UNPKG

2.45 kBPlain TextView Raw
1import { optionsFromArguments } from "../core/util/Defaults.js";
2import { WaveShaper } from "../signal/WaveShaper.js";
3import { Effect, EffectOptions } from "./Effect.js";
4
5export interface DistortionOptions extends EffectOptions {
6 distortion: number;
7 oversample: OverSampleType;
8}
9
10/**
11 * A simple distortion effect using Tone.WaveShaper.
12 * Algorithm from [this stackoverflow answer](http://stackoverflow.com/a/22313408).
13 * Read more about distortion on [Wikipedia] (https://en.wikipedia.org/wiki/Distortion_(music)).
14 * @example
15 * const dist = new Tone.Distortion(0.8).toDestination();
16 * const fm = new Tone.FMSynth().connect(dist);
17 * fm.triggerAttackRelease("A1", "8n");
18 * @category Effect
19 */
20export class Distortion extends Effect<DistortionOptions> {
21 readonly name: string = "Distortion";
22
23 /**
24 * The waveshaper which does the distortion
25 */
26 private _shaper: WaveShaper;
27
28 /**
29 * Stores the distortion value
30 */
31 private _distortion: number;
32
33 /**
34 * @param distortion The amount of distortion (nominal range of 0-1)
35 */
36 constructor(distortion?: number);
37 constructor(options?: Partial<DistortionOptions>);
38 constructor() {
39 const options = optionsFromArguments(
40 Distortion.getDefaults(),
41 arguments,
42 ["distortion"]
43 );
44 super(options);
45
46 this._shaper = new WaveShaper({
47 context: this.context,
48 length: 4096,
49 });
50
51 this._distortion = options.distortion;
52
53 this.connectEffect(this._shaper);
54 this.distortion = options.distortion;
55 this.oversample = options.oversample;
56 }
57
58 static getDefaults(): DistortionOptions {
59 return Object.assign(Effect.getDefaults(), {
60 distortion: 0.4,
61 oversample: "none" as OverSampleType,
62 });
63 }
64
65 /**
66 * The amount of distortion. Nominal range is between 0 and 1.
67 */
68 get distortion(): number {
69 return this._distortion;
70 }
71 set distortion(amount) {
72 this._distortion = amount;
73 const k = amount * 100;
74 const deg = Math.PI / 180;
75 this._shaper.setMap((x) => {
76 if (Math.abs(x) < 0.001) {
77 // should output 0 when input is 0
78 return 0;
79 } else {
80 return ((3 + k) * x * 20 * deg) / (Math.PI + k * Math.abs(x));
81 }
82 });
83 }
84
85 /**
86 * The oversampling of the effect. Can either be "none", "2x" or "4x".
87 */
88 get oversample(): OverSampleType {
89 return this._shaper.oversample;
90 }
91 set oversample(oversampling) {
92 this._shaper.oversample = oversampling;
93 }
94
95 dispose(): this {
96 super.dispose();
97 this._shaper.dispose();
98 return this;
99 }
100}