From e31bf1381feea8a26eebf31024b26a3e1ccbf002 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 15 Nov 2020 11:23:02 +0100 Subject: [PATCH] Provide the interpolated beat position --- src/sfizz/BeatClock.cpp | 26 +++++++++++++------------- src/sfizz/BeatClock.h | 24 ++++++++++++++++++------ src/sfizz/Synth.cpp | 2 +- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/sfizz/BeatClock.cpp b/src/sfizz/BeatClock.cpp index f9ef6c14..154cf138 100644 --- a/src/sfizz/BeatClock.cpp +++ b/src/sfizz/BeatClock.cpp @@ -64,12 +64,6 @@ T BeatClock::dequantize(qbeats_t qbeats) } /// -BeatClock::BeatClock() -{ - setSampleRate(config::defaultSampleRate); - setSamplesPerBlock(config::defaultSamplesPerBlock); -} - void BeatClock::clear() { beatsPerSecond_ = 2.0; @@ -99,7 +93,8 @@ void BeatClock::setSampleRate(double sampleRate) void BeatClock::setSamplesPerBlock(unsigned samplesPerBlock) { - runningBeat_.resize(samplesPerBlock); + runningBeatNumber_.resize(samplesPerBlock); + runningBeatPosition_.resize(samplesPerBlock); runningBeatsPerBar_.resize(samplesPerBlock); } @@ -147,11 +142,11 @@ void BeatClock::setPlaying(unsigned delay, bool playing) isPlaying_ = playing; } -absl::Span BeatClock::getRunningBeat() +absl::Span BeatClock::getRunningBeatNumber() { fillBufferUpTo(currentCycleFrames_); - return absl::MakeConstSpan(runningBeat_.data(), currentCycleFrames_); + return absl::MakeConstSpan(runningBeatNumber_.data(), currentCycleFrames_); } absl::Span BeatClock::getRunningBeatsPerBar() @@ -163,7 +158,8 @@ absl::Span BeatClock::getRunningBeatsPerBar() void BeatClock::fillBufferUpTo(unsigned delay) { - int *beatData = runningBeat_.data(); + int *beatNumberData = runningBeatNumber_.data(); + float *beatNumberPosition = runningBeatPosition_.data(); int *beatsPerBarData = runningBeatsPerBar_.data(); unsigned fill = currentCycleFill_; @@ -172,8 +168,10 @@ void BeatClock::fillBufferUpTo(unsigned delay) beatsPerBarData[i] = sig.beatsPerBar; if (!isPlaying_) { - for (; fill < delay; ++fill) - beatData[fill] = 0; + for (; fill < delay; ++fill) { + beatNumberData[fill] = 0; + beatNumberPosition[fill] = 0; + } currentCycleFill_ = fill; return; } @@ -190,7 +188,9 @@ void BeatClock::fillBufferUpTo(unsigned delay) mustApplyHostPos = false; // quantization to nearest for prevention of rounding errors - beatData[fill] = dequantize(quantize(clientPos.toBeats(sig))); + double beats = clientPos.toBeats(sig); + beatNumberData[fill] = dequantize(quantize(beats)); + beatNumberPosition[fill] = static_cast(beats); } currentCycleFill_ = fill; diff --git a/src/sfizz/BeatClock.h b/src/sfizz/BeatClock.h index e5fbfcba..b75ba182 100644 --- a/src/sfizz/BeatClock.h +++ b/src/sfizz/BeatClock.h @@ -5,6 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once +#include "Buffer.h" #include #include #include @@ -73,8 +74,6 @@ struct BBT { class BeatClock { public: - BeatClock(); - /** * @brief Set the sample rate. */ @@ -113,8 +112,20 @@ public: void setPlaying(unsigned delay, bool playing); /** * @brief Get the beat number for each frame of the current cycle. + * + * This signal is quantized to a fixed resolution, such that it never + * suffers 1-off errors due to imprecision in the host time position. */ - absl::Span getRunningBeat(); + absl::Span getRunningBeatNumber(); + /** + * @brief Get the beat position for each frame of the current cycle. + * + * This is a fractional equivalent of the beat number, however the beat + * boundaries can be traversed erratically due to approximation errors. + * If you need to perform work on exact beat transitions, prefer + * `getRunningBeatNumber` instead. + */ + absl::Span getRunningBeatPosition(); /** * @brief Get the time signature numerator for each frame of the current cycle. */ @@ -124,7 +135,7 @@ private: void fillBufferUpTo(unsigned delay); private: - double samplePeriod_ = 0; + double samplePeriod_ { 1.0 / config::defaultSampleRate }; // quantization typedef int64_t qbeats_t; @@ -150,8 +161,9 @@ private: // plugin-side counter BBT lastClientPos_; - std::vector runningBeat_; - std::vector runningBeatsPerBar_; + Buffer runningBeatNumber_ { config::defaultSamplesPerBlock }; + Buffer runningBeatPosition_ { config::defaultSamplesPerBlock }; + Buffer runningBeatsPerBar_ { config::defaultSamplesPerBlock }; }; } // namespace sfz diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 458aca2b..92fdc619 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -925,7 +925,7 @@ void Synth::renderBlock(AudioSpan buffer) noexcept constexpr bool metronomeEnabled = false; if (metronomeEnabled) { impl.resources_.metronome.processAdding( - bc.getRunningBeat().data(), bc.getRunningBeatsPerBar().data(), + bc.getRunningBeatNumber().data(), bc.getRunningBeatsPerBar().data(), buffer.getChannel(0), buffer.getChannel(1), numFrames); }