How can I tell when I've read all the MIDI events for a particular point in time?

I want to create a MIDI-to-MIDI plugin that accepts a sequence of chords and outputs just the
lowest note in each chord. I have studied the following MIDI plugin example and got the example working too:

JUCE/ Tutorial/ Create a basic Audio/MIDI plugin, Part 2/ Coding your plug-in

However, I’m puzzled by one aspect of what I am trying to achieve. I’d like my plugin to be able to accept 2-note chords, 3-note chords, 4-note chords, and, in general, N-note chords. Each chord will arrive as a cluster of MIDI events but all with the same timestamp (I assume). My code will read the chord by reading MIDI events from a MIDI input buffer, as does the code in
the above example.

My question is: How can my code determine that it has read all the MIDI events in the chord?More technically, if it reads one or more notes at time T, how can it be sure that it has read ALL the notes at time T, given that the plugin does not know how many notes are in the arriving chords?

The obvious solution is to wait until a MIDI event arrives that has a LATER time. But this will probably be the first note in the NEXT chord at the start of the next bar. By the time my plugin has seen this event, it will be way too late in real time to output the lowest note of the previous chord.

Should I somehow wait until the next AUDIO time unit passes, and then check the MIDI buffer?

Is there a JUCE call I can make to say “I’ve received one MIDI event. Please give me ALL the other MIDI events that are arriving at this exact same time”?

If this problem is NOT solvable, I guess I’ll have to add a setting to my plugin so that they
user can specify how many notes are going to arrive in each chord, and then the code can
simply wait for that many events to arrive in each round.

Another approach is for the code to observe the arriving chords and count how many notes are in each chord and wait for only that many each round. However, this will mean that the plugin will fumble the very first chord.

Can anyone help me address this issue?

I don’t think your plugin should care about which notes are played “together”. Mainly because your plugin will need to handle the case where a note is played and held, then another (higher or lower) note is played and held, and then yet another (higher or lower) note is played, etc. Also because a human player won’t always start playing them at the exact same time even if they intend to.

From the documentation of AudioProcessor::processBlock:

   If the processor is receiving a MIDI input, then the midiMessages array will be filled
   with the MIDI messages for this block. Each message's timestamp will indicate the
   message's time, as a number of samples from the start of the block.

This means 2 things:

  • the input MidiBuffer can contain MIDI events that didn’t arrive at the exact same time. There can be a MIDI event associated with the first sample of the block, and another MIDI event associated with the last sample of the block. These MIDI events don’t have the same time.
  • the input MidiBuffer of the current call to processBlock contains MIDI events that are arriving before the ones of the next call to processBlock. Any MIDI event that your plugin will process in a subsequent call of processBlock is by definition coming later. So within the processBlock function, your plugin already sees all MIDI events for a particular point in time.

I hope this will help you get started. Don’t hesitate to ask more specific questions (for instance, about how to keep track of which notes are playing).

McMartin: Thanks. I’ve read your reply carefully. My plugin is mainly for the case where a bunch of chords created in Ableton Piano Roll are coming into the MIDI plugin, so inaccuracies are not a huge concern. This said, I would like to make the plugin work with human players too.

The most important thing you seem to have told me is that the set of times in each processing block are disjoint. That is, you won’t receive a processing block with a MIDI event at time T and then another processing block with a MIDI event at time T. Each sample moment will appear in exactly one processing block. That’s very helpful to know, and answers my question.