[bug] Pfunc returning a reused Event gets "stuck"

This seems wrong to me.

(
var last = 0;
e = (type: \rest, dur: 1);
p = Ppar([
	Pfunc {
		(thisThread.clock.beats - last).postln;
		last = thisThread.clock.beats;
		e.put(\dur, exprand(0.1, 5)).debug("yielding")
	}
], 1).play
)

249.5030743  // first value is junk

yielding: ( 'type': rest, 'dur': 1.3232252066859 )
1.3232252066859  // matches last yielded dur

yielding: ( 'delta': 1.3232252066859, 'dur': 1.2520146424567, 'type': rest, 'server': localhost )
1.3232252066859  // uhm... I overwrote \dur, why is it using the old dur?

yielding: ( 'delta': 1.3232252066859, 'dur': 0.29091392633264, 'type': rest, 'server': localhost )
1.3232252066859  // and that continues

Yeah, I know, I shouldn’t reuse the Event here. But I’d have assumed it would use the last given value and I have no idea how it’s getting latched into old data – except that it’s something in Ppar.

hjh

It seems like adding an arg to Pfunc solves it, even though the name of the arg is unrelated to the rest of the code, here using ‘ev’ which is not used elsewhere. I have no idea why, just an observation.

(
var last = 0;
e = (type: \rest, dur: 1);
p = Ppar([
	Pfunc {|ev|
		(thisThread.clock.beats - last).postln;
		last = thisThread.clock.beats;
		e.put(\dur, exprand(0.1, 5)).debug("yielding")
	}
], 1).play
)

yielding: ( 'delta': 0.9976023755152, 'dur': 0.84764440158663, 'type': rest, 'server': localhost )
0.99760237551527
yielding: ( 'delta': 0.9976023755152, 'dur': 0.81589205263499, 'type': rest, 'server': localhost )
0.99760237551527
yielding: ( 'delta': 0.9976023755152, 'dur': 1.0318768187614, 'type': rest, 'server': localhost )

Except that the Pfunc body generates a new dur for every event, and the “add an arg” approach ignores that and has the same dur for every event.

Ppar must be copying the event somewhere internally and then not handling identical events properly… but I don’t have time to dig into it.

One of those where I thought “I can save a bit of garbage collection load by reusing an event object” and then a zero duration burned me pretty hard. At least 20 minutes and multiple force-quits of the interpreter to find out where the problem was.

hjh

Ok, I think I understand now. If for instance dur is swapped for freq, then the pattern does update the freq, whereas in your example the dur key is not updated. I was surprised that it worked with the freq key, I did not not know that ‘e’ is played with this syntax, I just expected it to update e not play the values in e. Is this kind of pattern pattern behavior described anywhere in the help files?

The only type of pattern that can be played is an event pattern (a pattern that yields events). Each event returned from an event pattern will be played.

A Pfunc that returns events is an event pattern. So there is no reason to expect that events from a Pfunc would not be played.

Sometimes pattern usage “fetishizes” Pbind a bit, in the sense that we sometimes think playing a Pbind is different from playing other types of patterns, but there’s nothing special about Pbind. An event produced by Pbind is no different from an equivalent event written directly in a Pfunc, and the calling EventStreamPlayer has no way to distinguish the source that produced the events – so the syntax that produced the events doesn’t matter.

That’s interesting, that freq changes per event but dur doesn’t. Will ponder tomorrow.

hjh

I think this happens because Ppar overwrites each event’s \delta in order to merge streams and maintain correct timing. The problem goes away if you use \delta instead of \dur:

(
var last = 0;
e = (type: \rest, delta: 1);
p = Ppar([
	Pfunc {
		(thisThread.clock.beats - last).postln;
		last = thisThread.clock.beats;
		e.put(\delta, exprand(0.1, 5)).debug("yielding")
	}
], 1).play
)
1 Like

Ah yes, it’s got to be that – overriding delta so that it doesn’t look at dur again.

If I have time later, I’ll add a note to the docs.

Thanks for the analysis – I had been doing code integration for a couple hours before that and was just tired, appreciate the extra pair of eyes.

hjh