New elements and fixes

This commit is contained in:
Dejvino
2026-02-28 17:49:26 +01:00
parent 58af6bd3dc
commit db76f4fcef
3 changed files with 357 additions and 84 deletions
+116 -41
View File
@@ -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::WAVETABLE || n.type == GridCell::OPERATOR || n.type == GridCell::NOISE || n.type == GridCell::DELAY || n.type == GridCell::REVERB) {
if (n.type == GridCell::WIRE || n.type == GridCell::FIXED_OSCILLATOR || n.type == GridCell::INPUT_OSCILLATOR || n.type == GridCell::WAVETABLE || n.type == GridCell::NOISE || n.type == GridCell::LFO || n.type == GridCell::LPF || n.type == GridCell::HPF || n.type == GridCell::VCA || n.type == GridCell::BITCRUSHER || n.type == GridCell::DISTORTION || n.type == GridCell::GLITCH || n.type == GridCell::OPERATOR || 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;
@@ -146,6 +146,24 @@ float SynthEngine::processGridStep() {
return connects ? n.value : 0.0f;
};
// Helper to sum inputs excluding the output direction
auto getSummedInput = [&](int x, int y, GridCell& c) -> float {
float sum = 0.0f;
int outDir = c.rotation; // 0:N, 1:E, 2:S, 3:W
if (outDir != 0) sum += getInput(x, y, x, y-1);
if (outDir != 1) sum += getInput(x, y, x+1, y);
if (outDir != 2) sum += getInput(x, y, x, y+1);
if (outDir != 3) sum += getInput(x, y, x-1, y);
return sum;
};
auto getInputFromTheBack = [&](int x, int y, GridCell& c) -> float {
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;
return getInput(x, y, x+dx, y+dy);
};
for (int x = 0; x < 5; ++x) {
for (int y = 0; y < 8; ++y) {
GridCell& c = grid[x][y];
@@ -155,11 +173,7 @@ float SynthEngine::processGridStep() {
val = 0.0f;
} else if (c.type == GridCell::FIXED_OSCILLATOR) {
// Gather inputs for modulation
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 mod = getSummedInput(x, y, c);
// Freq 10 to 1000 Hz
float freq = 10.0f + c.param * 990.0f + (mod * 500.0f); // FM
@@ -170,28 +184,23 @@ float SynthEngine::processGridStep() {
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::INPUT_OSCILLATOR) {
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 mod = getSummedInput(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;
} 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 mod = getSummedInput(x, y, c);
float freq = 440.0f + (mod * 500.0f); // Fixed base freq + FM
// Track current note frequency + FM
float freq = getFrequency() + (mod * 500.0f);
if (freq < 1.0f) freq = 1.0f;
float inc = freq * (float)SINE_TABLE_SIZE / (float)_sampleRate;
@@ -220,6 +229,8 @@ float SynthEngine::processGridStep() {
break;
}
} else if (c.type == GridCell::NOISE) {
float mod = getSummedInput(x, y, c);
float white = (float)rand() / (float)RAND_MAX * 2.0f - 1.0f;
int shade = (int)(c.param * 4.99f);
switch(shade) {
@@ -243,28 +254,92 @@ float SynthEngine::processGridStep() {
val = white - c.phase; // HPF result
break;
}
// Apply Amplitude Modulation (AM) from input
val *= (1.0f + mod);
} 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;
// Output full range -1.0 to 1.0
val = (float)sine_table[(int)c.phase] / 32768.0f;
} else if (c.type == GridCell::FORK) {
// Sum inputs from "Back" (Input direction)
// Rotation is "Forward". Input is "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;
// We only read from the specific input neighbor
val = getInput(x, y, x+dx, y+dy);
val = getInputFromTheBack(x, y, c);
} else if (c.type == GridCell::WIRE) {
// Sum inputs from all neighbors that point to me
float sum = 0.0f;
sum += getInput(x, y, x, y-1); // N
sum += getInput(x, y, x+1, y); // E
sum += getInput(x, y, x, y+1); // S
sum += getInput(x, y, x-1, y); // W
float sum = getSummedInput(x, y, c);
val = sum * c.param; // Fading
} else if (c.type == GridCell::LPF) {
// Input from Back
float in = getInputFromTheBack(x, y, c);
// Simple one-pole LPF
// Cutoff mapping: Exponential-ish 20Hz to 15kHz
float cutoff = 20.0f + c.param * c.param * 15000.0f;
float alpha = 2.0f * M_PI * cutoff / (float)_sampleRate;
if (alpha > 1.0f) alpha = 1.0f;
// c.phase stores previous output
val = c.phase + alpha * (in - c.phase);
c.phase = val;
} else if (c.type == GridCell::HPF) {
// Input from Back
float in = getInputFromTheBack(x, y, c);
float cutoff = 20.0f + c.param * c.param * 15000.0f;
float alpha = 2.0f * M_PI * cutoff / (float)_sampleRate;
if (alpha > 1.0f) alpha = 1.0f;
// HPF = Input - LPF
// c.phase stores LPF state
float lpf = c.phase + alpha * (in - c.phase);
c.phase = lpf;
val = in - lpf;
} else if (c.type == GridCell::VCA) {
// Input from Back
float in = getInputFromTheBack(x, y, c);
// Mod from other directions (sum)
float mod = getSummedInput(x, y, c);
mod -= in; // Remove signal input from mod sum (it was included in getInput calls)
// Gain = Param + Mod
float gain = c.param + mod;
if (gain < 0.0f) gain = 0.0f;
val = in * gain;
} else if (c.type == GridCell::BITCRUSHER) {
float in = getInputFromTheBack(x, y, c);
// Bit depth reduction
float bits = 1.0f + c.param * 15.0f; // 1 to 16 bits
float steps = powf(2.0f, bits);
val = roundf(in * steps) / steps;
} else if (c.type == GridCell::DISTORTION) {
float in = getInputFromTheBack(x, y, c);
// Soft clipping
float drive = 1.0f + c.param * 20.0f;
float x_driven = in * drive;
// Simple soft clip: x / (1 + |x|)
val = x_driven / (1.0f + fabsf(x_driven));
} else if (c.type == GridCell::GLITCH) {
float in = getInputFromTheBack(x, y, c);
// Param controls probability of glitch
float chance = c.param * 0.2f; // 0 to 20% chance per sample
if ((float)rand() / RAND_MAX < chance) {
int mode = rand() % 3;
if (mode == 0) val = in * 50.0f; // Massive gain (clipping)
else if (mode == 1) val = (float)(rand() % 32768) / 16384.0f - 1.0f; // White noise burst
else val = 0.0f; // Drop out
} else {
val = in;
}
} else if (c.type == GridCell::DELAY) {
// 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);
float input_val = getInputFromTheBack(x, y, c);
if (c.buffer && c.buffer_size > 0) {
// Write current input to buffer
@@ -289,10 +364,7 @@ float SynthEngine::processGridStep() {
}
} 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);
float input_val = getInputFromTheBack(x, y, c);
if (c.buffer && c.buffer_size > 0) {
// Fixed delay for reverb effect (e.g. 50ms)
@@ -318,14 +390,17 @@ float SynthEngine::processGridStep() {
// Gather inputs
float inputs[4];
int count = 0;
float iN = getInput(x, y, x, y-1); if(iN!=0) inputs[count++] = iN;
float iE = getInput(x, y, x+1, y); if(iE!=0) inputs[count++] = iE;
float iS = getInput(x, y, x, y+1); if(iS!=0) inputs[count++] = iS;
float iW = getInput(x, y, x-1, y); if(iW!=0) inputs[count++] = iW;
int outDir = (c.type == GridCell::SINK) ? -1 : c.rotation;
float iN = (outDir != 0) ? getInput(x, y, x, y-1) : 0.0f; if(iN!=0) inputs[count++] = iN;
float iE = (outDir != 1) ? getInput(x, y, x+1, y) : 0.0f; if(iE!=0) inputs[count++] = iE;
float iS = (outDir != 2) ? getInput(x, y, x, y+1) : 0.0f; if(iS!=0) inputs[count++] = iS;
float iW = (outDir != 3) ? getInput(x, y, x-1, y) : 0.0f; if(iW!=0) inputs[count++] = iW;
if (c.type == GridCell::SINK) {
// Sink just sums everything
val = iN + iE + iS + iW;
val = 0.0f;
for(int k=0; k<count; ++k) val += inputs[k];
} else {
// Operator
int opType = (int)(c.param * 5.99f);