MidiMessage::allNotesOff() question

Hi all,
I am playing around trying to build a midi plugin.
In previous plugins I kept my own array of notes that had been played to stop hanging notes.
I have been trying to utilize this allNotesOff method. It might save a bit of code but I can’t get it to work.
AllSoundOff() works but creates a clicking sound with most vst instruments I assume because the release part of the instrument doesn’t occur.
Can someone explain to me why this bit of code doesn’t generate any note offs ?
Can I just write a function that iterates through all 127 notes and generates note offs?
Would that be any slower than this method which I can’t get working?

void WayloChordAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer& midiMessages)
{
    ScopedNoDenormals noDenormals;
    auto totalNumInputChannels  = getTotalNumInputChannels();
    auto totalNumOutputChannels = getTotalNumOutputChannels();
    for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
        buffer.clear (i, 0, buffer.getNumSamples());

    MidiBuffer processedMidi;
    int time;
    MidiMessage m;
    int chordLength = 3;
    for(MidiBuffer::Iterator i (midiMessages); i.getNextEvent(m, time);)
    {

        if(m.isNoteOff())
        {
            MidiMessage n = MidiMessage::allNotesOff(m.getChannel());
            processedMidi.addEvent(n, time);

        }
        else if(m.isNoteOn()) {

            for (int i = 0; i < chordLength; i++) {

                int interval = 60 + i * 12;
                MidiMessage p = MidiMessage::noteOn(m.getChannel(), interval, m.getFloatVelocity());
                processedMidi.addEvent(p, time);
            }
        }

    }
    midiMessages.swapWith(processedMidi);
}

Any ideas?
Sean

No idea why it would not work; I use allNotesOff all the time and never had an issue. AFAIK the implementation just loops over all notes and does sends a noteOff event - so yeah you might implement it yourself and should not be any slower. Search the Juse codebase for the definition of allNotesOff and you’ll find it’s just a loop over all channels and all notes to generate the noteOff events.

You assumption about clicks is strange - the release DOES happen after noteOff - that’s the definition of release :). So if you have a very long release, allNotesOff would not silence the sound for a while. I typically use allNotesOff for Midi drum and piano effects; I have never experienced clicks. Can’t vouch for just any VST though.

thanks tomto.
Its AllSoundOff() that works with clicks. It sends a mute message to all midinotes. I haven’t figured what is happening with allnotesoff()
I think I will try writing my own one and seeing what happens…
Sean

Do you test your plugin on Ableton Live?
I don’t remember well, but I think I had similar situation on Ableton before.

And when you stop Ableton’s host sequencer, it will send midi cc 123(all note off) to midi tracks automatically.
You can check this behavior with M4L midi monitor.

My bad. I can see why allSoundOff() might create a click. allNotesOff() should work though. If you have a midi monitoring function in your Daw you should be able to see the noteOff events begin generated. Did you try that?

allNotesOff is not supported in all synth plugins. At the moment of writing this: Spire and Serum don’t support it for all channels. I wrote to Spire and they said they are planning to add it soon. I wrote to Serum and it may also be added in the next beta (it only works well for channel 1 in the last version I tried). The obvious hack is to send NoteOff messages to every note and every channel, however Ableton is only able to route midi tracks with one channel.

That is not correct. allNotesOff is a specific midi message (with a different MIDI code than NoteOff). Most DAWs don’t transform it into NoteOffs. Actually I can’t think of anyone that does.

1 Like

You’re right of course. What I meant to say is that in some DAWs a midi monitoring function might let you see whether the allNotesOff message is actually output to the plugin.

Aah I think that’s the issue here.
http://duc.avid.com/showthread.php?t=396432&page=4
I thought the allNotesOff was a JUCE method that actually sent 127 noteOff messages. I suspect the native instrument synths and/or cubase don’t deal with it … Another issue to raise with the midi organisation. So many troubles with DAWs dealing with midi. It’s supposed to be standard but every DAW and VST plugin treats it differently. Looks like I should write my own allNotesOff method … I guess I have to figure out how to pass a midibuffer into a function … Anyone done that?

In the context of your original post, tracking note-ons/note-offs is the most efficient/elegant way of keeping from having stuck notes. Sending 127 note-offs should really only be used as a reset/panic function.

thanks yeah looks like I am back to an array of note-ons playing which gets cleared by note-offs when a note off is played.

Did some digging … FWIW here’s how Juce does this in the MidiMessage class:

MidiMessage MidiMessage::allNotesOff (const int channel) noexcept
{
    return controllerEvent (channel, 123, 0);
}

MidiMessage MidiMessage::allSoundOff (const int channel) noexcept
{
    return controllerEvent (channel, 120, 0);
}

BUT … in MidiKeyboardState it’s implemented as

void MidiKeyboardState::allNotesOff (const int midiChannel)
{
    const ScopedLock sl (lock);

    if (midiChannel <= 0)
    {
        for (int i = 1; i <= 16; ++i)
            allNotesOff (i);
    }
    else
    {
        for (int i = 0; i < 128; ++i)
            noteOff (midiChannel, i, 0.0f);
    }
}

This is just a recursive function to call noteOff because every key of the MidiKeyboardComponent has to be cleared anyway. This is specific to the MidiKeyboardComponent.

Correct; OP can do something similar if he wants to implement his own allNotesOff()

For the record I ended up doing this in my plugin and it worked fine …

            else if (m.isNoteOff())
          
            {
                for (int i = 0; i < 128; ++i){
                    m = MidiMessage::noteOff(m.getChannel(), i, 0.0f);
                    processedMidi.addEvent(m, time);
                }

Thanks everyone for your help !!