Below is a script that is meant to do something simple:
- Create a finite PSequence (
pat) from 10 hardcoded notes with repeats=1
- Create another pattern (
dur) using PScaleLinLin to scale the notes in pat to the range 0.2 to 1.2
- Create reversed copies of each (
rpat and rdur)
- Schedule
pat notes to play for duration dur
- Schedule
rpat notes to play for duration rdur
- Run timeline.
You would expect both tracks to finish at the same time, because the sums of dur and rdur are the same forwards or backwards. But the first track finishes well before the second, as you can hear and see from the logging messages:
[2022-03-17 14:37:24,183] Timeline: Scheduled new track (total tracks: 1)
[2022-03-17 14:37:24,183] Timeline: Scheduled new track (total tracks: 2)
[2022-03-17 14:37:24,183] Timeline: Starting
[2022-03-17 14:37:27,624] Timeline: Track finished, removing from scheduler (total tracks: 1)
[2022-03-17 14:37:35,014] Timeline: Track finished, removing from scheduler (total tracks: 0)
[2022-03-17 14:37:35,014] Timeline: Finished
I found a workaround which is to pre-iterate through dur:
dur = iso.PSequence(dur.all(), 1) # <-- workaround!
When I uncomment that line, the tracks finish in the same millisecond:
[2022-03-17 14:52:35,214] Timeline: Scheduled new track (total tracks: 1)
[2022-03-17 14:52:35,214] Timeline: Scheduled new track (total tracks: 2)
[2022-03-17 14:52:35,214] Timeline: Starting
[2022-03-17 14:52:46,046] Timeline: Track finished, removing from scheduler (total tracks: 1)
[2022-03-17 14:52:46,046] Timeline: Track finished, removing from scheduler (total tracks: 0)
[2022-03-17 14:52:46,046] Timeline: Finished
But I am wondering why this happens. I looked at the code for PScaleLinLin and PMap which it calls, but nothing jumps out at me. It seems that when the PScaleLinLin pattern is iterated "live" (while scheduled on the timeline) something happens and it finishes early.
Not a huge deal since I have a workaround but thought it was worth reporting, and I'm curious what this turns out to be.
I'm on an M1 Mac Mini running macOS 12.3/Monterey and Python 3.10.2 (native ARM build) and the latest version of isobar from PyPI (0.1.1) (but it also happens when I install the latest version from GitHub).
Here is the full script:
#!/usr/bin/env python3
import isobar as iso
import logging
logging.basicConfig(level=logging.INFO, format="[%(asctime)s] %(message)s")
patnotes = [74, 1, 76, 76, 52, 30, 83, 13, 97, 9]
pat = iso.PSequence(patnotes, 1)
dur = iso.PScaleLinLin(pat, min(patnotes), max(patnotes), 0.2, 1.2)
# dur = iso.PSequence(dur.all(), 1) # <-- workaround!
rpat = iso.PReverse(pat.copy())
rdur = iso.PReverse(dur.copy())
# all have the same length:
print(len(pat))
print(len(dur))
print(len(rpat))
print(len(rdur))
timeline = iso.Timeline(40)
timeline.stop_when_done = True
timeline.schedule(dict(
note=pat,
duration=dur,
amplitude=100,
gate=1,
channel=0
))
timeline.schedule(dict(
note=rpat,
duration=rdur,
amplitude=100,
gate=1,
channel=0
))
try:
timeline.run()
except KeyboardInterrupt:
timeline.output_device.all_notes_off()
Below is a script that is meant to do something simple:
pat) from 10 hardcoded notes with repeats=1dur) using PScaleLinLin to scale the notes inpatto the range 0.2 to 1.2rpatandrdur)patnotes to play for durationdurrpatnotes to play for durationrdurYou would expect both tracks to finish at the same time, because the sums of
durandrdurare the same forwards or backwards. But the first track finishes well before the second, as you can hear and see from the logging messages:I found a workaround which is to pre-iterate through
dur:When I uncomment that line, the tracks finish in the same millisecond:
But I am wondering why this happens. I looked at the code for
PScaleLinLinandPMapwhich it calls, but nothing jumps out at me. It seems that when the PScaleLinLin pattern is iterated "live" (while scheduled on the timeline) something happens and it finishes early.Not a huge deal since I have a workaround but thought it was worth reporting, and I'm curious what this turns out to be.
I'm on an M1 Mac Mini running macOS 12.3/Monterey and Python 3.10.2 (native ARM build) and the latest version of isobar from PyPI (0.1.1) (but it also happens when I install the latest version from GitHub).
Here is the full script: