Timeline Groups and Commensurability
Two timelines become commensurable — meaning coordinates can be transferred between them — once they share a TimelineGroup.
from timetoalign import TimelineGroup
from timetoalign.loader.midi.performance import PerformanceMidiLoader
from timetoalign.loader.score.partitura import PartituraLoader
from timetoalign.testdata import ensure_data
DATA_DIR = ensure_data("midi" )
/home/laser/miniconda3/envs/timetoalign/lib/python3.11/site-packages/partitura/__init__.py:9: UserWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html. The pkg_resources package is slated for removal as early as 2025-11-30. Refrain from using this package or pin to Setuptools<81.
import pkg_resources
Create a Group
Adding both timelines to the same group establishes a linear mapping between their full extents.
group = TimelineGroup(id = "rachmaninoff" )
group.add_timeline(score_tl)
group.add_timeline(perf_tl)
group
TimelineGroup[rachmaninoff] (2 timelines, 2 timestamps)
┌────────────────────────────────────────────────────────────────────────┐
│ ContinuousLogicalTimeline[score] (122 events, 3 children, 2 cmaps) │
│ 0 ____________________________ 26.0 quarters │
│ ├─ notes 0 ____________________________ 26.0 (111 events) │
│ ├─ measures 0 ____________________________ 26.0 (7 events) │
│ └─ controls 0 _ 0 (4 events) │
│ │
│ DiscreteLogicalTimeline[performance] (111 events) │
│ 0 ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 11537 ticks │
└────────────────────────────────────────────────────────────────────────┘
Timestamps: 2
Transfer Coordinates
# Get timestamp at score position 20.0 - shows ALL peer timelines
ts = group.get_timestamp_at(20.0 , "score" )
ts
TimeStamp interpolated
score
20 quarters
axis
performance
8880 ticks
child
ticks
9600 ticks
cmap
floating_measures
6 floating_measures
cmap
Try: ts.get(<tl_id>), ts.get_unit(<unit>)
# Transfer back: get timestamp at performance position 50.0 (ticks are DISCRETE)
ts_back = group.get_timestamp_at(50 , "performance" )
ts_back
TimeStamp interpolated
performance
50 ticks
axis
score
0.112618 quarters
child
ticks
54 ticks
cmap
floating_measures
1.028154 floating_measures
cmap
Try: ts.get(<tl_id>), ts.get_unit(<unit>)
Partial Alignment
If the performance only covers part of the score (say, quarter-beat positions 8 to 20), specify start and end boundaries.
partial = TimelineGroup(id = "partial" )
partial.add_timeline(score_tl)
partial.add_timeline(
perf_tl,
start= score_tl.make_coordinate(8.0 ).with_timeline("score" ),
end= score_tl.make_coordinate(20.0 ).with_timeline("score" ),
)
partial
TimelineGroup[partial] (2 timelines, 4 timestamps)
┌────────────────────────────────────────────────────────────────────────┐
│ ContinuousLogicalTimeline[score] (122 events, 3 children, 2 cmaps) │
│ 0 ____________________________ 26.0 quarters │
│ ├─ notes 0 ____________________________ 26.0 (111 events) │
│ ├─ measures 0 ____________________________ 26.0 (7 events) │
│ └─ controls 0 _ 0 (4 events) │
│ │
│ DiscreteLogicalTimeline[performance] (111 events) │
│ 0 ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 11537 ticks │
└────────────────────────────────────────────────────────────────────────┘
Timestamps: 4
Next: Alignment Bundles