Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
fractional_delay.hpp
Go to the documentation of this file.
1#pragma once
2
5
7
8#include <algorithm>
9#include <array>
10#include <cmath>
11#include <cstddef>
12#include <limits>
13#include <new>
14#include <optional>
15#include <stdexcept>
16#include <type_traits>
17#include <utility>
18#include <vector>
19
20namespace pulp::signal {
21
27
28inline constexpr bool is_valid_fractional_delay_method(FractionalDelayMethod method) noexcept {
31}
32
41
43 double delay_samples = 1.0;
44 double feedback = 0.0;
45 bool valid = false;
46};
47
50inline Thiran1Coefficients design_thiran1(double delay_samples) noexcept {
51 if (!std::isfinite(delay_samples) || delay_samples < 1.0 || delay_samples > 2.0)
52 return {};
53 return {.delay_samples = delay_samples,
54 .feedback = (1.0 - delay_samples) / (1.0 + delay_samples),
55 .valid = true};
56}
57
58inline double thiran1_magnitude(const Thiran1Coefficients& design, double omega) noexcept {
59 if (!design.valid || !std::isfinite(omega))
60 return std::numeric_limits<double>::quiet_NaN();
61 return 1.0;
62}
63
66 double omega) noexcept {
67 if (!design.valid || !std::isfinite(omega))
68 return std::numeric_limits<double>::quiet_NaN();
69 const auto a = design.feedback;
70 const auto denominator = 1.0 + a * a + 2.0 * a * std::cos(omega);
71 if (!(denominator > 0.0) || !std::isfinite(denominator))
72 return std::numeric_limits<double>::quiet_NaN();
73 return (1.0 - a * a) / denominator;
74}
75
76inline std::array<double, 6> lagrange5_weights(double fraction) noexcept {
77 std::array<double, 6> weights{};
78 if (!std::isfinite(fraction) || fraction < 0.0 || fraction > 1.0) {
79 weights.fill(std::numeric_limits<double>::quiet_NaN());
80 return weights;
81 }
82 constexpr std::array<double, 6> nodes{-2.0, -1.0, 0.0, 1.0, 2.0, 3.0};
83 for (std::size_t i = 0; i < nodes.size(); ++i) {
84 double weight = 1.0;
85 for (std::size_t j = 0; j < nodes.size(); ++j) {
86 if (i != j)
87 weight *= (fraction - nodes[j]) / (nodes[i] - nodes[j]);
88 }
89 weights[i] = weight;
90 }
91 return weights;
92}
93
94template <typename SampleType>
95SampleType lagrange5(double fraction, SampleType ym2, SampleType ym1, SampleType y0, SampleType y1,
96 SampleType y2, SampleType y3) noexcept {
97 static_assert(std::is_floating_point_v<SampleType>);
98 const auto weights = lagrange5_weights(fraction);
99 const std::array<SampleType, 6> samples{ym2, ym1, y0, y1, y2, y3};
100 SampleType output{};
101 for (std::size_t i = 0; i < samples.size(); ++i)
102 output += static_cast<SampleType>(weights[i]) * samples[i];
103 return output;
104}
105
106namespace detail {
107
109 std::size_t integer = 0;
110 double fraction = 0.0;
111 double canonical = 0.0;
112 bool valid = false;
113};
114
115[[nodiscard]] inline FractionalDelaySplit split_fractional_delay(double delay_samples) noexcept {
116 if (!std::isfinite(delay_samples) || delay_samples < 0.0)
117 return {};
118 const auto nearest = std::round(delay_samples);
119 const auto tolerance =
120 8.0 * std::numeric_limits<double>::epsilon() * std::max(1.0, std::abs(delay_samples));
121 const auto canonical = std::abs(delay_samples - nearest) <= tolerance ? nearest : delay_samples;
122 if (canonical < 0.0)
123 return {};
124 constexpr auto size_digits = std::numeric_limits<std::size_t>::digits;
125 constexpr auto double_digits = std::numeric_limits<double>::digits;
126 const auto size_limit = static_cast<double>(std::numeric_limits<std::size_t>::max());
127 if constexpr (size_digits <= double_digits) {
128 if (canonical > size_limit)
129 return {};
130 } else {
131 // The cast to double rounds SIZE_MAX up to the next power of two.
132 // Reject that rounded endpoint before converting back to size_t.
133 if (canonical >= size_limit)
134 return {};
135 }
136 const auto integer_value = std::floor(canonical);
137 return {.integer = static_cast<std::size_t>(integer_value),
138 .fraction = canonical - integer_value,
139 .canonical = canonical,
140 .valid = true};
141}
142
143} // namespace detail
144
145template <typename SampleType> struct FractionalDelaySampleResult {
146 SampleType sample{};
148
149 [[nodiscard]] explicit operator bool() const noexcept {
151 }
152};
153
161template <typename SampleType = float> class FractionalDelayHistoryT {
162 static_assert(std::is_floating_point_v<SampleType>);
163
164 public:
168
170 move_from(std::move(other));
171 }
172
174 if (this != &other)
175 move_from(std::move(other));
176 return *this;
177 }
178
179 [[nodiscard]] bool prepare(std::size_t maximum_delay_samples) {
180 constexpr auto additional_history = 3u;
182 maximum_delay_samples > std::numeric_limits<std::size_t>::max() - additional_history)
183 return false;
184
185 const auto storage_size = maximum_delay_samples + additional_history;
186 std::vector<SampleType> replacement;
187 if (storage_size > replacement.max_size()) {
188 return false;
189 }
190#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
191 try {
192#endif
193 replacement.assign(storage_size, SampleType{});
194#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
195 } catch (const std::bad_alloc&) {
196 return false;
197 } catch (const std::length_error&) {
198 return false;
199 }
200#endif
201
202 buffer_.swap(replacement);
203 maximum_delay_samples_ = maximum_delay_samples;
204 write_ = 0;
205 valid_ = 0;
206 prepared_ = true;
207 return true;
208 }
209
210 void reset() noexcept {
211 std::fill(buffer_.begin(), buffer_.end(), SampleType{});
212 write_ = 0;
213 valid_ = 0;
214 }
215
219 void discard_history() noexcept {
220 write_ = 0;
221 valid_ = 0;
222 }
223
224 [[nodiscard]] bool prepared() const noexcept {
225 return prepared_;
226 }
227 [[nodiscard]] std::size_t maximum_delay_samples() const noexcept {
228 return prepared_ ? maximum_delay_samples_ : 0u;
229 }
230 [[nodiscard]] std::size_t retained_samples() const noexcept {
231 return buffer_.size();
232 }
233 [[nodiscard]] std::size_t retained_bytes() const noexcept {
234 return buffer_.size() * sizeof(SampleType);
235 }
236 [[nodiscard]] std::size_t required_older_lookback() const noexcept {
237 return prepared_ ? maximum_delay_samples_ + 3u : 0u;
238 }
239
240 [[nodiscard]] static constexpr std::size_t
243 return 2u;
245 return 3u;
246 return 0u;
247 }
248
251 [[nodiscard]] FractionalDelayStatus push(SampleType sample) noexcept {
252 if (!prepared_)
254 const auto status = std::isfinite(sample) ? FractionalDelayStatus::ok
256 buffer_[write_] = status == FractionalDelayStatus::ok ? sample : SampleType{};
257 write_ = (write_ + 1u) % buffer_.size();
258 valid_ = std::min(valid_ + 1u, buffer_.size());
259 return status;
260 }
261
265 read_at(double delay_samples, FractionalDelayMethod method) const noexcept {
266 if (!prepared_)
268 const auto minimum = minimum_delay_samples(method);
269 if (minimum == 0u)
271
272 const auto split = detail::split_fractional_delay(delay_samples);
273 if (!split.valid || split.canonical < static_cast<double>(minimum) ||
274 split.canonical > static_cast<double>(maximum_delay_samples_))
276
277 long double output = 0.0L;
278 if (method == FractionalDelayMethod::lagrange3) {
279 output = static_cast<long double>(Interpolator::lagrange<long double>(
280 static_cast<long double>(split.fraction), tap_delay(split.integer - 1u),
281 tap_delay(split.integer), tap_delay(split.integer + 1u),
282 tap_delay(split.integer + 2u)));
283 } else {
284 output = lagrange5<long double>(
285 split.fraction, tap_delay(split.integer - 2u), tap_delay(split.integer - 1u),
286 tap_delay(split.integer), tap_delay(split.integer + 1u),
287 tap_delay(split.integer + 2u), tap_delay(split.integer + 3u));
288 }
289
290 const auto limit = static_cast<long double>(std::numeric_limits<SampleType>::max());
291 if (!std::isfinite(output) || output > limit || output < -limit)
293 return {static_cast<SampleType>(output), FractionalDelayStatus::ok};
294 }
295
297 read_lagrange3_at(double delay_samples) const noexcept {
298 return read_at(delay_samples, FractionalDelayMethod::lagrange3);
299 }
300
302 read_lagrange5_at(double delay_samples) const noexcept {
303 return read_at(delay_samples, FractionalDelayMethod::lagrange5);
304 }
305
306 private:
307 void move_from(FractionalDelayHistoryT&& other) noexcept {
308 buffer_ = std::move(other.buffer_);
309 write_ = std::exchange(other.write_, 0u);
310 valid_ = std::exchange(other.valid_, 0u);
311 maximum_delay_samples_ = std::exchange(other.maximum_delay_samples_, 0u);
312 prepared_ = std::exchange(other.prepared_, false);
313 // Vector's moved-from size is valid but otherwise unspecified. Clear it
314 // so every moved-from query observes the same unprepared empty state.
315 other.buffer_.clear();
316 }
317
318 [[nodiscard]] long double tap_delay(std::size_t delay) const noexcept {
319 if (delay == 0u || delay > valid_)
320 return 0.0L;
321 const auto index = (write_ + buffer_.size() - delay) % buffer_.size();
322 return static_cast<long double>(buffer_[index]);
323 }
324
325 std::vector<SampleType> buffer_{};
326 std::size_t write_ = 0;
327 std::size_t valid_ = 0;
328 std::size_t maximum_delay_samples_ = 0;
329 bool prepared_ = false;
330};
331
334 std::size_t processed_frames = 0;
335 std::size_t fault_count = 0;
336
337 [[nodiscard]] explicit operator bool() const noexcept {
339 }
340};
341
350template <typename SampleType = float> class FractionalDelayLineT {
351 static_assert(std::is_floating_point_v<SampleType>);
352
353 public:
355 return prepare_impl(maximum_delay_samples, method, 1u);
356 }
357
360 [[nodiscard]] bool prepare_thiran1(std::size_t maximum_delay_samples,
361 std::size_t integer_interval_start) {
363 integer_interval_start);
364 }
365
366 private:
367 [[nodiscard]] bool prepare_impl(std::size_t maximum_delay_samples, FractionalDelayMethod method,
368 std::size_t thiran_integer_interval_start) {
370 return false;
371 const auto minimum = minimum_delay_samples(method);
372 const auto older = older_stencil_lookback(method);
373 if (maximum_delay_samples < minimum ||
374 maximum_delay_samples > std::numeric_limits<std::size_t>::max() - older - 1u)
375 return false;
379 return false;
380
381 const auto storage_size = maximum_delay_samples + older + 1u;
382 std::vector<SampleType> replacement;
383 if (storage_size > replacement.max_size()) {
384 return false;
385 }
386#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
387 try {
388#endif
389 replacement.assign(storage_size, SampleType{});
390#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
391 } catch (const std::bad_alloc&) {
392 return false;
393 } catch (const std::length_error&) {
394 return false;
395 }
396#endif
397
398 buffer_.swap(replacement);
399 maximum_delay_samples_ = maximum_delay_samples;
400 method_ = method;
401 thiran_integer_interval_start_ = thiran_integer_interval_start;
402 prepared_ = true;
403 reset_state();
404 return true;
405 }
406
407 public:
408 void reset() noexcept {
409 std::fill(buffer_.begin(), buffer_.end(), SampleType{});
410 reset_state();
411 }
412
413 [[nodiscard]] bool prepared() const noexcept {
414 return prepared_;
415 }
416 [[nodiscard]] std::optional<FractionalDelayMethod> method() const noexcept {
417 return prepared_ ? std::optional{method_} : std::nullopt;
418 }
419 [[nodiscard]] std::size_t maximum_delay_samples() const noexcept {
420 return prepared_ ? maximum_delay_samples_ : 0u;
421 }
422 [[nodiscard]] std::size_t minimum_delay_samples() const noexcept {
423 return prepared_ ? minimum_delay_samples(method_) : 0u;
424 }
425 [[nodiscard]] std::optional<std::size_t> thiran_integer_interval_start() const noexcept {
426 if (!prepared_ || method_ != FractionalDelayMethod::thiran1)
427 return std::nullopt;
428 return thiran_integer_interval_start_;
429 }
430 [[nodiscard]] std::size_t retained_samples() const noexcept {
431 return buffer_.size();
432 }
433 [[nodiscard]] std::size_t required_older_lookback() const noexcept {
434 return prepared_ ? maximum_delay_samples_ + older_stencil_lookback(method_) : 0u;
435 }
436
438 [[nodiscard]] static constexpr std::size_t processing_latency_samples() noexcept {
439 return 0;
440 }
441
442 [[nodiscard]] static constexpr std::size_t
448
449 [[nodiscard]] static constexpr std::size_t
452 return 0u;
454 return 2u;
456 return 3u;
457 return 0u;
458 }
459
460 [[nodiscard]] FractionalDelaySampleResult<SampleType> process(SampleType input,
461 double delay_samples) noexcept {
462 if (!prepared_)
464 if (!std::isfinite(input)) {
465 inject_zero();
467 }
468
469 const auto split = detail::split_fractional_delay(delay_samples);
470 const auto outside_general_range =
471 !split.valid || split.canonical < static_cast<double>(minimum_delay_samples()) ||
472 split.canonical > static_cast<double>(maximum_delay_samples_);
473 const auto outside_thiran_interval =
475 (!split.valid || split.integer != thiran_integer_interval_start_);
476 if (outside_general_range || outside_thiran_interval) {
477 inject_zero();
479 }
480
481 push(input);
482 long double output = 0.0L;
483 if (method_ == FractionalDelayMethod::thiran1)
484 output = read_thiran1(split.fraction);
485 else if (method_ == FractionalDelayMethod::lagrange3)
486 output = read_lagrange3(split.integer, split.fraction);
487 else
488 output = read_lagrange5(split.integer, split.fraction);
489
490 const auto limit = static_cast<long double>(std::numeric_limits<SampleType>::max());
491 if (!std::isfinite(output) || output > limit || output < -limit) {
492 replace_latest_with_zero();
493 reset_recursive_state();
495 }
496 return {static_cast<SampleType>(output), FractionalDelayStatus::ok};
497 }
498
499 [[nodiscard]] FractionalDelayBlockResult process(const SampleType* input, SampleType* output,
500 std::size_t frames,
501 double delay_samples) noexcept {
502 if (frames == 0)
503 return {FractionalDelayStatus::ok, 0, 0};
504 if (input == nullptr || output == nullptr)
506 if (!prepared_)
508 return process_block(input, output, frames,
509 [delay_samples](std::size_t) noexcept { return delay_samples; });
510 }
511
512 [[nodiscard]] FractionalDelayBlockResult process(const SampleType* input, SampleType* output,
513 const double* delay_samples,
514 std::size_t frames) noexcept {
515 if (frames == 0)
516 return {FractionalDelayStatus::ok, 0, 0};
517 if (input == nullptr || output == nullptr || delay_samples == nullptr)
519 if (!prepared_)
521 return process_block(input, output, frames,
522 [delay_samples](std::size_t i) noexcept { return delay_samples[i]; });
523 }
524
525 private:
526 template <typename DelayAt>
527 FractionalDelayBlockResult process_block(const SampleType* input, SampleType* output,
528 std::size_t frames, DelayAt&& delay_at) noexcept {
530 for (std::size_t i = 0; i < frames; ++i) {
531 const auto current_input = input[i];
532 const auto current = process(current_input, delay_at(i));
533 output[i] = current.sample;
534 ++result.processed_frames;
535 if (!current) {
536 if (result.status == FractionalDelayStatus::ok)
537 result.status = current.status;
538 ++result.fault_count;
539 }
540 }
541 return result;
542 }
543
544 void reset_state() noexcept {
545 write_ = 0;
546 valid_ = 0;
547 reset_recursive_state();
548 }
549
550 void reset_recursive_state() noexcept {
551 thiran_input_ = 0.0L;
552 thiran_output_ = 0.0L;
553 }
554
555 void push(SampleType sample) noexcept {
556 buffer_[write_] = sample;
557 write_ = (write_ + 1u) % buffer_.size();
558 valid_ = std::min(valid_ + 1u, buffer_.size());
559 }
560
561 void inject_zero() noexcept {
562 push(SampleType{});
563 reset_recursive_state();
564 }
565
566 void replace_latest_with_zero() noexcept {
567 const auto index = (write_ + buffer_.size() - 1u) % buffer_.size();
568 buffer_[index] = SampleType{};
569 }
570
571 [[nodiscard]] long double tap(std::size_t delay) const noexcept {
572 if (delay >= valid_)
573 return 0.0L;
574 const auto index = (write_ + buffer_.size() - 1u - delay) % buffer_.size();
575 return static_cast<long double>(buffer_[index]);
576 }
577
578 [[nodiscard]] long double read_thiran1(double fraction) noexcept {
579 const auto source = tap(thiran_integer_interval_start_ - 1u);
580 const auto design = design_thiran1(1.0 + fraction);
581 const auto a = static_cast<long double>(design.feedback);
582 const auto output = a * source + thiran_input_ - a * thiran_output_;
583 thiran_input_ = source;
584 thiran_output_ = output;
585 return output;
586 }
587
588 [[nodiscard]] long double read_lagrange3(std::size_t integer, double fraction) const noexcept {
589 return static_cast<long double>(Interpolator::lagrange<long double>(
590 static_cast<long double>(fraction), tap(integer - 1u), tap(integer), tap(integer + 1u),
591 tap(integer + 2u)));
592 }
593
594 [[nodiscard]] long double read_lagrange5(std::size_t integer, double fraction) const noexcept {
595 return lagrange5<long double>(fraction, tap(integer - 2u), tap(integer - 1u), tap(integer),
596 tap(integer + 1u), tap(integer + 2u), tap(integer + 3u));
597 }
598
599 std::vector<SampleType> buffer_{};
600 std::size_t write_ = 0;
601 std::size_t valid_ = 0;
602 std::size_t maximum_delay_samples_ = 0;
603 std::size_t thiran_integer_interval_start_ = 1;
605 long double thiran_input_ = 0.0L;
606 long double thiran_output_ = 0.0L;
607 bool prepared_ = false;
608};
609
614
615} // namespace pulp::signal
Prepared history shared by any number of stateless Lagrange read heads.
Definition fractional_delay.hpp:161
FractionalDelaySampleResult< SampleType > read_at(double delay_samples, FractionalDelayMethod method) const noexcept
Reads one stateless head from the current history snapshot.
Definition fractional_delay.hpp:265
FractionalDelayHistoryT(const FractionalDelayHistoryT &)=delete
FractionalDelayHistoryT(FractionalDelayHistoryT &&other) noexcept
Definition fractional_delay.hpp:169
bool prepare(std::size_t maximum_delay_samples)
Definition fractional_delay.hpp:179
std::size_t retained_samples() const noexcept
Definition fractional_delay.hpp:230
std::size_t retained_bytes() const noexcept
Definition fractional_delay.hpp:233
FractionalDelaySampleResult< SampleType > read_lagrange5_at(double delay_samples) const noexcept
Definition fractional_delay.hpp:302
void reset() noexcept
Definition fractional_delay.hpp:210
FractionalDelayStatus push(SampleType sample) noexcept
Advances history by one sample.
Definition fractional_delay.hpp:251
FractionalDelayHistoryT & operator=(FractionalDelayHistoryT &&other) noexcept
Definition fractional_delay.hpp:173
void discard_history() noexcept
Forgets all prior samples in constant time.
Definition fractional_delay.hpp:219
FractionalDelayHistoryT & operator=(const FractionalDelayHistoryT &)=delete
bool prepared() const noexcept
Definition fractional_delay.hpp:224
std::size_t required_older_lookback() const noexcept
Definition fractional_delay.hpp:236
std::size_t maximum_delay_samples() const noexcept
Definition fractional_delay.hpp:227
FractionalDelaySampleResult< SampleType > read_lagrange3_at(double delay_samples) const noexcept
Definition fractional_delay.hpp:297
static constexpr std::size_t minimum_delay_samples(FractionalDelayMethod method) noexcept
Definition fractional_delay.hpp:241
A prepared mono fractional-delay line.
Definition fractional_delay.hpp:350
static constexpr std::size_t minimum_delay_samples(FractionalDelayMethod method) noexcept
Definition fractional_delay.hpp:443
std::size_t retained_samples() const noexcept
Definition fractional_delay.hpp:430
bool prepared() const noexcept
Definition fractional_delay.hpp:413
FractionalDelaySampleResult< SampleType > process(SampleType input, double delay_samples) noexcept
Definition fractional_delay.hpp:460
bool prepare_thiran1(std::size_t maximum_delay_samples, std::size_t integer_interval_start)
Prepares Thiran-1 for delays in [integer_interval_start, integer_interval_start + 1).
Definition fractional_delay.hpp:360
std::optional< std::size_t > thiran_integer_interval_start() const noexcept
Definition fractional_delay.hpp:425
std::optional< FractionalDelayMethod > method() const noexcept
Definition fractional_delay.hpp:416
std::size_t required_older_lookback() const noexcept
Definition fractional_delay.hpp:433
std::size_t maximum_delay_samples() const noexcept
Definition fractional_delay.hpp:419
bool prepare(std::size_t maximum_delay_samples, FractionalDelayMethod method)
Definition fractional_delay.hpp:354
FractionalDelayBlockResult process(const SampleType *input, SampleType *output, std::size_t frames, double delay_samples) noexcept
Definition fractional_delay.hpp:499
static constexpr std::size_t older_stencil_lookback(FractionalDelayMethod method) noexcept
Definition fractional_delay.hpp:450
FractionalDelayBlockResult process(const SampleType *input, SampleType *output, const double *delay_samples, std::size_t frames) noexcept
Definition fractional_delay.hpp:512
void reset() noexcept
Definition fractional_delay.hpp:408
static constexpr std::size_t processing_latency_samples() noexcept
Processing itself adds no host-compensated latency.
Definition fractional_delay.hpp:438
std::size_t minimum_delay_samples() const noexcept
Definition fractional_delay.hpp:422
High-quality sample interpolation for delay lines and resampling.
Definition design_adherence.hpp:32
@ index
Definition gpu_pass.hpp:140
FractionalDelaySplit split_fractional_delay(double delay_samples) noexcept
Definition fractional_delay.hpp:115
Definition additive_bank.hpp:218
double thiran1_group_delay_samples(const Thiran1Coefficients &design, double omega) noexcept
Exact group delay of the first-order allpass at angular frequency omega.
Definition fractional_delay.hpp:65
FractionalDelayHistoryT< float > FractionalDelayHistory
Definition fractional_delay.hpp:612
SampleType lagrange5(double fraction, SampleType ym2, SampleType ym1, SampleType y0, SampleType y1, SampleType y2, SampleType y3) noexcept
Definition fractional_delay.hpp:95
FractionalDelayHistoryT< double > FractionalDelayHistory64
Definition fractional_delay.hpp:613
FractionalDelayStatus
Definition fractional_delay.hpp:33
@ ok
Definition fractional_delay.hpp:34
@ non_finite_input
Definition fractional_delay.hpp:37
@ output_out_of_range
Definition fractional_delay.hpp:39
@ invalid_delay
Definition fractional_delay.hpp:38
@ not_prepared
Definition fractional_delay.hpp:35
@ invalid_argument
Definition fractional_delay.hpp:36
@ delay
Definition envelope.hpp:57
FractionalDelayLineT< double > FractionalDelayLine64
Definition fractional_delay.hpp:611
@ non_finite_input
Definition comb_filter.hpp:36
@ output_out_of_range
Definition comb_filter.hpp:37
@ not_prepared
Definition comb_filter.hpp:33
@ invalid_argument
Definition comb_filter.hpp:35
std::array< double, 6 > lagrange5_weights(double fraction) noexcept
Definition fractional_delay.hpp:76
double thiran1_magnitude(const Thiran1Coefficients &design, double omega) noexcept
Definition fractional_delay.hpp:58
@ a
Definition formant_filter_bank.hpp:20
@ u
Definition formant_filter_bank.hpp:20
@ i
Definition formant_filter_bank.hpp:20
FractionalDelayLineT< float > FractionalDelayLine
Definition fractional_delay.hpp:610
@ nearest
Snap to the nearest in-scale degree in either direction.
Definition harmony_engine.hpp:175
FractionalDelayMethod
Definition fractional_delay.hpp:22
@ lagrange3
Definition fractional_delay.hpp:24
@ lagrange5
Definition fractional_delay.hpp:25
@ thiran1
Definition fractional_delay.hpp:23
@ ok
Definition breakpoint_envelope.hpp:36
Thiran1Coefficients design_thiran1(double delay_samples) noexcept
Designs H(z) = (a + z^-1) / (1 + a z^-1), where a = (1 - D) / (1 + D).
Definition fractional_delay.hpp:50
constexpr bool is_valid_fractional_delay_method(FractionalDelayMethod method) noexcept
Definition fractional_delay.hpp:28
Definition fractional_delay.hpp:332
FractionalDelayStatus status
Definition fractional_delay.hpp:333
std::size_t processed_frames
Definition fractional_delay.hpp:334
std::size_t fault_count
Definition fractional_delay.hpp:335
Definition fractional_delay.hpp:145
FractionalDelayStatus status
Definition fractional_delay.hpp:147
SampleType sample
Definition fractional_delay.hpp:146
static SampleType lagrange(SampleType frac, SampleType ym1, SampleType y0, SampleType y1, SampleType y2)
4-point Lagrange interpolation.
Definition interpolator.hpp:60
Definition fractional_delay.hpp:42
double feedback
Definition fractional_delay.hpp:44
bool valid
Definition fractional_delay.hpp:45
double delay_samples
Definition fractional_delay.hpp:43
Definition fractional_delay.hpp:108
double canonical
Definition fractional_delay.hpp:111
std::size_t integer
Definition fractional_delay.hpp:109
bool valid
Definition fractional_delay.hpp:112
double fraction
Definition fractional_delay.hpp:110