使用JavaSound(JavaSE7)播放音序器

使用JavaSound(JavaSE7)播放音序器,java,javasound,Java,Javasound,这是我第一次尝试编写一个程序,而不是在书中做练习。当我完成时,它将是一个钢琴卷编辑器MIDI音序器。用户键入一组歌词。该程序将单词转换为钢琴滚动编辑器上的音符,用户可以在其中移动并构建旋律。我有歌词提交的GUI和一个基本的钢琴滚动面板。我的笔记出现在面板上,上面印有歌词。现在我正在尝试构建一个音序器/合成器来播放这些音符。在这一点上,复杂性有点让人难以承受,所以我试着以一步一步的方式来处理这个问题。我学习了《头先Java》一书中的音乐节拍盒,以及《杀手游戏编程》一书中的MIDI章节。我在Java

这是我第一次尝试编写一个程序,而不是在书中做练习。当我完成时,它将是一个钢琴卷编辑器MIDI音序器。用户键入一组歌词。该程序将单词转换为钢琴滚动编辑器上的音符,用户可以在其中移动并构建旋律。我有歌词提交的GUI和一个基本的钢琴滚动面板。我的笔记出现在面板上,上面印有歌词。现在我正在尝试构建一个音序器/合成器来播放这些音符。在这一点上,复杂性有点让人难以承受,所以我试着以一步一步的方式来处理这个问题。我学习了《头先Java》一书中的音乐节拍盒,以及《杀手游戏编程》一书中的MIDI章节。我在JavaSound上一遍又一遍地使用JavaAPI。考虑到所有这些,我构建了一个包含sequencer和synth的类,我试图简单地创建一系列注释并播放它们(甚至不用担心将它们连接到屏幕上的图形注释形状)。但现在还没有任何进展。我现在有四个类(一个用于GUI,一个用于钢琴滚动面板,一个用于图形注释对象,一个用于音乐引擎)。我将尝试在下面发布一些代码。如果有人能帮我弄清楚为什么什么都没有,我会很感激的

这是音乐引擎课程。希望我在这里正确地发布了代码:

import javax.sound.midi.*;

public class MusicEngine {
private Sequencer sequencer;
private Sequence sequence;
private Synthesizer synthesizer;
private Track track;
MidiEvent event;

// Constructor
public MusicEngine() {
    createMidi();
}

// Get sequencer and sequence and track
public void createMidi() {
    try {
        sequencer =  MidiSystem.getSequencer();
        if (sequencer == null) {
            System.out.println("Cannot get a sequencer");
            System.exit(0);
        }
        sequencer.open();

        // If sequencer is not the same as synthesizer, link the two 
        // (required in J2SE 5.0)
        if (!(sequencer instanceof Synthesizer)) {
            System.out.println("Linking the sequencer to the synthesizer");
            synthesizer = MidiSystem.getSynthesizer();
            synthesizer.open();
            Receiver synthReceiver = synthesizer.getReceiver();
            Transmitter seqTransmitter = sequencer.getTransmitter();
            seqTransmitter.setReceiver(synthReceiver);
        } else 
            synthesizer = (Synthesizer)sequencer;
        sequence = new Sequence(Sequence.PPQ, 4);
        track = sequence.createTrack();
        sequencer.setTempoInBPM(120);
    } catch(MidiUnavailableException e) {
        System.out.println("No sequencer available");
        System.exit(0);
    } catch(Exception e) {
        e.printStackTrace();
        System.exit(0);
    }

}

// Create an individual MIDI event
public MidiEvent createEvent(int command, int channel, int one, int two, int tick) {
    event = null;
    try {
        ShortMessage a = new ShortMessage();
        a.setMessage(command, channel, one, two);
        event = new MidiEvent(a, tick);
    } catch(InvalidMidiDataException e) {
        e.printStackTrace();
    }
    return event;
}

    public void add(MidiEvent event) {
    track.add(event);
}

public void playSong(int tempo) {
    try {
        sequencer.setSequence(sequence);
    }
    catch (InvalidMidiDataException e) {
        e.printStackTrace();
    }

    sequencer.start();
}

}
这是钢琴滚动面板,它试图演奏一些音符:

import javax.sound.midi.ShortMessage;
import javax.swing.*;
import javax.swing.event.MouseInputAdapter;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;

public class MelodyPanel extends JPanel {
private String[] lyricList;
private ArrayList<MovableNote> noteList = new ArrayList<>();
private int xCoord = 1;
private int yCoord = 50;
private int startX, startY, stopX, stopY, diffX, diffY;
private int lyricPosition;
private int noteWidth = 40;
private static final int DEFAULT_NOTE_HEIGHT = 15;
private static final int SIXTEENTH_BEAT_WIDTH = 50;
private MusicEngine musicEngine;

private String[] noteNames = {"C1","C#1/Db1","D1","D#1/Eb1","E1","F1","F#1/Gb1","G1","G#/Ab1","A1","A#1/Bb1","B1",
        "C2","C#2/Db2","D2","D#2/Eb2","E2","F2","F#2/Gb2","G2","G#2/Ab2","A2","A#2/Bb2","B2",
        "C3","C#3/Db3","D3","D#3/Eb3","E3","F3","F#3/Gb3","G3","G#3/Ab3","A3","A#3/Bb3","B3",
        "C4","C#4/Db4","D4","D#4/Eb4","E4","F4","F#4/Gb4","G4","G#4/Ab4","A4","A#4/Bb4","B4",
        "C5","C#5/Db5","D5","D#5/Eb5","E5","F5","F#5/Gb5","G5","G#5/Ab5","A5","A#5/Bb5","B5",
        "C6","C#6/Db6","D6","D#6/Eb6","E6","F6","F#6/Gb6","G6","G#6/Ab6","A6","A#6/Bb6","B6",
        "C7","C#7/Db7","D7","D#7/Eb7","E7","F7","F#7/Gb7","G7","G#7/Ab7","A7","A#7/Bb7","B7"};

// Measure length = default note length x number of beats
private static final int FOUR_FOUR_MEASURE_LENGTH = SIXTEENTH_BEAT_WIDTH * 16;
private static final int THREE_FOUR_MEASURE_LENGTH = SIXTEENTH_BEAT_WIDTH * 12;
private static final int SIX_EIGHT_MEASURE_LENGTH = SIXTEENTH_BEAT_WIDTH * 24;

private Font f = new Font("SansSerif", Font.BOLD, 14);
private MovableNote mNote;
private MovableNote selectedNote = null;
private boolean dragging = false;

// Create an INITIAL MelodyPanel with lyrics, RESET to flatline melody
public void showMelodyPanel(String[] lyricList) {
    setBackground(Color.BLACK);
    this.lyricList = lyricList;

    // Create the MusicEngine sequencer and synth
    musicEngine = new MusicEngine();

    // For every syllable in the lyricList, create a MovableNote and put it in the ArrayList
    for (int i = 0; i < lyricList.length; i++) {
        lyricPosition = i;
        mNote = new MovableNote((SIXTEENTH_BEAT_WIDTH * lyricPosition) + 2, DEFAULT_NOTE_HEIGHT * 10, noteWidth, DEFAULT_NOTE_HEIGHT, lyricList[i]);
        noteList.add(mNote);
        // try adding a musical note to the track
        musicEngine.add(musicEngine.createEvent(ShortMessage.NOTE_ON, 0, 60, 100, i * 16));
        musicEngine.add(musicEngine.createEvent(ShortMessage.NOTE_OFF, 0, 60, 100, i * 16 + 4));
    }

    // try to play the song
    musicEngine.playSong(120);

    // The panel responds when you click on it
    addMouseListener(new NoteListener());

    // The panel responds when you drag the mouse on it
    addMouseMotionListener(new NoteListener());
}

@Override /** Paint the melodyPanel */
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    // Draw the note rows, iterating backwards through the noteNames array
    int counter1 = 1;
    int counter2 = 6;
    NoteRow row;
    for (int i = 83; i >= 0; i--) {
        row = new NoteRow(0, i * DEFAULT_NOTE_HEIGHT, SIXTEENTH_BEAT_WIDTH * 16 * lyricList.length, DEFAULT_NOTE_HEIGHT, noteNames[i]);
        row.draw(g);

        // Place horizontal lines to separate rows representing adjacent white piano keys
        if (counter1 % 12 == 0 || counter2 % 12 == 0) 
            g.setColor(Color.DARK_GRAY);
            g.drawLine(0, i * DEFAULT_NOTE_HEIGHT, this.getWidth(), i * DEFAULT_NOTE_HEIGHT);
        counter1++;
        counter2++;
    }

    // Draw the sixteenth note lines
    for (int i = 0; i < this.getWidth(); i += FOUR_FOUR_MEASURE_LENGTH / 16) {
        g.setColor(new Color(112,128,144));
        g.drawLine(i, 0, i, this.getHeight());
    }

    // Draw the eighth note lines
    for (int i = 0; i < this.getWidth(); i += FOUR_FOUR_MEASURE_LENGTH / 8) {
        g.setColor(new Color(95,158,160));
        g.drawLine(i, 0, i, this.getHeight());
    }

    // Draw the quarter note lines
    for (int i = 0; i < this.getWidth(); i += FOUR_FOUR_MEASURE_LENGTH / 4) {
        g.setColor(new Color(70,130,180));
        g.drawLine(i, 0, i, this.getHeight());
    }

    // Draw the measure lines
    for (int i = 0; i < this.getWidth(); i += FOUR_FOUR_MEASURE_LENGTH) {
        g.setColor(Color.WHITE);
        g.drawLine(i, 0, i, this.getHeight());
    }

    // For every MovableNote in the ArrayList draw a note on the MelodyPanel
    for (int i = 0; i < noteList.size(); i++) {
        if (noteList != null) {
            noteList.get(i).draw(g);

            // Paint the current syllable or word onto the current note
            g.setColor(Color.BLACK);
            g.setFont(f);
            g.drawString(noteList.get(i).getSyllable(), (int)noteList.get(i).getX() + 2, (int)noteList.get(i).getY() + 13);

        } else {
            // Code that informs user they need to submit some lyrics
            // Or something else if the user wishes to not use lyrics
        }
    }
}

private class NoteListener extends MouseInputAdapter {

    @Override
    public void mousePressed(MouseEvent e) {
        startX = e.getX();
        startY = e.getY();
        dragging = true;
        for (MovableNote n: noteList) {
            if (n.isHit(startX, startY)) {
                if (selectedNote != null) {
                    selectedNote = n;
                    System.out.println("You have selected a note");
                    selectedNote.setNoteColor(Color.BLACK);
                    repaint();
                } else {
                    selectedNote.setNoteColor(Color.YELLOW);
                    repaint();
                    selectedNote = null;
                }
            }
        }
        testPress(e.getX(), e.getY());
    }

    @Override public void mouseReleased(MouseEvent e) {
        dragging = false;
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        stopX = e.getX();
        stopY = e.getY();

        for (MovableNote n: noteList) {
            if (n.isHit(e.getX(), e.getY())) {
                System.out.println("You tried to drag a note");
                diffX = stopX - startX;
                diffY = stopY - startY;
                n.translate(diffX, diffY);
                repaint();
            }
        }

        // code to reset the the old x, y values
        startX += diffX;
        startY += diffY;

        testDrag(e.getX(), e.getY());
    }

}

// When mouse is pressed on panel, a note is created without any connection to a lyric
private void testPress(int x, int y) {
    // Test to see if mouse listener works
    System.out.println("The mouse was clicked on coordinates " + x + ", " + y);
}

// When mouse drags a note, the note moves
private void testDrag(int x, int y) {
    // Test to see if mouse listener works
    System.out.println("The mouse dragged to this location: " + x + ", " + y);
}

// Individual row that represents a single pitch horizontally
private class NoteRow extends Rectangle {
    Color color = (Color.GRAY);
    private String pitch;

    // Constructor
    public NoteRow(int x, int y, int width, int height, String pitch) {
        super(x, y, width, height);
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.pitch = pitch;

        // Set color of the row according to if it's a black keyboard key or a white keyboard key
        if (pitch.startsWith("C#") || pitch.startsWith("Db") || pitch.startsWith("D#") || 
                pitch.startsWith("Eb") || pitch.startsWith("F#") || pitch.startsWith("Gb") || pitch.startsWith("G#") || 
                pitch.startsWith("Ab") || pitch.startsWith("A#") || pitch.startsWith("Bb")) {
            this.color = (Color.DARK_GRAY);
        } else {
            this.color = (Color.LIGHT_GRAY);
        }
    }

    // Method for the note to draw itself
    void draw(Graphics gr) {
        Graphics2D g = (Graphics2D)gr;
        g.setColor(color);
        g.fill(this);
    }
}

}
导入javax.sound.midi.ShortMessage;
导入javax.swing.*;
导入javax.swing.event.MouseInputAdapter;
导入javax.swing.border.*;
导入java.awt.*;
导入java.awt.event.*;
导入java.util.ArrayList;
公共类MelodyPanel扩展了JPanel{
私有字符串[]歌词列表;
private ArrayList noteList=新建ArrayList();
私有int xCoord=1;
私人国际合作=50;
私人int startX、startY、stopX、stopY、diffX、diffY;
私人位置;
私有int noteWidth=40;
专用静态最终整数默认值注释高度=15;
私人静态最终整数十六拍宽=50;
私人音乐引擎;
私有字符串[]noteNames={“C1”、“C#1/Db1”、“D1”、“D#1/Eb1”、“E1”、“F1”、“F#1/Gb1”、“G1”、“G#/Ab1”、“A1”、“A#1/Bb1”、“B1”,
“C2”、“C#2/Db2”、“D2”、“D#2/Eb2”、“E2”、“F2”、“F#2/Gb2”、“G2”、“G#2/Ab2”、“A2”、“A#2/Bb2”、“B2”,
“C3”、“C#3/Db3”、“D3”、“D#3/Eb3”、“E3”、“F3”、“F#3/Gb3”、“G3”、“G#3/Ab3”、“A3”、“A#3/Bb3”、“B3”,
“C4”、“C#4/Db4”、“D4”、“D#4/Eb4”、“E4”、“F4”、“F#4/Gb4”、“G4”、“G#4/Ab4”、“A4”、“A#4/Bb4”、“B4”,
“C5”、“C#5/Db5”、“D5”、“D#5/Eb5”、“E5”、“F5”、“F#5/Gb5”、“G5”、“G#5/Ab5”、“A5”、“A#5/Bb5”、“B5”,
“C6”、“C#6/Db6”、“D6”、“D#6/Eb6”、“E6”、“F6”、“F#6/Gb6”、“G6”、“G#6/Ab6”、“A6”、“A#6/Bb6”、“B6”,
“C7”、“C#7/Db7”、“D7”、“D#7/Eb7”、“E7”、“F7”、“F#7/Gb7”、“G7”、“G#7/Ab7”、“A7”、“A#7/Bb7”、“B7”};
//测量长度=默认音符长度x拍数
私有静态最终int-FOUR\u-FOUR-MEASURE\u-LENGTH=第十六拍\u-WIDTH*16;
私有静态最终整数三个四个度量长度=第十六拍宽度*12;
私有静态最终整数六个八个度量长度=第十六拍宽度*24;
私有字体f=新字体(“SansSerif”,Font.BOLD,14);
私人动产票据;
private MovableNote selectedNote=null;
私有布尔值=false;
//创建带有歌词的初始旋律面板,重置为平面旋律
公共void showMelodyPanel(字符串[]歌词列表){
挫折背景(颜色:黑色);
this.lyricList=lyricList;
//创建MusicEngine sequencer和synth
musicEngine=新的musicEngine();
//对于歌词列表中的每个音节,创建一个可移动音符并将其放入ArrayList
for(int i=0;i=0;i--){
行=新注释行(0,i*默认注释高度,第十六拍宽度*16*歌词列表。长度,默认注释高度,注释名称[i]);
世界其他地区(g);
//将水平线放置到表示相邻白色钢琴键的分隔行
如果(计数器1%12==0 | |计数器2%12==0)
g、 setColor(颜色:深灰色);
g、 绘图线(0,i*默认注释高度,this.getWidth(),i*默认注释高度);
计数器1++;
计数器2++;
}
//画第十六个音符线
for(int i=0;i