How to detect the playback is continuous

Hi! I want to detect if the playback is ‘‘continuous’’ from the plugin (continuous: playback is not moved forward/backward manually, which from my point of view is different from PositionInfo.getIsPlaying()).
I come up with the following solution (pseudocode):

void process(juce::AudioBuffer<float> &buffer) noexcept {
    auto currentPos = processor->getPlayHead()->getPosition()->getTimeInSamples().orFallback(0);
    // previousPos is initialized as -1 (int64_t) in the constructor
    // isContinuous is initialized as true (bool) in the constructor
    if (currentPos - previousPos != spec.maximumBlockSize && currentPos - previousPos != 0 && previousPos != -1) {
        isContinuous = false;
    } else {
        isContinuous = true;
    }
    previousPos = currentPos;
    // do something else to buffer
}

Does this solution look good to you (assume that the DAW provides PositionInfo)?

You can’t rely on maximumBlocksize to check continuity, as the host can provide any (and variable) block size for every processBlock().

But what you can do is take the playhead position in samples, add the number samples in the process block and save that as an “expected next sample position”. In the next processBlock() you can check against the expected position and if it doesn’t match you have a discontinuity.

This smells like something that should be thoroughly tested with different hosts though. Maybe check if there are occasional “off by 1” false positives, which I could imagine happening if the sample time in positionInfo is computed from something else.

1 Like

if isPlaying, then it’s just current position. else it’s current position + numSamples

Have to be careful with this one. I’ve seen in at least one host that the playhead reported time can drift. This was about a year ago so it may have been since fixed in JUCE/Cubasis 3 but I had to add in a threshold of drift (approx 30 samples) - if it drifted outside those 30 samples (each way from expected number) I could be relatively confident that the playhead had been manually moved.

I think there were 1 or 2 other iOS hosts as well with the same issue.

Here is an example where I needed a timeline in the plugin. timeInSamples was my variable for tracking the timeline and I needed it to move smoothly so in problematic hosts I needed to also let it drift.

if (!juce::JUCEApplicationBase::isStandaloneApp())
{
        auto pos = getPlayHead()->getPosition();
        
        expectedTime = timeInSamples + lastBufferSize;
        
        timeInSamples = *pos->getTimeInSamples();
        
        if (expectedTime != timeInSamples)
        {
            if (std::abs(timeInSamples-lastTime) < 30 && pos->getIsPlaying())
            {
                timeInSamples = expectedTime;
            }
        }
}
2 Likes

true tho. i noticed a drift of max 1 sample in bitwig sometimes too and that was like a month ago or so

1 Like

@hugoderwolf @Mrugalla @DavidCNAntonia Many thanks to you all. Using lastBufferSize and tolerating a small drift seems like a perfect solution :smiling_face_with_three_hearts:

Yep, ±1 sample is what I would expect if the provided numbers are somehow computed back and forth by the host instead of synced to the audio driver. But 30 samples drift (from one block to another???) sounds like a lot!

1 Like

while we are at it :3 i made a video not long ago about an LFO whose phase always depends on rate, bpm and ppq and that thing also required this exact calculation because i needed it to trigger a crossfade:

Yeah, it was a surprise when I figured out what it was. I had a bug report of audible clicks in modulation which was being set by the host reported sample position. Turned out it was all over the place so kept jumping around in time at the end of each buffer - pretty nasty!

Hi! Note that many DAWs support automating tempo continuously.
If BPM changes between blocks, predictions become unreliable, because the plugin just doesn’t get enough information to really know what’s going on. Another special case to handle, plus loops, stopped playback, signature changes, etc.
It gets even more fun if for some reason you need to delay or predict the playhead position internally, e.g. for latency compensation somewhere within the signal chain inside of your plugin. Best come up with all kinds of crazy test cases.

Thanks for the video @Mrugalla - good strategies for coping with tempo sync!

1 Like

Hi :slight_smile:
So this works great in Pro Tools and Studio One.
In Ableton tough, it seems both timeInSamples and timeInSeconds is non-linear when the tempo is changing??

See this simple example where the tempo changes from 135 to 194 on bar 3:

ableton

With a block size of 2048, these are the values I get in ProcessBlock():

(one entry per block)

blockInfoLogs = {
  [0] = {
    lastBarPpqPosition = 0
    ppqPosition = 0
    timeInSamples = 0
    timeInSeconds = 0
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [1] = {
    lastBarPpqPosition = 0
    ppqPosition = 0.096000000000000001
    timeInSamples = 2048
    timeInSeconds = 0.042666666666666665
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [2] = {
    lastBarPpqPosition = 0
    ppqPosition = 0.192
    timeInSamples = 4096
    timeInSeconds = 0.08533333333333333
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [3] = {
    lastBarPpqPosition = 0
    ppqPosition = 0.28800000000000003
    timeInSamples = 6144
    timeInSeconds = 0.128
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [4] = {
    lastBarPpqPosition = 0
    ppqPosition = 0.38400000000000001
    timeInSamples = 8192
    timeInSeconds = 0.17066666666666666
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [5] = {
    lastBarPpqPosition = 0
    ppqPosition = 0.47999999999999998
    timeInSamples = 10240
    timeInSeconds = 0.21333333333333335
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [6] = {
    lastBarPpqPosition = 0
    ppqPosition = 0.57600000000000007
    timeInSamples = 12288
    timeInSeconds = 0.25600000000000001
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [7] = {
    lastBarPpqPosition = 0
    ppqPosition = 0.67200000000000004
    timeInSamples = 14336
    timeInSeconds = 0.29866666666666669
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [8] = {
    lastBarPpqPosition = 0
    ppqPosition = 0.76800000000000002
    timeInSamples = 16384
    timeInSeconds = 0.34133333333333332
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [9] = {
    lastBarPpqPosition = 0
    ppqPosition = 0.86399999999999999
    timeInSamples = 18432
    timeInSeconds = 0.38400000000000001
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [10] = {
    lastBarPpqPosition = 0
    ppqPosition = 0.95999999999999996
    timeInSamples = 20480
    timeInSeconds = 0.42666666666666669
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [11] = {
    lastBarPpqPosition = 0
    ppqPosition = 1.056
    timeInSamples = 22528
    timeInSeconds = 0.46933333333333332
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [12] = {
    lastBarPpqPosition = 0
    ppqPosition = 1.1520000000000001
    timeInSamples = 24576
    timeInSeconds = 0.51200000000000001
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [13] = {
    lastBarPpqPosition = 0
    ppqPosition = 1.248
    timeInSamples = 26624
    timeInSeconds = 0.55466666666666664
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [14] = {
    lastBarPpqPosition = 0
    ppqPosition = 1.3440000000000001
    timeInSamples = 28672
    timeInSeconds = 0.59733333333333338
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [15] = {
    lastBarPpqPosition = 0
    ppqPosition = 1.4399999999999999
    timeInSamples = 30720
    timeInSeconds = 0.64000000000000001
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [16] = {
    lastBarPpqPosition = 0
    ppqPosition = 1.536
    timeInSamples = 32768
    timeInSeconds = 0.68266666666666664
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [17] = {
    lastBarPpqPosition = 0
    ppqPosition = 1.6320000000000001
    timeInSamples = 34816
    timeInSeconds = 0.72533333333333339
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [18] = {
    lastBarPpqPosition = 0
    ppqPosition = 1.728
    timeInSamples = 36864
    timeInSeconds = 0.76800000000000002
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [19] = {
    lastBarPpqPosition = 0
    ppqPosition = 1.8240000000000001
    timeInSamples = 38912
    timeInSeconds = 0.81066666666666664
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [20] = {
    lastBarPpqPosition = 0
    ppqPosition = 1.9199999999999999
    timeInSamples = 40960
    timeInSeconds = 0.85333333333333339
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [21] = {
    lastBarPpqPosition = 0
    ppqPosition = 2.016
    timeInSamples = 43008
    timeInSeconds = 0.89600000000000002
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [22] = {
    lastBarPpqPosition = 0
    ppqPosition = 2.1120000000000001
    timeInSamples = 45056
    timeInSeconds = 0.93866666666666665
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [23] = {
    lastBarPpqPosition = 0
    ppqPosition = 2.2080000000000002
    timeInSamples = 47104
    timeInSeconds = 0.98133333333333327
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [24] = {
    lastBarPpqPosition = 0
    ppqPosition = 2.3040000000000003
    timeInSamples = 49152
    timeInSeconds = 1.024
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [25] = {
    lastBarPpqPosition = 0
    ppqPosition = 2.3999999999999999
    timeInSamples = 51200
    timeInSeconds = 1.0666666666666667
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [26] = {
    lastBarPpqPosition = 0
    ppqPosition = 2.496
    timeInSamples = 53248
    timeInSeconds = 1.1093333333333333
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [27] = {
    lastBarPpqPosition = 0
    ppqPosition = 2.5920000000000001
    timeInSamples = 55296
    timeInSeconds = 1.1519999999999999
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [28] = {
    lastBarPpqPosition = 0
    ppqPosition = 2.6880000000000002
    timeInSamples = 57344
    timeInSeconds = 1.1946666666666668
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [29] = {
    lastBarPpqPosition = 0
    ppqPosition = 2.7840000000000003
    timeInSamples = 59392
    timeInSeconds = 1.2373333333333334
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [30] = {
    lastBarPpqPosition = 0
    ppqPosition = 2.8799999999999999
    timeInSamples = 61440
    timeInSeconds = 1.28
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [31] = {
    lastBarPpqPosition = 0
    ppqPosition = 2.976
    timeInSamples = 63488
    timeInSeconds = 1.3226666666666667
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [32] = {
    lastBarPpqPosition = 0
    ppqPosition = 3.0720000000000001
    timeInSamples = 65536
    timeInSeconds = 1.3653333333333333
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [33] = {
    lastBarPpqPosition = 0
    ppqPosition = 3.1680000000000001
    timeInSamples = 67584
    timeInSeconds = 1.4079999999999999
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [34] = {
    lastBarPpqPosition = 0
    ppqPosition = 3.2640000000000002
    timeInSamples = 69632
    timeInSeconds = 1.4506666666666668
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [35] = {
    lastBarPpqPosition = 0
    ppqPosition = 3.3599999999999999
    timeInSamples = 71680
    timeInSeconds = 1.4933333333333334
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [36] = {
    lastBarPpqPosition = 0
    ppqPosition = 3.456
    timeInSamples = 73728
    timeInSeconds = 1.536
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [37] = {
    lastBarPpqPosition = 0
    ppqPosition = 3.552
    timeInSamples = 75776
    timeInSeconds = 1.5786666666666667
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [38] = {
    lastBarPpqPosition = 0
    ppqPosition = 3.6480000000000001
    timeInSamples = 77824
    timeInSeconds = 1.6213333333333333
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [39] = {
    lastBarPpqPosition = 0
    ppqPosition = 3.7440000000000002
    timeInSamples = 79872
    timeInSeconds = 1.6639999999999999
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [40] = {
    lastBarPpqPosition = 0
    ppqPosition = 3.8399999999999999
    timeInSamples = 81920
    timeInSeconds = 1.7066666666666668
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [41] = {
    lastBarPpqPosition = 0
    ppqPosition = 3.9359999999999999
    timeInSamples = 83968
    timeInSeconds = 1.7493333333333334
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [42] = {
    lastBarPpqPosition = 4
    ppqPosition = 4.032
    timeInSamples = 86016
    timeInSeconds = 1.792
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [43] = {
    lastBarPpqPosition = 4
    ppqPosition = 4.1280000000000001
    timeInSamples = 88064
    timeInSeconds = 1.8346666666666667
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [44] = {
    lastBarPpqPosition = 4
    ppqPosition = 4.2240000000000002
    timeInSamples = 90112
    timeInSeconds = 1.8773333333333333
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [45] = {
    lastBarPpqPosition = 4
    ppqPosition = 4.3200000000000003
    timeInSamples = 92160
    timeInSeconds = 1.9199999999999999
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [46] = {
    lastBarPpqPosition = 4
    ppqPosition = 4.4160000000000004
    timeInSamples = 94208
    timeInSeconds = 1.9626666666666666
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [47] = {
    lastBarPpqPosition = 4
    ppqPosition = 4.5120000000000005
    timeInSamples = 96256
    timeInSeconds = 2.0053333333333332
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [48] = {
    lastBarPpqPosition = 4
    ppqPosition = 4.6080000000000005
    timeInSamples = 98304
    timeInSeconds = 2.048
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [49] = {
    lastBarPpqPosition = 4
    ppqPosition = 4.7039999999999997
    timeInSamples = 100352
    timeInSeconds = 2.0906666666666665
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [50] = {
    lastBarPpqPosition = 4
    ppqPosition = 4.7999999999999998
    timeInSamples = 102400
    timeInSeconds = 2.1333333333333333
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [51] = {
    lastBarPpqPosition = 4
    ppqPosition = 4.8959999999999999
    timeInSamples = 104448
    timeInSeconds = 2.1760000000000002
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [52] = {
    lastBarPpqPosition = 4
    ppqPosition = 4.992
    timeInSamples = 106496
    timeInSeconds = 2.2186666666666666
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [53] = {
    lastBarPpqPosition = 4
    ppqPosition = 5.0880000000000001
    timeInSamples = 108544
    timeInSeconds = 2.2613333333333334
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [54] = {
    lastBarPpqPosition = 4
    ppqPosition = 5.1840000000000002
    timeInSamples = 110592
    timeInSeconds = 2.3039999999999998
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [55] = {
    lastBarPpqPosition = 4
    ppqPosition = 5.2800000000000002
    timeInSamples = 112640
    timeInSeconds = 2.3466666666666667
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [56] = {
    lastBarPpqPosition = 4
    ppqPosition = 5.3760000000000003
    timeInSamples = 114688
    timeInSeconds = 2.3893333333333335
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [57] = {
    lastBarPpqPosition = 4
    ppqPosition = 5.4720000000000004
    timeInSamples = 116736
    timeInSeconds = 2.4319999999999999
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [58] = {
    lastBarPpqPosition = 4
    ppqPosition = 5.5680000000000005
    timeInSamples = 118784
    timeInSeconds = 2.4746666666666668
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [59] = {
    lastBarPpqPosition = 4
    ppqPosition = 5.6639999999999997
    timeInSamples = 120832
    timeInSeconds = 2.5173333333333332
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [60] = {
    lastBarPpqPosition = 4
    ppqPosition = 5.7599999999999998
    timeInSamples = 122880
    timeInSeconds = 2.5600000000000001
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [61] = {
    lastBarPpqPosition = 4
    ppqPosition = 5.8559999999999999
    timeInSamples = 124928
    timeInSeconds = 2.6026666666666665
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [62] = {
    lastBarPpqPosition = 4
    ppqPosition = 5.952
    timeInSamples = 126976
    timeInSeconds = 2.6453333333333333
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [63] = {
    lastBarPpqPosition = 4
    ppqPosition = 6.048
    timeInSamples = 129024
    timeInSeconds = 2.6880000000000002
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [64] = {
    lastBarPpqPosition = 4
    ppqPosition = 6.1440000000000001
    timeInSamples = 131072
    timeInSeconds = 2.7306666666666666
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [65] = {
    lastBarPpqPosition = 4
    ppqPosition = 6.2400000000000002
    timeInSamples = 133120
    timeInSeconds = 2.7733333333333334
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [66] = {
    lastBarPpqPosition = 4
    ppqPosition = 6.3360000000000003
    timeInSamples = 135168
    timeInSeconds = 2.8159999999999998
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [67] = {
    lastBarPpqPosition = 4
    ppqPosition = 6.4320000000000004
    timeInSamples = 137216
    timeInSeconds = 2.8586666666666667
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [68] = {
    lastBarPpqPosition = 4
    ppqPosition = 6.5280000000000005
    timeInSamples = 139264
    timeInSeconds = 2.9013333333333335
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [69] = {
    lastBarPpqPosition = 4
    ppqPosition = 6.6240000000000006
    timeInSamples = 141312
    timeInSeconds = 2.944
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [70] = {
    lastBarPpqPosition = 4
    ppqPosition = 6.7199999999999998
    timeInSamples = 143360
    timeInSeconds = 2.9866666666666668
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [71] = {
    lastBarPpqPosition = 4
    ppqPosition = 6.8159999999999998
    timeInSamples = 145408
    timeInSeconds = 3.0293333333333332
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [72] = {
    lastBarPpqPosition = 4
    ppqPosition = 6.9119999999999999
    timeInSamples = 147456
    timeInSeconds = 3.0720000000000001
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [73] = {
    lastBarPpqPosition = 4
    ppqPosition = 7.008
    timeInSamples = 149504
    timeInSeconds = 3.1146666666666665
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [74] = {
    lastBarPpqPosition = 4
    ppqPosition = 7.1040000000000001
    timeInSamples = 151552
    timeInSeconds = 3.1573333333333333
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [75] = {
    lastBarPpqPosition = 4
    ppqPosition = 7.2000000000000002
    timeInSamples = 153600
    timeInSeconds = 3.2000000000000002
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [76] = {
    lastBarPpqPosition = 4
    ppqPosition = 7.2960000000000003
    timeInSamples = 155648
    timeInSeconds = 3.2426666666666666
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [77] = {
    lastBarPpqPosition = 4
    ppqPosition = 7.3920000000000003
    timeInSamples = 157696
    timeInSeconds = 3.2853333333333334
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [78] = {
    lastBarPpqPosition = 4
    ppqPosition = 7.4880000000000004
    timeInSamples = 159744
    timeInSeconds = 3.3279999999999998
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [79] = {
    lastBarPpqPosition = 4
    ppqPosition = 7.5840000000000005
    timeInSamples = 161792
    timeInSeconds = 3.3706666666666667
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [80] = {
    lastBarPpqPosition = 4
    ppqPosition = 7.6799999999999997
    timeInSamples = 163840
    timeInSeconds = 3.4133333333333336
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [81] = {
    lastBarPpqPosition = 4
    ppqPosition = 7.7759999999999998
    timeInSamples = 165888
    timeInSeconds = 3.456
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [82] = {
    lastBarPpqPosition = 4
    ppqPosition = 7.8719999999999999
    timeInSamples = 167936
    timeInSeconds = 3.4986666666666668
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [83] = {
    lastBarPpqPosition = 4
    ppqPosition = 7.968
    timeInSamples = 169984
    timeInSeconds = 3.5413333333333332
    bpm = 135
    isRecordingOrPlaying = 1
  }
  [84] = {
    lastBarPpqPosition = 8
    ppqPosition = 8.0919479166666672
    timeInSamples = 120128
    timeInSeconds = 2.5026666666666668
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [85] = {
    lastBarPpqPosition = 8
    ppqPosition = 8.2299034722222224
    timeInSamples = 122176
    timeInSeconds = 2.5453333333333332
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [86] = {
    lastBarPpqPosition = 8
    ppqPosition = 8.3678590277777776
    timeInSamples = 124224
    timeInSeconds = 2.5880000000000001
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [87] = {
    lastBarPpqPosition = 8
    ppqPosition = 8.5058145833333327
    timeInSamples = 126272
    timeInSeconds = 2.6306666666666665
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [88] = {
    lastBarPpqPosition = 8
    ppqPosition = 8.6437701388888896
    timeInSamples = 128320
    timeInSeconds = 2.6733333333333333
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [89] = {
    lastBarPpqPosition = 8
    ppqPosition = 8.7817256944444448
    timeInSamples = 130368
    timeInSeconds = 2.7160000000000002
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [90] = {
    lastBarPpqPosition = 8
    ppqPosition = 8.91968125
    timeInSamples = 132416
    timeInSeconds = 2.7586666666666666
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [91] = {
    lastBarPpqPosition = 8
    ppqPosition = 9.0576368055555552
    timeInSamples = 134464
    timeInSeconds = 2.8013333333333335
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [92] = {
    lastBarPpqPosition = 8
    ppqPosition = 9.1955923611111103
    timeInSamples = 136512
    timeInSeconds = 2.8439999999999999
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [93] = {
    lastBarPpqPosition = 8
    ppqPosition = 9.3335479166666672
    timeInSamples = 138560
    timeInSeconds = 2.8866666666666667
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [94] = {
    lastBarPpqPosition = 8
    ppqPosition = 9.4715034722222224
    timeInSamples = 140608
    timeInSeconds = 2.9293333333333331
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [95] = {
    lastBarPpqPosition = 8
    ppqPosition = 9.6094590277777776
    timeInSamples = 142656
    timeInSeconds = 2.972
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [96] = {
    lastBarPpqPosition = 8
    ppqPosition = 9.7474145833333327
    timeInSamples = 144704
    timeInSeconds = 3.0146666666666668
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [97] = {
    lastBarPpqPosition = 8
    ppqPosition = 9.8853701388888879
    timeInSamples = 146752
    timeInSeconds = 3.0573333333333332
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [98] = {
    lastBarPpqPosition = 8
    ppqPosition = 10.023325694444445
    timeInSamples = 148800
    timeInSeconds = 3.1000000000000001
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [99] = {
    lastBarPpqPosition = 8
    ppqPosition = 10.16128125
    timeInSamples = 150848
    timeInSeconds = 3.1426666666666665
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [100] = {
    lastBarPpqPosition = 8
    ppqPosition = 10.299236805555555
    timeInSamples = 152896
    timeInSeconds = 3.1853333333333333
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [101] = {
    lastBarPpqPosition = 8
    ppqPosition = 10.437192361111112
    timeInSamples = 154944
    timeInSeconds = 3.2280000000000002
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [102] = {
    lastBarPpqPosition = 8
    ppqPosition = 10.575147916666666
    timeInSamples = 156992
    timeInSeconds = 3.2706666666666666
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [103] = {
    lastBarPpqPosition = 8
    ppqPosition = 10.713103472222222
    timeInSamples = 159040
    timeInSeconds = 3.3133333333333335
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [104] = {
    lastBarPpqPosition = 8
    ppqPosition = 10.851059027777778
    timeInSamples = 161088
    timeInSeconds = 3.3559999999999999
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [105] = {
    lastBarPpqPosition = 8
    ppqPosition = 10.989014583333333
    timeInSamples = 163136
    timeInSeconds = 3.3986666666666667
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [106] = {
    lastBarPpqPosition = 8
    ppqPosition = 11.12697013888889
    timeInSamples = 165184
    timeInSeconds = 3.4413333333333331
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [107] = {
    lastBarPpqPosition = 8
    ppqPosition = 11.264925694444445
    timeInSamples = 167232
    timeInSeconds = 3.484
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [108] = {
    lastBarPpqPosition = 8
    ppqPosition = 11.40288125
    timeInSamples = 169280
    timeInSeconds = 3.5266666666666668
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [109] = {
    lastBarPpqPosition = 8
    ppqPosition = 11.540836805555555
    timeInSamples = 171328
    timeInSeconds = 3.5693333333333332
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [110] = {
    lastBarPpqPosition = 8
    ppqPosition = 11.67879236111111
    timeInSamples = 173376
    timeInSeconds = 3.6120000000000001
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [111] = {
    lastBarPpqPosition = 8
    ppqPosition = 11.816747916666667
    timeInSamples = 175424
    timeInSeconds = 3.6546666666666665
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [112] = {
    lastBarPpqPosition = 8
    ppqPosition = 11.954703472222223
    timeInSamples = 177472
    timeInSeconds = 3.6973333333333334
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [113] = {
    lastBarPpqPosition = 12
    ppqPosition = 12.092659027777778
    timeInSamples = 179520
    timeInSeconds = 3.7400000000000002
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [114] = {
    lastBarPpqPosition = 12
    ppqPosition = 12.230614583333333
    timeInSamples = 181568
    timeInSeconds = 3.7826666666666666
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [115] = {
    lastBarPpqPosition = 12
    ppqPosition = 12.368570138888888
    timeInSamples = 183616
    timeInSeconds = 3.8253333333333335
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [116] = {
    lastBarPpqPosition = 12
    ppqPosition = 12.506525694444445
    timeInSamples = 185664
    timeInSeconds = 3.8679999999999999
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [117] = {
    lastBarPpqPosition = 12
    ppqPosition = 12.64448125
    timeInSamples = 187712
    timeInSeconds = 3.9106666666666667
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [118] = {
    lastBarPpqPosition = 12
    ppqPosition = 12.782436805555555
    timeInSamples = 189760
    timeInSeconds = 3.9533333333333331
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [119] = {
    lastBarPpqPosition = 12
    ppqPosition = 12.920392361111112
    timeInSamples = 191808
    timeInSeconds = 3.996
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [120] = {
    lastBarPpqPosition = 12
    ppqPosition = 13.058347916666666
    timeInSamples = 193856
    timeInSeconds = 4.0386666666666668
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [121] = {
    lastBarPpqPosition = 12
    ppqPosition = 13.196303472222223
    timeInSamples = 195904
    timeInSeconds = 4.0813333333333333
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [122] = {
    lastBarPpqPosition = 12
    ppqPosition = 13.334259027777778
    timeInSamples = 197952
    timeInSeconds = 4.1239999999999997
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [123] = {
    lastBarPpqPosition = 12
    ppqPosition = 13.472214583333333
    timeInSamples = 200000
    timeInSeconds = 4.166666666666667
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [124] = {
    lastBarPpqPosition = 12
    ppqPosition = 13.61017013888889
    timeInSamples = 202048
    timeInSeconds = 4.2093333333333334
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [125] = {
    lastBarPpqPosition = 12
    ppqPosition = 13.748125694444443
    timeInSamples = 204096
    timeInSeconds = 4.2519999999999998
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [126] = {
    lastBarPpqPosition = 12
    ppqPosition = 13.88608125
    timeInSamples = 206144
    timeInSeconds = 4.2946666666666671
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [127] = {
    lastBarPpqPosition = 12
    ppqPosition = 14.024036805555555
    timeInSamples = 208192
    timeInSeconds = 4.3373333333333335
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [128] = {
    lastBarPpqPosition = 12
    ppqPosition = 14.16199236111111
    timeInSamples = 210240
    timeInSeconds = 4.3799999999999999
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [129] = {
    lastBarPpqPosition = 12
    ppqPosition = 14.299947916666667
    timeInSamples = 212288
    timeInSeconds = 4.4226666666666663
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [130] = {
    lastBarPpqPosition = 12
    ppqPosition = 14.437903472222221
    timeInSamples = 214336
    timeInSeconds = 4.4653333333333336
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [131] = {
    lastBarPpqPosition = 12
    ppqPosition = 14.575859027777778
    timeInSamples = 216384
    timeInSeconds = 4.508
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [132] = {
    lastBarPpqPosition = 12
    ppqPosition = 14.713814583333333
    timeInSamples = 218432
    timeInSeconds = 4.5506666666666664
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [133] = {
    lastBarPpqPosition = 12
    ppqPosition = 14.851770138888888
    timeInSamples = 220480
    timeInSeconds = 4.5933333333333337
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [134] = {
    lastBarPpqPosition = 12
    ppqPosition = 14.989725694444445
    timeInSamples = 222528
    timeInSeconds = 4.6360000000000001
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [135] = {
    lastBarPpqPosition = 12
    ppqPosition = 15.12768125
    timeInSamples = 224576
    timeInSeconds = 4.6786666666666665
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [136] = {
    lastBarPpqPosition = 12
    ppqPosition = 15.265636805555555
    timeInSamples = 226624
    timeInSeconds = 4.7213333333333329
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [137] = {
    lastBarPpqPosition = 12
    ppqPosition = 15.403592361111112
    timeInSamples = 228672
    timeInSeconds = 4.7640000000000002
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [138] = {
    lastBarPpqPosition = 12
    ppqPosition = 15.541547916666666
    timeInSamples = 230720
    timeInSeconds = 4.8066666666666666
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [139] = {
    lastBarPpqPosition = 12
    ppqPosition = 15.679503472222223
    timeInSamples = 232768
    timeInSeconds = 4.8493333333333331
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [140] = {
    lastBarPpqPosition = 12
    ppqPosition = 15.817459027777778
    timeInSamples = 234816
    timeInSeconds = 4.8920000000000003
    bpm = 194
    isRecordingOrPlaying = 1
  }
  [141] = {
    lastBarPpqPosition = 12
    ppqPosition = 15.955414583333333
    timeInSamples = 236864
    timeInSeconds = 4.9346666666666668
    bpm = 194
    isRecordingOrPlaying = 1
	}

It all makes sense up to entry [84], where the timeInSeconds jumps from 3.54 to 2.50 ! Same for the timeInSamples…

So does anyone has any idea on how to check if the playback is continuous in Ableton, I guess without using timeInSamples?

Cheers
Simon

Why don’t you just use the ppqposition? According to your own data, it’s continuous.

That’s actually a pretty good idea, thank you!

The increment must be something like numSamples * bpm / (60.0*sampleRate) +/- a few rounding errors.

I’ll try :slight_smile:

Ha! Actually no of course I cannot - because if the tempo jumps is during a block then the increment will be wrong since it should take into account the new tempo (which the plugin will receive only on the next block). Hence the idea of using timeInSamples, which works in most places expect in Ableton.

The biggest irony, is that the reason I need to detect if the playback is continuous is precisely because of the fact I cannot get the tempo at an exact sample but only on the current block.

Maybe one day the VST3 interface will give a way to get a tempo map - gosh that would make my life so much easier… (it’s actually possible in an ARA plugin, I went down that way but not great or easy for the end-user, and not available in every DAW :frowning: )

PS: just FYI I found this topic: CurrentPositionInfo.timeInSamples and tempo changes in ableton live - it seems this has been an Ableton bug for a looooong time.