fraukefroehlich
Joined: May 11, 2007 Posts: 22 Location: home
Audio files: 1
|
Posted: Sat Jun 14, 2008 12:16 am Post subject:
algorithmic composition Subject description: wolfram cellular automata determining the notes to be played with length specified by a markov chain |
 |
|
hi there,
the deadline has passed now and i'm here to show you my code.
i hope it is understandable and you may give me some advice on how to improve my style with chuck.
maybe it could have been done with fewer lines of code or using less resources. but all in all i'm happy with the result.
so here comes:
| Code: | //-----------------------------------------------------------------------------------//
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
//-----------------------------------------------------------------------------------//
140 => float bpm;
1::minute / bpm => dur viertel; //fourth
1::minute / bpm / 2 => dur achtel; //eighth
"v" => string v; //fourth
"a" => string a; //eighth
"pa" => string pa; //eighth pause
"pv" => string pv; //fourth pause
//this is the array holding the not durations as base for the markov chain calculations
[
a,a,pa,a,pa,a,v,v,pv,v,
pv,v,a,pv,v,a,v,v,a,v,
v,v,v,v,a,a,pa,v,a,a,v,
v,a,pv,v,a,v,v,a,v,v,v,
v,a,a,pa,v,a,a,v,pv,a,
a,a,v,a,pa,a,a,a,pa,a,
a,a,pv,a,a,a,v,a,pa,v,a] @=> string durations[];
//the array holding the "pyramid" generetad by the cellular automata
int wolfram[150][9];
int band[150][7]; //to cut out just a 7 bit wide segment of the pyramid
int rule[2][2][2]; //array for the rule used in calculating the cellular automata
//current and next line of the pyramid
int line[9];
int newLine[9];
//instruments
Shakers m[7];
HevyMetl mandolin[7];
//mix
Gain mix => dac;
mix.gain(.17);
//tones
Std.mtof(30) => mandolin[0].freq;
Std.mtof(42) => mandolin[1].freq;
Std.mtof(54) => mandolin[2].freq;
Std.mtof(66) => mandolin[3].freq;
Std.mtof(78) => mandolin[4].freq;
Std.mtof(90) => mandolin[5].freq;
Std.mtof(102) => mandolin[6].freq;
Std.mtof(50) => m[0].freq;
Std.mtof(62) => m[1].freq;
Std.mtof(74) => m[2].freq;
Std.mtof(86) => m[3].freq;
Std.mtof(98) => m[4].freq;
Std.mtof(110) => m[5].freq;
Std.mtof(122) => m[6].freq;
//connect to dac
for(0 => int i; i < m.cap(); i++){
m[i] => mix;
mandolin[i] => mix;
}
//starting position - first line of the pyramid (the peek)
1 @=> line[4];
//rules for cellular automata. first is rule 30, following are
//other rules, slightly modified by me
[
[0,1,1,1,1,0,0,0],
[0,1,1,1,1,0,0,0],
[0,1,1,1,0,1,1,0],
[1,0,0,1,1,0,0,0],
[1,0,1,1,1,0,0,1]] @=> int ruleValues[][];
//ruleCounter to switch to a random rule when changing
-1 => int ruleCounter;
//after 12 iterations change rule to avoid repeating patterns
12 => int iterations;
//please stop this somewhen... ;)
1::minute + now => time later;
//set first rule
setRule(ruleValues);
//calculate the pyramid of the cellular automata
for(0 => int i; i < wolfram.cap(); i++){
for(0 => int j; j < line.cap(); j++){
line[j] => wolfram[i][j];
}
getNewLine(line, rule) @=> newLine;
newLine @=> line;
//change rule
if(iterations % 12 == 0){
setRule(ruleValues);
}
}
//cut the segment out of the pyramid to use it as "music sheet"
cutBand(wolfram);
//----------------------------------------------------------//
// MAIN LOOP
//----------------------------------------------------------//
while (now < later){
play(band);
1::samp => now;
}
//----------------------------------------------------------//
// SET RULE
//----------------------------------------------------------//
fun void setRule(int ruleValues[][]){
//get and set random rule
Std.rand() % 5 => ruleCounter;
ruleValues[ruleCounter][0] @=> rule[0][0][0];
ruleValues[ruleCounter][1] @=> rule[0][0][1];
ruleValues[ruleCounter][2] @=> rule[0][1][0];
ruleValues[ruleCounter][3] @=> rule[0][1][1];
ruleValues[ruleCounter][4] @=> rule[1][0][0];
ruleValues[ruleCounter][5] @=> rule[1][0][1];
ruleValues[ruleCounter][6] @=> rule[1][1][0];
ruleValues[ruleCounter][7] @=> rule[1][1][1];
}
//----------------------------------------------------------//
// GET NEW LINE
//----------------------------------------------------------//
fun int[] getNewLine(int oldLine[], int rule[][][]){
int temp[9];
//look at the values of i-1, i and i+1 of the previous line. use the
//code (i.e. 101) as index for the array holding the rule. then copy
//the value of the array at index 101 to the newLine[i]. after completion
//return the whole line.
for(1 => int i; i < (oldLine.cap()-1); i++){
if(rule[oldLine[i-1]][oldLine[i]][oldLine[i+1]] == 1){
1 => temp[i];
}else{
0 => temp[i];
}
}
return temp;
}
//----------------------------------------------------------//
// CUT BAND
//----------------------------------------------------------//
//cut off first and last column
fun void cutBand(int wolfram[][]){
for(0 => int i; i < wolfram.cap(); i++){
for(1 => int j; j < wolfram[i].cap()-1; j++){
wolfram[i][j] @=> band[i][j-1];
<<<band[i][j-1]>>>;
}
<<<"-----------">>>;
}
}
//----------------------------------------------------------//
// PLAY SOUND
//----------------------------------------------------------//
fun void play(int band[][]){
//go through the columns of the segment
for(0 => int i; i < band.cap(); i++){
//go through rows of segment
for(0 => int j; j < band[i].cap(); j++){
if(band[i][j] == 0){
m[j] =< mix; //value 0 -> unchuck instrument
}else{
m[j] => mix; //value 1 -> chuck instrument
}
m[j].noteOn(1); //play note
}
//same for second instrument
(i + 1) % 150 => int vorsprung;
for(0 => int j; j < band[i].cap(); j++){
if(band[vorsprung][j] == 0){
mandolin[j] =< mix; //value 0 -> unchuck instrument
}else{
mandolin[j] => mix; //value 1 -> chuck instrument
}
mandolin[j].noteOn(1); //play note
}
combo(i) => dur note; //get note from markov chain
note => now;
}
}
//----------------------------------------------------------//
// GET NEXT DURATION
//----------------------------------------------------------//
fun dur combo(int b){
//post[] counts how often a specific note length emerges after a given
//combination of the two previous note lengths.
float post[4];
//b represents the index of the current note length combination. has
//to be calculated mod 72 as durations[] does not have more elements
b % 72 => int c;
//copy current length combination to c1
durations[c] + durations[c+1] => string c1;
//go through all durations
for(0 => int i; i < durations.cap() - 2; i++){
if(durations[i] + durations[i+1] == c1){
//count the lengths following to the c1 combination
if(durations[i+2] == "v") post[0] + 1 => post[0];
if(durations[i+2] == "a") post[1] + 1 => post[1];
if(durations[i+2] == "pa") post[2] + 1 => post[2];
if(durations[i+2] == "pv") post[3] + 1 => post[3];
}
}
//total count of combination c1
post[0] + post[1] + post[2] + post[3] => float sum;
float thresholds[post.cap()];
for(0 => int i; i < thresholds.cap(); i++){
post[i] / sum => float tmp; //probability of length i
if(i == 0){
//just copy first probability value
tmp @=> thresholds[i];
}else{
//then add the following probabilities to the previous in order
//to get intervals between 0 and 1
thresholds[i-1] + tmp @=> thresholds[i];
}
}
//give me a random value and check out to which interval it corresponds
getRandVal(thresholds) => int interval;
//check interval and return the note length duration
//if pause, unchuck instruments
if(interval == 2){
for(0 => int i; i < m.cap(); i++){
m[i] =< mix;
mandolin[i] =< mix;
}
<<<"-----------">>>;
<<< "pauseLength: achtel" >>>;
<<<"-----------">>>;
return achtel;
}
if(interval == 3){
for(0 => int i; i < m.cap(); i++){
m[i] =< mix;
mandolin[i] =< mix;
}
<<<"-----------">>>;
<<< "pauseLength: viertel" >>>;
<<<"-----------">>>;
return viertel;
}
if(interval == 0){
<<< "noteLength: viertel" >>>;
return viertel;
}
if(interval == 1){
<<< "noteLength: achtel" >>>;
return achtel;
}
}
//----------------------------------------------------------//
// GET RANDOM VALUE
//----------------------------------------------------------//
fun int getRandVal(float threshold[]){
Std.rand2f(0, 1) => float rand;
for(0 => int z; z < threshold.cap(); z++){
//if true, return index which corresponds to interval
if(rand <= threshold[z]) return z;
}
} |
what do you think about it?
edit: thx 4 the advice, kassen! _________________ u said it man... nobody chucks with the jesus... Last edited by fraukefroehlich on Tue Jun 17, 2008 11:57 pm; edited 1 time in total |
|