Host sync noteon noteoff

Hi, I am working on creating a vst plugin and ultimately, I would like to be able to create some midi messages, note ons, to generate some sound, without the user giving any input. It is kind of a test, for me to learn how all of the juce framework works. My goal, is to create a sound that is kind of like a metronome, and when I start the transport playing, I would like my note ons to generate a sound for each quarter note pulse. I am using some of the audio play head information and it appears to give me everything I need. My question is this. So if the processBlock() is being called many, many times in a second, and I manually create a noteon, how should I generate a noteoff? It seems like if you wanted your noteon to ring for a quarternote duration or any duration really, you're going to need to send a noteoff message to trigger in the future. That is if you create your noteon and noteoff in the same processblock call, you would have to set the noteoff to trigger in the future so your note will have some duration to it. Does this make sense? But it seems like it is a bit tricky, because in theory, a future processblock call could execute your noteoff message, but how would you do it? I think you would have to manually load your noteoff message in the same processblock call, but I am unsure of exactly how to do it. Thanks for the help.

In your processblock(AudioSampleBuffer& buffer, MidiBuffer& midiMessages) you would add the midi message with

midiMessages.addEvent(msg, samplesToWaitFromStartOfBlock);

buffer.getNumSamples() gives you the number of samples in the block. Setting samplesToWaitFromStartOfBlock to 0 means the event (note on e.g) will play at the start of the processblock, that is at the exact time as the first audio sample in the AudioSampleBuffer would play (if you have any samples in there). Setting it to buffer.getNumSamples() - 1 will make it play at the end of the block. Setting it to a larger value won't make it play at all. If you want it to play later you will just have to wait for later buffer to add it.

Have a look at the example below. This will play the same note every 2 seconds with a duration of 1 second.

 

void MySourceProcessor::processBlock(AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
    static int noteOn;
    static int samplesToNextMidiEvent;

    int noteNumber = 60;        //play middle c
    float velocity = 1.0;    //play max velocity
    int numSamples = buffer.getNumSamples();

    if (samplesToNextMidiEvent < numSamples)  //time to play the event yet?
    {
        MidiMessage msg;

        if (noteOn ^= 1)
            msg = MidiMessage::noteOn(1, noteNumber, velocity);
        else
            msg = MidiMessage::noteOff(1, noteNumber, 0);

        //here samplesToNextMidiEvent is between 0 and numSamples-1 and controls when
        //the midi event will play: 0 at start of the processblock, numSamples-1 at the end of processBlock
        midiMessages.addEvent(msg, samplesToNextMidiEvent);

        samplesToNextMidiEvent += 44100;   //the next midi event will play in exactly 1 second (assuming a samplerate of 44100)
    }

    samplesToNextMidiEvent -= numSamples; //count down with the number of samples in every processblock
}

 

1 Like

Thanks for the help. I will try this.

Thanks a lot for your help. I was able to get it to work using your example. I will keep studying your code so that I can have a solid understanding of how this is all working. Thanks for your help.