diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 56d7e6ce..1b644066 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -174,6 +174,8 @@ void sfz::Voice::release(int delay) noexcept } else { egEnvelope.startRelease(delay); } + + resources.modMatrix.releaseVoice(id, region->getId(), delay); } void sfz::Voice::off(int delay) noexcept diff --git a/src/sfizz/modulations/ModGenerator.h b/src/sfizz/modulations/ModGenerator.h index 8c7a89e8..3d7aed12 100644 --- a/src/sfizz/modulations/ModGenerator.h +++ b/src/sfizz/modulations/ModGenerator.h @@ -40,6 +40,15 @@ public: */ virtual void init(const ModKey& sourceKey, NumericId voiceId, unsigned delay) = 0; + /** + * @brief Send the generator a release notification. + * + * @param sourceKey identifier of the source to release + * @param voiceId the particular voice to initialize, if per-voice + * @param delay the frame time when it happens + */ + virtual void release(const ModKey& sourceKey, NumericId voiceId, unsigned delay) { (void)sourceKey; (void)voiceId; (void)delay; } + /** * @brief Generate a cycle of the modulator * diff --git a/src/sfizz/modulations/ModMatrix.cpp b/src/sfizz/modulations/ModMatrix.cpp index 913f3095..9290ba2d 100644 --- a/src/sfizz/modulations/ModMatrix.cpp +++ b/src/sfizz/modulations/ModMatrix.cpp @@ -211,6 +211,17 @@ void ModMatrix::initVoice(NumericId voiceId, NumericId regionId, } } +void ModMatrix::releaseVoice(NumericId voiceId, NumericId regionId, unsigned delay) +{ + Impl& impl = *impl_; + + for (Impl::Source &source : impl.sources_) { + const int flags = source.key.flags(); + if ((flags & kModIsPerVoice) && source.key.region() == regionId) + source.gen->release(source.key, voiceId, delay); + } +} + void ModMatrix::beginCycle(unsigned numFrames) { Impl& impl = *impl_; diff --git a/src/sfizz/modulations/ModMatrix.h b/src/sfizz/modulations/ModMatrix.h index 21592360..211cf06f 100644 --- a/src/sfizz/modulations/ModMatrix.h +++ b/src/sfizz/modulations/ModMatrix.h @@ -108,6 +108,12 @@ public: */ void initVoice(NumericId voiceId, NumericId regionId, unsigned delay); + /** + * @brief Release modulation source for a given voice. + * This must be called when a voice enters released state. + */ + void releaseVoice(NumericId voiceId, NumericId regionId, unsigned delay); + /** * @brief Start modulation processing for the entire cycle. * This clears all the buffers.