heygen-com/hyperframes · error · AudioFxRenderError
Unsupported WAV format ${format}/${bits}-bit: ${path}
Error message
Unsupported WAV format ${format}/${bits}-bit: ${path} What it means
Thrown by decodeSamples() when a WAV file's format/bits-per-sample combination is not one of the two supported decodings: IEEE float (format=3, 32-bit) or PCM (format=1, 16-bit). The audio FX pipeline only accepts samples in those two layouts because the upstream mixer writes 16-bit PCM or float32 and the baker that follows accepts only 16-bit. Any other combination — 24-bit PCM, 32-bit integer PCM, or extensible (0xFF) — has no decode path.
Source
Thrown at packages/engine/src/services/audioFxRender.ts:97
/** Interleaved samples as floats, for the two formats the mixer emits upstream. */
function decodeSamples(data: Buffer, format: number, bits: number, path: string): Float32Array {
if (format === 3 && bits === 32) {
const n = Math.floor(data.length / 4);
// A Float32Array view demands a 4-aligned offset, and chunk layouts that put
// `data` on an odd boundary (an 18-byte fmt plus a fact chunk, which
// ffmpeg's pcm_f32le writes) would otherwise throw RangeError. Copy then.
if (data.byteOffset % 4 === 0) return new Float32Array(data.buffer, data.byteOffset, n);
const copied = new Float32Array(n);
for (let i = 0; i < n; i++) copied[i] = data.readFloatLE(i * 4);
return copied;
}
if (format === 1 && bits === 16) {
const n = Math.floor(data.length / 2);
const out = new Float32Array(n);
for (let i = 0; i < n; i++) out[i] = data.readInt16LE(i * 2) / 32768;
return out;
}
throw new AudioFxRenderError(`Unsupported WAV format ${format}/${bits}-bit: ${path}`);
}
/**
* Write 16-bit PCM, interleaved, preserving the channel count.
*
* 16-bit rather than the float32 this used to emit: the very next step in the
* mixer bakes the volume envelope into the samples, and that baker accepts only
* 16-bit PCM. Emitting float meant enabling any effect silently downgraded a
* track's volume automation to the ffmpeg expression path, which is capped at 32
* straight segments — so a curved envelope was quantised and a dense one could
* fall back to rendering at base volume.
*/
export function writeWav(
path: string,
samples: Float32Array,
sampleRate: number,
channels = 1,
): void {View on GitHub (pinned to c2996c8626)
Solutions
- Re-export or transcode the source WAV to 16-bit PCM or 32-bit float: ffmpeg -i input.wav -c:a pcm_s16le output.wav
- If the file is WAVE_FORMAT_EXTENSIBLE, unwrap it to its base format: ffmpeg -i input.wav -c:a pcm_f32le output.wav
- Verify with ffprobe: ffprobe -show_entries stream=sample_fmt,bits_per_raw_sample input.wav — sample_fmt s16 or f32le are accepted.
- If you control the upstream render step, ensure writeWav() (which emits 16-bit PCM) is the only writer feeding the FX chain.
Example fix
// before: source WAV is 24-bit PCM
// after: transcode before passing to the pipeline
import { execSync } from 'child_process';
execSync('ffmpeg -y -i track.wav -c:a pcm_s16le track-16.wav');
await applyAudioFxChain('track-16.wav', chain, outWav, opts); Defensive patterns
Strategy: validation
Validate before calling
import { readFileSync } from 'fs';
function isSupportedWav(path: string): boolean {
const buf = readFileSync(path);
if (buf.length < 44 || buf.toString('ascii', 0, 4) !== 'RIFF') return false;
// format code at offset 20, bits at offset 34
const format = buf.readUInt16LE(20);
const bits = buf.readUInt16LE(34);
return (format === 3 && bits === 32) || (format === 1 && bits === 16);
}
// before calling applyAudioFxChain:
if (!isSupportedWav(inputWav)) {
// transcode or skip
} Try / catch
try {
await applyAudioFxChain(inputWav, chain, outWav, opts);
} catch (err) {
if (err instanceof AudioFxRenderError && err.message.includes('Unsupported WAV format')) {
// transcode and retry, or fall back to dry signal with a warning
}
throw err;
} Prevention
- Standardize all track WAVs to 16-bit PCM at the upstream render step.
- Validate WAV headers with ffprobe before passing to the FX pipeline.
- Document the two accepted format/bit-depth combinations in the audio module's README.
When it happens
Trigger: readWav() or applyAudioFxChain() is called on a WAV whose fmt chunk reports a format code and bit depth outside {3/32, 1/16}. The check fires after RIFF/data-chunk parsing succeeds, so the file is a valid WAV with an unsupported sample encoding.
Common situations: Author supplies a custom audio asset exported at 24-bit PCM (common in DAWs). An upstream tool re-encodes to 32-bit integer PCM instead of float. A WAV uses WAVE_FORMAT_EXTENSIBLE (0xFF) with a valid sub-format that the parser doesn't unwrap.
Related errors
- Unsupported output extension: ${ext}. Use .webm (VP9 alpha),
- Audio file too large for headless analysis (${mb}MB > ${MAX_
- ffmpeg could not extract first frame from ${videoPath}${deta
- Unable to bake required browser media proxies (${summary})
- ffmpeg is required to extract audio from video. Install: ${g
AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12).
Data as JSON: /api/errors/f9f6f644663c6f12.
Report an issue: GitHub.