Change the way the defaults and bounds for the opcodes are handled and read
This commit is contained in:
parent
02c5de1237
commit
b1f7a4bd66
51 changed files with 1623 additions and 1135 deletions
72
benchmarks/BM_opcodeSpec.cpp
Normal file
72
benchmarks/BM_opcodeSpec.cpp
Normal file
|
|
@ -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 <benchmark/benchmark.h>
|
||||
#include <random>
|
||||
#include <numeric>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
|
||||
class OpcodeSpecFixture : public benchmark::Fixture {
|
||||
public:
|
||||
void SetUp(const ::benchmark::State& state) {
|
||||
std::random_device rd { };
|
||||
std::mt19937 gen { rd() };
|
||||
std::uniform_real_distribution<float> 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();
|
||||
14
benchmarks/BM_opcodeSpec.h
Normal file
14
benchmarks/BM_opcodeSpec.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include "Range.h"
|
||||
|
||||
template<class T>
|
||||
struct OpcodeSpec
|
||||
{
|
||||
T defaultValue;
|
||||
sfz::Range<T> bounds;
|
||||
int flags { 0 };
|
||||
};
|
||||
|
||||
constexpr OpcodeSpec<float> constexprSpec { 0.0f, sfz::Range<float>(0.0f, 0.5f), 1 << 2 };
|
||||
extern const OpcodeSpec<float> constSpec;
|
||||
3
benchmarks/BM_opcodeSpec_def.cpp
Normal file
3
benchmarks/BM_opcodeSpec_def.cpp
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
#include "BM_opcodeSpec.h"
|
||||
|
||||
const OpcodeSpec<float> constSpec { 0.0f, sfz::Range<float>(0.0f, 0.5f), 1 << 2 };
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ Curve Curve::buildCurveFromHeader(
|
|||
{
|
||||
Curve curve;
|
||||
bool fillStatus[NumValues] = {};
|
||||
const Range<float> fullRange { -HUGE_VALF, +HUGE_VALF };
|
||||
const OpcodeSpec<float> fullRange {0.0f, Range<float>(-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<float>(opc.value, fullRange);
|
||||
auto valueOpt = opc.read(fullRange);
|
||||
if (!valueOpt)
|
||||
continue;
|
||||
|
||||
|
|
@ -268,7 +268,7 @@ void CurveSet::addCurveFromHeader(absl::Span<const Opcode> members)
|
|||
Curve::Interpolator itp = Curve::Interpolator::Linear;
|
||||
|
||||
if (const Opcode* opc = findOpcode(hash("curve_index"))) {
|
||||
if (auto opt = readOpcode<int>(opc->value, {0, 255}))
|
||||
if (auto opt = opc->read(Default::curveCC))
|
||||
curveIndex = *opt;
|
||||
else
|
||||
DBG("Invalid value for curve index: " << opc->value);
|
||||
|
|
|
|||
143
src/sfizz/Defaults.cpp
Normal file
143
src/sfizz/Defaults.cpp
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
#include "Defaults.h"
|
||||
|
||||
namespace sfz {
|
||||
|
||||
namespace Default {
|
||||
constexpr auto uint32_t_max = std::numeric_limits<uint32_t>::max();
|
||||
|
||||
extern const OpcodeSpec<float> delay { 0.0f, Range<float>(0.0f, 100.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<float> delayRandom { 0.0f, Range<float>(0.0f, 100.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<int64_t> offset { 0, Range<int64_t>(0, uint32_t_max), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<int64_t> offsetMod { 0, Range<int64_t>(0, uint32_t_max), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<int64_t> offsetRandom { 0, Range<int64_t>(0, uint32_t_max), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<uint32_t> sampleEnd { uint32_t_max, Range<uint32_t>(0, uint32_t_max), kEnforceLowerBound | kEnforceUpperBound };
|
||||
extern const OpcodeSpec<uint32_t> sampleCount { 0, Range<uint32_t>(0, uint32_t_max), 0 };
|
||||
extern const OpcodeSpec<uint32_t> loopRange { 0, Range<uint32_t>(0, uint32_t_max), 0 };
|
||||
extern const OpcodeSpec<float> loopCrossfade { 1e-3, Range<float>(1e-3, 1.0f), kEnforceLowerBound | kEnforceUpperBound };
|
||||
extern const OpcodeSpec<float> oscillatorPhase { 0.0f, Range<float>(0.0f, 1.0f), 0 };
|
||||
extern const OpcodeSpec<int> oscillatorMode { 0, Range<int>(0, 2), kIgnoreOOB };
|
||||
extern const OpcodeSpec<int> oscillatorMulti { 1, Range<int>(1, config::oscillatorsPerVoice), kIgnoreOOB };
|
||||
extern const OpcodeSpec<float> oscillatorDetune { 0.0f, Range<float>(-12000.0f, 12000.0f), 0 };
|
||||
extern const OpcodeSpec<float> oscillatorDetuneMod { 0.0f, Range<float>(-12000.0f, 12000.0f), 0 };
|
||||
extern const OpcodeSpec<float> oscillatorModDepth { 0.0f, Range<float>(0.0f, 10000.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<float> oscillatorModDepthMod { 0.0f, Range<float>(0.0f, 10000.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<int> oscillatorQuality { 1, Range<int>(0, 3), kIgnoreOOB };
|
||||
extern const OpcodeSpec<uint32_t> group { 0, Range<uint32_t>(0, uint32_t_max), 0 };
|
||||
extern const OpcodeSpec<float> offTime { 6e-3f, Range<float>(0.0f, 100.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<uint32_t> polyphony { config::maxVoices, Range<uint32_t>(0, config::maxVoices), 0 };
|
||||
extern const OpcodeSpec<uint32_t> notePolyphony { config::maxVoices, Range<uint32_t>(0, config::maxVoices), 0 };
|
||||
extern const OpcodeSpec<uint8_t> key { 60, Range<uint8_t>(0, 127), kIgnoreOOB | kCanBeNote };
|
||||
extern const OpcodeSpec<uint8_t> midi7 { 0, Range<uint8_t>(0, 127), kIgnoreOOB };
|
||||
extern const OpcodeSpec<float> float7 { 0.0f , Range<float>(0.0f, 127.0f), kIgnoreOOB };
|
||||
extern const OpcodeSpec<float> bend { 0.0f, Range<float>(-8192.0f, 8192.0f), kIgnoreOOB };
|
||||
extern const OpcodeSpec<float> normalized { 0.0f, Range<float>(0.0f, 1.0f), kIgnoreOOB };
|
||||
extern const OpcodeSpec<float> bipolar { 0.0f, Range<float>(-1.0f, 1.0f), kIgnoreOOB };
|
||||
extern const OpcodeSpec<uint16_t> ccNumber { 0, Range<uint16_t>(0, config::numCCs), kIgnoreOOB };
|
||||
extern const OpcodeSpec<uint8_t> smoothCC { 0, Range<uint8_t>(0, 100), kIgnoreOOB };
|
||||
extern const OpcodeSpec<uint8_t> curveCC { 0, Range<uint8_t>(0, 255), kIgnoreOOB };
|
||||
extern const OpcodeSpec<uint8_t> sustainCC { 64, Range<uint8_t>(0, 127), kIgnoreOOB };
|
||||
extern const OpcodeSpec<float> sustainThreshold { 0.0039f, Range<float>(0.0f, 1.0f), kIgnoreOOB };
|
||||
extern const OpcodeSpec<float> bpm { 0.0f, Range<float>(0.0f, 500.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<uint8_t> sequence { 1, Range<uint8_t>(1, 100), kIgnoreOOB };
|
||||
extern const OpcodeSpec<float> volume { 0.0f, Range<float>(-144.0f, 48.0f), 0 };
|
||||
extern const OpcodeSpec<float> volumeMod { 0.0f, Range<float>(-144.0f, 48.0f), 0 };
|
||||
extern const OpcodeSpec<float> amplitude { 100.0f, Range<float>(0.0f, 100.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<float> amplitudeMod { 0.0f, Range<float>(0.0f, 100.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<float> pan { 0.0f, Range<float>(-100.0f, 100.0f), 0 };
|
||||
extern const OpcodeSpec<float> panMod { 0.0f, Range<float>(-200.0f, 200.0f), 0 };
|
||||
extern const OpcodeSpec<float> position { 0.0f, Range<float>(-100.0f, 100.0f), 0 };
|
||||
extern const OpcodeSpec<float> positionMod { 0.0f, Range<float>(-200.0f, 200.0f), 0 };
|
||||
extern const OpcodeSpec<float> width { 100.0f, Range<float>(-100.0f, 100.0f), 0 };
|
||||
extern const OpcodeSpec<float> widthMod { 0.0f, Range<float>(-200.0f, 200.0f), 0 };
|
||||
extern const OpcodeSpec<uint8_t> crossfadeIn { 0, Range<uint8_t>(0, 127), kEnforceLowerBound | kEnforceUpperBound };
|
||||
extern const OpcodeSpec<float> crossfadeInNorm { 0.0f, Range<float>(0.0f, 1.0f), kEnforceLowerBound | kEnforceUpperBound };
|
||||
extern const OpcodeSpec<uint8_t> crossfadeOut { 127, Range<uint8_t>(0, 127), kEnforceLowerBound | kEnforceUpperBound };
|
||||
extern const OpcodeSpec<float> crossfadeOutNorm { 1.0f, Range<float>(0.0f, 1.0f), kEnforceLowerBound | kEnforceUpperBound };
|
||||
extern const OpcodeSpec<float> ampKeytrack { 0.0f, Range<float>(-96.0f, 12.0f), 0 };
|
||||
extern const OpcodeSpec<float> ampVeltrack { 100.0f, Range<float>(-100.0f, 100.0f), kIgnoreOOB };
|
||||
extern const OpcodeSpec<float> ampVelcurve { 0.0f, Range<float>(0.0f, 1.0f), kEnforceLowerBound | kEnforceUpperBound };
|
||||
extern const OpcodeSpec<float> ampRandom { 0.0f, Range<float>(0.0f, 24.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<float> rtDecay { 0.0f, Range<float>(0.0f, 200.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<float> filterCutoff { 0.0f, Range<float>(0.0f, 20000.0f), kEnforceLowerBound | kEnforceUpperBound };
|
||||
extern const OpcodeSpec<float> filterCutoffMod { 0.0f, Range<float>(-12000.0f, 12000.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<float> filterResonance { 0.0f, Range<float>(0.0f, 96.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<float> filterResonanceMod { 0.0f, Range<float>(0.0f, 96.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<float> filterGain { 0.0f, Range<float>(-96.0f, 96.0f), 0 };
|
||||
extern const OpcodeSpec<float> filterGainMod { 0.0f, Range<float>(-96.0f, 96.0f), 0 };
|
||||
extern const OpcodeSpec<float> filterRandom { 0.0f, Range<float>(0.0f, 12000.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<int> filterKeytrack { 0, Range<int>(0, 1200), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<int> filterVeltrack { 0, Range<int>(-12000, 12000), 0 };
|
||||
extern const OpcodeSpec<float> eqBandwidth { 1.0f, Range<float>(0.001f, 4.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<float> eqBandwidthMod { 0.0f, Range<float>(-4.0f, 4.0f), 0 };
|
||||
extern const OpcodeSpec<float> eqFrequency { 0.0f, Range<float>(0.0f, 30000.0f), kEnforceLowerBound | kEnforceUpperBound };
|
||||
extern const OpcodeSpec<float> eqFrequencyMod { 0.0f, Range<float>(-30000.0f, 30000.0f), 0 };
|
||||
extern const OpcodeSpec<float> eqGain { 0.0f, Range<float>(-96.0f, 96.0f), 0 };
|
||||
extern const OpcodeSpec<float> eqGainMod { 0.0f, Range<float>(-96.0f, 96.0f), 0 };
|
||||
extern const OpcodeSpec<float> eqVel2Frequency { 0.0f, Range<float>(-30000.0f, 30000.0f), 0 };
|
||||
extern const OpcodeSpec<float> eqVel2Gain { 0.0f, Range<float>(-96.0f, 96.0f), 0 };
|
||||
extern const OpcodeSpec<int> pitchKeytrack { 100, Range<int>(-1200, 1200), 0 };
|
||||
extern const OpcodeSpec<float> pitchRandom { 0.0f, Range<float>(0.0f, 12000.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<int> pitchVeltrack { 0, Range<int>(-12000, 12000), 0 };
|
||||
extern const OpcodeSpec<int> transpose { 0, Range<int>(-127, 127), kIgnoreOOB };
|
||||
extern const OpcodeSpec<float> pitch { 0.0f, Range<float>(-100.0f, 100.0f), 0 };
|
||||
extern const OpcodeSpec<float> pitchMod { 0.0f, Range<float>(-100.0f, 100.0f), 0 };
|
||||
extern const OpcodeSpec<float> bendUp { 200.0f, Range<float>(-12000.0f, 12000.0f), 0 };
|
||||
extern const OpcodeSpec<float> bendDown { -200.0f, Range<float>(-12000.0f, 12000.0f), 0 };
|
||||
extern const OpcodeSpec<float> bendStep { 1.0f, Range<float>(1.0f, 1200.0f), kIgnoreOOB };
|
||||
extern const OpcodeSpec<float> lfoFreq { 0.0f, Range<float>(0.0f, 100.0f), 0 };
|
||||
extern const OpcodeSpec<float> lfoFreqMod { 0.0f, Range<float>(-100.0f, 100.0f), 0 };
|
||||
extern const OpcodeSpec<float> lfoBeats { 0.0f, Range<float>(0.0f, 1000.0f), 0 };
|
||||
extern const OpcodeSpec<float> lfoBeatsMod { 0.0f, Range<float>(-1000.0f, 1000.0f), 0 };
|
||||
extern const OpcodeSpec<float> lfoPhase { 0.0f, Range<float>(0.0f, 1.0f), 0 };
|
||||
extern const OpcodeSpec<float> lfoDelay { 0.0f, Range<float>(0.0f, 30.0f), 0 };
|
||||
extern const OpcodeSpec<float> lfoFade { 0.0f, Range<float>(0.0f, 30.0f), 0 };
|
||||
extern const OpcodeSpec<unsigned> lfoCount { 0, Range<unsigned>(0, 1000), 0 };
|
||||
extern const OpcodeSpec<unsigned> lfoSteps { 0, Range<unsigned>(0, static_cast<unsigned>(config::maxLFOSteps)), 0 };
|
||||
extern const OpcodeSpec<float> lfoStepX { 0.0f, Range<float>(-100.0f, 100.0f), 0 };
|
||||
extern const OpcodeSpec<int> lfoWave { 0, Range<int>(0, 15), 0 };
|
||||
extern const OpcodeSpec<float> lfoOffset { 0.0f, Range<float>(-1.0f, 1.0f), 0 };
|
||||
extern const OpcodeSpec<float> lfoRatio { 1.0f, Range<float>(0.0f, 100.0f), 0 };
|
||||
extern const OpcodeSpec<float> lfoScale { 1.0f, Range<float>(0.0f, 1.0f), 0 };
|
||||
extern const OpcodeSpec<float> egTime { 0.0f, Range<float>(0.0f, 100.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<float> egRelease { 0.001f, Range<float>(0.0f, 100.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<float> egTimeMod { 0.0f, Range<float>(-100.0f, 100.0f), 0 };
|
||||
extern const OpcodeSpec<float> egPercent { 0.0f, Range<float>(0.0f, 100.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<float> egPercentMod { 0.0f, Range<float>(-100.0f, 100.0f), 0 };
|
||||
extern const OpcodeSpec<float> egDepth { 0.0f, Range<float>(-12000.0f, 12000.0f), 0 };
|
||||
extern const OpcodeSpec<float> egVel2Depth { 0.0f, Range<float>(-12000.0f, 12000.0f), 0 };
|
||||
extern const OpcodeSpec<int> flexEGDynamic { 0, Range<int>(0, 1), kIgnoreOOB };
|
||||
extern const OpcodeSpec<int> flexEGSustain { 0, Range<int>(0, 100), kIgnoreOOB };
|
||||
extern const OpcodeSpec<float> flexEGPointTime { 0.0f, Range<float>(0.0f, 100.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<float> flexEGPointLevel { 0.0f, Range<float>(-1.0f, 1.0f), kIgnoreOOB };
|
||||
extern const OpcodeSpec<float> flexEGPointShape { 0.0f, Range<float>(-100.0f, 100.0f), kEnforceLowerBound | kEnforceUpperBound };
|
||||
extern const OpcodeSpec<int> sampleQuality { 1, Range<int>(1, 10), kIgnoreOOB };
|
||||
extern const OpcodeSpec<int> octaveOffset { 0, Range<int>(-10, 10), 0 };
|
||||
extern const OpcodeSpec<int> noteOffset { 0, Range<int>(-127, 127), 0 };
|
||||
extern const OpcodeSpec<float> effect { 0.0f, Range<float>(0.0f, 100.0f), 0 };
|
||||
extern const OpcodeSpec<int> apanWaveform { 0, Range<int>(0, std::numeric_limits<int>::max()), 0 };
|
||||
extern const OpcodeSpec<float> apanFrequency { 0.0f, Range<float>(0.0f, std::numeric_limits<float>::max()), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<float> apanPhase { 0.5f, Range<float>(0.0f, 1.0f), 0 };
|
||||
extern const OpcodeSpec<float> apanLevel { 0.0f, Range<float>(0.0f, 100.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<float> distoTone { 100.0f, Range<float>(0.0f, 100.0f), kEnforceLowerBound | kEnforceUpperBound };
|
||||
extern const OpcodeSpec<float> distoDepth { 0.0f, Range<float>(0.0f, 100.0f), kEnforceLowerBound | kEnforceUpperBound };
|
||||
extern const OpcodeSpec<unsigned> distoStages { 1, Range<unsigned>(1, maxDistoStages), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<float> compAttack { 0.005f, Range<float>(0.0f, 10.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<float> compRelease { 0.05f, Range<float>(0.0f, 10.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<float> compThreshold { 0.0f, Range<float>(-100.0f, 0.0f), kIgnoreOOB };
|
||||
extern const OpcodeSpec<float> compRatio { 1.0f, Range<float>(1.0f, 50.0f), kIgnoreOOB };
|
||||
extern const OpcodeSpec<float> compGain { 0.0f, Range<float>(-100.0f, 100.0f), 0 };
|
||||
extern const OpcodeSpec<float> fverbSize { 0.0f, Range<float>(0.0f, 100.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<float> fverbPredelay { 0.0f, Range<float>(0.0f, 10.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<float> fverbTone { 100.0f, Range<float>(0.0f, 100.0f), kIgnoreOOB };
|
||||
extern const OpcodeSpec<float> fverbDamp { 0.0f, Range<float>(0.0f, 100.0f), kIgnoreOOB };
|
||||
extern const OpcodeSpec<float> gateAttack { 0.005f, Range<float>(0.0f, 10.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<float> gateRelease { 0.05f, Range<float>(0.0f, 10.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<float> gateHold { 0.0f, Range<float>(0.0f, 10.0f), kEnforceLowerBound };
|
||||
extern const OpcodeSpec<float> gateThreshold { 0.0f, Range<float>(-100.0f, 0.0f), kIgnoreOOB };
|
||||
extern const OpcodeSpec<float> lofiBitred { 0.0f, Range<float>(0.0f, 100.0f), kIgnoreOOB };
|
||||
extern const OpcodeSpec<float> lofiDecim { 0.0f, Range<float>(0.0f, 100.0f), kIgnoreOOB };
|
||||
extern const OpcodeSpec<float> rectify { 0.0f, Range<float>(0.0f, 100.0f), kIgnoreOOB };
|
||||
extern const OpcodeSpec<unsigned> stringsNumber { maxStrings, Range<unsigned>(0, maxStrings), kEnforceLowerBound };
|
||||
} // namespace Default
|
||||
|
||||
} // namespace sfz
|
||||
|
|
@ -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<class T>
|
||||
struct OpcodeSpec
|
||||
{
|
||||
T value;
|
||||
Range<T> 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<float> delayRange { 0.0, 100.0 };
|
||||
constexpr int64_t offset { 0 };
|
||||
constexpr int64_t offsetRandom { 0 };
|
||||
constexpr Range<int64_t> offsetRange { 0, std::numeric_limits<uint32_t>::max() };
|
||||
constexpr Range<int64_t> offsetCCRange = offsetRange;
|
||||
constexpr Range<uint32_t> sampleEndRange { 0, std::numeric_limits<uint32_t>::max() };
|
||||
constexpr Range<uint32_t> sampleCountRange { 0, std::numeric_limits<uint32_t>::max() };
|
||||
constexpr SfzLoopMode loopMode { SfzLoopMode::no_loop };
|
||||
constexpr Range<uint32_t> loopRange { 0, std::numeric_limits<uint32_t>::max() };
|
||||
constexpr float loopCrossfade { 1e-3 };
|
||||
constexpr Range<float> loopCrossfadeRange { loopCrossfade, 1.0 };
|
||||
extern const OpcodeSpec<float> delay;
|
||||
extern const OpcodeSpec<float> delayRandom;
|
||||
extern const OpcodeSpec<int64_t> offset;
|
||||
extern const OpcodeSpec<int64_t> offsetMod;
|
||||
extern const OpcodeSpec<int64_t> offsetRandom;
|
||||
extern const OpcodeSpec<uint32_t> sampleEnd;
|
||||
extern const OpcodeSpec<uint32_t> sampleCount;
|
||||
extern const OpcodeSpec<uint32_t> loopRange;
|
||||
extern const OpcodeSpec<float> loopCrossfade;
|
||||
extern const OpcodeSpec<float> oscillatorPhase;
|
||||
extern const OpcodeSpec<int> oscillatorMode;
|
||||
extern const OpcodeSpec<int> oscillatorMulti;
|
||||
extern const OpcodeSpec<float> oscillatorDetune;
|
||||
extern const OpcodeSpec<float> oscillatorDetuneMod;
|
||||
extern const OpcodeSpec<float> oscillatorModDepth;
|
||||
extern const OpcodeSpec<float> oscillatorModDepthMod;
|
||||
extern const OpcodeSpec<int> oscillatorQuality;
|
||||
extern const OpcodeSpec<uint32_t> group;
|
||||
extern const OpcodeSpec<float> offTime;
|
||||
extern const OpcodeSpec<uint32_t> polyphony;
|
||||
extern const OpcodeSpec<uint32_t> notePolyphony;
|
||||
extern const OpcodeSpec<uint8_t> key;
|
||||
extern const OpcodeSpec<uint8_t> midi7;
|
||||
extern const OpcodeSpec<float> float7;
|
||||
extern const OpcodeSpec<float> bend;
|
||||
extern const OpcodeSpec<float> normalized;
|
||||
extern const OpcodeSpec<float> bipolar;
|
||||
extern const OpcodeSpec<uint16_t> ccNumber;
|
||||
extern const OpcodeSpec<uint8_t> curveCC;
|
||||
extern const OpcodeSpec<uint8_t> smoothCC;
|
||||
extern const OpcodeSpec<uint8_t> sustainCC;
|
||||
extern const OpcodeSpec<float> sustainThreshold;
|
||||
extern const OpcodeSpec<float> bpm;
|
||||
extern const OpcodeSpec<uint8_t> sequence;
|
||||
extern const OpcodeSpec<float> volume;
|
||||
extern const OpcodeSpec<float> volumeMod;
|
||||
extern const OpcodeSpec<float> amplitude;
|
||||
extern const OpcodeSpec<float> amplitudeMod;
|
||||
extern const OpcodeSpec<float> pan;
|
||||
extern const OpcodeSpec<float> panMod;
|
||||
extern const OpcodeSpec<float> position;
|
||||
extern const OpcodeSpec<float> positionMod;
|
||||
extern const OpcodeSpec<float> width;
|
||||
extern const OpcodeSpec<float> widthMod;
|
||||
extern const OpcodeSpec<uint8_t> crossfadeIn;
|
||||
extern const OpcodeSpec<float> crossfadeInNorm;
|
||||
extern const OpcodeSpec<uint8_t> crossfadeOut;
|
||||
extern const OpcodeSpec<float> crossfadeOutNorm;
|
||||
extern const OpcodeSpec<float> ampKeytrack;
|
||||
extern const OpcodeSpec<float> ampVeltrack;
|
||||
extern const OpcodeSpec<float> ampVelcurve;
|
||||
extern const OpcodeSpec<float> ampRandom;
|
||||
extern const OpcodeSpec<float> rtDecay;
|
||||
extern const OpcodeSpec<float> filterCutoff;
|
||||
extern const OpcodeSpec<float> filterCutoffMod;
|
||||
extern const OpcodeSpec<float> filterResonance;
|
||||
extern const OpcodeSpec<float> filterResonanceMod;
|
||||
extern const OpcodeSpec<float> filterGain;
|
||||
extern const OpcodeSpec<float> filterGainMod;
|
||||
extern const OpcodeSpec<float> filterRandom;
|
||||
extern const OpcodeSpec<int> filterKeytrack;
|
||||
extern const OpcodeSpec<int> filterVeltrack;
|
||||
extern const OpcodeSpec<float> eqBandwidth;
|
||||
extern const OpcodeSpec<float> eqBandwidthMod;
|
||||
extern const OpcodeSpec<float> eqFrequency;
|
||||
extern const OpcodeSpec<float> eqFrequencyMod;
|
||||
extern const OpcodeSpec<float> eqGain;
|
||||
extern const OpcodeSpec<float> eqGainMod;
|
||||
extern const OpcodeSpec<float> eqVel2Frequency;
|
||||
extern const OpcodeSpec<float> eqVel2Gain;
|
||||
extern const OpcodeSpec<int> pitchKeytrack;
|
||||
extern const OpcodeSpec<float> pitchRandom;
|
||||
extern const OpcodeSpec<int> pitchVeltrack;
|
||||
extern const OpcodeSpec<int> transpose;
|
||||
extern const OpcodeSpec<float> pitch;
|
||||
extern const OpcodeSpec<float> pitchMod;
|
||||
extern const OpcodeSpec<float> bendUp;
|
||||
extern const OpcodeSpec<float> bendDown;
|
||||
extern const OpcodeSpec<float> bendStep;
|
||||
extern const OpcodeSpec<float> lfoFreq;
|
||||
extern const OpcodeSpec<float> lfoFreqMod;
|
||||
extern const OpcodeSpec<float> lfoBeats;
|
||||
extern const OpcodeSpec<float> lfoBeatsMod;
|
||||
extern const OpcodeSpec<float> lfoPhase;
|
||||
extern const OpcodeSpec<float> lfoDelay;
|
||||
extern const OpcodeSpec<float> lfoFade;
|
||||
extern const OpcodeSpec<unsigned> lfoCount;
|
||||
extern const OpcodeSpec<unsigned> lfoSteps;
|
||||
extern const OpcodeSpec<float> lfoStepX;
|
||||
extern const OpcodeSpec<int> lfoWave;
|
||||
extern const OpcodeSpec<float> lfoOffset;
|
||||
extern const OpcodeSpec<float> lfoRatio;
|
||||
extern const OpcodeSpec<float> lfoScale;
|
||||
extern const OpcodeSpec<float> egTime;
|
||||
extern const OpcodeSpec<float> egRelease;
|
||||
extern const OpcodeSpec<float> egTimeMod;
|
||||
extern const OpcodeSpec<float> egPercent;
|
||||
extern const OpcodeSpec<float> egPercentMod;
|
||||
extern const OpcodeSpec<float> egDepth;
|
||||
extern const OpcodeSpec<float> egVel2Depth;
|
||||
extern const OpcodeSpec<int> flexEGDynamic;
|
||||
extern const OpcodeSpec<int> flexEGSustain;
|
||||
extern const OpcodeSpec<float> flexEGPointTime;
|
||||
extern const OpcodeSpec<float> flexEGPointLevel;
|
||||
extern const OpcodeSpec<float> flexEGPointShape;
|
||||
extern const OpcodeSpec<int> sampleQuality;
|
||||
extern const OpcodeSpec<int> octaveOffset;
|
||||
extern const OpcodeSpec<int> noteOffset;
|
||||
extern const OpcodeSpec<float> effect;
|
||||
extern const OpcodeSpec<int> apanWaveform;
|
||||
extern const OpcodeSpec<float> apanFrequency;
|
||||
extern const OpcodeSpec<float> apanPhase;
|
||||
extern const OpcodeSpec<float> apanLevel;
|
||||
extern const OpcodeSpec<float> distoTone;
|
||||
extern const OpcodeSpec<float> distoDepth;
|
||||
extern const OpcodeSpec<unsigned> distoStages;
|
||||
extern const OpcodeSpec<float> compAttack;
|
||||
extern const OpcodeSpec<float> compRelease;
|
||||
extern const OpcodeSpec<float> compThreshold;
|
||||
extern const OpcodeSpec<float> compRatio;
|
||||
extern const OpcodeSpec<float> compGain;
|
||||
extern const OpcodeSpec<float> fverbSize;
|
||||
extern const OpcodeSpec<float> fverbPredelay;
|
||||
extern const OpcodeSpec<float> fverbTone;
|
||||
extern const OpcodeSpec<float> fverbDamp;
|
||||
extern const OpcodeSpec<float> gateAttack;
|
||||
extern const OpcodeSpec<float> gateRelease;
|
||||
extern const OpcodeSpec<float> gateHold;
|
||||
extern const OpcodeSpec<float> gateThreshold;
|
||||
extern const OpcodeSpec<float> lofiBitred;
|
||||
extern const OpcodeSpec<float> lofiDecim;
|
||||
extern const OpcodeSpec<float> rectify;
|
||||
extern const OpcodeSpec<unsigned> stringsNumber;
|
||||
|
||||
// common defaults
|
||||
constexpr Range<uint8_t> midi7Range { 0, 127 };
|
||||
constexpr Range<float> float7Range { 0.0f, 127.0f };
|
||||
constexpr Range<float> normalizedRange { 0.0f, 1.0f };
|
||||
constexpr Range<float> 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<float> oscillatorPhaseRange { -1.0, 1.0 };
|
||||
constexpr int oscillatorMode { 0 };
|
||||
constexpr int oscillatorMulti { 1 };
|
||||
constexpr Range<int> oscillatorModeRange { 0, 2 };
|
||||
constexpr Range<int> oscillatorMultiRange { 1, config::oscillatorsPerVoice };
|
||||
constexpr float oscillatorDetune { 0 };
|
||||
constexpr Range<float> oscillatorDetuneRange { -12000, 12000 };
|
||||
constexpr Range<float> oscillatorDetuneCCRange { -12000, 12000 };
|
||||
constexpr float oscillatorModDepth { 0 };
|
||||
constexpr Range<float> oscillatorModDepthRange { 0, 10000 }; // depth%, allowed to be >100 for FM
|
||||
constexpr Range<float> oscillatorModDepthCCRange { 0, 10000 };
|
||||
constexpr int oscillatorQuality { 1 };
|
||||
constexpr Range<int> 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<uint32_t> groupRange { 0, std::numeric_limits<uint32_t>::max() };
|
||||
constexpr SfzOffMode offMode { SfzOffMode::fast };
|
||||
constexpr float offTime { 6e-3f };
|
||||
constexpr Range<uint32_t> 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<uint8_t> keyRange { 0, 127 };
|
||||
constexpr auto velocityRange = normalizedRange;
|
||||
|
||||
// Region logic: MIDI conditions
|
||||
constexpr Range<uint8_t> channelRange { 1, 16 };
|
||||
constexpr Range<uint8_t> midiChannelRange { 0, 15 };
|
||||
constexpr Range<uint8_t> smoothCCRange { 0, 100 };
|
||||
constexpr float smoothTauPerStep { 3e-3 };
|
||||
constexpr Range<uint8_t> curveCCRange { 0, 255 };
|
||||
constexpr Range<uint16_t> ccNumberRange { 0, config::numCCs };
|
||||
constexpr auto ccValueRange = normalizedRange;
|
||||
constexpr Range<int> bendRange = { -8192, 8192 };
|
||||
constexpr Range<float> bendValueRange = symmetricNormalizedRange;
|
||||
constexpr int bend { 0 };
|
||||
constexpr SfzVelocityOverride velocityOverride { SfzVelocityOverride::current };
|
||||
|
||||
// Region logic: internal conditions
|
||||
constexpr Range<float> randRange { 0.0, 1.0 };
|
||||
constexpr Range<uint8_t> aftertouchRange { 0, 127 };
|
||||
constexpr uint8_t aftertouch { 0 };
|
||||
constexpr Range<float> bpmRange { 0.0, 500.0 };
|
||||
constexpr float bpm { 120.0 };
|
||||
constexpr uint8_t sequenceLength{ 1 };
|
||||
constexpr uint8_t sequencePosition{ 1 };
|
||||
constexpr Range<uint8_t> sequenceRange { 1, 100 };
|
||||
|
||||
// Region logic: Triggers
|
||||
constexpr SfzTrigger trigger { SfzTrigger::attack };
|
||||
constexpr Range<float> ccTriggerValueRange = normalizedRange;
|
||||
|
||||
// Performance parameters: amplifier
|
||||
constexpr float globalVolume { -7.35f };
|
||||
constexpr float volume { 0.0f };
|
||||
constexpr Range<float> volumeRange { -144.0, 48.0 };
|
||||
constexpr Range<float> volumeCCRange { -144.0, 48.0 };
|
||||
constexpr float amplitude { 100.0 };
|
||||
constexpr Range<float> amplitudeRange { 0.0, 1e8 };
|
||||
constexpr float pan { 0.0 };
|
||||
constexpr Range<float> panRange { -100.0, 100.0 };
|
||||
constexpr Range<float> panCCRange { -200.0, 200.0 };
|
||||
constexpr float position { 0.0 };
|
||||
constexpr Range<float> positionRange { -100.0, 100.0 };
|
||||
constexpr Range<float> positionCCRange { -200.0, 200.0 };
|
||||
constexpr float width { 100.0 };
|
||||
constexpr Range<float> widthRange { -100.0, 100.0 };
|
||||
constexpr Range<float> widthCCRange { -200.0, 200.0 };
|
||||
constexpr uint8_t ampKeycenter { 60 };
|
||||
constexpr float ampKeytrack { 0.0 };
|
||||
constexpr Range<float> ampKeytrackRange { -96, 12 };
|
||||
constexpr float ampVeltrack { 100.0 };
|
||||
constexpr Range<float> ampVeltrackRange { -100.0, 100.0 };
|
||||
constexpr Range<float> ampVelcurveRange { 0.0, 1.0 };
|
||||
constexpr float ampRandom { 0.0 };
|
||||
constexpr Range<float> ampRandomRange { 0.0, 24.0 };
|
||||
constexpr Range<uint8_t> crossfadeKeyInRange { 0, 0 };
|
||||
constexpr Range<uint8_t> crossfadeKeyOutRange { 127, 127 };
|
||||
// Default values for ranges
|
||||
constexpr Range<uint8_t> crossfadeKeyInRange { 0, 0 };
|
||||
constexpr Range<uint8_t> crossfadeKeyOutRange { 127, 127 };
|
||||
constexpr Range<float> crossfadeVelInRange { 0.0f, 0.0f };
|
||||
constexpr Range<float> crossfadeVelOutRange { 1.0f, 1.0f };
|
||||
constexpr Range<float> crossfadeCCInRange { 0.0f, 0.0f };
|
||||
constexpr Range<float> 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<float> 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<float> filterCutoffRange { 0.0f, 20000.0f };
|
||||
constexpr Range<float> filterCutoffModRange { -12000, 12000 };
|
||||
constexpr Range<float> filterGainRange { -96.0f, 96.0f };
|
||||
constexpr Range<float> filterGainModRange { -96.0f, 96.0f };
|
||||
constexpr Range<int> filterKeytrackRange { 0, 1200 };
|
||||
constexpr Range<float> filterRandomRange { 0, 12000 };
|
||||
constexpr Range<int> filterVeltrackRange { -12000, 12000 };
|
||||
constexpr Range<float> filterResonanceRange { 0.0f, 96.0f };
|
||||
constexpr Range<float> 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<float> eqBandwidthRange { 0.001f, 4.0f };
|
||||
constexpr Range<float> eqBandwidthModRange { -4.0f, 4.0f };
|
||||
constexpr Range<float> eqFrequencyRange { 0.0f, 30000.0f };
|
||||
constexpr Range<float> eqFrequencyModRange { -30000.0f, 30000.0f };
|
||||
constexpr Range<float> eqGainRange { -96.0f, 96.0f };
|
||||
constexpr Range<float> eqGainModRange { -96.0f, 96.0f };
|
||||
|
||||
// Performance parameters: pitch
|
||||
constexpr uint8_t pitchKeycenter { 60 };
|
||||
constexpr int pitchKeytrack { 100 };
|
||||
constexpr Range<int> pitchKeytrackRange { -1200, 1200 };
|
||||
constexpr float pitchRandom { 0 };
|
||||
constexpr Range<float> pitchRandomRange { 0, 12000 };
|
||||
constexpr int pitchVeltrack { 0 };
|
||||
constexpr Range<int> pitchVeltrackRange { -12000, 12000 };
|
||||
constexpr int transpose { 0 };
|
||||
constexpr Range<int> transposeRange { -127, 127 };
|
||||
constexpr float tune { 0 };
|
||||
constexpr Range<float> tuneRange { -12000, 12000 }; // ±100 in SFZv1, more in ARIA
|
||||
constexpr Range<float> tuneCCRange { -12000, 12000 };
|
||||
constexpr Range<int> bendBoundRange { -12000, 12000 };
|
||||
constexpr Range<int> 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<float> lfoFreqRange { 0.0, 100.0 };
|
||||
constexpr Range<float> lfoFreqModRange { -100.0, 100.0 };
|
||||
constexpr Range<float> lfoBeatsRange { 0.0, 1000.0 };
|
||||
constexpr Range<float> lfoBeatsModRange { -1000.0, 1000.0 };
|
||||
constexpr Range<float> lfoPhaseRange { 0.0, 1.0 };
|
||||
constexpr Range<float> lfoDelayRange { 0.0, 30.0 };
|
||||
constexpr Range<float> lfoFadeRange { 0.0, 30.0 };
|
||||
constexpr Range<unsigned> lfoCountRange { 0, 1000 };
|
||||
constexpr Range<unsigned> lfoStepsRange { 0, static_cast<unsigned>(config::maxLFOSteps) };
|
||||
constexpr Range<float> lfoStepXRange { -100.0, 100.0 };
|
||||
constexpr Range<int> lfoWaveRange { 0, 15 };
|
||||
constexpr Range<float> lfoOffsetRange { -1.0, 1.0 };
|
||||
constexpr Range<float> lfoRatioRange { 0.0, 100.0 };
|
||||
constexpr Range<float> 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<float> egTimeRange { 0.0, 100.0 };
|
||||
constexpr Range<float> egPercentRange { 0.0, 100.0 };
|
||||
constexpr Range<int> egDepthRange { -12000, 12000 };
|
||||
constexpr Range<float> egOnCCTimeRange { -100.0, 100.0 };
|
||||
constexpr Range<float> egOnCCPercentRange { -100.0, 100.0 };
|
||||
constexpr Range<float> pitchEgDepthRange { -12000.0, 12000.0 };
|
||||
constexpr Range<float> 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<int> flexEGDynamicRange { 0, 1 };
|
||||
constexpr Range<int> flexEGSustainRange { 0, 100 };
|
||||
constexpr Range<float> flexEGPointTimeRange { 0.0f, 100.0f };
|
||||
constexpr Range<float> flexEGPointLevelRange { -1.0f, 1.0f };
|
||||
constexpr Range<float> flexEGPointShapeRange { -100.0f, 100.0f };
|
||||
|
||||
// ***** SFZ v2 ********
|
||||
constexpr int sampleQuality { 1 };
|
||||
constexpr int sampleQualityInFreewheelingMode { 10 }; // for future use, possibly excessive
|
||||
constexpr Range<int> sampleQualityRange { 1, 10 }; // sample_quality
|
||||
|
||||
constexpr bool checkSustain { true }; // sustain_sw
|
||||
constexpr bool checkSostenuto { true }; // sostenuto_sw
|
||||
constexpr Range<int> octaveOffsetRange { -10, 10 }; // octave_offset
|
||||
constexpr Range<int> noteOffsetRange { -127, 127 }; // note_offset
|
||||
|
||||
constexpr Range<int> apanWaveformRange { 0, std::numeric_limits<int>::max() };
|
||||
constexpr Range<float> apanFrequencyRange { 0, std::numeric_limits<float>::max() };
|
||||
constexpr Range<float> apanPhaseRange { 0.0, 1.0 };
|
||||
constexpr Range<float> apanLevelRange { 0.0, 100.0 };
|
||||
}
|
||||
}
|
||||
} // namespace sfz
|
||||
|
|
|
|||
|
|
@ -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<float> ccAttack;
|
||||
CCMap<float> 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);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,9 +43,9 @@ private:
|
|||
Resources& resources;
|
||||
const EQDescription* description;
|
||||
std::unique_ptr<FilterEq> 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;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#pragma once
|
||||
#include "AudioBuffer.h"
|
||||
#include "Defaults.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/types/span.h"
|
||||
#include <array>
|
||||
|
|
@ -178,8 +179,8 @@ private:
|
|||
std::vector<std::unique_ptr<Effect>> _effects;
|
||||
AudioBuffer<float> _inputs { EffectChannels, config::defaultSamplesPerBlock };
|
||||
AudioBuffer<float> _outputs { EffectChannels, config::defaultSamplesPerBlock };
|
||||
float _gainToMain = 0.0;
|
||||
float _gainToMix = 0.0;
|
||||
float _gainToMain { Default::effect.value };
|
||||
float _gainToMix { Default::effect.value };
|
||||
};
|
||||
|
||||
} // namespace sfz
|
||||
|
|
|
|||
|
|
@ -51,10 +51,10 @@ using FileAudioBuffer = AudioBuffer<float, 2, config::defaultAlignment,
|
|||
using FileAudioBufferPtr = std::shared_ptr<FileAudioBuffer>;
|
||||
|
||||
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 };
|
||||
|
|
|
|||
|
|
@ -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 };
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ void sfz::FilterHolder::setup(const Region& region, unsigned filterId, int noteN
|
|||
baseCutoff *= centsFactor(keytrack);
|
||||
const auto veltrack = static_cast<float>(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<float>(*resonanceSpan, baseResonance);
|
||||
if (float* mod = mm.getModulation(resonanceTarget))
|
||||
|
|
|
|||
|
|
@ -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<int>(Default::filterKeycenter), float velocity = 0);
|
||||
void setup(const Region& region, unsigned filterId, int noteNumber = static_cast<int>(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> 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;
|
||||
|
|
|
|||
|
|
@ -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<Curve> 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<FlexEGPoint> points;
|
||||
// ARIA
|
||||
bool ampeg = false; // replaces the SFZv1 AmpEG (lowest with this bit wins)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||
|
||||
#pragma once
|
||||
#include "Defaults.h"
|
||||
#include <absl/types/optional.h>
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -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<LFOWave>(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<float> steps {}; // lfoN_stepX - normalized to unity
|
||||
|
|
|
|||
|
|
@ -117,6 +117,116 @@ OpcodeCategory Opcode::identifyCategory(absl::string_view name)
|
|||
return category;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
absl::optional<T> readInt_(OpcodeSpec<T> 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<int64_t>(spec.bounds.getEnd())) {
|
||||
if (spec.flags & kEnforceUpperBound)
|
||||
return spec.bounds.getEnd();
|
||||
|
||||
if (spec.flags & kIgnoreOOB)
|
||||
return {};
|
||||
}
|
||||
|
||||
if (returnedValue < static_cast<int64_t>(spec.bounds.getStart())) {
|
||||
if (spec.flags & kEnforceLowerBound)
|
||||
return spec.bounds.getStart();
|
||||
|
||||
if (spec.flags & kIgnoreOOB)
|
||||
return {};
|
||||
}
|
||||
|
||||
T castValue = static_cast<T>(returnedValue);
|
||||
if ((castValue != returnedValue) & kIgnoreOOB)
|
||||
return {};
|
||||
|
||||
return castValue;
|
||||
}
|
||||
|
||||
#define INSTANTIATE_FOR_INTEGRAL(T) \
|
||||
template <> \
|
||||
absl::optional<T> Opcode::read(OpcodeSpec<T> spec) const \
|
||||
{ \
|
||||
return readInt_<T>(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 <typename T>
|
||||
absl::optional<T> readFloat_(OpcodeSpec<T> 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<int64_t>(spec.bounds.getEnd())) {
|
||||
if (spec.flags & kEnforceUpperBound)
|
||||
return spec.bounds.getEnd();
|
||||
|
||||
if (spec.flags & kIgnoreOOB)
|
||||
return {};
|
||||
}
|
||||
|
||||
if (returnedValue < static_cast<int64_t>(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<T> Opcode::read(OpcodeSpec<T> spec) const \
|
||||
{ \
|
||||
return readFloat_<T>(spec, value); \
|
||||
}
|
||||
|
||||
INSTANTIATE_FOR_FLOATING_POINT(float)
|
||||
INSTANTIATE_FOR_FLOATING_POINT(double)
|
||||
|
||||
absl::optional<uint8_t> readNoteValue(absl::string_view value)
|
||||
{
|
||||
char noteLetter = absl::ascii_tolower(value.empty() ? '\0' : value.front());
|
||||
|
|
@ -167,56 +277,6 @@ absl::optional<uint8_t> readNoteValue(absl::string_view value)
|
|||
return static_cast<uint8_t>(noteNumber);
|
||||
}
|
||||
|
||||
///
|
||||
template <typename ValueType, absl::enable_if_t<std::is_integral<ValueType>::value, int>>
|
||||
absl::optional<ValueType> readOpcode(absl::string_view value, const Range<ValueType>& 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<ValueType>::max())
|
||||
returnedValue = std::numeric_limits<ValueType>::max();
|
||||
if (returnedValue < std::numeric_limits<ValueType>::min())
|
||||
returnedValue = std::numeric_limits<ValueType>::min();
|
||||
|
||||
return validRange.clamp(static_cast<ValueType>(returnedValue));
|
||||
}
|
||||
|
||||
template <typename ValueType, absl::enable_if_t<std::is_floating_point<ValueType>::value, int>>
|
||||
absl::optional<ValueType> readOpcode(absl::string_view value, const Range<ValueType>& 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<bool> readBooleanFromOpcode(const Opcode& opcode)
|
||||
{
|
||||
// Cakewalk-style booleans, case-insensitive
|
||||
|
|
@ -227,84 +287,13 @@ absl::optional<bool> readBooleanFromOpcode(const Opcode& opcode)
|
|||
|
||||
// ARIA-style booleans? (seen in egN_dynamic=1 for example)
|
||||
// TODO check this
|
||||
if (auto value = readOpcode(opcode.value, Range<int64_t>::wholeRange()))
|
||||
const OpcodeSpec<int64_t> fullInt64 { 0, Range<int64_t>::wholeRange(), 0 };
|
||||
if (auto value = opcode.read(fullInt64))
|
||||
return *value != 0;
|
||||
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
template <class ValueType>
|
||||
void setValueFromOpcode(const Opcode& opcode, ValueType& target, const Range<ValueType>& 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 <class ValueType>
|
||||
inline void setValueFromOpcode(const Opcode& opcode, absl::optional<ValueType>& target, const Range<ValueType>& 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 <class ValueType>
|
||||
void setRangeEndFromOpcode(const Opcode& opcode, Range<ValueType>& target, const Range<ValueType>& 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 <class ValueType>
|
||||
void setRangeStartFromOpcode(const Opcode& opcode, Range<ValueType>& target, const Range<ValueType>& 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 <class ValueType>
|
||||
void setCCPairFromOpcode(const Opcode& opcode, absl::optional<CCData<ValueType>>& target, const Range<ValueType>& 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<T> readOpcode<T>(absl::string_view value, const Range<T>& validRange); /*NOLINT(bugprone-macro-parentheses)*/ \
|
||||
template void setValueFromOpcode<T>(const Opcode& opcode, T& target, const Range<T>& validRange); /*NOLINT(bugprone-macro-parentheses)*/ \
|
||||
template void setValueFromOpcode<T>(const Opcode& opcode, absl::optional<T>& target, const Range<T>& validRange); /*NOLINT(bugprone-macro-parentheses)*/ \
|
||||
template void setRangeEndFromOpcode(const Opcode& opcode, Range<T>& target, const Range<T>& validRange); /*NOLINT(bugprone-macro-parentheses)*/ \
|
||||
template void setRangeStartFromOpcode(const Opcode& opcode, Range<T>& target, const Range<T>& validRange); /*NOLINT(bugprone-macro-parentheses)*/ \
|
||||
template void setCCPairFromOpcode(const Opcode& opcode, absl::optional<CCData<T>>& target, const Range<T>& 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)
|
||||
|
|
|
|||
|
|
@ -101,6 +101,9 @@ struct Opcode {
|
|||
category == kOpcodeStepCcN || category == kOpcodeSmoothCcN;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
absl::optional<T> read(OpcodeSpec<T> spec) const;
|
||||
|
||||
private:
|
||||
static OpcodeCategory identifyCategory(absl::string_view name);
|
||||
LEAK_DETECTOR(Opcode);
|
||||
|
|
@ -114,96 +117,11 @@ private:
|
|||
*/
|
||||
absl::optional<uint8_t> 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<ValueType> the cast value, or null
|
||||
*/
|
||||
template <typename ValueType, absl::enable_if_t<std::is_integral<ValueType>::value, int> = 0>
|
||||
absl::optional<ValueType> readOpcode(absl::string_view value, const Range<ValueType>& 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<ValueType> the cast value, or null
|
||||
*/
|
||||
template <typename ValueType, absl::enable_if_t<std::is_floating_point<ValueType>::value, int> = 0>
|
||||
absl::optional<ValueType> readOpcode(absl::string_view value, const Range<ValueType>& validRange);
|
||||
|
||||
/**
|
||||
* @brief Read a boolean value from the sfz file and cast it to the destination parameter.
|
||||
*/
|
||||
absl::optional<bool> 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 <class ValueType>
|
||||
void setValueFromOpcode(const Opcode& opcode, ValueType& target, const Range<ValueType>& 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 <class ValueType>
|
||||
void setValueFromOpcode(const Opcode& opcode, absl::optional<ValueType>& target, const Range<ValueType>& 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 <class ValueType>
|
||||
void setRangeEndFromOpcode(const Opcode& opcode, Range<ValueType>& target, const Range<ValueType>& 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 <class ValueType>
|
||||
void setRangeStartFromOpcode(const Opcode& opcode, Range<ValueType>& target, const Range<ValueType>& 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 <class ValueType>
|
||||
void setCCPairFromOpcode(const Opcode& opcode, absl::optional<CCData<ValueType>>& target, const Range<ValueType>& validRange);
|
||||
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const sfz::Opcode &opcode);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -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<float> range, const ModKey& target);
|
||||
bool processGenericCc(const Opcode& opcode, OpcodeSpec<float> spec, const ModKey& target);
|
||||
|
||||
void offsetAllKeys(int offset) noexcept;
|
||||
|
||||
|
|
@ -329,45 +319,45 @@ struct Region {
|
|||
// Sound source: sample playback
|
||||
std::shared_ptr<FileId> sampleId { new FileId }; // Sample
|
||||
absl::optional<int> 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<int64_t> 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<int64_t> offsetCC { Default::offsetMod.value };
|
||||
uint32_t sampleEnd { Default::sampleEnd.value }; // end
|
||||
absl::optional<uint32_t> sampleCount {}; // count
|
||||
absl::optional<SfzLoopMode> loopMode {}; // loopmode
|
||||
Range<uint32_t> loopRange { Default::loopRange }; //loopstart and loopend
|
||||
float loopCrossfade { Default::loopCrossfade }; // loop_crossfade
|
||||
Range<uint32_t> 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<int> oscillatorQuality;
|
||||
|
||||
// Instrument settings: voice lifecycle
|
||||
uint32_t group { Default::group }; // group
|
||||
uint32_t group { Default::group.value }; // group
|
||||
absl::optional<uint32_t> offBy {}; // off_by
|
||||
SfzOffMode offMode { Default::offMode }; // off_mode
|
||||
float offTime { Default::offTime }; // off_mode
|
||||
float offTime { Default::offTime.value }; // off_mode
|
||||
absl::optional<uint32_t> 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<uint8_t> keyRange { Default::keyRange }; //lokey, hikey and key
|
||||
Range<float> velocityRange { Default::velocityRange }; // hivel and lovel
|
||||
Range<uint8_t> keyRange { Default::key.bounds }; //lokey, hikey and key
|
||||
Range<float> velocityRange { Default::normalized.bounds }; // hivel and lovel
|
||||
|
||||
// Region logic: MIDI conditions
|
||||
Range<float> bendRange { Default::bendValueRange }; // hibend and lobend
|
||||
CCMap<Range<float>> ccConditions { Default::ccValueRange };
|
||||
Range<float> bendRange { Default::bipolar.bounds }; // hibend and lobend
|
||||
CCMap<Range<float>> ccConditions { Default::normalized.bounds };
|
||||
absl::optional<uint8_t> lastKeyswitch {}; // sw_last
|
||||
absl::optional<Range<uint8_t>> lastKeyswitchRange {}; // sw_last
|
||||
absl::optional<std::string> 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<uint8_t> aftertouchRange { Default::aftertouchRange }; // hichanaft and lochanaft
|
||||
Range<float> bpmRange { Default::bpmRange }; // hibpm and lobpm
|
||||
Range<float> randRange { Default::randRange }; // hirand and lorand
|
||||
uint8_t sequenceLength { Default::sequenceLength }; // seq_length
|
||||
uint8_t sequencePosition { Default::sequencePosition }; // seq_position
|
||||
Range<uint8_t> aftertouchRange { Default::midi7.bounds }; // hichanaft and lochanaft
|
||||
Range<float> bpmRange { Default::bpm.bounds }; // hibpm and lobpm
|
||||
Range<float> 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<Range<float>> ccTriggers { Default::ccTriggerValueRange }; // on_loccN on_hiccN
|
||||
CCMap<Range<float>> 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<std::pair<uint8_t, float>> velocityPoints; // amp_velcurve_N
|
||||
absl::optional<Curve> velCurve {};
|
||||
float ampRandom { Default::ampRandom }; // amp_random
|
||||
float ampRandom { Default::ampRandom.value }; // amp_random
|
||||
Range<uint8_t> crossfadeKeyInRange { Default::crossfadeKeyInRange };
|
||||
Range<uint8_t> crossfadeKeyOutRange { Default::crossfadeKeyOutRange };
|
||||
Range<float> crossfadeVelInRange { Default::crossfadeVelInRange };
|
||||
|
|
@ -413,7 +403,7 @@ struct Region {
|
|||
SfzCrossfadeCurve crossfadeCCCurve { Default::crossfadeCCCurve };
|
||||
CCMap<Range<float>> crossfadeCCInRange { Default::crossfadeCCInRange }; // xfin_loccN xfin_hiccN
|
||||
CCMap<Range<float>> 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<FilterDescription> 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;
|
||||
|
|
|
|||
|
|
@ -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<uint8_t> range)
|
||||
inline CXX14_CONSTEXPR uint8_t offsetAndClampKey(uint8_t key, int offset)
|
||||
{
|
||||
const int offsetKey { key + offset };
|
||||
if (offsetKey > std::numeric_limits<uint8_t>::max())
|
||||
return range.getEnd();
|
||||
return Default::key.bounds.getEnd();
|
||||
if (offsetKey < std::numeric_limits<uint8_t>::min())
|
||||
return range.getStart();
|
||||
return Default::key.bounds.getStart();
|
||||
|
||||
return range.clamp(static_cast<uint8_t>(offsetKey));
|
||||
return Default::key.bounds.clamp(static_cast<uint8_t>(offsetKey));
|
||||
}
|
||||
|
||||
namespace literals {
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <array>
|
||||
|
||||
namespace sfz {
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ void Synth::Impl::buildRegion(const std::vector<Opcode>& 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<Opcode>& 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<Opcode>& 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<Opcode>& 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<Opcode>& 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<Opcode>& 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<uint8_t>(member.parameters.back());
|
||||
insertPairUniquely(keyLabels_, noteNumber, std::string(member.value));
|
||||
}
|
||||
|
|
@ -380,10 +385,10 @@ void Synth::Impl::handleControlOpcodes(const std::vector<Opcode>& 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<Opcode>& rawMembers)
|
|||
// note(jpc): gain opcodes are linear volumes in % units
|
||||
|
||||
case hash("directtomain"):
|
||||
if (auto valueOpt = readOpcode<float>(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<float>(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<float>(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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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<ControllerSource> genController_;
|
||||
|
|
|
|||
|
|
@ -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<float> 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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,20 +47,20 @@ namespace fx {
|
|||
template <int Wave> void computeLfos(float* left, float* right, unsigned nframes);
|
||||
|
||||
private:
|
||||
float _samplePeriod = 0.0;
|
||||
float _samplePeriod { 0.0f };
|
||||
sfz::Buffer<float> _lfoOutLeft { config::defaultSamplesPerBlock };
|
||||
sfz::Buffer<float> _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
|
||||
|
|
|
|||
|
|
@ -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<float, 2> _tempBuffer2x { 2, _oversampling * config::defaultSamplesPerBlock };
|
||||
AudioBuffer<float, 2> _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<float>(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<float>(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<float>(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<float>(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<float>(opc.value, {-100.0, 100.0}))
|
||||
if (auto value = opc.read(Default::compGain))
|
||||
impl._inputGain = db2mag(*value);
|
||||
break;
|
||||
case hash("comp_stlink"):
|
||||
|
|
|
|||
|
|
@ -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<Effect> Disto::makeInstance(absl::Span<const Opcode> 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<float>(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<float>(opc.value, {0.0f, 100.0f}))
|
||||
if (auto value = opc.read(Default::effect))
|
||||
impl._wet = *value * 0.01f;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"):
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,13 +180,13 @@ namespace fx {
|
|||
std::unique_ptr<Effect> 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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -166,25 +166,25 @@ namespace fx {
|
|||
for (const Opcode& opc : members) {
|
||||
switch (opc.lettersOnlyHash) {
|
||||
case hash("gate_attack"):
|
||||
if (auto value = readOpcode<float>(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<float>(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<float>(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<float>(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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<ResonantArray> _stringsArray;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"(
|
||||
<control> note_offset=1
|
||||
<region> key=63 sample=*sine
|
||||
<region> lokey=50 hikey=55 pitch_keycenter=50 sample=*sine
|
||||
<region> lokey=40 hikey=44 pitch_keycenter=40 xfin_lokey=36 xfin_hikey=40 xfout_lokey=44 xfout_hikey=48 sample=*sine
|
||||
<control> note_offset=-1
|
||||
<region> key=63 sw_lokey=24 sw_hikey=28 sw_last=25 sw_up=25 sw_down=25 sw_previous=62 sample=*sine
|
||||
<control> note_offset=1 octave_offset=1
|
||||
<region> key=63 sample=*sine
|
||||
<control> note_offset=-1 octave_offset=-1
|
||||
<region> key=63 sample=*sine
|
||||
<control> // Check that this does not reset either note or octave offset
|
||||
<region> key=63 sample=*sine
|
||||
)");
|
||||
REQUIRE( synth.getNumRegions() == 7 );
|
||||
|
||||
REQUIRE(synth.getRegionView(0)->keyRange == Range<uint8_t>(64, 64));
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
// <region>
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
// <control>
|
||||
|
|
@ -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<uint8_t>(0, 100)).value() == 16 );
|
||||
REQUIRE( sfz::readOpcode("+16", sfz::Range<uint8_t>(0, 100)).value() == 16 );
|
||||
REQUIRE( sfz::readOpcode("110", sfz::Range<uint8_t>(0, 100)).value() == 100 );
|
||||
REQUIRE( sfz::readOpcode("-1", sfz::Range<uint8_t>(0, 100)).value() == 0 );
|
||||
REQUIRE( sfz::readOpcode("12.5", sfz::Range<int>(-100, 100)).value() == 12 );
|
||||
REQUIRE( sfz::readOpcode("+12.5", sfz::Range<int>(-100, 100)).value() == 12 );
|
||||
REQUIRE( sfz::readOpcode("-40", sfz::Range<int>(-100, 100)).value() == -40 );
|
||||
REQUIRE( sfz::readOpcode("-140", sfz::Range<int>(-100, 100)).value() == -100 );
|
||||
REQUIRE( sfz::readOpcode("12.5", sfz::Range<float>(0.0f, 100.0f)).value() == 12.5_a );
|
||||
REQUIRE( sfz::readOpcode("+12.5", sfz::Range<float>(0.0f, 100.0f)).value() == 12.5_a );
|
||||
REQUIRE( sfz::readOpcode("-22.5", sfz::Range<float>(-20.0f, 100.0f)).value() == -20.0_a );
|
||||
REQUIRE( sfz::readOpcode("150.5", sfz::Range<float>(-20.0f, 100.0f)).value() == 100.0_a );
|
||||
REQUIRE( sfz::readOpcode("50.25garbage", sfz::Range<float>(-20.0f, 100.0f)).value() == 50.25_a );
|
||||
REQUIRE( sfz::readOpcode("50.25garbage", sfz::Range<int>(-20, 100)).value() == 50 );
|
||||
REQUIRE( !sfz::readOpcode("garbage50.25", sfz::Range<int>(-20, 100)) );
|
||||
REQUIRE( !sfz::readOpcode("garbage", sfz::Range<int>(-20, 100)) );
|
||||
SECTION("Basic")
|
||||
{
|
||||
Opcode opcode { "", "16" };
|
||||
OpcodeSpec<uint8_t> spec { 0, Range<uint8_t>(0, 100), 0 };
|
||||
REQUIRE( opcode.read(spec) == 16);
|
||||
}
|
||||
|
||||
SECTION("Sign")
|
||||
{
|
||||
Opcode opcode { "", "+16" };
|
||||
OpcodeSpec<uint8_t> spec { 0, Range<uint8_t>(0, 100), 0 };
|
||||
REQUIRE( opcode.read(spec) == 16);
|
||||
}
|
||||
|
||||
SECTION("Ignore")
|
||||
{
|
||||
Opcode opcode { "", "110" };
|
||||
OpcodeSpec<uint8_t> spec { 0, Range<uint8_t>(0, 100), kIgnoreOOB };
|
||||
REQUIRE( !opcode.read(spec) );
|
||||
}
|
||||
|
||||
SECTION("Clamp upper")
|
||||
{
|
||||
Opcode opcode { "", "110" };
|
||||
OpcodeSpec<uint8_t> spec { 0, Range<uint8_t>(0, 100), kEnforceUpperBound };
|
||||
REQUIRE( opcode.read(spec) == 100 );
|
||||
}
|
||||
|
||||
SECTION("Clamp lower")
|
||||
{
|
||||
Opcode opcode { "", "10" };
|
||||
OpcodeSpec<uint8_t> spec { 0, Range<uint8_t>(20, 100), kEnforceLowerBound };
|
||||
REQUIRE( opcode.read(spec) == 20 );
|
||||
}
|
||||
|
||||
SECTION("Floating point")
|
||||
{
|
||||
Opcode opcode { "", "10.5" };
|
||||
OpcodeSpec<uint8_t> spec { 0, Range<uint8_t>(0, 100), 0 };
|
||||
REQUIRE( opcode.read(spec) == 10 );
|
||||
}
|
||||
|
||||
SECTION("Text after")
|
||||
{
|
||||
Opcode opcode { "", "10garbage" };
|
||||
OpcodeSpec<uint8_t> spec { 0, Range<uint8_t>(20, 100), kEnforceLowerBound };
|
||||
REQUIRE( opcode.read(spec) == 20 );
|
||||
}
|
||||
|
||||
SECTION("Text before")
|
||||
{
|
||||
Opcode opcode { "", "garbage10" };
|
||||
OpcodeSpec<uint8_t> spec { 0, Range<uint8_t>(20, 100), 0 };
|
||||
REQUIRE( !opcode.read(spec) );
|
||||
}
|
||||
|
||||
SECTION("Can be note")
|
||||
{
|
||||
Opcode opcode { "", "c4" };
|
||||
OpcodeSpec<uint8_t> spec { 0, Range<uint8_t>(20, 100), kCanBeNote };
|
||||
REQUIRE( opcode.read(spec) == 60 );
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("[Opcode] opcode read (int)")
|
||||
{
|
||||
SECTION("Basic")
|
||||
{
|
||||
Opcode opcode { "", "16" };
|
||||
OpcodeSpec<int> spec { 0, Range<int>(-100, 100), 0 };
|
||||
REQUIRE( opcode.read(spec) == 16);
|
||||
}
|
||||
|
||||
SECTION("Sign")
|
||||
{
|
||||
Opcode opcode { "", "+16" };
|
||||
OpcodeSpec<int> spec { 0, Range<int>(-100, 100), 0 };
|
||||
REQUIRE( opcode.read(spec) == 16);
|
||||
}
|
||||
|
||||
SECTION("Sign")
|
||||
{
|
||||
Opcode opcode { "", "-16" };
|
||||
OpcodeSpec<int> spec { 0, Range<int>(-100, 100), 0 };
|
||||
REQUIRE( opcode.read(spec) == -16);
|
||||
}
|
||||
|
||||
SECTION("Ignore")
|
||||
{
|
||||
Opcode opcode { "", "110" };
|
||||
OpcodeSpec<int> spec { 0, Range<int>(-100, 100), kIgnoreOOB };
|
||||
REQUIRE( !opcode.read(spec) );
|
||||
}
|
||||
|
||||
SECTION("Clamp upper")
|
||||
{
|
||||
Opcode opcode { "", "110" };
|
||||
OpcodeSpec<int> spec { 0, Range<int>(-100, 100), kEnforceUpperBound };
|
||||
REQUIRE( opcode.read(spec) == 100 );
|
||||
}
|
||||
|
||||
SECTION("Clamp lower")
|
||||
{
|
||||
Opcode opcode { "", "-110" };
|
||||
OpcodeSpec<int> spec { 0, Range<int>(-100, 100), kEnforceLowerBound };
|
||||
REQUIRE( opcode.read(spec) == -100 );
|
||||
}
|
||||
|
||||
SECTION("Floating point")
|
||||
{
|
||||
Opcode opcode { "", "10.5" };
|
||||
OpcodeSpec<int> spec { 0, Range<int>(-100, 100), 0 };
|
||||
REQUIRE( opcode.read(spec) == 10 );
|
||||
}
|
||||
|
||||
SECTION("Text after")
|
||||
{
|
||||
Opcode opcode { "", "10garbage" };
|
||||
OpcodeSpec<int> spec { 0, Range<int>(20, 100), kEnforceLowerBound };
|
||||
REQUIRE( opcode.read(spec) == 20 );
|
||||
}
|
||||
|
||||
SECTION("Text before")
|
||||
{
|
||||
Opcode opcode { "", "garbage10" };
|
||||
OpcodeSpec<int> spec { 0, Range<int>(20, 100), 0 };
|
||||
REQUIRE( !opcode.read(spec) );
|
||||
}
|
||||
|
||||
SECTION("Can be note")
|
||||
{
|
||||
Opcode opcode { "", "c4" };
|
||||
OpcodeSpec<int> spec { 0, Range<int>(20, 100), kCanBeNote };
|
||||
REQUIRE( opcode.read(spec) == 60 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("[Opcode] opcode read (float)")
|
||||
{
|
||||
SECTION("Basic")
|
||||
{
|
||||
Opcode opcode { "", "16.4" };
|
||||
OpcodeSpec<float> spec { 0.0f, Range<float>(-100.0f, 100.0f), 0 };
|
||||
REQUIRE( opcode.read(spec) == 16.4_a);
|
||||
}
|
||||
|
||||
SECTION("Plus sign")
|
||||
{
|
||||
Opcode opcode { "", "+16.4" };
|
||||
OpcodeSpec<float> spec { 0.0f, Range<float>(-100.0f, 100.0f), 0 };
|
||||
REQUIRE( opcode.read(spec) == 16.4_a);
|
||||
}
|
||||
|
||||
SECTION("Minus sign")
|
||||
{
|
||||
Opcode opcode { "", "-16.4" };
|
||||
OpcodeSpec<float> spec { 0.0f, Range<float>(-100.0f, 100.0f), 0 };
|
||||
REQUIRE( opcode.read(spec) == -16.4_a);
|
||||
}
|
||||
|
||||
SECTION("Ignore")
|
||||
{
|
||||
Opcode opcode { "", "110" };
|
||||
OpcodeSpec<float> spec { 0.0f, Range<float>(-100.0f, 100.0f), kIgnoreOOB };
|
||||
REQUIRE( !opcode.read(spec) );
|
||||
}
|
||||
|
||||
SECTION("Clamp upper")
|
||||
{
|
||||
Opcode opcode { "", "110" };
|
||||
OpcodeSpec<float> spec { 0.0f, Range<float>(-100.0f, 100.0f), kEnforceUpperBound };
|
||||
REQUIRE( opcode.read(spec) == 100.0f );
|
||||
}
|
||||
|
||||
SECTION("Clamp lower")
|
||||
{
|
||||
Opcode opcode { "", "-110" };
|
||||
OpcodeSpec<float> spec { 0.0f, Range<float>(-100.0f, 100.0f), kEnforceLowerBound };
|
||||
REQUIRE( opcode.read(spec) == -100.0f );
|
||||
}
|
||||
|
||||
SECTION("Text after")
|
||||
{
|
||||
Opcode opcode { "", "10.5garbage" };
|
||||
OpcodeSpec<float> spec { 0.0f, Range<float>(0.0f, 100.0f), kEnforceLowerBound };
|
||||
REQUIRE( opcode.read(spec) == 10.5f );
|
||||
}
|
||||
|
||||
SECTION("Text before")
|
||||
{
|
||||
Opcode opcode { "", "garbage10" };
|
||||
OpcodeSpec<float> spec { 0.0f, Range<float>(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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@ TEST_CASE("[Values] Count")
|
|||
std::vector<std::string> 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"(
|
||||
<region> sample=kick.wav
|
||||
<region> sample=kick.wav loop_start=10 loop_end=100
|
||||
<region> sample=kick.wav loopstart=10 loopend=100
|
||||
<region> 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<std::string> 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<std::string> messageList;
|
||||
Client client(&messageList);
|
||||
client.setReceiveCallback(&simpleMessageReceiver);
|
||||
synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
|
||||
<region> sample=kick.wav
|
||||
<region> sample=kick.wav hikey=-1
|
||||
<region> sample=kick.wav key=-1
|
||||
<region> 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<std::string> 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<std::string> 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<std::string> 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<std::string> 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<std::string> 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<std::string> 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")
|
|||
<region> sample=kick.wav pitch=4.2
|
||||
<region> 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<std::string> 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"(
|
||||
<region> sample=kick.wav
|
||||
<region> sample=kick.wav tune_oncc42=4.2
|
||||
<region> sample=kick.wav pitch_oncc42=4.2
|
||||
<region> 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<std::string> 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"(
|
||||
<region> sample=kick.wav
|
||||
<region> sample=kick.wav tune_stepcc42=4.2
|
||||
<region> sample=kick.wav tune_smoothcc42=4
|
||||
<region> sample=kick.wav tune_curvecc42=2
|
||||
<region> sample=kick.wav tune_stepcc42=-1
|
||||
<region> sample=kick.wav tune_smoothcc42=-4
|
||||
<region> sample=kick.wav tune_curvecc42=300
|
||||
<region> sample=kick.wav pitch_stepcc42=4.2
|
||||
<region> sample=kick.wav pitch_smoothcc42=4
|
||||
<region> sample=kick.wav pitch_curvecc42=2
|
||||
<region> sample=kick.wav pitch_stepcc42=-1
|
||||
<region> sample=kick.wav pitch_smoothcc42=-4
|
||||
<region> 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<std::string> 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")
|
|||
<region> sample=kick.wav pitch_smoothcc42=-4
|
||||
<region> 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<std::string> 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<std::string> 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<std::string> 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<std::string> messageList;
|
||||
Client client(&messageList);
|
||||
client.setReceiveCallback(&simpleMessageReceiver);
|
||||
|
||||
synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
|
||||
<region> sample=kick.wav
|
||||
<region> sample=kick.wav oscillator_quality=2
|
||||
<region> 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<std::string> 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<std::string> messageList;
|
||||
Client client(&messageList);
|
||||
client.setReceiveCallback(&simpleMessageReceiver);
|
||||
|
||||
synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
|
||||
<region> sample=kick.wav
|
||||
<region> sample=kick.wav oscillator_mode=2
|
||||
<region> sample=kick.wav oscillator_mode=1 oscillator_mode=-2
|
||||
<region> sample=kick.wav oscillator_multi=9
|
||||
<region> 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<std::string> 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<std::string> messageList;
|
||||
Client client(&messageList);
|
||||
client.setReceiveCallback(&simpleMessageReceiver);
|
||||
|
||||
synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
|
||||
<region> sample=kick.wav
|
||||
<region> sample=kick.wav oscillator_detune=9.2
|
||||
<region> sample=kick.wav oscillator_detune=-1200.2
|
||||
<region> sample=kick.wav oscillator_mod_depth=1564.75
|
||||
<region> 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<std::string> 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;
|
||||
|
|
|
|||
|
|
@ -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")
|
|||
<region> locc4=64 hicc67=32 pan_cc5=200 sample=*sine
|
||||
<region> width_cc98=200 sample=*sine
|
||||
<region> position_cc42=200 pitch_oncc56=200 sample=*sine
|
||||
<region> start_locc44=200 hikey=-1 sample=*sine
|
||||
<region> start_locc44=120 hikey=-1 sample=*sine
|
||||
)");
|
||||
auto usedCCs = synth.getUsedCCs();
|
||||
REQUIRE( usedCCs.test(1) );
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
<control> note_offset=1
|
||||
<region> key=63 sample=*sine
|
||||
<region> lokey=50 hikey=55 pitch_keycenter=50 sample=*sine
|
||||
<region> lokey=40 hikey=44 pitch_keycenter=40 xfin_lokey=36 xfin_hikey=40 xfout_lokey=44 xfout_hikey=48 sample=*sine
|
||||
<control> note_offset=-1
|
||||
<region> key=63 sw_lokey=24 sw_hikey=28 sw_last=25 sw_up=25 sw_down=25 sw_previous=62 sample=*sine
|
||||
<control> note_offset=1 octave_offset=1
|
||||
<region> key=63 sample=*sine
|
||||
<control> note_offset=-1 octave_offset=-1
|
||||
<region> key=63 sample=*sine
|
||||
<control> // Check that this does not reset either note or octave offset
|
||||
<region> key=63 sample=*sine
|
||||
Loading…
Add table
Reference in a new issue