85 assert(sampleRate > 0.0);
86 if (!(sampleRate > 0.0))
return;
88 sampleRate_ = sampleRate;
89 phasor_.prepare(sampleRate);
112 return (harmonic % 2 == 0) ? T(-1.0 / harmonic) : T(1.0 / harmonic);
123 return (harmonic % 2 == 0) ? T(0) : T(1.0 / harmonic);
134 if (harmonic % 2 == 0)
return T(0);
135 T sign = ((harmonic / 2) % 2 == 0) ? T(1) : T(-1);
136 return sign /
static_cast<T
>(harmonic * harmonic);
149 levelHarmonics_.assign(1, 1);
153 const double phase = twoPi<double> *
static_cast<double>(i) /
static_cast<double>(
kTableSize);
154 mipData_[
static_cast<size_t>(i)] =
static_cast<T
>(std::sin(phase));
158 updateMipSelection();
168 template <
typename HarmonicFunc>
171 std::vector<double> cosAmp(kMaxHarmonics + 1, 0.0);
172 std::vector<double> sinAmp(kMaxHarmonics + 1, 0.0);
173 for (
int h = 1; h <= kMaxHarmonics; ++h)
174 sinAmp[
static_cast<size_t>(h)] =
static_cast<double>(harmonicFunc(h));
175 buildLevels(cosAmp, sinAmp, kMaxHarmonics);
190 if (!data || size <= 0)
return;
197 int rawHarmonicLimit = (size - 1) / 2;
198 int maxHarmonics = std::min(rawHarmonicLimit, kMaxHarmonics);
199 if (maxHarmonics < 1)
return;
202 std::vector<double> cosCoeffs(
static_cast<size_t>(maxHarmonics + 1), 0.0);
203 std::vector<double> sinCoeffs(
static_cast<size_t>(maxHarmonics + 1), 0.0);
205 for (
int h = 1; h <= maxHarmonics; ++h)
207 double sumCos = 0.0, sumSin = 0.0;
208 for (
int i = 0; i < size; ++i)
211 const auto k =
static_cast<long long>(h) * i % size;
212 const double phase = twoPi<double> *
static_cast<double>(k) /
static_cast<double>(size);
213 sumCos +=
static_cast<double>(data[i]) * std::cos(phase);
214 sumSin +=
static_cast<double>(data[i]) * std::sin(phase);
216 cosCoeffs[
static_cast<size_t>(h)] = sumCos * 2.0 /
static_cast<double>(size);
217 sinCoeffs[
static_cast<size_t>(h)] = sumSin * 2.0 /
static_cast<double>(size);
220 buildLevels(cosCoeffs, sinCoeffs, maxHarmonics);
235 if (frequencyHz != frequencyHz)
return;
236 const bool changed = frequencyHz != frequency_;
237 frequency_ = frequencyHz;
238 phasor_.setFrequency(frequencyHz);
239 if (changed) updateMipSelection();
255 T phase = phasor_.advance();
256 return readTable(phase);
266 for (
int i = 0; i < numSamples; ++i)
276 const int nCh = buffer.getNumChannels();
277 const int nS = buffer.getNumSamples();
278 for (
int i = 0; i < nS; ++i)
281 for (
int ch = 0; ch < nCh; ++ch)
282 buffer.getChannel(ch)[i] = s;
292 phasor_.reset(phase);
306 [[nodiscard]]
inline T readFromLevel(T phase,
int level)
const noexcept
309 int i1 =
static_cast<int>(pos);
310 T frac = pos -
static_cast<T
>(i1);
318 size_t offset =
static_cast<size_t>(level *
kTableSize);
319 const T* table = &mipData_[offset];
333 [[nodiscard]]
inline T readTable(T phase)
const noexcept
335 if (mipData_.empty())
return T(0);
337 const T s0 = readFromLevel(phase, selLevel_);
338 if (selNext_ == selLevel_ || selWeight_ >= T(1))
340 const T s1 = readFromLevel(phase, selNext_);
341 return s1 + selWeight_ * (s0 - s1);
354 void updateMipSelection() noexcept
359 if (numMipLevels_ <= 1 || safeFreq_.size() <
static_cast<size_t>(numMipLevels_))
362 const T f = std::abs(frequency_);
363 const int last = numMipLevels_ - 1;
365 while (level < last && f > safeFreq_[
static_cast<size_t>(level)])
369 selNext_ = std::min(level + 1, last);
370 if (selNext_ == level)
return;
374 const T hi = safeFreq_[
static_cast<size_t>(level)];
375 const T lo = (level > 0)
376 ? safeFreq_[
static_cast<size_t>(level - 1)]
377 : hi *
static_cast<T
>(levelHarmonics_[1]) /
static_cast<T
>(levelHarmonics_[0]);
378 const T span = hi - lo;
379 selWeight_ = (span > T(0)) ? std::clamp((hi - f) / span, T(0), T(1)) : T(1);
387 void updateMipCutoffs()
389 if (numMipLevels_ <= 0)
return;
390 safeFreq_.resize(
static_cast<size_t>(numMipLevels_));
394 const double fold = std::max(sampleRate_ * 0.5, sampleRate_ - 20000.0);
395 for (
int level = 0; level < numMipLevels_; ++level)
396 safeFreq_[
static_cast<size_t>(level)] =
static_cast<T
>(
397 fold /
static_cast<double>(levelHarmonics_[
static_cast<size_t>(level)]));
408 void buildLevels(
const std::vector<double>& cosAmp,
const std::vector<double>& sinAmp,
412 mipData_.assign(
static_cast<size_t>(numMipLevels_ *
kTableSize), T(0));
413 levelHarmonics_.assign(
static_cast<size_t>(numMipLevels_), 1);
415 FFTReal<double> fft(
static_cast<size_t>(
kTableSize));
416 std::vector<double> spec(
static_cast<size_t>(
kTableSize + 2));
417 std::vector<double> cycle(
static_cast<size_t>(
kTableSize));
418 const double half = 0.5 *
static_cast<double>(
kTableSize);
420 for (
int level = 0; level < numMipLevels_; ++level)
422 const int budget = std::min(kLevelHarmonics[
static_cast<size_t>(level)], available);
423 levelHarmonics_[
static_cast<size_t>(level)] = std::max(budget, 1);
428 std::fill(spec.begin(), spec.end(), 0.0);
429 for (
int h = 1; h <= budget; ++h)
431 spec[
static_cast<size_t>(2 * h)] = half * cosAmp[
static_cast<size_t>(h)];
432 spec[
static_cast<size_t>(2 * h + 1)] = -half * sinAmp[
static_cast<size_t>(h)];
434 fft.inverse(spec.data(), cycle.data());
436 T* dst = &mipData_[
static_cast<size_t>(level *
kTableSize)];
438 dst[i] =
static_cast<T
>(cycle[
static_cast<size_t>(i)]);
447 normalizeAllLevelsGlobally();
448 updateMipSelection();
459 void normalizeAllLevelsGlobally()
462 for (
const T v : mipData_)
463 maxVal = std::max(maxVal, std::abs(v));
467 const T invMax = T(1) / maxVal;
468 for (T& v : mipData_)
476 static constexpr int kMaxHarmonics =
kTableSize / 2 - 1;
480 static constexpr std::array<int, kMaxMipLevels> kLevelHarmonics = {
481 kMaxHarmonics, 724, 512, 362, 256, 181, 128, 90, 64, 45,
482 32, 22, 16, 11, 8, 5, 4, 3, 2, 1 };
484 double sampleRate_ = 48000.0;
485 T frequency_ = T(440);
489 int numMipLevels_ = 0;
491 std::vector<T> mipData_;
492 std::vector<int> levelHarmonics_;
493 std::vector<T> safeFreq_;