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/publishcontrol route and the@wave-av/braid-audioSDK 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)
| offset | field | type | meaning |
|---|---|---|---|
| 0 | magic | u16 BE | 0x5742 ("WB", WaveBraid). Non-braid objects are ignored, never misread. |
| 2 | version | u8 | 1 |
| 3 | channels | u8 | interleaved channel count, 1–255 |
| 4 | epoch | u32 BE | publisher-run id; a restart bumps it so the subscriber re-primes deterministically |
| 8 | sampleIndex | u64 BE | per-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:
| channels | max windowFrames | max window @ 48kHz |
|---|---|---|
| 4 | 4800 | 100 ms |
| 5 | 3840 | ~79 ms |
| 6 | 3200 | ~66 ms |
| 8 | 2400 | ~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+urlorpath), 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.