From b1f7a4bd660d2ce616996c61f38e39e2c7045a24 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Sun, 8 Nov 2020 10:26:45 +0100 Subject: [PATCH 01/15] Change the way the defaults and bounds for the opcodes are handled and read --- benchmarks/BM_opcodeSpec.cpp | 72 ++++ benchmarks/BM_opcodeSpec.h | 14 + benchmarks/BM_opcodeSpec_def.cpp | 3 + benchmarks/CMakeLists.txt | 1 + src/CMakeLists.txt | 1 + src/sfizz/Config.h | 4 + src/sfizz/Curve.cpp | 6 +- src/sfizz/Defaults.cpp | 143 ++++++++ src/sfizz/Defaults.h | 417 ++++++++++------------- src/sfizz/EGDescription.h | 44 +-- src/sfizz/EQDescription.h | 10 +- src/sfizz/EQPool.h | 6 +- src/sfizz/Effects.h | 5 +- src/sfizz/FilePool.h | 6 +- src/sfizz/FilterDescription.h | 14 +- src/sfizz/FilterPool.cpp | 4 +- src/sfizz/FilterPool.h | 8 +- src/sfizz/FlexEGDescription.h | 10 +- src/sfizz/LFODescription.h | 21 +- src/sfizz/Opcode.cpp | 235 +++++++------ src/sfizz/Opcode.h | 88 +---- src/sfizz/Region.cpp | 510 ++++++++++++++++------------- src/sfizz/Region.h | 116 +++---- src/sfizz/SfzHelpers.h | 9 +- src/sfizz/Smoothers.cpp | 6 +- src/sfizz/Smoothers.h | 5 - src/sfizz/Synth.cpp | 65 ++-- src/sfizz/SynthConfig.h | 4 +- src/sfizz/SynthMessaging.cpp | 71 +++- src/sfizz/SynthPrivate.h | 4 +- src/sfizz/Voice.cpp | 7 +- src/sfizz/effects/Apan.cpp | 12 +- src/sfizz/effects/Apan.h | 16 +- src/sfizz/effects/Compressor.cpp | 12 +- src/sfizz/effects/Disto.cpp | 27 +- src/sfizz/effects/Eq.cpp | 9 +- src/sfizz/effects/Filter.cpp | 9 +- src/sfizz/effects/Fverb.cpp | 29 +- src/sfizz/effects/Gain.cpp | 3 +- src/sfizz/effects/Gate.cpp | 8 +- src/sfizz/effects/Lofi.cpp | 6 +- src/sfizz/effects/Rectify.cpp | 3 +- src/sfizz/effects/Strings.cpp | 6 +- src/sfizz/effects/Strings.h | 4 +- src/sfizz/effects/Width.cpp | 3 +- tests/FilesT.cpp | 15 +- tests/OpcodeT.cpp | 328 ++++++++++++++----- tests/RegionValueComputationsT.cpp | 6 +- tests/RegionValuesT.cpp | 335 ++++++++++++------- tests/SynthT.cpp | 6 +- tests/TestFiles/note_offset.sfz | 12 - 51 files changed, 1623 insertions(+), 1135 deletions(-) create mode 100644 benchmarks/BM_opcodeSpec.cpp create mode 100644 benchmarks/BM_opcodeSpec.h create mode 100644 benchmarks/BM_opcodeSpec_def.cpp create mode 100644 src/sfizz/Defaults.cpp delete mode 100644 tests/TestFiles/note_offset.sfz diff --git a/benchmarks/BM_opcodeSpec.cpp b/benchmarks/BM_opcodeSpec.cpp new file mode 100644 index 00000000..da31a30a --- /dev/null +++ b/benchmarks/BM_opcodeSpec.cpp @@ -0,0 +1,72 @@ +// 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 "BM_opcodeSpec.h" +#include +#include +#include +#include +#include +#include + +class OpcodeSpecFixture : public benchmark::Fixture { +public: + void SetUp(const ::benchmark::State& state) { + std::random_device rd { }; + std::mt19937 gen { rd() }; + std::uniform_real_distribution dist { 0.0f, 1.0f }; + value = dist(gen); + } + + void TearDown(const ::benchmark::State& /* state */) { + + } + + float value; + float returned; +}; + +BENCHMARK_DEFINE_F(OpcodeSpecFixture, ConstexprClamp)(benchmark::State& state) { + for (auto _ : state) + { + if (constexprSpec.flags | (1 << 2)) + returned = constexprSpec.bounds.clamp(value); + benchmark::DoNotOptimize(returned); + } +} + +BENCHMARK_DEFINE_F(OpcodeSpecFixture, ConstexprDontClamp)(benchmark::State& state) { + for (auto _ : state) + { + if (constexprSpec.flags | (1 << 1)) + returned = constexprSpec.bounds.clamp(value); + benchmark::DoNotOptimize(returned); + } +} + +BENCHMARK_DEFINE_F(OpcodeSpecFixture, ConstClamp)(benchmark::State& state) { + for (auto _ : state) + { + if (constSpec.flags | (1 << 2)) + returned = constSpec.bounds.clamp(value); + benchmark::DoNotOptimize(returned); + } +} + +BENCHMARK_DEFINE_F(OpcodeSpecFixture, ConstDontClamp)(benchmark::State& state) { + for (auto _ : state) + { + if (constSpec.flags | (1 << 1)) + returned = constSpec.bounds.clamp(value); + benchmark::DoNotOptimize(returned); + } +} + +BENCHMARK_REGISTER_F(OpcodeSpecFixture, ConstexprClamp); +BENCHMARK_REGISTER_F(OpcodeSpecFixture, ConstexprDontClamp); +BENCHMARK_REGISTER_F(OpcodeSpecFixture, ConstClamp); +BENCHMARK_REGISTER_F(OpcodeSpecFixture, ConstDontClamp); +BENCHMARK_MAIN(); diff --git a/benchmarks/BM_opcodeSpec.h b/benchmarks/BM_opcodeSpec.h new file mode 100644 index 00000000..8efcbe43 --- /dev/null +++ b/benchmarks/BM_opcodeSpec.h @@ -0,0 +1,14 @@ +#pragma once + +#include "Range.h" + +template +struct OpcodeSpec +{ + T defaultValue; + sfz::Range bounds; + int flags { 0 }; +}; + +constexpr OpcodeSpec constexprSpec { 0.0f, sfz::Range(0.0f, 0.5f), 1 << 2 }; +extern const OpcodeSpec constSpec; diff --git a/benchmarks/BM_opcodeSpec_def.cpp b/benchmarks/BM_opcodeSpec_def.cpp new file mode 100644 index 00000000..076dd27d --- /dev/null +++ b/benchmarks/BM_opcodeSpec_def.cpp @@ -0,0 +1,3 @@ +#include "BM_opcodeSpec.h" + +const OpcodeSpec constSpec { 0.0f, sfz::Range(0.0f, 0.5f), 1 << 2 }; diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index 89d7c8e3..77652c3e 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -38,6 +38,7 @@ sfizz_add_benchmark(bm_mapVsArray BM_mapVsArray.cpp) sfizz_add_benchmark(bm_random BM_random.cpp) sfizz_add_benchmark(bm_clamp BM_clamp.cpp) sfizz_add_benchmark(bm_allWithin BM_allWithin.cpp) +sfizz_add_benchmark(bm_opcodeSpec BM_opcodeSpec.cpp BM_opcodeSpec_def.cpp) sfizz_add_benchmark(bm_logger BM_logger.cpp) sfizz_add_benchmark(bm_smoothers BM_smoothers.cpp) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d548788c..d3c1f2bc 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -137,6 +137,7 @@ set(SFIZZ_SOURCES sfizz/Wavetables.cpp sfizz/Tuning.cpp sfizz/RegionSet.cpp + sfizz/Defaults.cpp sfizz/PolyphonyGroup.cpp sfizz/VoiceManager.cpp sfizz/VoiceStealing.cpp diff --git a/src/sfizz/Config.h b/src/sfizz/Config.h index 451a5bcc..faa06de3 100644 --- a/src/sfizz/Config.h +++ b/src/sfizz/Config.h @@ -150,6 +150,10 @@ namespace config { (int(polyphony * config::overflowVoiceMultiplier) < int(config::maxVoices)) ? int(polyphony * config::overflowVoiceMultiplier) : int(config::maxVoices); } + /** + * @brief The smoothing time constant per "smooth" steps + */ + constexpr float smoothTauPerStep { 3e-3 }; } // namespace config } // namespace sfz diff --git a/src/sfizz/Curve.cpp b/src/sfizz/Curve.cpp index 8d204a39..b4dcb93f 100644 --- a/src/sfizz/Curve.cpp +++ b/src/sfizz/Curve.cpp @@ -21,7 +21,7 @@ Curve Curve::buildCurveFromHeader( { Curve curve; bool fillStatus[NumValues] = {}; - const Range fullRange { -HUGE_VALF, +HUGE_VALF }; + const OpcodeSpec fullRange {0.0f, Range(-HUGE_VALF, +HUGE_VALF), 0 }; auto setPoint = [&curve, &fillStatus](int i, float x) { curve._points[i] = x; @@ -40,7 +40,7 @@ Curve Curve::buildCurveFromHeader( if (index >= NumValues) continue; - auto valueOpt = readOpcode(opc.value, fullRange); + auto valueOpt = opc.read(fullRange); if (!valueOpt) continue; @@ -268,7 +268,7 @@ void CurveSet::addCurveFromHeader(absl::Span members) Curve::Interpolator itp = Curve::Interpolator::Linear; if (const Opcode* opc = findOpcode(hash("curve_index"))) { - if (auto opt = readOpcode(opc->value, {0, 255})) + if (auto opt = opc->read(Default::curveCC)) curveIndex = *opt; else DBG("Invalid value for curve index: " << opc->value); diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp new file mode 100644 index 00000000..b7a77769 --- /dev/null +++ b/src/sfizz/Defaults.cpp @@ -0,0 +1,143 @@ +#include "Defaults.h" + +namespace sfz { + +namespace Default { +constexpr auto uint32_t_max = std::numeric_limits::max(); + +extern const OpcodeSpec delay { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec delayRandom { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec offset { 0, Range(0, uint32_t_max), kEnforceLowerBound }; +extern const OpcodeSpec offsetMod { 0, Range(0, uint32_t_max), kEnforceLowerBound }; +extern const OpcodeSpec offsetRandom { 0, Range(0, uint32_t_max), kEnforceLowerBound }; +extern const OpcodeSpec sampleEnd { uint32_t_max, Range(0, uint32_t_max), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec sampleCount { 0, Range(0, uint32_t_max), 0 }; +extern const OpcodeSpec loopRange { 0, Range(0, uint32_t_max), 0 }; +extern const OpcodeSpec loopCrossfade { 1e-3, Range(1e-3, 1.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec oscillatorPhase { 0.0f, Range(0.0f, 1.0f), 0 }; +extern const OpcodeSpec oscillatorMode { 0, Range(0, 2), kIgnoreOOB }; +extern const OpcodeSpec oscillatorMulti { 1, Range(1, config::oscillatorsPerVoice), kIgnoreOOB }; +extern const OpcodeSpec oscillatorDetune { 0.0f, Range(-12000.0f, 12000.0f), 0 }; +extern const OpcodeSpec oscillatorDetuneMod { 0.0f, Range(-12000.0f, 12000.0f), 0 }; +extern const OpcodeSpec oscillatorModDepth { 0.0f, Range(0.0f, 10000.0f), kEnforceLowerBound }; +extern const OpcodeSpec oscillatorModDepthMod { 0.0f, Range(0.0f, 10000.0f), kEnforceLowerBound }; +extern const OpcodeSpec oscillatorQuality { 1, Range(0, 3), kIgnoreOOB }; +extern const OpcodeSpec group { 0, Range(0, uint32_t_max), 0 }; +extern const OpcodeSpec offTime { 6e-3f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec polyphony { config::maxVoices, Range(0, config::maxVoices), 0 }; +extern const OpcodeSpec notePolyphony { config::maxVoices, Range(0, config::maxVoices), 0 }; +extern const OpcodeSpec key { 60, Range(0, 127), kIgnoreOOB | kCanBeNote }; +extern const OpcodeSpec midi7 { 0, Range(0, 127), kIgnoreOOB }; +extern const OpcodeSpec float7 { 0.0f , Range(0.0f, 127.0f), kIgnoreOOB }; +extern const OpcodeSpec bend { 0.0f, Range(-8192.0f, 8192.0f), kIgnoreOOB }; +extern const OpcodeSpec normalized { 0.0f, Range(0.0f, 1.0f), kIgnoreOOB }; +extern const OpcodeSpec bipolar { 0.0f, Range(-1.0f, 1.0f), kIgnoreOOB }; +extern const OpcodeSpec ccNumber { 0, Range(0, config::numCCs), kIgnoreOOB }; +extern const OpcodeSpec smoothCC { 0, Range(0, 100), kIgnoreOOB }; +extern const OpcodeSpec curveCC { 0, Range(0, 255), kIgnoreOOB }; +extern const OpcodeSpec sustainCC { 64, Range(0, 127), kIgnoreOOB }; +extern const OpcodeSpec sustainThreshold { 0.0039f, Range(0.0f, 1.0f), kIgnoreOOB }; +extern const OpcodeSpec bpm { 0.0f, Range(0.0f, 500.0f), kEnforceLowerBound }; +extern const OpcodeSpec sequence { 1, Range(1, 100), kIgnoreOOB }; +extern const OpcodeSpec volume { 0.0f, Range(-144.0f, 48.0f), 0 }; +extern const OpcodeSpec volumeMod { 0.0f, Range(-144.0f, 48.0f), 0 }; +extern const OpcodeSpec amplitude { 100.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec amplitudeMod { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec pan { 0.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec panMod { 0.0f, Range(-200.0f, 200.0f), 0 }; +extern const OpcodeSpec position { 0.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec positionMod { 0.0f, Range(-200.0f, 200.0f), 0 }; +extern const OpcodeSpec width { 100.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec widthMod { 0.0f, Range(-200.0f, 200.0f), 0 }; +extern const OpcodeSpec crossfadeIn { 0, Range(0, 127), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec crossfadeInNorm { 0.0f, Range(0.0f, 1.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec crossfadeOut { 127, Range(0, 127), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec crossfadeOutNorm { 1.0f, Range(0.0f, 1.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec ampKeytrack { 0.0f, Range(-96.0f, 12.0f), 0 }; +extern const OpcodeSpec ampVeltrack { 100.0f, Range(-100.0f, 100.0f), kIgnoreOOB }; +extern const OpcodeSpec ampVelcurve { 0.0f, Range(0.0f, 1.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec ampRandom { 0.0f, Range(0.0f, 24.0f), kEnforceLowerBound }; +extern const OpcodeSpec rtDecay { 0.0f, Range(0.0f, 200.0f), kEnforceLowerBound }; +extern const OpcodeSpec filterCutoff { 0.0f, Range(0.0f, 20000.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec filterCutoffMod { 0.0f, Range(-12000.0f, 12000.0f), kEnforceLowerBound }; +extern const OpcodeSpec filterResonance { 0.0f, Range(0.0f, 96.0f), kEnforceLowerBound }; +extern const OpcodeSpec filterResonanceMod { 0.0f, Range(0.0f, 96.0f), kEnforceLowerBound }; +extern const OpcodeSpec filterGain { 0.0f, Range(-96.0f, 96.0f), 0 }; +extern const OpcodeSpec filterGainMod { 0.0f, Range(-96.0f, 96.0f), 0 }; +extern const OpcodeSpec filterRandom { 0.0f, Range(0.0f, 12000.0f), kEnforceLowerBound }; +extern const OpcodeSpec filterKeytrack { 0, Range(0, 1200), kEnforceLowerBound }; +extern const OpcodeSpec filterVeltrack { 0, Range(-12000, 12000), 0 }; +extern const OpcodeSpec eqBandwidth { 1.0f, Range(0.001f, 4.0f), kEnforceLowerBound }; +extern const OpcodeSpec eqBandwidthMod { 0.0f, Range(-4.0f, 4.0f), 0 }; +extern const OpcodeSpec eqFrequency { 0.0f, Range(0.0f, 30000.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec eqFrequencyMod { 0.0f, Range(-30000.0f, 30000.0f), 0 }; +extern const OpcodeSpec eqGain { 0.0f, Range(-96.0f, 96.0f), 0 }; +extern const OpcodeSpec eqGainMod { 0.0f, Range(-96.0f, 96.0f), 0 }; +extern const OpcodeSpec eqVel2Frequency { 0.0f, Range(-30000.0f, 30000.0f), 0 }; +extern const OpcodeSpec eqVel2Gain { 0.0f, Range(-96.0f, 96.0f), 0 }; +extern const OpcodeSpec pitchKeytrack { 100, Range(-1200, 1200), 0 }; +extern const OpcodeSpec pitchRandom { 0.0f, Range(0.0f, 12000.0f), kEnforceLowerBound }; +extern const OpcodeSpec pitchVeltrack { 0, Range(-12000, 12000), 0 }; +extern const OpcodeSpec transpose { 0, Range(-127, 127), kIgnoreOOB }; +extern const OpcodeSpec pitch { 0.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec pitchMod { 0.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec bendUp { 200.0f, Range(-12000.0f, 12000.0f), 0 }; +extern const OpcodeSpec bendDown { -200.0f, Range(-12000.0f, 12000.0f), 0 }; +extern const OpcodeSpec bendStep { 1.0f, Range(1.0f, 1200.0f), kIgnoreOOB }; +extern const OpcodeSpec lfoFreq { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec lfoFreqMod { 0.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec lfoBeats { 0.0f, Range(0.0f, 1000.0f), 0 }; +extern const OpcodeSpec lfoBeatsMod { 0.0f, Range(-1000.0f, 1000.0f), 0 }; +extern const OpcodeSpec lfoPhase { 0.0f, Range(0.0f, 1.0f), 0 }; +extern const OpcodeSpec lfoDelay { 0.0f, Range(0.0f, 30.0f), 0 }; +extern const OpcodeSpec lfoFade { 0.0f, Range(0.0f, 30.0f), 0 }; +extern const OpcodeSpec lfoCount { 0, Range(0, 1000), 0 }; +extern const OpcodeSpec lfoSteps { 0, Range(0, static_cast(config::maxLFOSteps)), 0 }; +extern const OpcodeSpec lfoStepX { 0.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec lfoWave { 0, Range(0, 15), 0 }; +extern const OpcodeSpec lfoOffset { 0.0f, Range(-1.0f, 1.0f), 0 }; +extern const OpcodeSpec lfoRatio { 1.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec lfoScale { 1.0f, Range(0.0f, 1.0f), 0 }; +extern const OpcodeSpec egTime { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec egRelease { 0.001f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec egTimeMod { 0.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec egPercent { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec egPercentMod { 0.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec egDepth { 0.0f, Range(-12000.0f, 12000.0f), 0 }; +extern const OpcodeSpec egVel2Depth { 0.0f, Range(-12000.0f, 12000.0f), 0 }; +extern const OpcodeSpec flexEGDynamic { 0, Range(0, 1), kIgnoreOOB }; +extern const OpcodeSpec flexEGSustain { 0, Range(0, 100), kIgnoreOOB }; +extern const OpcodeSpec flexEGPointTime { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec flexEGPointLevel { 0.0f, Range(-1.0f, 1.0f), kIgnoreOOB }; +extern const OpcodeSpec flexEGPointShape { 0.0f, Range(-100.0f, 100.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec sampleQuality { 1, Range(1, 10), kIgnoreOOB }; +extern const OpcodeSpec octaveOffset { 0, Range(-10, 10), 0 }; +extern const OpcodeSpec noteOffset { 0, Range(-127, 127), 0 }; +extern const OpcodeSpec effect { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec apanWaveform { 0, Range(0, std::numeric_limits::max()), 0 }; +extern const OpcodeSpec apanFrequency { 0.0f, Range(0.0f, std::numeric_limits::max()), kEnforceLowerBound }; +extern const OpcodeSpec apanPhase { 0.5f, Range(0.0f, 1.0f), 0 }; +extern const OpcodeSpec apanLevel { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec distoTone { 100.0f, Range(0.0f, 100.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec distoDepth { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec distoStages { 1, Range(1, maxDistoStages), kEnforceLowerBound }; +extern const OpcodeSpec compAttack { 0.005f, Range(0.0f, 10.0f), kEnforceLowerBound }; +extern const OpcodeSpec compRelease { 0.05f, Range(0.0f, 10.0f), kEnforceLowerBound }; +extern const OpcodeSpec compThreshold { 0.0f, Range(-100.0f, 0.0f), kIgnoreOOB }; +extern const OpcodeSpec compRatio { 1.0f, Range(1.0f, 50.0f), kIgnoreOOB }; +extern const OpcodeSpec compGain { 0.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec fverbSize { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec fverbPredelay { 0.0f, Range(0.0f, 10.0f), kEnforceLowerBound }; +extern const OpcodeSpec fverbTone { 100.0f, Range(0.0f, 100.0f), kIgnoreOOB }; +extern const OpcodeSpec fverbDamp { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; +extern const OpcodeSpec gateAttack { 0.005f, Range(0.0f, 10.0f), kEnforceLowerBound }; +extern const OpcodeSpec gateRelease { 0.05f, Range(0.0f, 10.0f), kEnforceLowerBound }; +extern const OpcodeSpec gateHold { 0.0f, Range(0.0f, 10.0f), kEnforceLowerBound }; +extern const OpcodeSpec gateThreshold { 0.0f, Range(-100.0f, 0.0f), kIgnoreOOB }; +extern const OpcodeSpec lofiBitred { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; +extern const OpcodeSpec lofiDecim { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; +extern const OpcodeSpec rectify { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; +extern const OpcodeSpec stringsNumber { maxStrings, Range(0, maxStrings), kEnforceLowerBound }; +} // namespace Default + +} // namespace sfz diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 2ebca118..899094d1 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -38,253 +38,196 @@ enum class SfzSelfMask { mask, dontMask }; namespace sfz { + +enum OpcodeFlags : int { + kIgnoreOOB = 1, + kEnforceLowerBound = 1 << 1, + kEnforceUpperBound = 1 << 2, + kCanBeNote = 1 << 3, +}; + +template +struct OpcodeSpec +{ + T value; + Range bounds; + int flags; +}; + namespace Default { - // The categories match http://sfzformat.com/ - // ******* SFZ 1 ******* - // Sound source: sample playback - constexpr float delay { 0.0 }; - constexpr float delayRandom { 0.0 }; - constexpr Range delayRange { 0.0, 100.0 }; - constexpr int64_t offset { 0 }; - constexpr int64_t offsetRandom { 0 }; - constexpr Range offsetRange { 0, std::numeric_limits::max() }; - constexpr Range offsetCCRange = offsetRange; - constexpr Range sampleEndRange { 0, std::numeric_limits::max() }; - constexpr Range sampleCountRange { 0, std::numeric_limits::max() }; - constexpr SfzLoopMode loopMode { SfzLoopMode::no_loop }; - constexpr Range loopRange { 0, std::numeric_limits::max() }; - constexpr float loopCrossfade { 1e-3 }; - constexpr Range loopCrossfadeRange { loopCrossfade, 1.0 }; + extern const OpcodeSpec delay; + extern const OpcodeSpec delayRandom; + extern const OpcodeSpec offset; + extern const OpcodeSpec offsetMod; + extern const OpcodeSpec offsetRandom; + extern const OpcodeSpec sampleEnd; + extern const OpcodeSpec sampleCount; + extern const OpcodeSpec loopRange; + extern const OpcodeSpec loopCrossfade; + extern const OpcodeSpec oscillatorPhase; + extern const OpcodeSpec oscillatorMode; + extern const OpcodeSpec oscillatorMulti; + extern const OpcodeSpec oscillatorDetune; + extern const OpcodeSpec oscillatorDetuneMod; + extern const OpcodeSpec oscillatorModDepth; + extern const OpcodeSpec oscillatorModDepthMod; + extern const OpcodeSpec oscillatorQuality; + extern const OpcodeSpec group; + extern const OpcodeSpec offTime; + extern const OpcodeSpec polyphony; + extern const OpcodeSpec notePolyphony; + extern const OpcodeSpec key; + extern const OpcodeSpec midi7; + extern const OpcodeSpec float7; + extern const OpcodeSpec bend; + extern const OpcodeSpec normalized; + extern const OpcodeSpec bipolar; + extern const OpcodeSpec ccNumber; + extern const OpcodeSpec curveCC; + extern const OpcodeSpec smoothCC; + extern const OpcodeSpec sustainCC; + extern const OpcodeSpec sustainThreshold; + extern const OpcodeSpec bpm; + extern const OpcodeSpec sequence; + extern const OpcodeSpec volume; + extern const OpcodeSpec volumeMod; + extern const OpcodeSpec amplitude; + extern const OpcodeSpec amplitudeMod; + extern const OpcodeSpec pan; + extern const OpcodeSpec panMod; + extern const OpcodeSpec position; + extern const OpcodeSpec positionMod; + extern const OpcodeSpec width; + extern const OpcodeSpec widthMod; + extern const OpcodeSpec crossfadeIn; + extern const OpcodeSpec crossfadeInNorm; + extern const OpcodeSpec crossfadeOut; + extern const OpcodeSpec crossfadeOutNorm; + extern const OpcodeSpec ampKeytrack; + extern const OpcodeSpec ampVeltrack; + extern const OpcodeSpec ampVelcurve; + extern const OpcodeSpec ampRandom; + extern const OpcodeSpec rtDecay; + extern const OpcodeSpec filterCutoff; + extern const OpcodeSpec filterCutoffMod; + extern const OpcodeSpec filterResonance; + extern const OpcodeSpec filterResonanceMod; + extern const OpcodeSpec filterGain; + extern const OpcodeSpec filterGainMod; + extern const OpcodeSpec filterRandom; + extern const OpcodeSpec filterKeytrack; + extern const OpcodeSpec filterVeltrack; + extern const OpcodeSpec eqBandwidth; + extern const OpcodeSpec eqBandwidthMod; + extern const OpcodeSpec eqFrequency; + extern const OpcodeSpec eqFrequencyMod; + extern const OpcodeSpec eqGain; + extern const OpcodeSpec eqGainMod; + extern const OpcodeSpec eqVel2Frequency; + extern const OpcodeSpec eqVel2Gain; + extern const OpcodeSpec pitchKeytrack; + extern const OpcodeSpec pitchRandom; + extern const OpcodeSpec pitchVeltrack; + extern const OpcodeSpec transpose; + extern const OpcodeSpec pitch; + extern const OpcodeSpec pitchMod; + extern const OpcodeSpec bendUp; + extern const OpcodeSpec bendDown; + extern const OpcodeSpec bendStep; + extern const OpcodeSpec lfoFreq; + extern const OpcodeSpec lfoFreqMod; + extern const OpcodeSpec lfoBeats; + extern const OpcodeSpec lfoBeatsMod; + extern const OpcodeSpec lfoPhase; + extern const OpcodeSpec lfoDelay; + extern const OpcodeSpec lfoFade; + extern const OpcodeSpec lfoCount; + extern const OpcodeSpec lfoSteps; + extern const OpcodeSpec lfoStepX; + extern const OpcodeSpec lfoWave; + extern const OpcodeSpec lfoOffset; + extern const OpcodeSpec lfoRatio; + extern const OpcodeSpec lfoScale; + extern const OpcodeSpec egTime; + extern const OpcodeSpec egRelease; + extern const OpcodeSpec egTimeMod; + extern const OpcodeSpec egPercent; + extern const OpcodeSpec egPercentMod; + extern const OpcodeSpec egDepth; + extern const OpcodeSpec egVel2Depth; + extern const OpcodeSpec flexEGDynamic; + extern const OpcodeSpec flexEGSustain; + extern const OpcodeSpec flexEGPointTime; + extern const OpcodeSpec flexEGPointLevel; + extern const OpcodeSpec flexEGPointShape; + extern const OpcodeSpec sampleQuality; + extern const OpcodeSpec octaveOffset; + extern const OpcodeSpec noteOffset; + extern const OpcodeSpec effect; + extern const OpcodeSpec apanWaveform; + extern const OpcodeSpec apanFrequency; + extern const OpcodeSpec apanPhase; + extern const OpcodeSpec apanLevel; + extern const OpcodeSpec distoTone; + extern const OpcodeSpec distoDepth; + extern const OpcodeSpec distoStages; + extern const OpcodeSpec compAttack; + extern const OpcodeSpec compRelease; + extern const OpcodeSpec compThreshold; + extern const OpcodeSpec compRatio; + extern const OpcodeSpec compGain; + extern const OpcodeSpec fverbSize; + extern const OpcodeSpec fverbPredelay; + extern const OpcodeSpec fverbTone; + extern const OpcodeSpec fverbDamp; + extern const OpcodeSpec gateAttack; + extern const OpcodeSpec gateRelease; + extern const OpcodeSpec gateHold; + extern const OpcodeSpec gateThreshold; + extern const OpcodeSpec lofiBitred; + extern const OpcodeSpec lofiDecim; + extern const OpcodeSpec rectify; + extern const OpcodeSpec stringsNumber; - // common defaults - constexpr Range midi7Range { 0, 127 }; - constexpr Range float7Range { 0.0f, 127.0f }; - constexpr Range normalizedRange { 0.0f, 1.0f }; - constexpr Range symmetricNormalizedRange { -1.0, 1.0 }; + // Boolean default values + constexpr bool rtDead { false }; + constexpr bool checkSustain { true }; // sustain_sw + constexpr bool checkSostenuto { true }; // sostenuto_sw - // Wavetable oscillator - constexpr float oscillatorPhase { 0.0 }; - constexpr Range oscillatorPhaseRange { -1.0, 1.0 }; - constexpr int oscillatorMode { 0 }; - constexpr int oscillatorMulti { 1 }; - constexpr Range oscillatorModeRange { 0, 2 }; - constexpr Range oscillatorMultiRange { 1, config::oscillatorsPerVoice }; - constexpr float oscillatorDetune { 0 }; - constexpr Range oscillatorDetuneRange { -12000, 12000 }; - constexpr Range oscillatorDetuneCCRange { -12000, 12000 }; - constexpr float oscillatorModDepth { 0 }; - constexpr Range oscillatorModDepthRange { 0, 10000 }; // depth%, allowed to be >100 for FM - constexpr Range oscillatorModDepthCCRange { 0, 10000 }; - constexpr int oscillatorQuality { 1 }; - constexpr Range oscillatorQualityRange { 0, 3 }; + // Default/max count for objects + constexpr int numEQs { 3 }; + constexpr int numFilters { 2 }; + constexpr int numFlexEGs { 4 }; + constexpr int numFlexEGPoints { 8 }; + constexpr int numLFOs { 4 }; + constexpr int numLFOSubs { 2 }; + constexpr int numLFOSteps { 8 }; + constexpr int maxDistoStages { 4 }; + constexpr unsigned maxStrings { 88 }; - // Instrument setting: voice lifecycle - constexpr uint32_t group { 0 }; - constexpr Range groupRange { 0, std::numeric_limits::max() }; - constexpr SfzOffMode offMode { SfzOffMode::fast }; - constexpr float offTime { 6e-3f }; - constexpr Range polyphonyRange { 0, config::maxVoices }; + // Default values for enums + constexpr SfzTrigger trigger { SfzTrigger::attack }; + constexpr SfzOffMode offMode { SfzOffMode::fast }; + constexpr SfzVelocityOverride velocityOverride { SfzVelocityOverride::current }; constexpr SfzSelfMask selfMask { SfzSelfMask::mask }; + constexpr SfzCrossfadeCurve crossfadeKeyCurve { SfzCrossfadeCurve::power }; + constexpr SfzCrossfadeCurve crossfadeVelCurve { SfzCrossfadeCurve::power }; + constexpr SfzCrossfadeCurve crossfadeCCCurve { SfzCrossfadeCurve::power }; - // Region logic: key mapping - constexpr Range keyRange { 0, 127 }; - constexpr auto velocityRange = normalizedRange; - - // Region logic: MIDI conditions - constexpr Range channelRange { 1, 16 }; - constexpr Range midiChannelRange { 0, 15 }; - constexpr Range smoothCCRange { 0, 100 }; - constexpr float smoothTauPerStep { 3e-3 }; - constexpr Range curveCCRange { 0, 255 }; - constexpr Range ccNumberRange { 0, config::numCCs }; - constexpr auto ccValueRange = normalizedRange; - constexpr Range bendRange = { -8192, 8192 }; - constexpr Range bendValueRange = symmetricNormalizedRange; - constexpr int bend { 0 }; - constexpr SfzVelocityOverride velocityOverride { SfzVelocityOverride::current }; - - // Region logic: internal conditions - constexpr Range randRange { 0.0, 1.0 }; - constexpr Range aftertouchRange { 0, 127 }; - constexpr uint8_t aftertouch { 0 }; - constexpr Range bpmRange { 0.0, 500.0 }; - constexpr float bpm { 120.0 }; - constexpr uint8_t sequenceLength{ 1 }; - constexpr uint8_t sequencePosition{ 1 }; - constexpr Range sequenceRange { 1, 100 }; - - // Region logic: Triggers - constexpr SfzTrigger trigger { SfzTrigger::attack }; - constexpr Range ccTriggerValueRange = normalizedRange; - - // Performance parameters: amplifier - constexpr float globalVolume { -7.35f }; - constexpr float volume { 0.0f }; - constexpr Range volumeRange { -144.0, 48.0 }; - constexpr Range volumeCCRange { -144.0, 48.0 }; - constexpr float amplitude { 100.0 }; - constexpr Range amplitudeRange { 0.0, 1e8 }; - constexpr float pan { 0.0 }; - constexpr Range panRange { -100.0, 100.0 }; - constexpr Range panCCRange { -200.0, 200.0 }; - constexpr float position { 0.0 }; - constexpr Range positionRange { -100.0, 100.0 }; - constexpr Range positionCCRange { -200.0, 200.0 }; - constexpr float width { 100.0 }; - constexpr Range widthRange { -100.0, 100.0 }; - constexpr Range widthCCRange { -200.0, 200.0 }; - constexpr uint8_t ampKeycenter { 60 }; - constexpr float ampKeytrack { 0.0 }; - constexpr Range ampKeytrackRange { -96, 12 }; - constexpr float ampVeltrack { 100.0 }; - constexpr Range ampVeltrackRange { -100.0, 100.0 }; - constexpr Range ampVelcurveRange { 0.0, 1.0 }; - constexpr float ampRandom { 0.0 }; - constexpr Range ampRandomRange { 0.0, 24.0 }; - constexpr Range crossfadeKeyInRange { 0, 0 }; - constexpr Range crossfadeKeyOutRange { 127, 127 }; + // Default values for ranges + constexpr Range crossfadeKeyInRange { 0, 0 }; + constexpr Range crossfadeKeyOutRange { 127, 127 }; constexpr Range crossfadeVelInRange { 0.0f, 0.0f }; constexpr Range crossfadeVelOutRange { 1.0f, 1.0f }; constexpr Range crossfadeCCInRange { 0.0f, 0.0f }; constexpr Range crossfadeCCOutRange { 1.0f, 1.0f }; - constexpr SfzCrossfadeCurve crossfadeKeyCurve { SfzCrossfadeCurve::power }; - constexpr SfzCrossfadeCurve crossfadeVelCurve { SfzCrossfadeCurve::power }; - constexpr SfzCrossfadeCurve crossfadeCCCurve { SfzCrossfadeCurve::power }; - constexpr float rtDecay { 0.0f }; - constexpr bool rtDead { false }; - constexpr Range rtDecayRange { 0.0f, 200.0f }; - // Performance parameters: Filters - constexpr int numFilters { 2 }; - constexpr float filterCutoff { 0 }; - constexpr float filterResonance { 0 }; - constexpr float filterGain { 0 }; - constexpr int filterKeytrack { 0 }; - constexpr uint8_t filterKeycenter { 60 }; - constexpr float filterRandom { 0 }; - constexpr int filterVeltrack { 0 }; - constexpr float filterCutoffCC { 0 }; - constexpr float filterResonanceCC { 0 }; - constexpr float filterGainCC { 0 }; - constexpr Range filterCutoffRange { 0.0f, 20000.0f }; - constexpr Range filterCutoffModRange { -12000, 12000 }; - constexpr Range filterGainRange { -96.0f, 96.0f }; - constexpr Range filterGainModRange { -96.0f, 96.0f }; - constexpr Range filterKeytrackRange { 0, 1200 }; - constexpr Range filterRandomRange { 0, 12000 }; - constexpr Range filterVeltrackRange { -12000, 12000 }; - constexpr Range filterResonanceRange { 0.0f, 96.0f }; - constexpr Range filterResonanceModRange { 0.0f, 96.0f }; + // Various defaut values + // e.g. "additional" or multiple defautl values + constexpr int freewheelingQuality { 10 }; + constexpr float globalVolume { -7.35f }; + constexpr float defaultEQFreq [numEQs] { 50.0f, 500.0f, 5000.0f }; +} // namespace Default - // Performance parameters: EQ - constexpr int numEQs { 3 }; - constexpr float eqBandwidth { 1.0f }; - constexpr float eqBandwidthCC { 0.0f }; - constexpr float eqFrequencyUnset { 0.0f }; - constexpr float eqFrequency1 { 50.0f }; - constexpr float eqFrequency2 { 500.0f }; - constexpr float eqFrequency3 { 5000.0f }; - constexpr float eqFrequencyCC { 0.0f }; - constexpr float eqGain { 0.0f }; - constexpr float eqGainCC { 0.0f }; - constexpr float eqVel2frequency { 0.0f }; - constexpr float eqVel2gain { 0.0f }; - constexpr Range eqBandwidthRange { 0.001f, 4.0f }; - constexpr Range eqBandwidthModRange { -4.0f, 4.0f }; - constexpr Range eqFrequencyRange { 0.0f, 30000.0f }; - constexpr Range eqFrequencyModRange { -30000.0f, 30000.0f }; - constexpr Range eqGainRange { -96.0f, 96.0f }; - constexpr Range eqGainModRange { -96.0f, 96.0f }; - - // Performance parameters: pitch - constexpr uint8_t pitchKeycenter { 60 }; - constexpr int pitchKeytrack { 100 }; - constexpr Range pitchKeytrackRange { -1200, 1200 }; - constexpr float pitchRandom { 0 }; - constexpr Range pitchRandomRange { 0, 12000 }; - constexpr int pitchVeltrack { 0 }; - constexpr Range pitchVeltrackRange { -12000, 12000 }; - constexpr int transpose { 0 }; - constexpr Range transposeRange { -127, 127 }; - constexpr float tune { 0 }; - constexpr Range tuneRange { -12000, 12000 }; // ±100 in SFZv1, more in ARIA - constexpr Range tuneCCRange { -12000, 12000 }; - constexpr Range bendBoundRange { -12000, 12000 }; - constexpr Range bendStepRange { 1, 1200 }; - 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 }; - - // Modulation: LFO - constexpr int numLFOs { 4 }; - constexpr int numLFOSubs { 2 }; - constexpr int numLFOSteps { 8 }; - constexpr Range lfoFreqRange { 0.0, 100.0 }; - constexpr Range lfoFreqModRange { -100.0, 100.0 }; - constexpr Range lfoBeatsRange { 0.0, 1000.0 }; - constexpr Range lfoBeatsModRange { -1000.0, 1000.0 }; - constexpr Range lfoPhaseRange { 0.0, 1.0 }; - constexpr Range lfoDelayRange { 0.0, 30.0 }; - constexpr Range lfoFadeRange { 0.0, 30.0 }; - constexpr Range lfoCountRange { 0, 1000 }; - constexpr Range lfoStepsRange { 0, static_cast(config::maxLFOSteps) }; - constexpr Range lfoStepXRange { -100.0, 100.0 }; - constexpr Range lfoWaveRange { 0, 15 }; - constexpr Range lfoOffsetRange { -1.0, 1.0 }; - constexpr Range lfoRatioRange { 0.0, 100.0 }; - constexpr Range lfoScaleRange { 0.0, 1.0 }; - - // Envelope generators - constexpr float attack { 0 }; - constexpr float decay { 0 }; - constexpr float delayEG { 0 }; - constexpr float hold { 0 }; - constexpr float release { 0 }; - constexpr float ampegRelease { 0.001 }; // Default release to avoid clicks - constexpr float vel2release { 0.0f }; - constexpr float start { 0.0 }; - constexpr float sustain { 100.0 }; - constexpr uint16_t sustainCC { 64 }; - constexpr float sustainThreshold { 0.0039f }; // sforzando default (0.5f/127.0f) - constexpr float vel2sustain { 0.0 }; - constexpr int depth { 0 }; - constexpr Range egTimeRange { 0.0, 100.0 }; - constexpr Range egPercentRange { 0.0, 100.0 }; - constexpr Range egDepthRange { -12000, 12000 }; - constexpr Range egOnCCTimeRange { -100.0, 100.0 }; - constexpr Range egOnCCPercentRange { -100.0, 100.0 }; - constexpr Range pitchEgDepthRange { -12000.0, 12000.0 }; - constexpr Range filterEgDepthRange { -12000.0, 12000.0 }; - - // Flex envelope generators - constexpr int numFlexEGs { 4 }; - constexpr int numFlexEGPoints { 8 }; - constexpr int flexEGDynamic { 0 }; - constexpr int flexEGSustain { 0 }; - constexpr float flexEGPointTime { 0 }; - constexpr float flexEGPointLevel { 0 }; - constexpr float flexEGPointShape { 0 }; - constexpr Range flexEGDynamicRange { 0, 1 }; - constexpr Range flexEGSustainRange { 0, 100 }; - constexpr Range flexEGPointTimeRange { 0.0f, 100.0f }; - constexpr Range flexEGPointLevelRange { -1.0f, 1.0f }; - constexpr Range flexEGPointShapeRange { -100.0f, 100.0f }; - - // ***** SFZ v2 ******** - constexpr int sampleQuality { 1 }; - constexpr int sampleQualityInFreewheelingMode { 10 }; // for future use, possibly excessive - constexpr Range sampleQualityRange { 1, 10 }; // sample_quality - - constexpr bool checkSustain { true }; // sustain_sw - constexpr bool checkSostenuto { true }; // sostenuto_sw - constexpr Range octaveOffsetRange { -10, 10 }; // octave_offset - constexpr Range noteOffsetRange { -127, 127 }; // note_offset - - constexpr Range apanWaveformRange { 0, std::numeric_limits::max() }; - constexpr Range apanFrequencyRange { 0, std::numeric_limits::max() }; - constexpr Range apanPhaseRange { 0.0, 1.0 }; - constexpr Range apanLevelRange { 0.0, 100.0 }; -} -} +} // namespace sfz diff --git a/src/sfizz/EGDescription.h b/src/sfizz/EGDescription.h index 5cfe0d94..89edfde2 100644 --- a/src/sfizz/EGDescription.h +++ b/src/sfizz/EGDescription.h @@ -66,21 +66,21 @@ struct EGDescription { EGDescription& operator=(const EGDescription&) = default; EGDescription& operator=(EGDescription&&) = default; - float attack { Default::attack }; - float decay { Default::decay }; - float delay { Default::delayEG }; - float hold { Default::hold }; - float release { Default::release }; - float start { Default::start }; - float sustain { Default::sustain }; - int depth { Default::depth }; - float vel2attack { Default::attack }; - float vel2decay { Default::decay }; - float vel2delay { Default::delayEG }; - float vel2hold { Default::hold }; - float vel2release { Default::vel2release }; - float vel2sustain { Default::vel2sustain }; - int vel2depth { Default::depth }; + float attack { Default::egTime.value }; + float decay { Default::egTime.value }; + float delay { Default::egTime.value }; + float hold { Default::egTime.value }; + float release { Default::egTime.value }; + float start { Default::egPercent.bounds.getStart() }; + float sustain { Default::egPercent.bounds.getEnd() }; + float depth { Default::egDepth.value }; + float vel2attack { Default::egTimeMod.value }; + float vel2decay { Default::egTimeMod.value }; + float vel2delay { Default::egTimeMod.value }; + float vel2hold { Default::egTimeMod.value }; + float vel2release { Default::egPercentMod.value }; + float vel2sustain { Default::egPercentMod.value }; + float vel2depth { Default::egVel2Depth.value }; CCMap ccAttack; CCMap ccDecay; @@ -104,7 +104,7 @@ struct EGDescription { for (auto& mod: ccAttack) { returnedValue += state.getCCValue(mod.cc) * mod.data; } - return Default::egTimeRange.clamp(returnedValue); + return Default::egTime.bounds.clamp(returnedValue); } /** * @brief Get the decay with possibly a CC modifier and a velocity modifier @@ -120,7 +120,7 @@ struct EGDescription { for (auto& mod: ccDecay) { returnedValue += state.getCCValue(mod.cc) * mod.data; } - return Default::egTimeRange.clamp(returnedValue); + return Default::egTime.bounds.clamp(returnedValue); } /** * @brief Get the delay with possibly a CC modifier and a velocity modifier @@ -136,7 +136,7 @@ struct EGDescription { for (auto& mod: ccDelay) { returnedValue += state.getCCValue(mod.cc) * mod.data; } - return Default::egTimeRange.clamp(returnedValue); + return Default::egTime.bounds.clamp(returnedValue); } /** * @brief Get the holding duration with possibly a CC modifier and a velocity modifier @@ -152,7 +152,7 @@ struct EGDescription { for (auto& mod: ccHold) { returnedValue += state.getCCValue(mod.cc) * mod.data; } - return Default::egTimeRange.clamp(returnedValue); + return Default::egTime.bounds.clamp(returnedValue); } /** * @brief Get the release duration with possibly a CC modifier and a velocity modifier @@ -168,7 +168,7 @@ struct EGDescription { for (auto& mod: ccRelease) { returnedValue += state.getCCValue(mod.cc) * mod.data; } - return Default::egTimeRange.clamp(returnedValue); + return Default::egTime.bounds.clamp(returnedValue); } /** * @brief Get the starting level with possibly a CC modifier and a velocity modifier @@ -184,7 +184,7 @@ struct EGDescription { for (auto& mod: ccStart) { returnedValue += state.getCCValue(mod.cc) * mod.data; } - return Default::egPercentRange.clamp(returnedValue); + return Default::egPercent.bounds.clamp(returnedValue); } /** * @brief Get the sustain level with possibly a CC modifier and a velocity modifier @@ -200,7 +200,7 @@ struct EGDescription { for (auto& mod: ccSustain) { returnedValue += state.getCCValue(mod.cc) * mod.data; } - return Default::egPercentRange.clamp(returnedValue); + return Default::egPercent.bounds.clamp(returnedValue); } LEAK_DETECTOR(EGDescription); }; diff --git a/src/sfizz/EQDescription.h b/src/sfizz/EQDescription.h index c109a4a0..246d545b 100644 --- a/src/sfizz/EQDescription.h +++ b/src/sfizz/EQDescription.h @@ -14,11 +14,11 @@ namespace sfz { struct EQDescription { - float bandwidth { Default::eqBandwidth }; - float frequency { Default::eqFrequencyUnset }; - float gain { Default::eqGain }; - float vel2frequency { Default::eqVel2frequency }; - float vel2gain { Default::eqVel2gain }; + float bandwidth { Default::eqBandwidth.value }; + float frequency { Default::eqFrequency.value }; + float gain { Default::eqGain.value }; + float vel2frequency { Default::eqVel2Frequency.value }; + float vel2gain { Default::eqVel2Gain.value }; EqType type { EqType::kEqPeak }; }; } diff --git a/src/sfizz/EQPool.h b/src/sfizz/EQPool.h index 4670daac..63ba5dde 100644 --- a/src/sfizz/EQPool.h +++ b/src/sfizz/EQPool.h @@ -43,9 +43,9 @@ private: Resources& resources; const EQDescription* description; std::unique_ptr eq; - float baseBandwidth { Default::eqBandwidth }; - float baseFrequency { Default::eqFrequency1 }; - float baseGain { Default::eqGain }; + float baseBandwidth { Default::eqBandwidth.value }; + float baseFrequency { Default::eqFrequency.value }; + float baseGain { Default::eqGain.value }; bool prepared { false }; ModMatrix::TargetId gainTarget; ModMatrix::TargetId frequencyTarget; diff --git a/src/sfizz/Effects.h b/src/sfizz/Effects.h index 2056cac2..838557a8 100644 --- a/src/sfizz/Effects.h +++ b/src/sfizz/Effects.h @@ -6,6 +6,7 @@ #pragma once #include "AudioBuffer.h" +#include "Defaults.h" #include "absl/strings/string_view.h" #include "absl/types/span.h" #include @@ -178,8 +179,8 @@ private: std::vector> _effects; AudioBuffer _inputs { EffectChannels, config::defaultSamplesPerBlock }; AudioBuffer _outputs { EffectChannels, config::defaultSamplesPerBlock }; - float _gainToMain = 0.0; - float _gainToMix = 0.0; + float _gainToMain { Default::effect.value }; + float _gainToMix { Default::effect.value }; }; } // namespace sfz diff --git a/src/sfizz/FilePool.h b/src/sfizz/FilePool.h index fa67db72..2c77f6d9 100644 --- a/src/sfizz/FilePool.h +++ b/src/sfizz/FilePool.h @@ -51,10 +51,10 @@ using FileAudioBuffer = AudioBuffer; struct FileInformation { - uint32_t end { Default::sampleEndRange.getEnd() }; + uint32_t end { Default::sampleEnd.value }; uint32_t maxOffset { 0 }; - uint32_t loopBegin { Default::loopRange.getStart() }; - uint32_t loopEnd { Default::loopRange.getEnd() }; + uint32_t loopBegin { Default::loopRange.bounds.getStart() }; + uint32_t loopEnd { Default::loopRange.bounds.getEnd() }; bool hasLoop { false }; double sampleRate { config::defaultSampleRate }; int numChannels { 0 }; diff --git a/src/sfizz/FilterDescription.h b/src/sfizz/FilterDescription.h index 2f3193a0..7bdc39b6 100644 --- a/src/sfizz/FilterDescription.h +++ b/src/sfizz/FilterDescription.h @@ -14,13 +14,13 @@ namespace sfz { struct FilterDescription { - float cutoff { Default::filterCutoff }; - float resonance { Default::filterCutoff }; - float gain { Default::filterGain }; - int keytrack { Default::filterKeytrack }; - uint8_t keycenter { Default::filterKeycenter }; - int veltrack { Default::filterVeltrack }; - float random { Default::filterRandom }; + float cutoff { Default::filterCutoff.value }; + float resonance { Default::filterCutoff.value }; + float gain { Default::filterGain.value }; + int keytrack { Default::filterKeytrack.value }; + uint8_t keycenter { Default::key.value }; + int veltrack { Default::filterVeltrack.value }; + float random { Default::filterRandom.value }; FilterType type { FilterType::kFilterLpf2p }; }; } diff --git a/src/sfizz/FilterPool.cpp b/src/sfizz/FilterPool.cpp index d8c16e40..46b38d41 100644 --- a/src/sfizz/FilterPool.cpp +++ b/src/sfizz/FilterPool.cpp @@ -37,7 +37,7 @@ void sfz::FilterHolder::setup(const Region& region, unsigned filterId, int noteN baseCutoff *= centsFactor(keytrack); const auto veltrack = static_cast(description->veltrack) * velocity; baseCutoff *= centsFactor(veltrack); - baseCutoff = Default::filterCutoffRange.clamp(baseCutoff); + baseCutoff = Default::filterCutoff.bounds.clamp(baseCutoff); baseGain = description->gain; baseResonance = description->resonance; @@ -75,7 +75,7 @@ void sfz::FilterHolder::process(const float** inputs, float** outputs, unsigned for (size_t i = 0; i < numFrames; ++i) (*cutoffSpan)[i] *= centsFactor(mod[i]); } - sfz::clampAll(*cutoffSpan, Default::filterCutoffRange); + sfz::clampAll(*cutoffSpan, Default::filterCutoff.bounds); fill(*resonanceSpan, baseResonance); if (float* mod = mm.getModulation(resonanceTarget)) diff --git a/src/sfizz/FilterPool.h b/src/sfizz/FilterPool.h index d995e0db..13ecbb94 100644 --- a/src/sfizz/FilterPool.h +++ b/src/sfizz/FilterPool.h @@ -22,7 +22,7 @@ public: * @param noteNumber the triggering note number * @param velocity the triggering note velocity/value */ - void setup(const Region& region, unsigned filterId, int noteNumber = static_cast(Default::filterKeycenter), float velocity = 0); + void setup(const Region& region, unsigned filterId, int noteNumber = static_cast(Default::key.value), float velocity = 0); /** * @brief Process a block of stereo inputs * @@ -45,9 +45,9 @@ private: Resources& resources; const FilterDescription* description; std::unique_ptr filter; - float baseCutoff { Default::filterCutoff }; - float baseResonance { Default::filterResonance }; - float baseGain { Default::filterGain }; + float baseCutoff { Default::filterCutoff.value }; + float baseResonance { Default::filterResonance.value }; + float baseGain { Default::filterGain.value }; ModMatrix::TargetId gainTarget; ModMatrix::TargetId cutoffTarget; ModMatrix::TargetId resonanceTarget; diff --git a/src/sfizz/FlexEGDescription.h b/src/sfizz/FlexEGDescription.h index b8a0f59b..84d9078c 100644 --- a/src/sfizz/FlexEGDescription.h +++ b/src/sfizz/FlexEGDescription.h @@ -18,21 +18,21 @@ namespace FlexEGs { }; struct FlexEGPoint { - float time { Default::flexEGPointTime }; // duration until next step (s) - float level { Default::flexEGPointLevel }; // normalized amplitude + float time { Default::flexEGPointTime.value }; // duration until next step (s) + float level { Default::flexEGPointLevel.value }; // normalized amplitude void setShape(float shape); float shape() const noexcept { return shape_; } const Curve& curve() const; private: - float shape_ { Default::flexEGPointShape }; // 0: linear, positive: exp, negative: log + float shape_ { Default::flexEGPointShape.value }; // 0: linear, positive: exp, negative: log std::shared_ptr shapeCurve_; }; struct FlexEGDescription { - int dynamic { Default::flexEGDynamic }; // whether parameters can be modulated while EG runs - int sustain { Default::flexEGSustain }; // index of the sustain point (default to 0 in ARIA) + int dynamic { Default::flexEGDynamic.value }; // whether parameters can be modulated while EG runs + int sustain { Default::flexEGSustain.value }; // index of the sustain point (default to 0 in ARIA) std::vector points; // ARIA bool ampeg = false; // replaces the SFZv1 AmpEG (lowest with this bit wins) diff --git a/src/sfizz/LFODescription.h b/src/sfizz/LFODescription.h index 2628430f..ea312bca 100644 --- a/src/sfizz/LFODescription.h +++ b/src/sfizz/LFODescription.h @@ -5,6 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once +#include "Defaults.h" #include #include @@ -27,17 +28,17 @@ struct LFODescription { LFODescription(); ~LFODescription(); static const LFODescription& getDefault(); - float freq = 0; // lfoN_freq - float beats = 0; // lfoN_beats - float phase0 = 0; // lfoN_phase - float delay = 0; // lfoN_delay - float fade = 0; // lfoN_fade - unsigned count = 0; // lfoN_count + float freq { Default::lfoFreq.value }; // lfoN_freq + float beats { Default::lfoBeats.value }; // lfoN_beats + float phase0 { Default::lfoPhase.value }; // lfoN_phase + float delay { Default::lfoDelay.value }; // lfoN_delay + float fade { Default::lfoFade.value }; // lfoN_fade + unsigned count { Default::lfoCount.value }; // lfoN_count struct Sub { - LFOWave wave = LFOWave::Triangle; // lfoN_wave[X] - float offset = 0; // lfoN_offset[X] - float ratio = 1; // lfoN_ratio[X] - float scale = 1; // lfoN_scale[X] + LFOWave wave { static_cast(Default::lfoWave.value) }; // lfoN_wave[X] + float offset { Default::lfoOffset.value }; // lfoN_offset[X] + float ratio { Default::lfoRatio.value }; // lfoN_ratio[X] + float scale { Default::lfoScale.value }; // lfoN_scale[X] }; struct StepSequence { std::vector steps {}; // lfoN_stepX - normalized to unity diff --git a/src/sfizz/Opcode.cpp b/src/sfizz/Opcode.cpp index 1a60ff78..87f2e109 100644 --- a/src/sfizz/Opcode.cpp +++ b/src/sfizz/Opcode.cpp @@ -117,6 +117,116 @@ OpcodeCategory Opcode::identifyCategory(absl::string_view name) return category; } +template +absl::optional readInt_(OpcodeSpec spec, absl::string_view v) +{ + size_t numberEnd = 0; + + if (numberEnd < v.size() && (v[numberEnd] == '+' || v[numberEnd] == '-')) + ++numberEnd; + + while (numberEnd < v.size() && absl::ascii_isdigit(v[numberEnd])) + ++numberEnd; + + if (numberEnd == 0 && (spec.flags & kCanBeNote)) + return readNoteValue(v); + + v = v.substr(0, numberEnd); + + int64_t returnedValue; + if (!absl::SimpleAtoi(v, &returnedValue)) + return absl::nullopt; + + if (returnedValue > static_cast(spec.bounds.getEnd())) { + if (spec.flags & kEnforceUpperBound) + return spec.bounds.getEnd(); + + if (spec.flags & kIgnoreOOB) + return {}; + } + + if (returnedValue < static_cast(spec.bounds.getStart())) { + if (spec.flags & kEnforceLowerBound) + return spec.bounds.getStart(); + + if (spec.flags & kIgnoreOOB) + return {}; + } + + T castValue = static_cast(returnedValue); + if ((castValue != returnedValue) & kIgnoreOOB) + return {}; + + return castValue; +} + +#define INSTANTIATE_FOR_INTEGRAL(T) \ + template <> \ + absl::optional Opcode::read(OpcodeSpec spec) const \ + { \ + return readInt_(spec, value); \ + } + +INSTANTIATE_FOR_INTEGRAL(uint8_t) +INSTANTIATE_FOR_INTEGRAL(uint16_t) +INSTANTIATE_FOR_INTEGRAL(uint32_t) +INSTANTIATE_FOR_INTEGRAL(int8_t) +INSTANTIATE_FOR_INTEGRAL(int16_t) +INSTANTIATE_FOR_INTEGRAL(int32_t) +INSTANTIATE_FOR_INTEGRAL(int64_t) + + +template +absl::optional readFloat_(OpcodeSpec spec, absl::string_view v) +{ + size_t numberEnd = 0; + + if (numberEnd < v.size() && (v[numberEnd] == '+' || v[numberEnd] == '-')) + ++numberEnd; + while (numberEnd < v.size() && absl::ascii_isdigit(v[numberEnd])) + ++numberEnd; + + if (numberEnd < v.size() && v[numberEnd] == '.') { + ++numberEnd; + while (numberEnd < v.size() && absl::ascii_isdigit(v[numberEnd])) + ++numberEnd; + } + + v = v.substr(0, numberEnd); + + float returnedValue; + if (!absl::SimpleAtof(v, &returnedValue)) + return absl::nullopt; + + if (returnedValue > static_cast(spec.bounds.getEnd())) { + if (spec.flags & kEnforceUpperBound) + return spec.bounds.getEnd(); + + if (spec.flags & kIgnoreOOB) + return {}; + } + + if (returnedValue < static_cast(spec.bounds.getStart())) { + if (spec.flags & kEnforceLowerBound) + return spec.bounds.getStart(); + + if (spec.flags & kIgnoreOOB) + return {}; + } + + return returnedValue; +} + +#define INSTANTIATE_FOR_FLOATING_POINT(T) \ + template <> \ + absl::optional Opcode::read(OpcodeSpec spec) const \ + { \ + return readFloat_(spec, value); \ + } + +INSTANTIATE_FOR_FLOATING_POINT(float) +INSTANTIATE_FOR_FLOATING_POINT(double) + absl::optional readNoteValue(absl::string_view value) { char noteLetter = absl::ascii_tolower(value.empty() ? '\0' : value.front()); @@ -167,56 +277,6 @@ absl::optional readNoteValue(absl::string_view value) return static_cast(noteNumber); } -/// -template ::value, int>> -absl::optional readOpcode(absl::string_view value, const Range& validRange) -{ - size_t numberEnd = 0; - - if (numberEnd < value.size() && (value[numberEnd] == '+' || value[numberEnd] == '-')) - ++numberEnd; - while (numberEnd < value.size() && absl::ascii_isdigit(value[numberEnd])) - ++numberEnd; - - value = value.substr(0, numberEnd); - - int64_t returnedValue; - if (!absl::SimpleAtoi(value, &returnedValue)) - return absl::nullopt; - - if (returnedValue > std::numeric_limits::max()) - returnedValue = std::numeric_limits::max(); - if (returnedValue < std::numeric_limits::min()) - returnedValue = std::numeric_limits::min(); - - return validRange.clamp(static_cast(returnedValue)); -} - -template ::value, int>> -absl::optional readOpcode(absl::string_view value, const Range& validRange) -{ - size_t numberEnd = 0; - - if (numberEnd < value.size() && (value[numberEnd] == '+' || value[numberEnd] == '-')) - ++numberEnd; - while (numberEnd < value.size() && absl::ascii_isdigit(value[numberEnd])) - ++numberEnd; - - if (numberEnd < value.size() && value[numberEnd] == '.') { - ++numberEnd; - while (numberEnd < value.size() && absl::ascii_isdigit(value[numberEnd])) - ++numberEnd; - } - - value = value.substr(0, numberEnd); - - float returnedValue; - if (!absl::SimpleAtof(value, &returnedValue)) - return absl::nullopt; - - return validRange.clamp(returnedValue); -} - absl::optional readBooleanFromOpcode(const Opcode& opcode) { // Cakewalk-style booleans, case-insensitive @@ -227,84 +287,13 @@ absl::optional readBooleanFromOpcode(const Opcode& opcode) // ARIA-style booleans? (seen in egN_dynamic=1 for example) // TODO check this - if (auto value = readOpcode(opcode.value, Range::wholeRange())) + const OpcodeSpec fullInt64 { 0, Range::wholeRange(), 0 }; + if (auto value = opcode.read(fullInt64)) return *value != 0; return absl::nullopt; } -template -void setValueFromOpcode(const Opcode& opcode, ValueType& target, const Range& validRange) -{ - auto value = readOpcode(opcode.value, validRange); - if (!value) // Try and read a note rather than a number - value = readNoteValue(opcode.value); - if (value) - target = *value; -} - -template -inline void setValueFromOpcode(const Opcode& opcode, absl::optional& target, const Range& validRange) -{ - auto value = readOpcode(opcode.value, validRange); - if (!value) // Try and read a note rather than a number - value = readNoteValue(opcode.value); - if (value) - target = *value; -} - -template -void setRangeEndFromOpcode(const Opcode& opcode, Range& target, const Range& validRange) -{ - auto value = readOpcode(opcode.value, validRange); - if (!value) // Try and read a note rather than a number - value = readNoteValue(opcode.value); - if (value) - target.setEnd(*value); -} - -template -void setRangeStartFromOpcode(const Opcode& opcode, Range& target, const Range& validRange) -{ - auto value = readOpcode(opcode.value, validRange); - if (!value) // Try and read a note rather than a number - value = readNoteValue(opcode.value); - if (value) - target.setStart(*value); -} - -template -void setCCPairFromOpcode(const Opcode& opcode, absl::optional>& target, const Range& validRange) -{ - auto value = readOpcode(opcode.value, validRange); - if (value && Default::ccNumberRange.containsWithEnd(opcode.parameters.back())) - target = { opcode.parameters.back(), *value }; - else - target = {}; -} - -/// -#define INSTANCIATE_FOR(T) \ - template absl::optional readOpcode(absl::string_view value, const Range& validRange); /*NOLINT(bugprone-macro-parentheses)*/ \ - template void setValueFromOpcode(const Opcode& opcode, T& target, const Range& validRange); /*NOLINT(bugprone-macro-parentheses)*/ \ - template void setValueFromOpcode(const Opcode& opcode, absl::optional& target, const Range& validRange); /*NOLINT(bugprone-macro-parentheses)*/ \ - template void setRangeEndFromOpcode(const Opcode& opcode, Range& target, const Range& validRange); /*NOLINT(bugprone-macro-parentheses)*/ \ - template void setRangeStartFromOpcode(const Opcode& opcode, Range& target, const Range& validRange); /*NOLINT(bugprone-macro-parentheses)*/ \ - template void setCCPairFromOpcode(const Opcode& opcode, absl::optional>& target, const Range& validRange); /*NOLINT(bugprone-macro-parentheses)*/ - -INSTANCIATE_FOR(float) -INSTANCIATE_FOR(double) -INSTANCIATE_FOR(int8_t) -INSTANCIATE_FOR(int16_t) -INSTANCIATE_FOR(int32_t) -INSTANCIATE_FOR(int64_t) -INSTANCIATE_FOR(uint8_t) -INSTANCIATE_FOR(uint16_t) -INSTANCIATE_FOR(uint32_t) -//INSTANCIATE_FOR(uint64_t) - -#undef INSTANCIATE_FOR - } // namespace sfz std::ostream &operator<<(std::ostream &os, const sfz::Opcode &opcode) diff --git a/src/sfizz/Opcode.h b/src/sfizz/Opcode.h index a6c3a1d6..51ff6088 100644 --- a/src/sfizz/Opcode.h +++ b/src/sfizz/Opcode.h @@ -101,6 +101,9 @@ struct Opcode { category == kOpcodeStepCcN || category == kOpcodeSmoothCcN; } + template + absl::optional read(OpcodeSpec spec) const; + private: static OpcodeCategory identifyCategory(absl::string_view name); LEAK_DETECTOR(Opcode); @@ -114,96 +117,11 @@ private: */ absl::optional readNoteValue(absl::string_view value); -/** - * @brief Read a value from the sfz file and cast it to the destination parameter along - * with a proper clamping into range if needed. This particular template version acts on - * integral target types, but can accept floats as an input. - * - * @tparam ValueType the target casting type - * @param value the string value to be read and stored - * @param validRange the range of admitted values - * @return absl::optional the cast value, or null - */ -template ::value, int> = 0> -absl::optional readOpcode(absl::string_view value, const Range& validRange); - -/** - * @brief Read a value from the sfz file and cast it to the destination parameter along - * with a proper clamping into range if needed. This particular template version acts on - * floating types. - * - * @tparam ValueType the target casting type - * @param value the string value to be read and stored - * @param validRange the range of admitted values - * @return absl::optional the cast value, or null - */ -template ::value, int> = 0> -absl::optional readOpcode(absl::string_view value, const Range& validRange); - /** * @brief Read a boolean value from the sfz file and cast it to the destination parameter. */ absl::optional readBooleanFromOpcode(const Opcode& opcode); -/** - * @brief Set a target parameter from an opcode value, with possibly a textual note rather - * than a number - * - * @tparam ValueType - * @param opcode the source opcode - * @param target the value to update - * @param validRange the range of admitted values used to clamp the opcode - */ -template -void setValueFromOpcode(const Opcode& opcode, ValueType& target, const Range& validRange); - -/** - * @brief Set a target parameter from an opcode value, with possibly a textual note rather - * than a number - * - * @tparam ValueType - * @param opcode the source opcode - * @param target the value to update - * @param validRange the range of admitted values used to clamp the opcode - */ -template -void setValueFromOpcode(const Opcode& opcode, absl::optional& target, const Range& validRange); - -/** - * @brief Set a target end of a range from an opcode value, with possibly a textual note rather - * than a number - * - * @tparam ValueType - * @param opcode the source opcode - * @param target the value to update - * @param validRange the range of admitted values used to clamp the opcode - */ -template -void setRangeEndFromOpcode(const Opcode& opcode, Range& target, const Range& validRange); - -/** - * @brief Set a target beginning of a range from an opcode value, with possibly a textual note rather - * than a number - * - * @tparam ValueType - * @param opcode the source opcode - * @param target the value to update - * @param validRange the range of admitted values used to clamp the opcode - */ -template -void setRangeStartFromOpcode(const Opcode& opcode, Range& target, const Range& validRange); - -/** - * @brief Set a CC modulation parameter from an opcode value. - * - * @tparam ValueType - * @param opcode the source opcode - * @param target the new CC modulation parameter - * @param validRange the range of admitted values used to clamp the opcode - */ -template -void setCCPairFromOpcode(const Opcode& opcode, absl::optional>& target, const Range& validRange); - } std::ostream &operator<<(std::ostream &os, const sfz::Opcode &opcode); diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index fbbee939..d84fbc52 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -33,6 +33,18 @@ bool extendIfNecessary(std::vector& vec, unsigned size, unsigned defaultCapac return true; } +sfz::Region::Region(int regionNumber, const MidiState& midiState, absl::string_view defaultPath) +: id{regionNumber}, midiState(midiState), defaultPath(std::move(defaultPath)) +{ + ccSwitched.set(); + + gainToEffect.reserve(5); // sufficient room for main and fx1-4 + gainToEffect.push_back(1.0); // contribute 100% into the main bus + + // Default amplitude release + amplitudeEG.release = Default::egRelease.value; +} + bool sfz::Region::parseOpcode(const Opcode& rawOpcode) { const Opcode opcode = rawOpcode.cleanUp(kOpcodeScopeRegion); @@ -45,7 +57,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash(x "_stepcc&"): \ case hash(x "_smoothcc&") - #define LFO_EG_filter_EQ_target(sourceKey, targetKey, range) \ + #define LFO_EG_filter_EQ_target(sourceKey, targetKey, spec) \ { \ const auto number = opcode.parameters.front(); \ if (number == 0) \ @@ -55,7 +67,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(filters, index + 1, Default::numFilters)) \ return false; \ \ - if (auto value = readOpcode(opcode.value, range)) { \ + if (auto value = opcode.read(spec)) { \ const ModKey source = ModKey::createNXYZ(sourceKey, id, number - 1); \ const ModKey target = ModKey::createNXYZ(targetKey, id, index); \ getOrCreateConnection(source, target).sourceDepth = *value; \ @@ -82,8 +94,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) { if (opcode.value == "-1") sampleQuality.reset(); - else - setValueFromOpcode(opcode, sampleQuality, Default::sampleQualityRange); + else if (auto value = opcode.read(Default::sampleQuality)) + sampleQuality = *value; break; } break; @@ -91,28 +103,29 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) *sampleId = sampleId->reversed(opcode.value == "reverse"); break; case hash("delay"): - setValueFromOpcode(opcode, delay, Default::delayRange); + delay = opcode.read(Default::delay).value_or(delay); break; case hash("delay_random"): - setValueFromOpcode(opcode, delayRandom, Default::delayRange); + delayRandom = opcode.read(Default::delayRandom).value_or(delayRandom); break; case hash("offset"): - setValueFromOpcode(opcode, offset, Default::offsetRange); + offset = opcode.read(Default::offset).value_or(offset); break; case hash("offset_random"): - setValueFromOpcode(opcode, offsetRandom, Default::offsetRange); + offsetRandom = opcode.read(Default::offsetRandom).value_or(offsetRandom); break; case hash("offset_oncc&"): // also offset_cc& if (opcode.parameters.back() > config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::offsetCCRange)) + if (auto value = opcode.read(Default::offsetMod)) offsetCC[opcode.parameters.back()] = *value; break; case hash("end"): - setValueFromOpcode(opcode, sampleEnd, Default::sampleEndRange); + sampleEnd = opcode.read(Default::sampleEnd).value_or(sampleEnd); break; case hash("count"): - setValueFromOpcode(opcode, sampleCount, Default::sampleCountRange); + if (auto value = opcode.read(Default::sampleCount)) + sampleCount = *value; break; case hash("loop_mode"): // also loopmode switch (hash(opcode.value)) { @@ -133,18 +146,20 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) } break; case hash("loop_end"): // also loopend - setRangeEndFromOpcode(opcode, loopRange, Default::loopRange); + if (auto value = opcode.read(Default::loopRange)) + loopRange.setEnd(*value); break; case hash("loop_start"): // also loopstart - setRangeStartFromOpcode(opcode, loopRange, Default::loopRange); + if (auto value = opcode.read(Default::loopRange)) + loopRange.setStart(*value); break; case hash("loop_crossfade"): - setValueFromOpcode(opcode, loopCrossfade, Default::loopCrossfadeRange); + loopCrossfade = opcode.read(Default::loopCrossfade).value_or(loopCrossfade); break; // Wavetable oscillator case hash("oscillator_phase"): - if (auto value = readOpcode(opcode.value, Default::oscillatorPhaseRange)) + if (auto value = opcode.read(Default::oscillatorPhase)) oscillatorPhase = (*value >= 0) ? wrapPhase(*value) : -1.0f; break; case hash("oscillator"): @@ -152,40 +167,42 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) oscillatorEnabled = *value ? OscillatorEnabled::On : OscillatorEnabled::Off; break; case hash("oscillator_mode"): - setValueFromOpcode(opcode, oscillatorMode, Default::oscillatorModeRange); + oscillatorMode = opcode.read(Default::oscillatorMode).value_or(oscillatorMode); break; case hash("oscillator_multi"): - setValueFromOpcode(opcode, oscillatorMulti, Default::oscillatorMultiRange); + oscillatorMulti = opcode.read(Default::oscillatorMulti).value_or(oscillatorMulti); break; case hash("oscillator_detune"): - setValueFromOpcode(opcode, oscillatorDetune, Default::oscillatorDetuneRange); + oscillatorDetune = opcode.read(Default::oscillatorDetune).value_or(oscillatorDetune); break; case_any_ccN("oscillator_detune"): - processGenericCc(opcode, Default::oscillatorDetuneCCRange, ModKey::createNXYZ(ModId::OscillatorDetune, id)); + processGenericCc(opcode, Default::oscillatorDetuneMod, + ModKey::createNXYZ(ModId::OscillatorDetune, id)); break; case hash("oscillator_mod_depth"): - if (auto value = readOpcode(opcode.value, Default::oscillatorModDepthRange)) + if (auto value = opcode.read(Default::oscillatorModDepth)) oscillatorModDepth = normalizePercents(*value); break; case_any_ccN("oscillator_mod_depth"): - processGenericCc(opcode, Default::oscillatorModDepthCCRange, ModKey::createNXYZ(ModId::OscillatorModDepth, id)); + processGenericCc(opcode, Default::oscillatorModDepthMod, + ModKey::createNXYZ(ModId::OscillatorModDepth, id)); break; case hash("oscillator_quality"): if (opcode.value == "-1") oscillatorQuality.reset(); - else - setValueFromOpcode(opcode, oscillatorQuality, Default::oscillatorQualityRange); + else if (auto value = opcode.read(Default::oscillatorQuality)) + oscillatorQuality = *value; break; // Instrument settings: voice lifecycle case hash("group"): // also polyphony_group - setValueFromOpcode(opcode, group, Default::groupRange); + group = opcode.read(Default::group).value_or(group); break; case hash("off_by"): // also offby if (opcode.value == "-1") offBy.reset(); - else - setValueFromOpcode(opcode, offBy, Default::groupRange); + else if (auto value = opcode.read(Default::group)) + offBy = *value; break; case hash("off_mode"): // also offmode switch (hash(opcode.value)) { @@ -204,14 +221,13 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) break; case hash("off_time"): offMode = SfzOffMode::time; - setValueFromOpcode(opcode, offTime, Default::egTimeRange); + offTime = opcode.read(Default::offTime).value_or(offTime); break; case hash("polyphony"): - if (auto value = readOpcode(opcode.value, Default::polyphonyRange)) - polyphony = *value; + polyphony = opcode.read(Default::polyphony).value_or(polyphony); break; case hash("note_polyphony"): - if (auto value = readOpcode(opcode.value, Default::polyphonyRange)) + if (auto value = opcode.read(Default::notePolyphony)) notePolyphony = *value; break; case hash("note_selfmask"): @@ -237,72 +253,79 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) break; // Region logic: key mapping case hash("lokey"): - triggerOnNote = true; - setRangeStartFromOpcode(opcode, keyRange, Default::keyRange); + if (auto value = opcode.read(Default::key)) { + triggerOnNote = true; + keyRange.setStart(*value); + } break; case hash("hikey"): triggerOnNote = (opcode.value != "-1"); - setRangeEndFromOpcode(opcode, keyRange, Default::keyRange); + if (auto value = opcode.read(Default::key)) + keyRange.setEnd(*value); break; case hash("key"): triggerOnNote = (opcode.value != "-1"); - setRangeStartFromOpcode(opcode, keyRange, Default::keyRange); - setRangeEndFromOpcode(opcode, keyRange, Default::keyRange); - setValueFromOpcode(opcode, pitchKeycenter, Default::keyRange); + if (auto value = opcode.read(Default::key)) { + keyRange.setStart(*value); + keyRange.setEnd(*value); + pitchKeycenter = *value; + } break; case hash("lovel"): - if (auto value = readOpcode(opcode.value, Default::midi7Range)) + if (auto value = opcode.read(Default::midi7)) velocityRange.setStart(normalizeVelocity(*value)); break; case hash("hivel"): - if (auto value = readOpcode(opcode.value, Default::midi7Range)) + if (auto value = opcode.read(Default::midi7)) velocityRange.setEnd(normalizeVelocity(*value)); break; // Region logic: MIDI conditions case hash("lobend"): - if (auto value = readOpcode(opcode.value, Default::bendRange)) + if (auto value = opcode.read(Default::bend)) bendRange.setStart(normalizeBend(*value)); break; case hash("hibend"): - if (auto value = readOpcode(opcode.value, Default::bendRange)) + if (auto value = opcode.read(Default::bend)) bendRange.setEnd(normalizeBend(*value)); break; case hash("locc&"): if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::midi7Range)) + if (auto value = opcode.read(Default::midi7)) ccConditions[opcode.parameters.back()].setStart(normalizeCC(*value)); break; case hash("hicc&"): if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::midi7Range)) + if (auto value = opcode.read(Default::midi7)) ccConditions[opcode.parameters.back()].setEnd(normalizeCC(*value)); break; case hash("lohdcc&"): // also lorealcc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::normalizedRange)) + if (auto value = opcode.read(Default::normalized)) ccConditions[opcode.parameters.back()].setStart(*value); break; case hash("hihdcc&"): // also hirealcc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::normalizedRange)) + if (auto value = opcode.read(Default::normalized)) ccConditions[opcode.parameters.back()].setEnd(*value); break; case hash("sw_lokey"): // fallthrough case hash("sw_hikey"): break; case hash("sw_last"): - if (!lastKeyswitchRange) { - setValueFromOpcode(opcode, lastKeyswitch, Default::keyRange); - keySwitched = false; + if (auto value = opcode.read(Default::key)) { + if (!lastKeyswitchRange) { + lastKeyswitch = *value; + keySwitched = false; + } } break; case hash("sw_lolast"): - if (auto value = readOpcode(opcode.value, Default::keyRange)) { + if (auto value = opcode.read(Default::key)) { if (!lastKeyswitchRange) lastKeyswitchRange.emplace(*value, *value); else @@ -313,7 +336,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) } break; case hash("sw_hilast"): - if (auto value = readOpcode(opcode.value, Default::keyRange)) { + if (auto value = opcode.read(Default::key)) { if (!lastKeyswitchRange) lastKeyswitchRange.emplace(*value, *value); else @@ -327,15 +350,21 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) keyswitchLabel = opcode.value; break; case hash("sw_down"): - setValueFromOpcode(opcode, downKeyswitch, Default::keyRange); - keySwitched = false; + if (auto value = opcode.read(Default::key)) { + downKeyswitch = *value; + keySwitched = false; + } break; case hash("sw_up"): - setValueFromOpcode(opcode, upKeyswitch, Default::keyRange); + if (auto value = opcode.read(Default::key)) { + upKeyswitch = *value; + } break; case hash("sw_previous"): - setValueFromOpcode(opcode, previousKeyswitch, Default::keyRange); - previousKeySwitched = false; + if (auto value = opcode.read(Default::key)) { + previousKeyswitch = *value; + previousKeySwitched = false; + } break; case hash("sw_vel"): switch (hash(opcode.value)) { @@ -351,12 +380,11 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) break; case hash("sustain_cc"): - setValueFromOpcode(opcode, sustainCC, Default::ccNumberRange); + sustainCC = opcode.read(Default::sustainCC).value_or(sustainCC); break; case hash("sustain_lo"): - if (auto value = readOpcode(opcode.value, Default::float7Range)) { + if (auto value = opcode.read(Default::float7)) sustainThreshold = normalizeCC(*value); - } break; case hash("sustain_sw"): checkSustain = readBooleanFromOpcode(opcode).value_or(Default::checkSustain); @@ -366,28 +394,34 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) break; // Region logic: internal conditions case hash("lochanaft"): - setRangeStartFromOpcode(opcode, aftertouchRange, Default::aftertouchRange); + if (auto value = opcode.read(Default::midi7)) + aftertouchRange.setStart(*value); break; case hash("hichanaft"): - setRangeEndFromOpcode(opcode, aftertouchRange, Default::aftertouchRange); + if (auto value = opcode.read(Default::midi7)) + aftertouchRange.setEnd(*value); break; case hash("lobpm"): - setRangeStartFromOpcode(opcode, bpmRange, Default::bpmRange); + if (auto value = opcode.read(Default::bpm)) + bpmRange.setStart(*value); break; case hash("hibpm"): - setRangeEndFromOpcode(opcode, bpmRange, Default::bpmRange); + if (auto value = opcode.read(Default::bpm)) + bpmRange.setEnd(*value); break; case hash("lorand"): - setRangeStartFromOpcode(opcode, randRange, Default::randRange); + if (auto value = opcode.read(Default::normalized)) + randRange.setStart(*value); break; case hash("hirand"): - setRangeEndFromOpcode(opcode, randRange, Default::randRange); + if (auto value = opcode.read(Default::normalized)) + randRange.setEnd(*value); break; case hash("seq_length"): - setValueFromOpcode(opcode, sequenceLength, Default::sequenceRange); + sequenceLength = opcode.read(Default::sequence).value_or(sequenceLength); break; case hash("seq_position"): - setValueFromOpcode(opcode, sequencePosition, Default::sequenceRange); + sequencePosition = opcode.read(Default::sequence).value_or(sequencePosition); sequenceSwitched = false; break; // Region logic: triggers @@ -415,7 +449,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash("start_locc&"): // also on_locc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::midi7Range)) { + if (auto value = opcode.read(Default::midi7)) { triggerOnCC = true; ccTriggers[opcode.parameters.back()].setStart(normalizeCC(*value)); } @@ -423,7 +457,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash("start_hicc&"): // also on_hicc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::midi7Range)) { + if (auto value = opcode.read(Default::midi7)) { triggerOnCC = true; ccTriggers[opcode.parameters.back()].setEnd(normalizeCC(*value)); } @@ -431,7 +465,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash("start_lohdcc&"): // also on_lohdcc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::normalizedRange)) { + if (auto value = opcode.read(Default::normalized)) { triggerOnCC = true; ccTriggers[opcode.parameters.back()].setStart(*value); } @@ -439,7 +473,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash("start_hihdcc&"): // also on_hihdcc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::normalizedRange)) { + if (auto value = opcode.read(Default::normalized)) { triggerOnCC = true; ccTriggers[opcode.parameters.back()].setEnd(*value); } @@ -447,55 +481,55 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) // Performance parameters: amplifier case hash("volume"): // also gain - setValueFromOpcode(opcode, volume, Default::volumeRange); + volume = opcode.read(Default::volume).value_or(volume); break; case_any_ccN("volume"): // also gain - processGenericCc(opcode, Default::volumeCCRange, ModKey::createNXYZ(ModId::Volume, id)); + processGenericCc(opcode, Default::volumeMod, ModKey::createNXYZ(ModId::Volume, id)); break; case hash("amplitude"): - if (auto value = readOpcode(opcode.value, Default::amplitudeRange)) + if (auto value = opcode.read(Default::amplitude)) amplitude = normalizePercents(*value); break; case_any_ccN("amplitude"): - processGenericCc(opcode, Default::amplitudeRange, ModKey::createNXYZ(ModId::Amplitude, id)); + processGenericCc(opcode, Default::amplitudeMod, ModKey::createNXYZ(ModId::Amplitude, id)); break; case hash("pan"): - if (auto value = readOpcode(opcode.value, Default::panRange)) + if (auto value = opcode.read(Default::pan)) pan = normalizePercents(*value); break; case_any_ccN("pan"): - processGenericCc(opcode, Default::panCCRange, ModKey::createNXYZ(ModId::Pan, id)); + processGenericCc(opcode, Default::panMod, ModKey::createNXYZ(ModId::Pan, id)); break; case hash("position"): - if (auto value = readOpcode(opcode.value, Default::positionRange)) + if (auto value = opcode.read(Default::position)) position = normalizePercents(*value); break; case_any_ccN("position"): - processGenericCc(opcode, Default::positionCCRange, ModKey::createNXYZ(ModId::Position, id)); + processGenericCc(opcode, Default::positionMod, ModKey::createNXYZ(ModId::Position, id)); break; case hash("width"): - if (auto value = readOpcode(opcode.value, Default::widthRange)) + if (auto value = opcode.read(Default::width)) width = normalizePercents(*value); break; case_any_ccN("width"): - processGenericCc(opcode, Default::widthCCRange, ModKey::createNXYZ(ModId::Width, id)); + processGenericCc(opcode, Default::widthMod, ModKey::createNXYZ(ModId::Width, id)); break; case hash("amp_keycenter"): - setValueFromOpcode(opcode, ampKeycenter, Default::keyRange); + ampKeycenter = opcode.read(Default::key).value_or(ampKeycenter); break; case hash("amp_keytrack"): - setValueFromOpcode(opcode, ampKeytrack, Default::ampKeytrackRange); + ampKeytrack = opcode.read(Default::ampKeytrack).value_or(ampKeytrack); break; case hash("amp_veltrack"): - if (auto value = readOpcode(opcode.value, Default::ampVeltrackRange)) + if (auto value = opcode.read(Default::ampVeltrack)) ampVeltrack = normalizePercents(*value); break; case hash("amp_random"): - setValueFromOpcode(opcode, ampRandom, Default::ampRandomRange); + ampRandom = opcode.read(Default::ampRandom).value_or(ampRandom); break; case hash("amp_velcurve_&"): { - auto value = readOpcode(opcode.value, Default::ampVelcurveRange); + auto value = opcode.read(Default::ampVelcurve); if (opcode.parameters.back() > 127) return false; @@ -505,31 +539,35 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) } break; case hash("xfin_lokey"): - setRangeStartFromOpcode(opcode, crossfadeKeyInRange, Default::keyRange); + if (auto value = opcode.read(Default::key)) + crossfadeKeyInRange.setStart(*value); break; case hash("xfin_hikey"): - setRangeEndFromOpcode(opcode, crossfadeKeyInRange, Default::keyRange); + if (auto value = opcode.read(Default::key)) + crossfadeKeyInRange.setEnd(*value); break; case hash("xfout_lokey"): - setRangeStartFromOpcode(opcode, crossfadeKeyOutRange, Default::keyRange); + if (auto value = opcode.read(Default::key)) + crossfadeKeyOutRange.setStart(*value); break; case hash("xfout_hikey"): - setRangeEndFromOpcode(opcode, crossfadeKeyOutRange, Default::keyRange); + if (auto value = opcode.read(Default::key)) + crossfadeKeyOutRange.setEnd(*value); break; case hash("xfin_lovel"): - if (auto value = readOpcode(opcode.value, Default::midi7Range)) + if (auto value = opcode.read(Default::crossfadeIn)) crossfadeVelInRange.setStart(normalizeVelocity(*value)); break; case hash("xfin_hivel"): - if (auto value = readOpcode(opcode.value, Default::midi7Range)) + if (auto value = opcode.read(Default::crossfadeIn)) crossfadeVelInRange.setEnd(normalizeVelocity(*value)); break; case hash("xfout_lovel"): - if (auto value = readOpcode(opcode.value, Default::midi7Range)) + if (auto value = opcode.read(Default::crossfadeOut)) crossfadeVelOutRange.setStart(normalizeVelocity(*value)); break; case hash("xfout_hivel"): - if (auto value = readOpcode(opcode.value, Default::midi7Range)) + if (auto value = opcode.read(Default::crossfadeOut)) crossfadeVelOutRange.setEnd(normalizeVelocity(*value)); break; case hash("xf_keycurve"): @@ -559,25 +597,25 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash("xfin_locc&"): if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::midi7Range)) + if (auto value = opcode.read(Default::crossfadeIn)) crossfadeCCInRange[opcode.parameters.back()].setStart(normalizeCC(*value)); break; case hash("xfin_hicc&"): if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::midi7Range)) + if (auto value = opcode.read(Default::crossfadeIn)) crossfadeCCInRange[opcode.parameters.back()].setEnd(normalizeCC(*value)); break; case hash("xfout_locc&"): if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::midi7Range)) + if (auto value = opcode.read(Default::crossfadeOut)) crossfadeCCOutRange[opcode.parameters.back()].setStart(normalizeCC(*value)); break; case hash("xfout_hicc&"): if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::midi7Range)) + if (auto value = opcode.read(Default::crossfadeOut)) crossfadeCCOutRange[opcode.parameters.back()].setEnd(normalizeCC(*value)); break; case hash("xf_cccurve"): @@ -593,28 +631,28 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) } break; case hash("rt_decay"): - setValueFromOpcode(opcode, rtDecay, Default::rtDecayRange); + rtDecay = opcode.read(Default::rtDecay).value_or(rtDecay); break; case hash("global_amplitude"): - if (auto value = readOpcode(opcode.value, Default::amplitudeRange)) + if (auto value = opcode.read(Default::amplitude)) globalAmplitude = normalizePercents(*value); break; case hash("master_amplitude"): - if (auto value = readOpcode(opcode.value, Default::amplitudeRange)) + if (auto value = opcode.read(Default::amplitude)) masterAmplitude = normalizePercents(*value); break; case hash("group_amplitude"): - if (auto value = readOpcode(opcode.value, Default::amplitudeRange)) + if (auto value = opcode.read(Default::amplitude)) groupAmplitude = normalizePercents(*value); break; case hash("global_volume"): - setValueFromOpcode(opcode, globalVolume, Default::volumeRange); + globalVolume = opcode.read(Default::volume).value_or(globalVolume); break; case hash("master_volume"): - setValueFromOpcode(opcode, masterVolume, Default::volumeRange); + masterVolume = opcode.read(Default::volume).value_or(masterVolume); break; case hash("group_volume"): - setValueFromOpcode(opcode, groupVolume, Default::volumeRange); + groupVolume = opcode.read(Default::volume).value_or(groupVolume); break; // Performance parameters: filters @@ -623,7 +661,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.empty() ? 0 : (opcode.parameters.back() - 1); if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - setValueFromOpcode(opcode, filters[filterIndex].cutoff, Default::filterCutoffRange); + if (auto value = opcode.read(Default::filterCutoff)) + filters[filterIndex].cutoff = *value; } break; case hash("resonance&"): // also resonance @@ -631,7 +670,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.empty() ? 0 : (opcode.parameters.back() - 1); if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - setValueFromOpcode(opcode, filters[filterIndex].resonance, Default::filterResonanceRange); + if (auto value = opcode.read(Default::filterResonance)) + filters[filterIndex].resonance = *value; } break; case_any_ccN("cutoff&"): // also cutoff_oncc&, cutoff_cc&, cutoff&_cc& @@ -640,7 +680,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - processGenericCc(opcode, Default::filterCutoffModRange, ModKey::createNXYZ(ModId::FilCutoff, id, filterIndex)); + processGenericCc(opcode, Default::filterCutoffMod, ModKey::createNXYZ(ModId::FilCutoff, id, filterIndex)); } break; case_any_ccN("resonance&"): // also resonance_oncc&, resonance_cc&, resonance&_cc& @@ -649,7 +689,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - processGenericCc(opcode, Default::filterResonanceModRange, ModKey::createNXYZ(ModId::FilResonance, id, filterIndex)); + processGenericCc(opcode, Default::filterResonanceMod, ModKey::createNXYZ(ModId::FilResonance, id, filterIndex)); } break; case hash("fil&_keytrack"): // also fil_keytrack @@ -657,8 +697,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - - setValueFromOpcode(opcode, filters[filterIndex].keytrack, Default::filterKeytrackRange); + if (auto value = opcode.read(Default::filterKeytrack)) + filters[filterIndex].keytrack = *value; } break; case hash("fil&_keycenter"): // also fil_keycenter @@ -666,8 +706,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - - setValueFromOpcode(opcode, filters[filterIndex].keycenter, Default::keyRange); + if (auto value = opcode.read(Default::key)) + filters[filterIndex].keycenter = *value; } break; case hash("fil&_veltrack"): // also fil_veltrack @@ -675,8 +715,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - - setValueFromOpcode(opcode, filters[filterIndex].veltrack, Default::filterVeltrackRange); + if (auto value = opcode.read(Default::filterVeltrack)) + filters[filterIndex].veltrack = *value; } break; case hash("fil&_random"): // also fil_random, cutoff_random, cutoff&_random @@ -684,8 +724,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - - setValueFromOpcode(opcode, filters[filterIndex].random, Default::filterRandomRange); + if (auto value = opcode.read(Default::filterRandom)) + filters[filterIndex].random = *value; } break; case hash("fil&_gain"): // also fil_gain @@ -693,8 +733,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - - setValueFromOpcode(opcode, filters[filterIndex].gain, Default::filterGainRange); + if (auto value = opcode.read(Default::filterGain)) + filters[filterIndex].gain = *value; } break; case_any_ccN("fil&_gain"): // also fil_gain_oncc& @@ -703,7 +743,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - processGenericCc(opcode, Default::filterGainModRange, ModKey::createNXYZ(ModId::FilGain, id, filterIndex)); + processGenericCc(opcode, Default::filterGainMod, ModKey::createNXYZ(ModId::FilGain, id, filterIndex)); } break; case hash("fil&_type"): // also fil_type, filtype @@ -729,8 +769,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto eqIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - - setValueFromOpcode(opcode, equalizers[eqIndex].bandwidth, Default::eqBandwidthRange); + if (auto value = opcode.read(Default::eqBandwidth)) + equalizers[eqIndex].bandwidth = *value; } break; case_any_ccN("eq&_bw"): // also eq&_bwcc& @@ -739,7 +779,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - processGenericCc(opcode, Default::eqBandwidthModRange, ModKey::createNXYZ(ModId::EqBandwidth, id, eqIndex)); + processGenericCc(opcode, Default::eqBandwidthMod, ModKey::createNXYZ(ModId::EqBandwidth, id, eqIndex)); } break; case hash("eq&_freq"): @@ -747,7 +787,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto eqIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - setValueFromOpcode(opcode, equalizers[eqIndex].frequency, Default::eqFrequencyRange); + if (auto value = opcode.read(Default::eqFrequency)) + equalizers[eqIndex].frequency = *value; } break; case_any_ccN("eq&_freq"): // also eq&_freqcc& @@ -756,7 +797,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - processGenericCc(opcode, Default::eqFrequencyModRange, ModKey::createNXYZ(ModId::EqFrequency, id, eqIndex)); + processGenericCc(opcode, Default::eqFrequencyMod, ModKey::createNXYZ(ModId::EqFrequency, id, eqIndex)); } break; case hash("eq&_veltofreq"): // also eq&_vel2freq @@ -764,8 +805,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto eqIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - - setValueFromOpcode(opcode, equalizers[eqIndex].vel2frequency, Default::eqFrequencyModRange); + if (auto value = opcode.read(Default::eqVel2Frequency)) + equalizers[eqIndex].vel2frequency = *value; } break; case hash("eq&_gain"): @@ -773,7 +814,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto eqIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - setValueFromOpcode(opcode, equalizers[eqIndex].gain, Default::eqGainRange); + if (auto value = opcode.read(Default::eqGain)) + equalizers[eqIndex].gain = *value; } break; case_any_ccN("eq&_gain"): // also eq&_gaincc& @@ -782,7 +824,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - processGenericCc(opcode, Default::eqGainModRange, ModKey::createNXYZ(ModId::EqGain, id, eqIndex)); + processGenericCc(opcode, Default::eqGainMod, ModKey::createNXYZ(ModId::EqGain, id, eqIndex)); } break; case hash("eq&_veltogain"): // also eq&_vel2gain @@ -790,8 +832,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto eqIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - - setValueFromOpcode(opcode, equalizers[eqIndex].vel2gain, Default::eqGainModRange); + if (auto value = opcode.read(Default::eqVel2Gain)) + equalizers[eqIndex].vel2gain = *value; } break; case hash("eq&_type"): @@ -817,38 +859,38 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) pitchKeycenterFromSample = true; else { pitchKeycenterFromSample = false; - setValueFromOpcode(opcode, pitchKeycenter, Default::keyRange); + pitchKeycenter = opcode.read(Default::key).value_or(pitchKeycenter); } break; case hash("pitch_keytrack"): - setValueFromOpcode(opcode, pitchKeytrack, Default::pitchKeytrackRange); + pitchKeytrack = opcode.read(Default::pitchKeytrack).value_or(pitchKeytrack); break; case hash("pitch_veltrack"): - setValueFromOpcode(opcode, pitchVeltrack, Default::pitchVeltrackRange); + pitchVeltrack = opcode.read(Default::pitchVeltrack).value_or(pitchVeltrack); break; case hash("pitch_random"): - setValueFromOpcode(opcode, pitchRandom, Default::pitchRandomRange); + pitchRandom = opcode.read(Default::pitchRandom).value_or(pitchRandom); break; case hash("transpose"): - setValueFromOpcode(opcode, transpose, Default::transposeRange); + transpose = opcode.read(Default::transpose).value_or(transpose); break; case hash("pitch"): // also tune - setValueFromOpcode(opcode, tune, Default::tuneRange); + pitch = opcode.read(Default::pitch).value_or(pitch); break; case_any_ccN("pitch"): // also tune - processGenericCc(opcode, Default::tuneCCRange, ModKey::createNXYZ(ModId::Pitch, id)); + processGenericCc(opcode, Default::pitchMod, ModKey::createNXYZ(ModId::Pitch, id)); break; case hash("bend_up"): // also bendup - setValueFromOpcode(opcode, bendUp, Default::bendBoundRange); + bendUp = opcode.read(Default::bendUp).value_or(bendUp); break; case hash("bend_down"): // also benddown - setValueFromOpcode(opcode, bendDown, Default::bendBoundRange); + bendDown = opcode.read(Default::bendDown).value_or(bendDown); break; case hash("bend_step"): - setValueFromOpcode(opcode, bendStep, Default::bendStepRange); + bendStep = opcode.read(Default::bendStep).value_or(bendStep); break; case hash("bend_smooth"): - setValueFromOpcode(opcode, bendSmooth, Default::smoothCCRange); + bendSmooth = opcode.read(Default::smoothCC).value_or(bendSmooth); break; // Modulation: LFO @@ -859,7 +901,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - setValueFromOpcode(opcode, lfos[lfoNumber - 1].freq, Default::lfoFreqRange); + if (auto value = opcode.read(Default::lfoFreq)) + lfos[lfoNumber - 1].freq = *value; } break; case_any_ccN("lfo&_freq"): @@ -869,7 +912,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - processGenericCc(opcode, Default::lfoFreqModRange, ModKey::createNXYZ(ModId::LFOFrequency, id, lfoNumber - 1)); + processGenericCc(opcode, Default::lfoFreqMod, ModKey::createNXYZ(ModId::LFOFrequency, id, lfoNumber - 1)); } break; case hash("lfo&_beats"): @@ -879,7 +922,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - setValueFromOpcode(opcode, lfos[lfoNumber - 1].beats, Default::lfoBeatsRange); + if (auto value = opcode.read(Default::lfoBeats)) + lfos[lfoNumber - 1].beats = *value; } break; case_any_ccN("lfo&_beats"): @@ -889,7 +933,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - processGenericCc(opcode, Default::lfoBeatsModRange, ModKey::createNXYZ(ModId::LFOBeats, id, lfoNumber - 1)); + processGenericCc(opcode, Default::lfoBeatsMod, ModKey::createNXYZ(ModId::LFOBeats, id, lfoNumber - 1)); } break; case hash("lfo&_phase"): @@ -899,7 +943,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = readOpcode(opcode.value, Default::lfoPhaseRange)) + if (auto value = opcode.read(Default::lfoPhase)) lfos[lfoNumber - 1].phase0 = wrapPhase(*value); } break; @@ -910,7 +954,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - setValueFromOpcode(opcode, lfos[lfoNumber - 1].delay, Default::lfoDelayRange); + if (auto value = opcode.read(Default::lfoDelay)) + lfos[lfoNumber - 1].delay = *value; } break; case hash("lfo&_fade"): @@ -920,7 +965,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - setValueFromOpcode(opcode, lfos[lfoNumber - 1].fade, Default::lfoFadeRange); + if (auto value = opcode.read(Default::lfoFade)) + lfos[lfoNumber - 1].fade = *value; } break; case hash("lfo&_count"): @@ -930,7 +976,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - setValueFromOpcode(opcode, lfos[lfoNumber - 1].count, Default::lfoCountRange); + if (auto value = opcode.read(Default::lfoCount)) + lfos[lfoNumber - 1].count = *value; } break; case hash("lfo&_steps"): @@ -940,7 +987,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = readOpcode(opcode.value, Default::lfoStepsRange)) { + if (auto value = opcode.read(Default::lfoSteps)) { if (!lfos[lfoNumber - 1].seq) lfos[lfoNumber - 1].seq = LFODescription::StepSequence(); lfos[lfoNumber - 1].seq->steps.resize(*value); @@ -955,7 +1002,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = readOpcode(opcode.value, Default::lfoStepXRange)) { + if (auto value = opcode.read(Default::lfoStepX)) { if (!lfos[lfoNumber - 1].seq) lfos[lfoNumber - 1].seq = LFODescription::StepSequence(); if (!extendIfNecessary(lfos[lfoNumber - 1].seq->steps, stepNumber, Default::numLFOSteps)) @@ -972,7 +1019,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = readOpcode(opcode.value, Default::lfoWaveRange)) { + if (auto value = opcode.read(Default::lfoWave)) { if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) return false; lfos[lfoNumber - 1].sub[subNumber - 1].wave = static_cast(*value); @@ -987,7 +1034,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = readOpcode(opcode.value, Default::lfoOffsetRange)) { + if (auto value = opcode.read(Default::lfoOffset)) { if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) return false; lfos[lfoNumber - 1].sub[subNumber - 1].offset = *value; @@ -1002,7 +1049,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = readOpcode(opcode.value, Default::lfoRatioRange)) { + if (auto value = opcode.read(Default::lfoRatio)) { if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) return false; lfos[lfoNumber - 1].sub[subNumber - 1].ratio = *value; @@ -1017,7 +1064,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = readOpcode(opcode.value, Default::lfoScaleRange)) { + if (auto value = opcode.read(Default::lfoScale)) { if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) return false; lfos[lfoNumber - 1].sub[subNumber - 1].scale = *value; @@ -1031,7 +1078,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto lfoNumber = opcode.parameters.front(); if (lfoNumber == 0) return false; - if (auto value = readOpcode(opcode.value, Default::amplitudeRange)) { + if (auto value = opcode.read(Default::amplitudeMod)) { const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); const ModKey target = ModKey::createNXYZ(ModId::Amplitude, id); getOrCreateConnection(source, target).sourceDepth = *value; @@ -1043,7 +1090,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto lfoNumber = opcode.parameters.front(); if (lfoNumber == 0) return false; - if (auto value = readOpcode(opcode.value, Default::panCCRange)) { + if (auto value = opcode.read(Default::panMod)) { const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); const ModKey target = ModKey::createNXYZ(ModId::Pan, id); getOrCreateConnection(source, target).sourceDepth = *value; @@ -1055,7 +1102,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto lfoNumber = opcode.parameters.front(); if (lfoNumber == 0) return false; - if (auto value = readOpcode(opcode.value, Default::widthCCRange)) { + if (auto value = opcode.read(Default::widthMod)) { const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); const ModKey target = ModKey::createNXYZ(ModId::Width, id); getOrCreateConnection(source, target).sourceDepth = *value; @@ -1067,7 +1114,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto lfoNumber = opcode.parameters.front(); if (lfoNumber == 0) return false; - if (auto value = readOpcode(opcode.value, Default::positionCCRange)) { + if (auto value = opcode.read(Default::positionMod)) { const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); const ModKey target = ModKey::createNXYZ(ModId::Position, id); getOrCreateConnection(source, target).sourceDepth = *value; @@ -1079,7 +1126,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto lfoNumber = opcode.parameters.front(); if (lfoNumber == 0) return false; - if (auto value = readOpcode(opcode.value, Default::tuneCCRange)) { + if (auto value = opcode.read(Default::pitchMod)) { const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); const ModKey target = ModKey::createNXYZ(ModId::Pitch, id); getOrCreateConnection(source, target).sourceDepth = *value; @@ -1091,7 +1138,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto lfoNumber = opcode.parameters.front(); if (lfoNumber == 0) return false; - if (auto value = readOpcode(opcode.value, Default::volumeCCRange)) { + if (auto value = opcode.read(Default::volumeMod)) { const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); const ModKey target = ModKey::createNXYZ(ModId::Volume, id); getOrCreateConnection(source, target).sourceDepth = *value; @@ -1099,22 +1146,22 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) } break; case hash("lfo&_cutoff&"): - LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilCutoff, Default::filterCutoffModRange); + LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilCutoff, Default::filterCutoffMod); break; case hash("lfo&_resonance&"): - LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilResonance, Default::filterResonanceModRange); + LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilResonance, Default::filterResonanceMod); break; case hash("lfo&_fil&gain"): - LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilGain, Default::filterGainModRange); + LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilGain, Default::filterGainMod); break; case hash("lfo&_eq&gain"): - LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqGain, Default::eqGainModRange); + LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqGain, Default::eqGainMod); break; case hash("lfo&_eq&freq"): - LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqFrequency, Default::eqFrequencyModRange); + LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqFrequency, Default::eqFrequencyMod); break; case hash("lfo&_eq&bw"): - LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqBandwidth, Default::eqBandwidthModRange); + LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqBandwidth, Default::eqBandwidthMod); break; // Modulation: Flex EG (targets) @@ -1123,7 +1170,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto egNumber = opcode.parameters.front(); if (egNumber == 0) return false; - if (auto value = readOpcode(opcode.value, Default::amplitudeRange)) { + if (auto value = opcode.read(Default::amplitudeMod)) { const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); const ModKey target = ModKey::createNXYZ(ModId::Amplitude, id); getOrCreateConnection(source, target).sourceDepth = *value; @@ -1135,7 +1182,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto egNumber = opcode.parameters.front(); if (egNumber == 0) return false; - if (auto value = readOpcode(opcode.value, Default::panCCRange)) { + if (auto value = opcode.read(Default::panMod)) { const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); const ModKey target = ModKey::createNXYZ(ModId::Pan, id); getOrCreateConnection(source, target).sourceDepth = *value; @@ -1147,7 +1194,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto egNumber = opcode.parameters.front(); if (egNumber == 0) return false; - if (auto value = readOpcode(opcode.value, Default::widthCCRange)) { + if (auto value = opcode.read(Default::widthMod)) { const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); const ModKey target = ModKey::createNXYZ(ModId::Width, id); getOrCreateConnection(source, target).sourceDepth = *value; @@ -1159,7 +1206,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto egNumber = opcode.parameters.front(); if (egNumber == 0) return false; - if (auto value = readOpcode(opcode.value, Default::positionCCRange)) { + if (auto value = opcode.read(Default::positionMod)) { const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); const ModKey target = ModKey::createNXYZ(ModId::Position, id); getOrCreateConnection(source, target).sourceDepth = *value; @@ -1171,7 +1218,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto egNumber = opcode.parameters.front(); if (egNumber == 0) return false; - if (auto value = readOpcode(opcode.value, Default::tuneCCRange)) { + if (auto value = opcode.read(Default::pitchMod)) { const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); const ModKey target = ModKey::createNXYZ(ModId::Pitch, id); getOrCreateConnection(source, target).sourceDepth = *value; @@ -1183,7 +1230,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto egNumber = opcode.parameters.front(); if (egNumber == 0) return false; - if (auto value = readOpcode(opcode.value, Default::volumeCCRange)) { + if (auto value = opcode.read(Default::volumeMod)) { const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); const ModKey target = ModKey::createNXYZ(ModId::Volume, id); getOrCreateConnection(source, target).sourceDepth = *value; @@ -1191,22 +1238,22 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) } break; case hash("eg&_cutoff&"): - LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilCutoff, Default::filterCutoffModRange); + LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilCutoff, Default::filterCutoffMod); break; case hash("eg&_resonance&"): - LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilResonance, Default::filterResonanceModRange); + LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilResonance, Default::filterResonanceMod); break; case hash("eg&_fil&gain"): - LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilGain, Default::filterGainModRange); + LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilGain, Default::filterGainMod); break; case hash("eg&_eq&gain"): - LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqGain, Default::eqGainModRange); + LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqGain, Default::eqGainMod); break; case hash("eg&_eq&freq"): - LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqFrequency, Default::eqFrequencyModRange); + LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqFrequency, Default::eqFrequencyMod); break; case hash("eg&_eq&bw"): - LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqBandwidth, Default::eqBandwidthModRange); + LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqBandwidth, Default::eqBandwidthMod); break; case hash("eg&_ampeg"): @@ -1307,26 +1354,26 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) break; case hash("pitcheg_depth"): - if (auto value = readOpcode(opcode.value, Default::pitchEgDepthRange)) + if (auto value = opcode.read(Default::egDepth)) getOrCreateConnection( ModKey::createNXYZ(ModId::PitchEG, id), ModKey::createNXYZ(ModId::Pitch, id)).sourceDepth = *value; break; case hash("fileg_depth"): - if (auto value = readOpcode(opcode.value, Default::filterEgDepthRange)) + if (auto value = opcode.read(Default::egDepth)) getOrCreateConnection( ModKey::createNXYZ(ModId::FilEG, id), ModKey::createNXYZ(ModId::FilCutoff, id)).sourceDepth = *value; break; case hash("pitcheg_veltodepth"): // also pitcheg_vel2depth - if (auto value = readOpcode(opcode.value, Default::pitchEgDepthRange)) + if (auto value = opcode.read(Default::egVel2Depth)) getOrCreateConnection( ModKey::createNXYZ(ModId::PitchEG, id), ModKey::createNXYZ(ModId::Pitch, id)).velToDepth = *value; break; case hash("fileg_veltodepth"): // also fileg_vel2depth - if (auto value = readOpcode(opcode.value, Default::filterEgDepthRange)) + if (auto value = opcode.read(Default::egVel2Depth)) getOrCreateConnection( ModKey::createNXYZ(ModId::FilEG, id), ModKey::createNXYZ(ModId::FilCutoff, id)).velToDepth = *value; @@ -1341,7 +1388,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(flexEGs, egNumber, Default::numFlexEGs)) return false; auto& eg = flexEGs[egNumber - 1]; - setValueFromOpcode(opcode, eg.dynamic, Default::flexEGDynamicRange); + eg.dynamic = opcode.read(Default::flexEGDynamic).value_or(eg.dynamic); } break; case hash("eg&_sustain"): @@ -1352,7 +1399,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(flexEGs, egNumber, Default::numFlexEGs)) return false; auto& eg = flexEGs[egNumber - 1]; - setValueFromOpcode(opcode, eg.sustain, Default::flexEGSustainRange); + eg.sustain = opcode.read(Default::flexEGSustain).value_or(eg.sustain); } break; case hash("eg&_time&"): @@ -1366,7 +1413,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto pointNumber = opcode.parameters[1]; if (!extendIfNecessary(eg.points, pointNumber + 1, Default::numFlexEGPoints)) return false; - setValueFromOpcode(opcode, eg.points[pointNumber].time, Default::flexEGPointTimeRange); + if (auto value = opcode.read(Default::flexEGPointTime)) + eg.points[pointNumber].time = *value; } break; case hash("eg&_level&"): @@ -1380,7 +1428,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto pointNumber = opcode.parameters[1]; if (!extendIfNecessary(eg.points, pointNumber + 1, Default::numFlexEGPoints)) return false; - setValueFromOpcode(opcode, eg.points[pointNumber].level, Default::flexEGPointLevelRange); + if (auto value = opcode.read(Default::flexEGPointLevel)) + eg.points[pointNumber].level = *value; } break; case hash("eg&_shape&"): @@ -1394,7 +1443,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto pointNumber = opcode.parameters[1]; if (!extendIfNecessary(eg.points, pointNumber + 1, Default::numFlexEGPoints)) return false; - if (auto value = readOpcode(opcode.value, Default::flexEGPointShapeRange)) + if (auto value = opcode.read(Default::flexEGPointShape)) eg.points[pointNumber].setShape(*value); } break; @@ -1404,7 +1453,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto effectNumber = opcode.parameters.back(); if (!effectNumber || effectNumber < 1 || effectNumber > config::maxEffectBuses) break; - auto value = readOpcode(opcode.value, { 0, 100 }); + auto value = opcode.read(Default::effect); if (!value) break; if (static_cast(effectNumber + 1) > gainToEffect.size()) @@ -1413,7 +1462,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) break; } case hash("sw_default"): - setValueFromOpcode(opcode, defaultSwitch, Default::keyRange); + if (auto value = opcode.read(Default::key)) + defaultSwitch = *value; break; // Ignored opcodes @@ -1441,49 +1491,49 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, EGDescription& eg) switch (opcode.lettersOnlyHash) { case_any_eg("attack"): - setValueFromOpcode(opcode, eg.attack, Default::egTimeRange); + eg.attack = opcode.read(Default::egTime).value_or(eg.attack); break; case_any_eg("decay"): - setValueFromOpcode(opcode, eg.decay, Default::egTimeRange); + eg.decay = opcode.read(Default::egTime).value_or(eg.decay); break; case_any_eg("delay"): - setValueFromOpcode(opcode, eg.delay, Default::egTimeRange); + eg.delay = opcode.read(Default::egTime).value_or(eg.delay); break; case_any_eg("hold"): - setValueFromOpcode(opcode, eg.hold, Default::egTimeRange); + eg.hold = opcode.read(Default::egTime).value_or(eg.hold); break; case_any_eg("release"): - setValueFromOpcode(opcode, eg.release, Default::egTimeRange); + eg.release = opcode.read(Default::egRelease).value_or(eg.release); break; case_any_eg("start"): - setValueFromOpcode(opcode, eg.start, Default::egPercentRange); + eg.start = opcode.read(Default::egPercent).value_or(eg.start); break; case_any_eg("sustain"): - setValueFromOpcode(opcode, eg.sustain, Default::egPercentRange); + eg.sustain = opcode.read(Default::egPercent).value_or(eg.sustain); break; case_any_eg("veltoattack"): // also vel2attack - setValueFromOpcode(opcode, eg.vel2attack, Default::egOnCCTimeRange); + eg.vel2attack = opcode.read(Default::egTimeMod).value_or(eg.vel2attack); break; case_any_eg("veltodecay"): // also vel2decay - setValueFromOpcode(opcode, eg.vel2decay, Default::egOnCCTimeRange); + eg.vel2decay = opcode.read(Default::egTimeMod).value_or(eg.vel2decay); break; case_any_eg("veltodelay"): // also vel2delay - setValueFromOpcode(opcode, eg.vel2delay, Default::egOnCCTimeRange); + eg.vel2delay = opcode.read(Default::egTimeMod).value_or(eg.vel2delay); break; case_any_eg("veltohold"): // also vel2hold - setValueFromOpcode(opcode, eg.vel2hold, Default::egOnCCTimeRange); + eg.vel2hold = opcode.read(Default::egTimeMod).value_or(eg.vel2hold); break; case_any_eg("veltorelease"): // also vel2release - setValueFromOpcode(opcode, eg.vel2release, Default::egOnCCTimeRange); + eg.vel2release = opcode.read(Default::egTimeMod).value_or(eg.vel2release); break; case_any_eg("veltosustain"): // also vel2sustain - setValueFromOpcode(opcode, eg.vel2sustain, Default::egOnCCPercentRange); + eg.vel2sustain = opcode.read(Default::egPercentMod).value_or(eg.vel2sustain); break; case_any_eg("attack_oncc&"): // also attackcc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::egOnCCTimeRange)) + if (auto value = opcode.read(Default::egTimeMod)) eg.ccAttack[opcode.parameters.back()] = *value; break; @@ -1491,7 +1541,7 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, EGDescription& eg) if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::egOnCCTimeRange)) + if (auto value = opcode.read(Default::egTimeMod)) eg.ccDecay[opcode.parameters.back()] = *value; break; @@ -1499,7 +1549,7 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, EGDescription& eg) if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::egOnCCTimeRange)) + if (auto value = opcode.read(Default::egTimeMod)) eg.ccDelay[opcode.parameters.back()] = *value; break; @@ -1507,7 +1557,7 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, EGDescription& eg) if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::egOnCCTimeRange)) + if (auto value = opcode.read(Default::egTimeMod)) eg.ccHold[opcode.parameters.back()] = *value; break; @@ -1515,7 +1565,7 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, EGDescription& eg) if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::egOnCCTimeRange)) + if (auto value = opcode.read(Default::egTimeMod)) eg.ccRelease[opcode.parameters.back()] = *value; break; @@ -1523,7 +1573,7 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, EGDescription& eg) if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::egOnCCPercentRange)) + if (auto value = opcode.read(Default::egPercentMod)) eg.ccStart[opcode.parameters.back()] = *value; break; @@ -1531,7 +1581,7 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, EGDescription& eg) if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = readOpcode(opcode.value, Default::egOnCCPercentRange)) + if (auto value = opcode.read(Default::egPercentMod)) eg.ccSustain[opcode.parameters.back()] = *value; break; @@ -1557,7 +1607,7 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, absl::optional range, const ModKey& target) +bool sfz::Region::processGenericCc(const Opcode& opcode, OpcodeSpec spec, const ModKey& target) { if (!opcode.isAnyCcN()) return false; @@ -1591,19 +1641,21 @@ bool sfz::Region::processGenericCc(const Opcode& opcode, Range range, con ModKey::Parameters p = conn->source.parameters(); switch (opcode.category) { case kOpcodeOnCcN: - setValueFromOpcode(opcode, conn->sourceDepth, range); + conn->sourceDepth = opcode.read(spec).value_or(conn->sourceDepth); break; case kOpcodeCurveCcN: - setValueFromOpcode(opcode, p.curve, Default::curveCCRange); + p.curve = opcode.read(Default::curveCC).value_or(p.curve); break; case kOpcodeStepCcN: { - const Range stepCCRange { 0.0f, std::max(std::abs(range.getStart()), std::abs(range.getEnd())) }; - setValueFromOpcode(opcode, p.step, stepCCRange); + const float maxStep = + max(std::abs(spec.bounds.getStart()), std::abs(spec.bounds.getEnd())); + const OpcodeSpec stepCC { 0.0f, Range(0.0f, maxStep), kEnforceLowerBound | kEnforceUpperBound }; + p.step = opcode.read(stepCC).value_or(p.step); } break; case kOpcodeSmoothCcN: - setValueFromOpcode(opcode, p.smooth, Default::smoothCCRange); + p.smooth = opcode.read(Default::smoothCC).value_or(p.smooth); break; default: assert(false); @@ -1734,7 +1786,7 @@ float sfz::Region::getBasePitchVariation(float noteNumber, float velocity) const fast_real_distribution pitchDistribution { -pitchRandom, pitchRandom }; auto pitchVariationInCents = pitchKeytrack * (noteNumber - pitchKeycenter); // note difference with pitch center - pitchVariationInCents += tune; // sample tuning + pitchVariationInCents += pitch; // sample tuning pitchVariationInCents += config::centPerSemitone * transpose; // sample transpose pitchVariationInCents += velocity * pitchVeltrack; // track velocity pitchVariationInCents += pitchDistribution(Random::randomGenerator); // random pitch changes @@ -1782,7 +1834,7 @@ uint64_t sfz::Region::getOffset(Oversampling factor) const noexcept uint64_t finalOffset = offset + offsetDistribution(Random::randomGenerator); for (const auto& mod: offsetCC) finalOffset += static_cast(mod.data * midiState.getCCValue(mod.cc)); - return Default::offsetRange.clamp(finalOffset) * static_cast(factor); + return Default::offset.bounds.clamp(finalOffset) * static_cast(factor); } float sfz::Region::getDelay() const noexcept @@ -1871,37 +1923,37 @@ float sfz::Region::velocityCurve(float velocity) const noexcept void sfz::Region::offsetAllKeys(int offset) noexcept { // Offset key range - if (keyRange != Default::keyRange) { + if (keyRange != Default::key.bounds) { const auto start = keyRange.getStart(); const auto end = keyRange.getEnd(); - keyRange.setStart(offsetAndClampKey(start, offset, Default::keyRange)); - keyRange.setEnd(offsetAndClampKey(end, offset, Default::keyRange)); + keyRange.setStart(offsetAndClampKey(start, offset)); + keyRange.setEnd(offsetAndClampKey(end, offset)); } - pitchKeycenter = offsetAndClampKey(pitchKeycenter, offset, Default::keyRange); + pitchKeycenter = offsetAndClampKey(pitchKeycenter, offset); // Offset key switches if (upKeyswitch) - upKeyswitch = offsetAndClampKey(*upKeyswitch, offset, Default::keyRange); + upKeyswitch = offsetAndClampKey(*upKeyswitch, offset); if (lastKeyswitch) - lastKeyswitch = offsetAndClampKey(*lastKeyswitch, offset, Default::keyRange); + lastKeyswitch = offsetAndClampKey(*lastKeyswitch, offset); if (downKeyswitch) - downKeyswitch = offsetAndClampKey(*downKeyswitch, offset, Default::keyRange); + downKeyswitch = offsetAndClampKey(*downKeyswitch, offset); if (previousKeyswitch) - previousKeyswitch = offsetAndClampKey(*previousKeyswitch, offset, Default::keyRange); + previousKeyswitch = offsetAndClampKey(*previousKeyswitch, offset); // Offset crossfade ranges if (crossfadeKeyInRange != Default::crossfadeKeyInRange) { const auto start = crossfadeKeyInRange.getStart(); const auto end = crossfadeKeyInRange.getEnd(); - crossfadeKeyInRange.setStart(offsetAndClampKey(start, offset, Default::keyRange)); - crossfadeKeyInRange.setEnd(offsetAndClampKey(end, offset, Default::keyRange)); + crossfadeKeyInRange.setStart(offsetAndClampKey(start, offset)); + crossfadeKeyInRange.setEnd(offsetAndClampKey(end, offset)); } if (crossfadeKeyOutRange != Default::crossfadeKeyOutRange) { const auto start = crossfadeKeyOutRange.getStart(); const auto end = crossfadeKeyOutRange.getEnd(); - crossfadeKeyOutRange.setStart(offsetAndClampKey(start, offset, Default::keyRange)); - crossfadeKeyOutRange.setEnd(offsetAndClampKey(end, offset, Default::keyRange)); + crossfadeKeyOutRange.setStart(offsetAndClampKey(start, offset)); + crossfadeKeyOutRange.setEnd(offsetAndClampKey(end, offset)); } } diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index 92ecf255..87f39984 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -43,17 +43,7 @@ class RegionSet; * */ struct Region { - Region(int regionNumber, const MidiState& midiState, absl::string_view defaultPath = "") - : id{regionNumber}, midiState(midiState), defaultPath(std::move(defaultPath)) - { - ccSwitched.set(); - - gainToEffect.reserve(5); // sufficient room for main and fx1-4 - gainToEffect.push_back(1.0); // contribute 100% into the main bus - - // Default amplitude release - amplitudeEG.release = Default::ampegRelease; - } + Region(int regionNumber, const MidiState& midiState, absl::string_view defaultPath = ""); Region(const Region&) = default; ~Region() = default; @@ -280,12 +270,12 @@ struct Region { * @brief Process a generic CC opcode, and fill the modulation parameters. * * @param opcode - * @param range + * @param spec * @param target * @return true if the opcode was properly read and stored. * @return false */ - bool processGenericCc(const Opcode& opcode, Range range, const ModKey& target); + bool processGenericCc(const Opcode& opcode, OpcodeSpec spec, const ModKey& target); void offsetAllKeys(int offset) noexcept; @@ -329,45 +319,45 @@ struct Region { // Sound source: sample playback std::shared_ptr sampleId { new FileId }; // Sample absl::optional sampleQuality {}; - float delay { Default::delay }; // delay - float delayRandom { Default::delayRandom }; // delay_random - int64_t offset { Default::offset }; // offset - int64_t offsetRandom { Default::offsetRandom }; // offset_random - CCMap offsetCC { Default::offset }; - uint32_t sampleEnd { Default::sampleEndRange.getEnd() }; // end + float delay { Default::delay.value }; // delay + float delayRandom { Default::delayRandom.value }; // delay_random + int64_t offset { Default::offset.value }; // offset + int64_t offsetRandom { Default::offsetRandom.value }; // offset_random + CCMap offsetCC { Default::offsetMod.value }; + uint32_t sampleEnd { Default::sampleEnd.value }; // end absl::optional sampleCount {}; // count absl::optional loopMode {}; // loopmode - Range loopRange { Default::loopRange }; //loopstart and loopend - float loopCrossfade { Default::loopCrossfade }; // loop_crossfade + Range loopRange { Default::loopRange.bounds }; //loopstart and loopend + float loopCrossfade { Default::loopCrossfade.value }; // loop_crossfade // Wavetable oscillator - float oscillatorPhase { Default::oscillatorPhase }; + float oscillatorPhase { Default::oscillatorPhase.value }; enum class OscillatorEnabled { Auto = -1, Off = 0, On = 1 }; - OscillatorEnabled oscillatorEnabled = OscillatorEnabled::Auto; // oscillator - bool hasWavetableSample = false; // (set according to sample file) - int oscillatorMode = Default::oscillatorMode; - int oscillatorMulti = Default::oscillatorMulti; - float oscillatorDetune = Default::oscillatorDetune; - float oscillatorModDepth = Default::oscillatorModDepth; + OscillatorEnabled oscillatorEnabled { OscillatorEnabled::Auto }; // oscillator + bool hasWavetableSample { false }; // (set according to sample file) + int oscillatorMode { Default::oscillatorMode.value }; + int oscillatorMulti { Default::oscillatorMulti.value }; + float oscillatorDetune { Default::oscillatorDetune.value }; + float oscillatorModDepth { Default::oscillatorModDepth.value }; absl::optional oscillatorQuality; // Instrument settings: voice lifecycle - uint32_t group { Default::group }; // group + uint32_t group { Default::group.value }; // group absl::optional offBy {}; // off_by SfzOffMode offMode { Default::offMode }; // off_mode - float offTime { Default::offTime }; // off_mode + float offTime { Default::offTime.value }; // off_mode absl::optional notePolyphony {}; // note_polyphony - unsigned polyphony { config::maxVoices }; // polyphony + uint32_t polyphony { config::maxVoices }; // polyphony SfzSelfMask selfMask { Default::selfMask }; bool rtDead { Default::rtDead }; // Region logic: key mapping - Range keyRange { Default::keyRange }; //lokey, hikey and key - Range velocityRange { Default::velocityRange }; // hivel and lovel + Range keyRange { Default::key.bounds }; //lokey, hikey and key + Range velocityRange { Default::normalized.bounds }; // hivel and lovel // Region logic: MIDI conditions - Range bendRange { Default::bendValueRange }; // hibend and lobend - CCMap> ccConditions { Default::ccValueRange }; + Range bendRange { Default::bipolar.bounds }; // hibend and lobend + CCMap> ccConditions { Default::normalized.bounds }; absl::optional lastKeyswitch {}; // sw_last absl::optional> lastKeyswitchRange {}; // sw_last absl::optional keyswitchLabel {}; @@ -378,32 +368,32 @@ struct Region { SfzVelocityOverride velocityOverride { Default::velocityOverride }; // sw_vel bool checkSustain { Default::checkSustain }; // sustain_sw bool checkSostenuto { Default::checkSostenuto }; // sostenuto_sw - uint16_t sustainCC { Default::sustainCC }; // sustain_cc - float sustainThreshold { Default::sustainThreshold }; // sustain_cc + uint16_t sustainCC { Default::sustainCC.value }; // sustain_cc + float sustainThreshold { Default::sustainThreshold.value }; // sustain_cc // Region logic: internal conditions - Range aftertouchRange { Default::aftertouchRange }; // hichanaft and lochanaft - Range bpmRange { Default::bpmRange }; // hibpm and lobpm - Range randRange { Default::randRange }; // hirand and lorand - uint8_t sequenceLength { Default::sequenceLength }; // seq_length - uint8_t sequencePosition { Default::sequencePosition }; // seq_position + Range aftertouchRange { Default::midi7.bounds }; // hichanaft and lochanaft + Range bpmRange { Default::bpm.bounds }; // hibpm and lobpm + Range randRange { Default::normalized.bounds }; // hirand and lorand + uint8_t sequenceLength { Default::sequence.value }; // seq_length + uint8_t sequencePosition { Default::sequence.value }; // seq_position // Region logic: triggers SfzTrigger trigger { Default::trigger }; // trigger - CCMap> ccTriggers { Default::ccTriggerValueRange }; // on_loccN on_hiccN + CCMap> ccTriggers { Default::normalized.bounds }; // on_loccN on_hiccN // Performance parameters: amplifier - float volume { Default::volume }; // volume - float amplitude { normalizePercents(Default::amplitude) }; // amplitude - float pan { normalizePercents(Default::pan) }; // pan - float width { normalizePercents(Default::width) }; // width - float position { normalizePercents(Default::position) }; // position - uint8_t ampKeycenter { Default::ampKeycenter }; // amp_keycenter - float ampKeytrack { Default::ampKeytrack }; // amp_keytrack - float ampVeltrack { normalizePercents(Default::ampVeltrack) }; // amp_keytrack + float volume { Default::volume.value }; // volume + float amplitude { normalizePercents(Default::amplitude.value) }; // amplitude + float pan { normalizePercents(Default::pan.value) }; // pan + float width { normalizePercents(Default::width.value) }; // width + float position { normalizePercents(Default::position.value) }; // position + uint8_t ampKeycenter { Default::key.value }; // amp_keycenter + float ampKeytrack { Default::ampKeytrack.value }; // amp_keytrack + float ampVeltrack { normalizePercents(Default::ampVeltrack.value) }; // amp_veltrack std::vector> velocityPoints; // amp_velcurve_N absl::optional velCurve {}; - float ampRandom { Default::ampRandom }; // amp_random + float ampRandom { Default::ampRandom.value }; // amp_random Range crossfadeKeyInRange { Default::crossfadeKeyInRange }; Range crossfadeKeyOutRange { Default::crossfadeKeyOutRange }; Range crossfadeVelInRange { Default::crossfadeVelInRange }; @@ -413,7 +403,7 @@ struct Region { SfzCrossfadeCurve crossfadeCCCurve { Default::crossfadeCCCurve }; CCMap> crossfadeCCInRange { Default::crossfadeCCInRange }; // xfin_loccN xfin_hiccN CCMap> crossfadeCCOutRange { Default::crossfadeCCOutRange }; // xfout_loccN xfout_hiccN - float rtDecay { Default::rtDecay }; // rt_decay + float rtDecay { Default::rtDecay.value }; // rt_decay float globalAmplitude { 1.0 }; // global_amplitude float masterAmplitude { 1.0 }; // master_amplitude @@ -427,17 +417,17 @@ struct Region { std::vector filters; // Performance parameters: pitch - uint8_t pitchKeycenter { Default::pitchKeycenter }; // pitch_keycenter + uint8_t pitchKeycenter { Default::key.value }; // pitch_keycenter bool pitchKeycenterFromSample { false }; - int pitchKeytrack { Default::pitchKeytrack }; // pitch_keytrack - float pitchRandom { Default::pitchRandom }; // pitch_random - int pitchVeltrack { Default::pitchVeltrack }; // pitch_veltrack - int transpose { Default::transpose }; // transpose - float tune { Default::tune }; // tune - int bendUp { Default::bendUp }; - int bendDown { Default::bendDown }; - int bendStep { Default::bendStep }; - uint8_t bendSmooth { Default::bendSmooth }; + int pitchKeytrack { Default::pitchKeytrack.value }; // pitch_keytrack + float pitchRandom { Default::pitchRandom.value }; // pitch_random + int pitchVeltrack { Default::pitchVeltrack.value }; // pitch_veltrack + int transpose { Default::transpose.value }; // transpose + float pitch { Default::pitch.value }; // tune + float bendUp { Default::bendUp.value }; + float bendDown { Default::bendDown.value }; + float bendStep { Default::bendStep.value }; + uint8_t bendSmooth { Default::smoothCC.value }; // Envelopes EGDescription amplitudeEG; diff --git a/src/sfizz/SfzHelpers.h b/src/sfizz/SfzHelpers.h index b26f6560..7577d60d 100644 --- a/src/sfizz/SfzHelpers.h +++ b/src/sfizz/SfzHelpers.h @@ -182,18 +182,17 @@ constexpr float normalizeBend(float bendValue) * * @param key * @param offset - * @param range * @return uint8_t */ -inline CXX14_CONSTEXPR uint8_t offsetAndClampKey(uint8_t key, int offset, sfz::Range range) +inline CXX14_CONSTEXPR uint8_t offsetAndClampKey(uint8_t key, int offset) { const int offsetKey { key + offset }; if (offsetKey > std::numeric_limits::max()) - return range.getEnd(); + return Default::key.bounds.getEnd(); if (offsetKey < std::numeric_limits::min()) - return range.getStart(); + return Default::key.bounds.getStart(); - return range.clamp(static_cast(offsetKey)); + return Default::key.bounds.clamp(static_cast(offsetKey)); } namespace literals { diff --git a/src/sfizz/Smoothers.cpp b/src/sfizz/Smoothers.cpp index fda61be0..c2f6e2fb 100644 --- a/src/sfizz/Smoothers.cpp +++ b/src/sfizz/Smoothers.cpp @@ -5,6 +5,10 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "Smoothers.h" +#include "Config.h" +#include "MathHelpers.h" +#include "SfzHelpers.h" +#include "SIMDHelpers.h" namespace sfz { @@ -16,7 +20,7 @@ void Smoother::setSmoothing(uint8_t smoothValue, float sampleRate) { smoothing = (smoothValue > 0); if (smoothing) { - filter.setGain(std::tan(1.0f / (2 * Default::smoothTauPerStep * smoothValue * sampleRate))); + filter.setGain(std::tan(1.0f / (2 * config::smoothTauPerStep * smoothValue * sampleRate))); } } diff --git a/src/sfizz/Smoothers.h b/src/sfizz/Smoothers.h index 598dd203..50f99821 100644 --- a/src/sfizz/Smoothers.h +++ b/src/sfizz/Smoothers.h @@ -6,12 +6,7 @@ #pragma once -#include "Config.h" -#include "Defaults.h" -#include "MathHelpers.h" -#include "SfzHelpers.h" #include "OnePoleFilter.h" -#include "SIMDHelpers.h" #include namespace sfz { diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index b82cb372..43ac6241 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -191,7 +191,7 @@ void Synth::Impl::buildRegion(const std::vector& regionOpcodes) currentSwitch_ = *lastRegion->defaultSwitch; // There was a combination of group= and polyphony= on a region, so set the group polyphony - if (lastRegion->group != Default::group && lastRegion->polyphony != config::maxVoices) { + if (lastRegion->group != Default::group.value && lastRegion->polyphony != config::maxVoices) { voiceManager_.setGroupPolyphony(lastRegion->group, lastRegion->polyphony); } else { // Just check that there are enough polyphony groups @@ -276,11 +276,12 @@ void Synth::Impl::handleMasterOpcodes(const std::vector& members) switch (member.lettersOnlyHash) { case hash("polyphony"): ASSERT(currentSet_ != nullptr); - if (auto value = readOpcode(member.value, Default::polyphonyRange)) + if (auto value = member.read(Default::polyphony)) currentSet_->setPolyphonyLimit(*value); break; case hash("sw_default"): - setValueFromOpcode(member, currentSwitch_, Default::keyRange); + if (auto value = member.read(Default::key)) + currentSwitch_ = *value; break; } } @@ -294,15 +295,16 @@ void Synth::Impl::handleGlobalOpcodes(const std::vector& members) switch (member.lettersOnlyHash) { case hash("polyphony"): ASSERT(currentSet_ != nullptr); - if (auto value = readOpcode(member.value, Default::polyphonyRange)) + if (auto value = member.read(Default::polyphony)) currentSet_->setPolyphonyLimit(*value); break; case hash("sw_default"): - setValueFromOpcode(member, currentSwitch_, Default::keyRange); + if (auto value = member.read(Default::key)) + currentSwitch_ = *value; break; case hash("volume"): // FIXME : Probably best not to mess with this and let the host control the volume - // setValueFromOpcode(member, volume, Default::volumeRange); + // setValueFromOpcode(member, volume, OldDefault::volumeRange); break; } } @@ -318,13 +320,16 @@ void Synth::Impl::handleGroupOpcodes(const std::vector& members, const s switch (member.lettersOnlyHash) { case hash("group"): - setValueFromOpcode(member, groupIdx, Default::groupRange); + if (auto value = member.read(Default::group)) + groupIdx = *value; break; case hash("polyphony"): - setValueFromOpcode(member, maxPolyphony, Default::polyphonyRange); + if (auto value = member.read(Default::polyphony)) + maxPolyphony = *value; break; case hash("sw_default"): - setValueFromOpcode(member, currentSwitch_, Default::keyRange); + if (auto value = member.read(Default::key)) + currentSwitch_ = *value; break; } }; @@ -352,15 +357,15 @@ void Synth::Impl::handleControlOpcodes(const std::vector& members) switch (member.lettersOnlyHash) { case hash("set_cc&"): - if (Default::ccNumberRange.containsWithEnd(member.parameters.back())) { - const auto ccValue = readOpcode(member.value, Default::midi7Range); + if (Default::ccNumber.bounds.containsWithEnd(member.parameters.back())) { + const auto ccValue = member.read(Default::midi7); if (ccValue) setDefaultHdcc(member.parameters.back(), normalizeCC(*ccValue)); } break; case hash("set_hdcc&"): - if (Default::ccNumberRange.containsWithEnd(member.parameters.back())) { - const auto ccValue = readOpcode(member.value, Default::normalizedRange); + if (Default::ccNumber.bounds.containsWithEnd(member.parameters.back())) { + const auto ccValue = member.read(Default::normalized); if (ccValue) setDefaultHdcc(member.parameters.back(), *ccValue); } @@ -370,7 +375,7 @@ void Synth::Impl::handleControlOpcodes(const std::vector& members) setCCLabel(member.parameters.back(), std::string(member.value)); break; case hash("label_key&"): - if (member.parameters.back() <= Default::keyRange.getEnd()) { + if (member.parameters.back() <= Default::key.bounds.getEnd()) { const auto noteNumber = static_cast(member.parameters.back()); insertPairUniquely(keyLabels_, noteNumber, std::string(member.value)); } @@ -380,10 +385,10 @@ void Synth::Impl::handleControlOpcodes(const std::vector& members) DBG("Changing default sample path to " << defaultPath_); break; case hash("note_offset"): - setValueFromOpcode(member, noteOffset_, Default::noteOffsetRange); + noteOffset_ = member.read(Default::noteOffset).value_or(noteOffset_); break; case hash("octave_offset"): - setValueFromOpcode(member, octaveOffset_, Default::octaveOffsetRange); + octaveOffset_ = member.read(Default::octaveOffset).value_or(octaveOffset_); break; case hash("hint_ram_based"): if (member.value == "1") @@ -446,21 +451,21 @@ void Synth::Impl::handleEffectOpcodes(const std::vector& rawMembers) // note(jpc): gain opcodes are linear volumes in % units case hash("directtomain"): - if (auto valueOpt = readOpcode(opcode.value, { 0, 100 })) + if (auto valueOpt = opcode.read(Default::effect)) getOrCreateBus(0).setGainToMain(*valueOpt / 100); break; case hash("fx&tomain"): // fx&tomain if (opcode.parameters.front() < 1 || opcode.parameters.front() > config::maxEffectBuses) break; - if (auto valueOpt = readOpcode(opcode.value, { 0, 100 })) + if (auto valueOpt = opcode.read(Default::effect)) getOrCreateBus(opcode.parameters.front()).setGainToMain(*valueOpt / 100); break; case hash("fx&tomix"): // fx&tomix if (opcode.parameters.front() < 1 || opcode.parameters.front() > config::maxEffectBuses) break; - if (auto valueOpt = readOpcode(opcode.value, { 0, 100 })) + if (auto valueOpt = opcode.read(Default::effect)) getOrCreateBus(opcode.parameters.front()).setGainToMix(*valueOpt / 100); break; } @@ -584,10 +589,10 @@ void Synth::Impl::finalizeSfzLoad() region->sampleEnd = std::min(region->sampleEnd, fileInformation->end); if (fileInformation->hasLoop) { - if (region->loopRange.getStart() == Default::loopRange.getStart()) + if (region->loopRange.getStart() == Default::loopRange.bounds.getStart()) region->loopRange.setStart(fileInformation->loopBegin); - if (region->loopRange.getEnd() == Default::loopRange.getEnd()) + if (region->loopRange.getEnd() == Default::loopRange.bounds.getEnd()) region->loopRange.setEnd(fileInformation->loopEnd); if (!region->loopMode) @@ -597,7 +602,7 @@ void Synth::Impl::finalizeSfzLoad() if (region->isRelease() && !region->loopMode) region->loopMode = SfzLoopMode::one_shot; - if (region->loopRange.getEnd() == Default::loopRange.getEnd()) + if (region->loopRange.getEnd() == Default::loopRange.bounds.getEnd()) region->loopRange.setEnd(region->sampleEnd); if (fileInformation->numChannels == 2) @@ -611,7 +616,7 @@ void Synth::Impl::finalizeSfzLoad() uint64_t sumOffsetCC = region->offset + region->offsetRandom; for (const auto& offsets : region->offsetCC) sumOffsetCC += offsets.data; - return Default::offsetCCRange.clamp(sumOffsetCC); + return Default::offsetMod.bounds.clamp(sumOffsetCC); }(); if (!resources_.filePool.preloadFile(*region->sampleId, maxOffset)) @@ -663,14 +668,14 @@ void Synth::Impl::finalizeSfzLoad() // Set the default frequencies on equalizers if needed if (region->equalizers.size() > 0 - && region->equalizers[0].frequency == Default::eqFrequencyUnset) { - region->equalizers[0].frequency = Default::eqFrequency1; + && region->equalizers[0].frequency == Default::eqFrequency.value) { + region->equalizers[0].frequency = Default::defaultEQFreq[0]; if (region->equalizers.size() > 1 - && region->equalizers[1].frequency == Default::eqFrequencyUnset) { - region->equalizers[1].frequency = Default::eqFrequency2; + && region->equalizers[1].frequency == Default::eqFrequency.value) { + region->equalizers[1].frequency = Default::defaultEQFreq[1]; if (region->equalizers.size() > 2 - && region->equalizers[2].frequency == Default::eqFrequencyUnset) { - region->equalizers[2].frequency = Default::eqFrequency3; + && region->equalizers[2].frequency == Default::eqFrequency.value) { + region->equalizers[2].frequency = Default::defaultEQFreq[2]; } } } @@ -1479,7 +1484,7 @@ float Synth::getVolume() const noexcept void Synth::setVolume(float volume) noexcept { Impl& impl = *impl_; - impl.volume_ = Default::volumeRange.clamp(volume); + impl.volume_ = Default::volume.bounds.clamp(volume); } int Synth::getNumVoices() const noexcept diff --git a/src/sfizz/SynthConfig.h b/src/sfizz/SynthConfig.h index 3f710f89..47d265e6 100644 --- a/src/sfizz/SynthConfig.h +++ b/src/sfizz/SynthConfig.h @@ -13,8 +13,8 @@ struct SynthConfig { bool freeWheeling { false }; - int liveSampleQuality { sfz::Default::sampleQuality }; - int freeWheelingSampleQuality { sfz::Default::sampleQualityInFreewheelingMode }; + int liveSampleQuality { Default::sampleQuality.value }; + int freeWheelingSampleQuality { Default::freewheelingQuality }; int currentSampleQuality() const noexcept { diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index 9902b58b..0f6bd10b 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -124,6 +124,24 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co } } break; + MATCH("/region&/trigger_on_note", "") { + GET_REGION_OR_BREAK(indices[0]) + if (region.triggerOnNote) { + client.receive<'T'>(delay, path, {}); + } else { + client.receive<'F'>(delay, path, {}); + } + } break; + + MATCH("/region&/trigger_on_cc", "") { + GET_REGION_OR_BREAK(indices[0]) + if (region.triggerOnCC) { + client.receive<'T'>(delay, path, {}); + } else { + client.receive<'F'>(delay, path, {}); + } + } break; + MATCH("/region&/count", "") { GET_REGION_OR_BREAK(indices[0]) if (!region.sampleCount) { @@ -761,12 +779,12 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co client.receive<'i'>(delay, path, region.transpose); } break; - MATCH("/region&/tune", "") { + MATCH("/region&/pitch", "") { GET_REGION_OR_BREAK(indices[0]) - client.receive<'f'>(delay, path, region.tune); + client.receive<'f'>(delay, path, region.pitch); } break; - MATCH("/region&/tune_cc&", "") { + MATCH("/region&/pitch_cc&", "") { GET_REGION_OR_BREAK(indices[0]) auto value = region.ccModDepth(indices[1], ModId::Pitch); if (value) { @@ -776,7 +794,7 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co } } break; - MATCH("/region&/tune_stepcc&", "") { + MATCH("/region&/pitch_stepcc&", "") { GET_REGION_OR_BREAK(indices[0]) auto params = region.ccModParameters(indices[1], ModId::Pitch); if (params) { @@ -786,7 +804,7 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co } } break; - MATCH("/region&/tune_smoothcc&", "") { + MATCH("/region&/pitch_smoothcc&", "") { GET_REGION_OR_BREAK(indices[0]) auto params = region.ccModParameters(indices[1], ModId::Pitch); if (params) { @@ -796,7 +814,7 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co } } break; - MATCH("/region&/tune_curvecc&", "") { + MATCH("/region&/pitch_curvecc&", "") { GET_REGION_OR_BREAK(indices[0]) auto params = region.ccModParameters(indices[1], ModId::Pitch); if (params) { @@ -808,17 +826,17 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co MATCH("/region&/bend_up", "") { GET_REGION_OR_BREAK(indices[0]) - client.receive<'i'>(delay, path, region.bendUp); + client.receive<'f'>(delay, path, region.bendUp); } break; MATCH("/region&/bend_down", "") { GET_REGION_OR_BREAK(indices[0]) - client.receive<'i'>(delay, path, region.bendDown); + client.receive<'f'>(delay, path, region.bendDown); } break; MATCH("/region&/bend_step", "") { GET_REGION_OR_BREAK(indices[0]) - client.receive<'i'>(delay, path, region.bendStep); + client.receive<'f'>(delay, path, region.bendStep); } break; MATCH("/region&/bend_smooth", "") { @@ -863,7 +881,7 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co MATCH("/region&/ampeg_depth", "") { GET_REGION_OR_BREAK(indices[0]) - client.receive<'i'>(delay, path, region.amplitudeEG.depth); + client.receive<'f'>(delay, path, region.amplitudeEG.depth); } break; MATCH("/region&/ampeg_vel&attack", "") { @@ -912,7 +930,7 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co GET_REGION_OR_BREAK(indices[0]) if (indices[1] != 2) break; - client.receive<'i'>(delay, path, region.amplitudeEG.vel2depth); + client.receive<'f'>(delay, path, region.amplitudeEG.vel2depth); } break; MATCH("/region&/note_polyphony", "") { @@ -978,6 +996,37 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co client.receive<'f'>(delay, path, region.oscillatorPhase); } break; + MATCH("/region&/oscillator_quality", "") { + GET_REGION_OR_BREAK(indices[0]) + if (region.oscillatorQuality) { + client.receive<'i'>(delay, path, *region.oscillatorQuality); + } else { + client.receive<'N'>(delay, path, {}); + } + } break; + + MATCH("/region&/oscillator_mode", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'i'>(delay, path, region.oscillatorMode); + } break; + + MATCH("/region&/oscillator_multi", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'i'>(delay, path, region.oscillatorMulti); + } break; + + MATCH("/region&/oscillator_detune", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.oscillatorDetune); + } break; + + MATCH("/region&/oscillator_mod_depth", "") { + GET_REGION_OR_BREAK(indices[0]) + client.receive<'f'>(delay, path, region.oscillatorModDepth * 100.0f); + } break; + + // TODO: detune cc, mod depth cc + MATCH("/region&/effect&", "") { GET_REGION_OR_BREAK(indices[0]) auto effectIdx = indices[1]; diff --git a/src/sfizz/SynthPrivate.h b/src/sfizz/SynthPrivate.h index 0e251024..bd34ec22 100644 --- a/src/sfizz/SynthPrivate.h +++ b/src/sfizz/SynthPrivate.h @@ -257,8 +257,8 @@ struct Synth::Impl final: public Parser::Listener { // Control opcodes std::string defaultPath_ { "" }; - int noteOffset_ { 0 }; - int octaveOffset_ { 0 }; + int noteOffset_ { Default::noteOffset.value }; + int octaveOffset_ { Default::octaveOffset.value }; // Modulation source generators std::unique_ptr genController_; diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 64ddebe9..4ba91ba1 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -370,7 +370,8 @@ void Voice::startVoice(Region* region, int delay, const TriggerEvent& event) noe } } const float phase = region->getPhase(); - const int quality = region->oscillatorQuality.value_or(Default::oscillatorQuality); + const int quality = + region->oscillatorQuality.value_or(Default::oscillatorQuality.value); for (WavetableOscillator& osc : impl.waveOscillators_) { osc.setWavetable(wave); osc.setPhase(phase); @@ -464,7 +465,7 @@ void Voice::off(int delay, bool fast) noexcept Impl& impl = *impl_; if (!impl.region_->flexAmpEG) { if (impl.region_->offMode == SfzOffMode::fast || fast) { - impl.egAmplitude_.setReleaseTime(Default::offTime); + impl.egAmplitude_.setReleaseTime(Default::offTime.value); } else if (impl.region_->offMode == SfzOffMode::time) { impl.egAmplitude_.setReleaseTime(impl.region_->offTime); } @@ -1652,7 +1653,7 @@ void Voice::Impl::pitchEnvelope(absl::Span pitchSpan) noexcept return centsFactor(region_->getBendInCents(bend)); }; - if (region_->bendStep > 1) + if (region_->bendStep > 1.0f) pitchBendEnvelope(events, *bends, bendLambda, bendStepFactor_); else pitchBendEnvelope(events, *bends, bendLambda); diff --git a/src/sfizz/effects/Apan.cpp b/src/sfizz/effects/Apan.cpp index a51f4a4e..9151188a 100644 --- a/src/sfizz/effects/Apan.cpp +++ b/src/sfizz/effects/Apan.cpp @@ -81,27 +81,27 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("apan_waveform"): - if (auto value = readOpcode(opc.value, Default::apanWaveformRange)) + if (auto value = opc.read(Default::apanWaveform)) apan->_lfoWave = *value; break; case hash("apan_freq"): - if (auto value = readOpcode(opc.value, Default::apanFrequencyRange)) + if (auto value = opc.read(Default::apanFrequency)) apan->_lfoFrequency = *value; break; case hash("apan_phase"): - if (auto value = readOpcode(opc.value, Default::apanPhaseRange)) + if (auto value = opc.read(Default::apanPhase)) apan->_lfoPhaseOffset = wrapPhase(*value); break; case hash("apan_dry"): - if (auto value = readOpcode(opc.value, Default::apanLevelRange)) + if (auto value = opc.read(Default::apanLevel)) apan->_dry = *value / 100.0f; break; case hash("apan_wet"): - if (auto value = readOpcode(opc.value, Default::apanLevelRange)) + if (auto value = opc.read(Default::apanLevel)) apan->_wet = *value / 100.0f; break; case hash("apan_depth"): - if (auto value = readOpcode(opc.value, Default::apanLevelRange)) + if (auto value = opc.read(Default::apanLevel)) apan->_depth = *value / 100.0f; break; } diff --git a/src/sfizz/effects/Apan.h b/src/sfizz/effects/Apan.h index 52b85dc6..ac72e524 100644 --- a/src/sfizz/effects/Apan.h +++ b/src/sfizz/effects/Apan.h @@ -47,20 +47,20 @@ namespace fx { template void computeLfos(float* left, float* right, unsigned nframes); private: - float _samplePeriod = 0.0; + float _samplePeriod { 0.0f }; sfz::Buffer _lfoOutLeft { config::defaultSamplesPerBlock }; sfz::Buffer _lfoOutRight { config::defaultSamplesPerBlock }; // Controls - float _dry = 0.0; - float _wet = 0.0; - float _depth = 0.0; - int _lfoWave = 0; - float _lfoFrequency = 0.0; - float _lfoPhaseOffset = 0.5; + float _dry { Default::apanLevel.value }; + float _wet { Default::apanLevel.value }; + float _depth { Default::apanLevel.value }; + int _lfoWave { Default::apanWaveform.value }; + float _lfoFrequency { Default::apanFrequency.value }; + float _lfoPhaseOffset { Default::apanPhase.value }; // State - float _lfoPhase = 0.0; + float _lfoPhase { 0.0f }; }; } // namespace fx diff --git a/src/sfizz/effects/Compressor.cpp b/src/sfizz/effects/Compressor.cpp index 3aaf04a3..06b805ee 100644 --- a/src/sfizz/effects/Compressor.cpp +++ b/src/sfizz/effects/Compressor.cpp @@ -32,7 +32,7 @@ namespace fx { struct Compressor::Impl { faustCompressor _compressor[2]; bool _stlink = false; - float _inputGain = 1.0; + float _inputGain { Default::compGain.value }; AudioBuffer _tempBuffer2x { 2, _oversampling * config::defaultSamplesPerBlock }; AudioBuffer _gain2x { 2, _oversampling * config::defaultSamplesPerBlock }; hiir::Downsampler2xFpu<12> _downsampler2x[EffectChannels]; @@ -163,31 +163,31 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("comp_attack"): - if (auto value = readOpcode(opc.value, {0.0, 10.0})) { + if (auto value = opc.read(Default::compAttack)) { for (size_t c = 0; c < 2; ++c) impl.set_Attack(c, *value); } break; case hash("comp_release"): - if (auto value = readOpcode(opc.value, {0.0, 10.0})) { + if (auto value = opc.read(Default::compRelease)) { for (size_t c = 0; c < 2; ++c) impl.set_Release(c, *value); } break; case hash("comp_threshold"): - if (auto value = readOpcode(opc.value, {-100.0, 0.0})) { + if (auto value = opc.read(Default::compThreshold)) { for (size_t c = 0; c < 2; ++c) impl.set_Threshold(c, *value); } break; case hash("comp_ratio"): - if (auto value = readOpcode(opc.value, {1.0, 50.0})) { + if (auto value = opc.read(Default::compRatio)) { for (size_t c = 0; c < 2; ++c) impl.set_Ratio(c, *value); } break; case hash("comp_gain"): - if (auto value = readOpcode(opc.value, {-100.0, 100.0})) + if (auto value = opc.read(Default::compGain)) impl._inputGain = db2mag(*value); break; case hash("comp_stlink"): diff --git a/src/sfizz/effects/Disto.cpp b/src/sfizz/effects/Disto.cpp index 9e83856a..c3939f9e 100644 --- a/src/sfizz/effects/Disto.cpp +++ b/src/sfizz/effects/Disto.cpp @@ -37,15 +37,15 @@ namespace fx { struct Disto::Impl { enum { maxStages = 4 }; - float _samplePeriod = 1.0 / config::defaultSampleRate; - float _tone = 100.0; - float _depth = 0.0; - float _dry = 0.0; - float _wet = 0.0; - unsigned _numStages = 1; + float _samplePeriod { 1.0f / config::defaultSampleRate }; + float _tone { Default::distoTone.value }; + float _depth { Default::distoDepth.value }; + float _dry { Default::effect.value }; + float _wet { Default::effect.value }; + unsigned _numStages = { Default::distoStages.value }; float _toneLpfMem[EffectChannels] = {}; - faustDisto _stages[EffectChannels][maxStages]; + faustDisto _stages[EffectChannels][Default::maxDistoStages]; hiir::Upsampler2xFpu<12> _up2x[EffectChannels]; hiir::Upsampler2xFpu<4> _up4x[EffectChannels]; @@ -205,20 +205,23 @@ std::unique_ptr Disto::makeInstance(absl::Span members) for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("disto_tone"): - setValueFromOpcode(opc, impl._tone, {0.0f, 100.0f}); + if (auto value = opc.read(Default::distoTone)) + impl._tone = *value; break; case hash("disto_depth"): - setValueFromOpcode(opc, impl._depth, {0.0f, 100.0f}); + if (auto value = opc.read(Default::distoDepth)) + impl._depth = *value; break; case hash("disto_stages"): - setValueFromOpcode(opc, impl._numStages, {1, Impl::maxStages}); + if (auto value = opc.read(Default::distoStages)) + impl._numStages = *value; break; case hash("disto_dry"): - if (auto value = readOpcode(opc.value, {0.0f, 100.0f})) + if (auto value = opc.read(Default::effect)) impl._dry = *value * 0.01f; break; case hash("disto_wet"): - if (auto value = readOpcode(opc.value, {0.0f, 100.0f})) + if (auto value = opc.read(Default::effect)) impl._wet = *value * 0.01f; break; } diff --git a/src/sfizz/effects/Eq.cpp b/src/sfizz/effects/Eq.cpp index 1eda27e4..7c9b5594 100644 --- a/src/sfizz/effects/Eq.cpp +++ b/src/sfizz/effects/Eq.cpp @@ -70,13 +70,16 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("eq_freq"): - setValueFromOpcode(opc, desc.frequency, Default::eqFrequencyRange); + if (auto value = opc.read(Default::eqFrequency)) + desc.frequency = *value; break; case hash("eq_bw"): - setValueFromOpcode(opc, desc.bandwidth, Default::eqBandwidthRange); + if (auto value = opc.read(Default::eqBandwidth)) + desc.bandwidth = *value; break; case hash("eq_gain"): - setValueFromOpcode(opc, desc.gain, Default::eqGainRange); + if (auto value = opc.read(Default::eqGain)) + desc.gain = *value; break; case hash("eq_type"): { diff --git a/src/sfizz/effects/Filter.cpp b/src/sfizz/effects/Filter.cpp index d39d74f1..836306f3 100644 --- a/src/sfizz/effects/Filter.cpp +++ b/src/sfizz/effects/Filter.cpp @@ -72,10 +72,12 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("filter_cutoff"): - setValueFromOpcode(opc, desc.cutoff, Default::filterCutoffRange); + if (auto value = opc.read(Default::filterCutoff)) + desc.cutoff = *value; break; case hash("filter_resonance"): - setValueFromOpcode(opc, desc.resonance, Default::filterResonanceRange); + if (auto value = opc.read(Default::filterResonance)) + desc.resonance = *value; break; case hash("filter_type"): { @@ -90,7 +92,8 @@ namespace fx { } // extension case hash("sfizz:filter_gain"): - setValueFromOpcode(opc, desc.gain, Default::filterGainRange); + if (auto value = opc.read(Default::filterGain)) + desc.gain = *value; break; } } diff --git a/src/sfizz/effects/Fverb.cpp b/src/sfizz/effects/Fverb.cpp index 71e73efa..c3a1f408 100644 --- a/src/sfizz/effects/Fverb.cpp +++ b/src/sfizz/effects/Fverb.cpp @@ -180,13 +180,13 @@ namespace fx { std::unique_ptr fx { reverb }; const Impl::Profile* profile = &Impl::largeHall; - float dry = 0; - float wet = 0; - float input = 0; - float size = 0; - float predelay = 0; - float tone = 100; - float damp = 0; + float dry { Default::effect.value }; + float wet { Default::effect.value }; + float input { Default::effect.value }; + float size { Default::fverbSize.value }; + float predelay { Default::fverbPredelay.value }; + float tone { Default::fverbTone.value }; + float damp { Default::fverbDamp.value }; for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { @@ -211,25 +211,26 @@ namespace fx { } break; case hash("reverb_dry"): - setValueFromOpcode(opc, dry, {0.0f, 100.0f}); + + dry = opc.read(Default::effect).value_or(dry); break; case hash("reverb_wet"): - setValueFromOpcode(opc, wet, {0.0f, 100.0f}); + wet = opc.read(Default::effect).value_or(wet); break; case hash("reverb_input"): - setValueFromOpcode(opc, input, {0.0f, 100.0f}); + input = opc.read(Default::effect).value_or(input); break; case hash("reverb_size"): - setValueFromOpcode(opc, size, {0.0f, 100.0f}); + size = opc.read(Default::fverbSize).value_or(size); break; case hash("reverb_predelay"): - setValueFromOpcode(opc, predelay, {0.0f, 10.0f}); + predelay = opc.read(Default::fverbPredelay).value_or(predelay); break; case hash("reverb_tone"): - setValueFromOpcode(opc, tone, {0.0f, 100.0f}); + tone = opc.read(Default::fverbTone).value_or(tone); break; case hash("reverb_damp"): - setValueFromOpcode(opc, damp, {0.0f, 100.0f}); + damp = opc.read(Default::fverbDamp).value_or(damp); break; } } diff --git a/src/sfizz/effects/Gain.cpp b/src/sfizz/effects/Gain.cpp index 04cca832..7ad9fb9f 100644 --- a/src/sfizz/effects/Gain.cpp +++ b/src/sfizz/effects/Gain.cpp @@ -62,7 +62,8 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("gain"): - setValueFromOpcode(opc, gain->_gain, {-96.0f, 96.0f}); + if (auto value = opc.read(Default::volume)) + gain->_gain = *value; break; } } diff --git a/src/sfizz/effects/Gate.cpp b/src/sfizz/effects/Gate.cpp index b7a819d5..792060e6 100644 --- a/src/sfizz/effects/Gate.cpp +++ b/src/sfizz/effects/Gate.cpp @@ -166,25 +166,25 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("gate_attack"): - if (auto value = readOpcode(opc.value, {0.0, 10.0})) { + if (auto value = opc.read(Default::gateAttack)) { for (size_t c = 0; c < 2; ++c) impl.set_Attack(c, *value); } break; case hash("gate_hold"): - if (auto value = readOpcode(opc.value, {0.0, 10.0})) { + if (auto value = opc.read(Default::gateHold)) { for (size_t c = 0; c < 2; ++c) impl.set_Hold(c, *value); } break; case hash("gate_release"): - if (auto value = readOpcode(opc.value, {0.0, 10.0})) { + if (auto value = opc.read(Default::gateRelease)) { for (size_t c = 0; c < 2; ++c) impl.set_Release(c, *value); } break; case hash("gate_threshold"): - if (auto value = readOpcode(opc.value, {-100.0, 0.0})) { + if (auto value = opc.read(Default::gateThreshold)) { for (size_t c = 0; c < 2; ++c) impl.set_Threshold(c, *value); } diff --git a/src/sfizz/effects/Lofi.cpp b/src/sfizz/effects/Lofi.cpp index 12d7759f..00a11128 100644 --- a/src/sfizz/effects/Lofi.cpp +++ b/src/sfizz/effects/Lofi.cpp @@ -85,10 +85,12 @@ namespace fx { for (const Opcode& opcode : members) { switch (opcode.lettersOnlyHash) { case hash("bitred"): - setValueFromOpcode(opcode, lofi->_bitred_depth, { 0.0, 100.0 }); + if (auto value = opcode.read(Default::lofiBitred)) + lofi->_bitred_depth = *value; break; case hash("decim"): - setValueFromOpcode(opcode, lofi->_decim_depth, { 0.0, 100.0 }); + if (auto value = opcode.read(Default::lofiDecim)) + lofi->_decim_depth = *value; break; } } diff --git a/src/sfizz/effects/Rectify.cpp b/src/sfizz/effects/Rectify.cpp index 56be4682..f8d271dd 100644 --- a/src/sfizz/effects/Rectify.cpp +++ b/src/sfizz/effects/Rectify.cpp @@ -95,7 +95,8 @@ namespace fx { rectify->_full = false; break; case hash("rectify"): - setValueFromOpcode(opc, rectify->_amount, { 0.0, 100.0 }); + if (auto value = opc.read(Default::rectify)) + rectify->_amount = *value; break; } } diff --git a/src/sfizz/effects/Strings.cpp b/src/sfizz/effects/Strings.cpp index 9e7295d4..6538b68a 100644 --- a/src/sfizz/effects/Strings.cpp +++ b/src/sfizz/effects/Strings.cpp @@ -132,10 +132,12 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("strings_number"): - setValueFromOpcode(opc, strings->_numStrings, {0, MaximumNumStrings}); + if (auto value = opc.read(Default::stringsNumber)) + strings->_numStrings = *value; break; case hash("strings_wet"): - setValueFromOpcode(opc, strings->_wet, {0.0f, 100.0f}); + if (auto value = opc.read(Default::effect)) + strings->_wet = *value; break; } } diff --git a/src/sfizz/effects/Strings.h b/src/sfizz/effects/Strings.h index 2f46254b..f20ae8a8 100644 --- a/src/sfizz/effects/Strings.h +++ b/src/sfizz/effects/Strings.h @@ -51,8 +51,8 @@ namespace fx { private: enum { MaximumNumStrings = 88 }; - unsigned _numStrings = MaximumNumStrings; - float _wet = 0; + unsigned _numStrings { Default::maxStrings }; + float _wet { Default::effect.value }; std::unique_ptr _stringsArray; diff --git a/src/sfizz/effects/Width.cpp b/src/sfizz/effects/Width.cpp index a9c3c202..2a3cdc92 100644 --- a/src/sfizz/effects/Width.cpp +++ b/src/sfizz/effects/Width.cpp @@ -69,7 +69,8 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("width"): - setValueFromOpcode(opc, width->_width, {-100.0f, 100.0f}); + if (auto value = opc.read(Default::width)) + width->_width = *value; break; } } diff --git a/tests/FilesT.cpp b/tests/FilesT.cpp index 28c41dd9..1072d188 100644 --- a/tests/FilesT.cpp +++ b/tests/FilesT.cpp @@ -447,7 +447,20 @@ TEST_CASE("[Files] Set RealCC applies properly") TEST_CASE("[Files] Note and octave offsets") { Synth synth; - synth.loadSfzFile(fs::current_path() / "tests/TestFiles/note_offset.sfz"); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/note_offset.sfz", R"( + note_offset=1 + key=63 sample=*sine + lokey=50 hikey=55 pitch_keycenter=50 sample=*sine + lokey=40 hikey=44 pitch_keycenter=40 xfin_lokey=36 xfin_hikey=40 xfout_lokey=44 xfout_hikey=48 sample=*sine + note_offset=-1 + key=63 sw_lokey=24 sw_hikey=28 sw_last=25 sw_up=25 sw_down=25 sw_previous=62 sample=*sine + note_offset=1 octave_offset=1 + key=63 sample=*sine + note_offset=-1 octave_offset=-1 + key=63 sample=*sine + // Check that this does not reset either note or octave offset + key=63 sample=*sine + )"); REQUIRE( synth.getNumRegions() == 7 ); REQUIRE(synth.getRegionView(0)->keyRange == Range(64, 64)); diff --git a/tests/OpcodeT.cpp b/tests/OpcodeT.cpp index 24d6a98c..61971b39 100644 --- a/tests/OpcodeT.cpp +++ b/tests/OpcodeT.cpp @@ -7,12 +7,13 @@ #include "sfizz/Region.h" #include "catch2/catch.hpp" using namespace Catch::literals; +using namespace sfz; TEST_CASE("[Opcode] Construction") { SECTION("Normal construction") { - sfz::Opcode opcode { "sample", "dummy" }; + Opcode opcode { "sample", "dummy" }; REQUIRE(opcode.opcode == "sample"); REQUIRE(opcode.lettersOnlyHash == hash("sample")); REQUIRE(opcode.parameters.empty()); @@ -21,7 +22,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Normal construction with underscore") { - sfz::Opcode opcode { "sample_underscore", "dummy" }; + Opcode opcode { "sample_underscore", "dummy" }; REQUIRE(opcode.opcode == "sample_underscore"); REQUIRE(opcode.lettersOnlyHash == hash("sample_underscore")); REQUIRE(opcode.parameters.empty()); @@ -30,7 +31,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Normal construction with ampersand") { - sfz::Opcode opcode { "sample&_ampersand", "dummy" }; + Opcode opcode { "sample&_ampersand", "dummy" }; REQUIRE(opcode.opcode == "sample&_ampersand"); REQUIRE(opcode.lettersOnlyHash == hash("sample_ampersand")); REQUIRE(opcode.parameters.empty()); @@ -39,7 +40,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Normal construction with multiple ampersands") { - sfz::Opcode opcode { "&sample&_ampersand&", "dummy" }; + Opcode opcode { "&sample&_ampersand&", "dummy" }; REQUIRE(opcode.opcode == "&sample&_ampersand&"); REQUIRE(opcode.lettersOnlyHash == hash("sample_ampersand")); REQUIRE(opcode.parameters.empty()); @@ -48,7 +49,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Parameterized opcode") { - sfz::Opcode opcode { "sample123", "dummy" }; + Opcode opcode { "sample123", "dummy" }; REQUIRE(opcode.opcode == "sample123"); REQUIRE(opcode.lettersOnlyHash == hash("sample&")); REQUIRE(opcode.value == "dummy"); @@ -58,7 +59,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Parameterized opcode with ampersand") { - sfz::Opcode opcode { "sample&123", "dummy" }; + Opcode opcode { "sample&123", "dummy" }; REQUIRE(opcode.opcode == "sample&123"); REQUIRE(opcode.lettersOnlyHash == hash("sample&")); REQUIRE(opcode.value == "dummy"); @@ -68,7 +69,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Parameterized opcode with underscore") { - sfz::Opcode opcode { "sample_underscore123", "dummy" }; + Opcode opcode { "sample_underscore123", "dummy" }; REQUIRE(opcode.opcode == "sample_underscore123"); REQUIRE(opcode.lettersOnlyHash == hash("sample_underscore&")); REQUIRE(opcode.value == "dummy"); @@ -77,7 +78,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Parameterized opcode within the opcode") { - sfz::Opcode opcode { "sample1_underscore", "dummy" }; + Opcode opcode { "sample1_underscore", "dummy" }; REQUIRE(opcode.opcode == "sample1_underscore"); REQUIRE(opcode.lettersOnlyHash == hash("sample&_underscore")); REQUIRE(opcode.value == "dummy"); @@ -86,7 +87,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Parameterized opcode within the opcode") { - sfz::Opcode opcode { "sample123_underscore", "dummy" }; + Opcode opcode { "sample123_underscore", "dummy" }; REQUIRE(opcode.opcode == "sample123_underscore"); REQUIRE(opcode.lettersOnlyHash == hash("sample&_underscore")); REQUIRE(opcode.value == "dummy"); @@ -96,7 +97,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Parameterized opcode within the opcode twice") { - sfz::Opcode opcode { "sample123_double44_underscore", "dummy" }; + Opcode opcode { "sample123_double44_underscore", "dummy" }; REQUIRE(opcode.opcode == "sample123_double44_underscore"); REQUIRE(opcode.lettersOnlyHash == hash("sample&_double&_underscore")); REQUIRE(opcode.value == "dummy"); @@ -108,7 +109,7 @@ TEST_CASE("[Opcode] Construction") SECTION("Parameterized opcode within the opcode twice, with a back parameter") { - sfz::Opcode opcode { "sample123_double44_underscore23", "dummy" }; + Opcode opcode { "sample123_double44_underscore23", "dummy" }; REQUIRE(opcode.opcode == "sample123_double44_underscore23"); REQUIRE(opcode.lettersOnlyHash == hash("sample&_double&_underscore&")); REQUIRE(opcode.value == "dummy"); @@ -119,86 +120,86 @@ TEST_CASE("[Opcode] Construction") TEST_CASE("[Opcode] Note values") { - auto noteValue = sfz::readNoteValue("c-1"); + auto noteValue = readNoteValue("c-1"); REQUIRE(noteValue); REQUIRE(*noteValue == 0); - noteValue = sfz::readNoteValue("C-1"); + noteValue = readNoteValue("C-1"); REQUIRE(noteValue); REQUIRE(*noteValue == 0); - noteValue = sfz::readNoteValue("g9"); + noteValue = readNoteValue("g9"); REQUIRE(noteValue); REQUIRE(*noteValue == 127); - noteValue = sfz::readNoteValue("G9"); + noteValue = readNoteValue("G9"); REQUIRE(noteValue); REQUIRE(*noteValue == 127); - noteValue = sfz::readNoteValue("c#4"); + noteValue = readNoteValue("c#4"); REQUIRE(noteValue); REQUIRE(*noteValue == 61); - noteValue = sfz::readNoteValue(u8"c♯4"); + noteValue = readNoteValue(u8"c♯4"); REQUIRE(noteValue); REQUIRE(*noteValue == 61); - noteValue = sfz::readNoteValue("C#4"); + noteValue = readNoteValue("C#4"); REQUIRE(noteValue); REQUIRE(*noteValue == 61); - noteValue = sfz::readNoteValue(u8"C♯4"); + noteValue = readNoteValue(u8"C♯4"); REQUIRE(noteValue); REQUIRE(*noteValue == 61); - noteValue = sfz::readNoteValue("e#4"); + noteValue = readNoteValue("e#4"); REQUIRE(!noteValue); - noteValue = sfz::readNoteValue(u8"e♯4"); + noteValue = readNoteValue(u8"e♯4"); REQUIRE(!noteValue); - noteValue = sfz::readNoteValue("E#4"); + noteValue = readNoteValue("E#4"); REQUIRE(!noteValue); - noteValue = sfz::readNoteValue(u8"E♯4"); + noteValue = readNoteValue(u8"E♯4"); REQUIRE(!noteValue); - noteValue = sfz::readNoteValue("db4"); + noteValue = readNoteValue("db4"); REQUIRE(noteValue); REQUIRE(*noteValue == 61); - noteValue = sfz::readNoteValue(u8"d♭4"); + noteValue = readNoteValue(u8"d♭4"); REQUIRE(noteValue); REQUIRE(*noteValue == 61); - noteValue = sfz::readNoteValue("Db4"); + noteValue = readNoteValue("Db4"); REQUIRE(noteValue); REQUIRE(*noteValue == 61); - noteValue = sfz::readNoteValue(u8"D♭4"); + noteValue = readNoteValue(u8"D♭4"); REQUIRE(noteValue); REQUIRE(*noteValue == 61); - noteValue = sfz::readNoteValue("fb4"); + noteValue = readNoteValue("fb4"); REQUIRE(!noteValue); - noteValue = sfz::readNoteValue(u8"f♭4"); + noteValue = readNoteValue(u8"f♭4"); REQUIRE(!noteValue); - noteValue = sfz::readNoteValue("Fb4"); + noteValue = readNoteValue("Fb4"); REQUIRE(!noteValue); - noteValue = sfz::readNoteValue(u8"F♭4"); + noteValue = readNoteValue(u8"F♭4"); REQUIRE(!noteValue); } TEST_CASE("[Opcode] Categories") { - REQUIRE(sfz::Opcode("sample", "").category == sfz::kOpcodeNormal); - REQUIRE(sfz::Opcode("amplitude_oncc11", "").category == sfz::kOpcodeOnCcN); - REQUIRE(sfz::Opcode("cutoff_cc22", "").category == sfz::kOpcodeOnCcN); - REQUIRE(sfz::Opcode("lfo01_pitch_curvecc33", "").category == sfz::kOpcodeCurveCcN); - REQUIRE(sfz::Opcode("pan_stepcc44", "").category == sfz::kOpcodeStepCcN); - REQUIRE(sfz::Opcode("noise_level_smoothcc55", "").category == sfz::kOpcodeSmoothCcN); + REQUIRE(Opcode("sample", "").category == kOpcodeNormal); + REQUIRE(Opcode("amplitude_oncc11", "").category == kOpcodeOnCcN); + REQUIRE(Opcode("cutoff_cc22", "").category == kOpcodeOnCcN); + REQUIRE(Opcode("lfo01_pitch_curvecc33", "").category == kOpcodeCurveCcN); + REQUIRE(Opcode("pan_stepcc44", "").category == kOpcodeStepCcN); + REQUIRE(Opcode("noise_level_smoothcc55", "").category == kOpcodeSmoothCcN); } TEST_CASE("[Opcode] Derived names") { - REQUIRE(sfz::Opcode("sample", "").getDerivedName(sfz::kOpcodeNormal) == "sample"); - REQUIRE(sfz::Opcode("cutoff_cc22", "").getDerivedName(sfz::kOpcodeNormal) == "cutoff"); - REQUIRE(sfz::Opcode("lfo01_pitch_curvecc33", "").getDerivedName(sfz::kOpcodeOnCcN) == "lfo01_pitch_oncc33"); - REQUIRE(sfz::Opcode("pan_stepcc44", "").getDerivedName(sfz::kOpcodeCurveCcN) == "pan_curvecc44"); - REQUIRE(sfz::Opcode("noise_level_smoothcc55", "").getDerivedName(sfz::kOpcodeStepCcN) == "noise_level_stepcc55"); - REQUIRE(sfz::Opcode("sample", "").getDerivedName(sfz::kOpcodeSmoothCcN, 66) == "sample_smoothcc66"); + REQUIRE(Opcode("sample", "").getDerivedName(kOpcodeNormal) == "sample"); + REQUIRE(Opcode("cutoff_cc22", "").getDerivedName(kOpcodeNormal) == "cutoff"); + REQUIRE(Opcode("lfo01_pitch_curvecc33", "").getDerivedName(kOpcodeOnCcN) == "lfo01_pitch_oncc33"); + REQUIRE(Opcode("pan_stepcc44", "").getDerivedName(kOpcodeCurveCcN) == "pan_curvecc44"); + REQUIRE(Opcode("noise_level_smoothcc55", "").getDerivedName(kOpcodeStepCcN) == "noise_level_stepcc55"); + REQUIRE(Opcode("sample", "").getDerivedName(kOpcodeSmoothCcN, 66) == "sample_smoothcc66"); } TEST_CASE("[Opcode] Normalization") { // *_ccN - REQUIRE(sfz::Opcode("foo_cc7", "").cleanUp(sfz::kOpcodeScopeRegion).opcode == "foo_oncc7"); - REQUIRE(sfz::Opcode("foo_cc7", "").cleanUp(sfz::kOpcodeScopeControl).opcode == "foo_cc7"); + REQUIRE(Opcode("foo_cc7", "").cleanUp(kOpcodeScopeRegion).opcode == "foo_oncc7"); + REQUIRE(Opcode("foo_cc7", "").cleanUp(kOpcodeScopeControl).opcode == "foo_cc7"); // @@ -274,8 +275,8 @@ TEST_CASE("[Opcode] Normalization") for (auto pair : regionSpecific) { absl::string_view input = pair.first; absl::string_view expected = pair.second; - REQUIRE(sfz::Opcode(input, "").cleanUp(sfz::kOpcodeScopeRegion).opcode == expected); - REQUIRE(sfz::Opcode(input, "").cleanUp(sfz::kOpcodeScopeGeneric).opcode == input); + REQUIRE(Opcode(input, "").cleanUp(kOpcodeScopeRegion).opcode == expected); + REQUIRE(Opcode(input, "").cleanUp(kOpcodeScopeGeneric).opcode == input); } // @@ -288,42 +289,221 @@ TEST_CASE("[Opcode] Normalization") for (auto pair : controlSpecific) { absl::string_view input = pair.first; absl::string_view expected = pair.second; - REQUIRE(sfz::Opcode(input, "").cleanUp(sfz::kOpcodeScopeControl).opcode == expected); - REQUIRE(sfz::Opcode(input, "").cleanUp(sfz::kOpcodeScopeGeneric).opcode == input); + REQUIRE(Opcode(input, "").cleanUp(kOpcodeScopeControl).opcode == expected); + REQUIRE(Opcode(input, "").cleanUp(kOpcodeScopeGeneric).opcode == input); } // case - REQUIRE(sfz::Opcode("SaMpLe", "").cleanUp(sfz::kOpcodeScopeRegion).opcode == "sample"); + REQUIRE(Opcode("SaMpLe", "").cleanUp(kOpcodeScopeRegion).opcode == "sample"); } -TEST_CASE("[Opcode] readOpcode") +TEST_CASE("[Opcode] opcode read (uint8_t)") { - REQUIRE( sfz::readOpcode("16", sfz::Range(0, 100)).value() == 16 ); - REQUIRE( sfz::readOpcode("+16", sfz::Range(0, 100)).value() == 16 ); - REQUIRE( sfz::readOpcode("110", sfz::Range(0, 100)).value() == 100 ); - REQUIRE( sfz::readOpcode("-1", sfz::Range(0, 100)).value() == 0 ); - REQUIRE( sfz::readOpcode("12.5", sfz::Range(-100, 100)).value() == 12 ); - REQUIRE( sfz::readOpcode("+12.5", sfz::Range(-100, 100)).value() == 12 ); - REQUIRE( sfz::readOpcode("-40", sfz::Range(-100, 100)).value() == -40 ); - REQUIRE( sfz::readOpcode("-140", sfz::Range(-100, 100)).value() == -100 ); - REQUIRE( sfz::readOpcode("12.5", sfz::Range(0.0f, 100.0f)).value() == 12.5_a ); - REQUIRE( sfz::readOpcode("+12.5", sfz::Range(0.0f, 100.0f)).value() == 12.5_a ); - REQUIRE( sfz::readOpcode("-22.5", sfz::Range(-20.0f, 100.0f)).value() == -20.0_a ); - REQUIRE( sfz::readOpcode("150.5", sfz::Range(-20.0f, 100.0f)).value() == 100.0_a ); - REQUIRE( sfz::readOpcode("50.25garbage", sfz::Range(-20.0f, 100.0f)).value() == 50.25_a ); - REQUIRE( sfz::readOpcode("50.25garbage", sfz::Range(-20, 100)).value() == 50 ); - REQUIRE( !sfz::readOpcode("garbage50.25", sfz::Range(-20, 100)) ); - REQUIRE( !sfz::readOpcode("garbage", sfz::Range(-20, 100)) ); + SECTION("Basic") + { + Opcode opcode { "", "16" }; + OpcodeSpec spec { 0, Range(0, 100), 0 }; + REQUIRE( opcode.read(spec) == 16); + } + + SECTION("Sign") + { + Opcode opcode { "", "+16" }; + OpcodeSpec spec { 0, Range(0, 100), 0 }; + REQUIRE( opcode.read(spec) == 16); + } + + SECTION("Ignore") + { + Opcode opcode { "", "110" }; + OpcodeSpec spec { 0, Range(0, 100), kIgnoreOOB }; + REQUIRE( !opcode.read(spec) ); + } + + SECTION("Clamp upper") + { + Opcode opcode { "", "110" }; + OpcodeSpec spec { 0, Range(0, 100), kEnforceUpperBound }; + REQUIRE( opcode.read(spec) == 100 ); + } + + SECTION("Clamp lower") + { + Opcode opcode { "", "10" }; + OpcodeSpec spec { 0, Range(20, 100), kEnforceLowerBound }; + REQUIRE( opcode.read(spec) == 20 ); + } + + SECTION("Floating point") + { + Opcode opcode { "", "10.5" }; + OpcodeSpec spec { 0, Range(0, 100), 0 }; + REQUIRE( opcode.read(spec) == 10 ); + } + + SECTION("Text after") + { + Opcode opcode { "", "10garbage" }; + OpcodeSpec spec { 0, Range(20, 100), kEnforceLowerBound }; + REQUIRE( opcode.read(spec) == 20 ); + } + + SECTION("Text before") + { + Opcode opcode { "", "garbage10" }; + OpcodeSpec spec { 0, Range(20, 100), 0 }; + REQUIRE( !opcode.read(spec) ); + } + + SECTION("Can be note") + { + Opcode opcode { "", "c4" }; + OpcodeSpec spec { 0, Range(20, 100), kCanBeNote }; + REQUIRE( opcode.read(spec) == 60 ); + } +} + +TEST_CASE("[Opcode] opcode read (int)") +{ + SECTION("Basic") + { + Opcode opcode { "", "16" }; + OpcodeSpec spec { 0, Range(-100, 100), 0 }; + REQUIRE( opcode.read(spec) == 16); + } + + SECTION("Sign") + { + Opcode opcode { "", "+16" }; + OpcodeSpec spec { 0, Range(-100, 100), 0 }; + REQUIRE( opcode.read(spec) == 16); + } + + SECTION("Sign") + { + Opcode opcode { "", "-16" }; + OpcodeSpec spec { 0, Range(-100, 100), 0 }; + REQUIRE( opcode.read(spec) == -16); + } + + SECTION("Ignore") + { + Opcode opcode { "", "110" }; + OpcodeSpec spec { 0, Range(-100, 100), kIgnoreOOB }; + REQUIRE( !opcode.read(spec) ); + } + + SECTION("Clamp upper") + { + Opcode opcode { "", "110" }; + OpcodeSpec spec { 0, Range(-100, 100), kEnforceUpperBound }; + REQUIRE( opcode.read(spec) == 100 ); + } + + SECTION("Clamp lower") + { + Opcode opcode { "", "-110" }; + OpcodeSpec spec { 0, Range(-100, 100), kEnforceLowerBound }; + REQUIRE( opcode.read(spec) == -100 ); + } + + SECTION("Floating point") + { + Opcode opcode { "", "10.5" }; + OpcodeSpec spec { 0, Range(-100, 100), 0 }; + REQUIRE( opcode.read(spec) == 10 ); + } + + SECTION("Text after") + { + Opcode opcode { "", "10garbage" }; + OpcodeSpec spec { 0, Range(20, 100), kEnforceLowerBound }; + REQUIRE( opcode.read(spec) == 20 ); + } + + SECTION("Text before") + { + Opcode opcode { "", "garbage10" }; + OpcodeSpec spec { 0, Range(20, 100), 0 }; + REQUIRE( !opcode.read(spec) ); + } + + SECTION("Can be note") + { + Opcode opcode { "", "c4" }; + OpcodeSpec spec { 0, Range(20, 100), kCanBeNote }; + REQUIRE( opcode.read(spec) == 60 ); + } +} + + +TEST_CASE("[Opcode] opcode read (float)") +{ + SECTION("Basic") + { + Opcode opcode { "", "16.4" }; + OpcodeSpec spec { 0.0f, Range(-100.0f, 100.0f), 0 }; + REQUIRE( opcode.read(spec) == 16.4_a); + } + + SECTION("Plus sign") + { + Opcode opcode { "", "+16.4" }; + OpcodeSpec spec { 0.0f, Range(-100.0f, 100.0f), 0 }; + REQUIRE( opcode.read(spec) == 16.4_a); + } + + SECTION("Minus sign") + { + Opcode opcode { "", "-16.4" }; + OpcodeSpec spec { 0.0f, Range(-100.0f, 100.0f), 0 }; + REQUIRE( opcode.read(spec) == -16.4_a); + } + + SECTION("Ignore") + { + Opcode opcode { "", "110" }; + OpcodeSpec spec { 0.0f, Range(-100.0f, 100.0f), kIgnoreOOB }; + REQUIRE( !opcode.read(spec) ); + } + + SECTION("Clamp upper") + { + Opcode opcode { "", "110" }; + OpcodeSpec spec { 0.0f, Range(-100.0f, 100.0f), kEnforceUpperBound }; + REQUIRE( opcode.read(spec) == 100.0f ); + } + + SECTION("Clamp lower") + { + Opcode opcode { "", "-110" }; + OpcodeSpec spec { 0.0f, Range(-100.0f, 100.0f), kEnforceLowerBound }; + REQUIRE( opcode.read(spec) == -100.0f ); + } + + SECTION("Text after") + { + Opcode opcode { "", "10.5garbage" }; + OpcodeSpec spec { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; + REQUIRE( opcode.read(spec) == 10.5f ); + } + + SECTION("Text before") + { + Opcode opcode { "", "garbage10" }; + OpcodeSpec spec { 0.0f, Range(0.0f, 100.0f), 0 }; + REQUIRE( !opcode.read(spec) ); + } } TEST_CASE("[Opcode] readBooleanFromOpcode") { - REQUIRE(sfz::readBooleanFromOpcode({"", "1"}) == true); - REQUIRE(sfz::readBooleanFromOpcode({"", "0"}) == false); - REQUIRE(sfz::readBooleanFromOpcode({"", "777"}) == true); - REQUIRE(sfz::readBooleanFromOpcode({"", "on"}) == true); - REQUIRE(sfz::readBooleanFromOpcode({"", "off"}) == false); - REQUIRE(sfz::readBooleanFromOpcode({"", "On"}) == true); - REQUIRE(sfz::readBooleanFromOpcode({"", "oFf"}) == false); + REQUIRE(readBooleanFromOpcode({"", "1"}) == true); + REQUIRE(readBooleanFromOpcode({"", "0"}) == false); + REQUIRE(readBooleanFromOpcode({"", "777"}) == true); + REQUIRE(readBooleanFromOpcode({"", "on"}) == true); + REQUIRE(readBooleanFromOpcode({"", "off"}) == false); + REQUIRE(readBooleanFromOpcode({"", "On"}) == true); + REQUIRE(readBooleanFromOpcode({"", "oFf"}) == false); } diff --git a/tests/RegionValueComputationsT.cpp b/tests/RegionValueComputationsT.cpp index f3b1abca..39412b95 100644 --- a/tests/RegionValueComputationsT.cpp +++ b/tests/RegionValueComputationsT.cpp @@ -299,15 +299,15 @@ TEST_CASE("[Region] rt_decay") region.parseOpcode({ "rt_decay", "10" }); midiState.noteOnEvent(0, 64, 64_norm); midiState.advanceTime(100); - REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume - 1.0f).margin(0.1) ); + REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume.value - 1.0f).margin(0.1) ); region.parseOpcode({ "rt_decay", "20" }); midiState.noteOnEvent(0, 64, 64_norm); midiState.advanceTime(100); - REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume - 2.0f).margin(0.1) ); + REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume.value - 2.0f).margin(0.1) ); region.parseOpcode({ "trigger", "attack" }); midiState.noteOnEvent(0, 64, 64_norm); midiState.advanceTime(100); - REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume).margin(0.1) ); + REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume.value).margin(0.1) ); } TEST_CASE("[Region] Base delay") diff --git a/tests/RegionValuesT.cpp b/tests/RegionValuesT.cpp index f0274fd1..0e2a38c0 100644 --- a/tests/RegionValuesT.cpp +++ b/tests/RegionValuesT.cpp @@ -250,7 +250,7 @@ TEST_CASE("[Values] Count") std::vector expected { "/region0/count,N : { }", "/region1/count,h : { 2 }", - "/region2/count,h : { 0 }", + "/region2/count,N : { }", }; REQUIRE(messageList == expected); } @@ -324,6 +324,7 @@ TEST_CASE("[Values] Loop range") Client client(&messageList); client.setReceiveCallback(&simpleMessageReceiver); synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav sample=kick.wav loop_start=10 loop_end=100 sample=kick.wav loopstart=10 loopend=100 sample=kick.wav loop_start=-1 loopend=-100 @@ -331,10 +332,12 @@ TEST_CASE("[Values] Loop range") synth.dispatchMessage(client, 0, "/region0/loop_range", "", nullptr); synth.dispatchMessage(client, 0, "/region1/loop_range", "", nullptr); synth.dispatchMessage(client, 0, "/region2/loop_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/loop_range", "", nullptr); std::vector expected { - "/region0/loop_range,hh : { 10, 100 }", + "/region0/loop_range,hh : { 0, 44011 }", // Default loop points in the file "/region1/loop_range,hh : { 10, 100 }", - "/region2/loop_range,hh : { 0, 0 }", + "/region2/loop_range,hh : { 10, 100 }", + "/region3/loop_range,hh : { 0, 44011 }", }; REQUIRE(messageList == expected); } @@ -487,7 +490,7 @@ TEST_CASE("[Values] Key range") "/region1/key_range,ii : { 34, 60 }", "/region2/key_range,ii : { 60, 83 }", "/region3/key_range,ii : { 0, 60 }", - "/region4/key_range,ii : { 0, 0 }", + "/region4/key_range,ii : { 0, 127 }", "/region0/pitch_keycenter,i : { 60 }", "/region5/pitch_keycenter,i : { 32 }", // "/region6/pitch_keycenter,i : { 60 }", @@ -497,6 +500,32 @@ TEST_CASE("[Values] Key range") REQUIRE(messageList == expected); } +TEST_CASE("[Values] Triggers on note") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav hikey=-1 + sample=kick.wav key=-1 + sample=kick.wav hikey=-1 lokey=12 + )"); + synth.dispatchMessage(client, 0, "/region0/trigger_on_note", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/trigger_on_note", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/trigger_on_note", "", nullptr); + // TODO: Double check with Sforzando/rgc + synth.dispatchMessage(client, 0, "/region3/trigger_on_note", "", nullptr); + std::vector expected { + "/region0/trigger_on_note,T : { }", + "/region1/trigger_on_note,F : { }", + "/region2/trigger_on_note,F : { }", + "/region3/trigger_on_note,T : { }", + }; + REQUIRE(messageList == expected); +} + TEST_CASE("[Values] Velocity range") { Synth synth; @@ -517,7 +546,7 @@ TEST_CASE("[Values] Velocity range") "/region0/vel_range,ff : { 0, 1 }", "/region1/vel_range,ff : { 0.267717, 0.472441 }", "/region2/vel_range,ff : { 0, 0.472441 }", - "/region3/vel_range,ff : { 0, 0 }", + "/region3/vel_range,ff : { 0, 1 }", }; REQUIRE(messageList == expected); } @@ -542,7 +571,7 @@ TEST_CASE("[Values] Bend range") "/region0/bend_range,ff : { -1, 1 }", "/region1/bend_range,ff : { 0.108778, 0.24417 }", "/region2/bend_range,ff : { -0.108778, 0.108778 }", - "/region3/bend_range,ff : { -1, -1 }", + "/region3/bend_range,ff : { -1, 1 }", }; REQUIRE(messageList == expected); } @@ -572,7 +601,7 @@ TEST_CASE("[Values] CC condition range") "/region1/cc_range1,ff : { 0, 0.425197 }", "/region2/cc_range1,ff : { 0, 0.425197 }", "/region2/cc_range2,ff : { 0.015748, 0.0787402 }", - "/region3/cc_range1,ff : { 0, 0 }", + "/region3/cc_range1,ff : { 0.0787402, 1 }", }; REQUIRE(messageList == expected); } @@ -595,7 +624,7 @@ TEST_CASE("[Values] CC condition range") "/region1/cc_range1,ff : { 0, 0.1 }", "/region2/cc_range1,ff : { 0, 0.1 }", "/region2/cc_range2,ff : { 0.1, 0.2 }", - "/region3/cc_range1,ff : { 0, 0 }", + "/region3/cc_range1,ff : { 0.1, 1 }", }; REQUIRE(messageList == expected); } @@ -618,7 +647,7 @@ TEST_CASE("[Values] CC condition range") "/region1/cc_range1,ff : { 0, 0.1 }", "/region2/cc_range1,ff : { 0, 0.1 }", "/region2/cc_range2,ff : { 0.1, 0.2 }", - "/region3/cc_range1,ff : { 0, 0 }", + "/region3/cc_range1,ff : { 0.1, 1 }", }; REQUIRE(messageList == expected); } @@ -708,19 +737,17 @@ TEST_CASE("[Values] Upswitch") )"); synth.dispatchMessage(client, 0, "/region0/sw_up", "", nullptr); synth.dispatchMessage(client, 0, "/region1/sw_up", "", nullptr); - // TODO: activate for the new region parser; ignore oob - // synth.dispatchMessage(client, 0, "/region2/sw_up", "", nullptr); - // synth.dispatchMessage(client, 0, "/region3/sw_up", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/sw_up", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/sw_up", "", nullptr); synth.dispatchMessage(client, 0, "/region4/sw_up", "", nullptr); - // TODO: activate for the new region parser; ignore the second value - // synth.dispatchMessage(client, 0, "/region5/sw_up", "", nullptr); + synth.dispatchMessage(client, 0, "/region5/sw_up", "", nullptr); std::vector expected { "/region0/sw_up,N : { }", "/region1/sw_up,i : { 16 }", - // "/region2/sw_up,N : { }", - // "/region3/sw_up,N : { }", + "/region2/sw_up,N : { }", + "/region3/sw_up,N : { }", "/region4/sw_up,i : { 60 }", - // "/region5/sw_up,i : { 64 }", + "/region5/sw_up,i : { 64 }", }; REQUIRE(messageList == expected); } @@ -741,19 +768,17 @@ TEST_CASE("[Values] Downswitch") )"); synth.dispatchMessage(client, 0, "/region0/sw_down", "", nullptr); synth.dispatchMessage(client, 0, "/region1/sw_down", "", nullptr); - // TODO: activate for the new region parser; ignore oob - // synth.dispatchMessage(client, 0, "/region2/sw_down", "", nullptr); - // synth.dispatchMessage(client, 0, "/region3/sw_down", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/sw_down", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/sw_down", "", nullptr); synth.dispatchMessage(client, 0, "/region4/sw_down", "", nullptr); - // TODO: activate for the new region parser; ignore the second value - // synth.dispatchMessage(client, 0, "/region5/sw_down", "", nullptr); + synth.dispatchMessage(client, 0, "/region5/sw_down", "", nullptr); std::vector expected { "/region0/sw_down,N : { }", "/region1/sw_down,i : { 16 }", - // "/region2/sw_down,N : { }", - // "/region3/sw_down,N : { }", + "/region2/sw_down,N : { }", + "/region3/sw_down,N : { }", "/region4/sw_down,i : { 60 }", - // "/region5/sw_down,i : { 64 }", + "/region5/sw_down,i : { 64 }", }; REQUIRE(messageList == expected); } @@ -774,19 +799,17 @@ TEST_CASE("[Values] Previous keyswitch") )"); synth.dispatchMessage(client, 0, "/region0/sw_previous", "", nullptr); synth.dispatchMessage(client, 0, "/region1/sw_previous", "", nullptr); - // TODO: activate for the new region parser; ignore oob - // synth.dispatchMessage(client, 0, "/region2/sw_previous", "", nullptr); - // synth.dispatchMessage(client, 0, "/region3/sw_previous", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/sw_previous", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/sw_previous", "", nullptr); synth.dispatchMessage(client, 0, "/region4/sw_previous", "", nullptr); - // TODO: activate for the new region parser; ignore the second value - // synth.dispatchMessage(client, 0, "/region5/sw_previous", "", nullptr); + synth.dispatchMessage(client, 0, "/region5/sw_previous", "", nullptr); std::vector expected { "/region0/sw_previous,N : { }", "/region1/sw_previous,i : { 16 }", - // "/region2/sw_previous,N : { }", - // "/region3/sw_previous,N : { }", + "/region2/sw_previous,N : { }", + "/region3/sw_previous,N : { }", "/region4/sw_previous,i : { 60 }", - // "/region5/sw_previous,i : { 64 }", + "/region5/sw_previous,i : { 64 }", }; REQUIRE(messageList == expected); } @@ -838,7 +861,7 @@ TEST_CASE("[Values] Aftertouch range") "/region0/chanaft_range,ii : { 0, 127 }", "/region1/chanaft_range,ii : { 34, 60 }", "/region2/chanaft_range,ii : { 0, 60 }", - "/region3/chanaft_range,ii : { 0, 0 }", + "/region3/chanaft_range,ii : { 20, 127 }", "/region4/chanaft_range,ii : { 10, 10 }", }; REQUIRE(messageList == expected); @@ -894,7 +917,7 @@ TEST_CASE("[Values] Rand range") "/region0/rand_range,ff : { 0, 1 }", "/region1/rand_range,ff : { 0.2, 0.4 }", "/region2/rand_range,ff : { 0, 0.4 }", - "/region3/rand_range,ff : { 0, 0 }", + "/region3/rand_range,ff : { 0.2, 1 }", "/region4/rand_range,ff : { 0.1, 0.1 }", }; REQUIRE(messageList == expected); @@ -1582,16 +1605,15 @@ TEST_CASE("[Values] Crossfade key range") )"); synth.dispatchMessage(client, 0, "/region0/xfin_key_range", "", nullptr); synth.dispatchMessage(client, 0, "/region1/xfin_key_range", "", nullptr); - // TODO: activate for the new region parser ; parse note value - // synth.dispatchMessage(client, 0, "/region2/xfin_key_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/xfin_key_range", "", nullptr); synth.dispatchMessage(client, 0, "/region3/xfin_key_range", "", nullptr); synth.dispatchMessage(client, 0, "/region4/xfin_key_range", "", nullptr); std::vector expected { "/region0/xfin_key_range,ii : { 0, 0 }", "/region1/xfin_key_range,ii : { 10, 40 }", - // "/region2/xfin_key_range,ii : { 60, 83 }", + "/region2/xfin_key_range,ii : { 60, 83 }", "/region3/xfin_key_range,ii : { 0, 40 }", - "/region4/xfin_key_range,ii : { 10, 127 }", + "/region4/xfin_key_range,ii : { 10, 10 }", }; REQUIRE(messageList == expected); } @@ -1607,15 +1629,14 @@ TEST_CASE("[Values] Crossfade key range") )"); synth.dispatchMessage(client, 0, "/region0/xfout_key_range", "", nullptr); synth.dispatchMessage(client, 0, "/region1/xfout_key_range", "", nullptr); - // TODO: activate for the new region parser ; parse note value - // synth.dispatchMessage(client, 0, "/region2/xfout_key_range", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/xfout_key_range", "", nullptr); synth.dispatchMessage(client, 0, "/region3/xfout_key_range", "", nullptr); synth.dispatchMessage(client, 0, "/region4/xfout_key_range", "", nullptr); std::vector expected { "/region0/xfout_key_range,ii : { 127, 127 }", "/region1/xfout_key_range,ii : { 10, 40 }", - // "/region2/xfout_key_range,ii : { 60, 83 }", - "/region3/xfout_key_range,ii : { 0, 40 }", + "/region2/xfout_key_range,ii : { 60, 83 }", + "/region3/xfout_key_range,ii : { 40, 40 }", "/region4/xfout_key_range,ii : { 10, 127 }", }; REQUIRE(messageList == expected); @@ -1968,13 +1989,13 @@ TEST_CASE("[Values] Pitch/Tune") sample=kick.wav pitch=4.2 sample=kick.wav tune=-200 )"); - synth.dispatchMessage(client, 0, "/region0/tune", "", nullptr); - synth.dispatchMessage(client, 0, "/region1/tune", "", nullptr); - synth.dispatchMessage(client, 0, "/region2/tune", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/pitch", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/pitch", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/pitch", "", nullptr); std::vector expected { - "/region0/tune,f : { 0 }", - "/region1/tune,f : { 4.2 }", - "/region2/tune,f : { -200 }", + "/region0/pitch,f : { 0 }", + "/region1/pitch,f : { 4.2 }", + "/region2/pitch,f : { -200 }", }; REQUIRE(messageList == expected); } @@ -1983,16 +2004,16 @@ TEST_CASE("[Values] Pitch/Tune") { synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( sample=kick.wav - sample=kick.wav tune_oncc42=4.2 + sample=kick.wav pitch_oncc42=4.2 sample=kick.wav pitch_oncc2=-10 )"); - synth.dispatchMessage(client, 0, "/region0/tune_cc42", "", nullptr); - synth.dispatchMessage(client, 0, "/region1/tune_cc42", "", nullptr); - synth.dispatchMessage(client, 0, "/region2/tune_cc2", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/pitch_cc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/pitch_cc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/pitch_cc2", "", nullptr); std::vector expected { - "/region0/tune_cc42,N : { }", - "/region1/tune_cc42,f : { 4.2 }", - "/region2/tune_cc2,f : { -10 }", + "/region0/pitch_cc42,N : { }", + "/region1/pitch_cc42,f : { 4.2 }", + "/region2/pitch_cc2,f : { -10 }", }; REQUIRE(messageList == expected); } @@ -2001,33 +2022,33 @@ TEST_CASE("[Values] Pitch/Tune") { synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( sample=kick.wav - sample=kick.wav tune_stepcc42=4.2 - sample=kick.wav tune_smoothcc42=4 - sample=kick.wav tune_curvecc42=2 - sample=kick.wav tune_stepcc42=-1 - sample=kick.wav tune_smoothcc42=-4 - sample=kick.wav tune_curvecc42=300 + sample=kick.wav pitch_stepcc42=4.2 + sample=kick.wav pitch_smoothcc42=4 + sample=kick.wav pitch_curvecc42=2 + sample=kick.wav pitch_stepcc42=-1 + sample=kick.wav pitch_smoothcc42=-4 + sample=kick.wav pitch_curvecc42=300 )"); - synth.dispatchMessage(client, 0, "/region0/tune_stepcc42", "", nullptr); - synth.dispatchMessage(client, 0, "/region0/tune_smoothcc42", "", nullptr); - synth.dispatchMessage(client, 0, "/region0/tune_curvecc42", "", nullptr); - synth.dispatchMessage(client, 0, "/region1/tune_stepcc42", "", nullptr); - synth.dispatchMessage(client, 0, "/region2/tune_smoothcc42", "", nullptr); - synth.dispatchMessage(client, 0, "/region3/tune_curvecc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/pitch_stepcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/pitch_smoothcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/pitch_curvecc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/pitch_stepcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/pitch_smoothcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/pitch_curvecc42", "", nullptr); // TODO: activate for the new region parser ; ignore oob - // synth.dispatchMessage(client, 0, "/region4/tune_stepcc42", "", nullptr); - // synth.dispatchMessage(client, 0, "/region5/tune_smoothcc42", "", nullptr); - // synth.dispatchMessage(client, 0, "/region6/tune_curvecc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region4/pitch_stepcc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region5/pitch_smoothcc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region6/pitch_curvecc42", "", nullptr); std::vector expected { - "/region0/tune_stepcc42,N : { }", - "/region0/tune_smoothcc42,N : { }", - "/region0/tune_curvecc42,N : { }", - "/region1/tune_stepcc42,f : { 4.2 }", - "/region2/tune_smoothcc42,i : { 4 }", - "/region3/tune_curvecc42,i : { 2 }", - // "/region4/tune_stepcc42,N : { }", - // "/region5/tune_smoothcc42,N : { }", - // "/region6/tune_curvecc42,N : { }", + "/region0/pitch_stepcc42,N : { }", + "/region0/pitch_smoothcc42,N : { }", + "/region0/pitch_curvecc42,N : { }", + "/region1/pitch_stepcc42,f : { 4.2 }", + "/region2/pitch_smoothcc42,i : { 4 }", + "/region3/pitch_curvecc42,i : { 2 }", + // "/region4/pitch_stepcc42,N : { }", + // "/region5/pitch_smoothcc42,N : { }", + // "/region6/pitch_curvecc42,N : { }", }; REQUIRE(messageList == expected); } @@ -2043,26 +2064,26 @@ TEST_CASE("[Values] Pitch/Tune") sample=kick.wav pitch_smoothcc42=-4 sample=kick.wav pitch_curvecc42=300 )"); - synth.dispatchMessage(client, 0, "/region0/tune_stepcc42", "", nullptr); - synth.dispatchMessage(client, 0, "/region0/tune_smoothcc42", "", nullptr); - synth.dispatchMessage(client, 0, "/region0/tune_curvecc42", "", nullptr); - synth.dispatchMessage(client, 0, "/region1/tune_stepcc42", "", nullptr); - synth.dispatchMessage(client, 0, "/region2/tune_smoothcc42", "", nullptr); - synth.dispatchMessage(client, 0, "/region3/tune_curvecc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/pitch_stepcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/pitch_smoothcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/pitch_curvecc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/pitch_stepcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/pitch_smoothcc42", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/pitch_curvecc42", "", nullptr); // TODO: activate for the new region parser ; ignore oob - // synth.dispatchMessage(client, 0, "/region4/tune_stepcc42", "", nullptr); - // synth.dispatchMessage(client, 0, "/region5/tune_smoothcc42", "", nullptr); - // synth.dispatchMessage(client, 0, "/region6/tune_curvecc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region4/pitch_stepcc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region5/pitch_smoothcc42", "", nullptr); + // synth.dispatchMessage(client, 0, "/region6/pitch_curvecc42", "", nullptr); std::vector expected { - "/region0/tune_stepcc42,N : { }", - "/region0/tune_smoothcc42,N : { }", - "/region0/tune_curvecc42,N : { }", - "/region1/tune_stepcc42,f : { 4.2 }", - "/region2/tune_smoothcc42,i : { 4 }", - "/region3/tune_curvecc42,i : { 2 }", - // "/region4/tune_stepcc42,N : { }", - // "/region5/tune_smoothcc42,N : { }", - // "/region6/tune_curvecc42,N : { }", + "/region0/pitch_stepcc42,N : { }", + "/region0/pitch_smoothcc42,N : { }", + "/region0/pitch_curvecc42,N : { }", + "/region1/pitch_stepcc42,f : { 4.2 }", + "/region2/pitch_smoothcc42,i : { 4 }", + "/region3/pitch_curvecc42,i : { 2 }", + // "/region4/pitch_stepcc42,N : { }", + // "/region5/pitch_smoothcc42,N : { }", + // "/region6/pitch_curvecc42,N : { }", }; REQUIRE(messageList == expected); } @@ -2093,17 +2114,17 @@ TEST_CASE("[Values] Bend behavior") synth.dispatchMessage(client, 0, "/region2/bend_step", "", nullptr); synth.dispatchMessage(client, 0, "/region2/bend_smooth", "", nullptr); std::vector expected { - "/region0/bend_up,i : { 200 }", - "/region0/bend_down,i : { -200 }", - "/region0/bend_step,i : { 1 }", + "/region0/bend_up,f : { 200 }", + "/region0/bend_down,f : { -200 }", + "/region0/bend_step,f : { 1 }", "/region0/bend_smooth,i : { 0 }", - "/region1/bend_up,i : { 100 }", - "/region1/bend_down,i : { -400 }", - "/region1/bend_step,i : { 10 }", + "/region1/bend_up,f : { 100 }", + "/region1/bend_down,f : { -400 }", + "/region1/bend_step,f : { 10 }", "/region1/bend_smooth,i : { 10 }", - "/region2/bend_up,i : { -100 }", - "/region2/bend_down,i : { 400 }", - "/region2/bend_step,i : { 1 }", + "/region2/bend_up,f : { -100 }", + "/region2/bend_down,f : { 400 }", + "/region2/bend_step,f : { 1 }", "/region2/bend_smooth,i : { 0 }", }; REQUIRE(messageList == expected); @@ -2162,7 +2183,7 @@ TEST_CASE("[Values] ampeg") "/region0/ampeg_release,f : { 0.001 }", "/region0/ampeg_start,f : { 0 }", "/region0/ampeg_sustain,f : { 100 }", - "/region0/ampeg_depth,i : { 0 }", + "/region0/ampeg_depth,f : { 0 }", "/region1/ampeg_attack,f : { 1 }", "/region1/ampeg_delay,f : { 2 }", "/region1/ampeg_decay,f : { 3 }", @@ -2170,7 +2191,7 @@ TEST_CASE("[Values] ampeg") "/region1/ampeg_release,f : { 5 }", "/region1/ampeg_start,f : { 6 }", "/region1/ampeg_sustain,f : { 7 }", - "/region1/ampeg_depth,i : { 0 }", + "/region1/ampeg_depth,f : { 0 }", // "/region2/ampeg_attack,f : { 0 }", // "/region2/ampeg_delay,f : { 0 }", // "/region2/ampeg_decay,f : { 0 }", @@ -2178,7 +2199,7 @@ TEST_CASE("[Values] ampeg") // "/region2/ampeg_release,f : { 0.001 }", // "/region2/ampeg_start,f : { 0 }", // "/region2/ampeg_sustain,f : { 100 }", - // "/region2/ampeg_depth,i : { 0 }", + // "/region2/ampeg_depth,f : { 0 }", }; REQUIRE(messageList == expected); } @@ -2213,14 +2234,14 @@ TEST_CASE("[Values] ampeg") "/region0/ampeg_vel2hold,f : { 0 }", "/region0/ampeg_vel2release,f : { 0 }", "/region0/ampeg_vel2sustain,f : { 0 }", - "/region0/ampeg_vel2depth,i : { 0 }", + "/region0/ampeg_vel2depth,f : { 0 }", "/region1/ampeg_vel2attack,f : { 1 }", "/region1/ampeg_vel2delay,f : { 2 }", "/region1/ampeg_vel2decay,f : { 3 }", "/region1/ampeg_vel2hold,f : { 4 }", "/region1/ampeg_vel2release,f : { 5 }", "/region1/ampeg_vel2sustain,f : { 7 }", - "/region1/ampeg_vel2depth,i : { 0 }", + "/region1/ampeg_vel2depth,f : { 0 }", }; REQUIRE(messageList == expected); } @@ -2420,18 +2441,102 @@ TEST_CASE("[Values] Oscillator phase") )"); synth.dispatchMessage(client, 0, "/region0/oscillator_phase", "", nullptr); synth.dispatchMessage(client, 0, "/region1/oscillator_phase", "", nullptr); - // TODO: activate for the new region parser ; properly wrap - // synth.dispatchMessage(client, 0, "/region2/oscillator_phase", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/oscillator_phase", "", nullptr); synth.dispatchMessage(client, 0, "/region3/oscillator_phase", "", nullptr); std::vector expected { "/region0/oscillator_phase,f : { 0 }", "/region1/oscillator_phase,f : { 0.1 }", - // "/region2/oscillator_phase,f : { 0.1 }", + "/region2/oscillator_phase,f : { 0.1 }", "/region3/oscillator_phase,f : { -1 }", }; REQUIRE(messageList == expected); } +TEST_CASE("[Values] Oscillator quality") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav oscillator_quality=2 + sample=kick.wav oscillator_quality=0 oscillator_quality=-2 + )"); + synth.dispatchMessage(client, 0, "/region0/oscillator_quality", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/oscillator_quality", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/oscillator_quality", "", nullptr); + std::vector expected { + "/region0/oscillator_quality,N : { }", + "/region1/oscillator_quality,i : { 2 }", + "/region2/oscillator_quality,i : { 0 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Oscillator mode/multi") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav oscillator_mode=2 + sample=kick.wav oscillator_mode=1 oscillator_mode=-2 + sample=kick.wav oscillator_multi=9 + sample=kick.wav oscillator_multi=-2 + )"); + synth.dispatchMessage(client, 0, "/region0/oscillator_mode", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/oscillator_mode", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/oscillator_mode", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/oscillator_multi", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/oscillator_multi", "", nullptr); + synth.dispatchMessage(client, 0, "/region4/oscillator_multi", "", nullptr); + std::vector expected { + "/region0/oscillator_mode,i : { 0 }", + "/region1/oscillator_mode,i : { 2 }", + "/region2/oscillator_mode,i : { 1 }", + "/region0/oscillator_multi,i : { 1 }", + "/region3/oscillator_multi,i : { 9 }", + "/region4/oscillator_multi,i : { 1 }", + }; + REQUIRE(messageList == expected); +} + +TEST_CASE("[Values] Oscillator detune/mod depth") +{ + Synth synth; + std::vector messageList; + Client client(&messageList); + client.setReceiveCallback(&simpleMessageReceiver); + + synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( + sample=kick.wav + sample=kick.wav oscillator_detune=9.2 + sample=kick.wav oscillator_detune=-1200.2 + sample=kick.wav oscillator_mod_depth=1564.75 + sample=kick.wav oscillator_mod_depth=-2.2 + )"); + synth.dispatchMessage(client, 0, "/region0/oscillator_detune", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/oscillator_detune", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/oscillator_detune", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/oscillator_mod_depth", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/oscillator_mod_depth", "", nullptr); + synth.dispatchMessage(client, 0, "/region4/oscillator_mod_depth", "", nullptr); + std::vector expected { + "/region0/oscillator_detune,f : { 0 }", + "/region1/oscillator_detune,f : { 9.2 }", + "/region2/oscillator_detune,f : { -1200.2 }", + "/region0/oscillator_mod_depth,f : { 0 }", + "/region3/oscillator_mod_depth,f : { 1564.75 }", + "/region4/oscillator_mod_depth,f : { 0 }", + }; + REQUIRE(messageList == expected); +} + TEST_CASE("[Values] Effect sends") { Synth synth; diff --git a/tests/SynthT.cpp b/tests/SynthT.cpp index b9bf7ab8..fa5cb076 100644 --- a/tests/SynthT.cpp +++ b/tests/SynthT.cpp @@ -572,14 +572,14 @@ TEST_CASE("[Synth] sample quality") // default sample quality synth.noteOn(0, 60, 100); REQUIRE(synth.getNumActiveVoices() == 1); - REQUIRE(synth.getVoiceView(0)->getCurrentSampleQuality() == sfz::Default::sampleQuality); + REQUIRE(synth.getVoiceView(0)->getCurrentSampleQuality() == sfz::Default::sampleQuality.value); synth.allSoundOff(); // default sample quality, freewheeling synth.enableFreeWheeling(); synth.noteOn(0, 60, 100); REQUIRE(synth.getNumActiveVoices() == 1); - REQUIRE(synth.getVoiceView(0)->getCurrentSampleQuality() == sfz::Default::sampleQualityInFreewheelingMode); + REQUIRE(synth.getVoiceView(0)->getCurrentSampleQuality() == sfz::Default::freewheelingQuality); synth.allSoundOff(); synth.disableFreeWheeling(); @@ -1085,7 +1085,7 @@ TEST_CASE("[Synth] Used CCs") locc4=64 hicc67=32 pan_cc5=200 sample=*sine width_cc98=200 sample=*sine position_cc42=200 pitch_oncc56=200 sample=*sine - start_locc44=200 hikey=-1 sample=*sine + start_locc44=120 hikey=-1 sample=*sine )"); auto usedCCs = synth.getUsedCCs(); REQUIRE( usedCCs.test(1) ); diff --git a/tests/TestFiles/note_offset.sfz b/tests/TestFiles/note_offset.sfz deleted file mode 100644 index 40760e49..00000000 --- a/tests/TestFiles/note_offset.sfz +++ /dev/null @@ -1,12 +0,0 @@ - note_offset=1 - key=63 sample=*sine - lokey=50 hikey=55 pitch_keycenter=50 sample=*sine - lokey=40 hikey=44 pitch_keycenter=40 xfin_lokey=36 xfin_hikey=40 xfout_lokey=44 xfout_hikey=48 sample=*sine - note_offset=-1 - key=63 sw_lokey=24 sw_hikey=28 sw_last=25 sw_up=25 sw_down=25 sw_previous=62 sample=*sine - note_offset=1 octave_offset=1 - key=63 sample=*sine - note_offset=-1 octave_offset=-1 - key=63 sample=*sine - // Check that this does not reset either note or octave offset - key=63 sample=*sine From 24f77f46ebcee89014d283ac6064444e7fc735ad Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sun, 22 Nov 2020 20:54:58 +0100 Subject: [PATCH 02/15] Superfluous std::move --- src/sfizz/Region.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index d84fbc52..57848885 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -34,7 +34,7 @@ bool extendIfNecessary(std::vector& vec, unsigned size, unsigned defaultCapac } sfz::Region::Region(int regionNumber, const MidiState& midiState, absl::string_view defaultPath) -: id{regionNumber}, midiState(midiState), defaultPath(std::move(defaultPath)) +: id{regionNumber}, midiState(midiState), defaultPath(defaultPath) { ccSwitched.set(); From 0ab836787f564b3a2e1b714dd13b4fe273aa967e Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 12 Dec 2020 14:34:00 +0100 Subject: [PATCH 03/15] Add new sources to makefile --- common.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/common.mk b/common.mk index 81d513df..ba379cfe 100644 --- a/common.mk +++ b/common.mk @@ -50,6 +50,7 @@ SFIZZ_SOURCES = \ src/sfizz/AudioReader.cpp \ src/sfizz/BeatClock.cpp \ src/sfizz/Curve.cpp \ + src/sfizz/Defaults.cpp \ src/sfizz/effects/Apan.cpp \ src/sfizz/Effects.cpp \ src/sfizz/modulations/ModId.cpp \ From 17594241e7d5d6fca5990e39d576d9f948683070 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Wed, 30 Dec 2020 01:16:39 +0100 Subject: [PATCH 04/15] Read booleans as a template overload --- src/sfizz/Defaults.cpp | 7 +++++++ src/sfizz/Defaults.h | 26 +++++++++++++++----------- src/sfizz/FlexEGDescription.h | 2 +- src/sfizz/Opcode.cpp | 16 ++++++++++++++++ src/sfizz/Range.h | 4 +++- src/sfizz/Region.cpp | 17 +++++------------ src/sfizz/Region.h | 9 ++++----- src/sfizz/effects/Compressor.cpp | 5 ++--- src/sfizz/effects/Gate.cpp | 6 ++---- tests/FilesT.cpp | 20 ++++++++++---------- tests/RegionValuesT.cpp | 4 ++-- 11 files changed, 67 insertions(+), 49 deletions(-) diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp index b7a77769..aa768dd7 100644 --- a/src/sfizz/Defaults.cpp +++ b/src/sfizz/Defaults.cpp @@ -14,6 +14,7 @@ extern const OpcodeSpec sampleEnd { uint32_t_max, Range(0, u extern const OpcodeSpec sampleCount { 0, Range(0, uint32_t_max), 0 }; extern const OpcodeSpec loopRange { 0, Range(0, uint32_t_max), 0 }; extern const OpcodeSpec loopCrossfade { 1e-3, Range(1e-3, 1.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec oscillator { OscillatorEnabled::Auto, Range(OscillatorEnabled::Auto, OscillatorEnabled::On), 0 }; extern const OpcodeSpec oscillatorPhase { 0.0f, Range(0.0f, 1.0f), 0 }; extern const OpcodeSpec oscillatorMode { 0, Range(0, 2), kIgnoreOOB }; extern const OpcodeSpec oscillatorMulti { 1, Range(1, config::oscillatorsPerVoice), kIgnoreOOB }; @@ -37,6 +38,8 @@ extern const OpcodeSpec smoothCC { 0, Range(0, 100), kIgnoreOO extern const OpcodeSpec curveCC { 0, Range(0, 255), kIgnoreOOB }; extern const OpcodeSpec sustainCC { 64, Range(0, 127), kIgnoreOOB }; extern const OpcodeSpec sustainThreshold { 0.0039f, Range(0.0f, 1.0f), kIgnoreOOB }; +extern const OpcodeSpec checkSustain { true, Range(0, 1), 0 }; +extern const OpcodeSpec checkSostenuto { true, Range(0, 1), 0 }; extern const OpcodeSpec bpm { 0.0f, Range(0.0f, 500.0f), kEnforceLowerBound }; extern const OpcodeSpec sequence { 1, Range(1, 100), kIgnoreOOB }; extern const OpcodeSpec volume { 0.0f, Range(-144.0f, 48.0f), 0 }; @@ -57,6 +60,7 @@ extern const OpcodeSpec ampKeytrack { 0.0f, Range(-96.0f, 12.0f), extern const OpcodeSpec ampVeltrack { 100.0f, Range(-100.0f, 100.0f), kIgnoreOOB }; extern const OpcodeSpec ampVelcurve { 0.0f, Range(0.0f, 1.0f), kEnforceLowerBound | kEnforceUpperBound }; extern const OpcodeSpec ampRandom { 0.0f, Range(0.0f, 24.0f), kEnforceLowerBound }; +extern const OpcodeSpec rtDead { false, Range(0, 1), 0 }; extern const OpcodeSpec rtDecay { 0.0f, Range(0.0f, 200.0f), kEnforceLowerBound }; extern const OpcodeSpec filterCutoff { 0.0f, Range(0.0f, 20000.0f), kEnforceLowerBound | kEnforceUpperBound }; extern const OpcodeSpec filterCutoffMod { 0.0f, Range(-12000.0f, 12000.0f), kEnforceLowerBound }; @@ -105,6 +109,7 @@ extern const OpcodeSpec egPercent { 0.0f, Range(0.0f, 100.0f), kEn extern const OpcodeSpec egPercentMod { 0.0f, Range(-100.0f, 100.0f), 0 }; extern const OpcodeSpec egDepth { 0.0f, Range(-12000.0f, 12000.0f), 0 }; extern const OpcodeSpec egVel2Depth { 0.0f, Range(-12000.0f, 12000.0f), 0 }; +extern const OpcodeSpec flexEGAmpeg { false, Range(0, 1), 0 }; extern const OpcodeSpec flexEGDynamic { 0, Range(0, 1), kIgnoreOOB }; extern const OpcodeSpec flexEGSustain { 0, Range(0, 100), kIgnoreOOB }; extern const OpcodeSpec flexEGPointTime { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; @@ -123,6 +128,7 @@ extern const OpcodeSpec distoDepth { 0.0f, Range(0.0f, 100.0f), kE extern const OpcodeSpec distoStages { 1, Range(1, maxDistoStages), kEnforceLowerBound }; extern const OpcodeSpec compAttack { 0.005f, Range(0.0f, 10.0f), kEnforceLowerBound }; extern const OpcodeSpec compRelease { 0.05f, Range(0.0f, 10.0f), kEnforceLowerBound }; +extern const OpcodeSpec compSTLink { false, Range(0, 1), 0 }; extern const OpcodeSpec compThreshold { 0.0f, Range(-100.0f, 0.0f), kIgnoreOOB }; extern const OpcodeSpec compRatio { 1.0f, Range(1.0f, 50.0f), kIgnoreOOB }; extern const OpcodeSpec compGain { 0.0f, Range(-100.0f, 100.0f), 0 }; @@ -130,6 +136,7 @@ extern const OpcodeSpec fverbSize { 0.0f, Range(0.0f, 100.0f), kEn extern const OpcodeSpec fverbPredelay { 0.0f, Range(0.0f, 10.0f), kEnforceLowerBound }; extern const OpcodeSpec fverbTone { 100.0f, Range(0.0f, 100.0f), kIgnoreOOB }; extern const OpcodeSpec fverbDamp { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; +extern const OpcodeSpec gateSTLink { false, Range(0, 1), 0 }; extern const OpcodeSpec gateAttack { 0.005f, Range(0.0f, 10.0f), kEnforceLowerBound }; extern const OpcodeSpec gateRelease { 0.05f, Range(0.0f, 10.0f), kEnforceLowerBound }; extern const OpcodeSpec gateHold { 0.0f, Range(0.0f, 10.0f), kEnforceLowerBound }; diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 899094d1..9025265e 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -29,16 +29,18 @@ #include #include -enum class SfzTrigger { attack, release, release_key, first, legato }; -enum class SfzLoopMode { no_loop, one_shot, loop_continuous, loop_sustain }; -enum class SfzOffMode { fast, normal, time }; -enum class SfzVelocityOverride { current, previous }; -enum class SfzCrossfadeCurve { gain, power }; -enum class SfzSelfMask { mask, dontMask }; +enum class SfzTrigger { attack = 0, release, release_key, first, legato }; +enum class SfzLoopMode { no_loop = 0, one_shot, loop_continuous, loop_sustain }; +enum class SfzOffMode { fast = 0, normal, time }; +enum class SfzVelocityOverride { current = 0, previous }; +enum class SfzCrossfadeCurve { gain = 0, power }; +enum class SfzSelfMask { mask = 0, dontMask }; namespace sfz { +enum class OscillatorEnabled { Auto = -1, Off = 0, On = 1 }; + enum OpcodeFlags : int { kIgnoreOOB = 1, kEnforceLowerBound = 1 << 1, @@ -66,6 +68,7 @@ namespace Default extern const OpcodeSpec loopRange; extern const OpcodeSpec loopCrossfade; extern const OpcodeSpec oscillatorPhase; + extern const OpcodeSpec oscillator; extern const OpcodeSpec oscillatorMode; extern const OpcodeSpec oscillatorMulti; extern const OpcodeSpec oscillatorDetune; @@ -87,6 +90,8 @@ namespace Default extern const OpcodeSpec curveCC; extern const OpcodeSpec smoothCC; extern const OpcodeSpec sustainCC; + extern const OpcodeSpec checkSustain; + extern const OpcodeSpec checkSostenuto; extern const OpcodeSpec sustainThreshold; extern const OpcodeSpec bpm; extern const OpcodeSpec sequence; @@ -108,6 +113,7 @@ namespace Default extern const OpcodeSpec ampVeltrack; extern const OpcodeSpec ampVelcurve; extern const OpcodeSpec ampRandom; + extern const OpcodeSpec rtDead; extern const OpcodeSpec rtDecay; extern const OpcodeSpec filterCutoff; extern const OpcodeSpec filterCutoffMod; @@ -156,6 +162,7 @@ namespace Default extern const OpcodeSpec egPercentMod; extern const OpcodeSpec egDepth; extern const OpcodeSpec egVel2Depth; + extern const OpcodeSpec flexEGAmpeg; extern const OpcodeSpec flexEGDynamic; extern const OpcodeSpec flexEGSustain; extern const OpcodeSpec flexEGPointTime; @@ -175,6 +182,7 @@ namespace Default extern const OpcodeSpec compAttack; extern const OpcodeSpec compRelease; extern const OpcodeSpec compThreshold; + extern const OpcodeSpec compSTLink; extern const OpcodeSpec compRatio; extern const OpcodeSpec compGain; extern const OpcodeSpec fverbSize; @@ -183,6 +191,7 @@ namespace Default extern const OpcodeSpec fverbDamp; extern const OpcodeSpec gateAttack; extern const OpcodeSpec gateRelease; + extern const OpcodeSpec gateSTLink; extern const OpcodeSpec gateHold; extern const OpcodeSpec gateThreshold; extern const OpcodeSpec lofiBitred; @@ -190,11 +199,6 @@ namespace Default extern const OpcodeSpec rectify; extern const OpcodeSpec stringsNumber; - // Boolean default values - constexpr bool rtDead { false }; - constexpr bool checkSustain { true }; // sustain_sw - constexpr bool checkSostenuto { true }; // sostenuto_sw - // Default/max count for objects constexpr int numEQs { 3 }; constexpr int numFilters { 2 }; diff --git a/src/sfizz/FlexEGDescription.h b/src/sfizz/FlexEGDescription.h index 84d9078c..7788329d 100644 --- a/src/sfizz/FlexEGDescription.h +++ b/src/sfizz/FlexEGDescription.h @@ -35,7 +35,7 @@ struct FlexEGDescription { int sustain { Default::flexEGSustain.value }; // index of the sustain point (default to 0 in ARIA) std::vector points; // ARIA - bool ampeg = false; // replaces the SFZv1 AmpEG (lowest with this bit wins) + bool ampeg { Default::flexEGAmpeg.value }; // replaces the SFZv1 AmpEG (lowest with this bit wins) }; } // namespace sfz diff --git a/src/sfizz/Opcode.cpp b/src/sfizz/Opcode.cpp index 87f2e109..e7e3222a 100644 --- a/src/sfizz/Opcode.cpp +++ b/src/sfizz/Opcode.cpp @@ -294,6 +294,22 @@ absl::optional readBooleanFromOpcode(const Opcode& opcode) return absl::nullopt; } +template <> +absl::optional Opcode::read(OpcodeSpec) const +{ + auto v = readBooleanFromOpcode(*this); + if (!v) + return absl::nullopt; + + return *v ? OscillatorEnabled::On : OscillatorEnabled::Off; +} + +template <> +absl::optional Opcode::read(OpcodeSpec) const +{ + return readBooleanFromOpcode(*this); +} + } // namespace sfz std::ostream &operator<<(std::ostream &os, const sfz::Opcode &opcode) diff --git a/src/sfizz/Range.h b/src/sfizz/Range.h index 7bbe369f..04240553 100644 --- a/src/sfizz/Range.h +++ b/src/sfizz/Range.h @@ -19,7 +19,9 @@ namespace sfz */ template class Range { - static_assert(std::is_arithmetic::value, "The Type should be arithmetic"); + // static_assert(std::is_arithmetic::value + // || (std::is_enum::value && std::is_same::type, int>::value), + // "The Type should be arithmetic"); public: constexpr Range() = default; diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 57848885..cc73a2d1 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -163,8 +163,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) oscillatorPhase = (*value >= 0) ? wrapPhase(*value) : -1.0f; break; case hash("oscillator"): - if (auto value = readBooleanFromOpcode(opcode)) - oscillatorEnabled = *value ? OscillatorEnabled::On : OscillatorEnabled::Off; + oscillatorEnabled = opcode.read(Default::oscillator).value_or(oscillatorEnabled); break; case hash("oscillator_mode"): oscillatorMode = opcode.read(Default::oscillatorMode).value_or(oscillatorMode); @@ -243,13 +242,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) } break; case hash("rt_dead"): - if (opcode.value == "on") { - rtDead = true; - } else if (opcode.value == "off") { - rtDead = false; - } else { - DBG("Unkown rt_dead value:" << opcode.value); - } + rtDead = opcode.read(Default::rtDead).value_or(rtDead); break; // Region logic: key mapping case hash("lokey"): @@ -387,10 +380,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) sustainThreshold = normalizeCC(*value); break; case hash("sustain_sw"): - checkSustain = readBooleanFromOpcode(opcode).value_or(Default::checkSustain); + checkSustain = opcode.read(Default::checkSustain).value_or(checkSustain); break; case hash("sostenuto_sw"): - checkSostenuto = readBooleanFromOpcode(opcode).value_or(Default::checkSostenuto); + checkSostenuto = opcode.read(Default::checkSostenuto).value_or(checkSostenuto); break; // Region logic: internal conditions case hash("lochanaft"): @@ -1263,7 +1256,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(flexEGs, egNumber, Default::numFlexEGs)) return false; - if (auto ampeg = readBooleanFromOpcode(opcode)) { + if (auto ampeg = opcode.read(Default::flexEGAmpeg)) { FlexEGDescription& desc = flexEGs[egNumber - 1]; if (desc.ampeg != *ampeg) { desc.ampeg = *ampeg; diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index 87f39984..d7784767 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -332,8 +332,7 @@ struct Region { // Wavetable oscillator float oscillatorPhase { Default::oscillatorPhase.value }; - enum class OscillatorEnabled { Auto = -1, Off = 0, On = 1 }; - OscillatorEnabled oscillatorEnabled { OscillatorEnabled::Auto }; // oscillator + OscillatorEnabled oscillatorEnabled { Default::oscillator.value }; // oscillator bool hasWavetableSample { false }; // (set according to sample file) int oscillatorMode { Default::oscillatorMode.value }; int oscillatorMulti { Default::oscillatorMulti.value }; @@ -349,7 +348,7 @@ struct Region { absl::optional notePolyphony {}; // note_polyphony uint32_t polyphony { config::maxVoices }; // polyphony SfzSelfMask selfMask { Default::selfMask }; - bool rtDead { Default::rtDead }; + bool rtDead { Default::rtDead.value }; // Region logic: key mapping Range keyRange { Default::key.bounds }; //lokey, hikey and key @@ -366,8 +365,8 @@ struct Region { absl::optional previousKeyswitch {}; // sw_previous absl::optional defaultSwitch {}; SfzVelocityOverride velocityOverride { Default::velocityOverride }; // sw_vel - bool checkSustain { Default::checkSustain }; // sustain_sw - bool checkSostenuto { Default::checkSostenuto }; // sostenuto_sw + bool checkSustain { Default::checkSustain.value }; // sustain_sw + bool checkSostenuto { Default::checkSostenuto.value }; // sostenuto_sw uint16_t sustainCC { Default::sustainCC.value }; // sustain_cc float sustainThreshold { Default::sustainThreshold.value }; // sustain_cc diff --git a/src/sfizz/effects/Compressor.cpp b/src/sfizz/effects/Compressor.cpp index 06b805ee..94f4b242 100644 --- a/src/sfizz/effects/Compressor.cpp +++ b/src/sfizz/effects/Compressor.cpp @@ -31,7 +31,7 @@ namespace fx { struct Compressor::Impl { faustCompressor _compressor[2]; - bool _stlink = false; + bool _stlink { Default::compSTLink.value }; float _inputGain { Default::compGain.value }; AudioBuffer _tempBuffer2x { 2, _oversampling * config::defaultSamplesPerBlock }; AudioBuffer _gain2x { 2, _oversampling * config::defaultSamplesPerBlock }; @@ -191,8 +191,7 @@ namespace fx { impl._inputGain = db2mag(*value); break; case hash("comp_stlink"): - if (auto value = readBooleanFromOpcode(opc)) - impl._stlink = *value; + impl._stlink = opc.read(Default::compSTLink).value_or(impl._stlink); break; } } diff --git a/src/sfizz/effects/Gate.cpp b/src/sfizz/effects/Gate.cpp index 792060e6..a4a916a3 100644 --- a/src/sfizz/effects/Gate.cpp +++ b/src/sfizz/effects/Gate.cpp @@ -34,7 +34,7 @@ namespace fx { struct Gate::Impl { faustGate _gate[2]; - bool _stlink = false; + bool _stlink { Default::gateSTLink.value }; float _inputGain = 1.0; AudioBuffer _tempBuffer2x { 2, _oversampling * config::defaultSamplesPerBlock }; AudioBuffer _gain2x { 2, _oversampling * config::defaultSamplesPerBlock }; @@ -190,9 +190,7 @@ namespace fx { } break; case hash("gate_stlink"): - if (auto value = readBooleanFromOpcode(opc)) - impl._stlink = *value; - break; + impl._stlink = opc.read(Default::gateSTLink).value_or(impl._stlink); } } diff --git a/tests/FilesT.cpp b/tests/FilesT.cpp index 1072d188..2ed037a7 100644 --- a/tests/FilesT.cpp +++ b/tests/FilesT.cpp @@ -282,7 +282,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)") REQUIRE(!region->isStereo()); REQUIRE(region->isGenerator()); REQUIRE(region->isOscillator()); - REQUIRE(region->oscillatorEnabled == Region::OscillatorEnabled::Auto); + REQUIRE(region->oscillatorEnabled == OscillatorEnabled::Auto); // generator with multi region = synth.getRegionView(regionNumber++); @@ -290,7 +290,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)") REQUIRE(region->isStereo()); REQUIRE(region->isGenerator()); REQUIRE(region->isOscillator()); - REQUIRE(region->oscillatorEnabled == Region::OscillatorEnabled::Auto); + REQUIRE(region->oscillatorEnabled == OscillatorEnabled::Auto); // explicit wavetable region = synth.getRegionView(regionNumber++); @@ -298,7 +298,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)") REQUIRE(!region->isStereo()); REQUIRE(!region->isGenerator()); REQUIRE(region->isOscillator()); - REQUIRE(region->oscillatorEnabled == Region::OscillatorEnabled::On); + REQUIRE(region->oscillatorEnabled == OscillatorEnabled::On); // explicit wavetable with multi region = synth.getRegionView(regionNumber++); @@ -306,7 +306,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)") REQUIRE(region->isStereo()); REQUIRE(!region->isGenerator()); REQUIRE(region->isOscillator()); - REQUIRE(region->oscillatorEnabled == Region::OscillatorEnabled::On); + REQUIRE(region->oscillatorEnabled == OscillatorEnabled::On); // explicit disabled wavetable region = synth.getRegionView(regionNumber++); @@ -314,7 +314,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)") REQUIRE(!region->isStereo()); REQUIRE(!region->isGenerator()); REQUIRE(!region->isOscillator()); - REQUIRE(region->oscillatorEnabled == Region::OscillatorEnabled::Off); + REQUIRE(region->oscillatorEnabled == OscillatorEnabled::Off); // explicit disabled wavetable with multi region = synth.getRegionView(regionNumber++); @@ -322,7 +322,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)") REQUIRE(!region->isStereo()); REQUIRE(!region->isGenerator()); REQUIRE(!region->isOscillator()); - REQUIRE(region->oscillatorEnabled == Region::OscillatorEnabled::Off); + REQUIRE(region->oscillatorEnabled == OscillatorEnabled::Off); // implicit wavetable (sound file < 3000 frames) region = synth.getRegionView(regionNumber++); @@ -330,7 +330,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)") REQUIRE(!region->isStereo()); REQUIRE(!region->isGenerator()); REQUIRE(region->isOscillator()); - REQUIRE(region->oscillatorEnabled == Region::OscillatorEnabled::Auto); + REQUIRE(region->oscillatorEnabled == OscillatorEnabled::Auto); // implicit non-wavetable (sound file >= 3000 frames) region = synth.getRegionView(regionNumber++); @@ -338,7 +338,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)") REQUIRE(!region->isStereo()); REQUIRE(!region->isGenerator()); REQUIRE(!region->isOscillator()); - REQUIRE(region->oscillatorEnabled == Region::OscillatorEnabled::Auto); + REQUIRE(region->oscillatorEnabled == OscillatorEnabled::Auto); // generator with multi=1 (single) region = synth.getRegionView(regionNumber++); @@ -346,7 +346,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)") REQUIRE(!region->isStereo()); REQUIRE(region->isGenerator()); REQUIRE(region->isOscillator()); - REQUIRE(region->oscillatorEnabled == Region::OscillatorEnabled::Auto); + REQUIRE(region->oscillatorEnabled == OscillatorEnabled::Auto); // generator with multi=2 (ring modulation) region = synth.getRegionView(regionNumber++); @@ -354,7 +354,7 @@ TEST_CASE("[Files] Channels (channels_multi.sfz)") REQUIRE(!region->isStereo()); REQUIRE(region->isGenerator()); REQUIRE(region->isOscillator()); - REQUIRE(region->oscillatorEnabled == Region::OscillatorEnabled::Auto); + REQUIRE(region->oscillatorEnabled == OscillatorEnabled::Auto); } TEST_CASE("[Files] wrong (overlapping) replacement for defines") diff --git a/tests/RegionValuesT.cpp b/tests/RegionValuesT.cpp index 0e2a38c0..a3e02417 100644 --- a/tests/RegionValuesT.cpp +++ b/tests/RegionValuesT.cpp @@ -2347,7 +2347,7 @@ TEST_CASE("[Values] Sustain switch") "/region0/sustain_sw,T : { }", "/region1/sustain_sw,F : { }", "/region2/sustain_sw,T : { }", - "/region3/sustain_sw,T : { }", + "/region3/sustain_sw,F : { }", }; REQUIRE(messageList == expected); } @@ -2373,7 +2373,7 @@ TEST_CASE("[Values] Sostenuto switch") "/region0/sostenuto_sw,T : { }", "/region1/sostenuto_sw,F : { }", "/region2/sostenuto_sw,T : { }", - "/region3/sostenuto_sw,T : { }", + "/region3/sostenuto_sw,F : { }", }; REQUIRE(messageList == expected); } From 60b5783753af8024f0617fc643ca84f63d51d7d0 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Sun, 3 Jan 2021 22:54:25 +0100 Subject: [PATCH 05/15] Read enums through opcode.read --- src/sfizz/Defaults.cpp | 7 +++ src/sfizz/Defaults.h | 17 +++--- src/sfizz/Opcode.cpp | 111 +++++++++++++++++++++++++++++++++++ src/sfizz/Region.cpp | 100 ++++--------------------------- src/sfizz/Region.h | 14 ++--- src/sfizz/SfzFilter.cpp | 46 --------------- src/sfizz/SfzFilter.h | 10 ---- src/sfizz/effects/Eq.cpp | 8 +-- src/sfizz/effects/Filter.cpp | 8 +-- 9 files changed, 147 insertions(+), 174 deletions(-) diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp index aa768dd7..fc8be532 100644 --- a/src/sfizz/Defaults.cpp +++ b/src/sfizz/Defaults.cpp @@ -145,6 +145,13 @@ extern const OpcodeSpec lofiBitred { 0.0f, Range(0.0f, 100.0f), kI extern const OpcodeSpec lofiDecim { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; extern const OpcodeSpec rectify { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; extern const OpcodeSpec stringsNumber { maxStrings, Range(0, maxStrings), kEnforceLowerBound }; +extern const OpcodeSpec trigger { SfzTrigger::attack, Range(SfzTrigger::attack, SfzTrigger::release_key), 0}; +extern const OpcodeSpec crossfadeCurve { SfzCrossfadeCurve::power, Range(SfzCrossfadeCurve::gain, SfzCrossfadeCurve::power), 0}; +extern const OpcodeSpec offMode { SfzOffMode::fast, Range(SfzOffMode::fast, SfzOffMode::time), 0}; +extern const OpcodeSpec velocityOverride { SfzVelocityOverride::current, Range(SfzVelocityOverride::current, SfzVelocityOverride::previous), 0}; +extern const OpcodeSpec selfMask { SfzSelfMask::mask, Range(SfzSelfMask::mask, SfzSelfMask::dontMask), 0}; +extern const OpcodeSpec filter { FilterType::kFilterNone, Range(FilterType::kFilterNone, FilterType::kFilterPeq), 0}; +extern const OpcodeSpec eq { EqType::kEqNone, Range(EqType::kEqNone, EqType::kEqHighShelf), 0}; } // namespace Default } // namespace sfz diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 9025265e..2c307e0c 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -26,6 +26,7 @@ #pragma once #include "Range.h" #include "Config.h" +#include "SfzFilter.h" #include #include @@ -198,6 +199,13 @@ namespace Default extern const OpcodeSpec lofiDecim; extern const OpcodeSpec rectify; extern const OpcodeSpec stringsNumber; + extern const OpcodeSpec trigger; + extern const OpcodeSpec offMode; + extern const OpcodeSpec crossfadeCurve; + extern const OpcodeSpec velocityOverride; + extern const OpcodeSpec selfMask; + extern const OpcodeSpec filter; + extern const OpcodeSpec eq; // Default/max count for objects constexpr int numEQs { 3 }; @@ -210,15 +218,6 @@ namespace Default constexpr int maxDistoStages { 4 }; constexpr unsigned maxStrings { 88 }; - // Default values for enums - constexpr SfzTrigger trigger { SfzTrigger::attack }; - constexpr SfzOffMode offMode { SfzOffMode::fast }; - constexpr SfzVelocityOverride velocityOverride { SfzVelocityOverride::current }; - constexpr SfzSelfMask selfMask { SfzSelfMask::mask }; - constexpr SfzCrossfadeCurve crossfadeKeyCurve { SfzCrossfadeCurve::power }; - constexpr SfzCrossfadeCurve crossfadeVelCurve { SfzCrossfadeCurve::power }; - constexpr SfzCrossfadeCurve crossfadeCCCurve { SfzCrossfadeCurve::power }; - // Default values for ranges constexpr Range crossfadeKeyInRange { 0, 0 }; constexpr Range crossfadeKeyOutRange { 127, 127 }; diff --git a/src/sfizz/Opcode.cpp b/src/sfizz/Opcode.cpp index e7e3222a..a2609ca6 100644 --- a/src/sfizz/Opcode.cpp +++ b/src/sfizz/Opcode.cpp @@ -304,6 +304,117 @@ absl::optional Opcode::read(OpcodeSpec) co return *v ? OscillatorEnabled::On : OscillatorEnabled::Off; } +template <> +absl::optional Opcode::read(OpcodeSpec) const +{ + switch (hash(value)) { + case hash("attack"): return SfzTrigger::attack; + case hash("first"): return SfzTrigger::first; + case hash("legato"): return SfzTrigger::legato; + case hash("release"): return SfzTrigger::release; + case hash("release_key"): return SfzTrigger::release_key; + } + + DBG("Unknown trigger value: " << value); + return absl::nullopt; +} + +template <> +absl::optional Opcode::read(OpcodeSpec) const +{ + switch (hash(value)) { + case hash("power"): return SfzCrossfadeCurve::power; + case hash("gain"): return SfzCrossfadeCurve::gain; + } + + DBG("Unknown crossfade power curve: " << value); + return absl::nullopt; +} + +template <> +absl::optional Opcode::read(OpcodeSpec) const +{ + switch (hash(value)) { + case hash("fast"): return SfzOffMode::fast; + case hash("normal"): return SfzOffMode::normal; + case hash("time"): return SfzOffMode::time; + } + + DBG("Unknown off mode: " << value); + return absl::nullopt; +} + +template <> +absl::optional Opcode::read(OpcodeSpec) const +{ + switch (hash(value)) { + case hash("lpf_1p"): return kFilterLpf1p; + case hash("hpf_1p"): return kFilterHpf1p; + case hash("lpf_2p"): return kFilterLpf2p; + case hash("hpf_2p"): return kFilterHpf2p; + case hash("bpf_2p"): return kFilterBpf2p; + case hash("brf_2p"): return kFilterBrf2p; + case hash("bpf_1p"): return kFilterBpf1p; + case hash("brf_1p"): return kFilterBrf1p; + case hash("apf_1p"): return kFilterApf1p; + case hash("lpf_2p_sv"): return kFilterLpf2pSv; + case hash("hpf_2p_sv"): return kFilterHpf2pSv; + case hash("bpf_2p_sv"): return kFilterBpf2pSv; + case hash("brf_2p_sv"): return kFilterBrf2pSv; + case hash("lpf_4p"): return kFilterLpf4p; + case hash("hpf_4p"): return kFilterHpf4p; + case hash("lpf_6p"): return kFilterLpf6p; + case hash("hpf_6p"): return kFilterHpf6p; + case hash("pink"): return kFilterPink; + case hash("lsh"): return kFilterLsh; + case hash("hsh"): return kFilterHsh; + case hash("bpk_2p"): //fallthrough + case hash("pkf_2p"): //fallthrough + case hash("peq"): return kFilterPeq; + } + + DBG("Unknown filter type: " << value); + return kFilterNone; +} + +template <> +absl::optional Opcode::read(OpcodeSpec) const +{ + switch (hash(value)) { + case hash("peak"): return kEqPeak; + case hash("lshelf"): return kEqLowShelf; + case hash("hshelf"): return kEqHighShelf; + } + + DBG("Unknown EQ type: " << value); + return kEqNone; +} + +template <> +absl::optional Opcode::read(OpcodeSpec) const +{ + switch (hash(value)) { + case hash("current"): return SfzVelocityOverride::current; + case hash("previous"): return SfzVelocityOverride::previous; + } + + DBG("Unknown velocity override: " << value); + return absl::nullopt; +} + +template <> +absl::optional Opcode::read(OpcodeSpec) const +{ + switch (hash(value)) { + case hash("on"): + case hash("mask"): return SfzSelfMask::mask; + case hash("off"): return SfzSelfMask::dontMask; + } + + DBG("Unknown velocity override: " << value); + return absl::nullopt; +} + template <> absl::optional Opcode::read(OpcodeSpec) const { diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index cc73a2d1..22e0ef54 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -204,19 +204,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) offBy = *value; break; case hash("off_mode"): // also offmode - switch (hash(opcode.value)) { - case hash("fast"): - offMode = SfzOffMode::fast; - break; - case hash("normal"): - offMode = SfzOffMode::normal; - break; - case hash("time"): - offMode = SfzOffMode::time; - break; - default: - DBG("Unkown off mode:" << opcode.value); - } + offMode = opcode.read(Default::offMode).value_or(offMode); break; case hash("off_time"): offMode = SfzOffMode::time; @@ -360,16 +348,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) } break; case hash("sw_vel"): - switch (hash(opcode.value)) { - case hash("current"): - velocityOverride = SfzVelocityOverride::current; - break; - case hash("previous"): - velocityOverride = SfzVelocityOverride::previous; - break; - default: - DBG("Unknown velocity mode: " << opcode.value); - } + velocityOverride = + opcode.read(Default::velocityOverride).value_or(velocityOverride); break; case hash("sustain_cc"): @@ -419,25 +399,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) break; // Region logic: triggers case hash("trigger"): - switch (hash(opcode.value)) { - case hash("attack"): - trigger = SfzTrigger::attack; - break; - case hash("first"): - trigger = SfzTrigger::first; - break; - case hash("legato"): - trigger = SfzTrigger::legato; - break; - case hash("release"): - trigger = SfzTrigger::release; - break; - case hash("release_key"): - trigger = SfzTrigger::release_key; - break; - default: - DBG("Unknown trigger mode: " << opcode.value); - } + trigger = opcode.read(Default::trigger).value_or(trigger); break; case hash("start_locc&"): // also on_locc& if (opcode.parameters.back() >= config::numCCs) @@ -564,28 +526,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) crossfadeVelOutRange.setEnd(normalizeVelocity(*value)); break; case hash("xf_keycurve"): - switch (hash(opcode.value)) { - case hash("power"): - crossfadeKeyCurve = SfzCrossfadeCurve::power; - break; - case hash("gain"): - crossfadeKeyCurve = SfzCrossfadeCurve::gain; - break; - default: - DBG("Unknown crossfade power curve: " << opcode.value); - } + crossfadeKeyCurve = opcode.read(Default::crossfadeCurve).value_or(crossfadeKeyCurve); break; case hash("xf_velcurve"): - switch (hash(opcode.value)) { - case hash("power"): - crossfadeVelCurve = SfzCrossfadeCurve::power; - break; - case hash("gain"): - crossfadeVelCurve = SfzCrossfadeCurve::gain; - break; - default: - DBG("Unknown crossfade power curve: " << opcode.value); - } + crossfadeVelCurve = opcode.read(Default::crossfadeCurve).value_or(crossfadeVelCurve); break; case hash("xfin_locc&"): if (opcode.parameters.back() >= config::numCCs) @@ -612,16 +556,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) crossfadeCCOutRange[opcode.parameters.back()].setEnd(normalizeCC(*value)); break; case hash("xf_cccurve"): - switch (hash(opcode.value)) { - case hash("power"): - crossfadeCCCurve = SfzCrossfadeCurve::power; - break; - case hash("gain"): - crossfadeCCCurve = SfzCrossfadeCurve::gain; - break; - default: - DBG("Unknown crossfade power curve: " << opcode.value); - } + crossfadeCCCurve = opcode.read(Default::crossfadeCurve).value_or(crossfadeCCCurve); break; case hash("rt_decay"): rtDecay = opcode.read(Default::rtDecay).value_or(rtDecay); @@ -745,14 +680,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - absl::optional ftype = Filter::typeFromName(opcode.value); - - if (ftype) - filters[filterIndex].type = *ftype; - else { - filters[filterIndex].type = FilterType::kFilterNone; - DBG("Unknown filter type: " << opcode.value); - } + filters[filterIndex].type = + opcode.read(Default::filter).value_or(filters[filterIndex].type); } break; @@ -835,15 +764,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - absl::optional ftype = FilterEq::typeFromName(opcode.value); + equalizers[eqIndex].type = + opcode.read(Default::eq).value_or(equalizers[eqIndex].type); - if (ftype) - equalizers[eqIndex].type = *ftype; - else { - equalizers[eqIndex].type = EqType::kEqNone; - DBG("Unknown EQ type: " << opcode.value); - } - } + } break; // Performance parameters: pitch diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index d7784767..e064e1b6 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -343,11 +343,11 @@ struct Region { // Instrument settings: voice lifecycle uint32_t group { Default::group.value }; // group absl::optional offBy {}; // off_by - SfzOffMode offMode { Default::offMode }; // off_mode + SfzOffMode offMode { Default::offMode.value }; // off_mode float offTime { Default::offTime.value }; // off_mode absl::optional notePolyphony {}; // note_polyphony uint32_t polyphony { config::maxVoices }; // polyphony - SfzSelfMask selfMask { Default::selfMask }; + SfzSelfMask selfMask { Default::selfMask.value }; bool rtDead { Default::rtDead.value }; // Region logic: key mapping @@ -364,7 +364,7 @@ struct Region { absl::optional downKeyswitch {}; // sw_down absl::optional previousKeyswitch {}; // sw_previous absl::optional defaultSwitch {}; - SfzVelocityOverride velocityOverride { Default::velocityOverride }; // sw_vel + SfzVelocityOverride velocityOverride { Default::velocityOverride.value }; // sw_vel bool checkSustain { Default::checkSustain.value }; // sustain_sw bool checkSostenuto { Default::checkSostenuto.value }; // sostenuto_sw uint16_t sustainCC { Default::sustainCC.value }; // sustain_cc @@ -378,7 +378,7 @@ struct Region { uint8_t sequencePosition { Default::sequence.value }; // seq_position // Region logic: triggers - SfzTrigger trigger { Default::trigger }; // trigger + SfzTrigger trigger { Default::trigger.value }; // trigger CCMap> ccTriggers { Default::normalized.bounds }; // on_loccN on_hiccN // Performance parameters: amplifier @@ -397,9 +397,9 @@ struct Region { Range crossfadeKeyOutRange { Default::crossfadeKeyOutRange }; Range crossfadeVelInRange { Default::crossfadeVelInRange }; Range crossfadeVelOutRange { Default::crossfadeVelOutRange }; - SfzCrossfadeCurve crossfadeKeyCurve { Default::crossfadeKeyCurve }; - SfzCrossfadeCurve crossfadeVelCurve { Default::crossfadeVelCurve }; - SfzCrossfadeCurve crossfadeCCCurve { Default::crossfadeCCCurve }; + SfzCrossfadeCurve crossfadeKeyCurve { Default::crossfadeCurve.value }; + SfzCrossfadeCurve crossfadeVelCurve { Default::crossfadeCurve.value }; + SfzCrossfadeCurve crossfadeCCCurve { Default::crossfadeCurve.value }; CCMap> crossfadeCCInRange { Default::crossfadeCCInRange }; // xfin_loccN xfin_hiccN CCMap> crossfadeCCOutRange { Default::crossfadeCCOutRange }; // xfout_loccN xfout_hiccN float rtDecay { Default::rtDecay.value }; // rt_decay diff --git a/src/sfizz/SfzFilter.cpp b/src/sfizz/SfzFilter.cpp index 039dddb2..a1d22239 100644 --- a/src/sfizz/SfzFilter.cpp +++ b/src/sfizz/SfzFilter.cpp @@ -204,39 +204,6 @@ void Filter::setType(FilterType type) } } -absl::optional Filter::typeFromName(absl::string_view name) -{ - absl::optional ftype; - - switch (hash(name)) { - case hash("lpf_1p"): ftype = kFilterLpf1p; break; - case hash("hpf_1p"): ftype = kFilterHpf1p; break; - case hash("lpf_2p"): ftype = kFilterLpf2p; break; - case hash("hpf_2p"): ftype = kFilterHpf2p; break; - case hash("bpf_2p"): ftype = kFilterBpf2p; break; - case hash("brf_2p"): ftype = kFilterBrf2p; break; - case hash("bpf_1p"): ftype = kFilterBpf1p; break; - case hash("brf_1p"): ftype = kFilterBrf1p; break; - case hash("apf_1p"): ftype = kFilterApf1p; break; - case hash("lpf_2p_sv"): ftype = kFilterLpf2pSv; break; - case hash("hpf_2p_sv"): ftype = kFilterHpf2pSv; break; - case hash("bpf_2p_sv"): ftype = kFilterBpf2pSv; break; - case hash("brf_2p_sv"): ftype = kFilterBrf2pSv; break; - case hash("lpf_4p"): ftype = kFilterLpf4p; break; - case hash("hpf_4p"): ftype = kFilterHpf4p; break; - case hash("lpf_6p"): ftype = kFilterLpf6p; break; - case hash("hpf_6p"): ftype = kFilterHpf6p; break; - case hash("pink"): ftype = kFilterPink; break; - case hash("lsh"): ftype = kFilterLsh; break; - case hash("hsh"): ftype = kFilterHsh; break; - case hash("bpk_2p"): //fallthrough - case hash("pkf_2p"): //fallthrough - case hash("peq"): ftype = kFilterPeq; break; - } - - return ftype; -} - sfzFilterDsp *Filter::Impl::getDsp(unsigned channels, FilterType type) { switch (idDsp(channels, type)) { @@ -444,19 +411,6 @@ void FilterEq::setType(EqType type) } } -absl::optional FilterEq::typeFromName(absl::string_view name) -{ - absl::optional ftype; - - switch (hash(name)) { - case hash("peak"): ftype = kEqPeak; break; - case hash("lshelf"): ftype = kEqLowShelf; break; - case hash("hshelf"): ftype = kEqHighShelf; break; - } - - return ftype; -} - sfzFilterDsp *FilterEq::Impl::getDsp(unsigned channels, EqType type) { switch (idDsp(channels, type)) { diff --git a/src/sfizz/SfzFilter.h b/src/sfizz/SfzFilter.h index 62cba612..b64ffe8e 100644 --- a/src/sfizz/SfzFilter.h +++ b/src/sfizz/SfzFilter.h @@ -84,11 +84,6 @@ public: */ void setType(FilterType type); - /** - Get the filter type associated with the given name. - */ - static absl::optional typeFromName(absl::string_view name); - private: struct Impl; std::unique_ptr P; @@ -194,11 +189,6 @@ public: */ void setType(EqType type); - /** - Get the filter type associated with the given name. - */ - static absl::optional typeFromName(absl::string_view name); - private: struct Impl; std::unique_ptr P; diff --git a/src/sfizz/effects/Eq.cpp b/src/sfizz/effects/Eq.cpp index 7c9b5594..751ccc12 100644 --- a/src/sfizz/effects/Eq.cpp +++ b/src/sfizz/effects/Eq.cpp @@ -83,13 +83,7 @@ namespace fx { break; case hash("eq_type"): { - absl::optional ftype = sfz::FilterEq::typeFromName(opc.value); - if (ftype) - desc.type = *ftype; - else { - desc.type = EqType::kEqNone; - DBG("Unknown EQ type: " << std::string(opc.value)); - } + desc.type = opc.read(Default::eq).value_or(desc.type); break; } } diff --git a/src/sfizz/effects/Filter.cpp b/src/sfizz/effects/Filter.cpp index 836306f3..b3765b61 100644 --- a/src/sfizz/effects/Filter.cpp +++ b/src/sfizz/effects/Filter.cpp @@ -81,13 +81,7 @@ namespace fx { break; case hash("filter_type"): { - absl::optional ftype = sfz::Filter::typeFromName(opc.value); - if (ftype) - desc.type = *ftype; - else { - desc.type = FilterType::kFilterNone; - DBG("Unknown filter type: " << std::string(opc.value)); - } + desc.type = opc.read(Default::filter).value_or(desc.type); break; } // extension From e9941b4337a7c65272ee9145b3c496b7748dd1be Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Sun, 3 Jan 2021 23:29:33 +0100 Subject: [PATCH 06/15] Scope the enums in sfz and remove the prefix --- src/sfizz/ADSREnvelope.cpp | 2 +- src/sfizz/Defaults.cpp | 10 ++--- src/sfizz/Defaults.h | 22 +++++----- src/sfizz/FileMetadata.h | 4 +- src/sfizz/ModifierHelpers.h | 12 ++--- src/sfizz/Opcode.cpp | 38 ++++++++-------- src/sfizz/Region.cpp | 26 +++++------ src/sfizz/Region.h | 20 ++++----- src/sfizz/Synth.cpp | 8 ++-- src/sfizz/SynthMessaging.cpp | 44 +++++++++---------- src/sfizz/Voice.cpp | 6 +-- src/sfizz/VoiceManager.cpp | 4 +- .../modulations/sources/FlexEnvelope.cpp | 2 +- tests/FilesT.cpp | 28 ++++++------ 14 files changed, 113 insertions(+), 113 deletions(-) diff --git a/src/sfizz/ADSREnvelope.cpp b/src/sfizz/ADSREnvelope.cpp index b6fab78e..be5b3199 100644 --- a/src/sfizz/ADSREnvelope.cpp +++ b/src/sfizz/ADSREnvelope.cpp @@ -53,7 +53,7 @@ void ADSREnvelope::reset(const EGDescription& desc, const Region& region, const shouldRelease = false; freeRunning = ( (this->sustain == Float(0.0)) - || (region.loopMode == SfzLoopMode::one_shot && region.isOscillator()) + || (region.loopMode == LoopMode::one_shot && region.isOscillator()) ); currentValue = this->start; currentState = State::Delay; diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp index fc8be532..622b72f4 100644 --- a/src/sfizz/Defaults.cpp +++ b/src/sfizz/Defaults.cpp @@ -145,11 +145,11 @@ extern const OpcodeSpec lofiBitred { 0.0f, Range(0.0f, 100.0f), kI extern const OpcodeSpec lofiDecim { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; extern const OpcodeSpec rectify { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; extern const OpcodeSpec stringsNumber { maxStrings, Range(0, maxStrings), kEnforceLowerBound }; -extern const OpcodeSpec trigger { SfzTrigger::attack, Range(SfzTrigger::attack, SfzTrigger::release_key), 0}; -extern const OpcodeSpec crossfadeCurve { SfzCrossfadeCurve::power, Range(SfzCrossfadeCurve::gain, SfzCrossfadeCurve::power), 0}; -extern const OpcodeSpec offMode { SfzOffMode::fast, Range(SfzOffMode::fast, SfzOffMode::time), 0}; -extern const OpcodeSpec velocityOverride { SfzVelocityOverride::current, Range(SfzVelocityOverride::current, SfzVelocityOverride::previous), 0}; -extern const OpcodeSpec selfMask { SfzSelfMask::mask, Range(SfzSelfMask::mask, SfzSelfMask::dontMask), 0}; +extern const OpcodeSpec trigger { Trigger::attack, Range(Trigger::attack, Trigger::release_key), 0}; +extern const OpcodeSpec crossfadeCurve { CrossfadeCurve::power, Range(CrossfadeCurve::gain, CrossfadeCurve::power), 0}; +extern const OpcodeSpec offMode { OffMode::fast, Range(OffMode::fast, OffMode::time), 0}; +extern const OpcodeSpec velocityOverride { VelocityOverride::current, Range(VelocityOverride::current, VelocityOverride::previous), 0}; +extern const OpcodeSpec selfMask { SelfMask::mask, Range(SelfMask::mask, SelfMask::dontMask), 0}; extern const OpcodeSpec filter { FilterType::kFilterNone, Range(FilterType::kFilterNone, FilterType::kFilterPeq), 0}; extern const OpcodeSpec eq { EqType::kEqNone, Range(EqType::kEqNone, EqType::kEqHighShelf), 0}; } // namespace Default diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 2c307e0c..98d34919 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -30,16 +30,16 @@ #include #include -enum class SfzTrigger { attack = 0, release, release_key, first, legato }; -enum class SfzLoopMode { no_loop = 0, one_shot, loop_continuous, loop_sustain }; -enum class SfzOffMode { fast = 0, normal, time }; -enum class SfzVelocityOverride { current = 0, previous }; -enum class SfzCrossfadeCurve { gain = 0, power }; -enum class SfzSelfMask { mask = 0, dontMask }; namespace sfz { +enum class Trigger { attack = 0, release, release_key, first, legato }; +enum class LoopMode { no_loop = 0, one_shot, loop_continuous, loop_sustain }; +enum class OffMode { fast = 0, normal, time }; +enum class VelocityOverride { current = 0, previous }; +enum class CrossfadeCurve { gain = 0, power }; +enum class SelfMask { mask = 0, dontMask }; enum class OscillatorEnabled { Auto = -1, Off = 0, On = 1 }; enum OpcodeFlags : int { @@ -199,11 +199,11 @@ namespace Default extern const OpcodeSpec lofiDecim; extern const OpcodeSpec rectify; extern const OpcodeSpec stringsNumber; - extern const OpcodeSpec trigger; - extern const OpcodeSpec offMode; - extern const OpcodeSpec crossfadeCurve; - extern const OpcodeSpec velocityOverride; - extern const OpcodeSpec selfMask; + extern const OpcodeSpec trigger; + extern const OpcodeSpec offMode; + extern const OpcodeSpec crossfadeCurve; + extern const OpcodeSpec velocityOverride; + extern const OpcodeSpec selfMask; extern const OpcodeSpec filter; extern const OpcodeSpec eq; diff --git a/src/sfizz/FileMetadata.h b/src/sfizz/FileMetadata.h index 96facb03..a6a152be 100644 --- a/src/sfizz/FileMetadata.h +++ b/src/sfizz/FileMetadata.h @@ -28,7 +28,7 @@ struct RiffChunkInfo { /** @brief Loop mode, like SF_LOOP_* */ -enum LoopMode { +enum FileLoopMode { LoopNone, LoopForward, LoopBackward, @@ -52,7 +52,7 @@ struct InstrumentInfo { } loops[16]; }; #else -enum LoopMode { +enum FileLoopMode { LoopNone = SF_LOOP_NONE, LoopForward = SF_LOOP_FORWARD, LoopBackward = SF_LOOP_BACKWARD, diff --git a/src/sfizz/ModifierHelpers.h b/src/sfizz/ModifierHelpers.h index e9b76361..f3061111 100644 --- a/src/sfizz/ModifierHelpers.h +++ b/src/sfizz/ModifierHelpers.h @@ -16,7 +16,7 @@ namespace sfz { * @brief Compute a crossfade in value with respect to a crossfade range (note, velocity, cc, ...) */ template -float crossfadeIn(const sfz::Range& crossfadeRange, U value, SfzCrossfadeCurve curve) +float crossfadeIn(const sfz::Range& crossfadeRange, U value, CrossfadeCurve curve) { if (value < crossfadeRange.getStart()) return 0.0f; @@ -27,9 +27,9 @@ float crossfadeIn(const sfz::Range& crossfadeRange, U value, SfzCrossfadeCurv else if (value < crossfadeRange.getEnd()) { const auto crossfadePosition = static_cast(value - crossfadeRange.getStart()) / length; - if (curve == SfzCrossfadeCurve::power) + if (curve == CrossfadeCurve::power) return sqrt(crossfadePosition); - if (curve == SfzCrossfadeCurve::gain) + if (curve == CrossfadeCurve::gain) return crossfadePosition; } @@ -40,7 +40,7 @@ float crossfadeIn(const sfz::Range& crossfadeRange, U value, SfzCrossfadeCurv * @brief Compute a crossfade out value with respect to a crossfade range (note, velocity, cc, ...) */ template -float crossfadeOut(const sfz::Range& crossfadeRange, U value, SfzCrossfadeCurve curve) +float crossfadeOut(const sfz::Range& crossfadeRange, U value, CrossfadeCurve curve) { if (value > crossfadeRange.getEnd()) return 0.0f; @@ -51,9 +51,9 @@ float crossfadeOut(const sfz::Range& crossfadeRange, U value, SfzCrossfadeCur else if (value > crossfadeRange.getStart()) { const auto crossfadePosition = static_cast(value - crossfadeRange.getStart()) / length; - if (curve == SfzCrossfadeCurve::power) + if (curve == CrossfadeCurve::power) return std::sqrt(1 - crossfadePosition); - if (curve == SfzCrossfadeCurve::gain) + if (curve == CrossfadeCurve::gain) return 1 - crossfadePosition; } diff --git a/src/sfizz/Opcode.cpp b/src/sfizz/Opcode.cpp index a2609ca6..7f5f59d1 100644 --- a/src/sfizz/Opcode.cpp +++ b/src/sfizz/Opcode.cpp @@ -305,14 +305,14 @@ absl::optional Opcode::read(OpcodeSpec) co } template <> -absl::optional Opcode::read(OpcodeSpec) const +absl::optional Opcode::read(OpcodeSpec) const { switch (hash(value)) { - case hash("attack"): return SfzTrigger::attack; - case hash("first"): return SfzTrigger::first; - case hash("legato"): return SfzTrigger::legato; - case hash("release"): return SfzTrigger::release; - case hash("release_key"): return SfzTrigger::release_key; + case hash("attack"): return Trigger::attack; + case hash("first"): return Trigger::first; + case hash("legato"): return Trigger::legato; + case hash("release"): return Trigger::release; + case hash("release_key"): return Trigger::release_key; } DBG("Unknown trigger value: " << value); @@ -320,11 +320,11 @@ absl::optional Opcode::read(OpcodeSpec) const } template <> -absl::optional Opcode::read(OpcodeSpec) const +absl::optional Opcode::read(OpcodeSpec) const { switch (hash(value)) { - case hash("power"): return SfzCrossfadeCurve::power; - case hash("gain"): return SfzCrossfadeCurve::gain; + case hash("power"): return CrossfadeCurve::power; + case hash("gain"): return CrossfadeCurve::gain; } DBG("Unknown crossfade power curve: " << value); @@ -332,12 +332,12 @@ absl::optional Opcode::read(OpcodeSpec) co } template <> -absl::optional Opcode::read(OpcodeSpec) const +absl::optional Opcode::read(OpcodeSpec) const { switch (hash(value)) { - case hash("fast"): return SfzOffMode::fast; - case hash("normal"): return SfzOffMode::normal; - case hash("time"): return SfzOffMode::time; + case hash("fast"): return OffMode::fast; + case hash("normal"): return OffMode::normal; + case hash("time"): return OffMode::time; } DBG("Unknown off mode: " << value); @@ -391,11 +391,11 @@ absl::optional Opcode::read(OpcodeSpec) const } template <> -absl::optional Opcode::read(OpcodeSpec) const +absl::optional Opcode::read(OpcodeSpec) const { switch (hash(value)) { - case hash("current"): return SfzVelocityOverride::current; - case hash("previous"): return SfzVelocityOverride::previous; + case hash("current"): return VelocityOverride::current; + case hash("previous"): return VelocityOverride::previous; } DBG("Unknown velocity override: " << value); @@ -403,12 +403,12 @@ absl::optional Opcode::read(OpcodeSpec } template <> -absl::optional Opcode::read(OpcodeSpec) const +absl::optional Opcode::read(OpcodeSpec) const { switch (hash(value)) { case hash("on"): - case hash("mask"): return SfzSelfMask::mask; - case hash("off"): return SfzSelfMask::dontMask; + case hash("mask"): return SelfMask::mask; + case hash("off"): return SelfMask::dontMask; } DBG("Unknown velocity override: " << value); diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 22e0ef54..70d071ef 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -130,16 +130,16 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash("loop_mode"): // also loopmode switch (hash(opcode.value)) { case hash("no_loop"): - loopMode = SfzLoopMode::no_loop; + loopMode = LoopMode::no_loop; break; case hash("one_shot"): - loopMode = SfzLoopMode::one_shot; + loopMode = LoopMode::one_shot; break; case hash("loop_continuous"): - loopMode = SfzLoopMode::loop_continuous; + loopMode = LoopMode::loop_continuous; break; case hash("loop_sustain"): - loopMode = SfzLoopMode::loop_sustain; + loopMode = LoopMode::loop_sustain; break; default: DBG("Unkown loop mode:" << opcode.value); @@ -207,7 +207,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) offMode = opcode.read(Default::offMode).value_or(offMode); break; case hash("off_time"): - offMode = SfzOffMode::time; + offMode = OffMode::time; offTime = opcode.read(Default::offTime).value_or(offTime); break; case hash("polyphony"): @@ -220,10 +220,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash("note_selfmask"): switch (hash(opcode.value)) { case hash("on"): - selfMask = SfzSelfMask::mask; + selfMask = SelfMask::mask; break; case hash("off"): - selfMask = SfzSelfMask::dontMask; + selfMask = SelfMask::dontMask; break; default: DBG("Unkown self mask value:" << opcode.value); @@ -1608,9 +1608,9 @@ bool sfz::Region::registerNoteOn(int noteNumber, float velocity, float randValue const bool velOk = velocityRange.containsWithEnd(velocity); const bool randOk = randRange.contains(randValue) || (randValue == 1.0f && randRange.getEnd() == 1.0f); - const bool firstLegatoNote = (trigger == SfzTrigger::first && midiState.getActiveNotes() == 1); - const bool attackTrigger = (trigger == SfzTrigger::attack); - const bool notFirstLegatoNote = (trigger == SfzTrigger::legato && midiState.getActiveNotes() > 1); + const bool firstLegatoNote = (trigger == Trigger::first && midiState.getActiveNotes() == 1); + const bool attackTrigger = (trigger == Trigger::attack); + const bool notFirstLegatoNote = (trigger == Trigger::legato && midiState.getActiveNotes() > 1); return keyOk && velOk && randOk && (attackTrigger || firstLegatoNote || notFirstLegatoNote); } @@ -1636,10 +1636,10 @@ bool sfz::Region::registerNoteOff(int noteNumber, float velocity, float randValu // Release logic - if (trigger == SfzTrigger::release_key) + if (trigger == Trigger::release_key) return true; - if (trigger == SfzTrigger::release) { + if (trigger == Trigger::release) { if (midiState.getCCValue(sustainCC) < sustainThreshold) return true; @@ -1717,7 +1717,7 @@ float sfz::Region::getBaseVolumedB(int noteNumber) const noexcept baseVolumedB += globalVolume; baseVolumedB += masterVolume; baseVolumedB += groupVolume; - if (trigger == SfzTrigger::release || trigger == SfzTrigger::release_key) + if (trigger == Trigger::release || trigger == Trigger::release_key) baseVolumedB -= rtDecay * midiState.getNoteDuration(noteNumber); return baseVolumedB; } diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index e064e1b6..9260b8e7 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -61,7 +61,7 @@ struct Region { * @return true * @return false */ - bool isRelease() const noexcept { return trigger == SfzTrigger::release || trigger == SfzTrigger::release_key; } + bool isRelease() const noexcept { return trigger == Trigger::release || trigger == Trigger::release_key; } /** * @brief Is a generator (*sine or *silence mostly)? * @@ -97,7 +97,7 @@ struct Region { * @return true * @return false */ - bool shouldLoop() const noexcept { return (loopMode == SfzLoopMode::loop_continuous || loopMode == SfzLoopMode::loop_sustain); } + bool shouldLoop() const noexcept { return (loopMode == LoopMode::loop_continuous || loopMode == LoopMode::loop_sustain); } /** * @brief Given the current midi state, is the region switched on? * @@ -326,7 +326,7 @@ struct Region { CCMap offsetCC { Default::offsetMod.value }; uint32_t sampleEnd { Default::sampleEnd.value }; // end absl::optional sampleCount {}; // count - absl::optional loopMode {}; // loopmode + absl::optional loopMode {}; // loopmode Range loopRange { Default::loopRange.bounds }; //loopstart and loopend float loopCrossfade { Default::loopCrossfade.value }; // loop_crossfade @@ -343,11 +343,11 @@ struct Region { // Instrument settings: voice lifecycle uint32_t group { Default::group.value }; // group absl::optional offBy {}; // off_by - SfzOffMode offMode { Default::offMode.value }; // off_mode + OffMode offMode { Default::offMode.value }; // off_mode float offTime { Default::offTime.value }; // off_mode absl::optional notePolyphony {}; // note_polyphony uint32_t polyphony { config::maxVoices }; // polyphony - SfzSelfMask selfMask { Default::selfMask.value }; + SelfMask selfMask { Default::selfMask.value }; bool rtDead { Default::rtDead.value }; // Region logic: key mapping @@ -364,7 +364,7 @@ struct Region { absl::optional downKeyswitch {}; // sw_down absl::optional previousKeyswitch {}; // sw_previous absl::optional defaultSwitch {}; - SfzVelocityOverride velocityOverride { Default::velocityOverride.value }; // sw_vel + VelocityOverride velocityOverride { Default::velocityOverride.value }; // sw_vel bool checkSustain { Default::checkSustain.value }; // sustain_sw bool checkSostenuto { Default::checkSostenuto.value }; // sostenuto_sw uint16_t sustainCC { Default::sustainCC.value }; // sustain_cc @@ -378,7 +378,7 @@ struct Region { uint8_t sequencePosition { Default::sequence.value }; // seq_position // Region logic: triggers - SfzTrigger trigger { Default::trigger.value }; // trigger + Trigger trigger { Default::trigger.value }; // trigger CCMap> ccTriggers { Default::normalized.bounds }; // on_loccN on_hiccN // Performance parameters: amplifier @@ -397,9 +397,9 @@ struct Region { Range crossfadeKeyOutRange { Default::crossfadeKeyOutRange }; Range crossfadeVelInRange { Default::crossfadeVelInRange }; Range crossfadeVelOutRange { Default::crossfadeVelOutRange }; - SfzCrossfadeCurve crossfadeKeyCurve { Default::crossfadeCurve.value }; - SfzCrossfadeCurve crossfadeVelCurve { Default::crossfadeCurve.value }; - SfzCrossfadeCurve crossfadeCCCurve { Default::crossfadeCurve.value }; + CrossfadeCurve crossfadeKeyCurve { Default::crossfadeCurve.value }; + CrossfadeCurve crossfadeVelCurve { Default::crossfadeCurve.value }; + CrossfadeCurve crossfadeCCCurve { Default::crossfadeCurve.value }; CCMap> crossfadeCCInRange { Default::crossfadeCCInRange }; // xfin_loccN xfin_hiccN CCMap> crossfadeCCOutRange { Default::crossfadeCCOutRange }; // xfout_loccN xfout_hiccN float rtDecay { Default::rtDecay.value }; // rt_decay diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 43ac6241..76f935d4 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -596,11 +596,11 @@ void Synth::Impl::finalizeSfzLoad() region->loopRange.setEnd(fileInformation->loopEnd); if (!region->loopMode) - region->loopMode = SfzLoopMode::loop_continuous; + region->loopMode = LoopMode::loop_continuous; } if (region->isRelease() && !region->loopMode) - region->loopMode = SfzLoopMode::one_shot; + region->loopMode = LoopMode::one_shot; if (region->loopRange.getEnd() == Default::loopRange.bounds.getEnd()) region->loopRange.setEnd(region->sampleEnd); @@ -656,7 +656,7 @@ void Synth::Impl::finalizeSfzLoad() for (int cc = 0; cc < config::numCCs; cc++) { if (region->ccTriggers.contains(cc) || region->ccConditions.contains(cc) - || (cc == region->sustainCC && region->trigger == SfzTrigger::release)) + || (cc == region->sustainCC && region->trigger == Trigger::release)) ccActivationLists_[cc].push_back(region); } @@ -1052,7 +1052,7 @@ void Synth::Impl::noteOffDispatch(int delay, int noteNumber, float velocity) noe for (auto& region : noteActivationLists_[noteNumber]) { if (region->registerNoteOff(noteNumber, velocity, randValue)) { - if (region->trigger == SfzTrigger::release && !region->rtDead && !voiceManager_.playingAttackVoice(region)) + if (region->trigger == Trigger::release && !region->rtDead && !voiceManager_.playingAttackVoice(region)) continue; startVoice(region, delay, triggerEvent, ring); diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index 0f6bd10b..62335993 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -167,16 +167,16 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co } switch (*region.loopMode) { - case SfzLoopMode::no_loop: + case LoopMode::no_loop: client.receive<'s'>(delay, path, "no_loop"); break; - case SfzLoopMode::loop_continuous: + case LoopMode::loop_continuous: client.receive<'s'>(delay, path, "loop_continuous"); break; - case SfzLoopMode::loop_sustain: + case LoopMode::loop_sustain: client.receive<'s'>(delay, path, "loop_sustain"); break; - case SfzLoopMode::one_shot: + case LoopMode::one_shot: client.receive<'s'>(delay, path, "one_shot"); break; } @@ -204,13 +204,13 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co MATCH("/region&/off_mode", "") { GET_REGION_OR_BREAK(indices[0]) switch (region.offMode) { - case SfzOffMode::time: + case OffMode::time: client.receive<'s'>(delay, path, "time"); break; - case SfzOffMode::normal: + case OffMode::normal: client.receive<'s'>(delay, path, "normal"); break; - case SfzOffMode::fast: + case OffMode::fast: client.receive<'s'>(delay, path, "fast"); break; } @@ -313,10 +313,10 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co MATCH("/region&/sw_vel", "") { GET_REGION_OR_BREAK(indices[0]) switch (region.velocityOverride) { - case SfzVelocityOverride::current: + case VelocityOverride::current: client.receive<'s'>(delay, path, "current"); break; - case SfzVelocityOverride::previous: + case VelocityOverride::previous: client.receive<'s'>(delay, path, "previous"); break; } @@ -359,19 +359,19 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co MATCH("/region&/trigger", "") { GET_REGION_OR_BREAK(indices[0]) switch (region.trigger) { - case SfzTrigger::attack: + case Trigger::attack: client.receive<'s'>(delay, path, "attack"); break; - case SfzTrigger::first: + case Trigger::first: client.receive<'s'>(delay, path, "first"); break; - case SfzTrigger::release: + case Trigger::release: client.receive<'s'>(delay, path, "release"); break; - case SfzTrigger::release_key: + case Trigger::release_key: client.receive<'s'>(delay, path, "release_key"); break; - case SfzTrigger::legato: + case Trigger::legato: client.receive<'s'>(delay, path, "legato"); break; } @@ -696,10 +696,10 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co MATCH("/region&/xf_keycurve", "") { GET_REGION_OR_BREAK(indices[0]) switch (region.crossfadeKeyCurve) { - case SfzCrossfadeCurve::gain: + case CrossfadeCurve::gain: client.receive<'s'>(delay, path, "gain"); break; - case SfzCrossfadeCurve::power: + case CrossfadeCurve::power: client.receive<'s'>(delay, path, "power"); break; } @@ -708,10 +708,10 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co MATCH("/region&/xf_velcurve", "") { GET_REGION_OR_BREAK(indices[0]) switch (region.crossfadeVelCurve) { - case SfzCrossfadeCurve::gain: + case CrossfadeCurve::gain: client.receive<'s'>(delay, path, "gain"); break; - case SfzCrossfadeCurve::power: + case CrossfadeCurve::power: client.receive<'s'>(delay, path, "power"); break; } @@ -720,10 +720,10 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co MATCH("/region&/xf_cccurve", "") { GET_REGION_OR_BREAK(indices[0]) switch (region.crossfadeCCCurve) { - case SfzCrossfadeCurve::gain: + case CrossfadeCurve::gain: client.receive<'s'>(delay, path, "gain"); break; - case SfzCrossfadeCurve::power: + case CrossfadeCurve::power: client.receive<'s'>(delay, path, "power"); break; } @@ -945,10 +945,10 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co MATCH("/region&/note_selfmask", "") { GET_REGION_OR_BREAK(indices[0]) switch(region.selfMask) { - case SfzSelfMask::mask: + case SelfMask::mask: client.receive(delay, path, "T", nullptr); break; - case SfzSelfMask::dontMask: + case SelfMask::dontMask: client.receive(delay, path, "F", nullptr); break; } diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 4ba91ba1..dae62336 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -464,9 +464,9 @@ void Voice::off(int delay, bool fast) noexcept { Impl& impl = *impl_; if (!impl.region_->flexAmpEG) { - if (impl.region_->offMode == SfzOffMode::fast || fast) { + if (impl.region_->offMode == OffMode::fast || fast) { impl.egAmplitude_.setReleaseTime(Default::offTime.value); - } else if (impl.region_->offMode == SfzOffMode::time) { + } else if (impl.region_->offMode == OffMode::time) { impl.egAmplitude_.setReleaseTime(impl.region_->offTime); } } @@ -492,7 +492,7 @@ void Voice::registerNoteOff(int delay, int noteNumber, float velocity) noexcept if (impl.triggerEvent_.number == noteNumber && impl.triggerEvent_.type == TriggerEventType::NoteOn) { impl.noteIsOff_ = true; - if (impl.region_->loopMode == SfzLoopMode::one_shot) + if (impl.region_->loopMode == LoopMode::one_shot) return; if (!impl.region_->checkSustain diff --git a/src/sfizz/VoiceManager.cpp b/src/sfizz/VoiceManager.cpp index 490927b2..ff978f18 100644 --- a/src/sfizz/VoiceManager.cpp +++ b/src/sfizz/VoiceManager.cpp @@ -198,7 +198,7 @@ void VoiceManager::checkNotePolyphony(const Region* region, int delay, const Tri && voiceTriggerEvent.type == triggerEvent.type) { notePolyphonyCounter += 1; switch (region->selfMask) { - case SfzSelfMask::mask: + case SelfMask::mask: if (voiceTriggerEvent.value <= triggerEvent.value) { if (!selfMaskCandidate || selfMaskCandidate->getTriggerEvent().value > voiceTriggerEvent.value) { @@ -206,7 +206,7 @@ void VoiceManager::checkNotePolyphony(const Region* region, int delay, const Tri } } break; - case SfzSelfMask::dontMask: + case SelfMask::dontMask: if (!selfMaskCandidate || selfMaskCandidate->getAge() < voice->getAge()) selfMaskCandidate = voice; break; diff --git a/src/sfizz/modulations/sources/FlexEnvelope.cpp b/src/sfizz/modulations/sources/FlexEnvelope.cpp index 5cea2ad8..c9112376 100644 --- a/src/sfizz/modulations/sources/FlexEnvelope.cpp +++ b/src/sfizz/modulations/sources/FlexEnvelope.cpp @@ -38,7 +38,7 @@ void FlexEnvelopeSource::init(const ModKey& sourceKey, NumericId voiceId, FlexEnvelope* eg = voice->getFlexEG(egIndex); eg->configure(®ion->flexEGs[egIndex]); bool freeRunning = ( - (region->loopMode == SfzLoopMode::one_shot && region->isOscillator()) + (region->loopMode == LoopMode::one_shot && region->isOscillator()) ); if (freeRunning && region->flexAmpEG && egIndex == *region->flexAmpEG) eg->setFreeRunning(true); diff --git a/tests/FilesT.cpp b/tests/FilesT.cpp index 2ed037a7..0c25cfc9 100644 --- a/tests/FilesT.cpp +++ b/tests/FilesT.cpp @@ -51,7 +51,7 @@ TEST_CASE("[Files] Underscore opcodes (underscore_opcodes.sfz)") 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); + REQUIRE(synth.getRegionView(0)->loopMode == LoopMode::loop_sustain); } TEST_CASE("[Files] (regions_bad.sfz)") @@ -505,11 +505,11 @@ TEST_CASE("[Files] Off modes") synth.noteOn(0, 64, 63); REQUIRE( synth.getNumActiveVoices() == 2 ); const auto* fastVoice = - synth.getVoiceView(0)->getRegion()->offMode == SfzOffMode::fast ? + synth.getVoiceView(0)->getRegion()->offMode == OffMode::fast ? synth.getVoiceView(0) : synth.getVoiceView(1) ; const auto* normalVoice = - synth.getVoiceView(0)->getRegion()->offMode == SfzOffMode::fast ? + synth.getVoiceView(0)->getRegion()->offMode == OffMode::fast ? synth.getVoiceView(1) : synth.getVoiceView(0) ; synth.noteOn(100, 63, 63); @@ -530,9 +530,9 @@ TEST_CASE("[Files] Looped regions taken from files and possibly overriden") synth.setSampleRate(44100); synth.loadSfzFile(fs::current_path() / "tests/TestFiles/looped_regions.sfz"); REQUIRE( synth.getNumRegions() == 3 ); - REQUIRE( synth.getRegionView(0)->loopMode == SfzLoopMode::loop_continuous ); - REQUIRE( synth.getRegionView(1)->loopMode == SfzLoopMode::no_loop ); - REQUIRE( synth.getRegionView(2)->loopMode == SfzLoopMode::loop_continuous ); + REQUIRE( synth.getRegionView(0)->loopMode == LoopMode::loop_continuous ); + REQUIRE( synth.getRegionView(1)->loopMode == LoopMode::no_loop ); + REQUIRE( synth.getRegionView(2)->loopMode == LoopMode::loop_continuous ); REQUIRE(synth.getRegionView(0)->loopRange == Range { 77554, 186581 }); REQUIRE(synth.getRegionView(1)->loopRange == Range { 77554, 186581 }); @@ -546,7 +546,7 @@ TEST_CASE("[Files] Looped regions can start at 0") sample=wavetable_with_loop_at_endings.wav )"); REQUIRE( synth.getNumRegions() == 1 ); - REQUIRE( synth.getRegionView(0)->loopMode == SfzLoopMode::loop_continuous ); + REQUIRE( synth.getRegionView(0)->loopMode == LoopMode::loop_continuous ); REQUIRE( synth.getRegionView(0)->loopRange == Range { 0, synth.getRegionView(0)->sampleEnd } ); } @@ -563,13 +563,13 @@ TEST_CASE("[Synth] Release triggers automatically sets the loop mode") sample=kick.wav pitch_keycenter=69 trigger=release )"); REQUIRE( synth.getNumRegions() == 7 ); - REQUIRE( synth.getRegionView(0)->loopMode == SfzLoopMode::loop_sustain ); - REQUIRE( synth.getRegionView(1)->loopMode == SfzLoopMode::loop_sustain ); - REQUIRE( synth.getRegionView(2)->loopMode == SfzLoopMode::loop_sustain ); - REQUIRE( synth.getRegionView(3)->loopMode == SfzLoopMode::loop_sustain ); - REQUIRE( synth.getRegionView(4)->loopMode == SfzLoopMode::loop_continuous ); - REQUIRE( synth.getRegionView(5)->loopMode == SfzLoopMode::one_shot ); - REQUIRE( synth.getRegionView(6)->loopMode == SfzLoopMode::one_shot ); + REQUIRE( synth.getRegionView(0)->loopMode == LoopMode::loop_sustain ); + REQUIRE( synth.getRegionView(1)->loopMode == LoopMode::loop_sustain ); + REQUIRE( synth.getRegionView(2)->loopMode == LoopMode::loop_sustain ); + REQUIRE( synth.getRegionView(3)->loopMode == LoopMode::loop_sustain ); + REQUIRE( synth.getRegionView(4)->loopMode == LoopMode::loop_continuous ); + REQUIRE( synth.getRegionView(5)->loopMode == LoopMode::one_shot ); + REQUIRE( synth.getRegionView(6)->loopMode == LoopMode::one_shot ); } TEST_CASE("[Files] Case sentitiveness") From 293e7a935fd0285c029b66e3015ce82049e8d636 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Sun, 10 Jan 2021 19:01:20 +0100 Subject: [PATCH 07/15] WIP --- src/sfizz/Curve.cpp | 14 +- src/sfizz/Defaults.cpp | 195 ++++---- src/sfizz/Defaults.h | 54 ++- src/sfizz/EGDescription.h | 26 +- src/sfizz/EQDescription.h | 10 +- src/sfizz/EQPool.h | 6 +- src/sfizz/Effects.h | 4 +- src/sfizz/FilePool.cpp | 8 +- src/sfizz/FilePool.h | 6 +- src/sfizz/FilterDescription.h | 14 +- src/sfizz/FilterPool.h | 8 +- src/sfizz/FlexEGDescription.h | 12 +- src/sfizz/LFODescription.h | 33 +- src/sfizz/Opcode.cpp | 101 ++-- src/sfizz/Opcode.h | 2 +- src/sfizz/Region.cpp | 710 ++++++++++++----------------- src/sfizz/Region.h | 118 ++--- src/sfizz/Synth.cpp | 58 +-- src/sfizz/SynthConfig.h | 2 +- src/sfizz/SynthMessaging.cpp | 6 +- src/sfizz/SynthPrivate.h | 4 +- src/sfizz/Voice.cpp | 4 +- src/sfizz/effects/Apan.cpp | 18 +- src/sfizz/effects/Apan.h | 12 +- src/sfizz/effects/Compressor.cpp | 29 +- src/sfizz/effects/Disto.cpp | 25 +- src/sfizz/effects/Eq.cpp | 15 +- src/sfizz/effects/Filter.cpp | 15 +- src/sfizz/effects/Fverb.cpp | 28 +- src/sfizz/effects/Gain.cpp | 3 +- src/sfizz/effects/Gate.cpp | 24 +- src/sfizz/effects/Lofi.cpp | 6 +- src/sfizz/effects/Rectify.cpp | 3 +- src/sfizz/effects/Strings.cpp | 6 +- src/sfizz/effects/Strings.h | 2 +- src/sfizz/effects/Width.cpp | 3 +- tests/OpcodeT.cpp | 27 +- tests/RegionValueComputationsT.cpp | 6 +- tests/RegionValuesT.cpp | 10 +- tests/SynthT.cpp | 2 +- 40 files changed, 753 insertions(+), 876 deletions(-) diff --git a/src/sfizz/Curve.cpp b/src/sfizz/Curve.cpp index b4dcb93f..1f1c792b 100644 --- a/src/sfizz/Curve.cpp +++ b/src/sfizz/Curve.cpp @@ -40,11 +40,7 @@ Curve Curve::buildCurveFromHeader( if (index >= NumValues) continue; - auto valueOpt = opc.read(fullRange); - if (!valueOpt) - continue; - - setPoint(static_cast(index), *valueOpt); + setPoint(static_cast(index), opc.read(fullRange)); } curve.fill(itp, fillStatus); @@ -267,12 +263,8 @@ void CurveSet::addCurveFromHeader(absl::Span members) int curveIndex = -1; Curve::Interpolator itp = Curve::Interpolator::Linear; - if (const Opcode* opc = findOpcode(hash("curve_index"))) { - if (auto opt = opc->read(Default::curveCC)) - curveIndex = *opt; - else - DBG("Invalid value for curve index: " << opc->value); - } + if (const Opcode* opc = findOpcode(hash("curve_index"))) + curveIndex = opc->read(Default::curveCC); #if 0 // potential sfizz extension if (const Opcode* opc = findOpcode(hash("sfizz:curve_interpolator"))) { diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp index 622b72f4..ee712e58 100644 --- a/src/sfizz/Defaults.cpp +++ b/src/sfizz/Defaults.cpp @@ -1,150 +1,163 @@ #include "Defaults.h" +#include "MathHelpers.h" +#include "SfzHelpers.h" namespace sfz { namespace Default { constexpr auto uint32_t_max = std::numeric_limits::max(); -extern const OpcodeSpec delay { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; -extern const OpcodeSpec delayRandom { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; -extern const OpcodeSpec offset { 0, Range(0, uint32_t_max), kEnforceLowerBound }; -extern const OpcodeSpec offsetMod { 0, Range(0, uint32_t_max), kEnforceLowerBound }; -extern const OpcodeSpec offsetRandom { 0, Range(0, uint32_t_max), kEnforceLowerBound }; -extern const OpcodeSpec sampleEnd { uint32_t_max, Range(0, uint32_t_max), kEnforceLowerBound | kEnforceUpperBound }; -extern const OpcodeSpec sampleCount { 0, Range(0, uint32_t_max), 0 }; -extern const OpcodeSpec loopRange { 0, Range(0, uint32_t_max), 0 }; -extern const OpcodeSpec loopCrossfade { 1e-3, Range(1e-3, 1.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec delay { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec delayRandom { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec offset { 0, Range(0, uint32_t_max), 0 }; +extern const OpcodeSpec offsetMod { 0, Range(0, uint32_t_max), 0 }; +extern const OpcodeSpec offsetRandom { 0, Range(0, uint32_t_max), 0 }; +extern const OpcodeSpec sampleEnd { uint32_t_max, Range(0, uint32_t_max), kEnforceLowerBound }; +extern const OpcodeSpec sampleCount { 1, Range(1, uint32_t_max), 0 }; +extern const OpcodeSpec loopStart { 0, Range(0, uint32_t_max), 0 }; +extern const OpcodeSpec loopEnd { uint32_t_max, Range(0, uint32_t_max), 0 }; +extern const OpcodeSpec loopCrossfade { 1e-3, Range(1e-3, 1.0f), 0 }; extern const OpcodeSpec oscillator { OscillatorEnabled::Auto, Range(OscillatorEnabled::Auto, OscillatorEnabled::On), 0 }; extern const OpcodeSpec oscillatorPhase { 0.0f, Range(0.0f, 1.0f), 0 }; -extern const OpcodeSpec oscillatorMode { 0, Range(0, 2), kIgnoreOOB }; -extern const OpcodeSpec oscillatorMulti { 1, Range(1, config::oscillatorsPerVoice), kIgnoreOOB }; +extern const OpcodeSpec oscillatorMode { 0, Range(0, 2), 0 }; +extern const OpcodeSpec oscillatorMulti { 1, Range(1, config::oscillatorsPerVoice), 0 }; extern const OpcodeSpec oscillatorDetune { 0.0f, Range(-12000.0f, 12000.0f), 0 }; extern const OpcodeSpec oscillatorDetuneMod { 0.0f, Range(-12000.0f, 12000.0f), 0 }; -extern const OpcodeSpec oscillatorModDepth { 0.0f, Range(0.0f, 10000.0f), kEnforceLowerBound }; -extern const OpcodeSpec oscillatorModDepthMod { 0.0f, Range(0.0f, 10000.0f), kEnforceLowerBound }; -extern const OpcodeSpec oscillatorQuality { 1, Range(0, 3), kIgnoreOOB }; +extern const OpcodeSpec oscillatorModDepth { 0.0f, Range(0.0f, 10000.0f), kNormalizePercent }; +extern const OpcodeSpec oscillatorModDepthMod { 0.0f, Range(0.0f, 10000.0f), 0 }; +extern const OpcodeSpec oscillatorQuality { 1, Range(0, 3), 0 }; extern const OpcodeSpec group { 0, Range(0, uint32_t_max), 0 }; -extern const OpcodeSpec offTime { 6e-3f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec offTime { 6e-3f, Range(0.0f, 100.0f), 0 }; extern const OpcodeSpec polyphony { config::maxVoices, Range(0, config::maxVoices), 0 }; extern const OpcodeSpec notePolyphony { config::maxVoices, Range(0, config::maxVoices), 0 }; -extern const OpcodeSpec key { 60, Range(0, 127), kIgnoreOOB | kCanBeNote }; -extern const OpcodeSpec midi7 { 0, Range(0, 127), kIgnoreOOB }; -extern const OpcodeSpec float7 { 0.0f , Range(0.0f, 127.0f), kIgnoreOOB }; -extern const OpcodeSpec bend { 0.0f, Range(-8192.0f, 8192.0f), kIgnoreOOB }; -extern const OpcodeSpec normalized { 0.0f, Range(0.0f, 1.0f), kIgnoreOOB }; -extern const OpcodeSpec bipolar { 0.0f, Range(-1.0f, 1.0f), kIgnoreOOB }; -extern const OpcodeSpec ccNumber { 0, Range(0, config::numCCs), kIgnoreOOB }; -extern const OpcodeSpec smoothCC { 0, Range(0, 100), kIgnoreOOB }; -extern const OpcodeSpec curveCC { 0, Range(0, 255), kIgnoreOOB }; -extern const OpcodeSpec sustainCC { 64, Range(0, 127), kIgnoreOOB }; -extern const OpcodeSpec sustainThreshold { 0.0039f, Range(0.0f, 1.0f), kIgnoreOOB }; +extern const OpcodeSpec key { 60, Range(0, 127), kCanBeNote }; +extern const OpcodeSpec loKey { 0, Range(0, 127), kCanBeNote }; +extern const OpcodeSpec hiKey { 127, Range(0, 127), kCanBeNote }; +extern const OpcodeSpec loCC { 0.0f , Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec hiCC { 1.0f , Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec loVel { 0.0f , Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec hiVel { 1.0f , Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec loChannelAftertouch { 0, Range(0, 127), 0 }; +extern const OpcodeSpec hiChannelAftertouch { 127, Range(0, 127), 0 }; +extern const OpcodeSpec loBend { -1.0f, Range(-8192.0f, 8192.0f), kNormalizeBend }; +extern const OpcodeSpec hiBend { 1.0f, Range(-8192.0f, 8192.0f), kNormalizeBend }; +extern const OpcodeSpec loNormalized { 0.0f, Range(0.0f, 1.0f), 0 }; +extern const OpcodeSpec hiNormalized { 1.0f, Range(0.0f, 1.0f), 0 }; +extern const OpcodeSpec loBipolar { -1.0f, Range(-1.0f, 1.0f), 0 }; +extern const OpcodeSpec hiBipolar { 1.0f, Range(-1.0f, 1.0f), 0 }; +extern const OpcodeSpec ccNumber { 0, Range(0, config::numCCs), 0 }; +extern const OpcodeSpec smoothCC { 0, Range(0, 100), 0 }; +extern const OpcodeSpec curveCC { 0, Range(0, 255), 0 }; +extern const OpcodeSpec sustainCC { 64, Range(0, 127), 0 }; +extern const OpcodeSpec sustainThreshold { 0.0039f, Range(0.0f, 127.0f), kNormalizeMidi }; extern const OpcodeSpec checkSustain { true, Range(0, 1), 0 }; extern const OpcodeSpec checkSostenuto { true, Range(0, 1), 0 }; -extern const OpcodeSpec bpm { 0.0f, Range(0.0f, 500.0f), kEnforceLowerBound }; -extern const OpcodeSpec sequence { 1, Range(1, 100), kIgnoreOOB }; +extern const OpcodeSpec loBPM { 0.0f, Range(0.0f, 500.0f), 0 }; +extern const OpcodeSpec hiBPM { 500.0f, Range(0.0f, 500.0f), 0 }; +extern const OpcodeSpec sequence { 1, Range(1, 100), 0 }; extern const OpcodeSpec volume { 0.0f, Range(-144.0f, 48.0f), 0 }; extern const OpcodeSpec volumeMod { 0.0f, Range(-144.0f, 48.0f), 0 }; -extern const OpcodeSpec amplitude { 100.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; -extern const OpcodeSpec amplitudeMod { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; -extern const OpcodeSpec pan { 0.0f, Range(-100.0f, 100.0f), 0 }; -extern const OpcodeSpec panMod { 0.0f, Range(-200.0f, 200.0f), 0 }; -extern const OpcodeSpec position { 0.0f, Range(-100.0f, 100.0f), 0 }; -extern const OpcodeSpec positionMod { 0.0f, Range(-200.0f, 200.0f), 0 }; -extern const OpcodeSpec width { 100.0f, Range(-100.0f, 100.0f), 0 }; -extern const OpcodeSpec widthMod { 0.0f, Range(-200.0f, 200.0f), 0 }; -extern const OpcodeSpec crossfadeIn { 0, Range(0, 127), kEnforceLowerBound | kEnforceUpperBound }; -extern const OpcodeSpec crossfadeInNorm { 0.0f, Range(0.0f, 1.0f), kEnforceLowerBound | kEnforceUpperBound }; -extern const OpcodeSpec crossfadeOut { 127, Range(0, 127), kEnforceLowerBound | kEnforceUpperBound }; -extern const OpcodeSpec crossfadeOutNorm { 1.0f, Range(0.0f, 1.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec amplitude { 100.0f, Range(0.0f, 10000.0f), kNormalizePercent }; +extern const OpcodeSpec amplitudeMod { 0.0f, Range(0.0f, 10000.0f), kNormalizePercent }; +extern const OpcodeSpec pan { 0.0f, Range(-100.0f, 100.0f), kNormalizePercent }; +extern const OpcodeSpec panMod { 0.0f, Range(-200.0f, 200.0f), kNormalizePercent }; +extern const OpcodeSpec position { 0.0f, Range(-100.0f, 100.0f), kNormalizePercent }; +extern const OpcodeSpec positionMod { 0.0f, Range(-200.0f, 200.0f), kNormalizePercent }; +extern const OpcodeSpec width { 100.0f, Range(-100.0f, 100.0f), kNormalizePercent }; +extern const OpcodeSpec widthMod { 0.0f, Range(-200.0f, 200.0f), kNormalizePercent }; +extern const OpcodeSpec crossfadeIn { 0.0f, Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec crossfadeInNorm { 0.0f, Range(0.0f, 1.0f), 0 }; +extern const OpcodeSpec crossfadeOut { 1.0f, Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec crossfadeOutNorm { 1.0f, Range(0.0f, 1.0f), 0 }; extern const OpcodeSpec ampKeytrack { 0.0f, Range(-96.0f, 12.0f), 0 }; -extern const OpcodeSpec ampVeltrack { 100.0f, Range(-100.0f, 100.0f), kIgnoreOOB }; -extern const OpcodeSpec ampVelcurve { 0.0f, Range(0.0f, 1.0f), kEnforceLowerBound | kEnforceUpperBound }; -extern const OpcodeSpec ampRandom { 0.0f, Range(0.0f, 24.0f), kEnforceLowerBound }; +extern const OpcodeSpec ampVeltrack { 100.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec ampVelcurve { 0.0f, Range(0.0f, 1.0f), 0 }; +extern const OpcodeSpec ampRandom { 0.0f, Range(0.0f, 24.0f), 0 }; extern const OpcodeSpec rtDead { false, Range(0, 1), 0 }; -extern const OpcodeSpec rtDecay { 0.0f, Range(0.0f, 200.0f), kEnforceLowerBound }; -extern const OpcodeSpec filterCutoff { 0.0f, Range(0.0f, 20000.0f), kEnforceLowerBound | kEnforceUpperBound }; -extern const OpcodeSpec filterCutoffMod { 0.0f, Range(-12000.0f, 12000.0f), kEnforceLowerBound }; -extern const OpcodeSpec filterResonance { 0.0f, Range(0.0f, 96.0f), kEnforceLowerBound }; -extern const OpcodeSpec filterResonanceMod { 0.0f, Range(0.0f, 96.0f), kEnforceLowerBound }; +extern const OpcodeSpec rtDecay { 0.0f, Range(0.0f, 200.0f), 0 }; +extern const OpcodeSpec filterCutoff { 0.0f, Range(0.0f, 20000.0f), 0 }; +extern const OpcodeSpec filterCutoffMod { 0.0f, Range(-12000.0f, 12000.0f), 0 }; +extern const OpcodeSpec filterResonance { 0.0f, Range(0.0f, 96.0f), 0 }; +extern const OpcodeSpec filterResonanceMod { 0.0f, Range(0.0f, 96.0f), 0 }; extern const OpcodeSpec filterGain { 0.0f, Range(-96.0f, 96.0f), 0 }; extern const OpcodeSpec filterGainMod { 0.0f, Range(-96.0f, 96.0f), 0 }; -extern const OpcodeSpec filterRandom { 0.0f, Range(0.0f, 12000.0f), kEnforceLowerBound }; -extern const OpcodeSpec filterKeytrack { 0, Range(0, 1200), kEnforceLowerBound }; +extern const OpcodeSpec filterRandom { 0.0f, Range(0.0f, 12000.0f), 0 }; +extern const OpcodeSpec filterKeytrack { 0, Range(0, 1200), 0 }; extern const OpcodeSpec filterVeltrack { 0, Range(-12000, 12000), 0 }; -extern const OpcodeSpec eqBandwidth { 1.0f, Range(0.001f, 4.0f), kEnforceLowerBound }; +extern const OpcodeSpec eqBandwidth { 1.0f, Range(0.001f, 4.0f), 0 }; extern const OpcodeSpec eqBandwidthMod { 0.0f, Range(-4.0f, 4.0f), 0 }; -extern const OpcodeSpec eqFrequency { 0.0f, Range(0.0f, 30000.0f), kEnforceLowerBound | kEnforceUpperBound }; +extern const OpcodeSpec eqFrequency { 0.0f, Range(0.0f, 30000.0f), 0 }; extern const OpcodeSpec eqFrequencyMod { 0.0f, Range(-30000.0f, 30000.0f), 0 }; extern const OpcodeSpec eqGain { 0.0f, Range(-96.0f, 96.0f), 0 }; extern const OpcodeSpec eqGainMod { 0.0f, Range(-96.0f, 96.0f), 0 }; extern const OpcodeSpec eqVel2Frequency { 0.0f, Range(-30000.0f, 30000.0f), 0 }; extern const OpcodeSpec eqVel2Gain { 0.0f, Range(-96.0f, 96.0f), 0 }; extern const OpcodeSpec pitchKeytrack { 100, Range(-1200, 1200), 0 }; -extern const OpcodeSpec pitchRandom { 0.0f, Range(0.0f, 12000.0f), kEnforceLowerBound }; +extern const OpcodeSpec pitchRandom { 0.0f, Range(0.0f, 12000.0f), 0 }; extern const OpcodeSpec pitchVeltrack { 0, Range(-12000, 12000), 0 }; -extern const OpcodeSpec transpose { 0, Range(-127, 127), kIgnoreOOB }; +extern const OpcodeSpec transpose { 0, Range(-127, 127), 0 }; extern const OpcodeSpec pitch { 0.0f, Range(-100.0f, 100.0f), 0 }; extern const OpcodeSpec pitchMod { 0.0f, Range(-100.0f, 100.0f), 0 }; extern const OpcodeSpec bendUp { 200.0f, Range(-12000.0f, 12000.0f), 0 }; extern const OpcodeSpec bendDown { -200.0f, Range(-12000.0f, 12000.0f), 0 }; -extern const OpcodeSpec bendStep { 1.0f, Range(1.0f, 1200.0f), kIgnoreOOB }; +extern const OpcodeSpec bendStep { 1.0f, Range(1.0f, 1200.0f), 0 }; extern const OpcodeSpec lfoFreq { 0.0f, Range(0.0f, 100.0f), 0 }; extern const OpcodeSpec lfoFreqMod { 0.0f, Range(-100.0f, 100.0f), 0 }; extern const OpcodeSpec lfoBeats { 0.0f, Range(0.0f, 1000.0f), 0 }; extern const OpcodeSpec lfoBeatsMod { 0.0f, Range(-1000.0f, 1000.0f), 0 }; -extern const OpcodeSpec lfoPhase { 0.0f, Range(0.0f, 1.0f), 0 }; +extern const OpcodeSpec lfoPhase { 0.0f, Range(0.0f, 1.0f), kWrapPhase }; extern const OpcodeSpec lfoDelay { 0.0f, Range(0.0f, 30.0f), 0 }; extern const OpcodeSpec lfoFade { 0.0f, Range(0.0f, 30.0f), 0 }; extern const OpcodeSpec lfoCount { 0, Range(0, 1000), 0 }; extern const OpcodeSpec lfoSteps { 0, Range(0, static_cast(config::maxLFOSteps)), 0 }; -extern const OpcodeSpec lfoStepX { 0.0f, Range(-100.0f, 100.0f), 0 }; -extern const OpcodeSpec lfoWave { 0, Range(0, 15), 0 }; +extern const OpcodeSpec lfoStepX { 0.0f, Range(-100.0f, 100.0f), kNormalizePercent }; +extern const OpcodeSpec lfoWave { LFOWave::Triangle, Range(LFOWave::Triangle, LFOWave::RandomSH), 0 }; extern const OpcodeSpec lfoOffset { 0.0f, Range(-1.0f, 1.0f), 0 }; extern const OpcodeSpec lfoRatio { 1.0f, Range(0.0f, 100.0f), 0 }; extern const OpcodeSpec lfoScale { 1.0f, Range(0.0f, 1.0f), 0 }; -extern const OpcodeSpec egTime { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; -extern const OpcodeSpec egRelease { 0.001f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec egTime { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec egRelease { 0.001f, Range(0.0f, 100.0f), 0 }; extern const OpcodeSpec egTimeMod { 0.0f, Range(-100.0f, 100.0f), 0 }; -extern const OpcodeSpec egPercent { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; +extern const OpcodeSpec egPercent { 0.0f, Range(0.0f, 100.0f), 0 }; extern const OpcodeSpec egPercentMod { 0.0f, Range(-100.0f, 100.0f), 0 }; extern const OpcodeSpec egDepth { 0.0f, Range(-12000.0f, 12000.0f), 0 }; extern const OpcodeSpec egVel2Depth { 0.0f, Range(-12000.0f, 12000.0f), 0 }; extern const OpcodeSpec flexEGAmpeg { false, Range(0, 1), 0 }; -extern const OpcodeSpec flexEGDynamic { 0, Range(0, 1), kIgnoreOOB }; -extern const OpcodeSpec flexEGSustain { 0, Range(0, 100), kIgnoreOOB }; -extern const OpcodeSpec flexEGPointTime { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; -extern const OpcodeSpec flexEGPointLevel { 0.0f, Range(-1.0f, 1.0f), kIgnoreOOB }; -extern const OpcodeSpec flexEGPointShape { 0.0f, Range(-100.0f, 100.0f), kEnforceLowerBound | kEnforceUpperBound }; -extern const OpcodeSpec sampleQuality { 1, Range(1, 10), kIgnoreOOB }; +extern const OpcodeSpec flexEGDynamic { 0, Range(0, 1), 0 }; +extern const OpcodeSpec flexEGSustain { 0, Range(0, 100), 0 }; +extern const OpcodeSpec flexEGPointTime { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec flexEGPointLevel { 0.0f, Range(-1.0f, 1.0f), 0 }; +extern const OpcodeSpec flexEGPointShape { 0.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec sampleQuality { 1, Range(1, 10), 0 }; extern const OpcodeSpec octaveOffset { 0, Range(-10, 10), 0 }; extern const OpcodeSpec noteOffset { 0, Range(-127, 127), 0 }; -extern const OpcodeSpec effect { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec effect { 0.0f, Range(0.0f, 100.0f), kNormalizePercent }; extern const OpcodeSpec apanWaveform { 0, Range(0, std::numeric_limits::max()), 0 }; -extern const OpcodeSpec apanFrequency { 0.0f, Range(0.0f, std::numeric_limits::max()), kEnforceLowerBound }; -extern const OpcodeSpec apanPhase { 0.5f, Range(0.0f, 1.0f), 0 }; -extern const OpcodeSpec apanLevel { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; -extern const OpcodeSpec distoTone { 100.0f, Range(0.0f, 100.0f), kEnforceLowerBound | kEnforceUpperBound }; -extern const OpcodeSpec distoDepth { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound | kEnforceUpperBound }; -extern const OpcodeSpec distoStages { 1, Range(1, maxDistoStages), kEnforceLowerBound }; -extern const OpcodeSpec compAttack { 0.005f, Range(0.0f, 10.0f), kEnforceLowerBound }; -extern const OpcodeSpec compRelease { 0.05f, Range(0.0f, 10.0f), kEnforceLowerBound }; +extern const OpcodeSpec apanFrequency { 0.0f, Range(0.0f, std::numeric_limits::max()), 0 }; +extern const OpcodeSpec apanPhase { 0.5f, Range(0.0f, 1.0f), kWrapPhase }; +extern const OpcodeSpec apanLevel { 0.0f, Range(0.0f, 100.0f), kNormalizePercent }; +extern const OpcodeSpec distoTone { 100.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec distoDepth { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec distoStages { 1, Range(1, maxDistoStages), 0 }; +extern const OpcodeSpec compAttack { 0.005f, Range(0.0f, 10.0f), 0 }; +extern const OpcodeSpec compRelease { 0.05f, Range(0.0f, 10.0f), 0 }; extern const OpcodeSpec compSTLink { false, Range(0, 1), 0 }; -extern const OpcodeSpec compThreshold { 0.0f, Range(-100.0f, 0.0f), kIgnoreOOB }; -extern const OpcodeSpec compRatio { 1.0f, Range(1.0f, 50.0f), kIgnoreOOB }; -extern const OpcodeSpec compGain { 0.0f, Range(-100.0f, 100.0f), 0 }; -extern const OpcodeSpec fverbSize { 0.0f, Range(0.0f, 100.0f), kEnforceLowerBound }; -extern const OpcodeSpec fverbPredelay { 0.0f, Range(0.0f, 10.0f), kEnforceLowerBound }; -extern const OpcodeSpec fverbTone { 100.0f, Range(0.0f, 100.0f), kIgnoreOOB }; -extern const OpcodeSpec fverbDamp { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; +extern const OpcodeSpec compThreshold { 0.0f, Range(-100.0f, 0.0f), 0 }; +extern const OpcodeSpec compRatio { 1.0f, Range(1.0f, 50.0f), 0 }; +extern const OpcodeSpec compGain { 1.0f, Range(-100.0f, 100.0f), kDb2Mag }; +extern const OpcodeSpec fverbSize { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec fverbPredelay { 0.0f, Range(0.0f, 10.0f), 0 }; +extern const OpcodeSpec fverbTone { 100.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec fverbDamp { 0.0f, Range(0.0f, 100.0f), 0 }; extern const OpcodeSpec gateSTLink { false, Range(0, 1), 0 }; -extern const OpcodeSpec gateAttack { 0.005f, Range(0.0f, 10.0f), kEnforceLowerBound }; -extern const OpcodeSpec gateRelease { 0.05f, Range(0.0f, 10.0f), kEnforceLowerBound }; -extern const OpcodeSpec gateHold { 0.0f, Range(0.0f, 10.0f), kEnforceLowerBound }; -extern const OpcodeSpec gateThreshold { 0.0f, Range(-100.0f, 0.0f), kIgnoreOOB }; -extern const OpcodeSpec lofiBitred { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; -extern const OpcodeSpec lofiDecim { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; -extern const OpcodeSpec rectify { 0.0f, Range(0.0f, 100.0f), kIgnoreOOB }; -extern const OpcodeSpec stringsNumber { maxStrings, Range(0, maxStrings), kEnforceLowerBound }; +extern const OpcodeSpec gateAttack { 0.005f, Range(0.0f, 10.0f), 0 }; +extern const OpcodeSpec gateRelease { 0.05f, Range(0.0f, 10.0f), 0 }; +extern const OpcodeSpec gateHold { 0.0f, Range(0.0f, 10.0f), 0 }; +extern const OpcodeSpec gateThreshold { 0.0f, Range(-100.0f, 0.0f), 0 }; +extern const OpcodeSpec lofiBitred { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec lofiDecim { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec rectify { 0.0f, Range(0.0f, 100.0f), 0 }; +extern const OpcodeSpec stringsNumber { maxStrings, Range(0, maxStrings), 0 }; extern const OpcodeSpec trigger { Trigger::attack, Range(Trigger::attack, Trigger::release_key), 0}; extern const OpcodeSpec crossfadeCurve { CrossfadeCurve::power, Range(CrossfadeCurve::gain, CrossfadeCurve::power), 0}; extern const OpcodeSpec offMode { OffMode::fast, Range(OffMode::fast, OffMode::time), 0}; diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 98d34919..27f5481c 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -41,20 +41,37 @@ enum class VelocityOverride { current = 0, previous }; enum class CrossfadeCurve { gain = 0, power }; enum class SelfMask { mask = 0, dontMask }; enum class OscillatorEnabled { Auto = -1, Off = 0, On = 1 }; +enum class LFOWave : int { + Triangle, + Sine, + Pulse75, + Square, + Pulse25, + Pulse12_5, + Ramp, + Saw, + // ARIA extra + RandomSH = 12, +}; enum OpcodeFlags : int { - kIgnoreOOB = 1, + kCanBeNote = 1, kEnforceLowerBound = 1 << 1, kEnforceUpperBound = 1 << 2, - kCanBeNote = 1 << 3, + kNormalizePercent = 1 << 3, + kNormalizeMidi = 1 << 4, + kNormalizeBend = 1 << 5, + kWrapPhase = 1 << 6, + kDb2Mag = 1 << 7, }; template struct OpcodeSpec { - T value; + T defaultValue; Range bounds; int flags; + operator T() const { return defaultValue; } }; namespace Default @@ -66,7 +83,8 @@ namespace Default extern const OpcodeSpec offsetRandom; extern const OpcodeSpec sampleEnd; extern const OpcodeSpec sampleCount; - extern const OpcodeSpec loopRange; + extern const OpcodeSpec loopStart; + extern const OpcodeSpec loopEnd; extern const OpcodeSpec loopCrossfade; extern const OpcodeSpec oscillatorPhase; extern const OpcodeSpec oscillator; @@ -82,11 +100,20 @@ namespace Default extern const OpcodeSpec polyphony; extern const OpcodeSpec notePolyphony; extern const OpcodeSpec key; - extern const OpcodeSpec midi7; - extern const OpcodeSpec float7; - extern const OpcodeSpec bend; - extern const OpcodeSpec normalized; - extern const OpcodeSpec bipolar; + extern const OpcodeSpec loKey; + extern const OpcodeSpec hiKey; + extern const OpcodeSpec loVel; + extern const OpcodeSpec hiVel; + extern const OpcodeSpec loCC; + extern const OpcodeSpec hiCC; + extern const OpcodeSpec loBend; + extern const OpcodeSpec hiBend; + extern const OpcodeSpec loNormalized; + extern const OpcodeSpec hiNormalized; + extern const OpcodeSpec loBipolar; + extern const OpcodeSpec hiBipolar; + extern const OpcodeSpec loChannelAftertouch; + extern const OpcodeSpec hiChannelAftertouch; extern const OpcodeSpec ccNumber; extern const OpcodeSpec curveCC; extern const OpcodeSpec smoothCC; @@ -94,7 +121,8 @@ namespace Default extern const OpcodeSpec checkSustain; extern const OpcodeSpec checkSostenuto; extern const OpcodeSpec sustainThreshold; - extern const OpcodeSpec bpm; + extern const OpcodeSpec loBPM; + extern const OpcodeSpec hiBPM; extern const OpcodeSpec sequence; extern const OpcodeSpec volume; extern const OpcodeSpec volumeMod; @@ -106,9 +134,9 @@ namespace Default extern const OpcodeSpec positionMod; extern const OpcodeSpec width; extern const OpcodeSpec widthMod; - extern const OpcodeSpec crossfadeIn; + extern const OpcodeSpec crossfadeIn; extern const OpcodeSpec crossfadeInNorm; - extern const OpcodeSpec crossfadeOut; + extern const OpcodeSpec crossfadeOut; extern const OpcodeSpec crossfadeOutNorm; extern const OpcodeSpec ampKeytrack; extern const OpcodeSpec ampVeltrack; @@ -152,7 +180,7 @@ namespace Default extern const OpcodeSpec lfoCount; extern const OpcodeSpec lfoSteps; extern const OpcodeSpec lfoStepX; - extern const OpcodeSpec lfoWave; + extern const OpcodeSpec lfoWave; extern const OpcodeSpec lfoOffset; extern const OpcodeSpec lfoRatio; extern const OpcodeSpec lfoScale; diff --git a/src/sfizz/EGDescription.h b/src/sfizz/EGDescription.h index 89edfde2..5bf81ca4 100644 --- a/src/sfizz/EGDescription.h +++ b/src/sfizz/EGDescription.h @@ -66,21 +66,21 @@ struct EGDescription { EGDescription& operator=(const EGDescription&) = default; EGDescription& operator=(EGDescription&&) = default; - float attack { Default::egTime.value }; - float decay { Default::egTime.value }; - float delay { Default::egTime.value }; - float hold { Default::egTime.value }; - float release { Default::egTime.value }; + float attack { Default::egTime }; + float decay { Default::egTime }; + float delay { Default::egTime }; + float hold { Default::egTime }; + float release { Default::egTime }; float start { Default::egPercent.bounds.getStart() }; float sustain { Default::egPercent.bounds.getEnd() }; - float depth { Default::egDepth.value }; - float vel2attack { Default::egTimeMod.value }; - float vel2decay { Default::egTimeMod.value }; - float vel2delay { Default::egTimeMod.value }; - float vel2hold { Default::egTimeMod.value }; - float vel2release { Default::egPercentMod.value }; - float vel2sustain { Default::egPercentMod.value }; - float vel2depth { Default::egVel2Depth.value }; + float depth { Default::egDepth }; + float vel2attack { Default::egTimeMod }; + float vel2decay { Default::egTimeMod }; + float vel2delay { Default::egTimeMod }; + float vel2hold { Default::egTimeMod }; + float vel2release { Default::egPercentMod }; + float vel2sustain { Default::egPercentMod }; + float vel2depth { Default::egVel2Depth }; CCMap ccAttack; CCMap ccDecay; diff --git a/src/sfizz/EQDescription.h b/src/sfizz/EQDescription.h index 246d545b..7860d756 100644 --- a/src/sfizz/EQDescription.h +++ b/src/sfizz/EQDescription.h @@ -14,11 +14,11 @@ namespace sfz { struct EQDescription { - float bandwidth { Default::eqBandwidth.value }; - float frequency { Default::eqFrequency.value }; - float gain { Default::eqGain.value }; - float vel2frequency { Default::eqVel2Frequency.value }; - float vel2gain { Default::eqVel2Gain.value }; + float bandwidth { Default::eqBandwidth }; + float frequency { Default::eqFrequency }; + float gain { Default::eqGain }; + float vel2frequency { Default::eqVel2Frequency }; + float vel2gain { Default::eqVel2Gain }; EqType type { EqType::kEqPeak }; }; } diff --git a/src/sfizz/EQPool.h b/src/sfizz/EQPool.h index 63ba5dde..54567b2f 100644 --- a/src/sfizz/EQPool.h +++ b/src/sfizz/EQPool.h @@ -43,9 +43,9 @@ private: Resources& resources; const EQDescription* description; std::unique_ptr eq; - float baseBandwidth { Default::eqBandwidth.value }; - float baseFrequency { Default::eqFrequency.value }; - float baseGain { Default::eqGain.value }; + float baseBandwidth { Default::eqBandwidth }; + float baseFrequency { Default::eqFrequency }; + float baseGain { Default::eqGain }; bool prepared { false }; ModMatrix::TargetId gainTarget; ModMatrix::TargetId frequencyTarget; diff --git a/src/sfizz/Effects.h b/src/sfizz/Effects.h index 838557a8..8cc5d63f 100644 --- a/src/sfizz/Effects.h +++ b/src/sfizz/Effects.h @@ -179,8 +179,8 @@ private: std::vector> _effects; AudioBuffer _inputs { EffectChannels, config::defaultSamplesPerBlock }; AudioBuffer _outputs { EffectChannels, config::defaultSamplesPerBlock }; - float _gainToMain { Default::effect.value }; - float _gainToMix { Default::effect.value }; + float _gainToMain { Default::effect }; + float _gainToMix { Default::effect }; }; } // namespace sfz diff --git a/src/sfizz/FilePool.cpp b/src/sfizz/FilePool.cpp index b86bf76f..50617169 100644 --- a/src/sfizz/FilePool.cpp +++ b/src/sfizz/FilePool.cpp @@ -255,7 +255,7 @@ absl::optional sfz::FilePool::getFileInformation(const Fil if (!fileId.isReverse()) { if (haveInstrumentInfo && instrumentInfo.loop_count > 0) { returnedValue.hasLoop = true; - returnedValue.loopBegin = instrumentInfo.loops[0].start; + returnedValue.loopStart = instrumentInfo.loops[0].start; returnedValue.loopEnd = min(returnedValue.end, instrumentInfo.loops[0].end - 1); } } else { @@ -297,7 +297,7 @@ bool sfz::FilePool::preloadFile(const FileId& fileId, uint32_t maxOffset) noexce const auto factor = static_cast(oversamplingFactor); fileInformation->sampleRate = factor * static_cast(reader->sampleRate()); fileInformation->end = static_cast(factor * fileInformation->end); - fileInformation->loopBegin = static_cast(factor * fileInformation->loopBegin); + fileInformation->loopStart = static_cast(factor * fileInformation->loopStart); fileInformation->loopEnd = static_cast(factor * fileInformation->loopEnd); auto insertedPair = preloadedFiles.insert_or_assign(fileId, { readFromFile(*reader, framesToLoad, oversamplingFactor), @@ -329,7 +329,7 @@ sfz::FileDataHolder sfz::FilePool::loadFile(const FileId& fileId) noexcept const auto factor = static_cast(oversamplingFactor); fileInformation->sampleRate = factor * static_cast(reader->sampleRate()); fileInformation->end = static_cast(factor * fileInformation->end); - fileInformation->loopBegin = static_cast(factor * fileInformation->loopBegin); + fileInformation->loopStart = static_cast(factor * fileInformation->loopStart); fileInformation->loopEnd = static_cast(factor * fileInformation->loopEnd); auto insertedPair = preloadedFiles.insert_or_assign(fileId, { readFromFile(*reader, frames, oversamplingFactor), @@ -461,7 +461,7 @@ void sfz::FilePool::setOversamplingFactor(sfz::Oversampling factor) noexcept FileInformation& information = preloadedFile.second.information; information.sampleRate *= samplerateChange; information.end = static_cast(samplerateChange * information.end); - information.loopBegin = static_cast(samplerateChange * information.loopBegin); + information.loopStart = static_cast(samplerateChange * information.loopStart); information.loopEnd = static_cast(samplerateChange * information.loopEnd); if (preloadedFile.second.status == FileData::Status::Done) { diff --git a/src/sfizz/FilePool.h b/src/sfizz/FilePool.h index 2c77f6d9..6936fb63 100644 --- a/src/sfizz/FilePool.h +++ b/src/sfizz/FilePool.h @@ -51,10 +51,10 @@ using FileAudioBuffer = AudioBuffer; struct FileInformation { - uint32_t end { Default::sampleEnd.value }; + uint32_t end { Default::sampleEnd }; uint32_t maxOffset { 0 }; - uint32_t loopBegin { Default::loopRange.bounds.getStart() }; - uint32_t loopEnd { Default::loopRange.bounds.getEnd() }; + uint32_t loopStart { Default::loopStart }; + uint32_t loopEnd { Default::loopEnd }; bool hasLoop { false }; double sampleRate { config::defaultSampleRate }; int numChannels { 0 }; diff --git a/src/sfizz/FilterDescription.h b/src/sfizz/FilterDescription.h index 7bdc39b6..612d1e58 100644 --- a/src/sfizz/FilterDescription.h +++ b/src/sfizz/FilterDescription.h @@ -14,13 +14,13 @@ namespace sfz { struct FilterDescription { - float cutoff { Default::filterCutoff.value }; - float resonance { Default::filterCutoff.value }; - float gain { Default::filterGain.value }; - int keytrack { Default::filterKeytrack.value }; - uint8_t keycenter { Default::key.value }; - int veltrack { Default::filterVeltrack.value }; - float random { Default::filterRandom.value }; + float cutoff { Default::filterCutoff }; + float resonance { Default::filterCutoff }; + float gain { Default::filterGain }; + int keytrack { Default::filterKeytrack }; + uint8_t keycenter { Default::key }; + int veltrack { Default::filterVeltrack }; + float random { Default::filterRandom }; FilterType type { FilterType::kFilterLpf2p }; }; } diff --git a/src/sfizz/FilterPool.h b/src/sfizz/FilterPool.h index 13ecbb94..ab761124 100644 --- a/src/sfizz/FilterPool.h +++ b/src/sfizz/FilterPool.h @@ -22,7 +22,7 @@ public: * @param noteNumber the triggering note number * @param velocity the triggering note velocity/value */ - void setup(const Region& region, unsigned filterId, int noteNumber = static_cast(Default::key.value), float velocity = 0); + void setup(const Region& region, unsigned filterId, int noteNumber = static_cast(Default::key), float velocity = 0); /** * @brief Process a block of stereo inputs * @@ -45,9 +45,9 @@ private: Resources& resources; const FilterDescription* description; std::unique_ptr filter; - float baseCutoff { Default::filterCutoff.value }; - float baseResonance { Default::filterResonance.value }; - float baseGain { Default::filterGain.value }; + float baseCutoff { Default::filterCutoff }; + float baseResonance { Default::filterResonance }; + float baseGain { Default::filterGain }; ModMatrix::TargetId gainTarget; ModMatrix::TargetId cutoffTarget; ModMatrix::TargetId resonanceTarget; diff --git a/src/sfizz/FlexEGDescription.h b/src/sfizz/FlexEGDescription.h index 7788329d..8ba22069 100644 --- a/src/sfizz/FlexEGDescription.h +++ b/src/sfizz/FlexEGDescription.h @@ -18,24 +18,24 @@ namespace FlexEGs { }; struct FlexEGPoint { - float time { Default::flexEGPointTime.value }; // duration until next step (s) - float level { Default::flexEGPointLevel.value }; // normalized amplitude + float time { Default::flexEGPointTime }; // duration until next step (s) + float level { Default::flexEGPointLevel }; // normalized amplitude void setShape(float shape); float shape() const noexcept { return shape_; } const Curve& curve() const; private: - float shape_ { Default::flexEGPointShape.value }; // 0: linear, positive: exp, negative: log + float shape_ { Default::flexEGPointShape }; // 0: linear, positive: exp, negative: log std::shared_ptr shapeCurve_; }; struct FlexEGDescription { - int dynamic { Default::flexEGDynamic.value }; // whether parameters can be modulated while EG runs - int sustain { Default::flexEGSustain.value }; // index of the sustain point (default to 0 in ARIA) + int dynamic { Default::flexEGDynamic }; // whether parameters can be modulated while EG runs + int sustain { Default::flexEGSustain }; // index of the sustain point (default to 0 in ARIA) std::vector points; // ARIA - bool ampeg { Default::flexEGAmpeg.value }; // replaces the SFZv1 AmpEG (lowest with this bit wins) + bool ampeg { Default::flexEGAmpeg }; // replaces the SFZv1 AmpEG (lowest with this bit wins) }; } // namespace sfz diff --git a/src/sfizz/LFODescription.h b/src/sfizz/LFODescription.h index ea312bca..82859779 100644 --- a/src/sfizz/LFODescription.h +++ b/src/sfizz/LFODescription.h @@ -11,34 +11,21 @@ namespace sfz { -enum class LFOWave : int { - Triangle, - Sine, - Pulse75, - Square, - Pulse25, - Pulse12_5, - Ramp, - Saw, - // ARIA extra - RandomSH = 12, -}; - struct LFODescription { LFODescription(); ~LFODescription(); static const LFODescription& getDefault(); - float freq { Default::lfoFreq.value }; // lfoN_freq - float beats { Default::lfoBeats.value }; // lfoN_beats - float phase0 { Default::lfoPhase.value }; // lfoN_phase - float delay { Default::lfoDelay.value }; // lfoN_delay - float fade { Default::lfoFade.value }; // lfoN_fade - unsigned count { Default::lfoCount.value }; // lfoN_count + float freq { Default::lfoFreq }; // lfoN_freq + float beats { Default::lfoBeats }; // lfoN_beats + float phase0 { Default::lfoPhase }; // lfoN_phase + float delay { Default::lfoDelay }; // lfoN_delay + float fade { Default::lfoFade }; // lfoN_fade + unsigned count { Default::lfoCount }; // lfoN_count struct Sub { - LFOWave wave { static_cast(Default::lfoWave.value) }; // lfoN_wave[X] - float offset { Default::lfoOffset.value }; // lfoN_offset[X] - float ratio { Default::lfoRatio.value }; // lfoN_ratio[X] - float scale { Default::lfoScale.value }; // lfoN_scale[X] + LFOWave wave { Default::lfoWave }; // lfoN_wave[X] + float offset { Default::lfoOffset }; // lfoN_offset[X] + float ratio { Default::lfoRatio }; // lfoN_ratio[X] + float scale { Default::lfoScale }; // lfoN_scale[X] }; struct StepSequence { std::vector steps {}; // lfoN_stepX - normalized to unity diff --git a/src/sfizz/Opcode.cpp b/src/sfizz/Opcode.cpp index 7f5f59d1..a3e747fc 100644 --- a/src/sfizz/Opcode.cpp +++ b/src/sfizz/Opcode.cpp @@ -5,6 +5,7 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #include "Opcode.h" +#include "LFODescription.h" #include "StringViewHelpers.h" #include "absl/strings/ascii.h" #include "absl/strings/match.h" @@ -141,30 +142,22 @@ absl::optional readInt_(OpcodeSpec spec, absl::string_view v) if (spec.flags & kEnforceUpperBound) return spec.bounds.getEnd(); - if (spec.flags & kIgnoreOOB) - return {}; - } - - if (returnedValue < static_cast(spec.bounds.getStart())) { + return {}; + } else if (returnedValue < static_cast(spec.bounds.getStart())) { if (spec.flags & kEnforceLowerBound) return spec.bounds.getStart(); - if (spec.flags & kIgnoreOOB) - return {}; + return {}; } - T castValue = static_cast(returnedValue); - if ((castValue != returnedValue) & kIgnoreOOB) - return {}; - - return castValue; + return returnedValue; } #define INSTANTIATE_FOR_INTEGRAL(T) \ template <> \ - absl::optional Opcode::read(OpcodeSpec spec) const \ + T Opcode::read(OpcodeSpec spec) const \ { \ - return readInt_(spec, value); \ + return readInt_(spec, value).value_or(spec.defaultValue); \ } INSTANTIATE_FOR_INTEGRAL(uint8_t) @@ -198,30 +191,37 @@ absl::optional readFloat_(OpcodeSpec spec, absl::string_view v) if (!absl::SimpleAtof(v, &returnedValue)) return absl::nullopt; - if (returnedValue > static_cast(spec.bounds.getEnd())) { + if (spec.flags & kWrapPhase) + returnedValue = wrapPhase(returnedValue); + else if (returnedValue > static_cast(spec.bounds.getEnd())) { if (spec.flags & kEnforceUpperBound) return spec.bounds.getEnd(); - if (spec.flags & kIgnoreOOB) - return {}; - } - - if (returnedValue < static_cast(spec.bounds.getStart())) { + return {}; + } else if (returnedValue < static_cast(spec.bounds.getStart())) { if (spec.flags & kEnforceLowerBound) return spec.bounds.getStart(); - if (spec.flags & kIgnoreOOB) - return {}; + return {}; } + if (spec.flags & kNormalizeMidi) + returnedValue = normalize7Bits(returnedValue); + else if (spec.flags & kNormalizePercent) + returnedValue = normalizePercents(returnedValue); + else if (spec.flags & kNormalizeBend) + returnedValue = normalizeBend(returnedValue); + else if (spec.flags & kDb2Mag) + returnedValue = db2mag(returnedValue); + return returnedValue; } #define INSTANTIATE_FOR_FLOATING_POINT(T) \ template <> \ - absl::optional Opcode::read(OpcodeSpec spec) const \ + T Opcode::read(OpcodeSpec spec) const \ { \ - return readFloat_(spec, value); \ + return readFloat_(spec, value).value_or(spec.defaultValue); \ } INSTANTIATE_FOR_FLOATING_POINT(float) @@ -288,24 +288,21 @@ absl::optional readBooleanFromOpcode(const Opcode& opcode) // ARIA-style booleans? (seen in egN_dynamic=1 for example) // TODO check this const OpcodeSpec fullInt64 { 0, Range::wholeRange(), 0 }; - if (auto value = opcode.read(fullInt64)) - return *value != 0; - - return absl::nullopt; + return opcode.read(fullInt64); } template <> -absl::optional Opcode::read(OpcodeSpec) const +OscillatorEnabled Opcode::read(OpcodeSpec spec) const { auto v = readBooleanFromOpcode(*this); if (!v) - return absl::nullopt; + return spec.defaultValue; return *v ? OscillatorEnabled::On : OscillatorEnabled::Off; } template <> -absl::optional Opcode::read(OpcodeSpec) const +Trigger Opcode::read(OpcodeSpec spec) const { switch (hash(value)) { case hash("attack"): return Trigger::attack; @@ -316,11 +313,11 @@ absl::optional Opcode::read(OpcodeSpec) const } DBG("Unknown trigger value: " << value); - return absl::nullopt; + return spec.defaultValue; } template <> -absl::optional Opcode::read(OpcodeSpec) const +CrossfadeCurve Opcode::read(OpcodeSpec spec) const { switch (hash(value)) { case hash("power"): return CrossfadeCurve::power; @@ -328,11 +325,11 @@ absl::optional Opcode::read(OpcodeSpec) const } DBG("Unknown crossfade power curve: " << value); - return absl::nullopt; + return spec.defaultValue; } template <> -absl::optional Opcode::read(OpcodeSpec) const +OffMode Opcode::read(OpcodeSpec spec) const { switch (hash(value)) { case hash("fast"): return OffMode::fast; @@ -341,11 +338,11 @@ absl::optional Opcode::read(OpcodeSpec) const } DBG("Unknown off mode: " << value); - return absl::nullopt; + return spec.defaultValue; } template <> -absl::optional Opcode::read(OpcodeSpec) const +FilterType Opcode::read(OpcodeSpec spec) const { switch (hash(value)) { case hash("lpf_1p"): return kFilterLpf1p; @@ -374,11 +371,11 @@ absl::optional Opcode::read(OpcodeSpec) const } DBG("Unknown filter type: " << value); - return kFilterNone; + return spec.defaultValue; } template <> -absl::optional Opcode::read(OpcodeSpec) const +EqType Opcode::read(OpcodeSpec spec) const { switch (hash(value)) { case hash("peak"): return kEqPeak; @@ -387,11 +384,11 @@ absl::optional Opcode::read(OpcodeSpec) const } DBG("Unknown EQ type: " << value); - return kEqNone; + return spec.defaultValue; } template <> -absl::optional Opcode::read(OpcodeSpec) const +VelocityOverride Opcode::read(OpcodeSpec spec) const { switch (hash(value)) { case hash("current"): return VelocityOverride::current; @@ -399,11 +396,11 @@ absl::optional Opcode::read(OpcodeSpec) cons } DBG("Unknown velocity override: " << value); - return absl::nullopt; + return spec.defaultValue; } template <> -absl::optional Opcode::read(OpcodeSpec) const +SelfMask Opcode::read(OpcodeSpec spec) const { switch (hash(value)) { case hash("on"): @@ -412,13 +409,25 @@ absl::optional Opcode::read(OpcodeSpec) const } DBG("Unknown velocity override: " << value); - return absl::nullopt; + return spec.defaultValue; } template <> -absl::optional Opcode::read(OpcodeSpec) const +bool Opcode::read(OpcodeSpec spec) const { - return readBooleanFromOpcode(*this); + return readBooleanFromOpcode(*this).value_or(spec.defaultValue); +} + +template <> +LFOWave Opcode::read(OpcodeSpec spec) const +{ + const OpcodeSpec intSpec { + static_cast(spec.defaultValue), + Range(static_cast(spec.bounds.getStart()), static_cast(spec.bounds.getEnd())), + 0 + }; + int value = read(intSpec); + return static_cast(value); } } // namespace sfz diff --git a/src/sfizz/Opcode.h b/src/sfizz/Opcode.h index 51ff6088..3df4ed08 100644 --- a/src/sfizz/Opcode.h +++ b/src/sfizz/Opcode.h @@ -102,7 +102,7 @@ struct Opcode { } template - absl::optional read(OpcodeSpec spec) const; + T read(OpcodeSpec spec) const; private: static OpcodeCategory identifyCategory(absl::string_view name); diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 70d071ef..0f86c802 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -42,7 +42,7 @@ sfz::Region::Region(int regionNumber, const MidiState& midiState, absl::string_v gainToEffect.push_back(1.0); // contribute 100% into the main bus // Default amplitude release - amplitudeEG.release = Default::egRelease.value; + amplitudeEG.release = Default::egRelease; } bool sfz::Region::parseOpcode(const Opcode& rawOpcode) @@ -57,21 +57,19 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) case hash(x "_stepcc&"): \ case hash(x "_smoothcc&") - #define LFO_EG_filter_EQ_target(sourceKey, targetKey, spec) \ - { \ - const auto number = opcode.parameters.front(); \ - if (number == 0) \ - return false; \ - \ - const auto index = opcode.parameters.size() == 2 ? opcode.parameters.back() - 1 : 0; \ - if (!extendIfNecessary(filters, index + 1, Default::numFilters)) \ - return false; \ - \ - if (auto value = opcode.read(spec)) { \ - const ModKey source = ModKey::createNXYZ(sourceKey, id, number - 1); \ - const ModKey target = ModKey::createNXYZ(targetKey, id, index); \ - getOrCreateConnection(source, target).sourceDepth = *value; \ - } \ + #define LFO_EG_filter_EQ_target(sourceKey, targetKey, spec) \ + { \ + const auto number = opcode.parameters.front(); \ + if (number == 0) \ + return false; \ + \ + const auto index = opcode.parameters.size() == 2 ? opcode.parameters.back() - 1 : 0; \ + if (!extendIfNecessary(filters, index + 1, Default::numFilters)) \ + return false; \ + \ + const ModKey source = ModKey::createNXYZ(sourceKey, id, number - 1); \ + const ModKey target = ModKey::createNXYZ(targetKey, id, index); \ + getOrCreateConnection(source, target).sourceDepth = opcode.read(spec); \ } // Sound source: sample playback @@ -91,41 +89,34 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) } break; case hash("sample_quality"): - { - if (opcode.value == "-1") - sampleQuality.reset(); - else if (auto value = opcode.read(Default::sampleQuality)) - sampleQuality = *value; - break; - } + sampleQuality = opcode.read(Default::sampleQuality); break; case hash("direction"): *sampleId = sampleId->reversed(opcode.value == "reverse"); break; case hash("delay"): - delay = opcode.read(Default::delay).value_or(delay); + delay = opcode.read(Default::delay); break; case hash("delay_random"): - delayRandom = opcode.read(Default::delayRandom).value_or(delayRandom); + delayRandom = opcode.read(Default::delayRandom); break; case hash("offset"): - offset = opcode.read(Default::offset).value_or(offset); + offset = opcode.read(Default::offset); break; case hash("offset_random"): - offsetRandom = opcode.read(Default::offsetRandom).value_or(offsetRandom); + offsetRandom = opcode.read(Default::offsetRandom); break; case hash("offset_oncc&"): // also offset_cc& if (opcode.parameters.back() > config::numCCs) return false; - if (auto value = opcode.read(Default::offsetMod)) - offsetCC[opcode.parameters.back()] = *value; + + offsetCC[opcode.parameters.back()] = opcode.read(Default::offsetMod); break; case hash("end"): - sampleEnd = opcode.read(Default::sampleEnd).value_or(sampleEnd); + sampleEnd = opcode.read(Default::sampleEnd); break; case hash("count"): - if (auto value = opcode.read(Default::sampleCount)) - sampleCount = *value; + sampleCount = opcode.read(Default::sampleCount); break; case hash("loop_mode"): // also loopmode switch (hash(opcode.value)) { @@ -146,76 +137,71 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) } break; case hash("loop_end"): // also loopend - if (auto value = opcode.read(Default::loopRange)) - loopRange.setEnd(*value); + loopRange.setEnd(opcode.read(Default::loopEnd)); break; case hash("loop_start"): // also loopstart - if (auto value = opcode.read(Default::loopRange)) - loopRange.setStart(*value); + loopRange.setStart(opcode.read(Default::loopStart)); break; case hash("loop_crossfade"): - loopCrossfade = opcode.read(Default::loopCrossfade).value_or(loopCrossfade); + loopCrossfade = opcode.read(Default::loopCrossfade); break; // Wavetable oscillator case hash("oscillator_phase"): - if (auto value = opcode.read(Default::oscillatorPhase)) - oscillatorPhase = (*value >= 0) ? wrapPhase(*value) : -1.0f; + { + auto phase = opcode.read(Default::oscillatorPhase); + oscillatorPhase = (phase >= 0) ? wrapPhase(phase) : -1.0f; + } break; case hash("oscillator"): - oscillatorEnabled = opcode.read(Default::oscillator).value_or(oscillatorEnabled); + oscillatorEnabled = opcode.read(Default::oscillator); break; case hash("oscillator_mode"): - oscillatorMode = opcode.read(Default::oscillatorMode).value_or(oscillatorMode); + oscillatorMode = opcode.read(Default::oscillatorMode); break; case hash("oscillator_multi"): - oscillatorMulti = opcode.read(Default::oscillatorMulti).value_or(oscillatorMulti); + oscillatorMulti = opcode.read(Default::oscillatorMulti); break; case hash("oscillator_detune"): - oscillatorDetune = opcode.read(Default::oscillatorDetune).value_or(oscillatorDetune); + oscillatorDetune = opcode.read(Default::oscillatorDetune); break; case_any_ccN("oscillator_detune"): processGenericCc(opcode, Default::oscillatorDetuneMod, ModKey::createNXYZ(ModId::OscillatorDetune, id)); break; case hash("oscillator_mod_depth"): - if (auto value = opcode.read(Default::oscillatorModDepth)) - oscillatorModDepth = normalizePercents(*value); + oscillatorModDepth = opcode.read(Default::oscillatorModDepth); break; case_any_ccN("oscillator_mod_depth"): processGenericCc(opcode, Default::oscillatorModDepthMod, ModKey::createNXYZ(ModId::OscillatorModDepth, id)); break; case hash("oscillator_quality"): - if (opcode.value == "-1") - oscillatorQuality.reset(); - else if (auto value = opcode.read(Default::oscillatorQuality)) - oscillatorQuality = *value; + oscillatorQuality = opcode.read(Default::oscillatorQuality); break; // Instrument settings: voice lifecycle case hash("group"): // also polyphony_group - group = opcode.read(Default::group).value_or(group); + group = opcode.read(Default::group); break; case hash("off_by"): // also offby if (opcode.value == "-1") offBy.reset(); - else if (auto value = opcode.read(Default::group)) - offBy = *value; + else + offBy = opcode.read(Default::group); break; case hash("off_mode"): // also offmode - offMode = opcode.read(Default::offMode).value_or(offMode); + offMode = opcode.read(Default::offMode); break; case hash("off_time"): offMode = OffMode::time; - offTime = opcode.read(Default::offTime).value_or(offTime); + offTime = opcode.read(Default::offTime); break; case hash("polyphony"): - polyphony = opcode.read(Default::polyphony).value_or(polyphony); + polyphony = opcode.read(Default::polyphony); break; case hash("note_polyphony"): - if (auto value = opcode.read(Default::notePolyphony)) - notePolyphony = *value; + notePolyphony = opcode.read(Default::notePolyphony); break; case hash("note_selfmask"): switch (hash(opcode.value)) { @@ -230,98 +216,96 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) } break; case hash("rt_dead"): - rtDead = opcode.read(Default::rtDead).value_or(rtDead); + rtDead = opcode.read(Default::rtDead); break; // Region logic: key mapping case hash("lokey"): - if (auto value = opcode.read(Default::key)) { - triggerOnNote = true; - keyRange.setStart(*value); - } + triggerOnNote = true; + keyRange.setStart(opcode.read(Default::loKey)); break; case hash("hikey"): triggerOnNote = (opcode.value != "-1"); - if (auto value = opcode.read(Default::key)) - keyRange.setEnd(*value); + keyRange.setEnd(opcode.read(Default::hiKey)); break; case hash("key"): triggerOnNote = (opcode.value != "-1"); - if (auto value = opcode.read(Default::key)) { - keyRange.setStart(*value); - keyRange.setEnd(*value); - pitchKeycenter = *value; + { + auto value = opcode.read(Default::key); + keyRange.setStart(value); + keyRange.setEnd(value); + pitchKeycenter = value; } break; case hash("lovel"): - if (auto value = opcode.read(Default::midi7)) - velocityRange.setStart(normalizeVelocity(*value)); + velocityRange.setStart(opcode.read(Default::loVel)); break; case hash("hivel"): - if (auto value = opcode.read(Default::midi7)) - velocityRange.setEnd(normalizeVelocity(*value)); + velocityRange.setEnd(opcode.read(Default::hiVel)); break; // Region logic: MIDI conditions case hash("lobend"): - if (auto value = opcode.read(Default::bend)) - bendRange.setStart(normalizeBend(*value)); + bendRange.setStart(opcode.read(Default::loBend)); break; case hash("hibend"): - if (auto value = opcode.read(Default::bend)) - bendRange.setEnd(normalizeBend(*value)); + bendRange.setEnd(opcode.read(Default::hiBend)); break; case hash("locc&"): if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::midi7)) - ccConditions[opcode.parameters.back()].setStart(normalizeCC(*value)); + ccConditions[opcode.parameters.back()].setStart( + opcode.read(Default::loCC) + ); break; case hash("hicc&"): if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::midi7)) - ccConditions[opcode.parameters.back()].setEnd(normalizeCC(*value)); + ccConditions[opcode.parameters.back()].setEnd( + opcode.read(Default::hiCC) + ); break; case hash("lohdcc&"): // also lorealcc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::normalized)) - ccConditions[opcode.parameters.back()].setStart(*value); + ccConditions[opcode.parameters.back()].setStart( + opcode.read(Default::loNormalized) + ); break; case hash("hihdcc&"): // also hirealcc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::normalized)) - ccConditions[opcode.parameters.back()].setEnd(*value); + ccConditions[opcode.parameters.back()].setEnd( + opcode.read(Default::hiNormalized) + ); break; case hash("sw_lokey"): // fallthrough case hash("sw_hikey"): break; case hash("sw_last"): - if (auto value = opcode.read(Default::key)) { - if (!lastKeyswitchRange) { - lastKeyswitch = *value; - keySwitched = false; - } + if (!lastKeyswitchRange) { + lastKeyswitch = opcode.read(Default::key); + keySwitched = false; } break; case hash("sw_lolast"): - if (auto value = opcode.read(Default::key)) { + { + auto value = opcode.read(Default::key); if (!lastKeyswitchRange) - lastKeyswitchRange.emplace(*value, *value); + lastKeyswitchRange.emplace(value, value); else - lastKeyswitchRange->setStart(*value); + lastKeyswitchRange->setStart(value); keySwitched = false; lastKeyswitch = absl::nullopt; } break; case hash("sw_hilast"): - if (auto value = opcode.read(Default::key)) { + { + auto value = opcode.read(Default::key); if (!lastKeyswitchRange) - lastKeyswitchRange.emplace(*value, *value); + lastKeyswitchRange.emplace(value, value); else - lastKeyswitchRange->setEnd(*value); + lastKeyswitchRange->setEnd(value); keySwitched = false; lastKeyswitch = absl::nullopt; @@ -331,256 +315,228 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) keyswitchLabel = opcode.value; break; case hash("sw_down"): - if (auto value = opcode.read(Default::key)) { - downKeyswitch = *value; - keySwitched = false; - } + downKeyswitch = opcode.read(Default::key); + keySwitched = false; break; case hash("sw_up"): - if (auto value = opcode.read(Default::key)) { - upKeyswitch = *value; - } + upKeyswitch = opcode.read(Default::key); break; case hash("sw_previous"): - if (auto value = opcode.read(Default::key)) { - previousKeyswitch = *value; - previousKeySwitched = false; - } + previousKeyswitch = opcode.read(Default::key); + previousKeySwitched = false; break; case hash("sw_vel"): velocityOverride = - opcode.read(Default::velocityOverride).value_or(velocityOverride); + opcode.read(Default::velocityOverride); break; case hash("sustain_cc"): - sustainCC = opcode.read(Default::sustainCC).value_or(sustainCC); + sustainCC = opcode.read(Default::sustainCC); break; case hash("sustain_lo"): - if (auto value = opcode.read(Default::float7)) - sustainThreshold = normalizeCC(*value); + sustainThreshold = normalizeCC(opcode.read(Default::sustainThreshold)); break; case hash("sustain_sw"): - checkSustain = opcode.read(Default::checkSustain).value_or(checkSustain); + checkSustain = opcode.read(Default::checkSustain); break; case hash("sostenuto_sw"): - checkSostenuto = opcode.read(Default::checkSostenuto).value_or(checkSostenuto); + checkSostenuto = opcode.read(Default::checkSostenuto); break; // Region logic: internal conditions case hash("lochanaft"): - if (auto value = opcode.read(Default::midi7)) - aftertouchRange.setStart(*value); + aftertouchRange.setStart(opcode.read(Default::loChannelAftertouch)); break; case hash("hichanaft"): - if (auto value = opcode.read(Default::midi7)) - aftertouchRange.setEnd(*value); + aftertouchRange.setEnd(opcode.read(Default::hiChannelAftertouch)); break; case hash("lobpm"): - if (auto value = opcode.read(Default::bpm)) - bpmRange.setStart(*value); + bpmRange.setStart(opcode.read(Default::loBPM)); break; case hash("hibpm"): - if (auto value = opcode.read(Default::bpm)) - bpmRange.setEnd(*value); + bpmRange.setEnd(opcode.read(Default::hiBPM)); break; case hash("lorand"): - if (auto value = opcode.read(Default::normalized)) - randRange.setStart(*value); + randRange.setStart(opcode.read(Default::loNormalized)); break; case hash("hirand"): - if (auto value = opcode.read(Default::normalized)) - randRange.setEnd(*value); + randRange.setEnd(opcode.read(Default::hiNormalized)); break; case hash("seq_length"): - sequenceLength = opcode.read(Default::sequence).value_or(sequenceLength); + sequenceLength = opcode.read(Default::sequence); break; case hash("seq_position"): - sequencePosition = opcode.read(Default::sequence).value_or(sequencePosition); + sequencePosition = opcode.read(Default::sequence); sequenceSwitched = false; break; // Region logic: triggers case hash("trigger"): - trigger = opcode.read(Default::trigger).value_or(trigger); + trigger = opcode.read(Default::trigger); break; case hash("start_locc&"): // also on_locc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::midi7)) { - triggerOnCC = true; - ccTriggers[opcode.parameters.back()].setStart(normalizeCC(*value)); - } + triggerOnCC = true; + ccTriggers[opcode.parameters.back()].setStart( + opcode.read(Default::loCC) + ); break; case hash("start_hicc&"): // also on_hicc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::midi7)) { - triggerOnCC = true; - ccTriggers[opcode.parameters.back()].setEnd(normalizeCC(*value)); - } + triggerOnCC = true; + ccTriggers[opcode.parameters.back()].setEnd( + opcode.read(Default::hiCC) + ); break; case hash("start_lohdcc&"): // also on_lohdcc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::normalized)) { - triggerOnCC = true; - ccTriggers[opcode.parameters.back()].setStart(*value); - } + triggerOnCC = true; + ccTriggers[opcode.parameters.back()].setStart( + opcode.read(Default::loNormalized) + ); break; case hash("start_hihdcc&"): // also on_hihdcc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::normalized)) { - triggerOnCC = true; - ccTriggers[opcode.parameters.back()].setEnd(*value); - } + ccTriggers[opcode.parameters.back()].setEnd( + opcode.read(Default::hiNormalized) + ); break; // Performance parameters: amplifier case hash("volume"): // also gain - volume = opcode.read(Default::volume).value_or(volume); + volume = opcode.read(Default::volume); break; case_any_ccN("volume"): // also gain processGenericCc(opcode, Default::volumeMod, ModKey::createNXYZ(ModId::Volume, id)); break; case hash("amplitude"): - if (auto value = opcode.read(Default::amplitude)) - amplitude = normalizePercents(*value); + amplitude = opcode.read(Default::amplitude); break; case_any_ccN("amplitude"): processGenericCc(opcode, Default::amplitudeMod, ModKey::createNXYZ(ModId::Amplitude, id)); break; case hash("pan"): - if (auto value = opcode.read(Default::pan)) - pan = normalizePercents(*value); + pan = opcode.read(Default::pan); break; case_any_ccN("pan"): processGenericCc(opcode, Default::panMod, ModKey::createNXYZ(ModId::Pan, id)); break; case hash("position"): - if (auto value = opcode.read(Default::position)) - position = normalizePercents(*value); + position = opcode.read(Default::position); break; case_any_ccN("position"): processGenericCc(opcode, Default::positionMod, ModKey::createNXYZ(ModId::Position, id)); break; case hash("width"): - if (auto value = opcode.read(Default::width)) - width = normalizePercents(*value); + width = opcode.read(Default::width); break; case_any_ccN("width"): processGenericCc(opcode, Default::widthMod, ModKey::createNXYZ(ModId::Width, id)); break; case hash("amp_keycenter"): - ampKeycenter = opcode.read(Default::key).value_or(ampKeycenter); + ampKeycenter = opcode.read(Default::key); break; case hash("amp_keytrack"): - ampKeytrack = opcode.read(Default::ampKeytrack).value_or(ampKeytrack); + ampKeytrack = opcode.read(Default::ampKeytrack); break; case hash("amp_veltrack"): - if (auto value = opcode.read(Default::ampVeltrack)) - ampVeltrack = normalizePercents(*value); + ampVeltrack = opcode.read(Default::ampVeltrack); break; case hash("amp_random"): - ampRandom = opcode.read(Default::ampRandom).value_or(ampRandom); + ampRandom = opcode.read(Default::ampRandom); break; case hash("amp_velcurve_&"): { - auto value = opcode.read(Default::ampVelcurve); if (opcode.parameters.back() > 127) return false; const auto inputVelocity = static_cast(opcode.parameters.back()); - if (value) - velocityPoints.emplace_back(inputVelocity, *value); + velocityPoints.emplace_back(inputVelocity, opcode.read(Default::ampVelcurve)); } break; case hash("xfin_lokey"): - if (auto value = opcode.read(Default::key)) - crossfadeKeyInRange.setStart(*value); + crossfadeKeyInRange.setStart(opcode.read(Default::loKey)); break; case hash("xfin_hikey"): - if (auto value = opcode.read(Default::key)) - crossfadeKeyInRange.setEnd(*value); + crossfadeKeyInRange.setEnd(opcode.read(Default::hiKey)); break; case hash("xfout_lokey"): - if (auto value = opcode.read(Default::key)) - crossfadeKeyOutRange.setStart(*value); + crossfadeKeyOutRange.setStart(opcode.read(Default::loKey)); break; case hash("xfout_hikey"): - if (auto value = opcode.read(Default::key)) - crossfadeKeyOutRange.setEnd(*value); + crossfadeKeyOutRange.setEnd(opcode.read(Default::hiKey)); break; case hash("xfin_lovel"): - if (auto value = opcode.read(Default::crossfadeIn)) - crossfadeVelInRange.setStart(normalizeVelocity(*value)); + crossfadeVelInRange.setStart(opcode.read(Default::loVel)); break; case hash("xfin_hivel"): - if (auto value = opcode.read(Default::crossfadeIn)) - crossfadeVelInRange.setEnd(normalizeVelocity(*value)); + crossfadeVelInRange.setEnd(opcode.read(Default::hiVel)); break; case hash("xfout_lovel"): - if (auto value = opcode.read(Default::crossfadeOut)) - crossfadeVelOutRange.setStart(normalizeVelocity(*value)); + crossfadeVelOutRange.setStart(opcode.read(Default::loVel)); break; case hash("xfout_hivel"): - if (auto value = opcode.read(Default::crossfadeOut)) - crossfadeVelOutRange.setEnd(normalizeVelocity(*value)); + crossfadeVelOutRange.setEnd(opcode.read(Default::hiVel)); break; case hash("xf_keycurve"): - crossfadeKeyCurve = opcode.read(Default::crossfadeCurve).value_or(crossfadeKeyCurve); + crossfadeKeyCurve = opcode.read(Default::crossfadeCurve); break; case hash("xf_velcurve"): - crossfadeVelCurve = opcode.read(Default::crossfadeCurve).value_or(crossfadeVelCurve); + crossfadeVelCurve = opcode.read(Default::crossfadeCurve); break; case hash("xfin_locc&"): if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::crossfadeIn)) - crossfadeCCInRange[opcode.parameters.back()].setStart(normalizeCC(*value)); + crossfadeCCInRange[opcode.parameters.back()].setStart( + opcode.read(Default::loCC) + ); break; case hash("xfin_hicc&"): if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::crossfadeIn)) - crossfadeCCInRange[opcode.parameters.back()].setEnd(normalizeCC(*value)); + crossfadeCCInRange[opcode.parameters.back()].setEnd( + opcode.read(Default::loCC) + ); break; case hash("xfout_locc&"): if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::crossfadeOut)) - crossfadeCCOutRange[opcode.parameters.back()].setStart(normalizeCC(*value)); + crossfadeCCOutRange[opcode.parameters.back()].setStart( + opcode.read(Default::loCC) + ); break; case hash("xfout_hicc&"): if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::crossfadeOut)) - crossfadeCCOutRange[opcode.parameters.back()].setEnd(normalizeCC(*value)); + crossfadeCCOutRange[opcode.parameters.back()].setEnd( + opcode.read(Default::loCC) + ); break; case hash("xf_cccurve"): - crossfadeCCCurve = opcode.read(Default::crossfadeCurve).value_or(crossfadeCCCurve); + crossfadeCCCurve = opcode.read(Default::crossfadeCurve); break; case hash("rt_decay"): - rtDecay = opcode.read(Default::rtDecay).value_or(rtDecay); + rtDecay = opcode.read(Default::rtDecay); break; case hash("global_amplitude"): - if (auto value = opcode.read(Default::amplitude)) - globalAmplitude = normalizePercents(*value); + globalAmplitude = opcode.read(Default::amplitude); break; case hash("master_amplitude"): - if (auto value = opcode.read(Default::amplitude)) - masterAmplitude = normalizePercents(*value); + masterAmplitude = opcode.read(Default::amplitude); break; case hash("group_amplitude"): - if (auto value = opcode.read(Default::amplitude)) - groupAmplitude = normalizePercents(*value); + groupAmplitude = opcode.read(Default::amplitude); break; case hash("global_volume"): - globalVolume = opcode.read(Default::volume).value_or(globalVolume); + globalVolume = opcode.read(Default::volume); break; case hash("master_volume"): - masterVolume = opcode.read(Default::volume).value_or(masterVolume); + masterVolume = opcode.read(Default::volume); break; case hash("group_volume"): - groupVolume = opcode.read(Default::volume).value_or(groupVolume); + groupVolume = opcode.read(Default::volume); break; // Performance parameters: filters @@ -589,8 +545,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.empty() ? 0 : (opcode.parameters.back() - 1); if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - if (auto value = opcode.read(Default::filterCutoff)) - filters[filterIndex].cutoff = *value; + filters[filterIndex].cutoff = opcode.read(Default::filterCutoff); } break; case hash("resonance&"): // also resonance @@ -598,8 +553,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.empty() ? 0 : (opcode.parameters.back() - 1); if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - if (auto value = opcode.read(Default::filterResonance)) - filters[filterIndex].resonance = *value; + filters[filterIndex].resonance = opcode.read(Default::filterResonance); } break; case_any_ccN("cutoff&"): // also cutoff_oncc&, cutoff_cc&, cutoff&_cc& @@ -625,8 +579,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - if (auto value = opcode.read(Default::filterKeytrack)) - filters[filterIndex].keytrack = *value; + filters[filterIndex].keytrack = opcode.read(Default::filterKeytrack); } break; case hash("fil&_keycenter"): // also fil_keycenter @@ -634,8 +587,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - if (auto value = opcode.read(Default::key)) - filters[filterIndex].keycenter = *value; + filters[filterIndex].keycenter = opcode.read(Default::key); } break; case hash("fil&_veltrack"): // also fil_veltrack @@ -643,8 +595,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - if (auto value = opcode.read(Default::filterVeltrack)) - filters[filterIndex].veltrack = *value; + filters[filterIndex].veltrack = opcode.read(Default::filterVeltrack); } break; case hash("fil&_random"): // also fil_random, cutoff_random, cutoff&_random @@ -652,8 +603,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - if (auto value = opcode.read(Default::filterRandom)) - filters[filterIndex].random = *value; + filters[filterIndex].random = opcode.read(Default::filterRandom); } break; case hash("fil&_gain"): // also fil_gain @@ -661,8 +611,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto filterIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - if (auto value = opcode.read(Default::filterGain)) - filters[filterIndex].gain = *value; + filters[filterIndex].gain = opcode.read(Default::filterGain); } break; case_any_ccN("fil&_gain"): // also fil_gain_oncc& @@ -680,8 +629,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(filters, filterIndex + 1, Default::numFilters)) return false; - filters[filterIndex].type = - opcode.read(Default::filter).value_or(filters[filterIndex].type); + filters[filterIndex].type = opcode.read(Default::filter); } break; @@ -691,8 +639,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto eqIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - if (auto value = opcode.read(Default::eqBandwidth)) - equalizers[eqIndex].bandwidth = *value; + equalizers[eqIndex].bandwidth = opcode.read(Default::eqBandwidth); } break; case_any_ccN("eq&_bw"): // also eq&_bwcc& @@ -709,8 +656,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto eqIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - if (auto value = opcode.read(Default::eqFrequency)) - equalizers[eqIndex].frequency = *value; + equalizers[eqIndex].frequency = opcode.read(Default::eqFrequency); } break; case_any_ccN("eq&_freq"): // also eq&_freqcc& @@ -727,8 +673,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto eqIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - if (auto value = opcode.read(Default::eqVel2Frequency)) - equalizers[eqIndex].vel2frequency = *value; + equalizers[eqIndex].vel2frequency = opcode.read(Default::eqVel2Frequency); } break; case hash("eq&_gain"): @@ -736,8 +681,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto eqIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - if (auto value = opcode.read(Default::eqGain)) - equalizers[eqIndex].gain = *value; + equalizers[eqIndex].gain = opcode.read(Default::eqGain); } break; case_any_ccN("eq&_gain"): // also eq&_gaincc& @@ -754,8 +698,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto eqIndex = opcode.parameters.front() - 1; if (!extendIfNecessary(equalizers, eqIndex + 1, Default::numEQs)) return false; - if (auto value = opcode.read(Default::eqVel2Gain)) - equalizers[eqIndex].vel2gain = *value; + equalizers[eqIndex].vel2gain = opcode.read(Default::eqVel2Gain); } break; case hash("eq&_type"): @@ -765,7 +708,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; equalizers[eqIndex].type = - opcode.read(Default::eq).value_or(equalizers[eqIndex].type); + opcode.read(Default::eq); } break; @@ -776,38 +719,38 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) pitchKeycenterFromSample = true; else { pitchKeycenterFromSample = false; - pitchKeycenter = opcode.read(Default::key).value_or(pitchKeycenter); + pitchKeycenter = opcode.read(Default::key); } break; case hash("pitch_keytrack"): - pitchKeytrack = opcode.read(Default::pitchKeytrack).value_or(pitchKeytrack); + pitchKeytrack = opcode.read(Default::pitchKeytrack); break; case hash("pitch_veltrack"): - pitchVeltrack = opcode.read(Default::pitchVeltrack).value_or(pitchVeltrack); + pitchVeltrack = opcode.read(Default::pitchVeltrack); break; case hash("pitch_random"): - pitchRandom = opcode.read(Default::pitchRandom).value_or(pitchRandom); + pitchRandom = opcode.read(Default::pitchRandom); break; case hash("transpose"): - transpose = opcode.read(Default::transpose).value_or(transpose); + transpose = opcode.read(Default::transpose); break; case hash("pitch"): // also tune - pitch = opcode.read(Default::pitch).value_or(pitch); + pitch = opcode.read(Default::pitch); break; case_any_ccN("pitch"): // also tune processGenericCc(opcode, Default::pitchMod, ModKey::createNXYZ(ModId::Pitch, id)); break; case hash("bend_up"): // also bendup - bendUp = opcode.read(Default::bendUp).value_or(bendUp); + bendUp = opcode.read(Default::bendUp); break; case hash("bend_down"): // also benddown - bendDown = opcode.read(Default::bendDown).value_or(bendDown); + bendDown = opcode.read(Default::bendDown); break; case hash("bend_step"): - bendStep = opcode.read(Default::bendStep).value_or(bendStep); + bendStep = opcode.read(Default::bendStep); break; case hash("bend_smooth"): - bendSmooth = opcode.read(Default::smoothCC).value_or(bendSmooth); + bendSmooth = opcode.read(Default::smoothCC); break; // Modulation: LFO @@ -818,8 +761,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = opcode.read(Default::lfoFreq)) - lfos[lfoNumber - 1].freq = *value; + lfos[lfoNumber - 1].freq = opcode.read(Default::lfoFreq); } break; case_any_ccN("lfo&_freq"): @@ -839,8 +781,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = opcode.read(Default::lfoBeats)) - lfos[lfoNumber - 1].beats = *value; + lfos[lfoNumber - 1].beats = opcode.read(Default::lfoBeats); } break; case_any_ccN("lfo&_beats"): @@ -860,8 +801,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = opcode.read(Default::lfoPhase)) - lfos[lfoNumber - 1].phase0 = wrapPhase(*value); + lfos[lfoNumber - 1].phase0 = opcode.read(Default::lfoPhase); } break; case hash("lfo&_delay"): @@ -871,8 +811,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = opcode.read(Default::lfoDelay)) - lfos[lfoNumber - 1].delay = *value; + lfos[lfoNumber - 1].delay = opcode.read(Default::lfoDelay); } break; case hash("lfo&_fade"): @@ -882,8 +821,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = opcode.read(Default::lfoFade)) - lfos[lfoNumber - 1].fade = *value; + lfos[lfoNumber - 1].fade = opcode.read(Default::lfoFade); } break; case hash("lfo&_count"): @@ -893,8 +831,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = opcode.read(Default::lfoCount)) - lfos[lfoNumber - 1].count = *value; + lfos[lfoNumber - 1].count = opcode.read(Default::lfoCount); } break; case hash("lfo&_steps"): @@ -904,11 +841,9 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = opcode.read(Default::lfoSteps)) { - if (!lfos[lfoNumber - 1].seq) - lfos[lfoNumber - 1].seq = LFODescription::StepSequence(); - lfos[lfoNumber - 1].seq->steps.resize(*value); - } + if (!lfos[lfoNumber - 1].seq) + lfos[lfoNumber - 1].seq = LFODescription::StepSequence(); + lfos[lfoNumber - 1].seq->steps.resize(opcode.read(Default::lfoSteps)); } break; case hash("lfo&_step&"): @@ -919,13 +854,11 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = opcode.read(Default::lfoStepX)) { - if (!lfos[lfoNumber - 1].seq) - lfos[lfoNumber - 1].seq = LFODescription::StepSequence(); - if (!extendIfNecessary(lfos[lfoNumber - 1].seq->steps, stepNumber, Default::numLFOSteps)) - return false; - lfos[lfoNumber - 1].seq->steps[stepNumber - 1] = *value * 0.01f; - } + if (!lfos[lfoNumber - 1].seq) + lfos[lfoNumber - 1].seq = LFODescription::StepSequence(); + if (!extendIfNecessary(lfos[lfoNumber - 1].seq->steps, stepNumber, Default::numLFOSteps)) + return false; + lfos[lfoNumber - 1].seq->steps[stepNumber - 1] = opcode.read(Default::lfoStepX); } break; case hash("lfo&_wave&"): // also lfo&_wave @@ -936,11 +869,9 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = opcode.read(Default::lfoWave)) { - if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) + if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) return false; - lfos[lfoNumber - 1].sub[subNumber - 1].wave = static_cast(*value); - } + lfos[lfoNumber - 1].sub[subNumber - 1].wave = opcode.read(Default::lfoWave); } break; case hash("lfo&_offset&"): // also lfo&_offset @@ -951,11 +882,9 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = opcode.read(Default::lfoOffset)) { - if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) - return false; - lfos[lfoNumber - 1].sub[subNumber - 1].offset = *value; - } + if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) + return false; + lfos[lfoNumber - 1].sub[subNumber - 1].offset = opcode.read(Default::lfoOffset); } break; case hash("lfo&_ratio&"): // also lfo&_ratio @@ -966,11 +895,9 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = opcode.read(Default::lfoRatio)) { - if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) - return false; - lfos[lfoNumber - 1].sub[subNumber - 1].ratio = *value; - } + if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) + return false; + lfos[lfoNumber - 1].sub[subNumber - 1].ratio = opcode.read(Default::lfoRatio); } break; case hash("lfo&_scale&"): // also lfo&_scale @@ -981,11 +908,9 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(lfos, lfoNumber, Default::numLFOs)) return false; - if (auto value = opcode.read(Default::lfoScale)) { - if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) - return false; - lfos[lfoNumber - 1].sub[subNumber - 1].scale = *value; - } + if (!extendIfNecessary(lfos[lfoNumber - 1].sub, subNumber, Default::numLFOSubs)) + return false; + lfos[lfoNumber - 1].sub[subNumber - 1].scale = opcode.read(Default::lfoScale); } break; @@ -995,11 +920,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto lfoNumber = opcode.parameters.front(); if (lfoNumber == 0) return false; - if (auto value = opcode.read(Default::amplitudeMod)) { - const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Amplitude, id); - getOrCreateConnection(source, target).sourceDepth = *value; - } + const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); + const ModKey target = ModKey::createNXYZ(ModId::Amplitude, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::amplitudeMod); } break; case hash("lfo&_pan"): @@ -1007,11 +931,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto lfoNumber = opcode.parameters.front(); if (lfoNumber == 0) return false; - if (auto value = opcode.read(Default::panMod)) { - const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Pan, id); - getOrCreateConnection(source, target).sourceDepth = *value; - } + const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); + const ModKey target = ModKey::createNXYZ(ModId::Pan, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::panMod); } break; case hash("lfo&_width"): @@ -1019,11 +942,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto lfoNumber = opcode.parameters.front(); if (lfoNumber == 0) return false; - if (auto value = opcode.read(Default::widthMod)) { - const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Width, id); - getOrCreateConnection(source, target).sourceDepth = *value; - } + const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); + const ModKey target = ModKey::createNXYZ(ModId::Width, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::widthMod); } break; case hash("lfo&_position"): // sfizz extension @@ -1031,11 +953,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto lfoNumber = opcode.parameters.front(); if (lfoNumber == 0) return false; - if (auto value = opcode.read(Default::positionMod)) { - const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Position, id); - getOrCreateConnection(source, target).sourceDepth = *value; - } + const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); + const ModKey target = ModKey::createNXYZ(ModId::Position, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::positionMod); } break; case hash("lfo&_pitch"): @@ -1043,11 +964,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto lfoNumber = opcode.parameters.front(); if (lfoNumber == 0) return false; - if (auto value = opcode.read(Default::pitchMod)) { - const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Pitch, id); - getOrCreateConnection(source, target).sourceDepth = *value; - } + const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); + const ModKey target = ModKey::createNXYZ(ModId::Pitch, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::pitchMod); } break; case hash("lfo&_volume"): @@ -1055,11 +975,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto lfoNumber = opcode.parameters.front(); if (lfoNumber == 0) return false; - if (auto value = opcode.read(Default::volumeMod)) { - const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Volume, id); - getOrCreateConnection(source, target).sourceDepth = *value; - } + const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber - 1); + const ModKey target = ModKey::createNXYZ(ModId::Volume, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::volumeMod); } break; case hash("lfo&_cutoff&"): @@ -1087,11 +1006,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto egNumber = opcode.parameters.front(); if (egNumber == 0) return false; - if (auto value = opcode.read(Default::amplitudeMod)) { - const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Amplitude, id); - getOrCreateConnection(source, target).sourceDepth = *value; - } + const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); + const ModKey target = ModKey::createNXYZ(ModId::Amplitude, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::amplitudeMod); } break; case hash("eg&_pan"): @@ -1099,11 +1017,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto egNumber = opcode.parameters.front(); if (egNumber == 0) return false; - if (auto value = opcode.read(Default::panMod)) { - const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Pan, id); - getOrCreateConnection(source, target).sourceDepth = *value; - } + const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); + const ModKey target = ModKey::createNXYZ(ModId::Pan, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::panMod); } break; case hash("eg&_width"): @@ -1111,11 +1028,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto egNumber = opcode.parameters.front(); if (egNumber == 0) return false; - if (auto value = opcode.read(Default::widthMod)) { - const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Width, id); - getOrCreateConnection(source, target).sourceDepth = *value; - } + const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); + const ModKey target = ModKey::createNXYZ(ModId::Width, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::widthMod); } break; case hash("eg&_position"): // sfizz extension @@ -1123,11 +1039,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto egNumber = opcode.parameters.front(); if (egNumber == 0) return false; - if (auto value = opcode.read(Default::positionMod)) { - const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Position, id); - getOrCreateConnection(source, target).sourceDepth = *value; - } + const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); + const ModKey target = ModKey::createNXYZ(ModId::Position, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::positionMod); } break; case hash("eg&_pitch"): @@ -1135,11 +1050,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto egNumber = opcode.parameters.front(); if (egNumber == 0) return false; - if (auto value = opcode.read(Default::pitchMod)) { - const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Pitch, id); - getOrCreateConnection(source, target).sourceDepth = *value; - } + const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); + const ModKey target = ModKey::createNXYZ(ModId::Pitch, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::pitchMod); } break; case hash("eg&_volume"): @@ -1147,11 +1061,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto egNumber = opcode.parameters.front(); if (egNumber == 0) return false; - if (auto value = opcode.read(Default::volumeMod)) { - const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); - const ModKey target = ModKey::createNXYZ(ModId::Volume, id); - getOrCreateConnection(source, target).sourceDepth = *value; - } + const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber - 1); + const ModKey target = ModKey::createNXYZ(ModId::Volume, id); + getOrCreateConnection(source, target).sourceDepth = + opcode.read(Default::volumeMod); } break; case hash("eg&_cutoff&"): @@ -1180,15 +1093,14 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) return false; if (!extendIfNecessary(flexEGs, egNumber, Default::numFlexEGs)) return false; - if (auto ampeg = opcode.read(Default::flexEGAmpeg)) { - FlexEGDescription& desc = flexEGs[egNumber - 1]; - if (desc.ampeg != *ampeg) { - desc.ampeg = *ampeg; - flexAmpEG = absl::nullopt; - for (size_t i = 0, n = flexEGs.size(); i < n && !flexAmpEG; ++i) { - if (flexEGs[i].ampeg) - flexAmpEG = static_cast(i); - } + auto ampeg = opcode.read(Default::flexEGAmpeg); + FlexEGDescription& desc = flexEGs[egNumber - 1]; + if (desc.ampeg != ampeg) { + desc.ampeg = ampeg; + flexAmpEG = absl::nullopt; + for (size_t i = 0, n = flexEGs.size(); i < n && !flexAmpEG; ++i) { + if (flexEGs[i].ampeg) + flexAmpEG = static_cast(i); } } break; @@ -1271,29 +1183,25 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) break; case hash("pitcheg_depth"): - if (auto value = opcode.read(Default::egDepth)) - getOrCreateConnection( - ModKey::createNXYZ(ModId::PitchEG, id), - ModKey::createNXYZ(ModId::Pitch, id)).sourceDepth = *value; + getOrCreateConnection( + ModKey::createNXYZ(ModId::PitchEG, id), + ModKey::createNXYZ(ModId::Pitch, id)).sourceDepth = opcode.read(Default::egDepth); break; case hash("fileg_depth"): - if (auto value = opcode.read(Default::egDepth)) - getOrCreateConnection( - ModKey::createNXYZ(ModId::FilEG, id), - ModKey::createNXYZ(ModId::FilCutoff, id)).sourceDepth = *value; + getOrCreateConnection( + ModKey::createNXYZ(ModId::FilEG, id), + ModKey::createNXYZ(ModId::FilCutoff, id)).sourceDepth = opcode.read(Default::egDepth); break; case hash("pitcheg_veltodepth"): // also pitcheg_vel2depth - if (auto value = opcode.read(Default::egVel2Depth)) - getOrCreateConnection( - ModKey::createNXYZ(ModId::PitchEG, id), - ModKey::createNXYZ(ModId::Pitch, id)).velToDepth = *value; + getOrCreateConnection( + ModKey::createNXYZ(ModId::PitchEG, id), + ModKey::createNXYZ(ModId::Pitch, id)).velToDepth = opcode.read(Default::egVel2Depth); break; case hash("fileg_veltodepth"): // also fileg_vel2depth - if (auto value = opcode.read(Default::egVel2Depth)) - getOrCreateConnection( - ModKey::createNXYZ(ModId::FilEG, id), - ModKey::createNXYZ(ModId::FilCutoff, id)).velToDepth = *value; + getOrCreateConnection( + ModKey::createNXYZ(ModId::FilEG, id), + ModKey::createNXYZ(ModId::FilCutoff, id)).velToDepth = opcode.read(Default::egVel2Depth); break; // Flex envelopes @@ -1305,7 +1213,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(flexEGs, egNumber, Default::numFlexEGs)) return false; auto& eg = flexEGs[egNumber - 1]; - eg.dynamic = opcode.read(Default::flexEGDynamic).value_or(eg.dynamic); + eg.dynamic = opcode.read(Default::flexEGDynamic); } break; case hash("eg&_sustain"): @@ -1316,7 +1224,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (!extendIfNecessary(flexEGs, egNumber, Default::numFlexEGs)) return false; auto& eg = flexEGs[egNumber - 1]; - eg.sustain = opcode.read(Default::flexEGSustain).value_or(eg.sustain); + eg.sustain = opcode.read(Default::flexEGSustain); } break; case hash("eg&_time&"): @@ -1330,8 +1238,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto pointNumber = opcode.parameters[1]; if (!extendIfNecessary(eg.points, pointNumber + 1, Default::numFlexEGPoints)) return false; - if (auto value = opcode.read(Default::flexEGPointTime)) - eg.points[pointNumber].time = *value; + eg.points[pointNumber].time = opcode.read(Default::flexEGPointTime); } break; case hash("eg&_level&"): @@ -1345,8 +1252,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto pointNumber = opcode.parameters[1]; if (!extendIfNecessary(eg.points, pointNumber + 1, Default::numFlexEGPoints)) return false; - if (auto value = opcode.read(Default::flexEGPointLevel)) - eg.points[pointNumber].level = *value; + eg.points[pointNumber].level = opcode.read(Default::flexEGPointLevel); } break; case hash("eg&_shape&"): @@ -1360,8 +1266,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto pointNumber = opcode.parameters[1]; if (!extendIfNecessary(eg.points, pointNumber + 1, Default::numFlexEGPoints)) return false; - if (auto value = opcode.read(Default::flexEGPointShape)) - eg.points[pointNumber].setShape(*value); + eg.points[pointNumber].setShape(opcode.read(Default::flexEGPointShape)); } break; @@ -1370,17 +1275,13 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) const auto effectNumber = opcode.parameters.back(); if (!effectNumber || effectNumber < 1 || effectNumber > config::maxEffectBuses) break; - auto value = opcode.read(Default::effect); - if (!value) - break; if (static_cast(effectNumber + 1) > gainToEffect.size()) gainToEffect.resize(effectNumber + 1); - gainToEffect[effectNumber] = *value / 100; + gainToEffect[effectNumber] = opcode.read(Default::effect); break; } case hash("sw_default"): - if (auto value = opcode.read(Default::key)) - defaultSwitch = *value; + defaultSwitch = opcode.read(Default::key); break; // Ignored opcodes @@ -1408,98 +1309,91 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, EGDescription& eg) switch (opcode.lettersOnlyHash) { case_any_eg("attack"): - eg.attack = opcode.read(Default::egTime).value_or(eg.attack); + eg.attack = opcode.read(Default::egTime); break; case_any_eg("decay"): - eg.decay = opcode.read(Default::egTime).value_or(eg.decay); + eg.decay = opcode.read(Default::egTime); break; case_any_eg("delay"): - eg.delay = opcode.read(Default::egTime).value_or(eg.delay); + eg.delay = opcode.read(Default::egTime); break; case_any_eg("hold"): - eg.hold = opcode.read(Default::egTime).value_or(eg.hold); + eg.hold = opcode.read(Default::egTime); break; case_any_eg("release"): - eg.release = opcode.read(Default::egRelease).value_or(eg.release); + eg.release = opcode.read(Default::egRelease); break; case_any_eg("start"): - eg.start = opcode.read(Default::egPercent).value_or(eg.start); + eg.start = opcode.read(Default::egPercent); break; case_any_eg("sustain"): - eg.sustain = opcode.read(Default::egPercent).value_or(eg.sustain); + eg.sustain = opcode.read(Default::egPercent); break; case_any_eg("veltoattack"): // also vel2attack - eg.vel2attack = opcode.read(Default::egTimeMod).value_or(eg.vel2attack); + eg.vel2attack = opcode.read(Default::egTimeMod); break; case_any_eg("veltodecay"): // also vel2decay - eg.vel2decay = opcode.read(Default::egTimeMod).value_or(eg.vel2decay); + eg.vel2decay = opcode.read(Default::egTimeMod); break; case_any_eg("veltodelay"): // also vel2delay - eg.vel2delay = opcode.read(Default::egTimeMod).value_or(eg.vel2delay); + eg.vel2delay = opcode.read(Default::egTimeMod); break; case_any_eg("veltohold"): // also vel2hold - eg.vel2hold = opcode.read(Default::egTimeMod).value_or(eg.vel2hold); + eg.vel2hold = opcode.read(Default::egTimeMod); break; case_any_eg("veltorelease"): // also vel2release - eg.vel2release = opcode.read(Default::egTimeMod).value_or(eg.vel2release); + eg.vel2release = opcode.read(Default::egTimeMod); break; case_any_eg("veltosustain"): // also vel2sustain - eg.vel2sustain = opcode.read(Default::egPercentMod).value_or(eg.vel2sustain); + eg.vel2sustain = opcode.read(Default::egPercentMod); break; case_any_eg("attack_oncc&"): // also attackcc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::egTimeMod)) - eg.ccAttack[opcode.parameters.back()] = *value; + eg.ccAttack[opcode.parameters.back()] = opcode.read(Default::egTimeMod); break; case_any_eg("decay_oncc&"): // also decaycc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::egTimeMod)) - eg.ccDecay[opcode.parameters.back()] = *value; + eg.ccDecay[opcode.parameters.back()] = opcode.read(Default::egTimeMod); break; case_any_eg("delay_oncc&"): // also delaycc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::egTimeMod)) - eg.ccDelay[opcode.parameters.back()] = *value; + eg.ccDelay[opcode.parameters.back()] = opcode.read(Default::egTimeMod); break; case_any_eg("hold_oncc&"): // also holdcc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::egTimeMod)) - eg.ccHold[opcode.parameters.back()] = *value; + eg.ccHold[opcode.parameters.back()] = opcode.read(Default::egTimeMod); break; case_any_eg("release_oncc&"): // also releasecc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::egTimeMod)) - eg.ccRelease[opcode.parameters.back()] = *value; + eg.ccRelease[opcode.parameters.back()] = opcode.read(Default::egTimeMod); break; case_any_eg("start_oncc&"): // also startcc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::egPercentMod)) - eg.ccStart[opcode.parameters.back()] = *value; + eg.ccStart[opcode.parameters.back()] = opcode.read(Default::egPercentMod); break; case_any_eg("sustain_oncc&"): // also sustaincc& if (opcode.parameters.back() >= config::numCCs) return false; - if (auto value = opcode.read(Default::egPercentMod)) - eg.ccSustain[opcode.parameters.back()] = *value; + eg.ccSustain[opcode.parameters.back()] = opcode.read(Default::egPercentMod); break; default: @@ -1558,21 +1452,21 @@ bool sfz::Region::processGenericCc(const Opcode& opcode, OpcodeSpec spec, ModKey::Parameters p = conn->source.parameters(); switch (opcode.category) { case kOpcodeOnCcN: - conn->sourceDepth = opcode.read(spec).value_or(conn->sourceDepth); + conn->sourceDepth = opcode.read(spec); break; case kOpcodeCurveCcN: - p.curve = opcode.read(Default::curveCC).value_or(p.curve); + p.curve = opcode.read(Default::curveCC); break; case kOpcodeStepCcN: { const float maxStep = max(std::abs(spec.bounds.getStart()), std::abs(spec.bounds.getEnd())); - const OpcodeSpec stepCC { 0.0f, Range(0.0f, maxStep), kEnforceLowerBound | kEnforceUpperBound }; - p.step = opcode.read(stepCC).value_or(p.step); + const OpcodeSpec stepCC { 0.0f, Range(0.0f, maxStep), 0 }; + p.step = opcode.read(stepCC); } break; case kOpcodeSmoothCcN: - p.smooth = opcode.read(Default::smoothCC).value_or(p.smooth); + p.smooth = opcode.read(Default::smoothCC); break; default: assert(false); diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index 9260b8e7..4a7324f8 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -319,44 +319,44 @@ struct Region { // Sound source: sample playback std::shared_ptr sampleId { new FileId }; // Sample absl::optional sampleQuality {}; - float delay { Default::delay.value }; // delay - float delayRandom { Default::delayRandom.value }; // delay_random - int64_t offset { Default::offset.value }; // offset - int64_t offsetRandom { Default::offsetRandom.value }; // offset_random - CCMap offsetCC { Default::offsetMod.value }; - uint32_t sampleEnd { Default::sampleEnd.value }; // end - absl::optional sampleCount {}; // count + float delay { Default::delay }; // delay + float delayRandom { Default::delayRandom }; // delay_random + int64_t offset { Default::offset }; // offset + int64_t offsetRandom { Default::offsetRandom }; // offset_random + CCMap offsetCC { Default::offsetMod }; + uint32_t sampleEnd { Default::sampleEnd }; // end + uint32_t sampleCount { Default::sampleCount }; // count absl::optional loopMode {}; // loopmode - Range loopRange { Default::loopRange.bounds }; //loopstart and loopend - float loopCrossfade { Default::loopCrossfade.value }; // loop_crossfade + Range loopRange { Default::loopStart, Default::loopEnd }; //loopstart and loopend + float loopCrossfade { Default::loopCrossfade }; // loop_crossfade // Wavetable oscillator - float oscillatorPhase { Default::oscillatorPhase.value }; - OscillatorEnabled oscillatorEnabled { Default::oscillator.value }; // oscillator + float oscillatorPhase { Default::oscillatorPhase }; + OscillatorEnabled oscillatorEnabled { Default::oscillator }; // oscillator bool hasWavetableSample { false }; // (set according to sample file) - int oscillatorMode { Default::oscillatorMode.value }; - int oscillatorMulti { Default::oscillatorMulti.value }; - float oscillatorDetune { Default::oscillatorDetune.value }; - float oscillatorModDepth { Default::oscillatorModDepth.value }; + int oscillatorMode { Default::oscillatorMode }; + int oscillatorMulti { Default::oscillatorMulti }; + float oscillatorDetune { Default::oscillatorDetune }; + float oscillatorModDepth { Default::oscillatorModDepth }; absl::optional oscillatorQuality; // Instrument settings: voice lifecycle - uint32_t group { Default::group.value }; // group + uint32_t group { Default::group }; // group absl::optional offBy {}; // off_by - OffMode offMode { Default::offMode.value }; // off_mode - float offTime { Default::offTime.value }; // off_mode + OffMode offMode { Default::offMode }; // off_mode + float offTime { Default::offTime }; // off_mode absl::optional notePolyphony {}; // note_polyphony uint32_t polyphony { config::maxVoices }; // polyphony - SelfMask selfMask { Default::selfMask.value }; - bool rtDead { Default::rtDead.value }; + SelfMask selfMask { Default::selfMask }; + bool rtDead { Default::rtDead }; // Region logic: key mapping - Range keyRange { Default::key.bounds }; //lokey, hikey and key - Range velocityRange { Default::normalized.bounds }; // hivel and lovel + Range keyRange { Default::loKey, Default::hiKey }; //lokey, hikey and key + Range velocityRange { Default::loVel, Default::hiVel }; // hivel and lovel // Region logic: MIDI conditions - Range bendRange { Default::bipolar.bounds }; // hibend and lobend - CCMap> ccConditions { Default::normalized.bounds }; + Range bendRange { Default::loBend, Default::hiBend }; // hibend and lobend + CCMap> ccConditions {{ Default::loCC, Default::hiCC }}; absl::optional lastKeyswitch {}; // sw_last absl::optional> lastKeyswitchRange {}; // sw_last absl::optional keyswitchLabel {}; @@ -364,45 +364,45 @@ struct Region { absl::optional downKeyswitch {}; // sw_down absl::optional previousKeyswitch {}; // sw_previous absl::optional defaultSwitch {}; - VelocityOverride velocityOverride { Default::velocityOverride.value }; // sw_vel - bool checkSustain { Default::checkSustain.value }; // sustain_sw - bool checkSostenuto { Default::checkSostenuto.value }; // sostenuto_sw - uint16_t sustainCC { Default::sustainCC.value }; // sustain_cc - float sustainThreshold { Default::sustainThreshold.value }; // sustain_cc + VelocityOverride velocityOverride { Default::velocityOverride }; // sw_vel + bool checkSustain { Default::checkSustain }; // sustain_sw + bool checkSostenuto { Default::checkSostenuto }; // sostenuto_sw + uint16_t sustainCC { Default::sustainCC }; // sustain_cc + float sustainThreshold { Default::sustainThreshold }; // sustain_cc // Region logic: internal conditions - Range aftertouchRange { Default::midi7.bounds }; // hichanaft and lochanaft - Range bpmRange { Default::bpm.bounds }; // hibpm and lobpm - Range randRange { Default::normalized.bounds }; // hirand and lorand - uint8_t sequenceLength { Default::sequence.value }; // seq_length - uint8_t sequencePosition { Default::sequence.value }; // seq_position + Range aftertouchRange { Default::loChannelAftertouch, Default::hiChannelAftertouch }; // hichanaft and lochanaft + Range bpmRange { Default::loBPM, Default::hiBPM }; // hibpm and lobpm + Range randRange { Default::loNormalized, Default::hiNormalized }; // hirand and lorand + uint8_t sequenceLength { Default::sequence }; // seq_length + uint8_t sequencePosition { Default::sequence }; // seq_position // Region logic: triggers - Trigger trigger { Default::trigger.value }; // trigger - CCMap> ccTriggers { Default::normalized.bounds }; // on_loccN on_hiccN + Trigger trigger { Default::trigger }; // trigger + CCMap> ccTriggers {{ Default::loCC, Default::hiCC }}; // on_loccN on_hiccN // Performance parameters: amplifier - float volume { Default::volume.value }; // volume - float amplitude { normalizePercents(Default::amplitude.value) }; // amplitude - float pan { normalizePercents(Default::pan.value) }; // pan - float width { normalizePercents(Default::width.value) }; // width - float position { normalizePercents(Default::position.value) }; // position - uint8_t ampKeycenter { Default::key.value }; // amp_keycenter - float ampKeytrack { Default::ampKeytrack.value }; // amp_keytrack - float ampVeltrack { normalizePercents(Default::ampVeltrack.value) }; // amp_veltrack + float volume { Default::volume }; // volume + float amplitude { normalizePercents(Default::amplitude) }; // amplitude + float pan { normalizePercents(Default::pan) }; // pan + float width { normalizePercents(Default::width) }; // width + float position { normalizePercents(Default::position) }; // position + uint8_t ampKeycenter { Default::key }; // amp_keycenter + float ampKeytrack { Default::ampKeytrack }; // amp_keytrack + float ampVeltrack { normalizePercents(Default::ampVeltrack) }; // amp_veltrack std::vector> velocityPoints; // amp_velcurve_N absl::optional velCurve {}; - float ampRandom { Default::ampRandom.value }; // amp_random + float ampRandom { Default::ampRandom }; // amp_random Range crossfadeKeyInRange { Default::crossfadeKeyInRange }; Range crossfadeKeyOutRange { Default::crossfadeKeyOutRange }; Range crossfadeVelInRange { Default::crossfadeVelInRange }; Range crossfadeVelOutRange { Default::crossfadeVelOutRange }; - CrossfadeCurve crossfadeKeyCurve { Default::crossfadeCurve.value }; - CrossfadeCurve crossfadeVelCurve { Default::crossfadeCurve.value }; - CrossfadeCurve crossfadeCCCurve { Default::crossfadeCurve.value }; + CrossfadeCurve crossfadeKeyCurve { Default::crossfadeCurve }; + CrossfadeCurve crossfadeVelCurve { Default::crossfadeCurve }; + CrossfadeCurve crossfadeCCCurve { Default::crossfadeCurve }; CCMap> crossfadeCCInRange { Default::crossfadeCCInRange }; // xfin_loccN xfin_hiccN CCMap> crossfadeCCOutRange { Default::crossfadeCCOutRange }; // xfout_loccN xfout_hiccN - float rtDecay { Default::rtDecay.value }; // rt_decay + float rtDecay { Default::rtDecay }; // rt_decay float globalAmplitude { 1.0 }; // global_amplitude float masterAmplitude { 1.0 }; // master_amplitude @@ -416,17 +416,17 @@ struct Region { std::vector filters; // Performance parameters: pitch - uint8_t pitchKeycenter { Default::key.value }; // pitch_keycenter + uint8_t pitchKeycenter { Default::key }; // pitch_keycenter bool pitchKeycenterFromSample { false }; - int pitchKeytrack { Default::pitchKeytrack.value }; // pitch_keytrack - float pitchRandom { Default::pitchRandom.value }; // pitch_random - int pitchVeltrack { Default::pitchVeltrack.value }; // pitch_veltrack - int transpose { Default::transpose.value }; // transpose - float pitch { Default::pitch.value }; // tune - float bendUp { Default::bendUp.value }; - float bendDown { Default::bendDown.value }; - float bendStep { Default::bendStep.value }; - uint8_t bendSmooth { Default::smoothCC.value }; + int pitchKeytrack { Default::pitchKeytrack }; // pitch_keytrack + float pitchRandom { Default::pitchRandom }; // pitch_random + int pitchVeltrack { Default::pitchVeltrack }; // pitch_veltrack + int transpose { Default::transpose }; // transpose + float pitch { Default::pitch }; // tune + float bendUp { Default::bendUp }; + float bendDown { Default::bendDown }; + float bendStep { Default::bendStep }; + uint8_t bendSmooth { Default::smoothCC }; // Envelopes EGDescription amplitudeEG; diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 76f935d4..fefa48d4 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -191,7 +191,7 @@ void Synth::Impl::buildRegion(const std::vector& regionOpcodes) currentSwitch_ = *lastRegion->defaultSwitch; // There was a combination of group= and polyphony= on a region, so set the group polyphony - if (lastRegion->group != Default::group.value && lastRegion->polyphony != config::maxVoices) { + if (lastRegion->group != Default::group && lastRegion->polyphony != config::maxVoices) { voiceManager_.setGroupPolyphony(lastRegion->group, lastRegion->polyphony); } else { // Just check that there are enough polyphony groups @@ -276,12 +276,10 @@ void Synth::Impl::handleMasterOpcodes(const std::vector& members) switch (member.lettersOnlyHash) { case hash("polyphony"): ASSERT(currentSet_ != nullptr); - if (auto value = member.read(Default::polyphony)) - currentSet_->setPolyphonyLimit(*value); + currentSet_->setPolyphonyLimit(member.read(Default::polyphony)); break; case hash("sw_default"): - if (auto value = member.read(Default::key)) - currentSwitch_ = *value; + currentSwitch_ = member.read(Default::key); break; } } @@ -295,12 +293,10 @@ void Synth::Impl::handleGlobalOpcodes(const std::vector& members) switch (member.lettersOnlyHash) { case hash("polyphony"): ASSERT(currentSet_ != nullptr); - if (auto value = member.read(Default::polyphony)) - currentSet_->setPolyphonyLimit(*value); + currentSet_->setPolyphonyLimit(member.read(Default::polyphony)); break; case hash("sw_default"): - if (auto value = member.read(Default::key)) - currentSwitch_ = *value; + currentSwitch_ = member.read(Default::key); break; case hash("volume"): // FIXME : Probably best not to mess with this and let the host control the volume @@ -320,16 +316,13 @@ void Synth::Impl::handleGroupOpcodes(const std::vector& members, const s switch (member.lettersOnlyHash) { case hash("group"): - if (auto value = member.read(Default::group)) - groupIdx = *value; + groupIdx = member.read(Default::group); break; case hash("polyphony"): - if (auto value = member.read(Default::polyphony)) - maxPolyphony = *value; + maxPolyphony = member.read(Default::polyphony); break; case hash("sw_default"): - if (auto value = member.read(Default::key)) - currentSwitch_ = *value; + currentSwitch_ = member.read(Default::key); break; } }; @@ -358,16 +351,12 @@ void Synth::Impl::handleControlOpcodes(const std::vector& members) switch (member.lettersOnlyHash) { case hash("set_cc&"): if (Default::ccNumber.bounds.containsWithEnd(member.parameters.back())) { - const auto ccValue = member.read(Default::midi7); - if (ccValue) - setDefaultHdcc(member.parameters.back(), normalizeCC(*ccValue)); + setDefaultHdcc(member.parameters.back(), member.read(Default::loCC)); } break; case hash("set_hdcc&"): if (Default::ccNumber.bounds.containsWithEnd(member.parameters.back())) { - const auto ccValue = member.read(Default::normalized); - if (ccValue) - setDefaultHdcc(member.parameters.back(), *ccValue); + setDefaultHdcc(member.parameters.back(), member.read(Default::loNormalized)); } break; case hash("label_cc&"): @@ -385,10 +374,10 @@ void Synth::Impl::handleControlOpcodes(const std::vector& members) DBG("Changing default sample path to " << defaultPath_); break; case hash("note_offset"): - noteOffset_ = member.read(Default::noteOffset).value_or(noteOffset_); + noteOffset_ = member.read(Default::noteOffset); break; case hash("octave_offset"): - octaveOffset_ = member.read(Default::octaveOffset).value_or(octaveOffset_); + octaveOffset_ = member.read(Default::octaveOffset); break; case hash("hint_ram_based"): if (member.value == "1") @@ -451,22 +440,19 @@ void Synth::Impl::handleEffectOpcodes(const std::vector& rawMembers) // note(jpc): gain opcodes are linear volumes in % units case hash("directtomain"): - if (auto valueOpt = opcode.read(Default::effect)) - getOrCreateBus(0).setGainToMain(*valueOpt / 100); + getOrCreateBus(0).setGainToMain(opcode.read(Default::effect)); break; case hash("fx&tomain"): // fx&tomain if (opcode.parameters.front() < 1 || opcode.parameters.front() > config::maxEffectBuses) break; - if (auto valueOpt = opcode.read(Default::effect)) - getOrCreateBus(opcode.parameters.front()).setGainToMain(*valueOpt / 100); + getOrCreateBus(opcode.parameters.front()).setGainToMain(opcode.read(Default::effect)); break; case hash("fx&tomix"): // fx&tomix if (opcode.parameters.front() < 1 || opcode.parameters.front() > config::maxEffectBuses) break; - if (auto valueOpt = opcode.read(Default::effect)) - getOrCreateBus(opcode.parameters.front()).setGainToMix(*valueOpt / 100); + getOrCreateBus(opcode.parameters.front()).setGainToMix(opcode.read(Default::effect)); break; } } @@ -589,10 +575,10 @@ void Synth::Impl::finalizeSfzLoad() region->sampleEnd = std::min(region->sampleEnd, fileInformation->end); if (fileInformation->hasLoop) { - if (region->loopRange.getStart() == Default::loopRange.bounds.getStart()) - region->loopRange.setStart(fileInformation->loopBegin); + if (region->loopRange.getStart() == Default::loopStart) + region->loopRange.setStart(fileInformation->loopStart); - if (region->loopRange.getEnd() == Default::loopRange.bounds.getEnd()) + if (region->loopRange.getEnd() == Default::loopEnd) region->loopRange.setEnd(fileInformation->loopEnd); if (!region->loopMode) @@ -602,7 +588,7 @@ void Synth::Impl::finalizeSfzLoad() if (region->isRelease() && !region->loopMode) region->loopMode = LoopMode::one_shot; - if (region->loopRange.getEnd() == Default::loopRange.bounds.getEnd()) + if (region->loopRange.getEnd() == Default::loopEnd) region->loopRange.setEnd(region->sampleEnd); if (fileInformation->numChannels == 2) @@ -668,13 +654,13 @@ void Synth::Impl::finalizeSfzLoad() // Set the default frequencies on equalizers if needed if (region->equalizers.size() > 0 - && region->equalizers[0].frequency == Default::eqFrequency.value) { + && region->equalizers[0].frequency == Default::eqFrequency) { region->equalizers[0].frequency = Default::defaultEQFreq[0]; if (region->equalizers.size() > 1 - && region->equalizers[1].frequency == Default::eqFrequency.value) { + && region->equalizers[1].frequency == Default::eqFrequency) { region->equalizers[1].frequency = Default::defaultEQFreq[1]; if (region->equalizers.size() > 2 - && region->equalizers[2].frequency == Default::eqFrequency.value) { + && region->equalizers[2].frequency == Default::eqFrequency) { region->equalizers[2].frequency = Default::defaultEQFreq[2]; } } diff --git a/src/sfizz/SynthConfig.h b/src/sfizz/SynthConfig.h index 47d265e6..8fdbd510 100644 --- a/src/sfizz/SynthConfig.h +++ b/src/sfizz/SynthConfig.h @@ -13,7 +13,7 @@ struct SynthConfig { bool freeWheeling { false }; - int liveSampleQuality { Default::sampleQuality.value }; + int liveSampleQuality { Default::sampleQuality }; int freeWheelingSampleQuality { Default::freewheelingQuality }; int currentSampleQuality() const noexcept diff --git a/src/sfizz/SynthMessaging.cpp b/src/sfizz/SynthMessaging.cpp index 62335993..123fac10 100644 --- a/src/sfizz/SynthMessaging.cpp +++ b/src/sfizz/SynthMessaging.cpp @@ -144,11 +144,7 @@ void sfz::Synth::dispatchMessage(Client& client, int delay, const char* path, co MATCH("/region&/count", "") { GET_REGION_OR_BREAK(indices[0]) - if (!region.sampleCount) { - client.receive<'N'>(delay, path, {}); - } else { - client.receive<'h'>(delay, path, *region.sampleCount); - } + client.receive<'h'>(delay, path, region.sampleCount); } break; MATCH("/region&/loop_range", "") { diff --git a/src/sfizz/SynthPrivate.h b/src/sfizz/SynthPrivate.h index bd34ec22..b71e9810 100644 --- a/src/sfizz/SynthPrivate.h +++ b/src/sfizz/SynthPrivate.h @@ -257,8 +257,8 @@ struct Synth::Impl final: public Parser::Listener { // Control opcodes std::string defaultPath_ { "" }; - int noteOffset_ { Default::noteOffset.value }; - int octaveOffset_ { Default::octaveOffset.value }; + int noteOffset_ { Default::noteOffset }; + int octaveOffset_ { Default::octaveOffset }; // Modulation source generators std::unique_ptr genController_; diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index dae62336..8a13834f 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -371,7 +371,7 @@ void Voice::startVoice(Region* region, int delay, const TriggerEvent& event) noe } const float phase = region->getPhase(); const int quality = - region->oscillatorQuality.value_or(Default::oscillatorQuality.value); + region->oscillatorQuality.value_or(Default::oscillatorQuality); for (WavetableOscillator& osc : impl.waveOscillators_) { osc.setWavetable(wave); osc.setPhase(phase); @@ -465,7 +465,7 @@ void Voice::off(int delay, bool fast) noexcept Impl& impl = *impl_; if (!impl.region_->flexAmpEG) { if (impl.region_->offMode == OffMode::fast || fast) { - impl.egAmplitude_.setReleaseTime(Default::offTime.value); + impl.egAmplitude_.setReleaseTime(Default::offTime); } else if (impl.region_->offMode == OffMode::time) { impl.egAmplitude_.setReleaseTime(impl.region_->offTime); } diff --git a/src/sfizz/effects/Apan.cpp b/src/sfizz/effects/Apan.cpp index 9151188a..d100361f 100644 --- a/src/sfizz/effects/Apan.cpp +++ b/src/sfizz/effects/Apan.cpp @@ -81,28 +81,22 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("apan_waveform"): - if (auto value = opc.read(Default::apanWaveform)) - apan->_lfoWave = *value; + apan->_lfoWave = opc.read(Default::apanWaveform); break; case hash("apan_freq"): - if (auto value = opc.read(Default::apanFrequency)) - apan->_lfoFrequency = *value; + apan->_lfoFrequency = opc.read(Default::apanFrequency); break; case hash("apan_phase"): - if (auto value = opc.read(Default::apanPhase)) - apan->_lfoPhaseOffset = wrapPhase(*value); + apan->_lfoPhaseOffset = opc.read(Default::apanPhase); break; case hash("apan_dry"): - if (auto value = opc.read(Default::apanLevel)) - apan->_dry = *value / 100.0f; + apan->_dry = opc.read(Default::apanLevel); break; case hash("apan_wet"): - if (auto value = opc.read(Default::apanLevel)) - apan->_wet = *value / 100.0f; + apan->_wet = opc.read(Default::apanLevel); break; case hash("apan_depth"): - if (auto value = opc.read(Default::apanLevel)) - apan->_depth = *value / 100.0f; + apan->_depth = opc.read(Default::apanLevel); break; } } diff --git a/src/sfizz/effects/Apan.h b/src/sfizz/effects/Apan.h index ac72e524..9e30c144 100644 --- a/src/sfizz/effects/Apan.h +++ b/src/sfizz/effects/Apan.h @@ -52,12 +52,12 @@ namespace fx { sfz::Buffer _lfoOutRight { config::defaultSamplesPerBlock }; // Controls - float _dry { Default::apanLevel.value }; - float _wet { Default::apanLevel.value }; - float _depth { Default::apanLevel.value }; - int _lfoWave { Default::apanWaveform.value }; - float _lfoFrequency { Default::apanFrequency.value }; - float _lfoPhaseOffset { Default::apanPhase.value }; + float _dry { Default::apanLevel }; + float _wet { Default::apanLevel }; + float _depth { Default::apanLevel }; + int _lfoWave { Default::apanWaveform }; + float _lfoFrequency { Default::apanFrequency }; + float _lfoPhaseOffset { Default::apanPhase }; // State float _lfoPhase { 0.0f }; diff --git a/src/sfizz/effects/Compressor.cpp b/src/sfizz/effects/Compressor.cpp index 94f4b242..8fffd680 100644 --- a/src/sfizz/effects/Compressor.cpp +++ b/src/sfizz/effects/Compressor.cpp @@ -31,8 +31,8 @@ namespace fx { struct Compressor::Impl { faustCompressor _compressor[2]; - bool _stlink { Default::compSTLink.value }; - float _inputGain { Default::compGain.value }; + bool _stlink { Default::compSTLink }; + float _inputGain { Default::compGain }; AudioBuffer _tempBuffer2x { 2, _oversampling * config::defaultSamplesPerBlock }; AudioBuffer _gain2x { 2, _oversampling * config::defaultSamplesPerBlock }; hiir::Downsampler2xFpu<12> _downsampler2x[EffectChannels]; @@ -163,35 +163,38 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("comp_attack"): - if (auto value = opc.read(Default::compAttack)) { + { + auto value = opc.read(Default::compAttack); for (size_t c = 0; c < 2; ++c) - impl.set_Attack(c, *value); + impl.set_Attack(c, value); } break; case hash("comp_release"): - if (auto value = opc.read(Default::compRelease)) { + { + auto value = opc.read(Default::compRelease); for (size_t c = 0; c < 2; ++c) - impl.set_Release(c, *value); + impl.set_Release(c, value); } break; case hash("comp_threshold"): - if (auto value = opc.read(Default::compThreshold)) { + { + auto value = opc.read(Default::compThreshold); for (size_t c = 0; c < 2; ++c) - impl.set_Threshold(c, *value); + impl.set_Threshold(c, value); } break; case hash("comp_ratio"): - if (auto value = opc.read(Default::compRatio)) { + { + auto value = opc.read(Default::compRatio); for (size_t c = 0; c < 2; ++c) - impl.set_Ratio(c, *value); + impl.set_Ratio(c, value); } break; case hash("comp_gain"): - if (auto value = opc.read(Default::compGain)) - impl._inputGain = db2mag(*value); + impl._inputGain = opc.read(Default::compGain); break; case hash("comp_stlink"): - impl._stlink = opc.read(Default::compSTLink).value_or(impl._stlink); + impl._stlink = opc.read(Default::compSTLink); break; } } diff --git a/src/sfizz/effects/Disto.cpp b/src/sfizz/effects/Disto.cpp index c3939f9e..946fdae6 100644 --- a/src/sfizz/effects/Disto.cpp +++ b/src/sfizz/effects/Disto.cpp @@ -38,11 +38,11 @@ struct Disto::Impl { enum { maxStages = 4 }; float _samplePeriod { 1.0f / config::defaultSampleRate }; - float _tone { Default::distoTone.value }; - float _depth { Default::distoDepth.value }; - float _dry { Default::effect.value }; - float _wet { Default::effect.value }; - unsigned _numStages = { Default::distoStages.value }; + float _tone { Default::distoTone }; + float _depth { Default::distoDepth }; + float _dry { Default::effect }; + float _wet { Default::effect }; + unsigned _numStages = { Default::distoStages }; float _toneLpfMem[EffectChannels] = {}; faustDisto _stages[EffectChannels][Default::maxDistoStages]; @@ -205,24 +205,19 @@ std::unique_ptr Disto::makeInstance(absl::Span members) for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("disto_tone"): - if (auto value = opc.read(Default::distoTone)) - impl._tone = *value; + impl._tone = opc.read(Default::distoTone); break; case hash("disto_depth"): - if (auto value = opc.read(Default::distoDepth)) - impl._depth = *value; + impl._depth = opc.read(Default::distoDepth); break; case hash("disto_stages"): - if (auto value = opc.read(Default::distoStages)) - impl._numStages = *value; + impl._numStages = opc.read(Default::distoStages); break; case hash("disto_dry"): - if (auto value = opc.read(Default::effect)) - impl._dry = *value * 0.01f; + impl._dry = opc.read(Default::effect); break; case hash("disto_wet"): - if (auto value = opc.read(Default::effect)) - impl._wet = *value * 0.01f; + impl._wet = opc.read(Default::effect); break; } } diff --git a/src/sfizz/effects/Eq.cpp b/src/sfizz/effects/Eq.cpp index 751ccc12..25036195 100644 --- a/src/sfizz/effects/Eq.cpp +++ b/src/sfizz/effects/Eq.cpp @@ -70,22 +70,17 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("eq_freq"): - if (auto value = opc.read(Default::eqFrequency)) - desc.frequency = *value; + desc.frequency = opc.read(Default::eqFrequency); break; case hash("eq_bw"): - if (auto value = opc.read(Default::eqBandwidth)) - desc.bandwidth = *value; + desc.bandwidth = opc.read(Default::eqBandwidth); break; case hash("eq_gain"): - if (auto value = opc.read(Default::eqGain)) - desc.gain = *value; + desc.gain = opc.read(Default::eqGain); break; case hash("eq_type"): - { - desc.type = opc.read(Default::eq).value_or(desc.type); - break; - } + desc.type = opc.read(Default::eq); + break; } } diff --git a/src/sfizz/effects/Filter.cpp b/src/sfizz/effects/Filter.cpp index b3765b61..8b2dff72 100644 --- a/src/sfizz/effects/Filter.cpp +++ b/src/sfizz/effects/Filter.cpp @@ -72,22 +72,17 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("filter_cutoff"): - if (auto value = opc.read(Default::filterCutoff)) - desc.cutoff = *value; + desc.cutoff = opc.read(Default::filterCutoff); break; case hash("filter_resonance"): - if (auto value = opc.read(Default::filterResonance)) - desc.resonance = *value; + desc.resonance = opc.read(Default::filterResonance); break; case hash("filter_type"): - { - desc.type = opc.read(Default::filter).value_or(desc.type); - break; - } + desc.type = opc.read(Default::filter); + break; // extension case hash("sfizz:filter_gain"): - if (auto value = opc.read(Default::filterGain)) - desc.gain = *value; + desc.gain = opc.read(Default::filterGain); break; } } diff --git a/src/sfizz/effects/Fverb.cpp b/src/sfizz/effects/Fverb.cpp index c3a1f408..c8ab7938 100644 --- a/src/sfizz/effects/Fverb.cpp +++ b/src/sfizz/effects/Fverb.cpp @@ -180,13 +180,13 @@ namespace fx { std::unique_ptr fx { reverb }; const Impl::Profile* profile = &Impl::largeHall; - float dry { Default::effect.value }; - float wet { Default::effect.value }; - float input { Default::effect.value }; - float size { Default::fverbSize.value }; - float predelay { Default::fverbPredelay.value }; - float tone { Default::fverbTone.value }; - float damp { Default::fverbDamp.value }; + float dry { Default::effect }; + float wet { Default::effect }; + float input { Default::effect }; + float size { Default::fverbSize }; + float predelay { Default::fverbPredelay }; + float tone { Default::fverbTone }; + float damp { Default::fverbDamp }; for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { @@ -212,25 +212,25 @@ namespace fx { break; case hash("reverb_dry"): - dry = opc.read(Default::effect).value_or(dry); + dry = opc.read(Default::effect); break; case hash("reverb_wet"): - wet = opc.read(Default::effect).value_or(wet); + wet = opc.read(Default::effect); break; case hash("reverb_input"): - input = opc.read(Default::effect).value_or(input); + input = opc.read(Default::effect); break; case hash("reverb_size"): - size = opc.read(Default::fverbSize).value_or(size); + size = opc.read(Default::fverbSize); break; case hash("reverb_predelay"): - predelay = opc.read(Default::fverbPredelay).value_or(predelay); + predelay = opc.read(Default::fverbPredelay); break; case hash("reverb_tone"): - tone = opc.read(Default::fverbTone).value_or(tone); + tone = opc.read(Default::fverbTone); break; case hash("reverb_damp"): - damp = opc.read(Default::fverbDamp).value_or(damp); + damp = opc.read(Default::fverbDamp); break; } } diff --git a/src/sfizz/effects/Gain.cpp b/src/sfizz/effects/Gain.cpp index 7ad9fb9f..aa8d6d03 100644 --- a/src/sfizz/effects/Gain.cpp +++ b/src/sfizz/effects/Gain.cpp @@ -62,8 +62,7 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("gain"): - if (auto value = opc.read(Default::volume)) - gain->_gain = *value; + gain->_gain = opc.read(Default::volume); break; } } diff --git a/src/sfizz/effects/Gate.cpp b/src/sfizz/effects/Gate.cpp index a4a916a3..7bbc158a 100644 --- a/src/sfizz/effects/Gate.cpp +++ b/src/sfizz/effects/Gate.cpp @@ -34,7 +34,7 @@ namespace fx { struct Gate::Impl { faustGate _gate[2]; - bool _stlink { Default::gateSTLink.value }; + bool _stlink { Default::gateSTLink }; float _inputGain = 1.0; AudioBuffer _tempBuffer2x { 2, _oversampling * config::defaultSamplesPerBlock }; AudioBuffer _gain2x { 2, _oversampling * config::defaultSamplesPerBlock }; @@ -166,31 +166,35 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("gate_attack"): - if (auto value = opc.read(Default::gateAttack)) { + { + auto value = opc.read(Default::gateAttack); for (size_t c = 0; c < 2; ++c) - impl.set_Attack(c, *value); + impl.set_Attack(c, value); } break; case hash("gate_hold"): - if (auto value = opc.read(Default::gateHold)) { + { + auto value = opc.read(Default::gateHold); for (size_t c = 0; c < 2; ++c) - impl.set_Hold(c, *value); + impl.set_Hold(c, value); } break; case hash("gate_release"): - if (auto value = opc.read(Default::gateRelease)) { + { + auto value = opc.read(Default::gateRelease); for (size_t c = 0; c < 2; ++c) - impl.set_Release(c, *value); + impl.set_Release(c, value); } break; case hash("gate_threshold"): - if (auto value = opc.read(Default::gateThreshold)) { + { + auto value = opc.read(Default::gateThreshold); for (size_t c = 0; c < 2; ++c) - impl.set_Threshold(c, *value); + impl.set_Threshold(c, value); } break; case hash("gate_stlink"): - impl._stlink = opc.read(Default::gateSTLink).value_or(impl._stlink); + impl._stlink = opc.read(Default::gateSTLink); } } diff --git a/src/sfizz/effects/Lofi.cpp b/src/sfizz/effects/Lofi.cpp index 00a11128..24aaf772 100644 --- a/src/sfizz/effects/Lofi.cpp +++ b/src/sfizz/effects/Lofi.cpp @@ -85,12 +85,10 @@ namespace fx { for (const Opcode& opcode : members) { switch (opcode.lettersOnlyHash) { case hash("bitred"): - if (auto value = opcode.read(Default::lofiBitred)) - lofi->_bitred_depth = *value; + lofi->_bitred_depth = opcode.read(Default::lofiBitred); break; case hash("decim"): - if (auto value = opcode.read(Default::lofiDecim)) - lofi->_decim_depth = *value; + lofi->_decim_depth = opcode.read(Default::lofiDecim); break; } } diff --git a/src/sfizz/effects/Rectify.cpp b/src/sfizz/effects/Rectify.cpp index f8d271dd..5d25be46 100644 --- a/src/sfizz/effects/Rectify.cpp +++ b/src/sfizz/effects/Rectify.cpp @@ -95,8 +95,7 @@ namespace fx { rectify->_full = false; break; case hash("rectify"): - if (auto value = opc.read(Default::rectify)) - rectify->_amount = *value; + rectify->_amount = opc.read(Default::rectify); break; } } diff --git a/src/sfizz/effects/Strings.cpp b/src/sfizz/effects/Strings.cpp index 6538b68a..2ef50f7c 100644 --- a/src/sfizz/effects/Strings.cpp +++ b/src/sfizz/effects/Strings.cpp @@ -132,12 +132,10 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("strings_number"): - if (auto value = opc.read(Default::stringsNumber)) - strings->_numStrings = *value; + strings->_numStrings = opc.read(Default::stringsNumber); break; case hash("strings_wet"): - if (auto value = opc.read(Default::effect)) - strings->_wet = *value; + strings->_wet = opc.read(Default::effect); break; } } diff --git a/src/sfizz/effects/Strings.h b/src/sfizz/effects/Strings.h index f20ae8a8..29121174 100644 --- a/src/sfizz/effects/Strings.h +++ b/src/sfizz/effects/Strings.h @@ -52,7 +52,7 @@ namespace fx { enum { MaximumNumStrings = 88 }; unsigned _numStrings { Default::maxStrings }; - float _wet { Default::effect.value }; + float _wet { Default::effect }; std::unique_ptr _stringsArray; diff --git a/src/sfizz/effects/Width.cpp b/src/sfizz/effects/Width.cpp index 2a3cdc92..98906e52 100644 --- a/src/sfizz/effects/Width.cpp +++ b/src/sfizz/effects/Width.cpp @@ -69,8 +69,7 @@ namespace fx { for (const Opcode& opc : members) { switch (opc.lettersOnlyHash) { case hash("width"): - if (auto value = opc.read(Default::width)) - width->_width = *value; + width->_width = opc.read(Default::width); break; } } diff --git a/tests/OpcodeT.cpp b/tests/OpcodeT.cpp index 61971b39..7439a306 100644 --- a/tests/OpcodeT.cpp +++ b/tests/OpcodeT.cpp @@ -317,8 +317,8 @@ TEST_CASE("[Opcode] opcode read (uint8_t)") SECTION("Ignore") { Opcode opcode { "", "110" }; - OpcodeSpec spec { 0, Range(0, 100), kIgnoreOOB }; - REQUIRE( !opcode.read(spec) ); + OpcodeSpec spec { 0, Range(0, 100), 0 }; + REQUIRE( opcode.read(spec) == spec.defaultValue ); } SECTION("Clamp upper") @@ -345,21 +345,21 @@ TEST_CASE("[Opcode] opcode read (uint8_t)") SECTION("Text after") { Opcode opcode { "", "10garbage" }; - OpcodeSpec spec { 0, Range(20, 100), kEnforceLowerBound }; - REQUIRE( opcode.read(spec) == 20 ); + OpcodeSpec spec { 0, Range(0, 100), 0 }; + REQUIRE( opcode.read(spec) == 10 ); } SECTION("Text before") { Opcode opcode { "", "garbage10" }; - OpcodeSpec spec { 0, Range(20, 100), 0 }; - REQUIRE( !opcode.read(spec) ); + OpcodeSpec spec { 0, Range(0, 100), 0 }; + REQUIRE( opcode.read(spec) == spec.defaultValue ); } SECTION("Can be note") { Opcode opcode { "", "c4" }; - OpcodeSpec spec { 0, Range(20, 100), kCanBeNote }; + OpcodeSpec spec { 0, Range(0, 100), kCanBeNote }; REQUIRE( opcode.read(spec) == 60 ); } } @@ -387,13 +387,6 @@ TEST_CASE("[Opcode] opcode read (int)") REQUIRE( opcode.read(spec) == -16); } - SECTION("Ignore") - { - Opcode opcode { "", "110" }; - OpcodeSpec spec { 0, Range(-100, 100), kIgnoreOOB }; - REQUIRE( !opcode.read(spec) ); - } - SECTION("Clamp upper") { Opcode opcode { "", "110" }; @@ -418,7 +411,7 @@ TEST_CASE("[Opcode] opcode read (int)") SECTION("Text after") { Opcode opcode { "", "10garbage" }; - OpcodeSpec spec { 0, Range(20, 100), kEnforceLowerBound }; + OpcodeSpec spec { 0, Range(20, 100), 0 }; REQUIRE( opcode.read(spec) == 20 ); } @@ -464,8 +457,8 @@ TEST_CASE("[Opcode] opcode read (float)") SECTION("Ignore") { Opcode opcode { "", "110" }; - OpcodeSpec spec { 0.0f, Range(-100.0f, 100.0f), kIgnoreOOB }; - REQUIRE( !opcode.read(spec) ); + OpcodeSpec spec { 0.0f, Range(-100.0f, 100.0f), 0 }; + REQUIRE( opcode.read(spec) == spec.defaultValue ); } SECTION("Clamp upper") diff --git a/tests/RegionValueComputationsT.cpp b/tests/RegionValueComputationsT.cpp index 39412b95..f3b1abca 100644 --- a/tests/RegionValueComputationsT.cpp +++ b/tests/RegionValueComputationsT.cpp @@ -299,15 +299,15 @@ TEST_CASE("[Region] rt_decay") region.parseOpcode({ "rt_decay", "10" }); midiState.noteOnEvent(0, 64, 64_norm); midiState.advanceTime(100); - REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume.value - 1.0f).margin(0.1) ); + REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume - 1.0f).margin(0.1) ); region.parseOpcode({ "rt_decay", "20" }); midiState.noteOnEvent(0, 64, 64_norm); midiState.advanceTime(100); - REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume.value - 2.0f).margin(0.1) ); + REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume - 2.0f).margin(0.1) ); region.parseOpcode({ "trigger", "attack" }); midiState.noteOnEvent(0, 64, 64_norm); midiState.advanceTime(100); - REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume.value).margin(0.1) ); + REQUIRE( region.getBaseVolumedB(64) == Approx(Default::volume).margin(0.1) ); } TEST_CASE("[Region] Base delay") diff --git a/tests/RegionValuesT.cpp b/tests/RegionValuesT.cpp index a3e02417..a457607b 100644 --- a/tests/RegionValuesT.cpp +++ b/tests/RegionValuesT.cpp @@ -248,9 +248,9 @@ TEST_CASE("[Values] Count") synth.dispatchMessage(client, 0, "/region1/count", "", nullptr); synth.dispatchMessage(client, 0, "/region2/count", "", nullptr); std::vector expected { - "/region0/count,N : { }", + "/region0/count,h : { 1 }", "/region1/count,h : { 2 }", - "/region2/count,N : { }", + "/region2/count,h : { 1 }", }; REQUIRE(messageList == expected); } @@ -453,7 +453,7 @@ TEST_CASE("[Values] Off time") std::vector expected { "/region0/off_time,f : { 0.006 }", "/region1/off_time,f : { 0.1 }", - "/region2/off_time,f : { 0 }", + "/region2/off_time,f : { 0.006 }", }; REQUIRE(messageList == expected); } @@ -747,7 +747,7 @@ TEST_CASE("[Values] Upswitch") "/region2/sw_up,N : { }", "/region3/sw_up,N : { }", "/region4/sw_up,i : { 60 }", - "/region5/sw_up,i : { 64 }", + "/region5/sw_up,i : { 60 }", }; REQUIRE(messageList == expected); } @@ -778,7 +778,7 @@ TEST_CASE("[Values] Downswitch") "/region2/sw_down,N : { }", "/region3/sw_down,N : { }", "/region4/sw_down,i : { 60 }", - "/region5/sw_down,i : { 64 }", + "/region5/sw_down,i : { 60 }", }; REQUIRE(messageList == expected); } diff --git a/tests/SynthT.cpp b/tests/SynthT.cpp index fa5cb076..78701e5b 100644 --- a/tests/SynthT.cpp +++ b/tests/SynthT.cpp @@ -572,7 +572,7 @@ TEST_CASE("[Synth] sample quality") // default sample quality synth.noteOn(0, 60, 100); REQUIRE(synth.getNumActiveVoices() == 1); - REQUIRE(synth.getVoiceView(0)->getCurrentSampleQuality() == sfz::Default::sampleQuality.value); + REQUIRE(synth.getVoiceView(0)->getCurrentSampleQuality() == sfz::Default::sampleQuality); synth.allSoundOff(); // default sample quality, freewheeling From 9a1e3971a9ac2599b0a85d8e190c64fa82f512e8 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Wed, 3 Feb 2021 10:43:05 +0100 Subject: [PATCH 08/15] WIP --- src/CMakeLists.txt | 2 +- src/sfizz/Defaults.cpp | 32 ++++++++++---------- src/sfizz/Defaults.h | 41 ++++++++++++++++++++++--- src/sfizz/Opcode.cpp | 66 +++++++++++++++++++---------------------- src/sfizz/Opcode.h | 5 +++- src/sfizz/Region.cpp | 14 ++++----- src/sfizz/Region.h | 2 +- src/sfizz/SfzHelpers.h | 13 +++++--- tests/OpcodeT.cpp | 6 ++-- tests/RegionValuesT.cpp | 13 ++++---- 10 files changed, 113 insertions(+), 81 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d3c1f2bc..c2e40836 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -137,7 +137,6 @@ set(SFIZZ_SOURCES sfizz/Wavetables.cpp sfizz/Tuning.cpp sfizz/RegionSet.cpp - sfizz/Defaults.cpp sfizz/PolyphonyGroup.cpp sfizz/VoiceManager.cpp sfizz/VoiceStealing.cpp @@ -201,6 +200,7 @@ set(SFIZZ_PARSER_HEADERS set(SFIZZ_PARSER_SOURCES sfizz/Opcode.cpp + sfizz/Defaults.cpp sfizz/OpcodeCleanup.cpp sfizz/parser/Parser.cpp sfizz/parser/ParserPrivate.cpp) diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp index ee712e58..f883bc20 100644 --- a/src/sfizz/Defaults.cpp +++ b/src/sfizz/Defaults.cpp @@ -1,6 +1,4 @@ #include "Defaults.h" -#include "MathHelpers.h" -#include "SfzHelpers.h" namespace sfz { @@ -23,7 +21,7 @@ extern const OpcodeSpec oscillatorMode { 0, Range(0, 2), 0 }; extern const OpcodeSpec oscillatorMulti { 1, Range(1, config::oscillatorsPerVoice), 0 }; extern const OpcodeSpec oscillatorDetune { 0.0f, Range(-12000.0f, 12000.0f), 0 }; extern const OpcodeSpec oscillatorDetuneMod { 0.0f, Range(-12000.0f, 12000.0f), 0 }; -extern const OpcodeSpec oscillatorModDepth { 0.0f, Range(0.0f, 10000.0f), kNormalizePercent }; +extern const OpcodeSpec oscillatorModDepth { 0.0f, Range(0.0f, 10000.0f), 0 }; extern const OpcodeSpec oscillatorModDepthMod { 0.0f, Range(0.0f, 10000.0f), 0 }; extern const OpcodeSpec oscillatorQuality { 1, Range(0, 3), 0 }; extern const OpcodeSpec group { 0, Range(0, uint32_t_max), 0 }; @@ -33,14 +31,14 @@ extern const OpcodeSpec notePolyphony { config::maxVoices, Range key { 60, Range(0, 127), kCanBeNote }; extern const OpcodeSpec loKey { 0, Range(0, 127), kCanBeNote }; extern const OpcodeSpec hiKey { 127, Range(0, 127), kCanBeNote }; -extern const OpcodeSpec loCC { 0.0f , Range(0.0f, 127.0f), kNormalizeMidi }; -extern const OpcodeSpec hiCC { 1.0f , Range(0.0f, 127.0f), kNormalizeMidi }; -extern const OpcodeSpec loVel { 0.0f , Range(0.0f, 127.0f), kNormalizeMidi }; -extern const OpcodeSpec hiVel { 1.0f , Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec loCC { 0, Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec hiCC { 127, Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec loVel { 0, Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec hiVel { 127, Range(0.0f, 127.0f), kNormalizeMidi }; extern const OpcodeSpec loChannelAftertouch { 0, Range(0, 127), 0 }; extern const OpcodeSpec hiChannelAftertouch { 127, Range(0, 127), 0 }; -extern const OpcodeSpec loBend { -1.0f, Range(-8192.0f, 8192.0f), kNormalizeBend }; -extern const OpcodeSpec hiBend { 1.0f, Range(-8192.0f, 8192.0f), kNormalizeBend }; +extern const OpcodeSpec loBend { -8192, Range(-8192.0f, 8192.0f), kNormalizeBend }; +extern const OpcodeSpec hiBend { 8192, Range(-8192.0f, 8192.0f), kNormalizeBend }; extern const OpcodeSpec loNormalized { 0.0f, Range(0.0f, 1.0f), 0 }; extern const OpcodeSpec hiNormalized { 1.0f, Range(0.0f, 1.0f), 0 }; extern const OpcodeSpec loBipolar { -1.0f, Range(-1.0f, 1.0f), 0 }; @@ -49,7 +47,7 @@ extern const OpcodeSpec ccNumber { 0, Range(0, config::numCC extern const OpcodeSpec smoothCC { 0, Range(0, 100), 0 }; extern const OpcodeSpec curveCC { 0, Range(0, 255), 0 }; extern const OpcodeSpec sustainCC { 64, Range(0, 127), 0 }; -extern const OpcodeSpec sustainThreshold { 0.0039f, Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec sustainThreshold { 1, Range(0.0f, 127.0f), kNormalizeMidi }; extern const OpcodeSpec checkSustain { true, Range(0, 1), 0 }; extern const OpcodeSpec checkSostenuto { true, Range(0, 1), 0 }; extern const OpcodeSpec loBPM { 0.0f, Range(0.0f, 500.0f), 0 }; @@ -58,19 +56,19 @@ extern const OpcodeSpec sequence { 1, Range(1, 100), 0 }; extern const OpcodeSpec volume { 0.0f, Range(-144.0f, 48.0f), 0 }; extern const OpcodeSpec volumeMod { 0.0f, Range(-144.0f, 48.0f), 0 }; extern const OpcodeSpec amplitude { 100.0f, Range(0.0f, 10000.0f), kNormalizePercent }; -extern const OpcodeSpec amplitudeMod { 0.0f, Range(0.0f, 10000.0f), kNormalizePercent }; +extern const OpcodeSpec amplitudeMod { 0.0f, Range(0.0f, 10000.0f), 0 }; extern const OpcodeSpec pan { 0.0f, Range(-100.0f, 100.0f), kNormalizePercent }; -extern const OpcodeSpec panMod { 0.0f, Range(-200.0f, 200.0f), kNormalizePercent }; +extern const OpcodeSpec panMod { 0.0f, Range(-200.0f, 200.0f), 0 }; extern const OpcodeSpec position { 0.0f, Range(-100.0f, 100.0f), kNormalizePercent }; -extern const OpcodeSpec positionMod { 0.0f, Range(-200.0f, 200.0f), kNormalizePercent }; +extern const OpcodeSpec positionMod { 0.0f, Range(-200.0f, 200.0f), 0 }; extern const OpcodeSpec width { 100.0f, Range(-100.0f, 100.0f), kNormalizePercent }; -extern const OpcodeSpec widthMod { 0.0f, Range(-200.0f, 200.0f), kNormalizePercent }; +extern const OpcodeSpec widthMod { 0.0f, Range(-200.0f, 200.0f), 0 }; extern const OpcodeSpec crossfadeIn { 0.0f, Range(0.0f, 127.0f), kNormalizeMidi }; extern const OpcodeSpec crossfadeInNorm { 0.0f, Range(0.0f, 1.0f), 0 }; -extern const OpcodeSpec crossfadeOut { 1.0f, Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec crossfadeOut { 127.0f, Range(0.0f, 127.0f), kNormalizeMidi }; extern const OpcodeSpec crossfadeOutNorm { 1.0f, Range(0.0f, 1.0f), 0 }; extern const OpcodeSpec ampKeytrack { 0.0f, Range(-96.0f, 12.0f), 0 }; -extern const OpcodeSpec ampVeltrack { 100.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec ampVeltrack { 100.0f, Range(-100.0f, 100.0f), kNormalizePercent }; extern const OpcodeSpec ampVelcurve { 0.0f, Range(0.0f, 1.0f), 0 }; extern const OpcodeSpec ampRandom { 0.0f, Range(0.0f, 24.0f), 0 }; extern const OpcodeSpec rtDead { false, Range(0, 1), 0 }; @@ -144,7 +142,7 @@ extern const OpcodeSpec compRelease { 0.05f, Range(0.0f, 10.0f), 0 extern const OpcodeSpec compSTLink { false, Range(0, 1), 0 }; extern const OpcodeSpec compThreshold { 0.0f, Range(-100.0f, 0.0f), 0 }; extern const OpcodeSpec compRatio { 1.0f, Range(1.0f, 50.0f), 0 }; -extern const OpcodeSpec compGain { 1.0f, Range(-100.0f, 100.0f), kDb2Mag }; +extern const OpcodeSpec compGain { 0.0f, Range(-100.0f, 100.0f), kDb2Mag }; extern const OpcodeSpec fverbSize { 0.0f, Range(0.0f, 100.0f), 0 }; extern const OpcodeSpec fverbPredelay { 0.0f, Range(0.0f, 10.0f), 0 }; extern const OpcodeSpec fverbTone { 100.0f, Range(0.0f, 100.0f), 0 }; diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 27f5481c..8e25ec5e 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -24,11 +24,14 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once +#include +#include +#include #include "Range.h" #include "Config.h" #include "SfzFilter.h" -#include -#include +#include "SfzHelpers.h" +#include "MathHelpers.h" namespace sfz @@ -68,10 +71,40 @@ enum OpcodeFlags : int { template struct OpcodeSpec { - T defaultValue; + T defaultInputValue; Range bounds; int flags; - operator T() const { return defaultValue; } + template + typename std::enable_if::value, U>::type normalizeInput(U input) const + { + constexpr auto needsOperation { + kNormalizePercent | + kNormalizeMidi | + kNormalizeBend | + kDb2Mag + }; + + if (!(flags & needsOperation)) + return input; + else if (flags & kNormalizePercent) + return normalizePercents(input); + else if (flags & kNormalizeMidi) + return normalize7Bits(input); + else if (flags & kNormalizeBend) + return normalizeBend(input); + else if (flags & kDb2Mag) + return db2mag(input); + else // just in case + return input; + } + + template + typename std::enable_if::value, U>::type normalizeInput(U input) const + { + return input; + } + + operator T() const { return normalizeInput(defaultInputValue); } }; namespace Default diff --git a/src/sfizz/Opcode.cpp b/src/sfizz/Opcode.cpp index a3e747fc..fcc323a8 100644 --- a/src/sfizz/Opcode.cpp +++ b/src/sfizz/Opcode.cpp @@ -155,9 +155,9 @@ absl::optional readInt_(OpcodeSpec spec, absl::string_view v) #define INSTANTIATE_FOR_INTEGRAL(T) \ template <> \ - T Opcode::read(OpcodeSpec spec) const \ + absl::optional Opcode::readOptional(OpcodeSpec spec) const \ { \ - return readInt_(spec, value).value_or(spec.defaultValue); \ + return readInt_(spec, value); \ } INSTANTIATE_FOR_INTEGRAL(uint8_t) @@ -205,23 +205,14 @@ absl::optional readFloat_(OpcodeSpec spec, absl::string_view v) return {}; } - if (spec.flags & kNormalizeMidi) - returnedValue = normalize7Bits(returnedValue); - else if (spec.flags & kNormalizePercent) - returnedValue = normalizePercents(returnedValue); - else if (spec.flags & kNormalizeBend) - returnedValue = normalizeBend(returnedValue); - else if (spec.flags & kDb2Mag) - returnedValue = db2mag(returnedValue); - - return returnedValue; + return spec.normalizeInput(returnedValue); } #define INSTANTIATE_FOR_FLOATING_POINT(T) \ template <> \ - T Opcode::read(OpcodeSpec spec) const \ + absl::optional Opcode::readOptional(OpcodeSpec spec) const \ { \ - return readFloat_(spec, value).value_or(spec.defaultValue); \ + return readFloat_(spec, value); \ } INSTANTIATE_FOR_FLOATING_POINT(float) @@ -292,17 +283,17 @@ absl::optional readBooleanFromOpcode(const Opcode& opcode) } template <> -OscillatorEnabled Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { auto v = readBooleanFromOpcode(*this); if (!v) - return spec.defaultValue; + return {}; return *v ? OscillatorEnabled::On : OscillatorEnabled::Off; } template <> -Trigger Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { switch (hash(value)) { case hash("attack"): return Trigger::attack; @@ -313,11 +304,11 @@ Trigger Opcode::read(OpcodeSpec spec) const } DBG("Unknown trigger value: " << value); - return spec.defaultValue; + return absl::nullopt; } template <> -CrossfadeCurve Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { switch (hash(value)) { case hash("power"): return CrossfadeCurve::power; @@ -325,11 +316,11 @@ CrossfadeCurve Opcode::read(OpcodeSpec spec) const } DBG("Unknown crossfade power curve: " << value); - return spec.defaultValue; + return absl::nullopt; } template <> -OffMode Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { switch (hash(value)) { case hash("fast"): return OffMode::fast; @@ -338,11 +329,11 @@ OffMode Opcode::read(OpcodeSpec spec) const } DBG("Unknown off mode: " << value); - return spec.defaultValue; + return absl::nullopt; } template <> -FilterType Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { switch (hash(value)) { case hash("lpf_1p"): return kFilterLpf1p; @@ -371,11 +362,11 @@ FilterType Opcode::read(OpcodeSpec spec) const } DBG("Unknown filter type: " << value); - return spec.defaultValue; + return absl::nullopt; } template <> -EqType Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { switch (hash(value)) { case hash("peak"): return kEqPeak; @@ -384,11 +375,11 @@ EqType Opcode::read(OpcodeSpec spec) const } DBG("Unknown EQ type: " << value); - return spec.defaultValue; + return absl::nullopt; } template <> -VelocityOverride Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { switch (hash(value)) { case hash("current"): return VelocityOverride::current; @@ -396,11 +387,11 @@ VelocityOverride Opcode::read(OpcodeSpec spec) const } DBG("Unknown velocity override: " << value); - return spec.defaultValue; + return absl::nullopt; } template <> -SelfMask Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { switch (hash(value)) { case hash("on"): @@ -409,25 +400,28 @@ SelfMask Opcode::read(OpcodeSpec spec) const } DBG("Unknown velocity override: " << value); - return spec.defaultValue; + return absl::nullopt; } template <> -bool Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec) const { - return readBooleanFromOpcode(*this).value_or(spec.defaultValue); + return readBooleanFromOpcode(*this); } template <> -LFOWave Opcode::read(OpcodeSpec spec) const +absl::optional Opcode::readOptional(OpcodeSpec spec) const { const OpcodeSpec intSpec { - static_cast(spec.defaultValue), + static_cast(spec.defaultInputValue), Range(static_cast(spec.bounds.getStart()), static_cast(spec.bounds.getEnd())), 0 }; - int value = read(intSpec); - return static_cast(value); + + if (auto value = readOptional(intSpec)) + return static_cast(*value); + + return absl::nullopt; } } // namespace sfz diff --git a/src/sfizz/Opcode.h b/src/sfizz/Opcode.h index 3df4ed08..314e64f0 100644 --- a/src/sfizz/Opcode.h +++ b/src/sfizz/Opcode.h @@ -102,7 +102,10 @@ struct Opcode { } template - T read(OpcodeSpec spec) const; + absl::optional readOptional(OpcodeSpec spec) const; + + template + T read(OpcodeSpec spec) const { return readOptional(spec).value_or(spec); } private: static OpcodeCategory identifyCategory(absl::string_view name); diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 0f86c802..d892bd68 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -283,8 +283,8 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) break; case hash("sw_last"): if (!lastKeyswitchRange) { - lastKeyswitch = opcode.read(Default::key); - keySwitched = false; + lastKeyswitch = opcode.readOptional(Default::key); + keySwitched = !lastKeyswitch.has_value(); } break; case hash("sw_lolast"): @@ -315,15 +315,15 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) keyswitchLabel = opcode.value; break; case hash("sw_down"): - downKeyswitch = opcode.read(Default::key); - keySwitched = false; + downKeyswitch = opcode.readOptional(Default::key); + keySwitched = !downKeyswitch.has_value(); break; case hash("sw_up"): - upKeyswitch = opcode.read(Default::key); + upKeyswitch = opcode.readOptional(Default::key); break; case hash("sw_previous"): - previousKeyswitch = opcode.read(Default::key); - previousKeySwitched = false; + previousKeyswitch = opcode.readOptional(Default::key); + previousKeySwitched = !previousKeyswitch.has_value(); break; case hash("sw_vel"): velocityOverride = diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index 4a7324f8..c0ea5968 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -389,7 +389,7 @@ struct Region { float position { normalizePercents(Default::position) }; // position uint8_t ampKeycenter { Default::key }; // amp_keycenter float ampKeytrack { Default::ampKeytrack }; // amp_keytrack - float ampVeltrack { normalizePercents(Default::ampVeltrack) }; // amp_veltrack + float ampVeltrack { Default::ampVeltrack }; // amp_veltrack std::vector> velocityPoints; // amp_velcurve_N absl::optional velCurve {}; float ampRandom { Default::ampRandom }; // amp_random diff --git a/src/sfizz/SfzHelpers.h b/src/sfizz/SfzHelpers.h index 7577d60d..8fd15b33 100644 --- a/src/sfizz/SfzHelpers.h +++ b/src/sfizz/SfzHelpers.h @@ -16,7 +16,6 @@ #include "MathHelpers.h" #include "SIMDHelpers.h" #include "absl/meta/type_traits.h" -#include "Defaults.h" namespace sfz { @@ -126,6 +125,12 @@ constexpr float normalize7Bits(T value) return static_cast(min(max(value, T { 0 }), T { 127 })) / 127.0f; } +template <> +constexpr float normalize7Bits(bool value) +{ + return value ? 1.0f : 0.0f; +} + /** * @brief Normalize a CC value between 0.0 and 1.0 * @@ -188,11 +193,11 @@ inline CXX14_CONSTEXPR uint8_t offsetAndClampKey(uint8_t key, int offset) { const int offsetKey { key + offset }; if (offsetKey > std::numeric_limits::max()) - return Default::key.bounds.getEnd(); + return 127; if (offsetKey < std::numeric_limits::min()) - return Default::key.bounds.getStart(); + return 0; - return Default::key.bounds.clamp(static_cast(offsetKey)); + return clamp(static_cast(offsetKey), 0, 127); } namespace literals { diff --git a/tests/OpcodeT.cpp b/tests/OpcodeT.cpp index 7439a306..b01201a5 100644 --- a/tests/OpcodeT.cpp +++ b/tests/OpcodeT.cpp @@ -318,7 +318,7 @@ TEST_CASE("[Opcode] opcode read (uint8_t)") { Opcode opcode { "", "110" }; OpcodeSpec spec { 0, Range(0, 100), 0 }; - REQUIRE( opcode.read(spec) == spec.defaultValue ); + REQUIRE( opcode.read(spec) == spec.defaultInputValue ); } SECTION("Clamp upper") @@ -353,7 +353,7 @@ TEST_CASE("[Opcode] opcode read (uint8_t)") { Opcode opcode { "", "garbage10" }; OpcodeSpec spec { 0, Range(0, 100), 0 }; - REQUIRE( opcode.read(spec) == spec.defaultValue ); + REQUIRE( opcode.read(spec) == spec.defaultInputValue ); } SECTION("Can be note") @@ -458,7 +458,7 @@ TEST_CASE("[Opcode] opcode read (float)") { Opcode opcode { "", "110" }; OpcodeSpec spec { 0.0f, Range(-100.0f, 100.0f), 0 }; - REQUIRE( opcode.read(spec) == spec.defaultValue ); + REQUIRE( opcode.read(spec) == spec.defaultInputValue ); } SECTION("Clamp upper") diff --git a/tests/RegionValuesT.cpp b/tests/RegionValuesT.cpp index a457607b..c0e85444 100644 --- a/tests/RegionValuesT.cpp +++ b/tests/RegionValuesT.cpp @@ -747,7 +747,7 @@ TEST_CASE("[Values] Upswitch") "/region2/sw_up,N : { }", "/region3/sw_up,N : { }", "/region4/sw_up,i : { 60 }", - "/region5/sw_up,i : { 60 }", + "/region5/sw_up,N : { }", }; REQUIRE(messageList == expected); } @@ -778,7 +778,7 @@ TEST_CASE("[Values] Downswitch") "/region2/sw_down,N : { }", "/region3/sw_down,N : { }", "/region4/sw_down,i : { 60 }", - "/region5/sw_down,i : { 60 }", + "/region5/sw_down,N : { }", }; REQUIRE(messageList == expected); } @@ -809,7 +809,7 @@ TEST_CASE("[Values] Previous keyswitch") "/region2/sw_previous,N : { }", "/region3/sw_previous,N : { }", "/region4/sw_previous,i : { 60 }", - "/region5/sw_previous,i : { 64 }", + "/region5/sw_previous,N : { }", }; REQUIRE(messageList == expected); } @@ -889,7 +889,7 @@ TEST_CASE("[Values] BPM range") "/region0/bpm_range,ff : { 0, 500 }", "/region1/bpm_range,ff : { 34.1, 60.2 }", "/region2/bpm_range,ff : { 0, 60 }", - "/region3/bpm_range,ff : { 0, 0 }", + "/region3/bpm_range,ff : { 20, 500 }", "/region4/bpm_range,ff : { 10, 10 }", }; REQUIRE(messageList == expected); @@ -1553,12 +1553,11 @@ TEST_CASE("[Values] Amp Veltrack") )"); synth.dispatchMessage(client, 0, "/region0/amp_veltrack", "", nullptr); synth.dispatchMessage(client, 0, "/region1/amp_veltrack", "", nullptr); - // TODO: activate for the new region parser ; ignore oob - // synth.dispatchMessage(client, 0, "/region2/amp_veltrack", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/amp_veltrack", "", nullptr); std::vector expected { "/region0/amp_veltrack,f : { 100 }", "/region1/amp_veltrack,f : { 10.1 }", - // "/region2/amp_veltrack,f : { 100 }", + "/region2/amp_veltrack,f : { 100 }", }; REQUIRE(messageList == expected); } From 49d749e35481fae9f66d67791d0eeb8bff02337f Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Wed, 3 Feb 2021 21:57:17 +0100 Subject: [PATCH 09/15] WIP --- src/sfizz/Defaults.h | 8 ++++---- src/sfizz/Region.h | 8 ++++---- src/sfizz/Synth.cpp | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 8e25ec5e..65e7215f 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -87,13 +87,13 @@ struct OpcodeSpec if (!(flags & needsOperation)) return input; else if (flags & kNormalizePercent) - return normalizePercents(input); + return static_cast(normalizePercents(input)); else if (flags & kNormalizeMidi) - return normalize7Bits(input); + return static_cast(normalize7Bits(input)); else if (flags & kNormalizeBend) - return normalizeBend(input); + return static_cast(normalizeBend(input)); else if (flags & kDb2Mag) - return db2mag(input); + return static_cast(db2mag(input)); else // just in case return input; } diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index c0ea5968..4b3ee6c2 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -383,10 +383,10 @@ struct Region { // Performance parameters: amplifier float volume { Default::volume }; // volume - float amplitude { normalizePercents(Default::amplitude) }; // amplitude - float pan { normalizePercents(Default::pan) }; // pan - float width { normalizePercents(Default::width) }; // width - float position { normalizePercents(Default::position) }; // position + float amplitude { Default::amplitude }; // amplitude + float pan { Default::pan }; // pan + float width { Default::width }; // width + float position { Default::position }; // position uint8_t ampKeycenter { Default::key }; // amp_keycenter float ampKeytrack { Default::ampKeytrack }; // amp_keytrack float ampVeltrack { Default::ampVeltrack }; // amp_veltrack diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index fefa48d4..58c04f4d 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -360,7 +360,7 @@ void Synth::Impl::handleControlOpcodes(const std::vector& members) } break; case hash("label_cc&"): - if (Default::ccNumberRange.containsWithEnd(member.parameters.back())) + if (Default::ccNumber.bounds.containsWithEnd(member.parameters.back())) setCCLabel(member.parameters.back(), std::string(member.value)); break; case hash("label_key&"): From cb2caf4b15586705a42bfc74e8e49ab681a24f86 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Thu, 4 Feb 2021 00:19:11 +0100 Subject: [PATCH 10/15] Working tests --- src/sfizz/Curve.cpp | 3 +- src/sfizz/Defaults.cpp | 12 ++--- src/sfizz/Opcode.cpp | 12 +++-- src/sfizz/Region.cpp | 18 +++---- tests/OpcodeT.cpp | 13 +++-- tests/RegionValuesT.cpp | 106 +++++++++++++++++----------------------- 6 files changed, 79 insertions(+), 85 deletions(-) diff --git a/src/sfizz/Curve.cpp b/src/sfizz/Curve.cpp index 1f1c792b..30418d12 100644 --- a/src/sfizz/Curve.cpp +++ b/src/sfizz/Curve.cpp @@ -21,8 +21,7 @@ Curve Curve::buildCurveFromHeader( { Curve curve; bool fillStatus[NumValues] = {}; - const OpcodeSpec fullRange {0.0f, Range(-HUGE_VALF, +HUGE_VALF), 0 }; - + const OpcodeSpec fullRange {0.0f, Range{ -1e16, 1e16 }, 0 }; auto setPoint = [&curve, &fillStatus](int i, float x) { curve._points[i] = x; fillStatus[i] = true; diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp index f883bc20..e56171cb 100644 --- a/src/sfizz/Defaults.cpp +++ b/src/sfizz/Defaults.cpp @@ -16,13 +16,13 @@ extern const OpcodeSpec loopStart { 0, Range(0, uint32_t_max extern const OpcodeSpec loopEnd { uint32_t_max, Range(0, uint32_t_max), 0 }; extern const OpcodeSpec loopCrossfade { 1e-3, Range(1e-3, 1.0f), 0 }; extern const OpcodeSpec oscillator { OscillatorEnabled::Auto, Range(OscillatorEnabled::Auto, OscillatorEnabled::On), 0 }; -extern const OpcodeSpec oscillatorPhase { 0.0f, Range(0.0f, 1.0f), 0 }; +extern const OpcodeSpec oscillatorPhase { 0.0f, Range(-1000.0f, 1000.0f), 0 }; extern const OpcodeSpec oscillatorMode { 0, Range(0, 2), 0 }; extern const OpcodeSpec oscillatorMulti { 1, Range(1, config::oscillatorsPerVoice), 0 }; extern const OpcodeSpec oscillatorDetune { 0.0f, Range(-12000.0f, 12000.0f), 0 }; extern const OpcodeSpec oscillatorDetuneMod { 0.0f, Range(-12000.0f, 12000.0f), 0 }; -extern const OpcodeSpec oscillatorModDepth { 0.0f, Range(0.0f, 10000.0f), 0 }; -extern const OpcodeSpec oscillatorModDepthMod { 0.0f, Range(0.0f, 10000.0f), 0 }; +extern const OpcodeSpec oscillatorModDepth { 0.0f, Range(0.0f, 10000.0f), kNormalizePercent }; +extern const OpcodeSpec oscillatorModDepthMod { 0.0f, Range(0.0f, 10000.0f), kNormalizePercent }; extern const OpcodeSpec oscillatorQuality { 1, Range(0, 3), 0 }; extern const OpcodeSpec group { 0, Range(0, uint32_t_max), 0 }; extern const OpcodeSpec offTime { 6e-3f, Range(0.0f, 100.0f), 0 }; @@ -47,7 +47,7 @@ extern const OpcodeSpec ccNumber { 0, Range(0, config::numCC extern const OpcodeSpec smoothCC { 0, Range(0, 100), 0 }; extern const OpcodeSpec curveCC { 0, Range(0, 255), 0 }; extern const OpcodeSpec sustainCC { 64, Range(0, 127), 0 }; -extern const OpcodeSpec sustainThreshold { 1, Range(0.0f, 127.0f), kNormalizeMidi }; +extern const OpcodeSpec sustainThreshold { 1.0f, Range(0.0f, 127.0f), kNormalizeMidi }; extern const OpcodeSpec checkSustain { true, Range(0, 1), 0 }; extern const OpcodeSpec checkSostenuto { true, Range(0, 1), 0 }; extern const OpcodeSpec loBPM { 0.0f, Range(0.0f, 500.0f), 0 }; @@ -94,8 +94,8 @@ extern const OpcodeSpec pitchKeytrack { 100, Range(-1200, 1200), 0 }; extern const OpcodeSpec pitchRandom { 0.0f, Range(0.0f, 12000.0f), 0 }; extern const OpcodeSpec pitchVeltrack { 0, Range(-12000, 12000), 0 }; extern const OpcodeSpec transpose { 0, Range(-127, 127), 0 }; -extern const OpcodeSpec pitch { 0.0f, Range(-100.0f, 100.0f), 0 }; -extern const OpcodeSpec pitchMod { 0.0f, Range(-100.0f, 100.0f), 0 }; +extern const OpcodeSpec pitch { 0.0f, Range(-2400.0f, 2400.0f), 0 }; +extern const OpcodeSpec pitchMod { 0.0f, Range(-2400.0f, 2400.0f), 0 }; extern const OpcodeSpec bendUp { 200.0f, Range(-12000.0f, 12000.0f), 0 }; extern const OpcodeSpec bendDown { -200.0f, Range(-12000.0f, 12000.0f), 0 }; extern const OpcodeSpec bendStep { 1.0f, Range(1.0f, 1200.0f), 0 }; diff --git a/src/sfizz/Opcode.cpp b/src/sfizz/Opcode.cpp index fcc323a8..201709de 100644 --- a/src/sfizz/Opcode.cpp +++ b/src/sfizz/Opcode.cpp @@ -142,12 +142,12 @@ absl::optional readInt_(OpcodeSpec spec, absl::string_view v) if (spec.flags & kEnforceUpperBound) return spec.bounds.getEnd(); - return {}; + return absl::nullopt; } else if (returnedValue < static_cast(spec.bounds.getStart())) { if (spec.flags & kEnforceLowerBound) return spec.bounds.getStart(); - return {}; + return absl::nullopt; } return returnedValue; @@ -273,13 +273,19 @@ absl::optional readBooleanFromOpcode(const Opcode& opcode) // Cakewalk-style booleans, case-insensitive if (absl::EqualsIgnoreCase(opcode.value, "off")) return false; + if (absl::EqualsIgnoreCase(opcode.value, "on")) return true; // ARIA-style booleans? (seen in egN_dynamic=1 for example) // TODO check this const OpcodeSpec fullInt64 { 0, Range::wholeRange(), 0 }; - return opcode.read(fullInt64); + const auto v = opcode.readOptional(fullInt64); + + if (v) + return v != 0; + + return absl::nullopt; } template <> diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index d892bd68..d2710e0e 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -177,7 +177,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) ModKey::createNXYZ(ModId::OscillatorModDepth, id)); break; case hash("oscillator_quality"): - oscillatorQuality = opcode.read(Default::oscillatorQuality); + oscillatorQuality = opcode.readOptional(Default::oscillatorQuality); break; // Instrument settings: voice lifecycle @@ -334,7 +334,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) sustainCC = opcode.read(Default::sustainCC); break; case hash("sustain_lo"): - sustainThreshold = normalizeCC(opcode.read(Default::sustainThreshold)); + sustainThreshold = opcode.read(Default::sustainThreshold); break; case hash("sustain_sw"): checkSustain = opcode.read(Default::checkSustain); @@ -460,10 +460,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) crossfadeKeyInRange.setStart(opcode.read(Default::loKey)); break; case hash("xfin_hikey"): - crossfadeKeyInRange.setEnd(opcode.read(Default::hiKey)); + crossfadeKeyInRange.setEnd(opcode.read(Default::loKey)); // loKey for the proper default break; case hash("xfout_lokey"): - crossfadeKeyOutRange.setStart(opcode.read(Default::loKey)); + crossfadeKeyOutRange.setStart(opcode.read(Default::hiKey)); // hiKey for the proper default break; case hash("xfout_hikey"): crossfadeKeyOutRange.setEnd(opcode.read(Default::hiKey)); @@ -472,10 +472,10 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) crossfadeVelInRange.setStart(opcode.read(Default::loVel)); break; case hash("xfin_hivel"): - crossfadeVelInRange.setEnd(opcode.read(Default::hiVel)); + crossfadeVelInRange.setEnd(opcode.read(Default::loVel)); // loVel for the proper default break; case hash("xfout_lovel"): - crossfadeVelOutRange.setStart(opcode.read(Default::loVel)); + crossfadeVelOutRange.setStart(opcode.read(Default::hiVel)); // hiVel for the proper default break; case hash("xfout_hivel"): crossfadeVelOutRange.setEnd(opcode.read(Default::hiVel)); @@ -497,21 +497,21 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (opcode.parameters.back() >= config::numCCs) return false; crossfadeCCInRange[opcode.parameters.back()].setEnd( - opcode.read(Default::loCC) + opcode.read(Default::loCC) // loCC for the proper default ); break; case hash("xfout_locc&"): if (opcode.parameters.back() >= config::numCCs) return false; crossfadeCCOutRange[opcode.parameters.back()].setStart( - opcode.read(Default::loCC) + opcode.read(Default::hiCC) // hiCC for the proper default ); break; case hash("xfout_hicc&"): if (opcode.parameters.back() >= config::numCCs) return false; crossfadeCCOutRange[opcode.parameters.back()].setEnd( - opcode.read(Default::loCC) + opcode.read(Default::hiCC) ); break; case hash("xf_cccurve"): diff --git a/tests/OpcodeT.cpp b/tests/OpcodeT.cpp index b01201a5..20ce6a24 100644 --- a/tests/OpcodeT.cpp +++ b/tests/OpcodeT.cpp @@ -353,7 +353,8 @@ TEST_CASE("[Opcode] opcode read (uint8_t)") { Opcode opcode { "", "garbage10" }; OpcodeSpec spec { 0, Range(0, 100), 0 }; - REQUIRE( opcode.read(spec) == spec.defaultInputValue ); + REQUIRE( !opcode.readOptional(spec) ); + REQUIRE( opcode.read(spec) == 0 ); } SECTION("Can be note") @@ -411,15 +412,16 @@ TEST_CASE("[Opcode] opcode read (int)") SECTION("Text after") { Opcode opcode { "", "10garbage" }; - OpcodeSpec spec { 0, Range(20, 100), 0 }; - REQUIRE( opcode.read(spec) == 20 ); + OpcodeSpec spec { 0, Range(0, 100), 0 }; + REQUIRE( opcode.read(spec) == 10 ); } SECTION("Text before") { Opcode opcode { "", "garbage10" }; OpcodeSpec spec { 0, Range(20, 100), 0 }; - REQUIRE( !opcode.read(spec) ); + REQUIRE( !opcode.readOptional(spec) ); + REQUIRE( opcode.read(spec) == 0 ); } SECTION("Can be note") @@ -486,7 +488,8 @@ TEST_CASE("[Opcode] opcode read (float)") { Opcode opcode { "", "garbage10" }; OpcodeSpec spec { 0.0f, Range(0.0f, 100.0f), 0 }; - REQUIRE( !opcode.read(spec) ); + REQUIRE( !opcode.readOptional(spec) ); + REQUIRE( opcode.read(spec) == 0.0f ); } } diff --git a/tests/RegionValuesT.cpp b/tests/RegionValuesT.cpp index c0e85444..c34b6787 100644 --- a/tests/RegionValuesT.cpp +++ b/tests/RegionValuesT.cpp @@ -481,8 +481,7 @@ TEST_CASE("[Values] Key range") synth.dispatchMessage(client, 0, "/region4/key_range", "", nullptr); synth.dispatchMessage(client, 0, "/region0/pitch_keycenter", "", nullptr); synth.dispatchMessage(client, 0, "/region5/pitch_keycenter", "", nullptr); - // TODO: activate for the new region parser ; ignore the second value - // synth.dispatchMessage(client, 0, "/region6/pitch_keycenter", "", nullptr); + synth.dispatchMessage(client, 0, "/region6/pitch_keycenter", "", nullptr); synth.dispatchMessage(client, 0, "/region7/key_range", "", nullptr); synth.dispatchMessage(client, 0, "/region7/pitch_keycenter", "", nullptr); std::vector expected { @@ -493,7 +492,7 @@ TEST_CASE("[Values] Key range") "/region4/key_range,ii : { 0, 127 }", "/region0/pitch_keycenter,i : { 60 }", "/region5/pitch_keycenter,i : { 32 }", - // "/region6/pitch_keycenter,i : { 60 }", + "/region6/pitch_keycenter,i : { 60 }", "/region7/key_range,ii : { 26, 26 }", "/region7/pitch_keycenter,i : { 26 }", }; @@ -1612,7 +1611,7 @@ TEST_CASE("[Values] Crossfade key range") "/region1/xfin_key_range,ii : { 10, 40 }", "/region2/xfin_key_range,ii : { 60, 83 }", "/region3/xfin_key_range,ii : { 0, 40 }", - "/region4/xfin_key_range,ii : { 10, 10 }", + "/region4/xfin_key_range,ii : { 0, 0 }", }; REQUIRE(messageList == expected); } @@ -1666,7 +1665,7 @@ TEST_CASE("[Values] Crossfade velocity range") "/region0/xfin_vel_range,ff : { 0, 0 }", "/region1/xfin_vel_range,ff : { 0.0787402, 0.314961 }", "/region2/xfin_vel_range,ff : { 0, 0.314961 }", - "/region3/xfin_vel_range,ff : { 0.0787402, 1 }", + "/region3/xfin_vel_range,ff : { 0, 0 }", }; REQUIRE(messageList == expected); } @@ -1686,7 +1685,7 @@ TEST_CASE("[Values] Crossfade velocity range") std::vector expected { "/region0/xfout_vel_range,ff : { 1, 1 }", "/region1/xfout_vel_range,ff : { 0.0787402, 0.314961 }", - "/region2/xfout_vel_range,ff : { 0, 0.314961 }", + "/region2/xfout_vel_range,ff : { 0.314961, 0.314961 }", "/region3/xfout_vel_range,ff : { 0.0787402, 1 }", }; REQUIRE(messageList == expected); @@ -1787,7 +1786,7 @@ TEST_CASE("[Values] Crossfade CC range") "/region0/xfin_cc_range4,N : { }", "/region1/xfin_cc_range4,ff : { 0.0787402, 0.314961 }", "/region2/xfin_cc_range4,ff : { 0, 0.314961 }", - "/region3/xfin_cc_range4,ff : { 0.0787402, 1 }", + "/region3/xfin_cc_range4,ff : { 0, 0 }", }; REQUIRE(messageList == expected); } @@ -1807,7 +1806,7 @@ TEST_CASE("[Values] Crossfade CC range") std::vector expected { "/region0/xfout_cc_range4,N : { }", "/region1/xfout_cc_range4,ff : { 0.0787402, 0.314961 }", - "/region2/xfout_cc_range4,ff : { 0, 0.314961 }", + "/region2/xfout_cc_range4,ff : { 0.314961, 0.314961 }", "/region3/xfout_cc_range4,ff : { 0.0787402, 1 }", }; REQUIRE(messageList == expected); @@ -1934,12 +1933,11 @@ TEST_CASE("[Values] Pitch Random") )"); synth.dispatchMessage(client, 0, "/region0/pitch_random", "", nullptr); synth.dispatchMessage(client, 0, "/region1/pitch_random", "", nullptr); - // TODO: activate for the new region parser ; ignore oob - // synth.dispatchMessage(client, 0, "/region2/pitch_random", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/pitch_random", "", nullptr); std::vector expected { "/region0/pitch_random,f : { 0 }", "/region1/pitch_random,f : { 10 }", - // "/region2/pitch_random,f : { 0 }", + "/region2/pitch_random,f : { 0 }", }; REQUIRE(messageList == expected); } @@ -1961,15 +1959,14 @@ TEST_CASE("[Values] Transpose") synth.dispatchMessage(client, 0, "/region0/transpose", "", nullptr); synth.dispatchMessage(client, 0, "/region1/transpose", "", nullptr); synth.dispatchMessage(client, 0, "/region2/transpose", "", nullptr); - // TODO: activate for the new region parser ; ignore oob - // synth.dispatchMessage(client, 0, "/region3/transpose", "", nullptr); - // synth.dispatchMessage(client, 0, "/region4/transpose", "", nullptr); + synth.dispatchMessage(client, 0, "/region3/transpose", "", nullptr); + synth.dispatchMessage(client, 0, "/region4/transpose", "", nullptr); std::vector expected { "/region0/transpose,i : { 0 }", "/region1/transpose,i : { 10 }", "/region2/transpose,i : { -4 }", - // "/region3/transpose,i : { 0 }", - // "/region4/transpose,i : { 0 }", + "/region3/transpose,i : { 0 }", + "/region4/transpose,i : { 0 }", }; REQUIRE(messageList == expected); } @@ -2320,7 +2317,7 @@ TEST_CASE("[Values] RT dead") "/region0/rt_dead,F : { }", "/region1/rt_dead,T : { }", "/region2/rt_dead,F : { }", - "/region3/rt_dead,T : { }", + "/region3/rt_dead,F : { }", }; REQUIRE(messageList == expected); } @@ -2346,7 +2343,7 @@ TEST_CASE("[Values] Sustain switch") "/region0/sustain_sw,T : { }", "/region1/sustain_sw,F : { }", "/region2/sustain_sw,T : { }", - "/region3/sustain_sw,F : { }", + "/region3/sustain_sw,T : { }", }; REQUIRE(messageList == expected); } @@ -2372,7 +2369,7 @@ TEST_CASE("[Values] Sostenuto switch") "/region0/sostenuto_sw,T : { }", "/region1/sostenuto_sw,F : { }", "/region2/sostenuto_sw,T : { }", - "/region3/sostenuto_sw,F : { }", + "/region3/sostenuto_sw,T : { }", }; REQUIRE(messageList == expected); } @@ -2391,12 +2388,11 @@ TEST_CASE("[Values] Sustain CC") )"); synth.dispatchMessage(client, 0, "/region0/sustain_cc", "", nullptr); synth.dispatchMessage(client, 0, "/region1/sustain_cc", "", nullptr); - // TODO: activate for the new region parser ; ignore oob - // synth.dispatchMessage(client, 0, "/region2/sustain_cc", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/sustain_cc", "", nullptr); std::vector expected { "/region0/sustain_cc,i : { 64 }", "/region1/sustain_cc,i : { 10 }", - // "/region2/sustain_cc,i : { 20 }", + "/region2/sustain_cc,i : { 64 }", }; REQUIRE(messageList == expected); } @@ -2415,12 +2411,11 @@ TEST_CASE("[Values] Sustain low") )"); synth.dispatchMessage(client, 0, "/region0/sustain_lo", "", nullptr); synth.dispatchMessage(client, 0, "/region1/sustain_lo", "", nullptr); - // TODO: activate for the new region parser ; ignore oob - // synth.dispatchMessage(client, 0, "/region2/sustain_lo", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/sustain_lo", "", nullptr); std::vector expected { - "/region0/sustain_lo,f : { 0.0039 }", + "/region0/sustain_lo,f : { 0.00787402 }", "/region1/sustain_lo,f : { 0.0787402 }", - // "/region2/sustain_lo,f : { 0.0787402 }", + "/region2/sustain_lo,f : { 0.00787402 }", }; REQUIRE(messageList == expected); } @@ -2469,7 +2464,7 @@ TEST_CASE("[Values] Oscillator quality") std::vector expected { "/region0/oscillator_quality,N : { }", "/region1/oscillator_quality,i : { 2 }", - "/region2/oscillator_quality,i : { 0 }", + "/region2/oscillator_quality,N : { }", }; REQUIRE(messageList == expected); } @@ -2497,7 +2492,7 @@ TEST_CASE("[Values] Oscillator mode/multi") std::vector expected { "/region0/oscillator_mode,i : { 0 }", "/region1/oscillator_mode,i : { 2 }", - "/region2/oscillator_mode,i : { 1 }", + "/region2/oscillator_mode,i : { 0 }", "/region0/oscillator_multi,i : { 1 }", "/region3/oscillator_multi,i : { 9 }", "/region4/oscillator_multi,i : { 1 }", @@ -2553,14 +2548,13 @@ TEST_CASE("[Values] Effect sends") synth.dispatchMessage(client, 0, "/region1/effect1", "", nullptr); synth.dispatchMessage(client, 0, "/region2/effect1", "", nullptr); synth.dispatchMessage(client, 0, "/region2/effect2", "", nullptr); - // TODO: activate for the new region parser ; ignore oob - // synth.dispatchMessage(client, 0, "/region4/effect1", "", nullptr); + synth.dispatchMessage(client, 0, "/region4/effect1", "", nullptr); std::vector expected { // No reply to the first question "/region1/effect1,f : { 10 }", "/region2/effect1,f : { 0 }", "/region2/effect2,f : { 50.4 }", - // "/region4/effect1,f : { 100 }", + // No reply to the last question }; REQUIRE(messageList == expected); } @@ -2578,8 +2572,6 @@ TEST_CASE("[Values] Support floating point for int values") )"); synth.dispatchMessage(client, 0, "/region0/offset", "", nullptr); synth.dispatchMessage(client, 0, "/region1/pitch_keytrack", "", nullptr); - // TODO: activate for the new region parser ; ignore oob - // synth.dispatchMessage(client, 0, "/region4/effect1", "", nullptr); std::vector expected { "/region0/offset,h : { 1042 }", "/region1/pitch_keytrack,i : { -2 }", @@ -2899,15 +2891,14 @@ TEST_CASE("[Values] Filter value bounds") SECTION("Cutoff") { synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( - sample=kick.wav cutoff=20000000 // Bound this to 20k + sample=kick.wav cutoff=20000000 // Ignore the value sample=kick.wav cutoff=50 cutoff=-100 )"); synth.dispatchMessage(client, 0, "/region0/filter0/cutoff", "", nullptr); - // TODO: activate after new parser; ignore OOB - // synth.dispatchMessage(client, 0, "/region0/filter0/cutoff", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/filter0/cutoff", "", nullptr); std::vector expected { - "/region0/filter0/cutoff,f : { 20000 }", - // "/region0/filter0/cutoff,f : { 50 }", + "/region0/filter0/cutoff,f : { 0 }", + "/region1/filter0/cutoff,f : { 0 }", }; REQUIRE(messageList == expected); } @@ -2917,10 +2908,9 @@ TEST_CASE("[Values] Filter value bounds") synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( sample=kick.wav resonance=5 resonance=-5 )"); - // TODO: activate after new parser; ignore OOB - // synth.dispatchMessage(client, 0, "/region0/filter0/resonance", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/filter0/resonance", "", nullptr); std::vector expected { - // "/region0/filter0/resonance,f : { 5 }", + "/region0/filter0/resonance,f : { 0 }", }; REQUIRE(messageList == expected); } @@ -2928,19 +2918,17 @@ TEST_CASE("[Values] Filter value bounds") SECTION("Keycenter") { synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( - sample=kick.wav keycenter=40 keycenter=-5 - sample=kick.wav keycenter=40 keycenter=1000 - sample=kick.wav keycenter=c3 + sample=kick.wav fil_keycenter=40 + sample=kick.wav fil_keycenter=40 fil_keycenter=1000 + sample=kick.wav fil_keycenter=c3 )"); - // TODO: activate after new parser; ignore OOB - // synth.dispatchMessage(client, 0, "/region0/filter0/keycenter", "", nullptr); - // synth.dispatchMessage(client, 0, "/region1/filter0/keycenter", "", nullptr); - // TODO: activate after new parser; parse note - // synth.dispatchMessage(client, 0, "/region2/filter0/keycenter", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/filter0/keycenter", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/filter0/keycenter", "", nullptr); + synth.dispatchMessage(client, 0, "/region2/filter0/keycenter", "", nullptr); std::vector expected { - // "/region0/filter0/keycenter,i : { 40 }", - // "/region1/filter0/keycenter,i : { 40 }", - // "/region2/filter0/keycenter,i : { 48 }", + "/region0/filter0/keycenter,i : { 40 }", + "/region1/filter0/keycenter,i : { 60 }", + "/region2/filter0/keycenter,i : { 48 }", }; REQUIRE(messageList == expected); } @@ -3109,15 +3097,14 @@ TEST_CASE("[Values] EQ value bounds") SECTION("Frequency") { synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( - sample=kick.wav eq1_freq=20000000 // Bound this to 30k + sample=kick.wav eq1_freq=20000000 // Ignore sample=kick.wav eq1_freq=50 eq1_freq=-100 )"); synth.dispatchMessage(client, 0, "/region0/eq0/frequency", "", nullptr); - // TODO: activate after new parser; ignore OOB - // synth.dispatchMessage(client, 0, "/region0/eq0/frequency", "", nullptr); + synth.dispatchMessage(client, 0, "/region1/eq0/frequency", "", nullptr); std::vector expected { - "/region0/eq0/frequency,f : { 30000 }", - // "/region0/eq0/frequency,f : { 50 }", + "/region0/eq0/frequency,f : { 50 }", + "/region1/eq0/frequency,f : { 50 }", }; REQUIRE(messageList == expected); } @@ -3127,10 +3114,9 @@ TEST_CASE("[Values] EQ value bounds") synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( sample=kick.wav eq1_bw=5 eq1_bw=-5 )"); - // TODO: activate after new parser; ignore OOB - // synth.dispatchMessage(client, 0, "/region0/eq0/bandwidth", "", nullptr); + synth.dispatchMessage(client, 0, "/region0/eq0/bandwidth", "", nullptr); std::vector expected { - // "/region0/eq0/bandwidth,f : { 5 }", + "/region0/eq0/bandwidth,f : { 1 }", }; REQUIRE(messageList == expected); } From f62b1ba834d3dc1ea6e2a6c09165b7f95533b72f Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Thu, 4 Feb 2021 00:22:42 +0100 Subject: [PATCH 11/15] C++11 error --- src/sfizz/Defaults.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 65e7215f..2db5216c 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -77,7 +77,7 @@ struct OpcodeSpec template typename std::enable_if::value, U>::type normalizeInput(U input) const { - constexpr auto needsOperation { + constexpr int needsOperation { kNormalizePercent | kNormalizeMidi | kNormalizeBend | From 16e32f0bd1be0db7dc9090e901f0aaeac843b6a0 Mon Sep 17 00:00:00 2001 From: Paul Fd Date: Thu, 4 Feb 2021 01:08:07 +0100 Subject: [PATCH 12/15] Release test errors --- src/sfizz/Region.cpp | 2 ++ tests/RegionActivationT.cpp | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index d2710e0e..1355fc67 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -1546,9 +1546,11 @@ bool sfz::Region::registerNoteOff(int noteNumber, float velocity, float randValu return false; } + #include bool sfz::Region::registerCC(int ccNumber, float ccValue) noexcept { ASSERT(ccValue >= 0.0f && ccValue <= 1.0f); + if (ccConditions.getWithDefault(ccNumber).containsWithEnd(ccValue)) ccSwitched.set(ccNumber, true); else diff --git a/tests/RegionActivationT.cpp b/tests/RegionActivationT.cpp index 22723ff9..89a4254a 100644 --- a/tests/RegionActivationT.cpp +++ b/tests/RegionActivationT.cpp @@ -56,8 +56,8 @@ TEST_CASE("Region activation", "Region tests") REQUIRE(!region.isSwitchedOn()); region.registerCC(54, 19_norm); REQUIRE(region.isSwitchedOn()); - region.registerCC(54, 18_norm); - REQUIRE(region.isSwitchedOn()); + region.registerCC(54, 17_norm); + REQUIRE(!region.isSwitchedOn()); region.registerCC(54, 27_norm); REQUIRE(region.isSwitchedOn()); region.registerCC(4, 56_norm); From 2fd8c892cf4cd5a3ad219d77bfda45ba5817bf2b Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Thu, 4 Feb 2021 11:02:09 +0100 Subject: [PATCH 13/15] Last test errors --- tests/FilesT.cpp | 23 ++++++++++++----------- tests/TestHelpers.h | 9 +++++++++ 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/tests/FilesT.cpp b/tests/FilesT.cpp index 0c25cfc9..07d12c03 100644 --- a/tests/FilesT.cpp +++ b/tests/FilesT.cpp @@ -147,11 +147,12 @@ TEST_CASE("[Files] Group from AVL") REQUIRE(synth.getRegionView(i)->volume == 6.0f); REQUIRE(synth.getRegionView(i)->keyRange == Range(36, 36)); } - 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)); + + almostEqualRanges(synth.getRegionView(0)->velocityRange, { 1_norm, 26_norm }); + almostEqualRanges(synth.getRegionView(1)->velocityRange, { 27_norm, 52_norm }); + almostEqualRanges(synth.getRegionView(2)->velocityRange, { 53_norm, 77_norm }); + almostEqualRanges(synth.getRegionView(3)->velocityRange, { 78_norm, 102_norm }); + almostEqualRanges(synth.getRegionView(4)->velocityRange, { 103_norm, 127_norm }); } TEST_CASE("[Files] Full hierarchy") @@ -242,14 +243,14 @@ TEST_CASE("[Files] Pizz basic") REQUIRE(synth.getNumRegions() == 4); for (int i = 0; i < synth.getNumRegions(); ++i) { REQUIRE(synth.getRegionView(i)->keyRange == Range(12, 22)); - REQUIRE(synth.getRegionView(i)->velocityRange == Range(97_norm, 127_norm)); + almostEqualRanges(synth.getRegionView(i)->velocityRange, { 97_norm, 127_norm }); REQUIRE(synth.getRegionView(i)->pitchKeycenter == 21); - REQUIRE(synth.getRegionView(i)->ccConditions.getWithDefault(107) == Range(0_norm, 13_norm)); + almostEqualRanges(synth.getRegionView(i)->ccConditions.getWithDefault(107), { 0_norm, 13_norm }); } - 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)); + almostEqualRanges(synth.getRegionView(0)->randRange, { 0, 0.25 }); + almostEqualRanges(synth.getRegionView(1)->randRange, { 0.25, 0.5 }); + almostEqualRanges(synth.getRegionView(2)->randRange, { 0.5, 0.75 }); + almostEqualRanges(synth.getRegionView(3)->randRange, { 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)"); diff --git a/tests/TestHelpers.h b/tests/TestHelpers.h index 31c5feb5..6a5fda7e 100644 --- a/tests/TestHelpers.h +++ b/tests/TestHelpers.h @@ -5,9 +5,11 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once +#include "catch2/catch.hpp" #include "sfizz/Synth.h" #include "sfizz/Region.h" #include "sfizz/Voice.h" +#include "sfizz/Range.h" #include "sfizz/modulations/ModKey.h" class RegionCCView { @@ -30,6 +32,13 @@ private: sfz::ModKey target_; }; +template +void almostEqualRanges(const sfz::Range& lhs, const sfz::Range& rhs) +{ + REQUIRE(lhs.getStart() == Approx(rhs.getStart())); + REQUIRE(lhs.getEnd() == Approx(rhs.getEnd())); +} + template void sortAll(C& container) { From dc6805498116236b77328e06969b1b6ad8eb64a5 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Thu, 4 Feb 2021 11:52:20 +0100 Subject: [PATCH 14/15] Cleanups --- src/sfizz/Defaults.cpp | 7 ++++--- src/sfizz/Defaults.h | 16 ++++++++++++++++ src/sfizz/Opcode.cpp | 30 ++++++++++++++++++++++-------- src/sfizz/Region.cpp | 17 +---------------- tests/RegionValuesT.cpp | 8 ++++---- tests/TestHelpers.h | 2 +- 6 files changed, 48 insertions(+), 32 deletions(-) diff --git a/src/sfizz/Defaults.cpp b/src/sfizz/Defaults.cpp index e56171cb..8ac6d3af 100644 --- a/src/sfizz/Defaults.cpp +++ b/src/sfizz/Defaults.cpp @@ -73,7 +73,7 @@ extern const OpcodeSpec ampVelcurve { 0.0f, Range(0.0f, 1.0f), 0 } extern const OpcodeSpec ampRandom { 0.0f, Range(0.0f, 24.0f), 0 }; extern const OpcodeSpec rtDead { false, Range(0, 1), 0 }; extern const OpcodeSpec rtDecay { 0.0f, Range(0.0f, 200.0f), 0 }; -extern const OpcodeSpec filterCutoff { 0.0f, Range(0.0f, 20000.0f), 0 }; +extern const OpcodeSpec filterCutoff { 0.0f, Range(0.0f, 20000.0f), kEnforceUpperBound }; extern const OpcodeSpec filterCutoffMod { 0.0f, Range(-12000.0f, 12000.0f), 0 }; extern const OpcodeSpec filterResonance { 0.0f, Range(0.0f, 96.0f), 0 }; extern const OpcodeSpec filterResonanceMod { 0.0f, Range(0.0f, 96.0f), 0 }; @@ -84,8 +84,8 @@ extern const OpcodeSpec filterKeytrack { 0, Range(0, 1200), 0 }; extern const OpcodeSpec filterVeltrack { 0, Range(-12000, 12000), 0 }; extern const OpcodeSpec eqBandwidth { 1.0f, Range(0.001f, 4.0f), 0 }; extern const OpcodeSpec eqBandwidthMod { 0.0f, Range(-4.0f, 4.0f), 0 }; -extern const OpcodeSpec eqFrequency { 0.0f, Range(0.0f, 30000.0f), 0 }; -extern const OpcodeSpec eqFrequencyMod { 0.0f, Range(-30000.0f, 30000.0f), 0 }; +extern const OpcodeSpec eqFrequency { 0.0f, Range(0.0f, 20000.0f), kEnforceUpperBound }; +extern const OpcodeSpec eqFrequencyMod { 0.0f, Range(-20000.0f, 20000.0f), 0 }; extern const OpcodeSpec eqGain { 0.0f, Range(-96.0f, 96.0f), 0 }; extern const OpcodeSpec eqGainMod { 0.0f, Range(-96.0f, 96.0f), 0 }; extern const OpcodeSpec eqVel2Frequency { 0.0f, Range(-30000.0f, 30000.0f), 0 }; @@ -159,6 +159,7 @@ extern const OpcodeSpec stringsNumber { maxStrings, Range(0, extern const OpcodeSpec trigger { Trigger::attack, Range(Trigger::attack, Trigger::release_key), 0}; extern const OpcodeSpec crossfadeCurve { CrossfadeCurve::power, Range(CrossfadeCurve::gain, CrossfadeCurve::power), 0}; extern const OpcodeSpec offMode { OffMode::fast, Range(OffMode::fast, OffMode::time), 0}; +extern const OpcodeSpec loopMode { LoopMode::no_loop, Range(LoopMode::no_loop, LoopMode::loop_sustain), 0}; extern const OpcodeSpec velocityOverride { VelocityOverride::current, Range(VelocityOverride::current, VelocityOverride::previous), 0}; extern const OpcodeSpec selfMask { SelfMask::mask, Range(SelfMask::mask, SelfMask::dontMask), 0}; extern const OpcodeSpec filter { FilterType::kFilterNone, Range(FilterType::kFilterNone, FilterType::kFilterPeq), 0}; diff --git a/src/sfizz/Defaults.h b/src/sfizz/Defaults.h index 2db5216c..557ae19f 100644 --- a/src/sfizz/Defaults.h +++ b/src/sfizz/Defaults.h @@ -74,6 +74,14 @@ struct OpcodeSpec T defaultInputValue; Range bounds; int flags; + + /** + * @brief Normalizes an input as needed for the spec + * + * @tparam U + * @param input + * @return U + */ template typename std::enable_if::value, U>::type normalizeInput(U input) const { @@ -98,6 +106,13 @@ struct OpcodeSpec return input; } + /** + * @brief Normalizes an input as needed for the spec + * + * @tparam U + * @param input + * @return U + */ template typename std::enable_if::value, U>::type normalizeInput(U input) const { @@ -262,6 +277,7 @@ namespace Default extern const OpcodeSpec stringsNumber; extern const OpcodeSpec trigger; extern const OpcodeSpec offMode; + extern const OpcodeSpec loopMode; extern const OpcodeSpec crossfadeCurve; extern const OpcodeSpec velocityOverride; extern const OpcodeSpec selfMask; diff --git a/src/sfizz/Opcode.cpp b/src/sfizz/Opcode.cpp index 201709de..1628f292 100644 --- a/src/sfizz/Opcode.cpp +++ b/src/sfizz/Opcode.cpp @@ -197,12 +197,12 @@ absl::optional readFloat_(OpcodeSpec spec, absl::string_view v) if (spec.flags & kEnforceUpperBound) return spec.bounds.getEnd(); - return {}; + return absl::nullopt; } else if (returnedValue < static_cast(spec.bounds.getStart())) { if (spec.flags & kEnforceLowerBound) return spec.bounds.getStart(); - return {}; + return absl::nullopt; } return spec.normalizeInput(returnedValue); @@ -223,7 +223,7 @@ absl::optional readNoteValue(absl::string_view value) char noteLetter = absl::ascii_tolower(value.empty() ? '\0' : value.front()); value.remove_prefix(1); if (noteLetter < 'a' || noteLetter > 'g') - return {}; + return absl::nullopt; constexpr int offsetsABCDEFG[] = { 9, 11, 0, 2, 4, 5, 7 }; int noteNumber = offsetsABCDEFG[noteLetter - 'a']; @@ -244,11 +244,11 @@ absl::optional readNoteValue(absl::string_view value) if (absl::StartsWith(value, prefix.first)) { if (prefix.second == +1) { if (validSharpLetters.find(noteLetter) == absl::string_view::npos) - return {}; + return absl::nullopt; } else if (prefix.second == -1) { if (validFlatLetters.find(noteLetter) == absl::string_view::npos) - return {}; + return absl::nullopt; } noteNumber += prefix.second; value.remove_prefix(prefix.first.size()); @@ -258,12 +258,12 @@ absl::optional readNoteValue(absl::string_view value) int octaveNumber; if (!absl::SimpleAtoi(value, &octaveNumber)) - return {}; + return absl::nullopt; noteNumber += (octaveNumber + 1) * 12; if (noteNumber < 0 || noteNumber >= 128) - return {}; + return absl::nullopt; return static_cast(noteNumber); } @@ -293,7 +293,7 @@ absl::optional Opcode::readOptional(OpcodeSpec Opcode::readOptional(OpcodeSpec) const return absl::nullopt; } +template <> +absl::optional Opcode::readOptional(OpcodeSpec) const +{ + switch (hash(value)) { + case hash("no_loop"): return LoopMode::no_loop; + case hash("one_shot"): return LoopMode::one_shot; + case hash("loop_continuous"): return LoopMode::loop_continuous; + case hash("loop_sustain"): return LoopMode::loop_sustain; + } + + DBG("Unknown loop mode: " << value); + return absl::nullopt; +} + template <> absl::optional Opcode::readOptional(OpcodeSpec) const { diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 1355fc67..72324fdb 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -119,22 +119,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) sampleCount = opcode.read(Default::sampleCount); break; case hash("loop_mode"): // also loopmode - switch (hash(opcode.value)) { - case hash("no_loop"): - loopMode = LoopMode::no_loop; - break; - case hash("one_shot"): - loopMode = LoopMode::one_shot; - break; - case hash("loop_continuous"): - loopMode = LoopMode::loop_continuous; - break; - case hash("loop_sustain"): - loopMode = LoopMode::loop_sustain; - break; - default: - DBG("Unkown loop mode:" << opcode.value); - } + loopMode = opcode.readOptional(Default::loopMode); break; case hash("loop_end"): // also loopend loopRange.setEnd(opcode.read(Default::loopEnd)); diff --git a/tests/RegionValuesT.cpp b/tests/RegionValuesT.cpp index c34b6787..dc88297c 100644 --- a/tests/RegionValuesT.cpp +++ b/tests/RegionValuesT.cpp @@ -2891,13 +2891,13 @@ TEST_CASE("[Values] Filter value bounds") SECTION("Cutoff") { synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( - sample=kick.wav cutoff=20000000 // Ignore the value + sample=kick.wav cutoff=20000000 // Clamp the value sample=kick.wav cutoff=50 cutoff=-100 )"); synth.dispatchMessage(client, 0, "/region0/filter0/cutoff", "", nullptr); synth.dispatchMessage(client, 0, "/region1/filter0/cutoff", "", nullptr); std::vector expected { - "/region0/filter0/cutoff,f : { 0 }", + "/region0/filter0/cutoff,f : { 20000 }", "/region1/filter0/cutoff,f : { 0 }", }; REQUIRE(messageList == expected); @@ -3097,13 +3097,13 @@ TEST_CASE("[Values] EQ value bounds") SECTION("Frequency") { synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"( - sample=kick.wav eq1_freq=20000000 // Ignore + sample=kick.wav eq1_freq=20000000 // Clamp the value sample=kick.wav eq1_freq=50 eq1_freq=-100 )"); synth.dispatchMessage(client, 0, "/region0/eq0/frequency", "", nullptr); synth.dispatchMessage(client, 0, "/region1/eq0/frequency", "", nullptr); std::vector expected { - "/region0/eq0/frequency,f : { 50 }", + "/region0/eq0/frequency,f : { 20000 }", "/region1/eq0/frequency,f : { 50 }", }; REQUIRE(messageList == expected); diff --git a/tests/TestHelpers.h b/tests/TestHelpers.h index 6a5fda7e..0c60fb91 100644 --- a/tests/TestHelpers.h +++ b/tests/TestHelpers.h @@ -5,11 +5,11 @@ // If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz #pragma once -#include "catch2/catch.hpp" #include "sfizz/Synth.h" #include "sfizz/Region.h" #include "sfizz/Voice.h" #include "sfizz/Range.h" +#include "catch2/catch.hpp" #include "sfizz/modulations/ModKey.h" class RegionCCView { From acb860e984ccdfeb054b8af7d39e3433f4e4b664 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Thu, 4 Feb 2021 21:40:21 +0100 Subject: [PATCH 15/15] Cleanups --- src/sfizz/Region.cpp | 16 ++-------------- src/sfizz/Region.h | 2 +- tests/RegionValuesT.cpp | 2 +- 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 72324fdb..3d3008bf 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -170,10 +170,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) group = opcode.read(Default::group); break; case hash("off_by"): // also offby - if (opcode.value == "-1") - offBy.reset(); - else - offBy = opcode.read(Default::group); + offBy = opcode.readOptional(Default::group); break; case hash("off_mode"): // also offmode offMode = opcode.read(Default::offMode); @@ -189,16 +186,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) notePolyphony = opcode.read(Default::notePolyphony); break; case hash("note_selfmask"): - switch (hash(opcode.value)) { - case hash("on"): - selfMask = SelfMask::mask; - break; - case hash("off"): - selfMask = SelfMask::dontMask; - break; - default: - DBG("Unkown self mask value:" << opcode.value); - } + selfMask = opcode.read(Default::selfMask); break; case hash("rt_dead"): rtDead = opcode.read(Default::rtDead); diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index 4b3ee6c2..d8d6368e 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -474,7 +474,7 @@ struct Region { bool bpmSwitched { true }; bool aftertouchSwitched { true }; std::bitset ccSwitched; - absl::string_view defaultPath { "" }; + std::string defaultPath { "" }; int sequenceCounter { 0 }; LEAK_DETECTOR(Region); diff --git a/tests/RegionValuesT.cpp b/tests/RegionValuesT.cpp index dc88297c..197fe80a 100644 --- a/tests/RegionValuesT.cpp +++ b/tests/RegionValuesT.cpp @@ -2291,7 +2291,7 @@ TEST_CASE("[Values] Self-mask") "/region0/note_selfmask,T : { }", "/region1/note_selfmask,F : { }", "/region2/note_selfmask,T : { }", - "/region3/note_selfmask,F : { }", + "/region3/note_selfmask,T : { }", }; REQUIRE(messageList == expected); }