Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
nonlinear_shaping.hpp
Go to the documentation of this file.
1#pragma once
2
5
8
9#include <algorithm>
10#include <array>
11#include <cmath>
12#include <cstddef>
13#include <cstdint>
14#include <limits>
15#include <numbers>
16#include <type_traits>
17
18namespace pulp::signal {
19
26
27namespace detail {
28
29inline constexpr double kNonlinearMinimumSampleRate = 1000.0;
30inline constexpr double kNonlinearMaximumSampleRate = 768000.0;
31
32inline bool valid_alias_policy(NonlinearAliasPolicy policy) noexcept {
33 switch (policy) {
37 return true;
38 }
39 return false;
40}
41
42template <typename SampleType> class NonlinearOversamplingT {
43 public:
44 static_assert(std::is_floating_point_v<SampleType>);
46
47 bool prepare(double sample_rate) {
48 if (!std::isfinite(sample_rate) || sample_rate < kNonlinearMinimumSampleRate ||
50 sample_rate > static_cast<double>(std::numeric_limits<SampleType>::max()))
51 return false;
52 sample_rate_ = sample_rate;
53 oversampler_.set_kind(Oversampler::Kind::linear_phase_fir);
54 oversampler_.set_quality(Oversampler::Quality::standard);
55 configure_factor();
56 oversampler_.set_sample_rate(static_cast<SampleType>(sample_rate_));
57 return true;
58 }
59
61 if (!valid_alias_policy(policy) || policy_ == policy)
62 return false;
63 policy_ = policy;
64 configure_factor();
65 return true;
66 }
67
69 return policy_;
70 }
71
72 int oversample_factor() const noexcept {
73 switch (policy_) {
75 return 4;
77 return 2;
79 return 1;
80 }
81 return 1;
82 }
83
84 int latency_samples() const noexcept {
85 return policy_ == NonlinearAliasPolicy::off ? 0 : oversampler_.latency_samples();
86 }
87
88 int tail_samples() const noexcept {
89 return 2 * latency_samples();
90 }
91
92 double sample_rate() const noexcept {
93 return sample_rate_;
94 }
95
96 void reset() noexcept {
97 oversampler_.reset();
98 }
99
100 template <typename Callback> SampleType process(SampleType input, Callback&& callback) {
101 if (policy_ == NonlinearAliasPolicy::off)
102 return callback(input);
103 return oversampler_.process(input, callback);
104 }
105
106 private:
107 void configure_factor() {
108 using Factor = typename Oversampler::Factor;
109 oversampler_.set_factor(policy_ == NonlinearAliasPolicy::oversample_4x ? Factor::x4
110 : Factor::x2);
111 }
112
113 double sample_rate_ = 48000.0;
115 Oversampler oversampler_{};
116};
117
118inline double triangle_fold(double input) noexcept {
119 constexpr double half_pi = std::numbers::pi / 2.0;
120 return (2.0 / std::numbers::pi) * std::asin(std::sin(half_pi * input));
121}
122
123inline double triangle_fold_slope(double input) noexcept {
124 const double cosine = std::cos((std::numbers::pi / 2.0) * input);
125 if (std::abs(cosine) < 1.0e-12)
126 return 0.0;
127 return cosine > 0.0 ? 1.0 : -1.0;
128}
129
130} // namespace detail
131
139template <typename SampleType = float> class MultistageWavefolderT {
140 public:
141 static_assert(std::is_floating_point_v<SampleType>);
142 static constexpr int kMaxStages = 8;
143 static constexpr double kRawInputLimit = 64.0;
144
145 void prepare(double sample_rate) {
146 aliasing_.prepare(sample_rate);
147 }
148
150 aliasing_.set_alias_policy(policy);
151 }
153 return aliasing_.alias_policy();
154 }
155 int oversample_factor() const noexcept {
156 return aliasing_.oversample_factor();
157 }
158 int latency_samples() const noexcept {
159 return aliasing_.latency_samples();
160 }
161 int tail_samples() const noexcept {
162 return dc_output() == 0.0 ? aliasing_.tail_samples() : -1;
163 }
164 double sample_rate() const noexcept {
165 return aliasing_.sample_rate();
166 }
167
168 void set_stages(int stages) noexcept {
169 stages_ = std::clamp(stages, 1, kMaxStages);
170 }
171 int stages() const noexcept {
172 return stages_;
173 }
174
175 void set_fold(double fold01) noexcept {
176 if (std::isfinite(fold01))
177 fold_ = std::clamp(fold01, 0.0, 1.0);
178 }
179 double fold() const noexcept {
180 return fold_;
181 }
182
183 void set_stage_offset(int stage, double offset) noexcept {
184 if (stage < 0 || stage >= kMaxStages || !std::isfinite(offset))
185 return;
186 offsets_[static_cast<std::size_t>(stage)] = std::clamp(offset, -1.0, 1.0);
187 }
188 double stage_offset(int stage) const noexcept {
189 if (stage < 0 || stage >= kMaxStages)
190 return 0.0;
191 return offsets_[static_cast<std::size_t>(stage)];
192 }
193
194 void set_stage_symmetry(int stage, double symmetry) noexcept {
195 if (stage < 0 || stage >= kMaxStages || !std::isfinite(symmetry))
196 return;
197 symmetries_[static_cast<std::size_t>(stage)] = std::clamp(symmetry, -1.0, 1.0);
198 }
199 double stage_symmetry(int stage) const noexcept {
200 if (stage < 0 || stage >= kMaxStages)
201 return 0.0;
202 return symmetries_[static_cast<std::size_t>(stage)];
203 }
204
209 void set_dc_coupling(double amount01) noexcept {
210 if (!std::isfinite(amount01))
211 return;
212 dc_couplings_.fill(std::clamp(amount01, 0.0, 1.0));
213 }
214 void set_stage_dc_coupling(int stage, double amount01) noexcept {
215 if (stage < 0 || stage >= kMaxStages || !std::isfinite(amount01))
216 return;
217 dc_couplings_[static_cast<std::size_t>(stage)] = std::clamp(amount01, 0.0, 1.0);
218 }
219 double stage_dc_coupling(int stage) const noexcept {
220 if (stage < 0 || stage >= kMaxStages)
221 return 1.0;
222 return dc_couplings_[static_cast<std::size_t>(stage)];
223 }
224
226 double small_signal_gain() const noexcept {
227 double value = 0.0;
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;
233 derivative *= detail::triangle_fold_slope(argument) *
234 (stage_gain(stage) + 2.0 * symmetries_[index] * value);
235 value = detail::triangle_fold(argument) -
236 (1.0 - dc_couplings_[index]) * detail::triangle_fold(offsets_[index]);
237 }
238 return derivative;
239 }
240
241 double dc_output() const noexcept {
242 return shape(0.0);
243 }
244
245 void reset() noexcept {
246 aliasing_.reset();
247 }
248
249 SampleType process(SampleType input) noexcept {
250 if (!std::isfinite(static_cast<double>(input))) {
251 reset();
252 return SampleType{0};
253 }
254 const SampleType output = aliasing_.process(input, [this](SampleType sample) {
255 return static_cast<SampleType>(shape(static_cast<double>(sample)));
256 });
257 if (!std::isfinite(static_cast<double>(output))) {
258 reset();
259 return SampleType{0};
260 }
261 return output;
262 }
263
264 void process_block(const SampleType* input, SampleType* output,
265 std::size_t sample_count) noexcept {
266 if (input == nullptr || output == nullptr)
267 return;
268 for (std::size_t i = 0; i < sample_count; ++i)
269 output[i] = process(input[i]);
270 }
271
272 double shape(double input) const noexcept {
273 double output = std::clamp(input, -kRawInputLimit, kRawInputLimit);
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;
278 output = detail::triangle_fold(argument) -
279 (1.0 - dc_couplings_[index]) * detail::triangle_fold(offsets_[index]);
280 }
281 return output;
282 }
283
284 private:
285 double stage_gain(int stage) const noexcept {
286 return 1.0 + fold_ * (1.0 + 0.5 * static_cast<double>(stage));
287 }
288
289 int stages_ = 3;
290 double fold_ = 0.0;
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_{};
295};
296
304template <typename SampleType = float> class ChebyshevHarmonicShaperT {
305 public:
306 static_assert(std::is_floating_point_v<SampleType>);
307 static constexpr int kMaxHarmonic = 16;
308
310 coefficients_[1] = 1.0;
311 }
312
313 void prepare(double sample_rate) {
314 aliasing_.prepare(sample_rate);
315 }
317 aliasing_.set_alias_policy(policy);
318 }
320 return aliasing_.alias_policy();
321 }
322 int oversample_factor() const noexcept {
323 return aliasing_.oversample_factor();
324 }
325 int latency_samples() const noexcept {
326 return aliasing_.latency_samples();
327 }
328 int tail_samples() const noexcept {
329 return aliasing_.tail_samples();
330 }
331 double sample_rate() const noexcept {
332 return aliasing_.sample_rate();
333 }
334
335 void clear_harmonics() noexcept {
336 coefficients_.fill(0.0);
337 }
338
339 void set_harmonic(int order, double amplitude) noexcept {
340 if (order < 1 || order > kMaxHarmonic || !std::isfinite(amplitude))
341 return;
342 coefficients_[static_cast<std::size_t>(order)] = std::clamp(amplitude, -1.0, 1.0);
343 }
344
345 double harmonic(int order) const noexcept {
346 if (order < 1 || order > kMaxHarmonic)
347 return 0.0;
348 return coefficients_[static_cast<std::size_t>(order)];
349 }
350
351 static constexpr double dc_output() noexcept {
352 return 0.0;
353 }
354
356 double small_signal_gain() const noexcept {
357 double gain = 0.0;
358 for (int order = 1; order <= kMaxHarmonic; ++order) {
359 const int residue = order & 3;
360 const double derivative = residue == 1 ? static_cast<double>(order)
361 : residue == 3 ? -static_cast<double>(order)
362 : 0.0;
363 gain += coefficients_[static_cast<std::size_t>(order)] * derivative;
364 }
365 return gain;
366 }
367
369 double worst_case_output() const noexcept {
370 double bound = 0.0;
371 for (int order = 1; order <= kMaxHarmonic; ++order)
372 bound += std::abs(coefficients_[static_cast<std::size_t>(order)]) *
373 ((order & 1) == 0 ? 2.0 : 1.0);
374 return bound;
375 }
376
377 void reset() noexcept {
378 aliasing_.reset();
379 }
380
381 SampleType process(SampleType input) noexcept {
382 if (!std::isfinite(static_cast<double>(input))) {
383 reset();
384 return SampleType{0};
385 }
386 const SampleType output = aliasing_.process(input, [this](SampleType sample) {
387 return static_cast<SampleType>(shape(static_cast<double>(sample)));
388 });
389 if (!std::isfinite(static_cast<double>(output))) {
390 reset();
391 return SampleType{0};
392 }
393 return output;
394 }
395
396 void process_block(const SampleType* input, SampleType* output,
397 std::size_t sample_count) noexcept {
398 if (input == nullptr || output == nullptr)
399 return;
400 for (std::size_t i = 0; i < sample_count; ++i)
401 output[i] = process(input[i]);
402 }
403
404 double shape(double input) const noexcept {
405 const double x = std::clamp(input, -1.0, 1.0);
406 double previous = 1.0;
407 double current = x;
408 double output = coefficients_[1] * current;
409 for (int order = 2; order <= kMaxHarmonic; ++order) {
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);
413 previous = current;
414 current = next;
415 }
416 return output;
417 }
418
419 private:
420 std::array<double, kMaxHarmonic + 1> coefficients_{};
421 detail::NonlinearOversamplingT<SampleType> aliasing_{};
422};
423
424enum class RingModulationModel : std::uint8_t {
427};
428
429enum class RingCarrierWaveform : std::uint8_t {
433};
434
435enum class RingCarrierMode : std::uint8_t {
438};
439
440enum class RingOutputPolarity : std::uint8_t {
443};
444
450template <typename SampleType = float> class NonlinearRingModulatorT {
451 public:
452 static_assert(std::is_floating_point_v<SampleType>);
454 carrier_.set_shape(osc::VaShape::sine);
455 }
456
457 void prepare(double sample_rate) {
458 if (!aliasing_.prepare(sample_rate))
459 return;
460 sample_rate_ = aliasing_.sample_rate();
461 carrier_hz_ = std::clamp(carrier_hz_, 0.0, 0.49 * sample_rate_);
462 update_phase_increment();
463 reset_carrier();
464 }
465
467 if (!aliasing_.set_alias_policy(policy))
468 return;
469 update_phase_increment();
470 reset_carrier();
471 }
473 return aliasing_.alias_policy();
474 }
475 int oversample_factor() const noexcept {
476 return aliasing_.oversample_factor();
477 }
478 int latency_samples() const noexcept {
479 return aliasing_.latency_samples();
480 }
481 int tail_samples() const noexcept {
482 return aliasing_.tail_samples();
483 }
484 double sample_rate() const noexcept {
485 return sample_rate_;
486 }
487
489 switch (model) {
492 model_ = model;
493 return;
494 }
495 }
496 RingModulationModel model() const noexcept {
497 return model_;
498 }
499
500 void set_carrier_hz(double hz) noexcept {
501 if (!std::isfinite(hz))
502 return;
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);
507 }
508 double carrier_hz() const noexcept {
509 return carrier_hz_;
510 }
511
512 void set_index(double index01) noexcept {
513 if (std::isfinite(index01))
514 index_ = std::clamp(index01, 0.0, 1.0);
515 }
516 double index() const noexcept {
517 return index_;
518 }
519
520 void set_nonlinear_drive(double drive) noexcept {
521 if (std::isfinite(drive))
522 nonlinear_drive_ = std::clamp(drive, 0.25, 16.0);
523 }
524 double nonlinear_drive() const noexcept {
525 return nonlinear_drive_;
526 }
527
529 if (waveform_ == waveform)
530 return;
532 switch (waveform) {
535 break;
538 break;
541 break;
542 default:
543 return;
544 }
545 const double current_phase = phase();
546 carrier_.set_shape(shape);
547 reset_carrier(current_phase);
548 waveform_ = waveform;
549 }
551 return waveform_;
552 }
553
554 void set_carrier_mode(RingCarrierMode mode) noexcept {
555 switch (mode) {
558 carrier_mode_ = mode;
559 return;
560 }
561 }
562 RingCarrierMode carrier_mode() const noexcept {
563 return carrier_mode_;
564 }
565
566 void set_output_polarity(RingOutputPolarity polarity) noexcept {
567 switch (polarity) {
570 output_polarity_ = polarity;
571 return;
572 }
573 }
575 return output_polarity_;
576 }
577
578 void set_phase(double cycles) noexcept {
579 if (!std::isfinite(cycles))
580 return;
581 reset_carrier(cycles);
582 }
583 double phase() const noexcept {
584 const double value = carrier_.phase() + carrier_delay_cycles();
585 return value - std::floor(value);
586 }
587
588 static constexpr double dc_output() noexcept {
589 return 0.0;
590 }
591
592 void reset() noexcept {
593 aliasing_.reset();
594 reset_carrier();
595 }
596
597 SampleType process(SampleType input) noexcept {
598 if (!std::isfinite(static_cast<double>(input))) {
599 reset();
600 return SampleType{0};
601 }
602 const SampleType output = aliasing_.process(input, [this](SampleType sample) {
603 const double waveform = carrier_.next(phase_increment_);
604 const double mapped_carrier =
605 carrier_mode_ == RingCarrierMode::bipolar ? waveform : 0.5 * (waveform + 1.0);
606 return static_cast<SampleType>(shape(static_cast<double>(sample), mapped_carrier));
607 });
608 if (!std::isfinite(static_cast<double>(output))) {
609 reset();
610 return SampleType{0};
611 }
612 return output;
613 }
614
615 void process_block(const SampleType* input, SampleType* output,
616 std::size_t sample_count) noexcept {
617 if (input == nullptr || output == nullptr)
618 return;
619 for (std::size_t i = 0; i < sample_count; ++i)
620 output[i] = process(input[i]);
621 }
622
623 double shape(double input, double carrier) const noexcept {
624 carrier = std::clamp(carrier, -1.0, 1.0);
625 double modulated = 0.0;
626 switch (model_) {
628 modulated = input * carrier;
629 break;
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))) /
638 drive;
639 break;
640 }
641 }
642 const double mixed = std::lerp(input, modulated, index_);
643 return output_polarity_ == RingOutputPolarity::normal ? mixed : -mixed;
644 }
645
646 private:
647 double carrier_delay_cycles() const noexcept {
648 return 0.5 * static_cast<double>(aliasing_.latency_samples()) * carrier_hz_ / sample_rate_;
649 }
650
651 void reset_carrier(double logical_phase = 0.0) noexcept {
652 carrier_.reset(logical_phase - carrier_delay_cycles());
653 }
654
655 void update_phase_increment() noexcept {
656 phase_increment_ =
657 carrier_hz_ / (sample_rate_ * static_cast<double>(aliasing_.oversample_factor()));
658 }
659
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);
663 if (carrier > 0.0)
664 return 2.0 * limited;
665 if (carrier < 0.0)
666 return -2.0 * limited;
667 return 0.0;
668 }
669
670 static double log_cosh_correction(double drive, double magnitude) noexcept {
671 constexpr double kNegligibleCorrectionArgument = 40.0;
672 if (magnitude >= kNegligibleCorrectionArgument / drive)
673 return 0.0;
674 return std::log1p(std::exp(-2.0 * drive * magnitude));
675 }
676
677 double sample_rate_ = 48000.0;
678 double carrier_hz_ = 440.0;
679 double phase_increment_ = 440.0 / (48000.0 * 4.0);
680 double index_ = 1.0;
681 double nonlinear_drive_ = 2.0;
686 osc::VaOscillator carrier_{};
687 detail::NonlinearOversamplingT<SampleType> aliasing_{};
688};
689
696
697} // namespace pulp::signal
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 ...