Note durations clipping in interactive session

I am trying to get notes to play for their full beat, and then solicit user input. But when I add the input() it clips the notes short. I tried adding run_as_server() which made things worse, explicitly adding blocking=True to the play_note() call, and forcing the issue by adding a time.sleep(1) after the play_note() but alas, all to no avail.

So, what am I missing?

session = Session().run_as_server()
...
answer = None
while answer != "quit":
    answer = None
    ...
    for note in notes:
        piano.play_note(note, 1.0, 1.0)

    answer = input("Interval: ").lower()

If I understand correctly, you’re trying to get it to play the notes sequentially (as a melody) after every user input? As you’ve discovered, the system of clocks does not expect to be paused unexpectedly for input, which is why it clips notes afterward, since it checks the time and thinks it’s way behind schedule.

The correct approach is to use run_as_server(), but then also to wrap the melody in a function and fork it. That way it has its own time stream, and the notes can block as expected:

session = Session().run_as_server()
...
answer = None
while answer != "quit":
    answer = None
    ...
    def play_melody():
        for note in notes:
            piano.play_note(note, 1.0, 1.0)
    session.fork(play_melody)

    answer = input("Interval: ").lower()
1 Like

In response to a question you asked yesterday (not via the forum) about how to make the notation look a little better, take a look at this:

from scamp import *
import random

s = Session().run_as_server()

piano = s.new_part("piano")

answer = input("Interval: ").lower()

s.start_transcribing()
while answer != "q":
    def play_melody():
        start_pitch = random.randint(40, 80)
        piano.play_note(start_pitch, 1.0, 1.0)
        piano.play_note(start_pitch + int(answer), 1.0, 1.0)
    s.fork(play_melody, schedule_at=MetricPhaseTarget(0))
    answer = input("Interval: ").lower()

s.stop_transcribing().to_score().show()

Of course, this is simpler than what you’ve been creating — I just made it play whatever half-step interval the user types as an integer. But the important part is s.fork(play_melody, schedule_at=MetricPhaseTarget(0)). The metric phase target of 0 causes it to delay until the start of the beat before playing, which makes the notation turn out nicer.

It’s not a perfect solution, of course, since it creates a little delay sometimes, but it’s workable. The better solution would be to be able to pause and restart transcribing, and I think I can add that functionality to SCAMP fairly easily when I have a moment.

1 Like

Much improved, resulting in something sane-looking. Thanks.