Add the beat clock

This commit is contained in:
Jean Pierre Cimalando 2020-08-14 04:18:58 +02:00
parent 9813d41588
commit baf228802b
15 changed files with 604 additions and 19 deletions

View file

@ -48,6 +48,7 @@ SFIZZ_CXX_FLAGS = $(SFIZZ_C_FLAGS)
SFIZZ_SOURCES = \
src/sfizz/ADSREnvelope.cpp \
src/sfizz/AudioReader.cpp \
src/sfizz/BeatClock.cpp \
src/sfizz/Curve.cpp \
src/sfizz/effects/Apan.cpp \
src/sfizz/Effects.cpp \
@ -90,6 +91,7 @@ SFIZZ_SOURCES = \
src/sfizz/LFO.cpp \
src/sfizz/LFODescription.cpp \
src/sfizz/Messaging.cpp \
src/sfizz/Metronome.cpp \
src/sfizz/MidiState.cpp \
src/sfizz/OpcodeCleanup.cpp \
src/sfizz/Opcode.cpp \

View file

@ -175,11 +175,11 @@ typedef struct
// Timing data
int bar;
float bar_beat;
double bar_beat;
int beats_per_bar;
int beat_unit;
float bpm_tempo;
float speed;
double bpm_tempo;
double speed;
// Paths
char bundle_path[MAX_BUNDLE_PATH_SIZE];

View file

@ -21,6 +21,7 @@ set (SFIZZ_HEADERS
sfizz/AudioBuffer.h
sfizz/AudioReader.h
sfizz/AudioSpan.h
sfizz/BeatClock.h
sfizz/Buffer.h
sfizz/BufferPool.h
sfizz/CCMap.h
@ -79,6 +80,7 @@ set (SFIZZ_HEADERS
sfizz/LFO.h
sfizz/LFODescription.h
sfizz/MathHelpers.h
sfizz/Metronome.h
sfizz/MidiState.h
sfizz/ModifierHelpers.h
sfizz/OnePoleFilter.h
@ -149,6 +151,8 @@ set (SFIZZ_SOURCES
sfizz/PowerFollower.cpp
sfizz/FlexEGDescription.cpp
sfizz/FlexEnvelope.cpp
sfizz/BeatClock.cpp
sfizz/Metronome.cpp
sfizz/SynthMessaging.cpp
sfizz/modulations/ModId.cpp
sfizz/modulations/ModKey.cpp

View file

@ -375,7 +375,7 @@ SFIZZ_EXPORTED_API void sfizz_send_time_signature(sfizz_synth_t* synth, int dela
* @param bar The current bar.
* @param bar_beat The fractional position of the current beat within the bar.
*/
SFIZZ_EXPORTED_API void sfizz_send_time_position(sfizz_synth_t* synth, int delay, int bar, float bar_beat);
SFIZZ_EXPORTED_API void sfizz_send_time_position(sfizz_synth_t* synth, int delay, int bar, double bar_beat);
/**
* @brief Send the playback state.

View file

@ -344,7 +344,7 @@ public:
* @param bar The current bar.
* @param barBeat The fractional position of the current beat within the bar.
*/
void timePosition(int delay, int bar, float barBeat);
void timePosition(int delay, int bar, double barBeat);
/**
* @brief Send the playback state.

230
src/sfizz/BeatClock.cpp Normal file
View file

@ -0,0 +1,230 @@
// SPDX-License-Identifier: BSD-2-Clause
// This code is part of the sfizz library and is licensed under a BSD 2-clause
// license. You should have receive a LICENSE.md file along with the code.
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#include "BeatClock.h"
#include "Config.h"
#include "Debug.h"
#include <iostream>
#include <cmath>
namespace sfz {
bool TimeSignature::operator==(const TimeSignature& other) const
{
return beatsPerBar == other.beatsPerBar && beatUnit == other.beatUnit;
}
bool TimeSignature::operator!=(const TimeSignature& other) const
{
return !operator==(other);
}
///
BBT BBT::toSignature(TimeSignature oldSig, TimeSignature newSig) const
{
double beatsInOldSig = toBeats(oldSig);
double beatsInNewSig = beatsInOldSig * newSig.beatUnit / oldSig.beatUnit;
return BBT::fromBeats(newSig, beatsInNewSig);
}
double BBT::toBeats(TimeSignature sig) const
{
return beat + bar * sig.beatsPerBar;
}
BBT BBT::fromBeats(TimeSignature sig, double beats)
{
int newBar = static_cast<int>(beats / sig.beatsPerBar);
double newBeat = beats - newBar * sig.beatsPerBar;
return BBT(newBar, newBeat);
}
double BBT::toBars(TimeSignature sig) const
{
return bar + beat / sig.beatsPerBar;
}
///
constexpr int BeatClock::resolution;
auto BeatClock::quantize(double beats) -> qbeats_t
{
double d = beats * (1 << resolution);
d = std::copysign(0.5 + std::fabs(d), d);
return static_cast<qbeats_t>(d);
}
template <class T>
T BeatClock::dequantize(qbeats_t qbeats)
{
return qbeats / static_cast<T>(1 << resolution);
}
///
BeatClock::BeatClock()
{
setSampleRate(config::defaultSampleRate);
setSamplesPerBlock(config::defaultSamplesPerBlock);
}
void BeatClock::clear()
{
beatsPerSecond_ = 2.0;
timeSig_ = { 4, 4 };
isPlaying_ = false;
lastHostPos_ = { 0, 0 };
lastClientPos_ = { 0, 0 };
}
void BeatClock::beginCycle(unsigned numFrames)
{
currentCycleFrames_ = numFrames;
currentCycleFill_ = 0;
currentCycleStartPos_ = lastClientPos_;
}
void BeatClock::endCycle()
{
fillBufferUpTo(currentCycleFrames_);
}
void BeatClock::setSampleRate(double sampleRate)
{
samplePeriod_ = 1.0 / sampleRate;
}
void BeatClock::setSamplesPerBlock(unsigned samplesPerBlock)
{
runningBeat_.resize(samplesPerBlock);
runningBeatsPerBar_.resize(samplesPerBlock);
}
void BeatClock::setTempo(unsigned delay, double secondsPerBeat)
{
fillBufferUpTo(delay);
beatsPerSecond_ = 1.0 / secondsPerBeat;
}
void BeatClock::setTimeSignature(unsigned delay, TimeSignature newSig)
{
fillBufferUpTo(delay);
if (!newSig.valid()) {
CHECKFALSE;
return;
}
TimeSignature oldSig = timeSig_;
if (oldSig == newSig)
return;
timeSig_ = newSig;
// convert time to new signature
lastHostPos_ = lastHostPos_.toSignature(oldSig, newSig);
lastClientPos_ = lastClientPos_.toSignature(oldSig, newSig);
}
void BeatClock::setTimePosition(unsigned delay, BBT newPos)
{
fillBufferUpTo(delay);
lastHostPos_ = newPos;
// apply host position in the next frame
mustApplyHostPos_ = true;
}
void BeatClock::setPlaying(unsigned delay, bool playing)
{
fillBufferUpTo(delay);
isPlaying_ = playing;
}
absl::Span<const int> BeatClock::getRunningBeat()
{
fillBufferUpTo(currentCycleFrames_);
return absl::MakeConstSpan(runningBeat_.data(), currentCycleFrames_);
}
absl::Span<const int> BeatClock::getRunningBeatsPerBar()
{
fillBufferUpTo(currentCycleFrames_);
return absl::MakeConstSpan(runningBeatsPerBar_.data(), currentCycleFrames_);
}
void BeatClock::fillBufferUpTo(unsigned delay)
{
int *beatData = runningBeat_.data();
int *beatsPerBarData = runningBeatsPerBar_.data();
unsigned fill = currentCycleFill_;
const TimeSignature sig = timeSig_;
for (unsigned i = fill; i < delay; ++i)
beatsPerBarData[i] = sig.beatsPerBar;
if (!isPlaying_) {
for (; fill < delay; ++fill)
beatData[fill] = 0;
currentCycleFill_ = fill;
return;
}
BBT clientPos = lastClientPos_;
const double beatsPerFrame = beatsPerSecond_ * samplePeriod_;
const BBT hostPos = lastHostPos_;
bool mustApplyHostPos = mustApplyHostPos_;
for (; fill < delay; ++fill) {
clientPos = BBT::fromBeats(sig, clientPos.toBeats(sig) + beatsPerFrame);
clientPos = mustApplyHostPos ? hostPos : clientPos;
mustApplyHostPos = false;
// quantization to nearest for prevention of rounding errors
beatData[fill] = dequantize<int>(quantize(clientPos.toBeats(sig)));
#if 0
BBT oldClientPos = clientPos;
// quantization to nearest for prevention of rounding errors
qbeats_t oldQbeats = quantize(oldClientPos.toBeats(sig));
qbeats_t qbeats = quantize(clientPos.toBeats(sig));
int oldBeatNumber = dequantize<int>(oldQbeats);
int beatNumber = dequantize<int>(qbeats);
int beatIncrement = std::max(0, beatNumber - oldBeatNumber);
int beatDistanceToNextBar = sig.beatsPerBar - (oldBeatNumber % sig.beatsPerBar);
int barIncrement = (beatIncrement < beatDistanceToNextBar) ? 0 :
(1 + (beatIncrement - beatDistanceToNextBar) / sig.beatsPerBar);
beatData[fill] = beatIncrement;
barData[fill] = barIncrement;
#endif
}
currentCycleFill_ = fill;
lastClientPos_ = clientPos;
mustApplyHostPos_ = mustApplyHostPos;
}
} // namespace sfz
std::ostream& operator<<(std::ostream& os, const sfz::BBT& pos)
{
return os << pos.bar << ':' << std::fixed << pos.beat;
}
std::ostream& operator<<(std::ostream& os, const sfz::TimeSignature& sig)
{
return os << sig.beatsPerBar << '/' << sig.beatUnit;
}

160
src/sfizz/BeatClock.h Normal file
View file

@ -0,0 +1,160 @@
// SPDX-License-Identifier: BSD-2-Clause
// This code is part of the sfizz library and is licensed under a BSD 2-clause
// license. You should have receive a LICENSE.md file along with the code.
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#pragma once
#include <absl/types/span.h>
#include <vector>
#include <iosfwd>
namespace sfz {
/**
* @brief Musical time signature
*/
struct TimeSignature {
TimeSignature() {}
TimeSignature(int beatsPerBar, int beatUnit) : beatsPerBar(beatsPerBar), beatUnit(beatUnit) {}
/**
* @brief Check the signature validity.
* Valid signatures have a strictly positive numerator and denominator.
*/
bool valid() const { return beatsPerBar > 0 && beatUnit > 0; }
bool operator==(const TimeSignature& other) const;
bool operator!=(const TimeSignature& other) const;
/**
* @brief Time signature numerator, indicating the number of beats in a bar
*/
int beatsPerBar = 0;
/**
* @brief Time signature denominator, indicating the type of note (4=quarter)
*/
int beatUnit = 0;
};
/**
* @brief Musical time in BBT form
*/
struct BBT {
BBT() {}
BBT(int bar, double beat) : bar(bar), beat(beat) {}
/**
* @brief Convert the time to a different signature.
*/
BBT toSignature(TimeSignature oldSig, TimeSignature newSig) const;
/**
* @brief Convert the time to a fractional quantity in beats.
*/
double toBeats(TimeSignature sig) const;
/**
* @brief Convert the time to a fractional quantity in bars.
*/
double toBars(TimeSignature sig) const;
/**
* @brief Convert the fractional quantity in beats to musical time.
*/
static BBT fromBeats(TimeSignature sig, double beats);
/**
* @brief Bar number
*/
int bar = 0;
/**
* @brief Beat and tick, stored in the integral and fractional parts
*/
double beat = 0;
};
class BeatClock {
public:
BeatClock();
/**
* @brief Set the sample rate.
*/
void setSampleRate(double sampleRate);
/**
* @brief Set the block size.
*/
void setSamplesPerBlock(unsigned samplesPerBlock);
/**
* @brief Reinitialize the current state.
*/
void clear();
/**
* @brief Start a new cycle of clock processing.
*/
void beginCycle(unsigned numFrames);
/**
* @brief End the current cycle of clock processing.
*/
void endCycle();
/**
* @brief Set the tempo.
*/
void setTempo(unsigned delay, double secondsPerBeat);
/**
* @brief Set the time signature.
*/
void setTimeSignature(unsigned delay, TimeSignature newSig);
/**
* @brief Set the time position.
*/
void setTimePosition(unsigned delay, BBT newPos);
/**
* @brief Set whether the clock is ticking or stopped.
*/
void setPlaying(unsigned delay, bool playing);
/**
* @brief Get the beat number for each frame of the current cycle.
*/
absl::Span<const int> getRunningBeat();
/**
* @brief Get the time signature numerator for each frame of the current cycle.
*/
absl::Span<const int> getRunningBeatsPerBar();
private:
void fillBufferUpTo(unsigned delay);
private:
double samplePeriod_ = 0;
// quantization
typedef int64_t qbeats_t;
static constexpr int resolution = 16; // bits
static qbeats_t quantize(int beats) { return beats * (1 << resolution); }
static qbeats_t quantize(double beats);
template <class T> static T dequantize(qbeats_t qbeats);
// status of current cycle
unsigned currentCycleFrames_ = 0;
unsigned currentCycleFill_ = 0;
BBT currentCycleStartPos_;
// musical time information from host
double beatsPerSecond_ = 2.0;
TimeSignature timeSig_ { 4, 4 };
bool isPlaying_ = false;
// last time position received from host
BBT lastHostPos_;
bool mustApplyHostPos_ = false;
// plugin-side counter
BBT lastClientPos_;
std::vector<int> runningBeat_;
std::vector<int> runningBeatsPerBar_;
};
} // namespace sfz
std::ostream& operator<<(std::ostream& os, const sfz::BBT& pos);
std::ostream& operator<<(std::ostream& os, const sfz::TimeSignature& sig);

110
src/sfizz/Metronome.cpp Normal file
View file

@ -0,0 +1,110 @@
// SPDX-License-Identifier: BSD-2-Clause
// This code is part of the sfizz library and is licensed under a BSD 2-clause
// license. You should have receive a LICENSE.md file along with the code.
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#include "Metronome.h"
#include "Config.h"
namespace sfz {
Metronome::Metronome()
{
fGain = 0.5f;
init(config::defaultSampleRate);
}
void Metronome::init(float sampleRate)
{
fConst0 = std::min<float>(192000.0f, std::max<float>(1.0f, float(sampleRate)));
fConst1 = std::cos((2764.60156f / fConst0));
fConst2 = std::sqrt(std::max<float>(0.0f, ((fConst1 + 1.0f) / (1.0f - fConst1))));
fConst3 = (1.0f / fConst2);
fConst4 = std::cos((5529.20312f / fConst0));
fConst5 = std::sqrt(std::max<float>(0.0f, ((fConst4 + 1.0f) / (1.0f - fConst4))));
fConst6 = (1.0f / fConst5);
fConst7 = std::max<float>(1.0f, (0.00499999989f * fConst0));
fConst8 = (1.0f / fConst7);
fConst9 = (1.0f / std::max<float>(1.0f, (0.100000001f * fConst0)));
clear();
}
void Metronome::clear()
{
for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) {
iVec0[l0] = 0;
}
for (int l1 = 0; (l1 < 2); l1 = (l1 + 1)) {
iVec1[l1] = 0;
}
for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) {
iVec2[l2] = 0;
}
for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) {
iRec0[l3] = 0;
}
for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) {
fVec3[l4] = 0.0f;
}
for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) {
fRec1[l5] = 0.0f;
}
for (int l6 = 0; (l6 < 2); l6 = (l6 + 1)) {
fRec2[l6] = 0.0f;
}
for (int l7 = 0; (l7 < 2); l7 = (l7 + 1)) {
fVec4[l7] = 0.0f;
}
for (int l8 = 0; (l8 < 2); l8 = (l8 + 1)) {
fRec3[l8] = 0.0f;
}
for (int l9 = 0; (l9 < 2); l9 = (l9 + 1)) {
fRec4[l9] = 0.0f;
}
for (int l10 = 0; (l10 < 2); l10 = (l10 + 1)) {
iRec5[l10] = 0;
}
}
void Metronome::processAdding(const int* beats, const int* beatsPerBar, float* outputL, float* outputR, int numFrames)
{
float fSlow0 = float(fGain);
for (int i = 0; (i < numFrames); i = (i + 1)) {
int iTemp0 = int(beats[i]);
iVec0[0] = iTemp0;
iVec1[0] = 1;
int iTemp1 = ((iTemp0 - iVec0[1]) > 0);
iVec2[0] = iTemp1;
iRec0[0] = (iTemp1 ? ((iTemp0 % int(beatsPerBar[i])) == 0) : iRec0[1]);
fVec3[0] = fConst2;
float fTemp2 = float((1 - iVec1[1]));
float fTemp3 = (fConst3 * (fRec2[1] * (fTemp2 + fVec3[1])));
float fTemp4 = (fConst1 * (fTemp3 + fRec1[1]));
fRec1[0] = (fTemp4 + (fTemp2 + fTemp3));
fRec2[0] = (fTemp4 - fRec1[1]);
fVec4[0] = fConst5;
float fTemp5 = (fConst6 * (fRec4[1] * (fTemp2 + fVec4[1])));
float fTemp6 = (fConst4 * (fTemp5 + fRec3[1]));
fRec3[0] = (fTemp6 + (fTemp2 + fTemp5));
fRec4[0] = (fTemp6 - fRec3[1]);
iRec5[0] = (((iRec5[1] + (iRec5[1] > 0)) * (iTemp1 <= iVec2[1])) + (iTemp1 > iVec2[1]));
float fTemp7 = float(iRec5[0]);
float fTemp8 = (fSlow0 * ((iRec0[0] ? (0.0f - (fConst5 * fRec4[0])) : (0.0f - (fConst2 * fRec2[0]))) * std::max<float>(0.0f, std::min<float>((fConst8 * fTemp7), ((fConst9 * (fConst7 - fTemp7)) + 1.0f)))));
outputL[i] += float(fTemp8);
outputR[i] += float(fTemp8);
iVec0[1] = iVec0[0];
iVec1[1] = iVec1[0];
iVec2[1] = iVec2[0];
iRec0[1] = iRec0[0];
fVec3[1] = fVec3[0];
fRec1[1] = fRec1[0];
fRec2[1] = fRec2[0];
fVec4[1] = fVec4[0];
fRec3[1] = fRec3[0];
fRec4[1] = fRec4[0];
iRec5[1] = iRec5[0];
}
}
} // namespace sfz

59
src/sfizz/Metronome.h Normal file
View file

@ -0,0 +1,59 @@
// SPDX-License-Identifier: BSD-2-Clause
// This code is part of the sfizz library and is licensed under a BSD 2-clause
// license. You should have receive a LICENSE.md file along with the code.
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#pragma once
#include <algorithm>
#include <cmath>
namespace sfz {
class Metronome {
public:
Metronome();
void init(float sampleRate);
void clear();
void processAdding(const int* beats, const int* beatsPerBar, float* outputL, float* outputR, int numFrames);
void setGain(float gain) { fGain = gain; }
private:
float fGain;
int iVec0[2];
int iVec1[2];
int iVec2[2];
int iRec0[2];
float fConst0;
float fConst1;
float fConst2;
float fVec3[2];
float fConst3;
float fRec1[2];
float fRec2[2];
float fConst4;
float fConst5;
float fVec4[2];
float fConst6;
float fRec3[2];
float fRec4[2];
float fConst7;
float fConst8;
int iRec5[2];
float fConst9;
/*
import("stdfaust.lib");
process(beats, beatsPerBar) = tone : *(envelope) <: (_, _) with {
gain = hslider("[1] Gain", 0.5, 0.0, 1.0, 0.001);
beatNumber = int(beats);
beatIncrement = beatNumber-beatNumber';
tone = (os.oscws(440.0), os.oscws(880.0)) : select2(toneSelect);
toneSelect = x letrec { 'x = ba.if(beatIncrement>0, (beatNumber%int(beatsPerBar))==0, x); };
envelope = (beatIncrement>0) : en.ar(5e-3, 100e-3) : *(gain);
};
*/
};
} // namespace sfz

View file

@ -13,6 +13,8 @@
#include "Wavetables.h"
#include "Curve.h"
#include "Tuning.h"
#include "BeatClock.h"
#include "Metronome.h"
#include "modulations/ModMatrix.h"
#include "absl/types/optional.h"
@ -32,11 +34,15 @@ struct Resources
Tuning tuning;
absl::optional<StretchTuning> stretch;
ModMatrix modMatrix;
BeatClock beatClock;
Metronome metronome;
void setSampleRate(float samplerate)
{
midiState.setSampleRate(samplerate);
modMatrix.setSampleRate(samplerate);
beatClock.setSampleRate(samplerate);
metronome.init(samplerate);
}
void setSamplesPerBlock(int samplesPerBlock)
@ -44,6 +50,7 @@ struct Resources
bufferPool.setBufferSize(samplesPerBlock);
midiState.setSamplesPerBlock(samplesPerBlock);
modMatrix.setSamplesPerBlock(samplesPerBlock);
beatClock.setSamplesPerBlock(samplesPerBlock);
}
void clear()
@ -54,6 +61,8 @@ struct Resources
logger.clear();
midiState.reset();
modMatrix.clear();
beatClock.clear();
metronome.clear();
}
};
}

View file

@ -856,6 +856,9 @@ void Synth::renderBlock(AudioSpan<float> buffer) noexcept
ModMatrix& mm = impl.resources_.modMatrix;
mm.beginCycle(numFrames);
BeatClock& bc = impl.resources_.beatClock;
bc.beginCycle(numFrames);
{ // Clear effect busses
ScopedTiming logger { callbackBreakdown.effects };
for (auto& bus : impl.effectBuses_) {
@ -918,9 +921,20 @@ void Synth::renderBlock(AudioSpan<float> buffer) noexcept
// Apply the master volume
buffer.applyGain(db2mag(impl.volume_));
// Process the metronome (debugging tool for host time info)
constexpr bool metronomeEnabled = false;
if (metronomeEnabled) {
impl.resources_.metronome.processAdding(
bc.getRunningBeat().data(), bc.getRunningBeatsPerBar().data(),
buffer.getChannel(0), buffer.getChannel(1), numFrames);
}
// Perform any remaining modulators
mm.endCycle();
// Advance the clock to the end of cycle
bc.endCycle();
{ // Clear events and advance midi time
ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration };
impl.resources_.midiState.advanceTime(buffer.getNumFrames());
@ -1167,36 +1181,33 @@ void Synth::aftertouch(int /* delay */, uint8_t /* aftertouch */) noexcept
Impl& impl = *impl_;
ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration };
}
void Synth::tempo(int /* delay */, float /* secondsPerQuarter */) noexcept
void Synth::tempo(int delay, float secondsPerBeat) noexcept
{
Impl& impl = *impl_;
ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration };
impl.resources_.beatClock.setTempo(delay, secondsPerBeat);
}
void Synth::timeSignature(int delay, int beatsPerBar, int beatUnit)
{
Impl& impl = *impl_;
ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration };
(void)delay;
(void)beatsPerBar;
(void)beatUnit;
impl.resources_.beatClock.setTimeSignature(delay, TimeSignature(beatsPerBar, beatUnit));
}
void Synth::timePosition(int delay, int bar, float barBeat)
void Synth::timePosition(int delay, int bar, double barBeat)
{
Impl& impl = *impl_;
ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration };
(void)delay;
(void)bar;
(void)barBeat;
impl.resources_.beatClock.setTimePosition(delay, BBT(bar, barBeat));
}
void Synth::playbackState(int delay, int playbackState)
{
Impl& impl = *impl_;
ScopedTiming logger { impl.dispatchDuration_, ScopedTiming::Operation::addToDuration };
(void)delay;
(void)playbackState;
impl.resources_.beatClock.setPlaying(delay, playbackState == 1);
}
int Synth::getNumRegions() const noexcept

View file

@ -396,7 +396,7 @@ public:
* @param bar The current bar.
* @param bar_beat The fractional position of the current beat within the bar.
*/
void timePosition(int delay, int bar, float barBeat);
void timePosition(int delay, int bar, double barBeat);
/**
* @brief Send the playback state.
*

View file

@ -164,7 +164,7 @@ void sfz::Sfizz::timeSignature(int delay, int beatsPerBar, int beatUnit)
synth->timeSignature(delay, beatsPerBar, beatUnit);
}
void sfz::Sfizz::timePosition(int delay, int bar, float barBeat)
void sfz::Sfizz::timePosition(int delay, int bar, double barBeat)
{
synth->timePosition(delay, bar, barBeat);
}

View file

@ -166,7 +166,7 @@ void sfizz_send_time_signature(sfizz_synth_t* synth, int delay, int beats_per_ba
auto* self = reinterpret_cast<sfz::Synth*>(synth);
self->timeSignature(delay, beats_per_bar, beat_unit);
}
void sfizz_send_time_position(sfizz_synth_t* synth, int delay, int bar, float bar_beat)
void sfizz_send_time_position(sfizz_synth_t* synth, int delay, int bar, double bar_beat)
{
auto* self = reinterpret_cast<sfz::Synth*>(synth);
self->timePosition(delay, bar, bar_beat);

View file

@ -286,7 +286,7 @@ void SfizzVstProcessor::updateTimeInfo(const Vst::ProcessContext& context)
double beats = context.projectTimeMusic * 0.25 * _timeSigDenominator;
double bars = beats / _timeSigNumerator;
beats -= int(bars) * _timeSigNumerator;
synth.timePosition(0, int(bars), float(beats));
synth.timePosition(0, int(bars), beats);
}
synth.playbackState(0, (context.state & context.kPlaying) != 0);