From 0ed1f4cbebafcca3059a747b5bbca837d70bc067 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Tue, 31 Mar 2020 20:13:13 +0200 Subject: [PATCH] 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 --- benchmarks/BM_envelopes.cpp | 10 +- benchmarks/BM_filterModulation.cpp | 1 + benchmarks/BM_smoothers.cpp | 57 +++ benchmarks/BM_vaFilters.cpp | 59 +++ benchmarks/CMakeLists.txt | 2 + src/CMakeLists.txt | 1 + src/sfizz/Config.h | 4 + src/sfizz/Defaults.h | 4 +- src/sfizz/MathHelpers.h | 6 +- src/sfizz/ModifierHelpers.h | 3 +- src/sfizz/Modifiers.h | 54 ++ src/sfizz/Region.cpp | 21 +- src/sfizz/Region.h | 19 +- src/sfizz/SfzHelpers.h | 35 +- src/sfizz/Smoothers.cpp | 30 ++ src/sfizz/Smoothers.h | 24 + src/sfizz/Synth.cpp | 5 + src/sfizz/Voice.cpp | 156 ++++-- src/sfizz/Voice.h | 23 + tests/CMakeLists.txt | 1 + tests/FilesT.cpp | 175 +++---- tests/RegionT.cpp | 493 ++++++++++--------- tests/{OnePoleFilterT.cpp => SmoothersT.cpp} | 60 ++- 23 files changed, 798 insertions(+), 445 deletions(-) create mode 100644 benchmarks/BM_smoothers.cpp create mode 100644 benchmarks/BM_vaFilters.cpp create mode 100644 src/sfizz/Modifiers.h create mode 100644 src/sfizz/Smoothers.cpp create mode 100644 src/sfizz/Smoothers.h rename tests/{OnePoleFilterT.cpp => SmoothersT.cpp} (97%) diff --git a/benchmarks/BM_envelopes.cpp b/benchmarks/BM_envelopes.cpp index dc470e45..bbb75fb6 100644 --- a/benchmarks/BM_envelopes.cpp +++ b/benchmarks/BM_envelopes.cpp @@ -46,9 +46,8 @@ BENCHMARK_DEFINE_F(EnvelopeFixture, Linear)(benchmark::State& state) { } } -BENCHMARK_DEFINE_F(EnvelopeFixture, LinearNoEvent)(benchmark::State& state) { - for (auto _ : state) - { +BENCHMARK_DEFINE_F(EnvelopeFixture, LinearNoEvent) (benchmark::State& state) { + for (auto _ : state) { sfz::EventVector events { { 0, dist(gen) } }; @@ -79,9 +78,8 @@ BENCHMARK_DEFINE_F(EnvelopeFixture, Multiplicative)(benchmark::State& state) { } } -BENCHMARK_DEFINE_F(EnvelopeFixture, MultiplicativeNoEvent)(benchmark::State& state) { - for (auto _ : state) - { +BENCHMARK_DEFINE_F(EnvelopeFixture, MultiplicativeNoEvent) (benchmark::State& state) { + for (auto _ : state) { sfz::EventVector events { { 0, dist(gen) } }; diff --git a/benchmarks/BM_filterModulation.cpp b/benchmarks/BM_filterModulation.cpp index f97a9b54..caa4eebf 100644 --- a/benchmarks/BM_filterModulation.cpp +++ b/benchmarks/BM_filterModulation.cpp @@ -7,6 +7,7 @@ #include "SIMDHelpers.h" #include "OnePoleFilter.h" #include "SfzFilter.h" +#include "SfzHelpers.h" #include "ScopedFTZ.h" #include "SfzHelpers.h" #include diff --git a/benchmarks/BM_smoothers.cpp b/benchmarks/BM_smoothers.cpp new file mode 100644 index 00000000..920fa808 --- /dev/null +++ b/benchmarks/BM_smoothers.cpp @@ -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 +#include +#include +#include +#include +#include +#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(state.range(0)); + output = std::vector(state.range(0)); + std::generate(input.begin(), input.end(), [&]() { return dist(gen); }); + sfz::cumsum(input, absl::MakeSpan(input)); + } + + void TearDown(const ::benchmark::State& /* state */) + { + } + std::random_device rd {}; + std::mt19937 gen { rd() }; + std::uniform_real_distribution dist { 0.5, 4 }; + std::vector input; + std::vector 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(); diff --git a/benchmarks/BM_vaFilters.cpp b/benchmarks/BM_vaFilters.cpp new file mode 100644 index 00000000..2a04fe63 --- /dev/null +++ b/benchmarks/BM_vaFilters.cpp @@ -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 +#include +#include +#include +#include +#include + +constexpr int blockSize { 256 }; +constexpr float sampleRate { 48000.0f }; + +class FilterFixture : public benchmark::Fixture { +public: + void SetUp(const ::benchmark::State&) + { + input = std::vector(blockSize); + output = std::vector(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 dist { 1, 0.2 }; + std::vector input; + std::vector output; +}; + +BENCHMARK_DEFINE_F(FilterFixture, OnePole_VA) (benchmark::State& state) +{ + ScopedFTZ ftz; + sfz::OnePoleFilter filter; + for (auto _ : state) { + filter.processLowpass(input, absl::MakeSpan(output)); + } +} + +BENCHMARK_DEFINE_F(FilterFixture, OnePoleMul_VA) (benchmark::State& state) +{ + ScopedFTZ ftz; + sfz::OnePoleFilterMul filter; + for (auto _ : state) { + filter.processLowpass(input, absl::MakeSpan(output)); + } +} +BENCHMARK_REGISTER_F(FilterFixture, OnePole_VA); +BENCHMARK_REGISTER_F(FilterFixture, OnePoleMul_VA); +BENCHMARK_MAIN(); diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index d36e4547..3c0082a1 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -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}) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a75f96db..67c3b36f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/sfizz/Config.h b/src/sfizz/Config.h index 4b0a5b67..17e5d07c 100644 --- a/src/sfizz/Config.h +++ b/src/sfizz/Config.h @@ -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 }; diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 0b92670c..defb675b 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -82,8 +82,9 @@ namespace Default // Region logic: MIDI conditions constexpr Range channelRange { 1, 16 }; constexpr Range midiChannelRange { 0, 15 }; - constexpr Range stepCCRange { 0, 127 }; + constexpr Range stepCCRange { 0, 127 }; constexpr Range smoothCCRange { 0, 127 }; + constexpr float smoothTauPerStep { 3e-3 }; constexpr Range curveCCRange { 0, 255 }; constexpr Range 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 }; diff --git a/src/sfizz/MathHelpers.h b/src/sfizz/MathHelpers.h index b77ee5ee..70ce204a 100644 --- a/src/sfizz/MathHelpers.h +++ b/src/sfizz/MathHelpers.h @@ -254,6 +254,11 @@ constexpr Type sqrtTwo() { return static_cast(1.41421356237309504880168872 template constexpr Type sqrtTwoInv() { return static_cast(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& span1, Others... others) #define CHECK_SPAN_SIZES(...) SFIZZ_CHECK(checkSpanSizes(__VA_ARGS__)) - class ScopedRoundingMode { public: ScopedRoundingMode() = delete; diff --git a/src/sfizz/ModifierHelpers.h b/src/sfizz/ModifierHelpers.h index e3d8006e..f853b136 100644 --- a/src/sfizz/ModifierHelpers.h +++ b/src/sfizz/ModifierHelpers.h @@ -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, ...) */ diff --git a/src/sfizz/Modifiers.h b/src/sfizz/Modifiers.h new file mode 100644 index 00000000..1de3405e --- /dev/null +++ b/src/sfizz/Modifiers.h @@ -0,0 +1,54 @@ +#pragma once +#include +#include +#include + +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::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 ModifierVector : public std::vector { +public: + T& operator[](sfz::Mod idx) { return this->std::vector::operator[](static_cast(idx)); } + const T& operator[](sfz::Mod idx) const { return this->std::vector::operator[](static_cast(idx)); } +}; + +template +class ModifierArray : public std::array { +public: + T& operator[](sfz::Mod idx) { return this->std::array::operator[](static_cast(idx)); } + const T& operator[](sfz::Mod idx) const { return this->std::array::operator[](static_cast(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 allModifiers = {{ + Mod::amplitude, + Mod::pan, + Mod::width, + Mod::position, + Mod::pitch, + Mod::volume +}}; + +} diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 73dff35a..5084c221 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -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(bendUp) : -bend * static_cast(bendDown); + return centsFactor(bendInCents); +} diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index e363116b..3b09232c 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -17,6 +17,7 @@ #include "MidiState.h" #include "FileId.h" #include "NumericId.h" +#include "Modifiers.h" #include "absl/types/optional.h" #include #include @@ -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 volumeCC { {} }; // volume_oncc - CCMap amplitudeCC { {} }; // amplitude_oncc - CCMap panCC { {} }; // pan_oncc - CCMap widthCC { {} }; // width_oncc - CCMap 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 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 gainToEffect; + // Modifiers + ModifierArray> modifiers; + private: const MidiState& midiState; bool keySwitched { true }; diff --git a/src/sfizz/SfzHelpers.h b/src/sfizz/SfzHelpers.h index 43060eaa..191812e4 100644 --- a/src/sfizz/SfzHelpers.h +++ b/src/sfizz/SfzHelpers.h @@ -17,29 +17,20 @@ #include "absl/meta/type_traits.h" #include "Defaults.h" -namespace sfz -{ +namespace sfz { using CCNamePair = std::pair; using NoteNamePair = std::pair; template using MidiNoteArray = std::array; -template +template struct CCData { int cc; ValueType data; static_assert(config::numCCs - 1 < std::numeric_limits::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::max(), "The curve type in the Modifier struct cannot support the required number of curves"); -}; - template struct CCDataComparator { bool operator()(const CCData& ccData, const int& cc) @@ -106,13 +97,13 @@ struct MidiEventValueComparator { * @param centsPerOctave * @return constexpr float */ -template +template constexpr float centsFactor(T cents, T centsPerOctave = 1200) { return std::pow(2.0f, static_cast(cents) / centsPerOctave); } -template::value, int> = 0> +template ::value, int> = 0> constexpr T denormalize7Bits(float value) { return static_cast(value * 127.0f); @@ -128,10 +119,10 @@ constexpr uint8_t denormalizeVelocity(float value) return denormalize7Bits(value); } -template +template constexpr float normalize7Bits(T value) { - return static_cast(min(max(value, T{ 0 }), T{ 127 })) / 127.0f; + return static_cast(min(max(value, T { 0 }), T { 127 })) / 127.0f; } /** @@ -141,7 +132,7 @@ constexpr float normalize7Bits(T value) * @param ccValue * @return constexpr float */ -template +template constexpr float normalizeCC(T ccValue) { return normalize7Bits(ccValue); @@ -154,13 +145,12 @@ constexpr float normalizeCC(T ccValue) * @param ccValue * @return constexpr float */ -template +template constexpr float normalizeVelocity(T velocity) { return normalize7Bits(velocity); } - /** * @brief Normalize a percentage between 0 and 1 * @@ -168,7 +158,7 @@ constexpr float normalizeVelocity(T velocity) * @param percentValue * @return constexpr float */ -template +template constexpr float normalizePercents(T percentValue) { return percentValue * 0.01f; @@ -212,6 +202,12 @@ inline CXX14_CONSTEXPR Type vaGain(Type cutoff, Type sampleRate) return std::tan(cutoff / sampleRate * pi()); } +template +inline CXX14_CONSTEXPR Type vaGain(Type cutoff, Type sampleRate) +{ + return std::tan(cutoff / sampleRate * pi()); +} + /** * @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 - diff --git a/src/sfizz/Smoothers.cpp b/src/sfizz/Smoothers.cpp new file mode 100644 index 00000000..9f40b67d --- /dev/null +++ b/src/sfizz/Smoothers.cpp @@ -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 input, absl::Span output) +{ + if (smoothing) + filter.processLowpass(input, output); + else + copy(input, output); +} + +} diff --git a/src/sfizz/Smoothers.h b/src/sfizz/Smoothers.h new file mode 100644 index 00000000..4793f423 --- /dev/null +++ b/src/sfizz/Smoothers.h @@ -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 + +namespace sfz { +class Smoother { +public: + Smoother(); + void setSmoothing(uint8_t smoothValue, float sampleRate); + void reset(float value = 0.0f); + void process(absl::Span input, absl::Span output); + +private: + bool smoothing { false }; + OnePoleFilter filter {}; +}; + +} diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 422e922b..49c3c3db 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -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 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); } } diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 63a723de..d6033dd1 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -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(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& 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 modulationSpan) noexcept // Amplitude envelope applyGain1(baseGain, modulationSpan); - for (const auto& mod : region->amplitudeCC) { + forEachWithSmoother(Mod::amplitude, [&](const CCData& mod, Smoother& smoother) { linearModifier(resources, *tempSpan, mod, normalizePercents); + smoother.process(*tempSpan, *tempSpan); applyGain(*tempSpan, modulationSpan); - } + }); // Crossfade envelopes for (const auto& mod : region->crossfadeCCInRange) { @@ -306,12 +330,16 @@ void sfz::Voice::amplitudeEnvelope(absl::Span modulationSpan) noexcept // Volume envelope applyGain1(db2mag(baseVolumedB), modulationSpan); - for (const auto& mod : region->volumeCC) { + forEachWithSmoother(Mod::volume, [&](const CCData& mod, Smoother& smoother) { multiplicativeModifier(resources, *tempSpan, mod, [](float x) { return db2mag(x); }); + smoother.process(*tempSpan, *tempSpan); applyGain(*tempSpan, modulationSpan); - } + }); + + // Smooth the gain transitions + gainSmoother.process(modulationSpan, modulationSpan); } void sfz::Voice::ampStageMono(AudioSpan buffer) noexcept @@ -360,10 +388,11 @@ void sfz::Voice::panStageMono(AudioSpan buffer) noexcept // Apply panning fill(*modulationSpan, region->pan); - for (const auto& mod : region->panCC) { + forEachWithSmoother(Mod::pan, [&](const CCData& mod, Smoother& smoother) { linearModifier(resources, *tempSpan, mod, normalizePercents); + smoother.process(*tempSpan, *tempSpan); add(*tempSpan, *modulationSpan); - } + }); pan(*modulationSpan, leftBuffer, rightBuffer); } @@ -381,25 +410,28 @@ void sfz::Voice::panStageStereo(AudioSpan buffer) noexcept // Apply panning fill(*modulationSpan, region->pan); - for (const auto& mod : region->panCC) { + forEachWithSmoother(Mod::pan, [&](const CCData& mod, Smoother& smoother) { linearModifier(resources, *tempSpan, mod, normalizePercents); + smoother.process(*tempSpan, *tempSpan); add(*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& mod, Smoother& smoother) { linearModifier(resources, *tempSpan, mod, normalizePercents); + smoother.process(*tempSpan, *tempSpan); add(*tempSpan, *modulationSpan); - } + }); width(*modulationSpan, leftBuffer, rightBuffer); fill(*modulationSpan, region->position); - for (const auto& mod : region->positionCC) { + forEachWithSmoother(Mod::position, [&](const CCData& mod, Smoother& smoother) { linearModifier(resources, *tempSpan, mod, normalizePercents); + smoother.process(*tempSpan, *tempSpan); add(*tempSpan, *modulationSpan); - } + }); pan(*modulationSpan, leftBuffer, rightBuffer); } @@ -452,30 +484,13 @@ void sfz::Voice::fillWithData(AudioSpan 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(region->bendUp) : -bend * static_cast(region->bendDown); - return centsFactor(bendInCents); - }; - - if (region->bendStep > 1) - pitchBendEnvelope(events, *bends, bendLambda, bendStepFactor); - else - pitchBendEnvelope(events, *bends, bendLambda); - applyGain(*bends, *jumps); - - for (const auto& mod : region->tuneCC) { - multiplicativeModifier(resources, *bends, mod, [](float x) { return centsFactor(x); }); - applyGain(*bends, *jumps); - } + pitchEnvelope(*jumps); jumps->front() += floatPositionOffset; cumsum(*jumps, *jumps); @@ -584,30 +599,12 @@ void sfz::Voice::fillWithGenerator(AudioSpan 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(region->bendUp) : -bend * static_cast(region->bendDown); - return centsFactor(bendInCents); - }; - if (region->bendStep > 1) - pitchBendEnvelope(events, *bends, bendLambda, bendStepFactor); - else - pitchBendEnvelope(events, *bends, bendLambda); - applyGain(*bends, *frequencies); - - for (const auto& mod : region->tuneCC) { - multiplicativeModifier(resources, *bends, mod, [](float x) { - return centsFactor(x); - }); - applyGain(*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 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& numModifiers) +{ + for (auto& mod : allModifiers) + modifierSmoothers[mod].resize(numModifiers[mod]); +} + +void sfz::Voice::pitchEnvelope(absl::Span 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(*bends, pitchSpan); + + forEachWithSmoother(Mod::pitch, [&](const CCData& mod, Smoother& smoother) { + multiplicativeModifier(resources, *bends, mod, [](float x) { + return centsFactor(x); + }); + smoother.process(*bends, *bends); + applyGain(*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); +} diff --git a/src/sfizz/Voice.h b/src/sfizz/Voice.h index 450f8c0c..adbe7d81 100644 --- a/src/sfizz/Voice.h +++ b/src/sfizz/Voice.h @@ -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& 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 buffer) noexcept; void filterStageMono(AudioSpan buffer) noexcept; void filterStageStereo(AudioSpan buffer) noexcept; + void pitchEnvelope(absl::Span pitchSpan) noexcept; /** * @brief Remove the voice from the sister ring * */ void removeVoiceFromRing() noexcept; + + template + 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 noiseDist { 0, config::noiseVariance }; + ModifierArray> modifierSmoothers; + Smoother gainSmoother; + Smoother bendSmoother; + void resetSmoothers() noexcept; + std::array, 2> channelEnvelopeFilters; std::array smoothedChannelEnvelopes; + + HistoricalBuffer powerHistory { config::powerHistoryLength }; LEAK_DETECTOR(Voice); }; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index eb7303db..d3f32fe4 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -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 diff --git a/tests/FilesT.cpp b/tests/FilesT.cpp index b64264db..8d85b23a 100644 --- a/tests/FilesT.cpp +++ b/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(2, 14)); + REQUIRE(synth.getRegionView(0)->keyRange == Range(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(36, 36)); - REQUIRE(synth.getRegionView(1)->keyRange == sfz::Range(38, 38)); - REQUIRE(synth.getRegionView(2)->keyRange == sfz::Range(42, 42)); + REQUIRE(synth.getRegionView(0)->keyRange == Range(36, 36)); + REQUIRE(synth.getRegionView(1)->keyRange == Range(38, 38)); + REQUIRE(synth.getRegionView(2)->keyRange == Range(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(36, 36)); + REQUIRE(synth.getRegionView(i)->keyRange == Range(36, 36)); } - REQUIRE(synth.getRegionView(0)->velocityRange == sfz::Range(1_norm, 26_norm)); - REQUIRE(synth.getRegionView(1)->velocityRange == sfz::Range(27_norm, 52_norm)); - REQUIRE(synth.getRegionView(2)->velocityRange == sfz::Range(53_norm, 77_norm)); - REQUIRE(synth.getRegionView(3)->velocityRange == sfz::Range(78_norm, 102_norm)); - REQUIRE(synth.getRegionView(4)->velocityRange == sfz::Range(103_norm, 127_norm)); + REQUIRE(synth.getRegionView(0)->velocityRange == Range(1_norm, 26_norm)); + REQUIRE(synth.getRegionView(1)->velocityRange == Range(27_norm, 52_norm)); + REQUIRE(synth.getRegionView(2)->velocityRange == Range(53_norm, 77_norm)); + REQUIRE(synth.getRegionView(3)->velocityRange == Range(78_norm, 102_norm)); + REQUIRE(synth.getRegionView(4)->velocityRange == Range(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(60, 60)); + REQUIRE(synth.getRegionView(0)->keyRange == Range(60, 60)); REQUIRE(synth.getRegionView(1)->pan == 0.3_a); REQUIRE(synth.getRegionView(1)->delay == 67); - REQUIRE(synth.getRegionView(1)->keyRange == sfz::Range(61, 61)); + REQUIRE(synth.getRegionView(1)->keyRange == Range(61, 61)); REQUIRE(synth.getRegionView(2)->pan == 0.3_a); REQUIRE(synth.getRegionView(2)->delay == 56); - REQUIRE(synth.getRegionView(2)->keyRange == sfz::Range(50, 50)); + REQUIRE(synth.getRegionView(2)->keyRange == Range(50, 50)); REQUIRE(synth.getRegionView(3)->pan == 0.3_a); REQUIRE(synth.getRegionView(3)->delay == 56); - REQUIRE(synth.getRegionView(3)->keyRange == sfz::Range(51, 51)); + REQUIRE(synth.getRegionView(3)->keyRange == Range(51, 51)); REQUIRE(synth.getRegionView(4)->pan == -0.1_a); REQUIRE(synth.getRegionView(4)->delay == 47); - REQUIRE(synth.getRegionView(4)->keyRange == sfz::Range(40, 40)); + REQUIRE(synth.getRegionView(4)->keyRange == Range(40, 40)); REQUIRE(synth.getRegionView(5)->pan == -0.1_a); REQUIRE(synth.getRegionView(5)->delay == 47); - REQUIRE(synth.getRegionView(5)->keyRange == sfz::Range(41, 41)); + REQUIRE(synth.getRegionView(5)->keyRange == Range(41, 41)); REQUIRE(synth.getRegionView(6)->pan == -0.1_a); REQUIRE(synth.getRegionView(6)->delay == 36); - REQUIRE(synth.getRegionView(6)->keyRange == sfz::Range(30, 30)); + REQUIRE(synth.getRegionView(6)->keyRange == Range(30, 30)); REQUIRE(synth.getRegionView(7)->pan == -0.1_a); REQUIRE(synth.getRegionView(7)->delay == 36); - REQUIRE(synth.getRegionView(7)->keyRange == sfz::Range(31, 31)); + REQUIRE(synth.getRegionView(7)->keyRange == Range(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(12, 22)); - REQUIRE(synth.getRegionView(i)->velocityRange == sfz::Range(97_norm, 127_norm)); + REQUIRE(synth.getRegionView(i)->keyRange == Range(12, 22)); + REQUIRE(synth.getRegionView(i)->velocityRange == Range(97_norm, 127_norm)); REQUIRE(synth.getRegionView(i)->pitchKeycenter == 21); - REQUIRE(synth.getRegionView(i)->ccConditions.getWithDefault(107) == sfz::Range(0_norm, 13_norm)); + REQUIRE(synth.getRegionView(i)->ccConditions.getWithDefault(107) == Range(0_norm, 13_norm)); } - REQUIRE(synth.getRegionView(0)->randRange == sfz::Range(0, 0.25)); - REQUIRE(synth.getRegionView(1)->randRange == sfz::Range(0.25, 0.5)); - REQUIRE(synth.getRegionView(2)->randRange == sfz::Range(0.5, 0.75)); - REQUIRE(synth.getRegionView(3)->randRange == sfz::Range(0.75, 1.0)); + REQUIRE(synth.getRegionView(0)->randRange == Range(0, 0.25)); + REQUIRE(synth.getRegionView(1)->randRange == Range(0.25, 0.5)); + REQUIRE(synth.getRegionView(2)->randRange == Range(0.5, 0.75)); + REQUIRE(synth.getRegionView(3)->randRange == Range(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(64, 64) ); + REQUIRE(synth.getRegionView(0)->keyRange == Range(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(51, 56) ); + REQUIRE(synth.getRegionView(1)->keyRange == Range(51, 56)); REQUIRE( synth.getRegionView(1)->pitchKeycenter == 51 ); - REQUIRE( synth.getRegionView(2)->keyRange == sfz::Range(41, 45) ); + REQUIRE(synth.getRegionView(2)->keyRange == Range(41, 45)); REQUIRE( synth.getRegionView(2)->pitchKeycenter == 41 ); - REQUIRE( synth.getRegionView(2)->crossfadeKeyInRange == sfz::Range(37, 41) ); - REQUIRE( synth.getRegionView(2)->crossfadeKeyOutRange == sfz::Range(45, 49) ); + REQUIRE(synth.getRegionView(2)->crossfadeKeyInRange == Range(37, 41)); + REQUIRE(synth.getRegionView(2)->crossfadeKeyOutRange == Range(45, 49)); - REQUIRE( synth.getRegionView(3)->keyRange == sfz::Range(62, 62) ); - REQUIRE( synth.getRegionView(3)->keyswitchRange == sfz::Range(23, 27) ); + REQUIRE(synth.getRegionView(3)->keyRange == Range(62, 62)); + REQUIRE(synth.getRegionView(3)->keyswitchRange == Range(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(76, 76) ); + REQUIRE(synth.getRegionView(4)->keyRange == Range(76, 76)); REQUIRE( synth.getRegionView(4)->pitchKeycenter == 76 ); - REQUIRE( synth.getRegionView(5)->keyRange == sfz::Range(50, 50) ); + REQUIRE(synth.getRegionView(5)->keyRange == Range(50, 50)); REQUIRE( synth.getRegionView(5)->pitchKeycenter == 50 ); - REQUIRE( synth.getRegionView(6)->keyRange == sfz::Range(50, 50) ); + REQUIRE(synth.getRegionView(6)->keyRange == Range(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 buffer(2, 256); + AudioBuffer 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 buffer { 2, 256 }; + AudioBuffer 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 buffer { 2, 256 }; + AudioBuffer 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{ 77554, 186581 } ); - REQUIRE( synth.getRegionView(1)->loopRange == sfz::Range{ 77554, 186581 } ); - REQUIRE( synth.getRegionView(2)->loopRange == sfz::Range{ 4, 124 } ); + REQUIRE(synth.getRegionView(0)->loopRange == Range { 77554, 186581 }); + REQUIRE(synth.getRegionView(1)->loopRange == Range { 77554, 186581 }); + REQUIRE(synth.getRegionView(2)->loopRange == Range { 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({})); diff --git a/tests/RegionT.cpp b/tests/RegionT.cpp index c683cd96..994f0bd9 100644 --- a/tests/RegionT.cpp +++ b/tests/RegionT.cpp @@ -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(0, 4294967295)); + REQUIRE(region.loopRange == Range(0, 4294967295)); region.parseOpcode({ "loop_end", "184" }); - REQUIRE(region.loopRange == sfz::Range(0, 184)); + REQUIRE(region.loopRange == Range(0, 184)); region.parseOpcode({ "loop_end", "-1" }); - REQUIRE(region.loopRange == sfz::Range(0, 0)); + REQUIRE(region.loopRange == Range(0, 0)); } SECTION("loop_start") { region.parseOpcode({ "loop_start", "184" }); - REQUIRE(region.loopRange == sfz::Range(184, 4294967295)); + REQUIRE(region.loopRange == Range(184, 4294967295)); region.parseOpcode({ "loop_start", "-1" }); - REQUIRE(region.loopRange == sfz::Range(0, 4294967295)); + REQUIRE(region.loopRange == Range(0, 4294967295)); } SECTION("loopend") { - REQUIRE(region.loopRange == sfz::Range(0, 4294967295)); + REQUIRE(region.loopRange == Range(0, 4294967295)); region.parseOpcode({ "loopend", "184" }); - REQUIRE(region.loopRange == sfz::Range(0, 184)); + REQUIRE(region.loopRange == Range(0, 184)); region.parseOpcode({ "loopend", "-1" }); - REQUIRE(region.loopRange == sfz::Range(0, 0)); + REQUIRE(region.loopRange == Range(0, 0)); } SECTION("loopstart") { region.parseOpcode({ "loopstart", "184" }); - REQUIRE(region.loopRange == sfz::Range(184, 4294967295)); + REQUIRE(region.loopRange == Range(184, 4294967295)); region.parseOpcode({ "loopstart", "-1" }); - REQUIRE(region.loopRange == sfz::Range(0, 4294967295)); + REQUIRE(region.loopRange == Range(0, 4294967295)); } SECTION("group") @@ -194,87 +195,87 @@ TEST_CASE("[Region] Parsing opcodes") SECTION("lokey, hikey, and key") { - REQUIRE(region.keyRange == sfz::Range(0, 127)); + REQUIRE(region.keyRange == Range(0, 127)); region.parseOpcode({ "lokey", "37" }); - REQUIRE(region.keyRange == sfz::Range(37, 127)); + REQUIRE(region.keyRange == Range(37, 127)); region.parseOpcode({ "lokey", "c4" }); - REQUIRE(region.keyRange == sfz::Range(60, 127)); + REQUIRE(region.keyRange == Range(60, 127)); region.parseOpcode({ "lokey", "128" }); - REQUIRE(region.keyRange == sfz::Range(127, 127)); + REQUIRE(region.keyRange == Range(127, 127)); region.parseOpcode({ "lokey", "-3" }); - REQUIRE(region.keyRange == sfz::Range(0, 127)); + REQUIRE(region.keyRange == Range(0, 127)); region.parseOpcode({ "hikey", "65" }); - REQUIRE(region.keyRange == sfz::Range(0, 65)); + REQUIRE(region.keyRange == Range(0, 65)); region.parseOpcode({ "hikey", "c4" }); - REQUIRE(region.keyRange == sfz::Range(0, 60)); + REQUIRE(region.keyRange == Range(0, 60)); region.parseOpcode({ "hikey", "-1" }); - REQUIRE(region.keyRange == sfz::Range(0, 0)); + REQUIRE(region.keyRange == Range(0, 0)); region.parseOpcode({ "hikey", "128" }); - REQUIRE(region.keyRange == sfz::Range(0, 127)); + REQUIRE(region.keyRange == Range(0, 127)); region.parseOpcode({ "key", "26" }); - REQUIRE(region.keyRange == sfz::Range(26, 26)); + REQUIRE(region.keyRange == Range(26, 26)); REQUIRE(region.pitchKeycenter == 26); region.parseOpcode({ "key", "-26" }); - REQUIRE(region.keyRange == sfz::Range(0, 0)); + REQUIRE(region.keyRange == Range(0, 0)); REQUIRE(region.pitchKeycenter == 0); region.parseOpcode({ "key", "234" }); - REQUIRE(region.keyRange == sfz::Range(127, 127)); + REQUIRE(region.keyRange == Range(127, 127)); REQUIRE(region.pitchKeycenter == 127); region.parseOpcode({ "key", "c4" }); - REQUIRE(region.keyRange == sfz::Range(60, 60)); + REQUIRE(region.keyRange == Range(60, 60)); REQUIRE(region.pitchKeycenter == 60); } SECTION("lovel, hivel") { - REQUIRE(region.velocityRange == sfz::Range(0_norm, 127_norm)); + REQUIRE(region.velocityRange == Range(0_norm, 127_norm)); region.parseOpcode({ "lovel", "37" }); - REQUIRE(region.velocityRange == sfz::Range(37_norm, 127_norm)); + REQUIRE(region.velocityRange == Range(37_norm, 127_norm)); region.parseOpcode({ "lovel", "128" }); - REQUIRE(region.velocityRange == sfz::Range(127_norm, 127_norm)); + REQUIRE(region.velocityRange == Range(127_norm, 127_norm)); region.parseOpcode({ "lovel", "-3" }); - REQUIRE(region.velocityRange == sfz::Range(0_norm, 127_norm)); + REQUIRE(region.velocityRange == Range(0_norm, 127_norm)); region.parseOpcode({ "hivel", "65" }); - REQUIRE(region.velocityRange == sfz::Range(0_norm, 65_norm)); + REQUIRE(region.velocityRange == Range(0_norm, 65_norm)); region.parseOpcode({ "hivel", "-1" }); - REQUIRE(region.velocityRange == sfz::Range(0_norm, 0_norm)); + REQUIRE(region.velocityRange == Range(0_norm, 0_norm)); region.parseOpcode({ "hivel", "128" }); - REQUIRE(region.velocityRange == sfz::Range(0_norm, 127_norm)); + REQUIRE(region.velocityRange == Range(0_norm, 127_norm)); } SECTION("lobend, hibend") { - REQUIRE(region.bendRange == sfz::Range(-1.0f, 1.0f)); + REQUIRE(region.bendRange == Range(-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(-1.0f, 1.0f)); + REQUIRE(region.bendRange == Range(-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(-1.0f, 1.0f)); + REQUIRE(region.bendRange == Range(-1.0f, 1.0f)); } SECTION("locc, hicc") { - REQUIRE(region.ccConditions.getWithDefault(0) == sfz::Range(0_norm, 127_norm)); - REQUIRE(region.ccConditions[127] == sfz::Range(0_norm, 127_norm)); + REQUIRE(region.ccConditions.getWithDefault(0) == Range(0_norm, 127_norm)); + REQUIRE(region.ccConditions[127] == Range(0_norm, 127_norm)); region.parseOpcode({ "locc6", "4" }); - REQUIRE(region.ccConditions[6] == sfz::Range(4_norm, 127_norm)); + REQUIRE(region.ccConditions[6] == Range(4_norm, 127_norm)); region.parseOpcode({ "locc12", "-128" }); - REQUIRE(region.ccConditions[12] == sfz::Range(0_norm, 127_norm)); + REQUIRE(region.ccConditions[12] == Range(0_norm, 127_norm)); region.parseOpcode({ "hicc65", "39" }); - REQUIRE(region.ccConditions[65] == sfz::Range(0_norm, 39_norm)); + REQUIRE(region.ccConditions[65] == Range(0_norm, 39_norm)); region.parseOpcode({ "hicc127", "135" }); - REQUIRE(region.ccConditions[127] == sfz::Range(0_norm, 127_norm)); + REQUIRE(region.ccConditions[127] == Range(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(0, 127)); + REQUIRE(region.keyswitchRange == Range(0, 127)); region.parseOpcode({ "sw_lokey", "4" }); - REQUIRE(region.keyswitchRange == sfz::Range(4, 127)); + REQUIRE(region.keyswitchRange == Range(4, 127)); region.parseOpcode({ "sw_lokey", "128" }); - REQUIRE(region.keyswitchRange == sfz::Range(127, 127)); + REQUIRE(region.keyswitchRange == Range(127, 127)); region.parseOpcode({ "sw_lokey", "0" }); - REQUIRE(region.keyswitchRange == sfz::Range(0, 127)); + REQUIRE(region.keyswitchRange == Range(0, 127)); region.parseOpcode({ "sw_hikey", "39" }); - REQUIRE(region.keyswitchRange == sfz::Range(0, 39)); + REQUIRE(region.keyswitchRange == Range(0, 39)); region.parseOpcode({ "sw_hikey", "135" }); - REQUIRE(region.keyswitchRange == sfz::Range(0, 127)); + REQUIRE(region.keyswitchRange == Range(0, 127)); region.parseOpcode({ "sw_hikey", "-1" }); - REQUIRE(region.keyswitchRange == sfz::Range(0, 0)); + REQUIRE(region.keyswitchRange == Range(0, 0)); } SECTION("sw_label") @@ -398,53 +399,53 @@ TEST_CASE("[Region] Parsing opcodes") SECTION("lochanaft, hichanaft") { - REQUIRE(region.aftertouchRange == sfz::Range(0, 127)); + REQUIRE(region.aftertouchRange == Range(0, 127)); region.parseOpcode({ "lochanaft", "4" }); - REQUIRE(region.aftertouchRange == sfz::Range(4, 127)); + REQUIRE(region.aftertouchRange == Range(4, 127)); region.parseOpcode({ "lochanaft", "128" }); - REQUIRE(region.aftertouchRange == sfz::Range(127, 127)); + REQUIRE(region.aftertouchRange == Range(127, 127)); region.parseOpcode({ "lochanaft", "0" }); - REQUIRE(region.aftertouchRange == sfz::Range(0, 127)); + REQUIRE(region.aftertouchRange == Range(0, 127)); region.parseOpcode({ "hichanaft", "39" }); - REQUIRE(region.aftertouchRange == sfz::Range(0, 39)); + REQUIRE(region.aftertouchRange == Range(0, 39)); region.parseOpcode({ "hichanaft", "135" }); - REQUIRE(region.aftertouchRange == sfz::Range(0, 127)); + REQUIRE(region.aftertouchRange == Range(0, 127)); region.parseOpcode({ "hichanaft", "-1" }); - REQUIRE(region.aftertouchRange == sfz::Range(0, 0)); + REQUIRE(region.aftertouchRange == Range(0, 0)); } SECTION("lobpm, hibpm") { - REQUIRE(region.bpmRange == sfz::Range(0, 500)); + REQUIRE(region.bpmRange == Range(0, 500)); region.parseOpcode({ "lobpm", "47.5" }); - REQUIRE(region.bpmRange == sfz::Range(47.5, 500)); + REQUIRE(region.bpmRange == Range(47.5, 500)); region.parseOpcode({ "lobpm", "594" }); - REQUIRE(region.bpmRange == sfz::Range(500, 500)); + REQUIRE(region.bpmRange == Range(500, 500)); region.parseOpcode({ "lobpm", "0" }); - REQUIRE(region.bpmRange == sfz::Range(0, 500)); + REQUIRE(region.bpmRange == Range(0, 500)); region.parseOpcode({ "hibpm", "78" }); - REQUIRE(region.bpmRange == sfz::Range(0, 78)); + REQUIRE(region.bpmRange == Range(0, 78)); region.parseOpcode({ "hibpm", "895.4" }); - REQUIRE(region.bpmRange == sfz::Range(0, 500)); + REQUIRE(region.bpmRange == Range(0, 500)); region.parseOpcode({ "hibpm", "-1" }); - REQUIRE(region.bpmRange == sfz::Range(0, 0)); + REQUIRE(region.bpmRange == Range(0, 0)); } SECTION("lorand, hirand") { - REQUIRE(region.randRange == sfz::Range(0, 1)); + REQUIRE(region.randRange == Range(0, 1)); region.parseOpcode({ "lorand", "0.5" }); - REQUIRE(region.randRange == sfz::Range(0.5, 1)); + REQUIRE(region.randRange == Range(0.5, 1)); region.parseOpcode({ "lorand", "4" }); - REQUIRE(region.randRange == sfz::Range(1, 1)); + REQUIRE(region.randRange == Range(1, 1)); region.parseOpcode({ "lorand", "0" }); - REQUIRE(region.randRange == sfz::Range(0, 1)); + REQUIRE(region.randRange == Range(0, 1)); region.parseOpcode({ "hirand", "39" }); - REQUIRE(region.randRange == sfz::Range(0, 1)); + REQUIRE(region.randRange == Range(0, 1)); region.parseOpcode({ "hirand", "0.7" }); - REQUIRE(region.randRange == sfz::Range(0, 0.7f)); + REQUIRE(region.randRange == Range(0, 0.7f)); region.parseOpcode({ "hirand", "-1" }); - REQUIRE(region.randRange == sfz::Range(0, 0)); + REQUIRE(region.randRange == Range(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(15_norm, 127_norm)); + REQUIRE(region.ccTriggers[45] == Range(15_norm, 127_norm)); region.parseOpcode({ "on_hicc4", "47" }); REQUIRE(region.ccTriggers.contains(45)); - REQUIRE(region.ccTriggers[4] == sfz::Range(0_norm, 47_norm)); + REQUIRE(region.ccTriggers[4] == Range(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(0, 0)); + REQUIRE(region.crossfadeKeyInRange == Range(0, 0)); region.parseOpcode({ "xfin_lokey", "4" }); - REQUIRE(region.crossfadeKeyInRange == sfz::Range(4, 4)); + REQUIRE(region.crossfadeKeyInRange == Range(4, 4)); region.parseOpcode({ "xfin_lokey", "128" }); - REQUIRE(region.crossfadeKeyInRange == sfz::Range(127, 127)); + REQUIRE(region.crossfadeKeyInRange == Range(127, 127)); region.parseOpcode({ "xfin_lokey", "59" }); - REQUIRE(region.crossfadeKeyInRange == sfz::Range(59, 127)); + REQUIRE(region.crossfadeKeyInRange == Range(59, 127)); region.parseOpcode({ "xfin_hikey", "59" }); - REQUIRE(region.crossfadeKeyInRange == sfz::Range(59, 59)); + REQUIRE(region.crossfadeKeyInRange == Range(59, 59)); region.parseOpcode({ "xfin_hikey", "128" }); - REQUIRE(region.crossfadeKeyInRange == sfz::Range(59, 127)); + REQUIRE(region.crossfadeKeyInRange == Range(59, 127)); region.parseOpcode({ "xfin_hikey", "0" }); - REQUIRE(region.crossfadeKeyInRange == sfz::Range(0, 0)); + REQUIRE(region.crossfadeKeyInRange == Range(0, 0)); region.parseOpcode({ "xfin_hikey", "-1" }); - REQUIRE(region.crossfadeKeyInRange == sfz::Range(0, 0)); + REQUIRE(region.crossfadeKeyInRange == Range(0, 0)); } SECTION("xfin_lovel, xfin_hivel") { - REQUIRE(region.crossfadeVelInRange == sfz::Range(0_norm, 0_norm)); + REQUIRE(region.crossfadeVelInRange == Range(0_norm, 0_norm)); region.parseOpcode({ "xfin_lovel", "4" }); - REQUIRE(region.crossfadeVelInRange == sfz::Range(4_norm, 4_norm)); + REQUIRE(region.crossfadeVelInRange == Range(4_norm, 4_norm)); region.parseOpcode({ "xfin_lovel", "128" }); - REQUIRE(region.crossfadeVelInRange == sfz::Range(127_norm, 127_norm)); + REQUIRE(region.crossfadeVelInRange == Range(127_norm, 127_norm)); region.parseOpcode({ "xfin_lovel", "59" }); - REQUIRE(region.crossfadeVelInRange == sfz::Range(59_norm, 127_norm)); + REQUIRE(region.crossfadeVelInRange == Range(59_norm, 127_norm)); region.parseOpcode({ "xfin_hivel", "59" }); - REQUIRE(region.crossfadeVelInRange == sfz::Range(59_norm, 59_norm)); + REQUIRE(region.crossfadeVelInRange == Range(59_norm, 59_norm)); region.parseOpcode({ "xfin_hivel", "128" }); - REQUIRE(region.crossfadeVelInRange == sfz::Range(59_norm, 127_norm)); + REQUIRE(region.crossfadeVelInRange == Range(59_norm, 127_norm)); region.parseOpcode({ "xfin_hivel", "0" }); - REQUIRE(region.crossfadeVelInRange == sfz::Range(0_norm, 0_norm)); + REQUIRE(region.crossfadeVelInRange == Range(0_norm, 0_norm)); region.parseOpcode({ "xfin_hivel", "-1" }); - REQUIRE(region.crossfadeVelInRange == sfz::Range(0_norm, 0_norm)); + REQUIRE(region.crossfadeVelInRange == Range(0_norm, 0_norm)); } SECTION("xfout_lokey, xfout_hikey") { - REQUIRE(region.crossfadeKeyOutRange == sfz::Range(127, 127)); + REQUIRE(region.crossfadeKeyOutRange == Range(127, 127)); region.parseOpcode({ "xfout_lokey", "4" }); - REQUIRE(region.crossfadeKeyOutRange == sfz::Range(4, 127)); + REQUIRE(region.crossfadeKeyOutRange == Range(4, 127)); region.parseOpcode({ "xfout_lokey", "128" }); - REQUIRE(region.crossfadeKeyOutRange == sfz::Range(127, 127)); + REQUIRE(region.crossfadeKeyOutRange == Range(127, 127)); region.parseOpcode({ "xfout_lokey", "59" }); - REQUIRE(region.crossfadeKeyOutRange == sfz::Range(59, 127)); + REQUIRE(region.crossfadeKeyOutRange == Range(59, 127)); region.parseOpcode({ "xfout_hikey", "59" }); - REQUIRE(region.crossfadeKeyOutRange == sfz::Range(59, 59)); + REQUIRE(region.crossfadeKeyOutRange == Range(59, 59)); region.parseOpcode({ "xfout_hikey", "128" }); - REQUIRE(region.crossfadeKeyOutRange == sfz::Range(59, 127)); + REQUIRE(region.crossfadeKeyOutRange == Range(59, 127)); region.parseOpcode({ "xfout_hikey", "0" }); - REQUIRE(region.crossfadeKeyOutRange == sfz::Range(0, 0)); + REQUIRE(region.crossfadeKeyOutRange == Range(0, 0)); region.parseOpcode({ "xfout_hikey", "-1" }); - REQUIRE(region.crossfadeKeyOutRange == sfz::Range(0, 0)); + REQUIRE(region.crossfadeKeyOutRange == Range(0, 0)); } SECTION("xfout_lovel, xfout_hivel") { - REQUIRE(region.crossfadeVelOutRange == sfz::Range(127_norm, 127_norm)); + REQUIRE(region.crossfadeVelOutRange == Range(127_norm, 127_norm)); region.parseOpcode({ "xfout_lovel", "4" }); - REQUIRE(region.crossfadeVelOutRange == sfz::Range(4_norm, 127_norm)); + REQUIRE(region.crossfadeVelOutRange == Range(4_norm, 127_norm)); region.parseOpcode({ "xfout_lovel", "128" }); - REQUIRE(region.crossfadeVelOutRange == sfz::Range(127_norm, 127_norm)); + REQUIRE(region.crossfadeVelOutRange == Range(127_norm, 127_norm)); region.parseOpcode({ "xfout_lovel", "59" }); - REQUIRE(region.crossfadeVelOutRange == sfz::Range(59_norm, 127_norm)); + REQUIRE(region.crossfadeVelOutRange == Range(59_norm, 127_norm)); region.parseOpcode({ "xfout_hivel", "59" }); - REQUIRE(region.crossfadeVelOutRange == sfz::Range(59_norm, 59_norm)); + REQUIRE(region.crossfadeVelOutRange == Range(59_norm, 59_norm)); region.parseOpcode({ "xfout_hivel", "128" }); - REQUIRE(region.crossfadeVelOutRange == sfz::Range(59_norm, 127_norm)); + REQUIRE(region.crossfadeVelOutRange == Range(59_norm, 127_norm)); region.parseOpcode({ "xfout_hivel", "0" }); - REQUIRE(region.crossfadeVelOutRange == sfz::Range(0_norm, 0_norm)); + REQUIRE(region.crossfadeVelOutRange == Range(0_norm, 0_norm)); region.parseOpcode({ "xfout_hivel", "-1" }); - REQUIRE(region.crossfadeVelOutRange == sfz::Range(0_norm, 0_norm)); + REQUIRE(region.crossfadeVelOutRange == Range(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(4_norm, 4_norm)); + REQUIRE(region.crossfadeCCInRange[4] == Range(4_norm, 4_norm)); region.parseOpcode({ "xfin_locc4", "128" }); - REQUIRE(region.crossfadeCCInRange[4] == sfz::Range(127_norm, 127_norm)); + REQUIRE(region.crossfadeCCInRange[4] == Range(127_norm, 127_norm)); region.parseOpcode({ "xfin_locc4", "59" }); - REQUIRE(region.crossfadeCCInRange[4] == sfz::Range(59_norm, 127_norm)); + REQUIRE(region.crossfadeCCInRange[4] == Range(59_norm, 127_norm)); region.parseOpcode({ "xfin_hicc4", "59" }); - REQUIRE(region.crossfadeCCInRange[4] == sfz::Range(59_norm, 59_norm)); + REQUIRE(region.crossfadeCCInRange[4] == Range(59_norm, 59_norm)); region.parseOpcode({ "xfin_hicc4", "128" }); - REQUIRE(region.crossfadeCCInRange[4] == sfz::Range(59_norm, 127_norm)); + REQUIRE(region.crossfadeCCInRange[4] == Range(59_norm, 127_norm)); region.parseOpcode({ "xfin_hicc4", "0" }); - REQUIRE(region.crossfadeCCInRange[4] == sfz::Range(0_norm, 0_norm)); + REQUIRE(region.crossfadeCCInRange[4] == Range(0_norm, 0_norm)); region.parseOpcode({ "xfin_hicc4", "-1" }); - REQUIRE(region.crossfadeCCInRange[4] == sfz::Range(0_norm, 0_norm)); + REQUIRE(region.crossfadeCCInRange[4] == Range(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(4_norm, 127_norm)); + REQUIRE(region.crossfadeCCOutRange[4] == Range(4_norm, 127_norm)); region.parseOpcode({ "xfout_locc4", "128" }); - REQUIRE(region.crossfadeCCOutRange[4] == sfz::Range(127_norm, 127_norm)); + REQUIRE(region.crossfadeCCOutRange[4] == Range(127_norm, 127_norm)); region.parseOpcode({ "xfout_locc4", "59" }); - REQUIRE(region.crossfadeCCOutRange[4] == sfz::Range(59_norm, 127_norm)); + REQUIRE(region.crossfadeCCOutRange[4] == Range(59_norm, 127_norm)); region.parseOpcode({ "xfout_hicc4", "59" }); - REQUIRE(region.crossfadeCCOutRange[4] == sfz::Range(59_norm, 59_norm)); + REQUIRE(region.crossfadeCCOutRange[4] == Range(59_norm, 59_norm)); region.parseOpcode({ "xfout_hicc4", "128" }); - REQUIRE(region.crossfadeCCOutRange[4] == sfz::Range(59_norm, 127_norm)); + REQUIRE(region.crossfadeCCOutRange[4] == Range(59_norm, 127_norm)); region.parseOpcode({ "xfout_hicc4", "0" }); - REQUIRE(region.crossfadeCCOutRange[4] == sfz::Range(0_norm, 0_norm)); + REQUIRE(region.crossfadeCCOutRange[4] == Range(0_norm, 0_norm)); region.parseOpcode({ "xfout_hicc4", "-1" }); - REQUIRE(region.crossfadeCCOutRange[4] == sfz::Range(0_norm, 0_norm)); + REQUIRE(region.crossfadeCCOutRange[4] == Range(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" }); diff --git a/tests/OnePoleFilterT.cpp b/tests/SmoothersT.cpp similarity index 97% rename from tests/OnePoleFilterT.cpp rename to tests/SmoothersT.cpp index f44e65cc..63c05141 100644 --- a/tests/OnePoleFilterT.cpp +++ b/tests/SmoothersT.cpp @@ -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 -inline bool approxEqual(const std::array &lhs, const std::array &rhs) +inline bool approxEqual(const std::array& lhs, const std::array& 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 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 floatOutputLow01 = { 0.06567783171600353f, 0.18655945645590016f, 0.15368937959051f, 0.05054483866245487f, @@ -92,7 +93,8 @@ constexpr std::array 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 floatOutputHigh01 = { 0.6567783171600353f, 0.5520379302389311f, -0.8807386988928331f, -0.1507067103877182f, @@ -110,7 +112,8 @@ constexpr std::array 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 floatInput05 = { -0.8247415510202276f, -1.0299159073255513f, 0.7689727513393745f, -0.023063681797826918f, @@ -128,7 +131,8 @@ constexpr std::array 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 floatOutputLow05 = { -0.27491385034007587f, -0.7098571028952849f, -0.32360008629382064f, 0.14076966108257558f, @@ -146,7 +150,8 @@ constexpr std::array 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 floatOutputHigh05 = { -0.5498277006801517f, -0.32005880443026635f, 1.0925728376331951f, -0.1638333428804025f, @@ -164,7 +169,8 @@ constexpr std::array 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 floatInput09 = { -0.9629663717342508f, 1.054078826032172f, -1.0644939081323097f, -0.05328934531304567f, @@ -182,7 +188,8 @@ constexpr std::array 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 floatOutputLow09 = { -0.45614196555832937f, 0.01915105911173487f, -0.003925509462605503f, -0.5296828837089897f, @@ -200,7 +207,8 @@ constexpr std::array 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 floatOutputHigh09 = { -0.5068244061759215f, 1.034927766920437f, -1.0605683986697043f, 0.47639353839594406f, @@ -218,7 +226,8 @@ constexpr std::array 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 doubleInput01 = { 0.7224561488760388, 0.7385973866948313, -0.7270493193023231, -0.10016187172526334, @@ -236,7 +245,8 @@ constexpr std::array 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 doubleOutputLow01 = { 0.06567783171600353, 0.18655945645590016, 0.15368937959051, 0.05054483866245487, @@ -254,7 +264,8 @@ constexpr std::array 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 doubleOutputHigh01 = { 0.6567783171600353, 0.5520379302389311, -0.8807386988928331, -0.1507067103877182, @@ -272,7 +283,8 @@ constexpr std::array 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 doubleInput05 = { -0.8247415510202276, -1.0299159073255513, 0.7689727513393745, -0.023063681797826918, @@ -290,7 +302,8 @@ constexpr std::array 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 doubleOutputLow05 = { -0.27491385034007587, -0.7098571028952849, -0.32360008629382064, 0.14076966108257558, @@ -308,7 +321,8 @@ constexpr std::array 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 doubleOutputHigh05 = { -0.5498277006801517, -0.32005880443026635, 1.0925728376331951, -0.1638333428804025, @@ -326,7 +340,8 @@ constexpr std::array 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 doubleInput09 = { -0.9629663717342508, 1.054078826032172, -1.0644939081323097, -0.05328934531304567, @@ -344,7 +359,8 @@ constexpr std::array 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 doubleOutputLow09 = { -0.45614196555832937, 0.01915105911173487, -0.003925509462605503, -0.5296828837089897, @@ -362,7 +378,8 @@ constexpr std::array 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 doubleOutputHigh09 = { -0.5068244061759215, 1.034927766920437, -1.0605683986697043, 0.47639353839594406, @@ -380,7 +397,8 @@ constexpr std::array 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") {