Rhythmical Alternations
January 29, 2022
Last time, I looked at tidal.pegjs, which has an AST that is conceptually similar to rhythmical objects. In addition to sequential and parallel nodes, there are more ideas I haven't yet explored.
In this post, I want to take a look at alternating rhythms, which are enclosed with <
and >
in tidal mini notation.
Disclaimer: This post will be heavily repetitive and mathematical. As I am not a mathematician, I might not use conventional symbols for tree theory (if there are any).
Table of Contents
Example
C3 <Eb3 F3>
Playing back this pattern will have the following result:
C3 Eb3 C3 F3 C3 Eb3 C3 F3 C3 ...
In traditional western music notation, this could be notated like that:
In tidal.pegjs, the (unified) AST for C3 <Eb3 F3>
looks like this:
... which can be visualized with this tree:
Event Querying
So far, rendering the events for a rhythmical tree involved traversing the tree and calculating time and duration for each leaf.
When having alternating nodes, we need to know at which run through of the tree we are, to know which of the possible choices to pick. In the example above, we have two different ways to go, so for every first run, we pick the first and for every second run, we pick the second.
This can be made clearer with a table:
Q | 0 | 1 | 2 | 3 |
---|---|---|---|---|
V | C3 Eb3 | C3 F3 | C3 Eb3 | C3 F3 |
B0 | 0 | 1 | 0 | 1 |
- Q = query count
- V = event value(s)
- B0 = index of selected value in branch
- the dash indicates where it repeats
In this case, we can say:
To know which value to pick, the C3 is completely irrelevant, so we can ignore any non alternating nodes before and after.
Building Intuition
To further understand the behaviour of alternations, let's look at some more examples
Variable Branching Factor
The branching factor is the number of children of a node. The pattern <A B C>
has three children, so the branching factor is 3.
The table looks like this:
Q | 0 | 1 | 2 | 3 |
---|---|---|---|---|
V | A | B | C | A |
B0 | 0 | 1 | 2 | 0 |
Now, the index of the selected value is modulo 3:
More general, we can deduce:
Nested Alternations
It gets more complicated when we nest alternations into each other. Example: <<A B> C>
Q | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
V | A | C | B | C | A |
B0 | 0 | 1 | 0 | 1 | 0 |
B1 | 0 | _ | 1 | _ | 0 |
where Qr is the total length of the pattern until it repeats (dotted line).
Nested + Variable Branching Factor
<<A B> C D>
Q | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
V | A | C | D | B | C | D | A |
B0 | 0 | 1 | 2 | 0 | 1 | 2 | 0 |
B1 | 0 | _ | _ | 1 | _ | _ | 0 |
<<A B C> D>
Q | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
V | A | D | B | D | C | D | A |
B0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
B1 | 0 | _ | 1 | _ | 2 | _ | 0 |
From the two examples, we can deduce:
Nested with offset
<A <B C>>
Q | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
V | A | B | A | C | A |
B0 | 0 | 1 | 0 | 1 | 0 |
B1 | _ | 0 | _ | 1 | _ |
<A B <C D>>
Q | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
V | A | B | C | A | B | D | A |
B0 | 0 | 1 | 2 | 0 | 1 | 2 | 0 |
B1 | _ | _ | 0 | _ | _ | 1 | _ |
<A <B C D>>
Q | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|---|
V | A | B | A | C | A | D | A |
B0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
B1 | _ | 0 | _ | 1 | _ | 2 | _ |
From the above, we can deduce:
where I1 is the index of B1 inside B0.
Nesting even more
<<<A B> C> D>
Q | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|---|
V | A | D | C | D | B | D | C | D | A |
B0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
B1 | 0 | _ | 1 | _ | 0 | _ | 1 | _ | 0 |
B2 | 0 | _ | _ | _ | 1 | _ | _ | _ | 0 |
<<<A B> C> D E>
Q | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
V | A | D | E | C | D | E | B | D | E | C | D | E | A |
B0 | 0 | 1 | 2 | 0 | 1 | 2 | 0 | 1 | 2 | 0 | 1 | 2 | 0 |
B1 | 0 | _ | _ | 1 | _ | _ | 0 | _ | _ | 1 | _ | _ | 0 |
B2 | 0 | _ | _ | _ | _ | _ | 1 | _ | _ | _ | _ | _ | 0 |
From that, we can deduce:
<A <B <C D>>>
Q | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|---|
V | A | B | A | C | A | B | A | D | A |
B0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
B1 | _ | 0 | _ | 1 | _ | 0 | _ | 1 | _ |
B2 | _ | _ | _ | 0 | _ | _ | _ | 1 | _ |
<A <<B C> D>>
Q | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|---|
V | A | B | A | D | A | C | A | D | A |
B0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
B1 | _ | 0 | _ | 1 | _ | 0 | _ | 1 | _ |
B2 | _ | 0 | _ | _ | _ | 1 | _ | _ | _ |
<A <B <C <D E>>>>
Q | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
V | A | B | A | C | A | B | A | D | A | B | A | C | A | B | A | E | A |
B0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
B1 | _ | 0 | _ | 1 | _ | 0 | _ | 1 | _ | 0 | _ | 1 | _ | 0 | _ | 1 | _ |
B2 | _ | _ | _ | 0 | _ | _ | _ | 1 | _ | _ | _ | 0 | _ | _ | _ | 1 | _ |
B3 | _ | _ | _ | _ | _ | _ | _ | 0 | _ | _ | _ | _ | _ | _ | _ | 1 | _ |
General Formula
The above example can be deduced to:
Even more general:
In the example:
Conclusion
With the above general formula, we are able to know which branch will be selected at any query, without needing to calculate all preceeding query states. In a future post, I want to implement this + look at alternative ways to represent this. I think tidal cycles is doing this differently, using the slow function, which might be- simpler..