1 | import { StereoEffect } from "./StereoEffect.js";
|
2 | import { optionsFromArguments } from "../core/util/Defaults.js";
|
3 | import { readOnly } from "../core/util/Interface.js";
|
4 | import { Signal } from "../signal/Signal.js";
|
5 | import { LowpassCombFilter } from "../component/filter/LowpassCombFilter.js";
|
6 |
|
7 |
|
8 |
|
9 | const combFilterTunings = [
|
10 | 1557 / 44100,
|
11 | 1617 / 44100,
|
12 | 1491 / 44100,
|
13 | 1422 / 44100,
|
14 | 1277 / 44100,
|
15 | 1356 / 44100,
|
16 | 1188 / 44100,
|
17 | 1116 / 44100,
|
18 | ];
|
19 |
|
20 |
|
21 |
|
22 | const allpassFilterFrequencies = [225, 556, 441, 341];
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 | export class Freeverb extends StereoEffect {
|
36 | constructor() {
|
37 | const options = optionsFromArguments(Freeverb.getDefaults(), arguments, ["roomSize", "dampening"]);
|
38 | super(options);
|
39 | this.name = "Freeverb";
|
40 | |
41 |
|
42 |
|
43 | this._combFilters = [];
|
44 | |
45 |
|
46 |
|
47 | this._allpassFiltersL = [];
|
48 | |
49 |
|
50 |
|
51 | this._allpassFiltersR = [];
|
52 | this.roomSize = new Signal({
|
53 | context: this.context,
|
54 | value: options.roomSize,
|
55 | units: "normalRange",
|
56 | });
|
57 |
|
58 | this._allpassFiltersL = allpassFilterFrequencies.map((freq) => {
|
59 | const allpassL = this.context.createBiquadFilter();
|
60 | allpassL.type = "allpass";
|
61 | allpassL.frequency.value = freq;
|
62 | return allpassL;
|
63 | });
|
64 |
|
65 | this._allpassFiltersR = allpassFilterFrequencies.map((freq) => {
|
66 | const allpassR = this.context.createBiquadFilter();
|
67 | allpassR.type = "allpass";
|
68 | allpassR.frequency.value = freq;
|
69 | return allpassR;
|
70 | });
|
71 |
|
72 | this._combFilters = combFilterTunings.map((delayTime, index) => {
|
73 | const lfpf = new LowpassCombFilter({
|
74 | context: this.context,
|
75 | dampening: options.dampening,
|
76 | delayTime,
|
77 | });
|
78 | if (index < combFilterTunings.length / 2) {
|
79 | this.connectEffectLeft(lfpf, ...this._allpassFiltersL);
|
80 | }
|
81 | else {
|
82 | this.connectEffectRight(lfpf, ...this._allpassFiltersR);
|
83 | }
|
84 | this.roomSize.connect(lfpf.resonance);
|
85 | return lfpf;
|
86 | });
|
87 | readOnly(this, ["roomSize"]);
|
88 | }
|
89 | static getDefaults() {
|
90 | return Object.assign(StereoEffect.getDefaults(), {
|
91 | roomSize: 0.7,
|
92 | dampening: 3000,
|
93 | });
|
94 | }
|
95 | |
96 |
|
97 |
|
98 | get dampening() {
|
99 | return this._combFilters[0].dampening;
|
100 | }
|
101 | set dampening(d) {
|
102 | this._combFilters.forEach((c) => (c.dampening = d));
|
103 | }
|
104 | dispose() {
|
105 | super.dispose();
|
106 | this._allpassFiltersL.forEach((al) => al.disconnect());
|
107 | this._allpassFiltersR.forEach((ar) => ar.disconnect());
|
108 | this._combFilters.forEach((cf) => cf.dispose());
|
109 | this.roomSize.dispose();
|
110 | return this;
|
111 | }
|
112 | }
|
113 |
|
\ | No newline at end of file |