Tone.js/Tone/effect/PingPongDelay.ts
2019-11-04 22:29:14 -05:00

106 lines
3.2 KiB
TypeScript

import { StereoXFeedbackEffect, StereoXFeedbackEffectOptions } from "./StereoXFeedbackEffect";
import { NormalRange, Seconds, Time } from "../core/type/Units";
import { optionsFromArguments } from "../core/util/Defaults";
import { Delay } from "../core/context/Delay";
import { Signal } from "../signal/Signal";
import { readOnly } from "../core/util/Interface";
export interface PingPongDelayOptions extends StereoXFeedbackEffectOptions {
delayTime: Time;
maxDelay: Seconds;
}
/**
* PingPongDelay is a feedback delay effect where the echo is heard
* first in one channel and next in the opposite channel. In a stereo
* system these are the right and left channels.
* PingPongDelay in more simplified terms is two Tone.FeedbackDelays
* with independent delay values. Each delay is routed to one channel
* (left or right), and the channel triggered second will always
* trigger at the same interval after the first.
* @example
* import { MembraneSynth, PingPongDelay } from "tone";
* const pingPong = new PingPongDelay("4n", 0.2).toDestination();
* const drum = new MembraneSynth().connect(pingPong);
* drum.triggerAttackRelease("C4", "32n");
* @category Effect
*/
export class PingPongDelay extends StereoXFeedbackEffect<PingPongDelayOptions> {
readonly name: string = "PingPongDelay";
/**
* the delay node on the left side
*/
private _leftDelay: Delay;
/**
* the delay node on the right side
*/
private _rightDelay: Delay;
/**
* the predelay on the right side
*/
private _rightPreDelay: Delay;
/**
* the delay time signal
*/
readonly delayTime: Signal<"time">;
/**
* @param delayTime The delayTime between consecutive echos.
* @param feedback The amount of the effected signal which is fed back through the delay.
*/
constructor(delayTime?: Time, feedback?: NormalRange);
constructor(options?: Partial<PingPongDelayOptions>);
constructor() {
super(optionsFromArguments(PingPongDelay.getDefaults(), arguments, ["delayTime", "feedback"]));
const options = optionsFromArguments(PingPongDelay.getDefaults(), arguments, ["delayTime", "feedback"]);
this._leftDelay = new Delay({
context: this.context,
maxDelay: options.maxDelay,
});
this._rightDelay = new Delay({
context: this.context,
maxDelay: options.maxDelay
});
this._rightPreDelay = new Delay({
context: this.context,
maxDelay: options.maxDelay
});
this.delayTime = new Signal({
context: this.context,
units: "time",
value: options.delayTime,
});
// connect it up
this.connectEffectLeft(this._leftDelay);
this.connectEffectRight(this._rightPreDelay, this._rightDelay);
this.delayTime.fan(this._leftDelay.delayTime, this._rightDelay.delayTime, this._rightPreDelay.delayTime);
// rearranged the feedback to be after the rightPreDelay
this._feedbackL.disconnect();
this._feedbackL.connect(this._rightDelay);
readOnly(this, ["delayTime"]);
}
static getDefaults(): PingPongDelayOptions {
return Object.assign(StereoXFeedbackEffect.getDefaults(), {
delayTime: 0.25,
maxDelay: 1
});
}
dispose(): this {
super.dispose();
this._leftDelay.dispose();
this._rightDelay.dispose();
this._rightPreDelay.dispose();
this.delayTime.dispose();
return this;
}
}