46#include <pulp/signal/detail/simd_lanes.hpp>
57namespace lanes = signal::detail::lanes;
62template <
typename SampleType =
float>
67 while (
size <
static_cast<std::size_t
>(std::max(capacity, 1) + 4))
size <<= 1;
68 buffer_.assign(
size, SampleType{0});
74 std::fill(buffer_.begin(), buffer_.end(), SampleType{0});
79 buffer_[
static_cast<std::size_t
>(written_) & mask_] = x;
83 std::int64_t
written()
const {
return written_; }
88 double read(
double position)
const {
89 const double floor_pos = std::floor(position);
90 const auto i =
static_cast<std::int64_t
>(floor_pos);
91 const double t = position - floor_pos;
92 return hermite4(at(
i - 1), at(
i), at(
i + 1), at(
i + 2), t);
96 double at(std::int64_t index)
const {
97 if (index < 0 || index >= written_)
return 0.0;
98 return static_cast<double>(buffer_[
static_cast<std::size_t
>(index) & mask_]);
101 std::vector<SampleType> buffer_;
102 std::size_t mask_ = 0;
103 std::int64_t written_ = 0;
112 void design(
double cutoff_hz,
double sample_rate) {
122 const std::array<BiquadCoefficientsT<double>, 2>&
sections()
const {
127 std::array<BiquadCoefficientsT<double>, 2> section_{};
137 for (
int k = 0; k < 2; ++k)
138 x = s_[
static_cast<std::size_t
>(k)].process(
139 sections[
static_cast<std::size_t
>(k)], x);
144 std::array<SanitizedBiquadState, 2> s_{};
153 std::size_t
size = 8;
154 while (
size <
static_cast<std::size_t
>(std::max(capacity, 1) + 4))
156 buffer_.assign(
size * 2, SampleType{0});
162 std::fill(buffer_.begin(), buffer_.end(), SampleType{0});
167 const std::size_t slot = (
static_cast<std::size_t
>(written_) & mask_) * 2;
168 if constexpr (std::is_same_v<SampleType, float>) {
169 lanes::store_narrow2(&buffer_[slot], x);
171 buffer_[slot] =
static_cast<SampleType
>(lanes::lane(x, 0));
172 buffer_[slot + 1] =
static_cast<SampleType
>(lanes::lane(x, 1));
181 return static_cast<double>(written_ - 3);
184 lanes::D2
read(
double position)
const {
185 const double floor_pos = std::floor(position);
186 const auto i =
static_cast<std::int64_t
>(floor_pos);
187 const lanes::D2 t = lanes::splat(position - floor_pos);
190 const bool inside =
i >= 1 &&
i + 2 < written_;
191 const lanes::D2 y0 = inside ? at(
i - 1) : guarded(
i - 1);
192 const lanes::D2 y1 = inside ? at(
i) : guarded(
i);
193 const lanes::D2 y2 = inside ? at(
i + 1) : guarded(
i + 1);
194 const lanes::D2 y3 = inside ? at(
i + 2) : guarded(
i + 2);
196 const lanes::D2
c1 = lanes::splat(0.5) * (y2 - y0);
198 y0 - lanes::splat(2.5) * y1 + lanes::splat(2.0) * y2 - lanes::splat(0.5) * y3;
199 const lanes::D2
c3 = lanes::splat(0.5) * (y3 - y0) + lanes::splat(1.5) * (y1 - y2);
200 return ((
c3 * t +
c2) * t +
c1) * t + y1;
204 lanes::D2 guarded(std::int64_t index)
const {
205 return index < 0 || index >= written_ ? lanes::splat(0.0) : at(index);
208 lanes::D2 at(std::int64_t index)
const {
209 const std::size_t slot = (
static_cast<std::size_t
>(index) & mask_) * 2;
210 if constexpr (std::is_same_v<SampleType, float>)
211 return lanes::load_widen2(&buffer_[slot]);
213 return lanes::make(
static_cast<double>(buffer_[slot]),
214 static_cast<double>(buffer_[slot + 1]));
217 std::vector<SampleType> buffer_;
218 std::size_t mask_ = 0;
219 std::int64_t written_ = 0;
234 return {
c.b0,
c.b1 -
c.a1 *
c.b0,
c.b2 -
c.a2 *
c.b0,
c.a1,
c.a2};
247 return {lanes::splat(s.b0), lanes::splat(s.c1), lanes::splat(s.c2), lanes::splat(s.a1),
256 s = lanes::splat(0.0);
258 s = lanes::splat(0.0);
264 for (
int k = 0; k < Sections; ++k)
270 for (
int k = 0; k < Sections; ++k) {
271 const auto&
c = sections[k];
272 const lanes::D2 s1 = s1_[k];
273 const lanes::D2 y =
c.b0 * x + s1;
274 s1_[k] =
c.c1 * x + s2_[k] -
c.a1 * s1;
275 s2_[k] =
c.c2 * x -
c.a2 * s1;
287 for (
int k = 0; k < Sections; ++k) {
288 s1_[k] = healed(s1_[k]);
289 s2_[k] = healed(s2_[k]);
294 static lanes::D2 healed(lanes::D2 v) {
295 const double a = lanes::lane(v, 0);
296 const double b = lanes::lane(v, 1);
303 lanes::D2 s1_[Sections] = {};
304 lanes::D2 s2_[Sections] = {};
309template <
typename SampleType =
float>
314 void prepare(
double host_rate,
int max_block) {
315 host_rate_ = host_rate > 0.0 ? host_rate : 48000.0;
316 max_block_ = std::max(max_block, 1);
318 static_cast<int>(std::ceil(
static_cast<double>(max_block_) *
kMaxTankRate /
324 tank_in_[
c].assign(
static_cast<std::size_t
>(max_tank_samples_), SampleType{0});
325 tank_out_[
c].assign(
static_cast<std::size_t
>(max_tank_samples_), SampleType{0});
334 resampling_ = std::abs(tank_rate_ - host_rate_) > 1
e-6;
335 host_per_tank_ = host_rate_ / tank_rate_;
336 tank_per_host_ = tank_rate_ / host_rate_;
338 const double fast = std::max(host_rate_, tank_rate_);
339 const double slow = std::min(host_rate_, tank_rate_);
341 for (
int k = 0; k < 2; ++k)
359 std::fill(tank_in_[
c].begin(), tank_in_[
c].end(), SampleType{0});
360 std::fill(tank_out_[
c].begin(), tank_out_[
c].end(), SampleType{0});
364 next_tank_pos_ = 0.0;
370 host_origin_ = -(4.0 * tank_per_host_ + 4.0);
371 next_host_pos_ = host_origin_;
380 if (!resampling_)
return 0.0;
381 return 3.0 + (4.0 * tank_per_host_ + 4.0) * host_per_tank_;
388 return next_tank_pos_;
391 return next_host_pos_;
394 SampleType*
tank_input(
int rail) {
return tank_in_[rail].data(); }
395 SampleType*
tank_output(
int rail) {
return tank_out_[rail].data(); }
402 SampleType* tl = tank_in_[0].data();
403 SampleType* tr = tank_in_[1].data();
405 for (
int i = 0;
i < n; ++
i) {
412 const bool downsampling = tank_rate_ < host_rate_;
419 for (
int i = 0;
i < n; ++
i) {
422 in_ring_.push(downsampling ? aa.
process(sections, x) : x);
423 const double limit = in_ring_.readable_through();
424 while (next_tank_pos_ <= limit && produced < max_tank_samples_) {
425 lanes::D2 v = in_ring_.read(next_tank_pos_);
428 tl[produced] =
static_cast<SampleType
>(lanes::lane(v, 0));
429 tr[produced] =
static_cast<SampleType
>(lanes::lane(v, 1));
431 next_tank_pos_ = tank_position(++tank_count_);
442 const SampleType* tl = tank_out_[0].data();
443 const SampleType* tr = tank_out_[1].data();
445 for (
int i = 0;
i < tank_n; ++
i) {
451 const bool downsampling = tank_rate_ < host_rate_;
455 for (
int i = 0;
i < tank_n; ++
i) {
456 const lanes::D2 v = lanes::make(
static_cast<double>(
finite_or_zero(tl[
i])),
458 out_ring_.push(downsampling ? v : aa.
process(sections, v));
460 for (
int i = 0;
i < host_n; ++
i) {
461 lanes::D2 v = out_ring_.read(next_host_pos_);
464 left[
i] =
static_cast<SampleType
>(lanes::lane(v, 0));
465 right[
i] =
static_cast<SampleType
>(lanes::lane(v, 1));
466 next_host_pos_ = host_position(++host_count_);
473 StereoPositionRing<SampleType> out_ring_{};
474 std::array<std::vector<SampleType>,
kNumRails> tank_in_{};
475 std::array<std::vector<SampleType>,
kNumRails> tank_out_{};
476 StereoBiquadState<2> aa_in_{};
477 StereoBiquadState<2> aa_out_{};
478 ButterworthPair filter_{};
479 StereoSection sections_[2] = {};
481 double host_rate_ = 48000.0;
482 double tank_rate_ = 20000.0;
483 double host_per_tank_ = 1.0;
484 double tank_per_host_ = 1.0;
488 double tank_position(std::int64_t
count)
const {
489 return static_cast<double>(
count) * host_rate_ / tank_rate_;
491 double host_position(std::int64_t
count)
const {
492 return host_origin_ +
static_cast<double>(
count) * tank_rate_ / host_rate_;
495 std::int64_t tank_count_ = 0;
496 std::int64_t host_count_ = 0;
497 double host_origin_ = 0.0;
498 double next_tank_pos_ = 0.0;
499 double next_host_pos_ = 0.0;
501 int max_tank_samples_ = 0;
502 bool resampling_ =
false;
@ lowpass
Definition biquad.hpp:58
void set_coefficients(const BiquadCoefficientsT< U > &c)
Definition biquad.hpp:69
Coefficients coefficients() const
Definition biquad.hpp:81
Definition multirate.hpp:110
void design(double cutoff_hz, double sample_rate)
Definition multirate.hpp:112
const std::array< BiquadCoefficientsT< double >, 2 > & sections() const
Definition multirate.hpp:122
Definition multirate.hpp:131
double process(const std::array< BiquadCoefficientsT< double >, 2 > §ions, double x)
Definition multirate.hpp:135
void reset()
Definition multirate.hpp:133
Definition multirate.hpp:310
static constexpr int kNumRails
Definition multirate.hpp:312
SampleType * tank_input(int rail)
Definition multirate.hpp:394
double input_read_position() const
Definition multirate.hpp:387
double tank_rate() const
Definition multirate.hpp:347
void configure(double tank_rate)
Definition multirate.hpp:332
int host_to_tank(const SampleType *left, const SampleType *right, int n)
Definition multirate.hpp:401
SampleType * tank_output(int rail)
Definition multirate.hpp:395
bool resampling() const
Definition multirate.hpp:348
double output_read_position() const
Definition multirate.hpp:390
double interpolation_skew_samples() const
Definition multirate.hpp:379
void tank_to_host(int tank_n, SampleType *left, SampleType *right, int host_n)
Definition multirate.hpp:441
void prepare(double host_rate, int max_block)
Definition multirate.hpp:314
void reset()
Definition multirate.hpp:353
Definition multirate.hpp:63
std::int64_t written() const
Definition multirate.hpp:83
void reset()
Definition multirate.hpp:73
void prepare(int capacity)
Definition multirate.hpp:65
double read(double position) const
Definition multirate.hpp:88
void push(SampleType x)
Definition multirate.hpp:78
double readable_through() const
Definition multirate.hpp:86
Definition multirate.hpp:252
void reset()
Definition multirate.hpp:254
lanes::D2 process(const StereoSection *sections, lanes::D2 x)
Definition multirate.hpp:262
void heal()
Definition multirate.hpp:286
lanes::D2 process(const StereoSectionLanes *sections, lanes::D2 x)
Definition multirate.hpp:269
Definition multirate.hpp:150
double readable_through() const
Definition multirate.hpp:180
void prepare(int capacity)
Definition multirate.hpp:152
void reset()
Definition multirate.hpp:161
std::int64_t written() const
Definition multirate.hpp:177
lanes::D2 read(double position) const
Definition multirate.hpp:184
void push(lanes::D2 x)
Definition multirate.hpp:166
T finite_or_zero(T value)
Definition sanitize.hpp:12
constexpr int kHealIntervalSamples
Definition config.hpp:195
constexpr double kMaxTankRate
Definition config.hpp:37
constexpr double kButterworthQ1
Definition config.hpp:169
@ count
Definition config.hpp:227
@ size
Definition config.hpp:216
constexpr double kAaCutoffFraction
Definition config.hpp:170
constexpr std::array< double, 8 > kTankRates
Definition config.hpp:34
constexpr int kHermiteGuard
Definition config.hpp:171
constexpr double kButterworthQ0
Definition config.hpp:168
double hermite4(double y0, double y1, double y2, double y3, double t)
Definition interp.hpp:27
@ right
Definition multi_channel_meter.hpp:67
@ left
Definition multi_channel_meter.hpp:66
@ c
Definition spectrum_trace.hpp:35
@ c3
Full chorus. The lush one.
Definition scanner_vibrato.hpp:28
@ c2
Medium chorus.
Definition scanner_vibrato.hpp:27
@ c1
Shallow chorus — scanner plus dry.
Definition scanner_vibrato.hpp:26
T snap_to_zero(T x)
Returns 0 if |x| < snap_threshold, else x.
Definition denormal.hpp:45
@ a
Definition formant_filter_bank.hpp:20
@ i
Definition formant_filter_bank.hpp:20
@ e
Definition formant_filter_bank.hpp:20
Definition multirate.hpp:243
lanes::D2 a2
Definition multirate.hpp:244
static StereoSectionLanes from(const StereoSection &s)
Definition multirate.hpp:246
lanes::D2 c2
Definition multirate.hpp:244
lanes::D2 a1
Definition multirate.hpp:244
lanes::D2 b0
Definition multirate.hpp:244
lanes::D2 c1
Definition multirate.hpp:244
Definition multirate.hpp:230
static StereoSection from(const BiquadCoefficientsT< double > &c)
Definition multirate.hpp:233
double a1
Definition multirate.hpp:231
double b0
Definition multirate.hpp:231
double a2
Definition multirate.hpp:231
double c2
Definition multirate.hpp:231
double c1
Definition multirate.hpp:231