mirror of
https://github.com/R0m1k3/LiveFlow.git
synced 2026-10-20 05:28:21 +02:00
Gain automatique du micro avant la détection de parole
Les micros faibles (casques) passaient sous le seuil du VAD : la plupart des phrases n'étaient jamais découpées en segments. Un GainNode adaptatif (jusqu'à x40, ajusté toutes les 250 ms, repli en cas de saturation) amène le signal à un niveau exploitable avant le rééchantillonnage et le VAD. https://claude.ai/code/session_01YHMp3EKzr4s6o8w1ygxuUe
This commit is contained in:
1 file changed
+26
-2
+26
-2
@@ -14,6 +14,8 @@ const state = {
|
|||||||
lastLoudAt: 0,
|
lastLoudAt: 0,
|
||||||
silentWarned: false,
|
silentWarned: false,
|
||||||
sourceNode: null,
|
sourceNode: null,
|
||||||
|
gainNode: null,
|
||||||
|
lastGainAt: 0,
|
||||||
autoMicQueue: null,
|
autoMicQueue: null,
|
||||||
switching: false,
|
switching: false,
|
||||||
paused: false,
|
paused: false,
|
||||||
@@ -77,7 +79,8 @@ async function switchMic(deviceId) {
|
|||||||
if (state.mediaStream) state.mediaStream.getTracks().forEach((t) => t.stop());
|
if (state.mediaStream) state.mediaStream.getTracks().forEach((t) => t.stop());
|
||||||
state.mediaStream = stream;
|
state.mediaStream = stream;
|
||||||
state.sourceNode = state.audioContext.createMediaStreamSource(stream);
|
state.sourceNode = state.audioContext.createMediaStreamSource(stream);
|
||||||
state.sourceNode.connect(state.workletNode);
|
state.sourceNode.connect(state.gainNode);
|
||||||
|
state.gainNode.gain.value = 1; // le nouveau micro repart d'un gain neutre
|
||||||
state.lastLoudAt = Date.now();
|
state.lastLoudAt = Date.now();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -149,8 +152,12 @@ async function startRecording() {
|
|||||||
await state.audioContext.audioWorklet.addModule('worklet.js');
|
await state.audioContext.audioWorklet.addModule('worklet.js');
|
||||||
state.workletNode = new AudioWorkletNode(state.audioContext, 'pcm-downsampler');
|
state.workletNode = new AudioWorkletNode(state.audioContext, 'pcm-downsampler');
|
||||||
state.workletNode.port.onmessage = (e) => queuePcm(new Int16Array(e.data));
|
state.workletNode.port.onmessage = (e) => queuePcm(new Int16Array(e.data));
|
||||||
|
// gain automatique : compense les micros trop faibles (casques...)
|
||||||
|
state.gainNode = state.audioContext.createGain();
|
||||||
|
state.gainNode.gain.value = 1;
|
||||||
|
state.gainNode.connect(state.workletNode);
|
||||||
state.sourceNode = state.audioContext.createMediaStreamSource(state.mediaStream);
|
state.sourceNode = state.audioContext.createMediaStreamSource(state.mediaStream);
|
||||||
state.sourceNode.connect(state.workletNode);
|
state.sourceNode.connect(state.gainNode);
|
||||||
|
|
||||||
// les libellés des micros ne sont disponibles qu'une fois la permission accordée
|
// les libellés des micros ne sont disponibles qu'une fois la permission accordée
|
||||||
listMics();
|
listMics();
|
||||||
@@ -191,6 +198,23 @@ function updateVu(samples) {
|
|||||||
}
|
}
|
||||||
$('vu-bar').style.width = Math.min(100, (peak / 32768) * 140) + '%';
|
$('vu-bar').style.width = Math.min(100, (peak / 32768) * 140) + '%';
|
||||||
if (peak > 1500) state.lastLoudAt = Date.now();
|
if (peak > 1500) state.lastLoudAt = Date.now();
|
||||||
|
autoGain(peak);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gain automatique : monte progressivement le volume des micros faibles
|
||||||
|
// jusqu'à un niveau exploitable par la détection de parole, et redescend
|
||||||
|
// en cas de saturation. Ajusté au plus toutes les 250 ms.
|
||||||
|
function autoGain(peak) {
|
||||||
|
if (!state.gainNode || state.paused) return;
|
||||||
|
const now = Date.now();
|
||||||
|
if (now - state.lastGainAt < 250) return;
|
||||||
|
state.lastGainAt = now;
|
||||||
|
const g = state.gainNode.gain.value;
|
||||||
|
if (peak > 26000) {
|
||||||
|
state.gainNode.gain.value = Math.max(1, g * 0.7); // proche saturation
|
||||||
|
} else if (peak > 200 && peak < 8000) {
|
||||||
|
state.gainNode.gain.value = Math.min(40, g * 1.25); // parole trop faible
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function flushPcm() {
|
function flushPcm() {
|
||||||
|
|||||||
Reference in new issue
Block a user