140 sample_rate_ = sample_rate > 0.0 ? sample_rate : sample_rate_;
156 double note_hz() const noexcept {
return note_hz_; }
162 double pulse_width() const noexcept {
return core_.pulse_width(); }
174 ?
static_cast<long long>(delta_)
191 return (realized_hz_ > 0.0 && effective_note_hz_ > 0.0)
192 ? 1200.0 * std::log2(realized_hz_ / effective_note_hz_)
213 if (!(profile_.master_clock_hz > 0.0) || !(effective_note_hz_ > 0.0))
return 0.0;
214 const double ideal_divider =
216 ? profile_.master_clock_hz / effective_note_hz_
217 :
static_cast<double>(two_b_) * effective_note_hz_ / profile_.master_clock_hz;
222 if (!(ideal_divider > 0.5))
return 0.0;
228 !(ideal_divider <
static_cast<double>(two_b_) - 0.5))
230 return 1200.0 * std::log2(ideal_divider / (ideal_divider - 0.5));
239 const int n =
static_cast<int>(out.size());
244 std::uint64_t residue = 0;
245 for (
int i = 0;
i < n; ++
i)
246 out[
static_cast<std::size_t
>(
i)] = advance_divider(residue);
256 current_interval_ = advance_divider(residue_);
257 clocks_to_reset_ =
static_cast<double>(current_interval_);
259 current_interval_ = divider_;
260 clocks_to_reset_ = 0.0;
264 double phase() const noexcept {
return core_.phase(); }
271 return core_.next(increment_integer_);
278 const double increment = clocks_per_sample_ /
static_cast<double>(current_interval_);
280 if (clocks_to_reset_ < clocks_per_sample_) {
281 const double frac = clocks_to_reset_ > 0.0 ? clocks_to_reset_ / clocks_per_sample_ : 0.0;
282 out = core_.next_synced(increment, frac, 0.0);
283 const long long next_interval = advance_divider(residue_);
284 clocks_to_reset_ +=
static_cast<double>(next_interval);
285 current_interval_ = next_interval;
287 out = core_.next(increment);
289 clocks_to_reset_ -= clocks_per_sample_;
299 long long advance_divider(std::uint64_t& residue)
const noexcept {
302 const std::uint64_t m = (two_b_ - residue + delta_ - 1) / delta_;
303 residue = residue + m * delta_ - two_b_;
304 return static_cast<long long>(m);
307 void recompute() noexcept {
308 clocks_per_sample_ = sample_rate_ > 0.0 ? profile_.
master_clock_hz / sample_rate_ : 0.0;
313 two_b_ = std::uint64_t{1} << bits;
316 note_hz_ * std::exp2(
static_cast<double>(profile_.
octave_shift) +
321 const double ideal = effective_note_hz_ > 0.0 ? f_clk / effective_note_hz_ : 1.0;
322 divider_ =
static_cast<long long>(std::llround(ideal));
323 if (divider_ < 1) divider_ = 1;
324 realized_hz_ = divider_ > 0 ? f_clk /
static_cast<double>(divider_) : 0.0;
325 increment_integer_ = sample_rate_ > 0.0 ? realized_hz_ / sample_rate_ : 0.0;
329 f_clk > 0.0 ? effective_note_hz_ *
static_cast<double>(two_b_) / f_clk : 1.0;
330 long long d =
static_cast<long long>(std::llround(ideal));
332 if (
static_cast<std::uint64_t
>(d) >= two_b_) d =
static_cast<long long>(two_b_ - 1);
333 delta_ =
static_cast<std::uint64_t
>(d);
334 realized_hz_ = f_clk *
static_cast<double>(delta_) /
static_cast<double>(two_b_);
336 increment_integer_ = 0.0;
344 DcoProfile profile_{};
345 double sample_rate_ = 48000.0;
346 double note_hz_ = 261.625565;
349 double clocks_per_sample_ = 0.0;
350 double effective_note_hz_ = 261.625565;
351 double realized_hz_ = 0.0;
352 long long divider_ = 1;
353 std::uint64_t delta_ = 1;
354 std::uint64_t two_b_ = 1u << 24;
355 double increment_integer_ = 0.0;
358 std::uint64_t residue_ = 0;
359 long long current_interval_ = 1;
360 double clocks_to_reset_ = 0.0;
A divider-clocked oscillator front-end composing the shared VaOscillator.
Definition dco.hpp:137
void reset(double phase=0.0) noexcept
Reset the phase and the divider schedule to a known start.
Definition dco.hpp:252
VaShape shape() const noexcept
Definition dco.hpp:160
double note_hz() const noexcept
Definition dco.hpp:156
void prepare(double sample_rate) noexcept
Definition dco.hpp:139
double phase() const noexcept
Definition dco.hpp:264
double effective_note_hz() const noexcept
The effective note after footage and fine-tune — the target the divider approximates.
Definition dco.hpp:182
void set_shape(VaShape shape) noexcept
Definition dco.hpp:159
double detune_cents() const noexcept
Pitch-quantization error in cents: 1200 · log2(realized / f_note_eff).
Definition dco.hpp:190
const DcoProfile & profile() const noexcept
Definition dco.hpp:148
long long tuning_word() const noexcept
Fractional tuning word Δ = round(f_note_eff · 2^B / f_clk).
Definition dco.hpp:172
void set_pulse_width(double width) noexcept
Definition dco.hpp:161
void set_profile(const DcoProfile &profile) noexcept
Definition dco.hpp:144
double pulse_width() const noexcept
Definition dco.hpp:162
long long divider_n() const noexcept
Integer divider N = round(f_clk / f_note_eff).
Definition dco.hpp:167
double next() noexcept
Generate one sample and advance the divider by one output sample.
Definition dco.hpp:267
int reset_intervals(std::span< long long > out) const noexcept
Fill out with the next divider reset intervals, in master clocks, from a fresh divider state — a pure...
Definition dco.hpp:238
double quantization_bound_cents() const noexcept
The worst-case quantization bound in cents for the active scheme — an EXACT upper bound on |detune_ce...
Definition dco.hpp:212
double realized_hz() const noexcept
The realised frequency the divider actually produces: f_clk / N for integer-N, f_clk · Δ / 2^B (the a...
Definition dco.hpp:179
void set_note_hz(double note_hz) noexcept
Command the pitch.
Definition dco.hpp:152
DcoDivider
The divider scheme a profile selects.
Definition dco.hpp:98
@ integer_n
Fixed integer divider N; perfectly periodic, quantized pitch.
Definition dco.hpp:99
@ fractional_n
B-bit fractional accumulator; accurate average pitch, ±1-clock jitter.
Definition dco.hpp:100
VaShape
The static shapes.
Definition va.hpp:113
@ i
Definition formant_filter_bank.hpp:20
OSC-DCO profile — data-driven timing parameters, no waveform or hardware capture.
Definition dco.hpp:111
DcoDivider divider_scheme
Selects the integer-N (perfectly periodic) or fractional-N (accurate average, jittered) path.
Definition dco.hpp:117
double master_clock_hz
f_clk in Hz.
Definition dco.hpp:114
int octave_shift
Footage / octave selection, in octaves relative to the commanded note.
Definition dco.hpp:125
double fine_tune_cents
Global detune folded into the note before N / Δ derivation, in cents.
Definition dco.hpp:127
int accumulator_bits
B — accumulator width, fractional-N only.
Definition dco.hpp:120
Virtual-analog oscillator: the classic static shapes, bandlimited by composing PhaseAccumulator (the ...