Smooth alteration of Tempo

How do you alter Tempo in a smooth way in SuperCollider? For example Accelerando, decelerando (probably not the right name), and maybe some
sort of Rubato. It seems bpm only wants a single number, whereas for some
musical ideas you would want bpm controlled by EnvGen and so forth.

                     Thank You For Your Attention

If you’re up to installing a library, you can do this in Alga:

(
Alga.boot({
	a = AP((
		def: { SinOsc.ar * EnvPerc.ar(release: 0.1 * \tempo.kr(1)) },
		tempo: Pfunc { Alga.clocks[Server.default].tempo.reciprocal }
	)).play(chans: 2)
})
)

//10 times faster
Alga.interpTempo(tempo: 10, time: 5)

//Using a shape
Alga.interpTempo(tempo: 3, time: 8, shape: Env([0, 1, 0, 1], [1, 2, 3]))

Pseg works for this. If it’s not obvious from the example, the timing of Pseg follows your tempo also - which means each envelope segment is 8 beats, not 8 seconds. This makes the most musical sense, but it becomes harder to e.g. have a slow tempo increase over an absolute period of time.

(
Pdef(\tempoFlux, Pbind(
	\scale, Scale.melodicMinor,
	\dur, 1/8,
	\degree, Pseq([
		-1, 2, 3, 5, 4, 1
	], inf) + Pseq([0, -2], inf).durStep(8),
	\tempo, Pseg([0.5, 4, 0.5], [8, 8]).repeat
)).play
)
1 Like

@elgiano once shared with me this approach:

// accelerate all patterns from 1 to 2 in 10 seconds
Task { (1,1.01..2).do { |t| TempoClock.default.tempo = t; 0.1.wait } }.play

// nicer
(
~glissTempo = { |target = 2, dur = 3, step = 0.01|
var taskClock = TempoClock(1);
Tdef(\tempoChange) {
    var current = TempoClock.default.tempo;
    var numSteps = (target - current) / step;
    var stepDur = dur / numSteps;
    if (numSteps < 0) { step = step.neg; numSteps = numSteps.neg; };
    
    (current, step .. target).do { |newTempo|
        TempoClock.default.tempo = newTempo;
        stepDur.wait;
    }
}.play(taskClock);
};
)

// go to 120bpm in 3 seconds
~glissTempo.(2, 3)
1 Like

I use this extension:

https://swiki.hfbk-hamburg.de/MusicTechnology/763

1 Like

I installed this library and installed AlgaUGens in the directory where Platform.userExtensionDir points (/home/clfest/.local/share/SuperCollider/Extensions). The code above doesn’t seem to work, that is we get the beep, but the //10 times faster code seems to have no effect, as does the line beneath it, and it seems they should. Please advise.

                               Thank You For Your Attention

My bad, just pushed a fix for it.

Apparently my SuperCollider doesn’t understand ‘durStep’. When I commented it out I saw what I think your example is supposed to demonstrate.

Would this TempoClock extension be suitable for real time modification of the TempoClock, for example if you were going to ‘conduct’ a piece?

                   Thank You For Your Attention

Loaded the new Quark but it doesn’t seem to help.

     Thank You For Your Attention

For simulating by-ear tempo changes between several musicians (resp. their clocks),
there is the ListeningClock quark, which can do smooth clock tempo changes using
various warps.

(
// prep: make a listening clock, 
t = ListeningClock.new.permanent_(true);

// a fast attack sound to use 
SynthDef(\ping, {|freq, pan, amp=0.3|
	var e = EnvGen.ar(Env.perc(0, 0.1, amp), doneAction:2);
	var z = SinOsc.ar(freq, 0, 0.2);
	OffsetOut.ar(0, Pan2.ar(z*e, pan));
}).add;

	// a pattern on clock t:
Pdef(\a,
	Pbind(\instrument, \ping,
		\degree, Pseq((0..7), inf),
		\dur, 0.25, \pan, -0.5, \amp, 0.5
	)
).play(t);
)

// fadeTempo(newTempo, time, warp); //
// makes a smooth tempo change on a listening clock
// newTempo is the tempo to go to, 
// time is the transition time, 
// and warp the warp of the interpolation from current to new tempo.

t.verbose_(true);

t.fadeTempo(exprand(0.5, 2.0), 4); 
t.fadeTempo(exprand(0.5, 2.0), 4); 


t.fadeTempo(2, 2, 0);   // linear fade
t.fadeTempo(1, 2, 0);   

t.fadeTempo(2, 2, 3);   // float warp: change begins with little steps, ends w big steps ends 
t.fadeTempo(1, 2, 3);   

t.fadeTempo(2, 4, \cos);  		// cosine shape (default): change starts slow, ends slow
 t.fadeTempo(1, 6, \cos);  		// cosine shape (default): change starts slow, ends slow

t.fadeTempo(2, 4, \sin); 		// sine shape, starts faster, ends slow
2 Likes