在web audio api PCM中安排声音

时间:2013-06-17 19:02:28

标签: javascript scheduling web-audio pcm

您好我在客户端缓存了一组PCM数据(Float32) (所有这些音频阵列都是同一首歌的一部分) 所以它有点像PCM数据的客户端缓冲。 从服务器下载N个数组后,我开始播放这些缓冲区并调用下面的函数来播放样本数组。

var AudioStart =0;

function playPcmChunk(data){

    var source = audioContext.createBufferSource();

    var audio=new Float32Array(data);

    var audioBuffer = audioContext.createBuffer(1, audio.length , 44100);

    audioBuffer.getChannelData(0).set(audio);

    source.buffer = audioBuffer;

    source.start(AudioStart);

    AudioStart += audioBuffer.duration;
}

在everysample之间,我获得了点击次数。

现在为了确保我查看服务器端的数据,它与Audacity一起播放得非常流畅。

然后调试我明确地打印出值并在客户端和服务器端比较它们以查看传输是否存在问题并且它们是相同的。

那么为什么我会在缓冲的样本数组之间点击声音。

我计算的确切时间不正确。这是一个已知的网络音频API问题吗?

我认为这是我能得到的精确。我是否需要应用过滤器来消除点击次数。该过滤器的名称是什么?即使有我认为那将是黑客。

欢迎任何想法

修改

这是我读取websocket并在数组中存储30(这完全是随机数)这些样本的地方。 在存储了30个之后,我开始循环每个样本并调用playPcmChunk并丢弃其余的音频。(这是用于测试)

每个都是44100 32bitFloat,Mono。

wsAudio.onmessage = function (messageEvent) {
        if (messageEvent.data instanceof Blob) {


            var fileReader = new FileReader();
            fileReader.onload = function (e) {
                if (currentCount == -1) {
                    return;
                }
                if (currentCount < 30) {
                    audioChunks[currentCount] = e.target.result;
                    currentCount++;
                } else {

                    for (var j = 0; j < 30; j++) {

                        playPcmChunk(audioChunks[j]);
                    }
                    currentCount = -1;
                }



            };
            fileReader.readAsArrayBuffer(messageEvent.data);



        }
    }

2 个答案:

答案 0 :(得分:2)

我做了类似的事情并遇到了同样的问题。解决方案是使用audioContext.createJavaScriptNode()。

而不是在从websocket接收块时播放chunk,你应该将它存储在某处并在请求时填充输出缓冲区。

==

var audioNode = audioContext.createJavaScriptNode(4096, 1, 1);

audioNode.onaudioprocess = function(event) {
                           if (decodedAudioBuffer.length >= bufferSize) {
                                  var decoded = decodedAudioBuffer.splice(0, bufferSize);
                                  var samples = new Float32Array(bufferSize);
                                  for (var i=0; i<decoded.length; i++) {
                                         samples[i] = decoded[i];
                                  }

                                  samples = resampler.resample(samples);
                                  var output = event.outputBuffer.getChannelData(0);
                                    for (var i = 0; i < output.length; i++) {
                                      output[i] = samples[i];
                                    }

                           }
};

audioNode.connect(audioContext.destination);

答案 1 :(得分:0)

认为问题在于您根据audioContext.currentTime加上总缓冲持续时间进行调度。但问题是currentTime是一个移动目标。你需要一个一致的锚来建立你的所有时间。

您可能想要做的是,第一次开始游戏时,请说var AudioStart = audioContext.currentTime,然后按照您现有的方式继续添加。{1}}。然后,只需将您的播放安排为source.start(AudioStart);