Enhance FM synthesis + cleaning code architecture

This commit is contained in:
2025-10-06 13:48:14 +02:00
parent 324cf9d2ed
commit ff5add97e8
38 changed files with 893 additions and 548 deletions

View File

@ -30,6 +30,11 @@ class FMProcessor extends AudioWorkletProcessor {
this.lfoRate4 = 0.43
this.lfoDepth = 0.3
this.pitchLFOPhase = 0
this.pitchLFOWaveform = 0
this.pitchLFODepth = 0.1
this.pitchLFOBaseRate = 2.0
this.port.onmessage = (event) => {
const { type, value } = event.data
switch (type) {
@ -42,6 +47,11 @@ class FMProcessor extends AudioWorkletProcessor {
this.lfoRate3 = value.lfoRates[2]
this.lfoRate4 = value.lfoRates[3]
}
if (value.pitchLFO) {
this.pitchLFOWaveform = value.pitchLFO.waveform
this.pitchLFODepth = value.pitchLFO.depth
this.pitchLFOBaseRate = value.pitchLFO.baseRate
}
break
case 'operatorLevels':
this.opLevel1 = value.a
@ -73,14 +83,41 @@ class FMProcessor extends AudioWorkletProcessor {
}
}
generatePitchLFO(phase, waveform) {
const TWO_PI = Math.PI * 2
const normalizedPhase = phase / TWO_PI
switch (waveform) {
case 0: // sine
return Math.sin(phase)
case 1: // triangle
return 2 * Math.abs(2 * (normalizedPhase % 1 - 0.5)) - 1
case 2: // square
return normalizedPhase % 1 < 0.5 ? 1 : -1
case 3: // sawtooth
return 2 * (normalizedPhase % 1) - 1
default:
return 0
}
}
synthesize(algorithm) {
const TWO_PI = Math.PI * 2
const sampleRate = 44100
const freq1 = (this.baseFreq * this.frequencyRatios[0] * TWO_PI) / sampleRate
const freq2 = (this.baseFreq * this.frequencyRatios[1] * TWO_PI) / sampleRate
const freq3 = (this.baseFreq * this.frequencyRatios[2] * TWO_PI) / sampleRate
const freq4 = (this.baseFreq * this.frequencyRatios[3] * TWO_PI) / sampleRate
const avgDiff = (Math.abs(this.opLevel1 - this.opLevel3) + Math.abs(this.opLevel2 - this.opLevel4)) / (2 * 255)
const pitchLFORate = this.pitchLFOBaseRate * (0.3 + avgDiff * 1.4)
const pitchLFOValue = this.generatePitchLFO(this.pitchLFOPhase, this.pitchLFOWaveform)
const pitchMod = 1 + pitchLFOValue * this.pitchLFODepth
const modulatedBaseFreq = this.baseFreq * pitchMod
this.pitchLFOPhase += (pitchLFORate * TWO_PI) / sampleRate
if (this.pitchLFOPhase > TWO_PI) this.pitchLFOPhase -= TWO_PI
const freq1 = (modulatedBaseFreq * this.frequencyRatios[0] * TWO_PI) / sampleRate
const freq2 = (modulatedBaseFreq * this.frequencyRatios[1] * TWO_PI) / sampleRate
const freq3 = (modulatedBaseFreq * this.frequencyRatios[2] * TWO_PI) / sampleRate
const freq4 = (modulatedBaseFreq * this.frequencyRatios[3] * TWO_PI) / sampleRate
const lfo1 = Math.sin(this.lfoPhase1)
const lfo2 = Math.sin(this.lfoPhase2)