let there be midi

This commit is contained in:
Michael Deal 2012-02-15 20:46:03 -08:00
commit d338706cec
139 changed files with 12537 additions and 0 deletions

164
MIDIPlayer.css Normal file
View file

@ -0,0 +1,164 @@
body {
font-family: Andada;
font-size: 1.2em;
line-height: 2em;
background: #fcfae9;
color: #907d62;
margin: 0 50px;
}
div.player {
background-image: -webkit-gradient(linear,left top,left bottom,from(rgba(66,66,66,1)),to(rgba(22,22,22,1)));
background-image: -webkit-linear-gradient(top, rgba(66, 66, 66, 1) 0%, rgba(22, 22, 22, 1) 100%);
background-image: -moz-linear-gradient(top, rgba(66, 66, 66, 1) 0%, rgba(22, 22, 22, 1) 100%);
background-image: -ms-gradient(top, rgba(66, 66, 66, 1) 0%, rgba(22, 22, 22, 1) 100%);
background-image: -o-gradient(top, rgba(66, 66, 66, 1) 0%, rgba(22, 22, 22, 1) 100%);
background-image: linear-gradient(top, rgba(66, 66, 66, 1) 0%, rgba(22, 22, 22, 1) 100%);
padding: 15px 20px;
border: 1px solid #000;
box-shadow: 0 0 10px #fff;
-moz-box-shadow: 0 0 10px #fff;
-webkit-box-shadow: 0 0 10px #fff;
border-radius: 10px;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
color: #FFFFFF;
color: rgba(255, 255, 255, 0.8);
text-shadow: 1px 1px 2px #000;
-moz-text-shadow: 1px 1px 2px #000;
margin-bottom: 15px;
}
div.player #capsule {
border: 1px solid #000;
box-shadow: 0 0 10px #555;
-moz-box-shadow: 0 0 10px #555;
-webkit-box-shadow: 0 0 10px #555;
background: #000;
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(1, rgba(0,0,0,0.5)), color-stop(0, #333));
background-image: -webkit-linear-gradient(top, rgba(0, 0, 0, 0.5) 1, #333 0);
background-image: -moz-linear-gradient(top, rgba(0, 0, 0, 0.5) 1, #333 0);
background-image: -ms-gradient(top, rgba(0, 0, 0, 0.5) 1, #333 0);
background-image: -o-gradient(top, rgba(0, 0, 0, 0.5) 1, #333 0);
background-image: linear-gradient(top, rgba(0, 0, 0, 0.5) 1, #333 0);
overflow: hidden;
border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
width: 420px;
display: inline-block;
height: 30px;
}
div.player #capsule #cursor {
border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
background: #003b96;
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(1, #003b96), color-stop(0, #0088e9));
background-image: -webkit-linear-gradient(top, #003b96 1, #0088e9 0);
background-image: -moz-linear-gradient(top, #003b96 1, #0088e9 0);
background-image: -ms-gradient(top, #003b96 1, #0088e9 0);
background-image: -o-gradient(top, #003b96 1, #0088e9 0);
background-image: linear-gradient(top, #003b96 1, #0088e9 0);
width: 0;
display: inline-block;
height: 100%;
}
div.player span.time {
position: relative;
top: -9px;
padding: 0 10px;
width: 40px;
display: inline-block;
text-align: right;
}
div.player div.time-controls {
width: 560px;
margin: 10px auto 0;
}
input[type="image"]:hover {
opacity: 1;
}
input[type="image"]:active {
opacity: 0.85;
}
input[type="image"] {
opacity: 0.7;
}
p {
margin: 15px 0 0 15px;
color: #403522;
}
li {
color: #403522;
}
li {
margin-bottom: 20px;
color: #000;
background: rgba(255, 0, 0, 0);
border-radius: 10px;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
list-style-type: none;
padding: 2px 10px;
}
pre {
width: 90%;
overflow-x: scroll;
padding: 0;
margin: 0;
}
pre b {
color: #fff;
background: rgba(255, 0, 0, 0.5);
padding: 2px 5px;
}
li.indent {
color: #403522;
background: none;
position: relative;
left: 50px;
list-style-type: none;
}
li.indent.square {
background: none;
list-style-type: square;
}
h3 {
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(1, rgba(0, 200, 255, 0.35)), color-stop(0, rgba(0,88,127,0.42)));
color: #fff;
text-shadow: 1px 1px #000;
padding: 2px 10px;
border-bottom: 1px solid rgba(0,0,0,0.3);
border-top: 1px solid rgba(0,0,0,0.6);
}
li a {
color: #000;
}
h3 a {
color: #fff;
}
a, li.indent.demos a {
color: #06f;
}
li a:hover, a:hover, li.indent.demos a:hover {
color: #c09;
}
h3 a:hover {
color: #ff0;
}
h3 {
font-family: Oswald;
}
h1 {
font-family: Oswald; font-size: 2em; font-weight: bold; z-index: 2; padding-left: 15px; position: relative; color: rgba(0,0,0,0.5); text-shadow: 0 0 7px rgba(255,255,0,0.50);
}
#colors div {
-webkit-transition-property: background, color;
-webkit-transition-duration: .25s;
padding: 1px 0 1px 5px; font-family: arial; font-size: 9px; line-height: 9px; color: #aaa; width: 30px; height: 9px;
background-image: -webkit-gradient(linear,left top,left bottom,from(rgba(66,66,66,0.75)),to(rgba(0,0,0,1)));
border-bottom: 1px solid rgba(5,5,5,0.7);
}

362
MIDIPlayer.html Normal file

File diff suppressed because one or more lines are too long

142
README.html Normal file
View file

@ -0,0 +1,142 @@
<style type="text/css">
p {
margin: 15px 0 0 15px;
color: #403522;
}
li {
color: #403522;
}
li {
margin-bottom: 20px;
color: #000;
background: rgba(255, 0, 0, 0);
border-radius: 10px;
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
list-style-type: none;
padding: 2px 10px;
}
pre {
width: 90%;
overflow-x: scroll;
padding: 0;
margin: 0;
}
pre b {
color: #fff;
background: rgba(255, 0, 0, 0.5);
padding: 2px 5px;
}
li.indent {
color: #403522;
background: none;
position: relative;
left: 50px;
list-style-type: none;
}
li.indent.square {
background: none;
list-style-type: square;
}
h3 {
background-image: -webkit-gradient(linear, left top, left bottom, color-stop(1, rgba(0, 200, 255, 0.35)), color-stop(0, rgba(0,88,127,0.42)));
color: #fff;
text-shadow: 1px 1px #000;
padding: 2px 10px;
border-bottom: 1px solid rgba(0,0,0,0.3);
border-top: 1px solid rgba(0,0,0,0.6);
}
li a {
color: #000;
}
h3 a {
color: #fff;
}
a, li.indent.demos a {
color: #06f;
}
li a:hover, a:hover, li.indent.demos a:hover {
color: #c09;
}
h3 a:hover {
color: #ff0;
}
h3 {
font-family: Oswald;
}
h1 {
font-family: Oswald; font-size: 2em; font-weight: bold; z-index: 2; padding-left: 15px; position: relative; color: rgba(0,0,0,0.5); text-shadow: 0 0 7px rgba(255,255,0,0.50);
}
</style>
<h3>Description of package;</h3>
<li><a href="./js/MIDI.loadPlugin.js">MIDI.loadPlugin.js</a>: &nbsp;Decides which framework is best to use, and sends request.</li>
<li class="indent">
<pre>
// interface to download soundfont, then execute callback;
MIDI.loadPlugin(callback, soundfont);
// simple example to get started;
MIDI.loadPlugin(function() {
MIDI.noteOn(0, 100, 127, 0); // plays note once loaded
}, "soundfont/soundfont-ogg-guitar.js");
</pre>
</li>
<li><a href="./soundfont/soundfont-ogg.js">MIDI.Soundfont.js</a>: &nbsp;Customizable base64 Soundfont.</li>
<li class="indent square"><a href="http://mudcu.be/journal/2011/11/base64-soundfonts/">Encode your own soundfonts</a>, Drums, Guitars, and so on.</li>
<li class="indent square"><a href="https://github.com/mudx/MIDI.js">Share</a> them with the community!</li>
<li><a href="./js/MIDI.Plugin.js">MIDI.Plugin.js</a>: &nbsp;Ties together the following frameworks;</li>
<li class="indent"><pre>
MIDI.noteOn(channel, note, velocity, delay);
MIDI.noteOff(channel, note, delay);
MIDI.chordOn(channel, chord, velocity, delay);
MIDI.chordOff(channel, chord, delay);
MIDI.keyToNote = object; // A0 => 21
MIDI.noteToKey = object; // 21 => A0
</pre></li>
<li><a href="./js/MIDI.Player.js">MIDI.Player.js</a>: &nbsp;Streams the MIDI to the browser.
<li class="indent">
<pre>
MIDI.Player.currentTime = integer; // time we are at now within the song.
MIDI.Player.endTime = integer; // time when song ends.
MIDI.Player.playing = boolean; // are we playing? yes or no.
MIDI.Player.loadFile(file, callback); // load .MIDI from base64 or binary XML request.
MIDI.Player.start(); // start the MIDI track (you can put this in the loadFile callback)
MIDI.Player.resume(); // resume the MIDI track from pause.
MIDI.Player.pause(); // pause the MIDI track.
MIDI.Player.stop(); // stops all audio being played, and resets currentTime to 0.
<b>Callback whenever a note is played;</b>
MIDI.Player.removeListener(); // removes current listener.
MIDI.Player.addListener(function(data) { // set it to your own function!
var now = data.now; // where we are now
var end = data.end; // time when song ends
var channel = data.channel; // channel note is playing on
var message = data.message; // 128 is noteOff, 144 is noteOn
var note = data.note; // the note
var velocity = data.velocity; // the velocity of the note
// then do whatever you want with the information!
});
<b>Smooth animation, interpolates between onMidiEvent calls;</b>
MIDI.Player.clearAnimation(); // clears current animation.
MIDI.Player.setAnimation(function(data) {
var now = data.now; // where we are now
var end = data.end; // time when song ends
var events = data.events; // all the notes currently being processed
// then do what you want with the information!
});</pre></li>
</li>
<li><a href="./js/Color.js">Color.js</a>: &nbsp;Color conversions, music isn&rsquo;t complete without!</li>
<li class="indent"><pre>Color.Space(0xff0000, "HEX>RGB>HSL");</pre></li>
<li><a href="./js/DOMLoader.script.js">DOMLoader.script.js</a>: &nbsp;Loads scripts in synchronously, or asynchronously.</li>
<li class="indent"><pre>DOMLoader.script.add(src, callback);</pre></li>
<li><a href="./js/DOMLoader.XMLHttp.js">DOMLoader.XMLHttp.js</a>: &nbsp;Cross-browser XMLHttpd request.</li>
<li class="indent"><pre>DOMLoader.sendRequest(src, callback);</pre></li>
<li><a href="./js/MusicTheory.Synesthesia.js">MusicTheory.Synesthesia.js</a>: &nbsp;Note-to-color mappings (from Isaac Newton onwards).</li>
<h3>Many thanks to the authors of these libraries;</h3>
<li><a href="http://dev.w3.org/html5/spec/Overview.html">&lt;audio&gt;</a>: &nbsp;HTML5 specs</li>
<li><a href="https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html">WebAudioAPI</a>: &nbsp;W3C proposal by Google</li>
<li>Java package: &nbsp;<a href="https://github.com/abudaan/midibridge-js">MIDIBridge</a> by <a href="http://abumarkub.net">Daniel van der Meer</a></li>
<li class="indent square">Use this to hook up a MIDI keyboard to your browser!</li>
<li class="indent square">Access to 128 General MIDI instruments.</li>
<li>Flash package: &nbsp;<a href="http://www.schillmania.com/projects/soundmanager2/">SoundManager2</a> by <a href="http://schillmania.com">Scott Schiller</a></li>
<li><a href="https://github.com/gasman/jasmid">jasmid</a>: &nbsp;Reads MIDI file byte-code, and translats into a Javascript array.</li>
<li><a href="http://blog.danguer.com/2011/10/24/base64-binary-decoding-in-javascript/">base642binary.js</a>: &nbsp;Cleans up XML base64-requests for Web Audio API.</li>

112
WhitneyMusicBox.html Normal file
View file

@ -0,0 +1,112 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Whitney Music Box in HTML5</title>
<script src="./js/Color.js" type="text/javascript"></script>
<script src="./js/Event.js" type="text/javascript"></script>
<script src="./js/DOMLoader.XMLHttp.js" type="text/javascript"></script>
<script src="./js/DOMLoader.script.js" type="text/javascript"></script>
<script src="./js/MIDI.audioDetect.js" type="text/javascript"></script>
<script src="./js/MIDI.loadPlugin.js" type="text/javascript"></script>
<script src="./js/MIDI.Plugin.js" type="text/javascript"></script>
<script src="./js/MIDI.Player.js" type="text/javascript"></script>
<script src="./js/MusicTheory.Synesthesia.js" type="text/javascript"></script>
<script src="./js/VersionControl.Base64.js" type="text/javascript"></script>
<script src="./js/Widgets.Loader.js" type="text/javascript"></script>
<!-- base642binary package -->
<script src="./js/lib/base64binary.js" type="text/javascript"></script>
<!-- google fonts package -->
<link href="http://fonts.googleapis.com/css?family=Andada" rel="stylesheet" type="text/css" />
<style>
body {
background: #000; color: #fff; font-family: andada; line-height: 1.5em;
}
a {
color: #fff
}
</style>
</head>
<body>
Whitney Music Box animation in HTML5.<br>
Graphics code by <a href="https://github.com/jbum/Whitney-Music-Box-Examples">Jim Bumgardner</a>.<br>
Audio created with <a href="https://github.com/mudx/MIDI.js">MIDI.js</a><br>
<canvas id="mycanvas" />
<script type="text/javascript">
var dc;
var nbrPoints = 48;
var cycleLength = 60 * 3; // 3 minutes
var gw = 800;
var gh = 800;
var cx = gw / 2;
var cy = gh / 2;
var circleRadius = (gw / 2) * 0.95;
var startTime = (new Date()).getTime();
var PI = 3.1415927;
var PI2 = PI * 2;
var tines = [];
var lastSound = [];
RefreshFrame = function () {
dc.clearRect(0, 0, gw, gh);
dc.lineWidth = 3;
dc.strokeStyle = '#333';
dc.beginPath();
dc.moveTo(cx, cy);
dc.lineTo(gw, cy);
dc.stroke();
var speed = (2 * PI * nbrPoints) / cycleLength;
var ms = (new Date()).getTime();
var timer = (ms - startTime) * .001 * speed;
var maxRad = (gw / 2 - circleRadius) * .75;
var minRad = maxRad * .2;
for (var i = 0; i < nbrPoints; ++i) {
var r = (i + 1) / nbrPoints;
var a = timer * r;
var len = circleRadius * (1 + 1.0 / nbrPoints - r);
if (Math.floor(a / PI2) !== Math.floor(tines[i] / PI2)) {
MIDI.noteOn(0, i + 21, 100, 0);
MIDI.noteOn(0, i + 21 + 36, 100, 0);
lastSound[i] = ms;
}
var x = (cx + Math.cos(a) * len);
var y = (cy + Math.sin(a) * len);
var radv = minRad + (maxRad - minRad) * (1 - r);
radv = Math.max((radv + 6) - 6 * (ms - lastSound[i]) / 500.0, radv);
var huev = r * 360;
var satv = Math.round(100 * Math.min(1, (ms - lastSound[i]) / 1000.0));
var lumv = Math.round(100 * Math.max(0.5, 1 - (ms - lastSound[i]) / 1000.0));
dc.fillStyle = 'hsla(' + huev + ',' + satv + '%,' + lumv + '%,1)';
dc.beginPath();
dc.arc(x, y, radv, 0, PI2, false);
dc.fill();
tines[i] = a;
}
};
window.onload = function () {
MIDI.loadPlugin(function() {
loader.stop();
var canvas = document.getElementById('mycanvas');
canvas.style.width = gw + "px";
canvas.style.width = gw + "px";
canvas.width = gw;
canvas.height = gh;
dc = canvas.getContext('2d');
for (var i = 0; i < nbrPoints; ++i) {
if (i % 7 === 0) MIDI.noteOn(0, i + 21, 100, 0);
lastSound[i] = 0;
tines[i] = 0;
}
startTime = (new Date()).getTime();
setInterval(RefreshFrame, 1000 / 30);
});
};
var loader = new widgets.Loader({
message: "loading: Music Box..."
});
</script>
</body>
</html>

BIN
images/backward.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
images/forward.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
images/pause.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
images/play.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
images/shiverMeTimbers.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 953 B

BIN
images/stop.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
images/tuna.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

29
inc/SoundManager2/license.txt Executable file
View file

@ -0,0 +1,29 @@
Software License Agreement (BSD License)
Copyright (c) 2007, Scott Schiller (schillmania.com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
* Neither the name of schillmania.com nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission from schillmania.com.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -0,0 +1,104 @@
/** @license
SoundManager 2: JavaScript Sound for the Web
----------------------------------------------
http://schillmania.com/projects/soundmanager2/
Copyright (c) 2007, Scott Schiller. All rights reserved.
Code provided under the BSD License:
http://schillmania.com/projects/soundmanager2/license.txt
V2.97a.20111220
*/
(function(G){function W(W,la){function l(b){return function(a){var d=this._t;return!d||!d._a?(d&&d.sID?c._wD(k+"ignoring "+a.type+": "+d.sID):c._wD(k+"ignoring "+a.type),null):b.call(this,a)}}this.flashVersion=8;this.debugMode=!0;this.debugFlash=!1;this.consoleOnly=this.useConsole=!0;this.waitForWindowLoad=!1;this.bgColor="#ffffff";this.useHighPerformance=!1;this.html5PollingInterval=this.flashPollingInterval=null;this.flashLoadTimeout=1E3;this.wmode=null;this.allowScriptAccess="always";this.useFlashBlock=
!1;this.useHTML5Audio=!0;this.html5Test=/^(probably|maybe)$/i;this.preferFlash=!0;this.noSWFCache=!1;this.audioFormats={mp3:{type:['audio/mpeg; codecs="mp3"',"audio/mpeg","audio/mp3","audio/MPA","audio/mpa-robust"],required:!0},mp4:{related:["aac","m4a"],type:['audio/mp4; codecs="mp4a.40.2"',"audio/aac","audio/x-m4a","audio/MP4A-LATM","audio/mpeg4-generic"],required:!1},ogg:{type:["audio/ogg; codecs=vorbis"],required:!1},wav:{type:['audio/wav; codecs="1"',"audio/wav","audio/wave","audio/x-wav"],required:!1}};
this.defaultOptions={autoLoad:!1,autoPlay:!1,from:null,loops:1,onid3:null,onload:null,whileloading:null,onplay:null,onpause:null,onresume:null,whileplaying:null,onposition:null,onstop:null,onfailure:null,onfinish:null,multiShot:!0,multiShotEvents:!1,position:null,pan:0,stream:!0,to:null,type:null,usePolicyFile:!1,volume:100};this.flash9Options={isMovieStar:null,usePeakData:!1,useWaveformData:!1,useEQData:!1,onbufferchange:null,ondataerror:null};this.movieStarOptions={bufferTime:3,serverURL:null,onconnect:null,
duration:null};this.movieID="sm2-container";this.id=la||"sm2movie";this.debugID="soundmanager-debug";this.debugURLParam=/([#?&])debug=1/i;this.versionNumber="V2.97a.20111220";this.movieURL=this.version=null;this.url=W||null;this.altURL=null;this.enabled=this.swfLoaded=!1;this.oMC=null;this.sounds={};this.soundIDs=[];this.didFlashBlock=this.muted=!1;this.filePattern=null;this.filePatterns={flash8:/\.mp3(\?.*)?$/i,flash9:/\.mp3(\?.*)?$/i};this.features={buffering:!1,peakData:!1,waveformData:!1,eqData:!1,
movieStar:!1};this.sandbox={type:null,types:{remote:"remote (domain-based) rules",localWithFile:"local with file access (no internet access)",localWithNetwork:"local with network (internet access only, no local access)",localTrusted:"local, trusted (local+internet access)"},description:null,noRemote:null,noLocal:null};var ma;try{ma="undefined"!==typeof Audio&&"undefined"!==typeof(new Audio).canPlayType}catch(fb){ma=!1}this.hasHTML5=ma;this.html5={usingFlash:null};this.flash={};this.ignoreFlash=this.html5Only=
!1;var Ea,c=this,i=null,k="HTML5::",u,p=navigator.userAgent,j=G,O=j.location.href.toString(),h=document,na,X,m,B=[],oa=!0,w,P=!1,Q=!1,n=!1,y=!1,Y=!1,o,Za=0,R,v,pa,H,I,Z,Fa,qa,E,$,aa,J,ra,sa,ba,ca,K,Ga,ta,$a=["log","info","warn","error"],Ha,da,Ia,S=null,ua=null,q,va,L,Ja,ea,fa,wa,s,ga=!1,xa=!1,Ka,La,Ma,ha=0,T=null,ia,z=null,Na,ja,U,C,ya,za,Oa,r,Pa=Array.prototype.slice,F=!1,t,ka,Qa,A,Ra,Aa=p.match(/(ipad|iphone|ipod)/i),ab=p.match(/firefox/i),bb=p.match(/droid/i),D=p.match(/msie/i),cb=p.match(/webkit/i),
V=p.match(/safari/i)&&!p.match(/chrome/i),db=p.match(/opera/i),Ba=p.match(/(mobile|pre\/|xoom)/i)||Aa,Ca=!O.match(/usehtml5audio/i)&&!O.match(/sm2\-ignorebadua/i)&&V&&!p.match(/silk/i)&&p.match(/OS X 10_6_([3-7])/i),Sa="undefined"!==typeof console&&"undefined"!==typeof console.log,Da="undefined"!==typeof h.hasFocus?h.hasFocus():null,M=V&&"undefined"===typeof h.hasFocus,Ta=!M,Ua=/(mp3|mp4|mpa)/i,N=h.location?h.location.protocol.match(/http/i):null,Va=!N?"http://":"",Wa=/^\s*audio\/(?:x-)?(?:mpeg4|aac|flv|mov|mp4||m4v|m4a|mp4v|3gp|3g2)\s*(?:$|;)/i,
Xa="mpeg4,aac,flv,mov,mp4,m4v,f4v,m4a,mp4v,3gp,3g2".split(","),eb=RegExp("\\.("+Xa.join("|")+")(\\?.*)?$","i");this.mimePattern=/^\s*audio\/(?:x-)?(?:mp(?:eg|3))\s*(?:$|;)/i;this.useAltURL=!N;this._global_a=null;if(Ba&&(c.useHTML5Audio=!0,c.preferFlash=!1,Aa))F=c.ignoreFlash=!0;this.supported=this.ok=function(){return z?n&&!y:c.useHTML5Audio&&c.hasHTML5};this.getMovie=function(c){return u(c)||h[c]||j[c]};this.createSound=function(b){function a(){f=ea(f);c.sounds[e.id]=new Ea(e);c.soundIDs.push(e.id);
return c.sounds[e.id]}var d,f=null,e=d=null;d="soundManager.createSound(): "+q(!n?"notReady":"notOK");if(!n||!c.ok())return wa(d),!1;2===arguments.length&&(b={id:arguments[0],url:arguments[1]});f=v(b);f.url=ia(f.url);e=f;e.id.toString().charAt(0).match(/^[0-9]$/)&&c._wD("soundManager.createSound(): "+q("badID",e.id),2);c._wD("soundManager.createSound(): "+e.id+" ("+e.url+")",1);if(s(e.id,!0))return c._wD("soundManager.createSound(): "+e.id+" exists",1),c.sounds[e.id];if(ja(e))d=a(),c._wD("Loading sound "+
e.id+" via HTML5"),d._setup_html5(e);else{if(8<m){if(null===e.isMovieStar)e.isMovieStar=e.serverURL||(e.type?e.type.match(Wa):!1)||e.url.match(eb);e.isMovieStar&&c._wD("soundManager.createSound(): using MovieStar handling");if(e.isMovieStar){if(e.usePeakData)o("noPeak"),e.usePeakData=!1;1<e.loops&&o("noNSLoop")}}e=fa(e,"soundManager.createSound(): ");d=a();if(8===m)i._createSound(e.id,e.loops||1,e.usePolicyFile);else if(i._createSound(e.id,e.url,e.usePeakData,e.useWaveformData,e.useEQData,e.isMovieStar,
e.isMovieStar?e.bufferTime:!1,e.loops||1,e.serverURL,e.duration||null,e.autoPlay,!0,e.autoLoad,e.usePolicyFile),!e.serverURL)d.connected=!0,e.onconnect&&e.onconnect.apply(d);!e.serverURL&&(e.autoLoad||e.autoPlay)&&d.load(e)}!e.serverURL&&e.autoPlay&&d.play();return d};this.destroySound=function(b,a){if(!s(b))return!1;var d=c.sounds[b],f;d._iO={};d.stop();d.unload();for(f=0;f<c.soundIDs.length;f++)if(c.soundIDs[f]===b){c.soundIDs.splice(f,1);break}a||d.destruct(!0);delete c.sounds[b];return!0};this.load=
function(b,a){return!s(b)?!1:c.sounds[b].load(a)};this.unload=function(b){return!s(b)?!1:c.sounds[b].unload()};this.onposition=this.onPosition=function(b,a,d,f){return!s(b)?!1:c.sounds[b].onposition(a,d,f)};this.clearOnPosition=function(b,a,d){return!s(b)?!1:c.sounds[b].clearOnPosition(a,d)};this.start=this.play=function(b,a){if(!n||!c.ok())return wa("soundManager.play(): "+q(!n?"notReady":"notOK")),!1;if(!s(b)){a instanceof Object||(a={url:a});return a&&a.url?(c._wD('soundManager.play(): attempting to create "'+
b+'"',1),a.id=b,c.createSound(a).play()):!1}return c.sounds[b].play(a)};this.setPosition=function(b,a){return!s(b)?!1:c.sounds[b].setPosition(a)};this.stop=function(b){if(!s(b))return!1;c._wD("soundManager.stop("+b+")",1);return c.sounds[b].stop()};this.stopAll=function(){var b;c._wD("soundManager.stopAll()",1);for(b in c.sounds)c.sounds.hasOwnProperty(b)&&c.sounds[b].stop()};this.pause=function(b){return!s(b)?!1:c.sounds[b].pause()};this.pauseAll=function(){var b;for(b=c.soundIDs.length;b--;)c.sounds[c.soundIDs[b]].pause()};
this.resume=function(b){return!s(b)?!1:c.sounds[b].resume()};this.resumeAll=function(){var b;for(b=c.soundIDs.length;b--;)c.sounds[c.soundIDs[b]].resume()};this.togglePause=function(b){return!s(b)?!1:c.sounds[b].togglePause()};this.setPan=function(b,a){return!s(b)?!1:c.sounds[b].setPan(a)};this.setVolume=function(b,a){return!s(b)?!1:c.sounds[b].setVolume(a)};this.mute=function(b){var a=0;"string"!==typeof b&&(b=null);if(b){if(!s(b))return!1;c._wD('soundManager.mute(): Muting "'+b+'"');return c.sounds[b].mute()}c._wD("soundManager.mute(): Muting all sounds");
for(a=c.soundIDs.length;a--;)c.sounds[c.soundIDs[a]].mute();return c.muted=!0};this.muteAll=function(){c.mute()};this.unmute=function(b){"string"!==typeof b&&(b=null);if(b){if(!s(b))return!1;c._wD('soundManager.unmute(): Unmuting "'+b+'"');return c.sounds[b].unmute()}c._wD("soundManager.unmute(): Unmuting all sounds");for(b=c.soundIDs.length;b--;)c.sounds[c.soundIDs[b]].unmute();c.muted=!1;return!0};this.unmuteAll=function(){c.unmute()};this.toggleMute=function(b){return!s(b)?!1:c.sounds[b].toggleMute()};
this.getMemoryUse=function(){var c=0;i&&8!==m&&(c=parseInt(i._getMemoryUse(),10));return c};this.disable=function(b){var a;"undefined"===typeof b&&(b=!1);if(y)return!1;y=!0;o("shutdown",1);for(a=c.soundIDs.length;a--;)Ha(c.sounds[c.soundIDs[a]]);R(b);r.remove(j,"load",I);return!0};this.canPlayMIME=function(b){var a;c.hasHTML5&&(a=U({type:b}));return!z||a?a:b?!!(8<m&&b.match(Wa)||b.match(c.mimePattern)):null};this.canPlayURL=function(b){var a;c.hasHTML5&&(a=U({url:b}));return!z||a?a:b?!!b.match(c.filePattern):
null};this.canPlayLink=function(b){return"undefined"!==typeof b.type&&b.type&&c.canPlayMIME(b.type)?!0:c.canPlayURL(b.href)};this.getSoundById=function(b,a){if(!b)throw Error("soundManager.getSoundById(): sID is null/undefined");var d=c.sounds[b];!d&&!a&&c._wD('"'+b+'" is an invalid sound ID.',2);return d};this.onready=function(b,a){if(b&&b instanceof Function)return n&&c._wD(q("queue","onready")),a||(a=j),pa("onready",b,a),H(),!0;throw q("needFunction","onready");};this.ontimeout=function(b,a){if(b&&
b instanceof Function)return n&&c._wD(q("queue","ontimeout")),a||(a=j),pa("ontimeout",b,a),H({type:"ontimeout"}),!0;throw q("needFunction","ontimeout");};this._wD=this._writeDebug=function(b,a,d){var f,e;if(!c.debugMode)return!1;"undefined"!==typeof d&&d&&(b=b+" | "+(new Date).getTime());if(Sa&&c.useConsole){d=$a[a];if("undefined"!==typeof console[d])console[d](b);else console.log(b);if(c.consoleOnly)return!0}try{f=u("soundmanager-debug");if(!f)return!1;e=h.createElement("div");if(0===++Za%2)e.className=
"sm2-alt";a="undefined"===typeof a?0:parseInt(a,10);e.appendChild(h.createTextNode(b));if(a){if(2<=a)e.style.fontWeight="bold";if(3===a)e.style.color="#ff3333"}f.insertBefore(e,f.firstChild)}catch(i){}return!0};this._debug=function(){var b,a;o("currentObj",1);for(b=0,a=c.soundIDs.length;b<a;b++)c.sounds[c.soundIDs[b]]._debug()};this.reboot=function(){c._wD("soundManager.reboot()");c.soundIDs.length&&c._wD("Destroying "+c.soundIDs.length+" SMSound objects...");var b,a;for(b=c.soundIDs.length;b--;)c.sounds[c.soundIDs[b]].destruct();
try{if(D)ua=i.innerHTML;S=i.parentNode.removeChild(i);c._wD("Flash movie removed.")}catch(d){o("badRemove",2)}ua=S=z=null;c.enabled=sa=n=ga=xa=P=Q=y=c.swfLoaded=!1;c.soundIDs=c.sounds=[];i=null;for(b in B)if(B.hasOwnProperty(b))for(a=B[b].length;a--;)B[b][a].fired=!1;c._wD("soundManager: Rebooting...");j.setTimeout(c.beginDelayedInit,20)};this.getMoviePercent=function(){return i&&"undefined"!==typeof i.PercentLoaded?i.PercentLoaded():null};this.beginDelayedInit=function(){Y=!0;J();setTimeout(function(){if(xa)return!1;
ca();aa();return xa=!0},20);Z()};this.destruct=function(){c._wD("soundManager.destruct()");c.disable(!0)};Ea=function(b){var a=this,d,f,e,h,g,Ya,j=!1,x=[],l=0,n,r,p=null,t=null,u=null;this.sID=b.id;this.url=b.url;this._iO=this.instanceOptions=this.options=v(b);this.pan=this.options.pan;this.volume=this.options.volume;this.isHTML5=!1;this._a=null;this.id3={};this._debug=function(){if(c.debugMode){var b=null,e=[],d,f;for(b in a.options)null!==a.options[b]&&(a.options[b]instanceof Function?(d=a.options[b].toString(),
d=d.replace(/\s\s+/g," "),f=d.indexOf("{"),e.push(" "+b+": {"+d.substr(f+1,Math.min(Math.max(d.indexOf("\n")-1,64),64)).replace(/\n/g,"")+"... }")):e.push(" "+b+": "+a.options[b]));c._wD("SMSound() merged options: {\n"+e.join(", \n")+"\n}")}};this._debug();this.load=function(b){var d=null;if("undefined"!==typeof b)a._iO=v(b,a.options),a.instanceOptions=a._iO;else if(b=a.options,a._iO=b,a.instanceOptions=a._iO,p&&p!==a.url)o("manURL"),a._iO.url=a.url,a.url=null;if(!a._iO.url)a._iO.url=a.url;a._iO.url=
ia(a._iO.url);c._wD("SMSound.load(): "+a._iO.url,1);if(a._iO.url===a.url&&0!==a.readyState&&2!==a.readyState)return o("onURL",1),3===a.readyState&&a._iO.onload&&a._iO.onload.apply(a,[!!a.duration]),a;b=a._iO;p=a.url;a.loaded=!1;a.readyState=1;a.playState=0;if(ja(b))d=a._setup_html5(b),d._called_load?c._wD(k+"ignoring request to load again: "+a.sID):(c._wD(k+"load: "+a.sID),a._html5_canplay=!1,a._a.autobuffer="auto",a._a.preload="auto",d.load(),d._called_load=!0,b.autoPlay&&a.play());else try{a.isHTML5=
!1,a._iO=fa(ea(b)),b=a._iO,8===m?i._load(a.sID,b.url,b.stream,b.autoPlay,b.whileloading?1:0,b.loops||1,b.usePolicyFile):i._load(a.sID,b.url,!!b.stream,!!b.autoPlay,b.loops||1,!!b.autoLoad,b.usePolicyFile)}catch(e){o("smError",2),w("onload",!1),K({type:"SMSOUND_LOAD_JS_EXCEPTION",fatal:!0})}return a};this.unload=function(){0!==a.readyState&&(c._wD('SMSound.unload(): "'+a.sID+'"'),a.isHTML5?(h(),a._a&&(a._a.pause(),ya(a._a))):8===m?i._unload(a.sID,"about:blank"):i._unload(a.sID),d());return a};this.destruct=
function(b){c._wD('SMSound.destruct(): "'+a.sID+'"');if(a.isHTML5){if(h(),a._a)a._a.pause(),ya(a._a),F||e(),a._a._t=null,a._a=null}else a._iO.onfailure=null,i._destroySound(a.sID);b||c.destroySound(a.sID,!0)};this.start=this.play=function(b,d){var e,d=void 0===d?!0:d;b||(b={});a._iO=v(b,a._iO);a._iO=v(a._iO,a.options);a._iO.url=ia(a._iO.url);a.instanceOptions=a._iO;if(a._iO.serverURL&&!a.connected)return a.getAutoPlay()||(c._wD("SMSound.play(): Netstream not connected yet - setting autoPlay"),a.setAutoPlay(!0)),
a;ja(a._iO)&&(a._setup_html5(a._iO),g());if(1===a.playState&&!a.paused)if(e=a._iO.multiShot)c._wD('SMSound.play(): "'+a.sID+'" already playing (multi-shot)',1);else return c._wD('SMSound.play(): "'+a.sID+'" already playing (one-shot)',1),a;if(a.loaded)c._wD('SMSound.play(): "'+a.sID+'"');else if(0===a.readyState){c._wD('SMSound.play(): Attempting to load "'+a.sID+'"',1);if(!a.isHTML5)a._iO.autoPlay=!0;a.load(a._iO)}else{if(2===a.readyState)return c._wD('SMSound.play(): Could not load "'+a.sID+'" - exiting',
2),a;c._wD('SMSound.play(): "'+a.sID+'" is loading - attempting to play..',1)}if(!a.isHTML5&&9===m&&0<a.position&&a.position===a.duration)c._wD('SMSound.play(): "'+a.sID+'": Sound at end, resetting to position:0'),b.position=0;if(a.paused&&a.position&&0<a.position)c._wD('SMSound.play(): "'+a.sID+'" is resuming from paused state',1),a.resume();else{a._iO=v(b,a._iO);if(null!==a._iO.from&&null!==a._iO.to&&0===a.instanceCount&&0===a.playState&&!a._iO.serverURL){e=function(){a._iO=v(b,a._iO);a.play(a._iO)};
if(a.isHTML5&&!a._html5_canplay)return c._wD('SMSound.play(): Beginning load of "'+a.sID+'" for from/to case'),a.load({_oncanplay:e}),!1;if(!a.isHTML5&&!a.loaded&&(!a.readyState||2!==a.readyState))return c._wD('SMSound.play(): Preloading "'+a.sID+'" for from/to case'),a.load({onload:e}),!1;a._iO=r()}c._wD('SMSound.play(): "'+a.sID+'" is starting to play');(!a.instanceCount||a._iO.multiShotEvents||!a.isHTML5&&8<m&&!a.getAutoPlay())&&a.instanceCount++;0===a.playState&&a._iO.onposition&&Ya(a);a.playState=
1;a.paused=!1;a.position="undefined"!==typeof a._iO.position&&!isNaN(a._iO.position)?a._iO.position:0;if(!a.isHTML5)a._iO=fa(ea(a._iO));a._iO.onplay&&d&&(a._iO.onplay.apply(a),j=!0);a.setVolume(a._iO.volume,!0);a.setPan(a._iO.pan,!0);a.isHTML5?(g(),e=a._setup_html5(),a.setPosition(a._iO.position),e.play()):i._start(a.sID,a._iO.loops||1,9===m?a._iO.position:a._iO.position/1E3)}return a};this.stop=function(c){var b=a._iO;if(1===a.playState){a._onbufferchange(0);a._resetOnPosition(0);a.paused=!1;if(!a.isHTML5)a.playState=
0;n();b.to&&a.clearOnPosition(b.to);if(a.isHTML5){if(a._a)c=a.position,a.setPosition(0),a.position=c,a._a.pause(),a.playState=0,a._onTimer(),h()}else i._stop(a.sID,c),b.serverURL&&a.unload();a.instanceCount=0;a._iO={};b.onstop&&b.onstop.apply(a)}return a};this.setAutoPlay=function(b){c._wD("sound "+a.sID+" turned autoplay "+(b?"on":"off"));a._iO.autoPlay=b;a.isHTML5||(i._setAutoPlay(a.sID,b),b&&!a.instanceCount&&1===a.readyState&&(a.instanceCount++,c._wD("sound "+a.sID+" incremented instance count to "+
a.instanceCount)))};this.getAutoPlay=function(){return a._iO.autoPlay};this.setPosition=function(b){void 0===b&&(b=0);var d=a.isHTML5?Math.max(b,0):Math.min(a.duration||a._iO.duration,Math.max(b,0));a.position=d;b=a.position/1E3;a._resetOnPosition(a.position);a._iO.position=d;if(a.isHTML5){if(a._a)if(a._html5_canplay){if(a._a.currentTime!==b){c._wD("setPosition("+b+"): setting position");try{a._a.currentTime=b,(0===a.playState||a.paused)&&a._a.pause()}catch(e){c._wD("setPosition("+b+"): setting position failed: "+
e.message,2)}}}else c._wD("setPosition("+b+"): delaying, sound not ready")}else b=9===m?a.position:b,a.readyState&&2!==a.readyState&&i._setPosition(a.sID,b,a.paused||!a.playState);a.isHTML5&&a.paused&&a._onTimer(!0);return a};this.pause=function(b){if(a.paused||0===a.playState&&1!==a.readyState)return a;c._wD("SMSound.pause()");a.paused=!0;a.isHTML5?(a._setup_html5().pause(),h()):(b||void 0===b)&&i._pause(a.sID);a._iO.onpause&&a._iO.onpause.apply(a);return a};this.resume=function(){var b=a._iO;if(!a.paused)return a;
c._wD("SMSound.resume()");a.paused=!1;a.playState=1;a.isHTML5?(a._setup_html5().play(),g()):(b.isMovieStar&&!b.serverURL&&a.setPosition(a.position),i._pause(a.sID));j&&b.onplay?(b.onplay.apply(a),j=!0):b.onresume&&b.onresume.apply(a);return a};this.togglePause=function(){c._wD("SMSound.togglePause()");if(0===a.playState)return a.play({position:9===m&&!a.isHTML5?a.position:a.position/1E3}),a;a.paused?a.resume():a.pause();return a};this.setPan=function(b,c){"undefined"===typeof b&&(b=0);"undefined"===
typeof c&&(c=!1);a.isHTML5||i._setPan(a.sID,b);a._iO.pan=b;if(!c)a.pan=b,a.options.pan=b;return a};this.setVolume=function(b,d){"undefined"===typeof b&&(b=100);"undefined"===typeof d&&(d=!1);if(a.isHTML5){if(a._a)a._a.volume=Math.max(0,Math.min(1,b/100))}else i._setVolume(a.sID,c.muted&&!a.muted||a.muted?0:b);a._iO.volume=b;if(!d)a.volume=b,a.options.volume=b;return a};this.mute=function(){a.muted=!0;if(a.isHTML5){if(a._a)a._a.muted=!0}else i._setVolume(a.sID,0);return a};this.unmute=function(){a.muted=
!1;var b="undefined"!==typeof a._iO.volume;if(a.isHTML5){if(a._a)a._a.muted=!1}else i._setVolume(a.sID,b?a._iO.volume:a.options.volume);return a};this.toggleMute=function(){return a.muted?a.unmute():a.mute()};this.onposition=this.onPosition=function(b,c,d){x.push({position:b,method:c,scope:"undefined"!==typeof d?d:a,fired:!1});return a};this.clearOnPosition=function(a,b){var c,a=parseInt(a,10);if(isNaN(a))return!1;for(c=0;c<x.length;c++)if(a===x[c].position&&(!b||b===x[c].method))x[c].fired&&l--,
x.splice(c,1)};this._processOnPosition=function(){var b,c;b=x.length;if(!b||!a.playState||l>=b)return!1;for(;b--;)if(c=x[b],!c.fired&&a.position>=c.position)c.fired=!0,l++,c.method.apply(c.scope,[c.position]);return!0};this._resetOnPosition=function(a){var b,c;b=x.length;if(!b)return!1;for(;b--;)if(c=x[b],c.fired&&a<=c.position)c.fired=!1,l--;return!0};r=function(){var b=a._iO,d=b.from,e=b.to,f,g;g=function(){c._wD(a.sID+': "to" time of '+e+" reached.");a.clearOnPosition(e,g);a.stop()};f=function(){c._wD(a.sID+
': playing "from" '+d);if(null!==e&&!isNaN(e))a.onPosition(e,g)};if(null!==d&&!isNaN(d))b.position=d,b.multiShot=!1,f();return b};Ya=function(){var b=a._iO.onposition;if(b)for(var c in b)if(b.hasOwnProperty(c))a.onPosition(parseInt(c,10),b[c])};n=function(){var b=a._iO.onposition;if(b)for(var c in b)b.hasOwnProperty(c)&&a.clearOnPosition(parseInt(c,10))};g=function(){a.isHTML5&&Ka(a)};h=function(){a.isHTML5&&La(a)};d=function(){x=[];l=0;j=!1;a._hasTimer=null;a._a=null;a._html5_canplay=!1;a.bytesLoaded=
null;a.bytesTotal=null;a.duration=a._iO&&a._iO.duration?a._iO.duration:null;a.durationEstimate=null;a.eqData=[];a.eqData.left=[];a.eqData.right=[];a.failures=0;a.isBuffering=!1;a.instanceOptions={};a.instanceCount=0;a.loaded=!1;a.metadata={};a.readyState=0;a.muted=!1;a.paused=!1;a.peakData={left:0,right:0};a.waveformData={left:[],right:[]};a.playState=0;a.position=null};d();this._onTimer=function(b){var c,d=!1,e={};if(a._hasTimer||b){if(a._a&&(b||(0<a.playState||1===a.readyState)&&!a.paused)){c=a._get_html5_duration();
if(c!==t)t=c,a.duration=c,d=!0;a.durationEstimate=a.duration;c=1E3*a._a.currentTime||0;c!==u&&(u=c,d=!0);(d||b)&&a._whileplaying(c,e,e,e,e);return d}return!1}};this._get_html5_duration=function(){var b=a._iO,c=a._a?1E3*a._a.duration:b?b.duration:void 0;return c&&!isNaN(c)&&Infinity!==c?c:b?b.duration:null};this._setup_html5=function(b){var b=v(a._iO,b),e=decodeURI,g=F?c._global_a:a._a,h=e(b.url),i=g&&g._t?g._t.instanceOptions:null;if(g){if(g._t&&(!F&&h===e(p)||F&&i.url===b.url&&(!p||p===i.url)))return g;
c._wD("setting new URL on existing object: "+h+(p?", old URL: "+p:""));F&&g._t&&g._t.playState&&b.url!==i.url&&g._t.stop();d();g.src=b.url;p=a.url=b.url;g._called_load=!1}else{c._wD("creating HTML5 Audio() element with URL: "+h);g=new Audio(b.url);g._called_load=!1;if(bb)g._called_load=!0;if(F)c._global_a=g}a.isHTML5=!0;a._a=g;g._t=a;f();g.loop=1<b.loops?"loop":"";b.autoLoad||b.autoPlay?a.load():(g.autobuffer=!1,g.preload="none");g.loop=1<b.loops?"loop":"";return g};f=function(){if(a._a._added_events)return!1;
var b;c._wD(k+"adding event listeners: "+a.sID);a._a._added_events=!0;for(b in A)A.hasOwnProperty(b)&&a._a&&a._a.addEventListener(b,A[b],!1);return!0};e=function(){var b;c._wD(k+"removing event listeners: "+a.sID);a._a._added_events=!1;for(b in A)A.hasOwnProperty(b)&&a._a&&a._a.removeEventListener(b,A[b],!1)};this._onload=function(b){var d,b=!!b;c._wD(d+'"'+a.sID+'"'+(b?" loaded.":" failed to load? - "+a.url),b?1:2);d="SMSound._onload(): ";!b&&!a.isHTML5&&(!0===c.sandbox.noRemote&&c._wD(d+q("noNet"),
1),!0===c.sandbox.noLocal&&c._wD(d+q("noLocal"),1));a.loaded=b;a.readyState=b?3:2;a._onbufferchange(0);a._iO.onload&&a._iO.onload.apply(a,[b]);return!0};this._onbufferchange=function(b){if(0===a.playState||b&&a.isBuffering||!b&&!a.isBuffering)return!1;a.isBuffering=1===b;a._iO.onbufferchange&&(c._wD("SMSound._onbufferchange(): "+b),a._iO.onbufferchange.apply(a));return!0};this._onsuspend=function(){a._iO.onsuspend&&(c._wD("SMSound._onsuspend()"),a._iO.onsuspend.apply(a));return!0};this._onfailure=
function(b,d,e){a.failures++;c._wD('SMSound._onfailure(): "'+a.sID+'" count '+a.failures);if(a._iO.onfailure&&1===a.failures)a._iO.onfailure(a,b,d,e);else c._wD("SMSound._onfailure(): ignoring")};this._onfinish=function(){var b=a._iO.onfinish;a._onbufferchange(0);a._resetOnPosition(0);if(a.instanceCount){a.instanceCount--;if(!a.instanceCount)n(),a.playState=0,a.paused=!1,a.instanceCount=0,a.instanceOptions={},a._iO={},h();if((!a.instanceCount||a._iO.multiShotEvents)&&b)c._wD('SMSound._onfinish(): "'+
a.sID+'"'),b.apply(a)}};this._whileloading=function(b,c,d,e){var f=a._iO;a.bytesLoaded=b;a.bytesTotal=c;a.duration=Math.floor(d);a.bufferLength=e;if(f.isMovieStar)a.durationEstimate=a.duration;else if(a.durationEstimate=f.duration?a.duration>f.duration?a.duration:f.duration:parseInt(a.bytesTotal/a.bytesLoaded*a.duration,10),void 0===a.durationEstimate)a.durationEstimate=a.duration;3!==a.readyState&&f.whileloading&&f.whileloading.apply(a)};this._whileplaying=function(b,c,d,e,f){var g=a._iO;if(isNaN(b)||
null===b)return!1;a.position=b;a._processOnPosition();if(!a.isHTML5&&8<m){if(g.usePeakData&&"undefined"!==typeof c&&c)a.peakData={left:c.leftPeak,right:c.rightPeak};if(g.useWaveformData&&"undefined"!==typeof d&&d)a.waveformData={left:d.split(","),right:e.split(",")};if(g.useEQData&&"undefined"!==typeof f&&f&&f.leftEQ&&(b=f.leftEQ.split(","),a.eqData=b,a.eqData.left=b,"undefined"!==typeof f.rightEQ&&f.rightEQ))a.eqData.right=f.rightEQ.split(",")}1===a.playState&&(!a.isHTML5&&8===m&&!a.position&&a.isBuffering&&
a._onbufferchange(0),g.whileplaying&&g.whileplaying.apply(a));return!0};this._onmetadata=function(b,d){c._wD('SMSound._onmetadata(): "'+this.sID+'" metadata received.');var e={},f,g;for(f=0,g=b.length;f<g;f++)e[b[f]]=d[f];a.metadata=e;a._iO.onmetadata&&a._iO.onmetadata.apply(a)};this._onid3=function(b,d){c._wD('SMSound._onid3(): "'+this.sID+'" ID3 data received.');var e=[],f,g;for(f=0,g=b.length;f<g;f++)e[b[f]]=d[f];a.id3=v(a.id3,e);a._iO.onid3&&a._iO.onid3.apply(a)};this._onconnect=function(b){b=
1===b;c._wD('SMSound._onconnect(): "'+a.sID+'"'+(b?" connected.":" failed to connect? - "+a.url),b?1:2);if(a.connected=b)a.failures=0,s(a.sID)&&(a.getAutoPlay()?a.play(void 0,a.getAutoPlay()):a._iO.autoLoad&&a.load()),a._iO.onconnect&&a._iO.onconnect.apply(a,[b])};this._ondataerror=function(b){0<a.playState&&(c._wD("SMSound._ondataerror(): "+b),a._iO.ondataerror&&a._iO.ondataerror.apply(a))}};ba=function(){return h.body||h._docElement||h.getElementsByTagName("div")[0]};u=function(b){return h.getElementById(b)};
v=function(b,a){var d={},f,e;for(f in b)b.hasOwnProperty(f)&&(d[f]=b[f]);f="undefined"===typeof a?c.defaultOptions:a;for(e in f)f.hasOwnProperty(e)&&"undefined"===typeof d[e]&&(d[e]=f[e]);return d};r=function(){function b(a){var a=Pa.call(a),b=a.length;c?(a[1]="on"+a[1],3<b&&a.pop()):3===b&&a.push(!1);return a}function a(a,b){var g=a.shift(),h=[f[b]];if(c)g[h](a[0],a[1]);else g[h].apply(g,a)}var c=j.attachEvent,f={add:c?"attachEvent":"addEventListener",remove:c?"detachEvent":"removeEventListener"};
return{add:function(){a(b(arguments),"add")},remove:function(){a(b(arguments),"remove")}}}();A={abort:l(function(){c._wD(k+"abort: "+this._t.sID)}),canplay:l(function(){var b=this._t;if(b._html5_canplay)return!0;b._html5_canplay=!0;c._wD(k+"canplay: "+b.sID+", "+b.url);b._onbufferchange(0);var a=!isNaN(b.position)?b.position/1E3:null;if(b.position&&this.currentTime!==a){c._wD(k+"canplay: setting position to "+a);try{this.currentTime=a}catch(d){c._wD(k+"setting position failed: "+d.message,2)}}b._iO._oncanplay&&
b._iO._oncanplay()}),load:l(function(){var b=this._t;b.loaded||(b._onbufferchange(0),b._whileloading(b.bytesTotal,b.bytesTotal,b._get_html5_duration()),b._onload(!0))}),emptied:l(function(){c._wD(k+"emptied: "+this._t.sID)}),ended:l(function(){var b=this._t;c._wD(k+"ended: "+b.sID);b._onfinish()}),error:l(function(){c._wD(k+"error: "+this.error.code);this._t._onload(!1)}),loadeddata:l(function(){var b=this._t,a=b.bytesTotal||1;c._wD(k+"loadeddata: "+this._t.sID);if(!b._loaded&&!V)b.duration=b._get_html5_duration(),
b._whileloading(a,a,b._get_html5_duration()),b._onload(!0)}),loadedmetadata:l(function(){c._wD(k+"loadedmetadata: "+this._t.sID)}),loadstart:l(function(){c._wD(k+"loadstart: "+this._t.sID);this._t._onbufferchange(1)}),play:l(function(){c._wD(k+"play: "+this._t.sID+", "+this._t.url);this._t._onbufferchange(0)}),playing:l(function(){c._wD(k+"playing: "+this._t.sID);this._t._onbufferchange(0)}),progress:l(function(b){var a=this._t;if(a.loaded)return!1;var d,f,e;e=0;var h="progress"===b.type;f=b.target.buffered;
var g=b.loaded||0,i=b.total||1;if(f&&f.length){for(d=f.length;d--;)e=f.end(d)-f.start(d);g=e/b.target.duration;if(h&&1<f.length){e=[];f=f.length;for(d=0;d<f;d++)e.push(b.target.buffered.start(d)+"-"+b.target.buffered.end(d));c._wD(k+"progress: timeRanges: "+e.join(", "))}h&&!isNaN(g)&&c._wD(k+"progress: "+a.sID+": "+Math.floor(100*g)+"% loaded")}isNaN(g)||(a._onbufferchange(0),a._whileloading(g,i,a._get_html5_duration()),g&&i&&g===i&&A.load.call(this,b))}),ratechange:l(function(){c._wD(k+"ratechange: "+
this._t.sID)}),suspend:l(function(b){var a=this._t;c._wD(k+"suspend: "+a.sID);A.progress.call(this,b);a._onsuspend()}),stalled:l(function(){c._wD(k+"stalled: "+this._t.sID)}),timeupdate:l(function(){this._t._onTimer()}),waiting:l(function(){var b=this._t;c._wD(k+"waiting: "+b.sID);b._onbufferchange(1)})};ja=function(b){return!b.serverURL&&(b.type?U({type:b.type}):U({url:b.url})||c.html5Only)};ya=function(b){if(b)b.src=ab?"":"about:blank"};U=function(b){function a(a){return c.preferFlash&&t&&!c.ignoreFlash&&
"undefined"!==typeof c.flash[a]&&c.flash[a]}if(!c.useHTML5Audio||!c.hasHTML5)return!1;var d=b.url||null,b=b.type||null,f=c.audioFormats,e;if(b&&"undefined"!==c.html5[b])return c.html5[b]&&!a(b);if(!C){C=[];for(e in f)f.hasOwnProperty(e)&&(C.push(e),f[e].related&&(C=C.concat(f[e].related)));C=RegExp("\\.("+C.join("|")+")(\\?.*)?$","i")}e=d?d.toLowerCase().match(C):null;if(!e||!e.length)if(b)d=b.indexOf(";"),e=(-1!==d?b.substr(0,d):b).substr(6);else return!1;else e=e[1];if(e&&"undefined"!==typeof c.html5[e])return c.html5[e]&&
!a(e);b="audio/"+e;d=c.html5.canPlayType({type:b});return(c.html5[e]=d)&&c.html5[b]&&!a(b)};Oa=function(){function b(b){var d,e,f=!1;if(!a||"function"!==typeof a.canPlayType)return!1;if(b instanceof Array){for(d=0,e=b.length;d<e&&!f;d++)if(c.html5[b[d]]||a.canPlayType(b[d]).match(c.html5Test))f=!0,c.html5[b[d]]=!0,c.flash[b[d]]=!(!c.preferFlash||!t||!b[d].match(Ua));return f}b=a&&"function"===typeof a.canPlayType?a.canPlayType(b):!1;return!(!b||!b.match(c.html5Test))}if(!c.useHTML5Audio||"undefined"===
typeof Audio)return!1;var a="undefined"!==typeof Audio?db?new Audio(null):new Audio:null,d,f={},e,h;e=c.audioFormats;for(d in e)if(e.hasOwnProperty(d)&&(f[d]=b(e[d].type),f["audio/"+d]=f[d],c.flash[d]=c.preferFlash&&!c.ignoreFlash&&d.match(Ua)?!0:!1,e[d]&&e[d].related))for(h=e[d].related.length;h--;)f["audio/"+e[d].related[h]]=f[d],c.html5[e[d].related[h]]=f[d],c.flash[e[d].related[h]]=f[d];f.canPlayType=a?b:null;c.html5=v(c.html5,f);return!0};$={notReady:"Not loaded yet - wait for soundManager.onload()/onready()",
notOK:"Audio support is not available.",domError:"soundManager::createMovie(): appendChild/innerHTML call failed. DOM not ready or other error.",spcWmode:"soundManager::createMovie(): Removing wmode, preventing known SWF loading issue(s)",swf404:"soundManager: Verify that %s is a valid path.",tryDebug:"Try soundManager.debugFlash = true for more security details (output goes to SWF.)",checkSWF:"See SWF output for more debug info.",localFail:"soundManager: Non-HTTP page ("+h.location.protocol+" URL?) Review Flash player security settings for this special case:\nhttp://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html\nMay need to add/allow path, eg. c:/sm2/ or /users/me/sm2/",
waitFocus:"soundManager: Special case: Waiting for focus-related event..",waitImpatient:"soundManager: Getting impatient, still waiting for Flash%s...",waitForever:"soundManager: Waiting indefinitely for Flash (will recover if unblocked)...",needFunction:"soundManager: Function object expected for %s",badID:'Warning: Sound ID "%s" should be a string, starting with a non-numeric character',currentObj:"--- soundManager._debug(): Current sound objects ---",waitEI:"soundManager::initMovie(): Waiting for ExternalInterface call from Flash..",
waitOnload:"soundManager: Waiting for window.onload()",docLoaded:"soundManager: Document already loaded",onload:"soundManager::initComplete(): calling soundManager.onload()",onloadOK:"soundManager.onload() complete",init:"soundManager::init()",didInit:"soundManager::init(): Already called?",flashJS:"soundManager: Attempting to call Flash from JS..",secNote:"Flash security note: Network/internet URLs will not load due to security restrictions. Access can be configured via Flash Player Global Security Settings Page: http://www.macromedia.com/support/documentation/en/flashplayer/help/settings_manager04.html",
badRemove:"Warning: Failed to remove flash movie.",noPeak:"Warning: peakData features unsupported for movieStar formats",shutdown:"soundManager.disable(): Shutting down",queue:"soundManager: Queueing %s handler",smFail:"soundManager: Failed to initialise.",smError:"SMSound.load(): Exception: JS-Flash communication failed, or JS error.",fbTimeout:"No flash response, applying .swf_timedout CSS..",fbLoaded:"Flash loaded",fbHandler:"soundManager::flashBlockHandler()",manURL:"SMSound.load(): Using manually-assigned URL",
onURL:"soundManager.load(): current URL already assigned.",badFV:'soundManager.flashVersion must be 8 or 9. "%s" is invalid. Reverting to %s.',as2loop:"Note: Setting stream:false so looping can work (flash 8 limitation)",noNSLoop:"Note: Looping not implemented for MovieStar formats",needfl9:"Note: Switching to flash 9, required for MP4 formats.",mfTimeout:"Setting flashLoadTimeout = 0 (infinite) for off-screen, mobile flash case",mfOn:"mobileFlash::enabling on-screen flash repositioning",policy:"Enabling usePolicyFile for data access"};
q=function(){var b=Pa.call(arguments),a=b.shift(),a=$&&$[a]?$[a]:"",c,f;if(a&&b&&b.length)for(c=0,f=b.length;c<f;c++)a=a.replace("%s",b[c]);return a};ea=function(b){if(8===m&&1<b.loops&&b.stream)o("as2loop"),b.stream=!1;return b};fa=function(b,a){if(b&&!b.usePolicyFile&&(b.onid3||b.usePeakData||b.useWaveformData||b.useEQData))c._wD((a||"")+q("policy")),b.usePolicyFile=!0;return b};wa=function(b){"undefined"!==typeof console&&"undefined"!==typeof console.warn?console.warn(b):c._wD(b)};na=function(){return!1};
Ha=function(b){for(var a in b)b.hasOwnProperty(a)&&"function"===typeof b[a]&&(b[a]=na)};da=function(b){"undefined"===typeof b&&(b=!1);if(y||b)o("smFail",2),c.disable(b)};Ia=function(b){var a=null;if(b)if(b.match(/\.swf(\?.*)?$/i)){if(a=b.substr(b.toLowerCase().lastIndexOf(".swf?")+4))return b}else b.lastIndexOf("/")!==b.length-1&&(b+="/");b=(b&&-1!==b.lastIndexOf("/")?b.substr(0,b.lastIndexOf("/")+1):"./")+c.movieURL;c.noSWFCache&&(b+="?ts="+(new Date).getTime());return b};qa=function(){m=parseInt(c.flashVersion,
10);if(8!==m&&9!==m)c._wD(q("badFV",m,8)),c.flashVersion=m=8;var b=c.debugMode||c.debugFlash?"_debug.swf":".swf";if(c.useHTML5Audio&&!c.html5Only&&c.audioFormats.mp4.required&&9>m)c._wD(q("needfl9")),c.flashVersion=m=9;c.version=c.versionNumber+(c.html5Only?" (HTML5-only mode)":9===m?" (AS3/Flash 9)":" (AS2/Flash 8)");8<m?(c.defaultOptions=v(c.defaultOptions,c.flash9Options),c.features.buffering=!0,c.defaultOptions=v(c.defaultOptions,c.movieStarOptions),c.filePatterns.flash9=RegExp("\\.(mp3|"+Xa.join("|")+
")(\\?.*)?$","i"),c.features.movieStar=!0):c.features.movieStar=!1;c.filePattern=c.filePatterns[8!==m?"flash9":"flash8"];c.movieURL=(8===m?"soundmanager2.swf":"soundmanager2_flash9.swf").replace(".swf",b);c.features.peakData=c.features.waveformData=c.features.eqData=8<m};Ga=function(b,a){if(!i)return!1;i._setPolling(b,a)};ta=function(){if(c.debugURLParam.test(O))c.debugMode=!0;if(u(c.debugID))return!1;var b,a,d,f;if(c.debugMode&&!u(c.debugID)&&(!Sa||!c.useConsole||!c.consoleOnly)){b=h.createElement("div");
b.id=c.debugID+"-toggle";a={position:"fixed",bottom:"0px",right:"0px",width:"1.2em",height:"1.2em",lineHeight:"1.2em",margin:"2px",textAlign:"center",border:"1px solid #999",cursor:"pointer",background:"#fff",color:"#333",zIndex:10001};b.appendChild(h.createTextNode("-"));b.onclick=Ja;b.title="Toggle SM2 debug console";if(p.match(/msie 6/i))b.style.position="absolute",b.style.cursor="hand";for(f in a)a.hasOwnProperty(f)&&(b.style[f]=a[f]);a=h.createElement("div");a.id=c.debugID;a.style.display=c.debugMode?
"block":"none";if(c.debugMode&&!u(b.id)){try{d=ba(),d.appendChild(b)}catch(e){throw Error(q("domError")+" \n"+e.toString());}d.appendChild(a)}}};s=this.getSoundById;o=function(b,a){return b?c._wD(q(b),a):""};if(O.indexOf("sm2-debug=alert")+1&&c.debugMode)c._wD=function(b){G.alert(b)};Ja=function(){var b=u(c.debugID),a=u(c.debugID+"-toggle");if(!b)return!1;oa?(a.innerHTML="+",b.style.display="none"):(a.innerHTML="-",b.style.display="block");oa=!oa};w=function(b,a,c){if("undefined"!==typeof sm2Debugger)try{sm2Debugger.handleEvent(b,
a,c)}catch(f){}return!0};L=function(){var b=[];c.debugMode&&b.push("sm2_debug");c.debugFlash&&b.push("flash_debug");c.useHighPerformance&&b.push("high_performance");return b.join(" ")};va=function(){var b=q("fbHandler"),a=c.getMoviePercent(),d={type:"FLASHBLOCK"};if(c.html5Only)return!1;if(c.ok()){if(c.didFlashBlock&&c._wD(b+": Unblocked"),c.oMC)c.oMC.className=[L(),"movieContainer","swf_loaded"+(c.didFlashBlock?" swf_unblocked":"")].join(" ")}else{if(z)c.oMC.className=L()+" movieContainer "+(null===
a?"swf_timedout":"swf_error"),c._wD(b+": "+q("fbTimeout")+(a?" ("+q("fbLoaded")+")":""));c.didFlashBlock=!0;H({type:"ontimeout",ignoreInit:!0,error:d});K(d)}};pa=function(b,a,c){"undefined"===typeof B[b]&&(B[b]=[]);B[b].push({method:a,scope:c||null,fired:!1})};H=function(b){b||(b={type:"onready"});if(!n&&b&&!b.ignoreInit||"ontimeout"===b.type&&c.ok())return!1;var a={success:b&&b.ignoreInit?c.ok():!y},d=b&&b.type?B[b.type]||[]:[],f=[],e,h=[a],g=z&&c.useFlashBlock&&!c.ok();if(b.error)h[0].error=b.error;
for(a=0,e=d.length;a<e;a++)!0!==d[a].fired&&f.push(d[a]);if(f.length){c._wD("soundManager: Firing "+f.length+" "+b.type+"() item"+(1===f.length?"":"s"));for(a=0,e=f.length;a<e;a++)if(f[a].scope?f[a].method.apply(f[a].scope,h):f[a].method.apply(this,h),!g)f[a].fired=!0}return!0};I=function(){j.setTimeout(function(){c.useFlashBlock&&va();H();c.onload instanceof Function&&(o("onload",1),c.onload.apply(j),o("onloadOK",1));c.waitForWindowLoad&&r.add(j,"load",I)},1)};ka=function(){if(void 0!==t)return t;
var b=!1,a=navigator,c=a.plugins,f,e=j.ActiveXObject;if(c&&c.length)(a=a.mimeTypes)&&a["application/x-shockwave-flash"]&&a["application/x-shockwave-flash"].enabledPlugin&&a["application/x-shockwave-flash"].enabledPlugin.description&&(b=!0);else if("undefined"!==typeof e){try{f=new e("ShockwaveFlash.ShockwaveFlash")}catch(h){}b=!!f}return t=b};Na=function(){var b,a;if(Aa&&p.match(/os (1|2|3_0|3_1)/i)){c.hasHTML5=!1;c.html5Only=!0;if(c.oMC)c.oMC.style.display="none";return!1}if(c.useHTML5Audio){if(!c.html5||
!c.html5.canPlayType)return c._wD("SoundManager: No HTML5 Audio() support detected."),c.hasHTML5=!1,!0;c.hasHTML5=!0;if(Ca&&(c._wD("soundManager::Note: Buggy HTML5 Audio in Safari on this OS X release, see https://bugs.webkit.org/show_bug.cgi?id=32159 - "+(!t?" would use flash fallback for MP3/MP4, but none detected.":"will use flash fallback for MP3/MP4, if available"),1),ka()))return!0}else return!0;for(a in c.audioFormats)if(c.audioFormats.hasOwnProperty(a)&&(c.audioFormats[a].required&&!c.html5.canPlayType(c.audioFormats[a].type)||
c.flash[a]||c.flash[c.audioFormats[a].type]))b=!0;c.ignoreFlash&&(b=!1);c.html5Only=c.hasHTML5&&c.useHTML5Audio&&!b;return!c.html5Only};ia=function(b){var a,d,f=0;if(b instanceof Array){for(a=0,d=b.length;a<d;a++)if(b[a]instanceof Object){if(c.canPlayMIME(b[a].type)){f=a;break}}else if(c.canPlayURL(b[a])){f=a;break}if(b[f].url)b[f]=b[f].url;return b[f]}return b};Ka=function(b){if(!b._hasTimer)b._hasTimer=!0,!Ba&&c.html5PollingInterval&&(null===T&&0===ha&&(T=G.setInterval(Ma,c.html5PollingInterval)),
ha++)};La=function(b){if(b._hasTimer)b._hasTimer=!1,!Ba&&c.html5PollingInterval&&ha--};Ma=function(){var b;if(null!==T&&!ha)return G.clearInterval(T),T=null,!1;for(b=c.soundIDs.length;b--;)c.sounds[c.soundIDs[b]].isHTML5&&c.sounds[c.soundIDs[b]]._hasTimer&&c.sounds[c.soundIDs[b]]._onTimer()};K=function(b){b="undefined"!==typeof b?b:{};c.onerror instanceof Function&&c.onerror.apply(j,[{type:"undefined"!==typeof b.type?b.type:null}]);"undefined"!==typeof b.fatal&&b.fatal&&c.disable()};Qa=function(){if(!Ca||
!ka())return!1;var b=c.audioFormats,a,d;for(d in b)if(b.hasOwnProperty(d)&&("mp3"===d||"mp4"===d))if(c._wD("soundManager: Using flash fallback for "+d+" format"),c.html5[d]=!1,b[d]&&b[d].related)for(a=b[d].related.length;a--;)c.html5[b[d].related[a]]=!1};this._setSandboxType=function(b){var a=c.sandbox;a.type=b;a.description=a.types["undefined"!==typeof a.types[b]?b:"unknown"];c._wD("Flash security sandbox type: "+a.type);if("localWithFile"===a.type)a.noRemote=!0,a.noLocal=!1,o("secNote",2);else if("localWithNetwork"===
a.type)a.noRemote=!1,a.noLocal=!0;else if("localTrusted"===a.type)a.noRemote=!1,a.noLocal=!1};this._externalInterfaceOK=function(b,a){if(c.swfLoaded)return!1;var d,f=(new Date).getTime();c._wD("soundManager::externalInterfaceOK()"+(b?" (~"+(f-b)+" ms)":""));w("swf",!0);w("flashtojs",!0);c.swfLoaded=!0;M=!1;Ca&&Qa();if(!a||a.replace(/\+dev/i,"")!==c.versionNumber.replace(/\+dev/i,""))return d='soundManager: Fatal: JavaScript file build "'+c.versionNumber+'" does not match Flash SWF build "'+a+'" at '+
c.url+". Ensure both are up-to-date.",setTimeout(function(){throw Error(d);},0),!1;D?setTimeout(X,100):X()};ca=function(b,a){function d(){c._wD("-- SoundManager 2 "+c.version+(!c.html5Only&&c.useHTML5Audio?c.hasHTML5?" + HTML5 audio":", no HTML5 audio support":"")+(!c.html5Only?(c.useHighPerformance?", high performance mode, ":", ")+((c.flashPollingInterval?"custom ("+c.flashPollingInterval+"ms)":"normal")+" polling")+(c.wmode?", wmode: "+c.wmode:"")+(c.debugFlash?", flash debug mode":"")+(c.useFlashBlock?
", flashBlock mode":""):"")+" --",1)}function f(a,b){return'<param name="'+a+'" value="'+b+'" />'}if(P&&Q)return!1;if(c.html5Only)return qa(),d(),c.oMC=u(c.movieID),X(),Q=P=!0,!1;var e=a||c.url,i=c.altURL||e,g;g=ba();var j,m,k=L(),l,n=null,n=(n=h.getElementsByTagName("html")[0])&&n.dir&&n.dir.match(/rtl/i),b="undefined"===typeof b?c.id:b;qa();c.url=Ia(N?e:i);a=c.url;c.wmode=!c.wmode&&c.useHighPerformance?"transparent":c.wmode;if(null!==c.wmode&&(p.match(/msie 8/i)||!D&&!c.useHighPerformance)&&navigator.platform.match(/win32|win64/i))o("spcWmode"),
c.wmode=null;g={name:b,id:b,src:a,width:"auto",height:"auto",quality:"high",allowScriptAccess:c.allowScriptAccess,bgcolor:c.bgColor,pluginspage:Va+"www.macromedia.com/go/getflashplayer",title:"JS/Flash audio component (SoundManager 2)",type:"application/x-shockwave-flash",wmode:c.wmode,hasPriority:"true"};if(c.debugFlash)g.FlashVars="debug=1";c.wmode||delete g.wmode;if(D)e=h.createElement("div"),m=['<object id="'+b+'" data="'+a+'" type="'+g.type+'" title="'+g.title+'" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="'+
Va+'download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" width="'+g.width+'" height="'+g.height+'">',f("movie",a),f("AllowScriptAccess",c.allowScriptAccess),f("quality",g.quality),c.wmode?f("wmode",c.wmode):"",f("bgcolor",c.bgColor),f("hasPriority","true"),c.debugFlash?f("FlashVars",g.FlashVars):"","</object>"].join("");else for(j in e=h.createElement("embed"),g)g.hasOwnProperty(j)&&e.setAttribute(j,g[j]);ta();k=L();if(g=ba())if(c.oMC=u(c.movieID)||h.createElement("div"),
c.oMC.id){l=c.oMC.className;c.oMC.className=(l?l+" ":"movieContainer")+(k?" "+k:"");c.oMC.appendChild(e);if(D)j=c.oMC.appendChild(h.createElement("div")),j.className="sm2-object-box",j.innerHTML=m;Q=!0}else{c.oMC.id=c.movieID;c.oMC.className="movieContainer "+k;j=k=null;if(!c.useFlashBlock)if(c.useHighPerformance)k={position:"fixed",width:"8px",height:"8px",bottom:"0px",left:"0px",overflow:"hidden"};else if(k={position:"absolute",width:"6px",height:"6px",top:"-9999px",left:"-9999px"},n)k.left=Math.abs(parseInt(k.left,
10))+"px";if(cb)c.oMC.style.zIndex=1E4;if(!c.debugFlash)for(l in k)k.hasOwnProperty(l)&&(c.oMC.style[l]=k[l]);try{D||c.oMC.appendChild(e);g.appendChild(c.oMC);if(D)j=c.oMC.appendChild(h.createElement("div")),j.className="sm2-object-box",j.innerHTML=m;Q=!0}catch(r){throw Error(q("domError")+" \n"+r.toString());}}P=!0;d();c._wD("soundManager::createMovie(): Trying to load "+a+(!N&&c.altURL?" (alternate URL)":""),1);return!0};aa=function(){if(c.html5Only)return ca(),!1;if(i)return!1;i=c.getMovie(c.id);
if(!i)S?(D?c.oMC.innerHTML=ua:c.oMC.appendChild(S),S=null,P=!0):ca(c.id,c.url),i=c.getMovie(c.id);i&&o("waitEI");c.oninitmovie instanceof Function&&setTimeout(c.oninitmovie,1);return!0};Z=function(){setTimeout(Fa,1E3)};Fa=function(){if(ga)return!1;ga=!0;r.remove(j,"load",Z);if(M&&!Da)return o("waitFocus"),!1;var b;n||(b=c.getMoviePercent(),c._wD(q("waitImpatient",100===b?" (SWF loaded)":0<b?" (SWF "+b+"% loaded)":"")));setTimeout(function(){b=c.getMoviePercent();n||(c._wD("soundManager: No Flash response within expected time.\nLikely causes: "+
(0===b?"Loading "+c.movieURL+" may have failed (and/or Flash "+m+"+ not present?), ":"")+"Flash blocked or JS-Flash security error."+(c.debugFlash?" "+q("checkSWF"):""),2),!N&&b&&(o("localFail",2),c.debugFlash||o("tryDebug",2)),0===b&&c._wD(q("swf404",c.url)),w("flashtojs",!1,": Timed out"+N?" (Check flash security or flash blockers)":" (No plugin/missing SWF?)"));!n&&Ta&&(null===b?c.useFlashBlock||0===c.flashLoadTimeout?(c.useFlashBlock&&va(),o("waitForever")):da(!0):0===c.flashLoadTimeout?o("waitForever"):
da(!0))},c.flashLoadTimeout)};E=function(){function b(){r.remove(j,"focus",E);r.remove(j,"load",E)}if(Da||!M)return b(),!0;Da=Ta=!0;c._wD("soundManager::handleFocus()");V&&M&&r.remove(j,"mousemove",E);ga=!1;b();return!0};Ra=function(){var b,a=[];if(c.useHTML5Audio&&c.hasHTML5){for(b in c.audioFormats)c.audioFormats.hasOwnProperty(b)&&a.push(b+": "+c.html5[b]+(!c.html5[b]&&t&&c.flash[b]?" (using flash)":c.preferFlash&&c.flash[b]&&t?" (preferring flash)":!c.html5[b]?" ("+(c.audioFormats[b].required?
"required, ":"")+"and no flash support)":""));c._wD("-- SoundManager 2: HTML5 support tests ("+c.html5Test+"): "+a.join(", ")+" --",1)}};R=function(b){if(n)return!1;if(c.html5Only)return c._wD("-- SoundManager 2: loaded --"),n=!0,I(),w("onload",!0),!0;var a;if(!c.useFlashBlock||!c.flashLoadTimeout||c.getMoviePercent())n=!0,y&&(a={type:!t&&z?"NO_FLASH":"INIT_TIMEOUT"});c._wD("-- SoundManager 2 "+(y?"failed to load":"loaded")+" ("+(y?"security/load error":"OK")+") --",1);if(y||b){if(c.useFlashBlock&&
c.oMC)c.oMC.className=L()+" "+(null===c.getMoviePercent()?"swf_timedout":"swf_error");H({type:"ontimeout",error:a});w("onload",!1);K(a);return!1}w("onload",!0);if(c.waitForWindowLoad&&!Y)return o("waitOnload"),r.add(j,"load",I),!1;c.waitForWindowLoad&&Y&&o("docLoaded");I();return!0};X=function(){o("init");if(n)return o("didInit"),!1;if(c.html5Only){if(!n)r.remove(j,"load",c.beginDelayedInit),c.enabled=!0,R();return!0}aa();try{o("flashJS"),i._externalInterfaceTest(!1),Ga(!0,c.flashPollingInterval||
(c.useHighPerformance?10:50)),c.debugMode||i._disableDebug(),c.enabled=!0,w("jstoflash",!0),c.html5Only||r.add(j,"unload",na)}catch(b){return c._wD("js/flash exception: "+b.toString()),w("jstoflash",!1),K({type:"JS_TO_FLASH_EXCEPTION",fatal:!0}),da(!0),R(),!1}R();r.remove(j,"load",c.beginDelayedInit);return!0};J=function(){if(sa)return!1;sa=!0;ta();var b=O.toLowerCase(),a=null,a=null,d="undefined"!==typeof console&&"undefined"!==typeof console.log;if(-1!==b.indexOf("sm2-usehtml5audio="))a="1"===b.charAt(b.indexOf("sm2-usehtml5audio=")+
18),d&&console.log((a?"Enabling ":"Disabling ")+"useHTML5Audio via URL parameter"),c.useHTML5Audio=a;if(-1!==b.indexOf("sm2-preferflash="))a="1"===b.charAt(b.indexOf("sm2-preferflash=")+16),d&&console.log((a?"Enabling ":"Disabling ")+"preferFlash via URL parameter"),c.preferFlash=a;if(!t&&c.hasHTML5)c._wD("SoundManager: No Flash detected"+(!c.useHTML5Audio?", enabling HTML5.":". Trying HTML5-only mode.")),c.useHTML5Audio=!0,c.preferFlash=!1;Oa();c.html5.usingFlash=Na();z=c.html5.usingFlash;Ra();if(!t&&
z)c._wD("SoundManager: Fatal error: Flash is needed to play some required formats, but is not available."),c.flashLoadTimeout=1;h.removeEventListener&&h.removeEventListener("DOMContentLoaded",J,!1);aa();return!0};za=function(){"complete"===h.readyState&&(J(),h.detachEvent("onreadystatechange",za));return!0};ra=function(){Y=!0;r.remove(j,"load",ra)};ka();r.add(j,"focus",E);r.add(j,"load",E);r.add(j,"load",Z);r.add(j,"load",ra);V&&M&&r.add(j,"mousemove",E);h.addEventListener?h.addEventListener("DOMContentLoaded",
J,!1):h.attachEvent?h.attachEvent("onreadystatechange",za):(w("onload",!1),K({type:"NO_DOM2_EVENTS",fatal:!0}));"complete"===h.readyState&&setTimeout(J,100)}var la=null;if("undefined"===typeof SM2_DEFER||!SM2_DEFER)la=new W;G.SoundManager=W;G.soundManager=la})(window);

View file

@ -0,0 +1,77 @@
/** @license
*
* SoundManager 2: JavaScript Sound for the Web
* ----------------------------------------------
* http://schillmania.com/projects/soundmanager2/
*
* Copyright (c) 2007, Scott Schiller. All rights reserved.
* Code provided under the BSD License:
* http://schillmania.com/projects/soundmanager2/license.txt
*
* V2.97a.20111220
*/
(function(J){function R(R,ea){function l(b){return function(a){var c=this._t;return!c||!c._a?null:b.call(this,a)}}this.flashVersion=8;this.debugFlash=this.debugMode=!1;this.consoleOnly=this.useConsole=!0;this.waitForWindowLoad=!1;this.bgColor="#ffffff";this.useHighPerformance=!1;this.html5PollingInterval=this.flashPollingInterval=null;this.flashLoadTimeout=1E3;this.wmode=null;this.allowScriptAccess="always";this.useFlashBlock=!1;this.useHTML5Audio=!0;this.html5Test=/^(probably|maybe)$/i;this.preferFlash=
!0;this.noSWFCache=!1;this.audioFormats={mp3:{type:['audio/mpeg; codecs="mp3"',"audio/mpeg","audio/mp3","audio/MPA","audio/mpa-robust"],required:!0},mp4:{related:["aac","m4a"],type:['audio/mp4; codecs="mp4a.40.2"',"audio/aac","audio/x-m4a","audio/MP4A-LATM","audio/mpeg4-generic"],required:!1},ogg:{type:["audio/ogg; codecs=vorbis"],required:!1},wav:{type:['audio/wav; codecs="1"',"audio/wav","audio/wave","audio/x-wav"],required:!1}};this.defaultOptions={autoLoad:!1,autoPlay:!1,from:null,loops:1,onid3:null,
onload:null,whileloading:null,onplay:null,onpause:null,onresume:null,whileplaying:null,onposition:null,onstop:null,onfailure:null,onfinish:null,multiShot:!0,multiShotEvents:!1,position:null,pan:0,stream:!0,to:null,type:null,usePolicyFile:!1,volume:100};this.flash9Options={isMovieStar:null,usePeakData:!1,useWaveformData:!1,useEQData:!1,onbufferchange:null,ondataerror:null};this.movieStarOptions={bufferTime:3,serverURL:null,onconnect:null,duration:null};this.movieID="sm2-container";this.id=ea||"sm2movie";
this.debugID="soundmanager-debug";this.debugURLParam=/([#?&])debug=1/i;this.versionNumber="V2.97a.20111220";this.movieURL=this.version=null;this.url=R||null;this.altURL=null;this.enabled=this.swfLoaded=!1;this.oMC=null;this.sounds={};this.soundIDs=[];this.didFlashBlock=this.muted=!1;this.filePattern=null;this.filePatterns={flash8:/\.mp3(\?.*)?$/i,flash9:/\.mp3(\?.*)?$/i};this.features={buffering:!1,peakData:!1,waveformData:!1,eqData:!1,movieStar:!1};this.sandbox={};var fa;try{fa="undefined"!==typeof Audio&&
"undefined"!==typeof(new Audio).canPlayType}catch(Xa){fa=!1}this.hasHTML5=fa;this.html5={usingFlash:null};this.flash={};this.ignoreFlash=this.html5Only=!1;var Aa,c=this,h=null,S,p=navigator.userAgent,j=J,ga=j.location.href.toString(),k=document,ha,T,i,v=[],K=!1,L=!1,m=!1,w=!1,ia=!1,M,q,ja,C,D,U,Ba,ka,A,V,E,la,ma,na,W,F,Ca,oa,Da,X,Ea,N=null,pa=null,G,qa,H,Y,Z,ra,o,$=!1,sa=!1,Fa,Ga,Ha,aa=0,O=null,ba,s=null,Ia,ca,P,x,ta,ua,Ja,n,Ra=Array.prototype.slice,B=!1,r,da,Ka,u,La,va=p.match(/(ipad|iphone|ipod)/i),
Sa=p.match(/firefox/i),Ta=p.match(/droid/i),y=p.match(/msie/i),Ua=p.match(/webkit/i),Q=p.match(/safari/i)&&!p.match(/chrome/i),Va=p.match(/opera/i),wa=p.match(/(mobile|pre\/|xoom)/i)||va,xa=!ga.match(/usehtml5audio/i)&&!ga.match(/sm2\-ignorebadua/i)&&Q&&!p.match(/silk/i)&&p.match(/OS X 10_6_([3-7])/i),ya="undefined"!==typeof k.hasFocus?k.hasFocus():null,I=Q&&"undefined"===typeof k.hasFocus,Ma=!I,Na=/(mp3|mp4|mpa)/i,za=k.location?k.location.protocol.match(/http/i):null,Oa=!za?"http://":"",Pa=/^\s*audio\/(?:x-)?(?:mpeg4|aac|flv|mov|mp4||m4v|m4a|mp4v|3gp|3g2)\s*(?:$|;)/i,
Qa="mpeg4,aac,flv,mov,mp4,m4v,f4v,m4a,mp4v,3gp,3g2".split(","),Wa=RegExp("\\.("+Qa.join("|")+")(\\?.*)?$","i");this.mimePattern=/^\s*audio\/(?:x-)?(?:mp(?:eg|3))\s*(?:$|;)/i;this.useAltURL=!za;this._global_a=null;if(wa&&(c.useHTML5Audio=!0,c.preferFlash=!1,va))B=c.ignoreFlash=!0;this.supported=this.ok=function(){return s?m&&!w:c.useHTML5Audio&&c.hasHTML5};this.getMovie=function(b){return S(b)||k[b]||j[b]};this.createSound=function(b){function a(){e=Y(e);c.sounds[d.id]=new Aa(d);c.soundIDs.push(d.id);
return c.sounds[d.id]}var e=null,f=null,d=null;if(!m||!c.ok())return ra(void 0),!1;2===arguments.length&&(b={id:arguments[0],url:arguments[1]});e=q(b);e.url=ba(e.url);d=e;if(o(d.id,!0))return c.sounds[d.id];if(ca(d))f=a(),f._setup_html5(d);else{if(8<i){if(null===d.isMovieStar)d.isMovieStar=d.serverURL||(d.type?d.type.match(Pa):!1)||d.url.match(Wa);if(d.isMovieStar&&d.usePeakData)d.usePeakData=!1}d=Z(d,void 0);f=a();if(8===i)h._createSound(d.id,d.loops||1,d.usePolicyFile);else if(h._createSound(d.id,
d.url,d.usePeakData,d.useWaveformData,d.useEQData,d.isMovieStar,d.isMovieStar?d.bufferTime:!1,d.loops||1,d.serverURL,d.duration||null,d.autoPlay,!0,d.autoLoad,d.usePolicyFile),!d.serverURL)f.connected=!0,d.onconnect&&d.onconnect.apply(f);!d.serverURL&&(d.autoLoad||d.autoPlay)&&f.load(d)}!d.serverURL&&d.autoPlay&&f.play();return f};this.destroySound=function(b,a){if(!o(b))return!1;var e=c.sounds[b],f;e._iO={};e.stop();e.unload();for(f=0;f<c.soundIDs.length;f++)if(c.soundIDs[f]===b){c.soundIDs.splice(f,
1);break}a||e.destruct(!0);delete c.sounds[b];return!0};this.load=function(b,a){return!o(b)?!1:c.sounds[b].load(a)};this.unload=function(b){return!o(b)?!1:c.sounds[b].unload()};this.onposition=this.onPosition=function(b,a,e,f){return!o(b)?!1:c.sounds[b].onposition(a,e,f)};this.clearOnPosition=function(b,a,e){return!o(b)?!1:c.sounds[b].clearOnPosition(a,e)};this.start=this.play=function(b,a){if(!m||!c.ok())return ra("soundManager.play(): "+G(!m?"notReady":"notOK")),!1;if(!o(b)){a instanceof Object||
(a={url:a});return a&&a.url?(a.id=b,c.createSound(a).play()):!1}return c.sounds[b].play(a)};this.setPosition=function(b,a){return!o(b)?!1:c.sounds[b].setPosition(a)};this.stop=function(b){return!o(b)?!1:c.sounds[b].stop()};this.stopAll=function(){for(var b in c.sounds)c.sounds.hasOwnProperty(b)&&c.sounds[b].stop()};this.pause=function(b){return!o(b)?!1:c.sounds[b].pause()};this.pauseAll=function(){var b;for(b=c.soundIDs.length;b--;)c.sounds[c.soundIDs[b]].pause()};this.resume=function(b){return!o(b)?
!1:c.sounds[b].resume()};this.resumeAll=function(){var b;for(b=c.soundIDs.length;b--;)c.sounds[c.soundIDs[b]].resume()};this.togglePause=function(b){return!o(b)?!1:c.sounds[b].togglePause()};this.setPan=function(b,a){return!o(b)?!1:c.sounds[b].setPan(a)};this.setVolume=function(b,a){return!o(b)?!1:c.sounds[b].setVolume(a)};this.mute=function(b){var a=0;"string"!==typeof b&&(b=null);if(b)return!o(b)?!1:c.sounds[b].mute();for(a=c.soundIDs.length;a--;)c.sounds[c.soundIDs[a]].mute();return c.muted=!0};
this.muteAll=function(){c.mute()};this.unmute=function(b){"string"!==typeof b&&(b=null);if(b)return!o(b)?!1:c.sounds[b].unmute();for(b=c.soundIDs.length;b--;)c.sounds[c.soundIDs[b]].unmute();c.muted=!1;return!0};this.unmuteAll=function(){c.unmute()};this.toggleMute=function(b){return!o(b)?!1:c.sounds[b].toggleMute()};this.getMemoryUse=function(){var b=0;h&&8!==i&&(b=parseInt(h._getMemoryUse(),10));return b};this.disable=function(b){var a;"undefined"===typeof b&&(b=!1);if(w)return!1;w=!0;for(a=c.soundIDs.length;a--;)Da(c.sounds[c.soundIDs[a]]);
M(b);n.remove(j,"load",D);return!0};this.canPlayMIME=function(b){var a;c.hasHTML5&&(a=P({type:b}));return!s||a?a:b?!!(8<i&&b.match(Pa)||b.match(c.mimePattern)):null};this.canPlayURL=function(b){var a;c.hasHTML5&&(a=P({url:b}));return!s||a?a:b?!!b.match(c.filePattern):null};this.canPlayLink=function(b){return"undefined"!==typeof b.type&&b.type&&c.canPlayMIME(b.type)?!0:c.canPlayURL(b.href)};this.getSoundById=function(b){if(!b)throw Error("soundManager.getSoundById(): sID is null/undefined");return c.sounds[b]};
this.onready=function(b,a){if(b&&b instanceof Function)return a||(a=j),ja("onready",b,a),C(),!0;throw G("needFunction","onready");};this.ontimeout=function(b,a){if(b&&b instanceof Function)return a||(a=j),ja("ontimeout",b,a),C({type:"ontimeout"}),!0;throw G("needFunction","ontimeout");};this._wD=this._writeDebug=function(){return!0};this._debug=function(){};this.reboot=function(){var b,a;for(b=c.soundIDs.length;b--;)c.sounds[c.soundIDs[b]].destruct();try{if(y)pa=h.innerHTML;N=h.parentNode.removeChild(h)}catch(e){}pa=
N=s=null;c.enabled=ma=m=$=sa=K=L=w=c.swfLoaded=!1;c.soundIDs=c.sounds=[];h=null;for(b in v)if(v.hasOwnProperty(b))for(a=v[b].length;a--;)v[b][a].fired=!1;j.setTimeout(c.beginDelayedInit,20)};this.getMoviePercent=function(){return h&&"undefined"!==typeof h.PercentLoaded?h.PercentLoaded():null};this.beginDelayedInit=function(){ia=!0;E();setTimeout(function(){if(sa)return!1;W();V();return sa=!0},20);U()};this.destruct=function(){c.disable(!0)};Aa=function(b){var a=this,e,f,d,g,z,j,k=!1,t=[],l=0,n,p,
m=null,r=null,s=null;this.sID=b.id;this.url=b.url;this._iO=this.instanceOptions=this.options=q(b);this.pan=this.options.pan;this.volume=this.options.volume;this.isHTML5=!1;this._a=null;this.id3={};this._debug=function(){};this.load=function(b){var c=null;if("undefined"!==typeof b)a._iO=q(b,a.options),a.instanceOptions=a._iO;else if(b=a.options,a._iO=b,a.instanceOptions=a._iO,m&&m!==a.url)a._iO.url=a.url,a.url=null;if(!a._iO.url)a._iO.url=a.url;a._iO.url=ba(a._iO.url);if(a._iO.url===a.url&&0!==a.readyState&&
2!==a.readyState)return 3===a.readyState&&a._iO.onload&&a._iO.onload.apply(a,[!!a.duration]),a;b=a._iO;m=a.url;a.loaded=!1;a.readyState=1;a.playState=0;if(ca(b)){if(c=a._setup_html5(b),!c._called_load)a._html5_canplay=!1,a._a.autobuffer="auto",a._a.preload="auto",c.load(),c._called_load=!0,b.autoPlay&&a.play()}else try{a.isHTML5=!1,a._iO=Z(Y(b)),b=a._iO,8===i?h._load(a.sID,b.url,b.stream,b.autoPlay,b.whileloading?1:0,b.loops||1,b.usePolicyFile):h._load(a.sID,b.url,!!b.stream,!!b.autoPlay,b.loops||
1,!!b.autoLoad,b.usePolicyFile)}catch(d){F({type:"SMSOUND_LOAD_JS_EXCEPTION",fatal:!0})}return a};this.unload=function(){0!==a.readyState&&(a.isHTML5?(g(),a._a&&(a._a.pause(),ta(a._a))):8===i?h._unload(a.sID,"about:blank"):h._unload(a.sID),e());return a};this.destruct=function(b){if(a.isHTML5){if(g(),a._a)a._a.pause(),ta(a._a),B||d(),a._a._t=null,a._a=null}else a._iO.onfailure=null,h._destroySound(a.sID);b||c.destroySound(a.sID,!0)};this.start=this.play=function(b,c){var d,c=void 0===c?!0:c;b||(b=
{});a._iO=q(b,a._iO);a._iO=q(a._iO,a.options);a._iO.url=ba(a._iO.url);a.instanceOptions=a._iO;if(a._iO.serverURL&&!a.connected)return a.getAutoPlay()||a.setAutoPlay(!0),a;ca(a._iO)&&(a._setup_html5(a._iO),z());if(1===a.playState&&!a.paused&&(d=a._iO.multiShot,!d))return a;if(!a.loaded)if(0===a.readyState){if(!a.isHTML5)a._iO.autoPlay=!0;a.load(a._iO)}else if(2===a.readyState)return a;if(!a.isHTML5&&9===i&&0<a.position&&a.position===a.duration)b.position=0;if(a.paused&&a.position&&0<a.position)a.resume();
else{a._iO=q(b,a._iO);if(null!==a._iO.from&&null!==a._iO.to&&0===a.instanceCount&&0===a.playState&&!a._iO.serverURL){d=function(){a._iO=q(b,a._iO);a.play(a._iO)};if(a.isHTML5&&!a._html5_canplay)return a.load({_oncanplay:d}),!1;if(!a.isHTML5&&!a.loaded&&(!a.readyState||2!==a.readyState))return a.load({onload:d}),!1;a._iO=p()}(!a.instanceCount||a._iO.multiShotEvents||!a.isHTML5&&8<i&&!a.getAutoPlay())&&a.instanceCount++;0===a.playState&&a._iO.onposition&&j(a);a.playState=1;a.paused=!1;a.position="undefined"!==
typeof a._iO.position&&!isNaN(a._iO.position)?a._iO.position:0;if(!a.isHTML5)a._iO=Z(Y(a._iO));a._iO.onplay&&c&&(a._iO.onplay.apply(a),k=!0);a.setVolume(a._iO.volume,!0);a.setPan(a._iO.pan,!0);a.isHTML5?(z(),d=a._setup_html5(),a.setPosition(a._iO.position),d.play()):h._start(a.sID,a._iO.loops||1,9===i?a._iO.position:a._iO.position/1E3)}return a};this.stop=function(b){var c=a._iO;if(1===a.playState){a._onbufferchange(0);a._resetOnPosition(0);a.paused=!1;if(!a.isHTML5)a.playState=0;n();c.to&&a.clearOnPosition(c.to);
if(a.isHTML5){if(a._a)b=a.position,a.setPosition(0),a.position=b,a._a.pause(),a.playState=0,a._onTimer(),g()}else h._stop(a.sID,b),c.serverURL&&a.unload();a.instanceCount=0;a._iO={};c.onstop&&c.onstop.apply(a)}return a};this.setAutoPlay=function(b){a._iO.autoPlay=b;a.isHTML5||(h._setAutoPlay(a.sID,b),b&&!a.instanceCount&&1===a.readyState&&a.instanceCount++)};this.getAutoPlay=function(){return a._iO.autoPlay};this.setPosition=function(b){void 0===b&&(b=0);var c=a.isHTML5?Math.max(b,0):Math.min(a.duration||
a._iO.duration,Math.max(b,0));a.position=c;b=a.position/1E3;a._resetOnPosition(a.position);a._iO.position=c;if(a.isHTML5){if(a._a&&a._html5_canplay&&a._a.currentTime!==b)try{a._a.currentTime=b,(0===a.playState||a.paused)&&a._a.pause()}catch(d){}}else b=9===i?a.position:b,a.readyState&&2!==a.readyState&&h._setPosition(a.sID,b,a.paused||!a.playState);a.isHTML5&&a.paused&&a._onTimer(!0);return a};this.pause=function(b){if(a.paused||0===a.playState&&1!==a.readyState)return a;a.paused=!0;a.isHTML5?(a._setup_html5().pause(),
g()):(b||void 0===b)&&h._pause(a.sID);a._iO.onpause&&a._iO.onpause.apply(a);return a};this.resume=function(){var b=a._iO;if(!a.paused)return a;a.paused=!1;a.playState=1;a.isHTML5?(a._setup_html5().play(),z()):(b.isMovieStar&&!b.serverURL&&a.setPosition(a.position),h._pause(a.sID));k&&b.onplay?(b.onplay.apply(a),k=!0):b.onresume&&b.onresume.apply(a);return a};this.togglePause=function(){if(0===a.playState)return a.play({position:9===i&&!a.isHTML5?a.position:a.position/1E3}),a;a.paused?a.resume():a.pause();
return a};this.setPan=function(b,c){"undefined"===typeof b&&(b=0);"undefined"===typeof c&&(c=!1);a.isHTML5||h._setPan(a.sID,b);a._iO.pan=b;if(!c)a.pan=b,a.options.pan=b;return a};this.setVolume=function(b,d){"undefined"===typeof b&&(b=100);"undefined"===typeof d&&(d=!1);if(a.isHTML5){if(a._a)a._a.volume=Math.max(0,Math.min(1,b/100))}else h._setVolume(a.sID,c.muted&&!a.muted||a.muted?0:b);a._iO.volume=b;if(!d)a.volume=b,a.options.volume=b;return a};this.mute=function(){a.muted=!0;if(a.isHTML5){if(a._a)a._a.muted=
!0}else h._setVolume(a.sID,0);return a};this.unmute=function(){a.muted=!1;var b="undefined"!==typeof a._iO.volume;if(a.isHTML5){if(a._a)a._a.muted=!1}else h._setVolume(a.sID,b?a._iO.volume:a.options.volume);return a};this.toggleMute=function(){return a.muted?a.unmute():a.mute()};this.onposition=this.onPosition=function(b,c,d){t.push({position:b,method:c,scope:"undefined"!==typeof d?d:a,fired:!1});return a};this.clearOnPosition=function(a,b){var c,a=parseInt(a,10);if(isNaN(a))return!1;for(c=0;c<t.length;c++)if(a===
t[c].position&&(!b||b===t[c].method))t[c].fired&&l--,t.splice(c,1)};this._processOnPosition=function(){var b,c;b=t.length;if(!b||!a.playState||l>=b)return!1;for(;b--;)if(c=t[b],!c.fired&&a.position>=c.position)c.fired=!0,l++,c.method.apply(c.scope,[c.position]);return!0};this._resetOnPosition=function(a){var b,c;b=t.length;if(!b)return!1;for(;b--;)if(c=t[b],c.fired&&a<=c.position)c.fired=!1,l--;return!0};p=function(){var b=a._iO,c=b.from,d=b.to,e,f;f=function(){a.clearOnPosition(d,f);a.stop()};e=
function(){if(null!==d&&!isNaN(d))a.onPosition(d,f)};if(null!==c&&!isNaN(c))b.position=c,b.multiShot=!1,e();return b};j=function(){var b=a._iO.onposition;if(b)for(var c in b)if(b.hasOwnProperty(c))a.onPosition(parseInt(c,10),b[c])};n=function(){var b=a._iO.onposition;if(b)for(var c in b)b.hasOwnProperty(c)&&a.clearOnPosition(parseInt(c,10))};z=function(){a.isHTML5&&Fa(a)};g=function(){a.isHTML5&&Ga(a)};e=function(){t=[];l=0;k=!1;a._hasTimer=null;a._a=null;a._html5_canplay=!1;a.bytesLoaded=null;a.bytesTotal=
null;a.duration=a._iO&&a._iO.duration?a._iO.duration:null;a.durationEstimate=null;a.eqData=[];a.eqData.left=[];a.eqData.right=[];a.failures=0;a.isBuffering=!1;a.instanceOptions={};a.instanceCount=0;a.loaded=!1;a.metadata={};a.readyState=0;a.muted=!1;a.paused=!1;a.peakData={left:0,right:0};a.waveformData={left:[],right:[]};a.playState=0;a.position=null};e();this._onTimer=function(b){var c,d=!1,e={};if(a._hasTimer||b){if(a._a&&(b||(0<a.playState||1===a.readyState)&&!a.paused)){c=a._get_html5_duration();
if(c!==r)r=c,a.duration=c,d=!0;a.durationEstimate=a.duration;c=1E3*a._a.currentTime||0;c!==s&&(s=c,d=!0);(d||b)&&a._whileplaying(c,e,e,e,e);return d}return!1}};this._get_html5_duration=function(){var b=a._iO,c=a._a?1E3*a._a.duration:b?b.duration:void 0;return c&&!isNaN(c)&&Infinity!==c?c:b?b.duration:null};this._setup_html5=function(b){var b=q(a._iO,b),d=decodeURI,g=B?c._global_a:a._a,h=d(b.url),z=g&&g._t?g._t.instanceOptions:null;if(g){if(g._t&&(!B&&h===d(m)||B&&z.url===b.url&&(!m||m===z.url)))return g;
B&&g._t&&g._t.playState&&b.url!==z.url&&g._t.stop();e();g.src=b.url;m=a.url=b.url;g._called_load=!1}else{g=new Audio(b.url);g._called_load=!1;if(Ta)g._called_load=!0;if(B)c._global_a=g}a.isHTML5=!0;a._a=g;g._t=a;f();g.loop=1<b.loops?"loop":"";b.autoLoad||b.autoPlay?a.load():(g.autobuffer=!1,g.preload="none");g.loop=1<b.loops?"loop":"";return g};f=function(){if(a._a._added_events)return!1;var b;a._a._added_events=!0;for(b in u)u.hasOwnProperty(b)&&a._a&&a._a.addEventListener(b,u[b],!1);return!0};d=
function(){var b;a._a._added_events=!1;for(b in u)u.hasOwnProperty(b)&&a._a&&a._a.removeEventListener(b,u[b],!1)};this._onload=function(b){b=!!b;a.loaded=b;a.readyState=b?3:2;a._onbufferchange(0);a._iO.onload&&a._iO.onload.apply(a,[b]);return!0};this._onbufferchange=function(b){if(0===a.playState||b&&a.isBuffering||!b&&!a.isBuffering)return!1;a.isBuffering=1===b;a._iO.onbufferchange&&a._iO.onbufferchange.apply(a);return!0};this._onsuspend=function(){a._iO.onsuspend&&a._iO.onsuspend.apply(a);return!0};
this._onfailure=function(b,c,d){a.failures++;if(a._iO.onfailure&&1===a.failures)a._iO.onfailure(a,b,c,d)};this._onfinish=function(){var b=a._iO.onfinish;a._onbufferchange(0);a._resetOnPosition(0);if(a.instanceCount){a.instanceCount--;if(!a.instanceCount)n(),a.playState=0,a.paused=!1,a.instanceCount=0,a.instanceOptions={},a._iO={},g();(!a.instanceCount||a._iO.multiShotEvents)&&b&&b.apply(a)}};this._whileloading=function(b,c,d,e){var f=a._iO;a.bytesLoaded=b;a.bytesTotal=c;a.duration=Math.floor(d);a.bufferLength=
e;if(f.isMovieStar)a.durationEstimate=a.duration;else if(a.durationEstimate=f.duration?a.duration>f.duration?a.duration:f.duration:parseInt(a.bytesTotal/a.bytesLoaded*a.duration,10),void 0===a.durationEstimate)a.durationEstimate=a.duration;3!==a.readyState&&f.whileloading&&f.whileloading.apply(a)};this._whileplaying=function(b,c,d,e,f){var g=a._iO;if(isNaN(b)||null===b)return!1;a.position=b;a._processOnPosition();if(!a.isHTML5&&8<i){if(g.usePeakData&&"undefined"!==typeof c&&c)a.peakData={left:c.leftPeak,
right:c.rightPeak};if(g.useWaveformData&&"undefined"!==typeof d&&d)a.waveformData={left:d.split(","),right:e.split(",")};if(g.useEQData&&"undefined"!==typeof f&&f&&f.leftEQ&&(b=f.leftEQ.split(","),a.eqData=b,a.eqData.left=b,"undefined"!==typeof f.rightEQ&&f.rightEQ))a.eqData.right=f.rightEQ.split(",")}1===a.playState&&(!a.isHTML5&&8===i&&!a.position&&a.isBuffering&&a._onbufferchange(0),g.whileplaying&&g.whileplaying.apply(a));return!0};this._onmetadata=function(b,c){var d={},e,f;for(e=0,f=b.length;e<
f;e++)d[b[e]]=c[e];a.metadata=d;a._iO.onmetadata&&a._iO.onmetadata.apply(a)};this._onid3=function(b,c){var d=[],e,f;for(e=0,f=b.length;e<f;e++)d[b[e]]=c[e];a.id3=q(a.id3,d);a._iO.onid3&&a._iO.onid3.apply(a)};this._onconnect=function(b){b=1===b;if(a.connected=b)a.failures=0,o(a.sID)&&(a.getAutoPlay()?a.play(void 0,a.getAutoPlay()):a._iO.autoLoad&&a.load()),a._iO.onconnect&&a._iO.onconnect.apply(a,[b])};this._ondataerror=function(){0<a.playState&&a._iO.ondataerror&&a._iO.ondataerror.apply(a)}};na=function(){return k.body||
k._docElement||k.getElementsByTagName("div")[0]};S=function(b){return k.getElementById(b)};q=function(b,a){var e={},f,d;for(f in b)b.hasOwnProperty(f)&&(e[f]=b[f]);f="undefined"===typeof a?c.defaultOptions:a;for(d in f)f.hasOwnProperty(d)&&"undefined"===typeof e[d]&&(e[d]=f[d]);return e};n=function(){function b(a){var a=Ra.call(a),b=a.length;c?(a[1]="on"+a[1],3<b&&a.pop()):3===b&&a.push(!1);return a}function a(a,b){var h=a.shift(),k=[f[b]];if(c)h[k](a[0],a[1]);else h[k].apply(h,a)}var c=j.attachEvent,
f={add:c?"attachEvent":"addEventListener",remove:c?"detachEvent":"removeEventListener"};return{add:function(){a(b(arguments),"add")},remove:function(){a(b(arguments),"remove")}}}();u={abort:l(function(){}),canplay:l(function(){var b=this._t;if(b._html5_canplay)return!0;b._html5_canplay=!0;b._onbufferchange(0);var a=!isNaN(b.position)?b.position/1E3:null;if(b.position&&this.currentTime!==a)try{this.currentTime=a}catch(c){}b._iO._oncanplay&&b._iO._oncanplay()}),load:l(function(){var b=this._t;b.loaded||
(b._onbufferchange(0),b._whileloading(b.bytesTotal,b.bytesTotal,b._get_html5_duration()),b._onload(!0))}),emptied:l(function(){}),ended:l(function(){this._t._onfinish()}),error:l(function(){this._t._onload(!1)}),loadeddata:l(function(){var b=this._t,a=b.bytesTotal||1;if(!b._loaded&&!Q)b.duration=b._get_html5_duration(),b._whileloading(a,a,b._get_html5_duration()),b._onload(!0)}),loadedmetadata:l(function(){}),loadstart:l(function(){this._t._onbufferchange(1)}),play:l(function(){this._t._onbufferchange(0)}),
playing:l(function(){this._t._onbufferchange(0)}),progress:l(function(b){var a=this._t;if(a.loaded)return!1;var c,f=0,d=b.target.buffered;c=b.loaded||0;var g=b.total||1;if(d&&d.length){for(c=d.length;c--;)f=d.end(c)-d.start(c);c=f/b.target.duration}isNaN(c)||(a._onbufferchange(0),a._whileloading(c,g,a._get_html5_duration()),c&&g&&c===g&&u.load.call(this,b))}),ratechange:l(function(){}),suspend:l(function(b){var a=this._t;u.progress.call(this,b);a._onsuspend()}),stalled:l(function(){}),timeupdate:l(function(){this._t._onTimer()}),
waiting:l(function(){this._t._onbufferchange(1)})};ca=function(b){return!b.serverURL&&(b.type?P({type:b.type}):P({url:b.url})||c.html5Only)};ta=function(b){if(b)b.src=Sa?"":"about:blank"};P=function(b){function a(a){return c.preferFlash&&r&&!c.ignoreFlash&&"undefined"!==typeof c.flash[a]&&c.flash[a]}if(!c.useHTML5Audio||!c.hasHTML5)return!1;var e=b.url||null,b=b.type||null,f=c.audioFormats,d;if(b&&"undefined"!==c.html5[b])return c.html5[b]&&!a(b);if(!x){x=[];for(d in f)f.hasOwnProperty(d)&&(x.push(d),
f[d].related&&(x=x.concat(f[d].related)));x=RegExp("\\.("+x.join("|")+")(\\?.*)?$","i")}d=e?e.toLowerCase().match(x):null;if(!d||!d.length)if(b)e=b.indexOf(";"),d=(-1!==e?b.substr(0,e):b).substr(6);else return!1;else d=d[1];if(d&&"undefined"!==typeof c.html5[d])return c.html5[d]&&!a(d);b="audio/"+d;e=c.html5.canPlayType({type:b});return(c.html5[d]=e)&&c.html5[b]&&!a(b)};Ja=function(){function b(b){var d,e,f=!1;if(!a||"function"!==typeof a.canPlayType)return!1;if(b instanceof Array){for(d=0,e=b.length;d<
e&&!f;d++)if(c.html5[b[d]]||a.canPlayType(b[d]).match(c.html5Test))f=!0,c.html5[b[d]]=!0,c.flash[b[d]]=!(!c.preferFlash||!r||!b[d].match(Na));return f}b=a&&"function"===typeof a.canPlayType?a.canPlayType(b):!1;return!(!b||!b.match(c.html5Test))}if(!c.useHTML5Audio||"undefined"===typeof Audio)return!1;var a="undefined"!==typeof Audio?Va?new Audio(null):new Audio:null,e,f={},d,g;d=c.audioFormats;for(e in d)if(d.hasOwnProperty(e)&&(f[e]=b(d[e].type),f["audio/"+e]=f[e],c.flash[e]=c.preferFlash&&!c.ignoreFlash&&
e.match(Na)?!0:!1,d[e]&&d[e].related))for(g=d[e].related.length;g--;)f["audio/"+d[e].related[g]]=f[e],c.html5[d[e].related[g]]=f[e],c.flash[d[e].related[g]]=f[e];f.canPlayType=a?b:null;c.html5=q(c.html5,f);return!0};G=function(){};Y=function(b){if(8===i&&1<b.loops&&b.stream)b.stream=!1;return b};Z=function(b){if(b&&!b.usePolicyFile&&(b.onid3||b.usePeakData||b.useWaveformData||b.useEQData))b.usePolicyFile=!0;return b};ra=function(){};ha=function(){return!1};Da=function(b){for(var a in b)b.hasOwnProperty(a)&&
"function"===typeof b[a]&&(b[a]=ha)};X=function(b){"undefined"===typeof b&&(b=!1);(w||b)&&c.disable(b)};Ea=function(b){var a=null;if(b)if(b.match(/\.swf(\?.*)?$/i)){if(a=b.substr(b.toLowerCase().lastIndexOf(".swf?")+4))return b}else b.lastIndexOf("/")!==b.length-1&&(b+="/");b=(b&&-1!==b.lastIndexOf("/")?b.substr(0,b.lastIndexOf("/")+1):"./")+c.movieURL;c.noSWFCache&&(b+="?ts="+(new Date).getTime());return b};ka=function(){i=parseInt(c.flashVersion,10);if(8!==i&&9!==i)c.flashVersion=i=8;var b=c.debugMode||
c.debugFlash?"_debug.swf":".swf";if(c.useHTML5Audio&&!c.html5Only&&c.audioFormats.mp4.required&&9>i)c.flashVersion=i=9;c.version=c.versionNumber+(c.html5Only?" (HTML5-only mode)":9===i?" (AS3/Flash 9)":" (AS2/Flash 8)");8<i?(c.defaultOptions=q(c.defaultOptions,c.flash9Options),c.features.buffering=!0,c.defaultOptions=q(c.defaultOptions,c.movieStarOptions),c.filePatterns.flash9=RegExp("\\.(mp3|"+Qa.join("|")+")(\\?.*)?$","i"),c.features.movieStar=!0):c.features.movieStar=!1;c.filePattern=c.filePatterns[8!==
i?"flash9":"flash8"];c.movieURL=(8===i?"soundmanager2.swf":"soundmanager2_flash9.swf").replace(".swf",b);c.features.peakData=c.features.waveformData=c.features.eqData=8<i};Ca=function(b,a){if(!h)return!1;h._setPolling(b,a)};oa=function(){if(c.debugURLParam.test(ga))c.debugMode=!0};o=this.getSoundById;H=function(){var b=[];c.debugMode&&b.push("sm2_debug");c.debugFlash&&b.push("flash_debug");c.useHighPerformance&&b.push("high_performance");return b.join(" ")};qa=function(){G("fbHandler");var b=c.getMoviePercent(),
a={type:"FLASHBLOCK"};if(c.html5Only)return!1;if(c.ok()){if(c.oMC)c.oMC.className=[H(),"movieContainer","swf_loaded"+(c.didFlashBlock?" swf_unblocked":"")].join(" ")}else{if(s)c.oMC.className=H()+" movieContainer "+(null===b?"swf_timedout":"swf_error");c.didFlashBlock=!0;C({type:"ontimeout",ignoreInit:!0,error:a});F(a)}};ja=function(b,a,c){"undefined"===typeof v[b]&&(v[b]=[]);v[b].push({method:a,scope:c||null,fired:!1})};C=function(b){b||(b={type:"onready"});if(!m&&b&&!b.ignoreInit||"ontimeout"===
b.type&&c.ok())return!1;var a={success:b&&b.ignoreInit?c.ok():!w},e=b&&b.type?v[b.type]||[]:[],f=[],d,a=[a],g=s&&c.useFlashBlock&&!c.ok();if(b.error)a[0].error=b.error;for(b=0,d=e.length;b<d;b++)!0!==e[b].fired&&f.push(e[b]);if(f.length)for(b=0,d=f.length;b<d;b++)if(f[b].scope?f[b].method.apply(f[b].scope,a):f[b].method.apply(this,a),!g)f[b].fired=!0;return!0};D=function(){j.setTimeout(function(){c.useFlashBlock&&qa();C();c.onload instanceof Function&&c.onload.apply(j);c.waitForWindowLoad&&n.add(j,
"load",D)},1)};da=function(){if(void 0!==r)return r;var b=!1,a=navigator,c=a.plugins,f,d=j.ActiveXObject;if(c&&c.length)(a=a.mimeTypes)&&a["application/x-shockwave-flash"]&&a["application/x-shockwave-flash"].enabledPlugin&&a["application/x-shockwave-flash"].enabledPlugin.description&&(b=!0);else if("undefined"!==typeof d){try{f=new d("ShockwaveFlash.ShockwaveFlash")}catch(g){}b=!!f}return r=b};Ia=function(){var b,a;if(va&&p.match(/os (1|2|3_0|3_1)/i)){c.hasHTML5=!1;c.html5Only=!0;if(c.oMC)c.oMC.style.display=
"none";return!1}if(c.useHTML5Audio){if(!c.html5||!c.html5.canPlayType)return c.hasHTML5=!1,!0;c.hasHTML5=!0;if(xa&&da())return!0}else return!0;for(a in c.audioFormats)if(c.audioFormats.hasOwnProperty(a)&&(c.audioFormats[a].required&&!c.html5.canPlayType(c.audioFormats[a].type)||c.flash[a]||c.flash[c.audioFormats[a].type]))b=!0;c.ignoreFlash&&(b=!1);c.html5Only=c.hasHTML5&&c.useHTML5Audio&&!b;return!c.html5Only};ba=function(b){var a,e,f=0;if(b instanceof Array){for(a=0,e=b.length;a<e;a++)if(b[a]instanceof
Object){if(c.canPlayMIME(b[a].type)){f=a;break}}else if(c.canPlayURL(b[a])){f=a;break}if(b[f].url)b[f]=b[f].url;return b[f]}return b};Fa=function(b){if(!b._hasTimer)b._hasTimer=!0,!wa&&c.html5PollingInterval&&(null===O&&0===aa&&(O=J.setInterval(Ha,c.html5PollingInterval)),aa++)};Ga=function(b){if(b._hasTimer)b._hasTimer=!1,!wa&&c.html5PollingInterval&&aa--};Ha=function(){var b;if(null!==O&&!aa)return J.clearInterval(O),O=null,!1;for(b=c.soundIDs.length;b--;)c.sounds[c.soundIDs[b]].isHTML5&&c.sounds[c.soundIDs[b]]._hasTimer&&
c.sounds[c.soundIDs[b]]._onTimer()};F=function(b){b="undefined"!==typeof b?b:{};c.onerror instanceof Function&&c.onerror.apply(j,[{type:"undefined"!==typeof b.type?b.type:null}]);"undefined"!==typeof b.fatal&&b.fatal&&c.disable()};Ka=function(){if(!xa||!da())return!1;var b=c.audioFormats,a,e;for(e in b)if(b.hasOwnProperty(e)&&("mp3"===e||"mp4"===e))if(c.html5[e]=!1,b[e]&&b[e].related)for(a=b[e].related.length;a--;)c.html5[b[e].related[a]]=!1};this._setSandboxType=function(){};this._externalInterfaceOK=
function(){if(c.swfLoaded)return!1;(new Date).getTime();c.swfLoaded=!0;I=!1;xa&&Ka();y?setTimeout(T,100):T()};W=function(b,a){function e(a,b){return'<param name="'+a+'" value="'+b+'" />'}if(K&&L)return!1;if(c.html5Only)return ka(),c.oMC=S(c.movieID),T(),L=K=!0,!1;var f=a||c.url,d=c.altURL||f,g;g=na();var h,j,i=H(),l,m=null,m=(m=k.getElementsByTagName("html")[0])&&m.dir&&m.dir.match(/rtl/i),b="undefined"===typeof b?c.id:b;ka();c.url=Ea(za?f:d);a=c.url;c.wmode=!c.wmode&&c.useHighPerformance?"transparent":
c.wmode;if(null!==c.wmode&&(p.match(/msie 8/i)||!y&&!c.useHighPerformance)&&navigator.platform.match(/win32|win64/i))c.wmode=null;g={name:b,id:b,src:a,width:"auto",height:"auto",quality:"high",allowScriptAccess:c.allowScriptAccess,bgcolor:c.bgColor,pluginspage:Oa+"www.macromedia.com/go/getflashplayer",title:"JS/Flash audio component (SoundManager 2)",type:"application/x-shockwave-flash",wmode:c.wmode,hasPriority:"true"};if(c.debugFlash)g.FlashVars="debug=1";c.wmode||delete g.wmode;if(y)f=k.createElement("div"),
j=['<object id="'+b+'" data="'+a+'" type="'+g.type+'" title="'+g.title+'" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="'+Oa+'download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" width="'+g.width+'" height="'+g.height+'">',e("movie",a),e("AllowScriptAccess",c.allowScriptAccess),e("quality",g.quality),c.wmode?e("wmode",c.wmode):"",e("bgcolor",c.bgColor),e("hasPriority","true"),c.debugFlash?e("FlashVars",g.FlashVars):"","</object>"].join("");else for(h in f=
k.createElement("embed"),g)g.hasOwnProperty(h)&&f.setAttribute(h,g[h]);oa();i=H();if(g=na())if(c.oMC=S(c.movieID)||k.createElement("div"),c.oMC.id){l=c.oMC.className;c.oMC.className=(l?l+" ":"movieContainer")+(i?" "+i:"");c.oMC.appendChild(f);if(y)h=c.oMC.appendChild(k.createElement("div")),h.className="sm2-object-box",h.innerHTML=j;L=!0}else{c.oMC.id=c.movieID;c.oMC.className="movieContainer "+i;h=i=null;if(!c.useFlashBlock)if(c.useHighPerformance)i={position:"fixed",width:"8px",height:"8px",bottom:"0px",
left:"0px",overflow:"hidden"};else if(i={position:"absolute",width:"6px",height:"6px",top:"-9999px",left:"-9999px"},m)i.left=Math.abs(parseInt(i.left,10))+"px";if(Ua)c.oMC.style.zIndex=1E4;if(!c.debugFlash)for(l in i)i.hasOwnProperty(l)&&(c.oMC.style[l]=i[l]);try{y||c.oMC.appendChild(f);g.appendChild(c.oMC);if(y)h=c.oMC.appendChild(k.createElement("div")),h.className="sm2-object-box",h.innerHTML=j;L=!0}catch(n){throw Error(G("domError")+" \n"+n.toString());}}return K=!0};V=function(){if(c.html5Only)return W(),
!1;if(h)return!1;h=c.getMovie(c.id);if(!h)N?(y?c.oMC.innerHTML=pa:c.oMC.appendChild(N),N=null,K=!0):W(c.id,c.url),h=c.getMovie(c.id);c.oninitmovie instanceof Function&&setTimeout(c.oninitmovie,1);return!0};U=function(){setTimeout(Ba,1E3)};Ba=function(){if($)return!1;$=!0;n.remove(j,"load",U);if(I&&!ya)return!1;var b;m||(b=c.getMoviePercent());setTimeout(function(){b=c.getMoviePercent();!m&&Ma&&(null===b?c.useFlashBlock||0===c.flashLoadTimeout?c.useFlashBlock&&qa():X(!0):0!==c.flashLoadTimeout&&X(!0))},
c.flashLoadTimeout)};A=function(){function b(){n.remove(j,"focus",A);n.remove(j,"load",A)}if(ya||!I)return b(),!0;ya=Ma=!0;Q&&I&&n.remove(j,"mousemove",A);$=!1;b();return!0};La=function(){var b,a=[];if(c.useHTML5Audio&&c.hasHTML5)for(b in c.audioFormats)c.audioFormats.hasOwnProperty(b)&&a.push(b+": "+c.html5[b]+(!c.html5[b]&&r&&c.flash[b]?" (using flash)":c.preferFlash&&c.flash[b]&&r?" (preferring flash)":!c.html5[b]?" ("+(c.audioFormats[b].required?"required, ":"")+"and no flash support)":""))};
M=function(b){if(m)return!1;if(c.html5Only)return m=!0,D(),!0;var a;if(!c.useFlashBlock||!c.flashLoadTimeout||c.getMoviePercent())m=!0,w&&(a={type:!r&&s?"NO_FLASH":"INIT_TIMEOUT"});if(w||b){if(c.useFlashBlock&&c.oMC)c.oMC.className=H()+" "+(null===c.getMoviePercent()?"swf_timedout":"swf_error");C({type:"ontimeout",error:a});F(a);return!1}if(c.waitForWindowLoad&&!ia)return n.add(j,"load",D),!1;D();return!0};T=function(){if(m)return!1;if(c.html5Only){if(!m)n.remove(j,"load",c.beginDelayedInit),c.enabled=
!0,M();return!0}V();try{h._externalInterfaceTest(!1),Ca(!0,c.flashPollingInterval||(c.useHighPerformance?10:50)),c.debugMode||h._disableDebug(),c.enabled=!0,c.html5Only||n.add(j,"unload",ha)}catch(b){return F({type:"JS_TO_FLASH_EXCEPTION",fatal:!0}),X(!0),M(),!1}M();n.remove(j,"load",c.beginDelayedInit);return!0};E=function(){if(ma)return!1;ma=!0;oa();if(!r&&c.hasHTML5)c.useHTML5Audio=!0,c.preferFlash=!1;Ja();c.html5.usingFlash=Ia();s=c.html5.usingFlash;La();if(!r&&s)c.flashLoadTimeout=1;k.removeEventListener&&
k.removeEventListener("DOMContentLoaded",E,!1);V();return!0};ua=function(){"complete"===k.readyState&&(E(),k.detachEvent("onreadystatechange",ua));return!0};la=function(){ia=!0;n.remove(j,"load",la)};da();n.add(j,"focus",A);n.add(j,"load",A);n.add(j,"load",U);n.add(j,"load",la);Q&&I&&n.add(j,"mousemove",A);k.addEventListener?k.addEventListener("DOMContentLoaded",E,!1):k.attachEvent?k.attachEvent("onreadystatechange",ua):F({type:"NO_DOM2_EVENTS",fatal:!0});"complete"===k.readyState&&setTimeout(E,100)}
var ea=null;if("undefined"===typeof SM2_DEFER||!SM2_DEFER)ea=new R;J.SoundManager=R;J.soundManager=ea})(window);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

39
inc/midibridge/README Normal file
View file

@ -0,0 +1,39 @@
The midibridge is a Javascript API for interacting with the midi devices on your computer.
It provides methods for detecting the midi devices and for connecting these devices with each other.
The midibridge itself is considered a midi device as well, so it can be connected to the detected devices.
The midibridge can generate and send midi events to midi output devices, and receive midi events from midi input devices.
The midibridge can also filter and alter midi events.
Recording and playing back midi events with a sequencer will be added in later versions.
A midi output device is a physical output port on your computer, a virtual output port or a software synthesizer. It can also be a sequencer, a file or a function.
A midi input device is a physical or virtual input port, a sequencer, a file or a function.
A midi device can be both in- and output. The midibridge itself for instance is both in- and output because it can send and receive midi events.
The actual interaction with the midi devices on your computer is done by a Java applet. The midibridge automatically adds the applet to your webpage.
The midibridge has no visual parts, it is 'headless' code. You could say the midibridge enables you to write a 'front-end' on top of the applet.
Midi Devices -> Java Applet -> Javascript Midibridge API -> a GUI in Javascript, Flash, SVG, C# (Silverlight)
Because the midibridge is written in native Javascript, you can use it conflict-free with any Javascript framework.
The only files you need to get started are:
/lib/midibridge-0.5.1.min.js
/java/midiapplet.jar
/lib/MidiBridge.js is the non-minified version of /lib/midibridge-0.5.1.min.js
The other files and notably the files in the /js folder are code snippets that i have used in the quick start guide and the documentation on my blogpost, see:
http://www.abumarkub.net/abublog/?p=399

83
inc/midibridge/index.html Normal file
View file

@ -0,0 +1,83 @@
<!doctype html>
<html xmlns="http://www.w3.org/1999/xhtml">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="Cache-Control" Content="no-cache">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<script type="text/javascript" src="lib/MidiBridge.js"></script>
<script type="text/javascript">
window.onload = function() {
var jsmidi = parent.jsmidi;
var notes = {};
var events = {};
var startTime = 0;
var eventTimeOn = {};
var eventTimeOff = {};
for (var key in parent.MIDI.noteToKey) {
events[key] = [];
eventTimeOn[key] = 0;
eventTimeOff[key] = 0;
}
parent.writeMIDI = function() {
var tracks = [];
for (var key in events) {
tracks.push(new jsmidi.MidiTrack({ events: events[key] }));
}
var song = jsmidi.MidiWriter({ tracks: tracks });
return "data:audio/mid;base64," + song.b64;
};
midiBridge.init({
connectAllInputsToFirstOutput: true,
data: function(event) {
if (!(event.status == 128 || event.status == 144)) return;
//
var noteName = event.noteName;
var now = (new Date()).getTime();
var id = parseInt(event.data1);
var velocity = parseInt(event.data2);
//
if (event.status == midiBridge.NOTE_ON) {
console.log(noteName, "on");
//
eventTimeOn[id] = now;
//
} else {
console.log(id, noteName, "off")
if (!startTime) startTime = now;
if (!eventTimeOn[id]) eventTimeOn[id] = startTime;
if (!eventTimeOff[id]) eventTimeOff[id] = startTime;
//
var begin = now - eventTimeOff[id];
var end = now - eventTimeOn[id];
var duration = Math.max(0, begin - end);
//
var note = {
duration: duration,
channel: 0,
pitch: id,
volume: velocity
};
//
events[id].push(jsmidi.MidiEvent.noteOn(note));
note.duration = end;
console.log('begin', begin, 'end', end, begin-end);
events[id].push(jsmidi.MidiEvent.noteOff(note));
//
eventTimeOff[id] = now;
}
},
ready: function() {
if (typeof(MIDI) === "undefined") var MIDI = {};
MIDI.Plugin = midiBridge;
if (parent.MIDI && parent.MIDI.Java) {
parent.MIDI.Java.confirm(MIDI.Plugin);
}
}
});
};
</script>
<body></body>
</html>

Binary file not shown.

View file

@ -0,0 +1,502 @@
/**
* This version is supported by all browsers that support native JSON parsing:
* - Firefox 3.5+
* - Chrome 4.0+
* - Safari 4.0+
* - Opera 10.5+
* - Internet Explorer 8.0+
*
* If you want this version to work with other browsers, you can use the JSON parsing methods of your favorite Javascript
* framework (e.g. jQuery, Dojo, YUI, Mootools, etc.)
*
* Note for IE8 users: if you include MidiBridge.js (or preferably the minified version of it: midibridge-0.5.min.js) in your html,
* the method addEventListener will be added to the window object. In fact this method is just a wrapper around the attachEvent method,
* see code at the bottom of this file.
*/
(function() {
var midiBridge = {
NOTE_OFF : 0x80, //128
NOTE_ON : 0x90, //144
POLY_PRESSURE : 0xA0, //160
CONTROL_CHANGE : 0xB0, //176
PROGRAM_CHANGE : 0xC0, //192
CHANNEL_PRESSURE : 0xD0, //208
PITCH_BEND : 0xE0, //224
SYSTEM_EXCLUSIVE : 0xF0, //240
NOTE_NAMES_SHARP : "sharp",
NOTE_NAMES_FLAT : "flat",
NOTE_NAMES_SOUNDFONT : "soundfont",
NOTE_NAMES_ENHARMONIC_SHARP : "enh-sharp",
NOTE_NAMES_ENHARMONIC_FLAT : "enh-flat"
};
//human readable representation of status byte midi data
var status = [];
status[0x80] = "NOTE OFF";
status[0x90] = "NOTE ON";
status[0xA0] = "POLY PRESSURE";
status[0xB0] = "CONTROL CHANGE";
status[0xC0] = "PROGRAM CHANGE";
status[0xD0] = "CHANNEL PRESSURE";
status[0xE0] = "PITCH BEND";
status[0xF0] = "SYSTEM EXCLUSIVE";
//notenames in different modi
var noteNames = {
"sharp" : ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"],
"flat" : ["C", "Dâ™­", "D", "Eâ™­", "E", "F", "Gâ™­", "G", "Aâ™­", "A", "Bâ™­", "B"],
"soundfont" : ["C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B"],
"enh-sharp" : ["B#", "C#", "C##", "D#", "D##", "E#", "F#", "F##", "G#", "G##", "A#", "A##"],
"enh-flat" : ["Dâ™­â™­", "Dâ™­", "Eâ™­â™­", "Eâ™­", "Fâ™­", "Gâ™­â™­", "Gâ™­", "Aâ™­â™­", "Aâ™­", "Bâ™­", "Bâ™­", "Câ™­"]
}
//variable that holds a reference to the JSON parser method of your liking, defaults to native JSON parsing
var parseJSON = JSON.parse;
//method that gets called when midi note events arrive from the applet
var ondata = null;
var onerror = null;
var onready = null;
//the applet object
var applet = null;
var connectAllInputs = false;
var connectFirstInput = false;
var connectFirstOutput = false;
var connectAllInputsToFirstOutput = true;
var javaDir = "java";
var devices = {};
midiBridge.version = "0.5.1";
midiBridge.ready = false;
midiBridge.noteNameModus = midiBridge.NOTE_NAMES_SHARP;
/**
* static method called to initialize the MidiBridge
* possible arguments:
* 1) callback [function] callback when midi data has arrived
* 2) config object
* - ready : [function] callback when midibridge is ready/initialized
* - error : [function] callback in case of an error
* - data : [function] callback when midi data has arrived
* - connectAllInputs : [true,false] all found midi input devices get connected automatically
* - connectFirstInput : [true,false] the first found midi input device gets connected automatically
* - connectFirstOutput : [true,false] the first found midi output device gets connected automatically
* - connectAllInputsToFirstOutput : [true,false] all found midi input devices will be automatically connected to the first found midi output device
* - javaDir : [string] the folder where you store the midiapplet.jar on your webserver, defaults to "java"
*/
midiBridge.init = function(arg) {
//var args = Array.prototype.slice.call(arguments);
if( typeof arg === "function") {
ondata = arg;
} else if( typeof arg === "object") {
var config = arg;
connectAllInputs = config.connectAllInputs;
connectFirstInput = config.connectFirstInput;
connectFirstOutput = config.connectFirstOutput;
connectAllInputsToFirstOutput = config.connectAllInputsToFirstOutput;
ondata = config.data;
onready = config.ready;
onerror = config.error;
switch(true) {
case connectAllInputs && connectFirstOutput:
connectAllInputs = false;
connectFirstInput = false;
connectFirstOutput = false;
connectAllInputsToFirstOutput = true;
break;
case connectAllInputsToFirstOutput:
connectAllInputs = false;
connectFirstInput = false;
connectFirstInput = false;
connectFirstOutput = false;
break;
case connectFirstInput:
connectAllInputs = false;
connectAllInputsToFirstOutput = false;
break;
case connectFirstOutput:
connectAllInputs = false;
connectAllInputsToFirstOutput = false;
break;
case connectAllInputs:
connectFirstInput = false;
connectFirstOutput = false;
connectAllInputsToFirstOutput = false;
break;
}
}
/**
* Very simple java plugin detection
*/
if(!navigator.javaEnabled()) {
if(onerror) {
onerror("no java plugin found; install or enable the java plugin")
} else {
console.log("no java plugin found; install or enable the java plugin");
}
return;
}
/**
* If you are using the JSON parse method of your favorite Javascript framework replace the followingn lines by onlu:
*
* loadJava();
*/
loadJava();
};
/**
* static method called by the applet
*/
midiBridge.msgFromJava = function(jsonString) {
var data = parseJSON(jsonString);
var msgId = data.msgId;
//console.log(jsonString);
//console.log(msgId);
switch(msgId) {
case "upgrade-java":
if(onerror) {
onerror("please upgrade your java plugin!")
} else {
console.log("please upgrade your java plugin!");
}
break;
case "midi-started":
getApplet();
if(applet) {
devices = data.devices;
midiBridge.ready = true;
if(connectAllInputs) {
midiBridge.connectAllInputs();
}
if(connectFirstInput) {
midiBridge.connectFirstInput();
}
if(connectFirstOutput) {
midiBridge.connectFirstOutput();
}
if(connectAllInputsToFirstOutput) {
midiBridge.connectAllInputsToFirstOutput();
}
if(onready) {
onready("midibridge started");
}
}
//console.log("applet:",applet);
break;
case "midi-data":
if(ondata) {
ondata(new MidiMessage(data));
}
break;
case "error":
if(onerror) {
onerror(data.code);
}
break;
}
};
/**
* Send a midi event from javascript to java
* @param status : the midi status byte, e.g. NOTE ON, NOTE OFF, PITCH BEND and so on
* @param channel : the midi channel that this event will be sent to 0 - 15
* @param data1 : the midi note number
* @param data2 : the second data byte, when the status byte is NOTE ON or NOTE OFF, data2 is the velocity
*/
midiBridge.sendMidiEvent = function(status, channel, data1, data2) {
if(checkIfReady()) {
return parseJSON(applet.processMidiEvent(status, channel, data1, data2));
}
};
/**
* Get the list of all currently connected midi devices
*/
midiBridge.getDevices = function() {
return devices;
};
/**
* Refresh the list of all currently connected midi devices
*/
midiBridge.refreshDevices = function() {
if(checkIfReady()) {
return parseJSON(applet.getDevices());
}
};
/**
* Connect all found midi inputs to the midibridge right after the midibridge has been initialized
*/
midiBridge.connectAllInputs = function() {
if(checkIfReady()) {
return parseJSON(applet.connectAllInputs());
}
};
/**
* Connect the first found midi input to the midibridge right after the midibridge has been initialized
*/
midiBridge.connectFirstInput = function() {
if(checkIfReady()) {
return parseJSON(applet.connectFirstInput());
}
};
/**
* Connect the first found midi output to the midibridge right after the midibridge has been initialized
*/
midiBridge.connectFirstOutput = function() {
if(checkIfReady()) {
return parseJSON(applet.connectFirstOutput());
}
};
/**
* Connect the first found midi output to all connected midi inputs right after the midibridge has been initialized
*/
midiBridge.connectAllInputsToFirstOutput = function() {
if(checkIfReady()) {
return parseJSON(applet.connectAllInputsToFirstOutput());
}
};
/**
* Connect midi a midi input to the bridge, and/or a midi input to a midi output
* @param midiInId : [int] id of the midi input that will be connected to the bridge, use the ids as retrieved by getDevices()
* @param midiOutId : [int] optional, the id of the midi output that will be connected to the chosen midi input
* @param filter : [array] an array containing status codes that will *not* be sent from the chosen midi input to the chosen midi output
* e.g. if you supply the array [midiBridge.PITCH_BEND, midiBridge.POLY_PRESSURE], pitch bend and poly pressure midi messages will not be forwarded to the output
*/
midiBridge.addConnection = function(midiInId, midiOutId, filter) {
if(checkIfReady()) {
midiOutId = midiOutId == undefined ? -1 : midiOutId;
filter = filter == undefined ? [] : filter;
return parseJSON(applet.addConnection(midiInId, midiOutId, filter));
}
};
/**
* Remove a midi connection between between an input and the midibridge, and/or the given in- and output
* @param midiIdIn : [int] the midi input
* @param midiIdOut : [int] optional, the midi output
*/
midiBridge.removeConnection = function(midiInId, midiOutId) {
if(checkIfReady()) {
return parseJSON(applet.removeConnection(midiInId, midiOutId));
}
};
/**
* All previously setup midi connections will be disconnected
*/
midiBridge.disconnectAll = function() {
if(checkIfReady()) {
return parseJSON(applet.disconnectAll());
}
};
midiBridge.loadBase64String = function(data){
return parseJSON(applet.loadBase64String(data));
}
midiBridge.playBase64String = function(data){
return parseJSON(applet.playBase64String(data));
}
midiBridge.loadMidiFile = function(url){
return parseJSON(applet.loadMidiFile(url));
}
midiBridge.playMidiFile = function(url){
return parseJSON(applet.playMidiFile(url));
}
midiBridge.startSequencer = function(){
applet.startSequencer();
}
midiBridge.pauseSequencer = function(){
applet.pauseSequencer();
}
midiBridge.stopSequencer = function(){
applet.stopSequencer();
}
midiBridge.closeSequencer = function(){
applet.closeSequencer();
}
midiBridge.getSequencerPosition = function(){
return applet.getSequencerPosition();
}
midiBridge.setSequencerPosition = function(pos){
applet.setSequencerPosition(pos);
}
/**
* Check if a midiBridge function is called before initialization
*/
function checkIfReady() {
if(!midiBridge.ready) {
if(onerror) {
onerror("midibridge not ready!");
}
return "midibridge not ready!";
}
return true;
}
/**
* A div with the applet object is added to the body of your html document
*/
function loadJava() {
//console.log("loadJava");
var javaDiv = document.createElement("div");
javaDiv.setAttribute("id", "midibridge-java");
var html = "";
html += '<object tabindex="0" id="midibridge-applet" type="application/x-java-applet" height="1" width="1">';
html += '<param name="codebase" value="' + javaDir + '/" />';
html += '<param name="archive" value="midiapplet.jar" />';
html += '<param name="code" value="net.abumarkub.midi.applet.MidiApplet" />';
html += '<param name="scriptable" value="true" />';
html += '<param name="minJavaVersion" value="1.5" />';
//html += 'Your browser needs the Java plugin to use the midibridge. You can download it <a href="http://www.java.com/en/" target="blank" title="abumarkub midibridge download java" rel="abumarkub midibridge download java">here</a>';
html += '</object>';
javaDiv.innerHTML = html;
document.body.appendChild(javaDiv);
}
/**
* class MidiMessage is used to wrap the midi note data that arrives from the applet
*/
var MidiMessage = (function()//constructor
{
var _constructor = function(data) {
this.data1 = data.data1;
this.data2 = data.data2;
this.status = data.status;
this.status = this.data2 == 0 && this.status == midiBridge.NOTE_ON ? midiBridge.NOTE_OFF : this.status;
this.channel = data.channel;
this.noteName = midiBridge.getNoteName(this.data1, midiBridge.noteNameModus);
this.statusCode = midiBridge.getStatus(this.status);
this.microsecond = data.microsecond;
this.time = midiBridge.getNiceTime(this.microsecond);
};
_constructor.prototype = {
toString : function() {
var s = "";
s += this.noteName + " " + this.statusCode + " " + this.data1 + " " + this.data2 + " " + this.status;
s += this.microsecond ? this.microsecond + " " + this.time : "";
//console.log(s);
return s;
},
toJSONString : function() {
var s;
if(this.microsecond){
s= "{'notename':" + this.noteName + ", 'status':" + this.status + ", 'data1':" + this.data1 + ", 'data2':" + this.data2 + ", 'microsecond':" + this.microsecond + ", 'time':" + this.time + "}";
}else{
s= "{'notename':" + this.noteName + ", 'status':" + this.status + ", 'data1':" + this.data1 + ", 'data2':" + this.data2 + "}";
}
//console.log(s);
return s;
}
}
return _constructor;
})();
midiBridge.getNoteName = function(noteNumber, mode) {
var octave = Math.floor(((noteNumber) / 12) - 1);
var noteName = noteNames[mode][noteNumber % 12];
return noteName + "" + octave;
};
midiBridge.getNoteNumber = function(noteName, octave) {
var index = -1;
noteName = noteName.toUpperCase();
for(var key in noteNames) {
var modus = noteNames[key];
for(var i = 0, max = modus.length; i < max; i++) {
if(modus[i] === noteName) {
index = i;
break;
}
}
}
if(index === -1) {
return "invalid note name";
}
noteNumber = (12 + index) + (octave * 12);
return noteNumber;
}
midiBridge.getStatus = function($statusCode) {
return status[$statusCode];
};
midiBridge.getNiceTime = function(microseconds)
{
//console.log(microseconds);
var r = "";
var t = (microseconds / 1000 / 1000) >> 0;
var h = (t / (60 * 60)) >> 0;
var m = ((t % (60 * 60)) / 60) >> 0;
var s = t % (60);
var ms = (((microseconds /1000) - (h * 3600000) - (m * 60000) - (s * 1000)) + 0.5) >> 0;
//console.log(t,h,m,s,ms);
r += h > 0 ? h + ":" : "";
r += h > 0 ? m < 10 ? "0" + m : m : m;
r += ":";
r += s < 10 ? "0" + s : s;
r += ":";
r += ms == 0 ? "000" : ms < 10 ? "00" + ms : ms < 100 ? "0" + ms : ms;
return r;
}
function getApplet() {
try {
applet = midiBridge.getObject("midibridge-applet");
} catch(e) {
//console.log(e)
//Firefox needs more time to initialize the Applet
setTimeout(getApplet, 25);
return;
}
}
midiBridge.getObject = function(objectName) {
var ua = navigator.userAgent.toLowerCase();
//console.log(ua);
if(ua.indexOf("msie") !== -1 || ua.indexOf("webkit") !== -1) {
return window[objectName];
} else {
return document[objectName];
}
}
//add addEventListener to IE8
if(!window.addEventListener) {
window.addEventListener = function($id, $callback, $bubble) {
window.attachEvent('onload', $callback);
}
}
window.midiBridge = midiBridge;
})(window);

154
js/Color.js Normal file
View file

@ -0,0 +1,154 @@
/*
Color.Space : 0.3 : mudcu.be
-----------------------------
STRING <-> HEX <-> RGB <-> HSL
-----------------------------
var HEX = 0xFF0000;
var HSL = Color.Space(HEX, "HEX>RGB>HSL");
*/
if (!window.Color) Color = {};
if (!window.Color.Space) Color.Space = {};
(function () {
var DEG_RAD = Math.PI / 180;
var RAD_DEG = 1 / DEG_RAD;
var shortcuts = { };
var root = Color.Space = function(color, route) {
if (shortcuts[route]) {
route = shortcuts[route];
}
var arr = route.split(">");
var key = "";
for (var n = 0; n < arr.length; n ++) {
if (n > 1) {
key = key.split("_");
key.shift();
key = key.join("_");
}
key += (n == 0 ? "" : "_") + arr[n];
if (n > 0) color = root[key](color);
}
return color;
};
// STRING = 'FFFFFF' | 'FFFFFFFF'
root.STRING_HEX = function (o) {
return parseInt('0x' + o);
};
// HEX = 0x000000 -> 0xFFFFFF
root.HEX_STRING = 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.HEX_RGB = function (o) {
return {
R: (o >> 16),
G: (o >> 8) & 0xFF,
B: o & 0xFF
};
};
// RGB = R: Red / G: Green / B: Blue
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_HSL = function (o) { // RGB from 0 to 1
// http://www.easyrgb.com/index.php?X=MATH&H=18#text18
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
};
};
// HSL (1978) = H: Hue / S: Saturation / L: Lightess
root.HSL_RGB = function (o) {
// http://www.easyrgb.com/index.php?X=MATH&H=19
var H = o.H / 360,
S = o.S / 100,
L = o.L / 100,
R, G, B, _1, _2;
function Hue_2_RGB(v1, v2, vH) {
if (vH < 0) vH += 1;
if (vH > 1) vH -= 1;
if ((6 * vH) < 1) return v1 + (v2 - v1) * 6 * vH;
if ((2 * vH) < 1) return v2;
if ((3 * vH) < 2) return v1 + (v2 - v1) * ((2 / 3) - vH) * 6;
return v1;
}
if (S == 0) { // HSL from 0 to 1
R = L * 255;
G = L * 255;
B = L * 255;
} else {
if (L < 0.5) _2 = L * (1 + S);
else _2 = (L + S) - (S * L);
_1 = 2 * L - _2;
R = 255 * Hue_2_RGB(_1, _2, H + (1 / 3));
G = 255 * Hue_2_RGB(_1, _2, H);
B = 255 * Hue_2_RGB(_1, _2, H - (1 / 3));
}
return {
R: R,
G: G,
B: B
};
};
})();

126
js/DOMLoader.XMLHttp.js Normal file
View file

@ -0,0 +1,126 @@
/*
DOMLoader.XMLHttp : 0.1 : mudcu.be
-----------------------------------
DOMLoader.sendRequest({
url: "./dir/something.extension",
error: function(event) {
console.log(event);
},
callback: function(response) {
console.log(response.responseText);
},
progress: function (event) {
var percent = event.loaded / event.total * 100 >> 0;
loader.message("loading: " + percent + "%");
}
});
*/
if (typeof(DOMLoader) === "undefined") DOMLoader = {};
(function() { "use strict";
// Add XMLHttpRequest when not available
if (typeof (window.XMLHttpRequest) === "undefined") {
(function () { // http://www.quirksmode.org/js/xmlhttp.html
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;
}
window.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 =
"<!-- IEBinaryToArray_ByteStr -->\r\n"+
"<script type='text/vbscript'>\r\n"+
"Function IEBinaryToArray_ByteStr(Binary)\r\n"+
" IEBinaryToArray_ByteStr = CStr(Binary)\r\n"+
"End Function\r\n"+
"Function IEBinaryToArray_ByteStr_Last(Binary)\r\n"+
" Dim lastIndex\r\n"+
" lastIndex = LenB(Binary)\r\n"+
" if lastIndex mod 2 Then\r\n"+
" IEBinaryToArray_ByteStr_Last = Chr( AscB( MidB( Binary, lastIndex, 1 ) ) )\r\n"+
" Else\r\n"+
" IEBinaryToArray_ByteStr_Last = "+'""'+"\r\n"+
" End If\r\n"+
"End Function\r\n"+
"</script>\r\n";
// inject VBScript
document.write(IEBinaryToArray_ByteStr_Script);
DOMLoader.sendRequest = function(config) {
// 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 = new XMLHttpRequest();
req.open("GET", config.url, true);
req.setRequestHeader("Accept-Charset", "x-user-defined");
if (config.responseType) req.responseType = config.responseType;
if (config.error) req.onerror = config.error;
if (config.progress) req.onprogress = config.progress;
req.onreadystatechange = function (event) {
if (req.readyState === 4) {
if (req.status === 200) {
req.responseText = getResponseText(req.responseBody);
} else {
req = false;
}
if (config.callback) config.callback(req);
}
};
req.send(null);
return req;
}
} else {
DOMLoader.sendRequest = function(config) {
var req = new XMLHttpRequest();
req.open('GET', config.url, true);
if (req.overrideMimeType) req.overrideMimeType("text/plain; charset=x-user-defined");
if (config.responseType) req.responseType = config.responseType;
if (config.error) req.onerror = config.error;
if (config.progress) req.onprogress = config.progress;
req.onreadystatechange = function (event) {
if (req.readyState === 4) {
if (req.status !== 200) req = false;
if (config.callback) config.callback(req);
}
};
req.send("");
return req;
};
}
})();

131
js/DOMLoader.script.js Normal file
View file

@ -0,0 +1,131 @@
/*
DOMLoader : 0.2 : mudcu.be
---------------------------
DOMLoader.script.add({
strictOrder: true,
srcs: [
{
src: "../js/jszip/jszip.js",
verify: "JSZip",
callback: function() {
console.log(1)
}
},
{
src: "../inc/downloadify/js/swfobject.js",
verify: "swfobject",
callback: function() {
console.log(2)
}
}
],
callback: function() {
console.log(3)
}
});
*/
if (typeof(DOMLoader) === "undefined") DOMLoader = {};
DOMLoader.script = function() {
this.loaded = {};
this.loading = {};
return this;
};
DOMLoader.script.prototype.add = function(config) {
var that = this;
var srcs = config.srcs;
if (typeof(srcs) === "undefined") {
srcs = [{
src: config.src,
verify: config.verify
}];
}
/// adding the elements to the head
var doc = document.getElementsByTagName("head")[0];
///
var testElement = function(element, test) {
if (that.loaded[element.src]) return;
if (test && !eval(test)) return;
that.loaded[element.src] = true;
//
if (that.loading[element.src]) that.loading[element.src]();
delete that.loading[element.src];
//
if (element.callback) element.callback();
if (typeof(getNext) !== "undefined") getNext();
};
///
var batchTest = [];
var addElement = function(element) {
if (/([\w\d.\[\]])$/.test(element.verify)) { // check whether its a variable reference
element.test = "(typeof(" + element.verify + ") !== \"undefined\")";
batchTest.push(element.test);
}
var script = document.createElement("script");
script.onreadystatechange = function() {
if (this.readyState !== "loaded" && this.readyState !== "complete") return;
testElement(element);
};
script.onload = function() {
testElement(element);
};
script.setAttribute("type", "text/javascript");
script.setAttribute("src", element.src);
doc.appendChild(script);
that.loading[element.src] = function() {};
};
/// checking to see whether everything loaded properly
var onLoad = function(element) {
if (element) {
testElement(element, element.test);
} else {
for (var n = 0; n < srcs.length; n ++) {
testElement(srcs[n], srcs[n].test);
}
}
if (!config.strictOrder && eval(batchTest.join(" && "))) { // finished loading all the requested scripts
if (config.callback) config.callback();
} else { // keep calling back the function
setTimeout(function() { //- should get slower over time?
onLoad(element);
}, 10);
}
};
/// loading methods; strict ordering or loose ordering
if (config.strictOrder) {
var ID = -1;
var getNext = function() {
ID ++;
if (!srcs[ID]) { // all elements are loaded
if (config.callback) config.callback();
} else { // loading new script
var element = srcs[ID];
var src = element.src;
if (that.loading[src]) { // already loading from another call (attach to event)
that.loading[src] = function() {
if (element.callback) element.callback();
getNext();
}
} else if (!that.loaded[src]) { // create script element
addElement(element);
onLoad(element);
} else { // it's already been successfully loaded
getNext();
}
}
};
getNext();
} else { // loose ordering
for (var ID = 0; ID < srcs.length; ID ++) {
if (that.loaded[srcs[ID].src]) return;
addElement(srcs[ID]);
}
onLoad();
}
};
DOMLoader.script = (new DOMLoader.script());

155
js/Event.Mouse.js Normal file
View file

@ -0,0 +1,155 @@
/*
Event.Mouse : 0.3.1 : mudcu.be
-------------------------------------
Event.add(document, "mousedown", function(event) {
Event.drag({
type: "absolute",
event: event,
element: document,
callback: function (event, coords, state, self) {
Event.stopPropagation(event);
Event.preventDefault(event);
console.log(coords);
}
});
});
// this does the same thing
Event.drag({
type: "absolute",
element: document,
callback: function (event, coords, state, self) {
console.log(coords);
}
});
/// easier mousewheel events
Event.mousewheel(window, function(event, state, wheelData, self) {
self.stop.prevent.remove();
});
*/
if (typeof(Event) === "undefined") var Event = {};
Event.drag =
Event.dragElement = function(props) {
var el = props.element || document.body;
var doc = el.ownerDocument; // could be within an iframe
if (typeof(props.event) === "undefined") { // create event
Event.add(el, "mousedown", function(event) {
props.event = event;
Event.dragElement(props);
Event.preventDefault(event);
Event.stopPropagation(event);
});
return;
}
// functions accessible externally
var self = {
cancel: function() {
Event.remove(doc, "mousemove", mouseMove);
Event.remove(doc, "mouseup", mouseUp);
}
};
// event move
var mouseMove = function (event, state) {
if (typeof(state) === "undefined") state = "move";
var coord = Event.coords(event);
switch (props.type) {
case "move": // move
props.callback(event, {
x: coord.x + oX - eX,
y: coord.y + oY - eY
}, state, self);
break;
case "difference": // relative, from position within element
props.callback(event, {
x: coord.x - oX,
y: coord.y - oY
}, state, self);
break;
case "relative": // eveything is relative from origin
props.callback(event, {
x: coord.x - eX,
y: coord.y - eY
}, state, self);
break;
default: // "absolute", origin is 0x0
props.callback(event, {
x: coord.x,
y: coord.y
}, state, self);
break;
}
};
// event up
var mouseUp = function(event) {
self.cancel();
mouseMove(event, "up");
};
// current element position
var origin = abPos(el);
var oX = origin.x;
var oY = origin.y;
// current mouse position
var event = props.event;
var coord = Event.coords(event);
var eX = coord.x;
var eY = coord.y;
// events
Event.add(doc, "mousemove", mouseMove);
Event.add(doc, "mouseup", mouseUp);
mouseMove(event, "down"); // run mouse-down
//
return self;
};
Event.coords = (function() {
if (window.ActiveXObject) {
return function(event) {
return {
x: event.clientX + document.documentElement.scrollLeft,
y: event.clientY + document.documentElement.scrollTop
};
};
} else {
return function(event) {
return {
x: event.pageX,
y: event.pageY
};
};
}
})();
//////////////// MouseWheel ////////////////
Event.mousewheel = function(target, listener, timeout) {
var interval = 0;
var self = Event(target, "mousewheel", function(event) {
event = event || window.event;
var wheelData = event.detail ? event.detail * -1 : event.wheelDelta / 40;
listener(event, "wheel", wheelData);
window.clearInterval(interval);
interval = window.setInterval(function() {
window.clearInterval(interval);
listener(event, "wheelup", wheelData, self);
}, timeout || 150);
});
return self;
};
///// DOM.absPos
var abPos = function(o) {
o = typeof(o) === 'object' ? o : document.getElementById(o);
var offset = { x: 0, y: 0 };
while(o != null) {
offset.x += o.offsetLeft;
offset.y += o.offsetTop;
o = o.offsetParent;
};
return offset;
};

203
js/Event.js Normal file
View file

@ -0,0 +1,203 @@
/*
Event.js : v1.1 : mudcu.be
-----------------------
/// calling "Event" with "new" provides additional support;
Event(syntax.area, "click", function(event, self) {
self.stop().prevent().remove();
});
/// calling "Event" without "new" also works, but requires more work (and is faster);
var click = Event.add(syntax.area, "click", function(event) {
Event.stop(event);
Event.prevent(event);
Event.remove(syntax.area, "click", click);
});
/// multiple event-types bound to one function
var binding = Event(window, "click,mousemove,mousemove,mouseup", function(event, self) {
self.stop().prevent(); // stopPropagation and preventDefault
binding.remove(); // removes all the listeners
});
/// multiple events bound to one element
var binding = Event(window, {
"mousedown": function(event, self) {
self.remove(); // remove all the listeners
},
"mouseup": function(event, self) {
binding.remove(); // just remove this listener
}
});
*/
var Event = (function(root) { "use strict";
var add = document.addEventListener ? 'addEventListener' : 'attachEvent';
var remove = document.removeEventListener ? 'removeEventListener' : 'detachEvent';
var isEvent = (function () {
var events = {};
var types = [
'abort', 'beforeunload', 'blur', 'broadcast', 'change', 'click', 'close',
'command', 'commandupdate', 'contextmenu', 'dblclick', 'dragdrop',
'dragenter', 'dragexit', 'draggesture', 'dragover', 'error', 'focus',
'input', 'keydown', 'keypress', 'keyup', 'load', 'mousedown',
'mousewheel', 'mouseenter', 'mouseleave', 'mousemove', 'mouseout', 'mouseover',
'mouseup', 'move', 'overflow', 'overflowchanged', 'popuphidden',
'popuphiding', 'popupshowing', 'popupshown', 'select', 'scroll',
'syncfrompreference', 'synctopreference', 'readystatechange',
'reset', 'resize', 'select', 'submit', 'underflow', 'unload'
];
for (var n = 0, length = types.length; n < length; n ++) {
events[types[n]] = true;
}
return events;
})();
// event wrappers, and associated variables
var wrappers = {};
var counter = 0;
var testElement = document.createElement("div");
var getEventID = function(object) {
if (object === window) return "#window";
if (object === document) return "#document";
if (!object) object = {}; // FIXME: Happens in iOS
if (!object.uniqueID) {
object.uniqueID = "id" + counter ++;
}
return object.uniqueID;
};
// function to create new Events
root = {}; // double type the root function as object + function
root = function(target, type, listener, scope) {
// find the where function was called from (window is undefined)
var that = typeof(this) !== "undefined" ? this : {};
// check for multiple events in one string
if (type.indexOf && type.indexOf(",") !== -1) {
type = type.split(",");
}
// check type for multipel events
if (typeof(type) !== "string") { // has multiple events
that.events = {};
if (typeof(type.length) === "undefined") { // has multiple listeners (object)
for (var key in type) {
if (isEvent[key] && typeof(type[key]) === "function") {
that.events[key] = Event(target, key, type[key], scope);
}
}
} else { // has multiple listeners glued together (array)
for (var n = 0, length = type.length; n < length; n ++) {
that.events[type[n]] = Event(target, type[n], listener, scope);
}
}
that.remove = function() { // remove multiple events
for (var key in that.events) {
that.events[key].remove();
}
return that;
};
that.add = function() { // add multiple events
for (var key in that.events) {
that.events[key].add();
}
return that;
};
return that;
} else { // is single call
if (!(target && type && listener)) return "missing data.";
type = standardize(type);
}
// tracked wrapper
var wrapperID = type + getEventID(target) + "." + getEventID(listener);
if (!wrappers[wrapperID]) { // create new wrapper
wrappers[wrapperID] = function(event) {
return listener.call(scope, that.event = event, that);
};
}
// the wrapped listener
var wrapper = wrappers[wrapperID];
target[add](type, wrapper, false);
//
that.stop = function(event) {
event = event || that.event;
if (event.stopPropagation) {
event.stopPropagation();
} else { // <= IE8
event.cancelBubble = true;
}
return that;
};
that.prevent = function(event) {
event = event || that.event;
if (event.preventDefault) {
event.preventDefault();
} else { // <= IE8
event.returnValue = false;
}
return that;
};
that.add = function() { // so you can add it back
target[add](type, wrapper, false);
return that;
};
that.remove = function() {
target[remove](type, wrapper, false);
return that;
};
return that;
};
root.add = function(target, type, listener, scope) {
type = standardize(type);
target[add](type, wrap(type, target, listener, scope || target), false);
return listener;
};
root.remove = function(target, type, listener, scope) {
type = standardize(type);
target[remove](type, wrap(type, target, listener, scope || target), false);
return listener;
};
root.stop =
root.stopPropagation = function(event) {
if (event.stopPropagation) {
event.stopPropagation();
} else { // <= IE8
event.cancelBubble = true;
}
};
root.prevent =
root.preventDefault = function(event) {
if (event.preventDefault) {
event.preventDefault();
} else { // <= IE8
event.returnValue = false;
}
};
/////////////
var standardize = function(type) { // fix any browser discrepancies
if (!document.addEventListener) {
return "on" + type;
} else if (type === "mousewheel" && !("onmousewheel" in testElement)) {
return "DOMMouseScroll";
} else { //
return type;
}
};
var wrap = function(type, target, listener, scope) { // un-tracked wrapper
var wrapperID = type + getEventID(target) + "." + getEventID(listener);
if (!wrappers[wrapperID]) {
wrappers[wrapperID] = function(event) {
return listener.call(scope, event);
};
}
return wrappers[wrapperID];
};
//
return root;
//
})(Event);

279
js/MIDI.Player.js Normal file
View file

@ -0,0 +1,279 @@
/*
MIDI.Player : 0.3
-------------------------------------
https://github.com/mudx/MIDI.js
-------------------------------------
requires 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 delay = config.delay || 100;
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
});
}, delay);
};
// helpers
var 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;
loadMidiFile();
if (callback) callback(data);
return;
}
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 = window.atob(ff.join(""));
root.currentData = data;
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.setInterval(function () {
window.clearInterval(interval);
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 - 10, 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 = {};
};
})();

486
js/MIDI.Plugin.js Normal file
View file

@ -0,0 +1,486 @@
/*
MIDI.Plugin : 0.3
-------------------------------------
https://github.com/mudx/MIDI.js
-------------------------------------
MIDI.WebAudioAPI
MIDI.Flash
MIDI.HTML5
MIDI.instruments
MIDI.channels
MIDI.keyToNote
MIDI.noteToKey
setMute?
getInstruments?
*/
if (typeof (MIDI) === "undefined") var MIDI = {};
if (typeof (MIDI.Plugin) === "undefined") MIDI.Plugin = {};
(function() { "use strict";
/*
Web Audio API - OGG or MPEG Soundbank
--------------------------------------
https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html
*/
if (typeof (MIDI.WebAudioAPI) === "undefined") MIDI.WebAudioAPI = {};
if (window.AudioContext || window.webkitAudioContext) (function () {
var AudioContext = window.AudioContext || window.webkitAudioContext;
var root = MIDI.WebAudioAPI;
var ctx;
var sources = {};
var masterVolume = 1;
var audioBuffers = {};
var audioLoader = function (urlList, index, bufferList, oncomplete) {
var url = urlList[index];
var base64 = MIDI.Soundfont[url].split(",")[1];
var buffer = Base64Binary.decodeArrayBuffer(base64);
ctx.decodeAudioData(buffer, function (buffer) {
var msg = url; while(msg.length < 3) msg += "&nbsp;";
if (typeof(loader) !== "undefined") {
loader.message("Downloading: 100%<br>Processing: "+(index/87 * 100 >> 0)+"%<br>" + msg);
}
buffer.id = url;
bufferList[index] = buffer;
//
if (bufferList.length === urlList.length) {
while (bufferList.length) {
buffer = bufferList.pop();
var nodeId = MIDI.keyToNote[buffer.id];
audioBuffers[nodeId] = buffer;
}
oncomplete();
}
});
};
root.setVolume = function (n) {
masterVolume = n;
};
root.programChange = function (instrument) {
};
root.noteOn = function (channel, note, velocity, delay) {
/// check whether the note exists
if (!audioBuffers[note]) return;
/// convert relative delay to absolute delay
if (delay < ctx.currentTime) delay += ctx.currentTime;
/// crate audio buffer
var source = ctx.createBufferSource();
sources[channel + "" + note] = source;
source.buffer = audioBuffers[note];
source.connect(ctx.destination);
//
var gainNode = ctx.createGainNode();
var value = -0.5 + (velocity / 100) * 2;
var minus = (1 - masterVolume) * 2;
gainNode.connect(ctx.destination);
gainNode.gain.value = Math.max(-1, value - minus);
source.connect(gainNode);
//
// source.playbackRate.value = 2;
///
source.noteOn(delay || 0);
return source;
};
root.chordOn = function (channel, chord, velocity, delay) {
var ret = {}, note;
for (var n = 0, length = chord.length; n < length; n ++) {
ret[note = chord[n]] = root.noteOn(channel, note, velocity, delay);
}
return ret;
};
// FIX: needs some way to fade out smoothly..
root.noteOff = function (channel, note, delay) {
// var source = sources[channel+""+note];
// if (!source) return;
// source.noteOff(delay || 0);
// return source;
};
root.chordOff = function (channel, chord, delay) {
};
root.connect = function (callback) {
MIDI.lang = 'WebAudioAPI';
MIDI.setVolume = root.setVolume;
MIDI.programChange = root.programChange;
MIDI.noteOn = root.noteOn;
MIDI.noteOff = root.noteOff;
MIDI.chordOn = root.chordOn;
MIDI.chordOff = root.chordOff;
//
MIDI.Player.ctx = ctx = new AudioContext();
///
var urlList = [];
var keyToNote = MIDI.keyToNote;
for (var key in keyToNote) urlList.push(key);
var bufferList = [];
for (var i = 0; i < urlList.length; i++) {
audioLoader(urlList, i, bufferList, callback);
}
};
})();
/*
HTML5 <audio> - OGG or MPEG Soundbank
--------------------------------------
http://dev.w3.org/html5/spec/Overview.html#the-audio-element
*/
if (window.Audio) (function () {
var root = MIDI.HTML5 = {};
var note2id = {};
var volume = 1; // floating point
var channel_nid = -1; // current channel
var channel_map = {}; // map to current playing <audio> elements
var channels = []; // the audio channels
var notes = {}; // the piano keys
for (var nid = 0; nid < 12; nid++) {
channels[nid] = new Audio();
}
var playChannel = function (id) {
var note = notes[id];
if (!note) return;
var nid = (channel_nid + 1) % channels.length;
var time = (new Date()).getTime();
var audio = channels[nid];
channel_map[note.id] = audio;
audio.src = MIDI.Soundfont[note.id];
audio.volume = volume;
audio.play();
channel_nid = nid;
};
root.programChange = function () {
};
root.setVolume = function (n) {
volume = n;
};
root.noteOn = function (channel, note, velocity, delay) {
var id = note2id[note];
if (!notes[id]) return;
if (delay) {
var interval = window.setTimeout(function() {
playChannel(id);
}, delay * 1000);
return interval;
} else {
playChannel(id);
}
};
root.noteOff = function (channel, note, delay) {
// var nid = note2id[note];
// channel_map[nid].pause();
};
root.chordOn = function (channel, chord, velocity, delay) {
for (var key in chord) {
var n = chord[key];
var id = note2id[n];
if (!notes[id]) continue;
playChannel(id);
}
};
root.chordOff = function (channel, chord, delay) {
};
root.stopAllNotes = function () {
for (var nid = 0, length = channels.length; nid < length; nid++) {
channels[nid].pause();
}
};
root.connect = function (callback) {
var loading = {};
for (var key in MIDI.keyToNote) {
note2id[MIDI.keyToNote[key]] = key;
notes[key] = {
id: key
};
}
MIDI.lang = 'HTML5';
MIDI.setVolume = root.setVolume;
MIDI.programChange = root.programChange;
MIDI.noteOn = root.noteOn;
MIDI.noteOff = root.noteOff;
MIDI.chordOn = root.chordOn;
MIDI.chordOff = root.chordOff;
//
if (callback) callback();
//
};
})();
/*
Flash - MP3 Soundbank
----------------------
http://www.schillmania.com/projects/soundmanager2/
*/
(function () {
var root = MIDI.Flash = {};
var noteReverse = {};
var notes = {};
root.programChange = function () {
};
root.setVolume = function (channel, note) {
};
root.noteOn = function (channel, note, velocity, delay) {
var id = noteReverse[note];
if (!notes[id]) return;
if (delay) {
var interval = window.setTimeout(function() {
notes[id].play({ volume: velocity * 2 });
}, delay * 1000);
return interval;
} else {
notes[id].play({ volume: velocity * 2 });
}
};
root.noteOff = function (channel, note, delay) {
};
root.chordOn = function (channel, chord, velocity, delay) {
for (var key in chord) {
var n = chord[key];
var id = noteReverse[n];
if (notes[id]) {
notes[id].play({ volume: velocity * 2 });
}
}
};
root.chordOff = function (channel, chord, delay) {
};
root.stopAllNotes = function () {
};
root.connect = function (callback) {
soundManager.flashVersion = 9;
soundManager.useHTML5Audio = true;
soundManager.url = '../../swf/';
soundManager.useHighPerformance = true;
soundManager.wmode = 'transparent';
soundManager.flashPollingInterval = 1;
soundManager.debugMode = false;
soundManager.onload = function () {
var loaded = [];
var onload = function () {
loaded.push(this.sID);
if (typeof (loader) === "undefined") return;
loader.message("Processing: " + this.sID);
};
for (var i = 10; i < 65 + 10; i++) {
var id = noteReverse[i + 26];
notes[id] = soundManager.createSound({
id: id,
url: './soundfont/mp3/' + id + '.mp3',
multiShot: true,
autoLoad: true,
onload: onload
});
}
MIDI.lang = 'Flash';
MIDI.setVolume = root.setVolume;
MIDI.programChange = root.programChange;
MIDI.noteOn = root.noteOn;
MIDI.noteOff = root.noteOff;
MIDI.chordOn = root.chordOn;
MIDI.chordOff = root.chordOff;
//
var interval = window.setInterval(function () {
if (loaded.length !== 65) return;
window.clearInterval(interval);
if (callback) callback();
}, 25);
};
soundManager.onerror = function () {
};
for (var key in MIDI.keyToNote) {
noteReverse[MIDI.keyToNote[key]] = key;
}
};
})();
/*
Java - Native Soundbank
----------------------------
https://github.com/abudaan/midibridge-js
http://java.sun.com/products/java-media/sound/soundbanks.html
*/
(function () {
var root = MIDI.Java = {};
root.connect = function (callback) {
// deferred loading of <applet>
MIDI.Plugin = false;
if (!window.navigator.javaEnabled()) {
MIDI.Flash.connect(callback);
return;
}
MIDI.Java.callback = callback;
var iframe = document.createElement('iframe');
iframe.name = 'MIDIFrame';
iframe.src = 'inc/midibridge/index.html';
iframe.width = 1;
iframe.height = 1;
document.body.appendChild(iframe);
};
root.confirm = function (plugin) {
MIDI.programChange = function (program) {
plugin.sendMidiEvent(0xC0, 0, program, 0);
};
MIDI.setVolume = function (n) {
};
MIDI.noteOn = function (channel, note, velocity, delay) {
if (delay) {
var interval = window.setTimeout(function() {
plugin.sendMidiEvent(0x90, channel, note, velocity);
}, delay * 1000);
return interval;
} else {
plugin.sendMidiEvent(0x90, channel, note, velocity);
}
};
MIDI.noteOff = function (channel, note, delay) {
if (delay) {
var interval = window.setTimeout(function() {
plugin.sendMidiEvent(0x80, channel, note, 0);
}, delay * 1000);
return interval;
} else {
plugin.sendMidiEvent(0x80, channel, note, 0);
}
};
MIDI.chordOn = function (channel, chord, velocity, delay) {
for (var key in chord) {
var n = chord[key];
plugin.sendMidiEvent(0x90, channel, n, 100);
}
};
MIDI.chordOff = function (channel, chord, delay) {
for (var key in chord) {
var n = chord[key];
plugin.sendMidiEvent(0x80, channel, n, 100);
}
};
MIDI.stopAllNotes = function () {
};
MIDI.getInstruments = function() {
return [];
};
///
if (plugin.ready) {
MIDI.lang = "Java";
if (MIDI.Java.callback) {
MIDI.Java.callback();
}
} else {
MIDI.Flash.connect(MIDI.Java.callback);
}
};
})();
/*
helper functions
*/
// instrument-tracker
MIDI.instruments = (function (arr) {
var instruments = {};
for (var key in arr) {
var list = arr[key];
for (var n = 0, length = list.length; n < length; n++) {
var instrument = list[n];
if (!instrument) continue;
var num = parseInt(instrument.substr(0, instrument.indexOf(" ")), 10);
instrument = instrument.replace(num + " ", "");
instruments[--num] = {
instrument: instrument,
category: key
};
instruments[instrument] = {
number: num,
category: key
};
}
}
return instruments;
})({
'Piano': ['1 Acoustic Grand Piano', '2 Bright Acoustic Piano', '3 Electric Grand Piano', '4 Honky-tonk Piano', '5 Electric Piano 1', '6 Electric Piano 2', '7 Harpsichord', '8 Clavinet'],
'Chromatic Percussion': ['9 Celesta', '10 Glockenspiel', '11 Music Box', '12 Vibraphone', '13 Marimba', '14 Xylophone', '15 Tubular Bells', '16 Dulcimer'],
'Organ': ['17 Drawbar Organ', '18 Percussive Organ', '19 Rock Organ', '20 Church Organ', '21 Reed Organ', '22 Accordion', '23 Harmonica', '24 Tango Accordion'],
'Guitar': ['25 Acoustic Guitar (nylon)', '26 Acoustic Guitar (steel)', '27 Electric Guitar (jazz)', '28 Electric Guitar (clean)', '29 Electric Guitar (muted)', '30 Overdriven Guitar', '31 Distortion Guitar', '32 Guitar Harmonics'],
'Bass': ['33 Acoustic Bass', '34 Electric Bass (finger)', '35 Electric Bass (pick)', '36 Fretless Bass', '37 Slap Bass 1', '38 Slap Bass 2', '39 Synth Bass 1', '40 Synth Bass 2'],
'Strings': ['41 Violin', '42 Viola', '43 Cello', '44 Contrabass', '45 Tremolo Strings', '46 Pizzicato Strings', '47 Orchestral Harp', '48 Timpani'],
'Ensemble': ['49 String Ensemble 1', '50 String Ensemble 2', '51 Synth Strings 1', '52 Synth Strings 2', '53 Choir Aahs', '54 Voice Oohs', '55 Synth Choir', '56 Orchestra Hit'],
'Brass': ['57 Trumpet', '58 Trombone', '59 Tuba', '60 Muted Trumpet', '61 French Horn', '62 Brass Section', '63 Synth Brass 1', '64 Synth Brass 2'],
'Reed': ['65 Soprano Sax', '66 Alto Sax', '67 Tenor Sax', '68 Baritone Sax', '69 Oboe', '70 English Horn', '71 Bassoon', '72 Clarinet'],
'Pipe': ['73 Piccolo', '74 Flute', '75 Recorder', '76 Pan Flute', '77 Blown Bottle', '78 Shakuhachi', '79 Whistle', '80 Ocarina'],
'Synth Lead': ['81 Lead 1 (square)', '82 Lead 2 (sawtooth)', '83 Lead 3 (calliope)', '84 Lead 4 (chiff)', '85 Lead 5 (charang)', '86 Lead 6 (voice)', '87 Lead 7 (fifths)', '88 Lead 8 (bass + lead)'],
'Synth Pad': ['89 Pad 1 (new age)', '90 Pad 2 (warm)', '91 Pad 3 (polysynth)', '92 Pad 4 (choir)', '93 Pad 5 (bowed)', '94 Pad 6 (metallic)', '95 Pad 7 (halo)', '96 Pad 8 (sweep)'],
'Synth Effects': ['97 FX 1 (rain)', '98 FX 2 (soundtrack)', '99 FX 3 (crystal)', '100 FX 4 (atmosphere)', '101 FX 5 (brightness)', '102 FX 6 (goblins)', '103 FX 7 (echoes)', '104 FX 8 (sci-fi)'],
'Ethnic': ['105 Sitar', '106 Banjo', '107 Shamisen', '108 Koto', '109 Kalimba', '110 Bagpipe', '111 Fiddle', '112 Shanai'],
'Percussive': ['113 Tinkle Bell', '114 Agogo', '115 Steel Drums', '116 Woodblock', '117 Taiko Drum', '118 Melodic Tom', '119 Synth Drum'],
'Sound effects': ['120 Reverse Cymbal', '121 Guitar Fret Noise', '122 Breath Noise', '123 Seashore', '124 Bird Tweet', '125 Telephone Ring', '126 Helicopter', '127 Applause', '128 Gunshot']
});
// channel-tracker
MIDI.channels = (function () { // 0 - 15 channels
var channels = {};
for (var n = 0; n < 16; n++) {
channels[n] = { // default values
instrument: 0,
// Acoustic Grand Piano
mute: false,
mono: false,
omni: false,
solo: false
};
}
return channels;
})();
// note conversions
MIDI.keyToNote = {}; // C8 == 108
MIDI.noteToKey = {}; // 108 == C8
(function () {
var A0 = 0x15; // first note
var C8 = 0x6C; // last note
var number2key = ["C", "Db", "D", "Eb", "E", "F", "Gb", "G", "Ab", "A", "Bb", "B"];
for (var n = A0; n <= C8; n++) {
var octave = (n - 12) / 12 >> 0;
var name = number2key[n % 12] + octave;
MIDI.keyToNote[name] = n;
MIDI.noteToKey[n] = name;
}
})();
})();
MIDI.pianoKeyOffset = 21;

63
js/MIDI.audioDetect.js Normal file
View file

@ -0,0 +1,63 @@
/*
MIDI.audioDetect : 0.3
-------------------------------------
https://github.com/mudx/MIDI.js
-------------------------------------
Probably, Maybe, No... Absolutely!
-------------------------------------
Test to see what types of <audio> MIME types are playable by the browser.
*/
if (typeof(MIDI) === "undefined") var MIDI = {};
(function() { "use strict";
var supports = {};
var canPlayThrough = function (src) {
var audio = new Audio();
var mime = src.split(";")[0];
audio.id = "audio";
audio.setAttribute("preload", "auto");
audio.setAttribute("audiobuffer", true);
audio.addEventListener("canplaythrough", function() {
supports[mime] = true;
}, false);
audio.src = "data:" + src;
document.body.appendChild(audio);
};
MIDI.audioDetect = function(callback) {
// check whether <audio> tag is supported
if (typeof(Audio) === "undefined") return callback({});
// check whether canPlayType is supported
var audio = new Audio();
if (typeof(audio.canPlayType) === "undefined") return callback(supports);
// see what we can learn from the browser
var vorbis = audio.canPlayType('audio/ogg; codecs="vorbis"');
vorbis = (vorbis === "probably" || vorbis === "maybe");
var mpeg = audio.canPlayType('audio/mpeg');
mpeg = (mpeg === "probably" || mpeg === "maybe");
// maybe nothing is supported
if (!vorbis && !mpeg) {
callback(supports);
return;
}
// or maybe something is supported
if (vorbis) canPlayThrough("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=");
if (mpeg) canPlayThrough("audio/mpeg;base64,/+MYxAAAAANIAUAAAASEEB/jwOFM/0MM/90b/+RhST//w4NFwOjf///PZu////9lns5GFDv//l9GlUIEEIAAAgIg8Ir/JGq3/+MYxDsLIj5QMYcoAP0dv9HIjUcH//yYSg+CIbkGP//8w0bLVjUP///3Z0x5QCAv/yLjwtGKTEFNRTMuOTeqqqqqqqqqqqqq/+MYxEkNmdJkUYc4AKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq");
// lets find out!
var time = (new Date()).getTime();
var interval = window.setInterval(function() {
for (var key in supports) {}
var now = (new Date()).getTime();
var maxExecution = now - time > 5000;
if (key || maxExecution) {
window.clearInterval(interval);
callback(supports);
}
}, 1);
};
})();

95
js/MIDI.loadPlugin.js Normal file
View file

@ -0,0 +1,95 @@
/*
MIDI.loadPlugin(callback, type);
-------------------------------------
https://github.com/mudx/MIDI.js
-------------------------------------
*/
if (typeof (MIDI) === "undefined") var MIDI = {};
if (typeof (MIDI.Soundfont) === "undefined") MIDI.Soundfont = {};
(function() { "use strict";
var plugins = { "#webaudio": true, "#html5": true, "#java": true, "#flash": true };
MIDI.loadPlugin = function(callback, instrument) {
var type, loader;
var instrument = instrument || "";
MIDI.audioDetect(function(types) {
// use the most appropriate plugin if not specified
if (typeof(type) === 'undefined') {
if (plugins[window.location.hash]) {
type = window.location.hash;
} else {
type = "";
}
}
if (type === "") {
var isSafari = navigator.userAgent.toLowerCase().indexOf("safari") !== -1;
if (window.webkitAudioContext) { // Chrome
type = "#webaudio";
} else if (window.Audio && isSafari === false) { // Firefox
type = "#html5";
} else { // Safari and Internet Explorer
type = "#flash";
}
}
// use audio/ogg when supported
var filetype = types["audio/ogg"] ? "ogg" : "mp3";
// load the specified plugin
switch (type) {
case "#java":
// works well cross-browser, and highly featured, but required Java machine to startup
if (loader) loader.message("Soundfont (500KB)<br>Java Interface...");
MIDI.Java.connect(callback);
break;
case "#flash":
// fairly quick, but requires loading of individual MP3s
if (loader) loader.message("Soundfont (2MB)<br>Flash Interface...");
DOMLoader.script.add({
src: "./inc/SoundManager2/script/soundmanager2.js",
verify: "SoundManager",
callback: function () {
MIDI.Flash.connect(callback);
}
});
break;
case "#html5":
// works well in Firefox
DOMLoader.sendRequest({
url: "./soundfont/soundfont-" + filetype + ".js",
callback: function (response) {
MIDI.Soundfont = JSON.parse(response.responseText);
if (loader) loader.message("Downloading: 100%<br>Processing...");
MIDI.HTML5.connect(callback);
},
progress: function (evt) {
var percent = evt.loaded / 1719931 * 100 >> 0;
if (loader) loader.message("Downloading: " + (percent + "%"));
}
});
break;
case "#webaudio":
// works well in Chrome
DOMLoader.sendRequest({
url: "./soundfont/soundfont-" + filetype + instrument + ".js",
callback: function(response) {
MIDI.Soundfont = JSON.parse(response.responseText);
if (loader) loader.message("Downloading: 100%<br>Processing...");
MIDI.WebAudioAPI.connect(callback);
},
progress: function (evt) {
var percent = evt.loaded / 1719931 * 100 >> 0;
if (loader) loader.message("Downloading: " + (percent + "%"));
}
});
break;
default:
break;
}
});
};
})();

View file

@ -0,0 +1,259 @@
/*
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
*/
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 ]
}
};
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
var clr = colors[(note + 9) % 12];
if (clr[0] == clr[1] && clr[1] == clr[2]) {
clr = blend(parray, colors[(note + 10) % 12]);
}
var amount = clr[2] / 10;
var octave = note / 12 >> 0;
var octaveLum = clr[2] + amount * octave - 3 * amount; // map luminance to octave
data[note] = {
hsl: 'hsla(' + clr[0] + ',' + clr[1] + '%,' + octaveLum + '%, 1)',
hex: Color.Space({H:clr[0], S:clr[1], L:octaveLum}, "HSL>RGB>HEX>STRING")
};
var parray = clr;
}
return data;
};
})(MusicTheory.Synesthesia);

209
js/MusicTheory.js Normal file
View file

@ -0,0 +1,209 @@
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', '&#X266F;5', '6', 'b7', '7', '8', 'b9', '9', '&#X266F;9', '10', '11', 'b12', '12', '&#X266F;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(
'<b>notes:</b> ' + notes.substr(2) + '<br>' +
'<b>solfege:</b> ' + solfege.substr(2) + '<br>' +
'<b>intervals:</b> ' + intervals.substr(2) + '<br>' +
'<b>keys:</b> ' + keys.substr(2) + '<br>' +
'<b>gaps:</b> ' + gaps.substr(1)
);
};
})();

View file

@ -0,0 +1,67 @@
// http://ntt.cc/2008/01/19/base64-encoder-decoder-with-javascript.html
// window.atob and window.btoa
(function (window) {
var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
window.btoa || (window.btoa = function encode64(input) {
input = escape(input);
var output = "";
var chr1, chr2, chr3 = "";
var enc1, enc2, enc3, enc4 = "";
var i = 0;
do {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2)) {
enc3 = enc4 = 64;
} else if (isNaN(chr3)) {
enc4 = 64;
}
output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4);
chr1 = chr2 = chr3 = "";
enc1 = enc2 = enc3 = enc4 = "";
} while (i < input.length);
return output;
});
window.atob || (window.atob = function(input) {
var output = "";
var chr1, chr2, chr3 = "";
var enc1, enc2, enc3, enc4 = "";
var i = 0;
// remove all characters that are not A-Z, a-z, 0-9, +, /, or =
var base64test = /[^A-Za-z0-9\+\/\=]/g;
if (base64test.exec(input)) {
alert("There were invalid base64 characters in the input text.\n" + "Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\n" + "Expect errors in decoding.");
}
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
do {
enc1 = keyStr.indexOf(input.charAt(i++));
enc2 = keyStr.indexOf(input.charAt(i++));
enc3 = keyStr.indexOf(input.charAt(i++));
enc4 = keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64) {
output = output + String.fromCharCode(chr2);
}
if (enc4 != 64) {
output = output + String.fromCharCode(chr3);
}
chr1 = chr2 = chr3 = "";
enc1 = enc2 = enc3 = enc4 = "";
} while (i < input.length);
return unescape(output);
});
}(this));

181
js/Widgets.Loader.js Normal file
View file

@ -0,0 +1,181 @@
/*
var loader = new widgets.Loader({
id: "loader",
bars: 12,
radius: 20,
lineWidth: 3,
lineHeight: 10
});
loader.stop();
loader.message("New loading message...");
*/
if (typeof(widgets) === "undefined") widgets = {};
(function(root) {
var PI = Math.PI;
var defaultConfig = {
id: "loader",
bars: 12,
radius: 0,
lineWidth: 20,
lineHeight: 70
};
root.Loader = function (config) {
var that = this;
if (!document.body) return;
if (!config) config = {};
for (var key in defaultConfig) {
if (typeof(config[key]) === "undefined") {
config[key] = defaultConfig[key];
}
}
//
var canvas = document.getElementById(config.id);
if (!canvas) {
var div = document.createElement("div");
div.style.cssText = "color: #fff; pointer-events: none; -webkit-transition-property: opacity; -webkit-transition-duration: .5s; position: fixed; left: 0; top: 0; width: 100%; height: 100%; z-index: 10000; background: rgba(0,0,0,0.5); opacity: 1";
if (config.message) {
var span = document.createElement("span");
span.style.cssText = "font-family: courier; opacity: 1; display: inline-block;background: rgba(0,0,0,0.65); border-radius: 10px; padding: 10px; width: 200px; text-align: center; position: absolute; z-index: 1000;";
div.appendChild(span);
that.span = span;
}
var canvas = document.createElement("canvas");
document.body.appendChild(canvas);
canvas.id = config.id;
canvas.style.cssText = "opacity: 1; position: absolute; z-index: 1000;";
div.appendChild(canvas);
document.body.appendChild(div);
}
if (window.innerWidth && window.innerHeight) {
var width = window.innerWidth;
var height = window.innerHeight;
} else if (document.body && document.body.offsetWidth) {
var width = document.body.offsetWidth;
var height = document.body.offsetHeight;
} else if (document.compatMode === "CSS1Compat" && document.documentElement && document.documentElement.offsetWidth ) {
var width = document.documentElement.offsetWidth;
var height = document.documentElement.offsetHeight;
}
var max = config.lineHeight + 20;
var size = max * 2 + config.radius;
width -= size;
height -= size;
canvas.width = size;
canvas.height = size;
canvas.style.left = (width / 2) + "px";
canvas.style.top = (height / 2) + "px";
if (config.message) {
that.span.style.left = ((width + size) / 2 - that.span.offsetWidth/2) + "px";
that.span.style.top = (height / 2 + size - 10) + "px";
}
var that = this;
var interval = 0;
var offset = 0;
var delay = config.delay;
var bars = config.bars;
var radius = config.radius;
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)';
//
function animate() {
ctx.save();
ctx.clearRect(0, 0, size, size);
ctx.translate(size / 2, size / 2);
var hues = 360 - 360 / bars;
for (var i = 0; i < bars; i++) {
var angle = (i / bars * 2 * PI) + offset;
ctx.save();
ctx.translate(radius * Math.sin(-angle), radius * Math.cos(-angle));
ctx.rotate(angle);
// round-rect properties
var x = -config.lineWidth / 2;
var y = 0;
var width = config.lineWidth;
var height = config.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();
}
ctx.restore();
offset += 0.07;
//
if (config.messageAnimate) {
var iteration = offset / 0.07 >> 0;
if (iteration % 10 == 0) {
var length = config.messageAnimate.length;
var n = iteration / 10 % length;
that.span.innerHTML = config.message + config.messageAnimate[n];
}
}
};
//
this.message = function(message) {
if (!interval) this.start();
config.message = message;
if (message.substr(-3) === "...") {
config.message = message.substr(0, message.length - 3);
config.messageAnimate = [ ".&nbsp;&nbsp;","..&nbsp;","..." ].reverse();
} else {
config.messageAnimate = false;
}
that.span.innerHTML = config.message + (config.messageAnimate[0] || "");
};
//
this.stop = function () {
if (interval) {
window.clearInterval(interval);
interval = 0;
}
if (canvas && canvas.style) {
canvas.parentNode.style.opacity = 0;
window.setTimeout(function () {
canvas.parentNode.style.display = "none";
ctx.clearRect(0, 0, size, size);
}, 500);
}
};
//
this.start = function (max) {
if (interval) return;
canvas.parentNode.style.top = document.body.scrollTop + "px";
canvas.parentNode.style.opacity = 1;
canvas.parentNode.style.display = "block";
canvas.style.left = (width / 2) + "px";
canvas.style.top = (height / 2) + "px";
if (!config.delay) animate();
interval = window.setInterval(animate, 30);
if (config.message) {
this.message(config.message);
}
};
//
this.start(30 * 1000);
//
return this;
};
})(widgets);

80
js/lib/base64binary.js Normal file
View file

@ -0,0 +1,80 @@
/*
Copyright (c) 2011, Daniel Guerrero
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Daniel Guerrero nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL DANIEL GUERRERO BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
var Base64Binary = {
_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
/* will return a Uint8Array type */
decodeArrayBuffer: function(input) {
var bytes = Math.ceil( (3*input.length) / 4.0);
var ab = new ArrayBuffer(bytes);
this.decode(input, ab);
return ab;
},
decode: function(input, arrayBuffer) {
//get last chars to see if are valid
var lkey1 = this._keyStr.indexOf(input.charAt(input.length-1));
var lkey2 = this._keyStr.indexOf(input.charAt(input.length-1));
var bytes = Math.ceil( (3*input.length) / 4.0);
if (lkey1 == 64) bytes--; //padding chars, so skip
if (lkey2 == 64) bytes--; //padding chars, so skip
var uarray;
var chr1, chr2, chr3;
var enc1, enc2, enc3, enc4;
var i = 0;
var j = 0;
if (arrayBuffer)
uarray = new Uint8Array(arrayBuffer);
else
uarray = new Uint8Array(bytes);
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
for (i=0; i<bytes; i+=3) {
//get the 3 octects in 4 ascii chars
enc1 = this._keyStr.indexOf(input.charAt(j++));
enc2 = this._keyStr.indexOf(input.charAt(j++));
enc3 = this._keyStr.indexOf(input.charAt(j++));
enc4 = this._keyStr.indexOf(input.charAt(j++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
uarray[i] = chr1;
if (enc3 != 64) uarray[i+1] = chr2;
if (enc4 != 64) uarray[i+2] = chr3;
}
return uarray;
}
};

24
js/lib/jasmid/LICENSE Normal file
View file

@ -0,0 +1,24 @@
Copyright (c) 2010, Matt Westcott & Ben Firshman
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The names of its contributors may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -0,0 +1,24 @@
Copyright (c) 2010, Matt Westcott & Ben Firshman
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The names of its contributors may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -0,0 +1,238 @@
/*
class to parse the .mid file format
(depends on stream.js)
*/
function MidiFile(data) {
function readChunk(stream) {
var id = stream.read(4);
var length = stream.readInt32();
return {
'id': id,
'length': length,
'data': stream.read(length)
};
}
var lastEventTypeByte;
function readEvent(stream) {
var event = {};
event.deltaTime = stream.readVarInt();
var eventTypeByte = stream.readInt8();
if ((eventTypeByte & 0xf0) == 0xf0) {
/* system / meta event */
if (eventTypeByte == 0xff) {
/* meta event */
event.type = 'meta';
var subtypeByte = stream.readInt8();
var length = stream.readVarInt();
switch(subtypeByte) {
case 0x00:
event.subtype = 'sequenceNumber';
if (length != 2) throw "Expected length for sequenceNumber event is 2, got " + length;
event.number = stream.readInt16();
return event;
case 0x01:
event.subtype = 'text';
event.text = stream.read(length);
return event;
case 0x02:
event.subtype = 'copyrightNotice';
event.text = stream.read(length);
return event;
case 0x03:
event.subtype = 'trackName';
event.text = stream.read(length);
return event;
case 0x04:
event.subtype = 'instrumentName';
event.text = stream.read(length);
return event;
case 0x05:
event.subtype = 'lyrics';
event.text = stream.read(length);
return event;
case 0x06:
event.subtype = 'marker';
event.text = stream.read(length);
return event;
case 0x07:
event.subtype = 'cuePoint';
event.text = stream.read(length);
return event;
case 0x20:
event.subtype = 'midiChannelPrefix';
if (length != 1) throw "Expected length for midiChannelPrefix event is 1, got " + length;
event.channel = stream.readInt8();
return event;
case 0x2f:
event.subtype = 'endOfTrack';
if (length != 0) throw "Expected length for endOfTrack event is 0, got " + length;
return event;
case 0x51:
event.subtype = 'setTempo';
if (length != 3) throw "Expected length for setTempo event is 3, got " + length;
event.microsecondsPerBeat = (
(stream.readInt8() << 16)
+ (stream.readInt8() << 8)
+ stream.readInt8()
)
return event;
case 0x54:
event.subtype = 'smpteOffset';
if (length != 5) throw "Expected length for smpteOffset event is 5, got " + length;
var hourByte = stream.readInt8();
event.frameRate = {
0x00: 24, 0x20: 25, 0x40: 29, 0x60: 30
}[hourByte & 0x60];
event.hour = hourByte & 0x1f;
event.min = stream.readInt8();
event.sec = stream.readInt8();
event.frame = stream.readInt8();
event.subframe = stream.readInt8();
return event;
case 0x58:
event.subtype = 'timeSignature';
if (length != 4) throw "Expected length for timeSignature event is 4, got " + length;
event.numerator = stream.readInt8();
event.denominator = Math.pow(2, stream.readInt8());
event.metronome = stream.readInt8();
event.thirtyseconds = stream.readInt8();
return event;
case 0x59:
event.subtype = 'keySignature';
if (length != 2) throw "Expected length for keySignature event is 2, got " + length;
event.key = stream.readInt8();
event.scale = stream.readInt8();
return event;
case 0x7f:
event.subtype = 'sequencerSpecific';
event.data = stream.read(length);
return event;
default:
// console.log("Unrecognised meta event subtype: " + subtypeByte);
event.subtype = 'unknown'
event.data = stream.read(length);
return event;
}
event.data = stream.read(length);
return event;
} else if (eventTypeByte == 0xf0) {
event.type = 'sysEx';
var length = stream.readVarInt();
event.data = stream.read(length);
return event;
} else if (eventTypeByte == 0xf7) {
event.type = 'dividedSysEx';
var length = stream.readVarInt();
event.data = stream.read(length);
return event;
} else {
throw "Unrecognised MIDI event type byte: " + eventTypeByte;
}
} else {
/* channel event */
var param1;
if ((eventTypeByte & 0x80) == 0) {
/* running status - reuse lastEventTypeByte as the event type.
eventTypeByte is actually the first parameter
*/
param1 = eventTypeByte;
eventTypeByte = lastEventTypeByte;
} else {
param1 = stream.readInt8();
lastEventTypeByte = eventTypeByte;
}
var eventType = eventTypeByte >> 4;
event.channel = eventTypeByte & 0x0f;
event.type = 'channel';
switch (eventType) {
case 0x08:
event.subtype = 'noteOff';
event.noteNumber = param1;
event.velocity = stream.readInt8();
return event;
case 0x09:
event.noteNumber = param1;
event.velocity = stream.readInt8();
if (event.velocity == 0) {
event.subtype = 'noteOff';
} else {
event.subtype = 'noteOn';
}
return event;
case 0x0a:
event.subtype = 'noteAftertouch';
event.noteNumber = param1;
event.amount = stream.readInt8();
return event;
case 0x0b:
event.subtype = 'controller';
event.controllerType = param1;
event.value = stream.readInt8();
return event;
case 0x0c:
event.subtype = 'programChange';
event.programNumber = param1;
return event;
case 0x0d:
event.subtype = 'channelAftertouch';
event.amount = param1;
return event;
case 0x0e:
event.subtype = 'pitchBend';
event.value = param1 + (stream.readInt8() << 7);
return event;
default:
throw "Unrecognised MIDI event type: " + eventType
/*
console.log("Unrecognised MIDI event type: " + eventType);
stream.readInt8();
event.subtype = 'unknown';
return event;
*/
}
}
}
stream = Stream(data);
var headerChunk = readChunk(stream);
if (headerChunk.id != 'MThd' || headerChunk.length != 6) {
throw "Bad .mid file - header not found";
}
var headerStream = Stream(headerChunk.data);
var formatType = headerStream.readInt16();
var trackCount = headerStream.readInt16();
var timeDivision = headerStream.readInt16();
if (timeDivision & 0x8000) {
throw "Expressing time division in SMTPE frames is not supported yet"
} else {
ticksPerBeat = timeDivision;
}
var header = {
'formatType': formatType,
'trackCount': trackCount,
'ticksPerBeat': ticksPerBeat
}
var tracks = [];
for (var i = 0; i < header.trackCount; i++) {
tracks[i] = [];
var trackChunk = readChunk(stream);
if (trackChunk.id != 'MTrk') {
throw "Unexpected chunk - expected MTrk, got "+ trackChunk.id;
}
var trackStream = Stream(trackChunk.data);
while (!trackStream.eof()) {
var event = readEvent(trackStream);
tracks[i].push(event);
//console.log(event);
}
}
return {
'header': header,
'tracks': tracks
}
}

View file

@ -0,0 +1,83 @@
var clone = function (o) {
if (typeof o != 'object') return (o);
if (o == null) return (o);
var ret = (typeof o.length == 'number') ? [] : {};
for (var key in o) ret[key] = clone(o[key]);
return ret;
};
function Replayer(midiFile, timeWarp, eventProcessor) {
//console.log(midiFile)
var trackStates = [];
var beatsPerMinute = 120;
var ticksPerBeat = midiFile.header.ticksPerBeat;
for (var i = 0; i < midiFile.tracks.length; i++) {
trackStates[i] = {
"nextEventIndex": 0,
"ticksToNextEvent": (
midiFile.tracks[i].length ? midiFile.tracks[i][0].deltaTime : null
)
};
}
function getNextEvent() {
var ticksToNextEvent = null;
var nextEventTrack = null;
var nextEventIndex = null;
for (var i = 0; i < trackStates.length; i++) {
if (trackStates[i].ticksToNextEvent != null && (ticksToNextEvent == null || trackStates[i].ticksToNextEvent < ticksToNextEvent)) {
ticksToNextEvent = trackStates[i].ticksToNextEvent;
nextEventTrack = i;
nextEventIndex = trackStates[i].nextEventIndex;
}
}
if (nextEventTrack != null) {
/// consume event from that track
var nextEvent = midiFile.tracks[nextEventTrack][nextEventIndex];
if (midiFile.tracks[nextEventTrack][nextEventIndex + 1]) {
trackStates[nextEventTrack].ticksToNextEvent += midiFile.tracks[nextEventTrack][nextEventIndex + 1].deltaTime;
} else {
trackStates[nextEventTrack].ticksToNextEvent = null;
}
trackStates[nextEventTrack].nextEventIndex += 1;
/// advance timings on all tracks by ticksToNextEvent
for (var i = 0; i < trackStates.length; i++) {
if (trackStates[i].ticksToNextEvent != null) {
trackStates[i].ticksToNextEvent -= ticksToNextEvent
}
}
return {
"ticksToEvent": ticksToNextEvent,
"event": nextEvent,
"track": nextEventTrack
}
} else {
return null;
}
};
//
var midiEvent;
var temporal = [];
//
function processEvents() {
function processNext() {
if (midiEvent.ticksToEvent > 0) {
var beatsToGenerate = midiEvent.ticksToEvent / ticksPerBeat;
var secondsToGenerate = beatsToGenerate / (beatsPerMinute / 60);
}
var time = secondsToGenerate * 1000 * timeWarp || 0;
temporal.push([ midiEvent, time]);
midiEvent = getNextEvent();
};
//
if (midiEvent = getNextEvent()) {
while(midiEvent) processNext(true);
}
};
processEvents();
return {
"getData": function() {
// console.log(temporal)
return clone(temporal);
}
};
};

View file

@ -0,0 +1,68 @@
/* Wrapper for accessing strings through sequential reads */
function Stream(str) {
var position = 0;
function read(length) {
var result = str.substr(position, length);
position += length;
return result;
}
/* read a big-endian 32-bit integer */
function readInt32() {
var result = (
(str.charCodeAt(position) << 24)
+ (str.charCodeAt(position + 1) << 16)
+ (str.charCodeAt(position + 2) << 8)
+ str.charCodeAt(position + 3));
position += 4;
return result;
}
/* read a big-endian 16-bit integer */
function readInt16() {
var result = (
(str.charCodeAt(position) << 8)
+ str.charCodeAt(position + 1));
position += 2;
return result;
}
/* read an 8-bit integer */
function readInt8() {
var result = str.charCodeAt(position);
position += 1;
return result;
}
function eof() {
return position >= str.length;
}
/* read a MIDI-style variable-length integer
(big-endian value in groups of 7 bits,
with top bit set to signify that another byte follows)
*/
function readVarInt() {
var result = 0;
while (true) {
var b = readInt8();
if (b & 0x80) {
result += (b & 0x7f);
result <<= 7;
} else {
/* b is the last byte */
return result + b;
}
}
}
return {
'eof': eof,
'read': read,
'readInt32': readInt32,
'readInt16': readInt16,
'readInt8': readInt8,
'readVarInt': readVarInt
}
}

238
js/lib/jasmid/midifile.js Normal file
View file

@ -0,0 +1,238 @@
/*
class to parse the .mid file format
(depends on stream.js)
*/
function MidiFile(data) {
function readChunk(stream) {
var id = stream.read(4);
var length = stream.readInt32();
return {
'id': id,
'length': length,
'data': stream.read(length)
};
}
var lastEventTypeByte;
function readEvent(stream) {
var event = {};
event.deltaTime = stream.readVarInt();
var eventTypeByte = stream.readInt8();
if ((eventTypeByte & 0xf0) == 0xf0) {
/* system / meta event */
if (eventTypeByte == 0xff) {
/* meta event */
event.type = 'meta';
var subtypeByte = stream.readInt8();
var length = stream.readVarInt();
switch(subtypeByte) {
case 0x00:
event.subtype = 'sequenceNumber';
if (length != 2) throw "Expected length for sequenceNumber event is 2, got " + length;
event.number = stream.readInt16();
return event;
case 0x01:
event.subtype = 'text';
event.text = stream.read(length);
return event;
case 0x02:
event.subtype = 'copyrightNotice';
event.text = stream.read(length);
return event;
case 0x03:
event.subtype = 'trackName';
event.text = stream.read(length);
return event;
case 0x04:
event.subtype = 'instrumentName';
event.text = stream.read(length);
return event;
case 0x05:
event.subtype = 'lyrics';
event.text = stream.read(length);
return event;
case 0x06:
event.subtype = 'marker';
event.text = stream.read(length);
return event;
case 0x07:
event.subtype = 'cuePoint';
event.text = stream.read(length);
return event;
case 0x20:
event.subtype = 'midiChannelPrefix';
if (length != 1) throw "Expected length for midiChannelPrefix event is 1, got " + length;
event.channel = stream.readInt8();
return event;
case 0x2f:
event.subtype = 'endOfTrack';
if (length != 0) throw "Expected length for endOfTrack event is 0, got " + length;
return event;
case 0x51:
event.subtype = 'setTempo';
if (length != 3) throw "Expected length for setTempo event is 3, got " + length;
event.microsecondsPerBeat = (
(stream.readInt8() << 16)
+ (stream.readInt8() << 8)
+ stream.readInt8()
)
return event;
case 0x54:
event.subtype = 'smpteOffset';
if (length != 5) throw "Expected length for smpteOffset event is 5, got " + length;
var hourByte = stream.readInt8();
event.frameRate = {
0x00: 24, 0x20: 25, 0x40: 29, 0x60: 30
}[hourByte & 0x60];
event.hour = hourByte & 0x1f;
event.min = stream.readInt8();
event.sec = stream.readInt8();
event.frame = stream.readInt8();
event.subframe = stream.readInt8();
return event;
case 0x58:
event.subtype = 'timeSignature';
if (length != 4) throw "Expected length for timeSignature event is 4, got " + length;
event.numerator = stream.readInt8();
event.denominator = Math.pow(2, stream.readInt8());
event.metronome = stream.readInt8();
event.thirtyseconds = stream.readInt8();
return event;
case 0x59:
event.subtype = 'keySignature';
if (length != 2) throw "Expected length for keySignature event is 2, got " + length;
event.key = stream.readInt8();
event.scale = stream.readInt8();
return event;
case 0x7f:
event.subtype = 'sequencerSpecific';
event.data = stream.read(length);
return event;
default:
// console.log("Unrecognised meta event subtype: " + subtypeByte);
event.subtype = 'unknown'
event.data = stream.read(length);
return event;
}
event.data = stream.read(length);
return event;
} else if (eventTypeByte == 0xf0) {
event.type = 'sysEx';
var length = stream.readVarInt();
event.data = stream.read(length);
return event;
} else if (eventTypeByte == 0xf7) {
event.type = 'dividedSysEx';
var length = stream.readVarInt();
event.data = stream.read(length);
return event;
} else {
throw "Unrecognised MIDI event type byte: " + eventTypeByte;
}
} else {
/* channel event */
var param1;
if ((eventTypeByte & 0x80) == 0) {
/* running status - reuse lastEventTypeByte as the event type.
eventTypeByte is actually the first parameter
*/
param1 = eventTypeByte;
eventTypeByte = lastEventTypeByte;
} else {
param1 = stream.readInt8();
lastEventTypeByte = eventTypeByte;
}
var eventType = eventTypeByte >> 4;
event.channel = eventTypeByte & 0x0f;
event.type = 'channel';
switch (eventType) {
case 0x08:
event.subtype = 'noteOff';
event.noteNumber = param1;
event.velocity = stream.readInt8();
return event;
case 0x09:
event.noteNumber = param1;
event.velocity = stream.readInt8();
if (event.velocity == 0) {
event.subtype = 'noteOff';
} else {
event.subtype = 'noteOn';
}
return event;
case 0x0a:
event.subtype = 'noteAftertouch';
event.noteNumber = param1;
event.amount = stream.readInt8();
return event;
case 0x0b:
event.subtype = 'controller';
event.controllerType = param1;
event.value = stream.readInt8();
return event;
case 0x0c:
event.subtype = 'programChange';
event.programNumber = param1;
return event;
case 0x0d:
event.subtype = 'channelAftertouch';
event.amount = param1;
return event;
case 0x0e:
event.subtype = 'pitchBend';
event.value = param1 + (stream.readInt8() << 7);
return event;
default:
throw "Unrecognised MIDI event type: " + eventType
/*
console.log("Unrecognised MIDI event type: " + eventType);
stream.readInt8();
event.subtype = 'unknown';
return event;
*/
}
}
}
stream = Stream(data);
var headerChunk = readChunk(stream);
if (headerChunk.id != 'MThd' || headerChunk.length != 6) {
throw "Bad .mid file - header not found";
}
var headerStream = Stream(headerChunk.data);
var formatType = headerStream.readInt16();
var trackCount = headerStream.readInt16();
var timeDivision = headerStream.readInt16();
if (timeDivision & 0x8000) {
throw "Expressing time division in SMTPE frames is not supported yet"
} else {
ticksPerBeat = timeDivision;
}
var header = {
'formatType': formatType,
'trackCount': trackCount,
'ticksPerBeat': ticksPerBeat
}
var tracks = [];
for (var i = 0; i < header.trackCount; i++) {
tracks[i] = [];
var trackChunk = readChunk(stream);
if (trackChunk.id != 'MTrk') {
throw "Unexpected chunk - expected MTrk, got "+ trackChunk.id;
}
var trackStream = Stream(trackChunk.data);
while (!trackStream.eof()) {
var event = readEvent(trackStream);
tracks[i].push(event);
//console.log(event);
}
}
return {
'header': header,
'tracks': tracks
}
}

83
js/lib/jasmid/replayer.js Normal file
View file

@ -0,0 +1,83 @@
var clone = function (o) {
if (typeof o != 'object') return (o);
if (o == null) return (o);
var ret = (typeof o.length == 'number') ? [] : {};
for (var key in o) ret[key] = clone(o[key]);
return ret;
};
function Replayer(midiFile, timeWarp, eventProcessor) {
//console.log(midiFile)
var trackStates = [];
var beatsPerMinute = 120;
var ticksPerBeat = midiFile.header.ticksPerBeat;
for (var i = 0; i < midiFile.tracks.length; i++) {
trackStates[i] = {
"nextEventIndex": 0,
"ticksToNextEvent": (
midiFile.tracks[i].length ? midiFile.tracks[i][0].deltaTime : null
)
};
}
function getNextEvent() {
var ticksToNextEvent = null;
var nextEventTrack = null;
var nextEventIndex = null;
for (var i = 0; i < trackStates.length; i++) {
if (trackStates[i].ticksToNextEvent != null && (ticksToNextEvent == null || trackStates[i].ticksToNextEvent < ticksToNextEvent)) {
ticksToNextEvent = trackStates[i].ticksToNextEvent;
nextEventTrack = i;
nextEventIndex = trackStates[i].nextEventIndex;
}
}
if (nextEventTrack != null) {
/// consume event from that track
var nextEvent = midiFile.tracks[nextEventTrack][nextEventIndex];
if (midiFile.tracks[nextEventTrack][nextEventIndex + 1]) {
trackStates[nextEventTrack].ticksToNextEvent += midiFile.tracks[nextEventTrack][nextEventIndex + 1].deltaTime;
} else {
trackStates[nextEventTrack].ticksToNextEvent = null;
}
trackStates[nextEventTrack].nextEventIndex += 1;
/// advance timings on all tracks by ticksToNextEvent
for (var i = 0; i < trackStates.length; i++) {
if (trackStates[i].ticksToNextEvent != null) {
trackStates[i].ticksToNextEvent -= ticksToNextEvent
}
}
return {
"ticksToEvent": ticksToNextEvent,
"event": nextEvent,
"track": nextEventTrack
}
} else {
return null;
}
};
//
var midiEvent;
var temporal = [];
//
function processEvents() {
function processNext() {
if (midiEvent.ticksToEvent > 0) {
var beatsToGenerate = midiEvent.ticksToEvent / ticksPerBeat;
var secondsToGenerate = beatsToGenerate / (beatsPerMinute / 60);
}
var time = secondsToGenerate * 1000 * timeWarp || 0;
temporal.push([ midiEvent, time]);
midiEvent = getNextEvent();
};
//
if (midiEvent = getNextEvent()) {
while(midiEvent) processNext(true);
}
};
processEvents();
return {
"getData": function() {
// console.log(temporal)
return clone(temporal);
}
};
};

68
js/lib/jasmid/stream.js Normal file
View file

@ -0,0 +1,68 @@
/* Wrapper for accessing strings through sequential reads */
function Stream(str) {
var position = 0;
function read(length) {
var result = str.substr(position, length);
position += length;
return result;
}
/* read a big-endian 32-bit integer */
function readInt32() {
var result = (
(str.charCodeAt(position) << 24)
+ (str.charCodeAt(position + 1) << 16)
+ (str.charCodeAt(position + 2) << 8)
+ str.charCodeAt(position + 3));
position += 4;
return result;
}
/* read a big-endian 16-bit integer */
function readInt16() {
var result = (
(str.charCodeAt(position) << 8)
+ str.charCodeAt(position + 1));
position += 2;
return result;
}
/* read an 8-bit integer */
function readInt8() {
var result = str.charCodeAt(position);
position += 1;
return result;
}
function eof() {
return position >= str.length;
}
/* read a MIDI-style variable-length integer
(big-endian value in groups of 7 bits,
with top bit set to signify that another byte follows)
*/
function readVarInt() {
var result = 0;
while (true) {
var b = readInt8();
if (b & 0x80) {
result += (b & 0x7f);
result <<= 7;
} else {
/* b is the last byte */
return result + b;
}
}
}
return {
'eof': eof,
'read': read,
'readInt32': readInt32,
'readInt16': readInt16,
'readInt8': readInt8,
'readVarInt': readVarInt
}
}

31
minimal.html Normal file
View file

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html lang="en">
<head>
<script src="./js/DOMLoader.XMLHttp.js" type="text/javascript"></script>
<script src="./js/DOMLoader.script.js" type="text/javascript"></script>
<script src="./js/MIDI.audioDetect.js" type="text/javascript"></script>
<script src="./js/MIDI.loadPlugin.js" type="text/javascript"></script>
<script src="./js/MIDI.Plugin.js" type="text/javascript"></script>
<script src="./js/MIDI.Player.js" type="text/javascript"></script>
<!-- base64 packages -->
<script src="./js/VersionControl.Base64.js" type="text/javascript"></script>
<script src="./js/lib/base64binary.js" type="text/javascript"></script>
</head>
<body>
<script type="text/javascript">
window.onload = function () {
MIDI.loadPlugin(function() {
for (var n = 50; n < 100; n ++) {
var delay = (n - 50) / 4; // play one note every quarter second
var note = MIDI.pianoKeyOffset + n; // the MIDI note
var velocity = 127; // how hard the note hits
// play the note
MIDI.noteOn(0, note, velocity, delay);
}
});
};
</script>
</body>
</html>

BIN
soundfont/mp3/A0.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/A1.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/A2.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/A3.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/A4.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/A5.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/A6.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/A7.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/Ab1.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/Ab2.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/Ab3.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/Ab4.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/Ab5.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/Ab6.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/Ab7.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/B0.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/B1.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/B2.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/B3.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/B4.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/B5.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/B6.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/B7.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/Bb0.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/Bb1.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/Bb2.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/Bb3.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/Bb4.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/Bb5.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/Bb6.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/Bb7.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/C1.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/C2.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/C3.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/C4.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/C5.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/C6.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/C7.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/C8.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/D1.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/D2.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/D3.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/D4.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/D5.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/D6.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/D7.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/Db1.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/Db2.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/Db3.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/Db4.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/Db5.mp3 Normal file

Binary file not shown.

BIN
soundfont/mp3/Db6.mp3 Normal file

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show more