@logue/reverb 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/Reverb.es.js CHANGED
@@ -5,11 +5,11 @@
5
5
  * @author Logue <logue@hotmail.co.jp>
6
6
  * @copyright 2019-2022 By Masashi Yoshikawa All rights reserved.
7
7
  * @license MIT
8
- * @version 1.1.0
8
+ * @version 1.1.2
9
9
  * @see {@link https://github.com/logue/Reverb.js}
10
10
  */
11
11
 
12
- const a = {
12
+ const Noise = {
13
13
  BLUE: "blue",
14
14
  GREEN: "green",
15
15
  PINK: "pink",
@@ -17,243 +17,471 @@ const a = {
17
17
  VIOLET: "violet",
18
18
  WHITE: "white",
19
19
  BROWN: "red"
20
- }, g = 1 / 2 ** 32;
21
- class S {
22
- float(e = 1) {
23
- return this.int() * g * e;
24
- }
25
- norm(e = 1) {
26
- return (this.int() * g - 0.5) * 2 * e;
27
- }
28
- minmax(e, s) {
29
- return this.float() * (s - e) + e;
30
- }
31
- minmaxInt(e, s) {
32
- return e |= 0, s |= 0, e + (this.float() * (s - e) | 0);
33
- }
20
+ };
21
+
22
+ const INV_MAX = 1 / 2 ** 32;
23
+ class ARandom {
24
+ float(norm = 1) {
25
+ return this.int() * INV_MAX * norm;
26
+ }
27
+ norm(norm = 1) {
28
+ return (this.int() * INV_MAX - 0.5) * 2 * norm;
29
+ }
30
+ minmax(min, max) {
31
+ return this.float() * (max - min) + min;
32
+ }
33
+ minmaxInt(min, max) {
34
+ min |= 0;
35
+ max |= 0;
36
+ return min + ((this.float() * (max - min)) | 0);
37
+ }
34
38
  }
35
- const f = Math.random;
36
- class k extends S {
37
- int() {
38
- return f() * 4294967296 >>> 0;
39
- }
40
- float(e = 1) {
41
- return f() * e;
42
- }
43
- norm(e = 1) {
44
- return (f() - 0.5) * 2 * e;
45
- }
39
+
40
+ const random = Math.random;
41
+ /**
42
+ * A `Math.random()` based {@link IRandom} implementation. Also @see
43
+ * {@link SYSTEM}.
44
+ */
45
+ class SystemRandom extends ARandom {
46
+ int() {
47
+ return (random() * 4294967296) /* 2**32 */ >>> 0;
48
+ }
49
+ float(norm = 1) {
50
+ return random() * norm;
51
+ }
52
+ norm(norm = 1) {
53
+ return (random() - 0.5) * 2 * norm;
54
+ }
46
55
  }
47
- const h = new k(), G = {
48
- noise: a.WHITE,
49
- scale: 2,
56
+ /**
57
+ * Used as default PRNG throughout most other thi.ng projects, though usually is
58
+ * configurable.
59
+ */
60
+ const SYSTEM = new SystemRandom();
61
+
62
+ const defaults = {
63
+ noise: Noise.WHITE,
64
+ scale: 1,
50
65
  peaks: 2,
51
- randomAlgorithm: h,
66
+ randomAlgorithm: SYSTEM,
52
67
  decay: 2,
53
68
  delay: 0,
54
- reverse: !1,
69
+ reverse: false,
55
70
  time: 2,
56
- filterType: "lowpass",
71
+ filterType: "allpass",
57
72
  filterFreq: 2200,
58
73
  filterQ: 1,
59
74
  mix: 0.5,
60
- once: !1
61
- }, w = {
62
- version: "1.1.0",
63
- date: "2022-10-04T02:13:31.946Z"
64
- }, b = (t, e, s) => {
65
- const o = new Array(t);
66
- for (let n = 0; n < t; n++)
67
- o[n] = s.norm(e);
68
- return o;
69
- }, R = (t) => t.reduce((e, s) => e + s, 0);
70
- function* I(t, e) {
71
- const s = [t[Symbol.iterator](), e[Symbol.iterator]()];
72
- for (let o = 0; ; o ^= 1) {
73
- const n = s[o].next();
74
- if (n.done)
75
- return;
76
- yield n.value;
77
- }
75
+ once: false
76
+ };
77
+
78
+ const meta = {
79
+ version: "1.1.2",
80
+ date: "2022-11-06T12:24:34.397Z"
81
+ };
82
+
83
+ const preseed = (n, scale, rnd) => {
84
+ const state = new Array(n);
85
+ for (let i = 0; i < n; i++) {
86
+ state[i] = rnd.norm(scale);
87
+ }
88
+ return state;
89
+ };
90
+ const sum = (src) => src.reduce((sum, x) => sum + x, 0);
91
+ function* interleave(a, b) {
92
+ const src = [a[Symbol.iterator](), b[Symbol.iterator]()];
93
+ for (let i = 0; true; i ^= 1) {
94
+ const next = src[i].next();
95
+ if (next.done)
96
+ return;
97
+ yield next.value;
98
+ }
78
99
  }
79
- function* p(t = 2, e = 1, s = h) {
80
- const o = b(t, e, s);
81
- o.forEach((i, c) => o[c] = c & 1 ? i : -i);
82
- const n = 1 / t;
83
- let r = R(o);
84
- for (let i = 0, c = -1; ; ++i >= t && (i = 0))
85
- r -= o[i], r += o[i] = c * s.norm(e), c ^= 4294967294, yield c * r * n;
100
+
101
+ /**
102
+ * High-pass filtered noise. Opposite of {@link red}.
103
+ *
104
+ * @param n -
105
+ * @param scale -
106
+ * @param rnd -
107
+ */
108
+ function* blue(n = 2, scale = 1, rnd = SYSTEM) {
109
+ const state = preseed(n, scale, rnd);
110
+ state.forEach((x, i) => (state[i] = i & 1 ? x : -x));
111
+ const invN = 1 / n;
112
+ let acc = sum(state);
113
+ for (let i = 0, sign = -1; true; ++i >= n && (i = 0)) {
114
+ acc -= state[i];
115
+ acc += state[i] = sign * rnd.norm(scale);
116
+ sign ^= 0xfffffffe;
117
+ yield sign * acc * invN;
118
+ }
86
119
  }
87
- const A = (t = 2, e = 1, s = h) => I(p(t, e, s), p(t, e, s)), T = (t) => {
88
- let e = 32;
89
- return t &= -t, t && e--, t & 65535 && (e -= 16), t & 16711935 && (e -= 8), t & 252645135 && (e -= 4), t & 858993459 && (e -= 2), t & 1431655765 && (e -= 1), e;
120
+
121
+ /**
122
+ * Band-pass filtered noise (interleaved blue noise). Opposite of
123
+ * {@link violet}.
124
+ *
125
+ * @param n -
126
+ * @param scale -
127
+ * @param rnd -
128
+ */
129
+ const green = (n = 2, scale = 1, rnd = SYSTEM) => interleave(blue(n, scale, rnd), blue(n, scale, rnd));
130
+
131
+ /**
132
+ * Returns number of 1 bits in `x`.
133
+ *
134
+ * @param x -
135
+ */
136
+ const ctz32 = (x) => {
137
+ let c = 32;
138
+ x &= -x;
139
+ x && c--;
140
+ x & 0x0000ffff && (c -= 16);
141
+ x & 0x00ff00ff && (c -= 8);
142
+ x & 0x0f0f0f0f && (c -= 4);
143
+ x & 0x33333333 && (c -= 2);
144
+ x & 0x55555555 && (c -= 1);
145
+ return c;
90
146
  };
91
- function* $(t = 8, e = 1, s = h) {
92
- const o = b(t, e, s), n = 1 / t;
93
- let r = R(o);
94
- for (let i = 0; ; i = i + 1 >>> 0) {
95
- const c = T(i) % t;
96
- r -= o[c], r += o[c] = s.norm(e), yield r * n;
97
- }
147
+
148
+ /**
149
+ * Exponential decay (1/f) noise, based on Voss-McCarthy algorithm.
150
+ *
151
+ * @remarks
152
+ * The number of internal states should be in the [4..32] range (default: 8).
153
+ * Due to JS integer limitations, `n` > 32 are meaningless.
154
+ *
155
+ * References:
156
+ *
157
+ * - https://www.dsprelated.com/showarticle/908.php
158
+ * - https://www.firstpr.com.au/dsp/pink-noise/#Voss-McCartney
159
+ *
160
+ * @param n -
161
+ * @param scale -
162
+ * @param rnd -
163
+ */
164
+ function* pink(n = 8, scale = 1, rnd = SYSTEM) {
165
+ const state = preseed(n, scale, rnd);
166
+ const invN = 1 / n;
167
+ let acc = sum(state);
168
+ for (let i = 0; true; i = (i + 1) >>> 0) {
169
+ const id = ctz32(i) % n;
170
+ acc -= state[id];
171
+ acc += state[id] = rnd.norm(scale);
172
+ yield acc * invN;
173
+ }
98
174
  }
99
- function* m(t = 2, e = 1, s = h) {
100
- const o = b(t, e, s), n = 1 / t;
101
- let r = R(o);
102
- for (let i = 0; ; ++i >= t && (i = 0))
103
- r -= o[i], r += o[i] = s.norm(e), yield r * n;
175
+
176
+ /**
177
+ * Low-pass filtered noise (same as brown noise). Opposite of {@link blue}.
178
+ *
179
+ * @param n -
180
+ * @param scale -
181
+ * @param rnd -
182
+ */
183
+ function* red(n = 2, scale = 1, rnd = SYSTEM) {
184
+ const state = preseed(n, scale, rnd);
185
+ const invN = 1 / n;
186
+ let acc = sum(state);
187
+ for (let i = 0; true; ++i >= n && (i = 0)) {
188
+ acc -= state[i];
189
+ acc += state[i] = rnd.norm(scale);
190
+ yield acc * invN;
191
+ }
104
192
  }
105
- const F = (t = 2, e = 1, s = h) => I(m(t, e, s), m(t, e, s));
106
- function* y(t = 1, e = h) {
107
- for (; ; )
108
- yield e.norm(t);
193
+
194
+ /**
195
+ * Band-stop filtered noise (interleaved red noise). Opposite of {@link green}.
196
+ *
197
+ * @param n -
198
+ * @param scale -
199
+ * @param rnd -
200
+ */
201
+ const violet = (n = 2, scale = 1, rnd = SYSTEM) => interleave(red(n, scale, rnd), red(n, scale, rnd));
202
+
203
+ /**
204
+ * Unfiltered noise w/ uniform distribution. Merely yields samples from
205
+ * given PRNG.
206
+ *
207
+ * @param scale -
208
+ * @param rnd -
209
+ */
210
+ function* white(scale = 1, rnd = SYSTEM) {
211
+ while (true) {
212
+ yield rnd.norm(scale);
213
+ }
109
214
  }
110
- const x = (t, e) => t != null && typeof t[e] == "function", C = (t) => x(t, "xform") ? t.xform() : t, B = (t) => t != null && typeof t[Symbol.iterator] == "function";
111
- class u {
112
- constructor(e) {
113
- this.value = e;
114
- }
115
- deref() {
116
- return this.value;
117
- }
215
+
216
+ const implementsFunction = (x, fn) => x != null && typeof x[fn] === "function";
217
+
218
+ const ensureTransducer = (x) => implementsFunction(x, "xform") ? x.xform() : x;
219
+
220
+ const isIterable = (x) => x != null && typeof x[Symbol.iterator] === "function";
221
+
222
+ class Reduced {
223
+ constructor(val) {
224
+ this.value = val;
225
+ }
226
+ deref() {
227
+ return this.value;
228
+ }
118
229
  }
119
- const D = (t) => new u(t), L = (t) => t instanceof u, Q = (t) => t instanceof u ? t : new u(t), N = (t) => t instanceof u ? t.deref() : t, W = (t, e) => [t, (s) => s, e];
120
- function q(t) {
121
- return t ? [...t] : W(() => [], (e, s) => (e.push(s), e));
230
+ const reduced = (x) => new Reduced(x);
231
+ const isReduced = (x) => x instanceof Reduced;
232
+ const ensureReduced = (x) => x instanceof Reduced ? x : new Reduced(x);
233
+ const unreduced = (x) => (x instanceof Reduced ? x.deref() : x);
234
+
235
+ /**
236
+ * Convenience helper for building a full {@link Reducer} using the identity
237
+ * function (i.e. `(x) => x`) as completion step (true for 90% of all
238
+ * bundled transducers).
239
+ *
240
+ * @param init - init step of reducer
241
+ * @param rfn - reduction step of reducer
242
+ */
243
+ const reducer = (init, rfn) => [init, (acc) => acc, rfn];
244
+
245
+ function push(xs) {
246
+ return xs
247
+ ? [...xs]
248
+ : reducer(() => [], (acc, x) => (acc.push(x), acc));
122
249
  }
123
- function* H(t, e) {
124
- const s = C(t)(q()), o = s[1], n = s[2];
125
- for (let r of e) {
126
- const i = n([], r);
127
- if (L(i)) {
128
- yield* N(o(i.deref()));
129
- return;
250
+
251
+ /**
252
+ * Takes a transducer and input iterable. Returns iterator of
253
+ * transformed results.
254
+ *
255
+ * @param xform -
256
+ * @param xs -
257
+ */
258
+ function* iterator(xform, xs) {
259
+ const rfn = ensureTransducer(xform)(push());
260
+ const complete = rfn[1];
261
+ const reduce = rfn[2];
262
+ for (let x of xs) {
263
+ const y = reduce([], x);
264
+ if (isReduced(y)) {
265
+ yield* unreduced(complete(y.deref()));
266
+ return;
267
+ }
268
+ if (y.length) {
269
+ yield* y;
270
+ }
130
271
  }
131
- i.length && (yield* i);
132
- }
133
- yield* N(o([]));
272
+ yield* unreduced(complete([]));
134
273
  }
135
- const M = (t, e) => [t[0], t[1], e];
136
- function E(t, e) {
137
- return B(e) ? H(E(t), e) : (s) => {
138
- const o = s[2];
139
- let n = t;
140
- return M(s, (r, i) => --n > 0 ? o(r, i) : n === 0 ? Q(o(r, i)) : D(r));
141
- };
274
+
275
+ /**
276
+ * Reducer composition helper, internally used by various transducers
277
+ * during initialization. Takes existing reducer `rfn` (a 3-tuple) and a
278
+ * reducing function `fn`. Returns a new reducer tuple.
279
+ *
280
+ * @remarks
281
+ * `rfn[2]` reduces values of type `B` into an accumulator of type `A`.
282
+ * `fn` accepts values of type `C` and produces interim results of type
283
+ * `B`, which are then (possibly) passed to the "inner" `rfn[2]`
284
+ * function. Therefore the resulting reducer takes inputs of `C` and an
285
+ * accumulator of type `A`.
286
+ *
287
+ * It is assumed that `fn` internally calls `rfn[2]` to pass its own
288
+ * results for further processing by the nested reducer `rfn`.
289
+ *
290
+ * @example
291
+ * ```ts
292
+ * compR(rfn, fn)
293
+ * // [rfn[0], rfn[1], fn]
294
+ * ```
295
+ *
296
+ * @param rfn -
297
+ * @param fn -
298
+ */
299
+ const compR = (rfn, fn) => [rfn[0], rfn[1], fn];
300
+
301
+ function take(n, src) {
302
+ return isIterable(src)
303
+ ? iterator(take(n), src)
304
+ : (rfn) => {
305
+ const r = rfn[2];
306
+ let m = n;
307
+ return compR(rfn, (acc, x) => --m > 0
308
+ ? r(acc, x)
309
+ : m === 0
310
+ ? ensureReduced(r(acc, x))
311
+ : reduced(acc));
312
+ };
142
313
  }
143
- class v {
144
- constructor(e, s) {
145
- this.noise = y, this.ctx = e, this.options = { ...G, ...s }, this.wetGainNode = this.ctx.createGain(), this.dryGainNode = this.ctx.createGain(), this.filterNode = this.ctx.createBiquadFilter(), this.convolverNode = this.ctx.createConvolver(), this.outputNode = this.ctx.createGain(), this.isConnected = !1, this.setNoise(this.options.noise), this.buildImpulse(), this.mix(this.options.mix);
314
+
315
+ class Reverb {
316
+ constructor(ctx, options) {
317
+ this.noise = white;
318
+ this.ctx = ctx;
319
+ this.options = { ...defaults, ...options };
320
+ this.wetGainNode = this.ctx.createGain();
321
+ this.dryGainNode = this.ctx.createGain();
322
+ this.filterNode = this.ctx.createBiquadFilter();
323
+ this.convolverNode = this.ctx.createConvolver();
324
+ this.outputNode = this.ctx.createGain();
325
+ this.isConnected = false;
326
+ this.filterType(this.options.filterType);
327
+ this.setNoise(this.options.noise);
328
+ this.buildImpulse();
329
+ this.mix(this.options.mix);
146
330
  }
147
- connect(e) {
148
- return this.isConnected && this.options.once ? (this.isConnected = !1, this.outputNode) : (this.convolverNode.connect(this.filterNode), this.filterNode.connect(this.wetGainNode), e.connect(this.convolverNode), e.connect(this.dryGainNode).connect(this.outputNode), e.connect(this.wetGainNode).connect(this.outputNode), this.isConnected = !0, this.outputNode);
331
+ connect(sourceNode) {
332
+ if (this.isConnected && this.options.once) {
333
+ this.isConnected = false;
334
+ return this.outputNode;
335
+ }
336
+ this.convolverNode.connect(this.filterNode);
337
+ this.filterNode.connect(this.wetGainNode);
338
+ sourceNode.connect(this.convolverNode);
339
+ sourceNode.connect(this.dryGainNode).connect(this.outputNode);
340
+ sourceNode.connect(this.wetGainNode).connect(this.outputNode);
341
+ this.isConnected = true;
342
+ return this.outputNode;
149
343
  }
150
- disconnect(e) {
151
- return this.isConnected && (this.convolverNode.disconnect(this.filterNode), this.filterNode.disconnect(this.wetGainNode)), this.isConnected = !1, e;
344
+ disconnect(sourceNode) {
345
+ if (this.isConnected) {
346
+ this.convolverNode.disconnect(this.filterNode);
347
+ this.filterNode.disconnect(this.wetGainNode);
348
+ }
349
+ this.isConnected = false;
350
+ return sourceNode;
152
351
  }
153
- mix(e) {
154
- if (!this.inRange(e, 0, 1))
352
+ mix(mix) {
353
+ if (!this.inRange(mix, 0, 1)) {
155
354
  throw new RangeError("[Reverb.js] Dry/Wet ratio must be between 0 to 1.");
156
- this.options.mix = e, this.dryGainNode.gain.value = 1 - this.options.mix, this.wetGainNode.gain.value = this.options.mix, console.debug(`[Reverb.js] Set dry/wet ratio to ${e * 100}%`);
355
+ }
356
+ this.options.mix = mix;
357
+ this.dryGainNode.gain.value = 1 - this.options.mix;
358
+ this.wetGainNode.gain.value = this.options.mix;
157
359
  }
158
- time(e) {
159
- if (!this.inRange(e, 1, 50))
360
+ time(value) {
361
+ if (!this.inRange(value, 1, 50)) {
160
362
  throw new RangeError(
161
363
  "[Reverb.js] Time length of inpulse response must be less than 50sec."
162
364
  );
163
- this.options.time = e, this.buildImpulse(), console.debug(
164
- `[Reverb.js] Set inpulse response time length to ${e}sec.`
165
- );
365
+ }
366
+ this.options.time = value;
367
+ this.buildImpulse();
166
368
  }
167
- decay(e) {
168
- if (!this.inRange(e, 0, 100))
369
+ decay(value) {
370
+ if (!this.inRange(value, 0, 100)) {
169
371
  throw new RangeError(
170
372
  "[Reverb.js] Inpulse Response decay level must be less than 100."
171
373
  );
172
- this.options.decay = e, this.buildImpulse(), console.debug(`[Reverb.js] Set inpulse response decay level to ${e}.`);
374
+ }
375
+ this.options.decay = value;
376
+ this.buildImpulse();
173
377
  }
174
- delay(e) {
175
- if (!this.inRange(e, 0, 100))
378
+ delay(value) {
379
+ if (!this.inRange(value, 0, 100)) {
176
380
  throw new RangeError(
177
381
  "[Reverb.js] Inpulse Response delay time must be less than 100."
178
382
  );
179
- this.options.delay = e, this.buildImpulse(), console.debug(
180
- `[Reverb.js] Set inpulse response delay time to ${e}sec.`
181
- );
383
+ }
384
+ this.options.delay = value;
385
+ this.buildImpulse();
182
386
  }
183
- reverse(e) {
184
- this.options.reverse = e, this.buildImpulse(), console.debug(
185
- `[Reverb.js] Inpulse response is ${e ? "" : "not "}reversed.`
186
- );
387
+ reverse(reverse) {
388
+ this.options.reverse = reverse;
389
+ this.buildImpulse();
187
390
  }
188
- filterType(e) {
189
- this.filterNode.type = this.options.filterType = e, console.debug(`[Reverb.js] Set filter type to ${e}`);
391
+ filterType(type = "allpass") {
392
+ this.filterNode.type = this.options.filterType = type;
190
393
  }
191
- filterFreq(e) {
192
- if (!this.inRange(e, 20, 2e4))
394
+ filterFreq(freq) {
395
+ if (!this.inRange(freq, 20, 2e4)) {
193
396
  throw new RangeError(
194
397
  "[Reverb.js] Filter frequrncy must be between 20 and 20000."
195
398
  );
196
- this.options.filterFreq = e, this.filterNode.frequency.value = this.options.filterFreq, console.debug(`[Reverb.js] Set filter frequency to ${e}Hz.`);
399
+ }
400
+ this.options.filterFreq = freq;
401
+ this.filterNode.frequency.value = this.options.filterFreq;
197
402
  }
198
- filterQ(e) {
199
- if (!this.inRange(e, 0, 10))
403
+ filterQ(q) {
404
+ if (!this.inRange(q, 0, 10)) {
200
405
  throw new RangeError(
201
406
  "[Reverb.js] Filter quality value must be between 0 and 10."
202
407
  );
203
- this.options.filterQ = e, this.filterNode.Q.value = this.options.filterQ, console.debug(`[Reverb.js] Set filter Q to ${e}.`);
408
+ }
409
+ this.options.filterQ = q;
410
+ this.filterNode.Q.value = this.options.filterQ;
204
411
  }
205
- peaks(e) {
206
- this.options.peaks = e, this.buildImpulse(), console.debug(`[Reverb.js] Set IR source noise peaks to ${e}.`);
412
+ peaks(p) {
413
+ this.options.peaks = p;
414
+ this.buildImpulse();
207
415
  }
208
- scale(e) {
209
- this.options.scale = e, this.buildImpulse(), console.debug(`[Reverb.js] Set IR source noise scale to ${e}.`);
416
+ scale(s) {
417
+ this.options.scale = s;
418
+ this.buildImpulse();
210
419
  }
211
- randomAlgorithm(e) {
212
- this.options.randomAlgorithm = e, this.buildImpulse(), console.debug(`[Reverb.js] Set IR source noise generator to ${e}.`);
420
+ randomAlgorithm(a) {
421
+ this.options.randomAlgorithm = a;
422
+ this.buildImpulse();
213
423
  }
214
- setNoise(e) {
215
- switch (this.options.noise = e, e) {
216
- case a.BLUE:
217
- this.noise = p;
424
+ setNoise(type) {
425
+ this.options.noise = type;
426
+ switch (type) {
427
+ case Noise.BLUE:
428
+ this.noise = blue;
218
429
  break;
219
- case a.GREEN:
220
- this.noise = A;
430
+ case Noise.GREEN:
431
+ this.noise = green;
221
432
  break;
222
- case a.PINK:
223
- this.noise = $;
433
+ case Noise.PINK:
434
+ this.noise = pink;
224
435
  break;
225
- case a.RED:
226
- case a.BROWN:
227
- this.noise = m;
436
+ case Noise.RED:
437
+ case Noise.BROWN:
438
+ this.noise = red;
228
439
  break;
229
- case a.VIOLET:
230
- this.noise = F;
440
+ case Noise.VIOLET:
441
+ this.noise = violet;
231
442
  break;
232
443
  default:
233
- this.noise = y;
234
- break;
444
+ this.noise = white;
235
445
  }
236
- this.buildImpulse(), console.debug(`[Reverb.js] Set IR generator source noise type to ${e}.`);
446
+ this.buildImpulse();
237
447
  }
238
- setRandomAlgorythm(e) {
239
- this.options.randomAlgorithm = e, this.buildImpulse();
448
+ setRandomAlgorythm(algorithm) {
449
+ this.options.randomAlgorithm = algorithm;
450
+ this.buildImpulse();
240
451
  }
241
- inRange(e, s, o) {
242
- return (e - s) * (e - o) <= 0;
452
+ inRange(x, min, max) {
453
+ return (x - min) * (x - max) <= 0;
243
454
  }
244
455
  buildImpulse() {
245
- const e = this.ctx.sampleRate, s = Math.max(e * this.options.time, 1), o = e * this.options.delay, n = this.ctx.createBuffer(2, s, e), r = new Float32Array(s), i = new Float32Array(s), c = this.getNoise(s), j = this.getNoise(s);
246
- for (let l = 0; l < s; l++) {
247
- let d = 0;
248
- l < o ? (r[l] = 0, i[l] = 0, d = this.options.reverse ? s - (l - o) : l - o) : d = this.options.reverse ? s - l : l, r[l] = c[l] * (1 - d / s) ** this.options.decay, i[l] = j[l] * (1 - d / s) ** this.options.decay;
456
+ const rate = this.ctx.sampleRate;
457
+ const duration = Math.max(rate * this.options.time, 1);
458
+ const delayDuration = rate * this.options.delay;
459
+ const impulse = this.ctx.createBuffer(2, duration, rate);
460
+ const impulseL = new Float32Array(duration);
461
+ const impulseR = new Float32Array(duration);
462
+ const noiseL = this.getNoise(duration);
463
+ const noiseR = this.getNoise(duration);
464
+ for (let i = 0; i < duration; i++) {
465
+ let n = 0;
466
+ if (i < delayDuration) {
467
+ impulseL[i] = 0;
468
+ impulseR[i] = 0;
469
+ n = this.options.reverse ? duration - (i - delayDuration) : i - delayDuration;
470
+ } else {
471
+ n = this.options.reverse ? duration - i : i;
472
+ }
473
+ impulseL[i] = noiseL[i] * (1 - n / duration) ** this.options.decay;
474
+ impulseR[i] = noiseR[i] * (1 - n / duration) ** this.options.decay;
249
475
  }
250
- n.getChannelData(0).set(r), n.getChannelData(1).set(i), this.convolverNode.buffer = n;
476
+ impulse.getChannelData(0).set(impulseL);
477
+ impulse.getChannelData(1).set(impulseR);
478
+ this.convolverNode.buffer = impulse;
251
479
  }
252
- getNoise(e) {
480
+ getNoise(duration) {
253
481
  return [
254
- ...E(
255
- e,
256
- this.options.noise === a.WHITE ? this.noise(this.options.peaks, this.options.randomAlgorithm) : this.noise(
482
+ ...take(
483
+ duration,
484
+ this.noise === white ? white(this.options.scale, this.options.randomAlgorithm) : this.noise(
257
485
  this.options.peaks,
258
486
  this.options.scale,
259
487
  this.options.randomAlgorithm
@@ -262,9 +490,10 @@ class v {
262
490
  ];
263
491
  }
264
492
  }
265
- v.version = w.version;
266
- v.build = w.date;
267
- window.Reverb || (window.Reverb = v);
268
- export {
269
- v as default
270
- };
493
+ Reverb.version = meta.version;
494
+ Reverb.build = meta.date;
495
+ if (!window.Reverb) {
496
+ window.Reverb = Reverb;
497
+ }
498
+
499
+ export { Reverb as default };