- From: lonce wyse <lonce.wyse@zwhome.org>
- Date: Wed, 25 Jul 2012 21:00:25 +0800
- To: Joe Berkovitz <joe@noteflight.com>
- CC: public-audio@w3.org
- Message-ID: <500FEDE9.1090704@zwhome.org>
Hi -
Yes I realized that as I hit the email send button - however, it
actually isn't the periodicity of the callback that matters. They could
be aperiodic and the buffers to fill could be of different length - as
long as you know what time the sample buffer in the callback represents.
- lonce
On 25/7/2012 8:46 PM, Joe Berkovitz wrote:
>
> One other important point I overlooked: JSAudioNode processing
> callbacks are not sample accurate in terms of absolute time. They may
> jitter around since they precede actual sound output by a variable
> amount depending on the audio pipeline's overall latency at the time.
> The browser is free to play around with this latency to provide glitch
> free output.
>
> So it doesn't really provide you with the "rock solid" timing that you
> might expect.
>
> ...j
>
> On Jul 25, 2012 8:28 AM, "lonce wyse" <lonce.wyse@zwhome.org
> <mailto: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 <tel:978%20314%206271>
>> www.noteflight.com <http://www.noteflight.com>
>>
>
Received on Wednesday, 25 July 2012 13:01:14 UTC