Root note and bitmap of scale types
This commit is contained in:
+112
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user