Further changes to the envelope follower- Apply on a single channel- Track attack and release separately

This commit is contained in:
Paul Ferrand 2020-08-21 11:17:44 +02:00
parent 958d9bb5e8
commit afc9d72c89
4 changed files with 30 additions and 18 deletions

View file

@ -57,7 +57,8 @@ namespace config {
constexpr Oversampling defaultOversamplingFactor { Oversampling::x1 };
constexpr float A440 { 440.0 };
constexpr size_t powerHistoryLength { 16 };
constexpr float powerFollowerFactor { 10 };
constexpr float powerFollowerAttackFactor { 100 };
constexpr float powerFollowerReleaseFactor { 10 };
constexpr uint16_t numCCs { 512 };
constexpr int maxCurves { 256 };
constexpr int chunkSize { 1024 };
@ -72,10 +73,10 @@ namespace config {
*/
constexpr float stealingAgeCoeff { 0.5f };
/**
* @brief The threshold for envelope stealing.
* In percentage of the sum of all envelopes.
* @brief The threshold for power stealing.
* In percentage of the sum of all powers.
*/
constexpr float stealingEnvelopeCoeff { 0.5f };
constexpr float stealingPowerCoeff { 0.5f };
constexpr int filtersPerVoice { 2 };
constexpr int eqsPerVoice { 3 };
constexpr int oscillatorsPerVoice { 9 };

View file

@ -249,13 +249,13 @@ void sfz::Voice::setSampleRate(float sampleRate) noexcept
for (auto& lfo : lfos)
lfo->setSampleRate(sampleRate);
trackingFactor = samplesPerBlock / sampleRate * config::powerFollowerFactor;
attackTrackingFactor = config::powerFollowerAttackFactor / sampleRate;
releaseTrackingFactor = config::powerFollowerReleaseFactor / sampleRate;
}
void sfz::Voice::setSamplesPerBlock(int samplesPerBlock) noexcept
{
this->samplesPerBlock = samplesPerBlock;
this->trackingFactor = samplesPerBlock / sampleRate * config::powerFollowerFactor;
}
void sfz::Voice::renderBlock(AudioSpan<float> buffer) noexcept
@ -732,8 +732,7 @@ void sfz::Voice::reset() noexcept
floatPositionOffset = 0.0f;
noteIsOff = false;
for (auto& p : meanChannelPowers)
p = 0.0f;
meanChannelPower = 0.0f;
filters.clear();
equalizers.clear();
@ -765,7 +764,7 @@ void sfz::Voice::removeVoiceFromRing() noexcept
float sfz::Voice::getAveragePower() const noexcept
{
return max(meanChannelPowers[0], meanChannelPowers[1]);
return meanChannelPower;
}
bool sfz::Voice::releasedOrFree() const noexcept
@ -865,12 +864,23 @@ void sfz::Voice::updateChannelPowers(AudioSpan<float> buffer)
if (buffer.getNumFrames() == 0)
return;
const float factor = buffer.getNumFrames() / samplesPerBlock * trackingFactor;
for (unsigned i = 0; i < meanChannelPowers.size(); ++i) {
const auto input = buffer.getConstSpan(i);
const float meanPower = sfz::meanSquared(input);
meanChannelPowers[i] = meanChannelPowers[i] * (1 - factor) + meanPower * factor;
}
auto tempBuffer = resources.bufferPool.getBuffer(buffer.getNumFrames());
if (!tempBuffer)
return;
sfz::copy(buffer.getConstSpan(0), *tempBuffer);
for (unsigned i = 1; i < buffer.getNumChannels(); ++i)
sfz::add(buffer.getConstSpan(i), *tempBuffer);
const float meanPower = sfz::meanSquared<float>(*tempBuffer);
const float attackFactor = static_cast<float>(buffer.getNumFrames()) * attackTrackingFactor;
const float releaseFactor = static_cast<float>(buffer.getNumFrames()) * releaseTrackingFactor;
meanChannelPower = max(
meanChannelPower * (1 - attackFactor) + meanPower * attackFactor,
meanChannelPower * (1 - releaseFactor) + meanPower * releaseFactor
);
}

View file

@ -485,8 +485,9 @@ private:
Smoother xfadeSmoother;
void resetSmoothers() noexcept;
float trackingFactor { config::defaultSamplesPerBlock / config::defaultSampleRate * config::powerFollowerFactor };
std::array<float, 2> meanChannelPowers;
float attackTrackingFactor { config::powerFollowerAttackFactor / config::defaultSampleRate };
float releaseTrackingFactor { config::powerFollowerReleaseFactor / config::defaultSampleRate };
float meanChannelPower;
LEAK_DETECTOR(Voice);
};

View file

@ -19,7 +19,7 @@ sfz::Voice* sfz::VoiceStealing::steal(absl::Span<sfz::Voice*> voices) noexcept
// We are checking the power to try and kill voices with relative low contribution
// to the output compared to the rest.
const auto powerThreshold = sumPower
/ static_cast<float>(voices.size()) * config::stealingEnvelopeCoeff;
/ static_cast<float>(voices.size()) * config::stealingPowerCoeff;
// We are checking the age so that voices have the time to build up attack
// This is not perfect because pad-type voices will take a long time to output
// their sound, but it's reasonable for sounds with a quick attack and longer