- From: Chris Wilson <cwilso@google.com>
- Date: Sun, 29 Jul 2012 12:08:39 -0700
- To: Joe Berkovitz <joe@noteflight.com>
- Cc: lonce wyse <lonce.wyse@zwhome.org>, public-audio@w3.org
- Message-ID: <CAJK2wqUnG4cjn2zvMZg4KgThqQuqDSbMKN9T1cFtDDW34NwMkA@mail.gmail.com>
The way I've done this, BTW, is to set up a setTimeout loop that schedules the noteOns for some set amount of time ahead. On Wed, Jul 25, 2012 at 5:40 AM, Joe Berkovitz <joe@noteflight.com> wrote: > Rate or tempo changes can be computed an arbitrary amount of time in > advance, just like notes. The sequencer's job is to convert logical or > musical time (which can flow at a variable rate) into absolute time, which > is just a matter of more linear math. > > I think that the real issue is the amount of time it takes for the > sequencer to respond to real time user interaction that affects playback, > e.g. a tempo slider gesture to name just one of many examples. > > The good news is that the setTimeout throttling limitations only affect > windows that the user is not interacting with, in which case this issue > doesn't apply. > > Having said all that I am also curious whether notes are schedulable fron > onaudioprocess handlers but I see no reason why not... nor any overriding > reason to do so yet. > > ...Joe > On Jul 25, 2012 8:28 AM, "lonce wyse" <lonce.wyse@zwhome.org> wrote: > >> >> Hi - >> Of course, you would want to generate events as short a time in to >> the future as possible in order to stay responsive to rate (or tempo) >> changes. >> Ideally a JavaScriptAudioNode could be used as the event generator. >> It's onaudioprocess() method could check the length of the output buffer it >> is passed, and do nothing else but call "note on" events for other nodes it >> wants to play within that short period of time. >> I haven't tried that yet, but would noteon events be handled properly >> when generated in this "just in time" manner? Would this be a violation of >> protocol to use a onaudioprocess() as what would amount to a rock-solid >> sample-accurate periodic callback function? >> >> Best, >> - lonce >> >> >> >> On 25/7/2012 12:40 AM, Joseph Berkovitz wrote: >> >> HI Adam, >> >> I think one general way to structure sequencer playback is as follows >> -- I've used this approach with WebAudio successfully in the past: >> >> 1. Just before starting playback, take note of the AudioContext's >> currentTime property. Add a small time offset to it, say 100 ms. The >> result will be your performance start time, corresponding to time offset >> zero in your sequencer data. (The time offset provides a short window in >> which to schedule the first events in the sequence). >> >> 2. Create a scheduler function that will run periodically, which >> examines the AudioContext's currentTime and subtracts the previously >> captured startTime. That gives you a "current performance time" at the >> moment the callback occurs, expressed in terms of your sequencer >> data. Then create AudioNodes representing all sequencer events that occur >> within an arbitrary time window after this current performance time (say, >> several seconds) and schedule them with noteOn/noteOff. >> >> 3. Call the function immediately, and also use setInterval() or >> setTimeout() to schedule callbacks to the above function on some reasonable >> basis, say every 100-200 ms. The exact interval is not important and can be >> tuned for best performance. >> >> This approach is relatively insensitive to callback timing and in >> general allows audio to be scheduled an arbitrary interval in advance of >> its being played. >> >> ...Joe >> >> >> On Jul 24, 2012, at 11:40 AM, Adam Goode wrote: >> >> Hi, >> >> Yesterday I tried to write an extremely simple sequencer using >> webaudio. My goal was to have a tone play periodically, at a >> user-selectable low frequency interval. >> >> The main problem I ran into was the difficulties in scheduling events >> synchronized with the a-rate clock. >> >> If I want to play a tone twice per second, I want to call this code in >> a loop, indefinitely: >> >> var startTime = .... >> var o = c.createOscillator(); >> o.connect(c.destination); >> o.noteOn(startTime); >> o.noteOff(startTime + 0.1); >> >> I can't just put it in a loop, I need to schedule this in a callback, >> when necessary to fill the event queue. But what callback to use? >> setInterval is not appropriate, since the setInterval clock will skew >> quickly from c.currentTime. And busy looping with setInterval(0) will >> consume a lot of CPU and gets throttled when switching tabs (try putting >> the drum machine demo in a background tab and see). >> >> My solution was this: >> >> var controlOscillator = c.createOscillator(); >> controlOscillator.frequency.value = 2; >> var js = c.createJavaScriptNode(256, 1, 0); >> controlOscillator.connect(js); >> >> js.onaudioprocess = function(e) { >> ... detect positive zero crossing from control oscillator ... >> if (zeroCross) { >> var o = c.createOscillator(); >> o.connect(c.destination); >> var startTime = ... zero crossing offset + playbackTime ... >> o.noteOn(startTime); >> o.noteOff(startTime + 0.1); >> } >> }; >> >> >> This does work (except for missing playbackTime >> https://bugs.webkit.org/show_bug.cgi?id=61524, needing to connect the >> javascript node to destination, and another bug on chrome >> http://crbug.com/138646), but is awkward. There is also the question of >> having a disconnected graph: I am sending control data, not audio data, so >> I don't want to connect it to destination. >> >> I essentially want to have a callback for getting new control data, to >> keep the event pipeline filled without overflowing any noteOn buffer or >> falling behind. Is the javascript node appropriate for this? I feel like >> there could be something more explicit, like a setInterval off of the audio >> context. >> >> >> >> Adam >> >> >> >> ... . . . Joe >> >> *Joe Berkovitz* >> President >> >> * Noteflight LLC * >> 84 Hamilton St, Cambridge, MA 02139 >> phone: +1 978 314 6271 >> www.noteflight.com >> >> >>
Received on Sunday, 29 July 2012 19:09:08 UTC