BeatBox终极版——Head first java 650

该博客详细介绍了如何使用Java实现一个音乐服务器,该服务器能够接收多个客户端的连接,并通过ObjectOutputStream和ObjectInputStream进行对象的序列化传输。客户端是一个MIDI应用程序,可以发送用户选择的音频配置到服务器,并接收其他客户端的配置信息,实现音乐的同步播放。博客内容涵盖了网络编程、多线程、MIDI处理和GUI设计等多个方面。
摘要由CSDN通过智能技术生成

服务端

import java.io.*;
import java.util.*;
import java.net.*;

public class MusicServer {
    ArrayList<ObjectOutputStream> clientOutputStreams;

    public static void main(String[] args) {
        new MusicServer().go();
    }

    public class ClientHandler implements Runnable{
        Socket clientSocket;
        ObjectInputStream in;

        public ClientHandler(Socket s){
            try {
                clientSocket = s;
                in = new ObjectInputStream(clientSocket.getInputStream());  //getInputstream要抛出异常
            }catch(Exception ex){
                ex.printStackTrace();
            }
        }

        public void run(){
            Object o1 = null;
            Object o2 = null;
            try{
                while((o1 = in.readObject()) != null){//readObject存在异常
                    o2 = in.readObject();
                    System.out.println("read two objects");
                    tellEveryone(o1,o2);
                }
            }catch(Exception ex){}
        }
    }//关闭内部类

    public void go(){
        clientOutputStreams = new ArrayList<ObjectOutputStream>();  //忘记new这个会导致抛出nullpoint异常
        try{
            ServerSocket serverSocket = new ServerSocket(5000); //监听4242端口(存在io异常)
            while(true) {
                Socket socket = serverSocket.accept(); //接受客户端的连接
                ObjectOutputStream os = new ObjectOutputStream(socket.getOutputStream()); //存在io异常
                clientOutputStreams.add(os);  //将客户端的输出流保存起来

                Thread t = new Thread(new ClientHandler(socket));
                t.start();
            }
        }catch(Exception ex){ex.printStackTrace();}
    }

    public void tellEveryone(Object o1,Object o2){
        //利用迭代器和集合向所有客户端发送信息
        Iterator it = clientOutputStreams.iterator();

        while(it.hasNext()){
            try{
                ObjectOutputStream out = (ObjectOutputStream)it.next();
                out.writeObject(o1);  //io异常
                out.writeObject(o2);  //io异常
            }catch(Exception ex){}
        }
    }
}

客户端

import java.awt.*;
import javax.swing.*;
import java.io.*;
import javax.sound.midi.*;
import java.util.*;
import java.awt.event.*;
import java.net.*;
import javax.swing.event.*;

public class BeatBoxFinal {
    JFrame theFrame;
    JPanel mainPanel;
    JList incomingList;
    JTextField userMessage;
    ArrayList<JCheckBox> checkBoxList;  //存放256个勾选框
    int nextNum;
    Vector<String> listVector = new Vector<String>(); //动态数组存放读取到的音频的名字
    String userName;
    ObjectOutputStream out;
    ObjectInputStream in;
    HashMap<String, boolean[]> otherSeqsMap = new HashMap<String, boolean[]>(); //音频信息存储在map中根据key查询

    Sequencer sequencer;
    Sequence sequence;
    Sequence mySequence = null;
    Track track;

    String[] instrumentNames = {"Bass Drum", "Closed Hi-Hat", "Open Hi-Hat", "Acoustic Share", "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 BeatBoxFinal().startUp(args[0]);
    }

    public void startUp(String name) {
        userName = name;
        try {
            Socket socket = new Socket("127.0.0.1", 5000);
            out = new ObjectOutputStream(socket.getOutputStream());
            in = new ObjectInputStream(socket.getInputStream());
            Thread remote = new Thread(new RemoteReader());
            remote.start();
        } catch (Exception ex) {
            System.out.println("couldn't connect - you'll have to play alone");
        }
        setUpMidi();
        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)); //格组件的间距

        checkBoxList = new ArrayList<JCheckBox>();

        Box buttonBox = new Box(BoxLayout.Y_AXIS);  //box布局的容器
        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);

        JButton sendIt = new JButton("sendIt");
        sendIt.addActionListener(new MySendListener());
        buttonBox.add(sendIt);

        userMessage = new JTextField();
        buttonBox.add(userMessage);

        //收到信息后的List
        incomingList = new JList();
        incomingList.addListSelectionListener(new MyListSelectionListener());
        incomingList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); //限制用户只能选择一个
        JScrollPane theList = new JScrollPane(incomingList); //滚轮中有一个list
        buttonBox.add(theList);
        incomingList.setListData(listVector); //从动态数组里获得信息

        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); //16x16组件格局
        grid.setVgap(1); //组件竖直距离1
        grid.setHgap(2); //横距为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);
        }

        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 ex) {
            ex.printStackTrace();
        }
    }

    public void buildTrackAndStart() {
        ArrayList<Integer> trackList = null;
        sequence.deleteTrack(track);
        track = sequence.createTrack(); //创造新的track

        for (int i = 0; i < 16; i++) {
            trackList = new ArrayList<Integer>();
            for (int j = 0; j < 16; j++) {
                JCheckBox jc = (JCheckBox) checkBoxList.get(i + j * 16);
                if (jc.isSelected()) {
                    int key = instruments[i];
                    trackList.add(key);
                } else {
                    trackList.add(null);
                }
            }
            makeTracks(trackList);
        }
        track.add(makeEvent(192, 9, 1, 0, 15));
        try {
            sequencer.setSequence(sequence);
            sequencer.setLoopCount(sequencer.LOOP_CONTINUOUSLY);
            sequencer.start();
            sequencer.setTempoInBPM(120);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public void makeTracks(ArrayList list){
        Iterator it = list.iterator();
        for(int i=0;i<16;i++){
            Integer num = (Integer)it.next();
            if(num != null){
                int numKey = num.intValue();
                track.add(makeEvent(144,9,numKey,100,i));
                track.add(makeEvent(128,9,numKey,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 ex){
            ex.printStackTrace();
        }
        return event;
    }

    class MyStartListener implements ActionListener{
        public void actionPerformed(ActionEvent a){
            buildTrackAndStart();
        }
    }

    class MyStopListener implements ActionListener{
        public void actionPerformed(ActionEvent a){
            sequencer.stop();
        }
    }

    class MyUpTempoListener implements ActionListener{
        public void actionPerformed(ActionEvent event){
            float tempoFactor = sequencer.getTempoFactor();
            sequencer.setTempoFactor((float)(tempoFactor*1.03));
        }
    }

    class MyDownTempoListener implements ActionListener{
        public void actionPerformed(ActionEvent event){
            float tempoFactor = sequencer.getTempoFactor();
            sequencer.setTempoFactor((float)(tempoFactor*0.97));
        }
    }

    class MySendListener implements ActionListener{
        public void actionPerformed(ActionEvent event){
            boolean[] checkboxState = new boolean[256];

            for(int i=0;i<256;i++){
                JCheckBox check = (JCheckBox)checkBoxList.get(i);
                if(check.isSelected())
                    checkboxState[i] = true;
                else
                    checkboxState[i] = false;
            }
            String messageToSend = null;
            try{
                out.writeObject(userName+nextNum+":"+userMessage.getText());
                out.writeObject(checkboxState);
            }catch(Exception ex){
                System.out.println("Sorry dude.Could not send it to the server.");
            }
            userMessage.setText("");
        }
    }

    class MyListSelectionListener implements ListSelectionListener{
        public void valueChanged(ListSelectionEvent le){
            if(!le.getValueIsAdjusting()){//为了不得到两次事件
                String selected = (String)incomingList.getSelectedValue();
                if(selected != null){
                    boolean[] selectedState = (boolean[])otherSeqsMap.get(selected);//根据key在map中寻到信息
                    changeSequence(selectedState);
                    sequencer.stop();
                    buildTrackAndStart();
                }
            }
        }
    }

    //多线程随时接受服务器发来的信息
    class RemoteReader implements Runnable{
        boolean[] checkBoxState = null;
        String nameToShow = null;
        Object obj = null;

        public void run(){
            try {
                while ((obj = in.readObject()) != null) {
                    System.out.println("got an object from server");
                    System.out.println(obj.getClass());
                    nameToShow = (String) obj;
                    checkBoxState = (boolean[]) in.readObject();
                    otherSeqsMap.put(nameToShow, checkBoxState); //放入map存储
                    listVector.add(nameToShow); //把key加入动态数组
                    incomingList.setListData(listVector); //重新设置list
                }
            }catch(Exception ex){}
        }
    }

    class MyPlayMineListener implements ActionListener{
        public void actionPerformed(ActionEvent event){
            if(mySequence != null)
                sequence = mySequence;
        }
    }

    public void changeSequence(boolean[] checkboxState){
        for(int i=0;i<256;i++){
            JCheckBox checkBox = (JCheckBox)checkBoxList.get(i);
            if(checkboxState[i])
                checkBox.setSelected(true);
            else
                checkBox.setSelected(false);
        }
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值