BeatSched


A beat capable function scheduler  


Functions can be scheduled for precise execution using relative seconds, relative beats, absolute seconds or absolute beats.  This class uses TempoClock for scheduling, and has some overlap of capabilities with that.


The TempoClock class is used to specify what the tempo is, and is used for all beat <-> second calculations. The default global TempoClock object is used, or you can use a specific TempoClock instance.


There is a default global BeatSched that can be addressed through class methods.  It uses the SystemClock and the default global TempoClock.  You may also create individual instances that maintain their own scheduling queues, tempii, and time epochs.


If using BeatSched instances you can clear the queue, only affecting your own events.  If using the global BeatSched class, clearing the queue will affect everybody.  


All of these methods exist as both 

class (the default global scheduler) 

BeatSched.tsched(seconds,function)

and instance methods (a specific scheduler). 

beatSched = BeatSched.new;

beatSched.tsched(seconds,function)


The default clock used is the SystemClock, but you may also specify to use the AppClock.



tsched(seconds,function)

       time based scheduling

        delta specified in seconds

xtsched( seconds,function)

exclusive time based schedule

any previous messages scheduling using xtsched, xsched or xqsched will 

be cancelled. this is incredibly useful in situations where several messages 

might be sent and you only want the last one to be used as the final answer.

example:  a monkey is hitting many buttons, changing his mind about which 

sound to play next. this would result in many messages being stacked up all 

at the same time, and the server would choke trying to execute them all.  

this is a kind of enforced monophony.

another example:  a sequence plays successive notes, all using xsched,  

you then switch to a different sequence.  you don't want the note that was 

scheduled from the previous sequence to happen.  using one of the x-methods, 

you don't have to worry about it, the old notes will be cleared when new ones

are scheduled.

sched(beats,function)

        delta specified in beats

xsched(beats,function)

exclusive beat based scheduling

qsched(quantize,function)

        will happen at the next even division ( 4.0 means on the downbeat of a 4/4 bar ),

        or immediately if you happen to be exactly on a division.

xqsched(quantize,function)

exclusive quantized beat based scheduling

tschedAbs(time,function)

        will happen at the time specified in seconds

schedAbs(beat,function)

        will happen at the beat specified.

        

xblock

blocks any and all pending x-scheduled messages.

time

        get the scheduler's time

time_(seconds)

        set the scheduler's time        

beat

        get the scheduler's current beat

beat_(beat)

        set the scheduler's current beat.

        this is also used to start a "song":  zero the beat, and all absolute times

        previously scheduled events will be unpredictable

 deltaTillNext(quantizeDivision)

  returns the number of seconds untiil the next quantizeDivision.

  4.0 means the next even bar

  16.0 means the next 4 bar cycle

  0.25 means the next 16th note

 

        

clear

        clear all scheduled events. 

        

 

 

In the examples, remember to execute groups of code lines together.

 

b = BeatSched.new;

 

b.qsched(4.0,{ "hello".postln; });

 

b.qsched(4.0,{ "hello".postln; });



b.time; // since the app started


b.time = 0.0; // reset the time


b.time;

 

b.beat;


TempoClock.default.tempo = 2;

b.beat.postln;

TempoClock.default.tempo = 1;

b.beat.postln;



b.time = 0.0;

b.tschedAbs(4.0,{ "4 seconds absolute time".postln; });

b.tschedAbs(2.0,{ "2 seconds absolute time".postln; });



b.xsched(4.0, { "4 beats later".postln });

// cancels previous xsched

b.xsched(2.0, { "2 beats later".postln });


A little rounding error

(

TempoClock.default.tempo = 120 / 60.0;

d = Routine({

                20.do({

                var t;

                   t = BeatSched.global.tdeltaTillNext(4.0);

                   t.postln;

t.wait;

                });

        });

        SystemClock.play(d);

)



at 5206.432346276  we ask for deltaTillNext 4

[ 5204, 4, 5206.432346276 ]

1.5676537239997


that would be

5206.432346276 + 1.5676537239997

// at 5208

5208



// but when the scheded event comes due:

[ 5204, 4, 5207.999072862 ]

0.00092713799949706


its appears to be slightly ahead of schedule, due

to rounding errors in the several math ops that have happened.


so the right answer is 0.00092713799949706

as far as BeatSched is concerned.


but if you try to loop like this, you will suffer from rounding errors.


mostly you would never set up a loop like this, mostly

you just want to know when the next even beat is so you can get your groove on.





Tempo.bpm_(120);

d = Routine({

"wait for the downbeat...".postln; 

OSCSched.global.tdeltaTillNext(4.0).wait;


      32.do({ arg i;

           [i,BeatSched.beat].postln;

           Tempo.beats2secs(1.0).wait;

      });

 });

SystemClock.play(d);