网络音频振荡器在 Chrome 中意外地从一个频率滑到另一个频率
Web Audio oscillators unexpectedly glide from one frequency to another in Chrome
我将要描述的行为发生在 Chrome 44 中,但不会发生在 Firefox 40 中。
如果您创建一个振荡器,将其频率设置为 220 Hz,然后在一秒钟后将频率更改为 440 Hz,您会听到明显的滑音效果:不是立即从 220 更改为 440,而是振荡器 从原始频率滑行 到新频率。
下面的代码说明了这种现象:
var ac = new AudioContext();
var osc = ac.createOscillator();
osc.connect( ac.destination );
osc.type = 'sawtooth';
osc.frequency.value = 220;
osc.start( 0 );
window.setTimeout( function() {
osc.frequency.value = 440;
}, 1000 );
window.setTimeout( function() {
osc.stop( 0 );
}, 2000 );
我已经检查了 OscillatorNode 对象的文档,但没有提及此行为。
我也搜索过 Google,但(令人惊讶的是)我找不到任何其他提及此现象的内容。
这是怎么回事?这似乎不是正确的行为。如果我想让频率 滑动 ,我会使用 linearRampToValueAtTime() 方法。将频率直接设置为特定值应该只是...这样做。
这只是一个错误吗?我知道这个 API 仍然在不断变化,但这似乎是一个非常明显的错误 - 这不会通过最粗略的测试。但我也无法想象 Google 会如此 故意 .
实现它
最重要的是:有解决方法吗?
很确定这是一个错误。
我在规范中找不到任何说明 value
在 AudioParam
上的直接赋值应该进行任何类型的插值。
它可能没有被注意到,因为通常人们可能会使用自动化方法修改值。这让我想到了你的解决方法问题......
如果你真的想要一个明确的延迟,你可以这样做(注意没有 setTimeout
)。
// change the value to 440Hz 1 second from now
osc.frequency.setValueAtTime( 440, ac.currentTime + 1 );
如果您希望能够立即更改频率(例如,响应用户操作),您可以这样做:
osc.frequency.setValueAtTime( 440, 0 );
希望对您有所帮助。
顺便说一句,你应该考虑为此提出一个问题 (https://code.google.com/p/chromium/issues/list)。
这是内置的"dezippering"效果,工作组已经反复讨论了好几次。截至 6 月,工作组最终决定删除 dezippering(状态:https://github.com/WebAudio/web-audio-api/issues/76). So yeah, this is a Chrome "bug" - https://code.google.com/p/chromium/issues/detail?id=496282)。在修复之前,请按照 Kevin 的建议使用 setValueAtTime()。
我将要描述的行为发生在 Chrome 44 中,但不会发生在 Firefox 40 中。
如果您创建一个振荡器,将其频率设置为 220 Hz,然后在一秒钟后将频率更改为 440 Hz,您会听到明显的滑音效果:不是立即从 220 更改为 440,而是振荡器 从原始频率滑行 到新频率。
下面的代码说明了这种现象:
var ac = new AudioContext();
var osc = ac.createOscillator();
osc.connect( ac.destination );
osc.type = 'sawtooth';
osc.frequency.value = 220;
osc.start( 0 );
window.setTimeout( function() {
osc.frequency.value = 440;
}, 1000 );
window.setTimeout( function() {
osc.stop( 0 );
}, 2000 );
我已经检查了 OscillatorNode 对象的文档,但没有提及此行为。
我也搜索过 Google,但(令人惊讶的是)我找不到任何其他提及此现象的内容。
这是怎么回事?这似乎不是正确的行为。如果我想让频率 滑动 ,我会使用 linearRampToValueAtTime() 方法。将频率直接设置为特定值应该只是...这样做。
这只是一个错误吗?我知道这个 API 仍然在不断变化,但这似乎是一个非常明显的错误 - 这不会通过最粗略的测试。但我也无法想象 Google 会如此 故意 .
实现它最重要的是:有解决方法吗?
很确定这是一个错误。
我在规范中找不到任何说明 value
在 AudioParam
上的直接赋值应该进行任何类型的插值。
它可能没有被注意到,因为通常人们可能会使用自动化方法修改值。这让我想到了你的解决方法问题......
如果你真的想要一个明确的延迟,你可以这样做(注意没有 setTimeout
)。
// change the value to 440Hz 1 second from now
osc.frequency.setValueAtTime( 440, ac.currentTime + 1 );
如果您希望能够立即更改频率(例如,响应用户操作),您可以这样做:
osc.frequency.setValueAtTime( 440, 0 );
希望对您有所帮助。
顺便说一句,你应该考虑为此提出一个问题 (https://code.google.com/p/chromium/issues/list)。
这是内置的"dezippering"效果,工作组已经反复讨论了好几次。截至 6 月,工作组最终决定删除 dezippering(状态:https://github.com/WebAudio/web-audio-api/issues/76). So yeah, this is a Chrome "bug" - https://code.google.com/p/chromium/issues/detail?id=496282)。在修复之前,请按照 Kevin 的建议使用 setValueAtTime()。