Getting intuition for the bus argument of SoundIn

I am a bit confused about the bus argument in SoundIn. If I am using for instance a single microphone at index 1 and I pass 1 to SoundIn’ bus, I will hear the signal on the right output of my computer. If I pass in an array [1, 1], I will hear the same signal on both output channels. So is the bus argument kind of specifying where the signal should go?

Array arguments to any UGen (with a FEW exceptions that are mentioned in documentation) are expanded to an array of that UGen with single-values. So:

Foo.ar([1, 1])

is the same as:

[Foo.ar(1), Foo.ar(1)]

So, in your case, SoundIn.ar([1, 1]) is [SoundIn.ar(1), SoundIn.ar(1)] - that is, two identical SoundIn’s (a stereo pair) reading from channel 1.

And they both are auto-magically mapped to left and right speakers?! So if I would have 3 speakers and would right SoundIn.ar(1!3) I would be copying the same signal to all three outputs?

Not exactly. Generally, your outputs are read from buses 0...N (depending on the number of outs you have). So Out.ar(0, signal) would go to your first output, Out.ar(0, [left, right]) would go to the first two (presumably left and right). This is one place where an array in the second argument implicitly increments the first argument, so I think you basically Out.ar(0, [left, right]) ==> [Out.ar(0, left), Out.ar(1, right)]. Probably this is a little inconsistent now that I think about it, but it’s been this way forever.

Hmm, a key distinction here is between UGen inputs which expect a single value (most of them) and inputs which internally accept an array of values. Single-value inputs can handle arrays only by multichannel expansion; multi-value inputs don’t.

For instance, if you have a two-channel buffer, RecordBuf’s audio input should be a two-channel array and this doesn’t multichannel-expand into two RecordBufs (and shouldn’t – because two RecordBufs would both write into the left channel).

Out is a bit confusing because its bus argument is single-value – an array of buses produces multiple Out units – but the signal input behaves like RecordBuf (no expansion). Technically it’s not right to explain Out in terms of expansion because of this case: Out.ar([0, 1], [left, right]). This looks like it should put the left signal onto bus 0 and the right onto bus 1, but in reality, because the signal doesn’t distribute over the instances by mc-expansion:

Out.ar([0, 1], [left, right])
-->
Out.ar(0, [left, right]);
Out.ar(1, [left, right]);
bus 0 bus 1 bus 2
Out 0 left right
Out 1 left right
Mix left left+right right

So I think of Out’s signal input as being similar to RecordBuf’s signal input, rather than being a weird case of mc-expansion-with-bus-increment.

hjh

In has a variable output count, like PanAz &etc.

Out has a variable input count, like EnvGen &etc.

In can only read from consecutive inputs, hence SoundIn (which also takes NumOutputBuses into account).

Cheat sheet below, I guess best to draw or print these…

// In ; one two channel In, delayed by one second
DelayN.ar(In.ar(NumOutputBuses.ir, 2), 1, 1)

// In ; two single channel Ins, each delayed by one second
DelayN.ar(In.ar(NumOutputBuses.ir + [0, 1], 1), 1, 1)

// Out ; one Out summing to two buses
Out.ar(0, SinOsc.ar(440, 0) * 0.1 ! 2)

// Out ; two Outs summing to one bus each
Out.ar([0, 1], SinOsc.ar(440, 0) * 0.1)

// SoundIn ; one two channel In, delayed by one second
DelayN.ar(SoundIn.ar([0, 1]), 1, 1)

// SoundIn ; two single channel Ins, delayed by one second
DelayN.ar(SoundIn.ar([1, 0]), 1, 1)

Forgot about this point earlier…

Let’s take this…

var sig = SoundIn.ar(1 ! 3);
var eg = EnvGen.kr(... something...);

sig = RLPF.ar(sig, 1200, 0.2);

sig = sig * eg;

Now you have three channels in sig, all the same… and, as a result, three filters (all doing the same work), and three multipliers (all doing the same work).

This is inefficient.

It’s better to input what you want – if you’re reading one channel from the soundcard, then just read the one channel, and process as one channel. Then, if you want to map that single channel onto 2 or 3 or 20 outputs, do this at the output stage. It doesn’t really make sense to do output mapping at the input stage.

hjh