Help understanding Midi time

I’m trying to make sense of the timeStamp value in MidiMessages and the sampleNumber in MidiBuffer::addEvent().

What do these represent? The time since the track started? The time after the event is queued that it should be triggered? The time since the buffer was last filled? Or something else?

In the plugin I’m writing, the user triggers events in the UI, and I really want them to be sent out to other synths as soon as possible after that.

Does this mean I should timeStamp the MidiMessage as 0? Can I also put sampleNumber as 0?

If not, what should I be putting in these slots?

cheers

Phil

//==============================================================================
/** Returns the timestamp associated with this message.

    The exact meaning of this time and its units will vary, as messages are used in
    a variety of different contexts.

    If you're getting the message from a midi file, this could be a time in seconds, or
    a number of ticks - see MidiFile::convertTimestampTicksToSeconds().

    If the message is being used in a MidiBuffer, it might indicate the number of
    audio samples from the start of the buffer.

    If the message was created by a MidiInput, see MidiInputCallback::handleIncomingMidiMessage()
    for details of the way that it initialises this value.

    @see setTimeStamp, addToTimeStamp
*/
double getTimeStamp() const noexcept                { return timeStamp; }

That leaves me roughly as confused as I was previously.

What is this timeStamp FOR? I mean how is the value of the timeStamp treated when I put an event in the MidiBuffer in processBlock?

It’s for holding any double value you want to put there. The meaning of that double is up to you, or the code that created the MidiMessage.

But MidiBuffer is completely different - it doesn’t hold MidiMessage objects, it’s a packed format with an integer sample offset for each of its messages. It’s analogous to an AudioBuffer.

OK. So, as to the other part of my question. What about the sampleNumber?

What I really want to know is, when trying to send out Midi messages from my plugin, what should I put in both timeStamp and sampleNumber to ensure that the midi message gets sent out as quickly as possible.

With MIDI files it’s usually dependent on PPQ value defined in the MIDI file header, ie. beatPosition = tick / PPQ.

In processBlock position means sample offset from the start of the current audio buffer.

sample number: 0!

But what does it mean to say “offset from start of sample buffer”? Does it mean “wait this many sample points before sending the message out”?

Because I’d like all the messages to be sent immediately. Which would suggest putting a 0 there. But elsewhere the documentation seems to tell me that sampleNumber defines the ordering and if I try to put two events at the same samplePoint the second will overwrite the first.

And if I put two events at sampleNumber 0, one won’t overwrite the other?

no

1 Like

OK. Thanks.

So basically there shouldn’t be any problem having both the timeStamp in the MidiMessage I create and the samplePoint be zero when I use midiBuffer::addEvent(myMsg, 0);

That just sends the messages out ASAP?

yep

1 Like

cheers.

Be aware though, that you discretise your midi events by doing so in bufferSize fragments. So it will not sound very musical.
If the midi is captured by the host, it already has a number here, that you should preserve, if not, you should calculate the proper positions of the beat.
The latency of one buffer, that cannot be avoided, is less noticeable than the misplacements of the individual notes to the grid.

One processBlock call is basically: “I’ll tell you what is happening in the next bufferSize samples, and when it happens…”

1 Like

When you say “not very musical” you mean not quantized to a grid?

That’s OK, I’m not trying to sync. anything to any other pattern (at least not yet). I may add that later. But for now it’s OK if when the event happens, the midi signal gets sent.

No, I mean quantized to a random grid, that is different to anything sensible. Events can only occur every bufferSize samples, if you ignore the sample position inside the block.

It will not occur when the event gets sent.

Well, as I understand it, the earliest that I can send the Midi message out is at the beginning of the next processBlock.

If an event happens mid-processBlock I can’t magically get it into the currently playing one. I have to wait for the next processBlock to start.

But once I’m in the next processBlock. The sooner I send the message out, the less lag there is.

Or am I misunderstanding something?

Sure, but the buffer is 200ms long, you’d be sending out sudden bursts of messages every 200ms, which is going to sound pretty crappy depending on what these messages are.

If your messages are generated then you should be able to work out their timing correctly. If they’re coming in from a live source you can juce::MidiMessageCollector to help to reschedule them evenly.

Is the buffer not the same as the buffer you set the size of in the DAW then? I though it was something you could choose the length (and therefore frequency) of.

You’re saying you basically get 5 processBlocks per second?

I’m saying you get N blocks per second, where N is unknown.

1 Like