Tone.js/Tone/effect/Distortion.ts

100 lines
2.4 KiB
TypeScript
Raw Normal View History

2019-09-06 02:11:02 +00:00
import { optionsFromArguments } from "../core/util/Defaults";
import { WaveShaper } from "../signal/WaveShaper";
import { Effect, EffectOptions } from "./Effect";
export interface DistortionOptions extends EffectOptions {
distortion: number;
oversample: OverSampleType;
}
/**
* A simple distortion effect using Tone.WaveShaper.
* Algorithm from [this stackoverflow answer](http://stackoverflow.com/a/22313408).
*
* @example
2019-10-24 22:01:27 +00:00
* import { Distortion, FMSynth } from "tone";
* const dist = new Distortion(0.8).toDestination();
* const fm = new FMSynth().connect(dist);
2019-09-06 02:11:02 +00:00
* fm.triggerAttackRelease("A1", "8n");
2019-09-16 14:15:23 +00:00
* @category Effect
2019-09-06 02:11:02 +00:00
*/
export class Distortion extends Effect<DistortionOptions> {
readonly name: string = "Distortion";
/**
* The waveshaper which does the distortion
*/
private _shaper: WaveShaper;
/**
* Stores the distortion value
*/
private _distortion: number;
/**
* @param distortion The amount of distortion (nominal range of 0-1)
*/
constructor(distortion?: number);
constructor(options?: Partial<DistortionOptions>);
constructor() {
super(optionsFromArguments(Distortion.getDefaults(), arguments, ["distortion"]));
const options = optionsFromArguments(Distortion.getDefaults(), arguments, ["distortion"]);
this._shaper = new WaveShaper({
context: this.context,
length: 4096,
});
this._distortion = options.distortion;
this.connectEffect(this._shaper);
this.distortion = options.distortion;
this.oversample = options.oversample;
}
static getDefaults(): DistortionOptions {
return Object.assign(Effect.getDefaults(), {
distortion: 0.4,
oversample: "none" as OverSampleType,
});
}
/**
* The amount of distortion. Nominal range is between 0 and 1.
*/
get distortion(): number {
return this._distortion;
}
set distortion(amount) {
this._distortion = amount;
const k = amount * 100;
const deg = Math.PI / 180;
this._shaper.setMap((x) => {
if (Math.abs(x) < 0.001) {
// should output 0 when input is 0
return 0;
} else {
return (3 + k) * x * 20 * deg / (Math.PI + k * Math.abs(x));
}
});
}
/**
* The oversampling of the effect. Can either be "none", "2x" or "4x".
*/
get oversample(): OverSampleType {
return this._shaper.oversample;
}
set oversample(oversampling) {
this._shaper.oversample = oversampling;
}
dispose(): this {
super.dispose();
this._shaper.dispose();
return this;
}
}