diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index bcc6fa52..ee93a3d3 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -85,9 +85,6 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, float value, if (triggerType != TriggerType::CC) baseGain *= region->getNoteGain(number, value); - float crossfadeGain { region->getCrossfadeGain() }; - crossfadeEnvelope.reset(Default::normalizedRange.clamp(crossfadeGain)); - basePan = normalizePercents(region->pan); auto pan = basePan; if (region->panCC) @@ -217,11 +214,6 @@ void sfz::Voice::registerCC(int delay, int ccNumber, float ccValue) noexcept const float newWidth { baseWidth + ccValue * normalizePercents(region->widthCC->value) }; widthEnvelope.registerEvent(delay, Default::symmetricNormalizedRange.clamp(newWidth)); } - - if (region->crossfadeCCInRange.contains(ccNumber) || region->crossfadeCCOutRange.contains(ccNumber)) { - const float crossfadeGain = region->getCrossfadeGain(); - crossfadeEnvelope.registerEvent(delay, Default::normalizedRange.clamp(crossfadeGain)); - } } void sfz::Voice::registerPitchWheel(int delay, int pitch) noexcept @@ -294,26 +286,23 @@ void sfz::Voice::renderBlock(AudioSpan buffer) noexcept } template -void getLinearEnvelope(const sfz::CCMap& ccMods, const sfz::MidiState& state, absl::Span output, absl::Span temp) +void getLinearEnvelope(const sfz::CCMap& ccMods, const sfz::MidiState& state, absl::Span temp, std::function function) { - ASSERT(output.size() <= temp.size()); for (auto& mod : ccMods) { const auto eventList = state.getEvents(mod.cc); - const auto modifier = static_cast(mod.value); ASSERT(eventList.size() > 0); ASSERT(eventList[0].delay == 0); - auto lastValue = eventList[0].value; + auto lastValue = function(mod.value, eventList[0].value); auto lastDelay = eventList[0].delay; for (unsigned i = 1; i < eventList.size(); ++ i) { const auto event = eventList[i]; const auto length = event.delay - lastDelay; - const auto step = (event.value - lastValue) * modifier / length; - lastValue = sfz::linearRamp(temp.subspan(lastDelay, length), lastValue, step); + const auto step = (function(mod.value, event.value) - lastValue)/ length; + lastValue = sfz::linearRamp(temp.subspan(lastDelay, length), lastValue, step); lastDelay += length; } - sfz::fill(temp.subspan(lastDelay), lastValue * modifier); - sfz::add(temp, output); + sfz::fill(temp.subspan(lastDelay), lastValue); } } @@ -334,13 +323,30 @@ void sfz::Voice::processMono(AudioSpan buffer) noexcept ScopedTiming logger { amplitudeDuration }; // Amplitude envelope - fill(modulationSpan, baseGain); - getLinearEnvelope(region->amplitudeCC, resources.midiState, modulationSpan, tempSpan); + fill(modulationSpan, 0.0f); + getLinearEnvelope(region->amplitudeCC, resources.midiState, modulationSpan, [](const float& modifier, float value){ + return value * modifier; + }); + DBG("Amplitude curve back: " << modulationSpan.back()); + add(baseGain, modulationSpan); + DBG("FInal gain: " << modulationSpan.back()); applyGain(modulationSpan, leftBuffer); - // Crossfade envelope - crossfadeEnvelope.getBlock(modulationSpan); + // Crossfade envelopes + // crossfadeEnvelope.getBlock(modulationSpan); + fill(modulationSpan, 1.0f); + getLinearEnvelope>(region->crossfadeCCInRange, resources.midiState, modulationSpan, [this](const Range& range, float value){ + return crossfadeIn(range, value, region->crossfadeCCCurve); + }); applyGain(modulationSpan, leftBuffer); + DBG("XFin: " << modulationSpan.back()); + + fill(modulationSpan, 1.0f); + getLinearEnvelope>(region->crossfadeCCOutRange, resources.midiState, modulationSpan, [this](const Range& range, float value){ + return crossfadeOut(range, value, region->crossfadeCCCurve); + }); + applyGain(modulationSpan, leftBuffer); + DBG("XFout: " << modulationSpan.back()); // Volume envelope volumeEnvelope.getBlock(modulationSpan); @@ -394,12 +400,22 @@ void sfz::Voice::processStereo(AudioSpan buffer) noexcept ScopedTiming logger { amplitudeDuration }; // Amplitude envelope - fill(modulationSpan, baseGain); - getLinearEnvelope(region->amplitudeCC, resources.midiState, modulationSpan, tempSpan); + fill(modulationSpan, 0.0f); + getLinearEnvelope(region->amplitudeCC, resources.midiState, modulationSpan, [](float modifier, float value) { return value * modifier; }); + add(baseGain, modulationSpan); buffer.applyGain(modulationSpan); - // Crossfade envelope - crossfadeEnvelope.getBlock(modulationSpan); + // Crossfade envelopes + fill(modulationSpan, 1.0f); + getLinearEnvelope>(region->crossfadeCCInRange, resources.midiState, modulationSpan, [this](const Range& range, float value){ + return crossfadeIn(range, value, region->crossfadeCCCurve); + }); + buffer.applyGain(modulationSpan); + + fill(modulationSpan, 1.0f); + getLinearEnvelope>(region->crossfadeCCOutRange, resources.midiState, modulationSpan, [this](const Range& range, float value){ + return crossfadeOut(range, value, region->crossfadeCCCurve); + }); buffer.applyGain(modulationSpan); // Volume envelope