35 lines
1.3 KiB
C++
35 lines
1.3 KiB
C++
#include "synth_engine.h"
|
|
|
|
SynthEngine::SynthEngine(uint32_t sampleRate)
|
|
: _sampleRate(sampleRate),
|
|
_phase(0),
|
|
_increment(0)
|
|
{
|
|
// 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
|
|
// We use a 64-bit intermediate calculation to prevent overflow.
|
|
_increment = static_cast<uint32_t>((static_cast<uint64_t>(freq) << 32) / _sampleRate);
|
|
}
|
|
|
|
void SynthEngine::process(int16_t* buffer, uint32_t numFrames) {
|
|
for (uint32_t i = 0; i < numFrames; ++i) {
|
|
// 1. Advance the phase. Integer overflow automatically wraps it,
|
|
// which is exactly what we want for a continuous oscillator.
|
|
_phase += _increment;
|
|
|
|
// 2. Generate the sample. For a sawtooth wave, the sample value is
|
|
// directly proportional to the phase. We take the top 16 bits
|
|
// of the 32-bit phase accumulator to get a signed 16-bit sample.
|
|
int16_t sample = static_cast<int16_t>(_phase >> 16);
|
|
|
|
// 3. Write the sample to the buffer.
|
|
buffer[i] = sample;
|
|
}
|
|
} |