Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
frac_delay.hpp
Go to the documentation of this file.
1#pragma once
2
3// The delay primitive every recursive stage in the tank is built from.
4//
5// signal::DelayLineT already exists and is the right block for ordinary delay
6// work, but the tank needs two things it does not offer: a 4-point Hermite read
7// (linear interpolation zippers audibly on the slow, continuous read-position
8// sweeps this reverb runs on every one of its 16 lines) and an index step with
9// no integer modulo, because the inner loop performs on the order of 300 reads
10// per sample. So this is a power-of-two-masked ring with both read paths.
11//
12// Block access. The tank processes up to one control period at a time, and
13// every read in that span lands on a sample written BEFORE the span began
14// (the shortest read is longer than the span — the tank enforces that bound).
15// So a block reads with read_at() against a virtual write position `ahead`
16// samples past the real one, and commits its writes afterwards with
17// push_block(): the result is sample-for-sample what push/read interleaved
18// would have produced, minus the per-sample bookkeeping.
19//
20// RT contract: prepare() allocates; push/read/reset allocate nothing.
21
22#include <algorithm>
23#include <cmath>
24#include <cstddef>
25#include <limits>
26#include <type_traits>
27#include <vector>
28
29#include <pulp/signal/detail/simd_lanes.hpp>
32
33namespace pulp::signal::fdn {
34
35template <typename SampleType = float>
37 public:
38 // Rounds up to a power of two with room for the Hermite window, so a read
39 // at the maximum delay can still reach its two older neighbours.
40 //
41 // `stagger` offsets the ring inside its allocation by that many samples.
42 // Owners of many same-sized rings that advance in lockstep (the tank's
43 // lines, its diffusion stages) give each a different stagger: otherwise
44 // every ring's write lands at the same low address bits as every other's,
45 // and loads stall behind stores to unrelated rings.
46 void prepare(int max_delay_samples, std::size_t stagger = 0) {
47 const int needed = std::max(max_delay_samples, 1) + 4;
48 std::size_t size = 8;
49 while (size < static_cast<std::size_t>(needed)) size <<= 1;
50 buffer_.assign(size + stagger + kMirror, SampleType{0});
51 base_ = stagger;
52 size_ = size;
53 mask_ = size - 1;
54 write_ = 0;
55 max_delay_ = static_cast<int>(size) - 4;
56 }
57
58 void reset() {
59 std::fill(buffer_.begin(), buffer_.end(), SampleType{0});
60 write_ = 0;
61 }
62
63 int max_delay() const { return max_delay_; }
64
65 void push(SampleType x) {
66 SampleType* r = ring();
67 r[write_] = x;
68 // The mirror repeats the ring's first kMirror samples; a ring shorter
69 // than the mirror appears in it more than once.
70 for (std::size_t j = size_ + write_; j < size_ + kMirror; j += size_)
71 r[j] = x;
72 write_ = (write_ + 1) & mask_;
73 }
74
75 // Sample `delay` samples old (1 = the sample pushed most recently).
76 SampleType read(int delay) const {
77 const std::size_t idx = (write_ - static_cast<std::size_t>(delay)) & mask_;
78 return ring()[idx];
79 }
80
81 // Integer read relative to a write position `ahead` samples past the
82 // current one — the position the ring will have reached `ahead` pushes
83 // from now. Only meaningful for delays longer than `ahead`.
84 SampleType read_at(int ahead, int delay) const {
85 const std::size_t idx =
86 (write_ + static_cast<std::size_t>(ahead) - static_cast<std::size_t>(delay)) & mask_;
87 return ring()[idx];
88 }
89
90 // Copy `n` consecutive samples, oldest first, starting `delay` samples
91 // behind a write position `ahead` samples past the current one. A span
92 // that does not cross the ring boundary is a plain contiguous copy.
93 void copy_out(int ahead, int delay, SampleType* dst, int n) const {
94 const std::size_t start =
95 (write_ + static_cast<std::size_t>(ahead) - static_cast<std::size_t>(delay)) & mask_;
96 const SampleType* src = ring();
97 if (start + static_cast<std::size_t>(n) <= size_) {
98 for (int k = 0; k < n; ++k)
99 dst[k] = src[start + static_cast<std::size_t>(k)];
100 } else {
101 for (int k = 0; k < n; ++k)
102 dst[k] = src[(start + static_cast<std::size_t>(k)) & mask_];
103 }
104 }
105
106 // Commit `n` samples, oldest first: identical to n calls to push().
107 void push_block(const SampleType* x, int n) {
108 for (int done = 0; done < n; done += kMaxBlockSamples) {
109 const int piece = std::min(kMaxBlockSamples, n - done);
110 SampleType* dst = ring() + write_;
111 for (int k = 0; k < piece; ++k)
112 dst[k] = x[done + k];
113 advance(piece);
114 }
115 }
116
117 // As push_block(), reading every `stride`-th element of `x`.
118 void push_strided(const SampleType* x, std::size_t stride, int n) {
119 for (int k = 0; k < n; ++k)
120 push(x[static_cast<std::size_t>(k) * stride]);
121 }
122
123 // Up to kMaxBlockSamples + 4 consecutive samples starting at ring index
124 // `start` (masked), with no wrap: the ring keeps a copy of its first
125 // kMirror samples just past its end. A Hermite read's four taps are one
126 // 16-byte load from here, and a block's span is one contiguous run.
127 const SampleType* taps_at(std::size_t start) const {
128 return ring() + (start & mask_);
129 }
130
131 // Single-precision Hermite read against a position `ahead` pushes in the
132 // future. Same taps and curve as read(double), evaluated in float: the
133 // tank's block kernels run sixteen of these per sample, and a float
134 // evaluation of a float ring is exact to the ring's own precision.
135 SampleType read_hermite_at(int ahead, double delay) const {
136 const double d = std::clamp(delay, 2.0, static_cast<double>(max_delay_));
137 const int i = static_cast<int>(d);
138 const auto f = static_cast<SampleType>(d - static_cast<double>(i));
139 const std::size_t base =
140 (write_ + static_cast<std::size_t>(ahead) - static_cast<std::size_t>(i));
141 const SampleType* r = ring();
142 return hermite4_t<SampleType>(r[(base - 2) & mask_], r[(base - 1) & mask_], r[base & mask_],
143 r[(base + 1) & mask_], SampleType{1} - f);
144 }
145
146 // n Hermite reads in float, sample k at delays[k] behind a write position
147 // k - behind pushes ahead, as read_hermite_at(k - behind, delays[k])
148 // would give. `behind` lets a caller that has already pushed the span read
149 // each sample against its own post-push position (behind = n - 1) without
150 // folding the offset into the fractional delay, whose rounding would then
151 // depend on the block length. When every read in the span shares one
152 // integer delay and its taps do not cross the ring boundary, consecutive
153 // samples' taps are consecutive in memory and the span interpolates in one
154 // vectorizable pass; otherwise each read gathers its own taps.
155 // n <= kMaxBlockSamples.
156 void read_hermite_span(const double* delays, SampleType* out, int n, int behind = 0) const {
157 const double whole = std::floor(delays[0]);
158 if (whole >= 2.0 && whole + 1.0 <= static_cast<double>(max_delay_)) {
159 const std::size_t start =
160 (write_ - static_cast<std::size_t>(behind) - static_cast<std::size_t>(whole) - 2) &
161 mask_;
162 SampleType t[kMaxBlockSamples];
163 // Every read shares the integer delay exactly when every fraction
164 // relative to it lands in [0, 1) — checked on the fractions the
165 // reads would use, so the fast path never disagrees with
166 // read_hermite_at().
167 if (start + static_cast<std::size_t>(n) + 3 <= size_ + kMirror &&
168 fractions(delays, whole, t, n)) {
169 hermite_run(ring() + start, t, out, n);
170 return;
171 }
172 }
173 for (int k = 0; k < n; ++k)
174 out[k] = read_hermite_at(k - behind, delays[k]);
175 }
176
177 // read_hermite_span() with one delay for the whole span.
178 void read_hermite_span(double delay, SampleType* out, int n, int behind = 0) const {
179 const double d = std::clamp(delay, 2.0, static_cast<double>(max_delay_));
180 const double whole = std::floor(d);
181 const std::size_t start =
182 (write_ - static_cast<std::size_t>(behind) - static_cast<std::size_t>(whole) - 2) &
183 mask_;
184 if (start + static_cast<std::size_t>(n) + 3 <= size_ + kMirror) {
185 SampleType t[kMaxBlockSamples];
186 const SampleType tk = SampleType{1} - static_cast<SampleType>(d - whole);
187 for (int k = 0; k < n; ++k)
188 t[k] = tk;
189 hermite_run(ring() + start, t, out, n);
190 return;
191 }
192 for (int k = 0; k < n; ++k)
193 out[k] = read_hermite_at(k - behind, delay);
194 }
195
196 // Raw ring access for block kernels that address the buffer themselves.
197 SampleType* data() {
198 return ring();
199 }
200 std::size_t size() const {
201 return size_;
202 }
203 std::size_t mask() const {
204 return mask_;
205 }
206 std::size_t write_index() const {
207 return write_;
208 }
209 // Samples mirrored past the ring's end (see taps_at()).
210 static constexpr std::size_t mirror_samples() {
211 return kMirror;
212 }
213
214 // advance() for a run the caller knows touched neither the ring's first
215 // mirror_samples() samples nor its end: no mirror upkeep is due.
216 void skip(int n) {
217 write_ = (write_ + static_cast<std::size_t>(n)) & mask_;
218 }
219
220 // Advance the write position past `n` samples the caller stored directly
221 // as one contiguous run from data() + write_index() (which may extend
222 // into the mirror past the ring's end, n <= kMaxBlockSamples). Moves any
223 // part written past the end to its ring index, newest last so it wins
224 // when the run is longer than the ring, then refreshes the mirror if the
225 // ring's first samples changed.
226 void advance(int n) {
227 const std::size_t end = write_ + static_cast<std::size_t>(n);
228 SampleType* r = ring();
229 if (end > size_)
230 for (std::size_t j = size_; j < end; ++j)
231 r[j & mask_] = r[j];
232 if (write_ < kMirror || end > size_)
233 refresh_mirror();
234 write_ = end & mask_;
235 }
236
237 // Fractional read. `delay` is clamped into the window where all four
238 // Hermite taps exist, so an out-of-range modulation excursion degrades to
239 // the nearest legal read instead of walking off the allocation.
240 SampleType read(double delay) const {
241 const double d = std::clamp(delay, 2.0, static_cast<double>(max_delay_));
242 const int i = static_cast<int>(d);
243 const double f = d - static_cast<double>(i);
244 // Older samples sit at larger delays, so the time-ordered Hermite taps
245 // run from delay i+2 (oldest) down to i-1 (newest); the fractional
246 // position runs the other way, hence 1 - f.
247 return static_cast<SampleType>(hermite4(
248 static_cast<double>(read(i + 2)), static_cast<double>(read(i + 1)),
249 static_cast<double>(read(i)), static_cast<double>(read(i - 1)), 1.0 - f));
250 }
251
252 private:
253 // Samples copied past the ring's end so a block's span, or its taps,
254 // never wrap.
255 static constexpr std::size_t kMirror = static_cast<std::size_t>(kMaxBlockSamples) + 4;
256
257 void refresh_mirror() {
258 if (size_ == 0)
259 return;
260 SampleType* r = ring();
261 for (std::size_t j = 0; j < kMirror; ++j)
262 r[size_ + j] = r[j];
263 }
264
265 SampleType* ring() {
266 return buffer_.data() + base_;
267 }
268 const SampleType* ring() const {
269 return buffer_.data() + base_;
270 }
271
272 // t[k] = 1 - (delays[k] - whole) in SampleType; false when any fraction
273 // falls outside [0, 1), i.e. a read does not share the integer delay.
274 static bool fractions(const double* delays, double whole, SampleType* t, int n) {
275 namespace lanes = detail::lanes;
276 int k = 0;
277 bool inside = true;
278 if constexpr (std::is_same_v<SampleType, float>) {
279 const lanes::D2 base = lanes::splat(whole);
280 const lanes::F4 zero = lanes::splat(0.0f);
281 const lanes::F4 one = lanes::splat(1.0f);
282 auto ok = lanes::less_equal(zero, zero);
283 for (; k + 4 <= n; k += 4) {
284 const lanes::F4 f = lanes::narrow(lanes::load(delays + k) - base,
285 lanes::load(delays + k + 2) - base);
286 ok = lanes::both(ok, lanes::both(lanes::less_equal(zero, f), lanes::less(f, one)));
287 lanes::store(t + k, one - f);
288 }
289 inside = lanes::all(ok);
290 }
291 for (; k < n; ++k) {
292 const auto f = static_cast<SampleType>(delays[k] - whole);
293 inside = inside && f >= SampleType{0} && f < SampleType{1};
294 t[k] = SampleType{1} - f;
295 }
296 return inside;
297 }
298
299 // out[k] = Hermite of p[k .. k + 3] at t[k]: the contiguous-taps case.
300 // Four samples at a time as explicit vectors (the expression is
301 // Interpolator::hermite's, term for term), then a scalar tail.
302 static void hermite_run(const SampleType* p, const SampleType* t, SampleType* out, int n) {
303 int k = 0;
304 if constexpr (std::is_same_v<SampleType, float>) {
305 namespace lanes = detail::lanes;
306 const lanes::F4 half = lanes::splat(0.5f);
307 const lanes::F4 two_and_half = lanes::splat(2.5f);
308 const lanes::F4 two = lanes::splat(2.0f);
309 const lanes::F4 one_and_half = lanes::splat(1.5f);
310 for (; k + 4 <= n; k += 4) {
311 const lanes::F4 ym1 = lanes::load(p + k);
312 const lanes::F4 y0 = lanes::load(p + k + 1);
313 const lanes::F4 y1 = lanes::load(p + k + 2);
314 const lanes::F4 y2 = lanes::load(p + k + 3);
315 const lanes::F4 frac = lanes::load(t + k);
316 const lanes::F4 c0 = y0;
317 const lanes::F4 c1 = half * (y1 - ym1);
318 const lanes::F4 c2 = ym1 - two_and_half * y0 + two * y1 - half * y2;
319 const lanes::F4 c3 = half * (y2 - ym1) + one_and_half * (y0 - y1);
320 lanes::store(out + k, ((c3 * frac + c2) * frac + c1) * frac + c0);
321 }
322 }
323 for (; k < n; ++k)
324 out[k] = hermite4_t<SampleType>(p[k], p[k + 1], p[k + 2], p[k + 3], t[k]);
325 }
326
327 std::vector<SampleType> buffer_;
328 std::size_t base_ = 0;
329 std::size_t size_ = 0;
330 std::size_t mask_ = 0;
331 std::size_t write_ = 0;
332 int max_delay_ = 0;
333};
334
336
337} // namespace pulp::signal::fdn
Definition frac_delay.hpp:36
static constexpr std::size_t mirror_samples()
Definition frac_delay.hpp:210
void advance(int n)
Definition frac_delay.hpp:226
SampleType read_at(int ahead, int delay) const
Definition frac_delay.hpp:84
int max_delay() const
Definition frac_delay.hpp:63
std::size_t mask() const
Definition frac_delay.hpp:203
std::size_t write_index() const
Definition frac_delay.hpp:206
void reset()
Definition frac_delay.hpp:58
const SampleType * taps_at(std::size_t start) const
Definition frac_delay.hpp:127
void prepare(int max_delay_samples, std::size_t stagger=0)
Definition frac_delay.hpp:46
void copy_out(int ahead, int delay, SampleType *dst, int n) const
Definition frac_delay.hpp:93
void push_strided(const SampleType *x, std::size_t stride, int n)
Definition frac_delay.hpp:118
void push_block(const SampleType *x, int n)
Definition frac_delay.hpp:107
SampleType read(int delay) const
Definition frac_delay.hpp:76
SampleType read(double delay) const
Definition frac_delay.hpp:240
void push(SampleType x)
Definition frac_delay.hpp:65
std::size_t size() const
Definition frac_delay.hpp:200
SampleType read_hermite_at(int ahead, double delay) const
Definition frac_delay.hpp:135
void read_hermite_span(double delay, SampleType *out, int n, int behind=0) const
Definition frac_delay.hpp:178
void read_hermite_span(const double *delays, SampleType *out, int n, int behind=0) const
Definition frac_delay.hpp:156
void skip(int n)
Definition frac_delay.hpp:216
SampleType * data()
Definition frac_delay.hpp:197
@ f
Definition pitch.hpp:25
Definition config.hpp:15
FracDelayT< float > FracDelay
Definition frac_delay.hpp:335
T hermite4_t(T y0, T y1, T y2, T y3, T t)
Definition interp.hpp:32
constexpr int kMaxBlockSamples
Definition config.hpp:190
double hermite4(double y0, double y1, double y2, double y3, double t)
Definition interp.hpp:27
@ whole
Definition units.hpp:287
@ half
Definition units.hpp:290
@ delay
Definition envelope.hpp:57
@ 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
@ i
Definition formant_filter_bank.hpp:20
@ ok
Definition breakpoint_envelope.hpp:36
@ n
Definition input_events.hpp:40
@ k
Definition input_events.hpp:40
@ t
Definition input_events.hpp:41