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)