Difference between revisions of "StereoChordEGG.ck"
From CSWiki
Line 6: | Line 6: | ||
// hear what this little guy sounded like -- as best as my 35 year old, admittedly alcohol | // hear what this little guy sounded like -- as best as my 35 year old, admittedly alcohol | ||
// addled memories will permit. | // addled memories will permit. | ||
− | + | ||
− | + | ||
class Chord | class Chord | ||
{ | { | ||
− | + | string myName; // a name for us to show the user during debug prints. BTW: what's with <<<>>> ??!?! | |
− | + | ||
− | + | ||
− | + | //Paia's circuit used a top-octave generator to make a square wave train that they somehow filtered. | |
− | + | // I can't remember how that happened so I used banded wave guides, since it sounded right. | |
− | + | ||
− | + | // Paia used three note chords, so that's good enough for us. | |
− | + | BandedWG tonic => gain g; | |
− | + | BandedWG two => g; | |
− | + | BandedWG third => g; | |
− | + | ||
− | + | // the banded wave guides will be playing all the time, so the only control is that | |
− | + | // we will be ramping the gain of the mixer from current vol to wanted vol. | |
− | + | float currvol; | |
− | + | float wantedvol; | |
− | + | g => dac; | |
− | + | ||
− | + | // set some defaults for the banded wave guide generators. I don't know or care too much | |
− | + | // what these all mean. It is enough that someone out in internet land knows. | |
− | + | // "The internet is the ultimate irreferance": Jim Hinds. and you can quote me on that. | |
− | + | public void setBand ( BandedWG b, float loudness, int note ) { | |
− | + | loudness=> b.gain; | |
− | + | 1=> b.preset; | |
− | + | ||
− | + | // comp-XXX salesman: "hey Arnie! He doesn't know what std.mtof does!". Spock: "read the source, luke". | |
− | + | std.mtof(21+note) => b.freq; | |
− | + | ||
− | + | // we love rand functions to set important parameters so that the wool is firmly over our eyes. | |
− | + | // As the Church of the Subgenius sez: "Praise Bob!" | |
− | + | std.rand2f( 0.1, 0.9 ) => b.bowRate; | |
− | + | std.rand2f( 0.2, 0.35 ) => b.bowPressure; | |
− | + | std.rand2f( 0.6, 0.8 ) => b.startBowing; | |
− | + | } | |
− | + | ||
− | + | ||
− | + | // adjust the gain up or down as needed without going passed the desired limit | |
− | + | // note that the direction of the adjustment MUST be in agreement with the desired | |
− | + | // direction. This method doesnt know about that. That's one reason it is private. | |
− | + | private void gainTo ( float v, float wanted ) { | |
− | + | currvol + v => float adjust; | |
− | + | if ( wanted > currvol && adjust > wanted ) wanted => adjust; | |
− | + | if ( wanted < currvol && adjust < wanted ) wanted => adjust; | |
− | + | adjust=>currvol; | |
− | + | adjust=>g.gain; | |
− | + | } | |
− | + | ||
− | + | // set some reasonable values for this object. Normally we would do this in a constructor. (where | |
− | + | // are the constructors? I must have missed something... | |
− | + | // | |
− | + | public void setChord ( int tonicValue, int twoValue, int thirdValue,string n) { | |
− | + | n => myName; | |
− | + | setBand (tonic, .80, tonicValue); | |
− | + | setBand (two, .85, twoValue); | |
− | + | setBand (third, .9, thirdValue); | |
− | + | 0 => wantedvol; | |
− | + | 0 => currvol; | |
− | + | 0=> g.gain; | |
} | } | ||
− | + | ||
− | + | //ramp the volume on this object incrementally till we hit the wanted volume | |
− | + | public void rampgain ( ) { | |
− | + | float adjust; | |
− | + | while ( 1 ) { | |
− | + | 175::ms => now; | |
− | + | if ( currvol > wantedvol ) { | |
− | + | gainTo(-.2, wantedvol); | |
− | + | } | |
− | + | if ( currvol < wantedvol ) { | |
− | + | gainTo(.1, wantedvol); | |
− | + | } | |
− | + | // <<<myName, currvol,wantedvol>>>; | |
} | } | ||
} | } | ||
− | + | ||
} | } | ||
− | + | ||
// a function for "syntactic cod-liver-oil" since we can't spork c.rampgain directly | // a function for "syntactic cod-liver-oil" since we can't spork c.rampgain directly | ||
fun void runChord (Chord c) { | fun void runChord (Chord c) { | ||
− | + | c.rampgain(); | |
} | } | ||
− | + | ||
//set up the I, IV and V chords and start them sounding at amplitude zero | //set up the I, IV and V chords and start them sounding at amplitude zero | ||
Chord I; | Chord I; | ||
Line 101: | Line 101: | ||
V.setChord ( 5,7,2,"V"); | V.setChord ( 5,7,2,"V"); | ||
spork ~ runChord(V); | spork ~ runChord(V); | ||
− | + | ||
//since machines like to use numbers to access the chords, rather than names like I,IV,V | //since machines like to use numbers to access the chords, rather than names like I,IV,V | ||
//we put the chord object (references) into an array | //we put the chord object (references) into an array | ||
[I,IV,V] @=> Chord @ s[ ] ; | [I,IV,V] @=> Chord @ s[ ] ; | ||
− | + | ||
//changeto will bring up the volume on one of the chords and leave it like for a specified duration | //changeto will bring up the volume on one of the chords and leave it like for a specified duration | ||
fun void changeto (float amplitude,int index,dur t ) | fun void changeto (float amplitude,int index,dur t ) | ||
{ | { | ||
− | + | for ( 0 =>int i; i <3 ; i++ ) { | |
− | + | 0 => float v; | |
− | + | if (i == index ) amplitude => v; | |
− | + | v=> s [i].wantedvol; | |
− | + | } | |
− | + | t => now ; | |
} | } | ||
− | + | ||
//select a chord at random, bring it up to a random level and hold for some reasonable time | //select a chord at random, bring it up to a random level and hold for some reasonable time | ||
while (1) { | while (1) { | ||
− | + | changeto (std.rand2f(.5,.9), std.rand2(0,2), std.rand2f(1.5,4)::second ); | |
} | } |
Revision as of 18:08, 21 February 2006
// In the late '60s or early 70's Paia electronics came out with a circuit kit called the // Stereo Chord EGG (Electronic Gratification Generator). It was a top-octave generator // along with a resistor network to mix up the I,IV and V chords into the left and right channels. // // This little chuck proggy is an attempt to re-create "the wisdom of the ancients" and let you // hear what this little guy sounded like -- as best as my 35 year old, admittedly alcohol // addled memories will permit.
class Chord { string myName; // a name for us to show the user during debug prints. BTW: what's with <<<>>> ??!?!
//Paia's circuit used a top-octave generator to make a square wave train that they somehow filtered. // I can't remember how that happened so I used banded wave guides, since it sounded right.
// Paia used three note chords, so that's good enough for us. BandedWG tonic => gain g; BandedWG two => g; BandedWG third => g;
// the banded wave guides will be playing all the time, so the only control is that // we will be ramping the gain of the mixer from current vol to wanted vol. float currvol; float wantedvol; g => dac;
// set some defaults for the banded wave guide generators. I don't know or care too much // what these all mean. It is enough that someone out in internet land knows. // "The internet is the ultimate irreferance": Jim Hinds. and you can quote me on that. public void setBand ( BandedWG b, float loudness, int note ) { loudness=> b.gain; 1=> b.preset;
// comp-XXX salesman: "hey Arnie! He doesn't know what std.mtof does!". Spock: "read the source, luke". std.mtof(21+note) => b.freq;
// we love rand functions to set important parameters so that the wool is firmly over our eyes. // As the Church of the Subgenius sez: "Praise Bob!" std.rand2f( 0.1, 0.9 ) => b.bowRate; std.rand2f( 0.2, 0.35 ) => b.bowPressure; std.rand2f( 0.6, 0.8 ) => b.startBowing; }
// adjust the gain up or down as needed without going passed the desired limit // note that the direction of the adjustment MUST be in agreement with the desired // direction. This method doesnt know about that. That's one reason it is private. private void gainTo ( float v, float wanted ) { currvol + v => float adjust; if ( wanted > currvol && adjust > wanted ) wanted => adjust; if ( wanted < currvol && adjust < wanted ) wanted => adjust; adjust=>currvol; adjust=>g.gain; }
// set some reasonable values for this object. Normally we would do this in a constructor. (where // are the constructors? I must have missed something... // public void setChord ( int tonicValue, int twoValue, int thirdValue,string n) { n => myName; setBand (tonic, .80, tonicValue); setBand (two, .85, twoValue); setBand (third, .9, thirdValue); 0 => wantedvol; 0 => currvol; 0=> g.gain; }
//ramp the volume on this object incrementally till we hit the wanted volume public void rampgain ( ) { float adjust; while ( 1 ) { 175::ms => now; if ( currvol > wantedvol ) { gainTo(-.2, wantedvol); } if ( currvol < wantedvol ) { gainTo(.1, wantedvol); } // <<<myName, currvol,wantedvol>>>; } }
}
// a function for "syntactic cod-liver-oil" since we can't spork c.rampgain directly fun void runChord (Chord c) { c.rampgain(); }
//set up the I, IV and V chords and start them sounding at amplitude zero Chord I; I.setChord ( 1,3,5,"I"); spork ~ runChord(I); Chord IV; IV.setChord ( 4,6,1,"IV"); spork ~ runChord(IV); Chord V; V.setChord ( 5,7,2,"V"); spork ~ runChord(V);
//since machines like to use numbers to access the chords, rather than names like I,IV,V //we put the chord object (references) into an array [I,IV,V] @=> Chord @ s[ ] ;
//changeto will bring up the volume on one of the chords and leave it like for a specified duration fun void changeto (float amplitude,int index,dur t ) { for ( 0 =>int i; i <3 ; i++ ) { 0 => float v; if (i == index ) amplitude => v; v=> s [i].wantedvol; } t => now ; }
//select a chord at random, bring it up to a random level and hold for some reasonable time while (1) { changeto (std.rand2f(.5,.9), std.rand2(0,2), std.rand2f(1.5,4)::second ); }