Question about Pulses-per-quarter note

Hello there. I’d like to measure where I am relative to the tempo grid each block so that I can sync up certain parts of my audio generation. AudioPlayHead::CurrentPositionInfo measures this in pulses-per quarter note (ppq). I’m told that Logic has a resolution of 960 ppq, but I’m guessing that I can’t rely on this in other hosts. So how can I find out how many of these units there are per quarter note, and by extension, where I am on the grid at any time?

juce::AudioPlayHead::CurrentPositionInfo is the only option. As for where the play-head is located in a timeline, you can use time in samples, seconds and ticks (aka PPQ). Obviously a bunch of math is involved, but trickery is required for syncing to measures; you’ll need to use the current tempo and time-signature, too, since they’re are all interrelated.

Edit: It’s probably safe to assume that a DAW with MIDI and plugin support will support sending positioning in ticks to its plugins.

Well the assumption that it’s always 960 is wrong, it can be changed and many DAWs offer such a change. The position is reported in ppq but it’s up to you to decide what’s the resolution in the host, JUCE does not provide any means to fetch that value, neither does VST (i don’t know about AU/AAX).

Ah, I just realised I was being stupid. In CurrentPositionInfo we have time in seconds since the last edit, ppq since last edit, and tempo. From this, we can work out the resolution of ppq. Then we have the ppq since the last bar, from which we can work out the position relative to quarter notes. A bit convoluted, but it should work. Thanks.

AAX does but it’s not used in juce… But simple to get through the AAX API. Believe it always returns 960 though.

Rail

For what it’s worth, I’ve banged my head against this brick wall and came out on top…

Here’s what I’ve learned. I’ve tested this in Logic Pro X and REAPER and it holds up.

For the PPQ values provided in the CurrentPositionInfo struct it is simpler than I first thought.

The PPQ value is a double where the whole integer part (i.e. left of the decimal point) represents whole quarter notes.
The “remainder” (i.e. to the right of the decimal point) represents how far the current location sits in between the whole quarter notes either side of it.

In this sense, the actual resolution of an individual DAW doesn’t come into it. That is, you don’t need to know the DAW PPQ resolution to be able to resolve a location to a quarter note, 8th note, 16th etc.

So, for example for these ppqPostion values:
2.0 means at the start of the 2nd quarter note since the start of the project/edit.
2.5 means at the start of the 2nd 8th note after the 2nd quarter note.
3.75 means at the start of the 4th 16th note of the 3rd quarter note.

Hope this info helps someone.

4 Likes

Thanks adcingeo! Been looking into this recently and I’ve had the same findings.

1 Like

I think this code works

double BasicMidiPlugin::getBarPhase() { return (positioninfo.ppqPosition - positioninfo.ppqPositionOfLastBarStart) * 0.25; }

double BasicMidiPlugin::getPhaseBasedOnBarsPerCycle(double barsPerCycle)
{
	jassert(barsPerCycle > 0);

	if (barsPerCycle <= 1)
	{
		return fmod(getBarPhase(), barsPerCycle) / barsPerCycle;
	}
	else
	{
		int barLengthsPassed = floor((positioninfo.ppqPositionOfLastBarStart*0.25) / barsPerCycle);
		return fmod(getBarPhase() + barLengthsPassed, barsPerCycle);
	}
}

Both functions return 0 to 1, so you could, for example, have an oscillator with a frequency that cycles every 1 bar or 1/4 bar (quarter note), then use these functions to update the phase of the oscillator if needed.