From 83fbfc1fcbd483c15d6d389587b8019fade05e2e Mon Sep 17 00:00:00 2001 From: paulfd Date: Sat, 7 Sep 2019 14:03:44 +0200 Subject: [PATCH] Added the pan envelope --- sfizz/LinearEnvelope.h | 1 - sfizz/Region.cpp | 2 +- sfizz/Region.h | 2 +- sfizz/SfzHelpers.h | 6 ++++++ sfizz/Voice.cpp | 43 ++++++++++++++++++++++++++++++++++++------ sfizz/Voice.h | 4 ++-- 6 files changed, 47 insertions(+), 11 deletions(-) diff --git a/sfizz/LinearEnvelope.h b/sfizz/LinearEnvelope.h index 997a9081..20a25b94 100644 --- a/sfizz/LinearEnvelope.h +++ b/sfizz/LinearEnvelope.h @@ -41,7 +41,6 @@ public: void clear(); void reset(Type value = 0.0); void getBlock(absl::Span output); - private: std::function function { [](Type input) { return input; } }; static_assert(std::is_arithmetic::value); diff --git a/sfizz/Region.cpp b/sfizz/Region.cpp index 02df3818..0ea7bb1c 100644 --- a/sfizz/Region.cpp +++ b/sfizz/Region.cpp @@ -712,7 +712,7 @@ float sfz::Region::getNoteGain(int noteNumber, uint8_t velocity) noexcept return baseGain; } -float sfz::Region::getCCGain(const sfz::CCValueArray& ccState) noexcept +float sfz::Region::getCrossfadeGain(const sfz::CCValueArray& ccState) noexcept { float gain { 1.0f }; diff --git a/sfizz/Region.h b/sfizz/Region.h index b4bec2dd..1560b3dd 100644 --- a/sfizz/Region.h +++ b/sfizz/Region.h @@ -56,7 +56,7 @@ struct Region { bool isStereo() const noexcept; float getBasePitchVariation(int noteNumber, uint8_t velocity) noexcept; float getNoteGain(int noteNumber, uint8_t velocity) noexcept; - float getCCGain(const CCValueArray& ccState) noexcept; + float getCrossfadeGain(const CCValueArray& ccState) noexcept; float getBaseGain() noexcept; float velocityGain(uint8_t velocity) const noexcept; uint32_t getOffset() noexcept; diff --git a/sfizz/SfzHelpers.h b/sfizz/SfzHelpers.h index 1cc4ea41..eedb3039 100644 --- a/sfizz/SfzHelpers.h +++ b/sfizz/SfzHelpers.h @@ -53,6 +53,12 @@ inline constexpr float normalizePercents(T percentValue) return std::min(std::max(static_cast(percentValue), 0.0f), 100.0f) / 100.0f; } +template +inline constexpr float normalizeNegativePercents(T percentValue) +{ + return std::min(std::max(static_cast(percentValue), -100.0f), 100.0f) / 100.0f; +} + inline float ccSwitchedValue(const CCValueArray& ccValues, const std::optional& ccSwitch, float value) noexcept { if (ccSwitch) diff --git a/sfizz/Voice.cpp b/sfizz/Voice.cpp index 77480901..ef4574c7 100644 --- a/sfizz/Voice.cpp +++ b/sfizz/Voice.cpp @@ -22,6 +22,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "Voice.h" +#include "AudioSpan.h" #include "Defaults.h" #include "SIMDHelpers.h" #include "SfzHelpers.h" @@ -50,15 +51,24 @@ void sfz::Voice::startVoice(Region* region, int delay, int channel, int number, state = State::playing; speedRatio = static_cast(region->sampleRate / this->sampleRate); pitchRatio = region->getBasePitchVariation(number, value); + baseGain = region->getBaseGain(); if (triggerType != TriggerType::CC) baseGain *= region->getNoteGain(number, value); - baseGain *= region->getCCGain(ccState); + baseGain *= region->getCrossfadeGain(ccState); if (region->amplitudeCC) baseGain *= normalizeCC(ccState[region->amplitudeCC->first]) * normalizePercents(region->amplitudeCC->second); amplitudeEnvelope.reset(baseGain); + basePan = normalizeNegativePercents(region->pan); + auto pan = basePan; + if (region->panCC) + pan += normalizeCC(ccState[region->amplitudeCC->first]) * normalizeNegativePercents(region->amplitudeCC->second); + panEnvelope.reset(pan); + DBG("Base Panning: " << pan); + sourcePosition = region->getOffset(); + floatPosition = static_cast(sourcePosition); initialDelay = delay + region->getDelay(); baseFrequency = midiNoteFrequency(number) * pitchRatio; prepareEGEnvelope(delay, value); @@ -129,6 +139,11 @@ void sfz::Voice::registerCC(int delay, int channel [[maybe_unused]], int ccNumbe const float newGain { normalizeCC(ccValue) * normalizePercents(region->amplitudeCC->second) * baseGain }; amplitudeEnvelope.registerEvent(delay, newGain); } + + if (region->panCC && ccNumber == region->panCC->first) { + const float newPan { basePan + normalizeCC(ccValue) * normalizeNegativePercents(region->amplitudeCC->second)}; + panEnvelope.registerEvent(delay, newPan); + } } void sfz::Voice::registerPitchWheel(int delay [[maybe_unused]], int channel [[maybe_unused]], int pitch [[maybe_unused]]) noexcept @@ -190,15 +205,31 @@ void sfz::Voice::processMono(AudioSpan buffer) noexcept auto leftBuffer = buffer.getSpan(0); auto rightBuffer = buffer.getSpan(1); - auto envelopeSpan = tempSpan1.first(numSamples); - amplitudeEnvelope.getBlock(envelopeSpan); - ::applyGain(envelopeSpan, leftBuffer); + auto span1 = tempSpan1.first(numSamples); + auto span2 = tempSpan2.first(numSamples); - egEnvelope.getBlock(envelopeSpan); - ::applyGain(envelopeSpan, leftBuffer); + // Amplitude envelope + amplitudeEnvelope.getBlock(span1); + ::applyGain(span1, leftBuffer); + // AmpEG envelope + egEnvelope.getBlock(span1); + ::applyGain(span1, leftBuffer); + + // Prepare for stereo output ::copy(leftBuffer, rightBuffer); + + panEnvelope.getBlock(span1); + // We assume that the pan envelope is already normalized between -1 and 1 + ::fill(span2, 1.0f); + ::add(span1, span2); + ::applyGain(piFour, span2); + ::cos(span2, span1); + ::sin(span2, span2); + ::applyGain(span1, leftBuffer); + ::applyGain(span2, rightBuffer); } + void sfz::Voice::processStereo(AudioSpan buffer) noexcept { const auto numSamples = buffer.getNumFrames(); diff --git a/sfizz/Voice.h b/sfizz/Voice.h index da4e1ab7..7890a33b 100644 --- a/sfizz/Voice.h +++ b/sfizz/Voice.h @@ -90,6 +90,7 @@ private: float speedRatio { 1.0 }; float pitchRatio { 1.0 }; float baseGain { 1.0 }; + float basePan { 0.0 }; float baseFrequency { 440.0 }; float phase { 0.0f }; @@ -113,8 +114,7 @@ private: const CCValueArray& ccState; ADSREnvelope egEnvelope; LinearEnvelope amplitudeEnvelope; - LinearEnvelope leftPanEnvelope; - LinearEnvelope rightPanEnvelope; + LinearEnvelope panEnvelope; LEAK_DETECTOR(Voice); };