// Boolean2blobman3.ck // copyright 2007 Les Hall // This software released under the GNU General Protective License // experiments with creating music from base n sequences // four instruments in Boolean logic sequence // and animating them in POV-Ray // control variables 100 => float frequency; // fundamental frequency, all others proportional to this 2 => int n; // starting numeric base of the sequence 128 => int num_notes; // number of notes to record 8 => float notes_per_second; // 8th or 4th notes 4096 => int num_samples; // number of fft samples num_samples / 2 => int num_freq; // number of fft frequencies num_notes => int num_ffts; // number of ffts to take 0.001 => float noise_threshold; // below this is noise 4 => int k; // divisor of spectrum to visualize 1500 => float fmax; // maximum frequency 90 => float theta_max; // maximum blobman theta // gain of each instrument Gain g[5]; 0.20 => g[0].gain; // Heavy Metal 0.10 => g[1].gain; // Clarinet 0.50 => g[2].gain; // Bowed 0.50 => g[3].gain; // Bowed2 0.50 => g[4].gain; // Drums // the heavy metal instrument HevyMetl hm => g[0] => dac.left; 1.0 => hm.noteOff; float notes_hm[num_notes]; // the clarinet instrument Clarinet cl => g[1] => dac.right; 1.0 => cl.noteOff; float notes_cl[num_notes]; // the bowed instruments Bowed bw[8]; for (0 => int i; i < 4; i++) { bw[i] => g[2] => dac.left; // bass guitar bw[4+i] => g[3] => dac.right; // lead guitar 1.0 => bw[i].noteOff; 1.0 => bw[4+i].noteOff; } float notes_bw[num_notes]; // the drums Impulse imp; BPF bpf[4]; for (0 => int i; i < 4; i++) { imp => bpf[i] => g[4] => dac; 100 => bpf[i].Q; } // the FFT patch dac => FFT fft => blackhole; num_samples => fft.size; Windowing.hamming(num_samples) => fft.window; // declare variables int count; // the n-ary count complex samples[num_freq]; // one frequency sample set complex history[num_ffts][num_freq]; // complete history of ffts // time loop while (true) { // calculate the logic threshold (n-1) / 2.0 => float t; // start blowing on the clarinet 1.0 => cl.startBlowing; // loop in a 8-bit binary sequence and pluck the strings for (0 => int j15; j15 < n; j15++) { for (0 => int j14; j14 < n; j14++) { for (0 => int j13; j13 < n; j13++) { for (0 => int j12; j12 < n; j12++) { for (0 => int j11; j11 < n; j11++) { for (0 => int j10; j10 < n; j10++) { for (0 => int j9; j9 < n; j9++) { for (0 => int j8; j8 < n; j8++) { for (0 => int j7; j7 < n; j7++) { for (0 => int j6; j6 < n; j6++) { for (0 => int j5; j5 < n; j5++) { for (0 => int j4; j4 < n; j4++) { for (0 => int j3; j3 < n; j3++) { for (0 => int j2; j2 < n; j2++) { for (0 => int j1; j1 < n; j1++) { for (0 => int j0; j0 < n; j0++) { // the heavy metal instrument if ((j7 >= t) && (j6 >= t) || (j5 >= t) && (j4 >= t) || (j3 >= t) && (j2 >= t) || (j1 >= t) && (j0 >= t)) { (((j3>=t) + 2*(j2>=t) + 2*(j1>=t) + (j0>=t))) * frequency => hm.freq; 1.0 => hm.noteOn; } // the clarinet instrument if ((j7 <= t) && (j6 <= t) || (j5 <= t) && (j4 <= t) || (j3 <= t) && (j2 <= t) || (j1 <= t) && (j0 <= t)) { ((8 + 1*(j4>=t) + 2*(j3>=t) + 2*(j2>=t) + (j1>=t))) * frequency => cl.freq; 1.0 => cl.noteOn; } // the first bowed instrument if ((j9 <= t) && (j8 <= t) || (j7 <= t) && (j6 <= t) || (j5 <= t) && (j4 <= t) || (j3 <= t) && (j2 <= t)) { (2 + ((j5>=t) && (j4>=t) || (j3>=t) && (j2>=t))/1.0) * frequency => bw[0].freq; for (1 => int i; i < 4; i++) { bw[0].freq() - 0.50*frequency*i => bw[i].freq; } for (0 => int i; i < 4; i++) { 1.0 => bw[i].noteOn; } } // the second bowed instrument if (((j7 >= 0) && (j5 >= 0) || (j6 >= t) && (j4 >= t)) && (j2 >= t) || (j1 >= t) && (j0 >= t)) { (2 + 4*(4*(j4<=t) + 2*(j2<=t) + 1*(j1<=t))/7.0) * frequency => bw[4].freq; for (5 => int i; i < 8; i++) { bw[4].freq() - 0.50*frequency*(i-4) => bw[i].freq; } for (4 => int i; i < 8; i++) { 1.0 => bw[i].noteOn; } } // the drums if ( (j0 >= t) ) { (2 + 0.5*(j2 >= t)) * frequency => bpf[0].freq; for (1 => int i; i < 4; i++) { bpf[0].freq() - 0.50*frequency*i => bpf[i].freq; } 1000 => imp.next; } 1::second / notes_per_second => now; // advance time (j15*Math.pow(n,15) + j14*Math.pow(n,14) + j13*Math.pow(n,13) + j12*Math.pow(n,12) + j11*Math.pow(n,11) + j10*Math.pow(n,10) + j9*Math.pow(n,9) + j8*Math.pow(n,8) + j7*Math.pow(n,7) + j6*Math.pow(n,6) + j5*Math.pow(n,5) + j4*Math.pow(n,4) + j3*Math.pow(n,3) + j2*Math.pow(n,2) + j1*Math.pow(n,1) + j0*Math.pow(n,0)) $ int => count; hm.freq() => notes_hm[count]; cl.freq() => notes_cl[count]; bw[0].freq() => notes_bw[count]; if (count >= num_notes - 1) break; // take fft and remember it fft.upchuck().cvals() @=> samples; for (0 => int i; i < num_freq; i++) { samples[i] => history[count][i]; } } if (count >= num_notes - 1) break; } if (count >= num_notes - 1) break; } if (count >= num_notes - 1) break; } if (count >= num_notes - 1) break; } if (count >= num_notes - 1) break; } if (count >= num_notes - 1) break; } if (count >= num_notes - 1) break; } if (count >= num_notes - 1) break; } if (count >= num_notes - 1) break; } if (count >= num_notes - 1) break; } if (count >= num_notes - 1) break; } if (count >= num_notes - 1) break; } if (count >= num_notes - 1) break; } if (count >= num_notes - 1) break; } if (count >= num_notes - 1) break; } if (count >= num_notes - 1) break; // stop blowing on the clarinet 1.0 => cl.stopBlowing; // increment the base number n++; // advance time between counting sequences 4::second => now; } // print out the POV-Ray code // output header text // these are the include files <<<"#include \"colors.inc\"", " ">>>; <<<"#include \"textures.inc\"", " ">>>; <<<"#include \"finish.inc\"", " ">>>; // these are the settings <<<"global_settings", "{">>>; <<<" assumed_gamma", "1">>>; <<<" max_trace_level", "256">>>; <<<"}", " ">>>; // this is the camera <<<"camera { location <0, 0, -10000> look_at <0, 0, 0>", "}">>>; // this is the light source <<<"light_source { <0, 10000, -10000>, rgb <1, 1, 1,>", " }">>>; // this is the sky sphere <<<"sky_sphere { pigment { rgb<1, 1, 1>", "} }">>>; <<<"#declare Heavy_Metal = array[", num_notes, "]{">>>; for (0 => int i; i< num_notes; i++) { <<>>; } <<<"}", " ">>>; <<<"#declare Clarinet = array[", num_notes, "]{">>>; for (0 => int i; i< num_notes; i++) { <<>>; } <<<"}", " ">>>; <<<"#declare Bowed = array[", num_notes, "]{">>>; for (0 => int i; i< num_notes; i++) { <<>>; } <<<"}", " ">>>; // save magnitude of fft history array to POV-Ray <<<"#declare fft_hist = array[", count+1, "][", num_freq/k, "]{">>>; for (0 => int t; t <= count; t++) { <<<"{", " ">>>; for (0 => int f; f < num_freq/k; f++) { if ((history[t][f] $ polar).mag < noise_threshold) { <<>>; } else { <<<(history[t][f] $ polar).mag, ",">>>; } } <<<"},", " ">>>; } <<<"}", " ">>>; // draw the three spheres <<<"sphere {<-5000,0,0>, Heavy_Metal[clock *", num_notes, "] pigment {Red}}">>>; <<<"sphere {<0,0,0>, Clarinet[clock *", num_notes, "] pigment {Green}}">>>; <<<"sphere {<5000,0,0>, Bowed[clock *", num_notes, "] pigment {Blue}}">>>; // draw FFT lines for (0 => int f; f < num_freq/k-1; f++) { <<<"cylinder {<", -5000+10000*f/(num_freq $float)*k, ", 2000+100000*fft_hist[clock *", count+1, "][", f, "], 0>">>>; <<<" <", -5000+10000*(f+1)/(num_freq $float)*k, ", 2000+100000*fft_hist[clock *", count+1, "][", f+1, "], 0>, 20">>>; <<<" pigment {Black}", " ">>>; <<<"}", " ">>>; } // introducing: Blob-Man! and Blob-Woman! <<<"#include \"bmpeople.inc\"", " ">>>; // find average values of frequencies 0 => float avg_cl; 0 => float avg_hm; 0 => float avg_bw; 0 => float fmax_cl; 0 => float fmax_hm; 0 => float fmax_bw; 0 => float fmin_cl; 0 => float fmin_hm; 0 => float fmin_bw; for (0 => int i; i < num_notes; i++) { notes_cl[i]/num_notes +=> avg_cl; notes_hm[i]/num_notes +=> avg_hm; notes_bw[i]/num_notes +=> avg_bw; if (notes_cl[i] > fmax_cl) { notes_cl[i] => fmax_cl; } if (notes_hm[i] > fmax_hm) { notes_hm[i] => fmax_hm; } if (notes_bw[i] > fmax_bw) { notes_bw[i] => fmax_bw; } if (notes_cl[i] < fmin_cl) { notes_cl[i] => fmin_cl; } if (notes_hm[i] < fmin_hm) { notes_hm[i] => fmin_hm; } if (notes_bw[i] < fmin_bw) { notes_bw[i] => fmin_bw; } } <<<"#declare angles = array[", num_notes, "]{">>>; for (0 => int i; i < num_notes; i++) { <<<"<", theta_max*(notes_cl[i]-fmin_cl)/(fmax_cl-fmin_cl)-theta_max/2, ",", theta_max*(notes_hm[i]-fmin_hm)/(fmax_hm-fmin_hm)-theta_max/2, ",", theta_max*(notes_bw[i]-fmin_bw)/(fmax_bw-fmin_bw)-theta_max/2, ">,">>>; } <<<"}", " ">>>; <<<"#declare BM_Head_Rot = <1,1,1> * angles[clock *", num_notes, "];">>>; <<<"#declare BM_RA_S2E = <1,1,-1> * angles[clock *", num_notes, "];">>>; <<<"#declare BM_LA_S2E = <1,-1,1> * angles[clock *", num_notes, "];">>>; <<<"#declare BM_RA_E2W = <1,1,1> * angles[clock *", num_notes, "];">>>; <<<"#declare BM_LA_E2W = <1,1,1> * angles[clock *", num_notes, "];">>>; <<<"#declare BM_Torso_Rot= <1,1,1> * angles[clock *", num_notes, "];">>>; <<<"Blob_Man(Male,5000)", " ">>>; <<<"object {BlobMan", " ">>>; <<<" transform BMO_Foot_R", " ">>>; <<<" translate <-2500, -4000, 0>", " ">>>; <<<"}", " ">>>; <<<"Blob_Man(Female,5000)", " ">>>; <<<"object {BlobMan", " ">>>; <<<" transform BMO_Foot_R", " ">>>; <<<" translate <2500, -4000, 0>", " ">>>; <<<"}", " ">>>;