mirror of
https://github.com/noerw/leaflet-playback
synced 2025-03-13 19:30:27 +01:00
30 lines
No EOL
19 KiB
JavaScript
30 lines
No EOL
19 KiB
JavaScript
/*
|
|
|
|
WebMidi v1.0.0-beta.13
|
|
|
|
Tame the Web MIDI API. Send and receive MIDI messages with ease. Control instruments with user-friendly functions (playNote, sendPitchBend, etc.). React to MIDI input with simple event listeners (noteon, pitchbend, controlchange, etc.).
|
|
https://github.com/cotejp/webmidi
|
|
|
|
|
|
The MIT License (MIT)
|
|
|
|
Copyright (c) 2015, Jean-Philippe Côté
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
|
associated documentation files (the "Software"), to deal in the Software without restriction,
|
|
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
|
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
|
|
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
|
|
OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
!function(a){"use strict";function b(){Object.defineProperties(this,{supported:{enumerable:!0,get:function(){return"requestMIDIAccess"in navigator}},connected:{enumerable:!0,get:function(){return void 0!==this["interface"]}},inputs:{enumerable:!0,get:function(){var a=[];if(this.connected)for(var b=this["interface"].inputs.values(),c=b.next();c&&!c.done;c=b.next())a.push(c.value);return a}},outputs:{enumerable:!0,get:function(){var a=[];if(this.connected)for(var b=this["interface"].outputs.values(),c=b.next();c&&!c.done;c=b.next())a.push(c.value);return a}},sysexEnabled:{enumerable:!0,get:function(){return this["interface"]&&this["interface"].sysexEnabled}},time:{enumerable:!0,get:function(){return window.performance.now()}}}),c()}function c(){h.system.statechange=[];for(var a in i)i.hasOwnProperty(a)&&(h.channel[a]={});for(var b in j)j.hasOwnProperty(b)&&(h.system[b]=[])}function d(a){h.system.statechange.forEach(function(b){b(a)})}function e(a){var b,c,d=a.data[0]>>4,e=(15&a.data[0])+1;a.data.length>1&&(b=a.data[1],c=a.data.length>2?a.data[2]:void 0);var f={device:a.currentTarget,data:a.data,receivedTime:a.receivedTime,timeStamp:a.timeStamp,channel:e};d===i.noteoff||d===i.noteon&&0===c?(f.type="noteoff",f.note={number:b,name:k[b%12],octave:Math.floor(b/12-1)-3},f.velocity=c/127):d===i.noteon?(f.type="noteon",f.note={number:b,name:k[b%12],octave:Math.floor(b/12-1)-3},f.velocity=c/127):d===i.keyaftertouch?(f.type="keyaftertouch",f.note={number:b,name:k[b%12],octave:Math.floor(b/12-1)-3},f.value=c/127):d===i.controlchange&&b>=0&&119>=b?(f.type="controlchange",f.controller={number:b,name:""},f.value=c):d===i.channelmode&&b>=120&&127>=b?(f.type="channelmode",f.controller={number:b,name:""},f.value=c):d===i.programchange?(f.type="programchange",f.value=b):d===i.channelaftertouch?(f.type="channelaftertouch",f.value=b/127):d===i.pitchbend?(f.type="pitchbend",f.value=((c<<7)+b-8192)/8192):f.type="unknownchannelmessage",h.channel[f.type][f.device.id]&&h.channel[f.type][f.device.id][e]&&h.channel[f.type][f.device.id][e].forEach(function(a){a(f)})}function f(a){var b=a.data[0],c={device:a.currentTarget,data:a.data,receivedTime:a.receivedTime,timeStamp:a.timeStamp};b===j.sysex?c.type="sysex":b===j.timecode?c.type="timecode":b===j.songposition?c.type="songposition":b===j.songselect?(c.type="songselect",c.song=a.data[1]):b===j.tuningrequest?c.type="tuningrequest":b===j.clock?c.type="clock":b===j.start?c.type="start":b===j["continue"]?c.type="continue":b===j.stop?c.type="stop":b===j.activesensing?c.type="activesensing":b===j.reset?c.type="reset":c.type="unknownsystemmessage",h.system[c.type]&&h.system[c.type].forEach(function(a){a(c)})}function g(a){a.data[0]<240?e(a):a.data[0]<=255&&f(a)}var h={channel:{},system:{}},i={noteoff:8,noteon:9,keyaftertouch:10,controlchange:11,channelmode:11,programchange:12,channelaftertouch:13,pitchbend:14},j={sysex:240,timecode:241,songposition:242,songselect:243,tuningrequest:246,sysexend:247,clock:248,start:250,"continue":251,stop:252,activesensing:254,reset:255,unknownsystemmessage:-1},k=["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"],l={C:0,D:2,E:4,F:5,G:7,A:9,B:11},m={pitchbendrange:[0,0],channelfinetuning:[0,1],channelcoarsetuning:[0,2],tuningprogram:[0,3],tuningbank:[0,4],modulationrange:[0,5],azimuthangle:[61,0],elevationangle:[61,1],gain:[61,2],distanceratio:[61,3],maximumdistance:[61,4],maximumdistancegain:[61,5],referencedistanceratio:[61,6],panspreadangle:[61,7],rollangle:[61,8]};b.prototype.enable=function(a,b,c){var e=this;if(a&&"function"!=typeof a||b&&"function"!=typeof b)throw new TypeError("The success and error handlers must be functions.");return!this.supported&&b?void b("The Web MIDI API is not supported by your browser."):void navigator.requestMIDIAccess({sysex:c}).then(function(b){e["interface"]=b,e["interface"].onstatechange=d,e.inputs.forEach(function(a){a.onmidimessage=g}),a&&a()},b)},b.prototype.addListener=function(a,b,c){if(!this.connected)throw new Error("WebMidi must be connected before adding event listeners.");if(c=c||{},void 0===c.channel&&(c.channel="all"),c.channel.constructor!==Array&&(c.channel=[c.channel]),c.input=c.input||this.inputs,c.input.constructor!==Array&&(c.input=[c.input]),c.input.forEach(function(a){if(!(a instanceof MIDIInput))throw new ReferenceError("There is no such input device.")}),c.channel.forEach(function(a){if("all"!==a&&!(a>=1&&16>=a))throw new RangeError("The channel must be an integer between 1 and 16 or the value 'all'.")}),"function"!=typeof b)throw new TypeError("The 'listener' parameter must be a function.");if("statechange"===a||j[a])h.system[a].push(b);else{if(!i[a])throw new TypeError("The specified event type is not supported.");if(c.channel.indexOf("all")>-1){c.channel=[];for(var d=1;16>=d;d++)c.channel.push(d)}h.channel[a]||(h.channel[a]=[]),c.input.forEach(function(d){h.channel[a][d.id]||(h.channel[a][d.id]=[]),c.channel.forEach(function(c){h.channel[a][d.id][c]||(h.channel[a][d.id][c]=[]),h.channel[a][d.id][c].push(b)})})}return this},b.prototype.getDeviceById=function(a,b){for(var c="output"===b?this.outputs:this.inputs,d=0;d<c.length;d++)if(c[d].id===a)return c[d];return!1},b.prototype.getDeviceIndexById=function(a,b){for(var c="output"===b?this.outputs:this.inputs,d=0;d<c.length;d++)if(c[d].id===a)return d;return!1},b.prototype.hasListener=function(a,b,c){if(!this.connected)throw new Error("WebMidi must be connected before checking event listeners.");if("function"!=typeof b)throw new TypeError("The 'listener' parameter must be a function.");if(c=c||{},c.input=c.input||this.inputs,c.input.constructor!==Array&&(c.input=[c.input]),void 0===c.channel&&(c.channel="all"),c.channel.constructor!==Array&&(c.channel=[c.channel]),"statechange"===a||j[a]){for(var d=0;d<h.system[a].length;d++)if(h.system[a][d]===b)return!0}else if(i[a]){if(c.channel.indexOf("all")>-1){c.channel=[];for(var e=1;16>=e;e++)c.channel.push(e)}return h.channel[a]?c.input.every(function(d){return h.channel[a][d.id]?c.channel.every(function(c){var e=h.channel[a][d.id][c];return e&&e.indexOf(b)>-1}):!1}):!1}return!1},b.prototype.removeListener=function(a,b,c){if(!this.connected)throw new Error("WebMidi must be connected before removing event listeners.");if(c=c||{},c.input=c.input||this.inputs,c.input.constructor!==Array&&(c.input=[c.input]),void 0===c.channel&&(c.channel="all"),c.channel.constructor!==Array&&(c.channel=[c.channel]),"statechange"===a||j[a])for(var d=0;d<h.system[a].length;d++)h.system[a][d]===b&&h.system[a].splice(d,1);else if(i[a]){if(c.channel.indexOf("all")>-1){c.channel=[];for(var e=1;16>=e;e++)c.channel.push(e)}if(!h.channel[a])return!1;c.input.forEach(function(d){h.channel[a][d.id]&&c.channel.forEach(function(c){var e=h.channel[a][d.id][c];if(e)for(var f=0;f<e.length;f++)e[f]===b&&e.splice(f,1)})})}return this},b.prototype.send=function(a,b,c,d){if(!this.connected)throw new Error("WebMidi must be connected before sending messages.");if(!(a>=128&&255>=a))throw new RangeError("The status byte must be an integer between 128 (0x80) and 255 (0xFF).");Array.isArray(b)||(b=parseInt(b)>=0&&parseInt(b)<=127?[parseInt(b)]:[]),c=c||this.outputs,c.constructor!==Array&&(c=[c]),c.forEach(function(a){if(!(a instanceof MIDIOutput))throw new ReferenceError("There is no such output device.")});var e=[a];return b.forEach(function(a){if(!(a>=0&&255>=a))throw new RangeError("The data bytes must be integers between 0 (0x00) and 255 (0xFF).");e.push(a)}),c.forEach(function(a){a.send(e,parseFloat(d)||0)}),this},b.prototype.sendSysex=function(a,b,c,d){if(!this.sysexEnabled)throw new Error("SysEx message support must first be activated.");return a=[].concat(a),b.forEach(function(a){if(0>a||a>127)throw new RangeError("The data bytes of a SysEx message must be integers between 0 (0x00) and 127 (0x7F).")}),b=a.concat(b,j.sysexend),this.send(j.sysex,b,c,d),this},b.prototype.sendTimecodeQuarterFrame=function(a,b,c){return this.send(j.timecode,a,b,c),this},b.prototype.sendSongPosition=function(a,b,c){a=parseInt(a)||0;var d=a>>7&127,e=127&a;return this.send(j.songposition,[d,e],b,c),this},b.prototype.sendSongSelect=function(a,b,c){if(a=parseInt(a),!(a>=0&&127>=a))throw new RangeError("The song number must be between 0 and 127.");return this.send(j.songselect,[a],b,c),this},b.prototype.sendTuningRequest=function(a,b){return this.send(j.tuningrequest,void 0,a,b),this},b.prototype.sendClock=function(a,b){return this.send(j.clock,void 0,a,b),this},b.prototype.sendStart=function(a,b){return this.send(j.start,void 0,a,b),this},b.prototype.sendContinue=function(a,b){return this.send(j["continue"],void 0,a,b),this},b.prototype.sendStop=function(a,b){return this.send(j.stop,void 0,a,b),this},b.prototype.sendActiveSensing=function(a,b){return this.send(j.activesensing,void 0,a,b),this},b.prototype.sendReset=function(a,b){return this.send(j.reset,void 0,a,b),this},b.prototype.stopNote=function(a,b,c,d,e){var f=this;b=parseFloat(b),(isNaN(b)||0>b||b>1)&&(b=.5);var g=Math.round(127*b);return this._convertNoteToArray(a).forEach(function(a){f._convertChannelToArray(d).forEach(function(b){f.send((i.noteoff<<4)+(b-1),[a,g],c,f._parseTimeParameter(e))})}),this},b.prototype.playNote=function(a,b,c,d,e,f){var g=this;b=parseFloat(b),(isNaN(b)||0>b||b>1)&&(b=.5);var h=Math.round(127*b);return f=g._parseTimeParameter(f)||0,this._convertNoteToArray(a).forEach(function(a){g._convertChannelToArray(e).forEach(function(b){g.send((i.noteon<<4)+(b-1),[a,h],d,f)})}),void 0!==c&&this._convertNoteToArray(a).forEach(function(a){g._convertChannelToArray(e).forEach(function(b){g.send((i.noteoff<<4)+(b-1),[a,64],d,f+c)})}),this},b.prototype.sendKeyAftertouch=function(a,b,c,d,e){var f=this;if(1>d||d>16)throw new RangeError("The channel must be between 1 and 16.");b=parseFloat(b),(isNaN(b)||0>b||b>1)&&(b=.5);var g=Math.round(127*b);return this._convertNoteToArray(a).forEach(function(a){f._convertChannelToArray(d).forEach(function(b){f.send((i.keyaftertouch<<4)+(b-1),[a,g],c,f._parseTimeParameter(e))})}),this},b.prototype.sendControlChange=function(a,b,c,d,e){var f=this;if(a=parseInt(a),!(a>=0&&119>=a))throw new RangeError("Controller numbers must be between 0 and 119.");if(b=parseInt(b)||0,!(b>=0&&127>=b))throw new RangeError("Controller value must be between 0 and 127.");return this._convertChannelToArray(d).forEach(function(d){f.send((i.controlchange<<4)+(d-1),[a,b],c,f._parseTimeParameter(e))}),this},b.prototype._selectRegisteredParameter=function(a,b,c,d){var e=this;if(a[0]=parseInt(a[0]),!(a[0]>=0&&a[0]<=127))throw new RangeError("The control65 value must be between 0 and 127");if(a[1]=parseInt(a[1]),!(a[1]>=0&&a[1]<=127))throw new RangeError("The control64 value must be between 0 and 127");return this._convertChannelToArray(c).forEach(function(f){e.sendControlChange(101,a[0],b,c,d),e.sendControlChange(100,a[1],b,c,d)}),this},b.prototype._selectNonRegisteredParameter=function(a,b,c,d){var e=this;if(a[0]=parseInt(a[0]),!(a[0]>=0&&a[0]<=127))throw new RangeError("The control63 value must be between 0 and 127");if(a[1]=parseInt(a[1]),!(a[1]>=0&&a[1]<=127))throw new RangeError("The control62 value must be between 0 and 127");return this._convertChannelToArray(c).forEach(function(f){e.sendControlChange(99,a[0],b,c,d),e.sendControlChange(98,a[1],b,c,d)}),this},b.prototype._setCurrentRegisteredParameter=function(a,b,c,d){var e=this;if(a=[].concat(a),a[0]=parseInt(a[0]),!(a[0]>=0&&a[0]<=127))throw new RangeError("The msb value must be between 0 and 127");return this._convertChannelToArray(c).forEach(function(f){e.sendControlChange(6,a[0],b,c,d)}),a[1]=parseInt(a[1]),a[1]>=0&&a[1]<=127&&this._convertChannelToArray(c).forEach(function(f){e.sendControlChange(38,a[1],b,c,d)}),this},b.prototype._deselectRegisteredParameter=function(a,b,c){var d=this;return this._convertChannelToArray(b).forEach(function(e){d.sendControlChange(101,127,a,b,c),d.sendControlChange(100,127,a,b,c)}),this},b.prototype.setRegisteredParameter=function(a,b,c,d,e){var f=this;if(!Array.isArray(a)){if(!m[a])throw new Error("The specified parameter is not available.");a=m[a]}return this._convertChannelToArray(d).forEach(function(g){f._selectRegisteredParameter(a,c,d,e),f._setCurrentRegisteredParameter(b,c,d,e),f._deselectRegisteredParameter(c,d,e)}),this},b.prototype.setNonRegisteredParameter=function(a,b,c,d,e){var f=this;if(!(a[0]>=0&&a[0]<=127&&a[1]>=0&&a[1]<=127))throw new Error("Position 0 and 1 of the 2-position parameter array must both be between 0 and 127.");return b=[].concat(b),this._convertChannelToArray(d).forEach(function(g){f._selectNonRegisteredParameter(a,c,d,e),f._setCurrentRegisteredParameter(b,c,d,e),f._deselectRegisteredParameter(c,d,e)}),this},b.prototype.incrementRegisteredParameter=function(a,b,c,d){var e=this;if(!Array.isArray(a)){if(!m[a])throw new Error("The specified parameter is not available.");a=m[a]}return this._convertChannelToArray(c).forEach(function(f){e._selectRegisteredParameter(a,b,c,d),e.sendControlChange(96,0,b,c,d),e._deselectRegisteredParameter(b,c,d)}),this},b.prototype.decrementRegisteredParameter=function(a,b,c,d){var e=this;if(!Array.isArray(a)){if(!m[a])throw new Error("The specified parameter is not available.");a=m[a]}return this._convertChannelToArray(c).forEach(function(f){e._selectRegisteredParameter(a,b,c,d),e.sendControlChange(97,0,b,c,d),e._deselectRegisteredParameter(b,c,d)}),this},b.prototype.setPitchBendRange=function(a,b,c,d,e){var f=this;if(a=parseInt(a)||0,!(a>=0&&127>=a))throw new RangeError("The semitones value must be between 0 and 127");if(b=parseInt(b)||0,!(b>=0&&127>=b))throw new RangeError("The cents value must be between 0 and 127");return this._convertChannelToArray(d).forEach(function(g){f.setRegisteredParameter("pitchbendrange",[a,b],c,d,e)}),this},b.prototype.setModulationRange=function(a,b,c,d,e){var f=this;if(a=parseInt(a)||0,!(a>=0&&127>=a))throw new RangeError("The semitones value must be between 0 and 127");if(b=parseInt(b)||0,!(b>=0&&127>=b))throw new RangeError("The cents value must be between 0 and 127");return this._convertChannelToArray(d).forEach(function(g){f.setRegisteredParameter("modulationrange",[a,b],c,d,e)}),this},b.prototype.setMasterTuning=function(a,b,c,d){var e=this;if(a=parseFloat(a)||0,-65>=a||a>=64)throw new RangeError("The value must be a decimal number larger than -65 and smaller than 64.");var f=parseInt(a)+64,g=a-parseInt(a);g=Math.round((g+1)/2*16383);var h=g>>7&127,i=127&g;return this._convertChannelToArray(c).forEach(function(a){e.setRegisteredParameter("channelcoarsetuning",f,b,c,d),e.setRegisteredParameter("channelfinetuning",[h,i],b,c,d)}),this},b.prototype.setTuningProgram=function(a,b,c,d){var e=this;if(a=parseInt(a)||0,!(a>=0&&127>=a))throw new RangeError("The program value must be between 0 and 127");return this._convertChannelToArray(c).forEach(function(f){e.setRegisteredParameter("tuningprogram",a,b,c,d)}),this},b.prototype.setTuningBank=function(a,b,c,d){var e=this;if(a=parseInt(a)||0,!(a>=0&&127>=a))throw new RangeError("The bank value must be between 0 and 127");return this._convertChannelToArray(c).forEach(function(f){e.setRegisteredParameter("tuningbank",a,b,c,d)}),this},b.prototype.sendChannelMode=function(a,b,c,d,e){var f=this;if(a=parseInt(a),isNaN(a)||120>a||a>127)throw new RangeError("Channel mode commands must be between 120 and 127.");if(b=parseInt(b),isNaN(b)||0>b||b>127)throw new RangeError("Value must be integers between 0 and 127.");return this._convertChannelToArray(d).forEach(function(d){f.send((i.channelmode<<4)+(d-1),[a,b],c,f._parseTimeParameter(e))}),this},b.prototype.sendProgramChange=function(a,b,c,d){var e=this;if(a=parseInt(a),isNaN(a)||0>a||a>127)throw new RangeError("Program numbers must be between 0 and 127.");return this._convertChannelToArray(c).forEach(function(c){e.send((i.programchange<<4)+(c-1),[a],b,e._parseTimeParameter(d))}),this},b.prototype.sendChannelAftertouch=function(a,b,c,d){var e=this;a=parseFloat(a),(isNaN(a)||0>a||a>1)&&(a=.5);var f=Math.round(127*a);return this._convertChannelToArray(c).forEach(function(a){e.send((i.channelaftertouch<<4)+(a-1),[f],b,e._parseTimeParameter(d))}),this},b.prototype.sendPitchBend=function(a,b,c,d){var e=this;if(a=parseFloat(a),isNaN(a)||-1>a||a>1)throw new RangeError("Pitch bend value must be between -1 and 1.");var f=Math.round((a+1)/2*16383),g=f>>7&127,h=127&f;return this._convertChannelToArray(c).forEach(function(a){e.send((i.pitchbend<<4)+(a-1),[h,g],b,e._parseTimeParameter(d))}),this},b.prototype.guessNoteNumber=function(a){var b=!1;if(a&&a.toFixed&&a>=0&&127>=a?b=a:parseInt(a)>=0&&parseInt(a)<=127?b=parseInt(a):("string"==typeof a||a instanceof String)&&(b=this.noteNameToNumber(a)),b===!1)throw new Error("Invalid note number ("+a+").");return b},b.prototype.noteNameToNumber=function(a){var b=a.match(/([CDEFGAB])(#{0,2}|b{0,2})(-?\d+)/i);if(!b)throw new RangeError("Invalid note name.");var c=l[b[1].toUpperCase()],d=parseInt(b[3]),e=12*(d+2)+c;if(b[2].toLowerCase().indexOf("b")>-1?e-=b[2].length:b[2].toLowerCase().indexOf("#")>-1&&(e+=b[2].length),0>c||-2>d||d>8||0>e||e>127)throw new RangeError("Invalid note name or note outside valid range.");return e},b.prototype._convertNoteToArray=function(a){var b=this,c=[];return Array.isArray(a)||(a=[a]),a.forEach(function(a){c.push(b.guessNoteNumber(a))}),c},b.prototype._convertChannelToArray=function(a){if(("all"===a||void 0===a)&&(a=["all"]),Array.isArray(a)||(a=[a]),a.indexOf("all")>-1){a=[];for(var b=1;16>=b;b++)a.push(b)}return a.forEach(function(a){if(!(a>=1&&16>=a))throw new RangeError("MIDI channels must be between 1 and 16.")}),a},b.prototype._parseTimeParameter=function(a){return a&&a.substring&&"+"===a.substring(0,1)?parseFloat(a)+this.time||void 0:parseFloat(a)||void 0},"function"==typeof define&&"object"==typeof define.amd?define([],function(){return new b}):"undefined"!=typeof module&&module.exports?module.exports=b:a.WebMidi||(a.WebMidi=new b)}(this); |