commit 27a19dcf8fbc49b2b529a2750b972d0ada2d09cf
parent f7647dc2eb0c50fb731273d5ffa249f6e7706922
Author: Matt Demanett <matt@demanett.net>
Date: Thu, 14 Jun 2018 22:53:27 -0400
Saturation DSP; apply on VCAmp and Mix4/8.
Diffstat:
11 files changed, 62 insertions(+), 2 deletions(-)
diff --git a/benchmarks/signal_benchmark.cpp b/benchmarks/signal_benchmark.cpp
@@ -202,3 +202,19 @@ static void BM_DelayLine(benchmark::State& state) {
}
}
BENCHMARK(BM_DelayLine);
+
+static void BM_Saturator(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() * 20.0f;
+ }
+ Saturator s;
+ int i = 0;
+ for (auto _ : state) {
+ i = ++i % n;
+ benchmark::DoNotOptimize(s.next(buf[i]));
+ }
+}
+BENCHMARK(BM_Saturator);
diff --git a/src/Mix4.cpp b/src/Mix4.cpp
@@ -32,6 +32,7 @@ void Mix4::step() {
mono += _channel3.out;
mono += _channel4.out;
mono = _amplifier.next(mono);
+ mono = _saturator.next(mono);
_rmsLevel = _rms.next(mono) / 5.0f;
if (stereo) {
@@ -41,6 +42,7 @@ void Mix4::step() {
left += _channel3.left;
left += _channel4.left;
left = _amplifier.next(left);
+ left = _saturator.next(left);
outputs[L_OUTPUT].value = left;
float right = 0.0f;
@@ -49,6 +51,7 @@ void Mix4::step() {
right += _channel3.right;
right += _channel4.right;
right = _amplifier.next(right);
+ right = _saturator.next(right);
outputs[R_OUTPUT].value = right;
}
else {
diff --git a/src/Mix4.hpp b/src/Mix4.hpp
@@ -61,6 +61,7 @@ struct Mix4 : Module {
MixerChannel _channel4;
Amplifier _amplifier;
SlewLimiter _slewLimiter;
+ Saturator _saturator;
RootMeanSquare _rms;
float _rmsLevel = 0.0f;
diff --git a/src/Mix8.cpp b/src/Mix8.cpp
@@ -44,6 +44,7 @@ void Mix8::step() {
mono += _channel7.out;
mono += _channel8.out;
mono = _amplifier.next(mono);
+ mono = _saturator.next(mono);
_rmsLevel = _rms.next(mono) / 5.0f;
if (stereo) {
@@ -57,6 +58,7 @@ void Mix8::step() {
left += _channel7.left;
left += _channel8.left;
left = _amplifier.next(left);
+ left = _saturator.next(left);
outputs[L_OUTPUT].value = left;
float right = 0.0f;
@@ -69,6 +71,7 @@ void Mix8::step() {
right += _channel7.right;
right += _channel8.right;
right = _amplifier.next(right);
+ right = _saturator.next(right);
outputs[R_OUTPUT].value = right;
}
else {
diff --git a/src/Mix8.hpp b/src/Mix8.hpp
@@ -89,6 +89,7 @@ struct Mix8 : Module {
MixerChannel _channel8;
Amplifier _amplifier;
SlewLimiter _slewLimiter;
+ Saturator _saturator;
RootMeanSquare _rms;
float _rmsLevel = 0.0f;
diff --git a/src/Test.cpp b/src/Test.cpp
@@ -383,6 +383,11 @@ void Test::step() {
_average.reset();
}
outputs[OUT_OUTPUT].value = _average.next(inputs[IN_INPUT].value);
+
+#elif SATURATOR
+ float in = inputs[IN_INPUT].value;
+ outputs[OUT_OUTPUT].value = _saturator.next(in);
+ outputs[OUT2_OUTPUT].value = clamp(in, -Saturator::limit, Saturator::limit);
#endif
}
diff --git a/src/Test.hpp b/src/Test.hpp
@@ -24,7 +24,8 @@ extern Model* modelTest;
// #define TABLES 1
// #define SLEW 1
// #define RMS 1
-#define RAVG 1
+// #define RAVG 1
+#define SATURATOR 1
#include "pitch.hpp"
#ifdef LPF
@@ -78,6 +79,9 @@ extern Model* modelTest;
#include "dsp/signal.hpp"
#elif RAVG
#include "dsp/signal.hpp"
+#elif SATURATOR
+#include "dsp/oscillator.hpp"
+#include "dsp/signal.hpp"
#else
#error what
#endif
@@ -196,6 +200,8 @@ struct Test : Module {
#elif RAVG
RunningAverage _average;
SchmittTrigger _reset;
+#elif SATURATOR
+ Saturator _saturator;
#endif
Test()
diff --git a/src/VCAmp.cpp b/src/VCAmp.cpp
@@ -16,7 +16,7 @@ void VCAmp::step() {
level *= maxDecibels - minDecibels;
level += minDecibels;
_amplifier.setLevel(_levelSL.next(level));
- outputs[OUT_OUTPUT].value = _amplifier.next(inputs[IN_INPUT].value);
+ outputs[OUT_OUTPUT].value = _saturator.next(_amplifier.next(inputs[IN_INPUT].value));
_rmsLevel = _rms.next(outputs[OUT_OUTPUT].value / 5.0f);
}
else {
diff --git a/src/VCAmp.hpp b/src/VCAmp.hpp
@@ -34,6 +34,7 @@ struct VCAmp : Module {
const float minDecibels = Amplifier::minDecibels;
Amplifier _amplifier;
SlewLimiter _levelSL;
+ Saturator _saturator;
RootMeanSquare _rms;
float _rmsLevel = 0.0f;
diff --git a/src/dsp/signal.cpp b/src/dsp/signal.cpp
@@ -409,3 +409,21 @@ float Limiter::next(float sample) {
}
return out;
}
+
+
+const float Saturator::limit = 12.0f;
+
+static inline float saturation(float x) {
+ const float y1 = 0.98765f; // (2*x - 1)/x**2 where x is 0.9.
+ const float offset = 0.075f / Saturator::limit; // magic.
+ float x1 = (x + 1.0f) * 0.5f;
+ return Saturator::limit * (offset + x1 - sqrtf(x1 * x1 - y1 * x) * (1.0f / y1));
+}
+
+float Saturator::next(float sample) {
+ float x = sample * (1.0f / limit);
+ if (sample < 0.0f) {
+ return -saturation(-x);
+ }
+ return saturation(x);
+}
diff --git a/src/dsp/signal.hpp b/src/dsp/signal.hpp
@@ -220,5 +220,11 @@ struct Limiter {
float next(float sample);
};
+struct Saturator {
+ static const float limit;
+
+ float next(float sample);
+};
+
} // namespace dsp
} // namespace bogaudio