From c30cad25340e58f499d4a268351ee4f9c2f26090 Mon Sep 17 00:00:00 2001 From: Jean Pierre Cimalando Date: Sat, 26 Sep 2020 15:54:41 +0200 Subject: [PATCH] Implement egN_ampeg --- src/sfizz/FlexEGDescription.h | 2 ++ src/sfizz/FlexEnvelope.cpp | 19 ++++++++++++++ src/sfizz/FlexEnvelope.h | 15 +++++++++++ src/sfizz/Region.cpp | 33 ++++++++++++++++++++--- src/sfizz/Region.h | 2 ++ src/sfizz/Synth.cpp | 18 +++++++++---- src/sfizz/Voice.cpp | 49 +++++++++++++++++++++++++++-------- 7 files changed, 119 insertions(+), 19 deletions(-) diff --git a/src/sfizz/FlexEGDescription.h b/src/sfizz/FlexEGDescription.h index fd8e9428..b8a0f59b 100644 --- a/src/sfizz/FlexEGDescription.h +++ b/src/sfizz/FlexEGDescription.h @@ -34,6 +34,8 @@ struct FlexEGDescription { int dynamic { Default::flexEGDynamic }; // whether parameters can be modulated while EG runs int sustain { Default::flexEGSustain }; // index of the sustain point (default to 0 in ARIA) std::vector points; + // ARIA + bool ampeg = false; // replaces the SFZv1 AmpEG (lowest with this bit wins) }; } // namespace sfz diff --git a/src/sfizz/FlexEnvelope.cpp b/src/sfizz/FlexEnvelope.cpp index c58d3ae5..c9302c0b 100644 --- a/src/sfizz/FlexEnvelope.cpp +++ b/src/sfizz/FlexEnvelope.cpp @@ -104,6 +104,25 @@ void FlexEnvelope::release(unsigned releaseDelay) impl.currentFramesUntilRelease_ = releaseDelay; } +unsigned FlexEnvelope::getRemainingDelay() const noexcept +{ + const Impl& impl = *impl_; + return static_cast(impl.delayFramesLeft_); +} + +bool FlexEnvelope::isReleased() const noexcept +{ + const Impl& impl = *impl_; + return impl.isReleased_; +} + +bool FlexEnvelope::isFinished() const noexcept +{ + const Impl& impl = *impl_; + const FlexEGDescription& desc = *impl.desc_; + return impl.currentStageNumber_ >= desc.points.size(); +} + void FlexEnvelope::process(absl::Span out) { Impl& impl = *impl_; diff --git a/src/sfizz/FlexEnvelope.h b/src/sfizz/FlexEnvelope.h index 3316e715..d1d01a4a 100644 --- a/src/sfizz/FlexEnvelope.h +++ b/src/sfizz/FlexEnvelope.h @@ -40,6 +40,21 @@ public: */ void release(unsigned releaseDelay); + /** + Get the remaining delay samples + */ + unsigned getRemainingDelay() const noexcept; + + /** + Is the envelope released? + */ + bool isReleased() const noexcept; + + /** + Is the envelope finished? + */ + bool isFinished() const noexcept; + /** Process a cycle of the generator. */ diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index c599bc66..b48ed7f3 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -1162,6 +1162,28 @@ bool sfz::Region::parseOpcode(const Opcode& rawOpcode) LFO_EG_filter_EQ_target(ModId::Envelope, ModId::EqBandwidth, Default::eqBandwidthModRange); break; + case hash("eg&_ampeg"): + { + const auto egNumber = opcode.parameters.front(); + if (egNumber == 0) + return false; + if (!extendIfNecessary(flexEGs, egNumber, Default::numFlexEGs)) + return false; + if (auto value = readOpcode(opcode.value, Range { 0, 1 })) { + FlexEGDescription& desc = flexEGs[egNumber - 1]; + bool ampeg = *value != 0; + if (desc.ampeg != ampeg) { + desc.ampeg = ampeg; + flexAmpEG = absl::nullopt; + for (size_t i = 0, n = flexEGs.size(); i < n && !flexAmpEG; ++i) { + if (flexEGs[i].ampeg) + flexAmpEG = static_cast(i); + } + } + } + break; + } + // Amplitude Envelope case hash("ampeg_attack"): case hash("ampeg_decay"): @@ -1907,7 +1929,7 @@ float sfz::Region::getBendInCents(float bend) const noexcept return bend > 0.0f ? bend * static_cast(bendUp) : -bend * static_cast(bendDown); } -sfz::Region::Connection& sfz::Region::getOrCreateConnection(const ModKey& source, const ModKey& target) +sfz::Region::Connection* sfz::Region::getConnection(const ModKey& source, const ModKey& target) { auto pred = [&source, &target](const Connection& c) { @@ -1915,8 +1937,13 @@ sfz::Region::Connection& sfz::Region::getOrCreateConnection(const ModKey& source }; auto it = std::find_if(connections.begin(), connections.end(), pred); - if (it != connections.end()) - return *it; + return (it == connections.end()) ? nullptr : &*it; +} + +sfz::Region::Connection& sfz::Region::getOrCreateConnection(const ModKey& source, const ModKey& target) +{ + if (Connection* c = getConnection(source, target)) + return *c; sfz::Region::Connection c; c.source = source; diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index 76840c53..62692437 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -425,6 +425,7 @@ struct Region { // Envelopes std::vector flexEGs; + absl::optional flexAmpEG; // egN_ampeg // LFOs std::vector lfos; @@ -445,6 +446,7 @@ struct Region { float velToDepth = 0.0f; }; std::vector connections; + Connection* getConnection(const ModKey& source, const ModKey& target); Connection& getOrCreateConnection(const ModKey& source, const ModKey& target); // Parent diff --git a/src/sfizz/Synth.cpp b/src/sfizz/Synth.cpp index 52b02c96..4e7a9f7d 100644 --- a/src/sfizz/Synth.cpp +++ b/src/sfizz/Synth.cpp @@ -159,11 +159,6 @@ void sfz::Synth::buildRegion(const std::vector& regionOpcodes) ModKey::createCC(10, 1, defaultSmoothness, 100, 0), ModKey::createNXYZ(ModId::Pan, lastRegion->id)).sourceDepth = 1.0f; - // Create the amplitude envelope - lastRegion->getOrCreateConnection( - ModKey::createNXYZ(ModId::AmpEG, lastRegion->id), - ModKey::createNXYZ(ModId::Amplitude, lastRegion->id)).sourceDepth = 100.0f; - // auto parseOpcodes = [&](const std::vector& opcodes) { for (auto& opcode : opcodes) { @@ -182,6 +177,19 @@ void sfz::Synth::buildRegion(const std::vector& regionOpcodes) parseOpcodes(groupOpcodes); parseOpcodes(regionOpcodes); + // Create the amplitude envelope + if (!lastRegion->flexAmpEG) { + lastRegion->getOrCreateConnection( + ModKey::createNXYZ(ModId::AmpEG, lastRegion->id), + ModKey::createNXYZ(ModId::Amplitude, lastRegion->id)).sourceDepth = 100.0f; + } + else { + ModKey source = ModKey::createNXYZ(ModId::Envelope, lastRegion->id, *lastRegion->flexAmpEG); + ModKey target = ModKey::createNXYZ(ModId::Amplitude, lastRegion->id); + if (!lastRegion->getConnection(source, target)) + lastRegion->getOrCreateConnection(source, target).sourceDepth = 100.0f; + } + if (octaveOffset != 0 || noteOffset != 0) lastRegion->offsetAllKeys(octaveOffset * 12 + noteOffset); diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 98ecf495..ebed105b 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -151,8 +151,13 @@ void sfz::Voice::release(int delay) noexcept if (state != State::playing) return; - if (egAmplitude.getRemainingDelay() > delay) { - switchState(State::cleanMeUp); + if (!region->flexAmpEG) { + if (egAmplitude.getRemainingDelay() > delay) + switchState(State::cleanMeUp); + } + else { + if (flexEGs[*region->flexAmpEG]->getRemainingDelay() > static_cast(delay)) + switchState(State::cleanMeUp); } resources.modMatrix.releaseVoice(id, region->getId(), delay); @@ -160,10 +165,15 @@ void sfz::Voice::release(int delay) noexcept void sfz::Voice::off(int delay) noexcept { - if (region->offMode == SfzOffMode::fast) { - egAmplitude.setReleaseTime( Default::offTime ); - } else if (region->offMode == SfzOffMode::time) { - egAmplitude.setReleaseTime(region->offTime); + if (!region->flexAmpEG) { + if (region->offMode == SfzOffMode::fast) { + egAmplitude.setReleaseTime( Default::offTime ); + } else if (region->offMode == SfzOffMode::time) { + egAmplitude.setReleaseTime(region->offTime); + } + } + else { + // TODO(jpc): Flex AmpEG } release(delay); @@ -283,8 +293,14 @@ void sfz::Voice::renderBlock(AudioSpan buffer) noexcept panStageMono(buffer); } - if (!egAmplitude.isSmoothing()) - switchState(State::cleanMeUp); + if (!region->flexAmpEG) { + if (!egAmplitude.isSmoothing()) + switchState(State::cleanMeUp); + } + else { + if (flexEGs[*region->flexAmpEG]->isFinished()) + switchState(State::cleanMeUp); + } powerFollower.process(buffer); @@ -569,8 +585,14 @@ void sfz::Voice::fillWithData(AudioSpan buffer) noexcept << " for sample " << region->sampleId); } #endif - egAmplitude.setReleaseTime(0.0f); - egAmplitude.startRelease(i); + if (!region->flexAmpEG) { + egAmplitude.setReleaseTime(0.0f); + egAmplitude.startRelease(i); + } + else { + // TODO(jpc): Flex AmpEG + flexEGs[*region->flexAmpEG]->release(i); + } fill(indices->subspan(i), sampleEnd); fill(coeffs->subspan(i), 1.0f); break; @@ -850,7 +872,12 @@ float sfz::Voice::getAveragePower() const noexcept bool sfz::Voice::releasedOrFree() const noexcept { - return state != State::playing || egAmplitude.isReleased(); + if (state != State::playing) + return true; + if (!region->flexAmpEG) + return egAmplitude.isReleased(); + else + return flexEGs[*region->flexAmpEG]->isReleased(); } uint32_t sfz::Voice::getSourcePosition() const noexcept