Clean up the va OPF and wrap it as a linear smoother
Move modifiers and their helpers in their own files Add an enum class for modifiers and facilities to iterate over all possible targets Add smoothers to the voices and preallocate them Iterate over smoothers and modifiers jointly in the voices for each target
This commit is contained in:
parent
cb3f53496f
commit
0ed1f4cbeb
23 changed files with 798 additions and 445 deletions
|
|
@ -47,8 +47,7 @@ BENCHMARK_DEFINE_F(EnvelopeFixture, Linear)(benchmark::State& state) {
|
|||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(EnvelopeFixture, LinearNoEvent) (benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
sfz::EventVector events {
|
||||
{ 0, dist(gen) }
|
||||
};
|
||||
|
|
@ -80,8 +79,7 @@ BENCHMARK_DEFINE_F(EnvelopeFixture, Multiplicative)(benchmark::State& state) {
|
|||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(EnvelopeFixture, MultiplicativeNoEvent) (benchmark::State& state) {
|
||||
for (auto _ : state)
|
||||
{
|
||||
for (auto _ : state) {
|
||||
sfz::EventVector events {
|
||||
{ 0, dist(gen) }
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include "SIMDHelpers.h"
|
||||
#include "OnePoleFilter.h"
|
||||
#include "SfzFilter.h"
|
||||
#include "SfzHelpers.h"
|
||||
#include "ScopedFTZ.h"
|
||||
#include "SfzHelpers.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
|
|
|
|||
57
benchmarks/BM_smoothers.cpp
Normal file
57
benchmarks/BM_smoothers.cpp
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
// 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 "SIMDHelpers.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <random>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include "ModifierHelpers.h"
|
||||
#include "Smoothers.h"
|
||||
#include "absl/types/span.h"
|
||||
|
||||
class SmootherFixture : public benchmark::Fixture {
|
||||
public:
|
||||
void SetUp(const ::benchmark::State& state)
|
||||
{
|
||||
input = std::vector<float>(state.range(0));
|
||||
output = std::vector<float>(state.range(0));
|
||||
std::generate(input.begin(), input.end(), [&]() { return dist(gen); });
|
||||
sfz::cumsum<float, false>(input, absl::MakeSpan(input));
|
||||
}
|
||||
|
||||
void TearDown(const ::benchmark::State& /* state */)
|
||||
{
|
||||
}
|
||||
std::random_device rd {};
|
||||
std::mt19937 gen { rd() };
|
||||
std::uniform_real_distribution<float> dist { 0.5, 4 };
|
||||
std::vector<float> input;
|
||||
std::vector<float> output;
|
||||
};
|
||||
|
||||
BENCHMARK_DEFINE_F(SmootherFixture, Linear) (benchmark::State& state)
|
||||
{
|
||||
sfz::Smoother smoother;
|
||||
smoother.setSmoothing(10, sfz::config::defaultSampleRate);
|
||||
for (auto _ : state) {
|
||||
smoother.process(input, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
// BENCHMARK_DEFINE_F(SmootherFixture, Multiplicative)(benchmark::State& state) {
|
||||
// sfz::MultiplicativeSmoother smoother;
|
||||
// smoother.setSmoothing(10, sfz::config::defaultSampleRate);
|
||||
// for (auto _ : state)
|
||||
// {
|
||||
// smoother.process(input, absl::MakeSpan(output));
|
||||
// }
|
||||
// }
|
||||
|
||||
BENCHMARK_REGISTER_F(SmootherFixture, Linear)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
// BENCHMARK_REGISTER_F(SmootherFixture, Multiplicative)->RangeMultiplier(4)->Range(1 << 2, 1 << 12);
|
||||
BENCHMARK_MAIN();
|
||||
59
benchmarks/BM_vaFilters.cpp
Normal file
59
benchmarks/BM_vaFilters.cpp
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
// 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 "SIMDHelpers.h"
|
||||
#include "OnePoleFilter.h"
|
||||
#include "SfzFilter.h"
|
||||
#include "ScopedFTZ.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <random>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
|
||||
constexpr int blockSize { 256 };
|
||||
constexpr float sampleRate { 48000.0f };
|
||||
|
||||
class FilterFixture : public benchmark::Fixture {
|
||||
public:
|
||||
void SetUp(const ::benchmark::State&)
|
||||
{
|
||||
input = std::vector<float>(blockSize);
|
||||
output = std::vector<float>(blockSize);
|
||||
std::generate(input.begin(), input.end(), [&]() { return dist(gen); });
|
||||
}
|
||||
|
||||
void TearDown(const ::benchmark::State& /* state */)
|
||||
{
|
||||
}
|
||||
std::random_device rd {};
|
||||
std::mt19937 gen { rd() };
|
||||
std::normal_distribution<float> dist { 1, 0.2 };
|
||||
std::vector<float> input;
|
||||
std::vector<float> output;
|
||||
};
|
||||
|
||||
BENCHMARK_DEFINE_F(FilterFixture, OnePole_VA) (benchmark::State& state)
|
||||
{
|
||||
ScopedFTZ ftz;
|
||||
sfz::OnePoleFilter<float> filter;
|
||||
for (auto _ : state) {
|
||||
filter.processLowpass(input, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK_DEFINE_F(FilterFixture, OnePoleMul_VA) (benchmark::State& state)
|
||||
{
|
||||
ScopedFTZ ftz;
|
||||
sfz::OnePoleFilterMul<float> filter;
|
||||
for (auto _ : state) {
|
||||
filter.processLowpass(input, absl::MakeSpan(output));
|
||||
}
|
||||
}
|
||||
BENCHMARK_REGISTER_F(FilterFixture, OnePole_VA);
|
||||
BENCHMARK_REGISTER_F(FilterFixture, OnePoleMul_VA);
|
||||
BENCHMARK_MAIN();
|
||||
|
|
@ -62,6 +62,8 @@ sfizz_add_benchmark(bm_random BM_random.cpp)
|
|||
|
||||
sfizz_add_benchmark(bm_logger BM_logger.cpp)
|
||||
target_link_libraries(bm_logger PRIVATE sfizz::sfizz)
|
||||
sfizz_add_benchmark(bm_smoothers BM_smoothers.cpp)
|
||||
target_link_libraries(bm_smoothers PRIVATE sfizz::sfizz)
|
||||
|
||||
if (TARGET sfizz-samplerate)
|
||||
sfizz_add_benchmark(bm_resample BM_resample.cpp ${BENCHMARK_SIMD_SOURCES})
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ set (SFIZZ_SOURCES
|
|||
sfizz/Logger.cpp
|
||||
sfizz/SfzFilter.cpp
|
||||
sfizz/Curve.cpp
|
||||
sfizz/Smoothers.cpp
|
||||
sfizz/Wavetables.cpp
|
||||
sfizz/Tuning.cpp
|
||||
sfizz/RTSemaphore.cpp
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ enum class Oversampling: int {
|
|||
|
||||
namespace config {
|
||||
constexpr float defaultSampleRate { 48000 };
|
||||
constexpr float maxSampleRate { 192000 };
|
||||
constexpr int defaultSamplesPerBlock { 1024 };
|
||||
constexpr int maxBlockSize { 8192 };
|
||||
constexpr int bufferPoolSize { 6 };
|
||||
|
|
@ -39,6 +40,9 @@ namespace config {
|
|||
constexpr int numBackgroundThreads { 4 };
|
||||
constexpr int numVoices { 64 };
|
||||
constexpr unsigned maxVoices { 256 };
|
||||
constexpr unsigned smoothingSteps { 512 };
|
||||
constexpr uint8_t gainSmoothing { 10 };
|
||||
constexpr unsigned powerTableSizeExponent { 11 };
|
||||
constexpr int maxFilePromises { maxVoices };
|
||||
constexpr int sustainCC { 64 };
|
||||
constexpr int allSoundOffCC { 120 };
|
||||
|
|
|
|||
|
|
@ -82,8 +82,9 @@ namespace Default
|
|||
// Region logic: MIDI conditions
|
||||
constexpr Range<uint8_t> channelRange { 1, 16 };
|
||||
constexpr Range<uint8_t> midiChannelRange { 0, 15 };
|
||||
constexpr Range<float> stepCCRange { 0, 127 };
|
||||
constexpr Range<uint8_t> stepCCRange { 0, 127 };
|
||||
constexpr Range<uint8_t> smoothCCRange { 0, 127 };
|
||||
constexpr float smoothTauPerStep { 3e-3 };
|
||||
constexpr Range<uint8_t> curveCCRange { 0, 255 };
|
||||
constexpr Range<uint16_t> ccNumberRange { 0, config::numCCs };
|
||||
constexpr auto ccValueRange = normalizedRange;
|
||||
|
|
@ -202,6 +203,7 @@ namespace Default
|
|||
constexpr int bendUp { 200 }; // No range here because the bounds can be inverted
|
||||
constexpr int bendDown { -200 };
|
||||
constexpr int bendStep { 1 };
|
||||
constexpr uint8_t bendSmooth { 0 };
|
||||
|
||||
// Envelope generators
|
||||
constexpr float attack { 0 };
|
||||
|
|
|
|||
|
|
@ -254,6 +254,11 @@ constexpr Type sqrtTwo() { return static_cast<Type>(1.41421356237309504880168872
|
|||
template <class Type>
|
||||
constexpr Type sqrtTwoInv() { return static_cast<Type>(0.707106781186547524400844362104849039284835937688474036588); };
|
||||
|
||||
constexpr unsigned int mask(int x)
|
||||
{
|
||||
return (1U << x) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief lround for positive values
|
||||
* This optimizes a bit better by ignoring the negative code path
|
||||
|
|
@ -493,7 +498,6 @@ constexpr bool checkSpanSizes(const absl::Span<T>& span1, Others... others)
|
|||
|
||||
#define CHECK_SPAN_SIZES(...) SFIZZ_CHECK(checkSpanSizes(__VA_ARGS__))
|
||||
|
||||
|
||||
class ScopedRoundingMode {
|
||||
public:
|
||||
ScopedRoundingMode() = delete;
|
||||
|
|
|
|||
|
|
@ -2,12 +2,11 @@
|
|||
|
||||
#include "Range.h"
|
||||
#include "Defaults.h"
|
||||
#include "SfzHelpers.h"
|
||||
#include "Modifiers.h"
|
||||
#include "Resources.h"
|
||||
#include "absl/types/span.h"
|
||||
|
||||
namespace sfz {
|
||||
|
||||
/**
|
||||
* @brief Compute a crossfade in value with respect to a crossfade range (note, velocity, cc, ...)
|
||||
*/
|
||||
|
|
|
|||
54
src/sfizz/Modifiers.h
Normal file
54
src/sfizz/Modifiers.h
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
#pragma once
|
||||
#include <numeric>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
namespace sfz {
|
||||
|
||||
struct Modifier {
|
||||
float value { 0.0f };
|
||||
float step { 0.0f };
|
||||
uint8_t curve { 0 };
|
||||
uint8_t smooth { 0 };
|
||||
static_assert(config::maxCurves - 1 <= std::numeric_limits<decltype(curve)>::max(), "The curve type in the Modifier struct cannot support the required number of curves");
|
||||
};
|
||||
|
||||
enum class Mod : size_t {
|
||||
amplitude = 0,
|
||||
pan,
|
||||
width,
|
||||
position,
|
||||
pitch,
|
||||
volume,
|
||||
sentinel
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class ModifierVector : public std::vector<T> {
|
||||
public:
|
||||
T& operator[](sfz::Mod idx) { return this->std::vector<T>::operator[](static_cast<size_t>(idx)); }
|
||||
const T& operator[](sfz::Mod idx) const { return this->std::vector<T>::operator[](static_cast<size_t>(idx)); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class ModifierArray : public std::array<T, (size_t)Mod::sentinel> {
|
||||
public:
|
||||
T& operator[](sfz::Mod idx) { return this->std::array<T, (size_t)Mod::sentinel>::operator[](static_cast<size_t>(idx)); }
|
||||
const T& operator[](sfz::Mod idx) const { return this->std::array<T, (size_t)Mod::sentinel>::operator[](static_cast<size_t>(idx)); }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Helper for iterating over all possible modifiers.
|
||||
* Should fail at compile time if you update the modifiers but not this.
|
||||
*
|
||||
*/
|
||||
static const ModifierArray<Mod> allModifiers = {{
|
||||
Mod::amplitude,
|
||||
Mod::pan,
|
||||
Mod::width,
|
||||
Mod::position,
|
||||
Mod::pitch,
|
||||
Mod::volume
|
||||
}};
|
||||
|
||||
}
|
||||
|
|
@ -351,35 +351,35 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode)
|
|||
setValueFromOpcode(opcode, volume, Default::volumeRange);
|
||||
break;
|
||||
case_any_ccN("volume"): // also gain
|
||||
processGenericCc(opcode, Default::volumeCCRange, &volumeCC);
|
||||
processGenericCc(opcode, Default::volumeCCRange, &modifiers[Mod::volume]);
|
||||
break;
|
||||
case hash("amplitude"):
|
||||
if (auto value = readOpcode(opcode.value, Default::amplitudeRange))
|
||||
amplitude = normalizePercents(*value);
|
||||
break;
|
||||
case_any_ccN("amplitude"):
|
||||
processGenericCc(opcode, Default::amplitudeRange, &litudeCC);
|
||||
processGenericCc(opcode, Default::amplitudeRange, &modifiers[Mod::amplitude]);
|
||||
break;
|
||||
case hash("pan"):
|
||||
if (auto value = readOpcode(opcode.value, Default::panRange))
|
||||
pan = normalizePercents(*value);
|
||||
break;
|
||||
case_any_ccN("pan"):
|
||||
processGenericCc(opcode, Default::panCCRange, &panCC);
|
||||
processGenericCc(opcode, Default::panCCRange, &modifiers[Mod::pan]);
|
||||
break;
|
||||
case hash("position"):
|
||||
if (auto value = readOpcode(opcode.value, Default::positionRange))
|
||||
position = normalizePercents(*value);
|
||||
break;
|
||||
case_any_ccN("position"):
|
||||
processGenericCc(opcode, Default::positionCCRange, &positionCC);
|
||||
processGenericCc(opcode, Default::positionCCRange, &modifiers[Mod::position]);
|
||||
break;
|
||||
case hash("width"):
|
||||
if (auto value = readOpcode(opcode.value, Default::widthRange))
|
||||
width = normalizePercents(*value);
|
||||
break;
|
||||
case_any_ccN("width"):
|
||||
processGenericCc(opcode, Default::widthCCRange, &widthCC);
|
||||
processGenericCc(opcode, Default::widthCCRange, &modifiers[Mod::width]);
|
||||
break;
|
||||
case hash("amp_keycenter"):
|
||||
setValueFromOpcode(opcode, ampKeycenter, Default::keyRange);
|
||||
|
|
@ -742,7 +742,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode)
|
|||
setValueFromOpcode(opcode, tune, Default::tuneRange);
|
||||
break;
|
||||
case_any_ccN("pitch"): // also tune
|
||||
processGenericCc(opcode, Default::tuneCCRange, &tuneCC);
|
||||
processGenericCc(opcode, Default::tuneCCRange, &modifiers[Mod::pitch]);
|
||||
break;
|
||||
case hash("bend_up"): // also bendup
|
||||
setValueFromOpcode(opcode, bendUp, Default::bendBoundRange);
|
||||
|
|
@ -753,6 +753,9 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode)
|
|||
case hash("bend_step"):
|
||||
setValueFromOpcode(opcode, bendStep, Default::bendStepRange);
|
||||
break;
|
||||
case hash("bend_smooth"):
|
||||
setValueFromOpcode(opcode, bendSmooth, Default::smoothCCRange);
|
||||
break;
|
||||
|
||||
// Amplitude Envelope
|
||||
case hash("ampeg_attack"):
|
||||
|
|
@ -1219,3 +1222,9 @@ float sfz::Region::getGainToEffectBus(unsigned number) const noexcept
|
|||
|
||||
return gainToEffect[number];
|
||||
}
|
||||
|
||||
float sfz::Region::getBendInCents(float bend) const noexcept
|
||||
{
|
||||
const auto bendInCents = bend > 0.0f ? bend * static_cast<float>(bendUp) : -bend * static_cast<float>(bendDown);
|
||||
return centsFactor(bendInCents);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include "MidiState.h"
|
||||
#include "FileId.h"
|
||||
#include "NumericId.h"
|
||||
#include "Modifiers.h"
|
||||
#include "absl/types/optional.h"
|
||||
#include <bitset>
|
||||
#include <string>
|
||||
|
|
@ -195,6 +196,14 @@ struct Region {
|
|||
* @return float
|
||||
*/
|
||||
float velocityCurve(float velocity) const noexcept;
|
||||
/**
|
||||
* @brief Get the cents factor for a given bend value between -1 and 1
|
||||
*
|
||||
* @param bend
|
||||
* @return float
|
||||
*/
|
||||
float getBendInCents(float bend) const noexcept;
|
||||
|
||||
/**
|
||||
* @brief Get the region offset in samples
|
||||
*
|
||||
|
|
@ -309,11 +318,6 @@ struct Region {
|
|||
float pan { normalizePercents(Default::pan) }; // pan
|
||||
float width { normalizePercents(Default::width) }; // width
|
||||
float position { normalizePercents(Default::position) }; // position
|
||||
CCMap<Modifier> volumeCC { {} }; // volume_oncc
|
||||
CCMap<Modifier> amplitudeCC { {} }; // amplitude_oncc
|
||||
CCMap<Modifier> panCC { {} }; // pan_oncc
|
||||
CCMap<Modifier> widthCC { {} }; // width_oncc
|
||||
CCMap<Modifier> positionCC { {} }; // position_oncc
|
||||
uint8_t ampKeycenter { Default::ampKeycenter }; // amp_keycenter
|
||||
float ampKeytrack { Default::ampKeytrack }; // amp_keytrack
|
||||
float ampVeltrack { Default::ampVeltrack }; // amp_keytrack
|
||||
|
|
@ -342,10 +346,10 @@ struct Region {
|
|||
int pitchVeltrack { Default::pitchVeltrack }; // pitch_veltrack
|
||||
int transpose { Default::transpose }; // transpose
|
||||
int tune { Default::tune }; // tune
|
||||
CCMap<Modifier> tuneCC { {} };
|
||||
int bendUp { Default::bendUp };
|
||||
int bendDown { Default::bendDown };
|
||||
int bendStep { Default::bendStep };
|
||||
uint8_t bendSmooth { Default::bendSmooth };
|
||||
|
||||
// Envelopes
|
||||
EGDescription amplitudeEG;
|
||||
|
|
@ -357,6 +361,9 @@ struct Region {
|
|||
// Effects
|
||||
std::vector<float> gainToEffect;
|
||||
|
||||
// Modifiers
|
||||
ModifierArray<CCMap<Modifier>> modifiers;
|
||||
|
||||
private:
|
||||
const MidiState& midiState;
|
||||
bool keySwitched { true };
|
||||
|
|
|
|||
|
|
@ -17,8 +17,7 @@
|
|||
#include "absl/meta/type_traits.h"
|
||||
#include "Defaults.h"
|
||||
|
||||
namespace sfz
|
||||
{
|
||||
namespace sfz {
|
||||
|
||||
using CCNamePair = std::pair<uint16_t, std::string>;
|
||||
using NoteNamePair = std::pair<uint8_t, std::string>;
|
||||
|
|
@ -32,14 +31,6 @@ struct CCData {
|
|||
static_assert(config::numCCs - 1 < std::numeric_limits<decltype(cc)>::max(), "The cc type in the CCData struct cannot support the required number of CCs");
|
||||
};
|
||||
|
||||
struct Modifier {
|
||||
float value { 0.0f };
|
||||
float step { 0.0f };
|
||||
uint8_t curve { 0 };
|
||||
uint8_t smooth { 0 };
|
||||
static_assert(config::maxCurves - 1 <= std::numeric_limits<decltype(curve)>::max(), "The curve type in the Modifier struct cannot support the required number of curves");
|
||||
};
|
||||
|
||||
template <class ValueType>
|
||||
struct CCDataComparator {
|
||||
bool operator()(const CCData<ValueType>& ccData, const int& cc)
|
||||
|
|
@ -160,7 +151,6 @@ constexpr float normalizeVelocity(T velocity)
|
|||
return normalize7Bits(velocity);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Normalize a percentage between 0 and 1
|
||||
*
|
||||
|
|
@ -212,6 +202,12 @@ inline CXX14_CONSTEXPR Type vaGain(Type cutoff, Type sampleRate)
|
|||
return std::tan(cutoff / sampleRate * pi<Type>());
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
inline CXX14_CONSTEXPR Type vaGain(Type cutoff, Type sampleRate)
|
||||
{
|
||||
return std::tan(cutoff / sampleRate * pi<Type>());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief From a source view, find the next sfz header and its members and
|
||||
* return them, while updating the source by removing this header
|
||||
|
|
@ -275,4 +271,3 @@ bool findDefine(absl::string_view line, absl::string_view& variable, absl::strin
|
|||
bool findInclude(absl::string_view line, std::string& path);
|
||||
|
||||
} // namespace sfz
|
||||
|
||||
|
|
|
|||
30
src/sfizz/Smoothers.cpp
Normal file
30
src/sfizz/Smoothers.cpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#include "Smoothers.h"
|
||||
|
||||
namespace sfz {
|
||||
|
||||
Smoother::Smoother()
|
||||
{
|
||||
}
|
||||
|
||||
void Smoother::setSmoothing(uint8_t smoothValue, float sampleRate)
|
||||
{
|
||||
smoothing = (smoothValue > 0);
|
||||
if (smoothing) {
|
||||
filter.setGain(std::tan(1.0f / (2 * Default::smoothTauPerStep * smoothValue * sampleRate)));
|
||||
}
|
||||
}
|
||||
|
||||
void Smoother::reset(float value)
|
||||
{
|
||||
filter.reset(value);
|
||||
}
|
||||
|
||||
void Smoother::process(absl::Span<const float> input, absl::Span<float> output)
|
||||
{
|
||||
if (smoothing)
|
||||
filter.processLowpass(input, output);
|
||||
else
|
||||
copy<float>(input, output);
|
||||
}
|
||||
|
||||
}
|
||||
24
src/sfizz/Smoothers.h
Normal file
24
src/sfizz/Smoothers.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include "Config.h"
|
||||
#include "Defaults.h"
|
||||
#include "MathHelpers.h"
|
||||
#include "SfzHelpers.h"
|
||||
#include "OnePoleFilter.h"
|
||||
#include "SIMDHelpers.h"
|
||||
#include <array>
|
||||
|
||||
namespace sfz {
|
||||
class Smoother {
|
||||
public:
|
||||
Smoother();
|
||||
void setSmoothing(uint8_t smoothValue, float sampleRate);
|
||||
void reset(float value = 0.0f);
|
||||
void process(absl::Span<const float> input, absl::Span<float> output);
|
||||
|
||||
private:
|
||||
bool smoothing { false };
|
||||
OnePoleFilter<float> filter {};
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
#include "Debug.h"
|
||||
#include "Macros.h"
|
||||
#include "MidiState.h"
|
||||
#include "ModifierHelpers.h"
|
||||
#include "ScopedFTZ.h"
|
||||
#include "StringViewHelpers.h"
|
||||
#include "pugixml.hpp"
|
||||
|
|
@ -374,6 +375,7 @@ void sfz::Synth::finalizeSfzLoad()
|
|||
|
||||
size_t maxFilters { 0 };
|
||||
size_t maxEQs { 0 };
|
||||
ModifierArray<size_t> maxModifiers { 0 };
|
||||
|
||||
while (currentRegionIndex < currentRegionCount) {
|
||||
auto region = regions[currentRegionIndex].get();
|
||||
|
|
@ -480,6 +482,8 @@ void sfz::Synth::finalizeSfzLoad()
|
|||
region->registerTempo(2.0f);
|
||||
maxFilters = max(maxFilters, region->filters.size());
|
||||
maxEQs = max(maxEQs, region->equalizers.size());
|
||||
for (const auto& mod : allModifiers)
|
||||
maxModifiers[mod] = max(maxModifiers[mod], region->modifiers[mod].size());
|
||||
|
||||
++currentRegionIndex;
|
||||
}
|
||||
|
|
@ -490,6 +494,7 @@ void sfz::Synth::finalizeSfzLoad()
|
|||
for (auto& voice : voices) {
|
||||
voice->setMaxFiltersPerVoice(maxFilters);
|
||||
voice->setMaxEQsPerVoice(maxEQs);
|
||||
voice->prepareSmoothers(maxModifiers);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ sfz::Voice::Voice(int voiceNumber, sfz::Resources& resources)
|
|||
for (WavetableOscillator& osc : waveOscillators)
|
||||
osc.init(sampleRate);
|
||||
|
||||
gainSmoother.setSmoothing(config::gainSmoothing, sampleRate);
|
||||
|
||||
for (auto & filter : channelEnvelopeFilters)
|
||||
filter.setGain(vaGain(config::filteredEnvelopeCutoff, sampleRate));
|
||||
}
|
||||
|
|
@ -97,6 +99,7 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, float value,
|
|||
baseGain = region->getBaseGain();
|
||||
if (triggerType != TriggerType::CC)
|
||||
baseGain *= region->getNoteGain(number, value);
|
||||
gainSmoother.reset();
|
||||
|
||||
// Check that we can handle the number of filters; filters should be cleared here
|
||||
ASSERT((filters.capacity() - filters.size()) >= region->filters.size());
|
||||
|
|
@ -120,7 +123,26 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, float value,
|
|||
initialDelay = delay + static_cast<int>(region->getDelay() * sampleRate);
|
||||
baseFrequency = resources.tuning.getFrequencyOfKey(number);
|
||||
bendStepFactor = centsFactor(region->bendStep);
|
||||
bendSmoother.setSmoothing(region->bendSmooth, sampleRate);
|
||||
bendSmoother.reset(region->getBendInCents(resources.midiState.getPitchBend()));
|
||||
egEnvelope.reset(region->amplitudeEG, *region, resources.midiState, delay, value, sampleRate);
|
||||
|
||||
for (auto& modId : allModifiers) {
|
||||
ASSERT(modifierSmoothers[modId].size() >= region->modifiers[modId].size());
|
||||
forEachWithSmoother(modId, [modId, this](const CCData<Modifier>& mod, Smoother& smoother) {
|
||||
switch (modId) {
|
||||
case Mod::volume:
|
||||
smoother.reset(db2mag(resources.midiState.getCCValue(mod.cc) * mod.data.value));
|
||||
break;
|
||||
case Mod::pitch:
|
||||
smoother.reset(centsFactor(resources.midiState.getCCValue(mod.cc) * mod.data.value));
|
||||
break;
|
||||
default:
|
||||
smoother.reset(resources.midiState.getCCValue(mod.cc) * mod.data.value);
|
||||
}
|
||||
smoother.setSmoothing(mod.data.smooth, sampleRate);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
int sfz::Voice::getCurrentSampleQuality() const noexcept
|
||||
|
|
@ -206,6 +228,7 @@ void sfz::Voice::registerTempo(int delay, float secondsPerQuarter) noexcept
|
|||
void sfz::Voice::setSampleRate(float sampleRate) noexcept
|
||||
{
|
||||
this->sampleRate = sampleRate;
|
||||
gainSmoother.setSmoothing(config::gainSmoothing, sampleRate);
|
||||
|
||||
for (auto & filter : channelEnvelopeFilters)
|
||||
filter.setGain(vaGain(config::filteredEnvelopeCutoff, sampleRate));
|
||||
|
|
@ -283,10 +306,11 @@ void sfz::Voice::amplitudeEnvelope(absl::Span<float> modulationSpan) noexcept
|
|||
|
||||
// Amplitude envelope
|
||||
applyGain1<float>(baseGain, modulationSpan);
|
||||
for (const auto& mod : region->amplitudeCC) {
|
||||
forEachWithSmoother(Mod::amplitude, [&](const CCData<Modifier>& mod, Smoother& smoother) {
|
||||
linearModifier(resources, *tempSpan, mod, normalizePercents<float>);
|
||||
smoother.process(*tempSpan, *tempSpan);
|
||||
applyGain<float>(*tempSpan, modulationSpan);
|
||||
}
|
||||
});
|
||||
|
||||
// Crossfade envelopes
|
||||
for (const auto& mod : region->crossfadeCCInRange) {
|
||||
|
|
@ -306,12 +330,16 @@ void sfz::Voice::amplitudeEnvelope(absl::Span<float> modulationSpan) noexcept
|
|||
|
||||
// Volume envelope
|
||||
applyGain1<float>(db2mag(baseVolumedB), modulationSpan);
|
||||
for (const auto& mod : region->volumeCC) {
|
||||
forEachWithSmoother(Mod::volume, [&](const CCData<Modifier>& mod, Smoother& smoother) {
|
||||
multiplicativeModifier(resources, *tempSpan, mod, [](float x) {
|
||||
return db2mag(x);
|
||||
});
|
||||
smoother.process(*tempSpan, *tempSpan);
|
||||
applyGain<float>(*tempSpan, modulationSpan);
|
||||
}
|
||||
});
|
||||
|
||||
// Smooth the gain transitions
|
||||
gainSmoother.process(modulationSpan, modulationSpan);
|
||||
}
|
||||
|
||||
void sfz::Voice::ampStageMono(AudioSpan<float> buffer) noexcept
|
||||
|
|
@ -360,10 +388,11 @@ void sfz::Voice::panStageMono(AudioSpan<float> buffer) noexcept
|
|||
|
||||
// Apply panning
|
||||
fill(*modulationSpan, region->pan);
|
||||
for (const auto& mod : region->panCC) {
|
||||
forEachWithSmoother(Mod::pan, [&](const CCData<Modifier>& mod, Smoother& smoother) {
|
||||
linearModifier(resources, *tempSpan, mod, normalizePercents<float>);
|
||||
smoother.process(*tempSpan, *tempSpan);
|
||||
add<float>(*tempSpan, *modulationSpan);
|
||||
}
|
||||
});
|
||||
pan(*modulationSpan, leftBuffer, rightBuffer);
|
||||
}
|
||||
|
||||
|
|
@ -381,25 +410,28 @@ void sfz::Voice::panStageStereo(AudioSpan<float> buffer) noexcept
|
|||
|
||||
// Apply panning
|
||||
fill(*modulationSpan, region->pan);
|
||||
for (const auto& mod : region->panCC) {
|
||||
forEachWithSmoother(Mod::pan, [&](const CCData<Modifier>& mod, Smoother& smoother) {
|
||||
linearModifier(resources, *tempSpan, mod, normalizePercents<float>);
|
||||
smoother.process(*tempSpan, *tempSpan);
|
||||
add<float>(*tempSpan, *modulationSpan);
|
||||
}
|
||||
});
|
||||
pan(*modulationSpan, leftBuffer, rightBuffer);
|
||||
|
||||
// Apply the width/position process
|
||||
fill(*modulationSpan, region->width);
|
||||
for (const auto& mod : region->widthCC) {
|
||||
forEachWithSmoother(Mod::width, [&](const CCData<Modifier>& mod, Smoother& smoother) {
|
||||
linearModifier(resources, *tempSpan, mod, normalizePercents<float>);
|
||||
smoother.process(*tempSpan, *tempSpan);
|
||||
add<float>(*tempSpan, *modulationSpan);
|
||||
}
|
||||
});
|
||||
width(*modulationSpan, leftBuffer, rightBuffer);
|
||||
|
||||
fill(*modulationSpan, region->position);
|
||||
for (const auto& mod : region->positionCC) {
|
||||
forEachWithSmoother(Mod::position, [&](const CCData<Modifier>& mod, Smoother& smoother) {
|
||||
linearModifier(resources, *tempSpan, mod, normalizePercents<float>);
|
||||
smoother.process(*tempSpan, *tempSpan);
|
||||
add<float>(*tempSpan, *modulationSpan);
|
||||
}
|
||||
});
|
||||
pan(*modulationSpan, leftBuffer, rightBuffer);
|
||||
}
|
||||
|
||||
|
|
@ -452,30 +484,13 @@ void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
|
|||
auto source = currentPromise->getData();
|
||||
|
||||
auto jumps = resources.bufferPool.getBuffer(numSamples);
|
||||
auto bends = resources.bufferPool.getBuffer(numSamples);
|
||||
auto coeffs = resources.bufferPool.getBuffer(numSamples);
|
||||
auto indices = resources.bufferPool.getIndexBuffer(numSamples);
|
||||
if (!jumps || !bends || !indices || !coeffs)
|
||||
if (!jumps || !indices || !coeffs)
|
||||
return;
|
||||
|
||||
fill(*jumps, pitchRatio * speedRatio);
|
||||
|
||||
const auto events = resources.midiState.getPitchEvents();
|
||||
const auto bendLambda = [this](float bend) {
|
||||
const auto bendInCents = bend > 0.0f ? bend * static_cast<float>(region->bendUp) : -bend * static_cast<float>(region->bendDown);
|
||||
return centsFactor(bendInCents);
|
||||
};
|
||||
|
||||
if (region->bendStep > 1)
|
||||
pitchBendEnvelope(events, *bends, bendLambda, bendStepFactor);
|
||||
else
|
||||
pitchBendEnvelope(events, *bends, bendLambda);
|
||||
applyGain<float>(*bends, *jumps);
|
||||
|
||||
for (const auto& mod : region->tuneCC) {
|
||||
multiplicativeModifier(resources, *bends, mod, [](float x) { return centsFactor(x); });
|
||||
applyGain<float>(*bends, *jumps);
|
||||
}
|
||||
pitchEnvelope(*jumps);
|
||||
|
||||
jumps->front() += floatPositionOffset;
|
||||
cumsum<float>(*jumps, *jumps);
|
||||
|
|
@ -584,30 +599,12 @@ void sfz::Voice::fillWithGenerator(AudioSpan<float> buffer) noexcept
|
|||
const auto numFrames = buffer.getNumFrames();
|
||||
|
||||
auto frequencies = resources.bufferPool.getBuffer(numFrames);
|
||||
auto bends = resources.bufferPool.getBuffer(numFrames);
|
||||
if (!frequencies || !bends)
|
||||
if (!frequencies)
|
||||
return;
|
||||
|
||||
float keycenterFrequency = midiNoteFrequency(region->pitchKeycenter);
|
||||
fill(*frequencies, pitchRatio * keycenterFrequency);
|
||||
|
||||
const auto events = resources.midiState.getPitchEvents();
|
||||
const auto bendLambda = [this](float bend) {
|
||||
const auto bendInCents = bend > 0.0f ? bend * static_cast<float>(region->bendUp) : -bend * static_cast<float>(region->bendDown);
|
||||
return centsFactor(bendInCents);
|
||||
};
|
||||
if (region->bendStep > 1)
|
||||
pitchBendEnvelope(events, *bends, bendLambda, bendStepFactor);
|
||||
else
|
||||
pitchBendEnvelope(events, *bends, bendLambda);
|
||||
applyGain<float>(*bends, *frequencies);
|
||||
|
||||
for (const auto& mod : region->tuneCC) {
|
||||
multiplicativeModifier(resources, *bends, mod, [](float x) {
|
||||
return centsFactor(x);
|
||||
});
|
||||
applyGain<float>(*bends, *frequencies);
|
||||
}
|
||||
pitchEnvelope(*frequencies);
|
||||
|
||||
if (waveUnisonSize == 1) {
|
||||
WavetableOscillator& osc = waveOscillators[0];
|
||||
|
|
@ -784,7 +781,6 @@ void sfz::Voice::setupOscillatorUnison()
|
|||
#endif
|
||||
}
|
||||
|
||||
|
||||
void sfz::Voice::updateChannelPowers(AudioSpan<float> buffer)
|
||||
{
|
||||
assert(smoothedChannelEnvelopes.size() == channelEnvelopeFilters.size());
|
||||
|
|
@ -809,3 +805,59 @@ void sfz::Voice::switchState(State s)
|
|||
stateListener->onVoiceStateChanged(id, s);
|
||||
}
|
||||
}
|
||||
|
||||
void sfz::Voice::prepareSmoothers(const ModifierArray<size_t>& numModifiers)
|
||||
{
|
||||
for (auto& mod : allModifiers)
|
||||
modifierSmoothers[mod].resize(numModifiers[mod]);
|
||||
}
|
||||
|
||||
void sfz::Voice::pitchEnvelope(absl::Span<float> pitchSpan) noexcept
|
||||
{
|
||||
const auto numFrames = pitchSpan.size();
|
||||
auto bends = resources.bufferPool.getBuffer(numFrames);
|
||||
if (!bends)
|
||||
return;
|
||||
|
||||
const auto events = resources.midiState.getPitchEvents();
|
||||
const auto bendLambda = [this](float bend) {
|
||||
return region->getBendInCents(bend);
|
||||
};
|
||||
|
||||
if (region->bendStep > 1)
|
||||
pitchBendEnvelope(events, *bends, bendLambda, bendStepFactor);
|
||||
else
|
||||
pitchBendEnvelope(events, *bends, bendLambda);
|
||||
bendSmoother.process(*bends, *bends);
|
||||
applyGain<float>(*bends, pitchSpan);
|
||||
|
||||
forEachWithSmoother(Mod::pitch, [&](const CCData<Modifier>& mod, Smoother& smoother) {
|
||||
multiplicativeModifier(resources, *bends, mod, [](float x) {
|
||||
return centsFactor(x);
|
||||
});
|
||||
smoother.process(*bends, *bends);
|
||||
applyGain<float>(*bends, pitchSpan);
|
||||
});
|
||||
}
|
||||
|
||||
void sfz::Voice::resetSmoothers() noexcept
|
||||
{
|
||||
for (auto& mod : allModifiers) {
|
||||
const auto resetValue = [mod] {
|
||||
switch (mod) {
|
||||
case Mod::volume:
|
||||
return 1.0f;
|
||||
case Mod::pitch:
|
||||
return 1.0f;
|
||||
default:
|
||||
return 0.0f;
|
||||
}
|
||||
}();
|
||||
|
||||
for (auto& smoother : modifierSmoothers[mod]) {
|
||||
smoother.reset(resetValue);
|
||||
}
|
||||
}
|
||||
bendSmoother.reset(1.0f);
|
||||
gainSmoother.reset(0.0f);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "Region.h"
|
||||
#include "AudioBuffer.h"
|
||||
#include "Resources.h"
|
||||
#include "Smoothers.h"
|
||||
#include "AudioSpan.h"
|
||||
#include "LeakDetector.h"
|
||||
#include "OnePoleFilter.h"
|
||||
|
|
@ -301,6 +302,8 @@ public:
|
|||
Duration getLastFilterDuration() const noexcept { return filterDuration; }
|
||||
Duration getLastPanningDuration() const noexcept { return panningDuration; }
|
||||
|
||||
void prepareSmoothers(const ModifierArray<size_t>& numModifiers);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Fill a span with data from a file source. This is the first step
|
||||
|
|
@ -337,12 +340,25 @@ private:
|
|||
void panStageStereo(AudioSpan<float> buffer) noexcept;
|
||||
void filterStageMono(AudioSpan<float> buffer) noexcept;
|
||||
void filterStageStereo(AudioSpan<float> buffer) noexcept;
|
||||
void pitchEnvelope(absl::Span<float> pitchSpan) noexcept;
|
||||
|
||||
/**
|
||||
* @brief Remove the voice from the sister ring
|
||||
*
|
||||
*/
|
||||
void removeVoiceFromRing() noexcept;
|
||||
|
||||
template <class F>
|
||||
void forEachWithSmoother(sfz::Mod modId, F&& lambda)
|
||||
{
|
||||
auto mod = region->modifiers[modId].begin();
|
||||
auto smoother = modifierSmoothers[modId].begin();
|
||||
while (mod < region->modifiers[modId].end()) {
|
||||
lambda(*mod, *smoother);
|
||||
incrementAll(mod, smoother);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize frequency and gain coefficients for the oscillators.
|
||||
*/
|
||||
|
|
@ -410,8 +426,15 @@ private:
|
|||
|
||||
std::normal_distribution<float> noiseDist { 0, config::noiseVariance };
|
||||
|
||||
ModifierArray<std::vector<Smoother>> modifierSmoothers;
|
||||
Smoother gainSmoother;
|
||||
Smoother bendSmoother;
|
||||
void resetSmoothers() noexcept;
|
||||
|
||||
std::array<OnePoleFilter<float>, 2> channelEnvelopeFilters;
|
||||
std::array<float, 2> smoothedChannelEnvelopes;
|
||||
|
||||
HistoricalBuffer<float> powerHistory { config::powerHistoryLength };
|
||||
LEAK_DETECTOR(Voice);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ set(SFIZZ_TEST_SOURCES
|
|||
MidiStateT.cpp
|
||||
OnePoleFilterT.cpp
|
||||
InterpolatorsT.cpp
|
||||
SmoothersT.cpp
|
||||
RegionActivationT.cpp
|
||||
RegionValueComputationsT.cpp
|
||||
# If we're tweaking the curves this kind of tests does not make sense
|
||||
|
|
|
|||
175
tests/FilesT.cpp
175
tests/FilesT.cpp
|
|
@ -13,10 +13,11 @@
|
|||
#endif
|
||||
using namespace Catch::literals;
|
||||
using namespace sfz::literals;
|
||||
using namespace sfz;
|
||||
|
||||
TEST_CASE("[Files] Single region (regions_one.sfz)")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Regions/regions_one.sfz");
|
||||
REQUIRE(synth.getNumRegions() == 1);
|
||||
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy.wav");
|
||||
|
|
@ -25,7 +26,7 @@ TEST_CASE("[Files] Single region (regions_one.sfz)")
|
|||
|
||||
TEST_CASE("[Files] Multiple regions (regions_many.sfz)")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Regions/regions_many.sfz");
|
||||
REQUIRE(synth.getNumRegions() == 3);
|
||||
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy.wav");
|
||||
|
|
@ -35,15 +36,15 @@ TEST_CASE("[Files] Multiple regions (regions_many.sfz)")
|
|||
|
||||
TEST_CASE("[Files] Basic opcodes (regions_opcodes.sfz)")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Regions/regions_opcodes.sfz");
|
||||
REQUIRE(synth.getNumRegions() == 1);
|
||||
REQUIRE(synth.getRegionView(0)->keyRange == sfz::Range<uint8_t>(2, 14));
|
||||
REQUIRE(synth.getRegionView(0)->keyRange == Range<uint8_t>(2, 14));
|
||||
}
|
||||
|
||||
TEST_CASE("[Files] Underscore opcodes (underscore_opcodes.sfz)")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Regions/underscore_opcodes.sfz");
|
||||
REQUIRE(synth.getNumRegions() == 1);
|
||||
REQUIRE(synth.getRegionView(0)->loopMode == SfzLoopMode::loop_sustain);
|
||||
|
|
@ -51,7 +52,7 @@ TEST_CASE("[Files] Underscore opcodes (underscore_opcodes.sfz)")
|
|||
|
||||
TEST_CASE("[Files] (regions_bad.sfz)")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Regions/regions_bad.sfz");
|
||||
REQUIRE(synth.getNumRegions() == 2);
|
||||
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy.wav");
|
||||
|
|
@ -60,7 +61,7 @@ TEST_CASE("[Files] (regions_bad.sfz)")
|
|||
|
||||
TEST_CASE("[Files] Local include")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/root_local.sfz");
|
||||
REQUIRE(synth.getNumRegions() == 1);
|
||||
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy.wav");
|
||||
|
|
@ -68,7 +69,7 @@ TEST_CASE("[Files] Local include")
|
|||
|
||||
TEST_CASE("[Files] Multiple includes")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/multiple_includes.sfz");
|
||||
REQUIRE(synth.getNumRegions() == 2);
|
||||
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy.wav");
|
||||
|
|
@ -77,7 +78,7 @@ TEST_CASE("[Files] Multiple includes")
|
|||
|
||||
TEST_CASE("[Files] Multiple includes with comments")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/multiple_includes_with_comments.sfz");
|
||||
REQUIRE(synth.getNumRegions() == 2);
|
||||
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy.wav");
|
||||
|
|
@ -86,7 +87,7 @@ TEST_CASE("[Files] Multiple includes with comments")
|
|||
|
||||
TEST_CASE("[Files] Subdir include")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/root_subdir.sfz");
|
||||
REQUIRE(synth.getNumRegions() == 1);
|
||||
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy_subdir.wav");
|
||||
|
|
@ -94,7 +95,7 @@ TEST_CASE("[Files] Subdir include")
|
|||
|
||||
TEST_CASE("[Files] Subdir include Win")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/root_subdir_win.sfz");
|
||||
REQUIRE(synth.getNumRegions() == 1);
|
||||
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy_subdir.wav");
|
||||
|
|
@ -102,8 +103,8 @@ TEST_CASE("[Files] Subdir include Win")
|
|||
|
||||
TEST_CASE("[Files] Recursive include (with include guard)")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
sfz::Parser& parser = synth.getParser();
|
||||
Synth synth;
|
||||
Parser& parser = synth.getParser();
|
||||
parser.setRecursiveIncludeGuardEnabled(true);
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/root_recursive.sfz");
|
||||
REQUIRE(synth.getNumRegions() == 2);
|
||||
|
|
@ -113,8 +114,8 @@ TEST_CASE("[Files] Recursive include (with include guard)")
|
|||
|
||||
TEST_CASE("[Files] Include loops (with include guard)")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
sfz::Parser& parser = synth.getParser();
|
||||
Synth synth;
|
||||
Parser& parser = synth.getParser();
|
||||
parser.setRecursiveIncludeGuardEnabled(true);
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/Includes/root_loop.sfz");
|
||||
REQUIRE(synth.getNumRegions() == 2);
|
||||
|
|
@ -124,34 +125,34 @@ TEST_CASE("[Files] Include loops (with include guard)")
|
|||
|
||||
TEST_CASE("[Files] Define test")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/defines.sfz");
|
||||
REQUIRE(synth.getNumRegions() == 4);
|
||||
REQUIRE(synth.getRegionView(0)->keyRange == sfz::Range<uint8_t>(36, 36));
|
||||
REQUIRE(synth.getRegionView(1)->keyRange == sfz::Range<uint8_t>(38, 38));
|
||||
REQUIRE(synth.getRegionView(2)->keyRange == sfz::Range<uint8_t>(42, 42));
|
||||
REQUIRE(synth.getRegionView(0)->keyRange == Range<uint8_t>(36, 36));
|
||||
REQUIRE(synth.getRegionView(1)->keyRange == Range<uint8_t>(38, 38));
|
||||
REQUIRE(synth.getRegionView(2)->keyRange == Range<uint8_t>(42, 42));
|
||||
REQUIRE(synth.getRegionView(3)->volume == -12.0f);
|
||||
}
|
||||
|
||||
TEST_CASE("[Files] Group from AVL")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/groups_avl.sfz");
|
||||
REQUIRE(synth.getNumRegions() == 5);
|
||||
for (int i = 0; i < synth.getNumRegions(); ++i) {
|
||||
REQUIRE(synth.getRegionView(i)->volume == 6.0f);
|
||||
REQUIRE(synth.getRegionView(i)->keyRange == sfz::Range<uint8_t>(36, 36));
|
||||
REQUIRE(synth.getRegionView(i)->keyRange == Range<uint8_t>(36, 36));
|
||||
}
|
||||
REQUIRE(synth.getRegionView(0)->velocityRange == sfz::Range<float>(1_norm, 26_norm));
|
||||
REQUIRE(synth.getRegionView(1)->velocityRange == sfz::Range<float>(27_norm, 52_norm));
|
||||
REQUIRE(synth.getRegionView(2)->velocityRange == sfz::Range<float>(53_norm, 77_norm));
|
||||
REQUIRE(synth.getRegionView(3)->velocityRange == sfz::Range<float>(78_norm, 102_norm));
|
||||
REQUIRE(synth.getRegionView(4)->velocityRange == sfz::Range<float>(103_norm, 127_norm));
|
||||
REQUIRE(synth.getRegionView(0)->velocityRange == Range<float>(1_norm, 26_norm));
|
||||
REQUIRE(synth.getRegionView(1)->velocityRange == Range<float>(27_norm, 52_norm));
|
||||
REQUIRE(synth.getRegionView(2)->velocityRange == Range<float>(53_norm, 77_norm));
|
||||
REQUIRE(synth.getRegionView(3)->velocityRange == Range<float>(78_norm, 102_norm));
|
||||
REQUIRE(synth.getRegionView(4)->velocityRange == Range<float>(103_norm, 127_norm));
|
||||
}
|
||||
|
||||
TEST_CASE("[Files] Full hierarchy")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/basic_hierarchy.sfz");
|
||||
REQUIRE(synth.getNumRegions() == 8);
|
||||
for (int i = 0; i < synth.getNumRegions(); ++i) {
|
||||
|
|
@ -159,40 +160,40 @@ TEST_CASE("[Files] Full hierarchy")
|
|||
}
|
||||
REQUIRE(synth.getRegionView(0)->pan == 0.3_a);
|
||||
REQUIRE(synth.getRegionView(0)->delay == 67);
|
||||
REQUIRE(synth.getRegionView(0)->keyRange == sfz::Range<uint8_t>(60, 60));
|
||||
REQUIRE(synth.getRegionView(0)->keyRange == Range<uint8_t>(60, 60));
|
||||
|
||||
REQUIRE(synth.getRegionView(1)->pan == 0.3_a);
|
||||
REQUIRE(synth.getRegionView(1)->delay == 67);
|
||||
REQUIRE(synth.getRegionView(1)->keyRange == sfz::Range<uint8_t>(61, 61));
|
||||
REQUIRE(synth.getRegionView(1)->keyRange == Range<uint8_t>(61, 61));
|
||||
|
||||
REQUIRE(synth.getRegionView(2)->pan == 0.3_a);
|
||||
REQUIRE(synth.getRegionView(2)->delay == 56);
|
||||
REQUIRE(synth.getRegionView(2)->keyRange == sfz::Range<uint8_t>(50, 50));
|
||||
REQUIRE(synth.getRegionView(2)->keyRange == Range<uint8_t>(50, 50));
|
||||
|
||||
REQUIRE(synth.getRegionView(3)->pan == 0.3_a);
|
||||
REQUIRE(synth.getRegionView(3)->delay == 56);
|
||||
REQUIRE(synth.getRegionView(3)->keyRange == sfz::Range<uint8_t>(51, 51));
|
||||
REQUIRE(synth.getRegionView(3)->keyRange == Range<uint8_t>(51, 51));
|
||||
|
||||
REQUIRE(synth.getRegionView(4)->pan == -0.1_a);
|
||||
REQUIRE(synth.getRegionView(4)->delay == 47);
|
||||
REQUIRE(synth.getRegionView(4)->keyRange == sfz::Range<uint8_t>(40, 40));
|
||||
REQUIRE(synth.getRegionView(4)->keyRange == Range<uint8_t>(40, 40));
|
||||
|
||||
REQUIRE(synth.getRegionView(5)->pan == -0.1_a);
|
||||
REQUIRE(synth.getRegionView(5)->delay == 47);
|
||||
REQUIRE(synth.getRegionView(5)->keyRange == sfz::Range<uint8_t>(41, 41));
|
||||
REQUIRE(synth.getRegionView(5)->keyRange == Range<uint8_t>(41, 41));
|
||||
|
||||
REQUIRE(synth.getRegionView(6)->pan == -0.1_a);
|
||||
REQUIRE(synth.getRegionView(6)->delay == 36);
|
||||
REQUIRE(synth.getRegionView(6)->keyRange == sfz::Range<uint8_t>(30, 30));
|
||||
REQUIRE(synth.getRegionView(6)->keyRange == Range<uint8_t>(30, 30));
|
||||
|
||||
REQUIRE(synth.getRegionView(7)->pan == -0.1_a);
|
||||
REQUIRE(synth.getRegionView(7)->delay == 36);
|
||||
REQUIRE(synth.getRegionView(7)->keyRange == sfz::Range<uint8_t>(31, 31));
|
||||
REQUIRE(synth.getRegionView(7)->keyRange == Range<uint8_t>(31, 31));
|
||||
}
|
||||
|
||||
TEST_CASE("[Files] Reloading files")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/basic_hierarchy.sfz");
|
||||
REQUIRE(synth.getNumRegions() == 8);
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/basic_hierarchy.sfz");
|
||||
|
|
@ -202,7 +203,7 @@ TEST_CASE("[Files] Reloading files")
|
|||
TEST_CASE("[Files] Full hierarchy with antislashes")
|
||||
{
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/basic_hierarchy.sfz");
|
||||
REQUIRE(synth.getNumRegions() == 8);
|
||||
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "Regions/dummy.wav");
|
||||
|
|
@ -216,7 +217,7 @@ TEST_CASE("[Files] Full hierarchy with antislashes")
|
|||
}
|
||||
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/basic_hierarchy_antislash.sfz");
|
||||
REQUIRE(synth.getNumRegions() == 8);
|
||||
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "Regions/dummy.wav");
|
||||
|
|
@ -232,19 +233,19 @@ TEST_CASE("[Files] Full hierarchy with antislashes")
|
|||
|
||||
TEST_CASE("[Files] Pizz basic")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/SpecificBugs/MeatBassPizz/Programs/pizz.sfz");
|
||||
REQUIRE(synth.getNumRegions() == 4);
|
||||
for (int i = 0; i < synth.getNumRegions(); ++i) {
|
||||
REQUIRE(synth.getRegionView(i)->keyRange == sfz::Range<uint8_t>(12, 22));
|
||||
REQUIRE(synth.getRegionView(i)->velocityRange == sfz::Range<float>(97_norm, 127_norm));
|
||||
REQUIRE(synth.getRegionView(i)->keyRange == Range<uint8_t>(12, 22));
|
||||
REQUIRE(synth.getRegionView(i)->velocityRange == Range<float>(97_norm, 127_norm));
|
||||
REQUIRE(synth.getRegionView(i)->pitchKeycenter == 21);
|
||||
REQUIRE(synth.getRegionView(i)->ccConditions.getWithDefault(107) == sfz::Range<float>(0_norm, 13_norm));
|
||||
REQUIRE(synth.getRegionView(i)->ccConditions.getWithDefault(107) == Range<float>(0_norm, 13_norm));
|
||||
}
|
||||
REQUIRE(synth.getRegionView(0)->randRange == sfz::Range<float>(0, 0.25));
|
||||
REQUIRE(synth.getRegionView(1)->randRange == sfz::Range<float>(0.25, 0.5));
|
||||
REQUIRE(synth.getRegionView(2)->randRange == sfz::Range<float>(0.5, 0.75));
|
||||
REQUIRE(synth.getRegionView(3)->randRange == sfz::Range<float>(0.75, 1.0));
|
||||
REQUIRE(synth.getRegionView(0)->randRange == Range<float>(0, 0.25));
|
||||
REQUIRE(synth.getRegionView(1)->randRange == Range<float>(0.25, 0.5));
|
||||
REQUIRE(synth.getRegionView(2)->randRange == Range<float>(0.5, 0.75));
|
||||
REQUIRE(synth.getRegionView(3)->randRange == Range<float>(0.75, 1.0));
|
||||
REQUIRE(synth.getRegionView(0)->sampleId.filename() == R"(../Samples/pizz/a0_vl4_rr1.wav)");
|
||||
REQUIRE(synth.getRegionView(1)->sampleId.filename() == R"(../Samples/pizz/a0_vl4_rr2.wav)");
|
||||
REQUIRE(synth.getRegionView(2)->sampleId.filename() == R"(../Samples/pizz/a0_vl4_rr3.wav)");
|
||||
|
|
@ -253,7 +254,7 @@ TEST_CASE("[Files] Pizz basic")
|
|||
|
||||
TEST_CASE("[Files] Channels (channels.sfz)")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/channels.sfz");
|
||||
REQUIRE(synth.getNumRegions() == 2);
|
||||
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "mono_sample.wav");
|
||||
|
|
@ -264,7 +265,7 @@ TEST_CASE("[Files] Channels (channels.sfz)")
|
|||
|
||||
TEST_CASE("[Files] Channels (channels_multi.sfz)")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/channels_multi.sfz");
|
||||
REQUIRE(synth.getNumRegions() == 6);
|
||||
|
||||
|
|
@ -301,7 +302,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)")
|
|||
|
||||
TEST_CASE("[Files] sw_default")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/sw_default.sfz");
|
||||
REQUIRE( synth.getNumRegions() == 4 );
|
||||
REQUIRE( !synth.getRegionView(0)->isSwitchedOn() );
|
||||
|
|
@ -312,7 +313,7 @@ TEST_CASE("[Files] sw_default")
|
|||
|
||||
TEST_CASE("[Files] sw_default and playing with switches")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/sw_default.sfz");
|
||||
REQUIRE( synth.getNumRegions() == 4 );
|
||||
REQUIRE( !synth.getRegionView(0)->isSwitchedOn() );
|
||||
|
|
@ -341,7 +342,7 @@ TEST_CASE("[Files] sw_default and playing with switches")
|
|||
|
||||
TEST_CASE("[Files] wrong (overlapping) replacement for defines")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/SpecificBugs/wrong-replacements.sfz");
|
||||
|
||||
REQUIRE( synth.getNumRegions() == 3 );
|
||||
|
|
@ -355,14 +356,14 @@ TEST_CASE("[Files] wrong (overlapping) replacement for defines")
|
|||
|
||||
REQUIRE( synth.getRegionView(1)->keyRange.getStart() == 57 );
|
||||
REQUIRE( synth.getRegionView(1)->keyRange.getEnd() == 57 );
|
||||
REQUIRE(!synth.getRegionView(2)->amplitudeCC.empty());
|
||||
REQUIRE(synth.getRegionView(2)->amplitudeCC.contains(10));
|
||||
REQUIRE(synth.getRegionView(2)->amplitudeCC.getWithDefault(10).value == 34.0f);
|
||||
REQUIRE(!synth.getRegionView(2)->modifiers[Mod::amplitude].empty());
|
||||
REQUIRE(synth.getRegionView(2)->modifiers[Mod::amplitude].contains(10));
|
||||
REQUIRE(synth.getRegionView(2)->modifiers[Mod::amplitude].getWithDefault(10).value == 34.0f);
|
||||
}
|
||||
|
||||
TEST_CASE("[Files] Specific bug: relative path with backslashes")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/SpecificBugs/win_backslashes.sfz");
|
||||
REQUIRE(synth.getNumRegions() == 1);
|
||||
REQUIRE(synth.getRegionView(0)->sampleId.filename() == R"(Xylo/Subfolder/closedhat.wav)");
|
||||
|
|
@ -370,7 +371,7 @@ TEST_CASE("[Files] Specific bug: relative path with backslashes")
|
|||
|
||||
TEST_CASE("[Files] Default path")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/default_path.sfz");
|
||||
REQUIRE(synth.getNumRegions() == 4);
|
||||
REQUIRE(synth.getRegionView(0)->sampleId.filename() == R"(DefaultPath/SubPath1/sample1.wav)");
|
||||
|
|
@ -381,7 +382,7 @@ TEST_CASE("[Files] Default path")
|
|||
|
||||
TEST_CASE("[Files] Default path reset when calling loadSfzFile again")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/default_path.sfz");
|
||||
REQUIRE(synth.getNumRegions() == 4);
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/default_path_reset.sfz");
|
||||
|
|
@ -391,7 +392,7 @@ TEST_CASE("[Files] Default path reset when calling loadSfzFile again")
|
|||
|
||||
TEST_CASE("[Files] Default path is ignored for generators")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/default_path_generator.sfz");
|
||||
REQUIRE(synth.getNumRegions() == 1);
|
||||
REQUIRE(synth.getRegionView(0)->sampleId.filename() == R"(*sine)");
|
||||
|
|
@ -399,7 +400,7 @@ TEST_CASE("[Files] Default path is ignored for generators")
|
|||
|
||||
TEST_CASE("[Files] Set CC applies properly")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
const auto& midiState = synth.getResources().midiState;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/set_cc.sfz");
|
||||
REQUIRE(midiState.getCCValue(142) == 63_norm);
|
||||
|
|
@ -426,26 +427,26 @@ TEST_CASE("[Files] Set RealCC applies properly")
|
|||
|
||||
TEST_CASE("[Files] Note and octave offsets")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/note_offset.sfz");
|
||||
REQUIRE( synth.getNumRegions() == 7 );
|
||||
|
||||
REQUIRE( synth.getRegionView(0)->keyRange == sfz::Range<uint8_t>(64, 64) );
|
||||
REQUIRE(synth.getRegionView(0)->keyRange == Range<uint8_t>(64, 64));
|
||||
REQUIRE( synth.getRegionView(0)->pitchKeycenter == 64 );
|
||||
REQUIRE( synth.getRegionView(0)->keyswitchRange == sfz::Default::keyRange );
|
||||
REQUIRE( synth.getRegionView(0)->crossfadeKeyInRange == sfz::Default::crossfadeKeyInRange );
|
||||
REQUIRE( synth.getRegionView(0)->crossfadeKeyOutRange == sfz::Default::crossfadeKeyOutRange );
|
||||
REQUIRE(synth.getRegionView(0)->keyswitchRange == Default::keyRange);
|
||||
REQUIRE(synth.getRegionView(0)->crossfadeKeyInRange == Default::crossfadeKeyInRange);
|
||||
REQUIRE(synth.getRegionView(0)->crossfadeKeyOutRange == Default::crossfadeKeyOutRange);
|
||||
|
||||
REQUIRE( synth.getRegionView(1)->keyRange == sfz::Range<uint8_t>(51, 56) );
|
||||
REQUIRE(synth.getRegionView(1)->keyRange == Range<uint8_t>(51, 56));
|
||||
REQUIRE( synth.getRegionView(1)->pitchKeycenter == 51 );
|
||||
|
||||
REQUIRE( synth.getRegionView(2)->keyRange == sfz::Range<uint8_t>(41, 45) );
|
||||
REQUIRE(synth.getRegionView(2)->keyRange == Range<uint8_t>(41, 45));
|
||||
REQUIRE( synth.getRegionView(2)->pitchKeycenter == 41 );
|
||||
REQUIRE( synth.getRegionView(2)->crossfadeKeyInRange == sfz::Range<uint8_t>(37, 41) );
|
||||
REQUIRE( synth.getRegionView(2)->crossfadeKeyOutRange == sfz::Range<uint8_t>(45, 49) );
|
||||
REQUIRE(synth.getRegionView(2)->crossfadeKeyInRange == Range<uint8_t>(37, 41));
|
||||
REQUIRE(synth.getRegionView(2)->crossfadeKeyOutRange == Range<uint8_t>(45, 49));
|
||||
|
||||
REQUIRE( synth.getRegionView(3)->keyRange == sfz::Range<uint8_t>(62, 62) );
|
||||
REQUIRE( synth.getRegionView(3)->keyswitchRange == sfz::Range<uint8_t>(23, 27) );
|
||||
REQUIRE(synth.getRegionView(3)->keyRange == Range<uint8_t>(62, 62));
|
||||
REQUIRE(synth.getRegionView(3)->keyswitchRange == Range<uint8_t>(23, 27));
|
||||
REQUIRE( synth.getRegionView(3)->keyswitch );
|
||||
REQUIRE( *synth.getRegionView(3)->keyswitch == 24 );
|
||||
REQUIRE( synth.getRegionView(3)->keyswitchUp );
|
||||
|
|
@ -455,21 +456,21 @@ TEST_CASE("[Files] Note and octave offsets")
|
|||
REQUIRE( synth.getRegionView(3)->previousNote );
|
||||
REQUIRE( *synth.getRegionView(3)->previousNote == 61 );
|
||||
|
||||
REQUIRE( synth.getRegionView(4)->keyRange == sfz::Range<uint8_t>(76, 76) );
|
||||
REQUIRE(synth.getRegionView(4)->keyRange == Range<uint8_t>(76, 76));
|
||||
REQUIRE( synth.getRegionView(4)->pitchKeycenter == 76 );
|
||||
|
||||
REQUIRE( synth.getRegionView(5)->keyRange == sfz::Range<uint8_t>(50, 50) );
|
||||
REQUIRE(synth.getRegionView(5)->keyRange == Range<uint8_t>(50, 50));
|
||||
REQUIRE( synth.getRegionView(5)->pitchKeycenter == 50 );
|
||||
|
||||
REQUIRE( synth.getRegionView(6)->keyRange == sfz::Range<uint8_t>(50, 50) );
|
||||
REQUIRE(synth.getRegionView(6)->keyRange == Range<uint8_t>(50, 50));
|
||||
REQUIRE( synth.getRegionView(6)->pitchKeycenter == 50 );
|
||||
}
|
||||
|
||||
TEST_CASE("[Files] Off by with different delays")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.setSamplesPerBlock(256);
|
||||
sfz::AudioBuffer<float> buffer(2, 256);
|
||||
AudioBuffer<float> buffer(2, 256);
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/off_by.sfz");
|
||||
REQUIRE( synth.getNumRegions() == 4 );
|
||||
synth.noteOn(0, 63, 63);
|
||||
|
|
@ -484,7 +485,7 @@ TEST_CASE("[Files] Off by with different delays")
|
|||
|
||||
TEST_CASE("[Files] Off by with the same delays")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.setSamplesPerBlock(256);
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/off_by.sfz");
|
||||
REQUIRE( synth.getNumRegions() == 4 );
|
||||
|
|
@ -499,7 +500,7 @@ TEST_CASE("[Files] Off by with the same delays")
|
|||
|
||||
TEST_CASE("[Files] Off by with the same notes at the same time")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.setSamplesPerBlock(256);
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/off_by.sfz");
|
||||
REQUIRE( synth.getNumRegions() == 4 );
|
||||
|
|
@ -507,7 +508,7 @@ TEST_CASE("[Files] Off by with the same notes at the same time")
|
|||
REQUIRE( synth.getNumActiveVoices() == 2 );
|
||||
synth.noteOn(0, 65, 63);
|
||||
REQUIRE( synth.getNumActiveVoices() == 4 );
|
||||
sfz::AudioBuffer<float> buffer { 2, 256 };
|
||||
AudioBuffer<float> buffer { 2, 256 };
|
||||
synth.renderBlock(buffer);
|
||||
synth.noteOn(0, 65, 63);
|
||||
synth.renderBlock(buffer);
|
||||
|
|
@ -516,7 +517,7 @@ TEST_CASE("[Files] Off by with the same notes at the same time")
|
|||
|
||||
TEST_CASE("[Files] Off modes")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.setSamplesPerBlock(256);
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/off_mode.sfz");
|
||||
REQUIRE( synth.getNumRegions() == 3 );
|
||||
|
|
@ -532,7 +533,7 @@ TEST_CASE("[Files] Off modes")
|
|||
synth.getVoiceView(0) ;
|
||||
synth.noteOn(100, 63, 63);
|
||||
REQUIRE( synth.getNumActiveVoices() == 3 );
|
||||
sfz::AudioBuffer<float> buffer { 2, 256 };
|
||||
AudioBuffer<float> buffer { 2, 256 };
|
||||
synth.renderBlock(buffer);
|
||||
REQUIRE( synth.getNumActiveVoices() == 2 );
|
||||
REQUIRE( fastVoice->isFree() );
|
||||
|
|
@ -541,7 +542,7 @@ TEST_CASE("[Files] Off modes")
|
|||
|
||||
TEST_CASE("[Files] Looped regions taken from files and possibly overriden")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.setSamplesPerBlock(256);
|
||||
synth.setSampleRate(44100);
|
||||
synth.loadSfzFile(fs::current_path() / "tests/TestFiles/looped_regions.sfz");
|
||||
|
|
@ -550,9 +551,9 @@ TEST_CASE("[Files] Looped regions taken from files and possibly overriden")
|
|||
REQUIRE( synth.getRegionView(1)->loopMode == SfzLoopMode::no_loop );
|
||||
REQUIRE( synth.getRegionView(2)->loopMode == SfzLoopMode::loop_continuous );
|
||||
|
||||
REQUIRE( synth.getRegionView(0)->loopRange == sfz::Range<uint32_t>{ 77554, 186581 } );
|
||||
REQUIRE( synth.getRegionView(1)->loopRange == sfz::Range<uint32_t>{ 77554, 186581 } );
|
||||
REQUIRE( synth.getRegionView(2)->loopRange == sfz::Range<uint32_t>{ 4, 124 } );
|
||||
REQUIRE(synth.getRegionView(0)->loopRange == Range<uint32_t> { 77554, 186581 });
|
||||
REQUIRE(synth.getRegionView(1)->loopRange == Range<uint32_t> { 77554, 186581 });
|
||||
REQUIRE(synth.getRegionView(2)->loopRange == Range<uint32_t> { 4, 124 });
|
||||
}
|
||||
|
||||
TEST_CASE("[Files] Case sentitiveness")
|
||||
|
|
@ -568,7 +569,7 @@ TEST_CASE("[Files] Case sentitiveness")
|
|||
#endif
|
||||
|
||||
if (caseSensitiveFs) {
|
||||
sfz::Synth synth;
|
||||
Synth synth;
|
||||
synth.loadSfzFile(sfzFilePath);
|
||||
REQUIRE(synth.getNumRegions() == 4);
|
||||
REQUIRE(synth.getRegionView(0)->sampleId.filename() == "dummy1.wav");
|
||||
|
|
@ -580,8 +581,8 @@ TEST_CASE("[Files] Case sentitiveness")
|
|||
|
||||
TEST_CASE("[Files] Empty file")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
sfz::Parser& parser = synth.getParser();
|
||||
Synth synth;
|
||||
Parser& parser = synth.getParser();
|
||||
REQUIRE(!synth.loadSfzFile(""));
|
||||
REQUIRE(parser.getIncludedFiles().empty());
|
||||
REQUIRE(!synth.loadSfzFile({}));
|
||||
|
|
|
|||
|
|
@ -10,11 +10,12 @@
|
|||
#include "catch2/catch.hpp"
|
||||
using namespace Catch::literals;
|
||||
using namespace sfz::literals;
|
||||
using namespace sfz;
|
||||
|
||||
TEST_CASE("[Region] Parsing opcodes")
|
||||
{
|
||||
sfz::MidiState midiState;
|
||||
sfz::Region region { 0, midiState };
|
||||
MidiState midiState;
|
||||
Region region { 0, midiState };
|
||||
|
||||
SECTION("sample")
|
||||
{
|
||||
|
|
@ -132,36 +133,36 @@ TEST_CASE("[Region] Parsing opcodes")
|
|||
|
||||
SECTION("loop_end")
|
||||
{
|
||||
REQUIRE(region.loopRange == sfz::Range<uint32_t>(0, 4294967295));
|
||||
REQUIRE(region.loopRange == Range<uint32_t>(0, 4294967295));
|
||||
region.parseOpcode({ "loop_end", "184" });
|
||||
REQUIRE(region.loopRange == sfz::Range<uint32_t>(0, 184));
|
||||
REQUIRE(region.loopRange == Range<uint32_t>(0, 184));
|
||||
region.parseOpcode({ "loop_end", "-1" });
|
||||
REQUIRE(region.loopRange == sfz::Range<uint32_t>(0, 0));
|
||||
REQUIRE(region.loopRange == Range<uint32_t>(0, 0));
|
||||
}
|
||||
|
||||
SECTION("loop_start")
|
||||
{
|
||||
region.parseOpcode({ "loop_start", "184" });
|
||||
REQUIRE(region.loopRange == sfz::Range<uint32_t>(184, 4294967295));
|
||||
REQUIRE(region.loopRange == Range<uint32_t>(184, 4294967295));
|
||||
region.parseOpcode({ "loop_start", "-1" });
|
||||
REQUIRE(region.loopRange == sfz::Range<uint32_t>(0, 4294967295));
|
||||
REQUIRE(region.loopRange == Range<uint32_t>(0, 4294967295));
|
||||
}
|
||||
|
||||
SECTION("loopend")
|
||||
{
|
||||
REQUIRE(region.loopRange == sfz::Range<uint32_t>(0, 4294967295));
|
||||
REQUIRE(region.loopRange == Range<uint32_t>(0, 4294967295));
|
||||
region.parseOpcode({ "loopend", "184" });
|
||||
REQUIRE(region.loopRange == sfz::Range<uint32_t>(0, 184));
|
||||
REQUIRE(region.loopRange == Range<uint32_t>(0, 184));
|
||||
region.parseOpcode({ "loopend", "-1" });
|
||||
REQUIRE(region.loopRange == sfz::Range<uint32_t>(0, 0));
|
||||
REQUIRE(region.loopRange == Range<uint32_t>(0, 0));
|
||||
}
|
||||
|
||||
SECTION("loopstart")
|
||||
{
|
||||
region.parseOpcode({ "loopstart", "184" });
|
||||
REQUIRE(region.loopRange == sfz::Range<uint32_t>(184, 4294967295));
|
||||
REQUIRE(region.loopRange == Range<uint32_t>(184, 4294967295));
|
||||
region.parseOpcode({ "loopstart", "-1" });
|
||||
REQUIRE(region.loopRange == sfz::Range<uint32_t>(0, 4294967295));
|
||||
REQUIRE(region.loopRange == Range<uint32_t>(0, 4294967295));
|
||||
}
|
||||
|
||||
SECTION("group")
|
||||
|
|
@ -194,87 +195,87 @@ TEST_CASE("[Region] Parsing opcodes")
|
|||
|
||||
SECTION("lokey, hikey, and key")
|
||||
{
|
||||
REQUIRE(region.keyRange == sfz::Range<uint8_t>(0, 127));
|
||||
REQUIRE(region.keyRange == Range<uint8_t>(0, 127));
|
||||
region.parseOpcode({ "lokey", "37" });
|
||||
REQUIRE(region.keyRange == sfz::Range<uint8_t>(37, 127));
|
||||
REQUIRE(region.keyRange == Range<uint8_t>(37, 127));
|
||||
region.parseOpcode({ "lokey", "c4" });
|
||||
REQUIRE(region.keyRange == sfz::Range<uint8_t>(60, 127));
|
||||
REQUIRE(region.keyRange == Range<uint8_t>(60, 127));
|
||||
region.parseOpcode({ "lokey", "128" });
|
||||
REQUIRE(region.keyRange == sfz::Range<uint8_t>(127, 127));
|
||||
REQUIRE(region.keyRange == Range<uint8_t>(127, 127));
|
||||
region.parseOpcode({ "lokey", "-3" });
|
||||
REQUIRE(region.keyRange == sfz::Range<uint8_t>(0, 127));
|
||||
REQUIRE(region.keyRange == Range<uint8_t>(0, 127));
|
||||
region.parseOpcode({ "hikey", "65" });
|
||||
REQUIRE(region.keyRange == sfz::Range<uint8_t>(0, 65));
|
||||
REQUIRE(region.keyRange == Range<uint8_t>(0, 65));
|
||||
region.parseOpcode({ "hikey", "c4" });
|
||||
REQUIRE(region.keyRange == sfz::Range<uint8_t>(0, 60));
|
||||
REQUIRE(region.keyRange == Range<uint8_t>(0, 60));
|
||||
region.parseOpcode({ "hikey", "-1" });
|
||||
REQUIRE(region.keyRange == sfz::Range<uint8_t>(0, 0));
|
||||
REQUIRE(region.keyRange == Range<uint8_t>(0, 0));
|
||||
region.parseOpcode({ "hikey", "128" });
|
||||
REQUIRE(region.keyRange == sfz::Range<uint8_t>(0, 127));
|
||||
REQUIRE(region.keyRange == Range<uint8_t>(0, 127));
|
||||
region.parseOpcode({ "key", "26" });
|
||||
REQUIRE(region.keyRange == sfz::Range<uint8_t>(26, 26));
|
||||
REQUIRE(region.keyRange == Range<uint8_t>(26, 26));
|
||||
REQUIRE(region.pitchKeycenter == 26);
|
||||
region.parseOpcode({ "key", "-26" });
|
||||
REQUIRE(region.keyRange == sfz::Range<uint8_t>(0, 0));
|
||||
REQUIRE(region.keyRange == Range<uint8_t>(0, 0));
|
||||
REQUIRE(region.pitchKeycenter == 0);
|
||||
region.parseOpcode({ "key", "234" });
|
||||
REQUIRE(region.keyRange == sfz::Range<uint8_t>(127, 127));
|
||||
REQUIRE(region.keyRange == Range<uint8_t>(127, 127));
|
||||
REQUIRE(region.pitchKeycenter == 127);
|
||||
region.parseOpcode({ "key", "c4" });
|
||||
REQUIRE(region.keyRange == sfz::Range<uint8_t>(60, 60));
|
||||
REQUIRE(region.keyRange == Range<uint8_t>(60, 60));
|
||||
REQUIRE(region.pitchKeycenter == 60);
|
||||
}
|
||||
|
||||
SECTION("lovel, hivel")
|
||||
{
|
||||
REQUIRE(region.velocityRange == sfz::Range<float>(0_norm, 127_norm));
|
||||
REQUIRE(region.velocityRange == Range<float>(0_norm, 127_norm));
|
||||
region.parseOpcode({ "lovel", "37" });
|
||||
REQUIRE(region.velocityRange == sfz::Range<float>(37_norm, 127_norm));
|
||||
REQUIRE(region.velocityRange == Range<float>(37_norm, 127_norm));
|
||||
region.parseOpcode({ "lovel", "128" });
|
||||
REQUIRE(region.velocityRange == sfz::Range<float>(127_norm, 127_norm));
|
||||
REQUIRE(region.velocityRange == Range<float>(127_norm, 127_norm));
|
||||
region.parseOpcode({ "lovel", "-3" });
|
||||
REQUIRE(region.velocityRange == sfz::Range<float>(0_norm, 127_norm));
|
||||
REQUIRE(region.velocityRange == Range<float>(0_norm, 127_norm));
|
||||
region.parseOpcode({ "hivel", "65" });
|
||||
REQUIRE(region.velocityRange == sfz::Range<float>(0_norm, 65_norm));
|
||||
REQUIRE(region.velocityRange == Range<float>(0_norm, 65_norm));
|
||||
region.parseOpcode({ "hivel", "-1" });
|
||||
REQUIRE(region.velocityRange == sfz::Range<float>(0_norm, 0_norm));
|
||||
REQUIRE(region.velocityRange == Range<float>(0_norm, 0_norm));
|
||||
region.parseOpcode({ "hivel", "128" });
|
||||
REQUIRE(region.velocityRange == sfz::Range<float>(0_norm, 127_norm));
|
||||
REQUIRE(region.velocityRange == Range<float>(0_norm, 127_norm));
|
||||
}
|
||||
|
||||
SECTION("lobend, hibend")
|
||||
{
|
||||
REQUIRE(region.bendRange == sfz::Range<float>(-1.0f, 1.0f));
|
||||
REQUIRE(region.bendRange == Range<float>(-1.0f, 1.0f));
|
||||
region.parseOpcode({ "lobend", "400" });
|
||||
REQUIRE(region.bendRange.getStart() == Approx(sfz::normalizeBend(400)));
|
||||
REQUIRE(region.bendRange.getStart() == Approx(normalizeBend(400)));
|
||||
REQUIRE(region.bendRange.getEnd() == 1.0_a);
|
||||
region.parseOpcode({ "lobend", "-128" });
|
||||
REQUIRE(region.bendRange.getStart() == Approx(sfz::normalizeBend(-128)));
|
||||
REQUIRE(region.bendRange.getStart() == Approx(normalizeBend(-128)));
|
||||
REQUIRE(region.bendRange.getEnd() == 1.0_a);
|
||||
region.parseOpcode({ "lobend", "-10000" });
|
||||
REQUIRE(region.bendRange == sfz::Range<float>(-1.0f, 1.0f));
|
||||
REQUIRE(region.bendRange == Range<float>(-1.0f, 1.0f));
|
||||
region.parseOpcode({ "hibend", "13" });
|
||||
REQUIRE(region.bendRange.getStart() == -1.0_a);
|
||||
REQUIRE(region.bendRange.getEnd() == Approx(sfz::normalizeBend(13)));
|
||||
REQUIRE(region.bendRange.getEnd() == Approx(normalizeBend(13)));
|
||||
region.parseOpcode({ "hibend", "-1" });
|
||||
REQUIRE(region.bendRange.getStart() == -1.0_a);
|
||||
REQUIRE(region.bendRange.getEnd() == Approx(sfz::normalizeBend(-1)));
|
||||
REQUIRE(region.bendRange.getEnd() == Approx(normalizeBend(-1)));
|
||||
region.parseOpcode({ "hibend", "10000" });
|
||||
REQUIRE(region.bendRange == sfz::Range<float>(-1.0f, 1.0f));
|
||||
REQUIRE(region.bendRange == Range<float>(-1.0f, 1.0f));
|
||||
}
|
||||
|
||||
SECTION("locc, hicc")
|
||||
{
|
||||
REQUIRE(region.ccConditions.getWithDefault(0) == sfz::Range<float>(0_norm, 127_norm));
|
||||
REQUIRE(region.ccConditions[127] == sfz::Range<float>(0_norm, 127_norm));
|
||||
REQUIRE(region.ccConditions.getWithDefault(0) == Range<float>(0_norm, 127_norm));
|
||||
REQUIRE(region.ccConditions[127] == Range<float>(0_norm, 127_norm));
|
||||
region.parseOpcode({ "locc6", "4" });
|
||||
REQUIRE(region.ccConditions[6] == sfz::Range<float>(4_norm, 127_norm));
|
||||
REQUIRE(region.ccConditions[6] == Range<float>(4_norm, 127_norm));
|
||||
region.parseOpcode({ "locc12", "-128" });
|
||||
REQUIRE(region.ccConditions[12] == sfz::Range<float>(0_norm, 127_norm));
|
||||
REQUIRE(region.ccConditions[12] == Range<float>(0_norm, 127_norm));
|
||||
region.parseOpcode({ "hicc65", "39" });
|
||||
REQUIRE(region.ccConditions[65] == sfz::Range<float>(0_norm, 39_norm));
|
||||
REQUIRE(region.ccConditions[65] == Range<float>(0_norm, 39_norm));
|
||||
region.parseOpcode({ "hicc127", "135" });
|
||||
REQUIRE(region.ccConditions[127] == sfz::Range<float>(0_norm, 127_norm));
|
||||
REQUIRE(region.ccConditions[127] == Range<float>(0_norm, 127_norm));
|
||||
}
|
||||
|
||||
SECTION("lohdcc, hihdcc")
|
||||
|
|
@ -307,19 +308,19 @@ TEST_CASE("[Region] Parsing opcodes")
|
|||
|
||||
SECTION("sw_lokey, sw_hikey")
|
||||
{
|
||||
REQUIRE(region.keyswitchRange == sfz::Range<uint8_t>(0, 127));
|
||||
REQUIRE(region.keyswitchRange == Range<uint8_t>(0, 127));
|
||||
region.parseOpcode({ "sw_lokey", "4" });
|
||||
REQUIRE(region.keyswitchRange == sfz::Range<uint8_t>(4, 127));
|
||||
REQUIRE(region.keyswitchRange == Range<uint8_t>(4, 127));
|
||||
region.parseOpcode({ "sw_lokey", "128" });
|
||||
REQUIRE(region.keyswitchRange == sfz::Range<uint8_t>(127, 127));
|
||||
REQUIRE(region.keyswitchRange == Range<uint8_t>(127, 127));
|
||||
region.parseOpcode({ "sw_lokey", "0" });
|
||||
REQUIRE(region.keyswitchRange == sfz::Range<uint8_t>(0, 127));
|
||||
REQUIRE(region.keyswitchRange == Range<uint8_t>(0, 127));
|
||||
region.parseOpcode({ "sw_hikey", "39" });
|
||||
REQUIRE(region.keyswitchRange == sfz::Range<uint8_t>(0, 39));
|
||||
REQUIRE(region.keyswitchRange == Range<uint8_t>(0, 39));
|
||||
region.parseOpcode({ "sw_hikey", "135" });
|
||||
REQUIRE(region.keyswitchRange == sfz::Range<uint8_t>(0, 127));
|
||||
REQUIRE(region.keyswitchRange == Range<uint8_t>(0, 127));
|
||||
region.parseOpcode({ "sw_hikey", "-1" });
|
||||
REQUIRE(region.keyswitchRange == sfz::Range<uint8_t>(0, 0));
|
||||
REQUIRE(region.keyswitchRange == Range<uint8_t>(0, 0));
|
||||
}
|
||||
|
||||
SECTION("sw_label")
|
||||
|
|
@ -398,53 +399,53 @@ TEST_CASE("[Region] Parsing opcodes")
|
|||
|
||||
SECTION("lochanaft, hichanaft")
|
||||
{
|
||||
REQUIRE(region.aftertouchRange == sfz::Range<uint8_t>(0, 127));
|
||||
REQUIRE(region.aftertouchRange == Range<uint8_t>(0, 127));
|
||||
region.parseOpcode({ "lochanaft", "4" });
|
||||
REQUIRE(region.aftertouchRange == sfz::Range<uint8_t>(4, 127));
|
||||
REQUIRE(region.aftertouchRange == Range<uint8_t>(4, 127));
|
||||
region.parseOpcode({ "lochanaft", "128" });
|
||||
REQUIRE(region.aftertouchRange == sfz::Range<uint8_t>(127, 127));
|
||||
REQUIRE(region.aftertouchRange == Range<uint8_t>(127, 127));
|
||||
region.parseOpcode({ "lochanaft", "0" });
|
||||
REQUIRE(region.aftertouchRange == sfz::Range<uint8_t>(0, 127));
|
||||
REQUIRE(region.aftertouchRange == Range<uint8_t>(0, 127));
|
||||
region.parseOpcode({ "hichanaft", "39" });
|
||||
REQUIRE(region.aftertouchRange == sfz::Range<uint8_t>(0, 39));
|
||||
REQUIRE(region.aftertouchRange == Range<uint8_t>(0, 39));
|
||||
region.parseOpcode({ "hichanaft", "135" });
|
||||
REQUIRE(region.aftertouchRange == sfz::Range<uint8_t>(0, 127));
|
||||
REQUIRE(region.aftertouchRange == Range<uint8_t>(0, 127));
|
||||
region.parseOpcode({ "hichanaft", "-1" });
|
||||
REQUIRE(region.aftertouchRange == sfz::Range<uint8_t>(0, 0));
|
||||
REQUIRE(region.aftertouchRange == Range<uint8_t>(0, 0));
|
||||
}
|
||||
|
||||
SECTION("lobpm, hibpm")
|
||||
{
|
||||
REQUIRE(region.bpmRange == sfz::Range<float>(0, 500));
|
||||
REQUIRE(region.bpmRange == Range<float>(0, 500));
|
||||
region.parseOpcode({ "lobpm", "47.5" });
|
||||
REQUIRE(region.bpmRange == sfz::Range<float>(47.5, 500));
|
||||
REQUIRE(region.bpmRange == Range<float>(47.5, 500));
|
||||
region.parseOpcode({ "lobpm", "594" });
|
||||
REQUIRE(region.bpmRange == sfz::Range<float>(500, 500));
|
||||
REQUIRE(region.bpmRange == Range<float>(500, 500));
|
||||
region.parseOpcode({ "lobpm", "0" });
|
||||
REQUIRE(region.bpmRange == sfz::Range<float>(0, 500));
|
||||
REQUIRE(region.bpmRange == Range<float>(0, 500));
|
||||
region.parseOpcode({ "hibpm", "78" });
|
||||
REQUIRE(region.bpmRange == sfz::Range<float>(0, 78));
|
||||
REQUIRE(region.bpmRange == Range<float>(0, 78));
|
||||
region.parseOpcode({ "hibpm", "895.4" });
|
||||
REQUIRE(region.bpmRange == sfz::Range<float>(0, 500));
|
||||
REQUIRE(region.bpmRange == Range<float>(0, 500));
|
||||
region.parseOpcode({ "hibpm", "-1" });
|
||||
REQUIRE(region.bpmRange == sfz::Range<float>(0, 0));
|
||||
REQUIRE(region.bpmRange == Range<float>(0, 0));
|
||||
}
|
||||
|
||||
SECTION("lorand, hirand")
|
||||
{
|
||||
REQUIRE(region.randRange == sfz::Range<float>(0, 1));
|
||||
REQUIRE(region.randRange == Range<float>(0, 1));
|
||||
region.parseOpcode({ "lorand", "0.5" });
|
||||
REQUIRE(region.randRange == sfz::Range<float>(0.5, 1));
|
||||
REQUIRE(region.randRange == Range<float>(0.5, 1));
|
||||
region.parseOpcode({ "lorand", "4" });
|
||||
REQUIRE(region.randRange == sfz::Range<float>(1, 1));
|
||||
REQUIRE(region.randRange == Range<float>(1, 1));
|
||||
region.parseOpcode({ "lorand", "0" });
|
||||
REQUIRE(region.randRange == sfz::Range<float>(0, 1));
|
||||
REQUIRE(region.randRange == Range<float>(0, 1));
|
||||
region.parseOpcode({ "hirand", "39" });
|
||||
REQUIRE(region.randRange == sfz::Range<float>(0, 1));
|
||||
REQUIRE(region.randRange == Range<float>(0, 1));
|
||||
region.parseOpcode({ "hirand", "0.7" });
|
||||
REQUIRE(region.randRange == sfz::Range<float>(0, 0.7f));
|
||||
REQUIRE(region.randRange == Range<float>(0, 0.7f));
|
||||
region.parseOpcode({ "hirand", "-1" });
|
||||
REQUIRE(region.randRange == sfz::Range<float>(0, 0));
|
||||
REQUIRE(region.randRange == Range<float>(0, 0));
|
||||
}
|
||||
|
||||
SECTION("seq_length")
|
||||
|
|
@ -489,10 +490,10 @@ TEST_CASE("[Region] Parsing opcodes")
|
|||
}
|
||||
region.parseOpcode({ "on_locc45", "15" });
|
||||
REQUIRE(region.ccTriggers.contains(45));
|
||||
REQUIRE(region.ccTriggers[45] == sfz::Range<float>(15_norm, 127_norm));
|
||||
REQUIRE(region.ccTriggers[45] == Range<float>(15_norm, 127_norm));
|
||||
region.parseOpcode({ "on_hicc4", "47" });
|
||||
REQUIRE(region.ccTriggers.contains(45));
|
||||
REQUIRE(region.ccTriggers[4] == sfz::Range<float>(0_norm, 47_norm));
|
||||
REQUIRE(region.ccTriggers[4] == Range<float>(0_norm, 47_norm));
|
||||
}
|
||||
|
||||
SECTION("on_lohdcc, on_hihdcc")
|
||||
|
|
@ -540,28 +541,28 @@ TEST_CASE("[Region] Parsing opcodes")
|
|||
|
||||
SECTION("pan_oncc")
|
||||
{
|
||||
REQUIRE(region.panCC.empty());
|
||||
REQUIRE(region.modifiers[Mod::pan].empty());
|
||||
region.parseOpcode({ "pan_oncc45", "4.2" });
|
||||
REQUIRE(region.panCC.contains(45));
|
||||
REQUIRE(region.panCC[45].value == 4.2_a);
|
||||
REQUIRE(region.modifiers[Mod::pan].contains(45));
|
||||
REQUIRE(region.modifiers[Mod::pan][45].value == 4.2_a);
|
||||
region.parseOpcode({ "pan_curvecc17", "18" });
|
||||
REQUIRE(region.panCC[17].curve == 18);
|
||||
REQUIRE(region.modifiers[Mod::pan][17].curve == 18);
|
||||
region.parseOpcode({ "pan_curvecc17", "15482" });
|
||||
REQUIRE(region.panCC[17].curve == 255);
|
||||
REQUIRE(region.modifiers[Mod::pan][17].curve == 255);
|
||||
region.parseOpcode({ "pan_curvecc17", "-2" });
|
||||
REQUIRE(region.panCC[17].curve == 0);
|
||||
REQUIRE(region.modifiers[Mod::pan][17].curve == 0);
|
||||
region.parseOpcode({ "pan_smoothcc14", "85" });
|
||||
REQUIRE(region.panCC[14].smooth == 85);
|
||||
REQUIRE(region.modifiers[Mod::pan][14].smooth == 85);
|
||||
region.parseOpcode({ "pan_smoothcc14", "15482" });
|
||||
REQUIRE(region.panCC[14].smooth == 127);
|
||||
REQUIRE(region.modifiers[Mod::pan][14].smooth == 100);
|
||||
region.parseOpcode({ "pan_smoothcc14", "-2" });
|
||||
REQUIRE(region.panCC[14].smooth == 0);
|
||||
REQUIRE(region.modifiers[Mod::pan][14].smooth == 0);
|
||||
region.parseOpcode({ "pan_stepcc120", "24" });
|
||||
REQUIRE(region.panCC[120].step == 24.0_a);
|
||||
REQUIRE(region.modifiers[Mod::pan][120].step == 24.0_a);
|
||||
region.parseOpcode({ "pan_stepcc120", "15482" });
|
||||
REQUIRE(region.panCC[120].step == 200.0_a);
|
||||
REQUIRE(region.modifiers[Mod::pan][120].step == 200.0_a);
|
||||
region.parseOpcode({ "pan_stepcc120", "-2" });
|
||||
REQUIRE(region.panCC[120].step == 0.0f);
|
||||
REQUIRE(region.modifiers[Mod::pan][120].step == 0.0f);
|
||||
}
|
||||
|
||||
SECTION("width")
|
||||
|
|
@ -579,28 +580,28 @@ TEST_CASE("[Region] Parsing opcodes")
|
|||
|
||||
SECTION("width_oncc")
|
||||
{
|
||||
REQUIRE(region.widthCC.empty());
|
||||
REQUIRE(region.modifiers[Mod::width].empty());
|
||||
region.parseOpcode({ "width_oncc45", "4.2" });
|
||||
REQUIRE(region.widthCC.contains(45));
|
||||
REQUIRE(region.widthCC[45].value == 4.2_a);
|
||||
REQUIRE(region.modifiers[Mod::width].contains(45));
|
||||
REQUIRE(region.modifiers[Mod::width][45].value == 4.2_a);
|
||||
region.parseOpcode({ "width_curvecc17", "18" });
|
||||
REQUIRE(region.widthCC[17].curve == 18);
|
||||
REQUIRE(region.modifiers[Mod::width][17].curve == 18);
|
||||
region.parseOpcode({ "width_curvecc17", "15482" });
|
||||
REQUIRE(region.widthCC[17].curve == 255);
|
||||
REQUIRE(region.modifiers[Mod::width][17].curve == 255);
|
||||
region.parseOpcode({ "width_curvecc17", "-2" });
|
||||
REQUIRE(region.widthCC[17].curve == 0);
|
||||
REQUIRE(region.modifiers[Mod::width][17].curve == 0);
|
||||
region.parseOpcode({ "width_smoothcc14", "85" });
|
||||
REQUIRE(region.widthCC[14].smooth == 85);
|
||||
REQUIRE(region.modifiers[Mod::width][14].smooth == 85);
|
||||
region.parseOpcode({ "width_smoothcc14", "15482" });
|
||||
REQUIRE(region.widthCC[14].smooth == 127);
|
||||
REQUIRE(region.modifiers[Mod::width][14].smooth == 100);
|
||||
region.parseOpcode({ "width_smoothcc14", "-2" });
|
||||
REQUIRE(region.widthCC[14].smooth == 0);
|
||||
REQUIRE(region.modifiers[Mod::width][14].smooth == 0);
|
||||
region.parseOpcode({ "width_stepcc120", "24" });
|
||||
REQUIRE(region.widthCC[120].step == 24.0_a);
|
||||
REQUIRE(region.modifiers[Mod::width][120].step == 24.0_a);
|
||||
region.parseOpcode({ "width_stepcc120", "15482" });
|
||||
REQUIRE(region.widthCC[120].step == 200.0_a);
|
||||
REQUIRE(region.modifiers[Mod::width][120].step == 200.0_a);
|
||||
region.parseOpcode({ "width_stepcc120", "-20" });
|
||||
REQUIRE(region.widthCC[120].step == 0.0f);
|
||||
REQUIRE(region.modifiers[Mod::width][120].step == 0.0f);
|
||||
}
|
||||
|
||||
SECTION("position")
|
||||
|
|
@ -618,28 +619,28 @@ TEST_CASE("[Region] Parsing opcodes")
|
|||
|
||||
SECTION("position_oncc")
|
||||
{
|
||||
REQUIRE(region.positionCC.empty());
|
||||
REQUIRE(region.modifiers[Mod::position].empty());
|
||||
region.parseOpcode({ "position_oncc45", "4.2" });
|
||||
REQUIRE(region.positionCC.contains(45));
|
||||
REQUIRE(region.positionCC[45].value == 4.2_a);
|
||||
REQUIRE(region.modifiers[Mod::position].contains(45));
|
||||
REQUIRE(region.modifiers[Mod::position][45].value == 4.2_a);
|
||||
region.parseOpcode({ "position_curvecc17", "18" });
|
||||
REQUIRE(region.positionCC[17].curve == 18);
|
||||
REQUIRE(region.modifiers[Mod::position][17].curve == 18);
|
||||
region.parseOpcode({ "position_curvecc17", "15482" });
|
||||
REQUIRE(region.positionCC[17].curve == 255);
|
||||
REQUIRE(region.modifiers[Mod::position][17].curve == 255);
|
||||
region.parseOpcode({ "position_curvecc17", "-2" });
|
||||
REQUIRE(region.positionCC[17].curve == 0);
|
||||
REQUIRE(region.modifiers[Mod::position][17].curve == 0);
|
||||
region.parseOpcode({ "position_smoothcc14", "85" });
|
||||
REQUIRE(region.positionCC[14].smooth == 85);
|
||||
REQUIRE(region.modifiers[Mod::position][14].smooth == 85);
|
||||
region.parseOpcode({ "position_smoothcc14", "15482" });
|
||||
REQUIRE(region.positionCC[14].smooth == 127);
|
||||
REQUIRE(region.modifiers[Mod::position][14].smooth == 100);
|
||||
region.parseOpcode({ "position_smoothcc14", "-2" });
|
||||
REQUIRE(region.positionCC[14].smooth == 0);
|
||||
REQUIRE(region.modifiers[Mod::position][14].smooth == 0);
|
||||
region.parseOpcode({ "position_stepcc120", "24" });
|
||||
REQUIRE(region.positionCC[120].step == 24.0_a);
|
||||
REQUIRE(region.modifiers[Mod::position][120].step == 24.0_a);
|
||||
region.parseOpcode({ "position_stepcc120", "15482" });
|
||||
REQUIRE(region.positionCC[120].step == 200.0_a);
|
||||
REQUIRE(region.modifiers[Mod::position][120].step == 200.0_a);
|
||||
region.parseOpcode({ "position_stepcc120", "-2" });
|
||||
REQUIRE(region.positionCC[120].step == 0.0f);
|
||||
REQUIRE(region.modifiers[Mod::position][120].step == 0.0f);
|
||||
}
|
||||
|
||||
SECTION("amp_keycenter")
|
||||
|
|
@ -704,116 +705,116 @@ TEST_CASE("[Region] Parsing opcodes")
|
|||
|
||||
SECTION("xfin_lokey, xfin_hikey")
|
||||
{
|
||||
REQUIRE(region.crossfadeKeyInRange == sfz::Range<uint8_t>(0, 0));
|
||||
REQUIRE(region.crossfadeKeyInRange == Range<uint8_t>(0, 0));
|
||||
region.parseOpcode({ "xfin_lokey", "4" });
|
||||
REQUIRE(region.crossfadeKeyInRange == sfz::Range<uint8_t>(4, 4));
|
||||
REQUIRE(region.crossfadeKeyInRange == Range<uint8_t>(4, 4));
|
||||
region.parseOpcode({ "xfin_lokey", "128" });
|
||||
REQUIRE(region.crossfadeKeyInRange == sfz::Range<uint8_t>(127, 127));
|
||||
REQUIRE(region.crossfadeKeyInRange == Range<uint8_t>(127, 127));
|
||||
region.parseOpcode({ "xfin_lokey", "59" });
|
||||
REQUIRE(region.crossfadeKeyInRange == sfz::Range<uint8_t>(59, 127));
|
||||
REQUIRE(region.crossfadeKeyInRange == Range<uint8_t>(59, 127));
|
||||
region.parseOpcode({ "xfin_hikey", "59" });
|
||||
REQUIRE(region.crossfadeKeyInRange == sfz::Range<uint8_t>(59, 59));
|
||||
REQUIRE(region.crossfadeKeyInRange == Range<uint8_t>(59, 59));
|
||||
region.parseOpcode({ "xfin_hikey", "128" });
|
||||
REQUIRE(region.crossfadeKeyInRange == sfz::Range<uint8_t>(59, 127));
|
||||
REQUIRE(region.crossfadeKeyInRange == Range<uint8_t>(59, 127));
|
||||
region.parseOpcode({ "xfin_hikey", "0" });
|
||||
REQUIRE(region.crossfadeKeyInRange == sfz::Range<uint8_t>(0, 0));
|
||||
REQUIRE(region.crossfadeKeyInRange == Range<uint8_t>(0, 0));
|
||||
region.parseOpcode({ "xfin_hikey", "-1" });
|
||||
REQUIRE(region.crossfadeKeyInRange == sfz::Range<uint8_t>(0, 0));
|
||||
REQUIRE(region.crossfadeKeyInRange == Range<uint8_t>(0, 0));
|
||||
}
|
||||
|
||||
SECTION("xfin_lovel, xfin_hivel")
|
||||
{
|
||||
REQUIRE(region.crossfadeVelInRange == sfz::Range<float>(0_norm, 0_norm));
|
||||
REQUIRE(region.crossfadeVelInRange == Range<float>(0_norm, 0_norm));
|
||||
region.parseOpcode({ "xfin_lovel", "4" });
|
||||
REQUIRE(region.crossfadeVelInRange == sfz::Range<float>(4_norm, 4_norm));
|
||||
REQUIRE(region.crossfadeVelInRange == Range<float>(4_norm, 4_norm));
|
||||
region.parseOpcode({ "xfin_lovel", "128" });
|
||||
REQUIRE(region.crossfadeVelInRange == sfz::Range<float>(127_norm, 127_norm));
|
||||
REQUIRE(region.crossfadeVelInRange == Range<float>(127_norm, 127_norm));
|
||||
region.parseOpcode({ "xfin_lovel", "59" });
|
||||
REQUIRE(region.crossfadeVelInRange == sfz::Range<float>(59_norm, 127_norm));
|
||||
REQUIRE(region.crossfadeVelInRange == Range<float>(59_norm, 127_norm));
|
||||
region.parseOpcode({ "xfin_hivel", "59" });
|
||||
REQUIRE(region.crossfadeVelInRange == sfz::Range<float>(59_norm, 59_norm));
|
||||
REQUIRE(region.crossfadeVelInRange == Range<float>(59_norm, 59_norm));
|
||||
region.parseOpcode({ "xfin_hivel", "128" });
|
||||
REQUIRE(region.crossfadeVelInRange == sfz::Range<float>(59_norm, 127_norm));
|
||||
REQUIRE(region.crossfadeVelInRange == Range<float>(59_norm, 127_norm));
|
||||
region.parseOpcode({ "xfin_hivel", "0" });
|
||||
REQUIRE(region.crossfadeVelInRange == sfz::Range<float>(0_norm, 0_norm));
|
||||
REQUIRE(region.crossfadeVelInRange == Range<float>(0_norm, 0_norm));
|
||||
region.parseOpcode({ "xfin_hivel", "-1" });
|
||||
REQUIRE(region.crossfadeVelInRange == sfz::Range<float>(0_norm, 0_norm));
|
||||
REQUIRE(region.crossfadeVelInRange == Range<float>(0_norm, 0_norm));
|
||||
}
|
||||
|
||||
SECTION("xfout_lokey, xfout_hikey")
|
||||
{
|
||||
REQUIRE(region.crossfadeKeyOutRange == sfz::Range<uint8_t>(127, 127));
|
||||
REQUIRE(region.crossfadeKeyOutRange == Range<uint8_t>(127, 127));
|
||||
region.parseOpcode({ "xfout_lokey", "4" });
|
||||
REQUIRE(region.crossfadeKeyOutRange == sfz::Range<uint8_t>(4, 127));
|
||||
REQUIRE(region.crossfadeKeyOutRange == Range<uint8_t>(4, 127));
|
||||
region.parseOpcode({ "xfout_lokey", "128" });
|
||||
REQUIRE(region.crossfadeKeyOutRange == sfz::Range<uint8_t>(127, 127));
|
||||
REQUIRE(region.crossfadeKeyOutRange == Range<uint8_t>(127, 127));
|
||||
region.parseOpcode({ "xfout_lokey", "59" });
|
||||
REQUIRE(region.crossfadeKeyOutRange == sfz::Range<uint8_t>(59, 127));
|
||||
REQUIRE(region.crossfadeKeyOutRange == Range<uint8_t>(59, 127));
|
||||
region.parseOpcode({ "xfout_hikey", "59" });
|
||||
REQUIRE(region.crossfadeKeyOutRange == sfz::Range<uint8_t>(59, 59));
|
||||
REQUIRE(region.crossfadeKeyOutRange == Range<uint8_t>(59, 59));
|
||||
region.parseOpcode({ "xfout_hikey", "128" });
|
||||
REQUIRE(region.crossfadeKeyOutRange == sfz::Range<uint8_t>(59, 127));
|
||||
REQUIRE(region.crossfadeKeyOutRange == Range<uint8_t>(59, 127));
|
||||
region.parseOpcode({ "xfout_hikey", "0" });
|
||||
REQUIRE(region.crossfadeKeyOutRange == sfz::Range<uint8_t>(0, 0));
|
||||
REQUIRE(region.crossfadeKeyOutRange == Range<uint8_t>(0, 0));
|
||||
region.parseOpcode({ "xfout_hikey", "-1" });
|
||||
REQUIRE(region.crossfadeKeyOutRange == sfz::Range<uint8_t>(0, 0));
|
||||
REQUIRE(region.crossfadeKeyOutRange == Range<uint8_t>(0, 0));
|
||||
}
|
||||
|
||||
SECTION("xfout_lovel, xfout_hivel")
|
||||
{
|
||||
REQUIRE(region.crossfadeVelOutRange == sfz::Range<float>(127_norm, 127_norm));
|
||||
REQUIRE(region.crossfadeVelOutRange == Range<float>(127_norm, 127_norm));
|
||||
region.parseOpcode({ "xfout_lovel", "4" });
|
||||
REQUIRE(region.crossfadeVelOutRange == sfz::Range<float>(4_norm, 127_norm));
|
||||
REQUIRE(region.crossfadeVelOutRange == Range<float>(4_norm, 127_norm));
|
||||
region.parseOpcode({ "xfout_lovel", "128" });
|
||||
REQUIRE(region.crossfadeVelOutRange == sfz::Range<float>(127_norm, 127_norm));
|
||||
REQUIRE(region.crossfadeVelOutRange == Range<float>(127_norm, 127_norm));
|
||||
region.parseOpcode({ "xfout_lovel", "59" });
|
||||
REQUIRE(region.crossfadeVelOutRange == sfz::Range<float>(59_norm, 127_norm));
|
||||
REQUIRE(region.crossfadeVelOutRange == Range<float>(59_norm, 127_norm));
|
||||
region.parseOpcode({ "xfout_hivel", "59" });
|
||||
REQUIRE(region.crossfadeVelOutRange == sfz::Range<float>(59_norm, 59_norm));
|
||||
REQUIRE(region.crossfadeVelOutRange == Range<float>(59_norm, 59_norm));
|
||||
region.parseOpcode({ "xfout_hivel", "128" });
|
||||
REQUIRE(region.crossfadeVelOutRange == sfz::Range<float>(59_norm, 127_norm));
|
||||
REQUIRE(region.crossfadeVelOutRange == Range<float>(59_norm, 127_norm));
|
||||
region.parseOpcode({ "xfout_hivel", "0" });
|
||||
REQUIRE(region.crossfadeVelOutRange == sfz::Range<float>(0_norm, 0_norm));
|
||||
REQUIRE(region.crossfadeVelOutRange == Range<float>(0_norm, 0_norm));
|
||||
region.parseOpcode({ "xfout_hivel", "-1" });
|
||||
REQUIRE(region.crossfadeVelOutRange == sfz::Range<float>(0_norm, 0_norm));
|
||||
REQUIRE(region.crossfadeVelOutRange == Range<float>(0_norm, 0_norm));
|
||||
}
|
||||
|
||||
SECTION("xfin_locc, xfin_hicc")
|
||||
{
|
||||
REQUIRE(!region.crossfadeCCInRange.contains(4));
|
||||
region.parseOpcode({ "xfin_locc4", "4" });
|
||||
REQUIRE(region.crossfadeCCInRange[4] == sfz::Range<float>(4_norm, 4_norm));
|
||||
REQUIRE(region.crossfadeCCInRange[4] == Range<float>(4_norm, 4_norm));
|
||||
region.parseOpcode({ "xfin_locc4", "128" });
|
||||
REQUIRE(region.crossfadeCCInRange[4] == sfz::Range<float>(127_norm, 127_norm));
|
||||
REQUIRE(region.crossfadeCCInRange[4] == Range<float>(127_norm, 127_norm));
|
||||
region.parseOpcode({ "xfin_locc4", "59" });
|
||||
REQUIRE(region.crossfadeCCInRange[4] == sfz::Range<float>(59_norm, 127_norm));
|
||||
REQUIRE(region.crossfadeCCInRange[4] == Range<float>(59_norm, 127_norm));
|
||||
region.parseOpcode({ "xfin_hicc4", "59" });
|
||||
REQUIRE(region.crossfadeCCInRange[4] == sfz::Range<float>(59_norm, 59_norm));
|
||||
REQUIRE(region.crossfadeCCInRange[4] == Range<float>(59_norm, 59_norm));
|
||||
region.parseOpcode({ "xfin_hicc4", "128" });
|
||||
REQUIRE(region.crossfadeCCInRange[4] == sfz::Range<float>(59_norm, 127_norm));
|
||||
REQUIRE(region.crossfadeCCInRange[4] == Range<float>(59_norm, 127_norm));
|
||||
region.parseOpcode({ "xfin_hicc4", "0" });
|
||||
REQUIRE(region.crossfadeCCInRange[4] == sfz::Range<float>(0_norm, 0_norm));
|
||||
REQUIRE(region.crossfadeCCInRange[4] == Range<float>(0_norm, 0_norm));
|
||||
region.parseOpcode({ "xfin_hicc4", "-1" });
|
||||
REQUIRE(region.crossfadeCCInRange[4] == sfz::Range<float>(0_norm, 0_norm));
|
||||
REQUIRE(region.crossfadeCCInRange[4] == Range<float>(0_norm, 0_norm));
|
||||
}
|
||||
|
||||
SECTION("xfout_locc, xfout_hicc")
|
||||
{
|
||||
REQUIRE(!region.crossfadeCCOutRange.contains(4));
|
||||
region.parseOpcode({ "xfout_locc4", "4" });
|
||||
REQUIRE(region.crossfadeCCOutRange[4] == sfz::Range<float>(4_norm, 127_norm));
|
||||
REQUIRE(region.crossfadeCCOutRange[4] == Range<float>(4_norm, 127_norm));
|
||||
region.parseOpcode({ "xfout_locc4", "128" });
|
||||
REQUIRE(region.crossfadeCCOutRange[4] == sfz::Range<float>(127_norm, 127_norm));
|
||||
REQUIRE(region.crossfadeCCOutRange[4] == Range<float>(127_norm, 127_norm));
|
||||
region.parseOpcode({ "xfout_locc4", "59" });
|
||||
REQUIRE(region.crossfadeCCOutRange[4] == sfz::Range<float>(59_norm, 127_norm));
|
||||
REQUIRE(region.crossfadeCCOutRange[4] == Range<float>(59_norm, 127_norm));
|
||||
region.parseOpcode({ "xfout_hicc4", "59" });
|
||||
REQUIRE(region.crossfadeCCOutRange[4] == sfz::Range<float>(59_norm, 59_norm));
|
||||
REQUIRE(region.crossfadeCCOutRange[4] == Range<float>(59_norm, 59_norm));
|
||||
region.parseOpcode({ "xfout_hicc4", "128" });
|
||||
REQUIRE(region.crossfadeCCOutRange[4] == sfz::Range<float>(59_norm, 127_norm));
|
||||
REQUIRE(region.crossfadeCCOutRange[4] == Range<float>(59_norm, 127_norm));
|
||||
region.parseOpcode({ "xfout_hicc4", "0" });
|
||||
REQUIRE(region.crossfadeCCOutRange[4] == sfz::Range<float>(0_norm, 0_norm));
|
||||
REQUIRE(region.crossfadeCCOutRange[4] == Range<float>(0_norm, 0_norm));
|
||||
region.parseOpcode({ "xfout_hicc4", "-1" });
|
||||
REQUIRE(region.crossfadeCCOutRange[4] == sfz::Range<float>(0_norm, 0_norm));
|
||||
REQUIRE(region.crossfadeCCOutRange[4] == Range<float>(0_norm, 0_norm));
|
||||
}
|
||||
|
||||
SECTION("xf_keycurve")
|
||||
|
|
@ -932,7 +933,7 @@ TEST_CASE("[Region] Parsing opcodes")
|
|||
REQUIRE(region.tune == -9600);
|
||||
}
|
||||
|
||||
SECTION("bend_up, bend_down, bend_step")
|
||||
SECTION("bend_up, bend_down, bend_step, bend_smooth")
|
||||
{
|
||||
REQUIRE(region.bendUp == 200);
|
||||
REQUIRE(region.bendDown == -200);
|
||||
|
|
@ -959,6 +960,12 @@ TEST_CASE("[Region] Parsing opcodes")
|
|||
REQUIRE(region.bendStep == 1);
|
||||
region.parseOpcode({ "bend_step", "9700" });
|
||||
REQUIRE(region.bendStep == 1200);
|
||||
region.parseOpcode({ "bend_smooth", "10" });
|
||||
REQUIRE(region.bendSmooth == 10);
|
||||
region.parseOpcode({ "bend_smooth", "120" });
|
||||
REQUIRE(region.bendSmooth == 100);
|
||||
region.parseOpcode({ "bend_smooth", "-2" });
|
||||
REQUIRE(region.bendSmooth == 0);
|
||||
}
|
||||
|
||||
SECTION("ampeg")
|
||||
|
|
@ -1173,7 +1180,7 @@ TEST_CASE("[Region] Parsing opcodes")
|
|||
REQUIRE(region.filters[0].cutoff == 500.0f);
|
||||
// Check filter defaults
|
||||
REQUIRE(region.filters[0].keycenter == 60);
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterLpf2p);
|
||||
REQUIRE(region.filters[0].type == FilterType::kFilterLpf2p);
|
||||
REQUIRE(region.filters[0].keytrack == 0);
|
||||
REQUIRE(region.filters[0].gain == 0);
|
||||
REQUIRE(region.filters[0].veltrack == 0);
|
||||
|
|
@ -1187,7 +1194,7 @@ TEST_CASE("[Region] Parsing opcodes")
|
|||
REQUIRE(region.filters[1].cutoff == 5000.0f);
|
||||
// Check filter defaults
|
||||
REQUIRE(region.filters[1].keycenter == 60);
|
||||
REQUIRE(region.filters[1].type == sfz::FilterType::kFilterLpf2p);
|
||||
REQUIRE(region.filters[1].type == FilterType::kFilterLpf2p);
|
||||
REQUIRE(region.filters[1].keytrack == 0);
|
||||
REQUIRE(region.filters[1].gain == 0);
|
||||
REQUIRE(region.filters[1].veltrack == 0);
|
||||
|
|
@ -1202,7 +1209,7 @@ TEST_CASE("[Region] Parsing opcodes")
|
|||
REQUIRE(region.filters[3].cutoff == 50.0f);
|
||||
// Check filter defaults
|
||||
REQUIRE(region.filters[2].keycenter == 60);
|
||||
REQUIRE(region.filters[2].type == sfz::FilterType::kFilterLpf2p);
|
||||
REQUIRE(region.filters[2].type == FilterType::kFilterLpf2p);
|
||||
REQUIRE(region.filters[2].keytrack == 0);
|
||||
REQUIRE(region.filters[2].gain == 0);
|
||||
REQUIRE(region.filters[2].veltrack == 0);
|
||||
|
|
@ -1211,7 +1218,7 @@ TEST_CASE("[Region] Parsing opcodes")
|
|||
REQUIRE(region.filters[2].gainCC.empty());
|
||||
REQUIRE(region.filters[2].resonanceCC.empty());
|
||||
REQUIRE(region.filters[3].keycenter == 60);
|
||||
REQUIRE(region.filters[3].type == sfz::FilterType::kFilterLpf2p);
|
||||
REQUIRE(region.filters[3].type == FilterType::kFilterLpf2p);
|
||||
REQUIRE(region.filters[3].keytrack == 0);
|
||||
REQUIRE(region.filters[3].gain == 0);
|
||||
REQUIRE(region.filters[3].veltrack == 0);
|
||||
|
|
@ -1313,55 +1320,55 @@ TEST_CASE("[Region] Parsing opcodes")
|
|||
|
||||
region.parseOpcode({ "fil_type", "lpf_1p" });
|
||||
REQUIRE(region.filters.size() == 1);
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterLpf1p);
|
||||
REQUIRE(region.filters[0].type == FilterType::kFilterLpf1p);
|
||||
region.parseOpcode({ "fil_type", "lpf_2p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterLpf2p);
|
||||
REQUIRE(region.filters[0].type == FilterType::kFilterLpf2p);
|
||||
region.parseOpcode({ "fil_type", "hpf_1p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterHpf1p);
|
||||
REQUIRE(region.filters[0].type == FilterType::kFilterHpf1p);
|
||||
region.parseOpcode({ "fil_type", "hpf_2p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterHpf2p);
|
||||
REQUIRE(region.filters[0].type == FilterType::kFilterHpf2p);
|
||||
region.parseOpcode({ "fil_type", "bpf_2p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterBpf2p);
|
||||
REQUIRE(region.filters[0].type == FilterType::kFilterBpf2p);
|
||||
region.parseOpcode({ "fil_type", "brf_2p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterBrf2p);
|
||||
REQUIRE(region.filters[0].type == FilterType::kFilterBrf2p);
|
||||
region.parseOpcode({ "fil_type", "bpf_1p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterBpf1p);
|
||||
REQUIRE(region.filters[0].type == FilterType::kFilterBpf1p);
|
||||
region.parseOpcode({ "fil_type", "brf_1p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterBrf1p);
|
||||
REQUIRE(region.filters[0].type == FilterType::kFilterBrf1p);
|
||||
region.parseOpcode({ "fil_type", "apf_1p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterApf1p);
|
||||
REQUIRE(region.filters[0].type == FilterType::kFilterApf1p);
|
||||
region.parseOpcode({ "fil_type", "lpf_2p_sv" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterLpf2pSv);
|
||||
REQUIRE(region.filters[0].type == FilterType::kFilterLpf2pSv);
|
||||
region.parseOpcode({ "fil_type", "hpf_2p_sv" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterHpf2pSv);
|
||||
REQUIRE(region.filters[0].type == FilterType::kFilterHpf2pSv);
|
||||
region.parseOpcode({ "fil_type", "bpf_2p_sv" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterBpf2pSv);
|
||||
REQUIRE(region.filters[0].type == FilterType::kFilterBpf2pSv);
|
||||
region.parseOpcode({ "fil_type", "brf_2p_sv" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterBrf2pSv);
|
||||
REQUIRE(region.filters[0].type == FilterType::kFilterBrf2pSv);
|
||||
region.parseOpcode({ "fil_type", "lpf_4p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterLpf4p);
|
||||
REQUIRE(region.filters[0].type == FilterType::kFilterLpf4p);
|
||||
region.parseOpcode({ "fil_type", "hpf_4p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterHpf4p);
|
||||
REQUIRE(region.filters[0].type == FilterType::kFilterHpf4p);
|
||||
region.parseOpcode({ "fil_type", "lpf_6p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterLpf6p);
|
||||
REQUIRE(region.filters[0].type == FilterType::kFilterLpf6p);
|
||||
region.parseOpcode({ "fil_type", "hpf_6p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterHpf6p);
|
||||
REQUIRE(region.filters[0].type == FilterType::kFilterHpf6p);
|
||||
region.parseOpcode({ "fil_type", "pink" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterPink);
|
||||
REQUIRE(region.filters[0].type == FilterType::kFilterPink);
|
||||
region.parseOpcode({ "fil_type", "lsh" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterLsh);
|
||||
REQUIRE(region.filters[0].type == FilterType::kFilterLsh);
|
||||
region.parseOpcode({ "fil_type", "hsh" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterHsh);
|
||||
REQUIRE(region.filters[0].type == FilterType::kFilterHsh);
|
||||
region.parseOpcode({ "fil_type", "peq" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterPeq);
|
||||
REQUIRE(region.filters[0].type == FilterType::kFilterPeq);
|
||||
region.parseOpcode({ "fil_type", "lpf_1p" });
|
||||
region.parseOpcode({ "fil_type", "pkf_2p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterPeq);
|
||||
REQUIRE(region.filters[0].type == FilterType::kFilterPeq);
|
||||
region.parseOpcode({ "fil_type", "lpf_1p" });
|
||||
region.parseOpcode({ "fil_type", "bpk_2p" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterPeq);
|
||||
REQUIRE(region.filters[0].type == FilterType::kFilterPeq);
|
||||
region.parseOpcode({ "fil_type", "unknown" });
|
||||
REQUIRE(region.filters[0].type == sfz::FilterType::kFilterNone);
|
||||
REQUIRE(region.filters[0].type == FilterType::kFilterNone);
|
||||
}
|
||||
|
||||
SECTION("EQ stacking and gains")
|
||||
|
|
@ -1372,7 +1379,7 @@ TEST_CASE("[Region] Parsing opcodes")
|
|||
REQUIRE(region.equalizers.size() == 1);
|
||||
REQUIRE(region.equalizers[0].gain == 6.0f);
|
||||
// Check defaults
|
||||
REQUIRE(region.equalizers[0].type == sfz::EqType::kEqPeak);
|
||||
REQUIRE(region.equalizers[0].type == EqType::kEqPeak);
|
||||
REQUIRE(region.equalizers[0].bandwidth == 1.0f);
|
||||
REQUIRE(region.equalizers[0].frequency == 0.0f);
|
||||
REQUIRE(region.equalizers[0].vel2frequency == 0);
|
||||
|
|
@ -1385,7 +1392,7 @@ TEST_CASE("[Region] Parsing opcodes")
|
|||
REQUIRE(region.equalizers.size() == 2);
|
||||
REQUIRE(region.equalizers[1].gain == -96.0f);
|
||||
// Check defaults
|
||||
REQUIRE(region.equalizers[1].type == sfz::EqType::kEqPeak);
|
||||
REQUIRE(region.equalizers[1].type == EqType::kEqPeak);
|
||||
REQUIRE(region.equalizers[1].bandwidth == 1.0f);
|
||||
REQUIRE(region.equalizers[1].frequency == 0.0f);
|
||||
REQUIRE(region.equalizers[1].vel2frequency == 0);
|
||||
|
|
@ -1397,7 +1404,7 @@ TEST_CASE("[Region] Parsing opcodes")
|
|||
region.parseOpcode({ "eq4_gain", "500" });
|
||||
REQUIRE(region.equalizers.size() == 4);
|
||||
REQUIRE(region.equalizers[2].gain == 0.0f);
|
||||
REQUIRE(region.equalizers[3].type == sfz::EqType::kEqPeak);
|
||||
REQUIRE(region.equalizers[3].type == EqType::kEqPeak);
|
||||
REQUIRE(region.equalizers[3].gain == 96.0f);
|
||||
// Check defaults
|
||||
REQUIRE(region.equalizers[2].bandwidth == 1.0f);
|
||||
|
|
@ -1419,13 +1426,13 @@ TEST_CASE("[Region] Parsing opcodes")
|
|||
SECTION("EQ types")
|
||||
{
|
||||
region.parseOpcode({ "eq1_type", "hshelf" });
|
||||
REQUIRE(region.equalizers[0].type == sfz::EqType::kEqHighShelf);
|
||||
REQUIRE(region.equalizers[0].type == EqType::kEqHighShelf);
|
||||
region.parseOpcode({ "eq1_type", "somethingsomething" });
|
||||
REQUIRE(region.equalizers[0].type == sfz::EqType::kEqNone);
|
||||
REQUIRE(region.equalizers[0].type == EqType::kEqNone);
|
||||
region.parseOpcode({ "eq1_type", "lshelf" });
|
||||
REQUIRE(region.equalizers[0].type == sfz::EqType::kEqLowShelf);
|
||||
REQUIRE(region.equalizers[0].type == EqType::kEqLowShelf);
|
||||
region.parseOpcode({ "eq1_type", "peak" });
|
||||
REQUIRE(region.equalizers[0].type == sfz::EqType::kEqPeak);
|
||||
REQUIRE(region.equalizers[0].type == EqType::kEqPeak);
|
||||
}
|
||||
|
||||
SECTION("EQ parameter dispatch")
|
||||
|
|
@ -1438,7 +1445,7 @@ TEST_CASE("[Region] Parsing opcodes")
|
|||
region.parseOpcode({ "eq2_freq", "300" });
|
||||
REQUIRE(region.equalizers[1].frequency == 300.0f);
|
||||
region.parseOpcode({ "eq3_type", "lshelf" });
|
||||
REQUIRE(region.equalizers[2].type == sfz::EqType::kEqLowShelf);
|
||||
REQUIRE(region.equalizers[2].type == EqType::kEqLowShelf);
|
||||
region.parseOpcode({ "eq3_vel2gain", "10" });
|
||||
REQUIRE(region.equalizers[2].vel2gain == 10.0f);
|
||||
region.parseOpcode({ "eq1_vel2freq", "100" });
|
||||
|
|
@ -1455,7 +1462,7 @@ TEST_CASE("[Region] Parsing opcodes")
|
|||
region.parseOpcode({ "eq3_freq_oncc15", "20" });
|
||||
REQUIRE(region.equalizers[2].frequencyCC[15] == 20.0f);
|
||||
region.parseOpcode({ "eq1_type", "hshelf" });
|
||||
REQUIRE(region.equalizers[0].type == sfz::EqType::kEqHighShelf);
|
||||
REQUIRE(region.equalizers[0].type == EqType::kEqHighShelf);
|
||||
region.parseOpcode({ "eq2_gaincc123", "2" });
|
||||
REQUIRE(region.equalizers[1].gainCC.contains(123));
|
||||
REQUIRE(region.equalizers[1].gainCC[123] == 2.0f);
|
||||
|
|
@ -1576,103 +1583,103 @@ TEST_CASE("[Region] Parsing opcodes")
|
|||
|
||||
SECTION("amplitude_cc")
|
||||
{
|
||||
REQUIRE(region.amplitudeCC.empty());
|
||||
REQUIRE(region.modifiers[Mod::amplitude].empty());
|
||||
region.parseOpcode({ "amplitude_cc1", "40" });
|
||||
REQUIRE(region.amplitudeCC.contains(1));
|
||||
REQUIRE(region.amplitudeCC[1].value == 40.0_a);
|
||||
REQUIRE(region.modifiers[Mod::amplitude].contains(1));
|
||||
REQUIRE(region.modifiers[Mod::amplitude][1].value == 40.0_a);
|
||||
region.parseOpcode({ "amplitude_oncc2", "30" });
|
||||
REQUIRE(region.amplitudeCC.contains(2));
|
||||
REQUIRE(region.amplitudeCC[2].value == 30.0_a);
|
||||
REQUIRE(region.modifiers[Mod::amplitude].contains(2));
|
||||
REQUIRE(region.modifiers[Mod::amplitude][2].value == 30.0_a);
|
||||
region.parseOpcode({ "amplitude_curvecc17", "18" });
|
||||
REQUIRE(region.amplitudeCC[17].curve == 18);
|
||||
REQUIRE(region.modifiers[Mod::amplitude][17].curve == 18);
|
||||
region.parseOpcode({ "amplitude_curvecc17", "15482" });
|
||||
REQUIRE(region.amplitudeCC[17].curve == 255);
|
||||
REQUIRE(region.modifiers[Mod::amplitude][17].curve == 255);
|
||||
region.parseOpcode({ "amplitude_curvecc17", "-2" });
|
||||
REQUIRE(region.amplitudeCC[17].curve == 0);
|
||||
REQUIRE(region.modifiers[Mod::amplitude][17].curve == 0);
|
||||
region.parseOpcode({ "amplitude_smoothcc14", "85" });
|
||||
REQUIRE(region.amplitudeCC[14].smooth == 85);
|
||||
REQUIRE(region.modifiers[Mod::amplitude][14].smooth == 85);
|
||||
region.parseOpcode({ "amplitude_smoothcc14", "15482" });
|
||||
REQUIRE(region.amplitudeCC[14].smooth == 127);
|
||||
REQUIRE(region.modifiers[Mod::amplitude][14].smooth == 100);
|
||||
region.parseOpcode({ "amplitude_smoothcc14", "-2" });
|
||||
REQUIRE(region.amplitudeCC[14].smooth == 0);
|
||||
REQUIRE(region.modifiers[Mod::amplitude][14].smooth == 0);
|
||||
region.parseOpcode({ "amplitude_stepcc120", "24" });
|
||||
REQUIRE(region.amplitudeCC[120].step == 24.0_a);
|
||||
REQUIRE(region.[Mod::amplitude][120].step == 24.0_a);
|
||||
region.parseOpcode({ "amplitude_stepcc120", "15482" });
|
||||
REQUIRE(region.amplitudeCC[120].step == 100.0_a);
|
||||
REQUIRE(region.[Mod::amplitude][120].step == 100.0_a);
|
||||
region.parseOpcode({ "amplitude_stepcc120", "-2" });
|
||||
REQUIRE(region.amplitudeCC[120].step == 0.0f);
|
||||
REQUIRE(region.modifiers[Mod::amplitude][120].step == 0.0f);
|
||||
}
|
||||
|
||||
SECTION("volume_oncc/gain_cc")
|
||||
{
|
||||
REQUIRE(region.volumeCC.empty());
|
||||
REQUIRE(region.modifiers[Mod::volume].empty());
|
||||
region.parseOpcode({ "gain_cc1", "40" });
|
||||
REQUIRE(region.volumeCC.contains(1));
|
||||
REQUIRE(region.volumeCC[1].value == 40_a);
|
||||
REQUIRE(region.modifiers[Mod::volume].contains(1));
|
||||
REQUIRE(region.modifiers[Mod::volume][1].value == 40_a);
|
||||
region.parseOpcode({ "volume_oncc2", "-76" });
|
||||
REQUIRE(region.volumeCC.contains(2));
|
||||
REQUIRE(region.volumeCC[2].value == -76.0_a);
|
||||
REQUIRE(region.modifiers[Mod::volume].contains(2));
|
||||
REQUIRE(region.modifiers[Mod::volume][2].value == -76.0_a);
|
||||
region.parseOpcode({ "gain_oncc4", "-1" });
|
||||
REQUIRE(region.volumeCC.contains(4));
|
||||
REQUIRE(region.volumeCC[4].value == -1.0_a);
|
||||
REQUIRE(region.modifiers[Mod::volume].contains(4));
|
||||
REQUIRE(region.modifiers[Mod::volume][4].value == -1.0_a);
|
||||
region.parseOpcode({ "volume_curvecc17", "18" });
|
||||
REQUIRE(region.volumeCC[17].curve == 18);
|
||||
REQUIRE(region.modifiers[Mod::volume][17].curve == 18);
|
||||
region.parseOpcode({ "volume_curvecc17", "15482" });
|
||||
REQUIRE(region.volumeCC[17].curve == 255);
|
||||
REQUIRE(region.modifiers[Mod::volume][17].curve == 255);
|
||||
region.parseOpcode({ "volume_curvecc17", "-2" });
|
||||
REQUIRE(region.volumeCC[17].curve == 0);
|
||||
REQUIRE(region.modifiers[Mod::volume][17].curve == 0);
|
||||
region.parseOpcode({ "volume_smoothcc14", "85" });
|
||||
REQUIRE(region.volumeCC[14].smooth == 85);
|
||||
REQUIRE(region.modifiers[Mod::volume][14].smooth == 85);
|
||||
region.parseOpcode({ "volume_smoothcc14", "15482" });
|
||||
REQUIRE(region.volumeCC[14].smooth == 127);
|
||||
REQUIRE(region.modifiers[Mod::volume][14].smooth == 100);
|
||||
region.parseOpcode({ "volume_smoothcc14", "-2" });
|
||||
REQUIRE(region.volumeCC[14].smooth == 0);
|
||||
REQUIRE(region.modifiers[Mod::volume][14].smooth == 0);
|
||||
region.parseOpcode({ "volume_stepcc120", "24" });
|
||||
REQUIRE(region.volumeCC[120].step == 24.0f);
|
||||
REQUIRE(region.modifiers[Mod::volume][120].step == 24.0f);
|
||||
region.parseOpcode({ "volume_stepcc120", "15482" });
|
||||
REQUIRE(region.volumeCC[120].step == 144.0f);
|
||||
REQUIRE(region.modifiers[Mod::volume][120].step == 144.0f);
|
||||
region.parseOpcode({ "volume_stepcc120", "-2" });
|
||||
REQUIRE(region.volumeCC[120].step == 0.0f);
|
||||
REQUIRE(region.modifiers[Mod::volume][120].step == 0.0f);
|
||||
}
|
||||
|
||||
SECTION("tune_cc/pitch_cc")
|
||||
{
|
||||
REQUIRE(region.tuneCC.empty());
|
||||
REQUIRE(region.modifiers[Mod::pitch].empty());
|
||||
region.parseOpcode({ "pitch_cc1", "40" });
|
||||
REQUIRE(region.tuneCC.contains(1));
|
||||
REQUIRE(region.tuneCC[1].value == 40.0);
|
||||
REQUIRE(region.modifiers[Mod::pitch].contains(1));
|
||||
REQUIRE(region.modifiers[Mod::pitch][1].value == 40.0);
|
||||
region.parseOpcode({ "tune_oncc2", "-76" });
|
||||
REQUIRE(region.tuneCC.contains(2));
|
||||
REQUIRE(region.tuneCC[2].value == -76.0);
|
||||
REQUIRE(region.modifiers[Mod::pitch].contains(2));
|
||||
REQUIRE(region.modifiers[Mod::pitch][2].value == -76.0);
|
||||
region.parseOpcode({ "pitch_oncc4", "-1" });
|
||||
REQUIRE(region.tuneCC.contains(4));
|
||||
REQUIRE(region.tuneCC[4].value == -1.0);
|
||||
REQUIRE(region.modifiers[Mod::pitch].contains(4));
|
||||
REQUIRE(region.modifiers[Mod::pitch][4].value == -1.0);
|
||||
region.parseOpcode({ "tune_curvecc17", "18" });
|
||||
REQUIRE(region.tuneCC[17].curve == 18);
|
||||
REQUIRE(region.modifiers[Mod::pitch][17].curve == 18);
|
||||
region.parseOpcode({ "pitch_curvecc17", "15482" });
|
||||
REQUIRE(region.tuneCC[17].curve == 255);
|
||||
REQUIRE(region.modifiers[Mod::pitch][17].curve == 255);
|
||||
region.parseOpcode({ "tune_curvecc17", "-2" });
|
||||
REQUIRE(region.tuneCC[17].curve == 0);
|
||||
REQUIRE(region.modifiers[Mod::pitch][17].curve == 0);
|
||||
region.parseOpcode({ "pitch_smoothcc14", "85" });
|
||||
REQUIRE(region.tuneCC[14].smooth == 85);
|
||||
REQUIRE(region.modifiers[Mod::pitch][14].smooth == 85);
|
||||
region.parseOpcode({ "tune_smoothcc14", "15482" });
|
||||
REQUIRE(region.tuneCC[14].smooth == 127);
|
||||
REQUIRE(region.modifiers[Mod::pitch][14].smooth == 100);
|
||||
region.parseOpcode({ "pitch_smoothcc14", "-2" });
|
||||
REQUIRE(region.tuneCC[14].smooth == 0);
|
||||
REQUIRE(region.modifiers[Mod::pitch][14].smooth == 0);
|
||||
region.parseOpcode({ "tune_stepcc120", "24" });
|
||||
REQUIRE(region.tuneCC[120].step == 24.0f);
|
||||
REQUIRE(region.modifiers[Mod::pitch][120].step == 24.0f);
|
||||
region.parseOpcode({ "pitch_stepcc120", "15482" });
|
||||
REQUIRE(region.tuneCC[120].step == 9600.0f);
|
||||
REQUIRE(region.modifiers[Mod::pitch][120].step == 9600.0f);
|
||||
region.parseOpcode({ "tune_stepcc120", "-2" });
|
||||
REQUIRE(region.tuneCC[120].step == 0.0f);
|
||||
REQUIRE(region.modifiers[Mod::pitch][120].step == 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
// Specific region bugs
|
||||
TEST_CASE("[Region] Non-conforming floating point values in integer opcodes")
|
||||
{
|
||||
sfz::MidiState midiState;
|
||||
sfz::Region region { 0, midiState };
|
||||
MidiState midiState;
|
||||
Region region { 0, midiState };
|
||||
region.parseOpcode({ "offset", "2014.5" });
|
||||
REQUIRE(region.offset == 2014);
|
||||
region.parseOpcode({ "pitch_keytrack", "-2.1" });
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||
|
||||
#include "sfizz/OnePoleFilter.h"
|
||||
#include "sfizz/Smoothers.h"
|
||||
#include "catch2/catch.hpp"
|
||||
// #include "cnpy.h"
|
||||
// #include "ghc/fs_std.hpp"
|
||||
|
|
@ -16,14 +17,13 @@
|
|||
using namespace Catch::literals;
|
||||
|
||||
template <class Type, size_t N>
|
||||
inline bool approxEqual(const std::array<Type, N> &lhs, const std::array<Type, N> &rhs)
|
||||
inline bool approxEqual(const std::array<Type, N>& lhs, const std::array<Type, N>& rhs, Type epsilon = 1e-3)
|
||||
{
|
||||
if (lhs.size() != rhs.size())
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < rhs.size(); ++i)
|
||||
if (lhs[i] != Approx(rhs[i]).epsilon(1e-3))
|
||||
{
|
||||
if (lhs[i] != Approx(rhs[i]).epsilon(epsilon)) {
|
||||
std::cerr << lhs[i] << " != " << rhs[i] << " at index " << i << '\n';
|
||||
return false;
|
||||
}
|
||||
|
|
@ -74,7 +74,8 @@ constexpr std::array<float, 64> floatInput01 = {
|
|||
1.1666758495956464f, -0.04382336233428379f, 0.43819763320865857f, 0.1740610608056625f,
|
||||
0.30473671729007396f, -0.4065881153810866f, -0.9784770671900811f, -0.17674381857142665f,
|
||||
0.3493213284003123f, -1.2540491577273034f, 1.2597719140599792f, 0.4198847510851298f,
|
||||
0.9612865621570132f, -1.5614809857797225f, -0.31416474166626646f, -1.4741449502960542f };
|
||||
0.9612865621570132f, -1.5614809857797225f, -0.31416474166626646f, -1.4741449502960542f
|
||||
};
|
||||
|
||||
constexpr std::array<float, 64> floatOutputLow01 = {
|
||||
0.06567783171600353f, 0.18655945645590016f, 0.15368937959051f, 0.05054483866245487f,
|
||||
|
|
@ -92,7 +93,8 @@ constexpr std::array<float, 64> floatOutputLow01 = {
|
|||
0.09460636244101792f, 0.17948270447550216f, 0.18270169192308128f, 0.20514308375655024f,
|
||||
0.21137141199133533f, 0.16368102816645502f, 0.008005824629720673f, -0.0984698603721838f,
|
||||
-0.06487738486552441f, -0.13532948119242824f, -0.11020387039992532f, 0.06252925741325283f,
|
||||
0.1767213299964926f, 0.0900270496677931f, -0.09685475276689556f, -0.24181840607858007f };
|
||||
0.1767213299964926f, 0.0900270496677931f, -0.09685475276689556f, -0.24181840607858007f
|
||||
};
|
||||
|
||||
constexpr std::array<float, 64> floatOutputHigh01 = {
|
||||
0.6567783171600353f, 0.5520379302389311f, -0.8807386988928331f, -0.1507067103877182f,
|
||||
|
|
@ -110,7 +112,8 @@ constexpr std::array<float, 64> floatOutputHigh01 = {
|
|||
1.0720694871546286f, -0.22330606680978596f, 0.2554959412855773f, -0.031082022950887744f,
|
||||
0.09336530529873863f, -0.5702691435475415f, -0.9864828918198018f, -0.07827395819924285f,
|
||||
0.41419871326583674f, -1.1187196765348753f, 1.3699757844599045f, 0.35735549367187697f,
|
||||
0.7845652321605207f, -1.6515080354475156f, -0.2173099888993709f, -1.2323265442174742f };
|
||||
0.7845652321605207f, -1.6515080354475156f, -0.2173099888993709f, -1.2323265442174742f
|
||||
};
|
||||
|
||||
constexpr std::array<float, 64> floatInput05 = {
|
||||
-0.8247415510202276f, -1.0299159073255513f, 0.7689727513393745f, -0.023063681797826918f,
|
||||
|
|
@ -128,7 +131,8 @@ constexpr std::array<float, 64> floatInput05 = {
|
|||
-0.6137810912250902f, -0.7039958189789415f, -1.33840097232278f, 0.4786946763969468f,
|
||||
-0.46464793721558995f, -1.7121509287301122f, 0.7887828546774234f, -0.902172963851904f,
|
||||
-0.2591368523894675f, -0.9510361177022718f, 0.5739217219088085f, -0.25730420306720403f,
|
||||
0.41740839680521646f, -2.0979181310103074f, 1.1494564006889283f, 0.5059893282486726f };
|
||||
0.41740839680521646f, -2.0979181310103074f, 1.1494564006889283f, 0.5059893282486726f
|
||||
};
|
||||
|
||||
constexpr std::array<float, 64> floatOutputLow05 = {
|
||||
-0.27491385034007587f, -0.7098571028952849f, -0.32360008629382064f, 0.14076966108257558f,
|
||||
|
|
@ -146,7 +150,8 @@ constexpr std::array<float, 64> floatOutputLow05 = {
|
|||
0.02703177262292994f, -0.4302483791937005f, -0.8242150568318073f, -0.5613071175858801f,
|
||||
-0.18242012613484115f, -0.7864063306935144f, -0.5699248015820677f, -0.22777163691884944f,
|
||||
-0.46302715105340697f, -0.5577333737150487f, -0.311615923169504f, 0.001667198557366828f,
|
||||
0.05392379743179307f, -0.5421953122577658f, -0.49688568085971485f, 0.3861866826926287f };
|
||||
0.05392379743179307f, -0.5421953122577658f, -0.49688568085971485f, 0.3861866826926287f
|
||||
};
|
||||
|
||||
constexpr std::array<float, 64> floatOutputHigh05 = {
|
||||
-0.5498277006801517f, -0.32005880443026635f, 1.0925728376331951f, -0.1638333428804025f,
|
||||
|
|
@ -164,7 +169,8 @@ constexpr std::array<float, 64> floatOutputHigh05 = {
|
|||
-0.6408128638480202f, -0.27374743978524096f, -0.5141859154909728f, 1.040001793982827f,
|
||||
-0.2822278110807488f, -0.9257445980365978f, 1.358707656259491f, -0.6744013269330547f,
|
||||
0.20389029866393948f, -0.3933027439872231f, 0.8855376450783126f, -0.2589714016245709f,
|
||||
0.36348459937342337f, -1.5557228187525416f, 1.6463420815486431f, 0.11980264555604392f };
|
||||
0.36348459937342337f, -1.5557228187525416f, 1.6463420815486431f, 0.11980264555604392f
|
||||
};
|
||||
|
||||
constexpr std::array<float, 64> floatInput09 = {
|
||||
-0.9629663717342508f, 1.054078826032172f, -1.0644939081323097f, -0.05328934531304567f,
|
||||
|
|
@ -182,7 +188,8 @@ constexpr std::array<float, 64> floatInput09 = {
|
|||
0.7517403248613556f, 1.1194691465807607f, -1.1160170942539855f, -1.0010374555669668f,
|
||||
2.1609909686692763f, -0.07213993925443297f, -0.5083174992310037f, -0.7489925703250175f,
|
||||
0.5119124853257149f, -0.33950253799120345f, -0.26764774112191847f, 0.10271208568438035f,
|
||||
-0.09893862035889031f, -0.4154625911342657f, 0.11272544601558693f, -0.6895075000870634f };
|
||||
-0.09893862035889031f, -0.4154625911342657f, 0.11272544601558693f, -0.6895075000870634f
|
||||
};
|
||||
|
||||
constexpr std::array<float, 64> floatOutputLow09 = {
|
||||
-0.45614196555832937f, 0.01915105911173487f, -0.003925509462605503f, -0.5296828837089897f,
|
||||
|
|
@ -200,7 +207,8 @@ constexpr std::array<float, 64> floatOutputLow09 = {
|
|||
1.3518864464016498f, 0.9575142994410892f, 0.0520306721253716f, -1.0000768566454319f,
|
||||
0.496816040067124f, 1.015603963410564f, -0.22150068331359823f, -0.6072258583851468f,
|
||||
-0.14426034859888792f, 0.07407521986377441f, -0.2836988048502276f, -0.09305893177831953f,
|
||||
-0.003110407570995219f, -0.24382743742154736f, -0.15623482860471877f, -0.28143543764463197f };
|
||||
-0.003110407570995219f, -0.24382743742154736f, -0.15623482860471877f, -0.28143543764463197f
|
||||
};
|
||||
|
||||
constexpr std::array<float, 64> floatOutputHigh09 = {
|
||||
-0.5068244061759215f, 1.034927766920437f, -1.0605683986697043f, 0.47639353839594406f,
|
||||
|
|
@ -218,7 +226,8 @@ constexpr std::array<float, 64> floatOutputHigh09 = {
|
|||
-0.6001461215402942f, 0.16195484713967145f, -1.1680477663793571f, -0.0009605989215348831f,
|
||||
1.6641749286021523f, -1.087743902664997f, -0.28681681591740543f, -0.14176671193987078f,
|
||||
0.6561728339246028f, -0.41357775785497786f, 0.016051063728309112f, 0.19577101746269987f,
|
||||
-0.09582821278789509f, -0.17163515371271834f, 0.2689602746203057f, -0.40807206244243144f };
|
||||
-0.09582821278789509f, -0.17163515371271834f, 0.2689602746203057f, -0.40807206244243144f
|
||||
};
|
||||
|
||||
constexpr std::array<double, 64> doubleInput01 = {
|
||||
0.7224561488760388, 0.7385973866948313, -0.7270493193023231, -0.10016187172526334,
|
||||
|
|
@ -236,7 +245,8 @@ constexpr std::array<double, 64> doubleInput01 = {
|
|||
1.1666758495956464, -0.04382336233428379, 0.43819763320865857, 0.1740610608056625,
|
||||
0.30473671729007396, -0.4065881153810866, -0.9784770671900811, -0.17674381857142665,
|
||||
0.3493213284003123, -1.2540491577273034, 1.2597719140599792, 0.4198847510851298,
|
||||
0.9612865621570132, -1.5614809857797225, -0.31416474166626646, -1.4741449502960542 };
|
||||
0.9612865621570132, -1.5614809857797225, -0.31416474166626646, -1.4741449502960542
|
||||
};
|
||||
|
||||
constexpr std::array<double, 64> doubleOutputLow01 = {
|
||||
0.06567783171600353, 0.18655945645590016, 0.15368937959051, 0.05054483866245487,
|
||||
|
|
@ -254,7 +264,8 @@ constexpr std::array<double, 64> doubleOutputLow01 = {
|
|||
0.09460636244101792, 0.17948270447550216, 0.18270169192308128, 0.20514308375655024,
|
||||
0.21137141199133533, 0.16368102816645502, 0.008005824629720673, -0.0984698603721838,
|
||||
-0.06487738486552441, -0.13532948119242824, -0.11020387039992532, 0.06252925741325283,
|
||||
0.1767213299964926, 0.0900270496677931, -0.09685475276689556, -0.24181840607858007 };
|
||||
0.1767213299964926, 0.0900270496677931, -0.09685475276689556, -0.24181840607858007
|
||||
};
|
||||
|
||||
constexpr std::array<double, 64> doubleOutputHigh01 = {
|
||||
0.6567783171600353, 0.5520379302389311, -0.8807386988928331, -0.1507067103877182,
|
||||
|
|
@ -272,7 +283,8 @@ constexpr std::array<double, 64> doubleOutputHigh01 = {
|
|||
1.0720694871546286, -0.22330606680978596, 0.2554959412855773, -0.031082022950887744,
|
||||
0.09336530529873863, -0.5702691435475415, -0.9864828918198018, -0.07827395819924285,
|
||||
0.41419871326583674, -1.1187196765348753, 1.3699757844599045, 0.35735549367187697,
|
||||
0.7845652321605207, -1.6515080354475156, -0.2173099888993709, -1.2323265442174742 };
|
||||
0.7845652321605207, -1.6515080354475156, -0.2173099888993709, -1.2323265442174742
|
||||
};
|
||||
|
||||
constexpr std::array<double, 64> doubleInput05 = {
|
||||
-0.8247415510202276, -1.0299159073255513, 0.7689727513393745, -0.023063681797826918,
|
||||
|
|
@ -290,7 +302,8 @@ constexpr std::array<double, 64> doubleInput05 = {
|
|||
-0.6137810912250902, -0.7039958189789415, -1.33840097232278, 0.4786946763969468,
|
||||
-0.46464793721558995, -1.7121509287301122, 0.7887828546774234, -0.902172963851904,
|
||||
-0.2591368523894675, -0.9510361177022718, 0.5739217219088085, -0.25730420306720403,
|
||||
0.41740839680521646, -2.0979181310103074, 1.1494564006889283, 0.5059893282486726 };
|
||||
0.41740839680521646, -2.0979181310103074, 1.1494564006889283, 0.5059893282486726
|
||||
};
|
||||
|
||||
constexpr std::array<double, 64> doubleOutputLow05 = {
|
||||
-0.27491385034007587, -0.7098571028952849, -0.32360008629382064, 0.14076966108257558,
|
||||
|
|
@ -308,7 +321,8 @@ constexpr std::array<double, 64> doubleOutputLow05 = {
|
|||
0.02703177262292994, -0.4302483791937005, -0.8242150568318073, -0.5613071175858801,
|
||||
-0.18242012613484115, -0.7864063306935144, -0.5699248015820677, -0.22777163691884944,
|
||||
-0.46302715105340697, -0.5577333737150487, -0.311615923169504, 0.001667198557366828,
|
||||
0.05392379743179307, -0.5421953122577658, -0.49688568085971485, 0.3861866826926287 };
|
||||
0.05392379743179307, -0.5421953122577658, -0.49688568085971485, 0.3861866826926287
|
||||
};
|
||||
|
||||
constexpr std::array<double, 64> doubleOutputHigh05 = {
|
||||
-0.5498277006801517, -0.32005880443026635, 1.0925728376331951, -0.1638333428804025,
|
||||
|
|
@ -326,7 +340,8 @@ constexpr std::array<double, 64> doubleOutputHigh05 = {
|
|||
-0.6408128638480202, -0.27374743978524096, -0.5141859154909728, 1.040001793982827,
|
||||
-0.2822278110807488, -0.9257445980365978, 1.358707656259491, -0.6744013269330547,
|
||||
0.20389029866393948, -0.3933027439872231, 0.8855376450783126, -0.2589714016245709,
|
||||
0.36348459937342337, -1.5557228187525416, 1.6463420815486431, 0.11980264555604392 };
|
||||
0.36348459937342337, -1.5557228187525416, 1.6463420815486431, 0.11980264555604392
|
||||
};
|
||||
|
||||
constexpr std::array<double, 64> doubleInput09 = {
|
||||
-0.9629663717342508, 1.054078826032172, -1.0644939081323097, -0.05328934531304567,
|
||||
|
|
@ -344,7 +359,8 @@ constexpr std::array<double, 64> doubleInput09 = {
|
|||
0.7517403248613556, 1.1194691465807607, -1.1160170942539855, -1.0010374555669668,
|
||||
2.1609909686692763, -0.07213993925443297, -0.5083174992310037, -0.7489925703250175,
|
||||
0.5119124853257149, -0.33950253799120345, -0.26764774112191847, 0.10271208568438035,
|
||||
-0.09893862035889031, -0.4154625911342657, 0.11272544601558693, -0.6895075000870634 };
|
||||
-0.09893862035889031, -0.4154625911342657, 0.11272544601558693, -0.6895075000870634
|
||||
};
|
||||
|
||||
constexpr std::array<double, 64> doubleOutputLow09 = {
|
||||
-0.45614196555832937, 0.01915105911173487, -0.003925509462605503, -0.5296828837089897,
|
||||
|
|
@ -362,7 +378,8 @@ constexpr std::array<double, 64> doubleOutputLow09 = {
|
|||
1.3518864464016498, 0.9575142994410892, 0.0520306721253716, -1.0000768566454319,
|
||||
0.496816040067124, 1.015603963410564, -0.22150068331359823, -0.6072258583851468,
|
||||
-0.14426034859888792, 0.07407521986377441, -0.2836988048502276, -0.09305893177831953,
|
||||
-0.003110407570995219, -0.24382743742154736, -0.15623482860471877, -0.28143543764463197 };
|
||||
-0.003110407570995219, -0.24382743742154736, -0.15623482860471877, -0.28143543764463197
|
||||
};
|
||||
|
||||
constexpr std::array<double, 64> doubleOutputHigh09 = {
|
||||
-0.5068244061759215, 1.034927766920437, -1.0605683986697043, 0.47639353839594406,
|
||||
|
|
@ -380,7 +397,8 @@ constexpr std::array<double, 64> doubleOutputHigh09 = {
|
|||
-0.6001461215402942, 0.16195484713967145, -1.1680477663793571, -0.0009605989215348831,
|
||||
1.6641749286021523, -1.087743902664997, -0.28681681591740543, -0.14176671193987078,
|
||||
0.6561728339246028, -0.41357775785497786, 0.016051063728309112, 0.19577101746269987,
|
||||
-0.09582821278789509, -0.17163515371271834, 0.2689602746203057, -0.40807206244243144 };
|
||||
-0.09582821278789509, -0.17163515371271834, 0.2689602746203057, -0.40807206244243144
|
||||
};
|
||||
|
||||
TEST_CASE("[OnePoleFilter] Tests")
|
||||
{
|
||||
Loading…
Add table
Reference in a new issue