Hi all!

How do people do multichannel stuff?

To start with - say if I've got 4 channels, then I want d1 to go to 1st channel, d2 to go to 2nd, d3 to 3rd, etc...?

And i guess it would be much harder to spatialise it, so for example to have d1 moving around the room/through the different channels at different points..?

Thanks in advance!

1 Like

Firstly, you'll want to look at separating audio outputs in superdirt and supercollider, as per:

Then you can use # orbit to choose your stereo output pairs - orbit is patternable as it turns out, so this puts output on a different stereo pair each cycle:

# orbit "<0 1 2>"

Then just route your sc outputs wherever you want them to appear

1 Like

Hey thanks.

I'm getting it ready to use 16 speakers - this is what I've done, could you check it please? These lines are what I've changed from the supercollider startup file

s.options.numOutputBusChannels = 16;

~dirt = SuperDirt(16, s);

~dirt.start(57120, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);

So then I run this, if I wanted to send one pattern the first speaker I would write # orbit "0.0625"

then say if I wanted to send another pattern to the 12th speaker, I would write # orbit "0.75"

...if my maths is right?

Thanks again!

I initially thought this is more complicated than it needs to be, but by the end of this post I realised there were a few ways to skin this cat :wink: - here's what I initially thought you would do:

Option 1:
Inside s.reboot {

s.options.numOutputBusChannels = 16;

Then inside s.waitForBoot:

// leave this at 2 (stereo channel per orbit)
~dirt = SuperDirt(2, s); // two output channels, increase if you want to pan across more channels
~dirt.start(57120, [0, 2, 4, 6, 8, 10, 12, 14] );   // start listening on port 57120, create 8 stereo busses

then you have # orbit 0..7 each with a stereo pair of speakers (use # pan [0|1] to access individual speakers.

Option 2:
realistically, another option would be to make each orbit a single speaker, might look like:
leave sc output channels at 16 -> inside s.waitForBoot:

~dirt = SuperDirt(1, s); // mono output channel
~dirt.start(57120, [0,1, 2,3, 4,5, 6,7, 8,9, 10,11, 12,13, 14,15] );   // start listening on port 57120, create 16 mono busses

Then you use # orbit 0..15 to access each individual speaker, # pan does nothing

Option 3:
then of course you could use a single orbit with 16 speakers which is what I think you've proposed. sc output channels stay at 16 -> inside s.waitForBoot:

~dirt = SuperDirt(16, s); // 16ch output
~dirt.start(57120, [0] );   // start listening on port 57120, create 16 mono busses

Then you use # orbit 0 to access the bank of speakers, and use divisions of 1/16 in # pan to access each individual speaker

Disclaimer: all of this is wholly untested - without knowing exactly what your plan is,it's hard to say which would work best but I feel like option 3 might be most flexible (I'm not sure if you can specify a pattern to play on multiple orbits for example, which you'd need to pan smoothly I think)

Ok, I will try all these and get back to you. I only have 1 hour in the spatial sound lab tomorrow to test it out so just wanted to pre empt some of my confusion......... Thank you so much

So with the option 3 as you wrote - not quite sure the difference between pan and orbit

are you saying to do the following to send this pattern to the 2nd speaker only (if my maths is right? 0 is first speaker, so second speaker is 0.0625?) -

d1 $ s "bd*8" # pan 0.0625

then I don't understand where # orbit 0 comes in?

Sorry if this is tedious, I'm very inexperienced with sound terms / speaker technical jargon & set ups etc. In absolute laymans terms would be great

yeah - here's a tip though, don't worry about your maths and use fractions for readability

d1 $ s "bd*8" # pan (1/16)

pan through the full range of speakers (adjust the fractions if you want to limit the speakers)

d1 $ s "bd*8" # pan (range (0/16) (16/16) (slow 8 saw))

a new and undocumented-ish feature in current tidal - using panbus on a long sample (note it goes from -1 to 1 instead of 0 to 1) so that it will pan even though you're only playing an event once every 4 cycles:

    $ s "[bev/4]"    
    # panbus 1 (range (-8/8) (8/8) (slow 4 saw))   
    # legato 1

well, this is where my lack of experience/knowledge with this comes in -
In a default setup, an orbit refers to a pair of stereo channels, there are multiple orbits which effectively map directly to each dN $
The orbits allow global effects (such as delay, reverb) to be applied in different amounts to different orbits.
In the config we've setup though, there is only a single orbit - I don't know if tidal will definitely just loop on the single available orbit, or whether it will send to non-existent orbits (I'd expect it'll do the former), but by defining # orbit 0 it was like a safeguard that it will go exactly where you wanted it to

Yes this would work fine. If you want to send a sound to a particular speaker by number without doing the maths, you can also use channel, e.g. d1 $ sound "bd" # channel "5" to go to the sixth speaker (since it starts counting from 0).

You can test this without having to be on an actual multichannel system. Just start superdirt with these settings and open a scope (click on numbers on bottom right, and "show scope"). Then run something like this and you should see the kick move around: d1 $ channel "0 .. 15" # sound "bd"

Because bd is a stereo sample, it will play across adjacent channels. There should be a way to handle how stereo samples are played but I think it's a bit buggy:

I wouldn't worry too much about orbits. With the above config you are creating 18 but you could stick with the usual 12 (which are assigned from d1 to d12) by replacing the dirt.start line with ~dirt.start(57120, 0 ! 12); (which would be the same as having twelve zeroes). That's a bit less resource intensive. You could reduce the number of orbits as cleary says if you have problems with cpu usage but I think the usage is low, and then you will have problems with using reverb and delays.

1 Like

Looking at option 3, which is 16 channel output with orbit 0 and pan aware to access bank of speakers, and option 2, mono output channel, Is it possible to have both, where i can send discrete output through one speaker and have a pan aware orbit, and toggle between the two?

Also on panning, is it possible to reduce the width of the source such that superdirt doesn't spread the audio across too many speakers? I remember looking through old threads of superdirt panning in the past and it didn't seem to be resolved.

Short answer is, I don't know I'm afraid. I don't have access to anything to test so everything I've posted to this point is purely a guess, I'm not comfortable extrapolating those guesses further

I think you can't vary the number of channels to pan between per orbit, but can send to a single channel as I described earlier.

There's some discussion of the parameters available to control pan width / splay etc here:

It'd be great if you could join the thread there if you have trouble or success.. When I get access to multichannel systems there's never enough time to work through it properly. I did get to work on a multichannel system last week but ended up using 7 raspberry pis outputting 2 channels each :slight_smile:

One of the problems is with the idea of stereo. Since samples are recorded in stereo, and playback is meant to be stereo on two speakers, once there's more than 2 speakers, it's difficult to decide how to split the 2 stereo sources across multiple speakers. Outside of supercollider, one way i've tried to get past that is to use a surround sound bed and place these two speakers as sound sources within that bed. And to pan would be to move those sound sources within the bed itself. That way option 1, which is the default works out of the box and panning would be to tie the positional parameters into tidalcycles for patterning.

1 Like

It might be total overkill, but I know that there are good plugins for ambisonics or spatialization on SuperCollider: It might be possible to adapt these to SuperDirt.

1 Like

@mmmoth On that issue we discuss pan width/splay for dealing with samples containing more than one channel.
@raph there's an issue exploring ambisonics here

I thought i'd just note this down here. If any audio effect is applied to a B format encoding, there's a chance it will alter the spatialization. IIRC trond lossius recommends applying effects to A format first. There's the IEM plugins which have omni/multi versions of compressors and reverb, and i assume those take this into account or i've been using those wrong.