Add a lookup table for wavetable octaves

This commit is contained in:
Jean Pierre Cimalando 2020-06-22 05:25:48 +02:00
parent a4f43cabd0
commit 4acb4cd7f7
3 changed files with 50 additions and 0 deletions

View file

@ -200,6 +200,39 @@ unsigned WavetableRange::getOctaveForFrequency(float f)
return clamp<int>(oct, 0, countOctaves - 1);
}
static const auto octaveForFrequencyTable = []()
{
static constexpr unsigned N = 1024;
std::array<float, N> table;
constexpr double fmin = 1 / WavetableRange::frequencyScaleFactor;
constexpr double fmax = (1 << (WavetableRange::countOctaves - 1)) / WavetableRange::frequencyScaleFactor;
for (unsigned i = 0; i < N; ++i) {
double f = fmin + (i * (1.0 / (N - 1))) * (fmax - fmin);
table[i] = std::log2(f * WavetableRange::frequencyScaleFactor);
}
return table;
}();
float WavetableRange::getFractionalOctaveForFrequency(float f)
{
static constexpr unsigned N = octaveForFrequencyTable.size();
constexpr double fmin = 1 / WavetableRange::frequencyScaleFactor;
constexpr double fmax = (1 << (WavetableRange::countOctaves - 1)) / WavetableRange::frequencyScaleFactor;
float pos = (f - fmin) * ((N - 1) / static_cast<float>(fmax - fmin));
int index1 = static_cast<int>(pos);
float frac = pos - index1;
index1 = clamp<int>(index1, 0, N - 1);
int index2 = std::min<int>(index1 + 1, N - 1);
return (1.0f - frac) * octaveForFrequencyTable[index1] +
frac * octaveForFrequencyTable[index2];
}
WavetableRange WavetableRange::getRangeForOctave(int o)
{
WavetableRange range;

View file

@ -113,6 +113,7 @@ public:
static constexpr float frequencyScaleFactor = 0.05;
static unsigned getOctaveForFrequency(float f);
static float getFractionalOctaveForFrequency(float f);
static WavetableRange getRangeForOctave(int o);
static WavetableRange getRangeForFrequency(float f);

View file

@ -8,6 +8,7 @@
#include "sfizz/MathHelpers.h"
#include "catch2/catch.hpp"
#include <algorithm>
#include <cmath>
TEST_CASE("[Wavetables] Frequency ranges")
{
@ -38,3 +39,18 @@ TEST_CASE("[Wavetables] Frequency ranges")
REQUIRE(min_oct == 0);
REQUIRE(max_oct == sfz::WavetableRange::countOctaves - 1);
}
TEST_CASE("[Wavetables] Octave number lookup")
{
for (int note = 0; note < 128; ++note) {
double f = midiNoteFrequency(note);
float ref = std::log2(f * sfz::WavetableRange::frequencyScaleFactor);
float oct = sfz::WavetableRange::getFractionalOctaveForFrequency(f);
ref = clamp<float>(ref, 0, sfz::WavetableRange::countOctaves - 1);
oct = clamp<float>(oct, 0, sfz::WavetableRange::countOctaves - 1);
REQUIRE(oct == Approx(ref).margin(0.03f));
}
}