TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Metronomes in JavaScript

205 pointsby baylearnover 5 years ago

18 comments

rock_artistover 5 years ago
As an audio developer, making a timer metronome is the wrong approach. Still, many metronome apps with this design flaw exists and... they perform bad. (that&#x27;s why prescheduled audio events works best...)<p>Timers in general will jitter.<p>Audio processing usually involves a callback to process an audio block (array of audio samples... floats).<p>To simplify things, this audio block runs on realtime thread and copies the block to desired output. you&#x27;re guaranteed it&#x27;ll be continuous between each call. (you can cause overflow&#x2F;stutter if you hold it for too long).<p>With setTimer approaches each callback WILL have offset. But if you need to synchronize things or your metronome needs to run with other audio, it WILL be jerky. That&#x27;s why a proper metronome would also be &#x27;sample accurate&#x27;.<p>WebAudio &#x2F; AudioContext was made exactly to solve that!<p>similar to common audio processing standard, you end up getting a callback and usually need to use WebAsm&#x2F;C++ under the hood to keep the golden DSP rule - never allocate on block processing callback.<p>btw, on Firefox 69 (macOS) only the pre-scheduled audio made a sound :)
评论 #20936615 未加载
评论 #20936715 未加载
评论 #20940630 未加载
评论 #20938068 未加载
评论 #20942640 未加载
danShumwayover 5 years ago
This is a really great writeup -- it&#x27;s concise and to the point, the demos are good.<p>It&#x27;s not just audio; timing in general is kind of terrible in Javascript. Spectre&#x2F;Meltdown made it worse, because now some browsers introduce arbitrary jitter for security purposes. The advice I&#x27;ve always seen is to try and avoid ever doing your own timing in Javascript -- use `requestAnimationFrame` instead of `setTimeout`, use web audio scheduling instead of `setTimeout`. Basically, avoid `setTimeout` for most high-precision things if possible.<p>I don&#x27;t know what the status is with shared array buffers and WASM. At one point I was very excited about the potential of WASM to get around some of the problems above, but last I checked, this was being partially held back by the same security concerns.
评论 #20953416 未加载
评论 #20942369 未加载
评论 #20942375 未加载
namukangover 5 years ago
If anyone actually needs a simple metronome that tracks time precisely using the Web Audio API, I built one recently: <a href="https:&#x2F;&#x2F;dkthehuman.com&#x2F;metronome" rel="nofollow">https:&#x2F;&#x2F;dkthehuman.com&#x2F;metronome</a><p>- It&#x27;s fast (the #1 metronome app on the iOS App Store taking 7+ seconds to start up on my iPhone was the reason I built this)<p>- It has keyboard shortcuts on desktop (use arrow keys to adjust BPM and space bar to toggle playing)<p>- It&#x27;s a progressive web app so you can add it to your home screen and it&#x27;ll behave like an app
评论 #20941617 未加载
评论 #20944010 未加载
评论 #20938711 未加载
评论 #20937338 未加载
whiddershinsover 5 years ago
Great article.<p>I want to weigh in about this whole perceivable jitter thing.<p>I think it’s important when making music related programming decisions to recognize there’s a whole area of perception in between actually conscious “hey that metronome is off!” and actually being imperceptible. In that area the feel and impact of music can be altered while no one can pinpoint why.<p>For safety’s sake I think sub-millisecond timing in controllers and things like metronomes needs to be the standard.<p>The ideal should be audio rate accuracy, when it can be reasonably achieved.<p>It’s really bad to fall in the trap of thinking that just because no one can point out a problem, it isn’t having an effect. Especially with audio where people have trouble explaining what they are hearing.
评论 #20941211 未加载
评论 #20941432 未加载
srikuover 5 years ago
The age old solution to this problem continues to work just fine - have jitter-tolerant low frequency scheduler callbacks that schedule events using an accurate clock (sample time) a short way (100ms or so) into the future. That way you get both accurate audio with timely response. Been doing this kind of thing for 20+ years now .. web or noweb.<p>I use an encapsulated &quot;steller&quot; library to do this with JS on the web. Steller can sync graphics with audio too.<p>Really wish the joint &quot;get time stamp&quot; function that gives current DOMHiresTimestamp and the synchronized AudioContext currentTime were available on all browsers.<p>Steller - <a href="https:&#x2F;&#x2F;github.com&#x2F;srikumarks&#x2F;steller" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;srikumarks&#x2F;steller</a><p>Taka Keeper - <a href="http:&#x2F;&#x2F;talakeeper.org&#x2F;talas.html" rel="nofollow">http:&#x2F;&#x2F;talakeeper.org&#x2F;talas.html</a> (targeted at South Indian classical music forms, so not all may get the terms)<p>Edit: Fixed autocorrect errors
braindongleover 5 years ago
Nicely done. I wonder: what is the use case that prompted this investigation? 40-50 milliseconds is correct in terms of latency that musicians notice. If you&#x27;re aiming at any realtime musical collaboration over the internet, the Big Problem is network latency. Unpredictable and just too long. And, if you&#x27;re not working over the internet, why use a browser?<p>Edit: <a href="https:&#x2F;&#x2F;hello-magenta.glitch.me" rel="nofollow">https:&#x2F;&#x2F;hello-magenta.glitch.me</a> seems to be the use case. Cool and inevitable that this would be worked-on, but after spending years with both algorithmically-supported composition and all-human composition, I&#x27;m skeptical. There is a special sauce that machines will never grok. Or, I&#x27;m wrong.
评论 #20936974 未加载
saagarjhaover 5 years ago
I wrote a bad metronome using setInterval at some point (<a href="http:&#x2F;&#x2F;server.saagarjha.com&#x2F;metronome" rel="nofollow">http:&#x2F;&#x2F;server.saagarjha.com&#x2F;metronome</a>) and had somewhat different issues: if you moved the page to the background, my browser would throttle it and coalesce the events so it wouldn’t actually “tick” at the right rate anymore. And for whatever reason, in WebKit setting 60 bpm just doesn’t make any noise at all…
kmntover 5 years ago
hard to imagine an environment with worse input response and timing behavior than web browsers. Buffering audio output would be easiest way to compensate for callback jitter, but shortening delay between user input and a note playing seems unresolvable.
javajoshover 5 years ago
Cool article, but there&#x27;s one additional experiment worth trying: use recursive `requestAnimationFrame()` calls. On most browsers this will give you a relatively steady 60fps&#x2F;17ms callback rate.<p><a href="https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;API&#x2F;window&#x2F;requestAnimationFrame" rel="nofollow">https:&#x2F;&#x2F;developer.mozilla.org&#x2F;en-US&#x2F;docs&#x2F;Web&#x2F;API&#x2F;window&#x2F;requ...</a>
gatherhuntererover 5 years ago
This is intended for game loops but it is a nice timer that targets iterations per second (FPS) using requestAnimationFrame. This is my preferred solution when I cannot just read the system clock on a recursive setTimeout.<p><a href="http:&#x2F;&#x2F;pixijs.download&#x2F;next&#x2F;docs&#x2F;PIXI.Ticker.html" rel="nofollow">http:&#x2F;&#x2F;pixijs.download&#x2F;next&#x2F;docs&#x2F;PIXI.Ticker.html</a>
menssenover 5 years ago
I don&#x27;t know the answer to this, but I&#x27;ve always been genuinely curious: how accurate is the Date object?<p>setInterval&#x27;s minimum interval is ~15ms [1], so shouldn&#x27;t something like...<p>setInterval(() =&gt; (new Date()).valueOf() % DESIRED_TICK_INTERVAL &lt; 15 &amp;&amp; tickTheMetronome(), 15)<p>...get you within 15ms accuracy, and it can probably be reduced in Chrome et al?<p>[1] <a href="http:&#x2F;&#x2F;www.adequatelygood.com&#x2F;Minimum-Timer-Intervals-in-JavaScript.html" rel="nofollow">http:&#x2F;&#x2F;www.adequatelygood.com&#x2F;Minimum-Timer-Intervals-in-Jav...</a>
评论 #20937378 未加载
bezieioover 5 years ago
This is similar to a problem I ran into when building Bezie. I needed to keep track of the current tempo to send out MIDI clock events. I ended up using a web worker since `setInteral` was unreliable in backgrounded tabs. Here&#x27;s the worker: <a href="https:&#x2F;&#x2F;github.com&#x2F;jperler&#x2F;bezie&#x2F;blob&#x2F;master&#x2F;app&#x2F;workers&#x2F;tick.js" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;jperler&#x2F;bezie&#x2F;blob&#x2F;master&#x2F;app&#x2F;workers&#x2F;tic...</a>
sheerunover 5 years ago
If you want something really accurate and resistant to any problems with CPU and drift in tickers, then you need to schedule ticks by yourself by reading e.g. performance.now(), like so: <a href="https:&#x2F;&#x2F;gist.github.com&#x2F;sheerun&#x2F;00e358e7bdbcd2088573e4b7b921ce67" rel="nofollow">https:&#x2F;&#x2F;gist.github.com&#x2F;sheerun&#x2F;00e358e7bdbcd2088573e4b7b921...</a><p>Above example will indefinitely beat with 60bpm (10ms accuracy)
评论 #20941332 未加载
cyberferretover 5 years ago
This brings back so many vivid memories of me trying to write a hybrid mobile app a few years ago which had a metronome feature. I wrestled with a pure Javascript metronome clicker for so long, and eventually built that component using WebAudio which was much more accurate and reliable.<p>I did start writing a blog post about it but never finished it. This article is a much better and more in depth analysis of the problem anyhow.
ZoomZoomZoomover 5 years ago
Don&#x27;t know about JS, but speaking of metronomes in general, for Android there&#x27;s a few of them on F-Droid, and last time I checked, the <i>only one</i> that worked consistently is the one that&#x27;s integrated in an old app Practice Hub. I don&#x27;t get it, my phone has a clock that seems to work ok, how hard can it be to click in time?
hughesover 5 years ago
I enjoyed reading this. Playing with a problem is such a great way to understand it. The charts are hard to read though - I wish they showed something like absolute error, or at least omitted the initial zero point so the y-axis could be centered around the target.
onemoresoopover 5 years ago
&gt;and if you can, move any expensive work that you have to do from the main thread to a Worker.<p>And if you can, move away from the browser to native.<p>And if you can use a hardware midi clock or just a standalone metronome.
delvinjover 5 years ago
Very interesting analysis.<p>I used to use google metronome but the constant hiccups were annoying. I wonder if they are using Web Audio scheduling or setInterval().