UNPKG

7.19 kBJavaScriptView Raw
1import { ToneAudioBuffer } from "../core/context/ToneAudioBuffer.js";
2import { optionsFromArguments } from "../core/util/Defaults.js";
3import { assert } from "../core/util/Debug.js";
4import { Source } from "../source/Source.js";
5import { ToneBufferSource } from "./buffer/ToneBufferSource.js";
6/**
7 * Noise is a noise generator. It uses looped noise buffers to save on performance.
8 * Noise supports the noise types: "pink", "white", and "brown". Read more about
9 * colors of noise on [Wikipedia](https://en.wikipedia.org/wiki/Colors_of_noise).
10 *
11 * @example
12 * // initialize the noise and start
13 * const noise = new Tone.Noise("pink").start();
14 * // make an autofilter to shape the noise
15 * const autoFilter = new Tone.AutoFilter({
16 * frequency: "8n",
17 * baseFrequency: 200,
18 * octaves: 8
19 * }).toDestination().start();
20 * // connect the noise
21 * noise.connect(autoFilter);
22 * // start the autofilter LFO
23 * autoFilter.start();
24 * @category Source
25 */
26export class Noise extends Source {
27 constructor() {
28 const options = optionsFromArguments(Noise.getDefaults(), arguments, [
29 "type",
30 ]);
31 super(options);
32 this.name = "Noise";
33 /**
34 * Private reference to the source
35 */
36 this._source = null;
37 this._playbackRate = options.playbackRate;
38 this.type = options.type;
39 this._fadeIn = options.fadeIn;
40 this._fadeOut = options.fadeOut;
41 }
42 static getDefaults() {
43 return Object.assign(Source.getDefaults(), {
44 fadeIn: 0,
45 fadeOut: 0,
46 playbackRate: 1,
47 type: "white",
48 });
49 }
50 /**
51 * The type of the noise. Can be "white", "brown", or "pink".
52 * @example
53 * const noise = new Tone.Noise().toDestination().start();
54 * noise.type = "brown";
55 */
56 get type() {
57 return this._type;
58 }
59 set type(type) {
60 assert(type in _noiseBuffers, "Noise: invalid type: " + type);
61 if (this._type !== type) {
62 this._type = type;
63 // if it's playing, stop and restart it
64 if (this.state === "started") {
65 const now = this.now();
66 this._stop(now);
67 this._start(now);
68 }
69 }
70 }
71 /**
72 * The playback rate of the noise. Affects
73 * the "frequency" of the noise.
74 */
75 get playbackRate() {
76 return this._playbackRate;
77 }
78 set playbackRate(rate) {
79 this._playbackRate = rate;
80 if (this._source) {
81 this._source.playbackRate.value = rate;
82 }
83 }
84 /**
85 * internal start method
86 */
87 _start(time) {
88 const buffer = _noiseBuffers[this._type];
89 this._source = new ToneBufferSource({
90 url: buffer,
91 context: this.context,
92 fadeIn: this._fadeIn,
93 fadeOut: this._fadeOut,
94 loop: true,
95 onended: () => this.onstop(this),
96 playbackRate: this._playbackRate,
97 }).connect(this.output);
98 this._source.start(this.toSeconds(time), Math.random() * (buffer.duration - 0.001));
99 }
100 /**
101 * internal stop method
102 */
103 _stop(time) {
104 if (this._source) {
105 this._source.stop(this.toSeconds(time));
106 this._source = null;
107 }
108 }
109 /**
110 * The fadeIn time of the amplitude envelope.
111 */
112 get fadeIn() {
113 return this._fadeIn;
114 }
115 set fadeIn(time) {
116 this._fadeIn = time;
117 if (this._source) {
118 this._source.fadeIn = this._fadeIn;
119 }
120 }
121 /**
122 * The fadeOut time of the amplitude envelope.
123 */
124 get fadeOut() {
125 return this._fadeOut;
126 }
127 set fadeOut(time) {
128 this._fadeOut = time;
129 if (this._source) {
130 this._source.fadeOut = this._fadeOut;
131 }
132 }
133 _restart(time) {
134 // TODO could be optimized by cancelling the buffer source 'stop'
135 this._stop(time);
136 this._start(time);
137 }
138 /**
139 * Clean up.
140 */
141 dispose() {
142 super.dispose();
143 if (this._source) {
144 this._source.disconnect();
145 }
146 return this;
147 }
148}
149//--------------------
150// THE NOISE BUFFERS
151//--------------------
152// Noise buffer stats
153const BUFFER_LENGTH = 44100 * 5;
154const NUM_CHANNELS = 2;
155/**
156 * Cache the noise buffers
157 */
158const _noiseCache = {
159 brown: null,
160 pink: null,
161 white: null,
162};
163/**
164 * The noise arrays. Generated on initialization.
165 * borrowed heavily from https://github.com/zacharydenton/noise.js
166 * (c) 2013 Zach Denton (MIT)
167 */
168const _noiseBuffers = {
169 get brown() {
170 if (!_noiseCache.brown) {
171 const buffer = [];
172 for (let channelNum = 0; channelNum < NUM_CHANNELS; channelNum++) {
173 const channel = new Float32Array(BUFFER_LENGTH);
174 buffer[channelNum] = channel;
175 let lastOut = 0.0;
176 for (let i = 0; i < BUFFER_LENGTH; i++) {
177 const white = Math.random() * 2 - 1;
178 channel[i] = (lastOut + 0.02 * white) / 1.02;
179 lastOut = channel[i];
180 channel[i] *= 3.5; // (roughly) compensate for gain
181 }
182 }
183 _noiseCache.brown = new ToneAudioBuffer().fromArray(buffer);
184 }
185 return _noiseCache.brown;
186 },
187 get pink() {
188 if (!_noiseCache.pink) {
189 const buffer = [];
190 for (let channelNum = 0; channelNum < NUM_CHANNELS; channelNum++) {
191 const channel = new Float32Array(BUFFER_LENGTH);
192 buffer[channelNum] = channel;
193 let b0, b1, b2, b3, b4, b5, b6;
194 b0 = b1 = b2 = b3 = b4 = b5 = b6 = 0.0;
195 for (let i = 0; i < BUFFER_LENGTH; i++) {
196 const white = Math.random() * 2 - 1;
197 b0 = 0.99886 * b0 + white * 0.0555179;
198 b1 = 0.99332 * b1 + white * 0.0750759;
199 b2 = 0.969 * b2 + white * 0.153852;
200 b3 = 0.8665 * b3 + white * 0.3104856;
201 b4 = 0.55 * b4 + white * 0.5329522;
202 b5 = -0.7616 * b5 - white * 0.016898;
203 channel[i] =
204 b0 + b1 + b2 + b3 + b4 + b5 + b6 + white * 0.5362;
205 channel[i] *= 0.11; // (roughly) compensate for gain
206 b6 = white * 0.115926;
207 }
208 }
209 _noiseCache.pink = new ToneAudioBuffer().fromArray(buffer);
210 }
211 return _noiseCache.pink;
212 },
213 get white() {
214 if (!_noiseCache.white) {
215 const buffer = [];
216 for (let channelNum = 0; channelNum < NUM_CHANNELS; channelNum++) {
217 const channel = new Float32Array(BUFFER_LENGTH);
218 buffer[channelNum] = channel;
219 for (let i = 0; i < BUFFER_LENGTH; i++) {
220 channel[i] = Math.random() * 2 - 1;
221 }
222 }
223 _noiseCache.white = new ToneAudioBuffer().fromArray(buffer);
224 }
225 return _noiseCache.white;
226 },
227};
228//# sourceMappingURL=Noise.js.map
\No newline at end of file