146 double threshold, std::span<double> out)
noexcept {
147 if (!std::isfinite(increment) || increment == 0.0)
return 0;
151 const double q0 = phase_before_advance - threshold;
152 const double first = std::floor(q0);
153 const double last = std::floor(q0 + increment);
154 if (!std::isfinite(
first) || !std::isfinite(last))
return 0;
156 const bool forward = increment > 0.0;
158 if (!(magnitude >= 1.0))
return 0;
160 const int capacity =
static_cast<int>(out.size());
161 const int count = magnitude >
static_cast<double>(capacity)
163 :
static_cast<int>(magnitude);
165 for (
int k = 0; k < count; ++k) {
168 out[
static_cast<std::size_t
>(k)] = (level - q0) / increment;
198 double phase() const noexcept {
return phase_.phase(); }
208 double next(
double increment)
noexcept {
209 const double entry_phase = phase_.phase();
210 double out = value(entry_phase) + carry_;
213 phase_.advance(increment);
214 correct_events(increment, out);
217 scan_threshold(entry_phase, increment, increment, 0.0, 1.0, out);
233 double next_synced(
double increment,
double sync_frac,
double sync_phase = 0.0) noexcept {
234 const double entry_phase = phase_.phase();
235 double out = value(entry_phase) + carry_;
238 phase_.advance_synced(increment, sync_frac, sync_phase);
239 correct_events(increment, out);
252 const double f = clamp_unit(sync_frac);
253 scan_threshold(entry_phase, increment * f, increment, 0.0, f, out);
254 scan_threshold(wrap_unit(sync_phase), increment * (1.0 - f), increment, f, 1.0 - f, out);
268 void correct_events(
double increment,
double& out)
noexcept {
270 const double value_step = value(
e.phase_after) - value(
e.phase_before);
271 const double slope_step =
272 (slope_per_cycle(
e.phase_after) - slope_per_cycle(
e.phase_before)) * increment;
273 add_break(
e.frac, value_step, slope_step, out);
286 void scan_threshold(
double start_phase,
double delta,
double rate,
double t0,
double span,
287 double& out)
noexcept {
289 if (!internal_threshold(t))
return;
297 const bool forward = delta > 0.0;
298 const double value_step =
299 forward ? (t.value_above - t.value_below) : (t.value_below - t.value_above);
300 const double slope_step =
301 (
forward ? (t.slope_above - t.slope_below) : (t.slope_below - t.slope_above)) * rate;
303 for (
int k = 0; k < n; ++k)
304 add_break(t0 + fracs[k] * span, value_step, slope_step, out);
315 double value_below = 0.0;
316 double value_above = 0.0;
317 double slope_below = 0.0;
318 double slope_above = 0.0;
321 bool internal_threshold(Threshold& t)
const noexcept {
325 if (!(pulse_width_ > 0.0 && pulse_width_ < 1.0))
return false;
326 t = {pulse_width_, 1.0, -1.0, 0.0, 0.0};
330 t = {0.5, 1.0, 1.0, 4.0, -4.0};
355 double value(
double p)
const noexcept {
372 return p >= 1.0 ? 0.0 : std::sin(2.0 * std::numbers::pi * p);
375 return 2.0 *
p - 1.0;
381 return (pulse_width_ >= 1.0 || p < pulse_width_) ? 1.0 : -1.0;
384 return p < 0.5 ? (4.0 *
p - 1.0) : (3.0 - 4.0 *
p);
397 double slope_per_cycle(
double p)
const noexcept {
400 return 2.0 * std::numbers::pi * std::cos(2.0 * std::numbers::pi * p);
404 return p < 0.5 ? 4.0 : -4.0;
413 void add_break(
double frac,
double value_step,
double slope_step,
double& out)
noexcept {
414 if (value_step != 0.0) {
415 const Correction
c =
poly_blep(frac, value_step);
419 if (slope_step != 0.0) {
426 static double clamp_unit(
double x)
noexcept {
427 if (!(x > 0.0))
return 0.0;
428 if (x > 1.0)
return 1.0;
438 static double wrap_unit(
double x)
noexcept {
439 const double w =
x - std::floor(x);
440 return (w >= 0.0 && w < 1.0) ?
w : 0.0;
443 PhaseAccumulator phase_;
445 double pulse_width_ = 0.5;
Bandlimited-step (BLEP) and bandlimited-ramp (BLAMP) correction kernels.
static constexpr int max_events_per_sample
Event capacity of a single advance. See the truncation note above.
Definition phase.hpp:132
std::span< const PhaseEvent > events() const
Events from the last advance, in chronological order.
Definition phase.hpp:179
Virtual-analog oscillator over the static shapes.
Definition va.hpp:174
void set_shape(VaShape shape) noexcept
Definition va.hpp:176
void set_pulse_width(double width) noexcept
Fraction of the period the square spends high, clamped to [0, 1].
Definition va.hpp:188
VaShape shape() const noexcept
Definition va.hpp:177
double next(double increment) noexcept
Generate one sample and advance by increment cycles.
Definition va.hpp:208
double pulse_width() const noexcept
Definition va.hpp:189
void reset(double phase=0.0) noexcept
Set the phase and drop any pending correction.
Definition va.hpp:192
double phase() const noexcept
Current phase, in [0, 1).
Definition va.hpp:198
double next_synced(double increment, double sync_frac, double sync_phase=0.0) noexcept
Generate one sample, advancing by increment but forcing the phase to sync_phase at sub-sample positio...
Definition va.hpp:233
Correction poly_blep(double d, double height) noexcept
polyBLEP correction for a step in the VALUE.
Definition blep.hpp:177
int threshold_crossings(double phase_before_advance, double increment, double threshold, std::span< double > out) noexcept
Sub-sample positions at which the phase crosses threshold (mod 1) during one sample,...
Definition va.hpp:145
Correction poly_blamp(double d, double slope_change) noexcept
polyBLAMP correction for a break in the SLOPE.
Definition blep.hpp:206
VaShape
The static shapes.
Definition va.hpp:113
@ square
Value steps of +2 at the wrap and -2 at the pulse edge.
Definition va.hpp:116
@ sine
Continuous across a wrap; a sync still steps it.
Definition va.hpp:114
@ saw
Value step of -2 at the wrap.
Definition va.hpp:115
@ triangle
Slope breaks at the wrap and the apex; value is continuous.
Definition va.hpp:117
@ first
Definition dither.hpp:23
@ forward
(s + 1) mod N.
Definition stage_sequencer.hpp:18
@ c
Definition spectrum_trace.hpp:35
@ e
Definition formant_filter_bank.hpp:20
@ p
Definition input_events.hpp:40
@ x
Definition input_events.hpp:41
@ t
Definition input_events.hpp:41
@ w
Definition input_events.hpp:41
A single phase discontinuity within one sample period.
Definition phase.hpp:28