diff --git a/index.html b/index.html
new file mode 100644
index 0000000..2397574
--- /dev/null
+++ b/index.html
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+ Document
+
+
+
+ Oscillator 1
+
+
+
Decay
+
Attack
+
Sustain
+
Release
+
+
+
+
Distortion
+
LFO
+
Reverb
+
+
+
+ Oscillator 2
+
+
+
+
Decay
+
Attack
+
Sustain
+
Release
+
+
+
+
Distortion
+
LFO
+
Reverb
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/scripts/midi.js b/scripts/midi.js
new file mode 100644
index 0000000..2af406f
--- /dev/null
+++ b/scripts/midi.js
@@ -0,0 +1,34 @@
+var midi, data;
+// request MIDI access
+if (navigator.requestMIDIAccess) {
+ navigator.requestMIDIAccess({
+ sysex: false
+ }).then(onMIDISuccess, onMIDIFailure);
+} else {
+ alert("No MIDI support in your browser.");
+}
+
+// midi functions
+function onMIDISuccess(midiAccess) {
+ // when we get a succesful response, run this code
+ midi = midiAccess; // this is our raw MIDI data, inputs, outputs, and sysex status
+
+ var inputs = midi.inputs.values();
+ // loop over all available inputs and listen for any MIDI input
+ for (var input = inputs.next(); input && !input.done; input = inputs.next()) {
+ // each time there is a midi message call the onMIDIMessage function
+ input.value.onmidimessage = onMIDIMessage;
+ }
+}
+
+function onMIDIFailure(error) {
+ // when we get a failed response, run this code
+ console.log("No access to MIDI devices or your browser doesn't support WebMIDI API. Please use WebMIDIAPIShim " + error);
+}
+
+function onMIDIMessage(message) {
+ data = message.data; // this gives us our [command/channel, note, velocity] data.
+ console.log('MIDI data', data); // MIDI data [144, 63, 73]
+ midiNote(data[1], data[2]);
+ midiNote2(data[1], data[2]);
+}
\ No newline at end of file
diff --git a/scripts/osc1.js b/scripts/osc1.js
new file mode 100644
index 0000000..5c46bef
--- /dev/null
+++ b/scripts/osc1.js
@@ -0,0 +1,88 @@
+var dist1_1;
+var filter1_1;
+var reverb1_1 = 1;
+synth1 = new Tone.FMSynth({
+ oscillator: {
+ type: "sawtooth",
+ detune: 0,
+ },
+ envelope: {
+ attack: 0,
+ decay: 0,
+ sustain: 0,
+ release: 0,
+ },
+
+ }).toMaster();
+
+piano.on('change',function(keyValue) {
+ if (keyValue.state == true) { // If Key is down
+ synth1.triggerAttackRelease(Tone.Frequency(keyValue.note, "midi").toNote()); // Play note
+ }
+})
+// Midi input
+function midiNote(note, vel){
+ if(vel !=0){ // Skip Key up, If velocity is 0 then play
+ synth1.triggerAttackRelease(Tone.Frequency(note, "midi").toNote()); // Play note
+ piano.toggleKey(note, true)
+ }else{
+ piano.toggleKey(note, false)
+ }
+}
+
+//filters
+function updateFilter1(){
+ var filter1 = new Tone.AutoFilter(filter1_1).start(); //LFO
+ var reverb1 = new Tone.Reverb(reverb1_1);
+ var distortion1 = new Tone.Distortion(dist1_1); //DIST
+ // connect the player to the filter, distortion and then to the master output
+ synth1.chain(filter1, distortion1, reverb1, Tone.Destination);
+}
+
+
+// Controls
+var sus1_d = new Nexus.Dial('#sustain1', dial_settings1)
+var dec1_d = new Nexus.Dial('#decay1', dial_settings1)
+var atk1_d = new Nexus.Dial('#attack1', dial_settings1)
+var rel1_d = new Nexus.Dial('#release1', dial_settings1)
+// var tune1_d = new Nexus.Dial('#tune1', dial_settings1)
+var select1 = new Nexus.Select('#osc1', dropdown_osc)
+
+var dist1 = new Nexus.Dial('#dist1', distortion_settings)
+var lfo1 = new Nexus.Dial('#lfo1', dial_settings1)
+var reverb1_d = new Nexus.Dial('#reverb1', reverb_settings)
+// When controls change
+
+sus1_d.on('change',function(value) {
+ synth1.envelope.attack = value;
+});
+dec1_d.on('change',function(value) {
+ synth1.envelope.decay = value;
+});
+atk1_d.on('change',function(value) {
+ synth1.envelope.attack = value;
+});
+rel1_d.on('change',function(value) {
+ synth1.envelope.release = value;
+});
+// tune1_d.on('change',function(value) {
+// synth1.oscillator.detune = value;
+// });
+select1.on('change',function(value) {
+ synth1.oscillator.type = value.value;
+});
+
+//Effect knobs
+dist1.on('change',function(value) {
+ dist1_1 = value.toFixed(1);
+ typewatch(function(){updateFilter1();}, 100 );
+
+});
+lfo1.on('change',function(value) {
+ filter1_1 = value.toFixed(1);
+ typewatch(function(){updateFilter1();}, 100 );
+});
+reverb1_d.on('change',function(value) {
+ reverb1_1 = value.toFixed(0);
+ typewatch(function(){updateFilter1();}, 100 );
+});
diff --git a/scripts/osc2.js b/scripts/osc2.js
new file mode 100644
index 0000000..1b34ee0
--- /dev/null
+++ b/scripts/osc2.js
@@ -0,0 +1,84 @@
+var dist2_2;
+var filter2_2;
+var reverb2_2 = 1;
+synth2 = new Tone.FMSynth({
+ oscillator: {
+ type: "sawtooth",
+ detune: 0,
+ },
+ envelope: {
+ attack: 0,
+ decay: 0,
+ sustain: 0,
+ release: 0,
+ },
+
+ }).toMaster();
+
+piano.on('change',function(keyValue) {
+ if (keyValue.state == true) { // If Key is down
+ synth2.triggerAttackRelease(Tone.Frequency(keyValue.note, "midi").toNote()); // Play note
+ }
+})
+// Midi input
+function midiNote2(note, vel){
+ if(vel !=0){ // Skip Key up, If velocity is 0 then play
+ synth2.triggerAttackRelease(Tone.Frequency(note, "midi").toNote()); // Play note
+ }
+}
+//filters
+function updateFilter2(){
+ var filter2 = new Tone.AutoFilter(filter2_2).start(); //LFO
+ var reverb2 = new Tone.Reverb(reverb2_2);
+ var distortion2 = new Tone.Distortion(dist2_2); //DIST
+ // connect the player to the filter, distortion and then to the master output
+ synth2.chain(filter2, distortion2, reverb2, Tone.Destination);
+}
+
+
+// Controls
+var sus2_d = new Nexus.Dial('#sustain2', dial_settings1)
+var dec2_d = new Nexus.Dial('#decay2', dial_settings1)
+var atk2_d = new Nexus.Dial('#attack2', dial_settings1)
+var rel2_d = new Nexus.Dial('#release2', dial_settings1)
+// var tune2_d = new Nexus.Dial('#tune2', dial_settings2)
+var select2 = new Nexus.Select('#osc2', dropdown_osc)
+
+var dist2 = new Nexus.Dial('#dist2', distortion_settings)
+var lfo2 = new Nexus.Dial('#lfo2', dial_settings1)
+var reverb2_d = new Nexus.Dial('#reverb2', reverb_settings)
+// When controls change
+
+sus2_d.on('change',function(value) {
+ synth2.envelope.attack = value;
+});
+dec2_d.on('change',function(value) {
+ synth2.envelope.decay = value;
+});
+atk2_d.on('change',function(value) {
+ synth2.envelope.attack = value;
+});
+rel2_d.on('change',function(value) {
+ synth2.envelope.release = value;
+});
+// tune2_d.on('change',function(value) {
+// synth2.oscillator.detune = value;
+// });
+select2.on('change',function(value) {
+ synth2.oscillator.type = value.value;
+});
+
+//Effect knobs
+dist2.on('change',function(value) {
+ dist2_2 = value.toFixed(1);
+ typewatch(function(){updateFilter2();}, 100 );
+
+});
+lfo2.on('change',function(value) {
+ filter2_2 = value.toFixed(1);
+ typewatch(function(){updateFilter2();}, 100 );
+});
+reverb2_d.on('change',function(value) {
+ reverb2_2 = value.toFixed(0);
+ typewatch(function(){updateFilter2();}, 100 );
+});
diff --git a/scripts/scripts.js b/scripts/scripts.js
new file mode 100644
index 0000000..9aa1e87
--- /dev/null
+++ b/scripts/scripts.js
@@ -0,0 +1,47 @@
+//Piano roll
+var piano = new Nexus.Piano('#target',{
+ 'size': [750,125],
+ 'mode': 'button', // 'button', 'toggle', or 'impulse'
+ 'lowNote': 24,
+ 'highNote': 100
+})
+var dial_settings1 = {
+ 'size': [50,50],
+ 'interaction': 'radial',
+ 'mode': 'relative',
+ 'min': 0,
+ 'max': 10,
+ 'step': 0,
+ 'value': 0
+}
+var dropdown_osc = {
+ 'size': [100,30],
+ 'options': ['sawtooth', 'sawtooth2', 'sawtooth3', 'sawtooth4','sine', 'sine2', 'sine3', 'sine4', 'square', 'square2', 'square3', 'square4', 'triangle', 'triangle2', 'triangle3', 'triangle4']
+}
+var distortion_settings = {
+ 'size': [50,50],
+ 'interaction': 'radial', // "radial", "vertical", or "horizontal"
+ 'mode': 'relative', // "absolute" or "relative"
+ 'min': 0,
+ 'max': 1,
+ 'step': 0.1,
+ 'value': 0
+}
+var reverb_settings = {
+ 'size': [50,50],
+ 'interaction': 'radial', // "radial", "vertical", or "horizontal"
+ 'mode': 'relative', // "absolute" or "relative"
+ 'min': 1,
+ 'max': 10,
+ 'step': 0.1,
+ 'value': 0
+}
+
+
+var typewatch = function(){
+ var timer = 0;
+ return function(callback, ms){
+ clearTimeout (timer);
+ timer = setTimeout(callback, ms);
+ }
+}();
\ No newline at end of file
diff --git a/scripts/scripts_obs.js b/scripts/scripts_obs.js
new file mode 100644
index 0000000..dcffc6d
--- /dev/null
+++ b/scripts/scripts_obs.js
@@ -0,0 +1,133 @@
+const synth = new Tone.FMSynth().toMaster();
+var sus1 = 0;
+var atk1 = 0;
+var wav = "sawtooth";
+// var synth = new Tone.AMSynth({
+// oscillator: {
+// type: "square",
+// },
+// envelope: {
+// attack: atk1,
+// decay: 0.1,
+// sustain: sus1,
+// release: 0.1,
+// },
+// modulation: {
+// type: "square",
+// },
+// }).toMaster();
+// const synth = new Tone.FMSynth().toDestination();
+// synth.type = "pwm";
+
+var activeSynths = {};
+const createPiano = (lowNote, highNote) => {
+ const newPiano = new Nexus.Piano("#target", {
+ size: [500, 125],
+ mode: "button",
+ lowNote,
+ highNote,
+ });
+
+ return newPiano;
+};
+
+let lowNote = 72;
+let highNote = 84;
+let piano = createPiano(lowNote, highNote);
+
+synth.triggerRelease();
+
+
+const keyMapper = {
+ a: 0,
+ w: 1,
+ s: 2,
+ e: 3,
+ d: 4,
+ f: 5,
+ t: 6,
+ g: 7,
+ y: 8,
+ h: 9,
+ u: 10,
+ j: 11,
+ k: 12,
+};
+
+
+
+piano.on("change", (k) => {
+ if (k.state) {
+ if (!activeSynths[k.note]) {
+ activeSynths[k.note] = new Tone.AMSynth({
+ oscillator: {
+ type: wav,
+ },
+ envelope: {
+ attack: atk1,
+ decay: 0.1,
+ sustain: sus1,
+ release: 0.1,
+ },
+ modulation: {
+ type: wav,
+ },
+ }).toMaster();
+ }
+ activeSynths[k.note].triggerAttack(k.note);
+ document.querySelector(".innernote").innerHTML =
+ k.note + " - " + activeSynths[k.note].triggerAttack(k.note);
+ } else {
+ activeSynths[k.note].triggerRelease();
+ }
+});
+
+var sustain1 = new Nexus.Dial('#sus1',{
+ 'size': [75,75],
+ 'interaction': 'radial', // "radial", "vertical", or "horizontal"
+ 'mode': 'relative', // "absolute" or "relative"
+ 'min': 0,
+ 'max': 1,
+ 'step': 0,
+ 'value': 0
+})
+
+sustain1.on('change',function(v) {
+ sus1 = v;
+})
+var attack1 = new Nexus.Dial('#attack1',{
+ 'size': [75,75],
+ 'interaction': 'radial', // "radial", "vertical", or "horizontal"
+ 'mode': 'relative', // "absolute" or "relative"
+ 'min': 0,
+ 'max': 1,
+ 'step': 0,
+ 'value': 0
+})
+
+attack1.on('change',function(va) {
+ atk1 = va;
+})
+
+var select = new Nexus.Select('#waves',{
+ 'size': [100,30],
+ 'options': ['sine','sawtooth', 'square']
+})
+
+select.on('change',function(waves) {
+ wav = waves;
+})
+
+document.addEventListener("keydown", (event) => {
+ const keyIndex = keyMapper[event.key];
+ keyIndex !== undefined && !piano.keys[keyIndex]._state.state
+ ? piano.toggleIndex(keyIndex, true)
+ : null;
+});
+
+document.addEventListener("keyup", (event) => {
+ const keyIndex = keyMapper[event.key];
+ keyIndex !== undefined && piano.keys[keyIndex]._state.state
+ ? piano.toggleIndex(keyIndex, false)
+ : null;
+});
\ No newline at end of file
diff --git a/scripts/webmidi.min.js b/scripts/webmidi.min.js
new file mode 100644
index 0000000..f5654ca
--- /dev/null
+++ b/scripts/webmidi.min.js
@@ -0,0 +1,31 @@
+/*
+
+WebMidi v2.5.1
+
+WebMidi.js helps you 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/djipco/webmidi
+
+
+The MIT License (MIT)
+
+Copyright (c) 2015-2019, 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(scope){"use strict";function WebMidi(){if(WebMidi.prototype._singleton)throw new Error("WebMidi is a singleton, it cannot be instantiated directly.");(WebMidi.prototype._singleton=this)._inputs=[],this._outputs=[],this._userHandlers={},this._stateChangeQueue=[],this._processingStateChange=!1,this._midiInterfaceEvents=["connected","disconnected"],this._nrpnBuffer=[[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]],this._nrpnEventsEnabled=!0,this._nrpnTypes=["entry","increment","decrement"],this._notes=["C","C#","D","D#","E","F","F#","G","G#","A","A#","B"],this._semitones={C:0,D:2,E:4,F:5,G:7,A:9,B:11},Object.defineProperties(this,{MIDI_SYSTEM_MESSAGES:{value:{sysex:240,timecode:241,songposition:242,songselect:243,tuningrequest:246,sysexend:247,clock:248,start:250,continue:251,stop:252,activesensing:254,reset:255,midimessage:0,unknownsystemmessage:-1},writable:!1,enumerable:!0,configurable:!1},MIDI_CHANNEL_MESSAGES:{value:{noteoff:8,noteon:9,keyaftertouch:10,controlchange:11,channelmode:11,nrpn:11,programchange:12,channelaftertouch:13,pitchbend:14},writable:!1,enumerable:!0,configurable:!1},MIDI_REGISTERED_PARAMETER:{value:{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]},writable:!1,enumerable:!0,configurable:!1},MIDI_CONTROL_CHANGE_MESSAGES:{value:{bankselectcoarse:0,modulationwheelcoarse:1,breathcontrollercoarse:2,footcontrollercoarse:4,portamentotimecoarse:5,dataentrycoarse:6,volumecoarse:7,balancecoarse:8,pancoarse:10,expressioncoarse:11,effectcontrol1coarse:12,effectcontrol2coarse:13,generalpurposeslider1:16,generalpurposeslider2:17,generalpurposeslider3:18,generalpurposeslider4:19,bankselectfine:32,modulationwheelfine:33,breathcontrollerfine:34,footcontrollerfine:36,portamentotimefine:37,dataentryfine:38,volumefine:39,balancefine:40,panfine:42,expressionfine:43,effectcontrol1fine:44,effectcontrol2fine:45,holdpedal:64,portamento:65,sustenutopedal:66,softpedal:67,legatopedal:68,hold2pedal:69,soundvariation:70,resonance:71,soundreleasetime:72,soundattacktime:73,brightness:74,soundcontrol6:75,soundcontrol7:76,soundcontrol8:77,soundcontrol9:78,soundcontrol10:79,generalpurposebutton1:80,generalpurposebutton2:81,generalpurposebutton3:82,generalpurposebutton4:83,reverblevel:91,tremololevel:92,choruslevel:93,celestelevel:94,phaserlevel:95,databuttonincrement:96,databuttondecrement:97,nonregisteredparametercoarse:98,nonregisteredparameterfine:99,registeredparametercoarse:100,registeredparameterfine:101},writable:!1,enumerable:!0,configurable:!1},MIDI_NRPN_MESSAGES:{value:{entrymsb:6,entrylsb:38,increment:96,decrement:97,paramlsb:98,parammsb:99,nullactiveparameter:127},writable:!1,enumerable:!0,configurable:!1},MIDI_CHANNEL_MODE_MESSAGES:{value:{allsoundoff:120,resetallcontrollers:121,localcontrol:122,allnotesoff:123,omnimodeoff:124,omnimodeon:125,monomodeon:126,polymodeon:127},writable:!1,enumerable:!0,configurable:!1},octaveOffset:{value:0,writable:!0,enumerable:!0,configurable:!1}}),Object.defineProperties(this,{supported:{enumerable:!0,get:function(){return"requestMIDIAccess"in navigator}},enabled:{enumerable:!0,get:function(){return void 0!==this.interface}.bind(this)},inputs:{enumerable:!0,get:function(){return this._inputs}.bind(this)},outputs:{enumerable:!0,get:function(){return this._outputs}.bind(this)},sysexEnabled:{enumerable:!0,get:function(){return!(!this.interface||!this.interface.sysexEnabled)}.bind(this)},nrpnEventsEnabled:{enumerable:!0,get:function(){return!!this._nrpnEventsEnabled}.bind(this),set:function(enabled){return this._nrpnEventsEnabled=enabled,this._nrpnEventsEnabled}},nrpnTypes:{enumerable:!0,get:function(){return this._nrpnTypes}.bind(this)},time:{enumerable:!0,get:function(){return performance.now()}}})}var wm=new WebMidi;function Input(midiInput){var that=this;this._userHandlers={channel:{},system:{}},this._midiInput=midiInput,Object.defineProperties(this,{connection:{enumerable:!0,get:function(){return that._midiInput.connection}},id:{enumerable:!0,get:function(){return that._midiInput.id}},manufacturer:{enumerable:!0,get:function(){return that._midiInput.manufacturer}},name:{enumerable:!0,get:function(){return that._midiInput.name}},state:{enumerable:!0,get:function(){return that._midiInput.state}},type:{enumerable:!0,get:function(){return that._midiInput.type}}}),this._initializeUserHandlers(),this._midiInput.onmidimessage=this._onMidiMessage.bind(this)}function Output(midiOutput){var that=this;this._midiOutput=midiOutput,Object.defineProperties(this,{connection:{enumerable:!0,get:function(){return that._midiOutput.connection}},id:{enumerable:!0,get:function(){return that._midiOutput.id}},manufacturer:{enumerable:!0,get:function(){return that._midiOutput.manufacturer}},name:{enumerable:!0,get:function(){return that._midiOutput.name}},state:{enumerable:!0,get:function(){return that._midiOutput.state}},type:{enumerable:!0,get:function(){return that._midiOutput.type}}})}WebMidi.prototype.enable=function(callback,sysex){this.enabled||(this.supported?navigator.requestMIDIAccess({sysex:sysex}).then(function(midiAccess){var promiseTimeout,events=[],promises=[];this.interface=midiAccess,this._resetInterfaceUserHandlers(),this.interface.onstatechange=function(e){events.push(e)};for(var inputs=midiAccess.inputs.values(),input=inputs.next();input&&!input.done;input=inputs.next())promises.push(input.value.open());for(var outputs=midiAccess.outputs.values(),output=outputs.next();output&&!output.done;output=outputs.next())promises.push(output.value.open());function onPortsOpen(){clearTimeout(promiseTimeout),this._updateInputsAndOutputs(),this.interface.onstatechange=this._onInterfaceStateChange.bind(this),"function"==typeof callback&&callback.call(this),events.forEach(function(event){this._onInterfaceStateChange(event)}.bind(this))}promiseTimeout=setTimeout(onPortsOpen.bind(this),200),Promise&&Promise.all(promises).catch(function(err){}).then(onPortsOpen.bind(this))}.bind(this),function(err){"function"==typeof callback&&callback.call(this,err)}.bind(this)):"function"==typeof callback&&callback(new Error("The Web MIDI API is not supported by your browser.")))},WebMidi.prototype.disable=function(){if(!this.supported)throw new Error("The Web MIDI API is not supported by your browser.");this.interface&&(this.interface.onstatechange=void 0),this.interface=void 0,this._inputs=[],this._outputs=[],this._nrpnEventsEnabled=!0,this._resetInterfaceUserHandlers()},WebMidi.prototype.addListener=function(type,listener){if(!this.enabled)throw new Error("WebMidi must be enabled before adding event listeners.");if("function"!=typeof listener)throw new TypeError("The 'listener' parameter must be a function.");if(!(0<=this._midiInterfaceEvents.indexOf(type)))throw new TypeError("The specified event type is not supported.");return this._userHandlers[type].push(listener),this},WebMidi.prototype.hasListener=function(type,listener){if(!this.enabled)throw new Error("WebMidi must be enabled before checking event listeners.");if("function"!=typeof listener)throw new TypeError("The 'listener' parameter must be a function.");if(!(0<=this._midiInterfaceEvents.indexOf(type)))throw new TypeError("The specified event type is not supported.");for(var o=0;o>4,channelBufferIndex=15&e.data[0],channel=1+channelBufferIndex;if(1=wm.MIDI_NRPN_MESSAGES.increment&&data1<=wm.MIDI_NRPN_MESSAGES.parammsb||data1===wm.MIDI_NRPN_MESSAGES.entrymsb||data1===wm.MIDI_NRPN_MESSAGES.entrylsb)){var ccEvent={target:this,type:"controlchange",data:e.data,timestamp:e.timeStamp,channel:channel,controller:{number:data1,name:this.getCcNameByNumber(data1)},value:data2};if(ccEvent.controller.number===wm.MIDI_NRPN_MESSAGES.parammsb&&ccEvent.value!=wm.MIDI_NRPN_MESSAGES.nullactiveparameter)wm._nrpnBuffer[channelBufferIndex]=[],wm._nrpnBuffer[channelBufferIndex][0]=ccEvent;else if(1===wm._nrpnBuffer[channelBufferIndex].length&&ccEvent.controller.number===wm.MIDI_NRPN_MESSAGES.paramlsb)wm._nrpnBuffer[channelBufferIndex].push(ccEvent);else if(2!==wm._nrpnBuffer[channelBufferIndex].length||ccEvent.controller.number!==wm.MIDI_NRPN_MESSAGES.increment&&ccEvent.controller.number!==wm.MIDI_NRPN_MESSAGES.decrement&&ccEvent.controller.number!==wm.MIDI_NRPN_MESSAGES.entrymsb)if(3===wm._nrpnBuffer[channelBufferIndex].length&&wm._nrpnBuffer[channelBufferIndex][2].number===wm.MIDI_NRPN_MESSAGES.entrymsb&&ccEvent.controller.number===wm.MIDI_NRPN_MESSAGES.entrylsb)wm._nrpnBuffer[channelBufferIndex].push(ccEvent);else if(3<=wm._nrpnBuffer[channelBufferIndex].length&&wm._nrpnBuffer[channelBufferIndex].length<=4&&ccEvent.controller.number===wm.MIDI_NRPN_MESSAGES.parammsb&&ccEvent.value===wm.MIDI_NRPN_MESSAGES.nullactiveparameter)wm._nrpnBuffer[channelBufferIndex].push(ccEvent);else if(4<=wm._nrpnBuffer[channelBufferIndex].length&&wm._nrpnBuffer[channelBufferIndex].length<=5&&ccEvent.controller.number===wm.MIDI_NRPN_MESSAGES.paramlsb&&ccEvent.value===wm.MIDI_NRPN_MESSAGES.nullactiveparameter){wm._nrpnBuffer[channelBufferIndex].push(ccEvent);var rawData=[];wm._nrpnBuffer[channelBufferIndex].forEach(function(ev){rawData.push(ev.data)});var nrpnNumber=wm._nrpnBuffer[channelBufferIndex][0].value<<7|wm._nrpnBuffer[channelBufferIndex][1].value,nrpnValue=wm._nrpnBuffer[channelBufferIndex][2].value;6===wm._nrpnBuffer[channelBufferIndex].length&&(nrpnValue=wm._nrpnBuffer[channelBufferIndex][2].value<<7|wm._nrpnBuffer[channelBufferIndex][3].value);var nrpnControllerType="";switch(wm._nrpnBuffer[channelBufferIndex][2].controller.number){case wm.MIDI_NRPN_MESSAGES.entrymsb:nrpnControllerType=wm._nrpnTypes[0];break;case wm.MIDI_NRPN_MESSAGES.increment:nrpnControllerType=wm._nrpnTypes[1];break;case wm.MIDI_NRPN_MESSAGES.decrement:nrpnControllerType=wm._nrpnTypes[2];break;default:throw new Error("The NPRN type was unidentifiable.")}var nrpnEvent={timestamp:ccEvent.timestamp,channel:ccEvent.channel,type:"nrpn",data:rawData,controller:{number:nrpnNumber,type:nrpnControllerType,name:"Non-Registered Parameter "+nrpnNumber},value:nrpnValue};wm._nrpnBuffer[channelBufferIndex]=[],this._userHandlers.channel[nrpnEvent.type]&&this._userHandlers.channel[nrpnEvent.type][nrpnEvent.channel]&&this._userHandlers.channel[nrpnEvent.type][nrpnEvent.channel].forEach(function(callback){callback(nrpnEvent)})}else wm._nrpnBuffer[channelBufferIndex]=[];else wm._nrpnBuffer[channelBufferIndex].push(ccEvent)}},Input.prototype._parseChannelEvent=function(e){var data1,data2,command=e.data[0]>>4,channel=1+(15&e.data[0]);1>7&127,lsb=127&value;return this.send(wm.MIDI_SYSTEM_MESSAGES.songposition,[msb,lsb],this._parseTimeParameter(options.time)),this},Output.prototype.sendSongSelect=function(value,options){if(options=options||{},!(0<=(value=Math.floor(value))&&value<=127))throw new RangeError("The song number must be between 0 and 127.");return this.send(wm.MIDI_SYSTEM_MESSAGES.songselect,[value],this._parseTimeParameter(options.time)),this},Output.prototype.sendTuningRequest=function(options){return options=options||{},this.send(wm.MIDI_SYSTEM_MESSAGES.tuningrequest,void 0,this._parseTimeParameter(options.time)),this},Output.prototype.sendClock=function(options){return options=options||{},this.send(wm.MIDI_SYSTEM_MESSAGES.clock,void 0,this._parseTimeParameter(options.time)),this},Output.prototype.sendStart=function(options){return options=options||{},this.send(wm.MIDI_SYSTEM_MESSAGES.start,void 0,this._parseTimeParameter(options.time)),this},Output.prototype.sendContinue=function(options){return options=options||{},this.send(wm.MIDI_SYSTEM_MESSAGES.continue,void 0,this._parseTimeParameter(options.time)),this},Output.prototype.sendStop=function(options){return options=options||{},this.send(wm.MIDI_SYSTEM_MESSAGES.stop,void 0,this._parseTimeParameter(options.time)),this},Output.prototype.sendActiveSensing=function(options){return options=options||{},this.send(wm.MIDI_SYSTEM_MESSAGES.activesensing,[],this._parseTimeParameter(options.time)),this},Output.prototype.sendReset=function(options){return options=options||{},this.send(wm.MIDI_SYSTEM_MESSAGES.reset,void 0,this._parseTimeParameter(options.time)),this},Output.prototype.stopNote=function(note,channel,options){if("all"===note)return this.sendChannelMode("allnotesoff",0,channel,options);var nVelocity=64;return(options=options||{}).rawVelocity?!isNaN(options.velocity)&&0<=options.velocity&&options.velocity<=127&&(nVelocity=options.velocity):!isNaN(options.velocity)&&0<=options.velocity&&options.velocity<=1&&(nVelocity=127*options.velocity),this._convertNoteToArray(note).forEach(function(item){wm.toMIDIChannels(channel).forEach(function(ch){this.send((wm.MIDI_CHANNEL_MESSAGES.noteoff<<4)+(ch-1),[item,Math.round(nVelocity)],this._parseTimeParameter(options.time))}.bind(this))}.bind(this)),this},Output.prototype.playNote=function(note,channel,options){var time,nVelocity=64;if((options=options||{}).rawVelocity?!isNaN(options.velocity)&&0<=options.velocity&&options.velocity<=127&&(nVelocity=options.velocity):!isNaN(options.velocity)&&0<=options.velocity&&options.velocity<=1&&(nVelocity=127*options.velocity),time=this._parseTimeParameter(options.time),this._convertNoteToArray(note).forEach(function(item){wm.toMIDIChannels(channel).forEach(function(ch){this.send((wm.MIDI_CHANNEL_MESSAGES.noteon<<4)+(ch-1),[item,Math.round(nVelocity)],time)}.bind(this))}.bind(this)),!isNaN(options.duration)){options.duration<=0&&(options.duration=0);var nRelease=64;options.rawVelocity?!isNaN(options.release)&&0<=options.release&&options.release<=127&&(nRelease=options.release):!isNaN(options.release)&&0<=options.release&&options.release<=1&&(nRelease=127*options.release),this._convertNoteToArray(note).forEach(function(item){wm.toMIDIChannels(channel).forEach(function(ch){this.send((wm.MIDI_CHANNEL_MESSAGES.noteoff<<4)+(ch-1),[item,Math.round(nRelease)],(time||wm.time)+options.duration)}.bind(this))}.bind(this))}return this},Output.prototype.sendKeyAftertouch=function(note,channel,pressure,options){var that=this;if(options=options||{},channel<1||16>7&127,lsb=127&fine;return wm.toMIDIChannels(channel).forEach(function(){that.setRegisteredParameter("channelcoarsetuning",coarse,channel,{time:options.time}),that.setRegisteredParameter("channelfinetuning",[msb,lsb],channel,{time:options.time})}),this},Output.prototype.setTuningProgram=function(value,channel,options){var that=this;if(options=options||{},!(0<=(value=Math.floor(value))&&value<=127))throw new RangeError("The program value must be between 0 and 127");return wm.toMIDIChannels(channel).forEach(function(){that.setRegisteredParameter("tuningprogram",value,channel,{time:options.time})}),this},Output.prototype.setTuningBank=function(value,channel,options){var that=this;if(options=options||{},!(0<=(value=Math.floor(value)||0)&&value<=127))throw new RangeError("The bank value must be between 0 and 127");return wm.toMIDIChannels(channel).forEach(function(){that.setRegisteredParameter("tuningbank",value,channel,{time:options.time})}),this},Output.prototype.sendChannelMode=function(command,value,channel,options){if(options=options||{},"string"==typeof command){if(!(command=wm.MIDI_CHANNEL_MODE_MESSAGES[command]))throw new TypeError("Invalid channel mode message name.")}else if(!(120<=(command=Math.floor(command))&&command<=127))throw new RangeError("Channel mode numerical identifiers must be between 120 and 127.");if((value=Math.floor(value)||0)<0||127>7&127,lsb=127&nLevel;return wm.toMIDIChannels(channel).forEach(function(ch){that.send((wm.MIDI_CHANNEL_MESSAGES.pitchbend<<4)+(ch-1),[lsb,msb],that._parseTimeParameter(options.time))}),this},Output.prototype._parseTimeParameter=function(time){var value,parsed=parseFloat(time);return"string"==typeof time&&"+"===time.substring(0,1)?parsed&&0wm.time&&(value=parsed),value},Output.prototype._convertNoteToArray=function(note){var notes=[];return Array.isArray(note)||(note=[note]),note.forEach(function(item){notes.push(wm.guessNoteNumber(item))}),notes},"function"==typeof define&&"object"==typeof define.amd?define([],function(){return wm}):"undefined"!=typeof module&&module.exports?module.exports=wm:scope.WebMidi||(scope.WebMidi=wm)}(this);
\ No newline at end of file