phaser/src/sound/webaudio/WebAudioSoundManager.js

261 lines
7.3 KiB
JavaScript
Raw Normal View History

2018-02-12 16:01:20 +00:00
/**
* @author Richard Davey <rich@photonstorm.com>
* @copyright 2018 Photon Storm Ltd.
* @license {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
*/
var Class = require('../../utils/Class');
var BaseSoundManager = require('../BaseSoundManager');
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
2018-01-06 18:14:17 +00:00
* @author Pavle Goloskokovic <pgoloskokovic@gmail.com> (http://prunegames.com)
2018-02-12 12:25:30 +00:00
* @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-02-12 12:25:30 +00:00
Extends: BaseSoundManager,
2018-01-26 14:36:41 +00:00
2018-02-12 12:25:30 +00:00
initialize:
function WebAudioSoundManager (game)
2018-01-26 14:36:41 +00:00
{
2017-11-10 11:55:32 +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
*/
this.context = this.createAudioContext(game);
2018-01-26 14:36:41 +00:00
/**
2018-01-06 18:14:43 +00:00
* Gain node responsible for controlling global muting.
*
2018-02-12 12:25:30 +00:00
* @name Phaser.Sound.WebAudioSoundManager#masterMuteNode
* @type {GainNode}
* @since 3.0.0
*/
this.masterMuteNode = this.context.createGain();
2018-01-26 14:36:41 +00:00
/**
2018-01-06 18:14:43 +00:00
* Gain node responsible for controlling global volume.
*
2018-02-12 12:25:30 +00:00
* @name Phaser.Sound.WebAudioSoundManager#masterVolumeNode
* @type {GainNode}
* @since 3.0.0
*/
this.masterVolumeNode = this.context.createGain();
2018-02-12 12:25:30 +00:00
this.masterMuteNode.connect(this.masterVolumeNode);
2018-02-12 12:25:30 +00:00
this.masterVolumeNode.connect(this.context.destination);
2018-01-26 14:36:41 +00:00
/**
* Destination node for connecting individual sounds to.
*
2018-02-12 12:25:30 +00:00
* @name Phaser.Sound.WebAudioSoundManager#destination
* @type {AudioNode}
* @since 3.0.0
*/
this.destination = this.masterMuteNode;
2018-02-12 12:25:30 +00:00
/**
* Is the Sound Manager touch locked?
*
* @name Phaser.Sound.WebAudioSoundManager#locked
* @type {boolean}
* @since 3.0.0
*/
this.locked = this.context.state === 'suspended' && 'ontouchstart' in window;
2018-02-12 12:25:30 +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)
{
var audioConfig = game.config.audio;
2018-02-12 12:25:30 +00:00
2018-01-26 14:36:41 +00:00
if (audioConfig && audioConfig.context)
{
audioConfig.context.resume();
return audioConfig.context;
2017-11-10 11:55:32 +00:00
}
2018-02-12 12:25:30 +00:00
return new AudioContext();
},
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.
* @param {ISoundConfig} [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)
{
var sound = new WebAudioSound(this, key, config);
2018-02-12 12:25:30 +00:00
this.sounds.push(sound);
2018-02-12 12:25:30 +00:00
return sound;
},
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-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
* @private
* @since 3.0.0
2017-11-26 15:19:56 +00:00
*/
2018-01-26 14:36:41 +00:00
unlock: function ()
{
var _this = this;
2018-02-12 12:25:30 +00:00
2018-01-26 14:36:41 +00:00
var unlock = function ()
{
_this.context.resume().then(function ()
{
document.body.removeEventListener('touchstart', unlock);
document.body.removeEventListener('touchend', unlock);
_this.unlocked = true;
});
};
2018-02-12 12:25:30 +00:00
document.body.addEventListener('touchstart', unlock, false);
document.body.addEventListener('touchend', unlock, false);
},
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 ()
{
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 ()
{
this.context.resume();
},
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 ()
{
BaseSoundManager.prototype.destroy.call(this);
this.destination = null;
this.masterVolumeNode.disconnect();
this.masterVolumeNode = null;
this.masterMuteNode.disconnect();
this.masterMuteNode = null;
this.context.suspend();
this.context = null;
2017-11-10 11:55:32 +00:00
}
});
2018-01-26 14:36:41 +00:00
/**
* Global mute setting.
2018-01-06 18:20:13 +00:00
*
* @name Phaser.Sound.WebAudioSoundManager#mute
2018-02-12 12:25:30 +00:00
* @type {boolean}
*/
Object.defineProperty(WebAudioSoundManager.prototype, 'mute', {
2018-02-12 12:25:30 +00:00
2018-01-26 14:36:41 +00:00
get: function ()
{
return this.masterMuteNode.gain.value === 0;
},
2018-02-12 12:25:30 +00:00
2018-01-26 14:36:41 +00:00
set: function (value)
{
this.masterMuteNode.gain.setValueAtTime(value ? 0 : 1, 0);
2018-01-26 14:36:41 +00:00
2018-01-26 14:09:55 +00:00
/**
* @event Phaser.Sound.WebAudioSoundManager#mute
* @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.
*/
this.emit('mute', this, value);
}
2018-02-12 12:25:30 +00:00
});
2018-01-26 14:36:41 +00:00
/**
* Global volume setting.
2018-01-06 18:20:28 +00:00
*
* @name Phaser.Sound.WebAudioSoundManager#volume
2018-02-12 12:25:30 +00:00
* @type {number}
*/
Object.defineProperty(WebAudioSoundManager.prototype, 'volume', {
2018-02-12 12:25:30 +00:00
2018-01-26 14:36:41 +00:00
get: function ()
{
return this.masterVolumeNode.gain.value;
},
2018-02-12 12:25:30 +00:00
2018-01-26 14:36:41 +00:00
set: function (value)
{
this.masterVolumeNode.gain.setValueAtTime(value, 0);
2018-01-26 14:36:41 +00:00
2018-01-26 14:10:10 +00:00
/**
* @event Phaser.Sound.WebAudioSoundManager#volume
* @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.
*/
this.emit('volume', this, value);
}
2018-02-12 12:25:30 +00:00
});
2018-02-12 12:25:30 +00:00
2017-11-10 11:55:32 +00:00
module.exports = WebAudioSoundManager;