#ifndef CELLULAR_AUTOMATA_STRATEGY_H #define CELLULAR_AUTOMATA_STRATEGY_H #include "MelodyStrategy.h" #include class CellularAutomataStrategy : public MelodyStrategy { public: void generate(Step (*sequence)[NUM_STEPS], int track, int numSteps, int* scaleNotes, int numScaleNotes, int* chordNotes, int numChordNotes, int seed, int intensity) override { randomSeed(seed); int* sourceNotes = (numChordNotes > 0) ? chordNotes : scaleNotes; int sourceNoteCount = (numChordNotes > 0) ? numChordNotes : numScaleNotes; if (sourceNoteCount == 0) return; bool cells[NUM_STEPS]; for (int i = 0; i < numSteps; i++) { cells[i] = (random(100) < (intensity * 8)); // Initial density } int rule = random(256); // Wolfram rule for (int gen = 0; gen < 4; gen++) { // A few generations bool next_cells[NUM_STEPS]; for (int i = 0; i < numSteps; i++) { bool left = cells[(i - 1 + numSteps) % numSteps]; bool middle = cells[i]; bool right = cells[(i + 1) % numSteps]; int index = (left << 2) | (middle << 1) | right; next_cells[i] = (rule >> index) & 1; } memcpy(cells, next_cells, sizeof(cells)); } for (int i = 0; i < numSteps; i++) { if (cells[i]) { int octave = 3 + random(3); sequence[track][i].note = 12 * octave + sourceNotes[random(sourceNoteCount)]; sequence[track][i].accent = (random(100) < 20); sequence[track][i].tie = false; } else { sequence[track][i].note = -1; sequence[track][i].accent = false; sequence[track][i].tie = false; } } randomSeed(micros()); } void generateScale(int* scaleNotes, int& numScaleNotes) override { // This strategy doesn't generate its own scales, but the method must be implemented. } void mutate(Step (*sequence)[NUM_STEPS], int track, int numSteps, int* scaleNotes, int numScaleNotes, int* chordNotes, int numChordNotes, int intensity) override { // For simplicity, just regenerate with a new seed. generate(sequence, track, numSteps, scaleNotes, numScaleNotes, chordNotes, numChordNotes, random(65536), intensity); } const char* getName() override { return "Cellular"; } }; #endif