OK ready
This commit is contained in:
167
public/worklets/chorus-processor.js
Normal file
167
public/worklets/chorus-processor.js
Normal file
@ -0,0 +1,167 @@
|
||||
class ChorusProcessor extends AudioWorkletProcessor {
|
||||
constructor() {
|
||||
super()
|
||||
|
||||
this.mode = 'chorus'
|
||||
this.rate = 0.5
|
||||
this.depth = 0.5
|
||||
this.feedback = 0
|
||||
this.spread = 0.3
|
||||
this.bypassed = false
|
||||
|
||||
this.delayBufferSize = Math.floor(sampleRate * 0.05)
|
||||
this.delayBufferL = new Float32Array(this.delayBufferSize)
|
||||
this.delayBufferR = new Float32Array(this.delayBufferSize)
|
||||
this.writeIndex = 0
|
||||
|
||||
this.lfoPhase = 0
|
||||
this.lfoPhaseRight = 0
|
||||
|
||||
this.port.onmessage = (event) => {
|
||||
const { type, value } = event.data
|
||||
switch (type) {
|
||||
case 'mode':
|
||||
this.mode = value
|
||||
break
|
||||
case 'frequency':
|
||||
this.rate = value
|
||||
break
|
||||
case 'depth':
|
||||
this.depth = value
|
||||
break
|
||||
case 'feedback':
|
||||
this.feedback = value
|
||||
break
|
||||
case 'spread':
|
||||
this.spread = value
|
||||
break
|
||||
case 'bypass':
|
||||
this.bypassed = value
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
processChorus(sampleL, sampleR) {
|
||||
const baseDelay = 15
|
||||
const maxDepth = 8
|
||||
|
||||
this.lfoPhase += this.rate / sampleRate
|
||||
this.lfoPhaseRight += this.rate / sampleRate
|
||||
|
||||
if (this.lfoPhase >= 1) this.lfoPhase -= 1
|
||||
if (this.lfoPhaseRight >= 1) this.lfoPhaseRight -= 1
|
||||
|
||||
const spreadPhase = this.spread * 0.5
|
||||
const lfoL = Math.sin(this.lfoPhase * Math.PI * 2)
|
||||
const lfoR = Math.sin((this.lfoPhaseRight + spreadPhase) * Math.PI * 2)
|
||||
|
||||
const delayTimeL = baseDelay + lfoL * maxDepth * this.depth
|
||||
const delayTimeR = baseDelay + lfoR * maxDepth * this.depth
|
||||
|
||||
const delaySamplesL = (delayTimeL / 1000) * sampleRate
|
||||
const delaySamplesR = (delayTimeR / 1000) * sampleRate
|
||||
|
||||
const readIndexL = (this.writeIndex - delaySamplesL + this.delayBufferSize) % this.delayBufferSize
|
||||
const readIndexR = (this.writeIndex - delaySamplesR + this.delayBufferSize) % this.delayBufferSize
|
||||
|
||||
const readIndexL0 = Math.floor(readIndexL) % this.delayBufferSize
|
||||
const readIndexL1 = (readIndexL0 + 1) % this.delayBufferSize
|
||||
const fracL = readIndexL - Math.floor(readIndexL)
|
||||
|
||||
const readIndexR0 = Math.floor(readIndexR) % this.delayBufferSize
|
||||
const readIndexR1 = (readIndexR0 + 1) % this.delayBufferSize
|
||||
const fracR = readIndexR - Math.floor(readIndexR)
|
||||
|
||||
const delayedL = this.delayBufferL[readIndexL0] * (1 - fracL) + this.delayBufferL[readIndexL1] * fracL
|
||||
const delayedR = this.delayBufferR[readIndexR0] * (1 - fracR) + this.delayBufferR[readIndexR1] * fracR
|
||||
|
||||
this.delayBufferL[this.writeIndex] = sampleL + delayedL * this.feedback
|
||||
this.delayBufferR[this.writeIndex] = sampleR + delayedR * this.feedback
|
||||
|
||||
return [delayedL, delayedR]
|
||||
}
|
||||
|
||||
processFlanger(sampleL, sampleR) {
|
||||
const baseDelay = 1
|
||||
const maxDepth = 5
|
||||
|
||||
this.lfoPhase += this.rate / sampleRate
|
||||
this.lfoPhaseRight += this.rate / sampleRate
|
||||
|
||||
if (this.lfoPhase >= 1) this.lfoPhase -= 1
|
||||
if (this.lfoPhaseRight >= 1) this.lfoPhaseRight -= 1
|
||||
|
||||
const spreadPhase = this.spread * 0.5
|
||||
const lfoL = Math.sin(this.lfoPhase * Math.PI * 2)
|
||||
const lfoR = Math.sin((this.lfoPhaseRight + spreadPhase) * Math.PI * 2)
|
||||
|
||||
const delayTimeL = baseDelay + lfoL * maxDepth * this.depth
|
||||
const delayTimeR = baseDelay + lfoR * maxDepth * this.depth
|
||||
|
||||
const delaySamplesL = (delayTimeL / 1000) * sampleRate
|
||||
const delaySamplesR = (delayTimeR / 1000) * sampleRate
|
||||
|
||||
const readIndexL = (this.writeIndex - delaySamplesL + this.delayBufferSize) % this.delayBufferSize
|
||||
const readIndexR = (this.writeIndex - delaySamplesR + this.delayBufferSize) % this.delayBufferSize
|
||||
|
||||
const readIndexL0 = Math.floor(readIndexL) % this.delayBufferSize
|
||||
const readIndexL1 = (readIndexL0 + 1) % this.delayBufferSize
|
||||
const fracL = readIndexL - Math.floor(readIndexL)
|
||||
|
||||
const readIndexR0 = Math.floor(readIndexR) % this.delayBufferSize
|
||||
const readIndexR1 = (readIndexR0 + 1) % this.delayBufferSize
|
||||
const fracR = readIndexR - Math.floor(readIndexR)
|
||||
|
||||
const delayedL = this.delayBufferL[readIndexL0] * (1 - fracL) + this.delayBufferL[readIndexL1] * fracL
|
||||
const delayedR = this.delayBufferR[readIndexR0] * (1 - fracR) + this.delayBufferR[readIndexR1] * fracR
|
||||
|
||||
this.delayBufferL[this.writeIndex] = sampleL + delayedL * this.feedback * 0.9
|
||||
this.delayBufferR[this.writeIndex] = sampleR + delayedR * this.feedback * 0.9
|
||||
|
||||
return [delayedL, delayedR]
|
||||
}
|
||||
|
||||
process(inputs, outputs) {
|
||||
const input = inputs[0]
|
||||
const output = outputs[0]
|
||||
|
||||
if (!input || input.length === 0 || !output || output.length === 0) {
|
||||
return true
|
||||
}
|
||||
|
||||
const inputL = input[0]
|
||||
const inputR = input[1] || input[0]
|
||||
const outputL = output[0]
|
||||
const outputR = output[1] || output[0]
|
||||
|
||||
if (!inputL || !outputL) {
|
||||
return true
|
||||
}
|
||||
|
||||
for (let i = 0; i < inputL.length; i++) {
|
||||
if (this.bypassed) {
|
||||
outputL[i] = inputL[i]
|
||||
if (outputR) outputR[i] = inputR[i]
|
||||
continue
|
||||
}
|
||||
|
||||
let processedL, processedR
|
||||
|
||||
if (this.mode === 'flanger') {
|
||||
[processedL, processedR] = this.processFlanger(inputL[i], inputR[i])
|
||||
} else {
|
||||
[processedL, processedR] = this.processChorus(inputL[i], inputR[i])
|
||||
}
|
||||
|
||||
outputL[i] = processedL
|
||||
if (outputR) outputR[i] = processedR
|
||||
|
||||
this.writeIndex = (this.writeIndex + 1) % this.delayBufferSize
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
registerProcessor('chorus-processor', ChorusProcessor)
|
||||
Reference in New Issue
Block a user