Time Dependant Variables

Programming in time

When you are live coding music you will often want things to change over time. One good way to demonstrate this is using chord sequences. Let’s say you have the sequence C-F-C-G, which we can represent as the Python list [0, 3, 0, 4], and we want to play the chords for 8 beats each but with a player that is playing notes every quarter beats. How do we do this? One solution might be to use the Pattern stutter method that repeats values in a Pattern “n” times:

>>> print(P[0, 3, 0, 4].stutter(4) + (0, 2, 4))
P[P(0, 2, 4), P(0, 2, 4), P(0, 2, 4), P(0, 2, 4), P(3, 5, 7), P(3, 5, 7), P(3, 5, 7), P(3, 5, 7), P(0, 2, 4), P(0, 2, 4), P(0, 2, 4), P(0, 2, 4), P(4, 6, 8), P(4, 6, 8), P(4, 6, 8), P(4, 6, 8)]

So to play the chord sequence above with a “pluck” sound we might do something like this:

p1 >> pluck(P[0, 3, 0, 4].stutter(32), dur=1/4) + (0, 2, 4)

At 4 notes per beat and 8 beats per chord we can easily work out that we need to stutter each pitch value 32 times. The problem is we have to change that value whenever we change the duration. If we change our duration to [1/2, 1/4, 1/4] we would need to do some maths in our head (or using Python) to calculate how many times to stutter the pitch values. To avoid this we can use variables that change their value over time so after 8 beats we automatically start playing a different pitch. These are known as “time-dependent variables” or “TimeVar” for short.

A TimeVar has a series of values that it changes between after a pre-defined number of beats and is created using a var object with the syntax var([list_of_values],[list_of_durations]). Example:

>>> a = var([0,3],4)             # Duration can be single value
>>> print(int(Clock.now()), a)   # 'a' initially has a value of 0 when 0 beats have elapsed
0, 0
>>> print(int(Clock.now()), a)   # After 4 beats, the value changes to 3
4, 3
>>> print(int(Clock.now()), a)   # After another 4 beats, the value changes back to 0
8, 0

So to solve our original problem with playing a chord sequence, we could use the following code with any value for duration and we would still here the sequence play for 8 beats per chord:

p1 >> pluck(var([0, 3, 0, 4], 8), dur=[1,1/4,1/4,1/2]) + (0, 2, 4)

Transforming TimeVars

When you use mathematical operation on a var, a new var is returned that also changes its value over time:

>>> a = var([0,3], 4)
>>> b = a + 5
>>> print(a, b)        # Current time = 0
0, 5
>>> print(a, b)        # beat = 4
3, 8
>>> c = PRange(4) + a
>>> print(c)           # beat = 8 and 'a' has a value of 0
P[0, 1, 2, 3]
>>> print(c)           # beat = 12 and a has a value of 3
P[3, 4, 5, 6]

Continuous change

So far we’ve only seen a TimeVar take on one of a set of predefined values but There are also types of TimeVar that gradually change between their values over time. One such example is the linvar. This is instantiated the same way as a var but the value changes linearly between states over time. The example below moves the panning from left to right over 8 beats and then back again.

p1 >> pluck(dur=1/4, pan=linvar([-1,1],8))