Midi note rhythm generation inaccuracies

Hi all!
I need to generate quarter notes, eighth notes, sixteenth notes, etc. in my midi plugin. I made a simply algorithm for this and it works perfectly in the Reaper DAW, but for some reason there are inaccuracies in the Ableton, maybe someone knows what could be the matter?

    currentBufferStartInSamples = *playhead->getPosition()->getTimeInSamples();
    double bpm = *playhead->getPosition()->getBpm();
    rateInHz = (bpm / 60.0) * rateInNotes;
    periodInSamples = (1.0 / rateInHz) * getSampleRate();
    
    isPlaying = playhead->getPosition()->getIsPlaying();
 
    for(int sample = 0; sample < buffer.getNumSamples(); ++sample)
    {
         if( ((currentBufferStartInSamples + sample ) % (periodInSamples)) == 0 )
               midiBuffer.addEvent(mm.noteOn(1, 64, 1.0f), sample);
    }
       

I will be very grateful for any help! does anyone know a prettier way to do what i’m trying to implement?

i’d not use timeInSamples for this, but ppq, cause it’s about musical time intervals rather than time itself. ppq - floor(ppq) will always give you a number between 0 and 1 that describes where in a certain beat you are so you can connect this information with a phasor, which could trigger the addEvent whenever it flips back to 0. you can multiply ppq with some value to change the speed of the phasor. the increment value of the phasor is calculated in a similiar way as you already do, too

1 Like

Thank you, but how will I be able to do it with sample accuracy? I can only detect PPQ once per buffer… Maybe I didn’t quite understand your idea correctly?

that’s why i suggested syncing up your ppq and bpm data with a phasor. a phasor, as you might know, is a dsp object that just ramps from 0 to 1 continuously. they are often used in oscillators to define where to read from the wavetable and stuff like that. so you’d just have to write the math that uses ppq, bpm and your rate parameter value to get the correct phase and increment value for the phasor and then it works. everytime the phasor goes back from 1 to 0 you know you’re exactly on some beat.

the phase is defined by = ppq * .25 / rateSync with rateSync being some values like .5, 1, 2 etc, you know, whatever describes the change in speed compared to a quarter note. probably what your “rateInNotes” variable does too.

and the increment value for the phasor is = 1 / (barLength * rateSync) with barLength being quarterNoteLength * 4, with quarterNoteLength being sampleRate / beatsPerSec with beatsperSec being bpm / 60

3 Likes

Thanks! Now I figured it out and everything works perfectly!

2 Likes

Great thread - @Froggo-Lab, any chance you can give us more details of how you got this sorted?

3 Likes

@austrianaudioJV
something like this

double twoPi = MathConstants<double>::twoPi;
double sampleRate = getSampleRate();
double ppq = std::fmod(*playhead->getPosition()->getPpqPosition() * 0.5 * twoPi, twoPi);
double beatsPerSec = bpm / 60;
double quarterNoteLength = sampleRate / beatsPerSec;
double barLength = quarterNoteLength * 4;
double phasorIncrement = (twoPi / barLength) * rateInNotes * 0.5;
phasor.phase = std::fmod(ppq * 0.25 * rateInNotes, twoPi);

for(int sample = 0; sample < buffer.getNumSamples(); ++sample)
{
    phasorCurrentValue = phasor.advance(phasorIncrement);
    
    if(phasorCurrentValue - phasorIncrement < 0 && phasorCurrentValue + phasorIncrement > 0)
    {
        midiBuffer.addEvent(mm.noteOn(1, 64, 1.0f), sample);
    }
}
4 Likes

Great stuff, thanks for the concise snippet - definitely proves inspiring for future MIDI work …

1 Like

Thanks for details @Froggo-Lab, will be very useful. Have you tested this in Logic?

I’m just about to start work on a new MIDI plugin and was slightly concerned by this thread : Syncing to getPosition() issue

Haven’t got around to it yet, but will be starting soon, so haven’t been able to test myself as yet.

1 Like

At the moment, I checked only in Reaper and Ableton. If you try Logic and find problems, please write here

1 Like