73 return y0 + frac * (y1 - y0);
92 assert(length > 0 && position >= T(0) && position <
static_cast<T
>(length));
93 if (length <= 0)
return T(0);
99 if (!(position >= T(0))) { idx0 = 0; frac = T(0); }
100 else if (position >=
static_cast<T
>(length)) { idx0 = length - 1; frac = T(0); }
102 idx0 =
static_cast<int>(position);
103 frac = position -
static_cast<T
>(idx0);
107 if (idx1 >= length) idx1 = 0;
125template <FloatType T>
127 T c = (y2 - y0) * T(0.5);
130 T a = w + v + (y3 - y1) * T(0.5);
132 return (((a * frac) - b) * frac + c) * frac + y1;
150template <FloatType T>
152 assert(length > 0 && position >= T(0) && position <
static_cast<T
>(length));
153 if (length <= 0)
return T(0);
159 if (!(position >= T(0))) { idx1 = 0; frac = T(0); }
160 else if (position >=
static_cast<T
>(length)) { idx1 = length - 1; frac = T(0); }
162 idx1 =
static_cast<int>(position);
163 frac = position -
static_cast<T
>(idx1);
166 int idx0 = (idx1 > 0) ? idx1 - 1 : length - 1;
167 int idx2 = idx1 + 1;
if (idx2 >= length) idx2 -= length;
168 int idx3 = idx2 + 1;
if (idx3 >= length) idx3 -= length;
170 return interpolateHermite(buffer[idx0], buffer[idx1], buffer[idx2], buffer[idx3], frac);
177template <FloatType T>
195template <FloatType T>
203 static constexpr T inv6 = T(1.0 / 6.0);
204 static constexpr T inv2 = T(0.5);
206 T l0 = -(d * dm1 * dm2) * inv6;
207 T l1 = (dp1 * dm1 * dm2) * inv2;
208 T l2 = -(dp1 * d * dm2) * inv2;
209 T l3 = (dp1 * d * dm1) * inv6;
211 return l0 * y0 + l1 * y1 + l2 * y2 + l3 * y3;
229template <FloatType T>
231 assert(length > 0 && position >= T(0) && position <
static_cast<T
>(length));
232 if (length <= 0)
return T(0);
238 if (!(position >= T(0))) { idx1 = 0; frac = T(0); }
239 else if (position >=
static_cast<T
>(length)) { idx1 = length - 1; frac = T(0); }
241 idx1 =
static_cast<int>(position);
242 frac = position -
static_cast<T
>(idx1);
245 int idx0 = (idx1 > 0) ? idx1 - 1 : length - 1;
246 int idx2 = idx1 + 1;
if (idx2 >= length) idx2 -= length;
247 int idx3 = idx2 + 1;
if (idx3 >= length) idx3 -= length;
278template <FloatType T>
280 T frac, T& state)
noexcept
286 T safeFrac = (frac < T(0.001)) ? T(0.001) : frac;
287 T coeff = (T(1) - safeFrac) / (T(1) + safeFrac);
289 T output = coeff * (currentSample - state) + previousSample;
293 if (std::abs(output) < T(1e-15)) output = T(0);
321template <FloatType T>
334 constexpr double kBeta = 10.0;
335 constexpr double kPi = 3.14159265358979323846;
336 const double invI0Beta = 1.0 / besselI0(kBeta);
337 const double halfSpan =
static_cast<double>(
kTaps) / 2.0;
339 for (
int p = 0; p <=
kPhases; ++p)
341 T* row = table_.data() +
static_cast<size_t>(p) *
kTaps;
342 const double phase =
static_cast<double>(p) /
kPhases;
347 std::fill(row, row +
kTaps, T(0));
353 for (
int t = 0; t <
kTaps; ++t)
355 const double x =
static_cast<double>(t -
kBefore) - phase;
356 const double r = x / halfSpan;
357 const double window = (r * r < 1.0)
358 ? besselI0(kBeta * std::sqrt(1.0 - r * r)) * invI0Beta
360 h[t] = std::sin(kPi * x) / (kPi * x) * window;
363 for (
int t = 0; t <
kTaps; ++t)
364 row[t] =
static_cast<T
>(h[t] / sum);
374 [[nodiscard]] T
read(
const T* x,
double frac)
const noexcept
376 const double p = frac *
static_cast<double>(
kPhases);
377 const int ip = std::clamp(
static_cast<int>(p), 0,
kPhases - 1);
378 const T t =
static_cast<T
>(p -
static_cast<double>(ip));
379 const T* h0 = table_.data() +
static_cast<size_t>(ip) *
kTaps;
380 const T* h1 = h0 +
kTaps;
383 return a + t * (b - a);
394 [[nodiscard]] T
readRing(
const T* ring, int64_t mask, int64_t intPos,
double frac)
const noexcept
396 const int64_t first = intPos -
kBefore;
397 const auto start =
static_cast<size_t>(first & mask);
398 if (start +
static_cast<size_t>(
kTaps) <=
static_cast<size_t>(mask) + 1)
399 return read(ring + start, frac);
401 for (
int t = 0; t <
kTaps; ++t)
402 window[t] = ring[
static_cast<size_t>((first + t) & mask)];
403 return read(window, frac);
408 [[nodiscard]]
static double besselI0(
double x)
noexcept
410 double sum = 1.0, term = 1.0;
411 const double halfX = x / 2.0;
412 for (
int k = 1; k < 60; ++k)
414 const double f = halfX /
static_cast<double>(k);
417 if (term < sum * 1e-17)
break;
422 std::vector<T> table_;
445template <FloatType T>
457 constexpr double kBeta = 10.0;
458 constexpr double kPi = 3.14159265358979323846;
459 const double invI0Beta = 1.0 / besselI0(kBeta);
462 for (
int k = 0; k <
kSteps; ++k)
464 const double rate = std::exp2(
static_cast<double>(k + 1) /
kStepsPerOctave);
465 half_[k] =
static_cast<int>(std::ceil(16.0 * rate));
467 total +=
static_cast<size_t>(
kPhases + 1) *
static_cast<size_t>(2 * half_[k]);
469 table_.assign(total, T(0));
471 std::vector<double> h;
472 for (
int k = 0; k <
kSteps; ++k)
474 const double rate = std::exp2(
static_cast<double>(k + 1) /
kStepsPerOctave);
475 const int taps = 2 * half_[k];
476 h.assign(
static_cast<size_t>(taps), 0.0);
477 for (
int p = 0; p <=
kPhases; ++p)
479 const double phase =
static_cast<double>(p) /
kPhases;
481 for (
int t = 0; t < taps; ++t)
483 const double u = (
static_cast<double>(t - (half_[k] - 1)) - phase) / rate;
484 const double r = u / 16.0;
485 const double window = (r * r < 1.0)
486 ? besselI0(kBeta * std::sqrt(1.0 - r * r)) * invI0Beta
488 const double sinc = (u == 0.0) ? 1.0 : std::sin(kPi * u) / (kPi * u);
489 h[
static_cast<size_t>(t)] = sinc * window;
490 sum += h[
static_cast<size_t>(t)];
492 T* row = table_.data() + offset_[k] +
static_cast<size_t>(p) *
static_cast<size_t>(taps);
493 for (
int t = 0; t < taps; ++t)
494 row[t] =
static_cast<T
>(h[
static_cast<size_t>(t)] / sum);
505 [[nodiscard]]
static int stepFor(
double rate)
noexcept
507 const double steps = std::ceil(std::log2(std::max(rate, 1.0)) *
kStepsPerOctave - 1e-9);
508 return std::clamp(
static_cast<int>(steps) - 1, 0,
kSteps - 1);
522 [[nodiscard]] T
readRing(
const T* ring, int64_t mask, int64_t intPos,
double frac,
int step)
const noexcept
524 const int half = half_[step];
525 const int taps = 2 * half;
526 const double p = frac *
static_cast<double>(
kPhases);
527 const int ip = std::clamp(
static_cast<int>(p), 0,
kPhases - 1);
528 const T t =
static_cast<T
>(p -
static_cast<double>(ip));
529 const T* h0 = table_.data() + offset_[step] +
static_cast<size_t>(ip) *
static_cast<size_t>(taps);
530 const T* h1 = h0 + taps;
532 const int64_t first = intPos - (half - 1);
533 const auto start =
static_cast<size_t>(first & mask);
534 if (start +
static_cast<size_t>(taps) >
static_cast<size_t>(mask) + 1) [[unlikely]]
539 for (
int k = 0; k < taps; ++k)
540 window[k] = ring[
static_cast<size_t>((first + k) & mask)];
543 return a + t * (b - a);
545 const T* x = ring + start;
548 return a + t * (b - a);
552 [[nodiscard]]
int reach(
int step)
const noexcept {
return half_[step]; }
556 [[nodiscard]]
static double besselI0(
double x)
noexcept
558 double sum = 1.0, term = 1.0;
559 const double halfX = x / 2.0;
560 for (
int k = 1; k < 60; ++k)
562 const double f = halfX /
static_cast<double>(k);
565 if (term < sum * 1e-17)
break;
570 std::vector<T> table_;
571 size_t offset_[
kSteps] {};
32-tap Kaiser-windowed sinc reader for transparent fractional reads.
T read(const T *x, double frac) const noexcept
Interpolates kTaps consecutive samples at x[kBefore] + frac.
static constexpr int kAfter
Samples needed after intPos.
T readRing(const T *ring, int64_t mask, int64_t intPos, double frac) const noexcept
Reads a power-of-two ring buffer at intPos + frac.
static constexpr int kPhases
Tabulated fractional phases.
static constexpr int kTaps
Kernel length.
SincInterpolator()
Builds the kernel table (allocates: construct on a setup thread).
static constexpr int kBefore
Samples needed before intPos.
Band-limited fractional reader for read rates from 1 to 4.
static constexpr int kSteps
Tabulated rates.
int reach(int step) const noexcept
static constexpr int kMaxTaps
Kernel length at rate 4.
T readRing(const T *ring, int64_t mask, int64_t intPos, double frac, int step) const noexcept
Reads a power-of-two ring buffer at intPos + frac with the kernel of a rate step. It needs the sample...
static int stepFor(double rate) noexcept
The table for a read rate: the nearest tabulated rate at or above it. Costs a log2,...
static constexpr int kPhases
Phases per rate.
static constexpr int kStepsPerOctave
Rate resolution.
StretchedSincReader()
Builds the kernel tables (allocates: construct on a setup thread).
T dotProductT(const T *DSPARK_RESTRICT a, const T *DSPARK_RESTRICT b, int count) noexcept
Main namespace for the DSPark framework.
T interpolateCubic(const T *buffer, int length, T position) noexcept
Alias of interpolateHermite (Catmull-Rom evaluated in Hermite form). Kept for backward compatibility.
T interpolateHermite(T y0, T y1, T y2, T y3, T frac) noexcept
4-point, 3rd-order Hermite interpolation (optimized x-form).
T interpolateLinear(T y0, T y1, T frac) noexcept
Linear interpolation between two adjacent samples.
T interpolateLagrange(T y0, T y1, T y2, T y3, T frac) noexcept
4-point Lagrange interpolation from discrete samples.
T interpolateAllpass(T currentSample, T previousSample, T frac, T &state) noexcept
Allpass interpolation (first-order Thiran) for fractional delay.