2019-08-02 20:29:09 +00:00
|
|
|
import { Merge } from "../component/channel/Merge";
|
|
|
|
import { Gain } from "../core/context/Gain";
|
|
|
|
import { Seconds } from "../core/type/Units";
|
|
|
|
import { optionsFromArguments } from "../core/util/Defaults";
|
|
|
|
import { Noise } from "../source/Noise";
|
|
|
|
import { Effect, EffectOptions } from "./Effect";
|
2019-11-08 17:34:22 +00:00
|
|
|
import { OfflineContext } from "../core/context/OfflineContext";
|
2019-08-02 20:29:09 +00:00
|
|
|
|
|
|
|
interface ReverbOptions extends EffectOptions {
|
|
|
|
decay: Seconds;
|
|
|
|
preDelay: Seconds;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-09-14 20:39:18 +00:00
|
|
|
* Simple convolution created with decaying noise.
|
|
|
|
* Generates an Impulse Response Buffer
|
|
|
|
* with Tone.Offline then feeds the IR into ConvolverNode.
|
2019-09-14 23:55:50 +00:00
|
|
|
* Note: the Reverb will not make any sound until [[generate]]
|
2019-09-14 20:39:18 +00:00
|
|
|
* has been invoked and resolved.
|
2019-08-02 20:29:09 +00:00
|
|
|
*
|
2019-09-14 20:39:18 +00:00
|
|
|
* Inspiration from [ReverbGen](https://github.com/adelespinasse/reverbGen).
|
|
|
|
* Copyright (c) 2014 Alan deLespinasse Apache 2.0 License.
|
2019-09-16 14:15:23 +00:00
|
|
|
*
|
|
|
|
* @category Effect
|
2019-08-02 20:29:09 +00:00
|
|
|
*/
|
|
|
|
export class Reverb extends Effect<ReverbOptions> {
|
|
|
|
|
2019-09-04 23:18:44 +00:00
|
|
|
readonly name: string = "Reverb";
|
2019-08-02 20:29:09 +00:00
|
|
|
|
|
|
|
/**
|
2019-09-14 20:39:18 +00:00
|
|
|
* Convolver node
|
2019-08-02 20:29:09 +00:00
|
|
|
*/
|
|
|
|
private _convolver: ConvolverNode = this.context.createConvolver();
|
|
|
|
|
|
|
|
/**
|
2019-09-29 14:19:56 +00:00
|
|
|
* The duration of the reverb.
|
|
|
|
* [[generate]] must be called in order to update the values.
|
2019-08-02 20:29:09 +00:00
|
|
|
*/
|
|
|
|
decay: Seconds;
|
2019-09-29 14:19:56 +00:00
|
|
|
|
2019-08-02 20:29:09 +00:00
|
|
|
/**
|
|
|
|
* The amount of time before the reverb is fully ramped in.
|
2019-09-29 14:19:56 +00:00
|
|
|
* [[generate]] must be called in order to update the values.
|
2019-08-02 20:29:09 +00:00
|
|
|
*/
|
|
|
|
preDelay: Seconds;
|
|
|
|
|
2019-08-27 16:00:59 +00:00
|
|
|
/**
|
2019-08-30 16:06:38 +00:00
|
|
|
* @param decay The amount of time it will reverberate for.
|
2019-08-27 16:00:59 +00:00
|
|
|
*/
|
2019-08-02 20:29:09 +00:00
|
|
|
constructor(decay?: Seconds);
|
|
|
|
constructor(options?: Partial<ReverbOptions>);
|
|
|
|
constructor() {
|
|
|
|
|
|
|
|
super(optionsFromArguments(Reverb.getDefaults(), arguments, ["decay"]));
|
|
|
|
const options = optionsFromArguments(Reverb.getDefaults(), arguments, ["decay"]);
|
|
|
|
|
|
|
|
this.decay = options.decay;
|
|
|
|
this.preDelay = options.preDelay;
|
|
|
|
|
|
|
|
this.connectEffect(this._convolver);
|
|
|
|
}
|
|
|
|
|
|
|
|
static getDefaults(): ReverbOptions {
|
|
|
|
return Object.assign(Effect.getDefaults(), {
|
2019-09-14 22:12:44 +00:00
|
|
|
decay: 1.5,
|
|
|
|
preDelay: 0.01,
|
2019-08-02 20:29:09 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generate the Impulse Response. Returns a promise while the IR is being generated.
|
|
|
|
* @return Promise which returns this object.
|
|
|
|
*/
|
|
|
|
async generate(): Promise<this> {
|
2019-11-08 17:34:22 +00:00
|
|
|
const context = new OfflineContext(2, this.decay + this.preDelay, this.context.sampleRate);
|
|
|
|
// create a noise burst which decays over the duration
|
|
|
|
const noiseL = new Noise({ context });
|
|
|
|
const noiseR = new Noise({ context });
|
|
|
|
const merge = new Merge({ context });
|
|
|
|
noiseL.connect(merge, 0, 0);
|
|
|
|
noiseR.connect(merge, 0, 1);
|
|
|
|
const gainNode = new Gain({ context }).toDestination();
|
|
|
|
merge.connect(gainNode);
|
|
|
|
noiseL.start(0);
|
|
|
|
noiseR.start(0);
|
|
|
|
// predelay
|
|
|
|
gainNode.gain.setValueAtTime(0, 0);
|
|
|
|
gainNode.gain.setValueAtTime(1, this.preDelay);
|
|
|
|
// decay
|
|
|
|
gainNode.gain.exponentialApproachValueAtTime(0, this.preDelay, this.decay);
|
|
|
|
|
|
|
|
// render the output
|
|
|
|
const response = await context.render();
|
|
|
|
this._convolver.buffer = response.get() as AudioBuffer;
|
2019-08-02 20:29:09 +00:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
dispose(): this {
|
|
|
|
super.dispose();
|
|
|
|
this._convolver.disconnect();
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
}
|