Difference between revisions of "Son of ethereal.ck"

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

Latest revision as of 12:16, 27 September 2007

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