commit 5592ba3f51b551dd6f5a143351bbf74c1db5ae86
parent 46bc16deb7e5315c7255d2419c564bdf2e55dafe
Author: Matt Demanett <matt@demanett.net>
Date: Tue, 6 Feb 2018 01:09:06 -0500
Crude additive oscillator dsp.
Diffstat:
4 files changed, 200 insertions(+), 12 deletions(-)
diff --git a/benchmarks/oscillator.cpp b/benchmarks/oscillator.cpp
@@ -44,3 +44,15 @@ static void BM_TriangleOscillator(benchmark::State& state) {
}
}
BENCHMARK(BM_TriangleOscillator);
+
+static void BM_SineBankOscillator(benchmark::State& state) {
+ SineBankOscillator o(44100.0, 440.0, 100);
+ for (int i = 1, n = o.partialCount(); i <= n; ++i) {
+ o.setPartial(i, i, 1.0 / (float)i);
+ }
+
+ for (auto _ : state) {
+ o.next();
+ }
+}
+BENCHMARK(BM_SineBankOscillator);
diff --git a/src/Test.cpp b/src/Test.cpp
@@ -2,8 +2,9 @@
// #define LPF 1
// #define SINE 1
// #define SQUARE 1
-#define SAW 1
+// #define SAW 1
// #define TRIANGLE 1
+#define SINEBANK 1
#include "bogaudio.hpp"
#include "pitch.hpp"
@@ -17,6 +18,8 @@
#include "dsp/oscillator.hpp"
#elif TRIANGLE
#include "dsp/oscillator.hpp"
+#elif SINEBANK
+#include "dsp/oscillator.hpp"
#else
#error what
#endif
@@ -56,6 +59,8 @@ struct Test : Module {
SawOscillator _saw;
#elif TRIANGLE
TriangleOscillator _triangle;
+#elif SINEBANK
+ SineBankOscillator _sineBank;
#endif
Test()
@@ -70,9 +75,49 @@ struct Test : Module {
, _saw(44100.0, 1000.0, 5.0)
#elif TRIANGLE
, _triangle(44100.0, 1000.0, 5.0)
+#elif SINEBANK
+ , _sineBank(44101.0, 1000.0, 100)
#endif
{
reset();
+
+#ifdef SINEBANK
+ const float baseAmplitude = 5.0;
+ switch (4) {
+ case 1: {
+ // saw
+ for (int i = 1, n = _sineBank.partialCount(); i <= n; ++i) {
+ _sineBank.setPartial(i, i, baseAmplitude / (float)i);
+ }
+ break;
+ }
+
+ case 2: {
+ // square
+ for (int i = 1, n = _sineBank.partialCount(); i <= n; ++i) {
+ _sineBank.setPartial(i, i, i % 2 == 1 ? baseAmplitude / (float)i : 0.0);
+ }
+ break;
+ }
+
+ case 3: {
+ // triangle
+ float phase = M_PI / 2.0;
+ for (int i = 1, n = _sineBank.partialCount(); i <= n; ++i) {
+ _sineBank.setPartial(i, i, i % 2 == 1 ? baseAmplitude / (float)(i * i) : 0.0, &phase);
+ }
+ break;
+ }
+
+ case 4: {
+ // saw-square
+ for (int i = 1, n = _sineBank.partialCount(); i <= n; ++i) {
+ _sineBank.setPartial(i, i, i % 2 == 1 ? baseAmplitude / (float)i : baseAmplitude / (float)(2 * i));
+ }
+ break;
+ }
+ }
+#endif
}
virtual void reset() override;
@@ -123,6 +168,11 @@ void Test::step() {
_triangle.setSampleRate(engineGetSampleRate());
_triangle.setFrequency(oscillatorPitch());
outputs[OUT_OUTPUT].value = _triangle.next();
+
+#elif SINEBANK
+ _sineBank.setSampleRate(engineGetSampleRate());
+ _sineBank.setFrequency(oscillatorPitch());
+ outputs[OUT_OUTPUT].value = _sineBank.next();
#endif
}
diff --git a/src/dsp/oscillator.cpp b/src/dsp/oscillator.cpp
@@ -4,6 +4,10 @@
using namespace bogaudio::dsp;
+void Phasor::setPhase(float phase) {
+ _phase = phase / (2.0 * M_PI);
+}
+
void Phasor::updateDelta() {
float sampleTime = 1.0 / _sampleRate;
float cycleTime = 1.0 / _frequency;
@@ -19,13 +23,26 @@ float Phasor::_next() {
}
+void SineOscillator::setPhase(float phase) {
+ float x = cosf(phase) * _amplitude;
+ float y = sinf(phase) * _amplitude;
+ for (int i = 0; i < _n; ++i) {
+ _x[i] = x;
+ _y[i] = y;
+ }
+ _step = 0;
+}
+
void SineOscillator::updateDeltaTheta() {
- float sampleTime = 1.0 / _sampleRate;
- float cycleTime = 1.0 / _frequency;
- float _deltaTheta = (sampleTime / cycleTime) * 2.0f * M_PI;
+ float deltaTheta = 0.0f;
+ if (_sampleRate > 0.0f && _frequency > 0.0f) {
+ float sampleTime = 1.0f / _sampleRate;
+ float cycleTime = 1.0f / _frequency;
+ deltaTheta = (sampleTime / cycleTime) * 2.0f * M_PI;
+ }
for (int i = 0; i < _n; ++i) {
- _sinDeltaTheta[i] = sinf((i + 1) * _deltaTheta);
- _cosDeltaTheta[i] = cosf((i + 1) * _deltaTheta);
+ _sinDeltaTheta[i] = sinf((i + 1) * deltaTheta);
+ _cosDeltaTheta[i] = cosf((i + 1) * deltaTheta);
}
}
@@ -99,3 +116,58 @@ float TriangleOscillator::_next() {
}
return _amplitude * (p - 4.0);
}
+
+
+void SineBankOscillator::setPartial(int i, float frequencyRatio, float amplitude, float* phase) {
+ if (i > (int)_partials.size()) {
+ return;
+ }
+
+ if (amplitude > 0.01) {
+ _partials[i - 1].enabled = true;
+ _partials[i - 1].frequencyRatio = frequencyRatio;
+ _partials[i - 1].frequency = _frequency * frequencyRatio;
+ _partials[i - 1].sine.setFrequency(_frequency * frequencyRatio);
+ _partials[i - 1].amplitude = amplitude;
+ if (phase) {
+ _partials[i - 1].sine.setPhase(*phase);
+ }
+ }
+ else {
+ _partials[i - 1].enabled = false;
+ }
+}
+
+void SineBankOscillator::disablePartial(int i) {
+ if (i > (int)_partials.size()) {
+ return;
+ }
+ _partials[i - 1].enabled = false;
+}
+
+void SineBankOscillator::_sampleRateChanged() {
+ _maxPartialFrequency = _maxPartialFrequencySRRatio * _sampleRate;
+ for (Partial& p : _partials) {
+ p.sine.setSampleRate(_sampleRate);
+ }
+}
+
+void SineBankOscillator::_frequencyChanged() {
+ for (Partial& p : _partials) {
+ p.frequency = _frequency * p.frequencyRatio;
+ p.sine.setFrequency(_frequency * p.frequencyRatio);
+ }
+}
+
+float SineBankOscillator::_next() {
+ float next = 0.0;
+ for (Partial& p : _partials) {
+ if (p.enabled && p.frequency < _maxPartialFrequency) {
+ next += p.sine.next() * p.amplitude;
+ }
+ else {
+ p.sine.next(); // keep spinning, maintain phase.
+ }
+ }
+ return next;
+}
diff --git a/src/dsp/oscillator.hpp b/src/dsp/oscillator.hpp
@@ -1,5 +1,7 @@
#pragma once
+#include <vector>
+
#include "base.hpp"
namespace bogaudio {
@@ -43,10 +45,12 @@ struct Phasor : OscillatorGenerator {
Phasor(
float sampleRate,
- float frequency
+ float frequency,
+ float initialPhase = 0.0
)
: OscillatorGenerator(sampleRate, frequency)
{
+ setPhase(initialPhase);
updateDelta();
}
@@ -58,6 +62,7 @@ struct Phasor : OscillatorGenerator {
updateDelta();
}
+ void setPhase(float phase);
void updateDelta();
virtual float _next() override;
};
@@ -70,17 +75,18 @@ struct SineOscillator : OscillatorGenerator {
float _sinDeltaTheta[_n];
float _cosDeltaTheta[_n];
+ float _amplitude;
+
SineOscillator(
float sampleRate,
float frequency,
- float amplitude = 1.0
+ float amplitude = 1.0,
+ float initialPhase = 0.0
)
: OscillatorGenerator(sampleRate, frequency)
+ , _amplitude(amplitude)
{
- for (int i = 0; i < _n; ++i) {
- _x[i] = amplitude;
- _y[i] = 0.0;
- }
+ setPhase(initialPhase);
updateDeltaTheta();
}
@@ -92,6 +98,7 @@ struct SineOscillator : OscillatorGenerator {
updateDeltaTheta();
}
+ void setPhase(float phase);
void updateDeltaTheta();
virtual float _next() override;
};
@@ -150,5 +157,52 @@ struct TriangleOscillator : Phasor {
virtual float _next() override;
};
+struct SineBankOscillator : OscillatorGenerator {
+ struct Partial {
+ bool enabled;
+ float frequency;
+ float frequencyRatio;
+ float amplitude;
+ SineOscillator sine;
+
+ Partial()
+ : enabled(false)
+ , frequency(0.0)
+ , frequencyRatio(0.0)
+ , amplitude(0.0)
+ , sine(0.0, 0.0, 1.0)
+ {}
+ };
+
+ const float _maxPartialFrequencySRRatio = 0.48;
+ float _maxPartialFrequency;
+ std::vector<Partial> _partials;
+
+ SineBankOscillator(
+ float sampleRate,
+ float frequency,
+ int partialCount
+ )
+ : OscillatorGenerator(sampleRate, frequency)
+ , _maxPartialFrequency(0.0)
+ , _partials(partialCount)
+ {
+ _sampleRateChanged();
+ _frequencyChanged();
+ }
+
+ int partialCount() {
+ return _partials.size();
+ }
+
+ // one-based indexes.
+ void setPartial(int i, float frequencyRatio, float amplitude, float* phase = NULL);
+ void disablePartial(int i);
+
+ virtual void _sampleRateChanged() override;
+ virtual void _frequencyChanged() override;
+ virtual float _next() override;
+};
+
} // namespace dsp
} // namespace bogaudio