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;
|
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;
|
int current_preset = 0;
|
||||||
|
int current_patch_slot = 0; // 0-7
|
||||||
|
|
||||||
float note_to_freq(int octave, int semitone_offset);
|
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.
|
// The audio callback needs access to our synth, so we make it global.
|
||||||
SynthEngine engine(SAMPLE_RATE);
|
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.
|
* @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
|
// 6. Run Simulation
|
||||||
engine.setGate(true);
|
engine.setGate(true);
|
||||||
float oldFreq = engine.getFrequency();
|
float oldFreq = engine.getFrequency();
|
||||||
@ -1105,6 +1145,8 @@ int main(int argc, char* argv[]) {
|
|||||||
SDL_Event e;
|
SDL_Event e;
|
||||||
bool exportButtonPressed = false;
|
bool exportButtonPressed = false;
|
||||||
bool importButtonPressed = false;
|
bool importButtonPressed = false;
|
||||||
|
bool saveButtonPressed = false;
|
||||||
|
bool loadButtonPressed = false;
|
||||||
|
|
||||||
while (!quit) {
|
while (!quit) {
|
||||||
checkSerialInput(serialPort);
|
checkSerialInput(serialPort);
|
||||||
@ -1206,6 +1248,18 @@ int main(int argc, char* argv[]) {
|
|||||||
my >= importButtonRect.y && my <= importButtonRect.y + importButtonRect.h) {
|
my >= importButtonRect.y && my <= importButtonRect.y + importButtonRect.h) {
|
||||||
importButtonPressed = true;
|
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) {
|
} else if (e.type == SDL_MOUSEWHEEL) {
|
||||||
SDL_Keymod modState = SDL_GetModState();
|
SDL_Keymod modState = SDL_GetModState();
|
||||||
@ -1231,26 +1285,34 @@ int main(int argc, char* argv[]) {
|
|||||||
// Synth Scroll
|
// Synth Scroll
|
||||||
int synthX = mx - GRID_PANEL_WIDTH;
|
int synthX = mx - GRID_PANEL_WIDTH;
|
||||||
|
|
||||||
if (synthX < SYNTH_PANEL_WIDTH / 2) { // Left knob (Octave)
|
if (my < 500) {
|
||||||
if (e.wheel.y > 0) current_octave++;
|
if (synthX < SYNTH_PANEL_WIDTH / 2) { // Left knob (Octave)
|
||||||
else if (e.wheel.y < 0) current_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 < 0) current_octave = 0;
|
||||||
if (current_octave > 8) current_octave = 8;
|
if (current_octave > 8) current_octave = 8;
|
||||||
|
|
||||||
// If a note is being held, update its frequency to the new octave
|
// If a note is being held, update its frequency to the new octave
|
||||||
if (!auto_melody_enabled && current_key_scancode != 0) {
|
if (!auto_melody_enabled && current_key_scancode != 0) {
|
||||||
engine.setFrequency(note_to_freq(current_octave, key_to_note_map[ (SDL_Scancode)current_key_scancode ]));
|
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) {
|
} else if (e.type == SDL_KEYDOWN) {
|
||||||
if (e.key.repeat == 0) { // Ignore key repeats
|
if (e.key.repeat == 0) { // Ignore key repeats
|
||||||
@ -1330,6 +1392,30 @@ int main(int argc, char* argv[]) {
|
|||||||
}
|
}
|
||||||
importButtonPressed = false;
|
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) {
|
} else if (e.type == SDL_KEYUP) {
|
||||||
if (!auto_melody_enabled && e.key.keysym.scancode == current_key_scancode) {
|
if (!auto_melody_enabled && e.key.keysym.scancode == current_key_scancode) {
|
||||||
engine.setGate(false);
|
engine.setGate(false);
|
||||||
@ -1340,11 +1426,12 @@ 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 | Preset: %d",
|
snprintf(title, sizeof(title), "NoiceSynth | Vol: %.0f%% | Oct: %d | Auto(M): %s | Preset: %d | Slot: %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);
|
current_preset,
|
||||||
|
current_patch_slot);
|
||||||
SDL_SetWindowTitle(window, title);
|
SDL_SetWindowTitle(window, title);
|
||||||
|
|
||||||
// Clear screen
|
// Clear screen
|
||||||
@ -1411,6 +1498,16 @@ int main(int argc, char* argv[]) {
|
|||||||
drawButton(renderer, 300, 435, 100, 30, "EXPORT", exportButtonPressed);
|
drawButton(renderer, 300, 435, 100, 30, "EXPORT", exportButtonPressed);
|
||||||
drawButton(renderer, 410, 435, 100, 30, "IMPORT", importButtonPressed);
|
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) ---
|
// --- Draw Grid Panel (Left) ---
|
||||||
SDL_Rect gridViewport = {0, 0, GRID_PANEL_WIDTH, WINDOW_HEIGHT};
|
SDL_Rect gridViewport = {0, 0, GRID_PANEL_WIDTH, WINDOW_HEIGHT};
|
||||||
SDL_RenderSetViewport(renderer, &gridViewport);
|
SDL_RenderSetViewport(renderer, &gridViewport);
|
||||||
|
|||||||
@ -348,6 +348,10 @@ void SynthEngine::rebuildProcessingOrder() {
|
|||||||
rebuildProcessingOrder_locked();
|
rebuildProcessingOrder_locked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SynthEngine::updateGraph() {
|
||||||
|
rebuildProcessingOrder_locked();
|
||||||
|
}
|
||||||
|
|
||||||
float SynthEngine::processGridStep() {
|
float SynthEngine::processGridStep() {
|
||||||
|
|
||||||
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 {
|
||||||
|
|||||||
@ -118,6 +118,7 @@ public:
|
|||||||
int importGrid(const uint8_t* buffer, size_t size);
|
int importGrid(const uint8_t* buffer, size_t size);
|
||||||
void loadPreset(int preset);
|
void loadPreset(int preset);
|
||||||
void rebuildProcessingOrder();
|
void rebuildProcessingOrder();
|
||||||
|
void updateGraph();
|
||||||
void clearGrid();
|
void clearGrid();
|
||||||
|
|
||||||
GridCell grid[GRID_W][GRID_H];
|
GridCell grid[GRID_W][GRID_H];
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user