commit 8b91d0ca4ed12c9da190c819667f8a75f3e7772c
parent 2eb603fb5eb79ad2231776ef0d84fa7bda75fdcd
Author: Matt Demanett <matt@demanett.net>
Date: Thu, 15 Feb 2018 21:23:10 -0500
Progress(?) on a stable sine bank.
Diffstat:
4 files changed, 161 insertions(+), 11 deletions(-)
diff --git a/benchmarks/oscillator.cpp b/benchmarks/oscillator.cpp
@@ -56,3 +56,15 @@ static void BM_SineBankOscillator(benchmark::State& state) {
}
}
BENCHMARK(BM_SineBankOscillator);
+
+static void BM_SineBankOscillator2(benchmark::State& state) {
+ SineBankOscillator2 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_SineBankOscillator2);
diff --git a/src/Test.cpp b/src/Test.cpp
@@ -42,6 +42,7 @@ struct Test : Module {
enum OutputsIds {
OUT_OUTPUT,
+ OUT2_OUTPUT,
NUM_OUTPUTS
};
@@ -61,6 +62,7 @@ struct Test : Module {
TriangleOscillator _triangle;
#elif SINEBANK
SineBankOscillator _sineBank;
+ SineBankOscillator2 _sineBank2;
#endif
Test()
@@ -76,20 +78,24 @@ struct Test : Module {
#elif TRIANGLE
, _triangle(44100.0, 1000.0, 5.0)
#elif SINEBANK
- , _sineBank(44101.0, 1000.0, 100)
+ , _sineBank(44101.0, 1000.0, 50)
+ , _sineBank2(44101.0, 1000.0, 50)
#endif
{
reset();
#ifdef SINEBANK
const float baseAmplitude = 5.0;
- switch (1) {
+ switch (5) {
case 1: {
// saw
float phase = M_PI;
for (int i = 1, n = _sineBank.partialCount(); i <= n; ++i) {
_sineBank.setPartial(i, i, baseAmplitude / (float)i, &phase);
}
+ for (int i = 1, n = _sineBank2.partialCount(); i <= n; ++i) {
+ _sineBank2.setPartial(i, i, baseAmplitude / (float)i, &phase);
+ }
break;
}
@@ -98,6 +104,9 @@ struct Test : Module {
for (int i = 1, n = _sineBank.partialCount(); i <= n; ++i) {
_sineBank.setPartial(i, i, i % 2 == 1 ? baseAmplitude / (float)i : 0.0);
}
+ for (int i = 1, n = _sineBank2.partialCount(); i <= n; ++i) {
+ _sineBank2.setPartial(i, i, i % 2 == 1 ? baseAmplitude / (float)i : 0.0);
+ }
break;
}
@@ -107,6 +116,9 @@ struct Test : Module {
for (int i = 1, n = _sineBank.partialCount(); i <= n; ++i) {
_sineBank.setPartial(i, i, i % 2 == 1 ? baseAmplitude / (float)(i * i) : 0.0, &phase);
}
+ for (int i = 1, n = _sineBank2.partialCount(); i <= n; ++i) {
+ _sineBank2.setPartial(i, i, i % 2 == 1 ? baseAmplitude / (float)(i * i) : 0.0, &phase);
+ }
break;
}
@@ -115,16 +127,30 @@ struct Test : Module {
for (int i = 1, n = _sineBank.partialCount(); i <= n; ++i) {
_sineBank.setPartial(i, i, i % 2 == 1 ? baseAmplitude / (float)i : baseAmplitude / (float)(2 * i));
}
+ for (int i = 1, n = _sineBank2.partialCount(); i <= n; ++i) {
+ _sineBank2.setPartial(i, i, i % 2 == 1 ? baseAmplitude / (float)i : baseAmplitude / (float)(2 * i));
+ }
break;
}
case 5: {
// ?
- float phase = M_PI;
- float multiple = 1.0;
- for (int i = 1, n = _sineBank.partialCount(); i <= n; ++i) {
- _sineBank.setPartial(i, multiple, baseAmplitude / multiple, &phase);
- multiple += 0.9;
+ float phase = 0.0;
+ float factor = 0.717;
+ float factor2 = factor;
+ {
+ float multiple = 1.0;
+ for (int i = 1, n = _sineBank.partialCount(); i <= n; ++i) {
+ _sineBank.setPartial(i, multiple, baseAmplitude / multiple, &phase);
+ multiple += i % 2 == 1 ? factor : factor2;
+ }
+ }
+ {
+ float multiple = 1.0;
+ for (int i = 1, n = _sineBank2.partialCount(); i <= n; ++i) {
+ _sineBank2.setPartial(i, multiple, baseAmplitude / multiple, &phase);
+ multiple += i % 2 == 1 ? factor : factor2;
+ }
}
break;
}
@@ -185,6 +211,9 @@ void Test::step() {
_sineBank.setSampleRate(engineGetSampleRate());
_sineBank.setFrequency(oscillatorPitch());
outputs[OUT_OUTPUT].value = _sineBank.next();
+ _sineBank2.setSampleRate(engineGetSampleRate());
+ _sineBank2.setFrequency(oscillatorPitch());
+ outputs[OUT2_OUTPUT].value = _sineBank2.next();
#endif
}
@@ -220,6 +249,7 @@ TestWidget::TestWidget() {
auto inInputPosition = Vec(10.5, 258.0);
auto outOutputPosition = Vec(10.5, 296.0);
+ auto out2OutputPosition = Vec(20.5, 316.0);
// end generated by svg_widgets.rb
addParam(createParam<Knob26>(param1ParamPosition, module, Test::PARAM1_PARAM, 0.0, 1.0, 0.5));
@@ -230,4 +260,5 @@ TestWidget::TestWidget() {
addInput(createInput<Port24>(inInputPosition, module, Test::IN_INPUT));
addOutput(createOutput<Port24>(outOutputPosition, module, Test::OUT_OUTPUT));
+ addOutput(createOutput<Port24>(out2OutputPosition, module, Test::OUT2_OUTPUT));
}
diff --git a/src/dsp/oscillator.cpp b/src/dsp/oscillator.cpp
@@ -179,10 +179,10 @@ float SineBankOscillator::_next() {
if (++_steps >= _stepsToReset) {
_steps = 0;
- float phase = _phase * M_PI;
- for (Partial& p : _partials) {
- p.sine.setPhase(phase * p.frequencyRatio);
- }
+ // float phase = _phase * M_PI;
+ // for (Partial& p : _partials) {
+ // p.sine.setPhase(phase * p.frequencyRatio);
+ // }
}
float next = 0.0;
@@ -196,3 +196,60 @@ float SineBankOscillator::_next() {
}
return next;
}
+
+
+void SineBankOscillator2::setPartial(int i, float frequencyRatio, float amplitude, float* phase) {
+ if (i > (int)_partials.size()) {
+ return;
+ }
+
+ Partial& p = _partials[i - 1];
+ if (amplitude > 0.01) {
+ p.enabled = true;
+ p.frequencyRatio = frequencyRatio;
+ p.amplitude = amplitude;
+ if (phase) {
+ p.phase = _radiansToPhase(*phase);
+ }
+ _updatePartial(p);
+ }
+ else {
+ p.enabled = false;
+ }
+}
+
+void SineBankOscillator2::_updatePartial(Partial& p) {
+ const float d = (float)pow(10, resolution);
+ p.frequency = _frequency * p.frequencyRatio;
+ p.frequency *= d;
+ p.frequency = roundf(p.frequency);
+ p.deltaPhase = (phase_t)p.frequency;
+ p.frequency /= d;
+ // printf("UPDATE fr=%f f=%f dp=%u k=%d mp=%u f0=%f\n", p.frequencyRatio, p.frequency, p.deltaPhase, resolution, _maxPhase, _frequency);
+}
+
+void SineBankOscillator2::_sampleRateChanged() {
+ _maxPartialFrequency = _maxPartialFrequencySRRatio * _sampleRate;
+ _maxPhase = pow(10, resolution) * _sampleRate;
+ for (Partial& p : _partials) {
+ _updatePartial(p);
+ // need to scale phase?
+ }
+}
+
+void SineBankOscillator2::_frequencyChanged() {
+ for (Partial& p : _partials) {
+ _updatePartial(p);
+ }
+}
+
+float SineBankOscillator2::_next() {
+ float next = 0.0;
+ for (Partial& p : _partials) {
+ p.phase = (p.phase + p.deltaPhase) % _maxPhase;
+ if (p.enabled && p.frequencyRatio * _frequency < _maxPartialFrequency) {
+ next += p.amplitude * sinf(_phaseToRadians(p.phase));
+ }
+ }
+ return next;
+}
diff --git a/src/dsp/oscillator.hpp b/src/dsp/oscillator.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <stdlib.h>
+#include <stdint.h>
#include <vector>
#include "base.hpp"
@@ -208,5 +209,54 @@ struct SineBankOscillator : Phasor {
virtual float _next() override;
};
+struct SineBankOscillator2 : OscillatorGenerator {
+ typedef uint64_t phase_t;
+ const int resolution = 2;
+
+ struct Partial {
+ bool enabled = false;
+ float frequencyRatio = 1.0;
+ float frequency = 1.0;
+ float amplitude = 1.0;
+ phase_t phase = 0.0;
+ phase_t deltaPhase = 0.0;
+ };
+
+ phase_t _maxPhase = 0.0;
+ const float _maxPartialFrequencySRRatio = 0.48;
+ float _maxPartialFrequency = 0.0;
+ std::vector<Partial> _partials;
+
+ SineBankOscillator2(
+ float sampleRate,
+ float frequency,
+ int partialCount
+ )
+ : OscillatorGenerator(sampleRate, frequency)
+ , _partials(partialCount)
+ {
+ _sampleRateChanged();
+ _frequencyChanged();
+ }
+
+ int partialCount() {
+ return _partials.size();
+ }
+
+ // one-based indexes.
+ void setPartial(int i, float frequencyRatio, float amplitude, float* phase = NULL);
+
+ void _updatePartial(Partial& p);
+ float _phaseToRadians(phase_t p) {
+ return (p / (float)_maxPhase) * 2.0f * M_PI;
+ }
+ phase_t _radiansToPhase(float r) {
+ return ((phase_t)roundf(_maxPhase * (r / (2.0f * M_PI)))) % _maxPhase;
+ }
+ virtual void _sampleRateChanged() override;
+ virtual void _frequencyChanged() override;
+ virtual float _next() override;
+};
+
} // namespace dsp
} // namespace bogaudio