调度声音在web音频api 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;
}

在每个样本之间,我得到点击。

现在确保我查看了服务器端的数据,它在Audacity上运行良好。

然后在调试时,我打印出这些值,并在客户端和服务器端比较它们,看看是否有传输问题,它们是相同的。

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

是我计算的确切时间不正确吗?这是一个已知的web音频api问题吗?

我想这是我能得到的最精确的了。我需要应用一个过滤器来摆脱点击。过滤器的名称是什么?即使有,我认为那也很糟糕。

欢迎有任何想法

编辑:

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

每个44100 32bitFloat,单声道。

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);

        }
    }

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

你应该把它存储在某个地方,并在被请求时填充输出缓冲区,而不是在从websocket接收数据时播放数据块。

= =

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);

认为问题是您正在基于audioContext.currentTime加上总缓冲区持续时间进行调度。但问题是currentTime是一个移动的目标。你需要一个稳定的锚来确定你所有的时间。

你可能想要做的是,你第一次开始玩,说var AudioStart = audioContext.currentTime,然后不断增加它的方式,你已经是。然后将播放设置为source.start(AudioStart);

最新更新