W3C home > Mailing lists > Public > public-audio@w3.org > October to December 2012

Re: MIDI synchronization issues

From: Srikumar Karaikudi Subramanian <srikumarks@gmail.com>
Date: Tue, 2 Oct 2012 05:50:41 +0530
Cc: Chris Wilson <cwilso@google.com>, public-audio@w3.org, Jussi Kalliokoski <jussi.kalliokoski@gmail.com>, Joseph Berkovitz <joe@noteflight.com>
Message-Id: <229FF0CA-3237-412F-97D4-31966CA918B5@gmail.com>
To: James Ingram <j.ingram@netcologne.de>
Hi James,

The tick() function in the gist is not the right approach, I think. If we consider a MIDI sequence that has drum hits spaced 1 sec apart and use PREQUEUE = 500ms (anything less than 1 sec actually) , then the tick() will try to land itself just in time to send out the drum hit, by which time it may already be too late [1] ... unless I'm reading the gist code wrongly.

A better approach would be to ask the system for *regular* tick() callbacks with a period that is *independent* of the message time stamps. Then if we have a PREQUEUE that is some multiple (ex: 3x) of the tick() interval, we can catch up if a large jitter happens and the time stamps become useful to the backend high precision scheduler.

The best way to get reliable periodic callbacks in a browser is to use requestAnimationFrame(). If my reading of your gist code is right, all that is needed is to change the last line from -
	window.setTimeout(tick, delay);
to -
	webkitRequestAnimationFrame(tick); // Gets called at 60Hz usually.

Then, when time stamps begin to be supported in the MIDI implementation, PREQUE = 50ms can give the rock solid timing promised by the underlying implementation. This will also allow a JS player to respond to global tempo changes quickly if there is a tempo slider in the UI. 

Furthermore, in current browsers, it is not possible to guarantee a small enough upper limit on the time difference between a generated event and a JS function called in response. This means that even if you have a "MIDI message sent" callback installed, you may receive that late anyway. It is easier (imho) to assume that the message goes out as expected and plan to do the necessary UI. If the UI is wrong, it would be wrong only up to PREQUEUE.


[1] setInterval and setTimeout are just plain unreliable for music timing in the browser as far as I've seen. I've measured standard deviations of 400ms for such "target times" in Chrome some time ago. In Node.js, though, setInterval is rock solid (deviations ~< 0.4ms) while setTimeout is as goofy as in Chrome. (Node.js has a MIDI npm module btw.)

On 2 Oct, 2012, at 2:29 AM, James Ingram <j.ingram@netcologne.de> wrote:

> Hi Chris,
> I'll put it another way: There is going to be a synchronization problem when the timestamp property on sendMiDIMessage is implemented and PREQUEUE is increased.
> Lets say the sendMIDIMessage timestamps are working as advertised, and we increase PREQUEUE to 500. That would mean in [1] that the reportTimestamp function would only be called ca. every 500ms, and would not be able to report the timestamp as often as it needs to. There is no way, as things stand, for the world outside the while{} loop to report the sending of events inside the loop at the time they are actually sent. I think this problem needs thinking about now. We don't need to wait for sendMIDIMessage timestamps to be implemented.
> Whatever the answer is going to be, I think it also needs to take empty messages into account. Empty messages have lots of uses when synchronizing with other things going on on the same computer. Maybe one of MIDI's more obscure messages could be hijacked for the purpose, but the state of the output device should not change. Maybe someone has an idea in that direction?
> Hope that's a bit clearer.
> best,
> James
> [1] https://gist.github.com/3806262
Received on Tuesday, 2 October 2012 00:21:12 UTC

This archive was generated by hypermail 2.4.0 : Friday, 17 January 2020 19:03:13 UTC