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.
101 lines
3.2 KiB
101 lines
3.2 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 <cstdlib>
|
|
#include <math.h>
|
|
|
|
#include "../util.h"
|
|
|
|
#include "../luts.h"
|
|
|
|
class Oscillator {
|
|
public:
|
|
enum Mode { MODE_SINE = 0, MODE_SAW, MODE_SQUARE };
|
|
|
|
Mode const * mode;
|
|
float phase; // current waveform phase angle (radians)
|
|
float value; // current amplitude value
|
|
float driftAmount;
|
|
float driftValue;
|
|
|
|
Oscillator() : phase(randFrac()), value(0), driftAmount(0.001f), driftValue(0) {}
|
|
|
|
void assign(Mode const * mode);
|
|
|
|
// Generate next output sample and advance the phase angle
|
|
inline void tick(float* out, size_t bufferSize, float *pitch, float* gain) {
|
|
size_t frameCount = bufferSize / 2;
|
|
|
|
float driftBuf[frameCount];
|
|
for(size_t i = 0; i < frameCount; ++i) {
|
|
driftValue += 0.005f * whiteNoise() - 0.00001f * driftValue;
|
|
driftBuf[i] = 1.0f + driftAmount * driftValue;
|
|
}
|
|
float phaseStepBuf[frameCount];
|
|
for(size_t i = 0; i < frameCount; ++i) {
|
|
phaseStepBuf[i] = cvToStep(pitch[i]) * driftBuf[i];
|
|
}
|
|
|
|
float phaseBuf[frameCount];
|
|
for(size_t i = 0; i < frameCount; ++i) {
|
|
phaseBuf[i] = phase;
|
|
phase += phaseStepBuf[i];
|
|
phase -= floorf(phase);
|
|
}
|
|
|
|
if(*mode == MODE_SINE) {
|
|
for(size_t i = 0, j = 0; i < frameCount; ++i) {
|
|
float value = fastSin(phaseBuf[i]);
|
|
out[j++] += gain[j & 1] * value;
|
|
out[j++] += gain[j & 1] * value;
|
|
}
|
|
} else if(*mode == MODE_SAW) {
|
|
for(size_t i = 0, j = 0; i < frameCount; ++i) {
|
|
float value = (2.0f * phaseBuf[i]) - 1.0f; // Render naive waveshape
|
|
value -= polyBlep(phaseBuf[i], phaseStepBuf[i]); // Layer output of Poly BLEP on top
|
|
out[j++] += gain[j & 1] * value;
|
|
out[j++] += gain[j & 1] * value;
|
|
}
|
|
} else if (*mode == MODE_SQUARE) {
|
|
for(size_t i = 0, j = 0; i < frameCount; ++i) {
|
|
float value = phaseBuf[i] < 0.5f ? 1.f : -1.f; // Render naive waveshape
|
|
|
|
value += polyBlep(phaseBuf[i], phaseStepBuf[i]); // Layer output of Poly BLEP on top (flip)
|
|
value -= polyBlep(fmodf(phaseBuf[i] + 0.5f, 1.0f), phaseStepBuf[i]); // Layer output of Poly BLEP on top (flop)
|
|
|
|
out[j++] = gain[j & 1] * value;
|
|
out[j++] = gain[j & 1] * value;
|
|
}
|
|
}
|
|
}
|
|
|
|
inline float polyBlep(float t, float dt) {
|
|
// t-t^2/2 +1/2
|
|
// 0 < t <= 1
|
|
// discontinuities between 0 & 1
|
|
if(t < dt) {
|
|
t /= dt;
|
|
return t + t - t * t - 1.0f;
|
|
}
|
|
|
|
// t^2/2 +t +1/2
|
|
// -1 <= t <= 0
|
|
// discontinuities between -1 & 0
|
|
else if(t > 1.0f - dt) {
|
|
t = (t - 1.0f) / dt;
|
|
return t * t + t + t + 1.0f;
|
|
}
|
|
|
|
// no discontinuities
|
|
// 0 otherwise
|
|
else {
|
|
return 0.0;
|
|
}
|
|
}
|
|
};
|
|
|
|
#endif |