W3C home > Mailing lists > Public > public-audio@w3.org > July to September 2012

Re: Reflections on writing a sequencer

From: Stuart Memo <stuartmemo@gmail.com>
Date: Tue, 24 Jul 2012 17:16:13 +0100
Message-ID: <CAHZEqmqfHiLdqCTQ7jaN0eajMKOEdEQk9ZHA2sBZ+tPDjH9tew@mail.gmail.com>
To: Adam Goode <agoode@google.com>
Cc: Audio Working Group <public-audio@w3.org>
I've seen examples of drum machines using requestAnimationFrame for this
purpose.

https://developer.mozilla.org/en/DOM/window.requestAnimationFrame

Does this help achieve what you want?

On 24 July 2012 16:40, Adam Goode <agoode@google.com> 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
>
>
>
Received on Tuesday, 24 July 2012 16:16:40 GMT

This archive was generated by hypermail 2.2.0+W3C-0.50 : Tuesday, 24 July 2012 16:16:41 GMT