@logue/reverb 0.4.2 → 0.5.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.
@@ -1,718 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en" class="h-100">
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta
6
- name="viewport"
7
- content="width=device-width, initial-scale=1, shrink-to-fit=no"
8
- />
9
- <meta name="description" content="Reverb effect written in JavaScript." />
10
- <meta name="author" content="Masashi Yoshikawa" />
11
- <!-- ogp -->
12
- <meta property="og:title" content="JavaScript Reverb Effect Test" />
13
- <meta property="og:type" content="article" />
14
- <meta property="og:url" content="https://logue.github.io/Reverb.js/" />
15
- <meta
16
- property="og:image"
17
- content="https://repository-images.githubusercontent.com/194181712/20bdd780-9995-11e9-8811-42e3b44d1cec"
18
- />
19
- <meta property="og:site_name" content="Logue's Lab" />
20
- <meta
21
- property="og:description"
22
- content="Reverb effect written in JavaScript."
23
- />
24
- <meta property="fb:app_id" content="129144050466298" />
25
- <meta
26
- property="article:publisher"
27
- content="https://www.facebook.com/logue256"
28
- />
29
- <meta name="twitter:card" content="Summary" />
30
- <meta name="twitter:site" content="@logue256" />
31
- <meta name="twitter:title" content="JavaScript Reverb Effect Test" />
32
- <meta
33
- name="twitter:url"
34
- content="https://logue.github.io/Reverb.js/localaudio.html"
35
- />
36
- <meta
37
- name="twitter:description"
38
- content="Reverb effect written in JavaScript."
39
- />
40
- <meta
41
- name="twitter:image"
42
- content="https://repository-images.githubusercontent.com/194181712/20bdd780-9995-11e9-8811-42e3b44d1cec"
43
- />
44
- <title>Reverb.js Demo</title>
45
- <!-- Global site tag (gtag.js) - Google Analytics -->
46
- <script
47
- async
48
- src="https://www.googletagmanager.com/gtag/js?id=UA-33600926-1"
49
- ></script>
50
- <script>
51
- window.dataLayer = window.dataLayer || [];
52
- function gtag() {
53
- dataLayer.push(arguments);
54
- }
55
- gtag('js', new Date());
56
-
57
- gtag('config', 'UA-33600926-1');
58
- </script>
59
- <link rel="dns-prefetch" href="https://cdn.jsdelivr.net/" />
60
- <!-- Bootstrap core CSS -->
61
- <link
62
- rel="stylesheet"
63
- href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css"
64
- integrity="sha256-93wNFzm2GO3EoByj9rKZCwGjAJAwr0nujPaOgwUt8ZQ="
65
- crossorigin="anonymous"
66
- />
67
- <!-- Web Fonts -->
68
- <link
69
- href="https://fonts.googleapis.com/css?family=M+PLUS+Rounded+1c|Varela+Round&display=swap"
70
- rel="stylesheet"
71
- />
72
- <link
73
- rel="stylesheet"
74
- href="https://use.fontawesome.com/releases/v5.12.0/css/all.css"
75
- />
76
- <style>
77
- /*<!CDATA[*/
78
- body {
79
- font-family: 'Varela Round', 'Rounded Mplus 1c', sans-serif;
80
- }
81
-
82
- /*]]>*/
83
- </style>
84
- </head>
85
-
86
- <body class="d-flex flex-column h-100 pt-5">
87
- <header>
88
- <!-- Fixed navbar -->
89
- <nav class="navbar navbar-expand-md navbar-dark fixed-top bg-dark">
90
- <a class="navbar-brand" href="#">Reverb.js</a>
91
- <button
92
- class="navbar-toggler"
93
- type="button"
94
- data-toggle="collapse"
95
- data-target="#navbarCollapse"
96
- aria-controls="navbarCollapse"
97
- aria-expanded="false"
98
- aria-label="Toggle navigation"
99
- >
100
- <span class="navbar-toggler-icon"></span>
101
- </button>
102
- <div class="collapse navbar-collapse" id="navbarCollapse">
103
- <ul class="navbar-nav ml-auto mar-0">
104
- <li class="nav-item active">
105
- <a class="nav-link" href="#"
106
- >Demo <span class="sr-only">(current)</span></a
107
- >
108
- </li>
109
- <li class="nav-item">
110
- <a class="nav-link" href="https://github.com/logue/Reverb.js"
111
- >Github</a
112
- >
113
- </li>
114
- </ul>
115
- </div>
116
- </nav>
117
- </header>
118
-
119
- <!-- Begin page content -->
120
- <main role="main" class="flex-shrink-0 mt-2">
121
- <div class="container">
122
- <h1>Reverb.js Demo</h1>
123
- <div class="d-flex">
124
- <div>
125
- <button id="play" class="btn btn-primary" disabled>
126
- <i class="fas fa-play"></i> Play
127
- </button>
128
- </div>
129
- <div>
130
- <button id="stop" class="btn btn-secondary" disabled>
131
- <i class="fas fa-stop"></i> Stop
132
- </button>
133
- </div>
134
- <div class="custom-file form-control-sm ml-3">
135
- <input
136
- type="file"
137
- class="custom-file-input"
138
- id="file"
139
- accept="audio/*"
140
- />
141
- <label class="custom-file-label" for="file"
142
- >Load Audio file
143
- <small class="d-none d-sm-inline"
144
- >(drag and drop file to change audio)</small
145
- >
146
- </label>
147
- </div>
148
- </div>
149
- <h2>Reverb Control</h2>
150
- <div class="custom-control custom-switch">
151
- <input id="reverb" type="checkbox" class="custom-control-input" />
152
- <label class="custom-control-label" for="reverb">Reverb</label>
153
- </div>
154
- <div class="form-row">
155
- <div class="col">
156
- <div class="form-group">
157
- <label for="time">Time</label>
158
- <input
159
- type="range"
160
- class="custom-range"
161
- value="3"
162
- min="0"
163
- max="50"
164
- id="time"
165
- />
166
- </div>
167
- </div>
168
- <div class="col">
169
- <div class="form-group">
170
- <label for="decay">Decay</label>
171
- <input
172
- type="range"
173
- class="custom-range"
174
- value="2"
175
- min="0"
176
- max="100"
177
- id="decay"
178
- />
179
- </div>
180
- </div>
181
- <div class="col">
182
- <div class="form-group">
183
- <label for="delay">Delay</label>
184
- <input
185
- type="range"
186
- class="custom-range"
187
- value="0"
188
- min="0"
189
- max="100"
190
- id="delay"
191
- />
192
- </div>
193
- </div>
194
- </div>
195
- <div class="form-group">
196
- <div class="custom-control custom-checkbox">
197
- <input type="checkbox" class="custom-control-input" id="reverse" />
198
- <label class="custom-control-label" for="reverse">Reverse</label>
199
- </div>
200
- </div>
201
- <div class="form-row">
202
- <div class="col">
203
- <div class="form-group">
204
- <label for="filter">Filter Type</label>
205
- <select id="filter" class="form-control">
206
- <option value="lowpass" selected="selected">lowpass</option>
207
- <option value="highpass">highpass</option>
208
- <option value="bandpass">bandpass</option>
209
- <option value="lowshelf">lowshelf</option>
210
- <option value="highshelf">highshelf</option>
211
- <option value="peaking">peaking</option>
212
- <option value="notch">notch</option>
213
- <option value="allpass">allpass</option>
214
- </select>
215
- </div>
216
- </div>
217
- <div class="col">
218
- <div class="form-group">
219
- <label for="freq">Filter frequency</label>
220
- <input
221
- type="range"
222
- class="custom-range"
223
- value="2500"
224
- min="20"
225
- max="5000"
226
- step="5"
227
- id="freq"
228
- />
229
- </div>
230
- </div>
231
- <div class="col">
232
- <div class="form-group">
233
- <label for="freq">Quality (Q) value</label>
234
- <input
235
- type="range"
236
- class="custom-range"
237
- value="1"
238
- min=".0001"
239
- max="10"
240
- step=".0005"
241
- id="q"
242
- />
243
- </div>
244
- </div>
245
- </div>
246
- <div class="form-group">
247
- <label for="mix">Dry / Wet</label>
248
- <div class="input-group mb-3">
249
- <div class="input-group-prepend">
250
- <span class="input-group-text">Dry</span>
251
- </div>
252
- <div class="form-control">
253
- <input
254
- type="range"
255
- id="mix"
256
- class="custom-range"
257
- min="0"
258
- max="1"
259
- step="0.05"
260
- value="0.5"
261
- />
262
- </div>
263
- <div class="input-group-append">
264
- <span class="input-group-text">Wet</span>
265
- </div>
266
- </div>
267
- </div>
268
- <h2>Spectrum Analysis</h2>
269
- <div class="overflow-auto">
270
- <canvas id="canvas" class="d-none"></canvas>
271
- <img id="test" class="d-none" />
272
- <canvas id="graph"></canvas>
273
- </div>
274
- </div>
275
- </main>
276
-
277
- <footer class="footer mt-auto py-3 bg-light">
278
- <div class="container">
279
- <address class="text-muted">
280
- <i class="far fa-copyright"></i> 2019 by Logue / MIT License.
281
- </address>
282
- </div>
283
- </footer>
284
- <!--script src="https://cdn.jsdelivr.net/npm/jquery@3.4.1/dist/jquery.slim.min.js"
285
- integrity="sha256-pasqAKBDmFT4eHoN2ndd6lN370kFiGUFyTiUHWhU7k8=" crossorigin="anonymous"></script>
286
- <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/js/bootstrap.bundle.min.js"
287
- integrity="sha256-fzFFyH01cBVPYzl16KT40wqjhgPtq6FFUB6ckN2+GGw=" crossorigin="anonymous"></script-->
288
- <script
289
- src="https://cdn.jsdelivr.net/npm/three-js@79.0.0/three.js"
290
- integrity="sha256-A2ofbc4qfSfxXRlxuONE0Bj7ulHxEAIiYk537fvbkJU="
291
- crossorigin="anonymous"
292
- ></script>
293
- <script src="reverb.js"></script>
294
- <script>
295
- // Setup Audio Context
296
- const AudioCtx = new (window.AudioContext || window.webkitAudioContext)();
297
-
298
- // Defreeze AudioContext for iOS.
299
- document.addEventListener('touchstart', initAudioContext);
300
- function initAudioContext() {
301
- document.removeEventListener('touchstart', initAudioContext);
302
- // wake up AudioContext
303
- const emptySource = AudioCtx.createBufferSource();
304
- emptySource.start();
305
- emptySource.stop();
306
- }
307
-
308
- // Audio object
309
- const audio = new Audio();
310
-
311
- // Audio Source
312
- const AudioSrc = AudioCtx.createMediaElementSource(audio);
313
-
314
- // Analyzer Node
315
- const AnalyserNode = AudioCtx.createAnalyser();
316
-
317
- // Setup Reverb Class
318
- const reverb = new Reverb.default(AudioCtx);
319
-
320
- // decode audio
321
- const LoadSample = async input => {
322
- if (audio) {
323
- audio.pause();
324
- audio.src = '';
325
- }
326
- audio.src = await loadDataUri(input);
327
- };
328
-
329
- // Load array buffer
330
- const loadDataUri = async input => {
331
- document.getElementById('play').disabled = 'disabled';
332
- document.getElementById('stop').disabled = 'disabled';
333
- return await new Promise(resolve => {
334
- if (input instanceof File) {
335
- const reader = new FileReader();
336
- reader.onload = event => {
337
- resolve(event.target.result);
338
- document.getElementById('play').disabled = '';
339
- document.getElementById('stop').disabled = '';
340
- };
341
- reader.readAsDataURL(input);
342
- } else {
343
- fetch(input)
344
- .then(response => {
345
- return {
346
- mime: response.headers.get('content-type'),
347
- buffer: response.arrayBuffer(),
348
- };
349
- })
350
- .then(res => {
351
- // to base64
352
- let binary = '';
353
- let bytes = [].slice.call(new Uint8Array(res.buffer));
354
-
355
- bytes.forEach(b => (binary += String.fromCharCode(b)));
356
- const base64 = window.btoa(binary);
357
- // prepend data scheme
358
- resolve('data:' + res.mime + ';base64;' + base64);
359
-
360
- document.getElementById('play').disabled = '';
361
- document.getElementById('stop').disabled = '';
362
- });
363
- }
364
- }).catch(e => alert(e));
365
- };
366
-
367
- const handleFileSelect = async e => {
368
- const file = e.target.files[0];
369
- AudioSrc.buffer = await LoadSample(file);
370
- };
371
-
372
- // Reverb switch handler
373
- const setReverb = () => {
374
- AudioSrc.disconnect();
375
-
376
- if (document.getElementById('reverb').checked) {
377
- // Connect Reverb
378
- reverb.connect(AudioSrc).connect(AnalyserNode);
379
- } else {
380
- reverb.disconnect(AudioSrc).connect(AnalyserNode);
381
- }
382
- AnalyserNode.connect(AudioCtx.destination);
383
- };
384
-
385
- /**
386
- * Draw Texture Functions
387
- **/
388
- const PIXEL_RATIO = () => {
389
- const ctx = document.createElement('canvas').getContext('2d'),
390
- dpr = window.devicePixelRatio || 1,
391
- bsr =
392
- ctx.webkitBackingStorePixelRatio ||
393
- ctx.mozBackingStorePixelRatio ||
394
- ctx.msBackingStorePixelRatio ||
395
- ctx.oBackingStorePixelRatio ||
396
- ctx.backingStorePixelRatio ||
397
- 1;
398
- return dpr / bsr;
399
- };
400
-
401
- // Create retina quality canvas
402
- const createRetinaCanvas = (w, h, ratio) => {
403
- if (!ratio) {
404
- ratio = PIXEL_RATIO;
405
- }
406
- const canvas = document.getElementById('canvas');
407
- //const canvas = document.createElement('canvas');
408
- canvas.width = w * ratio;
409
- canvas.height = h * ratio;
410
- canvas.style.width = w + 'px';
411
- canvas.style.height = h + 'px';
412
- canvas.getContext('2d').setTransform(ratio, 0, 0, ratio, 0, 0);
413
- return canvas;
414
- };
415
-
416
- // Spectrum Analysis canvas size
417
- const SPRITE_HEIGHT = 256;
418
- const SPRITE_WIDTH = 512;
419
-
420
- // Sprite Canvas
421
- const spriteCanvas = createRetinaCanvas(SPRITE_WIDTH, SPRITE_HEIGHT);
422
-
423
- // Draw Graph
424
- const DrawGraph = () => {
425
- const AnalyseData = new Float32Array(1024);
426
- AnalyserNode.getFloatFrequencyData(AnalyseData);
427
-
428
- const sprite = spriteCanvas.getContext('2d', {antialias: false});
429
-
430
- // Background
431
- //sprite.fillStyle = "#343a40";
432
- //sprite.fillRect(0, 0, SPRITE_WIDTH, SPRITE_HEIGHT);
433
-
434
- sprite.clearRect(0, 0, spriteCanvas.width, spriteCanvas.height);
435
-
436
- // Graph
437
- const grad = sprite.createLinearGradient(0, 0, spriteCanvas.width, 0);
438
- grad.addColorStop(0, 'rgb(255, 0, 0)');
439
- grad.addColorStop(0.2, 'rgb(255, 255, 0)');
440
- grad.addColorStop(0.4, 'rgb(0, 255, 0)');
441
- grad.addColorStop(0.6, 'rgb(0, 255, 255)');
442
- grad.addColorStop(0.8, 'rgb(0, 0, 255)');
443
- grad.addColorStop(1, 'rgb(255, 0, 255)');
444
- sprite.fillStyle = grad;
445
- //sprite.fillStyle = document.getElementById('reverb').checked ? "#17a2b8" : "#28a745";
446
-
447
- for (let i = 0; i < spriteCanvas.width; ++i) {
448
- const f = (AudioCtx.sampleRate * i) / 1024;
449
- y = 128 + (AnalyseData[i] + 48.16) * 2.56 + 1;
450
- sprite.fillRect(i, spriteCanvas.height - y, 1, y);
451
- }
452
-
453
- return spriteCanvas.toDataURL();
454
- };
455
-
456
- // Draw Axis
457
- const DrawAxis = () => {
458
- const sprite = spriteCanvas.getContext('2d', {antialias: false});
459
- // y axis (dB)
460
- for (let d = -50; d < 50; d += 10) {
461
- const y = (SPRITE_HEIGHT / 2 - (d * SPRITE_HEIGHT) / 100) | 0;
462
- // Line
463
- sprite.fillStyle = '#6c757d';
464
- sprite.fillRect(20, y, SPRITE_WIDTH, 1);
465
- // Label
466
- sprite.fillStyle = '#fd7e14';
467
- sprite.fillText(d + 'dB', 5, y);
468
- }
469
- sprite.fillStyle = '#ffc107';
470
- sprite.fillRect(20, SPRITE_HEIGHT / 2, SPRITE_WIDTH, 1);
471
-
472
- // x axis (frequency)
473
- for (let f = 2000; f < AudioCtx.sampleRate / 2; f += 2000) {
474
- const x = ((f * 1024) / AudioCtx.sampleRate) | 0;
475
- // Line
476
- sprite.fillStyle = '#6c757d';
477
- sprite.fillRect(x, 0, 1, 245);
478
- // Label
479
- sprite.fillStyle = '#e83e8c';
480
- sprite.fillText(f / 1000 + 'kHz', x - 10, 255);
481
- }
482
-
483
- return spriteCanvas.toDataURL();
484
- };
485
-
486
- // スプライトのデバッグ
487
- const debug = src => {
488
- const canvas = document.getElementById('canvas');
489
- canvas.style.width = SPRITE_WIDTH + 'px';
490
- canvas.style.height = SPRITE_HEIGHT + 'px';
491
- canvas.width = SPRITE_WIDTH;
492
- canvas.height = SPRITE_HEIGHT;
493
-
494
- const img = document.getElementById('test');
495
- img.style.width = SPRITE_WIDTH + 'px';
496
- img.style.height = SPRITE_HEIGHT + 'px';
497
- img.src = src;
498
- //ctx.clearRect(0, 0, canvas.width, canvas.height);
499
-
500
- const image = new Image();
501
- image.addEventListener('load', () => {
502
- canvas.getContext('2d').drawImage(image, 0, 0); // Or at whatever offset you like
503
- });
504
- image.src = src;
505
- };
506
-
507
- /**
508
- * 3D Spectrum Analyzer Code
509
- */
510
-
511
- // 3D canvas size
512
- const CANVAS_WIDTH = 960;
513
- const CANVAS_HEIGHT = 540;
514
-
515
- // Create renderer
516
- const renderer = new THREE.WebGLRenderer({
517
- canvas: document.querySelector('#graph'),
518
- });
519
- renderer.setPixelRatio(window.devicePixelRatio);
520
- renderer.setSize(CANVAS_WIDTH, CANVAS_HEIGHT);
521
-
522
- // Create Scene
523
- const scene = new THREE.Scene();
524
-
525
- // Create camera
526
- const camera = new THREE.PerspectiveCamera(
527
- 30,
528
- CANVAS_WIDTH / CANVAS_HEIGHT,
529
- 1,
530
- 2000
531
- );
532
- // Move Initial camera position (x, y, z)
533
- camera.position.set(100, 50, 1000);
534
- //const camera = new THREE.OrthographicCamera(-CANVAS_WIDTH, CANVAS_WIDTH, CANVAS_HEIGHT, -CANVAS_HEIGHT, 1, 100000);
535
-
536
- // Append Fog
537
- // new THREE.Fog(color, start distance, end distance);
538
- scene.fog = new THREE.Fog(0x000000, 1000, 2000);
539
-
540
- //debug(DrawAxis())
541
-
542
- const AxisMesh = new THREE.Mesh(
543
- // Plane
544
- new THREE.PlaneGeometry(SPRITE_WIDTH, SPRITE_HEIGHT, 5, 5),
545
- // Texture
546
- new THREE.MeshBasicMaterial({
547
- transparent: true,
548
- needsUpdate: true,
549
- map: new THREE.TextureLoader().load(DrawAxis()),
550
- side: THREE.DoubleSide,
551
- })
552
- );
553
-
554
- // Move Mesh object
555
- AxisMesh.position.set(0, 0, 0);
556
-
557
- scene.add(AxisMesh);
558
-
559
- let depth = 0;
560
- let geometries = [];
561
- let materials = [];
562
- let textures = [];
563
- let meshs = [];
564
-
565
- const MAX_DEPTH = 1024;
566
-
567
- // Loop event
568
- const tick = () => {
569
- // Draw Texture image
570
- const sprite = DrawGraph();
571
-
572
- debug(sprite);
573
-
574
- textures[depth] = new THREE.TextureLoader().load(sprite);
575
-
576
- geometries[depth] = new THREE.PlaneGeometry(
577
- SPRITE_WIDTH,
578
- SPRITE_HEIGHT,
579
- 5,
580
- 5
581
- );
582
-
583
- materials[depth] = new THREE.MeshBasicMaterial({
584
- color: 0xccddee,
585
- transparent: true,
586
- needsUpdate: true,
587
- map: textures[depth],
588
- side: THREE.DoubleSide,
589
- });
590
-
591
- // Mesh object
592
- meshs[depth] = new THREE.Mesh(geometries[depth], materials[depth]);
593
-
594
- // Move Mesh object
595
- meshs[depth].position.set(0, 0, depth);
596
- AxisMesh.position.set(0, 0, depth);
597
-
598
- // Append Mesh object to 3D scene
599
- scene.add(meshs[depth]);
600
-
601
- // Render
602
- renderer.render(scene, camera);
603
-
604
- // Move Camera
605
- camera.position.z = depth + 650;
606
- //camera.zoom = 2;
607
- camera.updateProjectionMatrix();
608
-
609
- // Look to origin
610
- camera.lookAt(new THREE.Vector3(0, 0, depth));
611
-
612
- // Remove old Mesh
613
- if (depth > MAX_DEPTH) {
614
- scene.remove(meshs[depth - MAX_DEPTH]);
615
- //meshs[depth - MAX_DEPTH].dispose();
616
- geometries[depth - MAX_DEPTH].dispose();
617
- materials[depth - MAX_DEPTH].dispose();
618
- textures[depth - MAX_DEPTH].dispose();
619
-
620
- // Manual Gabarge Collection
621
- delete geometries[depth - MAX_DEPTH];
622
- delete materials[depth - MAX_DEPTH];
623
- delete textures[depth - MAX_DEPTH];
624
- }
625
-
626
- // incriment depth
627
- depth++;
628
-
629
- // Update Animation
630
- requestAnimationFrame(tick);
631
- };
632
-
633
- // Regist Event
634
- window.addEventListener('load', async () => {
635
- audio.src = await LoadSample('./demo.wav');
636
- // Play button
637
- document.getElementById('play').addEventListener('click', async () => {
638
- if (AudioCtx.state == 'suspended') AudioCtx.resume();
639
- setReverb();
640
- audio.play();
641
- });
642
-
643
- // Stop button
644
- document.getElementById('stop').addEventListener('click', () => {
645
- audio.stop();
646
- });
647
-
648
- // File form
649
- document.getElementById('file').addEventListener('dragover', e => {
650
- e.stopPropagation();
651
- e.preventDefault();
652
- e.dataTransfer.dropEffect = 'copy';
653
- return false;
654
- });
655
- document
656
- .getElementById('file')
657
- .addEventListener('drag', handleFileSelect, false);
658
- document
659
- .getElementById('file')
660
- .addEventListener('change', handleFileSelect, false);
661
-
662
- // Reverb switch button
663
- document.getElementById('reverb').addEventListener('click', setReverb);
664
- // Reverse checkbox
665
- document
666
- .getElementById('reverse')
667
- .addEventListener('click', () =>
668
- reverb.reverse(document.getElementById('reverse').checked)
669
- );
670
- // Reverb dualation time
671
- document
672
- .getElementById('time')
673
- .addEventListener('change', () =>
674
- reverb.time(document.getElementById('time').value)
675
- );
676
- // Decay time
677
- document
678
- .getElementById('decay')
679
- .addEventListener('change', () =>
680
- reverb.decay(document.getElementById('decay').value)
681
- );
682
- // Delay time
683
- document
684
- .getElementById('delay')
685
- .addEventListener('change', () =>
686
- reverb.delay(document.getElementById('delay').value)
687
- );
688
- // Filter select box
689
- document
690
- .getElementById('filter')
691
- .addEventListener('change', () =>
692
- reverb.filterType(document.getElementById('filter').value)
693
- );
694
- // Filter frequency
695
- document
696
- .getElementById('freq')
697
- .addEventListener('change', () =>
698
- reverb.filterFreq(document.getElementById('freq').value)
699
- );
700
- // Filter quality
701
- document
702
- .getElementById('q')
703
- .addEventListener('change', () =>
704
- reverb.filterQ(document.getElementById('q').value)
705
- );
706
- // Dry/Wet
707
- document
708
- .getElementById('mix')
709
- .addEventListener('change', () =>
710
- reverb.mix(document.getElementById('mix').value)
711
- );
712
-
713
- // Execute Animation Thread
714
- tick();
715
- });
716
- </script>
717
- </body>
718
- </html>