Comments on AudioWorklet examples

Hongchan,

Thank you for the new writeups on AudioWorklet. I'm sorry it's taken me a
long time to respond, I been getting over a bad flu and this is my first
week back.

This facet of the spec is absolutely the most important thing we're working
on, and I've thoroughly compared the new examples with the old ones in the
current editor's draft (see
https://www.w3.org/TR/webaudio/#a-bitcrusher-node and following). I don't
see anything that is definitely wrong, but a few important questions have
been left to the imagination. The original bitcrusher did not surface some
of the important questions like how to pass initialization values to the
audio thread, or how AudioParams show up in the main thread. The later
examples like the VU/clip meter got into this territory and were more
illustrative, using postMessage and onMessage to show the complete
lifecycle.

Looking at
https://github.com/WebAudio/web-audio-api/wiki/AudioWorklet-Examples here's
what I see as things that need to be clarified:

1. You're passing initial values for the params "bitDepth" and
"frequencyReduction" into the AudioWorkletNode constructor via
AudioNodeOptions. This is fine, but someone might assume that these values
are magically propagated into the corresponding AudioParams. Maybe you
meant for that to happen, but it was never said: but there is nothing in
the definition of AudioNodeOptions that says a key/value pair whose key is
named the same as an AudioParam automatically acts as an initializer for
it. Also, some AudioNodeOptions values may not correspond to AudioParams.

Based on our previous discussion, I'd expect that there needs to be a
subclass constructor that explicitly copies these values out of the
AudioNodeOptions into the new node's AudioParams, like this:

class BitcrusherNode extends AudioWorkletNode {
  constructor(ctx, options) {
    super(ctx, 'Bitcrusher', options);
    if (options.hasOwnProperty('bitDepth') {
      this.bitDepth.value = options.bitDepth;
    }
    // ...initialize other params, initial state up front, possibly
utilizing postMessage()...
}

2. When are the params for a node determined, and when can they change?
We've changed up the lifecycle quite a bit now, so I'm not sure what the
answer is. I recall that we went to some trouble before to ensure that the
set of params was known at the actual time that an AudioWorkerNode was
instantiated, just like they would be for a native node.

The only opportunity we have to discover parameter descriptors is before
the success of the promise from the script import for a node type.  So
*maybe* it works like this: after the script is imported for an
AudioWorkletProcessor, the Processor gets instantiated once prior to the
success of the Promise and its paramDescriptors getter is examined; the
result determines the set of parameters exposed by subsequent nodes of that
type. The Processor instance is then thrown away; its only purpose was to
figure out what params exist for this node type.

This would make it hard to add/remove parameters on the fly. But I don't
know that this is important.

3. In the actual spec, I think it would be a good idea to mock up a
complete node that not only has a couple of AudioParams but also has some
non-param aspects, like a read-only attribute reflecting the state of the
audio side (like "clip" and "volume" for the VU meter), or a method that
mutates the state of the audio side (say, to reset the accumulated
smoothing state of the VU meter). A pass-through VU meter that acts as a
pass-through GainNode would fit the bill.

Best,
...Joe

Received on Friday, 27 May 2016 19:31:12 UTC