Move the power follower to its own file
This commit is contained in:
parent
dd8134277c
commit
cb144ad42f
6 changed files with 123 additions and 47 deletions
1
dpf.mk
1
dpf.mk
|
|
@ -103,6 +103,7 @@ SFIZZ_SOURCES = \
|
|||
src/sfizz/Parser.cpp \
|
||||
src/sfizz/parser/Parser.cpp \
|
||||
src/sfizz/parser/ParserPrivate.cpp \
|
||||
src/sfizz/PowerFollower.cpp \
|
||||
src/sfizz/Region.cpp \
|
||||
src/sfizz/RTSemaphore.cpp \
|
||||
src/sfizz/ScopedFTZ.cpp \
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ set (SFIZZ_HEADERS
|
|||
sfizz/Oversampler.h
|
||||
sfizz/Panning.h
|
||||
sfizz/PolyphonyGroup.h
|
||||
sfizz/PowerFollower.h
|
||||
sfizz/railsback/2-1.h
|
||||
sfizz/railsback/4-1.h
|
||||
sfizz/railsback/4-2.h
|
||||
|
|
@ -138,6 +139,7 @@ set (SFIZZ_SOURCES
|
|||
sfizz/Effects.cpp
|
||||
sfizz/LFO.cpp
|
||||
sfizz/LFODescription.cpp
|
||||
sfizz/PowerFollower.cpp
|
||||
sfizz/modulations/ModId.cpp
|
||||
sfizz/modulations/ModKey.cpp
|
||||
sfizz/modulations/ModKeyHash.cpp
|
||||
|
|
|
|||
75
src/sfizz/PowerFollower.cpp
Normal file
75
src/sfizz/PowerFollower.cpp
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||
// license. You should have receive a LICENSE.md file along with the code.
|
||||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||
|
||||
#include "PowerFollower.h"
|
||||
#include "Defaults.h"
|
||||
#include "SIMDHelpers.h"
|
||||
#include <absl/types/span.h>
|
||||
|
||||
namespace sfz {
|
||||
|
||||
PowerFollower::PowerFollower()
|
||||
: sampleRate_(config::defaultSampleRate),
|
||||
samplesPerBlock_(config::defaultSamplesPerBlock),
|
||||
tempBuffer_(new float[config::defaultSamplesPerBlock])
|
||||
{
|
||||
updateTrackingFactor();
|
||||
}
|
||||
|
||||
void PowerFollower::setSampleRate(float sampleRate) noexcept
|
||||
{
|
||||
if (sampleRate_ != sampleRate) {
|
||||
sampleRate_ = sampleRate;
|
||||
updateTrackingFactor();
|
||||
}
|
||||
}
|
||||
|
||||
void PowerFollower::setSamplesPerBlock(unsigned samplesPerBlock)
|
||||
{
|
||||
if (samplesPerBlock_ != samplesPerBlock) {
|
||||
tempBuffer_.reset(new float[samplesPerBlock]);
|
||||
samplesPerBlock_ = samplesPerBlock;
|
||||
updateTrackingFactor();
|
||||
}
|
||||
}
|
||||
|
||||
void PowerFollower::process(AudioSpan<float> buffer) noexcept
|
||||
{
|
||||
size_t numFrames = buffer.getNumFrames();
|
||||
if (numFrames == 0)
|
||||
return;
|
||||
|
||||
absl::Span<float> tempBuffer(tempBuffer_.get(), numFrames);
|
||||
|
||||
copy(buffer.getConstSpan(0), tempBuffer);
|
||||
for (unsigned i = 1; i < buffer.getNumChannels(); ++i)
|
||||
add(buffer.getConstSpan(i), tempBuffer);
|
||||
|
||||
const float meanPower = 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
|
||||
);
|
||||
}
|
||||
|
||||
void PowerFollower::clear() noexcept
|
||||
{
|
||||
meanChannelPower_ = 0;
|
||||
}
|
||||
|
||||
void PowerFollower::updateTrackingFactor() noexcept
|
||||
{
|
||||
// Protect the envelope follower against blowups
|
||||
const auto maxTrackingFactor = sampleRate_ / samplesPerBlock_;
|
||||
attackTrackingFactor_ = min(config::powerFollowerAttackFactor, maxTrackingFactor) / sampleRate_;
|
||||
releaseTrackingFactor_ = min(config::powerFollowerReleaseFactor, maxTrackingFactor) / sampleRate_;
|
||||
}
|
||||
|
||||
} // namespace sfz
|
||||
37
src/sfizz/PowerFollower.h
Normal file
37
src/sfizz/PowerFollower.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||
// license. You should have receive a LICENSE.md file along with the code.
|
||||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||
|
||||
#pragma once
|
||||
#include "AudioSpan.h"
|
||||
#include <memory>
|
||||
|
||||
namespace sfz {
|
||||
|
||||
class PowerFollower {
|
||||
public:
|
||||
PowerFollower();
|
||||
void setSampleRate(float sampleRate) noexcept;
|
||||
void setSamplesPerBlock(unsigned samplesPerBlock);
|
||||
void process(AudioSpan<float> buffer) noexcept;
|
||||
void clear() noexcept;
|
||||
float getAveragePower() const noexcept { return meanChannelPower_; }
|
||||
|
||||
private:
|
||||
void updateTrackingFactor() noexcept;
|
||||
|
||||
private:
|
||||
float sampleRate_ {};
|
||||
unsigned samplesPerBlock_ {};
|
||||
|
||||
std::unique_ptr<float[]> tempBuffer_;
|
||||
|
||||
float attackTrackingFactor_ {};
|
||||
float releaseTrackingFactor_ {};
|
||||
|
||||
float meanChannelPower_ {};
|
||||
};
|
||||
|
||||
} // namespace sfz
|
||||
|
|
@ -237,14 +237,6 @@ void sfz::Voice::registerTempo(int delay, float secondsPerQuarter) noexcept
|
|||
UNUSED(secondsPerQuarter);
|
||||
}
|
||||
|
||||
void sfz::Voice::updateTrackingFactor() noexcept
|
||||
{
|
||||
// Protect the envelope follower against blowups
|
||||
const auto maxTrackingFactor = sampleRate / samplesPerBlock;
|
||||
attackTrackingFactor = min(config::powerFollowerAttackFactor, maxTrackingFactor) / sampleRate;
|
||||
releaseTrackingFactor = min(config::powerFollowerReleaseFactor, maxTrackingFactor) / sampleRate;
|
||||
}
|
||||
|
||||
void sfz::Voice::setSampleRate(float sampleRate) noexcept
|
||||
{
|
||||
this->sampleRate = sampleRate;
|
||||
|
|
@ -257,13 +249,13 @@ void sfz::Voice::setSampleRate(float sampleRate) noexcept
|
|||
for (auto& lfo : lfos)
|
||||
lfo->setSampleRate(sampleRate);
|
||||
|
||||
updateTrackingFactor();
|
||||
powerFollower.setSampleRate(sampleRate);
|
||||
}
|
||||
|
||||
void sfz::Voice::setSamplesPerBlock(int samplesPerBlock) noexcept
|
||||
{
|
||||
this->samplesPerBlock = samplesPerBlock;
|
||||
updateTrackingFactor();
|
||||
powerFollower.setSamplesPerBlock(samplesPerBlock);
|
||||
}
|
||||
|
||||
void sfz::Voice::renderBlock(AudioSpan<float> buffer) noexcept
|
||||
|
|
@ -299,7 +291,7 @@ void sfz::Voice::renderBlock(AudioSpan<float> buffer) noexcept
|
|||
if (!egEnvelope.isSmoothing())
|
||||
switchState(State::cleanMeUp);
|
||||
|
||||
updateChannelPowers(buffer);
|
||||
powerFollower.process(buffer);
|
||||
|
||||
age += buffer.getNumFrames();
|
||||
if (triggerDelay) {
|
||||
|
|
@ -740,7 +732,7 @@ void sfz::Voice::reset() noexcept
|
|||
floatPositionOffset = 0.0f;
|
||||
noteIsOff = false;
|
||||
|
||||
meanChannelPower = 0.0f;
|
||||
powerFollower.clear();
|
||||
|
||||
filters.clear();
|
||||
equalizers.clear();
|
||||
|
|
@ -772,7 +764,7 @@ void sfz::Voice::removeVoiceFromRing() noexcept
|
|||
|
||||
float sfz::Voice::getAveragePower() const noexcept
|
||||
{
|
||||
return meanChannelPower;
|
||||
return powerFollower.getAveragePower();
|
||||
}
|
||||
|
||||
bool sfz::Voice::releasedOrFree() const noexcept
|
||||
|
|
@ -867,31 +859,6 @@ void sfz::Voice::setupOscillatorUnison()
|
|||
#endif
|
||||
}
|
||||
|
||||
void sfz::Voice::updateChannelPowers(AudioSpan<float> buffer)
|
||||
{
|
||||
if (buffer.getNumFrames() == 0)
|
||||
return;
|
||||
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
void sfz::Voice::switchState(State s)
|
||||
{
|
||||
if (s != state) {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
#include "AudioSpan.h"
|
||||
#include "LeakDetector.h"
|
||||
#include "OnePoleFilter.h"
|
||||
#include "PowerFollower.h"
|
||||
#include "NumericId.h"
|
||||
#include "absl/types/span.h"
|
||||
#include <memory>
|
||||
|
|
@ -485,15 +486,8 @@ private:
|
|||
Smoother xfadeSmoother;
|
||||
void resetSmoothers() noexcept;
|
||||
|
||||
/**
|
||||
* @brief Update and clamp the tracking factors to ensure the power
|
||||
* follower does not blow up.
|
||||
*
|
||||
*/
|
||||
void updateTrackingFactor() noexcept;
|
||||
float attackTrackingFactor { config::powerFollowerAttackFactor / config::defaultSampleRate };
|
||||
float releaseTrackingFactor { config::powerFollowerReleaseFactor / config::defaultSampleRate };
|
||||
float meanChannelPower;
|
||||
PowerFollower powerFollower;
|
||||
|
||||
LEAK_DETECTOR(Voice);
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue