make EffectChain standalone

- EffectChain knows of audioEngine so it can create Effects
- EffectChain connects to the target specified by .connect(target)
- EffectChain can connect to other Effects or EffectChains
- EffectChain can clone itself and connect to the original's target
- Add EffectChain.update to mirror Effects API
- Use deepest setting first in setEffectsFromTarget
This commit is contained in:
Michael "Z" Goddard 2018-06-18 11:59:45 -04:00 committed by Corey Frang
parent f5c219ceb3
commit d40564d61a

View file

@ -1,32 +1,35 @@
class EffectChain { class EffectChain {
constructor (audioEngine) { constructor (audioEngine, effects) {
this.audioEngine = audioEngine; this.audioEngine = audioEngine;
this.outputNode = this.audioEngine.audioContext.createGain(); this.inputNode = this.audioEngine.audioContext.createGain();
this.effects = effects;
this.lastEffect = null; this.lastEffect = null;
this._effects = audioEngine.effects.map(Effect => { this._effects = effects.map(Effect => {
const effect = new Effect(audioEngine, this, this.lastEffect); const effect = new Effect(audioEngine, this, this.lastEffect);
this[effect.name] = effect; this[effect.name] = effect;
this.lastEffect = effect; this.lastEffect = effect;
return effect; return effect;
}); });
// Walk backwards through effects connecting the last output to audio engine,
// then each effect's output to the input of the next effect.
this._effects.reduceRight((nextNode, effect) => {
effect.connect(nextNode);
return effect;
}, this.audioEngine);
this._soundPlayers = new Set(); this._soundPlayers = new Set();
} }
clone () {
const chain = new EffectChain(this.audioEngine, this.effects);
if (this.target === target) {
chain.connect(target);
}
return chain;
}
addSoundPlayer (soundPlayer) { addSoundPlayer (soundPlayer) {
if (!this._soundPlayers.has(soundPlayer)) { if (!this._soundPlayers.has(soundPlayer)) {
this._soundPlayers.add(soundPlayer); this._soundPlayers.add(soundPlayer);
this._effects.forEach(effect => effect.update()); this.update();
} }
} }
@ -35,7 +38,7 @@ class EffectChain {
} }
getInputNode () { getInputNode () {
return this.outputNode; return this.inputNode;
} }
/** /**
@ -43,8 +46,17 @@ class EffectChain {
* @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(); const {lastEffect} = this;
this.outputNode.connect(target.getInputNode()); if (target === lastEffect) {
this.inputNode.disconnect();
this.inputNode.connect(lastEffect.getInputNode());
return;
}
this.target = target;
this._effects[0].connect(target);
} }
@ -54,12 +66,10 @@ class EffectChain {
setEffectsFromTarget (target) { setEffectsFromTarget (target) {
this._effects.forEach(effect => { this._effects.forEach(effect => {
if (effect.name in target) { if ('soundEffects' in target && effect.name in target.soundEffects) {
effect.set(target[effect.name]);
} else if ('soundEffects' in target && effect.name in target.soundEffects) {
effect.set(target.soundEffects[effect.name]); effect.set(target.soundEffects[effect.name]);
} else { } else if (effect.name in target) {
effect.set(effect.DEFAULT_VALUE); effect.set(target[effect.name]);
} }
}); });
} }
@ -70,6 +80,10 @@ class EffectChain {
} }
} }
update () {
this._effects.forEach(effect => effect.update());
}
clear () { clear () {
this._effects.forEach(effect => effect.clear()); this._effects.forEach(effect => effect.clear());
} }