Conditionally select a pbind with another pattern

Ive been trying to think about how to conditionally switch between an array Pbinds/Pdefs in a sequence. This simple approach works quite well, by putting each one in a Ppar and setting the event to Rest if it doesn’t match the index

(
~pChainSwitch = {|patt, switch|
    var patternList = List.new;
    patt.do({|elem, i|
        patternList.add(
            Pbind(
                \switch, switch,
                \switchIdx, i,
                \dur, Pfunc({|ev|
                    var val;
                    if(ev[\switchIdx] == ev[\switch]){ val = ev[\dur]}{ val = Rest(ev[\dur]) };
                    val
                })
            )
            <> elem
        );
    });
    Ppar(patternList, inf);
};
    
    a = Pbind(\instrument, \default, \dur, 1);
    b = Pbind(\instrument, \default, \degree, Prand([1,3,4,5], inf), \octave, 4, \dur, 0.5);
    c = Pbind(\instrument, \default, \degree, Prand([2,5,7,8], inf), \octave, 6, \dur, 1);
    
    ~pChainSwitch.([a, b, c], Pseq([1, 0, 1, 2], inf)).trace.play(t);
)

However, I’d like to be able to do something like:

    Pdef(\p1,
        ~pChainSwitch.([a, b, c], Pkey(\seq), inf))
        <> Pbind(\seq, Pseq([1, 0, 1, 2], inf)
    ).trace.play(t);

…and set the the index from a key downstream. I think I can see why it doesn’t work but I’m not sure how to change the design to allow for this - any ideas?

There are a couple of ways to think about that:

  • Conditionally switching the evaluation of Pbinds (that is, decide which one of them you want, and then evaluate only that one);
  • Or, conditionally switch between the events produced from Pbinds (evaluate all the Pbinds, all the time, and suppress the events from the ones that shouldn’t play).

The first approach already has native objects for it.

// using numeric indices
Pswitch1([
	Pbind(\instrument, \default, \dur, 1),
	Pbind(\instrument, \default, \degree, Prand([1,3,4,5], inf), \octave, 4, \dur, 0.5),
	Pbind(\instrument, \default, \degree, Prand([2,5,7,8], inf), \octave, 6, \dur, 1)
], Pkey(\seq))

// or, using symbolic keys
Psym1(Pkey(\seq), (
	a: Pbind(\instrument, \default, \dur, 1),
	b: Pbind(\instrument, \default, \degree, Prand([1,3,4,5], inf), \octave, 4, \dur, 0.5),
	c: Pbind(\instrument, \default, \degree, Prand([2,5,7,8], inf), \octave, 6, \dur, 1)
))

Your code example reflects the second approach. The problem here is that Ppar produces multiple events for the same moment in time (some with delta == 0), and every one of those events evaluates the Pbind(\seq). You’re assuming that at a given beat, \seq will stay the same, but it doesn’t.

I think that the \seq pattern needs to be timed, perhaps like:

    Pdef(\p1,
        ~pChainSwitch.([a, b, c], Pkey(\seq), inf))
        <> Pbind(\seq, Pstep(Pseq([1, 0, 1, 2], inf), 1, inf))
    ).trace.play(t);

… so that, in one beat, there is a consistent value for \seq, and then a different consistent value for it in the next beat, and so on.

hjh

1 Like

Oh wow I didnt realise there was Pswitch1 or Psym1! Thanks for the tip