44 [[nodiscard]]
explicit operator bool() const noexcept {
54 [[nodiscard]]
explicit operator bool() const noexcept {
62 std::size_t delay_samples,
double gain,
63 double omega)
noexcept {
64 constexpr auto nan = std::numeric_limits<double>::quiet_NaN();
66 !std::isfinite(omega) || std::abs(gain) > 1.0 ||
68 std::abs(gain) > 0.999))
71 const auto delayed = std::polar(1.0, -omega *
static_cast<double>(delay_samples));
73 return 1.0 + gain * delayed;
74 const auto denominator = 1.0 - gain * delayed;
76 return 1.0 / denominator;
77 return (delayed - gain) / denominator;
93 static_assert(std::is_floating_point_v<SampleType>);
110 if (!prepared_ || !valid_config(candidate))
114 history_.discard_history();
123 [[nodiscard]]
bool prepared() const noexcept {
return prepared_; }
124 [[nodiscard]]
bool configured() const noexcept {
return configured_; }
126 return prepared_ ? maximum_delay_samples_ : 0
u;
129 [[nodiscard]] std::size_t
fault_count() const noexcept {
return fault_count_; }
140 [[nodiscard]] std::optional<std::size_t>
tail_samples() const noexcept {
144 return config_.gain == 0.0 ? 0
u : config_.delay_samples;
146 return config_.gain == 0.0 ? std::optional<std::size_t>{0
u} : std::nullopt;
147 return config_.gain == 0.0 ? std::optional{config_.delay_samples} : std::nullopt;
155 if (!std::isfinite(input))
158 const auto delayed = history_.read_lagrange3_at(
159 static_cast<double>(config_.delay_samples));
163 const auto x =
static_cast<long double>(input);
164 const auto d =
static_cast<long double>(delayed.sample);
165 const auto g =
static_cast<long double>(config_.gain);
166 long double output = 0.0L;
167 long double stored = 0.0L;
176 output = d - g * stored;
179 const auto limit =
static_cast<long double>(std::numeric_limits<SampleType>::max());
180 if (!std::isfinite(output) || !std::isfinite(stored) || std::abs(output) > limit ||
181 std::abs(stored) > limit)
191 std::size_t frames)
noexcept {
194 if (input ==
nullptr || output ==
nullptr)
202 for (std::size_t
i = 0;
i < frames; ++
i) {
203 const auto current_input = input[
i];
204 const auto current =
process(current_input);
205 output[
i] = current.sample;
209 result.
status = current.status;
217 [[nodiscard]]
bool valid_config(
const CombFilterConfig& candidate)
const noexcept {
220 candidate.delay_samples > maximum_delay_samples_ || !std::isfinite(candidate.gain))
223 return std::abs(candidate.gain) <= 1.0;
227 [[nodiscard]] CombFilterSampleResult<SampleType> fail(
CombFilterStatus status)
noexcept {
228 history_.discard_history();
233 FractionalDelayHistoryT<SampleType> history_{};
234 CombFilterConfig config_{};
235 std::size_t maximum_delay_samples_ = 0;
236 std::size_t fault_count_ = 0;
237 bool prepared_ =
false;
238 bool configured_ =
false;
A fixed-capacity, integer-delay comb-filter family.
Definition comb_filter.hpp:92
static constexpr std::size_t minimum_delay_samples
Definition comb_filter.hpp:97
bool prepare(std::size_t maximum_delay_samples)
Definition comb_filter.hpp:99
bool configure(const CombFilterConfig &candidate) noexcept
Definition comb_filter.hpp:109
CombFilterSampleResult< SampleType > process(SampleType input) noexcept
Definition comb_filter.hpp:150
std::size_t maximum_delay_samples() const noexcept
Definition comb_filter.hpp:125
CombFilterBlockResult process(const SampleType *input, SampleType *output, std::size_t frames) noexcept
Definition comb_filter.hpp:190
static constexpr double maximum_recursive_gain
Definition comb_filter.hpp:96
void reset() noexcept
Definition comb_filter.hpp:118
bool configured() const noexcept
Definition comb_filter.hpp:124
bool prepared() const noexcept
Definition comb_filter.hpp:123
std::size_t fault_count() const noexcept
Definition comb_filter.hpp:129
std::optional< std::size_t > tail_samples() const noexcept
Finite tail in samples, or nullopt for a recursive infinite tail.
Definition comb_filter.hpp:140
const CombFilterConfig & config() const noexcept
Definition comb_filter.hpp:128
static constexpr std::size_t processing_latency_samples() noexcept
Comb structures retain a direct path and therefore add no fixed host compensation latency.
Definition comb_filter.hpp:134
void clear_fault_count() noexcept
Definition comb_filter.hpp:130
Prepared fractional-delay storage with Thiran-1 and Lagrange-3/5 reads.
Definition additive_bank.hpp:218
CombFilterMode
Definition comb_filter.hpp:18
@ allpass
Definition comb_filter.hpp:18
@ feedforward
Definition comb_filter.hpp:18
@ feedback
Definition comb_filter.hpp:18
CombFilterT< double > CombFilter64
Definition comb_filter.hpp:242
@ ok
Definition fractional_delay.hpp:34
CombFilterStatus
Definition comb_filter.hpp:31
@ ok
Definition comb_filter.hpp:32
@ 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
@ not_configured
Definition comb_filter.hpp:34
T snap_to_zero(T x)
Returns 0 if |x| < snap_threshold, else x.
Definition denormal.hpp:45
CombFilterT< float > CombFilter
Definition comb_filter.hpp:241
@ u
Definition formant_filter_bank.hpp:20
@ i
Definition formant_filter_bank.hpp:20
constexpr bool is_valid_comb_filter_mode(CombFilterMode mode) noexcept
Definition comb_filter.hpp:20
@ ok
Definition breakpoint_envelope.hpp:36
std::complex< double > comb_filter_response(CombFilterMode mode, std::size_t delay_samples, double gain, double omega) noexcept
Returns H(e^jw) for the documented mode equations.
Definition comb_filter.hpp:61
Definition comb_filter.hpp:49
std::size_t fault_count
Definition comb_filter.hpp:52
std::size_t processed_frames
Definition comb_filter.hpp:51
CombFilterStatus status
Definition comb_filter.hpp:50
Definition comb_filter.hpp:25
std::size_t delay_samples
Definition comb_filter.hpp:27
double gain
Definition comb_filter.hpp:28
CombFilterMode mode
Definition comb_filter.hpp:26
Definition comb_filter.hpp:40
SampleType sample
Definition comb_filter.hpp:41
CombFilterStatus status
Definition comb_filter.hpp:42