Файловый менеджер - Редактировать - /home/jogoso94/public_html/static/img/logo/lib.tar
�азад
soundjs.min.js 0000644 00000150720 15043670427 0007366 0 ustar 00 /*! * @license SoundJS * Visit http://createjs.com/ for documentation, updates and examples. * * Copyright (c) 2011-2013 gskinner.com, inc. * * Distributed under the terms of the MIT license. * http://www.opensource.org/licenses/mit-license.html * * This notice shall be included in all copies or substantial portions of the Software. */ /**! * SoundJS FlashAudioPlugin also includes swfobject (http://code.google.com/p/swfobject/) */ this.createjs=this.createjs||{},function(){var a=createjs.SoundJS=createjs.SoundJS||{};a.version="0.6.0",a.buildDate="Thu, 11 Dec 2014 23:32:09 GMT"}(),this.createjs=this.createjs||{},createjs.extend=function(a,b){"use strict";function c(){this.constructor=a}return c.prototype=b.prototype,a.prototype=new c},this.createjs=this.createjs||{},createjs.promote=function(a,b){"use strict";var c=a.prototype,d=Object.getPrototypeOf&&Object.getPrototypeOf(c)||c.__proto__;if(d){c[(b+="_")+"constructor"]=d.constructor;for(var e in d)c.hasOwnProperty(e)&&"function"==typeof d[e]&&(c[b+e]=d[e])}return a},this.createjs=this.createjs||{},createjs.indexOf=function(a,b){"use strict";for(var c=0,d=a.length;d>c;c++)if(b===a[c])return c;return-1},this.createjs=this.createjs||{},function(){"use strict";createjs.proxy=function(a,b){var c=Array.prototype.slice.call(arguments,2);return function(){return a.apply(b,Array.prototype.slice.call(arguments,0).concat(c))}}}(),this.createjs=this.createjs||{},function(){"use strict";var a=Object.defineProperty?!0:!1,b={};try{Object.defineProperty(b,"bar",{get:function(){return this._bar},set:function(a){this._bar=a}})}catch(c){a=!1}createjs.definePropertySupported=a}(),this.createjs=this.createjs||{},function(){"use strict";function a(){throw"BrowserDetect cannot be instantiated"}var b=a.agent=window.navigator.userAgent;a.isWindowPhone=b.indexOf("IEMobile")>-1||b.indexOf("Windows Phone")>-1,a.isFirefox=b.indexOf("Firefox")>-1,a.isOpera=null!=window.opera,a.isChrome=b.indexOf("Chrome")>-1,a.isIOS=(b.indexOf("iPod")>-1||b.indexOf("iPhone")>-1||b.indexOf("iPad")>-1)&&!a.isWindowPhone,a.isAndroid=b.indexOf("Android")>-1&&!a.isWindowPhone,a.isBlackberry=b.indexOf("Blackberry")>-1,createjs.BrowserDetect=a}(),this.createjs=this.createjs||{},function(){"use strict";function a(){this._listeners=null,this._captureListeners=null}var b=a.prototype;a.initialize=function(a){a.addEventListener=b.addEventListener,a.on=b.on,a.removeEventListener=a.off=b.removeEventListener,a.removeAllEventListeners=b.removeAllEventListeners,a.hasEventListener=b.hasEventListener,a.dispatchEvent=b.dispatchEvent,a._dispatchEvent=b._dispatchEvent,a.willTrigger=b.willTrigger},b.addEventListener=function(a,b,c){var d;d=c?this._captureListeners=this._captureListeners||{}:this._listeners=this._listeners||{};var e=d[a];return e&&this.removeEventListener(a,b,c),e=d[a],e?e.push(b):d[a]=[b],b},b.on=function(a,b,c,d,e,f){return b.handleEvent&&(c=c||b,b=b.handleEvent),c=c||this,this.addEventListener(a,function(a){b.call(c,a,e),d&&a.remove()},f)},b.removeEventListener=function(a,b,c){var d=c?this._captureListeners:this._listeners;if(d){var e=d[a];if(e)for(var f=0,g=e.length;g>f;f++)if(e[f]==b){1==g?delete d[a]:e.splice(f,1);break}}},b.off=b.removeEventListener,b.removeAllEventListeners=function(a){a?(this._listeners&&delete this._listeners[a],this._captureListeners&&delete this._captureListeners[a]):this._listeners=this._captureListeners=null},b.dispatchEvent=function(a){if("string"==typeof a){var b=this._listeners;if(!b||!b[a])return!1;a=new createjs.Event(a)}else a.target&&a.clone&&(a=a.clone());try{a.target=this}catch(c){}if(a.bubbles&&this.parent){for(var d=this,e=[d];d.parent;)e.push(d=d.parent);var f,g=e.length;for(f=g-1;f>=0&&!a.propagationStopped;f--)e[f]._dispatchEvent(a,1+(0==f));for(f=1;g>f&&!a.propagationStopped;f++)e[f]._dispatchEvent(a,3)}else this._dispatchEvent(a,2);return a.defaultPrevented},b.hasEventListener=function(a){var b=this._listeners,c=this._captureListeners;return!!(b&&b[a]||c&&c[a])},b.willTrigger=function(a){for(var b=this;b;){if(b.hasEventListener(a))return!0;b=b.parent}return!1},b.toString=function(){return"[EventDispatcher]"},b._dispatchEvent=function(a,b){var c,d=1==b?this._captureListeners:this._listeners;if(a&&d){var e=d[a.type];if(!e||!(c=e.length))return;try{a.currentTarget=this}catch(f){}try{a.eventPhase=b}catch(f){}a.removed=!1,e=e.slice();for(var g=0;c>g&&!a.immediatePropagationStopped;g++){var h=e[g];h.handleEvent?h.handleEvent(a):h(a),a.removed&&(this.off(a.type,h,1==b),a.removed=!1)}}},createjs.EventDispatcher=a}(),this.createjs=this.createjs||{},function(){"use strict";function a(a,b,c){this.type=a,this.target=null,this.currentTarget=null,this.eventPhase=0,this.bubbles=!!b,this.cancelable=!!c,this.timeStamp=(new Date).getTime(),this.defaultPrevented=!1,this.propagationStopped=!1,this.immediatePropagationStopped=!1,this.removed=!1}var b=a.prototype;b.preventDefault=function(){this.defaultPrevented=this.cancelable&&!0},b.stopPropagation=function(){this.propagationStopped=!0},b.stopImmediatePropagation=function(){this.immediatePropagationStopped=this.propagationStopped=!0},b.remove=function(){this.removed=!0},b.clone=function(){return new a(this.type,this.bubbles,this.cancelable)},b.set=function(a){for(var b in a)this[b]=a[b];return this},b.toString=function(){return"[Event (type="+this.type+")]"},createjs.Event=a}(),this.createjs=this.createjs||{},function(){"use strict";function a(a,b,c){this.Event_constructor("error"),this.title=a,this.message=b,this.data=c}var b=createjs.extend(a,createjs.Event);b.clone=function(){return new createjs.ErrorEvent(this.title,this.message,this.data)},createjs.ErrorEvent=createjs.promote(a,"Event")}(),this.createjs=this.createjs||{},function(){"use strict";function a(a,b){this.Event_constructor("progress"),this.loaded=a,this.total=null==b?1:b,this.progress=0==b?0:this.loaded/this.total}var b=createjs.extend(a,createjs.Event);b.clone=function(){return new createjs.ProgressEvent(this.loaded,this.total)},createjs.ProgressEvent=createjs.promote(a,"Event")}(window),this.createjs=this.createjs||{},function(){"use strict";function a(){this.src=null,this.type=null,this.id=null,this.maintainOrder=!1,this.callback=null,this.data=null,this.method=createjs.LoadItem.GET,this.values=null,this.headers=null,this.withCredentials=!1,this.mimeType=null,this.crossOrigin="Anonymous",this.loadTimeout=8e3}var b=a.prototype={},c=a;c.create=function(b){if("string"==typeof b){var d=new a;return d.src=b,d}if(b instanceof c)return b;if(b instanceof Object)return b;throw new Error("Type not recognized.")},b.set=function(a){for(var b in a)this[b]=a[b];return this},createjs.LoadItem=c}(),function(){var a={};a.ABSOLUTE_PATT=/^(?:\w+:)?\/{2}/i,a.RELATIVE_PATT=/^[./]*?\//i,a.EXTENSION_PATT=/\/?[^/]+\.(\w{1,5})$/i,a.parseURI=function(b){var c={absolute:!1,relative:!1};if(null==b)return c;var d=b.indexOf("?");d>-1&&(b=b.substr(0,d));var e;return a.ABSOLUTE_PATT.test(b)?c.absolute=!0:a.RELATIVE_PATT.test(b)&&(c.relative=!0),(e=b.match(a.EXTENSION_PATT))&&(c.extension=e[1].toLowerCase()),c},a.formatQueryString=function(a,b){if(null==a)throw new Error("You must specify data.");var c=[];for(var d in a)c.push(d+"="+escape(a[d]));return b&&(c=c.concat(b)),c.join("&")},a.buildPath=function(a,b){if(null==b)return a;var c=[],d=a.indexOf("?");if(-1!=d){var e=a.slice(d+1);c=c.concat(e.split("&"))}return-1!=d?a.slice(0,d)+"?"+this._formatQueryString(b,c):a+"?"+this._formatQueryString(b,c)},a.isCrossDomain=function(a){var b=document.createElement("a");b.href=a.src;var c=document.createElement("a");c.href=location.href;var d=""!=b.hostname&&(b.port!=c.port||b.protocol!=c.protocol||b.hostname!=c.hostname);return d},a.isLocal=function(a){var b=document.createElement("a");return b.href=a.src,""==b.hostname&&"file:"==b.protocol},a.isBinary=function(a){switch(a){case createjs.AbstractLoader.IMAGE:case createjs.AbstractLoader.BINARY:return!0;default:return!1}},a.isImageTag=function(a){return a instanceof HTMLImageElement},a.isAudioTag=function(a){return window.HTMLAudioElement?a instanceof HTMLAudioElement:!1},a.isVideoTag=function(a){return window.HTMLVideoElement?a instanceof HTMLVideoElement:void 0},a.isText=function(a){switch(a){case createjs.AbstractLoader.TEXT:case createjs.AbstractLoader.JSON:case createjs.AbstractLoader.MANIFEST:case createjs.AbstractLoader.XML:case createjs.AbstractLoader.CSS:case createjs.AbstractLoader.SVG:case createjs.AbstractLoader.JAVASCRIPT:return!0;default:return!1}},a.getTypeByExtension=function(a){if(null==a)return createjs.AbstractLoader.TEXT;switch(a.toLowerCase()){case"jpeg":case"jpg":case"gif":case"png":case"webp":case"bmp":return createjs.AbstractLoader.IMAGE;case"ogg":case"mp3":case"webm":return createjs.AbstractLoader.SOUND;case"mp4":case"webm":case"ts":return createjs.AbstractLoader.VIDEO;case"json":return createjs.AbstractLoader.JSON;case"xml":return createjs.AbstractLoader.XML;case"css":return createjs.AbstractLoader.CSS;case"js":return createjs.AbstractLoader.JAVASCRIPT;case"svg":return createjs.AbstractLoader.SVG;default:return createjs.AbstractLoader.TEXT}},createjs.RequestUtils=a}(),this.createjs=this.createjs||{},function(){"use strict";function a(a,b,c){this.EventDispatcher_constructor(),this.loaded=!1,this.canceled=!1,this.progress=0,this.type=c,this.resultFormatter=null,this._item=a?createjs.LoadItem.create(a):null,this._preferXHR=b,this._result=null,this._rawResult=null,this._loadedItems=null,this._tagSrcAttribute=null,this._tag=null}var b=createjs.extend(a,createjs.EventDispatcher),c=a;c.POST="POST",c.GET="GET",c.BINARY="binary",c.CSS="css",c.IMAGE="image",c.JAVASCRIPT="javascript",c.JSON="json",c.JSONP="jsonp",c.MANIFEST="manifest",c.SOUND="sound",c.VIDEO="video",c.SPRITESHEET="spritesheet",c.SVG="svg",c.TEXT="text",c.XML="xml",b.getItem=function(){return this._item},b.getResult=function(a){return a?this._rawResult:this._result},b.getTag=function(){return this._tag},b.setTag=function(a){this._tag=a},b.load=function(){this._createRequest(),this._request.on("complete",this,this),this._request.on("progress",this,this),this._request.on("loadStart",this,this),this._request.on("abort",this,this),this._request.on("timeout",this,this),this._request.on("error",this,this);var a=new createjs.Event("initialize");a.loader=this._request,this.dispatchEvent(a),this._request.load()},b.cancel=function(){this.canceled=!0,this.destroy()},b.destroy=function(){this._request&&(this._request.removeAllEventListeners(),this._request.destroy()),this._request=null,this._item=null,this._rawResult=null,this._result=null,this._loadItems=null,this.removeAllEventListeners()},b.getLoadedItems=function(){return this._loadedItems},b._createRequest=function(){this._request=this._preferXHR?new createjs.XHRRequest(this._item):new createjs.TagRequest(this._item,this._tag||this._createTag(),this._tagSrcAttribute)},b._createTag=function(){return null},b._sendLoadStart=function(){this._isCanceled()||this.dispatchEvent("loadstart")},b._sendProgress=function(a){if(!this._isCanceled()){var b=null;"number"==typeof a?(this.progress=a,b=new createjs.ProgressEvent(this.progress)):(b=a,this.progress=a.loaded/a.total,b.progress=this.progress,(isNaN(this.progress)||1/0==this.progress)&&(this.progress=0)),this.hasEventListener("progress")&&this.dispatchEvent(b)}},b._sendComplete=function(){if(!this._isCanceled()){this.loaded=!0;var a=new createjs.Event("complete");a.rawResult=this._rawResult,null!=this._result&&(a.result=this._result),this.dispatchEvent(a)}},b._sendError=function(a){!this._isCanceled()&&this.hasEventListener("error")&&(null==a&&(a=new createjs.ErrorEvent("PRELOAD_ERROR_EMPTY")),this.dispatchEvent(a))},b._isCanceled=function(){return null==window.createjs||this.canceled?!0:!1},b.resultFormatter=null,b.handleEvent=function(a){switch(a.type){case"complete":this._rawResult=a.target._response;var b=this.resultFormatter&&this.resultFormatter(this),c=this;b instanceof Function?b(function(a){c._result=a,c._sendComplete()}):(this._result=b||this._rawResult,this._sendComplete());break;case"progress":this._sendProgress(a);break;case"error":this._sendError(a);break;case"loadstart":this._sendLoadStart();break;case"abort":case"timeout":this._isCanceled()||this.dispatchEvent(a.type)}},b.buildPath=function(a,b){return createjs.RequestUtils.buildPath(a,b)},b.toString=function(){return"[PreloadJS AbstractLoader]"},createjs.AbstractLoader=createjs.promote(a,"EventDispatcher")}(),this.createjs=this.createjs||{},function(){"use strict";function a(a,b,c){this.AbstractLoader_constructor(a,b,c),this.resultFormatter=this._formatResult,this._tagSrcAttribute="src"}var b=createjs.extend(a,createjs.AbstractLoader);b.load=function(){this._tag||(this._tag=this._createTag(this._item.src)),this._tag.preload="auto",this._tag.load(),this.AbstractLoader_load()},b._createTag=function(){},b._createRequest=function(){this._request=this._preferXHR?new createjs.XHRRequest(this._item):new createjs.MediaTagRequest(this._item,this._tag||this._createTag(),this._tagSrcAttribute)},b._formatResult=function(a){return this._tag.removeEventListener&&this._tag.removeEventListener("canplaythrough",this._loadedHandler),this._tag.onstalled=null,this._preferXHR&&(a.getTag().src=a.getResult(!0)),a.getTag()},createjs.AbstractMediaLoader=createjs.promote(a,"AbstractLoader")}(),this.createjs=this.createjs||{},function(){"use strict";var a=function(a){this._item=a},b=createjs.extend(a,createjs.EventDispatcher);b.load=function(){},b.destroy=function(){},b.cancel=function(){},createjs.AbstractRequest=createjs.promote(a,"EventDispatcher")}(),this.createjs=this.createjs||{},function(){"use strict";function a(a,b,c){this.AbstractRequest_constructor(a),this._tag=b,this._tagSrcAttribute=c,this._loadedHandler=createjs.proxy(this._handleTagComplete,this),this._addedToDOM=!1,this._startTagVisibility=null}var b=createjs.extend(a,createjs.AbstractRequest);b.load=function(){null==this._tag.parentNode&&(window.document.body.appendChild(this._tag),this._addedToDOM=!0),this._tag.onload=createjs.proxy(this._handleTagComplete,this),this._tag.onreadystatechange=createjs.proxy(this._handleReadyStateChange,this);var a=new createjs.Event("initialize");a.loader=this._tag,this.dispatchEvent(a),this._hideTag(),this._tag[this._tagSrcAttribute]=this._item.src},b.destroy=function(){this._clean(),this._tag=null,this.AbstractRequest_destroy()},b._handleReadyStateChange=function(){clearTimeout(this._loadTimeout);var a=this._tag;("loaded"==a.readyState||"complete"==a.readyState)&&this._handleTagComplete()},b._handleTagComplete=function(){this._rawResult=this._tag,this._result=this.resultFormatter&&this.resultFormatter(this)||this._rawResult,this._clean(),this._showTag(),this.dispatchEvent("complete")},b._clean=function(){this._tag.onload=null,this._tag.onreadystatechange=null,this._addedToDOM&&null!=this._tag.parentNode&&this._tag.parentNode.removeChild(this._tag)},b._hideTag=function(){this._startTagVisibility=this._tag.style.visibility,this._tag.style.visibility="hidden"},b._showTag=function(){this._tag.style.visibility=this._startTagVisibility},b._handleStalled=function(){},createjs.TagRequest=createjs.promote(a,"AbstractRequest")}(),this.createjs=this.createjs||{},function(){"use strict";function a(a,b,c){this.AbstractRequest_constructor(a),this._tag=b,this._tagSrcAttribute=c,this._loadedHandler=createjs.proxy(this._handleTagComplete,this)}var b=createjs.extend(a,createjs.TagRequest);b.load=function(){this._tag.onstalled=createjs.proxy(this._handleStalled,this),this._tag.onprogress=createjs.proxy(this._handleProgress,this),this._tag.addEventListener&&this._tag.addEventListener("canplaythrough",this._loadedHandler,!1),this.TagRequest_load()},b._handleReadyStateChange=function(){clearTimeout(this._loadTimeout);var a=this._tag;("loaded"==a.readyState||"complete"==a.readyState)&&this._handleTagComplete()},b._handleStalled=function(){},b._handleProgress=function(a){if(a&&!(a.loaded>0&&0==a.total)){var b=new createjs.ProgressEvent(a.loaded,a.total);this.dispatchEvent(b)}},b._clean=function(){this._tag.removeEventListener&&this._tag.removeEventListener("canplaythrough",this._loadedHandler),this._tag.onstalled=null,this._tag.onprogress=null,this.TagRequest__clean()},createjs.MediaTagRequest=createjs.promote(a,"TagRequest")}(),this.createjs=this.createjs||{},function(){"use strict";function a(a){this.AbstractRequest_constructor(a),this._request=null,this._loadTimeout=null,this._xhrLevel=1,this._response=null,this._rawResponse=null,this._canceled=!1,this._handleLoadStartProxy=createjs.proxy(this._handleLoadStart,this),this._handleProgressProxy=createjs.proxy(this._handleProgress,this),this._handleAbortProxy=createjs.proxy(this._handleAbort,this),this._handleErrorProxy=createjs.proxy(this._handleError,this),this._handleTimeoutProxy=createjs.proxy(this._handleTimeout,this),this._handleLoadProxy=createjs.proxy(this._handleLoad,this),this._handleReadyStateChangeProxy=createjs.proxy(this._handleReadyStateChange,this),!this._createXHR(a)}var b=createjs.extend(a,createjs.AbstractRequest);a.ACTIVEX_VERSIONS=["Msxml2.XMLHTTP.6.0","Msxml2.XMLHTTP.5.0","Msxml2.XMLHTTP.4.0","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"],b.getResult=function(a){return a&&this._rawResponse?this._rawResponse:this._response},b.cancel=function(){this.canceled=!0,this._clean(),this._request.abort()},b.load=function(){if(null==this._request)return void this._handleError();this._request.addEventListener("loadstart",this._handleLoadStartProxy,!1),this._request.addEventListener("progress",this._handleProgressProxy,!1),this._request.addEventListener("abort",this._handleAbortProxy,!1),this._request.addEventListener("error",this._handleErrorProxy,!1),this._request.addEventListener("timeout",this._handleTimeoutProxy,!1),this._request.addEventListener("load",this._handleLoadProxy,!1),this._request.addEventListener("readystatechange",this._handleReadyStateChangeProxy,!1),1==this._xhrLevel&&(this._loadTimeout=setTimeout(createjs.proxy(this._handleTimeout,this),this._item.loadTimeout));try{this._item.values&&this._item.method!=createjs.AbstractLoader.GET?this._item.method==createjs.AbstractLoader.POST&&this._request.send(createjs.RequestUtils.formatQueryString(this._item.values)):this._request.send()}catch(a){this.dispatchEvent(new createjs.ErrorEvent("XHR_SEND",null,a))}},b.setResponseType=function(a){this._request.responseType=a},b.getAllResponseHeaders=function(){return this._request.getAllResponseHeaders instanceof Function?this._request.getAllResponseHeaders():null},b.getResponseHeader=function(a){return this._request.getResponseHeader instanceof Function?this._request.getResponseHeader(a):null},b._handleProgress=function(a){if(a&&!(a.loaded>0&&0==a.total)){var b=new createjs.ProgressEvent(a.loaded,a.total);this.dispatchEvent(b)}},b._handleLoadStart=function(){clearTimeout(this._loadTimeout),this.dispatchEvent("loadstart")},b._handleAbort=function(a){this._clean(),this.dispatchEvent(new createjs.ErrorEvent("XHR_ABORTED",null,a))},b._handleError=function(a){this._clean(),this.dispatchEvent(new createjs.ErrorEvent(a.message))},b._handleReadyStateChange=function(){4==this._request.readyState&&this._handleLoad()},b._handleLoad=function(){if(!this.loaded){this.loaded=!0;var a=this._checkError();if(a)return void this._handleError(a);this._response=this._getResponse(),this._clean(),this.dispatchEvent(new createjs.Event("complete"))}},b._handleTimeout=function(a){this._clean(),this.dispatchEvent(new createjs.ErrorEvent("PRELOAD_TIMEOUT",null,a))},b._checkError=function(){var a=parseInt(this._request.status);switch(a){case 404:case 0:return new Error(a)}return null},b._getResponse=function(){if(null!=this._response)return this._response;if(null!=this._request.response)return this._request.response;try{if(null!=this._request.responseText)return this._request.responseText}catch(a){}try{if(null!=this._request.responseXML)return this._request.responseXML}catch(a){}return null},b._createXHR=function(a){var b=createjs.RequestUtils.isCrossDomain(a),c={},d=null;if(window.XMLHttpRequest)d=new XMLHttpRequest,b&&void 0===d.withCredentials&&window.XDomainRequest&&(d=new XDomainRequest);else{for(var e=0,f=s.ACTIVEX_VERSIONS.length;f>e;e++){{s.ACTIVEX_VERSIONS[e]}try{d=new ActiveXObject(axVersions);break}catch(g){}}if(null==d)return!1}a.mimeType&&d.overrideMimeType&&d.overrideMimeType(a.mimeType),this._xhrLevel="string"==typeof d.responseType?2:1;var h=null;if(h=a.method==createjs.AbstractLoader.GET?createjs.RequestUtils.buildPath(a.src,a.values):a.src,d.open(a.method||createjs.AbstractLoader.GET,h,!0),b&&d instanceof XMLHttpRequest&&1==this._xhrLevel&&(c.Origin=location.origin),a.values&&a.method==createjs.AbstractLoader.POST&&(c["Content-Type"]="application/x-www-form-urlencoded"),b||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest"),a.headers)for(var i in a.headers)c[i]=a.headers[i];for(i in c)d.setRequestHeader(i,c[i]);return d instanceof XMLHttpRequest&&void 0!==a.withCredentials&&(d.withCredentials=a.withCredentials),this._request=d,!0},b._clean=function(){clearTimeout(this._loadTimeout),this._request.removeEventListener("loadstart",this._handleLoadStartProxy),this._request.removeEventListener("progress",this._handleProgressProxy),this._request.removeEventListener("abort",this._handleAbortProxy),this._request.removeEventListener("error",this._handleErrorProxy),this._request.removeEventListener("timeout",this._handleTimeoutProxy),this._request.removeEventListener("load",this._handleLoadProxy),this._request.removeEventListener("readystatechange",this._handleReadyStateChangeProxy)},b.toString=function(){return"[PreloadJS XHRRequest]"},createjs.XHRRequest=createjs.promote(a,"AbstractRequest")}(),this.createjs=this.createjs||{},function(){"use strict";function a(a,b){this.AbstractMediaLoader_constructor(a,b,createjs.AbstractLoader.SOUND),createjs.RequestUtils.isAudioTag(a)?this._tag=a:createjs.RequestUtils.isAudioTag(a.src)?this._tag=a:createjs.RequestUtils.isAudioTag(a.tag)&&(this._tag=createjs.RequestUtils.isAudioTag(a)?a:a.src),null!=this._tag&&(this._preferXHR=!1)}var b=createjs.extend(a,createjs.AbstractMediaLoader),c=a;c.canLoadItem=function(a){return a.type==createjs.AbstractLoader.SOUND},b._createTag=function(a){var b=document.createElement("audio");return b.autoplay=!1,b.preload="none",b.src=a,b},createjs.SoundLoader=createjs.promote(a,"AbstractMediaLoader")}(),this.createjs=this.createjs||{},function(){"use strict";function a(){throw"Sound cannot be instantiated"}function b(a,b){this.init(a,b)}var c=a;c.INTERRUPT_ANY="any",c.INTERRUPT_EARLY="early",c.INTERRUPT_LATE="late",c.INTERRUPT_NONE="none",c.PLAY_INITED="playInited",c.PLAY_SUCCEEDED="playSucceeded",c.PLAY_INTERRUPTED="playInterrupted",c.PLAY_FINISHED="playFinished",c.PLAY_FAILED="playFailed",c.SUPPORTED_EXTENSIONS=["mp3","ogg","mpeg","wav","m4a","mp4","aiff","wma","mid"],c.EXTENSION_MAP={m4a:"mp4"},c.FILE_PATTERN=/^(?:(\w+:)\/{2}(\w+(?:\.\w+)*\/?))?([/.]*?(?:[^?]+)?\/)?((?:[^/?]+)\.(\w+))(?:\?(\S+)?)?$/,c.defaultInterruptBehavior=c.INTERRUPT_NONE,c.alternateExtensions=[],c.activePlugin=null,c._pluginsRegistered=!1,c._lastID=0,c._masterVolume=1,c._masterMute=!1,c._instances=[],c._idHash={},c._preloadHash={},c.addEventListener=null,c.removeEventListener=null,c.removeAllEventListeners=null,c.dispatchEvent=null,c.hasEventListener=null,c._listeners=null,createjs.EventDispatcher.initialize(c),c.getPreloadHandlers=function(){return{callback:createjs.proxy(c.initLoad,c),types:["sound"],extensions:c.SUPPORTED_EXTENSIONS}},c._handleLoadComplete=function(a){var b=a.target.getItem().src;if(c._preloadHash[b])for(var d=0,e=c._preloadHash[b].length;e>d;d++){var f=c._preloadHash[b][d];if(c._preloadHash[b][d]=!0,c.hasEventListener("fileload")){var a=new createjs.Event("fileload");a.src=f.src,a.id=f.id,a.data=f.data,a.sprite=f.sprite,c.dispatchEvent(a)}}},c._handleLoadError=function(a){var b=a.target.getItem().src;if(c._preloadHash[b])for(var d=0,e=c._preloadHash[b].length;e>d;d++){var f=c._preloadHash[b][d];if(c._preloadHash[b][d]=!1,c.hasEventListener("fileerror")){var a=new createjs.Event("fileerror");a.src=f.src,a.id=f.id,a.data=f.data,a.sprite=f.sprite,c.dispatchEvent(a)}}},c._registerPlugin=function(a){return a.isSupported()?(c.activePlugin=new a,!0):!1},c.registerPlugins=function(a){c._pluginsRegistered=!0;for(var b=0,d=a.length;d>b;b++)if(c._registerPlugin(a[b]))return!0;return!1},c.initializeDefaultPlugins=function(){return null!=c.activePlugin?!0:c._pluginsRegistered?!1:c.registerPlugins([createjs.WebAudioPlugin,createjs.HTMLAudioPlugin])?!0:!1},c.isReady=function(){return null!=c.activePlugin},c.getCapabilities=function(){return null==c.activePlugin?null:c.activePlugin._capabilities},c.getCapability=function(a){return null==c.activePlugin?null:c.activePlugin._capabilities[a]},c.initLoad=function(a){return c._registerSound(a)},c._registerSound=function(a){if(!c.initializeDefaultPlugins())return!1;var d=c._parsePath(a.src);if(null==d)return!1;a.src=d.src,a.type="sound";var e=a.data,f=c.activePlugin.defaultNumChannels||null;if(null!=e&&(isNaN(e.channels)?isNaN(e)||(f=parseInt(e)):f=parseInt(e.channels),e.audioSprite))for(var g,h=e.audioSprite.length;h--;)g=e.audioSprite[h],c._idHash[g.id]={src:a.src,startTime:parseInt(g.startTime),duration:parseInt(g.duration)};null!=a.id&&(c._idHash[a.id]={src:a.src});var i=c.activePlugin.register(a,f);return b.create(a.src,f),null!=e&&isNaN(e)?a.data.channels=f||b.maxPerChannel():a.data=f||b.maxPerChannel(),i.type&&(a.type=i.type),i},c.registerSound=function(a,b,d,e){var f={src:a,id:b,data:d};a instanceof Object&&(e=b,f=a),f=createjs.LoadItem.create(f),null!=e&&(f.src=e+a);var g=c._registerSound(f);if(!g)return!1;if(c._preloadHash[f.src]||(c._preloadHash[f.src]=[]),c._preloadHash[f.src].push(f),1==c._preloadHash[f.src].length)g.on("complete",createjs.proxy(this._handleLoadComplete,this)),g.on("error",createjs.proxy(this._handleLoadError,this)),c.activePlugin.preload(g);else if(1==c._preloadHash[f.src][0])return!0;return f},c.registerSounds=function(a,b){var c=[];a.path&&(b?b+=a.path:b=a.path);for(var d=0,e=a.length;e>d;d++)c[d]=createjs.Sound.registerSound(a[d].src,a[d].id,a[d].data,b);return c},c.registerManifest=function(a,b){try{console.log("createjs.Sound.registerManifest is deprecated, please use createjs.Sound.registerSounds.")}catch(c){}return this.registerSounds(a,b)},c.removeSound=function(a,d){if(null==c.activePlugin)return!1;a instanceof Object&&(a=a.src),a=c._getSrcById(a).src,null!=d&&(a=d+a);var e=c._parsePath(a);if(null==e)return!1;a=e.src;for(var f in c._idHash)c._idHash[f].src==a&&delete c._idHash[f];return b.removeSrc(a),delete c._preloadHash[a],c.activePlugin.removeSound(a),!0},c.removeSounds=function(a,b){var c=[];a.path&&(b?b+=a.path:b=a.path);for(var d=0,e=a.length;e>d;d++)c[d]=createjs.Sound.removeSound(a[d].src,b);return c},c.removeManifest=function(a,b){try{console.log("createjs.Sound.removeManifest is deprecated, please use createjs.Sound.removeSounds.")}catch(d){}return c.removeSounds(a,b)},c.removeAllSounds=function(){c._idHash={},c._preloadHash={},b.removeAll(),c.activePlugin&&c.activePlugin.removeAllSounds()},c.loadComplete=function(a){if(!c.isReady())return!1;var b=c._parsePath(a);return a=b?c._getSrcById(b.src).src:c._getSrcById(a).src,1==c._preloadHash[a][0]},c._parsePath=function(a){"string"!=typeof a&&(a=a.toString());var b=a.match(c.FILE_PATTERN);if(null==b)return!1;for(var d=b[4],e=b[5],f=c.getCapabilities(),g=0;!f[e];)if(e=c.alternateExtensions[g++],g>c.alternateExtensions.length)return null;a=a.replace("."+b[5],"."+e);var h={name:d,src:a,extension:e};return h},c.play=function(a,b,d,e,f,g,h,i,j){b instanceof Object&&(d=b.delay,e=b.offset,f=b.loop,g=b.volume,h=b.pan,i=b.startTime,j=b.duration,b=b.interrupt);var k=c.createInstance(a,i,j),l=c._playInstance(k,b,d,e,f,g,h);return l||k._playFailed(),k},c.createInstance=function(a,d,e){if(!c.initializeDefaultPlugins())return new createjs.DefaultSoundInstance(a,d,e);a=c._getSrcById(a);var f=c._parsePath(a.src),g=null;return null!=f&&null!=f.src?(b.create(f.src),null==d&&(d=a.startTime),g=c.activePlugin.create(f.src,d,e||a.duration)):g=new createjs.DefaultSoundInstance(a,d,e),g.uniqueId=c._lastID++,g},c.setVolume=function(a){if(null==Number(a))return!1;if(a=Math.max(0,Math.min(1,a)),c._masterVolume=a,!this.activePlugin||!this.activePlugin.setVolume||!this.activePlugin.setVolume(a))for(var b=this._instances,d=0,e=b.length;e>d;d++)b[d].setMasterVolume(a)},c.getVolume=function(){return c._masterVolume},c.setMute=function(a){if(null==a)return!1;if(this._masterMute=a,!this.activePlugin||!this.activePlugin.setMute||!this.activePlugin.setMute(a))for(var b=this._instances,c=0,d=b.length;d>c;c++)b[c].setMasterMute(a);return!0},c.getMute=function(){return this._masterMute},c.stop=function(){for(var a=this._instances,b=a.length;b--;)a[b].stop()},c._playInstance=function(a,b,d,e,f,g,h){if(b instanceof Object&&(d=b.delay,e=b.offset,f=b.loop,g=b.volume,h=b.pan,b=b.interrupt),b=b||c.defaultInterruptBehavior,null==d&&(d=0),null==e&&(e=a.getPosition()),null==f&&(f=a.loop),null==g&&(g=a.volume),null==h&&(h=a.pan),0==d){var i=c._beginPlaying(a,b,e,f,g,h);if(!i)return!1}else{var j=setTimeout(function(){c._beginPlaying(a,b,e,f,g,h)},d);a.delayTimeoutId=j}return this._instances.push(a),!0},c._beginPlaying=function(a,c,d,e,f,g){if(!b.add(a,c))return!1;var h=a._beginPlaying(d,e,f,g);if(!h){var i=createjs.indexOf(this._instances,a);return i>-1&&this._instances.splice(i,1),!1}return!0},c._getSrcById=function(a){return c._idHash[a]||{src:a}},c._playFinished=function(a){b.remove(a);var c=createjs.indexOf(this._instances,a);c>-1&&this._instances.splice(c,1)},createjs.Sound=a,b.channels={},b.create=function(a,c){var d=b.get(a);return null==d?(b.channels[a]=new b(a,c),!0):!1},b.removeSrc=function(a){var c=b.get(a);return null==c?!1:(c._removeAll(),delete b.channels[a],!0)},b.removeAll=function(){for(var a in b.channels)b.channels[a]._removeAll();b.channels={}},b.add=function(a,c){var d=b.get(a.src);return null==d?!1:d._add(a,c)},b.remove=function(a){var c=b.get(a.src);return null==c?!1:(c._remove(a),!0)},b.maxPerChannel=function(){return d.maxDefault},b.get=function(a){return b.channels[a]};var d=b.prototype;d.constructor=b,d.src=null,d.max=null,d.maxDefault=100,d.length=0,d.init=function(a,b){this.src=a,this.max=b||this.maxDefault,-1==this.max&&(this.max=this.maxDefault),this._instances=[]},d._get=function(a){return this._instances[a]},d._add=function(a,b){return this._getSlot(b,a)?(this._instances.push(a),this.length++,!0):!1},d._remove=function(a){var b=createjs.indexOf(this._instances,a);return-1==b?!1:(this._instances.splice(b,1),this.length--,!0)},d._removeAll=function(){for(var a=this.length-1;a>=0;a--)this._instances[a].stop()},d._getSlot=function(b){var c,d;if(b!=a.INTERRUPT_NONE&&(d=this._get(0),null==d))return!0;for(var e=0,f=this.max;f>e;e++){if(c=this._get(e),null==c)return!0;if(c.playState==a.PLAY_FINISHED||c.playState==a.PLAY_INTERRUPTED||c.playState==a.PLAY_FAILED){d=c;break}b!=a.INTERRUPT_NONE&&(b==a.INTERRUPT_EARLY&&c.getPosition()<d.getPosition()||b==a.INTERRUPT_LATE&&c.getPosition()>d.getPosition())&&(d=c)}return null!=d?(d._interrupt(),this._remove(d),!0):!1},d.toString=function(){return"[Sound SoundChannel]"}}(),this.createjs=this.createjs||{},function(){"use strict";var a=function(a,b,c,d){this.EventDispatcher_constructor(),this.src=a,this.uniqueId=-1,this.playState=null,this.delayTimeoutId=null,this._startTime=Math.max(0,b||0),this._volume=1,createjs.definePropertySupported&&Object.defineProperty(this,"volume",{get:this.getVolume,set:this.setVolume}),this._pan=0,createjs.definePropertySupported&&Object.defineProperty(this,"pan",{get:this.getPan,set:this.setPan}),this._duration=Math.max(0,c||0),createjs.definePropertySupported&&Object.defineProperty(this,"duration",{get:this.getDuration,set:this.setDuration}),this._playbackResource=null,createjs.definePropertySupported&&Object.defineProperty(this,"playbackResource",{get:this.getPlaybackResource,set:this.setPlaybackResource}),d!==!1&&d!==!0&&this.setPlaybackResource(d),this._position=0,createjs.definePropertySupported&&Object.defineProperty(this,"position",{get:this.getPosition,set:this.setPosition}),this._loop=0,createjs.definePropertySupported&&Object.defineProperty(this,"loop",{get:this.getLoop,set:this.setLoop}),this._muted=!1,createjs.definePropertySupported&&Object.defineProperty(this,"muted",{get:this.getMuted,set:this.setMuted}),this._paused=!1,createjs.definePropertySupported&&Object.defineProperty(this,"paused",{get:this.getPaused,set:this.setPaused}) },b=createjs.extend(a,createjs.EventDispatcher);b.play=function(a,b,c,d,e,f){return this.playState==createjs.Sound.PLAY_SUCCEEDED?(a instanceof Object&&(c=a.offset,d=a.loop,e=a.volume,f=a.pan),null!=c&&this.setPosition(c),null!=d&&this.setLoop(d),null!=e&&this.setVolume(e),null!=f&&this.setPan(f),void(this._paused&&this.setPaused(!1))):(this._cleanUp(),createjs.Sound._playInstance(this,a,b,c,d,e,f),this)},b.pause=function(){return this._paused||this.playState!=createjs.Sound.PLAY_SUCCEEDED?!1:(this.setPaused(!0),!0)},b.resume=function(){return this._paused?(this.setPaused(!1),!0):!1},b.stop=function(){return this._position=0,this._paused=!1,this._handleStop(),this._cleanUp(),this.playState=createjs.Sound.PLAY_FINISHED,this},b.destroy=function(){this._cleanUp(),this.src=null,this.playbackResource=null,this.removeAllEventListeners()},b.toString=function(){return"[AbstractSoundInstance]"},b.getPaused=function(){return this._paused},b.setPaused=function(a){return a!==!0&&a!==!1||this._paused==a||1==a&&this.playState!=createjs.Sound.PLAY_SUCCEEDED?void 0:(this._paused=a,a?this._pause():this._resume(),clearTimeout(this.delayTimeoutId),this)},b.setVolume=function(a){return a==this._volume?this:(this._volume=Math.max(0,Math.min(1,a)),this._muted||this._updateVolume(),this)},b.getVolume=function(){return this._volume},b.setMute=function(a){this.setMuted(a)},b.getMute=function(){return this._muted},b.setMuted=function(a){return a===!0||a===!1?(this._muted=a,this._updateVolume(),this):void 0},b.getMuted=function(){return this._muted},b.setPan=function(a){return a==this._pan?this:(this._pan=Math.max(-1,Math.min(1,a)),this._updatePan(),this)},b.getPan=function(){return this._pan},b.getPosition=function(){return this._paused||this.playState!=createjs.Sound.PLAY_SUCCEEDED?this._position:this._calculateCurrentPosition()},b.setPosition=function(a){return this._position=Math.max(0,a),this.playState==createjs.Sound.PLAY_SUCCEEDED&&this._updatePosition(),this},b.getDuration=function(){return this._duration},b.setDuration=function(a){return a==this._duration?this:(this._duration=Math.max(0,a||0),this._updateDuration(),this)},b.setPlaybackResource=function(a){return this._playbackResource=a,0==this._duration&&this._setDurationFromSource(),this},b.getPlaybackResource=function(){return this._playbackResource},b.getLoop=function(){return this._loop},b.setLoop=function(a){null!=this._playbackResource&&(0!=this._loop&&0==a&&this._removeLooping(a),0==this._loop&&0!=a&&this._addLooping(a)),this._loop=a},b._sendEvent=function(a){var b=new createjs.Event(a);this.dispatchEvent(b)},b._cleanUp=function(){clearTimeout(this.delayTimeoutId),this._handleCleanUp(),this._paused=!1,createjs.Sound._playFinished(this)},b._interrupt=function(){this._cleanUp(),this.playState=createjs.Sound.PLAY_INTERRUPTED,this._sendEvent("interrupted")},b._beginPlaying=function(a,b,c,d){return this.setPosition(a),this.setLoop(b),this.setVolume(c),this.setPan(d),null!=this._playbackResource&&this._position<this._duration?(this._paused=!1,this._handleSoundReady(),this.playState=createjs.Sound.PLAY_SUCCEEDED,this._sendEvent("succeeded"),!0):(this._playFailed(),!1)},b._playFailed=function(){this._cleanUp(),this.playState=createjs.Sound.PLAY_FAILED,this._sendEvent("failed")},b._handleSoundComplete=function(){return this._position=0,0!=this._loop?(this._loop--,this._handleLoop(),void this._sendEvent("loop")):(this._cleanUp(),this.playState=createjs.Sound.PLAY_FINISHED,void this._sendEvent("complete"))},b._handleSoundReady=function(){},b._updateVolume=function(){},b._updatePan=function(){},b._updateDuration=function(){},b._setDurationFromSource=function(){},b._calculateCurrentPosition=function(){},b._updatePosition=function(){},b._removeLooping=function(){},b._addLooping=function(){},b._pause=function(){},b._resume=function(){},b._handleStop=function(){},b._handleCleanUp=function(){},b._handleLoop=function(){},createjs.AbstractSoundInstance=createjs.promote(a,"EventDispatcher"),createjs.DefaultSoundInstance=createjs.AbstractSoundInstance}(),this.createjs=this.createjs||{},function(){"use strict";var a=function(){this._capabilities=null,this._loaders={},this._audioSources={},this._soundInstances={},this._loaderClass,this._soundInstanceClass},b=a.prototype;a._capabilities=null,a.isSupported=function(){return!0},b.register=function(a){if(this._audioSources[a.src]=!0,this._soundInstances[a.src]=[],this._loaders[a.src])return this._loaders[a.src];var b=new this._loaderClass(a);return b.on("complete",createjs.proxy(this._handlePreloadComplete,this)),this._loaders[a.src]=b,b},b.preload=function(a){a.on("error",createjs.proxy(this._handlePreloadError,this)),a.load()},b.isPreloadStarted=function(a){return null!=this._audioSources[a]},b.isPreloadComplete=function(a){return!(null==this._audioSources[a]||1==this._audioSources[a])},b.removeSound=function(a){if(this._soundInstances[a]){for(var b=this._soundInstances[a].length;b--;){var c=this._soundInstances[a][b];c.destroy()}delete this._soundInstances[a],delete this._audioSources[a],this._loaders[a]&&this._loaders[a].destroy(),delete this._loaders[a]}},b.removeAllSounds=function(){for(var a in this._audioSources)this.removeSound(a)},b.create=function(a,b,c){this.isPreloadStarted(a)||this.preload(this.register(a));var d=new this._soundInstanceClass(a,b,c,this._audioSources[a]);return this._soundInstances[a].push(d),d},b.setVolume=function(a){return this._volume=a,this._updateVolume(),!0},b.getVolume=function(){return this._volume},b.setMute=function(){return this._updateVolume(),!0},b.toString=function(){return"[AbstractPlugin]"},b._handlePreloadComplete=function(a){var b=a.target.getItem().src;this._audioSources[b]=a.result;for(var c=0,d=this._soundInstances[b].length;d>c;c++){var e=this._soundInstances[b][c];e.setPlaybackResource(this._audioSources[b])}},b._handlePreloadError=function(){},b._updateVolume=function(){},createjs.AbstractPlugin=a}(),this.createjs=this.createjs||{},function(){"use strict";function a(a){this.AbstractLoader_constructor(a,!0,createjs.AbstractLoader.SOUND)}var b=createjs.extend(a,createjs.AbstractLoader);a.context=null,b.toString=function(){return"[WebAudioLoader]"},b._createRequest=function(){this._request=new createjs.XHRRequest(this._item,!1),this._request.setResponseType("arraybuffer")},b._sendComplete=function(){a.context.decodeAudioData(this._rawResult,createjs.proxy(this._handleAudioDecoded,this),createjs.proxy(this._handleError,this))},b._handleAudioDecoded=function(a){this._result=a,this.AbstractLoader__sendComplete()},createjs.WebAudioLoader=createjs.promote(a,"AbstractLoader")}(),this.createjs=this.createjs||{},function(){"use strict";function a(a,b,d,e){this.AbstractSoundInstance_constructor(a,b,d,e),this.gainNode=c.context.createGain(),this.panNode=c.context.createPanner(),this.panNode.panningModel=c._panningModel,this.panNode.connect(this.gainNode),this.sourceNode=null,this._soundCompleteTimeout=null,this._sourceNodeNext=null,this._playbackStartTime=0,this._endedHandler=createjs.proxy(this._handleSoundComplete,this)}var b=createjs.extend(a,createjs.AbstractSoundInstance),c=a;c.context=null,c.destinationNode=null,c._panningModel="equalpower",b.destroy=function(){this.AbstractSoundInstance_destroy(),this.panNode.disconnect(0),this.panNode=null,this.gainNode.disconnect(0),this.gainNode=null},b.toString=function(){return"[WebAudioSoundInstance]"},b._updatePan=function(){this.panNode.setPosition(this._pan,0,-.5)},b._removeLooping=function(){this._sourceNodeNext=this._cleanUpAudioNode(this._sourceNodeNext)},b._addLooping=function(){this.playState==createjs.Sound.PLAY_SUCCEEDED&&(this._sourceNodeNext=this._createAndPlayAudioNode(this._playbackStartTime,0))},b._setDurationFromSource=function(){this._duration=1e3*this.playbackResource.duration},b._handleCleanUp=function(){this.sourceNode&&this.playState==createjs.Sound.PLAY_SUCCEEDED&&(this.sourceNode=this._cleanUpAudioNode(this.sourceNode),this._sourceNodeNext=this._cleanUpAudioNode(this._sourceNodeNext)),0!=this.gainNode.numberOfOutputs&&this.gainNode.disconnect(0),clearTimeout(this._soundCompleteTimeout),this._playbackStartTime=0},b._cleanUpAudioNode=function(a){return a&&(a.stop(0),a.disconnect(0),a=null),a},b._handleSoundReady=function(){this.gainNode.connect(c.destinationNode);var a=.001*this._duration,b=.001*this._position;this.sourceNode=this._createAndPlayAudioNode(c.context.currentTime-a,b),this._playbackStartTime=this.sourceNode.startTime-b,this._soundCompleteTimeout=setTimeout(this._endedHandler,1e3*(a-b)),0!=this._loop&&(this._sourceNodeNext=this._createAndPlayAudioNode(this._playbackStartTime,0))},b._createAndPlayAudioNode=function(a,b){var d=c.context.createBufferSource();d.buffer=this.playbackResource,d.connect(this.panNode);var e=.001*this._duration;return d.startTime=a+e,d.start(d.startTime,b+.001*this._startTime,e-b),d},b._pause=function(){this._position=1e3*(c.context.currentTime-this._playbackStartTime),this.sourceNode=this._cleanUpAudioNode(this.sourceNode),this._sourceNodeNext=this._cleanUpAudioNode(this._sourceNodeNext),0!=this.gainNode.numberOfOutputs&&this.gainNode.disconnect(0),clearTimeout(this._soundCompleteTimeout)},b._resume=function(){this._handleSoundReady()},b._updateVolume=function(){var a=this._muted?0:this._volume;a!=this.gainNode.gain.value&&(this.gainNode.gain.value=a)},b._calculateCurrentPosition=function(){return 1e3*(c.context.currentTime-this._playbackStartTime)},b._updatePosition=function(){this.sourceNode=this._cleanUpAudioNode(this.sourceNode),this._sourceNodeNext=this._cleanUpAudioNode(this._sourceNodeNext),clearTimeout(this._soundCompleteTimeout),this._paused||this._handleSoundReady()},b._handleLoop=function(){this._cleanUpAudioNode(this.sourceNode),this.sourceNode=this._sourceNodeNext,this._playbackStartTime=this.sourceNode.startTime,this._sourceNodeNext=this._createAndPlayAudioNode(this._playbackStartTime,0),this._soundCompleteTimeout=setTimeout(this._endedHandler,this._duration)},b._updateDuration=function(){this._pause(),this._resume()},createjs.WebAudioSoundInstance=createjs.promote(a,"AbstractSoundInstance")}(),this.createjs=this.createjs||{},function(){"use strict";function a(){this.AbstractPlugin_constructor(),this._panningModel=c._panningModel,this._volume=1,this.context=c.context,this.dynamicsCompressorNode=this.context.createDynamicsCompressor(),this.dynamicsCompressorNode.connect(this.context.destination),this.gainNode=this.context.createGain(),this.gainNode.connect(this.dynamicsCompressorNode),createjs.WebAudioSoundInstance.destinationNode=this.gainNode,this._capabilities=c._capabilities,this._loaderClass=createjs.WebAudioLoader,this._soundInstanceClass=createjs.WebAudioSoundInstance,this._addPropsToClasses()}var b=createjs.extend(a,createjs.AbstractPlugin),c=a;c._capabilities=null,c._panningModel="equalpower",c.context=null,c.isSupported=function(){var a=createjs.BrowserDetect.isIOS||createjs.BrowserDetect.isAndroid||createjs.BrowserDetect.isBlackberry;return"file:"!=location.protocol||a||this._isFileXHRSupported()?(c._generateCapabilities(),null==c.context?!1:!0):!1},c.playEmptySound=function(){var a=c.context.createBufferSource();a.buffer=c.context.createBuffer(1,1,22050),a.connect(c.context.destination),a.start(0,0,0)},c._isFileXHRSupported=function(){var a=!0,b=new XMLHttpRequest;try{b.open("GET","WebAudioPluginTest.fail",!1)}catch(c){return a=!1}b.onerror=function(){a=!1},b.onload=function(){a=404==this.status||200==this.status||0==this.status&&""!=this.response};try{b.send()}catch(c){a=!1}return a},c._generateCapabilities=function(){if(null==c._capabilities){var a=document.createElement("audio");if(null==a.canPlayType)return null;if(null==c.context)if(window.AudioContext)c.context=new AudioContext;else{if(!window.webkitAudioContext)return null;c.context=new webkitAudioContext}c._compatibilitySetUp(),c.playEmptySound(),c._capabilities={panning:!0,volume:!0,tracks:-1};for(var b=createjs.Sound.SUPPORTED_EXTENSIONS,d=createjs.Sound.EXTENSION_MAP,e=0,f=b.length;f>e;e++){var g=b[e],h=d[g]||g;c._capabilities[g]="no"!=a.canPlayType("audio/"+g)&&""!=a.canPlayType("audio/"+g)||"no"!=a.canPlayType("audio/"+h)&&""!=a.canPlayType("audio/"+h)}c.context.destination.numberOfChannels<2&&(c._capabilities.panning=!1)}},c._compatibilitySetUp=function(){if(c._panningModel="equalpower",!c.context.createGain){c.context.createGain=c.context.createGainNode;var a=c.context.createBufferSource();a.__proto__.start=a.__proto__.noteGrainOn,a.__proto__.stop=a.__proto__.noteOff,c._panningModel=0}},b.toString=function(){return"[WebAudioPlugin]"},b._addPropsToClasses=function(){var a=this._soundInstanceClass;a.context=this.context,a.destinationNode=this.gainNode,a._panningModel=this._panningModel,this._loaderClass.context=this.context},b._updateVolume=function(){var a=createjs.Sound._masterMute?0:this._volume;a!=this.gainNode.gain.value&&(this.gainNode.gain.value=a)},createjs.WebAudioPlugin=createjs.promote(a,"AbstractPlugin")}(),this.createjs=this.createjs||{},function(){"use strict";function a(a){this.src=a,this.length=0,this.available=0,this.tags=[],this.duration=0}var b=a.prototype;b.constructor=a;var c=a;c.tags={},c.get=function(b){var d=c.tags[b];return null==d&&(d=c.tags[b]=new a(b)),d},c.remove=function(a){var b=c.tags[a];return null==b?!1:(b.removeAll(),delete c.tags[a],!0)},c.getInstance=function(a){var b=c.tags[a];return null==b?null:b.get()},c.setInstance=function(a,b){var d=c.tags[a];return null==d?null:d.set(b)},c.getDuration=function(a){var b=c.tags[a];return null==b?0:b.getDuration()},b.add=function(a){this.tags.push(a),this.length++,this.available++},b.removeAll=function(){for(var a;this.length--;)a=this.tags[this.length],a.parentNode&&a.parentNode.removeChild(a),delete this.tags[this.length];this.src=null,this.tags.length=0},b.get=function(){if(0==this.tags.length)return null;this.available=this.tags.length;var a=this.tags.pop();return null==a.parentNode&&document.body.appendChild(a),a},b.set=function(a){var b=createjs.indexOf(this.tags,a);-1==b&&this.tags.push(a),this.available=this.tags.length},b.getDuration=function(){return this.duration||(this.duration=1e3*this.tags[this.tags.length-1].duration),this.duration},b.toString=function(){return"[HTMLAudioTagPool]"},createjs.HTMLAudioTagPool=a}(),this.createjs=this.createjs||{},function(){"use strict";function a(a,b,c,d){this.AbstractSoundInstance_constructor(a,b,c,d),this._audioSpriteStopTime=null,this._delayTimeoutId=null,this._endedHandler=createjs.proxy(this._handleSoundComplete,this),this._readyHandler=createjs.proxy(this._handleTagReady,this),this._stalledHandler=createjs.proxy(this.playFailed,this),this._audioSpriteEndHandler=createjs.proxy(this._handleAudioSpriteLoop,this),this._loopHandler=createjs.proxy(this._handleSoundComplete,this),c?this._audioSpriteStopTime=.001*(b+c):this._duration=createjs.HTMLAudioTagPool.getDuration(this.src)}var b=createjs.extend(a,createjs.AbstractSoundInstance);b.setMasterVolume=function(){this._updateVolume()},b.setMasterMute=function(){this._updateVolume()},b.toString=function(){return"[HTMLAudioSoundInstance]"},b._removeLooping=function(){null!=this._playbackResource&&(this._playbackResource.loop=!1,this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED,this._loopHandler,!1))},b._addLooping=function(){null==this._playbackResource||this._audioSpriteStopTime||(this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED,this._loopHandler,!1),this._playbackResource.loop=!0)},b._handleCleanUp=function(){var a=this._playbackResource;if(null!=a){a.pause(),a.loop=!1,a.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_ENDED,this._endedHandler,!1),a.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_READY,this._readyHandler,!1),a.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_STALLED,this._stalledHandler,!1),a.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED,this._loopHandler,!1),a.removeEventListener(createjs.HTMLAudioPlugin._TIME_UPDATE,this._audioSpriteEndHandler,!1);try{a.currentTime=this._startTime}catch(b){}createjs.HTMLAudioTagPool.setInstance(this.src,a),this._playbackResource=null}},b._beginPlaying=function(a,b,c,d){return this._playbackResource=createjs.HTMLAudioTagPool.getInstance(this.src),this.AbstractSoundInstance__beginPlaying(a,b,c,d)},b._handleSoundReady=function(){if(4!==this._playbackResource.readyState){var a=this._playbackResource;return a.addEventListener(createjs.HTMLAudioPlugin._AUDIO_READY,this._readyHandler,!1),a.addEventListener(createjs.HTMLAudioPlugin._AUDIO_STALLED,this._stalledHandler,!1),a.preload="auto",void a.load()}this._updateVolume(),this._playbackResource.currentTime=.001*(this._startTime+this._position),this._audioSpriteStopTime?this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._TIME_UPDATE,this._audioSpriteEndHandler,!1):(this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._AUDIO_ENDED,this._endedHandler,!1),0!=this._loop&&(this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED,this._loopHandler,!1),this._playbackResource.loop=!0)),this._playbackResource.play()},b._handleTagReady=function(){this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_READY,this._readyHandler,!1),this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_STALLED,this._stalledHandler,!1),this._handleSoundReady()},b._pause=function(){this._playbackResource.pause()},b._resume=function(){this._playbackResource.play()},b._updateVolume=function(){if(null!=this._playbackResource){var a=this._muted||createjs.Sound._masterMute?0:this._volume*createjs.Sound._masterVolume;a!=this._playbackResource.volume&&(this._playbackResource.volume=a)}},b._calculateCurrentPosition=function(){return 1e3*this._playbackResource.currentTime-this._startTime},b._updatePosition=function(){this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED,this._loopHandler,!1),this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED,this._handleSetPositionSeek,!1);try{this._playbackResource.currentTime=.001*(this._position+this._startTime)}catch(a){this._handleSetPositionSeek(null)}},b._handleSetPositionSeek=function(){null!=this._playbackResource&&(this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED,this._handleSetPositionSeek,!1),this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED,this._loopHandler,!1))},b._handleAudioSpriteLoop=function(){this._playbackResource.currentTime<=this._audioSpriteStopTime||(this._playbackResource.pause(),0==this._loop?this._handleSoundComplete(null):(this._position=0,this._loop--,this._playbackResource.currentTime=.001*this._startTime,this._paused||this._playbackResource.play(),this._sendEvent("loop")))},b._handleLoop=function(){0==this._loop&&(this._playbackResource.loop=!1,this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED,this._loopHandler,!1))},b._updateDuration=function(){this._audioSpriteStopTime=.001*(startTime+duration),this.playState==createjs.Sound.PLAY_SUCCEEDED&&(this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_ENDED,this._endedHandler,!1),this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._TIME_UPDATE,this._audioSpriteEndHandler,!1))},createjs.HTMLAudioSoundInstance=createjs.promote(a,"AbstractSoundInstance")}(),this.createjs=this.createjs||{},function(){"use strict";function a(){this.AbstractPlugin_constructor(),this.defaultNumChannels=2,this._capabilities=c._capabilities,this._loaderClass=createjs.SoundLoader,this._soundInstanceClass=createjs.HTMLAudioSoundInstance}var b=createjs.extend(a,createjs.AbstractPlugin),c=a;c.MAX_INSTANCES=30,c._AUDIO_READY="canplaythrough",c._AUDIO_ENDED="ended",c._AUDIO_SEEKED="seeked",c._AUDIO_STALLED="stalled",c._TIME_UPDATE="timeupdate",c._capabilities=null,c.enableIOS=!1,c.isSupported=function(){return c._generateCapabilities(),null==c._capabilities?!1:!0},c._generateCapabilities=function(){if(null==c._capabilities){var a=document.createElement("audio");if(null==a.canPlayType)return null;c._capabilities={panning:!0,volume:!0,tracks:-1};for(var b=createjs.Sound.SUPPORTED_EXTENSIONS,d=createjs.Sound.EXTENSION_MAP,e=0,f=b.length;f>e;e++){var g=b[e],h=d[g]||g;c._capabilities[g]="no"!=a.canPlayType("audio/"+g)&&""!=a.canPlayType("audio/"+g)||"no"!=a.canPlayType("audio/"+h)&&""!=a.canPlayType("audio/"+h)}}},b.register=function(a,b){for(var c=createjs.HTMLAudioTagPool.get(a.src),d=null,e=0;b>e;e++)d=this._createTag(a.src),c.add(d);var f=this.AbstractPlugin_register(a,b);return f.setTag(d),f},b.removeSound=function(a){this.AbstractPlugin_removeSound(a),createjs.HTMLAudioTagPool.remove(a)},b.create=function(a,b,c){var d=this.AbstractPlugin_create(a,b,c);return d.setPlaybackResource(null),d},b.toString=function(){return"[HTMLAudioPlugin]"},b.setVolume=b.getVolume=b.setMute=null,b._createTag=function(a){var b=document.createElement("audio");return b.autoplay=!1,b.preload="none",b.src=a,b},createjs.HTMLAudioPlugin=createjs.promote(a,"AbstractPlugin")}(); iOS.js 0000644 00000031741 15043670427 0005612 0 ustar 00 /* * iOS.js v1.9 * http://www.iOSjs.com/ * * Developed by Empty Galaxy * http://www.emptygalaxy.com/ * * Copyright (c) 2014 * Dual-licensed under the BSD or MIT licenses. * http://www.iOSjs.com/license/ */ var iOSjs = new function() { this.init = function() { // enable binding functions this.enableBinding(); // listen for events this.addEventListener(window, "load", this.handleWindowLoad.bind(this)); this.addEventListener(window, "orientationchange", this.handleOrientationChange.bind(this)); this.addEventListener(window, "resize", this.handleReize.bind(this)); } var resFunction = null; this.setResFunction = function(resFunc) { resFunction = resFunc; } var curOrientation = 0; // ===================================== // Read Device Properties // ===================================== this.isiOSDevice = function() { var u = navigator.userAgent; return u.indexOf("iPhone") > -1 || u.indexOf("iPod") > -1 || u.indexOf("iPad") > -1; } this.isiPhone = function() { return navigator.userAgent.indexOf("iPhone") > -1; } this.isiPod = function() { return navigator.userAgent.indexOf("iPod") > -1; } this.isiPad = function() { return navigator.userAgent.indexOf("iPad") > -1; } this.hasRetinaDisplay = function() { if(!window.devicePixelRatio) return false; return window.devicePixelRatio > 1; } // ===================================== // Read Browser Properties // ===================================== this.isFullscreen = function() { return navigator.standalone; } this.getViewportSize = function() { var windowSize = this.getWindowSize(); var bodySize = this.getElementSize(document.body); var scale = bodySize.width / windowSize.width; return {width:(windowSize.width * scale), height:(windowSize.height * scale)}; } this.getNormalWindowSize = function() { var width = 0; var heigth = 0; if(typeof(window.innerWidth) == "number") { // non-IE width = window.innerWidth; height = window.innerHeight; } else if(document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) { // IE 6+ in 'standards compliant mode' width = document.documentElement.clientWidth; height = document.documentElement.clientHeight; } else if(document.body && (document.body.clientWidth || document.body.clientHeight)) { // IE 4 compatible width = document.body.clientWidth; height = document.body.clientHeight; } return {width:width, height:height}; } this.getWindowSize = function() { var width = 0; var height = 0; if(this.isiOSDevice()) { // start with screen resolution width = screen.width; height = screen.height; // swap width & height if(window.orientation != 0) { var temp = width; width = height; height = temp; } var ua = navigator.userAgent; // subtract height of the status bar if(!(this.isFullscreen() && iOS_getMetaContent("apple-mobile-web-app-status-bar-style").toLowerCase() == "black-translucent")) height -= 20; if(ua.indexOf("iPhone") > -1 || ua.indexOf("iPod") > -1) { if(!this.isFullscreen()) { // subtract height of the button bar if(window.orientation == 0) height -= 44; else height -= 32; } } if(ua.indexOf("iPad") > -1) { // subtract height of the navigation bar if(!this.isFullscreen()) height -= 58; } } else { var size = this.getNormalWindowSize(); width = size.width; height = size.height; } return {width:width, height:height}; } // ===================================== // Read HTML Properties // ===================================== this.getCurSize = function() { //if(!window.orientation == 0) return this.getNormalWindowSize(); } this.getSizeWithoutPanels = function() { var width = 0; var height = 0; width = screen.width; height = screen.height; var nw = this.getNormalWindowSize(); var or = nw.width > nw.height ? 1 : 0; if(or != 0) { var temp = width; width = height; height = temp; } return {width:width, height:height}; } this.getMaxSize = function() { var width = 0; var height = 0; var nw = this.getNormalWindowSize(); var or = nw.width > nw.height ? 1 : 0; if(this.isiOSDevice()) { // start with screen resolution width = screen.width; height = screen.height; // swap width & height if(or != 0) { var temp = width; width = height; height = temp; } var ua = navigator.userAgent; if(ua.indexOf("iPhone") > -1 || ua.indexOf("iPod") > -1) { if(or == 0) height = this.getNormalWindowSize().height; } if(ua.indexOf("iPad") > -1) { width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; } } else { width = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth; height = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight; } return {width:width, height:height}; } this.getPageSize = function() { var bodySize = this.getElementSize(document.body); return bodySize; } // ===================================== // HTML Element Functions // ===================================== this.getElementSize = function(element) { if(!element) return {width:0, height:0}; var ns4; if(ns4) { var elem = getObjNN4(document, element); return {width:elem.clip.width, height:elem.clip.height}; } else { if(document.all) return {width:element.style.pixelWidth, height:element.style.pixelHeight}; else return {width:element.offsetWidth, height:element.offsetHeight}; } } this.getElementOffset = function(element) { var x = 0; var y = 0; while(element && !isNaN(element.offsetLeft) && !isNaN(element.offsetTop)) { x += element.offsetLeft - element.scrollLeft; y += element.offsetTop - element.scrollTop; element = element.offsetParent; } return {x: x, y: y}; } this.getElementPadding = function(element) { var style = element.currentStyle || window.getComputedStyle(element); return {top: parseFloat(style.paddingTop), right: parseFloat(style.paddingRight), bottom: parseFloat(style.paddingBottom), left: parseFloat(style.paddingLeft)}; } this.getElementMargin = function(element) { var style = element.currentStyle || window.getComputedStyle(element); return {top: parseFloat(style.marginTop), right: parseFloat(style.marginRight), bottom: parseFloat(style.marginBottom), left: parseFloat(style.marginLeft)}; } this.getMetaContent = function(name) { name = name.toLowerCase(); var metaList = document.getElementsByTagName("meta"); for(var i=0; i<metaList.length; i++) { var meta = metaList[i]; if(meta.name.toLowerCase() == name) { return meta.content; } } return null; } // ===================================== // Event Listening // ===================================== this.enableBinding = function() { if(!Function.prototype.bind) { Function.prototype.bind = function(target) { var method = this; var temp = function() { return method.apply(target, arguments); } return temp; } } } this.addEventListener = function(obj, evType, fn) { if(obj.addEventListener) { obj.addEventListener(evType, fn, false); return true; } else if(obj.attachEvent) { var r = obj.attachEvent("on" + evType, fn); return r; } else { return false; } } this.removeEventListener = function(obj, evType, fn) { if(obj.removeEventListener) { obj.removeEventListener(evType, fn, false); return true; } else if(obj.detachEvent) { var r = obj.detachEvent("on" + evType, fn); return r; } else { return false; } } // ===================================== // Event Handling // ===================================== this.handleWindowLoad = function(e) { this.initPage(); this.updateOrientation(); this.updateHeight(); // slightly delay hiding the address bar //setTimeout(this.hideAddressBar.bind(this), 100); } this.handleOrientationChange = function(e) { this.updateOrientation(); this.resize(); // slightly delay hiding the address bar //setTimeout(this.hideAddressBar.bind(this), 100); } this.handleReize = function(e) { this.resize(); /* famobi: add delayed resize needed when exiting fullscreen in chrome on older devices */ var self = this; setTimeout(function() { self.resize(); }, 500); } // ===================================== // Page Setup // ===================================== this.initPage = function() { if(this.isFullscreen()) this.createWebappLinks(); // set the iOS class on <html> var html = document.documentElement; var classes = html.className.split(" "); // Retina display if(this.hasRetinaDisplay() && classes.indexOf("retina") == -1) classes.push("retina"); if(this.isiOSDevice()) { // iOS class if(classes.indexOf("iOS") == -1) classes.push("iOS"); // fullscreen class if(this.isFullscreen() && classes.indexOf("fullscreen") == -1) classes.push("fullscreen"); // Device var ua = navigator.userAgent; if(ua.indexOf("iPhone") > -1) html.setAttribute("device", "iPhone"); else if(ua.indexOf("iPod") > -1) html.setAttribute("device", "iPod"); else if(ua.indexOf("iPad") > -1) html.setAttribute("device", "iPad"); // Device Family if(ua.indexOf("iPhone") > -1 || ua.indexOf("iPod") > -1) html.setAttribute("deviceFamily", "iPhone_iPod"); else if(ua.indexOf("iPad") > -1) html.setAttribute("deviceFamily", "iPad"); } html.className = classes.join(" "); } this.updateOrientation = function() { var orientation = "portrait"; if(window.orientation == 90 || window.orientation == -90) { orientation = "landscape"; curOrientation = 1; } else { curOrientation = 0; } document.documentElement.setAttribute("orientation", orientation); } this.resize = function() { this.updateHeight(); } // ===================================== // UI Functionality // ===================================== this.hideAddressBar = function() { //if(window.pageYOffset <= 1) window.scrollTo(window.pageXOffset, 1); } this.updateHeight = function() { var b = document.body; var viewportSize = this.getViewportSize(); var bodyPadding = this.getElementPadding(b); var bodyMargin = this.getElementMargin(b); // Add all var height = viewportSize.height; height -= (bodyPadding.top + bodyPadding.bottom) + (bodyMargin.top + bodyMargin.bottom); if(b.children.length > 0) { var l = b.children.length; var fc = b.children[0]; var fcPadding = this.getElementPadding(fc); var fcMargin = this.getElementMargin(fc); for(var i=l-1; i>=0; i--) { var lc = b.children[i]; if(lc.style.position == "absolute" || lc.style.position == "fixed") continue; if(lc.tagName == "SCRIPT") continue; break; } var lcPadding = this.getElementPadding(lc); var lcMargin = this.getElementMargin(lc); height -= (fcPadding.top + lcPadding.bottom) + (fcMargin.top + lcMargin.bottom) + 1; } //b.style.minHeight = Math.floor(height) + "px"; if (resFunction != null) { resFunction(); } } // ======== Scrolling ======== this.disableScrolling = function() { this.addEventListener(document.body, "touchmove", this.preventScrolling); } this.enableScrolling = function() { this.removeEventListener(document.body, "touchmove", this.preventScrolling); } this.preventScrolling = function(e) { //if(e.touches.length==1) { e.preventDefault(); //this.hideAddressBar(); } } // ======== Zooming ======== this.disableZooming = function() { this.addEventListener(document.body, "touchmove", this.preventZooming); } this.enableZooming = function() { this.removeEventListener(document.body, "touchmove", this.preventZooming); } this.preventZooming = function(e) { if(e.touches.length==2) e.preventDefault(); } // ===================================== // Content Setup // ===================================== this.createWebappLinks = function() { var aList = document.getElementsByTagName("a"); for(var i=0; i<aList.length; i++) { var a = aList[i]; if(a.href != "" && a.target == "") { a.onclick = this.handleWebAppLink; } } } this.handleWebAppLink = function() { // divert the user to the page in the same window window.location = this.getAttribute("href"); return false; } // ===================================== // Configurations // ===================================== this.autoWebapp = function() { this.addEventListener(window, "load", this.setupAutoWebapp); } this.setupAutoWebapp = function() { this.disableScrolling(); this.disableZooming(); } // ===================================== // Page Setup // ===================================== // initialize this.init(); }(); howler.js 0000644 00000235256 15043670427 0006427 0 ustar 00 /*! * howler.js v2.2.0 * howlerjs.com * * (c) 2013-2020, James Simpson of GoldFire Studios * goldfirestudios.com * * MIT License */ (function() { 'use strict'; /** Global Methods **/ /***************************************************************************/ /** * Create the global controller. All contained methods and properties apply * to all sounds that are currently playing or will be in the future. */ var HowlerGlobal = function() { this.init(); }; HowlerGlobal.prototype = { /** * Initialize the global Howler object. * @return {Howler} */ init: function() { var self = this || Howler; // Create a global ID counter. self._counter = 1000; // Pool of unlocked HTML5 Audio objects. self._html5AudioPool = []; self.html5PoolSize = 10; // Internal properties. self._codecs = {}; self._howls = []; self._muted = false; self._volume = 1; self._canPlayEvent = 'canplaythrough'; self._navigator = (typeof window !== 'undefined' && window.navigator) ? window.navigator : null; // Public properties. self.masterGain = null; self.noAudio = false; self.usingWebAudio = true; self.autoSuspend = true; self.ctx = null; // Set to false to disable the auto audio unlocker. self.autoUnlock = true; // Setup the various state values for global tracking. self._setup(); return self; }, /** * Get/set the global volume for all sounds. * @param {Float} vol Volume from 0.0 to 1.0. * @return {Howler/Float} Returns self or current volume. */ volume: function(vol) { var self = this || Howler; vol = parseFloat(vol); // If we don't have an AudioContext created yet, run the setup. if (!self.ctx) { setupAudioContext(); } if (typeof vol !== 'undefined' && vol >= 0 && vol <= 1) { self._volume = vol; // Don't update any of the nodes if we are muted. if (self._muted) { return self; } // When using Web Audio, we just need to adjust the master gain. if (self.usingWebAudio) { self.masterGain.gain.setValueAtTime(vol, Howler.ctx.currentTime); } // Loop through and change volume for all HTML5 audio nodes. for (var i=0; i<self._howls.length; i++) { if (!self._howls[i]._webAudio) { // Get all of the sounds in this Howl group. var ids = self._howls[i]._getSoundIds(); // Loop through all sounds and change the volumes. for (var j=0; j<ids.length; j++) { var sound = self._howls[i]._soundById(ids[j]); if (sound && sound._node) { sound._node.volume = sound._volume * vol; } } } } return self; } return self._volume; }, /** * Handle muting and unmuting globally. * @param {Boolean} muted Is muted or not. */ mute: function(muted) { var self = this || Howler; // If we don't have an AudioContext created yet, run the setup. if (!self.ctx) { setupAudioContext(); } self._muted = muted; // With Web Audio, we just need to mute the master gain. if (self.usingWebAudio) { self.masterGain.gain.setValueAtTime(muted ? 0 : self._volume, Howler.ctx.currentTime); } // Loop through and mute all HTML5 Audio nodes. for (var i=0; i<self._howls.length; i++) { if (!self._howls[i]._webAudio) { // Get all of the sounds in this Howl group. var ids = self._howls[i]._getSoundIds(); // Loop through all sounds and mark the audio node as muted. for (var j=0; j<ids.length; j++) { var sound = self._howls[i]._soundById(ids[j]); if (sound && sound._node) { sound._node.muted = (muted) ? true : sound._muted; } } } } return self; }, /** * Handle stopping all sounds globally. */ stop: function() { var self = this || Howler; // Loop through all Howls and stop them. for (var i=0; i<self._howls.length; i++) { self._howls[i].stop(); } return self; }, /** * Unload and destroy all currently loaded Howl objects. * @return {Howler} */ unload: function() { var self = this || Howler; for (var i=self._howls.length-1; i>=0; i--) { self._howls[i].unload(); } // Create a new AudioContext to make sure it is fully reset. if (self.usingWebAudio && self.ctx && typeof self.ctx.close !== 'undefined') { self.ctx.close(); self.ctx = null; setupAudioContext(); } return self; }, /** * Check for codec support of specific extension. * @param {String} ext Audio file extention. * @return {Boolean} */ codecs: function(ext) { return (this || Howler)._codecs[ext.replace(/^x-/, '')]; }, /** * Setup various state values for global tracking. * @return {Howler} */ _setup: function() { var self = this || Howler; // Keeps track of the suspend/resume state of the AudioContext. self.state = self.ctx ? self.ctx.state || 'suspended' : 'suspended'; // Automatically begin the 30-second suspend process self._autoSuspend(); // Check if audio is available. if (!self.usingWebAudio) { // No audio is available on this system if noAudio is set to true. if (typeof Audio !== 'undefined') { try { var test = new Audio(); // Check if the canplaythrough event is available. if (typeof test.oncanplaythrough === 'undefined') { self._canPlayEvent = 'canplay'; } } catch(e) { self.noAudio = true; } } else { self.noAudio = true; } } // Test to make sure audio isn't disabled in Internet Explorer. try { var test = new Audio(); if (test.muted) { self.noAudio = true; } } catch (e) {} // Check for supported codecs. if (!self.noAudio) { self._setupCodecs(); } return self; }, /** * Check for browser support for various codecs and cache the results. * @return {Howler} */ _setupCodecs: function() { var self = this || Howler; var audioTest = null; // Must wrap in a try/catch because IE11 in server mode throws an error. try { audioTest = (typeof Audio !== 'undefined') ? new Audio() : null; } catch (err) { return self; } if (!audioTest || typeof audioTest.canPlayType !== 'function') { return self; } var mpegTest = audioTest.canPlayType('audio/mpeg;').replace(/^no$/, ''); // Opera version <33 has mixed MP3 support, so we need to check for and block it. var checkOpera = self._navigator && self._navigator.userAgent.match(/OPR\/([0-6].)/g); var isOldOpera = (checkOpera && parseInt(checkOpera[0].split('/')[1], 10) < 33); self._codecs = { mp3: !!(!isOldOpera && (mpegTest || audioTest.canPlayType('audio/mp3;').replace(/^no$/, ''))), mpeg: !!mpegTest, opus: !!audioTest.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/, ''), ogg: !!audioTest.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ''), oga: !!audioTest.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ''), wav: !!audioTest.canPlayType('audio/wav; codecs="1"').replace(/^no$/, ''), aac: !!audioTest.canPlayType('audio/aac;').replace(/^no$/, ''), caf: !!audioTest.canPlayType('audio/x-caf;').replace(/^no$/, ''), m4a: !!(audioTest.canPlayType('audio/x-m4a;') || audioTest.canPlayType('audio/m4a;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''), m4b: !!(audioTest.canPlayType('audio/x-m4b;') || audioTest.canPlayType('audio/m4b;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''), mp4: !!(audioTest.canPlayType('audio/x-mp4;') || audioTest.canPlayType('audio/mp4;') || audioTest.canPlayType('audio/aac;')).replace(/^no$/, ''), weba: !!audioTest.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, ''), webm: !!audioTest.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, ''), dolby: !!audioTest.canPlayType('audio/mp4; codecs="ec-3"').replace(/^no$/, ''), flac: !!(audioTest.canPlayType('audio/x-flac;') || audioTest.canPlayType('audio/flac;')).replace(/^no$/, '') }; return self; }, /** * Some browsers/devices will only allow audio to be played after a user interaction. * Attempt to automatically unlock audio on the first user interaction. * Concept from: http://paulbakaus.com/tutorials/html5/web-audio-on-ios/ * @return {Howler} */ _unlockAudio: function() { var self = this || Howler; // Only run this if Web Audio is supported and it hasn't already been unlocked. if (self._audioUnlocked || !self.ctx) { return; } self._audioUnlocked = false; self.autoUnlock = false; // Some mobile devices/platforms have distortion issues when opening/closing tabs and/or web views. // Bugs in the browser (especially Mobile Safari) can cause the sampleRate to change from 44100 to 48000. // By calling Howler.unload(), we create a new AudioContext with the correct sampleRate. if (!self._mobileUnloaded && self.ctx.sampleRate !== 44100) { self._mobileUnloaded = true; self.unload(); } // Scratch buffer for enabling iOS to dispose of web audio buffers correctly, as per: // http://stackoverflow.com/questions/24119684 self._scratchBuffer = self.ctx.createBuffer(1, 1, 22050); // Call this method on touch start to create and play a buffer, // then check if the audio actually played to determine if // audio has now been unlocked on iOS, Android, etc. var unlock = function(e) { // Create a pool of unlocked HTML5 Audio objects that can // be used for playing sounds without user interaction. HTML5 // Audio objects must be individually unlocked, as opposed // to the WebAudio API which only needs a single activation. // This must occur before WebAudio setup or the source.onended // event will not fire. while (self._html5AudioPool.length < self.html5PoolSize) { try { var audioNode = new Audio(); // Mark this Audio object as unlocked to ensure it can get returned // to the unlocked pool when released. audioNode._unlocked = true; // Add the audio node to the pool. self._releaseHtml5Audio(audioNode); } catch (e) { self.noAudio = true; break; } } // Loop through any assigned audio nodes and unlock them. for (var i=0; i<self._howls.length; i++) { if (!self._howls[i]._webAudio) { // Get all of the sounds in this Howl group. var ids = self._howls[i]._getSoundIds(); // Loop through all sounds and unlock the audio nodes. for (var j=0; j<ids.length; j++) { var sound = self._howls[i]._soundById(ids[j]); if (sound && sound._node && !sound._node._unlocked) { sound._node._unlocked = true; sound._node.load(); } } } } // Fix Android can not play in suspend state. self._autoResume(); // Create an empty buffer. var source = self.ctx.createBufferSource(); source.buffer = self._scratchBuffer; source.connect(self.ctx.destination); // Play the empty buffer. if (typeof source.start === 'undefined') { source.noteOn(0); } else { source.start(0); } // Calling resume() on a stack initiated by user gesture is what actually unlocks the audio on Android Chrome >= 55. if (typeof self.ctx.resume === 'function') { self.ctx.resume(); } // Setup a timeout to check that we are unlocked on the next event loop. source.onended = function() { source.disconnect(0); // Update the unlocked state and prevent this check from happening again. self._audioUnlocked = true; // Remove the touch start listener. document.removeEventListener('touchstart', unlock, true); document.removeEventListener('touchend', unlock, true); document.removeEventListener('click', unlock, true); // Let all sounds know that audio has been unlocked. for (var i=0; i<self._howls.length; i++) { self._howls[i]._emit('unlock'); } }; }; // Setup a touch start listener to attempt an unlock in. document.addEventListener('touchstart', unlock, true); document.addEventListener('touchend', unlock, true); document.addEventListener('click', unlock, true); return self; }, /** * Get an unlocked HTML5 Audio object from the pool. If none are left, * return a new Audio object and throw a warning. * @return {Audio} HTML5 Audio object. */ _obtainHtml5Audio: function() { var self = this || Howler; // Return the next object from the pool if one exists. if (self._html5AudioPool.length) { return self._html5AudioPool.pop(); } //.Check if the audio is locked and throw a warning. var testPlay = new Audio().play(); if (testPlay && typeof Promise !== 'undefined' && (testPlay instanceof Promise || typeof testPlay.then === 'function')) { testPlay.catch(function() { console.warn('HTML5 Audio pool exhausted, returning potentially locked audio object.'); }); } return new Audio(); }, /** * Return an activated HTML5 Audio object to the pool. * @return {Howler} */ _releaseHtml5Audio: function(audio) { var self = this || Howler; // Don't add audio to the pool if we don't know if it has been unlocked. if (audio._unlocked) { self._html5AudioPool.push(audio); } return self; }, /** * Automatically suspend the Web Audio AudioContext after no sound has played for 30 seconds. * This saves processing/energy and fixes various browser-specific bugs with audio getting stuck. * @return {Howler} */ _autoSuspend: function() { var self = this; if (!self.autoSuspend || !self.ctx || typeof self.ctx.suspend === 'undefined' || !Howler.usingWebAudio) { return; } // Check if any sounds are playing. for (var i=0; i<self._howls.length; i++) { if (self._howls[i]._webAudio) { for (var j=0; j<self._howls[i]._sounds.length; j++) { if (!self._howls[i]._sounds[j]._paused) { return self; } } } } if (self._suspendTimer) { clearTimeout(self._suspendTimer); } // If no sound has played after 30 seconds, suspend the context. self._suspendTimer = setTimeout(function() { if (!self.autoSuspend) { return; } self._suspendTimer = null; self.state = 'suspending'; // Handle updating the state of the audio context after suspending. var handleSuspension = function() { self.state = 'suspended'; if (self._resumeAfterSuspend) { delete self._resumeAfterSuspend; self._autoResume(); } }; // Either the state gets suspended or it is interrupted. // Either way, we need to update the state to suspended. self.ctx.suspend().then(handleSuspension, handleSuspension); }, 30000); return self; }, /** * Automatically resume the Web Audio AudioContext when a new sound is played. * @return {Howler} */ _autoResume: function() { var self = this; if (!self.ctx || typeof self.ctx.resume === 'undefined' || !Howler.usingWebAudio) { return; } if (self.state === 'running' && self.ctx.state !== 'interrupted' && self._suspendTimer) { clearTimeout(self._suspendTimer); self._suspendTimer = null; } else if (self.state === 'suspended' || self.state === 'running' && self.ctx.state === 'interrupted') { self.ctx.resume().then(function() { self.state = 'running'; // Emit to all Howls that the audio has resumed. for (var i=0; i<self._howls.length; i++) { self._howls[i]._emit('resume'); } }); if (self._suspendTimer) { clearTimeout(self._suspendTimer); self._suspendTimer = null; } } else if (self.state === 'suspending') { self._resumeAfterSuspend = true; } return self; } }; // Setup the global audio controller. var Howler = new HowlerGlobal(); /** Group Methods **/ /***************************************************************************/ /** * Create an audio group controller. * @param {Object} o Passed in properties for this group. */ var Howl = function(o) { var self = this; // Throw an error if no source is provided. if (!o.src || o.src.length === 0) { console.error('An array of source files must be passed with any new Howl.'); return; } self.init(o); }; Howl.prototype = { /** * Initialize a new Howl group object. * @param {Object} o Passed in properties for this group. * @return {Howl} */ init: function(o) { var self = this; // If we don't have an AudioContext created yet, run the setup. if (!Howler.ctx) { setupAudioContext(); } // Setup user-defined default properties. self._autoplay = o.autoplay || false; self._format = (typeof o.format !== 'string') ? o.format : [o.format]; self._html5 = o.html5 || false; self._muted = o.mute || false; self._loop = o.loop || false; self._pool = o.pool || 5; self._preload = (typeof o.preload === 'boolean' || o.preload === 'metadata') ? o.preload : true; self._rate = o.rate || 1; self._sprite = o.sprite || {}; self._src = (typeof o.src !== 'string') ? o.src : [o.src]; self._volume = o.volume !== undefined ? o.volume : 1; self._xhr = { method: o.xhr && o.xhr.method ? o.xhr.method : 'GET', headers: o.xhr && o.xhr.headers ? o.xhr.headers : null, withCredentials: o.xhr && o.xhr.withCredentials ? o.xhr.withCredentials : false, }; // Setup all other default properties. self._duration = 0; self._state = 'unloaded'; self._sounds = []; self._endTimers = {}; self._queue = []; self._playLock = false; // Setup event listeners. self._onend = o.onend ? [{fn: o.onend}] : []; self._onfade = o.onfade ? [{fn: o.onfade}] : []; self._onload = o.onload ? [{fn: o.onload}] : []; self._onloaderror = o.onloaderror ? [{fn: o.onloaderror}] : []; self._onplayerror = o.onplayerror ? [{fn: o.onplayerror}] : []; self._onpause = o.onpause ? [{fn: o.onpause}] : []; self._onplay = o.onplay ? [{fn: o.onplay}] : []; self._onstop = o.onstop ? [{fn: o.onstop}] : []; self._onmute = o.onmute ? [{fn: o.onmute}] : []; self._onvolume = o.onvolume ? [{fn: o.onvolume}] : []; self._onrate = o.onrate ? [{fn: o.onrate}] : []; self._onseek = o.onseek ? [{fn: o.onseek}] : []; self._onunlock = o.onunlock ? [{fn: o.onunlock}] : []; self._onresume = []; // Web Audio or HTML5 Audio? self._webAudio = Howler.usingWebAudio && !self._html5; // Automatically try to enable audio. if (typeof Howler.ctx !== 'undefined' && Howler.ctx && Howler.autoUnlock) { Howler._unlockAudio(); } // Keep track of this Howl group in the global controller. Howler._howls.push(self); // If they selected autoplay, add a play event to the load queue. if (self._autoplay) { self._queue.push({ event: 'play', action: function() { self.play(); } }); } // Load the source file unless otherwise specified. if (self._preload && self._preload !== 'none') { self.load(); } return self; }, /** * Load the audio file. * @return {Howler} */ load: function() { var self = this; var url = null; // If no audio is available, quit immediately. if (Howler.noAudio) { self._emit('loaderror', null, 'No audio support.'); return; } // Make sure our source is in an array. if (typeof self._src === 'string') { self._src = [self._src]; } // Loop through the sources and pick the first one that is compatible. for (var i=0; i<self._src.length; i++) { var ext, str; if (self._format && self._format[i]) { // If an extension was specified, use that instead. ext = self._format[i]; } else { // Make sure the source is a string. str = self._src[i]; if (typeof str !== 'string') { self._emit('loaderror', null, 'Non-string found in selected audio sources - ignoring.'); continue; } // Extract the file extension from the URL or base64 data URI. ext = /^data:audio\/([^;,]+);/i.exec(str); if (!ext) { ext = /\.([^.]+)$/.exec(str.split('?', 1)[0]); } if (ext) { ext = ext[1].toLowerCase(); } } // Log a warning if no extension was found. if (!ext) { console.warn('No file extension was found. Consider using the "format" property or specify an extension.'); } // Check if this extension is available. if (ext && Howler.codecs(ext)) { url = self._src[i]; break; } } if (!url) { self._emit('loaderror', null, 'No codec support for selected audio sources.'); return; } self._src = url; self._state = 'loading'; // If the hosting page is HTTPS and the source isn't, // drop down to HTML5 Audio to avoid Mixed Content errors. if (window.location.protocol === 'https:' && url.slice(0, 5) === 'http:') { self._html5 = true; self._webAudio = false; } // Create a new sound object and add it to the pool. new Sound(self); // Load and decode the audio data for playback. if (self._webAudio) { loadBuffer(self); } return self; }, /** * Play a sound or resume previous playback. * @param {String/Number} sprite Sprite name for sprite playback or sound id to continue previous. * @param {Boolean} internal Internal Use: true prevents event firing. * @return {Number} Sound ID. */ play: function(sprite, internal) { var self = this; var id = null; // Determine if a sprite, sound id or nothing was passed if (typeof sprite === 'number') { id = sprite; sprite = null; } else if (typeof sprite === 'string' && self._state === 'loaded' && !self._sprite[sprite]) { // If the passed sprite doesn't exist, do nothing. return null; } else if (typeof sprite === 'undefined') { // Use the default sound sprite (plays the full audio length). sprite = '__default'; // Check if there is a single paused sound that isn't ended. // If there is, play that sound. If not, continue as usual. if (!self._playLock) { var num = 0; for (var i=0; i<self._sounds.length; i++) { if (self._sounds[i]._paused && !self._sounds[i]._ended) { num++; id = self._sounds[i]._id; } } if (num === 1) { sprite = null; } else { id = null; } } } // Get the selected node, or get one from the pool. var sound = id ? self._soundById(id) : self._inactiveSound(); // If the sound doesn't exist, do nothing. if (!sound) { return null; } // Select the sprite definition. if (id && !sprite) { sprite = sound._sprite || '__default'; } // If the sound hasn't loaded, we must wait to get the audio's duration. // We also need to wait to make sure we don't run into race conditions with // the order of function calls. if (self._state !== 'loaded') { // Set the sprite value on this sound. sound._sprite = sprite; // Mark this sound as not ended in case another sound is played before this one loads. sound._ended = false; // Add the sound to the queue to be played on load. var soundId = sound._id; self._queue.push({ event: 'play', action: function() { self.play(soundId); } }); return soundId; } // Don't play the sound if an id was passed and it is already playing. if (id && !sound._paused) { // Trigger the play event, in order to keep iterating through queue. if (!internal) { self._loadQueue('play'); } return sound._id; } // Make sure the AudioContext isn't suspended, and resume it if it is. if (self._webAudio) { Howler._autoResume(); } // Determine how long to play for and where to start playing. var seek = Math.max(0, sound._seek > 0 ? sound._seek : self._sprite[sprite][0] / 1000); var duration = Math.max(0, ((self._sprite[sprite][0] + self._sprite[sprite][1]) / 1000) - seek); var timeout = (duration * 1000) / Math.abs(sound._rate); var start = self._sprite[sprite][0] / 1000; var stop = (self._sprite[sprite][0] + self._sprite[sprite][1]) / 1000; sound._sprite = sprite; // Mark the sound as ended instantly so that this async playback // doesn't get grabbed by another call to play while this one waits to start. sound._ended = false; // Update the parameters of the sound. var setParams = function() { sound._paused = false; sound._seek = seek; sound._start = start; sound._stop = stop; sound._loop = !!(sound._loop || self._sprite[sprite][2]); }; // End the sound instantly if seek is at the end. if (seek >= stop) { self._ended(sound); return; } // Begin the actual playback. var node = sound._node; if (self._webAudio) { // Fire this when the sound is ready to play to begin Web Audio playback. var playWebAudio = function() { self._playLock = false; setParams(); self._refreshBuffer(sound); // Setup the playback params. var vol = (sound._muted || self._muted) ? 0 : sound._volume; node.gain.setValueAtTime(vol, Howler.ctx.currentTime); sound._playStart = Howler.ctx.currentTime; // Play the sound using the supported method. if (typeof node.bufferSource.start === 'undefined') { sound._loop ? node.bufferSource.noteGrainOn(0, seek, 86400) : node.bufferSource.noteGrainOn(0, seek, duration); } else { sound._loop ? node.bufferSource.start(0, seek, 86400) : node.bufferSource.start(0, seek, duration); } // Start a new timer if none is present. if (timeout !== Infinity) { self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout); } if (!internal) { setTimeout(function() { self._emit('play', sound._id); self._loadQueue(); }, 0); } }; if (Howler.state === 'running' && Howler.ctx.state !== 'interrupted') { playWebAudio(); } else { self._playLock = true; // Wait for the audio context to resume before playing. self.once('resume', playWebAudio); // Cancel the end timer. self._clearTimer(sound._id); } } else { // Fire this when the sound is ready to play to begin HTML5 Audio playback. var playHtml5 = function() { node.currentTime = seek; node.muted = sound._muted || self._muted || Howler._muted || node.muted; node.volume = sound._volume * Howler.volume(); node.playbackRate = sound._rate; // Some browsers will throw an error if this is called without user interaction. try { var play = node.play(); // Support older browsers that don't support promises, and thus don't have this issue. if (play && typeof Promise !== 'undefined' && (play instanceof Promise || typeof play.then === 'function')) { // Implements a lock to prevent DOMException: The play() request was interrupted by a call to pause(). self._playLock = true; // Set param values immediately. setParams(); // Releases the lock and executes queued actions. play .then(function() { self._playLock = false; node._unlocked = true; if (!internal) { self._emit('play', sound._id); self._loadQueue(); } }) .catch(function() { self._playLock = false; self._emit('playerror', sound._id, 'Playback was unable to start. This is most commonly an issue ' + 'on mobile devices and Chrome where playback was not within a user interaction.'); // Reset the ended and paused values. sound._ended = true; sound._paused = true; }); } else if (!internal) { self._playLock = false; setParams(); self._emit('play', sound._id); self._loadQueue(); } // Setting rate before playing won't work in IE, so we set it again here. node.playbackRate = sound._rate; // If the node is still paused, then we can assume there was a playback issue. if (node.paused) { self._emit('playerror', sound._id, 'Playback was unable to start. This is most commonly an issue ' + 'on mobile devices and Chrome where playback was not within a user interaction.'); return; } // Setup the end timer on sprites or listen for the ended event. if (sprite !== '__default' || sound._loop) { self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout); } else { self._endTimers[sound._id] = function() { // Fire ended on this audio node. self._ended(sound); // Clear this listener. node.removeEventListener('ended', self._endTimers[sound._id], false); }; node.addEventListener('ended', self._endTimers[sound._id], false); } } catch (err) { self._emit('playerror', sound._id, err); } }; // If this is streaming audio, make sure the src is set and load again. if (node.src === 'data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA') { node.src = self._src; node.load(); } // Play immediately if ready, or wait for the 'canplaythrough'e vent. var loadedNoReadyState = (window && window.ejecta) || (!node.readyState && Howler._navigator.isCocoonJS); if (node.readyState >= 3 || loadedNoReadyState) { playHtml5(); } else { self._playLock = true; var listener = function() { // Begin playback. playHtml5(); // Clear this listener. node.removeEventListener(Howler._canPlayEvent, listener, false); }; node.addEventListener(Howler._canPlayEvent, listener, false); // Cancel the end timer. self._clearTimer(sound._id); } } return sound._id; }, /** * Pause playback and save current position. * @param {Number} id The sound ID (empty to pause all in group). * @return {Howl} */ pause: function(id) { var self = this; // If the sound hasn't loaded or a play() promise is pending, add it to the load queue to pause when capable. if (self._state !== 'loaded' || self._playLock) { self._queue.push({ event: 'pause', action: function() { self.pause(id); } }); return self; } // If no id is passed, get all ID's to be paused. var ids = self._getSoundIds(id); for (var i=0; i<ids.length; i++) { // Clear the end timer. self._clearTimer(ids[i]); // Get the sound. var sound = self._soundById(ids[i]); if (sound && !sound._paused) { // Reset the seek position. sound._seek = self.seek(ids[i]); sound._rateSeek = 0; sound._paused = true; // Stop currently running fades. self._stopFade(ids[i]); if (sound._node) { if (self._webAudio) { // Make sure the sound has been created. if (!sound._node.bufferSource) { continue; } if (typeof sound._node.bufferSource.stop === 'undefined') { sound._node.bufferSource.noteOff(0); } else { sound._node.bufferSource.stop(0); } // Clean up the buffer source. self._cleanBuffer(sound._node); } else if (!isNaN(sound._node.duration) || sound._node.duration === Infinity) { sound._node.pause(); } } } // Fire the pause event, unless `true` is passed as the 2nd argument. if (!arguments[1]) { self._emit('pause', sound ? sound._id : null); } } return self; }, /** * Stop playback and reset to start. * @param {Number} id The sound ID (empty to stop all in group). * @param {Boolean} internal Internal Use: true prevents event firing. * @return {Howl} */ stop: function(id, internal) { var self = this; // If the sound hasn't loaded, add it to the load queue to stop when capable. if (self._state !== 'loaded' || self._playLock) { self._queue.push({ event: 'stop', action: function() { self.stop(id); } }); return self; } // If no id is passed, get all ID's to be stopped. var ids = self._getSoundIds(id); for (var i=0; i<ids.length; i++) { // Clear the end timer. self._clearTimer(ids[i]); // Get the sound. var sound = self._soundById(ids[i]); if (sound) { // Reset the seek position. sound._seek = sound._start || 0; sound._rateSeek = 0; sound._paused = true; sound._ended = true; // Stop currently running fades. self._stopFade(ids[i]); if (sound._node) { if (self._webAudio) { // Make sure the sound's AudioBufferSourceNode has been created. if (sound._node.bufferSource) { if (typeof sound._node.bufferSource.stop === 'undefined') { sound._node.bufferSource.noteOff(0); } else { sound._node.bufferSource.stop(0); } // Clean up the buffer source. self._cleanBuffer(sound._node); } } else if (!isNaN(sound._node.duration) || sound._node.duration === Infinity) { sound._node.currentTime = sound._start || 0; sound._node.pause(); // If this is a live stream, stop download once the audio is stopped. if (sound._node.duration === Infinity) { self._clearSound(sound._node); } } } if (!internal) { self._emit('stop', sound._id); } } } return self; }, /** * Mute/unmute a single sound or all sounds in this Howl group. * @param {Boolean} muted Set to true to mute and false to unmute. * @param {Number} id The sound ID to update (omit to mute/unmute all). * @return {Howl} */ mute: function(muted, id) { var self = this; // If the sound hasn't loaded, add it to the load queue to mute when capable. if (self._state !== 'loaded'|| self._playLock) { self._queue.push({ event: 'mute', action: function() { self.mute(muted, id); } }); return self; } // If applying mute/unmute to all sounds, update the group's value. if (typeof id === 'undefined') { if (typeof muted === 'boolean') { self._muted = muted; } else { return self._muted; } } // If no id is passed, get all ID's to be muted. var ids = self._getSoundIds(id); for (var i=0; i<ids.length; i++) { // Get the sound. var sound = self._soundById(ids[i]); if (sound) { sound._muted = muted; // Cancel active fade and set the volume to the end value. if (sound._interval) { self._stopFade(sound._id); } if (self._webAudio && sound._node) { sound._node.gain.setValueAtTime(muted ? 0 : sound._volume, Howler.ctx.currentTime); } else if (sound._node) { sound._node.muted = Howler._muted ? true : muted; } self._emit('mute', sound._id); } } return self; }, /** * Get/set the volume of this sound or of the Howl group. This method can optionally take 0, 1 or 2 arguments. * volume() -> Returns the group's volume value. * volume(id) -> Returns the sound id's current volume. * volume(vol) -> Sets the volume of all sounds in this Howl group. * volume(vol, id) -> Sets the volume of passed sound id. * @return {Howl/Number} Returns self or current volume. */ volume: function() { var self = this; var args = arguments; var vol, id; // Determine the values based on arguments. if (args.length === 0) { // Return the value of the groups' volume. return self._volume; } else if (args.length === 1 || args.length === 2 && typeof args[1] === 'undefined') { // First check if this is an ID, and if not, assume it is a new volume. var ids = self._getSoundIds(); var index = ids.indexOf(args[0]); if (index >= 0) { id = parseInt(args[0], 10); } else { vol = parseFloat(args[0]); } } else if (args.length >= 2) { vol = parseFloat(args[0]); id = parseInt(args[1], 10); } // Update the volume or return the current volume. var sound; if (typeof vol !== 'undefined' && vol >= 0 && vol <= 1) { // If the sound hasn't loaded, add it to the load queue to change volume when capable. if (self._state !== 'loaded'|| self._playLock) { self._queue.push({ event: 'volume', action: function() { self.volume.apply(self, args); } }); return self; } // Set the group volume. if (typeof id === 'undefined') { self._volume = vol; } // Update one or all volumes. id = self._getSoundIds(id); for (var i=0; i<id.length; i++) { // Get the sound. sound = self._soundById(id[i]); if (sound) { sound._volume = vol; // Stop currently running fades. if (!args[2]) { self._stopFade(id[i]); } if (self._webAudio && sound._node && !sound._muted) { sound._node.gain.setValueAtTime(vol, Howler.ctx.currentTime); } else if (sound._node && !sound._muted) { sound._node.volume = vol * Howler.volume(); } self._emit('volume', sound._id); } } } else { sound = id ? self._soundById(id) : self._sounds[0]; return sound ? sound._volume : 0; } return self; }, /** * Fade a currently playing sound between two volumes (if no id is passed, all sounds will fade). * @param {Number} from The value to fade from (0.0 to 1.0). * @param {Number} to The volume to fade to (0.0 to 1.0). * @param {Number} len Time in milliseconds to fade. * @param {Number} id The sound id (omit to fade all sounds). * @return {Howl} */ fade: function(from, to, len, id) { var self = this; // If the sound hasn't loaded, add it to the load queue to fade when capable. if (self._state !== 'loaded' || self._playLock) { self._queue.push({ event: 'fade', action: function() { self.fade(from, to, len, id); } }); return self; } // Make sure the to/from/len values are numbers. from = Math.min(Math.max(0, parseFloat(from)), 1); to = Math.min(Math.max(0, parseFloat(to)), 1); len = parseFloat(len); // Set the volume to the start position. self.volume(from, id); // Fade the volume of one or all sounds. var ids = self._getSoundIds(id); for (var i=0; i<ids.length; i++) { // Get the sound. var sound = self._soundById(ids[i]); // Create a linear fade or fall back to timeouts with HTML5 Audio. if (sound) { // Stop the previous fade if no sprite is being used (otherwise, volume handles this). if (!id) { self._stopFade(ids[i]); } // If we are using Web Audio, let the native methods do the actual fade. if (self._webAudio && !sound._muted) { var currentTime = Howler.ctx.currentTime; var end = currentTime + (len / 1000); sound._volume = from; sound._node.gain.setValueAtTime(from, currentTime); sound._node.gain.linearRampToValueAtTime(to, end); } self._startFadeInterval(sound, from, to, len, ids[i], typeof id === 'undefined'); } } return self; }, /** * Starts the internal interval to fade a sound. * @param {Object} sound Reference to sound to fade. * @param {Number} from The value to fade from (0.0 to 1.0). * @param {Number} to The volume to fade to (0.0 to 1.0). * @param {Number} len Time in milliseconds to fade. * @param {Number} id The sound id to fade. * @param {Boolean} isGroup If true, set the volume on the group. */ _startFadeInterval: function(sound, from, to, len, id, isGroup) { var self = this; var vol = from; var diff = to - from; var steps = Math.abs(diff / 0.01); var stepLen = Math.max(4, (steps > 0) ? len / steps : len); var lastTick = Date.now(); // Store the value being faded to. sound._fadeTo = to; // Update the volume value on each interval tick. sound._interval = setInterval(function() { // Update the volume based on the time since the last tick. var tick = (Date.now() - lastTick) / len; lastTick = Date.now(); vol += diff * tick; // Make sure the volume is in the right bounds. if (diff < 0) { vol = Math.max(to, vol); } else { vol = Math.min(to, vol); } // Round to within 2 decimal points. vol = Math.round(vol * 100) / 100; // Change the volume. if (self._webAudio) { sound._volume = vol; } else { self.volume(vol, sound._id, true); } // Set the group's volume. if (isGroup) { self._volume = vol; } // When the fade is complete, stop it and fire event. if ((to < from && vol <= to) || (to > from && vol >= to)) { clearInterval(sound._interval); sound._interval = null; sound._fadeTo = null; self.volume(to, sound._id); self._emit('fade', sound._id); } }, stepLen); }, /** * Internal method that stops the currently playing fade when * a new fade starts, volume is changed or the sound is stopped. * @param {Number} id The sound id. * @return {Howl} */ _stopFade: function(id) { var self = this; var sound = self._soundById(id); if (sound && sound._interval) { if (self._webAudio) { sound._node.gain.cancelScheduledValues(Howler.ctx.currentTime); } clearInterval(sound._interval); sound._interval = null; self.volume(sound._fadeTo, id); sound._fadeTo = null; self._emit('fade', id); } return self; }, /** * Get/set the loop parameter on a sound. This method can optionally take 0, 1 or 2 arguments. * loop() -> Returns the group's loop value. * loop(id) -> Returns the sound id's loop value. * loop(loop) -> Sets the loop value for all sounds in this Howl group. * loop(loop, id) -> Sets the loop value of passed sound id. * @return {Howl/Boolean} Returns self or current loop value. */ loop: function() { var self = this; var args = arguments; var loop, id, sound; // Determine the values for loop and id. if (args.length === 0) { // Return the grou's loop value. return self._loop; } else if (args.length === 1) { if (typeof args[0] === 'boolean') { loop = args[0]; self._loop = loop; } else { // Return this sound's loop value. sound = self._soundById(parseInt(args[0], 10)); return sound ? sound._loop : false; } } else if (args.length === 2) { loop = args[0]; id = parseInt(args[1], 10); } // If no id is passed, get all ID's to be looped. var ids = self._getSoundIds(id); for (var i=0; i<ids.length; i++) { sound = self._soundById(ids[i]); if (sound) { sound._loop = loop; if (self._webAudio && sound._node && sound._node.bufferSource) { sound._node.bufferSource.loop = loop; if (loop) { sound._node.bufferSource.loopStart = sound._start || 0; sound._node.bufferSource.loopEnd = sound._stop; } } } } return self; }, /** * Get/set the playback rate of a sound. This method can optionally take 0, 1 or 2 arguments. * rate() -> Returns the first sound node's current playback rate. * rate(id) -> Returns the sound id's current playback rate. * rate(rate) -> Sets the playback rate of all sounds in this Howl group. * rate(rate, id) -> Sets the playback rate of passed sound id. * @return {Howl/Number} Returns self or the current playback rate. */ rate: function() { var self = this; var args = arguments; var rate, id; // Determine the values based on arguments. if (args.length === 0) { // We will simply return the current rate of the first node. id = self._sounds[0]._id; } else if (args.length === 1) { // First check if this is an ID, and if not, assume it is a new rate value. var ids = self._getSoundIds(); var index = ids.indexOf(args[0]); if (index >= 0) { id = parseInt(args[0], 10); } else { rate = parseFloat(args[0]); } } else if (args.length === 2) { rate = parseFloat(args[0]); id = parseInt(args[1], 10); } // Update the playback rate or return the current value. var sound; if (typeof rate === 'number') { // If the sound hasn't loaded, add it to the load queue to change playback rate when capable. if (self._state !== 'loaded' || self._playLock) { self._queue.push({ event: 'rate', action: function() { self.rate.apply(self, args); } }); return self; } // Set the group rate. if (typeof id === 'undefined') { self._rate = rate; } // Update one or all volumes. id = self._getSoundIds(id); for (var i=0; i<id.length; i++) { // Get the sound. sound = self._soundById(id[i]); if (sound) { // Keep track of our position when the rate changed and update the playback // start position so we can properly adjust the seek position for time elapsed. if (self.playing(id[i])) { sound._rateSeek = self.seek(id[i]); sound._playStart = self._webAudio ? Howler.ctx.currentTime : sound._playStart; } sound._rate = rate; // Change the playback rate. if (self._webAudio && sound._node && sound._node.bufferSource) { sound._node.bufferSource.playbackRate.setValueAtTime(rate, Howler.ctx.currentTime); } else if (sound._node) { sound._node.playbackRate = rate; } // Reset the timers. var seek = self.seek(id[i]); var duration = ((self._sprite[sound._sprite][0] + self._sprite[sound._sprite][1]) / 1000) - seek; var timeout = (duration * 1000) / Math.abs(sound._rate); // Start a new end timer if sound is already playing. if (self._endTimers[id[i]] || !sound._paused) { self._clearTimer(id[i]); self._endTimers[id[i]] = setTimeout(self._ended.bind(self, sound), timeout); } self._emit('rate', sound._id); } } } else { sound = self._soundById(id); return sound ? sound._rate : self._rate; } return self; }, /** * Get/set the seek position of a sound. This method can optionally take 0, 1 or 2 arguments. * seek() -> Returns the first sound node's current seek position. * seek(id) -> Returns the sound id's current seek position. * seek(seek) -> Sets the seek position of the first sound node. * seek(seek, id) -> Sets the seek position of passed sound id. * @return {Howl/Number} Returns self or the current seek position. */ seek: function() { var self = this; var args = arguments; var seek, id; // Determine the values based on arguments. if (args.length === 0) { // We will simply return the current position of the first node. id = self._sounds[0]._id; } else if (args.length === 1) { // First check if this is an ID, and if not, assume it is a new seek position. var ids = self._getSoundIds(); var index = ids.indexOf(args[0]); if (index >= 0) { id = parseInt(args[0], 10); } else if (self._sounds.length) { id = self._sounds[0]._id; seek = parseFloat(args[0]); } } else if (args.length === 2) { seek = parseFloat(args[0]); id = parseInt(args[1], 10); } // If there is no ID, bail out. if (typeof id === 'undefined') { return self; } // If the sound hasn't loaded, add it to the load queue to seek when capable. if (self._state !== 'loaded' || self._playLock) { self._queue.push({ event: 'seek', action: function() { self.seek.apply(self, args); } }); return self; } // Get the sound. var sound = self._soundById(id); if (sound) { if (typeof seek === 'number' && seek >= 0) { // Pause the sound and update position for restarting playback. var playing = self.playing(id); if (playing) { self.pause(id, true); } // Move the position of the track and cancel timer. sound._seek = seek; sound._ended = false; self._clearTimer(id); // Update the seek position for HTML5 Audio. if (!self._webAudio && sound._node && !isNaN(sound._node.duration)) { sound._node.currentTime = seek; } // Seek and emit when ready. var seekAndEmit = function() { self._emit('seek', id); // Restart the playback if the sound was playing. if (playing) { self.play(id, true); } }; // Wait for the play lock to be unset before emitting (HTML5 Audio). if (playing && !self._webAudio) { var emitSeek = function() { if (!self._playLock) { seekAndEmit(); } else { setTimeout(emitSeek, 0); } }; setTimeout(emitSeek, 0); } else { seekAndEmit(); } } else { if (self._webAudio) { var realTime = self.playing(id) ? Howler.ctx.currentTime - sound._playStart : 0; var rateSeek = sound._rateSeek ? sound._rateSeek - sound._seek : 0; return sound._seek + (rateSeek + realTime * Math.abs(sound._rate)); } else { return sound._node.currentTime; } } } return self; }, /** * Check if a specific sound is currently playing or not (if id is provided), or check if at least one of the sounds in the group is playing or not. * @param {Number} id The sound id to check. If none is passed, the whole sound group is checked. * @return {Boolean} True if playing and false if not. */ playing: function(id) { var self = this; // Check the passed sound ID (if any). if (typeof id === 'number') { var sound = self._soundById(id); return sound ? !sound._paused : false; } // Otherwise, loop through all sounds and check if any are playing. for (var i=0; i<self._sounds.length; i++) { if (!self._sounds[i]._paused) { return true; } } return false; }, /** * Get the duration of this sound. Passing a sound id will return the sprite duration. * @param {Number} id The sound id to check. If none is passed, return full source duration. * @return {Number} Audio duration in seconds. */ duration: function(id) { var self = this; var duration = self._duration; // If we pass an ID, get the sound and return the sprite length. var sound = self._soundById(id); if (sound) { duration = self._sprite[sound._sprite][1] / 1000; } return duration; }, /** * Returns the current loaded state of this Howl. * @return {String} 'unloaded', 'loading', 'loaded' */ state: function() { return this._state; }, /** * Unload and destroy the current Howl object. * This will immediately stop all sound instances attached to this group. */ unload: function() { var self = this; // Stop playing any active sounds. var sounds = self._sounds; for (var i=0; i<sounds.length; i++) { // Stop the sound if it is currently playing. if (!sounds[i]._paused) { self.stop(sounds[i]._id); } // Remove the source or disconnect. if (!self._webAudio) { // Set the source to 0-second silence to stop any downloading (except in IE). self._clearSound(sounds[i]._node); // Remove any event listeners. sounds[i]._node.removeEventListener('error', sounds[i]._errorFn, false); sounds[i]._node.removeEventListener(Howler._canPlayEvent, sounds[i]._loadFn, false); // Release the Audio object back to the pool. Howler._releaseHtml5Audio(sounds[i]._node); } // Empty out all of the nodes. delete sounds[i]._node; // Make sure all timers are cleared out. self._clearTimer(sounds[i]._id); } // Remove the references in the global Howler object. var index = Howler._howls.indexOf(self); if (index >= 0) { Howler._howls.splice(index, 1); } // Delete this sound from the cache (if no other Howl is using it). var remCache = true; for (i=0; i<Howler._howls.length; i++) { if (Howler._howls[i]._src === self._src || self._src.indexOf(Howler._howls[i]._src) >= 0) { remCache = false; break; } } if (cache && remCache) { delete cache[self._src]; } // Clear global errors. Howler.noAudio = false; // Clear out `self`. self._state = 'unloaded'; self._sounds = []; self = null; return null; }, /** * Listen to a custom event. * @param {String} event Event name. * @param {Function} fn Listener to call. * @param {Number} id (optional) Only listen to events for this sound. * @param {Number} once (INTERNAL) Marks event to fire only once. * @return {Howl} */ on: function(event, fn, id, once) { var self = this; var events = self['_on' + event]; if (typeof fn === 'function') { events.push(once ? {id: id, fn: fn, once: once} : {id: id, fn: fn}); } return self; }, /** * Remove a custom event. Call without parameters to remove all events. * @param {String} event Event name. * @param {Function} fn Listener to remove. Leave empty to remove all. * @param {Number} id (optional) Only remove events for this sound. * @return {Howl} */ off: function(event, fn, id) { var self = this; var events = self['_on' + event]; var i = 0; // Allow passing just an event and ID. if (typeof fn === 'number') { id = fn; fn = null; } if (fn || id) { // Loop through event store and remove the passed function. for (i=0; i<events.length; i++) { var isId = (id === events[i].id); if (fn === events[i].fn && isId || !fn && isId) { events.splice(i, 1); break; } } } else if (event) { // Clear out all events of this type. self['_on' + event] = []; } else { // Clear out all events of every type. var keys = Object.keys(self); for (i=0; i<keys.length; i++) { if ((keys[i].indexOf('_on') === 0) && Array.isArray(self[keys[i]])) { self[keys[i]] = []; } } } return self; }, /** * Listen to a custom event and remove it once fired. * @param {String} event Event name. * @param {Function} fn Listener to call. * @param {Number} id (optional) Only listen to events for this sound. * @return {Howl} */ once: function(event, fn, id) { var self = this; // Setup the event listener. self.on(event, fn, id, 1); return self; }, /** * Emit all events of a specific type and pass the sound id. * @param {String} event Event name. * @param {Number} id Sound ID. * @param {Number} msg Message to go with event. * @return {Howl} */ _emit: function(event, id, msg) { var self = this; var events = self['_on' + event]; // Loop through event store and fire all functions. for (var i=events.length-1; i>=0; i--) { // Only fire the listener if the correct ID is used. if (!events[i].id || events[i].id === id || event === 'load') { setTimeout(function(fn) { fn.call(this, id, msg); }.bind(self, events[i].fn), 0); // If this event was setup with `once`, remove it. if (events[i].once) { self.off(event, events[i].fn, events[i].id); } } } // Pass the event type into load queue so that it can continue stepping. self._loadQueue(event); return self; }, /** * Queue of actions initiated before the sound has loaded. * These will be called in sequence, with the next only firing * after the previous has finished executing (even if async like play). * @return {Howl} */ _loadQueue: function(event) { var self = this; if (self._queue.length > 0) { var task = self._queue[0]; // Remove this task if a matching event was passed. if (task.event === event) { self._queue.shift(); self._loadQueue(); } // Run the task if no event type is passed. if (!event) { task.action(); } } return self; }, /** * Fired when playback ends at the end of the duration. * @param {Sound} sound The sound object to work with. * @return {Howl} */ _ended: function(sound) { var self = this; var sprite = sound._sprite; // If we are using IE and there was network latency we may be clipping // audio before it completes playing. Lets check the node to make sure it // believes it has completed, before ending the playback. if (!self._webAudio && sound._node && !sound._node.paused && !sound._node.ended && sound._node.currentTime < sound._stop) { setTimeout(self._ended.bind(self, sound), 100); return self; } // Should this sound loop? var loop = !!(sound._loop || self._sprite[sprite][2]); // Fire the ended event. self._emit('end', sound._id); // Restart the playback for HTML5 Audio loop. if (!self._webAudio && loop) { self.stop(sound._id, true).play(sound._id); } // Restart this timer if on a Web Audio loop. if (self._webAudio && loop) { self._emit('play', sound._id); sound._seek = sound._start || 0; sound._rateSeek = 0; sound._playStart = Howler.ctx.currentTime; var timeout = ((sound._stop - sound._start) * 1000) / Math.abs(sound._rate); self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout); } // Mark the node as paused. if (self._webAudio && !loop) { sound._paused = true; sound._ended = true; sound._seek = sound._start || 0; sound._rateSeek = 0; self._clearTimer(sound._id); // Clean up the buffer source. self._cleanBuffer(sound._node); // Attempt to auto-suspend AudioContext if no sounds are still playing. Howler._autoSuspend(); } // When using a sprite, end the track. if (!self._webAudio && !loop) { self.stop(sound._id, true); } return self; }, /** * Clear the end timer for a sound playback. * @param {Number} id The sound ID. * @return {Howl} */ _clearTimer: function(id) { var self = this; if (self._endTimers[id]) { // Clear the timeout or remove the ended listener. if (typeof self._endTimers[id] !== 'function') { clearTimeout(self._endTimers[id]); } else { var sound = self._soundById(id); if (sound && sound._node) { sound._node.removeEventListener('ended', self._endTimers[id], false); } } delete self._endTimers[id]; } return self; }, /** * Return the sound identified by this ID, or return null. * @param {Number} id Sound ID * @return {Object} Sound object or null. */ _soundById: function(id) { var self = this; // Loop through all sounds and find the one with this ID. for (var i=0; i<self._sounds.length; i++) { if (id === self._sounds[i]._id) { return self._sounds[i]; } } return null; }, /** * Return an inactive sound from the pool or create a new one. * @return {Sound} Sound playback object. */ _inactiveSound: function() { var self = this; self._drain(); // Find the first inactive node to recycle. for (var i=0; i<self._sounds.length; i++) { if (self._sounds[i]._ended) { return self._sounds[i].reset(); } } // If no inactive node was found, create a new one. return new Sound(self); }, /** * Drain excess inactive sounds from the pool. */ _drain: function() { var self = this; var limit = self._pool; var cnt = 0; var i = 0; // If there are less sounds than the max pool size, we are done. if (self._sounds.length < limit) { return; } // Count the number of inactive sounds. for (i=0; i<self._sounds.length; i++) { if (self._sounds[i]._ended) { cnt++; } } // Remove excess inactive sounds, going in reverse order. for (i=self._sounds.length - 1; i>=0; i--) { if (cnt <= limit) { return; } if (self._sounds[i]._ended) { // Disconnect the audio source when using Web Audio. if (self._webAudio && self._sounds[i]._node) { self._sounds[i]._node.disconnect(0); } // Remove sounds until we have the pool size. self._sounds.splice(i, 1); cnt--; } } }, /** * Get all ID's from the sounds pool. * @param {Number} id Only return one ID if one is passed. * @return {Array} Array of IDs. */ _getSoundIds: function(id) { var self = this; if (typeof id === 'undefined') { var ids = []; for (var i=0; i<self._sounds.length; i++) { ids.push(self._sounds[i]._id); } return ids; } else { return [id]; } }, /** * Load the sound back into the buffer source. * @param {Sound} sound The sound object to work with. * @return {Howl} */ _refreshBuffer: function(sound) { var self = this; // Setup the buffer source for playback. sound._node.bufferSource = Howler.ctx.createBufferSource(); sound._node.bufferSource.buffer = cache[self._src]; // Connect to the correct node. if (sound._panner) { sound._node.bufferSource.connect(sound._panner); } else { sound._node.bufferSource.connect(sound._node); } // Setup looping and playback rate. sound._node.bufferSource.loop = sound._loop; if (sound._loop) { sound._node.bufferSource.loopStart = sound._start || 0; sound._node.bufferSource.loopEnd = sound._stop || 0; } sound._node.bufferSource.playbackRate.setValueAtTime(sound._rate, Howler.ctx.currentTime); return self; }, /** * Prevent memory leaks by cleaning up the buffer source after playback. * @param {Object} node Sound's audio node containing the buffer source. * @return {Howl} */ _cleanBuffer: function(node) { var self = this; var isIOS = Howler._navigator && Howler._navigator.vendor.indexOf('Apple') >= 0; if (Howler._scratchBuffer && node.bufferSource) { node.bufferSource.onended = null; node.bufferSource.disconnect(0); if (isIOS) { try { node.bufferSource.buffer = Howler._scratchBuffer; } catch(e) {} } } node.bufferSource = null; return self; }, /** * Set the source to a 0-second silence to stop any downloading (except in IE). * @param {Object} node Audio node to clear. */ _clearSound: function(node) { var checkIE = /MSIE |Trident\//.test(Howler._navigator && Howler._navigator.userAgent); if (!checkIE) { node.src = 'data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA'; } } }; /** Single Sound Methods **/ /***************************************************************************/ /** * Setup the sound object, which each node attached to a Howl group is contained in. * @param {Object} howl The Howl parent group. */ var Sound = function(howl) { this._parent = howl; this.init(); }; Sound.prototype = { /** * Initialize a new Sound object. * @return {Sound} */ init: function() { var self = this; var parent = self._parent; // Setup the default parameters. self._muted = parent._muted; self._loop = parent._loop; self._volume = parent._volume; self._rate = parent._rate; self._seek = 0; self._paused = true; self._ended = true; self._sprite = '__default'; // Generate a unique ID for this sound. self._id = ++Howler._counter; // Add itself to the parent's pool. parent._sounds.push(self); // Create the new node. self.create(); return self; }, /** * Create and setup a new sound object, whether HTML5 Audio or Web Audio. * @return {Sound} */ create: function() { var self = this; var parent = self._parent; var volume = (Howler._muted || self._muted || self._parent._muted) ? 0 : self._volume; if (parent._webAudio) { // Create the gain node for controlling volume (the source will connect to this). self._node = (typeof Howler.ctx.createGain === 'undefined') ? Howler.ctx.createGainNode() : Howler.ctx.createGain(); self._node.gain.setValueAtTime(volume, Howler.ctx.currentTime); self._node.paused = true; self._node.connect(Howler.masterGain); } else if (!Howler.noAudio) { // Get an unlocked Audio object from the pool. self._node = Howler._obtainHtml5Audio(); // Listen for errors (http://dev.w3.org/html5/spec-author-view/spec.html#mediaerror). self._errorFn = self._errorListener.bind(self); self._node.addEventListener('error', self._errorFn, false); // Listen for 'canplaythrough' event to let us know the sound is ready. self._loadFn = self._loadListener.bind(self); self._node.addEventListener(Howler._canPlayEvent, self._loadFn, false); // Setup the new audio node. self._node.src = parent._src; self._node.preload = parent._preload === true ? 'auto' : parent._preload; self._node.volume = volume * Howler.volume(); // Begin loading the source. self._node.load(); } return self; }, /** * Reset the parameters of this sound to the original state (for recycle). * @return {Sound} */ reset: function() { var self = this; var parent = self._parent; // Reset all of the parameters of this sound. self._muted = parent._muted; self._loop = parent._loop; self._volume = parent._volume; self._rate = parent._rate; self._seek = 0; self._rateSeek = 0; self._paused = true; self._ended = true; self._sprite = '__default'; // Generate a new ID so that it isn't confused with the previous sound. self._id = ++Howler._counter; return self; }, /** * HTML5 Audio error listener callback. */ _errorListener: function() { var self = this; // Fire an error event and pass back the code. self._parent._emit('loaderror', self._id, self._node.error ? self._node.error.code : 0); // Clear the event listener. self._node.removeEventListener('error', self._errorFn, false); }, /** * HTML5 Audio canplaythrough listener callback. */ _loadListener: function() { var self = this; var parent = self._parent; // Round up the duration to account for the lower precision in HTML5 Audio. parent._duration = Math.ceil(self._node.duration * 10) / 10; // Setup a sprite if none is defined. if (Object.keys(parent._sprite).length === 0) { parent._sprite = {__default: [0, parent._duration * 1000]}; } if (parent._state !== 'loaded') { parent._state = 'loaded'; parent._emit('load'); parent._loadQueue(); } // Clear the event listener. self._node.removeEventListener(Howler._canPlayEvent, self._loadFn, false); } }; /** Helper Methods **/ /***************************************************************************/ var cache = {}; /** * Buffer a sound from URL, Data URI or cache and decode to audio source (Web Audio API). * @param {Howl} self */ var loadBuffer = function(self) { var url = self._src; // Check if the buffer has already been cached and use it instead. if (cache[url]) { // Set the duration from the cache. self._duration = cache[url].duration; // Load the sound into this Howl. loadSound(self); return; } if (/^data:[^;]+;base64,/.test(url)) { // Decode the base64 data URI without XHR, since some browsers don't support it. var data = atob(url.split(',')[1]); var dataView = new Uint8Array(data.length); for (var i=0; i<data.length; ++i) { dataView[i] = data.charCodeAt(i); } decodeAudioData(dataView.buffer, self); } else { // Load the buffer from the URL. var xhr = new XMLHttpRequest(); xhr.open(self._xhr.method, url, true); xhr.withCredentials = self._xhr.withCredentials; xhr.responseType = 'arraybuffer'; // Apply any custom headers to the request. if (self._xhr.headers) { Object.keys(self._xhr.headers).forEach(function(key) { xhr.setRequestHeader(key, self._xhr.headers[key]); }); } xhr.onload = function() { // Make sure we get a successful response back. var code = (xhr.status + '')[0]; if (code !== '0' && code !== '2' && code !== '3') { self._emit('loaderror', null, 'Failed loading audio file with status: ' + xhr.status + '.'); return; } decodeAudioData(xhr.response, self); }; xhr.onerror = function() { // If there is an error, switch to HTML5 Audio. if (self._webAudio) { self._html5 = true; self._webAudio = false; self._sounds = []; delete cache[url]; self.load(); } }; safeXhrSend(xhr); } }; /** * Send the XHR request wrapped in a try/catch. * @param {Object} xhr XHR to send. */ var safeXhrSend = function(xhr) { try { xhr.send(); } catch (e) { xhr.onerror(); } }; /** * Decode audio data from an array buffer. * @param {ArrayBuffer} arraybuffer The audio data. * @param {Howl} self */ var decodeAudioData = function(arraybuffer, self) { // Fire a load error if something broke. var error = function() { self._emit('loaderror', null, 'Decoding audio data failed.'); }; // Load the sound on success. var success = function(buffer) { if (buffer && self._sounds.length > 0) { cache[self._src] = buffer; loadSound(self, buffer); } else { error(); } }; // Decode the buffer into an audio source. if (typeof Promise !== 'undefined' && Howler.ctx.decodeAudioData.length === 1) { Howler.ctx.decodeAudioData(arraybuffer).then(success).catch(error); } else { Howler.ctx.decodeAudioData(arraybuffer, success, error); } } /** * Sound is now loaded, so finish setting everything up and fire the loaded event. * @param {Howl} self * @param {Object} buffer The decoded buffer sound source. */ var loadSound = function(self, buffer) { // Set the duration. if (buffer && !self._duration) { self._duration = buffer.duration; } // Setup a sprite if none is defined. if (Object.keys(self._sprite).length === 0) { self._sprite = {__default: [0, self._duration * 1000]}; } // Fire the loaded event. if (self._state !== 'loaded') { self._state = 'loaded'; self._emit('load'); self._loadQueue(); } }; /** * Setup the audio context when available, or switch to HTML5 Audio mode. */ var setupAudioContext = function() { // If we have already detected that Web Audio isn't supported, don't run this step again. if (!Howler.usingWebAudio) { return; } // Check if we are using Web Audio and setup the AudioContext if we are. try { if (typeof AudioContext !== 'undefined') { Howler.ctx = new AudioContext(); } else if (typeof webkitAudioContext !== 'undefined') { Howler.ctx = new webkitAudioContext(); } else { Howler.usingWebAudio = false; } } catch(e) { Howler.usingWebAudio = false; } // If the audio context creation still failed, set using web audio to false. if (!Howler.ctx) { Howler.usingWebAudio = false; } // Check if a webview is being used on iOS8 or earlier (rather than the browser). // If it is, disable Web Audio as it causes crashing. var iOS = (/iP(hone|od|ad)/.test(Howler._navigator && Howler._navigator.platform)); var appVersion = Howler._navigator && Howler._navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/); var version = appVersion ? parseInt(appVersion[1], 10) : null; if (iOS && version && version < 9) { var safari = /safari/.test(Howler._navigator && Howler._navigator.userAgent.toLowerCase()); if (Howler._navigator && !safari) { Howler.usingWebAudio = false; } } // Create and expose the master GainNode when using Web Audio (useful for plugins or advanced usage). if (Howler.usingWebAudio) { Howler.masterGain = (typeof Howler.ctx.createGain === 'undefined') ? Howler.ctx.createGainNode() : Howler.ctx.createGain(); Howler.masterGain.gain.setValueAtTime(Howler._muted ? 0 : Howler._volume, Howler.ctx.currentTime); Howler.masterGain.connect(Howler.ctx.destination); } // Re-run the setup on Howler. Howler._setup(); }; // Add support for AMD (Asynchronous Module Definition) libraries such as require.js. if (typeof define === 'function' && define.amd) { define([], function() { return { Howler: Howler, Howl: Howl }; }); } // Add support for CommonJS libraries such as browserify. if (typeof exports !== 'undefined') { exports.Howler = Howler; exports.Howl = Howl; } // Add to global in Node.js (for testing, etc). if (typeof global !== 'undefined') { global.HowlerGlobal = HowlerGlobal; global.Howler = Howler; global.Howl = Howl; global.Sound = Sound; } else if (typeof window !== 'undefined') { // Define globally in case AMD is not available or unused. window.HowlerGlobal = HowlerGlobal; window.Howler = Howler; window.Howl = Howl; window.Sound = Sound; } })();
| ver. 1.4 |
Github
|
.
| PHP 8.2.29 | Генераци� �траницы: 0 |
proxy
|
phpinfo
|
�а�тройка