Canvas

Max-MSP ambisonic renderer

Ambix_3th_order-sound_ctrl.maxpat

Host: Windows NUC, Max 9.1.5
Layer: output (sound, back end)
In: OSC positions (UDP 10000) + 16 audio channels over Dante
Out: 16 loudspeaker feeds + 1 subwoofer feed over Dante

This patch is the rendering engine behind Ambisonics sound control. It receives the positions of up to sixteen sound sources and their audio, encodes them into a third-order ambisonic sound field, and decodes that field to the lab's measured, irregular layout of sixteen loudspeakers plus a subwoofer, all in real time. Most users never touch it: the TouchDesigner component is the interface, and the renderer runs on a dedicated machine. Splitting the work this way keeps audio rendering apart from the graphics and tracking load on the main workstation. It also keeps the decoder calibration in one place, independent of any project.

Role in the setup

The renderer is the second half of the lab's spatial sound chain. Ambisonics sound control decides where each sound is and what it plays. The renderer turns that into speaker signals for this particular room. Because the calibration lives here, any TouchDesigner project that sends positions and audio in the expected format sounds correct in the lab without project-specific tuning.

System context

MachineRole
HP Z8 workstationTouchDesigner: tracking, content and source audio. Audio goes onto the Dante network through Dante Via. Positions are sent over OSC.
Windows NUCMax 9.1.5 running this patch. Audio input and output go through Dante Virtual Soundcard in ASIO mode.
Dante networkcarries all audio between the machines and to the amplifiers and loudspeakers at 48 kHz. Routing is managed in Dante Controller.
Authoring machine (Mac)where the patch is edited. It is not part of the live chain. Patch iterations reach the NUC through a shared OneDrive folder.

Signal processing pipeline

  1. Position intake (OSC). udpreceive 10000 receives the positions. The patch routes the addresses /tx1 /ty1 /tz1 … /tx16 /ty16 /tz16 (one triplet per source), a tracked listener /lx1 /ly1 /lz1, a global /gain_range, per-source ranges /range_gain1 … /range_gain16, and /_samplerate (information only).
  2. Cartesian → spherical. Each source position (X = width, Y = height, Z = depth, metres) is converted to azimuth, elevation and distance relative to the reference listening point (X = 0, Y = 1.5, Z = 2.5). A sign-preserving minimum-magnitude floor on the depth term removes the singularity when a source is at exactly the reference depth.
  3. Gain. Each source's level falls with its distance to the listening reference. The gain range is the distance in metres at which the level reaches zero. It is set globally (/gain_range) or per source (/range_gain1 … /range_gain16); per source, it is fed by Rangegain in TouchDesigner. The reference is either fixed or tracked. An inversion toggle mirrors the tracked listener through the room centre to correct for the orientation of the tracking. Direction never comes from the listener, because listener orientation cannot be tracked reliably. A minimum floor on the range parameter prevents a division by zero while the patch loads. A global "gain active" switch sets all sources to full gain for direction-only tests.
  4. Encoding. ambiencode~ 3 16 (ICST) encodes the 16 audio inputs (adc~ 1–16, from Dante) into a third-order AmbiX field: 16 channels, ACN order, SN3D normalisation.
  5. File input. Two looped players (buffer~ + groove~, 16 channels each) add pre-encoded third-order B-format WAV files to the field before decoding. Each player has its own toggle and is off by default. (In development.)
  6. Decoding. ambidecode~ 3 16 (ICST) decodes the field to the 16 measured loudspeaker positions. Each speaker is defined by azimuth, elevation and distance in a decoder grid that can be edited live.
  7. Subwoofer. The omnidirectional W component (ACN 0) is taken from the encoder, low-pass filtered (lores~, 100 Hz) and sent to channel 17.
  8. Output. dac~ 1–17 sends the speaker feeds to Dante.

Loudspeaker calibration

Speaker positions were measured in the room and converted to decoder coordinates with a purpose-built interactive calibration tool, which has a top-down view and an elevation view. The tool exports azimuth, elevation and distance per speaker. These values are typed into the decoder grid, take effect immediately, and need no new patch version. The encoder's speaker-matched default positions (used in calibration mode) are derived from the same data, so the two stay consistent.

#RingXYZAzimuthElevationDistance
1ground−2.60.54.5−127.57°−16.95°3.43 m
2ground−2.60.52.5−90.00°−21.04°2.79 m
3ground−2.60.50.1−47.29°−15.78°3.68 m
4ground00.5−0.30.00°−19.65°2.97 m
5ground2.60.50.147.29°−15.78°3.68 m
6ground2.60.52.590.00°−21.04°2.79 m
7ground2.60.54.5127.57°−16.95°3.43 m
8rear03.07.15180.00°17.88°4.89 m
9high−2.53.73.25−106.70°40.13°3.41 m
10high−2.53.71.75−73.30°40.13°3.41 m
11high−1.253.70−26.57°38.21°3.56 m
12high1.253.7026.57°38.21°3.56 m
13high2.53.71.7573.30°40.13°3.41 m
14high2.53.73.25106.70°40.13°3.41 m
15high1.253.75153.43°38.21°3.56 m
16high−1.253.75−153.43°38.21°3.56 m

Convention: azimuth 0° points from the listening point towards the north wall. Positive azimuth turns towards +X. Z increases towards the entrance. The table also appears in the Lab model.

Operating modes

ModeOptionsDefault
Direction (global and per source)live tracked position, or a fixed position that matches the source's own speaker (calibration)tracked
Test audio (global and per source)live Dante input, or a looped voice recordinglive
Listener referencefixed point, or tracked listener (with optional mirroring)—
Gain activedistance-based gain, or full gain on all sourceson
Ambisonic file players (2)off / playoff

A debug panel shows each source's tracked position, its distance to the listener and the gain value sent to the encoder. This makes reactivity problems visible without console output.

Implementation notes

Limitations and open questions

Outlook

Availability

The renderer is not part of the public Td-updates repository. It runs on the lab's NUC and is maintained by the lab.

Relations

References