使用Web Audio API将多个ArrayBuffer合并/分层为一个AudioBuffer

sam*_*rad 4 javascript merge arraybuffer audiobuffer web-audio-api

我需要分层循环.wav轨道,最终我将需要能够打开和关闭并保持同步。

首先,我加载了曲目,并停止BufferLoader了将加载的内容arraybuffer变成的AudioBuffer(因此false

        function loadTracks(data) {
            for (var i = 0; i < data.length; i++) {
                trackUrls.push(data[i]['url']);
            };
            bufferLoader = new BufferLoader(context, trackUrls, finishedLoading);
            bufferLoader.load(false);
            return loaderDefered.promise;
        }
Run Code Online (Sandbox Code Playgroud)

当您单击屏幕上的按钮时,它将调用startStop()

    function startStop(index, name, isPlaying) {
        if(!activeBuffer) {
            activeBuffer = bufferList[index];
        }else{
            activeBuffer = appendBuffer(activeBuffer, bufferList[index]);
        }
        context.decodeAudioData(activeBuffer, function(buffer){
            audioBuffer = buffer;
            play();
        })


    function play() {
        var scheduledTime = 0.015;
        try {
            audioSource.stop(scheduledTime);
        } catch (e) {}

        audioSource = context.createBufferSource();
        audioSource.buffer = audioBuffer;
        audioSource.loop = true;
        audioSource.connect(context.destination);
        var currentTime = context.currentTime + 0.010 || 0;
        audioSource.start(scheduledTime - 0.005, currentTime, audioBuffer.duration - currentTime);
        audioSource.playbackRate.value = 1;
    }
Run Code Online (Sandbox Code Playgroud)

在这个github上找到的大多数代码。在演示中,您可以听到他正在对AudioBuffers进行分层。

我已经在主机上尝试过相同的方法。

不管这些argularJS东西,Web Audio东西都发生service.js在:

/js/angular/service.js 
Run Code Online (Sandbox Code Playgroud)

如果您打开控制台并单击按钮,您会看到activeBuffer.byteLength(类型ArrayBuffer)正在增加,但是即使在通过该context.decodeAudioData方法解码之后,它仍只会播放您单击的第一个声音,而不是合并的声音AudioBuffer

cwi*_*lso 5

我不确定我是否完全了解您的情况-您不希望它们同时播放吗?(即,低音在鼓的顶部分层)。

每当您点击该文件的按钮时,您当前的代码就会尝试连接一个其他音频文件。您不能只连接音频文件(以ENCODED格式),然后通过解码运行它-解码音频数据方法将解码数组缓冲区中的第一个完整声音,然后停止(因为它已经完成了声音解码)。

您应该做的是更改逻辑,以将生成的AudioBuffers中的缓冲区数据连接起来(请参见下文)。即使这种逻辑也不完全是您应该做的-这仍然会缓存编码的音频文件,并在您每次按下按钮时进行解码。相反,您应该缓存解码后的音频缓冲区,然后将其串联起来。

function startStop(index, name, isPlaying) {

    // Note we're decoding just the new sound
    context.decodeAudioData( bufferList[index], function(buffer){
        // We have a decoded buffer - now we need to concatenate it
        audioBuffer = buffer;

        if(!audioBuffer) {
            audioBuffer = buffer;
        }else{
            audioBuffer = concatenateAudioBuffers(audioBuffer, buffer);
        }

        play();
    })
}

function concatenateAudioBuffers(buffer1, buffer2) {
    if (!buffer1 || !buffer2) {
        console.log("no buffers!");
        return null;
    }

    if (buffer1.numberOfChannels != buffer2.numberOfChannels) {
        console.log("number of channels is not the same!");
        return null;
    }

    if (buffer1.sampleRate != buffer2.sampleRate) {
        console.log("sample rates don't match!");
        return null;
    }

    var tmp = context.createBuffer(buffer1.numberOfChannels, buffer1.length + buffer2.length, buffer1.sampleRate);

    for (var i=0; i<tmp.numberOfChannels; i++) {
        var data = tmp.getChannelData(i);
        data.set(buffer1.getChannelData(i));
        data.set(buffer2.getChannelData(i),buffer1.length);
    }
    return tmp;
};
Run Code Online (Sandbox Code Playgroud)