Add a lookup table for wavetable octaves
This commit is contained in:
parent
a4f43cabd0
commit
4acb4cd7f7
3 changed files with 50 additions and 0 deletions
|
|
@ -200,6 +200,39 @@ unsigned WavetableRange::getOctaveForFrequency(float f)
|
||||||
return clamp<int>(oct, 0, countOctaves - 1);
|
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 WavetableRange::getRangeForOctave(int o)
|
||||||
{
|
{
|
||||||
WavetableRange range;
|
WavetableRange range;
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,7 @@ public:
|
||||||
static constexpr float frequencyScaleFactor = 0.05;
|
static constexpr float frequencyScaleFactor = 0.05;
|
||||||
|
|
||||||
static unsigned getOctaveForFrequency(float f);
|
static unsigned getOctaveForFrequency(float f);
|
||||||
|
static float getFractionalOctaveForFrequency(float f);
|
||||||
static WavetableRange getRangeForOctave(int o);
|
static WavetableRange getRangeForOctave(int o);
|
||||||
static WavetableRange getRangeForFrequency(float f);
|
static WavetableRange getRangeForFrequency(float f);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#include "sfizz/MathHelpers.h"
|
#include "sfizz/MathHelpers.h"
|
||||||
#include "catch2/catch.hpp"
|
#include "catch2/catch.hpp"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
TEST_CASE("[Wavetables] Frequency ranges")
|
TEST_CASE("[Wavetables] Frequency ranges")
|
||||||
{
|
{
|
||||||
|
|
@ -38,3 +39,18 @@ TEST_CASE("[Wavetables] Frequency ranges")
|
||||||
REQUIRE(min_oct == 0);
|
REQUIRE(min_oct == 0);
|
||||||
REQUIRE(max_oct == sfz::WavetableRange::countOctaves - 1);
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue