#include "MidiDriver.h" #include "TrackerTypes.h" #include "UIThread.h" #include "config.h" #include "SharedState.h" bool wasPlaying = false; static void handlePlayback() { bool nowPlaying = isPlaying; int tracksToPlay = (playMode == MODE_POLY) ? NUM_TRACKS : 1; if (!wasPlaying && !nowPlaying) { midi.sendRealtime(0xFA); // MIDI Start } else if (wasPlaying && !nowPlaying) { midi.sendRealtime(0xFC); // MIDI Stop for (int i=0; i= clockInterval) { lastClockTime += clockInterval; midi.sendRealtime(0xF8); // MIDI Clock clockCount++; if (clockCount < 6) return; // 24 ppqn / 4 = 6 pulses per 16th note clockCount = 0; midi.lock(); Step local_sequence[NUM_TRACKS][NUM_STEPS]; memcpy(local_sequence, sequence, sizeof(local_sequence)); Step local_nextSequence[NUM_TRACKS][NUM_STEPS]; memcpy(local_nextSequence, nextSequence, sizeof(local_nextSequence)); midi.unlock(); for(int t=0; t= NUM_STEPS) nextStep = 0; // Determine if we are tying to the next note bool isTied = local_sequence[t][playbackStep].tie && (local_sequence[t][nextStep].note != -1); int prevNote = local_sequence[t][playbackStep].note; // Note Off for previous step (if NOT tied) if (!isTied && prevNote != -1) { midi.sendNoteOff(prevNote, trackChannel); } } playbackStep++; if (playbackStep >= NUM_STEPS) { playbackStep = 0; // Theme change if (sequenceChangeScheduled && queuedTheme != -1) { currentThemeIndex = queuedTheme; queuedTheme = -1; // nextSequence is already generated } // Mutation if (mutationEnabled) { if (!sequenceChangeScheduled) { memcpy(local_nextSequence, local_sequence, sizeof(sequence)); } mutateSequence(local_nextSequence); midi.lock(); memcpy(nextSequence, local_nextSequence, sizeof(sequence)); sequenceChangeScheduled = true; midi.unlock(); } for (int i=0; i 1000)) { Serial.println("Core 0 Freeze detected"); rp2040.reboot(); } if (needsPanic) { if (playMode == MODE_POLY) { for (int i=0; i