Live

Spatialisation — sound placed in space

A circle drawn in the score is the room. Objects moving inside it are sound sources: on a path (o2p), by hand (controlXY), or both. Oscilla works out where each source is — azimuth, elevation, distance — and sends it over OSC, about 30 times a second. Something else pans the sound: SuperCollider or Pd (both ready-made, in the demos), or any renderer that takes positions over OSC.

SuperCollider / Pd ← OSC: where each source is ← Oscilla (the score) ↓ the speakers: a quad, a dome, the IEM CUBE …

Oscilla sends position only; no sound passes through it.


Oscilla sends to UDP port 57120 by default (sclang's port; --osc-out changes it). Pd and sclang cannot both listen on 57120 — run one of them, or move one.


Writing it

A source on a path — o2p

o2p(path:orbit, uid:src1, dur:10, loop:0, spatial:plan, bounds:room, osc:1)

The object follows orbit; every frame its position on the circle room is turned into azimuth / elevation / distance and sent to /oscilla/spat/src1. With trig:touch the performer drags it along the path instead (a rail: a fixed ring of the dome, say). With drag:1, clicking it stops it and it can be dragged anywhere in the circle; clicking again sends it back to the nearest point of its path.

The keys

key
spatial: plan or dome turns it on (below)
bounds: an element id the room: a <circle>, an <ellipse> (its smaller radius) or any shape (the circle in its box). o2p without it uses its path's box
format: aed (default), ae, ad, xyz, aedg, raw what is sent (below)
elev: degrees plan mode only: the source's height (default 0, ear level). On a controlXY with a rotation handle, the handle sets it instead
osc: 1 send it (the bus channels below are published either way)
oscAddr: an address instead of /oscilla/spat/<name>. On a controlXY, the handle's id is added: oscAddr:"/room" → /room/src4

Plan or dome

spatial:plan — the listener in the middle, seen from above. The middle is here, the edge is the circle of speakers: distance 0..1. Height comes from elev:.

spatial:dome — a dome seen from above, for speakers at several heights. The middle is straight up (90°), the edge is ear level (0°); a ring halfway out is 45°. A source moving inward rises; one crossing the middle goes overhead. Distance is always 1.

Front is the top of the circle in both.


What is sent

/oscilla/spat/ azi elev dist (format:aed, all floats)

azi degrees, 0 = front, positive = left (counter-clockwise seen from above), −180..180; behind is ±180
elev degrees, 0 = ear level, 90 = straight up, −90 = below
dist 0 = the middle .. 1 = the circle (plan); 1 (dome)

This is the convention of VBAP (SuperCollider's and Pd's), the IEM plugins, ATK and Ambisonics generally. A renderer that counts azimuth the other way round (clockwise) needs -azi.

Every argument is a float, always — an azimuth of exactly 90 is sent as 90.0, not as an integer, so a receiver can match on fff.

format: arguments
aed azi elev dist
ae azi elev
ad azi dist
xyz x y z — x front, y left, z up; on the unit sphere when dist = 1
aedg azi elev dist gain (gain = 1 − dist/2: louder nearer the middle)
raw the three 0..1 values of the bus (below)

The bus

Each source also publishes three channels, 0..1, that anything in the score can follow:

channel 0 0.5 1
<uid>.azi front behind front again (counter-clockwise: 0.25 = left)
<uid>.elev below ear level straight up
<uid>.dist the middle the circle

scale(uid:ring, sx: follow(src2.dist, 0, 1, 0.9), sy: follow(src2.dist, 0, 1, 0.9)) synth(uid:pad, freq: follow(src1.elev, 200, 800))


The receivers

SuperCollider — sc/oscilla-spatial.scd

Needs sc3-plugins (for VBAP). Every new /oscilla/spat/<name> gets a source of its own, whatever the name. At the top of the file:

~layout \stereo, \quad, \octo, \dome8, \cube24 — or add your own to ~layouts: [azimuth, elevation] per speaker, in output order, azimuth positive to the left
~out the first output
~useInputs true: source n plays audio input n (in order of arrival) — an instrument, or another program's tracks (below)
~sound the test sound; replace it with your own

Position is smoothed as a direction, so a source crossing behind (179° → −179°) goes the short way. Distance becomes spread: a source in the middle sounds from every speaker, one at the edge from the nearest. ~stopAll.() silences everything.

Pd — pd/oscilla-spatial.pd

Needs the vbap external (Pd: Help → Find externals → vbap; Debian / Ubuntu: pd-vbap). Each demo's patch has that demo's speakers and its source names (src1 …) — Pd routes by name, so a new name needs a new block. The patches are generated: edit scripts/gen-oscilla-spatial-pd.py and run it, rather than editing the .pd. Replace a source's [noise~] part with your own sound or an [adc~].

Ardour (or any DAW) as the sound

The DAW keeps the material; SuperCollider places it. Set ~useInputs = true and connect the DAW's track outputs to SuperCollider's inputs (JACK / PipeWire: Ardour's track outs → SuperCollider:in_1, in_2 …): the first source heard plays input 1, and so on. Ardour's own panners are not driven by Oscilla.

Another renderer

Point oscAddr: at the address it expects, choose format:, and check which way it counts azimuth.


Speakers

Directions as Oscilla and both receivers use them (azimuth positive = left). Channel numbers are output numbers.

Quad — 1 front-left 45°, 2 front-right −45°, 3 rear-right −135°, 4 rear-left 135°.

Dome, 8 — 1–4 at ear level as the quad, 5–8 the same directions at 45° up.

IEM CUBE, 24 — 12 at ear level, 8 at about 28°, 4 at about 57°, numbered clockwise from the front:

azimuth / elevation
1–6 −0.1/−0.5, −23.7/0, −48.0/0.2, −72.3/0.3, −102.7/0.3, −138.2/−0.2
7–12 −179.7/−0.1, 138.1/−0.3, 100.6/0.2, 69.4/0, 44.6/0.1, 21.2/0.1
13–20 −22.6/27.9, −67.5/28.0, −113.8/27.6, −157.5/28.4, 156.3/28.5, 112.9/28.2, 65.0/28.1, 22.4/27.4
21–24 −46.2/56.3, −132.4/56.9, 132.7/56.7, 42.6/57.1

Worked out from the 2008 survey of the room (TU Graz, report IGMS-2008-05, in the demo's resources/), seen from the middle of the lower ring at its height. The speakers are 3.3 to 6.3 m away; VBAP does not correct for that. Check with the room's current setup before a concert.


Not done

Tip: use ← → or ↑ ↓ to navigate the docs