Timelines, Events, and Maps

Loading, EventStore, Coordinate, ConversionMap

Timelines, Events, and Maps

Load real musical data, explore it as an EventStore, create a Timeline, and attach a ConversionMap to translate between units.

from pathlib import Path

from timetoalign.loader.score.partitura import PartituraLoader
from timetoalign.maps import TicksToQuarters

Load Events from a Score

DATA_DIR = Path(".").resolve().parents[1] / "tests" / "data" / "vienna_1x22"

loader = PartituraLoader()
loader.load(DATA_DIR / "Chopin_op10_no3.musicxml")
loader.store
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
~\miniconda3\envs\tta\Lib\site-packages\IPython\core\formatters.py in __call__(self, obj)
    343             method = get_real_method(obj, self.print_method)
    344             if method is not None:
--> 345                 return method()
    346             return None
    347         else:

~\git\tta\timetoalign\timetoalign\loader\store.py in _repr_html_(self)
    239         rows = []
    240         for name, info in summary.items():
--> 241             unit = info.get("unit", "unknown")
    242             count = info.get("count", 0)
    243             coord_range = info.get("range", (0.0, 0.0))

AttributeError: 'int' object has no attribute 'get'
ScoreStore(notes=498, measures=22, controls=27, annotations=0)

Create a Timeline

tl = loader.create_timeline(uid="chopin_etude")
tl
ContinuousLogicalTimeline[chopin_etude] (547 events, 3 children, 3 cmaps)
                      0 ________________________________ 41.5 quarters
  ├─ notes            0 ________________________________ 41.5 (498 events)
  ├─ measures         0 ________________________________ 41.5 (22 events)
  └─ controls         0 ______________________________   40 (27 events)

Access Events

The loader creates child timelines for each event category (notes, measures, controls). Access them via get_child().

tl.get_child("notes").get_events(event_type="Note").to_dataframe().head()
id name temporal_type event_type start end duration duration_float mc mn ... spelled_pitch tpc octave velocity tied gracenote chord_id voice staff part_id
0 notes:note:000001 B3 interval Note 0 0.50 1/2 0.50 1 1 ... {'gpc_int': 6, 'gpc_str': 'B', 'acc': 0, 'spc_... 5 3 64 0 None NaN 1 1 P1
1 notes:note:000002 E4 interval Note 1/2 1.00 1/2 0.50 2 2 ... {'gpc_int': 2, 'gpc_str': 'E', 'acc': 0, 'spc_... 4 4 64 0 None NaN 1 1 P1
2 notes:note:000003 G♯3 interval Note 1/2 0.75 1/4 0.25 2 2 ... {'gpc_int': 4, 'gpc_str': 'G', 'acc': 1, 'spc_... 8 3 64 0 None NaN 3 1 P1
3 notes:note:000004 E2 interval Note 1/2 0.75 1/4 0.25 2 2 ... {'gpc_int': 2, 'gpc_str': 'E', 'acc': 0, 'spc_... 4 2 64 0 None NaN 4 2 P1
4 notes:note:000005 E2 interval Note 1/2 1.50 1 1.00 2 2 ... {'gpc_int': 2, 'gpc_str': 'E', 'acc': 0, 'spc_... 4 2 64 0 None NaN 7 2 P1

5 rows × 23 columns

Coordinates

A Coordinate binds a number to a unit, ensuring type-safe arithmetic.

coord = tl.make_coordinate(8)
coord
Coordinate(8, quarters)

Conversion Maps (C-Maps)

Attach a map to translate the timeline’s native quarters into MIDI ticks (at 480 pulses per quarter).

q2t = TicksToQuarters(ppq=480).inverse()
tl.add_conversion_map(q2t)

ticks_coord = tl.convert_to(coord, target_unit="ticks")
{
    "input": f"{coord.value} {coord.unit.name}",
    "output": f"{ticks_coord}",
}
{'input': '8 quarters', 'output': '3840 ticks'}

Next: Children, Regions & Timestamps