From fd761e1cce237c99897cbadcffffca7ce4b0970b Mon Sep 17 00:00:00 2001 From: Michael Deal Date: Fri, 25 Jan 2013 00:28:08 -0800 Subject: [PATCH] update grunt so unnecessary files are not included into MIDI.js by default, shrink build from over 100kb to 24kb --- build/MIDI.js | 3869 +++++---------------------------------------- build/MIDI.min.js | 2 +- demo-Basic.html | 3 +- grunt.js | 17 +- 4 files changed, 405 insertions(+), 3486 deletions(-) diff --git a/build/MIDI.js b/build/MIDI.js index 3f61a70..529de32 100644 --- a/build/MIDI.js +++ b/build/MIDI.js @@ -1,450 +1,3 @@ -/* - ---------------------------------------------------- - Color Space : 1.2 : 2012.11.06 - ---------------------------------------------------- - https://github.com/mudcube/Color.Space.js - ---------------------------------------------------- - RGBA <-> HSLA <-> W3 - RGBA <-> HSVA - RGBA <-> CMY <-> CMYK - RGBA <-> HEX24 <-> W3 - RGBA <-> HEX32 - RGBA <-> W3 - ---------------------------------------------------- - Examples - ---------------------------------------------------- - Color.Space(0x99ff0000, "HEX32>RGBA>HSLA>W3"); // outputs "hsla(60,100%,17%,0.6)" - Color.Space(0xFF0000, "HEX24>RGB>HSL"); // convert hex24 to HSL object. - ---------------------------------------------------- - W3 values - ---------------------------------------------------- - rgb(255,0,0) - rgba(255,0,0,1) - rgb(100%,0%,0%) - rgba(100%,0%,0%,1) - hsl(120, 100%, 50%) - hsla(120, 100%, 50%, 1) - #000000 -*/ - -if (typeof(Color) === "undefined") var Color = {}; -if (typeof(Color.Space) === "undefined") Color.Space = {}; - -(function () { "use strict"; - -var useEval = false; // caches functions for quicker access. - -var functions = { - // holds generated cached conversion functions. -}; - -var shortcuts = { - "HEX24>HSL": "HEX24>RGB>HSL", - "HEX32>HSLA": "HEX32>RGBA>HSLA", - "HEX24>CMYK": "HEX24>RGB>CMY>CMYK", - "RGB>CMYK": "RGB>CMY>CMYK" -}; - -var root = Color.Space = function(color, route) { - if (shortcuts[route]) { // shortcut available - route = shortcuts[route]; - } - var r = route.split(">"); - // check whether color is an [], if so, convert to {} - if (typeof(color) === "object" && color[0] >= 0) { // array - var type = r[0]; - var tmp = {}; - for(var i = 0; i < type.length; i ++) { - var str = type.substr(i, 1); - tmp[str] = color[i]; - } - color = tmp; - } - if (functions[route]) { // cached function available - return functions[route](color); - } - var f = "color"; - for (var pos = 1, key = r[0]; pos < r.length; pos ++) { - if (pos > 1) { // recycle previous - key = key.substr(key.indexOf("_") + 1); - } - key += (pos === 0 ? "" : "_") + r[pos]; - color = root[key](color); - if (useEval) { - f = "Color.Space."+key+"("+f+")"; - } - } - if (useEval) { - functions[route] = eval("(function(color) { return "+f+" })"); - } - return color; -}; - -// W3C - RGB + RGBA - -root.RGB_W3 = function(o) { - return "rgb(" + (o.R >> 0) + "," + (o.G >> 0) + "," + (o.B >> 0) + ")"; -}; - -root.RGBA_W3 = function(o) { - var alpha = typeof(o.A) === "number" ? o.A / 255 : 1; - return "rgba(" + (o.R >> 0) + "," + (o.G >> 0) + "," + (o.B >> 0) + "," + alpha + ")"; -}; - -root.W3_RGB = function(o) { - var o = o.substr(4, o.length - 5).split(","); - return { - R: parseInt(o[0]), - G: parseInt(o[1]), - B: parseInt(o[2]) - } -}; - -root.W3_RGBA = function(o) { - var o = o.substr(5, o.length - 6).split(","); - return { - R: parseInt(o[0]), - G: parseInt(o[1]), - B: parseInt(o[2]), - A: parseFloat(o[3]) * 255 - } -}; - -// W3C - HSL + HSLA - -root.HSL_W3 = function(o) { - return "hsl(" + ((o.H + 0.5) >> 0) + "," + ((o.S + 0.5) >> 0) + "%," + ((o.L + 0.5) >> 0) + "%)"; -}; - -root.HSLA_W3 = function(o) { - var alpha = typeof(o.A) === "number" ? o.A / 255 : 1; - return "hsla(" + ((o.H + 0.5) >> 0) + "," + ((o.S + 0.5) >> 0) + "%," + ((o.L + 0.5) >> 0) + "%," + alpha + ")"; -}; - -root.W3_HSL = function(o) { - var o = o.substr(4, o.length - 5).split(","); - return { - H: parseInt(o[0]), - S: parseInt(o[1]), - L: parseInt(o[2]) - } -}; - -root.W3_HSLA = function(o) { - var o = o.substr(5, o.length - 6).split(","); - return { - H: parseInt(o[0]), - S: parseInt(o[1]), - L: parseInt(o[2]), - A: parseFloat(o[3]) * 255 - } -}; - -// W3 HEX = "FFFFFF" | "FFFFFFFF" - -root.W3_HEX = -root.W3_HEX24 = function (o) { - if (o.substr(0, 1) === "#") o = o.substr(1); - if (o.length === 3) o = o[0] + o[0] + o[1] + o[1] + o[2] + o[2]; - return parseInt("0x" + o); -}; - -root.W3_HEX32 = function (o) { - if (o.substr(0, 1) === "#") o = o.substr(1); - if (o.length === 6) { - return parseInt("0xFF" + o); - } else { - return parseInt("0x" + o); - } -}; - -// HEX = 0x000000 -> 0xFFFFFF - -root.HEX_W3 = -root.HEX24_W3 = function (o, maxLength) { - if (!maxLength) maxLength = 6; - if (!o) o = 0; - var z = o.toString(16); - // when string is lesser than maxLength - var n = z.length; - while (n < maxLength) { - z = "0" + z; - n++; - } - // when string is greater than maxLength - var n = z.length; - while (n > maxLength) { - z = z.substr(1); - n--; - } - return "#" + z; -}; - -root.HEX32_W3 = function(o) { - return root.HEX_W3(o, 8); -}; - -root.HEX_RGB = -root.HEX24_RGB = function (o) { - return { - R: (o >> 16), - G: (o >> 8) & 0xFF, - B: o & 0xFF - }; -}; - -// HEX32 = 0x00000000 -> 0xFFFFFFFF - -root.HEX32_RGBA = function (o) { - return { - R: o >>> 16 & 0xFF, - G: o >>> 8 & 0xFF, - B: o & 0xFF, - A: o >>> 24 - }; -}; - -// RGBA = R: Red / G: Green / B: Blue / A: Alpha - -root.RGBA_HEX32 = function (o) { - return (o.A << 24 | o.R << 16 | o.G << 8 | o.B) >>> 0; -}; - -// RGB = R: Red / G: Green / B: Blue - -root.RGB_HEX24 = -root.RGB_HEX = function (o) { - if (o.R < 0) o.R = 0; - if (o.G < 0) o.G = 0; - if (o.B < 0) o.B = 0; - if (o.R > 255) o.R = 255; - if (o.G > 255) o.G = 255; - if (o.B > 255) o.B = 255; - return o.R << 16 | o.G << 8 | o.B; -}; - -root.RGB_CMY = function (o) { - return { - C: 1 - (o.R / 255), - M: 1 - (o.G / 255), - Y: 1 - (o.B / 255) - }; -}; - -root.RGBA_HSLA = -root.RGB_HSL = function (o) { // RGB from 0 to 1 - var _R = o.R / 255, - _G = o.G / 255, - _B = o.B / 255, - min = Math.min(_R, _G, _B), - max = Math.max(_R, _G, _B), - D = max - min, - H, - S, - L = (max + min) / 2; - if (D === 0) { // No chroma - H = 0; - S = 0; - } else { // Chromatic data - if (L < 0.5) S = D / (max + min); - else S = D / (2 - max - min); - var DR = (((max - _R) / 6) + (D / 2)) / D; - var DG = (((max - _G) / 6) + (D / 2)) / D; - var DB = (((max - _B) / 6) + (D / 2)) / D; - if (_R === max) H = DB - DG; - else if (_G === max) H = (1 / 3) + DR - DB; - else if (_B === max) H = (2 / 3) + DG - DR; - if (H < 0) H += 1; - if (H > 1) H -= 1; - } - return { - H: H * 360, - S: S * 100, - L: L * 100, - A: o.A - }; -}; - -root.RGBA_HSVA = -root.RGB_HSV = function (o) { //- RGB from 0 to 255 - var _R = o.R / 255, - _G = o.G / 255, - _B = o.B / 255, - min = Math.min(_R, _G, _B), - max = Math.max(_R, _G, _B), - D = max - min, - H, - S, - V = max; - if (D === 0) { // No chroma - H = 0; - S = 0; - } else { // Chromatic data - S = D / max; - var DR = (((max - _R) / 6) + (D / 2)) / D; - var DG = (((max - _G) / 6) + (D / 2)) / D; - var DB = (((max - _B) / 6) + (D / 2)) / D; - if (_R === max) H = DB - DG; - else if (_G === max) H = (1 / 3) + DR - DB; - else if (_B === max) H = (2 / 3) + DG - DR; - if (H < 0) H += 1; - if (H > 1) H -= 1; - } - return { - H: H * 360, - S: S * 100, - V: V * 100, - A: o.A - }; -}; - -// CMY = C: Cyan / M: Magenta / Y: Yellow - -root.CMY_RGB = function (o) { - return { - R: Math.max(0, (1 - o.C) * 255), - G: Math.max(0, (1 - o.M) * 255), - B: Math.max(0, (1 - o.Y) * 255) - }; -}; - -root.CMY_CMYK = function (o) { - var C = o.C; - var M = o.M; - var Y = o.Y; - var K = Math.min(Y, Math.min(M, Math.min(C, 1))); - C = Math.round((C - K) / (1 - K) * 100); - M = Math.round((M - K) / (1 - K) * 100); - Y = Math.round((Y - K) / (1 - K) * 100); - K = Math.round(K * 100); - return { - C: C, - M: M, - Y: Y, - K: K - }; -}; - -// CMYK = C: Cyan / M: Magenta / Y: Yellow / K: Key (black) - -root.CMYK_CMY = function (o) { - return { - C: (o.C * (1 - o.K) + o.K), - M: (o.M * (1 - o.K) + o.K), - Y: (o.Y * (1 - o.K) + o.K) - }; -}; - -// HSL (1978) = H: Hue / S: Saturation / L: Lightess -// en.wikipedia.org/wiki/HSL_and_HSV - -root.HSLA_RGBA = -root.HSL_RGB = function (o) { - var H = o.H / 360; - var S = o.S / 100; - var L = o.L / 100; - var R, G, B; - var temp1, temp2, temp3; - if (S === 0) { - R = G = B = L; - } else { - if (L < 0.5) temp2 = L * (1 + S); - else temp2 = (L + S) - (S * L); - temp1 = 2 * L - temp2; - // calculate red - temp3 = H + (1 / 3); - if (temp3 < 0) temp3 += 1; - if (temp3 > 1) temp3 -= 1; - if ((6 * temp3) < 1) R = temp1 + (temp2 - temp1) * 6 * temp3; - else if ((2 * temp3) < 1) R = temp2; - else if ((3 * temp3) < 2) R = temp1 + (temp2 - temp1) * ((2 / 3) - temp3) * 6; - else R = temp1; - // calculate green - temp3 = H; - if (temp3 < 0) temp3 += 1; - if (temp3 > 1) temp3 -= 1; - if ((6 * temp3) < 1) G = temp1 + (temp2 - temp1) * 6 * temp3; - else if ((2 * temp3) < 1) G = temp2; - else if ((3 * temp3) < 2) G = temp1 + (temp2 - temp1) * ((2 / 3) - temp3) * 6; - else G = temp1; - // calculate blue - temp3 = H - (1 / 3); - if (temp3 < 0) temp3 += 1; - if (temp3 > 1) temp3 -= 1; - if ((6 * temp3) < 1) B = temp1 + (temp2 - temp1) * 6 * temp3; - else if ((2 * temp3) < 1) B = temp2; - else if ((3 * temp3) < 2) B = temp1 + (temp2 - temp1) * ((2 / 3) - temp3) * 6; - else B = temp1; - } - return { - R: R * 255, - G: G * 255, - B: B * 255, - A: o.A - }; -}; - -// HSV (1978) = H: Hue / S: Saturation / V: Value -// en.wikipedia.org/wiki/HSL_and_HSV - -root.HSVA_RGBA = -root.HSV_RGB = function (o) { - var H = o.H / 360; - var S = o.S / 100; - var V = o.V / 100; - var R, G, B, D, A, C; - if (S === 0) { - R = G = B = Math.round(V * 255); - } else { - if (H >= 1) H = 0; - H = 6 * H; - D = H - Math.floor(H); - A = Math.round(255 * V * (1 - S)); - B = Math.round(255 * V * (1 - (S * D))); - C = Math.round(255 * V * (1 - (S * (1 - D)))); - V = Math.round(255 * V); - switch (Math.floor(H)) { - case 0: - R = V; - G = C; - B = A; - break; - case 1: - R = B; - G = V; - B = A; - break; - case 2: - R = A; - G = V; - B = C; - break; - case 3: - R = A; - G = B; - B = V; - break; - case 4: - R = C; - G = A; - B = V; - break; - case 5: - R = V; - G = A; - B = B; - break; - } - } - return { - R: R, - G: G, - B: B, - A: o.A - }; -}; - -})(); /* ------------------------------------- MIDI.audioDetect : 0.3 @@ -692,288 +245,6 @@ var createQueue = function(conf) { return self; }; -})(); -/* - ------------------------------------- - MIDI.Player : 0.3 - ------------------------------------- - https://github.com/mudcube/MIDI.js - ------------------------------------- - #jasmid - ------------------------------------- -*/ - -if (typeof (MIDI) === "undefined") var MIDI = {}; -if (typeof (MIDI.Player) === "undefined") MIDI.Player = {}; - -(function() { "use strict"; - -var root = MIDI.Player; -root.callback = undefined; // your custom callback goes here! -root.currentTime = 0; -root.endTime = 0; -root.restart = 0; -root.playing = false; -root.timeWarp = 1; - -// -root.start = -root.resume = function () { - if (root.currentTime < -1) root.currentTime = -1; - startAudio(root.currentTime); -}; - -root.pause = function () { - var tmp = root.restart; - stopAudio(); - root.restart = tmp; -}; - -root.stop = function () { - stopAudio(); - root.restart = 0; - root.currentTime = 0; -}; - -root.addListener = function(callback) { - onMidiEvent = callback; -}; - -root.removeListener = function() { - onMidiEvent = undefined; -}; - -root.clearAnimation = function() { - if (root.interval) { - window.clearInterval(root.interval); - } -}; - -root.setAnimation = function(config) { - var callback = (typeof(config) === "function") ? config : config.callback; - var interval = config.interval || 30; - var currentTime = 0; - var tOurTime = 0; - var tTheirTime = 0; - // - root.clearAnimation(); - root.interval = window.setInterval(function () { - if (root.endTime === 0) return; - if (root.playing) { - currentTime = (tTheirTime === root.currentTime) ? tOurTime - (new Date).getTime() : 0; - if (root.currentTime === 0) { - currentTime = 0; - } else { - currentTime = root.currentTime - currentTime; - } - if (tTheirTime !== root.currentTime) { - tOurTime = (new Date).getTime(); - tTheirTime = root.currentTime; - } - } else { // paused - currentTime = root.currentTime; - } - var endTime = root.endTime; - var percent = currentTime / endTime; - var total = currentTime / 1000; - var minutes = total / 60; - var seconds = total - (minutes * 60); - var t1 = minutes * 60 + seconds; - var t2 = (endTime / 1000); - if (t2 - t1 < -1) return; - callback({ - now: t1, - end: t2, - events: noteRegistrar - }); - }, interval); -}; - -// helpers - -root.loadMidiFile = function() { // reads midi into javascript array of events - root.replayer = new Replayer(MidiFile(root.currentData), root.timeWarp); - root.data = root.replayer.getData(); - root.endTime = getLength(); -}; - -root.loadFile = function (file, callback) { - root.stop(); - if (file.indexOf("base64,") !== -1) { - var data = window.atob(file.split(",")[1]); - root.currentData = data; - root.loadMidiFile(); - if (callback) callback(data); - return; - } - /// - var title = file.split(" - ")[1] || file; - document.getElementById("playback-title").innerHTML = title.replace(".mid",""); - /// - var fetch = new XMLHttpRequest(); - fetch.open('GET', file); - fetch.overrideMimeType("text/plain; charset=x-user-defined"); - fetch.onreadystatechange = function () { - if (this.readyState === 4 && this.status === 200) { - var t = this.responseText || ""; - var ff = []; - var mx = t.length; - var scc = String.fromCharCode; - for (var z = 0; z < mx; z++) { - ff[z] = scc(t.charCodeAt(z) & 255); - } - var data = ff.join(""); - root.currentData = data; - root.loadMidiFile(); - if (callback) callback(data); - } - }; - fetch.send(); -}; - -// Playing the audio - -var eventQueue = []; // hold events to be triggered -var queuedTime; // -var startTime = 0; // to measure time elapse -var noteRegistrar = {}; // get event for requested note -var onMidiEvent = undefined; // listener callback -var scheduleTracking = function (channel, note, currentTime, offset, message, velocity) { - var interval = window.setTimeout(function () { - var data = { - channel: channel, - note: note, - now: currentTime, - end: root.endTime, - message: message, - velocity: velocity - }; - // - if (message === 128) { - delete noteRegistrar[note]; - } else { - noteRegistrar[note] = data; - } - if (onMidiEvent) { - onMidiEvent(data); - } - root.currentTime = currentTime; - if (root.currentTime === queuedTime && queuedTime < root.endTime) { // grab next sequence - startAudio(queuedTime, true); - } - }, currentTime - offset); - return interval; -}; - -var getContext = function() { - if (MIDI.lang === 'WebAudioAPI') { - return MIDI.Player.ctx; - } else if (!root.ctx) { - root.ctx = { currentTime: 0 }; - } - return root.ctx; -}; - -var getLength = function() { - var data = root.data; - var length = data.length; - var totalTime = 0.5; - for (var n = 0; n < length; n++) { - totalTime += data[n][1]; - } - return totalTime; -}; - -var startAudio = function (currentTime, fromCache) { - if (!root.replayer) return; - if (!fromCache) { - if (typeof (currentTime) === "undefined") currentTime = root.restart; - if (root.playing) stopAudio(); - root.playing = true; - root.data = root.replayer.getData(); - root.endTime = getLength(); - } - var note; - var offset = 0; - var messages = 0; - var data = root.data; - var ctx = getContext(); - var length = data.length; - // - queuedTime = 0.5; - startTime = ctx.currentTime; - // - for (var n = 0; n < length && messages < 100; n++) { - queuedTime += data[n][1]; - if (queuedTime < currentTime) { - offset = queuedTime; - continue; - } - currentTime = queuedTime - offset; - var event = data[n][0].event; - if (event.type !== "channel") continue; - var channel = event.channel; - switch (event.subtype) { - case 'noteOn': - if (MIDI.channels[channel].mute) break; - note = event.noteNumber - (root.MIDIOffset || 0); - eventQueue.push({ - event: event, - source: MIDI.noteOn(channel, event.noteNumber, event.velocity, currentTime / 1000 + ctx.currentTime), - interval: scheduleTracking(channel, note, queuedTime, offset, 144, event.velocity) - }); - messages ++; - break; - case 'noteOff': - if (MIDI.channels[channel].mute) break; - note = event.noteNumber - (root.MIDIOffset || 0); - eventQueue.push({ - event: event, - source: MIDI.noteOff(channel, event.noteNumber, currentTime / 1000 + ctx.currentTime), - interval: scheduleTracking(channel, note, queuedTime, offset, 128) - }); - break; - default: - break; - } - } -}; - -var stopAudio = function () { - var ctx = getContext(); - root.playing = false; - root.restart += (ctx.currentTime - startTime) * 1000; - // stop the audio, and intervals - while (eventQueue.length) { - var o = eventQueue.pop(); - window.clearInterval(o.interval); - if (!o.source) continue; // is not webaudio - if (typeof(o.source) === "number") { - window.clearTimeout(o.source); - } else { // webaudio - var source = o.source; - source.disconnect(0); - source.noteOff(0); - } - } - // run callback to cancel any notes still playing - for (var key in noteRegistrar) { - var o = noteRegistrar[key] - if (noteRegistrar[key].message === 144 && onMidiEvent) { - onMidiEvent({ - channel: o.channel, - note: o.note, - now: o.now, - end: o.end, - message: 128, - velocity: o.velocity - }); - } - } - // reset noteRegistrar - noteRegistrar = {}; -}; - })(); /* -------------------------------------------- @@ -1510,876 +781,419 @@ MIDI.noteToKey = {}; // 108 == C8 } })(); -})(); -var invertObject = function (o) { - if (o.length) { - var ret = {}; - for (var key = 0; key < o.length; key ++) { - ret[o[key]] = key; - } - } else { - var ret = {}; - for (var key in o) { - ret[o[key]] = key; - } - } - return ret; -}; - -if (typeof(MusicTheory) === "undefined") MusicTheory = {}; - -(function() { - - var root = MusicTheory; - - // KEY SIGNATURES - - root.key2number = { - 'A': 0, - 'A#': 1, - 'Bb': 1, - 'B': 2, - 'C': 3, - 'C#': 4, - 'Db': 4, - 'D': 5, - 'D#': 6, - 'Eb': 6, - 'E': 7, - 'F': 8, - 'F#': 9, - 'Gb': 9, - 'G': 10, - 'G#': 11, - 'Ab': 11 - }; - - root.number2float = { - 0: 0, - 1: 0.5, - 2: 1, - 3: 2, - 4: 2.5, - 5: 3, - 6: 3.5, - 7: 4, - 8: 5, - 9: 5.5, - 10: 6, - 11: 6.5, - 12: 7 - }; - - root.number2key = invertObject(root.key2number); - root.float2number = invertObject(root.number2float); - - root.getKeySignature = function (key) { - var keys = [ 'A', 'AB', 'B', 'C', 'CD', 'D', 'DE', 'E', 'F', 'FG', 'G', 'GA' ]; - var accidental = [ 'F', 'C', 'G', 'D', 'A', 'E', 'B' ]; - var signature = { // key signatures - 'Fb': -8, - 'Cb': -7, - 'Gb': -6, - 'Db': -5, - 'Ab': -4, - 'Eb': -3, - 'Bb': -2, - 'F': -1, - 'C': 0, - 'G': 1, - 'D': 2, - 'A': 3, - 'E': 4, - 'B': 5, - 'F#': 6, - 'C#': 7, - 'G#': 8, - 'D#': 9, - 'A#': 10, - 'E#': 11, - 'B#': 12 - }[key]; - if(signature < 0) { // flat - accidental = accidental.splice(7 + signature, -signature).reverse().join(''); - } else { // sharp - accidental = accidental.splice(0, signature).join(''); - } - for(var i = 0; i < keys.length; i ++) { - if (keys[i].length > 1) { - if (accidental.indexOf(keys[i][0]) != -1 || accidental.indexOf(keys[i][1]) != -1) { - if (signature > 0) { - keys[i] = keys[i][0] + '#'; - } else { - keys[i] = keys[i][1] + 'b'; - } - } else { - keys[i] = keys[i][0] + '#'; - } - } - }; - Piano.keySignature = keys; - }; - - //// TEMPO - - root.tempoFromTap = function(that) { - function getName(v) { - var tempo = { // wikipedia - 200: 'Prestissimo', - 168: 'Presto', - 140: 'Vivace', - 120: 'Allegro', - 112: 'Allegretto', - 101: 'Moderato', - 76: 'Andante', - 66: 'Adagio', - 60: 'Larghetto', - 40: 'Lento', - 0: 'Larghissimo' - }; - for (var n = 0, name = ""; n < 250; n ++) { - if (tempo[n]) name = tempo[n]; - if (v < n) return name; - } - return 'Prestissimo'; - }; - if (that.tap) { - var diff = (new Date()).getTime() - that.tap; - var c = 1 / (diff / 1000) * 60; - Piano.tempo = c; - console.log(getName(c), c, diff) - document.getElementById("taptap").value = (c>>0) +"bmp " + getName(c); - } - that.tap = (new Date()).getTime(); - }; - - //// CHORD FINDER - - root.findChord = function(r) { - function rewrite(o) { - var z = {}; - for (var i in o) { - var r = {}; - for (var ii in o[i]) { - r[o[i][ii]] = 1; - } - z[i] = r; - } - return z; - }; - var test = {}; - var values = "0 3".split(' '); - var chords = rewrite(Piano.chords); - for (var key in chords) { - for (var n = 0, length = values.length; n < length; n ++) { - if (isNaN(chords[key][values[n]])) { - test[key] = 1; - break; - } - } - } - var results = []; - for (var key in chords) { - if (!test[key]) results.push(key); - } - document.getElementById("find").value = results; - return results; - }; - - ///// CHORD INFORMATION - - root.scaleInfo = function(o) { - var intervalNames = [ 'r', 'b2', '2', 'b3', '3', '4', 'b5', '5', '♯5', '6', 'b7', '7', '8', 'b9', '9', '♯9', '10', '11', 'b12', '12', '♯12', '13' ]; // Interval numbers - var notes = '', - intervals = '', - gaps = '', - solfege = '', - // colors = '', - keys = ''; - for (var i in o) { - if (o[i] > 0) { - gaps += '-' + (o[i] - key); - } - var key = o[i]; - var note = Piano.calculateNote(key) % 12; - var noteName = Piano.keySignature[note]; - var color = Piano.Color[Piano.HSL].english[note]; - solfege += ', ' + MusicTheory.Solfege[noteName].syllable; - // colors += ', ' + (color[0] ? color[0].toUpperCase() + color.substr(1) : 'Undefined'); - keys += ', ' + key; - notes += ', ' + noteName; - intervals += ', ' + intervalNames[key]; - } - console.log( - 'notes: ' + notes.substr(2) + '
' + - 'solfege: ' + solfege.substr(2) + '
' + - 'intervals: ' + intervals.substr(2) + '
' + - 'keys: ' + keys.substr(2) + '
' + - 'gaps: ' + gaps.substr(1) - ); - }; - })(); /* - ------------------------------------------------------------ - MusicTheory.Synesthesia : 0.3 - ------------------------------------------------------------ - Peacock: “Instruments to perform color-music: Two centuries of technological experimentation,” Leonardo, 21 (1988), 397-406. - Gerstner: Karl Gerstner, The Forms of Color 1986 - Klein: Colour-Music: The art of light, London: Crosby Lockwood and Son, 1927. - Jameson: “Visual music in a visual programming language,” IEEE Symposium on Visual Languages, 1999, 111-118. - Helmholtz: Treatise on Physiological Optics, New York: Dover Books, 1962 - Jones: The art of light & color, New York: Van Nostrand Reinhold, 1972 - ------------------------------------------------------------ - Reference: http://rhythmiclight.com/archives/ideas/colorscales.html - ------------------------------------------------------------ + ------------------------------------- + MIDI.Player : 0.3 + ------------------------------------- + https://github.com/mudcube/MIDI.js + ------------------------------------- + #jasmid + ------------------------------------- */ -if (typeof(MusicTheory) === "undefined") var MusicTheory = {}; -if (typeof(MusicTheory.Synesthesia) === "undefined") MusicTheory.Synesthesia = {}; - -(function(root) { - root.data = { - 'Isaac Newton (1704)': { - ref: "Gerstner, p.167", - english: ['red',null,'orange',null,'yellow','green',null,'blue',null,'indigo',null,'violet'], - 0: [ 0, 96, 51 ], // C - 1: [ 0, 0, 0 ], // C# - 2: [ 29, 94, 52 ], // D - 3: [ 0, 0, 0 ], // D# - 4: [ 60, 90, 60 ], // E - 5: [ 135, 76, 32 ], // F - 6: [ 0, 0, 0 ], // F# - 7: [ 248, 82, 28 ], // G - 8: [ 0, 0, 0 ], // G# - 9: [ 302, 88, 26 ], // A - 10: [ 0, 0, 0 ], // A# - 11: [ 325, 84, 46 ] // B - }, - 'Louis Bertrand Castel (1734)': { - ref: 'Peacock, p.400', - english: ['blue','blue-green','green','olive green','yellow','yellow-orange','orange','red','crimson','violet','agate','indigo'], - 0: [ 248, 82, 28 ], - 1: [ 172, 68, 34 ], - 2: [ 135, 76, 32 ], - 3: [ 79, 59, 36 ], - 4: [ 60, 90, 60 ], - 5: [ 49, 90, 60 ], - 6: [ 29, 94, 52 ], - 7: [ 360, 96, 51 ], - 8: [ 1, 89, 33 ], - 9: [ 325, 84, 46 ], - 10: [ 273, 80, 27 ], - 11: [ 302, 88, 26 ] - }, - 'George Field (1816)': { - ref: 'Klein, p.69', - english: ['blue',null,'purple',null,'red','orange',null,'yellow',null,'yellow green',null,'green'], - 0: [ 248, 82, 28 ], - 1: [ 0, 0, 0 ], - 2: [ 302, 88, 26 ], - 3: [ 0, 0, 0 ], - 4: [ 360, 96, 51 ], - 5: [ 29, 94, 52 ], - 6: [ 0, 0, 0 ], - 7: [ 60, 90, 60 ], - 8: [ 0, 0, 0 ], - 9: [ 79, 59, 36 ], - 10: [ 0, 0, 0 ], - 11: [ 135, 76, 32 ] - }, - 'D. D. Jameson (1844)': { - ref: 'Jameson, p.12', - english: ['red','red-orange','orange','orange-yellow','yellow','green','green-blue','blue','blue-purple','purple','purple-violet','violet'], - 0: [ 360, 96, 51 ], - 1: [ 14, 91, 51 ], - 2: [ 29, 94, 52 ], - 3: [ 49, 90, 60 ], - 4: [ 60, 90, 60 ], - 5: [ 135, 76, 32 ], - 6: [ 172, 68, 34 ], - 7: [ 248, 82, 28 ], - 8: [ 273, 80, 27 ], - 9: [ 302, 88, 26 ], - 10: [ 313, 78, 37 ], - 11: [ 325, 84, 46 ] - }, - 'Theodor Seemann (1881)': { - ref: 'Klein, p.86', - english: ['carmine','scarlet','orange','yellow-orange','yellow','green','green blue','blue','indigo','violet','brown','black'], - 0: [ 0, 58, 26 ], - 1: [ 360, 96, 51 ], - 2: [ 29, 94, 52 ], - 3: [ 49, 90, 60 ], - 4: [ 60, 90, 60 ], - 5: [ 135, 76, 32 ], - 6: [ 172, 68, 34 ], - 7: [ 248, 82, 28 ], - 8: [ 302, 88, 26 ], - 9: [ 325, 84, 46 ], - 10: [ 0, 58, 26 ], - 11: [ 0, 0, 3 ] - }, - 'A. Wallace Rimington (1893)': { - ref: 'Peacock, p.402', - english: ['deep red','crimson','orange-crimson','orange','yellow','yellow-green','green','blueish green','blue-green','indigo','deep blue','violet'], - 0: [ 360, 96, 51 ], - 1: [ 1, 89, 33 ], - 2: [ 14, 91, 51 ], - 3: [ 29, 94, 52 ], - 4: [ 60, 90, 60 ], - 5: [ 79, 59, 36 ], - 6: [ 135, 76, 32 ], - 7: [ 163, 62, 40 ], - 8: [ 172, 68, 34 ], - 9: [ 302, 88, 26 ], - 10: [ 248, 82, 28 ], - 11: [ 325, 84, 46 ] - }, - 'Bainbridge Bishop (1893)': { - ref: 'Bishop, p.11', - english: ['red','orange-red or scarlet','orange','gold or yellow-orange','yellow or green-gold','yellow-green','green','greenish-blue or aquamarine','blue','indigo or violet-blue','violet','violet-red','red'], - 0: [ 360, 96, 51 ], - 1: [ 1, 89, 33 ], - 2: [ 29, 94, 52 ], - 3: [ 50, 93, 52 ], - 4: [ 60, 90, 60 ], - 5: [ 73, 73, 55 ], - 6: [ 135, 76, 32 ], - 7: [ 163, 62, 40 ], - 8: [ 302, 88, 26 ], - 9: [ 325, 84, 46 ], - 10: [ 343, 79, 47 ], - 11: [ 360, 96, 51 ] - }, - 'H. von Helmholtz (1910)': { - ref: 'Helmholtz, p.22', - english: ['yellow','green','greenish blue','cayan-blue','indigo blue','violet','end of red','red','red','red','red orange','orange'], - 0: [ 60, 90, 60 ], - 1: [ 135, 76, 32 ], - 2: [ 172, 68, 34 ], - 3: [ 211, 70, 37 ], - 4: [ 302, 88, 26 ], - 5: [ 325, 84, 46 ], - 6: [ 330, 84, 34 ], - 7: [ 360, 96, 51 ], - 8: [ 10, 91, 43 ], - 9: [ 10, 91, 43 ], - 10: [ 8, 93, 51 ], - 11: [ 28, 89, 50 ] - }, - 'Alexander Scriabin (1911)': { - ref: 'Jones, p.104', - english: ['red','violet','yellow','steely with the glint of metal','pearly blue the shimmer of moonshine','dark red','bright blue','rosy orange','purple','green','steely with a glint of metal','pearly blue the shimmer of moonshine'], - 0: [ 360, 96, 51 ], - 1: [ 325, 84, 46 ], - 2: [ 60, 90, 60 ], - 3: [ 245, 21, 43 ], - 4: [ 211, 70, 37 ], - 5: [ 1, 89, 33 ], - 6: [ 248, 82, 28 ], - 7: [ 29, 94, 52 ], - 8: [ 302, 88, 26 ], - 9: [ 135, 76, 32 ], - 10: [ 245, 21, 43 ], - 11: [ 211, 70, 37 ] - }, - 'Adrian Bernard Klein (1930)': { - ref: 'Klein, p.209', - english: ['dark red','red','red orange','orange','yellow','yellow green','green','blue-green','blue','blue violet','violet','dark violet'], - 0: [ 0, 91, 40 ], - 1: [ 360, 96, 51 ], - 2: [ 14, 91, 51 ], - 3: [ 29, 94, 52 ], - 4: [ 60, 90, 60 ], - 5: [ 73, 73, 55 ], - 6: [ 135, 76, 32 ], - 7: [ 172, 68, 34 ], - 8: [ 248, 82, 28 ], - 9: [ 292, 70, 31 ], - 10: [ 325, 84, 46 ], - 11: [ 330, 84, 34 ] - }, - 'August Aeppli (1940)': { - ref: 'Gerstner, p.169', - english: ['red',null,'orange',null,'yellow',null,'green','blue-green',null,'ultramarine blue','violet','purple'], - 0: [ 0, 96, 51 ], - 1: [ 0, 0, 0 ], - 2: [ 29, 94, 52 ], - 3: [ 0, 0, 0 ], - 4: [ 60, 90, 60 ], - 5: [ 0, 0, 0 ], - 6: [ 135, 76, 32 ], - 7: [ 172, 68, 34 ], - 8: [ 0, 0, 0 ], - 9: [ 211, 70, 37 ], - 10: [ 273, 80, 27 ], - 11: [ 302, 88, 26 ] - }, - 'I. J. Belmont (1944)': { - ref: 'Belmont, p.226', - english: ['red','red-orange','orange','yellow-orange','yellow','yellow-green','green','blue-green','blue','blue-violet','violet','red-violet'], - 0: [ 360, 96, 51 ], - 1: [ 14, 91, 51 ], - 2: [ 29, 94, 52 ], - 3: [ 50, 93, 52 ], - 4: [ 60, 90, 60 ], - 5: [ 73, 73, 55 ], - 6: [ 135, 76, 32 ], - 7: [ 172, 68, 34 ], - 8: [ 248, 82, 28 ], - 9: [ 313, 78, 37 ], - 10: [ 325, 84, 46 ], - 11: [ 338, 85, 37 ] - }, - 'Steve Zieverink (2004)': { - ref: 'Cincinnati Contemporary Art Center', - english: ['yellow-green','green','blue-green','blue','indigo','violet','ultra violet','infra red','red','orange','yellow-white','yellow'], - 0: [ 73, 73, 55 ], - 1: [ 135, 76, 32 ], - 2: [ 172, 68, 34 ], - 3: [ 248, 82, 28 ], - 4: [ 302, 88, 26 ], - 5: [ 325, 84, 46 ], - 6: [ 326, 79, 24 ], - 7: [ 1, 89, 33 ], - 8: [ 360, 96, 51 ], - 9: [ 29, 94, 52 ], - 10: [ 62, 78, 74 ], - 11: [ 60, 90, 60 ] - }, - 'Circle of Fifths (2012)': { - ref: "Stuart Wheatman", // http://www.valleysfamilychurch.org/ - english: [], - data: ['#122400', '#2E002E', '#002914', '#470000', '#002142', '#2E2E00', '#290052', '#003D00', '#520029', '#003D3D', '#522900', '#000080', '#244700', '#570057', '#004D26', '#7A0000', '#003B75', '#4C4D00', '#47008F', '#006100', '#850042', '#005C5C', '#804000', '#0000C7', '#366B00', '#80007F', '#00753B', '#B80000', '#0057AD', '#6B6B00', '#6600CC', '#008A00', '#B8005C', '#007F80', '#B35900', '#2424FF', '#478F00', '#AD00AD', '#00994D', '#F00000', '#0073E6', '#8F8F00', '#8A14FF', '#00AD00', '#EB0075', '#00A3A3', '#E07000', '#6B6BFF', '#5CB800', '#DB00DB', '#00C261', '#FF5757', '#3399FF', '#ADAD00', '#B56BFF', '#00D600', '#FF57AB', '#00C7C7', '#FF9124', '#9999FF', '#6EDB00', '#FF29FF', '#00E070', '#FF9999', '#7ABDFF', '#D1D100', '#D1A3FF', '#00FA00', '#FFA3D1', '#00E5E6', '#FFC285', '#C2C2FF', '#80FF00', '#FFA8FF', '#00E070', '#FFCCCC', '#C2E0FF', '#F0F000', '#EBD6FF', '#ADFFAD', '#FFD6EB', '#8AFFFF', '#FFEBD6', '#EBEBFF', '#E0FFC2', '#FFEBFF', '#E5FFF2', '#FFF5F5'] } - }; - - root.map = function(type) { - var data = {}; - var blend = function(a, b) { - return [ // blend two colors and round results - (a[0] * 0.5 + b[0] * 0.5 + 0.5) >> 0, - (a[1] * 0.5 + b[1] * 0.5 + 0.5) >> 0, - (a[2] * 0.5 + b[2] * 0.5 + 0.5) >> 0 - ]; - }; - var syn = root.data; - var colors = syn[type] || syn["D. D. Jameson (1844)"]; - for (var note = 0; note <= 88; note ++) { // creates mapping for 88 notes - if (colors.data) { - data[note] = { - hsl: colors.data[note], - hex: colors.data[note] - } - } else { - var clr = colors[(note + 9) % 12]; - var H = clr.H || clr[0]; - var S = clr.S || clr[1]; - var L = clr.L || clr[2]; - if (H == S && S == L) { - clr = blend(parray, colors[(note + 10) % 12]); - } - var amount = L / 10; - var octave = note / 12 >> 0; - var octaveLum = L + amount * octave - 3 * amount; // map luminance to octave - data[note] = { - hsl: 'hsla(' + H + ',' + S + '%,' + octaveLum + '%, 1)', - hex: Color.Space({H:H, S:S, L:octaveLum}, "HSL>RGB>HEX>W3") - }; - var parray = clr; - } - } - return data; - }; - -})(MusicTheory.Synesthesia); -/* - ---------------------------------------------------- - Loader.js : 0.4.2 : 2012/11/09 - ---------------------------------------------------- - https://github.com/mudcube/Loader.js - ---------------------------------------------------- - /// Simple setup. - var loader = new widgets.Loader; - - /// More complex setup. - var loader = new widgets.Loader({ - id: "loader", - bars: 12, - radius: 0, - lineWidth: 20, - lineHeight: 70, - timeout: 30, // maximum timeout in seconds. - background: "rgba(0,0,0,0.5)", - container: document.body, - oncomplete: function() { - // call function once loader has completed - }, - onstart: function() { - // call function once loader has started - } - }); - - /// Add a new message to the queue. - var loaderId = loader.add({ - message: "test", - getProgress: function() { // sends progress to loader.js - return progress; // value between 1-100 - } - }); - - /// Remove a specific loader message. - loader.remove(loaderId); - - /// Recenter the loader within container (run onresize) - loader.center(); - - /// Stop all loader instances. - loader.stop(); -*/ - -if (typeof (widgets) === "undefined") var widgets = {}; +if (typeof (MIDI) === "undefined") var MIDI = {}; +if (typeof (MIDI.Player) === "undefined") MIDI.Player = {}; (function() { "use strict"; -var PI = Math.PI; -var noCanvas = !document.createElement("canvas").getContext; -var fadeOutSpeed = 400; -var defaultConfig = { - id: "loader", - bars: 12, - radius: 0, - lineWidth: 20, - lineHeight: 70, - timeout: 0, - display: true +var root = MIDI.Player; +root.callback = undefined; // your custom callback goes here! +root.currentTime = 0; +root.endTime = 0; +root.restart = 0; +root.playing = false; +root.timeWarp = 1; + +// +root.start = +root.resume = function () { + if (root.currentTime < -1) root.currentTime = -1; + startAudio(root.currentTime); }; -widgets.Loader = function (configure) { - if (noCanvas) return; - var that = this; - if (typeof (configure) === "string") configure = { message: configure }; - if (typeof (configure) === "boolean") configure = { display: false }; - if (typeof (configure) === "undefined") configure = {}; - configure.container = configure.container || document.body; - if (!configure.container) return; +root.pause = function () { + var tmp = root.restart; + stopAudio(); + root.restart = tmp; +}; - /// Mixin the default configurations. - for (var key in defaultConfig) { - if (typeof (configure[key]) === "undefined") { - configure[key] = defaultConfig[key]; +root.stop = function () { + stopAudio(); + root.restart = 0; + root.currentTime = 0; +}; + +root.addListener = function(callback) { + onMidiEvent = callback; +}; + +root.removeListener = function() { + onMidiEvent = undefined; +}; + +root.clearAnimation = function() { + if (root.interval) { + window.clearInterval(root.interval); + } +}; + +root.setAnimation = function(config) { + var callback = (typeof(config) === "function") ? config : config.callback; + var interval = config.interval || 30; + var currentTime = 0; + var tOurTime = 0; + var tTheirTime = 0; + // + root.clearAnimation(); + root.interval = window.setInterval(function () { + if (root.endTime === 0) return; + if (root.playing) { + currentTime = (tTheirTime === root.currentTime) ? tOurTime - (new Date).getTime() : 0; + if (root.currentTime === 0) { + currentTime = 0; + } else { + currentTime = root.currentTime - currentTime; + } + if (tTheirTime !== root.currentTime) { + tOurTime = (new Date).getTime(); + tTheirTime = root.currentTime; + } + } else { // paused + currentTime = root.currentTime; } - } - - /// Setup element - var canvas = document.getElementById(configure.id); - if (!canvas) { - var div = document.createElement("div"); - var span = document.createElement("span"); - span.className = "message"; - div.appendChild(span); - div.className = defaultConfig.id; - div.style.cssText = transitionCSS("opacity", fadeOutSpeed); - this.span = span; - this.div = div; - var canvas = document.createElement("canvas"); - document.body.appendChild(canvas); - canvas.id = configure.id; - canvas.style.cssText = "opacity: 1; position: absolute; z-index: 10000;"; - div.appendChild(canvas); - configure.container.appendChild(div); - } else { - this.span = canvas.parentNode.getElementsByTagName("span")[0]; - } - - /// Configure - var delay = configure.delay; - var bars = configure.bars; - var radius = configure.radius; - var max = configure.lineHeight + 20; - var size = max * 2 + configure.radius * 2; - var windowSize = getWindowSize(configure.container); - var width = windowSize.width - size; - var height = windowSize.height - size; - var deviceRatio = window.devicePixelRatio || 1; - /// - canvas.width = size * deviceRatio; - canvas.height = size * deviceRatio; - /// - var iteration = 0; - var ctx = canvas.getContext("2d"); - ctx.globalCompositeOperation = "lighter"; - ctx.shadowOffsetX = 1; - ctx.shadowOffsetY = 1; - ctx.shadowBlur = 1; - ctx.shadowColor = "rgba(0, 0, 0, 0.5)"; - - /// Public functions. - this.messages = {}; - this.message = function (message, onstart) { - if (!this.interval) return this.start(onstart, message); - return this.add({ - message: message, - onstart: onstart + var endTime = root.endTime; + var percent = currentTime / endTime; + var total = currentTime / 1000; + var minutes = total / 60; + var seconds = total - (minutes * 60); + var t1 = minutes * 60 + seconds; + var t2 = (endTime / 1000); + if (t2 - t1 < -1) return; + callback({ + now: t1, + end: t2, + events: noteRegistrar }); - }; - - this.update = function(id, message, percent) { - if (!id) for (var id in this.messages); - var item = this.messages[id]; - item.message = message; - if (typeof(percent) === "number") item.span.innerHTML = percent + "%"; - if (message.substr(-3) === "...") { // animated dots - item._message = message.substr(0, message.length - 3); - item.messageAnimate = [".  ", ".. ", "..."].reverse(); - } else { // normal - item._message = message; - item.messageAnimate = false; + }, interval); +}; + +// helpers + +root.loadMidiFile = function() { // reads midi into javascript array of events + root.replayer = new Replayer(MidiFile(root.currentData), root.timeWarp); + root.data = root.replayer.getData(); + root.endTime = getLength(); +}; + +root.loadFile = function (file, callback) { + root.stop(); + if (file.indexOf("base64,") !== -1) { + var data = window.atob(file.split(",")[1]); + root.currentData = data; + root.loadMidiFile(); + if (callback) callback(data); + return; + } + /// + var title = file.split(" - ")[1] || file; + document.getElementById("playback-title").innerHTML = title.replace(".mid",""); + /// + var fetch = new XMLHttpRequest(); + fetch.open('GET', file); + fetch.overrideMimeType("text/plain; charset=x-user-defined"); + fetch.onreadystatechange = function () { + if (this.readyState === 4 && this.status === 200) { + var t = this.responseText || ""; + var ff = []; + var mx = t.length; + var scc = String.fromCharCode; + for (var z = 0; z < mx; z++) { + ff[z] = scc(t.charCodeAt(z) & 255); + } + var data = ff.join(""); + root.currentData = data; + root.loadMidiFile(); + if (callback) callback(data); } - /// - item.element.innerHTML = message; }; - - this.add = function (conf) { - if (typeof(conf) === "string") conf = { message: conf }; - var background = configure.background ? configure.background : "rgba(0,0,0,0.65)"; - this.span.style.cssText = "background: " + background + ";"; - this.div.style.cssText = transitionCSS("opacity", fadeOutSpeed); - if (this.stopPropagation) { - this.div.style.cssText += "background: rgba(0,0,0,0.25);"; - } else { - this.div.style.cssText += "pointer-events: none;"; - } - /// - canvas.parentNode.style.opacity = 1; - canvas.parentNode.style.display = "block"; - if (configure.background) this.div.style.background = configure.backgrond; - /// - var timestamp = (new Date()).getTime(); - var seed = Math.abs(timestamp * Math.random() >> 0); - var message = conf.message; - /// - var container = document.createElement("div"); - container.style.cssText = transitionCSS("opacity", 500); - var span = document.createElement("span"); - span.style.cssText = "float: right; width: 50px;"; - var node = document.createElement("span"); - node.innerHTML = message; - /// - container.appendChild(node); - container.appendChild(span); - /// - var item = this.messages[seed] = { - seed: seed, - container: container, - element: node, - span: span, + fetch.send(); +}; + +// Playing the audio + +var eventQueue = []; // hold events to be triggered +var queuedTime; // +var startTime = 0; // to measure time elapse +var noteRegistrar = {}; // get event for requested note +var onMidiEvent = undefined; // listener callback +var scheduleTracking = function (channel, note, currentTime, offset, message, velocity) { + var interval = window.setTimeout(function () { + var data = { + channel: channel, + note: note, + now: currentTime, + end: root.endTime, message: message, - timeout: (conf.timeout || configure.timeout) * 1000, - timestamp: timestamp, - getProgress: conf.getProgress + velocity: velocity }; - this.span.appendChild(container); - this.span.style.display = "block"; - this.update(item.seed, message); - /// Escape event loop. - if (conf.onstart) { - window.setTimeout(conf.onstart, 50); - } - /// - this.center(); - /// - if (!this.interval) { - if (!conf.delay) renderAnimation(); - window.clearInterval(this.interval); - this.interval = window.setInterval(renderAnimation, 30); - } - /// Return identifier. - return seed; - }; - - this.remove = function (seed) { - iteration += 0.07; - var timestamp = (new Date()).getTime(); - if (typeof(seed) === "object") seed = seed.join(":"); - if (seed) seed = ":" + seed + ":"; - /// Remove element. - for (var key in this.messages) { - var item = this.messages[key]; - if (!seed || seed.indexOf(":" + item.seed + ":") !== -1) { - delete this.messages[item.seed]; - item.container.style.color = "#99ff88"; - removeChild(item); - if (item.getProgress) item.span.innerHTML = "100%"; - } - } - }; - - this.start = function (onstart, message) { - if (!(message || configure.message)) return; - return this.add({ - message: message || configure.message, - onstart: onstart - }); - }; - - this.stop = function () { - this.remove(); - window.clearInterval(this.interval); - delete this.interval; - if (configure.oncomplete) configure.oncomplete(); - if (canvas && canvas.style) { - div.style.cssText += "pointer-events: none;"; - window.setTimeout(function() { - that.div.style.opacity = 0; - }, 1); - window.setTimeout(function () { - if (that.interval) return; - that.stopPropagation = false; - canvas.parentNode.style.display = "none"; - ctx.clearRect(0, 0, size, size); - }, fadeOutSpeed * 1000); - } - }; - - this.center = function() { - var windowSize = getWindowSize(configure.container); - var width = windowSize.width - size; - var height = windowSize.height - size; - /// Center the animation within the content. - canvas.style.left = (width / 2) + "px"; - canvas.style.top = (height / 2) + "px"; - canvas.style.width = (size) + "px"; - canvas.style.height = (size) + "px"; - that.span.style.top = (height / 2 + size - 10) + "px"; - }; - - var style = document.createElement("style"); - style.innerHTML = '\ -.loader { color: #fff; position: fixed; left: 0; top: 0; width: 100%; height: 100%; z-index: 100000; opacity: 0; display: none; }\ -.loader span.message { line-height: 1.5em; font-family: monospace; font-size: 14px; margin: auto; opacity: 1; display: none; border-radius: 10px; padding: 0px; width: 300px; text-align: center; position: absolute; z-index: 10000; left: 0; right: 0; }\ -.loader span.message div { border-bottom: 1px solid #222; padding: 5px 10px; clear: both; text-align: left; opacity: 1; }\ -.loader span.message div:last-child { border-bottom: none; }\ -'; - document.head.appendChild(style); - /// Private functions. - var removeChild = function(item) { - window.setTimeout(function() { // timeout in case within same event loop. - item.container.style.opacity = 0; - }, 1); - window.setTimeout(function() { // wait for opacity=0 before removing the element. - item.container.parentNode.removeChild(item.container); - }, 250); - }; - var renderAnimation = function () { - var timestamp = (new Date()).getTime(); - for (var key in that.messages) { - var item = that.messages[key]; - var nid = iteration / 0.07 >> 0; - if (nid % 5 === 0 && item.getProgress) { - if (item.timeout && item.timestamp && timestamp - item.timestamp > item.timeout) { - that.remove(item.seed); - continue; - } - var progress = item.getProgress(); - if (progress >= 100) { - that.remove(item.seed); - continue; - } - item.span.innerHTML = (progress >> 0) + "%"; - } - if (nid % 10 === 0) { - if (item.messageAnimate) { - var length = item.messageAnimate.length; - var n = nid / 10 % length; - var text = item._message + item.messageAnimate[n]; - item.element.innerHTML = text; - } - } - } - if (!key) { - that.stop(); - } // - ctx.save(); - ctx.clearRect(0, 0, size * deviceRatio, size * deviceRatio); - ctx.scale(deviceRatio, deviceRatio); - ctx.translate(size / 2, size / 2); - var hues = 360 - 360 / bars; - for (var i = 0; i < bars; i++) { - var angle = (i / bars * 2 * PI) + iteration; - ctx.save(); - ctx.translate(radius * Math.sin(-angle), radius * Math.cos(-angle)); - ctx.rotate(angle); - // round-rect properties - var x = -configure.lineWidth / 2; - var y = 0; - var width = configure.lineWidth; - var height = configure.lineHeight; - var curve = width / 2; - // round-rect path - ctx.beginPath(); - ctx.moveTo(x + curve, y); - ctx.lineTo(x + width - curve, y); - ctx.quadraticCurveTo(x + width, y, x + width, y + curve); - ctx.lineTo(x + width, y + height - curve); - ctx.quadraticCurveTo(x + width, y + height, x + width - curve, y + height); - ctx.lineTo(x + curve, y + height); - ctx.quadraticCurveTo(x, y + height, x, y + height - curve); - ctx.lineTo(x, y + curve); - ctx.quadraticCurveTo(x, y, x + curve, y); - // round-rect fill - var hue = ((i / (bars - 1)) * hues); - ctx.fillStyle = "hsla(" + hue + ", 100%, 50%, 0.85)"; - ctx.fill(); - ctx.restore(); + if (message === 128) { + delete noteRegistrar[note]; + } else { + noteRegistrar[note] = data; } - ctx.restore(); - iteration += 0.07; - }; - // - if (configure.display === false) return this; - // - this.start(); - // - return this; + if (onMidiEvent) { + onMidiEvent(data); + } + root.currentTime = currentTime; + if (root.currentTime === queuedTime && queuedTime < root.endTime) { // grab next sequence + startAudio(queuedTime, true); + } + }, currentTime - offset); + return interval; }; -//// - -var transitionCSS = function(type, ms) { - return '\ - -webkit-transition-property: '+type+';\ - -webkit-transition-duration: '+ms+'ms;\ - -moz-transition-property: '+type+';\ - -moz-transition-duration: '+ms+'ms;\ - -o-transition-property: '+type+';\ - -o-transition-duration: '+ms+'ms;\ - -ms-transition-property: '+type+';\ - -ms-transition-duration: '+ms+'ms;'; +var getContext = function() { + if (MIDI.lang === 'WebAudioAPI') { + return MIDI.Player.ctx; + } else if (!root.ctx) { + root.ctx = { currentTime: 0 }; + } + return root.ctx; }; -var getWindowSize = function (element) { - if (window.innerWidth && window.innerHeight) { - var width = window.innerWidth; - var height = window.innerHeight; - } else if (document.compatMode === "CSS1Compat" && document.documentElement && document.documentElement.offsetWidth) { - var width = document.documentElement.offsetWidth; - var height = document.documentElement.offsetHeight; - } else if (document.body && document.body.offsetWidth) { - var width = document.body.offsetWidth; - var height = document.body.offsetHeight; +var getLength = function() { + var data = root.data; + var length = data.length; + var totalTime = 0.5; + for (var n = 0; n < length; n++) { + totalTime += data[n][1]; } - if (element) { - var width = element.offsetWidth; + return totalTime; +}; + +var startAudio = function (currentTime, fromCache) { + if (!root.replayer) return; + if (!fromCache) { + if (typeof (currentTime) === "undefined") currentTime = root.restart; + if (root.playing) stopAudio(); + root.playing = true; + root.data = root.replayer.getData(); + root.endTime = getLength(); } - return { - width: width, - height: height - }; + var note; + var offset = 0; + var messages = 0; + var data = root.data; + var ctx = getContext(); + var length = data.length; + // + queuedTime = 0.5; + startTime = ctx.currentTime; + // + for (var n = 0; n < length && messages < 100; n++) { + queuedTime += data[n][1]; + if (queuedTime < currentTime) { + offset = queuedTime; + continue; + } + currentTime = queuedTime - offset; + var event = data[n][0].event; + if (event.type !== "channel") continue; + var channel = event.channel; + switch (event.subtype) { + case 'noteOn': + if (MIDI.channels[channel].mute) break; + note = event.noteNumber - (root.MIDIOffset || 0); + eventQueue.push({ + event: event, + source: MIDI.noteOn(channel, event.noteNumber, event.velocity, currentTime / 1000 + ctx.currentTime), + interval: scheduleTracking(channel, note, queuedTime, offset, 144, event.velocity) + }); + messages ++; + break; + case 'noteOff': + if (MIDI.channels[channel].mute) break; + note = event.noteNumber - (root.MIDIOffset || 0); + eventQueue.push({ + event: event, + source: MIDI.noteOff(channel, event.noteNumber, currentTime / 1000 + ctx.currentTime), + interval: scheduleTracking(channel, note, queuedTime, offset, 128) + }); + break; + default: + break; + } + } +}; + +var stopAudio = function () { + var ctx = getContext(); + root.playing = false; + root.restart += (ctx.currentTime - startTime) * 1000; + // stop the audio, and intervals + while (eventQueue.length) { + var o = eventQueue.pop(); + window.clearInterval(o.interval); + if (!o.source) continue; // is not webaudio + if (typeof(o.source) === "number") { + window.clearTimeout(o.source); + } else { // webaudio + var source = o.source; + source.disconnect(0); + source.noteOff(0); + } + } + // run callback to cancel any notes still playing + for (var key in noteRegistrar) { + var o = noteRegistrar[key] + if (noteRegistrar[key].message === 144 && onMidiEvent) { + onMidiEvent({ + channel: o.channel, + note: o.note, + now: o.now, + end: o.end, + message: 128, + velocity: o.velocity + }); + } + } + // reset noteRegistrar + noteRegistrar = {}; }; })(); +/* + + DOMLoader.XMLHttp + -------------------------- + DOMLoader.sendRequest({ + url: "./dir/something.extension", + data: "test!", + onerror: function(event) { + console.log(event); + }, + onload: function(response) { + console.log(response.responseText); + }, + onprogress: function (event) { + var percent = event.loaded / event.total * 100 >> 0; + loader.message("loading: " + percent + "%"); + } + }); + +*/ + +if (typeof(DOMLoader) === "undefined") var DOMLoader = {}; + +// Add XMLHttpRequest when not available + +if (typeof (XMLHttpRequest) === "undefined") { + var XMLHttpRequest; + (function () { // find equivalent for IE + var factories = [ + function () { + return new ActiveXObject("Msxml2.XMLHTTP") + }, function () { + return new ActiveXObject("Msxml3.XMLHTTP") + }, function () { + return new ActiveXObject("Microsoft.XMLHTTP") + }]; + for (var i = 0; i < factories.length; i++) { + try { + factories[i](); + } catch (e) { + continue; + } + break; + } + XMLHttpRequest = factories[i]; + })(); +} + +if (typeof ((new XMLHttpRequest()).responseText) === "undefined") { + // http://stackoverflow.com/questions/1919972/how-do-i-access-xhr-responsebody-for-binary-data-from-javascript-in-ie + var IEBinaryToArray_ByteStr_Script = + "\r\n"+ + "\r\n"; + + // inject VBScript + document.write(IEBinaryToArray_ByteStr_Script); + + DOMLoader.sendRequest = function(conf) { + // helper to convert from responseBody to a "responseText" like thing + function getResponseText(binary) { + var byteMapping = {}; + for (var i = 0; i < 256; i++) { + for (var j = 0; j < 256; j++) { + byteMapping[String.fromCharCode(i + j * 256)] = String.fromCharCode(i) + String.fromCharCode(j); + } + } + // call into VBScript utility fns + var rawBytes = IEBinaryToArray_ByteStr(binary); + var lastChr = IEBinaryToArray_ByteStr_Last(binary); + return rawBytes.replace(/[\s\S]/g, function (match) { + return byteMapping[match]; + }) + lastChr; + }; + // + var req = XMLHttpRequest(); + req.open("GET", conf.url, true); + if (conf.responseType) req.responseType = conf.responseType; + if (conf.onerror) req.onerror = conf.onerror; + if (conf.onprogress) req.onprogress = conf.onprogress; + req.onreadystatechange = function (event) { + if (req.readyState === 4) { + if (req.status === 200) { + req.responseText = getResponseText(req.responseBody); + } else { + req = false; + } + if (conf.onload) conf.onload(req); + } + }; + req.setRequestHeader("Accept-Charset", "x-user-defined"); + req.send(null); + return req; + } +} else { + DOMLoader.sendRequest = function(conf) { + var req = new XMLHttpRequest(); + req.open(conf.data ? "POST" : "GET", conf.url, true); + if (req.overrideMimeType) req.overrideMimeType("text/plain; charset=x-user-defined"); + if (conf.data) req.setRequestHeader('Content-type','application/x-www-form-urlencoded'); + if (conf.responseType) req.responseType = conf.responseType; + if (conf.onerror) req.onerror = conf.onerror; + if (conf.onprogress) req.onprogress = conf.onprogress; + req.onreadystatechange = function (event) { + if (req.readyState === 4) { + if (req.status !== 200 && req.status != 304) { + if (conf.onerror) conf.onerror(event, false); + return; + } + if (conf.onload) { + conf.onload(req); + } + } + }; + req.send(conf.data); + return req; + }; +} /* ---------------------------------------------------- DOMLoader.script.js : 0.1.2 : 2012/09/08 : http://mudcu.be @@ -2566,1913 +1380,4 @@ DOMLoader.script.prototype.add = function(config) { DOMLoader.script = (new DOMLoader.script()); -})(); -/* - - DOMLoader.XMLHttp - -------------------------- - DOMLoader.sendRequest({ - url: "./dir/something.extension", - data: "test!", - onerror: function(event) { - console.log(event); - }, - onload: function(response) { - console.log(response.responseText); - }, - onprogress: function (event) { - var percent = event.loaded / event.total * 100 >> 0; - loader.message("loading: " + percent + "%"); - } - }); - -*/ - -if (typeof(DOMLoader) === "undefined") var DOMLoader = {}; - -// Add XMLHttpRequest when not available - -if (typeof (XMLHttpRequest) === "undefined") { - var XMLHttpRequest; - (function () { // find equivalent for IE - var factories = [ - function () { - return new ActiveXObject("Msxml2.XMLHTTP") - }, function () { - return new ActiveXObject("Msxml3.XMLHTTP") - }, function () { - return new ActiveXObject("Microsoft.XMLHTTP") - }]; - for (var i = 0; i < factories.length; i++) { - try { - factories[i](); - } catch (e) { - continue; - } - break; - } - XMLHttpRequest = factories[i]; - })(); -} - -if (typeof ((new XMLHttpRequest()).responseText) === "undefined") { - // http://stackoverflow.com/questions/1919972/how-do-i-access-xhr-responsebody-for-binary-data-from-javascript-in-ie - var IEBinaryToArray_ByteStr_Script = - "\r\n"+ - "\r\n"; - - // inject VBScript - document.write(IEBinaryToArray_ByteStr_Script); - - DOMLoader.sendRequest = function(conf) { - // helper to convert from responseBody to a "responseText" like thing - function getResponseText(binary) { - var byteMapping = {}; - for (var i = 0; i < 256; i++) { - for (var j = 0; j < 256; j++) { - byteMapping[String.fromCharCode(i + j * 256)] = String.fromCharCode(i) + String.fromCharCode(j); - } - } - // call into VBScript utility fns - var rawBytes = IEBinaryToArray_ByteStr(binary); - var lastChr = IEBinaryToArray_ByteStr_Last(binary); - return rawBytes.replace(/[\s\S]/g, function (match) { - return byteMapping[match]; - }) + lastChr; - }; - // - var req = XMLHttpRequest(); - req.open("GET", conf.url, true); - if (conf.responseType) req.responseType = conf.responseType; - if (conf.onerror) req.onerror = conf.onerror; - if (conf.onprogress) req.onprogress = conf.onprogress; - req.onreadystatechange = function (event) { - if (req.readyState === 4) { - if (req.status === 200) { - req.responseText = getResponseText(req.responseBody); - } else { - req = false; - } - if (conf.onload) conf.onload(req); - } - }; - req.setRequestHeader("Accept-Charset", "x-user-defined"); - req.send(null); - return req; - } -} else { - DOMLoader.sendRequest = function(conf) { - var req = new XMLHttpRequest(); - req.open(conf.data ? "POST" : "GET", conf.url, true); - if (req.overrideMimeType) req.overrideMimeType("text/plain; charset=x-user-defined"); - if (conf.data) req.setRequestHeader('Content-type','application/x-www-form-urlencoded'); - if (conf.responseType) req.responseType = conf.responseType; - if (conf.onerror) req.onerror = conf.onerror; - if (conf.onprogress) req.onprogress = conf.onprogress; - req.onreadystatechange = function (event) { - if (req.readyState === 4) { - if (req.status !== 200 && req.status != 304) { - if (conf.onerror) conf.onerror(event, false); - return; - } - if (conf.onload) { - conf.onload(req); - } - } - }; - req.send(conf.data); - return req; - }; -} -/* - ---------------------------------------------------- - Event.js : 1.1.1 : 2012/11/19 : MIT License - ---------------------------------------------------- - https://github.com/mudcube/Event.js - ---------------------------------------------------- - 1 : click, dblclick, dbltap - 1+ : tap, longpress, drag, swipe - 2+ : pinch, rotate - : mousewheel, devicemotion, shake - ---------------------------------------------------- - TODO - ---------------------------------------------------- - * switch configuration to 4th argument on addEventListener - * bbox calculation for elements scaled with transform. - ---------------------------------------------------- - NOTES - ---------------------------------------------------- - * When using other libraries that may have built in "Event" namespace, - i.e. Typescript, you can use "eventjs" instead of "Event" for all example calls. - ---------------------------------------------------- - REQUIREMENTS: querySelector, querySelectorAll - ---------------------------------------------------- - * There are two ways to add/remove events with this library. - ---------------------------------------------------- - // Retains "this" attribute as target, and overrides native addEventListener. - target.addEventListener(type, listener, useCapture); - target.removeEventListener(type, listener, useCapture); - - // Attempts to perform as fast as possible. - Event.add(type, listener, configure); - Event.remove(type, listener, configure); - - * You can turn prototyping on/off for individual features. - ---------------------------------------------------- - Event.modifyEventListener = true; // add custom *EventListener commands to HTMLElements. - Event.modifySelectors = true; // add bulk *EventListener commands on NodeLists from querySelectorAll and others. - - * Example of setting up a single listener with a custom configuration. - ---------------------------------------------------- - // optional configuration. - var configure = { - fingers: 2, // listen for specifically two fingers. - snap: 90 // snap to 90 degree intervals. - }; - // adding with addEventListener() - target.addEventListener("swipe", function(event) { - // additional variables can be found on the event object. - console.log(event.velocity, event.angle, event.fingers); - }, configure); - - // adding with Event.add() - Event.add("swipe", function(event, self) { - // additional variables can be found on the self object. - console.log(self.velocity, self.angle, self.fingers); - }, configure); - - * Multiple listeners glued together. - ---------------------------------------------------- - // adding with addEventListener() - target.addEventListener("click swipe", function(event) { }); - - // adding with Event.add() - Event.add(target, "click swipe", function(event, self) { }); - - * Use query selectors to create an event (querySelectorAll) - ---------------------------------------------------- - // adding events to NodeList from querySelectorAll() - document.querySelectorAll("#element a.link").addEventListener("click", callback); - - // adding with Event.add() - Event.add("#element a.link", "click", callback); - - * Listen for selector to become available (querySelector) - ---------------------------------------------------- - Event.add("body", "ready", callback); - // or... - Event.add({ - target: "body", - type: "ready", - timeout: 10000, // set a timeout to stop checking. - interval: 30, // set how often to check for element. - listener: callback - }); - - * Multiple listeners bound to one callback w/ single configuration. - ---------------------------------------------------- - var bindings = Event.add({ - target: target, - type: "click swipe", - snap: 90, // snap to 90 degree intervals. - minFingers: 2, // minimum required fingers to start event. - maxFingers: 4, // maximum fingers in one event. - listener: function(event, self) { - console.log(self.gesture); // will be click or swipe. - console.log(self.x); - console.log(self.y); - console.log(self.identifier); - console.log(self.start); - console.log(self.fingers); // somewhere between "2" and "4". - self.pause(); // disable event. - self.resume(); // enable event. - self.remove(); // remove event. - } - }); - - * Multiple listeners bound to multiple callbacks w/ single configuration. - ---------------------------------------------------- - var bindings = Event.add({ - target: target, - minFingers: 1, - maxFingers: 12, - listeners: { - click: function(event, self) { - self.remove(); // removes this click listener. - }, - swipe: function(event, self) { - binding.remove(); // removes both the click + swipe listeners. - } - } - }); - - * Multiple listeners bound to multiple callbacks w/ multiple configurations. - ---------------------------------------------------- - var binding = Event.add({ - target: target, - listeners: { - longpress: { - fingers: 1, - wait: 500, // milliseconds - listener: function(event, self) { - console.log(self.fingers); // "1" finger. - } - }, - drag: { - fingers: 3, - position: "relative", // "relative", "absolute", "difference", "move" - listener: function(event, self) { - console.log(self.fingers); // "3" fingers. - console.log(self.x); // coordinate is relative to edge of target. - } - } - } - }); - - * Capturing an event and manually forwarding it to a proxy (tiered events). - ---------------------------------------------------- - Event.add(target, "down", function(event, self) { - var x = event.pageX; // local variables that wont change. - var y = event.pageY; - Event.proxy.drag({ - event: event, - target: target, - listener: function(event, self) { - console.log(x - event.pageX); // measure movement. - console.log(y - event.pageY); - } - }); - }); - ---------------------------------------------------- - - * Event proxies. - * type, fingers, state, start, x, y, position, bbox - * rotation, scale, velocity, angle, delay, timeout - ---------------------------------------------------- - // "Click" :: fingers, minFingers, maxFingers. - Event.add(window, "click", function(event, self) { - console.log(self.gesture, self.x, self.y); - }); - // "Double-Click" :: fingers, minFingers, maxFingers. - Event.add(window, "dblclick", function(event, self) { - console.log(self.gesture, self.x, self.y); - }); - // "Drag" :: fingers, maxFingers, position - Event.add(window, "drag", function(event, self) { - console.log(self.gesture, self.fingers, self.state, self.start, self.x, self.y, self.bbox); - }); - // "Gesture" :: fingers, minFingers, maxFingers. - Event.add(window, "gesture", function(event, self) { - console.log(self.gesture, self.fingers, self.state, self.rotation, self.scale); - }); - // "Swipe" :: fingers, minFingers, maxFingers, snap, threshold. - Event.add(window, "swipe", function(event, self) { - console.log(self.gesture, self.fingers, self.velocity, self.angle); - }); - // "Tap" :: fingers, minFingers, maxFingers, timeout. - Event.add(window, "tap", function(event, self) { - console.log(self.gesture, self.fingers); - }); - // "Longpress" :: fingers, minFingers, maxFingers, delay. - Event.add(window, "longpress", function(event, self) { - console.log(self.gesture, self.fingers); - }); - // - Event.add(window, "shake", function(event, self) { - console.log(self.gesture, self.acceleration, self.accelerationIncludingGravity); - }); - // - Event.add(window, "devicemotion", function(event, self) { - console.log(self.gesture, self.acceleration, self.accelerationIncludingGravity); - }); - // - Event.add(window, "wheel", function(event, self) { - console.log(self.gesture, self.state, self.wheelDelta); - }); - - * Stop, prevent and cancel. - ---------------------------------------------------- - Event.stop(event); // stop bubble. - Event.prevent(event); // prevent default. - Event.cancel(event); // stop and prevent. - - * Track for proper command/control-key for Mac/PC. - ---------------------------------------------------- - Event.add(window, "keyup keydown", Event.proxy.metaTracker); - console.log(Event.proxy.metaKey); - - * Test for event features, in this example Drag & Drop file support. - ---------------------------------------------------- - console.log(Event.supports('dragstart') && Event.supports('drop') && !!window.FileReader); - -*/ - -if (typeof(Event) === "undefined") var Event = {}; -if (typeof(eventjs) === "undefined") var eventjs = Event; - -Event = (function(root) { "use strict"; - -// Add custom *EventListener commands to HTMLElements. -root.modifyEventListener = false; - -// Add bulk *EventListener commands on NodeLists from querySelectorAll and others. -root.modifySelectors = false; - -// Event maintenance. -root.add = function(target, type, listener, configure) { - return eventManager(target, type, listener, configure, "add"); -}; - -root.remove = function(target, type, listener, configure) { - return eventManager(target, type, listener, configure, "remove"); -}; - -root.stop = function(event) { - if (event.stopPropagation) event.stopPropagation(); - event.cancelBubble = true; // <= IE8 - event.bubble = 0; -}; - -root.prevent = function(event) { - if (event.preventDefault) event.preventDefault(); - event.returnValue = false; // <= IE8 -}; - -root.cancel = function(event) { - root.stop(event); - root.prevent(event); -}; - -// Check whether event is natively supported (via @kangax) -root.supports = function (target, type) { - if (typeof(target) === "string") { - type = target; - target = window; - } - type = "on" + type; - if (type in target) return true; - if (!target.setAttribute) target = document.createElement("div"); - if (target.setAttribute && target.removeAttribute) { - target.setAttribute(type, ""); - var isSupported = typeof target[type] === "function"; - if (typeof target[type] !== "undefined") target[type] = null; - target.removeAttribute(type); - return isSupported; - } -}; - -var clone = function (obj) { - if (!obj || typeof (obj) !== 'object') return obj; - var temp = new obj.constructor(); - for (var key in obj) { - if (!obj[key] || typeof (obj[key]) !== 'object') { - temp[key] = obj[key]; - } else { // clone sub-object - temp[key] = clone(obj[key]); - } - } - return temp; -}; - -/// Handle custom *EventListener commands. -var eventManager = function(target, type, listener, configure, trigger, fromOverwrite) { - configure = configure || {}; - // Check for element to load on interval (before onload). - if (typeof(target) === "string" && type === "ready") { - var time = (new Date()).getTime(); - var timeout = configure.timeout; - var ms = configure.interval || 1000 / 60; - var interval = window.setInterval(function() { - if ((new Date()).getTime() - time > timeout) { - window.clearInterval(interval); - } - if (document.querySelector(target)) { - window.clearInterval(interval); - listener(); - } - }, ms); - return; - } - // Get DOM element from Query Selector. - if (typeof(target) === "string") { - target = document.querySelectorAll(target); - if (target.length === 0) return createError("Missing target on listener!"); // No results. - if (target.length === 1) { // Single target. - target = target[0]; - } - } - /// Handle multiple targets. - var event; - var events = {}; - if (target.length > 0) { - for (var n0 = 0, length0 = target.length; n0 < length0; n0 ++) { - event = eventManager(target[n0], type, listener, clone(configure), trigger); - if (event) events[n0] = event; - } - return createBatchCommands(events); - } - // Check for multiple events in one string. - if (type.indexOf && type.indexOf(" ") !== -1) type = type.split(" "); - if (type.indexOf && type.indexOf(",") !== -1) type = type.split(","); - // Attach or remove multiple events associated with a target. - if (typeof(type) !== "string") { // Has multiple events. - if (typeof(type.length) === "number") { // Handle multiple listeners glued together. - for (var n1 = 0, length1 = type.length; n1 < length1; n1 ++) { // Array [type] - event = eventManager(target, type[n1], listener, clone(configure), trigger); - if (event) events[type[n1]] = event; - } - } else { // Handle multiple listeners. - for (var key in type) { // Object {type} - if (typeof(type[key]) === "function") { // without configuration. - event = eventManager(target, key, type[key], clone(configure), trigger); - } else { // with configuration. - event = eventManager(target, key, type[key].listener, clone(type[key]), trigger); - } - if (event) events[key] = event; - } - } - return createBatchCommands(events); - } - // Ensure listener is a function. - if (typeof(listener) !== "function") return createError("Listener is not a function!"); - // Generate a unique wrapper identifier. - var useCapture = configure.useCapture || false; - var id = normalize(type) + getID(target) + "." + getID(listener) + "." + (useCapture ? 1 : 0); - // Handle the event. - if (root.Gesture && root.Gesture._gestureHandlers[type]) { // Fire custom event. - if (trigger === "remove") { // Remove event listener. - if (!wrappers[id]) return; // Already removed. - wrappers[id].remove(); - delete wrappers[id]; - } else if (trigger === "add") { // Attach event listener. - if (wrappers[id]) return wrappers[id]; // Already attached. - // Retains "this" orientation. - if (configure.useCall && !root.modifyEventListener) { - var tmp = listener; - listener = function(event, self) { - for (var key in self) event[key] = self[key]; - return tmp.call(target, event); - }; - } - // Create listener proxy. - configure.gesture = type; - configure.target = target; - configure.listener = listener; - configure.fromOverwrite = fromOverwrite; - // Record wrapper. - wrappers[id] = root.proxy[type](configure); - } - } else { // Fire native event. - type = normalize(type); - if (trigger === "remove") { // Remove event listener. - if (!wrappers[id]) return; // Already removed. - target[remove](type, listener, useCapture); - delete wrappers[id]; - } else if (trigger === "add") { // Attach event listener. - if (wrappers[id]) return wrappers[id]; // Already attached. - target[add](type, listener, useCapture); - // Record wrapper. - wrappers[id] = { - type: type, - target: target, - listener: listener, - remove: function() { - root.remove(target, type, listener, configure); - } - }; - } - } - return wrappers[id]; -}; - -/// Perform batch actions on multiple events. -var createBatchCommands = function(events) { - return { - remove: function() { // Remove multiple events. - for (var key in events) { - events[key].remove(); - } - }, - add: function() { // Add multiple events. - for (var key in events) { - events[key].add(); - } - } - }; -}; - -/// Display error message in console. -var createError = function(message) { - if (typeof(console) === "undefined") return; - if (typeof(console.error) === "undefined") return; - console.error(message); -}; - -/// Handle naming discrepancies between platforms. -var normalize = (function() { - var translate = {}; - return function(type) { - if (!root.pointerType) { - if (window.navigator.msPointerEnabled) { - root.pointerType = "mspointer"; - translate = { - "mousedown": "MSPointerDown", - "mousemove": "MSPointerMove", - "mouseup": "MSPointerUp" - }; - } else if (root.supports("touchstart")) { - root.pointerType = "touch"; - translate = { - "mousedown": "touchstart", - "mouseup": "touchend", - "mousemove": "touchmove" - }; - } else { - root.pointerType = "mouse"; - } - } - if (translate[type]) type = translate[type]; - if (!document.addEventListener) { // IE - return "on" + type; - } else { - return type; - } - }; -})(); - -/// Event wrappers to keep track of all events placed in the window. -var wrappers = {}; -var counter = 0; -var getID = function(object) { - if (object === window) return "#window"; - if (object === document) return "#document"; - if (!object) return createError("Missing target on listener!"); - if (!object.uniqueID) object.uniqueID = "id" + counter ++; - return object.uniqueID; -}; - -/// Detect platforms native *EventListener command. -var add = document.addEventListener ? "addEventListener" : "attachEvent"; -var remove = document.removeEventListener ? "removeEventListener" : "detachEvent"; - -/* - Pointer.js - ------------------------ - Modified from; https://github.com/borismus/pointer.js -*/ - -root.createPointerEvent = function (event, self, preventRecord) { - var eventName = self.gesture; - var target = self.target; - var pts = event.changedTouches || root.proxy.getCoords(event); - if (pts.length) { - var pt = pts[0]; - self.pointers = preventRecord ? [] : pts; - self.pageX = pt.pageX; - self.pageY = pt.pageY; - self.x = self.pageX; - self.y = self.pageY; - } - /// - var newEvent = document.createEvent("Event"); - newEvent.initEvent(eventName, true, true); - newEvent.originalEvent = event; - for (var k in self) newEvent[k] = self[k]; - target.dispatchEvent(newEvent); -}; - -/// Allows *EventListener to use custom event proxies. -if (root.modifyEventListener) (function() { - var augmentEventListener = function(proto) { - var recall = function(trigger) { // overwrite native *EventListener's - var handle = trigger + "EventListener"; - var handler = proto[handle]; - proto[handle] = function (type, listener, useCapture) { - if (root.Gesture && root.Gesture._gestureHandlers[type]) { // capture custom events. - var configure = useCapture; - if (typeof(useCapture) === "object") { - configure.useCall = true; - } else { // convert to configuration object. - configure = { - useCall: true, - useCapture: useCapture - }; - } - eventManager(this, type, listener, configure, trigger, true); - handler.call(this, type, listener, useCapture); - } else { // use native function. - handler.call(this, normalize(type), listener, useCapture); - } - }; - }; - recall("add"); - recall("remove"); - }; - // NOTE: overwriting HTMLElement doesn't do anything in Firefox. - if (navigator.userAgent.match(/Firefox/)) { - // TODO: fix Firefox for the general case. - augmentEventListener(HTMLDivElement.prototype); - augmentEventListener(HTMLCanvasElement.prototype); - } else { - augmentEventListener(HTMLElement.prototype); - } - augmentEventListener(document); - augmentEventListener(window); -})(); - -/// Allows querySelectorAll and other NodeLists to perform *EventListener commands in bulk. -if (root.modifySelectors) (function() { - var proto = NodeList.prototype; - proto.removeEventListener = function(type, listener, useCapture) { - for (var n = 0, length = this.length; n < length; n ++) { - this[n].removeEventListener(type, listener, useCapture); - } - }; - proto.addEventListener = function(type, listener, useCapture) { - for (var n = 0, length = this.length; n < length; n ++) { - this[n].addEventListener(type, listener, useCapture); - } - }; -})(); - -return root; - -})(Event); -/* - ---------------------------------------------------- - Event.proxy : 0.4.2 : 2012/07/29 : MIT License - ---------------------------------------------------- - https://github.com/mudcube/Event.js - ---------------------------------------------------- - Pointer Gestures - ---------------------------------------------------- - 1 : click, dblclick, dbltap - 1+ : tap, taphold, drag, swipe - 2+ : pinch, rotate - ---------------------------------------------------- - Gyroscope Gestures - ---------------------------------------------------- - * shake - ---------------------------------------------------- - Fixes issues with - ---------------------------------------------------- - * mousewheel-Firefox uses DOMMouseScroll and does not return wheelDelta. - * devicemotion-Fixes issue where event.acceleration is not returned. - ---------------------------------------------------- - Ideas for the future - ---------------------------------------------------- - * Keyboard, GamePad, and other input abstractions. - * Event batching - i.e. for every x fingers down a new gesture is created. -*/ - -if (typeof(Event) === "undefined") var Event = {}; -if (typeof(Event.proxy) === "undefined") Event.proxy = {}; - -Event.proxy = (function(root) { "use strict"; - -/* - Create a new pointer gesture instance. -*/ - -root.pointerSetup = function(conf, self) { - /// Configure. - conf.doc = conf.target.ownerDocument || conf.target; // Associated document. - conf.minFingers = conf.minFingers || conf.fingers || 1; // Minimum required fingers. - conf.maxFingers = conf.maxFingers || conf.fingers || Infinity; // Maximum allowed fingers. - conf.position = conf.position || "relative"; // Determines what coordinate system points are returned. - /// Convenience data. - self = self || {}; - self.gesture = conf.gesture; - self.target = conf.target; - self.pointerType = Event.pointerType; - /// - if (Event.modifyEventListener && conf.fromOverwrite) conf.listener = Event.createPointerEvent; - /// Convenience commands. - var fingers = 0; - var type = self.gesture.indexOf("pointer") === 0 && Event.modifyEventListener ? "pointer" : "mouse"; - self.proxy = function(listener) { - self.defaultListener = conf.listener; - conf.listener = listener; - listener(conf.event, self); - }; - self.remove = function() { - if (conf.onPointerDown) Event.remove(conf.target, type + "down", conf.onPointerDown); - if (conf.onPointerMove) Event.remove(conf.doc, type + "move", conf.onPointerMove); - if (conf.onPointerUp) Event.remove(conf.doc, type + "up", conf.onPointerUp); - }; - self.resume = function(opt) { - if (conf.onPointerMove && (!opt || opt.move)) Event.add(conf.doc, type + "move", conf.onPointerMove); - if (conf.onPointerUp && (!opt || opt.move)) Event.add(conf.doc, type + "up", conf.onPointerUp); - conf.fingers = fingers; - }; - self.pause = function(opt) { - fingers = conf.fingers; - if (conf.onPointerMove && (!opt || opt.move)) Event.remove(conf.doc, type + "move", conf.onPointerMove); - if (conf.onPointerUp && (!opt || opt.up)) Event.remove(conf.doc, type + "up", conf.onPointerUp); - conf.fingers = 0; - }; - /// - return self; -}; - -/* - Begin proxied pointer command. -*/ - -root.pointerStart = function(event, self, conf) { - var addTouchStart = function(touch, sid) { - var bbox = conf.bbox; - var pt = track[sid] = {}; - /// - switch(conf.position) { - case "absolute": // Absolute from within window. - pt.offsetX = 0; - pt.offsetY = 0; - break; - case "difference": // Relative from origin. - pt.offsetX = touch.pageX; - pt.offsetY = touch.pageY; - break; - case "move": // Move target element. - pt.offsetX = touch.pageX - bbox.x1; - pt.offsetY = touch.pageY - bbox.y1; - break; - default: // Relative from within target. - pt.offsetX = bbox.x1; - pt.offsetY = bbox.y1; - break; - } - /// - if (conf.position === "relative") { - var x = (touch.pageX + bbox.scrollLeft - pt.offsetX) * bbox.scaleX; - var y = (touch.pageY + bbox.scrollTop - pt.offsetY) * bbox.scaleY; - } else { - var x = (touch.pageX - pt.offsetX); - var y = (touch.pageY - pt.offsetY); - } - /// - pt.rotation = 0; - pt.scale = 1; - pt.startTime = pt.moveTime = (new Date).getTime(); - pt.move = { x: x, y: y }; - pt.start = { x: x, y: y }; - /// - conf.fingers ++; - }; - /// - conf.event = event; - if (self.defaultListener) { - conf.listener = self.defaultListener; - delete self.defaultListener; - } - /// - var isTouchStart = !conf.fingers; - var track = conf.tracker; - var touches = event.changedTouches || root.getCoords(event); - var length = touches.length; - // Adding touch events to tracking. - for (var i = 0; i < length; i ++) { - var touch = touches[i]; - var sid = touch.identifier || Infinity; // Touch ID. - // Track the current state of the touches. - if (conf.fingers) { - if (conf.fingers >= conf.maxFingers) { - var ids = []; - for (var sid in conf.tracker) ids.push(sid); - self.identifier = ids.join(","); - return isTouchStart; - } - var fingers = 0; // Finger ID. - for (var rid in track) { - // Replace removed finger. - if (track[rid].up) { - delete track[rid]; - addTouchStart(touch, sid); - conf.cancel = true; - break; - } - fingers ++; - } - // Add additional finger. - if (track[sid]) continue; - addTouchStart(touch, sid); - } else { // Start tracking fingers. - track = conf.tracker = {}; - self.bbox = conf.bbox = root.getBoundingBox(conf.target); - conf.fingers = 0; - conf.cancel = false; - addTouchStart(touch, sid); - } - } - /// - var ids = []; - for (var sid in conf.tracker) ids.push(sid); - self.identifier = ids.join(","); - /// - return isTouchStart; -}; - -/* - End proxied pointer command. -*/ - -root.pointerEnd = function(event, self, conf, onPointerUp) { - // Record changed touches have ended (iOS changedTouches is not reliable). - var touches = event.touches || []; - var length = touches.length; - var exists = {}; - for (var i = 0; i < length; i ++) { - var touch = touches[i]; - exists[touch.identifier || Infinity] = true; - } - for (var key in conf.tracker) { - var track = conf.tracker[key]; - if (!exists[key] && !track.up) { - if (onPointerUp) { // add changedTouches to mouse. - event.changedTouches = [{ - pageX: track.pageX, - pageY: track.pageY, - identifier: key === "Infinity" ? Infinity : key - }]; - onPointerUp(event, "up"); - } - conf.tracker[key].up = true; - conf.fingers --; - } - } -/* - // This should work but fails in Safari on iOS4 so not using it. - var touches = event.changedTouches || root.getCoords(event); - var length = touches.length; - // Record changed touches have ended (this should work). - for (var i = 0; i < length; i ++) { - var touch = touches[i]; - var sid = touch.identifier || Infinity; - if (conf.tracker[sid]) { - conf.tracker[sid].up = true; - conf.fingers --; - } - } -*/ - // Wait for all fingers to be released. - if (conf.fingers !== 0) return false; - // Record total number of fingers gesture used. - var ids = []; - conf.gestureFingers = 0; - for (var sid in conf.tracker) { - conf.gestureFingers ++; - ids.push(sid); - } - self.identifier = ids.join(","); - // Our pointer gesture has ended. - return true; -}; - -/* - Returns mouse coords in an array to match event.*Touches - ------------------------------------------------------------ - var touch = event.changedTouches || root.getCoords(event); -*/ - -root.getCoords = function(event) { - if (typeof(event.pageX) !== "undefined") { // Desktop browsers. - root.getCoords = function(event) { - return Array({ - type: "mouse", - x: event.pageX, - y: event.pageY, - pageX: event.pageX, - pageY: event.pageY, - identifier: Infinity - }); - }; - } else { // Internet Explorer <= 8.0 - root.getCoords = function(event) { - event = event || window.event; - return Array({ - type: "mouse", - x: event.clientX + document.documentElement.scrollLeft, - y: event.clientY + document.documentElement.scrollTop, - pageX: event.clientX + document.documentElement.scrollLeft, - pageY: event.clientY + document.documentElement.scrollTop, - identifier: Infinity - }); - }; - } - return root.getCoords(event); -}; - -/* - Returns single coords in an object. - ------------------------------------------------------------ - var mouse = root.getCoord(event); -*/ - -root.getCoord = function(event) { - if ("ontouchstart" in window) { // Mobile browsers. - var pX = 0; - var pY = 0; - root.getCoord = function(event) { - var touches = event.changedTouches; - if (touches.length) { // ontouchstart + ontouchmove - return { - x: pX = touches[0].pageX, - y: pY = touches[0].pageY - }; - } else { // ontouchend - return { - x: pX, - y: pY - }; - } - }; - } else if(typeof(event.pageX) !== "undefined" && typeof(event.pageY) !== "undefined") { // Desktop browsers. - root.getCoord = function(event) { - return { - x: event.pageX, - y: event.pageY - }; - }; - } else { // Internet Explorer <=8.0 - root.getCoord = function(event) { - event = event || window.event; - return { - x: event.clientX + document.documentElement.scrollLeft, - y: event.clientY + document.documentElement.scrollTop - }; - }; - } - return root.getCoord(event); -}; - -/* - Get target scale and position in space. -*/ - -root.getBoundingBox = function(o) { - if (o === window || o === document) o = document.body; - /// - var bbox = { - x1: 0, - y1: 0, - x2: 0, - y2: 0, - scrollLeft: 0, - scrollTop: 0 - }; - /// - if (o === document.body) { - bbox.height = window.innerHeight; - bbox.width = window.innerWidth; - } else { - bbox.height = o.offsetHeight; - bbox.width = o.offsetWidth; - } - /// Get the scale of the element. - bbox.scaleX = o.width / bbox.width || 1; - bbox.scaleY = o.height / bbox.height || 1; - /// Get the offset of element. - var tmp = o; - while (tmp !== null) { - bbox.x1 += tmp.offsetLeft; - bbox.y1 += tmp.offsetTop; - tmp = tmp.offsetParent; - }; - /// Get the scroll of container element. - var tmp = o.parentNode; - while (tmp !== null) { - if (tmp === document.body) break; - if (tmp.scrollTop === undefined) break; - bbox.scrollLeft += tmp.scrollLeft; - bbox.scrollTop += tmp.scrollTop; - tmp = tmp.parentNode; - }; - /// Record the extent of box. - bbox.x2 = bbox.x1 + bbox.width; - bbox.y2 = bbox.y1 + bbox.height; - /// - return bbox; -}; - -/* - Keep track of metaKey, the proper ctrlKey for users platform. -*/ - -(function() { - var agent = navigator.userAgent.toLowerCase(); - var mac = agent.indexOf("macintosh") !== -1; - if (mac && agent.indexOf("khtml") !== -1) { // chrome, safari. - var watch = { 91: true, 93: true }; - } else if (mac && agent.indexOf("firefox") !== -1) { // mac firefox. - var watch = { 224: true }; - } else { // windows, linux, or mac opera. - var watch = { 17: true }; - } - root.isMetaKey = function(event) { - return !!watch[event.keyCode]; - }; - root.metaTracker = function(event) { - if (watch[event.keyCode]) { - root.metaKey = event.type === "keydown"; - } - }; -})(); - -return root; - -})(Event.proxy); -/* - "Click" event proxy. - ---------------------------------------------------- - Event.add(window, "click", function(event, self) {}); -*/ - -if (typeof(Event) === "undefined") var Event = {}; -if (typeof(Event.proxy) === "undefined") Event.proxy = {}; - -Event.proxy = (function(root) { "use strict"; - -root.click = function(conf) { - conf.maxFingers = conf.maxFingers || conf.fingers || 1; - // Setting up local variables. - var EVENT; - // Tracking the events. - conf.onPointerDown = function (event) { - if (root.pointerStart(event, self, conf)) { - Event.add(conf.doc, "mousemove", conf.onPointerMove).listener(event); - Event.add(conf.doc, "mouseup", conf.onPointerUp); - } - }; - conf.onPointerMove = function (event) { - EVENT = event; - }; - conf.onPointerUp = function(event) { - if (root.pointerEnd(event, self, conf)) { - Event.remove(conf.doc, "mousemove", conf.onPointerMove); - Event.remove(conf.doc, "mouseup", conf.onPointerUp); - if (EVENT.cancelBubble && ++ EVENT.bubble > 1) return; - var pointers = EVENT.changedTouches || root.getCoords(EVENT); - var pointer = pointers[0]; - var bbox = conf.bbox; - var newbbox = root.getBoundingBox(conf.target); - if (conf.position === "relative") { - var ax = (pointer.pageX + bbox.scrollLeft - bbox.x1) * bbox.scaleX; - var ay = (pointer.pageY + bbox.scrollTop - bbox.y1) * bbox.scaleY; - } else { - var ax = (pointer.pageX - bbox.x1); - var ay = (pointer.pageY - bbox.y1); - } - if (ax > 0 && ax < bbox.width && // Within target coordinates. - ay > 0 && ay < bbox.height && - bbox.scrollTop === newbbox.scrollTop) { - conf.listener(EVENT, self); - } - } - }; - // Generate maintenance commands, and other configurations. - var self = root.pointerSetup(conf); - self.state = "click"; - // Attach events. - Event.add(conf.target, "mousedown", conf.onPointerDown); - // Return this object. - return self; -}; - -Event.Gesture = Event.Gesture || {}; -Event.Gesture._gestureHandlers = Event.Gesture._gestureHandlers || {}; -Event.Gesture._gestureHandlers.click = root.click; - -return root; - -})(Event.proxy); -/* - "Double-Click" aka "Double-Tap" event proxy. - ---------------------------------------------------- - Event.add(window, "dblclick", function(event, self) {}); - ---------------------------------------------------- - Touch an target twice for <= 700ms, with less than 25 pixel drift. -*/ - -if (typeof(Event) === "undefined") var Event = {}; -if (typeof(Event.proxy) === "undefined") Event.proxy = {}; - -Event.proxy = (function(root) { "use strict"; - -root.dbltap = -root.dblclick = function(conf) { - conf.maxFingers = conf.maxFingers || conf.fingers || 1; - // Setting up local variables. - var delay = 700; // in milliseconds - var time0, time1, timeout; - var pointer0, pointer1; - // Tracking the events. - conf.onPointerDown = function (event) { - var pointers = event.changedTouches || root.getCoords(event); - if (time0 && !time1) { // Click #2 - pointer1 = pointers[0]; - time1 = (new Date).getTime() - time0; - } else { // Click #1 - pointer0 = pointers[0]; - time0 = (new Date).getTime(); - time1 = 0; - clearTimeout(timeout); - timeout = setTimeout(function() { - time0 = 0; - }, delay); - } - if (root.pointerStart(event, self, conf)) { - Event.add(conf.doc, "mousemove", conf.onPointerMove).listener(event); - Event.add(conf.doc, "mouseup", conf.onPointerUp); - } - }; - conf.onPointerMove = function (event) { - if (time0 && !time1) { - var pointers = event.changedTouches || root.getCoords(event); - pointer1 = pointers[0]; - } - var bbox = conf.bbox; - if (conf.position === "relative") { - var ax = (pointer1.pageX + bbox.scrollLeft - bbox.x1) * bbox.scaleX; - var ay = (pointer1.pageY + bbox.scrollTop - bbox.y1) * bbox.scaleY; - } else { - var ax = (pointer1.pageX - bbox.x1); - var ay = (pointer1.pageY - bbox.y1); - } - if (!(ax > 0 && ax < bbox.width && // Within target coordinates.. - ay > 0 && ay < bbox.height && - Math.abs(pointer1.pageX - pointer0.pageX) <= 25 && // Within drift deviance. - Math.abs(pointer1.pageY - pointer0.pageY) <= 25)) { - // Cancel out this listener. - Event.remove(conf.doc, "mousemove", conf.onPointerMove); - clearTimeout(timeout); - time0 = time1 = 0; - } - }; - conf.onPointerUp = function(event) { - if (root.pointerEnd(event, self, conf)) { - Event.remove(conf.doc, "mousemove", conf.onPointerMove); - Event.remove(conf.doc, "mouseup", conf.onPointerUp); - } - if (time0 && time1) { - if (time1 <= delay && !(event.cancelBubble && ++event.bubble > 1)) { - self.state = conf.gesture; - conf.listener(event, self); - } - clearTimeout(timeout); - time0 = time1 = 0; - } - }; - // Generate maintenance commands, and other configurations. - var self = root.pointerSetup(conf); - self.state = "dblclick"; - // Attach events. - Event.add(conf.target, "mousedown", conf.onPointerDown); - // Return this object. - return self; -}; - -Event.Gesture = Event.Gesture || {}; -Event.Gesture._gestureHandlers = Event.Gesture._gestureHandlers || {}; -Event.Gesture._gestureHandlers.dbltap = root.dbltap; -Event.Gesture._gestureHandlers.dblclick = root.dblclick; - -return root; - -})(Event.proxy); -/* - "Drag" event proxy (1+ fingers). - ---------------------------------------------------- - CONFIGURE: maxFingers, position. - ---------------------------------------------------- - Event.add(window, "drag", function(event, self) { - console.log(self.gesture, self.state, self.start, self.x, self.y, self.bbox); - }); -*/ - -if (typeof(Event) === "undefined") var Event = {}; -if (typeof(Event.proxy) === "undefined") Event.proxy = {}; - -Event.proxy = (function(root) { "use strict"; - -root.dragElement = function(that, event) { - root.drag({ - event: event, - target: that, - position: "move", - listener: function(event, self) { - that.style.left = self.x + "px"; - that.style.top = self.y + "px"; - } - }); -}; - -root.drag = function(conf) { - conf.gesture = "drag"; - conf.onPointerDown = function (event) { - if (root.pointerStart(event, self, conf)) { - Event.add(conf.doc, "mousemove", conf.onPointerMove); - Event.add(conf.doc, "mouseup", conf.onPointerUp); - } - // Process event listener. - conf.onPointerMove(event, "down"); - }; - conf.onPointerMove = function (event, state) { - var bbox = conf.bbox; - var touches = event.changedTouches || root.getCoords(event); - var length = touches.length; - for (var i = 0; i < length; i ++) { - var touch = touches[i]; - var identifier = touch.identifier || Infinity; - var pt = conf.tracker[identifier]; - // Identifier defined outside of listener. - if (!pt) continue; - pt.pageX = touch.pageX; - pt.pageY = touch.pageY; - // Record data. - self.state = state || "move"; - self.identifier = identifier; - self.start = pt.start; - self.fingers = 1; // TODO(mud): option to track as single set, or individually. - if (conf.position === "relative") { - self.x = (pt.pageX + bbox.scrollLeft - pt.offsetX) * bbox.scaleX; - self.y = (pt.pageY + bbox.scrollTop - pt.offsetY) * bbox.scaleY; - } else { - self.x = (pt.pageX - pt.offsetX); - self.y = (pt.pageY - pt.offsetY); - } - /// - conf.listener(event, self); - } - }; - conf.onPointerUp = function(event) { - // Remove tracking for touch. - if (root.pointerEnd(event, self, conf, conf.onPointerMove)) { - Event.remove(conf.doc, "mousemove", conf.onPointerMove); - Event.remove(conf.doc, "mouseup", conf.onPointerUp); - } - }; - // Generate maintenance commands, and other configurations. - var self = root.pointerSetup(conf); - // Attach events. - if (conf.event) { - conf.onPointerDown(conf.event); - } else { - Event.add(conf.target, "mousedown", conf.onPointerDown); - } - // Return this object. - return self; -}; - -Event.Gesture = Event.Gesture || {}; -Event.Gesture._gestureHandlers = Event.Gesture._gestureHandlers || {}; -Event.Gesture._gestureHandlers.drag = root.drag; - -return root; - -})(Event.proxy); -/* - "Gesture" event proxy (2+ fingers). - ---------------------------------------------------- - CONFIGURE: minFingers, maxFingers. - ---------------------------------------------------- - Event.add(window, "gesture", function(event, self) { - console.log(self.rotation, self.scale, self.fingers, self.state); - }); -*/ - -if (typeof(Event) === "undefined") var Event = {}; -if (typeof(Event.proxy) === "undefined") Event.proxy = {}; - -Event.proxy = (function(root) { "use strict"; - -var RAD_DEG = Math.PI / 180; - -root.gesture = function(conf) { - conf.minFingers = conf.minFingers || conf.fingers || 2; - // Tracking the events. - conf.onPointerDown = function (event) { - var fingers = conf.fingers; - if (root.pointerStart(event, self, conf)) { - Event.add(conf.doc, "mousemove", conf.onPointerMove); - Event.add(conf.doc, "mouseup", conf.onPointerUp); - } - // Record gesture start. - if (conf.fingers === conf.minFingers && fingers !== conf.fingers) { - self.fingers = conf.minFingers; - self.scale = 1; - self.rotation = 0; - self.state = "start"; - var sids = ""; //- FIXME(mud): can generate duplicate IDs. - for (var key in conf.tracker) sids += key; - self.identifier = parseInt(sids); - conf.listener(event, self); - } - }; - /// - conf.onPointerMove = function (event, state) { - var bbox = conf.bbox; - var points = conf.tracker; - var touches = event.changedTouches || root.getCoords(event); - var length = touches.length; - // Update tracker coordinates. - for (var i = 0; i < length; i ++) { - var touch = touches[i]; - var sid = touch.identifier || Infinity; - var pt = points[sid]; - // Check whether "pt" is used by another gesture. - if (!pt) continue; - // Find the actual coordinates. - if (conf.position === "relative") { - pt.move.x = (touch.pageX + bbox.scrollLeft - bbox.x1) * bbox.scaleX; - pt.move.y = (touch.pageY + bbox.scrollTop - bbox.y1) * bbox.scaleY; - } else { - pt.move.x = (touch.pageX - bbox.x1); - pt.move.y = (touch.pageY - bbox.y1); - } - } - /// - if (conf.fingers < conf.minFingers) return; - /// - var touches = []; - var scale = 0; - var rotation = 0; - /// Calculate centroid of gesture. - var centroidx = 0; - var centroidy = 0; - var length = 0; - for (var sid in points) { - var touch = points[sid]; - if (touch.up) continue; - centroidx += touch.move.x; - centroidy += touch.move.y; - length ++; - } - centroidx /= length; - centroidy /= length; - /// - for (var sid in points) { - var touch = points[sid]; - if (touch.up) continue; - var start = touch.start; - if (!start.distance) { - var dx = start.x - centroidx; - var dy = start.y - centroidy; - start.distance = Math.sqrt(dx * dx + dy * dy); - start.angle = Math.atan2(dx, dy) / RAD_DEG; - } - // Calculate scale. - var dx = touch.move.x - centroidx; - var dy = touch.move.y - centroidy; - var distance = Math.sqrt(dx * dx + dy * dy); - scale += distance / start.distance; - // Calculate rotation. - var angle = Math.atan2(dx, dy) / RAD_DEG; - var rotate = (start.angle - angle + 360) % 360 - 180; - touch.DEG2 = touch.DEG1; // Previous degree. - touch.DEG1 = rotate > 0 ? rotate : -rotate; // Current degree. - if (typeof(touch.DEG2) !== "undefined") { - if (rotate > 0) { - touch.rotation += touch.DEG1 - touch.DEG2; - } else { - touch.rotation -= touch.DEG1 - touch.DEG2; - } - rotation += touch.rotation; - } - // Attach current points to self. - touches.push(touch.move); - } - /// - self.touches = touches; - self.fingers = conf.fingers; - self.scale = scale / conf.fingers; - self.rotation = rotation / conf.fingers; - self.state = "change"; - conf.listener(event, self); - }; - conf.onPointerUp = function(event) { - // Remove tracking for touch. - var fingers = conf.fingers; - if (root.pointerEnd(event, self, conf)) { - Event.remove(conf.doc, "mousemove", conf.onPointerMove); - Event.remove(conf.doc, "mouseup", conf.onPointerUp); - } - // Check whether fingers has dropped below minFingers. - if (fingers === conf.minFingers && conf.fingers < conf.minFingers) { - self.fingers = conf.fingers; - self.state = "end"; - conf.listener(event, self); - } - }; - // Generate maintenance commands, and other configurations. - var self = root.pointerSetup(conf); - // Attach events. - Event.add(conf.target, "mousedown", conf.onPointerDown); - // Return this object. - return self; -}; - -Event.Gesture = Event.Gesture || {}; -Event.Gesture._gestureHandlers = Event.Gesture._gestureHandlers || {}; -Event.Gesture._gestureHandlers.gesture = root.gesture; - -return root; - -})(Event.proxy); -/* - "Pointer" event proxy (1+ fingers). - ---------------------------------------------------- - CONFIGURE: minFingers, maxFingers. - ---------------------------------------------------- - Event.add(window, "gesture", function(event, self) { - console.log(self.rotation, self.scale, self.fingers, self.state); - }); -*/ - -if (typeof(Event) === "undefined") var Event = {}; -if (typeof(Event.proxy) === "undefined") Event.proxy = {}; - -Event.proxy = (function(root) { "use strict"; - -root.pointerdown = -root.pointermove = -root.pointerup = function(conf) { - if (conf.target.isPointerEmitter) return; - // Tracking the events. - var isDown = true; - conf.onPointerDown = function (event) { - isDown = false; - self.gesture = "pointerdown"; - conf.listener(event, self); - }; - conf.onPointerMove = function (event) { - self.gesture = "pointermove"; - conf.listener(event, self, isDown); - }; - conf.onPointerUp = function (event) { - isDown = true; - self.gesture = "pointerup"; - conf.listener(event, self, true); - }; - // Generate maintenance commands, and other configurations. - var self = root.pointerSetup(conf); - // Attach events. - Event.add(conf.target, "mousedown", conf.onPointerDown); - Event.add(conf.target, "mousemove", conf.onPointerMove); - Event.add(conf.doc, "mouseup", conf.onPointerUp); - // Return this object. - conf.target.isPointerEmitter = true; - return self; -}; - -Event.Gesture = Event.Gesture || {}; -Event.Gesture._gestureHandlers = Event.Gesture._gestureHandlers || {}; -Event.Gesture._gestureHandlers.pointerdown = root.pointerdown; -Event.Gesture._gestureHandlers.pointermove = root.pointermove; -Event.Gesture._gestureHandlers.pointerup = root.pointerup; - -return root; - -})(Event.proxy); -/* - "Device Motion" and "Shake" event proxy. - ---------------------------------------------------- - http://developer.android.com/reference/android/hardware/SensorEvent.html#values - ---------------------------------------------------- - Event.add(window, "shake", function(event, self) {}); - Event.add(window, "devicemotion", function(event, self) { - console.log(self.acceleration, self.accelerationIncludingGravity); - }); -*/ - -if (typeof(Event) === "undefined") var Event = {}; -if (typeof(Event.proxy) === "undefined") Event.proxy = {}; - -Event.proxy = (function(root) { "use strict"; - -root.shake = function(conf) { - // Externally accessible data. - var self = { - gesture: "devicemotion", - acceleration: {}, - accelerationIncludingGravity: {}, - target: conf.target, - listener: conf.listener, - remove: function() { - window.removeEventListener('devicemotion', onDeviceMotion, false); - } - }; - // Setting up local variables. - var threshold = 4; // Gravitational threshold. - var timeout = 1000; // Timeout between shake events. - var timeframe = 200; // Time between shakes. - var shakes = 3; // Minimum shakes to trigger event. - var lastShake = (new Date).getTime(); - var gravity = { x: 0, y: 0, z: 0 }; - var delta = { - x: { count: 0, value: 0 }, - y: { count: 0, value: 0 }, - z: { count: 0, value: 0 } - }; - // Tracking the events. - var onDeviceMotion = function(e) { - var alpha = 0.8; // Low pass filter. - var o = e.accelerationIncludingGravity; - gravity.x = alpha * gravity.x + (1 - alpha) * o.x; - gravity.y = alpha * gravity.y + (1 - alpha) * o.y; - gravity.z = alpha * gravity.z + (1 - alpha) * o.z; - self.accelerationIncludingGravity = gravity; - self.acceleration.x = o.x - gravity.x; - self.acceleration.y = o.y - gravity.y; - self.acceleration.z = o.z - gravity.z; - /// - if (conf.gesture === "devicemotion") { - conf.listener(e, self); - return; - } - var data = "xyz"; - var now = (new Date).getTime(); - for (var n = 0, length = data.length; n < length; n ++) { - var letter = data[n]; - var ACCELERATION = self.acceleration[letter]; - var DELTA = delta[letter]; - var abs = Math.abs(ACCELERATION); - /// Check whether another shake event was recently registered. - if (now - lastShake < timeout) continue; - /// Check whether delta surpasses threshold. - if (abs > threshold) { - var idx = now * ACCELERATION / abs; - var span = Math.abs(idx + DELTA.value); - // Check whether last delta was registered within timeframe. - if (DELTA.value && span < timeframe) { - DELTA.value = idx; - DELTA.count ++; - // Check whether delta count has enough shakes. - if (DELTA.count === shakes) { - conf.listener(e, self); - // Reset tracking. - lastShake = now; - DELTA.value = 0; - DELTA.count = 0; - } - } else { - // Track first shake. - DELTA.value = idx; - DELTA.count = 1; - } - } - } - }; - // Attach events. - if (!window.addEventListener) return; - window.addEventListener('devicemotion', onDeviceMotion, false); - // Return this object. - return self; -}; - -Event.Gesture = Event.Gesture || {}; -Event.Gesture._gestureHandlers = Event.Gesture._gestureHandlers || {}; -Event.Gesture._gestureHandlers.shake = root.shake; - -return root; - -})(Event.proxy); -/* - "Swipe" event proxy (1+ fingers). - ---------------------------------------------------- - CONFIGURE: snap, threshold, maxFingers. - ---------------------------------------------------- - Event.add(window, "swipe", function(event, self) { - console.log(self.velocity, self.angle); - }); -*/ - -if (typeof(Event) === "undefined") var Event = {}; -if (typeof(Event.proxy) === "undefined") Event.proxy = {}; - -Event.proxy = (function(root) { "use strict"; - -var RAD_DEG = Math.PI / 180; - -root.swipe = function(conf) { - conf.snap = conf.snap || 90; // angle snap. - conf.threshold = conf.threshold || 1; // velocity threshold. - // Tracking the events. - conf.onPointerDown = function (event) { - if (root.pointerStart(event, self, conf)) { - Event.add(conf.doc, "mousemove", conf.onPointerMove).listener(event); - Event.add(conf.doc, "mouseup", conf.onPointerUp); - } - }; - conf.onPointerMove = function (event) { - var touches = event.changedTouches || root.getCoords(event); - var length = touches.length; - for (var i = 0; i < length; i ++) { - var touch = touches[i]; - var sid = touch.identifier || Infinity; - var o = conf.tracker[sid]; - // Identifier defined outside of listener. - if (!o) continue; - o.move.x = touch.pageX; - o.move.y = touch.pageY; - o.moveTime = (new Date).getTime(); - } - }; - conf.onPointerUp = function(event) { - if (root.pointerEnd(event, self, conf)) { - Event.remove(conf.doc, "mousemove", conf.onPointerMove); - Event.remove(conf.doc, "mouseup", conf.onPointerUp); - /// - var velocity1; - var velocity2 - var degree1; - var degree2; - /// Calculate centroid of gesture. - var start = { x: 0, y: 0 }; - var endx = 0; - var endy = 0; - var length = 0; - /// - for (var sid in conf.tracker) { - var touch = conf.tracker[sid]; - var xdist = touch.move.x - touch.start.x; - var ydist = touch.move.y - touch.start.y; - - endx += touch.move.x; - endy += touch.move.y; - start.x += touch.start.x; - start.y += touch.start.y; - length ++; - - - var distance = Math.sqrt(xdist * xdist + ydist * ydist); - var ms = touch.moveTime - touch.startTime; - var degree2 = Math.atan2(xdist, ydist) / RAD_DEG + 180; - var velocity2 = ms ? distance / ms : 0; - if (typeof(degree1) === "undefined") { - degree1 = degree2; - velocity1 = velocity2; - } else if (Math.abs(degree2 - degree1) <= 20) { - degree1 = (degree1 + degree2) / 2; - velocity1 = (velocity1 + velocity2) / 2; - } else { - return; - } - } - /// - if (velocity1 > conf.threshold) { - start.x /= length; - start.y /= length; - self.start = start; - self.x = endx / length; - self.y = endy / length; - self.angle = -((((degree1 / conf.snap + 0.5) >> 0) * conf.snap || 360) - 360); - self.velocity = velocity1; - self.fingers = conf.gestureFingers; - self.state = "swipe"; - conf.listener(event, self); - } - } - }; - // Generate maintenance commands, and other configurations. - var self = root.pointerSetup(conf); - // Attach events. - Event.add(conf.target, "mousedown", conf.onPointerDown); - // Return this object. - return self; -}; - -Event.Gesture = Event.Gesture || {}; -Event.Gesture._gestureHandlers = Event.Gesture._gestureHandlers || {}; -Event.Gesture._gestureHandlers.swipe = root.swipe; - -return root; - -})(Event.proxy); -/* - "Tap" and "Longpress" event proxy. - ---------------------------------------------------- - CONFIGURE: delay (longpress), timeout (tap). - ---------------------------------------------------- - Event.add(window, "tap", function(event, self) { - console.log(self.fingers); - }); - ---------------------------------------------------- - multi-finger tap // touch an target for <= 250ms. - multi-finger longpress // touch an target for >= 500ms -*/ - -if (typeof(Event) === "undefined") var Event = {}; -if (typeof(Event.proxy) === "undefined") Event.proxy = {}; - -Event.proxy = (function(root) { "use strict"; - -root.tap = -root.longpress = function(conf) { - conf.delay = conf.delay || 500; - conf.timeout = conf.timeout || 250; - // Setting up local variables. - var timestamp, timeout; - // Tracking the events. - conf.onPointerDown = function (event) { - if (root.pointerStart(event, self, conf)) { - timestamp = (new Date).getTime(); - // Initialize event listeners. - Event.add(conf.doc, "mousemove", conf.onPointerMove).listener(event); - Event.add(conf.doc, "mouseup", conf.onPointerUp); - // Make sure this is a "longpress" event. - if (conf.gesture !== "longpress") return; - timeout = setTimeout(function() { - if (event.cancelBubble && ++event.bubble > 1) return; - // Make sure no fingers have been changed. - var fingers = 0; - for (var key in conf.tracker) { - if (conf.tracker[key].end === true) return; - if (conf.cancel) return; - fingers ++; - } - // Send callback. - self.state = "start"; - self.fingers = fingers; - conf.listener(event, self); - }, conf.delay); - } - }; - conf.onPointerMove = function (event) { - var bbox = conf.bbox; - var touches = event.changedTouches || root.getCoords(event); - var length = touches.length; - for (var i = 0; i < length; i ++) { - var touch = touches[i]; - var identifier = touch.identifier || Infinity; - var pt = conf.tracker[identifier]; - if (!pt) continue; - if (conf.position === "relative") { - var x = (touch.pageX + bbox.scrollLeft - bbox.x1) * bbox.scaleX; - var y = (touch.pageY + bbox.scrollTop - bbox.y1) * bbox.scaleY; - } else { - var x = (touch.pageX - bbox.x1); - var y = (touch.pageY - bbox.y1); - } - if (!(x > 0 && x < bbox.width && // Within target coordinates.. - y > 0 && y < bbox.height && - Math.abs(x - pt.start.x) <= 25 && // Within drift deviance. - Math.abs(y - pt.start.y) <= 25)) { - // Cancel out this listener. - Event.remove(conf.doc, "mousemove", conf.onPointerMove); - conf.cancel = true; - return; - } - } - }; - conf.onPointerUp = function(event) { - if (root.pointerEnd(event, self, conf)) { - clearTimeout(timeout); - Event.remove(conf.doc, "mousemove", conf.onPointerMove); - Event.remove(conf.doc, "mouseup", conf.onPointerUp); - if (event.cancelBubble && ++event.bubble > 1) return; - // Callback release on longpress. - if (conf.gesture === "longpress") { - if (self.state === "start") { - self.state = "end"; - conf.listener(event, self); - } - return; - } - // Cancel event due to movement. - if (conf.cancel) return; - // Ensure delay is within margins. - if ((new Date).getTime() - timestamp > conf.timeout) return; - // Send callback. - self.state = "tap"; - self.fingers = conf.gestureFingers; - conf.listener(event, self); - } - }; - // Generate maintenance commands, and other configurations. - var self = root.pointerSetup(conf); - // Attach events. - Event.add(conf.target, "mousedown", conf.onPointerDown); - // Return this object. - return self; -}; - -Event.Gesture = Event.Gesture || {}; -Event.Gesture._gestureHandlers = Event.Gesture._gestureHandlers || {}; -Event.Gesture._gestureHandlers.tap = root.tap; -Event.Gesture._gestureHandlers.longpress = root.longpress; - -return root; - -})(Event.proxy); -/* - "Mouse Wheel" event proxy. - ---------------------------------------------------- - Event.add(window, "wheel", function(event, self) { - console.log(self.state, self.wheelDelta); - }); -*/ - -if (typeof(Event) === "undefined") var Event = {}; -if (typeof(Event.proxy) === "undefined") Event.proxy = {}; - -Event.proxy = (function(root) { "use strict"; - -root.wheel = function(conf) { - // Configure event listener. - var interval; - var timeout = conf.timeout || 150; - var count = 0; - // Externally accessible data. - var self = { - gesture: "wheel", - state: "start", - wheelDelta: 0, - target: conf.target, - listener: conf.listener, - remove: function() { - conf.target[remove](type, onMouseWheel, false); - } - }; - // Tracking the events. - var onMouseWheel = function(event) { - event = event || window.event; - self.state = count++ ? "change" : "start"; - self.wheelDelta = event.detail ? event.detail * -20 : event.wheelDelta; - conf.listener(event, self); - clearTimeout(interval); - interval = setTimeout(function() { - count = 0; - self.state = "end"; - self.wheelDelta = 0; - conf.listener(event, self); - }, timeout); - }; - // Attach events. - var add = document.addEventListener ? "addEventListener" : "attachEvent"; - var remove = document.removeEventListener ? "removeEventListener" : "detachEvent"; - var type = Event.supports("mousewheel") ? "mousewheel" : "DOMMouseScroll"; - conf.target[add](type, onMouseWheel, false); - // Return this object. - return self; -}; - -Event.Gesture = Event.Gesture || {}; -Event.Gesture._gestureHandlers = Event.Gesture._gestureHandlers || {}; -Event.Gesture._gestureHandlers.wheel = root.wheel; - -return root; - -})(Event.proxy); \ No newline at end of file +})(); \ No newline at end of file diff --git a/build/MIDI.min.js b/build/MIDI.min.js index ea67fc2..aea1fe3 100644 --- a/build/MIDI.min.js +++ b/build/MIDI.min.js @@ -1 +1 @@ -if(typeof Color=="undefined")var Color={};typeof Color.Space=="undefined"&&(Color.Space={}),function(){"use strict";var useEval=!1,functions={},shortcuts={"HEX24>HSL":"HEX24>RGB>HSL","HEX32>HSLA":"HEX32>RGBA>HSLA","HEX24>CMYK":"HEX24>RGB>CMY>CMYK","RGB>CMYK":"RGB>CMY>CMYK"},root=Color.Space=function(color,route){shortcuts[route]&&(route=shortcuts[route]);var r=route.split(">");if(typeof color=="object"&&color[0]>=0){var type=r[0],tmp={};for(var i=0;i1&&(key=key.substr(key.indexOf("_")+1)),key+=(pos===0?"":"_")+r[pos],color=root[key](color),useEval&&(f="Color.Space."+key+"("+f+")");return useEval&&(functions[route]=eval("(function(color) { return "+f+" })")),color};root.RGB_W3=function(e){return"rgb("+(e.R>>0)+","+(e.G>>0)+","+(e.B>>0)+")"},root.RGBA_W3=function(e){var t=typeof e.A=="number"?e.A/255:1;return"rgba("+(e.R>>0)+","+(e.G>>0)+","+(e.B>>0)+","+t+")"},root.W3_RGB=function(e){var e=e.substr(4,e.length-5).split(",");return{R:parseInt(e[0]),G:parseInt(e[1]),B:parseInt(e[2])}},root.W3_RGBA=function(e){var e=e.substr(5,e.length-6).split(",");return{R:parseInt(e[0]),G:parseInt(e[1]),B:parseInt(e[2]),A:parseFloat(e[3])*255}},root.HSL_W3=function(e){return"hsl("+(e.H+.5>>0)+","+(e.S+.5>>0)+"%,"+(e.L+.5>>0)+"%)"},root.HSLA_W3=function(e){var t=typeof e.A=="number"?e.A/255:1;return"hsla("+(e.H+.5>>0)+","+(e.S+.5>>0)+"%,"+(e.L+.5>>0)+"%,"+t+")"},root.W3_HSL=function(e){var e=e.substr(4,e.length-5).split(",");return{H:parseInt(e[0]),S:parseInt(e[1]),L:parseInt(e[2])}},root.W3_HSLA=function(e){var e=e.substr(5,e.length-6).split(",");return{H:parseInt(e[0]),S:parseInt(e[1]),L:parseInt(e[2]),A:parseFloat(e[3])*255}},root.W3_HEX=root.W3_HEX24=function(e){return e.substr(0,1)==="#"&&(e=e.substr(1)),e.length===3&&(e=e[0]+e[0]+e[1]+e[1]+e[2]+e[2]),parseInt("0x"+e)},root.W3_HEX32=function(e){return e.substr(0,1)==="#"&&(e=e.substr(1)),e.length===6?parseInt("0xFF"+e):parseInt("0x"+e)},root.HEX_W3=root.HEX24_W3=function(e,t){t||(t=6),e||(e=0);var n=e.toString(16),r=n.length;while(rt)n=n.substr(1),r--;return"#"+n},root.HEX32_W3=function(e){return root.HEX_W3(e,8)},root.HEX_RGB=root.HEX24_RGB=function(e){return{R:e>>16,G:e>>8&255,B:e&255}},root.HEX32_RGBA=function(e){return{R:e>>>16&255,G:e>>>8&255,B:e&255,A:e>>>24}},root.RGBA_HEX32=function(e){return(e.A<<24|e.R<<16|e.G<<8|e.B)>>>0},root.RGB_HEX24=root.RGB_HEX=function(e){return e.R<0&&(e.R=0),e.G<0&&(e.G=0),e.B<0&&(e.B=0),e.R>255&&(e.R=255),e.G>255&&(e.G=255),e.B>255&&(e.B=255),e.R<<16|e.G<<8|e.B},root.RGB_CMY=function(e){return{C:1-e.R/255,M:1-e.G/255,Y:1-e.B/255}},root.RGBA_HSLA=root.RGB_HSL=function(e){var t=e.R/255,n=e.G/255,r=e.B/255,i=Math.min(t,n,r),s=Math.max(t,n,r),o=s-i,u,a,f=(s+i)/2;if(o===0)u=0,a=0;else{f<.5?a=o/(s+i):a=o/(2-s-i);var l=((s-t)/6+o/2)/o,c=((s-n)/6+o/2)/o,h=((s-r)/6+o/2)/o;t===s?u=h-c:n===s?u=1/3+l-h:r===s&&(u=2/3+c-l),u<0&&(u+=1),u>1&&(u-=1)}return{H:u*360,S:a*100,L:f*100,A:e.A}},root.RGBA_HSVA=root.RGB_HSV=function(e){var t=e.R/255,n=e.G/255,r=e.B/255,i=Math.min(t,n,r),s=Math.max(t,n,r),o=s-i,u,a,f=s;if(o===0)u=0,a=0;else{a=o/s;var l=((s-t)/6+o/2)/o,c=((s-n)/6+o/2)/o,h=((s-r)/6+o/2)/o;t===s?u=h-c:n===s?u=1/3+l-h:r===s&&(u=2/3+c-l),u<0&&(u+=1),u>1&&(u-=1)}return{H:u*360,S:a*100,V:f*100,A:e.A}},root.CMY_RGB=function(e){return{R:Math.max(0,(1-e.C)*255),G:Math.max(0,(1-e.M)*255),B:Math.max(0,(1-e.Y)*255)}},root.CMY_CMYK=function(e){var t=e.C,n=e.M,r=e.Y,i=Math.min(r,Math.min(n,Math.min(t,1)));return t=Math.round((t-i)/(1-i)*100),n=Math.round((n-i)/(1-i)*100),r=Math.round((r-i)/(1-i)*100),i=Math.round(i*100),{C:t,M:n,Y:r,K:i}},root.CMYK_CMY=function(e){return{C:e.C*(1-e.K)+e.K,M:e.M*(1-e.K)+e.K,Y:e.Y*(1-e.K)+e.K}},root.HSLA_RGBA=root.HSL_RGB=function(e){var t=e.H/360,n=e.S/100,r=e.L/100,i,s,o,u,a,f;return n===0?i=s=o=r:(r<.5?a=r*(1+n):a=r+n-n*r,u=2*r-a,f=t+1/3,f<0&&(f+=1),f>1&&(f-=1),6*f<1?i=u+(a-u)*6*f:2*f<1?i=a:3*f<2?i=u+(a-u)*(2/3-f)*6:i=u,f=t,f<0&&(f+=1),f>1&&(f-=1),6*f<1?s=u+(a-u)*6*f:2*f<1?s=a:3*f<2?s=u+(a-u)*(2/3-f)*6:s=u,f=t-1/3,f<0&&(f+=1),f>1&&(f-=1),6*f<1?o=u+(a-u)*6*f:2*f<1?o=a:3*f<2?o=u+(a-u)*(2/3-f)*6:o=u),{R:i*255,G:s*255,B:o*255,A:e.A}},root.HSVA_RGBA=root.HSV_RGB=function(e){var t=e.H/360,n=e.S/100,r=e.V/100,i,s,o,u,a,f;if(n===0)i=s=o=Math.round(r*255);else{t>=1&&(t=0),t=6*t,u=t-Math.floor(t),a=Math.round(255*r*(1-n)),o=Math.round(255*r*(1-n*u)),f=Math.round(255*r*(1-n*(1-u))),r=Math.round(255*r);switch(Math.floor(t)){case 0:i=r,s=f,o=a;break;case 1:i=o,s=r,o=a;break;case 2:i=a,s=r,o=f;break;case 3:i=a,s=o,o=r;break;case 4:i=f,s=a,o=r;break;case 5:i=r,s=a,o=o}}return{R:i,G:s,B:o,A:e.A}}}();if(typeof MIDI=="undefined")var MIDI={};(function(){"use strict";var e={},t=function(t){var n=new Audio,r=t.split(";")[0];n.id="audio",n.setAttribute("preload","auto"),n.setAttribute("audiobuffer",!0),n.addEventListener("canplaythrough",function(){e[r]=!0},!1),n.src="data:"+t,document.body.appendChild(n)};MIDI.audioDetect=function(n){if(typeof Audio=="undefined")return n({});var r=new Audio;if(typeof r.canPlayType=="undefined")return n(e);var i=r.canPlayType('audio/ogg; codecs="vorbis"');i=i==="probably"||i==="maybe";var s=r.canPlayType("audio/mpeg");s=s==="probably"||s==="maybe";if(!i&&!s){n(e);return}i&&t("audio/ogg;base64,T2dnUwACAAAAAAAAAADqnjMlAAAAAOyyzPIBHgF2b3JiaXMAAAAAAUAfAABAHwAAQB8AAEAfAACZAU9nZ1MAAAAAAAAAAAAA6p4zJQEAAAANJGeqCj3//////////5ADdm9yYmlzLQAAAFhpcGguT3JnIGxpYlZvcmJpcyBJIDIwMTAxMTAxIChTY2hhdWZlbnVnZ2V0KQAAAAABBXZvcmJpcw9CQ1YBAAABAAxSFCElGVNKYwiVUlIpBR1jUFtHHWPUOUYhZBBTiEkZpXtPKpVYSsgRUlgpRR1TTFNJlVKWKUUdYxRTSCFT1jFloXMUS4ZJCSVsTa50FkvomWOWMUYdY85aSp1j1jFFHWNSUkmhcxg6ZiVkFDpGxehifDA6laJCKL7H3lLpLYWKW4q91xpT6y2EGEtpwQhhc+211dxKasUYY4wxxsXiUyiC0JBVAAABAABABAFCQ1YBAAoAAMJQDEVRgNCQVQBABgCAABRFcRTHcRxHkiTLAkJDVgEAQAAAAgAAKI7hKJIjSZJkWZZlWZameZaouaov+64u667t6roOhIasBACAAAAYRqF1TCqDEEPKQ4QUY9AzoxBDDEzGHGNONKQMMogzxZAyiFssLqgQBKEhKwKAKAAAwBjEGGIMOeekZFIi55iUTkoDnaPUUcoolRRLjBmlEluJMYLOUeooZZRCjKXFjFKJscRUAABAgAMAQICFUGjIigAgCgCAMAYphZRCjCnmFHOIMeUcgwwxxiBkzinoGJNOSuWck85JiRhjzjEHlXNOSuekctBJyaQTAAAQ4AAAEGAhFBqyIgCIEwAwSJKmWZomipamiaJniqrqiaKqWp5nmp5pqqpnmqpqqqrrmqrqypbnmaZnmqrqmaaqiqbquqaquq6nqrZsuqoum65q267s+rZru77uqapsm6or66bqyrrqyrbuurbtS56nqqKquq5nqq6ruq5uq65r25pqyq6purJtuq4tu7Js664s67pmqq5suqotm64s667s2rYqy7ovuq5uq7Ks+6os+75s67ru2rrwi65r66os674qy74x27bwy7ouHJMnqqqnqq7rmarrqq5r26rr2rqmmq5suq4tm6or26os67Yry7aumaosm64r26bryrIqy77vyrJui67r66Ys67oqy8Lu6roxzLat+6Lr6roqy7qvyrKuu7ru+7JuC7umqrpuyrKvm7Ks+7auC8us27oxuq7vq7It/KosC7+u+8Iy6z5jdF1fV21ZGFbZ9n3d95Vj1nVhWW1b+V1bZ7y+bgy7bvzKrQvLstq2scy6rSyvrxvDLux8W/iVmqratum6um7Ksq/Lui60dd1XRtf1fdW2fV+VZd+3hV9pG8OwjK6r+6os68Jry8ov67qw7MIvLKttK7+r68ow27qw3L6wLL/uC8uq277v6rrStXVluX2fsSu38QsAABhwAAAIMKEMFBqyIgCIEwBAEHIOKQahYgpCCKGkEEIqFWNSMuakZM5JKaWUFEpJrWJMSuaclMwxKaGUlkopqYRSWiqlxBRKaS2l1mJKqcVQSmulpNZKSa2llGJMrcUYMSYlc05K5pyUklJrJZXWMucoZQ5K6iCklEoqraTUYuacpA46Kx2E1EoqMZWUYgupxFZKaq2kFGMrMdXUWo4hpRhLSrGVlFptMdXWWqs1YkxK5pyUzDkqJaXWSiqtZc5J6iC01DkoqaTUYiopxco5SR2ElDLIqJSUWiupxBJSia20FGMpqcXUYq4pxRZDSS2WlFosqcTWYoy1tVRTJ6XFklKMJZUYW6y5ttZqDKXEVkqLsaSUW2sx1xZjjqGkFksrsZWUWmy15dhayzW1VGNKrdYWY40x5ZRrrT2n1mJNMdXaWqy51ZZbzLXnTkprpZQWS0oxttZijTHmHEppraQUWykpxtZara3FXEMpsZXSWiypxNhirLXFVmNqrcYWW62ltVprrb3GVlsurdXcYqw9tZRrrLXmWFNtBQAADDgAAASYUAYKDVkJAEQBAADGMMYYhEYpx5yT0ijlnHNSKucghJBS5hyEEFLKnINQSkuZcxBKSSmUklJqrYVSUmqttQIAAAocAAACbNCUWByg0JCVAEAqAIDBcTRNFFXVdX1fsSxRVFXXlW3jVyxNFFVVdm1b+DVRVFXXtW3bFn5NFFVVdmXZtoWiqrqybduybgvDqKqua9uybeuorqvbuq3bui9UXVmWbVu3dR3XtnXd9nVd+Bmzbeu2buu+8CMMR9/4IeTj+3RCCAAAT3AAACqwYXWEk6KxwEJDVgIAGQAAgDFKGYUYM0gxphhjTDHGmAAAgAEHAIAAE8pAoSErAoAoAADAOeecc84555xzzjnnnHPOOeecc44xxhhjjDHGGGOMMcYYY4wxxhhjjDHGGGOMMcYYY0wAwE6EA8BOhIVQaMhKACAcAABACCEpKaWUUkoRU85BSSmllFKqFIOMSkoppZRSpBR1lFJKKaWUIqWgpJJSSimllElJKaWUUkoppYw6SimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaVUSimllFJKKaWUUkoppRQAYPLgAACVYOMMK0lnhaPBhYasBAByAwAAhRiDEEJpraRUUkolVc5BKCWUlEpKKZWUUqqYgxBKKqmlklJKKbXSQSihlFBKKSWUUkooJYQQSgmhlFRCK6mEUkoHoYQSQimhhFRKKSWUzkEoIYUOQkmllNRCSB10VFIpIZVSSiklpZQ6CKGUklJLLZVSWkqpdBJSKamV1FJqqbWSUgmhpFZKSSWl0lpJJbUSSkklpZRSSymFVFJJJYSSUioltZZaSqm11lJIqZWUUkqppdRSSiWlkEpKqZSSUmollZRSaiGVlEpJKaTUSimlpFRCSamlUlpKLbWUSkmptFRSSaWUlEpJKaVSSksppRJKSqmllFpJKYWSUkoplZJSSyW1VEoKJaWUUkmptJRSSymVklIBAEAHDgAAAUZUWoidZlx5BI4oZJiAAgAAQABAgAkgMEBQMApBgDACAQAAAADAAAAfAABHARAR0ZzBAUKCwgJDg8MDAAAAAAAAAAAAAACAT2dnUwAEAAAAAAAAAADqnjMlAgAAADzQPmcBAQA="),s&&t("audio/mpeg;base64,/+MYxAAAAANIAUAAAASEEB/jwOFM/0MM/90b/+RhST//w4NFwOjf///PZu////9lns5GFDv//l9GlUIEEIAAAgIg8Ir/JGq3/+MYxDsLIj5QMYcoAP0dv9HIjUcH//yYSg+CIbkGP//8w0bLVjUP///3Z0x5QCAv/yLjwtGKTEFNRTMuOTeqqqqqqqqqqqqq/+MYxEkNmdJkUYc4AKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq");var o=(new Date).getTime(),u=window.setInterval(function(){for(var t in e);var r=(new Date).getTime(),i=r-o>5e3;if(t||i)window.clearInterval(u),n(e)},1)}})();if(typeof MIDI=="undefined")var MIDI={};typeof MIDI.Soundfont=="undefined"&&(MIDI.Soundfont={}),function(){"use strict";var e=!1;MIDI.loadPlugin=function(e){typeof e=="function"&&(e={callback:e});var r=e.instruments||e.instrument||"acoustic_grand_piano";typeof r!="object"&&(r=[r]),r.map(function(e){return typeof e=="number"&&(e=MIDI.GeneralMIDI.byId[e]),e}),MIDI.soundfontUrl=e.soundfontUrl||MIDI.soundfontUrl||"./soundfont/",MIDI.audioDetect(function(i){var s="";typeof s=="undefined"&&(n[window.location.hash]?s=window.location.hash.substr(1):s=""),s===""&&(navigator.requestMIDIAccess?s="webmidi":window.webkitAudioContext?s="webaudio":window.Audio?s="audiotag":s="flash");if(!t[s])return;var o=i["audio/ogg"]?"ogg":"mp3";t[s](o,r,e.callback)})};var t={};t.webmidi=function(e,t,n){MIDI.loader&&MIDI.loader.message("Web MIDI API..."),MIDI.WebMIDI.connect(n)},t.flash=function(e,t,n){MIDI.loader&&MIDI.loader.message("Flash API..."),DOMLoader.script.add({src:"./inc/SoundManager2/script/soundmanager2.js",verify:"SoundManager",callback:function(){MIDI.Flash.connect(n)}})},t.audiotag=function(t,n,s){MIDI.loader&&MIDI.loader.message("HTML5 Audio API...");var o=i({items:n,getNext:function(n){e?DOMLoader.sendRequest({url:MIDI.soundfontUrl+n+"-"+t+".js",onprogress:r,onload:function(e){MIDI.Soundfont[n]=JSON.parse(e.responseText),MIDI.loader&&MIDI.loader.update(null,"Downloading",100),o.getNext()}}):DOMLoader.script.add({src:MIDI.soundfontUrl+n+"-"+t+".js",verify:n,callback:function(){MIDI.loader&&MIDI.loader.update(null,"Downloading...",100),o.getNext()}})},onComplete:function(){MIDI.AudioTag.connect(s)}})},t.webaudio=function(t,n,s){MIDI.loader&&MIDI.loader.message("Web Audio API...");var o=i({items:n,getNext:function(n){e?DOMLoader.sendRequest({url:MIDI.soundfontUrl+n+"-"+t+".js",onprogress:r,onload:function(e){MIDI.Soundfont[n]=JSON.parse(e.responseText),MIDI.loader&&MIDI.loader.update(null,"Downloading...",100),o.getNext()}}):DOMLoader.script.add({src:MIDI.soundfontUrl+n+"-"+t+".js",verify:"MIDI.Soundfont."+n,callback:function(){MIDI.loader&&MIDI.loader.update(null,"Downloading...",100),o.getNext()}})},onComplete:function(){MIDI.WebAudioAPI.connect(s)}})};var n={"#webmidi":!0,"#webaudio":!0,"#audiotag":!0,"#flash":!0},r=function(e){this.totalSize||(this.getResponseHeader("Content-Length-Raw")?this.totalSize=parseInt(this.getResponseHeader("Content-Length-Raw")):this.totalSize=e.total);var t=this.totalSize?Math.round(e.loaded/this.totalSize*100):"";MIDI.loader&&MIDI.loader.update(null,"Downloading...",t)},i=function(e){var t={};t.queue=[];for(var n in e.items)t.queue.push(e.items[n]);return t.getNext=function(){if(!t.queue.length)return e.onComplete();e.getNext(t.queue.shift())},setTimeout(t.getNext,1),t}}();if(typeof MIDI=="undefined")var MIDI={};typeof MIDI.Player=="undefined"&&(MIDI.Player={}),function(){"use strict";var e=MIDI.Player;e.callback=undefined,e.currentTime=0,e.endTime=0,e.restart=0,e.playing=!1,e.timeWarp=1,e.start=e.resume=function(){e.currentTime<-1&&(e.currentTime=-1),f(e.currentTime)},e.pause=function(){var t=e.restart;l(),e.restart=t},e.stop=function(){l(),e.restart=0,e.currentTime=0},e.addListener=function(e){s=e},e.removeListener=function(){s=undefined},e.clearAnimation=function(){e.interval&&window.clearInterval(e.interval)},e.setAnimation=function(t){var n=typeof t=="function"?t:t.callback,r=t.interval||30,s=0,o=0,u=0;e.clearAnimation(),e.interval=window.setInterval(function(){if(e.endTime===0)return;e.playing?(s=u===e.currentTime?o-(new Date).getTime():0,e.currentTime===0?s=0:s=e.currentTime-s,u!==e.currentTime&&(o=(new Date).getTime(),u=e.currentTime)):s=e.currentTime;var t=e.endTime,r=s/t,a=s/1e3,f=a/60,l=a-f*60,c=f*60+l,h=t/1e3;if(h-c<-1)return;n({now:c,end:h,events:i})},r)},e.loadMidiFile=function(){e.replayer=new Replayer(MidiFile(e.currentData),e.timeWarp),e.data=e.replayer.getData(),e.endTime=a()},e.loadFile=function(t,n){e.stop();if(t.indexOf("base64,")!==-1){var r=window.atob(t.split(",")[1]);e.currentData=r,e.loadMidiFile(),n&&n(r);return}var i=t.split(" - ")[1]||t;document.getElementById("playback-title").innerHTML=i.replace(".mid","");var s=new XMLHttpRequest;s.open("GET",t),s.overrideMimeType("text/plain; charset=x-user-defined"),s.onreadystatechange=function(){if(this.readyState===4&&this.status===200){var t=this.responseText||"",r=[],i=t.length,s=String.fromCharCode;for(var o=0;oProcessing: "+(r/87*100>>0)+"%
"+l),n.id=f,i[r]=n;if(i.length===t.length){while(i.length){n=i.pop();if(!n)continue;var c=MIDI.keyToNote[n.id];s[a+""+c]=n}o(e)}})};t.setVolume=function(e){i=e},t.programChange=function(e,t){MIDI.channels[e].instrument=t},t.noteOn=function(e,t,o,u){if(!MIDI.channels[e])return;var a=MIDI.channels[e].instrument;if(!s[a+""+t])return;u>0,s=n[r%12]+i;MIDI.keyToNote[s]=r,MIDI.noteToKey[r]=s}}()})();var invertObject=function(e){if(e.length){var t={};for(var n=0;n1&&(n.indexOf(t[i][0])!=-1||n.indexOf(t[i][1])!=-1?r>0?t[i]=t[i][0]+"#":t[i]=t[i][1]+"b":t[i]=t[i][0]+"#");Piano.keySignature=t},e.tempoFromTap=function(e){function t(e){var t={200:"Prestissimo",168:"Presto",140:"Vivace",120:"Allegro",112:"Allegretto",101:"Moderato",76:"Andante",66:"Adagio",60:"Larghetto",40:"Lento",0:"Larghissimo"};for(var n=0,r="";n<250;n++){t[n]&&(r=t[n]);if(e>0)+"bmp "+t(r)}e.tap=(new Date).getTime()},e.findChord=function(e){function t(e){var t={};for(var n in e){var r={};for(var i in e[n])r[e[n][i]]=1;t[n]=r}return t}var n={},r="0 3".split(" "),i=t(Piano.chords);for(var s in i)for(var o=0,u=r.length;o0&&(i+="-"+(e[u]-a));var a=e[u],f=Piano.calculateNote(a)%12,l=Piano.keySignature[f],c=Piano.Color[Piano.HSL].english[f];s+=", "+MusicTheory.Solfege[l].syllable,o+=", "+a,n+=", "+l,r+=", "+t[a]}console.log("notes: "+n.substr(2)+"
"+"solfege: "+s.substr(2)+"
"+"intervals: "+r.substr(2)+"
"+"keys: "+o.substr(2)+"
"+"gaps: "+i.substr(1))}}();if(typeof MusicTheory=="undefined")var MusicTheory={};typeof MusicTheory.Synesthesia=="undefined"&&(MusicTheory.Synesthesia={}),function(e){e.data={"Isaac Newton (1704)":{ref:"Gerstner, p.167",english:["red",null,"orange",null,"yellow","green",null,"blue",null,"indigo",null,"violet"],0:[0,96,51],1:[0,0,0],2:[29,94,52],3:[0,0,0],4:[60,90,60],5:[135,76,32],6:[0,0,0],7:[248,82,28],8:[0,0,0],9:[302,88,26],10:[0,0,0],11:[325,84,46]},"Louis Bertrand Castel (1734)":{ref:"Peacock, p.400",english:["blue","blue-green","green","olive green","yellow","yellow-orange","orange","red","crimson","violet","agate","indigo"],0:[248,82,28],1:[172,68,34],2:[135,76,32],3:[79,59,36],4:[60,90,60],5:[49,90,60],6:[29,94,52],7:[360,96,51],8:[1,89,33],9:[325,84,46],10:[273,80,27],11:[302,88,26]},"George Field (1816)":{ref:"Klein, p.69",english:["blue",null,"purple",null,"red","orange",null,"yellow",null,"yellow green",null,"green"],0:[248,82,28],1:[0,0,0],2:[302,88,26],3:[0,0,0],4:[360,96,51],5:[29,94,52],6:[0,0,0],7:[60,90,60],8:[0,0,0],9:[79,59,36],10:[0,0,0],11:[135,76,32]},"D. D. Jameson (1844)":{ref:"Jameson, p.12",english:["red","red-orange","orange","orange-yellow","yellow","green","green-blue","blue","blue-purple","purple","purple-violet","violet"],0:[360,96,51],1:[14,91,51],2:[29,94,52],3:[49,90,60],4:[60,90,60],5:[135,76,32],6:[172,68,34],7:[248,82,28],8:[273,80,27],9:[302,88,26],10:[313,78,37],11:[325,84,46]},"Theodor Seemann (1881)":{ref:"Klein, p.86",english:["carmine","scarlet","orange","yellow-orange","yellow","green","green blue","blue","indigo","violet","brown","black"],0:[0,58,26],1:[360,96,51],2:[29,94,52],3:[49,90,60],4:[60,90,60],5:[135,76,32],6:[172,68,34],7:[248,82,28],8:[302,88,26],9:[325,84,46],10:[0,58,26],11:[0,0,3]},"A. Wallace Rimington (1893)":{ref:"Peacock, p.402",english:["deep red","crimson","orange-crimson","orange","yellow","yellow-green","green","blueish green","blue-green","indigo","deep blue","violet"],0:[360,96,51],1:[1,89,33],2:[14,91,51],3:[29,94,52],4:[60,90,60],5:[79,59,36],6:[135,76,32],7:[163,62,40],8:[172,68,34],9:[302,88,26],10:[248,82,28],11:[325,84,46]},"Bainbridge Bishop (1893)":{ref:"Bishop, p.11",english:["red","orange-red or scarlet","orange","gold or yellow-orange","yellow or green-gold","yellow-green","green","greenish-blue or aquamarine","blue","indigo or violet-blue","violet","violet-red","red"],0:[360,96,51],1:[1,89,33],2:[29,94,52],3:[50,93,52],4:[60,90,60],5:[73,73,55],6:[135,76,32],7:[163,62,40],8:[302,88,26],9:[325,84,46],10:[343,79,47],11:[360,96,51]},"H. von Helmholtz (1910)":{ref:"Helmholtz, p.22",english:["yellow","green","greenish blue","cayan-blue","indigo blue","violet","end of red","red","red","red","red orange","orange"],0:[60,90,60],1:[135,76,32],2:[172,68,34],3:[211,70,37],4:[302,88,26],5:[325,84,46],6:[330,84,34],7:[360,96,51],8:[10,91,43],9:[10,91,43],10:[8,93,51],11:[28,89,50]},"Alexander Scriabin (1911)":{ref:"Jones, p.104",english:["red","violet","yellow","steely with the glint of metal","pearly blue the shimmer of moonshine","dark red","bright blue","rosy orange","purple","green","steely with a glint of metal","pearly blue the shimmer of moonshine"],0:[360,96,51],1:[325,84,46],2:[60,90,60],3:[245,21,43],4:[211,70,37],5:[1,89,33],6:[248,82,28],7:[29,94,52],8:[302,88,26],9:[135,76,32],10:[245,21,43],11:[211,70,37]},"Adrian Bernard Klein (1930)":{ref:"Klein, p.209",english:["dark red","red","red orange","orange","yellow","yellow green","green","blue-green","blue","blue violet","violet","dark violet"],0:[0,91,40],1:[360,96,51],2:[14,91,51],3:[29,94,52],4:[60,90,60],5:[73,73,55],6:[135,76,32],7:[172,68,34],8:[248,82,28],9:[292,70,31],10:[325,84,46],11:[330,84,34]},"August Aeppli (1940)":{ref:"Gerstner, p.169",english:["red",null,"orange",null,"yellow",null,"green","blue-green",null,"ultramarine blue","violet","purple"],0:[0,96,51],1:[0,0,0],2:[29,94,52],3:[0,0,0],4:[60,90,60],5:[0,0,0],6:[135,76,32],7:[172,68,34],8:[0,0,0],9:[211,70,37],10:[273,80,27],11:[302,88,26]},"I. J. Belmont (1944)":{ref:"Belmont, p.226",english:["red","red-orange","orange","yellow-orange","yellow","yellow-green","green","blue-green","blue","blue-violet","violet","red-violet"],0:[360,96,51],1:[14,91,51],2:[29,94,52],3:[50,93,52],4:[60,90,60],5:[73,73,55],6:[135,76,32],7:[172,68,34],8:[248,82,28],9:[313,78,37],10:[325,84,46],11:[338,85,37]},"Steve Zieverink (2004)":{ref:"Cincinnati Contemporary Art Center",english:["yellow-green","green","blue-green","blue","indigo","violet","ultra violet","infra red","red","orange","yellow-white","yellow"],0:[73,73,55],1:[135,76,32],2:[172,68,34],3:[248,82,28],4:[302,88,26],5:[325,84,46],6:[326,79,24],7:[1,89,33],8:[360,96,51],9:[29,94,52],10:[62,78,74],11:[60,90,60]},"Circle of Fifths (2012)":{ref:"Stuart Wheatman",english:[],data:["#122400","#2E002E","#002914","#470000","#002142","#2E2E00","#290052","#003D00","#520029","#003D3D","#522900","#000080","#244700","#570057","#004D26","#7A0000","#003B75","#4C4D00","#47008F","#006100","#850042","#005C5C","#804000","#0000C7","#366B00","#80007F","#00753B","#B80000","#0057AD","#6B6B00","#6600CC","#008A00","#B8005C","#007F80","#B35900","#2424FF","#478F00","#AD00AD","#00994D","#F00000","#0073E6","#8F8F00","#8A14FF","#00AD00","#EB0075","#00A3A3","#E07000","#6B6BFF","#5CB800","#DB00DB","#00C261","#FF5757","#3399FF","#ADAD00","#B56BFF","#00D600","#FF57AB","#00C7C7","#FF9124","#9999FF","#6EDB00","#FF29FF","#00E070","#FF9999","#7ABDFF","#D1D100","#D1A3FF","#00FA00","#FFA3D1","#00E5E6","#FFC285","#C2C2FF","#80FF00","#FFA8FF","#00E070","#FFCCCC","#C2E0FF","#F0F000","#EBD6FF","#ADFFAD","#FFD6EB","#8AFFFF","#FFEBD6","#EBEBFF","#E0FFC2","#FFEBFF","#E5FFF2","#FFF5F5"]}},e.map=function(t){var n={},r=function(e,t){return[e[0]*.5+t[0]*.5+.5>>0,e[1]*.5+t[1]*.5+.5>>0,e[2]*.5+t[2]*.5+.5>>0]},i=e.data,s=i[t]||i["D. D. Jameson (1844)"];for(var o=0;o<=88;o++)if(s.data)n[o]={hsl:s.data[o],hex:s.data[o]};else{var u=s[(o+9)%12],a=u.H||u[0],f=u.S||u[1],l=u.L||u[2];a==f&&f==l&&(u=r(d,s[(o+10)%12]));var c=l/10,h=o/12>>0,p=l+c*h-3*c;n[o]={hsl:"hsla("+a+","+f+"%,"+p+"%, 1)",hex:Color.Space({H:a,S:f,L:p},"HSL>RGB>HEX>W3")};var d=u}return n}}(MusicTheory.Synesthesia);if(typeof widgets=="undefined")var widgets={};(function(){"use strict";var e=Math.PI,t=!document.createElement("canvas").getContext,n=400,r={id:"loader",bars:12,radius:0,lineWidth:20,lineHeight:70,timeout:0,display:!0};widgets.Loader=function(o){if(t)return;var u=this;typeof o=="string"&&(o={message:o}),typeof o=="boolean"&&(o={display:!1}),typeof o=="undefined"&&(o={}),o.container=o.container||document.body;if(!o.container)return;for(var a in r)typeof o[a]=="undefined"&&(o[a]=r[a]);var f=document.getElementById(o.id);if(!f){var l=document.createElement("div"),c=document.createElement("span");c.className="message",l.appendChild(c),l.className=r.id,l.style.cssText=i("opacity",n),this.span=c,this.div=l;var f=document.createElement("canvas");document.body.appendChild(f),f.id=o.id,f.style.cssText="opacity: 1; position: absolute; z-index: 10000;",l.appendChild(f),o.container.appendChild(l)}else this.span=f.parentNode.getElementsByTagName("span")[0];var h=o.delay,p=o.bars,d=o.radius,v=o.lineHeight+20,m=v*2+o.radius*2,g=s(o.container),y=g.width-m,b=g.height-m,w=window.devicePixelRatio||1;f.width=m*w,f.height=m*w;var E=0,S=f.getContext("2d");S.globalCompositeOperation="lighter",S.shadowOffsetX=1,S.shadowOffsetY=1,S.shadowBlur=1,S.shadowColor="rgba(0, 0, 0, 0.5)",this.messages={},this.message=function(e,t){return this.interval?this.add({message:e,onstart:t}):this.start(t,e)},this.update=function(e,t,n){if(!e)for(var e in this.messages);var r=this.messages[e];r.message=t,typeof n=="number"&&(r.span.innerHTML=n+"%"),t.substr(-3)==="..."?(r._message=t.substr(0,t.length-3),r.messageAnimate=[".  ",".. ","..."].reverse()):(r._message=t,r.messageAnimate=!1),r.element.innerHTML=t},this.add=function(e){typeof e=="string"&&(e={message:e});var t=o.background?o.background:"rgba(0,0,0,0.65)";this.span.style.cssText="background: "+t+";",this.div.style.cssText=i("opacity",n),this.stopPropagation?this.div.style.cssText+="background: rgba(0,0,0,0.25);":this.div.style.cssText+="pointer-events: none;",f.parentNode.style.opacity=1,f.parentNode.style.display="block",o.background&&(this.div.style.background=o.backgrond);var r=(new Date).getTime(),s=Math.abs(r*Math.random()>>0),u=e.message,a=document.createElement("div");a.style.cssText=i("opacity",500);var l=document.createElement("span");l.style.cssText="float: right; width: 50px;";var c=document.createElement("span");c.innerHTML=u,a.appendChild(c),a.appendChild(l);var h=this.messages[s]={seed:s,container:a,element:c,span:l,message:u,timeout:(e.timeout||o.timeout)*1e3,timestamp:r,getProgress:e.getProgress};return this.span.appendChild(a),this.span.style.display="block",this.update(h.seed,u),e.onstart&&window.setTimeout(e.onstart,50),this.center(),this.interval||(e.delay||N(),window.clearInterval(this.interval),this.interval=window.setInterval(N,30)),s},this.remove=function(e){E+=.07;var t=(new Date).getTime();typeof e=="object"&&(e=e.join(":")),e&&(e=":"+e+":");for(var n in this.messages){var r=this.messages[n];if(!e||e.indexOf(":"+r.seed+":")!==-1)delete this.messages[r.seed],r.container.style.color="#99ff88",T(r),r.getProgress&&(r.span.innerHTML="100%")}},this.start=function(e,t){if(!t&&!o.message)return;return this.add({message:t||o.message,onstart:e})},this.stop=function(){this.remove(),window.clearInterval(this.interval),delete this.interval,o.oncomplete&&o.oncomplete(),f&&f.style&&(l.style.cssText+="pointer-events: none;",window.setTimeout(function(){u.div.style.opacity=0},1),window.setTimeout(function(){if(u.interval)return;u.stopPropagation=!1,f.parentNode.style.display="none",S.clearRect(0,0,m,m)},n*1e3))},this.center=function(){var e=s(o.container),t=e.width-m,n=e.height-m;f.style.left=t/2+"px",f.style.top=n/2+"px",f.style.width=m+"px",f.style.height=m+"px",u.span.style.top=n/2+m-10+"px"};var x=document.createElement("style");x.innerHTML=".loader { color: #fff; position: fixed; left: 0; top: 0; width: 100%; height: 100%; z-index: 100000; opacity: 0; display: none; }.loader span.message { line-height: 1.5em; font-family: monospace; font-size: 14px; margin: auto; opacity: 1; display: none; border-radius: 10px; padding: 0px; width: 300px; text-align: center; position: absolute; z-index: 10000; left: 0; right: 0; }.loader span.message div { border-bottom: 1px solid #222; padding: 5px 10px; clear: both; text-align: left; opacity: 1; }.loader span.message div:last-child { border-bottom: none; }",document.head.appendChild(x);var T=function(e){window.setTimeout(function(){e.container.style.opacity=0},1),window.setTimeout(function(){e.container.parentNode.removeChild(e.container)},250)},N=function(){var t=(new Date).getTime();for(var n in u.messages){var r=u.messages[n],i=E/.07>>0;if(i%5===0&&r.getProgress){if(r.timeout&&r.timestamp&&t-r.timestamp>r.timeout){u.remove(r.seed);continue}var s=r.getProgress();if(s>=100){u.remove(r.seed);continue}r.span.innerHTML=(s>>0)+"%"}if(i%10===0&&r.messageAnimate){var a=r.messageAnimate.length,f=i/10%a,l=r._message+r.messageAnimate[f];r.element.innerHTML=l}}n||u.stop(),S.save(),S.clearRect(0,0,m*w,m*w),S.scale(w,w),S.translate(m/2,m/2);var c=360-360/p;for(var h=0;h\r\n";document.write(IEBinaryToArray_ByteStr_Script),DOMLoader.sendRequest=function(e){function t(e){var t={};for(var n=0;n<256;n++)for(var r=0;r<256;r++)t[String.fromCharCode(n+r*256)]=String.fromCharCode(n)+String.fromCharCode(r);var i=IEBinaryToArray_ByteStr(e),s=IEBinaryToArray_ByteStr_Last(e);return i.replace(/[\s\S]/g,function(e){return t[e]})+s}var n=XMLHttpRequest();return n.open("GET",e.url,!0),e.responseType&&(n.responseType=e.responseType),e.onerror&&(n.onerror=e.onerror),e.onprogress&&(n.onprogress=e.onprogress),n.onreadystatechange=function(r){n.readyState===4&&(n.status===200?n.responseText=t(n.responseBody):n=!1,e.onload&&e.onload(n))},n.setRequestHeader("Accept-Charset","x-user-defined"),n.send(null),n}}else DOMLoader.sendRequest=function(e){var t=new XMLHttpRequest;return t.open(e.data?"POST":"GET",e.url,!0),t.overrideMimeType&&t.overrideMimeType("text/plain; charset=x-user-defined"),e.data&&t.setRequestHeader("Content-type","application/x-www-form-urlencoded"),e.responseType&&(t.responseType=e.responseType),e.onerror&&(t.onerror=e.onerror),e.onprogress&&(t.onprogress=e.onprogress),t.onreadystatechange=function(n){if(t.readyState===4){if(t.status!==200&&t.status!=304){e.onerror&&e.onerror(n,!1);return}e.onload&&e.onload(t)}},t.send(e.data),t};if(typeof Event=="undefined")var Event={};if(typeof eventjs=="undefined")var eventjs=Event;Event=function(e){"use strict";e.modifyEventListener=!1,e.modifySelectors=!1,e.add=function(e,t,r,i){return n(e,t,r,i,"add")},e.remove=function(e,t,r,i){return n(e,t,r,i,"remove")},e.stop=function(e){e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0,e.bubble=0},e.prevent=function(e){e.preventDefault&&e.preventDefault(),e.returnValue=!1},e.cancel=function(t){e.stop(t),e.prevent(t)},e.supports=function(e,t){typeof e=="string"&&(t=e,e=window),t="on"+t;if(t in e)return!0;e.setAttribute||(e=document.createElement("div"));if(e.setAttribute&&e.removeAttribute){e.setAttribute(t,"");var n=typeof e[t]=="function";return typeof e[t]!="undefined"&&(e[t]=null),e.removeAttribute(t),n}};var t=function(e){if(!e||typeof e!="object")return e;var n=new e.constructor;for(var r in e)!e[r]||typeof e[r]!="object"?n[r]=e[r]:n[r]=t(e[r]);return n},n=function(u,c,h,p,d,v){p=p||{};if(typeof u=="string"&&c==="ready"){var m=(new Date).getTime(),g=p.timeout,y=p.interval||1e3/60,b=window.setInterval(function(){(new Date).getTime()-m>g&&window.clearInterval(b),document.querySelector(u)&&(window.clearInterval(b),h())},y);return}if(typeof u=="string"){u=document.querySelectorAll(u);if(u.length===0)return i("Missing target on listener!");u.length===1&&(u=u[0])}var w,E={};if(u.length>0){for(var S=0,x=u.length;S=r.maxFingers){var h=[];for(var c in r.tracker)h.push(c);return n.identifier=h.join(","),s}var p=0;for(var d in o){if(o[d].up){delete o[d],i(l,c),r.cancel=!0;break}p++}if(o[c])continue;i(l,c)}else o=r.tracker={},n.bbox=r.bbox=e.getBoundingBox(r.target),r.fingers=0,r.cancel=!1,i(l,c)}var h=[];for(var c in r.tracker)h.push(c);return n.identifier=h.join(","),s},e.pointerEnd=function(e,t,n,r){var i=e.touches||[],s=i.length,o={};for(var u=0;u1)return;var s=n.changedTouches||e.getCoords(n),o=s[0],u=t.bbox,a=e.getBoundingBox(t.target);if(t.position==="relative")var f=(o.pageX+u.scrollLeft-u.x1)*u.scaleX,l=(o.pageY+u.scrollTop-u.y1)*u.scaleY;else var f=o.pageX-u.x1,l=o.pageY-u.y1;f>0&&f0&&l0&&l0&&c1)&&(a.state=t.gesture,t.listener(o,a)),clearTimeout(s),r=i=0)};var a=e.pointerSetup(t);return a.state="dblclick",Event.add(t.target,"mousedown",t.onPointerDown),a},Event.Gesture=Event.Gesture||{},Event.Gesture._gestureHandlers=Event.Gesture._gestureHandlers||{},Event.Gesture._gestureHandlers.dbltap=e.dbltap,Event.Gesture._gestureHandlers.dblclick=e.dblclick,e}(Event.proxy);if(typeof Event=="undefined")var Event={};typeof Event.proxy=="undefined"&&(Event.proxy={}),Event.proxy=function(e){"use strict";return e.dragElement=function(t,n){e.drag({event:n,target:t,position:"move",listener:function(e,n){t.style.left=n.x+"px",t.style.top=n.y+"px"}})},e.drag=function(t){t.gesture="drag",t.onPointerDown=function(r){e.pointerStart(r,n,t)&&(Event.add(t.doc,"mousemove",t.onPointerMove),Event.add(t.doc,"mouseup",t.onPointerUp)),t.onPointerMove(r,"down")},t.onPointerMove=function(r,i){var s=t.bbox,o=r.changedTouches||e.getCoords(r),u=o.length;for(var a=0;a0?x:-x,typeof c.DEG2!="undefined"&&(x>0?c.rotation+=c.DEG1-c.DEG2:c.rotation-=c.DEG1-c.DEG2,v+=c.rotation),a.push(c.move)}r.touches=a,r.fingers=n.fingers,r.scale=d/n.fingers,r.rotation=v/n.fingers,r.state="change",n.listener(i,r)},n.onPointerUp=function(t){var i=n.fingers;e.pointerEnd(t,r,n)&&(Event.remove(n.doc,"mousemove",n.onPointerMove),Event.remove(n.doc,"mouseup",n.onPointerUp)),i===n.minFingers&&n.fingersn){var w=p*g/b,E=Math.abs(w+y.value);y.value&&En.threshold&&(f.x/=h,f.y/=h,r.start=f,r.x=l/h,r.y=c/h,r.angle=-(((u/n.snap+.5>>0)*n.snap||360)-360),r.velocity=s,r.fingers=n.gestureFingers,r.state="swipe",n.listener(i,r))}};var r=e.pointerSetup(n);return Event.add(n.target,"mousedown",n.onPointerDown),r},Event.Gesture=Event.Gesture||{},Event.Gesture._gestureHandlers=Event.Gesture._gestureHandlers||{},Event.Gesture._gestureHandlers.swipe=e.swipe,e}(Event.proxy);if(typeof Event=="undefined")var Event={};typeof Event.proxy=="undefined"&&(Event.proxy={}),Event.proxy=function(e){"use strict";return e.tap=e.longpress=function(t){t.delay=t.delay||500,t.timeout=t.timeout||250;var n,r;t.onPointerDown=function(s){if(e.pointerStart(s,i,t)){n=(new Date).getTime(),Event.add(t.doc,"mousemove",t.onPointerMove).listener(s),Event.add(t.doc,"mouseup",t.onPointerUp);if(t.gesture!=="longpress")return;r=setTimeout(function(){if(s.cancelBubble&&++s.bubble>1)return;var e=0;for(var n in t.tracker){if(t.tracker[n].end===!0)return;if(t.cancel)return;e++}i.state="start",i.fingers=e,t.listener(s,i)},t.delay)}},t.onPointerMove=function(n){var r=t.bbox,i=n.changedTouches||e.getCoords(n),s=i.length;for(var o=0;o0&&l0&&c1)return;if(t.gesture==="longpress"){i.state==="start"&&(i.state="end",t.listener(s,i));return}if(t.cancel)return;if((new Date).getTime()-n>t.timeout)return;i.state="tap",i.fingers=t.gestureFingers,t.listener(s,i)}};var i=e.pointerSetup(t);return Event.add(t.target,"mousedown",t.onPointerDown),i},Event.Gesture=Event.Gesture||{},Event.Gesture._gestureHandlers=Event.Gesture._gestureHandlers||{},Event.Gesture._gestureHandlers.tap=e.tap,Event.Gesture._gestureHandlers.longpress=e.longpress,e}(Event.proxy);if(typeof Event=="undefined")var Event={};typeof Event.proxy=="undefined"&&(Event.proxy={}),Event.proxy=function(e){"use strict";return e.wheel=function(e){var t,n=e.timeout||150,r=0,i={gesture:"wheel",state:"start",wheelDelta:0,target:e.target,listener:e.listener,remove:function(){e.target[u](a,s,!1)}},s=function(s){s=s||window.event,i.state=r++?"change":"start",i.wheelDelta=s.detail?s.detail*-20:s.wheelDelta,e.listener(s,i),clearTimeout(t),t=setTimeout(function(){r=0,i.state="end",i.wheelDelta=0,e.listener(s,i)},n)},o=document.addEventListener?"addEventListener":"attachEvent",u=document.removeEventListener?"removeEventListener":"detachEvent",a=Event.supports("mousewheel")?"mousewheel":"DOMMouseScroll";return e.target[o](a,s,!1),i},Event.Gesture=Event.Gesture||{},Event.Gesture._gestureHandlers=Event.Gesture._gestureHandlers||{},Event.Gesture._gestureHandlers.wheel=e.wheel,e}(Event.proxy); \ No newline at end of file +if(typeof MIDI=="undefined")var MIDI={};(function(){"use strict";var e={},t=function(t){var n=new Audio,r=t.split(";")[0];n.id="audio",n.setAttribute("preload","auto"),n.setAttribute("audiobuffer",!0),n.addEventListener("canplaythrough",function(){e[r]=!0},!1),n.src="data:"+t,document.body.appendChild(n)};MIDI.audioDetect=function(n){if(typeof Audio=="undefined")return n({});var r=new Audio;if(typeof r.canPlayType=="undefined")return n(e);var i=r.canPlayType('audio/ogg; codecs="vorbis"');i=i==="probably"||i==="maybe";var s=r.canPlayType("audio/mpeg");s=s==="probably"||s==="maybe";if(!i&&!s){n(e);return}i&&t("audio/ogg;base64,T2dnUwACAAAAAAAAAADqnjMlAAAAAOyyzPIBHgF2b3JiaXMAAAAAAUAfAABAHwAAQB8AAEAfAACZAU9nZ1MAAAAAAAAAAAAA6p4zJQEAAAANJGeqCj3//////////5ADdm9yYmlzLQAAAFhpcGguT3JnIGxpYlZvcmJpcyBJIDIwMTAxMTAxIChTY2hhdWZlbnVnZ2V0KQAAAAABBXZvcmJpcw9CQ1YBAAABAAxSFCElGVNKYwiVUlIpBR1jUFtHHWPUOUYhZBBTiEkZpXtPKpVYSsgRUlgpRR1TTFNJlVKWKUUdYxRTSCFT1jFloXMUS4ZJCSVsTa50FkvomWOWMUYdY85aSp1j1jFFHWNSUkmhcxg6ZiVkFDpGxehifDA6laJCKL7H3lLpLYWKW4q91xpT6y2EGEtpwQhhc+211dxKasUYY4wxxsXiUyiC0JBVAAABAABABAFCQ1YBAAoAAMJQDEVRgNCQVQBABgCAABRFcRTHcRxHkiTLAkJDVgEAQAAAAgAAKI7hKJIjSZJkWZZlWZameZaouaov+64u667t6roOhIasBACAAAAYRqF1TCqDEEPKQ4QUY9AzoxBDDEzGHGNONKQMMogzxZAyiFssLqgQBKEhKwKAKAAAwBjEGGIMOeekZFIi55iUTkoDnaPUUcoolRRLjBmlEluJMYLOUeooZZRCjKXFjFKJscRUAABAgAMAQICFUGjIigAgCgCAMAYphZRCjCnmFHOIMeUcgwwxxiBkzinoGJNOSuWck85JiRhjzjEHlXNOSuekctBJyaQTAAAQ4AAAEGAhFBqyIgCIEwAwSJKmWZomipamiaJniqrqiaKqWp5nmp5pqqpnmqpqqqrrmqrqypbnmaZnmqrqmaaqiqbquqaquq6nqrZsuqoum65q267s+rZru77uqapsm6or66bqyrrqyrbuurbtS56nqqKquq5nqq6ruq5uq65r25pqyq6purJtuq4tu7Js664s67pmqq5suqotm64s667s2rYqy7ovuq5uq7Ks+6os+75s67ru2rrwi65r66os674qy74x27bwy7ouHJMnqqqnqq7rmarrqq5r26rr2rqmmq5suq4tm6or26os67Yry7aumaosm64r26bryrIqy77vyrJui67r66Ys67oqy8Lu6roxzLat+6Lr6roqy7qvyrKuu7ru+7JuC7umqrpuyrKvm7Ks+7auC8us27oxuq7vq7It/KosC7+u+8Iy6z5jdF1fV21ZGFbZ9n3d95Vj1nVhWW1b+V1bZ7y+bgy7bvzKrQvLstq2scy6rSyvrxvDLux8W/iVmqratum6um7Ksq/Lui60dd1XRtf1fdW2fV+VZd+3hV9pG8OwjK6r+6os68Jry8ov67qw7MIvLKttK7+r68ow27qw3L6wLL/uC8uq277v6rrStXVluX2fsSu38QsAABhwAAAIMKEMFBqyIgCIEwBAEHIOKQahYgpCCKGkEEIqFWNSMuakZM5JKaWUFEpJrWJMSuaclMwxKaGUlkopqYRSWiqlxBRKaS2l1mJKqcVQSmulpNZKSa2llGJMrcUYMSYlc05K5pyUklJrJZXWMucoZQ5K6iCklEoqraTUYuacpA46Kx2E1EoqMZWUYgupxFZKaq2kFGMrMdXUWo4hpRhLSrGVlFptMdXWWqs1YkxK5pyUzDkqJaXWSiqtZc5J6iC01DkoqaTUYiopxco5SR2ElDLIqJSUWiupxBJSia20FGMpqcXUYq4pxRZDSS2WlFosqcTWYoy1tVRTJ6XFklKMJZUYW6y5ttZqDKXEVkqLsaSUW2sx1xZjjqGkFksrsZWUWmy15dhayzW1VGNKrdYWY40x5ZRrrT2n1mJNMdXaWqy51ZZbzLXnTkprpZQWS0oxttZijTHmHEppraQUWykpxtZara3FXEMpsZXSWiypxNhirLXFVmNqrcYWW62ltVprrb3GVlsurdXcYqw9tZRrrLXmWFNtBQAADDgAAASYUAYKDVkJAEQBAADGMMYYhEYpx5yT0ijlnHNSKucghJBS5hyEEFLKnINQSkuZcxBKSSmUklJqrYVSUmqttQIAAAocAAACbNCUWByg0JCVAEAqAIDBcTRNFFXVdX1fsSxRVFXXlW3jVyxNFFVVdm1b+DVRVFXXtW3bFn5NFFVVdmXZtoWiqrqybduybgvDqKqua9uybeuorqvbuq3bui9UXVmWbVu3dR3XtnXd9nVd+Bmzbeu2buu+8CMMR9/4IeTj+3RCCAAAT3AAACqwYXWEk6KxwEJDVgIAGQAAgDFKGYUYM0gxphhjTDHGmAAAgAEHAIAAE8pAoSErAoAoAADAOeecc84555xzzjnnnHPOOeecc44xxhhjjDHGGGOMMcYYY4wxxhhjjDHGGGOMMcYYY0wAwE6EA8BOhIVQaMhKACAcAABACCEpKaWUUkoRU85BSSmllFKqFIOMSkoppZRSpBR1lFJKKaWUIqWgpJJSSimllElJKaWUUkoppYw6SimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaVUSimllFJKKaWUUkoppRQAYPLgAACVYOMMK0lnhaPBhYasBAByAwAAhRiDEEJpraRUUkolVc5BKCWUlEpKKZWUUqqYgxBKKqmlklJKKbXSQSihlFBKKSWUUkooJYQQSgmhlFRCK6mEUkoHoYQSQimhhFRKKSWUzkEoIYUOQkmllNRCSB10VFIpIZVSSiklpZQ6CKGUklJLLZVSWkqpdBJSKamV1FJqqbWSUgmhpFZKSSWl0lpJJbUSSkklpZRSSymFVFJJJYSSUioltZZaSqm11lJIqZWUUkqppdRSSiWlkEpKqZSSUmollZRSaiGVlEpJKaTUSimlpFRCSamlUlpKLbWUSkmptFRSSaWUlEpJKaVSSksppRJKSqmllFpJKYWSUkoplZJSSyW1VEoKJaWUUkmptJRSSymVklIBAEAHDgAAAUZUWoidZlx5BI4oZJiAAgAAQABAgAkgMEBQMApBgDACAQAAAADAAAAfAABHARAR0ZzBAUKCwgJDg8MDAAAAAAAAAAAAAACAT2dnUwAEAAAAAAAAAADqnjMlAgAAADzQPmcBAQA="),s&&t("audio/mpeg;base64,/+MYxAAAAANIAUAAAASEEB/jwOFM/0MM/90b/+RhST//w4NFwOjf///PZu////9lns5GFDv//l9GlUIEEIAAAgIg8Ir/JGq3/+MYxDsLIj5QMYcoAP0dv9HIjUcH//yYSg+CIbkGP//8w0bLVjUP///3Z0x5QCAv/yLjwtGKTEFNRTMuOTeqqqqqqqqqqqqq/+MYxEkNmdJkUYc4AKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq");var o=(new Date).getTime(),u=window.setInterval(function(){for(var t in e);var r=(new Date).getTime(),i=r-o>5e3;if(t||i)window.clearInterval(u),n(e)},1)}})();if(typeof MIDI=="undefined")var MIDI={};typeof MIDI.Soundfont=="undefined"&&(MIDI.Soundfont={}),function(){"use strict";var e=!1;MIDI.loadPlugin=function(e){typeof e=="function"&&(e={callback:e});var r=e.instruments||e.instrument||"acoustic_grand_piano";typeof r!="object"&&(r=[r]),r.map(function(e){return typeof e=="number"&&(e=MIDI.GeneralMIDI.byId[e]),e}),MIDI.soundfontUrl=e.soundfontUrl||MIDI.soundfontUrl||"./soundfont/",MIDI.audioDetect(function(i){var s="";typeof s=="undefined"&&(n[window.location.hash]?s=window.location.hash.substr(1):s=""),s===""&&(navigator.requestMIDIAccess?s="webmidi":window.webkitAudioContext?s="webaudio":window.Audio?s="audiotag":s="flash");if(!t[s])return;var o=i["audio/ogg"]?"ogg":"mp3";t[s](o,r,e.callback)})};var t={};t.webmidi=function(e,t,n){MIDI.loader&&MIDI.loader.message("Web MIDI API..."),MIDI.WebMIDI.connect(n)},t.flash=function(e,t,n){MIDI.loader&&MIDI.loader.message("Flash API..."),DOMLoader.script.add({src:"./inc/SoundManager2/script/soundmanager2.js",verify:"SoundManager",callback:function(){MIDI.Flash.connect(n)}})},t.audiotag=function(t,n,s){MIDI.loader&&MIDI.loader.message("HTML5 Audio API...");var o=i({items:n,getNext:function(n){e?DOMLoader.sendRequest({url:MIDI.soundfontUrl+n+"-"+t+".js",onprogress:r,onload:function(e){MIDI.Soundfont[n]=JSON.parse(e.responseText),MIDI.loader&&MIDI.loader.update(null,"Downloading",100),o.getNext()}}):DOMLoader.script.add({src:MIDI.soundfontUrl+n+"-"+t+".js",verify:n,callback:function(){MIDI.loader&&MIDI.loader.update(null,"Downloading...",100),o.getNext()}})},onComplete:function(){MIDI.AudioTag.connect(s)}})},t.webaudio=function(t,n,s){MIDI.loader&&MIDI.loader.message("Web Audio API...");var o=i({items:n,getNext:function(n){e?DOMLoader.sendRequest({url:MIDI.soundfontUrl+n+"-"+t+".js",onprogress:r,onload:function(e){MIDI.Soundfont[n]=JSON.parse(e.responseText),MIDI.loader&&MIDI.loader.update(null,"Downloading...",100),o.getNext()}}):DOMLoader.script.add({src:MIDI.soundfontUrl+n+"-"+t+".js",verify:"MIDI.Soundfont."+n,callback:function(){MIDI.loader&&MIDI.loader.update(null,"Downloading...",100),o.getNext()}})},onComplete:function(){MIDI.WebAudioAPI.connect(s)}})};var n={"#webmidi":!0,"#webaudio":!0,"#audiotag":!0,"#flash":!0},r=function(e){this.totalSize||(this.getResponseHeader("Content-Length-Raw")?this.totalSize=parseInt(this.getResponseHeader("Content-Length-Raw")):this.totalSize=e.total);var t=this.totalSize?Math.round(e.loaded/this.totalSize*100):"";MIDI.loader&&MIDI.loader.update(null,"Downloading...",t)},i=function(e){var t={};t.queue=[];for(var n in e.items)t.queue.push(e.items[n]);return t.getNext=function(){if(!t.queue.length)return e.onComplete();e.getNext(t.queue.shift())},setTimeout(t.getNext,1),t}}();if(typeof MIDI=="undefined")var MIDI={};(function(){"use strict";(function(){var e=null,t=null,n=[],r=MIDI.WebMIDI={};r.setVolume=function(e,n){t.send([176+e,7,n])},r.programChange=function(e,n){t.send([192+e,n])},r.noteOn=function(e,n,r,i){t.send([144+e,n,r],i*1e3)},r.noteOff=function(e,n,r){t.send([128+e,n],r*1e3)},r.chordOn=function(e,n,r,i){for(var s=0;sProcessing: "+(r/87*100>>0)+"%
"+l),n.id=f,i[r]=n;if(i.length===t.length){while(i.length){n=i.pop();if(!n)continue;var c=MIDI.keyToNote[n.id];s[a+""+c]=n}o(e)}})};t.setVolume=function(e){i=e},t.programChange=function(e,t){MIDI.channels[e].instrument=t},t.noteOn=function(e,t,o,u){if(!MIDI.channels[e])return;var a=MIDI.channels[e].instrument;if(!s[a+""+t])return;u>0,s=n[r%12]+i;MIDI.keyToNote[s]=r,MIDI.noteToKey[r]=s}}()})();if(typeof MIDI=="undefined")var MIDI={};typeof MIDI.Player=="undefined"&&(MIDI.Player={}),function(){"use strict";var e=MIDI.Player;e.callback=undefined,e.currentTime=0,e.endTime=0,e.restart=0,e.playing=!1,e.timeWarp=1,e.start=e.resume=function(){e.currentTime<-1&&(e.currentTime=-1),f(e.currentTime)},e.pause=function(){var t=e.restart;l(),e.restart=t},e.stop=function(){l(),e.restart=0,e.currentTime=0},e.addListener=function(e){s=e},e.removeListener=function(){s=undefined},e.clearAnimation=function(){e.interval&&window.clearInterval(e.interval)},e.setAnimation=function(t){var n=typeof t=="function"?t:t.callback,r=t.interval||30,s=0,o=0,u=0;e.clearAnimation(),e.interval=window.setInterval(function(){if(e.endTime===0)return;e.playing?(s=u===e.currentTime?o-(new Date).getTime():0,e.currentTime===0?s=0:s=e.currentTime-s,u!==e.currentTime&&(o=(new Date).getTime(),u=e.currentTime)):s=e.currentTime;var t=e.endTime,r=s/t,a=s/1e3,f=a/60,l=a-f*60,c=f*60+l,h=t/1e3;if(h-c<-1)return;n({now:c,end:h,events:i})},r)},e.loadMidiFile=function(){e.replayer=new Replayer(MidiFile(e.currentData),e.timeWarp),e.data=e.replayer.getData(),e.endTime=a()},e.loadFile=function(t,n){e.stop();if(t.indexOf("base64,")!==-1){var r=window.atob(t.split(",")[1]);e.currentData=r,e.loadMidiFile(),n&&n(r);return}var i=t.split(" - ")[1]||t;document.getElementById("playback-title").innerHTML=i.replace(".mid","");var s=new XMLHttpRequest;s.open("GET",t),s.overrideMimeType("text/plain; charset=x-user-defined"),s.onreadystatechange=function(){if(this.readyState===4&&this.status===200){var t=this.responseText||"",r=[],i=t.length,s=String.fromCharCode;for(var o=0;o\r\n";document.write(IEBinaryToArray_ByteStr_Script),DOMLoader.sendRequest=function(e){function t(e){var t={};for(var n=0;n<256;n++)for(var r=0;r<256;r++)t[String.fromCharCode(n+r*256)]=String.fromCharCode(n)+String.fromCharCode(r);var i=IEBinaryToArray_ByteStr(e),s=IEBinaryToArray_ByteStr_Last(e);return i.replace(/[\s\S]/g,function(e){return t[e]})+s}var n=XMLHttpRequest();return n.open("GET",e.url,!0),e.responseType&&(n.responseType=e.responseType),e.onerror&&(n.onerror=e.onerror),e.onprogress&&(n.onprogress=e.onprogress),n.onreadystatechange=function(r){n.readyState===4&&(n.status===200?n.responseText=t(n.responseBody):n=!1,e.onload&&e.onload(n))},n.setRequestHeader("Accept-Charset","x-user-defined"),n.send(null),n}}else DOMLoader.sendRequest=function(e){var t=new XMLHttpRequest;return t.open(e.data?"POST":"GET",e.url,!0),t.overrideMimeType&&t.overrideMimeType("text/plain; charset=x-user-defined"),e.data&&t.setRequestHeader("Content-type","application/x-www-form-urlencoded"),e.responseType&&(t.responseType=e.responseType),e.onerror&&(t.onerror=e.onerror),e.onprogress&&(t.onprogress=e.onprogress),t.onreadystatechange=function(n){if(t.readyState===4){if(t.status!==200&&t.status!=304){e.onerror&&e.onerror(n,!1);return}e.onload&&e.onload(t)}},t.send(e.data),t};if(typeof DOMLoader=="undefined")var DOMLoader={};(function(){"use strict";DOMLoader.script=function(){return this.loaded={},this.loading={},this},DOMLoader.script.prototype.add=function(e){var t=this;typeof e=="string"&&(e={src:e});var n=e.srcs;typeof n=="undefined"&&(n=[{src:e.src,verify:e.verify}]);var r=document.getElementsByTagName("head")[0],i=function(e,n){if(t.loaded[e.src])return;if(n&&typeof window[n]=="undefined")return;t.loaded[e.src]=!0,t.loading[e.src]&&t.loading[e.src](),delete t.loading[e.src],e.callback&&e.callback(),typeof f!="undefined"&&f()},s=[],o=function(n){typeof n=="string"&&(n={src:n,verify:e.verify});if(/([\w\d.])$/.test(n.verify)){n.test=n.verify;if(typeof n.test=="object")for(var o in n.test)s.push(n.test[o]);else s.push(n.test)}if(t.loaded[n.src])return;var u=document.createElement("script");u.onreadystatechange=function(){if(this.readyState!=="loaded"&&this.readyState!=="complete")return;i(n)},u.onload=function(){i(n)},u.onerror=function(){},u.setAttribute("type","text/javascript"),u.setAttribute("src",n.src),r.appendChild(u),t.loading[n.src]=function(){}},u=function(t){if(t)i(t,t.test);else for(var r=0;r + - + diff --git a/grunt.js b/grunt.js index ca4b6d6..604db65 100644 --- a/grunt.js +++ b/grunt.js @@ -10,10 +10,23 @@ module.exports = function (grunt) { grunt.initConfig({ concat: { - 'build/MIDI.js': "./js/**" + 'build/MIDI.js': [ + "./js/MIDI/AudioDetect.js", + "./js/MIDI/LoadPlugin.js", + "./js/MIDI/Plugin.js", + "./js/MIDI/Player.js", + "./js/Window/DOMLoader.XMLHttp.js", // req when using XHR + "./js/Window/DOMLoader.script.js", // req otherwise +// "./js/Color/SpaceW3.js", // optional +// "./js/MusicTheory/Synesthesia.js", // optional +// "./js/Widgets/Loader.js", // optional +// "./js/Window/Event.js" // optional + ] }, min: { - 'build/MIDI.min.js': ['build/MIDI.js'] + 'build/MIDI.min.js': [ + 'build/MIDI.js' + ] } }); ///