DX7 capability

This commit is contained in:
Dejvino 2026-02-28 19:41:35 +01:00
parent 7ff85048df
commit 0cecb05044
3 changed files with 207 additions and 55 deletions

233
main.cpp
View File

@ -14,10 +14,11 @@
// --- Configuration --- // --- Configuration ---
const uint32_t SAMPLE_RATE = 44100; const uint32_t SAMPLE_RATE = 44100;
const uint32_t CHANNELS = 1; // Mono const uint32_t CHANNELS = 1; // Mono
const int GRID_PANEL_WIDTH = 400; const int CELL_SIZE = 60;
const int GRID_PANEL_WIDTH = 12 * CELL_SIZE; // 720
const int SYNTH_PANEL_WIDTH = 800; const int SYNTH_PANEL_WIDTH = 800;
const int WINDOW_WIDTH = GRID_PANEL_WIDTH + SYNTH_PANEL_WIDTH; // 1200 const int WINDOW_WIDTH = GRID_PANEL_WIDTH + SYNTH_PANEL_WIDTH; // 1200
const int WINDOW_HEIGHT = 640; const int WINDOW_HEIGHT = 12 * CELL_SIZE; // 720
// --- Visualization Buffer --- // --- Visualization Buffer ---
const size_t VIS_BUFFER_SIZE = 8192; const size_t VIS_BUFFER_SIZE = 8192;
@ -36,6 +37,7 @@ int current_key_scancode = 0; // 0 for none
bool auto_melody_enabled = false; bool auto_melody_enabled = false;
Uint32 auto_melody_next_event_time = 0; Uint32 auto_melody_next_event_time = 0;
const int c_major_scale[] = {0, 2, 4, 5, 7, 9, 11, 12}; // Semitones from root const int c_major_scale[] = {0, 2, 4, 5, 7, 9, 11, 12}; // Semitones from root
int current_preset = 0;
float note_to_freq(int octave, int semitone_offset); float note_to_freq(int octave, int semitone_offset);
@ -243,6 +245,45 @@ void drawParamBar(SDL_Renderer* renderer, int x, int y, int size, float value, u
SDL_RenderFillRect(renderer, &fg); SDL_RenderFillRect(renderer, &fg);
} }
void drawDirectionArrow(SDL_Renderer* renderer, int cx, int cy, int size, int rotation) {
int r = size / 2 - 2;
int tipX = cx;
int tipY = cy;
switch(rotation) {
case 0: tipY -= r; break; // N
case 1: tipX += r; break; // E
case 2: tipY += r; break; // S
case 3: tipX -= r; break; // W
}
int arrowSize = 5;
int x1, y1, x2, y2, x3, y3;
if (rotation == 0) { // N
x1 = tipX; y1 = tipY;
x2 = tipX - arrowSize; y2 = tipY + arrowSize;
x3 = tipX + arrowSize; y3 = tipY + arrowSize;
} else if (rotation == 1) { // E
x1 = tipX; y1 = tipY;
x2 = tipX - arrowSize; y2 = tipY - arrowSize;
x3 = tipX - arrowSize; y3 = tipY + arrowSize;
} else if (rotation == 2) { // S
x1 = tipX; y1 = tipY;
x2 = tipX - arrowSize; y2 = tipY - arrowSize;
x3 = tipX + arrowSize; y3 = tipY - arrowSize;
} else { // W
x1 = tipX; y1 = tipY;
x2 = tipX + arrowSize; y2 = tipY - arrowSize;
x3 = tipX + arrowSize; y3 = tipY + arrowSize;
}
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
SDL_RenderDrawLine(renderer, x1, y1, x2, y2);
SDL_RenderDrawLine(renderer, x2, y2, x3, y3);
SDL_RenderDrawLine(renderer, x3, y3, x1, y1);
}
void drawTypeLabel(SDL_Renderer* renderer, int x, int y, char c) { void drawTypeLabel(SDL_Renderer* renderer, int x, int y, char c) {
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255); SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
drawChar(renderer, x + 3, y + 3, 8, c); drawChar(renderer, x + 3, y + 3, 8, c);
@ -280,11 +321,7 @@ void drawGridCell(SDL_Renderer* renderer, int x, int y, int size, SynthEngine::G
if (cell.rotation == 2) dy = r; if (cell.rotation == 2) dy = r;
if (cell.rotation == 3) dx = -r; if (cell.rotation == 3) dx = -r;
SDL_RenderDrawLine(renderer, cx, cy, cx+dx, cy+dy); SDL_RenderDrawLine(renderer, cx, cy, cx+dx, cy+dy);
// Param (Fading) drawDirectionArrow(renderer, cx, cy, size, cell.rotation);
char buf[16]; snprintf(buf, 16, "%.2f", cell.param);
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
drawString(renderer, x + 5, y + size - 18, 10, buf);
drawParamBar(renderer, x, y, size, cell.param, 0, 255, 0);
drawTypeLabel(renderer, x, y, '-'); drawTypeLabel(renderer, x, y, '-');
} else if (cell.type == SynthEngine::GridCell::FIXED_OSCILLATOR) { } else if (cell.type == SynthEngine::GridCell::FIXED_OSCILLATOR) {
DrawCircle(renderer, cx, cy, r); DrawCircle(renderer, cx, cy, r);
@ -295,6 +332,7 @@ void drawGridCell(SDL_Renderer* renderer, int x, int y, int size, SynthEngine::G
if (cell.rotation == 2) dy = r; if (cell.rotation == 2) dy = r;
if (cell.rotation == 3) dx = -r; if (cell.rotation == 3) dx = -r;
SDL_RenderDrawLine(renderer, cx, cy, cx+dx, cy+dy); SDL_RenderDrawLine(renderer, cx, cy, cx+dx, cy+dy);
drawDirectionArrow(renderer, cx, cy, size, cell.rotation);
// Param (Freq) // Param (Freq)
char buf[16]; char buf[16];
snprintf(buf, 16, "%.0f", 10.0f + cell.param*990.0f); snprintf(buf, 16, "%.0f", 10.0f + cell.param*990.0f);
@ -312,6 +350,7 @@ void drawGridCell(SDL_Renderer* renderer, int x, int y, int size, SynthEngine::G
if (cell.rotation == 2) dy = r; if (cell.rotation == 2) dy = r;
if (cell.rotation == 3) dx = -r; if (cell.rotation == 3) dx = -r;
SDL_RenderDrawLine(renderer, cx, cy, cx+dx, cy+dy); SDL_RenderDrawLine(renderer, cx, cy, cx+dx, cy+dy);
drawDirectionArrow(renderer, cx, cy, size, cell.rotation);
// Param (Octave) // Param (Octave)
char buf[16]; snprintf(buf, 16, "O%d", 1 + (int)(cell.param * 4.99f)); char buf[16]; snprintf(buf, 16, "O%d", 1 + (int)(cell.param * 4.99f));
SDL_SetRenderDrawColor(renderer, 255, 200, 0, 255); SDL_SetRenderDrawColor(renderer, 255, 200, 0, 255);
@ -330,6 +369,7 @@ void drawGridCell(SDL_Renderer* renderer, int x, int y, int size, SynthEngine::G
if (cell.rotation == 2) dy = r; if (cell.rotation == 2) dy = r;
if (cell.rotation == 3) dx = -r; if (cell.rotation == 3) dx = -r;
SDL_RenderDrawLine(renderer, cx, cy, cx+dx, cy+dy); SDL_RenderDrawLine(renderer, cx, cy, cx+dx, cy+dy);
drawDirectionArrow(renderer, cx, cy, size, cell.rotation);
// Param (Color) // Param (Color)
const char* colors[] = {"BRN", "PNK", "WHT", "YEL", "GRN"}; const char* colors[] = {"BRN", "PNK", "WHT", "YEL", "GRN"};
@ -347,6 +387,7 @@ void drawGridCell(SDL_Renderer* renderer, int x, int y, int size, SynthEngine::G
if (cell.rotation == 2) dy = r; if (cell.rotation == 2) dy = r;
if (cell.rotation == 3) dx = -r; if (cell.rotation == 3) dx = -r;
SDL_RenderDrawLine(renderer, cx, cy, cx+dx, cy+dy); SDL_RenderDrawLine(renderer, cx, cy, cx+dx, cy+dy);
drawDirectionArrow(renderer, cx, cy, size, cell.rotation);
drawString(renderer, cx - 8, cy - 5, 12, "LFO"); drawString(renderer, cx - 8, cy - 5, 12, "LFO");
// Param (Freq) // Param (Freq)
char buf[16]; snprintf(buf, 16, "%.1f", 0.1f + cell.param * 19.9f); char buf[16]; snprintf(buf, 16, "%.1f", 0.1f + cell.param * 19.9f);
@ -354,12 +395,6 @@ void drawGridCell(SDL_Renderer* renderer, int x, int y, int size, SynthEngine::G
drawString(renderer, x + 5, y + size - 18, 10, buf); drawString(renderer, x + 5, y + size - 18, 10, buf);
drawParamBar(renderer, x, y, size, cell.param, 0, 255, 255); drawParamBar(renderer, x, y, size, cell.param, 0, 255, 255);
drawTypeLabel(renderer, x, y, 'L'); drawTypeLabel(renderer, x, y, 'L');
} else if (cell.type == SynthEngine::GridCell::GATE) {
SDL_Rect box = {cx - r, cy - r, r*2, r*2};
SDL_RenderDrawRect(renderer, &box);
if (cell.value > 0.5f) SDL_RenderFillRect(renderer, &box);
drawString(renderer, cx - 8, cy - 5, 12, "GAT");
drawTypeLabel(renderer, x, y, '!');
} else if (cell.type == SynthEngine::GridCell::GATE_INPUT) { } else if (cell.type == SynthEngine::GridCell::GATE_INPUT) {
SDL_Rect box = {cx - r, cy - r, r*2, r*2}; SDL_Rect box = {cx - r, cy - r, r*2, r*2};
SDL_RenderDrawRect(renderer, &box); SDL_RenderDrawRect(renderer, &box);
@ -377,6 +412,7 @@ void drawGridCell(SDL_Renderer* renderer, int x, int y, int size, SynthEngine::G
int odx=0, ody=0; int odx=0, ody=0;
if(cell.rotation==0) ody=-r; else if(cell.rotation==1) odx=r; else if(cell.rotation==2) ody=r; else odx=-r; if(cell.rotation==0) ody=-r; else if(cell.rotation==1) odx=r; else if(cell.rotation==2) ody=r; else odx=-r;
SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody); SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody);
drawDirectionArrow(renderer, cx, cy, size, cell.rotation);
drawParamBar(renderer, x, y, size, cell.param, 255, 255, 255); drawParamBar(renderer, x, y, size, cell.param, 255, 255, 255);
drawTypeLabel(renderer, x, y, 'A'); drawTypeLabel(renderer, x, y, 'A');
@ -391,6 +427,7 @@ void drawGridCell(SDL_Renderer* renderer, int x, int y, int size, SynthEngine::G
int odx=0, ody=0; int odx=0, ody=0;
if(cell.rotation==0) ody=-r; else if(cell.rotation==1) odx=r; else if(cell.rotation==2) ody=r; else odx=-r; if(cell.rotation==0) ody=-r; else if(cell.rotation==1) odx=r; else if(cell.rotation==2) ody=r; else odx=-r;
SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody); SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody);
drawDirectionArrow(renderer, cx, cy, size, cell.rotation);
drawParamBar(renderer, x, y, size, cell.param, 255, 255, 255); drawParamBar(renderer, x, y, size, cell.param, 255, 255, 255);
drawTypeLabel(renderer, x, y, 'D'); drawTypeLabel(renderer, x, y, 'D');
@ -405,6 +442,7 @@ void drawGridCell(SDL_Renderer* renderer, int x, int y, int size, SynthEngine::G
int odx=0, ody=0; int odx=0, ody=0;
if(cell.rotation==0) ody=-r; else if(cell.rotation==1) odx=r; else if(cell.rotation==2) ody=r; else odx=-r; if(cell.rotation==0) ody=-r; else if(cell.rotation==1) odx=r; else if(cell.rotation==2) ody=r; else odx=-r;
SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody); SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody);
drawDirectionArrow(renderer, cx, cy, size, cell.rotation);
drawParamBar(renderer, x, y, size, cell.param, 255, 255, 255); drawParamBar(renderer, x, y, size, cell.param, 255, 255, 255);
drawTypeLabel(renderer, x, y, 'S'); drawTypeLabel(renderer, x, y, 'S');
@ -419,6 +457,7 @@ void drawGridCell(SDL_Renderer* renderer, int x, int y, int size, SynthEngine::G
int odx=0, ody=0; int odx=0, ody=0;
if(cell.rotation==0) ody=-r; else if(cell.rotation==1) odx=r; else if(cell.rotation==2) ody=r; else odx=-r; if(cell.rotation==0) ody=-r; else if(cell.rotation==1) odx=r; else if(cell.rotation==2) ody=r; else odx=-r;
SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody); SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody);
drawDirectionArrow(renderer, cx, cy, size, cell.rotation);
drawParamBar(renderer, x, y, size, cell.param, 255, 255, 255); drawParamBar(renderer, x, y, size, cell.param, 255, 255, 255);
drawTypeLabel(renderer, x, y, 'E'); drawTypeLabel(renderer, x, y, 'E');
@ -436,6 +475,7 @@ void drawGridCell(SDL_Renderer* renderer, int x, int y, int size, SynthEngine::G
int odx=0, ody=0; int odx=0, ody=0;
if(cell.rotation==0) ody=-r; else if(cell.rotation==1) odx=r; else if(cell.rotation==2) ody=r; else odx=-r; if(cell.rotation==0) ody=-r; else if(cell.rotation==1) odx=r; else if(cell.rotation==2) ody=r; else odx=-r;
SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody); SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody);
drawDirectionArrow(renderer, cx, cy, size, cell.rotation);
// Param // Param
char buf[16]; snprintf(buf, 16, "%.2f", cell.param); char buf[16]; snprintf(buf, 16, "%.2f", cell.param);
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255); SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);
@ -456,6 +496,7 @@ void drawGridCell(SDL_Renderer* renderer, int x, int y, int size, SynthEngine::G
int odx=0, ody=0; int odx=0, ody=0;
if(cell.rotation==0) ody=-r; else if(cell.rotation==1) odx=r; else if(cell.rotation==2) ody=r; else odx=-r; if(cell.rotation==0) ody=-r; else if(cell.rotation==1) odx=r; else if(cell.rotation==2) ody=r; else odx=-r;
SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody); SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody);
drawDirectionArrow(renderer, cx, cy, size, cell.rotation);
// Param // Param
char buf[16]; snprintf(buf, 16, "%.2f", cell.param); char buf[16]; snprintf(buf, 16, "%.2f", cell.param);
SDL_SetRenderDrawColor(renderer, 255, 255, 0, 255); SDL_SetRenderDrawColor(renderer, 255, 255, 0, 255);
@ -474,6 +515,7 @@ void drawGridCell(SDL_Renderer* renderer, int x, int y, int size, SynthEngine::G
int odx=0, ody=0; int odx=0, ody=0;
if(cell.rotation==0) ody=-r; else if(cell.rotation==1) odx=r; else if(cell.rotation==2) ody=r; else odx=-r; if(cell.rotation==0) ody=-r; else if(cell.rotation==1) odx=r; else if(cell.rotation==2) ody=r; else odx=-r;
SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody); SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody);
drawDirectionArrow(renderer, cx, cy, size, cell.rotation);
// Param // Param
char buf[16]; snprintf(buf, 16, "%.2f", cell.param); char buf[16]; snprintf(buf, 16, "%.2f", cell.param);
SDL_SetRenderDrawColor(renderer, 255, 0, 255, 255); SDL_SetRenderDrawColor(renderer, 255, 0, 255, 255);
@ -492,6 +534,7 @@ void drawGridCell(SDL_Renderer* renderer, int x, int y, int size, SynthEngine::G
int odx=0, ody=0; int odx=0, ody=0;
if(cell.rotation==0) ody=-r; else if(cell.rotation==1) odx=r; else if(cell.rotation==2) ody=r; else odx=-r; if(cell.rotation==0) ody=-r; else if(cell.rotation==1) odx=r; else if(cell.rotation==2) ody=r; else odx=-r;
SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody); SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody);
drawDirectionArrow(renderer, cx, cy, size, cell.rotation);
char buf[16]; snprintf(buf, 16, "%.2f", cell.param); char buf[16]; snprintf(buf, 16, "%.2f", cell.param);
SDL_SetRenderDrawColor(renderer, 255, 100, 100, 255); SDL_SetRenderDrawColor(renderer, 255, 100, 100, 255);
drawString(renderer, x + 5, y + size - 18, 10, buf); drawString(renderer, x + 5, y + size - 18, 10, buf);
@ -509,6 +552,7 @@ void drawGridCell(SDL_Renderer* renderer, int x, int y, int size, SynthEngine::G
int odx=0, ody=0; int odx=0, ody=0;
if(cell.rotation==0) ody=-r; else if(cell.rotation==1) odx=r; else if(cell.rotation==2) ody=r; else odx=-r; if(cell.rotation==0) ody=-r; else if(cell.rotation==1) odx=r; else if(cell.rotation==2) ody=r; else odx=-r;
SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody); SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody);
drawDirectionArrow(renderer, cx, cy, size, cell.rotation);
drawParamBar(renderer, x, y, size, cell.param, 255, 150, 0); drawParamBar(renderer, x, y, size, cell.param, 255, 150, 0);
drawTypeLabel(renderer, x, y, '|'); drawTypeLabel(renderer, x, y, '|');
} else if (cell.type == SynthEngine::GridCell::PITCH_SHIFTER) { } else if (cell.type == SynthEngine::GridCell::PITCH_SHIFTER) {
@ -521,6 +565,7 @@ void drawGridCell(SDL_Renderer* renderer, int x, int y, int size, SynthEngine::G
int odx=0, ody=0; int odx=0, ody=0;
if(cell.rotation==0) ody=-r; else if(cell.rotation==1) odx=r; else if(cell.rotation==2) ody=r; else odx=-r; if(cell.rotation==0) ody=-r; else if(cell.rotation==1) odx=r; else if(cell.rotation==2) ody=r; else odx=-r;
SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody); SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody);
drawDirectionArrow(renderer, cx, cy, size, cell.rotation);
drawParamBar(renderer, x, y, size, cell.param, 100, 255, 100); drawParamBar(renderer, x, y, size, cell.param, 100, 255, 100);
drawTypeLabel(renderer, x, y, '^'); drawTypeLabel(renderer, x, y, '^');
} else if (cell.type == SynthEngine::GridCell::GLITCH) { } else if (cell.type == SynthEngine::GridCell::GLITCH) {
@ -533,6 +578,7 @@ void drawGridCell(SDL_Renderer* renderer, int x, int y, int size, SynthEngine::G
int odx=0, ody=0; int odx=0, ody=0;
if(cell.rotation==0) ody=-r; else if(cell.rotation==1) odx=r; else if(cell.rotation==2) ody=r; else odx=-r; if(cell.rotation==0) ody=-r; else if(cell.rotation==1) odx=r; else if(cell.rotation==2) ody=r; else odx=-r;
SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody); SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody);
drawDirectionArrow(renderer, cx, cy, size, cell.rotation);
drawParamBar(renderer, x, y, size, cell.param, 255, 0, 0); drawParamBar(renderer, x, y, size, cell.param, 255, 0, 0);
drawTypeLabel(renderer, x, y, 'G'); drawTypeLabel(renderer, x, y, 'G');
@ -553,6 +599,8 @@ void drawGridCell(SDL_Renderer* renderer, int x, int y, int size, SynthEngine::G
if(rDir==0) rdy=-r; else if(rDir==1) rdx=r; else if(rDir==2) rdy=r; else rdx=-r; if(rDir==0) rdy=-r; else if(rDir==1) rdx=r; else if(rDir==2) rdy=r; else rdx=-r;
SDL_RenderDrawLine(renderer, cx, cy, cx+ldx, cy+ldy); SDL_RenderDrawLine(renderer, cx, cy, cx+ldx, cy+ldy);
SDL_RenderDrawLine(renderer, cx, cy, cx+rdx, cy+rdy); SDL_RenderDrawLine(renderer, cx, cy, cx+rdx, cy+rdy);
drawDirectionArrow(renderer, cx, cy, size, lDir);
drawDirectionArrow(renderer, cx, cy, size, rDir);
// Param (Balance) // Param (Balance)
char buf[16]; snprintf(buf, 16, "%.1f", cell.param); char buf[16]; snprintf(buf, 16, "%.1f", cell.param);
@ -573,6 +621,7 @@ void drawGridCell(SDL_Renderer* renderer, int x, int y, int size, SynthEngine::G
int odx=0, ody=0; int odx=0, ody=0;
if(outDir==0) ody=-r; else if(outDir==1) odx=r; else if(outDir==2) ody=r; else odx=-r; if(outDir==0) ody=-r; else if(outDir==1) odx=r; else if(outDir==2) ody=r; else odx=-r;
SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody); SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody);
drawDirectionArrow(renderer, cx, cy, size, cell.rotation);
// Param (Delay time in ms) // Param (Delay time in ms)
char buf[16]; char buf[16];
@ -595,6 +644,7 @@ void drawGridCell(SDL_Renderer* renderer, int x, int y, int size, SynthEngine::G
int odx=0, ody=0; int odx=0, ody=0;
if(outDir==0) ody=-r; else if(outDir==1) odx=r; else if(outDir==2) ody=r; else odx=-r; if(outDir==0) ody=-r; else if(outDir==1) odx=r; else if(outDir==2) ody=r; else odx=-r;
SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody); SDL_RenderDrawLine(renderer, cx, cy, cx+odx, cy+ody);
drawDirectionArrow(renderer, cx, cy, size, cell.rotation);
// Param (Strength) // Param (Strength)
char buf[16]; snprintf(buf, 16, "%.2f", cell.param); char buf[16]; snprintf(buf, 16, "%.2f", cell.param);
SDL_SetRenderDrawColor(renderer, 200, 100, 255, 255); SDL_SetRenderDrawColor(renderer, 200, 100, 255, 255);
@ -610,6 +660,7 @@ void drawGridCell(SDL_Renderer* renderer, int x, int y, int size, SynthEngine::G
if (cell.rotation == 2) dy = r; if (cell.rotation == 2) dy = r;
if (cell.rotation == 3) dx = -r; if (cell.rotation == 3) dx = -r;
SDL_RenderDrawLine(renderer, cx, cy, cx+dx, cy+dy); SDL_RenderDrawLine(renderer, cx, cy, cx+dx, cy+dy);
drawDirectionArrow(renderer, cx, cy, size, cell.rotation);
// Draw Op Symbol // Draw Op Symbol
char opChar = '?'; char opChar = '?';
@ -632,6 +683,7 @@ void drawGridCell(SDL_Renderer* renderer, int x, int y, int size, SynthEngine::G
if (cell.rotation == 2) dy = r; if (cell.rotation == 2) dy = r;
if (cell.rotation == 3) dx = -r; if (cell.rotation == 3) dx = -r;
SDL_RenderDrawLine(renderer, cx, cy, cx+dx, cy+dy); SDL_RenderDrawLine(renderer, cx, cy, cx+dx, cy+dy);
drawDirectionArrow(renderer, cx, cy, size, cell.rotation);
// Param (Wave index) // Param (Wave index)
int idx = (int)(cell.param * 7.99f); int idx = (int)(cell.param * 7.99f);
char buf[4]; char buf[4];
@ -645,8 +697,8 @@ void drawGridCell(SDL_Renderer* renderer, int x, int y, int size, SynthEngine::G
void clearGrid() { void clearGrid() {
std::lock_guard<std::mutex> lock(engine.gridMutex); std::lock_guard<std::mutex> lock(engine.gridMutex);
for (int x = 0; x < 5; ++x) { for (int x = 0; x < SynthEngine::GRID_W; ++x) {
for (int y = 0; y < 8; ++y) { for (int y = 0; y < SynthEngine::GRID_H; ++y) {
SynthEngine::GridCell& c = engine.grid[x][y]; SynthEngine::GridCell& c = engine.grid[x][y];
if (c.type == SynthEngine::GridCell::SINK) continue; if (c.type == SynthEngine::GridCell::SINK) continue;
@ -671,8 +723,8 @@ void randomizeGrid() {
const int numTypes = (int)SynthEngine::GridCell::SINK; const int numTypes = (int)SynthEngine::GridCell::SINK;
// 1. Clear existing buffers first // 1. Clear existing buffers first
for (int x = 0; x < 5; ++x) { for (int x = 0; x < SynthEngine::GRID_W; ++x) {
for (int y = 0; y < 8; ++y) { for (int y = 0; y < SynthEngine::GRID_H; ++y) {
SynthEngine::GridCell& c = engine.grid[x][y]; SynthEngine::GridCell& c = engine.grid[x][y];
if (c.buffer) { if (c.buffer) {
delete[] c.buffer; delete[] c.buffer;
@ -687,14 +739,14 @@ void randomizeGrid() {
int attempts = 0; int attempts = 0;
bool inputOscillatorReachable = false; bool inputOscillatorReachable = false;
bool visited[5][8]; bool visited[SynthEngine::GRID_W][SynthEngine::GRID_H];
while (!inputOscillatorReachable && attempts < 1000) { while (!inputOscillatorReachable && attempts < 1000) {
attempts++; attempts++;
// 2. Randomize (without allocation) // 2. Randomize (without allocation)
for (int x = 0; x < 5; ++x) { for (int x = 0; x < SynthEngine::GRID_W; ++x) {
for (int y = 0; y < 8; ++y) { for (int y = 0; y < SynthEngine::GRID_H; ++y) {
SynthEngine::GridCell& c = engine.grid[x][y]; SynthEngine::GridCell& c = engine.grid[x][y];
if (c.type == SynthEngine::GridCell::SINK) continue; if (c.type == SynthEngine::GridCell::SINK) continue;
@ -705,12 +757,12 @@ void randomizeGrid() {
} }
// 3. Check Connectivity // 3. Check Connectivity
// BFS from SINK (2,3) backwards // BFS from SINK backwards
memset(visited, 0, sizeof(visited)); memset(visited, 0, sizeof(visited));
std::vector<std::pair<int, int>> q; std::vector<std::pair<int, int>> q;
q.push_back({2, 3}); q.push_back({SynthEngine::GRID_W / 2, SynthEngine::GRID_H - 1});
visited[2][3] = true; visited[SynthEngine::GRID_W / 2][SynthEngine::GRID_H - 1] = true;
int head = 0; int head = 0;
while(head < (int)q.size()) { while(head < (int)q.size()) {
@ -725,7 +777,7 @@ void randomizeGrid() {
for(int i=0; i<4; ++i) { for(int i=0; i<4; ++i) {
int tx = cx + nx[i]; int tx = cx + nx[i];
int ty = cy + ny[i]; int ty = cy + ny[i];
if (tx >= 0 && tx < 5 && ty >= 0 && ty < 8 && !visited[tx][ty]) { if (tx >= 0 && tx < SynthEngine::GRID_W && ty >= 0 && ty < SynthEngine::GRID_H && !visited[tx][ty]) {
SynthEngine::GridCell& neighbor = engine.grid[tx][ty]; SynthEngine::GridCell& neighbor = engine.grid[tx][ty];
bool pointsToCurr = false; bool pointsToCurr = false;
@ -766,8 +818,8 @@ void randomizeGrid() {
} }
// After BFS, check if an input oscillator is reachable // After BFS, check if an input oscillator is reachable
for (int x = 0; x < 5; ++x) { for (int x = 0; x < SynthEngine::GRID_W; ++x) {
for (int y = 0; y < 8; ++y) { for (int y = 0; y < SynthEngine::GRID_H; ++y) {
if (visited[x][y] && engine.grid[x][y].type == SynthEngine::GridCell::INPUT_OSCILLATOR) { if (visited[x][y] && engine.grid[x][y].type == SynthEngine::GridCell::INPUT_OSCILLATOR) {
inputOscillatorReachable = true; inputOscillatorReachable = true;
break; break;
@ -779,8 +831,8 @@ void randomizeGrid() {
// 4. Prune unreachable elements if a valid grid was found // 4. Prune unreachable elements if a valid grid was found
if (inputOscillatorReachable) { if (inputOscillatorReachable) {
for (int x = 0; x < 5; ++x) { for (int x = 0; x < SynthEngine::GRID_W; ++x) {
for (int y = 0; y < 8; ++y) { for (int y = 0; y < SynthEngine::GRID_H; ++y) {
if (!visited[x][y]) { if (!visited[x][y]) {
engine.grid[x][y].type = SynthEngine::GridCell::EMPTY; engine.grid[x][y].type = SynthEngine::GridCell::EMPTY;
engine.grid[x][y].param = 0.5f; engine.grid[x][y].param = 0.5f;
@ -791,8 +843,8 @@ void randomizeGrid() {
} }
// 5. Allocate buffers for DELAYs and REVERBs that are still present // 5. Allocate buffers for DELAYs and REVERBs that are still present
for (int x = 0; x < 5; ++x) { for (int x = 0; x < SynthEngine::GRID_W; ++x) {
for (int y = 0; y < 8; ++y) { for (int y = 0; y < SynthEngine::GRID_H; ++y) {
SynthEngine::GridCell& c = engine.grid[x][y]; SynthEngine::GridCell& c = engine.grid[x][y];
if (c.type == SynthEngine::GridCell::DELAY || c.type == SynthEngine::GridCell::REVERB || c.type == SynthEngine::GridCell::PITCH_SHIFTER) { if (c.type == SynthEngine::GridCell::DELAY || c.type == SynthEngine::GridCell::REVERB || c.type == SynthEngine::GridCell::PITCH_SHIFTER) {
c.buffer_size = 2 * SAMPLE_RATE; c.buffer_size = 2 * SAMPLE_RATE;
@ -805,6 +857,97 @@ void randomizeGrid() {
printf("Randomized in %d attempts. Input Osc reachable: %s\n", attempts, inputOscillatorReachable ? "YES" : "NO"); printf("Randomized in %d attempts. Input Osc reachable: %s\n", attempts, inputOscillatorReachable ? "YES" : "NO");
} }
void loadPreset(int preset) {
clearGrid();
std::lock_guard<std::mutex> lock(engine.gridMutex);
auto placeOp = [&](int x, int y, float ratio, float att, float rel) {
// Layout:
// (x, y) : G-IN (South)
// (x, y+1) : WIRE (East)
// (x+1, y+1): ATT (East)
// (x+2, y+1): REL (East)
// (x+3, y+1): VCA (South)
// (x+3, y) : OSC (South)
engine.grid[x][y].type = SynthEngine::GridCell::GATE_INPUT; engine.grid[x][y].rotation = 2; // S
engine.grid[x][y+1].type = SynthEngine::GridCell::WIRE; engine.grid[x][y+1].rotation = 1; // E
engine.grid[x+1][y+1].type = SynthEngine::GridCell::ADSR_ATTACK; engine.grid[x+1][y+1].rotation = 1; // E
engine.grid[x+1][y+1].param = att;
engine.grid[x+2][y+1].type = SynthEngine::GridCell::ADSR_RELEASE; engine.grid[x+2][y+1].rotation = 1; // E
engine.grid[x+2][y+1].param = rel;
engine.grid[x+3][y+1].type = SynthEngine::GridCell::VCA; engine.grid[x+3][y+1].rotation = 2; // S
engine.grid[x+3][y+1].param = 0.0f; // Controlled by Env
engine.grid[x+3][y].type = SynthEngine::GridCell::INPUT_OSCILLATOR; engine.grid[x+3][y].rotation = 2; // S
engine.grid[x+3][y].param = (ratio > 1.0f) ? 0.5f : 0.0f;
};
int sinkX = SynthEngine::GRID_W / 2;
int sinkY = SynthEngine::GRID_H - 1;
if (preset == 1) {
// Algo 32: Parallel Operators
// 6 Ops in parallel feeding the sink
// We'll place 3, and wire them
placeOp(0, 0, 1.0f, 0.01f, 0.5f); // Op 1
placeOp(4, 0, 1.0f, 0.05f, 0.3f); // Op 2
placeOp(8, 0, 2.0f, 0.01f, 0.2f); // Op 3
// Wire outputs to sink
// Op1 Out at (3, 1) -> South
// VCA is at (x+3, y+1). For Op1(0,0) -> (3,1).
engine.grid[3][2].type = SynthEngine::GridCell::WIRE; engine.grid[3][2].rotation = 2;
engine.grid[3][3].type = SynthEngine::GridCell::WIRE; engine.grid[3][3].rotation = 1; // E
engine.grid[4][3].type = SynthEngine::GridCell::WIRE; engine.grid[4][3].rotation = 1; // E
engine.grid[5][3].type = SynthEngine::GridCell::WIRE; engine.grid[5][3].rotation = 1; // E
engine.grid[6][3].type = SynthEngine::GridCell::WIRE; engine.grid[6][3].rotation = 2; // S
// Op2 Out at (7, 1) -> South
engine.grid[7][2].type = SynthEngine::GridCell::WIRE; engine.grid[7][2].rotation = 2;
engine.grid[7][3].type = SynthEngine::GridCell::WIRE; engine.grid[7][3].rotation = 3; // W
// Op3 Out at (11, 1) -> South
engine.grid[11][2].type = SynthEngine::GridCell::WIRE; engine.grid[11][2].rotation = 2;
engine.grid[11][3].type = SynthEngine::GridCell::WIRE; engine.grid[11][3].rotation = 3; // W
engine.grid[10][3].type = SynthEngine::GridCell::WIRE; engine.grid[10][3].rotation = 3; // W
engine.grid[9][3].type = SynthEngine::GridCell::WIRE; engine.grid[9][3].rotation = 3; // W
engine.grid[8][3].type = SynthEngine::GridCell::WIRE; engine.grid[8][3].rotation = 3; // W
// Funnel down to sink
for(int y=4; y<sinkY; ++y) {
engine.grid[6][y].type = SynthEngine::GridCell::WIRE; engine.grid[6][y].rotation = 2;
}
} else if (preset == 2) {
// Algo 1: Stack (FM)
// Op 2 Modulates Op 1
// Op 1 is Carrier
// Modulator (Top)
placeOp(4, 0, 2.0f, 0.01f, 0.2f); // VCA at (7, 1)
// Carrier (Bottom)
placeOp(4, 2, 1.0f, 0.01f, 0.8f); // VCA at (7, 3). Osc at (7, 2).
// Connect Modulator to Carrier
// Mod VCA (7, 1) South.
// Carrier Osc (7, 2) South. Back is North (7, 1).
// Direct connection! No wire needed.
// Carrier Output to Sink
// Carrier VCA (7, 3) South.
engine.grid[7][4].type = SynthEngine::GridCell::WIRE; engine.grid[7][4].rotation = 3; // W
engine.grid[6][4].type = SynthEngine::GridCell::WIRE; engine.grid[6][4].rotation = 2; // S
for(int y=5; y<sinkY; ++y) {
engine.grid[6][y].type = SynthEngine::GridCell::WIRE; engine.grid[6][y].rotation = 2;
}
}
}
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
(void)argc; (void)argv; (void)argc; (void)argv;
@ -872,7 +1015,6 @@ int main(int argc, char* argv[]) {
SynthEngine::GridCell::WAVETABLE, SynthEngine::GridCell::WAVETABLE,
SynthEngine::GridCell::NOISE, SynthEngine::GridCell::NOISE,
SynthEngine::GridCell::LFO, SynthEngine::GridCell::LFO,
SynthEngine::GridCell::GATE,
SynthEngine::GridCell::GATE_INPUT, SynthEngine::GridCell::GATE_INPUT,
SynthEngine::GridCell::ADSR_ATTACK, SynthEngine::GridCell::ADSR_ATTACK,
SynthEngine::GridCell::ADSR_DECAY, SynthEngine::GridCell::ADSR_DECAY,
@ -928,9 +1070,9 @@ int main(int argc, char* argv[]) {
int mx = e.button.x; int mx = e.button.x;
int my = e.button.y; int my = e.button.y;
if (mx < GRID_PANEL_WIDTH) { if (mx < GRID_PANEL_WIDTH) {
int gx = mx / 80; int gx = mx / CELL_SIZE;
int gy = my / 80; int gy = my / CELL_SIZE;
if (gx >= 0 && gx < 5 && gy >= 0 && gy < 8) { if (gx >= 0 && gx < SynthEngine::GRID_W && gy >= 0 && gy < SynthEngine::GRID_H) {
std::lock_guard<std::mutex> lock(engine.gridMutex); std::lock_guard<std::mutex> lock(engine.gridMutex);
SynthEngine::GridCell& c = engine.grid[gx][gy]; SynthEngine::GridCell& c = engine.grid[gx][gy];
if (c.type != SynthEngine::GridCell::SINK) { if (c.type != SynthEngine::GridCell::SINK) {
@ -998,9 +1140,9 @@ int main(int argc, char* argv[]) {
if (mx < GRID_PANEL_WIDTH) { if (mx < GRID_PANEL_WIDTH) {
// Grid Scroll // Grid Scroll
float step = fineTune ? 0.01f : 0.05f; float step = fineTune ? 0.01f : 0.05f;
int gx = mx / 80; int gx = mx / CELL_SIZE;
int gy = my / 80; int gy = my / CELL_SIZE;
if (gx >= 0 && gx < 5 && gy >= 0 && gy < 8) { if (gx >= 0 && gx < SynthEngine::GRID_W && gy >= 0 && gy < SynthEngine::GRID_H) {
std::lock_guard<std::mutex> lock(engine.gridMutex); std::lock_guard<std::mutex> lock(engine.gridMutex);
SynthEngine::GridCell& c = engine.grid[gx][gy]; SynthEngine::GridCell& c = engine.grid[gx][gy];
if (e.wheel.y > 0) c.param += step; if (e.wheel.y > 0) c.param += step;
@ -1048,6 +1190,12 @@ int main(int argc, char* argv[]) {
randomizeGrid(); randomizeGrid();
} else if (e.key.keysym.scancode == SDL_SCANCODE_DELETE) { } else if (e.key.keysym.scancode == SDL_SCANCODE_DELETE) {
clearGrid(); clearGrid();
} else if (e.key.keysym.scancode == SDL_SCANCODE_PAGEUP) {
current_preset = (current_preset + 1) % 3;
loadPreset(current_preset);
} else if (e.key.keysym.scancode == SDL_SCANCODE_PAGEDOWN) {
current_preset = (current_preset - 1 + 3) % 3;
loadPreset(current_preset);
} else if (e.key.keysym.scancode == SDL_SCANCODE_M) { } else if (e.key.keysym.scancode == SDL_SCANCODE_M) {
auto_melody_enabled = !auto_melody_enabled; auto_melody_enabled = !auto_melody_enabled;
engine.setGate(false); // Silence synth on mode change engine.setGate(false); // Silence synth on mode change
@ -1075,10 +1223,11 @@ int main(int argc, char* argv[]) {
// Update window title with current values // Update window title with current values
char title[256]; char title[256];
snprintf(title, sizeof(title), "NoiceSynth | Vol: %.0f%% | Oct: %d | Auto(M): %s", snprintf(title, sizeof(title), "NoiceSynth | Vol: %.0f%% | Oct: %d | Auto(M): %s | Preset: %d",
knob_vol_val * 100.0f, knob_vol_val * 100.0f,
current_octave, current_octave,
auto_melody_enabled ? "ON" : "OFF"); auto_melody_enabled ? "ON" : "OFF",
current_preset);
SDL_SetWindowTitle(window, title); SDL_SetWindowTitle(window, title);
// Clear screen // Clear screen
@ -1153,9 +1302,9 @@ int main(int argc, char* argv[]) {
{ {
// Lock only for reading state to draw // Lock only for reading state to draw
std::lock_guard<std::mutex> lock(engine.gridMutex); std::lock_guard<std::mutex> lock(engine.gridMutex);
for(int x=0; x<5; ++x) { for(int x=0; x < SynthEngine::GRID_W; ++x) {
for(int y=0; y<8; ++y) { for(int y=0; y < SynthEngine::GRID_H; ++y) {
drawGridCell(renderer, x*80, y*80, 80, engine.grid[x][y]); drawGridCell(renderer, x*CELL_SIZE, y*CELL_SIZE, CELL_SIZE, engine.grid[x][y]);
} }
} }
} }

View File

@ -33,7 +33,7 @@ SynthEngine::SynthEngine(uint32_t sampleRate)
setFrequency(440.0f); setFrequency(440.0f);
// Initialize SINK // Initialize SINK
grid[2][3].type = GridCell::SINK; grid[GRID_W / 2][GRID_H - 1].type = GridCell::SINK;
} }
SynthEngine::~SynthEngine() { SynthEngine::~SynthEngine() {
@ -82,14 +82,14 @@ float SynthEngine::_random() {
float SynthEngine::processGridStep() { float SynthEngine::processGridStep() {
// Double buffer for values to handle feedback loops gracefully (1-sample delay) // Double buffer for values to handle feedback loops gracefully (1-sample delay)
float next_values[5][8]; float next_values[GRID_W][GRID_H];
auto isConnected = [&](int tx, int ty, int from_x, int from_y) -> bool { auto isConnected = [&](int tx, int ty, int from_x, int from_y) -> bool {
if (from_x < 0 || from_x >= 5 || from_y < 0 || from_y >= 8) return false; if (from_x < 0 || from_x >= GRID_W || from_y < 0 || from_y >= GRID_H) return false;
GridCell& n = grid[from_x][from_y]; GridCell& n = grid[from_x][from_y];
bool connects = false; 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::NOISE || n.type == GridCell::LFO || n.type == GridCell::GATE || n.type == GridCell::GATE_INPUT || n.type == GridCell::ADSR_ATTACK || n.type == GridCell::ADSR_DECAY || n.type == GridCell::ADSR_SUSTAIN || n.type == GridCell::ADSR_RELEASE || n.type == GridCell::LPF || n.type == GridCell::HPF || n.type == GridCell::VCA || n.type == GridCell::BITCRUSHER || n.type == GridCell::DISTORTION || n.type == GridCell::RECTIFIER || n.type == GridCell::PITCH_SHIFTER || n.type == GridCell::GLITCH || n.type == GridCell::OPERATOR || 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::GATE_INPUT || n.type == GridCell::ADSR_ATTACK || n.type == GridCell::ADSR_DECAY || n.type == GridCell::ADSR_SUSTAIN || n.type == GridCell::ADSR_RELEASE || n.type == GridCell::LPF || n.type == GridCell::HPF || n.type == GridCell::VCA || n.type == GridCell::BITCRUSHER || n.type == GridCell::DISTORTION || n.type == GridCell::RECTIFIER || n.type == GridCell::PITCH_SHIFTER || n.type == GridCell::GLITCH || n.type == GridCell::OPERATOR || n.type == GridCell::DELAY || n.type == GridCell::REVERB) {
// Check rotation // Check rotation
// 0:N (y-1), 1:E (x+1), 2:S (y+1), 3:W (x-1) // 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; if (n.rotation == 0 && from_y - 1 == ty && from_x == tx) connects = true;
@ -171,8 +171,8 @@ float SynthEngine::processGridStep() {
return hasSide ? gain : 1.0f; return hasSide ? gain : 1.0f;
}; };
for (int x = 0; x < 5; ++x) { for (int x = 0; x < GRID_W; ++x) {
for (int y = 0; y < 8; ++y) { for (int y = 0; y < GRID_H; ++y) {
GridCell& c = grid[x][y]; GridCell& c = grid[x][y];
float val = 0.0f; float val = 0.0f;
@ -279,7 +279,7 @@ float SynthEngine::processGridStep() {
} else if (c.type == GridCell::FORK) { } else if (c.type == GridCell::FORK) {
// Sum inputs from "Back" (Input direction) // Sum inputs from "Back" (Input direction)
val = getInputFromTheBack(x, y, c); val = getInputFromTheBack(x, y, c);
} else if (c.type == GridCell::GATE || c.type == GridCell::GATE_INPUT) { } else if (c.type == GridCell::GATE_INPUT) {
// Outputs 1.0 when gate is open (key pressed), 0.0 otherwise // Outputs 1.0 when gate is open (key pressed), 0.0 otherwise
val = _isGateOpen ? 1.0f : 0.0f; val = _isGateOpen ? 1.0f : 0.0f;
} else if (c.type == GridCell::ADSR_ATTACK) { } else if (c.type == GridCell::ADSR_ATTACK) {
@ -311,7 +311,7 @@ float SynthEngine::processGridStep() {
} else if (c.type == GridCell::WIRE) { } else if (c.type == GridCell::WIRE) {
// Sum inputs from all neighbors that point to me // Sum inputs from all neighbors that point to me
float sum = getSummedInput(x, y, c); float sum = getSummedInput(x, y, c);
val = sum * c.param; // Fading val = sum;
} else if (c.type == GridCell::LPF) { } else if (c.type == GridCell::LPF) {
// Input from Back // Input from Back
float in = getInputFromTheBack(x, y, c); float in = getInputFromTheBack(x, y, c);
@ -514,13 +514,13 @@ float SynthEngine::processGridStep() {
} }
// Update state // Update state
for(int x=0; x<5; ++x) { for(int x=0; x < GRID_W; ++x) {
for(int y=0; y<8; ++y) { for(int y=0; y < GRID_H; ++y) {
grid[x][y].value = next_values[x][y]; grid[x][y].value = next_values[x][y];
} }
} }
return grid[2][3].value; return grid[GRID_W / 2][GRID_H - 1].value;
} }
void SynthEngine::process(int16_t* buffer, uint32_t numFrames) { void SynthEngine::process(int16_t* buffer, uint32_t numFrames) {

View File

@ -70,7 +70,7 @@ public:
// --- Grid Synth --- // --- Grid Synth ---
struct GridCell { struct GridCell {
enum Type { EMPTY, FIXED_OSCILLATOR, INPUT_OSCILLATOR, WAVETABLE, NOISE, LFO, GATE, GATE_INPUT, ADSR_ATTACK, ADSR_DECAY, ADSR_SUSTAIN, ADSR_RELEASE, FORK, WIRE, LPF, HPF, VCA, BITCRUSHER, DISTORTION, RECTIFIER, PITCH_SHIFTER, GLITCH, OPERATOR, DELAY, REVERB, SINK }; enum Type { EMPTY, FIXED_OSCILLATOR, INPUT_OSCILLATOR, WAVETABLE, NOISE, LFO, GATE_INPUT, ADSR_ATTACK, ADSR_DECAY, ADSR_SUSTAIN, ADSR_RELEASE, FORK, WIRE, LPF, HPF, VCA, BITCRUSHER, DISTORTION, RECTIFIER, PITCH_SHIFTER, GLITCH, OPERATOR, DELAY, REVERB, SINK };
enum Op { OP_ADD, OP_MUL, OP_SUB, OP_DIV, OP_MIN, OP_MAX }; enum Op { OP_ADD, OP_MUL, OP_SUB, OP_DIV, OP_MIN, OP_MAX };
Type type = EMPTY; Type type = EMPTY;
@ -83,7 +83,10 @@ public:
uint32_t write_idx = 0; // For Delay uint32_t write_idx = 0; // For Delay
}; };
GridCell grid[5][8]; static const int GRID_W = 12;
static const int GRID_H = 12;
GridCell grid[GRID_W][GRID_H];
std::mutex gridMutex; std::mutex gridMutex;
// Helper to process one sample step of the grid // Helper to process one sample step of the grid