Javascript 如何不断地重新填充缓冲区/流并播放音频,而不会在缓冲区结束时出现恼人的暂停和单击声音?

Javascript 如何不断地重新填充缓冲区/流并播放音频,而不会在缓冲区结束时出现恼人的暂停和单击声音?,javascript,web-audio-api,Javascript,Web Audio Api,试图创建舒缓的氢气声音发生器,但网络音频api太有限,或者我遗漏了一些东西。没有onbufferend或onrequestmoredata或类似内容。唯一存在的东西是从AudioBufferSourceNode中统一的。我想做的是不可能的吗 stackoverflow抱怨我应该添加更多的细节,因为这篇文章主要包含代码,但我没有更多的细节要添加 document.addEventListener(“DOMContentLoaded”,()=>{ const button=document.que

试图创建舒缓的氢气声音发生器,但网络音频api太有限,或者我遗漏了一些东西。没有onbufferend或onrequestmoredata或类似内容。唯一存在的东西是从AudioBufferSourceNode中统一的。我想做的是不可能的吗

stackoverflow抱怨我应该添加更多的细节,因为这篇文章主要包含代码,但我没有更多的细节要添加

document.addEventListener(“DOMContentLoaded”,()=>{
const button=document.querySelector('button');
const buttonStop=document.querySelector(“#buttonStop”);
让AudioContext=window.AudioContext | | window.webkitadiocontext;
让audioCtx;
//单声道
常数通道=1;
函数init(){
audioCtx=新的AudioContext();
}
buttonStop.onclick=函数(){
audioCtx.close();
audioCtx=null;
}
常数钳位=(num,min,max)=>Math.min(Math.max(num,min,max);
恒赫兹实时频率=440;
让dk;
设dPos=0.0;
让第一次=真实;
常数表=[];
函数和(t){
如果(第一次){
对于(变量i=0;i<9;++i){
设n=i+2;//todo:这应该持续增加,2->无穷大
表[i]=[];
表[i][0]=((1-1/Math.pow(n,2));
表[i][1]=((1/4-1/Math.pow((n+1),2));
表[i][2]=((1/9-1/Math.pow((n+2),2));
表[i][3]=((1/Math.pow(4,2))-1/Math.pow((n+3,2));
表[i][4]=((1/Math.pow(5,2))-1/Math.pow((n+4,2));
表[i][5]=((1/Math.pow(6,2))-1/Math.pow((n+5,2));
}
第一次=错误;
}
设sum_值=0.0;
for(设i=0;i<9;++i)
{
sum_value+=Math.sin(表[i][0]*t);
sum_value+=Math.sin(表[i][1]*t);
sum_value+=Math.sin(表[i][2]*t);
sum_value+=Math.sin(表[i][3]*t);
sum_value+=Math.sin(表[i][4]*t);
sum_value+=Math.sin(表[i][5]*t);
}
返回和值;
}
button.onclick=函数(){
如果(!audioCtx){
init();
dk=hz\u实时频率*2*Math.PI/audioCtx.sampleRate;
}
//在顶部创建一个空的两秒立体声缓冲区
//音频上下文的采样率
设frameCount_buffersize=audioCtx.sampleRate*2.0;
让myArrayBuffer=audioCtx.createBuffer(通道、帧数、缓冲大小、audioCtx.sampleRate);
函数fillAudioBuffer(){
//用白噪声填充缓冲器;
//只是-1.0和1.0之间的随机值
对于(让通道=0;通道<通道;通道++){
//这为我们提供了包含数据的实际数组
让nowBuffering=myArrayBuffer.getChannelData(通道);
for(设i_sampleNumber=0;i_sampleNumber{
源。断开连接(audioCtx。目标);
continueSource();
}
}
continueSource();
}
});

氢声
氢声
发出氢气声
停止

这里有一种可能的方法来做你想做的事情,假设你得到的点击是因为在一个缓冲区的结束和下一个缓冲区的开始之间有一个间隙

创建两个单独的缓冲区和两个相应的AudioBufferSourceNodes。为每个事件设置一个统一的事件处理程序。开始播放第一个缓冲区,并安排第二个缓冲区在第一个缓冲区结束时开始

当您获得onended事件时,创建一个新的缓冲区和源,并安排它在第二个缓冲区的末尾开始播放。为此缓冲区设置一个新的onended事件处理程序,该处理程序基本上也会执行相同的操作

现在,当你得到一个统一的事件,将有一个缓冲区已经安排好播放没有间隙,你可以创建一个新的准备去当当前播放一个完成

但是,由于一个缓冲区末尾的值可能与下一个缓冲区开头的值非常不同,因此在缓冲区之间仍可能会出现一些单击。要解决这一问题,您可能需要(通过增益节点)降低一个缓冲区的末尾,然后升高下一个缓冲区的开头。或交叉淡入两个缓冲区,以实现平滑过渡


缓冲区的淡入/淡出可以通过AudioBufferSourceNode AudioParam自动完成,也可以在填充缓冲区时完成。

完成“source.buffer=myArrayBuffer”的那一刻就是这样。当您将该缓冲区播放到最后时,AudioBufferSourceNode将毫无用处。我已经尝试在oneded函数中执行“source.buffer=new_myArrayBuffer”,但它不允许这样做。我尝试了上面另一篇see编辑的文章,但这也不是唯一的问题。这似乎也不是问题所在。编辑:以上文章现在更新我必须问。你没有声音问题吗?我想出来了。fillAudioBuffer函数确实影响了它。函数运行时间刚好足以导致该声音错误。写了C++版本,它没有这个问题。它可以在我的上一台电脑上正常运行,比我现在的电脑慢。Javascript的速度出乎意料地比我想象的要慢。谢谢你的两个缓冲区建议。我听到一个小小的咔嗒声