EG and LFO sources for the filters and EQs

This commit is contained in:
Paul Ferrand 2020-09-18 01:03:45 +02:00
parent fd8b00b9a1
commit 83cd4b6317
5 changed files with 1325 additions and 898 deletions

File diff suppressed because it is too large Load diff

View file

@ -85,6 +85,7 @@ end_region_oncc:
egV1 = "ampeg"|"fileg"|"pitcheg"; egV1 = "ampeg"|"fileg"|"pitcheg";
eqV1 = "eq" number; eqV1 = "eq" number;
lfoV2 = "lfo" number; lfoV2 = "lfo" number;
egV2 = "eg" number;
(lfoV1) "_" ("depth"|"freq"|"fade") "cc" (number) END { (lfoV1) "_" ("depth"|"freq"|"fade") "cc" (number) END {
opcode = absl::StrCat(group(1), "_", group(2), "_oncc", group(3)); opcode = absl::StrCat(group(1), "_", group(2), "_oncc", group(3));
@ -102,7 +103,14 @@ end_region_oncc:
opcode = absl::StrCat(group(1), "_", group(2), "1"); opcode = absl::StrCat(group(1), "_", group(2), "1");
goto end_region; goto end_region;
} }
(lfoV2) "_" ("cutoff"|"resonance") ("_" any)? END {
opcode = absl::StrCat(group(1), "_", group(2), "1", group(3));
goto end_region;
}
(egV2) "_" ("cutoff"|"resonance") ("_" any)? END {
opcode = absl::StrCat(group(1), "_", group(2), "1", group(3));
goto end_region;
}
"loop" ("mode"|"start"|"end") END { "loop" ("mode"|"start"|"end") END {
opcode = absl::StrCat("loop_", group(1)); opcode = absl::StrCat("loop_", group(1));
goto end_region; goto end_region;

View file

@ -45,6 +45,23 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode)
case hash(x "_stepcc&"): \ case hash(x "_stepcc&"): \
case hash(x "_smoothcc&") case hash(x "_smoothcc&")
#define LFO_EG_filter_EQ_target(sourceKey, targetKey, range) \
{ \
const auto number = opcode.parameters.front(); \
if (number == 0) \
return false; \
\
const auto index = opcode.parameters.size() == 2 ? opcode.parameters.back() - 1 : 0; \
if (!extendIfNecessary(filters, index + 1, Default::numFilters)) \
return false; \
\
if (auto value = readOpcode(opcode.value, range)) { \
const ModKey source = ModKey::createNXYZ(sourceKey, id, number - 1); \
const ModKey target = ModKey::createNXYZ(targetKey, id, index); \
getOrCreateConnection(source, target).sourceDepth = *value; \
} \
}
// Sound source: sample playback // Sound source: sample playback
case hash("sample"): case hash("sample"):
{ {
@ -1016,6 +1033,24 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode)
} }
} }
break; break;
case hash("lfo&_cutoff&"):
LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilCutoff, Default::filterCutoffModRange);
break;
case hash("lfo&_resonance&"):
LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilResonance, Default::filterResonanceModRange);
break;
case hash("lfo&_fil&_gain"):
LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilGain, Default::filterGainModRange);
break;
case hash("lfo&_eq&gain"):
LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqGain, Default::eqGainModRange);
break;
case hash("lfo&_eq&freq"):
LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqFrequency, Default::eqFrequencyModRange);
break;
case hash("lfo&_eq&bw"):
LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqBandwidth, Default::eqBandwidthModRange);
break;
// Modulation: Flex EG (targets) // Modulation: Flex EG (targets)
case hash("eg&_amplitude"): case hash("eg&_amplitude"):
@ -1090,6 +1125,24 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode)
} }
} }
break; break;
case hash("eg&_cutoff&"):
LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilCutoff, Default::filterCutoffModRange);
break;
case hash("eg&_resonance&"):
LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilResonance, Default::filterResonanceModRange);
break;
case hash("eg&_fil&_gain"):
LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilGain, Default::filterGainModRange);
break;
case hash("eg&_eq&gain"):
LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqGain, Default::eqGainModRange);
break;
case hash("eg&_eq&freq"):
LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqFrequency, Default::eqFrequencyModRange);
break;
case hash("eg&_eq&bw"):
LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqBandwidth, Default::eqBandwidthModRange);
break;
// Amplitude Envelope // Amplitude Envelope
case hash("ampeg_attack"): case hash("ampeg_attack"):
@ -1292,6 +1345,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode)
return false; return false;
#undef case_any_ccN #undef case_any_ccN
#undef LFO_EG_filter_EQ_target
} }
return true; return true;

View file

@ -88,17 +88,17 @@ std::string ModKey::toString() const
case ModId::Volume: case ModId::Volume:
return absl::StrCat("Volume {", region_.number(), "}"); return absl::StrCat("Volume {", region_.number(), "}");
case ModId::FilGain: case ModId::FilGain:
return absl::StrCat("FilterGain {", region_.number(), ", N=", params_.N, "}"); return absl::StrCat("FilterGain {", region_.number(), ", N=", 1 + params_.N, "}");
case ModId::FilCutoff: case ModId::FilCutoff:
return absl::StrCat("FilterCutoff {", region_.number(), ", N=", params_.N, "}"); return absl::StrCat("FilterCutoff {", region_.number(), ", N=", 1 + params_.N, "}");
case ModId::FilResonance: case ModId::FilResonance:
return absl::StrCat("FilterResonance {", region_.number(), ", N=", params_.N, "}"); return absl::StrCat("FilterResonance {", region_.number(), ", N=", 1 + params_.N, "}");
case ModId::EqGain: case ModId::EqGain:
return absl::StrCat("EqGain {", region_.number(), ", N=", params_.N, "}"); return absl::StrCat("EqGain {", region_.number(), ", N=", 1 + params_.N, "}");
case ModId::EqFrequency: case ModId::EqFrequency:
return absl::StrCat("EqFrequency {", region_.number(), ", N=", params_.N, "}"); return absl::StrCat("EqFrequency {", region_.number(), ", N=", 1 + params_.N, "}");
case ModId::EqBandwidth: case ModId::EqBandwidth:
return absl::StrCat("EqBandwidth {", region_.number(), ", N=", params_.N, "}"); return absl::StrCat("EqBandwidth {", region_.number(), ", N=", 1 + params_.N, "}");
default: default:
return {}; return {};

View file

@ -112,9 +112,9 @@ TEST_CASE("[Modulations] Filter CC connections")
const std::string graph = synth.getResources().modMatrix.toDotGraph(); const std::string graph = synth.getResources().modMatrix.toDotGraph();
REQUIRE(graph == createReferenceGraph({ REQUIRE(graph == createReferenceGraph({
R"("Controller 1 {curve=0, smooth=10, value=2, step=0}" -> "FilterResonance {0, N=2}")", R"("Controller 1 {curve=0, smooth=10, value=2, step=0}" -> "FilterResonance {0, N=3}")",
R"("Controller 2 {curve=2, smooth=0, value=100, step=0}" -> "FilterCutoff {0, N=1}")", R"("Controller 2 {curve=2, smooth=0, value=100, step=0}" -> "FilterCutoff {0, N=2}")",
R"("Controller 3 {curve=0, smooth=0, value=5, step=0.5}" -> "FilterGain {0, N=0}")", R"("Controller 3 {curve=0, smooth=0, value=5, step=0.5}" -> "FilterGain {0, N=1}")",
})); }));
} }
@ -130,8 +130,104 @@ TEST_CASE("[Modulations] EQ CC connections")
const std::string graph = synth.getResources().modMatrix.toDotGraph(); const std::string graph = synth.getResources().modMatrix.toDotGraph();
REQUIRE(graph == createReferenceGraph({ REQUIRE(graph == createReferenceGraph({
R"("Controller 1 {curve=0, smooth=10, value=2, step=0}" -> "EqBandwidth {0, N=2}")", R"("Controller 1 {curve=0, smooth=10, value=2, step=0}" -> "EqBandwidth {0, N=3}")",
R"("Controller 2 {curve=0, smooth=0, value=5, step=0.5}" -> "EqGain {0, N=0}")", R"("Controller 2 {curve=0, smooth=0, value=5, step=0.5}" -> "EqGain {0, N=1}")",
R"("Controller 3 {curve=3, smooth=0, value=300, step=0}" -> "EqFrequency {0, N=1}")", R"("Controller 3 {curve=3, smooth=0, value=300, step=0}" -> "EqFrequency {0, N=2}")",
}));
}
TEST_CASE("[Modulations] LFO Filter connections")
{
sfz::Synth synth;
synth.loadSfzString("/modulation.sfz", R"(
<region> sample=*sine
lfo1_freq=0.1 lfo1_cutoff1=1
lfo2_freq=1 lfo2_cutoff=2
lfo3_freq=2 lfo3_resonance=3
lfo4_freq=0.5 lfo4_resonance1=4
lfo5_freq=0.5 lfo5_resonance2=5
lfo6_freq=3 lfo6_fil1_gain=-1
)");
const std::string graph = synth.getResources().modMatrix.toDotGraph();
REQUIRE(graph == createReferenceGraph({
R"("LFO 1 {0}" -> "FilterCutoff {0, N=1}")",
R"("LFO 2 {0}" -> "FilterCutoff {0, N=1}")",
R"("LFO 3 {0}" -> "FilterResonance {0, N=1}")",
R"("LFO 4 {0}" -> "FilterResonance {0, N=1}")",
R"("LFO 5 {0}" -> "FilterResonance {0, N=2}")",
R"("LFO 6 {0}" -> "FilterGain {0, N=1}")",
}));
}
TEST_CASE("[Modulations] EG Filter connections")
{
sfz::Synth synth;
synth.loadSfzString("/modulation.sfz", R"(
<region> sample=*sine
eg1_time1=0.1 eg1_cutoff1=1
eg2_time1=1 eg2_cutoff=2
eg3_time1=2 eg3_resonance=3
eg4_time1=0.5 eg4_resonance1=4
eg5_time1=0.5 eg5_resonance2=5
eg6_time1=3 eg6_fil1_gain=-1
)");
const std::string graph = synth.getResources().modMatrix.toDotGraph();
REQUIRE(graph == createReferenceGraph({
R"("EG 1 {0}" -> "FilterCutoff {0, N=1}")",
R"("EG 2 {0}" -> "FilterCutoff {0, N=1}")",
R"("EG 3 {0}" -> "FilterResonance {0, N=1}")",
R"("EG 4 {0}" -> "FilterResonance {0, N=1}")",
R"("EG 5 {0}" -> "FilterResonance {0, N=2}")",
R"("EG 6 {0}" -> "FilterGain {0, N=1}")",
}));
}
TEST_CASE("[Modulations] LFO EQ connections")
{
sfz::Synth synth;
synth.loadSfzString("/modulation.sfz", R"(
<region> sample=*sine
lfo1_freq=0.1 lfo1_eq1bw=1
lfo2_freq=1 lfo2_eq2freq=2
lfo3_freq=2 lfo3_eq3gain=3
lfo4_freq=0.5 lfo4_eq3bw=4
lfo5_freq=0.5 lfo5_eq2gain=5
lfo6_freq=3 lfo6_eq1freq=-1
)");
const std::string graph = synth.getResources().modMatrix.toDotGraph();
REQUIRE(graph == createReferenceGraph({
R"("LFO 1 {0}" -> "EqBandwidth {0, N=1}")",
R"("LFO 2 {0}" -> "EqFrequency {0, N=2}")",
R"("LFO 3 {0}" -> "EqGain {0, N=3}")",
R"("LFO 4 {0}" -> "EqBandwidth {0, N=3}")",
R"("LFO 5 {0}" -> "EqGain {0, N=2}")",
R"("LFO 6 {0}" -> "EqFrequency {0, N=1}")",
}));
}
TEST_CASE("[Modulations] EG EQ connections")
{
sfz::Synth synth;
synth.loadSfzString("/modulation.sfz", R"(
<region> sample=*sine
eg1_freq=0.1 eg1_eq1bw=1
eg2_freq=1 eg2_eq2freq=2
eg3_freq=2 eg3_eq3gain=3
eg4_freq=0.5 eg4_eq3bw=4
eg5_freq=0.5 eg5_eq2gain=5
eg6_freq=3 eg6_eq1freq=-1
)");
const std::string graph = synth.getResources().modMatrix.toDotGraph();
REQUIRE(graph == createReferenceGraph({
R"("EG 1 {0}" -> "EqBandwidth {0, N=1}")",
R"("EG 2 {0}" -> "EqFrequency {0, N=2}")",
R"("EG 3 {0}" -> "EqGain {0, N=3}")",
R"("EG 4 {0}" -> "EqBandwidth {0, N=3}")",
R"("EG 5 {0}" -> "EqGain {0, N=2}")",
R"("EG 6 {0}" -> "EqFrequency {0, N=1}")",
})); }));
} }