import type { Effect } from './Effect.interface' export class ReverbEffect implements Effect { readonly id = 'reverb' private audioContext: AudioContext private inputNode: GainNode private outputNode: GainNode private convolverNode: ConvolverNode private wetNode: GainNode private dryNode: GainNode constructor(audioContext: AudioContext) { this.audioContext = audioContext this.inputNode = audioContext.createGain() this.outputNode = audioContext.createGain() this.convolverNode = audioContext.createConvolver() this.wetNode = audioContext.createGain() this.dryNode = audioContext.createGain() this.wetNode.gain.value = 0 this.dryNode.gain.value = 1 this.inputNode.connect(this.dryNode) this.inputNode.connect(this.convolverNode) this.convolverNode.connect(this.wetNode) this.dryNode.connect(this.outputNode) this.wetNode.connect(this.outputNode) this.generateImpulseResponse() } private generateImpulseResponse(): void { const length = this.audioContext.sampleRate * 2 const impulse = this.audioContext.createBuffer(2, length, this.audioContext.sampleRate) const left = impulse.getChannelData(0) const right = impulse.getChannelData(1) for (let i = 0; i < length; i++) { left[i] = (Math.random() * 2 - 1) * Math.pow(1 - i / length, 2) right[i] = (Math.random() * 2 - 1) * Math.pow(1 - i / length, 2) } this.convolverNode.buffer = impulse } getInputNode(): AudioNode { return this.inputNode } getOutputNode(): AudioNode { return this.outputNode } updateParams(values: Record): void { if (values.reverbWetDry !== undefined) { const wet = values.reverbWetDry / 100 this.wetNode.gain.value = wet this.dryNode.gain.value = 1 - wet } } dispose(): void { this.inputNode.disconnect() this.outputNode.disconnect() this.convolverNode.disconnect() this.wetNode.disconnect() this.dryNode.disconnect() } }