Smooth the crossfades
This commit is contained in:
parent
f874ad3db5
commit
4ee4bbe9c1
3 changed files with 49 additions and 17 deletions
|
|
@ -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 };
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue