Polyrhythm tracks

This commit is contained in:
Dejvino 2026-03-04 23:20:27 +01:00
parent 288a363618
commit e9f9682663
7 changed files with 78 additions and 53 deletions

View File

@ -4,6 +4,7 @@
#include "config.h" #include "config.h"
#include "SharedState.h" #include "SharedState.h"
static int local_numSteps[NUM_TRACKS];
static Step local_sequence[NUM_TRACKS][NUM_STEPS]; static Step local_sequence[NUM_TRACKS][NUM_STEPS];
static Step local_nextSequence[NUM_TRACKS][NUM_STEPS]; static Step local_nextSequence[NUM_TRACKS][NUM_STEPS];
@ -42,16 +43,24 @@ static void handlePlayback() {
midi.lock(); midi.lock();
memcpy(local_sequence, sequence, sizeof(local_sequence)); memcpy(local_sequence, sequence, sizeof(local_sequence));
memcpy(local_nextSequence, nextSequence, sizeof(local_nextSequence)); memcpy(local_nextSequence, nextSequence, sizeof(local_nextSequence));
for (int i = 0; i < NUM_TRACKS; i++) local_numSteps[i] = numSteps[i];
midi.unlock(); midi.unlock();
int master_len = 0;
for(int i=0; i<NUM_TRACKS; i++) {
if(local_numSteps[i] > master_len) master_len = local_numSteps[i];
}
if (master_len == 0) master_len = NUM_STEPS;
for(int t=0; t<NUM_TRACKS; t++) { for(int t=0; t<NUM_TRACKS; t++) {
int trackChannel = midiChannels[t]; int trackChannel = midiChannels[t];
int nextStep = playbackStep + 1; int track_len = local_numSteps[t];
if (nextStep >= numSteps) nextStep = 0; int current_step = playbackStep % track_len;
int next_step = (playbackStep + 1) % track_len;
// Determine if we are tying to the next note // Determine if we are tying to the next note
bool isTied = local_sequence[t][playbackStep].tie && (local_sequence[t][nextStep].note != -1); bool isTied = local_sequence[t][current_step].tie && (local_sequence[t][next_step].note != -1);
int prevNote = local_sequence[t][playbackStep].note; int prevNote = local_sequence[t][current_step].note;
// Note Off for previous step (if NOT tied) // Note Off for previous step (if NOT tied)
if (!isTied && prevNote != -1) { if (!isTied && prevNote != -1) {
@ -61,9 +70,8 @@ static void handlePlayback() {
playbackStep++; playbackStep++;
bool justPanicked = false; bool justPanicked = false;
if (playbackStep >= numSteps) { // When the global step counter completes a full cycle of the longest track
playbackStep = 0; if ((playbackStep > 0) && ((playbackStep % master_len) == 0)) {
for (int i=0; i<NUM_TRACKS; i++) midi.panic(midiChannels[i]); for (int i=0; i<NUM_TRACKS; i++) midi.panic(midiChannels[i]);
justPanicked = true; justPanicked = true;
@ -114,16 +122,18 @@ static void handlePlayback() {
// Note On for new step // Note On for new step
for(int t=0; t<NUM_TRACKS; t++) { for(int t=0; t<NUM_TRACKS; t++) {
int trackChannel = midiChannels[t]; int trackChannel = midiChannels[t];
int prevStep = (playbackStep == 0) ? numSteps - 1 : playbackStep - 1; int track_len = local_numSteps[t];
bool wasTied = local_sequence[t][prevStep].tie && (local_sequence[t][playbackStep].note != -1); int current_step = playbackStep % track_len;
int prevNote = local_sequence[t][prevStep].note; int prev_step = (playbackStep == 0) ? track_len - 1 : (playbackStep - 1) % track_len;
int currentNote = local_sequence[t][playbackStep].note; bool wasTied = local_sequence[t][prev_step].tie && (local_sequence[t][current_step].note != -1);
int prevNote = local_sequence[t][prev_step].note;
int currentNote = local_sequence[t][current_step].note;
// If tied to the SAME note, do not retrigger (sustain) // If tied to the SAME note, do not retrigger (sustain)
bool isContinuing = wasTied && (prevNote == currentNote) && !justPanicked; bool isContinuing = wasTied && (prevNote == currentNote) && !justPanicked;
if (!trackMute[t] && currentNote != -1 && !isContinuing) { if (!trackMute[t] && currentNote != -1 && !isContinuing) {
uint8_t velocity = local_sequence[t][playbackStep].accent ? 127 : 100; uint8_t velocity = local_sequence[t][current_step].accent ? 127 : 100;
midi.sendNoteOn(currentNote, velocity, trackChannel); midi.sendNoteOn(currentNote, velocity, trackChannel);
} }

View File

@ -62,7 +62,9 @@ void setup() {
EEPROM.begin(4096); EEPROM.begin(4096);
if (!loadSequence()) { if (!loadSequence()) {
Serial.println(F("Starting fresh instead.")); Serial.println(F("Starting fresh instead."));
numSteps = NUM_STEPS; for (int i = 0; i < NUM_TRACKS; i++) {
numSteps[i] = NUM_STEPS;
}
for(int i=0; i<NUM_TRACKS; i++) { for(int i=0; i<NUM_TRACKS; i++) {
midiChannels[i] = i + 1; midiChannels[i] = i + 1;

View File

@ -104,7 +104,7 @@ bool isItemVisible(int index) {
int menuSelection = 0; int menuSelection = 0;
volatile bool trackMute[NUM_TRACKS]; volatile bool trackMute[NUM_TRACKS];
int randomizeTrack = 0; int randomizeTrack = 0;
volatile int numSteps = NUM_STEPS; volatile int numSteps[NUM_TRACKS] = {NUM_STEPS, NUM_STEPS, NUM_STEPS, NUM_STEPS};
volatile int playbackStep = 0; volatile int playbackStep = 0;
volatile int midiChannels[NUM_TRACKS]; volatile int midiChannels[NUM_TRACKS];
int scaleNotes[12]; int scaleNotes[12];

View File

@ -65,7 +65,7 @@ bool isItemVisible(int index);
extern int menuSelection; extern int menuSelection;
extern volatile bool trackMute[NUM_TRACKS]; extern volatile bool trackMute[NUM_TRACKS];
extern int randomizeTrack; extern int randomizeTrack;
extern volatile int numSteps; extern volatile int numSteps[NUM_TRACKS];
extern volatile int playbackStep; extern volatile int playbackStep;
extern volatile int midiChannels[NUM_TRACKS]; extern volatile int midiChannels[NUM_TRACKS];
extern int scaleNotes[12]; extern int scaleNotes[12];

View File

@ -51,8 +51,8 @@ void UIManager::showMessage(const char* msg) {
void UIManager::draw(UIState currentState, int menuSelection, void UIManager::draw(UIState currentState, int menuSelection,
int midiChannel, int tempo, MelodyStrategy* currentStrategy, int midiChannel, int tempo, MelodyStrategy* currentStrategy,
int queuedTheme, int currentThemeIndex, int queuedTheme, int currentThemeIndex,
int numScaleNotes, const int* scaleNotes, int melodySeed, int numSteps, int numScaleNotes, const int* scaleNotes, int melodySeed, int currentTrackNumSteps,
bool mutationEnabled, bool songModeEnabled, bool mutationEnabled, bool songModeEnabled,
const Step sequence[][NUM_STEPS], int playbackStep, bool isPlaying, const Step sequence[][NUM_STEPS], int playbackStep, bool isPlaying,
int randomizeTrack, const bool* trackMute, const int* trackIntensities) { int randomizeTrack, const bool* trackMute, const int* trackIntensities) {
@ -64,7 +64,7 @@ void UIManager::draw(UIState currentState, int menuSelection,
switch(currentState) { switch(currentState) {
case UI_MENU_MAIN: case UI_MENU_MAIN:
drawMenu(menuSelection, currentState, midiChannel, tempo, currentStrategy->getName(), queuedTheme, currentThemeIndex, numScaleNotes, scaleNotes, melodySeed, numSteps, mutationEnabled, songModeEnabled, isPlaying, randomizeTrack, trackMute, trackIntensities); drawMenu(menuSelection, currentState, midiChannel, tempo, currentStrategy->getName(), queuedTheme, currentThemeIndex, numScaleNotes, scaleNotes, melodySeed, currentTrackNumSteps, mutationEnabled, songModeEnabled, isPlaying, randomizeTrack, trackMute, trackIntensities);
break; break;
case UI_SETUP_CHANNEL_EDIT: case UI_SETUP_CHANNEL_EDIT:
display.println(F("SET MIDI CHANNEL")); display.println(F("SET MIDI CHANNEL"));
@ -95,7 +95,7 @@ void UIManager::draw(UIState currentState, int menuSelection,
display.setCursor(20, 25); display.setCursor(20, 25);
display.setTextSize(2); display.setTextSize(2);
display.print(F("LEN: ")); display.print(F("LEN: "));
display.print(numSteps); display.print(currentTrackNumSteps);
display.setTextSize(1); display.setTextSize(1);
display.setCursor(0, 50); display.setCursor(0, 50);
display.println(F(" (Press to confirm)")); display.println(F(" (Press to confirm)"));
@ -233,8 +233,8 @@ void UIManager::drawNumberEditor(const char* title, int value, int minVal, int m
} }
void UIManager::drawMenu(int selection, UIState currentState, int midiChannel, int tempo, const char* flavourName, void UIManager::drawMenu(int selection, UIState currentState, int midiChannel, int tempo, const char* flavourName,
int queuedTheme, int currentThemeIndex, int numScaleNotes, int queuedTheme, int currentThemeIndex, int numScaleNotes,
const int* scaleNotes, int melodySeed, int numSteps, bool mutationEnabled, const int* scaleNotes, int melodySeed, int currentTrackNumSteps, bool mutationEnabled,
bool songModeEnabled, bool isPlaying, int randomizeTrack, const bool* trackMute, const int* trackIntensities) { bool songModeEnabled, bool isPlaying, int randomizeTrack, const bool* trackMute, const int* trackIntensities) {
// Calculate visual cursor position and scroll offset // Calculate visual cursor position and scroll offset
@ -294,7 +294,7 @@ void UIManager::drawMenu(int selection, UIState currentState, int midiChannel, i
} }
} }
} else if (id == MENU_ID_TEMPO) { display.print(F(": ")); display.print(tempo); } } else if (id == MENU_ID_TEMPO) { display.print(F(": ")); display.print(tempo); }
else if (id == MENU_ID_STEPS) { display.print(F(": ")); display.print(numSteps); } else if (id == MENU_ID_STEPS) { display.print(F(": ")); display.print(currentTrackNumSteps); }
else if (id == MENU_ID_SONG_MODE) { display.print(F(": ")); display.print(songModeEnabled ? F("ON") : F("OFF")); } else if (id == MENU_ID_SONG_MODE) { display.print(F(": ")); display.print(songModeEnabled ? F("ON") : F("OFF")); }
else if (id == MENU_ID_TRACK_SELECT) { display.print(F(": ")); display.print(randomizeTrack + 1); } else if (id == MENU_ID_TRACK_SELECT) { display.print(F(": ")); display.print(randomizeTrack + 1); }
else if (id == MENU_ID_MUTE) { display.print(F(": ")); display.print(trackMute[randomizeTrack] ? F("YES") : F("NO")); } else if (id == MENU_ID_MUTE) { display.print(F(": ")); display.print(trackMute[randomizeTrack] ? F("YES") : F("NO")); }
@ -342,7 +342,7 @@ int UIManager::getPixelIndex(int x, int y) {
void UIManager::updateLeds(const Step sequence[][NUM_STEPS], int playbackStep, bool isPlaying, void UIManager::updateLeds(const Step sequence[][NUM_STEPS], int playbackStep, bool isPlaying,
UIState currentState, bool songModeEnabled, UIState currentState, bool songModeEnabled,
int songRepeatsRemaining, bool sequenceChangeScheduled, PlayMode playMode, int songRepeatsRemaining, bool sequenceChangeScheduled, PlayMode playMode,
int selectedTrack, int numSteps, int numScaleNotes, const int* scaleNotes, const bool* trackMute) { int selectedTrack, const int* numSteps, int numScaleNotes, const int* scaleNotes, const bool* trackMute) {
pixels.clear(); pixels.clear();
const uint32_t COLOR_PLAYHEAD = pixels.Color(0, 255, 0); const uint32_t COLOR_PLAYHEAD = pixels.Color(0, 255, 0);
@ -354,7 +354,7 @@ void UIManager::updateLeds(const Step sequence[][NUM_STEPS], int playbackStep, b
if(playMode == MODE_POLY) { if(playMode == MODE_POLY) {
for(int t=0; t<NUM_TRACKS; t++) { for(int t=0; t<NUM_TRACKS; t++) {
for(int s=0; s<NUM_STEPS; s++) { for(int s=0; s<NUM_STEPS; s++) {
if (s >= numSteps) continue; if (s >= numSteps[t]) continue;
int row = t * 2 + (s / NUM_STEPS); int row = t * 2 + (s / NUM_STEPS);
int col = s % NUM_STEPS; int col = s % NUM_STEPS;
@ -366,7 +366,7 @@ void UIManager::updateLeds(const Step sequence[][NUM_STEPS], int playbackStep, b
color = getNoteColor(note, !sequence[t][s].accent); color = getNoteColor(note, !sequence[t][s].accent);
} }
if (isPlaying && s == playbackStep) { if (isPlaying && s == (playbackStep % numSteps[t])) {
if (trackMute[t]) { if (trackMute[t]) {
color = COLOR_MUTED_PLAYHEAD; color = COLOR_MUTED_PLAYHEAD;
} else { } else {
@ -381,12 +381,12 @@ void UIManager::updateLeds(const Step sequence[][NUM_STEPS], int playbackStep, b
// --- Mono Mode (original) --- // --- Mono Mode (original) ---
const Step* trackSequence = sequence[selectedTrack]; const Step* trackSequence = sequence[selectedTrack];
for (int s = 0; s < NUM_STEPS; s++) { for (int s = 0; s < NUM_STEPS; s++) {
if (s >= numSteps) continue; if (s >= numSteps[selectedTrack]) continue;
int x = s % NUM_STEPS; int x = s % NUM_STEPS;
int yBase = (s / NUM_STEPS) * 2; int yBase = (s / NUM_STEPS) * 2;
uint32_t color = 0, dimColor = 0; uint32_t color = 0, dimColor = 0;
bool isCursorHere = (isPlaying && s == playbackStep); bool isCursorHere = (isPlaying && s == (playbackStep % numSteps[selectedTrack]));
if (trackSequence[s].note != -1) { if (trackSequence[s].note != -1) {
color = getNoteColor(trackSequence[s].note, trackSequence[s].tie); color = getNoteColor(trackSequence[s].note, trackSequence[s].tie);
dimColor = getNoteColor(trackSequence[s].note, true); dimColor = getNoteColor(trackSequence[s].note, true);

View File

@ -15,9 +15,9 @@ public:
void showMessage(const char* msg); void showMessage(const char* msg);
void draw(UIState currentState, int menuSelection, void draw(UIState currentState, int menuSelection,
int midiChannel, int tempo, MelodyStrategy* currentStrategy, int midiChannel, int tempo, MelodyStrategy* currentStrategy,
int queuedTheme, int currentThemeIndex, int queuedTheme, int currentThemeIndex,
int numScaleNotes, const int* scaleNotes, int melodySeed, int numSteps, int numScaleNotes, const int* scaleNotes, int melodySeed, int currentTrackNumSteps,
bool mutationEnabled, bool songModeEnabled, bool mutationEnabled, bool songModeEnabled,
const Step sequence[][NUM_STEPS], int playbackStep, bool isPlaying, const Step sequence[][NUM_STEPS], int playbackStep, bool isPlaying,
int randomizeTrack, const bool* trackMute, const int* trackIntensities); int randomizeTrack, const bool* trackMute, const int* trackIntensities);
@ -25,7 +25,7 @@ public:
void updateLeds(const Step sequence[][NUM_STEPS], int playbackStep, bool isPlaying, void updateLeds(const Step sequence[][NUM_STEPS], int playbackStep, bool isPlaying,
UIState currentState, bool songModeEnabled, UIState currentState, bool songModeEnabled,
int songRepeatsRemaining, bool sequenceChangeScheduled, PlayMode playMode, int songRepeatsRemaining, bool sequenceChangeScheduled, PlayMode playMode,
int selectedTrack, int numSteps, int numScaleNotes, const int* scaleNotes, const bool* trackMute); int selectedTrack, const int* numSteps, int numScaleNotes, const int* scaleNotes, const bool* trackMute);
private: private:
Adafruit_SSD1306 display; Adafruit_SSD1306 display;
@ -33,7 +33,7 @@ private:
void drawMenu(int selection, UIState currentState, int midiChannel, int tempo, const char* flavourName, void drawMenu(int selection, UIState currentState, int midiChannel, int tempo, const char* flavourName,
int queuedTheme, int currentThemeIndex, int queuedTheme, int currentThemeIndex,
int numScaleNotes, const int* scaleNotes, int melodySeed, int numSteps, int numScaleNotes, const int* scaleNotes, int melodySeed, int currentTrackNumSteps,
bool mutationEnabled, bool songModeEnabled, bool isPlaying, int randomizeTrack, const bool* trackMute, const int* trackIntensities); bool mutationEnabled, bool songModeEnabled, bool isPlaying, int randomizeTrack, const bool* trackMute, const int* trackIntensities);
void drawNumberEditor(const char* title, int value, int minVal, int maxVal); void drawNumberEditor(const char* title, int value, int minVal, int maxVal);

View File

@ -44,9 +44,11 @@ void saveSequence(bool quiet) {
EEPROM.put(addr, mutes); addr += sizeof(mutes); EEPROM.put(addr, mutes); addr += sizeof(mutes);
EEPROM.put(addr, (int)tempo); addr += sizeof(int); EEPROM.put(addr, (int)tempo); addr += sizeof(int);
int intensities[NUM_TRACKS]; int intensities[NUM_TRACKS];
for(int i=0; i<NUM_TRACKS; i++) intensities[i] = trackIntensity[i]; for(int i=0; i<NUM_TRACKS; i++) intensities[i] = (int)trackIntensity[i];
EEPROM.put(addr, intensities); addr += sizeof(intensities); EEPROM.put(addr, intensities); addr += sizeof(intensities);
EEPROM.put(addr, (int)numSteps); addr += sizeof(int); int steps[NUM_TRACKS];
for(int i=0; i<NUM_TRACKS; i++) steps[i] = numSteps[i];
EEPROM.put(addr, steps); addr += sizeof(steps);
EEPROM.put(addr, numScaleNotes); addr += sizeof(numScaleNotes); EEPROM.put(addr, numScaleNotes); addr += sizeof(numScaleNotes);
for (int i = 0; i<12; i++) { for (int i = 0; i<12; i++) {
@ -96,9 +98,14 @@ bool loadSequence() {
if (trackIntensity[i] < 1) trackIntensity[i] = 1; if (trackIntensity[i] < 1) trackIntensity[i] = 1;
if (trackIntensity[i] > 10) trackIntensity[i] = 10; if (trackIntensity[i] > 10) trackIntensity[i] = 10;
} }
EEPROM.get(addr, t); addr += sizeof(int); int steps[NUM_TRACKS];
numSteps = t; EEPROM.get(addr, steps); addr += sizeof(steps);
if (numSteps <= 0 || numSteps >= NUM_STEPS) numSteps = NUM_STEPS; for(int i=0; i<NUM_TRACKS; i++) {
numSteps[i] = steps[i];
if (numSteps[i] <= 0 || numSteps[i] > NUM_STEPS) {
numSteps[i] = NUM_STEPS;
}
}
EEPROM.get(addr, numScaleNotes); addr += sizeof(numScaleNotes); EEPROM.get(addr, numScaleNotes); addr += sizeof(numScaleNotes);
if (numScaleNotes < 0 || numScaleNotes > 12) numScaleNotes = 0; if (numScaleNotes < 0 || numScaleNotes > 12) numScaleNotes = 0;
@ -124,7 +131,9 @@ static void savePatch(int bank, int slot) {
} }
EEPROM.put(addr, currentStrategyIndices); addr += sizeof(currentStrategyIndices); EEPROM.put(addr, currentStrategyIndices); addr += sizeof(currentStrategyIndices);
EEPROM.put(addr, melodySeeds); addr += sizeof(melodySeeds); EEPROM.put(addr, melodySeeds); addr += sizeof(melodySeeds);
EEPROM.put(addr, (int)numSteps); addr += sizeof(int); int steps[NUM_TRACKS];
for(int i=0; i<NUM_TRACKS; i++) steps[i] = numSteps[i];
EEPROM.put(addr, steps); addr += sizeof(steps);
bool mutes[NUM_TRACKS]; bool mutes[NUM_TRACKS];
for(int i=0; i<NUM_TRACKS; i++) mutes[i] = trackMute[i]; for(int i=0; i<NUM_TRACKS; i++) mutes[i] = trackMute[i];
EEPROM.put(addr, mutes); addr += sizeof(mutes); EEPROM.put(addr, mutes); addr += sizeof(mutes);
@ -153,10 +162,14 @@ static void loadPatch(int bank, int slot) {
if (currentStrategyIndices[i] < 0 || currentStrategyIndices[i] >= numStrategies) currentStrategyIndices[i] = 0; if (currentStrategyIndices[i] < 0 || currentStrategyIndices[i] >= numStrategies) currentStrategyIndices[i] = 0;
} }
EEPROM.get(addr, melodySeeds); addr += sizeof(melodySeeds); EEPROM.get(addr, melodySeeds); addr += sizeof(melodySeeds);
int t; int steps[NUM_TRACKS];
EEPROM.get(addr, t); addr += sizeof(int); EEPROM.get(addr, steps); addr += sizeof(steps);
numSteps = t; for(int i=0; i<NUM_TRACKS; i++) {
if (numSteps <= 0 || numSteps >= NUM_STEPS) numSteps = NUM_STEPS; numSteps[i] = steps[i];
if (numSteps[i] <= 0 || numSteps[i] > NUM_STEPS) {
numSteps[i] = NUM_STEPS;
}
}
bool mutes[NUM_TRACKS]; bool mutes[NUM_TRACKS];
EEPROM.get(addr, mutes); addr += sizeof(mutes); EEPROM.get(addr, mutes); addr += sizeof(mutes);
@ -195,7 +208,7 @@ void factoryReset() {
static void generateTrackData(int track, int themeType, Step (*target)[NUM_STEPS]) { static void generateTrackData(int track, int themeType, Step (*target)[NUM_STEPS]) {
randomSeed(melodySeeds[track] + themeType * 12345); randomSeed(melodySeeds[track] + themeType * 12345);
strategies[currentStrategyIndices[track]]->generate(target, track, numSteps, scaleNotes, numScaleNotes, melodySeeds[track] + themeType * 12345, trackIntensity[track]); strategies[currentStrategyIndices[track]]->generate(target, track, numSteps[track], scaleNotes, numScaleNotes, melodySeeds[track] + themeType * 12345, trackIntensity[track]);
} }
void generateRandomScale() { void generateRandomScale() {
@ -229,7 +242,7 @@ void generateTheme(int themeType) {
} }
void mutateSequence(Step (*target)[NUM_STEPS]) { void mutateSequence(Step (*target)[NUM_STEPS]) {
for(int i=0; i<NUM_TRACKS; i++) strategies[currentStrategyIndices[i]]->mutate(target, i, numSteps, scaleNotes, numScaleNotes, trackIntensity[i]); for(int i=0; i<NUM_TRACKS; i++) strategies[currentStrategyIndices[i]]->mutate(target, i, numSteps[i], scaleNotes, numScaleNotes, trackIntensity[i]);
} }
static void handleInput() { static void handleInput() {
@ -268,9 +281,9 @@ static void handleInput() {
if (tempo > 240) tempo = 240; if (tempo > 240) tempo = 240;
break; break;
case UI_EDIT_STEPS: case UI_EDIT_STEPS:
numSteps += delta; numSteps[randomizeTrack] += delta;
if (numSteps < 1) numSteps = 1; if (numSteps[randomizeTrack] < 1) numSteps[randomizeTrack] = 1;
if (numSteps > NUM_STEPS) numSteps = NUM_STEPS; if (numSteps[randomizeTrack] > NUM_STEPS) numSteps[randomizeTrack] = NUM_STEPS;
break; break;
case UI_EDIT_FLAVOUR: case UI_EDIT_FLAVOUR:
{ {
@ -570,7 +583,7 @@ static void drawUI() {
// to avoid holding the lock during slow display operations. // to avoid holding the lock during slow display operations.
UIState local_currentState; UIState local_currentState;
int local_menuSelection, local_randomizeTrack, local_tempo, local_currentThemeIndex, local_queuedTheme, local_numScaleNotes; int local_menuSelection, local_randomizeTrack, local_tempo, local_currentThemeIndex, local_queuedTheme, local_numScaleNotes;
int local_melodySeed, local_numSteps; int local_melodySeed, local_currentTrackNumSteps;
bool local_mutationEnabled, local_songModeEnabled, local_isPlaying; bool local_mutationEnabled, local_songModeEnabled, local_isPlaying;
bool local_trackMute[NUM_TRACKS]; bool local_trackMute[NUM_TRACKS];
int local_midiChannel; int local_midiChannel;
@ -590,7 +603,7 @@ static void drawUI() {
} }
local_midiChannel = midiChannels[local_randomizeTrack]; local_midiChannel = midiChannels[local_randomizeTrack];
local_tempo = tempo; local_tempo = tempo;
local_numSteps = numSteps; local_currentTrackNumSteps = numSteps[local_randomizeTrack];
local_strategy = strategies[currentStrategyIndices[local_randomizeTrack]]; local_strategy = strategies[currentStrategyIndices[local_randomizeTrack]];
local_queuedTheme = queuedTheme; local_queuedTheme = queuedTheme;
local_currentThemeIndex = currentThemeIndex; local_currentThemeIndex = currentThemeIndex;
@ -608,7 +621,7 @@ static void drawUI() {
ui.draw(local_currentState, local_menuSelection, ui.draw(local_currentState, local_menuSelection,
local_midiChannel, local_tempo, local_strategy, local_midiChannel, local_tempo, local_strategy,
local_queuedTheme, local_currentThemeIndex, local_numScaleNotes, local_scaleNotes, local_melodySeed, local_numSteps, local_queuedTheme, local_currentThemeIndex, local_numScaleNotes, local_scaleNotes, local_melodySeed, local_currentTrackNumSteps,
local_mutationEnabled, local_songModeEnabled, (const Step (*)[NUM_STEPS])local_sequence, local_playbackStep, local_isPlaying, local_randomizeTrack, (const bool*)local_trackMute, (const int*)local_trackIntensities); local_mutationEnabled, local_songModeEnabled, (const Step (*)[NUM_STEPS])local_sequence, local_playbackStep, local_isPlaying, local_randomizeTrack, (const bool*)local_trackMute, (const int*)local_trackIntensities);
} }
@ -623,8 +636,8 @@ static void updateLeds() {
int local_songRepeatsRemaining; int local_songRepeatsRemaining;
bool local_sequenceChangeScheduled; bool local_sequenceChangeScheduled;
PlayMode local_playMode; PlayMode local_playMode;
int local_numScaleNotes, local_numSteps; int local_numScaleNotes;
int local_scaleNotes[12]; int local_scaleNotes[12], local_numSteps[NUM_TRACKS];
bool local_trackMute[NUM_TRACKS]; bool local_trackMute[NUM_TRACKS];
int local_randomizeTrack; int local_randomizeTrack;
@ -639,7 +652,7 @@ static void updateLeds() {
local_sequenceChangeScheduled = sequenceChangeScheduled; local_sequenceChangeScheduled = sequenceChangeScheduled;
local_playMode = playMode; local_playMode = playMode;
local_numScaleNotes = numScaleNotes; local_numScaleNotes = numScaleNotes;
local_numSteps = numSteps; for (int i = 0; i < NUM_TRACKS; i++) local_numSteps[i] = numSteps[i];
local_randomizeTrack = randomizeTrack; local_randomizeTrack = randomizeTrack;
memcpy(local_scaleNotes, scaleNotes, sizeof(local_scaleNotes)); memcpy(local_scaleNotes, scaleNotes, sizeof(local_scaleNotes));
memcpy(local_trackMute, (const void*)trackMute, sizeof(local_trackMute)); memcpy(local_trackMute, (const void*)trackMute, sizeof(local_trackMute));
@ -661,7 +674,7 @@ static void updateLeds() {
ui.updateLeds((const Step (*)[NUM_STEPS])local_sequence, local_playbackStep, local_isPlaying, ui.updateLeds((const Step (*)[NUM_STEPS])local_sequence, local_playbackStep, local_isPlaying,
local_currentState, local_songModeEnabled, local_songRepeatsRemaining, local_currentState, local_songModeEnabled, local_songRepeatsRemaining,
local_sequenceChangeScheduled, ledDisplayMode, local_randomizeTrack, local_numSteps, local_numScaleNotes, local_sequenceChangeScheduled, ledDisplayMode, local_randomizeTrack, local_numSteps, local_numScaleNotes,
local_scaleNotes, (const bool*)local_trackMute); local_scaleNotes, (const bool*)local_trackMute);
} }