fix initial grid state
This commit is contained in:
parent
534a7512c4
commit
c7aa020f67
@ -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,26 +1285,34 @@ int main(int argc, char* argv[]) {
|
||||
// Synth Scroll
|
||||
int synthX = mx - GRID_PANEL_WIDTH;
|
||||
|
||||
if (synthX < SYNTH_PANEL_WIDTH / 2) { // Left knob (Octave)
|
||||
if (e.wheel.y > 0) current_octave++;
|
||||
else if (e.wheel.y < 0) current_octave--;
|
||||
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--;
|
||||
|
||||
if (current_octave < 0) current_octave = 0;
|
||||
if (current_octave > 8) current_octave = 8;
|
||||
if (current_octave < 0) current_octave = 0;
|
||||
if (current_octave > 8) current_octave = 8;
|
||||
|
||||
// If a note is being held, update its frequency to the new octave
|
||||
if (!auto_melody_enabled && current_key_scancode != 0) {
|
||||
engine.setFrequency(note_to_freq(current_octave, key_to_note_map[ (SDL_Scancode)current_key_scancode ]));
|
||||
// If a note is being held, update its frequency to the new octave
|
||||
if (!auto_melody_enabled && current_key_scancode != 0) {
|
||||
engine.setFrequency(note_to_freq(current_octave, key_to_note_map[ (SDL_Scancode)current_key_scancode ]));
|
||||
}
|
||||
} else { // Right knob (volume)
|
||||
float volStep = fineTune ? 0.01f : 0.05f;
|
||||
if (e.wheel.y > 0) knob_vol_val += volStep;
|
||||
else if (e.wheel.y < 0) knob_vol_val -= volStep;
|
||||
|
||||
if (knob_vol_val > 1.0f) knob_vol_val = 1.0f;
|
||||
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 { // Right knob (volume)
|
||||
float volStep = fineTune ? 0.01f : 0.05f;
|
||||
if (e.wheel.y > 0) knob_vol_val += volStep;
|
||||
else if (e.wheel.y < 0) knob_vol_val -= volStep;
|
||||
|
||||
if (knob_vol_val > 1.0f) knob_vol_val = 1.0f;
|
||||
if (knob_vol_val < 0.0f) knob_vol_val = 0.0f;
|
||||
engine.setVolume(knob_vol_val);
|
||||
}
|
||||
}
|
||||
} 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);
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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];
|
||||
|
||||
Loading…
Reference in New Issue
Block a user