You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WebAudioContext处理FFMPEG.Wasm导出WAV blob获全零Float32Array问题

问题分析与解决

你的核心问题是创建BufferSource后没有为它设置音频数据,导致OfflineAudioContext渲染的是空白音频,自然得到全零的Float32Array。

错误点定位

在你的代码中,创建source = offlineContext.createBufferSource()后,只做了连接和启动操作,却没有把解码后的decodedData赋值给source.buffer——相当于让一个空的音源去渲染,结果必然是全零数组。

修正后的代码

先修复这个核心问题,同时简化不必要的步骤(比如无需FileReader,直接用audio_data.buffer解码即可):

const audio_data = ffmpeg.FS('readFile', 'output_audio.wav');
show_audio = true;
const blob = new Blob([audio_data.buffer], { type: 'audio/wav' })
src = URL.createObjectURL(blob);

// Convert the Audio Stream to a Buffer for Whisper
const audioContext = new AudioContext({
    sampleRate: 16000,
    echoCancellation: false,
    autoGainControl: true,
    noiseSuppression: true,
});

// 直接用audio_data.buffer解码,无需FileReader
audioContext.decodeAudioData(audio_data.buffer).then(function(decodedData) {
    console.log(decodedData);

    // 修复:创建BufferSource后必须关联解码后的buffer
    var offlineContext = new OfflineAudioContext(decodedData.numberOfChannels, decodedData.length, decodedData.sampleRate);
    var source = offlineContext.createBufferSource();
    source.buffer = decodedData; // 关键缺失的一行
    source.connect(offlineContext.destination);
    source.start(0);

    offlineContext.startRendering().then(function(renderedBuffer) {
        console.log(renderedBuffer);
        console.log(renderedBuffer.getChannelData(0));
        BUFFER_AUDIO_DATA = renderedBuffer.getChannelData(0);
    });
});

进一步优化(适配Whisper.cpp需求)

Whisper.cpp要求输入是16kHz单声道的Float32Array,如果你的原始音频不是这个格式,还需要做重采样和声道合并:

async function convertToWhisperInput(audioBuffer, targetSampleRate = 16000) {
    const sourceSampleRate = audioBuffer.sampleRate;
    const sourceChannels = audioBuffer.numberOfChannels;

    // 合并多声道为单声道
    let monoData;
    if (sourceChannels === 1) {
        monoData = audioBuffer.getChannelData(0);
    } else {
        monoData = new Float32Array(audioBuffer.length);
        const channel1 = audioBuffer.getChannelData(0);
        const channel2 = audioBuffer.getChannelData(1);
        for (let i = 0; i < audioBuffer.length; i++) {
            monoData[i] = (channel1[i] + channel2[i]) / 2;
        }
    }

    // 重采样到16kHz
    if (sourceSampleRate !== targetSampleRate) {
        const ratio = targetSampleRate / sourceSampleRate;
        const newLength = Math.round(monoData.length * ratio);
        const resampledData = new Float32Array(newLength);
        for (let i = 0; i < newLength; i++) {
            const sourceIndex = i / ratio;
            const left = Math.floor(sourceIndex);
            const right = left + 1;
            const weight = sourceIndex - left;
            resampledData[i] = monoData[left] * (1 - weight) + (monoData[right] || monoData[left]) * weight;
        }
        return resampledData;
    }

    return monoData;
}

// 使用示例
audioContext.decodeAudioData(audio_data.buffer).then(async function(decodedData) {
    BUFFER_AUDIO_DATA = await convertToWhisperInput(decodedData);
    console.log(BUFFER_AUDIO_DATA); // 现在应该是正确的音频数据
});

其他尝试的问题解释

  • 直接用Float32Array.from(audio_data.buffer)不行:因为WAV文件包含文件头,不是原始的PCM浮点数据,必须经过解码才能得到正确的音频采样值。
  • 无参数AudioContext不影响核心问题,只是采样率可能不匹配,但核心还是BufferSource没赋值。

内容的提问来源于stack exchange,提问作者MatejMecka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 04:49:56