Performing a function with sample accuracy using processBlock

Let’s say I want to something to occur at a frequency of 1 bar. The common advice is to count samples in the process block like the following

AudioPlayHead::CurrentPositionInfo pos;
	if (getPlayHead() != 0 && getPlayHead()->getCurrentPosition(pos))
	{
		const int numSamples = buffer.getNumSamples();
		
		const auto timeInSamples = pos.timeInSamples;
		const auto samplesPerBeat = int64(sampleRate * (60 / pos.bpm));
		const auto onBarSample = 4 * samplesPerBeat;

		const int64 linearSamplePos = timeInSamples % onBarSample;
		const int64 samplesBeforeLoop = onBarSample - linearSamplePos;

		if (samplesBeforeLoop <  numSamples)
		{
			// Do something at samplesBeforeLoop
		}

	}

But this only tells me at what sample position in the current buffer something will happen. How would I go about scheduling something to happen at that sample position in real time? Like looping my own playhead or something.

it’s easier to do this with the project position’s ppq instead of timeInSamples, because that yields a number where every integer is a full quarter note. so you can write ppq - floor(ppq) to get a number between 0 and 1 that represents where in this quarter note you are. that looks an awful lot like a phasor of an oscillator so you can write code around that that takes this phase value and just moves on. you need to take the bpm into account for that. i keep having to look up the exact formulas myself, but it’s not too hard. once you have a phasor you can just take the moment where it wraps from 1 to 0 and take that as your trigger moment.

tipp: output the phasor as audio signal so you can use an oscilloscope in your debug daw to check if it works correctly visually.

now you can just multiply the ppq with some value before doing ppq - floor(ppq) in order to use different beat values than quarter notes. for example ppq * .25 is a full bar. increment speed also then has to be adjusted to work with the new setting. that’s why i would suggest implementing this without variable speed first.

2 Likes

Be aware of some DAWs not providing ppq, timeInSamples is generally accepted to be provided by all DAWs. Also, some DAWs provide -ve ppq values (Logic does when looping iirc, or was it Bitwig - one of them, anyway) so needs to be taken into account.

1 Like

Thanks for the replies @Mrugalla and @leehu . I really appreciate you taking the time to understand my question and providing a solution!

I’m quite at a loss for dealing with the ppqPosition. Can you point me in some general direction for creating phase signal using the ppqPosition?

rateSync is the speed parameter here. it looks a bit more complicated than a start implementation should look like because of latency and parameter smoothing, but basically this

1 Like

I’ll give it a shot and see how I get on with it. Thanks again @Mrugalla! :slight_smile: