Java MIDI Track playing duplicate notes
I am creating an application where the user can add multiple MIDI notes to a collection, from here they can press the "Play" button and the application will iterate through each note and play them through the speakers.
I've created a MIDIMessage class that holds details of the note the user has chose to add to the list, the details stored being the Pitch,Velocity,Delay and Channel.
Each of these messages is saved to an ArrayList with the type as MIDIMessage.
I then go on to attatch the iterator of the collection to an iterator object and play a sound whilst there is still an element in the collection that hasn't been used.
For some reason even if I only add one note to the collection there is always two notes playing with exactly the same pitch, length and velocity.
Also each note plays at the same time no matter how many are present in the collection, I assumed there would be some sort of delay in between them.
Following is the code I am using at the moment:
MIDIMessage:
package javatest;
public class MIDIMessage
{
private int pitch;
private int velocity;
private int channel;
public MIDIMessage(int p, int v, int c)
{
pitch = p;
velocity = v;
channel = c;
}
public int GetPitch()
{
return this.pitch;
}
public int GetVelocity()
{
return this.velocity;
}
public int GetChannel()
{
return this.channel;
}
}
Adding a note to the collection:
public void AddToList()
{
int channel = jComboBoxChannels.getSelectedIndex();
int pitch = jComboBoxPitch.getSelectedIndex();
int velocity = ((Integer)jSpinnerVelocity.getValue());
collection.add(new MIDIMessage(pitch,velocity,channel));
}
Playing the notes:
try
{
jButton1.setEnabled(false);
Sequencer sequencer = MidiSystem.getSequencer();
sequencer.open();
Sequence sequence = new Sequence(Sequence.PPQ,1);
Track track = sequence.createTrack();
Iterator itr = collection.iterator();
int i = 0;
while(itr.hasNext())
{
M开发者_Go百科IDIMessage msg = (MIDIMessage)itr.next();
ShortMessage noteOnMsg = new ShortMessage();
//Signal/Channel/Pitch/Velocity
noteOnMsg.setMessage(ShortMessage.NOTE_ON, msg.GetChannel(),msg.GetPitch(),msg.GetVelocity());
ShortMessage noteOffMsg = new ShortMessage();
//Signal/Channel/Pitch/Velocity
noteOffMsg.setMessage(ShortMessage.NOTE_OFF,msg.GetChannel(),msg.GetPitch(),msg.GetVelocity());
track.add(new MidiEvent(noteOnMsg,0));
track.add(new MidiEvent(noteOffMsg,1));
//i = i+1;
}
sequencer.setSequence(sequence);
sequencer.setTempoInBPM(120);
sequencer.setLoopCount(1);
sequencer.start();
Thread.sleep(1000);
}
I'm not sure why the notes are played twice, but this is definitely wrong:
track.add(new MidiEvent(noteOnMsg,0));
track.add(new MidiEvent(noteOffMsg,1));
As you can see here, a MidiEvent
consists of the message and a MIDI tick. You always add a noteOnMsg
on tick 0 and a noteOffMsg
on tick 1, which explains why for multiple notes, they are all played at the same time. You want to do something like this instead:
startTick = 0;
while(itr.hasNext()) {
[...]
track.add(new MidiEvent(noteOnMsg,startTick));
track.add(new MidiEvent(noteOffMsg,startTick + how_long_the_note_is_played));
startTick += difference_between_this_note_and_the_next;
[...]
}
I'm not sure what your delay
means and if you can use it here, so I'm using descriptive variable names instead.
Note that you'll have to use MIDI ticks here - if you want to convert seconds in MIDI ticks, see this SO question (or rather its answer):
[How long is one MIDI tick?]
The formula is
60000 / (BPM * PPQ)
(milliseconds).
精彩评论