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