xaveruth
Joined: Jan 04, 2019 Posts: 3 Location: Toronto
|
Posted: Fri Jan 04, 2019 11:43 pm Post subject:
Cellular Automaton Song ("Cellular Automatune") |
 |
|
Hi all, I was trying to come up with a tune inspired by fractals, and came up with this.
I think it does actually qualify as a fractal, and is also inspired by cellular automata, which I read about in Stephen Wolfram's book, A New Kind of Science. Enjoy!
------------
0 => int startAheadBy; //in bars
//specify which loops to play
//row0: index: 0 = 64 bar pattern, 1 = 32 bar pattern, etc.
//row1: on/off
//row2: octaves up/down
[[0, 1, 2, 3, 4, 5, 6],
[1, 1, 1, 1, 1, 1, 1],
[-2, -1, 0, 0, 1, 1, 2]] @=> int currLoops[][];
//param0: pan
//param1: gain
//param2: semitones up/down
//param3: vibratoGain
//param4: vibratoFreq
//param5: bowPressure
[[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
[-24.0, -12.0, 0.0, -12.0, 0.0, 12.0, 24.0],
[0.05, 0.05, 0.02, 0.05, 0.1, 0.05, 0.05],
[2.0, 2.0, 4.0, 4.0, 6.0, 8.0, 8.0], //maybe make them all powers of 2?
[0.5, 0.2, 0.8, 0.5, 0.5, 0.5, 0.5]] @=> float params[][];
int numBaseDurs[currLoops[0].cap()];
int freqHolderArray[currLoops[0].cap()];
for (0 => int i; i < currLoops[0].cap(); i++) { 50 => freqHolderArray[i];} //set initial tones to 50
//array of Bowed instruments
Pan2 p[currLoops[0].cap()];
Bowed xave[currLoops[0].cap()];
//set up parameters for Bowed instruments
for (0 => int i; i < xave.cap(); i++) {
xave[i] => p[i] => dac;
1 => xave[i].bowPosition;
params[0][i] => p[i].pan;
params[3][i] => xave[i].vibratoGain;
params[4][i] => xave[i].vibratoFreq;
params[5][i] => xave[i].bowPressure;
}
//setting up the melody
50 => int basetone; //what note is this? -- it's D
[1, 2, 3, 2, 3, 4, 5, 6, 7, 8, 7,
6, 5, 6, 7, 8, 7, 6, 3, 5, 6, 5, 4, 3, 4, 3, 2, 1, 5,
8, 7, 6, 5, 4, 3, 2, 3, 2, 1, 5,
1, 2, 3, 2, 3, 4, 5, 6, 7, 8, 7] @=> int melodyUnconverted[];
int melody[melodyUnconverted.cap()];
[14, 1, 1, 12, 4, 10, 2, 2, 2, 8, 8,
12, 2, 2, 8, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2,2,2,2,16,
10, 2, 2, 2, 12, 4, 14, 1, 1, 8, 8,
14, 1, 1, 12, 4, 10, 2, 2, 2, 16] @=> int durs[];
int cumDurs[durs.cap()+1];
//convert melody to semitones (i.e. do = 1, re = 3, mi = 5, etc.)
[[1, 2, 3, 4, 5, 6, 7, 8],
[1, 3, 5, 6, 8, 10, 12, 13]] @=> int conversionTable[][];
for (0 => int i; i < melodyUnconverted.cap(); i++) {
for (0 => int j; j < conversionTable[0].cap(); j++) {
if (melodyUnconverted[i] == conversionTable[0][j]) {
conversionTable[1][j] => melody[i];
}
}
}
//initialize cumulative durs array
0 => int count;
for (0 => int i; i < cumDurs.cap(); i++) {
if (i == 0) { 0 => cumDurs[i]; }
else { cumDurs[i-1] + durs[i-1] => cumDurs[i]; }
}
//timing stuff
500::ms => dur quarter;
quarter / 64 => dur twofiftysixth;
startAheadBy * 256 => int TwoFiftySixths;
//APPLY CELLULAR AUTOMATON PATTERN
int patternOnOff[currLoops[0].cap()][(Math.pow(2, currLoops[0].cap() - 1)) $ int];
//initialize top layer to all 1s
for (0 => int i; i < Math.pow(2, currLoops[0].cap() - 1); i++) { 1 => patternOnOff[0][i]; }
//initialize other layers
for (1 => int i; i < currLoops[0].cap(); i++) {
for (0 => int j; j < Math.pow(2, currLoops[0].cap() - 1); j++) {
if (patternOnOff[i - 1][j] == 1) {
if (j % Math.pow(2, currLoops[0].cap() - i) >= Math.pow(2, currLoops[0].cap() - i)/2) { 1 => patternOnOff[i][j]; }
else { (0 => patternOnOff[i][j]); }
}
else if (patternOnOff[i - 1][j] == 0) {
if (j % Math.pow(2, currLoops[0].cap() - i) >= Math.pow(2, currLoops[0].cap() - i)/2) { 0 => patternOnOff[i][j]; }
else { (1 => patternOnOff[i][j]); }
}
<<< i, j, patternOnOff[i][j] >>>;
}
}
//1 => w.record;
//PLAY THE DAMN THING
while (TwoFiftySixths < Math.pow(2, currLoops[0].cap() - 1) * 256) {
//calculate number of "base durations" for each pattern
//i.e. for the 64-bar pattern the "base duration" is a quarter note,
//so calculate how many quarter notes have elapsed so far
for (0 => int i; i < currLoops[0].cap(); i++) {
TwoFiftySixths / Math.pow(2, currLoops[0].cap() - 1 - currLoops[0][i]) $ int => numBaseDurs[i];
}
Math.floor(TwoFiftySixths / 256) $ int => int currBar;
for (0 => int j; j < currLoops[0].cap(); j++) { //for loop runs through all "current loops"
if (patternOnOff[currLoops[0][j]][currBar] == 1 && currLoops[1][j] == 1) {
0 => int check; 0 => int i;
do {
i++;
//ensure it stops after loop
if ((numBaseDurs[j] % cumDurs[cumDurs.cap()-1]) >= cumDurs[cumDurs.cap()-1]) {
1 => check;
0 => freqHolderArray[j];
}
else if ((numBaseDurs[j] % cumDurs[cumDurs.cap()-1]) >= cumDurs[i-1] && (numBaseDurs[j] % cumDurs[cumDurs.cap()-1]) < cumDurs[i]) {
//if (TwoFiftySixths % 256 == 0) { <<< currBar, currLoops[0][j] >>>; }
1 => check;
//version with int octave jumps
basetone + melody[i-1] - 1 + currLoops[2][j] * 12 => freqHolderArray[j];
//version with float semitone jumps
//(basetone + melody[i-1] - 1 + params[2][j]) $ int => freqHolderArray[j];
}
} until (check == 1);
}
else {
0 => freqHolderArray[j];
}
}
//set notes "on" (requirement of "Bowed" instruments)
for (0 => int i; i < currLoops[0].cap(); i++) {
if (freqHolderArray[i] > 0) {
freqHolderArray[i] => Std.mtof => xave[i].freq;
params[1][i] => xave[i].noteOn;
}
else { 0 => xave[i].noteOff; }
}
//advance time
twofiftysixth => now;
TwoFiftySixths++; //basic counter -- how many 256th notes have passed
}
//0 => w.record;
[url][/url] |
|