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
|
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||||
|
|
||||||
#include "Wavetables.h"
|
#include "Wavetables.h"
|
||||||
|
#include "MathHelpers.h"
|
||||||
#include <kiss_fftr.h>
|
#include <kiss_fftr.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
|
@ -112,4 +113,33 @@ const HarmonicProfile& HarmonicProfile::getSquare()
|
||||||
return squareProfile;
|
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
|
} // namespace sfz
|
||||||
|
|
|
||||||
|
|
@ -38,4 +38,36 @@ public:
|
||||||
void generate(absl::Span<float> table, double amplitude, double cutoff) const;
|
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
|
} // namespace sfz
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ set(SFIZZ_TEST_SOURCES
|
||||||
CurveT.cpp
|
CurveT.cpp
|
||||||
RegionTriggersT.cpp
|
RegionTriggersT.cpp
|
||||||
FloatHelpersT.cpp
|
FloatHelpersT.cpp
|
||||||
|
WavetablesT.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(sfizz_tests ${SFIZZ_TEST_SOURCES})
|
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