
//Initialize basic sequence info.
95.2 => float BPM;
4 => int numberOfBars;
4 => int beatsPerBar;
beatsPerBar * numberOfBars * 60 / BPM => float lengthOfSequence; //seconds

//determines quantization
16 => int stepsPerBar; //16th notes
stepsPerBar * numberOfBars => int stepsPerSequence;

14 => int numberOfSamples;
string sampleNames[numberOfSamples];
//put in file names
"PBJ7.wav" => sampleNames[0];
"PBJ12.wav" => sampleNames[1];
"PBJ13.wav" => sampleNames[2];
"PBJ14.wav" => sampleNames[3];
"PBJclic4.wav" => sampleNames[4];
"PBJdrum11.wav" => sampleNames[5];
"PBJdrum2.wav" => sampleNames[6];
"PBJdrum3.wav" => sampleNames[7];
"PBJkick20.wav" => sampleNames[8];
"PBJkick21.wav" => sampleNames[9];
"PBJmain7.wav" => sampleNames[10];
"PBJratt1.wav" => sampleNames[11];
"PBJsnare.wav" => sampleNames[12];
"PBJratt2.wav" => sampleNames[13];

//creates array of SndBuf, reads in the filename to initialize
SndBuf buf[numberOfSamples];
Gain gainAll;
0.1 => gainAll.gain;
for(0 => int i; i < numberOfSamples; i++)
{
    sampleNames[i] => buf[i].read;
    0 => buf[i].op;
    buf[i] => gainAll => dac;
}

//encode the information for my song
float chorusInfo[numberOfSamples][stepsPerSequence];
1 => chorusInfo[3][0];
1 => chorusInfo[3][16];
1 => chorusInfo[3][32];
1 => chorusInfo[3][48];
track chorusTrack;
chorusInfo @=> chorusTrack.trackInformation;

float chimeInfo[numberOfSamples][stepsPerSequence];
1 => chimeInfo[0][8];
1 => chimeInfo[0][8 + 16];
1 => chimeInfo[0][8 + 32];
1 => chimeInfo[0][8 + 48];
track chimeTrack;
chimeInfo @=> chimeTrack.trackInformation;

float drum1Info[numberOfSamples][stepsPerSequence];
1 => drum1Info[8][0];
1 => drum1Info[8][3];
1 => drum1Info[8][4];
1 => drum1Info[8][6];
1 => drum1Info[8][10];
1 => drum1Info[8][14];
1 => drum1Info[8][0 + 16];
1 => drum1Info[8][3 + 16];
1 => drum1Info[8][4 + 16];
1 => drum1Info[8][6 + 16];
1 => drum1Info[8][10 + 16];
1 => drum1Info[8][14 + 16];
track drumTrack1;
drum1Info @=> drumTrack1.trackInformation;

float drum2Info[numberOfSamples][stepsPerSequence];
1.2 => drum2Info[9][0 + 32];
1.2 => drum2Info[9][3 + 32];
1.2 => drum2Info[9][4 + 32];
1.2 => drum2Info[9][6 + 32];
1.2 => drum2Info[9][10 + 32];
1.2 => drum2Info[9][14 + 32];
1.2 => drum2Info[9][0 + 48];
1.2 => drum2Info[9][3 + 48];
1.2 => drum2Info[9][4 + 48];
1.2 => drum2Info[9][6 + 48];
1.2 => drum2Info[9][10 + 48];
1.2 => drum2Info[9][14 + 48];
track drumTrack2;
drum2Info @=> drumTrack2.trackInformation;

float drum3Info[numberOfSamples][stepsPerSequence];
1 => drum3Info[5][10];
1 => drum3Info[5][10 + 16];
1 => drum3Info[5][10 + 32];
1 => drum3Info[5][10 + 48];
track drumTrack3;
drum3Info @=> drumTrack3.trackInformation;

float drum4Info[numberOfSamples][stepsPerSequence];
1 => drum4Info[6][12];
1 => drum4Info[6][12 + 16];
1 => drum4Info[6][12 + 32];
1 => drum4Info[6][12 + 48];
track drumTrack4;
drum4Info @=> drumTrack4.trackInformation;

float drumSnareInfo[numberOfSamples][stepsPerSequence];
1 => drumSnareInfo [12][4];
1 => drumSnareInfo [12][12];
1 => drumSnareInfo [12][4 + 16];
1 => drumSnareInfo [12][12 + 16];
1 => drumSnareInfo [12][4 + 32];
1 => drumSnareInfo [12][12 + 32];
1 => drumSnareInfo [12][4 + 48];
1 => drumSnareInfo [12][10 + 48];
1 => drumSnareInfo [12][12 + 48];
1 => drumSnareInfo [12][14 + 48];
1 => drumSnareInfo [12][15 + 48];
track drumSnareTrack;
drumSnareInfo @=> drumSnareTrack.trackInformation;

float rattleInfo[numberOfSamples][stepsPerSequence];
1 => rattleInfo[13][2];
1 => rattleInfo[11][4];
1 => rattleInfo[11][5];
1 => rattleInfo[13][8];
1 => rattleInfo[13][10];
1 => rattleInfo[11][12];
1 => rattleInfo[11][13];
1 => rattleInfo[11][14];

1 => rattleInfo[13][2 + 16];
1 => rattleInfo[11][4 + 16];
1 => rattleInfo[11][5 + 16];
1 => rattleInfo[13][8 + 16];
1 => rattleInfo[13][10 + 16];
1 => rattleInfo[11][12 + 16];
1 => rattleInfo[11][13 + 16];
1 => rattleInfo[11][14 + 16];

1 => rattleInfo[13][2 + 32];
1 => rattleInfo[11][4 + 32];
1 => rattleInfo[11][5 + 32];
1 => rattleInfo[13][8 + 32];
1 => rattleInfo[13][10 + 32];
1 => rattleInfo[11][12 + 32];
1 => rattleInfo[11][13 + 32];
1 => rattleInfo[11][14 + 32];

1 => rattleInfo[13][2 + 48];
1 => rattleInfo[11][4 + 48];
1 => rattleInfo[11][5 + 48];
1 => rattleInfo[13][8 + 48];
1 => rattleInfo[13][10 + 48];
1 => rattleInfo[11][12 + 48];
1 => rattleInfo[11][13 + 48];
1 => rattleInfo[11][14 + 48];
track rattleTrack;
rattleInfo @=> rattleTrack.trackInformation;


float clickInfo[numberOfSamples][stepsPerSequence];
1 => clickInfo[4][2];
1 => clickInfo[4][6];
1 => clickInfo[4][10];
1 => clickInfo[4][14];
track clickTrack;
clickInfo @=> clickTrack.trackInformation;

float originalSampleInfo[numberOfSamples][stepsPerSequence];
1 => originalSampleInfo[10][0];
track originalSampleTrack;
originalSampleInfo @=> originalSampleTrack.trackInformation;

//put my tracks into an array of tracks
track songTracks[10];
drumTrack1 @=> songTracks[0];
drumTrack2 @=> songTracks[1];
drumTrack3 @=> songTracks[2];
drumTrack4 @=> songTracks[3];
drumSnareTrack @=> songTracks[4]; //
rattleTrack @=> songTracks[5]; //
clickTrack @=> songTracks[6];
chimeTrack @=> songTracks[7];
chorusTrack @=> songTracks[8];
originalSampleTrack @=> songTracks[9]; //


//create sequence for my song
sequence song;
stepsPerSequence => song.stepsPerSequence;
lengthOfSequence / stepsPerSequence => song.step_length;
songTracks.cap() => song.numberOfTracks;
songTracks @=> song.trackArray;
buf @=> song.samples;
gainAll @=> song.gainAll;
<<<"READY">>>;
song.performancePlay();

/*
//ORIGINAL SAMPLE
float originalSample[numberOfSamples][stepsPerSequence];
1 => originalSample[10][0];
track originalSampleTrack;
originalSample @=> originalSampleTrack.trackInformation;
track originalSongTracks[1];
originalSampleTrack @=> originalSongTracks[0];

sequence originalSong;
stepsPerSequence => originalSong.stepsPerSequence;
lengthOfSequence / stepsPerSequence => originalSong.step_length;
numberOfSamples => originalSong.numberOfTracks;
originalSongTracks @=> originalSong.trackArray;
buf @=> originalSong.samples;
originalSong.play();
*/

class track
{
    1 => int trackOn;
    //trackInformation[sample corresponding to sndbuf array][which point in the song (step #)];
    float trackInformation[][];

    fun void stopTrack()
    {
        0 => trackOn;
    }
    fun void startTrack()
    {
        1 => trackOn;
    }
    fun void toggle()
    {
        if(trackOn)
        {
            0 => trackOn;
        }
        else
        {
            1 => trackOn;
        }
    }
    
}

class sequence
{

     float step_length;
     int stepsPerSequence;
     int numberOfTracks;
     Gain @ gainAll;

     Event new_step;
	 1 => int on;
    
     SndBuf @ samples[];
    
     track trackArray[];
    
    fun void play()
    {
        spork ~ KeyBoardListener();
        while(on){
            playTracks();
        }
    }
    
    fun void performancePlay()
    {
        spork ~ KeyBoardListener();
        turnOffAllTracks();
        while(on){
            playTracks();
        }
    }
    
    fun void KeyBoardListener()
    {
        // computer keyboard input via terminal
        KBHit kb;

        while( true )
        {
            // wait on event
            kb => now;
        
            // loop through 1 or more keys
            while( kb.more() )
            {
                // get key
                kb.getchar() => int c;
                
                if( c == 122 && numberOfTracks > 0) //z
                    trackArray[0].toggle();
                else if( c == 120 && numberOfTracks > 1) //x
                    trackArray[1].toggle();
                else if(c == 99 && numberOfTracks > 2) //c
                    trackArray[2].toggle();
                else if(c == 118 && numberOfTracks > 3) //v
                    trackArray[3].toggle();
                else if(c == 97 && numberOfTracks > 4) //a
                    trackArray[4].toggle();
                else if(c == 115 && numberOfTracks > 5)//s
                    trackArray[5].toggle();
                else if(c == 100 && numberOfTracks > 6)//d
                    trackArray[6].toggle();
                else if(c == 102 && numberOfTracks > 7)//f
                    trackArray[7].toggle();
                else if(c == 113 && numberOfTracks > 8)//q
                    trackArray[8].toggle();
                else if(c == 119 && numberOfTracks > 9)//w
                    trackArray[9].toggle();
                else if(c == 101 && numberOfTracks > 10)//e
                    trackArray[10].toggle();
                else if(c == 114 && numberOfTracks > 11)//r
                    trackArray[11].toggle();
                else if(c == 49 && numberOfTracks > 12)//1
                    trackArray[12].toggle();
                else if(c == 50 && numberOfTracks > 13)//2
                    trackArray[13].toggle();
                else if(c == 51 && numberOfTracks > 14)//3
                    trackArray[14].toggle();
                else if(c == 52 && numberOfTracks > 15)//4
                    trackArray[15].toggle();
                else if(c == 32){
                    turnOffAllTracks();
                }
                
            }
        }
    }
    
    
    fun void playTracks()
    {
        0 => int i;
        1 => int n;
        for(0 => int step; step < stepsPerSequence; step++)
        {   
            for(0 => int track; track < trackArray.cap(); track++)
            {
                for(0 => int sample;  sample < samples.cap(); sample++)
                {   
                    trackArray[track].trackInformation[sample][step] => float val;
                    
                    
                    if(val != 0 && trackArray[track].trackOn){
                        spork ~ playSample(sample, val);
                    }
                    
                }
                
            }
            new_step.broadcast();
            if(i % 4 == 0){
                <<<n>>>;
                n++;
            }
            i++;
            if(n == 5)
                1 => n;
            step_length::second => now;
        }
        

    }
    
    fun void playSample(int sample, float val)
    {
        new_step => now;
        
        1 => samples[sample].op;
        0 => samples[sample].pos;
        val => samples[sample].gain;
        //samples[sample] => dac;
        //samples[sample] =< dac;
    }
    
    fun void turnOffAllTracks()
    {
        for(0 => int i; i < numberOfTracks; i++)
        {
             trackArray[i].stopTrack();
        }
    }
    
    fun void turnOffTracks(int off[])
    {
        for(0 => int i; i < off.cap(); i++)
        {
            if(off[i] < numberOfTracks)
                trackArray[off[i]].stopTrack();
        }
    }
    
    fun void turnOnTracks(int on[])
    {
        for(0 => int i; i < on.cap(); i++)
        {
            if(on[i] < numberOfTracks)
                trackArray[on[i]].startTrack();
        }
    }
	
    fun void stopSequence()
    {
        0 => on;
    }
    
}
