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

View file

@ -249,13 +249,13 @@ void sfz::Voice::setSampleRate(float sampleRate) noexcept
for (auto& lfo : lfos) for (auto& lfo : lfos)
lfo->setSampleRate(sampleRate); lfo->setSampleRate(sampleRate);
trackingFactor = samplesPerBlock / sampleRate * config::powerFollowerFactor; attackTrackingFactor = config::powerFollowerAttackFactor / sampleRate;
releaseTrackingFactor = config::powerFollowerReleaseFactor / sampleRate;
} }
void sfz::Voice::setSamplesPerBlock(int samplesPerBlock) noexcept void sfz::Voice::setSamplesPerBlock(int samplesPerBlock) noexcept
{ {
this->samplesPerBlock = samplesPerBlock; this->samplesPerBlock = samplesPerBlock;
this->trackingFactor = samplesPerBlock / sampleRate * config::powerFollowerFactor;
} }
void sfz::Voice::renderBlock(AudioSpan<float> buffer) noexcept void sfz::Voice::renderBlock(AudioSpan<float> buffer) noexcept
@ -732,8 +732,7 @@ void sfz::Voice::reset() noexcept
floatPositionOffset = 0.0f; floatPositionOffset = 0.0f;
noteIsOff = false; noteIsOff = false;
for (auto& p : meanChannelPowers) meanChannelPower = 0.0f;
p = 0.0f;
filters.clear(); filters.clear();
equalizers.clear(); equalizers.clear();
@ -765,7 +764,7 @@ void sfz::Voice::removeVoiceFromRing() noexcept
float sfz::Voice::getAveragePower() const noexcept float sfz::Voice::getAveragePower() const noexcept
{ {
return max(meanChannelPowers[0], meanChannelPowers[1]); return meanChannelPower;
} }
bool sfz::Voice::releasedOrFree() const noexcept bool sfz::Voice::releasedOrFree() const noexcept
@ -865,12 +864,23 @@ void sfz::Voice::updateChannelPowers(AudioSpan<float> buffer)
if (buffer.getNumFrames() == 0) if (buffer.getNumFrames() == 0)
return; return;
const float factor = buffer.getNumFrames() / samplesPerBlock * trackingFactor; auto tempBuffer = resources.bufferPool.getBuffer(buffer.getNumFrames());
for (unsigned i = 0; i < meanChannelPowers.size(); ++i) { if (!tempBuffer)
const auto input = buffer.getConstSpan(i); return;
const float meanPower = sfz::meanSquared(input);
meanChannelPowers[i] = meanChannelPowers[i] * (1 - factor) + meanPower * factor; 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; Smoother xfadeSmoother;
void resetSmoothers() noexcept; void resetSmoothers() noexcept;
float trackingFactor { config::defaultSamplesPerBlock / config::defaultSampleRate * config::powerFollowerFactor }; float attackTrackingFactor { config::powerFollowerAttackFactor / config::defaultSampleRate };
std::array<float, 2> meanChannelPowers; float releaseTrackingFactor { config::powerFollowerReleaseFactor / config::defaultSampleRate };
float meanChannelPower;
LEAK_DETECTOR(Voice); 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 // We are checking the power to try and kill voices with relative low contribution
// to the output compared to the rest. // to the output compared to the rest.
const auto powerThreshold = sumPower 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 // 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 // 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 // their sound, but it's reasonable for sounds with a quick attack and longer