65 static_assert(std::is_floating_point_v<T>,
"Oscillator requires float or double");
81 assert(sampleRate > 0.0);
82 sampleRate_ = sampleRate;
107 if (freq != freq)
return;
109 T nyquist =
static_cast<T
>(sampleRate_ * 0.5);
110 frequency_ = std::clamp(freq, T(0), nyquist);
143 syncRatio_ = std::max(T(0), ratio);
163 phase_ = phase - std::floor(phase);
164 if (phase_ >= T(1)) phase_ -= T(1);
173 const T ph = syncOn_ ? slavePhase_ : phase_;
174 const T ideal = (ph < T(0.5)) ? (T(4) * ph - T(1)) : (T(3) - T(4) * ph);
175 triState_ =
static_cast<double>(ideal * triExpectedPeak_);
187 triState_ = -
static_cast<double>(triExpectedPeak_);
201 return nextSyncSample();
210 out =
fastSin(phase_ * twoPi<T>);
214 out = T(2) * phase_ - T(1);
215 out -= polyBlep(phase_, phaseInc_);
220 T raw = (phase_ < T(0.5)) ? T(1) : T(-1);
221 raw += polyBlep(phase_, phaseInc_);
224 T halfPhase = phase_ + T(0.5);
225 if (halfPhase >= T(1)) halfPhase -= T(1);
227 raw -= polyBlep(halfPhase, phaseInc_);
234 T raw = (phase_ < T(0.5)) ? T(1) : T(-1);
235 raw += polyBlep(phase_, phaseInc_);
237 T halfPhase = phase_ + T(0.5);
238 if (halfPhase >= T(1)) halfPhase -= T(1);
239 raw -= polyBlep(halfPhase, phaseInc_);
244 const double inc =
static_cast<double>(phaseInc_);
245 triState_ = inc *
static_cast<double>(raw) + (1.0 - inc) * triState_;
246 out =
static_cast<T
>(triState_) * triNorm_;
253 if (phase_ >= T(1)) phase_ -= T(1);
270 for (
size_t i = 0; i < numSamples; ++i)
286 const int nCh = buffer.getNumChannels();
287 const int nS = buffer.getNumSamples();
290 for (
int i = 0; i < nS; ++i)
294 T* ch0 = buffer.getChannel(0);
295 for (
int i = 0; i < nS; ++i)
297 for (
int ch = 1; ch < nCh; ++ch)
298 std::copy_n(ch0,
static_cast<size_t>(nS), buffer.getChannel(ch));
301 [[nodiscard]] T
getPhase() const noexcept {
return phase_; }
308 [[nodiscard]] T rawSlaveValue(T ph)
const noexcept
332 [[nodiscard]] T nextSyncSample() noexcept
334 const bool squareLike =
338 T raw = rawSlaveValue(slavePhase_) + corr_[
static_cast<size_t>(corrHead_)];
339 corr_[
static_cast<size_t>(corrHead_)] = T(0);
340 corrHead_ = (corrHead_ + 1) & kCorrMask;
349 const double inc =
static_cast<double>(slaveInc_);
350 triState_ = inc * (
static_cast<double>(raw) -
static_cast<double>(syncSquareDc_))
351 + (1.0 - inc) * triState_;
352 out =
static_cast<T
>(triState_) * triNorm_;
356 const T masterOld = phase_;
357 const T slaveOld = slavePhase_;
359 slavePhase_ += slaveInc_;
361 const bool masterWrap = phase_ >= T(1);
362 const T alphaSync = masterWrap ? (T(1) - masterOld) / phaseInc_ : T(2);
369 T alphaEdge = T(2), edgeJump = T(0);
370 if (slavePhase_ >= T(1))
372 alphaEdge = (T(1) - slaveOld) / slaveInc_;
375 else if (squareLike && slaveOld < T(0.5) && slavePhase_ >= T(0.5))
377 alphaEdge = (T(0.5) - slaveOld) / slaveInc_;
380 if (alphaEdge <= alphaSync && alphaEdge <= T(1))
381 scheduleMinBlep(edgeJump, T(1) - alphaEdge);
383 if (slavePhase_ >= T(1)) slavePhase_ -= T(1);
389 T atJump = slaveOld + alphaSync * slaveInc_;
390 atJump -= std::floor(atJump);
391 const T jump = rawSlaveValue(T(0)) - rawSlaveValue(atJump);
393 scheduleMinBlep(jump, T(1) - alphaSync);
396 slavePhase_ = (phase_ / std::max(phaseInc_, T(1e-12))) * slaveInc_;
397 slavePhase_ -= std::floor(slavePhase_);
409 void scheduleMinBlep(T jump, T frac)
noexcept
412 for (
int j = 0; j < kCorrLen; ++j)
413 corr_[
static_cast<size_t>((corrHead_ + j) & kCorrMask)] +=
414 jump * table.residual(
static_cast<T
>(j) + frac);
426 void reseedSlave() noexcept
428 const T r = slaveInc_ / std::max(phaseInc_, T(1e-12));
429 slavePhase_ = phase_ * r;
430 slavePhase_ -= std::floor(slavePhase_);
442 static inline T polyBlep(T phase, T inc)
noexcept
444 if (inc < T(1e-10))
return T(0);
449 return t + t - t * t - T(1);
451 else if (phase > T(1) - inc)
453 T t = (phase - T(1)) / inc;
454 return t * t + t + t + T(1);
460 void updatePhaseInc() noexcept
466 phaseInc_ = std::min(frequency_ /
static_cast<T
>(sampleRate_), T(0.5));
467 const bool wasOn = syncOn_;
468 syncOn_ = syncRatio_ > T(1.001) && phaseInc_ > T(0);
470 slaveInc_ = std::min(phaseInc_ * syncRatio_, T(0.5));
477 syncSquareDc_ = T(0);
478 if (syncOn_ && phaseInc_ > T(0))
480 const T r = slaveInc_ / phaseInc_;
481 const T f = r - std::floor(r);
482 syncSquareDc_ = (std::min(f, T(0.5)) - std::max(f - T(0.5), T(0))) / r;
487 if (syncOn_ && !wasOn)
496 void updateTriNorm() noexcept
499 const T inc = syncOn_ ? slaveInc_ : phaseInc_;
500 if (inc == triNormInc_)
505 if (inc > T(0) && inc < T(1))
511 T leakCoeff = T(1) - inc;
512 T halfPeriodSamples = T(0.5) / inc;
513 T q = std::pow(leakCoeff, halfPeriodSamples);
514 T expectedPeak = (T(1) - q) / (T(1) + q);
515 triExpectedPeak_ = expectedPeak;
516 triNorm_ = (expectedPeak > T(0.001)) ? T(1) / expectedPeak : T(4);
520 triExpectedPeak_ = T(0.25);
525 double sampleRate_ = 48000.0;
526 T frequency_ = T(440);
529 double triState_ = 0.0;
531 T triExpectedPeak_ = T(0.25);
532 T triNormInc_ = T(-1);
537 static constexpr int kCorrMask = kCorrLen - 1;
538 static_assert((kCorrLen & kCorrMask) == 0,
"minBLEP ring needs a power-of-two span");
540 bool syncOn_ =
false;
542 T slavePhase_ = T(0);
544 T syncSquareDc_ = T(0);
545 std::array<T, kCorrLen> corr_{};