Multichannel BufRd / BufWr for feedback granulation

hey, im creating a multichannel Playbuf here multiplied by a window function for granulation before i sum the signals and route the stereo signal to a fx bus. The fx itself is based on a feedback loop created by GrainBufJ and BufWr and i thought because this is granulation again that you could get rid of the GrainbufJ inside the fx and just use multichannel Playbuf / BufRd from the source multiplied by the window function and feed it into a multichannel BufWr before you sum the signals.
Can you help me on that?

(
var timingInformation = { |numChannels, trig, grainRate|
	var arrayOfTrigsAndPhases = numChannels.collect{ |i|
		var localTrig = PulseDivider.ar(trig, numChannels, i);
		var hasTriggered = PulseCount.ar(localTrig) > 0;
		var localPhase = Sweep.ar(localTrig, grainRate * hasTriggered);
		[localTrig, localPhase];
	};
	var trigsAndPhasesArray = arrayOfTrigsAndPhases.flop;
	(\trigger : trigsAndPhasesArray[0], \phase: trigsAndPhasesArray[1]);
};

var hanningWindow = { |phase|
	(1 - (phase * 2pi).cos) / 2 * (phase < 1);
};

SynthDef(\grains, { |sndBuf|

	var numChannels = 8;

	var tFreq = \tFreq.kr(10);
	var trig = Impulse.ar(tFreq);
	var grainRate = tFreq / \overlap.kr(1);

	var timings = timingInformation.(numChannels, trig, grainRate);
	var grainWindows = hanningWindow.(timings.phase);

	var pos = Phasor.ar(
		trig: 0,
		rate: \posRate.kr(1) * BufRateScale.kr(sndBuf) * SampleDur.ir / BufDur.kr(sndBuf),
		start: \posLo.kr(0),
		end: \posHi.kr(1)
	);

	var sig = PlayBuf.ar(
		numChannels: 1,
		bufnum: sndBuf,
		rate: \playBackRate.kr(1),
		trigger: timings.trigger,
		startPos: pos * BufFrames.kr(sndBuf),
		loop: 1
	);

	sig = sig * grainWindows;

	sig = Pan2.ar(sig, \pan.kr(0));
	sig = sig.sum;

	sig = sig * \amp.kr(-25.dbamp);

	sig = LeakDC.ar(sig);
	OffsetOut.ar(\out.kr(0), sig);
}).add;

SynthDef(\granular_fx, {

	var tFreqMod = SinOsc.ar(\tFreqMF.kr(1), Rand(0.0, 2pi)) * \tFreqMD.kr(0);
	var rateMod = SinOsc.ar(\rateMF.kr(1), Rand(0.0, 2pi)).range(0, \rateMD.kr(0));
	var offsetMod = SinOsc.ar(\offsetMF.kr(1), Rand(0.0, 2pi)).range(0, \offsetMD.kr(0));

	var tFreq = \tFreq.kr(20) + tFreqMod;
	var rate = \rate.kr(1) - rateMod;

	var trig = Impulse.ar(tFreq);
	var grainDur = max(\overlap.kr(1) / tFreq, \minGrainDur.kr(0.001));

	var bufFrames = 2**16;
	var sndBuf = { LocalBuf(bufFrames).clear } !2;

	var writePos = Phasor.ar(DC.ar(0), end: bufFrames);
	var readPos = (writePos - ControlDur.ir / bufFrames - \offset.kr(0) - offsetMod).wrap(0, 1);

	var inSig = In.ar(\in.kr(0), 2);

	var sig = GrainBufJ.ar(
		numChannels: 1,
		loop: 1,
		trigger: trig,
		dur: grainDur,
		sndbuf: sndBuf,
		rate: rate,
		pos: readPos,
		interp: 4,
		pan: 0,
		envbufnum: -1,
	);

	sig = HPF.ar(sig, \hpf.kr(40));
	sig = LPF.ar(sig, \lpf.kr(15000));

	// writing granulated + input back to grain buffer
	sndBuf.do { |b, i|
		BufWr.ar(sig[i] * \feedback.kr(0.3) + inSig[i], b, writePos)
	};

	sig = XFade2.ar(inSig, sig, \mix.kr(0).linlin(0, 1, -1, 1).lag(3));

	sig = sig.tanh;

	OffsetOut.ar(\out.kr(0), sig);
}).add;
)

// loadd soundfile into buffer
b = Buffer.read(s, Platform.resourceDir +/+ "sounds/a11wlk01.wav");

// create bus for fx routing
~fxBus = Bus.audio(s, 2);

(
Routine({

	s.bind {

		Synth(\grains, [

			\tFreq, 1000,
			\overlap, 8,
			\sndBuf, b,

			\amp, -25.dbamp,
			\out, ~fxBus,

		], addAction: \addToHead);

	};

	s.sync;

	// fx
	s.bind {

		Synth(\granular_fx, [

			\in, ~fxBus,

			\overlap, 2,

			\tFreq, 26.60,
			\tFreqMF, 25.10,
			\tFreqMD, 0.0,

			\rate, 2.0,
			\rateMF, 19.80,
			\rateMD, 1.0,

			\offset, 0.042,
			\offsetMF, 94,
			\offsetMD, 0.11,

			\lpf, 14000,
			\hpf, 500,

			\mix, 1,
			\feedback, 0.35,

		], addAction: \addToTail);
	};

}).play;
)
1 Like