84 lines
2.5 KiB
C++
84 lines
2.5 KiB
C++
#include "synth_engine.h"
|
|
#include <math.h>
|
|
|
|
// A simple sine lookup table for the sine oscillator
|
|
const int SINE_TABLE_SIZE = 256;
|
|
static int16_t sine_table[SINE_TABLE_SIZE];
|
|
static bool sine_table_filled = false;
|
|
|
|
/**
|
|
* @brief Fills the global sine table. Called once on startup.
|
|
*/
|
|
void fill_sine_table() {
|
|
if (sine_table_filled) return;
|
|
for (int i = 0; i < SINE_TABLE_SIZE; ++i) {
|
|
// M_PI is not standard C++, but it's common. If it fails, use 3.1415926535...
|
|
sine_table[i] = static_cast<int16_t>(sin(2.0 * M_PI * i / SINE_TABLE_SIZE) * 32767.0);
|
|
}
|
|
sine_table_filled = true;
|
|
}
|
|
|
|
SynthEngine::SynthEngine(uint32_t sampleRate)
|
|
: _sampleRate(sampleRate),
|
|
_phase(0),
|
|
_increment(0),
|
|
_volume(0.5f),
|
|
_waveform(SAWTOOTH),
|
|
_isGateOpen(false)
|
|
{
|
|
fill_sine_table();
|
|
// Initialize with a default frequency
|
|
setFrequency(440.0f);
|
|
}
|
|
|
|
void SynthEngine::setFrequency(float freq) {
|
|
// Calculate the phase increment for a given frequency.
|
|
// The phase accumulator is a 32-bit unsigned integer (0 to 2^32-1).
|
|
// One full cycle of the accumulator represents one cycle of the waveform.
|
|
// increment = (frequency * 2^32) / sampleRate
|
|
// The original calculation was incorrect for float frequencies.
|
|
_increment = static_cast<uint32_t>((double)freq * (4294967296.0 / (double)_sampleRate));
|
|
}
|
|
|
|
void SynthEngine::setVolume(float vol) {
|
|
if (vol < 0.0f) vol = 0.0f;
|
|
if (vol > 1.0f) vol = 1.0f;
|
|
_volume = vol;
|
|
}
|
|
|
|
void SynthEngine::setWaveform(Waveform form) {
|
|
_waveform = form;
|
|
}
|
|
|
|
void SynthEngine::setGate(bool isOpen) {
|
|
_isGateOpen = isOpen;
|
|
}
|
|
|
|
float SynthEngine::getFrequency() const {
|
|
return (float)((double)_increment * (double)_sampleRate / 4294967296.0);
|
|
}
|
|
|
|
void SynthEngine::process(int16_t* buffer, uint32_t numFrames) {
|
|
for (uint32_t i = 0; i < numFrames; ++i) {
|
|
_phase += _increment;
|
|
|
|
int16_t sample = 0;
|
|
if (_isGateOpen) {
|
|
switch (_waveform) {
|
|
case SAWTOOTH:
|
|
sample = static_cast<int16_t>(_phase >> 16);
|
|
break;
|
|
case SQUARE:
|
|
sample = (_phase < 0x80000000) ? 32767 : -32768;
|
|
break;
|
|
case SINE:
|
|
// Use top 8 bits of phase as index into sine table
|
|
sample = sine_table[(_phase >> 24) & 0xFF];
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Apply volume and write to buffer
|
|
buffer[i] = static_cast<int16_t>(sample * _volume);
|
|
}
|
|
} |