import type { Effect } from './Effect.interface' export class RingModEffect implements Effect { readonly id = 'ring' private inputNode: GainNode private outputNode: GainNode private processorNode: AudioWorkletNode | null = null constructor(audioContext: AudioContext) { this.inputNode = audioContext.createGain() this.outputNode = audioContext.createGain() } async initialize(audioContext: AudioContext): Promise { this.processorNode = new AudioWorkletNode(audioContext, 'ring-mod-processor', { numberOfInputs: 1, numberOfOutputs: 1, outputChannelCount: [2] }) this.processorNode.port.postMessage({ type: 'bypass', value: true }) this.inputNode.connect(this.processorNode) this.processorNode.connect(this.outputNode) } getInputNode(): AudioNode { return this.inputNode } getOutputNode(): AudioNode { return this.outputNode } setBypass(bypass: boolean): void { if (this.processorNode) { this.processorNode.port.postMessage({ type: 'bypass', value: bypass }) } } updateParams(values: Record): void { if (!this.processorNode) return if (values.ringFreq !== undefined) { this.processorNode.port.postMessage({ type: 'frequency', value: values.ringFreq }) } if (values.ringShape !== undefined) { this.processorNode.port.postMessage({ type: 'shape', value: values.ringShape }) } if (values.ringSpread !== undefined && typeof values.ringSpread === 'number') { this.processorNode.port.postMessage({ type: 'spread', value: values.ringSpread / 100 }) } } dispose(): void { if (this.processorNode) { this.processorNode.disconnect() } this.inputNode.disconnect() this.outputNode.disconnect() } }