from klotho import Tree, RhythmTree as RT, plot, play
from klotho.chronos import TemporalUnit as UT, TemporalUnitSequence as UTS, TemporalBlock as BT
from fractions import Fraction
import numpy as npYou may have noticed that in our examples so far, we’ve been pairing RTs with parameters like bpm and beat to actually hear them. That’s because an RT on its own is a purely proportional object — it describes how time is divided, but not how long anything actually is.
Enter the Temporal Unit — or UT, from the French Unité temporelle.
Definition¶
A Temporal Unit (UT) is essentially a container for an RT that adds absolute temporal context. While an RT describes proportional subdivisions in the abstract, a UT fixes a tempo so that those proportions can be interpreted as real durations in time (seconds, milliseconds, etc.).
The concept was formalized by Karim Haddad in his doctoral thesis “L’Unité Temporelle: Une approche pour l’écriture de la durée et de sa quantification” (Sorbonne Université, 2020), building on the RT formalism developed by Haddad, Carlos Agon, and Gérard Assayag at IRCAM.
A UT is defined by the following parameters:
tempus— the time signature / measure (equivalent to the RT’smeas). This is the outer container size.prolationis— the subdivisions (equivalent to the RT’sSpart). These are the proportional subdivisions.beat— the reference beat for tempo (e.g.,'1/4'for a quarter note).bpm— beats per minute. Together withbeat, this anchors the proportions to real time.span— same as in RTs: how manytempus-sized units the rhythm spans.
S = ((3, (1, 1, 1)), 2, (2, (1, 1)), 1)
ut = UT(tempus='4/4', prolatio=S, beat='1/4', bpm=72)
print(ut)
plot(ut, layout='containers').play()Tempus: 4/4
Prolatio: Subdivision
Events: 7
Tempo: 1/4 = 72
Time: 00s:000ms - 03s:333ms (03s:333ms)
--------------------------------------------------
The UT wraps the same proportional structure we’ve been working with, but now it has a concrete temporal interpretation. Changing the bpm stretches or compresses the rhythm in real time without altering the proportional relationships:
Compositional Units¶
A Compositional Unit (UC) extends the UT with non-temporal parameters — pitch, dynamics, instrumentation, and more. If a UT is “a rhythm with a tempo,” a UC is “a complete musical passage with a rhythm, tempo, pitches, dynamics, and instrument assignments.”
You can think of a UC as a “UT with benefits.” We’ll explore UCs in detail in later notebooks, but it’s worth flagging now that the temporal structure we’ve been building is the foundation upon which all other musical parameters will be layered.
from klotho.thetos.composition import CompositionalUnit as UC
uc = UC.from_ut(ut)
print(uc)Tempus: 4/4
Prolatio: Subdivision
Events: 7
Tempo: 1/4 = 72
Time: 00s:000ms - 03s:333ms (03s:333ms)
--------------------------------------------------
We’ll work with UCs extensively when we get to composition and scoring. For now, just know they exist and that UTs are their rhythmic backbone.
Tempo as a Lens¶
The same proportional structure sounds dramatically different at different tempi. Let’s take a simpler subdivision and hear it at three different speeds:
S_simple = ((3, (1, 1, 1)), 2, 1)
for tempo in [60, 120, 200]:
ut_tempo = UT(tempus='4/4', prolatio=S_simple, beat='1/4', bpm=tempo)
print(f"bpm = {tempo}:")
plot(ut_tempo, layout='tree').play()bpm = 60:
bpm = 120:
bpm = 200:
The proportional relationships between the beats are identical in all three cases. What changes is the scale — how those proportions map onto real-world time. At 60 bpm, each quarter note is exactly 1 second; at 200 bpm, it’s 0.3 seconds.
Beat and Tempus¶
The beat parameter determines which subdivision receives one “click” of the metronome, and tempus (equivalent to meas in RT syntax) sets the total metric container. Different combinations change how the same subdivisions are grouped:
S_waltz = (1, 1, 1)
ut_44 = UT(tempus='4/4', prolatio=S_waltz, beat='1/4', bpm=100)
ut_34 = UT(tempus='3/4', prolatio=S_waltz, beat='1/4', bpm=100)
ut_68 = UT(tempus='6/8', prolatio=S_waltz, beat='3/8', bpm=100)
for label, u in [("4/4", ut_44), ("3/4", ut_34), ("6/8", ut_68)]:
print(f"tempus = {label}:")
print(u)
plot(u, layout='containers').play()
print()tempus = 4/4:
Tempus: 4/4
Prolatio: Subdivision
Events: 3
Tempo: 1/4 = 100
Time: 00s:000ms - 02s:399ms (02s:399ms)
--------------------------------------------------
tempus = 3/4:
Tempus: 3/4
Prolatio: Subdivision
Events: 3
Tempo: 1/4 = 100
Time: 00s:000ms - 01s:799ms (01s:799ms)
--------------------------------------------------
tempus = 6/8:
Tempus: 6/8
Prolatio: Subdivision
Events: 3
Tempo: 3/8 = 100
Time: 00s:000ms - 01s:199ms (01s:199ms)
--------------------------------------------------
The UT formalism, like the RT that underlies it, doesn’t impose a single notational interpretation. The same proportional structure can be contextualized in different metric containers, and it’s up to the composer (or the notation system) to decide how to interpret that.
Why UTs Matter¶
An RT is purely proportional — it describes how time is divided but has no idea when or how long. The UT supplies a tempo context that converts proportions into real durations. This is what makes playback possible: without a UT (or its equivalent parameters), there’s no way to know how fast a rhythm should go.
In the next notebook, we’ll explore how temporal units can be arranged into sequences and blocks — the structural units that form larger musical forms.