(

SynthDef("longplayer",{

arg buffer = 0,length = 1,realLength,

    pitch1 = 1,pitch2 = 0.75,pitch3 = 1.5,pitch4 = 0.5,pitch5 = 0.66,pitch6 = 1.33,

    startPos1 = 0,startPos2 = 0,startPos3 = 0,startPos4 = 0,startPos5 = 0,startPos6 = 0,

    offset1 = 0.204589821,offset2 = 46.44188,offset3 = 329.185022,

    offset4 = 2786.513362,offset5 = 11146.05345,offset6 = 19751.10132,

    yteration;

var e,osc;

e = Env.new([0,1,1,0],[0.05,0.95,0.05]);

osc = 

PlayBuf.ar(1,buffer,pitch1,startPos: (startPos1 + (offset1 * yteration))%realLength)

+

PlayBuf.ar(1,buffer,pitch2,startPos: (startPos2 + (offset2 * yteration))%realLength)

+

PlayBuf.ar(1,buffer,pitch3,startPos: (startPos3 + (offset3 * yteration))%realLength)

+

PlayBuf.ar(1,buffer,pitch4,startPos: (startPos4 + (offset4 * yteration))%realLength)

+

PlayBuf.ar(1,buffer,pitch5,startPos: (startPos5 + (offset5 * yteration))%realLength)

+

PlayBuf.ar(1,buffer,pitch6,startPos: (startPos6 + (offset6 * yteration))%realLength);


Out.ar([0,1],osc * EnvGen.kr(e,timeScale:length, doneAction: 2));

}).writeDefFile;

s.sendSynthDef("longplayer");

);


(

/*

SCREEN SIZE CONFIGURABLE

enter screen width in variable screenw

enter screen height in variable screenh


the soundfile has an extra section, the first two minutes, added to its end

this is to allow the 2 minute segment to slide seamlessly accross the join of

end and start points, as if the soundfile was glued together into a continuous circle


the upshot is that there are all kinds of work arounds in th GUI depending on sample rate and screen size, so that the range sliders show the correct positions.


this is written for 44100 sample rate

*/

var date;

var yr,mnth,dy,hr,min,sec,dumdum;

var leap,fullYearsRun,leapYears,notLeapYears,daysInFullYears,totalDays;

var daysInMonths,monthDays,leapMonthDays;

var onTime,listNo,extraIterations,timeCheck;

var onAt,extraIt,totalIterations,incList,realLength,lpCallList;

var timeZoneOffset;

//calculating time run

var minsrun,hrsrun,daysrun;


//GUI/////////////////////////

var daze,hrz,minz,scop,txt,rs1,rs2,rs3,rs4,rs5,rs6;

var screenw, screenh;

//for countdown

var onIn;

//for range sliders

var rangeList;

rangeList = #[rs1,rs2,rs3,rs4,rs5,rs6];


//screen dimensions

//width

screenw = 1680;

//height

screenh = 1050;



//London

timeZoneOffset = 12;

s.sendMsg("/b_allocRead",1,String.scDir ++"/sounds/20 20.aif");


lpCallList = List.fill(6,0);

//realLength is 20 mins 20 seconds * sample rate - here 44100

//actual soundfile is longer to emulate smooth transition across joined up start and end point

realLength = 53802000;

monthDays =#[0,31,59,90,120,151,181,212,243,273,304,334];

leapMonthDays =#[0,31,60,91,121,152,182,213,244,274,305,335];

incList = #[0.204589821,46.44188,329.185022, 2593.175981, 11146.05345, 19751.10132];

dumdum = List.fill(12,0);


date = Date.gmtime;

yr = date.year; 

mnth = date.month;

dy = date.day;

hr = date.hour;

min = date.minute;

sec = date.second;


if(min.even,{onTime = (min + 2)%60;timeCheck = 240},{onTime = (min + 3)%60;timeCheck = 360});


if(min > 56,{onAt = onTime + 60},

            {onAt = onTime});

            

["onAt "++onAt].postln;

if(yr%400 == 0,{leap = 1},

                 {if( yr%100 == 0,{leap = 0},

                                    {if( yr%4 == 0,{leap = 1},{leap = 0})}

                    )

                 }

  );

  

if(yr == 2000,{fullYearsRun = 0},

                {fullYearsRun = yr - 2000}

  );

if(yr ==2000,{leapYears = 0},

               {leapYears = (fullYearsRun/400).asInt    //one every 400 years

      + ((fullYearsRun/100).asInt * 24)      //24 per century

      + (((fullYearsRun%100)-1)/4).asInt     //one every 4 years

      + 1}                                   //one for 2000

  );

 if(yr == 2000,{notLeapYears = 0},

                {notLeapYears = fullYearsRun - leapYears});

                

 daysInFullYears = (notLeapYears * 365) + (leapYears * 366);

 

//calculate how many days in full months so far this year

if(leap == 0,{daysInMonths = monthDays.at(mnth-1)},

             {daysInMonths = leapMonthDays.at(mnth-1)});

 // if ontime is stroke of midnight then add a day

 // extraIt is extra iterations, number of hours and minutes passed in current day

if(min > 57,{hr = hr + 1;if(((hr + 1)%24) == 0,{dy = dy + 1;extraIt = 0},{extraIt = ((hr*30) + (onTime/2).floor)})},

  {extraIt = ((hr*30) + (onTime/2).floor)});

totalDays = daysInFullYears + daysInMonths + (dy - 1);

listNo = totalDays*720;

// + 30 to work around missing hour bug in total iteration calc.

//not necessary ?

//totalIterations = listNo + extraIt + 30 ;


totalIterations = listNo + extraIt;

//time zone offset

totalIterations = totalIterations + (timeZoneOffset * 30);


["time zone offset is local time plus "++timeZoneOffset++" hours"].postln;

["date and time at 180 degrees longitude is "++(if(hr + timeZoneOffset > 23,{dy+1},{dy}))++" : "++mnth++" : "++yr++"   "++((hr + timeZoneOffset)%24)++" hours : "++min++" minutes"].postln;

["total iterations is "++totalIterations].postln;

"this has been called from longplayer app".postln;

//startup

6.do({arg i;var temp;temp = (totalIterations*(incList@i))%realLength;lpCallList.put(i,temp)});


["start point list is "++lpCallList].postln;


minsrun = totalIterations * 2;

minz = minsrun%60;

if(minz == -0,{minz = 0});

hrsrun = ((minsrun/60).floor);

hrz = hrsrun%24;

if(hrz == -0,{hrz = 0});

daze = (hrsrun/24).floor;



//GUI////////////////////

/*

the soundfile has an extra section, the first two minutes, added to its end

this is to allow the 2 minute segment to slide seamlessly accross the join of

end and start points, as if the soundfile was glued together into a continuous circle


the upshot is that there are all kinds of work arounds in th GUI depending on smaple rate and screen size, so that the range sliders show the correct positions.


this is written for 44100 sample rate and 1240 pixel range slider

*/


w = SCWindow("Longplayer", Rect(0, 0, screenw, screenh));

l = SCCompositeView(w, Rect(0, 0, screenw+20, screenh/2.3));

c = Stethoscope.new(s, view:l);

w.front;

w.view.background = Color.new255(49,26,176);


txt = SCStaticText(w, Rect(20,  screenh/2.3, screenh*0.8, 60));

txt.string = "  Longplayer                        "++daze++" days "++hrz++" hours and "++minz++" minutes";

txt.font = Font("Courier", 15);

txt.backColor_(Color.new255(15,61,176));


x = SCStaticText(w, Rect(20, (screenh/2.3)+100, 200, 40));

x.string = "  LAYERS  ";

x.font = Font("Courier", 15);

x.backColor_(Color.new255(15,61,176));


rs1 = SCRangeSlider(w, Rect(20,(screenh/2.3)+170,screenw-40,40)).backColor_(Color.new255(171,29,227)).range_(0.0895);

rs2 = SCRangeSlider(w, Rect(20,(screenh/2.3)+220,screenw-40,40)).backColor_(Color.new255(171,29,227)).range_(0.0895);

rs3 = SCRangeSlider(w, Rect(20,(screenh/2.3)+270,screenw-40,40)).backColor_(Color.new255(171,29,227)).range_(0.0895);

rs4 = SCRangeSlider(w, Rect(20,(screenh/2.3)+320,screenw-40,40)).backColor_(Color.new255(171,29,227)).range_(0.0895);

rs5 = SCRangeSlider(w, Rect(20,(screenh/2.3)+370,screenw-40,40)).backColor_(Color.new255(171,29,227)).range_(0.0895);

rs6 = SCRangeSlider(w, Rect(20,(screenh/2.3)+420,screenw-40,40)).backColor_(Color.new255(171,29,227)).range_(0.0895);


//////////////////////



onIn = ((onAt * 60) - ((Date.localtime.minute * 60) + (Date.localtime.second))).post;

//start up post routine

t = Routine({

onIn.do

({arg j;

  {txt.string = "  Longplayer starting up in "++(onIn - j)++ " seconds"}.defer;

     1.wait;

     });

});

SystemClock.play(t);


//play routine

r = Routine({

onIn.wait;

inf.do({arg j;

x =

Synth("longplayer",['buffer',1,'length',120,'realLength',realLength,'startPos1',lpCallList@0,'startPos2',lpCallList@1,'startPos3',lpCallList@2,'startPos4',lpCallList@3,'startPos5',lpCallList@4,'startPos6',lpCallList@5,'yteration',j]);

totalIterations = totalIterations +1;

//set range sliders

//calculate start points

//59094000 is divisor to map samples to pixels in a 1240 pixel length range slider

{rs1.lo_((((lpCallList@0 + (incList@0 * j))%realLength)/59094000)%0.91044).range_(0.0895);

 rs2.lo_((((lpCallList@1 + (incList@1 * j))%realLength)/59094000)%0.91044).range_(0.0895);

 rs3.lo_((((lpCallList@2 + (incList@2 * j))%realLength)/59094000)%0.91044).range_(0.0895);

 rs4.lo_((((lpCallList@3 + (incList@3 * j))%realLength)/59094000)%0.91044).range_(0.0895);

 rs5.lo_((((lpCallList@4 + (incList@4 * j))%realLength)/59094000)%0.91044).range_(0.0895);

 rs6.lo_((((lpCallList@5 + (incList@5 * j))%realLength)/59094000)%0.91044).range_(0.0895);

}.defer;


minsrun = totalIterations * 2;

//work around

minsrun = minsrun - 2;

minz = minsrun%60;

if(minz == -0,{minz = 0});

hrsrun = ((minsrun/60).floor);

hrz = hrsrun%24;

if(hrz == -0,{hrz = 0});

daze = (hrsrun/24).floor;

{txt.string = "  Longplayer                        "++daze++" days "++hrz++" hours and "++minz++" minutes";

}.defer;

120.wait;

     });

   });

  

SystemClock.play(r);

 


)