Files
bruitiste/src/domain/audio/effects/FMSourceEffect.ts

92 lines
2.5 KiB
TypeScript

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<void> {
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()
}
}