BeatBox

该博客介绍了如何用Java编程实现一个简单的MIDI音乐制作应用——BeatBox。通过创建JFrame、JCheckBox和MidiEvent等元素,用户可以交互式选择乐器并播放节奏。代码详细展示了如何设置MIDI序列、音轨和音符,以及如何响应开始、停止、调整节奏速度的按钮操作。
摘要由CSDN通过智能技术生成

文章目录


前言

《Head First Java》BeatBox实例


代码

import javax.swing.*;
import java.awt.*;
import javax.sound.midi.*;
import java.util.*;//ArrayList
import java.awt.event.*;

public class BeatBox {
    JPanel mainPanel;
    ArrayList

            checkboxList;//把checkbox存储在ArrayList中
    Sequencer sequencer;
    Sequence sequence;
    Track track;
    JFrame theFrame;

    String[] instrumentNames={"Bass Drum","Close Hi-Hat","Open Hi-Hat","Acounstic snare","Crash Cymbal","Hand Clap",
            "High Tom","Hi Bongo","Maracas","Whistle","Low conga","Cowbell","Vibraslap","Low-mid Tom","High Agogo","Open Hi Conga"};
    //乐器的名称,以String的array维护
    int[] instruments={35,42,46,38,49,39,50,60,70,72,64,56,58,47,67,63};
    //实际的乐器关键字,例如说35就代表Bass Drum

    public static void main(String[] args){
        BeatBox beatBox=new BeatBox();
        beatBox.buildGUI();
    }

    public void buildGUI(){
        theFrame=new JFrame("Cyber BeatBox");
        theFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel background=new JPanel(new BorderLayout());//JPanel面板需要添加BorderLayout布局管理器
        background.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));//设置面板上摆设组件时的空白边缘


        checkboxList=new ArrayList();
        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);



        GridLayout grid=new GridLayout(16,16);//布局管理器之网格布局GridLayout (16*16的网格分布)
        grid.setVgap(1);//设置垂直间距
        grid.setHgap(5);//设置水平间距
        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);          //从左至右,从上至下
        }
        setUpMidi();

        theFrame.getContentPane().add(background);
        //theFrame.setBounds(50,50,100,100);
        theFrame.pack();//若是已定义的setBound()范围太小,窗口自动调整
        theFrame.setVisible(true);
    }

    public void setUpMidi(){  //midi音频
        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;

        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) checkboxList.get(j+(16*i));
                if(jc.isSelected()){   //判断选取的状态
                    trackList[j]=key;
                }else{
                    trackList[j]=0;
                }
            }

            makeTracks(trackList);
            //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();}
    }

    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 MyUpTempoListener implements ActionListener{
        public void actionPerformed(ActionEvent a){
            float tempoFactor=sequencer.getTempoFactor();
            sequencer.setTempoFactor((float)(tempoFactor*2));//节奏速度
        }
    }
    public class MyDownTempoListener implements ActionListener{
        public void actionPerformed(ActionEvent a){
            float tempoFactor=sequencer.getTempoFactor();
            sequencer.setTempoFactor((float)(tempoFactor*0.5));
        }
    }

    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);//tick表示拍
        }catch(Exception e){e.printStackTrace();}
        return event;
    }

}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zzzyzh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值