44 static_assert(std::is_floating_point_v<SampleType>);
50 sample_rate >
static_cast<double>(std::numeric_limits<SampleType>::max()))
53 oversampler_.set_kind(Oversampler::Kind::linear_phase_fir);
54 oversampler_.set_quality(Oversampler::Quality::standard);
56 oversampler_.set_sample_rate(
static_cast<SampleType
>(sample_rate_));
100 template <
typename Callback> SampleType
process(SampleType input, Callback&& callback) {
102 return callback(input);
103 return oversampler_.process(input, callback);
107 void configure_factor() {
113 double sample_rate_ = 48000.0;
119 constexpr double half_pi = std::numbers::pi / 2.0;
120 return (2.0 / std::numbers::pi) * std::asin(std::sin(half_pi * input));
124 const double cosine = std::cos((std::numbers::pi / 2.0) * input);
125 if (std::abs(cosine) < 1.0e-12)
127 return cosine > 0.0 ? 1.0 : -1.0;
141 static_assert(std::is_floating_point_v<SampleType>);
150 aliasing_.set_alias_policy(policy);
153 return aliasing_.alias_policy();
156 return aliasing_.oversample_factor();
159 return aliasing_.latency_samples();
162 return dc_output() == 0.0 ? aliasing_.tail_samples() : -1;
165 return aliasing_.sample_rate();
176 if (std::isfinite(fold01))
177 fold_ = std::clamp(fold01, 0.0, 1.0);
184 if (stage < 0 || stage >=
kMaxStages || !std::isfinite(offset))
186 offsets_[
static_cast<std::size_t
>(stage)] = std::clamp(offset, -1.0, 1.0);
191 return offsets_[
static_cast<std::size_t
>(stage)];
195 if (stage < 0 || stage >=
kMaxStages || !std::isfinite(symmetry))
197 symmetries_[
static_cast<std::size_t
>(stage)] = std::clamp(symmetry, -1.0, 1.0);
202 return symmetries_[
static_cast<std::size_t
>(stage)];
210 if (!std::isfinite(amount01))
212 dc_couplings_.fill(std::clamp(amount01, 0.0, 1.0));
215 if (stage < 0 || stage >=
kMaxStages || !std::isfinite(amount01))
217 dc_couplings_[
static_cast<std::size_t
>(stage)] = std::clamp(amount01, 0.0, 1.0);
222 return dc_couplings_[
static_cast<std::size_t
>(stage)];
228 double derivative = 1.0;
229 for (
int stage = 0; stage < stages_; ++stage) {
230 const std::size_t index =
static_cast<std::size_t
>(stage);
231 const double argument =
232 stage_gain(stage) * value + offsets_[index] + symmetries_[index] * value * value;
234 (stage_gain(stage) + 2.0 * symmetries_[index] * value);
249 SampleType
process(SampleType input)
noexcept {
250 if (!std::isfinite(
static_cast<double>(input))) {
252 return SampleType{0};
254 const SampleType output = aliasing_.process(input, [
this](SampleType sample) {
255 return static_cast<SampleType
>(
shape(
static_cast<double>(sample)));
257 if (!std::isfinite(
static_cast<double>(output))) {
259 return SampleType{0};
265 std::size_t sample_count)
noexcept {
266 if (input ==
nullptr || output ==
nullptr)
268 for (std::size_t
i = 0;
i < sample_count; ++
i)
272 double shape(
double input)
const noexcept {
274 for (
int stage = 0; stage < stages_; ++stage) {
275 const std::size_t index =
static_cast<std::size_t
>(stage);
276 const double argument =
277 stage_gain(stage) * output + offsets_[index] + symmetries_[index] * output * output;
285 double stage_gain(
int stage)
const noexcept {
286 return 1.0 + fold_ * (1.0 + 0.5 *
static_cast<double>(stage));
291 std::array<double, kMaxStages> offsets_{};
292 std::array<double, kMaxStages> symmetries_{};
293 std::array<double, kMaxStages> dc_couplings_{1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0};
294 detail::NonlinearOversamplingT<SampleType> aliasing_{};
306 static_assert(std::is_floating_point_v<SampleType>);
310 coefficients_[1] = 1.0;
317 aliasing_.set_alias_policy(policy);
320 return aliasing_.alias_policy();
323 return aliasing_.oversample_factor();
326 return aliasing_.latency_samples();
329 return aliasing_.tail_samples();
332 return aliasing_.sample_rate();
336 coefficients_.fill(0.0);
340 if (order < 1 || order >
kMaxHarmonic || !std::isfinite(amplitude))
342 coefficients_[
static_cast<std::size_t
>(order)] = std::clamp(amplitude, -1.0, 1.0);
348 return coefficients_[
static_cast<std::size_t
>(order)];
359 const int residue = order & 3;
360 const double derivative = residue == 1 ?
static_cast<double>(order)
361 : residue == 3 ? -
static_cast<double>(order)
363 gain += coefficients_[
static_cast<std::size_t
>(order)] * derivative;
372 bound += std::abs(coefficients_[
static_cast<std::size_t
>(order)]) *
373 ((order & 1) == 0 ? 2.0 : 1.0);
381 SampleType
process(SampleType input)
noexcept {
382 if (!std::isfinite(
static_cast<double>(input))) {
384 return SampleType{0};
386 const SampleType output = aliasing_.process(input, [
this](SampleType sample) {
387 return static_cast<SampleType
>(
shape(
static_cast<double>(sample)));
389 if (!std::isfinite(
static_cast<double>(output))) {
391 return SampleType{0};
397 std::size_t sample_count)
noexcept {
398 if (input ==
nullptr || output ==
nullptr)
400 for (std::size_t
i = 0;
i < sample_count; ++
i)
404 double shape(
double input)
const noexcept {
405 const double x = std::clamp(input, -1.0, 1.0);
406 double previous = 1.0;
408 double output = coefficients_[1] * current;
410 const double next = 2.0 * x * current - previous;
411 const double at_zero = (order & 1) != 0 ? 0.0 : ((order & 3) == 0 ? 1.0 : -1.0);
412 output += coefficients_[
static_cast<std::size_t
>(order)] * (next - at_zero);
420 std::array<double, kMaxHarmonic + 1> coefficients_{};
421 detail::NonlinearOversamplingT<SampleType> aliasing_{};
452 static_assert(std::is_floating_point_v<SampleType>);
460 sample_rate_ = aliasing_.sample_rate();
461 carrier_hz_ = std::clamp(carrier_hz_, 0.0, 0.49 * sample_rate_);
462 update_phase_increment();
467 if (!aliasing_.set_alias_policy(policy))
469 update_phase_increment();
473 return aliasing_.alias_policy();
476 return aliasing_.oversample_factor();
479 return aliasing_.latency_samples();
482 return aliasing_.tail_samples();
501 if (!std::isfinite(hz))
503 const double current_phase =
phase();
504 carrier_hz_ = std::clamp(hz, 0.0, 0.49 * sample_rate_);
505 update_phase_increment();
506 reset_carrier(current_phase);
513 if (std::isfinite(index01))
514 index_ = std::clamp(index01, 0.0, 1.0);
521 if (std::isfinite(drive))
522 nonlinear_drive_ = std::clamp(drive, 0.25, 16.0);
525 return nonlinear_drive_;
529 if (waveform_ == waveform)
545 const double current_phase =
phase();
546 carrier_.set_shape(
shape);
547 reset_carrier(current_phase);
548 waveform_ = waveform;
558 carrier_mode_ = mode;
563 return carrier_mode_;
570 output_polarity_ = polarity;
575 return output_polarity_;
579 if (!std::isfinite(cycles))
581 reset_carrier(cycles);
584 const double value = carrier_.phase() + carrier_delay_cycles();
585 return value - std::floor(value);
597 SampleType
process(SampleType input)
noexcept {
598 if (!std::isfinite(
static_cast<double>(input))) {
600 return SampleType{0};
602 const SampleType output = aliasing_.process(input, [
this](SampleType sample) {
603 const double waveform = carrier_.next(phase_increment_);
604 const double mapped_carrier =
606 return static_cast<SampleType
>(
shape(
static_cast<double>(sample), mapped_carrier));
608 if (!std::isfinite(
static_cast<double>(output))) {
610 return SampleType{0};
616 std::size_t sample_count)
noexcept {
617 if (input ==
nullptr || output ==
nullptr)
619 for (std::size_t
i = 0;
i < sample_count; ++
i)
623 double shape(
double input,
double carrier)
const noexcept {
624 carrier = std::clamp(carrier, -1.0, 1.0);
625 double modulated = 0.0;
628 modulated = input * carrier;
631 const double drive = nonlinear_drive_;
632 const double half_input = 0.5 * input;
633 const double plus = carrier + half_input;
634 const double minus = carrier - half_input;
635 const double magnitude_difference = stable_magnitude_difference(half_input, carrier);
636 modulated = magnitude_difference + (log_cosh_correction(drive, std::abs(plus)) -
637 log_cosh_correction(drive, std::abs(minus))) /
642 const double mixed = std::lerp(input, modulated, index_);
647 double carrier_delay_cycles() const noexcept {
648 return 0.5 *
static_cast<double>(aliasing_.latency_samples()) * carrier_hz_ / sample_rate_;
651 void reset_carrier(
double logical_phase = 0.0) noexcept {
652 carrier_.
reset(logical_phase - carrier_delay_cycles());
655 void update_phase_increment() noexcept {
657 carrier_hz_ / (sample_rate_ *
static_cast<double>(aliasing_.oversample_factor()));
660 static double stable_magnitude_difference(
double half_input,
double carrier)
noexcept {
661 const double carrier_magnitude = std::abs(carrier);
662 const double limited = std::clamp(half_input, -carrier_magnitude, carrier_magnitude);
664 return 2.0 * limited;
666 return -2.0 * limited;
670 static double log_cosh_correction(
double drive,
double magnitude)
noexcept {
671 constexpr double kNegligibleCorrectionArgument = 40.0;
672 if (magnitude >= kNegligibleCorrectionArgument / drive)
674 return std::log1p(std::exp(-2.0 * drive * magnitude));
677 double sample_rate_ = 48000.0;
678 double carrier_hz_ = 440.0;
679 double phase_increment_ = 440.0 / (48000.0 * 4.0);
681 double nonlinear_drive_ = 2.0;
686 osc::VaOscillator carrier_{};
687 detail::NonlinearOversamplingT<SampleType> aliasing_{};
A fixed-storage Chebyshev-series transfer function.
Definition nonlinear_shaping.hpp:304
SampleType process(SampleType input) noexcept
Definition nonlinear_shaping.hpp:381
double worst_case_output() const noexcept
A transfer-domain bound, independent of the selected alias filter.
Definition nonlinear_shaping.hpp:369
int oversample_factor() const noexcept
Definition nonlinear_shaping.hpp:322
double harmonic(int order) const noexcept
Definition nonlinear_shaping.hpp:345
int latency_samples() const noexcept
Definition nonlinear_shaping.hpp:325
double shape(double input) const noexcept
Definition nonlinear_shaping.hpp:404
void prepare(double sample_rate)
Definition nonlinear_shaping.hpp:313
int tail_samples() const noexcept
Definition nonlinear_shaping.hpp:328
void set_alias_policy(NonlinearAliasPolicy policy)
Definition nonlinear_shaping.hpp:316
void reset() noexcept
Definition nonlinear_shaping.hpp:377
double small_signal_gain() const noexcept
The exact derivative of the configured, unclipped series at zero.
Definition nonlinear_shaping.hpp:356
void clear_harmonics() noexcept
Definition nonlinear_shaping.hpp:335
void process_block(const SampleType *input, SampleType *output, std::size_t sample_count) noexcept
Definition nonlinear_shaping.hpp:396
ChebyshevHarmonicShaperT() noexcept
Definition nonlinear_shaping.hpp:309
void set_harmonic(int order, double amplitude) noexcept
Definition nonlinear_shaping.hpp:339
NonlinearAliasPolicy alias_policy() const noexcept
Definition nonlinear_shaping.hpp:319
static constexpr int kMaxHarmonic
Definition nonlinear_shaping.hpp:307
double sample_rate() const noexcept
Definition nonlinear_shaping.hpp:331
static constexpr double dc_output() noexcept
Definition nonlinear_shaping.hpp:351
A sequential wavefolder whose stage drive increases through the chain.
Definition nonlinear_shaping.hpp:139
double stage_dc_coupling(int stage) const noexcept
Definition nonlinear_shaping.hpp:219
double dc_output() const noexcept
Definition nonlinear_shaping.hpp:241
double stage_offset(int stage) const noexcept
Definition nonlinear_shaping.hpp:188
void reset() noexcept
Definition nonlinear_shaping.hpp:245
void set_stage_symmetry(int stage, double symmetry) noexcept
Definition nonlinear_shaping.hpp:194
int tail_samples() const noexcept
Definition nonlinear_shaping.hpp:161
double sample_rate() const noexcept
Definition nonlinear_shaping.hpp:164
int oversample_factor() const noexcept
Definition nonlinear_shaping.hpp:155
void set_fold(double fold01) noexcept
Definition nonlinear_shaping.hpp:175
int latency_samples() const noexcept
Definition nonlinear_shaping.hpp:158
void set_alias_policy(NonlinearAliasPolicy policy)
Definition nonlinear_shaping.hpp:149
double stage_symmetry(int stage) const noexcept
Definition nonlinear_shaping.hpp:199
double shape(double input) const noexcept
Definition nonlinear_shaping.hpp:272
void set_stage_offset(int stage, double offset) noexcept
Definition nonlinear_shaping.hpp:183
void prepare(double sample_rate)
Definition nonlinear_shaping.hpp:145
static constexpr double kRawInputLimit
Definition nonlinear_shaping.hpp:143
int stages() const noexcept
Definition nonlinear_shaping.hpp:171
double small_signal_gain() const noexcept
The exact slope at the origin where differentiable; zero at a fold cusp.
Definition nonlinear_shaping.hpp:226
static constexpr int kMaxStages
Definition nonlinear_shaping.hpp:142
void set_dc_coupling(double amount01) noexcept
How much of each stage's zero-input operating point reaches the next stage.
Definition nonlinear_shaping.hpp:209
void process_block(const SampleType *input, SampleType *output, std::size_t sample_count) noexcept
Definition nonlinear_shaping.hpp:264
double fold() const noexcept
Definition nonlinear_shaping.hpp:179
SampleType process(SampleType input) noexcept
Definition nonlinear_shaping.hpp:249
NonlinearAliasPolicy alias_policy() const noexcept
Definition nonlinear_shaping.hpp:152
void set_stages(int stages) noexcept
Definition nonlinear_shaping.hpp:168
void set_stage_dc_coupling(int stage, double amount01) noexcept
Definition nonlinear_shaping.hpp:214
An internally carried ring modulator with ideal and diode-ring models.
Definition nonlinear_shaping.hpp:450
void set_phase(double cycles) noexcept
Definition nonlinear_shaping.hpp:578
void set_nonlinear_drive(double drive) noexcept
Definition nonlinear_shaping.hpp:520
RingCarrierMode carrier_mode() const noexcept
Definition nonlinear_shaping.hpp:562
NonlinearRingModulatorT() noexcept
Definition nonlinear_shaping.hpp:453
void set_carrier_waveform(RingCarrierWaveform waveform) noexcept
Definition nonlinear_shaping.hpp:528
double phase() const noexcept
Definition nonlinear_shaping.hpp:583
RingModulationModel model() const noexcept
Definition nonlinear_shaping.hpp:496
double shape(double input, double carrier) const noexcept
Definition nonlinear_shaping.hpp:623
void set_model(RingModulationModel model) noexcept
Definition nonlinear_shaping.hpp:488
void set_output_polarity(RingOutputPolarity polarity) noexcept
Definition nonlinear_shaping.hpp:566
double sample_rate() const noexcept
Definition nonlinear_shaping.hpp:484
static constexpr double dc_output() noexcept
Definition nonlinear_shaping.hpp:588
SampleType process(SampleType input) noexcept
Definition nonlinear_shaping.hpp:597
RingCarrierWaveform carrier_waveform() const noexcept
Definition nonlinear_shaping.hpp:550
RingOutputPolarity output_polarity() const noexcept
Definition nonlinear_shaping.hpp:574
void set_carrier_hz(double hz) noexcept
Definition nonlinear_shaping.hpp:500
void reset() noexcept
Definition nonlinear_shaping.hpp:592
void process_block(const SampleType *input, SampleType *output, std::size_t sample_count) noexcept
Definition nonlinear_shaping.hpp:615
double index() const noexcept
Definition nonlinear_shaping.hpp:516
double carrier_hz() const noexcept
Definition nonlinear_shaping.hpp:508
void set_index(double index01) noexcept
Definition nonlinear_shaping.hpp:512
void set_alias_policy(NonlinearAliasPolicy policy)
Definition nonlinear_shaping.hpp:466
void set_carrier_mode(RingCarrierMode mode) noexcept
Definition nonlinear_shaping.hpp:554
int tail_samples() const noexcept
Definition nonlinear_shaping.hpp:481
int latency_samples() const noexcept
Definition nonlinear_shaping.hpp:478
NonlinearAliasPolicy alias_policy() const noexcept
Definition nonlinear_shaping.hpp:472
int oversample_factor() const noexcept
Definition nonlinear_shaping.hpp:475
void prepare(double sample_rate)
Definition nonlinear_shaping.hpp:457
double nonlinear_drive() const noexcept
Definition nonlinear_shaping.hpp:524
Definition oversampling.hpp:78
void set_factor(Factor f)
RT contract: set_factor(), set_sample_rate(), set_kind(), and reset() are setup/control operations th...
Definition oversampling.hpp:111
Factor
Definition oversampling.hpp:80
Definition nonlinear_shaping.hpp:42
SampleType process(SampleType input, Callback &&callback)
Definition nonlinear_shaping.hpp:100
int oversample_factor() const noexcept
Definition nonlinear_shaping.hpp:72
void reset() noexcept
Definition nonlinear_shaping.hpp:96
int tail_samples() const noexcept
Definition nonlinear_shaping.hpp:88
int latency_samples() const noexcept
Definition nonlinear_shaping.hpp:84
NonlinearAliasPolicy alias_policy() const noexcept
Definition nonlinear_shaping.hpp:68
double sample_rate() const noexcept
Definition nonlinear_shaping.hpp:92
bool prepare(double sample_rate)
Definition nonlinear_shaping.hpp:47
OversamplerT< SampleType > Oversampler
Definition nonlinear_shaping.hpp:45
bool set_alias_policy(NonlinearAliasPolicy policy)
Definition nonlinear_shaping.hpp:60
void reset(double phase=0.0) noexcept
Set the phase and drop any pending correction.
Definition va.hpp:192
double triangle_fold_slope(double input) noexcept
Definition nonlinear_shaping.hpp:123
constexpr double kNonlinearMaximumSampleRate
Definition nonlinear_shaping.hpp:30
bool valid_alias_policy(NonlinearAliasPolicy policy) noexcept
Definition nonlinear_shaping.hpp:32
constexpr double kNonlinearMinimumSampleRate
Definition nonlinear_shaping.hpp:29
double triangle_fold(double input) noexcept
Definition nonlinear_shaping.hpp:118
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
@ triangle
Slope breaks at the wrap and the apex; value is continuous.
Definition va.hpp:117
Definition additive_bank.hpp:218
RingModulationModel
Definition nonlinear_shaping.hpp:424
@ ideal_multiplier
Definition nonlinear_shaping.hpp:425
@ diode_ring
Definition nonlinear_shaping.hpp:426
RingCarrierWaveform
Definition nonlinear_shaping.hpp:429
@ square
Definition nonlinear_shaping.hpp:432
@ sine
Definition nonlinear_shaping.hpp:430
@ triangle
Definition nonlinear_shaping.hpp:431
NonlinearRingModulatorT< double > NonlinearRingModulator64
Definition nonlinear_shaping.hpp:695
MultistageWavefolderT< double > MultistageWavefolder64
Definition nonlinear_shaping.hpp:691
NonlinearRingModulatorT< float > NonlinearRingModulator
Definition nonlinear_shaping.hpp:694
NonlinearAliasPolicy
Antialiasing choices shared by the nonlinear-shaping processors.
Definition nonlinear_shaping.hpp:21
@ off
Definition nonlinear_shaping.hpp:24
@ oversample_2x
Definition nonlinear_shaping.hpp:23
@ oversample_4x
Definition nonlinear_shaping.hpp:22
RingOutputPolarity
Definition nonlinear_shaping.hpp:440
@ inverted
Definition nonlinear_shaping.hpp:442
@ normal
Definition nonlinear_shaping.hpp:441
@ i
Definition formant_filter_bank.hpp:20
ChebyshevHarmonicShaperT< double > ChebyshevHarmonicShaper64
Definition nonlinear_shaping.hpp:693
OversamplerT< float > Oversampler
Definition oversampling.hpp:457
@ square
Definition lfo_sampling.hpp:58
@ sine
Definition lfo_sampling.hpp:54
@ triangle
Definition lfo_sampling.hpp:55
ChebyshevHarmonicShaperT< float > ChebyshevHarmonicShaper
Definition nonlinear_shaping.hpp:692
MultistageWavefolderT< float > MultistageWavefolder
Definition nonlinear_shaping.hpp:690
RingCarrierMode
Definition nonlinear_shaping.hpp:435
@ bipolar
Definition nonlinear_shaping.hpp:436
@ unipolar
Definition nonlinear_shaping.hpp:437
Virtual-analog oscillator: the classic static shapes, bandlimited by composing PhaseAccumulator (the ...