commit 46bc16deb7e5315c7255d2419c564bdf2e55dafe
parent 904643efba9cb13158d0fba992c847cd016a04c9
Author: Matt Demanett <matt@demanett.net>
Date: Wed, 31 Jan 2018 01:38:25 -0500
Basic saw/square/triangle oscillator DSP; test harness.
Diffstat:
4 files changed, 254 insertions(+), 1 deletion(-)
diff --git a/benchmarks/oscillator.cpp b/benchmarks/oscillator.cpp
@@ -5,6 +5,14 @@
using namespace bogaudio::dsp;
+static void BM_Phasor(benchmark::State& state) {
+ Phasor p(44100.0, 440.0);
+ for (auto _ : state) {
+ p.next();
+ }
+}
+BENCHMARK(BM_Phasor);
+
static void BM_SineOscillator(benchmark::State& state) {
SineOscillator o(44100.0, 440.0);
for (auto _ : state) {
@@ -12,3 +20,27 @@ static void BM_SineOscillator(benchmark::State& state) {
}
}
BENCHMARK(BM_SineOscillator);
+
+static void BM_SawOscillator(benchmark::State& state) {
+ SawOscillator o(44100.0, 440.0);
+ for (auto _ : state) {
+ o.next();
+ }
+}
+BENCHMARK(BM_SawOscillator);
+
+static void BM_SquareOscillator(benchmark::State& state) {
+ SquareOscillator o(44100.0, 440.0);
+ for (auto _ : state) {
+ o.next();
+ }
+}
+BENCHMARK(BM_SquareOscillator);
+
+static void BM_TriangleOscillator(benchmark::State& state) {
+ TriangleOscillator o(44100.0, 440.0);
+ for (auto _ : state) {
+ o.next();
+ }
+}
+BENCHMARK(BM_TriangleOscillator);
diff --git a/src/Test.cpp b/src/Test.cpp
@@ -1,6 +1,25 @@
+// #define LPF 1
+// #define SINE 1
+// #define SQUARE 1
+#define SAW 1
+// #define TRIANGLE 1
+
#include "bogaudio.hpp"
+#include "pitch.hpp"
+#ifdef LPF
#include "dsp/filter.hpp"
+#elif SINE
+#include "dsp/oscillator.hpp"
+#elif SQUARE
+#include "dsp/oscillator.hpp"
+#elif SAW
+#include "dsp/oscillator.hpp"
+#elif TRIANGLE
+#include "dsp/oscillator.hpp"
+#else
+#error what
+#endif
using namespace bogaudio::dsp;
@@ -27,33 +46,91 @@ struct Test : Module {
NUM_LIGHTS
};
+#ifdef LPF
LowPassFilter _lpf;
+#elif SINE
+ SineOscillator _sine;
+#elif SQUARE
+ SquareOscillator _square;
+#elif SAW
+ SawOscillator _saw;
+#elif TRIANGLE
+ TriangleOscillator _triangle;
+#endif
Test()
: Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS)
+#ifdef LPF
, _lpf(44100.0, 1000.0, 1.0)
+#elif SINE
+ , _sine(44100.0, 1000.0, 5.0)
+#elif SQUARE
+ , _square(44100.0, 1000.0, 5.0)
+#elif SAW
+ , _saw(44100.0, 1000.0, 5.0)
+#elif TRIANGLE
+ , _triangle(44100.0, 1000.0, 5.0)
+#endif
{
reset();
}
virtual void reset() override;
virtual void step() override;
+ float oscillatorPitch();
};
void Test::reset() {
}
void Test::step() {
- if (!inputs[IN_INPUT].active || !outputs[OUT_OUTPUT].active) {
+ if (!outputs[OUT_OUTPUT].active) {
return;
}
+#ifdef LPF
+ if (!inputs[IN_INPUT].active) {
+ return;
+ }
_lpf.setParams(
engineGetSampleRate(),
10000.0 * clampf(params[PARAM1_PARAM].value, 0.0, 1.0),
std::max(10.0 * clampf(params[PARAM2_PARAM].value, 0.0, 1.0), 0.1)
);
outputs[OUT_OUTPUT].value = _lpf.next(inputs[IN_INPUT].value);
+
+#elif SINE
+ _sine.setSampleRate(engineGetSampleRate());
+ _sine.setFrequency(oscillatorPitch());
+ outputs[OUT_OUTPUT].value = _sine.next();
+
+#elif SQUARE
+ _square.setSampleRate(engineGetSampleRate());
+ _square.setFrequency(oscillatorPitch());
+ float pw = params[PARAM2_PARAM].value;
+ if (inputs[CV2_INPUT].active) {
+ pw += clampf(inputs[CV2_INPUT].value, -5.0, 5.0) / 10.0;
+ }
+ _square.setPulseWidth(pw);
+ outputs[OUT_OUTPUT].value = _square.next();
+
+#elif SAW
+ _saw.setSampleRate(engineGetSampleRate());
+ _saw.setFrequency(oscillatorPitch());
+ outputs[OUT_OUTPUT].value = _saw.next();
+
+#elif TRIANGLE
+ _triangle.setSampleRate(engineGetSampleRate());
+ _triangle.setFrequency(oscillatorPitch());
+ outputs[OUT_OUTPUT].value = _triangle.next();
+#endif
+}
+
+float Test::oscillatorPitch() {
+ if (inputs[CV1_INPUT].active) {
+ return cvToFrequency(inputs[CV1_INPUT].value);
+ }
+ return 10000.0 * powf(params[PARAM1_PARAM].value, 2.0);
}
diff --git a/src/dsp/oscillator.cpp b/src/dsp/oscillator.cpp
@@ -4,6 +4,21 @@
using namespace bogaudio::dsp;
+void Phasor::updateDelta() {
+ float sampleTime = 1.0 / _sampleRate;
+ float cycleTime = 1.0 / _frequency;
+ _delta = (sampleTime / cycleTime) * 2.0f;
+}
+
+float Phasor::_next() {
+ _phase += _delta;
+ if (_phase >= 2.0) {
+ _phase -= 2.0;
+ }
+ return _phase;
+}
+
+
void SineOscillator::updateDeltaTheta() {
float sampleTime = 1.0 / _sampleRate;
float cycleTime = 1.0 / _frequency;
@@ -29,8 +44,58 @@ float SineOscillator::_next() {
_x[i] = t[i];
}
}
+
float out = _y[_step];
++_step;
_step %= _n;
return out;
}
+
+
+float SawOscillator::_next() {
+ Phasor::_next();
+ return _amplitude * (_phase - 1.0f);
+}
+
+
+void SquareOscillator::setPulseWidth(float pw) {
+ if (pw >= 0.9) {
+ _pulseWidth = 0.9;
+ }
+ else if (pw <= 0.1) {
+ _pulseWidth = 0.1;
+ }
+ else {
+ _pulseWidth = pw;
+ }
+ _pulseWidth *= 2.0;
+}
+
+float SquareOscillator::_next() {
+ Phasor::_next();
+ if (positive) {
+ if (_phase >= _pulseWidth) {
+ positive = false;
+ return _negativeAmplitude;
+ }
+ return _amplitude;
+ }
+ if (_phase < _pulseWidth) {
+ positive = true;
+ return _amplitude;
+ }
+ return _negativeAmplitude;
+}
+
+
+float TriangleOscillator::_next() {
+ Phasor::_next();
+ float p = 2.0 * _phase;
+ if (_phase < 0.5) {
+ return _amplitude * p;
+ }
+ if (_phase < 1.5) {
+ return _amplitude * (2.0 - p);
+ }
+ return _amplitude * (p - 4.0);
+}
diff --git a/src/dsp/oscillator.hpp b/src/dsp/oscillator.hpp
@@ -37,6 +37,31 @@ struct OscillatorGenerator : Generator {
virtual void _frequencyChanged() {}
};
+struct Phasor : OscillatorGenerator {
+ float _delta;
+ double _phase = 0.0;
+
+ Phasor(
+ float sampleRate,
+ float frequency
+ )
+ : OscillatorGenerator(sampleRate, frequency)
+ {
+ updateDelta();
+ }
+
+ virtual void _sampleRateChanged() override {
+ updateDelta();
+ }
+
+ virtual void _frequencyChanged() override {
+ updateDelta();
+ }
+
+ void updateDelta();
+ virtual float _next() override;
+};
+
struct SineOscillator : OscillatorGenerator {
static const int _n = 4;
int _step = 0;
@@ -71,5 +96,59 @@ struct SineOscillator : OscillatorGenerator {
virtual float _next() override;
};
+struct SawOscillator : Phasor {
+ float _amplitude;
+
+ SawOscillator(
+ float sampleRate,
+ float frequency,
+ float amplitude = 1.0
+ )
+ : Phasor(sampleRate, frequency)
+ , _amplitude(amplitude)
+ {
+ }
+
+ virtual float _next() override;
+};
+
+struct SquareOscillator : Phasor {
+ float _amplitude;
+ float _negativeAmplitude;
+ float _pulseWidth = 0.5;
+ bool positive = true;
+
+ SquareOscillator(
+ float sampleRate,
+ float frequency,
+ float amplitude = 1.0
+ )
+ : Phasor(sampleRate, frequency)
+ , _amplitude(amplitude)
+ , _negativeAmplitude(-amplitude)
+ {
+ }
+
+ void setPulseWidth(float pw);
+
+ virtual float _next() override;
+};
+
+struct TriangleOscillator : Phasor {
+ float _amplitude;
+
+ TriangleOscillator(
+ float sampleRate,
+ float frequency,
+ float amplitude = 1.0
+ )
+ : Phasor(sampleRate, frequency)
+ , _amplitude(amplitude)
+ {
+ }
+
+ virtual float _next() override;
+};
+
} // namespace dsp
} // namespace bogaudio