88 void prepare(
double sourceRate,
double targetRate,
93 sourceRate_ = std::max(sourceRate, 1.0);
94 targetRate_ = std::max(targetRate, 1.0);
95 ratio_ = targetRate_ / sourceRate_;
96 srcStep_ = 1.0 / ratio_;
98 sincPoints_ = qualityToSincPoints(quality);
99 kaiserBeta_ = qualityToKaiserBeta(quality);
133 resetChannelState(mono_);
134 for (
auto& cs : channelStates_)
135 resetChannelState(cs);
149 [[nodiscard]] std::vector<T>
process(
const T* input,
int inputLength)
151 if (sincTable_.empty())
return {};
155 const double outLenD =
156 std::ceil(
static_cast<double>(inputLength) * ratio_);
157 const int outputLength =
static_cast<int>(
158 std::min(outLenD,
static_cast<double>(std::numeric_limits<int>::max())));
160 std::vector<T> output(
static_cast<size_t>(outputLength));
161 const int halfSinc = sincPoints_ / 2;
163 for (
int outIdx = 0; outIdx < outputLength; ++outIdx)
166 double srcPos =
static_cast<double>(outIdx) / ratio_;
167 if (srcPos >= inputLength)
break;
169 int intPos =
static_cast<int>(srcPos);
170 double frac = srcPos -
static_cast<double>(intPos);
172 output[
static_cast<size_t>(outIdx)] = interpolateOffline(input, inputLength, intPos, frac, halfSinc);
188 return processChannel(input, inputLength, output, mono_);
202 int numCh = std::min(input.getNumChannels(), output.getNumChannels());
203 int inLen = input.getNumSamples();
205 assert(
static_cast<int>(channelStates_.size()) >= numCh &&
206 "Resampler channels not allocated! Call prepare(spec...) first.");
209 numCh = std::min(numCh,
static_cast<int>(channelStates_.size()));
212 for (
int ch = 0; ch < numCh; ++ch)
214 outCount = processChannel(input.getChannel(ch), inLen,
215 output.getChannel(ch),
216 channelStates_[
static_cast<size_t>(ch)]);
229 const double maxOut =
230 std::ceil(
static_cast<double>(inputLength) * ratio_) + 2.0;
231 return static_cast<int>(
232 std::min(maxOut,
static_cast<double>(std::numeric_limits<int>::max())));
236 [[nodiscard]]
double getRatio() const noexcept {
return ratio_; }
248 return static_cast<int>(std::round(
static_cast<double>(sincPoints_ / 2) * ratio_));
252 static constexpr int kOversample = 256;
254 static int qualityToSincPoints(
Quality q)
noexcept
276 static double qualityToKaiserBeta(
Quality q)
noexcept
289 [[nodiscard]]
static double besselI0(
double x)
noexcept
291 double sum = 1.0, term = 1.0;
292 for (
int k = 1; k <= 50; ++k)
294 const double half = x / (2.0 * k);
297 if (term < 1e-15 * sum)
break;
302 void buildSincTable()
307 sincTable_.resize(
static_cast<size_t>((kOversample + 1) * sincPoints_));
309 const int halfSinc = sincPoints_ / 2;
310 constexpr double kPi = std::numbers::pi;
311 const double beta = kaiserBeta_;
312 const double i0Beta = besselI0(beta);
315 double cutoff = (ratio_ < 1.0) ? (ratio_ * 0.95) : 1.0;
317 for (
int phase = 0; phase <= kOversample; ++phase)
319 const double frac =
static_cast<double>(phase) /
static_cast<double>(kOversample);
320 const int base = phase * sincPoints_;
323 for (
int tap = 0; tap < sincPoints_; ++tap)
336 const double t =
static_cast<double>(tap - halfSinc + 1) - frac;
337 const double x = t * cutoff;
339 double sincVal = (std::abs(x) < 1e-10)
341 : cutoff * std::sin(kPi * x) / (kPi * x);
346 const double wx = t /
static_cast<double>(halfSinc);
347 const double win = (std::abs(wx) >= 1.0)
349 : besselI0(beta * std::sqrt(1.0 - wx * wx)) / i0Beta;
351 const double v = sincVal * win;
352 sincTable_[
static_cast<size_t>(base + tap)] =
static_cast<T
>(v);
358 if (std::abs(sum) > 1e-12)
360 const T inv =
static_cast<T
>(1.0 / sum);
361 for (
int tap = 0; tap < sincPoints_; ++tap)
362 sincTable_[
static_cast<size_t>(base + tap)] *= inv;
375 T interpolateOffline(
const T* data,
int length,
int intPos,
double frac,
int halfSinc)
const noexcept
377 const double exactPhase = frac *
static_cast<double>(kOversample);
378 int p0 =
static_cast<int>(exactPhase);
379 if (p0 > kOversample - 1) p0 = kOversample - 1;
380 const T pf =
static_cast<T
>(exactPhase -
static_cast<double>(p0));
382 const T* k0 = sincTable_.data() +
static_cast<size_t>(p0) * sincPoints_;
383 const T* k1 = k0 + sincPoints_;
386 const int firstSrc = intPos - halfSinc + 1;
387 if (firstSrc >= 0 && firstSrc + sincPoints_ <= length)
390 const T* src = data + firstSrc;
393 return s0 + pf * (s1 - s0);
398 for (
int tap = 0; tap < sincPoints_; ++tap)
400 const int srcIdx = firstSrc + tap;
401 if (srcIdx < 0 || srcIdx >= length)
continue;
402 const T kernel = k0[tap] + pf * (k1[tap] - k0[tap]);
403 result += data[srcIdx] * kernel;
417 T interpolateFromHistory(
const T* historyPtr,
int readPos,
double frac)
const noexcept
419 const double exactPhase = frac *
static_cast<double>(kOversample);
420 int p0 =
static_cast<int>(exactPhase);
421 if (p0 > kOversample - 1) p0 = kOversample - 1;
422 const T pf =
static_cast<T
>(exactPhase -
static_cast<double>(p0));
424 const T* k0 = sincTable_.data() +
static_cast<size_t>(p0) * sincPoints_;
425 const T* k1 = k0 + sincPoints_;
428 const T* histPtr = &historyPtr[readPos];
432 return s0 + pf * (s1 - s0);
437 std::vector<T> history;
439 double fractionalPos = 0.0;
442 void resetChannelState(ChannelState& cs)
444 cs.history.assign(
static_cast<size_t>(sincPoints_ * 2), T(0));
446 cs.fractionalPos = 0.0;
449 void ensureChannelStates(
int numChannels)
451 if (
static_cast<int>(channelStates_.size()) < numChannels)
452 channelStates_.resize(
static_cast<size_t>(numChannels));
457 const size_t needed =
static_cast<size_t>(sincPoints_ * 2);
458 for (
auto& cs : channelStates_)
460 if (cs.history.size() != needed)
462 cs.history.assign(needed, T(0));
464 cs.fractionalPos = 0.0;
469 int processChannel(
const T* input,
int inputLength, T* output,
470 ChannelState& state)
noexcept
472 if (state.history.empty())
return 0;
477 T*
const hist = state.history.data();
478 const int n = sincPoints_;
479 const double step = srcStep_;
480 int writePos = state.writePos;
481 double frac = state.fractionalPos;
484 for (
int i = 0; i < inputLength; ++i)
488 const T x = input[i];
490 hist[writePos + n] = x;
496 output[outIdx++] = interpolateFromHistory(hist, writePos, frac);
503 state.writePos = writePos;
504 state.fractionalPos = frac;
508 double sourceRate_ = 44100.0;
509 double targetRate_ = 48000.0;
511 double srcStep_ = 1.0;
512 double kaiserBeta_ = 10.0;
514 int sincPoints_ = 32;
516 std::vector<T> sincTable_;
518 std::vector<ChannelState> channelStates_;