Son of ethereal.ck
From CSWiki
// Son_of_Ethereal // -- originally written by Graham Percival, gperciva@uvic.ca, // Oct 2005 // Placed in the public domain. // 20070401 tps -- ok; try is changing the oscillators at random. // Do it by making an array of pointers to oscillators // 20070427 tps -- fixing up deprecated references (i.e., // std becomes Std, sinosc => SinOsc, etc. Rationalizing formatting // the way I likes it, etc. // 20070503 tps -- rather than just use integer multiples of the fundamental // for the harmonics, let's use some simple intervals... change harms // to be a float array to start with. // (Notes from original author at end) // ---------------------------------------------------------------------------- // Global stuff... // PARAMETERS 1 => int DEBUG; // 1 = debug print on, 0 = off 15 => int MAXOSC; // max of 15 oscillators at any one time 20 => int MAXHARM; // max of 20 pitches at any one time 110.0 => float fundfreq; // start with fundamental frequency of 110 Hz 0.2 => float NEWFREQPROB; // probability of changing the fundamental // // frequency. 1-NEWFREQPROB = chance of // // adding a new harmonic. 1000 => int MINEVENTTIME; // minimum time between events. (in ms) 3000 => int MAXEVENTTIME; // max time... (also in ms) SinOsc oscs[MAXOSC]; // oscs don't have to be sinosc; //TriOsc oscs[MAXOSC]; // try uncommenting one of //SqrOsc oscs[MAXOSC]; // these lines. // create relatively consonant intervals (2:1, 3:2, 5:3, 7:5) // over two octaves... [2., 3./2., 5./3., 7./5., 4., 3., 10./3., 14./5. ] @=> float intervals[]; intervals.cap() - 1 => int maxintervals; // auto init (don't touch these things) 1.0/MAXOSC => float MAXGAIN; float harms[MAXOSC]; // binary "is this in use?" array Pan2 pans[MAXOSC]; Envelope envs[MAXOSC]; 0 => int fundfreqblock; // init the oscs for (0 => int i; i < oscs.cap() ; i++ ) { oscs[i] => envs[i] => pans[i] => dac; 0 => harms[i]; 0 => pans[i].pan; } // functions: // newfundfreq() change gradually to a new fundamental frequency // addharm() add a new harmonic // walkharm() add a random pan // -------------------------------------------------------------------- fun void newfundfreq () { // don't get a new fundamental frequency if we're already // changing one. if (fundfreqblock==1) { return; } else { 1=> fundfreqblock; } // pick new fundamental fundfrequency float newfundfreq; fundfreq * Std.rand2f(0.8,1.25) => newfundfreq; if (newfundfreq < 110) 110 => newfundfreq; if (newfundfreq > 330) 330 => newfundfreq; // limit how far it // // can change if (DEBUG) <<< "start fundfreq moving to", newfundfreq >>>; // gliss to new fundfreq over 5 seconds...divide into 50 steps Std.fabs( (fundfreq-newfundfreq)/50) => float stepsize; for (0 => int i; i < 50; i++) { // yes, this can result in the fundreq alternating around the result // -- i.e. if funfreq is close to newfundfreq, it might reach (and // surpass) the goal, and then move in the opposite direction. This // is not a bug! :) // (ok, it _was_ unintentional, but I kind-of like // this behavior, so I didn't fix the bug) if (fundfreq < newfundfreq) stepsize +=> fundfreq; if (fundfreq > newfundfreq) stepsize -=> fundfreq; 100::ms => now; } if (DEBUG) <<< "fundfreq now", fundfreq >>>; 0 => fundfreqblock; } // -------------------------------------------------------------------- fun void addharm () { int i; // Find first unused osc -- reuse, recycle, and... err... something // else! // If all oscs are used, don't add a harmonic. Number of unused // osc is stored in i. for( 0 => i; i < oscs.cap(); i++ ) if (harms[i] == 0) break; if (i==MAXOSC) return; // pick harmonic to play... // Std.rand2(2, MAXHARM) => harms[i]; // new way to try to do this.... intervals[Std.rand2(0, maxintervals)] => harms[i]; fundfreq * harms[i] => oscs[i].freq; // ...and a random pan. Std.randf() => float t; Math.sin(t) => pans[i].pan; // target volume and speed at which we fade in Std.rand2f(MAXGAIN/4, MAXGAIN) => envs[i].target; // WTF is .time measured in?!?! // .time is measured in 100::ms for some ungodly reason. // This really needs to be documented!!! Std.rand2f(10, 20) => envs[i].time; envs[i].time() * 100::ms => now; if (DEBUG) <<< "into harms[", i, "] = ", harms[i] >>>; Std.rand2(500,10000) => int length; // isn't this a cool language? It's got a "maybe" statement! QED. // (tps} Sheesh...whatever. Isn't it basically the same as // Std.rand2(0, 1)? // anyway...half the time choose a new pan for harmonic if ( maybe ) walkharm(i, t, length/10); length::ms=>now; // fadeout; don't do it as fast as fadein 0 => envs[i].target; Std.rand2f(15, 30) => envs[i].time; // in seconds... envs[i].time() * 100::ms => now; if (DEBUG) <<< "from harms[", i, "] = ", harms[i] >>>; // release osc (lets us know that we're not using it) 0 => harms[i]; } // -------------------------------------------------------------------- fun void walkharm( int i, float t, int length ) { // panning harmonic; get speed of movement // Std.rand2(10, 30) / 1000.0 => float stepsize; // hm, why this rather than Std.rand2f (0.010, 0.030)? quicker? // let's try it: Std.rand2f (.010, .030) => float stepsize; for( 0 => int j; j < length; j++ ) { Math.sin(t) => pans[i].pan; stepsize +=> t; 10::ms => now; } } // -------------------------------------------------------------------- // main loop; random stuff happens // while( true ) { Std.rand2f(0, 1) => float doact; // now where's your precious // // maybe??! // do nothing if it's exactly NEWFREQPROB! This is not a bug! :) // (so you say) if (doact < NEWFREQPROB ) spork ~ newfundfreq(); if (doact > NEWFREQPROB ) spork ~ addharm(); Std.rand2(MINEVENTTIME, MAXEVENTTIME)::ms => now; } // Notes from original author: // Generates new age music. Make $$$ fast by holding down the // shift and pressing the "4" key! [ha ha] // Also by generating harmonically-related pitches. // (no, seriously; that was the class assignment. "Make // a program that generates harmonically-related pitches. You // can use it to produce reams of crappy new age music and // sell it") Well, in my opinion the professor sounds like // a real supercilious snob but what do I know? Maybe I'm reading // too much into his comment