Pspawner Communication and Conditionals

Hi,

Can two different Pspawners understand each other? (not to get philosophical…)

I have ~spawnerA and ~spawnerB

I’d like to do something like (~spawnerA stop).if{~spawnerB stop}{~spawnerB loop}

Because I am exporting them as separate channels later I need them in their own Pspawner.
Assume ~spawnerA is of an indeterminate length.

edit:

I’ve managed to get them to talk to each other by calling isPlaying in a conditional statement but now I have an issue of synchronicity.

~spawnerB will always generate an additional event to check ~spawnerA. I’d like it to be a dead stop, when A is done B executes a stop command.

Is presented below the best solution?

a = Pseq([0.125],1);

(
~spawnerA = Pspawner({

	|sp|

	1.do{
		sp.seq(
			Pbind(
				\instrument,\whiteNoiseRaw,
				\node,0,
				\dur, 0.125,
				\amp, 0.5,
		));
	}
}).play;

~spawnerB = Pspawner({

	|sp|


	loop{

		sp.seq(

			Pbind(
				\instrument,\sineTone,
				\freq,500,
				\node,2,
				\rel,1,
				\sus,Pkey(\rel),
				\dur,0.125,
				\amp,0.5,
				\condition, Pfunc{ if(~spawnerA.isPlaying == false, {~spawnerB.stop},{"is playing".postln})},
		));
	};
}).play;
)

Thanks,

MJ

The question here actually contains a clue pointing to another solution.

Written this way, spawnerB indeed needs to evaluate the Pbind in order to reach the condition… but the condition can choose to prevent the event from being generated!

As originally written, the condition has a value for both branches: either B’s event stream player, or a string. So Pbind has to embed one or the other into the event (and return the event, which you don’t want).

\condition, Pfunc{
    if(~spawnerA.isPlaying == false) {
        ~spawnerB.stop
    } {
        "is playing".postln
    }
}

But if the “stop” branch returns nil, then Pbind says, “oh, this subpattern is done… so I’m done too.” And then it stops by itself. (I’ll also reverse the condition to make it a little shorter.)

\condition, Pfunc{
    if(~spawnerA.isPlaying) {
        "is playing".postln  // or just 0, anything non-nil
    } {
        ~spawnerB.stop;
        nil  // here, suppress the output event
    }
}

If this is the only pattern running in the spawner, you can do without ~spawnerB.stop; – but if there are other patterns running by sp.par then you do need to force the whole spawner to stop.

hjh

Fantastic, thank you!

For posterity, I was running into some trouble at first as I was calling nil inside this loop structure which caused the server to hang. Removing the loop{} or creating a fixed length iteration with .do resolved the server hang and terminated the stream as expected. Thank you again!

~spawnerB = Pspawner({
	
	|sp|
	
	\\this loop
	loop{
		
		sp.seq(
			
			Pbind(
				\instrument,\default,
				\freq,500,
				\dur,Pseq([0.125],1),
				\amp,0.5,
				\condition, Pfunc{ 
					if(~spawnerA.isPlaying) {
						"is playing".postln;
						
					} {
						~spawnerB.stop;nil
						
					}
				},
				
		));
	};
}).play;

This worked as expected

~spawnerB = Pspawner({
	
	|sp|
	
	
		sp.seq(
			
			Pbind(
				\instrument,\default,
				\freq,500,
				\dur,0.125,
				\amp,0.5,
				\condition, Pfunc{ 
					if(~spawnerA.isPlaying) {
						"is playing".postln;
						
					} {
						~spawnerB.stop;nil
						
					}
				},
				
		));

}).play;

best,

MJ

Oh, I see.

You could replace loop { ... } with while { ~spawnerA.isPlaying } { ... } – so, if ~spawnerA stops, then ~spawnerB would not do sp.seq anymore. (The issue being that your intention was not actually an infinite loop – the loop should have an exit condition – so, the way that the loop is written should reflect the exit condition – namely, while.)

hjh

1 Like

Thank you again! When and how to use while has escaped me, and this is a great reference

MJ