timeInSamples increments not consistent with getNumSamples() in VST3

I’m having a severe problem with VST3 implementation of a plugin.
processBlock() is been called, consistently with a buffer size of 512 samples, but the timeInSamples increments from getPlayHead()->getCurrentPosition(pos) changes from 511 to 513.

I’m logging getNumSamples(), and timeInSamples in every processBlock() call - so I’m sure the buffer size don’t change from call to call (yes, I know that host may change the buffer size - but is not this case).
Unfortunately, the increments I get in timeInSamples are not coherent with buffer sizes.

Any suggestions, besides trying to detect such incoherencies and overwrite timeInSamples values?

Which host?

Unfortunately, there’s not much can be done about something like this - the host generates that number in whatever way it sees fit…

I’m having this issue with Reaper (I haven’t tested with others)…
I believe that it could be some sort of rounding/truncating bug or similar.
VST works fine.

Yes, probably a rounding error, but we just copy the number that the host provides straight into that struct - if it’s wrong then there’s no chance for the juce wrapper to do anything about that.

beware that timeInSamples is also totally wrong in ableton live when the tempo is automated (IIRC)

I would keep own sample counter in the processor class just to be sure. Initialized when playback is started or when playback position is changed.

What is the best way to detect such events?
Start playing? (first isPlaying == true?)
Stop playing? (first isPlaying==false?)
Position changed during playing?
Position changed while stopped?

Hi all!

As it seems I face the same issue with VST3 in Ableton Live 10.1.4 because “timeInSamples” might be +/-1 sample off the expected value.
I verified that the samplesPerBlock size has not changed (“prepareToPlay” is not called again during playback).
This is tested with different VST3 SDK version (VST v3.6.7 with JUCE v5.2.1 and VST v3.6.13 v5.4.4 JUCE) and the problem persists.

I was not able to reproduce with other DAWs (e.g Reaper 5.9) so I guess that is a DAW specific issue.
However, as the plugin engine state should reset when the playhead jumps I need to track the DAW playhead position and this bug makes the engine reset unexpectedly.

Has anyone found a good solution to catch any playhead jumps bearing in mind this problem?

Here is an example code snippet that I wrote to catch playhead jumps.

void NewProjectAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer& midiMessages)
{
    ScopedNoDenormals noDenormals;
    auto totalNumInputChannels  = getTotalNumInputChannels();
    auto totalNumOutputChannels = getTotalNumOutputChannels();

    for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
        buffer.clear (i, 0, buffer.getNumSamples());

    AudioPlayHead::CurrentPositionInfo position;
    if (playHead)
    {
        playHead->getCurrentPosition(position);
        int64 currentDAWSamplePosition = position.timeInSamples;
        int64 expectedDAWSamplePosition = previousDAWposition + previousBufferSize;
        bool areSamplesEqual = currentDAWSamplePosition == expectedDAWSamplePosition;
       
        if (! areSamplesEqual) {
            // reset engine state
        }

        previousDAWposition = position.timeInSamples;
        previousBufferSize = buffer.getNumSamples();
    }
}

I added previousDAWposition and previousBufferSize class variables and use them to calculate the expected sample position during the next process callback. Has anyone tried another approach to catch these playhead jumps considering the bug in Ableton Live 10?

Can I ask why Juce manipulates TimeInSamples to 0 in VST3? A negative number would seem valid for prerolls and can occur when looping back to the start also.

We came across this problem as well, and so we modified the JUCE SDK, and added a new member (actualTimeInSamples) that doesn’t limit to 0. I see no reason for limiting it to 0.

Also, when checking if there was a jump or loop, we compare to within 1 sample, instead of for equality.

1 Like

Thanks Howard, yes seems odd and I’m going to alter it too to solve since timing is thrown with it like this. Must be an oversight that has stuck.

I did notice that ppqPosition correctly relays negative values and it is possible to calculate time in samples from that, though I’m not fully sure of the precision there but maybe it is the more popular approach since I think it has been around or at least supported longer.

Will note that re jumps too.