2017-11-14 15:00:24 +00:00
|
|
|
var Class = require('../utils/Class');
|
|
|
|
var Extend = require('../utils/object/Extend');
|
|
|
|
var EventDispatcher = require('../events/EventDispatcher');
|
2017-11-23 12:19:22 +00:00
|
|
|
var NOOP = require('../utils/NOOP');
|
2018-01-06 14:45:42 +00:00
|
|
|
/*!
|
|
|
|
* @author Pavle Goloskokovic <pgoloskokovic@gmail.com> (http://prunegames.com)
|
|
|
|
*/
|
2017-11-14 15:00:24 +00:00
|
|
|
var BaseSound = new Class({
|
2018-01-06 14:45:42 +00:00
|
|
|
/**
|
|
|
|
* @class Phaser.Sound.BaseSound
|
|
|
|
* @constructor
|
|
|
|
* @param {ISoundManager} manager - Reference to the current sound manager instance.
|
|
|
|
* @param {string} key - Asset key for the sound.
|
|
|
|
* @param {ISoundConfig} [config] - An optional config object containing default sound settings.
|
|
|
|
*/
|
2017-11-14 15:00:24 +00:00
|
|
|
initialize: function BaseSound(manager, key, config) {
|
|
|
|
/**
|
2017-11-15 16:26:20 +00:00
|
|
|
* Local reference to the sound manager.
|
|
|
|
*
|
2017-12-04 21:09:41 +00:00
|
|
|
* @private
|
2017-11-14 15:00:24 +00:00
|
|
|
* @property {Phaser.Sound.BaseSoundManager} manager
|
|
|
|
*/
|
|
|
|
this.manager = manager;
|
2017-11-15 16:26:20 +00:00
|
|
|
/**
|
2018-01-06 14:47:58 +00:00
|
|
|
* Asset key for the sound.
|
2017-11-15 16:26:20 +00:00
|
|
|
*
|
2018-01-06 14:47:58 +00:00
|
|
|
* @readonly
|
2017-11-15 16:26:20 +00:00
|
|
|
* @property {string} key
|
|
|
|
*/
|
2017-11-14 15:00:24 +00:00
|
|
|
this.key = key;
|
2018-01-03 20:55:41 +00:00
|
|
|
/**
|
2018-01-06 14:47:58 +00:00
|
|
|
* Event dispatcher used to handle all sound instance relevant events.
|
2018-01-03 20:55:41 +00:00
|
|
|
*
|
2018-01-06 14:47:58 +00:00
|
|
|
* @readonly
|
2018-01-03 20:55:41 +00:00
|
|
|
* @property {Phaser.Events.EventDispatcher}
|
|
|
|
*/
|
|
|
|
this.events = new EventDispatcher();
|
2017-12-05 18:24:17 +00:00
|
|
|
/**
|
|
|
|
* Flag indicating if sound is currently playing.
|
|
|
|
*
|
|
|
|
* @readonly
|
|
|
|
* @property {boolean} isPlaying
|
|
|
|
*/
|
|
|
|
this.isPlaying = false;
|
|
|
|
/**
|
|
|
|
* Flag indicating if sound is currently paused.
|
|
|
|
*
|
|
|
|
* @readonly
|
|
|
|
* @property {boolean} isPaused
|
|
|
|
*/
|
|
|
|
this.isPaused = false;
|
2017-12-05 18:28:08 +00:00
|
|
|
/**
|
|
|
|
* A property that holds the value of sound's actual playback rate,
|
|
|
|
* after its rate and detune values has been combined with global
|
|
|
|
* rate and detune values.
|
|
|
|
*
|
2018-01-06 14:47:58 +00:00
|
|
|
* @readonly
|
2017-12-05 18:28:08 +00:00
|
|
|
* @property {number} totalRate
|
|
|
|
*/
|
|
|
|
this.totalRate = 1;
|
2017-12-06 17:06:05 +00:00
|
|
|
/**
|
|
|
|
* A value representing the duration, in seconds.
|
|
|
|
* It could be total sound duration or a marker duration.
|
|
|
|
*
|
|
|
|
* @readonly
|
|
|
|
* @property {number} duration
|
|
|
|
*/
|
2017-12-06 17:07:43 +00:00
|
|
|
this.duration = this.duration || 0;
|
2017-12-06 17:06:05 +00:00
|
|
|
/**
|
2018-01-06 14:47:58 +00:00
|
|
|
* The total duration of the sound in seconds.
|
2017-12-06 17:06:05 +00:00
|
|
|
*
|
|
|
|
* @readonly
|
|
|
|
* @property {number}
|
|
|
|
*/
|
2017-12-06 17:07:43 +00:00
|
|
|
this.totalDuration = this.totalDuration || 0;
|
2017-12-06 17:04:18 +00:00
|
|
|
/**
|
2018-01-06 14:47:58 +00:00
|
|
|
* A config object used to store default sound settings' values.
|
2017-12-06 17:04:18 +00:00
|
|
|
* Default values will be set by properties' setters.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @property {ISoundConfig} config
|
|
|
|
*/
|
2017-12-13 21:25:22 +00:00
|
|
|
this.config = {
|
|
|
|
/**
|
|
|
|
* Initializing delay config setting
|
|
|
|
*/
|
|
|
|
delay: 0
|
|
|
|
};
|
2017-12-06 17:04:18 +00:00
|
|
|
/**
|
|
|
|
* Reference to the currently used config.
|
|
|
|
* It could be default config or marker config.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @property {ISoundConfig} currentConfig
|
|
|
|
*/
|
|
|
|
this.currentConfig = this.config;
|
2017-11-15 16:26:20 +00:00
|
|
|
/**
|
2017-12-07 19:57:05 +00:00
|
|
|
* Boolean indicating whether the sound is muted or not.
|
|
|
|
* Gets or sets the muted state of this sound.
|
2017-11-15 16:26:20 +00:00
|
|
|
*
|
|
|
|
* @property {boolean} mute
|
|
|
|
*/
|
2017-11-14 15:00:24 +00:00
|
|
|
this.mute = false;
|
2017-11-15 16:26:20 +00:00
|
|
|
/**
|
2017-12-07 19:56:51 +00:00
|
|
|
* Gets or sets the volume of this sound,
|
|
|
|
* a value between 0 (silence) and 1 (full volume).
|
2017-11-15 16:26:20 +00:00
|
|
|
*
|
|
|
|
* @property {number} volume
|
|
|
|
*/
|
2017-11-14 15:00:24 +00:00
|
|
|
this.volume = 1;
|
2017-11-15 16:26:20 +00:00
|
|
|
/**
|
2017-11-16 14:23:04 +00:00
|
|
|
* Defines the speed at which the audio asset will be played.
|
|
|
|
* Value of 1.0 plays the audio at full speed, 0.5 plays the audio
|
|
|
|
* at half speed and 2.0 doubles the audio's playback speed.
|
|
|
|
* This value gets multiplied by global rate to have the final playback speed.
|
2017-11-15 16:26:20 +00:00
|
|
|
*
|
|
|
|
* @property {number} rate
|
|
|
|
*/
|
2017-11-14 15:00:24 +00:00
|
|
|
this.rate = 1;
|
2017-11-16 15:41:48 +00:00
|
|
|
/**
|
|
|
|
* Represents detuning of sound in [cents](https://en.wikipedia.org/wiki/Cent_%28music%29).
|
|
|
|
* The range of the value is -1200 to 1200, but we recommend setting it to [50](https://en.wikipedia.org/wiki/50_Cent).
|
|
|
|
*
|
|
|
|
* @property {number} detune
|
|
|
|
*/
|
|
|
|
this.detune = 0;
|
2017-11-15 16:26:20 +00:00
|
|
|
/**
|
2017-12-07 19:56:34 +00:00
|
|
|
* Property representing the position of playback for this sound, in seconds.
|
|
|
|
* Setting it to a specific value moves current playback to that position.
|
|
|
|
* The value given is clamped to the range 0 to current marker duration.
|
|
|
|
* Setting seek of a stopped sound has no effect.
|
2017-11-15 16:26:20 +00:00
|
|
|
*
|
|
|
|
* @property {number} seek
|
|
|
|
*/
|
2017-11-14 15:00:24 +00:00
|
|
|
this.seek = 0;
|
2017-11-15 16:26:20 +00:00
|
|
|
/**
|
2018-01-06 14:47:58 +00:00
|
|
|
* Flag indicating whether or not the sound or current sound marker will loop.
|
2017-11-15 16:26:20 +00:00
|
|
|
*
|
|
|
|
* @property {boolean} loop
|
|
|
|
*/
|
2017-11-14 15:00:24 +00:00
|
|
|
this.loop = false;
|
2017-11-15 16:26:20 +00:00
|
|
|
this.config = Extend(this.config, config);
|
|
|
|
/**
|
|
|
|
* Object containing markers definitions.
|
|
|
|
*
|
2017-12-04 21:09:41 +00:00
|
|
|
* @readonly
|
2017-11-15 16:26:20 +00:00
|
|
|
* @property {{}} markers
|
|
|
|
*/
|
|
|
|
this.markers = {};
|
|
|
|
/**
|
2017-11-22 17:03:44 +00:00
|
|
|
* Currently playing marker.
|
|
|
|
* 'null' if whole sound is playing.
|
2017-11-15 16:26:20 +00:00
|
|
|
*
|
2017-12-04 21:09:41 +00:00
|
|
|
* @readonly
|
2017-11-22 17:03:44 +00:00
|
|
|
* @property {ISoundMarker} currentMarker
|
2017-11-15 16:26:20 +00:00
|
|
|
*/
|
2017-11-22 17:03:44 +00:00
|
|
|
this.currentMarker = null;
|
2018-01-04 18:37:20 +00:00
|
|
|
/**
|
|
|
|
* Flag indicating if destroy method was called on this sound.
|
|
|
|
*
|
|
|
|
* @private
|
|
|
|
* @property {boolean} pendingRemove
|
|
|
|
*/
|
|
|
|
this.pendingRemove = false;
|
2017-11-14 15:00:24 +00:00
|
|
|
},
|
2018-01-06 14:50:14 +00:00
|
|
|
/**
|
|
|
|
* Adds a marker into the current sound. A marker is represented by name, start time, duration, and optionally config object.
|
|
|
|
* 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.BaseSound#addMarker
|
|
|
|
* @param {ISoundMarker} marker - Marker object
|
|
|
|
* @returns {boolean} Whether the marker was added successfully
|
|
|
|
*/
|
2017-11-14 15:00:24 +00:00
|
|
|
addMarker: function (marker) {
|
2017-11-23 11:31:34 +00:00
|
|
|
if (!marker) {
|
2017-11-23 11:52:19 +00:00
|
|
|
console.error('addMarker - Marker object has to be provided!');
|
2017-11-23 11:31:34 +00:00
|
|
|
return false;
|
|
|
|
}
|
2017-11-23 11:34:43 +00:00
|
|
|
if (!marker.name || typeof marker.name !== 'string') {
|
2017-11-23 11:52:19 +00:00
|
|
|
console.error('addMarker - Marker has to have a valid name!');
|
2017-11-23 11:37:10 +00:00
|
|
|
return false;
|
2017-11-23 11:34:43 +00:00
|
|
|
}
|
2017-11-23 11:35:55 +00:00
|
|
|
if (this.markers[marker.name]) {
|
2017-11-23 11:52:19 +00:00
|
|
|
console.error('addMarker - Marker with name \'' + marker.name + '\' already exists for sound \'' + this.key + '\'!');
|
2017-11-23 11:37:10 +00:00
|
|
|
return false;
|
2017-11-23 11:35:55 +00:00
|
|
|
}
|
2017-11-23 11:33:56 +00:00
|
|
|
marker = Extend(true, {
|
|
|
|
name: '',
|
|
|
|
start: 0,
|
|
|
|
duration: this.totalDuration,
|
|
|
|
config: {
|
|
|
|
mute: false,
|
|
|
|
volume: 1,
|
|
|
|
rate: 1,
|
|
|
|
detune: 0,
|
|
|
|
seek: 0,
|
2017-12-13 21:25:58 +00:00
|
|
|
loop: false,
|
|
|
|
delay: 0
|
2017-11-23 11:33:56 +00:00
|
|
|
}
|
|
|
|
}, marker);
|
2017-11-23 11:30:24 +00:00
|
|
|
this.markers[marker.name] = marker;
|
2017-11-23 11:35:55 +00:00
|
|
|
return true;
|
2017-11-14 15:00:24 +00:00
|
|
|
},
|
2018-01-06 14:50:40 +00:00
|
|
|
/**
|
|
|
|
* Updates previously added marker.
|
|
|
|
*
|
|
|
|
* @method Phaser.Sound.BaseSound#updateMarker
|
|
|
|
* @param {ISoundMarker} marker - Marker object with updated values.
|
|
|
|
* @returns {boolean} Whether the marker was updated successfully.
|
|
|
|
*/
|
2017-11-23 11:41:41 +00:00
|
|
|
updateMarker: function (marker) {
|
2017-11-23 11:55:22 +00:00
|
|
|
if (!marker) {
|
|
|
|
console.error('updateMarker - Marker object has to be provided!');
|
|
|
|
return false;
|
|
|
|
}
|
2017-11-23 11:56:06 +00:00
|
|
|
if (!marker.name || typeof marker.name !== 'string') {
|
|
|
|
console.error('updateMarker - Marker has to have a valid name!');
|
|
|
|
return false;
|
|
|
|
}
|
2017-11-23 11:56:32 +00:00
|
|
|
if (!this.markers[marker.name]) {
|
|
|
|
console.error('updateMarker - Marker with name \'' + marker.name + '\' does not exist for sound \'' + this.key + '\'!');
|
|
|
|
return false;
|
|
|
|
}
|
2017-11-23 11:54:47 +00:00
|
|
|
this.markers[marker.name] = Extend(true, this.markers[marker.name], marker);
|
|
|
|
return true;
|
2017-11-23 11:41:41 +00:00
|
|
|
},
|
2017-11-14 15:00:24 +00:00
|
|
|
removeMarker: function (markerName) {
|
2017-11-23 12:14:41 +00:00
|
|
|
var marker = this.markers[markerName];
|
|
|
|
if (!marker) {
|
2017-11-23 12:13:25 +00:00
|
|
|
console.error('removeMarker - Marker with name \'' + marker.name + '\' does not exist for sound \'' + this.key + '\'!');
|
2017-11-23 12:14:41 +00:00
|
|
|
return null;
|
2017-11-23 12:13:25 +00:00
|
|
|
}
|
2017-11-23 12:12:21 +00:00
|
|
|
this.markers[markerName] = null;
|
2017-11-23 12:14:41 +00:00
|
|
|
return marker;
|
2017-11-14 15:00:24 +00:00
|
|
|
},
|
2017-11-22 17:05:18 +00:00
|
|
|
play: function (markerName, config) {
|
|
|
|
if (markerName === void 0) { markerName = ''; }
|
|
|
|
if (typeof markerName === 'object') {
|
|
|
|
config = markerName;
|
|
|
|
markerName = '';
|
2017-11-16 13:54:08 +00:00
|
|
|
}
|
2017-11-22 17:05:18 +00:00
|
|
|
if (typeof markerName !== 'string') {
|
2017-11-16 13:19:04 +00:00
|
|
|
console.error('Sound marker name has to be a string!');
|
|
|
|
return null;
|
|
|
|
}
|
2017-11-22 17:05:18 +00:00
|
|
|
if (!markerName) {
|
2017-11-23 12:52:03 +00:00
|
|
|
this.currentMarker = null;
|
2017-11-16 13:19:04 +00:00
|
|
|
this.currentConfig = this.config;
|
2017-11-22 17:00:53 +00:00
|
|
|
this.duration = this.totalDuration;
|
2017-11-16 13:19:04 +00:00
|
|
|
}
|
|
|
|
else {
|
2017-11-22 17:05:18 +00:00
|
|
|
if (!this.markers[markerName]) {
|
|
|
|
console.error('No marker with name \'' + markerName + '\' found for sound \'' + this.key + '\'!');
|
2017-11-16 13:19:04 +00:00
|
|
|
return null;
|
|
|
|
}
|
2017-11-22 17:05:18 +00:00
|
|
|
this.currentMarker = this.markers[markerName];
|
2017-11-22 17:03:44 +00:00
|
|
|
this.currentConfig = this.currentMarker.config;
|
2017-11-22 17:00:53 +00:00
|
|
|
this.duration = this.currentMarker.duration;
|
2017-11-16 13:19:04 +00:00
|
|
|
}
|
2017-12-07 19:55:47 +00:00
|
|
|
this.resetConfig();
|
2017-11-16 13:19:04 +00:00
|
|
|
this.currentConfig = Extend(this.currentConfig, config);
|
2017-11-17 14:14:57 +00:00
|
|
|
this.isPlaying = true;
|
|
|
|
this.isPaused = false;
|
2017-11-14 15:00:24 +00:00
|
|
|
return this;
|
|
|
|
},
|
|
|
|
pause: function () {
|
2017-11-17 17:37:49 +00:00
|
|
|
if (this.isPaused || !this.isPlaying) {
|
2017-11-17 16:16:06 +00:00
|
|
|
return false;
|
|
|
|
}
|
2017-11-17 14:16:25 +00:00
|
|
|
this.isPlaying = false;
|
|
|
|
this.isPaused = true;
|
2017-11-17 16:16:06 +00:00
|
|
|
return true;
|
2017-11-14 15:00:24 +00:00
|
|
|
},
|
|
|
|
resume: function () {
|
2017-11-17 17:37:49 +00:00
|
|
|
if (!this.isPaused || this.isPlaying) {
|
2017-11-17 16:16:06 +00:00
|
|
|
return false;
|
|
|
|
}
|
2017-11-17 14:18:51 +00:00
|
|
|
this.isPlaying = true;
|
|
|
|
this.isPaused = false;
|
2017-11-17 16:16:06 +00:00
|
|
|
return true;
|
2017-11-14 15:00:24 +00:00
|
|
|
},
|
|
|
|
stop: function () {
|
2017-11-17 17:37:49 +00:00
|
|
|
if (!this.isPaused && !this.isPlaying) {
|
2017-11-17 16:16:06 +00:00
|
|
|
return false;
|
|
|
|
}
|
2017-11-17 14:03:59 +00:00
|
|
|
this.isPlaying = false;
|
|
|
|
this.isPaused = false;
|
2017-12-07 19:17:38 +00:00
|
|
|
this.resetConfig();
|
2017-11-17 16:16:06 +00:00
|
|
|
return true;
|
2017-11-14 15:00:24 +00:00
|
|
|
},
|
2017-11-26 15:19:56 +00:00
|
|
|
/**
|
2017-12-05 18:31:58 +00:00
|
|
|
* @protected
|
2017-11-26 15:19:56 +00:00
|
|
|
*/
|
2017-11-16 12:32:35 +00:00
|
|
|
applyConfig: function () {
|
|
|
|
this.mute = this.currentConfig.mute;
|
|
|
|
this.volume = this.currentConfig.volume;
|
2017-11-16 14:23:04 +00:00
|
|
|
this.rate = this.currentConfig.rate;
|
2017-11-16 16:21:00 +00:00
|
|
|
this.detune = this.currentConfig.detune;
|
2017-12-12 19:21:42 +00:00
|
|
|
this.loop = this.currentConfig.loop;
|
2017-11-16 12:32:35 +00:00
|
|
|
},
|
2017-12-05 18:40:25 +00:00
|
|
|
/**
|
|
|
|
* @protected
|
|
|
|
*/
|
|
|
|
resetConfig: function () {
|
|
|
|
this.currentConfig.seek = 0;
|
2017-12-13 21:26:32 +00:00
|
|
|
this.currentConfig.delay = 0;
|
2017-12-05 18:40:25 +00:00
|
|
|
},
|
2017-12-04 21:09:41 +00:00
|
|
|
/**
|
2017-12-05 18:31:58 +00:00
|
|
|
* @protected
|
2017-12-04 21:09:41 +00:00
|
|
|
*/
|
2017-11-23 12:19:22 +00:00
|
|
|
update: NOOP,
|
2017-11-14 15:00:24 +00:00
|
|
|
destroy: function () {
|
2018-01-04 18:38:51 +00:00
|
|
|
if (this.pendingRemove) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.pendingRemove = true;
|
2017-12-10 12:17:17 +00:00
|
|
|
this.manager = null;
|
|
|
|
this.key = '';
|
2018-01-04 18:39:21 +00:00
|
|
|
this.events.destroy();
|
|
|
|
this.events = null;
|
2017-12-10 12:17:17 +00:00
|
|
|
this.isPlaying = false;
|
|
|
|
this.isPaused = false;
|
|
|
|
this.config = null;
|
|
|
|
this.currentConfig = null;
|
|
|
|
this.markers = null;
|
|
|
|
this.currentMarker = null;
|
2017-11-27 16:30:55 +00:00
|
|
|
},
|
|
|
|
/**
|
2017-12-05 18:31:58 +00:00
|
|
|
* @protected
|
2017-11-27 16:30:55 +00:00
|
|
|
*/
|
|
|
|
setRate: function () {
|
|
|
|
var cent = 1.0005777895065548; // Math.pow(2, 1/1200);
|
2017-12-04 21:05:29 +00:00
|
|
|
var totalDetune = this.currentConfig.detune + this.manager.detune;
|
2017-11-27 16:30:55 +00:00
|
|
|
var detuneRate = Math.pow(cent, totalDetune);
|
2017-12-01 14:33:02 +00:00
|
|
|
this.totalRate = this.currentConfig.rate * this.manager.rate * detuneRate;
|
2017-11-14 15:00:24 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
module.exports = BaseSound;
|