You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
85 lines
2.4 KiB
85 lines
2.4 KiB
#ifndef __OSCILLATOR_H__
|
|
#define __OSCILLATOR_H__
|
|
|
|
/* PolyBLEP oscillator inspired by: https://www.metafunction.co.uk/post/all-about-digital-oscillators-part-2-blits-bleps
|
|
* Further info about BLEP at: https://pbat.ch/sndkit/blep/
|
|
*/
|
|
|
|
#include <math.h>
|
|
|
|
#define PIx2 (2 * M_PI)
|
|
|
|
class Oscillator {
|
|
public:
|
|
enum Mode { MODE_SINE, MODE_SAW, MODE_SQUARE };
|
|
|
|
Mode mode;
|
|
float phase; // current waveform phase angle (radians)
|
|
float phaseStep; // phase angle step per sample
|
|
float value; // current amplitude value
|
|
float driftAmount;
|
|
float driftValue;
|
|
|
|
Oscillator() {
|
|
mode = MODE_SAW;
|
|
phase = 0;
|
|
phaseStep = (440 * 2 * M_PI) / 44100;
|
|
value = 0;
|
|
driftAmount = 0.001;
|
|
driftValue = 0;
|
|
}
|
|
|
|
float polyBlep(float t) {
|
|
float dt = phaseStep / PIx2;
|
|
|
|
// t-t^2/2 +1/2
|
|
// 0 < t <= 1
|
|
// discontinuities between 0 & 1
|
|
if (t < dt) {
|
|
t /= dt;
|
|
return t + t - t * t - 1.0;
|
|
}
|
|
|
|
// t^2/2 +t +1/2
|
|
// -1 <= t <= 0
|
|
// discontinuities between -1 & 0
|
|
else if (t > 1.0 - dt) {
|
|
t = (t - 1.0) / dt;
|
|
return t * t + t + t + 1.0;
|
|
}
|
|
|
|
// no discontinuities
|
|
// 0 otherwise
|
|
else return 0.0;
|
|
}
|
|
|
|
// Generate next output sample and advance the phase angle
|
|
float tick() {
|
|
float t = phase / PIx2; // Define half phase
|
|
|
|
if (mode == MODE_SINE) {
|
|
value = sinf(phase); // No harmonics in sine so no aliasing!! No Poly BLEPs needed!
|
|
} else if (mode == MODE_SAW) {
|
|
value = (2.0 * phase / PIx2) - 1.0; // Render naive waveshape
|
|
value -= polyBlep(t); // Layer output of Poly BLEP on top
|
|
} else if (mode == MODE_SQUARE) {
|
|
if (phase < M_PI) {
|
|
value = 1.0; // Flip
|
|
} else {
|
|
value = -1.0; // Flop
|
|
}
|
|
value += polyBlep(t); // Layer output of Poly BLEP on top (flip)
|
|
value -= polyBlep(fmodf(t + 0.5, 1.0)); // Layer output of Poly BLEP on top (flop)
|
|
}
|
|
|
|
driftValue += 0.01 * ((float) rand() / RAND_MAX - 0.5) - 0.00001 * driftValue;
|
|
phase += phaseStep * (1.0 + driftAmount * driftValue);
|
|
while(phase >= PIx2) { // wrap if phase angle >=360º
|
|
phase -= PIx2;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
};
|
|
|
|
#endif |