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 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 };
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue