Son of ethereal.ck

From CSWiki
Revision as of 11:12, 16 May 2007 by Chuckles (talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

// Can't figure out how to get this formatted as an unformatted // block in this wiki...hacking by putting a blank line // between every other line

// 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