# `decode-pipeline.ts` _(no submodules)_ ## Purpose This module owns the pure logic of the decode pipeline: format sniffing from magic bytes, the ffmpeg argument list that emits `f32le` interleaved samples to a MEMFS scratch file, and the deinterleave step that produces per-channel `Float32Array`s for the `DecodeResult` shape. The pipeline runs entirely through the supplied `WorkerHost` so cancellation, timeouts, and OOM detection are inherited from a single source of truth. ## Features - `sniffFormat(bytes)` recognises WAV, MP3 (ID3v2 + frame-sync), Ogg (Vorbis vs Opus by inspecting the bos packet), FLAC, AAC ADTS, and WebM/EBML headers. - `deinterleave(samples, channels)` returns `channels` equal-length `Float32Array`s. - `runDecode(opts)` orchestrates writeFile → run → readFile via `WorkerHost.submitFfmpeg` and returns a normalised `DecodeResult`. - Default sample rate (48 000) and channel count (2) for callers that do not pre-probe their input. ## Usage: Basic ```ts import { runDecode } from "@suaveplan/audio-codec-ffmpeg-wasm/decode/decode-pipeline"; const result = await runDecode({ host, bytes, format: "wav" }); console.log(result.channelData.length); // channel count console.log(result.channelData[0].length); // frame count console.log(result.sampleRate); ``` ## Usage: Advanced ```ts import { runDecode, sniffFormat, deinterleave, } from "@suaveplan/audio-codec-ffmpeg-wasm/decode/decode-pipeline"; const fmt = sniffFormat(bytes); if (!fmt) throw new Error("unsupported"); const result = await runDecode({ host, bytes, format: fmt as "wav" | "mp3" | "ogg" | "opus" | "flac" | "aac" | "webm", sampleRate: 44_100, channels: 1, timeoutMs: 30_000, signal: controller.signal, }); // Drop a deinterleaved view for downstream processing const ch = deinterleave(new Float32Array([0, 1, 2, 3]), 2); ``` ## API Reference - `DEFAULT_SAMPLE_RATE: 48_000`. - `DEFAULT_CHANNELS: 2`. - `sniffFormat(bytes: Uint8Array): string | undefined`. - `deinterleave(interleaved: Float32Array, channels: number): Float32Array[]`. - `runDecode(opts: DecodePipelineOptions): Promise`. ## Implementation Notes The deinterleave step copies the raw `Uint8Array` through a `Float32Array` view to honour the f32le wire layout and then takes a `.slice()` so the returned arrays own their own backing buffer — callers can transfer or mutate them without aliasing the worker output. The pipeline never silently catches MEMFS cleanup failures here; the host's `submitFfmpeg` handles try/finally cleanup and logs any delete failures via the injected logger. A non-zero ffmpeg exit is mapped to `AUDIO_CODEC_FFMPEG_WASM.DECODE_FAILED` inside the worker host so this module never sees it directly.