Implement lfoN_beats

This commit is contained in:
Jean Pierre Cimalando 2020-11-15 15:00:51 +01:00
parent c1306f8a71
commit d8dcb2e56f
6 changed files with 54 additions and 14 deletions

View file

@ -222,6 +222,7 @@ namespace Default
constexpr int numLFOSubs { 2 }; constexpr int numLFOSubs { 2 };
constexpr int numLFOSteps { 8 }; constexpr int numLFOSteps { 8 };
constexpr Range<float> lfoFreqRange { 0.0, 100.0 }; constexpr Range<float> lfoFreqRange { 0.0, 100.0 };
constexpr Range<float> lfoBeatsRange { 0.0, 1000.0 };
constexpr Range<float> lfoPhaseRange { 0.0, 1.0 }; constexpr Range<float> lfoPhaseRange { 0.0, 1.0 };
constexpr Range<float> lfoDelayRange { 0.0, 30.0 }; constexpr Range<float> lfoDelayRange { 0.0, 30.0 };
constexpr Range<float> lfoFadeRange { 0.0, 30.0 }; constexpr Range<float> lfoFadeRange { 0.0, 30.0 };

View file

@ -6,6 +6,7 @@
#include "LFO.h" #include "LFO.h"
#include "LFODescription.h" #include "LFODescription.h"
#include "BeatClock.h"
#include "BufferPool.h" #include "BufferPool.h"
#include "MathHelpers.h" #include "MathHelpers.h"
#include "SIMDHelpers.h" #include "SIMDHelpers.h"
@ -17,14 +18,16 @@
namespace sfz { namespace sfz {
struct LFO::Impl { struct LFO::Impl {
explicit Impl(BufferPool& bufferPool) explicit Impl(BufferPool& bufferPool, BeatClock* beatClock)
: bufferPool_(bufferPool), : bufferPool_(bufferPool),
beatClock_(beatClock),
sampleRate_(config::defaultSampleRate), sampleRate_(config::defaultSampleRate),
desc_(&LFODescription::getDefault()) desc_(&LFODescription::getDefault())
{ {
} }
BufferPool& bufferPool_; BufferPool& bufferPool_;
BeatClock* beatClock_ = nullptr;
float sampleRate_ = 0; float sampleRate_ = 0;
// control // control
@ -38,8 +41,8 @@ struct LFO::Impl {
std::array<int, config::maxLFOSubs> sampleHoldState_ {{}}; std::array<int, config::maxLFOSubs> sampleHoldState_ {{}};
}; };
LFO::LFO(BufferPool& bufferPool) LFO::LFO(BufferPool& bufferPool, BeatClock* beatClock)
: impl_(new Impl(bufferPool)) : impl_(new Impl(bufferPool, beatClock))
{ {
} }
@ -299,26 +302,46 @@ void LFO::processFadeIn(absl::Span<float> out)
void LFO::generatePhase(unsigned nth, absl::Span<float> phases) void LFO::generatePhase(unsigned nth, absl::Span<float> phases)
{ {
Impl& impl = *impl_; Impl& impl = *impl_;
BeatClock* beatClock = impl.beatClock_;
const LFODescription& desc = *impl.desc_; const LFODescription& desc = *impl.desc_;
const LFODescription::Sub& sub = desc.sub[nth]; const LFODescription::Sub& sub = desc.sub[nth];
const float samplePeriod = 1.0f / impl.sampleRate_; const float samplePeriod = 1.0f / impl.sampleRate_;
const float baseFreq = desc.freq; const float baseFreq = desc.freq;
const float beats = desc.beats;
const float phaseOffset = desc.phase0; const float phaseOffset = desc.phase0;
const float ratio = sub.ratio; const float ratio = sub.ratio;
float phase = impl.subPhases_[nth]; float phase = impl.subPhases_[nth];
const size_t numFrames = phases.size();
for (size_t i = 0, n = phases.size(); i < n; ++i) { if (beatClock && beatClock->isPlaying() && beats > 0) {
float withOffset = phase + phaseOffset; // generate using the beat clock
withOffset -= (int)withOffset; float beatRatio = (ratio > 0) ? (1.0f / ratio) : 0.0f;
beatClock->calculatePhase(beats * beatRatio, phases.data());
phases[i] = withOffset; for (size_t i = 0; i < numFrames; ++i) {
float withOffset = phase + phaseOffset;
withOffset -= (int)withOffset;
// TODO(jpc) lfoN_count: number of repetitions phases[i] = withOffset;
float incr = ratio * samplePeriod * baseFreq; // TODO(jpc) lfoN_count: number of repetitions
phase += incr; }
int numWraps = (int)phase; }
phase -= numWraps; else {
// generate using the frequency
for (size_t i = 0; i < numFrames; ++i) {
float withOffset = phase + phaseOffset;
withOffset -= (int)withOffset;
phases[i] = withOffset;
// TODO(jpc) lfoN_count: number of repetitions
float incr = ratio * samplePeriod * baseFreq;
phase += incr;
int numWraps = (int)phase;
phase -= numWraps;
}
} }
impl.subPhases_[nth] = phase; impl.subPhases_[nth] = phase;

View file

@ -10,6 +10,7 @@
namespace sfz { namespace sfz {
class BufferPool; class BufferPool;
class BeatClock;
enum class LFOWave : int; enum class LFOWave : int;
struct LFODescription; struct LFODescription;
@ -50,7 +51,9 @@ struct LFODescription;
class LFO { class LFO {
public: public:
explicit LFO(BufferPool& bufferPool); explicit LFO(
BufferPool& bufferPool,
BeatClock* beatClock = nullptr);
~LFO(); ~LFO();
/** /**

View file

@ -28,6 +28,7 @@ struct LFODescription {
~LFODescription(); ~LFODescription();
static const LFODescription& getDefault(); static const LFODescription& getDefault();
float freq = 0; // lfoN_freq float freq = 0; // lfoN_freq
float beats = 0; // lfoN_beats
float phase0 = 0; // lfoN_phase float phase0 = 0; // lfoN_phase
float delay = 0; // lfoN_delay float delay = 0; // lfoN_delay
float fade = 0; // lfoN_fade float fade = 0; // lfoN_fade

View file

@ -866,6 +866,16 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode)
setValueFromOpcode(opcode, lfos[lfoNumber - 1].freq, Default::lfoFreqRange); setValueFromOpcode(opcode, lfos[lfoNumber - 1].freq, Default::lfoFreqRange);
} }
break; break;
case hash("lfo&_beats"):
{
const auto lfoNumber = opcode.parameters.front();
if (lfoNumber == 0)
return false;
if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs))
return false;
setValueFromOpcode(opcode, lfos[lfoNumber - 1].beats, Default::lfoBeatsRange);
}
break;
case hash("lfo&_phase"): case hash("lfo&_phase"):
{ {
const auto lfoNumber = opcode.parameters.front(); const auto lfoNumber = opcode.parameters.front();

View file

@ -1475,10 +1475,12 @@ void Voice::setMaxEQsPerVoice(size_t numFilters)
void Voice::setMaxLFOsPerVoice(size_t numLFOs) void Voice::setMaxLFOsPerVoice(size_t numLFOs)
{ {
Impl& impl = *impl_; Impl& impl = *impl_;
Resources& resources = impl.resources_;
impl.lfos_.resize(numLFOs); impl.lfos_.resize(numLFOs);
for (size_t i = 0; i < numLFOs; ++i) { for (size_t i = 0; i < numLFOs; ++i) {
auto lfo = absl::make_unique<LFO>(impl.resources_.bufferPool); auto lfo = absl::make_unique<LFO>(resources.bufferPool, &resources.beatClock);
lfo->setSampleRate(impl.sampleRate_); lfo->setSampleRate(impl.sampleRate_);
impl.lfos_[i] = std::move(lfo); impl.lfos_[i] = std::move(lfo);
} }