diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ac6682e5..230a6433 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,7 +15,7 @@ env: jobs: clang_tidy: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 with: diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 8ae0805f..a23dbfae 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -804,7 +804,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (parseEGOpcode(opcode, filterEG)) { getOrCreateConnection( ModKey::createNXYZ(ModId::FilEG, id), - ModKey::createNXYZ(ModId::FilCutoff, id)); + ModKey::createNXYZ(ModId::FilCutoff, id, 0)); return true; } } @@ -832,7 +832,7 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) if (parseLFOOpcode(opcode, filterLFO)) { getOrCreateConnection( ModKey::createNXYZ(ModId::FilLFO, id), - ModKey::createNXYZ(ModId::FilCutoff, id)); + ModKey::createNXYZ(ModId::FilCutoff, id, 0)); return true; } } @@ -897,7 +897,7 @@ bool sfz::Region::parseLFOOpcode(const Opcode& opcode, LFODescription& lfo) else if (absl::StartsWith(opcode.name, "fillfo_")) { sourceKey = ModKey::createNXYZ(ModId::FilLFO, id); sourceDepthKey = ModKey::createNXYZ(ModId::FilLFODepth, id); - targetKey = ModKey::createNXYZ(ModId::FilCutoff, id); + targetKey = ModKey::createNXYZ(ModId::FilCutoff, id, 0); lfo.freqKey = ModKey::createNXYZ(ModId::FilLFOFrequency, id); depthSpec = Default::filLFODepth; depthModSpec = Default::filterCutoffMod; @@ -1076,7 +1076,7 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, EGDescription& eg) case hash("fileg_depth"): getOrCreateConnection( ModKey::createNXYZ(ModId::FilEG, id), - ModKey::createNXYZ(ModId::FilCutoff, id)).sourceDepth = opcode.read(Default::egDepth); + ModKey::createNXYZ(ModId::FilCutoff, id, 0)).sourceDepth = opcode.read(Default::egDepth); break; case hash("pitcheg_veltodepth"): // also pitcheg_vel2depth @@ -1087,7 +1087,7 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, EGDescription& eg) case hash("fileg_veltodepth"): // also fileg_vel2depth getOrCreateConnection( ModKey::createNXYZ(ModId::FilEG, id), - ModKey::createNXYZ(ModId::FilCutoff, id)).velToDepth = opcode.read(Default::egVel2Depth); + ModKey::createNXYZ(ModId::FilCutoff, id, 0)).velToDepth = opcode.read(Default::egVel2Depth); break; case_any_ccN("pitcheg_depth"): @@ -1099,7 +1099,7 @@ bool sfz::Region::parseEGOpcode(const Opcode& opcode, EGDescription& eg) case_any_ccN("fileg_depth"): getOrCreateConnection( ModKey::createNXYZ(ModId::FilEG, id), - ModKey::createNXYZ(ModId::FilCutoff, id)).sourceDepthMod = ModKey::createNXYZ(ModId::FilEGDepth, id); + ModKey::createNXYZ(ModId::FilCutoff, id, 0)).sourceDepthMod = ModKey::createNXYZ(ModId::FilEGDepth, id); processGenericCc(opcode, Default::filterCutoffMod, ModKey::createNXYZ(ModId::FilEGDepth, id)); break; @@ -1161,15 +1161,30 @@ bool sfz::Region::parseLFOOpcodeV2(const Opcode& opcode) return nullptr; return &lfo.sub[subNumber1Based - 1]; }; - auto LFO_EG_filter_EQ_target = [this, &opcode, lfoNumber](ModId sourceId, ModId targetId, const OpcodeSpec& spec) -> bool { - const unsigned index = opcode.parameters.size() == 2 ? opcode.parameters.back() - 1 : 0; - if (!extendIfNecessary(filters, index + 1, Default::numFilters)) - return false; - const ModKey source = ModKey::createNXYZ(sourceId, id, lfoNumber); - const ModKey target = ModKey::createNXYZ(targetId, id, index); + auto LFO_target = [this, &opcode, lfoNumber](const ModKey& target, const OpcodeSpec& spec) -> bool { + const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber); getOrCreateConnection(source, target).sourceDepth = opcode.read(spec); return true; }; + auto LFO_target_cc = [this, &opcode, lfoNumber](const ModKey& target, const OpcodeSpec& spec) -> bool { + const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber); + const ModKey depth = ModKey::getSourceDepthKey(source, target); + ASSERT(depth); + Connection& conn = getOrCreateConnection(source, target); + conn.sourceDepthMod = depth; + processGenericCc(opcode, spec, depth); + return true; + }; + auto ensureFilter = [this, &opcode]() { + ASSERT(opcode.parameters.size() >= 2); + const unsigned index = opcode.parameters[1] - 1; + return extendIfNecessary(filters, index + 1, Default::numFilters); + }; + auto ensureEQ = [this, &opcode]() { + ASSERT(opcode.parameters.size() >= 2); + const unsigned index = opcode.parameters[1] - 1; + return extendIfNecessary(equalizers, index + 1, Default::numEQs); + }; // switch (opcode.lettersOnlyHash) { @@ -1252,71 +1267,100 @@ bool sfz::Region::parseLFOOpcodeV2(const Opcode& opcode) // Modulation: LFO (targets) case hash("lfo&_amplitude"): - { - const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber); - const ModKey target = ModKey::createNXYZ(ModId::Amplitude, id); - getOrCreateConnection(source, target).sourceDepth = - opcode.read(Default::amplitudeMod); - } + LFO_target(ModKey::createNXYZ(ModId::Amplitude, id), Default::amplitudeMod); + break; + case_any_ccN("lfo&_amplitude"): + LFO_target_cc(ModKey::createNXYZ(ModId::Amplitude, id), Default::amplitudeMod); break; case hash("lfo&_pan"): - { - const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber); - const ModKey target = ModKey::createNXYZ(ModId::Pan, id); - getOrCreateConnection(source, target).sourceDepth = - opcode.read(Default::panMod); - } + LFO_target(ModKey::createNXYZ(ModId::Pan, id), Default::panMod); + break; + case_any_ccN("lfo&_pan"): + LFO_target_cc(ModKey::createNXYZ(ModId::Pan, id), Default::panMod); break; case hash("lfo&_width"): - { - const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber); - const ModKey target = ModKey::createNXYZ(ModId::Width, id); - getOrCreateConnection(source, target).sourceDepth = - opcode.read(Default::widthMod); - } + LFO_target(ModKey::createNXYZ(ModId::Width, id), Default::widthMod); + break; + case_any_ccN("lfo&_width"): + LFO_target_cc(ModKey::createNXYZ(ModId::Width, id), Default::widthMod); break; case hash("lfo&_position"): // sfizz extension - { - const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber); - const ModKey target = ModKey::createNXYZ(ModId::Position, id); - getOrCreateConnection(source, target).sourceDepth = - opcode.read(Default::positionMod); - } + LFO_target(ModKey::createNXYZ(ModId::Position, id), Default::positionMod); + break; + case_any_ccN("lfo&_position"): // sfizz extension + LFO_target_cc(ModKey::createNXYZ(ModId::Position, id), Default::positionMod); break; case hash("lfo&_pitch"): - { - const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber); - const ModKey target = ModKey::createNXYZ(ModId::Pitch, id); - getOrCreateConnection(source, target).sourceDepth = - opcode.read(Default::pitchMod); - } + LFO_target(ModKey::createNXYZ(ModId::Pitch, id), Default::pitchMod); + break; + case_any_ccN("lfo&_pitch"): + LFO_target_cc(ModKey::createNXYZ(ModId::Pitch, id), Default::pitchMod); break; case hash("lfo&_volume"): - { - const ModKey source = ModKey::createNXYZ(ModId::LFO, id, lfoNumber); - const ModKey target = ModKey::createNXYZ(ModId::Volume, id); - getOrCreateConnection(source, target).sourceDepth = - opcode.read(Default::volumeMod); - } + LFO_target(ModKey::createNXYZ(ModId::Volume, id), Default::volumeMod); + break; + case_any_ccN("lfo&_volume"): + LFO_target_cc(ModKey::createNXYZ(ModId::Volume, id), Default::volumeMod); break; - case hash("lfo&_cutoff&"): - LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilCutoff, Default::filterCutoffMod); + if (!ensureFilter()) + return false; + LFO_target(ModKey::createNXYZ(ModId::FilCutoff, id, opcode.parameters[1] - 1), Default::filterCutoffMod); + break; + case_any_ccN("lfo&_cutoff&"): + if (!ensureFilter()) + return false; + LFO_target_cc(ModKey::createNXYZ(ModId::FilCutoff, id, opcode.parameters[1] - 1), Default::filterCutoffMod); break; case hash("lfo&_resonance&"): - LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilResonance, Default::filterResonanceMod); + if (!ensureFilter()) + return false; + LFO_target(ModKey::createNXYZ(ModId::FilResonance, id, opcode.parameters[1] - 1), Default::filterResonanceMod); + break; + case_any_ccN("lfo&_resonance&"): + if (!ensureFilter()) + return false; + LFO_target_cc(ModKey::createNXYZ(ModId::FilResonance, id, opcode.parameters[1] - 1), Default::filterResonanceMod); break; case hash("lfo&_fil&gain"): - LFO_EG_filter_EQ_target(ModId::LFO, ModId::FilGain, Default::filterGainMod); + if (!ensureFilter()) + return false; + LFO_target(ModKey::createNXYZ(ModId::FilGain, id, opcode.parameters[1] - 1), Default::filterGainMod); + break; + case_any_ccN("lfo&_fil&gain"): + if (!ensureFilter()) + return false; + LFO_target_cc(ModKey::createNXYZ(ModId::FilGain, id, opcode.parameters[1] - 1), Default::filterGainMod); break; case hash("lfo&_eq&gain"): - LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqGain, Default::eqGainMod); + if (!ensureEQ()) + return false; + LFO_target(ModKey::createNXYZ(ModId::EqGain, id, opcode.parameters[1] - 1), Default::eqGainMod); + break; + case_any_ccN("lfo&_eq&gain"): + if (!ensureEQ()) + return false; + LFO_target_cc(ModKey::createNXYZ(ModId::EqGain, id, opcode.parameters[1] - 1), Default::eqGainMod); break; case hash("lfo&_eq&freq"): - LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqFrequency, Default::eqFrequencyMod); + if (!ensureEQ()) + return false; + LFO_target(ModKey::createNXYZ(ModId::EqFrequency, id, opcode.parameters[1] - 1), Default::eqFrequencyMod); + break; + case_any_ccN("lfo&_eq&freq"): + if (!ensureEQ()) + return false; + LFO_target_cc(ModKey::createNXYZ(ModId::EqFrequency, id, opcode.parameters[1] - 1), Default::eqFrequencyMod); break; case hash("lfo&_eq&bw"): - LFO_EG_filter_EQ_target(ModId::LFO, ModId::EqBandwidth, Default::eqBandwidthMod); + if (!ensureEQ()) + return false; + LFO_target(ModKey::createNXYZ(ModId::EqBandwidth, id, opcode.parameters[1] - 1), Default::eqBandwidthMod); + break; + case_any_ccN("lfo&_eq&bw"): + if (!ensureEQ()) + return false; + LFO_target_cc(ModKey::createNXYZ(ModId::EqBandwidth, id, opcode.parameters[1] - 1), Default::eqBandwidthMod); break; default: @@ -1344,15 +1388,30 @@ bool sfz::Region::parseEGOpcodeV2(const Opcode& opcode) return nullptr; return &eg.points[pointNumber]; }; - auto LFO_EG_filter_EQ_target = [this, &opcode, egNumber](ModId sourceId, ModId targetId, const OpcodeSpec& spec) -> bool { - const unsigned index = opcode.parameters.size() == 2 ? opcode.parameters.back() - 1 : 0; - if (!extendIfNecessary(filters, index + 1, Default::numFilters)) - return false; - const ModKey source = ModKey::createNXYZ(sourceId, id, egNumber); - const ModKey target = ModKey::createNXYZ(targetId, id, index); + auto EG_target = [this, &opcode, egNumber](const ModKey& target, const OpcodeSpec& spec) -> bool { + const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber); getOrCreateConnection(source, target).sourceDepth = opcode.read(spec); return true; }; + auto EG_target_cc = [this, &opcode, egNumber](const ModKey& target, const OpcodeSpec& spec) -> bool { + const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber); + const ModKey depth = ModKey::getSourceDepthKey(source, target); + ASSERT(depth); + Connection& conn = getOrCreateConnection(source, target); + conn.sourceDepthMod = depth; + processGenericCc(opcode, spec, depth); + return true; + }; + auto ensureFilter = [this, &opcode]() { + ASSERT(opcode.parameters.size() >= 2); + const unsigned index = opcode.parameters[1] - 1; + return extendIfNecessary(filters, index + 1, Default::numFilters); + }; + auto ensureEQ = [this, &opcode]() { + ASSERT(opcode.parameters.size() >= 2); + const unsigned index = opcode.parameters[1] - 1; + return extendIfNecessary(equalizers, index + 1, Default::numEQs); + }; // switch (opcode.lettersOnlyHash) { @@ -1385,70 +1444,100 @@ bool sfz::Region::parseEGOpcodeV2(const Opcode& opcode) // Modulation: Flex EG (targets) case hash("eg&_amplitude"): - { - const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber); - const ModKey target = ModKey::createNXYZ(ModId::Amplitude, id); - getOrCreateConnection(source, target).sourceDepth = - opcode.read(Default::amplitudeMod); - } + EG_target(ModKey::createNXYZ(ModId::Amplitude, id), Default::amplitudeMod); + break; + case_any_ccN("eg&_amplitude"): + EG_target_cc(ModKey::createNXYZ(ModId::Amplitude, id), Default::amplitudeMod); break; case hash("eg&_pan"): - { - const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber); - const ModKey target = ModKey::createNXYZ(ModId::Pan, id); - getOrCreateConnection(source, target).sourceDepth = - opcode.read(Default::panMod); - } + EG_target(ModKey::createNXYZ(ModId::Pan, id), Default::panMod); + break; + case_any_ccN("eg&_pan"): + EG_target_cc(ModKey::createNXYZ(ModId::Pan, id), Default::panMod); break; case hash("eg&_width"): - { - const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber); - const ModKey target = ModKey::createNXYZ(ModId::Width, id); - getOrCreateConnection(source, target).sourceDepth = - opcode.read(Default::widthMod); - } + EG_target(ModKey::createNXYZ(ModId::Width, id), Default::widthMod); + break; + case_any_ccN("eg&_width"): + EG_target_cc(ModKey::createNXYZ(ModId::Width, id), Default::widthMod); break; case hash("eg&_position"): // sfizz extension - { - const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber); - const ModKey target = ModKey::createNXYZ(ModId::Position, id); - getOrCreateConnection(source, target).sourceDepth = - opcode.read(Default::positionMod); - } + EG_target(ModKey::createNXYZ(ModId::Position, id), Default::positionMod); + break; + case_any_ccN("eg&_position"): // sfizz extension + EG_target_cc(ModKey::createNXYZ(ModId::Position, id), Default::positionMod); break; case hash("eg&_pitch"): - { - const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber); - const ModKey target = ModKey::createNXYZ(ModId::Pitch, id); - getOrCreateConnection(source, target).sourceDepth = - opcode.read(Default::pitchMod); - } + EG_target(ModKey::createNXYZ(ModId::Pitch, id), Default::pitchMod); + break; + case_any_ccN("eg&_pitch"): + EG_target_cc(ModKey::createNXYZ(ModId::Pitch, id), Default::pitchMod); break; case hash("eg&_volume"): - { - const ModKey source = ModKey::createNXYZ(ModId::Envelope, id, egNumber); - const ModKey target = ModKey::createNXYZ(ModId::Volume, id); - getOrCreateConnection(source, target).sourceDepth = - opcode.read(Default::volumeMod); - } + EG_target(ModKey::createNXYZ(ModId::Volume, id), Default::volumeMod); + break; + case_any_ccN("eg&_volume"): + EG_target_cc(ModKey::createNXYZ(ModId::Volume, id), Default::volumeMod); break; case hash("eg&_cutoff&"): - LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilCutoff, Default::filterCutoffMod); + if (!ensureFilter()) + return false; + EG_target(ModKey::createNXYZ(ModId::FilCutoff, id, opcode.parameters[1] - 1), Default::filterCutoffMod); + break; + case_any_ccN("eg&_cutoff&"): + if (!ensureFilter()) + return false; + EG_target_cc(ModKey::createNXYZ(ModId::FilCutoff, id, opcode.parameters[1] - 1), Default::filterCutoffMod); break; case hash("eg&_resonance&"): - LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilResonance, Default::filterResonanceMod); + if (!ensureFilter()) + return false; + EG_target(ModKey::createNXYZ(ModId::FilResonance, id, opcode.parameters[1] - 1), Default::filterResonanceMod); + break; + case_any_ccN("eg&_resonance&"): + if (!ensureFilter()) + return false; + EG_target_cc(ModKey::createNXYZ(ModId::FilResonance, id, opcode.parameters[1] - 1), Default::filterResonanceMod); break; case hash("eg&_fil&gain"): - LFO_EG_filter_EQ_target(ModId::Envelope, ModId::FilGain, Default::filterGainMod); + if (!ensureFilter()) + return false; + EG_target(ModKey::createNXYZ(ModId::FilGain, id, opcode.parameters[1] - 1), Default::filterGainMod); + break; + case_any_ccN("eg&_fil&gain"): + if (!ensureFilter()) + return false; + EG_target_cc(ModKey::createNXYZ(ModId::FilGain, id, opcode.parameters[1] - 1), Default::filterGainMod); break; case hash("eg&_eq&gain"): - LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqGain, Default::eqGainMod); + if (!ensureEQ()) + return false; + EG_target(ModKey::createNXYZ(ModId::EqGain, id, opcode.parameters[1] - 1), Default::eqGainMod); + break; + case_any_ccN("eg&_eq&gain"): + if (!ensureEQ()) + return false; + EG_target_cc(ModKey::createNXYZ(ModId::EqGain, id, opcode.parameters[1] - 1), Default::eqGainMod); break; case hash("eg&_eq&freq"): - LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqFrequency, Default::eqFrequencyMod); + if (!ensureEQ()) + return false; + EG_target(ModKey::createNXYZ(ModId::EqFrequency, id, opcode.parameters[1] - 1), Default::eqFrequencyMod); + break; + case_any_ccN("eg&_eq&freq"): + if (!ensureEQ()) + return false; + EG_target_cc(ModKey::createNXYZ(ModId::EqFrequency, id, opcode.parameters[1] - 1), Default::eqFrequencyMod); break; case hash("eg&_eq&bw"): - LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqBandwidth, Default::eqBandwidthMod); + if (!ensureEQ()) + return false; + EG_target(ModKey::createNXYZ(ModId::EqBandwidth, id, opcode.parameters[1] - 1), Default::eqBandwidthMod); + break; + case_any_ccN("eg&_eq&bw"): + if (!ensureEQ()) + return false; + EG_target_cc(ModKey::createNXYZ(ModId::EqBandwidth, id, opcode.parameters[1] - 1), Default::eqBandwidthMod); break; case hash("eg&_ampeg"): diff --git a/src/sfizz/modulations/ModId.cpp b/src/sfizz/modulations/ModId.cpp index dcc70a44..2d57a69b 100644 --- a/src/sfizz/modulations/ModId.cpp +++ b/src/sfizz/modulations/ModId.cpp @@ -100,6 +100,54 @@ int ModIds::flags(ModId id) noexcept return kModIsPerVoice|kModIsAdditive; case ModId::LFOPhase: return kModIsPerVoice|kModIsAdditive; + case ModId::LFOAmplitudeDepth: + return kModIsPerVoice|kModIsMultiplicative; + case ModId::LFOPanDepth: + return kModIsPerVoice|kModIsAdditive; + case ModId::LFOWidthDepth: + return kModIsPerVoice|kModIsAdditive; + case ModId::LFOPositionDepth: + return kModIsPerVoice|kModIsAdditive; + case ModId::LFOPitchDepth: + return kModIsPerVoice|kModIsAdditive; + case ModId::LFOVolumeDepth: + return kModIsPerVoice|kModIsAdditive; + case ModId::LFOFilCutoffDepth: + return kModIsPerVoice|kModIsAdditive; + case ModId::LFOFilResonanceDepth: + return kModIsPerVoice|kModIsAdditive; + case ModId::LFOFilGainDepth: + return kModIsPerVoice|kModIsAdditive; + case ModId::LFOEqGainDepth: + return kModIsPerVoice|kModIsAdditive; + case ModId::LFOEqFrequencyDepth: + return kModIsPerVoice|kModIsAdditive; + case ModId::LFOEqBandwidthDepth: + return kModIsPerVoice|kModIsAdditive; + case ModId::EGAmplitudeDepth: + return kModIsPerVoice|kModIsMultiplicative; + case ModId::EGPanDepth: + return kModIsPerVoice|kModIsAdditive; + case ModId::EGWidthDepth: + return kModIsPerVoice|kModIsAdditive; + case ModId::EGPositionDepth: + return kModIsPerVoice|kModIsAdditive; + case ModId::EGPitchDepth: + return kModIsPerVoice|kModIsAdditive; + case ModId::EGVolumeDepth: + return kModIsPerVoice|kModIsAdditive; + case ModId::EGFilCutoffDepth: + return kModIsPerVoice|kModIsAdditive; + case ModId::EGFilResonanceDepth: + return kModIsPerVoice|kModIsAdditive; + case ModId::EGFilGainDepth: + return kModIsPerVoice|kModIsAdditive; + case ModId::EGEqGainDepth: + return kModIsPerVoice|kModIsAdditive; + case ModId::EGEqFrequencyDepth: + return kModIsPerVoice|kModIsAdditive; + case ModId::EGEqBandwidthDepth: + return kModIsPerVoice|kModIsAdditive; // unknown default: diff --git a/src/sfizz/modulations/ModId.h b/src/sfizz/modulations/ModId.h index 1e18356f..b6a3e130 100644 --- a/src/sfizz/modulations/ModId.h +++ b/src/sfizz/modulations/ModId.h @@ -64,6 +64,30 @@ enum class ModId : int { LFOFrequency, LFOBeats, LFOPhase, + LFOAmplitudeDepth, + LFOPanDepth, + LFOWidthDepth, + LFOPositionDepth, + LFOPitchDepth, + LFOVolumeDepth, + LFOFilCutoffDepth, + LFOFilResonanceDepth, + LFOFilGainDepth, + LFOEqGainDepth, + LFOEqFrequencyDepth, + LFOEqBandwidthDepth, + EGAmplitudeDepth, + EGPanDepth, + EGWidthDepth, + EGPositionDepth, + EGPitchDepth, + EGVolumeDepth, + EGFilCutoffDepth, + EGFilResonanceDepth, + EGFilGainDepth, + EGEqGainDepth, + EGEqFrequencyDepth, + EGEqBandwidthDepth, _TargetsEnd, // [/targets] -------------------------------------------------------------- diff --git a/src/sfizz/modulations/ModKey.cpp b/src/sfizz/modulations/ModKey.cpp index 3fef944f..107b0b34 100644 --- a/src/sfizz/modulations/ModKey.cpp +++ b/src/sfizz/modulations/ModKey.cpp @@ -170,11 +170,179 @@ std::string ModKey::toString() const return absl::StrCat("LFOBeats {", region_.number(), ", N=", 1 + params_.N, "}"); case ModId::LFOPhase: return absl::StrCat("LFOPhase {", region_.number(), ", N=", 1 + params_.N, "}"); + case ModId::LFOAmplitudeDepth: + return absl::StrCat("LFOAmplitudeDepth {", region_.number(), ", N=", 1 + params_.N, "}"); + case ModId::LFOPanDepth: + return absl::StrCat("LFOPanDepth {", region_.number(), ", N=", 1 + params_.N, "}"); + case ModId::LFOWidthDepth: + return absl::StrCat("LFOWidthDepth {", region_.number(), ", N=", 1 + params_.N, "}"); + case ModId::LFOPositionDepth: + return absl::StrCat("LFOPositionDepth {", region_.number(), ", N=", 1 + params_.N, "}"); + case ModId::LFOPitchDepth: + return absl::StrCat("LFOPitchDepth {", region_.number(), ", N=", 1 + params_.N, "}"); + case ModId::LFOVolumeDepth: + return absl::StrCat("LFOVolumeDepth {", region_.number(), ", N=", 1 + params_.N, "}"); + case ModId::LFOFilCutoffDepth: + return absl::StrCat("LFOFilCutoffDepth {", region_.number(), ", N=", 1 + params_.N, ", X=", 1 + params_.X, "}"); + case ModId::LFOFilResonanceDepth: + return absl::StrCat("LFOFilResonanceDepth {", region_.number(), ", N=", 1 + params_.N, ", X=", 1 + params_.X, "}"); + case ModId::LFOFilGainDepth: + return absl::StrCat("LFOFilGainDepth {", region_.number(), ", N=", 1 + params_.N, ", X=", 1 + params_.X, "}"); + case ModId::LFOEqGainDepth: + return absl::StrCat("LFOEqGainDepth {", region_.number(), ", N=", 1 + params_.N, ", X=", 1 + params_.X, "}"); + case ModId::LFOEqFrequencyDepth: + return absl::StrCat("LFOEqFrequencyDepth {", region_.number(), ", N=", 1 + params_.N, ", X=", 1 + params_.X, "}"); + case ModId::LFOEqBandwidthDepth: + return absl::StrCat("LFOEqBandwidthDepth {", region_.number(), ", N=", 1 + params_.N, ", X=", 1 + params_.X, "}"); + case ModId::EGAmplitudeDepth: + return absl::StrCat("EGAmplitudeDepth {", region_.number(), ", N=", 1 + params_.N, "}"); + case ModId::EGPanDepth: + return absl::StrCat("EGPanDepth {", region_.number(), ", N=", 1 + params_.N, "}"); + case ModId::EGWidthDepth: + return absl::StrCat("EGWidthDepth {", region_.number(), ", N=", 1 + params_.N, "}"); + case ModId::EGPositionDepth: + return absl::StrCat("EGPositionDepth {", region_.number(), ", N=", 1 + params_.N, "}"); + case ModId::EGPitchDepth: + return absl::StrCat("EGPitchDepth {", region_.number(), ", N=", 1 + params_.N, "}"); + case ModId::EGVolumeDepth: + return absl::StrCat("EGVolumeDepth {", region_.number(), ", N=", 1 + params_.N, "}"); + case ModId::EGFilCutoffDepth: + return absl::StrCat("EGFilCutoffDepth {", region_.number(), ", N=", 1 + params_.N, ", X=", 1 + params_.X, "}"); + case ModId::EGFilResonanceDepth: + return absl::StrCat("EGFilResonanceDepth {", region_.number(), ", N=", 1 + params_.N, ", X=", 1 + params_.X, "}"); + case ModId::EGFilGainDepth: + return absl::StrCat("EGFilGainDepth {", region_.number(), ", N=", 1 + params_.N, ", X=", 1 + params_.X, "}"); + case ModId::EGEqGainDepth: + return absl::StrCat("EGEqGainDepth {", region_.number(), ", N=", 1 + params_.N, ", X=", 1 + params_.X, "}"); + case ModId::EGEqFrequencyDepth: + return absl::StrCat("EGEqFrequencyDepth {", region_.number(), ", N=", 1 + params_.N, ", X=", 1 + params_.X, "}"); + case ModId::EGEqBandwidthDepth: + return absl::StrCat("EGEqBandwidthDepth {", region_.number(), ", N=", 1 + params_.N, ", X=", 1 + params_.X, "}"); default: return {}; } } +ModKey ModKey::getSourceDepthKey(ModKey source, ModKey target) +{ + const NumericId region = source.region(); + const ModKey::Parameters& tp = target.parameters(); + + switch (source.id()) { + case ModId::AmpLFO: + switch (target.id()) { + case ModId::Volume: + return ModKey::createNXYZ(ModId::AmpLFODepth, region); + default: + break; + } + break; + + case ModId::PitchLFO: + switch (target.id()) { + case ModId::Pitch: + return ModKey::createNXYZ(ModId::PitchLFODepth, region); + default: + break; + } + break; + + case ModId::FilLFO: + switch (target.id()) { + case ModId::FilCutoff: + return ModKey::createNXYZ(ModId::FilLFODepth, region); + default: + break; + } + break; + + case ModId::PitchEG: + switch (target.id()) { + case ModId::Pitch: + return ModKey::createNXYZ(ModId::PitchEGDepth, region); + default: + break; + } + break; + + case ModId::FilEG: + switch (target.id()) { + case ModId::FilCutoff: + return ModKey::createNXYZ(ModId::FilEGDepth, region); + default: + break; + } + break; + + case ModId::LFO: + switch (target.id()) { + case ModId::Amplitude: + return ModKey::createNXYZ(ModId::LFOAmplitudeDepth, region, tp.N); + case ModId::Pan: + return ModKey::createNXYZ(ModId::LFOPanDepth, region, tp.N); + case ModId::Width: + return ModKey::createNXYZ(ModId::LFOWidthDepth, region, tp.N); + case ModId::Position: + return ModKey::createNXYZ(ModId::LFOPositionDepth, region, tp.N); + case ModId::Pitch: + return ModKey::createNXYZ(ModId::LFOPitchDepth, region, tp.N); + case ModId::Volume: + return ModKey::createNXYZ(ModId::LFOVolumeDepth, region, tp.N); + case ModId::FilCutoff: + return ModKey::createNXYZ(ModId::LFOFilCutoffDepth, region, tp.N, tp.X); + case ModId::FilResonance: + return ModKey::createNXYZ(ModId::LFOFilResonanceDepth, region, tp.N, tp.X); + case ModId::FilGain: + return ModKey::createNXYZ(ModId::LFOFilGainDepth, region, tp.N, tp.X); + case ModId::EqGain: + return ModKey::createNXYZ(ModId::LFOEqGainDepth, region, tp.N, tp.X); + case ModId::EqFrequency: + return ModKey::createNXYZ(ModId::LFOEqFrequencyDepth, region, tp.N, tp.X); + case ModId::EqBandwidth: + return ModKey::createNXYZ(ModId::LFOEqBandwidthDepth, region, tp.N, tp.X); + default: + break; + } + break; + + case ModId::Envelope: + switch (target.id()) { + case ModId::Amplitude: + return ModKey::createNXYZ(ModId::EGAmplitudeDepth, region, tp.N); + case ModId::Pan: + return ModKey::createNXYZ(ModId::EGPanDepth, region, tp.N); + case ModId::Width: + return ModKey::createNXYZ(ModId::EGWidthDepth, region, tp.N); + case ModId::Position: + return ModKey::createNXYZ(ModId::EGPositionDepth, region, tp.N); + case ModId::Pitch: + return ModKey::createNXYZ(ModId::EGPitchDepth, region, tp.N); + case ModId::Volume: + return ModKey::createNXYZ(ModId::EGVolumeDepth, region, tp.N); + case ModId::FilCutoff: + return ModKey::createNXYZ(ModId::EGFilCutoffDepth, region, tp.N, tp.X); + case ModId::FilResonance: + return ModKey::createNXYZ(ModId::EGFilResonanceDepth, region, tp.N, tp.X); + case ModId::FilGain: + return ModKey::createNXYZ(ModId::EGFilGainDepth, region, tp.N, tp.X); + case ModId::EqGain: + return ModKey::createNXYZ(ModId::EGEqGainDepth, region, tp.N, tp.X); + case ModId::EqFrequency: + return ModKey::createNXYZ(ModId::EGEqFrequencyDepth, region, tp.N, tp.X); + case ModId::EqBandwidth: + return ModKey::createNXYZ(ModId::EGEqBandwidthDepth, region, tp.N, tp.X); + default: + break; + } + break; + + default: + break; + } + + return {}; +} + } // namespace sfz diff --git a/src/sfizz/modulations/ModKey.h b/src/sfizz/modulations/ModKey.h index 69dc50b3..92f11ca4 100644 --- a/src/sfizz/modulations/ModKey.h +++ b/src/sfizz/modulations/ModKey.h @@ -42,6 +42,12 @@ public: bool isTarget() const noexcept; std::string toString() const; + /** + * @brief Obtain the modulation key of the source depth, in the connection + * between source and target, if such a key exists. + */ + static ModKey getSourceDepthKey(ModKey source, ModKey target); + struct RawParameters { union { //! Parameters if this key identifies a CC source diff --git a/src/sfizz/modulations/ModMatrix.cpp b/src/sfizz/modulations/ModMatrix.cpp index 3d780ef4..7c64244f 100644 --- a/src/sfizz/modulations/ModMatrix.cpp +++ b/src/sfizz/modulations/ModMatrix.cpp @@ -423,7 +423,12 @@ float* ModMatrix::getModulation(TargetId targetId) for (uint32_t i = 0; i < numFrames; ++i) buffer[i] = sourceDepth * sourceBuffer[i]; } + else if (targetFlags & kModIsMultiplicative) { + for (uint32_t i = 0; i < numFrames; ++i) + buffer[i] = (sourceDepth * sourceDepthMod[i]) * sourceBuffer[i]; + } else { + ASSERT(targetFlags & kModIsAdditive); for (uint32_t i = 0; i < numFrames; ++i) buffer[i] = (sourceDepth + sourceDepthMod[i]) * sourceBuffer[i]; } @@ -435,7 +440,7 @@ float* ModMatrix::getModulation(TargetId targetId) multiplyMul1(sourceDepth, sourceBuffer, buffer); else { for (uint32_t i = 0; i < numFrames; ++i) - buffer[i] *= (sourceDepth + sourceDepthMod[i]) * sourceBuffer[i]; + buffer[i] *= (sourceDepth * sourceDepthMod[i]) * sourceBuffer[i]; } } else {