Ambisonic Bed Mixer — B-Format Summing

Sums 2–8 B-format ambisonic Sound objects (same order / same channel count / same sample rate / same time grid) into a single combined bed. Per-stem gain control, peak protection, direct WAV export with validation, and visualisation.

Author: Shai Cohen Affiliation: Department of Music, Bar-Ilan University, Israel Version: 0.2 (2026) License: MIT License Repo: https://github.com/ShaiCohen-ops/Praat-plugin_AudioTools
Contents:

What this does

This script implements B-format ambisonic summing — it takes 2–8 Full-3D ACN/SN3D B-format Sound objects (from the Higher-Order Ambisonic Encoder) and sums them into a single combined bed. Each stem can have a uniform gain applied across all its ACN channels (per-stem gain only — per-channel gains would distort the direction a stem was encoded at). The output is a combined ambisonic bed ready for decoding or further processing.

Why a bed mixer? In ambisonics, multiple point sources can be linearly summed in the B-format domain. This is how you build a complex soundfield from independently-encoded sources: encode each source to B-format, then add them together. This script does exactly that — with per-stem gain control, grid validation, and direct export — without re-encoding the bed (which would destroy the existing soundfield).

Key Features:

Do NOT re-encode: This script exports the bed directly via WAV. Do not pass the finished bed back through the Higher-Order Ambisonic Encoder — the Encoder is a source-to-B-format tool; the bed is already B-format. Re-encoding it would treat it as new raw audio and destroy the existing soundfield.

Quick start

  1. Prepare your B-format stems using the Higher-Order Ambisonic Encoder with:
    • Submission mode: OFF
    • Peak protection: OFF
    • Same sample rate, duration, and start time (0) for all stems
  2. Select 2–8 B-format Sound objects in Praat (same order, same sample rate, same time grid).
  3. Run script…Ambisonic_Bed_Mixer.praat.
  4. The Info window prints the selected sounds with their corresponding Gain_N numbers.
  5. In the form, set Gain_1…Gain_8 values (negative values are valid for polarity flip).
  6. Enable Peak_protect and set Target_peak (0.95 recommended).
  7. Enable Export_wav to save the bed directly to WAV (never re-encode).
  8. Click OK — script validates, sums, protects peak, exports, and draws visualisation.
Quick tip: The Info window lists the selected sounds before the form opens, so you can match Gain_N numbers to names. Use negative gains for polarity inversion (e.g., to cancel a stem or create a difference bed). Enable Peak_protect to prevent clipping — it applies a single shared attenuation to the final bed, preserving relative levels between stems.
Important: This script assumes every input is Full-3D ACN/SN3D B-format. Channel count alone does not confirm convention — a 16-channel Sound could be ACN/N3D, FuMa-derived, or unrelated. Ensure all stems are encoded with the same convention (the companion Higher-Order Ambisonic Encoder uses ACN/SN3D with the ambiX convention). The script validates time grid, sample rate, and channel count, but cannot verify the B-format convention from the samples themselves.

Assumptions — Can Be Verified from the Samples

Same order

All stems must have the same number of channels: 4 (1st order), 9 (2nd order), or 16 (3rd order). The script checks and refuses to mix mismatched orders.

Same sample rate

All stems must share the same sample rate. The script checks and reports mismatches.

Same start time

All stems must start at the same time (ideally 0). The script checks and refuses to guess.

Same sample count

All stems must have the same number of samples. The script checks and refuses to pad/trim automatically — this must be done externally.

Why so strict? Ambisonic summing is linear — mismatched grids would produce phase errors and temporal misalignments. The script deliberately refuses to guess (no auto-padding, no resampling) so you can fix stems externally and be confident the mix is correct. This is the same rigor as a professional DAW's stem import.

Encoding Your Stems for This Script

In the Higher-Order Ambisonic Encoder, ensure BOTH of these are true for every stem:
  • Submission mode: OFF — submission mode force-enables its own peak protection, which is exactly what we don't want per-stem.
  • Peak protection: OFF — we apply peak protection exactly once, on the final summed bed, not per stem.
All stems also need:
  • Start time = 0 (or all the same start time)
  • Same sample rate
  • Same duration / sample count
This script now checks all of these and refuses to mix stems that don't match, rather than guessing.
Why no per-stem peak protection? If you attenuate each stem individually to avoid clipping, you lose the relative distance/level relationships between sources. Peak protection should happen once, on the final summed bed, with a shared attenuation factor that preserves the mix's internal balance. This is the correct professional practice for ambisonic bed mixing.

Summing Rules — Do Not Relax These

Per-stem gain

One gain value per STEM, applied uniformly across all of that stem's ACN channels. Per-channel gains would distort the direction a stem was encoded at — this is a fundamental property of ambisonic encoding.

Straight per-channel addition

ACN0+ACN0, ACN1+ACN1, … Never channel-stacking/interleaving. Combine to stereo grows channel count; it never sums. This script uses Formula for per-channel addition.

Peak protection

Happens exactly ONCE, on the final summed bed. Attenuate-only (never boosts), so the relative levels between stems (their encoded directions/distances) survive.

No post-mix SN3D self-test

The SN3D identity only holds for a single point source. Validate each stem individually with the Encoder's own self-test before mixing; trust linearity for the sum.

Summing equation:

For each ACN channel c and sample n:

Bed[c, n] = Σi Gaini × Stemi[c, n]

This is a linear sum of the spherical harmonic coefficients. No mixing of channels across stems, no interleaving — just element-wise addition.

Applications

Multi-source ambisonic mixing

Use case: Build a complex soundfield from multiple independently-encoded sources (e.g., a voice at front center, a guitar at left, a synth at right).

Settings: Encode each source to B-format with the Encoder (Submission mode OFF, Peak protection OFF). Mix them here with per-stem gains. The output is a combined B-format bed ready for decoding.

Stem level adjustment

Use case: Adjust the relative levels of stems in an existing ambisonic mix.

Settings: Load the stems, set gains (negative for polarity flip), mix. The resulting bed can be re-exported directly to WAV (no re-encoding).

Polarity inversion / cancellation

Use case: Create a difference bed by subtracting one stem from another (e.g., to isolate a source by cancellation).

Settings: Set one gain to +1.0, another to −1.0. The result is the difference between the two stems.

Archiving / delivery

Use case: Create a single 3rd-order ambiX WAV for delivery.

Settings: Mix stems, enable Peak_protect, enable Export_wav. The script validates the exported WAV (re-reads it to confirm channel count, sample rate, sample count). The output is a compliant ambiX file.

Workflow: Voice + Guitar + Synth → 3rd-order ambiX mix

Stems: 3 B-format files (each 16 channels).
Settings: Gains: Voice=1.0, Guitar=0.7, Synth=0.5. Peak_protect=0.95. Export WAV.
Result: A single 16-channel ambiX WAV with the three sources mixed at the specified levels. The script validates the WAV and reports PASS.

Workflow: Cancel a stem with polarity inversion

Stems: Two B-format files that should be identical.
Settings: Gain_1=1.0, Gain_2=−1.0.
Result: The output bed is near-zero (or contains the difference between them). This confirms the stems are identical (or reveals the residual).

Workflow: Create a bed from 8 stems

Stems: 8 B-format files (max capacity).
Settings: Adjust gains individually, Peak_protect=0.95, Export WAV.
Result: A full 8-stem bed. The visualisation shows all 8 gain bars with stem names.

Troubleshooting:
"Stems do not share an identical time grid" — Fix externally: pad/trim every stem to the same start time (0) and sample count. This script deliberately does not guess.
"Selected sounds have N channels - not supported" — This script supports 1st (4ch), 2nd (9ch), and 3rd (16ch) only. It does not support or imply 4th/5th order.
Peak protection attenuates too much — Reduce the sum of the gains (mix quieter) or lower the target peak (e.g., 0.9).
Export validation fails — Check disk space, folder permissions, and that the WAV was not modified. In case of failure, the script deletes the non-conformant file and aborts.
Do not play the bed directly — The output is B-format (W/Y/Z/X...), not speaker feeds. Decode it first with the Higher-Order Ambisonic Decoder for playback.

Visualisation

When Draw_visualization is enabled, the script generates:
  • Per-stem gain bars — blue = positive gain, red = negative gain. Each bar labelled with the stem name and gain value.
  • Output waveform — ACN0 (W / omni) channel of the summed bed.
  • Summary panel — number of stems, order, duration, sample rate, peak pre-protect, attenuation factor, elapsed time.
The gain bars are particularly useful for verifying that your gain settings match the intended stem levels, especially when using negative gains for polarity inversion.