From bd85a97db31d49d4dd21f12251db6e1aa4bd15c5 Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Tue, 31 Mar 2020 00:33:06 +0200 Subject: [PATCH] Handle the volume cc modifiers like the rest --- src/sfizz/Region.cpp | 5 ++++- src/sfizz/Region.h | 2 +- src/sfizz/Voice.cpp | 41 ++++++++++++++--------------------------- 3 files changed, 19 insertions(+), 29 deletions(-) diff --git a/src/sfizz/Region.cpp b/src/sfizz/Region.cpp index 1bb17db9..7a2aea2c 100644 --- a/src/sfizz/Region.cpp +++ b/src/sfizz/Region.cpp @@ -294,7 +294,10 @@ bool sfz::Region::parseOpcode(const Opcode& opcode) case hash("gain_cc&"): case hash("gain_oncc&"): // fallthrough case hash("volume_oncc&"): - setCCPairFromOpcode(opcode, volumeCC, Default::volumeCCRange); + if (opcode.parameters.back() > config::numCCs) + return false; + if (auto value = readOpcode(opcode.value, Default::volumeCCRange)) + volumeCC[opcode.parameters.back()] = *value; break; case hash("amplitude"): if (auto value = readOpcode(opcode.value, Default::amplitudeRange)) diff --git a/src/sfizz/Region.h b/src/sfizz/Region.h index 8cd8e3ad..2e2a81ca 100644 --- a/src/sfizz/Region.h +++ b/src/sfizz/Region.h @@ -276,7 +276,7 @@ struct Region { float pan { normalizePercents(Default::pan) }; // pan float width { normalizePercents(Default::width) }; // width float position { normalizePercents(Default::position) }; // position - absl::optional> volumeCC; // volume_oncc + CCMap volumeCC { Default::zeroModifier }; // volume_oncc CCMap amplitudeCC { Default::zeroModifier }; // amplitude_oncc CCMap panCC { Default::zeroModifier }; // pan_oncc CCMap widthCC { Default::zeroModifier }; // width_oncc diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index c2648566..f9516f84 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -74,23 +74,11 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, float value, speedRatio = static_cast(currentPromise->sampleRate / this->sampleRate); } pitchRatio = region->getBasePitchVariation(number, value); - baseVolumedB = region->getBaseVolumedB(number); - auto volumedB = baseVolumedB; - if (region->volumeCC) - volumedB += resources.midiState.getCCValue(region->volumeCC->cc) * region->volumeCC->value; - volumeEnvelope.reset(db2mag(Default::volumeRange.clamp(volumedB))); - baseGain = region->getBaseGain(); if (triggerType != TriggerType::CC) baseGain *= region->getNoteGain(number, value); - pitchBendEnvelope.setFunction([region](float bend){ - const auto bendInCents = bend > 0.0f ? bend * static_cast(region->bendUp) : -bend * static_cast(region->bendDown); - return centsFactor(bendInCents); - }); - pitchBendEnvelope.reset(resources.midiState.getPitchBend()); - // Check that we can handle the number of filters; filters should be cleared here ASSERT((filters.capacity() - filters.size()) >= region->filters.size()); ASSERT((equalizers.capacity() - equalizers.size()) >= region->equalizers.size()); @@ -171,23 +159,14 @@ void sfz::Voice::registerCC(int delay, int ccNumber, float ccValue) noexcept if (region->checkSustain && noteIsOff && ccNumber == config::sustainCC && ccValue < config::halfCCThreshold) release(delay); - - // Add a minimum delay for smoothing the envelopes - // TODO: this feels like a hack, revisit this along with the smoothed envelopes... - delay = max(delay, minEnvelopeDelay); - - if (region->volumeCC && ccNumber == region->volumeCC->cc) { - const float newVolumedB { baseVolumedB + ccValue * region->volumeCC->value }; - volumeEnvelope.registerEvent(delay, db2mag(Default::volumeRange.clamp(newVolumedB))); - } } void sfz::Voice::registerPitchWheel(int delay, float pitch) noexcept { if (state == State::idle) return; - - pitchBendEnvelope.registerEvent(delay, pitch); + UNUSED(delay); + UNUSED(pitch); } void sfz::Voice::registerAftertouch(int delay, uint8_t aftertouch) noexcept @@ -293,7 +272,12 @@ void sfz::Voice::ampStageMono(AudioSpan buffer) noexcept applyGain(*modulationSpan, leftBuffer); // Volume envelope - volumeEnvelope.getBlock(*modulationSpan); + fill(*modulationSpan, db2mag(baseVolumedB)); + for (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 @@ -330,17 +314,20 @@ void sfz::Voice::ampStageStereo(AudioSpan buffer) noexcept linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeIn(mod.value, x, xfCurve); }); applyGain(*tempSpan, *modulationSpan); } - for (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 - volumeEnvelope.getBlock(*modulationSpan); + fill(*modulationSpan, db2mag(baseVolumedB)); + for (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