Merge pull request #85 from mzgoddard/volume-effect

add and use VolumeEffect in AudioPlayer
This commit is contained in:
Eric Rosenbaum 2018-06-07 13:53:26 -04:00 committed by GitHub
commit 6c8edf52b9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 69 additions and 17 deletions

View file

@ -1,5 +1,6 @@
const PitchEffect = require('./effects/PitchEffect');
const PanEffect = require('./effects/PanEffect'); const PanEffect = require('./effects/PanEffect');
const PitchEffect = require('./effects/PitchEffect');
const VolumeEffect = require('./effects/VolumeEffect');
const SoundPlayer = require('./SoundPlayer'); const SoundPlayer = require('./SoundPlayer');
@ -17,9 +18,11 @@ class AudioPlayer {
this.outputNode = this.audioEngine.audioContext.createGain(); this.outputNode = this.audioEngine.audioContext.createGain();
// Create the audio effects // Create the audio effects
const pitchEffect = new PitchEffect(this.audioEngine, this, null); const volumeEffect = new VolumeEffect(this.audioEngine, this, null);
const pitchEffect = new PitchEffect(this.audioEngine, this, volumeEffect);
const panEffect = new PanEffect(this.audioEngine, this, pitchEffect); const panEffect = new PanEffect(this.audioEngine, this, pitchEffect);
this.effects = { this.effects = {
volume: volumeEffect,
pitch: pitchEffect, pitch: pitchEffect,
pan: panEffect pan: panEffect
}; };
@ -28,6 +31,7 @@ class AudioPlayer {
// outputNode -> "pitchEffect" -> panEffect -> audioEngine.input // outputNode -> "pitchEffect" -> panEffect -> audioEngine.input
panEffect.connect(this.audioEngine); panEffect.connect(this.audioEngine);
pitchEffect.connect(panEffect); pitchEffect.connect(panEffect);
volumeEffect.connect(pitchEffect);
// reset effects to their default parameters // reset effects to their default parameters
this.clearEffects(); this.clearEffects();
@ -123,9 +127,6 @@ class AudioPlayer {
for (const effectName in this.effects) { for (const effectName in this.effects) {
this.effects[effectName].clear(); this.effects[effectName].clear();
} }
if (this.audioEngine === null) return;
this.outputNode.gain.setTargetAtTime(1.0, 0, this.audioEngine.DECAY_TIME);
} }
/** /**
@ -133,8 +134,7 @@ class AudioPlayer {
* @param {number} value - the volume in range 0-100 * @param {number} value - the volume in range 0-100
*/ */
setVolume (value) { setVolume (value) {
if (this.audioEngine === null) return; this.setEffect('volume', value);
this.outputNode.gain.setTargetAtTime(value / 100, 0, this.audioEngine.DECAY_TIME);
} }
/** /**
@ -142,6 +142,7 @@ class AudioPlayer {
* @param {object} target - target whose node to should be connected * @param {object} target - target whose node to should be connected
*/ */
connect (target) { connect (target) {
this.outputNode.disconnect();
this.outputNode.connect(target.getInputNode()); this.outputNode.connect(target.getInputNode());
} }
@ -149,6 +150,7 @@ class AudioPlayer {
* Clean up and disconnect audio nodes. * Clean up and disconnect audio nodes.
*/ */
dispose () { dispose () {
this.effects.volume.dispose();
this.effects.pitch.dispose(); this.effects.pitch.dispose();
this.effects.pan.dispose(); this.effects.pan.dispose();

View file

@ -38,7 +38,7 @@ class Effect {
* @return {boolean} is the effect affecting the graph? * @return {boolean} is the effect affecting the graph?
*/ */
get _isPatch () { get _isPatch () {
return this.initialized; return this.initialized && this.value !== this.DEFAULT_VALUE;
} }
/** /**
@ -46,7 +46,7 @@ class Effect {
* @return {AudioNode} - audio node that is the input for this effect * @return {AudioNode} - audio node that is the input for this effect
*/ */
getInputNode () { getInputNode () {
if (this.initialized) { if (this._isPatch) {
return this.inputNode; return this.inputNode;
} }
return this.target.getInputNode(); return this.target.getInputNode();
@ -117,6 +117,10 @@ class Effect {
return; return;
} }
if (this.outputNode !== null) {
this.outputNode.disconnect();
}
let nextTarget = target; let nextTarget = target;
if (this._isPatch) { if (this._isPatch) {
nextTarget = this; nextTarget = this;

View file

@ -20,14 +20,6 @@ class PanEffect extends Effect {
this.channelMerger = null; this.channelMerger = null;
} }
/**
* Should the effect be connected to the audio graph?
* @return {boolean} is the effect affecting the graph?
*/
get _isPatch () {
return this.initialized && this.value !== 0;
}
/** /**
* Initialize the Effect. * Initialize the Effect.
* Effects start out uninitialized. Then initialize when they are first set * Effects start out uninitialized. Then initialize when they are first set

View file

@ -0,0 +1,54 @@
const Effect = require('./Effect');
/**
* Affect the volume of an effect chain.
*/
class VolumeEffect extends Effect {
/**
* Default value to set the Effect to when constructed and when clear'ed.
* @const {number}
*/
get DEFAULT_VALUE () {
return 100;
}
/**
* Initialize the Effect.
* Effects start out uninitialized. Then initialize when they are first set
* with some value.
* @throws {Error} throws when left unimplemented
*/
initialize () {
this.inputNode = this.audioEngine.audioContext.createGain();
this.outputNode = this.inputNode;
this.initialized = true;
}
/**
* Set the effects value.
* @private
* @param {number} value - new value to set effect to
*/
_set (value) {
this.value = value;
// A gain of 1 is normal. Scale down scratch's volume value. Apply the
// change over a tiny period of time.
this.outputNode.gain.setTargetAtTime(value / 100, 0, this.audioEngine.DECAY_TIME);
}
/**
* Clean up and disconnect audio nodes.
*/
dispose () {
this.outputNode.disconnect();
this.inputNode = null;
this.outputNode = null;
this.target = null;
this.initialized = false;
}
}
module.exports = VolumeEffect;