# Block-based midi processing in a right way?

**URL:** <https://forum.juce.com/t/block-based-midi-processing-in-a-right-way/11876>\
**Category:** Audio Plugins\
**Created:** [November 18, 2013, 6:27am UTC](https://forum.juce.com/t/block-based-midi-processing-in-a-right-way/11876 "2013-11-18T06:27:26Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![mikeg](https://avatars.discourse-cdn.com/v4/letter/m/3ec8ea/32.png) [@mikeg](https://forum.juce.com/u/mikeg)\
**Post date:** [November 18, 2013, 6:27am UTC](https://forum.juce.com/t/block-based-midi-processing-in-a-right-way/11876/1 "2013-11-18T06:27:26Z")

</div>

Is&nbsp;MidiMessageCollector is somehow useful in midi processing or is it just for JUCE's internals?

I need a structure to accumulate&nbsp;midi events produced by a plugin that I'll then pass to host (MidiBuffer) according to block's sample offset on a per-block basis.

I currently use MidiSequence and it's not so good in per-block-processing or maybe I use it in a wrong way.

---

<div class="post-metadata">

**Author:** ![jules](https://avatars.discourse-cdn.com/v4/letter/j/41988e/32.png) [@jules](https://forum.juce.com/u/jules)\
**Post date:** [November 18, 2013, 9:16am UTC](https://forum.juce.com/t/block-based-midi-processing-in-a-right-way/11876/2 "2013-11-18T09:16:59Z")

</div>

What could I tell you that isn't already explained in the class's comments? It does what exactly it says it does - i.e. collects messages and packages them into blocks. Whether or not that's useful for what you're doing depends on what you're doing!

---

<div class="post-metadata">

**Author:** ![mikeg](https://avatars.discourse-cdn.com/v4/letter/m/3ec8ea/32.png) [@mikeg](https://forum.juce.com/u/mikeg)\
**Post date:** [November 18, 2013, 1:05pm UTC](https://forum.juce.com/t/block-based-midi-processing-in-a-right-way/11876/3 "2013-11-18T13:05:00Z")

</div>

I have an idea for a midi effect plugin, but as in any case I need to start from the basics tasks.

So, the first tasks i put on myself is to do&nbsp;a simple midi-arp functionality like this:  
1. plugin receives midi msg note-on (C3 - for example)  
2. plugin produce (1/16 - for example) midi note (C3) on/off msgs and sends them to host constantly&nbsp;  
while input midi msg note-off (C3) not received.

```
midi event : on off on off
plug's input : C . . . . C C - C      
plug's output: C . C . C . C . C (1/16th notes)
```

**I'm struggling to find the right structure to hold produced midi messages, so it will be use to use it in a processBlock() to forward them&nbsp;to host.&nbsp;**

(currently I store produced&nbsp;midi messages in a MidiMessageSequence, but I have problem with keeping right offset)

For icoming midi messages I have in-house MidiReceiver class that handles all the necessary info (pressedKeysNumber, lastNoteNumer, lastVelocity, lastNoteOffSamplePos, etc...) that a plugin will need to interpret.

&nbsp;

Here is my processBlock() and&nbsp;it looks/works not good:&nbsp; ![smiley](http://www.juce.com/sites/all/libraries/ckeditor/plugins/smiley/images/regular_smile.gif "smiley")

```
void MyPluginAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
    const int blockSamples = buffer.getNumSamples();

    // TODO: clean this...
    double noteMiliseconds = (60000.0 / lastPosInfo.bpm) * rate;
    double samplesPerMilisecond = getSampleRate(); 
    samplesPerMilisecond /= 1000.0;
    int noteSamples = noteMiliseconds * samplesPerMilisecond;

    // Now pass any incoming midi messages to our keyboard state object, and let it
    // add messages to the buffer if the user is clicking on the on-screen keys
    keyboardState.processNextMidiBuffer (midiMessages, 0, blockSamples, true);

    // track incoming midi messages...
    midiReceiver.onMessagesReceived (midiMessages);
    midiMessages.clear();

    // This is the place where you'd normally do the guts of your plugin's
    MidiMessage midiMsg (0xf0);
    int midiMsgPos = 0.0;

    // reset offset on the first pressed key...
    if (midiReceiver.getFirstNoteOnSamplePos() >= 0)
    {
        offsetSamples = midiReceiver.getFirstNoteOnSamplePos();
        midiReceiver.setFirstNoteOnSamplePos (-2); // set to undefined state
    }

    // clear midi sequence events after last key was released...
    for (int i = 0; i < midiSequence.getNumEvents(); ++i)
    { 
        midiMsg = midiSequence.getEventPointer(i)->message;
        midiMsgPos = midiSequence.getEventTime(i);
        if (midiMsgPos > midiReceiver.getLastNoteOffSamplePos())
        { // after last key was released...
            if (midiMsg.isNoteOff())
            {
                midiMessages.addEvent (midiMsg, midiReceiver.getLastNoteOffSamplePos());
            }
            midiSequence.clear();
            midiReceiver.setLastNoteOffSamplePos (INT_MAX);
            break;
        }
    }

    // add new events to midi sequence...
    if (midiReceiver.getPressedKeys() > 0 && midiSequence.getNumEvents() == 0)
    { 
        midiMsg = MidiMessage::noteOn (1, midiReceiver.getLastNoteNumber(), midiReceiver.getLastVelocity());
        midiSequence.addEvent (midiMsg, offsetSamples);
        offsetSamples += noteSamples;
        midiMsg = MidiMessage::noteOff (1, midiReceiver.getLastNoteNumber());
        midiSequence.addEvent (midiMsg, offsetSamples);
        offsetSamples += noteSamples;
        midiSequence.updateMatchedPairs(); // connect the note-on and note-off messages 
    }

    // add midi sequence's events to midi buffer and update offsetSamples of events...
    for (int i = 0; i < midiSequence.getNumEvents(); ++i)
    { 
        midiMsg = midiSequence.getEventPointer(i)->message;
        midiMsgPos = midiSequence.getEventTime(i);
        if (midiMsgPos < blockSamples)
        { // event should appear in current block
            midiMessages.addEvent (midiMsg, midiMsgPos);
            midiSequence.deleteEvent (i--, false);
            // TODO: update event's offsets (and offsetSamples?)
            midiSequence.updateMatchedPairs();
        }
        else
        { // advance midi sequence's events to next block
            midiSequence.addTimeToMessages (-blockSamples); // TODO: update event's offsets (and offsetSamples?)
            midiSequence.updateMatchedPairs();
            break;
        }
    }
}
```

---

<div class="post-metadata">

**Author:** ![mikeg](https://avatars.discourse-cdn.com/v4/letter/m/3ec8ea/32.png) [@mikeg](https://forum.juce.com/u/mikeg)\
**Post date:** [November 18, 2013, 1:57pm UTC](https://forum.juce.com/t/block-based-midi-processing-in-a-right-way/11876/4 "2013-11-18T13:57:00Z")

</div>

People, please help! ![smiley](http://www.juce.com/sites/all/libraries/ckeditor/plugins/smiley/images/regular_smile.gif "smiley")

---

<div class="post-metadata">

**Author:** ![oxxyyd](https://avatars.discourse-cdn.com/v4/letter/o/e47c2d/32.png) [@oxxyyd](https://forum.juce.com/u/oxxyyd)\
**Post date:** [November 18, 2013, 4:12pm UTC](https://forum.juce.com/t/block-based-midi-processing-in-a-right-way/11876/5 "2013-11-18T16:12:00Z")

</div>

My first advice is refine and concentrate on the main thing which as I understand is the arpegiator. Skip all other stuff like keyboardstates etc. until later.

I haven't worked on any midi plugins myself but this is how I would go about it:

1. In processBlock, wait for a note-on event.
2. When received, record its samplePos and add ½ second (44 100/2 = 22 050)&nbsp;
3. Wait for the frame that contains this samplePos
4. Add a note-on event to the MidiBuffer and another 22 050 to the samplePos
5. Wait for the frame that contains this samplePos
6. Add a note-off event to the MidiBuffer and another 22 050 to the samplePos
7. Goto 3.
8. Loop until a note-off is recived, add a note-off event to MidiBuffer if the last event added was a note-on, then go back to 1.

samplePos is a running counter that you increment w buffer.getNumSamples() for every processBlock call.

Make this work for any single key. Then make it work various bpm's (that should alter the ½ seconds). Then make it work for several simultaneous keys, different velocities etc.

&nbsp;

---

<div class="post-metadata">

**Author:** ![mikeg](https://avatars.discourse-cdn.com/v4/letter/m/3ec8ea/32.png) [@mikeg](https://forum.juce.com/u/mikeg)\
**Post date:** [November 19, 2013, 1:32pm UTC](https://forum.juce.com/t/block-based-midi-processing-in-a-right-way/11876/6 "2013-11-19T13:32:00Z")

</div>

My head feels better now so&nbsp;I'll have to rethink my processBlock().&nbsp; ![smiley](http://www.juce.com/sites/all/libraries/ckeditor/plugins/smiley/images/regular_smile.gif "smiley")
