diff --git a/EuclideanStrategy.h b/EuclideanStrategy.h new file mode 100644 index 0000000..844d8c8 --- /dev/null +++ b/EuclideanStrategy.h @@ -0,0 +1,87 @@ +#ifndef EUCLIDEAN_STRATEGY_H +#define EUCLIDEAN_STRATEGY_H + +#include "MelodyStrategy.h" +#include + +class EuclideanStrategy : public MelodyStrategy { +public: + void generate(Step* sequence, int numSteps, int* scaleNotes, int numScaleNotes, int seed) override { + randomSeed(seed); + if (numScaleNotes == 0) return; + + int pulses = random(1, numSteps + 1); + int offset = random(numSteps); + + // Euclidean distribution (Bresenham) + int bucket = 0; + + // Generate pattern + bool pattern[numSteps]; + for(int i=0; i= numSteps) { + bucket -= numSteps; + pattern[i] = true; + } else { + pattern[i] = false; + } + } + + for (int i = 0; i < numSteps; i++) { + // Apply offset + int stepIndex = (i + offset) % numSteps; + + if (pattern[i]) { + int octave = random(3) + 3; // 3, 4, 5 + sequence[stepIndex].note = 12 * octave + scaleNotes[random(numScaleNotes)]; + sequence[stepIndex].accent = (random(100) < 30); + sequence[stepIndex].tie = (random(100) < 10); + } else { + sequence[stepIndex].note = -1; + sequence[stepIndex].accent = false; + sequence[stepIndex].tie = false; + } + } + randomSeed(micros()); + } + + void generateScale(int* scaleNotes, int& numScaleNotes) override { + numScaleNotes = random(3, 13); // 3 to 12 notes + for (int i = 0; i < 12; i++) { + scaleNotes[i] = i; // Fill with all notes + } + // Shuffle + for (int i = 0; i < 12; i++) { + int j = random(12); + int temp = scaleNotes[i]; + scaleNotes[i] = scaleNotes[j]; + scaleNotes[j] = temp; + } + sortArray(scaleNotes, numScaleNotes); + } + + void mutate(Step* sequence, int numSteps, int* scaleNotes, int numScaleNotes) override { + // Rotate sequence + if (random(2) == 0) { + Step last = sequence[numSteps - 1]; + for (int i = numSteps - 1; i > 0; i--) { + sequence[i] = sequence[i - 1]; + } + sequence[0] = last; + } else { + // Randomize a note + int s = random(numSteps); + if (sequence[s].note != -1) { + int octave = random(3) + 3; + sequence[s].note = 12 * octave + scaleNotes[random(numScaleNotes)]; + } + } + } + + const char* getName() override { + return "Euclid"; + } +}; + +#endif \ No newline at end of file diff --git a/RP2040_Tracker.ino b/RP2040_Tracker.ino index 9d5d022..4747914 100644 --- a/RP2040_Tracker.ino +++ b/RP2040_Tracker.ino @@ -5,6 +5,7 @@ #include "MelodyStrategy.h" #include "LuckyStrategy.h" #include "ArpStrategy.h" +#include "EuclideanStrategy.h" #include "MidiDriver.h" #include "UIManager.h" @@ -50,10 +51,10 @@ int numScaleNotes = 0; int melodySeed = 0; volatile int queuedTheme = -1; volatile int currentThemeIndex = 1; -const uint32_t EEPROM_MAGIC = 0x42424246; +const uint32_t EEPROM_MAGIC = 0x42424247; -MelodyStrategy* strategies[] = { new LuckyStrategy(), new ArpStrategy() }; -const int numStrategies = 2; +MelodyStrategy* strategies[] = { new LuckyStrategy(), new ArpStrategy(), new EuclideanStrategy() }; +const int numStrategies = 3; int currentStrategyIndex = 0; volatile bool mutationEnabled = false;