from pathlib import Path
from timetoalign import TimelineGroup
from timetoalign.loader.midi.performance import PerformanceMidiLoader
from timetoalign.loader.score.partitura import PartituraLoader
DATA_DIR = Path(".").resolve().parents[1] / "tests" / "data"Timeline Groups and Commensurability
TimelineGroup, coordinate transfer, partial alignment
Timeline Groups and Commensurability
Two timelines become commensurable — meaning coordinates can be transferred between them — once they share a TimelineGroup.
Load a Score and a Performance
_pt = PartituraLoader()
_pt.load(DATA_DIR / "midi" / "score" / "rachmaninoff_piano.mid")
score_tl = _pt.create_timeline(uid="score")
perf_tl = PerformanceMidiLoader.from_file(
DATA_DIR / "midi" / "performance" / "rachmaninoff_perf.mid"
).create_timeline(uid="performance")
{
"score": f"{score_tl.length} {score_tl.unit.name}",
"performance": f"{perf_tl.length} {perf_tl.unit.name}",
}/home/laser/miniconda3/envs/timetoalign/lib/python3.11/site-packages/partitura/io/importmidi.py:576: UserWarning: pitch spelling
warnings.warn("pitch spelling")
/home/laser/miniconda3/envs/timetoalign/lib/python3.11/site-packages/partitura/io/importmidi.py:661: UserWarning: create_part
part = create_part(
/home/laser/miniconda3/envs/timetoalign/lib/python3.11/site-packages/partitura/io/importmidi.py:661: UserWarning: add notes
part = create_part(
/home/laser/miniconda3/envs/timetoalign/lib/python3.11/site-packages/partitura/io/importmidi.py:661: UserWarning: add time sigs and measures
part = create_part(
/home/laser/miniconda3/envs/timetoalign/lib/python3.11/site-packages/partitura/io/importmidi.py:661: UserWarning: tie notes
part = create_part(
/home/laser/miniconda3/envs/timetoalign/lib/python3.11/site-packages/partitura/io/importmidi.py:661: UserWarning: find tuplets
part = create_part(
/home/laser/miniconda3/envs/timetoalign/lib/python3.11/site-packages/partitura/io/importmidi.py:661: UserWarning: done create_part
part = create_part(
{'score': '25.985417 quarters quarters', 'performance': '11537 ticks ticks'}
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)
groupTimelineGroup[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")
tsTimeStamp interpolated
| ID | Coordinate | Type |
|---|---|---|
| score | 20 quarters | axis |
| performance | 8880 ticks | child |
| measures | 6 measures | cmap |
| ticks | 9600 ticks | cmap |
# Transfer back: get timestamp at performance position 50.0 (ticks are DISCRETE)
ts_back = group.get_timestamp_at(50, "performance")
ts_backTimeStamp interpolated
| ID | Coordinate | Type |
|---|---|---|
| performance | 50 ticks | axis |
| score | 0.112618 quarters | child |
| measures | 1.028154 measures | cmap |
| ticks | 54 ticks | cmap |
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=(8.0, "score"),
end=(20.0, "score"),
)
partialTimelineGroup[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