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
相关产品推荐
相关产品推荐

