diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 5da0f909..dac552c6 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -235,53 +235,59 @@ void sfz::Voice::renderBlock(AudioSpan buffer) noexcept this->triggerDelay = absl::nullopt; } +void sfz::Voice::amplitudeEnvelope(absl::Span modulationSpan) noexcept +{ + const auto numSamples = modulationSpan.size(); + const auto xfCurve = region->crossfadeCCCurve; + + auto tempSpan = resources.bufferPool.getBuffer(numSamples); + if (!tempSpan) + return; + + // AmpEG envelope + egEnvelope.getBlock(modulationSpan); + + // Amplitude envelope + applyGain(baseGain, modulationSpan); + for (const auto& mod : region->amplitudeCC) { + const auto events = resources.midiState.getCCEvents(mod.cc); + linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; }); + applyGain(*tempSpan, modulationSpan); + } + + // Crossfade envelopes + for (const auto& mod : region->crossfadeCCInRange) { + const auto events = resources.midiState.getCCEvents(mod.cc); + linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeIn(mod.value, x, xfCurve); }); + applyGain(*tempSpan, modulationSpan); + } + for (const auto& mod : region->crossfadeCCOutRange) { + const auto events = resources.midiState.getCCEvents(mod.cc); + linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeOut(mod.value, x, xfCurve); }); + applyGain(*tempSpan, modulationSpan); + } + + // Volume envelope + applyGain(db2mag(baseVolumedB), modulationSpan); + for (const auto& mod : region->volumeCC) { + const auto events = resources.midiState.getCCEvents(mod.cc); + multiplicativeEnvelope(events, *tempSpan, [&](float x) { return db2mag(x * mod.value); }); + applyGain(*tempSpan, modulationSpan); + } +} + void sfz::Voice::ampStageMono(AudioSpan buffer) noexcept { ScopedTiming logger { amplitudeDuration }; const auto numSamples = buffer.getNumFrames(); const auto leftBuffer = buffer.getSpan(0); - const auto xfCurve = region->crossfadeCCCurve; auto modulationSpan = resources.bufferPool.getBuffer(numSamples); - auto tempSpan = resources.bufferPool.getBuffer(numSamples); - if (!modulationSpan || !tempSpan) + if (!modulationSpan) return; - // Amplitude envelope - fill(*modulationSpan, baseGain); - for (const auto& mod : region->amplitudeCC) { - const auto events = resources.midiState.getCCEvents(mod.cc); - linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; }); - applyGain(*tempSpan, *modulationSpan); - } - applyGain(*modulationSpan, leftBuffer); - - // Crossfade envelopes - fill(*modulationSpan, 1.0f); - for (const auto& mod : region->crossfadeCCInRange) { - const auto events = resources.midiState.getCCEvents(mod.cc); - linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeIn(mod.value, x, xfCurve); }); - applyGain(*tempSpan, *modulationSpan); - } - for (const auto& mod : region->crossfadeCCOutRange) { - const auto events = resources.midiState.getCCEvents(mod.cc); - linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeOut(mod.value, x, xfCurve); }); - applyGain(*tempSpan, *modulationSpan); - } - applyGain(*modulationSpan, leftBuffer); - - // Volume envelope - fill(*modulationSpan, db2mag(baseVolumedB)); - for (const auto& mod : region->volumeCC) { - const auto events = resources.midiState.getCCEvents(mod.cc); - multiplicativeEnvelope(events, *tempSpan, [&](float x) { return db2mag(x * mod.value); }); - applyGain(*tempSpan, *modulationSpan); - } - applyGain(*modulationSpan, leftBuffer); - - // AmpEG envelope - egEnvelope.getBlock(*modulationSpan); + amplitudeEnvelope(*modulationSpan); applyGain(*modulationSpan, leftBuffer); } @@ -290,48 +296,11 @@ void sfz::Voice::ampStageStereo(AudioSpan buffer) noexcept ScopedTiming logger { amplitudeDuration }; const auto numSamples = buffer.getNumFrames(); - - const auto xfCurve = region->crossfadeCCCurve; - auto modulationSpan = resources.bufferPool.getBuffer(numSamples); - auto tempSpan = resources.bufferPool.getBuffer(numSamples); - if (!modulationSpan || !tempSpan) + if (!modulationSpan) return; - // Amplitude envelope - fill(*modulationSpan, baseGain); - for (const auto& mod : region->amplitudeCC) { - const auto events = resources.midiState.getCCEvents(mod.cc); - linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; }); - applyGain(*tempSpan, *modulationSpan); - } - buffer.applyGain(*modulationSpan); - - // Crossfade envelopes - fill(*modulationSpan, 1.0f); - for (const auto& mod : region->crossfadeCCInRange) { - const auto events = resources.midiState.getCCEvents(mod.cc); - linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeIn(mod.value, x, xfCurve); }); - applyGain(*tempSpan, *modulationSpan); - } - for (const auto& mod : region->crossfadeCCOutRange) { - const auto events = resources.midiState.getCCEvents(mod.cc); - linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeOut(mod.value, x, xfCurve); }); - applyGain(*tempSpan, *modulationSpan); - } - buffer.applyGain(*modulationSpan); - - // Volume envelope - fill(*modulationSpan, db2mag(baseVolumedB)); - for (const auto& mod : region->volumeCC) { - const auto events = resources.midiState.getCCEvents(mod.cc); - multiplicativeEnvelope(events, *tempSpan, [&](float x) { return db2mag(x * mod.value); }); - applyGain(*tempSpan, *modulationSpan); - } - buffer.applyGain(*modulationSpan); - - // AmpEG envelope - egEnvelope.getBlock(*modulationSpan); + amplitudeEnvelope(*modulationSpan); buffer.applyGain(*modulationSpan); } diff --git a/src/sfizz/Voice.h b/src/sfizz/Voice.h index 7afcd24e..f0a70af9 100644 --- a/src/sfizz/Voice.h +++ b/src/sfizz/Voice.h @@ -237,6 +237,7 @@ private: * @param buffer */ void fillWithGenerator(AudioSpan buffer) noexcept; + void amplitudeEnvelope(absl::Span modulationSpan) noexcept; void ampStageMono(AudioSpan buffer) noexcept; void ampStageStereo(AudioSpan buffer) noexcept; void panStageMono(AudioSpan buffer) noexcept;