scratch – Blame information for rev 73

Subversion Repositories:
Rev:
Rev Author Line No. Line
73 office 1 /*!
2 * SoundJS
3 * Visit http://createjs.com/ for documentation, updates and examples.
4 *
5 * Copyright (c) 2010 gskinner.com, inc.
6 *
7 * Permission is hereby granted, free of charge, to any person
8 * obtaining a copy of this software and associated documentation
9 * files (the "Software"), to deal in the Software without
10 * restriction, including without limitation the rights to use,
11 * copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following
14 * conditions:
15 *
16 * The above copyright notice and this permission notice shall be
17 * included in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
21 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26 * OTHER DEALINGS IN THE SOFTWARE.
27 */
28  
29  
30 //##############################################################################
31 // version.js
32 //##############################################################################
33  
34 this.createjs = this.createjs || {};
35  
36 (function () {
37  
38 /**
39 * Static class holding library specific information such as the version and buildDate of the library.
40 * The SoundJS class has been renamed {{#crossLink "Sound"}}{{/crossLink}}. Please see {{#crossLink "Sound"}}{{/crossLink}}
41 * for information on using sound.
42 * @class SoundJS
43 **/
44 var s = createjs.SoundJS = createjs.SoundJS || {};
45  
46 /**
47 * The version string for this release.
48 * @property version
49 * @type String
50 * @static
51 **/
52 s.version = /*=version*/"0.6.2"; // injected by build process
53  
54 /**
55 * The build date for this release in UTC format.
56 * @property buildDate
57 * @type String
58 * @static
59 **/
60 s.buildDate = /*=date*/"Thu, 26 Nov 2015 20:44:31 GMT"; // injected by build process
61  
62 })();
63  
64 //##############################################################################
65 // extend.js
66 //##############################################################################
67  
68 this.createjs = this.createjs||{};
69  
70 /**
71 * @class Utility Methods
72 */
73  
74 /**
75 * Sets up the prototype chain and constructor property for a new class.
76 *
77 * This should be called right after creating the class constructor.
78 *
79 * function MySubClass() {}
80 * createjs.extend(MySubClass, MySuperClass);
81 * MySubClass.prototype.doSomething = function() { }
82 *
83 * var foo = new MySubClass();
84 * console.log(foo instanceof MySuperClass); // true
85 * console.log(foo.prototype.constructor === MySubClass); // true
86 *
87 * @method extend
88 * @param {Function} subclass The subclass.
89 * @param {Function} superclass The superclass to extend.
90 * @return {Function} Returns the subclass's new prototype.
91 */
92 createjs.extend = function(subclass, superclass) {
93 "use strict";
94  
95 function o() { this.constructor = subclass; }
96 o.prototype = superclass.prototype;
97 return (subclass.prototype = new o());
98 };
99  
100 //##############################################################################
101 // promote.js
102 //##############################################################################
103  
104 this.createjs = this.createjs||{};
105  
106 /**
107 * @class Utility Methods
108 */
109  
110 /**
111 * Promotes any methods on the super class that were overridden, by creating an alias in the format `prefix_methodName`.
112 * It is recommended to use the super class's name as the prefix.
113 * An alias to the super class's constructor is always added in the format `prefix_constructor`.
114 * This allows the subclass to call super class methods without using `function.call`, providing better performance.
115 *
116 * For example, if `MySubClass` extends `MySuperClass`, and both define a `draw` method, then calling `promote(MySubClass, "MySuperClass")`
117 * would add a `MySuperClass_constructor` method to MySubClass and promote the `draw` method on `MySuperClass` to the
118 * prototype of `MySubClass` as `MySuperClass_draw`.
119 *
120 * This should be called after the class's prototype is fully defined.
121 *
122 * function ClassA(name) {
123 * this.name = name;
124 * }
125 * ClassA.prototype.greet = function() {
126 * return "Hello "+this.name;
127 * }
128 *
129 * function ClassB(name, punctuation) {
130 * this.ClassA_constructor(name);
131 * this.punctuation = punctuation;
132 * }
133 * createjs.extend(ClassB, ClassA);
134 * ClassB.prototype.greet = function() {
135 * return this.ClassA_greet()+this.punctuation;
136 * }
137 * createjs.promote(ClassB, "ClassA");
138 *
139 * var foo = new ClassB("World", "!?!");
140 * console.log(foo.greet()); // Hello World!?!
141 *
142 * @method promote
143 * @param {Function} subclass The class to promote super class methods on.
144 * @param {String} prefix The prefix to add to the promoted method names. Usually the name of the superclass.
145 * @return {Function} Returns the subclass.
146 */
147 createjs.promote = function(subclass, prefix) {
148 "use strict";
149  
150 var subP = subclass.prototype, supP = (Object.getPrototypeOf&&Object.getPrototypeOf(subP))||subP.__proto__;
151 if (supP) {
152 subP[(prefix+="_") + "constructor"] = supP.constructor; // constructor is not always innumerable
153 for (var n in supP) {
154 if (subP.hasOwnProperty(n) && (typeof supP[n] == "function")) { subP[prefix + n] = supP[n]; }
155 }
156 }
157 return subclass;
158 };
159  
160 //##############################################################################
161 // IndexOf.js
162 //##############################################################################
163  
164 this.createjs = this.createjs||{};
165  
166 /**
167 * @class Utility Methods
168 */
169  
170 /**
171 * Finds the first occurrence of a specified value searchElement in the passed in array, and returns the index of
172 * that value. Returns -1 if value is not found.
173 *
174 * var i = createjs.indexOf(myArray, myElementToFind);
175 *
176 * @method indexOf
177 * @param {Array} array Array to search for searchElement
178 * @param searchElement Element to find in array.
179 * @return {Number} The first index of searchElement in array.
180 */
181 createjs.indexOf = function (array, searchElement){
182 "use strict";
183  
184 for (var i = 0,l=array.length; i < l; i++) {
185 if (searchElement === array[i]) {
186 return i;
187 }
188 }
189 return -1;
190 };
191  
192 //##############################################################################
193 // Proxy.js
194 //##############################################################################
195  
196 this.createjs = this.createjs||{};
197  
198 /**
199 * Various utilities that the CreateJS Suite uses. Utilities are created as separate files, and will be available on the
200 * createjs namespace directly.
201 *
202 * <h4>Example</h4>
203 *
204 * myObject.addEventListener("change", createjs.proxy(myMethod, scope));
205 *
206 * @class Utility Methods
207 * @main Utility Methods
208 */
209  
210 (function() {
211 "use strict";
212  
213 /**
214 * A function proxy for methods. By default, JavaScript methods do not maintain scope, so passing a method as a
215 * callback will result in the method getting called in the scope of the caller. Using a proxy ensures that the
216 * method gets called in the correct scope.
217 *
218 * Additional arguments can be passed that will be applied to the function when it is called.
219 *
220 * <h4>Example</h4>
221 *
222 * myObject.addEventListener("event", createjs.proxy(myHandler, this, arg1, arg2));
223 *
224 * function myHandler(arg1, arg2) {
225 * // This gets called when myObject.myCallback is executed.
226 * }
227 *
228 * @method proxy
229 * @param {Function} method The function to call
230 * @param {Object} scope The scope to call the method name on
231 * @param {mixed} [arg] * Arguments that are appended to the callback for additional params.
232 * @public
233 * @static
234 */
235 createjs.proxy = function (method, scope) {
236 var aArgs = Array.prototype.slice.call(arguments, 2);
237 return function () {
238 return method.apply(scope, Array.prototype.slice.call(arguments, 0).concat(aArgs));
239 };
240 }
241  
242 }());
243  
244 //##############################################################################
245 // BrowserDetect.js
246 //##############################################################################
247  
248 this.createjs = this.createjs||{};
249  
250 /**
251 * @class Utility Methods
252 */
253 (function() {
254 "use strict";
255  
256 /**
257 * An object that determines the current browser, version, operating system, and other environment
258 * variables via user agent string.
259 *
260 * Used for audio because feature detection is unable to detect the many limitations of mobile devices.
261 *
262 * <h4>Example</h4>
263 *
264 * if (createjs.BrowserDetect.isIOS) { // do stuff }
265 *
266 * @property BrowserDetect
267 * @type {Object}
268 * @param {Boolean} isFirefox True if our browser is Firefox.
269 * @param {Boolean} isOpera True if our browser is opera.
270 * @param {Boolean} isChrome True if our browser is Chrome. Note that Chrome for Android returns true, but is a
271 * completely different browser with different abilities.
272 * @param {Boolean} isIOS True if our browser is safari for iOS devices (iPad, iPhone, and iPod).
273 * @param {Boolean} isAndroid True if our browser is Android.
274 * @param {Boolean} isBlackberry True if our browser is Blackberry.
275 * @constructor
276 * @static
277 */
278 function BrowserDetect() {
279 throw "BrowserDetect cannot be instantiated";
280 };
281  
282 var agent = BrowserDetect.agent = window.navigator.userAgent;
283 BrowserDetect.isWindowPhone = (agent.indexOf("IEMobile") > -1) || (agent.indexOf("Windows Phone") > -1);
284 BrowserDetect.isFirefox = (agent.indexOf("Firefox") > -1);
285 BrowserDetect.isOpera = (window.opera != null);
286 BrowserDetect.isChrome = (agent.indexOf("Chrome") > -1); // NOTE that Chrome on Android returns true but is a completely different browser with different abilities
287 BrowserDetect.isIOS = (agent.indexOf("iPod") > -1 || agent.indexOf("iPhone") > -1 || agent.indexOf("iPad") > -1) && !BrowserDetect.isWindowPhone;
288 BrowserDetect.isAndroid = (agent.indexOf("Android") > -1) && !BrowserDetect.isWindowPhone;
289 BrowserDetect.isBlackberry = (agent.indexOf("Blackberry") > -1);
290  
291 createjs.BrowserDetect = BrowserDetect;
292  
293 }());
294  
295 //##############################################################################
296 // EventDispatcher.js
297 //##############################################################################
298  
299 this.createjs = this.createjs||{};
300  
301 (function() {
302 "use strict";
303  
304  
305 // constructor:
306 /**
307 * EventDispatcher provides methods for managing queues of event listeners and dispatching events.
308 *
309 * You can either extend EventDispatcher or mix its methods into an existing prototype or instance by using the
310 * EventDispatcher {{#crossLink "EventDispatcher/initialize"}}{{/crossLink}} method.
311 *
312 * Together with the CreateJS Event class, EventDispatcher provides an extended event model that is based on the
313 * DOM Level 2 event model, including addEventListener, removeEventListener, and dispatchEvent. It supports
314 * bubbling / capture, preventDefault, stopPropagation, stopImmediatePropagation, and handleEvent.
315 *
316 * EventDispatcher also exposes a {{#crossLink "EventDispatcher/on"}}{{/crossLink}} method, which makes it easier
317 * to create scoped listeners, listeners that only run once, and listeners with associated arbitrary data. The
318 * {{#crossLink "EventDispatcher/off"}}{{/crossLink}} method is merely an alias to
319 * {{#crossLink "EventDispatcher/removeEventListener"}}{{/crossLink}}.
320 *
321 * Another addition to the DOM Level 2 model is the {{#crossLink "EventDispatcher/removeAllEventListeners"}}{{/crossLink}}
322 * method, which can be used to listeners for all events, or listeners for a specific event. The Event object also
323 * includes a {{#crossLink "Event/remove"}}{{/crossLink}} method which removes the active listener.
324 *
325 * <h4>Example</h4>
326 * Add EventDispatcher capabilities to the "MyClass" class.
327 *
328 * EventDispatcher.initialize(MyClass.prototype);
329 *
330 * Add an event (see {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}}).
331 *
332 * instance.addEventListener("eventName", handlerMethod);
333 * function handlerMethod(event) {
334 * console.log(event.target + " Was Clicked");
335 * }
336 *
337 * <b>Maintaining proper scope</b><br />
338 * Scope (ie. "this") can be be a challenge with events. Using the {{#crossLink "EventDispatcher/on"}}{{/crossLink}}
339 * method to subscribe to events simplifies this.
340 *
341 * instance.addEventListener("click", function(event) {
342 * console.log(instance == this); // false, scope is ambiguous.
343 * });
344 *
345 * instance.on("click", function(event) {
346 * console.log(instance == this); // true, "on" uses dispatcher scope by default.
347 * });
348 *
349 * If you want to use addEventListener instead, you may want to use function.bind() or a similar proxy to manage
350 * scope.
351 *
352 * <b>Browser support</b>
353 * The event model in CreateJS can be used separately from the suite in any project, however the inheritance model
354 * requires modern browsers (IE9+).
355 *
356 *
357 * @class EventDispatcher
358 * @constructor
359 **/
360 function EventDispatcher() {
361  
362  
363 // private properties:
364 /**
365 * @protected
366 * @property _listeners
367 * @type Object
368 **/
369 this._listeners = null;
370  
371 /**
372 * @protected
373 * @property _captureListeners
374 * @type Object
375 **/
376 this._captureListeners = null;
377 }
378 var p = EventDispatcher.prototype;
379  
380 /**
381 * <strong>REMOVED</strong>. Removed in favor of using `MySuperClass_constructor`.
382 * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}}
383 * for details.
384 *
385 * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance.
386 *
387 * @method initialize
388 * @protected
389 * @deprecated
390 */
391 // p.initialize = function() {}; // searchable for devs wondering where it is.
392  
393  
394 // static public methods:
395 /**
396 * Static initializer to mix EventDispatcher methods into a target object or prototype.
397 *
398 * EventDispatcher.initialize(MyClass.prototype); // add to the prototype of the class
399 * EventDispatcher.initialize(myObject); // add to a specific instance
400 *
401 * @method initialize
402 * @static
403 * @param {Object} target The target object to inject EventDispatcher methods into. This can be an instance or a
404 * prototype.
405 **/
406 EventDispatcher.initialize = function(target) {
407 target.addEventListener = p.addEventListener;
408 target.on = p.on;
409 target.removeEventListener = target.off = p.removeEventListener;
410 target.removeAllEventListeners = p.removeAllEventListeners;
411 target.hasEventListener = p.hasEventListener;
412 target.dispatchEvent = p.dispatchEvent;
413 target._dispatchEvent = p._dispatchEvent;
414 target.willTrigger = p.willTrigger;
415 };
416  
417  
418 // public methods:
419 /**
420 * Adds the specified event listener. Note that adding multiple listeners to the same function will result in
421 * multiple callbacks getting fired.
422 *
423 * <h4>Example</h4>
424 *
425 * displayObject.addEventListener("click", handleClick);
426 * function handleClick(event) {
427 * // Click happened.
428 * }
429 *
430 * @method addEventListener
431 * @param {String} type The string type of the event.
432 * @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when
433 * the event is dispatched.
434 * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase.
435 * @return {Function | Object} Returns the listener for chaining or assignment.
436 **/
437 p.addEventListener = function(type, listener, useCapture) {
438 var listeners;
439 if (useCapture) {
440 listeners = this._captureListeners = this._captureListeners||{};
441 } else {
442 listeners = this._listeners = this._listeners||{};
443 }
444 var arr = listeners[type];
445 if (arr) { this.removeEventListener(type, listener, useCapture); }
446 arr = listeners[type]; // remove may have deleted the array
447 if (!arr) { listeners[type] = [listener]; }
448 else { arr.push(listener); }
449 return listener;
450 };
451  
452 /**
453 * A shortcut method for using addEventListener that makes it easier to specify an execution scope, have a listener
454 * only run once, associate arbitrary data with the listener, and remove the listener.
455 *
456 * This method works by creating an anonymous wrapper function and subscribing it with addEventListener.
457 * The wrapper function is returned for use with `removeEventListener` (or `off`).
458 *
459 * <b>IMPORTANT:</b> To remove a listener added with `on`, you must pass in the returned wrapper function as the listener, or use
460 * {{#crossLink "Event/remove"}}{{/crossLink}}. Likewise, each time you call `on` a NEW wrapper function is subscribed, so multiple calls
461 * to `on` with the same params will create multiple listeners.
462 *
463 * <h4>Example</h4>
464 *
465 * var listener = myBtn.on("click", handleClick, null, false, {count:3});
466 * function handleClick(evt, data) {
467 * data.count -= 1;
468 * console.log(this == myBtn); // true - scope defaults to the dispatcher
469 * if (data.count == 0) {
470 * alert("clicked 3 times!");
471 * myBtn.off("click", listener);
472 * // alternately: evt.remove();
473 * }
474 * }
475 *
476 * @method on
477 * @param {String} type The string type of the event.
478 * @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when
479 * the event is dispatched.
480 * @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).
481 * @param {Boolean} [once=false] If true, the listener will remove itself after the first time it is triggered.
482 * @param {*} [data] Arbitrary data that will be included as the second parameter when the listener is called.
483 * @param {Boolean} [useCapture=false] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase.
484 * @return {Function} Returns the anonymous function that was created and assigned as the listener. This is needed to remove the listener later using .removeEventListener.
485 **/
486 p.on = function(type, listener, scope, once, data, useCapture) {
487 if (listener.handleEvent) {
488 scope = scope||listener;
489 listener = listener.handleEvent;
490 }
491 scope = scope||this;
492 return this.addEventListener(type, function(evt) {
493 listener.call(scope, evt, data);
494 once&&evt.remove();
495 }, useCapture);
496 };
497  
498 /**
499 * Removes the specified event listener.
500 *
501 * <b>Important Note:</b> that you must pass the exact function reference used when the event was added. If a proxy
502 * function, or function closure is used as the callback, the proxy/closure reference must be used - a new proxy or
503 * closure will not work.
504 *
505 * <h4>Example</h4>
506 *
507 * displayObject.removeEventListener("click", handleClick);
508 *
509 * @method removeEventListener
510 * @param {String} type The string type of the event.
511 * @param {Function | Object} listener The listener function or object.
512 * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase.
513 **/
514 p.removeEventListener = function(type, listener, useCapture) {
515 var listeners = useCapture ? this._captureListeners : this._listeners;
516 if (!listeners) { return; }
517 var arr = listeners[type];
518 if (!arr) { return; }
519 for (var i=0,l=arr.length; i<l; i++) {
520 if (arr[i] == listener) {
521 if (l==1) { delete(listeners[type]); } // allows for faster checks.
522 else { arr.splice(i,1); }
523 break;
524 }
525 }
526 };
527  
528 /**
529 * A shortcut to the removeEventListener method, with the same parameters and return value. This is a companion to the
530 * .on method.
531 *
532 * <b>IMPORTANT:</b> To remove a listener added with `on`, you must pass in the returned wrapper function as the listener. See
533 * {{#crossLink "EventDispatcher/on"}}{{/crossLink}} for an example.
534 *
535 * @method off
536 * @param {String} type The string type of the event.
537 * @param {Function | Object} listener The listener function or object.
538 * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase.
539 **/
540 p.off = p.removeEventListener;
541  
542 /**
543 * Removes all listeners for the specified type, or all listeners of all types.
544 *
545 * <h4>Example</h4>
546 *
547 * // Remove all listeners
548 * displayObject.removeAllEventListeners();
549 *
550 * // Remove all click listeners
551 * displayObject.removeAllEventListeners("click");
552 *
553 * @method removeAllEventListeners
554 * @param {String} [type] The string type of the event. If omitted, all listeners for all types will be removed.
555 **/
556 p.removeAllEventListeners = function(type) {
557 if (!type) { this._listeners = this._captureListeners = null; }
558 else {
559 if (this._listeners) { delete(this._listeners[type]); }
560 if (this._captureListeners) { delete(this._captureListeners[type]); }
561 }
562 };
563  
564 /**
565 * Dispatches the specified event to all listeners.
566 *
567 * <h4>Example</h4>
568 *
569 * // Use a string event
570 * this.dispatchEvent("complete");
571 *
572 * // Use an Event instance
573 * var event = new createjs.Event("progress");
574 * this.dispatchEvent(event);
575 *
576 * @method dispatchEvent
577 * @param {Object | String | Event} eventObj An object with a "type" property, or a string type.
578 * While a generic object will work, it is recommended to use a CreateJS Event instance. If a string is used,
579 * dispatchEvent will construct an Event instance if necessary with the specified type. This latter approach can
580 * be used to avoid event object instantiation for non-bubbling events that may not have any listeners.
581 * @param {Boolean} [bubbles] Specifies the `bubbles` value when a string was passed to eventObj.
582 * @param {Boolean} [cancelable] Specifies the `cancelable` value when a string was passed to eventObj.
583 * @return {Boolean} Returns false if `preventDefault()` was called on a cancelable event, true otherwise.
584 **/
585 p.dispatchEvent = function(eventObj, bubbles, cancelable) {
586 if (typeof eventObj == "string") {
587 // skip everything if there's no listeners and it doesn't bubble:
588 var listeners = this._listeners;
589 if (!bubbles && (!listeners || !listeners[eventObj])) { return true; }
590 eventObj = new createjs.Event(eventObj, bubbles, cancelable);
591 } else if (eventObj.target && eventObj.clone) {
592 // redispatching an active event object, so clone it:
593 eventObj = eventObj.clone();
594 }
595  
596 // TODO: it would be nice to eliminate this. Maybe in favour of evtObj instanceof Event? Or !!evtObj.createEvent
597 try { eventObj.target = this; } catch (e) {} // try/catch allows redispatching of native events
598  
599 if (!eventObj.bubbles || !this.parent) {
600 this._dispatchEvent(eventObj, 2);
601 } else {
602 var top=this, list=[top];
603 while (top.parent) { list.push(top = top.parent); }
604 var i, l=list.length;
605  
606 // capture & atTarget
607 for (i=l-1; i>=0 && !eventObj.propagationStopped; i--) {
608 list[i]._dispatchEvent(eventObj, 1+(i==0));
609 }
610 // bubbling
611 for (i=1; i<l && !eventObj.propagationStopped; i++) {
612 list[i]._dispatchEvent(eventObj, 3);
613 }
614 }
615 return !eventObj.defaultPrevented;
616 };
617  
618 /**
619 * Indicates whether there is at least one listener for the specified event type.
620 * @method hasEventListener
621 * @param {String} type The string type of the event.
622 * @return {Boolean} Returns true if there is at least one listener for the specified event.
623 **/
624 p.hasEventListener = function(type) {
625 var listeners = this._listeners, captureListeners = this._captureListeners;
626 return !!((listeners && listeners[type]) || (captureListeners && captureListeners[type]));
627 };
628  
629 /**
630 * Indicates whether there is at least one listener for the specified event type on this object or any of its
631 * ancestors (parent, parent's parent, etc). A return value of true indicates that if a bubbling event of the
632 * specified type is dispatched from this object, it will trigger at least one listener.
633 *
634 * This is similar to {{#crossLink "EventDispatcher/hasEventListener"}}{{/crossLink}}, but it searches the entire
635 * event flow for a listener, not just this object.
636 * @method willTrigger
637 * @param {String} type The string type of the event.
638 * @return {Boolean} Returns `true` if there is at least one listener for the specified event.
639 **/
640 p.willTrigger = function(type) {
641 var o = this;
642 while (o) {
643 if (o.hasEventListener(type)) { return true; }
644 o = o.parent;
645 }
646 return false;
647 };
648  
649 /**
650 * @method toString
651 * @return {String} a string representation of the instance.
652 **/
653 p.toString = function() {
654 return "[EventDispatcher]";
655 };
656  
657  
658 // private methods:
659 /**
660 * @method _dispatchEvent
661 * @param {Object | String | Event} eventObj
662 * @param {Object} eventPhase
663 * @protected
664 **/
665 p._dispatchEvent = function(eventObj, eventPhase) {
666 var l, listeners = (eventPhase==1) ? this._captureListeners : this._listeners;
667 if (eventObj && listeners) {
668 var arr = listeners[eventObj.type];
669 if (!arr||!(l=arr.length)) { return; }
670 try { eventObj.currentTarget = this; } catch (e) {}
671 try { eventObj.eventPhase = eventPhase; } catch (e) {}
672 eventObj.removed = false;
673  
674 arr = arr.slice(); // to avoid issues with items being removed or added during the dispatch
675 for (var i=0; i<l && !eventObj.immediatePropagationStopped; i++) {
676 var o = arr[i];
677 if (o.handleEvent) { o.handleEvent(eventObj); }
678 else { o(eventObj); }
679 if (eventObj.removed) {
680 this.off(eventObj.type, o, eventPhase==1);
681 eventObj.removed = false;
682 }
683 }
684 }
685 };
686  
687  
688 createjs.EventDispatcher = EventDispatcher;
689 }());
690  
691 //##############################################################################
692 // Event.js
693 //##############################################################################
694  
695 this.createjs = this.createjs||{};
696  
697 (function() {
698 "use strict";
699  
700 // constructor:
701 /**
702 * Contains properties and methods shared by all events for use with
703 * {{#crossLink "EventDispatcher"}}{{/crossLink}}.
704 *
705 * Note that Event objects are often reused, so you should never
706 * rely on an event object's state outside of the call stack it was received in.
707 * @class Event
708 * @param {String} type The event type.
709 * @param {Boolean} bubbles Indicates whether the event will bubble through the display list.
710 * @param {Boolean} cancelable Indicates whether the default behaviour of this event can be cancelled.
711 * @constructor
712 **/
713 function Event(type, bubbles, cancelable) {
714  
715  
716 // public properties:
717 /**
718 * The type of event.
719 * @property type
720 * @type String
721 **/
722 this.type = type;
723  
724 /**
725 * The object that generated an event.
726 * @property target
727 * @type Object
728 * @default null
729 * @readonly
730 */
731 this.target = null;
732  
733 /**
734 * The current target that a bubbling event is being dispatched from. For non-bubbling events, this will
735 * always be the same as target. For example, if childObj.parent = parentObj, and a bubbling event
736 * is generated from childObj, then a listener on parentObj would receive the event with
737 * target=childObj (the original target) and currentTarget=parentObj (where the listener was added).
738 * @property currentTarget
739 * @type Object
740 * @default null
741 * @readonly
742 */
743 this.currentTarget = null;
744  
745 /**
746 * For bubbling events, this indicates the current event phase:<OL>
747 * <LI> capture phase: starting from the top parent to the target</LI>
748 * <LI> at target phase: currently being dispatched from the target</LI>
749 * <LI> bubbling phase: from the target to the top parent</LI>
750 * </OL>
751 * @property eventPhase
752 * @type Number
753 * @default 0
754 * @readonly
755 */
756 this.eventPhase = 0;
757  
758 /**
759 * Indicates whether the event will bubble through the display list.
760 * @property bubbles
761 * @type Boolean
762 * @default false
763 * @readonly
764 */
765 this.bubbles = !!bubbles;
766  
767 /**
768 * Indicates whether the default behaviour of this event can be cancelled via
769 * {{#crossLink "Event/preventDefault"}}{{/crossLink}}. This is set via the Event constructor.
770 * @property cancelable
771 * @type Boolean
772 * @default false
773 * @readonly
774 */
775 this.cancelable = !!cancelable;
776  
777 /**
778 * The epoch time at which this event was created.
779 * @property timeStamp
780 * @type Number
781 * @default 0
782 * @readonly
783 */
784 this.timeStamp = (new Date()).getTime();
785  
786 /**
787 * Indicates if {{#crossLink "Event/preventDefault"}}{{/crossLink}} has been called
788 * on this event.
789 * @property defaultPrevented
790 * @type Boolean
791 * @default false
792 * @readonly
793 */
794 this.defaultPrevented = false;
795  
796 /**
797 * Indicates if {{#crossLink "Event/stopPropagation"}}{{/crossLink}} or
798 * {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called on this event.
799 * @property propagationStopped
800 * @type Boolean
801 * @default false
802 * @readonly
803 */
804 this.propagationStopped = false;
805  
806 /**
807 * Indicates if {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called
808 * on this event.
809 * @property immediatePropagationStopped
810 * @type Boolean
811 * @default false
812 * @readonly
813 */
814 this.immediatePropagationStopped = false;
815  
816 /**
817 * Indicates if {{#crossLink "Event/remove"}}{{/crossLink}} has been called on this event.
818 * @property removed
819 * @type Boolean
820 * @default false
821 * @readonly
822 */
823 this.removed = false;
824 }
825 var p = Event.prototype;
826  
827 /**
828 * <strong>REMOVED</strong>. Removed in favor of using `MySuperClass_constructor`.
829 * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}}
830 * for details.
831 *
832 * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance.
833 *
834 * @method initialize
835 * @protected
836 * @deprecated
837 */
838 // p.initialize = function() {}; // searchable for devs wondering where it is.
839  
840 // public methods:
841 /**
842 * Sets {{#crossLink "Event/defaultPrevented"}}{{/crossLink}} to true if the event is cancelable.
843 * Mirrors the DOM level 2 event standard. In general, cancelable events that have `preventDefault()` called will
844 * cancel the default behaviour associated with the event.
845 * @method preventDefault
846 **/
847 p.preventDefault = function() {
848 this.defaultPrevented = this.cancelable&&true;
849 };
850  
851 /**
852 * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} to true.
853 * Mirrors the DOM event standard.
854 * @method stopPropagation
855 **/
856 p.stopPropagation = function() {
857 this.propagationStopped = true;
858 };
859  
860 /**
861 * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} and
862 * {{#crossLink "Event/immediatePropagationStopped"}}{{/crossLink}} to true.
863 * Mirrors the DOM event standard.
864 * @method stopImmediatePropagation
865 **/
866 p.stopImmediatePropagation = function() {
867 this.immediatePropagationStopped = this.propagationStopped = true;
868 };
869  
870 /**
871 * Causes the active listener to be removed via removeEventListener();
872 *
873 * myBtn.addEventListener("click", function(evt) {
874 * // do stuff...
875 * evt.remove(); // removes this listener.
876 * });
877 *
878 * @method remove
879 **/
880 p.remove = function() {
881 this.removed = true;
882 };
883  
884 /**
885 * Returns a clone of the Event instance.
886 * @method clone
887 * @return {Event} a clone of the Event instance.
888 **/
889 p.clone = function() {
890 return new Event(this.type, this.bubbles, this.cancelable);
891 };
892  
893 /**
894 * Provides a chainable shortcut method for setting a number of properties on the instance.
895 *
896 * @method set
897 * @param {Object} props A generic object containing properties to copy to the instance.
898 * @return {Event} Returns the instance the method is called on (useful for chaining calls.)
899 * @chainable
900 */
901 p.set = function(props) {
902 for (var n in props) { this[n] = props[n]; }
903 return this;
904 };
905  
906 /**
907 * Returns a string representation of this object.
908 * @method toString
909 * @return {String} a string representation of the instance.
910 **/
911 p.toString = function() {
912 return "[Event (type="+this.type+")]";
913 };
914  
915 createjs.Event = Event;
916 }());
917  
918 //##############################################################################
919 // ErrorEvent.js
920 //##############################################################################
921  
922 this.createjs = this.createjs||{};
923  
924 (function() {
925 "use strict";
926  
927 /**
928 * A general error {{#crossLink "Event"}}{{/crossLink}}, that describes an error that occurred, as well as any details.
929 * @class ErrorEvent
930 * @param {String} [title] The error title
931 * @param {String} [message] The error description
932 * @param {Object} [data] Additional error data
933 * @constructor
934 */
935 function ErrorEvent(title, message, data) {
936 this.Event_constructor("error");
937  
938 /**
939 * The short error title, which indicates the type of error that occurred.
940 * @property title
941 * @type String
942 */
943 this.title = title;
944  
945 /**
946 * The verbose error message, containing details about the error.
947 * @property message
948 * @type String
949 */
950 this.message = message;
951  
952 /**
953 * Additional data attached to an error.
954 * @property data
955 * @type {Object}
956 */
957 this.data = data;
958 }
959  
960 var p = createjs.extend(ErrorEvent, createjs.Event);
961  
962 p.clone = function() {
963 return new createjs.ErrorEvent(this.title, this.message, this.data);
964 };
965  
966 createjs.ErrorEvent = createjs.promote(ErrorEvent, "Event");
967  
968 }());
969  
970 //##############################################################################
971 // ProgressEvent.js
972 //##############################################################################
973  
974 this.createjs = this.createjs || {};
975  
976 (function (scope) {
977 "use strict";
978  
979 // constructor
980 /**
981 * A CreateJS {{#crossLink "Event"}}{{/crossLink}} that is dispatched when progress changes.
982 * @class ProgressEvent
983 * @param {Number} loaded The amount that has been loaded. This can be any number relative to the total.
984 * @param {Number} [total=1] The total amount that will load. This will default to 1, so if the `loaded` value is
985 * a percentage (between 0 and 1), it can be omitted.
986 * @todo Consider having this event be a "fileprogress" event as well
987 * @constructor
988 */
989 function ProgressEvent(loaded, total) {
990 this.Event_constructor("progress");
991  
992 /**
993 * The amount that has been loaded (out of a total amount)
994 * @property loaded
995 * @type {Number}
996 */
997 this.loaded = loaded;
998  
999 /**
1000 * The total "size" of the load.
1001 * @property total
1002 * @type {Number}
1003 * @default 1
1004 */
1005 this.total = (total == null) ? 1 : total;
1006  
1007 /**
1008 * The percentage (out of 1) that the load has been completed. This is calculated using `loaded/total`.
1009 * @property progress
1010 * @type {Number}
1011 * @default 0
1012 */
1013 this.progress = (total == 0) ? 0 : this.loaded / this.total;
1014 };
1015  
1016 var p = createjs.extend(ProgressEvent, createjs.Event);
1017  
1018 /**
1019 * Returns a clone of the ProgressEvent instance.
1020 * @method clone
1021 * @return {ProgressEvent} a clone of the Event instance.
1022 **/
1023 p.clone = function() {
1024 return new createjs.ProgressEvent(this.loaded, this.total);
1025 };
1026  
1027 createjs.ProgressEvent = createjs.promote(ProgressEvent, "Event");
1028  
1029 }(window));
1030  
1031 //##############################################################################
1032 // LoadItem.js
1033 //##############################################################################
1034  
1035 this.createjs = this.createjs || {};
1036  
1037 (function () {
1038 "use strict";
1039  
1040 /**
1041 * All loaders accept an item containing the properties defined in this class. If a raw object is passed instead,
1042 * it will not be affected, but it must contain at least a {{#crossLink "src:property"}}{{/crossLink}} property. A
1043 * string path or HTML tag is also acceptable, but it will be automatically converted to a LoadItem using the
1044 * {{#crossLink "create"}}{{/crossLink}} method by {{#crossLink "AbstractLoader"}}{{/crossLink}}
1045 * @class LoadItem
1046 * @constructor
1047 * @since 0.6.0
1048 */
1049 function LoadItem() {
1050 /**
1051 * The source of the file that is being loaded. This property is <b>required</b>. The source can either be a
1052 * string (recommended), or an HTML tag.
1053 * This can also be an object, but in that case it has to include a type and be handled by a plugin.
1054 * @property src
1055 * @type {String}
1056 * @default null
1057 */
1058 this.src = null;
1059  
1060 /**
1061 * The type file that is being loaded. The type of the file is usually inferred by the extension, but can also
1062 * be set manually. This is helpful in cases where a file does not have an extension.
1063 * @property type
1064 * @type {String}
1065 * @default null
1066 */
1067 this.type = null;
1068  
1069 /**
1070 * A string identifier which can be used to reference the loaded object. If none is provided, this will be
1071 * automatically set to the {{#crossLink "src:property"}}{{/crossLink}}.
1072 * @property id
1073 * @type {String}
1074 * @default null
1075 */
1076 this.id = null;
1077  
1078 /**
1079 * Determines if a manifest will maintain the order of this item, in relation to other items in the manifest
1080 * that have also set the `maintainOrder` property to `true`. This only applies when the max connections has
1081 * been set above 1 (using {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}). Everything with this
1082 * property set to `false` will finish as it is loaded. Ordered items are combined with script tags loading in
1083 * order when {{#crossLink "LoadQueue/maintainScriptOrder:property"}}{{/crossLink}} is set to `true`.
1084 * @property maintainOrder
1085 * @type {Boolean}
1086 * @default false
1087 */
1088 this.maintainOrder = false;
1089  
1090 /**
1091 * A callback used by JSONP requests that defines what global method to call when the JSONP content is loaded.
1092 * @property callback
1093 * @type {String}
1094 * @default null
1095 */
1096 this.callback = null;
1097  
1098 /**
1099 * An arbitrary data object, which is included with the loaded object.
1100 * @property data
1101 * @type {Object}
1102 * @default null
1103 */
1104 this.data = null;
1105  
1106 /**
1107 * The request method used for HTTP calls. Both {{#crossLink "AbstractLoader/GET:property"}}{{/crossLink}} or
1108 * {{#crossLink "AbstractLoader/POST:property"}}{{/crossLink}} request types are supported, and are defined as
1109 * constants on {{#crossLink "AbstractLoader"}}{{/crossLink}}.
1110 * @property method
1111 * @type {String}
1112 * @default get
1113 */
1114 this.method = createjs.LoadItem.GET;
1115  
1116 /**
1117 * An object hash of name/value pairs to send to the server.
1118 * @property values
1119 * @type {Object}
1120 * @default null
1121 */
1122 this.values = null;
1123  
1124 /**
1125 * An object hash of headers to attach to an XHR request. PreloadJS will automatically attach some default
1126 * headers when required, including "Origin", "Content-Type", and "X-Requested-With". You may override the
1127 * default headers by including them in your headers object.
1128 * @property headers
1129 * @type {Object}
1130 * @default null
1131 */
1132 this.headers = null;
1133  
1134 /**
1135 * Enable credentials for XHR requests.
1136 * @property withCredentials
1137 * @type {Boolean}
1138 * @default false
1139 */
1140 this.withCredentials = false;
1141  
1142 /**
1143 * Set the mime type of XHR-based requests. This is automatically set to "text/plain; charset=utf-8" for text
1144 * based files (json, xml, text, css, js).
1145 * @property mimeType
1146 * @type {String}
1147 * @default null
1148 */
1149 this.mimeType = null;
1150  
1151 /**
1152 * Sets the crossOrigin attribute for CORS-enabled images loading cross-domain.
1153 * @property crossOrigin
1154 * @type {boolean}
1155 * @default Anonymous
1156 */
1157 this.crossOrigin = null;
1158  
1159 /**
1160 * The duration in milliseconds to wait before a request times out. This only applies to tag-based and and XHR
1161 * (level one) loading, as XHR (level 2) provides its own timeout event.
1162 * @property loadTimeout
1163 * @type {Number}
1164 * @default 8000 (8 seconds)
1165 */
1166 this.loadTimeout = s.LOAD_TIMEOUT_DEFAULT;
1167 };
1168  
1169 var p = LoadItem.prototype = {};
1170 var s = LoadItem;
1171  
1172 /**
1173 * Default duration in milliseconds to wait before a request times out. This only applies to tag-based and and XHR
1174 * (level one) loading, as XHR (level 2) provides its own timeout event.
1175 * @property LOAD_TIMEOUT_DEFAULT
1176 * @type {number}
1177 * @static
1178 */
1179 s.LOAD_TIMEOUT_DEFAULT = 8000;
1180  
1181 /**
1182 * Create a LoadItem.
1183 * <ul>
1184 * <li>String-based items are converted to a LoadItem with a populated {{#crossLink "src:property"}}{{/crossLink}}.</li>
1185 * <li>LoadItem instances are returned as-is</li>
1186 * <li>Objects are returned with any needed properties added</li>
1187 * </ul>
1188 * @method create
1189 * @param {LoadItem|String|Object} value The load item value
1190 * @returns {LoadItem|Object}
1191 * @static
1192 */
1193 s.create = function (value) {
1194 if (typeof value == "string") {
1195 var item = new LoadItem();
1196 item.src = value;
1197 return item;
1198 } else if (value instanceof s) {
1199 return value;
1200 } else if (value instanceof Object && value.src) {
1201 if (value.loadTimeout == null) {
1202 value.loadTimeout = s.LOAD_TIMEOUT_DEFAULT;
1203 }
1204 return value;
1205 } else {
1206 throw new Error("Type not recognized.");
1207 }
1208 };
1209  
1210 /**
1211 * Provides a chainable shortcut method for setting a number of properties on the instance.
1212 *
1213 * <h4>Example</h4>
1214 *
1215 * var loadItem = new createjs.LoadItem().set({src:"image.png", maintainOrder:true});
1216 *
1217 * @method set
1218 * @param {Object} props A generic object containing properties to copy to the LoadItem instance.
1219 * @return {LoadItem} Returns the instance the method is called on (useful for chaining calls.)
1220 */
1221 p.set = function(props) {
1222 for (var n in props) { this[n] = props[n]; }
1223 return this;
1224 };
1225  
1226 createjs.LoadItem = s;
1227  
1228 }());
1229  
1230 //##############################################################################
1231 // RequestUtils.js
1232 //##############################################################################
1233  
1234 (function () {
1235  
1236 /**
1237 * Utilities that assist with parsing load items, and determining file types, etc.
1238 * @class RequestUtils
1239 */
1240 var s = {};
1241  
1242 /**
1243 * The Regular Expression used to test file URLS for an absolute path.
1244 * @property ABSOLUTE_PATH
1245 * @type {RegExp}
1246 * @static
1247 */
1248 s.ABSOLUTE_PATT = /^(?:\w+:)?\/{2}/i;
1249  
1250 /**
1251 * The Regular Expression used to test file URLS for a relative path.
1252 * @property RELATIVE_PATH
1253 * @type {RegExp}
1254 * @static
1255 */
1256 s.RELATIVE_PATT = (/^[./]*?\//i);
1257  
1258 /**
1259 * The Regular Expression used to test file URLS for an extension. Note that URIs must already have the query string
1260 * removed.
1261 * @property EXTENSION_PATT
1262 * @type {RegExp}
1263 * @static
1264 */
1265 s.EXTENSION_PATT = /\/?[^/]+\.(\w{1,5})$/i;
1266  
1267 /**
1268 * Parse a file path to determine the information we need to work with it. Currently, PreloadJS needs to know:
1269 * <ul>
1270 * <li>If the path is absolute. Absolute paths start with a protocol (such as `http://`, `file://`, or
1271 * `//networkPath`)</li>
1272 * <li>If the path is relative. Relative paths start with `../` or `/path` (or similar)</li>
1273 *
  • The file extension. This is determined by the filename with an extension. Query strings are dropped, and
  • 1274
  • * the file path is expected to follow the format `name.ext`.li>
  • 1275
  • * </ul>
  • 1276
  • * @method parseURI
  • 1277
  • * @param {String} path
  • 1278
  • * @returns {Object} An Object with an `absolute` and `relative` Boolean values, as well as an optional 'extension`
  • 1279
  • * property, which is the lowercase extension.
  • 1280
  • * @static
  • 1281
  • */
  • 1282
  • s.parseURI = function (path) {
  • 1283
  • var info = {absolute: false, relative: false};
  • 1284
  • if (path == null) { return info; }
  • 1285  
    1286
  • // Drop the query string
  • 1287
  • var queryIndex = path.indexOf("?");
  • 1288
  • if (queryIndex > -1) {
  • 1289
  • path = path.substr(0, queryIndex);
  • 1290
  • }
  • 1291  
    1292
  • // Absolute
  • 1293
  • var match;
  • 1294
  • if (s.ABSOLUTE_PATT.test(path)) {
  • 1295
  • info.absolute = true;
  • 1296  
    1297
  • // Relative
  • 1298
  • } else if (s.RELATIVE_PATT.test(path)) {
  • 1299
  • info.relative = true;
  • 1300
  • }
  • 1301  
    1302
  • // Extension
  • 1303
  • if (match = path.match(s.EXTENSION_PATT)) {
  • 1304
  • info.extension = match[1].toLowerCase();
  • 1305
  • }
  • 1306
  • return info;
  • 1307
  • };
  • 1308  
    1309
  • /**
  • 1310
  • * Formats an object into a query string for either a POST or GET request.
  • 1311
  • * @method formatQueryString
  • 1312
  • * @param {Object} data The data to convert to a query string.
  • 1313
  • * @param {Array} [query] Existing name/value pairs to append on to this query.
  • 1314
  • * @static
  • 1315
  • */
  • 1316
  • s.formatQueryString = function (data, query) {
  • 1317
  • if (data == null) {
  • 1318
  • throw new Error('You must specify data.');
  • 1319
  • }
  • 1320
  • var params = [];
  • 1321
  • for (var n in data) {
  • 1322
  • params.push(n + '=' + escape(data[n]));
  • 1323
  • }
  • 1324
  • if (query) {
  • 1325
  • params = params.concat(query);
  • 1326
  • }
  • 1327
  • return params.join('&');
  • 1328
  • };
  • 1329  
    1330
  • /**
  • 1331
  • * A utility method that builds a file path using a source and a data object, and formats it into a new path.
  • 1332
  • * @method buildPath
  • 1333
  • * @param {String} src The source path to add values to.
  • 1334
  • * @param {Object} [data] Object used to append values to this request as a query string. Existing parameters on the
  • 1335
  • * path will be preserved.
  • 1336
  • * @returns {string} A formatted string that contains the path and the supplied parameters.
  • 1337
  • * @static
  • 1338
  • */
  • 1339
  • s.buildPath = function (src, data) {
  • 1340
  • if (data == null) {
  • 1341
  • return src;
  • 1342
  • }
  • 1343  
    1344
  • var query = [];
  • 1345
  • var idx = src.indexOf('?');
  • 1346  
    1347
  • if (idx != -1) {
  • 1348
  • var q = src.slice(idx + 1);
  • 1349
  • query = query.concat(q.split('&'));
  • 1350
  • }
  • 1351  
    1352
  • if (idx != -1) {
  • 1353
  • return src.slice(0, idx) + '?' + this.formatQueryString(data, query);
  • 1354
  • } else {
  • 1355
  • return src + '?' + this.formatQueryString(data, query);
  • 1356
  • }
  • 1357
  • };
  • 1358  
    1359
  • /**
  • 1360
  • * @method isCrossDomain
  • 1361
  • * @param {LoadItem|Object} item A load item with a `src` property.
  • 1362
  • * @return {Boolean} If the load item is loading from a different domain than the current location.
  • 1363
  • * @static
  • 1364
  • */
  • 1365
  • s.isCrossDomain = function (item) {
  • 1366
  • var target = document.createElement("a");
  • 1367
  • target.href = item.src;
  • 1368  
    1369
  • var host = document.createElement("a");
  • 1370
  • host.href = location.href;
  • 1371  
    1372
  • var crossdomain = (target.hostname != "") &&
  • 1373
  • (target.port != host.port ||
  • 1374
  • target.protocol != host.protocol ||
  • 1375
  • target.hostname != host.hostname);
  • 1376
  • return crossdomain;
  • 1377
  • };
  • 1378  
    1379
  • /**
  • 1380
  • * @method isLocal
  • 1381
  • * @param {LoadItem|Object} item A load item with a `src` property
  • 1382
  • * @return {Boolean} If the load item is loading from the "file:" protocol. Assume that the host must be local as
  • 1383
  • * well.
  • 1384
  • * @static
  • 1385
  • */
  • 1386
  • s.isLocal = function (item) {
  • 1387
  • var target = document.createElement("a");
  • 1388
  • target.href = item.src;
  • 1389
  • return target.hostname == "" && target.protocol == "file:";
  • 1390
  • };
  • 1391  
    1392
  • /**
  • 1393
  • * Determine if a specific type should be loaded as a binary file. Currently, only images and items marked
  • 1394
  • * specifically as "binary" are loaded as binary. Note that audio is <b>not</b> a binary type, as we can not play
  • 1395
  • * back using an audio tag if it is loaded as binary. Plugins can change the item type to binary to ensure they get
  • 1396
  • * a binary result to work with. Binary files are loaded using XHR2. Types are defined as static constants on
  • 1397
  • * {{#crossLink "AbstractLoader"}}{{/crossLink}}.
  • 1398
  • * @method isBinary
  • 1399
  • * @param {String} type The item type.
  • 1400
  • * @return {Boolean} If the specified type is binary.
  • 1401
  • * @static
  • 1402
  • */
  • 1403
  • s.isBinary = function (type) {
  • 1404
  • switch (type) {
  • 1405
  • case createjs.AbstractLoader.IMAGE:
  • 1406
  • case createjs.AbstractLoader.BINARY:
  • 1407
  • return true;
  • 1408
  • default:
  • 1409
  • return false;
  • 1410
  • }
  • 1411
  • };
  • 1412  
    1413
  • /**
  • 1414
  • * Check if item is a valid HTMLImageElement
  • 1415
  • * @method isImageTag
  • 1416
  • * @param {Object} item
  • 1417
  • * @returns {Boolean}
  • 1418
  • * @static
  • 1419
  • */
  • 1420
  • s.isImageTag = function(item) {
  • 1421
  • return item instanceof HTMLImageElement;
  • 1422
  • };
  • 1423  
    1424
  • /**
  • 1425
  • * Check if item is a valid HTMLAudioElement
  • 1426
  • * @method isAudioTag
  • 1427
  • * @param {Object} item
  • 1428
  • * @returns {Boolean}
  • 1429
  • * @static
  • 1430
  • */
  • 1431
  • s.isAudioTag = function(item) {
  • 1432
  • if (window.HTMLAudioElement) {
  • 1433
  • return item instanceof HTMLAudioElement;
  • 1434
  • } else {
  • 1435
  • return false;
  • 1436
  • }
  • 1437
  • };
  • 1438  
    1439
  • /**
  • 1440
  • * Check if item is a valid HTMLVideoElement
  • 1441
  • * @method isVideoTag
  • 1442
  • * @param {Object} item
  • 1443
  • * @returns {Boolean}
  • 1444
  • * @static
  • 1445
  • */
  • 1446
  • s.isVideoTag = function(item) {
  • 1447
  • if (window.HTMLVideoElement) {
  • 1448
  • return item instanceof HTMLVideoElement;
  • 1449
  • } else {
  • 1450
  • return false;
  • 1451
  • }
  • 1452
  • };
  • 1453  
    1454
  • /**
  • 1455
  • * Determine if a specific type is a text-based asset, and should be loaded as UTF-8.
  • 1456
  • * @method isText
  • 1457
  • * @param {String} type The item type.
  • 1458
  • * @return {Boolean} If the specified type is text.
  • 1459
  • * @static
  • 1460
  • */
  • 1461
  • s.isText = function (type) {
  • 1462
  • switch (type) {
  • 1463
  • case createjs.AbstractLoader.TEXT:
  • 1464
  • case createjs.AbstractLoader.JSON:
  • 1465
  • case createjs.AbstractLoader.MANIFEST:
  • 1466
  • case createjs.AbstractLoader.XML:
  • 1467
  • case createjs.AbstractLoader.CSS:
  • 1468
  • case createjs.AbstractLoader.SVG:
  • 1469
  • case createjs.AbstractLoader.JAVASCRIPT:
  • 1470
  • case createjs.AbstractLoader.SPRITESHEET:
  • 1471
  • return true;
  • 1472
  • default:
  • 1473
  • return false;
  • 1474
  • }
  • 1475
  • };
  • 1476  
    1477
  • /**
  • 1478
  • * Determine the type of the object using common extensions. Note that the type can be passed in with the load item
  • 1479
  • * if it is an unusual extension.
  • 1480
  • * @method getTypeByExtension
  • 1481
  • * @param {String} extension The file extension to use to determine the load type.
  • 1482
  • * @return {String} The determined load type (for example, <code>AbstractLoader.IMAGE</code>). Will return `null` if
  • 1483
  • * the type can not be determined by the extension.
  • 1484
  • * @static
  • 1485
  • */
  • 1486
  • s.getTypeByExtension = function (extension) {
  • 1487
  • if (extension == null) {
  • 1488
  • return createjs.AbstractLoader.TEXT;
  • 1489
  • }
  • 1490  
    1491
  • switch (extension.toLowerCase()) {
  • 1492
  • case "jpeg":
  • 1493
  • case "jpg":
  • 1494
  • case "gif":
  • 1495
  • case "png":
  • 1496
  • case "webp":
  • 1497
  • case "bmp":
  • 1498
  • return createjs.AbstractLoader.IMAGE;
  • 1499
  • case "ogg":
  • 1500
  • case "mp3":
  • 1501
  • case "webm":
  • 1502
  • return createjs.AbstractLoader.SOUND;
  • 1503
  • case "mp4":
  • 1504
  • case "webm":
  • 1505
  • case "ts":
  • 1506
  • return createjs.AbstractLoader.VIDEO;
  • 1507
  • case "json":
  • 1508
  • return createjs.AbstractLoader.JSON;
  • 1509
  • case "xml":
  • 1510
  • return createjs.AbstractLoader.XML;
  • 1511
  • case "css":
  • 1512
  • return createjs.AbstractLoader.CSS;
  • 1513
  • case "js":
  • 1514
  • return createjs.AbstractLoader.JAVASCRIPT;
  • 1515
  • case 'svg':
  • 1516
  • return createjs.AbstractLoader.SVG;
  • 1517
  • default:
  • 1518
  • return createjs.AbstractLoader.TEXT;
  • 1519
  • }
  • 1520
  • };
  • 1521  
    1522
  • createjs.RequestUtils = s;
  • 1523  
    1524
  • }());
  • 1525  
    1526
  • //##############################################################################
  • 1527
  • // AbstractLoader.js
  • 1528
  • //##############################################################################
  • 1529  
    1530
  • this.createjs = this.createjs || {};
  • 1531  
    1532
  • (function () {
  • 1533
  • "use strict";
  • 1534  
    1535
  • // constructor
  • 1536
  • /**
  • 1537
  • * The base loader, which defines all the generic methods, properties, and events. All loaders extend this class,
  • 1538
  • * including the {{#crossLink "LoadQueue"}}{{/crossLink}}.
  • 1539
  • * @class AbstractLoader
  • 1540
  • * @param {LoadItem|object|string} loadItem The item to be loaded.
  • 1541
  • * @param {Boolean} [preferXHR] Determines if the LoadItem should <em>try</em> and load using XHR, or take a
  • 1542
  • * tag-based approach, which can be better in cross-domain situations. Not all loaders can load using one or the
  • 1543
  • * other, so this is a suggested directive.
  • 1544
  • * @param {String} [type] The type of loader. Loader types are defined as constants on the AbstractLoader class,
  • 1545
  • * such as {{#crossLink "IMAGE:property"}}{{/crossLink}}, {{#crossLink "CSS:property"}}{{/crossLink}}, etc.
  • 1546
  • * @extends EventDispatcher
  • 1547
  • */
  • 1548
  • function AbstractLoader(loadItem, preferXHR, type) {
  • 1549
  • this.EventDispatcher_constructor();
  • 1550  
    1551
  • // public properties
  • 1552
  • /**
  • 1553
  • * If the loader has completed loading. This provides a quick check, but also ensures that the different approaches
  • 1554
  • * used for loading do not pile up resulting in more than one `complete` {{#crossLink "Event"}}{{/crossLink}}.
  • 1555
  • * @property loaded
  • 1556
  • * @type {Boolean}
  • 1557
  • * @default false
  • 1558
  • */
  • 1559
  • this.loaded = false;
  • 1560  
    1561
  • /**
  • 1562
  • * Determine if the loader was canceled. Canceled loads will not fire complete events. Note that this property
  • 1563
  • * is readonly, so {{#crossLink "LoadQueue"}}{{/crossLink}} queues should be closed using {{#crossLink "LoadQueue/close"}}{{/crossLink}}
  • 1564
  • * instead.
  • 1565
  • * @property canceled
  • 1566
  • * @type {Boolean}
  • 1567
  • * @default false
  • 1568
  • * @readonly
  • 1569
  • */
  • 1570
  • this.canceled = false;
  • 1571  
    1572
  • /**
  • 1573
  • * The current load progress (percentage) for this item. This will be a number between 0 and 1.
  • 1574
  • *
  • 1575
  • * <h4>Example</h4>
  • 1576
  • *
  • 1577
  • * var queue = new createjs.LoadQueue();
  • 1578
  • * queue.loadFile("largeImage.png");
  • 1579
  • * queue.on("progress", function() {
  • 1580
  • * console.log("Progress:", queue.progress, event.progress);
  • 1581
  • * });
  • 1582
  • *
  • 1583
  • * @property progress
  • 1584
  • * @type {Number}
  • 1585
  • * @default 0
  • 1586
  • */
  • 1587
  • this.progress = 0;
  • 1588  
    1589
  • /**
  • 1590
  • * The type of item this loader will load. See {{#crossLink "AbstractLoader"}}{{/crossLink}} for a full list of
  • 1591
  • * supported types.
  • 1592
  • * @property type
  • 1593
  • * @type {String}
  • 1594
  • */
  • 1595
  • this.type = type;
  • 1596  
    1597
  • /**
  • 1598
  • * A formatter function that converts the loaded raw result into the final result. For example, the JSONLoader
  • 1599
  • * converts a string of text into a JavaScript object. Not all loaders have a resultFormatter, and this property
  • 1600
  • * can be overridden to provide custom formatting.
  • 1601
  • *
  • 1602
  • * Optionally, a resultFormatter can return a callback function in cases where the formatting needs to be
  • 1603
  • * asynchronous, such as creating a new image. The callback function is passed 2 parameters, which are callbacks
  • 1604
  • * to handle success and error conditions in the resultFormatter. Note that the resultFormatter method is
  • 1605
  • * called in the current scope, as well as the success and error callbacks.
  • 1606
  • *
  • 1607
  • * <h4>Example asynchronous resultFormatter</h4>
  • 1608
  • *
  • 1609
  • * function _formatResult(loader) {
  • 1610
  • * return function(success, error) {
  • 1611
  • * if (errorCondition) { error(errorDetailEvent); }
  • 1612
  • * success(result);
  • 1613
  • * }
  • 1614
  • * }
  • 1615
  • * @property resultFormatter
  • 1616
  • * @type {Function}
  • 1617
  • * @default null
  • 1618
  • */
  • 1619
  • this.resultFormatter = null;
  • 1620  
    1621
  • // protected properties
  • 1622
  • /**
  • 1623
  • * The {{#crossLink "LoadItem"}}{{/crossLink}} this loader represents. Note that this is null in a {{#crossLink "LoadQueue"}}{{/crossLink}},
  • 1624
  • * but will be available on loaders such as {{#crossLink "XMLLoader"}}{{/crossLink}} and {{#crossLink "ImageLoader"}}{{/crossLink}}.
  • 1625
  • * @property _item
  • 1626
  • * @type {LoadItem|Object}
  • 1627
  • * @private
  • 1628
  • */
  • 1629
  • if (loadItem) {
  • 1630
  • this._item = createjs.LoadItem.create(loadItem);
  • 1631
  • } else {
  • 1632
  • this._item = null;
  • 1633
  • }
  • 1634  
    1635
  • /**
  • 1636
  • * Whether the loader will try and load content using XHR (true) or HTML tags (false).
  • 1637
  • * @property _preferXHR
  • 1638
  • * @type {Boolean}
  • 1639
  • * @private
  • 1640
  • */
  • 1641
  • this._preferXHR = preferXHR;
  • 1642  
    1643
  • /**
  • 1644
  • * The loaded result after it is formatted by an optional {{#crossLink "resultFormatter"}}{{/crossLink}}. For
  • 1645
  • * items that are not formatted, this will be the same as the {{#crossLink "_rawResult:property"}}{{/crossLink}}.
  • 1646
  • * The result is accessed using the {{#crossLink "getResult"}}{{/crossLink}} method.
  • 1647
  • * @property _result
  • 1648
  • * @type {Object|String}
  • 1649
  • * @private
  • 1650
  • */
  • 1651
  • this._result = null;
  • 1652  
    1653
  • /**
  • 1654
  • * The loaded result before it is formatted. The rawResult is accessed using the {{#crossLink "getResult"}}{{/crossLink}}
  • 1655
  • * method, and passing `true`.
  • 1656
  • * @property _rawResult
  • 1657
  • * @type {Object|String}
  • 1658
  • * @private
  • 1659
  • */
  • 1660
  • this._rawResult = null;
  • 1661  
    1662
  • /**
  • 1663
  • * A list of items that loaders load behind the scenes. This does not include the main item the loader is
  • 1664
  • * responsible for loading. Examples of loaders that have sub-items include the {{#crossLink "SpriteSheetLoader"}}{{/crossLink}} and
  • 1665
  • * {{#crossLink "ManifestLoader"}}{{/crossLink}}.
  • 1666
  • * @property _loadItems
  • 1667
  • * @type {null}
  • 1668
  • * @protected
  • 1669
  • */
  • 1670
  • this._loadedItems = null;
  • 1671  
    1672
  • /**
  • 1673
  • * The attribute the items loaded using tags use for the source.
  • 1674
  • * @type {string}
  • 1675
  • * @default null
  • 1676
  • * @private
  • 1677
  • */
  • 1678
  • this._tagSrcAttribute = null;
  • 1679  
    1680
  • /**
  • 1681
  • * An HTML tag (or similar) that a loader may use to load HTML content, such as images, scripts, etc.
  • 1682
  • * @property _tag
  • 1683
  • * @type {Object}
  • 1684
  • * @private
  • 1685
  • */
  • 1686
  • this._tag = null;
  • 1687
  • };
  • 1688  
    1689
  • var p = createjs.extend(AbstractLoader, createjs.EventDispatcher);
  • 1690
  • var s = AbstractLoader;
  • 1691  
    1692
  • // TODO: deprecated
  • 1693
  • // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.
  • 1694  
    1695  
    1696
  • /**
  • 1697
  • * Defines a POST request, use for a method value when loading data.
  • 1698
  • * @property POST
  • 1699
  • * @type {string}
  • 1700
  • * @default post
  • 1701
  • * @static
  • 1702
  • */
  • 1703
  • s.POST = "POST";
  • 1704  
    1705
  • /**
  • 1706
  • * Defines a GET request, use for a method value when loading data.
  • 1707
  • * @property GET
  • 1708
  • * @type {string}
  • 1709
  • * @default get
  • 1710
  • * @static
  • 1711
  • */
  • 1712
  • s.GET = "GET";
  • 1713  
    1714
  • /**
  • 1715
  • * The preload type for generic binary types. Note that images are loaded as binary files when using XHR.
  • 1716
  • * @property BINARY
  • 1717
  • * @type {String}
  • 1718
  • * @default binary
  • 1719
  • * @static
  • 1720
  • * @since 0.6.0
  • 1721
  • */
  • 1722
  • s.BINARY = "binary";
  • 1723  
    1724
  • /**
  • 1725
  • * The preload type for css files. CSS files are loaded using a &lt;link&gt; when loaded with XHR, or a
  • 1726
  • * &lt;style&gt; tag when loaded with tags.
  • 1727
  • * @property CSS
  • 1728
  • * @type {String}
  • 1729
  • * @default css
  • 1730
  • * @static
  • 1731
  • * @since 0.6.0
  • 1732
  • */
  • 1733
  • s.CSS = "css";
  • 1734  
    1735
  • /**
  • 1736
  • * The preload type for image files, usually png, gif, or jpg/jpeg. Images are loaded into an &lt;image&gt; tag.
  • 1737
  • * @property IMAGE
  • 1738
  • * @type {String}
  • 1739
  • * @default image
  • 1740
  • * @static
  • 1741
  • * @since 0.6.0
  • 1742
  • */
  • 1743
  • s.IMAGE = "image";
  • 1744  
    1745
  • /**
  • 1746
  • * The preload type for javascript files, usually with the "js" file extension. JavaScript files are loaded into a
  • 1747
  • * &lt;script&gt; tag.
  • 1748
  • *
  • 1749
  • * Since version 0.4.1+, due to how tag-loaded scripts work, all JavaScript files are automatically injected into
  • 1750
  • * the body of the document to maintain parity between XHR and tag-loaded scripts. In version 0.4.0 and earlier,
  • 1751
  • * only tag-loaded scripts are injected.
  • 1752
  • * @property JAVASCRIPT
  • 1753
  • * @type {String}
  • 1754
  • * @default javascript
  • 1755
  • * @static
  • 1756
  • * @since 0.6.0
  • 1757
  • */
  • 1758
  • s.JAVASCRIPT = "javascript";
  • 1759  
    1760
  • /**
  • 1761
  • * The preload type for json files, usually with the "json" file extension. JSON data is loaded and parsed into a
  • 1762
  • * JavaScript object. Note that if a `callback` is present on the load item, the file will be loaded with JSONP,
  • 1763
  • * no matter what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property is set to, and the JSON
  • 1764
  • * must contain a matching wrapper function.
  • 1765
  • * @property JSON
  • 1766
  • * @type {String}
  • 1767
  • * @default json
  • 1768
  • * @static
  • 1769
  • * @since 0.6.0
  • 1770
  • */
  • 1771
  • s.JSON = "json";
  • 1772  
    1773
  • /**
  • 1774
  • * The preload type for jsonp files, usually with the "json" file extension. JSON data is loaded and parsed into a
  • 1775
  • * JavaScript object. You are required to pass a callback parameter that matches the function wrapper in the JSON.
  • 1776
  • * Note that JSONP will always be used if there is a callback present, no matter what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}}
  • 1777
  • * property is set to.
  • 1778
  • * @property JSONP
  • 1779
  • * @type {String}
  • 1780
  • * @default jsonp
  • 1781
  • * @static
  • 1782
  • * @since 0.6.0
  • 1783
  • */
  • 1784
  • s.JSONP = "jsonp";
  • 1785  
    1786
  • /**
  • 1787
  • * The preload type for json-based manifest files, usually with the "json" file extension. The JSON data is loaded
  • 1788
  • * and parsed into a JavaScript object. PreloadJS will then look for a "manifest" property in the JSON, which is an
  • 1789
  • * Array of files to load, following the same format as the {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}
  • 1790
  • * method. If a "callback" is specified on the manifest object, then it will be loaded using JSONP instead,
  • 1791
  • * regardless of what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property is set to.
  • 1792
  • * @property MANIFEST
  • 1793
  • * @type {String}
  • 1794
  • * @default manifest
  • 1795
  • * @static
  • 1796
  • * @since 0.6.0
  • 1797
  • */
  • 1798
  • s.MANIFEST = "manifest";
  • 1799  
    1800
  • /**
  • 1801
  • * The preload type for sound files, usually mp3, ogg, or wav. When loading via tags, audio is loaded into an
  • 1802
  • * &lt;audio&gt; tag.
  • 1803
  • * @property SOUND
  • 1804
  • * @type {String}
  • 1805
  • * @default sound
  • 1806
  • * @static
  • 1807
  • * @since 0.6.0
  • 1808
  • */
  • 1809
  • s.SOUND = "sound";
  • 1810  
    1811
  • /**
  • 1812
  • * The preload type for video files, usually mp4, ts, or ogg. When loading via tags, video is loaded into an
  • 1813
  • * &lt;video&gt; tag.
  • 1814
  • * @property VIDEO
  • 1815
  • * @type {String}
  • 1816
  • * @default video
  • 1817
  • * @static
  • 1818
  • * @since 0.6.0
  • 1819
  • */
  • 1820
  • s.VIDEO = "video";
  • 1821  
    1822
  • /**
  • 1823
  • * The preload type for SpriteSheet files. SpriteSheet files are JSON files that contain string image paths.
  • 1824
  • * @property SPRITESHEET
  • 1825
  • * @type {String}
  • 1826
  • * @default spritesheet
  • 1827
  • * @static
  • 1828
  • * @since 0.6.0
  • 1829
  • */
  • 1830
  • s.SPRITESHEET = "spritesheet";
  • 1831  
    1832
  • /**
  • 1833
  • * The preload type for SVG files.
  • 1834
  • * @property SVG
  • 1835
  • * @type {String}
  • 1836
  • * @default svg
  • 1837
  • * @static
  • 1838
  • * @since 0.6.0
  • 1839
  • */
  • 1840
  • s.SVG = "svg";
  • 1841  
    1842
  • /**
  • 1843
  • * The preload type for text files, which is also the default file type if the type can not be determined. Text is
  • 1844
  • * loaded as raw text.
  • 1845
  • * @property TEXT
  • 1846
  • * @type {String}
  • 1847
  • * @default text
  • 1848
  • * @static
  • 1849
  • * @since 0.6.0
  • 1850
  • */
  • 1851
  • s.TEXT = "text";
  • 1852  
    1853
  • /**
  • 1854
  • * The preload type for xml files. XML is loaded into an XML document.
  • 1855
  • * @property XML
  • 1856
  • * @type {String}
  • 1857
  • * @default xml
  • 1858
  • * @static
  • 1859
  • * @since 0.6.0
  • 1860
  • */
  • 1861
  • s.XML = "xml";
  • 1862  
    1863
  • // Events
  • 1864
  • /**
  • 1865
  • * The {{#crossLink "ProgressEvent"}}{{/crossLink}} that is fired when the overall progress changes. Prior to
  • 1866
  • * version 0.6.0, this was just a regular {{#crossLink "Event"}}{{/crossLink}}.
  • 1867
  • * @event progress
  • 1868
  • * @since 0.3.0
  • 1869
  • */
  • 1870  
    1871
  • /**
  • 1872
  • * The {{#crossLink "Event"}}{{/crossLink}} that is fired when a load starts.
  • 1873
  • * @event loadstart
  • 1874
  • * @param {Object} target The object that dispatched the event.
  • 1875
  • * @param {String} type The event type.
  • 1876
  • * @since 0.3.1
  • 1877
  • */
  • 1878  
    1879
  • /**
  • 1880
  • * The {{#crossLink "Event"}}{{/crossLink}} that is fired when the entire queue has been loaded.
  • 1881
  • * @event complete
  • 1882
  • * @param {Object} target The object that dispatched the event.
  • 1883
  • * @param {String} type The event type.
  • 1884
  • * @since 0.3.0
  • 1885
  • */
  • 1886  
    1887
  • /**
  • 1888
  • * The {{#crossLink "ErrorEvent"}}{{/crossLink}} that is fired when the loader encounters an error. If the error was
  • 1889
  • * encountered by a file, the event will contain the item that caused the error. Prior to version 0.6.0, this was
  • 1890
  • * just a regular {{#crossLink "Event"}}{{/crossLink}}.
  • 1891
  • * @event error
  • 1892
  • * @since 0.3.0
  • 1893
  • */
  • 1894  
    1895
  • /**
  • 1896
  • * The {{#crossLink "Event"}}{{/crossLink}} that is fired when the loader encounters an internal file load error.
  • 1897
  • * This enables loaders to maintain internal queues, and surface file load errors.
  • 1898
  • * @event fileerror
  • 1899
  • * @param {Object} target The object that dispatched the event.
  • 1900
  • * @param {String} type The even type ("fileerror")
  • 1901
  • * @param {LoadItem|object} The item that encountered the error
  • 1902
  • * @since 0.6.0
  • 1903
  • */
  • 1904  
    1905
  • /**
  • 1906
  • * The {{#crossLink "Event"}}{{/crossLink}} that is fired when a loader internally loads a file. This enables
  • 1907
  • * loaders such as {{#crossLink "ManifestLoader"}}{{/crossLink}} to maintain internal {{#crossLink "LoadQueue"}}{{/crossLink}}s
  • 1908
  • * and notify when they have loaded a file. The {{#crossLink "LoadQueue"}}{{/crossLink}} class dispatches a
  • 1909
  • * slightly different {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event.
  • 1910
  • * @event fileload
  • 1911
  • * @param {Object} target The object that dispatched the event.
  • 1912
  • * @param {String} type The event type ("fileload")
  • 1913
  • * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}}
  • 1914
  • * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the
  • 1915
  • * object will contain that value as a `src` property.
  • 1916
  • * @param {Object} result The HTML tag or parsed result of the loaded item.
  • 1917
  • * @param {Object} rawResult The unprocessed result, usually the raw text or binary data before it is converted
  • 1918
  • * to a usable object.
  • 1919
  • * @since 0.6.0
  • 1920
  • */
  • 1921  
    1922
  • /**
  • 1923
  • * The {{#crossLink "Event"}}{{/crossLink}} that is fired after the internal request is created, but before a load.
  • 1924
  • * This allows updates to the loader for specific loading needs, such as binary or XHR image loading.
  • 1925
  • * @event initialize
  • 1926
  • * @param {Object} target The object that dispatched the event.
  • 1927
  • * @param {String} type The event type ("initialize")
  • 1928
  • * @param {AbstractLoader} loader The loader that has been initialized.
  • 1929
  • */
  • 1930  
    1931  
    1932
  • /**
  • 1933
  • * Get a reference to the manifest item that is loaded by this loader. In some cases this will be the value that was
  • 1934
  • * passed into {{#crossLink "LoadQueue"}}{{/crossLink}} using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or
  • 1935
  • * {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. However if only a String path was passed in, then it will
  • 1936
  • * be a {{#crossLink "LoadItem"}}{{/crossLink}}.
  • 1937
  • * @method getItem
  • 1938
  • * @return {Object} The manifest item that this loader is responsible for loading.
  • 1939
  • * @since 0.6.0
  • 1940
  • */
  • 1941
  • p.getItem = function () {
  • 1942
  • return this._item;
  • 1943
  • };
  • 1944  
    1945
  • /**
  • 1946
  • * Get a reference to the content that was loaded by the loader (only available after the {{#crossLink "complete:event"}}{{/crossLink}}
  • 1947
  • * event is dispatched.
  • 1948
  • * @method getResult
  • 1949
  • * @param {Boolean} [raw=false] Determines if the returned result will be the formatted content, or the raw loaded
  • 1950
  • * data (if it exists).
  • 1951
  • * @return {Object}
  • 1952
  • * @since 0.6.0
  • 1953
  • */
  • 1954
  • p.getResult = function (raw) {
  • 1955
  • return raw ? this._rawResult : this._result;
  • 1956
  • };
  • 1957  
    1958
  • /**
  • 1959
  • * Return the `tag` this object creates or uses for loading.
  • 1960
  • * @method getTag
  • 1961
  • * @return {Object} The tag instance
  • 1962
  • * @since 0.6.0
  • 1963
  • */
  • 1964
  • p.getTag = function () {
  • 1965
  • return this._tag;
  • 1966
  • };
  • 1967  
    1968
  • /**
  • 1969
  • * Set the `tag` this item uses for loading.
  • 1970
  • * @method setTag
  • 1971
  • * @param {Object} tag The tag instance
  • 1972
  • * @since 0.6.0
  • 1973
  • */
  • 1974
  • p.setTag = function(tag) {
  • 1975
  • this._tag = tag;
  • 1976
  • };
  • 1977  
    1978
  • /**
  • 1979
  • * Begin loading the item. This method is required when using a loader by itself.
  • 1980
  • *
  • 1981
  • * <h4>Example</h4>
  • 1982
  • *
  • 1983
  • * var queue = new createjs.LoadQueue();
  • 1984
  • * queue.on("complete", handleComplete);
  • 1985
  • * queue.loadManifest(fileArray, false); // Note the 2nd argument that tells the queue not to start loading yet
  • 1986
  • * queue.load();
  • 1987
  • *
  • 1988
  • * @method load
  • 1989
  • */
  • 1990
  • p.load = function () {
  • 1991
  • this._createRequest();
  • 1992  
    1993
  • this._request.on("complete", this, this);
  • 1994
  • this._request.on("progress", this, this);
  • 1995
  • this._request.on("loadStart", this, this);
  • 1996
  • this._request.on("abort", this, this);
  • 1997
  • this._request.on("timeout", this, this);
  • 1998
  • this._request.on("error", this, this);
  • 1999  
    2000
  • var evt = new createjs.Event("initialize");
  • 2001
  • evt.loader = this._request;
  • 2002
  • this.dispatchEvent(evt);
  • 2003  
    2004
  • this._request.load();
  • 2005
  • };
  • 2006  
    2007
  • /**
  • 2008
  • * Close the the item. This will stop any open requests (although downloads using HTML tags may still continue in
  • 2009
  • * the background), but events will not longer be dispatched.
  • 2010
  • * @method cancel
  • 2011
  • */
  • 2012
  • p.cancel = function () {
  • 2013
  • this.canceled = true;
  • 2014
  • this.destroy();
  • 2015
  • };
  • 2016  
    2017
  • /**
  • 2018
  • * Clean up the loader.
  • 2019
  • * @method destroy
  • 2020
  • */
  • 2021
  • p.destroy = function() {
  • 2022
  • if (this._request) {
  • 2023
  • this._request.removeAllEventListeners();
  • 2024
  • this._request.destroy();
  • 2025
  • }
  • 2026  
    2027
  • this._request = null;
  • 2028  
    2029
  • this._item = null;
  • 2030
  • this._rawResult = null;
  • 2031
  • this._result = null;
  • 2032  
    2033
  • this._loadItems = null;
  • 2034  
    2035
  • this.removeAllEventListeners();
  • 2036
  • };
  • 2037  
    2038
  • /**
  • 2039
  • * Get any items loaded internally by the loader. The enables loaders such as {{#crossLink "ManifestLoader"}}{{/crossLink}}
  • 2040
  • * to expose items it loads internally.
  • 2041
  • * @method getLoadedItems
  • 2042
  • * @return {Array} A list of the items loaded by the loader.
  • 2043
  • * @since 0.6.0
  • 2044
  • */
  • 2045
  • p.getLoadedItems = function () {
  • 2046
  • return this._loadedItems;
  • 2047
  • };
  • 2048  
    2049  
    2050
  • // Private methods
  • 2051
  • /**
  • 2052
  • * Create an internal request used for loading. By default, an {{#crossLink "XHRRequest"}}{{/crossLink}} or
  • 2053
  • * {{#crossLink "TagRequest"}}{{/crossLink}} is created, depending on the value of {{#crossLink "preferXHR:property"}}{{/crossLink}}.
  • 2054
  • * Other loaders may override this to use different request types, such as {{#crossLink "ManifestLoader"}}{{/crossLink}},
  • 2055
  • * which uses {{#crossLink "JSONLoader"}}{{/crossLink}} or {{#crossLink "JSONPLoader"}}{{/crossLink}} under the hood.
  • 2056
  • * @method _createRequest
  • 2057
  • * @protected
  • 2058
  • */
  • 2059
  • p._createRequest = function() {
  • 2060
  • if (!this._preferXHR) {
  • 2061
  • this._request = new createjs.TagRequest(this._item, this._tag || this._createTag(), this._tagSrcAttribute);
  • 2062
  • } else {
  • 2063
  • this._request = new createjs.XHRRequest(this._item);
  • 2064
  • }
  • 2065
  • };
  • 2066  
    2067
  • /**
  • 2068
  • * Create the HTML tag used for loading. This method does nothing by default, and needs to be implemented
  • 2069
  • * by loaders that require tag loading.
  • 2070
  • * @method _createTag
  • 2071
  • * @param {String} src The tag source
  • 2072
  • * @return {HTMLElement} The tag that was created
  • 2073
  • * @protected
  • 2074
  • */
  • 2075
  • p._createTag = function(src) { return null; };
  • 2076  
    2077
  • /**
  • 2078
  • * Dispatch a loadstart {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/loadstart:event"}}{{/crossLink}}
  • 2079
  • * event for details on the event payload.
  • 2080
  • * @method _sendLoadStart
  • 2081
  • * @protected
  • 2082
  • */
  • 2083
  • p._sendLoadStart = function () {
  • 2084
  • if (this._isCanceled()) { return; }
  • 2085
  • this.dispatchEvent("loadstart");
  • 2086
  • };
  • 2087  
    2088
  • /**
  • 2089
  • * Dispatch a {{#crossLink "ProgressEvent"}}{{/crossLink}}.
  • 2090
  • * @method _sendProgress
  • 2091
  • * @param {Number | Object} value The progress of the loaded item, or an object containing <code>loaded</code>
  • 2092
  • * and <code>total</code> properties.
  • 2093
  • * @protected
  • 2094
  • */
  • 2095
  • p._sendProgress = function (value) {
  • 2096
  • if (this._isCanceled()) { return; }
  • 2097
  • var event = null;
  • 2098
  • if (typeof(value) == "number") {
  • 2099
  • this.progress = value;
  • 2100
  • event = new createjs.ProgressEvent(this.progress);
  • 2101
  • } else {
  • 2102
  • event = value;
  • 2103
  • this.progress = value.loaded / value.total;
  • 2104
  • event.progress = this.progress;
  • 2105
  • if (isNaN(this.progress) || this.progress == Infinity) { this.progress = 0; }
  • 2106
  • }
  • 2107
  • this.hasEventListener("progress") && this.dispatchEvent(event);
  • 2108
  • };
  • 2109  
    2110
  • /**
  • 2111
  • * Dispatch a complete {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}} event
  • 2112
  • * @method _sendComplete
  • 2113
  • * @protected
  • 2114
  • */
  • 2115
  • p._sendComplete = function () {
  • 2116
  • if (this._isCanceled()) { return; }
  • 2117  
    2118
  • this.loaded = true;
  • 2119  
    2120
  • var event = new createjs.Event("complete");
  • 2121
  • event.rawResult = this._rawResult;
  • 2122  
    2123
  • if (this._result != null) {
  • 2124
  • event.result = this._result;
  • 2125
  • }
  • 2126  
    2127
  • this.dispatchEvent(event);
  • 2128
  • };
  • 2129  
    2130
  • /**
  • 2131
  • * Dispatch an error {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}}
  • 2132
  • * event for details on the event payload.
  • 2133
  • * @method _sendError
  • 2134
  • * @param {ErrorEvent} event The event object containing specific error properties.
  • 2135
  • * @protected
  • 2136
  • */
  • 2137
  • p._sendError = function (event) {
  • 2138
  • if (this._isCanceled() || !this.hasEventListener("error")) { return; }
  • 2139
  • if (event == null) {
  • 2140
  • event = new createjs.ErrorEvent("PRELOAD_ERROR_EMPTY"); // TODO: Populate error
  • 2141
  • }
  • 2142
  • this.dispatchEvent(event);
  • 2143
  • };
  • 2144  
    2145
  • /**
  • 2146
  • * Determine if the load has been canceled. This is important to ensure that method calls or asynchronous events
  • 2147
  • * do not cause issues after the queue has been cleaned up.
  • 2148
  • * @method _isCanceled
  • 2149
  • * @return {Boolean} If the loader has been canceled.
  • 2150
  • * @protected
  • 2151
  • */
  • 2152
  • p._isCanceled = function () {
  • 2153
  • if (window.createjs == null || this.canceled) {
  • 2154
  • return true;
  • 2155
  • }
  • 2156
  • return false;
  • 2157
  • };
  • 2158  
    2159
  • /**
  • 2160
  • * A custom result formatter function, which is called just before a request dispatches its complete event. Most
  • 2161
  • * loader types already have an internal formatter, but this can be user-overridden for custom formatting. The
  • 2162
  • * formatted result will be available on Loaders using {{#crossLink "getResult"}}{{/crossLink}}, and passing `true`.
  • 2163
  • * @property resultFormatter
  • 2164
  • * @type Function
  • 2165
  • * @return {Object} The formatted result
  • 2166
  • * @since 0.6.0
  • 2167
  • */
  • 2168
  • p.resultFormatter = null;
  • 2169  
    2170
  • /**
  • 2171
  • * Handle events from internal requests. By default, loaders will handle, and redispatch the necessary events, but
  • 2172
  • * this method can be overridden for custom behaviours.
  • 2173
  • * @method handleEvent
  • 2174
  • * @param {Event} event The event that the internal request dispatches.
  • 2175
  • * @protected
  • 2176
  • * @since 0.6.0
  • 2177
  • */
  • 2178
  • p.handleEvent = function (event) {
  • 2179
  • switch (event.type) {
  • 2180
  • case "complete":
  • 2181
  • this._rawResult = event.target._response;
  • 2182
  • var result = this.resultFormatter && this.resultFormatter(this);
  • 2183
  • if (result instanceof Function) {
  • 2184
  • result.call(this,
  • 2185
  • createjs.proxy(this._resultFormatSuccess, this),
  • 2186
  • createjs.proxy(this._resultFormatFailed, this)
  • 2187
  • );
  • 2188
  • } else {
  • 2189
  • this._result = result || this._rawResult;
  • 2190
  • this._sendComplete();
  • 2191
  • }
  • 2192
  • break;
  • 2193
  • case "progress":
  • 2194
  • this._sendProgress(event);
  • 2195
  • break;
  • 2196
  • case "error":
  • 2197
  • this._sendError(event);
  • 2198
  • break;
  • 2199
  • case "loadstart":
  • 2200
  • this._sendLoadStart();
  • 2201
  • break;
  • 2202
  • case "abort":
  • 2203
  • case "timeout":
  • 2204
  • if (!this._isCanceled()) {
  • 2205
  • this.dispatchEvent(new createjs.ErrorEvent("PRELOAD_" + event.type.toUpperCase() + "_ERROR"));
  • 2206
  • }
  • 2207
  • break;
  • 2208
  • }
  • 2209
  • };
  • 2210  
    2211
  • /**
  • 2212
  • * The "success" callback passed to {{#crossLink "AbstractLoader/resultFormatter"}}{{/crossLink}} asynchronous
  • 2213
  • * functions.
  • 2214
  • * @method _resultFormatSuccess
  • 2215
  • * @param {Object} result The formatted result
  • 2216
  • * @private
  • 2217
  • */
  • 2218
  • p._resultFormatSuccess = function (result) {
  • 2219
  • this._result = result;
  • 2220
  • this._sendComplete();
  • 2221
  • };
  • 2222  
    2223
  • /**
  • 2224
  • * The "error" callback passed to {{#crossLink "AbstractLoader/resultFormatter"}}{{/crossLink}} asynchronous
  • 2225
  • * functions.
  • 2226
  • * @method _resultFormatSuccess
  • 2227
  • * @param {Object} error The error event
  • 2228
  • * @private
  • 2229
  • */
  • 2230
  • p._resultFormatFailed = function (event) {
  • 2231
  • this._sendError(event);
  • 2232
  • };
  • 2233  
    2234
  • /**
  • 2235
  • * @method buildPath
  • 2236
  • * @protected
  • 2237
  • * @deprecated Use the {{#crossLink "RequestUtils"}}{{/crossLink}} method {{#crossLink "RequestUtils/buildPath"}}{{/crossLink}}
  • 2238
  • * instead.
  • 2239
  • */
  • 2240
  • p.buildPath = function (src, data) {
  • 2241
  • return createjs.RequestUtils.buildPath(src, data);
  • 2242
  • };
  • 2243  
    2244
  • /**
  • 2245
  • * @method toString
  • 2246
  • * @return {String} a string representation of the instance.
  • 2247
  • */
  • 2248
  • p.toString = function () {
  • 2249
  • return "[PreloadJS AbstractLoader]";
  • 2250
  • };
  • 2251  
    2252
  • createjs.AbstractLoader = createjs.promote(AbstractLoader, "EventDispatcher");
  • 2253  
    2254
  • }());
  • 2255  
    2256
  • //##############################################################################
  • 2257
  • // AbstractMediaLoader.js
  • 2258
  • //##############################################################################
  • 2259  
    2260
  • this.createjs = this.createjs || {};
  • 2261  
    2262
  • (function () {
  • 2263
  • "use strict";
  • 2264  
    2265
  • // constructor
  • 2266
  • /**
  • 2267
  • * The AbstractMediaLoader is a base class that handles some of the shared methods and properties of loaders that
  • 2268
  • * handle HTML media elements, such as Video and Audio.
  • 2269
  • * @class AbstractMediaLoader
  • 2270
  • * @param {LoadItem|Object} loadItem
  • 2271
  • * @param {Boolean} preferXHR
  • 2272
  • * @param {String} type The type of media to load. Usually "video" or "audio".
  • 2273
  • * @extends AbstractLoader
  • 2274
  • * @constructor
  • 2275
  • */
  • 2276
  • function AbstractMediaLoader(loadItem, preferXHR, type) {
  • 2277
  • this.AbstractLoader_constructor(loadItem, preferXHR, type);
  • 2278  
    2279
  • // public properties
  • 2280
  • this.resultFormatter = this._formatResult;
  • 2281  
    2282
  • // protected properties
  • 2283
  • this._tagSrcAttribute = "src";
  • 2284  
    2285
  • this.on("initialize", this._updateXHR, this);
  • 2286
  • };
  • 2287  
    2288
  • var p = createjs.extend(AbstractMediaLoader, createjs.AbstractLoader);
  • 2289  
    2290
  • // static properties
  • 2291
  • // public methods
  • 2292
  • p.load = function () {
  • 2293
  • // TagRequest will handle most of this, but Sound / Video need a few custom properties, so just handle them here.
  • 2294
  • if (!this._tag) {
  • 2295
  • this._tag = this._createTag(this._item.src);
  • 2296
  • }
  • 2297  
    2298
  • this._tag.preload = "auto";
  • 2299
  • this._tag.load();
  • 2300  
    2301
  • this.AbstractLoader_load();
  • 2302
  • };
  • 2303  
    2304
  • // protected methods
  • 2305
  • /**
  • 2306
  • * Creates a new tag for loading if it doesn't exist yet.
  • 2307
  • * @method _createTag
  • 2308
  • * @private
  • 2309
  • */
  • 2310
  • p._createTag = function () {};
  • 2311  
    2312  
    2313
  • p._createRequest = function() {
  • 2314
  • if (!this._preferXHR) {
  • 2315
  • this._request = new createjs.MediaTagRequest(this._item, this._tag || this._createTag(), this._tagSrcAttribute);
  • 2316
  • } else {
  • 2317
  • this._request = new createjs.XHRRequest(this._item);
  • 2318
  • }
  • 2319
  • };
  • 2320  
    2321
  • // protected methods
  • 2322
  • /**
  • 2323
  • * Before the item loads, set its mimeType and responseType.
  • 2324
  • * @property _updateXHR
  • 2325
  • * @param {Event} event
  • 2326
  • * @private
  • 2327
  • */
  • 2328
  • p._updateXHR = function (event) {
  • 2329
  • // Only exists for XHR
  • 2330
  • if (event.loader.setResponseType) {
  • 2331
  • event.loader.setResponseType("blob");
  • 2332
  • }
  • 2333
  • };
  • 2334  
    2335
  • /**
  • 2336
  • * The result formatter for media files.
  • 2337
  • * @method _formatResult
  • 2338
  • * @param {AbstractLoader} loader
  • 2339
  • * @returns {HTMLVideoElement|HTMLAudioElement}
  • 2340
  • * @private
  • 2341
  • */
  • 2342
  • p._formatResult = function (loader) {
  • 2343
  • this._tag.removeEventListener && this._tag.removeEventListener("canplaythrough", this._loadedHandler);
  • 2344
  • this._tag.onstalled = null;
  • 2345
  • if (this._preferXHR) {
  • 2346
  • var URL = window.URL || window.webkitURL;
  • 2347
  • var result = loader.getResult(true);
  • 2348  
    2349
  • loader.getTag().src = URL.createObjectURL(result);
  • 2350
  • }
  • 2351
  • return loader.getTag();
  • 2352
  • };
  • 2353  
    2354
  • createjs.AbstractMediaLoader = createjs.promote(AbstractMediaLoader, "AbstractLoader");
  • 2355  
    2356
  • }());
  • 2357  
    2358
  • //##############################################################################
  • 2359
  • // AbstractRequest.js
  • 2360
  • //##############################################################################
  • 2361  
    2362
  • this.createjs = this.createjs || {};
  • 2363  
    2364
  • (function () {
  • 2365
  • "use strict";
  • 2366  
    2367
  • /**
  • 2368
  • * A base class for actual data requests, such as {{#crossLink "XHRRequest"}}{{/crossLink}}, {{#crossLink "TagRequest"}}{{/crossLink}},
  • 2369
  • * and {{#crossLink "MediaRequest"}}{{/crossLink}}. PreloadJS loaders will typically use a data loader under the
  • 2370
  • * hood to get data.
  • 2371
  • * @class AbstractRequest
  • 2372
  • * @param {LoadItem} item
  • 2373
  • * @constructor
  • 2374
  • */
  • 2375
  • var AbstractRequest = function (item) {
  • 2376
  • this._item = item;
  • 2377
  • };
  • 2378  
    2379
  • var p = createjs.extend(AbstractRequest, createjs.EventDispatcher);
  • 2380  
    2381
  • // public methods
  • 2382
  • /**
  • 2383
  • * Begin a load.
  • 2384
  • * @method load
  • 2385
  • */
  • 2386
  • p.load = function() {};
  • 2387  
    2388
  • /**
  • 2389
  • * Clean up a request.
  • 2390
  • * @method destroy
  • 2391
  • */
  • 2392
  • p.destroy = function() {};
  • 2393  
    2394
  • /**
  • 2395
  • * Cancel an in-progress request.
  • 2396
  • * @method cancel
  • 2397
  • */
  • 2398
  • p.cancel = function() {};
  • 2399  
    2400
  • createjs.AbstractRequest = createjs.promote(AbstractRequest, "EventDispatcher");
  • 2401  
    2402
  • }());
  • 2403  
    2404
  • //##############################################################################
  • 2405
  • // TagRequest.js
  • 2406
  • //##############################################################################
  • 2407  
    2408
  • this.createjs = this.createjs || {};
  • 2409  
    2410
  • (function () {
  • 2411
  • "use strict";
  • 2412  
    2413
  • // constructor
  • 2414
  • /**
  • 2415
  • * An {{#crossLink "AbstractRequest"}}{{/crossLink}} that loads HTML tags, such as images and scripts.
  • 2416
  • * @class TagRequest
  • 2417
  • * @param {LoadItem} loadItem
  • 2418
  • * @param {HTMLElement} tag
  • 2419
  • * @param {String} srcAttribute The tag attribute that specifies the source, such as "src", "href", etc.
  • 2420
  • */
  • 2421
  • function TagRequest(loadItem, tag, srcAttribute) {
  • 2422
  • this.AbstractRequest_constructor(loadItem);
  • 2423  
    2424
  • // protected properties
  • 2425
  • /**
  • 2426
  • * The HTML tag instance that is used to load.
  • 2427
  • * @property _tag
  • 2428
  • * @type {HTMLElement}
  • 2429
  • * @protected
  • 2430
  • */
  • 2431
  • this._tag = tag;
  • 2432  
    2433
  • /**
  • 2434
  • * The tag attribute that specifies the source, such as "src", "href", etc.
  • 2435
  • * @property _tagSrcAttribute
  • 2436
  • * @type {String}
  • 2437
  • * @protected
  • 2438
  • */
  • 2439
  • this._tagSrcAttribute = srcAttribute;
  • 2440  
    2441
  • /**
  • 2442
  • * A method closure used for handling the tag load event.
  • 2443
  • * @property _loadedHandler
  • 2444
  • * @type {Function}
  • 2445
  • * @private
  • 2446
  • */
  • 2447
  • this._loadedHandler = createjs.proxy(this._handleTagComplete, this);
  • 2448  
    2449
  • /**
  • 2450
  • * Determines if the element was added to the DOM automatically by PreloadJS, so it can be cleaned up after.
  • 2451
  • * @property _addedToDOM
  • 2452
  • * @type {Boolean}
  • 2453
  • * @private
  • 2454
  • */
  • 2455
  • this._addedToDOM = false;
  • 2456  
    2457
  • /**
  • 2458
  • * Determines what the tags initial style.visibility was, so we can set it correctly after a load.
  • 2459
  • *
  • 2460
  • * @type {null}
  • 2461
  • * @private
  • 2462
  • */
  • 2463
  • this._startTagVisibility = null;
  • 2464
  • };
  • 2465  
    2466
  • var p = createjs.extend(TagRequest, createjs.AbstractRequest);
  • 2467  
    2468
  • // public methods
  • 2469
  • p.load = function () {
  • 2470
  • this._tag.onload = createjs.proxy(this._handleTagComplete, this);
  • 2471
  • this._tag.onreadystatechange = createjs.proxy(this._handleReadyStateChange, this);
  • 2472
  • this._tag.onerror = createjs.proxy(this._handleError, this);
  • 2473  
    2474
  • var evt = new createjs.Event("initialize");
  • 2475
  • evt.loader = this._tag;
  • 2476  
    2477
  • this.dispatchEvent(evt);
  • 2478  
    2479
  • this._hideTag();
  • 2480  
    2481
  • this._loadTimeout = setTimeout(createjs.proxy(this._handleTimeout, this), this._item.loadTimeout);
  • 2482  
    2483
  • this._tag[this._tagSrcAttribute] = this._item.src;
  • 2484  
    2485
  • // wdg:: Append the tag AFTER setting the src, or SVG loading on iOS will fail.
  • 2486
  • if (this._tag.parentNode == null) {
  • 2487
  • window.document.body.appendChild(this._tag);
  • 2488
  • this._addedToDOM = true;
  • 2489
  • }
  • 2490
  • };
  • 2491  
    2492
  • p.destroy = function() {
  • 2493
  • this._clean();
  • 2494
  • this._tag = null;
  • 2495  
    2496
  • this.AbstractRequest_destroy();
  • 2497
  • };
  • 2498  
    2499
  • // private methods
  • 2500
  • /**
  • 2501
  • * Handle the readyStateChange event from a tag. We need this in place of the `onload` callback (mainly SCRIPT
  • 2502
  • * and LINK tags), but other cases may exist.
  • 2503
  • * @method _handleReadyStateChange
  • 2504
  • * @private
  • 2505
  • */
  • 2506
  • p._handleReadyStateChange = function () {
  • 2507
  • clearTimeout(this._loadTimeout);
  • 2508
  • // This is strictly for tags in browsers that do not support onload.
  • 2509
  • var tag = this._tag;
  • 2510  
    2511
  • // Complete is for old IE support.
  • 2512
  • if (tag.readyState == "loaded" || tag.readyState == "complete") {
  • 2513
  • this._handleTagComplete();
  • 2514
  • }
  • 2515
  • };
  • 2516  
    2517
  • /**
  • 2518
  • * Handle any error events from the tag.
  • 2519
  • * @method _handleError
  • 2520
  • * @protected
  • 2521
  • */
  • 2522
  • p._handleError = function() {
  • 2523
  • this._clean();
  • 2524
  • this.dispatchEvent("error");
  • 2525
  • };
  • 2526  
    2527
  • /**
  • 2528
  • * Handle the tag's onload callback.
  • 2529
  • * @method _handleTagComplete
  • 2530
  • * @private
  • 2531
  • */
  • 2532
  • p._handleTagComplete = function () {
  • 2533
  • this._rawResult = this._tag;
  • 2534
  • this._result = this.resultFormatter && this.resultFormatter(this) || this._rawResult;
  • 2535  
    2536
  • this._clean();
  • 2537
  • this._showTag();
  • 2538  
    2539
  • this.dispatchEvent("complete");
  • 2540
  • };
  • 2541  
    2542
  • /**
  • 2543
  • * The tag request has not loaded within the time specified in loadTimeout.
  • 2544
  • * @method _handleError
  • 2545
  • * @param {Object} event The XHR error event.
  • 2546
  • * @private
  • 2547
  • */
  • 2548
  • p._handleTimeout = function () {
  • 2549
  • this._clean();
  • 2550
  • this.dispatchEvent(new createjs.Event("timeout"));
  • 2551
  • };
  • 2552  
    2553
  • /**
  • 2554
  • * Remove event listeners, but don't destroy the request object
  • 2555
  • * @method _clean
  • 2556
  • * @private
  • 2557
  • */
  • 2558
  • p._clean = function() {
  • 2559
  • this._tag.onload = null;
  • 2560
  • this._tag.onreadystatechange = null;
  • 2561
  • this._tag.onerror = null;
  • 2562
  • if (this._addedToDOM && this._tag.parentNode != null) {
  • 2563
  • this._tag.parentNode.removeChild(this._tag);
  • 2564
  • }
  • 2565
  • clearTimeout(this._loadTimeout);
  • 2566
  • };
  • 2567  
    2568
  • p._hideTag = function() {
  • 2569
  • this._startTagVisibility = this._tag.style.visibility;
  • 2570
  • this._tag.style.visibility = "hidden";
  • 2571
  • };
  • 2572  
    2573
  • p._showTag = function() {
  • 2574
  • this._tag.style.visibility = this._startTagVisibility;
  • 2575
  • };
  • 2576  
    2577
  • /**
  • 2578
  • * Handle a stalled audio event. The main place this happens is with HTMLAudio in Chrome when playing back audio
  • 2579
  • * that is already in a load, but not complete.
  • 2580
  • * @method _handleStalled
  • 2581
  • * @private
  • 2582
  • */
  • 2583
  • p._handleStalled = function () {
  • 2584
  • //Ignore, let the timeout take care of it. Sometimes its not really stopped.
  • 2585
  • };
  • 2586  
    2587
  • createjs.TagRequest = createjs.promote(TagRequest, "AbstractRequest");
  • 2588  
    2589
  • }());
  • 2590  
    2591
  • //##############################################################################
  • 2592
  • // MediaTagRequest.js
  • 2593
  • //##############################################################################
  • 2594  
    2595
  • this.createjs = this.createjs || {};
  • 2596  
    2597
  • (function () {
  • 2598
  • "use strict";
  • 2599  
    2600
  • // constructor
  • 2601
  • /**
  • 2602
  • * An {{#crossLink "TagRequest"}}{{/crossLink}} that loads HTML tags for video and audio.
  • 2603
  • * @class MediaTagRequest
  • 2604
  • * @param {LoadItem} loadItem
  • 2605
  • * @param {HTMLAudioElement|HTMLVideoElement} tag
  • 2606
  • * @param {String} srcAttribute The tag attribute that specifies the source, such as "src", "href", etc.
  • 2607
  • * @constructor
  • 2608
  • */
  • 2609
  • function MediaTagRequest(loadItem, tag, srcAttribute) {
  • 2610
  • this.AbstractRequest_constructor(loadItem);
  • 2611  
    2612
  • // protected properties
  • 2613
  • this._tag = tag;
  • 2614
  • this._tagSrcAttribute = srcAttribute;
  • 2615
  • this._loadedHandler = createjs.proxy(this._handleTagComplete, this);
  • 2616
  • };
  • 2617  
    2618
  • var p = createjs.extend(MediaTagRequest, createjs.TagRequest);
  • 2619
  • var s = MediaTagRequest;
  • 2620  
    2621
  • // public methods
  • 2622
  • p.load = function () {
  • 2623
  • var sc = createjs.proxy(this._handleStalled, this);
  • 2624
  • this._stalledCallback = sc;
  • 2625  
    2626
  • var pc = createjs.proxy(this._handleProgress, this);
  • 2627
  • this._handleProgress = pc;
  • 2628  
    2629
  • this._tag.addEventListener("stalled", sc);
  • 2630
  • this._tag.addEventListener("progress", pc);
  • 2631  
    2632
  • // This will tell us when audio is buffered enough to play through, but not when its loaded.
  • 2633
  • // The tag doesn't keep loading in Chrome once enough has buffered, and we have decided that behaviour is sufficient.
  • 2634
  • this._tag.addEventListener && this._tag.addEventListener("canplaythrough", this._loadedHandler, false); // canplaythrough callback doesn't work in Chrome, so we use an event.
  • 2635  
    2636
  • this.TagRequest_load();
  • 2637
  • };
  • 2638  
    2639
  • // private methods
  • 2640
  • p._handleReadyStateChange = function () {
  • 2641
  • clearTimeout(this._loadTimeout);
  • 2642
  • // This is strictly for tags in browsers that do not support onload.
  • 2643
  • var tag = this._tag;
  • 2644  
    2645
  • // Complete is for old IE support.
  • 2646
  • if (tag.readyState == "loaded" || tag.readyState == "complete") {
  • 2647
  • this._handleTagComplete();
  • 2648
  • }
  • 2649
  • };
  • 2650  
    2651
  • p._handleStalled = function () {
  • 2652
  • //Ignore, let the timeout take care of it. Sometimes its not really stopped.
  • 2653
  • };
  • 2654  
    2655
  • /**
  • 2656
  • * An XHR request has reported progress.
  • 2657
  • * @method _handleProgress
  • 2658
  • * @param {Object} event The XHR progress event.
  • 2659
  • * @private
  • 2660
  • */
  • 2661
  • p._handleProgress = function (event) {
  • 2662
  • if (!event || event.loaded > 0 && event.total == 0) {
  • 2663
  • return; // Sometimes we get no "total", so just ignore the progress event.
  • 2664
  • }
  • 2665  
    2666
  • var newEvent = new createjs.ProgressEvent(event.loaded, event.total);
  • 2667
  • this.dispatchEvent(newEvent);
  • 2668
  • };
  • 2669  
    2670
  • // protected methods
  • 2671
  • p._clean = function () {
  • 2672
  • this._tag.removeEventListener && this._tag.removeEventListener("canplaythrough", this._loadedHandler);
  • 2673
  • this._tag.removeEventListener("stalled", this._stalledCallback);
  • 2674
  • this._tag.removeEventListener("progress", this._progressCallback);
  • 2675  
    2676
  • this.TagRequest__clean();
  • 2677
  • };
  • 2678  
    2679
  • createjs.MediaTagRequest = createjs.promote(MediaTagRequest, "TagRequest");
  • 2680  
    2681
  • }());
  • 2682  
    2683
  • //##############################################################################
  • 2684
  • // XHRRequest.js
  • 2685
  • //##############################################################################
  • 2686  
    2687
  • this.createjs = this.createjs || {};
  • 2688  
    2689
  • (function () {
  • 2690
  • "use strict";
  • 2691  
    2692
  • // constructor
  • 2693
  • /**
  • 2694
  • * A preloader that loads items using XHR requests, usually XMLHttpRequest. However XDomainRequests will be used
  • 2695
  • * for cross-domain requests if possible, and older versions of IE fall back on to ActiveX objects when necessary.
  • 2696
  • * XHR requests load the content as text or binary data, provide progress and consistent completion events, and
  • 2697
  • * can be canceled during load. Note that XHR is not supported in IE 6 or earlier, and is not recommended for
  • 2698
  • * cross-domain loading.
  • 2699
  • * @class XHRRequest
  • 2700
  • * @constructor
  • 2701
  • * @param {Object} item The object that defines the file to load. Please see the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}}
  • 2702
  • * for an overview of supported file properties.
  • 2703
  • * @extends AbstractLoader
  • 2704
  • */
  • 2705
  • function XHRRequest (item) {
  • 2706
  • this.AbstractRequest_constructor(item);
  • 2707  
    2708
  • // protected properties
  • 2709
  • /**
  • 2710
  • * A reference to the XHR request used to load the content.
  • 2711
  • * @property _request
  • 2712
  • * @type {XMLHttpRequest | XDomainRequest | ActiveX.XMLHTTP}
  • 2713
  • * @private
  • 2714
  • */
  • 2715
  • this._request = null;
  • 2716  
    2717
  • /**
  • 2718
  • * A manual load timeout that is used for browsers that do not support the onTimeout event on XHR (XHR level 1,
  • 2719
  • * typically IE9).
  • 2720
  • * @property _loadTimeout
  • 2721
  • * @type {Number}
  • 2722
  • * @private
  • 2723
  • */
  • 2724
  • this._loadTimeout = null;
  • 2725  
    2726
  • /**
  • 2727
  • * The browser's XHR (XMLHTTPRequest) version. Supported versions are 1 and 2. There is no official way to detect
  • 2728
  • * the version, so we use capabilities to make a best guess.
  • 2729
  • * @property _xhrLevel
  • 2730
  • * @type {Number}
  • 2731
  • * @default 1
  • 2732
  • * @private
  • 2733
  • */
  • 2734
  • this._xhrLevel = 1;
  • 2735  
    2736
  • /**
  • 2737
  • * The response of a loaded file. This is set because it is expensive to look up constantly. This property will be
  • 2738
  • * null until the file is loaded.
  • 2739
  • * @property _response
  • 2740
  • * @type {mixed}
  • 2741
  • * @private
  • 2742
  • */
  • 2743
  • this._response = null;
  • 2744  
    2745
  • /**
  • 2746
  • * The response of the loaded file before it is modified. In most cases, content is converted from raw text to
  • 2747
  • * an HTML tag or a formatted object which is set to the <code>result</code> property, but the developer may still
  • 2748
  • * want to access the raw content as it was loaded.
  • 2749
  • * @property _rawResponse
  • 2750
  • * @type {String|Object}
  • 2751
  • * @private
  • 2752
  • */
  • 2753
  • this._rawResponse = null;
  • 2754  
    2755
  • this._canceled = false;
  • 2756  
    2757
  • // Setup our event handlers now.
  • 2758
  • this._handleLoadStartProxy = createjs.proxy(this._handleLoadStart, this);
  • 2759
  • this._handleProgressProxy = createjs.proxy(this._handleProgress, this);
  • 2760
  • this._handleAbortProxy = createjs.proxy(this._handleAbort, this);
  • 2761
  • this._handleErrorProxy = createjs.proxy(this._handleError, this);
  • 2762
  • this._handleTimeoutProxy = createjs.proxy(this._handleTimeout, this);
  • 2763
  • this._handleLoadProxy = createjs.proxy(this._handleLoad, this);
  • 2764
  • this._handleReadyStateChangeProxy = createjs.proxy(this._handleReadyStateChange, this);
  • 2765  
    2766
  • if (!this._createXHR(item)) {
  • 2767
  • //TODO: Throw error?
  • 2768
  • }
  • 2769
  • };
  • 2770  
    2771
  • var p = createjs.extend(XHRRequest, createjs.AbstractRequest);
  • 2772  
    2773
  • // static properties
  • 2774
  • /**
  • 2775
  • * A list of XMLHTTP object IDs to try when building an ActiveX object for XHR requests in earlier versions of IE.
  • 2776
  • * @property ACTIVEX_VERSIONS
  • 2777
  • * @type {Array}
  • 2778
  • * @since 0.4.2
  • 2779
  • * @private
  • 2780
  • */
  • 2781
  • XHRRequest.ACTIVEX_VERSIONS = [
  • 2782
  • "Msxml2.XMLHTTP.6.0",
  • 2783
  • "Msxml2.XMLHTTP.5.0",
  • 2784
  • "Msxml2.XMLHTTP.4.0",
  • 2785
  • "MSXML2.XMLHTTP.3.0",
  • 2786
  • "MSXML2.XMLHTTP",
  • 2787
  • "Microsoft.XMLHTTP"
  • 2788
  • ];
  • 2789  
    2790
  • // Public methods
  • 2791
  • /**
  • 2792
  • * Look up the loaded result.
  • 2793
  • * @method getResult
  • 2794
  • * @param {Boolean} [raw=false] Return a raw result instead of a formatted result. This applies to content
  • 2795
  • * loaded via XHR such as scripts, XML, CSS, and Images. If there is no raw result, the formatted result will be
  • 2796
  • * returned instead.
  • 2797
  • * @return {Object} A result object containing the content that was loaded, such as:
  • 2798
  • * <ul>
  • 2799
  • * <li>An image tag (&lt;image /&gt;) for images</li>
  • 2800
  • * <li>A script tag for JavaScript (&lt;script /&gt;). Note that scripts loaded with tags may be added to the
  • 2801
  • * HTML head.</li>
  • 2802
  • * <li>A style tag for CSS (&lt;style /&gt;)</li>
  • 2803
  • * <li>Raw text for TEXT</li>
  • 2804
  • * <li>A formatted JavaScript object defined by JSON</li>
  • 2805
  • * <li>An XML document</li>
  • 2806
  • * <li>An binary arraybuffer loaded by XHR</li>
  • 2807
  • * </ul>
  • 2808
  • * Note that if a raw result is requested, but not found, the result will be returned instead.
  • 2809
  • */
  • 2810
  • p.getResult = function (raw) {
  • 2811
  • if (raw && this._rawResponse) {
  • 2812
  • return this._rawResponse;
  • 2813
  • }
  • 2814
  • return this._response;
  • 2815
  • };
  • 2816  
    2817
  • // Overrides abstract method in AbstractRequest
  • 2818
  • p.cancel = function () {
  • 2819
  • this.canceled = true;
  • 2820
  • this._clean();
  • 2821
  • this._request.abort();
  • 2822
  • };
  • 2823  
    2824
  • // Overrides abstract method in AbstractLoader
  • 2825
  • p.load = function () {
  • 2826
  • if (this._request == null) {
  • 2827
  • this._handleError();
  • 2828
  • return;
  • 2829
  • }
  • 2830  
    2831
  • //Events
  • 2832
  • if (this._request.addEventListener != null) {
  • 2833
  • this._request.addEventListener("loadstart", this._handleLoadStartProxy, false);
  • 2834
  • this._request.addEventListener("progress", this._handleProgressProxy, false);
  • 2835
  • this._request.addEventListener("abort", this._handleAbortProxy, false);
  • 2836
  • this._request.addEventListener("error", this._handleErrorProxy, false);
  • 2837
  • this._request.addEventListener("timeout", this._handleTimeoutProxy, false);
  • 2838  
    2839
  • // Note: We don't get onload in all browsers (earlier FF and IE). onReadyStateChange handles these.
  • 2840
  • this._request.addEventListener("load", this._handleLoadProxy, false);
  • 2841
  • this._request.addEventListener("readystatechange", this._handleReadyStateChangeProxy, false);
  • 2842
  • } else {
  • 2843
  • // IE9 support
  • 2844
  • this._request.onloadstart = this._handleLoadStartProxy;
  • 2845
  • this._request.onprogress = this._handleProgressProxy;
  • 2846
  • this._request.onabort = this._handleAbortProxy;
  • 2847
  • this._request.onerror = this._handleErrorProxy;
  • 2848
  • this._request.ontimeout = this._handleTimeoutProxy;
  • 2849  
    2850
  • // Note: We don't get onload in all browsers (earlier FF and IE). onReadyStateChange handles these.
  • 2851
  • this._request.onload = this._handleLoadProxy;
  • 2852
  • this._request.onreadystatechange = this._handleReadyStateChangeProxy;
  • 2853
  • }
  • 2854  
    2855
  • // Set up a timeout if we don't have XHR2
  • 2856
  • if (this._xhrLevel == 1) {
  • 2857
  • this._loadTimeout = setTimeout(createjs.proxy(this._handleTimeout, this), this._item.loadTimeout);
  • 2858
  • }
  • 2859  
    2860
  • // Sometimes we get back 404s immediately, particularly when there is a cross origin request. // note this does not catch in Chrome
  • 2861
  • try {
  • 2862
  • if (!this._item.values || this._item.method == createjs.AbstractLoader.GET) {
  • 2863
  • this._request.send();
  • 2864
  • } else if (this._item.method == createjs.AbstractLoader.POST) {
  • 2865
  • this._request.send(createjs.RequestUtils.formatQueryString(this._item.values));
  • 2866
  • }
  • 2867
  • } catch (error) {
  • 2868
  • this.dispatchEvent(new createjs.ErrorEvent("XHR_SEND", null, error));
  • 2869
  • }
  • 2870
  • };
  • 2871  
    2872
  • p.setResponseType = function (type) {
  • 2873
  • // Some old browsers doesn't support blob, so we convert arraybuffer to blob after response is downloaded
  • 2874
  • if (type === 'blob') {
  • 2875
  • type = window.URL ? 'blob' : 'arraybuffer';
  • 2876
  • this._responseType = type;
  • 2877
  • }
  • 2878
  • this._request.responseType = type;
  • 2879
  • };
  • 2880  
    2881
  • /**
  • 2882
  • * Get all the response headers from the XmlHttpRequest.
  • 2883
  • *
  • 2884
  • * <strong>From the docs:</strong> Return all the HTTP headers, excluding headers that are a case-insensitive match
  • 2885
  • * for Set-Cookie or Set-Cookie2, as a single string, with each header line separated by a U+000D CR U+000A LF pair,
  • 2886
  • * excluding the status line, and with each header name and header value separated by a U+003A COLON U+0020 SPACE
  • 2887
  • * pair.
  • 2888
  • * @method getAllResponseHeaders
  • 2889
  • * @return {String}
  • 2890
  • * @since 0.4.1
  • 2891
  • */
  • 2892
  • p.getAllResponseHeaders = function () {
  • 2893
  • if (this._request.getAllResponseHeaders instanceof Function) {
  • 2894
  • return this._request.getAllResponseHeaders();
  • 2895
  • } else {
  • 2896
  • return null;
  • 2897
  • }
  • 2898
  • };
  • 2899  
    2900
  • /**
  • 2901
  • * Get a specific response header from the XmlHttpRequest.
  • 2902
  • *
  • 2903
  • * <strong>From the docs:</strong> Returns the header field value from the response of which the field name matches
  • 2904
  • * header, unless the field name is Set-Cookie or Set-Cookie2.
  • 2905
  • * @method getResponseHeader
  • 2906
  • * @param {String} header The header name to retrieve.
  • 2907
  • * @return {String}
  • 2908
  • * @since 0.4.1
  • 2909
  • */
  • 2910
  • p.getResponseHeader = function (header) {
  • 2911
  • if (this._request.getResponseHeader instanceof Function) {
  • 2912
  • return this._request.getResponseHeader(header);
  • 2913
  • } else {
  • 2914
  • return null;
  • 2915
  • }
  • 2916
  • };
  • 2917  
    2918
  • // protected methods
  • 2919
  • /**
  • 2920
  • * The XHR request has reported progress.
  • 2921
  • * @method _handleProgress
  • 2922
  • * @param {Object} event The XHR progress event.
  • 2923
  • * @private
  • 2924
  • */
  • 2925
  • p._handleProgress = function (event) {
  • 2926
  • if (!event || event.loaded > 0 && event.total == 0) {
  • 2927
  • return; // Sometimes we get no "total", so just ignore the progress event.
  • 2928
  • }
  • 2929  
    2930
  • var newEvent = new createjs.ProgressEvent(event.loaded, event.total);
  • 2931
  • this.dispatchEvent(newEvent);
  • 2932
  • };
  • 2933  
    2934
  • /**
  • 2935
  • * The XHR request has reported a load start.
  • 2936
  • * @method _handleLoadStart
  • 2937
  • * @param {Object} event The XHR loadStart event.
  • 2938
  • * @private
  • 2939
  • */
  • 2940
  • p._handleLoadStart = function (event) {
  • 2941
  • clearTimeout(this._loadTimeout);
  • 2942
  • this.dispatchEvent("loadstart");
  • 2943
  • };
  • 2944  
    2945
  • /**
  • 2946
  • * The XHR request has reported an abort event.
  • 2947
  • * @method handleAbort
  • 2948
  • * @param {Object} event The XHR abort event.
  • 2949
  • * @private
  • 2950
  • */
  • 2951
  • p._handleAbort = function (event) {
  • 2952
  • this._clean();
  • 2953
  • this.dispatchEvent(new createjs.ErrorEvent("XHR_ABORTED", null, event));
  • 2954
  • };
  • 2955  
    2956
  • /**
  • 2957
  • * The XHR request has reported an error event.
  • 2958
  • * @method _handleError
  • 2959
  • * @param {Object} event The XHR error event.
  • 2960
  • * @private
  • 2961
  • */
  • 2962
  • p._handleError = function (event) {
  • 2963
  • this._clean();
  • 2964
  • this.dispatchEvent(new createjs.ErrorEvent(event.message));
  • 2965
  • };
  • 2966  
    2967
  • /**
  • 2968
  • * The XHR request has reported a readyState change. Note that older browsers (IE 7 & 8) do not provide an onload
  • 2969
  • * event, so we must monitor the readyStateChange to determine if the file is loaded.
  • 2970
  • * @method _handleReadyStateChange
  • 2971
  • * @param {Object} event The XHR readyStateChange event.
  • 2972
  • * @private
  • 2973
  • */
  • 2974
  • p._handleReadyStateChange = function (event) {
  • 2975
  • if (this._request.readyState == 4) {
  • 2976
  • this._handleLoad();
  • 2977
  • }
  • 2978
  • };
  • 2979  
    2980
  • /**
  • 2981
  • * The XHR request has completed. This is called by the XHR request directly, or by a readyStateChange that has
  • 2982
  • * <code>request.readyState == 4</code>. Only the first call to this method will be processed.
  • 2983
  • * @method _handleLoad
  • 2984
  • * @param {Object} event The XHR load event.
  • 2985
  • * @private
  • 2986
  • */
  • 2987
  • p._handleLoad = function (event) {
  • 2988
  • if (this.loaded) {
  • 2989
  • return;
  • 2990
  • }
  • 2991
  • this.loaded = true;
  • 2992  
    2993
  • var error = this._checkError();
  • 2994
  • if (error) {
  • 2995
  • this._handleError(error);
  • 2996
  • return;
  • 2997
  • }
  • 2998  
    2999
  • this._response = this._getResponse();
  • 3000
  • // Convert arraybuffer back to blob
  • 3001
  • if (this._responseType === 'arraybuffer') {
  • 3002
  • try {
  • 3003
  • this._response = new Blob([this._response]);
  • 3004
  • } catch (e) {
  • 3005
  • // Fallback to use BlobBuilder if Blob constructor is not supported
  • 3006
  • // Tested on Android 2.3 ~ 4.2 and iOS5 safari
  • 3007
  • window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
  • 3008
  • if (e.name === 'TypeError' && window.BlobBuilder) {
  • 3009
  • var builder = new BlobBuilder();
  • 3010
  • builder.append(this._response);
  • 3011
  • this._response = builder.getBlob();
  • 3012
  • }
  • 3013
  • }
  • 3014
  • }
  • 3015
  • this._clean();
  • 3016  
    3017
  • this.dispatchEvent(new createjs.Event("complete"));
  • 3018
  • };
  • 3019  
    3020
  • /**
  • 3021
  • * The XHR request has timed out. This is called by the XHR request directly, or via a <code>setTimeout</code>
  • 3022
  • * callback.
  • 3023
  • * @method _handleTimeout
  • 3024
  • * @param {Object} [event] The XHR timeout event. This is occasionally null when called by the backup setTimeout.
  • 3025
  • * @private
  • 3026
  • */
  • 3027
  • p._handleTimeout = function (event) {
  • 3028
  • this._clean();
  • 3029  
    3030
  • this.dispatchEvent(new createjs.ErrorEvent("PRELOAD_TIMEOUT", null, event));
  • 3031
  • };
  • 3032  
    3033
  • // Protected
  • 3034
  • /**
  • 3035
  • * Determine if there is an error in the current load. This checks the status of the request for problem codes. Note
  • 3036
  • * that this does not check for an actual response. Currently, it only checks for 404 or 0 error code.
  • 3037
  • * @method _checkError
  • 3038
  • * @return {int} If the request status returns an error code.
  • 3039
  • * @private
  • 3040
  • */
  • 3041
  • p._checkError = function () {
  • 3042
  • //LM: Probably need additional handlers here, maybe 501
  • 3043
  • var status = parseInt(this._request.status);
  • 3044  
    3045
  • switch (status) {
  • 3046
  • case 404: // Not Found
  • 3047
  • case 0: // Not Loaded
  • 3048
  • return new Error(status);
  • 3049
  • }
  • 3050
  • return null;
  • 3051
  • };
  • 3052  
    3053
  • /**
  • 3054
  • * Validate the response. Different browsers have different approaches, some of which throw errors when accessed
  • 3055
  • * in other browsers. If there is no response, the <code>_response</code> property will remain null.
  • 3056
  • * @method _getResponse
  • 3057
  • * @private
  • 3058
  • */
  • 3059
  • p._getResponse = function () {
  • 3060
  • if (this._response != null) {
  • 3061
  • return this._response;
  • 3062
  • }
  • 3063  
    3064
  • if (this._request.response != null) {
  • 3065
  • return this._request.response;
  • 3066
  • }
  • 3067  
    3068
  • // Android 2.2 uses .responseText
  • 3069
  • try {
  • 3070
  • if (this._request.responseText != null) {
  • 3071
  • return this._request.responseText;
  • 3072
  • }
  • 3073
  • } catch (e) {
  • 3074
  • }
  • 3075  
    3076
  • // When loading XML, IE9 does not return .response, instead it returns responseXML.xml
  • 3077
  • try {
  • 3078
  • if (this._request.responseXML != null) {
  • 3079
  • return this._request.responseXML;
  • 3080
  • }
  • 3081
  • } catch (e) {
  • 3082
  • }
  • 3083  
    3084
  • return null;
  • 3085
  • };
  • 3086  
    3087
  • /**
  • 3088
  • * Create an XHR request. Depending on a number of factors, we get totally different results.
  • 3089
  • * <ol><li>Some browsers get an <code>XDomainRequest</code> when loading cross-domain.</li>
  • 3090
  • * <li>XMLHttpRequest are created when available.</li>
  • 3091
  • * <li>ActiveX.XMLHTTP objects are used in older IE browsers.</li>
  • 3092
  • * <li>Text requests override the mime type if possible</li>
  • 3093
  • * <li>Origin headers are sent for crossdomain requests in some browsers.</li>
  • 3094
  • * <li>Binary loads set the response type to "arraybuffer"</li></ol>
  • 3095
  • * @method _createXHR
  • 3096
  • * @param {Object} item The requested item that is being loaded.
  • 3097
  • * @return {Boolean} If an XHR request or equivalent was successfully created.
  • 3098
  • * @private
  • 3099
  • */
  • 3100
  • p._createXHR = function (item) {
  • 3101
  • // Check for cross-domain loads. We can't fully support them, but we can try.
  • 3102
  • var crossdomain = createjs.RequestUtils.isCrossDomain(item);
  • 3103
  • var headers = {};
  • 3104  
    3105
  • // Create the request. Fallback to whatever support we have.
  • 3106
  • var req = null;
  • 3107
  • if (window.XMLHttpRequest) {
  • 3108
  • req = new XMLHttpRequest();
  • 3109
  • // This is 8 or 9, so use XDomainRequest instead.
  • 3110
  • if (crossdomain && req.withCredentials === undefined && window.XDomainRequest) {
  • 3111
  • req = new XDomainRequest();
  • 3112
  • }
  • 3113
  • } else { // Old IE versions use a different approach
  • 3114
  • for (var i = 0, l = s.ACTIVEX_VERSIONS.length; i < l; i++) {
  • 3115
  • var axVersion = s.ACTIVEX_VERSIONS[i];
  • 3116
  • try {
  • 3117
  • req = new ActiveXObject(axVersion);
  • 3118
  • break;
  • 3119
  • } catch (e) {
  • 3120
  • }
  • 3121
  • }
  • 3122
  • if (req == null) {
  • 3123
  • return false;
  • 3124
  • }
  • 3125
  • }
  • 3126  
    3127
  • // Default to utf-8 for Text requests.
  • 3128
  • if (item.mimeType == null && createjs.RequestUtils.isText(item.type)) {
  • 3129
  • item.mimeType = "text/plain; charset=utf-8";
  • 3130
  • }
  • 3131  
    3132
  • // IE9 doesn't support overrideMimeType(), so we need to check for it.
  • 3133
  • if (item.mimeType && req.overrideMimeType) {
  • 3134
  • req.overrideMimeType(item.mimeType);
  • 3135
  • }
  • 3136  
    3137
  • // Determine the XHR level
  • 3138
  • this._xhrLevel = (typeof req.responseType === "string") ? 2 : 1;
  • 3139  
    3140
  • var src = null;
  • 3141
  • if (item.method == createjs.AbstractLoader.GET) {
  • 3142
  • src = createjs.RequestUtils.buildPath(item.src, item.values);
  • 3143
  • } else {
  • 3144
  • src = item.src;
  • 3145
  • }
  • 3146  
    3147
  • // Open the request. Set cross-domain flags if it is supported (XHR level 1 only)
  • 3148
  • req.open(item.method || createjs.AbstractLoader.GET, src, true);
  • 3149  
    3150
  • if (crossdomain && req instanceof XMLHttpRequest && this._xhrLevel == 1) {
  • 3151
  • headers["Origin"] = location.origin;
  • 3152
  • }
  • 3153  
    3154
  • // To send data we need to set the Content-type header)
  • 3155
  • if (item.values && item.method == createjs.AbstractLoader.POST) {
  • 3156
  • headers["Content-Type"] = "application/x-www-form-urlencoded";
  • 3157
  • }
  • 3158  
    3159
  • if (!crossdomain && !headers["X-Requested-With"]) {
  • 3160
  • headers["X-Requested-With"] = "XMLHttpRequest";
  • 3161
  • }
  • 3162  
    3163
  • if (item.headers) {
  • 3164
  • for (var n in item.headers) {
  • 3165
  • headers[n] = item.headers[n];
  • 3166
  • }
  • 3167
  • }
  • 3168  
    3169
  • for (n in headers) {
  • 3170
  • req.setRequestHeader(n, headers[n])
  • 3171
  • }
  • 3172  
    3173
  • if (req instanceof XMLHttpRequest && item.withCredentials !== undefined) {
  • 3174
  • req.withCredentials = item.withCredentials;
  • 3175
  • }
  • 3176  
    3177
  • this._request = req;
  • 3178  
    3179
  • return true;
  • 3180
  • };
  • 3181  
    3182
  • /**
  • 3183
  • * A request has completed (or failed or canceled), and needs to be disposed.
  • 3184
  • * @method _clean
  • 3185
  • * @private
  • 3186
  • */
  • 3187
  • p._clean = function () {
  • 3188
  • clearTimeout(this._loadTimeout);
  • 3189  
    3190
  • if (this._request.removeEventListener != null) {
  • 3191
  • this._request.removeEventListener("loadstart", this._handleLoadStartProxy);
  • 3192
  • this._request.removeEventListener("progress", this._handleProgressProxy);
  • 3193
  • this._request.removeEventListener("abort", this._handleAbortProxy);
  • 3194
  • this._request.removeEventListener("error", this._handleErrorProxy);
  • 3195
  • this._request.removeEventListener("timeout", this._handleTimeoutProxy);
  • 3196
  • this._request.removeEventListener("load", this._handleLoadProxy);
  • 3197
  • this._request.removeEventListener("readystatechange", this._handleReadyStateChangeProxy);
  • 3198
  • } else {
  • 3199
  • this._request.onloadstart = null;
  • 3200
  • this._request.onprogress = null;
  • 3201
  • this._request.onabort = null;
  • 3202
  • this._request.onerror = null;
  • 3203
  • this._request.ontimeout = null;
  • 3204
  • this._request.onload = null;
  • 3205
  • this._request.onreadystatechange = null;
  • 3206
  • }
  • 3207
  • };
  • 3208  
    3209
  • p.toString = function () {
  • 3210
  • return "[PreloadJS XHRRequest]";
  • 3211
  • };
  • 3212  
    3213
  • createjs.XHRRequest = createjs.promote(XHRRequest, "AbstractRequest");
  • 3214  
    3215
  • }());
  • 3216  
    3217
  • //##############################################################################
  • 3218
  • // SoundLoader.js
  • 3219
  • //##############################################################################
  • 3220  
    3221
  • this.createjs = this.createjs || {};
  • 3222  
    3223
  • (function () {
  • 3224
  • "use strict";
  • 3225  
    3226
  • // constructor
  • 3227
  • /**
  • 3228
  • * A loader for HTML audio files. PreloadJS can not load WebAudio files, as a WebAudio context is required, which
  • 3229
  • * should be created by either a library playing the sound (such as <a href="http://soundjs.com">SoundJS</a>, or an
  • 3230
  • * external framework that handles audio playback. To load content that can be played by WebAudio, use the
  • 3231
  • * {{#crossLink "BinaryLoader"}}{{/crossLink}}, and handle the audio context decoding manually.
  • 3232
  • * @class SoundLoader
  • 3233
  • * @param {LoadItem|Object} loadItem
  • 3234
  • * @param {Boolean} preferXHR
  • 3235
  • * @extends AbstractMediaLoader
  • 3236
  • * @constructor
  • 3237
  • */
  • 3238
  • function SoundLoader(loadItem, preferXHR) {
  • 3239
  • this.AbstractMediaLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.SOUND);
  • 3240  
    3241
  • // protected properties
  • 3242
  • if (createjs.RequestUtils.isAudioTag(loadItem)) {
  • 3243
  • this._tag = loadItem;
  • 3244
  • } else if (createjs.RequestUtils.isAudioTag(loadItem.src)) {
  • 3245
  • this._tag = loadItem;
  • 3246
  • } else if (createjs.RequestUtils.isAudioTag(loadItem.tag)) {
  • 3247
  • this._tag = createjs.RequestUtils.isAudioTag(loadItem) ? loadItem : loadItem.src;
  • 3248
  • }
  • 3249  
    3250
  • if (this._tag != null) {
  • 3251
  • this._preferXHR = false;
  • 3252
  • }
  • 3253
  • };
  • 3254  
    3255
  • var p = createjs.extend(SoundLoader, createjs.AbstractMediaLoader);
  • 3256
  • var s = SoundLoader;
  • 3257  
    3258
  • // static methods
  • 3259
  • /**
  • 3260
  • * Determines if the loader can load a specific item. This loader can only load items that are of type
  • 3261
  • * {{#crossLink "AbstractLoader/SOUND:property"}}{{/crossLink}}.
  • 3262
  • * @method canLoadItem
  • 3263
  • * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load.
  • 3264
  • * @returns {Boolean} Whether the loader can load the item.
  • 3265
  • * @static
  • 3266
  • */
  • 3267
  • s.canLoadItem = function (item) {
  • 3268
  • return item.type == createjs.AbstractLoader.SOUND;
  • 3269
  • };
  • 3270  
    3271
  • // protected methods
  • 3272
  • p._createTag = function (src) {
  • 3273
  • var tag = document.createElement("audio");
  • 3274
  • tag.autoplay = false;
  • 3275
  • tag.preload = "none";
  • 3276  
    3277
  • //LM: Firefox fails when this the preload="none" for other tags, but it needs to be "none" to ensure PreloadJS works.
  • 3278
  • tag.src = src;
  • 3279
  • return tag;
  • 3280
  • };
  • 3281  
    3282
  • createjs.SoundLoader = createjs.promote(SoundLoader, "AbstractMediaLoader");
  • 3283  
    3284
  • }());
  • 3285  
    3286
  • //##############################################################################
  • 3287
  • // AudioSprite.js
  • 3288
  • //##############################################################################
  • 3289  
    3290
  • // NOTE this is "Class" is purely to document audioSprite Setup and usage.
  • 3291  
    3292  
    3293
  • /**
  • 3294
  • * <strong>Note: AudioSprite is not a class, but its usage is easily lost in the documentation, so it has been called
  • 3295
  • * out here for quick reference.</strong>
  • 3296
  • *
  • 3297
  • * Audio sprites are much like CSS sprites or image sprite sheets: multiple audio assets grouped into a single file.
  • 3298
  • * Audio sprites work around limitations in certain browsers, where only a single sound can be loaded and played at a
  • 3299
  • * time. We recommend at least 300ms of silence between audio clips to deal with HTML audio tag inaccuracy, and to prevent
  • 3300
  • * accidentally playing bits of the neighbouring clips.
  • 3301
  • *
  • 3302
  • * <strong>Benefits of Audio Sprites:</strong>
  • 3303
  • * <ul>
  • 3304
  • * <li>More robust support for older browsers and devices that only allow a single audio instance, such as iOS 5.</li>
  • 3305
  • * <li>They provide a work around for the Internet Explorer 9 audio tag limit, which restricts how many different
  • 3306
  • * sounds that could be loaded at once.</li>
  • 3307
  • * <li>Faster loading by only requiring a single network request for several sounds, especially on mobile devices
  • 3308
  • * where the network round trip for each file can add significant latency.</li>
  • 3309
  • * </ul>
  • 3310
  • *
  • 3311
  • * <strong>Drawbacks of Audio Sprites</strong>
  • 3312
  • * <ul>
  • 3313
  • * <li>No guarantee of smooth looping when using HTML or Flash audio. If you have a track that needs to loop
  • 3314
  • * smoothly and you are supporting non-web audio browsers, do not use audio sprites for that sound if you can avoid
  • 3315
  • * it.</li>
  • 3316
  • * <li>No guarantee that HTML audio will play back immediately, especially the first time. In some browsers
  • 3317
  • * (Chrome!), HTML audio will only load enough to play through at the current download speed – so we rely on the
  • 3318
  • * `canplaythrough` event to determine if the audio is loaded. Since audio sprites must jump ahead to play specific
  • 3319
  • * sounds, the audio may not yet have downloaded fully.</li>
  • 3320
  • * <li>Audio sprites share the same core source, so if you have a sprite with 5 sounds and are limited to 2
  • 3321
  • * concurrently playing instances, you can only play 2 of the sounds at the same time.</li>
  • 3322
  • * </ul>
  • 3323
  • *
  • 3324
  • * <h4>Example</h4>
  • 3325
  • *
  • 3326
  • * createjs.Sound.initializeDefaultPlugins();
  • 3327
  • * var assetsPath = "./assets/";
  • 3328
  • * var sounds = [{
  • 3329
  • * src:"MyAudioSprite.ogg", data: {
  • 3330
  • * audioSprite: [
  • 3331
  • * {id:"sound1", startTime:0, duration:500},
  • 3332
  • * {id:"sound2", startTime:1000, duration:400},
  • 3333
  • * {id:"sound3", startTime:1700, duration: 1000}
  • 3334
  • * ]}
  • 3335
  • * }
  • 3336
  • * ];
  • 3337
  • * createjs.Sound.alternateExtensions = ["mp3"];
  • 3338
  • * createjs.Sound.on("fileload", loadSound);
  • 3339
  • * createjs.Sound.registerSounds(sounds, assetsPath);
  • 3340
  • * // after load is complete
  • 3341
  • * createjs.Sound.play("sound2");
  • 3342
  • *
  • 3343
  • * You can also create audio sprites on the fly by setting the startTime and duration when creating an new AbstractSoundInstance.
  • 3344
  • *
  • 3345
  • * createjs.Sound.play("MyAudioSprite", {startTime: 1000, duration: 400});
  • 3346
  • *
  • 3347
  • * The excellent CreateJS community has created a tool to create audio sprites, available at
  • 3348
  • * <a href="https://github.com/tonistiigi/audiosprite" target="_blank">https://github.com/tonistiigi/audiosprite</a>,
  • 3349
  • * as well as a <a href="http://jsfiddle.net/bharat_battu/g8fFP/12/" target="_blank">jsfiddle</a> to convert the output
  • 3350
  • * to SoundJS format.
  • 3351
  • *
  • 3352
  • * @class AudioSprite
  • 3353
  • * @since 0.6.0
  • 3354
  • */
  • 3355  
    3356
  • //##############################################################################
  • 3357
  • // PlayPropsConfig.js
  • 3358
  • //##############################################################################
  • 3359  
    3360
  • this.createjs = this.createjs || {};
  • 3361  
    3362
  • (function () {
  • 3363
  • "use strict";
  • 3364
  • /**
  • 3365
  • * A class to store the optional play properties passed in {{#crossLink "Sound/play"}}{{/crossLink}} and
  • 3366
  • * {{#crossLink "AbstractSoundInstance/play"}}{{/crossLink}} calls.
  • 3367
  • *
  • 3368
  • * Optional Play Properties Include:
  • 3369
  • * <ul>
  • 3370
  • * <li>interrupt - How to interrupt any currently playing instances of audio with the same source,
  • 3371
  • * if the maximum number of instances of the sound are already playing. Values are defined as <code>INTERRUPT_TYPE</code>
  • 3372
  • * constants on the Sound class, with the default defined by {{#crossLink "Sound/defaultInterruptBehavior:property"}}{{/crossLink}}.</li>
  • 3373
  • * <li>delay - The amount of time to delay the start of audio playback, in milliseconds.</li>
  • 3374
  • * <li>offset - The offset from the start of the audio to begin playback, in milliseconds.</li>
  • 3375
  • * <li>loop - How many times the audio loops when it reaches the end of playback. The default is 0 (no
  • 3376
  • * loops), and -1 can be used for infinite playback.</li>
  • 3377
  • * <li>volume - The volume of the sound, between 0 and 1. Note that the master volume is applied
  • 3378
  • * against the individual volume.</li>
  • 3379
  • * <li>pan - The left-right pan of the sound (if supported), between -1 (left) and 1 (right).</li>
  • 3380
  • * <li>startTime - To create an audio sprite (with duration), the initial offset to start playback and loop from, in milliseconds.</li>
  • 3381
  • * <li>duration - To create an audio sprite (with startTime), the amount of time to play the clip for, in milliseconds.</li>
  • 3382
  • * </ul>
  • 3383
  • *
  • 3384
  • * <h4>Example</h4>
  • 3385
  • *
  • 3386
  • * var ppc = new createjs.PlayPropsConfig().set({interrupt: createjs.Sound.INTERRUPT_ANY, loop: -1, volume: 0.5})
  • 3387
  • * createjs.Sound.play("mySound", ppc);
  • 3388
  • * mySoundInstance.play(ppc);
  • 3389
  • *
  • 3390
  • * @class PlayPropsConfig
  • 3391
  • * @constructor
  • 3392
  • * @since 0.6.1
  • 3393
  • */
  • 3394
  • // TODO think of a better name for this class
  • 3395
  • var PlayPropsConfig = function () {
  • 3396
  • // Public Properties
  • 3397
  • /**
  • 3398
  • * How to interrupt any currently playing instances of audio with the same source,
  • 3399
  • * if the maximum number of instances of the sound are already playing. Values are defined as
  • 3400
  • * <code>INTERRUPT_TYPE</code> constants on the Sound class, with the default defined by
  • 3401
  • * {{#crossLink "Sound/defaultInterruptBehavior:property"}}{{/crossLink}}.
  • 3402
  • * @property interrupt
  • 3403
  • * @type {string}
  • 3404
  • * @default null
  • 3405
  • */
  • 3406
  • this.interrupt = null;
  • 3407  
    3408
  • /**
  • 3409
  • * The amount of time to delay the start of audio playback, in milliseconds.
  • 3410
  • * @property delay
  • 3411
  • * @type {Number}
  • 3412
  • * @default null
  • 3413
  • */
  • 3414
  • this.delay = null;
  • 3415  
    3416
  • /**
  • 3417
  • * The offset from the start of the audio to begin playback, in milliseconds.
  • 3418
  • * @property offset
  • 3419
  • * @type {number}
  • 3420
  • * @default null
  • 3421
  • */
  • 3422
  • this.offset = null;
  • 3423  
    3424
  • /**
  • 3425
  • * How many times the audio loops when it reaches the end of playback. The default is 0 (no
  • 3426
  • * loops), and -1 can be used for infinite playback.
  • 3427
  • * @property loop
  • 3428
  • * @type {number}
  • 3429
  • * @default null
  • 3430
  • */
  • 3431
  • this.loop = null;
  • 3432  
    3433
  • /**
  • 3434
  • * The volume of the sound, between 0 and 1. Note that the master volume is applied
  • 3435
  • * against the individual volume.
  • 3436
  • * @property volume
  • 3437
  • * @type {number}
  • 3438
  • * @default null
  • 3439
  • */
  • 3440
  • this.volume = null;
  • 3441  
    3442
  • /**
  • 3443
  • * The left-right pan of the sound (if supported), between -1 (left) and 1 (right).
  • 3444
  • * @property pan
  • 3445
  • * @type {number}
  • 3446
  • * @default null
  • 3447
  • */
  • 3448
  • this.pan = null;
  • 3449  
    3450
  • /**
  • 3451
  • * Used to create an audio sprite (with duration), the initial offset to start playback and loop from, in milliseconds.
  • 3452
  • * @property startTime
  • 3453
  • * @type {number}
  • 3454
  • * @default null
  • 3455
  • */
  • 3456
  • this.startTime = null;
  • 3457  
    3458
  • /**
  • 3459
  • * Used to create an audio sprite (with startTime), the amount of time to play the clip for, in milliseconds.
  • 3460
  • * @property duration
  • 3461
  • * @type {number}
  • 3462
  • * @default null
  • 3463
  • */
  • 3464
  • this.duration = null;
  • 3465
  • };
  • 3466
  • var p = PlayPropsConfig.prototype = {};
  • 3467
  • var s = PlayPropsConfig;
  • 3468  
    3469  
    3470
  • // Static Methods
  • 3471
  • /**
  • 3472
  • * Creates a PlayPropsConfig from another PlayPropsConfig or an Object.
  • 3473
  • *
  • 3474
  • * @method create
  • 3475
  • * @param {PlayPropsConfig|Object} value The play properties
  • 3476
  • * @returns {PlayPropsConfig}
  • 3477
  • * @static
  • 3478
  • */
  • 3479
  • s.create = function (value) {
  • 3480
  • if (value instanceof s || value instanceof Object) {
  • 3481
  • var ppc = new createjs.PlayPropsConfig();
  • 3482
  • ppc.set(value);
  • 3483
  • return ppc;
  • 3484
  • } else {
  • 3485
  • throw new Error("Type not recognized.");
  • 3486
  • }
  • 3487
  • };
  • 3488  
    3489
  • // Public Methods
  • 3490
  • /**
  • 3491
  • * Provides a chainable shortcut method for setting a number of properties on the instance.
  • 3492
  • *
  • 3493
  • * <h4>Example</h4>
  • 3494
  • *
  • 3495
  • * var PlayPropsConfig = new createjs.PlayPropsConfig().set({loop:-1, volume:0.7});
  • 3496
  • *
  • 3497
  • * @method set
  • 3498
  • * @param {Object} props A generic object containing properties to copy to the PlayPropsConfig instance.
  • 3499
  • * @return {PlayPropsConfig} Returns the instance the method is called on (useful for chaining calls.)
  • 3500
  • */
  • 3501
  • p.set = function(props) {
  • 3502
  • for (var n in props) { this[n] = props[n]; }
  • 3503
  • return this;
  • 3504
  • };
  • 3505  
    3506
  • p.toString = function() {
  • 3507
  • return "[PlayPropsConfig]";
  • 3508
  • };
  • 3509  
    3510
  • createjs.PlayPropsConfig = s;
  • 3511  
    3512
  • }());
  • 3513  
    3514
  • //##############################################################################
  • 3515
  • // Sound.js
  • 3516
  • //##############################################################################
  • 3517  
    3518
  • this.createjs = this.createjs || {};
  • 3519  
    3520  
    3521  
    3522
  • (function () {
  • 3523
  • "use strict";
  • 3524  
    3525
  • /**
  • 3526
  • * The Sound class is the public API for creating sounds, controlling the overall sound levels, and managing plugins.
  • 3527
  • * All Sound APIs on this class are static.
  • 3528
  • *
  • 3529
  • * <b>Registering and Preloading</b><br />
  • 3530
  • * Before you can play a sound, it <b>must</b> be registered. You can do this with {{#crossLink "Sound/registerSound"}}{{/crossLink}},
  • 3531
  • * or register multiple sounds using {{#crossLink "Sound/registerSounds"}}{{/crossLink}}. If you don't register a
  • 3532
  • * sound prior to attempting to play it using {{#crossLink "Sound/play"}}{{/crossLink}} or create it using {{#crossLink "Sound/createInstance"}}{{/crossLink}},
  • 3533
  • * the sound source will be automatically registered but playback will fail as the source will not be ready. If you use
  • 3534
  • * <a href="http://preloadjs.com" target="_blank">PreloadJS</a>, registration is handled for you when the sound is
  • 3535
  • * preloaded. It is recommended to preload sounds either internally using the register functions or externally using
  • 3536
  • * PreloadJS so they are ready when you want to use them.
  • 3537
  • *
  • 3538
  • * <b>Playback</b><br />
  • 3539
  • * To play a sound once it's been registered and preloaded, use the {{#crossLink "Sound/play"}}{{/crossLink}} method.
  • 3540
  • * This method returns a {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} which can be paused, resumed, muted, etc.
  • 3541
  • * Please see the {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} documentation for more on the instance control APIs.
  • 3542
  • *
  • 3543
  • * <b>Plugins</b><br />
  • 3544
  • * By default, the {{#crossLink "WebAudioPlugin"}}{{/crossLink}} or the {{#crossLink "HTMLAudioPlugin"}}{{/crossLink}}
  • 3545
  • * are used (when available), although developers can change plugin priority or add new plugins (such as the
  • 3546
  • * provided {{#crossLink "FlashAudioPlugin"}}{{/crossLink}}). Please see the {{#crossLink "Sound"}}{{/crossLink}} API
  • 3547
  • * methods for more on the playback and plugin APIs. To install plugins, or specify a different plugin order, see
  • 3548
  • * {{#crossLink "Sound/installPlugins"}}{{/crossLink}}.
  • 3549
  • *
  • 3550
  • * <h4>Example</h4>
  • 3551
  • *
  • 3552
  • * createjs.FlashAudioPlugin.swfPath = "../src/soundjs/flashaudio";
  • 3553
  • * createjs.Sound.registerPlugins([createjs.WebAudioPlugin, createjs.FlashAudioPlugin]);
  • 3554
  • * createjs.Sound.alternateExtensions = ["mp3"];
  • 3555
  • * createjs.Sound.on("fileload", this.loadHandler, this);
  • 3556
  • * createjs.Sound.registerSound("path/to/mySound.ogg", "sound");
  • 3557
  • * function loadHandler(event) {
  • 3558
  • * // This is fired for each sound that is registered.
  • 3559
  • * var instance = createjs.Sound.play("sound"); // play using id. Could also use full source path or event.src.
  • 3560
  • * instance.on("complete", this.handleComplete, this);
  • 3561
  • * instance.volume = 0.5;
  • 3562
  • * }
  • 3563
  • *
  • 3564
  • * The maximum number of concurrently playing instances of the same sound can be specified in the "data" argument
  • 3565
  • * of {{#crossLink "Sound/registerSound"}}{{/crossLink}}. Note that if not specified, the active plugin will apply
  • 3566
  • * a default limit. Currently HTMLAudioPlugin sets a default limit of 2, while WebAudioPlugin and FlashAudioPlugin set a
  • 3567
  • * default limit of 100.
  • 3568
  • *
  • 3569
  • * createjs.Sound.registerSound("sound.mp3", "soundId", 4);
  • 3570
  • *
  • 3571
  • * Sound can be used as a plugin with PreloadJS to help preload audio properly. Audio preloaded with PreloadJS is
  • 3572
  • * automatically registered with the Sound class. When audio is not preloaded, Sound will do an automatic internal
  • 3573
  • * load. As a result, it may fail to play the first time play is called if the audio is not finished loading. Use
  • 3574
  • * the {{#crossLink "Sound/fileload:event"}}{{/crossLink}} event to determine when a sound has finished internally
  • 3575
  • * preloading. It is recommended that all audio is preloaded before it is played.
  • 3576
  • *
  • 3577
  • * var queue = new createjs.LoadQueue();
  • 3578
  • * queue.installPlugin(createjs.Sound);
  • 3579
  • *
  • 3580
  • * <b>Audio Sprites</b><br />
  • 3581
  • * SoundJS has added support for {{#crossLink "AudioSprite"}}{{/crossLink}}, available as of version 0.6.0.
  • 3582
  • * For those unfamiliar with audio sprites, they are much like CSS sprites or sprite sheets: multiple audio assets
  • 3583
  • * grouped into a single file.
  • 3584
  • *
  • 3585
  • * <h4>Example</h4>
  • 3586
  • *
  • 3587
  • * var assetsPath = "./assets/";
  • 3588
  • * var sounds = [{
  • 3589
  • * src:"MyAudioSprite.ogg", data: {
  • 3590
  • * audioSprite: [
  • 3591
  • * {id:"sound1", startTime:0, duration:500},
  • 3592
  • * {id:"sound2", startTime:1000, duration:400},
  • 3593
  • * {id:"sound3", startTime:1700, duration: 1000}
  • 3594
  • * ]}
  • 3595
  • * }
  • 3596
  • * ];
  • 3597
  • * createjs.Sound.alternateExtensions = ["mp3"];
  • 3598
  • * createjs.Sound.on("fileload", loadSound);
  • 3599
  • * createjs.Sound.registerSounds(sounds, assetsPath);
  • 3600
  • * // after load is complete
  • 3601
  • * createjs.Sound.play("sound2");
  • 3602
  • *
  • 3603
  • * <b>Mobile Playback</b><br />
  • 3604
  • * Devices running iOS require the WebAudio context to be "unlocked" by playing at least one sound inside of a user-
  • 3605
  • * initiated event (such as touch/click). Earlier versions of SoundJS included a "MobileSafe" sample, but this is no
  • 3606
  • * longer necessary as of SoundJS 0.6.2.
  • 3607
  • * <ul>
  • 3608
  • * <li>
  • 3609
  • * In SoundJS 0.4.1 and above, you can either initialize plugins or use the {{#crossLink "WebAudioPlugin/playEmptySound"}}{{/crossLink}}
  • 3610
  • * method in the call stack of a user input event to manually unlock the audio context.
  • 3611
  • * </li>
  • 3612
  • * <li>
  • 3613
  • * In SoundJS 0.6.2 and above, SoundJS will automatically listen for the first document-level "mousedown"
  • 3614
  • * and "touchend" event, and unlock WebAudio. This will continue to check these events until the WebAudio
  • 3615
  • * context becomes "unlocked" (changes from "suspended" to "running")
  • 3616
  • * </li>
  • 3617
  • * <li>
  • 3618
  • * Both the "mousedown" and "touchend" events can be used to unlock audio in iOS9+, the "touchstart" event
  • 3619
  • * will work in iOS8 and below. The "touchend" event will only work in iOS9 when the gesture is interpreted
  • 3620
  • * as a "click", so if the user long-presses the button, it will no longer work.
  • 3621
  • * </li>
  • 3622
  • * <li>
  • 3623
  • * When using the <a href="http://www.createjs.com/docs/easeljs/classes/Touch.html">EaselJS Touch class</a>,
  • 3624
  • * the "mousedown" event will not fire when a canvas is clicked, since MouseEvents are prevented, to ensure
  • 3625
  • * only touch events fire. To get around this, you can either rely on "touchend", or:
  • 3626
  • * <ol>
  • 3627
  • * <li>Set the `allowDefault` property on the Touch class constructor to `true` (defaults to `false`).</li>
  • 3628
  • * <li>Set the `preventSelection` property on the EaselJS `Stage` to `false`.</li>
  • 3629
  • * </ol>
  • 3630
  • * These settings may change how your application behaves, and are not recommended.
  • 3631
  • * </li>
  • 3632
  • * </ul>
  • 3633
  • *
  • 3634
  • * <b>Loading Alternate Paths and Extension-less Files</b><br />
  • 3635
  • * SoundJS supports loading alternate paths and extension-less files by passing an object instead of a string for
  • 3636
  • * the `src` property, which is a hash using the format `{extension:"path", extension2:"path2"}`. These labels are
  • 3637
  • * how SoundJS determines if the browser will support the sound. This also enables multiple formats to live in
  • 3638
  • * different folders, or on CDNs, which often has completely different filenames for each file.
  • 3639
  • *
  • 3640
  • * Priority is determined by the property order (first property is tried first). This is supported by both internal loading
  • 3641
  • * and loading with PreloadJS.
  • 3642
  • *
  • 3643
  • * <em>Note: an id is required for playback.</em>
  • 3644
  • *
  • 3645
  • * <h4>Example</h4>
  • 3646
  • *
  • 3647
  • * var sounds = {path:"./audioPath/",
  • 3648
  • * manifest: [
  • 3649
  • * {id: "cool", src: {mp3:"mp3/awesome.mp3", ogg:"noExtensionOggFile"}}
  • 3650
  • * ]};
  • 3651
  • *
  • 3652
  • * createjs.Sound.alternateExtensions = ["mp3"];
  • 3653
  • * createjs.Sound.addEventListener("fileload", handleLoad);
  • 3654
  • * createjs.Sound.registerSounds(sounds);
  • 3655
  • *
  • 3656
  • * <h3>Known Browser and OS issues</h3>
  • 3657
  • * <b>IE 9 HTML Audio limitations</b><br />
  • 3658
  • * <ul><li>There is a delay in applying volume changes to tags that occurs once playback is started. So if you have
  • 3659
  • * muted all sounds, they will all play during this delay until the mute applies internally. This happens regardless of
  • 3660
  • * when or how you apply the volume change, as the tag seems to need to play to apply it.</li>
  • 3661
  • * <li>MP3 encoding will not always work for audio tags, particularly in Internet Explorer. We've found default
  • 3662
  • * encoding with 64kbps works.</li>
  • 3663
  • * <li>Occasionally very short samples will get cut off.</li>
  • 3664
  • * <li>There is a limit to how many audio tags you can load and play at once, which appears to be determined by
  • 3665
  • * hardware and browser settings. See {{#crossLink "HTMLAudioPlugin.MAX_INSTANCES"}}{{/crossLink}} for a safe
  • 3666
  • * estimate.</li></ul>
  • 3667
  • *
  • 3668
  • * <b>Firefox 25 Web Audio limitations</b>
  • 3669
  • * <ul><li>mp3 audio files do not load properly on all windows machines, reported
  • 3670
  • * <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=929969" target="_blank">here</a>. </br>
  • 3671
  • * For this reason it is recommended to pass another FF supported type (ie ogg) first until this bug is resolved, if
  • 3672
  • * possible.</li></ul>
  • 3673  
    3674
  • * <b>Safari limitations</b><br />
  • 3675
  • * <ul><li>Safari requires Quicktime to be installed for audio playback.</li></ul>
  • 3676
  • *
  • 3677
  • * <b>iOS 6 Web Audio limitations</b><br />
  • 3678
  • * <ul><li>Sound is initially locked, and must be unlocked via a user-initiated event. Please see the section on
  • 3679
  • * Mobile Playback above.</li>
  • 3680
  • * <li>A bug exists that will distort un-cached web audio when a video element is present in the DOM that has audio
  • 3681
  • * at a different sampleRate.</li>
  • 3682
  • * </ul>
  • 3683
  • *
  • 3684
  • * <b>Android HTML Audio limitations</b><br />
  • 3685
  • * <ul><li>We have no control over audio volume. Only the user can set volume on their device.</li>
  • 3686
  • * <li>We can only play audio inside a user event (touch/click). This currently means you cannot loop sound or use
  • 3687
  • * a delay.</li></ul>
  • 3688
  • *
  • 3689
  • * <b>Web Audio and PreloadJS</b><br />
  • 3690
  • * <ul><li>Web Audio must be loaded through XHR, therefore when used with PreloadJS, tag loading is not possible.
  • 3691
  • * This means that tag loading can not be used to avoid cross domain issues.</li><ul>
  • 3692
  • *
  • 3693
  • * @class Sound
  • 3694
  • * @static
  • 3695
  • * @uses EventDispatcher
  • 3696
  • */
  • 3697
  • function Sound() {
  • 3698
  • throw "Sound cannot be instantiated";
  • 3699
  • }
  • 3700  
    3701
  • var s = Sound;
  • 3702  
    3703  
    3704
  • // Static Properties
  • 3705
  • /**
  • 3706
  • * The interrupt value to interrupt any currently playing instance with the same source, if the maximum number of
  • 3707
  • * instances of the sound are already playing.
  • 3708
  • * @property INTERRUPT_ANY
  • 3709
  • * @type {String}
  • 3710
  • * @default any
  • 3711
  • * @static
  • 3712
  • */
  • 3713
  • s.INTERRUPT_ANY = "any";
  • 3714  
    3715
  • /**
  • 3716
  • * The interrupt value to interrupt the earliest currently playing instance with the same source that progressed the
  • 3717
  • * least distance in the audio track, if the maximum number of instances of the sound are already playing.
  • 3718
  • * @property INTERRUPT_EARLY
  • 3719
  • * @type {String}
  • 3720
  • * @default early
  • 3721
  • * @static
  • 3722
  • */
  • 3723
  • s.INTERRUPT_EARLY = "early";
  • 3724  
    3725
  • /**
  • 3726
  • * The interrupt value to interrupt the currently playing instance with the same source that progressed the most
  • 3727
  • * distance in the audio track, if the maximum number of instances of the sound are already playing.
  • 3728
  • * @property INTERRUPT_LATE
  • 3729
  • * @type {String}
  • 3730
  • * @default late
  • 3731
  • * @static
  • 3732
  • */
  • 3733
  • s.INTERRUPT_LATE = "late";
  • 3734  
    3735
  • /**
  • 3736
  • * The interrupt value to not interrupt any currently playing instances with the same source, if the maximum number of
  • 3737
  • * instances of the sound are already playing.
  • 3738
  • * @property INTERRUPT_NONE
  • 3739
  • * @type {String}
  • 3740
  • * @default none
  • 3741
  • * @static
  • 3742
  • */
  • 3743
  • s.INTERRUPT_NONE = "none";
  • 3744  
    3745
  • /**
  • 3746
  • * Defines the playState of an instance that is still initializing.
  • 3747
  • * @property PLAY_INITED
  • 3748
  • * @type {String}
  • 3749
  • * @default playInited
  • 3750
  • * @static
  • 3751
  • */
  • 3752
  • s.PLAY_INITED = "playInited";
  • 3753  
    3754
  • /**
  • 3755
  • * Defines the playState of an instance that is currently playing or paused.
  • 3756
  • * @property PLAY_SUCCEEDED
  • 3757
  • * @type {String}
  • 3758
  • * @default playSucceeded
  • 3759
  • * @static
  • 3760
  • */
  • 3761
  • s.PLAY_SUCCEEDED = "playSucceeded";
  • 3762  
    3763
  • /**
  • 3764
  • * Defines the playState of an instance that was interrupted by another instance.
  • 3765
  • * @property PLAY_INTERRUPTED
  • 3766
  • * @type {String}
  • 3767
  • * @default playInterrupted
  • 3768
  • * @static
  • 3769
  • */
  • 3770
  • s.PLAY_INTERRUPTED = "playInterrupted";
  • 3771  
    3772
  • /**
  • 3773
  • * Defines the playState of an instance that completed playback.
  • 3774
  • * @property PLAY_FINISHED
  • 3775
  • * @type {String}
  • 3776
  • * @default playFinished
  • 3777
  • * @static
  • 3778
  • */
  • 3779
  • s.PLAY_FINISHED = "playFinished";
  • 3780  
    3781
  • /**
  • 3782
  • * Defines the playState of an instance that failed to play. This is usually caused by a lack of available channels
  • 3783
  • * when the interrupt mode was "INTERRUPT_NONE", the playback stalled, or the sound could not be found.
  • 3784
  • * @property PLAY_FAILED
  • 3785
  • * @type {String}
  • 3786
  • * @default playFailed
  • 3787
  • * @static
  • 3788
  • */
  • 3789
  • s.PLAY_FAILED = "playFailed";
  • 3790  
    3791
  • /**
  • 3792
  • * A list of the default supported extensions that Sound will <i>try</i> to play. Plugins will check if the browser
  • 3793
  • * can play these types, so modifying this list before a plugin is initialized will allow the plugins to try to
  • 3794
  • * support additional media types.
  • 3795
  • *
  • 3796
  • * NOTE this does not currently work for {{#crossLink "FlashAudioPlugin"}}{{/crossLink}}.
  • 3797
  • *
  • 3798
  • * More details on file formats can be found at <a href="http://en.wikipedia.org/wiki/Audio_file_format" target="_blank">http://en.wikipedia.org/wiki/Audio_file_format</a>.<br />
  • 3799
  • * A very detailed list of file formats can be found at <a href="http://www.fileinfo.com/filetypes/audio" target="_blank">http://www.fileinfo.com/filetypes/audio</a>.
  • 3800
  • * @property SUPPORTED_EXTENSIONS
  • 3801
  • * @type {Array[String]}
  • 3802
  • * @default ["mp3", "ogg", "opus", "mpeg", "wav", "m4a", "mp4", "aiff", "wma", "mid"]
  • 3803
  • * @since 0.4.0
  • 3804
  • * @static
  • 3805
  • */
  • 3806
  • s.SUPPORTED_EXTENSIONS = ["mp3", "ogg", "opus", "mpeg", "wav", "m4a", "mp4", "aiff", "wma", "mid"];
  • 3807  
    3808
  • /**
  • 3809
  • * Some extensions use another type of extension support to play (one of them is a codex). This allows you to map
  • 3810
  • * that support so plugins can accurately determine if an extension is supported. Adding to this list can help
  • 3811
  • * plugins determine more accurately if an extension is supported.
  • 3812
  • *
  • 3813
  • * A useful list of extensions for each format can be found at <a href="http://html5doctor.com/html5-audio-the-state-of-play/" target="_blank">http://html5doctor.com/html5-audio-the-state-of-play/</a>.
  • 3814
  • * @property EXTENSION_MAP
  • 3815
  • * @type {Object}
  • 3816
  • * @since 0.4.0
  • 3817
  • * @default {m4a:"mp4"}
  • 3818
  • * @static
  • 3819
  • */
  • 3820
  • s.EXTENSION_MAP = {
  • 3821
  • m4a:"mp4"
  • 3822
  • };
  • 3823  
    3824
  • /**
  • 3825
  • * The RegExp pattern used to parse file URIs. This supports simple file names, as well as full domain URIs with
  • 3826
  • * query strings. The resulting match is: protocol:$1 domain:$2 path:$3 file:$4 extension:$5 query:$6.
  • 3827
  • * @property FILE_PATTERN
  • 3828
  • * @type {RegExp}
  • 3829
  • * @static
  • 3830
  • * @protected
  • 3831
  • */
  • 3832
  • s.FILE_PATTERN = /^(?:(\w+:)\/{2}(\w+(?:\.\w+)*\/?))?([/.]*?(?:[^?]+)?\/)?((?:[^/?]+)\.(\w+))(?:\?(\S+)?)?$/;
  • 3833  
    3834  
    3835
  • // Class Public properties
  • 3836
  • /**
  • 3837
  • * Determines the default behavior for interrupting other currently playing instances with the same source, if the
  • 3838
  • * maximum number of instances of the sound are already playing. Currently the default is {{#crossLink "Sound/INTERRUPT_NONE:property"}}{{/crossLink}}
  • 3839
  • * but this can be set and will change playback behavior accordingly. This is only used when {{#crossLink "Sound/play"}}{{/crossLink}}
  • 3840
  • * is called without passing a value for interrupt.
  • 3841
  • * @property defaultInterruptBehavior
  • 3842
  • * @type {String}
  • 3843
  • * @default Sound.INTERRUPT_NONE, or "none"
  • 3844
  • * @static
  • 3845
  • * @since 0.4.0
  • 3846
  • */
  • 3847
  • 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.
  • 3848  
    3849
  • /**
  • 3850
  • * An array of extensions to attempt to use when loading sound, if the default is unsupported by the active plugin.
  • 3851
  • * These are applied in order, so if you try to Load Thunder.ogg in a browser that does not support ogg, and your
  • 3852
  • * extensions array is ["mp3", "m4a", "wav"] it will check mp3 support, then m4a, then wav. The audio files need
  • 3853
  • * to exist in the same location, as only the extension is altered.
  • 3854
  • *
  • 3855
  • * Note that regardless of which file is loaded, you can call {{#crossLink "Sound/createInstance"}}{{/crossLink}}
  • 3856
  • * and {{#crossLink "Sound/play"}}{{/crossLink}} using the same id or full source path passed for loading.
  • 3857
  • *
  • 3858
  • *

    Exampleh4>

  • 3859
  • *

  • 3860
  • * var sounds = [

  • 3861
  • * {src:"myPath/mySound.ogg", id:"example"},

  • 3862
  • * ];

  • 3863
  • * createjs.Sound.alternateExtensions = ["mp3"]; // now if ogg is not supported, SoundJS will try asset0.mp3

  • 3864
  • * createjs.Sound.on("fileload", handleLoad); // call handleLoad when each sound loads

  • 3865
  • * createjs.Sound.registerSounds(sounds, assetPath);

  • 3866
  • * // ...

  • 3867
  • * createjs.Sound.play("myPath/mySound.ogg"); // works regardless of what extension is supported. Note calling with ID is a better approach

  • 3868
  • *

  • 3869
  • * @property alternateExtensions

  • 3870
  • * @type {Array}

  • 3871
  • * @since 0.5.2

  • 3872
  • * @static

  • 3873
  • */

  • 3874
  • s.alternateExtensions = [];

  • 3875  
    3876
  • /**

  • 3877
  • * The currently active plugin. If this is null, then no plugin could be initialized. If no plugin was specified,

  • 3878
  • * Sound attempts to apply the default plugins: {{#crossLink "WebAudioPlugin"}}{{/crossLink}}, followed by

  • 3879
  • * {{#crossLink "HTMLAudioPlugin"}}{{/crossLink}}.

  • 3880
  • * @property activePlugin

  • 3881
  • * @type {Object}

  • 3882
  • * @static

  • 3883
  • */

  • 3884
  • s.activePlugin = null;

  • 3885  
    3886  
    3887
  • // class getter / setter properties

  • 3888
  • /**

  • 3889
  • * Set the master volume of Sound. The master volume is multiplied against each sound's individual volume. For

  • 3890
  • * example, if master volume is 0.5 and a sound's volume is 0.5, the resulting volume is 0.25. To set individual

  • 3891
  • * sound volume, use AbstractSoundInstance {{#crossLink "AbstractSoundInstance/volume:property"}}{{/crossLink}} instead.

  • 3892
  • *

  • 3893
  • * <h4>Example</h4>

  • 3894
  • *

  • 3895
  • * createjs.Sound.volume = 0.5;

  • 3896
  • *

  • 3897
  • *

  • 3898
  • * @property volume

  • 3899
  • * @type {Number}

  • 3900
  • * @default 1

  • 3901
  • * @since 0.6.1

  • 3902
  • */

  • 3903
  • s._masterVolume = 1;

  • 3904
  • Object.defineProperty(s, "volume", {

  • 3905
  • get: function () {return this._masterVolume;},

  • 3906
  • set: function (value) {

  • 3907
  • if (Number(value) == null) {return false;}

  • 3908
  • value = Math.max(0, Math.min(1, value));

  • 3909
  • s._masterVolume = value;

  • 3910
  • if (!this.activePlugin || !this.activePlugin.setVolume || !this.activePlugin.setVolume(value)) {

  • 3911
  • var instances = this._instances;

  • 3912
  • for (var i = 0, l = instances.length; i < l; i++) {

  • 3913
  • instances[i].setMasterVolume(value);

  • 3914
  • }

  • 3915
  • }

  • 3916
  • }

  • 3917
  • });

  • 3918  
    3919
  • /**

  • 3920
  • * Mute/Unmute all audio. Note that muted audio still plays at 0 volume. This global mute value is maintained

  • 3921
  • * separately and when set will override, but not change the mute property of individual instances. To mute an individual

  • 3922
  • * instance, use AbstractSoundInstance {{#crossLink "AbstractSoundInstance/muted:property"}}{{/crossLink}} instead.

  • 3923
  • *

  • 3924
  • * <h4>Example</h4>

  • 3925
  • *

  • 3926
  • * createjs.Sound.muted = true;

  • 3927
  • *

  • 3928
  • *

  • 3929
  • * @property muted

  • 3930
  • * @type {Boolean}

  • 3931
  • * @default false

  • 3932
  • * @since 0.6.1

  • 3933
  • */

  • 3934
  • s._masterMute = false;

  • 3935
  • // OJR references to the methods were not working, so the code had to be duplicated here

  • 3936
  • Object.defineProperty(s, "muted", {

  • 3937
  • get: function () {return this._masterMute;},

  • 3938
  • set: function (value) {

  • 3939
  • if (value == null) {return false;}

  • 3940  
    3941
  • this._masterMute = value;

  • 3942
  • if (!this.activePlugin || !this.activePlugin.setMute || !this.activePlugin.setMute(value)) {

  • 3943
  • var instances = this._instances;

  • 3944
  • for (var i = 0, l = instances.length; i < l; i++) {

  • 3945
  • instances[i].setMasterMute(value);

  • 3946
  • }

  • 3947
  • }

  • 3948
  • return true;

  • 3949
  • }

  • 3950
  • });

  • 3951  
    3952
  • /**

  • 3953
  • * Get the active plugins capabilities, which help determine if a plugin can be used in the current environment,

  • 3954
  • * or if the plugin supports a specific feature. Capabilities include:

  • 3955
  • * <ul>

  • 3956
  • * <li><b>panning:</b> If the plugin can pan audio from left to right</li>

  • 3957
  • * <li><b>volume;</b> If the plugin can control audio volume.</li>

  • 3958
  • * <li><b>tracks:</b> The maximum number of audio tracks that can be played back at a time. This will be -1

  • 3959
  • * if there is no known limit.</li>

  • 3960
  • * <br />An entry for each file type in {{#crossLink "Sound/SUPPORTED_EXTENSIONS:property"}}{{/crossLink}}:

  • 3961
  • * <li><b>mp3:</b> If MP3 audio is supported.</li>

  • 3962
  • * <li><b>ogg:</b> If OGG audio is supported.</li>

  • 3963
  • * <li><b>wav:</b> If WAV audio is supported.</li>

  • 3964
  • * <li><b>mpeg:</b> If MPEG audio is supported.</li>

  • 3965
  • * <li><b>m4a:</b> If M4A audio is supported.</li>

  • 3966
  • * <li><b>mp4:</b> If MP4 audio is supported.</li>

  • 3967
  • * <li><b>aiff:</b> If aiff audio is supported.</li>

  • 3968
  • * <li><b>wma:</b> If wma audio is supported.</li>

  • 3969
  • * <li><b>mid:</b> If mid audio is supported.</li>

  • 3970
  • * </ul>

  • 3971
  • *

  • 3972
  • * You can get a specific capability of the active plugin using standard object notation

  • 3973
  • *

  • 3974
  • * <h4>Example</h4>

  • 3975
  • *

  • 3976
  • * var mp3 = createjs.Sound.capabilities.mp3;

  • 3977
  • *

  • 3978
  • * Note this property is read only.

  • 3979
  • *

  • 3980
  • * @property capabilities

  • 3981
  • * @type {Object}

  • 3982
  • * @static

  • 3983
  • * @readOnly

  • 3984
  • * @since 0.6.1

  • 3985
  • */

  • 3986
  • Object.defineProperty(s, "capabilities", {

  • 3987
  • get: function () {

  • 3988
  • if (s.activePlugin == null) {return null;}

  • 3989
  • return s.activePlugin._capabilities;

  • 3990
  • },

  • 3991
  • set: function (value) { return false;}

  • 3992
  • });

  • 3993  
    3994  
    3995
  • // Class Private properties

  • 3996
  • /**

  • 3997
  • * Determines if the plugins have been registered. If false, the first call to play() will instantiate the default

  • 3998
  • * plugins ({{#crossLink "WebAudioPlugin"}}{{/crossLink}}, followed by {{#crossLink "HTMLAudioPlugin"}}{{/crossLink}}).

  • 3999
  • * If plugins have been registered, but none are applicable, then sound playback will fail.

  • 4000
  • * @property _pluginsRegistered

  • 4001
  • * @type {Boolean}

  • 4002
  • * @default false

  • 4003
  • * @static

  • 4004
  • * @protected

  • 4005
  • */

  • 4006
  • s._pluginsRegistered = false;

  • 4007  
    4008
  • /**

  • 4009
  • * Used internally to assign unique IDs to each AbstractSoundInstance.

  • 4010
  • * @property _lastID

  • 4011
  • * @type {Number}

  • 4012
  • * @static

  • 4013
  • * @protected

  • 4014
  • */

  • 4015
  • s._lastID = 0;

  • 4016  
    4017
  • /**

  • 4018
  • * An array containing all currently playing instances. This allows Sound to control the volume, mute, and playback of

  • 4019
  • * all instances when using static APIs like {{#crossLink "Sound/stop"}}{{/crossLink}} and {{#crossLink "Sound/setVolume"}}{{/crossLink}}.

  • 4020
  • * When an instance has finished playback, it gets removed via the {{#crossLink "Sound/finishedPlaying"}}{{/crossLink}}

  • 4021
  • * method. If the user replays an instance, it gets added back in via the {{#crossLink "Sound/_beginPlaying"}}{{/crossLink}}

  • 4022
  • * method.

  • 4023
  • * @property _instances

  • 4024
  • * @type {Array}

  • 4025
  • * @protected

  • 4026
  • * @static

  • 4027
  • */

  • 4028
  • s._instances = [];

  • 4029  
    4030
  • /**

  • 4031
  • * An object hash storing objects with sound sources, startTime, and duration via there corresponding ID.

  • 4032
  • * @property _idHash

  • 4033
  • * @type {Object}

  • 4034
  • * @protected

  • 4035
  • * @static

  • 4036
  • */

  • 4037
  • s._idHash = {};

  • 4038  
    4039
  • /**

  • 4040
  • * An object hash that stores preloading sound sources via the parsed source that is passed to the plugin. Contains the

  • 4041
  • * source, id, and data that was passed in by the user. Parsed sources can contain multiple instances of source, id,

  • 4042
  • * and data.

  • 4043
  • * @property _preloadHash

  • 4044
  • * @type {Object}

  • 4045
  • * @protected

  • 4046
  • * @static

  • 4047
  • */

  • 4048
  • s._preloadHash = {};

  • 4049  
    4050
  • /**

  • 4051
  • * An object hash storing {{#crossLink "PlayPropsConfig"}}{{/crossLink}} via the parsed source that is passed as defaultPlayProps in

  • 4052
  • * {{#crossLink "Sound/registerSound"}}{{/crossLink}} and {{#crossLink "Sound/registerSounds"}}{{/crossLink}}.

  • 4053
  • * @property _defaultPlayPropsHash

  • 4054
  • * @type {Object}

  • 4055
  • * @protected

  • 4056
  • * @static

  • 4057
  • * @since 0.6.1

  • 4058
  • */

  • 4059
  • s._defaultPlayPropsHash = {};

  • 4060  
    4061  
    4062
  • // EventDispatcher methods:

  • 4063
  • s.addEventListener = null;

  • 4064
  • s.removeEventListener = null;

  • 4065
  • s.removeAllEventListeners = null;

  • 4066
  • s.dispatchEvent = null;

  • 4067
  • s.hasEventListener = null;

  • 4068
  • s._listeners = null;

  • 4069  
    4070
  • createjs.EventDispatcher.initialize(s); // inject EventDispatcher methods.

  • 4071  
    4072  
    4073
  • // Events

  • 4074
  • /**

  • 4075
  • * This event is fired when a file finishes loading internally. This event is fired for each loaded sound,

  • 4076
  • * so any handler methods should look up the <code>event.src</code> to handle a particular sound.

  • 4077
  • * @event fileload

  • 4078
  • * @param {Object} target The object that dispatched the event.

  • 4079
  • * @param {String} type The event type.

  • 4080
  • * @param {String} src The source of the sound that was loaded.

  • 4081
  • * @param {String} [id] The id passed in when the sound was registered. If one was not provided, it will be null.

  • 4082
  • * @param {Number|Object} [data] Any additional data associated with the item. If not provided, it will be undefined.

  • 4083
  • * @since 0.4.1

  • 4084
  • */

  • 4085  
    4086
  • /**

  • 4087
  • * This event is fired when a file fails loading internally. This event is fired for each loaded sound,

  • 4088
  • * so any handler methods should look up the <code>event.src</code> to handle a particular sound.

  • 4089
  • * @event fileerror

  • 4090
  • * @param {Object} target The object that dispatched the event.

  • 4091
  • * @param {String} type The event type.

  • 4092
  • * @param {String} src The source of the sound that was loaded.

  • 4093
  • * @param {String} [id] The id passed in when the sound was registered. If one was not provided, it will be null.

  • 4094
  • * @param {Number|Object} [data] Any additional data associated with the item. If not provided, it will be undefined.

  • 4095
  • * @since 0.6.0

  • 4096
  • */

  • 4097  
    4098  
    4099
  • // Class Public Methods

  • 4100
  • /**

  • 4101
  • * Get the preload rules to allow Sound to be used as a plugin by <a href="http://preloadjs.com" target="_blank">PreloadJS</a>.

  • 4102
  • * Any load calls that have the matching type or extension will fire the callback method, and use the resulting

  • 4103
  • * object, which is potentially modified by Sound. This helps when determining the correct path, as well as

  • 4104
  • * registering the audio instance(s) with Sound. This method should not be called, except by PreloadJS.

  • 4105
  • * @method getPreloadHandlers

  • 4106
  • * @return {Object} An object containing:

  • 4107
  • * <ul><li>callback: A preload callback that is fired when a file is added to PreloadJS, which provides

  • 4108
  • * Sound a mechanism to modify the load parameters, select the correct file format, register the sound, etc.</li>

  • 4109
  • * <li>types: A list of file types that are supported by Sound (currently supports "sound").</li>

  • 4110
  • * <li>extensions: A list of file extensions that are supported by Sound (see {{#crossLink "Sound/SUPPORTED_EXTENSIONS:property"}}{{/crossLink}}).</li></ul>

  • 4111
  • * @static

  • 4112
  • * @protected

  • 4113
  • */

  • 4114
  • s.getPreloadHandlers = function () {

  • 4115
  • return {

  • 4116
  • callback:createjs.proxy(s.initLoad, s),

  • 4117
  • types:["sound"],

  • 4118
  • extensions:s.SUPPORTED_EXTENSIONS

  • 4119
  • };

  • 4120
  • };

  • 4121  
    4122
  • /**

  • 4123
  • * Used to dispatch fileload events from internal loading.

  • 4124
  • * @method _handleLoadComplete

  • 4125
  • * @param event A loader event.

  • 4126
  • * @protected

  • 4127
  • * @static

  • 4128
  • * @since 0.6.0

  • 4129
  • */

  • 4130
  • s._handleLoadComplete = function(event) {

  • 4131
  • var src = event.target.getItem().src;

  • 4132
  • if (!s._preloadHash[src]) {return;}

  • 4133  
    4134
  • for (var i = 0, l = s._preloadHash[src].length; i < l; i++) {

  • 4135
  • var item = s._preloadHash[src][i];

  • 4136
  • s._preloadHash[src][i] = true;

  • 4137  
    4138
  • if (!s.hasEventListener("fileload")) { continue; }

  • 4139  
    4140
  • var event = new createjs.Event("fileload");

  • 4141
  • event.src = item.src;

  • 4142
  • event.id = item.id;

  • 4143
  • event.data = item.data;

  • 4144
  • event.sprite = item.sprite;

  • 4145  
    4146
  • s.dispatchEvent(event);

  • 4147
  • }

  • 4148
  • };

  • 4149  
    4150
  • /**

  • 4151
  • * Used to dispatch error events from internal preloading.

  • 4152
  • * @param event

  • 4153
  • * @protected

  • 4154
  • * @since 0.6.0

  • 4155
  • * @static

  • 4156
  • */

  • 4157
  • s._handleLoadError = function(event) {

  • 4158
  • var src = event.target.getItem().src;

  • 4159
  • if (!s._preloadHash[src]) {return;}

  • 4160  
    4161
  • for (var i = 0, l = s._preloadHash[src].length; i < l; i++) {

  • 4162
  • var item = s._preloadHash[src][i];

  • 4163
  • s._preloadHash[src][i] = false;

  • 4164  
    4165
  • if (!s.hasEventListener("fileerror")) { continue; }

  • 4166  
    4167
  • var event = new createjs.Event("fileerror");

  • 4168
  • event.src = item.src;

  • 4169
  • event.id = item.id;

  • 4170
  • event.data = item.data;

  • 4171
  • event.sprite = item.sprite;

  • 4172  
    4173
  • s.dispatchEvent(event);

  • 4174
  • }

  • 4175
  • };

  • 4176  
    4177
  • /**

  • 4178
  • * Used by {{#crossLink "Sound/registerPlugins"}}{{/crossLink}} to register a Sound plugin.

  • 4179
  • *

  • 4180
  • * @method _registerPlugin

  • 4181
  • * @param {Object} plugin The plugin class to install.

  • 4182
  • * @return {Boolean} Whether the plugin was successfully initialized.

  • 4183
  • * @static

  • 4184
  • * @private

  • 4185
  • */

  • 4186
  • s._registerPlugin = function (plugin) {

  • 4187
  • // Note: Each plugin is passed in as a class reference, but we store the activePlugin as an instance

  • 4188
  • if (plugin.isSupported()) {

  • 4189
  • s.activePlugin = new plugin();

  • 4190
  • return true;

  • 4191
  • }

  • 4192
  • return false;

  • 4193
  • };

  • 4194  
    4195
  • /**

  • 4196
  • * Register a list of Sound plugins, in order of precedence. To register a single plugin, pass a single element in the array.

  • 4197
  • *

  • 4198
  • * <h4>Example</h4>

  • 4199
  • *

  • 4200
  • * createjs.FlashAudioPlugin.swfPath = "../src/soundjs/flashaudio/";

  • 4201
  • * createjs.Sound.registerPlugins([createjs.WebAudioPlugin, createjs.HTMLAudioPlugin, createjs.FlashAudioPlugin]);

  • 4202
  • *

  • 4203
  • * @method registerPlugins

  • 4204
  • * @param {Array} plugins An array of plugins classes to install.

  • 4205
  • * @return {Boolean} Whether a plugin was successfully initialized.

  • 4206
  • * @static

  • 4207
  • */

  • 4208
  • s.registerPlugins = function (plugins) {

  • 4209
  • s._pluginsRegistered = true;

  • 4210
  • for (var i = 0, l = plugins.length; i < l; i++) {

  • 4211
  • if (s._registerPlugin(plugins[i])) {

  • 4212
  • return true;

  • 4213
  • }

  • 4214
  • }

  • 4215
  • return false;

  • 4216
  • };

  • 4217  
    4218
  • /**

  • 4219
  • * Initialize the default plugins. This method is automatically called when any audio is played or registered before

  • 4220
  • * the user has manually registered plugins, and enables Sound to work without manual plugin setup. Currently, the

  • 4221
  • * default plugins are {{#crossLink "WebAudioPlugin"}}{{/crossLink}} followed by {{#crossLink "HTMLAudioPlugin"}}{{/crossLink}}.

  • 4222
  • *

  • 4223
  • * <h4>Example</h4>

  • 4224
  • *

  • 4225
  • * if (!createjs.initializeDefaultPlugins()) { return; }

  • 4226
  • *

  • 4227
  • * @method initializeDefaultPlugins

  • 4228
  • * @returns {Boolean} True if a plugin was initialized, false otherwise.

  • 4229
  • * @since 0.4.0

  • 4230
  • * @static

  • 4231
  • */

  • 4232
  • s.initializeDefaultPlugins = function () {

  • 4233
  • if (s.activePlugin != null) {return true;}

  • 4234
  • if (s._pluginsRegistered) {return false;}

  • 4235
  • if (s.registerPlugins([createjs.WebAudioPlugin, createjs.HTMLAudioPlugin])) {return true;}

  • 4236
  • return false;

  • 4237
  • };

  • 4238  
    4239
  • /**

  • 4240
  • * Determines if Sound has been initialized, and a plugin has been activated.

  • 4241
  • *

  • 4242
  • * <h4>Example</h4>

  • 4243
  • * This example sets up a Flash fallback, but only if there is no plugin specified yet.

  • 4244
  • *

  • 4245
  • * if (!createjs.Sound.isReady()) {

  • 4246
  • * createjs.FlashAudioPlugin.swfPath = "../src/soundjs/flashaudio/";

  • 4247
  • * createjs.Sound.registerPlugins([createjs.WebAudioPlugin, createjs.HTMLAudioPlugin, createjs.FlashAudioPlugin]);

  • 4248
  • * }

  • 4249
  • *

  • 4250
  • * @method isReady

  • 4251
  • * @return {Boolean} If Sound has initialized a plugin.

  • 4252
  • * @static

  • 4253
  • */

  • 4254
  • s.isReady = function () {

  • 4255
  • return (s.activePlugin != null);

  • 4256
  • };

  • 4257  
    4258
  • /**

  • 4259
  • * Deprecated, please use {{#crossLink "Sound/capabilities:property"}}{{/crossLink}} instead.

  • 4260
  • *

  • 4261
  • * @method getCapabilities

  • 4262
  • * @return {Object} An object containing the capabilities of the active plugin.

  • 4263
  • * @static

  • 4264
  • * @deprecated

  • 4265
  • */

  • 4266
  • s.getCapabilities = function () {

  • 4267
  • if (s.activePlugin == null) {return null;}

  • 4268
  • return s.activePlugin._capabilities;

  • 4269
  • };

  • 4270  
    4271
  • /**

  • 4272
  • * Deprecated, please use {{#crossLink "Sound/capabilities:property"}}{{/crossLink}} instead.

  • 4273
  • *

  • 4274
  • * @method getCapability

  • 4275
  • * @param {String} key The capability to retrieve

  • 4276
  • * @return {Number|Boolean} The value of the capability.

  • 4277
  • * @static

  • 4278
  • * @see getCapabilities

  • 4279
  • * @deprecated

  • 4280
  • */

  • 4281
  • s.getCapability = function (key) {

  • 4282
  • if (s.activePlugin == null) {return null;}

  • 4283
  • return s.activePlugin._capabilities[key];

  • 4284
  • };

  • 4285  
    4286
  • /**

  • 4287
  • * Process manifest items from <a href="http://preloadjs.com" target="_blank">PreloadJS</a>. This method is intended

  • 4288
  • * for usage by a plugin, and not for direct interaction.

  • 4289
  • * @method initLoad

  • 4290
  • * @param {Object} src The object to load.

  • 4291
  • * @return {Object|AbstractLoader} An instance of AbstractLoader.

  • 4292
  • * @protected

  • 4293
  • * @static

  • 4294
  • */

  • 4295
  • s.initLoad = function (loadItem) {

  • 4296
  • return s._registerSound(loadItem);

  • 4297
  • };

  • 4298  
    4299
  • /**

  • 4300
  • * Internal method for loading sounds. This should not be called directly.

  • 4301
  • *

  • 4302
  • * @method _registerSound

  • 4303
  • * @param {Object} src The object to load, containing src property and optionally containing id and data.

  • 4304
  • * @return {Object} An object with the modified values that were passed in, which defines the sound.

  • 4305
  • * Returns false if the source cannot be parsed or no plugins can be initialized.

  • 4306
  • * Returns true if the source is already loaded.

  • 4307
  • * @static

  • 4308
  • * @private

  • 4309
  • * @since 0.6.0

  • 4310
  • */

  • 4311  
    4312
  • s._registerSound = function (loadItem) {

  • 4313
  • if (!s.initializeDefaultPlugins()) {return false;}

  • 4314  
    4315
  • var details;

  • 4316
  • if (loadItem.src instanceof Object) {

  • 4317
  • details = s._parseSrc(loadItem.src);

  • 4318
  • details.src = loadItem.path + details.src;

  • 4319
  • } else {

  • 4320
  • details = s._parsePath(loadItem.src);

  • 4321
  • }

  • 4322
  • if (details == null) {return false;}

  • 4323
  • loadItem.src = details.src;

  • 4324
  • loadItem.type = "sound";

  • 4325  
    4326
  • var data = loadItem.data;

  • 4327
  • var numChannels = null;

  • 4328
  • if (data != null) {

  • 4329
  • if (!isNaN(data.channels)) {

  • 4330
  • numChannels = parseInt(data.channels);

  • 4331
  • } else if (!isNaN(data)) {

  • 4332
  • numChannels = parseInt(data);

  • 4333
  • }

  • 4334  
    4335
  • if(data.audioSprite) {

  • 4336
  • var sp;

  • 4337
  • for(var i = data.audioSprite.length; i--; ) {

  • 4338
  • sp = data.audioSprite[i];

  • 4339
  • s._idHash[sp.id] = {src: loadItem.src, startTime: parseInt(sp.startTime), duration: parseInt(sp.duration)};

  • 4340  
    4341
  • if (sp.defaultPlayProps) {

  • 4342
  • s._defaultPlayPropsHash[sp.id] = createjs.PlayPropsConfig.create(sp.defaultPlayProps);

  • 4343
  • }

  • 4344
  • }

  • 4345
  • }

  • 4346
  • }

  • 4347
  • if (loadItem.id != null) {s._idHash[loadItem.id] = {src: loadItem.src}};

  • 4348
  • var loader = s.activePlugin.register(loadItem);

  • 4349  
    4350
  • SoundChannel.create(loadItem.src, numChannels);

  • 4351  
    4352
  • // return the number of instances to the user. This will also be returned in the load event.

  • 4353
  • if (data == null || !isNaN(data)) {

  • 4354
  • loadItem.data = numChannels || SoundChannel.maxPerChannel();

  • 4355
  • } else {

  • 4356
  • loadItem.data.channels = numChannels || SoundChannel.maxPerChannel();

  • 4357
  • }

  • 4358  
    4359
  • if (loader.type) {loadItem.type = loader.type;}

  • 4360  
    4361
  • if (loadItem.defaultPlayProps) {

  • 4362
  • s._defaultPlayPropsHash[loadItem.src] = createjs.PlayPropsConfig.create(loadItem.defaultPlayProps);

  • 4363
  • }

  • 4364
  • return loader;

  • 4365
  • };

  • 4366  
    4367
  • /**

  • 4368
  • * Register an audio file for loading and future playback in Sound. This is automatically called when using

  • 4369
  • * <a href="http://preloadjs.com" target="_blank">PreloadJS</a>. It is recommended to register all sounds that

  • 4370
  • * need to be played back in order to properly prepare and preload them. Sound does internal preloading when required.

  • 4371
  • *

  • 4372
  • * <h4>Example</h4>

  • 4373
  • *

  • 4374
  • * createjs.Sound.alternateExtensions = ["mp3"];

  • 4375
  • * createjs.Sound.on("fileload", handleLoad); // add an event listener for when load is completed

  • 4376
  • * createjs.Sound.registerSound("myAudioPath/mySound.ogg", "myID", 3);

  • 4377
  • * createjs.Sound.registerSound({ogg:"path1/mySound.ogg", mp3:"path2/mySoundNoExtension"}, "myID", 3);

  • 4378
  • *

  • 4379
  • *

  • 4380
  • * @method registerSound

  • 4381
  • * @param {String | Object} src The source or an Object with a "src" property or an Object with multiple extension labeled src properties.

  • 4382
  • * @param {String} [id] An id specified by the user to play the sound later. Note id is required for when src is multiple extension labeled src properties.

  • 4383
  • * @param {Number | Object} [data] Data associated with the item. Sound uses the data parameter as the number of

  • 4384
  • * channels for an audio instance, however a "channels" property can be appended to the data object if it is used

  • 4385
  • * for other information. The audio channels will set a default based on plugin if no value is found.

  • 4386
  • * Sound also uses the data property to hold an {{#crossLink "AudioSprite"}}{{/crossLink}} array of objects in the following format {id, startTime, duration}.<br/>

  • 4387
  • * id used to play the sound later, in the same manner as a sound src with an id.<br/>

  • 4388
  • * startTime is the initial offset to start playback and loop from, in milliseconds.<br/>

  • 4389
  • * duration is the amount of time to play the clip for, in milliseconds.<br/>

  • 4390
  • * This allows Sound to support audio sprites that are played back by id.

  • 4391
  • * @param {string} basePath Set a path that will be prepended to src for loading.

  • 4392
  • * @param {Object | PlayPropsConfig} defaultPlayProps Optional Playback properties that will be set as the defaults on any new AbstractSoundInstance.

  • 4393
  • * See {{#crossLink "PlayPropsConfig"}}{{/crossLink}} for options.

  • 4394
  • * @return {Object} An object with the modified values that were passed in, which defines the sound.

  • 4395
  • * Returns false if the source cannot be parsed or no plugins can be initialized.

  • 4396
  • * Returns true if the source is already loaded.

  • 4397
  • * @static

  • 4398
  • * @since 0.4.0

  • 4399
  • */

  • 4400
  • s.registerSound = function (src, id, data, basePath, defaultPlayProps) {

  • 4401
  • var loadItem = {src: src, id: id, data:data, defaultPlayProps:defaultPlayProps};

  • 4402
  • if (src instanceof Object && src.src) {

  • 4403
  • basePath = id;

  • 4404
  • loadItem = src;

  • 4405
  • }

  • 4406
  • loadItem = createjs.LoadItem.create(loadItem);

  • 4407
  • loadItem.path = basePath;

  • 4408  
    4409
  • if (basePath != null && !(loadItem.src instanceof Object)) {loadItem.src = basePath + src;}

  • 4410  
    4411
  • var loader = s._registerSound(loadItem);

  • 4412
  • if(!loader) {return false;}

  • 4413  
    4414
  • if (!s._preloadHash[loadItem.src]) { s._preloadHash[loadItem.src] = [];}

  • 4415
  • s._preloadHash[loadItem.src].push(loadItem);

  • 4416
  • if (s._preloadHash[loadItem.src].length == 1) {

  • 4417
  • // OJR note this will disallow reloading a sound if loading fails or the source changes

  • 4418
  • loader.on("complete", createjs.proxy(this._handleLoadComplete, this));

  • 4419
  • loader.on("error", createjs.proxy(this._handleLoadError, this));

  • 4420
  • s.activePlugin.preload(loader);

  • 4421
  • } else {

  • 4422
  • if (s._preloadHash[loadItem.src][0] == true) {return true;}

  • 4423
  • }

  • 4424  
    4425
  • return loadItem;

  • 4426
  • };

  • 4427  
    4428
  • /**

  • 4429
  • * Register an array of audio files for loading and future playback in Sound. It is recommended to register all

  • 4430
  • * sounds that need to be played back in order to properly prepare and preload them. Sound does internal preloading

  • 4431
  • * when required.

  • 4432
  • *

  • 4433
  • * <h4>Example</h4>

  • 4434
  • *

  • 4435
  • * var assetPath = "./myAudioPath/";

  • 4436
  • * var sounds = [

  • 4437
  • * {src:"asset0.ogg", id:"example"},

  • 4438
  • * {src:"asset1.ogg", id:"1", data:6},

  • 4439
  • * {src:"asset2.mp3", id:"works"}

  • 4440
  • * {src:{mp3:"path1/asset3.mp3", ogg:"path2/asset3NoExtension}, id:"better"}

  • 4441
  • * ];

  • 4442
  • * createjs.Sound.alternateExtensions = ["mp3"]; // if the passed extension is not supported, try this extension

  • 4443
  • * createjs.Sound.on("fileload", handleLoad); // call handleLoad when each sound loads

  • 4444
  • * createjs.Sound.registerSounds(sounds, assetPath);

  • 4445
  • *

  • 4446
  • * @method registerSounds

  • 4447
  • * @param {Array} sounds An array of objects to load. Objects are expected to be in the format needed for

  • 4448
  • * {{#crossLink "Sound/registerSound"}}{{/crossLink}}: <code>{src:srcURI, id:ID, data:Data}</code>

  • 4449
  • * with "id" and "data" being optional.

  • 4450
  • * You can also pass an object with path and manifest properties, where path is a basePath and manifest is an array of objects to load.

  • 4451
  • * Note id is required if src is an object with extension labeled src properties.

  • 4452
  • * @param {string} basePath Set a path that will be prepended to each src when loading. When creating, playing, or removing

  • 4453
  • * audio that was loaded with a basePath by src, the basePath must be included.

  • 4454
  • * @return {Object} An array of objects with the modified values that were passed in, which defines each sound.

  • 4455
  • * Like registerSound, it will return false for any values when the source cannot be parsed or if no plugins can be initialized.

  • 4456
  • * Also, it will return true for any values when the source is already loaded.

  • 4457
  • * @static

  • 4458
  • * @since 0.6.0

  • 4459
  • */

  • 4460
  • s.registerSounds = function (sounds, basePath) {

  • 4461
  • var returnValues = [];

  • 4462
  • if (sounds.path) {

  • 4463
  • if (!basePath) {

  • 4464
  • basePath = sounds.path;

  • 4465
  • } else {

  • 4466
  • basePath = basePath + sounds.path;

  • 4467
  • }

  • 4468
  • sounds = sounds.manifest;

  • 4469
  • // TODO document this feature

  • 4470
  • }

  • 4471
  • for (var i = 0, l = sounds.length; i < l; i++) {

  • 4472
  • returnValues[i] = createjs.Sound.registerSound(sounds[i].src, sounds[i].id, sounds[i].data, basePath, sounds[i].defaultPlayProps);

  • 4473
  • }

  • 4474
  • return returnValues;

  • 4475
  • };

  • 4476  
    4477
  • /**

  • 4478
  • * Remove a sound that has been registered with {{#crossLink "Sound/registerSound"}}{{/crossLink}} or

  • 4479
  • * {{#crossLink "Sound/registerSounds"}}{{/crossLink}}.

  • 4480
  • * <br />Note this will stop playback on active instances playing this sound before deleting them.

  • 4481
  • * <br />Note if you passed in a basePath, you need to pass it or prepend it to the src here.

  • 4482
  • *

  • 4483
  • * <h4>Example</h4>

  • 4484
  • *

  • 4485
  • * createjs.Sound.removeSound("myID");

  • 4486
  • * createjs.Sound.removeSound("myAudioBasePath/mySound.ogg");

  • 4487
  • * createjs.Sound.removeSound("myPath/myOtherSound.mp3", "myBasePath/");

  • 4488
  • * createjs.Sound.removeSound({mp3:"musicNoExtension", ogg:"music.ogg"}, "myBasePath/");

  • 4489
  • *

  • 4490
  • * @method removeSound

  • 4491
  • * @param {String | Object} src The src or ID of the audio, or an Object with a "src" property, or an Object with multiple extension labeled src properties.

  • 4492
  • * @param {string} basePath Set a path that will be prepended to each src when removing.

  • 4493
  • * @return {Boolean} True if sound is successfully removed.

  • 4494
  • * @static

  • 4495
  • * @since 0.4.1

  • 4496
  • */

  • 4497
  • s.removeSound = function(src, basePath) {

  • 4498
  • if (s.activePlugin == null) {return false;}

  • 4499  
    4500
  • if (src instanceof Object && src.src) {src = src.src;}

  • 4501  
    4502
  • var details;

  • 4503
  • if (src instanceof Object) {

  • 4504
  • details = s._parseSrc(src);

  • 4505
  • } else {

  • 4506
  • src = s._getSrcById(src).src;

  • 4507
  • details = s._parsePath(src);

  • 4508
  • }

  • 4509
  • if (details == null) {return false;}

  • 4510
  • src = details.src;

  • 4511
  • if (basePath != null) {src = basePath + src;}

  • 4512  
    4513
  • for(var prop in s._idHash){

  • 4514
  • if(s._idHash[prop].src == src) {

  • 4515
  • delete(s._idHash[prop]);

  • 4516
  • }

  • 4517
  • }

  • 4518  
    4519
  • // clear from SoundChannel, which also stops and deletes all instances

  • 4520
  • SoundChannel.removeSrc(src);

  • 4521  
    4522
  • delete(s._preloadHash[src]);

  • 4523  
    4524
  • s.activePlugin.removeSound(src);

  • 4525  
    4526
  • return true;

  • 4527
  • };

  • 4528  
    4529
  • /**

  • 4530
  • * Remove an array of audio files that have been registered with {{#crossLink "Sound/registerSound"}}{{/crossLink}} or

  • 4531
  • * {{#crossLink "Sound/registerSounds"}}{{/crossLink}}.

  • 4532
  • * <br />Note this will stop playback on active instances playing this audio before deleting them.

  • 4533
  • * <br />Note if you passed in a basePath, you need to pass it or prepend it to the src here.

  • 4534
  • *

  • 4535
  • * <h4>Example</h4>

  • 4536
  • *

  • 4537
  • * assetPath = "./myPath/";

  • 4538
  • * var sounds = [

  • 4539
  • * {src:"asset0.ogg", id:"example"},

  • 4540
  • * {src:"asset1.ogg", id:"1", data:6},

  • 4541
  • * {src:"asset2.mp3", id:"works"}

  • 4542
  • * ];

  • 4543
  • * createjs.Sound.removeSounds(sounds, assetPath);

  • 4544
  • *

  • 4545
  • * @method removeSounds

  • 4546
  • * @param {Array} sounds An array of objects to remove. Objects are expected to be in the format needed for

  • 4547
  • * {{#crossLink "Sound/removeSound"}}{{/crossLink}}: <code>{srcOrID:srcURIorID}</code>.

  • 4548
  • * You can also pass an object with path and manifest properties, where path is a basePath and manifest is an array of objects to remove.

  • 4549
  • * @param {string} basePath Set a path that will be prepended to each src when removing.

  • 4550
  • * @return {Object} An array of Boolean values representing if the sounds with the same array index were

  • 4551
  • * successfully removed.

  • 4552
  • * @static

  • 4553
  • * @since 0.4.1

  • 4554
  • */

  • 4555
  • s.removeSounds = function (sounds, basePath) {

  • 4556
  • var returnValues = [];

  • 4557
  • if (sounds.path) {

  • 4558
  • if (!basePath) {

  • 4559
  • basePath = sounds.path;

  • 4560
  • } else {

  • 4561
  • basePath = basePath + sounds.path;

  • 4562
  • }

  • 4563
  • sounds = sounds.manifest;

  • 4564
  • }

  • 4565
  • for (var i = 0, l = sounds.length; i < l; i++) {

  • 4566
  • returnValues[i] = createjs.Sound.removeSound(sounds[i].src, basePath);

  • 4567
  • }

  • 4568
  • return returnValues;

  • 4569
  • };

  • 4570  
    4571
  • /**

  • 4572
  • * Remove all sounds that have been registered with {{#crossLink "Sound/registerSound"}}{{/crossLink}} or

  • 4573
  • * {{#crossLink "Sound/registerSounds"}}{{/crossLink}}.

  • 4574
  • * <br />Note this will stop playback on all active sound instances before deleting them.

  • 4575
  • *

  • 4576
  • * <h4>Example</h4>

  • 4577
  • *

  • 4578
  • * createjs.Sound.removeAllSounds();

  • 4579
  • *

  • 4580
  • * @method removeAllSounds

  • 4581
  • * @static

  • 4582
  • * @since 0.4.1

  • 4583
  • */

  • 4584
  • s.removeAllSounds = function() {

  • 4585
  • s._idHash = {};

  • 4586
  • s._preloadHash = {};

  • 4587
  • SoundChannel.removeAll();

  • 4588
  • if (s.activePlugin) {s.activePlugin.removeAllSounds();}

  • 4589
  • };

  • 4590  
    4591
  • /**

  • 4592
  • * Check if a source has been loaded by internal preloaders. This is necessary to ensure that sounds that are

  • 4593
  • * not completed preloading will not kick off a new internal preload if they are played.

  • 4594
  • *

  • 4595
  • * <h4>Example</h4>

  • 4596
  • *

  • 4597
  • * var mySound = "assetPath/asset0.ogg";

  • 4598
  • * if(createjs.Sound.loadComplete(mySound) {

  • 4599
  • * createjs.Sound.play(mySound);

  • 4600
  • * }

  • 4601
  • *

  • 4602
  • * @method loadComplete

  • 4603
  • * @param {String} src The src or id that is being loaded.

  • 4604
  • * @return {Boolean} If the src is already loaded.

  • 4605
  • * @since 0.4.0

  • 4606
  • * @static

  • 4607
  • */

  • 4608
  • s.loadComplete = function (src) {

  • 4609
  • if (!s.isReady()) { return false; }

  • 4610
  • var details = s._parsePath(src);

  • 4611
  • if (details) {

  • 4612
  • src = s._getSrcById(details.src).src;

  • 4613
  • } else {

  • 4614
  • src = s._getSrcById(src).src;

  • 4615
  • }

  • 4616
  • if(s._preloadHash[src] == undefined) {return false;}

  • 4617
  • return (s._preloadHash[src][0] == true); // src only loads once, so if it's true for the first it's true for all

  • 4618
  • };

  • 4619  
    4620
  • /**

  • 4621
  • * Parse the path of a sound. Alternate extensions will be attempted in order if the

  • 4622
  • * current extension is not supported

  • 4623
  • * @method _parsePath

  • 4624
  • * @param {String} value The path to an audio source.

  • 4625
  • * @return {Object} A formatted object that can be registered with the {{#crossLink "Sound/activePlugin:property"}}{{/crossLink}}

  • 4626
  • * and returned to a preloader like <a href="http://preloadjs.com" target="_blank">PreloadJS</a>.

  • 4627
  • * @protected

  • 4628
  • * @static

  • 4629
  • */

  • 4630
  • s._parsePath = function (value) {

  • 4631
  • if (typeof(value) != "string") {value = value.toString();}

  • 4632  
    4633
  • var match = value.match(s.FILE_PATTERN);

  • 4634
  • if (match == null) {return false;}

  • 4635  
    4636
  • var name = match[4];

  • 4637
  • var ext = match[5];

  • 4638
  • var c = s.capabilities;

  • 4639
  • var i = 0;

  • 4640
  • while (!c[ext]) {

  • 4641
  • ext = s.alternateExtensions[i++];

  • 4642
  • if (i > s.alternateExtensions.length) { return null;} // no extensions are supported

  • 4643
  • }

  • 4644
  • value = value.replace("."+match[5], "."+ext);

  • 4645  
    4646
  • var ret = {name:name, src:value, extension:ext};

  • 4647
  • return ret;

  • 4648
  • };

  • 4649  
    4650
  • /**

  • 4651
  • * Parse the path of a sound based on properties of src matching with supported extensions.

  • 4652
  • * Returns false if none of the properties are supported

  • 4653
  • * @method _parseSrc

  • 4654
  • * @param {Object} value The paths to an audio source, indexed by extension type.

  • 4655
  • * @return {Object} A formatted object that can be registered with the {{#crossLink "Sound/activePlugin:property"}}{{/crossLink}}

  • 4656
  • * and returned to a preloader like <a href="http://preloadjs.com" target="_blank">PreloadJS</a>.

  • 4657
  • * @protected

  • 4658
  • * @static

  • 4659
  • */

  • 4660
  • s._parseSrc = function (value) {

  • 4661
  • var ret = {name:undefined, src:undefined, extension:undefined};

  • 4662
  • var c = s.capabilities;

  • 4663  
    4664
  • for (var prop in value) {

  • 4665
  • if(value.hasOwnProperty(prop) && c[prop]) {

  • 4666
  • ret.src = value[prop];

  • 4667
  • ret.extension = prop;

  • 4668
  • break;

  • 4669
  • }

  • 4670
  • }

  • 4671
  • if (!ret.src) {return false;} // no matches

  • 4672  
    4673
  • var i = ret.src.lastIndexOf("/");

  • 4674
  • if (i != -1) {

  • 4675
  • ret.name = ret.src.slice(i+1);

  • 4676
  • } else {

  • 4677
  • ret.name = ret.src;

  • 4678
  • }

  • 4679  
    4680
  • return ret;

  • 4681
  • };

  • 4682  
    4683
  • /* ---------------

  • 4684
  • Static API.

  • 4685
  • --------------- */

  • 4686
  • /**

  • 4687
  • * Play a sound and get a {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} to control. If the sound fails to play, a

  • 4688
  • * AbstractSoundInstance will still be returned, and have a playState of {{#crossLink "Sound/PLAY_FAILED:property"}}{{/crossLink}}.

  • 4689
  • * Note that even on sounds with failed playback, you may still be able to call AbstractSoundInstance {{#crossLink "AbstractSoundInstance/play"}}{{/crossLink}},

  • 4690
  • * since the failure could be due to lack of available channels. If the src does not have a supported extension or

  • 4691
  • * if there is no available plugin, a default AbstractSoundInstance will be returned which will not play any audio, but will not generate errors.

  • 4692
  • *

  • 4693
  • * <h4>Example</h4>

  • 4694
  • *

  • 4695
  • * createjs.Sound.on("fileload", handleLoad);

  • 4696
  • * createjs.Sound.registerSound("myAudioPath/mySound.mp3", "myID", 3);

  • 4697
  • * function handleLoad(event) {

  • 4698
  • * createjs.Sound.play("myID");

  • 4699
  • * // store off AbstractSoundInstance for controlling

  • 4700
  • * var myInstance = createjs.Sound.play("myID", {interrupt: createjs.Sound.INTERRUPT_ANY, loop:-1});

  • 4701
  • * }

  • 4702
  • *

  • 4703
  • * NOTE to create an audio sprite that has not already been registered, both startTime and duration need to be set.

  • 4704
  • * This is only when creating a new audio sprite, not when playing using the id of an already registered audio sprite.

  • 4705
  • *

  • 4706
  • * <b>Parameters Deprecated</b><br />

  • 4707
  • * The parameters for this method are deprecated in favor of a single parameter that is an Object or {{#crossLink "PlayPropsConfig"}}{{/crossLink}}.

  • 4708
  • *

  • 4709
  • * @method play

  • 4710
  • * @param {String} src The src or ID of the audio.

  • 4711
  • * @param {String | Object} [interrupt="none"|options] <b>This parameter will be renamed playProps in the next release.</b><br />

  • 4712
  • * This parameter can be an instance of {{#crossLink "PlayPropsConfig"}}{{/crossLink}} or an Object that contains any or all optional properties by name,

  • 4713
  • * including: interrupt, delay, offset, loop, volume, pan, startTime, and duration (see the above code sample).

  • 4714
  • * <br /><strong>OR</strong><br />

  • 4715
  • * <b>Deprecated</b> How to interrupt any currently playing instances of audio with the same source,

  • 4716
  • * if the maximum number of instances of the sound are already playing. Values are defined as <code>INTERRUPT_TYPE</code>

  • 4717
  • * constants on the Sound class, with the default defined by {{#crossLink "Sound/defaultInterruptBehavior:property"}}{{/crossLink}}.

  • 4718
  • * @param {Number} [delay=0] <b>Deprecated</b> The amount of time to delay the start of audio playback, in milliseconds.

  • 4719
  • * @param {Number} [offset=0] <b>Deprecated</b> The offset from the start of the audio to begin playback, in milliseconds.

  • 4720
  • * @param {Number} [loop=0] <b>Deprecated</b> How many times the audio loops when it reaches the end of playback. The default is 0 (no

  • 4721
  • * loops), and -1 can be used for infinite playback.

  • 4722
  • * @param {Number} [volume=1] <b>Deprecated</b> The volume of the sound, between 0 and 1. Note that the master volume is applied

  • 4723
  • * against the individual volume.

  • 4724
  • * @param {Number} [pan=0] <b>Deprecated</b> The left-right pan of the sound (if supported), between -1 (left) and 1 (right).

  • 4725
  • * @param {Number} [startTime=null] <b>Deprecated</b> To create an audio sprite (with duration), the initial offset to start playback and loop from, in milliseconds.

  • 4726
  • * @param {Number} [duration=null] <b>Deprecated</b> To create an audio sprite (with startTime), the amount of time to play the clip for, in milliseconds.

  • 4727
  • * @return {AbstractSoundInstance} A {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} that can be controlled after it is created.

  • 4728
  • * @static

  • 4729
  • */

  • 4730
  • s.play = function (src, interrupt, delay, offset, loop, volume, pan, startTime, duration) {

  • 4731
  • var playProps;

  • 4732
  • if (interrupt instanceof Object || interrupt instanceof createjs.PlayPropsConfig) {

  • 4733
  • playProps = createjs.PlayPropsConfig.create(interrupt);

  • 4734
  • } else {

  • 4735
  • playProps = createjs.PlayPropsConfig.create({interrupt:interrupt, delay:delay, offset:offset, loop:loop, volume:volume, pan:pan, startTime:startTime, duration:duration});

  • 4736
  • }

  • 4737
  • var instance = s.createInstance(src, playProps.startTime, playProps.duration);

  • 4738
  • var ok = s._playInstance(instance, playProps);

  • 4739
  • if (!ok) {instance._playFailed();}

  • 4740
  • return instance;

  • 4741
  • };

  • 4742  
    4743
  • /**

  • 4744
  • * Creates a {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} using the passed in src. If the src does not have a

  • 4745
  • * supported extension or if there is no available plugin, a default AbstractSoundInstance will be returned that can be

  • 4746
  • * called safely but does nothing.

  • 4747
  • *

  • 4748
  • * <h4>Example</h4>

  • 4749
  • *

  • 4750
  • * var myInstance = null;

  • 4751
  • * createjs.Sound.on("fileload", handleLoad);

  • 4752
  • * createjs.Sound.registerSound("myAudioPath/mySound.mp3", "myID", 3);

  • 4753
  • * function handleLoad(event) {

  • 4754
  • * myInstance = createjs.Sound.createInstance("myID");

  • 4755
  • * // alternately we could call the following

  • 4756
  • * myInstance = createjs.Sound.createInstance("myAudioPath/mySound.mp3");

  • 4757
  • * }

  • 4758
  • *

  • 4759
  • * NOTE to create an audio sprite that has not already been registered, both startTime and duration need to be set.

  • 4760
  • * This is only when creating a new audio sprite, not when playing using the id of an already registered audio sprite.

  • 4761
  • *

  • 4762
  • * @method createInstance

  • 4763
  • * @param {String} src The src or ID of the audio.

  • 4764
  • * @param {Number} [startTime=null] To create an audio sprite (with duration), the initial offset to start playback and loop from, in milliseconds.

  • 4765
  • * @param {Number} [duration=null] To create an audio sprite (with startTime), the amount of time to play the clip for, in milliseconds.

  • 4766
  • * @return {AbstractSoundInstance} A {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} that can be controlled after it is created.

  • 4767
  • * Unsupported extensions will return the default AbstractSoundInstance.

  • 4768
  • * @since 0.4.0

  • 4769
  • * @static

  • 4770
  • */

  • 4771
  • s.createInstance = function (src, startTime, duration) {

  • 4772
  • if (!s.initializeDefaultPlugins()) {return new createjs.DefaultSoundInstance(src, startTime, duration);}

  • 4773  
    4774
  • var defaultPlayProps = s._defaultPlayPropsHash[src]; // for audio sprites, which create and store defaults by id

  • 4775
  • src = s._getSrcById(src);

  • 4776  
    4777
  • var details = s._parsePath(src.src);

  • 4778  
    4779
  • var instance = null;

  • 4780
  • if (details != null && details.src != null) {

  • 4781
  • SoundChannel.create(details.src);

  • 4782
  • if (startTime == null) {startTime = src.startTime;}

  • 4783
  • instance = s.activePlugin.create(details.src, startTime, duration || src.duration);

  • 4784  
    4785
  • defaultPlayProps = defaultPlayProps || s._defaultPlayPropsHash[details.src];

  • 4786
  • if(defaultPlayProps) {

  • 4787
  • instance.applyPlayProps(defaultPlayProps);

  • 4788
  • }

  • 4789
  • } else {

  • 4790
  • instance = new createjs.DefaultSoundInstance(src, startTime, duration);

  • 4791
  • }

  • 4792  
    4793
  • instance.uniqueId = s._lastID++;

  • 4794  
    4795
  • return instance;

  • 4796
  • };

  • 4797  
    4798
  • /**

  • 4799
  • * Stop all audio (global stop). Stopped audio is reset, and not paused. To play audio that has been stopped,

  • 4800
  • * call AbstractSoundInstance {{#crossLink "AbstractSoundInstance/play"}}{{/crossLink}}.

  • 4801
  • *

  • 4802
  • * <h4>Example</h4>

  • 4803
  • *

  • 4804
  • * createjs.Sound.stop();

  • 4805
  • *

  • 4806
  • * @method stop

  • 4807
  • * @static

  • 4808
  • */

  • 4809
  • s.stop = function () {

  • 4810
  • var instances = this._instances;

  • 4811
  • for (var i = instances.length; i--; ) {

  • 4812
  • instances[i].stop(); // NOTE stop removes instance from this._instances

  • 4813
  • }

  • 4814
  • };

  • 4815  
    4816
  • /**

  • 4817
  • * Deprecated, please use {{#crossLink "Sound/volume:property"}}{{/crossLink}} instead.

  • 4818
  • *

  • 4819
  • * @method setVolume

  • 4820
  • * @param {Number} value The master volume value. The acceptable range is 0-1.

  • 4821
  • * @static

  • 4822
  • * @deprecated

  • 4823
  • */

  • 4824
  • s.setVolume = function (value) {

  • 4825
  • if (Number(value) == null) {return false;}

  • 4826
  • value = Math.max(0, Math.min(1, value));

  • 4827
  • s._masterVolume = value;

  • 4828
  • if (!this.activePlugin || !this.activePlugin.setVolume || !this.activePlugin.setVolume(value)) {

  • 4829
  • var instances = this._instances;

  • 4830
  • for (var i = 0, l = instances.length; i < l; i++) {

  • 4831
  • instances[i].setMasterVolume(value);

  • 4832
  • }

  • 4833
  • }

  • 4834
  • };

  • 4835  
    4836
  • /**

  • 4837
  • * Deprecated, please use {{#crossLink "Sound/volume:property"}}{{/crossLink}} instead.

  • 4838
  • *

  • 4839
  • * @method getVolume

  • 4840
  • * @return {Number} The master volume, in a range of 0-1.

  • 4841
  • * @static

  • 4842
  • * @deprecated

  • 4843
  • */

  • 4844
  • s.getVolume = function () {

  • 4845
  • return this._masterVolume;

  • 4846
  • };

  • 4847  
    4848
  • /**

  • 4849
  • * Deprecated, please use {{#crossLink "Sound/muted:property"}}{{/crossLink}} instead.

  • 4850
  • *

  • 4851
  • * @method setMute

  • 4852
  • * @param {Boolean} value Whether the audio should be muted or not.

  • 4853
  • * @return {Boolean} If the mute was set.

  • 4854
  • * @static

  • 4855
  • * @since 0.4.0

  • 4856
  • * @deprecated

  • 4857
  • */

  • 4858
  • s.setMute = function (value) {

  • 4859
  • if (value == null) {return false;}

  • 4860  
    4861
  • this._masterMute = value;

  • 4862
  • if (!this.activePlugin || !this.activePlugin.setMute || !this.activePlugin.setMute(value)) {

  • 4863
  • var instances = this._instances;

  • 4864
  • for (var i = 0, l = instances.length; i < l; i++) {

  • 4865
  • instances[i].setMasterMute(value);

  • 4866
  • }

  • 4867
  • }

  • 4868
  • return true;

  • 4869
  • };

  • 4870  
    4871
  • /**

  • 4872
  • * Deprecated, please use {{#crossLink "Sound/muted:property"}}{{/crossLink}} instead.

  • 4873
  • *

  • 4874
  • * @method getMute

  • 4875
  • * @return {Boolean} The mute value of Sound.

  • 4876
  • * @static

  • 4877
  • * @since 0.4.0

  • 4878
  • * @deprecated

  • 4879
  • */

  • 4880
  • s.getMute = function () {

  • 4881
  • return this._masterMute;

  • 4882
  • };

  • 4883  
    4884
  • /**

  • 4885
  • * Set the default playback properties for all new SoundInstances of the passed in src or ID.

  • 4886
  • * See {{#crossLink "PlayPropsConfig"}}{{/crossLink}} for available properties.

  • 4887
  • *

  • 4888
  • * @method setDefaultPlayProps

  • 4889
  • * @param {String} src The src or ID used to register the audio.

  • 4890
  • * @param {Object | PlayPropsConfig} playProps The playback properties you would like to set.

  • 4891
  • * @since 0.6.1

  • 4892
  • */

  • 4893
  • s.setDefaultPlayProps = function(src, playProps) {

  • 4894
  • src = s._getSrcById(src);

  • 4895
  • s._defaultPlayPropsHash[s._parsePath(src.src).src] = createjs.PlayPropsConfig.create(playProps);

  • 4896
  • };

  • 4897  
    4898
  • /**

  • 4899
  • * Get the default playback properties for the passed in src or ID. These properties are applied to all

  • 4900
  • * new SoundInstances. Returns null if default does not exist.

  • 4901
  • *

  • 4902
  • * @method getDefaultPlayProps

  • 4903
  • * @param {String} src The src or ID used to register the audio.

  • 4904
  • * @returns {PlayPropsConfig} returns an existing PlayPropsConfig or null if one does not exist

  • 4905
  • * @since 0.6.1

  • 4906
  • */

  • 4907
  • s.getDefaultPlayProps = function(src) {

  • 4908
  • src = s._getSrcById(src);

  • 4909
  • return s._defaultPlayPropsHash[s._parsePath(src.src).src];

  • 4910
  • };

  • 4911  
    4912  
    4913
  • /* ---------------

  • 4914
  • Internal methods

  • 4915
  • --------------- */

  • 4916
  • /**

  • 4917
  • * Play an instance. This is called by the static API, as well as from plugins. This allows the core class to

  • 4918
  • * control delays.

  • 4919
  • * @method _playInstance

  • 4920
  • * @param {AbstractSoundInstance} instance The {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} to start playing.

  • 4921
  • * @param {PlayPropsConfig} playProps A PlayPropsConfig object.

  • 4922
  • * @return {Boolean} If the sound can start playing. Sounds that fail immediately will return false. Sounds that

  • 4923
  • * have a delay will return true, but may still fail to play.

  • 4924
  • * @protected

  • 4925
  • * @static

  • 4926
  • */

  • 4927
  • s._playInstance = function (instance, playProps) {

  • 4928
  • var defaultPlayProps = s._defaultPlayPropsHash[instance.src] || {};

  • 4929
  • if (playProps.interrupt == null) {playProps.interrupt = defaultPlayProps.interrupt || s.defaultInterruptBehavior};

  • 4930
  • if (playProps.delay == null) {playProps.delay = defaultPlayProps.delay || 0;}

  • 4931
  • if (playProps.offset == null) {playProps.offset = instance.getPosition();}

  • 4932
  • if (playProps.loop == null) {playProps.loop = instance.loop;}

  • 4933
  • if (playProps.volume == null) {playProps.volume = instance.volume;}

  • 4934
  • if (playProps.pan == null) {playProps.pan = instance.pan;}

  • 4935  
    4936
  • if (playProps.delay == 0) {

  • 4937
  • var ok = s._beginPlaying(instance, playProps);

  • 4938
  • if (!ok) {return false;}

  • 4939
  • } else {

  • 4940
  • //Note that we can't pass arguments to proxy OR setTimeout (IE only), so just wrap the function call.

  • 4941
  • // OJR WebAudio may want to handle this differently, so it might make sense to move this functionality into the plugins in the future

  • 4942
  • var delayTimeoutId = setTimeout(function () {

  • 4943
  • s._beginPlaying(instance, playProps);

  • 4944
  • }, playProps.delay);

  • 4945
  • instance.delayTimeoutId = delayTimeoutId;

  • 4946
  • }

  • 4947  
    4948
  • this._instances.push(instance);

  • 4949  
    4950
  • return true;

  • 4951
  • };

  • 4952  
    4953
  • /**

  • 4954
  • * Begin playback. This is called immediately or after delay by {{#crossLink "Sound/playInstance"}}{{/crossLink}}.

  • 4955
  • * @method _beginPlaying

  • 4956
  • * @param {AbstractSoundInstance} instance A {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} to begin playback.

  • 4957
  • * @param {PlayPropsConfig} playProps A PlayPropsConfig object.

  • 4958
  • * @return {Boolean} If the sound can start playing. If there are no available channels, or the instance fails to

  • 4959
  • * start, this will return false.

  • 4960
  • * @protected

  • 4961
  • * @static

  • 4962
  • */

  • 4963
  • s._beginPlaying = function (instance, playProps) {

  • 4964
  • if (!SoundChannel.add(instance, playProps.interrupt)) {

  • 4965
  • return false;

  • 4966
  • }

  • 4967
  • var result = instance._beginPlaying(playProps);

  • 4968
  • if (!result) {

  • 4969
  • var index = createjs.indexOf(this._instances, instance);

  • 4970
  • if (index > -1) {this._instances.splice(index, 1);}

  • 4971
  • return false;

  • 4972
  • }

  • 4973
  • return true;

  • 4974
  • };

  • 4975  
    4976
  • /**

  • 4977
  • * Get the source of a sound via the ID passed in with a register call. If no ID is found the value is returned

  • 4978
  • * instead.

  • 4979
  • * @method _getSrcById

  • 4980
  • * @param {String} value The ID the sound was registered with.

  • 4981
  • * @return {String} The source of the sound if it has been registered with this ID or the value that was passed in.

  • 4982
  • * @protected

  • 4983
  • * @static

  • 4984
  • */

  • 4985
  • s._getSrcById = function (value) {

  • 4986
  • return s._idHash[value] || {src: value};

  • 4987
  • };

  • 4988  
    4989
  • /**

  • 4990
  • * A sound has completed playback, been interrupted, failed, or been stopped. This method removes the instance from

  • 4991
  • * Sound management. It will be added again, if the sound re-plays. Note that this method is called from the

  • 4992
  • * instances themselves.

  • 4993
  • * @method _playFinished

  • 4994
  • * @param {AbstractSoundInstance} instance The instance that finished playback.

  • 4995
  • * @protected

  • 4996
  • * @static

  • 4997
  • */

  • 4998
  • s._playFinished = function (instance) {

  • 4999
  • SoundChannel.remove(instance);

  • 5000
  • var index = createjs.indexOf(this._instances, instance);

  • 5001
  • if (index > -1) {this._instances.splice(index, 1);} // OJR this will always be > -1, there is no way for an instance to exist without being added to this._instances

  • 5002
  • };

  • 5003  
    5004
  • createjs.Sound = Sound;

  • 5005  
    5006
  • /**

  • 5007
  • * An internal class that manages the number of active {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} instances for

  • 5008
  • * each sound type. This method is only used internally by the {{#crossLink "Sound"}}{{/crossLink}} class.

  • 5009
  • *

  • 5010
  • * The number of sounds is artificially limited by Sound in order to prevent over-saturation of a

  • 5011
  • * single sound, as well as to stay within hardware limitations, although the latter may disappear with better

  • 5012
  • * browser support.

  • 5013
  • *

  • 5014
  • * When a sound is played, this class ensures that there is an available instance, or interrupts an appropriate

  • 5015
  • * sound that is already playing.

  • 5016
  • * #class SoundChannel

  • 5017
  • * @param {String} src The source of the instances

  • 5018
  • * @param {Number} [max=1] The number of instances allowed

  • 5019
  • * @constructor

  • 5020
  • * @protected

  • 5021
  • */

  • 5022
  • function SoundChannel(src, max) {

  • 5023
  • this.init(src, max);

  • 5024
  • }

  • 5025  
    5026
  • /* ------------

  • 5027
  • Static API

  • 5028
  • ------------ */

  • 5029
  • /**

  • 5030
  • * A hash of channel instances indexed by source.

  • 5031
  • * #property channels

  • 5032
  • * @type {Object}

  • 5033
  • * @static

  • 5034
  • */

  • 5035
  • SoundChannel.channels = {};

  • 5036  
    5037
  • /**

  • 5038
  • * Create a sound channel. Note that if the sound channel already exists, this will fail.

  • 5039
  • * #method create

  • 5040
  • * @param {String} src The source for the channel

  • 5041
  • * @param {Number} max The maximum amount this channel holds. The default is {{#crossLink "SoundChannel.maxDefault"}}{{/crossLink}}.

  • 5042
  • * @return {Boolean} If the channels were created.

  • 5043
  • * @static

  • 5044
  • */

  • 5045
  • SoundChannel.create = function (src, max) {

  • 5046
  • var channel = SoundChannel.get(src);

  • 5047
  • if (channel == null) {

  • 5048
  • SoundChannel.channels[src] = new SoundChannel(src, max);

  • 5049
  • return true;

  • 5050
  • }

  • 5051
  • return false;

  • 5052
  • };

  • 5053
  • /**

  • 5054
  • * Delete a sound channel, stop and delete all related instances. Note that if the sound channel does not exist, this will fail.

  • 5055
  • * #method remove

  • 5056
  • * @param {String} src The source for the channel

  • 5057
  • * @return {Boolean} If the channels were deleted.

  • 5058
  • * @static

  • 5059
  • */

  • 5060
  • SoundChannel.removeSrc = function (src) {

  • 5061
  • var channel = SoundChannel.get(src);

  • 5062
  • if (channel == null) {return false;}

  • 5063
  • channel._removeAll(); // this stops and removes all active instances

  • 5064
  • delete(SoundChannel.channels[src]);

  • 5065
  • return true;

  • 5066
  • };

  • 5067
  • /**

  • 5068
  • * Delete all sound channels, stop and delete all related instances.

  • 5069
  • * #method removeAll

  • 5070
  • * @static

  • 5071
  • */

  • 5072
  • SoundChannel.removeAll = function () {

  • 5073
  • for(var channel in SoundChannel.channels) {

  • 5074
  • SoundChannel.channels[channel]._removeAll(); // this stops and removes all active instances

  • 5075
  • }

  • 5076
  • SoundChannel.channels = {};

  • 5077
  • };

  • 5078
  • /**

  • 5079
  • * Add an instance to a sound channel.

  • 5080
  • * #method add

  • 5081
  • * @param {AbstractSoundInstance} instance The instance to add to the channel

  • 5082
  • * @param {String} interrupt The interrupt value to use. Please see the {{#crossLink "Sound/play"}}{{/crossLink}}

  • 5083
  • * for details on interrupt modes.

  • 5084
  • * @return {Boolean} The success of the method call. If the channel is full, it will return false.

  • 5085
  • * @static

  • 5086
  • */

  • 5087
  • SoundChannel.add = function (instance, interrupt) {

  • 5088
  • var channel = SoundChannel.get(instance.src);

  • 5089
  • if (channel == null) {return false;}

  • 5090
  • return channel._add(instance, interrupt);

  • 5091
  • };

  • 5092
  • /**

  • 5093
  • * Remove an instance from the channel.

  • 5094
  • * #method remove

  • 5095
  • * @param {AbstractSoundInstance} instance The instance to remove from the channel

  • 5096
  • * @return The success of the method call. If there is no channel, it will return false.

  • 5097
  • * @static

  • 5098
  • */

  • 5099
  • SoundChannel.remove = function (instance) {

  • 5100
  • var channel = SoundChannel.get(instance.src);

  • 5101
  • if (channel == null) {return false;}

  • 5102
  • channel._remove(instance);

  • 5103
  • return true;

  • 5104
  • };

  • 5105
  • /**

  • 5106
  • * Get the maximum number of sounds you can have in a channel.

  • 5107
  • * #method maxPerChannel

  • 5108
  • * @return {Number} The maximum number of sounds you can have in a channel.

  • 5109
  • */

  • 5110
  • SoundChannel.maxPerChannel = function () {

  • 5111
  • return p.maxDefault;

  • 5112
  • };

  • 5113
  • /**

  • 5114
  • * Get a channel instance by its src.

  • 5115
  • * #method get

  • 5116
  • * @param {String} src The src to use to look up the channel

  • 5117
  • * @static

  • 5118
  • */

  • 5119
  • SoundChannel.get = function (src) {

  • 5120
  • return SoundChannel.channels[src];

  • 5121
  • };

  • 5122  
    5123
  • var p = SoundChannel.prototype;

  • 5124
  • p.constructor = SoundChannel;

  • 5125  
    5126
  • /**

  • 5127
  • * <strong>REMOVED</strong>. Removed in favor of using `MySuperClass_constructor`.

  • 5128
  • * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}}

  • 5129
  • * for details.

  • 5130
  • *

  • 5131
  • * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance.

  • 5132
  • *

  • 5133
  • * @method initialize

  • 5134
  • * @protected

  • 5135
  • * @deprecated

  • 5136
  • */

  • 5137
  • // p.initialize = function() {}; // searchable for devs wondering where it is.

  • 5138  
    5139  
    5140
  • /**

  • 5141
  • * The source of the channel.

  • 5142
  • * #property src

  • 5143
  • * @type {String}

  • 5144
  • */

  • 5145
  • p.src = null;

  • 5146  
    5147
  • /**

  • 5148
  • * The maximum number of instances in this channel. -1 indicates no limit

  • 5149
  • * #property max

  • 5150
  • * @type {Number}

  • 5151
  • */

  • 5152
  • p.max = null;

  • 5153  
    5154
  • /**

  • 5155
  • * The default value to set for max, if it isn't passed in. Also used if -1 is passed.

  • 5156
  • * #property maxDefault

  • 5157
  • * @type {Number}

  • 5158
  • * @default 100

  • 5159
  • * @since 0.4.0

  • 5160
  • */

  • 5161
  • p.maxDefault = 100;

  • 5162  
    5163
  • /**

  • 5164
  • * The current number of active instances.

  • 5165
  • * #property length

  • 5166
  • * @type {Number}

  • 5167
  • */

  • 5168
  • p.length = 0;

  • 5169  
    5170
  • /**

  • 5171
  • * Initialize the channel.

  • 5172
  • * #method init

  • 5173
  • * @param {String} src The source of the channel

  • 5174
  • * @param {Number} max The maximum number of instances in the channel

  • 5175
  • * @protected

  • 5176
  • */

  • 5177
  • p.init = function (src, max) {

  • 5178
  • this.src = src;

  • 5179
  • this.max = max || this.maxDefault;

  • 5180
  • if (this.max == -1) {this.max = this.maxDefault;}

  • 5181
  • this._instances = [];

  • 5182
  • };

  • 5183  
    5184
  • /**

  • 5185
  • * Get an instance by index.

  • 5186
  • * #method get

  • 5187
  • * @param {Number} index The index to return.

  • 5188
  • * @return {AbstractSoundInstance} The AbstractSoundInstance at a specific instance.

  • 5189
  • */

  • 5190
  • p._get = function (index) {

  • 5191
  • return this._instances[index];

  • 5192
  • };

  • 5193  
    5194
  • /**

  • 5195
  • * Add a new instance to the channel.

  • 5196
  • * #method add

  • 5197
  • * @param {AbstractSoundInstance} instance The instance to add.

  • 5198
  • * @return {Boolean} The success of the method call. If the channel is full, it will return false.

  • 5199
  • */

  • 5200
  • p._add = function (instance, interrupt) {

  • 5201
  • if (!this._getSlot(interrupt, instance)) {return false;}

  • 5202
  • this._instances.push(instance);

  • 5203
  • this.length++;

  • 5204
  • return true;

  • 5205
  • };

  • 5206  
    5207
  • /**

  • 5208
  • * Remove an instance from the channel, either when it has finished playing, or it has been interrupted.

  • 5209
  • * #method remove

  • 5210
  • * @param {AbstractSoundInstance} instance The instance to remove

  • 5211
  • * @return {Boolean} The success of the remove call. If the instance is not found in this channel, it will

  • 5212
  • * return false.

  • 5213
  • */

  • 5214
  • p._remove = function (instance) {

  • 5215
  • var index = createjs.indexOf(this._instances, instance);

  • 5216
  • if (index == -1) {return false;}

  • 5217
  • this._instances.splice(index, 1);

  • 5218
  • this.length--;

  • 5219
  • return true;

  • 5220
  • };

  • 5221  
    5222
  • /**

  • 5223
  • * Stop playback and remove all instances from the channel. Usually in response to a delete call.

  • 5224
  • * #method removeAll

  • 5225
  • */

  • 5226
  • p._removeAll = function () {

  • 5227
  • // Note that stop() removes the item from the list

  • 5228
  • for (var i=this.length-1; i>=0; i--) {

  • 5229
  • this._instances[i].stop();

  • 5230
  • }

  • 5231
  • };

  • 5232  
    5233
  • /**

  • 5234
  • * Get an available slot depending on interrupt value and if slots are available.

  • 5235
  • * #method getSlot

  • 5236
  • * @param {String} interrupt The interrupt value to use.

  • 5237
  • * @param {AbstractSoundInstance} instance The sound instance that will go in the channel if successful.

  • 5238
  • * @return {Boolean} Determines if there is an available slot. Depending on the interrupt mode, if there are no slots,

  • 5239
  • * an existing AbstractSoundInstance may be interrupted. If there are no slots, this method returns false.

  • 5240
  • */

  • 5241
  • p._getSlot = function (interrupt, instance) {

  • 5242
  • var target, replacement;

  • 5243  
    5244
  • if (interrupt != Sound.INTERRUPT_NONE) {

  • 5245
  • // First replacement candidate

  • 5246
  • replacement = this._get(0);

  • 5247
  • if (replacement == null) {

  • 5248
  • return true;

  • 5249
  • }

  • 5250
  • }

  • 5251  
    5252
  • for (var i = 0, l = this.max; i < l; i++) {

  • 5253
  • target = this._get(i);

  • 5254  
    5255
  • // Available Space

  • 5256
  • if (target == null) {

  • 5257
  • return true;

  • 5258
  • }

  • 5259  
    5260
  • // Audio is complete or not playing

  • 5261
  • if (target.playState == Sound.PLAY_FINISHED ||

  • 5262
  • target.playState == Sound.PLAY_INTERRUPTED ||

  • 5263
  • target.playState == Sound.PLAY_FAILED) {

  • 5264
  • replacement = target;

  • 5265
  • break;

  • 5266
  • }

  • 5267  
    5268
  • if (interrupt == Sound.INTERRUPT_NONE) {

  • 5269
  • continue;

  • 5270
  • }

  • 5271  
    5272
  • // Audio is a better candidate than the current target, according to playhead

  • 5273
  • if ((interrupt == Sound.INTERRUPT_EARLY && target.getPosition() < replacement.getPosition()) ||

  • 5274
  • (interrupt == Sound.INTERRUPT_LATE && target.getPosition() > replacement.getPosition())) {

  • 5275
  • replacement = target;

  • 5276
  • }

  • 5277
  • }

  • 5278  
    5279
  • if (replacement != null) {

  • 5280
  • replacement._interrupt();

  • 5281
  • this._remove(replacement);

  • 5282
  • return true;

  • 5283
  • }

  • 5284
  • return false;

  • 5285
  • };

  • 5286  
    5287
  • p.toString = function () {

  • 5288
  • return "[Sound SoundChannel]";

  • 5289
  • };

  • 5290
  • // do not add SoundChannel to namespace

  • 5291  
    5292
  • }());

  • 5293  
    5294
  • //##############################################################################

  • 5295
  • // AbstractSoundInstance.js

  • 5296
  • //##############################################################################

  • 5297  
    5298
  • this.createjs = this.createjs || {};

  • 5299  
    5300
  • /**

  • 5301
  • * A AbstractSoundInstance is created when any calls to the Sound API method {{#crossLink "Sound/play"}}{{/crossLink}} or

  • 5302
  • * {{#crossLink "Sound/createInstance"}}{{/crossLink}} are made. The AbstractSoundInstance is returned by the active plugin

  • 5303
  • * for control by the user.

  • 5304
  • *

  • 5305
  • * <h4>Example</h4>

  • 5306
  • *

  • 5307
  • * var myInstance = createjs.Sound.play("myAssetPath/mySrcFile.mp3");

  • 5308
  • *

  • 5309
  • * A number of additional parameters provide a quick way to determine how a sound is played. Please see the Sound

  • 5310
  • * API method {{#crossLink "Sound/play"}}{{/crossLink}} for a list of arguments.

  • 5311
  • *

  • 5312
  • * Once a AbstractSoundInstance is created, a reference can be stored that can be used to control the audio directly through

  • 5313
  • * the AbstractSoundInstance. If the reference is not stored, the AbstractSoundInstance will play out its audio (and any loops), and

  • 5314
  • * is then de-referenced from the {{#crossLink "Sound"}}{{/crossLink}} class so that it can be cleaned up. If audio

  • 5315
  • * playback has completed, a simple call to the {{#crossLink "AbstractSoundInstance/play"}}{{/crossLink}} instance method

  • 5316
  • * will rebuild the references the Sound class need to control it.

  • 5317
  • *

  • 5318
  • * var myInstance = createjs.Sound.play("myAssetPath/mySrcFile.mp3", {loop:2});

  • 5319
  • * myInstance.on("loop", handleLoop);

  • 5320
  • * function handleLoop(event) {

  • 5321
  • * myInstance.volume = myInstance.volume * 0.5;

  • 5322
  • * }

  • 5323
  • *

  • 5324
  • * Events are dispatched from the instance to notify when the sound has completed, looped, or when playback fails

  • 5325
  • *

  • 5326
  • * var myInstance = createjs.Sound.play("myAssetPath/mySrcFile.mp3");

  • 5327
  • * myInstance.on("complete", handleComplete);

  • 5328
  • * myInstance.on("loop", handleLoop);

  • 5329
  • * myInstance.on("failed", handleFailed);

  • 5330
  • *

  • 5331
  • *

  • 5332
  • * @class AbstractSoundInstance

  • 5333
  • * @param {String} src The path to and file name of the sound.

  • 5334
  • * @param {Number} startTime Audio sprite property used to apply an offset, in milliseconds.

  • 5335
  • * @param {Number} duration Audio sprite property used to set the time the clip plays for, in milliseconds.

  • 5336
  • * @param {Object} playbackResource Any resource needed by plugin to support audio playback.

  • 5337
  • * @extends EventDispatcher

  • 5338
  • * @constructor

  • 5339
  • */

  • 5340  
    5341
  • (function () {

  • 5342
  • "use strict";

  • 5343  
    5344  
    5345
  • // Constructor:

  • 5346
  • var AbstractSoundInstance = function (src, startTime, duration, playbackResource) {

  • 5347
  • this.EventDispatcher_constructor();

  • 5348  
    5349  
    5350
  • // public properties:

  • 5351
  • /**

  • 5352
  • * The source of the sound.

  • 5353
  • * @property src

  • 5354
  • * @type {String}

  • 5355
  • * @default null

  • 5356
  • */

  • 5357
  • this.src = src;

  • 5358  
    5359
  • /**

  • 5360
  • * The unique ID of the instance. This is set by {{#crossLink "Sound"}}{{/crossLink}}.

  • 5361
  • * @property uniqueId

  • 5362
  • * @type {String} | Number

  • 5363
  • * @default -1

  • 5364
  • */

  • 5365
  • this.uniqueId = -1;

  • 5366  
    5367
  • /**

  • 5368
  • * The play state of the sound. Play states are defined as constants on {{#crossLink "Sound"}}{{/crossLink}}.

  • 5369
  • * @property playState

  • 5370
  • * @type {String}

  • 5371
  • * @default null

  • 5372
  • */

  • 5373
  • this.playState = null;

  • 5374  
    5375
  • /**

  • 5376
  • * A Timeout created by {{#crossLink "Sound"}}{{/crossLink}} when this AbstractSoundInstance is played with a delay.

  • 5377
  • * This allows AbstractSoundInstance to remove the delay if stop, pause, or cleanup are called before playback begins.

  • 5378
  • * @property delayTimeoutId

  • 5379
  • * @type {timeoutVariable}

  • 5380
  • * @default null

  • 5381
  • * @protected

  • 5382
  • * @since 0.4.0

  • 5383
  • */

  • 5384
  • this.delayTimeoutId = null;

  • 5385
  • // TODO consider moving delay into AbstractSoundInstance so it can be handled by plugins

  • 5386  
    5387  
    5388
  • // private properties

  • 5389
  • // Getter / Setter Properties

  • 5390
  • // OJR TODO find original reason that we didn't use defined functions. I think it was performance related

  • 5391
  • /**

  • 5392
  • * The volume of the sound, between 0 and 1.

  • 5393
  • *

  • 5394
  • * The actual output volume of a sound can be calculated using:

  • 5395
  • * <code>myInstance.volume * createjs.Sound.getVolume();</code>

  • 5396
  • *

  • 5397
  • * @property volume

  • 5398
  • * @type {Number}

  • 5399
  • * @default 1

  • 5400
  • */

  • 5401
  • this._volume = 1;

  • 5402
  • Object.defineProperty(this, "volume", {

  • 5403
  • get: this.getVolume,

  • 5404
  • set: this.setVolume

  • 5405
  • });

  • 5406  
    5407
  • /**

  • 5408
  • * The pan of the sound, between -1 (left) and 1 (right). Note that pan is not supported by HTML Audio.

  • 5409
  • *

  • 5410
  • * <br />Note in WebAudioPlugin this only gives us the "x" value of what is actually 3D audio.

  • 5411
  • *

  • 5412
  • * @property pan

  • 5413
  • * @type {Number}

  • 5414
  • * @default 0

  • 5415
  • */

  • 5416
  • this._pan = 0;

  • 5417
  • Object.defineProperty(this, "pan", {

  • 5418
  • get: this.getPan,

  • 5419
  • set: this.setPan

  • 5420
  • });

  • 5421  
    5422
  • /**

  • 5423
  • * Audio sprite property used to determine the starting offset.

  • 5424
  • * @property startTime

  • 5425
  • * @type {Number}

  • 5426
  • * @default 0

  • 5427
  • * @since 0.6.1

  • 5428
  • */

  • 5429
  • this._startTime = Math.max(0, startTime || 0);

  • 5430
  • Object.defineProperty(this, "startTime", {

  • 5431
  • get: this.getStartTime,

  • 5432
  • set: this.setStartTime

  • 5433
  • });

  • 5434  
    5435
  • /**

  • 5436
  • * Sets or gets the length of the audio clip, value is in milliseconds.

  • 5437
  • *

  • 5438
  • * @property duration

  • 5439
  • * @type {Number}

  • 5440
  • * @default 0

  • 5441
  • * @since 0.6.0

  • 5442
  • */

  • 5443
  • this._duration = Math.max(0, duration || 0);

  • 5444
  • Object.defineProperty(this, "duration", {

  • 5445
  • get: this.getDuration,

  • 5446
  • set: this.setDuration

  • 5447
  • });

  • 5448  
    5449
  • /**

  • 5450
  • * Object that holds plugin specific resource need for audio playback.

  • 5451
  • * This is set internally by the plugin. For example, WebAudioPlugin will set an array buffer,

  • 5452
  • * HTMLAudioPlugin will set a tag, FlashAudioPlugin will set a flash reference.

  • 5453
  • *

  • 5454
  • * @property playbackResource

  • 5455
  • * @type {Object}

  • 5456
  • * @default null

  • 5457
  • */

  • 5458
  • this._playbackResource = null;

  • 5459
  • Object.defineProperty(this, "playbackResource", {

  • 5460
  • get: this.getPlaybackResource,

  • 5461
  • set: this.setPlaybackResource

  • 5462
  • });

  • 5463
  • if(playbackResource !== false && playbackResource !== true) { this.setPlaybackResource(playbackResource); }

  • 5464  
    5465
  • /**

  • 5466
  • * The position of the playhead in milliseconds. This can be set while a sound is playing, paused, or stopped.

  • 5467
  • *

  • 5468
  • * @property position

  • 5469
  • * @type {Number}

  • 5470
  • * @default 0

  • 5471
  • * @since 0.6.0

  • 5472
  • */

  • 5473
  • this._position = 0;

  • 5474
  • Object.defineProperty(this, "position", {

  • 5475
  • get: this.getPosition,

  • 5476
  • set: this.setPosition

  • 5477
  • });

  • 5478  
    5479
  • /**

  • 5480
  • * The number of play loops remaining. Negative values will loop infinitely.

  • 5481
  • *

  • 5482
  • * @property loop

  • 5483
  • * @type {Number}

  • 5484
  • * @default 0

  • 5485
  • * @public

  • 5486
  • * @since 0.6.0

  • 5487
  • */

  • 5488
  • this._loop = 0;

  • 5489
  • Object.defineProperty(this, "loop", {

  • 5490
  • get: this.getLoop,

  • 5491
  • set: this.setLoop

  • 5492
  • });

  • 5493  
    5494
  • /**

  • 5495
  • * Mutes or unmutes the current audio instance.

  • 5496
  • *

  • 5497
  • * @property muted

  • 5498
  • * @type {Boolean}

  • 5499
  • * @default false

  • 5500
  • * @since 0.6.0

  • 5501
  • */

  • 5502
  • this._muted = false;

  • 5503
  • Object.defineProperty(this, "muted", {

  • 5504
  • get: this.getMuted,

  • 5505
  • set: this.setMuted

  • 5506
  • });

  • 5507  
    5508
  • /**

  • 5509
  • * Pauses or resumes the current audio instance.

  • 5510
  • *

  • 5511
  • * @property paused

  • 5512
  • * @type {Boolean}

  • 5513
  • */

  • 5514
  • this._paused = false;

  • 5515
  • Object.defineProperty(this, "paused", {

  • 5516
  • get: this.getPaused,

  • 5517
  • set: this.setPaused

  • 5518
  • });

  • 5519  
    5520  
    5521
  • // Events

  • 5522
  • /**

  • 5523
  • * The event that is fired when playback has started successfully.

  • 5524
  • * @event succeeded

  • 5525
  • * @param {Object} target The object that dispatched the event.

  • 5526
  • * @param {String} type The event type.

  • 5527
  • * @since 0.4.0

  • 5528
  • */

  • 5529  
    5530
  • /**

  • 5531
  • * The event that is fired when playback is interrupted. This happens when another sound with the same

  • 5532
  • * src property is played using an interrupt value that causes this instance to stop playing.

  • 5533
  • * @event interrupted

  • 5534
  • * @param {Object} target The object that dispatched the event.

  • 5535
  • * @param {String} type The event type.

  • 5536
  • * @since 0.4.0

  • 5537
  • */

  • 5538  
    5539
  • /**

  • 5540
  • * The event that is fired when playback has failed. This happens when there are too many channels with the same

  • 5541
  • * src property already playing (and the interrupt value doesn't cause an interrupt of another instance), or

  • 5542
  • * the sound could not be played, perhaps due to a 404 error.

  • 5543
  • * @event failed

  • 5544
  • * @param {Object} target The object that dispatched the event.

  • 5545
  • * @param {String} type The event type.

  • 5546
  • * @since 0.4.0

  • 5547
  • */

  • 5548  
    5549
  • /**

  • 5550
  • * The event that is fired when a sound has completed playing but has loops remaining.

  • 5551
  • * @event loop

  • 5552
  • * @param {Object} target The object that dispatched the event.

  • 5553
  • * @param {String} type The event type.

  • 5554
  • * @since 0.4.0

  • 5555
  • */

  • 5556  
    5557
  • /**

  • 5558
  • * The event that is fired when playback completes. This means that the sound has finished playing in its

  • 5559
  • * entirety, including its loop iterations.

  • 5560
  • * @event complete

  • 5561
  • * @param {Object} target The object that dispatched the event.

  • 5562
  • * @param {String} type The event type.

  • 5563
  • * @since 0.4.0

  • 5564
  • */

  • 5565
  • };

  • 5566  
    5567
  • var p = createjs.extend(AbstractSoundInstance, createjs.EventDispatcher);

  • 5568  
    5569
  • // TODO: deprecated

  • 5570
  • // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.

  • 5571  
    5572  
    5573
  • // Public Methods:

  • 5574
  • /**

  • 5575
  • * Play an instance. This method is intended to be called on SoundInstances that already exist (created

  • 5576
  • * with the Sound API {{#crossLink "Sound/createInstance"}}{{/crossLink}} or {{#crossLink "Sound/play"}}{{/crossLink}}).

  • 5577
  • *

  • 5578
  • * <h4>Example</h4>

  • 5579
  • *

  • 5580
  • * var myInstance = createjs.Sound.createInstance(mySrc);

  • 5581
  • * myInstance.play({interrupt:createjs.Sound.INTERRUPT_ANY, loop:2, pan:0.5});

  • 5582
  • *

  • 5583
  • * Note that if this sound is already playing, this call will still set the passed in parameters.

  • 5584  
    5585
  • * <b>Parameters Deprecated</b><br />

  • 5586
  • * The parameters for this method are deprecated in favor of a single parameter that is an Object or {{#crossLink "PlayPropsConfig"}}{{/crossLink}}.

  • 5587
  • *

  • 5588
  • * @method play

  • 5589
  • * @param {String | Object} [interrupt="none"|options] <b>This parameter will be renamed playProps in the next release.</b><br />

  • 5590
  • * This parameter can be an instance of {{#crossLink "PlayPropsConfig"}}{{/crossLink}} or an Object that contains any or all optional properties by name,

  • 5591
  • * including: interrupt, delay, offset, loop, volume, pan, startTime, and duration (see the above code sample).

  • 5592
  • * <br /><strong>OR</strong><br />

  • 5593
  • * <b>Deprecated</b> How to interrupt any currently playing instances of audio with the same source,

  • 5594
  • * if the maximum number of instances of the sound are already playing. Values are defined as <code>INTERRUPT_TYPE</code>

  • 5595
  • * constants on the Sound class, with the default defined by {{#crossLink "Sound/defaultInterruptBehavior:property"}}{{/crossLink}}.

  • 5596
  • * @param {Number} [delay=0] <b>Deprecated</b> The amount of time to delay the start of audio playback, in milliseconds.

  • 5597
  • * @param {Number} [offset=0] <b>Deprecated</b> The offset from the start of the audio to begin playback, in milliseconds.

  • 5598
  • * @param {Number} [loop=0] <b>Deprecated</b> How many times the audio loops when it reaches the end of playback. The default is 0 (no

  • 5599
  • * loops), and -1 can be used for infinite playback.

  • 5600
  • * @param {Number} [volume=1] <b>Deprecated</b> The volume of the sound, between 0 and 1. Note that the master volume is applied

  • 5601
  • * against the individual volume.

  • 5602
  • * @param {Number} [pan=0] <b>Deprecated</b> The left-right pan of the sound (if supported), between -1 (left) and 1 (right).

  • 5603
  • * Note that pan is not supported for HTML Audio.

  • 5604
  • * @return {AbstractSoundInstance} A reference to itself, intended for chaining calls.

  • 5605
  • */

  • 5606
  • p.play = function (interrupt, delay, offset, loop, volume, pan) {

  • 5607
  • var playProps;

  • 5608
  • if (interrupt instanceof Object || interrupt instanceof createjs.PlayPropsConfig) {

  • 5609
  • playProps = createjs.PlayPropsConfig.create(interrupt);

  • 5610
  • } else {

  • 5611
  • playProps = createjs.PlayPropsConfig.create({interrupt:interrupt, delay:delay, offset:offset, loop:loop, volume:volume, pan:pan});

  • 5612
  • }

  • 5613  
    5614
  • if (this.playState == createjs.Sound.PLAY_SUCCEEDED) {

  • 5615
  • this.applyPlayProps(playProps);

  • 5616
  • if (this._paused) { this.setPaused(false); }

  • 5617
  • return;

  • 5618
  • }

  • 5619
  • this._cleanUp();

  • 5620
  • createjs.Sound._playInstance(this, playProps); // make this an event dispatch??

  • 5621
  • return this;

  • 5622
  • };

  • 5623  
    5624
  • /**

  • 5625
  • * Stop playback of the instance. Stopped sounds will reset their position to 0, and calls to {{#crossLink "AbstractSoundInstance/resume"}}{{/crossLink}}

  • 5626
  • * will fail. To start playback again, call {{#crossLink "AbstractSoundInstance/play"}}{{/crossLink}}.

  • 5627
  • *

  • 5628
  • * If you don't want to lose your position use yourSoundInstance.paused = true instead. {{#crossLink "AbstractSoundInstance/paused"}}{{/crossLink}}.

  • 5629
  • *

  • 5630
  • * <h4>Example</h4>

  • 5631
  • *

  • 5632
  • * myInstance.stop();

  • 5633
  • *

  • 5634
  • * @method stop

  • 5635
  • * @return {AbstractSoundInstance} A reference to itself, intended for chaining calls.

  • 5636
  • */

  • 5637
  • p.stop = function () {

  • 5638
  • this._position = 0;

  • 5639
  • this._paused = false;

  • 5640
  • this._handleStop();

  • 5641
  • this._cleanUp();

  • 5642
  • this.playState = createjs.Sound.PLAY_FINISHED;

  • 5643
  • return this;

  • 5644
  • };

  • 5645  
    5646
  • /**

  • 5647
  • * Remove all external references and resources from AbstractSoundInstance. Note this is irreversible and AbstractSoundInstance will no longer work

  • 5648
  • * @method destroy

  • 5649
  • * @since 0.6.0

  • 5650
  • */

  • 5651
  • p.destroy = function() {

  • 5652
  • this._cleanUp();

  • 5653
  • this.src = null;

  • 5654
  • this.playbackResource = null;

  • 5655  
    5656
  • this.removeAllEventListeners();

  • 5657
  • };

  • 5658  
    5659
  • /**

  • 5660
  • * Takes an PlayPropsConfig or Object with the same properties and sets them on this instance.

  • 5661
  • * @method applyPlayProps

  • 5662
  • * @param {PlayPropsConfig | Object} playProps A PlayPropsConfig or object containing the same properties.

  • 5663
  • * @since 0.6.1

  • 5664
  • * @return {AbstractSoundInstance} A reference to itself, intended for chaining calls.

  • 5665
  • */

  • 5666
  • p.applyPlayProps = function(playProps) {

  • 5667
  • if (playProps.offset != null) { this.setPosition(playProps.offset) }

  • 5668
  • if (playProps.loop != null) { this.setLoop(playProps.loop); }

  • 5669
  • if (playProps.volume != null) { this.setVolume(playProps.volume); }

  • 5670
  • if (playProps.pan != null) { this.setPan(playProps.pan); }

  • 5671
  • if (playProps.startTime != null) {

  • 5672
  • this.setStartTime(playProps.startTime);

  • 5673
  • this.setDuration(playProps.duration);

  • 5674
  • }

  • 5675
  • return this;

  • 5676
  • };

  • 5677  
    5678
  • p.toString = function () {

  • 5679
  • return "[AbstractSoundInstance]";

  • 5680
  • };

  • 5681  
    5682
  • // get/set methods that allow support for IE8

  • 5683
  • /**

  • 5684
  • * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/paused:property"}}{{/crossLink}} directly as a property,

  • 5685
  • *

  • 5686
  • * @deprecated

  • 5687
  • * @method getPaused

  • 5688
  • * @returns {boolean} If the instance is currently paused

  • 5689
  • * @since 0.6.0

  • 5690
  • */

  • 5691
  • p.getPaused = function() {

  • 5692
  • return this._paused;

  • 5693
  • };

  • 5694  
    5695
  • /**

  • 5696
  • * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/paused:property"}}{{/crossLink}} directly as a property

  • 5697
  • *

  • 5698
  • * @deprecated

  • 5699
  • * @method setPaused

  • 5700
  • * @param {boolean} value

  • 5701
  • * @since 0.6.0

  • 5702
  • * @return {AbstractSoundInstance} A reference to itself, intended for chaining calls.

  • 5703
  • */

  • 5704
  • p.setPaused = function (value) {

  • 5705
  • if ((value !== true && value !== false) || this._paused == value) {return;}

  • 5706
  • if (value == true && this.playState != createjs.Sound.PLAY_SUCCEEDED) {return;}

  • 5707
  • this._paused = value;

  • 5708
  • if(value) {

  • 5709
  • this._pause();

  • 5710
  • } else {

  • 5711
  • this._resume();

  • 5712
  • }

  • 5713
  • clearTimeout(this.delayTimeoutId);

  • 5714
  • return this;

  • 5715
  • };

  • 5716  
    5717
  • /**

  • 5718
  • * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/volume:property"}}{{/crossLink}} directly as a property

  • 5719
  • *

  • 5720
  • * @deprecated

  • 5721
  • * @method setVolume

  • 5722
  • * @param {Number} value The volume to set, between 0 and 1.

  • 5723
  • * @return {AbstractSoundInstance} A reference to itself, intended for chaining calls.

  • 5724
  • */

  • 5725
  • p.setVolume = function (value) {

  • 5726
  • if (value == this._volume) { return this; }

  • 5727
  • this._volume = Math.max(0, Math.min(1, value));

  • 5728
  • if (!this._muted) {

  • 5729
  • this._updateVolume();

  • 5730
  • }

  • 5731
  • return this;

  • 5732
  • };

  • 5733  
    5734
  • /**

  • 5735
  • * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/volume:property"}}{{/crossLink}} directly as a property

  • 5736
  • *

  • 5737
  • * @deprecated

  • 5738
  • * @method getVolume

  • 5739
  • * @return {Number} The current volume of the sound instance.

  • 5740
  • */

  • 5741
  • p.getVolume = function () {

  • 5742
  • return this._volume;

  • 5743
  • };

  • 5744  
    5745
  • /**

  • 5746
  • * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/muted:property"}}{{/crossLink}} directly as a property

  • 5747
  • *

  • 5748
  • * @deprecated

  • 5749
  • * @method setMuted

  • 5750
  • * @param {Boolean} value If the sound should be muted.

  • 5751
  • * @return {AbstractSoundInstance} A reference to itself, intended for chaining calls.

  • 5752
  • * @since 0.6.0

  • 5753
  • */

  • 5754
  • p.setMuted = function (value) {

  • 5755
  • if (value !== true && value !== false) {return;}

  • 5756
  • this._muted = value;

  • 5757
  • this._updateVolume();

  • 5758
  • return this;

  • 5759
  • };

  • 5760  
    5761
  • /**

  • 5762
  • * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/muted:property"}}{{/crossLink}} directly as a property

  • 5763
  • *

  • 5764
  • * @deprecated

  • 5765
  • * @method getMuted

  • 5766
  • * @return {Boolean} If the sound is muted.

  • 5767
  • * @since 0.6.0

  • 5768
  • */

  • 5769
  • p.getMuted = function () {

  • 5770
  • return this._muted;

  • 5771
  • };

  • 5772  
    5773
  • /**

  • 5774
  • * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/pan:property"}}{{/crossLink}} directly as a property

  • 5775
  • *

  • 5776
  • * @deprecated

  • 5777
  • * @method setPan

  • 5778
  • * @param {Number} value The pan value, between -1 (left) and 1 (right).

  • 5779
  • * @return {AbstractSoundInstance} Returns reference to itself for chaining calls

  • 5780
  • */

  • 5781
  • p.setPan = function (value) {

  • 5782
  • if(value == this._pan) { return this; }

  • 5783
  • this._pan = Math.max(-1, Math.min(1, value));

  • 5784
  • this._updatePan();

  • 5785
  • return this;

  • 5786
  • };

  • 5787  
    5788
  • /**

  • 5789
  • * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/pan:property"}}{{/crossLink}} directly as a property

  • 5790
  • *

  • 5791
  • * @deprecated

  • 5792
  • * @method getPan

  • 5793
  • * @return {Number} The value of the pan, between -1 (left) and 1 (right).

  • 5794
  • */

  • 5795
  • p.getPan = function () {

  • 5796
  • return this._pan;

  • 5797
  • };

  • 5798  
    5799
  • /**

  • 5800
  • * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/position:property"}}{{/crossLink}} directly as a property

  • 5801
  • *

  • 5802
  • * @deprecated

  • 5803
  • * @method getPosition

  • 5804
  • * @return {Number} The position of the playhead in the sound, in milliseconds.

  • 5805
  • */

  • 5806
  • p.getPosition = function () {

  • 5807
  • if (!this._paused && this.playState == createjs.Sound.PLAY_SUCCEEDED) {

  • 5808
  • this._position = this._calculateCurrentPosition();

  • 5809
  • }

  • 5810
  • return this._position;

  • 5811
  • };

  • 5812  
    5813
  • /**

  • 5814
  • * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/position:property"}}{{/crossLink}} directly as a property

  • 5815
  • *

  • 5816
  • * @deprecated

  • 5817
  • * @method setPosition

  • 5818
  • * @param {Number} value The position to place the playhead, in milliseconds.

  • 5819
  • * @return {AbstractSoundInstance} Returns reference to itself for chaining calls

  • 5820
  • */

  • 5821
  • p.setPosition = function (value) {

  • 5822
  • this._position = Math.max(0, value);

  • 5823
  • if (this.playState == createjs.Sound.PLAY_SUCCEEDED) {

  • 5824
  • this._updatePosition();

  • 5825
  • }

  • 5826
  • return this;

  • 5827
  • };

  • 5828  
    5829
  • /**

  • 5830
  • * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/startTime:property"}}{{/crossLink}} directly as a property

  • 5831
  • *

  • 5832
  • * @deprecated

  • 5833
  • * @method getStartTime

  • 5834
  • * @return {Number} The startTime of the sound instance in milliseconds.

  • 5835
  • */

  • 5836
  • p.getStartTime = function () {

  • 5837
  • return this._startTime;

  • 5838
  • };

  • 5839  
    5840
  • /**

  • 5841
  • * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/startTime:property"}}{{/crossLink}} directly as a property

  • 5842
  • *

  • 5843
  • * @deprecated

  • 5844
  • * @method setStartTime

  • 5845
  • * @param {number} value The new startTime time in milli seconds.

  • 5846
  • * @return {AbstractSoundInstance} Returns reference to itself for chaining calls

  • 5847
  • */

  • 5848
  • p.setStartTime = function (value) {

  • 5849
  • if (value == this._startTime) { return this; }

  • 5850
  • this._startTime = Math.max(0, value || 0);

  • 5851
  • this._updateStartTime();

  • 5852
  • return this;

  • 5853
  • };

  • 5854  
    5855
  • /**

  • 5856
  • * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/duration:property"}}{{/crossLink}} directly as a property

  • 5857
  • *

  • 5858
  • * @deprecated

  • 5859
  • * @method getDuration

  • 5860
  • * @return {Number} The duration of the sound instance in milliseconds.

  • 5861
  • */

  • 5862
  • p.getDuration = function () {

  • 5863
  • return this._duration;

  • 5864
  • };

  • 5865  
    5866
  • /**

  • 5867
  • * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/duration:property"}}{{/crossLink}} directly as a property

  • 5868
  • *

  • 5869
  • * @deprecated

  • 5870
  • * @method setDuration

  • 5871
  • * @param {number} value The new duration time in milli seconds.

  • 5872
  • * @return {AbstractSoundInstance} Returns reference to itself for chaining calls

  • 5873
  • * @since 0.6.0

  • 5874
  • */

  • 5875
  • p.setDuration = function (value) {

  • 5876
  • if (value == this._duration) { return this; }

  • 5877
  • this._duration = Math.max(0, value || 0);

  • 5878
  • this._updateDuration();

  • 5879
  • return this;

  • 5880
  • };

  • 5881  
    5882
  • /**

  • 5883
  • * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/playbackResource:property"}}{{/crossLink}} directly as a property

  • 5884
  • *

  • 5885
  • * @deprecated

  • 5886
  • * @method setPlayback

  • 5887
  • * @param {Object} value The new playback resource.

  • 5888
  • * @return {AbstractSoundInstance} Returns reference to itself for chaining calls

  • 5889
  • * @since 0.6.0

  • 5890
  • **/

  • 5891
  • p.setPlaybackResource = function (value) {

  • 5892
  • this._playbackResource = value;

  • 5893
  • if (this._duration == 0) { this._setDurationFromSource(); }

  • 5894
  • return this;

  • 5895
  • };

  • 5896  
    5897
  • /**

  • 5898
  • * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/playbackResource:property"}}{{/crossLink}} directly as a property

  • 5899
  • *

  • 5900
  • * @deprecated

  • 5901
  • * @method setPlayback

  • 5902
  • * @param {Object} value The new playback resource.

  • 5903
  • * @return {Object} playback resource used for playing audio

  • 5904
  • * @since 0.6.0

  • 5905
  • **/

  • 5906
  • p.getPlaybackResource = function () {

  • 5907
  • return this._playbackResource;

  • 5908
  • };

  • 5909  
    5910
  • /**

  • 5911
  • * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/loop:property"}}{{/crossLink}} directly as a property

  • 5912
  • *

  • 5913
  • * @deprecated

  • 5914
  • * @method getLoop

  • 5915
  • * @return {number}

  • 5916
  • * @since 0.6.0

  • 5917
  • **/

  • 5918
  • p.getLoop = function () {

  • 5919
  • return this._loop;

  • 5920
  • };

  • 5921  
    5922
  • /**

  • 5923
  • * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/loop:property"}}{{/crossLink}} directly as a property,

  • 5924
  • *

  • 5925
  • * @deprecated

  • 5926
  • * @method setLoop

  • 5927
  • * @param {number} value The number of times to loop after play.

  • 5928
  • * @since 0.6.0

  • 5929
  • */

  • 5930
  • p.setLoop = function (value) {

  • 5931
  • if(this._playbackResource != null) {

  • 5932
  • // remove looping

  • 5933
  • if (this._loop != 0 && value == 0) {

  • 5934
  • this._removeLooping(value);

  • 5935
  • }

  • 5936
  • // add looping

  • 5937
  • else if (this._loop == 0 && value != 0) {

  • 5938
  • this._addLooping(value);

  • 5939
  • }

  • 5940
  • }

  • 5941
  • this._loop = value;

  • 5942
  • };

  • 5943  
    5944  
    5945
  • // Private Methods:

  • 5946
  • /**

  • 5947
  • * A helper method that dispatches all events for AbstractSoundInstance.

  • 5948
  • * @method _sendEvent

  • 5949
  • * @param {String} type The event type

  • 5950
  • * @protected

  • 5951
  • */

  • 5952
  • p._sendEvent = function (type) {

  • 5953
  • var event = new createjs.Event(type);

  • 5954
  • this.dispatchEvent(event);

  • 5955
  • };

  • 5956  
    5957
  • /**

  • 5958
  • * Clean up the instance. Remove references and clean up any additional properties such as timers.

  • 5959
  • * @method _cleanUp

  • 5960
  • * @protected

  • 5961
  • */

  • 5962
  • p._cleanUp = function () {

  • 5963
  • clearTimeout(this.delayTimeoutId); // clear timeout that plays delayed sound

  • 5964
  • this._handleCleanUp();

  • 5965
  • this._paused = false;

  • 5966  
    5967
  • createjs.Sound._playFinished(this); // TODO change to an event

  • 5968
  • };

  • 5969  
    5970
  • /**

  • 5971
  • * The sound has been interrupted.

  • 5972
  • * @method _interrupt

  • 5973
  • * @protected

  • 5974
  • */

  • 5975
  • p._interrupt = function () {

  • 5976
  • this._cleanUp();

  • 5977
  • this.playState = createjs.Sound.PLAY_INTERRUPTED;

  • 5978
  • this._sendEvent("interrupted");

  • 5979
  • };

  • 5980  
    5981
  • /**

  • 5982
  • * Called by the Sound class when the audio is ready to play (delay has completed). Starts sound playing if the

  • 5983
  • * src is loaded, otherwise playback will fail.

  • 5984
  • * @method _beginPlaying

  • 5985
  • * @param {PlayPropsConfig} playProps A PlayPropsConfig object.

  • 5986
  • * @return {Boolean} If playback succeeded.

  • 5987
  • * @protected

  • 5988
  • */

  • 5989
  • // OJR FlashAudioSoundInstance overwrites

  • 5990
  • p._beginPlaying = function (playProps) {

  • 5991
  • this.setPosition(playProps.offset);

  • 5992
  • this.setLoop(playProps.loop);

  • 5993
  • this.setVolume(playProps.volume);

  • 5994
  • this.setPan(playProps.pan);

  • 5995
  • if (playProps.startTime != null) {

  • 5996
  • this.setStartTime(playProps.startTime);

  • 5997
  • this.setDuration(playProps.duration);

  • 5998
  • }

  • 5999  
    6000
  • if (this._playbackResource != null && this._position < this._duration) {

  • 6001
  • this._paused = false;

  • 6002
  • this._handleSoundReady();

  • 6003
  • this.playState = createjs.Sound.PLAY_SUCCEEDED;

  • 6004
  • this._sendEvent("succeeded");

  • 6005
  • return true;

  • 6006
  • } else {

  • 6007
  • this._playFailed();

  • 6008
  • return false;

  • 6009
  • }

  • 6010
  • };

  • 6011  
    6012
  • /**

  • 6013
  • * Play has failed, which can happen for a variety of reasons.

  • 6014
  • * Cleans up instance and dispatches failed event

  • 6015
  • * @method _playFailed

  • 6016
  • * @private

  • 6017
  • */

  • 6018
  • p._playFailed = function () {

  • 6019
  • this._cleanUp();

  • 6020
  • this.playState = createjs.Sound.PLAY_FAILED;

  • 6021
  • this._sendEvent("failed");

  • 6022
  • };

  • 6023  
    6024
  • /**

  • 6025
  • * Audio has finished playing. Manually loop it if required.

  • 6026
  • * @method _handleSoundComplete

  • 6027
  • * @param event

  • 6028
  • * @protected

  • 6029
  • */

  • 6030
  • p._handleSoundComplete = function (event) {

  • 6031
  • this._position = 0; // have to set this as it can be set by pause during playback

  • 6032  
    6033
  • if (this._loop != 0) {

  • 6034
  • this._loop--; // NOTE this introduces a theoretical limit on loops = float max size x 2 - 1

  • 6035
  • this._handleLoop();

  • 6036
  • this._sendEvent("loop");

  • 6037
  • return;

  • 6038
  • }

  • 6039  
    6040
  • this._cleanUp();

  • 6041
  • this.playState = createjs.Sound.PLAY_FINISHED;

  • 6042
  • this._sendEvent("complete");

  • 6043
  • };

  • 6044  
    6045
  • // Plugin specific code

  • 6046
  • /**

  • 6047
  • * Handles starting playback when the sound is ready for playing.

  • 6048
  • * @method _handleSoundReady

  • 6049
  • * @protected

  • 6050
  • */

  • 6051
  • p._handleSoundReady = function () {

  • 6052
  • // plugin specific code

  • 6053
  • };

  • 6054  
    6055
  • /**

  • 6056
  • * Internal function used to update the volume based on the instance volume, master volume, instance mute value,

  • 6057
  • * and master mute value.

  • 6058
  • * @method _updateVolume

  • 6059
  • * @protected

  • 6060
  • */

  • 6061
  • p._updateVolume = function () {

  • 6062
  • // plugin specific code

  • 6063
  • };

  • 6064  
    6065
  • /**

  • 6066
  • * Internal function used to update the pan

  • 6067
  • * @method _updatePan

  • 6068
  • * @protected

  • 6069
  • * @since 0.6.0

  • 6070
  • */

  • 6071
  • p._updatePan = function () {

  • 6072
  • // plugin specific code

  • 6073
  • };

  • 6074  
    6075
  • /**

  • 6076
  • * Internal function used to update the startTime of the audio.

  • 6077
  • * @method _updateStartTime

  • 6078
  • * @protected

  • 6079
  • * @since 0.6.1

  • 6080
  • */

  • 6081
  • p._updateStartTime = function () {

  • 6082
  • // plugin specific code

  • 6083
  • };

  • 6084  
    6085
  • /**

  • 6086
  • * Internal function used to update the duration of the audio.

  • 6087
  • * @method _updateDuration

  • 6088
  • * @protected

  • 6089
  • * @since 0.6.0

  • 6090
  • */

  • 6091
  • p._updateDuration = function () {

  • 6092
  • // plugin specific code

  • 6093
  • };

  • 6094  
    6095
  • /**

  • 6096
  • * Internal function used to get the duration of the audio from the source we'll be playing.

  • 6097
  • * @method _updateDuration

  • 6098
  • * @protected

  • 6099
  • * @since 0.6.0

  • 6100
  • */

  • 6101
  • p._setDurationFromSource = function () {

  • 6102
  • // plugin specific code

  • 6103
  • };

  • 6104  
    6105
  • /**

  • 6106
  • * Internal function that calculates the current position of the playhead and sets this._position to that value

  • 6107
  • * @method _calculateCurrentPosition

  • 6108
  • * @protected

  • 6109
  • * @since 0.6.0

  • 6110
  • */

  • 6111
  • p._calculateCurrentPosition = function () {

  • 6112
  • // plugin specific code that sets this.position

  • 6113
  • };

  • 6114  
    6115
  • /**

  • 6116
  • * Internal function used to update the position of the playhead.

  • 6117
  • * @method _updatePosition

  • 6118
  • * @protected

  • 6119
  • * @since 0.6.0

  • 6120
  • */

  • 6121
  • p._updatePosition = function () {

  • 6122
  • // plugin specific code

  • 6123
  • };

  • 6124  
    6125
  • /**

  • 6126
  • * Internal function called when looping is removed during playback.

  • 6127
  • * @method _removeLooping

  • 6128
  • * @param {number} value The number of times to loop after play.

  • 6129
  • * @protected

  • 6130
  • * @since 0.6.0

  • 6131
  • */

  • 6132
  • p._removeLooping = function (value) {

  • 6133
  • // plugin specific code

  • 6134
  • };

  • 6135  
    6136
  • /**

  • 6137
  • * Internal function called when looping is added during playback.

  • 6138
  • * @method _addLooping

  • 6139
  • * @param {number} value The number of times to loop after play.

  • 6140
  • * @protected

  • 6141
  • * @since 0.6.0

  • 6142
  • */

  • 6143
  • p._addLooping = function (value) {

  • 6144
  • // plugin specific code

  • 6145
  • };

  • 6146  
    6147
  • /**

  • 6148
  • * Internal function called when pausing playback

  • 6149
  • * @method _pause

  • 6150
  • * @protected

  • 6151
  • * @since 0.6.0

  • 6152
  • */

  • 6153
  • p._pause = function () {

  • 6154
  • // plugin specific code

  • 6155
  • };

  • 6156  
    6157
  • /**

  • 6158
  • * Internal function called when resuming playback

  • 6159
  • * @method _resume

  • 6160
  • * @protected

  • 6161
  • * @since 0.6.0

  • 6162
  • */

  • 6163
  • p._resume = function () {

  • 6164
  • // plugin specific code

  • 6165
  • };

  • 6166  
    6167
  • /**

  • 6168
  • * Internal function called when stopping playback

  • 6169
  • * @method _handleStop

  • 6170
  • * @protected

  • 6171
  • * @since 0.6.0

  • 6172
  • */

  • 6173
  • p._handleStop = function() {

  • 6174
  • // plugin specific code

  • 6175
  • };

  • 6176  
    6177
  • /**

  • 6178
  • * Internal function called when AbstractSoundInstance is being cleaned up

  • 6179
  • * @method _handleCleanUp

  • 6180
  • * @protected

  • 6181
  • * @since 0.6.0

  • 6182
  • */

  • 6183
  • p._handleCleanUp = function() {

  • 6184
  • // plugin specific code

  • 6185
  • };

  • 6186  
    6187
  • /**

  • 6188
  • * Internal function called when AbstractSoundInstance has played to end and is looping

  • 6189
  • * @method _handleLoop

  • 6190
  • * @protected

  • 6191
  • * @since 0.6.0

  • 6192
  • */

  • 6193
  • p._handleLoop = function () {

  • 6194
  • // plugin specific code

  • 6195
  • };

  • 6196  
    6197
  • createjs.AbstractSoundInstance = createjs.promote(AbstractSoundInstance, "EventDispatcher");

  • 6198
  • createjs.DefaultSoundInstance = createjs.AbstractSoundInstance; // used when no plugin is supported

  • 6199
  • }());

  • 6200  
    6201
  • //##############################################################################

  • 6202
  • // AbstractPlugin.js

  • 6203
  • //##############################################################################

  • 6204  
    6205
  • this.createjs = this.createjs || {};

  • 6206  
    6207
  • (function () {

  • 6208
  • "use strict";

  • 6209  
    6210  
    6211
  • // constructor:

  • 6212
  • /**

  • 6213
  • * A default plugin class used as a base for all other plugins.

  • 6214
  • * @class AbstractPlugin

  • 6215
  • * @constructor

  • 6216
  • * @since 0.6.0

  • 6217
  • */

  • 6218  
    6219
  • var AbstractPlugin = function () {

  • 6220
  • // private properties:

  • 6221
  • /**

  • 6222
  • * The capabilities of the plugin.

  • 6223
  • * method and is used internally.

  • 6224
  • * @property _capabilities

  • 6225
  • * @type {Object}

  • 6226
  • * @default null

  • 6227
  • * @protected

  • 6228
  • * @static

  • 6229
  • */

  • 6230
  • this._capabilities = null;

  • 6231  
    6232
  • /**

  • 6233
  • * Object hash indexed by the source URI of all created loaders, used to properly destroy them if sources are removed.

  • 6234
  • * @type {Object}

  • 6235
  • * @protected

  • 6236
  • */

  • 6237
  • this._loaders = {};

  • 6238  
    6239
  • /**

  • 6240
  • * Object hash indexed by the source URI of each file to indicate if an audio source has begun loading,

  • 6241
  • * is currently loading, or has completed loading. Can be used to store non boolean data after loading

  • 6242
  • * is complete (for example arrayBuffers for web audio).

  • 6243
  • * @property _audioSources

  • 6244
  • * @type {Object}

  • 6245
  • * @protected

  • 6246
  • */

  • 6247
  • this._audioSources = {};

  • 6248  
    6249
  • /**

  • 6250
  • * Object hash indexed by the source URI of all created SoundInstances, updates the playbackResource if it loads after they are created,

  • 6251
  • * and properly destroy them if sources are removed

  • 6252
  • * @type {Object}

  • 6253
  • * @protected

  • 6254
  • */

  • 6255
  • this._soundInstances = {};

  • 6256  
    6257
  • /**

  • 6258
  • * The internal master volume value of the plugin.

  • 6259
  • * @property _volume

  • 6260
  • * @type {Number}

  • 6261
  • * @default 1

  • 6262
  • * @protected

  • 6263
  • */

  • 6264
  • this._volume = 1;

  • 6265  
    6266
  • /**

  • 6267
  • * A reference to a loader class used by a plugin that must be set.

  • 6268
  • * @type {Object}

  • 6269
  • * @protected

  • 6270
  • */

  • 6271
  • this._loaderClass;

  • 6272  
    6273
  • /**

  • 6274
  • * A reference to an AbstractSoundInstance class used by a plugin that must be set.

  • 6275
  • * @type {Object}

  • 6276
  • * @protected;

  • 6277
  • */

  • 6278
  • this._soundInstanceClass;

  • 6279
  • };

  • 6280
  • var p = AbstractPlugin.prototype;

  • 6281  
    6282
  • /**

  • 6283
  • * <strong>REMOVED</strong>. Removed in favor of using `MySuperClass_constructor`.

  • 6284
  • * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}}

  • 6285
  • * for details.

  • 6286
  • *

  • 6287
  • * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance.

  • 6288
  • *

  • 6289
  • * @method initialize

  • 6290
  • * @protected

  • 6291
  • * @deprecated

  • 6292
  • */

  • 6293
  • // p.initialize = function() {}; // searchable for devs wondering where it is.

  • 6294  
    6295  
    6296
  • // Static Properties:

  • 6297
  • // NOTE THESE PROPERTIES NEED TO BE ADDED TO EACH PLUGIN

  • 6298
  • /**

  • 6299
  • * The capabilities of the plugin. This is generated via the _generateCapabilities method and is used internally.

  • 6300
  • * @property _capabilities

  • 6301
  • * @type {Object}

  • 6302
  • * @default null

  • 6303
  • * @protected

  • 6304
  • * @static

  • 6305
  • */

  • 6306
  • AbstractPlugin._capabilities = null;

  • 6307  
    6308
  • /**

  • 6309
  • * Determine if the plugin can be used in the current browser/OS.

  • 6310
  • * @method isSupported

  • 6311
  • * @return {Boolean} If the plugin can be initialized.

  • 6312
  • * @static

  • 6313
  • */

  • 6314
  • AbstractPlugin.isSupported = function () {

  • 6315
  • return true;

  • 6316
  • };

  • 6317  
    6318  
    6319
  • // public methods:

  • 6320
  • /**

  • 6321
  • * Pre-register a sound for preloading and setup. This is called by {{#crossLink "Sound"}}{{/crossLink}}.

  • 6322
  • * Note all plugins provide a <code>Loader</code> instance, which <a href="http://preloadjs.com" target="_blank">PreloadJS</a>

  • 6323
  • * can use to assist with preloading.

  • 6324
  • * @method register

  • 6325
  • * @param {String} loadItem An Object containing the source of the audio

  • 6326
  • * Note that not every plugin will manage this value.

  • 6327
  • * @return {Object} A result object, containing a "tag" for preloading purposes.

  • 6328
  • */

  • 6329
  • p.register = function (loadItem) {

  • 6330
  • var loader = this._loaders[loadItem.src];

  • 6331
  • if(loader && !loader.canceled) {return this._loaders[loadItem.src];} // already loading/loaded this, so don't load twice

  • 6332
  • // OJR potential issue that we won't be firing loaded event, might need to trigger if this is already loaded?

  • 6333
  • this._audioSources[loadItem.src] = true;

  • 6334
  • this._soundInstances[loadItem.src] = [];

  • 6335
  • loader = new this._loaderClass(loadItem);

  • 6336
  • loader.on("complete", this._handlePreloadComplete, this);

  • 6337
  • this._loaders[loadItem.src] = loader;

  • 6338
  • return loader;

  • 6339
  • };

  • 6340  
    6341
  • // note sound calls register before calling preload

  • 6342
  • /**

  • 6343
  • * Internally preload a sound.

  • 6344
  • * @method preload

  • 6345
  • * @param {Loader} loader The sound URI to load.

  • 6346
  • */

  • 6347
  • p.preload = function (loader) {

  • 6348
  • loader.on("error", this._handlePreloadError, this);

  • 6349
  • loader.load();

  • 6350
  • };

  • 6351  
    6352
  • /**

  • 6353
  • * Checks if preloading has started for a specific source. If the source is found, we can assume it is loading,

  • 6354
  • * or has already finished loading.

  • 6355
  • * @method isPreloadStarted

  • 6356
  • * @param {String} src The sound URI to check.

  • 6357
  • * @return {Boolean}

  • 6358
  • */

  • 6359
  • p.isPreloadStarted = function (src) {

  • 6360
  • return (this._audioSources[src] != null);

  • 6361
  • };

  • 6362  
    6363
  • /**

  • 6364
  • * Checks if preloading has finished for a specific source.

  • 6365
  • * @method isPreloadComplete

  • 6366
  • * @param {String} src The sound URI to load.

  • 6367
  • * @return {Boolean}

  • 6368
  • */

  • 6369
  • p.isPreloadComplete = function (src) {

  • 6370
  • return (!(this._audioSources[src] == null || this._audioSources[src] == true));

  • 6371
  • };

  • 6372  
    6373
  • /**

  • 6374
  • * Remove a sound added using {{#crossLink "WebAudioPlugin/register"}}{{/crossLink}}. Note this does not cancel a preload.

  • 6375
  • * @method removeSound

  • 6376
  • * @param {String} src The sound URI to unload.

  • 6377
  • */

  • 6378
  • p.removeSound = function (src) {

  • 6379
  • if (!this._soundInstances[src]) { return; }

  • 6380
  • for (var i = this._soundInstances[src].length; i--; ) {

  • 6381
  • var item = this._soundInstances[src][i];

  • 6382
  • item.destroy();

  • 6383
  • }

  • 6384
  • delete(this._soundInstances[src]);

  • 6385
  • delete(this._audioSources[src]);

  • 6386
  • if(this._loaders[src]) { this._loaders[src].destroy(); }

  • 6387
  • delete(this._loaders[src]);

  • 6388
  • };

  • 6389  
    6390
  • /**

  • 6391
  • * Remove all sounds added using {{#crossLink "WebAudioPlugin/register"}}{{/crossLink}}. Note this does not cancel a preload.

  • 6392
  • * @method removeAllSounds

  • 6393
  • * @param {String} src The sound URI to unload.

  • 6394
  • */

  • 6395
  • p.removeAllSounds = function () {

  • 6396
  • for(var key in this._audioSources) {

  • 6397
  • this.removeSound(key);

  • 6398
  • }

  • 6399
  • };

  • 6400  
    6401
  • /**

  • 6402
  • * Create a sound instance. If the sound has not been preloaded, it is internally preloaded here.

  • 6403
  • * @method create

  • 6404
  • * @param {String} src The sound source to use.

  • 6405
  • * @param {Number} startTime Audio sprite property used to apply an offset, in milliseconds.

  • 6406
  • * @param {Number} duration Audio sprite property used to set the time the clip plays for, in milliseconds.

  • 6407
  • * @return {AbstractSoundInstance} A sound instance for playback and control.

  • 6408
  • */

  • 6409
  • p.create = function (src, startTime, duration) {

  • 6410
  • if (!this.isPreloadStarted(src)) {

  • 6411
  • this.preload(this.register(src));

  • 6412
  • }

  • 6413
  • var si = new this._soundInstanceClass(src, startTime, duration, this._audioSources[src]);

  • 6414
  • this._soundInstances[src].push(si);

  • 6415
  • return si;

  • 6416
  • };

  • 6417  
    6418
  • // if a plugin does not support volume and mute, it should set these to null

  • 6419
  • /**

  • 6420
  • * Set the master volume of the plugin, which affects all SoundInstances.

  • 6421
  • * @method setVolume

  • 6422
  • * @param {Number} value The volume to set, between 0 and 1.

  • 6423
  • * @return {Boolean} If the plugin processes the setVolume call (true). The Sound class will affect all the

  • 6424
  • * instances manually otherwise.

  • 6425
  • */

  • 6426
  • p.setVolume = function (value) {

  • 6427
  • this._volume = value;

  • 6428
  • this._updateVolume();

  • 6429
  • return true;

  • 6430
  • };

  • 6431  
    6432
  • /**

  • 6433
  • * Get the master volume of the plugin, which affects all SoundInstances.

  • 6434
  • * @method getVolume

  • 6435
  • * @return {Number} The volume level, between 0 and 1.

  • 6436
  • */

  • 6437
  • p.getVolume = function () {

  • 6438
  • return this._volume;

  • 6439
  • };

  • 6440  
    6441
  • /**

  • 6442
  • * Mute all sounds via the plugin.

  • 6443
  • * @method setMute

  • 6444
  • * @param {Boolean} value If all sound should be muted or not. Note that plugin-level muting just looks up

  • 6445
  • * the mute value of Sound {{#crossLink "Sound/getMute"}}{{/crossLink}}, so this property is not used here.

  • 6446
  • * @return {Boolean} If the mute call succeeds.

  • 6447
  • */

  • 6448
  • p.setMute = function (value) {

  • 6449
  • this._updateVolume();

  • 6450
  • return true;

  • 6451
  • };

  • 6452  
    6453
  • // plugins should overwrite this method

  • 6454
  • p.toString = function () {

  • 6455
  • return "[AbstractPlugin]";

  • 6456
  • };

  • 6457  
    6458  
    6459
  • // private methods:

  • 6460
  • /**

  • 6461
  • * Handles internal preload completion.

  • 6462
  • * @method _handlePreloadComplete

  • 6463
  • * @protected

  • 6464
  • */

  • 6465
  • p._handlePreloadComplete = function (event) {

  • 6466
  • var src = event.target.getItem().src;

  • 6467
  • this._audioSources[src] = event.result;

  • 6468
  • for (var i = 0, l = this._soundInstances[src].length; i < l; i++) {

  • 6469
  • var item = this._soundInstances[src][i];

  • 6470
  • item.setPlaybackResource(this._audioSources[src]);

  • 6471
  • // ToDo consider adding play call here if playstate == playfailed

  • 6472
  • }

  • 6473
  • };

  • 6474  
    6475
  • /**

  • 6476
  • * Handles internal preload erros

  • 6477
  • * @method _handlePreloadError

  • 6478
  • * @param event

  • 6479
  • * @protected

  • 6480
  • */

  • 6481
  • p._handlePreloadError = function(event) {

  • 6482
  • //delete(this._audioSources[src]);

  • 6483
  • };

  • 6484  
    6485
  • /**

  • 6486
  • * Set the gain value for master audio. Should not be called externally.

  • 6487
  • * @method _updateVolume

  • 6488
  • * @protected

  • 6489
  • */

  • 6490
  • p._updateVolume = function () {

  • 6491
  • // Plugin Specific code

  • 6492
  • };

  • 6493  
    6494
  • createjs.AbstractPlugin = AbstractPlugin;

  • 6495
  • }());

  • 6496  
    6497
  • //##############################################################################

  • 6498
  • // WebAudioLoader.js

  • 6499
  • //##############################################################################

  • 6500  
    6501
  • this.createjs = this.createjs || {};

  • 6502  
    6503
  • (function () {

  • 6504
  • "use strict";

  • 6505  
    6506
  • /**

  • 6507
  • * Loader provides a mechanism to preload Web Audio content via PreloadJS or internally. Instances are returned to

  • 6508
  • * the preloader, and the load method is called when the asset needs to be requested.

  • 6509
  • *

  • 6510
  • * @class WebAudioLoader

  • 6511
  • * @param {String} loadItem The item to be loaded

  • 6512
  • * @extends XHRRequest

  • 6513
  • * @protected

  • 6514
  • */

  • 6515
  • function Loader(loadItem) {

  • 6516
  • this.AbstractLoader_constructor(loadItem, true, createjs.AbstractLoader.SOUND);

  • 6517  
    6518
  • };

  • 6519
  • var p = createjs.extend(Loader, createjs.AbstractLoader);

  • 6520  
    6521
  • // TODO: deprecated

  • 6522
  • // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.

  • 6523  
    6524  
    6525
  • /**

  • 6526
  • * web audio context required for decoding audio

  • 6527
  • * @property context

  • 6528
  • * @type {AudioContext}

  • 6529
  • * @static

  • 6530
  • */

  • 6531
  • Loader.context = null;

  • 6532  
    6533  
    6534
  • // public methods

  • 6535
  • p.toString = function () {

  • 6536
  • return "[WebAudioLoader]";

  • 6537
  • };

  • 6538  
    6539  
    6540
  • // private methods

  • 6541
  • p._createRequest = function() {

  • 6542
  • this._request = new createjs.XHRRequest(this._item, false);

  • 6543
  • this._request.setResponseType("arraybuffer");

  • 6544
  • };

  • 6545  
    6546
  • p._sendComplete = function (event) {

  • 6547
  • // OJR we leave this wrapped in Loader because we need to reference src and the handler only receives a single argument, the decodedAudio

  • 6548
  • Loader.context.decodeAudioData(this._rawResult,

  • 6549
  • createjs.proxy(this._handleAudioDecoded, this),

  • 6550
  • createjs.proxy(this._sendError, this));

  • 6551
  • };

  • 6552  
    6553  
    6554
  • /**

  • 6555
  • * The audio has been decoded.

  • 6556
  • * @method handleAudioDecoded

  • 6557
  • * @param decoded

  • 6558
  • * @protected

  • 6559
  • */

  • 6560
  • p._handleAudioDecoded = function (decodedAudio) {

  • 6561
  • this._result = decodedAudio;

  • 6562
  • this.AbstractLoader__sendComplete();

  • 6563
  • };

  • 6564  
    6565
  • createjs.WebAudioLoader = createjs.promote(Loader, "AbstractLoader");

  • 6566
  • }());

  • 6567  
    6568
  • //##############################################################################

  • 6569
  • // WebAudioSoundInstance.js

  • 6570
  • //##############################################################################

  • 6571  
    6572
  • this.createjs = this.createjs || {};

  • 6573  
    6574
  • /**

  • 6575
  • * WebAudioSoundInstance extends the base api of {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} and is used by

  • 6576
  • * {{#crossLink "WebAudioPlugin"}}{{/crossLink}}.

  • 6577
  • *

  • 6578
  • * WebAudioSoundInstance exposes audioNodes for advanced users.

  • 6579
  • *

  • 6580
  • * @param {String} src The path to and file name of the sound.

  • 6581
  • * @param {Number} startTime Audio sprite property used to apply an offset, in milliseconds.

  • 6582
  • * @param {Number} duration Audio sprite property used to set the time the clip plays for, in milliseconds.

  • 6583
  • * @param {Object} playbackResource Any resource needed by plugin to support audio playback.

  • 6584
  • * @class WebAudioSoundInstance

  • 6585
  • * @extends AbstractSoundInstance

  • 6586
  • * @constructor

  • 6587
  • */

  • 6588
  • (function () {

  • 6589
  • "use strict";

  • 6590  
    6591
  • function WebAudioSoundInstance(src, startTime, duration, playbackResource) {

  • 6592
  • this.AbstractSoundInstance_constructor(src, startTime, duration, playbackResource);

  • 6593  
    6594  
    6595
  • // public properties

  • 6596
  • /**

  • 6597
  • * NOTE this is only intended for use by advanced users.

  • 6598
  • * <br />GainNode for controlling <code>WebAudioSoundInstance</code> volume. Connected to the {{#crossLink "WebAudioSoundInstance/destinationNode:property"}}{{/crossLink}}.

  • 6599
  • * @property gainNode

  • 6600
  • * @type {AudioGainNode}

  • 6601
  • * @since 0.4.0

  • 6602
  • *

  • 6603
  • */

  • 6604
  • this.gainNode = s.context.createGain();

  • 6605  
    6606
  • /**

  • 6607
  • * NOTE this is only intended for use by advanced users.

  • 6608
  • * <br />A panNode allowing left and right audio channel panning only. Connected to WebAudioSoundInstance {{#crossLink "WebAudioSoundInstance/gainNode:property"}}{{/crossLink}}.

  • 6609
  • * @property panNode

  • 6610
  • * @type {AudioPannerNode}

  • 6611
  • * @since 0.4.0

  • 6612
  • */

  • 6613
  • this.panNode = s.context.createPanner();

  • 6614
  • this.panNode.panningModel = s._panningModel;

  • 6615
  • this.panNode.connect(this.gainNode);

  • 6616
  • this._updatePan();

  • 6617  
    6618
  • /**

  • 6619
  • * NOTE this is only intended for use by advanced users.

  • 6620
  • * <br />sourceNode is the audio source. Connected to WebAudioSoundInstance {{#crossLink "WebAudioSoundInstance/panNode:property"}}{{/crossLink}}.

  • 6621
  • * @property sourceNode

  • 6622
  • * @type {AudioNode}

  • 6623
  • * @since 0.4.0

  • 6624
  • *

  • 6625
  • */

  • 6626
  • this.sourceNode = null;

  • 6627  
    6628  
    6629
  • // private properties

  • 6630
  • /**

  • 6631
  • * Timeout that is created internally to handle sound playing to completion.

  • 6632
  • * Stored so we can remove it when stop, pause, or cleanup are called

  • 6633
  • * @property _soundCompleteTimeout

  • 6634
  • * @type {timeoutVariable}

  • 6635
  • * @default null

  • 6636
  • * @protected

  • 6637
  • * @since 0.4.0

  • 6638
  • */

  • 6639
  • this._soundCompleteTimeout = null;

  • 6640  
    6641
  • /**

  • 6642
  • * NOTE this is only intended for use by very advanced users.

  • 6643
  • * _sourceNodeNext is the audio source for the next loop, inserted in a look ahead approach to allow for smooth

  • 6644
  • * looping. Connected to {{#crossLink "WebAudioSoundInstance/gainNode:property"}}{{/crossLink}}.

  • 6645
  • * @property _sourceNodeNext

  • 6646
  • * @type {AudioNode}

  • 6647
  • * @default null

  • 6648
  • * @protected

  • 6649
  • * @since 0.4.1

  • 6650
  • *

  • 6651
  • */

  • 6652
  • this._sourceNodeNext = null;

  • 6653  
    6654
  • /**

  • 6655
  • * Time audio started playback, in seconds. Used to handle set position, get position, and resuming from paused.

  • 6656
  • * @property _playbackStartTime

  • 6657
  • * @type {Number}

  • 6658
  • * @default 0

  • 6659
  • * @protected

  • 6660
  • * @since 0.4.0

  • 6661
  • */

  • 6662
  • this._playbackStartTime = 0;

  • 6663  
    6664
  • // Proxies, make removing listeners easier.

  • 6665
  • this._endedHandler = createjs.proxy(this._handleSoundComplete, this);

  • 6666
  • };

  • 6667
  • var p = createjs.extend(WebAudioSoundInstance, createjs.AbstractSoundInstance);

  • 6668
  • var s = WebAudioSoundInstance;

  • 6669  
    6670
  • // TODO: deprecated

  • 6671
  • // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.

  • 6672  
    6673  
    6674
  • /**

  • 6675
  • * Note this is only intended for use by advanced users.

  • 6676
  • * <br />Audio context used to create nodes. This is and needs to be the same context used by {{#crossLink "WebAudioPlugin"}}{{/crossLink}}.

  • 6677
  • * @property context

  • 6678
  • * @type {AudioContext}

  • 6679
  • * @static

  • 6680
  • * @since 0.6.0

  • 6681
  • */

  • 6682
  • s.context = null;

  • 6683  
    6684
  • /**

  • 6685
  • * Note this is only intended for use by advanced users.

  • 6686
  • * <br />The scratch buffer that will be assigned to the buffer property of a source node on close.

  • 6687
  • * This is and should be the same scratch buffer referenced by {{#crossLink "WebAudioPlugin"}}{{/crossLink}}.

  • 6688
  • * @property _scratchBuffer

  • 6689
  • * @type {AudioBufferSourceNode}

  • 6690
  • * @static

  • 6691
  • */

  • 6692
  • s._scratchBuffer = null;

  • 6693  
    6694
  • /**

  • 6695
  • * Note this is only intended for use by advanced users.

  • 6696
  • * <br /> Audio node from WebAudioPlugin that sequences to <code>context.destination</code>

  • 6697
  • * @property destinationNode

  • 6698
  • * @type {AudioNode}

  • 6699
  • * @static

  • 6700
  • * @since 0.6.0

  • 6701
  • */

  • 6702
  • s.destinationNode = null;

  • 6703  
    6704
  • /**

  • 6705
  • * Value to set panning model to equal power for WebAudioSoundInstance. Can be "equalpower" or 0 depending on browser implementation.

  • 6706
  • * @property _panningModel

  • 6707
  • * @type {Number / String}

  • 6708
  • * @protected

  • 6709
  • * @static

  • 6710
  • * @since 0.6.0

  • 6711
  • */

  • 6712
  • s._panningModel = "equalpower";

  • 6713  
    6714  
    6715
  • // Public methods

  • 6716
  • p.destroy = function() {

  • 6717
  • this.AbstractSoundInstance_destroy();

  • 6718  
    6719
  • this.panNode.disconnect(0);

  • 6720
  • this.panNode = null;

  • 6721
  • this.gainNode.disconnect(0);

  • 6722
  • this.gainNode = null;

  • 6723
  • };

  • 6724  
    6725
  • p.toString = function () {

  • 6726
  • return "[WebAudioSoundInstance]";

  • 6727
  • };

  • 6728  
    6729  
    6730
  • // Private Methods

  • 6731
  • p._updatePan = function() {

  • 6732
  • this.panNode.setPosition(this._pan, 0, -0.5);

  • 6733
  • // z need to be -0.5 otherwise the sound only plays in left, right, or center

  • 6734
  • };

  • 6735  
    6736
  • p._removeLooping = function(value) {

  • 6737
  • this._sourceNodeNext = this._cleanUpAudioNode(this._sourceNodeNext);

  • 6738
  • };

  • 6739  
    6740
  • p._addLooping = function(value) {

  • 6741
  • if (this.playState != createjs.Sound.PLAY_SUCCEEDED) { return; }

  • 6742
  • this._sourceNodeNext = this._createAndPlayAudioNode(this._playbackStartTime, 0);

  • 6743
  • };

  • 6744  
    6745
  • p._setDurationFromSource = function () {

  • 6746
  • this._duration = this.playbackResource.duration * 1000;

  • 6747
  • };

  • 6748  
    6749
  • p._handleCleanUp = function () {

  • 6750
  • if (this.sourceNode && this.playState == createjs.Sound.PLAY_SUCCEEDED) {

  • 6751
  • this.sourceNode = this._cleanUpAudioNode(this.sourceNode);

  • 6752
  • this._sourceNodeNext = this._cleanUpAudioNode(this._sourceNodeNext);

  • 6753
  • }

  • 6754  
    6755
  • if (this.gainNode.numberOfOutputs != 0) {this.gainNode.disconnect(0);}

  • 6756
  • // OJR there appears to be a bug that this doesn't always work in webkit (Chrome and Safari). According to the documentation, this should work.

  • 6757  
    6758
  • clearTimeout(this._soundCompleteTimeout);

  • 6759  
    6760
  • this._playbackStartTime = 0; // This is used by getPosition

  • 6761
  • };

  • 6762  
    6763
  • /**

  • 6764
  • * Turn off and disconnect an audioNode, then set reference to null to release it for garbage collection

  • 6765
  • * @method _cleanUpAudioNode

  • 6766
  • * @param audioNode

  • 6767
  • * @return {audioNode}

  • 6768
  • * @protected

  • 6769
  • * @since 0.4.1

  • 6770
  • */

  • 6771
  • p._cleanUpAudioNode = function(audioNode) {

  • 6772
  • if(audioNode) {

  • 6773
  • audioNode.stop(0);

  • 6774
  • audioNode.disconnect(0);

  • 6775
  • // necessary to prevent leak on iOS Safari 7-9. will throw in almost all other

  • 6776
  • // browser implementations.

  • 6777
  • try { audioNode.buffer = s._scratchBuffer; } catch(e) {}

  • 6778
  • audioNode = null;

  • 6779
  • }

  • 6780
  • return audioNode;

  • 6781
  • };

  • 6782  
    6783
  • p._handleSoundReady = function (event) {

  • 6784
  • this.gainNode.connect(s.destinationNode); // this line can cause a memory leak. Nodes need to be disconnected from the audioDestination or any sequence that leads to it.

  • 6785  
    6786
  • var dur = this._duration * 0.001;

  • 6787
  • var pos = this._position * 0.001;

  • 6788
  • if (pos > dur) {pos = dur;}

  • 6789
  • this.sourceNode = this._createAndPlayAudioNode((s.context.currentTime - dur), pos);

  • 6790
  • this._playbackStartTime = this.sourceNode.startTime - pos;

  • 6791  
    6792
  • this._soundCompleteTimeout = setTimeout(this._endedHandler, (dur - pos) * 1000);

  • 6793  
    6794
  • if(this._loop != 0) {

  • 6795
  • this._sourceNodeNext = this._createAndPlayAudioNode(this._playbackStartTime, 0);

  • 6796
  • }

  • 6797
  • };

  • 6798  
    6799
  • /**

  • 6800
  • * Creates an audio node using the current src and context, connects it to the gain node, and starts playback.

  • 6801
  • * @method _createAndPlayAudioNode

  • 6802
  • * @param {Number} startTime The time to add this to the web audio context, in seconds.

  • 6803
  • * @param {Number} offset The amount of time into the src audio to start playback, in seconds.

  • 6804
  • * @return {audioNode}

  • 6805
  • * @protected

  • 6806
  • * @since 0.4.1

  • 6807
  • */

  • 6808
  • p._createAndPlayAudioNode = function(startTime, offset) {

  • 6809
  • var audioNode = s.context.createBufferSource();

  • 6810
  • audioNode.buffer = this.playbackResource;

  • 6811
  • audioNode.connect(this.panNode);

  • 6812
  • var dur = this._duration * 0.001;

  • 6813
  • audioNode.startTime = startTime + dur;

  • 6814
  • audioNode.start(audioNode.startTime, offset+(this._startTime*0.001), dur - offset);

  • 6815
  • return audioNode;

  • 6816
  • };

  • 6817  
    6818
  • p._pause = function () {

  • 6819
  • this._position = (s.context.currentTime - this._playbackStartTime) * 1000; // * 1000 to give milliseconds, lets us restart at same point

  • 6820
  • this.sourceNode = this._cleanUpAudioNode(this.sourceNode);

  • 6821
  • this._sourceNodeNext = this._cleanUpAudioNode(this._sourceNodeNext);

  • 6822  
    6823
  • if (this.gainNode.numberOfOutputs != 0) {this.gainNode.disconnect(0);}

  • 6824  
    6825
  • clearTimeout(this._soundCompleteTimeout);

  • 6826
  • };

  • 6827  
    6828
  • p._resume = function () {

  • 6829
  • this._handleSoundReady();

  • 6830
  • };

  • 6831  
    6832
  • /*

  • 6833
  • p._handleStop = function () {

  • 6834
  • // web audio does not need to do anything extra

  • 6835
  • };

  • 6836
  • */

  • 6837  
    6838
  • p._updateVolume = function () {

  • 6839
  • var newVolume = this._muted ? 0 : this._volume;

  • 6840
  • if (newVolume != this.gainNode.gain.value) {

  • 6841
  • this.gainNode.gain.value = newVolume;

  • 6842
  • }

  • 6843
  • };

  • 6844  
    6845
  • p._calculateCurrentPosition = function () {

  • 6846
  • return ((s.context.currentTime - this._playbackStartTime) * 1000); // pos in seconds * 1000 to give milliseconds

  • 6847
  • };

  • 6848  
    6849
  • p._updatePosition = function () {

  • 6850
  • this.sourceNode = this._cleanUpAudioNode(this.sourceNode);

  • 6851
  • this._sourceNodeNext = this._cleanUpAudioNode(this._sourceNodeNext);

  • 6852
  • clearTimeout(this._soundCompleteTimeout);

  • 6853  
    6854
  • if (!this._paused) {this._handleSoundReady();}

  • 6855
  • };

  • 6856  
    6857
  • // OJR we are using a look ahead approach to ensure smooth looping.

  • 6858
  • // We add _sourceNodeNext to the audio context so that it starts playing even if this callback is delayed.

  • 6859
  • // This technique is described here: http://www.html5rocks.com/en/tutorials/audio/scheduling/

  • 6860
  • // NOTE the cost of this is that our audio loop may not always match the loop event timing precisely.

  • 6861
  • p._handleLoop = function () {

  • 6862
  • this._cleanUpAudioNode(this.sourceNode);

  • 6863
  • this.sourceNode = this._sourceNodeNext;

  • 6864
  • this._playbackStartTime = this.sourceNode.startTime;

  • 6865
  • this._sourceNodeNext = this._createAndPlayAudioNode(this._playbackStartTime, 0);

  • 6866
  • this._soundCompleteTimeout = setTimeout(this._endedHandler, this._duration);

  • 6867
  • };

  • 6868  
    6869
  • p._updateDuration = function () {

  • 6870
  • if(this.playState == createjs.Sound.PLAY_SUCCEEDED) {

  • 6871
  • this._pause();

  • 6872
  • this._resume();

  • 6873
  • }

  • 6874
  • };

  • 6875  
    6876
  • createjs.WebAudioSoundInstance = createjs.promote(WebAudioSoundInstance, "AbstractSoundInstance");

  • 6877
  • }());

  • 6878  
    6879
  • //##############################################################################

  • 6880
  • // WebAudioPlugin.js

  • 6881
  • //##############################################################################

  • 6882  
    6883
  • this.createjs = this.createjs || {};

  • 6884  
    6885
  • (function () {

  • 6886  
    6887
  • "use strict";

  • 6888  
    6889
  • /**

  • 6890
  • * Play sounds using Web Audio in the browser. The WebAudioPlugin is currently the default plugin, and will be used

  • 6891
  • * anywhere that it is supported. To change plugin priority, check out the Sound API

  • 6892
  • * {{#crossLink "Sound/registerPlugins"}}{{/crossLink}} method.

  • 6893  
    6894
  • * <h4>Known Browser and OS issues for Web Audio</h4>

  • 6895
  • * <b>Firefox 25</b>

  • 6896
  • * <li>

  • 6897
  • * mp3 audio files do not load properly on all windows machines, reported <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=929969" target="_blank">here</a>.

  • 6898
  • * <br />For this reason it is recommended to pass another FireFox-supported type (i.e. ogg) as the default

  • 6899
  • * extension, until this bug is resolved

  • 6900
  • * </li>

  • 6901
  • *

  • 6902
  • * <b>Webkit (Chrome and Safari)</b>

  • 6903
  • * <li>

  • 6904
  • * AudioNode.disconnect does not always seem to work. This can cause the file size to grow over time if you

  • 6905
  • * are playing a lot of audio files.

  • 6906
  • * </li>

  • 6907
  • *

  • 6908
  • * <b>iOS 6 limitations</b>

  • 6909
  • * <ul>

  • 6910
  • * <li>

  • 6911
  • * Sound is initially muted and will only unmute through play being called inside a user initiated event

  • 6912
  • * (touch/click). Please read the mobile playback notes in the the {{#crossLink "Sound"}}{{/crossLink}}

  • 6913
  • * class for a full overview of the limitations, and how to get around them.

  • 6914
  • * </li>

  • 6915
  • * <li>

  • 6916
  • * A bug exists that will distort un-cached audio when a video element is present in the DOM. You can avoid

  • 6917
  • * this bug by ensuring the audio and video audio share the same sample rate.

  • 6918
  • * </li>

  • 6919
  • * </ul>

  • 6920
  • * @class WebAudioPlugin

  • 6921
  • * @extends AbstractPlugin

  • 6922
  • * @constructor

  • 6923
  • * @since 0.4.0

  • 6924
  • */

  • 6925
  • function WebAudioPlugin() {

  • 6926
  • this.AbstractPlugin_constructor();

  • 6927  
    6928  
    6929
  • // Private Properties

  • 6930
  • /**

  • 6931
  • * Value to set panning model to equal power for WebAudioSoundInstance. Can be "equalpower" or 0 depending on browser implementation.

  • 6932
  • * @property _panningModel

  • 6933
  • * @type {Number / String}

  • 6934
  • * @protected

  • 6935
  • */

  • 6936
  • this._panningModel = s._panningModel;;

  • 6937  
    6938
  • /**

  • 6939
  • * The web audio context, which WebAudio uses to play audio. All nodes that interact with the WebAudioPlugin

  • 6940
  • * need to be created within this context.

  • 6941
  • * @property context

  • 6942
  • * @type {AudioContext}

  • 6943
  • */

  • 6944
  • this.context = s.context;

  • 6945  
    6946
  • /**

  • 6947
  • * A DynamicsCompressorNode, which is used to improve sound quality and prevent audio distortion.

  • 6948
  • * It is connected to <code>context.destination</code>.

  • 6949
  • *

  • 6950
  • * Can be accessed by advanced users through createjs.Sound.activePlugin.dynamicsCompressorNode.

  • 6951
  • * @property dynamicsCompressorNode

  • 6952
  • * @type {AudioNode}

  • 6953
  • */

  • 6954
  • this.dynamicsCompressorNode = this.context.createDynamicsCompressor();

  • 6955
  • this.dynamicsCompressorNode.connect(this.context.destination);

  • 6956  
    6957
  • /**

  • 6958
  • * A GainNode for controlling master volume. It is connected to {{#crossLink "WebAudioPlugin/dynamicsCompressorNode:property"}}{{/crossLink}}.

  • 6959
  • *

  • 6960
  • * Can be accessed by advanced users through createjs.Sound.activePlugin.gainNode.

  • 6961
  • * @property gainNode

  • 6962
  • * @type {AudioGainNode}

  • 6963
  • */

  • 6964
  • this.gainNode = this.context.createGain();

  • 6965
  • this.gainNode.connect(this.dynamicsCompressorNode);

  • 6966
  • createjs.WebAudioSoundInstance.destinationNode = this.gainNode;

  • 6967  
    6968
  • this._capabilities = s._capabilities;

  • 6969  
    6970
  • this._loaderClass = createjs.WebAudioLoader;

  • 6971
  • this._soundInstanceClass = createjs.WebAudioSoundInstance;

  • 6972  
    6973
  • this._addPropsToClasses();

  • 6974
  • }

  • 6975
  • var p = createjs.extend(WebAudioPlugin, createjs.AbstractPlugin);

  • 6976  
    6977
  • // TODO: deprecated

  • 6978
  • // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.

  • 6979  
    6980  
    6981
  • // Static Properties

  • 6982
  • var s = WebAudioPlugin;

  • 6983
  • /**

  • 6984
  • * The capabilities of the plugin. This is generated via the {{#crossLink "WebAudioPlugin/_generateCapabilities:method"}}{{/crossLink}}

  • 6985
  • * method and is used internally.

  • 6986
  • * @property _capabilities

  • 6987
  • * @type {Object}

  • 6988
  • * @default null

  • 6989
  • * @protected

  • 6990
  • * @static

  • 6991
  • */

  • 6992
  • s._capabilities = null;

  • 6993  
    6994
  • /**

  • 6995
  • * Value to set panning model to equal power for WebAudioSoundInstance. Can be "equalpower" or 0 depending on browser implementation.

  • 6996
  • * @property _panningModel

  • 6997
  • * @type {Number / String}

  • 6998
  • * @protected

  • 6999
  • * @static

  • 7000
  • */

  • 7001
  • s._panningModel = "equalpower";

  • 7002  
    7003
  • /**

  • 7004
  • * The web audio context, which WebAudio uses to play audio. All nodes that interact with the WebAudioPlugin

  • 7005
  • * need to be created within this context.

  • 7006
  • *

  • 7007
  • * Advanced users can set this to an existing context, but <b>must</b> do so before they call

  • 7008
  • * {{#crossLink "Sound/registerPlugins"}}{{/crossLink}} or {{#crossLink "Sound/initializeDefaultPlugins"}}{{/crossLink}}.

  • 7009
  • *

  • 7010
  • * @property context

  • 7011
  • * @type {AudioContext}

  • 7012
  • * @static

  • 7013
  • */

  • 7014
  • s.context = null;

  • 7015  
    7016
  • /**

  • 7017
  • * The scratch buffer that will be assigned to the buffer property of a source node on close.

  • 7018
  • * Works around an iOS Safari bug: https://github.com/CreateJS/SoundJS/issues/102

  • 7019
  • *

  • 7020
  • * Advanced users can set this to an existing source node, but <b>must</b> do so before they call

  • 7021
  • * {{#crossLink "Sound/registerPlugins"}}{{/crossLink}} or {{#crossLink "Sound/initializeDefaultPlugins"}}{{/crossLink}}.

  • 7022
  • *

  • 7023
  • * @property _scratchBuffer

  • 7024
  • * @type {AudioBuffer}

  • 7025
  • * @protected

  • 7026
  • * @static

  • 7027
  • */

  • 7028
  • s._scratchBuffer = null;

  • 7029  
    7030
  • /**

  • 7031
  • * Indicated whether audio on iOS has been unlocked, which requires a touchend/mousedown event that plays an

  • 7032
  • * empty sound.

  • 7033
  • * @property _unlocked

  • 7034
  • * @type {boolean}

  • 7035
  • * @since 0.6.2

  • 7036
  • * @private

  • 7037
  • */

  • 7038
  • s._unlocked = false;

  • 7039  
    7040  
    7041
  • // Static Public Methods

  • 7042
  • /**

  • 7043
  • * Determine if the plugin can be used in the current browser/OS.

  • 7044
  • * @method isSupported

  • 7045
  • * @return {Boolean} If the plugin can be initialized.

  • 7046
  • * @static

  • 7047
  • */

  • 7048
  • s.isSupported = function () {

  • 7049
  • // check if this is some kind of mobile device, Web Audio works with local protocol under PhoneGap and it is unlikely someone is trying to run a local file

  • 7050
  • var isMobilePhoneGap = createjs.BrowserDetect.isIOS || createjs.BrowserDetect.isAndroid || createjs.BrowserDetect.isBlackberry;

  • 7051
  • // OJR isMobile may be redundant with _isFileXHRSupported available. Consider removing.

  • 7052
  • if (location.protocol == "file:" && !isMobilePhoneGap && !this._isFileXHRSupported()) { return false; } // Web Audio requires XHR, which is not usually available locally

  • 7053
  • s._generateCapabilities();

  • 7054
  • if (s.context == null) {return false;}

  • 7055
  • return true;

  • 7056
  • };

  • 7057  
    7058
  • /**

  • 7059
  • * Plays an empty sound in the web audio context. This is used to enable web audio on iOS devices, as they

  • 7060
  • * require the first sound to be played inside of a user initiated event (touch/click). This is called when

  • 7061
  • * {{#crossLink "WebAudioPlugin"}}{{/crossLink}} is initialized (by Sound {{#crossLink "Sound/initializeDefaultPlugins"}}{{/crossLink}}

  • 7062
  • * for example).

  • 7063
  • *

  • 7064
  • * <h4>Example</h4>

  • 7065
  • *

  • 7066
  • * function handleTouch(event) {

  • 7067
  • * createjs.WebAudioPlugin.playEmptySound();

  • 7068
  • * }

  • 7069
  • *

  • 7070
  • * @method playEmptySound

  • 7071
  • * @static

  • 7072
  • * @since 0.4.1

  • 7073
  • */

  • 7074
  • s.playEmptySound = function() {

  • 7075
  • if (s.context == null) {return;}

  • 7076
  • var source = s.context.createBufferSource();

  • 7077
  • source.buffer = s._scratchBuffer;

  • 7078
  • source.connect(s.context.destination);

  • 7079
  • source.start(0, 0, 0);

  • 7080
  • };

  • 7081  
    7082  
    7083
  • // Static Private Methods

  • 7084
  • /**

  • 7085
  • * Determine if XHR is supported, which is necessary for web audio.

  • 7086
  • * @method _isFileXHRSupported

  • 7087
  • * @return {Boolean} If XHR is supported.

  • 7088
  • * @since 0.4.2

  • 7089
  • * @protected

  • 7090
  • * @static

  • 7091
  • */

  • 7092
  • s._isFileXHRSupported = function() {

  • 7093
  • // it's much easier to detect when something goes wrong, so let's start optimistically

  • 7094
  • var supported = true;

  • 7095  
    7096
  • var xhr = new XMLHttpRequest();

  • 7097
  • try {

  • 7098
  • xhr.open("GET", "WebAudioPluginTest.fail", false); // loading non-existant file triggers 404 only if it could load (synchronous call)

  • 7099
  • } catch (error) {

  • 7100
  • // catch errors in cases where the onerror is passed by

  • 7101
  • supported = false;

  • 7102
  • return supported;

  • 7103
  • }

  • 7104
  • xhr.onerror = function() { supported = false; }; // cause irrelevant

  • 7105
  • // with security turned off, we can get empty success results, which is actually a failed read (status code 0?)

  • 7106
  • xhr.onload = function() { supported = this.status == 404 || (this.status == 200 || (this.status == 0 && this.response != "")); };

  • 7107
  • try {

  • 7108
  • xhr.send();

  • 7109
  • } catch (error) {

  • 7110
  • // catch errors in cases where the onerror is passed by

  • 7111
  • supported = false;

  • 7112
  • }

  • 7113  
    7114
  • return supported;

  • 7115
  • };

  • 7116  
    7117
  • /**

  • 7118
  • * Determine the capabilities of the plugin. Used internally. Please see the Sound API {{#crossLink "Sound/getCapabilities"}}{{/crossLink}}

  • 7119
  • * method for an overview of plugin capabilities.

  • 7120
  • * @method _generateCapabilities

  • 7121
  • * @static

  • 7122
  • * @protected

  • 7123
  • */

  • 7124
  • s._generateCapabilities = function () {

  • 7125
  • if (s._capabilities != null) {return;}

  • 7126
  • // Web Audio can be in any formats supported by the audio element, from http://www.w3.org/TR/webaudio/#AudioContext-section

  • 7127
  • var t = document.createElement("audio");

  • 7128
  • if (t.canPlayType == null) {return null;}

  • 7129  
    7130
  • if (s.context == null) {

  • 7131
  • if (window.AudioContext) {

  • 7132
  • s.context = new AudioContext();

  • 7133
  • } else if (window.webkitAudioContext) {

  • 7134
  • s.context = new webkitAudioContext();

  • 7135
  • } else {

  • 7136
  • return null;

  • 7137
  • }

  • 7138
  • }

  • 7139
  • if (s._scratchBuffer == null) {

  • 7140
  • s._scratchBuffer = s.context.createBuffer(1, 1, 22050);

  • 7141
  • }

  • 7142  
    7143
  • s._compatibilitySetUp();

  • 7144  
    7145
  • // Listen for document level clicks to unlock WebAudio on iOS. See the _unlock method.

  • 7146
  • if ("ontouchstart" in window && s.context.state != "running") {

  • 7147
  • s._unlock(); // When played inside of a touch event, this will enable audio on iOS immediately.

  • 7148
  • document.addEventListener("mousedown", s._unlock, true);

  • 7149
  • document.addEventListener("touchend", s._unlock, true);

  • 7150
  • }

  • 7151  
    7152  
    7153
  • s._capabilities = {

  • 7154
  • panning:true,

  • 7155
  • volume:true,

  • 7156
  • tracks:-1

  • 7157
  • };

  • 7158  
    7159
  • // determine which extensions our browser supports for this plugin by iterating through Sound.SUPPORTED_EXTENSIONS

  • 7160
  • var supportedExtensions = createjs.Sound.SUPPORTED_EXTENSIONS;

  • 7161
  • var extensionMap = createjs.Sound.EXTENSION_MAP;

  • 7162
  • for (var i = 0, l = supportedExtensions.length; i < l; i++) {

  • 7163
  • var ext = supportedExtensions[i];

  • 7164
  • var playType = extensionMap[ext] || ext;

  • 7165
  • s._capabilities[ext] = (t.canPlayType("audio/" + ext) != "no" && t.canPlayType("audio/" + ext) != "") || (t.canPlayType("audio/" + playType) != "no" && t.canPlayType("audio/" + playType) != "");

  • 7166
  • } // OJR another way to do this might be canPlayType:"m4a", codex: mp4

  • 7167  
    7168
  • // 0=no output, 1=mono, 2=stereo, 4=surround, 6=5.1 surround.

  • 7169
  • // See http://www.w3.org/TR/webaudio/#AudioChannelSplitter for more details on channels.

  • 7170
  • if (s.context.destination.numberOfChannels < 2) {

  • 7171
  • s._capabilities.panning = false;

  • 7172
  • }

  • 7173
  • };

  • 7174  
    7175
  • /**

  • 7176
  • * Set up compatibility if only deprecated web audio calls are supported.

  • 7177
  • * See http://www.w3.org/TR/webaudio/#DeprecationNotes

  • 7178
  • * Needed so we can support new browsers that don't support deprecated calls (Firefox) as well as old browsers that

  • 7179
  • * don't support new calls.

  • 7180
  • *

  • 7181
  • * @method _compatibilitySetUp

  • 7182
  • * @static

  • 7183
  • * @protected

  • 7184
  • * @since 0.4.2

  • 7185
  • */

  • 7186
  • s._compatibilitySetUp = function() {

  • 7187
  • s._panningModel = "equalpower";

  • 7188
  • //assume that if one new call is supported, they all are

  • 7189
  • if (s.context.createGain) { return; }

  • 7190  
    7191
  • // simple name change, functionality the same

  • 7192
  • s.context.createGain = s.context.createGainNode;

  • 7193  
    7194
  • // source node, add to prototype

  • 7195
  • var audioNode = s.context.createBufferSource();

  • 7196
  • audioNode.__proto__.start = audioNode.__proto__.noteGrainOn; // note that noteGrainOn requires all 3 parameters

  • 7197
  • audioNode.__proto__.stop = audioNode.__proto__.noteOff;

  • 7198  
    7199
  • // panningModel

  • 7200
  • s._panningModel = 0;

  • 7201
  • };

  • 7202  
    7203
  • /**

  • 7204
  • * Try to unlock audio on iOS. This is triggered from either WebAudio plugin setup (which will work if inside of

  • 7205
  • * a `mousedown` or `touchend` event stack), or the first document touchend/mousedown event. If it fails (touchend

  • 7206
  • * will fail if the user presses for too long, indicating a scroll event instead of a click event.

  • 7207
  • *

  • 7208
  • * Note that earlier versions of iOS supported `touchstart` for this, but iOS9 removed this functionality. Adding

  • 7209
  • * a `touchstart` event to support older platforms may preclude a `mousedown` even from getting fired on iOS9, so we

  • 7210
  • * stick with `mousedown` and `touchend`.

  • 7211
  • * @method _unlock

  • 7212
  • * @since 0.6.2

  • 7213
  • * @private

  • 7214
  • */

  • 7215
  • s._unlock = function() {

  • 7216
  • if (s._unlocked) { return; }

  • 7217
  • s.playEmptySound();

  • 7218
  • if (s.context.state == "running") {

  • 7219
  • document.removeEventListener("mousedown", s._unlock, true);

  • 7220
  • document.removeEventListener("touchend", s._unlock, true);

  • 7221
  • s._unlocked = true;

  • 7222
  • }

  • 7223
  • };

  • 7224  
    7225  
    7226
  • // Public Methods

  • 7227
  • p.toString = function () {

  • 7228
  • return "[WebAudioPlugin]";

  • 7229
  • };

  • 7230  
    7231  
    7232
  • // Private Methods

  • 7233
  • /**

  • 7234
  • * Set up needed properties on supported classes WebAudioSoundInstance and WebAudioLoader.

  • 7235
  • * @method _addPropsToClasses

  • 7236
  • * @static

  • 7237
  • * @protected

  • 7238
  • * @since 0.6.0

  • 7239
  • */

  • 7240
  • p._addPropsToClasses = function() {

  • 7241
  • var c = this._soundInstanceClass;

  • 7242
  • c.context = this.context;

  • 7243
  • c._scratchBuffer = s._scratchBuffer;

  • 7244
  • c.destinationNode = this.gainNode;

  • 7245
  • c._panningModel = this._panningModel;

  • 7246  
    7247
  • this._loaderClass.context = this.context;

  • 7248
  • };

  • 7249  
    7250  
    7251
  • /**

  • 7252
  • * Set the gain value for master audio. Should not be called externally.

  • 7253
  • * @method _updateVolume

  • 7254
  • * @protected

  • 7255
  • */

  • 7256
  • p._updateVolume = function () {

  • 7257
  • var newVolume = createjs.Sound._masterMute ? 0 : this._volume;

  • 7258
  • if (newVolume != this.gainNode.gain.value) {

  • 7259
  • this.gainNode.gain.value = newVolume;

  • 7260
  • }

  • 7261
  • };

  • 7262  
    7263
  • createjs.WebAudioPlugin = createjs.promote(WebAudioPlugin, "AbstractPlugin");

  • 7264
  • }());

  • 7265  
    7266
  • //##############################################################################

  • 7267
  • // HTMLAudioTagPool.js

  • 7268
  • //##############################################################################

  • 7269  
    7270
  • this.createjs = this.createjs || {};

  • 7271  
    7272
  • (function () {

  • 7273
  • "use strict";

  • 7274  
    7275
  • /**

  • 7276
  • * HTMLAudioTagPool is an object pool for HTMLAudio tag instances.

  • 7277
  • * @class HTMLAudioTagPool

  • 7278
  • * @param {String} src The source of the channel.

  • 7279
  • * @protected

  • 7280
  • */

  • 7281
  • function HTMLAudioTagPool() {

  • 7282
  • throw "HTMLAudioTagPool cannot be instantiated";

  • 7283
  • }

  • 7284  
    7285
  • var s = HTMLAudioTagPool;

  • 7286  
    7287
  • // Static Properties

  • 7288
  • /**

  • 7289
  • * A hash lookup of each base audio tag, indexed by the audio source.

  • 7290
  • * @property _tags

  • 7291
  • * @type {{}}

  • 7292
  • * @static

  • 7293
  • * @protected

  • 7294
  • */

  • 7295
  • s._tags = {};

  • 7296  
    7297
  • /**

  • 7298
  • * An object pool for html audio tags

  • 7299
  • * @property _tagPool

  • 7300
  • * @type {TagPool}

  • 7301
  • * @static

  • 7302
  • * @protected

  • 7303
  • */

  • 7304
  • s._tagPool = new TagPool();

  • 7305  
    7306
  • /**

  • 7307
  • * A hash lookup of if a base audio tag is available, indexed by the audio source

  • 7308
  • * @property _tagsUsed

  • 7309
  • * @type {{}}

  • 7310
  • * @protected

  • 7311
  • * @static

  • 7312
  • */

  • 7313
  • s._tagUsed = {};

  • 7314  
    7315
  • // Static Methods

  • 7316
  • /**

  • 7317
  • * Get an audio tag with the given source.

  • 7318
  • * @method get

  • 7319
  • * @param {String} src The source file used by the audio tag.

  • 7320
  • * @static

  • 7321
  • */

  • 7322
  • s.get = function (src) {

  • 7323
  • var t = s._tags[src];

  • 7324
  • if (t == null) {

  • 7325
  • // create new base tag

  • 7326
  • t = s._tags[src] = s._tagPool.get();

  • 7327
  • t.src = src;

  • 7328
  • } else {

  • 7329
  • // get base or pool

  • 7330
  • if (s._tagUsed[src]) {

  • 7331
  • t = s._tagPool.get();

  • 7332
  • t.src = src;

  • 7333
  • } else {

  • 7334
  • s._tagUsed[src] = true;

  • 7335
  • }

  • 7336
  • }

  • 7337
  • return t;

  • 7338
  • };

  • 7339  
    7340
  • /**

  • 7341
  • * Return an audio tag to the pool.

  • 7342
  • * @method set

  • 7343
  • * @param {String} src The source file used by the audio tag.

  • 7344
  • * @param {HTMLElement} tag Audio tag to set.

  • 7345
  • * @static

  • 7346
  • */

  • 7347
  • s.set = function (src, tag) {

  • 7348
  • // check if this is base, if yes set boolean if not return to pool

  • 7349
  • if(tag == s._tags[src]) {

  • 7350
  • s._tagUsed[src] = false;

  • 7351
  • } else {

  • 7352
  • s._tagPool.set(tag);

  • 7353
  • }

  • 7354
  • };

  • 7355  
    7356
  • /**

  • 7357
  • * Delete stored tag reference and return them to pool. Note that if the tag reference does not exist, this will fail.

  • 7358
  • * @method remove

  • 7359
  • * @param {String} src The source for the tag

  • 7360
  • * @return {Boolean} If the TagPool was deleted.

  • 7361
  • * @static

  • 7362
  • */

  • 7363
  • s.remove = function (src) {

  • 7364
  • var tag = s._tags[src];

  • 7365
  • if (tag == null) {return false;}

  • 7366
  • s._tagPool.set(tag);

  • 7367
  • delete(s._tags[src]);

  • 7368
  • delete(s._tagUsed[src]);

  • 7369
  • return true;

  • 7370
  • };

  • 7371  
    7372
  • /**

  • 7373
  • * Gets the duration of the src audio in milliseconds

  • 7374
  • * @method getDuration

  • 7375
  • * @param {String} src The source file used by the audio tag.

  • 7376
  • * @return {Number} Duration of src in milliseconds

  • 7377
  • * @static

  • 7378
  • */

  • 7379
  • s.getDuration= function (src) {

  • 7380
  • var t = s._tags[src];

  • 7381
  • if (t == null || !t.duration) {return 0;} // OJR duration is NaN if loading has not completed

  • 7382
  • return t.duration * 1000;

  • 7383
  • };

  • 7384  
    7385
  • createjs.HTMLAudioTagPool = HTMLAudioTagPool;

  • 7386  
    7387  
    7388
  • // ************************************************************************************************************

  • 7389
  • /**

  • 7390
  • * The TagPool is an object pool for HTMLAudio tag instances.

  • 7391
  • * #class TagPool

  • 7392
  • * @param {String} src The source of the channel.

  • 7393
  • * @protected

  • 7394
  • */

  • 7395
  • function TagPool(src) {

  • 7396  
    7397
  • // Public Properties

  • 7398
  • /**

  • 7399
  • * A list of all available tags in the pool.

  • 7400
  • * #property tags

  • 7401
  • * @type {Array}

  • 7402
  • * @protected

  • 7403
  • */

  • 7404
  • this._tags = [];

  • 7405
  • };

  • 7406  
    7407
  • var p = TagPool.prototype;

  • 7408
  • p.constructor = TagPool;

  • 7409  
    7410  
    7411
  • // Public Methods

  • 7412
  • /**

  • 7413
  • * Get an HTMLAudioElement for immediate playback. This takes it out of the pool.

  • 7414
  • * #method get

  • 7415
  • * @return {HTMLAudioElement} An HTML audio tag.

  • 7416
  • */

  • 7417
  • p.get = function () {

  • 7418
  • var tag;

  • 7419
  • if (this._tags.length == 0) {

  • 7420
  • tag = this._createTag();

  • 7421
  • } else {

  • 7422
  • tag = this._tags.pop();

  • 7423
  • }

  • 7424
  • if (tag.parentNode == null) {document.body.appendChild(tag);}

  • 7425
  • return tag;

  • 7426
  • };

  • 7427  
    7428
  • /**

  • 7429
  • * Put an HTMLAudioElement back in the pool for use.

  • 7430
  • * #method set

  • 7431
  • * @param {HTMLAudioElement} tag HTML audio tag

  • 7432
  • */

  • 7433
  • p.set = function (tag) {

  • 7434
  • // OJR this first step seems unnecessary

  • 7435
  • var index = createjs.indexOf(this._tags, tag);

  • 7436
  • if (index == -1) {

  • 7437
  • this._tags.src = null;

  • 7438
  • this._tags.push(tag);

  • 7439
  • }

  • 7440
  • };

  • 7441  
    7442
  • p.toString = function () {

  • 7443
  • return "[TagPool]";

  • 7444
  • };

  • 7445  
    7446  
    7447
  • // Private Methods

  • 7448
  • /**

  • 7449
  • * Create an HTML audio tag.

  • 7450
  • * #method _createTag

  • 7451
  • * @param {String} src The source file to set for the audio tag.

  • 7452
  • * @return {HTMLElement} Returns an HTML audio tag.

  • 7453
  • * @protected

  • 7454
  • */

  • 7455
  • p._createTag = function () {

  • 7456
  • var tag = document.createElement("audio");

  • 7457
  • tag.autoplay = false;

  • 7458
  • tag.preload = "none";

  • 7459
  • //LM: Firefox fails when this the preload="none" for other tags, but it needs to be "none" to ensure PreloadJS works.

  • 7460
  • return tag;

  • 7461
  • };

  • 7462  
    7463
  • }());

  • 7464  
    7465
  • //##############################################################################

  • 7466
  • // HTMLAudioSoundInstance.js

  • 7467
  • //##############################################################################

  • 7468  
    7469
  • this.createjs = this.createjs || {};

  • 7470  
    7471
  • (function () {

  • 7472
  • "use strict";

  • 7473  
    7474
  • /**

  • 7475
  • * HTMLAudioSoundInstance extends the base api of {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} and is used by

  • 7476
  • * {{#crossLink "HTMLAudioPlugin"}}{{/crossLink}}.

  • 7477
  • *

  • 7478
  • * @param {String} src The path to and file name of the sound.

  • 7479
  • * @param {Number} startTime Audio sprite property used to apply an offset, in milliseconds.

  • 7480
  • * @param {Number} duration Audio sprite property used to set the time the clip plays for, in milliseconds.

  • 7481
  • * @param {Object} playbackResource Any resource needed by plugin to support audio playback.

  • 7482
  • * @class HTMLAudioSoundInstance

  • 7483
  • * @extends AbstractSoundInstance

  • 7484
  • * @constructor

  • 7485
  • */

  • 7486
  • function HTMLAudioSoundInstance(src, startTime, duration, playbackResource) {

  • 7487
  • this.AbstractSoundInstance_constructor(src, startTime, duration, playbackResource);

  • 7488  
    7489  
    7490
  • // Private Properties

  • 7491
  • this._audioSpriteStopTime = null;

  • 7492
  • this._delayTimeoutId = null;

  • 7493  
    7494
  • // Proxies, make removing listeners easier.

  • 7495
  • this._endedHandler = createjs.proxy(this._handleSoundComplete, this);

  • 7496
  • this._readyHandler = createjs.proxy(this._handleTagReady, this);

  • 7497
  • this._stalledHandler = createjs.proxy(this._playFailed, this);

  • 7498
  • this._audioSpriteEndHandler = createjs.proxy(this._handleAudioSpriteLoop, this);

  • 7499
  • this._loopHandler = createjs.proxy(this._handleSoundComplete, this);

  • 7500  
    7501
  • if (duration) {

  • 7502
  • this._audioSpriteStopTime = (startTime + duration) * 0.001;

  • 7503
  • } else {

  • 7504
  • this._duration = createjs.HTMLAudioTagPool.getDuration(this.src);

  • 7505
  • }

  • 7506
  • }

  • 7507
  • var p = createjs.extend(HTMLAudioSoundInstance, createjs.AbstractSoundInstance);

  • 7508  
    7509
  • // TODO: deprecated

  • 7510
  • // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.

  • 7511  
    7512  
    7513
  • // Public Methods

  • 7514
  • /**

  • 7515
  • * Called by {{#crossLink "Sound"}}{{/crossLink}} when plugin does not handle master volume.

  • 7516
  • * undoc'd because it is not meant to be used outside of Sound

  • 7517
  • * #method setMasterVolume

  • 7518
  • * @param value

  • 7519
  • */

  • 7520
  • p.setMasterVolume = function (value) {

  • 7521
  • this._updateVolume();

  • 7522
  • };

  • 7523  
    7524
  • /**

  • 7525
  • * Called by {{#crossLink "Sound"}}{{/crossLink}} when plugin does not handle master mute.

  • 7526
  • * undoc'd because it is not meant to be used outside of Sound

  • 7527
  • * #method setMasterMute

  • 7528
  • * @param value

  • 7529
  • */

  • 7530
  • p.setMasterMute = function (isMuted) {

  • 7531
  • this._updateVolume();

  • 7532
  • };

  • 7533  
    7534
  • p.toString = function () {

  • 7535
  • return "[HTMLAudioSoundInstance]";

  • 7536
  • };

  • 7537  
    7538
  • //Private Methods

  • 7539
  • p._removeLooping = function() {

  • 7540
  • if(this._playbackResource == null) {return;}

  • 7541
  • this._playbackResource.loop = false;

  • 7542
  • this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._loopHandler, false);

  • 7543
  • };

  • 7544  
    7545
  • p._addLooping = function() {

  • 7546
  • if(this._playbackResource == null || this._audioSpriteStopTime) {return;}

  • 7547
  • this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._loopHandler, false);

  • 7548
  • this._playbackResource.loop = true;

  • 7549
  • };

  • 7550  
    7551
  • p._handleCleanUp = function () {

  • 7552
  • var tag = this._playbackResource;

  • 7553
  • if (tag != null) {

  • 7554
  • tag.pause();

  • 7555
  • tag.loop = false;

  • 7556
  • tag.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_ENDED, this._endedHandler, false);

  • 7557
  • tag.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_READY, this._readyHandler, false);

  • 7558
  • tag.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_STALLED, this._stalledHandler, false);

  • 7559
  • tag.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._loopHandler, false);

  • 7560
  • tag.removeEventListener(createjs.HTMLAudioPlugin._TIME_UPDATE, this._audioSpriteEndHandler, false);

  • 7561  
    7562
  • try {

  • 7563
  • tag.currentTime = this._startTime;

  • 7564
  • } catch (e) {

  • 7565
  • } // Reset Position

  • 7566
  • createjs.HTMLAudioTagPool.set(this.src, tag);

  • 7567
  • this._playbackResource = null;

  • 7568
  • }

  • 7569
  • };

  • 7570  
    7571
  • p._beginPlaying = function (playProps) {

  • 7572
  • this._playbackResource = createjs.HTMLAudioTagPool.get(this.src);

  • 7573
  • return this.AbstractSoundInstance__beginPlaying(playProps);

  • 7574
  • };

  • 7575  
    7576
  • p._handleSoundReady = function (event) {

  • 7577
  • if (this._playbackResource.readyState !== 4) {

  • 7578
  • var tag = this._playbackResource;

  • 7579
  • tag.addEventListener(createjs.HTMLAudioPlugin._AUDIO_READY, this._readyHandler, false);

  • 7580
  • tag.addEventListener(createjs.HTMLAudioPlugin._AUDIO_STALLED, this._stalledHandler, false);

  • 7581
  • tag.preload = "auto"; // This is necessary for Firefox, as it won't ever "load" until this is set.

  • 7582
  • tag.load();

  • 7583
  • return;

  • 7584
  • }

  • 7585  
    7586
  • this._updateVolume();

  • 7587
  • this._playbackResource.currentTime = (this._startTime + this._position) * 0.001;

  • 7588
  • if (this._audioSpriteStopTime) {

  • 7589
  • this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._TIME_UPDATE, this._audioSpriteEndHandler, false);

  • 7590
  • } else {

  • 7591
  • this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._AUDIO_ENDED, this._endedHandler, false);

  • 7592
  • if(this._loop != 0) {

  • 7593
  • this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._loopHandler, false);

  • 7594
  • this._playbackResource.loop = true;

  • 7595
  • }

  • 7596
  • }

  • 7597  
    7598
  • this._playbackResource.play();

  • 7599
  • };

  • 7600  
    7601
  • /**

  • 7602
  • * Used to handle when a tag is not ready for immediate playback when it is returned from the HTMLAudioTagPool.

  • 7603
  • * @method _handleTagReady

  • 7604
  • * @param event

  • 7605
  • * @protected

  • 7606
  • */

  • 7607
  • p._handleTagReady = function (event) {

  • 7608
  • this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_READY, this._readyHandler, false);

  • 7609
  • this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_STALLED, this._stalledHandler, false);

  • 7610  
    7611
  • this._handleSoundReady();

  • 7612
  • };

  • 7613  
    7614
  • p._pause = function () {

  • 7615
  • this._playbackResource.pause();

  • 7616
  • };

  • 7617  
    7618
  • p._resume = function () {

  • 7619
  • this._playbackResource.play();

  • 7620
  • };

  • 7621  
    7622
  • p._updateVolume = function () {

  • 7623
  • if (this._playbackResource != null) {

  • 7624
  • var newVolume = (this._muted || createjs.Sound._masterMute) ? 0 : this._volume * createjs.Sound._masterVolume;

  • 7625
  • if (newVolume != this._playbackResource.volume) {this._playbackResource.volume = newVolume;}

  • 7626
  • }

  • 7627
  • };

  • 7628  
    7629
  • p._calculateCurrentPosition = function() {

  • 7630
  • return (this._playbackResource.currentTime * 1000) - this._startTime;

  • 7631
  • };

  • 7632  
    7633
  • p._updatePosition = function() {

  • 7634
  • this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._loopHandler, false);

  • 7635
  • this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._handleSetPositionSeek, false);

  • 7636
  • try {

  • 7637
  • this._playbackResource.currentTime = (this._position + this._startTime) * 0.001;

  • 7638
  • } catch (error) { // Out of range

  • 7639
  • this._handleSetPositionSeek(null);

  • 7640
  • }

  • 7641
  • };

  • 7642  
    7643
  • /**

  • 7644
  • * Used to enable setting position, as we need to wait for that seek to be done before we add back our loop handling seek listener

  • 7645
  • * @method _handleSetPositionSeek

  • 7646
  • * @param event

  • 7647
  • * @protected

  • 7648
  • */

  • 7649
  • p._handleSetPositionSeek = function(event) {

  • 7650
  • if (this._playbackResource == null) { return; }

  • 7651
  • this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._handleSetPositionSeek, false);

  • 7652
  • this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._loopHandler, false);

  • 7653
  • };

  • 7654  
    7655
  • /**

  • 7656
  • * Timer used to loop audio sprites.

  • 7657
  • * NOTE because of the inaccuracies in the timeupdate event (15 - 250ms) and in setting the tag to the desired timed

  • 7658
  • * (up to 300ms), it is strongly recommended not to loop audio sprites with HTML Audio if smooth looping is desired

  • 7659
  • *

  • 7660
  • * @method _handleAudioSpriteLoop

  • 7661
  • * @param event

  • 7662
  • * @private

  • 7663
  • */

  • 7664
  • p._handleAudioSpriteLoop = function (event) {

  • 7665
  • if(this._playbackResource.currentTime <= this._audioSpriteStopTime) {return;}

  • 7666
  • this._playbackResource.pause();

  • 7667
  • if(this._loop == 0) {

  • 7668
  • this._handleSoundComplete(null);

  • 7669
  • } else {

  • 7670
  • this._position = 0;

  • 7671
  • this._loop--;

  • 7672
  • this._playbackResource.currentTime = this._startTime * 0.001;

  • 7673
  • if(!this._paused) {this._playbackResource.play();}

  • 7674
  • this._sendEvent("loop");

  • 7675
  • }

  • 7676
  • };

  • 7677  
    7678
  • // NOTE with this approach audio will loop as reliably as the browser allows

  • 7679
  • // but we could end up sending the loop event after next loop playback begins

  • 7680
  • p._handleLoop = function (event) {

  • 7681
  • if(this._loop == 0) {

  • 7682
  • this._playbackResource.loop = false;

  • 7683
  • this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._loopHandler, false);

  • 7684
  • }

  • 7685
  • };

  • 7686  
    7687
  • p._updateStartTime = function () {

  • 7688
  • this._audioSpriteStopTime = (this._startTime + this._duration) * 0.001;

  • 7689  
    7690
  • if(this.playState == createjs.Sound.PLAY_SUCCEEDED) {

  • 7691
  • this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_ENDED, this._endedHandler, false);

  • 7692
  • this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._TIME_UPDATE, this._audioSpriteEndHandler, false);

  • 7693
  • }

  • 7694
  • };

  • 7695  
    7696
  • p._updateDuration = function () {

  • 7697
  • this._audioSpriteStopTime = (this._startTime + this._duration) * 0.001;

  • 7698  
    7699
  • if(this.playState == createjs.Sound.PLAY_SUCCEEDED) {

  • 7700
  • this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_ENDED, this._endedHandler, false);

  • 7701
  • this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._TIME_UPDATE, this._audioSpriteEndHandler, false);

  • 7702
  • }

  • 7703
  • };

  • 7704  
    7705
  • p._setDurationFromSource = function () {

  • 7706
  • this._duration = createjs.HTMLAudioTagPool.getDuration(this.src);

  • 7707
  • this._playbackResource = null;

  • 7708
  • };

  • 7709  
    7710
  • createjs.HTMLAudioSoundInstance = createjs.promote(HTMLAudioSoundInstance, "AbstractSoundInstance");

  • 7711
  • }());

  • 7712  
    7713
  • //##############################################################################

  • 7714
  • // HTMLAudioPlugin.js

  • 7715
  • //##############################################################################

  • 7716  
    7717
  • this.createjs = this.createjs || {};

  • 7718  
    7719
  • (function () {

  • 7720  
    7721
  • "use strict";

  • 7722  
    7723
  • /**

  • 7724
  • * Play sounds using HTML &lt;audio&gt; tags in the browser. This plugin is the second priority plugin installed

  • 7725
  • * by default, after the {{#crossLink "WebAudioPlugin"}}{{/crossLink}}. For older browsers that do not support html

  • 7726
  • * audio, include and install the {{#crossLink "FlashAudioPlugin"}}{{/crossLink}}.

  • 7727
  • *

  • 7728
  • * <h4>Known Browser and OS issues for HTML Audio</h4>

  • 7729
  • * <b>All browsers</b><br />

  • 7730
  • * Testing has shown in all browsers there is a limit to how many audio tag instances you are allowed. If you exceed

  • 7731
  • * this limit, you can expect to see unpredictable results. Please use {{#crossLink "Sound.MAX_INSTANCES"}}{{/crossLink}} as

  • 7732
  • * a guide to how many total audio tags you can safely use in all browsers. This issue is primarily limited to IE9.

  • 7733
  • *

  • 7734
  • * <b>IE html limitations</b><br />

  • 7735
  • * <ul><li>There is a delay in applying volume changes to tags that occurs once playback is started. So if you have

  • 7736
  • * muted all sounds, they will all play during this delay until the mute applies internally. This happens regardless of

  • 7737
  • * when or how you apply the volume change, as the tag seems to need to play to apply it.</li>

  • 7738
  • * <li>MP3 encoding will not always work for audio tags if it's not default. We've found default encoding with

  • 7739
  • * 64kbps works.</li>

  • 7740
  • * <li>Occasionally very short samples will get cut off.</li>

  • 7741
  • * <li>There is a limit to how many audio tags you can load or play at once, which appears to be determined by

  • 7742
  • * hardware and browser settings. See {{#crossLink "HTMLAudioPlugin.MAX_INSTANCES"}}{{/crossLink}} for a safe estimate.

  • 7743
  • * Note that audio sprites can be used as a solution to this issue.</li></ul>

  • 7744
  • *

  • 7745
  • * <b>Safari limitations</b><br />

  • 7746
  • * <ul><li>Safari requires Quicktime to be installed for audio playback.</li></ul>

  • 7747
  • *

  • 7748
  • * <b>iOS 6 limitations</b><br />

  • 7749
  • * <ul><li>can only have one &lt;audio&gt; tag</li>

  • 7750
  • * <li>can not preload or autoplay the audio</li>

  • 7751
  • * <li>can not cache the audio</li>

  • 7752
  • * <li>can not play the audio except inside a user initiated event.</li>

  • 7753
  • * <li>Note it is recommended to use {{#crossLink "WebAudioPlugin"}}{{/crossLink}} for iOS (6+)</li>

  • 7754
  • * <li>audio sprites can be used to mitigate some of these issues and are strongly recommended on iOS</li>

  • 7755
  • * </ul>

  • 7756
  • *

  • 7757
  • * <b>Android Native Browser limitations</b><br />

  • 7758
  • * <ul><li>We have no control over audio volume. Only the user can set volume on their device.</li>

  • 7759
  • * <li>We can only play audio inside a user event (touch/click). This currently means you cannot loop sound or use a delay.</li></ul>

  • 7760
  • * <b> Android Chrome 26.0.1410.58 specific limitations</b><br />

  • 7761
  • * <ul> <li>Can only play 1 sound at a time.</li>

  • 7762
  • * <li>Sound is not cached.</li>

  • 7763
  • * <li>Sound can only be loaded in a user initiated touch/click event.</li>

  • 7764
  • * <li>There is a delay before a sound is played, presumably while the src is loaded.</li>

  • 7765
  • * </ul>

  • 7766
  • *

  • 7767
  • * See {{#crossLink "Sound"}}{{/crossLink}} for general notes on known issues.

  • 7768
  • *

  • 7769
  • * @class HTMLAudioPlugin

  • 7770
  • * @extends AbstractPlugin

  • 7771
  • * @constructor

  • 7772
  • */

  • 7773
  • function HTMLAudioPlugin() {

  • 7774
  • this.AbstractPlugin_constructor();

  • 7775  
    7776  
    7777
  • // Public Properties

  • 7778
  • /**

  • 7779
  • * This is no longer needed as we are now using object pooling for tags.

  • 7780
  • *

  • 7781
  • * <b>NOTE this property only exists as a limitation of HTML audio.</b>

  • 7782
  • * @property defaultNumChannels

  • 7783
  • * @type {Number}

  • 7784
  • * @default 2

  • 7785
  • * @since 0.4.0

  • 7786
  • * @deprecated

  • 7787
  • */

  • 7788
  • this.defaultNumChannels = 2;

  • 7789  
    7790
  • this._capabilities = s._capabilities;

  • 7791  
    7792
  • this._loaderClass = createjs.SoundLoader;

  • 7793
  • this._soundInstanceClass = createjs.HTMLAudioSoundInstance;

  • 7794
  • }

  • 7795  
    7796
  • var p = createjs.extend(HTMLAudioPlugin, createjs.AbstractPlugin);

  • 7797
  • var s = HTMLAudioPlugin;

  • 7798  
    7799
  • // TODO: deprecated

  • 7800
  • // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.

  • 7801  
    7802  
    7803
  • // Static Properties

  • 7804
  • /**

  • 7805
  • * The maximum number of instances that can be loaded or played. This is a browser limitation, primarily limited to IE9.

  • 7806
  • * The actual number varies from browser to browser (and is largely hardware dependant), but this is a safe estimate.

  • 7807
  • * Audio sprites work around this limitation.

  • 7808
  • * @property MAX_INSTANCES

  • 7809
  • * @type {Number}

  • 7810
  • * @default 30

  • 7811
  • * @static

  • 7812
  • */

  • 7813
  • s.MAX_INSTANCES = 30;

  • 7814  
    7815
  • /**

  • 7816
  • * Event constant for the "canPlayThrough" event for cleaner code.

  • 7817
  • * @property _AUDIO_READY

  • 7818
  • * @type {String}

  • 7819
  • * @default canplaythrough

  • 7820
  • * @static

  • 7821
  • * @protected

  • 7822
  • */

  • 7823
  • s._AUDIO_READY = "canplaythrough";

  • 7824  
    7825
  • /**

  • 7826
  • * Event constant for the "ended" event for cleaner code.

  • 7827
  • * @property _AUDIO_ENDED

  • 7828
  • * @type {String}

  • 7829
  • * @default ended

  • 7830
  • * @static

  • 7831
  • * @protected

  • 7832
  • */

  • 7833
  • s._AUDIO_ENDED = "ended";

  • 7834  
    7835
  • /**

  • 7836
  • * Event constant for the "seeked" event for cleaner code. We utilize this event for maintaining loop events.

  • 7837
  • * @property _AUDIO_SEEKED

  • 7838
  • * @type {String}

  • 7839
  • * @default seeked

  • 7840
  • * @static

  • 7841
  • * @protected

  • 7842
  • */

  • 7843
  • s._AUDIO_SEEKED = "seeked";

  • 7844  
    7845
  • /**

  • 7846
  • * Event constant for the "stalled" event for cleaner code.

  • 7847
  • * @property _AUDIO_STALLED

  • 7848
  • * @type {String}

  • 7849
  • * @default stalled

  • 7850
  • * @static

  • 7851
  • * @protected

  • 7852
  • */

  • 7853
  • s._AUDIO_STALLED = "stalled";

  • 7854  
    7855
  • /**

  • 7856
  • * Event constant for the "timeupdate" event for cleaner code. Utilized for looping audio sprites.

  • 7857
  • * This event callsback ever 15 to 250ms and can be dropped by the browser for performance.

  • 7858
  • * @property _TIME_UPDATE

  • 7859
  • * @type {String}

  • 7860
  • * @default timeupdate

  • 7861
  • * @static

  • 7862
  • * @protected

  • 7863
  • */

  • 7864
  • s._TIME_UPDATE = "timeupdate";

  • 7865  
    7866
  • /**

  • 7867
  • * The capabilities of the plugin. This is generated via the {{#crossLink "HTMLAudioPlugin/_generateCapabilities"}}{{/crossLink}}

  • 7868
  • * method. Please see the Sound {{#crossLink "Sound/getCapabilities"}}{{/crossLink}} method for an overview of all

  • 7869
  • * of the available properties.

  • 7870
  • * @property _capabilities

  • 7871
  • * @type {Object}

  • 7872
  • * @protected

  • 7873
  • * @static

  • 7874
  • */

  • 7875
  • s._capabilities = null;

  • 7876  
    7877  
    7878
  • // Static Methods

  • 7879
  • /**

  • 7880
  • * Determine if the plugin can be used in the current browser/OS. Note that HTML audio is available in most modern

  • 7881
  • * browsers, but is disabled in iOS because of its limitations.

  • 7882
  • * @method isSupported

  • 7883
  • * @return {Boolean} If the plugin can be initialized.

  • 7884
  • * @static

  • 7885
  • */

  • 7886
  • s.isSupported = function () {

  • 7887
  • s._generateCapabilities();

  • 7888
  • return (s._capabilities != null);

  • 7889
  • };

  • 7890  
    7891
  • /**

  • 7892
  • * Determine the capabilities of the plugin. Used internally. Please see the Sound API {{#crossLink "Sound/getCapabilities"}}{{/crossLink}}

  • 7893
  • * method for an overview of plugin capabilities.

  • 7894
  • * @method _generateCapabilities

  • 7895
  • * @static

  • 7896
  • * @protected

  • 7897
  • */

  • 7898
  • s._generateCapabilities = function () {

  • 7899
  • if (s._capabilities != null) {return;}

  • 7900
  • var t = document.createElement("audio");

  • 7901
  • if (t.canPlayType == null) {return null;}

  • 7902  
    7903
  • s._capabilities = {

  • 7904
  • panning:false,

  • 7905
  • volume:true,

  • 7906
  • tracks:-1

  • 7907
  • };

  • 7908  
    7909
  • // determine which extensions our browser supports for this plugin by iterating through Sound.SUPPORTED_EXTENSIONS

  • 7910
  • var supportedExtensions = createjs.Sound.SUPPORTED_EXTENSIONS;

  • 7911
  • var extensionMap = createjs.Sound.EXTENSION_MAP;

  • 7912
  • for (var i = 0, l = supportedExtensions.length; i < l; i++) {

  • 7913
  • var ext = supportedExtensions[i];

  • 7914
  • var playType = extensionMap[ext] || ext;

  • 7915
  • s._capabilities[ext] = (t.canPlayType("audio/" + ext) != "no" && t.canPlayType("audio/" + ext) != "") || (t.canPlayType("audio/" + playType) != "no" && t.canPlayType("audio/" + playType) != "");

  • 7916
  • } // OJR another way to do this might be canPlayType:"m4a", codex: mp4

  • 7917
  • };

  • 7918  
    7919  
    7920
  • // public methods

  • 7921
  • p.register = function (loadItem) {

  • 7922
  • var tag = createjs.HTMLAudioTagPool.get(loadItem.src);

  • 7923
  • var loader = this.AbstractPlugin_register(loadItem);

  • 7924
  • loader.setTag(tag);

  • 7925  
    7926
  • return loader;

  • 7927
  • };

  • 7928  
    7929
  • p.removeSound = function (src) {

  • 7930
  • this.AbstractPlugin_removeSound(src);

  • 7931
  • createjs.HTMLAudioTagPool.remove(src);

  • 7932
  • };

  • 7933  
    7934
  • p.create = function (src, startTime, duration) {

  • 7935
  • var si = this.AbstractPlugin_create(src, startTime, duration);

  • 7936
  • si.setPlaybackResource(null);

  • 7937
  • return si;

  • 7938
  • };

  • 7939  
    7940
  • p.toString = function () {

  • 7941
  • return "[HTMLAudioPlugin]";

  • 7942
  • };

  • 7943  
    7944
  • // plugin does not support these

  • 7945
  • p.setVolume = p.getVolume = p.setMute = null;

  • 7946  
    7947  
    7948
  • createjs.HTMLAudioPlugin = createjs.promote(HTMLAudioPlugin, "AbstractPlugin");

  • 7949
  • }());