/** * @module SoundJS */ this.createjs = this.createjs || {}; (function () { /** * Static class holding library specific information such as the version and buildDate of the library. * The SoundJS class has been renamed {{#crossLink "Sound"}}{{/crossLink}}. Please see {{#crossLink "Sound"}}{{/crossLink}} * for information on using sound. * @class SoundJS **/ var s = createjs.SoundJS = createjs.SoundJS || {}; /** * The version string for this release. * @property version * @type String * @static **/ s.version = /*version*/"NEXT"; // injected by build process /** * The build date for this release in UTC format. * @property buildDate * @type String * @static **/ s.buildDate = /*date*/"Wed, 27 Nov 2013 19:49:18 GMT"; // injected by build process })(); /* * EventDispatcher * Visit http://createjs.com/ for documentation, updates and examples. * * Copyright (c) 2010 gskinner.com, inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** * @module CreateJS */ // namespace: this.createjs = this.createjs||{}; (function() { "use strict"; /** * EventDispatcher provides methods for managing queues of event listeners and dispatching events. * * You can either extend EventDispatcher or mix its methods into an existing prototype or instance by using the * EventDispatcher {{#crossLink "EventDispatcher/initialize"}}{{/crossLink}} method. * * Together with the CreateJS Event class, EventDispatcher provides an extended event model that is based on the * DOM Level 2 event model, including addEventListener, removeEventListener, and dispatchEvent. It supports * bubbling / capture, preventDefault, stopPropagation, stopImmediatePropagation, and handleEvent. * * EventDispatcher also exposes a {{#crossLink "EventDispatcher/on"}}{{/crossLink}} method, which makes it easier * to create scoped listeners, listeners that only run once, and listeners with associated arbitrary data. The * {{#crossLink "EventDispatcher/off"}}{{/crossLink}} method is merely an alias to * {{#crossLink "EventDispatcher/removeEventListener"}}{{/crossLink}}. * * Another addition to the DOM Level 2 model is the {{#crossLink "EventDispatcher/removeAllEventListeners"}}{{/crossLink}} * method, which can be used to listeners for all events, or listeners for a specific event. The Event object also * includes a {{#crossLink "Event/remove"}}{{/crossLink}} method which removes the active listener. * *

Example

* Add EventDispatcher capabilities to the "MyClass" class. * * EventDispatcher.initialize(MyClass.prototype); * * Add an event (see {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}}). * * instance.addEventListener("eventName", handlerMethod); * function handlerMethod(event) { * console.log(event.target + " Was Clicked"); * } * * Maintaining proper scope
* Scope (ie. "this") can be be a challenge with events. Using the {{#crossLink "EventDispatcher/on"}}{{/crossLink}} * method to subscribe to events simplifies this. * * instance.addEventListener("click", function(event) { * console.log(instance == this); // false, scope is ambiguous. * }); * * instance.on("click", function(event) { * console.log(instance == this); // true, "on" uses dispatcher scope by default. * }); * * If you want to use addEventListener instead, you may want to use function.bind() or a similar proxy to manage scope. * * * @class EventDispatcher * @constructor **/ var EventDispatcher = function() { /* this.initialize(); */ // not needed. }; var p = EventDispatcher.prototype; /** * Static initializer to mix EventDispatcher methods into a target object or prototype. * * EventDispatcher.initialize(MyClass.prototype); // add to the prototype of the class * EventDispatcher.initialize(myObject); // add to a specific instance * * @method initialize * @static * @param {Object} target The target object to inject EventDispatcher methods into. This can be an instance or a * prototype. **/ EventDispatcher.initialize = function(target) { target.addEventListener = p.addEventListener; target.on = p.on; target.removeEventListener = target.off = p.removeEventListener; target.removeAllEventListeners = p.removeAllEventListeners; target.hasEventListener = p.hasEventListener; target.dispatchEvent = p.dispatchEvent; target._dispatchEvent = p._dispatchEvent; }; // constructor: // private properties: /** * @protected * @property _listeners * @type Object **/ p._listeners = null; /** * @protected * @property _captureListeners * @type Object **/ p._captureListeners = null; // constructor: /** * Initialization method. * @method initialize * @protected **/ p.initialize = function() {}; // public methods: /** * Adds the specified event listener. Note that adding multiple listeners to the same function will result in * multiple callbacks getting fired. * *

Example

* * displayObject.addEventListener("click", handleClick); * function handleClick(event) { * // Click happened. * } * * @method addEventListener * @param {String} type The string type of the event. * @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when * the event is dispatched. * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. * @return {Function | Object} Returns the listener for chaining or assignment. **/ p.addEventListener = function(type, listener, useCapture) { var listeners; if (useCapture) { listeners = this._captureListeners = this._captureListeners||{}; } else { listeners = this._listeners = this._listeners||{}; } var arr = listeners[type]; if (arr) { this.removeEventListener(type, listener, useCapture); } arr = listeners[type]; // remove may have deleted the array if (!arr) { listeners[type] = [listener]; } else { arr.push(listener); } return listener; }; /** * A shortcut method for using addEventListener that makes it easier to specify an execution scope, have a listener * only run once, associate arbitrary data with the listener, and remove the listener. * * This method works by creating an anonymous wrapper function and subscribing it with addEventListener. * The created anonymous function is returned for use with .removeEventListener (or .off). * *

Example

* * var listener = myBtn.on("click", handleClick, null, false, {count:3}); * function handleClick(evt, data) { * data.count -= 1; * console.log(this == myBtn); // true - scope defaults to the dispatcher * if (data.count == 0) { * alert("clicked 3 times!"); * myBtn.off("click", listener); * // alternately: evt.remove(); * } * } * * @method on * @param {String} type The string type of the event. * @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when * the event is dispatched. * @param {Object} [scope] The scope to execute the listener in. Defaults to the dispatcher/currentTarget for function listeners, and to the listener itself for object listeners (ie. using handleEvent). * @param {Boolean} [once=false] If true, the listener will remove itself after the first time it is triggered. * @param {*} [data] Arbitrary data that will be included as the second parameter when the listener is called. * @param {Boolean} [useCapture=false] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. * @return {Function} Returns the anonymous function that was created and assigned as the listener. This is needed to remove the listener later using .removeEventListener. **/ p.on = function(type, listener, scope, once, data, useCapture) { if (listener.handleEvent) { scope = scope||listener; listener = listener.handleEvent; } scope = scope||this; return this.addEventListener(type, function(evt) { listener.call(scope, evt, data); once&&evt.remove(); }, useCapture); }; /** * Removes the specified event listener. * * Important Note: that you must pass the exact function reference used when the event was added. If a proxy * function, or function closure is used as the callback, the proxy/closure reference must be used - a new proxy or * closure will not work. * *

Example

* * displayObject.removeEventListener("click", handleClick); * * @method removeEventListener * @param {String} type The string type of the event. * @param {Function | Object} listener The listener function or object. * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase. **/ p.removeEventListener = function(type, listener, useCapture) { var listeners = useCapture ? this._captureListeners : this._listeners; if (!listeners) { return; } var arr = listeners[type]; if (!arr) { return; } for (var i=0,l=arr.length; iExample * * // Remove all listeners * displayObject.removeAllEventListeners(); * * // Remove all click listeners * displayObject.removeAllEventListeners("click"); * * @method removeAllEventListeners * @param {String} [type] The string type of the event. If omitted, all listeners for all types will be removed. **/ p.removeAllEventListeners = function(type) { if (!type) { this._listeners = this._captureListeners = null; } else { if (this._listeners) { delete(this._listeners[type]); } if (this._captureListeners) { delete(this._captureListeners[type]); } } }; /** * Dispatches the specified event to all listeners. * *

Example

* * // Use a string event * this.dispatchEvent("complete"); * * // Use an Event instance * var event = new createjs.Event("progress"); * this.dispatchEvent(event); * * @method dispatchEvent * @param {Object | String | Event} eventObj An object with a "type" property, or a string type. * While a generic object will work, it is recommended to use a CreateJS Event instance. If a string is used, * dispatchEvent will construct an Event instance with the specified type. * @param {Object} [target] The object to use as the target property of the event object. This will default to the * dispatching object. This parameter is deprecated and will be removed. * @return {Boolean} Returns the value of eventObj.defaultPrevented. **/ p.dispatchEvent = function(eventObj, target) { if (typeof eventObj == "string") { // won't bubble, so skip everything if there's no listeners: var listeners = this._listeners; if (!listeners || !listeners[eventObj]) { return false; } eventObj = new createjs.Event(eventObj); } // TODO: deprecated. Target param is deprecated, only use case is MouseEvent/mousemove, remove. eventObj.target = target||this; if (!eventObj.bubbles || !this.parent) { this._dispatchEvent(eventObj, 2); } else { var top=this, list=[top]; while (top.parent) { list.push(top = top.parent); } var i, l=list.length; // capture & atTarget for (i=l-1; i>=0 && !eventObj.propagationStopped; i--) { list[i]._dispatchEvent(eventObj, 1+(i==0)); } // bubbling for (i=1; iExample * myObject.addEventListener("change", createjs.proxy(myMethod, scope)); * * @module CreateJS * @main CreateJS */ // namespace: this.createjs = this.createjs||{}; (function() { "use strict"; /** * Contains properties and methods shared by all events for use with * {{#crossLink "EventDispatcher"}}{{/crossLink}}. * * Note that Event objects are often reused, so you should never * rely on an event object's state outside of the call stack it was received in. * @class Event * @param {String} type The event type. * @param {Boolean} bubbles Indicates whether the event will bubble through the display list. * @param {Boolean} cancelable Indicates whether the default behaviour of this event can be cancelled. * @constructor **/ var Event = function(type, bubbles, cancelable) { this.initialize(type, bubbles, cancelable); }; var p = Event.prototype; // events: // public properties: /** * The type of event. * @property type * @type String **/ p.type = null; /** * The object that generated an event. * @property target * @type Object * @default null * @readonly */ p.target = null; /** * The current target that a bubbling event is being dispatched from. For non-bubbling events, this will * always be the same as target. For example, if childObj.parent = parentObj, and a bubbling event * is generated from childObj, then a listener on parentObj would receive the event with * target=childObj (the original target) and currentTarget=parentObj (where the listener was added). * @property currentTarget * @type Object * @default null * @readonly */ p.currentTarget = null; /** * For bubbling events, this indicates the current event phase:
    *
  1. capture phase: starting from the top parent to the target
  2. *
  3. at target phase: currently being dispatched from the target
  4. *
  5. bubbling phase: from the target to the top parent
  6. *
* @property eventPhase * @type Number * @default 0 * @readonly */ p.eventPhase = 0; /** * Indicates whether the event will bubble through the display list. * @property bubbles * @type Boolean * @default false * @readonly */ p.bubbles = false; /** * Indicates whether the default behaviour of this event can be cancelled via * {{#crossLink "Event/preventDefault"}}{{/crossLink}}. This is set via the Event constructor. * @property cancelable * @type Boolean * @default false * @readonly */ p.cancelable = false; /** * The epoch time at which this event was created. * @property timeStamp * @type Number * @default 0 * @readonly */ p.timeStamp = 0; /** * Indicates if {{#crossLink "Event/preventDefault"}}{{/crossLink}} has been called * on this event. * @property defaultPrevented * @type Boolean * @default false * @readonly */ p.defaultPrevented = false; /** * Indicates if {{#crossLink "Event/stopPropagation"}}{{/crossLink}} or * {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called on this event. * @property propagationStopped * @type Boolean * @default false * @readonly */ p.propagationStopped = false; /** * Indicates if {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called * on this event. * @property immediatePropagationStopped * @type Boolean * @default false * @readonly */ p.immediatePropagationStopped = false; /** * Indicates if {{#crossLink "Event/remove"}}{{/crossLink}} has been called on this event. * @property removed * @type Boolean * @default false * @readonly */ p.removed = false; // constructor: /** * Initialization method. * @method initialize * @param {String} type The event type. * @param {Boolean} bubbles Indicates whether the event will bubble through the display list. * @param {Boolean} cancelable Indicates whether the default behaviour of this event can be cancelled. * @protected **/ p.initialize = function(type, bubbles, cancelable) { this.type = type; this.bubbles = bubbles; this.cancelable = cancelable; this.timeStamp = (new Date()).getTime(); }; // public methods: /** * Sets {{#crossLink "Event/defaultPrevented"}}{{/crossLink}} to true. * Mirrors the DOM event standard. * @method preventDefault **/ p.preventDefault = function() { this.defaultPrevented = true; }; /** * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} to true. * Mirrors the DOM event standard. * @method stopPropagation **/ p.stopPropagation = function() { this.propagationStopped = true; }; /** * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} and * {{#crossLink "Event/immediatePropagationStopped"}}{{/crossLink}} to true. * Mirrors the DOM event standard. * @method stopImmediatePropagation **/ p.stopImmediatePropagation = function() { this.immediatePropagationStopped = this.propagationStopped = true; }; /** * Causes the active listener to be removed via removeEventListener(); * * myBtn.addEventListener("click", function(evt) { * // do stuff... * evt.remove(); // removes this listener. * }); * * @method remove **/ p.remove = function() { this.removed = true; }; /** * Returns a clone of the Event instance. * @method clone * @return {Event} a clone of the Event instance. **/ p.clone = function() { return new Event(this.type, this.bubbles, this.cancelable); }; /** * Returns a string representation of this object. * @method toString * @return {String} a string representation of the instance. **/ p.toString = function() { return "[Event (type="+this.type+")]"; }; createjs.Event = Event; }()); /* * IndexOf * Visit http://createjs.com/ for documentation, updates and examples. * * Copyright (c) 2010 gskinner.com, inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** * @module CreateJS */ // namespace: this.createjs = this.createjs||{}; /** * @class Utility Methods */ (function() { "use strict"; /* * Employs Duff's Device to make a more performant implementation of indexOf. * see http://jsperf.com/duffs-indexof/2 * #method indexOf * @param {Array} array Array to search for searchElement * @param searchElement Element to search array for. * @return {Number} The position of the first occurrence of a specified value searchElement in the passed in array ar. * @constructor */ /* replaced with simple for loop for now, perhaps will be researched further createjs.indexOf = function (ar, searchElement) { var l = ar.length; var n = (l * 0.125) ^ 0; // 0.125 == 1/8, using multiplication because it's faster in some browsers // ^0 floors result for (var i = 0; i < n; i++) { if(searchElement === ar[i*8]) { return (i*8);} if(searchElement === ar[i*8+1]) { return (i*8+1);} if(searchElement === ar[i*8+2]) { return (i*8+2);} if(searchElement === ar[i*8+3]) { return (i*8+3);} if(searchElement === ar[i*8+4]) { return (i*8+4);} if(searchElement === ar[i*8+5]) { return (i*8+5);} if(searchElement === ar[i*8+6]) { return (i*8+6);} if(searchElement === ar[i*8+7]) { return (i*8+7);} } var n = l % 8; for (var i = 0; i < n; i++) { if (searchElement === ar[l-n+i]) { return l-n+i; } } return -1; } */ /** * Finds the first occurrence of a specified value searchElement in the passed in array, and returns the index of * that value. Returns -1 if value is not found. * * var i = createjs.indexOf(myArray, myElementToFind); * * @method indexOf * @param {Array} array Array to search for searchElement * @param searchElement Element to find in array. * @return {Number} The first index of searchElement in array. */ createjs.indexOf = function (array, searchElement){ for (var i = 0,l=array.length; i < l; i++) { if (searchElement === array[i]) { return i; } } return -1; } }());/* * Proxy * Visit http://createjs.com/ for documentation, updates and examples. * * Copyright (c) 2010 gskinner.com, inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ /** * @module CreateJS */ // namespace: this.createjs = this.createjs||{}; /** * Various utilities that the CreateJS Suite uses. Utilities are created as separate files, and will be available on the * createjs namespace directly: * *

Example

* myObject.addEventListener("change", createjs.proxy(myMethod, scope)); * * @class Utility Methods * @main Utility Methods */ (function() { "use strict"; /** * A function proxy for methods. By default, JavaScript methods do not maintain scope, so passing a method as a * callback will result in the method getting called in the scope of the caller. Using a proxy ensures that the * method gets called in the correct scope. * * Additional arguments can be passed that will be applied to the function when it is called. * *

Example

* myObject.addEventListener("event", createjs.proxy(myHandler, this, arg1, arg2)); * * function myHandler(arg1, arg2) { * // This gets called when myObject.myCallback is executed. * } * * @method proxy * @param {Function} method The function to call * @param {Object} scope The scope to call the method name on * @param {mixed} [arg] * Arguments that are appended to the callback for additional params. * @public * @static */ createjs.proxy = function (method, scope) { var aArgs = Array.prototype.slice.call(arguments, 2); return function () { return method.apply(scope, Array.prototype.slice.call(arguments, 0).concat(aArgs)); }; } }());/* * Sound * Visit http://createjs.com/ for documentation, updates and examples. * * * Copyright (c) 2012 gskinner.com, inc. * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ // namespace: this.createjs = this.createjs || {}; /** * The SoundJS library manages the playback of audio on the web. It works via plugins which abstract the actual audio * implementation, so playback is possible on any platform without specific knowledge of what mechanisms are necessary * to play sounds. * * To use SoundJS, use the public API on the {{#crossLink "Sound"}}{{/crossLink}} class. This API is for: * * * Please note that as of version 0.4.0, the "SoundJS" object only provides version information. All APIs from * SoundJS are now available on the {{#crossLink "Sound"}}{{/crossLink}} class. * * Controlling Sounds
* Playing sounds creates {{#crossLink "SoundInstance"}}{{/crossLink}} instances, which can be controlled individually. * * *

Feature Set Example

* createjs.Sound.alternateExtensions = ["mp3"]; * createjs.Sound.addEventListener("fileload", createjs.proxy(this.loadHandler, this)); * createjs.Sound.registerSound("path/to/mySound.ogg", "sound"); * function loadHandler(event) { * // This is fired for each sound that is registered. * var instance = createjs.Sound.play("sound"); // play using id. Could also use full sourcepath or event.src. * instance.addEventListener("complete", createjs.proxy(this.handleComplete, this)); * instance.volume = 0.5; * } * *

Browser Support

* Audio will work in browsers which support HTMLAudioElement (http://caniuse.com/audio) * or WebAudio (http://caniuse.com/audio-api). A Flash fallback can be added * as well, which will work in any browser that supports the Flash player. * @module SoundJS * @main SoundJS */ (function () { "use strict"; //TODO: Interface to validate plugins and throw warnings //TODO: Determine if methods exist on a plugin before calling // OJR this is only an issue if something breaks or user changes something //TODO: Interface to validate instances and throw warnings //TODO: Surface errors on audio from all plugins //TODO: Timeouts // OJR for? /** * The Sound class is the public API for creating sounds, controlling the overall sound levels, and managing plugins. * All Sound APIs on this class are static. * * Registering and Preloading
* Before you can play a sound, it must be registered. You can do this with {{#crossLink "Sound/registerSound"}}{{/crossLink}}, * or register multiple sounds using {{#crossLink "Sound/registerManifest"}}{{/crossLink}}. If you don't register a * sound prior to attempting to play it using {{#crossLink "Sound/play"}}{{/crossLink}} or create it using {{#crossLink "Sound/createInstance"}}{{/crossLink}}, * the sound source will be automatically registered but playback will fail as the source will not be ready. If you use * PreloadJS, this is handled for you when the sound is * preloaded. It is recommended to preload sounds either internally using the register functions or externally using * PreloadJS so they are ready when you want to use them. * * Playback
* To play a sound once it's been registered and preloaded, use the {{#crossLink "Sound/play"}}{{/crossLink}} method. * This method returns a {{#crossLink "SoundInstance"}}{{/crossLink}} which can be paused, resumed, muted, etc. * Please see the {{#crossLink "SoundInstance"}}{{/crossLink}} documentation for more on the instance control APIs. * * Plugins
* By default, the {{#crossLink "WebAudioPlugin"}}{{/crossLink}} or the {{#crossLink "HTMLAudioPlugin"}}{{/crossLink}} * are used (when available), although developers can change plugin priority or add new plugins (such as the * provided {{#crossLink "FlashPlugin"}}{{/crossLink}}). Please see the {{#crossLink "Sound"}}{{/crossLink}} API * methods for more on the playback and plugin APIs. To install plugins, or specify a different plugin order, see * {{#crossLink "Sound/installPlugins"}}{{/crossLink}}. * *

Example

* createjs.Sound.registerPlugins([createjs.WebAudioPlugin, createjs.FlashPlugin]); * createjs.Sound.alternateExtensions = ["mp3"]; * createjs.Sound.addEventListener("fileload", createjs.proxy(this.loadHandler, (this)); * createjs.Sound.registerSound("path/to/mySound.ogg", "sound"); * function loadHandler(event) { * // This is fired for each sound that is registered. * var instance = createjs.Sound.play("sound"); // play using id. Could also use full source path or event.src. * instance.addEventListener("complete", createjs.proxy(this.handleComplete, this)); * instance.volume = 0.5; * } * * The maximum number of concurrently playing instances of the same sound can be specified in the "data" argument * of {{#crossLink "Sound/registerSound"}}{{/crossLink}}. Note that if not specified, the active plugin will apply * a default limit. Currently HTMLAudioPlugin sets a default limit of 2, while WebAudioPlugin and FlashPlugin set a * default limit of 100. * * createjs.Sound.registerSound("sound.mp3", "soundId", 4); * * Sound can be used as a plugin with PreloadJS to help preload audio properly. Audio preloaded with PreloadJS is * automatically registered with the Sound class. When audio is not preloaded, Sound will do an automatic internal * load. As a result, it may not play immediately the first time play is called. Use the * {{#crossLink "Sound/fileload"}}{{/crossLink}} event to determine when a sound has finished internally preloading. * It is recommended that all audio is preloaded before it is played. * * createjs.PreloadJS.installPlugin(createjs.Sound); * * Mobile Safe Approach
* Mobile devices require sounds to be played inside of a user initiated event (touch/click) in varying degrees. * As of SoundJS 0.4.1, you can launch a site inside of a user initiated event and have audio playback work. To * enable as broadly as possible, the site needs to setup the Sound plugin in its initialization (for example via * createjs.Sound.initializeDefaultPlugins();), and all sounds need to be played in the scope of the * application. See the MobileSafe demo for a working example. * *

Example

* document.getElementById("status").addEventListener("click", handleTouch, false); // works on Android and iPad * function handleTouch(event) { * document.getElementById("status").removeEventListener("click", handleTouch, false); // remove the listener * var thisApp = new myNameSpace.MyApp(); // launch the app * } * *

Known Browser and OS issues

* IE 9 HTML Audio limitations
* * * Firefox 25 Web Audio limitations * * Safari limitations
* * * iOS 6 Web Audio limitations
* * * Android HTML Audio limitations
* * * * @class Sound * @static * @uses EventDispatcher */ function Sound() { throw "Sound cannot be instantiated"; } var s = Sound; /** * This approach has is being replaced by {{#crossLink "Sound/alternateExtensions:property"}}{{/crossLink}}, and * support will be removed in the next version. * The character (or characters) that are used to split multiple paths from an audio source. * @property DELIMITER * @type {String} * @default | * @static * @deprecated */ s.DELIMITER = "|"; /** * The duration in milliseconds to determine a timeout. * @property AUDIO_TIMEOUT * @static * @type {Number} * @default 8000 * @protected */ s.AUDIO_TIMEOUT = 8000; // TODO: This is not implemented // OJR remove property? doc'd as protected to remove from docs for now /** * The interrupt value to interrupt any currently playing instance with the same source, if the maximum number of * instances of the sound are already playing. * @property INTERRUPT_ANY * @type {String} * @default any * @static */ s.INTERRUPT_ANY = "any"; /** * The interrupt value to interrupt the earliest currently playing instance with the same source that progressed the * least distance in the audio track, if the maximum number of instances of the sound are already playing. * @property INTERRUPT_EARLY * @type {String} * @default early * @static */ s.INTERRUPT_EARLY = "early"; /** * The interrupt value to interrupt the currently playing instance with the same source that progressed the most * distance in the audio track, if the maximum number of instances of the sound are already playing. * @property INTERRUPT_LATE * @type {String} * @default late * @static */ s.INTERRUPT_LATE = "late"; /** * The interrupt value to not interrupt any currently playing instances with the same source, if the maximum number of * instances of the sound are already playing. * @property INTERRUPT_NONE * @type {String} * @default none * @static */ s.INTERRUPT_NONE = "none"; // The playState in plugins should be implemented with these values. /** * Defines the playState of an instance that is still initializing. * @property PLAY_INITED * @type {String} * @default playInited * @static */ s.PLAY_INITED = "playInited"; /** * Defines the playState of an instance that is currently playing or paused. * @property PLAY_SUCCEEDED * @type {String} * @default playSucceeded * @static */ s.PLAY_SUCCEEDED = "playSucceeded"; /** * Defines the playState of an instance that was interrupted by another instance. * @property PLAY_INTERRUPTED * @type {String} * @default playInterrupted * @static */ s.PLAY_INTERRUPTED = "playInterrupted"; /** * Defines the playState of an instance that completed playback. * @property PLAY_FINISHED * @type {String} * @default playFinished * @static */ s.PLAY_FINISHED = "playFinished"; /** * Defines the playState of an instance that failed to play. This is usually caused by a lack of available channels * when the interrupt mode was "INTERRUPT_NONE", the playback stalled, or the sound could not be found. * @property PLAY_FAILED * @type {String} * @default playFailed * @static */ s.PLAY_FAILED = "playFailed"; /** * A list of the default supported extensions that Sound will try to play. Plugins will check if the browser * can play these types, so modifying this list before a plugin is initialized will allow the plugins to try to * support additional media types. * * NOTE this does not currently work for {{#crossLink "FlashPlugin"}}{{/crossLink}}. * * More details on file formats can be found at http://en.wikipedia.org/wiki/Audio_file_format. A very detailed * list of file formats can be found at http://www.fileinfo.com/filetypes/audio. A useful list of extensions for * each format can be found at http://html5doctor.com/html5-audio-the-state-of-play/ * @property SUPPORTED_EXTENSIONS * @type {Array[String]} * @default ["mp3", "ogg", "mpeg", "wav", "m4a", "mp4", "aiff", "wma", "mid"] */ s.SUPPORTED_EXTENSIONS = ["mp3", "ogg", "mpeg", "wav", "m4a", "mp4", "aiff", "wma", "mid"]; // OJR FlashPlugin does not currently support /** * Some extensions use another type of extension support to play (one of them is a codex). This allows you to map * that support so plugins can accurately determine if an extension is supported. Adding to this list can help * plugins determine more accurately if an extension is supported. * @property EXTENSION_MAP * @type {Object} * @since 0.4.0 */ s.EXTENSION_MAP = { m4a:"mp4" }; /** * The RegExp pattern used to parse file URIs. This supports simple file names, as well as full domain URIs with * query strings. The resulting match is: protocol:$1 domain:$2 path:$3 file:$4 extension:$5 query:$6. * @property FILE_PATTERN * @type {RegExp} * @static * @protected */ s.FILE_PATTERN = /^(?:(\w+:)\/{2}(\w+(?:\.\w+)*\/?))?([/.]*?(?:[^?]+)?\/)?((?:[^/?]+)\.(\w+))(?:\?(\S+)?)?$/; /** * Determines the default behavior for interrupting other currently playing instances with the same source, if the * maximum number of instances of the sound are already playing. Currently the default is {{#crossLink "Sound/INTERRUPT_NONE:property"}}{{/crossLink}} * but this can be set and will change playback behavior accordingly. This is only used when {{#crossLink "Sound/play"}}{{/crossLink}} * is called without passing a value for interrupt. * @property defaultInterruptBehavior * @type {String} * @default none * @static * @since 0.4.0 */ s.defaultInterruptBehavior = s.INTERRUPT_NONE; // OJR does s.INTERRUPT_ANY make more sense as default? Needs game dev testing to see which case makes more sense. /** * An array of extensions to attempt to use when loading sound, if the default is unsupported by the active plugin. * These are applied in order, so if you try to Load Thunder.ogg in a browser that does not support ogg, and your * extensions array is ["mp3", "m4a", "wav"] it will check mp3 support, then m4a, then wav. These audio files need * to exist in the same location. * *

Example

* var manifest = [ * {src:"asset0.ogg", id:"example"}, * ]; * createjs.Sound.alternateExtensions = ["mp3"]; // now if ogg is not supported, SoundJS will try asset0.mp3 * createjs.Sound.addEventListener("fileload", handleLoad); // call handleLoad when each sound loads * createjs.Sound.registerManifest(manifest, assetPath); * * Note that regardless of which file is loaded, you can create and play instances using the id or the same * assetPath + src passed for loading. * @property alternateExtensions * @type {Array} * @since 0.5.2 */ s.alternateExtensions = []; /** * Used internally to assign unique IDs to each SoundInstance. * @property lastID * @type {Number} * @static * @protected */ s.lastId = 0; /** * The currently active plugin. If this is null, then no plugin could be initialized. If no plugin was specified, * Sound attempts to apply the default plugins: {{#crossLink "WebAudioPlugin"}}{{/crossLink}}, followed by * {{#crossLink "HTMLAudioPlugin"}}{{/crossLink}}. * @property activePlugin * @type {Object} * @static */ s.activePlugin = null; /** * Determines if the plugins have been registered. If false, the first call to play() will instantiate the default * plugins ({{#crossLink "WebAudioPlugin"}}{{/crossLink}}, followed by {{#crossLink "HTMLAudioPlugin"}}{{/crossLink}}). * If plugins have been registered, but none are applicable, then sound playback will fail. * @property pluginsRegistered * @type {Boolean} * @default false * @static * @protected */ s.pluginsRegistered = false; /** * The master volume value, which affects all sounds. Use {{#crossLink "Sound/getVolume"}}{{/crossLink}} and * {{#crossLink "Sound/setVolume"}}{{/crossLink}} to modify the volume of all audio. * @property masterVolume * @type {Number} * @default 1 * @protected * @since 0.4.0 */ s.masterVolume = 1; /** * The master mute value, which affects all sounds. This is applies to all sound instances. This value can be set * through {{#crossLink "Sound/setMute"}}{{/crossLink}} and accessed via {{#crossLink "Sound/getMute"}}{{/crossLink}}. * @property masterMute * @type {Boolean} * @default false * @protected * @static * @since 0.4.0 */ s.masterMute = false; /** * An array containing all currently playing instances. This allows Sound to control the volume, mute, and playback of * all instances when using static APIs like {{#crossLink "Sound/stop"}}{{/crossLink}} and {{#crossLink "Sound/setVolume"}}{{/crossLink}}. * When an instance has finished playback, it gets removed via the {{#crossLink "Sound/finishedPlaying"}}{{/crossLink}} * method. If the user replays an instance, it gets added back in via the {{#crossLink "Sound/beginPlaying"}}{{/crossLink}} * method. * @property instances * @type {Array} * @protected * @static */ s.instances = []; /** * An object hash storing sound sources via there corresponding ID. * @property idHash * @type {Object} * @protected * @static */ s.idHash = {}; /** * An object hash that stores preloading sound sources via the parsed source that is passed to the plugin. Contains the * source, id, and data that was passed in by the user. Parsed sources can contain multiple instances of source, id, * and data. * @property preloadHash * @type {Object} * @protected * @static */ s.preloadHash = {}; /** * An object that stands in for audio that fails to play. This allows developers to continue to call methods * on the failed instance without having to check if it is valid first. The instance is instantiated once, and * shared to keep the memory footprint down. * @property defaultSoundInstance * @type {Object} * @protected * @static */ s.defaultSoundInstance = null; // mix-ins: // EventDispatcher methods: s.addEventListener = null; s.removeEventListener = null; s.removeAllEventListeners = null; s.dispatchEvent = null; s.hasEventListener = null; s._listeners = null; createjs.EventDispatcher.initialize(s); // inject EventDispatcher methods. // Events /** * This event is fired when a file finishes loading internally. This event is fired for each loaded sound, * so any handler methods should look up the event.src to handle a particular sound. * @event fileload * @param {Object} target The object that dispatched the event. * @param {String} type The event type. * @param {String} src The source of the sound that was loaded. * @param {String} [id] The id passed in when the sound was registered. If one was not provided, it will be null. * @param {Number|Object} [data] Any additional data associated with the item. If not provided, it will be undefined. * @since 0.4.1 */ //TODO: Deprecated /** * REMOVED. Use {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}} and the {{#crossLink "Sound/fileload:event"}}{{/crossLink}} * event. * @property onLoadComplete * @type {Function} * @deprecated Use addEventListener and the fileload event. * @since 0.4.0 */ /** * Used by external plugins to dispatch file load events. * @method sendFileLoadEvent * @param {String} src A sound file has completed loading, and should be dispatched. * @protected * @static * @since 0.4.1 */ s.sendFileLoadEvent = function (src) { if (!s.preloadHash[src]) { return; } for (var i = 0, l = s.preloadHash[src].length; i < l; i++) { var item = s.preloadHash[src][i]; s.preloadHash[src][i] = true; if (!s.hasEventListener("fileload")) { continue; } var event = new createjs.Event("fileload"); event.src = item.src; event.id = item.id; event.data = item.data; s.dispatchEvent(event); } }; /** * Get the preload rules to allow Sound to be used as a plugin by PreloadJS. * Any load calls that have the matching type or extension will fire the callback method, and use the resulting * object, which is potentially modified by Sound. This helps when determining the correct path, as well as * registering the audio instance(s) with Sound. This method should not be called, except by PreloadJS. * @method getPreloadHandlers * @return {Object} An object containing: * * @static * @protected */ s.getPreloadHandlers = function () { return { callback:createjs.proxy(s.initLoad, s), types:["sound"], extensions:s.SUPPORTED_EXTENSIONS }; }; /** * Deprecated in favor of {{#crossLink "Sound/registerPlugins"}}{{/crossLink}} with a single argument. * createjs.Sound.registerPlugins([createjs.WebAudioPlugin]); * * @method registerPlugin * @param {Object} plugin The plugin class to install. * @return {Boolean} Whether the plugin was successfully initialized. * @static * @deprecated */ s.registerPlugin = function (plugin) { return s._registerPlugin(plugin); }; /** * Register a Sound plugin. Plugins handle the actual playback of audio. The default plugins are * ({{#crossLink "WebAudioPlugin"}}{{/crossLink}} followed by {{#crossLink "HTMLAudioPlugin"}}{{/crossLink}}), * and are installed if no other plugins are present when the user attempts to start playback or register sound. *

Example

* createjs.FlashPlugin.swfPath = "../src/SoundJS/"; * createjs.Sound._registerPlugin(createjs.FlashPlugin); * * To register multiple plugins, use {{#crossLink "Sound/registerPlugins"}}{{/crossLink}}. * * @method _registerPlugin * @param {Object} plugin The plugin class to install. * @return {Boolean} Whether the plugin was successfully initialized. * @static * @private */ s._registerPlugin = function (plugin) { s.pluginsRegistered = true; if (plugin == null) { return false; } // Note: Each plugin is passed in as a class reference, but we store the activePlugin as an instance if (plugin.isSupported()) { s.activePlugin = new plugin(); //TODO: Check error on initialization return true; } return false; }; /** * Register a list of Sound plugins, in order of precedence. To register a single plugin, pass a single element in the array. * *

Example

* createjs.FlashPlugin.swfPath = "../src/SoundJS/"; * createjs.Sound.registerPlugins([createjs.WebAudioPlugin, createjs.HTMLAudioPlugin, createjs.FlashPlugin]); * * @method registerPlugins * @param {Array} plugins An array of plugins classes to install. * @return {Boolean} Whether a plugin was successfully initialized. * @static */ s.registerPlugins = function (plugins) { for (var i = 0, l = plugins.length; i < l; i++) { var plugin = plugins[i]; if (s._registerPlugin(plugin)) { return true; } } return false; }; /** * Initialize the default plugins. This method is automatically called when any audio is played or registered before * the user has manually registered plugins, and enables Sound to work without manual plugin setup. Currently, the * default plugins are {{#crossLink "WebAudioPlugin"}}{{/crossLink}} followed by {{#crossLink "HTMLAudioPlugin"}}{{/crossLink}}. * * *

Example

* if (!createjs.initializeDefaultPlugins()) { return; } * * @method initializeDefaultPlugins * @returns {Boolean} If a plugin is initialized (true) or not (false). If the browser does not have the * capabilities to initialize any available plugins, this will return false. * @since 0.4.0 */ s.initializeDefaultPlugins = function () { if (s.activePlugin != null) { return true; } if (s.pluginsRegistered) { return false; } if (s.registerPlugins([createjs.WebAudioPlugin, createjs.HTMLAudioPlugin])) { return true; } return false; }; /** * Determines if Sound has been initialized, and a plugin has been activated. * *

Example

* This example sets up a Flash fallback, but only if there is no plugin specified yet. * * if (!createjs.Sound.isReady()) { * createjs.FlashPlugin.swfPath = "../src/SoundJS/"; * createjs.Sound.registerPlugins([createjs.WebAudioPlugin, createjs.HTMLAudioPlugin, createjs.FlashPlugin]); * } * * @method isReady * @return {Boolean} If Sound has initialized a plugin. * @static */ s.isReady = function () { return (s.activePlugin != null); }; /** * Get the active plugins capabilities, which help determine if a plugin can be used in the current environment, * or if the plugin supports a specific feature. Capabilities include: *