BogaudioModules

BogaudioModules for VCV Rack
Log | Files | Refs | README | LICENSE

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:
Mbenchmarks/signal_benchmark.cpp | 16++++++++++++++++
Msrc/Test.cpp | 2++
Msrc/Test.hpp | 1+
Msrc/dsp/signal.cpp | 14++++++++++++++
Msrc/dsp/signal.hpp | 13+++++++++++++
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;