New elements and fixes
This commit is contained in:
+116
-41
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user