2018-02-12 16:01:20 +00:00
|
|
|
/**
|
|
|
|
* @author Richard Davey <rich@photonstorm.com>
|
2018-03-21 14:54:23 +00:00
|
|
|
* @author Pavle Goloskokovic <pgoloskokovic@gmail.com> (http://prunegames.com)
|
2018-02-12 16:01:20 +00:00
|
|
|
* @copyright 2018 Photon Storm Ltd.
|
|
|
|
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
|
|
|
|
*/
|
2018-03-05 13:39:08 +00:00
|
|
|
|
2017-11-17 13:17:59 +00:00
|
|
|
var BaseSoundManager = require('../BaseSoundManager');
|
2018-03-05 13:39:08 +00:00
|
|
|
var Class = require('../../utils/Class');
|
2017-11-14 16:35:44 +00:00
|
|
|
var WebAudioSound = require('./WebAudioSound');
|
2018-01-26 14:36:41 +00:00
|
|
|
|
2018-02-12 12:25:30 +00:00
|
|
|
/**
|
|
|
|
* @classdesc
|
|
|
|
* Web Audio API implementation of the sound manager.
|
|
|
|
*
|
|
|
|
* @class WebAudioSoundManager
|
|
|
|
* @extends Phaser.Sound.BaseSoundManager
|
|
|
|
* @memberOf Phaser.Sound
|
|
|
|
* @constructor
|
|
|
|
* @since 3.0.0
|
2018-02-18 19:01:01 +00:00
|
|
|
*
|
2018-02-12 12:25:30 +00:00
|
|
|
* @param {Phaser.Game} game - Reference to the current game instance.
|
2018-01-06 18:14:17 +00:00
|
|
|
*/
|
2017-11-10 11:55:32 +00:00
|
|
|
var WebAudioSoundManager = new Class({
|
2018-03-05 13:39:08 +00:00
|
|
|
|
2017-11-10 12:05:29 +00:00
|
|
|
Extends: BaseSoundManager,
|
2018-03-05 13:39:08 +00:00
|
|
|
|
|
|
|
initialize:
|
|
|
|
|
|
|
|
function WebAudioSoundManager (game)
|
2018-01-26 14:36:41 +00:00
|
|
|
{
|
2017-11-10 11:55:32 +00:00
|
|
|
/**
|
2017-11-15 13:38:45 +00:00
|
|
|
* The AudioContext being used for playback.
|
|
|
|
*
|
2018-02-12 12:25:30 +00:00
|
|
|
* @name Phaser.Sound.WebAudioSoundManager#context
|
|
|
|
* @type {AudioContext}
|
2018-02-18 19:01:01 +00:00
|
|
|
* @private
|
2018-02-12 12:25:30 +00:00
|
|
|
* @since 3.0.0
|
2017-11-10 11:55:32 +00:00
|
|
|
*/
|
2017-11-15 14:11:37 +00:00
|
|
|
this.context = this.createAudioContext(game);
|
2018-01-26 14:36:41 +00:00
|
|
|
|
2017-11-15 16:49:23 +00:00
|
|
|
/**
|
2018-01-06 18:14:43 +00:00
|
|
|
* Gain node responsible for controlling global muting.
|
2017-11-15 16:49:23 +00:00
|
|
|
*
|
2018-02-12 12:25:30 +00:00
|
|
|
* @name Phaser.Sound.WebAudioSoundManager#masterMuteNode
|
|
|
|
* @type {GainNode}
|
2018-02-18 19:01:29 +00:00
|
|
|
* @private
|
2018-02-12 12:25:30 +00:00
|
|
|
* @since 3.0.0
|
2017-11-15 16:49:23 +00:00
|
|
|
*/
|
2018-01-06 14:12:39 +00:00
|
|
|
this.masterMuteNode = this.context.createGain();
|
2018-01-26 14:36:41 +00:00
|
|
|
|
2017-11-15 13:38:45 +00:00
|
|
|
/**
|
2018-01-06 18:14:43 +00:00
|
|
|
* Gain node responsible for controlling global volume.
|
2017-11-15 13:38:45 +00:00
|
|
|
*
|
2018-02-12 12:25:30 +00:00
|
|
|
* @name Phaser.Sound.WebAudioSoundManager#masterVolumeNode
|
|
|
|
* @type {GainNode}
|
2018-02-18 19:01:45 +00:00
|
|
|
* @private
|
2018-02-12 12:25:30 +00:00
|
|
|
* @since 3.0.0
|
2017-11-15 13:38:45 +00:00
|
|
|
*/
|
2018-01-06 14:12:39 +00:00
|
|
|
this.masterVolumeNode = this.context.createGain();
|
2018-03-05 13:39:08 +00:00
|
|
|
|
2017-11-15 16:49:23 +00:00
|
|
|
this.masterMuteNode.connect(this.masterVolumeNode);
|
2018-03-05 13:39:08 +00:00
|
|
|
|
2017-11-15 16:49:23 +00:00
|
|
|
this.masterVolumeNode.connect(this.context.destination);
|
2018-01-26 14:36:41 +00:00
|
|
|
|
2017-11-15 13:46:12 +00:00
|
|
|
/**
|
|
|
|
* Destination node for connecting individual sounds to.
|
|
|
|
*
|
2018-02-12 12:25:30 +00:00
|
|
|
* @name Phaser.Sound.WebAudioSoundManager#destination
|
|
|
|
* @type {AudioNode}
|
2018-02-18 19:02:06 +00:00
|
|
|
* @private
|
2018-02-12 12:25:30 +00:00
|
|
|
* @since 3.0.0
|
2017-11-15 13:46:12 +00:00
|
|
|
*/
|
2017-11-15 16:49:23 +00:00
|
|
|
this.destination = this.masterMuteNode;
|
2018-03-05 13:39:08 +00:00
|
|
|
|
2018-01-17 17:13:04 +00:00
|
|
|
this.locked = this.context.state === 'suspended' && 'ontouchstart' in window;
|
2018-03-05 13:39:08 +00:00
|
|
|
|
2017-11-15 14:11:37 +00:00
|
|
|
BaseSoundManager.call(this, game);
|
2017-11-10 11:55:32 +00:00
|
|
|
},
|
2018-01-26 14:36:41 +00:00
|
|
|
|
2017-11-26 15:19:56 +00:00
|
|
|
/**
|
2018-01-06 18:17:19 +00:00
|
|
|
* Method responsible for instantiating and returning AudioContext instance.
|
|
|
|
* If an instance of an AudioContext class was provided trough the game config,
|
|
|
|
* that instance will be returned instead. This can come in handy if you are reloading
|
|
|
|
* a Phaser game on a page that never properly refreshes (such as in an SPA project)
|
|
|
|
* and you want to reuse already instantiated AudioContext.
|
|
|
|
*
|
|
|
|
* @method Phaser.Sound.WebAudioSoundManager#createAudioContext
|
2018-02-12 12:25:30 +00:00
|
|
|
* @private
|
|
|
|
* @since 3.0.0
|
2018-02-18 19:01:01 +00:00
|
|
|
*
|
2018-01-06 18:17:19 +00:00
|
|
|
* @param {Phaser.Game} game - Reference to the current game instance.
|
2018-02-18 19:01:01 +00:00
|
|
|
*
|
2018-02-12 12:25:30 +00:00
|
|
|
* @return {AudioContext} The AudioContext instance to be used for playback.
|
2017-11-26 15:19:56 +00:00
|
|
|
*/
|
2018-01-26 14:36:41 +00:00
|
|
|
createAudioContext: function (game)
|
|
|
|
{
|
2017-11-15 14:11:37 +00:00
|
|
|
var audioConfig = game.config.audio;
|
2018-03-05 13:39:08 +00:00
|
|
|
|
2018-01-26 14:36:41 +00:00
|
|
|
if (audioConfig && audioConfig.context)
|
|
|
|
{
|
2018-01-31 13:09:01 +00:00
|
|
|
audioConfig.context.resume();
|
2018-03-21 14:54:23 +00:00
|
|
|
|
2017-11-10 18:05:26 +00:00
|
|
|
return audioConfig.context;
|
2017-11-10 11:55:32 +00:00
|
|
|
}
|
2018-03-05 13:39:08 +00:00
|
|
|
|
2018-01-07 22:04:11 +00:00
|
|
|
return new AudioContext();
|
2017-11-14 16:35:44 +00:00
|
|
|
},
|
2018-01-26 14:36:41 +00:00
|
|
|
|
2018-01-06 18:18:00 +00:00
|
|
|
/**
|
|
|
|
* Adds a new sound into the sound manager.
|
|
|
|
*
|
|
|
|
* @method Phaser.Sound.WebAudioSoundManager#add
|
2018-02-12 12:25:30 +00:00
|
|
|
* @since 3.0.0
|
2018-02-18 19:01:01 +00:00
|
|
|
*
|
2018-01-06 18:18:00 +00:00
|
|
|
* @param {string} key - Asset key for the sound.
|
2018-02-18 19:02:57 +00:00
|
|
|
* @param {SoundConfig} [config] - An optional config object containing default sound settings.
|
2018-02-18 19:01:01 +00:00
|
|
|
*
|
2018-02-12 12:25:30 +00:00
|
|
|
* @return {Phaser.Sound.WebAudioSound} The new sound instance.
|
2018-01-06 18:18:00 +00:00
|
|
|
*/
|
2018-01-26 14:36:41 +00:00
|
|
|
add: function (key, config)
|
|
|
|
{
|
2017-11-14 16:35:44 +00:00
|
|
|
var sound = new WebAudioSound(this, key, config);
|
2018-03-05 13:39:08 +00:00
|
|
|
|
2017-11-14 16:35:44 +00:00
|
|
|
this.sounds.push(sound);
|
2018-03-05 13:39:08 +00:00
|
|
|
|
2017-11-14 16:35:44 +00:00
|
|
|
return sound;
|
2017-11-21 14:43:10 +00:00
|
|
|
},
|
2018-01-26 14:36:41 +00:00
|
|
|
|
2017-11-26 15:19:56 +00:00
|
|
|
/**
|
2018-01-06 18:18:48 +00:00
|
|
|
* Unlocks Web Audio API on iOS devices on the initial touch event.
|
2018-01-17 13:10:54 +00:00
|
|
|
*
|
2018-01-26 14:09:22 +00:00
|
|
|
* Read more about how this issue is handled here in [this article](https://medium.com/@pgoloskokovic/unlocking-web-audio-the-smarter-way-8858218c0e09).
|
2018-01-06 18:18:48 +00:00
|
|
|
*
|
|
|
|
* @method Phaser.Sound.WebAudioSoundManager#unlock
|
2018-02-12 12:25:30 +00:00
|
|
|
* @since 3.0.0
|
2017-11-26 15:19:56 +00:00
|
|
|
*/
|
2018-01-26 14:36:41 +00:00
|
|
|
unlock: function ()
|
|
|
|
{
|
2017-11-21 14:43:10 +00:00
|
|
|
var _this = this;
|
2018-03-05 13:39:08 +00:00
|
|
|
|
2018-01-26 14:36:41 +00:00
|
|
|
var unlock = function ()
|
|
|
|
{
|
|
|
|
_this.context.resume().then(function ()
|
|
|
|
{
|
2018-01-17 17:13:52 +00:00
|
|
|
document.body.removeEventListener('touchstart', unlock);
|
|
|
|
document.body.removeEventListener('touchend', unlock);
|
2018-01-17 17:14:28 +00:00
|
|
|
_this.unlocked = true;
|
2018-01-17 17:13:52 +00:00
|
|
|
});
|
|
|
|
};
|
2018-03-05 13:39:08 +00:00
|
|
|
|
2018-01-17 17:13:52 +00:00
|
|
|
document.body.addEventListener('touchstart', unlock, false);
|
|
|
|
document.body.addEventListener('touchend', unlock, false);
|
2017-11-21 17:09:30 +00:00
|
|
|
},
|
2018-01-26 14:36:41 +00:00
|
|
|
|
2018-01-06 18:19:37 +00:00
|
|
|
/**
|
2018-01-07 21:12:04 +00:00
|
|
|
* Method used internally for pausing sound manager if
|
|
|
|
* Phaser.Sound.WebAudioSoundManager#pauseOnBlur is set to true.
|
|
|
|
*
|
2018-01-06 18:19:37 +00:00
|
|
|
* @method Phaser.Sound.WebAudioSoundManager#onBlur
|
2018-02-12 12:25:30 +00:00
|
|
|
* @protected
|
|
|
|
* @since 3.0.0
|
2018-01-06 18:19:37 +00:00
|
|
|
*/
|
2018-01-26 14:36:41 +00:00
|
|
|
onBlur: function ()
|
|
|
|
{
|
2017-11-21 17:09:30 +00:00
|
|
|
this.context.suspend();
|
|
|
|
},
|
2018-01-26 14:36:41 +00:00
|
|
|
|
2018-01-06 18:19:48 +00:00
|
|
|
/**
|
2018-01-07 21:12:17 +00:00
|
|
|
* Method used internally for resuming sound manager if
|
|
|
|
* Phaser.Sound.WebAudioSoundManager#pauseOnBlur is set to true.
|
|
|
|
*
|
2018-01-06 18:19:48 +00:00
|
|
|
* @method Phaser.Sound.WebAudioSoundManager#onFocus
|
2018-02-12 12:25:30 +00:00
|
|
|
* @protected
|
|
|
|
* @since 3.0.0
|
2018-01-06 18:19:48 +00:00
|
|
|
*/
|
2018-01-26 14:36:41 +00:00
|
|
|
onFocus: function ()
|
|
|
|
{
|
2017-11-21 17:09:30 +00:00
|
|
|
this.context.resume();
|
2018-01-07 19:20:01 +00:00
|
|
|
},
|
2018-01-26 14:36:41 +00:00
|
|
|
|
2018-01-07 19:20:32 +00:00
|
|
|
/**
|
|
|
|
* Calls Phaser.Sound.BaseSoundManager#destroy method
|
|
|
|
* and cleans up all Web Audio API related stuff.
|
|
|
|
*
|
|
|
|
* @method Phaser.Sound.WebAudioSoundManager#destroy
|
2018-02-12 12:25:30 +00:00
|
|
|
* @since 3.0.0
|
2018-01-07 19:20:32 +00:00
|
|
|
*/
|
2018-01-26 14:36:41 +00:00
|
|
|
destroy: function ()
|
|
|
|
{
|
2018-01-07 19:20:01 +00:00
|
|
|
this.destination = null;
|
|
|
|
this.masterVolumeNode.disconnect();
|
|
|
|
this.masterVolumeNode = null;
|
|
|
|
this.masterMuteNode.disconnect();
|
|
|
|
this.masterMuteNode = null;
|
2018-03-05 13:39:08 +00:00
|
|
|
|
2018-02-19 15:17:06 +00:00
|
|
|
if (this.game.config.audio && this.game.config.audio.context)
|
|
|
|
{
|
|
|
|
this.context.suspend();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
this.context.close();
|
|
|
|
}
|
2018-03-05 13:39:08 +00:00
|
|
|
|
2018-01-07 19:20:01 +00:00
|
|
|
this.context = null;
|
2018-03-05 13:39:08 +00:00
|
|
|
|
2018-02-18 20:52:51 +00:00
|
|
|
BaseSoundManager.prototype.destroy.call(this);
|
2017-11-15 14:11:37 +00:00
|
|
|
},
|
2018-01-26 14:36:41 +00:00
|
|
|
|
2018-03-05 13:39:08 +00:00
|
|
|
/**
|
2018-03-28 13:13:30 +00:00
|
|
|
* @event Phaser.Sound.WebAudioSoundManager#muteEvent
|
2018-03-05 13:39:08 +00:00
|
|
|
* @param {Phaser.Sound.WebAudioSoundManager} soundManager - Reference to the sound manager that emitted event.
|
|
|
|
* @param {boolean} value - An updated value of Phaser.Sound.WebAudioSoundManager#mute property.
|
|
|
|
*/
|
|
|
|
|
2018-03-21 14:54:23 +00:00
|
|
|
/**
|
|
|
|
* Sets the muted state of all this Sound Manager.
|
|
|
|
*
|
|
|
|
* @method Phaser.Sound.WebAudioSoundManager#setMute
|
2018-03-28 13:13:30 +00:00
|
|
|
* @fires Phaser.Sound.WebAudioSoundManager#muteEvent
|
2018-03-21 14:54:23 +00:00
|
|
|
* @since 3.3.0
|
|
|
|
*
|
|
|
|
* @param {boolean} value - `true` to mute all sounds, `false` to unmute them.
|
|
|
|
*
|
|
|
|
* @return {Phaser.Sound.WebAudioSoundManager} This Sound Manager.
|
|
|
|
*/
|
2018-03-22 13:22:23 +00:00
|
|
|
setMute: function (value)
|
|
|
|
{
|
2018-03-21 14:54:23 +00:00
|
|
|
this.mute = value;
|
|
|
|
|
|
|
|
return this;
|
2018-03-22 13:22:23 +00:00
|
|
|
},
|
2018-03-21 14:54:23 +00:00
|
|
|
|
2018-03-05 13:39:08 +00:00
|
|
|
/**
|
|
|
|
* @name Phaser.Sound.WebAudioSoundManager#mute
|
|
|
|
* @type {boolean}
|
|
|
|
* @fires Phaser.Sound.WebAudioSoundManager#MuteEvent
|
|
|
|
* @since 3.0.0
|
|
|
|
*/
|
|
|
|
mute: {
|
|
|
|
|
|
|
|
get: function ()
|
|
|
|
{
|
|
|
|
return (this.masterMuteNode.gain.value === 0);
|
|
|
|
},
|
|
|
|
|
|
|
|
set: function (value)
|
|
|
|
{
|
|
|
|
this.masterMuteNode.gain.setValueAtTime(value ? 0 : 1, 0);
|
|
|
|
|
|
|
|
this.emit('mute', this, value);
|
|
|
|
}
|
|
|
|
|
2017-11-15 14:31:24 +00:00
|
|
|
},
|
2018-01-26 14:36:41 +00:00
|
|
|
|
2018-03-05 13:39:08 +00:00
|
|
|
/**
|
|
|
|
* @event Phaser.Sound.WebAudioSoundManager#VolumeEvent
|
|
|
|
* @param {Phaser.Sound.WebAudioSoundManager} soundManager - Reference to the sound manager that emitted event.
|
|
|
|
* @param {number} value - An updated value of Phaser.Sound.WebAudioSoundManager#volume property.
|
|
|
|
*/
|
|
|
|
|
2018-03-21 14:54:23 +00:00
|
|
|
/**
|
|
|
|
* Sets the volume of this Sound Manager.
|
|
|
|
*
|
|
|
|
* @method Phaser.Sound.WebAudioSoundManager#setVolume
|
|
|
|
* @fires Phaser.Sound.WebAudioSoundManager#VolumeEvent
|
|
|
|
* @since 3.3.0
|
|
|
|
*
|
|
|
|
* @param {number} value - The global volume of this Sound Manager.
|
|
|
|
*
|
|
|
|
* @return {Phaser.Sound.WebAudioSoundManager} This Sound Manager.
|
|
|
|
*/
|
2018-03-22 13:22:23 +00:00
|
|
|
setVolume: function (value)
|
|
|
|
{
|
2018-03-21 14:54:23 +00:00
|
|
|
this.volume = value;
|
|
|
|
|
|
|
|
return this;
|
2018-03-22 13:22:23 +00:00
|
|
|
},
|
2018-03-21 14:54:23 +00:00
|
|
|
|
2018-03-05 13:39:08 +00:00
|
|
|
/**
|
|
|
|
* @name Phaser.Sound.WebAudioSoundManager#volume
|
|
|
|
* @type {number}
|
|
|
|
* @fires Phaser.Sound.WebAudioSoundManager#VolumeEvent
|
|
|
|
* @since 3.0.0
|
|
|
|
*/
|
|
|
|
volume: {
|
|
|
|
|
|
|
|
get: function ()
|
|
|
|
{
|
|
|
|
return this.masterVolumeNode.gain.value;
|
|
|
|
},
|
|
|
|
|
|
|
|
set: function (value)
|
|
|
|
{
|
|
|
|
this.masterVolumeNode.gain.setValueAtTime(value, 0);
|
|
|
|
|
|
|
|
this.emit('volume', this, value);
|
|
|
|
}
|
|
|
|
|
2017-11-15 14:31:24 +00:00
|
|
|
}
|
2018-03-05 13:39:08 +00:00
|
|
|
|
2017-11-15 14:31:24 +00:00
|
|
|
});
|
2018-03-05 13:39:08 +00:00
|
|
|
|
2017-11-10 11:55:32 +00:00
|
|
|
module.exports = WebAudioSoundManager;
|