1 /** 2 * The MIT License (MIT) 3 * 4 * Copyright (c) 2016 DeNA Co., Ltd. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 * SOFTWARE. 23 */ 24 25 /// <reference path="base.js"/> 26 /// <reference path="event_dispatcher.js"/> 27 /// <reference path="loader.js"/> 28 /// <reference path="user_agent.js"/> 29 /// <reference path="../externs/webaudio.js"/> 30 31 /** 32 * A class that plays sound. 33 * @extends {createjs.EventDispatcher} 34 * @constructor 35 */ 36 createjs.Sound = function() { 37 createjs.EventDispatcher.call(this); 38 39 /** 40 * The sound players. 41 * @type {Object.<string,createjs.Sound.Player>} 42 * @private 43 */ 44 this.players_ = {}; 45 }; 46 createjs.inherits('Sound', createjs.Sound, createjs.EventDispatcher); 47 48 /** 49 * The instance of the createjs.Sound object. 50 * @type {createjs.Sound} 51 * @private 52 */ 53 createjs.Sound.instance_ = null; 54 55 /** 56 * The character (or characters) that are used to split multiple paths from an 57 * audio source. 58 * @const {string} 59 */ 60 createjs.Sound.DELIMITER = '|'; 61 62 /** 63 * The interrupt value to interrupt any currently playing instance with the same 64 * source, if the maximum number of instances of the sound are already playing. 65 * @const {number} 66 */ 67 createjs.Sound.INTERRUPT_ANY = 0; // 'any' 68 69 /** 70 * The interrupt value to interrupt the earliest currently playing instance with 71 * the same source that progressed the least distance in the audio track, if the 72 * maximum number of instances of the sound are already playing. 73 * @const {number} 74 */ 75 createjs.Sound.INTERRUPT_EARLY = 1; // 'early'; 76 77 /** 78 * The interrupt value to interrupt the currently playing instance with the same 79 * source that progressed the most distance in the audio track, if the maximum 80 * number of instances of the sound are already playing. 81 * @const {number} 82 */ 83 createjs.Sound.INTERRUPT_LATE = 2; // 'late'; 84 85 /** 86 * The interrupt value to not interrupt any currently playing instances with the 87 * same source, if the maximum number of instances of the sound are already 88 * playing. 89 * @const {number} 90 */ 91 createjs.Sound.INTERRUPT_NONE = 3; // 'none'; 92 93 /** 94 * Defines the playState of an instance that is still initializing. 95 * @const {number} 96 */ 97 createjs.Sound.PLAY_INITED = 0; // 'playInited'; 98 99 /** 100 * Defines the playState of an instance that is currently playing or paused. 101 * @const {number} 102 */ 103 createjs.Sound.PLAY_SUCCEEDED = 2; // 'playSucceeded'; 104 105 /** 106 * Defines the playState of an instance that was interrupted by another instance. 107 * @const {number} 108 */ 109 createjs.Sound.PLAY_INTERRUPTED = 3; // 'playInterrupted'; 110 111 /** 112 * Defines the playState of an instance that completed playback. 113 * @const {number} 114 */ 115 createjs.Sound.PLAY_FINISHED = 4; // 'playFinished'; 116 117 /** 118 * Defines the playState of an instance that failed to play. 119 * @const {number} 120 */ 121 createjs.Sound.PLAY_FAILED = 5; // 'playFailed'; 122 123 /** 124 * Returns the global instance of the createjs.Sound object. 125 * @return {createjs.Sound} 126 */ 127 createjs.Sound.getInstance_ = function() { 128 /// <returns type="createjs.Sound"/> 129 if (!createjs.Sound.instance_) { 130 createjs.Sound.instance_ = new createjs.Sound(); 131 } 132 return createjs.Sound.instance_; 133 }; 134 135 /** 136 * The features supported by this module. 137 * @type {Object.<string,number>} 138 * @private 139 */ 140 createjs.Sound.prototype.capabilities_ = { 141 'panning': 1, 142 'volume': 1, 143 'mp3': 1, 144 'mpeg': 1, 145 'm4a': 1, 146 'mp4': 1, 147 'ogg': 0, 148 'wav': 0 149 }; 150 151 /** 152 * An inner interface that provides methods for the original SoundJS plug-ins. 153 * @interface 154 */ 155 createjs.Sound.Plugin = function() {}; 156 157 /** 158 * An inner class that emulates the original createjs.HTMLAudioPlugin class. 159 * @implements {createjs.Sound.Plugin} 160 * @constructor 161 */ 162 createjs.HTMLAudioPlugin = function() { 163 }; 164 165 // Export the createjs.HTMLAudioPlugin object to the global namespace. 166 createjs.exportObject('createjs.HTMLAudioPlugin', createjs.HTMLAudioPlugin, { 167 }, { 168 'enableIOS': true 169 }); 170 171 /** 172 * An inner class that emulates the original createjs.WebAudioPlugin class. 173 * @implements {createjs.Sound.Plugin} 174 * @constructor 175 */ 176 createjs.WebAudioPlugin = function() { 177 }; 178 179 /** 180 * Whether this plug-in is initialized. 181 * @type {boolean} 182 * @private 183 */ 184 createjs.WebAudioPlugin.initialized_ = false; 185 186 /** 187 * An HTMLAudioElement object that plays a dummy sound. 188 * @type {HTMLAudioElement} 189 * @private 190 */ 191 createjs.WebAudioPlugin.audio_ = null; 192 193 /** 194 * The AudioContext instance used by this plug-in. 195 * @type {AudioContext} 196 * @private 197 */ 198 createjs.WebAudioPlugin['context'] = null; 199 200 /** 201 * The node that plays an empty sound. 202 * @type {AudioBufferSourceNode} 203 * @private 204 */ 205 createjs.WebAudioPlugin.source_ = null; 206 207 /** 208 * The 1-sample audio buffer representing an empty sound. 209 * @type {AudioBuffer} 210 * @private 211 */ 212 createjs.WebAudioPlugin.buffer_ = null; 213 214 /** 215 * Retrieves the audio context. 216 * @return {AudioContext} context 217 * @private 218 */ 219 createjs.WebAudioPlugin.getContext_ = function() { 220 /// <returns type="AudioContext"/> 221 if (!createjs.WebAudioPlugin.initialized_) { 222 createjs.WebAudioPlugin.initialized_ = true; 223 if (createjs.AudioContext) { 224 // Attach a dummy object to the 'createjs.WebAudioPlugin.context' property 225 // when the createjs.Sound class uses FrameAudioPlayer objects (i.e. when 226 // it uses an <iframe> element to play sounds) to avoid creating an 227 // unnecessary AudioContent object. 228 if (createjs.Config.useFrame()) { 229 createjs.WebAudioPlugin['context'] = { 230 'currentTime': -1 231 }; 232 } else { 233 var context = new createjs.AudioContext(); 234 createjs.WebAudioPlugin['context'] = context; 235 } 236 } 237 } 238 return createjs.WebAudioPlugin['context']; 239 }; 240 241 /** 242 * Plays a dummy sound. This method creates an empty <audio> element and plays 243 * it. This method is a workaround for old iPhones, which need to have an 244 * <audio> element played to play sounds even with Web Audio. 245 * @private 246 */ 247 createjs.WebAudioPlugin.playDummySound_ = function() { 248 if (!createjs.WebAudioPlugin.audio_) { 249 createjs.WebAudioPlugin.audio_ = 250 /** @type {HTMLAudioElement} */ (document.createElement('audio')); 251 } 252 createjs.WebAudioPlugin.audio_.play(); 253 }; 254 255 /** 256 * Resets this plug-in to its initial state. 257 * @private 258 */ 259 createjs.WebAudioPlugin.reset_ = function() { 260 createjs.WebAudioPlugin.stopEmptySound_(); 261 createjs.WebAudioPlugin.audio_ = null; 262 createjs.WebAudioPlugin['context'] = null; 263 createjs.WebAudioPlugin.initialized_ = false; 264 }; 265 266 /** 267 * Stops playing an empty sound. This method stops playing an empty sound played 268 * by the 'createjs.WebAudioPlugin.playEmptySound()' method and destroys all its 269 * resources. 270 * @private 271 */ 272 createjs.WebAudioPlugin.stopEmptySound_ = function() { 273 var source = createjs.WebAudioPlugin.source_; 274 if (source) { 275 if (source.stop) { 276 source.stop(0); 277 } else { 278 source.noteOff(0); 279 } 280 source.disconnect(0); 281 createjs.WebAudioPlugin.source_ = null; 282 } 283 }; 284 285 /** 286 * Plays an empty sound. This method plays an empty sound both with an <audio> 287 * element and with Web Audio. (This method does not play any sounds when this 288 * module uses an <iframe> element, which automatically plays an empty sound.) 289 * @const 290 */ 291 createjs.WebAudioPlugin.playEmptySound = function() { 292 var context = createjs.WebAudioPlugin.getContext_(); 293 if (context) { 294 // Abort playing empty sounds when the createjs.Sound class uses an <iframe> 295 // element to play sounds. (The returned AudioContent object is a dummy 296 // object and cannot play sounds.) 297 if (createjs.Config.useFrame()) { 298 return; 299 } 300 // An application may call this method before this method finishes playing 301 // the previous sound. To avoid node leaks, this method stops playing the 302 // previous sound, destroys its node, and plays a new one. 303 if (createjs.WebAudioPlugin.source_) { 304 createjs.WebAudioPlugin.stopEmptySound_(); 305 } 306 var source = context.createBufferSource(); 307 createjs.WebAudioPlugin.source_ = source; 308 if (!createjs.WebAudioPlugin.buffer_) { 309 createjs.WebAudioPlugin.buffer_ = context.createBuffer(1, 1, 22500); 310 } 311 source.buffer = createjs.WebAudioPlugin.buffer_; 312 source.onended = createjs.WebAudioPlugin.stopEmptySound_; 313 if (source.start) { 314 source.start(0); 315 } else { 316 source.noteOn(0); 317 } 318 } 319 createjs.WebAudioPlugin.playDummySound_(); 320 }; 321 322 // Export the createjs.WebAudioPlugin object to the global namespace. 323 createjs.exportObject('createjs.WebAudioPlugin', createjs.WebAudioPlugin, { 324 }, { 325 'playEmptySound': createjs.WebAudioPlugin.playEmptySound 326 }); 327 328 /** 329 * The base class that plays audio. 330 * @param {createjs.Loader.Item} item 331 * @extends {createjs.EventDispatcher} 332 * @implements {createjs.Loader.Item.Listener} 333 * @constructor 334 */ 335 createjs.Sound.Player = function(item) { 336 /// <param type="cretejs.Loader.Item" name="item"/> 337 /** 338 * @type {createjs.Loader.Item} 339 * @protected 340 */ 341 this.item = item; 342 }; 343 createjs.inherits( 344 'Sound.Player', createjs.Sound.Player, createjs.EventDispatcher); 345 346 /** 347 * @enum {number} 348 * @private 349 */ 350 createjs.Sound.Player.Event = { 351 CANPLAY: 1 << 0, 352 SEEKED: 1 << 1, 353 ENDED: 1 << 2, 354 TOUCH: 1 << 3 355 }; 356 357 /** 358 * The current state of this player. 359 * @type {number} 360 */ 361 createjs.Sound.Player.prototype['playState'] = createjs.Sound.PLAY_FAILED; 362 363 /** 364 * Whether this player repeats playing a sound portion. 365 * @type {number} 366 * @protected 367 */ 368 createjs.Sound.Player.prototype.loop = 0; 369 370 /** 371 * The start position of a sound portion to be played by this player in seconds. 372 * @type {number} 373 * @protected 374 */ 375 createjs.Sound.Player.prototype.offset = 0; 376 377 /** 378 * The duration of a sound portion to be played by this player in seconds. 379 * (This value is not always equal to the duration of the sound.) 380 * @type {number} 381 * @protected 382 */ 383 createjs.Sound.Player.prototype.duration = 0; 384 385 /** 386 * The volume for this sound player. 387 * @type {number} 388 * @protected 389 */ 390 createjs.Sound.Player.prototype.volume = 1; 391 392 /** 393 * Plays audio. This method initializes internal variables and decodes audio 394 * data. Even though the createjs.Loader object preloads audio data, this player 395 * may wait until a browser finishes decoding it, i.e. this method does not 396 * always plays audio immediately. 397 * @param {number} interrupt 398 * @param {number} delay 399 * @param {number} offset 400 * @param {number} loop 401 * @param {number} volume 402 * @param {number} pan 403 * @private 404 */ 405 createjs.Sound.Player.prototype.play_ = 406 function(interrupt, delay, offset, loop, volume, pan) { 407 /// <param type="number" name="interrupt"/> 408 /// <param type="number" name="delay"/> 409 /// <param type="number" name="offset"/> 410 /// <param type="number" name="loop"/> 411 /// <param type="number" name="volume"/> 412 /// <param type="number" name="pan"/> 413 if (loop != null) { 414 this.loop = loop; 415 } 416 if (offset >= 0) { 417 this.offset = offset; 418 } 419 if (volume != null) { 420 this.volume = volume; 421 } 422 this['playState'] = createjs.Sound.PLAY_SUCCEEDED; 423 }; 424 425 /** 426 * Stops playing audio. 427 * @private 428 */ 429 createjs.Sound.Player.prototype.stop_ = function() { 430 this['playState'] = createjs.Sound.PLAY_FINISHED; 431 }; 432 433 /** 434 * Sets the mute state. 435 * @param {boolean} mute 436 * @private 437 */ 438 createjs.Sound.Player.prototype.setMute_ = function(mute) { 439 /// <param type="boolean" name="mute"/> 440 }; 441 442 /** 443 * Sets the sound volume. 444 * @param {number} volume 445 * @private 446 */ 447 createjs.Sound.Player.prototype.setVolume_ = function(volume) { 448 /// <param type="number" name="volume"/> 449 }; 450 451 /** 452 * Initializes this sound as an audio sprite. 453 * @param {string} id 454 * @param {number} offset 455 * @param {number} duration 456 * @private 457 */ 458 createjs.Sound.Player.prototype.setSprite_ = function(id, offset, duration) { 459 /// <param type="string" name="id"/> 460 /// <param type="number" name="offset"/> 461 /// <param type="number" name="duration"/> 462 }; 463 464 /** @override */ 465 createjs.Sound.Player.prototype.handleLoad = function(loader, buffer) { 466 /// <param type="createjs.Loader" name="loader"/> 467 /// <param type="ArrayBuffer" name="buffer"/> 468 return true; 469 }; 470 471 // Export the methods used by applications. 472 createjs.Sound.Player.prototype['play'] = createjs.notImplemented; 473 createjs.Sound.Player.prototype['stop'] = createjs.notImplemented; 474 createjs.Sound.Player.prototype['setMute'] = createjs.notImplemented; 475 createjs.Sound.Player.prototype['setVolume'] = createjs.notImplemented; 476 477 /** 478 * A class that implements the createjs.Sound.Player interface with the 479 * HTMLAudioElement interface. 480 * @param {createjs.Loader.Item} item 481 * @extends {createjs.Sound.Player} 482 * @implements {EventListener} 483 * @constructor 484 */ 485 createjs.Sound.HTMLAudioPlayer = function(item) { 486 /// <param type="cretejs.Loader.Item" name="item"/> 487 createjs.Sound.Player.call(this, item); 488 }; 489 createjs.inherits('Sound.HTMLAudioPlayer', 490 createjs.Sound.HTMLAudioPlayer, 491 createjs.Sound.Player); 492 493 /** 494 * @type {number} 495 * @private 496 */ 497 createjs.Sound.HTMLAudioPlayer.prototype.mask_ = 0; 498 499 /** 500 * @type {boolean} 501 * @private 502 */ 503 createjs.Sound.HTMLAudioPlayer.prototype.paused_ = true; 504 505 /** 506 * The timer ID. This value tells this player has already set a timer. 507 * @type {number} 508 * @private 509 */ 510 createjs.Sound.HTMLAudioPlayer.prototype.timer_ = 0; 511 512 /** 513 * Starts listening an event from the specified HTMLAudioElement object. 514 * @param {EventTarget} audio 515 * @param {string} type 516 * @param {number} id 517 * @private 518 */ 519 createjs.Sound.HTMLAudioPlayer.prototype.listen_ = function(audio, type, id) { 520 /// <param type="EventTarget" name="audio"/> 521 /// <param type="string" name="type"/> 522 /// <param type="number" name="id"/> 523 if (!(this.mask_ & id)) { 524 audio.addEventListener(type, this, false); 525 this.mask_ |= id; 526 } 527 }; 528 529 /** 530 * Stops listening an event from the specified HTMLAudioElement object. 531 * @param {EventTarget} audio 532 * @param {string} type 533 * @param {number} id 534 * @private 535 */ 536 createjs.Sound.HTMLAudioPlayer.prototype.unlisten_ = function(audio, type, id) { 537 /// <param type="EventTarget" name="audio"/> 538 /// <param type="string" name="type"/> 539 /// <param type="number" name="id"/> 540 audio.removeEventListener(type, this, false); 541 this.mask_ &= ~id; 542 }; 543 544 /** 545 * Called when the hosting browser finishes playing this sound. 546 * @private 547 */ 548 createjs.Sound.HTMLAudioPlayer.prototype.handleEnded_ = function() { 549 this.timer_ = 0; 550 this.stop_(); 551 this.dispatchNotification('complete'); 552 }; 553 554 /** 555 * Starts playing audio. 556 * @private 557 */ 558 createjs.Sound.HTMLAudioPlayer.prototype.start_ = function() { 559 createjs.assert(!!this.item); 560 if (!this.paused_) { 561 return; 562 } 563 createjs.log('HTMLAudio: play ' + this.item.id); 564 var audio = /** @type {HTMLAudioElement} */ (this.item.resultObject); 565 // Some Android 4.4 WebViews (e.g. Softbank 302SH) stops playing a sound 566 // without dispatching an 'ended' event when the 'loop' property is true. To 567 // repeat a sound on such devices, this method always set false to the 'loop' 568 // property to false and re-start playing when this player receives an 'ended' 569 // event. 570 if (createjs.FALSE) { 571 audio.loop = !!this.loop; 572 } 573 // Set a timer to stop this sound when it expires. (The HTMLAudioElement 574 // class cannot change its duration and this player has to use a timer to 575 // stop it manually.) 576 if (!this.loop && this.duration) { 577 if (this.offset) { 578 audio.currentTime = this.offset; 579 } 580 if (this.timer_) { 581 clearTimeout(this.timer_); 582 } 583 this.timer_ = setTimeout(this.handleEnded_.bind(this), this.duration); 584 } 585 }; 586 587 /** 588 * Adds the specified HTMLAudioElement object to the DOM tree. 589 * @param {HTMLAudioElement} audio 590 * @private 591 */ 592 createjs.Sound.HTMLAudioPlayer.prototype.appendChild_ = function(audio) { 593 /// <param type="HTMLAudioElement" name="audio"/> 594 if (!audio.parentNode) { 595 document.body.appendChild(audio); 596 } 597 }; 598 599 /** @override */ 600 createjs.Sound.HTMLAudioPlayer.prototype.play_ = 601 function(interrupt, delay, offset, loop, volume, pan) { 602 /// <param type="number" name="interrupt"/> 603 /// <param type="number" name="delay"/> 604 /// <param type="number" name="offset"/> 605 /// <param type="number" name="loop"/> 606 /// <param type="number" name="volume"/> 607 /// <param type="number" name="pan"/> 608 if (!this.paused_) { 609 return; 610 } 611 createjs.Sound.HTMLAudioPlayer.superClass_.play_.call( 612 this, interrupt, delay, offset, loop, volume, pan); 613 var audio = /** @type {HTMLAudioElement} */ (this.item.resultObject); 614 createjs.assert(!!audio); 615 this.appendChild_(audio); 616 // Wait until the specified audio becomes ready to play when it is not. 617 // Otherwise, play the audio now. 618 var HAVE_NOTHING = 0; 619 var HAVE_METADATA = 1; 620 var HAVE_CURRENT_DATA = 2; 621 var HAVE_FUTURE_DATA = 3; 622 var HAVE_ENOUGH_DATA = 4; 623 if (audio.readyState != HAVE_ENOUGH_DATA) { 624 createjs.log('HTMLAudio: load ' + this.item.id); 625 this.listen_(audio, 'canplay', createjs.Sound.Player.Event.CANPLAY); 626 audio.preload = 'auto'; 627 audio.load(); 628 } else { 629 this.start_(); 630 } 631 }; 632 633 /** @override */ 634 createjs.Sound.HTMLAudioPlayer.prototype.stop_ = function() { 635 createjs.assert(!!this.item); 636 createjs.log('HTMLAudio: stop ' + this.item.id); 637 var audio = /** @type {HTMLAudioElement} */ (this.item.resultObject); 638 audio.pause(); 639 var parent = audio.parentNode; 640 if (parent) { 641 parent.removeChild(audio); 642 } 643 this.unlisten_(audio, 'canplay', createjs.Sound.Player.Event.CANPLAY); 644 this.unlisten_(audio, 'ended', createjs.Sound.Player.Event.ENDED); 645 this.unlisten_(window, 'touchstart', createjs.Sound.Player.Event.TOUCH); 646 this.paused_ = true; 647 createjs.Sound.HTMLAudioPlayer.superClass_.stop_.call(this); 648 }; 649 650 /** @override */ 651 createjs.Sound.HTMLAudioPlayer.prototype.setMute_ = function(mute) { 652 /// <param type="boolean" name="mute"/> 653 if (this.item) { 654 var audio = /** @type {HTMLAudioElement} */ (this.item.resultObject); 655 audio.mute = mute; 656 } 657 }; 658 659 /** @override */ 660 createjs.Sound.HTMLAudioPlayer.prototype.setVolume_ = function(volume) { 661 /// <param type="number" name="volume"/> 662 if (this.item && this.volume != volume) { 663 this.volume = volume; 664 var audio = /** @type {HTMLAudioElement} */ (this.item.resultObject); 665 audio.volume = volume; 666 } 667 }; 668 669 /** @override */ 670 createjs.Sound.HTMLAudioPlayer.prototype.setSprite_ = 671 function(id, offset, duration) { 672 /// <param type="string" name="id"/> 673 /// <param type="number" name="offset"/> 674 /// <param type="number" name="duration"/> 675 // This player uses the specified offset to set the 'currentTime' property 676 // and the specified duration to call a 'setTimeout()' function, i.e. the 677 // offset should be in seconds and the duration should be in milliseconds. 678 this.offset = offset * 0.001; 679 this.duration = duration; 680 }; 681 682 /** @override */ 683 createjs.Sound.HTMLAudioPlayer.prototype.handleEvent = function(event) { 684 /// <param type="Event" name="event"/> 685 var type = event.type; 686 var audio = event.target; 687 createjs.log('HTMLAudio: event ' + this.item.id + ',' + type); 688 if (type == 'canplay') { 689 this.unlisten_(audio, type, createjs.Sound.Player.Event.CANPLAY); 690 this.start_(); 691 } else if (type == 'ended') { 692 if (this.loop) { 693 audio.play(); 694 } else { 695 this.stop_(); 696 } 697 } else if (type == 'touchstart') { 698 this.unlisten_(window, type, createjs.Sound.Player.Event.TOUCH); 699 this.start_(); 700 } 701 }; 702 703 // Export overridden methods. 704 createjs.Sound.HTMLAudioPlayer.prototype['play'] = 705 createjs.Sound.HTMLAudioPlayer.prototype.play_; 706 createjs.Sound.HTMLAudioPlayer.prototype['stop'] = 707 createjs.Sound.HTMLAudioPlayer.prototype.stop_; 708 createjs.Sound.HTMLAudioPlayer.prototype['setMute'] = 709 createjs.Sound.HTMLAudioPlayer.prototype.setMute_; 710 createjs.Sound.HTMLAudioPlayer.prototype['setVolume'] = 711 createjs.Sound.HTMLAudioPlayer.prototype.setVolume_; 712 713 /** 714 * A class that implements the createjs.Sound.Player interface with the WebAudio 715 * API without using HTMLAudioElement objects. This player needs to decode ALL 716 * audio data before playing it and it takes more memory than other players. 717 * @param {createjs.Loader.Item} item 718 * @extends {createjs.Sound.Player} 719 * @constructor 720 */ 721 createjs.Sound.BufferAudioPlayer = function(item) { 722 /// <param type="cretejs.Loader.Item" name="item"/> 723 createjs.Sound.Player.call(this, item); 724 }; 725 createjs.inherits('Sound.BufferAudioPlayer', 726 createjs.Sound.BufferAudioPlayer, 727 createjs.Sound.Player); 728 729 /** 730 * The source node that plays audio with this player. 731 * @type {AudioBufferSourceNode} 732 * @private 733 */ 734 createjs.Sound.BufferAudioPlayer.prototype.source_ = null; 735 736 /** 737 * The gain node that changes the volume of this player. 738 * @type {GainNode} 739 * @private 740 */ 741 createjs.Sound.BufferAudioPlayer.prototype.gain_ = null; 742 743 /** 744 * The createjs.Loader object that waits for this object to decode data. 745 * @type {createjs.Loader} 746 * @private 747 */ 748 createjs.Sound.BufferAudioPlayer.prototype.loader_ = null; 749 750 /** 751 * @type {number} 752 * @private 753 */ 754 createjs.Sound.BufferAudioPlayer.prototype.auto_ = 0; 755 756 /** 757 * Called when the hosting browser finishes playing this sound. 758 * @private 759 */ 760 createjs.Sound.BufferAudioPlayer.prototype.handleEnded_ = function() { 761 this.stop_(); 762 this.dispatchNotification('complete'); 763 }; 764 765 /** 766 * Plays decoded audio. 767 * @param {AudioBuffer} buffer 768 * @private 769 */ 770 createjs.Sound.BufferAudioPlayer.prototype.playAudioBuffer_ = function(buffer) { 771 /// <param type="AudioBuffer" name="buffer"/> 772 // Add the following audio graph to the destination node. (This class 773 // multiplies the master volume to the audio volume to connect the gain node 774 // directly to the destination.) 775 // +---------------+ +------+ +-------------+ 776 // | buffer source |-->| gain |-->| destination | 777 // +---------------+ +------+ +-------------+ 778 createjs.log('WebAudio: play ' + this.item.id); 779 var context = createjs.WebAudioPlugin.getContext_(); 780 var gain = 781 context.createGain ? context.createGain() : context.createGainNode(); 782 gain.connect(context.destination); 783 gain.gain.value = this.volume; 784 this.gain_ = gain; 785 786 var source = context.createBufferSource(); 787 source.connect(gain); 788 source.buffer = buffer; 789 if (this.loop) { 790 source.loop = true; 791 if (source.start) { 792 source.start(0); 793 } else { 794 source.noteOn(0); 795 } 796 } else { 797 source.onended = this.handleEnded_.bind(this); 798 if (source.start) { 799 source.start(0, this.offset, this.duration); 800 } else { 801 source.noteGrainOn(0, this.offset, this.duration); 802 } 803 } 804 this.source_ = source; 805 }; 806 807 /** 808 * Called when the AudioContext class finishes decoding sound data. 809 * @param {AudioBuffer} buffer 810 * @private 811 */ 812 createjs.Sound.BufferAudioPlayer.prototype.handleDecode_ = function(buffer) { 813 /// <param type="AudioBuffer" name="buffer"/> 814 this.duration = buffer.duration; 815 this.item.resultObject = buffer; 816 if (this.loader_) { 817 this.loader_.sendFileComplete(!buffer, buffer); 818 this.loader_ = null; 819 } 820 if (this.auto_) { 821 this.playAudioBuffer_(buffer); 822 this.auto_ = 0; 823 } 824 }; 825 826 /** @override */ 827 createjs.Sound.BufferAudioPlayer.prototype.play_ = 828 function(interrupt, delay, offset, loop, volume, pan) { 829 /// <param type="number" name="interrupt"/> 830 /// <param type="number" name="delay"/> 831 /// <param type="number" name="offset"/> 832 /// <param type="number" name="loop"/> 833 /// <param type="number" name="volume"/> 834 /// <param type="number" name="pan"/> 835 createjs.Sound.BufferAudioPlayer.superClass_.play_.call( 836 this, interrupt, delay, offset, loop, volume, pan); 837 if (!this.item.resultObject) { 838 // A browser does not finish decoding this sound. Play this sound when a 839 // browser finishes decoding it. 840 this.auto_ = 1; 841 return; 842 } 843 if (this.source_) { 844 this.stop_(); 845 } 846 createjs.WebAudioPlugin.playDummySound_(); 847 this.playAudioBuffer_(/** @type {AudioBuffer} */ (this.item.resultObject)); 848 }; 849 850 /** @override */ 851 createjs.Sound.BufferAudioPlayer.prototype.stop_ = function() { 852 createjs.Sound.BufferAudioPlayer.superClass_.stop_.call(this); 853 this.auto_ = 0; 854 var source = this.source_; 855 if (source) { 856 createjs.log('WebAudio: stop ' + this.item.id); 857 // Read the 'playbackState' property if this AudioBufferSourceNode has it 858 // and check if its value is 3 (FINISHED_STATE). This code is a workaround 859 // for "InvalidStateError" exceptions on older browsers (e.g. SC-02F) whose 860 // AudioBufferSourceNode interface does not have the onended property. 861 var playbackState = source.playbackState || 0; 862 if (playbackState != 3) { 863 if (source.stop) { 864 source.stop(0); 865 } else { 866 source.noteOff(0); 867 } 868 } 869 source.disconnect(0); 870 source.onended = null; 871 // When an AudioBufferSouceNode object is disconnected from a destination 872 // node, Mobile Safari does not delete its AudioBuffer object. Attach a 873 // 1-sample AudioBuffer object to the AudioBufferSourceNode object to delete 874 // the AudioBuffer object on the browser. (This code throws an exception on 875 // Chrome and Firefox, i.e. this code must be executed only on Mobile 876 // Safari.) 877 if (createjs.UserAgent.isIPhone()) { 878 if (!createjs.WebAudioPlugin.buffer_) { 879 var context = createjs.WebAudioPlugin.getContext_(); 880 createjs.WebAudioPlugin.buffer_ = context.createBuffer(1, 1, 22500); 881 } 882 this.source_.buffer = createjs.WebAudioPlugin.buffer_; 883 } 884 this.source_ = null; 885 this.gain_.disconnect(0); 886 this.gain_ = null; 887 } 888 }; 889 890 /** @override */ 891 createjs.Sound.BufferAudioPlayer.prototype.setMute_ = function(mute) { 892 /// <param type="boolean" name="mute"/> 893 if (this.gain_) { 894 if (mute) { 895 this.gain_.gain.value = 0; 896 } else { 897 this.gain_.gain.value = this.volume; 898 } 899 } 900 }; 901 902 /** @override */ 903 createjs.Sound.BufferAudioPlayer.prototype.setVolume_ = function(volume) { 904 /// <param type="number" name="volume"/> 905 if (this.volume != volume) { 906 this.volume = volume; 907 if (this.gain_) { 908 this.gain_.gain.value = volume; 909 } 910 } 911 }; 912 913 /** @override */ 914 createjs.Sound.BufferAudioPlayer.prototype.setSprite_ = 915 function(id, offset, duration) { 916 /// <param type="string" name="id"/> 917 /// <param type="number" name="offset"/> 918 /// <param type="number" name="duration"/> 919 this.offset = offset * 0.001; 920 this.duration = duration * 0.001; 921 }; 922 923 /** @override */ 924 createjs.Sound.BufferAudioPlayer.prototype.handleLoad = 925 function(loader, buffer) { 926 /// <param type="createjs.Loader" name="loader"/> 927 /// <param type="ArrayBuffer" name="buffer"/> 928 if (buffer) { 929 var context = createjs.WebAudioPlugin.getContext_(); 930 var handleDecode = 931 createjs.Sound.BufferAudioPlayer.prototype.handleDecode_.bind(this); 932 context.decodeAudioData( 933 buffer, handleDecode, /** @type {function()} */ (handleDecode)); 934 if (this.item.isSynchronous()) { 935 this.loader_ = loader; 936 return false; 937 } 938 } 939 return true; 940 }; 941 942 // Export overridden methods. 943 createjs.Sound.BufferAudioPlayer.prototype['play'] = 944 createjs.Sound.BufferAudioPlayer.prototype.play_; 945 createjs.Sound.BufferAudioPlayer.prototype['stop'] = 946 createjs.Sound.BufferAudioPlayer.prototype.stop_; 947 createjs.Sound.BufferAudioPlayer.prototype['setMute'] = 948 createjs.Sound.BufferAudioPlayer.prototype.setMute_; 949 createjs.Sound.BufferAudioPlayer.prototype['setVolume'] = 950 createjs.Sound.BufferAudioPlayer.prototype.setVolume_; 951 952 /** 953 * A class that implements the createjs.Sound.Player interface with the 954 * WebAudio API and plays sounds on an <iframe> element. 955 * @param {createjs.Loader.Item} item 956 * @extends {createjs.Sound.Player} 957 * @constructor 958 */ 959 createjs.Sound.FrameAudioPlayer = function(item) { 960 /// <param type="cretejs.Loader.Item" name="item"/> 961 createjs.Sound.Player.call(this, item); 962 963 /** 964 * The ID assigned to a sound file or an audio sprite. 965 * @type {string} 966 * @private 967 */ 968 this.id_ = item.id; 969 }; 970 createjs.inherits('Sound.FrameAudioPlayer', 971 createjs.Sound.FrameAudioPlayer, 972 createjs.Sound.Player); 973 974 /** 975 * An inner class that encapsulates an <iframe> element. 976 * @implements {EventListener} 977 * @constructor 978 */ 979 createjs.Sound.FrameAudioPlayer.Frame = function() { 980 var frame = 981 /** @type {HTMLIFrameElement} */ (document.createElement('iframe')); 982 frame.id = 'cjs-iframe'; 983 var style = frame.style; 984 style.zIndex = 200000; 985 style.position = 'absolute'; 986 style.border = '0px'; 987 style.top = '0px'; 988 style.left = '0px'; 989 var parent = document.body; 990 var rectangle = parent.getBoundingClientRect(); 991 style.width = rectangle.width + 'px'; 992 style.height = rectangle.height + 'px'; 993 window.addEventListener('message', this, false); 994 if (createjs.DEBUG) { 995 frame.src = 996 createjs.Sound.FrameAudioPlayer.Frame.HEADER_ + 997 createjs.Sound.FrameAudioPlayer.Frame.SOURCE_DEBUG_ + 998 createjs.Sound.FrameAudioPlayer.Frame.FOOTER_; 999 } else { 1000 frame.src = 1001 createjs.Sound.FrameAudioPlayer.Frame.HEADER_ + 1002 createjs.Sound.FrameAudioPlayer.Frame.SOURCE_MIN_ + 1003 createjs.Sound.FrameAudioPlayer.Frame.FOOTER_; 1004 } 1005 parent.appendChild(frame); 1006 1007 /** 1008 * The <iframe> element that actually plays sounds. 1009 * @type {HTMLIFrameElement} 1010 * @private 1011 */ 1012 this.frame_ = frame; 1013 1014 /** 1015 * The messages queued to this frame. An <iframe> element drops messages until 1016 * it finishes loading a page, i.e. this frame cannot send messages until it 1017 * receives an INITIALIZE command. This array temporarily saves messages until 1018 * the <iframe> element becomes ready to receive them. 1019 * @type {Array.<Object>} 1020 * @private 1021 */ 1022 this.messages_ = []; 1023 1024 /** 1025 * The mapping table from a resource ID to a FrameAudioPlayer object. This 1026 * table is used for dispatching messages received from the <iframe> element 1027 * to FrameAudioPlayer objects. 1028 * @type {Object.<string,createjs.Sound.FrameAudioPlayer>} 1029 * @private 1030 */ 1031 this.players_ = {}; 1032 }; 1033 1034 /** 1035 * @const {string} 1036 * @private 1037 */ 1038 createjs.Sound.FrameAudioPlayer.Frame.HEADER_ = 1039 'data:text/html,' + 1040 '<html style="-webkit-user-select:none;">' + 1041 '<head>' + 1042 '<script type="text/javascript">'; 1043 1044 /** 1045 * @const {string} 1046 * @private 1047 */ 1048 createjs.Sound.FrameAudioPlayer.Frame.FOOTER_ = 1049 '</script>' + 1050 '</head>' + 1051 '<body>' + 1052 '</body>' + 1053 '</html>'; 1054 1055 /** 1056 * The optimized source code of this <iframe> element. 1057 * @const {string} 1058 * @private 1059 */ 1060 createjs.Sound.FrameAudioPlayer.Frame.SOURCE_MIN_ = 1061 'var e,f=window,g=f.webkitAudioContext||f.AudioContext,h=null,k=null,l=' + 1062 '!1;function m(){this.f={}}var n=1;function p(a,b){this.f=a;this.o=b}va' + 1063 'r q=MouseEvent.WEBKIT_FORCE_AT_MOUSE_DOWN?"touchend":"touchstart";e=p.' + 1064 'prototype;e.k=1;e.l=-1;e.n=0;e.i=0;e.p=0;e.h=null;e.g=null;e.m=null;e.' + 1065 'j=null;e.q=function(a){this.g=a;this.o.postMessage({a:6,b:this.f},"*")' + 1066 ';this.i&&(r(this,this.p,this.k),this.i=0);if(this.h){for(var b=0;b<thi' + 1067 's.h.length;++b){var c=this.h[b];c.g=a;c.i&&(r(c,c.p,c.k),c.i=0)}this.h' + 1068 '=null}};e.r=function(){s(this);this.o.postMessage({a:7,b:this.f},"*")}' + 1069 ';function r(a,b,c){if(a.g){a.m&&s(a);a.k=c;var d=h;c=d.createGain?d.cr' + 1070 'eateGain():d.createGainNode();c.connect(d.destination);c.gain.value=a.' + 1071 'k;a.j=c;d=d.createBufferSource();d.connect(c);d.buffer=a.g;b?d.loop=!0' + 1072 ':d.onended=a.r.bind(a);0<=a.l?d.start?d.start(0,a.l,a.n):d.noteGrainOn' + 1073 '(0,a.l,a.n):d.start?d.start(0):d.noteOn(0);a.m=d}else a.i=1,a.p=b,a.k=' + 1074 'c}function s(a){var b=a.m;b&&(3!=(b.playbackState||0)&&(b.stop?b.stop(' + 1075 '0):b.noteOff(0)),b.disconnect(0),b.onended=null,l&&k&&(b.buffer=k),a.m' + 1076 '=null,a.j.disconnect(0),a.j=null)}function t(){h.currentTime||!n?f.par' + 1077 'ent.postMessage({a:5},"*"):(--n,f.addEventListener(q,u,!1))}function v' + 1078 '(){var a=h.createBufferSource();a.buffer=k;a.start?a.start(0):a.noteOn' + 1079 '(0);setTimeout(t,100)}m.prototype.handleEvent=function(a){var b=a.type' + 1080 ';if("message"==b){var b=a.data,c=b.a,d=b.b;if(0==c)this.f[d]||(a=new p' + 1081 '(d,a.source),this.f[d]=a,a=a.q.bind(a),h.decodeAudioData(b.c,a,a));els' + 1082 'e if(a=this.f[d])1==c?r(a,b.c,b.d):2==c?s(a):3==c?(b=b.c,a.j&&(a.j.gai' + 1083 'n.value=b)):8==c&&(c=new p(a.f,a.o),c.f=b.c,c.g=a.g,c.l=b.d,c.n=b.e,th' + 1084 'is.f[b.c]=c,a.g||(a.h||(a.h=[]),a.h.push(c)))}else f.removeEventListen' + 1085 'er(b,this,!1),v()};var u=null;f.onload=function(){h=new g;u=new m;k=h.' + 1086 'createBuffer(1,1,22500);var a=navigator.platform;l="iPhone"==a||"iPad"' + 1087 '==a;v();f.addEventListener("message",u,!1);f.parent.postMessage({a:4},' + 1088 '"*")};'; 1089 1090 /** 1091 * The source code of this <iframe> element used for debug. 1092 * @const {string} 1093 * @private 1094 */ 1095 createjs.Sound.FrameAudioPlayer.Frame.SOURCE_DEBUG_ = 1096 'var e,f=window,g=f.webkitAudioContext||f.AudioContext;function h(a){co' + 1097 'nsole.debug(a)}var k=null,l=null,m=!1;function n(){this.f={}}var p=1;f' + 1098 'unction q(a,b){this.f=a;this.o=b}var r=MouseEvent.WEBKIT_FORCE_AT_MOUS' + 1099 'E_DOWN?"touchend":"touchstart";e=q.prototype;e.k=1;e.l=-1;e.n=0;e.i=0;' + 1100 'e.p=0;e.h=null;e.g=null;e.m=null;e.j=null;e.q=function(a){h("decode="+' + 1101 'this.f);this.g=a;this.o.postMessage({a:6,b:this.f},"*");this.i&&(s(thi' + 1102 's,this.p,this.k),this.i=0);if(this.h){for(var b=0;b<this.h.length;++b)' + 1103 '{var c=this.h[b];c.g=a;c.i&&(s(c,c.p,c.k),c.i=0)}this.h=null}};e.r=fun' + 1104 'ction(){h("ended="+this.f);t(this);this.o.postMessage({a:7,b:this.f},"' + 1105 '*")};function s(a,b,c){h("play="+a.f+","+b+","+c);if(a.g){a.m&&t(a);a.' + 1106 'k=c;var d=k;c=d.createGain?d.createGain():d.createGainNode();c.connect' + 1107 '(d.destination);c.gain.value=a.k;a.j=c;d=d.createBufferSource();d.conn' + 1108 'ect(c);d.buffer=a.g;b?d.loop=!0:d.onended=a.r.bind(a);0<=a.l?d.start?d' + 1109 '.start(0,a.l,a.n):d.noteGrainOn(0,a.l,a.n):d.start?d.start(0):d.noteOn' + 1110 '(0);a.m=d}else a.i=1,a.p=b,a.k=c}function t(a){h("stop="+a.f);var b=a.' + 1111 'm;b&&(3!=(b.playbackState||0)&&(b.stop?b.stop(0):b.noteOff(0)),b.disco' + 1112 'nnect(0),b.onended=null,m&&l&&(b.buffer=l),a.m=null,a.j.disconnect(0),' + 1113 'a.j=null)}function u(){h("> currentTime="+k.currentTime);k.currentTime' + 1114 '||!p?f.parent.postMessage({a:5},"*"):(--p,f.addEventListener(r,v,!1))}' + 1115 'function w(){var a=k.createBufferSource();a.buffer=l;a.start?a.start(0' + 1116 '):a.noteOn(0);setTimeout(u,100)}n.prototype.handleEvent=function(a){va' + 1117 'r b=a.type;if("message"==b){var b=a.data,c=b.a,d=b.b;if(0==c)h("load="' + 1118 '+d),this.f[d]||(a=new q(d,a.source),this.f[d]=a,a=a.q.bind(a),k.decode' + 1119 'AudioData(b.c,a,a));else if(a=this.f[d])1==c?s(a,b.c,b.d):2==c?t(a):3=' + 1120 '=c?(b=b.c,h("volume="+a.f+","+b),a.j&&(a.j.gain.value=b)):8==c&&(h("cl' + 1121 'one="+b.c+","+b.d+","+b.e),c=new q(a.f,a.o),c.f=b.c,c.g=a.g,c.l=b.d,c.' + 1122 'n=b.e,this.f[b.c]=c,a.g||(a.h||(a.h=[]),a.h.push(c)))}else h("> type="' + 1123 '+b),f.removeEventListener(b,this,!1),w()};var v=null;f.onload=function' + 1124 '(){k=new g;v=new n;l=k.createBuffer(1,1,22500);var a=navigator.platfor' + 1125 'm;m="iPhone"==a||"iPad"==a;w();f.addEventListener("message",v,!1);f.pa' + 1126 'rent.postMessage({a:4},"*")};'; 1127 1128 /** 1129 * Loads the specified sound and decodes it. 1130 * @param {string} id 1131 * @param {ArrayBuffer} buffer 1132 * @const 1133 */ 1134 createjs.Sound.FrameAudioPlayer.Frame.prototype.load_ = function(id, buffer) { 1135 /// <param type="string" name="id"/> 1136 /// <param type="ArrayBuffer" name="buffer"/> 1137 var window = this.frame_.contentWindow; 1138 if (window) { 1139 window.postMessage({ 1140 'a': createjs.FrameCommand.LOAD, 1141 'b': id, 1142 'c': buffer 1143 }, '*'); 1144 } 1145 }; 1146 1147 /** 1148 * Starts loading the specified sound. 1149 * @param {string} id 1150 * @param {ArrayBuffer} buffer 1151 * @param {createjs.Sound.FrameAudioPlayer} player 1152 * @return {boolean} 1153 * @const 1154 */ 1155 createjs.Sound.FrameAudioPlayer.Frame.prototype.load = 1156 function(id, buffer, player) { 1157 /// <param type="string" name="id"/> 1158 /// <param type="ArrayBuffer" name="buffer"/> 1159 /// <param type="createjs.Sound.FrameAudioPlayer" name="player"/> 1160 /// <returns type="boolean"/> 1161 if (this.players_[id]) { 1162 return true; 1163 } 1164 this.players_[id] = player; 1165 var message = { 1166 'a': createjs.FrameCommand.LOAD, 1167 'b': id, 1168 'c': buffer 1169 }; 1170 if (this.messages_) { 1171 this.messages_.push(message); 1172 } else { 1173 var window = this.frame_.contentWindow; 1174 if (window) { 1175 window.postMessage(message, '*'); 1176 } 1177 } 1178 return false; 1179 }; 1180 1181 /** 1182 * Starts playing the specified sound. 1183 * @param {string} id 1184 * @param {number} loop 1185 * @param {number} volume 1186 * @const 1187 */ 1188 createjs.Sound.FrameAudioPlayer.Frame.prototype.play = 1189 function(id, loop, volume) { 1190 /// <param type="string" name="id"/> 1191 /// <param type="number" name="loop"/> 1192 var window = this.frame_.contentWindow; 1193 if (window) { 1194 window.postMessage({ 1195 'a': createjs.FrameCommand.PLAY, 1196 'b': id, 1197 'c': loop, 1198 'd': volume 1199 }, '*'); 1200 } 1201 }; 1202 1203 /** 1204 * Stops playing the specified sound. 1205 * @param {string} id 1206 * @const 1207 */ 1208 createjs.Sound.FrameAudioPlayer.Frame.prototype.stop = function(id) { 1209 /// <param type="string" name="id"/> 1210 var window = this.frame_.contentWindow; 1211 if (window) { 1212 window.postMessage({ 1213 'a': createjs.FrameCommand.STOP, 1214 'b': id 1215 }, '*'); 1216 } 1217 }; 1218 1219 /** 1220 * Changes the volume of the specified sound. 1221 * @param {string} id 1222 * @param {number} volume 1223 * @const 1224 */ 1225 createjs.Sound.FrameAudioPlayer.Frame.prototype.setVolume = 1226 function(id, volume) { 1227 /// <param type="string" name="id"/> 1228 /// <param type="number" name="volume"/> 1229 var window = this.frame_.contentWindow; 1230 if (window) { 1231 window.postMessage({ 1232 'a': createjs.FrameCommand.SET_VOLUME, 1233 'b': id, 1234 'c': volume 1235 }, '*'); 1236 } 1237 }; 1238 1239 /** 1240 * Creates a clone of the specified sound. 1241 * @param {string} id 1242 * @param {string} clone 1243 * @param {number} offset 1244 * @param {number} duration 1245 * @param {createjs.Sound.FrameAudioPlayer} player 1246 * @const 1247 */ 1248 createjs.Sound.FrameAudioPlayer.Frame.prototype.clone = 1249 function(id, clone, offset, duration, player) { 1250 /// <param type="string" name="id"/> 1251 /// <param type="string" name="clone"/> 1252 /// <param type="number" name="offset"/> 1253 /// <param type="number" name="duration"/> 1254 /// <param type="createjs.Sound.FrameAudioPlayer" name="player"/> 1255 var window = this.frame_.contentWindow; 1256 if (window) { 1257 var message = { 1258 'a': createjs.FrameCommand.CLONE, 1259 'b': id, 1260 'c': clone, 1261 'd': offset, 1262 'e': duration 1263 }; 1264 if (this.messages_) { 1265 this.messages_.push(message); 1266 } else { 1267 window.postMessage(message, '*'); 1268 } 1269 this.players_[clone] = player; 1270 } 1271 }; 1272 1273 /** 1274 * Destroys this player. This player destroys the <iframe> element to delete 1275 * all its resources, e.g. AudioBuffers, BufferSourceNodes, etc. 1276 * @const 1277 */ 1278 createjs.Sound.FrameAudioPlayer.Frame.prototype.destroy = function() { 1279 window.removeEventListener('message', this, false); 1280 document.body.removeChild(this.frame_); 1281 this.frame_ = null; 1282 }; 1283 1284 /** @override */ 1285 createjs.Sound.FrameAudioPlayer.Frame.prototype.handleEvent = function(event) { 1286 /// <param type="MessageEvent" name="event"/> 1287 var data = /** @type {Object} */ (/** @type{*} */ (event.data)); 1288 var command = /** @type {number} */ (data['a']); 1289 if (command == createjs.FrameCommand.INITIALIZE) { 1290 if (this.messages_) { 1291 var window = this.frame_.contentWindow; 1292 if (window) { 1293 for (var i = 0; i < this.messages_.length; ++i) { 1294 window.postMessage(this.messages_[i], '*'); 1295 } 1296 } 1297 this.messages_ = null; 1298 } 1299 return; 1300 } 1301 if (command == createjs.FrameCommand.TOUCH) { 1302 var style = this.frame_.style; 1303 style.zIndex = -1; 1304 return; 1305 } 1306 var id = /** @type {string} */ (data['b']); 1307 var player = this.players_[id]; 1308 if (!player) { 1309 return; 1310 } 1311 if (command == createjs.FrameCommand.DECODE) { 1312 player.handleDecode(); 1313 } else if (command == createjs.FrameCommand.END) { 1314 player.handleEnd(); 1315 } 1316 }; 1317 1318 /** 1319 * The player that actually plays sounds in an <iframe> element. 1320 * @type {createjs.Sound.FrameAudioPlayer.Frame} 1321 * @private 1322 */ 1323 createjs.Sound.FrameAudioPlayer.frame_ = null; 1324 1325 /** 1326 * Whether this player is in the mute state. 1327 * @type {boolean} 1328 * @private 1329 */ 1330 createjs.Sound.FrameAudioPlayer.prototype.mute_ = false; 1331 1332 /** 1333 * The createjs.Loader object that loads the sound associated with this 1334 * player. 1335 * @type {createjs.Loader} 1336 * @private 1337 */ 1338 createjs.Sound.FrameAudioPlayer.prototype.loader_ = null; 1339 1340 /** 1341 * The ID assigned to an audio sprite. 1342 * @type {string} 1343 * @private 1344 */ 1345 createjs.Sound.FrameAudioPlayer.prototype.id_ = ''; 1346 1347 /** 1348 * Retrieves the global FrameAudioPlayer object. 1349 * @private 1350 */ 1351 createjs.Sound.FrameAudioPlayer.getFrame_ = function() { 1352 /// <returns type="createjs.Sound.FrameAudioPlayer.Frame"/> 1353 if (!createjs.Sound.FrameAudioPlayer.frame_) { 1354 createjs.Sound.FrameAudioPlayer.frame_ = 1355 new createjs.Sound.FrameAudioPlayer.Frame(); 1356 } 1357 return createjs.Sound.FrameAudioPlayer.frame_; 1358 }; 1359 1360 /** 1361 * Destroys the global resources used by FrameAudioPlayer objects. 1362 * @private 1363 */ 1364 createjs.Sound.FrameAudioPlayer.destroy_ = function() { 1365 var frame = createjs.Sound.FrameAudioPlayer.frame_; 1366 if (frame) { 1367 frame.destroy(); 1368 createjs.Sound.FrameAudioPlayer.frame_ = null; 1369 } 1370 }; 1371 1372 /** @override */ 1373 createjs.Sound.FrameAudioPlayer.prototype.play_ = 1374 function(interrupt, delay, offset, loop, volume, pan) { 1375 /// <param type="number" name="interrupt"/> 1376 /// <param type="number" name="delay"/> 1377 /// <param type="number" name="offset"/> 1378 /// <param type="number" name="loop"/> 1379 /// <param type="number" name="volume"/> 1380 /// <param type="number" name="pan"/> 1381 createjs.Sound.FrameAudioPlayer.superClass_.play_.call( 1382 this, interrupt, delay, offset, loop, volume, pan); 1383 var frame = createjs.Sound.FrameAudioPlayer.getFrame_(); 1384 frame.play(this.id_, this.loop, this.volume); 1385 }; 1386 1387 /** @override */ 1388 createjs.Sound.FrameAudioPlayer.prototype.stop_ = function() { 1389 createjs.Sound.FrameAudioPlayer.superClass_.stop_.call(this); 1390 var frame = createjs.Sound.FrameAudioPlayer.getFrame_(); 1391 frame.stop(this.id_); 1392 }; 1393 1394 /** @override */ 1395 createjs.Sound.FrameAudioPlayer.prototype.setMute_ = function(mute) { 1396 /// <param type="boolean" name="mute"/> 1397 var volume = mute ? 0 : this.volume; 1398 var frame = createjs.Sound.FrameAudioPlayer.getFrame_(); 1399 frame.setVolume(this.id_, volume); 1400 }; 1401 1402 /** @override */ 1403 createjs.Sound.FrameAudioPlayer.prototype.setVolume_ = function(volume) { 1404 /// <param type="number" name="volume"/> 1405 if (this.volume != volume) { 1406 this.volume = volume; 1407 var frame = createjs.Sound.FrameAudioPlayer.getFrame_(); 1408 frame.setVolume(this.id_, volume); 1409 } 1410 }; 1411 1412 /** @override */ 1413 createjs.Sound.FrameAudioPlayer.prototype.setSprite_ = 1414 function(id, offset, duration) { 1415 /// <param type="string" name="id"/> 1416 /// <param type="number" name="offset"/> 1417 /// <param type="number" name="duration"/> 1418 this.id_ = id; 1419 this.offset = offset * 0.001; 1420 this.duration = duration * 0.001; 1421 var frame = createjs.Sound.FrameAudioPlayer.getFrame_(); 1422 frame.clone(this.item.id, id, this.offset, this.duration, this); 1423 }; 1424 1425 /** @override */ 1426 createjs.Sound.FrameAudioPlayer.prototype.handleLoad = 1427 function(loader, buffer) { 1428 /// <param type="createjs.Loader" name="loader"/> 1429 /// <param type="ArrayBuffer" name="buffer"/> 1430 if (buffer) { 1431 var frame = createjs.Sound.FrameAudioPlayer.getFrame_(); 1432 var result = frame.load(this.item.id, buffer, this); 1433 if (!result && this.item.isSynchronous()) { 1434 this.loader_ = loader; 1435 return false; 1436 } 1437 } 1438 return true; 1439 }; 1440 1441 /** 1442 * Called when the createjs.Sound.FrameAudioPlayer.Frame object finishes 1443 * decoding a sound. 1444 * @const 1445 */ 1446 createjs.Sound.FrameAudioPlayer.prototype.handleDecode = function() { 1447 if (this.loader_) { 1448 this.loader_.sendFileComplete(false, null); 1449 this.loader_ = null; 1450 } 1451 }; 1452 1453 /** 1454 * Called when the createjs.Sound.FrameAudioPlayer.Frame object finishes 1455 * playing a sound. 1456 * @const 1457 */ 1458 createjs.Sound.FrameAudioPlayer.prototype.handleEnd = function() { 1459 this.dispatchNotification('complete'); 1460 }; 1461 1462 // Export overridden methods. 1463 createjs.Sound.FrameAudioPlayer.prototype['play'] = 1464 createjs.Sound.FrameAudioPlayer.prototype.play_; 1465 createjs.Sound.FrameAudioPlayer.prototype['stop'] = 1466 createjs.Sound.FrameAudioPlayer.prototype.stop_; 1467 createjs.Sound.FrameAudioPlayer.prototype['setMute'] = 1468 createjs.Sound.FrameAudioPlayer.prototype.setMute_; 1469 createjs.Sound.FrameAudioPlayer.prototype['setVolume'] = 1470 createjs.Sound.FrameAudioPlayer.prototype.setVolume_; 1471 1472 /** 1473 * A class that intermediates a createjs.LoadQueue object and a createjs.Sound 1474 * object. 1475 * @implements {createjs.LoadQueue.Listener} 1476 * @constructor 1477 */ 1478 createjs.Sound.Proxy = function() { 1479 }; 1480 1481 /** @override */ 1482 createjs.Sound.Proxy.prototype.handleFileStart = function(item) { 1483 /// <param type="createjs.Loader.Item" name="item"/> 1484 if (item.isSound()) { 1485 var player = createjs.Sound.getInstance_().addPlayer_(item); 1486 item.setListener(player); 1487 } 1488 }; 1489 1490 /** @override */ 1491 createjs.Sound.Proxy.prototype.handleFileComplete = function(item) { 1492 /// <param type="createjs.Loader.Item" name="item"/> 1493 /// <returns type="boolean"/> 1494 return !!createjs.Sound.getInstance_().getPlayer_(item.id); 1495 }; 1496 1497 /** 1498 * Creates an available player. 1499 * @param {createjs.Loader.Item} item 1500 * @return {createjs.Sound.Player} 1501 * @private 1502 */ 1503 createjs.Sound.prototype.createPlayer_ = function(item) { 1504 /// <param type="createjs.Loader.Item" name="item"/> 1505 /// <returns type="createjs.Sound.Player"/> 1506 var context = createjs.WebAudioPlugin.getContext_(); 1507 if (context) { 1508 if (createjs.Config.useFrame()) { 1509 return new createjs.Sound.FrameAudioPlayer(item); 1510 } 1511 return new createjs.Sound.BufferAudioPlayer(item); 1512 } 1513 createjs.assert(!createjs.UserAgent.isIPhone()); 1514 return new createjs.Sound.HTMLAudioPlayer(item); 1515 }; 1516 1517 /** 1518 * Creates a sound player for the specified item and adds it to this object. 1519 * @param {createjs.Loader.Item} item 1520 * @return {createjs.Sound.Player} 1521 * @private 1522 */ 1523 createjs.Sound.prototype.addPlayer_ = function(item) { 1524 /// <param type="createjs.Loader.Item" name="item"/> 1525 /// <returns type="createjs.Sound.Player"/> 1526 var source = item.getSource(); 1527 var player = this.players_[source]; 1528 if (!player) { 1529 player = this.createPlayer_(item); 1530 this.players_[source] = player; 1531 if (item.id != source) { 1532 this.players_[item.id] = player; 1533 } 1534 } 1535 return player; 1536 }; 1537 1538 /** 1539 * Retrieves a preloaded item. 1540 * @param {string} key 1541 * @return {createjs.Sound.Player} 1542 * @private 1543 */ 1544 createjs.Sound.prototype.getPlayer_ = function(key) { 1545 /// <param type="string" name="key"/> 1546 /// <returns type="createjs.Sound.Player"/> 1547 return this.players_[key]; 1548 }; 1549 1550 /** 1551 * Retrieves the capabilities of the active plug-in, 1552 * @return {Object} 1553 * @private 1554 */ 1555 createjs.Sound.prototype.getCapabilities_ = function() { 1556 /// <returns ype="Object"/> 1557 return this.capabilities_; 1558 }; 1559 1560 /** 1561 * Returns a specific capability of the active plugin. 1562 * @param {string} key 1563 * @return {number} 1564 */ 1565 createjs.Sound.prototype.getCapability_ = function(key) { 1566 /// <param type="string" name="key"/> 1567 /// <returns type="number"/> 1568 return this.capabilities_[key] || 0; 1569 }; 1570 1571 /** 1572 * Returns the source source from the specified ID. 1573 * @param {string} id 1574 * @return {string} 1575 * @private 1576 */ 1577 createjs.Sound.prototype.getSourceById_ = function(id) { 1578 /// <param type="string" name="id"/> 1579 /// <returns type="string"/> 1580 return ''; 1581 }; 1582 1583 /** 1584 * Registers an audio file for loading. 1585 * @param {string} source 1586 * @param {Object} data 1587 * @private 1588 */ 1589 createjs.Sound.prototype.registerSound_ = function(source, data) { 1590 /// <param type="string" name="source"/> 1591 /// <param type="Object" name="data"/> 1592 var player = this.getPlayer_(source); 1593 var audioSprite = createjs.getArray(data['audioSprite']); 1594 if (player && audioSprite) { 1595 for (var i = 0; i < audioSprite.length; ++i) { 1596 // Create a clone of the source player and update its offset and 1597 // duration. The createjs.Sound.registerSound() method uses the number 1598 // milliseconds both for the 'startTime' property and for the 'duration' 1599 // property. Players should convert their values to their preferable 1600 // formats.) 1601 var sprite = audioSprite[i]; 1602 var id = createjs.getString(sprite['id']); 1603 var startTime = createjs.getNumber(sprite['startTime']); 1604 var duration = createjs.getNumber(sprite['duration']); 1605 var clone = this.createPlayer_(player.item); 1606 clone.setSprite_(id, startTime, duration); 1607 this.players_[id] = clone; 1608 } 1609 } 1610 }; 1611 1612 /** 1613 * Removes a sound from this object. 1614 * @param {string} key 1615 * @param {string} basePath 1616 * @return {boolean} 1617 * @private 1618 */ 1619 createjs.Sound.prototype.removeSound_ = function(key, basePath) { 1620 /// <param type="string" name="key"/> 1621 /// <param type="string" name="basePath"/> 1622 /// <returns type="boolean"/> 1623 var player = this.getPlayer_(key); 1624 if (!player) { 1625 return false; 1626 } 1627 player.stop_(); 1628 var item = player.item; 1629 var source = item.getSource(); 1630 this.players_[source] = null; 1631 if (item.id != source) { 1632 this.players_[item.id] = null; 1633 } 1634 return true; 1635 }; 1636 1637 /** 1638 * Removes all sounds. 1639 * @private 1640 */ 1641 createjs.Sound.prototype.removeAllSounds_ = function() { 1642 createjs.notImplemented(); 1643 }; 1644 1645 /** 1646 * Returns whether a source file has been loaded by this object. 1647 * @param {string} source 1648 * @return {boolean} 1649 * @private 1650 */ 1651 createjs.Sound.prototype.loadComplete_ = function(source) { 1652 /// <param type="string" name="source"/> 1653 /// <returns type="boolean"/> 1654 return false; 1655 }; 1656 1657 /** 1658 * Creates a new sound instance. 1659 * @param {string} source 1660 * @param {number=} opt_startTime 1661 * @param {number=} opt_duration 1662 * @return {createjs.Sound.Player} 1663 * @private 1664 */ 1665 createjs.Sound.prototype.createInstance_ = 1666 function(source, opt_startTime, opt_duration) { 1667 /// <param type="string" name="source"/> 1668 /// <param type="number" optional="true" name="opt_startTime"/> 1669 /// <param type="number" optional="true" name="opt_duration"/> 1670 /// <returns type="createjs.Sound.Player"/> 1671 return this.getPlayer_(source); 1672 }; 1673 1674 /** 1675 * Plays a sound file. 1676 * @param {string} source 1677 * @param {number} interrupt 1678 * @param {number} delay 1679 * @param {number} offset 1680 * @param {number} loop 1681 * @param {number} volume 1682 * @param {number} pan 1683 * @private 1684 */ 1685 createjs.Sound.prototype.play_ = 1686 function(source, interrupt, delay, offset, loop, volume, pan) { 1687 /// <param type="string" name="source"/> 1688 /// <param type="number" name="interrupt"/> 1689 /// <param type="number" name="delay"/> 1690 /// <param type="number" name="offset"/> 1691 /// <param type="number" name="loop"/> 1692 /// <param type="number" name="volume"/> 1693 /// <param type="number" name="pan"/> 1694 var player = this.createInstance_(source); 1695 if (player) { 1696 player.play_(0, delay, offset, loop, volume, pan); 1697 } 1698 }; 1699 1700 /** 1701 * Sets the master volume. 1702 * @param {number} volume 1703 * @private 1704 */ 1705 createjs.Sound.prototype.setVolume_ = function(volume) { 1706 /// <param type="number" name="volume"/> 1707 }; 1708 1709 /** 1710 * Gets the master volume. 1711 * @return {number} 1712 * @private 1713 */ 1714 createjs.Sound.prototype.getVolume_ = function() { 1715 /// <returns type="number"/> 1716 return 1; 1717 }; 1718 1719 /** 1720 * Sets the mute state. 1721 * @param {boolean} value 1722 * @return {boolean} 1723 * @private 1724 */ 1725 createjs.Sound.prototype.setMute_ = function(value) { 1726 /// <param type="boolean" name="value"/> 1727 /// <returns type="boolean"/> 1728 for (var key in this.players_) { 1729 var player = this.players_[key]; 1730 if (player) { 1731 player.setMute_(value); 1732 } 1733 } 1734 return true; 1735 }; 1736 1737 /** 1738 * Returns the current mute state. 1739 * @return {boolean} 1740 * @private 1741 */ 1742 createjs.Sound.prototype.getMute_ = function() { 1743 /// <returns type="boolean"/> 1744 return false; 1745 }; 1746 1747 /** 1748 * Stops playing all audio. 1749 * @private 1750 */ 1751 createjs.Sound.prototype.stop_ = function() { 1752 }; 1753 1754 /** 1755 * Registers a plug-in. 1756 * @param {Object} plugin 1757 * @return {boolean} 1758 */ 1759 createjs.Sound.registerPlugin = function(plugin) { 1760 /// <param type="Object" name="plugin"/> 1761 /// <returns type="boolean"/> 1762 return false; 1763 }; 1764 1765 /** 1766 * Registers plug-ins. 1767 * @param {Array} plugins 1768 * @return {boolean} 1769 */ 1770 createjs.Sound.registerPlugins = function(plugins) { 1771 /// <param type="Array" elementType="Object" name="plugins"/> 1772 /// <returns type="boolean"/> 1773 return false; 1774 }; 1775 1776 /** 1777 * Returns whether there is at least one listener for the specified event type. 1778 * @return {createjs.Sound.Plugin} 1779 */ 1780 createjs.Sound.getActivePlugin = function() { 1781 /// <returns type="createjs.WebAudioPlugin"/> 1782 if (createjs.AudioContext) { 1783 return new createjs.WebAudioPlugin(); 1784 } 1785 return new createjs.HTMLAudioPlugin(); 1786 }; 1787 1788 /** 1789 * Initializes the default plug-ins. 1790 * @return {boolean} 1791 */ 1792 createjs.Sound.initializeDefaultPlugins = function() { 1793 /// <returns type="boolean"/> 1794 return true; 1795 }; 1796 1797 /** 1798 * Returns whether this module can play sound. 1799 * @return {boolean} 1800 */ 1801 createjs.Sound.isReady = function() { 1802 /// <returns type="boolean"/> 1803 return true; 1804 }; 1805 1806 /** 1807 * Creates a new sound instance. 1808 * @param {string} source 1809 * @return {createjs.Sound.Player} 1810 */ 1811 createjs.Sound.createInstance = function(source) { 1812 /// <param type="string" name="source"/> 1813 /// <returns type="createjs.Sound.Player"/> 1814 return createjs.Sound.getInstance_().createInstance_(source); 1815 }; 1816 1817 /** 1818 * Creates audio sprites from an audio file and registers them. This method 1819 * creates audio sprites from an audio file (loaded by a LoadQueue object) so 1820 * a game can play a part of the audio file as listed in the following snippet. 1821 * var queue = new createjs.LoadQueue(); 1822 * queue.on('complete', function() { 1823 * createjs.Sound.registerSound('http://server/audio.m4a', '', { 1824 * audioSprite: [ 1825 * { id: 'sound1', startTime: 0, duration: 500 }, 1826 * { id: 'sound2', startTime: 1000, duration: 400 }, 1827 * { id: 'sound3', startTime: 1700, duration: 1000 } 1828 * } 1829 * ); 1830 * }); 1831 * queue.loadFile({ src: 'http://server/audio.m4a' }); 1832 * @param {string|Object} source 1833 * @param {string=} opt_id 1834 * @param {number|Object=} opt_data 1835 * @param {boolean=} opt_preload 1836 * @param {string=} opt_basePath 1837 */ 1838 createjs.Sound.registerSound = 1839 function(source, opt_id, opt_data, opt_preload, opt_basePath) { 1840 /// <param type="string" name="source"/> 1841 /// <param type="string" optional="true" name="opt_id"/> 1842 /// <param type="number" optional="true" name="opt_data"/> 1843 /// <param type="boolean" optional="true" name="opt_preload"> 1844 /// <param type="string" optional="true" name="opt_basePath"/> 1845 var id = opt_id || createjs.getString(source); 1846 createjs.Sound.getInstance_().registerSound_( 1847 id, createjs.getObject(opt_data)); 1848 }; 1849 1850 /** 1851 * Creates audio sprites from audio files and registers them. 1852 * createjs.Sound.registerSounds([{ 1853 * src: 'http://server/audio.m4a', 1854 * data: { 1855 * audioSprite: [ 1856 * { id: 'sound1', startTime: 0, duration: 500 }, 1857 * { id: 'sound2', startTime: 1000, duration: 400 }, 1858 * { id: 'sound3', startTime: 1700, duration: 1000 } 1859 * ] 1860 * } 1861 * }]); 1862 * @param {Array.<Object>} sources 1863 * @param {string=} opt_basePath 1864 */ 1865 createjs.Sound.registerSounds = function(sources, opt_basePath) { 1866 for (var i = 0; i < sources.length; ++i) { 1867 var source = sources[i]; 1868 createjs.Sound.registerSound(source['src'], '', source['data']); 1869 } 1870 }; 1871 1872 /** 1873 * Registers a manifest of audio files for loading. 1874 * @param {Array} manifest 1875 * @param {string} basePath 1876 * @return {Array.<Object>} 1877 */ 1878 createjs.Sound.registerManifest = function(manifest, basePath) { 1879 /// <param type="Array" elementType="Object" name="manifest"/> 1880 /// <param type="string" name="basePath"/> 1881 /// <returns type="Array"/> 1882 var values = []; 1883 var length = manifest.length; 1884 for (var i = 0; i < length; ++i) { 1885 var item = manifest[i]; 1886 values.push(createjs.Sound.registerSound( 1887 item['src'], item['id'], item['data'], item['preload'], basePath)); 1888 } 1889 return values; 1890 }; 1891 1892 /** 1893 * Removes a sound. 1894 * @param {string|Object} src 1895 * @param {string} basePath 1896 * @return {boolean} 1897 */ 1898 createjs.Sound.removeSound = function(src, basePath) { 1899 /// <param type="string" name="src"/> 1900 /// <param type="string" name="basePath"/> 1901 /// <returns type="boolean"/> 1902 var instance = createjs.Sound.getInstance_(); 1903 if (createjs.isObject(src)) { 1904 var item = createjs.getObject(src); 1905 return instance.removeSound_(createjs.getString(item['src']), basePath); 1906 } 1907 return instance.removeSound_(createjs.getString(src), basePath); 1908 }; 1909 1910 /** 1911 * Removes all sound files in a manifest. 1912 * @param {Array.<Object>} manifest 1913 * @param {string} basePath 1914 * @return {Array.<boolean>} 1915 */ 1916 createjs.Sound.removeManifest = function(manifest, basePath) { 1917 /// <param type="Array" elementType="Object" name="manifest"/> 1918 /// <param type="string" name="basePath"/> 1919 /// <returns type="Array"/> 1920 var instance = createjs.Sound.getInstance_(); 1921 var returnValues = []; 1922 var length = manifest.length; 1923 for (var i = 0; i < length; ++i) { 1924 var item = createjs.getObject(manifest[i]); 1925 returnValues[i] = instance.removeSound_(item['src'], basePath); 1926 } 1927 return returnValues; 1928 }; 1929 1930 /** 1931 * Removes all sounds registered to this object. 1932 */ 1933 createjs.Sound.removeAllSounds = function() { 1934 return createjs.Sound.getInstance_().removeAllSounds_(); 1935 }; 1936 1937 /** 1938 * Returns whether a source has been loaded. 1939 * @param {string} source 1940 * @return {boolean} 1941 */ 1942 createjs.Sound.prototype.loadComplete = function(source) { 1943 /// <param type="string" name="source"/> 1944 /// <returns type="boolean"/> 1945 return createjs.Sound.getInstance_().loadComplete_(source); 1946 }; 1947 1948 /** 1949 * Resets the global variables used by this class and the inner classes in this 1950 * file. 1951 * @param {number=} opt_destroy 1952 * @const 1953 */ 1954 createjs.Sound.reset = function(opt_destroy) { 1955 /// <param type="number" optional="true" name="opt_destroy"/> 1956 if (opt_destroy) { 1957 var instance = createjs.Sound.getInstance_(); 1958 for (var key in instance.players_) { 1959 var player = instance.players_[key]; 1960 if (player) { 1961 player.stop_(); 1962 } 1963 } 1964 createjs.WebAudioPlugin.reset_(); 1965 if (createjs.Config.useFrame()) { 1966 createjs.Sound.FrameAudioPlayer.destroy_(); 1967 } 1968 } 1969 }; 1970 1971 /** 1972 * Plays a sound. 1973 * @param {string} source 1974 * @param {string|Object} value 1975 * @param {number=} opt_delay 1976 * @param {number=} opt_offset 1977 * @param {number=} opt_loop 1978 * @param {number=} opt_volume 1979 * @param {number=} opt_pan 1980 * @static 1981 */ 1982 createjs.Sound.play = function(source, 1983 value, 1984 opt_delay, 1985 opt_offset, 1986 opt_loop, 1987 opt_volume, 1988 opt_pan) { 1989 /// <param type="string" name="source"/> 1990 /// <param type="string" name="value"/> 1991 /// <param type="number" optional="true" name="opt_delay"/> 1992 /// <param type="number" optional="true" name="opt_offset"/> 1993 /// <param type="number" optional="true" name="opt_loop"/> 1994 /// <param type="number" optional="true" name="opt_volume"/> 1995 /// <param type="number" optional="true" name="opt_pan"/> 1996 if (value != null && createjs.isObject(value)) { 1997 var options = createjs.getObject(value); 1998 value = options['interrupt']; 1999 opt_delay = options['delay']; 2000 opt_offset = options['offset']; 2001 opt_loop = options['loop']; 2002 opt_volume = options['volume']; 2003 opt_pan = options['pan']; 2004 } 2005 var interrupt = createjs.Sound.INTERRUPT_NONE; 2006 if (createjs.isString(value)) { 2007 var key = createjs.getString(value); 2008 var INTERRUPTS = { 2009 'any': createjs.Sound.INTERRUPT_ANY, 2010 'early': createjs.Sound.INTERRUPT_EARLY, 2011 'late': createjs.Sound.INTERRUPT_LATE, 2012 'none': createjs.Sound.INTERRUPT_NONE 2013 }; 2014 interrupt = INTERRUPTS[key] || createjs.Sound.INTERRUPT_NONE; 2015 } 2016 var delay = opt_delay || 0; 2017 var offset = opt_offset || 0; 2018 var loop = opt_loop || 0; 2019 var volume = (opt_volume == null) ? 1 : createjs.getNumber(opt_volume); 2020 var pan = opt_pan || 0; 2021 createjs.Sound.getInstance_().play_( 2022 source, interrupt, delay, offset, loop, volume, pan); 2023 }; 2024 2025 /** 2026 * Sets the master volume. 2027 * @param {number} value 2028 * @static 2029 */ 2030 createjs.Sound.setVolume = function(value) { 2031 /// <param type="number" name="volume"/> 2032 value = createjs.max(0, createjs.min(1, value)); 2033 return createjs.Sound.getInstance_().setVolume_(value); 2034 }; 2035 2036 /** 2037 * Returns the master volume. 2038 * @return {number} 2039 * @static 2040 */ 2041 createjs.Sound.getVolume = function() { 2042 /// <returns type="number"/> 2043 return createjs.Sound.getInstance_().getVolume_(); 2044 }; 2045 2046 /** 2047 * Mutes/Unmutes all audio. 2048 * @param {boolean} value 2049 * @return {boolean} 2050 */ 2051 createjs.Sound.setMute = function(value) { 2052 /// <param type="boolean" name="value"/> 2053 /// <returns type="boolean"/> 2054 createjs.assert(value != null); 2055 return createjs.Sound.getInstance_().setMute_(value); 2056 }; 2057 2058 /** 2059 * Returns the mute status. 2060 * @return {boolean} 2061 */ 2062 createjs.Sound.getMute = function() { 2063 /// <returns type="boolean"/> 2064 return createjs.Sound.getInstance_().getMute_(); 2065 }; 2066 2067 /** 2068 * Stops all audio (global stop) 2069 */ 2070 createjs.Sound.stop = function() { 2071 return createjs.Sound.getInstance_().stop_(); 2072 }; 2073 2074 /** 2075 * Adds an event listener. 2076 * @param {string} type 2077 * @param {Function|Object} listener 2078 * @param {boolean=} opt_useCapture 2079 * @return {Function|Object} 2080 */ 2081 createjs.Sound.addListener = function(type, listener, opt_useCapture) { 2082 /// <param type="string" name="type"/> 2083 /// <param type="Function" name="listener"/> 2084 /// <param type="boolean" optional="true" name="opt_useCapture"/> 2085 /// <returns type="Function"/> 2086 var instance = createjs.Sound.getInstance_(); 2087 return instance.on(type, listener); 2088 }; 2089 2090 /** 2091 * Removes the specified event listener. 2092 * @param {string} type 2093 * @param {Function|Object} listener 2094 * @param {boolean=} opt_useCapture 2095 */ 2096 createjs.Sound.removeListener = function(type, listener, opt_useCapture) { 2097 /// <param type="string" name="type"/> 2098 /// <param type="Function" name="listener"/> 2099 /// <param type="boolean" optional="true" name="opt_useCapture"/> 2100 var instance = createjs.Sound.getInstance_(); 2101 instance.off(type, listener); 2102 }; 2103 2104 /** 2105 * Removes all listeners for the specified type, or all listeners of all types. 2106 * @param {string=} opt_type 2107 */ 2108 createjs.Sound.removeAllListeners = function(opt_type) { 2109 /// <param type="string" optional="true" name="opt_type"/> 2110 var instance = createjs.Sound.getInstance_(); 2111 instance.removeAllListeners(opt_type || ''); 2112 }; 2113 2114 /** 2115 * Dispatches the specified event to all listeners. 2116 * @param {Object|string|Event} event 2117 * @param {Object=} opt_target 2118 * @return {boolean} 2119 */ 2120 createjs.Sound.dispatch = function(event, opt_target) { 2121 /// <param type="Object" name="event"/> 2122 /// <param type="Object" optional="true" name="opt_target"/> 2123 /// <returns type="boolean"/> 2124 var instance = createjs.Sound.getInstance_(); 2125 return instance.dispatch(event, opt_target || null); 2126 }; 2127 2128 /** 2129 * Returns whether there is at least one listener for the specified event type. 2130 * @param {string} type 2131 * @return {boolean} 2132 */ 2133 createjs.Sound.hasListener = function(type) { 2134 /// <param type="string" name="type"/> 2135 /// <returns type="boolean"/> 2136 var instance = createjs.Sound.getInstance_(); 2137 return instance.hasListener(type); 2138 }; 2139 2140 /** 2141 * A table of exported functions. 2142 * @const {Object} 2143 */ 2144 createjs.Sound.exports = createjs.exportStatic('createjs.Sound', { 2145 'INTERRUPT_ANY': createjs.Sound.INTERRUPT_ANY, 2146 'INTERRUPT_EARLY': createjs.Sound.INTERRUPT_EARLY, 2147 'INTERRUPT_LATE': createjs.Sound.INTERRUPT_LATE, 2148 'INTERRUPT_NONE': createjs.Sound.INTERRUPT_NONE, 2149 'PLAY_SUCCEEDED': createjs.Sound.PLAY_SUCCEEDED, 2150 'PLAY_FINISHED': createjs.Sound.PLAY_FINISHED, 2151 'PLAY_FAILED': createjs.Sound.PLAY_FAILED, 2152 'activePlugin': createjs.Sound.getActivePlugin(), 2153 'initializeDefaultPlugins': createjs.Sound.initializeDefaultPlugins, 2154 'isReady': createjs.Sound.isReady, 2155 'createInstance': createjs.Sound.createInstance, 2156 'registerSound': createjs.Sound.registerSound, 2157 'registerSounds': createjs.Sound.registerSounds, 2158 'removeSound': createjs.Sound.removeSound, 2159 'play': createjs.Sound.play, 2160 'addEventListener': createjs.Sound.addListener, 2161 'removeEventListener': createjs.Sound.removeListener, 2162 'removeAllEventListeners': createjs.Sound.removeAllListeners, 2163 'dispatchEvent': createjs.Sound.dispatch, 2164 'hasEventListener': createjs.Sound.hasListener, 2165 'setMute': createjs.Sound.setMute, 2166 'setVolume': createjs.Sound.setVolume 2167 }); 2168