Newbie: what is the unit of .wait and can it be changed?

What’s the unit of wait? I could not find any info about it, nor could I find info on how to change the unit. Thanks much in advance!

(
{
"one thing".postln; 
2.wait;
"another thing".postln;
1.5.wait;
"one last thing".postln;
}.fork;
)

Hi Wolfgang,

It’s in beats

http://doc.sccode.org/Classes/SimpleNumber.html#-wait

The default tempo of the default clock is 1, meaning 1 beat per second, so if you haven’t specified otherwise, the wait is in seconds.

To change that, you would have to change the tempo of the clock your routine is running on.

Cheers

eddi

1 Like

Hi eddi,

thanks for the answer. Changing the tempo of the clock the routine is running on is what I am struggling with. I learned to use Pbind(PATTERNDATA).play(TempoClock(2)); to set the tempo. So I tried it on wait like this:

(
{
Pbind(
	\degree, Pseq([0 ,1 ,2 ,3 ,4 ,5 ,6 ,7]),
	\dur, 1
).play(TempoClock(2));
	8.wait(TempoClock(4));
Pbind(
	\degree, Pseq([0 ,1 ,2 ,3 ,4 ,5 ,6 ,7]),
	\dur, 1
).play(TempoClock(2));
}.fork
)

But while this did not generate an error, it also does not matter which number I use for the TempoClock after wait.

So I put the TempoClock after fork:

(
{
Pbind(
	\degree, Pseq([0 ,1 ,2 ,3 ,4 ,5 ,6 ,7]),
	\dur, 1
).play(TempoClock(2));
	8.wait;
Pbind(
	\degree, Pseq([0 ,1 ,2 ,3 ,4 ,5 ,6 ,7]),
	\dur, 1
).play(TempoClock(2));
}.fork(TempoClock(4))
)

This worked, as I was now able to change the tempo base for wait. Is this the recommended way?

Also I am not sure if my understanding of the interaction of waitand Pbind().playis correct: The first play and the first wait seem to start at the same time, and after the first wait is over, the next play and wait pair start. Is this correct?

Thanks in advance!

You don’t need to create new clocks for everything.

TempoClock supports a method tempo to get the current tempo, in beats per second (so .tempo * 60 is beats per minute), and a method tempo_() to change the tempo (also beats per second, so .tempo_(bpm / 60) is valid). These should be explained in the TempoClock help file, which if you haven’t read, go do so now.

Setter methods like tempo_ have a friendlier syntax: clock.tempo = bpm/60.

The help file should also explain that there is always a default TempoClock, used when you play a pattern without specifying a clock: TempoClock.default.

So you can change the master tempo by TempoClock.default.tempo = bpm/60;.

Further, many common clock methods have shortcuts for the default clock, so: TempoClock.tempo = bpm/60;.

hjh

Also, I would suggest the simplest possible design that accomplishes the goal. You might have a good reason to run a routine at one tempo, and then run the patterns in it at half tempo, but with such a simple tempo relationship, it would be more straightforward to run everything at pattern tempo.

Also, if you want pattern tempi to appear to be independent while their onsets are coordinated, another way to modify the apparent tempo of a pattern is by \stretch: \stretch, 2 in the pattern will make every event twice as long (half tempo) etc. So you could actually handle the requirement expressed above using one clock instead of three.

hjh

1 Like

Thank you, using TempoClock.default.tempo = bpm/60 helped to achieve the first part of my goal, which was to have one point where I can change the tempo for both .wait and Pbind().play. So this works:

(
TempoClock.default.tempo = 4;
{
Pbind(
	\degree, Pseq([0 ,0, 0, 0]),
	\dur, 1
).play;
	4.wait;
Pbind(
	\degree, Pseq([2 ,2]),
	\dur, 1
).play;
	2.wait;
Pbind(
	\degree, Pseq([3 ,3]),
	\dur, 1
).play;
}.fork
)

But ultimately I would like to be able to change the tempo gradually over time. So I replaced
TempoClock.default.tempo = 4;
with
TempoClock.default.tempo = Line.kr(0, 4, 8);
which throws an error I don’t understand. Please, what is my mistake here?

Line is a UGen, it only makes sense within a synth definition. What you need is a language-side solution.

Concerning your setup: probably it makes sense to look into Pspawner, which is a powerful pattern, designed to arrange sub-patterns, exactly the task you are going to achieve here.

And while James is right that you don’t need to make new tempo clocks for everything, keep in mind that adjusting the default tempo clock means, that all new patterns that you are playing without a specified TempoClock will take the adjusted default TempoClock, which can be very confusing. So IF you are going to change the tempo by manipulating a clock (you could do it in other ways) I’d recommend to take a dedicated new clock.

Example with Pspawner, suggested Pn as a more comfortable Pattern for repetition:

(
t = TempoClock(1);

p = Pspawner { |sp|	
	sp.seq(
		Pbind(
			\degree, Pn(0, 4),
			\dur, 0.2
		)
	);
	sp.wait(0.3);
	sp.seq(
		Pbind(
			\degree, Pn(2, 2),
			\dur, 0.2
		)
	);
	sp.wait(0.5);
	sp.seq(
		Pbind(
			\degree, Pn(3, 3),
			\dur, 0.2
		)
	);
}.play(t)
)

Concerning the tempo fade, you could do it by using one pattern changing the tempo clock of the other one. This solution is a bit lazy (here changing every 0.02 seconds), but practically it works. Note that Pseg is also a very useful Pattern, you can define curve types e.g. which is nice to find out convincing transitions.

(
TempoClock.default.tempo = 1;
t = TempoClock(1);

p = Pspawner { |sp| loop {
	sp.seq(
		Pbind(
			\degree, Pn(0, 4),
			\dur, 0.2
		)
	);
	sp.wait(0.3);
	sp.seq(
		Pbind(
			\degree, Pn(2, 2),
			\dur, 0.2
		)
	);
	sp.wait(0.5);
	sp.seq(
		Pbind(
			\degree, Pn(3, 3),
			\dur, 0.2
		)
	);
} };

q = Pbind(
	\dur, 0.02,
	\type, \rest,
	\newTempo, Pseg(Pseq([1, 1.5], inf), Pseq([5, 3, 2], inf)),
	\do, Pfunc { |ev| t.tempo = ev[\newTempo] }	
);
)

(
x = p.play(t);
y = q.play;
)

(
x.stop;
y.stop;
)

Besides you could do it also with multiplying durations with a factor, but this is probably less comfortable here, as the factor would have to be written at several places.

Other than that the tempo fade question has just been posed 5 days ago, and Simon has pointed to a worked-out soluion by Fredrik (which I haven’t tried yet):

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

1 Like

Hi Daniel, thanks much again! I will need some time to digest the Pspawner example.

Regarding changing TempoClock.default: The reason why I use it (instead of the “local” TempoClock) is that the local TempoClock only works on Pbind().play, not on .wait. The only way I found to change the beat duration of .wait was to put a TempoClock() after fork – but in this case only the .wait in the .fork are affected, but not the Pbind().play in the .fork. Please see my according confustion in my post above.

Which other ways are recommended to change the beat duration of .wait – beside changing the TempoClock.default?

P.S. Thanks also for the link to the wiki at the hfbk-hamburg – I will look at their curriculum, perhaps they will have an SC beginner tutorial I can attended!

Here you give two reasons more to take Pspawner :slight_smile: - constructs with nested ‘play’ statements are an indicator that code should be reorganised.

My side remark refered to the rough way of multiplying everything with a factor,
e.g.

wait(1 / ~tempo) 
...
\dur, 1 / ~tempo
...

Then you can change the tempo by setting the according variable. But as said especially in this case I’d not recommend it.

This website is really old - if you’re looking for tutorials with focus on Patterns: imo see primarily these two: The Pattern Guide from SCDoc help and Bruno Ruviaros tutorial.

1 Like

… and with this method also it’s a bit tricky where necessary to wrap into a Function. With Pspawner it’s not, but then sub-patterns can’t be changed while running. For this Pfunc could be wrapped around the tempo variable.

(
~tempo = 5;

p = Pspawner { |sp| 
	loop {
		sp.seq(
			Pbind(
				\degree, Pseq((0..7), 2),
				\dur, 1 / ~tempo
			)
		);
		sp.wait(8 / ~tempo);
	} 
}.play
)

// doesn't have an effect for currently running sub-pattern

~tempo = 10

p.stop

But a side remark anyway, I think the change with a TempoClock is much clearer / better in your use case.

1 Like

Regarding changing TempoClock.default: The reason why I use it (instead of the “local” TempoClock) is that the local TempoClock only works on Pbind().play, not on .wait. The only way I found to change the beat duration of .wait was to put a TempoClock() after fork – but in this case only the .wait in the .fork are affected, but not the Pbind().play in the .fork.

Yes, because when you pattern.play, it will use the clock that you specify, and if you didn’t specify a clock, then it will use TempoClock.default and not the clock in the enclosing routine.

So you could do:

(
r = {
	patternA.play(thisThread.clock);
	something.wait;
	patternB.play(thisThread.clock);
}.fork(TempoClock(2));  // but this is actually a bad idea, see below
)

When you use Pspawner as Daniel suggested, then everything within Pspawner is under control of the clock that Pspawner is running on, so that bit of fine print disappears.

Then, the other thing that might be tripping you up is that it’s not really ideal practice to embed new TempoClocks into method calls. Better practice is to keep a reference to the new clock in a variable. Then you can refer to the clock anywhere that you need.

That is – rule of thumb, if you catch yourself writing object.something(TempoClock(...)), then you’re probably making a mistake.

// antipattern, please try to avoid this
(
r = {
	// seems to be necessary
	// b/c you have no reference to the Routine's clock
	patternA.play(TempoClock(2));
	something.wait;
	patternB.play(TempoClock(2));
}.fork(TempoClock(2));
)

// better
(
t = TempoClock(2);

r = {
	patternA.play(t);  // variable reference to clock
	something.wait;
	patternB.play(t);  // and again
}.fork(t);  // and again
)

hjh

1 Like

Oh, and… I had mentioned the \stretch key in patterns, but that seems not to have been noticed in this thread.

hjh

1 Like

@jamshark70 and @dkmayer: Thanks much for the additional replies, still working on digesting these!

I don’t understand this – how would the \stretch key in a pattern affect the beat duration of .wait, as .wait is being used outside of/in-between pattern?

The – probably naive – reason for myself doing this was that I wanted to try to have each pattern in the `.fork run at its own tempo. :slight_smile:

Ah, ok, it doesn’t do that… but…

… you could use \stretch to simulate different tempi in each pattern, without running multiple clocks. So you would have the effect of tempo relationships between the players, and a wait time whose duration is controlled by the (single) clock (and is independent of any of the patterns’ \stretch values).

In any case, if you do want multiple clocks, it’s still better to keep variable references to all of them yourself.

hjh

This demand wasn’t in my focus before, but then I’d still use Pspawner with a dedicated TempoClock - it would affect the overall tempo and the wait times, plus sub-patterns’ tempo can be relatively set with a division of dur, as I mentioned before, or the stretch key. Master and relative tempos can also be set with ramps as described before.