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.

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"

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}",
}
C:\Users\hentschel\miniconda3\envs\tta\Lib\site-packages\partitura\io\importmidi.py:575: UserWarning: pitch spelling
  warnings.warn("pitch spelling")
C:\Users\hentschel\miniconda3\envs\tta\Lib\site-packages\partitura\io\importmidi.py:658: UserWarning: create_part
  part = create_part(
C:\Users\hentschel\miniconda3\envs\tta\Lib\site-packages\partitura\io\importmidi.py:658: UserWarning: add notes
  part = create_part(
C:\Users\hentschel\miniconda3\envs\tta\Lib\site-packages\partitura\io\importmidi.py:658: UserWarning: add time sigs and measures
  part = create_part(
C:\Users\hentschel\miniconda3\envs\tta\Lib\site-packages\partitura\io\importmidi.py:658: UserWarning: tie notes
  part = create_part(
C:\Users\hentschel\miniconda3\envs\tta\Lib\site-packages\partitura\io\importmidi.py:658: UserWarning: find tuplets
  part = create_part(
C:\Users\hentschel\miniconda3\envs\tta\Lib\site-packages\partitura\io\importmidi.py:658: 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)
group
TimelineGroup[rachmaninoff] (2 timelines, 2 timestamps)
┌────────────────────────────────────────────────────────────────────────┐
│ ContinuousLogicalTimeline[score] (121 events, 3 children, 2 cmaps)     │
│                       0 ____________________________ 26.0 quarters     │
│   ├─ notes            0 ____________________________ 26.0 (111 events) │
│   ├─ measures         0 ____________________________ 26.0 (7 events)   │
│   └─ controls         0 _                            0 (3 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
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_back
TimeStamp 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"),
)
partial
TimelineGroup[partial] (2 timelines, 4 timestamps)
┌────────────────────────────────────────────────────────────────────────┐
│ ContinuousLogicalTimeline[score] (121 events, 3 children, 2 cmaps)     │
│                       0 ____________________________ 26.0 quarters     │
│   ├─ notes            0 ____________________________ 26.0 (111 events) │
│   ├─ measures         0 ____________________________ 26.0 (7 events)   │
│   └─ controls         0 _                            0 (3 events)      │
│                                                                        │
│ DiscreteLogicalTimeline[performance] (111 events)                      │
│                       0 ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, 11537 ticks     │
└────────────────────────────────────────────────────────────────────────┘
Timestamps: 4

Next: Alignment Bundles