diff --git a/src/sfizz/Voice.cpp b/src/sfizz/Voice.cpp index 370d29d8..ee3484d1 100644 --- a/src/sfizz/Voice.cpp +++ b/src/sfizz/Voice.cpp @@ -249,6 +249,51 @@ void sfz::Voice::renderBlock(AudioSpan buffer) noexcept #endif } +template +void linearModifier(const sfz::Resources& resources, absl::Span span, const sfz::CCData& ccData, F&& lambda) +{ + const auto events = resources.midiState.getCCEvents(ccData.cc); + const auto curve = resources.curves.getCurve(ccData.data.curve); + if (ccData.data.steps == 0) { + linearEnvelope(events, span, [&ccData, &curve, &lambda](float x) { + return lambda(curve.evalNormalized(x) * ccData.data.value); + }); + } else { + const float stepSize { ccData.data.value / ccData.data.steps }; + linearEnvelope(events, span, [&ccData, &curve, &lambda](float x) { + return lambda(curve.evalNormalized(x) * ccData.data.value); + }, stepSize); + } +} + +template +void multiplicativeModifier(const sfz::Resources& resources, absl::Span span, const sfz::CCData& ccData, F&& lambda) +{ + const auto events = resources.midiState.getCCEvents(ccData.cc); + const auto curve = resources.curves.getCurve(ccData.data.curve); + if (ccData.data.steps == 0) { + multiplicativeEnvelope(events, span, [&ccData, &curve, &lambda](float x) { + return lambda(curve.evalNormalized(x) * ccData.data.value); + }); + } else { + // FIXME: not sure about this step size for multiplicative envelopes + const float stepSize { ccData.data.value / ccData.data.steps }; + multiplicativeEnvelope(events, span, [&ccData, &curve, &lambda](float x) { + return lambda(curve.evalNormalized(x) * ccData.data.value); + }, stepSize); + } +} + +void linearModifier(const sfz::Resources& resources, absl::Span span, const sfz::CCData& ccData) +{ + linearModifier(resources, span, ccData, [](float x) { return x; }); +} + +void multiplicativeModifier(const sfz::Resources& resources, absl::Span span, const sfz::CCData& ccData) +{ + multiplicativeModifier(resources, span, ccData, [](float x) { return x; }); +} + void sfz::Voice::amplitudeEnvelope(absl::Span modulationSpan) noexcept { const auto numSamples = modulationSpan.size(); @@ -264,28 +309,32 @@ void sfz::Voice::amplitudeEnvelope(absl::Span modulationSpan) noexcept // 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.data.value; }); + linearModifier(resources, *tempSpan, mod); 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.data, x, xfCurve); }); + linearEnvelope(events, *tempSpan, [&](float x) { + return crossfadeIn(mod.data, 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.data, x, xfCurve); }); + linearEnvelope(events, *tempSpan, [&](float x) { + return crossfadeOut(mod.data, 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.data.value); }); + multiplicativeModifier(resources, *tempSpan, mod, [](float x) { + return db2mag(x); + }); applyGain(*tempSpan, modulationSpan); } } @@ -337,8 +386,7 @@ void sfz::Voice::panStageMono(AudioSpan buffer) noexcept // Apply panning fill(*modulationSpan, region->pan); for (const auto& mod : region->panCC) { - const auto events = resources.midiState.getCCEvents(mod.cc); - linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.data.value; }); + linearModifier(resources, *tempSpan, mod); add(*tempSpan, *modulationSpan); } pan(*modulationSpan, leftBuffer, rightBuffer); @@ -357,30 +405,24 @@ void sfz::Voice::panStageStereo(AudioSpan buffer) noexcept return; // Apply panning - // panningModulation(*modulationSpan); fill(*modulationSpan, region->pan); for (const auto& mod : region->panCC) { - const auto events = resources.midiState.getCCEvents(mod.cc); - linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.data.value; }); + linearModifier(resources, *tempSpan, mod); add(*tempSpan, *modulationSpan); } pan(*modulationSpan, leftBuffer, rightBuffer); // Apply the width/position process - // widthModulation(*modulationSpan); fill(*modulationSpan, region->width); for (const auto& mod : region->widthCC) { - const auto events = resources.midiState.getCCEvents(mod.cc); - linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.data.value; }); + linearModifier(resources, *tempSpan, mod); add(*tempSpan, *modulationSpan); } width(*modulationSpan, leftBuffer, rightBuffer); - // positionModulation(*modulationSpan); fill(*modulationSpan, region->position); for (const auto& mod : region->positionCC) { - const auto events = resources.midiState.getCCEvents(mod.cc); - linearEnvelope(events, *tempSpan, [&mod](float x) { return x * mod.data.value; }); + linearModifier(resources, *tempSpan, mod); add(*tempSpan, *modulationSpan); } pan(*modulationSpan, leftBuffer, rightBuffer); @@ -457,8 +499,7 @@ void sfz::Voice::fillWithData(AudioSpan buffer) noexcept applyGain(*bends, *jumps); for (const auto& mod : region->tuneCC) { - const auto events = resources.midiState.getCCEvents(mod.cc); - multiplicativeEnvelope(events, *bends, [&](float x) { return centsFactor(x * mod.data.value); }); + multiplicativeModifier(resources, *bends, mod, [](float x) { return centsFactor(x); }); applyGain(*bends, *jumps); } @@ -561,8 +602,9 @@ void sfz::Voice::fillWithGenerator(AudioSpan buffer) noexcept applyGain(*bends, *frequencies); for (const auto& mod : region->tuneCC) { - const auto events = resources.midiState.getCCEvents(mod.cc); - multiplicativeEnvelope(events, *bends, [&](float x) { return centsFactor(x * mod.data.value); }); + multiplicativeModifier(resources, *bends, mod, [](float x) { + return centsFactor(x); + }); applyGain(*bends, *frequencies); }