diff --git a/src/SoundBank.js b/src/SoundBank.js index ecbb1c4..044dd90 100644 --- a/src/SoundBank.js +++ b/src/SoundBank.js @@ -1,21 +1,64 @@ const log = require('./log'); +/** + * A symbol indicating all targets are to be effected. + * @const {string} + */ const ALL_TARGETS = '*'; class SoundBank { + /** + * A bank of sounds that can be played. + * @constructor + * @param {AudioEngine} audioEngine - related AudioEngine + * @param {EffectChain} effectChainPrime - original EffectChain cloned for + * playing sounds + */ constructor (audioEngine, effectChainPrime) { + /** + * AudioEngine this SoundBank is related to. + * @type {AudioEngine} + */ this.audioEngine = audioEngine; + /** + * Map of ids to soundPlayers. + * @type {object} + */ this.soundPlayers = {}; + + /** + * Map of targets by sound id. + * @type {Map} + */ this.playerTargets = new Map(); + + /** + * Map of effect chains by sound id. + * @type {Map { if (playerTarget === target) { @@ -55,12 +112,22 @@ class SoundBank { }); } + /** + * Stop playback of sound by id if was lasted played by the target. + * @param {Target} target - target to check if it last played the sound + * @param {string} soundId - id of the sound to stop + */ stop (target, soundId) { if (this.playerTargets.get(soundId) === target) { this.soundPlayers[soundId].stop(); } } + /** + * Stop all sounds for all targets or a specific target. + * @param {Target|string} target - a symbol for all targets or the target + * to stop sounds for + */ stopAllSounds (target = ALL_TARGETS) { this.playerTargets.forEach((playerTarget, key) => { if (target === ALL_TARGETS || playerTarget === target) { @@ -69,6 +136,9 @@ class SoundBank { }); } + /** + * Dispose of all EffectChains and SoundPlayers. + */ dispose () { this.playerTargets.clear(); this.soundEffects.forEach(effects => effects.dispose()); diff --git a/src/effects/EffectChain.js b/src/effects/EffectChain.js index e0b175f..bef3775 100644 --- a/src/effects/EffectChain.js +++ b/src/effects/EffectChain.js @@ -1,15 +1,37 @@ class EffectChain { + /** + * Chain of effects that can be applied to a group of SoundPlayers. + * @param {AudioEngine} audioEngine - engine whose effects these belong to + * @param {Array} effects - array of Effect classes to construct + */ constructor (audioEngine, effects) { + /** + * AudioEngine whose effects these belong to. + * @type {AudioEngine} + */ this.audioEngine = audioEngine; + /** + * Node incoming connections will attach to. This node than connects to + * the items in the chain which finally connect to some output. + * @type {AudioNode} + */ this.inputNode = this.audioEngine.audioContext.createGain(); + /** + * List of Effect types to create. + * @type {Array} + */ this.effects = effects; - // Effects are instantiate in reverse so that the first refers to the + // Effects are instantiated in reverse so that the first refers to the // second, the second refers to the third, etc and the last refers to // null. let lastEffect = null; + /** + * List of instantiated Effects. + * @type {Array} + */ this._effects = effects .reverse() .map(Effect => { @@ -20,12 +42,28 @@ class EffectChain { }) .reverse(); + /** + * First effect of this chain. + * @type {Effect} + */ this.firstEffect = this._effects[0]; + + /** + * Last effect of this chain. + * @type {Effect} + */ this.lastEffect = this._effects[this._effects.length - 1]; + /** + * A set of players this chain is managing. + */ this._soundPlayers = new Set(); } + /** + * Create a clone of the EffectChain. + * @returns {EffectChain} a clone of this EffectChain + */ clone () { const chain = new EffectChain(this.audioEngine, this.effects); if (this.target) { @@ -34,6 +72,10 @@ class EffectChain { return chain; } + /** + * Add a sound player. + * @param {SoundPlayer} soundPlayer - a sound player to manage + */ addSoundPlayer (soundPlayer) { if (!this._soundPlayers.has(soundPlayer)) { this._soundPlayers.add(soundPlayer); @@ -41,16 +83,24 @@ class EffectChain { } } + /** + * Remove a sound player. + * @param {SoundPlayer} soundPlayer - a sound player to stop managing + */ removeSoundPlayer (soundPlayer) { this._soundPlayers.remove(soundPlayer); } + /** + * Get the audio input node. + * @returns {AudioNode} audio node the upstream can connect to + */ getInputNode () { return this.inputNode; } /** - * Connnect this player's output to another audio node + * Connnect this player's output to another audio node. * @param {object} target - target whose node to should be connected */ connect (target) { @@ -70,11 +120,19 @@ class EffectChain { firstEffect.connect(target); } - + /** + * Array of SoundPlayers managed by this EffectChain. + * @returns {Array} sound players managed by this chain + */ getSoundPlayers () { return [...this._soundPlayers]; } + /** + * Set Effect values with named values on target.soundEffects if it exist + * and then from target itself. + * @param {Target} target - target to set values from + */ setEffectsFromTarget (target) { this._effects.forEach(effect => { if ('soundEffects' in target && effect.name in target.soundEffects) { @@ -85,20 +143,35 @@ class EffectChain { }); } + /** + * Set an effect value by its name. + * @param {string} effect - effect name to change + * @param {number} value - value to set effect to + */ set (effect, value) { if (effect in this) { this[effect].set(value); } } + /** + * Update managed sound players with the effects on this chain. + */ update () { this._effects.forEach(effect => effect.update()); } + /** + * Clear all effects to their default values. + */ clear () { this._effects.forEach(effect => effect.clear()); } + /** + * Dispose of all effects in this chain. Nothing is done to managed + * SoundPlayers. + */ dispose () { this._soundPlayers = null; this._effects.forEach(effect => effect.dispose());