UNPKG

phaser

Version:

A fast, free and fun HTML5 Game Framework for Desktop and Mobile web browsers.

1,614 lines (1,281 loc) 46.9 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Phaser Source: sound/Sound.js</title> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/sunlight.default.css"> <link type="text/css" rel="stylesheet" href="styles/site.cerulean.css"> </head> <body> <div class="container-fluid"> <div class="navbar navbar-fixed-top navbar-inverse"> <div class="navbar-inner"> <a class="brand" href="index.html">Phaser</a> <ul class="nav"> <li class="dropdown"> <a href="namespaces.list.html" class="dropdown-toggle" data-toggle="dropdown">Namespaces<b class="caret"></b></a> <ul class="dropdown-menu "> <li class="class-depth-0"> <a href="Phaser.html">Phaser</a> </li> </ul> </li> <li class="dropdown"> <a href="classes.list.html" class="dropdown-toggle" data-toggle="dropdown">Classes<b class="caret"></b></a> <ul class="dropdown-menu "> <li class="class-depth-1"> <a href="Phaser.Animation.html">Animation</a> </li> <li class="class-depth-1"> <a href="Phaser.AnimationManager.html">AnimationManager</a> </li> <li class="class-depth-1"> <a href="Phaser.AnimationParser.html">AnimationParser</a> </li> <li class="class-depth-1"> <a href="Phaser.ArrayList.html">ArrayList</a> </li> <li class="class-depth-1"> <a href="Phaser.AudioSprite.html">AudioSprite</a> </li> <li class="class-depth-1"> <a href="Phaser.BitmapData.html">BitmapData</a> </li> <li class="class-depth-1"> <a href="Phaser.BitmapText.html">BitmapText</a> </li> <li class="class-depth-1"> <a href="Phaser.Button.html">Button</a> </li> <li class="class-depth-1"> <a href="Phaser.Cache.html">Cache</a> </li> <li class="class-depth-1"> <a href="Phaser.Camera.html">Camera</a> </li> <li class="class-depth-1"> <a href="Phaser.Canvas.html">Canvas</a> </li> <li class="class-depth-1"> <a href="Phaser.Circle.html">Circle</a> </li> <li class="class-depth-1"> <a href="Phaser.Color.html">Color</a> </li> <li class="class-depth-1"> <a href="Phaser.Device.html">Device</a> </li> <li class="class-depth-1"> <a href="Phaser.Easing.html">Easing</a> </li> <li class="class-depth-2"> <a href="Phaser.Easing.Back.html">Back</a> </li> <li class="class-depth-2"> <a href="Phaser.Easing.Bounce.html">Bounce</a> </li> <li class="class-depth-2"> <a href="Phaser.Easing.Circular.html">Circular</a> </li> <li class="class-depth-2"> <a href="Phaser.Easing.Cubic.html">Cubic</a> </li> <li class="class-depth-2"> <a href="Phaser.Easing.Elastic.html">Elastic</a> </li> <li class="class-depth-2"> <a href="Phaser.Easing.Exponential.html">Exponential</a> </li> <li class="class-depth-2"> <a href="Phaser.Easing.Linear.html">Linear</a> </li> <li class="class-depth-2"> <a href="Phaser.Easing.Quadratic.html">Quadratic</a> </li> <li class="class-depth-2"> <a href="Phaser.Easing.Quartic.html">Quartic</a> </li> <li class="class-depth-2"> <a href="Phaser.Easing.Quintic.html">Quintic</a> </li> <li class="class-depth-2"> <a href="Phaser.Easing.Sinusoidal.html">Sinusoidal</a> </li> <li class="class-depth-1"> <a href="Phaser.Ellipse.html">Ellipse</a> </li> <li class="class-depth-1"> <a href="Phaser.Events.html">Events</a> </li> <li class="class-depth-1"> <a href="Phaser.Filter.html">Filter</a> </li> <li class="class-depth-1"> <a href="Phaser.FlexGrid.html">FlexGrid</a> </li> <li class="class-depth-1"> <a href="Phaser.FlexLayer.html">FlexLayer</a> </li> <li class="class-depth-1"> <a href="Phaser.Frame.html">Frame</a> </li> <li class="class-depth-1"> <a href="Phaser.FrameData.html">FrameData</a> </li> <li class="class-depth-1"> <a href="Phaser.Game.html">Game</a> </li> <li class="class-depth-1"> <a href="Phaser.GameObjectCreator.html">GameObjectCreator</a> </li> <li class="class-depth-1"> <a href="Phaser.GameObjectFactory.html">GameObjectFactory</a> </li> <li class="class-depth-1"> <a href="Phaser.Gamepad.html">Gamepad</a> </li> <li class="class-depth-1"> <a href="Phaser.GamepadButton.html">GamepadButton</a> </li> <li class="class-depth-1"> <a href="Phaser.Graphics.html">Graphics</a> </li> <li class="class-depth-1"> <a href="Phaser.Group.html">Group</a> </li> <li class="class-depth-1"> <a href="Phaser.Image.html">Image</a> </li> <li class="class-depth-1"> <a href="Phaser.Input.html">Input</a> </li> <li class="class-depth-1"> <a href="Phaser.InputHandler.html">InputHandler</a> </li> <li class="class-depth-1"> <a href="Phaser.Key.html">Key</a> </li> <li class="class-depth-1"> <a href="Phaser.Keyboard.html">Keyboard</a> </li> <li class="class-depth-1"> <a href="Phaser.Line.html">Line</a> </li> <li class="class-depth-1"> <a href="Phaser.LinkedList.html">LinkedList</a> </li> <li class="class-depth-1"> <a href="Phaser.Loader.html">Loader</a> </li> <li class="class-depth-1"> <a href="Phaser.LoaderParser.html">LoaderParser</a> </li> <li class="class-depth-1"> <a href="Phaser.Math.html">Math</a> </li> <li class="class-depth-1"> <a href="Phaser.Mouse.html">Mouse</a> </li> <li class="class-depth-1"> <a href="Phaser.MSPointer.html">MSPointer</a> </li> <li class="class-depth-1"> <a href="Phaser.Net.html">Net</a> </li> <li class="class-depth-1"> <a href="Phaser.Particle.html">Particle</a> </li> <li class="class-depth-1"> <a href="Phaser.Particles.html">Particles</a> </li> <li class="class-depth-2"> <a href="Phaser.Particles.Arcade.html">Arcade</a> </li> <li class="class-depth-3"> <a href="Phaser.Particles.Arcade.Emitter.html">Emitter</a> </li> <li class="class-depth-1"> <a href="Phaser.Physics.html">Physics</a> </li> <li class="class-depth-2"> <a href="Phaser.Physics.Arcade.html">Arcade</a> </li> <li class="class-depth-3"> <a href="Phaser.Physics.Arcade.Body.html">Body</a> </li> <li class="class-depth-2"> <a href="Phaser.Physics.Ninja.html">Ninja</a> </li> <li class="class-depth-3"> <a href="Phaser.Physics.Ninja.AABB.html">AABB</a> </li> <li class="class-depth-3"> <a href="Phaser.Physics.Ninja.Body.html">Body</a> </li> <li class="class-depth-3"> <a href="Phaser.Physics.Ninja.Circle.html">Circle</a> </li> <li class="class-depth-3"> <a href="Phaser.Physics.Ninja.Tile.html">Tile</a> </li> <li class="class-depth-2"> <a href="Phaser.Physics.P2.html">P2</a> </li> <li class="class-depth-3"> <a href="Phaser.Physics.P2.Body.html">Body</a> </li> <li class="class-depth-3"> <a href="Phaser.Physics.P2.BodyDebug.html">BodyDebug</a> </li> <li class="class-depth-3"> <a href="Phaser.Physics.P2.CollisionGroup.html">CollisionGroup</a> </li> <li class="class-depth-3"> <a href="Phaser.Physics.P2.ContactMaterial.html">ContactMaterial</a> </li> <li class="class-depth-3"> <a href="Phaser.Physics.P2.DistanceConstraint.html">DistanceConstraint</a> </li> <li class="class-depth-3"> <a href="Phaser.Physics.P2.FixtureList.html">FixtureList</a> </li> <li class="class-depth-3"> <a href="Phaser.Physics.P2.GearConstraint.html">GearConstraint</a> </li> <li class="class-depth-3"> <a href="Phaser.Physics.P2.InversePointProxy.html">InversePointProxy</a> </li> <li class="class-depth-3"> <a href="Phaser.Physics.P2.LockConstraint.html">LockConstraint</a> </li> <li class="class-depth-3"> <a href="Phaser.Physics.P2.Material.html">Material</a> </li> <li class="class-depth-3"> <a href="Phaser.Physics.P2.PointProxy.html">PointProxy</a> </li> <li class="class-depth-3"> <a href="Phaser.Physics.P2.PrismaticConstraint.html">PrismaticConstraint</a> </li> <li class="class-depth-3"> <a href="Phaser.Physics.P2.RevoluteConstraint.html">RevoluteConstraint</a> </li> <li class="class-depth-3"> <a href="Phaser.Physics.P2.RotationalSpring.html">RotationalSpring</a> </li> <li class="class-depth-3"> <a href="Phaser.Physics.P2.Spring.html">Spring</a> </li> <li class="class-depth-1"> <a href="Phaser.Plugin.html">Plugin</a> </li> <li class="class-depth-1"> <a href="Phaser.PluginManager.html">PluginManager</a> </li> <li class="class-depth-1"> <a href="Phaser.Point.html">Point</a> </li> <li class="class-depth-1"> <a href="Phaser.Pointer.html">Pointer</a> </li> <li class="class-depth-1"> <a href="Phaser.Polygon.html">Polygon</a> </li> <li class="class-depth-1"> <a href="Phaser.QuadTree.html">QuadTree</a> </li> <li class="class-depth-1"> <a href="Phaser.RandomDataGenerator.html">RandomDataGenerator</a> </li> <li class="class-depth-1"> <a href="Phaser.Rectangle.html">Rectangle</a> </li> <li class="class-depth-1"> <a href="Phaser.RenderTexture.html">RenderTexture</a> </li> <li class="class-depth-1"> <a href="Phaser.RequestAnimationFrame.html">RequestAnimationFrame</a> </li> <li class="class-depth-1"> <a href="Phaser.RetroFont.html">RetroFont</a> </li> <li class="class-depth-1"> <a href="Phaser.Rope.html">Rope</a> </li> <li class="class-depth-1"> <a href="Phaser.ScaleManager.html">ScaleManager</a> </li> <li class="class-depth-1"> <a href="Phaser.Signal.html">Signal</a> </li> <li class="class-depth-1"> <a href="Phaser.SignalBinding.html">SignalBinding</a> </li> <li class="class-depth-1"> <a href="Phaser.SinglePad.html">SinglePad</a> </li> <li class="class-depth-1"> <a href="Phaser.Sound.html">Sound</a> </li> <li class="class-depth-1"> <a href="Phaser.SoundManager.html">SoundManager</a> </li> <li class="class-depth-1"> <a href="Phaser.Sprite.html">Sprite</a> </li> <li class="class-depth-1"> <a href="Phaser.SpriteBatch.html">SpriteBatch</a> </li> <li class="class-depth-1"> <a href="Phaser.Stage.html">Stage</a> </li> <li class="class-depth-1"> <a href="Phaser.State.html">State</a> </li> <li class="class-depth-1"> <a href="Phaser.StateManager.html">StateManager</a> </li> <li class="class-depth-1"> <a href="Phaser.Text.html">Text</a> </li> <li class="class-depth-1"> <a href="Phaser.Tile.html">Tile</a> </li> <li class="class-depth-1"> <a href="Phaser.Tilemap.html">Tilemap</a> </li> <li class="class-depth-1"> <a href="Phaser.TilemapLayer.html">TilemapLayer</a> </li> <li class="class-depth-1"> <a href="Phaser.TilemapParser.html">TilemapParser</a> </li> <li class="class-depth-1"> <a href="Phaser.Tileset.html">Tileset</a> </li> <li class="class-depth-1"> <a href="Phaser.TileSprite.html">TileSprite</a> </li> <li class="class-depth-1"> <a href="Phaser.Time.html">Time</a> </li> <li class="class-depth-1"> <a href="Phaser.Timer.html">Timer</a> </li> <li class="class-depth-1"> <a href="Phaser.TimerEvent.html">TimerEvent</a> </li> <li class="class-depth-1"> <a href="Phaser.Touch.html">Touch</a> </li> <li class="class-depth-1"> <a href="Phaser.Tween.html">Tween</a> </li> <li class="class-depth-1"> <a href="Phaser.TweenManager.html">TweenManager</a> </li> <li class="class-depth-1"> <a href="Phaser.Utils.html">Utils</a> </li> <li class="class-depth-2"> <a href="Phaser.Utils.Debug.html">Debug</a> </li> <li class="class-depth-1"> <a href="Phaser.World.html">World</a> </li> </ul> </li> </ul> </div> </div> <div class="row-fluid"> <div class="span12"> <div id="main"> <h1 class="page-title">Source: sound/Sound.js</h1> <section> <article> <pre class="sunlight-highlight-javascript linenums">/** * @author Richard Davey &lt;rich@photonstorm.com> * @copyright 2014 Photon Storm Ltd. * @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License} */ /** * The Sound class constructor. * * @class Phaser.Sound * @constructor * @param {Phaser.Game} game - Reference to the current game instance. * @param {string} key - Asset key for the sound. * @param {number} [volume=1] - Default value for the volume, between 0 and 1. * @param {boolean} [loop=false] - Whether or not the sound will loop. */ Phaser.Sound = function (game, key, volume, loop, connect) { if (typeof volume == 'undefined') { volume = 1; } if (typeof loop == 'undefined') { loop = false; } if (typeof connect === 'undefined') { connect = game.sound.connectToMaster; } /** * A reference to the currently running Game. * @property {Phaser.Game} game */ this.game = game; /** * @property {string} name - Name of the sound. */ this.name = key; /** * @property {string} key - Asset key for the sound. */ this.key = key; /** * @property {boolean} loop - Whether or not the sound or current sound marker will loop. */ this.loop = loop; /** * @property {number} volume - The sound or sound marker volume. A value between 0 (silence) and 1 (full volume). */ this.volume = volume; /** * @property {object} markers - The sound markers. */ this.markers = {}; /** * @property {AudioContext} context - Reference to the AudioContext instance. */ this.context = null; /** * @property {boolean} autoplay - Boolean indicating whether the sound should start automatically. */ this.autoplay = false; /** * @property {number} totalDuration - The total duration of the sound in seconds. */ this.totalDuration = 0; /** * @property {number} startTime - The time the Sound starts at (typically 0 unless starting from a marker) * @default */ this.startTime = 0; /** * @property {number} currentTime - The current time the sound is at. */ this.currentTime = 0; /** * @property {number} duration - The duration of the current sound marker in seconds. */ this.duration = 0; /** * @property {number} durationMS - The duration of the current sound marker in ms. */ this.durationMS = 0; /** * @property {number} position - The position of the current sound marker. */ this.position = 0; /** * @property {number} stopTime - The time the sound stopped. */ this.stopTime = 0; /** * @property {boolean} paused - true if the sound is paused, otherwise false. * @default */ this.paused = false; /** * @property {number} pausedPosition - The position the sound had reached when it was paused. */ this.pausedPosition = 0; /** * @property {number} pausedTime - The game time at which the sound was paused. */ this.pausedTime = 0; /** * @property {boolean} isPlaying - true if the sound is currently playing, otherwise false. * @default */ this.isPlaying = false; /** * @property {string} currentMarker - The string ID of the currently playing marker, if any. * @default */ this.currentMarker = ''; /** * @property {boolean} pendingPlayback - true if the sound file is pending playback * @readonly */ this.pendingPlayback = false; /** * @property {boolean} override - if true when you play this sound it will always start from the beginning. * @default */ this.override = false; /** * @property {boolean} allowMultiple - This will allow you to have multiple instances of this Sound playing at once. This is only useful when running under Web Audio, and we recommend you implement a local pooling system to not flood the sound channels. * @default */ this.allowMultiple = false; /** * @property {boolean} usingWebAudio - true if this sound is being played with Web Audio. * @readonly */ this.usingWebAudio = this.game.sound.usingWebAudio; /** * @property {boolean} usingAudioTag - true if the sound is being played via the Audio tag. */ this.usingAudioTag = this.game.sound.usingAudioTag; /** * @property {object} externalNode - If defined this Sound won't connect to the SoundManager master gain node, but will instead connect to externalNode. */ this.externalNode = null; /** * @property {object} masterGainNode - The master gain node in a Web Audio system. */ this.masterGainNode = null; /** * @property {object} gainNode - The gain node in a Web Audio system. */ this.gainNode = null; if (this.usingWebAudio) { this.context = this.game.sound.context; this.masterGainNode = this.game.sound.masterGain; if (typeof this.context.createGain === 'undefined') { this.gainNode = this.context.createGainNode(); } else { this.gainNode = this.context.createGain(); } this.gainNode.gain.value = volume * this.game.sound.volume; if (connect) { this.gainNode.connect(this.masterGainNode); } } else { if (this.game.cache.getSound(key) && this.game.cache.isSoundReady(key)) { this._sound = this.game.cache.getSoundData(key); this.totalDuration = 0; if (this._sound.duration) { this.totalDuration = this._sound.duration; } } else { this.game.cache.onSoundUnlock.add(this.soundHasUnlocked, this); } } /** * @property {Phaser.Signal} onDecoded - The onDecoded event is dispatched when the sound has finished decoding (typically for mp3 files) */ this.onDecoded = new Phaser.Signal(); /** * @property {Phaser.Signal} onPlay - The onPlay event is dispatched each time this sound is played. */ this.onPlay = new Phaser.Signal(); /** * @property {Phaser.Signal} onPause - The onPause event is dispatched when this sound is paused. */ this.onPause = new Phaser.Signal(); /** * @property {Phaser.Signal} onResume - The onResume event is dispatched when this sound is resumed from a paused state. */ this.onResume = new Phaser.Signal(); /** * @property {Phaser.Signal} onLoop - The onLoop event is dispatched when this sound loops during playback. */ this.onLoop = new Phaser.Signal(); /** * @property {Phaser.Signal} onStop - The onStop event is dispatched when this sound stops playback. */ this.onStop = new Phaser.Signal(); /** * @property {Phaser.Signal} onMute - The onMouse event is dispatched when this sound is muted. */ this.onMute = new Phaser.Signal(); /** * @property {Phaser.Signal} onMarkerComplete - The onMarkerComplete event is dispatched when a marker within this sound completes playback. */ this.onMarkerComplete = new Phaser.Signal(); /** * @property {Phaser.Signal} onFadeComplete - The onFadeComplete event is dispatched when this sound finishes fading either in or out. */ this.onFadeComplete = new Phaser.Signal(); /** * @property {number} _volume - The global audio volume. A value between 0 (silence) and 1 (full volume). * @private */ this._volume = volume; /** * @property {any} _buffer - Decoded data buffer / Audio tag. * @private */ this._buffer = null; /** * @property {boolean} _muted - Boolean indicating whether the sound is muted or not. * @private */ this._muted = false; /** * @property {number} _tempMarker - Internal marker var. * @private */ this._tempMarker = 0; /** * @property {number} _tempPosition - Internal marker var. * @private */ this._tempPosition = 0; /** * @property {number} _tempVolume - Internal marker var. * @private */ this._tempVolume = 0; /** * @property {number} _muteVolume - Internal cache var. * @private */ this._muteVolume = 0; /** * @property {boolean} _tempLoop - Internal cache var. * @private */ this._tempLoop = 0; /** * @property {boolean} _paused - Was this sound paused via code or a game event? * @private */ this._paused = false; /** * @property {boolean} _onDecodedEventDispatched - Was the onDecoded event dispatched? * @private */ this._onDecodedEventDispatched = false; }; Phaser.Sound.prototype = { /** * Called automatically when this sound is unlocked. * @method Phaser.Sound#soundHasUnlocked * @param {string} key - The Phaser.Cache key of the sound file to check for decoding. * @protected */ soundHasUnlocked: function (key) { if (key === this.key) { this._sound = this.game.cache.getSoundData(this.key); this.totalDuration = this._sound.duration; } }, /** * Adds a marker into the current Sound. A marker is represented by a unique key and a start time and duration. * This allows you to bundle multiple sounds together into a single audio file and use markers to jump between them for playback. * * @method Phaser.Sound#addMarker * @param {string} name - A unique name for this marker, i.e. 'explosion', 'gunshot', etc. * @param {number} start - The start point of this marker in the audio file, given in seconds. 2.5 = 2500ms, 0.5 = 500ms, etc. * @param {number} duration - The duration of the marker in seconds. 2.5 = 2500ms, 0.5 = 500ms, etc. * @param {number} [volume=1] - The volume the sound will play back at, between 0 (silent) and 1 (full volume). * @param {boolean} [loop=false] - Sets if the sound will loop or not. */ addMarker: function (name, start, duration, volume, loop) { if (typeof volume == 'undefined') { volume = 1; } if (typeof loop == 'undefined') { loop = false; } this.markers[name] = { name: name, start: start, stop: start + duration, volume: volume, duration: duration, durationMS: duration * 1000, loop: loop }; }, /** * Removes a marker from the sound. * @method Phaser.Sound#removeMarker * @param {string} name - The key of the marker to remove. */ removeMarker: function (name) { delete this.markers[name]; }, /** * Called automatically by Phaser.SoundManager. * @method Phaser.Sound#update * @protected */ update: function () { if (this.isDecoded && !this._onDecodedEventDispatched) { this.onDecoded.dispatch(this); this._onDecodedEventDispatched = true; } if (this.pendingPlayback && this.game.cache.isSoundReady(this.key)) { this.pendingPlayback = false; this.play(this._tempMarker, this._tempPosition, this._tempVolume, this._tempLoop); } if (this.isPlaying) { this.currentTime = this.game.time.now - this.startTime; if (this.currentTime >= this.durationMS) { if (this.usingWebAudio) { if (this.loop) { // won't work with markers, needs to reset the position this.onLoop.dispatch(this); if (this.currentMarker === '') { this.currentTime = 0; this.startTime = this.game.time.now; } else { this.onMarkerComplete.dispatch(this.currentMarker, this); this.play(this.currentMarker, 0, this.volume, true, true); } } else { this.stop(); } } else { if (this.loop) { this.onLoop.dispatch(this); this.play(this.currentMarker, 0, this.volume, true, true); } else { this.stop(); } } } } }, /** * Play this sound, or a marked section of it. * @method Phaser.Sound#play * @param {string} [marker=''] - If you want to play a marker then give the key here, otherwise leave blank to play the full sound. * @param {number} [position=0] - The starting position to play the sound from - this is ignored if you provide a marker. * @param {number} [volume=1] - Volume of the sound you want to play. If none is given it will use the volume given to the Sound when it was created (which defaults to 1 if none was specified). * @param {boolean} [loop=false] - Loop when it finished playing? * @param {boolean} [forceRestart=true] - If the sound is already playing you can set forceRestart to restart it from the beginning. * @return {Phaser.Sound} This sound instance. */ play: function (marker, position, volume, loop, forceRestart) { if (typeof marker === 'undefined') { marker = ''; } if (typeof forceRestart === 'undefined') { forceRestart = true; } if (this.isPlaying && !this.allowMultiple && !forceRestart && !this.override) { // Use Restart instead return this; } if (this.isPlaying && !this.allowMultiple && (this.override || forceRestart)) { if (this.usingWebAudio) { if (typeof this._sound.stop === 'undefined') { this._sound.noteOff(0); } else { this._sound.stop(0); } } else if (this.usingAudioTag) { this._sound.pause(); this._sound.currentTime = 0; } } this.currentMarker = marker; if (marker !== '') { if (this.markers[marker]) { // Playing a marker? Then we default to the marker values this.position = this.markers[marker].start; this.volume = this.markers[marker].volume; this.loop = this.markers[marker].loop; this.duration = this.markers[marker].duration; this.durationMS = this.markers[marker].durationMS; if (typeof volume !== 'undefined') { this.volume = volume; } if (typeof loop !== 'undefined') { this.loop = loop; } this._tempMarker = marker; this._tempPosition = this.position; this._tempVolume = this.volume; this._tempLoop = this.loop; } else { console.warn("Phaser.Sound.play: audio marker " + marker + " doesn't exist"); return this; } } else { position = position || 0; if (typeof volume === 'undefined') { volume = this._volume; } if (typeof loop === 'undefined') { loop = this.loop; } this.position = position; this.volume = volume; this.loop = loop; this.duration = 0; this.durationMS = 0; this._tempMarker = marker; this._tempPosition = position; this._tempVolume = volume; this._tempLoop = loop; } if (this.usingWebAudio) { // Does the sound need decoding? if (this.game.cache.isSoundDecoded(this.key)) { // Do we need to do this every time we play? How about just if the buffer is empty? if (this._buffer === null) { this._buffer = this.game.cache.getSoundData(this.key); } this._sound = this.context.createBufferSource(); this._sound.buffer = this._buffer; if (this.externalNode) { this._sound.connect(this.externalNode); } else { this._sound.connect(this.gainNode); } this.totalDuration = this._sound.buffer.duration; if (this.duration === 0) { // console.log('duration reset'); this.duration = this.totalDuration; this.durationMS = this.totalDuration * 1000; } if (this.loop && marker === '') { this._sound.loop = true; } // Useful to cache this somewhere perhaps? if (typeof this._sound.start === 'undefined') { this._sound.noteGrainOn(0, this.position, this.duration); // this._sound.noteGrainOn(0, this.position, this.duration / 1000); //this._sound.noteOn(0); // the zero is vitally important, crashes iOS6 without it } else { // this._sound.start(0, this.position, this.duration / 1000); this._sound.start(0, this.position, this.duration); } this.isPlaying = true; this.startTime = this.game.time.now; this.currentTime = 0; this.stopTime = this.startTime + this.durationMS; this.onPlay.dispatch(this); } else { this.pendingPlayback = true; if (this.game.cache.getSound(this.key) && this.game.cache.getSound(this.key).isDecoding === false) { this.game.sound.decode(this.key, this); } } } else { if (this.game.cache.getSound(this.key) && this.game.cache.getSound(this.key).locked) { this.game.cache.reloadSound(this.key); this.pendingPlayback = true; } else { if (this._sound && (this.game.device.cocoonJS || this._sound.readyState === 4)) { this._sound.play(); // This doesn't become available until you call play(), wonderful ... this.totalDuration = this._sound.duration; if (this.duration === 0) { this.duration = this.totalDuration; this.durationMS = this.totalDuration * 1000; } this._sound.currentTime = this.position; this._sound.muted = this._muted; if (this._muted) { this._sound.volume = 0; } else { this._sound.volume = this._volume; } this.isPlaying = true; this.startTime = this.game.time.now; this.currentTime = 0; this.stopTime = this.startTime + this.durationMS; this.onPlay.dispatch(this); } else { this.pendingPlayback = true; } } } return this; }, /** * Restart the sound, or a marked section of it. * * @method Phaser.Sound#restart * @param {string} [marker=''] - If you want to play a marker then give the key here, otherwise leave blank to play the full sound. * @param {number} [position=0] - The starting position to play the sound from - this is ignored if you provide a marker. * @param {number} [volume=1] - Volume of the sound you want to play. * @param {boolean} [loop=false] - Loop when it finished playing? */ restart: function (marker, position, volume, loop) { marker = marker || ''; position = position || 0; volume = volume || 1; if (typeof loop == 'undefined') { loop = false; } this.play(marker, position, volume, loop, true); }, /** * Pauses the sound. * * @method Phaser.Sound#pause */ pause: function () { if (this.isPlaying && this._sound) { this.paused = true; this.pausedPosition = this.currentTime; this.pausedTime = this.game.time.now; this.onPause.dispatch(this); this.stop(); } }, /** * Resumes the sound. * * @method Phaser.Sound#resume */ resume: function () { if (this.paused && this._sound) { if (this.usingWebAudio) { var p = this.position + (this.pausedPosition / 1000); this._sound = this.context.createBufferSource(); this._sound.buffer = this._buffer; if (this.externalNode) { this._sound.connect(this.externalNode); } else { this._sound.connect(this.gainNode); } if (this.loop) { this._sound.loop = true; } if (typeof this._sound.start === 'undefined') { this._sound.noteGrainOn(0, p, this.duration); //this._sound.noteOn(0); // the zero is vitally important, crashes iOS6 without it } else { this._sound.start(0, p, this.duration); } } else { this._sound.play(); } this.isPlaying = true; this.paused = false; this.startTime += (this.game.time.now - this.pausedTime); this.onResume.dispatch(this); } }, /** * Stop playing this sound. * * @method Phaser.Sound#stop */ stop: function () { if (this.isPlaying && this._sound) { if (this.usingWebAudio) { if (typeof this._sound.stop === 'undefined') { this._sound.noteOff(0); } else { try { this._sound.stop(0); } catch (e) { // Thanks Android 4.4 } } } else if (this.usingAudioTag) { this._sound.pause(); this._sound.currentTime = 0; } } this.isPlaying = false; var prevMarker = this.currentMarker; if (this.currentMarker !== '') { this.onMarkerComplete.dispatch(this.currentMarker, this); } this.currentMarker = ''; if (!this.paused) { this.onStop.dispatch(this, prevMarker); } }, /** * Starts this sound playing (or restarts it if already doing so) and sets the volume to zero. * Then increases the volume from 0 to 1 over the duration specified. * At the end of the fade Sound.onFadeComplete is dispatched with this Sound object as the first parameter, * and the final volume (1) as the second parameter. * * @method Phaser.Sound#fadeIn * @param {number} [duration=1000] - The time in milliseconds during which the Sound should fade in. * @param {boolean} [loop=false] - Should the Sound be set to loop? Note that this doesn't cause the fade to repeat. */ fadeIn: function (duration, loop) { if (typeof duration === 'undefined') { duration = 1000; } if (typeof loop === 'undefined') { loop = false; } if (this.paused) { return; } this.play('', 0, 0, loop); var tween = this.game.add.tween(this).to( { volume: 1 }, duration, Phaser.Easing.Linear.None, true); tween.onComplete.add(this.fadeComplete, this); }, /** * Decreases the volume of this Sound from its current value to 0 over the duration specified. * At the end of the fade Sound.onFadeComplete is dispatched with this Sound object as the first parameter, * and the final volume (0) as the second parameter. * * @method Phaser.Sound#fadeOut * @param {number} [duration=1000] - The time in milliseconds during which the Sound should fade out. */ fadeOut: function (duration) { if (typeof duration === 'undefined') { duration = 1000; } if (!this.isPlaying || this.paused || this.volume &lt;= 0) { return; } var tween = this.game.add.tween(this).to( { volume: 0 }, duration, Phaser.Easing.Linear.None, true); tween.onComplete.add(this.fadeComplete, this); }, /** * Internal handler for Sound.fadeIn and Sound.fadeOut. * * @method Phaser.Sound#fadeComplete * @private */ fadeComplete: function () { this.onFadeComplete.dispatch(this, this.volume); if (this.volume === 0) { this.stop(); } }, /** * Destroys this sound and all associated events and removes it from the SoundManager. * * @method Phaser.Sound#destroy * @param {boolean} [remove=true] - If true this Sound is automatically removed from the SoundManager. */ destroy: function (remove) { if (typeof remove === 'undefined') { remove = true; } this.stop(); if (remove) { this.game.sound.remove(this); } else { this.markers = {}; this.context = null; this._buffer = null; this.externalNode = null; this.onDecoded.dispose(); this.onPlay.dispose(); this.onPause.dispose(); this.onResume.dispose(); this.onLoop.dispose(); this.onStop.dispose(); this.onMute.dispose(); this.onMarkerComplete.dispose(); } } }; Phaser.Sound.prototype.constructor = Phaser.Sound; /** * @name Phaser.Sound#isDecoding * @property {boolean} isDecoding - Returns true if the sound file is still decoding. * @readonly */ Object.defineProperty(Phaser.Sound.prototype, "isDecoding", { get: function () { return this.game.cache.getSound(this.key).isDecoding; } }); /** * @name Phaser.Sound#isDecoded * @property {boolean} isDecoded - Returns true if the sound file has decoded. * @readonly */ Object.defineProperty(Phaser.Sound.prototype, "isDecoded", { get: function () { return this.game.cache.isSoundDecoded(this.key); } }); /** * @name Phaser.Sound#mute * @property {boolean} mute - Gets or sets the muted state of this sound. */ Object.defineProperty(Phaser.Sound.prototype, "mute", { get: function () { return (this._muted || this.game.sound.mute); }, set: function (value) { value = value || null; if (value) { this._muted = true; if (this.usingWebAudio) { this._muteVolume = this.gainNode.gain.value; this.gainNode.gain.value = 0; } else if (this.usingAudioTag && this._sound) { this._muteVolume = this._sound.volume; this._sound.volume = 0; } } else { this._muted = false; if (this.usingWebAudio) { this.gainNode.gain.value = this._muteVolume; } else if (this.usingAudioTag && this._sound) { this._sound.volume = this._muteVolume; } } this.onMute.dispatch(this); } }); /** * @name Phaser.Sound#volume * @property {number} volume - Gets or sets the volume of this sound, a value between 0 and 1. * @readonly */ Object.defineProperty(Phaser.Sound.prototype, "volume", { get: function () { return this._volume; }, set: function (value) { if (this.usingWebAudio) { this._volume = value; this.gainNode.gain.value = value; } else if (this.usingAudioTag && this._sound) { // Causes an Index size error in Firefox if you don't clamp the value if (value >= 0 && value &lt;= 1) { this._volume = value; this._sound.volume = value; } } } }); </pre> </article> </section> </div> <div class="clearfix"></div> <footer> <span class="copyright"> Phaser Copyright © 2012-2014 Photon Storm Ltd. </span> <br /> <span class="jsdoc-message"> Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.3.0-dev</a> on Thu Oct 09 2014 16:09:45 GMT+0100 (BST) using the <a href="https://github.com/terryweiss/docstrap">DocStrap template</a>. </span> </footer> </div> <br clear="both"> </div> </div> <script src="scripts/sunlight.js"></script> <script src="scripts/sunlight.javascript.js"></script> <script src="scripts/sunlight-plugin.doclinks.js"></script> <script src="scripts/sunlight-plugin.linenumbers.js"></script> <script src="scripts/sunlight-plugin.menu.js"></script> <script src="scripts/jquery.min.js"></script> <script src="scripts/jquery.scrollTo.js"></script> <script src="scripts/jquery.localScroll.js"></script> <script src="scripts/bootstrap-dropdown.js"></script> <script src="scripts/toc.js"></script> <script> Sunlight.highlightAll({lineNumbers:true, showMenu: true, enableDoclinks :true}); </script> <script> $( function () { $( "#toc" ).toc( { anchorName : function(i, heading, prefix) { return $(heading).attr("id") || ( prefix + i ); }, selectors : "h1,h2,h3,h4", showAndHide : false, scrollTo : 60 } ); $( "#toc>ul" ).addClass( "nav nav-pills nav-stacked" ); $( "#main span[id^='toc']" ).addClass( "toc-shim" ); } ); </script> </body> </html>