Sharing data within a PbindFx

I have a pattern. Inside that patter i want \lag to depend on \delTime. \lag is inside the pbindData part. \delTime is inside the fxData part. So i have to share data between those parts.

(
var rate = 1;
~rimtry = PbindFx([
	\instrument, \pBuf,
	\rate, Pseq([rate.neg,rate,rate,rate,rate,rate],inf),
	\buf, b.rimclick,
	\dur, Pseq([1/16,3/16,3/16,1/16,4/16,4/16], inf),
	\amp, 1,
	\lag, PL(\delTime),
	\stretch, 1,
	\fxOrder, 1,
	\cleanupDelay, 0.05
],
[
	\fx, \flutter,
	\flutFreq, Pseq([Pwhite(5e2, 8e2,1),Pwhite(2e3,2e3,3), Pwhite(5e2, 8e2,1)],inf),
	\delTime, Pwhite(0.05,0.06),
	\k, Pwhite(0.3,0.5),
	\amp, 1,
	\cleanupDelay, 2
]);
)

Here you can see ive tried with PL(\delTime) to share data. The result is silence. Replacing PL(\delTime) with a number, plays the pattern properly.
From what iv’e understood from the helpfiles is that PbindFx sort of treats its pbinddata and fxdata as two separate Pbinds(if there is only 1 effect). So i guess if i want to data share between pbinddata and fxdata, i need to do it the same way you’d do between two different Pbinds. I couldnt figure out how to access those two ‘indepent’ Pbinds of the PbindFx. So i made the pbinds beforehand separately, like the PbindFx helpfile describes.

(
var rate = 1;
~src = Pbind(
	\instrument, \pBuf,
	\rate, Pseq([rate.neg,rate,rate,rate,rate,rate],inf),
	\buf, b.rimclick,
	\dur, Pseq([1/16,3/16,3/16,1/16,4/16,4/16], inf),
	\amp, 1,
	\lag, 0.1,      //need to get the delTime data here somehow
	\stretch, 1,
	\fxOrder, 1,
	\cleanupDelay, 0.05
);
~fx1 = Pbind(
	\fx, \flutter,
	\flutFreq, Pseq([Pwhite(5e2, 8e2,1),Pwhite(2e3,2e3,3), Pwhite(5e2, 8e2,1)],inf),
	\delTime, Pwhite(0.05,0.06),
	\k, Pwhite(0.3,0.5),
	\amp, 1,
	\cleanupDelay, 2
);


~rimtry = PbindFx(PL(\src),PL(\fx1));
~rimtry.play;
)

However there is a problem.
This is an example from the helpfiles for sharing data between two different pbinds.

~bass = Pbind(
    \degree, Pwhite(0, 7, inf),
    \octave, 3,    // down 2 octaves
    \dur, Pwhite(1, 4, inf),
    \legato, 1,
    \amp, 0.2
).collect({ |event|
    ~lastBassEvent = event;
}).play(quant: Quant(quant: 1, timingOffset: 0.1));

Here some other pattern wants to get data from the ~bass pattern. You’d have to set the timingOffset of the Quant for this being able to happen.
The problem is that i cant do this because the PbindFx is played as a whole.
How do i share data between these two parts of the PbindFx.
Would someone please get me out of this hole, im trying to get on with my project, but something seemingly simple like this just prevents me from getting on.

ive used this function once for data sharing, maybe its useful to you:

// assist data-sharing in pbindfx creation
// pbindfx is wrapped in a private environment (Penvir)
// arguments are just pdef names
(
~pbindFx = {|srcName ... fxNames|
    // add private environment, shared between source and fxs
    Penvir(Event.new(parent:currentEnvironment),
        PbindFx(
            // source: record latest event in ~src
            *[Pdef(srcName).collect(~src=_)]
            // add all fx: they can access source event saved in ~src
            ++ fxNames.collect(Pdef(_))
        )
    )
};
)

// declare Pdefs for source and fx
Pdef(\source, Pbind(...));
Pdef(\fx1, Pbind(...));
Pdef(\fx2, Pbind(...));

// use function for data sharing
Pdef(\source_fx, ~pbindFx.(\source, \fx1, \fx2));

// and use for example:
Pif(Pfunc{ ~src.something } |==| 1, 0, 1)

Thank you, but how are you sure that you’re using data from the current event and not from the previous one? See this quote from the helpfiles about data sharing.

“Second, we have to ensure that the source pattern is evaluated before any client patterns that depend on the source’s value. The only way to do this is to schedule the source slightly earlier, because items scheduled at the same time on any clock can execute in any order. (There is no priority mechanism to make one thread always run first.) But, this scheduling requirement should not affect audio timing.”

With this setup.

(
var rate = 1;
~src = Pbind(
	\instrument, \pBuf,
	\rate, Pseq([rate.neg,rate,rate,rate,rate,rate],inf),
	\buf, b.rimclick,
	\dur, Pseq([1/16,3/16,3/16,1/16,4/16,4/16], inf),
	\amp, 1,
	\lag, Pfunc{[~flut,"lag"].postln},
	\stretch, 1,
	\fxOrder, 1,
	\cleanupDelay, 0.05
);
~fx1 = Pbind(
	\fx, \flutter,
	\flutFreq, Pseq([Pwhite(5e2, 8e2,1),Pwhite(2e3,2e3,3), Pwhite(5e2, 8e2,1)],inf),
	\delTime, Pwhite(0.05,0.06).collect{|ev| ~flut = ev; [ev,"delTime"].postln},
	\k, Pwhite(0.3,0.5),
	\amp, 1,
	\cleanupDelay, 2
);


~rimtry = PbindFx(PL(\src),PL(\fx1));
~rimtry.play(quant:1);
)

The post window shows:

[ 0.057951644659042, lag ]          //here lag takes a value from the ~flut which was assigned the last time i ran the pattern
[ 0.058572716712952, delTime ]
[ 0.058572716712952, lag ]
[ 0.056340724229813, delTime ]
[ 0.056340724229813, lag ]
[ 0.053133987188339, delTime ]
[ 0.053133987188339, lag ]
[ 0.054131323099136, delTime ]
[ 0.054131323099136, lag ]
[ 0.050507274866104, delTime ]

Where you can see lag actually uses the data from the previous event. Thats why i need the the ~fx1 being scheduled a little bit earlier. But i dont want the audio timing to change. This is normally done with Quant. Like this: p.play(quant: Quant(0,0,0.1)), p is a pattern. But i cant do that because im using PbindFx.

Hi,

from my understanding of your example you can, as it’s about a random pattern, take over the data from the source stream with a sharing construct like this:

\lag, Pwhite(0.05,0.06).collect(~lag = _)
...
\delTime, Pfunc { ~lag  }

Things become a bit more tricky if the fx pattern is not random and the fx is not applied to every source synth. In that case the fx stream is only producing the next event in case of an fx application which is defined by \fxOrder. You could work around this like in the following example with Pclutch and data sharing as above:


(
SynthDef(\source, { |out = 0, freq = 400, decayTime = 0.5,
    attackTime = 0.005, amp = 0.1, gate = 1|
    var env, sig = Decay.ar(Impulse.ar(0), decayTime, Saw.ar(freq));
    env = EnvGen.ar(Env.asr(attackTime, amp, decayTime, \lin), gate, doneAction: 2);
    Out.ar(out, sig ! 2 * env)
}).add;

SynthDef(\wah, { |out, in, resLo = 200, resHi = 5000,
    cutOffMoveFreq = 0.5, rq = 0.1, amp = 1, mix = 1|
    var sig, inSig = In.ar(in, 2);
    sig = RLPF.ar(
        inSig,
        LinExp.kr(LFDNoise3.kr(cutOffMoveFreq), -1, 1, resLo, resHi),
        rq,
        amp
    ).softclip;
    Out.ar(out, (1 - mix) * inSig + (sig * mix));
}).add;
)


(
p = PbindFx([
        \instrument, \source,
		\dur, 0.25,
        \amp, 0.2,
		
		\midinote, Pseq([Pwhite(70, 90, 1), 60, 60], inf),
		\fxOrder, Pseq([1, 0, 0], inf),
		// want to toggle between fast and slow wah-wah on every fx event (every third)
		// Normally you would write Pseq([50, 1], inf) in fx data.
		// However, if you need it in src data, then you can generate it here
		\wahFreq, Pclutch(Pseq([50, 1], inf), Pkey(\fxOrder)).collect(~wahFreq = _),
		\timingOffset, 0.1,
        \decayTime, Pseq([2, 0.5, 0.5], inf),
        \cleanupDelay, Pkey(\decayTime)
    ],[
        \fx, \wah,
        \mix, 0.7,	
		\cutOffMoveFreq, Pfunc { ~wahFreq  },
        \cleanupDelay, 0.01
    ]
);

q = p.trace.play;
)

As far as I can see, this should actually cover all cases where you would want to access data from an fx stream. A differentiated lagging doesn’t seem to be possible (my assumption at the moment), but also not necessary. That said, using \lag and \timingOffset with PbindFx is possible – and in many cases a must, e.g., in order to preserve rhythm when fxs with delay are alternating (PbindFx helpfile examples 2a, 2b).

Thank you, the sharing the data source ----> fx does seem to work instead of trying to share data fx —> source. Now both patterns use data from the same event instead of one using the data of a previous event.(I guess thats because the source pattern is always scheduled first in a PbindFx?). Simple solution, i like it, thank you.