import type { Effect } from './Effect.interface' import type { FMAlgorithm } from '../../../config/fmAlgorithms' export class FMSourceEffect implements Effect { readonly id = 'fm-source' 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, 'fm-processor') this.processorNode.connect(this.outputNode) } getInputNode(): AudioNode { return this.inputNode } getOutputNode(): AudioNode { return this.outputNode } setBypass(): void { // Source node doesn't support bypass } updateParams(): void { // Parameters handled via specific methods } setAlgorithm(algorithm: FMAlgorithm, lfoRates?: number[], pitchLFO?: { waveform: number; depth: number; baseRate: number }): void { if (!this.processorNode) return this.processorNode.port.postMessage({ type: 'algorithm', value: { id: algorithm.id, ratios: algorithm.frequencyRatios, lfoRates: lfoRates || [0.37, 0.53, 0.71, 0.43], pitchLFO: pitchLFO || { waveform: 0, depth: 0.1, baseRate: 2.0 } } }) } setOperatorLevels(a: number, b: number, c: number, d: number): void { if (!this.processorNode) return this.processorNode.port.postMessage({ type: 'operatorLevels', value: { a, b, c, d } }) } setBaseFrequency(freq: number): void { if (!this.processorNode) return this.processorNode.port.postMessage({ type: 'baseFreq', value: freq }) } setFeedback(amount: number): void { if (!this.processorNode) return this.processorNode.port.postMessage({ type: 'feedback', value: amount }) } setLoopLength(sampleRate: number, duration: number): void { if (!this.processorNode) return const loopLength = sampleRate * duration this.processorNode.port.postMessage({ type: 'loopLength', value: loopLength }) } setPlaybackRate(rate: number): void { if (!this.processorNode) return this.processorNode.port.postMessage({ type: 'playbackRate', value: rate }) } reset(): void { if (!this.processorNode) return this.processorNode.port.postMessage({ type: 'reset' }) } dispose(): void { if (this.processorNode) { this.processorNode.disconnect() } this.inputNode.disconnect() this.outputNode.disconnect() } }