Further changes to the envelope follower- Apply on a single channel- Track attack and release separately
This commit is contained in:
parent
958d9bb5e8
commit
afc9d72c89
4 changed files with 30 additions and 18 deletions
|
|
@ -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 };
|
||||
|
|
|
|||
|
|
@ -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
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue