Wavetable and reverb
This commit is contained in:
+63
-1
@@ -118,7 +118,7 @@ float SynthEngine::processGridStep() {
|
||||
|
||||
// Check if neighbor outputs to (tx, ty)
|
||||
bool connects = false;
|
||||
if (n.type == GridCell::WIRE || n.type == GridCell::FIXED_OSCILLATOR || n.type == GridCell::INPUT_OSCILLATOR || n.type == GridCell::OPERATOR || n.type == GridCell::NOISE || n.type == GridCell::DELAY) {
|
||||
if (n.type == GridCell::WIRE || n.type == GridCell::FIXED_OSCILLATOR || n.type == GridCell::INPUT_OSCILLATOR || n.type == GridCell::WAVETABLE || n.type == GridCell::OPERATOR || n.type == GridCell::NOISE || n.type == GridCell::DELAY || n.type == GridCell::REVERB) {
|
||||
// Check rotation
|
||||
// 0:N (y-1), 1:E (x+1), 2:S (y+1), 3:W (x-1)
|
||||
if (n.rotation == 0 && from_y - 1 == ty && from_x == tx) connects = true;
|
||||
@@ -184,6 +184,41 @@ float SynthEngine::processGridStep() {
|
||||
c.phase += inc;
|
||||
if (c.phase >= SINE_TABLE_SIZE) c.phase -= SINE_TABLE_SIZE;
|
||||
val = (float)sine_table[(int)c.phase] / 32768.0f;
|
||||
} else if (c.type == GridCell::WAVETABLE) {
|
||||
float mod = 0.0f;
|
||||
mod += getInput(x, y, x, y-1);
|
||||
mod += getInput(x, y, x+1, y);
|
||||
mod += getInput(x, y, x, y+1);
|
||||
mod += getInput(x, y, x-1, y);
|
||||
|
||||
float freq = 440.0f + (mod * 500.0f); // Fixed base freq + 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;
|
||||
|
||||
float phase_norm = c.phase / (float)SINE_TABLE_SIZE; // 0.0 to 1.0
|
||||
int wave_select = (int)(c.param * 7.99f);
|
||||
|
||||
switch(wave_select) {
|
||||
case 0: val = (float)sine_table[(int)c.phase] / 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
|
||||
case 4: val = 1.0f - (phase_norm * 2.0f); break; // Ramp
|
||||
case 5: val = (phase_norm < 0.25f) ? 1.0f : -1.0f; break; // Pulse 25%
|
||||
case 6: // Distorted Sine
|
||||
val = sin(phase_norm * 2.0 * M_PI) + sin(phase_norm * 4.0 * M_PI) * 0.3f;
|
||||
val /= 1.3f; // Normalize
|
||||
break;
|
||||
case 7: // Organ-like
|
||||
val = sin(phase_norm * 2.0 * M_PI) * 0.6f +
|
||||
sin(phase_norm * 4.0 * M_PI) * 0.2f +
|
||||
sin(phase_norm * 8.0 * M_PI) * 0.1f;
|
||||
val /= 0.9f; // Normalize
|
||||
break;
|
||||
}
|
||||
} else if (c.type == GridCell::NOISE) {
|
||||
float white = (float)rand() / (float)RAND_MAX * 2.0f - 1.0f;
|
||||
int shade = (int)(c.param * 4.99f);
|
||||
@@ -252,6 +287,33 @@ float SynthEngine::processGridStep() {
|
||||
} else {
|
||||
val = 0.0f; // No buffer, no output
|
||||
}
|
||||
} else if (c.type == GridCell::REVERB) {
|
||||
// Input is from the "Back" (rot+2)
|
||||
int inDir = (c.rotation + 2) % 4;
|
||||
int dx=0, dy=0;
|
||||
if(inDir==0) dy=-1; else if(inDir==1) dx=1; else if(inDir==2) dy=1; else dx=-1;
|
||||
float input_val = getInput(x, y, x+dx, y+dy);
|
||||
|
||||
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