87 lines
2.8 KiB
C++
87 lines
2.8 KiB
C++
#ifndef EUCLIDEAN_STRATEGY_H
|
|
#define EUCLIDEAN_STRATEGY_H
|
|
|
|
#include "MelodyStrategy.h"
|
|
#include <Arduino.h>
|
|
|
|
class EuclideanStrategy : public MelodyStrategy {
|
|
public:
|
|
void generate(Step (*sequence)[NUM_STEPS], int track, 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; i++) {
|
|
bucket += pulses;
|
|
if (bucket >= 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[track][stepIndex].note = 12 * octave + scaleNotes[random(numScaleNotes)];
|
|
sequence[track][stepIndex].accent = (random(100) < 30);
|
|
sequence[track][stepIndex].tie = (random(100) < 10);
|
|
} else {
|
|
sequence[track][stepIndex].note = -1;
|
|
sequence[track][stepIndex].accent = false;
|
|
sequence[track][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)[NUM_STEPS], int track, int numSteps, int* scaleNotes, int numScaleNotes) override {
|
|
// Rotate sequence
|
|
if (random(2) == 0) {
|
|
Step last = sequence[track][numSteps - 1];
|
|
for (int i = numSteps - 1; i > 0; i--) {
|
|
sequence[track][i] = sequence[track][i - 1];
|
|
}
|
|
sequence[track][0] = last;
|
|
} else {
|
|
// Randomize a note
|
|
int s = random(numSteps);
|
|
if (sequence[track][s].note != -1) {
|
|
int octave = random(3) + 3;
|
|
sequence[track][s].note = 12 * octave + scaleNotes[random(numScaleNotes)];
|
|
}
|
|
}
|
|
}
|
|
|
|
const char* getName() override {
|
|
return "Euclid";
|
|
}
|
|
};
|
|
|
|
#endif |