Refactor: UIThread trimming

This commit is contained in:
Dejvino 2026-03-06 21:47:33 +01:00
parent 71583bdb4e
commit f979c2c5d7
6 changed files with 342 additions and 293 deletions

195
Persistence.cpp Normal file
View 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
View 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
View 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
View 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

View File

@ -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;

View File

@ -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;