PDA

View Full Version : construct midi messages and sync them to the tempo


asiohead
11-19-2009, 10:36 PM
I’m working on a step sequencer, and I need to create some midi events. But I can’t exactly figure out how. (The notes come from an array, NotesArray.)

I initialise a IMidiMsg once like this

IMidiMsg* seqMsg = new IMidiMsg(0,128,0,100);


Then I generated a message like this in a method that gets called in ProcessDoubleReplacing


seqMsg->MakeNoteOnMsg(NotesArray[x],100,0);
mMidiQueue.push_back(*seqMsg);
seqMsg->MakeNoteOffMsg(NotesArray[x],0);
mMidiQueue.push_back(*seqMsg);
SendMidiMsg(seqMsg);

But this doesn’t work at all because I have no control over how fast the queue is being read. The note events are being fired so close, nothin really happens.
Also, why do you have to give an offset in the MakeNote … methods, and what does this Offset mean exactly ?



Could someone explain how to construct and work with midi messages, where to send/handle them (ProcessMidiMsg or ProcessDoubleReplacing)

How do I sync the sending of messages to the tempo, because now they just fire at sample rate. I have no control over it.

And how do I set the other parameters on the seqMsg object , like decay, note length, AttackTime, etc …



Thanx

Tale
11-21-2009, 05:55 AM
When your host software receives a MIDI message, your plug is probably busy generating audio in ProcessDoubleReplacing. So the host temporarily stores the MIDI message, recording it's sample offset. When your plug returns from ProcessDoubleReplacing (i.e. when it has finished processing a sample block), the host will send the temporarilly stored MIDI messages to your plug using ProcessMidiMsg. Along with the MIDI message it gives you the sample offset at which the MIDI message should occur. This offset is relatoive to the next ProcessDoubleReplacing call, so an offset of 0 means before the 1st sample, an offset of 1 means after the 1st sample etc.

When you send MIDI back out and you want it to be sample accurate, you will need to specify the offset again. I don't think it's safe to specify an offset larger than the current sample block frame count, so your plug will have to know when exactly to send the MIDI messages. Here is a fragment of code that sends a Note On and a Note Off every 0.5 seconds (assuming a sample rate of 44100 Hz):

void ProcessDoubleReplacing(double** inputs, double** outputs, int nFrames)
{
for (int offset = 0; offset < nFrames; ++offset)
{
// Note On
if (mTimer == 0)
SendMidiMsg(&IMidiMsg(offset, 0x90, mNoteNumber, 127));
// Note Off
else if (mTimer == 22050)
SendMidiMsg(&IMidiMsg(offset, 0x80, mNoteNumber, 0));

if (++mTimer >= 44100)
mTimer = 0;
}
}

I hope this clarifies things a bit for you.

asiohead
11-21-2009, 03:21 PM
It does indeed, thanx mate, I really appreciate it !