fix(voice): widen the volume boost leg and add a master soft clip limiter (#1782)

This commit is contained in:
Hampus authored and GitHub committed 2026-08-20 17:42:02 +02:00
1 parent c020eded31
commit 25af7516a4
8 files changed
+514 -4

No files matched your search

@@ -1,6 +1,7 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
import {Logger} from '@app/features/platform/utils/AppLogger';
import {createVoiceSoftClipNode} from '@app/features/voice/engine/VoiceSharedAudioContext';
import {buildDeepFilterAudioChain, type DeepFilterAudioChain} from '@app/features/voice/utils/DeepFilterNoiseProcessor';
const logger = new Logger('MicTestAudioGraph');
@@ -11,6 +12,8 @@ export interface MicTestAudioGraph {
inputGain: GainNode;
delay: DelayNode;
outputGain: GainNode;
softClipInput: GainNode;
softClipOutput: AudioNode;
playbackTarget: AudioNode;
dispose: () => Promise<void>;
}
@@ -80,10 +83,14 @@ export async function createMicTestAudioGraph({
analyser.smoothingTimeConstant = 0.2;
delay.delayTime.value = playbackDelaySeconds;
outputGainNode.gain.value = outputGain;
const softClip = createVoiceSoftClipNode(audioContext);
const softClipInput = softClip?.input ?? outputGainNode;
const softClipOutput: AudioNode = softClip?.output ?? outputGainNode;
inputGainNode.connect(analyser);
analyser.connect(delay);
delay.connect(outputGainNode);
outputGainNode.connect(playbackTarget);
if (softClip) outputGainNode.connect(softClip.input);
softClipOutput.connect(playbackTarget);
const dispose = async () => {
source.disconnect();
@@ -91,6 +98,8 @@ export async function createMicTestAudioGraph({
inputGainNode.disconnect();
delay.disconnect();
outputGainNode.disconnect();
softClipInput.disconnect();
softClipOutput.disconnect();
passthroughDestination?.disconnect();
passthroughDestination?.stream.getTracks().forEach((track) => track.stop());
if (deepFilterChain) {
@@ -106,6 +115,8 @@ export async function createMicTestAudioGraph({
inputGain: inputGainNode,
delay,
outputGain: outputGainNode,
softClipInput,
softClipOutput,
playbackTarget,
dispose,
};
@@ -244,7 +244,7 @@ export const useMicTest = (settings: MicTestSettings) => {
playbackDestination.disconnect();
playbackDestination.stream.getTracks().forEach((track) => track.stop());
playbackDestinationRef.current = null;
graphRef.current.outputGain.disconnect();
graphRef.current.softClipOutput.disconnect();
playbackTarget = audioContext.destination;
const sinkableAudioContext = audioContext as SinkableAudioContext;
if (settings.outputDeviceId !== 'default' && sinkableAudioContext.setSinkId) {
@@ -254,7 +254,7 @@ export const useMicTest = (settings: MicTestSettings) => {
logger.warn('Failed to set mic test AudioContext output device', sinkError);
}
}
graphRef.current.outputGain.connect(playbackTarget);
graphRef.current.softClipOutput.connect(playbackTarget);
graphRef.current.playbackTarget = playbackTarget;
}
setIsTesting(true);