diff --git a/RP2040_Tracker.ino b/RP2040_Tracker.ino index 145a776..efb6208 100644 --- a/RP2040_Tracker.ino +++ b/RP2040_Tracker.ino @@ -38,7 +38,7 @@ struct Step { Step sequence[NUM_STEPS]; Step nextSequence[NUM_STEPS]; -volatile bool nextSequenceReady = false; +volatile bool sequenceChangeScheduled = false; volatile bool needsPanic = false; mutex_t midiMutex; @@ -414,7 +414,7 @@ void handleInput() { int theme = (queuedTheme != -1) ? queuedTheme : currentThemeIndex; mutex_enter_blocking(&midiMutex); generateSequenceData(theme, nextSequence); - nextSequenceReady = true; + sequenceChangeScheduled = true; mutex_exit(&midiMutex); } } @@ -424,7 +424,7 @@ void handleInput() { int theme = (queuedTheme != -1) ? queuedTheme : currentThemeIndex; mutex_enter_blocking(&midiMutex); generateSequenceData(theme, nextSequence); - nextSequenceReady = true; + sequenceChangeScheduled = true; mutex_exit(&midiMutex); } } @@ -432,14 +432,7 @@ void handleInput() { if (menuSelection == 4) { songModeEnabled = !songModeEnabled; if (songModeEnabled) { - // Start Song Mode immediately - if (isPlaying) { - songModeNeedsNext = true; - } else { - // If stopped, just generate a start - songModeNeedsNext = true; - // We rely on the loop() to pick it up, or we can force it here if not playing - } + songModeNeedsNext = true; } } if (menuSelection >= THEME_1_INDEX) { // Themes @@ -448,7 +441,7 @@ void handleInput() { queuedTheme = selectedTheme; mutex_enter_blocking(&midiMutex); generateSequenceData(queuedTheme, nextSequence); - nextSequenceReady = true; + sequenceChangeScheduled = true; mutex_exit(&midiMutex); } else { generateTheme(selectedTheme); @@ -536,28 +529,42 @@ void handlePlayback() { if (playbackStep >= NUM_STEPS) { playbackStep = 0; + // Theme change + if (sequenceChangeScheduled && queuedTheme != -1) { + currentThemeIndex = queuedTheme; + queuedTheme = -1; + // nextSequence is already generated + } + // Mutation - if (mutationEnabled && !nextSequenceReady) { - memcpy(nextSequence, sequence, sizeof(sequence)); - mutateSequence(nextSequence); - nextSequenceReady = true; - } - - // Song Mode Logic - if (songModeEnabled && songRepeatsRemaining > 0) { - songRepeatsRemaining--; - } - - if (nextSequenceReady) { - sendMidi(0xB0, 123, 0); // Panic / All Notes Off - memcpy(sequence, nextSequence, sizeof(sequence)); - nextSequenceReady = false; - if (queuedTheme != -1) { - currentThemeIndex = queuedTheme; - queuedTheme = -1; + if (mutationEnabled) { + if (!sequenceChangeScheduled) { + memcpy(nextSequence, sequence, sizeof(sequence)); } - if (songModeEnabled) { + mutateSequence(nextSequence); + sequenceChangeScheduled = true; + } + + sendMidi(0xB0, 123, 0); // Panic / All Notes Off + + if (sequenceChangeScheduled) { + memcpy(sequence, nextSequence, sizeof(sequence)); + sequenceChangeScheduled = false; + } + + // Song Mode? Advance repeats + if (songModeEnabled) { + // we just used one repeat + if (songRepeatsRemaining <= 1) { + // let's start another round songRepeatsRemaining = nextSongRepeats; + } else { + // next repeat + songRepeatsRemaining--; + } + // Trigger next song segment generation if we are on the last repeat + if (songRepeatsRemaining <= 1 && !sequenceChangeScheduled && !songModeNeedsNext) { + songModeNeedsNext = true; } } } @@ -573,11 +580,6 @@ void handlePlayback() { sendMidi(0x80, prevNote, 0); } - // Trigger next song segment generation if we are on the last repeat - if (songModeEnabled && songRepeatsRemaining == 1 && !nextSequenceReady && !songModeNeedsNext) { - songModeNeedsNext = true; - } - mutex_exit(&midiMutex); } } @@ -876,7 +878,7 @@ void updateLeds() { pixels.setPixelColor(getPixelIndex(x, yBase + 3), colorP3); } - if (nextSequenceReady && (millis() / 125) % 2) { + if (sequenceChangeScheduled && (millis() / 125) % 2) { pixels.setPixelColor(NUM_PIXELS - 1, pixels.Color(127, 50, 0)); } mutex_exit(&midiMutex); @@ -904,7 +906,7 @@ void loop() { generateSequenceData(nextTheme, nextSequence); queuedTheme = nextTheme; nextSongRepeats = repeats; - nextSequenceReady = true; + sequenceChangeScheduled = true; mutex_exit(&midiMutex); songModeNeedsNext = false;