Hi everyone,
I’d like to share a new question that’s come up as a result of the experiments I’ve been conducting on synchronization.
This post is somewhat related to the other two (link and link) I wrote recently on the topic of synchronizing audio file playback with patterns. Today I’ll try to break the problem down into smaller parts and address the one that’s been giving me the most trouble lately.
In short, we have a sort of score, consisting of patterns that are played upon receiving an OSC message. The score can also be interrupted by receiving another OSC message.
The base code is as follows:
// 1) boot the server
s.boot;
// 2) define part (and its internal components)
(
~intro_bars = 4;
~p_pause = Pbind(
\instrument, \default,
\degree, Pseq([\rest], inf),
\dur, Pseq([4], 1),
\amp, 1.0,
\callback, Pfunc({ |e|
"bar %: one bar pause\n".postf(t.bar.asInteger);
})
);
~p_melody = Pbind(
\instrument, \default,
\root, 0,
\scale, Scale.major,
\degree, Pseq( (0..7), 1),
\dur, 4,
\octave, 5,
\amp, 1.0,
\legato, 0.9,
\callback, Pfunc({ |e|
e.use{
"playng note %\n".postf( ~degree )
}
})
);
~my_part = Pseq([
Pseq([~p_pause], ~intro_bars),
Pseq([~p_melody], 1)
], 1).asEventStreamPlayer;
);
// 3) define the address where to send OSC messages
~my_addr = NetAddr("127.0.0.1", 15600);
// 4 ) define OSC message receivers
(
OSCdef( \start, {
| msg, time, addr, recvPort |
t = TempoClock.new(110/60);
~my_part.reset.play(t, quant:Quant(1, 0, 0));
}, "/player/start/", recvPort: ~my_addr.port );
OSCdef( \stop, {
| msg, time, addr, recvPort |
~my_part.stop;
}, "/player/stop/", recvPort: ~my_addr.port );
);
Now I can execute the score by evaluating the following line
~my_addr.sendMsg("/player/start/");
The output in the post window is as follows (as I expected):
bar 0: one bar pause
bar 1: one bar pause
bar 2: one bar pause
bar 3: one bar pause
playng note 0
playng note 1
playng note 2
playng note 3
playng note 4
playng note 5
playng note 6
playng note 7
During execution, I can always pause the playback by evaluating the line:
~my_addr.sendMsg("/player/stop/");
or by using the line ~my_addr.sendMsg(“/player/start/”); again to restart playback (on a new TempoClock).
So I tried evaluating the two lines simultaneously in this form:
(
~my_addr.sendMsg("/player/stop/", 0);
~my_addr.sendMsg("/player/start/", 1);
)
but I get results that are hard to interpret.
If I run these lines quickly, say twice, I get an output like this:
bar 0: one bar pause
bar 0: one bar pause
bar 1: one bar pause
bar 1: one bar pause
playng note 0
playng note 1
playng note 2
playng note 3
playng note 4
playng note 5
playng note 6
playng note 7
If I do the same thing by evaluating the lines repeatedly—this time three times—I get something like this:
bar 0: one bar pause
bar 0: one bar pause
bar 0: one bar pause
bar 1: one bar pause
playng note 0
playng note 1
playng note 2
playng note 3
playng note 4
playng note 5
playng note 6
playng note 7
And the musical notes play out of sync or in some other unexpected way. I would have expected the pattern to stop and start over, just as it did when the lines were evaluated separately.
Why is this happening?
The only way I’ve found to work around this problem is to let a little time pass between the pattern stopping and the new playback starting.
However, this is not the ideal situation because, in actual use—especially during the initial fine-tuning phase—it is necessary to be able to stop the execution and start over immediately, and to do so repeatedly.
I’m convinced that this approach to the design requirement isn’t the best method, but I thought it was certainly one of the possible methods, and I’d like to explore it further. I think the issue I’m facing has to do with pattern scheduling, but I’m not sure how to proceed.
I’m also not entirely convinced about reassigning a new TempoClock to the variable t every time I receive a start message (where does the old TempoClock go? Couldn’t that create conflicts?).
However, it’s the only way I’ve found to “reset” the TimeClock and start it over from the beginning (start counting beats from zero at an arbitrary and unpredictable point in time).
Do you have any other suggestions?
Thank you so much for your support