commit 448f40cc2bf72251ac90b0d19b30d5d2ffe3bfc0
parent bdf9a7fc2677e2f63d7376e80f384f8684d44a3e
Author: Matt Demanett <matt@demanett.net>
Date: Mon, 7 May 2018 23:13:23 -0400
Experiment with alternative to RMS for envelope following: very fast but sensitive to the normalization factor used.
Diffstat:
5 files changed, 46 insertions(+), 0 deletions(-)
diff --git a/benchmarks/signal_benchmark.cpp b/benchmarks/signal_benchmark.cpp
@@ -102,6 +102,22 @@ static void BM_RMS_Modulating(benchmark::State& state) {
}
BENCHMARK(BM_RMS_Modulating);
+static void BM_PucketteEnvelopeFollower(benchmark::State& state) {
+ SineOscillator o(500.0, 100.0);
+ const int n = 256;
+ float buf[n];
+ for (int i = 0; i < n; ++i) {
+ buf[i] = o.next() * 5.0f;
+ }
+ PucketteEnvelopeFollower pef;
+ int i = 0;
+ for (auto _ : state) {
+ i = ++i % n;
+ benchmark::DoNotOptimize(pef.next(buf[i]));
+ }
+}
+BENCHMARK(BM_PucketteEnvelopeFollower);
+
static void BM_SlewLimiter_Fast(benchmark::State& state) {
WhiteNoiseGenerator r;
const int n = 256;
diff --git a/src/Test.cpp b/src/Test.cpp
@@ -356,6 +356,8 @@ void Test::step() {
_rms.setSampleRate(engineGetSampleRate());
_rms.setSensitivity(sensitivity);
outputs[OUT_OUTPUT].value = _rms.next(inputs[IN_INPUT].value);
+ _pef.setSensitivity(sensitivity);
+ outputs[OUT2_OUTPUT].value = _pef.next(inputs[IN_INPUT].value);
#endif
}
diff --git a/src/Test.hpp b/src/Test.hpp
@@ -188,6 +188,7 @@ struct Test : Module {
SlewLimiter _slew;
#elif RMS
RootMeanSquare _rms;
+ PucketteEnvelopeFollower _pef;
#endif
Test()
diff --git a/src/dsp/signal.cpp b/src/dsp/signal.cpp
@@ -111,6 +111,20 @@ float RootMeanSquare::next(float sample) {
}
+void PucketteEnvelopeFollower::setSensitivity(float sensitivity) {
+ assert(sensitivity >= 0.0f);
+ assert(sensitivity <= 1.0f);
+ _sensitivity = std::min(sensitivity, 0.97f);
+}
+
+float PucketteEnvelopeFollower::next(float sample) {
+ const float norm = 5.0f;
+ sample /= norm;
+ _lastOutput = _sensitivity * _lastOutput + (1 - _sensitivity) * sample * sample;
+ return _lastOutput * norm;
+}
+
+
bool PositiveZeroCrossing::next(float sample) {
switch (_state) {
case NEGATIVE_STATE: {
diff --git a/src/dsp/signal.hpp b/src/dsp/signal.hpp
@@ -67,6 +67,19 @@ struct RootMeanSquare {
float next(float sample);
};
+// Puckette 2007, "Theory and Technique"
+struct PucketteEnvelopeFollower {
+ float _sensitivity = -1.0f;
+ float _lastOutput = 0.0f;
+
+ PucketteEnvelopeFollower(float sensitivity = 1.0f) {
+ setSensitivity(sensitivity);
+ }
+
+ void setSensitivity(float sensitivity);
+ float next(float sample);
+};
+
struct PositiveZeroCrossing {
const float positiveThreshold = 0.01f;
const float negativeThreshold = -positiveThreshold;