package book;
import java.awt.BorderLayout;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.sound.midi.MidiEvent;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.sound.midi.ShortMessage;
import javax.sound.midi.Track;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.Border;
public class BeatBox {
JPanel mainPanel;
ArrayList<JCheckBox> checkboxsList;
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 Bonggo",
"Maracas","Whistle","Low Conga","Cowbell","Vibraslap","Low-mid Tom","High Agogo",
"open Hi Conga"};
//乐器的关键词例如35是bass
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() {
JFrame theFrame = new JFrame("Cyber BeatBox");
theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭窗口时关闭程序
BorderLayout layout = new BorderLayout();
JPanel background = new JPanel();
background.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));//设定面板上摆设组件的空白边缘
checkboxsList = new ArrayList<JCheckBox>();
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 MySUpTempoListener());
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);
theFrame.getContentPane().add(background);
GridLayout grid = new GridLayout(16,16);//网格布局
grid.setVgap(1);//设置组件之间的垂直距离
grid.setVgap(2);
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);
checkboxsList.add(c);
mainPanel.add(c);
}//循环结束
setUpMidi();
theFrame.setBounds(50,50,300,300);
theFrame.pack();
theFrame.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();
}
}//关闭方法
public void buildTrackAndStart() {
int [] trackList = null;//创建出16个元素的数组来存储一项乐器的值,如果要演奏,其值为关键字,否则为0
sequence.deleteTrack(track);
track = sequence.createTrack();//去掉旧的track 做一个新的
for (int i=0;i<16; i++) {//对每个乐器都执行一次
trackList = new int[16];
int key = instruments[i];//代表乐器的关键字
for(int j=0;j<16;j++) {//对每一拍执行一次
JCheckBox jc = (JCheckBox)checkboxsList.get(j+(16*i));
//如果有勾选,将关键字值放到数组得该位置上,不然补0
if(jc.isSelected()) {
trackList[j]=key;
}else {
trackList[j]=0;
}
}//关闭内部循环
makeTracks(trackList);//创建此乐器的事件并加到track上
track.add(makeEvent(176,1,127,0,16));
}//关闭外部循环
track.add(makeEvent(192,9,1,0,15));//确保16拍有事件,否则beatbox不会重复播放
try {
sequencer.setSequence(sequence);
sequencer.setLoopCount(sequencer.LOOP_CONTINUOUSLY);//播放无数次
sequencer.start();//开始播放
sequencer.setTempoInBPM(120);
}catch(Exception e)
{
e.printStackTrace();
}
}//关闭buildTrackAndStart方法
public class MyStartListener implements ActionListener{
public void actionPerformed(ActionEvent a) {
buildTrackAndStart();
}
}//关闭内部类
public class MyStopListener implements ActionListener{
public void actionPerformed(ActionEvent a) {
sequencer.stop();
}
}//关闭内部类
public class MySUpTempoListener implements ActionListener{
public void actionPerformed(ActionEvent a) {
float tempoFactor = sequencer.getTempoFactor();
sequencer.setTempoFactor((float)(tempoFactor*1.03));//节奏团子,每次调整0.03
}
}//关闭内部类
public class MyDownTempoListener implements ActionListener{
public void actionPerformed(ActionEvent a) {
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));//144表示开始
track.add(makeEvent(128,9,key,100,i+1));//128表示结束
}
}
}
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;
}
}//关闭类