commit 0358eba8d2beece08d69f47b2f738fa18b182d97
parent 96a1d785b9119307e37211806290caff78f1f629
Author: Matt Demanett <matt@demanett.net>
Date: Sat, 17 Feb 2018 16:33:51 -0500
Replace sine oscillator with more stable one; fixes to sine bank; alternate triangle output configuration in sine bank tests using negative amplitudes.
Diffstat:
4 files changed, 52 insertions(+), 247 deletions(-)
diff --git a/benchmarks/oscillator.cpp b/benchmarks/oscillator.cpp
@@ -56,15 +56,3 @@ 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
@@ -62,7 +62,6 @@ struct Test : Module {
TriangleOscillator _triangle;
#elif SINEBANK
SineBankOscillator _sineBank;
- SineBankOscillator2 _sineBank2;
#endif
Test()
@@ -79,7 +78,6 @@ struct Test : Module {
, _triangle(44100.0, 1000.0, 5.0)
#elif SINEBANK
, _sineBank(44101.0, 1000.0, 50)
- , _sineBank2(44101.0, 1000.0, 50)
#endif
{
onReset();
@@ -93,9 +91,6 @@ struct Test : Module {
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;
}
@@ -104,20 +99,24 @@ 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;
}
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);
+ if (false) {
+ 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);
+ }
}
- for (int i = 1, n = _sineBank2.partialCount(); i <= n; ++i) {
- _sineBank2.setPartial(i, i, i % 2 == 1 ? baseAmplitude / (float)(i * i) : 0.0, &phase);
+ else {
+ float phase = 0.0f;
+ _sineBank.setPartial(1, 1.0f, baseAmplitude, &phase);
+ for (int i = 2, n = _sineBank.partialCount(); i < n; ++i) {
+ float k = 2*i - 1;
+ _sineBank.setPartial(i, k, powf(-1.0f, k) * baseAmplitude/(k * k), &phase);
+ }
}
break;
}
@@ -127,9 +126,6 @@ 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;
}
@@ -138,19 +134,10 @@ struct Test : Module {
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;
- }
+ 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;
}
break;
}
@@ -211,9 +198,6 @@ 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
}
diff --git a/src/dsp/oscillator.cpp b/src/dsp/oscillator.cpp
@@ -24,56 +24,23 @@ 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;
+// A New Recursive Quadrature Oscillator, Martin Vicanek, 2015 - http://vicanek.de/articles/QuadOsc.pdf
+void SineOscillator::setPhase(double phase) {
+ _x = cos(phase);
+ _y = sin(phase);
}
-void SineOscillator::updateDeltaTheta() {
- float deltaTheta = (_frequency / _sampleRate) * 2.0f * M_PI;
- for (int i = 0; i < _n; ++i) {
- _sinDeltaTheta[i] = sinf((i + 1) * deltaTheta);
- _cosDeltaTheta[i] = cosf((i + 1) * deltaTheta);
- }
+void SineOscillator::update() {
+ double w = (_frequency / _sampleRate) * 2.0 * M_PI;
+ _k1 = tan(w / 2.0);
+ _k2 = 2.0 * _k1 / (1 + _k1*_k1);
}
float SineOscillator::_next() {
- ++_sampleCount;
-
- if (_step == 0) {
- const int n1 = _n - 1;
- if (_sampleCount > _maxSamplesBeforeNormalize) {
- _sampleCount = 0;
-
- // https://dsp.stackexchange.com/questions/124/how-to-implement-a-digital-oscillator
- // float g = (3.0f - (_x[n1]*_x[n1] + _y[n1]*_y[n1])) / 2.0f; // would work if _amplitude was always 1.0?
- float g = _amplitude / sqrtf(_x[n1]*_x[n1] + _y[n1]*_y[n1]);
- _x[n1] *= g;
- _y[n1] *= g;
- }
-
- for (int i = 0; i < n1; ++i) {
- _x[i] = _x[n1];
- _y[i] = _y[n1];
- }
-
- float t[_n];
- for (int i = 0; i < _n; ++i) {
- t[i] = _x[i]*_cosDeltaTheta[i] - _y[i]*_sinDeltaTheta[i];
- _y[i] = _x[i]*_sinDeltaTheta[i] + _y[i]*_cosDeltaTheta[i];
- _x[i] = t[i];
- }
- }
-
- float out = _y[_step];
- ++_step;
- _step %= _n;
- return out;
+ double t = _x - _k1*_y;
+ _y = _y + _k2*t;
+ _x = t - _k1*_y;
+ return _amplitude * _y;
}
@@ -132,31 +99,23 @@ void SineBankOscillator::setPartial(int i, float frequencyRatio, float amplitude
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;
+ Partial& p = _partials[i - 1];
+ if (amplitude > 0.01f || amplitude < -0.01f) {
+ p.enabled = true;
+ p.frequencyRatio = frequencyRatio;
+ p.frequency = _frequency * frequencyRatio;
+ p.sine.setFrequency((double)_frequency * (double)frequencyRatio);
+ p.amplitude = amplitude;
if (phase) {
- _partials[i - 1].sine.setPhase(*phase);
+ p.sine.setPhase(*phase);
}
}
else {
- _partials[i - 1].enabled = false;
- }
-}
-
-void SineBankOscillator::disablePartial(int i) {
- if (i > (int)_partials.size()) {
- return;
+ p.enabled = false;
}
- _partials[i - 1].enabled = false;
}
void SineBankOscillator::_sampleRateChanged() {
- Phasor::_sampleRateChanged();
-
_maxPartialFrequency = _maxPartialFrequencySRRatio * _sampleRate;
for (Partial& p : _partials) {
p.sine.setSampleRate(_sampleRate);
@@ -164,8 +123,6 @@ void SineBankOscillator::_sampleRateChanged() {
}
void SineBankOscillator::_frequencyChanged() {
- Phasor::_frequencyChanged();
-
for (Partial& p : _partials) {
p.frequency = _frequency * p.frequencyRatio;
p.sine.setFrequency(_frequency * p.frequencyRatio);
@@ -173,16 +130,6 @@ void SineBankOscillator::_frequencyChanged() {
}
float SineBankOscillator::_next() {
- Phasor::_next();
-
- if (++_steps >= _stepsToReset) {
- _steps = 0;
- // float phase = _phase * M_PI;
- // for (Partial& p : _partials) {
- // p.sine.setPhase(phase * p.frequencyRatio);
- // }
- }
-
float next = 0.0;
for (Partial& p : _partials) {
if (p.enabled && p.frequency < _maxPartialFrequency) {
@@ -194,60 +141,3 @@ 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
@@ -71,39 +71,34 @@ struct Phasor : OscillatorGenerator {
};
struct SineOscillator : OscillatorGenerator {
- static const int _n = 4;
- int _step = 0;
- float _x[_n];
- float _y[_n];
- float _sinDeltaTheta[_n];
- float _cosDeltaTheta[_n];
- unsigned int _sampleCount = 0;
- unsigned int _maxSamplesBeforeNormalize = 1000 + (Seeds::next() % 100);
- float _amplitude;
+ double _k1, _k2;
+ double _x;
+ double _y;
+ double _amplitude;
SineOscillator(
- float sampleRate,
- float frequency,
- float amplitude = 1.0,
- float initialPhase = 0.0
+ double sampleRate,
+ double frequency,
+ double amplitude = 1.0,
+ double initialPhase = 0.0
)
: OscillatorGenerator(sampleRate, frequency)
, _amplitude(amplitude)
{
setPhase(initialPhase);
- updateDeltaTheta();
+ update();
}
virtual void _sampleRateChanged() override {
- updateDeltaTheta();
+ update();
}
virtual void _frequencyChanged() override {
- updateDeltaTheta();
+ update();
}
- void setPhase(float phase);
- void updateDeltaTheta();
+ void setPhase(double phase);
+ void update();
virtual float _next() override;
};
@@ -161,7 +156,7 @@ struct TriangleOscillator : Phasor {
virtual float _next() override;
};
-struct SineBankOscillator : Phasor {
+struct SineBankOscillator : OscillatorGenerator {
struct Partial {
bool enabled;
float frequency;
@@ -180,8 +175,6 @@ struct SineBankOscillator : Phasor {
const float _maxPartialFrequencySRRatio = 0.48;
float _maxPartialFrequency = 0.0;
- unsigned _steps = 0;
- unsigned _stepsToReset = 1000;
std::vector<Partial> _partials;
SineBankOscillator(
@@ -189,49 +182,6 @@ struct SineBankOscillator : Phasor {
float frequency,
int partialCount
)
- : Phasor(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 disablePartial(int i);
-
- virtual void _sampleRateChanged() override;
- virtual void _frequencyChanged() override;
- 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)
{
@@ -243,16 +193,9 @@ struct SineBankOscillator2 : OscillatorGenerator {
return _partials.size();
}
- // one-based indexes.
+ // one-based index.
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;