View this PageEdit this PageUploads to this PageHistory of this PageTop of the SwikiRecent ChangesSearch the SwikiHelp Guide

tempoclock beatmatching, interpolation, synchronisation

Home   How To   Code Pool   Public Library   Theory   Events
extension - create a document called extTempoClock.sc containing the code below and save in the class directory.

// redFrik 050621
// beatmatching, interpolation, clock synchronisation
// this will adjust tempo to assure downbeat after x seconds

+TempoClock {
	
	sync {|tempo, secs= 4, resolution= 1|
		var next, time, durCur, durNew, durDif, durAvg, stepsPerBeat,
			delta, factor, steps, sum, durs, index= 0;
		secs= secs.max(0.03);					//saftey and lower jitter limit
		next= this.timeToNextBeat(1);
		time= secs-(this.tempo.reciprocal*next);
		if(time<next, {						//jump directly
			this.tempo_(next/secs);		//set a high tempo
			this.sched(next, {
				this.tempo_(tempo);
				nil;
			});
		}, {							//else interpolate
			this.sched(next, {				//offset the thing to next beat
				durCur= this.tempo.reciprocal;
				durNew= tempo.reciprocal;
				durDif= durNew-durCur;
				durAvg= durCur+durNew/2;		//average duration for number of steps
				stepsPerBeat= resolution.max(0.001).reciprocal.round;
				steps= (time/durAvg).round*stepsPerBeat;
				delta= stepsPerBeat.reciprocal;		//quantized resolution
				durs= Array.series(steps, durCur, durDif/steps);
				sum= durs.sum/stepsPerBeat;
				factor= time/sum;
				this.sched(0, {
					var tmp;
					if(index<steps, {
						tmp= (durs[index]*factor).reciprocal;
						this.tempo_(tmp);
						index= index+1;
						delta;
					}, {
						this.tempo_(tempo);
						nil;
					});
				});
				nil;
			});
		});
	}

}



examples:
//////////////////////////////////
s.boot;
(
SynthDef(\ping, {|freq|
	var e, z;
	e= EnvGen.ar(Env.perc(0, 0.1), doneAction:2);
	z= SinOsc.ar(freq.dup, 0, 0.2);
	OffsetOut.ar(0, z*e);
}).send(s);
)

//-- go from 1.5 to 0.8 and end on downbeat 4 sec from now
~from= 1.5;
~to= 0.8;
~sec= 4;
c= TempoClock(~from);
c.sched(c.timeToNextBeat(1), {Synth(\ping, [\freq, 800]); 1});
(
SystemClock.sched(~sec, {Synth(\ping, [\freq, 1200]); ~to.reciprocal});
c.sync(~to, ~sec);
)

//-- dec temo.  after 8.1 sec tempo 1.1
~from= 1.9;
~to= 1.1;
~sec= 8.1;
c= TempoClock(~from);
c.sched(c.timeToNextBeat(1), {Synth(\ping, [\freq, 800]); 1});
(
SystemClock.sched(~sec, {Synth(\ping, [\freq, 1200]); ~to.reciprocal});
c.sync(~to, ~sec);
)

//-- inc
~from= 1.1;
~to= 1.9;
~sec= 8.1;
c= TempoClock(~from);
c.sched(c.timeToNextBeat(1), {Synth(\ping, [\freq, 800]); 1});
(
SystemClock.sched(~sec, {Synth(\ping, [\freq, 1200]); ~to.reciprocal});
c.sync(~to, ~sec);
)

//-- quick adjust.  interpolation suffers a little.
~from= 1.0;
~to= 1.2;
~sec= 3.3;
c= TempoClock(~from);
c.sched(c.timeToNextBeat(1), {Synth(\ping, [\freq, 800]); 1});
(
SystemClock.sched(~sec, {Synth(\ping, [\freq, 1200]); ~to.reciprocal});
c.sync(~to, ~sec);
)


//-- 2 tempoclocks!!!  syncs them after 4.7 seconds
~from1= 1.02;
~to1= 1.8;
~from2= 1.3;
~to2= 1.8;
~sec= 4.7;
c= TempoClock(~from1);
d= TempoClock(~from2);
c.sched(c.timeToNextBeat(1), {Synth(\ping, [\freq, 800]); 1});
d.sched(d.timeToNextBeat(1), {Synth(\ping, [\freq, 1200]); 1});
(
c.sync(~to1, ~sec);
d.sync(~to2, ~sec);
)

//-- 2 tempoclocks synced almost at once
~from1= 1.02;
~to1= 1.8;
~from2= 1.3;
~to2= 1.8;
~sec= 0;
c= TempoClock(~from1);
d= TempoClock(~from2);
c.sched(c.timeToNextBeat(1), {Synth(\ping, [\freq, 800]); 1});
d.sched(d.timeToNextBeat(1), {Synth(\ping, [\freq, 1200]); 1});
(
c.sync(~to1, ~sec);
d.sync(~to2, ~sec);
)


//-- resolution make the interpolation smoother.  this will update tempo 5times/beat (0.2)
~from= 1.1;
~to= 1.5;
~sec= 7.3;
c= TempoClock(~from);
a= Pbind(\degree, Pseq([0, 5, 3, 2], inf), \dur, 0.125, \amp, 0.1).play(c);
c.sync(~to, ~sec, 0.2);


see also syncing tempclocks

Links to this Page