Braided Audio

WAVE Braided Audio publishes N synchronized audio channels — stems, languages, camera-angle commentary, a multichannel bed — as one MoQ track of interleaved multi-channel PCM, instead of N independent tracks. A subscriber reconstructs a single shared clock from that one track and applies a per-channel gain (a fader). It is the structural cure for a whole class of stem-silence / drift bugs: N independent MoQ tracks force a player to re-derive timing from N separately-arriving, independently backlogged streams; one interleaved track has one arrival timeline, so channels are phase-locked by construction.

Use cases: stem players and remix decks, karaoke, multi-language commentary, immersive/spatial beds, and multichannel audio-over-IP delivered over the web.

Braided Audio is proven live today as the WAVE Listen stem mixer at listen.wave.online/s/chillwave-stems (four lofi instrument faders — drums, bass, keys, guitar). The customer-callable /v1/braid/publish control route and the @wave-av/braid-audio SDK package described below are coming — this page documents the frozen wire contract and the shape of the API being built on top of it.

Wire contract (frozen)

Every published MoQ object is:

[ 16-byte sync header ][ interleaved S16LE payload ]

Sync header (16 bytes, big-endian)

offsetfieldtypemeaning
0magicu16 BE0x5742 ("WB", WaveBraid). Non-braid objects are ignored, never misread.
2versionu81
3channelsu8interleaved channel count, 1–255
4epochu32 BEpublisher-run id; a restart bumps it so the subscriber re-primes deterministically
8sampleIndexu64 BEper-channel frame index of this window's first frame (monotonic within an epoch)

The subscriber times playback from {epoch, sampleIndex}never the MoQ object id — so a relay backlog burst or a publisher restart is a deterministic resync, not silent drift. A gap or backward step in sampleIndex, or a change in epoch, signals a discontinuity and triggers a re-prime.

Payload — interleaved S16LE

channels mono streams interleaved per frame, little-endian signed 16-bit. Frame k, channel c sits at byte 16 + (kchannels + c)2. S16LE (not S32LE) halves bandwidth.

Object-size envelope

Every object must stay at or below ~38400 bytes so it survives as a single unfragmented browser delivery. Object bytes = 16 + windowFrames channels 2, so the publish window shrinks as channel count grows:

channelsmax windowFramesmax window @ 48kHz
44800100 ms
53840~79 ms
63200~66 ms
82400~49 ms

Manifest

A reserved wave-manifest control track carries the JSON manifest the subscriber reads first:

{
  "v": 2,
  "mode": "braid",
  "track": "stems",          // the single interleaved audio track to subscribe to
  "format": "s16le",
  "sampleRate": 48000,
  "channels": 4,
  "windowFrames": 4800,
  "stems": [                 // channel index i == stems[i]; drives the faders
    { "index": 0, "track": "drums",  "label": "Drums" },
    { "index": 1, "track": "bass",   "label": "Bass" },
    { "index": 2, "track": "keys",   "label": "Keys" },
    { "index": 3, "track": "guitar", "label": "Guitar" }
  ]
}

Every channel set is validated sample-identical before it goes live — a set that would drift never publishes.

Publish API (coming)

POST /v1/braid/publish

Requires gateway auth scoped moq:write. Orchestrates one braid publisher — merges the given sources into interleaved S16LE, sync-headers each object, and writes the audio track plus the wave-manifest control track.

Request

{
  "ns": "chillwave-stems",
  "sources": [
    { "label": "Drums",  "url": "https://storage.example.com/chillwave/drums.wav" },
    { "label": "Bass",   "url": "https://storage.example.com/chillwave/bass.wav" }
  ],
  "windowMs": 100
}
  • ns — the MoQ namespace to publish under.
  • sources — 2 or more channel sources (label + url or path), one per stem/channel.
  • windowMs — optional; auto-clamped to the object-size envelope for the resulting channel count.

Response

{ "ns": "chillwave-stems", "track": "stems", "channels": 4, "manifest": { "...": "..." } }

Subscribing reuses the standard MoQ subscribe/token-mint path — a braid subscriber is an ordinary MoQ subscriber that also reads the wave-manifest track.

Client SDK — @wave-av/braid-audio (coming)

A framework-agnostic core (DataView-only — runs unchanged in a browser, a Web Worker, or Node) for decoding the wire format on the receive side:

import { decodeBraidObject } from "@wave-av/braid-audio";

// obj is one MoQ object payload (header + interleaved PCM)
const { channels, epoch, sampleIndex, channelsData } = decodeBraidObject(obj);
// channelsData[i] is a Float32Array in [-1, 1) for channel i — feed each to a GainNode fader.

On top of the core, a documented browser layer wires each decoded channel to a ChannelSplitter → N GainNode faders → a shared master gain, reusing a bounded play-head (drop-on-overrun, rebuild-on-underrun, re-prime on epoch change) so the browser stays on the live edge.

Constraints

  • 48kHz fixed sample rate.
  • 2 or more channel sources per braid.
  • Per-org concurrency and fleet-wide braid caps are operational limits enforced at the gateway; exact

values are set per environment.

See What WAVE speaks for the transports Braided Audio rides on, and the API reference for the full contract as it ships.