Javascript web音频api PCM中的声音调度

Javascript web音频api PCM中的声音调度,javascript,scheduling,web-audio-api,pcm,Javascript,Scheduling,Web Audio Api,Pcm,嗨,我有一个PCM数据数组(Float32)缓冲在客户端 (所有这些音频阵列都是同一首歌曲的组成部分) 因此,这是一种PCM数据的客户端缓冲。 从服务器下载N个数组后,我开始播放这些缓冲区,并调用下面的函数来播放示例数组 var AudioStart =0; function playPcmChunk(data){ var source = audioContext.createBufferSource(); var audio=new Float32Array(data)

嗨,我有一个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;
}
在每个示例之间,我都会收到点击

现在,为了确保我查看了服务器端的数据,它以大胆的方式播放得非常流畅

然后,为了进行调试,我以书面形式打印出这些值,并在客户端和服务器端对它们进行比较,以查看传输是否有问题,它们是否相同

那么为什么我会在缓冲的样本数组之间听到咔哒声呢

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

我认为这是我能得到的最精确的结果。我是否需要应用过滤器来消除点击。该过滤器的名称是什么?即使有,我想那也是哈克

欢迎提出任何意见

编辑:

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

每个是44100 32位浮点单声道

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



        }
    }
wsAudio.onmessage=函数(messageEvent){
if(Blob的messageEvent.data实例){
var fileReader=newfilereader();
fileReader.onload=函数(e){
如果(currentCount==-1){
返回;
}
如果(当前计数<30){
audioChunks[currentCount]=e.target.result;
currentCount++;
}否则{
对于(var j=0;j<30;j++){
playPcmChunk(audiochunk[j]);
}
currentCount=-1;
}
};
fileReader.readAsArrayBuffer(messageEvent.data);
}
}

我认为问题在于您是根据
audioContext.currentTime
加上总缓冲区持续时间进行调度的。但问题是,
currentTime
是一个移动的目标。你需要一个始终如一的锚来保证你所有的时间


您可能想做的是,在您第一次开始播放时,说
var AudioStart=audioContext.currentTime
,然后继续以您现有的方式添加。然后只需将您的播放安排为
source.start(AudioStart)

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

您不应该在从websocket接收数据块时播放它,而应该将其存储在某个位置,并在请求时填充输出缓冲区

==

var audioNode=audioContext.createJavaScriptNode(4096,1,1);
audioNode.onaudioprocess=函数(事件){
if(decodedAudioBuffer.length>=bufferSize){
var decoded=decoded缓冲区拼接(0,缓冲区大小);
var samples=新的Float32Array(bufferSize);

对于(var i=0;我需要查看调用playPcmChunk的代码。我也尝试了source.noteOn(AudioStart);AudioStart+=audioBuffer.duration;当我得到第一个区块时,我运行这个程序,只有AudioStart=audioContext.currentTime;但仍然没有乐趣,我也尝试了这个程序来确保它是一个调度。我将所有数据下载到一个数组中,而不是一个区块中。然后播放了这个程序。这样就不会产生任何咔哒声。因此,当调度是毫无疑问,它是平滑的。我也发现了这一点。在计划播放现有缓冲区的同时创建一个新的缓冲区似乎容易导致播放中出现问题(尤其是使用较大的缓冲区)这个实验在当前播放缓冲器的中间开始缓冲,看起来更稳定。这是给我造成的各种错误,但是如果有人感兴趣的话,我是一个快速克隆,我在一起做的更好一点:是的,我在我以前的评论上发布了这个链接,实际上联系了戴维,那个站点的作者D。avid,实际上在谷歌工作。所以我希望在某个时候能得到回复。是的,我用它来重新采样我的音频样本,因为它们的采样率与audioContext.sampleRate不同。@AnthonyHo,我希望以类似的方式重新采样(麦克风输入从44100下降到16000或8000…)但我在这里有点困惑。event.outputBuffer.length不一定不匹配吗?我们正在更改音频上下文中的采样数。这是如何工作的?
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);