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]); }