Please use the existing modules as templates.
Some details are clarified below.
A module must allow both ways of opening ports:
// MIDI-Out:
port = JZZ.synth.MySynth(); // open port directly
// or
JZZ.synth.MySynth.register('My Synth 1'); // register
JZZ.synth.MySynth.register('My Synth 2'); // (can register multiple instances)
port = JZZ().openMidiOut('My Synth 1'); // open the registered port
// MIDI-In:
port = JZZ.input.MyGadget(); // open port directly
// or
JZZ.input.MyGadget.register('My Gadget 1'); // register
JZZ.input.MyGadget.register('My Gadget 2'); // (can register multiple instances)
port = JZZ().openMidiIn('My Gadget 1'); // open the registered port
A module should implement the engine object that provides two functions:
Functions _openIn() and _openOut() can override the port's _info / _receive / _close members as explained here.
The port object passed to _openIn/Out() will normally be in the paused state. When the port is initialized and ready to go, call port._resume(), or, if an error occured, - port._crash().
engine = {
_info: function(name) { return { ... } },
_openOut: function(port, name) {
// ...
port._info = this._info(name);
port._receive = function(msg) { ... };
port._close = function() { ... };
if (success)
port._resume();
else
port._crash();
}
};
You don't have to override _receive() for the MIDI-In ports, though, you may do it if you like! Call port._emit() whenever you need to emit a MIDI message:
myGadget.onKeyDown = function (note, velocity) {
port._emit(JZZ.MIDI(0x90, note, velocity));
}
Finally, a module must define the port register/open functions as shown below:
JZZ.synth.MySynth = function(name) {
// ...
return JZZ.lib.openMidiOut(name, engine);
}
JZZ.synth.MySynth.register = function(name) {
// ...
return JZZ.lib.registerMidiOut(name, engine);
}
JZZ.input.MyGadget = function(name) {
// ...
return JZZ.lib.openMidiIn(name, engine);
}
JZZ.input.MyGadget.register = function(name) {
// ...
return JZZ.lib.registerMidiIn(name, engine);
}
If no asynchronous calls required to initialize the port:
function init(port) {
// do stuff...
if (success) {
port._resume();
}
else {
port._crash();
}
}
If an asynchronous call is required to initialize every port:
function init(port) {
port._pause(); // wait until the asynchronous call returns
// do stuff...
asyncCall({
onsuccess: function() {
// do more stuff...
port._resume();
},
onerror: function() {
// do cleanup...
port._crash();
}
);
}
If a single asynchronous call is required before initializing all ports:
var returned = false;
var success = false;
var waiting = [];
function finish(port) {
if (success) {
// do more stuff...
port._resume();
}
else {
// do cleanup...
port._crash();
}
}
function init(port) {
if (returned) {
finish(port);
return;
}
port._pause(); // wait until the asynchronous call returns
waiting.push(port);
if (waiting.length == 1) { // first time
// do stuff...
asyncCall({ onsuccess: onsuccess, onerror: onerror });
}
}
function onerror() {
returned = true;
for (var i=0; i<waiting.length; i++) finish(waiting[i]);
}
function onsuccess() {
returned = true;
success = true;
for (var i=0; i<waiting.length; i++) finish(waiting[i]);
}