PicoWaveTracker/EuclideanStrategy.h
2026-02-22 22:25:17 +01:00

95 lines
3.2 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, int intensity) override {
randomSeed(seed);
if (numScaleNotes == 0) return;
// Intensity controls density.
// Intensity 1 = ~10% density, Intensity 10 = ~100% density
int targetPulses = (numSteps * intensity) / 10;
if (targetPulses < 1) targetPulses = 1;
// Add some variation (+/- 1 pulse)
int pulses = targetPulses + random(-1, 2);
if (pulses < 1) pulses = 1;
if (pulses > numSteps) pulses = numSteps;
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, int intensity) 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