Reputation: 6860
I know you can boost or reduce volume with gain. I was wondering if there was a way (perhaps via a node) to cap the maximum volume of the output - not reducing any audio below that max value. It is acceptable if there is distortion for audio that gets capped like this.
Upvotes: 2
Views: 704
Reputation: 6048
An alternative that might be simpler is to use a WaveShaperNode. I think a curve
equal to [-1, 0, 1] will do what you want, clamping values to +/-1. If you don't oversample, there won't be any additional delay.
Note that I'm pretty sure all browsers implement this kind of clamping before sending audio to the speakers.
Upvotes: 2
Reputation: 9066
This is not possible with any of the built-in AudioNodes. But it can be achieved with a custom AudioWorklet. I recently published a package which does exactly that. It's called limiter-audio-worklet.
It exports two functions:
import { addLimiterAudioWorkletModule, createLimiterAudioWorkletNode } from 'limiter-audio-worklet';
The first function can be used to add the AudioWorklet
to a particular AudioContext
.
await addLimiterAudioWorkletModule((url) => {
audioContext.audioWorklet.addModule(url);
});
Once that is done the actual AudioWorkletNode
can be created like this:
const limiterAudioWorkletNode = createLimiterAudioWorkletNode(
AudioWorkletNode,
audioContext,
{ attack: 0 }
);
If you set the attack
two zero you get the desired effect. Everything above +1/-1 gets clamped. If you increase the attack
it will transition smoother using a look ahead. This will introduce a small delay (of the same size) but sounds much nicer.
Of course it's also necessary to connect the previously created limiterAudioWorkletNode
close to the end of your audio graph.
yourLastAudioNode
.connect(limiterAudioWorkletNode)
.connect(audioContext.destination);
Upvotes: 1