fix initial grid state

This commit is contained in:
Dejvino 2026-03-01 15:19:36 +01:00
parent 534a7512c4
commit c7aa020f67
3 changed files with 122 additions and 20 deletions

View File

@ -45,7 +45,7 @@ bool auto_melody_enabled = false;
Uint32 auto_melody_next_event_time = 0;
const int c_major_scale[] = {0, 2, 4, 5, 7, 9, 11, 12}; // Semitones from root
int current_preset = 0;
int current_patch_slot = 0; // 0-7
float note_to_freq(int octave, int semitone_offset);
@ -54,6 +54,43 @@ float note_to_freq(int octave, int semitone_offset);
// The audio callback needs access to our synth, so we make it global.
SynthEngine engine(SAMPLE_RATE);
void savePatch(int slot) {
char filename[64];
snprintf(filename, sizeof(filename), "noicesynth_patch_%d.dat", slot);
FILE* f = fopen(filename, "wb");
if (f) {
uint8_t buf[SynthEngine::MAX_SERIALIZED_GRID_SIZE];
size_t size = engine.exportGrid(buf);
fwrite(buf, 1, size, f);
fclose(f);
printf("Saved patch to slot %d (%s)\n", slot, filename);
} else {
printf("Failed to save patch to slot %d\n", slot);
}
}
void loadPatch(int slot) {
char filename[64];
snprintf(filename, sizeof(filename), "noicesynth_patch_%d.dat", slot);
FILE* f = fopen(filename, "rb");
if (f) {
fseek(f, 0, SEEK_END);
long size = ftell(f);
fseek(f, 0, SEEK_SET);
if (size > 0 && size <= (long)SynthEngine::MAX_SERIALIZED_GRID_SIZE) {
uint8_t buf[SynthEngine::MAX_SERIALIZED_GRID_SIZE];
fread(buf, 1, size, f);
engine.importGrid(buf, size);
printf("Loaded patch from slot %d (%s)\n", slot, filename);
}
fclose(f);
} else {
printf("Failed to load patch from slot %d (file not found)\n", slot);
}
}
/**
* @brief The audio callback function that miniaudio will call.
*
@ -923,6 +960,9 @@ void randomizeGrid() {
}
}
// 5. Update processing order for simulation
engine.updateGraph();
// 6. Run Simulation
engine.setGate(true);
float oldFreq = engine.getFrequency();
@ -1105,6 +1145,8 @@ int main(int argc, char* argv[]) {
SDL_Event e;
bool exportButtonPressed = false;
bool importButtonPressed = false;
bool saveButtonPressed = false;
bool loadButtonPressed = false;
while (!quit) {
checkSerialInput(serialPort);
@ -1206,6 +1248,18 @@ int main(int argc, char* argv[]) {
my >= importButtonRect.y && my <= importButtonRect.y + importButtonRect.h) {
importButtonPressed = true;
}
SDL_Rect saveButtonRect = {270, 535, 80, 30};
if (synthX >= saveButtonRect.x && synthX <= saveButtonRect.x + saveButtonRect.w &&
my >= saveButtonRect.y && my <= saveButtonRect.y + saveButtonRect.h) {
saveButtonPressed = true;
}
SDL_Rect loadButtonRect = {450, 535, 80, 30};
if (synthX >= loadButtonRect.x && synthX <= loadButtonRect.x + loadButtonRect.w &&
my >= loadButtonRect.y && my <= loadButtonRect.y + loadButtonRect.h) {
loadButtonPressed = true;
}
}
} else if (e.type == SDL_MOUSEWHEEL) {
SDL_Keymod modState = SDL_GetModState();
@ -1231,6 +1285,7 @@ int main(int argc, char* argv[]) {
// Synth Scroll
int synthX = mx - GRID_PANEL_WIDTH;
if (my < 500) {
if (synthX < SYNTH_PANEL_WIDTH / 2) { // Left knob (Octave)
if (e.wheel.y > 0) current_octave++;
else if (e.wheel.y < 0) current_octave--;
@ -1251,6 +1306,13 @@ int main(int argc, char* argv[]) {
if (knob_vol_val < 0.0f) knob_vol_val = 0.0f;
engine.setVolume(knob_vol_val);
}
} else {
// Patch Slot Knob
if (e.wheel.y > 0) current_patch_slot++;
else if (e.wheel.y < 0) current_patch_slot--;
if (current_patch_slot < 0) current_patch_slot = 0;
if (current_patch_slot > 7) current_patch_slot = 7;
}
}
} else if (e.type == SDL_KEYDOWN) {
if (e.key.repeat == 0) { // Ignore key repeats
@ -1330,6 +1392,30 @@ int main(int argc, char* argv[]) {
}
importButtonPressed = false;
}
if (saveButtonPressed) {
int mx = e.button.x;
int my = e.button.y;
int synthX = mx - GRID_PANEL_WIDTH;
SDL_Rect saveButtonRect = {270, 535, 80, 30};
if (mx >= GRID_PANEL_WIDTH &&
synthX >= saveButtonRect.x && synthX <= saveButtonRect.x + saveButtonRect.w &&
my >= saveButtonRect.y && my <= saveButtonRect.y + saveButtonRect.h) {
savePatch(current_patch_slot);
}
saveButtonPressed = false;
}
if (loadButtonPressed) {
int mx = e.button.x;
int my = e.button.y;
int synthX = mx - GRID_PANEL_WIDTH;
SDL_Rect loadButtonRect = {450, 535, 80, 30};
if (mx >= GRID_PANEL_WIDTH &&
synthX >= loadButtonRect.x && synthX <= loadButtonRect.x + loadButtonRect.w &&
my >= loadButtonRect.y && my <= loadButtonRect.y + loadButtonRect.h) {
loadPatch(current_patch_slot);
}
loadButtonPressed = false;
}
} else if (e.type == SDL_KEYUP) {
if (!auto_melody_enabled && e.key.keysym.scancode == current_key_scancode) {
engine.setGate(false);
@ -1340,11 +1426,12 @@ int main(int argc, char* argv[]) {
// Update window title with current values
char title[256];
snprintf(title, sizeof(title), "NoiceSynth | Vol: %.0f%% | Oct: %d | Auto(M): %s | Preset: %d",
snprintf(title, sizeof(title), "NoiceSynth | Vol: %.0f%% | Oct: %d | Auto(M): %s | Preset: %d | Slot: %d",
knob_vol_val * 100.0f,
current_octave,
auto_melody_enabled ? "ON" : "OFF",
current_preset);
current_preset,
current_patch_slot);
SDL_SetWindowTitle(window, title);
// Clear screen
@ -1411,6 +1498,16 @@ int main(int argc, char* argv[]) {
drawButton(renderer, 300, 435, 100, 30, "EXPORT", exportButtonPressed);
drawButton(renderer, 410, 435, 100, 30, "IMPORT", importButtonPressed);
// Patch Slot Control
float normalized_slot = (float)current_patch_slot / 7.0f;
drawKnob(renderer, 400, 550, 40, normalized_slot);
char slotBuf[16];
snprintf(slotBuf, sizeof(slotBuf), "SLOT %d", current_patch_slot);
drawString(renderer, 380, 600, 12, slotBuf);
drawButton(renderer, 270, 535, 80, 30, "SAVE", saveButtonPressed);
drawButton(renderer, 450, 535, 80, 30, "LOAD", loadButtonPressed);
// --- Draw Grid Panel (Left) ---
SDL_Rect gridViewport = {0, 0, GRID_PANEL_WIDTH, WINDOW_HEIGHT};
SDL_RenderSetViewport(renderer, &gridViewport);

View File

@ -348,6 +348,10 @@ void SynthEngine::rebuildProcessingOrder() {
rebuildProcessingOrder_locked();
}
void SynthEngine::updateGraph() {
rebuildProcessingOrder_locked();
}
float SynthEngine::processGridStep() {
auto isConnected = [&](int tx, int ty, int from_x, int from_y) -> bool {

View File

@ -118,6 +118,7 @@ public:
int importGrid(const uint8_t* buffer, size_t size);
void loadPreset(int preset);
void rebuildProcessingOrder();
void updateGraph();
void clearGrid();
GridCell grid[GRID_W][GRID_H];