Help with passing a value through a bus

Hello there! I am new here and need help for a supercollider class project:

I am writing a tool consisting of multiple loop pedal style recorders, each going through a different effect.
The recorders are based off the Eli Fieldstell Tutorial : Live Recording & Looping in week 4 of his intermidiate supercollider course. I think I have a good understanding of the code and my loopers work as expected. However, a problem comes up when I try to use his method of using a Sweep to set a maximum for a Phasor through a dedicated Bus. It works fine for the loopers, but when I try to use this same Bus to send the max point to a UGen within a synthDef containing GrainBuf, indicating the pos of the GrainBuf, it doesn’t seem to pick up the value.
I am struggling to understand why this is, especially since the method is very similar to the working one. My GrainBuf SynthDef Nodes are correctly placed ahead of the Sweep Nodes.
Code for the Looper:

SynthDef(\sweep, {
        var sig, trigSig;
        trigSig = In.ar(\inTrig.ir(0), 1); //entrée du trig bus
        sig = Sweep.ar(\trig.tr(0) + trigSig, SampleRate.ir * \run.kr(1));
        Out.ar(\out.ir(0), sig);
    }).add;
    //ptr suit le sweep et lorsque sweep est arrêté, place le maximum du phasor à la valuer du sweep (la grosseur de la boucle)
    SynthDef(\ptr, {
        var sig, max, trigSig;
        trigSig = In.ar(\inTrig.ir(0), 1);
        max = In.ar(\inMax.ir(0), 1);
        sig = Phasor.ar(\trig.tr(0) + trigSig, 1, 0, max, 0);
        Out.ar(\out.ir(0), sig);
    }).add;

Code for my own Synthdef

 SynthDef(\granSynth,{
        arg grFreq, trigRandomness, dur, durMod, rate, rateMod, pan, panSpread, amp, ptrRate, ptrMod, scrub;
        var sig, max;

        max = In.ar(\inMax.ir(0), 1);
        trigSig = In.ar(\inTrig.ir(0), 1);


        grFreq = grFreq.linexp(0.0, 1.0, 1, 500);
        dur = dur.linexp(0.0, 1.0, 0.01, 2);
        durMod = durMod.bilin(0.5, 0.0, 1.0, 0.2, 0, 2 );
        rate = rate.linexp(0.0, 1.0, 0.25, 4);
        rateMod = rateMod.linexp(0.0, 1.0, 1, 4);
        ptrRate = ptrRate.linlin(0.0, 1.0, 1, 2);
        ptrMod = ptrMod.linlin(0.0, 1.0, 0, max);
        scrub = scrub.linlin(0.0, 1.0, 0, max) ;



        trig = CoinGate.ar((1 - trigRandomness), Impulse.ar(grFreq)) + Dust.ar(trigRandomness * grFreq);

        sig = GrainBuf.ar(
            numChannels: 2,
            trigger: trig,
            dur: dur + TRand.ar(-1.0 * durMod, durMod, trig),
            sndbuf: \bufnum.ir(0),
            rate: rate * TRand.ar(1.0 / rateMod, rateMod, trig) * BufRateScale.kr(\bufnum.ir(0)),

            pos: Fold.ar(scrub + TRand.ar(-1.0 * ptrMod, ptrMod, trig), 0.0 , max), //-->> NOT WORKING**

            interp: 4,
            pan: Fold.ar((pan + TRand.ar(-1panSpread, panSpread, trig))), //voir commentaire de pos
            envbufnum: -1,
            maxGrains: 1024,
        );

        sig = sig amp.varlag(\ampLag.kr(5), -2) * \playButton.kr(0); //all effects must end with this to enable play/mute functionality

        Out.ar(\out.ir(0), sig);

    }).add;

Without reading (watching?) the tutorial… if the GrainBuf synths are reading the value of the Sweep bus using In.ar, then the GrainBuf synths should be placed later than the Sweep synth – behind, not ahead of. (Though, you could be using the word “ahead” to mean later than… it’s unclear with the given information.)

One way to make the scenario more clear would be for you to share the code that you’re using to create the synths. I don’t see an obvious problem with the SynthDefs – but for this issue, the order of nodes is critical, and that’s the one part of the puzzle you haven’t shared.

hjh

yes sorry I should have included more code. I do believe that my nodes are ordered correctly, hence my confusion. But I may be missing something there. Here is the relevant code. I included all the synth creation code as well as the group creation code but I think only a piece is relevant

Groups:

	~inputGrp = Group.new;
	~trigGrp = Group.after(~inputGrp);
	~sweepGrp = Group.after(~trigGrp);
	~ptrGrp = Group.after(~sweepGrp);
	~playGrp = Group.after(~ptrGrp);
	~recGrp = Group.after(~playGrp);
	~fxGrp = Group.after(~recGrp);
	~directOutGrp = Group.after(~fxGrp);

Synth Creation:

	
////////////**********SYNTH INIT*************/////////////
	//INPUTS
	~inputSynths = ~inputAmt.collect{
		arg index;
		Synth(
			\input, [
				\in, ~inputs[index],
				\outLoop, ~inputBus[index],
				\outDirect, ~directOuts,
				\amp, 1,
			],~inputGrp
		);
	};

	//CONTROL SYNTHS
	~fxNames.do({
		arg item;

		~fxTrigSynths.add(item -> ~inputAmt.collect{
			arg index;
			Synth(
				\trig, [
					\trig, 0,
					\out, ~fxTrigBus.at(item)[index],
				], ~trigGrp)});

		~fxSweepSynths.add(item -> ~inputAmt.collect{
			arg index;
			Synth(
				\sweep, [
					\trig, 0,
					\inTrig, ~fxTrigBus.at(item)[index],
					\out, ~fxSweepBus.at(item)[index],
					\run, 0,
				], ~sweepGrp)});

		~fxPtrSynths.add(item -> ~inputAmt.collect{
			arg index;
			Synth(
				\ptr, [
					\trig, 0,
					\inTrig, ~fxTrigBus.at(item)[index],
					\inMax, ~fxSweepBus.at(item)[index],
					\out, ~fxPtrBus.at(item)[index],
				], ~ptrGrp)});


		~fxPlaySynths.add(item -> ~inputAmt.collect{
			arg index;
			Synth(
				\play, [
					\inPtr, ~fxPtrBus.at(item)[index],
					\out, ~fxLoopBus.at(item)[index],
					\buf, ~fxBuffers.at(item)[index],
				], ~playGrp)});

		~fxRecSynths.add(item -> ~inputAmt.collect{
			arg index;
			Synth(
				\rec, [
					\inPtr, ~fxPtrBus.at(item)[index],
					\inputSig, ~inputBus[index],
					\inLoop, ~fxLoopBus.at(item)[index],
					\buf,  ~fxBuffers.at(item)[index],
					\liveAmp, 0, //set to 1 to record
					\loopAmp, 0, // 1 = overdub
				], ~recGrp)});

	});


//Init Granulator
	~fxSynths.add(\granulator -> ~inputAmt.collect{
		arg index, fxName;
		fxName = \granulator;
		Synth(\granSynth, [
			\inMax, ~fxSweepBus.at(fxName)[index],
			\bufnum, ~fxBuffers.at(fxName)[index],
			//\inTrig, ~fxTrigBus.at(fxName)[index],
			\out, ~granulatorOuts
		] , ~fxGrp)
	});
	

As you can see the granulator Synths and the Ptr Synths listen to the same sweep bus, but the value doesn’t seem to make it to the granulators. My recorders receive it since when i listen to them directly the loop correctly, which would be impossible if the phasor wasn’t receiving a max value.

For information, my implementation creates buffers for each instance of an input * each instance of an effect, hence the iterative Synth Creation.

Let me know if any additional info is needed

Agreed, yes, that looks fine.

No time to run your code, but you might also check the units of the position values. It looks like the sweep is measuring time in samples. GrainBuf’s pos input is not in samples; it’s a normalized value where 0 is the start of the buffer and 1 is the end. If max is always a whole number of samples, and it’s going to an input that expects a fraction between 0 and 1, then I can imagine two likely possibilities. One is that it would clip to 1, so every grain would wrap around to the beginning. The other is that it would take pos modulo 1.

If the Sweep unit is producing sample indices, you’d normalize that in GrainBuf by dividing by BufFrames.kr(bufnum): pos: Fold.ar(scrub + TRand.ar(-1.0 * ptrMod, ptrMod, trig), 0.0 , max) / BufFrames.kr(bufnum) (keeping all of your other logic the same, just scaling the units at the point of usage).

hjh

That was the solution, thank you very much!
I hadn’t understood that one object was counting in samples and the other in buffer position ration.
thank you!