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

  1. 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
  2. If the file is WAVE_FORMAT_EXTENSIBLE, unwrap it to its base format: ffmpeg -i input.wav -c:a pcm_f32le output.wav
  3. Verify with ffprobe: ffprobe -show_entries stream=sample_fmt,bits_per_raw_sample input.wav — sample_fmt s16 or f32le are accepted.
  4. 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

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


AI-assisted analysis of heygen-com/hyperframes@c2996c8626 (2026-08-12). Data as JSON: /api/errors/f9f6f644663c6f12. Report an issue: GitHub.