This commit is contained in:
Paul Ferrand 2021-02-04 11:52:20 +01:00
parent 2fd8c892cf
commit dc68054981
6 changed files with 48 additions and 32 deletions

View file

@ -73,7 +73,7 @@ extern const OpcodeSpec<float> ampVelcurve { 0.0f, Range<float>(0.0f, 1.0f), 0 }
extern const OpcodeSpec<float> ampRandom { 0.0f, Range<float>(0.0f, 24.0f), 0 };
extern const OpcodeSpec<bool> rtDead { false, Range<bool>(0, 1), 0 };
extern const OpcodeSpec<float> rtDecay { 0.0f, Range<float>(0.0f, 200.0f), 0 };
extern const OpcodeSpec<float> filterCutoff { 0.0f, Range<float>(0.0f, 20000.0f), 0 };
extern const OpcodeSpec<float> filterCutoff { 0.0f, Range<float>(0.0f, 20000.0f), kEnforceUpperBound };
extern const OpcodeSpec<float> filterCutoffMod { 0.0f, Range<float>(-12000.0f, 12000.0f), 0 };
extern const OpcodeSpec<float> filterResonance { 0.0f, Range<float>(0.0f, 96.0f), 0 };
extern const OpcodeSpec<float> filterResonanceMod { 0.0f, Range<float>(0.0f, 96.0f), 0 };
@ -84,8 +84,8 @@ extern const OpcodeSpec<int> filterKeytrack { 0, Range<int>(0, 1200), 0 };
extern const OpcodeSpec<int> filterVeltrack { 0, Range<int>(-12000, 12000), 0 };
extern const OpcodeSpec<float> eqBandwidth { 1.0f, Range<float>(0.001f, 4.0f), 0 };
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), 0 };
extern const OpcodeSpec<float> eqFrequencyMod { 0.0f, Range<float>(-30000.0f, 30000.0f), 0 };
extern const OpcodeSpec<float> eqFrequency { 0.0f, Range<float>(0.0f, 20000.0f), kEnforceUpperBound };
extern const OpcodeSpec<float> eqFrequencyMod { 0.0f, Range<float>(-20000.0f, 20000.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 };
@ -159,6 +159,7 @@ extern const OpcodeSpec<unsigned> stringsNumber { maxStrings, Range<unsigned>(0,
extern const OpcodeSpec<Trigger> trigger { Trigger::attack, Range<Trigger>(Trigger::attack, Trigger::release_key), 0};
extern const OpcodeSpec<CrossfadeCurve> crossfadeCurve { CrossfadeCurve::power, Range<CrossfadeCurve>(CrossfadeCurve::gain, CrossfadeCurve::power), 0};
extern const OpcodeSpec<OffMode> offMode { OffMode::fast, Range<OffMode>(OffMode::fast, OffMode::time), 0};
extern const OpcodeSpec<LoopMode> loopMode { LoopMode::no_loop, Range<LoopMode>(LoopMode::no_loop, LoopMode::loop_sustain), 0};
extern const OpcodeSpec<VelocityOverride> velocityOverride { VelocityOverride::current, Range<VelocityOverride>(VelocityOverride::current, VelocityOverride::previous), 0};
extern const OpcodeSpec<SelfMask> selfMask { SelfMask::mask, Range<SelfMask>(SelfMask::mask, SelfMask::dontMask), 0};
extern const OpcodeSpec<FilterType> filter { FilterType::kFilterNone, Range<FilterType>(FilterType::kFilterNone, FilterType::kFilterPeq), 0};

View file

@ -74,6 +74,14 @@ struct OpcodeSpec
T defaultInputValue;
Range<T> bounds;
int flags;
/**
* @brief Normalizes an input as needed for the spec
*
* @tparam U
* @param input
* @return U
*/
template<class U=T>
typename std::enable_if<std::is_arithmetic<U>::value, U>::type normalizeInput(U input) const
{
@ -98,6 +106,13 @@ struct OpcodeSpec
return input;
}
/**
* @brief Normalizes an input as needed for the spec
*
* @tparam U
* @param input
* @return U
*/
template<class U=T>
typename std::enable_if<!std::is_arithmetic<U>::value, U>::type normalizeInput(U input) const
{
@ -262,6 +277,7 @@ namespace Default
extern const OpcodeSpec<unsigned> stringsNumber;
extern const OpcodeSpec<Trigger> trigger;
extern const OpcodeSpec<OffMode> offMode;
extern const OpcodeSpec<LoopMode> loopMode;
extern const OpcodeSpec<CrossfadeCurve> crossfadeCurve;
extern const OpcodeSpec<VelocityOverride> velocityOverride;
extern const OpcodeSpec<SelfMask> selfMask;

View file

@ -197,12 +197,12 @@ absl::optional<T> readFloat_(OpcodeSpec<T> spec, absl::string_view v)
if (spec.flags & kEnforceUpperBound)
return spec.bounds.getEnd();
return {};
return absl::nullopt;
} else if (returnedValue < static_cast<int64_t>(spec.bounds.getStart())) {
if (spec.flags & kEnforceLowerBound)
return spec.bounds.getStart();
return {};
return absl::nullopt;
}
return spec.normalizeInput(returnedValue);
@ -223,7 +223,7 @@ absl::optional<uint8_t> readNoteValue(absl::string_view value)
char noteLetter = absl::ascii_tolower(value.empty() ? '\0' : value.front());
value.remove_prefix(1);
if (noteLetter < 'a' || noteLetter > 'g')
return {};
return absl::nullopt;
constexpr int offsetsABCDEFG[] = { 9, 11, 0, 2, 4, 5, 7 };
int noteNumber = offsetsABCDEFG[noteLetter - 'a'];
@ -244,11 +244,11 @@ absl::optional<uint8_t> readNoteValue(absl::string_view value)
if (absl::StartsWith(value, prefix.first)) {
if (prefix.second == +1) {
if (validSharpLetters.find(noteLetter) == absl::string_view::npos)
return {};
return absl::nullopt;
}
else if (prefix.second == -1) {
if (validFlatLetters.find(noteLetter) == absl::string_view::npos)
return {};
return absl::nullopt;
}
noteNumber += prefix.second;
value.remove_prefix(prefix.first.size());
@ -258,12 +258,12 @@ absl::optional<uint8_t> readNoteValue(absl::string_view value)
int octaveNumber;
if (!absl::SimpleAtoi(value, &octaveNumber))
return {};
return absl::nullopt;
noteNumber += (octaveNumber + 1) * 12;
if (noteNumber < 0 || noteNumber >= 128)
return {};
return absl::nullopt;
return static_cast<uint8_t>(noteNumber);
}
@ -293,7 +293,7 @@ absl::optional<OscillatorEnabled> Opcode::readOptional(OpcodeSpec<OscillatorEnab
{
auto v = readBooleanFromOpcode(*this);
if (!v)
return {};
return absl::nullopt;
return *v ? OscillatorEnabled::On : OscillatorEnabled::Off;
}
@ -409,6 +409,20 @@ absl::optional<SelfMask> Opcode::readOptional(OpcodeSpec<SelfMask>) const
return absl::nullopt;
}
template <>
absl::optional<LoopMode> Opcode::readOptional(OpcodeSpec<LoopMode>) const
{
switch (hash(value)) {
case hash("no_loop"): return LoopMode::no_loop;
case hash("one_shot"): return LoopMode::one_shot;
case hash("loop_continuous"): return LoopMode::loop_continuous;
case hash("loop_sustain"): return LoopMode::loop_sustain;
}
DBG("Unknown loop mode: " << value);
return absl::nullopt;
}
template <>
absl::optional<bool> Opcode::readOptional(OpcodeSpec<bool>) const
{

View file

@ -119,22 +119,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode)
sampleCount = opcode.read(Default::sampleCount);
break;
case hash("loop_mode"): // also loopmode
switch (hash(opcode.value)) {
case hash("no_loop"):
loopMode = LoopMode::no_loop;
break;
case hash("one_shot"):
loopMode = LoopMode::one_shot;
break;
case hash("loop_continuous"):
loopMode = LoopMode::loop_continuous;
break;
case hash("loop_sustain"):
loopMode = LoopMode::loop_sustain;
break;
default:
DBG("Unkown loop mode:" << opcode.value);
}
loopMode = opcode.readOptional(Default::loopMode);
break;
case hash("loop_end"): // also loopend
loopRange.setEnd(opcode.read(Default::loopEnd));

View file

@ -2891,13 +2891,13 @@ TEST_CASE("[Values] Filter value bounds")
SECTION("Cutoff")
{
synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
<region> sample=kick.wav cutoff=20000000 // Ignore the value
<region> sample=kick.wav cutoff=20000000 // Clamp the value
<region> sample=kick.wav cutoff=50 cutoff=-100
)");
synth.dispatchMessage(client, 0, "/region0/filter0/cutoff", "", nullptr);
synth.dispatchMessage(client, 0, "/region1/filter0/cutoff", "", nullptr);
std::vector<std::string> expected {
"/region0/filter0/cutoff,f : { 0 }",
"/region0/filter0/cutoff,f : { 20000 }",
"/region1/filter0/cutoff,f : { 0 }",
};
REQUIRE(messageList == expected);
@ -3097,13 +3097,13 @@ TEST_CASE("[Values] EQ value bounds")
SECTION("Frequency")
{
synth.loadSfzString(fs::current_path() / "tests/TestFiles/value_tests.sfz", R"(
<region> sample=kick.wav eq1_freq=20000000 // Ignore
<region> sample=kick.wav eq1_freq=20000000 // Clamp the value
<region> sample=kick.wav eq1_freq=50 eq1_freq=-100
)");
synth.dispatchMessage(client, 0, "/region0/eq0/frequency", "", nullptr);
synth.dispatchMessage(client, 0, "/region1/eq0/frequency", "", nullptr);
std::vector<std::string> expected {
"/region0/eq0/frequency,f : { 50 }",
"/region0/eq0/frequency,f : { 20000 }",
"/region1/eq0/frequency,f : { 50 }",
};
REQUIRE(messageList == expected);

View file

@ -5,11 +5,11 @@
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
#pragma once
#include "catch2/catch.hpp"
#include "sfizz/Synth.h"
#include "sfizz/Region.h"
#include "sfizz/Voice.h"
#include "sfizz/Range.h"
#include "catch2/catch.hpp"
#include "sfizz/modulations/ModKey.h"
class RegionCCView {