From 088da9df65f1dc182de6b9f9fa98f1b80630c28b Mon Sep 17 00:00:00 2001 From: Paul Ferrand Date: Mon, 30 Mar 2020 21:51:21 +0200 Subject: [PATCH] multiplicativeEnvelope free function for pitch --- src/sfizz/MidiState.cpp | 7 +++++- src/sfizz/MidiState.h | 3 ++- src/sfizz/SfzHelpers.h | 2 +- src/sfizz/Voice.cpp | 55 ++++++++++++++++++++++++++--------------- 4 files changed, 44 insertions(+), 23 deletions(-) diff --git a/src/sfizz/MidiState.cpp b/src/sfizz/MidiState.cpp index 94964722..a2e4107c 100644 --- a/src/sfizz/MidiState.cpp +++ b/src/sfizz/MidiState.cpp @@ -157,10 +157,15 @@ void sfz::MidiState::resetAllControllers(int delay) noexcept pitchBendEvent(delay, 0.0f); } -const sfz::EventVector& sfz::MidiState::getEvents(int ccIdx) const noexcept +const sfz::EventVector& sfz::MidiState::getCCEvents(int ccIdx) const noexcept { if (ccIdx < 0 || ccIdx > config::numCCs) return nullEvent; return cc[ccIdx]; } + +const sfz::EventVector& sfz::MidiState::getPitchEvents() const noexcept +{ + return pitchEvents; +} diff --git a/src/sfizz/MidiState.h b/src/sfizz/MidiState.h index f09147f5..2c6f2496 100644 --- a/src/sfizz/MidiState.h +++ b/src/sfizz/MidiState.h @@ -121,7 +121,8 @@ public: */ void resetAllControllers(int delay) noexcept; - const EventVector& getEvents(int ccIdx) const noexcept; + const EventVector& getCCEvents(int ccIdx) const noexcept; + const EventVector& getPitchEvents() const noexcept; private: diff --git a/src/sfizz/SfzHelpers.h b/src/sfizz/SfzHelpers.h index 5aea9bdb..c7c55975 100644 --- a/src/sfizz/SfzHelpers.h +++ b/src/sfizz/SfzHelpers.h @@ -373,7 +373,7 @@ void multiplicativeEnvelope(const EventVector& events, absl::Span envelop const auto event = events[i]; const auto length = event.delay - lastDelay; const auto nextValue = lambda(event.value); - const auto step = std::exp((std::log(nextValue) - std::log(currentValue)) / length); + const auto step = std::exp((std::log(nextValue) - std::log(lastValue)) / length); multiplicativeRamp(envelope.subspan(lastDelay, length), lastValue, step); lastValue = nextValue; lastDelay += length; diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index c08b6d79..9d1ee9c1 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -187,7 +187,7 @@ void sfz::Voice::registerPitchWheel(int delay, float pitch) noexcept if (state == State::idle) return; - pitchBendEnvelope.registerEvent(delay, pitch * 8191.0f); + pitchBendEnvelope.registerEvent(delay, pitch); } void sfz::Voice::registerAftertouch(int delay, uint8_t aftertouch) noexcept @@ -272,7 +272,7 @@ void sfz::Voice::ampStageMono(AudioSpan buffer) noexcept // Amplitude envelope fill(*modulationSpan, baseGain); for (auto& mod : region->amplitudeCC) { - const auto events = resources.midiState.getEvents(mod.cc); + const auto events = resources.midiState.getCCEvents(mod.cc); linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; }); applyGain(*tempSpan, *modulationSpan); } @@ -281,12 +281,12 @@ void sfz::Voice::ampStageMono(AudioSpan buffer) noexcept // Crossfade envelopes fill(*modulationSpan, 1.0f); for (auto& mod : region->crossfadeCCInRange) { - const auto events = resources.midiState.getEvents(mod.cc); + const auto events = resources.midiState.getCCEvents(mod.cc); linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeIn(mod.value, x, xfCurve); }); applyGain(*tempSpan, *modulationSpan); } for (auto& mod : region->crossfadeCCOutRange) { - const auto events = resources.midiState.getEvents(mod.cc); + const auto events = resources.midiState.getCCEvents(mod.cc); linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeOut(mod.value, x, xfCurve); }); applyGain(*tempSpan, *modulationSpan); } @@ -317,25 +317,26 @@ void sfz::Voice::ampStageStereo(AudioSpan buffer) noexcept // Amplitude envelope fill(*modulationSpan, baseGain); for (auto& mod : region->amplitudeCC) { - const auto events = resources.midiState.getEvents(mod.cc); + 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 (auto& mod : region->crossfadeCCInRange) { - const auto events = resources.midiState.getEvents(mod.cc); + const auto events = resources.midiState.getCCEvents(mod.cc); linearEnvelope(events, *tempSpan, [&](float x) { return crossfadeIn(mod.value, x, xfCurve); }); applyGain(*tempSpan, *modulationSpan); } + for (auto& mod : region->crossfadeCCOutRange) { - const auto events = resources.midiState.getEvents(mod.cc); + 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 @@ -366,7 +367,7 @@ void sfz::Voice::panStageMono(AudioSpan buffer) noexcept // Apply panning fill(*modulationSpan, region->pan); for (auto& mod : region->panCC) { - const auto events = resources.midiState.getEvents(mod.cc); + const auto events = resources.midiState.getCCEvents(mod.cc); linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; }); add(*tempSpan, *modulationSpan); } @@ -389,7 +390,7 @@ void sfz::Voice::panStageStereo(AudioSpan buffer) noexcept // panningModulation(*modulationSpan); fill(*modulationSpan, region->pan); for (auto& mod : region->panCC) { - const auto events = resources.midiState.getEvents(mod.cc); + const auto events = resources.midiState.getCCEvents(mod.cc); linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; }); add(*tempSpan, *modulationSpan); } @@ -399,7 +400,7 @@ void sfz::Voice::panStageStereo(AudioSpan buffer) noexcept // widthModulation(*modulationSpan); fill(*modulationSpan, region->width); for (auto& mod : region->widthCC) { - const auto events = resources.midiState.getEvents(mod.cc); + const auto events = resources.midiState.getCCEvents(mod.cc); linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; }); add(*tempSpan, *modulationSpan); } @@ -408,7 +409,7 @@ void sfz::Voice::panStageStereo(AudioSpan buffer) noexcept // positionModulation(*modulationSpan); fill(*modulationSpan, region->position); for (auto& mod : region->positionCC) { - const auto events = resources.midiState.getEvents(mod.cc); + const auto events = resources.midiState.getCCEvents(mod.cc); linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.value; }); add(*tempSpan, *modulationSpan); } @@ -472,10 +473,17 @@ void sfz::Voice::fillWithData(AudioSpan buffer) noexcept return; fill(*jumps, pitchRatio * speedRatio); - if (region->bendStep > 1) - pitchBendEnvelope.getQuantizedBlock(*bends, bendStepFactor); - else - pitchBendEnvelope.getBlock(*bends); + // if (region->bendStep > 1) + // pitchBendEnvelope.getQuantizedBlock(*bends, bendStepFactor); + // else + // pitchBendEnvelope.getBlock(*bends); + const auto events = resources.midiState.getPitchEvents(); + const auto bendLambda = [this](float bend){ + const auto bendInCents = bend > 0.0f ? bend * static_cast(region->bendUp) : -bend * static_cast(region->bendDown); + return centsFactor(bendInCents); + }; + multiplicativeEnvelope(events, *bends, bendLambda); + DBG("Bend: " << bends->back()); applyGain(*bends, *jumps); jumps->front() += floatPositionOffset; @@ -558,11 +566,18 @@ void sfz::Voice::fillWithGenerator(AudioSpan buffer) noexcept float keycenterFrequency = midiNoteFrequency(region->pitchKeycenter); fill(*frequencies, pitchRatio * keycenterFrequency); - if (region->bendStep > 1) - pitchBendEnvelope.getQuantizedBlock(*bends, bendStepFactor); - else - pitchBendEnvelope.getBlock(*bends); + const auto events = resources.midiState.getPitchEvents(); + const auto bendLambda = [this](float bend){ + const auto bendInCents = bend > 0.0f ? bend * static_cast(region->bendUp) : -bend * static_cast(region->bendDown); + return centsFactor(bendInCents); + }; + // if (region->bendStep > 1) + // pitchBendEnvelope.getQuantizedBlock(*bends, bendStepFactor); + // else + // pitchBendEnvelope.getBlock(*bends); + multiplicativeEnvelope(events, *bends, bendLambda); + DBG("Bend: " << bends->back()); applyGain(*bends, *frequencies); waveOscillator.processModulated(frequencies->data(), leftSpan.data(), buffer.getNumFrames());