Refactor: UIThread trimming
This commit is contained in:
parent
71583bdb4e
commit
f979c2c5d7
195
Persistence.cpp
Normal file
195
Persistence.cpp
Normal file
@ -0,0 +1,195 @@
|
||||
#include "Persistence.h"
|
||||
#include "SharedState.h"
|
||||
#include "MidiDriver.h"
|
||||
#include "UIManager.h"
|
||||
#include "SequenceGenerator.h"
|
||||
#include <EEPROM.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
void Persistence::saveSequence(bool quiet) {
|
||||
midi.lock();
|
||||
int addr = 0;
|
||||
EEPROM.put(addr, EEPROM_MAGIC); addr += sizeof(EEPROM_MAGIC);
|
||||
int channels[NUM_TRACKS];
|
||||
for(int i=0; i<NUM_TRACKS; i++) channels[i] = midiChannels[i];
|
||||
EEPROM.put(addr, channels); addr += sizeof(channels);
|
||||
EEPROM.put(addr, melodySeeds); addr += sizeof(melodySeeds);
|
||||
EEPROM.put(addr, currentStrategyIndices); addr += sizeof(currentStrategyIndices);
|
||||
bool mutes[NUM_TRACKS];
|
||||
for(int i=0; i<NUM_TRACKS; i++) mutes[i] = trackMute[i];
|
||||
EEPROM.put(addr, mutes); addr += sizeof(mutes);
|
||||
EEPROM.put(addr, (int)tempo); addr += sizeof(int);
|
||||
int intensities[NUM_TRACKS];
|
||||
for(int i=0; i<NUM_TRACKS; i++) intensities[i] = (int)trackIntensity[i];
|
||||
EEPROM.put(addr, intensities); addr += sizeof(intensities);
|
||||
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, 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);
|
||||
}
|
||||
|
||||
EEPROM.put(addr, sequence); addr += sizeof(sequence);
|
||||
midi.unlock();
|
||||
EEPROM.commit();
|
||||
if (!quiet) ui.showMessage("SAVED!");
|
||||
}
|
||||
|
||||
bool Persistence::loadSequence() {
|
||||
midi.lock();
|
||||
int addr = 0;
|
||||
uint32_t magic;
|
||||
EEPROM.get(addr, magic); addr += sizeof(magic);
|
||||
if (magic != EEPROM_MAGIC) {
|
||||
midi.unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
int channels[NUM_TRACKS];
|
||||
EEPROM.get(addr, channels); addr += sizeof(channels);
|
||||
for(int i=0; i<NUM_TRACKS; i++) {
|
||||
midiChannels[i] = channels[i];
|
||||
if (midiChannels[i] < 1) midiChannels[i] = 1;
|
||||
if (midiChannels[i] > 16) midiChannels[i] = 16;
|
||||
}
|
||||
EEPROM.get(addr, melodySeeds); addr += sizeof(melodySeeds);
|
||||
EEPROM.get(addr, currentStrategyIndices); addr += sizeof(currentStrategyIndices);
|
||||
for(int i=0; i<NUM_TRACKS; i++) {
|
||||
if (currentStrategyIndices[i] < 0 || currentStrategyIndices[i] >= numStrategies) currentStrategyIndices[i] = 0;
|
||||
}
|
||||
bool mutes[NUM_TRACKS];
|
||||
EEPROM.get(addr, mutes); addr += sizeof(mutes);
|
||||
for(int i=0; i<NUM_TRACKS; i++) trackMute[i] = mutes[i];
|
||||
int t;
|
||||
EEPROM.get(addr, t); addr += sizeof(int);
|
||||
tempo = t;
|
||||
if (tempo < 40) tempo = 40;
|
||||
if (tempo > 240) tempo = 240;
|
||||
int intensities[NUM_TRACKS];
|
||||
EEPROM.get(addr, intensities); addr += sizeof(intensities);
|
||||
for(int i=0; i<NUM_TRACKS; i++) {
|
||||
trackIntensity[i] = intensities[i];
|
||||
if (trackIntensity[i] < 1) trackIntensity[i] = 1;
|
||||
if (trackIntensity[i] > 10) trackIntensity[i] = 10;
|
||||
}
|
||||
int steps[NUM_TRACKS];
|
||||
EEPROM.get(addr, steps); addr += sizeof(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, 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++) {
|
||||
EEPROM.get(addr, scaleNotes[i]); addr += sizeof(int);
|
||||
if (scaleNotes[i] < 0) scaleNotes[i] = 0;
|
||||
if (scaleNotes[i] > 11) scaleNotes[i] = 11;
|
||||
}
|
||||
|
||||
EEPROM.get(addr, sequence); addr += sizeof(sequence);
|
||||
midi.unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Persistence::savePatch(int bank, int slot) {
|
||||
int patchIndex = bank * 4 + 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);
|
||||
}
|
||||
EEPROM.put(addr, currentStrategyIndices); addr += sizeof(currentStrategyIndices);
|
||||
EEPROM.put(addr, melodySeeds); addr += sizeof(melodySeeds);
|
||||
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];
|
||||
for(int i=0; i<NUM_TRACKS; i++) mutes[i] = trackMute[i];
|
||||
EEPROM.put(addr, mutes); addr += sizeof(mutes);
|
||||
int intensities[NUM_TRACKS];
|
||||
for(int i=0; i<NUM_TRACKS; i++) intensities[i] = trackIntensity[i];
|
||||
EEPROM.put(addr, intensities); addr += sizeof(intensities);
|
||||
midi.unlock();
|
||||
EEPROM.commit();
|
||||
ui.showMessage("SAVED!");
|
||||
}
|
||||
|
||||
void Persistence::loadPatch(int bank, int slot, Step (*scratchBuffer)[NUM_STEPS]) {
|
||||
int patchIndex = bank * 4 + 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++) {
|
||||
EEPROM.get(addr, scaleNotes[i]); addr += sizeof(int);
|
||||
if (scaleNotes[i] < 0) scaleNotes[i] = 0;
|
||||
if (scaleNotes[i] > 11) scaleNotes[i] = 11;
|
||||
}
|
||||
EEPROM.get(addr, currentStrategyIndices); addr += sizeof(currentStrategyIndices);
|
||||
for(int i=0; i<NUM_TRACKS; i++) {
|
||||
if (currentStrategyIndices[i] < 0 || currentStrategyIndices[i] >= numStrategies) currentStrategyIndices[i] = 0;
|
||||
}
|
||||
EEPROM.get(addr, melodySeeds); addr += sizeof(melodySeeds);
|
||||
int steps[NUM_TRACKS];
|
||||
EEPROM.get(addr, steps); addr += sizeof(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;
|
||||
}
|
||||
}
|
||||
|
||||
bool mutes[NUM_TRACKS];
|
||||
EEPROM.get(addr, mutes); addr += sizeof(mutes);
|
||||
for(int i=0; i<NUM_TRACKS; i++) trackMute[i] = mutes[i];
|
||||
|
||||
int intensities[NUM_TRACKS];
|
||||
EEPROM.get(addr, intensities); addr += sizeof(intensities);
|
||||
for(int i=0; i<NUM_TRACKS; i++) {
|
||||
trackIntensity[i] = intensities[i];
|
||||
if (trackIntensity[i] < 1) trackIntensity[i] = 1;
|
||||
if (trackIntensity[i] > 10) trackIntensity[i] = 10;
|
||||
}
|
||||
|
||||
if (isPlaying) {
|
||||
SequenceGenerator::generateSequenceData(currentThemeIndex, nextSequence);
|
||||
sequenceChangeScheduled = true;
|
||||
} else {
|
||||
SequenceGenerator::generateSequenceData(currentThemeIndex, scratchBuffer);
|
||||
memcpy(sequence, scratchBuffer, sizeof(sequence));
|
||||
}
|
||||
midi.unlock();
|
||||
ui.showMessage("LOADED!");
|
||||
}
|
||||
|
||||
void Persistence::factoryReset() {
|
||||
ui.showMessage("RESETTING...");
|
||||
for(int i=0; i<NUM_TRACKS; i++) {
|
||||
trackIntensity[i] = 10;
|
||||
}
|
||||
uint32_t magic = 0;
|
||||
EEPROM.put(0, magic);
|
||||
EEPROM.commit();
|
||||
delay(500);
|
||||
rp2040.reboot();
|
||||
}
|
||||
16
Persistence.h
Normal file
16
Persistence.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef PERSISTENCE_H
|
||||
#define PERSISTENCE_H
|
||||
|
||||
#include "TrackerTypes.h"
|
||||
#include "config.h"
|
||||
|
||||
class Persistence {
|
||||
public:
|
||||
static void saveSequence(bool quiet);
|
||||
static bool loadSequence();
|
||||
static void savePatch(int bank, int slot);
|
||||
static void loadPatch(int bank, int slot, Step (*scratchBuffer)[NUM_STEPS]);
|
||||
static void factoryReset();
|
||||
};
|
||||
|
||||
#endif
|
||||
90
SequenceGenerator.cpp
Normal file
90
SequenceGenerator.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
#include "SequenceGenerator.h"
|
||||
#include "SharedState.h"
|
||||
#include "MidiDriver.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
void SequenceGenerator::generateTrackData(int track, int themeType, Step (*target)[NUM_STEPS]) {
|
||||
randomSeed(melodySeeds[track] + themeType * 12345);
|
||||
strategies[currentStrategyIndices[track]]->generate(target, track, numSteps[track], scaleNotes, numScaleNotes, melodySeeds[track] + themeType * 12345, trackIntensity[track]);
|
||||
}
|
||||
|
||||
void SequenceGenerator::generateSequenceData(int themeType, Step (*target)[NUM_STEPS]) {
|
||||
Serial.println(F("Generating sequence."));
|
||||
for(int i=0; i<NUM_TRACKS; i++) {
|
||||
SequenceGenerator::generateTrackData(i, themeType, target);
|
||||
}
|
||||
}
|
||||
|
||||
void SequenceGenerator::mutateSequence(Step (*target)[NUM_STEPS]) {
|
||||
for(int i=0; i<NUM_TRACKS; i++) {
|
||||
if (random(100) < (trackIntensity[i] * 10)) {
|
||||
strategies[currentStrategyIndices[i]]->mutate(target, i, numSteps[i], scaleNotes, numScaleNotes, trackIntensity[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SequenceGenerator::generateRandomScale() {
|
||||
Serial.println(F("Generating new scale."));
|
||||
SequenceGenerator::updateScale();
|
||||
}
|
||||
|
||||
void SequenceGenerator::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();
|
||||
}
|
||||
|
||||
void SequenceGenerator::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)];
|
||||
SequenceGenerator::updateScale();
|
||||
}
|
||||
}
|
||||
17
SequenceGenerator.h
Normal file
17
SequenceGenerator.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef SEQUENCE_GENERATOR_H
|
||||
#define SEQUENCE_GENERATOR_H
|
||||
|
||||
#include "TrackerTypes.h"
|
||||
#include "config.h"
|
||||
|
||||
class SequenceGenerator {
|
||||
public:
|
||||
static void generateTrackData(int track, int themeType, Step (*target)[NUM_STEPS]);
|
||||
static void generateSequenceData(int themeType, Step (*target)[NUM_STEPS]);
|
||||
static void mutateSequence(Step (*target)[NUM_STEPS]);
|
||||
static void generateRandomScale();
|
||||
static void updateScale();
|
||||
static void pickRandomScaleType();
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -76,6 +76,7 @@ extern int melodySeeds[NUM_TRACKS];
|
||||
extern volatile int queuedTheme;
|
||||
extern volatile int currentThemeIndex;
|
||||
extern int currentRoot;
|
||||
extern volatile int trackIntensity[NUM_TRACKS];
|
||||
extern int currentScaleType;
|
||||
extern int enabledScaleTypes;
|
||||
extern const uint32_t EEPROM_MAGIC;
|
||||
|
||||
316
UIThread.cpp
316
UIThread.cpp
@ -1,22 +1,13 @@
|
||||
#include <SPI.h>
|
||||
#include <Wire.h>
|
||||
#include <EEPROM.h>
|
||||
#include "TrackerTypes.h"
|
||||
#include "MelodyStrategy.h"
|
||||
#include "LuckyStrategy.h"
|
||||
#include "ArpStrategy.h"
|
||||
#include "EuclideanStrategy.h"
|
||||
#include "MarkovStrategy.h"
|
||||
#include "CellularAutomataStrategy.h"
|
||||
#include "LSystemStrategy.h"
|
||||
#include "DroneStrategy.h"
|
||||
#include "MidiDriver.h"
|
||||
#include "UIManager.h"
|
||||
#include "config.h"
|
||||
#include "UIThread.h"
|
||||
#include "SharedState.h"
|
||||
|
||||
extern volatile int trackIntensity[NUM_TRACKS];
|
||||
#include "SequenceGenerator.h"
|
||||
#include "Persistence.h"
|
||||
|
||||
static Step local_sequence[NUM_TRACKS][NUM_STEPS];
|
||||
|
||||
@ -26,222 +17,26 @@ static int scaleTypeEditIndex = 0;
|
||||
static int scaleEditNoteIndex = 0;
|
||||
static void drawUI();
|
||||
static void updateLeds();
|
||||
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();
|
||||
int addr = 0;
|
||||
EEPROM.put(addr, EEPROM_MAGIC); addr += sizeof(EEPROM_MAGIC);
|
||||
int channels[NUM_TRACKS];
|
||||
for(int i=0; i<NUM_TRACKS; i++) channels[i] = midiChannels[i];
|
||||
EEPROM.put(addr, channels); addr += sizeof(channels);
|
||||
EEPROM.put(addr, melodySeeds); addr += sizeof(melodySeeds);
|
||||
EEPROM.put(addr, currentStrategyIndices); addr += sizeof(currentStrategyIndices);
|
||||
bool mutes[NUM_TRACKS];
|
||||
for(int i=0; i<NUM_TRACKS; i++) mutes[i] = trackMute[i];
|
||||
EEPROM.put(addr, mutes); addr += sizeof(mutes);
|
||||
EEPROM.put(addr, (int)tempo); addr += sizeof(int);
|
||||
int intensities[NUM_TRACKS];
|
||||
for(int i=0; i<NUM_TRACKS; i++) intensities[i] = (int)trackIntensity[i];
|
||||
EEPROM.put(addr, intensities); addr += sizeof(intensities);
|
||||
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, 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);
|
||||
}
|
||||
|
||||
EEPROM.put(addr, sequence); addr += sizeof(sequence);
|
||||
midi.unlock();
|
||||
EEPROM.commit();
|
||||
if (!quiet) ui.showMessage("SAVED!");
|
||||
Persistence::saveSequence(quiet);
|
||||
}
|
||||
|
||||
bool loadSequence() {
|
||||
midi.lock();
|
||||
int addr = 0;
|
||||
uint32_t magic;
|
||||
EEPROM.get(addr, magic); addr += sizeof(magic);
|
||||
if (magic != EEPROM_MAGIC) {
|
||||
midi.unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
int channels[NUM_TRACKS];
|
||||
EEPROM.get(addr, channels); addr += sizeof(channels);
|
||||
for(int i=0; i<NUM_TRACKS; i++) {
|
||||
midiChannels[i] = channels[i];
|
||||
if (midiChannels[i] < 1) midiChannels[i] = 1;
|
||||
if (midiChannels[i] > 16) midiChannels[i] = 16;
|
||||
}
|
||||
EEPROM.get(addr, melodySeeds); addr += sizeof(melodySeeds);
|
||||
EEPROM.get(addr, currentStrategyIndices); addr += sizeof(currentStrategyIndices);
|
||||
for(int i=0; i<NUM_TRACKS; i++) {
|
||||
if (currentStrategyIndices[i] < 0 || currentStrategyIndices[i] >= numStrategies) currentStrategyIndices[i] = 0;
|
||||
}
|
||||
bool mutes[NUM_TRACKS];
|
||||
EEPROM.get(addr, mutes); addr += sizeof(mutes);
|
||||
for(int i=0; i<NUM_TRACKS; i++) trackMute[i] = mutes[i];
|
||||
int t;
|
||||
EEPROM.get(addr, t); addr += sizeof(int);
|
||||
tempo = t;
|
||||
if (tempo < 40) tempo = 40;
|
||||
if (tempo > 240) tempo = 240;
|
||||
int intensities[NUM_TRACKS];
|
||||
EEPROM.get(addr, intensities); addr += sizeof(intensities);
|
||||
for(int i=0; i<NUM_TRACKS; i++) {
|
||||
trackIntensity[i] = intensities[i];
|
||||
if (trackIntensity[i] < 1) trackIntensity[i] = 1;
|
||||
if (trackIntensity[i] > 10) trackIntensity[i] = 10;
|
||||
}
|
||||
int steps[NUM_TRACKS];
|
||||
EEPROM.get(addr, steps); addr += sizeof(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, 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++) {
|
||||
EEPROM.get(addr, scaleNotes[i]); addr += sizeof(int);
|
||||
if (scaleNotes[i] < 0) scaleNotes[i] = 0;
|
||||
if (scaleNotes[i] > 11) scaleNotes[i] = 11;
|
||||
}
|
||||
|
||||
EEPROM.get(addr, sequence); addr += sizeof(sequence);
|
||||
midi.unlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
static void savePatch(int bank, int slot) {
|
||||
int patchIndex = bank * 4 + 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);
|
||||
}
|
||||
EEPROM.put(addr, currentStrategyIndices); addr += sizeof(currentStrategyIndices);
|
||||
EEPROM.put(addr, melodySeeds); addr += sizeof(melodySeeds);
|
||||
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];
|
||||
for(int i=0; i<NUM_TRACKS; i++) mutes[i] = trackMute[i];
|
||||
EEPROM.put(addr, mutes); addr += sizeof(mutes);
|
||||
int intensities[NUM_TRACKS];
|
||||
for(int i=0; i<NUM_TRACKS; i++) intensities[i] = trackIntensity[i];
|
||||
EEPROM.put(addr, intensities); addr += sizeof(intensities);
|
||||
midi.unlock();
|
||||
EEPROM.commit();
|
||||
ui.showMessage("SAVED!");
|
||||
}
|
||||
|
||||
static void loadPatch(int bank, int slot) {
|
||||
int patchIndex = bank * 4 + 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++) {
|
||||
EEPROM.get(addr, scaleNotes[i]); addr += sizeof(int);
|
||||
if (scaleNotes[i] < 0) scaleNotes[i] = 0;
|
||||
if (scaleNotes[i] > 11) scaleNotes[i] = 11;
|
||||
}
|
||||
EEPROM.get(addr, currentStrategyIndices); addr += sizeof(currentStrategyIndices);
|
||||
for(int i=0; i<NUM_TRACKS; i++) {
|
||||
if (currentStrategyIndices[i] < 0 || currentStrategyIndices[i] >= numStrategies) currentStrategyIndices[i] = 0;
|
||||
}
|
||||
EEPROM.get(addr, melodySeeds); addr += sizeof(melodySeeds);
|
||||
int steps[NUM_TRACKS];
|
||||
EEPROM.get(addr, steps); addr += sizeof(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;
|
||||
}
|
||||
}
|
||||
|
||||
bool mutes[NUM_TRACKS];
|
||||
EEPROM.get(addr, mutes); addr += sizeof(mutes);
|
||||
for(int i=0; i<NUM_TRACKS; i++) trackMute[i] = mutes[i];
|
||||
|
||||
int intensities[NUM_TRACKS];
|
||||
EEPROM.get(addr, intensities); addr += sizeof(intensities);
|
||||
for(int i=0; i<NUM_TRACKS; i++) {
|
||||
trackIntensity[i] = intensities[i];
|
||||
if (trackIntensity[i] < 1) trackIntensity[i] = 1;
|
||||
if (trackIntensity[i] > 10) trackIntensity[i] = 10;
|
||||
}
|
||||
|
||||
if (isPlaying) {
|
||||
generateSequenceData(currentThemeIndex, nextSequence);
|
||||
sequenceChangeScheduled = true;
|
||||
} else {
|
||||
generateSequenceData(currentThemeIndex, local_sequence);
|
||||
memcpy(sequence, local_sequence, sizeof(local_sequence));
|
||||
}
|
||||
midi.unlock();
|
||||
ui.showMessage("LOADED!");
|
||||
return Persistence::loadSequence();
|
||||
}
|
||||
|
||||
void factoryReset() {
|
||||
ui.showMessage("RESETTING...");
|
||||
for(int i=0; i<NUM_TRACKS; i++) {
|
||||
trackIntensity[i] = 10;
|
||||
}
|
||||
uint32_t magic = 0;
|
||||
EEPROM.put(0, magic);
|
||||
EEPROM.commit();
|
||||
delay(500);
|
||||
rp2040.reboot();
|
||||
}
|
||||
|
||||
static void generateTrackData(int track, int themeType, Step (*target)[NUM_STEPS]) {
|
||||
randomSeed(melodySeeds[track] + themeType * 12345);
|
||||
strategies[currentStrategyIndices[track]]->generate(target, track, numSteps[track], scaleNotes, numScaleNotes, melodySeeds[track] + themeType * 12345, trackIntensity[track]);
|
||||
Persistence::factoryReset();
|
||||
}
|
||||
|
||||
void generateRandomScale() {
|
||||
Serial.println(F("Generating new scale."));
|
||||
// All tracks share the same scale for now
|
||||
strategies[currentStrategyIndices[0]]->generateScale(scaleNotes, numScaleNotes);
|
||||
}
|
||||
|
||||
static void generateSequenceData(int themeType, Step (*target)[NUM_STEPS]) {
|
||||
Serial.println(F("Generating sequence."));
|
||||
for(int i=0; i<NUM_TRACKS; i++) {
|
||||
generateTrackData(i, themeType, target);
|
||||
}
|
||||
SequenceGenerator::generateRandomScale();
|
||||
}
|
||||
|
||||
void generateTheme(int themeType) {
|
||||
pickRandomScaleType();
|
||||
generateSequenceData(themeType, local_sequence);
|
||||
SequenceGenerator::pickRandomScaleType();
|
||||
SequenceGenerator::generateSequenceData(themeType, local_sequence);
|
||||
|
||||
Serial.println(F("Generating theme."));
|
||||
midi.lock();
|
||||
@ -258,72 +53,7 @@ void generateTheme(int themeType) {
|
||||
}
|
||||
|
||||
void mutateSequence(Step (*target)[NUM_STEPS]) {
|
||||
for(int i=0; i<NUM_TRACKS; i++) {
|
||||
if (random(100) < (trackIntensity[i] * 10)) {
|
||||
strategies[currentStrategyIndices[i]]->mutate(target, i, numSteps[i], scaleNotes, numScaleNotes, trackIntensity[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
SequenceGenerator::mutateSequence(target);
|
||||
}
|
||||
|
||||
static void handleInput() {
|
||||
@ -370,10 +100,10 @@ static void handleInput() {
|
||||
currentRoot += delta;
|
||||
if (currentRoot < 0) currentRoot = 11;
|
||||
if (currentRoot > 11) currentRoot = 0;
|
||||
updateScale();
|
||||
SequenceGenerator::updateScale();
|
||||
if (isPlaying) {
|
||||
sequenceChangeScheduled = true;
|
||||
generateSequenceData((queuedTheme != -1) ? queuedTheme : currentThemeIndex, nextSequence);
|
||||
SequenceGenerator::generateSequenceData((queuedTheme != -1) ? queuedTheme : currentThemeIndex, nextSequence);
|
||||
}
|
||||
break;
|
||||
case UI_EDIT_SCALE_TYPE:
|
||||
@ -423,7 +153,7 @@ static void handleInput() {
|
||||
if (isPlaying) {
|
||||
int theme = (queuedTheme != -1) ? queuedTheme : currentThemeIndex;
|
||||
midi.lock();
|
||||
generateSequenceData(theme, nextSequence);
|
||||
SequenceGenerator::generateSequenceData(theme, nextSequence);
|
||||
sequenceChangeScheduled = true;
|
||||
midi.unlock();
|
||||
}
|
||||
@ -488,7 +218,7 @@ static void handleInput() {
|
||||
if (!sequenceChangeScheduled) {
|
||||
memcpy(nextSequence, sequence, sizeof(sequence));
|
||||
}
|
||||
generateTrackData(randomizeTrack, theme, nextSequence);
|
||||
SequenceGenerator::generateTrackData(randomizeTrack, theme, nextSequence);
|
||||
sequenceChangeScheduled = true;
|
||||
}
|
||||
midi.unlock();
|
||||
@ -531,7 +261,7 @@ static void handleInput() {
|
||||
if (isPlaying) {
|
||||
queuedTheme = selectedTheme;
|
||||
midi.lock();
|
||||
generateSequenceData(queuedTheme, nextSequence);
|
||||
SequenceGenerator::generateSequenceData(queuedTheme, nextSequence);
|
||||
sequenceChangeScheduled = true;
|
||||
midi.unlock();
|
||||
} else {
|
||||
@ -545,8 +275,8 @@ static void handleInput() {
|
||||
int sub = offset % 8;
|
||||
bool isSave = sub >= 4;
|
||||
int slot = sub % 4;
|
||||
if (isSave) savePatch(bank, slot);
|
||||
else loadPatch(bank, slot);
|
||||
if (isSave) Persistence::savePatch(bank, slot);
|
||||
else Persistence::loadPatch(bank, slot, local_sequence);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -585,7 +315,7 @@ static void handleInput() {
|
||||
if (!sequenceChangeScheduled) {
|
||||
memcpy(nextSequence, sequence, sizeof(sequence));
|
||||
}
|
||||
generateTrackData(randomizeTrack, theme, nextSequence);
|
||||
SequenceGenerator::generateTrackData(randomizeTrack, theme, nextSequence);
|
||||
sequenceChangeScheduled = true;
|
||||
midi.unlock();
|
||||
}
|
||||
@ -599,7 +329,7 @@ static void handleInput() {
|
||||
if (!sequenceChangeScheduled) {
|
||||
memcpy(nextSequence, sequence, sizeof(sequence));
|
||||
}
|
||||
generateTrackData(randomizeTrack, theme, nextSequence);
|
||||
SequenceGenerator::generateTrackData(randomizeTrack, theme, nextSequence);
|
||||
sequenceChangeScheduled = true;
|
||||
midi.unlock();
|
||||
}
|
||||
@ -618,7 +348,7 @@ static void handleInput() {
|
||||
if (isPlaying) {
|
||||
int theme = (queuedTheme != -1) ? queuedTheme : currentThemeIndex;
|
||||
midi.lock();
|
||||
generateSequenceData(theme, nextSequence);
|
||||
SequenceGenerator::generateSequenceData(theme, nextSequence);
|
||||
sequenceChangeScheduled = true;
|
||||
midi.unlock();
|
||||
}
|
||||
@ -637,7 +367,7 @@ static void handleInput() {
|
||||
if (isPlaying) {
|
||||
int theme = (queuedTheme != -1) ? queuedTheme : currentThemeIndex;
|
||||
midi.lock();
|
||||
generateSequenceData(theme, nextSequence);
|
||||
SequenceGenerator::generateSequenceData(theme, nextSequence);
|
||||
sequenceChangeScheduled = true;
|
||||
midi.unlock();
|
||||
}
|
||||
@ -650,7 +380,7 @@ static void handleInput() {
|
||||
if (isPlaying) {
|
||||
int theme = (queuedTheme != -1) ? queuedTheme : currentThemeIndex;
|
||||
midi.lock();
|
||||
generateSequenceData(theme, nextSequence);
|
||||
SequenceGenerator::generateSequenceData(theme, nextSequence);
|
||||
sequenceChangeScheduled = true;
|
||||
midi.unlock();
|
||||
}
|
||||
@ -663,7 +393,7 @@ static void handleInput() {
|
||||
if (isPlaying) {
|
||||
int theme = (queuedTheme != -1) ? queuedTheme : currentThemeIndex;
|
||||
midi.lock();
|
||||
generateSequenceData(theme, nextSequence);
|
||||
SequenceGenerator::generateSequenceData(theme, nextSequence);
|
||||
sequenceChangeScheduled = true;
|
||||
midi.unlock();
|
||||
}
|
||||
@ -804,7 +534,7 @@ void loopUI() {
|
||||
int nextTheme = random(1, 8); // Themes 1-7
|
||||
int repeats = random(1, 9); // 1-8 repeats
|
||||
|
||||
generateSequenceData(nextTheme, nextSequence);
|
||||
SequenceGenerator::generateSequenceData(nextTheme, nextSequence);
|
||||
queuedTheme = nextTheme;
|
||||
nextSongRepeats = repeats;
|
||||
sequenceChangeScheduled = true;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user