Java Drum Sequencer: как интегрировать живое секвенсирование из состояний checkBox? - PullRequest
0 голосов
/ 30 мая 2020

Я новичок и работаю над небольшим проектом драм-машины, основанным на коде Head First Java в главе 13.

В настоящее время код создает последовательность на основе моего ввода в Флажок сетки, код dr aws на GUI.

Однако я хочу, чтобы программа работала как настоящая драм-машина, где я могу добавлять или вычитать удары во время воспроизведения последовательности.

Моя идея заключалась в том, чтобы все каналы воспроизводились на каждом тике последовательности по умолчанию, и чтобы флажки включали канал на этом c тике. Однако мне сложно понять, как это реализовать.

Возможно ли? Есть ли более простой или лучший метод, который я не вижу для достижения того, к чему стремлюсь?

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;
                }
}
...