- From: Chris Wilson <cwilso@google.com>
- Date: Fri, 14 Dec 2012 11:12:55 -1000
- To: Marcos Caceres <marcos@marcosc.com>
- Cc: Jussi Kalliokoski <jussi.kalliokoski@gmail.com>, "public-audio@w3.org" <public-audio@w3.org>
- Message-ID: <CAJK2wqUtxDdj60tYRU02iEXLz+qhhxeWf+PG8c4TfG6zdVzSEQ@mail.gmail.com>
I don't actually know of any systems that do this (future-scheduling of MIDI input), personally, but that's not the point of timestamps in my opinion. The point of the timestamps on input is based on the fact that the underlying system (device driver, e.g.) will get the MIDI input likely on a much higher precision time clock than it will be able to pass the message into a JavaScript callback (on the main thread, which may get blocked by layout, etc.). The higher precision of that timestamp allows, e.g. a higher-precision recording of the timing of input messages in a sequence; for example, if you're recording the MIDI messages from a live piano controller, you will want the subtleties of that timing recorded - you may have some lag when passing through to send(), but when playing back that recorded sequence later, your timestamps will be more precise. Likewise, the timestamps on send need to be on a consistent time clock, to keep a rock-solid "sequence timing" going - that's why we use performance timing rather than time.now() - and using offsets would require finding the "current time" when send() is called frequently. You could make it an offset, rather than an absolute; however, that would require coders to call window.performance.now() more frequently. To schedule the next note of a sequence with absolute times, presuming "note" is an object that contains the next note's data and timestamp as an absolute start time: out.send( note.data, sequence.startTime + note.timestamp ); if you had offsets instead: out.send( note.data, note.timestamp - ( window.performance.now() - sequence.startTime ); There are other ways to structure this, of course - and in those cases, you may not have this kind of offset. For example, Standard MIDI Files record offsets from the last note - but that's actually not as relevant as it seems, because "the last note" is not where you're likely scheduling THIS note. The main point is, it's going to be easier to not have to convert between a time offset *from the current time* all the time. The symmetry with receiving is also a very good thing, of course. Your example is a relevant counter-example - but keep in mind, it is quite rare that you would want to actually call send() on a large number of notes at once, because then you can't cancel them or control tempo. I've had it on my list to do a sequence-playing example for a while; hope to get to that in the next couple of weeks. -Chris On Fri, Dec 14, 2012 at 10:27 AM, Marcos Caceres <marcos@marcosc.com> wrote: > > > On Friday, December 14, 2012 at 8:12 PM, Jussi Kalliokoski wrote: > > > > > Not necessarily. Some platform MIDI APIs have an internal clock and > allow MIDI messages to be sent and processed ahead of time, so when you > receive a MIDI message, it might not be supposed to take effect > immediately. The timestamps being synchronized with DOMHRTF essentially let > you leverage/emulate this feature without exposing meaningless details > about the underlying API, such as its internal clock. > So 2 things: > > 1. the spec is not clear with regards to this, as it says: "Let event be a > newly constructed MIDIEvent, with the timestamp attribute set to the time > the message was received by the system". That doesn't seem to match what > you described above. > 2. how common is this use case? or how common are these devices? (I > honestly don't know, but it would be good to have some data). > > I presume most people will just want a little delay in sending data. Here > is two things I just made for fun by changing the API to use delay instead > of timestamp: > > for(var i=2, fib=[0,1]; i<12; i++){ > fib[i] = fib[i-2] + fib[i-1]; > output.send([0x91, fib[i] ,0x5f], (100 * fib[i])); > } > > > for (var l = 128, i = 0; i < l; i++) { > var value = Math.floor(l * (Math.sin(i * 0.09)) + l) / 2; > output.send([0x91, value ,0x5f], (50 * i)); > }; > > > The current API would require me to prefix everything with > performance.now() or an alias - which is inconvenient for my use cases > above. > > I'm still not sure what the most common use cases for this API will be. > > -- > Marcos Caceres > > > > >
Received on Friday, 14 December 2012 21:13:27 UTC