Optimize more by avoiding floating point
This commit is contained in:
parent
8cc8898c01
commit
534a7512c4
@ -12,7 +12,7 @@ const int I2S_LRC_PIN = 10; // Left-Right Clock (GP10)
|
|||||||
const int I2S_DOUT_PIN = 11; // Data Out (GP11)
|
const int I2S_DOUT_PIN = 11; // Data Out (GP11)
|
||||||
|
|
||||||
// Audio parameters
|
// Audio parameters
|
||||||
const int SAMPLE_RATE = 44100 / 2 / 2 / 2;
|
const int SAMPLE_RATE = 44100 / 4;
|
||||||
const int16_t AMPLITUDE = 16383 / 2; // Use a lower amplitude to avoid clipping (max is 32767 for 16-bit)
|
const int16_t AMPLITUDE = 16383 / 2; // Use a lower amplitude to avoid clipping (max is 32767 for 16-bit)
|
||||||
|
|
||||||
// Create an I2S output object
|
// Create an I2S output object
|
||||||
|
|||||||
@ -28,6 +28,7 @@ SynthEngine::SynthEngine(uint32_t sampleRate)
|
|||||||
_volume(0.5f),
|
_volume(0.5f),
|
||||||
_waveform(SAWTOOTH),
|
_waveform(SAWTOOTH),
|
||||||
_isGateOpen(false),
|
_isGateOpen(false),
|
||||||
|
_freqToPhaseInc(0.0f),
|
||||||
_rngState(12345)
|
_rngState(12345)
|
||||||
{
|
{
|
||||||
fill_sine_table();
|
fill_sine_table();
|
||||||
@ -35,6 +36,7 @@ SynthEngine::SynthEngine(uint32_t sampleRate)
|
|||||||
setFrequency(440.0f);
|
setFrequency(440.0f);
|
||||||
|
|
||||||
// Initialize SINK
|
// Initialize SINK
|
||||||
|
_freqToPhaseInc = 4294967296.0f / (float)_sampleRate;
|
||||||
grid[GRID_W / 2][GRID_H - 1].type = GridCell::SINK;
|
grid[GRID_W / 2][GRID_H - 1].type = GridCell::SINK;
|
||||||
rebuildProcessingOrder();
|
rebuildProcessingOrder();
|
||||||
}
|
}
|
||||||
@ -92,6 +94,7 @@ int SynthEngine::importGrid(const uint8_t* buffer, size_t size) {
|
|||||||
c.rotation = 0;
|
c.rotation = 0;
|
||||||
c.value = 0.0f;
|
c.value = 0.0f;
|
||||||
c.phase = 0.0f;
|
c.phase = 0.0f;
|
||||||
|
c.phase_accumulator = 0;
|
||||||
c.next_value = 0.0f;
|
c.next_value = 0.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,6 +130,7 @@ void SynthEngine::clearGrid() {
|
|||||||
c.rotation = 0;
|
c.rotation = 0;
|
||||||
c.value = 0.0f;
|
c.value = 0.0f;
|
||||||
c.phase = 0.0f;
|
c.phase = 0.0f;
|
||||||
|
c.phase_accumulator = 0;
|
||||||
c.next_value = 0.0f;
|
c.next_value = 0.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -446,45 +450,45 @@ float SynthEngine::processGridStep() {
|
|||||||
// Gather inputs for modulation
|
// Gather inputs for modulation
|
||||||
float mod = getInputFromTheBack(x, y, c);
|
float mod = getInputFromTheBack(x, y, c);
|
||||||
|
|
||||||
// Freq 10 to 1000 Hz
|
// Freq 10 to 1000 Hz.
|
||||||
float freq = 10.0f + c.param * 990.0f + (mod * 500.0f); // FM
|
float freq = 10.0f + c.param * 990.0f + (mod * 500.0f); // FM
|
||||||
if (freq < 1.0f) freq = 1.0f;
|
if (freq < 1.0f) freq = 1.0f;
|
||||||
|
|
||||||
float inc = freq * (float)SINE_TABLE_SIZE / (float)_sampleRate;
|
// Fixed point phase accumulation
|
||||||
c.phase += inc;
|
uint32_t inc = (uint32_t)(freq * _freqToPhaseInc);
|
||||||
if (c.phase >= SINE_TABLE_SIZE) c.phase -= SINE_TABLE_SIZE;
|
c.phase_accumulator += inc;
|
||||||
val = (float)sine_table[(int)c.phase] / 32768.0f;
|
// Top 8 bits of 32-bit accumulator form the 256-entry table index
|
||||||
|
val = (float)sine_table[c.phase_accumulator >> 24] / 32768.0f;
|
||||||
val *= getSideInputGain(x, y, c);
|
val *= getSideInputGain(x, y, c);
|
||||||
} else if (c.type == GridCell::INPUT_OSCILLATOR) {
|
} else if (c.type == GridCell::INPUT_OSCILLATOR) {
|
||||||
float mod = getInputFromTheBack(x, y, c);
|
float mod = getInputFromTheBack(x, y, c);
|
||||||
|
|
||||||
// Freq based on current note + octave param (1-5)
|
// Freq based on current note + octave param (1-5)
|
||||||
float baseFreq = getFrequency();
|
|
||||||
int octave = 1 + (int)(c.param * 4.99f); // Map 0.0-1.0 to 1-5
|
int octave = 1 + (int)(c.param * 4.99f); // Map 0.0-1.0 to 1-5
|
||||||
float freq = baseFreq * (float)(1 << (octave - 1)); // 2^(octave-1)
|
|
||||||
freq += (mod * 500.0f); // Apply FM
|
// Use the engine's global increment directly to avoid float conversion round-trip
|
||||||
if (freq < 1.0f) freq = 1.0f; // Protect against negative/zero freq
|
uint32_t baseInc = _increment;
|
||||||
float inc = freq * (float)SINE_TABLE_SIZE / (float)_sampleRate;
|
uint32_t inc = baseInc << (octave - 1);
|
||||||
c.phase += inc;
|
|
||||||
if (c.phase >= SINE_TABLE_SIZE) c.phase -= SINE_TABLE_SIZE;
|
// Apply FM (mod is float, convert to fixed point increment)
|
||||||
val = (float)sine_table[(int)c.phase] / 32768.0f;
|
inc += (int32_t)(mod * 500.0f * _freqToPhaseInc);
|
||||||
|
|
||||||
|
c.phase_accumulator += inc;
|
||||||
|
val = (float)sine_table[c.phase_accumulator >> 24] / 32768.0f;
|
||||||
val *= getSideInputGain(x, y, c);
|
val *= getSideInputGain(x, y, c);
|
||||||
} else if (c.type == GridCell::WAVETABLE) {
|
} else if (c.type == GridCell::WAVETABLE) {
|
||||||
float mod = getInputFromTheBack(x, y, c);
|
float mod = getInputFromTheBack(x, y, c);
|
||||||
|
|
||||||
// Track current note frequency + FM
|
// Track current note frequency + FM. Use direct increment for speed.
|
||||||
float freq = getFrequency() + (mod * 500.0f);
|
uint32_t inc = _increment + (int32_t)(mod * 500.0f * _freqToPhaseInc);
|
||||||
if (freq < 1.0f) freq = 1.0f;
|
c.phase_accumulator += inc;
|
||||||
|
|
||||||
float inc = freq * (float)SINE_TABLE_SIZE / (float)_sampleRate;
|
// 0.0 to 1.0 representation for math-based waveforms
|
||||||
c.phase += inc;
|
float phase_norm = (float)c.phase_accumulator / 4294967296.0f;
|
||||||
if (c.phase >= SINE_TABLE_SIZE) c.phase -= SINE_TABLE_SIZE;
|
|
||||||
|
|
||||||
float phase_norm = c.phase / (float)SINE_TABLE_SIZE; // 0.0 to 1.0
|
|
||||||
int wave_select = (int)(c.param * 7.99f);
|
int wave_select = (int)(c.param * 7.99f);
|
||||||
|
|
||||||
switch(wave_select) {
|
switch(wave_select) {
|
||||||
case 0: val = (float)sine_table[(int)c.phase] / 32768.0f; break;
|
case 0: val = (float)sine_table[c.phase_accumulator >> 24] / 32768.0f; break;
|
||||||
case 1: val = (phase_norm * 2.0f) - 1.0f; break; // Saw
|
case 1: val = (phase_norm * 2.0f) - 1.0f; break; // Saw
|
||||||
case 2: val = (phase_norm < 0.5f) ? 1.0f : -1.0f; break; // Square
|
case 2: val = (phase_norm < 0.5f) ? 1.0f : -1.0f; break; // Square
|
||||||
case 3: val = (phase_norm < 0.5f) ? (phase_norm * 4.0f - 1.0f) : (3.0f - phase_norm * 4.0f); break; // Triangle
|
case 3: val = (phase_norm < 0.5f) ? (phase_norm * 4.0f - 1.0f) : (3.0f - phase_norm * 4.0f); break; // Triangle
|
||||||
@ -535,11 +539,10 @@ float SynthEngine::processGridStep() {
|
|||||||
} else if (c.type == GridCell::LFO) {
|
} else if (c.type == GridCell::LFO) {
|
||||||
// Low Frequency Oscillator (0.1 Hz to 20 Hz)
|
// Low Frequency Oscillator (0.1 Hz to 20 Hz)
|
||||||
float freq = 0.1f + c.param * 19.9f;
|
float freq = 0.1f + c.param * 19.9f;
|
||||||
float inc = freq * (float)SINE_TABLE_SIZE / (float)_sampleRate;
|
uint32_t inc = (uint32_t)(freq * _freqToPhaseInc);
|
||||||
c.phase += inc;
|
c.phase_accumulator += inc;
|
||||||
if (c.phase >= SINE_TABLE_SIZE) c.phase -= SINE_TABLE_SIZE;
|
|
||||||
// Output full range -1.0 to 1.0
|
// Output full range -1.0 to 1.0
|
||||||
val = (float)sine_table[(int)c.phase] / 32768.0f;
|
val = (float)sine_table[c.phase_accumulator >> 24] / 32768.0f;
|
||||||
} else if (c.type == GridCell::FORK) {
|
} else if (c.type == GridCell::FORK) {
|
||||||
// Sum inputs from "Back" (Input direction)
|
// Sum inputs from "Back" (Input direction)
|
||||||
val = getInputFromTheBack(x, y, c);
|
val = getInputFromTheBack(x, y, c);
|
||||||
|
|||||||
@ -107,6 +107,7 @@ public:
|
|||||||
float value = 0.0f; // Current output sample
|
float value = 0.0f; // Current output sample
|
||||||
float next_value = 0.0f; // For double-buffering in processGridStep
|
float next_value = 0.0f; // For double-buffering in processGridStep
|
||||||
float phase = 0.0f; // For Oscillator, Noise state
|
float phase = 0.0f; // For Oscillator, Noise state
|
||||||
|
uint32_t phase_accumulator = 0; // For Oscillators (Fixed point optimization)
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int GRID_W = 12;
|
static const int GRID_W = 12;
|
||||||
@ -131,6 +132,7 @@ private:
|
|||||||
uint32_t _increment; // Phase increment per sample, determines frequency.
|
uint32_t _increment; // Phase increment per sample, determines frequency.
|
||||||
float _volume;
|
float _volume;
|
||||||
Waveform _waveform;
|
Waveform _waveform;
|
||||||
|
float _freqToPhaseInc; // Pre-calculated constant for frequency to phase increment conversion
|
||||||
bool _isGateOpen;
|
bool _isGateOpen;
|
||||||
uint32_t _rngState;
|
uint32_t _rngState;
|
||||||
std::vector<std::pair<int, int>> _processing_order;
|
std::vector<std::pair<int, int>> _processing_order;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user