Getting accurate time from DAW with tempo changes

Hi,

I’m working on a plugin that uses Elastique to stretch audio based on tempo changes in the DAW. When I start playback from the beginning of the DAW timeline, the timeInSeconds value that I receive from the DAW (through AudioPlayHead::CurrentPositionInfo) is accurate and works well. However, if I start playback from elsewhere in the timeline I get a different value for timeInSeconds.

For example, if I play from the beginning, then at bar 8 the timeInSeconds value is 20.89, but if I start playback at bar 7, then at bar 8 the timeInSeconds value is 21.45. Shouldn’t it always return the same value for a given position regardless of where I started playback?

If not, is there some other way I can calculate the timeInSeconds at bar 8 that will be the same regardless of where I start playback? Does anyone have advice for getting accurate playback position when there are tempo changes in the DAW?

OK I’ve figured out my problem and now have correct timing (using ppqPosition) for syncing playback with the host. One issue I’m dealing with now is that at the tempo change, there is an audible glitch because of the updated ppqPosition.

What is the suggested way to resolve this discontinuity? I’ve looked at juce’s SmoothedValue class but am unsure if I should use it or how I would use it.

Does anyone have a suggestion for how I can improve glitches with ppqPosition when the tempo has changed in my DAW?

1 Like

Which DAW are you using and have you tried with other ones? It sounds like a DAW bug actually, as I think the host should report the correct time. I’m not sure about the exact mechanism that the information is collected, but I think it’s just a matter of the plugin asking it from the host. If the host reports it wrong, you’ll have a hard time working around that I guess. If you had access to the complete tempo list, you could work it out yourself, but I don’t think there’s a way right now to get the list.

That said, if it’s a DAW bug it is likely that a different DAW will get it right.

Thanks hugoderwolf!

The DAW that I’ve been testing with is REAPER which is typically a well-behaved DAW. I’ve tried other DAWs and get similar results. Starting playback from the beginning of the timeline will always work using timeInSeconds for syncing my audio source, but starting after a tempo change will result in the audio not syncing correctly.

Changing timeInSeconds to seconds calculated with the ppqPosition fixes the syncing issue but introduces small audio glitches at the tempo change position because ppqPosition will jump when the tempo changes. I’m assuming that there is no way to make timeInSeconds work so I’m using ppqPosition and applying a small gain ramp when the tempo changes.

If there was a way that I could continue to use timeInSeconds reliably, I would prefer to do so because there is no jump so the audio always sounds smooth regardless of any tempo change

Hmm, the PPQ position is not supposed to jump on tempo changes! If it does, clearly something somewhere is going wrong (probably computing the PPQ position from sample position, but based only on the current tempo).

Yes that’s exactly it. I’m computing the position in seconds from PPQ like this:
(ppq * 60.0) / bpm

When there is a tempo change, the resulting value jumps to a new position in seconds which is what causes the audible glitch. The only thing I could think of to mitigate this is to try smoothly transitioning to the new bpm.

Are there any other solutions that I could try?

tempo can change over time.
that means that you can’t assume that the time in seconds is a simple function of the ppqn and instantaneous tempo.
For example, if 10 seconds into a song the tempo doubles, it would clearly be wrong to calculate the elapsed time as now being 20 seconds.

Thanks Jeff,

I understand what you’re saying but I was still surprised that the timeInSeconds value I receive from the DAW for a particular spot appears to be different depending on where I start playback from. I’m guessing that the small discrepancy (0.0046 seconds) occurs because the DAW may be interpolating timeInSeconds slightly differently depending on when playback starts, especially if the tempo map involves subtle rounding or time adjustments.

What I want is a timeInSeconds value that ignores tempo changes because I am handling them internally by applying my own stretch factor.

One solution that appears to be working for me is to use an internal mechanism for determining the playback position. This is how it works:

//When host playback starts
startPosition = Time::getMillisecondCounterHiRes() * 0.001 - ((positionInfo.ppqPosition * 60.0) / positionInfo.bpm);

//during processBlock calls
currentPosition = Time::getMillisecondCounterHiRes()*0.001 - stateInfo.transports.startPosition;

I handle seeking and stop/starts myself, and for my purposes this seems to be the best approach.

That’s quite hacky and only works in realtime, also many hosts do some nasty things when just starting (pre-rolling and that kind of stuff). Does it actually give you better accuracy this way?

If you want to measure the time elapsed from some reference point in time, you’ll be better off simply counting samples in processBlock().

Thanks hugoderwolf. You were absolutely right—counting samples in processBlock() turned out to be a much more reliable and accurate solution. It resolves the issues I had with timing inaccuracies, especially during pre-roll and other edge cases where hosts behave unpredictably.

The previous approach worked reasonably well for basic real-time playback, but this new method ensures precise alignment regardless of the host’s behavior. I appreciate you pointing me in the right direction!