Tap Tempo on the server

Usually I would implement tap tempo in sclang but the other day I was in a situation where it was convenient to implement tap tempo on the server and as this subject comes up from time to time, I wanted to share my code. It works like this:

  • 3 taps in a new tempo sets the new tempo
  • continuous tapping in the same tempo refines the tempo by supplying more data points
  • if the rate of tapping (ie. the time interval between this and the previous tap) changes by more than 200 ms, the tap counting is reset.

Try it:

(
s.waitForBoot{
	SynthDef(\tapTempo, {
		var trig = K2A.ar(\t_trig.kr(0));
		var trig1 = Delay1.ar(trig);
		var trig2 = Delay2.ar(trig);
		var phasor = Phasor.ar(trig2, 1, 0, inf, 0);
		var thistime = Latch.ar(phasor / SampleRate.ir, trig1);
		var lasttime = Latch.ar(thistime, trig);
		var reset = (thistime - lasttime).abs > 0.2;
		var count = PulseCount.ar(trig, reset);
		var phasor2 = Phasor.ar(reset, 1, 0, inf, 0);
		var tapDur = Latch.ar(phasor2 / count / SampleRate.ir, trig1 * (count > 0) * (1 - reset));
		var tempo = Select.kr(tapDur > 0, [1, tapDur]);
		Out.ar(0, Impulse.ar(1/tempo))
	}).add;

	s.sync;
	
	~tapSynth = Synth(\tapTempo);

	~button = Button()
	.fixedHeight_(80)
	.fixedWidth_(80)
	.canFocus_(false)
	.states_([ [\Tap, \, Color.grey.alpha_(0.2)], [\Tap, \, Color.green.alpha_(0.6)] ])
	.action_{|n|
		if (n.() == 1)
		{
			~tapSynth.set(\t_trig, 1);
			{ 0.1.wait; ~button.value_(0) }.fork(AppClock)
		}
	};

	~view = View().layout_(HLayout(~button)).front;
}
)

(
~tapSynth.free;
~view.close
)
1 Like