Feedback FM Cross-Modulation with Granulation

hey, im trying to implement feedback fm crossmodulation together with granulation via Impulse / PulseDivider / Sweep for the grain windows and therefore creating numChannels * 2 LocalIn channels and route (0…4) channels to sigs and (5…9) channels to mods. Afterwards im just using sigs multiply it by the grainwindows, pan the grains and sum them to get a stereo output signal.
It seems to work but im not sure about [mods, sigs].flat and the routing of the channels? is this correct? thanks.
In my implementation freqsA and freqsB are both a multichannel demand signal with numChannels.

var numChannels = 5;

var fbIn = LocalIn.ar(numChannels * 2);

var fbInA = (numChannels..numChannels * 2 - 1).collect{ |chan| fbIn[chan] };
var fbInB = (0..numChannels - 1).collect{|chan| fbIn[chan] };

var mods = SinOsc.ar(freqsA + (fbInA * modA));
var sigs = SinOsc.ar(freqsB + (fbInB * modB));

LocalOut.ar([mods, sigs].flat);

sigs = sigs * grainWindows;

sigs = PanAz.ar(2, sigs);
sigs = sigs.sum;

You want to use mods as your modulator of sigs, not fbInA. Then you want to use LocalOut to only feed back sigs to modulate mods.

Right? In the standard chain, mods can modulate sigs because it is upstream, so do that. sigs cannot modulate mods because it is downstream. That one needs to feed back.

Sam

thank you very much, so this is correct?

fbIn = LocalIn.ar(numChannels);

mods = SinOsc.ar(freqsA + (fbIn * modA));
sigs = SinOsc.ar(freqsB + (mods * modB));

LocalOut.ar(sigs);

sigs = sigs * grainWindows;

i have been trying to implement this example

with the difference that i have a multichannel signal and a multichannel modulator instead of using two LocalIn channels and fbIn.reverse.

I think you could rewrite this example:

(
Ndef(\xfm, { arg freqA = 32, freqB = 9, modAtoB=540, modBtoA=240;
	var fbIn = LocalIn.ar(2);
	var sigs = SinOsc.ar([freqA, freqB] + (fbIn.reverse * [modBtoA, modAtoB]));
	LocalOut.ar(sigs);
	sigs * 0.5;
}).play;

Spec.add(\freqA, [1, 10000, \exp]);
Spec.add(\freqB, [1, 10000, \exp]);
Spec.add(\modBtoA, [0, 1000, 5]);
Spec.add(\modAtoB, [0, 1000, 5]);

Ndef(\xfm).gui;
)

like that:

(
Ndef(\xfm, { arg freqA = 32, freqB = 9, modAtoB=540, modBtoA=240;
	var fbIn = LocalIn.ar(2);
	var sigs = [
		SinOsc.ar(freqA + (fbIn[1] * modBtoA)),
		SinOsc.ar(freqB + (fbIn[0] * modAtoB))
	];
	LocalOut.ar(sigs);
	sigs * 0.5;
}).play;

Spec.add(\freqA, [1, 10000, \exp]);
Spec.add(\freqB, [1, 10000, \exp]);
Spec.add(\modBtoA, [0, 1000, 5]);
Spec.add(\modAtoB, [0, 1000, 5]);

Ndef(\xfm).gui;
)

which should not be different when dealing with multichannel signals and granulation from this:

fbIn = LocalIn.ar(numChannels * 2);

fbInA = (numChannels..numChannels * 2 - 1).collect{|chan| fbIn[chan] };
fbInB = (0..numChannels - 1).collect{|chan| fbIn[chan] };

sigs = [
	SinOsc.ar(freqsA + (fbInA * modA)),
	SinOsc.ar(freqsB + (fbInB * modB))
];

LocalOut.ar(sigs.flat);

sigs = sigs[1] * grainWindows;

or my initial example:

var fbIn = LocalIn.ar(numChannels * 2);

var fbInA = (numChannels..numChannels * 2 - 1).collect{ |chan| fbIn[chan] };
var fbInB = (0..numChannels - 1).collect{|chan| fbIn[chan] };

var mods = SinOsc.ar(freqsA + (fbInA * modA));
var sigs = SinOsc.ar(freqsB + (fbInB * modB));

LocalOut.ar([mods, sigs].flat);

sigs = sigs * grainWindows;

or am I wrong?