27 static_assert(std::is_floating_point_v<SampleType>);
34 [[nodiscard]]
bool prepare(
double base_sample_rate,
double max_one_way_seconds,
36 if (!std::isfinite(base_sample_rate) || !(base_sample_rate > 0.0) ||
37 !std::isfinite(max_one_way_seconds) ||
42 if (!std::isfinite(internal_rate) ||
43 internal_rate >
static_cast<double>(std::numeric_limits<SampleType>::max()) ||
44 max_one_way_seconds * internal_rate <
48 Oversampler next_oversampler;
51 : Oversampler::Factor::x4);
52 next_oversampler.
set_sample_rate(
static_cast<SampleType
>(base_sample_rate));
53 next_oversampler.
set_quality(Oversampler::Quality::standard);
54 next_oversampler.
set_kind(Oversampler::Kind::linear_phase_fir);
58 if (!next_line.
prepare(internal_rate, max_one_way_seconds))
60 const auto effective_seconds = clamped_seconds(target_one_way_seconds_, internal_rate,
63 static_cast<SampleType
>(effective_seconds * internal_rate));
65 oversampler_ = std::move(next_oversampler);
66 line_ = std::move(next_line);
67 base_sample_rate_ = base_sample_rate;
68 internal_sample_rate_ = internal_rate;
69 max_one_way_seconds_ = max_one_way_seconds;
70 target_one_way_seconds_ = effective_seconds;
73 configure_internal_bell_pole();
79 if (!std::isfinite(seconds))
82 target_one_way_seconds_ = std::max(0.0, seconds);
85 target_one_way_seconds_ =
86 clamped_seconds(seconds, internal_sample_rate_, max_one_way_seconds_);
87 line_.set_length_samples(
88 static_cast<SampleType
>(target_one_way_seconds_ * internal_sample_rate_));
92 return prepared_ ?
static_cast<double>(line_.length_samples()) / internal_sample_rate_
93 : target_one_way_seconds_;
98 ?
static_cast<double>(line_.current_length_samples()) / internal_sample_rate_
103 return prepared_ ? line_.round_trip_seconds() : 0.0;
107 reed_.set_closing_pressure(value);
109 void set_flow_gain(SampleType value)
noexcept { reed_.set_flow_gain(value); }
112 bell_.set_reflection_gain(value);
117 if (!std::isfinite(
static_cast<double>(value)))
119 base_rate_bell_loss_pole_ =
121 configure_internal_bell_pole();
125 return base_rate_bell_loss_pole_;
128 return bell_.loss_pole();
133 [[nodiscard]] SampleType
process(SampleType mouth_pressure)
noexcept {
136 if (!std::isfinite(
static_cast<double>(mouth_pressure)))
137 mouth_pressure = last_finite_mouth_pressure_;
139 mouth_pressure = std::clamp(mouth_pressure, SampleType{}, SampleType{1});
140 last_finite_mouth_pressure_ = mouth_pressure;
143 auto whole_loop = [
this](SampleType oversampled_mouth)
noexcept {
144 SampleType reed_arrival{};
145 SampleType bell_arrival{};
146 line_.read_outputs(reed_arrival, bell_arrival);
147 const auto reed_reflection = reed_.process(oversampled_mouth, reed_arrival);
148 const auto bell_reflection = bell_.process(bell_arrival);
149 line_.push_inputs(reed_reflection, bell_reflection);
153 const auto output = oversampling_factor_ == 1
154 ? whole_loop(mouth_pressure)
155 : oversampler_.process(mouth_pressure, whole_loop);
156 if (!std::isfinite(
static_cast<double>(output))) {
159 oversampler_.reset();
169 return oversampling_factor_ == 1 ? 0 : oversampler_.latency_samples();
172 [[nodiscard]]
bool prepared() const noexcept {
return prepared_; }
175 oversampler_.reset();
179 last_finite_mouth_pressure_ = SampleType{};
183 void configure_internal_bell_pole() noexcept {
184 const auto factor = std::max(1, oversampling_factor_);
186 base_rate_bell_loss_pole_ == SampleType{}
188 :
static_cast<SampleType
>(std::pow(
189 static_cast<double>(base_rate_bell_loss_pole_), 1.0 / factor));
190 bell_.set_loss_pole(mapped);
193 [[nodiscard]]
static double clamped_seconds(
double seconds,
double internal_rate,
196 return std::clamp(seconds, minimum,
maximum);
199 Oversampler oversampler_{};
200 WaveguideLineT<SampleType> line_{};
201 ReedExciterT<SampleType> reed_{};
202 WaveguideReflectionFilterT<SampleType> bell_{};
203 double base_sample_rate_ = 0.0;
204 double internal_sample_rate_ = 0.0;
205 double max_one_way_seconds_ = 0.0;
207 int oversampling_factor_ = 1;
208 SampleType base_rate_bell_loss_pole_ =
static_cast<SampleType
>(
210 SampleType last_finite_mouth_pressure_{};
211 bool prepared_ =
false;
Definition oversampling.hpp:78
void set_kind(Kind kind)
Definition oversampling.hpp:121
void set_sample_rate(SampleType sr)
Definition oversampling.hpp:116
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
void set_quality(Quality quality)
Definition oversampling.hpp:126
Owns and oversamples one complete reed -> bore -> bell feedback loop.
Definition reed_waveguide_loop.hpp:26
void set_bell_loss_pole(SampleType value) noexcept
Sets the bell pole in the base-rate domain.
Definition reed_waveguide_loop.hpp:116
void set_bore_impedance(SampleType value) noexcept
Definition reed_waveguide_loop.hpp:110
double current_one_way_seconds() const noexcept
Definition reed_waveguide_loop.hpp:96
SampleType process(SampleType mouth_pressure) noexcept
Returns the pressure wave arriving at the bell before reflection.
Definition reed_waveguide_loop.hpp:133
int oversampling_factor() const noexcept
Definition reed_waveguide_loop.hpp:167
void set_flow_gain(SampleType value) noexcept
Definition reed_waveguide_loop.hpp:109
static constexpr float maximum_base_rate_bell_loss_pole
Definition reed_waveguide_loop.hpp:32
bool prepare(double base_sample_rate, double max_one_way_seconds, int oversampling_factor=2)
Definition reed_waveguide_loop.hpp:34
double round_trip_seconds() const noexcept
Definition reed_waveguide_loop.hpp:102
SampleType internal_bell_loss_pole() const noexcept
Definition reed_waveguide_loop.hpp:127
void set_closing_pressure(SampleType value) noexcept
Definition reed_waveguide_loop.hpp:106
void reset() noexcept
Definition reed_waveguide_loop.hpp:174
void set_bell_reflection_gain(SampleType value) noexcept
Definition reed_waveguide_loop.hpp:111
double target_one_way_seconds() const noexcept
Definition reed_waveguide_loop.hpp:91
static constexpr double default_one_way_seconds
Definition reed_waveguide_loop.hpp:31
void set_one_way_seconds(double seconds) noexcept
Definition reed_waveguide_loop.hpp:78
int latency_samples() const noexcept
Definition reed_waveguide_loop.hpp:168
int tail_samples() const noexcept
Definition reed_waveguide_loop.hpp:171
bool prepared() const noexcept
Definition reed_waveguide_loop.hpp:172
SampleType bell_loss_pole() const noexcept
Definition reed_waveguide_loop.hpp:124
A passive bidirectional waveguide segment.
Definition waveguide_line.hpp:33
void set_length_samples(SampleType length) noexcept
Definition waveguide_line.hpp:74
static constexpr double minimum_length_samples
Definition waveguide_line.hpp:37
bool prepare(double sample_rate, double max_length_seconds=default_max_length_seconds)
Definition waveguide_line.hpp:43
static constexpr double default_loss_pole
Definition waveguide_reflection_filter.hpp:32
Definition additive_bank.hpp:218
ReedWaveguideLoopT< double > ReedWaveguideLoop64
Definition reed_waveguide_loop.hpp:215
ReedWaveguideLoopT< float > ReedWaveguideLoop
Definition reed_waveguide_loop.hpp:214
@ maximum
Definition spectrum_trace.hpp:34
float minimum(const float *data, std::size_t count) noexcept
Prepared bidirectional traveling-wave delay rails.
Bounded memoryless single-reed valve for waveguide compositions.
Passive one-pole waveguide termination.