diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index a16c91a5..7d69d202 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -1251,8 +1251,22 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) ModKey::createNXYZ(ModId::FilCutoff, id)).sourceDepth = *value; break; - // TODO(jpc): pitcheg_vel2depth - // TODO(jpc): fileg_vel2depth + case hash("pitcheg_vel&depth"): + if (opcode.parameters.front() != 2) + return false; // Was not vel2... + if (auto value = readOpcode(opcode.value, Default::pitchEgDepthRange)) + getOrCreateConnection( + ModKey::createNXYZ(ModId::PitchEG, id), + ModKey::createNXYZ(ModId::Pitch, id)).velToDepth = *value; + break; + case hash("fileg_vel&depth"): + if (opcode.parameters.front() != 2) + return false; // Was not vel2... + if (auto value = readOpcode(opcode.value, Default::filterEgDepthRange)) + getOrCreateConnection( + ModKey::createNXYZ(ModId::FilEG, id), + ModKey::createNXYZ(ModId::FilCutoff, id)).velToDepth = *value; + break; // Flex envelopes case hash("eg&_dynamic"): diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index ca55827f..fabe91c4 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -442,6 +442,7 @@ struct Region { ModKey source; ModKey target; float sourceDepth = 0.0f; + float velToDepth = 0.0f; }; std::vector connections; Connection& getOrCreateConnection(const ModKey& source, const ModKey& target); diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 7f6b6d10..b191d841 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -820,7 +820,7 @@ void sfz::Synth::renderBlock(AudioSpan buffer) noexcept if (voice->isFree()) continue; - mm.beginVoice(voice->getId(), voice->getRegion()->getId()); + mm.beginVoice(voice->getId(), voice->getRegion()->getId(), voice->getTriggerEvent().value); activeVoices++; renderVoiceToOutputs(*voice, *tempSpan); @@ -1558,7 +1558,7 @@ void sfz::Synth::setupModMatrix() continue; } - if (!mm.connect(source, target, conn.sourceDepth)) { + if (!mm.connect(source, target, conn.sourceDepth, conn.velToDepth)) { DBG("[sfizz] Failed to connect modulation source and target"); ASSERTFALSE; } diff --git a/src/sfizz/modulations/ModMatrix.cpp b/src/sfizz/modulations/ModMatrix.cpp index d7ddc444..ffba3f6a 100644 --- a/src/sfizz/modulations/ModMatrix.cpp +++ b/src/sfizz/modulations/ModMatrix.cpp @@ -27,6 +27,8 @@ struct ModMatrix::Impl { NumericId currentVoiceId_ {}; NumericId currentRegionId_ {}; + float currentVoiceTriggerValue_ {}; + struct Source { ModKey key; ModGenerator* gen {}; @@ -36,6 +38,7 @@ struct ModMatrix::Impl { struct ConnectionData { float sourceDepth_ {}; + float velToDepth_ {}; }; struct Target { @@ -190,7 +193,7 @@ ModMatrix::TargetId ModMatrix::findTarget(const ModKey& key) const return TargetId(it->second); } -bool ModMatrix::connect(SourceId sourceId, TargetId targetId, float sourceDepth) +bool ModMatrix::connect(SourceId sourceId, TargetId targetId, float sourceDepth, float velToDepth) { Impl& impl = *impl_; unsigned sourceIndex = sourceId.number(); @@ -202,6 +205,7 @@ bool ModMatrix::connect(SourceId sourceId, TargetId targetId, float sourceDepth) Impl::Target& target = impl.targets_[targetIndex]; Impl::ConnectionData& conn = target.connectedSources[sourceIndex]; conn.sourceDepth_ = sourceDepth; + conn.velToDepth_ = velToDepth; return true; } @@ -302,13 +306,15 @@ void ModMatrix::endCycle() impl.numFrames_ = 0; } -void ModMatrix::beginVoice(NumericId voiceId, NumericId regionId) +void ModMatrix::beginVoice(NumericId voiceId, NumericId regionId, float triggerValue) { Impl& impl = *impl_; impl.currentVoiceId_ = voiceId; impl.currentRegionId_ = regionId; + impl.currentVoiceTriggerValue_ = triggerValue; + ASSERT(regionId); const auto idNumber = static_cast(regionId.number()); @@ -345,6 +351,8 @@ void ModMatrix::endVoice() impl.currentVoiceId_ = {}; impl.currentRegionId_ = {}; + + impl.currentVoiceTriggerValue_ = 0.0f; } float* ModMatrix::getModulation(TargetId targetId) @@ -354,6 +362,7 @@ float* ModMatrix::getModulation(TargetId targetId) Impl& impl = *impl_; const NumericId regionId = impl.currentRegionId_; + const float triggerValue = impl.currentVoiceTriggerValue_; const uint32_t targetIndex = targetId.number(); Impl::Target &target = impl.targets_[targetIndex]; const int targetFlags = target.key.flags(); @@ -381,7 +390,6 @@ float* ModMatrix::getModulation(TargetId targetId) // then add or multiply, depending on target flags while (sourcesPos != sourcesEnd) { Impl::Source &source = impl.sources_[sourcesPos->first]; - const float sourceDepth = sourcesPos->second.sourceDepth_; const int sourceFlags = source.key.flags(); // only accept per-voice sources of the same region @@ -398,6 +406,12 @@ float* ModMatrix::getModulation(TargetId targetId) source.bufferReady = true; } + float sourceDepth = sourcesPos->second.sourceDepth_; + if (sourceFlags & kModIsPerVoice) { + const float velToDepth = sourcesPos->second.velToDepth_; + sourceDepth += triggerValue * velToDepth; + } + if (isFirstSource) { if (sourceDepth != 1) { for (uint32_t i = 0; i < numFrames; ++i) diff --git a/src/sfizz/modulations/ModMatrix.h b/src/sfizz/modulations/ModMatrix.h index 0f0fb471..0a01dd5b 100644 --- a/src/sfizz/modulations/ModMatrix.h +++ b/src/sfizz/modulations/ModMatrix.h @@ -92,9 +92,10 @@ public: * @param sourceId source of the connection * @param targetId target of the connection * @param sourceDepth amount which multiplies the source output + * @param velToDepth amount which full velocity adds to the source depth * @return true if the connection was successfully made, otherwise false */ - bool connect(SourceId sourceId, TargetId targetId, float sourceDepth); + bool connect(SourceId sourceId, TargetId targetId, float sourceDepth, float velToDepth = 0.0f); /** * @brief Reinitialize modulation sources overall. @@ -134,8 +135,9 @@ public: * * @param voiceId the identifier of the current voice * @param regionId the identifier of the region of the current voice + * @param triggerValue the velocity of the current voice */ - void beginVoice(NumericId voiceId, NumericId regionId); + void beginVoice(NumericId voiceId, NumericId regionId, float triggerValue); /** * @brief End modulation processing for a given voice.