我正在創建一個midi鋼琴卷編輯器。 Note類創建幷包含一個NOTE_ON對象和一個關聯的NOTE_OFF對象以及一個用戶在屏幕上操縱矩形,以操縱音符的音高,時間和持續時間。以下是此類的代碼減去矩形的代碼。我無法弄清楚爲什麼它不能正常工作。測試程序創建這些Note對象中的五個,並將它們顯示在鋼琴捲簾上,並且它們可以正常播放。矩形上下拖動時,更改音高的方法也可以正常工作。但是當我調用改變時間或持續時間的方法時,音符開始行爲不端。首先,他們在移動時不會播放他們被告知的內容,然後如果音符被拖動到彼此的頂部或者彼此之間,則移動的音符將阻止其下方的音符播放。以arg形式發送到這些方法的運動單位設置爲16,因此音符總是會捕捉到第16個節拍位置。任何人都可以發現我的代碼有問題嗎?爲什麼不會注意到MIDI時間的工作?
public class Note {
MidiEvent noteOn;
MidiEvent noteOff;
private int channel;
private int pitch;
private int vel;
// Constructor calls methods to create NOTE_ON, NOTE_OFF, and graphical rectangle
public Note(MidiMessage on, long tickPos) {
noteOn = createNoteOn(on, tickPos);
ShortMessage shortMessage = (ShortMessage) on;
noteOff = createNoteOff(shortMessage.getChannel(), shortMessage.getData1(), tickPos);
}
public MidiEvent createNoteOn(MidiMessage on, long tickPos) {
noteOn = new MidiEvent(on, tickPos);
return noteOn;
}
public MidiEvent createNoteOff(int chan, int pitch, long tickPos) {
try {
noteOff = new MidiEvent(new ShortMessage(ShortMessage.NOTE_OFF, chan, pitch, 0), tickPos + 2);
} catch (InvalidMidiDataException e) {
e.printStackTrace();
}
return noteOff;
}
// Method for moving musical pitch of this note up or down for both NOTE_ON and NOTE_OFF
public void setPitch(int pitchUpOrDown) {
MidiMessage message = noteOn.getMessage();
ShortMessage shortMessage = (ShortMessage) message;
channel = shortMessage.getChannel();
pitch = shortMessage.getData1();
vel = shortMessage.getData2();
try {
shortMessage.setMessage(ShortMessage.NOTE_ON, channel, pitch + pitchUpOrDown, vel);
} catch (InvalidMidiDataException e) {
e.printStackTrace();
}
message = noteOff.getMessage();
shortMessage = (ShortMessage) message;
try {
shortMessage.setMessage(ShortMessage.NOTE_OFF, channel, pitch + pitchUpOrDown, 0);
} catch (InvalidMidiDataException e) {
e.printStackTrace();
}
}
// Moves entire note without changing duration of note
public void shiftLocation(int diff) {
noteOn.setTick(noteOn.getTick() + diff);
noteOff.setTick(noteOff.getTick() + diff);
}
// Moves start time of note while leaving end time in place, changes duration of note
public void setStartTime(long start) {
noteOn.setTick(start);
}
// Moves end time of note while leaving start time in place, changes duration of note
public void setDuration(int duration) {
noteOff.setTick(noteOff.getTick() + duration);
}
的MIDI音序器和合成器:
import javax.sound.midi.*;
public class MusicEngine {
Sequencer sequencer;
Sequence sequence;
Synthesizer synthesizer;
Track track;
MidiEvent event;
// PPQ, or ticks per beat
int ticksPerBeat = 16;
int tempoBPM = 120;
// 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, ticksPerBeat);
track = sequence.createTrack();
sequencer.setTempoInBPM(tempoBPM);
} 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();
}
public void stopSong() {
sequencer.stop();
}
}
可能有助於發佈您用來播放序列的代碼嗎?另外,你可以首先將事情隔離爲一個簡單的測試案例,在這個例子中你用一對筆記創建一個軌道,改變一個筆記的時間/持續時間,然後播放序列? –
我添加了合成器和音序器引擎。我必須離開一點。當我回來時,我會嘗試簡化代碼並從我更詳細的代碼中提取簡單的測試代碼。 –