Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TAG issue: Constructibility & De-sugaring of static methods #250

Closed
chrislo opened this issue Oct 17, 2013 · 7 comments
Closed

TAG issue: Constructibility & De-sugaring of static methods #250

chrislo opened this issue Oct 17, 2013 · 7 comments
Assignees
Labels
status: ready for editing w3c-tag-tracker Group bringing to attention of the TAG, or tracked by the TAG but not needing response.
Milestone

Comments

@chrislo
Copy link
Member

chrislo commented Oct 17, 2013

The following issue was raised by the W3C TAG as part of their review of the Web Audio API

Constructibility & De-sugaring of static methods

The current API defines 26 interfaces:

$ cat webaudio.idl | grep -i interface | cut -d " " -f 2
AudioContext
OfflineAudioContext
OfflineAudioCompletionEvent
AudioNode
AudioDestinationNode
AudioParam
GainNode
DelayNode
AudioBuffer
AudioBufferSourceNode
MediaElementAudioSourceNode
ScriptProcessorNode
AudioProcessingEvent
PannerNode
AudioListener
ConvolverNode
AnalyserNode
ChannelSplitterNode
ChannelMergerNode
DynamicsCompressorNode
BiquadFilterNode
WaveShaperNode
OscillatorNode
PeriodicWave
MediaStreamAudioSourceNode
MediaStreamAudioDestinationNode

Of these, only two are marked constructible:

$ cat webaudio.idl | grep -A 1 -i constructor | grep interface | cut -d " " -f 2
AudioContext
OfflineAudioContext

Most of the types represented by the non-constructable interfaces are visible in the API through normal use. For instance, to get a PannerNode instance a developer currently uses:

var panner = context.createPanner();

Where context is an instance of AudioContext (or one of its subclasses). Prickly questions arise from this arrangement:

  1. Assuming that the static methods on the context are desirable shortcuts for wiring up the context of a Node instance to the context against which it runs, how does that context get set in a way that would allow pure JS objects to describe it?
  2. By what privileged mechanism does the system create instances of these types if they do not have constructors?
  3. Are these types in any way subclassable? If not, why not?
  4. If the intent is to mirror other DOM APIs, it's curious to have create*() methods but no factory (e.g.: createElement("tagname"))

Adding constructors and context-setting methods (or constructor params) for most of the interfaces that lack them would answer #'s 1 and 2 and largely obviate 4. E.g.:

// A possible de-sugaring for createPanner() when ctors are defined:
AudioContext.prototype.createPanner = function() {
    var p = new PannerNode();
    p.context = this;
    return p;   
};

// An alternative that provides the context via the PannerNode ctor:
AudioContext.prototype.createPanner = function() {
    return new PannerNode({ context: this });
};

// An alternative that uses a positional context param:
AudioContext.prototype.createPanner = function(attributes) {
  return new PannerNode(this, attributes);
};

Either constructor style allows these AudioNode types to conceptually be modeled more cleanly as JS objects which could self-host.

Of course, this requires answering the follow-on questions "what happens if the context is invalid, changes, or is never set?", but those are reasonable to ask and their answers don't need to be complicated (certainly not for v1).

An alternative design might locate the constructors on the context directly, but this seems to create as many problems as it solves.

Using the constructor style from the last variant, we can re-work one of the examples from Section 7:

...
var context = new AudioContext();
...

function playSound() {
    var oneShotSound = context.createBufferSource();
    oneShotSound.buffer = dogBarkingBuffer;

    // Create a filter, panner, and gain node. 

    var lowpass = context.createBiquadFilter();

    var panner = context.createPanner();
    panner.panningModel = "equalpower";
    panner.distanceModel = "linear";

    var gainNode2 = context.createGain();


    // Make connections 
    oneShotSound.connect(lowpass);
    lowpass.connect(panner);
    panner.connect(gainNode2);
    gainNode2.connect(compressor);

    oneShotSound.start(context.currentTime + 0.75);
}

to:

...
var context = new AudioContext();
...

function playSound() {
    var oneShotSound = new BufferSource(context, { buffer: dogBarkingBuffer });

    // Create a filter, panner, and gain node. 
    var lowpass = new BiquadFilterNode(context);
    var panner = new PannerNode(context, { 
      panningModel: "equalpower",
      distanceModel: "linear"
    });
    var gainNode2 = new GainNode(context);

    // Make connections 
    oneShotSound.connect(lowpass);
    lowpass.connect(panner);
    panner.connect(gainNode2);
    gainNode2.connect(compressor);

    oneShotSound.start(context.currentTime + 0.75);
}
@olivierthereaux olivierthereaux added this to the V1 milestone Jun 3, 2014
@pendragon-andyh
Copy link

The last example allows much more fluent coding. The "Composing New Nodes" section of http://htmlpreview.github.io/?https://github.com/pendragon-andyh/tony.js/blob/master/examples/example-api.html takes the same approach with the AudioContext's factory methods - and also allows AudioParam values to be set.

It also allows connect/disconnect/start/stop to be chained - to allow much more concise code.

@cwilso cwilso modified the milestones: V1, Web Audio v.1 Oct 17, 2014
@cwilso cwilso modified the milestones: Web Audio v 1.0, Web Audio Last Call 1 Oct 29, 2014
@cwilso cwilso self-assigned this Jun 2, 2015
@joeberkovitz
Copy link
Contributor

Next step: discuss with TAG, include in written response to the TAG issues, including this one.

@joeberkovitz
Copy link
Contributor

@cwilso has there been any discussion with TAG? We need to address this in order to get the spec into V1 shape. Please let the group know if you are still on this, or if the chairs should find another way to resolve.

@cwilso cwilso changed the title Constructibility & De-sugaring of static methods TAG: Constructibility & De-sugaring of static methods Oct 26, 2015
@cwilso cwilso changed the title TAG: Constructibility & De-sugaring of static methods TAG issue: Constructibility & De-sugaring of static methods Oct 26, 2015
@joeberkovitz
Copy link
Contributor

TPAC: De-sugar all concrete context-created node types by adding constructors with context as initial parameter, and create...() arguments as subsequent parameters.

AudioBuffer constructor doesn't need to take an initial context argument.

AudioListener constructor doesn't need any arguments.

@joeberkovitz
Copy link
Contributor

Currently I am hesitating to do this until #308 can be merged due to the mess caused by the base interface name change.

@joeberkovitz
Copy link
Contributor

This is now in progress via #662

@joeberkovitz
Copy link
Contributor

The constructor signatures have evolved a bit since I began #662 a while back to include property bags instead of explicit arguments. When someone picks this work up, it would be probably useful to use the branch in #662 as a starting point (250-desugaring)

@mdjp mdjp added the TAG label Sep 22, 2016
@svgeesus svgeesus added the TAG label Nov 6, 2017
@plehegar plehegar added the w3c-tag-tracker Group bringing to attention of the TAG, or tracked by the TAG but not needing response. label Apr 21, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: ready for editing w3c-tag-tracker Group bringing to attention of the TAG, or tracked by the TAG but not needing response.
Projects
None yet
Development

No branches or pull requests

8 participants