This is an archived snapshot of W3C's public bugzilla bug tracker, decommissioned in April 2019. Please see the home page for more details.

Bug 20502 - MIDIEvent should have a port attribute
Summary: MIDIEvent should have a port attribute
Status: CLOSED LATER
Alias: None
Product: AudioWG
Classification: Unclassified
Component: MIDI API (show other bugs)
Version: unspecified
Hardware: PC All
: P2 normal
Target Milestone: TBD
Assignee: This bug has no owner yet - up for the taking
QA Contact: public-audio
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-12-24 08:12 UTC by Marcos Caceres
Modified: 2013-01-18 15:50 UTC (History)
2 users (show)

See Also:


Attachments

Description Marcos Caceres 2012-12-24 08:12:47 UTC
In situations where there are multiple sources attached to a device, it is important to distinguish which MIDI output emitted a particular message. As such, I recommend adding a port attribute to the MIDIEvent interface:

interface MIDIEvent : Event {
readonly attribute MIDIPort port;
...
}
Comment 1 Marcos Caceres 2012-12-24 10:27:05 UTC
On Monday, 24 December 2012 at 07:42, Jussi Kalliokoski wrote:
>Yes, actually I thought that for events on an EventTarget, both "this" and
>".target" would automatically be the port, but now that I checked, it seems that >only the former is true.

But then you still have two objects that are disjoint ("this" and the MIDIEvent instance). It would be nicer, IMO, to have them combined (specially because there can be multiple sources for an event, and a single listener).

There is precedence for knowing the "source" of the event. For instance, Web Messaging has a "source" attribute.   

There is also GamepadEvent, which has:
readonly attribute Gamepad gamepad; 
http://dvcs.w3.org/hg/gamepad/raw-file/tip/gamepad.html#gamepadevent-interface

> But that being the case, I think we should use 
>".target", rather than introduce a new way of reporting the target.

According to DOM4, the event.target "Returns the object event is dispatched to." Not the object it was dispatched *from*.

For example, in Web Messaging. If I postMessage some data from document A to iframe "Document B", I get:

e.source.document.title === "Document A"; 
e.target.document.title === "Document B"; 

In any case, I find .target confusing. It's also more confusing because you also have the sourceElement attribute, which will probably have to also be set.
Comment 2 Chris Wilson 2012-12-25 20:40:12 UTC
Can't you easily set this up by binding the onmessage handler?
Comment 3 Marcos Caceres 2012-12-25 21:00:31 UTC
(In reply to comment #2)
> Can't you easily set this up by binding the onmessage handler?

It's probably not a good idea to use the onmessage handler because it can be overridden by anyone (please also see issue at bottom of this reply). Also, to set that up requires some minor gymnastics when you could just get it for free from the event itself.

Like: 
var recording = []; 
for(....; i++){
midiaccess.getInputs()[i].addEventListener('message', function (e) {
  var instrument = {port: this, event: e};  
  recording.push(instrument);
  //or 
  e.port = this; 
  recording.push(e);
}); 

The second case above kinda sucks because it's not nice to add things to object that you don't own (in this case a MIDIEvent). 

Actually, that brings up a separate issues I forgot to raise: is the MIDIAccess object a singleton? As in: 

a = navigator.requestMIDIAccess();
b = navigator.requestMIDIAccess();

a === b? 

In the spec, this is currently unclear in 5.1.1:
"success: Let access be the MIDIAccess object for which access has been granted."

Which kinda reads like the spec is assuming requestMIDIAccess() will not be called repeatedly. 

Need to file a separate bug for the above, but some clarification would be good.
Comment 4 Chris Wilson 2012-12-25 21:06:17 UTC
(In reply to comment #3)
> (In reply to comment #2)
> > Can't you easily set this up by binding the onmessage handler?
> 
> It's probably not a good idea to use the onmessage handler because it can be
> overridden by anyone (please also see issue at bottom of this reply). 

"Can't you easily set this up by binding the message handler (onmessage or addEventHandler function)?"  Binding is on the function object, irrelevant of onmessage or addEventHandler.

>Also,
> to set that up requires some minor gymnastics when you could just get it for
> free from the event itself.

Well, it's not totally "free" - because it would have to be set on the event object for each call then - but not very expensive, I suppose.

> Like: 
> var recording = []; 
> for(....; i++){
> midiaccess.getInputs()[i].addEventListener('message', function (e) {
>   var instrument = {port: this, event: e};  
>   recording.push(instrument);
>   //or 
>   e.port = this; 
>   recording.push(e);
> }); 
> 
> The second case above kinda sucks because it's not nice to add things to
> object that you don't own (in this case a MIDIEvent). 

Well, but this leads me to believe it's not a good idea, because it will encourage the use of adding things to the MIDIPort (to get back to your own code), and binding (in the rare case that you would need a pointer back to your objects that isn't just a function pointer).
Comment 5 Marcos Caceres 2012-12-25 21:24:00 UTC
(In reply to comment #4)
> (In reply to comment #3)
> > (In reply to comment #2)
> > > Can't you easily set this up by binding the onmessage handler?
> > 
> > It's probably not a good idea to use the onmessage handler because it can be
> > overridden by anyone (please also see issue at bottom of this reply). 
> 
> "Can't you easily set this up by binding the message handler (onmessage or
> addEventHandler function)?"  Binding is on the function object, irrelevant
> of onmessage or addEventHandler.

Maybe I'm not getting what you mean here. Are you literally saying use .bind()? Or something else? 
 
> >Also,
> > to set that up requires some minor gymnastics when you could just get it for
> > free from the event itself.
> 
> Well, it's not totally "free" - because it would have to be set on the event
> object for each call then - but not very expensive, I suppose.
> 
> > Like: 
> > var recording = []; 
> > for(....; i++){
> > midiaccess.getInputs()[i].addEventListener('message', function (e) {
> >   var instrument = {port: this, event: e};  
> >   recording.push(instrument);
> >   //or 
> >   e.port = this; 
> >   recording.push(e);
> > }); 
> > 
> > The second case above kinda sucks because it's not nice to add things to
> > object that you don't own (in this case a MIDIEvent). 
> 
> Well, but this leads me to believe it's not a good idea, because it will
> encourage the use of adding things to the MIDIPort (to get back to your own
> code), and binding (in the rare case that you would need a pointer back to
> your objects that isn't just a function pointer).

Oh, my example was supposed to be all bad - I'll see if I can come up with a real usage scenario as I just made that on up on the spot. In any case, I think we might be misunderstanding each other, but I can understand the need for a good justification to adding this. 

I might need a stronger use case. At the moment, this might just fall into the "nice to have" category. 

I'll also be honest: I didn't know that "this" would become the port itself before Jussi mentioned it. It makes sense, but I wonder if many developers know about that.
Comment 6 Chris Wilson 2012-12-25 22:55:45 UTC
(In reply to comment #5)
> > "Can't you easily set this up by binding the message handler (onmessage or
> > addEventHandler function)?"  Binding is on the function object, irrelevant
> > of onmessage or addEventHandler.
> 
> Maybe I'm not getting what you mean here. Are you literally saying use
> .bind()? Or something else? 

Yes, calling .bind.

port.addEventListener( "message", myhandler.bind( myobj ) );

> Oh, my example was supposed to be all bad - I'll see if I can come up with a
> real usage scenario as I just made that on up on the spot. In any case, I
> think we might be misunderstanding each other, but I can understand the need
> for a good justification to adding this. 
> 
> I might need a stronger use case. At the moment, this might just fall into
> the "nice to have" category. 

I'm not fundamentally opposed, just want to ensure we have strong justification.

> I'll also be honest: I didn't know that "this" would become the port itself
> before Jussi mentioned it. It makes sense, but I wonder if many developers
> know about that.

Hmm, noted.  Have to fix that in my shim, I think.
Comment 7 Marcos Caceres 2012-12-25 23:11:04 UTC
(In reply to comment #6)
> (In reply to comment #5)
> > > "Can't you easily set this up by binding the message handler (onmessage or
> > > addEventHandler function)?"  Binding is on the function object, irrelevant
> > > of onmessage or addEventHandler.
> > 
> > Maybe I'm not getting what you mean here. Are you literally saying use
> > .bind()? Or something else? 
> 
> Yes, calling .bind.
> 
> port.addEventListener( "message", myhandler.bind( myobj ) );

I honestly don't know how many people use or understand bind (I'm personally often confused by it). I've personally have never have had to use it. That's not to say that people don't use bind.

> > Oh, my example was supposed to be all bad - I'll see if I can come up with a
> > real usage scenario as I just made that on up on the spot. In any case, I
> > think we might be misunderstanding each other, but I can understand the need
> > for a good justification to adding this. 
> > 
> > I might need a stronger use case. At the moment, this might just fall into
> > the "nice to have" category. 
> 
> I'm not fundamentally opposed, just want to ensure we have strong
> justification.

Agree. Would be good to hear if Jussi or others have a strong use case. 

> > I'll also be honest: I didn't know that "this" would become the port itself
> > before Jussi mentioned it. It makes sense, but I wonder if many developers
> > know about that.
> 
> Hmm, noted.  Have to fix that in my shim, I think.

I added it the other day to my fork by doing something like:

function MIDIPort(...){
  var self = this;
  ... 
  function (type, listener, useCapture) {
     dispatcher.addEventListener(type, function (e) {
        listener.call(self, e);
     }, useCapture);
  }
}
Comment 8 Chris Wilson 2012-12-26 19:02:54 UTC
Moved to "LATER" for justification.
Comment 9 Olivier Thereaux 2013-01-18 15:50:57 UTC
Batch-closing RESOLVED MIDI issues. Reminder: midi issues now tracked at https://github.com/WebAudio/web-midi-api/issues