Add wavetable selection by frequency
This commit is contained in:
parent
e6b0b31f9b
commit
9d4d857e97
4 changed files with 103 additions and 0 deletions
|
|
@ -5,6 +5,7 @@
|
|||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||
|
||||
#include "Wavetables.h"
|
||||
#include "MathHelpers.h"
|
||||
#include <kiss_fftr.h>
|
||||
#include <memory>
|
||||
|
||||
|
|
@ -112,4 +113,33 @@ const HarmonicProfile& HarmonicProfile::getSquare()
|
|||
return squareProfile;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
constexpr unsigned WavetableRange::countOctaves;
|
||||
constexpr float WavetableRange::frequencyScaleFactor;
|
||||
|
||||
unsigned WavetableRange::getOctaveForFrequency(float f)
|
||||
{
|
||||
int oct = fp_exponent(frequencyScaleFactor * f);
|
||||
return clamp<int>(oct, 0, countOctaves - 1);
|
||||
}
|
||||
|
||||
WavetableRange WavetableRange::getRangeForOctave(int o)
|
||||
{
|
||||
WavetableRange range;
|
||||
|
||||
Fraction<uint64_t> mant = fp_mantissa(0.0f);
|
||||
float k = 1.0f / frequencyScaleFactor;
|
||||
|
||||
range.minFrequency = k * fp_from_parts<float>(0, o, 0);
|
||||
range.maxFrequency = k * fp_from_parts<float>(0, o, mant.den - 1);
|
||||
|
||||
return range;
|
||||
}
|
||||
|
||||
WavetableRange WavetableRange::getRangeForFrequency(float f)
|
||||
{
|
||||
int oct = getOctaveForFrequency(f);
|
||||
return getRangeForOctave(oct);
|
||||
}
|
||||
|
||||
} // namespace sfz
|
||||
|
|
|
|||
|
|
@ -38,4 +38,36 @@ public:
|
|||
void generate(absl::Span<float> table, double amplitude, double cutoff) const;
|
||||
};
|
||||
|
||||
/**
|
||||
A helper to select ranges of a multi-sampled oscillator, according to the
|
||||
frequency of an oscillator.
|
||||
|
||||
The ranges are identified by octave numbers; not octaves in a musical sense,
|
||||
but as logarithmic divisions of the frequency range.
|
||||
*/
|
||||
class WavetableRange {
|
||||
public:
|
||||
float minFrequency = 0;
|
||||
float maxFrequency = 0;
|
||||
|
||||
static constexpr unsigned countOctaves = 10;
|
||||
static constexpr float frequencyScaleFactor = 0.05;
|
||||
|
||||
static unsigned getOctaveForFrequency(float f);
|
||||
static WavetableRange getRangeForOctave(int o);
|
||||
static WavetableRange getRangeForFrequency(float f);
|
||||
|
||||
// Note: using the frequency factor 0.05, octaves are as follows:
|
||||
// octave 0: 20 Hz - 40 Hz
|
||||
// octave 1: 40 Hz - 80 Hz
|
||||
// octave 2: 80 Hz - 160 Hz
|
||||
// octave 3: 160 Hz - 320 Hz
|
||||
// octave 4: 320 Hz - 640 Hz
|
||||
// octave 5: 640 Hz - 1280 Hz
|
||||
// octave 6: 1280 Hz - 2560 Hz
|
||||
// octave 7: 2560 Hz - 5120 Hz
|
||||
// octave 8: 5120 Hz - 10240 Hz
|
||||
// octave 9: 10240 Hz - 20480 Hz
|
||||
};
|
||||
|
||||
} // namespace sfz
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ set(SFIZZ_TEST_SOURCES
|
|||
CurveT.cpp
|
||||
RegionTriggersT.cpp
|
||||
FloatHelpersT.cpp
|
||||
WavetablesT.cpp
|
||||
)
|
||||
|
||||
add_executable(sfizz_tests ${SFIZZ_TEST_SOURCES})
|
||||
|
|
|
|||
40
tests/WavetablesT.cpp
Normal file
40
tests/WavetablesT.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||
// license. You should have receive a LICENSE.md file along with the code.
|
||||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||
|
||||
#include "sfizz/Wavetables.h"
|
||||
#include "sfizz/MathHelpers.h"
|
||||
#include "catch2/catch.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
TEST_CASE("[Wavetables] Frequency ranges")
|
||||
{
|
||||
int cur_oct = std::numeric_limits<int>::min();
|
||||
int min_oct = std::numeric_limits<int>::max();
|
||||
int max_oct = std::numeric_limits<int>::min();
|
||||
|
||||
for (int note = 0; note < 128; ++note) {
|
||||
double f = midiNoteFrequency(note);
|
||||
|
||||
int oct = sfz::WavetableRange::getOctaveForFrequency(f);
|
||||
|
||||
REQUIRE(oct >= 0);
|
||||
REQUIRE(oct < sfz::WavetableRange::countOctaves);
|
||||
|
||||
REQUIRE(oct >= cur_oct);
|
||||
cur_oct = oct;
|
||||
|
||||
min_oct = std::min(min_oct, oct);
|
||||
max_oct = std::max(max_oct, oct);
|
||||
|
||||
sfz::WavetableRange range = sfz::WavetableRange::getRangeForOctave(oct);
|
||||
REQUIRE((f >= range.minFrequency || oct == 0));
|
||||
REQUIRE((f <= range.maxFrequency || oct == sfz::WavetableRange::countOctaves - 1));
|
||||
}
|
||||
|
||||
// check ranges to be decently adjusted to the MIDI frequency range
|
||||
REQUIRE(min_oct == 0);
|
||||
REQUIRE(max_oct == sfz::WavetableRange::countOctaves - 1);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue