Difference between revisions of "StereoChordEGG.ck"

From CSWiki
Jump to: navigation, search
 
(4 intermediate revisions by the same user not shown)
Line 1: Line 1:
    // In the late '60s or early 70's Paia electronics came out with a circuit kit called the
+
// 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
+
// 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.
+
// 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
+
//  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
+
// 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 <<<>>> ??!?!
+
    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.
+
    //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.
+
    // 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.
+
    // Paia used three note chords, so that's good enough for us.
        BandedWG tonic => gain g;
+
    BandedWG tonic => gain g;
        BandedWG two => g;
+
    BandedWG two => g;
        BandedWG third => g;
+
    BandedWG third => g;
 
+
        // the banded wave guides will be playing all the time, so the only control is that
+
    // 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.
+
    // we will be ramping the gain of the mixer from current vol to wanted vol.
        float currvol;
+
    float currvol;
        float wantedvol;
+
    float wantedvol;
        g => dac;
+
    g => dac;
 
+
        // set some defaults for the banded wave guide generators.  I don't know or care too much
+
    // 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.
+
    //  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.
+
    //  "The internet is the ultimate irreferance":  Jim Hinds. and you can quote me on that.
        public void  setBand ( BandedWG b, float loudness, int note ) {
+
    public void  setBand ( BandedWG b, float loudness, int note ) {
            loudness=> b.gain;
+
        loudness=> b.gain;
            1=> b.preset;
+
        1=> b.preset;
 
+
            // comp-XXX salesman: "hey Arnie!  He doesn't know what std.mtof does!". Spock: "read the source, luke".
+
        // comp-XXX salesman: "hey Arnie!  He doesn't know what std.mtof does!". Spock: "read the source, luke".
            std.mtof(21+note) => b.freq;
+
        std.mtof(21+note) => b.freq;
 
+
            // we love rand functions to set important parameters so that the wool is firmly over our eyes.
+
        // 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!"
+
        //  As the Church of the Subgenius sez: "Praise Bob!"
            std.rand2f( 0.1, 0.9 ) => b.bowRate;
+
        std.rand2f( 0.1, 0.9 ) => b.bowRate;
            std.rand2f( 0.2, 0.35 ) => b.bowPressure;
+
        std.rand2f( 0.2, 0.35 ) => b.bowPressure;
            std.rand2f( 0.6, 0.8 ) => b.startBowing;
+
        std.rand2f( 0.6, 0.8 ) => b.startBowing;
        }
+
    }
 
+
 
+
        // adjust the gain up or down as needed without going passed the desired limit
+
    // 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
+
    // 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.
+
    // direction.  This method doesnt know about that.  That's one reason it is private.
        private void gainTo ( float v, float wanted ) {
+
    private void gainTo ( float v, float wanted ) {
            currvol + v => float adjust;
+
        currvol + v => float adjust;
            if ( wanted > currvol && adjust > wanted ) wanted => adjust;
+
        if ( wanted > currvol && adjust > wanted ) wanted => adjust;
            if ( wanted < currvol && adjust < wanted ) wanted => adjust;
+
        if ( wanted < currvol && adjust < wanted ) wanted => adjust;
            adjust=>currvol;
+
        adjust=>currvol;
            adjust=>g.gain;
+
        adjust=>g.gain;
        }
+
    }
 
+
        // set some reasonable values for this object.  Normally we would do this in a constructor. (where
+
    // set some reasonable values for this object.  Normally we would do this in a constructor. (where
        // are the constructors?  I must have missed something...
+
    // are the constructors?  I must have missed something...
        //
+
    //
        public void  setChord ( int tonicValue, int twoValue, int thirdValue,string n) {
+
    public void  setChord ( int tonicValue, int twoValue, int thirdValue,string n) {
            n => myName;
+
        n => myName;
            setBand (tonic, .80, tonicValue);
+
        setBand (tonic, .80, tonicValue);
            setBand (two, .85, twoValue);
+
        setBand (two, .85, twoValue);
            setBand (third, .9, thirdValue);
+
        setBand (third, .9, thirdValue);
            0 => wantedvol;
+
        0 => wantedvol;
            0 => currvol;
+
        0 => currvol;
            0=> g.gain;
+
        0=> g.gain;
        }
+
    }
 
+
        //ramp the volume on this object incrementally till we hit the wanted volume
+
    //ramp the volume on this object incrementally till we hit the wanted volume
        public void rampgain ( ) {
+
    public void rampgain ( ) {
            float adjust;
+
        float adjust;
            while ( 1 ) {
+
        while ( 1 ) {
                175::ms => now;
+
            175::ms => now;
                if ( currvol > wantedvol ) {
+
            if ( currvol > wantedvol ) {
                    gainTo(-.2, wantedvol);
+
                gainTo(-.2, wantedvol);
                }
+
            }
                if ( currvol < wantedvol ) {
+
            if ( currvol < wantedvol ) {
                    gainTo(.1, wantedvol);
+
                gainTo(.1, wantedvol);
                }
+
            }
                // <<<myName, currvol,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();
+
    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;
    I.setChord ( 1,3,5,"I");
+
I.setChord ( 1,3,5,"I");
    spork ~ runChord(I);
+
spork ~ runChord(I);
    Chord IV;
+
Chord IV;
    IV.setChord ( 4,6,1,"IV");
+
IV.setChord ( 4,6,1,"IV");
    spork ~ runChord(IV);
+
spork ~ runChord(IV);
    Chord V;
+
Chord V;
    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++ ) {
+
    for ( 0 =>int i; i <3 ; i++ ) {
            0 => float v;
+
        0 => float v;
            if (i == index ) amplitude => v;
+
        if (i == index ) amplitude => v;
            v=> s [i].wantedvol;
+
        v=> s [i].wantedvol;
        }
+
    }
        t => now ;
+
    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 );
+
    changeto (std.rand2f(.5,.9),  std.rand2(0,2), std.rand2f(1.5,4)::second );
    }
+
}

Latest revision as of 18:09, 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 );
}