UNPKG

qambi

Version:

MIDI sequencer, loads MIDI files, can record and playback MIDI, uses WebMIDI and WebAudio

1,481 lines (1,441 loc) 445 kB
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.qambi = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ /* FileSaver.js * A saveAs() FileSaver implementation. * 1.1.20160328 * * By Eli Grey, http://eligrey.com * License: MIT * See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md */ /*global self */ /*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */ /*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ var saveAs = saveAs || (function(view) { "use strict"; // IE <10 is explicitly unsupported if (typeof navigator !== "undefined" && /MSIE [1-9]\./.test(navigator.userAgent)) { return; } var doc = view.document // only get URL when necessary in case Blob.js hasn't overridden it yet , get_URL = function() { return view.URL || view.webkitURL || view; } , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a") , can_use_save_link = "download" in save_link , click = function(node) { var event = new MouseEvent("click"); node.dispatchEvent(event); } , is_safari = /Version\/[\d\.]+.*Safari/.test(navigator.userAgent) , webkit_req_fs = view.webkitRequestFileSystem , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem , throw_outside = function(ex) { (view.setImmediate || view.setTimeout)(function() { throw ex; }, 0); } , force_saveable_type = "application/octet-stream" , fs_min_size = 0 // the Blob API is fundamentally broken as there is no "downloadfinished" event to subscribe to , arbitrary_revoke_timeout = 1000 * 40 // in ms , revoke = function(file) { var revoker = function() { if (typeof file === "string") { // file is an object URL get_URL().revokeObjectURL(file); } else { // file is a File file.remove(); } }; /* // Take note W3C: var uri = typeof file === "string" ? file : file.toURL() , revoker = function(evt) { // idealy DownloadFinishedEvent.data would be the URL requested if (evt.data === uri) { if (typeof file === "string") { // file is an object URL get_URL().revokeObjectURL(file); } else { // file is a File file.remove(); } } } ; view.addEventListener("downloadfinished", revoker); */ setTimeout(revoker, arbitrary_revoke_timeout); } , dispatch = function(filesaver, event_types, event) { event_types = [].concat(event_types); var i = event_types.length; while (i--) { var listener = filesaver["on" + event_types[i]]; if (typeof listener === "function") { try { listener.call(filesaver, event || filesaver); } catch (ex) { throw_outside(ex); } } } } , auto_bom = function(blob) { // prepend BOM for UTF-8 XML and text/* types (including HTML) if (/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) { return new Blob(["\ufeff", blob], {type: blob.type}); } return blob; } , FileSaver = function(blob, name, no_auto_bom) { if (!no_auto_bom) { blob = auto_bom(blob); } // First try a.download, then web filesystem, then object URLs var filesaver = this , type = blob.type , blob_changed = false , object_url , target_view , dispatch_all = function() { dispatch(filesaver, "writestart progress write writeend".split(" ")); } // on any filesys errors revert to saving with object URLs , fs_error = function() { if (target_view && is_safari && typeof FileReader !== "undefined") { // Safari doesn't allow downloading of blob urls var reader = new FileReader(); reader.onloadend = function() { var base64Data = reader.result; target_view.location.href = "data:attachment/file" + base64Data.slice(base64Data.search(/[,;]/)); filesaver.readyState = filesaver.DONE; dispatch_all(); }; reader.readAsDataURL(blob); filesaver.readyState = filesaver.INIT; return; } // don't create more object URLs than needed if (blob_changed || !object_url) { object_url = get_URL().createObjectURL(blob); } if (target_view) { target_view.location.href = object_url; } else { var new_tab = view.open(object_url, "_blank"); if (new_tab === undefined && is_safari) { //Apple do not allow window.open, see http://bit.ly/1kZffRI view.location.href = object_url } } filesaver.readyState = filesaver.DONE; dispatch_all(); revoke(object_url); } , abortable = function(func) { return function() { if (filesaver.readyState !== filesaver.DONE) { return func.apply(this, arguments); } }; } , create_if_not_found = {create: true, exclusive: false} , slice ; filesaver.readyState = filesaver.INIT; if (!name) { name = "download"; } if (can_use_save_link) { object_url = get_URL().createObjectURL(blob); setTimeout(function() { save_link.href = object_url; save_link.download = name; click(save_link); dispatch_all(); revoke(object_url); filesaver.readyState = filesaver.DONE; }); return; } // Object and web filesystem URLs have a problem saving in Google Chrome when // viewed in a tab, so I force save with application/octet-stream // http://code.google.com/p/chromium/issues/detail?id=91158 // Update: Google errantly closed 91158, I submitted it again: // https://code.google.com/p/chromium/issues/detail?id=389642 if (view.chrome && type && type !== force_saveable_type) { slice = blob.slice || blob.webkitSlice; blob = slice.call(blob, 0, blob.size, force_saveable_type); blob_changed = true; } // Since I can't be sure that the guessed media type will trigger a download // in WebKit, I append .download to the filename. // https://bugs.webkit.org/show_bug.cgi?id=65440 if (webkit_req_fs && name !== "download") { name += ".download"; } if (type === force_saveable_type || webkit_req_fs) { target_view = view; } if (!req_fs) { fs_error(); return; } fs_min_size += blob.size; req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) { fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) { var save = function() { dir.getFile(name, create_if_not_found, abortable(function(file) { file.createWriter(abortable(function(writer) { writer.onwriteend = function(event) { target_view.location.href = file.toURL(); filesaver.readyState = filesaver.DONE; dispatch(filesaver, "writeend", event); revoke(file); }; writer.onerror = function() { var error = writer.error; if (error.code !== error.ABORT_ERR) { fs_error(); } }; "writestart progress write abort".split(" ").forEach(function(event) { writer["on" + event] = filesaver["on" + event]; }); writer.write(blob); filesaver.abort = function() { writer.abort(); filesaver.readyState = filesaver.DONE; }; filesaver.readyState = filesaver.WRITING; }), fs_error); }), fs_error); }; dir.getFile(name, {create: false}, abortable(function(file) { // delete file if it already exists file.remove(); save(); }), abortable(function(ex) { if (ex.code === ex.NOT_FOUND_ERR) { save(); } else { fs_error(); } })); }), fs_error); }), fs_error); } , FS_proto = FileSaver.prototype , saveAs = function(blob, name, no_auto_bom) { return new FileSaver(blob, name, no_auto_bom); } ; // IE 10+ (native saveAs) if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob) { return function(blob, name, no_auto_bom) { if (!no_auto_bom) { blob = auto_bom(blob); } return navigator.msSaveOrOpenBlob(blob, name || "download"); }; } FS_proto.abort = function() { var filesaver = this; filesaver.readyState = filesaver.DONE; dispatch(filesaver, "abort"); }; FS_proto.readyState = FS_proto.INIT = 0; FS_proto.WRITING = 1; FS_proto.DONE = 2; FS_proto.error = FS_proto.onwritestart = FS_proto.onprogress = FS_proto.onwrite = FS_proto.onabort = FS_proto.onerror = FS_proto.onwriteend = null; return saveAs; }( typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content )); // `self` is undefined in Firefox for Android content script context // while `this` is nsIContentFrameMessageManager // with an attribute `content` that corresponds to the window if (typeof module !== "undefined" && module.exports) { module.exports.saveAs = saveAs; } else if ((typeof define !== "undefined" && define !== null) && (define.amd !== null)) { define([], function() { return saveAs; }); } },{}],2:[function(require,module,exports){ // the whatwg-fetch polyfill installs the fetch() function // on the global object (window or self) // // Return that as the export for use in Webpack, Browserify etc. require('whatwg-fetch'); module.exports = self.fetch.bind(self); },{"whatwg-fetch":6}],3:[function(require,module,exports){ (function (process,__dirname){ var path='./bin/'; var v=process.versions.node.split('.'); if (v[0]==0 && v[1]<=10) path+='0_10/'; else if (v[0]==0 && v[1]<=12) path+='0_12/'; else if (v[0]<=4) path+='4_8/'; else if (v[0]<=5) path+='5_12/'; else if (v[0]<=6) path+='6_12/'; else if (v[0]<=7) path+='7_10/'; else if (v[0]<=8) path+='8_9/'; if(process.platform=="win32"&&process.arch=="ia32") path+='win32/jazz'; else if(process.platform=="win32"&&process.arch=="x64") path+='win64/jazz'; else if(process.platform=="darwin"&&process.arch=="x64") path+='macos64/jazz'; else if(process.platform=="darwin"&&process.arch=="ia32") path+='macos32/jazz'; else if(process.platform=="linux"&&process.arch=="x64") path+='linux64/jazz'; else if(process.platform=="linux"&&process.arch=="ia32") path+='linux32/jazz'; else if(process.platform=="linux"&&process.arch=="arm") path+='linuxa7/jazz'; module.exports=require(path); module.exports.package=require(__dirname + '/package.json'); }).call(this,require('_process'),"/node_modules/jazz-midi") },{"_process":5}],4:[function(require,module,exports){ (function (global){ (function(global, factory) { if (typeof exports === 'object' && typeof module !== 'undefined') { module.exports = factory(); } else if (typeof define === 'function' && define.amd) { define('JZZ', [], factory); } else { if (global.JZZ && global.JZZ.MIDI) return; global.JZZ = factory(); } })(this, function(){ var _scope = typeof window === 'undefined' ? global : window; var _version = '0.4.6'; var i, j, k, m, n; var _time = Date.now || function () { return new Date().getTime(); }; var _startTime = _time(); var _now = typeof performance != 'undefined' && performance.now ? function() { return performance.now(); } : function() { return _time() - _startTime; }; // _R: common root for all async objects function _R() { this._orig = this; this._ready = false; this._queue = []; this._err = []; } _R.prototype._exec = function() { while (this._ready && this._queue.length) { var x = this._queue.shift(); if (this._orig._bad) { if (this._orig._hope && x[0] == _or) { this._orig._hope = false; x[0].apply(this, x[1]); } else { this._queue = []; this._orig._hope = false; } } else if (x[0] != _or) { x[0].apply(this, x[1]); } } }; _R.prototype._push = function(func, arg) { this._queue.push([func, arg]); _R.prototype._exec.apply(this); }; _R.prototype._slip = function(func, arg) { this._queue.unshift([func, arg]); }; _R.prototype._pause = function() { this._ready = false; }; _R.prototype._resume = function() { this._ready = true; _R.prototype._exec.apply(this); }; _R.prototype._break = function(err) { this._orig._bad = true; this._orig._hope = true; if (err) this._orig._err.push(err); }; _R.prototype._repair = function() { this._orig._bad = false; }; _R.prototype._crash = function(err) { this._break(err); this._resume(); }; _R.prototype.err = function() { return _clone(this._err); }; _R.prototype._image = function() { var F = function() {}; F.prototype = this._orig; var ret = new F(); ret._ready = false; ret._queue = []; return ret; }; function _wait(obj, delay) { setTimeout(function() { obj._resume(); }, delay); } _R.prototype.wait = function(delay) { if (!delay) return this; var ret = this._image(); this._push(_wait, [ret, delay]); return ret; }; function _kick(obj) { obj._resume(); } function _rechain(self, obj, name) { self[name] = function() { var arg = arguments; var ret = obj._image(); this._push(_kick, [ret]); return ret[name].apply(ret, arg); }; } function _and(q) { if (q instanceof Function) q.apply(this); else console.log(q); } _R.prototype.and = function(func) { this._push(_and, [func]); return this; }; function _or(q) { if (q instanceof Function) q.apply(this); else console.log(q); } _R.prototype.or = function(func) { this._push(_or, [func]); return this; }; _R.prototype._info = {}; _R.prototype.info = function() { var info = _clone(this._orig._info); if (typeof info.engine == 'undefined') info.engine = 'none'; if (typeof info.sysex == 'undefined') info.sysex = true; return info; }; _R.prototype.name = function() { return this.info().name; }; function _close(obj) { this._break('closed'); obj._resume(); } _R.prototype.close = function() { var ret = new _R(); if (this._close) this._push(this._close, []); this._push(_close, [ret]); return ret; }; function _tryAny(arr) { if (!arr.length) { this._break(); return; } var func = arr.shift(); if (arr.length) { var self = this; this._slip(_or, [ function(){ _tryAny.apply(self,[arr]);} ]); } try { this._repair(); func.apply(this); } catch (err) { this._break(err.toString()); } } function _push(arr, obj) { for (var i = 0; i < arr.length; i++) if (arr[i] === obj) return; arr.push(obj); } function _pop(arr, obj) { for (var i = 0; i < arr.length; i++) if (arr[i] === obj) { arr.splice(i, 1); return; } } // _J: JZZ object function _J() { _R.apply(this); } _J.prototype = new _R(); _J.prototype.time = function() { return 0; }; if (typeof performance != 'undefined' && performance.now) _J.prototype._time = function() { return performance.now(); }; function _initTimer() { if (!_J.prototype._time) _J.prototype._time = function() { return Date.now(); }; _J.prototype._startTime = _J.prototype._time(); _J.prototype.time = function() { return _J.prototype._time() - _J.prototype._startTime; }; } function _clone(obj, key, val) { if (typeof key == 'undefined') return _clone(obj, [], []); if (obj instanceof Object) { for (var i = 0; i < key.length; i++) if (key[i] === obj) return val[i]; var ret; if (obj instanceof Array) ret = []; else ret = {}; key.push(obj); val.push(ret); for(var k in obj) if (obj.hasOwnProperty(k)) ret[k] = _clone(obj[k], key, val); return ret; } return obj; } _J.prototype._info = { name: 'JZZ.js', ver: _version, version: _version }; var _outs = []; var _ins = []; function _postRefresh() { this._orig._info.engine = _engine._type; this._orig._info.version = _engine._version; this._orig._info.sysex = _engine._sysex; this._orig._info.inputs = []; this._orig._info.outputs = []; _outs = []; _ins = []; _engine._allOuts = {}; _engine._allIns = {}; var i, x; for (i = 0; i < _engine._outs.length; i++) { x = _engine._outs[i]; x.engine = _engine; _engine._allOuts[x.name] = x; this._orig._info.outputs.push({ name: x.name, manufacturer: x.manufacturer, version: x.version, engine: _engine._type }); _outs.push(x); } for (i = 0; i < _virtual._outs.length; i++) { x = _virtual._outs[i]; this._orig._info.outputs.push({ name: x.name, manufacturer: x.manufacturer, version: x.version, engine: x.type }); _outs.push(x); } for (i = 0; i < _engine._ins.length; i++) { x = _engine._ins[i]; x.engine = _engine; _engine._allIns[x.name] = x; this._orig._info.inputs.push({ name: x.name, manufacturer: x.manufacturer, version: x.version, engine: _engine._type }); _ins.push(x); } for (i = 0; i < _virtual._ins.length; i++) { x = _virtual._ins[i]; this._orig._info.inputs.push({ name: x.name, manufacturer: x.manufacturer, version: x.version, engine: x.type }); _ins.push(x); } } function _refresh() { this._slip(_postRefresh, []); _engine._refresh(this); } _J.prototype.refresh = function() { this._push(_refresh, []); return this; }; function _filterList(q, arr) { if (typeof q == 'undefined') return arr.slice(); var i, n; var a = []; if (q instanceof RegExp) { for (n=0; n<arr.length; n++) if (q.test(arr[n].name)) a.push(arr[n]); return a; } if (q instanceof Function) q = q(arr); if (!(q instanceof Array)) q = [q]; for (i=0; i<q.length; i++) { for (n=0; n<arr.length; n++) { if (q[i]+'' === n+'' || q[i] === arr[n].name || (q[i] instanceof Object && q[i].name === arr[n].name)) a.push(arr[n]); } } return a; } function _notFound(port, q) { var msg; if (q instanceof RegExp) msg = 'Port matching ' + q + ' not found'; else if (q instanceof Object || typeof q == 'undefined') msg = 'Port not found'; else msg = 'Port "' + q + '" not found'; port._crash(msg); } function _openMidiOut(port, arg) { var arr = _filterList(arg, _outs); if (!arr.length) { _notFound(port, arg); return; } var pack = function(x) { return function() { x.engine._openOut(this, x.name); }; }; for (var i=0; i<arr.length; i++) arr[i] = pack(arr[i]); port._slip(_tryAny, [arr]); port._resume(); } _J.prototype.openMidiOut = function(arg) { var port = new _M(); this._push(_refresh, []); this._push(_openMidiOut, [port, arg]); return port; }; function _openMidiIn(port, arg) { var arr = _filterList(arg, _ins); if (!arr.length) { _notFound(port, arg); return; } var pack = function(x) { return function() { x.engine._openIn(this, x.name); }; }; for (var i=0; i<arr.length; i++) arr[i] = pack(arr[i]); port._slip(_tryAny, [arr]); port._resume(); } _J.prototype.openMidiIn = function(arg) { var port = new _M(); this._push(_refresh, []); this._push(_openMidiIn, [port, arg]); return port; }; function _onChange(watcher, arg) { watcher._slip(_connectW, [arg]); watcher._resume(); } _J.prototype.onChange = function(arg) { if (!this._orig._watcher) this._orig._watcher = new _W(); var watcher = this._orig._watcher._image(); this._push(_onChange, [watcher, arg]); return watcher; }; _J.prototype._close = function() { _engine._close(); }; // _M: MIDI-In/Out object function _M() { _R.apply(this); this._handles = []; this._outs = []; } _M.prototype = new _R(); _M.prototype._filter = function(msg) { if (this._orig._mpe) { var out; var outs = 0; if (this._handles && this._handles.length) { outs = this._handles.length; out = this._handles[0]; } if (this._outs && this._outs.length) { outs = this._outs.length; out = this._outs[0]; } if (outs == 1 && !out._mpe) { msg = this._orig._mpe.filter(msg); } } return msg; }; _M.prototype._receive = function(msg) { this._emit(this._filter(msg)); }; function _receive(msg) { this._receive(msg); } _M.prototype.send = function() { this._push(_receive, [MIDI.apply(null, arguments)]); return this; }; _M.prototype.note = function(c, n, v, t) { this.noteOn(c, n, v); if (t) this.wait(t).noteOff(c, n); return this; }; _M.prototype._emit = function(msg) { var i; for (i = 0; i < this._handles.length; i++) this._handles[i].apply(this, [MIDI(msg)._stamp(this)]); for (i = 0; i < this._outs.length; i++) { var m = MIDI(msg); if (!m._stamped(this._outs[i])) this._outs[i].send(m._stamp(this)); } }; function _emit(msg) { this._emit(msg); } _M.prototype.emit = function(msg) { this._push(_emit, [msg]); return this; }; function _connect(arg) { if (arg instanceof Function) _push(this._orig._handles, arg); else _push(this._orig._outs, arg); } function _disconnect(arg) { if (typeof arg == 'undefined') { this._orig._handles = []; this._orig._outs = []; } else if (arg instanceof Function) _pop(this._orig._handles, arg); else _pop(this._orig._outs, arg); } _M.prototype.connect = function(arg) { this._push(_connect, [arg]); return this; }; _M.prototype.disconnect = function(arg) { this._push(_disconnect, [arg]); return this; }; _M.prototype.ch = function(n) { if (typeof n == 'undefined') return this; if (n != parseInt(n) || n < 0 || n > 15) throw RangeError('Bad channel value: ' + n + ' (must be from 0 to 15)'); var chan = new _C(this, n); this._push(_kick, [chan]); return chan; }; function _mpe(m, n) { if (!this._orig._mpe) this._orig._mpe = new MPE(); this._orig._mpe.setup(m, n); } _M.prototype.mpe = function(m, n) { if (typeof m == 'undefined' && typeof n == 'undefined') return this; MPE.validate(m, n); var chan = n ? new _E(this, m, n) : new _C(this, m); this._push(_mpe, [m, n]); this._push(_kick, [chan]); return chan; }; // _C: MIDI Channel object function _C(port, chan) { _M.apply(this); this._port = port._orig; this._chan = chan; _rechain(this, this._port, 'ch'); _rechain(this, this._port, 'mpe'); _rechain(this, this._port, 'connect'); _rechain(this, this._port, 'disconnect'); _rechain(this, this._port, 'close'); } _C.prototype = new _M(); _C.prototype.channel = function() { return this._chan; }; _C.prototype._receive = function(msg) { this._port._receive(msg); }; _C.prototype.note = function(n, v, t) { this.noteOn(n, v); if (t) this.wait(t).noteOff(n); return this; }; // _E: MPE Channel object function _E(port, m, n) { _M.apply(this); this._port = port._orig; this._master = m; this._band = n; _rechain(this, this._port, 'ch'); _rechain(this, this._port, 'mpe'); _rechain(this, this._port, 'connect'); _rechain(this, this._port, 'disconnect'); _rechain(this, this._port, 'close'); } _E.prototype = new _M(); _E.prototype.channel = function() { return this._master; }; _E.prototype._receive = function(msg) { this._port._receive(msg); }; _E.prototype.note = function(n, v, t) { this.noteOn(n, v); if (t) this.wait(t).noteOff(n); return this; }; // _W: Watcher object ~ MIDIAccess.onstatechange function _W() { _R.apply(this); this._handles = []; _rechain(this, _jzz, 'refresh'); _rechain(this, _jzz, 'openMidiOut'); _rechain(this, _jzz, 'openMidiIn'); _rechain(this, _jzz, 'onChange'); _rechain(this, _jzz, 'close'); } _W.prototype = new _R(); function _connectW(arg) { if (arg instanceof Function) { if (!this._orig._handles.length) _engine._watch(); _push(this._orig._handles, arg); } } function _disconnectW(arg) { if (typeof arg == 'undefined') this._orig._handles = []; else _pop(this._orig._handles, arg); if (!this._orig._handles.length) _engine._unwatch(); } _W.prototype.connect = function(arg) { this._push(_connectW, [arg]); return this; }; _W.prototype.disconnect = function(arg) { this._push(_disconnectW, [arg]); return this; }; function _changed(x0, y0, x1, y1) { var i; if (x0.length != x1.length || y0.length != y1.length) return true; for (i = 0; i < x0.length; i++) if (x0[i].name != x1[i].name) return true; for (i = 0; i < y0.length; i++) if (y0[i].name != y1[i].name) return true; return false; } function _diff(x0, y0, x1, y1) { if (!_changed(x0, y0, x1, y1)) return; var ax = []; // added var ay = []; var rx = []; // removed var ry = []; var i; var h = {}; for (i = 0; i < x0.length; i++) h[x0[i].name] = true; for (i = 0; i < x1.length; i++) if (!h[x1[i].name]) ax.push(x1[i]); h = {}; for (i = 0; i < x1.length; i++) h[x1[i].name] = true; for (i = 0; i < x0.length; i++) if (!h[x0[i].name]) rx.push(x0[i]); h = {}; for (i = 0; i < y0.length; i++) h[y0[i].name] = true; for (i = 0; i < y1.length; i++) if (!h[y1[i].name]) ay.push(y1[i]); h = {}; for (i = 0; i < y1.length; i++) h[y1[i].name] = true; for (i = 0; i < y0.length; i++) if (!h[y0[i].name]) ry.push(y0[i]); if (ax.length || rx.length || ay.length || ry.length) { return { inputs: { added: ax, removed: rx }, outputs: { added: ay, removed: ry } }; } } function _fireW(arg) { for (i = 0; i < _jzz._watcher._handles.length; i++) _jzz._watcher._handles[i].apply(_jzz, [arg]); } var _jzz; var _engine = {}; var _virtual = { _outs: [], _ins: []}; // Node.js function _tryNODE() { if (typeof module != 'undefined' && module.exports) { _initNode(require('jazz-midi')); return; } this._break(); } // Jazz-Plugin function _tryJazzPlugin() { var div = document.createElement('div'); div.style.visibility='hidden'; document.body.appendChild(div); var obj = document.createElement('object'); obj.style.visibility='hidden'; obj.style.width='0px'; obj.style.height='0px'; obj.classid = 'CLSID:1ACE1618-1C7D-4561-AEE1-34842AA85E90'; obj.type = 'audio/x-jazz'; document.body.appendChild(obj); if (obj.isJazz) { _initJazzPlugin(obj); return; } this._break(); } // Web MIDI API function _tryWebMIDI() { if (navigator.requestMIDIAccess) { var self = this; var onGood = function(midi) { _initWebMIDI(midi); self._resume(); }; var onBad = function(msg) { self._crash(msg); }; var opt = {}; navigator.requestMIDIAccess(opt).then(onGood, onBad); this._pause(); return; } this._break(); } function _tryWebMIDIsysex() { if (navigator.requestMIDIAccess) { var self = this; var onGood = function(midi) { _initWebMIDI(midi, true); self._resume(); }; var onBad = function(msg) { self._crash(msg); }; var opt = {sysex:true}; navigator.requestMIDIAccess(opt).then(onGood, onBad); this._pause(); return; } this._break(); } // Web-extension function _tryCRX() { var self = this; var inst; var msg; function eventHandle(e) { inst = true; if (!msg) msg = document.getElementById('jazz-midi-msg'); if (!msg) return; var a = []; try { a = JSON.parse(msg.innerText);} catch (err) {} msg.innerText = ''; document.removeEventListener('jazz-midi-msg', eventHandle); if (a[0] === 'version') { _initCRX(msg, a[2]); self._resume(); } else { self._crash(); } } this._pause(); document.addEventListener('jazz-midi-msg', eventHandle); try { document.dispatchEvent(new Event('jazz-midi'));} catch (err) {} window.setTimeout(function() { if (!inst) self._crash();}, 0); } function _zeroBreak() { this._pause(); var self = this; setTimeout(function(){ self._crash();}, 0); } function _filterEngines(opt) { var ret = [_tryNODE, _zeroBreak]; var arr = _filterEngineNames(opt); for (var i=0; i<arr.length; i++) { if (arr[i] == 'webmidi') { if (opt && opt.sysex === true) ret.push(_tryWebMIDIsysex); if (!opt || opt.sysex !== true || opt.degrade === true) ret.push(_tryWebMIDI); } else if (arr[i] == 'extension') ret.push(_tryCRX); else if (arr[i] == 'plugin') ret.push(_tryJazzPlugin); } ret.push(_initNONE); return ret; } function _filterEngineNames(opt) { var web = ['extension', 'plugin', 'webmidi']; if (!opt || !opt.engine) return web; var arr = opt.engine instanceof Array ? opt.engine : [opt.engine]; var dup = {}; var none; var etc; var head = []; var tail = []; var i; for (i = 0; i < arr.length; i++) { var name = arr[i].toString().toLowerCase(); if (dup[name]) continue; dup[name] = true; if (name === 'none') none = true; if (name === 'etc') etc = true; if (etc) tail.push(name); else head.push(name); _pop(web, name); } if (etc || head.length || tail.length) none = false; return none ? [] : head.concat(etc ? web : tail); } function _initJZZ(opt) { _initAudioContext(); _jzz = new _J(); _jzz._options = opt; _jzz._push(_tryAny, [_filterEngines(opt)]); _jzz.refresh(); _jzz._push(_initTimer, []); _jzz._push(function(){ if (!_outs.length && !_ins.length) this._break(); }, []); _jzz._resume(); } function _initNONE() { _engine._type = 'none'; _engine._sysex = true; _engine._refresh = function() { _engine._outs = []; _engine._ins = []; }; _engine._watch = function() {}; _engine._unwatch = function() {}; } // common initialization for Jazz-Plugin and jazz-midi function _initEngineJP() { _engine._inArr = []; _engine._outArr = []; _engine._inMap = {}; _engine._outMap = {}; _engine._outsW = []; _engine._insW = []; _engine._version = _engine._main.version; _engine._sysex = true; var watcher; _closeAll = function() { for (var i = 0; i < this.clients.length; i++) this._close(this.clients[i]); }; _engine._refresh = function() { _engine._outs = []; _engine._ins = []; var i, x; for (i = 0; (x = _engine._main.MidiOutInfo(i)).length; i++) { _engine._outs.push({ type: _engine._type, name: x[0], manufacturer: x[1], version: x[2] }); } for (i = 0; (x = _engine._main.MidiInInfo(i)).length; i++) { _engine._ins.push({ type: _engine._type, name: x[0], manufacturer: x[1], version: x[2] }); } var diff = _diff(_engine._insW, _engine._outsW, _engine._ins, _engine._outs); if (diff) { for (j = 0; j < diff.inputs.removed.length; j++) { impl = _engine._inMap[diff.inputs.removed[j].name]; if (impl) impl._closeAll(); } for (j = 0; j < diff.outputs.removed.length; j++) { impl = _engine._outMap[diff.inputs.removed[j].name]; if (impl) impl._closeAll(); } _engine._insW = _engine._ins; _engine._outsW = _engine._outs; if (watcher) _fireW(diff); } }; _engine._openOut = function(port, name) { var impl = _engine._outMap[name]; if (!impl) { if (_engine._pool.length <= _engine._outArr.length) _engine._pool.push(_engine._newPlugin()); impl = { name: name, clients: [], info: { name: name, manufacturer: _engine._allOuts[name].manufacturer, version: _engine._allOuts[name].version, type: 'MIDI-out', sysex: _engine._sysex, engine: _engine._type }, _close: function(port){ _engine._closeOut(port); }, _closeAll: _closeAll, _receive: function(a){ this.plugin.MidiOutRaw(a.slice()); } }; var plugin = _engine._pool[_engine._outArr.length]; impl.plugin = plugin; _engine._outArr.push(impl); _engine._outMap[name] = impl; } if (!impl.open) { var s = impl.plugin.MidiOutOpen(name); if (s !== name) { if (s) impl.plugin.MidiOutClose(); port._break(); return; } impl.open = true; } port._orig._impl = impl; _push(impl.clients, port._orig); port._info = impl.info; port._receive = function(arg) { impl._receive(arg); }; port._close = function() { impl._close(this); }; }; _engine._openIn = function(port, name) { var impl = _engine._inMap[name]; if (!impl) { if (_engine._pool.length <= _engine._inArr.length) _engine._pool.push(_engine._newPlugin()); impl = { name: name, clients: [], info: { name: name, manufacturer: _engine._allIns[name].manufacturer, version: _engine._allIns[name].version, type: 'MIDI-in', sysex: _engine._sysex, engine: _engine._type }, _close: function(port){ _engine._closeIn(port); }, _closeAll: _closeAll, handle: function(t, a) { for (var i = 0; i < this.clients.length; i++) { var msg = MIDI(a); this.clients[i]._emit(msg); } } }; var makeHandle = function(x) { return function(t, a) { x.handle(t, a); }; }; impl.onmidi = makeHandle(impl); var plugin = _engine._pool[_engine._inArr.length]; impl.plugin = plugin; _engine._inArr.push(impl); _engine._inMap[name] = impl; } if (!impl.open) { var s = impl.plugin.MidiInOpen(name, impl.onmidi); if (s !== name) { if (s) impl.plugin.MidiInClose(); port._break(); return; } impl.open = true; } port._orig._impl = impl; _push(impl.clients, port._orig); port._info = impl.info; port._close = function() { impl._close(this); }; }; _engine._closeOut = function(port) { var impl = port._impl; _pop(impl.clients, port._orig); if (!impl.clients.length) { impl.open = false; impl.plugin.MidiOutClose(); } }; _engine._closeIn = function(port) { var impl = port._impl; _pop(impl.clients, port._orig); if (!impl.clients.length) { impl.open = false; impl.plugin.MidiInClose(); } }; _engine._close = function() { for (var i = 0; i < _engine._inArr.length; i++) if (_engine._inArr[i].open) _engine._inArr[i].plugin.MidiInClose(); _engine._unwatch(); }; function onChange() { if (watcher) { _engine._refresh(); watcher = false; } } function watch(name) { watcher = true; setTimeout(onChange, 0); } _engine._watch = function() { _engine._main.OnConnectMidiIn(watch); _engine._main.OnConnectMidiOut(watch); _engine._main.OnDisconnectMidiIn(watch); _engine._main.OnDisconnectMidiOut(watch); }; _engine._unwatch = function() { _engine._main.OnConnectMidiIn(); _engine._main.OnConnectMidiOut(); _engine._main.OnDisconnectMidiIn(); _engine._main.OnDisconnectMidiOut(); }; _J.prototype._time = function() { return _engine._main.Time(); }; } function _initNode(obj) { _engine._type = 'node'; _engine._main = obj; _engine._pool = []; _engine._newPlugin = function() { return new obj.MIDI(); }; _initEngineJP(); } function _initJazzPlugin(obj) { _engine._type = 'plugin'; _engine._main = obj; _engine._pool = [obj]; _engine._newPlugin = function() { var plg = document.createElement('object'); plg.style.visibility='hidden'; plg.style.width='0px'; obj.style.height='0px'; plg.classid = 'CLSID:1ACE1618-1C7D-4561-AEE1-34842AA85E90'; plg.type = 'audio/x-jazz'; document.body.appendChild(plg); return plg.isJazz ? plg : undefined; }; _initEngineJP(); } function _initWebMIDI(access, sysex) { _engine._type = 'webmidi'; _engine._version = 43; _engine._sysex = !!sysex; _engine._access = access; _engine._inMap = {}; _engine._outMap = {}; _engine._outsW = []; _engine._insW = []; var watcher; _closeAll = function() { for (var i = 0; i < this.clients.length; i++) this._close(this.clients[i]); }; _engine._refresh = function() { _engine._outs = []; _engine._ins = []; _engine._access.outputs.forEach(function(port, key) { _engine._outs.push({type: _engine._type, name: port.name, manufacturer: port.manufacturer, version: port.version}); }); _engine._access.inputs.forEach(function(port, key) { _engine._ins.push({type: _engine._type, name: port.name, manufacturer: port.manufacturer, version: port.version}); }); var diff = _diff(_engine._insW, _engine._outsW, _engine._ins, _engine._outs); if (diff) { for (j = 0; j < diff.inputs.removed.length; j++) { impl = _engine._inMap[diff.inputs.removed[j].name]; if (impl) impl._closeAll(); } for (j = 0; j < diff.outputs.removed.length; j++) { impl = _engine._outMap[diff.inputs.removed[j].name]; if (impl) impl._closeAll(); } _engine._insW = _engine._ins; _engine._outsW = _engine._outs; if (watcher) _fireW(diff); } }; _engine._openOut = function(port, name) { var impl = _engine._outMap[name]; if (!impl) { impl = { name: name, clients: [], info: { name: name, manufacturer: _engine._allOuts[name].manufacturer, version: _engine._allOuts[name].version, type: 'MIDI-out', sysex: _engine._sysex, engine: _engine._type }, _close: function(port){ _engine._closeOut(port); }, _closeAll: _closeAll, _receive: function(a){ if (impl.dev) this.dev.send(a.slice());} }; } var found; _engine._access.outputs.forEach(function(dev, key) { if (dev.name === name) found = dev; }); if (found) { impl.dev = found; _engine._outMap[name] = impl; if (impl.dev.open) impl.dev.open(); port._orig._impl = impl; _push(impl.clients, port._orig); port._info = impl.info; port._receive = function(arg) { impl._receive(arg); }; port._close = function() { impl._close(this); }; } else port._break(); }; _engine._openIn = function(port, name) { var impl = _engine._inMap[name]; if (!impl) { impl = { name: name, clients: [], info: { name: name, manufacturer: _engine._allIns[name].manufacturer, version: _engine._allIns[name].version, type: 'MIDI-in', sysex: _engine._sysex, engine: _engine._type }, _close: function(port){ _engine._closeIn(port); }, _closeAll: _closeAll, handle: function(evt) { for (var i = 0; i < this.clients.length; i++) { var msg = MIDI([].slice.call(evt.data)); this.clients[i]._emit(msg); } } }; } var found; _engine._access.inputs.forEach(function(dev, key) { if (dev.name === name) found = dev; }); if (found) { impl.dev = found; var makeHandle = function(x) { return function(evt) { x.handle(evt); }; }; impl.dev.onmidimessage = makeHandle(impl); _engine._inMap[name] = impl; if (impl.dev.open) impl.dev.open(); port._orig._impl = impl; _push(impl.clients, port._orig); port._info = impl.info; port._close = function() { impl._close(this); }; } else port._break(); }; _engine._closeOut = function(port) { var impl = port._impl; _pop(impl.clients, port._orig); if (!impl.clients.length) { if (impl.dev && impl.dev.close) impl.dev.close(); impl.dev = undefined; } }; _engine._closeIn = function(port) { var impl = port._impl; _pop(impl.clients, port._orig); if (!impl.clients.length) { if (impl.dev && impl.dev.close) impl.dev.close(); impl.dev = undefined; } }; _engine._close = function() { }; _engine._watch = function() { _engine._access.onstatechange = function() { watcher = true; setTimeout(function() { if (watcher) { _engine._refresh(); watcher = false; } }, 0); }; }; _engine._unwatch = function() { _engine._access.onstatechange = undefined; }; } function _initCRX(msg, ver) { _engine._type = 'extension'; _engine._version = ver; _engine._sysex = true; _engine._pool = []; _engine._outs = []; _engine._ins = []; _engine._inArr = []; _engine._outArr = []; _engine._inMap = {}; _engine._outMap = {}; _engine._outsW = []; _engine._insW = []; _engine.refreshClients = []; _engine._msg = msg; _engine._newPlugin = function() { var plugin = { id: _engine._pool.length }; if (!plugin.id) plugin.ready = true; else document.dispatchEvent(new CustomEvent('jazz-midi', {detail:['new']})); _engine._pool.push(plugin); }; _engine._newPlugin(); _engine._refresh = function(client) { _engine.refreshClients.push(client); client._pause(); setTimeout(function() { document.dispatchEvent(new CustomEvent('jazz-midi', { detail: ['refresh'] })); }, 0); }; _closeAll = function() { for (var i = 0; i < this.clients.length; i++) this._close(this.clients[i]); }; _engine._openOut = function(port, name) { var impl = _engine._outMap[name]; if (!impl) { if (_engine._pool.length <= _engine._outArr.length) _engine._newPlugin(); var plugin = _engine._pool[_engine._outArr.length]; impl = { name: name, clients: [], info: { name: name, manufacturer: _engine._allOuts[name].manufacturer, version: _engine._allOuts[name].version, type: 'MIDI-out', sysex: _engine._sysex, engine: _engine._type }, _start: function(){ document.dispatchEvent(new CustomEvent('jazz-midi', {detail:['openout', plugin.id, name]})); }, _close: function(port){ _engine._closeOut(port); }, _closeAll: _closeAll, _receive: function(a){ var v = a.slice(); v.splice(0, 0, 'play', plugin.id); document.dispatchEvent(new CustomEvent('jazz-midi', {detail: v})); } }; impl.plugin = plugin; plugin.output = impl; _engine._outArr.push(impl); _engine._outMap[name] = impl; } port._orig._impl = impl; _push(impl.clients, port._orig); port._info = impl.info; port._receive = function(arg) { impl._receive(arg); }; port._close = function() { impl._close(this); }; if (!impl.open) { if (impl.plugin.ready) impl._start(); port._pause(); } }; _engine._openIn = function(port, name) { var impl = _engine._inMap[name]; if (!impl) { if (_engine._pool.length <= _engine._inArr.length) _engine._newPlugin(); var plugin = _engine._pool[_engine._inArr.length]; impl = { name: name, clients: [], info: { name: name, manufacturer: _engine._allIns[name].manufacturer, version: _engine._allIns[name].version, type: 'MIDI-in', sysex: _engine._sysex, engine: _engine._type }, _start: function(){ document.dispatchEvent(new CustomEvent('jazz-midi', {detail:['openin', plugin.id, name]})); }, _close: function(port){ _engine._closeIn(port); }, _closeAll: _closeAll }; impl.plugin = plugin; plugin.input = impl; _engine._inArr.push(impl); _engine._inMap[name] = impl; } port._orig._impl = impl; _push(impl.clients, port._orig); port._info = impl.info; port._close = function() { impl._close(this); }; if (!impl.open) { if (impl.plugin.ready) impl._start(); port._pause(); } }; _engine._closeOut = function(port) { var impl = port._impl; _pop(impl.clients, port._orig); if (!impl.clients.length) { impl.open = false; document.dispatchEvent(new CustomEvent('jazz-midi', {detail:['closeout', impl.plugin.id]})); } }; _engine._closeIn = function(port) { var impl = port._impl; _pop(impl.clients, port._orig); if (!impl.clients.length) { impl.open = false; document.dispatchEvent(new CustomEvent('jazz-midi', {detail:['closein', impl.plugin.id]})); } }; _engine._close = function() { }; var watcher; _engine._watch = function() { _engine._insW = _engine._ins; _engine._outsW = _engine._outs; watcher = setInterval(function() { document.dispatchEvent(new CustomEvent('jazz-midi', {detail:['refresh']})); }, 250); }; _engine._unwatch = function() { clearInterval(watcher); watcher = undefined; }; document.addEventListener('jazz-midi-msg', function(e) { var v = _engine._msg.innerText.split('\n'); var impl, i, j; _engine._msg.innerText = ''; for (i = 0; i < v.length; i++) { var a = []; try { a = JSON.parse(v[i]);} catch (err) {} if (!a.length) continue; if (a[0] === 'refresh') { if (a[1].ins) { for (j = 0; j < a[1].ins.length; j++) a[1].ins[j].type = _engine._type; _engine._ins = a[1].ins; } if (a[1].outs) { for (j = 0; j < a[1].outs.length; j++) a[1].outs[j].type = _engine._type; _engine._outs = a[1].outs; } for (j = 0; j < _engine.refreshClients.length; j++) _engine.refreshClients[j]._resume(); _engine.refreshClients = []; var diff = _diff(_engine._insW, _engine._outsW, _engine._ins, _engine._outs); if (diff) { _engine._insW = _engine._ins; _engine._outsW = _engine._outs; for (j = 0; j < diff.inputs.removed.length; j++) { impl = _engine._inMap[diff.inputs.removed[j].name]; if (impl) impl._closeAll(); } for (j = 0; j < diff.outputs.removed.length; j++) { impl = _engine._outMap[diff.outputs.removed[j].name]; if (impl) impl._closeAll(); } if (watcher) _fireW(diff); } } else if (a[0] === 'version') { var plugin = _engine._pool[a[1]]; if (plugin) { plugin.ready = true; if (plugin.input) plugin.input._start(); if (plugin.output) plugin.output._start(); } } else if (a[0] === 'openout') { impl = _engine._pool[a[1]].output; if (impl) { if (a[2] == impl.name) { impl.open = true; if (impl.clients) for (j = 0; j < impl.clients.length; j++) impl.clients[j]._resume(); } else if (impl.clients) for (j = 0; j < impl.clients.length; j++) impl.clients[j]._crash(); } } else if (a[0] === 'openin') { impl = _engine._pool[a[1