text: /**
   * SeamlessLoop.js 2.0 - Reproduces seamless loops on HTML5/Javascript
   * https://github.com/Hivenfour/SeamlessLoop
   * 
   * Copyright (c) 2012 Main Software,
   * Written by Darío Tejedor Rico. Contact mail: hivenfour@gmail.com
   * The source code is freely distributable under the terms of LGPL license.
   * License details at http://www.gnu.org/licenses/lgpl-3.0.txt
   * 
   * USAGE:
   * - Create the Seamlessloop object
   * 		var loop = new SeamlessLoop();
   * 
   * - Add as many sounds as you will use, providing duration in miliseconds
   * (sounds must be pre-loaded if you want to update the loop without gaps)
   * 		loop.addUri(uri, length, "sound1");
   * 		loop.addUri(uri, length, "sound2");
   * ...
   * 
   * - Establish your callback function that will be called when all sounds are pre-loaded
   * 		loop.callback(soundsLoaded);
   * 
   * - Start reproducing the seamless loop:
   * 		function soundsLoaded() {
   * 			var n = 1;
   * 			loop.start("sound" + n);
   * 		};
   * 
   * - Update the looping sound, you can do this
   * synchronously (waiting the loop to finish)
   * or asynchronously (change sound immediately):
   * 		n++;
   * 		loop.update("sound" + n, false);
   * 
   * - Modify the seamless loop volume:
   * 		loop.volume(0.5);
   * 		loop.volume(loop.volume() + 0.1);
   * 
   * - Stop the seamless loop:
   * 		loop.stop();
   */
  
  function SeamlessLoop() {
  	this.is = {
  			  ff: Boolean(!(window.mozInnerScreenX == null) && /firefox/.test( navigator.userAgent.toLowerCase() )),
  			  ie: Boolean(document.all && !window.opera),
  			  opera: Boolean(window.opera),
  			  chrome: Boolean(window.chrome),
  			  safari: Boolean(!window.chrome && /safari/.test( navigator.userAgent.toLowerCase() ) && window.getComputedStyle && !window.globalStorage && !window.opera)
  			};
  	console.debug("ff: " + this.is.ff);
  	console.debug("ie: " + this.is.ie);
  	console.debug("opera: " + this.is.opera);
  	console.debug("chrome: " + this.is.chrome);
  	console.debug("safari: " + this.is.safari);
  	this._total = 0;
  	this._load = 0;
  	this.cb_loaded;
  	this.cb_loaded_flag = new Boolean();
  	this.timeout;
  	this.playDelay = -30;
  	this.stopDelay = 30;
  	if(this.is.chrome) this.playDelay = -25;
  	if(this.is.chrome) this.stopDelay = 25;
  	if(this.is.ff) this.playDelay = -25;
  	if(this.is.ff) this.stopDelay = 85;
  	if(this.is.opera) this.playDelay = 5;
  	if(this.is.opera) this.stopDelay = 0;
  	console.debug(this.playDelay + ", " + this.stopDelay);
  	this.next = 1;
  	this.audios = new Array();
  	this.actual = new Array();
  	this.dropOld = new Boolean();
  	this.old;
  	this._volume = 1;
  	
  	var t = this;
  	this._eventCanplaythrough = function(audBool) {
  		if(audBool == false) {
  			audBool = true;
  			t._load++;
  			if(t._load == t._total) {
  				t.loaded = true;
  				if(t.cb_loaded_flag == true) {
  					t.cb_loaded();
  					t.cb_loaded_flag = false;
  				}
  			}
  		}
  	};
  	
  	this._eventPlaying = function(audMute) {
  		setTimeout(function() {
  			audMute.pause();
  			try {
  				audMute.currentTime = 0;
  			} catch (e){console.debug(e.message);};
  		}, t.stopDelay);
  		
  		if(t.dropOld == true) {
  			setTimeout(function() {
  				if(t.old.paused == false) {
  					t.old.pause();
  					try {
  						t.old.currentTime = 0;
  					} catch (e){console.debug(e.message);};
  				}
  			}, t.stopDelay);
  			t.dropOld = false;
  		}
  	};
  
  	this._eventEnded = function(aud) {
  		aud.volume = this._volume;
  	};
  
  	this.doLoop = function() {
  		var key = (this.next == 1 ? "_1" : "_2");
  		var antikey = (this.next == 1 ? "_2" : "_1");
  		
  		var t = this;
  		this.timeout = setTimeout(function() {t.doLoop();}, this.actual._length + this.playDelay);
  		
  		if(this.is.opera) this.actual[antikey].pause();
  		
  		this.actual[key].play();
  		this.next *= -1;
  	};
  	
  	this.isLoaded = function() {
  		return Boolean(this._load == this._total);
  	};
  }
  
  SeamlessLoop.prototype.start = function(id) {
  	if(id != "") {
  		this.actual = this.audios[id];
  	}
  	this.doLoop();
  };
  
  SeamlessLoop.prototype.volume = function(vol) {
  	if(typeof vol != "undefined") {
  		this.actual._1.volume = vol;
          	this.actual._2.volume = vol;
  		this._volume = vol;
  	}
  	
  	return vol;
  };
  
  SeamlessLoop.prototype.stop = function() {
  	clearTimeout(this.timeout);
  	this.actual._1.currentTime = 0;
  	this.actual._1.pause();
  	this.actual._2.currentTime = 0;
  	this.actual._2.pause();
  };
  
  SeamlessLoop.prototype.callback = function(cb_loaded) {
  	this.cb_loaded = cb_loaded;
  	if(this.isLoaded() == true) cb_loaded();
  	else this.cb_loaded_flag = true;
  };
  
  SeamlessLoop.prototype.update = function(id, sync) {
  	//var key = (this.next == 1 ? "_1" : "_2");
  	var antikey = (this.next == 1 ? "_2" : "_1");
  
  	this.old = this.actual[antikey];
  	this.actual = this.audios[id];
  	if(sync == false) {
  		if(this.old.paused == false) {
  			this.dropOld = true;
  			if(this.is.opera) this.old.pause();
  		}
  		clearTimeout(this.timeout);
  		this.doLoop();
  	}
  };
  
  SeamlessLoop.prototype.addUri = function(uri, length, id) {
  	this.audios[id] = new Array();
  	this.audios[id]._length = length;
  	var t = this;
  	this.audios[id]._1_isLoaded = new Boolean();
  	this.audios[id]._2_isLoaded = new Boolean();
  	this.audios[id]._1 = new Audio(uri);
  	this.audios[id]._2 = new Audio(uri);
  	this._total++;
  	this.audios[id]._1.addEventListener("canplaythrough", function() {t._eventCanplaythrough(t.audios[id]._1_isLoaded);});
  	this.audios[id]._2.addEventListener("canplaythrough", function() {t._eventCanplaythrough(t.audios[id]._2_isLoaded);});
  	this.audios[id]._1.addEventListener("playing", function() {t._eventPlaying(t.audios[id]._2);});
  	this.audios[id]._2.addEventListener("playing", function() {t._eventPlaying(t.audios[id]._1);});
  	this.audios[id]._1.addEventListener("ended", function() {t._eventEnded(t.audios[id]._1);});
  	this.audios[id]._2.addEventListener("ended", function() {t._eventEnded(t.audios[id]._2);});
  	this.audios[id]._1.load();
  	this.audios[id]._2.load();
  	this.audios[id]._1.volume = this._volume;
  	this.audios[id]._2.volume = this._volume;
  };