【发布时间】:2013-11-09 03:31:43
【问题描述】:
我正在开发一个 Javascript 音乐应用程序。
离线渲染工作正常,即生成一个缓冲区,使用 AudioBufferSourceNode 在给定时间播放它。时机几乎完美。
但我需要生成无法使用 API 的默认节点创建的音调。所以我将声音生成逻辑放在 ScriptProcessorNode 的回调中。
我相当肯定我的 ScriptProcessorNode 中的代码足够快,因为一旦开始播放声音就可以在我想要的任意数量的缓冲期中正常播放 - 所以及时填充缓冲区可能不是这里的问题。从我的实验中,我发现 ScriptProcessorNode 的 onaudioprocess 事件会定期触发,而不取决于处理器节点的创建时间。这会在应用程序中产生不可预测的延迟:如果用户在回调开始后立即按下一个键,那么它会等到下一个时段播放。
我创建了this fiddle 来演示它。有一个简单的仪器和两个按钮来控制它。播放一个预先录制的缓冲区:
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 的缓冲区大小,但声音很快就会失真。为什么会这样?如果回调中的代码不够快,那么一段时间后声音不会出现故障吗?它没有!
【问题讨论】:
-
缓冲区延迟很可能与声卡的延迟有关,因为浏览器无法使用 ASIO 等低延迟驱动程序,这是意料之中的。预生成的样本可以排队等待缓冲区,而实时样本生成到 current 缓冲区(即,无需检查,可能是双倍或三倍缓冲,这会导致延迟)。
标签: javascript audio web-audio-api