Root note and bitmap of scale types

This commit is contained in:
Dejvino
2026-03-06 21:29:17 +01:00
parent 84ef40a555
commit b6150cbacd
5 changed files with 167 additions and 2 deletions
+112
View File
@@ -22,6 +22,7 @@ static Step local_sequence[NUM_TRACKS][NUM_STEPS];
static void handleInput();
static int scaleEditSelection = 0;
static int scaleTypeEditIndex = 0;
static int scaleEditNoteIndex = 0;
static void drawUI();
static void updateLeds();
@@ -29,6 +30,8 @@ static void generateTrackData(int track, int themeType, Step (*target)[NUM_STEPS
static void generateSequenceData(int themeType, Step (*target)[NUM_STEPS]);
static void savePatch(int bank, int slot);
static void loadPatch(int bank, int slot);
static void updateScale();
static void pickRandomScaleType();
void saveSequence(bool quiet) {
midi.lock();
@@ -50,6 +53,9 @@ void saveSequence(bool quiet) {
for(int i=0; i<NUM_TRACKS; i++) steps[i] = numSteps[i];
EEPROM.put(addr, steps); addr += sizeof(steps);
EEPROM.put(addr, currentRoot); addr += sizeof(currentRoot);
EEPROM.put(addr, currentScaleType); addr += sizeof(currentScaleType);
EEPROM.put(addr, enabledScaleTypes); addr += sizeof(enabledScaleTypes);
EEPROM.put(addr, numScaleNotes); addr += sizeof(numScaleNotes);
for (int i = 0; i<12; i++) {
EEPROM.put(addr, scaleNotes[i]); addr += sizeof(int);
@@ -107,6 +113,9 @@ bool loadSequence() {
}
}
EEPROM.get(addr, currentRoot); addr += sizeof(currentRoot);
EEPROM.get(addr, currentScaleType); addr += sizeof(currentScaleType);
EEPROM.get(addr, enabledScaleTypes); addr += sizeof(enabledScaleTypes);
EEPROM.get(addr, numScaleNotes); addr += sizeof(numScaleNotes);
if (numScaleNotes < 0 || numScaleNotes > 12) numScaleNotes = 0;
for (int i = 0; i<12; i++) {
@@ -125,6 +134,9 @@ static void savePatch(int bank, int slot) {
int addr = 512 + patchIndex * 256; // Start after main save, 256 bytes per patch
midi.lock();
EEPROM.put(addr, currentRoot); addr += sizeof(currentRoot);
EEPROM.put(addr, currentScaleType); addr += sizeof(currentScaleType);
EEPROM.put(addr, enabledScaleTypes); addr += sizeof(enabledScaleTypes);
EEPROM.put(addr, numScaleNotes); addr += sizeof(numScaleNotes);
for (int i = 0; i < 12; i++) {
EEPROM.put(addr, scaleNotes[i]); addr += sizeof(int);
@@ -150,6 +162,9 @@ static void loadPatch(int bank, int slot) {
int addr = 512 + patchIndex * 256;
midi.lock();
EEPROM.get(addr, currentRoot); addr += sizeof(currentRoot);
EEPROM.get(addr, currentScaleType); addr += sizeof(currentScaleType);
EEPROM.get(addr, enabledScaleTypes); addr += sizeof(enabledScaleTypes);
EEPROM.get(addr, numScaleNotes); addr += sizeof(numScaleNotes);
if (numScaleNotes < 0 || numScaleNotes > 12) numScaleNotes = 0;
for (int i = 0; i < 12; i++) {
@@ -225,6 +240,7 @@ static void generateSequenceData(int themeType, Step (*target)[NUM_STEPS]) {
}
void generateTheme(int themeType) {
pickRandomScaleType();
generateSequenceData(themeType, local_sequence);
Serial.println(F("Generating theme."));
@@ -249,6 +265,67 @@ void mutateSequence(Step (*target)[NUM_STEPS]) {
}
}
static void updateScale() {
// 0: Chromatic, 1: Major, 2: Minor, 3: Harm Min, 4: Pent Maj, 5: Pent Min, 6: Chord Maj, 7: Chord Min, 8: Chord Dim, 9: Chord 7
int intervals[12];
int count = 0;
switch(currentScaleType) {
case 0: // Chromatic
for(int i=0; i<12; i++) intervals[count++] = i;
break;
case 1: // Major
intervals[0]=0; intervals[1]=2; intervals[2]=4; intervals[3]=5; intervals[4]=7; intervals[5]=9; intervals[6]=11; count=7;
break;
case 2: // Minor
intervals[0]=0; intervals[1]=2; intervals[2]=3; intervals[3]=5; intervals[4]=7; intervals[5]=8; intervals[6]=10; count=7;
break;
case 3: // Harmonic Minor
intervals[0]=0; intervals[1]=2; intervals[2]=3; intervals[3]=5; intervals[4]=7; intervals[5]=8; intervals[6]=11; count=7;
break;
case 4: // Pentatonic Major
intervals[0]=0; intervals[1]=2; intervals[2]=4; intervals[3]=7; intervals[4]=9; count=5;
break;
case 5: // Pentatonic Minor
intervals[0]=0; intervals[1]=3; intervals[2]=5; intervals[3]=7; intervals[4]=10; count=5;
break;
case 6: // Chord Major
intervals[0]=0; intervals[1]=4; intervals[2]=7; count=3;
break;
case 7: // Chord Minor
intervals[0]=0; intervals[1]=3; intervals[2]=7; count=3;
break;
case 8: // Chord Dim
intervals[0]=0; intervals[1]=3; intervals[2]=6; count=3;
break;
case 9: // Chord 7
intervals[0]=0; intervals[1]=4; intervals[2]=7; intervals[3]=10; count=4;
break;
}
midi.lock();
numScaleNotes = count;
for(int i=0; i<count; i++) {
scaleNotes[i] = (currentRoot + intervals[i]) % 12;
}
sortArray(scaleNotes, numScaleNotes);
midi.unlock();
}
static void pickRandomScaleType() {
int candidates[10];
int count = 0;
for (int i = 0; i < 10; i++) {
if (enabledScaleTypes & (1 << i)) {
candidates[count++] = i;
}
}
if (count > 0) {
currentScaleType = candidates[random(count)];
updateScale();
}
}
static void handleInput() {
// Handle Encoder Rotation
int delta = 0;
@@ -289,6 +366,21 @@ static void handleInput() {
if (numSteps[randomizeTrack] < 1) numSteps[randomizeTrack] = 1;
if (numSteps[randomizeTrack] > NUM_STEPS) numSteps[randomizeTrack] = NUM_STEPS;
break;
case UI_EDIT_ROOT:
currentRoot += delta;
if (currentRoot < 0) currentRoot = 11;
if (currentRoot > 11) currentRoot = 0;
updateScale();
if (isPlaying) {
sequenceChangeScheduled = true;
generateSequenceData((queuedTheme != -1) ? queuedTheme : currentThemeIndex, nextSequence);
}
break;
case UI_EDIT_SCALE_TYPE:
scaleTypeEditIndex += delta;
if (scaleTypeEditIndex < 0) scaleTypeEditIndex = 10;
if (scaleTypeEditIndex > 10) scaleTypeEditIndex = 0;
break;
case UI_EDIT_FLAVOUR:
{
currentStrategyIndices[randomizeTrack] += (delta > 0 ? 1 : -1);
@@ -408,6 +500,11 @@ static void handleInput() {
scaleEditSelection = 0;
break;
case MENU_ID_ROOT: currentState = UI_EDIT_ROOT; break;
case MENU_ID_SCALE_TYPE:
currentState = UI_EDIT_SCALE_TYPE;
scaleTypeEditIndex = 0;
break;
case MENU_ID_TEMPO: currentState = UI_EDIT_TEMPO; break;
case MENU_ID_STEPS: currentState = UI_EDIT_STEPS; break;
@@ -467,6 +564,19 @@ static void handleInput() {
currentState = UI_MENU_MAIN;
saveSequence(true);
break;
case UI_EDIT_ROOT:
currentState = UI_MENU_MAIN;
saveSequence(true);
break;
case UI_EDIT_SCALE_TYPE:
if (scaleTypeEditIndex == 10) {
currentState = UI_MENU_MAIN;
saveSequence(true);
} else {
enabledScaleTypes ^= (1 << scaleTypeEditIndex);
if (enabledScaleTypes == 0) enabledScaleTypes = (1 << scaleTypeEditIndex); // Prevent disabling all
}
break;
case UI_EDIT_FLAVOUR:
currentState = UI_MENU_MAIN;
if (isPlaying) {
@@ -606,6 +716,8 @@ static void drawUI() {
local_currentState = currentState;
if (local_currentState == UI_SCALE_EDIT || local_currentState == UI_SCALE_NOTE_EDIT || local_currentState == UI_SCALE_TRANSPOSE) {
local_menuSelection = scaleEditSelection;
} else if (local_currentState == UI_EDIT_SCALE_TYPE) {
local_menuSelection = scaleTypeEditIndex;
} else {
local_menuSelection = menuSelection;
}