- From: Joe Berkovitz <joe@noteflight.com>
- Date: Fri, 27 May 2016 15:30:43 -0400
- To: Hongchan Choi <hongchan@google.com>
- Cc: Audio Working Group <public-audio@w3.org>
- Message-ID: <CA+ojG-bs98CEwbxzg2ZFHrQGCOrrxeJneSxKmJt6cTT0mJ6bmQ@mail.gmail.com>
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