Optimizations 1
This commit is contained in:
+5
-117
@@ -1,5 +1,6 @@
|
||||
#include "synth_engine.h"
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
// A simple sine lookup table for the sine oscillator
|
||||
const int SINE_TABLE_SIZE = 256;
|
||||
@@ -37,14 +38,6 @@ SynthEngine::SynthEngine(uint32_t sampleRate)
|
||||
}
|
||||
|
||||
SynthEngine::~SynthEngine() {
|
||||
for (int x = 0; x < GRID_W; ++x) {
|
||||
for (int y = 0; y < GRID_H; ++y) {
|
||||
if (grid[x][y].buffer) {
|
||||
delete[] grid[x][y].buffer;
|
||||
grid[x][y].buffer = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SynthEngine::exportGrid(uint8_t* buffer) {
|
||||
@@ -62,6 +55,7 @@ void SynthEngine::exportGrid(uint8_t* buffer) {
|
||||
|
||||
void SynthEngine::importGrid(const uint8_t* buffer) {
|
||||
SynthLockGuard<SynthMutex> lock(gridMutex);
|
||||
|
||||
size_t idx = 0;
|
||||
for(int y=0; y<GRID_H; ++y) {
|
||||
for(int x=0; x<GRID_W; ++x) {
|
||||
@@ -71,15 +65,7 @@ void SynthEngine::importGrid(const uint8_t* buffer) {
|
||||
uint8_t r = buffer[idx++];
|
||||
|
||||
GridCell::Type newType = (GridCell::Type)t;
|
||||
if (c.type != newType) {
|
||||
if (c.buffer) { delete[] c.buffer; c.buffer = nullptr; c.buffer_size = 0; }
|
||||
c.type = newType;
|
||||
if (c.type == GridCell::DELAY || c.type == GridCell::REVERB || c.type == GridCell::PITCH_SHIFTER) {
|
||||
c.buffer_size = 2 * _sampleRate;
|
||||
c.buffer = new float[c.buffer_size]();
|
||||
c.write_idx = 0;
|
||||
}
|
||||
}
|
||||
c.type = newType;
|
||||
c.param = (float)p / 255.0f;
|
||||
c.rotation = r;
|
||||
}
|
||||
@@ -93,11 +79,6 @@ void SynthEngine::clearGrid() {
|
||||
GridCell& c = grid[x][y];
|
||||
if (c.type == GridCell::SINK) continue;
|
||||
|
||||
if (c.buffer) {
|
||||
delete[] c.buffer;
|
||||
c.buffer = nullptr;
|
||||
c.buffer_size = 0;
|
||||
}
|
||||
c.type = GridCell::EMPTY;
|
||||
c.param = 0.5f;
|
||||
c.rotation = 0;
|
||||
@@ -257,8 +238,8 @@ float SynthEngine::_random() {
|
||||
|
||||
float SynthEngine::processGridStep() {
|
||||
// Double buffer for values to handle feedback loops gracefully (1-sample delay)
|
||||
float next_values[GRID_W][GRID_H];
|
||||
|
||||
static float next_values[GRID_W][GRID_H];
|
||||
|
||||
auto isConnected = [&](int tx, int ty, int from_x, int from_y) -> bool {
|
||||
if (from_x < 0 || from_x >= GRID_W || from_y < 0 || from_y >= GRID_H) return false;
|
||||
GridCell& n = grid[from_x][from_y];
|
||||
@@ -545,50 +526,6 @@ float SynthEngine::processGridStep() {
|
||||
// Mix between original and rectified based on param
|
||||
float rect = fabsf(in);
|
||||
val = in * (1.0f - c.param) + rect * c.param;
|
||||
} else if (c.type == GridCell::PITCH_SHIFTER) {
|
||||
float in = getInputFromTheBack(x, y, c);
|
||||
if (c.buffer && c.buffer_size > 0) {
|
||||
c.buffer[c.write_idx] = in;
|
||||
|
||||
// Granular pitch shift
|
||||
// Pitch ratio: 0.5 to 2.0
|
||||
float pitchRatio = 0.5f + c.param * 1.5f;
|
||||
// Delay rate change: 1.0 - pitchRatio
|
||||
// If pitch=1, rate=0 (delay constant). If pitch=2, rate=-1 (delay decreases).
|
||||
float rate = 1.0f - pitchRatio;
|
||||
|
||||
c.phase += rate;
|
||||
// Wrap phase within window (e.g. 4096 samples)
|
||||
float windowSize = 4096.0f;
|
||||
if (c.phase >= windowSize) c.phase -= windowSize;
|
||||
if (c.phase < 0.0f) c.phase += windowSize;
|
||||
|
||||
// Read from buffer
|
||||
// Simple crossfade windowing would be better, but for now just a single tap with moving delay
|
||||
// To reduce clicks, we really need 2 taps. Let's stick to single tap for simplicity in this grid context, or maybe just a vibrato if rate is LFO?
|
||||
// Actually, let's implement the 2-tap crossfade for quality.
|
||||
// Tap 1
|
||||
float p1 = c.phase;
|
||||
float p2 = c.phase + windowSize * 0.5f;
|
||||
if (p2 >= windowSize) p2 -= windowSize;
|
||||
|
||||
// Window function (Triangle)
|
||||
auto getWindow = [&](float p) -> float {
|
||||
return 1.0f - fabsf(2.0f * (p / windowSize) - 1.0f);
|
||||
};
|
||||
|
||||
// Read indices
|
||||
int r1 = (int)c.write_idx - (int)p1;
|
||||
if (r1 < 0) r1 += c.buffer_size;
|
||||
int r2 = (int)c.write_idx - (int)p2;
|
||||
if (r2 < 0) r2 += c.buffer_size;
|
||||
|
||||
val = c.buffer[r1] * getWindow(p1) + c.buffer[r2] * getWindow(p2);
|
||||
|
||||
c.write_idx = (c.write_idx + 1) % c.buffer_size;
|
||||
} else {
|
||||
val = 0.0f;
|
||||
}
|
||||
} else if (c.type == GridCell::GLITCH) {
|
||||
float in = getInputFromTheBack(x, y, c);
|
||||
// Param controls probability of glitch
|
||||
@@ -601,55 +538,6 @@ float SynthEngine::processGridStep() {
|
||||
} else {
|
||||
val = in;
|
||||
}
|
||||
} else if (c.type == GridCell::DELAY) {
|
||||
// Input is from the "Back" (rot+2)
|
||||
float input_val = getInputFromTheBack(x, y, c);
|
||||
|
||||
if (c.buffer && c.buffer_size > 0) {
|
||||
// Write current input to buffer
|
||||
c.buffer[c.write_idx] = input_val;
|
||||
|
||||
// Calculate read index based on parameter. Max delay is buffer_size.
|
||||
uint32_t delay_samples = c.param * (c.buffer_size - 1);
|
||||
|
||||
// Using modulo for wraparound. Need to handle negative result from subtraction.
|
||||
int read_idx = (int)c.write_idx - (int)delay_samples;
|
||||
if (read_idx < 0) {
|
||||
read_idx += c.buffer_size;
|
||||
}
|
||||
|
||||
// Read delayed value for output
|
||||
val = c.buffer[read_idx];
|
||||
|
||||
// Increment write index
|
||||
c.write_idx = (c.write_idx + 1) % c.buffer_size;
|
||||
} else {
|
||||
val = 0.0f; // No buffer, no output
|
||||
}
|
||||
} else if (c.type == GridCell::REVERB) {
|
||||
// Input is from the "Back" (rot+2)
|
||||
float input_val = getInputFromTheBack(x, y, c);
|
||||
|
||||
if (c.buffer && c.buffer_size > 0) {
|
||||
// Fixed delay for reverb effect (e.g. 50ms)
|
||||
uint32_t delay_samples = (uint32_t)(0.05f * _sampleRate);
|
||||
if (delay_samples >= c.buffer_size) delay_samples = c.buffer_size - 1;
|
||||
|
||||
int read_idx = (int)c.write_idx - (int)delay_samples;
|
||||
if (read_idx < 0) read_idx += c.buffer_size;
|
||||
|
||||
float delayed = c.buffer[read_idx];
|
||||
// Feedback controlled by param (0.0 to 0.95)
|
||||
float feedback = c.param * 0.95f;
|
||||
float newValue = input_val + delayed * feedback;
|
||||
|
||||
c.buffer[c.write_idx] = newValue;
|
||||
val = newValue;
|
||||
|
||||
c.write_idx = (c.write_idx + 1) % c.buffer_size;
|
||||
} else {
|
||||
val = 0.0f;
|
||||
}
|
||||
} else if (c.type == GridCell::OPERATOR || c.type == GridCell::SINK) {
|
||||
// Gather inputs
|
||||
float inputs[4];
|
||||
|
||||
Reference in New Issue
Block a user