61 lines
1.4 KiB
JavaScript
61 lines
1.4 KiB
JavaScript
class OutputLimiter extends AudioWorkletProcessor {
|
|
static get parameterDescriptors() {
|
|
return [
|
|
{
|
|
name: 'threshold',
|
|
defaultValue: 0.8,
|
|
minValue: 0.1,
|
|
maxValue: 1.0,
|
|
automationRate: 'k-rate'
|
|
},
|
|
{
|
|
name: 'makeup',
|
|
defaultValue: 0.5,
|
|
minValue: 0.1,
|
|
maxValue: 2.0,
|
|
automationRate: 'k-rate'
|
|
}
|
|
]
|
|
}
|
|
|
|
constructor() {
|
|
super()
|
|
}
|
|
|
|
softClip(x, threshold) {
|
|
if (Math.abs(x) < threshold) {
|
|
return x
|
|
}
|
|
const sign = x < 0 ? -1 : 1
|
|
const scaled = (Math.abs(x) - threshold) / (1 - threshold)
|
|
return sign * (threshold + (1 - threshold) * Math.tanh(scaled))
|
|
}
|
|
|
|
process(inputs, outputs, parameters) {
|
|
const input = inputs[0]
|
|
const output = outputs[0]
|
|
|
|
if (input.length === 0 || output.length === 0) {
|
|
return true
|
|
}
|
|
|
|
const threshold = parameters.threshold[0]
|
|
const makeup = parameters.makeup[0]
|
|
|
|
for (let channel = 0; channel < input.length; channel++) {
|
|
const inputChannel = input[channel]
|
|
const outputChannel = output[channel]
|
|
|
|
for (let i = 0; i < inputChannel.length; i++) {
|
|
let sample = this.softClip(inputChannel[i], threshold)
|
|
sample = sample * makeup
|
|
outputChannel[i] = sample
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
}
|
|
|
|
registerProcessor('output-limiter', OutputLimiter)
|