43 constexpr explicit operator bool() const noexcept {
73 std::uint32_t transition_samples = 64) {
87 left_history_ = std::move(
left);
88 right_history_ = std::move(
right);
92 transition_samples_ = transition_samples;
93 current_left_delay_samples_ = 2.0;
94 current_right_delay_samples_ = 2.0;
95 target_left_delay_samples_ = 2.0;
96 target_right_delay_samples_ = 2.0;
97 transition_remaining_ = 0;
108 if (!std::isfinite(samples))
110 const auto minimum =
static_cast<double>(minimum_delay_samples(interpolation_));
111 if (samples < minimum)
113 if (samples >
static_cast<double>(maximum_delay_samples_))
115 adopt_target(samples, samples);
120 double right_samples)
noexcept {
123 const auto left_status = validate_delay(left_samples);
124 const auto right_status = validate_delay(right_samples);
129 adopt_target(left_samples, right_samples);
134 double beats_per_minute)
noexcept {
165 std::size_t frame_count)
noexcept {
171 if (frame_count == 0)
173 if (
left ==
nullptr ||
right ==
nullptr) {
178 for (std::size_t index = 0; index < frame_count; ++index) {
179 const auto left_read = read(left_history_, current_left_delay_samples_);
180 const auto right_read = read(right_history_, current_right_delay_samples_);
181 if (!left_read || !right_read) {
189 float wet_left = left_read.sample;
190 float wet_right = right_read.sample;
191 if (transition_remaining_ != 0) {
192 const auto next_left = read(left_history_, target_left_delay_samples_);
193 const auto next_right = read(right_history_, target_right_delay_samples_);
194 if (!next_left || !next_right) {
198 const auto elapsed = transition_samples_ - transition_remaining_ + 1U;
200 transition_samples_ == 0
202 :
static_cast<float>(elapsed) /
static_cast<float>(transition_samples_);
203 wet_left += amount * (next_left.sample - wet_left);
204 wet_right += amount * (next_right.sample - wet_right);
205 --transition_remaining_;
206 if (transition_remaining_ == 0) {
207 current_left_delay_samples_ = target_left_delay_samples_;
208 current_right_delay_samples_ = target_right_delay_samples_;
212 const float input_left =
left[index];
213 const float input_right =
right[index];
214 if (!std::isfinite(input_left) || !std::isfinite(input_right)) {
219 const float safe_left = std::isfinite(input_left) ? input_left : 0.0f;
220 const float safe_right = std::isfinite(input_right) ? input_right : 0.0f;
221 const float feedback_left =
222 feedback_ * ((1.0f - crossfeed_) * wet_left + crossfeed_ * wet_right);
223 const float feedback_right =
224 feedback_ * ((1.0f - crossfeed_) * wet_right + crossfeed_ * wet_left);
225 left[index] = wet_left;
226 right[index] = wet_right;
227 const auto left_status = left_history_.push(safe_left + feedback_left);
228 const auto right_status = right_history_.push(safe_right + feedback_right);
240 left_history_.reset();
241 right_history_.reset();
242 current_left_delay_samples_ = initialized_ ? target_left_delay_samples_ : 2.0;
243 current_right_delay_samples_ = initialized_ ? target_right_delay_samples_ : 2.0;
244 transition_remaining_ = 0;
254 return prepared_ ? sample_rate_ : 0.0;
257 return prepared_ ? maximum_delay_samples_ : 0;
260 return prepared_ ? current_left_delay_samples_ : 0.0;
263 return prepared_ ? target_left_delay_samples_ : 0.0;
266 return prepared_ ? current_right_delay_samples_ : 0.0;
269 return prepared_ ? target_right_delay_samples_ : 0.0;
272 return transition_remaining_ != 0;
281 return interpolation_;
287 return feedback_ > 0.0 ? -1
288 :
static_cast<int>(std::max(target_left_delay_samples_,
289 target_right_delay_samples_));
298 static constexpr std::size_t
303 [[nodiscard]] FractionalDelaySampleResult<float>
304 read(
const FractionalDelayHistoryT<float>& history,
double delay)
const noexcept {
306 ? history.read_lagrange5_at(
delay)
307 : history.read_lagrange3_at(
delay);
311 if (!std::isfinite(samples))
313 if (samples <
static_cast<double>(minimum_delay_samples(interpolation_)))
315 if (samples >
static_cast<double>(maximum_delay_samples_))
320 void adopt_target(
double left_samples,
double right_samples)
noexcept {
323 current_left_delay_samples_ = left_samples;
324 current_right_delay_samples_ = right_samples;
325 target_left_delay_samples_ = left_samples;
326 target_right_delay_samples_ = right_samples;
327 transition_remaining_ = 0;
330 if (left_samples == target_left_delay_samples_ &&
331 right_samples == target_right_delay_samples_)
333 target_left_delay_samples_ = left_samples;
334 target_right_delay_samples_ = right_samples;
335 if (transition_samples_ == 0) {
336 current_left_delay_samples_ = left_samples;
337 current_right_delay_samples_ = right_samples;
338 transition_remaining_ = 0;
341 transition_remaining_ = transition_samples_;
344 FractionalDelayHistoryT<float> left_history_;
345 FractionalDelayHistoryT<float> right_history_;
346 double sample_rate_ = 0.0;
347 std::size_t maximum_delay_samples_ = 0;
348 double current_left_delay_samples_ = 2.0;
349 double current_right_delay_samples_ = 2.0;
350 double target_left_delay_samples_ = 2.0;
351 double target_right_delay_samples_ = 2.0;
352 double feedback_ = 0.0;
353 double crossfeed_ = 0.0;
354 std::uint32_t transition_samples_ = 64;
355 std::uint32_t transition_remaining_ = 0;
357 bool prepared_ =
false;
358 bool initialized_ =
false;
Prepared history shared by any number of stateless Lagrange read heads.
Definition fractional_delay.hpp:161
TempoDelayWrapperError set_delay_samples(double left_samples, double right_samples) noexcept
Definition tempo_delay_wrapper.hpp:119
double target_right_delay_samples() const noexcept
Definition tempo_delay_wrapper.hpp:268
int tail_samples() const noexcept
Definition tempo_delay_wrapper.hpp:286
TempoDelayWrapperError set_delay_samples(double samples) noexcept
Definition tempo_delay_wrapper.hpp:105
double current_delay_samples() const noexcept
Definition tempo_delay_wrapper.hpp:259
TempoDelayWrapper & operator=(const TempoDelayWrapper &)=delete
static constexpr double kMaximumFeedback
Definition tempo_delay_wrapper.hpp:63
double sample_rate() const noexcept
Definition tempo_delay_wrapper.hpp:253
void reset() noexcept
Definition tempo_delay_wrapper.hpp:237
TempoDelayWrapperError set_tempo(timebase::BeatDivision division, double beats_per_minute) noexcept
Definition tempo_delay_wrapper.hpp:133
bool prepared() const noexcept
Definition tempo_delay_wrapper.hpp:247
static constexpr int latency_samples() noexcept
Definition tempo_delay_wrapper.hpp:283
bool initialized() const noexcept
Definition tempo_delay_wrapper.hpp:250
TempoDelayWrapperInterpolation interpolation() const noexcept
Definition tempo_delay_wrapper.hpp:280
TempoDelayWrapperError prepare(double sample_rate, std::size_t maximum_delay_samples, TempoDelayWrapperInterpolation interpolation=TempoDelayWrapperInterpolation::lagrange3, std::uint32_t transition_samples=64)
Definition tempo_delay_wrapper.hpp:70
std::size_t maximum_delay_samples() const noexcept
Definition tempo_delay_wrapper.hpp:256
double target_delay_samples() const noexcept
Definition tempo_delay_wrapper.hpp:262
TempoDelayWrapperError set_crossfeed(double crossfeed) noexcept
Definition tempo_delay_wrapper.hpp:157
static constexpr std::size_t kMinimumCapacitySamples
Definition tempo_delay_wrapper.hpp:64
TempoDelayWrapperError set_feedback(double feedback) noexcept
Definition tempo_delay_wrapper.hpp:150
TempoDelayWrapper()=default
TempoDelayWrapperProcessResult process(float *left, float *right, std::size_t frame_count) noexcept
Definition tempo_delay_wrapper.hpp:164
TempoDelayWrapper(const TempoDelayWrapper &)=delete
bool transition_active() const noexcept
Definition tempo_delay_wrapper.hpp:271
double current_right_delay_samples() const noexcept
Definition tempo_delay_wrapper.hpp:265
double feedback() const noexcept
Definition tempo_delay_wrapper.hpp:274
double crossfeed() const noexcept
Definition tempo_delay_wrapper.hpp:277
Prepared fractional-delay storage with Thiran-1 and Lagrange-3/5 reads.
Definition additive_bank.hpp:218
TempoDelayWrapperInterpolation
Definition tempo_delay_wrapper.hpp:17
@ lagrange3
Definition tempo_delay_wrapper.hpp:18
@ lagrange5
Definition tempo_delay_wrapper.hpp:19
@ right
Definition multi_channel_meter.hpp:67
@ left
Definition multi_channel_meter.hpp:66
SampleType lagrange5(double fraction, SampleType ym2, SampleType ym1, SampleType y0, SampleType y1, SampleType y2, SampleType y3) noexcept
Definition fractional_delay.hpp:95
@ ok
Definition fractional_delay.hpp:34
@ invalid_delay
Definition fractional_delay.hpp:38
@ invalid_argument
Definition fractional_delay.hpp:36
@ delay
Definition envelope.hpp:57
TempoDelayWrapperError
Definition tempo_delay_wrapper.hpp:23
@ none
Definition tempo_delay_wrapper.hpp:24
@ invalid_sample_rate
Definition tempo_delay_wrapper.hpp:26
@ invalid_feedback
Definition tempo_delay_wrapper.hpp:33
@ out_of_range
Definition tempo_delay_wrapper.hpp:32
@ non_finite_input
Definition tempo_delay_wrapper.hpp:35
@ invalid_crossfeed
Definition tempo_delay_wrapper.hpp:34
@ invalid_tempo
Definition tempo_delay_wrapper.hpp:30
@ unsupported_interpolation
Definition tempo_delay_wrapper.hpp:28
@ invalid_delay
Definition tempo_delay_wrapper.hpp:29
@ invalid_capacity
Definition tempo_delay_wrapper.hpp:27
@ invalid_division
Definition tempo_delay_wrapper.hpp:31
@ not_prepared
Definition tempo_delay_wrapper.hpp:25
@ non_finite_input
Definition comb_filter.hpp:36
@ not_prepared
Definition comb_filter.hpp:33
@ invalid_sample_rate
Definition auto_ducked_send.hpp:18
constexpr double kMaximumTempoDelaySampleRate
Definition tempo_delay.hpp:41
@ out_of_range
Definition tempo_delay.hpp:24
@ invalid_tempo
Definition tempo_delay.hpp:21
@ invalid_division
Definition tempo_delay.hpp:20
@ lagrange3
Definition fractional_delay.hpp:24
@ thiran1
Definition fractional_delay.hpp:23
@ none
Definition dither.hpp:17
@ invalid_capacity
Definition graphic_eq.hpp:22
TempoDelayResult tempo_delay_samples(timebase::BeatDivision division, double beats_per_minute, double sample_rate) noexcept
Convert an exact persisted musical division to a fractional delay length.
Definition tempo_delay.hpp:50
@ out_of_range
Definition formant_filter_bank.hpp:27
BeatDivision
Definition beat_division.hpp:15
Definition tempo_delay_wrapper.hpp:38
TempoDelayWrapperError error
Definition tempo_delay_wrapper.hpp:39
std::size_t fault_count
Definition tempo_delay_wrapper.hpp:41
std::size_t processed_frames
Definition tempo_delay_wrapper.hpp:40
Musical-division conversion and fixed-state delay-time transitions.