77template <
typename SampleType =
float>
99 std::size_t max_block_size,
115 const double min_rate = std::min(input_rate_, output_rate_);
116 const double min_nyq = 0.5 * min_rate;
123 const double poly_rate =
static_cast<double>(quality_.
phases) * input_rate_;
124 const double fc_norm = cutoff_hz / poly_rate;
125 const double df_norm = transition_hz / poly_rate;
136 constexpr std::size_t kMaxProtoTaps = 1u << 16;
137 if (n_taps > kMaxProtoTaps) n_taps = kMaxProtoTaps;
141 const std::size_t L = quality_.
phases;
148 for (
auto& v : prototype_) v *=
static_cast<double>(L);
156 phases_.assign(L, std::vector<SampleType>(
taps_per_phase, SampleType{0.0f}));
157 for (std::size_t p = 0; p < L; ++p) {
160 static_cast<SampleType
>(prototype_[(
taps_per_phase - 1u - k) * L + p]);
168 delays_.resize(channels_);
172 const double ratio = output_rate_ / input_rate_;
173 const std::size_t worst_out =
174 static_cast<std::size_t
>(std::ceil(
static_cast<double>(max_block_size) *
ratio)) + 8u;
175 scratch_out_.assign(channels_, std::vector<SampleType>(worst_out,
179 step_ = input_rate_ / output_rate_;
190 step_ = input_rate_ / output_rate_;
207 std::size_t in_count,
208 SampleType*
const* output,
209 std::size_t out_capacity) {
210 if (channels_ == 0 || taps_per_phase_ == 0 || phases_.empty())
return {};
211 const std::size_t L = phases_.size();
212 const double L_d =
static_cast<double>(L);
214 std::size_t out_n = 0;
215 std::size_t input_consumed = 0;
221 while (out_n < out_capacity) {
223 while (phase_acc_ >= 1.0) {
224 if (input_consumed >= in_count) {
226 return {out_n, input_consumed};
228 for (std::size_t
c = 0;
c < channels_; ++
c) {
229 delays_[
c].push(input[
c][input_consumed]);
238 const double phase_pos = phase_acc_ * L_d;
239 std::size_t p0 =
static_cast<std::size_t
>(phase_pos);
240 if (p0 >= L) p0 = L - 1u;
241 std::size_t p1 = p0 + 1u;
242 double frac = phase_pos -
static_cast<double>(p0);
243 if (p1 >= L) { p1 = p0; frac = 0.0; }
245 for (std::size_t
c = 0;
c < channels_; ++
c) {
246 const auto window = delays_[
c].window();
247 const auto& ph0 = phases_[p0];
248 const auto& ph1 = phases_[p1];
263 const SampleType* win = window.data();
264 const std::size_t T = taps_per_phase_;
265 SampleType a0 = SampleType{0.0f};
266 SampleType a1 = SampleType{0.0f};
267 SampleType a2 = SampleType{0.0f};
268 SampleType a3 = SampleType{0.0f};
271 SampleType b0 = SampleType{0.0f};
272 SampleType b1 = SampleType{0.0f};
273 SampleType b2 = SampleType{0.0f};
274 SampleType b3 = SampleType{0.0f};
275 for (; k + 4u <= T; k += 4u) {
276 a0 += win[k] * ph0[k]; b0 += win[k] * ph1[k];
277 a1 += win[k + 1u] * ph0[k + 1u]; b1 += win[k + 1u] * ph1[k + 1u];
278 a2 += win[k + 2u] * ph0[k + 2u]; b2 += win[k + 2u] * ph1[k + 2u];
279 a3 += win[k + 3u] * ph0[k + 3u]; b3 += win[k + 3u] * ph1[k + 3u];
281 SampleType acc0 = (a0 + a1) + (a2 + a3);
282 SampleType acc1 = (b0 + b1) + (b2 + b3);
283 for (; k < T; ++k) { acc0 += win[k] * ph0[k]; acc1 += win[k] * ph1[k]; }
284 output[
c][out_n] = acc0 +
static_cast<SampleType
>(frac) * (acc1 - acc0);
289 for (; k + 4u <= T; k += 4u) {
290 a0 += win[k] * ph0[k];
291 a1 += win[k + 1u] * ph0[k + 1u];
292 a2 += win[k + 2u] * ph0[k + 2u];
293 a3 += win[k + 3u] * ph0[k + 3u];
295 SampleType acc0 = (a0 + a1) + (a2 + a3);
296 for (; k < T; ++k) acc0 += win[k] * ph0[k];
297 output[
c][out_n] = acc0;
304 return {out_n, input_consumed};
308 std::size_t in_count,
309 SampleType*
const* output,
310 std::size_t out_capacity) {
315 std::size_t in_count,
317 std::size_t out_capacity) {
318 const SampleType* in_ptrs[1] = { input };
319 SampleType* out_ptrs[1] = { output };
325 std::size_t in_count,
327 std::size_t out_capacity) {
336 const double ratio = output_rate_ / input_rate_;
337 return static_cast<std::size_t
>(std::ceil(
static_cast<double>(in_count) *
ratio)) + 8u;
345 std::size_t
phases()
const {
return phases_.size(); }
358 double input_rate_ = 0.0;
359 double output_rate_ = 0.0;
360 std::size_t channels_ = 0;
365 std::vector<double> prototype_;
366 std::vector<std::vector<SampleType>> phases_;
367 std::size_t taps_per_phase_ = 0;
370 std::vector<MirroredHistoryBuffer<SampleType>> delays_;
375 std::vector<std::vector<SampleType>> scratch_out_;
379 double phase_acc_ = 0.0;
Definition resampler.hpp:78
double input_rate() const
Definition resampler.hpp:353
std::size_t process_block_mono(const SampleType *input, std::size_t in_count, SampleType *output, std::size_t out_capacity)
Mono convenience wrapper around process_block.
Definition resampler.hpp:324
ResamplerProcessResult process_block_detailed(const SampleType *const *input, std::size_t in_count, SampleType *const *output, std::size_t out_capacity)
Block API.
Definition resampler.hpp:206
void set_ratio(double input_rate, double output_rate)
Update the streaming ratio without rebuilding the filter.
Definition resampler.hpp:186
void reset()
Zero the delay lines + phase accumulator.
Definition resampler.hpp:196
void prepare(double input_rate, double output_rate, std::size_t channels, std::size_t max_block_size, ResamplerQuality quality={})
Configure the conversion.
Definition resampler.hpp:96
std::size_t channels() const
Definition resampler.hpp:355
std::size_t taps_per_phase() const
Per-phase filter length.
Definition resampler.hpp:342
ResamplerProcessResult process_block_mono_detailed(const SampleType *input, std::size_t in_count, SampleType *output, std::size_t out_capacity)
Definition resampler.hpp:314
double output_rate() const
Definition resampler.hpp:354
std::size_t prototype_length() const
Total prototype length (= phases * taps_per_phase).
Definition resampler.hpp:351
std::size_t phases() const
Number of polyphase branches (L).
Definition resampler.hpp:345
std::size_t max_output_for(std::size_t in_count) const
Worst-case output sample count for a given input count.
Definition resampler.hpp:335
std::size_t process_block(const SampleType *const *input, std::size_t in_count, SampleType *const *output, std::size_t out_capacity)
Definition resampler.hpp:307
Fixed-capacity contiguous sample history for single-thread DSP algorithms.
Definition additive_bank.hpp:218
ResamplerT< double > Resampler64
Definition resampler.hpp:383
@ c
Definition spectrum_trace.hpp:35
@ delay
Definition envelope.hpp:57
@ quality
Definition realtime_pitch_time_geometry.hpp:25
@ ratio
base_frequency_hz * ratio.
Definition fm_operator_engine.hpp:20
ResamplerT< float > Resampler
Definition resampler.hpp:382
std::size_t kaiser_length_for_transition(double stopband_db, double normalized_width)
Definition windowed_sinc_design.hpp:36
std::vector< double > design_windowed_sinc(std::size_t taps, double cutoff, double beta)
Definition windowed_sinc_design.hpp:58
double kaiser_beta_for_stopband(double stopband_db)
Definition windowed_sinc_design.hpp:27
Definition resampler.hpp:72
std::size_t input_frames_consumed
Definition resampler.hpp:74
std::size_t output_frames
Definition resampler.hpp:73
Quality knobs for the Kaiser-window prototype.
Definition resampler.hpp:65
double transition_fraction
transition width / min Nyquist
Definition resampler.hpp:67
double stopband_db
minimum stopband attenuation
Definition resampler.hpp:66
double cutoff_fraction
cutoff / min Nyquist
Definition resampler.hpp:68
std::size_t phases
polyphase oversample factor L
Definition resampler.hpp:69
Shared Kaiser-windowed-sinc FIR design helpers.