简体   繁体   English

WebAudio 计时如何工作? 使用 setInterval 是一个糟糕的解决方案吗?

[英]How does WebAudio timing work? Is using setInterval a bad solution?

I'm trying to make a synthesizer/sequencer with the WebAudio API.我正在尝试使用 WebAudio API 制作合成器/音序器。 Mostly trying to make something that can playback a song made up of notes and events like MIDI to control the multiple channels of the synth.主要是尝试制作可以播放由音符和事件(如 MIDI)组成的歌曲的东西,以控制合成器的多个通道。 But I still need to tackle the timing aspect.但我仍然需要解决时间方面的问题。

I've read tutorials on the WebAudio API, but I don't quite understand how timing/scheduling/clock works.我已经阅读了有关 WebAudio API 的教程,但我不太了解时序/调度/时钟是如何工作的。 At first I made a polyphonic synthesizer that played notes for keypresses, and this did not need any consideration for timing.起初我做了一个和弦合成器,可以为按键演奏音符,这不需要任何时间考虑。 I then made the oscillator playback an an array of notes at specific time intervals using setInterval .然后我使用setInterval使振荡器以特定的时间间隔播放一系列音符。 However I have noticed in the past when switching tabs in Google Chrome, the playback rate is significantly slowed down, I assume to be less resource intensive - but other synth libraries didn't have this issue .但是我过去注意到谷歌浏览器中切换标签时,播放速度显着减慢,我认为资源密集度较低 - 但其他合成库没有这个问题 Also I can only assume that using setInterval isn't great for smooth (is buffered the right word?) playback, especially when considering ADSR envelopes oscillators.此外,我只能假设使用setInterval不太适合平滑(缓冲正确的词?)播放,尤其是在考虑 ADSR 包络振荡器时。

From what I am reading, the WebAudio API has an ever-increasing currentTime timer variable.从我读到的内容来看,WebAudio API 有一个不断增加的currentTime计时器变量。 But if notes are stored in an array and I want to cycle it at a set rate, how would the WebAudio timer be manipulated to iterate an array over a set rate?但是,如果音符存储在一个数组中并且我想以设定的速率循环它,那么如何操纵 WebAudio 计时器以在设定的速率上迭代一个数组? My setInterval solution (volume warning) doesn't take into account the WebAudio timer at all, and just calls voice() with setInterval to play a note, overwriting the last voice played.我的setInterval 解决方案(音量警告)根本不考虑 WebAudio 计时器,只是使用setInterval调用voice()来播放音符,覆盖上次播放的语音。

Are there better or efficient ways to playback/loop a sequence of notes other than setInterval ?除了setInterval之外,是否有更好或有效的方法来播放/循环一系列音符?

Just an update to clarify: When I wrote this question, I was using setInterval to play a sequence of notes at fixed intervals (eg unscheduled--constantly starting/stopping oscillators) and was wondering about more reliable ways to play notes.只是一个更新澄清:当我写这个问题时,我正在使用setInterval以固定间隔播放一系列音符(例如,计划外——不断地启动/停止振荡器),并且想知道更可靠的演奏音符的方法。 I found that a better solution would be to use setValueAtTime on osc.frequency as well as a GainNode .我发现更好的解决方案是在osc.frequencyGainNode上使用setValueAtTime For a simple prototype synth, this works well, but a more advanced synth could use the timer on osc.start and osc.stop .对于简单的原型合成器,这很有效,但更高级的合成器可以使用osc.startosc.stop上的计时器。 The problem is looping the song .问题是循环播放歌曲 In order to loop, I need to constantly schedule more notes so that by the end of the song, it starts over.为了循环播放,我需要不断地安排更多的音符,以便在歌曲结束时重新开始。 I can use setInterval to schedule the entire song loop, but it still has to keep time with the song playing , and setInterval (and even Web Workers' onmessage calls) could be slowed down when the tab is inactive for example. I can use setInterval to schedule the entire song loop, but it still has to keep time with the song playing , and setInterval (and even Web Workers' onmessage calls) could be slowed down when the tab is inactive for example. setInterval's clock isn't even reliable, so I simply check every 5ms if (currentTime >= songTime) and schedule if condition is met. setInterval 的时钟甚至不可靠,所以我只是每 5 毫秒检查一次 if (currentTime >= songTime)并安排是否满足条件。 That method may not be too efficient.这种方法可能不太有效。 What I have so far . 到目前为止我所拥有的

I wrote this article a few years ago: https://www.html5rocks.com/en/tutorials/audio/scheduling/ .我几年前写了这篇文章: https : //www.html5rocks.com/en/tutorials/audio/scheduling/ It gets into the differences between the web audio timers and setInterval;它探讨了网络音频计时器和 setInterval 之间的差异; in short, you can't "manipulate time" in the web audio clock, it's driven by a hardware clock in your sound card.简而言之,您不能在网络音频时钟中“操纵时间”,它是由声卡中的硬件时钟驱动的。 You can schedule events to occur in its time frame, though, using setInterval as a very jittery/ slower cycle reminder to schedule new events.不过,您可以安排事件在其时间范围内发生,使用 setInterval 作为非常紧张/较慢的周期提醒来安排新事件。

As for your switching-tabs issue, this is a 1Hz rate limiter that most modern browsers have to avoid power cost from people using setInterval as a rendering timer (eg setInterval with an interval of 16ms to try to schedule every frame of video).至于你的切换标签问题,这是一个 1Hz 速率限制器,大多数现代浏览器必须避免使用 setInterval 作为渲染计时器的人的电力成本(例如,setInterval 的间隔为 16ms 以尝试安排视频的每一帧)。 You can avoid it in two ways - a hack using Web Workers, which I use in my metronome demo ( https://github.com/cwilso/metronome ), or you can hook in to when the window loses focus (onblur event firing on the window object) to start scheduling more than 1s of events at a time.您可以通过两种方式避免它 - 使用 Web Workers 进行黑客攻击,我在我的节拍器演示 ( https://github.com/cwilso/metronome ) 中使用它,或者您可以在窗口失去焦点时挂钩(onblur 事件触发)在 window 对象上)开始一次调度超过 1s 的事件。 The only problem is when the window gets focus again (onfocus event fires on the window object), you'll have up to a second's worth of events already scheduled in Web Audio - you couldn't switch back into the window and immediately hit "stop", eg唯一的问题是当窗口再次获得焦点时(onfocus 事件在窗口对象上触发),您将在网络音频中安排最多一秒钟的事件——您无法切换回窗口并立即点击“停止”,例如

setInterval by itself isn't a great solution for musical timing of repetitive rhythms, since it will jitter (ie be delayed) when there is substantial other stuff going on in the main thread (including garbage collection). setInterval 本身并不是重复节奏的音乐计时的一个很好的解决方案,因为当主线程中发生大量其他事情(包括垃圾收集)时,它会抖动(即被延迟)。 You'll start to hear the jitter, especially on less-capable CPUs.您会开始听到抖动,尤其是在功能较弱的 CPU 上。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM