import { StereoEffect, StereoEffectOptions } from "./StereoEffect"; import { NormalRange } from "../core/type/Units"; import { Signal } from "../signal/Signal"; import { Gain } from "../core/context/Gain"; import { readOnly } from "../core/util/Interface"; import { Split } from "../component/channel/Split"; import { Merge } from "../component/channel/Merge"; export interface StereoFeedbackEffectOptions extends StereoEffectOptions { feedback: NormalRange; } /** * Just like a stereo feedback effect, but the feedback is routed from left to right * and right to left instead of on the same channel. * ``` * +--------------------------------+ feedbackL <-----------------------------------+ * | | * +--> +-----> +----> +---+ * feedbackMerge +--> split (EFFECT) merge +--> feedbackSplit * +--> +-----> +----> +---+ * | | * +--------------------------------+ feedbackR <-----------------------------------+ * ``` */ export class StereoFeedbackEffect extends StereoEffect { /** * The amount of feedback from the output * back into the input of the effect (routed * across left and right channels). */ readonly feedback: Signal<"normalRange">; /** * the left side feedback */ protected _feedbackL: Gain; /** * the right side feedback */ protected _feedbackR: Gain; /** * Split the channels for feedback */ protected _feedbackSplit: Split; /** * Merge the channels for feedback */ protected _feedbackMerge: Merge; constructor(options: StereoFeedbackEffectOptions) { super(options); this.feedback = new Signal({ context: this.context, value: options.feedback, units: "normalRange" }); this._feedbackL = new Gain({ context: this.context }); this._feedbackR = new Gain({ context: this.context }); this._feedbackSplit = new Split({ context: this.context, channels: 2 }); this._feedbackMerge = new Merge({ context: this.context, channels: 2 }); this._merge.connect(this._feedbackSplit); this._feedbackMerge.connect(this._split); // the left output connected to the left input this._feedbackSplit.connect(this._feedbackL, 0, 0); this._feedbackL.connect(this._feedbackMerge, 0, 0); // the right output connected to the right input this._feedbackSplit.connect(this._feedbackR, 1, 0); this._feedbackR.connect(this._feedbackMerge, 0, 1); // the feedback control this.feedback.fan(this._feedbackL.gain, this._feedbackR.gain); readOnly(this, ["feedback"]); } static getDefaults(): StereoFeedbackEffectOptions { return Object.assign(StereoEffect.getDefaults(), { feedback: 0.5, }); } dispose(): this { super.dispose(); this.feedback.dispose(); this._feedbackL.dispose(); this._feedbackR.dispose(); this._feedbackSplit.dispose(); this._feedbackMerge.dispose(); return this; } }