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)
|
||||
|
||||
// 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)
|
||||
|
||||
// Create an I2S output object
|
||||
|
||||
@ -28,6 +28,7 @@ SynthEngine::SynthEngine(uint32_t sampleRate)
|
||||
_volume(0.5f),
|
||||
_waveform(SAWTOOTH),
|
||||
_isGateOpen(false),
|
||||
_freqToPhaseInc(0.0f),
|
||||
_rngState(12345)
|
||||
{
|
||||
fill_sine_table();
|
||||
@ -35,6 +36,7 @@ SynthEngine::SynthEngine(uint32_t sampleRate)
|
||||
setFrequency(440.0f);
|
||||
|
||||
// Initialize SINK
|
||||
_freqToPhaseInc = 4294967296.0f / (float)_sampleRate;
|
||||
grid[GRID_W / 2][GRID_H - 1].type = GridCell::SINK;
|
||||
rebuildProcessingOrder();
|
||||
}
|
||||
@ -92,6 +94,7 @@ int SynthEngine::importGrid(const uint8_t* buffer, size_t size) {
|
||||
c.rotation = 0;
|
||||
c.value = 0.0f;
|
||||
c.phase = 0.0f;
|
||||
c.phase_accumulator = 0;
|
||||
c.next_value = 0.0f;
|
||||
}
|
||||
}
|
||||
@ -127,6 +130,7 @@ void SynthEngine::clearGrid() {
|
||||
c.rotation = 0;
|
||||
c.value = 0.0f;
|
||||
c.phase = 0.0f;
|
||||
c.phase_accumulator = 0;
|
||||
c.next_value = 0.0f;
|
||||
}
|
||||
}
|
||||
@ -446,45 +450,45 @@ float SynthEngine::processGridStep() {
|
||||
// Gather inputs for modulation
|
||||
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
|
||||
if (freq < 1.0f) freq = 1.0f;
|
||||
|
||||
float inc = freq * (float)SINE_TABLE_SIZE / (float)_sampleRate;
|
||||
c.phase += inc;
|
||||
if (c.phase >= SINE_TABLE_SIZE) c.phase -= SINE_TABLE_SIZE;
|
||||
val = (float)sine_table[(int)c.phase] / 32768.0f;
|
||||
// Fixed point phase accumulation
|
||||
uint32_t inc = (uint32_t)(freq * _freqToPhaseInc);
|
||||
c.phase_accumulator += inc;
|
||||
// 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);
|
||||
} else if (c.type == GridCell::INPUT_OSCILLATOR) {
|
||||
float mod = getInputFromTheBack(x, y, c);
|
||||
|
||||
// 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
|
||||
float freq = baseFreq * (float)(1 << (octave - 1)); // 2^(octave-1)
|
||||
freq += (mod * 500.0f); // Apply FM
|
||||
if (freq < 1.0f) freq = 1.0f; // Protect against negative/zero freq
|
||||
float inc = freq * (float)SINE_TABLE_SIZE / (float)_sampleRate;
|
||||
c.phase += inc;
|
||||
if (c.phase >= SINE_TABLE_SIZE) c.phase -= SINE_TABLE_SIZE;
|
||||
val = (float)sine_table[(int)c.phase] / 32768.0f;
|
||||
|
||||
// Use the engine's global increment directly to avoid float conversion round-trip
|
||||
uint32_t baseInc = _increment;
|
||||
uint32_t inc = baseInc << (octave - 1);
|
||||
|
||||
// Apply FM (mod is float, convert to fixed point increment)
|
||||
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);
|
||||
} else if (c.type == GridCell::WAVETABLE) {
|
||||
float mod = getInputFromTheBack(x, y, c);
|
||||
|
||||
// Track current note frequency + FM
|
||||
float freq = getFrequency() + (mod * 500.0f);
|
||||
if (freq < 1.0f) freq = 1.0f;
|
||||
// Track current note frequency + FM. Use direct increment for speed.
|
||||
uint32_t inc = _increment + (int32_t)(mod * 500.0f * _freqToPhaseInc);
|
||||
c.phase_accumulator += inc;
|
||||
|
||||
float inc = freq * (float)SINE_TABLE_SIZE / (float)_sampleRate;
|
||||
c.phase += inc;
|
||||
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
|
||||
// 0.0 to 1.0 representation for math-based waveforms
|
||||
float phase_norm = (float)c.phase_accumulator / 4294967296.0f;
|
||||
int wave_select = (int)(c.param * 7.99f);
|
||||
|
||||
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 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
|
||||
@ -535,11 +539,10 @@ float SynthEngine::processGridStep() {
|
||||
} else if (c.type == GridCell::LFO) {
|
||||
// Low Frequency Oscillator (0.1 Hz to 20 Hz)
|
||||
float freq = 0.1f + c.param * 19.9f;
|
||||
float inc = freq * (float)SINE_TABLE_SIZE / (float)_sampleRate;
|
||||
c.phase += inc;
|
||||
if (c.phase >= SINE_TABLE_SIZE) c.phase -= SINE_TABLE_SIZE;
|
||||
uint32_t inc = (uint32_t)(freq * _freqToPhaseInc);
|
||||
c.phase_accumulator += inc;
|
||||
// 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) {
|
||||
// Sum inputs from "Back" (Input direction)
|
||||
val = getInputFromTheBack(x, y, c);
|
||||
|
||||
@ -107,6 +107,7 @@ public:
|
||||
float value = 0.0f; // Current output sample
|
||||
float next_value = 0.0f; // For double-buffering in processGridStep
|
||||
float phase = 0.0f; // For Oscillator, Noise state
|
||||
uint32_t phase_accumulator = 0; // For Oscillators (Fixed point optimization)
|
||||
};
|
||||
|
||||
static const int GRID_W = 12;
|
||||
@ -131,6 +132,7 @@ private:
|
||||
uint32_t _increment; // Phase increment per sample, determines frequency.
|
||||
float _volume;
|
||||
Waveform _waveform;
|
||||
float _freqToPhaseInc; // Pre-calculated constant for frequency to phase increment conversion
|
||||
bool _isGateOpen;
|
||||
uint32_t _rngState;
|
||||
std::vector<std::pair<int, int>> _processing_order;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user