Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
phase_distortion.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <cmath>
5
6namespace pulp::signal {
7
16
38template <typename SampleType = float>
40public:
41 void set_sample_rate(double sr) { sample_rate_ = sr > 0.0 ? sr : sample_rate_; }
42 void set_frequency(double hz) {
43 frequency_ = std::clamp(hz, 0.0, 0.49 * sample_rate_);
44 }
45 void set_shape(PhaseDistortionShape shape) { shape_ = shape; }
46
48 void set_amount(double amount) { amount_ = std::clamp(amount, 0.0, 1.0); }
49
51 void set_resonant_depth(double multiples) {
52 resonant_depth_ = std::clamp(multiples, 1.0, 32.0);
53 }
54
55 void reset() { phase_ = 0.0; }
56
57 double phase() const { return phase_; }
58
59 SampleType process() {
60 phase_ += frequency_ / sample_rate_;
61 if (phase_ >= 1.0) phase_ -= std::floor(phase_);
62 return static_cast<SampleType>(evaluate(phase_));
63 }
64
65private:
66 static constexpr double kPi = 3.14159265358979323846;
67
68 double evaluate(double p) const {
69 switch (shape_) {
71 return std::cos(2.0 * kPi * warp_saw(p));
73 return std::cos(2.0 * kPi * warp_pulse(p));
75 return resonant(p, 1.0 - p);
77 return resonant(p, 1.0 - std::fabs(2.0 * p - 1.0));
79 return resonant(p, std::clamp(2.0 * (1.0 - p), 0.0, 1.0));
80 }
81 return std::cos(2.0 * kPi * p);
82 }
83
84 // Two straight segments meeting at a bend point. At amount 0 the bend sits
85 // at the half-cycle and the warp is the identity, so the output is a plain
86 // cosine; as the bend slides toward zero the second segment stretches and
87 // the waveform develops a saw's asymmetry.
88 double warp_saw(double p) const {
89 const double bend = 0.5 - 0.49 * amount_;
90 return p < bend ? p * (0.5 / bend) : 0.5 + (p - bend) * (0.5 / (1.0 - bend));
91 }
92
93 // A ramp that reaches the far side of the cosine early and then holds
94 // there, which narrows the excursion into a pulse.
95 double warp_pulse(double p) const {
96 const double width = 1.0 - 0.98 * amount_;
97 return p < width ? p * (1.0 / width) : 1.0;
98 }
99
100 // A carrier at a swept multiple of the phase, windowed once per cycle. The
101 // window is what turns a high harmonic into a formant instead of a whistle,
102 // and it is why the sweep reads as a filter opening.
103 double resonant(double p, double window) const {
104 const double multiple = 1.0 + amount_ * (resonant_depth_ - 1.0);
105 return std::cos(2.0 * kPi * p * multiple) * std::clamp(window, 0.0, 1.0);
106 }
107
108 double sample_rate_ = 44100.0;
109 double frequency_ = 220.0;
110 double amount_ = 0.0;
111 double resonant_depth_ = 12.0;
113 double phase_ = 0.0;
114};
115
118
119} // namespace pulp::signal
Phase distortion: a cosine read at a warped phase.
Definition phase_distortion.hpp:39
SampleType process()
Definition phase_distortion.hpp:59
void set_shape(PhaseDistortionShape shape)
Definition phase_distortion.hpp:45
void set_sample_rate(double sr)
Definition phase_distortion.hpp:41
void set_amount(double amount)
How far the phase is warped, 0 (an undistorted cosine) to 1.
Definition phase_distortion.hpp:48
double phase() const
Definition phase_distortion.hpp:57
void set_frequency(double hz)
Definition phase_distortion.hpp:42
void reset()
Definition phase_distortion.hpp:55
void set_resonant_depth(double multiples)
Highest carrier multiple the resonant shapes reach at full amount.
Definition phase_distortion.hpp:51
@ width
Definition config.hpp:225
Definition additive_bank.hpp:218
PhaseDistortionOscT< double > PhaseDistortionOsc64
Definition phase_distortion.hpp:117
PhaseDistortionOscT< float > PhaseDistortionOsc
Definition phase_distortion.hpp:116
PhaseDistortionShape
Which phase warp a PhaseDistortionOscT applies.
Definition phase_distortion.hpp:9
@ pulse
a ramp then a hold: sine becomes pulse-like
Definition phase_distortion.hpp:11
@ resonant_triangle
the same carrier windowed by a triangle
Definition phase_distortion.hpp:13
@ resonant_trapezoid
the same carrier windowed by a clamped trapezoid
Definition phase_distortion.hpp:14
@ saw
the bend point slides toward zero: sine becomes saw-like
Definition phase_distortion.hpp:10
@ resonant_saw
a swept carrier windowed by a falling ramp
Definition phase_distortion.hpp:12
@ p
Definition input_events.hpp:40