Smooth the crossfades

This commit is contained in:
Paul Ferrand 2020-07-05 15:25:57 +02:00
parent f874ad3db5
commit 4ee4bbe9c1
3 changed files with 49 additions and 17 deletions

View file

@ -41,6 +41,7 @@ namespace config {
constexpr int numVoices { 64 }; constexpr int numVoices { 64 };
constexpr unsigned maxVoices { 256 }; constexpr unsigned maxVoices { 256 };
constexpr unsigned smoothingSteps { 512 }; constexpr unsigned smoothingSteps { 512 };
constexpr uint8_t xfadeSmoothing { 5 };
constexpr uint8_t gainSmoothing { 0 }; constexpr uint8_t gainSmoothing { 0 };
constexpr unsigned powerTableSizeExponent { 11 }; constexpr unsigned powerTableSizeExponent { 11 };
constexpr int maxFilePromises { maxVoices }; constexpr int maxFilePromises { maxVoices };

View file

@ -25,6 +25,7 @@ sfz::Voice::Voice(int voiceNumber, sfz::Resources& resources)
osc.init(sampleRate); osc.init(sampleRate);
gainSmoother.setSmoothing(config::gainSmoothing, sampleRate); gainSmoother.setSmoothing(config::gainSmoothing, sampleRate);
xfadeSmoother.setSmoothing(config::xfadeSmoothing, sampleRate);
for (auto & filter : channelEnvelopeFilters) for (auto & filter : channelEnvelopeFilters)
filter.setGain(vaGain(config::filteredEnvelopeCutoff, sampleRate)); filter.setGain(vaGain(config::filteredEnvelopeCutoff, sampleRate));
@ -245,6 +246,7 @@ void sfz::Voice::setSampleRate(float sampleRate) noexcept
{ {
this->sampleRate = sampleRate; this->sampleRate = sampleRate;
gainSmoother.setSmoothing(config::gainSmoothing, sampleRate); gainSmoother.setSmoothing(config::gainSmoothing, sampleRate);
xfadeSmoother.setSmoothing(config::xfadeSmoothing, sampleRate);
for (auto & filter : channelEnvelopeFilters) for (auto & filter : channelEnvelopeFilters)
filter.setGain(vaGain(config::filteredEnvelopeCutoff, sampleRate)); filter.setGain(vaGain(config::filteredEnvelopeCutoff, sampleRate));
@ -308,11 +310,45 @@ void sfz::Voice::renderBlock(AudioSpan<float> buffer) noexcept
#endif #endif
} }
void sfz::Voice::amplitudeEnvelope(absl::Span<float> modulationSpan) noexcept void sfz::Voice::applyCrossfades(absl::Span<float> modulationSpan) noexcept
{ {
const auto numSamples = modulationSpan.size(); const auto numSamples = modulationSpan.size();
const auto xfCurve = region->crossfadeCCCurve; const auto xfCurve = region->crossfadeCCCurve;
auto tempSpan = resources.bufferPool.getBuffer(numSamples);
if (!tempSpan)
return;
bool smoothOutput = false;
for (const auto& mod : region->crossfadeCCInRange) {
const auto events = resources.midiState.getCCEvents(mod.cc);
smoothOutput |= (events.size() > 1);
linearEnvelope(events, *tempSpan, [&](float x) {
return crossfadeIn(mod.data, x, xfCurve);
});
applyGain<float>(*tempSpan, modulationSpan);
}
for (const auto& mod : region->crossfadeCCOutRange) {
const auto events = resources.midiState.getCCEvents(mod.cc);
smoothOutput |= (events.size() > 1);
linearEnvelope(events, *tempSpan, [&](float x) {
return crossfadeOut(mod.data, x, xfCurve);
});
applyGain<float>(*tempSpan, modulationSpan);
}
if (smoothOutput) {
xfadeSmoother.reset(modulationSpan.front());
xfadeSmoother.process(modulationSpan, modulationSpan);
}
}
void sfz::Voice::amplitudeEnvelope(absl::Span<float> modulationSpan) noexcept
{
const auto numSamples = modulationSpan.size();
auto tempSpan = resources.bufferPool.getBuffer(numSamples); auto tempSpan = resources.bufferPool.getBuffer(numSamples);
if (!tempSpan) if (!tempSpan)
return; return;
@ -328,22 +364,6 @@ void sfz::Voice::amplitudeEnvelope(absl::Span<float> modulationSpan) noexcept
applyGain<float>(*tempSpan, modulationSpan); applyGain<float>(*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);
});
applyGain<float>(*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);
});
applyGain<float>(*tempSpan, modulationSpan);
}
// Volume envelope // Volume envelope
applyGain1<float>(db2mag(baseVolumedB), modulationSpan); applyGain1<float>(db2mag(baseVolumedB), modulationSpan);
forEachWithSmoother(Mod::volume, [&](const CCData<Modifier>& mod, Smoother& smoother) { forEachWithSmoother(Mod::volume, [&](const CCData<Modifier>& mod, Smoother& smoother) {
@ -370,6 +390,7 @@ void sfz::Voice::ampStageMono(AudioSpan<float> buffer) noexcept
return; return;
amplitudeEnvelope(*modulationSpan); amplitudeEnvelope(*modulationSpan);
applyCrossfades(*modulationSpan);
applyGain<float>(*modulationSpan, leftBuffer); applyGain<float>(*modulationSpan, leftBuffer);
} }
@ -383,6 +404,7 @@ void sfz::Voice::ampStageStereo(AudioSpan<float> buffer) noexcept
return; return;
amplitudeEnvelope(*modulationSpan); amplitudeEnvelope(*modulationSpan);
applyCrossfades(*modulationSpan);
buffer.applyGain(*modulationSpan); buffer.applyGain(*modulationSpan);
} }

View file

@ -340,6 +340,14 @@ private:
* @param modulationSpan * @param modulationSpan
*/ */
void amplitudeEnvelope(absl::Span<float> modulationSpan) noexcept; void amplitudeEnvelope(absl::Span<float> modulationSpan) noexcept;
/**
* @brief Apply the crossfade envelope to a span.
*
* @param modulationSpan
*/
void applyCrossfades(absl::Span<float> modulationSpan) noexcept;
/** /**
* @brief Amplitude stage for a mono source * @brief Amplitude stage for a mono source
* *
@ -473,6 +481,7 @@ private:
ModifierArray<std::vector<Smoother>> modifierSmoothers; ModifierArray<std::vector<Smoother>> modifierSmoothers;
Smoother gainSmoother; Smoother gainSmoother;
Smoother bendSmoother; Smoother bendSmoother;
Smoother xfadeSmoother;
void resetSmoothers() noexcept; void resetSmoothers() noexcept;
std::array<OnePoleFilter<float>, 2> channelEnvelopeFilters; std::array<OnePoleFilter<float>, 2> channelEnvelopeFilters;