(

//********************ADAM SCOTT NEAL***********************\\

//**************UNTITLED SUPERCOLLIDER PROJECT*************\\

//***************************12/14/10***************************\\ 


//*************************************************************\\

//************************ SYNTHDEFS *************************\\

//*************************************************************\\ 

// ADDITIVE SYNTH 'HIGH BELLS'

var instrument, out; 

SynthDef( "highbell", {arg dur=2.0, fundamental, partialOne, partialTwo, partialThree, db=0, pan=0 ;  

             a = Env.new([ 0.0001, 1.0, 0.0001 ],[0.001, 0.999 ],'linear' ) ;

             b = EnvGen.kr( a, doneAction: 2 ) ; 

             c = Mix(SinOsc.ar( [fundamental, partialOne, partialTwo, partialThree], 0.0, db.dbamp*[0.5, 0.4, 0.3, 0.2, 0.1]) );

             out = Pan2.ar( c * b, pan);

             Out.ar( 0, out ) ;  

}).send(s);  
 
 

// ADDITIVE SYNTH 'LARGE BELLS' 

SynthDef( "lowbell", {arg dur=5.0, fundamental, partialOne, partialTwo, partialThree, partialFour, partialFive, partialSix, partialSeven, partialEight, db=0, pan=0 ;  

             a = Env.new([ 0.0001, 1.0, 0.75, 0.0001 ],[dur*0.001, dur*0.009, dur*0.99 ],'exponential' ) ;  

             b = EnvGen.kr( a, doneAction: 2 ) ; 

             c = Mix(SinOsc.ar([fundamental, partialOne, partialTwo, partialThree, partialFour, partialFive, partialSix, partialSeven, partialEight],0, db.dbamp*[0.5,1,0.8,0.5,0.9,0.4,0.3,0.6,0.1]));

             out = Pan2.ar( c * b, pan);

             Out.ar( 0, out ) ;

}).send(s); 
 
 

// FILTERED NOISE 'ORGAN' 

SynthDef( "organ", {arg dur=5.0, fundamental, partialOne, partialTwo, partialThree, partialFour, partialFive, partialSix, db=0, pan=0 ;  

             a = Env.new([ 0.0001, 1.0, 0.75, 0.5, 0.0001 ],[dur*0.001, dur*0.009, dur*0.1, dur*0.89 ],'exponential' ) ;

             b = EnvGen.kr( a, doneAction: 2 ) ; 

             c = Mix(Resonz.ar(PinkNoise.ar, [fundamental, partialOne, partialTwo, partialThree, partialFour, partialFive, partialSix],0.0003, db.dbamp*[10,8,7,6,5,5,4,3,2]));

             out = Pan2.ar( (c*10) * b, pan);

             Out.ar( 0, out ) ;

}).send(s); 
 
 

// BANDPASS FILTER 'TRICKLING' 

SynthDef("trickle", { arg dur, db = 0.0, crackleParam=1.0, pan, cf, rq, sourcedB, reverbdB ; 

      var env, source, out ; 

      env = Env.new([ 0.00001, 1.0, 0.00001 ],[ 0.1, 0.9], 'exponential' ); 

      source = EnvGen.kr( env, timeScale: dur,  doneAction: 2) * Crackle.ar(crackleParam, db.dbamp ) ; 

  // FILTER

      out = BPF.ar(source, cf, rq  ) ;   

      // SEND TO REVERB BUS

      Out.ar(2, out * reverbdB.dbamp ) ; 

      out = Pan2.ar( out * sourcedB.dbamp, pan )  ; 

      Out.ar(0, out ) ; 

}).send(s);  
 

// RESONATING FILTER 'GHOSTS' 

SynthDef("ghosts", {arg dur=2.0, centerFreq, db=0, pan=0 ;  

             a = Env.new([ 0.0001, 1.0, 0.0001 ],[0.001, 0.999 ],'linear' ) ;

             b = EnvGen.kr( a, doneAction: 2 ) ; 

             c = Resonz.ar(PinkNoise.ar, centerFreq, 0.001, db.dbamp);

             out = Pan2.ar( (c*10) * b, pan);

             Out.ar( 0, out ) ;  

}).send(s);  
 

// KARPLUS-STRONG 'DRUM' 

SynthDef("drum", {arg pitch, db=0, pan=0;

   a = Env.new([ 0.0001, 1.0, 0.0001 ],[0.001, 0.999 ],'linear' ) ;

             b = EnvGen.kr( a, doneAction: 2 ) ; 

             c = Pluck.ar(WhiteNoise.ar(0.1), Impulse.kr(2), pitch.reciprocal, pitch.reciprocal, 2, 0.9, db.dbamp ) ;

             out = Pan2.ar(c * b, pan);

             Out.ar( 0, out); 

}).send(s); 
 
 
 

// REVERB 

SynthDef("fxexamplereverb", {arg delaytime=0.01, decaytime=1; 

      var input;

      var numc,numa,temp;

      input=In.ar(0,2); //get two channels of input starting (and ending) on bus 0

      numc = 4; // number of comb delays

      numa = 6; // number of allpass delays

      // reverb predelay time :

      temp = DelayN.ar(input, 0.048,0.048);

      temp=Mix.fill(numc,{CombL.ar(temp,0.1,rrand(0.01, 0.1),5)});

      // chain of 4 allpass delays on each of two channels (8 total) :

      numa.do({ temp = AllpassN.ar(temp, 0.051, [rrand(0.01, 0.05),rrand(0.01, 0.05)], 1) });

      // add original sound to reverb and play it :

      Out.ar(0,(0.1*temp));

      }).send(s);   
 
 

//*************************************************************\\

//********************** SCORE/ROUTINE ***********************\\

//*************************************************************\\ 

r = Routine({ 

      //VARIABLES

      var numberofnotes, waittimesarray, indexnumber=0, upperindexnumber=0, lowerwaittime, upperwaittime, bellvolume, waitspeed=1 ; 

      var superSet, currentSet, lowerBound=8, upperBound=16, lastLowerBound, boundaryShift, nextNote, nextNoteIndex, partialOne, partialTwo, partialThree,

      partialFour, partialFive, partialSix, partialSeven, partialEight; 

      var highBellNextNote, highBellNextNoteIndex, highBellPartialOne, highBellPartialTwo, highBellPartialThree; 

      var trickleStartIndex, trickleNextIndex, firstCf, nextCf, tricklewaittimesarray, trickleindexnumber=0 ; 

      var firstPan, panArray, panArrayweights ; 
 

      //"SUPER SET" - Frequencies based on synthesized bell timbres starting on 100, 200, 400, 800, 1600, and 3200 Hz

      //all fundamental pitches and most partials (except the Karplus-Strong "drum") are based on this set

      superSet = [100, 119, 156, 200, 238, 251, 301, 312, 400, 476, 502, 532, 602, 624, 800,

             820, 952, 1004, 1064, 1204, 1248, 1600, 1640, 1904, 2008, 2128, 2408, 2496, 3200,

             3280, 4016, 4256, 4816, 6400, 6560]; 

      //ARRAY OF PAN POSITIONS, TO BE SELECTED BELOW

      panArray = [-1, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1]; 
 

      //START THE REVERB

      Synth("fxexamplereverb") ; 

      1.0.wait; // small wait to keep routine from hiccupping at the beginning

  

      // MAIN LOOP

      4.do({ 
 

      //CHOOSE THE NUMBER OF LARGE BELLS IN THE LOOP

      numberofnotes = rrand(5,9) ;

      ("Number of Notes = " ++ numberofnotes).postln ; 

      //MAKE AN ARRAY FOR THE MAIN RHYTHM

      waittimesarray = Array.fill(numberofnotes, {rrand(1,4)}) ;

      ("Wait Times = " ++ waittimesarray).postln ; 

      //"Wait speed" - should get faster as tonic goes higher

      waitspeed = 1/(superSet[lowerBound]/400);

      waitspeed.postln;

      ("Wait speed = " ++ waitspeed).postln; 

      //BELLS WILL BE CHOSEN FROM THIS SUBSET OF THE "SUPER SET"

      currentSet = superSet.copyRange(lowerBound, upperBound);

      ("Current Set = " ++ currentSet).postln; 
 

      // FILTERED NOISE "ORGAN" WILL PLAY AT THE BEGINNING OF EACH LOOP

      Synth( "organ", [ \dur, rrand(24, 36),

             \fundamental, (superSet[lowerBound])*0.25,

             \partialOne, (superSet[lowerBound+2])*0.25,

             \partialTwo, (superSet[lowerBound+4])*0.25,

             \partialThree, (superSet[lowerBound+6])*0.25,

             \partialFour, (superSet[lowerBound+8])*0.25,

             \partialFive, (superSet[lowerBound+10])*0.25,

             \partialSix, (superSet[lowerBound+12])*0.25,

             \db, -12, \pan, rrand(-0.1, 0.1) ] ) ; 

      indexnumber=0; 

      while({indexnumber < numberofnotes}, { 

      //LARGE BELLS CHOSEN RANDOMLY THE CURRENT SUBSET - WAIT TIMES BASED ON RHYTHM ARRAY 

      nextNote = currentSet.choose.postln; 

      nextNoteIndex = superSet.indexOf(nextNote).postln; 

      ("Next Note = " ++ nextNote).postln;

      ("Wait this long: " ++ waittimesarray[indexnumber]).postln ; 

      Synth( "lowbell", [ \dur, rrand(5, 8),

             \fundamental, nextNote,

             \partialOne, superSet[nextNoteIndex + 2],

             \partialTwo, superSet[nextNoteIndex + 4],

             \partialThree, superSet[nextNoteIndex + 6],

             \partialFour, superSet[nextNoteIndex + 8],

             \partialFive, superSet[nextNoteIndex + 10],

             \partialSix, superSet[nextNoteIndex + 12],

             \partialSeven, superSet[nextNoteIndex + 14],

             \partialEight, superSet[nextNoteIndex + 16],

             \db, ((waittimesarray[indexnumber]*3)-42), \pan, rrand(-0.6, 0.6) ] ) ; 
 

                   // "TRIGGERED" INSTRUMENTS 

                   //if the lowest pitch of the subset is played, play HIGH BELLS

                   if(nextNoteIndex == lowerBound, { 

                   //MAKE A PANNING ARRAY, AND A WEIGHTS ARRAY - PANNING WILL BE

                   //WEIGHTED AROUND ONE PAN POSITION 

                   firstPan = panArray.choose;

                   panArrayweights = Array.fill(11, 0);

                   panArrayweights.put(panArray.indexOf(firstPan), 10);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))-1, 8);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))+1, 8);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))-2, 6);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))+2, 6);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))-3, 4);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))+3, 4);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))-4, 2);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))+4, 2);

                   panArrayweights = panArrayweights.normalizeSum; 

                   "Small bells".postln ;

                   ("How many notes do I play? : " ++ numberofnotes).postln;

                   upperindexnumber = 0 ; 

                   numberofnotes.do({

                         bellvolume = waittimesarray[upperindexnumber] ;

                         upperwaittime = (bellvolume*waitspeed)*0.25; 

                         highBellNextNoteIndex = ([12, 14, 16].choose)+lowerBound; 

                         Synth( "highbell", [ \dur, rrand(2, 3),

                               \fundamental, superSet[highBellNextNoteIndex],

                               \partialOne, superSet[highBellNextNoteIndex + 4],

                               \partialTwo, superSet[nextNoteIndex + 8],

                               \partialThree, superSet[nextNoteIndex + 12], 

                         \db, (bellvolume*3)-39, \pan, panArray.wchoose(panArrayweights) ] ) ;   

                         upperwaittime.wait;

                         ("Wait time = " ++ upperwaittime).postln;

                         upperindexnumber = upperindexnumber + 1 ;

                         ("Upper index number = " ++ upperindexnumber).postln ;

                               });

                   0.2.wait;

                   }); // end of HIGH BELLS 
 

                   //if the fourth note of the subset is played, HIGH BELLS (with different pitches)

                   if(nextNoteIndex == (lowerBound+3), { 

                   firstPan = panArray.choose;

                   panArrayweights = Array.fill(11, 0);

                   panArrayweights.put(panArray.indexOf(firstPan), 10);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))-1, 8);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))+1, 8);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))-2, 6);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))+2, 6);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))-3, 4);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))+3, 4);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))-4, 2);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))+4, 2);

                   panArrayweights = panArrayweights.normalizeSum; 

                   "Small bells".postln ;

                   ("How many notes do I play? : " ++ numberofnotes).postln;

                   upperindexnumber = 0 ; 

                   numberofnotes.do({

                         bellvolume = waittimesarray[upperindexnumber] ;

                         upperwaittime = (bellvolume*waitspeed)*0.25; 

                         highBellNextNoteIndex = ([16, 18, 20].choose)+lowerBound; 

                         Synth( "highbell", [ \dur, rrand(2, 3),

                               \fundamental, superSet[highBellNextNoteIndex],

                               \partialOne, superSet[highBellNextNoteIndex + 3],

                               \partialTwo, superSet[nextNoteIndex + 6],

                               \partialThree, superSet[nextNoteIndex + 9],

                         \db, (bellvolume*3)-39, \pan, panArray.wchoose(panArrayweights) ] ) ;   
 

                         upperwaittime.wait;

                         ("Wait time = " ++ upperwaittime).postln;

                         upperindexnumber = upperindexnumber + 1 ;

                         ("Upper index number = " ++ upperindexnumber).postln ;

                               });

                   0.2.wait;

                   }); // end of second HIGH BELLS 
 

                   //if the highest note of the subset is played, play TRICKLE

                   if(nextNoteIndex == (upperBound),  { 

                   //FIRST CENTER FREQUENCY IS VERY HIGH IN THE SUPERSET -

                   //ALL SUBSEQUENT GRAINS WILL DESCEND THROUGH THE SUPERSET FREQUENCIES 

                   "Trickling".postln ; 

                   trickleStartIndex=25;

                   trickleNextIndex=trickleStartIndex;

                   firstCf = superSet.clipAt(lowerBound+trickleStartIndex) ;

                   ("First Center Frequency: " ++ firstCf).postln ;

                   nextCf = firstCf; 

                   firstPan = panArray.choose;

                   panArrayweights = Array.fill(11, 0);

                   panArrayweights.put(panArray.indexOf(firstPan), 10);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))-1, 8);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))+1, 8);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))-2, 6);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))+2, 6);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))-3, 4);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))+3, 4);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))-4, 2);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))+4, 2);

                   panArrayweights = panArrayweights.normalizeSum; 

                   rrand(5, 8).do({ 

                         //Make a rhythm array

                         ("Number of Notes = " ++ numberofnotes).postln ;

                         tricklewaittimesarray = waittimesarray.copy;

                         ("Wait Times = " ++ tricklewaittimesarray).postln ; 

 
                        trickleindexnumber=0;
 

                         while({trickleindexnumber < numberofnotes}, { 

                               ("Wait this long: " ++ (tricklewaittimesarray[trickleindexnumber]*0.02)).postln ; 

                               //nextCf = nextCf-rrand(30, 100);

                               nextCf = superSet[lowerBound+trickleNextIndex];

                               //if(nextCf < superSet[lowerBound], {nextCf = superSet[lowerBound]}, {nextCf = nextCf});

                               ("Next Center Frequency: " ++ nextCf).postln; 

                               Synth("trickle", [\dur, rrand(0.5, 1.0), \db, -9, \pan, panArray.wchoose(panArrayweights), \cf, nextCf, \rq, rrand(0.1, 1.0)] );

                               (tricklewaittimesarray[trickleindexnumber]*0.02).wait;  

                               trickleindexnumber = trickleindexnumber + 1 ;

                               if(trickleNextIndex > 1, {trickleNextIndex = (trickleNextIndex - 1)}, {trickleNextIndex = 0});

                                                       }); // end of trickle while loop

                               }); // end of trickle do loop

                   0.2.wait;

                   }); // end of trickle 
 

                   // if the sixth pitch of the subset is played, play "GHOSTS"

                   if(nextNoteIndex == (lowerBound+5), { 

                   firstPan = panArray.choose;

                   panArrayweights = Array.fill(11, 0);

                   panArrayweights.put(panArray.indexOf(firstPan), 10);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))-1, 8);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))+1, 8);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))-2, 6);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))+2, 6);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))-3, 4);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))+3, 4);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))-4, 2);

                   panArrayweights.clipPut((panArray.indexOf(firstPan))+4, 2);

                   panArrayweights = panArrayweights.normalizeSum; 

                   "Ghosts!".postln ;

                   ("How many notes do I play? : " ++ numberofnotes).postln;

 
                  upperindexnumber = 0 ; 

                   numberofnotes.do({

                         bellvolume = waittimesarray[upperindexnumber] ;

                         upperwaittime = (bellvolume*waitspeed)*0.1; 

                         Synth( "ghosts", [ \dur, rrand(2, 3),

                         \centerFreq, [superSet[lowerBound+6], superSet[lowerBound+7], superSet[lowerBound+8], superSet[lowerBound+9], superSet[lowerBound+10]].choose,

                         \db, -3, \pan, panArray.wchoose(panArrayweights) ] ) ;   

                         upperwaittime.wait;

                         ("Wait time = " ++ upperwaittime).postln;

                         upperindexnumber = upperindexnumber + 1 ;

                         ("Upper index number = " ++ upperindexnumber).postln ;

                               });

                   0.2.wait;

                   }); // end of Ghosts 
 

             // if third pitch of the subset is played, play DRUM

             if(nextNoteIndex == (lowerBound+2), { 

             firstPan = panArray.choose;

             panArrayweights = Array.fill(11, 0);

             panArrayweights.put(panArray.indexOf(firstPan), 10);

             panArrayweights.clipPut((panArray.indexOf(firstPan))-1, 8);

             panArrayweights.clipPut((panArray.indexOf(firstPan))+1, 8);

             panArrayweights.clipPut((panArray.indexOf(firstPan))-2, 6);

             panArrayweights.clipPut((panArray.indexOf(firstPan))+2, 6);

             panArrayweights.clipPut((panArray.indexOf(firstPan))-3, 4);

             panArrayweights.clipPut((panArray.indexOf(firstPan))+3, 4);

             panArrayweights.clipPut((panArray.indexOf(firstPan))-4, 2);

             panArrayweights.clipPut((panArray.indexOf(firstPan))+4, 2);

             panArrayweights = panArrayweights.normalizeSum; 

             "Low drums".postln ;

             ("How many notes do I play? : " ++ numberofnotes).postln;

  
           upperindexnumber = 0 ; 

             numberofnotes.do({

                   bellvolume = waittimesarray[upperindexnumber] ;

                   upperwaittime = (bellvolume*waitspeed)*0.1; 

                   Synth( "drum", [ \pitch, (superSet[lowerBound])*0.5, \db, -9, \pan, panArray.wchoose(panArrayweights) ] ) ;   

                   upperwaittime.wait;

                   ("Wait time = " ++ upperwaittime).postln;

                   upperindexnumber = upperindexnumber + 1 ;

                   ("Upper index number = " ++ upperindexnumber).postln ;

                         });

             0.2.wait;

             }); // end of DRUM 
 

      waittimesarray[indexnumber].wait;

      indexnumber = indexnumber + 1 ; 

}); // end of main while loop 
 

//ON THE NEXT LOOP, THE SUBSET WILL SHIFT

      lastLowerBound = lowerBound.copy;

      boundaryShift = [-3, -2, 2, 3].choose;

      lowerBound = lowerBound+boundaryShift;

      upperBound = upperBound+boundaryShift; 

}); // end of main do loop 
 

// FINAL NOTE (THE LOWEST NOTE OF THE LAST SUBSET)

      Synth( "organ", [ \dur, rrand(24, 36),

             \fundamental, (superSet[lastLowerBound])*0.25,

             \partialOne, (superSet[lastLowerBound+2])*0.25,

             \partialTwo, (superSet[lastLowerBound+4])*0.25,

             \partialThree, (superSet[lastLowerBound+6])*0.25,

             \partialFour, (superSet[lastLowerBound+8])*0.25,

             \partialFive, (superSet[lastLowerBound+10])*0.25,

             \partialSix, (superSet[lastLowerBound+12])*0.25,

             \db, -9, \pan, rrand(-0.1, 0.1) ] ) ; 

      Synth( "lowbell", [ \dur, rrand(5, 8),

             \fundamental, superSet[lastLowerBound],

             \partialOne, superSet[lastLowerBound + 2],

             \partialTwo, superSet[lastLowerBound + 4],

             \partialThree, superSet[lastLowerBound + 6],

             \partialFour, superSet[lastLowerBound + 8],

             \partialFive, superSet[lastLowerBound + 10],

             \partialSix, superSet[lastLowerBound + 12],

             \partialSeven, superSet[lastLowerBound + 14],

             \partialEight, superSet[lastLowerBound + 16],

             \db, -36, \pan, rrand(-0.6, 0.6) ] ) ; 


"The End".postln; 

}); 

SystemClock.play(r);