2019-11-05 00:09:13 +00:00
|
|
|
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<Options extends StereoFeedbackEffectOptions> extends StereoEffect<Options> {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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);
|
|
|
|
|
2019-11-13 17:58:37 +00:00
|
|
|
// the left output connected to the left input
|
2019-11-05 00:09:13 +00:00
|
|
|
this._feedbackSplit.connect(this._feedbackL, 0, 0);
|
|
|
|
this._feedbackL.connect(this._feedbackMerge, 0, 0);
|
|
|
|
|
2019-11-13 17:58:37 +00:00
|
|
|
// the right output connected to the right input
|
2019-11-05 00:09:13 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|