anacrusis = ShiftMap(offset=-0.5, source_unit="quarters", target_unit="quarters")notation_beats = [0.5, 1.0, 1.5, 2.0, 2.5, 3.0]pd.DataFrame( {"notation_beat": notation_beats,"adjusted_beat": [anacrusis(b) for b in notation_beats], })
notation_beat
adjusted_beat
0
0.5
0.0
1
1.0
0.5
2
1.5
1.0
3
2.0
1.5
4
2.5
2.0
5
3.0
2.5
TableMap: Non-Linear Mapping
Explicit anchor points with interpolation. Ideal for tempo-varying conversions.
tempo_map = TableMap( x_values=[0, 480, 960, 1440], y_values=[0.0, 0.5, 1.5, 2.0], source_unit="ticks", target_unit="seconds",)tick_samples = [0, 240, 480, 720, 960, 1200, 1440]pd.DataFrame( {"ticks": tick_samples,"seconds": [tempo_map(t) for t in tick_samples], })
ticks
seconds
0
0
0.00
1
240
0.25
2
480
0.50
3
720
1.00
4
960
1.50
5
1200
1.75
6
1440
2.00
# From MIDI-style tempo eventstempo_map = TableMap.from_tempo_changes( tick_positions=[0, 960], tempos_bpm=[120.0, 60.0], ticks_per_quarter=480,)ticks = [0, 240, 480, 720, 960, 1200, 1440, 1680, 1920]seconds = tempo_map(np.array(ticks))pd.DataFrame( {"ticks": ticks,"quarters": [t /480for t in ticks],"seconds": seconds, })
ticks
quarters
seconds
0
0
0.0
0.00
1
240
0.5
0.25
2
480
1.0
0.50
3
720
1.5
0.75
4
960
2.0
1.00
5
1200
2.5
1.50
6
1440
3.0
2.00
7
1680
3.5
2.50
8
1920
4.0
3.00
Interpolation Methods
Kind
Behaviour
linear
Straight line between anchors (default)
previous
Hold the left anchor’s value
next
Jump to the right anchor’s value
nearest
Use whichever anchor is closer
x = [0, 10, 20, 30]y = [0, 3, 7, 10]linear = TableMap(x_values=x, y_values=y, kind="linear")previous = TableMap(x_values=x, y_values=y, kind="previous")next_ = TableMap(x_values=x, y_values=y, kind="next")nearest = TableMap(x_values=x, y_values=y, kind="nearest")test_x = [5, 15, 25]pd.DataFrame( {"x": test_x,"linear": [linear(v) for v in test_x],"previous": [previous(v) for v in test_x],"next": [next_(v) for v in test_x],"nearest": [nearest(v) for v in test_x], })
x
linear
previous
next
nearest
0
5
1.5
0.0
3.0
0.0
1
15
5.0
3.0
7.0
3.0
2
25
8.5
7.0
10.0
7.0
ChainMap: Composing Maps
Chain maps with >> or .then(): f(g(x))
ticks_to_quarters = TicksToQuarters(ppq=480)quarters_to_seconds = ScalarMap( scalar=0.5, source_unit="quarters", target_unit="seconds")ticks_to_seconds = ticks_to_quarters >> quarters_to_secondsticks = [0, 480, 960, 1440, 1920]pd.DataFrame( {"ticks": ticks,"quarters": [ticks_to_quarters(t) for t in ticks],"seconds": [ticks_to_seconds(t) for t in ticks], })
ticks
quarters
seconds
0
0
0.0
0.0
1
480
1.0
0.5
2
960
2.0
1.0
3
1440
3.0
1.5
4
1920
4.0
2.0
# Inverse of a chain reverses order and inverts each mapseconds_to_ticks = ticks_to_seconds.inverse()seconds = [0.0, 0.5, 1.0, 1.5, 2.0]pd.DataFrame( {"seconds": seconds,"ticks": [seconds_to_ticks(s) for s in seconds], })