I have some functionality in my plugin that does some weighted moving averaging over multiple frames. It needs to reset when the playhead is moved, i.e. the frames aren’t consecutive in time. My current implementation trys to getTimeInSamples from the playhead position and calculate where it should be based on the previous position and the frame size. If the DAW doesn’t provide that information, it falls back to checking if play/stop has been toggled. It’s made very clunky by the different ways the different hosts handle this information. Pyramix, for example, provides the optional timeInSamples parameter, but it’s suck at 0 all the time. Wavelab stops calling processBlock when the transport is stopped, but others continue to do so. Wavelab also reports the blockSize with a factor applied to it. Etc., Etc.. Below is my current implementation. Any ideas for a smarter approach?
/* We want to reset delayEstimator whenever the playhead is moved in the DAW, becuase if I am listening to
* one part of a song in the DAW, and then I move to another part of it, I don't want the delay estimator
* to use the previous estimations in determining the average delay that it reports. There are a couple of
* ways to determine if the playhead has been moved. The preferred method is to read out the current
* position of the playhead in samples and, if the DAW transport is in play mode, see if it is exactly
* one frame ahead of the location from the last location - if so, these are consecutive frames, and we
* don't need to perform a reset - if not, the playhead has been moved, and we do want to reset.
* With some DAW/plugin format combinations we can't get the current time in samples though (Pyramix).
* In those cases, we check to see if the DAW transport is in play mode or stop mode and if that changes
* we reset. This is less robust for a couple of reasons. 1: In cases where the DAW stops calling
* processBlock when the transport is stopped (like WaveLab) you'd never actually see stop mode so it would
* never tigger a reset, and 2: If you stop playback and then restart from the same spot, it will trigger a
* reset when it actually shouldn't. */
// playHead has transport info provided by DAW
const auto position = getPlayHead()->getPosition();
const auto isPlaying = position->getIsPlaying();
// If this is the first block, we need to store some values for comparison, and we don't need to evaluate
// whether to reset delayEstimator
if (getFirstBlockFlag() && isPlaying)
{
setFirstBlockFlag (false);
setWasPlaying (true);
if (position->getTimeInSamples()) // If DAW provides this info, grab it
{
setPrevTimeInSamples (*position->getTimeInSamples());
}
}
else // Not the first block played
{
if (isPlaying)
{
/* If the DAW provides this info, we want to use it. In some cases (Pyramix), though, the DAW does
* provide the optional timeInSamples parameter, but it is stuck at 0. In that case, we want to fall
* back to the getWasPlaying method. This implementation means a true timeInSamples = 0 condition
* won't trigger a reset, so there will be cases where the delayEstimator doesn't reset until the
* second block in when the playhead is moved back to the beginning, but it feels more robust than
* just checking what host we are in and having behavior tied to each DAW. */
if (position->getTimeInSamples() && position->getTimeInSamples() != 0)
{
const auto currentTimeInSamples = *position->getTimeInSamples();
if (currentTimeInSamples != getPrevTimeInSamples() + prevFrameLen)
{
delayEstimator.reset(); // This frame is not consecutive with the previous one
}
setPrevTimeInSamples (currentTimeInSamples);
}
else if (!getWasPlaying()) // Can't get currentTimeInSamples - use Play/Stop method
{
delayEstimator.reset(); // Play/Stop has been toggled
}
}
setWasPlaying (isPlaying);
}```
