标题翻译
Java Drum Sequencer: How to integrate live sequencing from checkBox states?
问题
我是初学者,正在基于《Head First Java》第13章的代码开发一个小型鼓机项目。
目前,该代码根据我在复选框网格上的输入创建一个序列,并将其绘制到GUI上。
然而,我希望程序能够像真正的鼓机一样运行,即我可以在序列播放时添加或减少击打。
我的想法是默认情况下让所有通道在序列的每个节拍上都播放,并在特定节拍处取消通道的静音复选框。然而,我很难弄清楚如何实现这一点。
这是否可行?是否有更简单或更好的方法可以实现我所追求的目标?
英文翻译
I'm a beginner working on a little drum machine project based off of Head First Java's code in Chapter 13.
At present, the code creates a sequence based on my input on the checkbox grid that the code draws to the GUI.
However I want the program to function like a real drum machine where I can add or subtract hits while the sequence plays.
My idea was to have all channels play on every tick of the sequence per default, and have the checkboxes unmute the channel at that specific tick. However I'm having a hard time figuring out how to implement that.
Is it possible? Is there an easier or better method that I'm not seeing to achieve what I'm aiming for?
import java.awt.*;
import javax.swing.*;
import javax.sound.midi.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.util.*;
import java.awt.event.*;
public class BeatBox {
JPanel mainPanel;
ArrayList<JCheckBox> checkboxList;
Sequencer sequencer;
Sequence sequence;
Track track;
JFrame theFrame;
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(){
theFrame=new JFrame("Cyber BeatBox");
theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
BorderLayout layout=new BorderLayout();
JPanel background=new JPanel(layout);
background.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
//Build tempo slider
JSlider slider = new JSlider();
slider.setOrientation(JSlider.HORIZONTAL);
slider.setMinimum(50);
slider.setMaximum(200);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
slider.setMajorTickSpacing(10);
slider.setMinorTickSpacing(1);
slider.setValue(120);
JLabel label = new JLabel();
label.setText("Tempo: " + slider.getValue());
slider.addChangeListener(e -> {
JSlider source = (JSlider) e.getSource();
//float tempoFactor=sequencer.getTempoFactor();
sequencer.setTempoFactor((float)source.getValue()/100);
label.setText("Tempo: " + String.valueOf(source.getValue()));
});
checkboxList=new ArrayList<JCheckBox>();
Box buttonBox=new Box(BoxLayout.X_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 resetButton = new JButton("Reset Patch");
resetButton.addActionListener(new MyResetListener());
buttonBox.add(resetButton);
Box nameBox=new Box(BoxLayout.Y_AXIS);
for(int i=0;i< 16;i++){
nameBox.add(new Label(instrumentNames[i]));
}
background.add(BorderLayout.NORTH,buttonBox);
background.add(BorderLayout.WEST,nameBox);
theFrame.getContentPane().add(background);
background.add(BorderLayout.SOUTH, slider);
buttonBox.add(BorderLayout.EAST, label);
GridLayout grid=new GridLayout(16,16);grid.setVgap(1);
grid.setHgap(2);
mainPanel=new JPanel(grid);
background.add(BorderLayout.CENTER,mainPanel);
for(int i=0;i< 256;i++){
JCheckBox c=new JCheckBox();
c.setSelected(false);
checkboxList.add(c);
mainPanel.add(c);
} // end loop
setUpMidi();
theFrame.setBounds(50,50,300,300);
theFrame.pack();
theFrame.setVisible(true);
} // close method
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(); }
} // close method
public void buildTrackAndStart(){
int[]trackList=null;
sequence.deleteTrack(track);
track=sequence.createTrack();
sequencer.setTickPosition(0);
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)checkboxList.get(j+(16*i));
if(!jc.isSelected()){
trackList[j]=key;
} /*else{
trackList[j]=0;
}*/
} // close inner loop
makeTracks(trackList);
track.add(makeEvent(176,1,127,0,16));
} // close outer
track.add(makeEvent(192,9,1,0,15));
try{
sequencer.setSequence(sequence);
sequencer.setLoopCount(sequencer.LOOP_CONTINUOUSLY);
sequencer.setMasterSyncMode(Sequencer.SyncMode.MIDI_SYNC);
sequencer.start();
sequencer.setTempoInBPM(120);
}catch(Exception e){
e.printStackTrace();
}
} // close buildTrackAndStart method
//Inner Classes
public class MyStartListener implements ActionListener{
public void actionPerformed(ActionEvent a){
buildTrackAndStart(); }
} // close inner class
public class MyStopListener implements ActionListener{
public void actionPerformed(ActionEvent a){
sequencer.stop();
sequencer.setTickPosition(0);}
} // close inner class
public class MyUpTempoListener implements ActionListener{
public void actionPerformed(ActionEvent a){
float tempoFactor=sequencer.getTempoFactor();
sequencer.setTempoFactor((float)(tempoFactor*1.03));
}
} // close inner class
public class MyDownTempoListener implements ActionListener{
public void actionPerformed(ActionEvent a){
float tempoFactor=sequencer.getTempoFactor();
sequencer.setTempoFactor((float)(tempoFactor*.97));
}
} // close inner class
public class MyResetListener implements ActionListener{
public void actionPerformed(ActionEvent a){
for(int i = 0; i<256; i++){
JCheckBox loopBox = checkboxList.get(i);
loopBox.setSelected(false);
}
}
} // close inner class
//Makers
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+1));
}
}
}
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;
}
}
专注分享java语言的经验与见解,让所有开发者获益!
评论