天天看点

第13章-Swing(2)--BeatBox-总结与实例

2015/6/22

源码:

package BeatBox;
import java.awt.*;

import javax.swing.*;

import java.util.*;
import java.awt.event.*;

import javax.sound.midi.*;
public class BeatBox {
	
	JPanel mainPanel;
	//把checkbox储存咋ArrayList中
	ArrayList<JCheckBox> checkboxList;
	Sequencer sequencer;
	Sequence sequence;
	Track track;
	JFrame frame;
	
	//乐器的名称
	String[] instrumentNames={"Bass Drum","Closed Hi-Hat","Open Hi-Hat","Acoustic Snare","Crash Cymbal","Hand Clap","High Tom","Hi Bongo","Maracas","Whistle","Low Conga","Cowbell","Vibraslap","Low-mid Tom","High Agogo","Open Hi Conga"};
	//实际的乐器关键字
	int[] instruments={35,42,46,38,49,39,50,60,70,72,64,56,58,47,67,63};
	
	public static void main(String[] args){
		new BeatBox().buildGUI();
	}
	public void buildGUI(){
		frame=new JFrame("Cyber BeatBox");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		//将background的布局改为BorderLayout
		BorderLayout layout=new BorderLayout();
		JPanel background=new JPanel(layout);
		//设定面板上摆设组件式的空白边缘
		background.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
		
		checkboxList=new ArrayList<JCheckBox>();
		//Box类,是一种不可见组件,Box 用来提供使用 BoxLayout的容器
		//BoxLayout.Y_AXIS表示垂直排列
		//用来储存按钮
		Box buttonBox=new Box(BoxLayout.Y_AXIS);
		
		//开始按钮
		JButton start=new JButton("Start");
		start.addActionListener(new MyStartListener());
		buttonBox.add(start);
		
		//停止按钮
		JButton stop=new JButton("Stop");
		stop.addActionListener(new MyStopListener());
		buttonBox.add(stop);
		
		//提高声音按钮
		JButton upTempo=new JButton("Tempo Up");
		upTempo.addActionListener(new MyUpTempoListener());
		buttonBox.add(upTempo);
		
		//降低声音按钮
		JButton downTempo=new JButton("Tempo Down");
		downTempo.addActionListener(new MydownTempoListener());
		buttonBox.add(downTempo);
		
		//用来储存乐器的名字
		Box nameBox=new Box(BoxLayout.Y_AXIS);
		for(int i=0;i<16;i++){
			nameBox.add(new Label(instrumentNames[i]));
		}
		
		background.add(BorderLayout.EAST,buttonBox);
		background.add(BorderLayout.WEST,nameBox);
		
		frame.getContentPane().add(background);
		
		//GridLayout是表格布局,设定行数和列数,按顺序将组件添加到每个格子中
		GridLayout grid=new GridLayout(16,16);
		//表格布局中的水平间隙和垂直间隙
		grid.setVgap(1);
		grid.setHgap(2);
		//将mainPanel设定为表格布局
		mainPanel=new JPanel(grid);
		background.add(BorderLayout.CENTER,mainPanel);
		
		//创建CheckBox,设定为false并加到ArrayList和面板上
		for(int i=0;i<256;i++){
			JCheckBox c=new JCheckBox();
			c.setSelected(false);
			checkboxList.add(c);
			mainPanel.add(c);
		}
		
		setUpMidi();
		
		frame.setBounds(50,50,300,300);
		/**
		Pack()方法的作用:调整此窗口的大小,以适合其子组件的首选大小和布局。
		如果该窗口和/或其所有者还不可显示,则在计算首选大小之前都将变得可显示。
		在计算首选大小之后,将会验证该窗口。
		 */
		frame.pack();
		frame.setVisible(true);
	}
	
	public void setUpMidi(){
		try{
			sequencer=MidiSystem.getSequencer();
			sequencer.open();
			sequence=new Sequence(Sequence.PPQ,4);
			track=sequence.createTrack();
			sequencer.setTempoInBPM(120);
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	
	//核心代码,创建出16个元素的数组来储存一项乐器的值,如果该乐器应该要演奏,其值会是关键字值,否则值为零。
	public void buildTrackAndStart(){
		int[] trackList=null;
		//清除之前的track,之后建一个新的
		sequence.deleteTrack(track);
		track=sequence.createTrack();
		
		//对每个乐器都执行一次
		for(int i=0;i<16;i++){
			trackList=new int[16];
			//设定代表乐器的关键字
			int key=instruments[i];
			
			for(int j=0;j<16;j++){//每个拍子运行一次
				//取得每一个CheckBox
				JCheckBox jc=(JCheckBox)checkboxList.get(j+(16*i));
				if(jc.isSelected()){
					trackList[j]=key;
				}else{
					trackList[j]=0;
				}
			}
			//创建此乐器的事件,并且加到track上
			makeTracks(trackList);
			/*插入编号为176的类型,它不会做任何事情,只是用来判别音符是 否被播放,
			 * 它与144(开始发声)类型是同时进行的*/ 
			track.add(makeEvent(176,1,127,0,16));
		}
		//确保第16拍有事件,否则不会重复播放
		track.add(makeEvent(192,9,1,0,15));
		try{
			//制定循环播放
			sequencer.setSequence(sequence);
			sequencer.setLoopCount(sequencer.LOOP_CONTINUOUSLY);
			sequencer.start();
			sequencer.setTempoInBPM(120);
		}catch(Exception e){
			e.printStackTrace();
		}
	}
	//内部类
	public class MyStartListener implements ActionListener{


		public void actionPerformed(ActionEvent e) {
			buildTrackAndStart();
			
		}
		
	}
	public class MyStopListener implements ActionListener{

		@Override
		public void actionPerformed(ActionEvent e) {
			// TODO 自动生成的方法存根
			sequencer.stop();
		}
		
	}
	public class MyUpTempoListener implements ActionListener{

		@Override
		public void actionPerformed(ActionEvent e) {
			// TODO 自动生成的方法存根
			float tempoFactor=sequencer.getTempoFactor();
			sequencer.setTempoFactor((float)(tempoFactor*1.03));
		}
		
	}
	public class MydownTempoListener implements ActionListener{

		@Override
		public void actionPerformed(ActionEvent e) {
			// TODO 自动生成的方法存根
			float tempoFactor=sequencer.getTempoFactor();
			sequencer.setTempoFactor((float)(tempoFactor*0.97));
		}
		
	}
	public void makeTracks(int[] list){
		for(int i=0;i<16;i++){
			int key=list[i];
			
			if(key!=0){
				track.add(makeEvent(144,9,key,100,i));
				track.add(makeEvent(128,9,key,100,i++));
			}
		}
	}
	public MidiEvent makeEvent(int comd,int chan,int one,int two,int tick){
		MidiEvent event=null;
		try{
			ShortMessage a=new ShortMessage();
			a.setMessage(comd,chan,one,two);
			event=new MidiEvent(a,tick);
		}catch(Exception e){e.printStackTrace();}
		return event;
	}
}