diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 55f92c73..a32d6754 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -920,8 +920,10 @@ bool sfz::Region::parseLFOOpcode(const Opcode& opcode, LFODescription& lfo) getOrCreateConnection(sourceKey, targetKey).sourceDepthMod = sourceDepthKey; processGenericCc(opcode, depthModSpec, sourceDepthKey); break; - case_any_lfo("depthchanaft"): // NOLINT bugprone-branch-clone - // TODO(jpc) LFO v1 + case_any_lfo("depthchanaft"): + getOrCreateConnection(sourceKey, targetKey).sourceDepthMod = sourceDepthKey; + getOrCreateConnection(ModKey::createNXYZ(ModId::ChannelAftertouch), sourceDepthKey).sourceDepth + = opcode.read(depthModSpec); break; case_any_lfo("depthpolyaft"): // NOLINT bugprone-branch-clone // TODO(jpc) LFO v1 @@ -936,7 +938,8 @@ bool sfz::Region::parseLFOOpcode(const Opcode& opcode, LFODescription& lfo) processGenericCc(opcode, Default::lfoFreqMod, lfo.freqKey); break; case_any_lfo("freqchanaft"): // NOLINT bugprone-branch-clone - // TODO(jpc) LFO v1 + getOrCreateConnection(ModKey::createNXYZ(ModId::ChannelAftertouch), lfo.freqKey).sourceDepth + = opcode.read(Default::lfoFreqMod); break; case_any_lfo("freqpolyaft"): // NOLINT bugprone-branch-clone // TODO(jpc) LFO v1 diff --git a/tests/ModulationsT.cpp b/tests/ModulationsT.cpp index cfec1788..bd701ae6 100644 --- a/tests/ModulationsT.cpp +++ b/tests/ModulationsT.cpp @@ -390,6 +390,67 @@ TEST_CASE("[Modulations] LFO v1 CC connections") }, 3)); } +TEST_CASE("[Modulations] LFO v1 CC frequency connections") +{ + sfz::Synth synth; + synth.loadSfzString("/modulation.sfz", R"( + sample=*sine amplfo_freq_oncc1=10 + sample=*sine pitchlfo_freq_cc2=1200 + sample=*sine fillfo_freqcc3=-3600 + )"); + + const std::string graph = synth.getResources().modMatrix.toDotGraph(); + REQUIRE(graph == createDefaultGraph({ + R"("Controller 1 {curve=0, smooth=0, step=0}" -> "AmplitudeLFOFrequency {0}")", + R"("Controller 2 {curve=0, smooth=0, step=0}" -> "PitchLFOFrequency {1}")", + R"("Controller 3 {curve=0, smooth=0, step=0}" -> "FilterLFOFrequency {2}")", + R"("AmplitudeLFO {0}" -> "Volume {0}")", + R"("PitchLFO {1}" -> "Pitch {1}")", + R"("FilterLFO {2}" -> "FilterCutoff {2, N=1}")", + }, 3)); +} + +TEST_CASE("[Modulations] LFO v1 aftertouch connections") +{ + sfz::Synth synth; + synth.loadSfzString("/modulation.sfz", R"( + sample=*sine amplfo_depthchanaft=10 + sample=*sine pitchlfo_depthchanaft=1200 + sample=*sine fillfo_depthchanaft=-3600 + )"); + + const std::string graph = synth.getResources().modMatrix.toDotGraph(); + REQUIRE(graph == createDefaultGraph({ + R"("ChannelAftertouch" -> "AmplitudeLFODepth {0}")", + R"("ChannelAftertouch" -> "PitchLFODepth {1}")", + R"("ChannelAftertouch" -> "FilterLFODepth {2}")", + R"("AmplitudeLFO {0}" -> "Volume {0}")", + R"("PitchLFO {1}" -> "Pitch {1}")", + R"("FilterLFO {2}" -> "FilterCutoff {2, N=1}")", + }, 3)); +} + + +TEST_CASE("[Modulations] LFO v1 aftertouch frequency connections") +{ + sfz::Synth synth; + synth.loadSfzString("/modulation.sfz", R"( + sample=*sine amplfo_freqchanaft=10 + sample=*sine pitchlfo_freqchanaft=1200 + sample=*sine fillfo_freqchanaft=-3600 + )"); + + const std::string graph = synth.getResources().modMatrix.toDotGraph(); + REQUIRE(graph == createDefaultGraph({ + R"("ChannelAftertouch" -> "AmplitudeLFOFrequency {0}")", + R"("ChannelAftertouch" -> "PitchLFOFrequency {1}")", + R"("ChannelAftertouch" -> "FilterLFOFrequency {2}")", + R"("AmplitudeLFO {0}" -> "Volume {0}")", + R"("PitchLFO {1}" -> "Pitch {1}")", + R"("FilterLFO {2}" -> "FilterCutoff {2, N=1}")", + }, 3)); +} + TEST_CASE("[Modulations] EG v1 CC connections") { sfz::Synth synth;