我正在开发一个 Javascript 音乐应用程序。
离线渲染工作正常,即生成一个缓冲区,在给定时间使用 AudioBufferSourceNode 播放它。时机几乎是完美的。
但我需要生成无法使用 API 的默认节点创建的音调。所以我将声音生成逻辑放在 ScriptProcessorNode 的回调中。
我相当确定我的 ScriptProcessorNode 中的代码足够快,因为一旦开始声音播放,我想要的任何数量的缓冲期都不会出现故障 - 所以及时填充缓冲区可能不是这里的问题。从我的实验中,我发现 ScriptProcessorNode 的 onaudioprocess 事件会定期触发,而不取决于处理器节点的创建时间。这会在应用程序中产生不可预测的延迟:如果用户在回调开始后立即按下一个键,那么它会等到下一个时段播放。
我创建了这个小提琴来演示它。有一个简单的仪器和两个按钮来控制它。播放一个预先录制的缓冲区:
function playBuffer()
{
source = ac.createBufferSource();
source.buffer = buffer;
source.connect(ac.destination);
source.start(0);
};
另一个播放相同的声音但现场直播:
function playLive()
{
processor = ac.createScriptProcessor(4096, 0, 1);
processor.onaudioprocess = function(e)
{
sineStrument.fillBuffer(e.outputBuffer.getChannelData(0), e.outputBuffer.length);
}
processor.connect(ac.destination);
};
使用第一个按钮,您可以生成节奏并听到它完美无缺。您不能使用第二个按钮,因为声音开始大约需要 50 多毫秒。
现在请注意,该仪器非常简单,我认为这里没有计算速度问题。另外,如果你的时间正确,你可以让实时处理的声音与你的点击同步播放——我认为你“只”需要在调用 onaudioprocess 回调之前点击。
1) playBuffer 函数立即播放和 2) 可以使用 playLive 函数获得正确计时的事实告诉我,应该有一种技术方法来获得正确计时的 ScriptProcessorNode。
我该怎么做?为什么播放缓冲区没有固定的开始时间?
我也尝试过减小 ScriptProcessorNode 的缓冲区大小,但声音很快就会失真。为什么会这样?如果回调中的代码不够快,一段时间后声音不会出现故障吗?它不是!