【问题标题】:How do I decode MP3 with js-mp3 and play in AudioContext?如何使用 js-mp3 解码 MP3 并在 AudioContext 中播放?
【发布时间】:2021-12-03 20:27:39
【问题描述】:

由于 Safari 15 中的一个错误有时会导致AudioContext.decodeAudioData 对于普通 MP3 文件失败(请参阅Safari 15 fails to decode audio data that previous versions decoded without problems),我正在尝试解决此问题。解决方法是使用库 https://github.com/soundbus-technologies/js-mp3 解码文件,然后从该数据创建一个 AudioBuffer 并播放它。

问题在于 js-mp3 返回一个带有 PCM 数据的 ArrayBuffer,而创建一个 AudioBuffer 需要两个单独的数组,每个通道一个,以及 sampleRate 和 sample 帧长度。到目前为止,我得到的是:


function concatTypedArrays(a, b) { // a, b TypedArray of same type
    var c = new (a.constructor)(a.length + b.length);
    c.set(a, 0);
    c.set(b, a.length);
    return c;
};

// responseData is an ArrayBuffer with the MP3 file...
let decoder = Mp3.newDecoder(responseData);
let pcmArrayBuffer = decoder.decode();

//Trying to read the frames to get the two channels. Maybe get it correctly from
//the pcmArrayBuffer instead?
    
decoder.source.pos = 0;
let left = new Float32Array(), right = new Float32Array();
console.log('Frame count: ' + decoder.frameStarts.length);
let result;
let i = 0;
let samplesDecoded = 0;
                    
while (true) {

    let result = decoder.readFrame();
    if (result.err) {
        break;
    } else {
        console.log('READ FRAME ' + (++i));
        samplesDecoded += 1152; //Think this is the right sample count per frame for MPEG1 files
        left = concatTypedArrays(left, decoder.frame.v_vec[0]);
        right = concatTypedArrays(left, decoder.frame.v_vec[1]);
    }
}

let audioContext = new AudioContext();
let buffer = audioContext.createBuffer(2, samplesDecoded, decoder.sampleRate);
let source = audioContext.createBufferSource();
source.buffer = buffer;
source.connect(audioContext.destination);
source.start(0);

现在,这种作品,因为我确实听到了声音,而且我能听到它们是正确的声音,但它们被奇怪地扭曲了。我正在尝试播放的示例声音文件是 https://cardgames.io/mahjong/sounds/selecttile.mp3

有什么想法吗?或者如何将.decode()函数返回的单个PCM数组缓冲区正确转换为正常播放所需的格式?

【问题讨论】:

  • 几个问题:can you get the example to work?。您是否正在运行节点服务器并从客户端向其发送 MP3 数据?如果不是,实际设置是什么? The sound isn't available,所有声音都会发生这种情况还是只发生这种特定的声音?您共享的脚本是您正在处理的整个系统,还是有其他脚本和网页?如果有,您能否提供该问题的最小工作示例?
  • right = concatTypedArrays(left,
  • 尽管您似乎没有在任何地方使用leftright 缓冲区。代码示例不完整。

标签: javascript audio mp3 web-audio-api audiocontext


【解决方案1】:

上面fdcpp 链接的示例表明decoder.decode() 返回的ArrayBuffer 可用于将其写入WAV 文件而无需进一步修改。这意味着数据必须是交错的 PCM 数据。

因此,当将数据转换回浮点值时,它应该可以工作。此外,它必须按照 Web Audio API 的预期放入平面阵列中。

const interleavedPcmData = new DataView(pcmArrayBuffer);
const numberOfChannels = decoder.frame.header.numberOfChannels();
const audioBuffer = new AudioBuffer({
    length: pcmArrayBuffer.byteLength / 2 / numberOfChannels,
    numberOfChannels,
    sampleRate: decoder.sampleRate
});
const planarChannelDatas = [];

for (let i = 0; i < numberOfChannels; i += 1) {
    planarChannelDatas.push(audioBuffer.getChannelData(i));
}

for (let i = 0; i < interleavedPcmData.byteLength; i += 2) {
    const channelNumber = i / 2 % numberOfChannels;
    const value = interleavedPcmData.getInt16(i, true);

    planarChannelDatas[channelNumber][Math.floor(i / 2 / numberOfChannels)]
        = value < 0
            ? value / 32768
            : value / 32767;
}

【讨论】:

  • 谢谢!!!效果很好,享受赏金?(不能再奖励2小时,但你得到了它)
  • 太好了,我很高兴它有效。我敢肯定,我迟早也需要解决 Safari 中的该错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-06
  • 2013-11-11
  • 1970-01-01
  • 1970-01-01
  • 2013-10-02
相关资源
最近更新 更多