Replace RMS voice detection with TeamSpeak's own RNN VAD
Ports WebRTC's rnn_vad (as TS3 embeds it) to Java: LPC, pitch estimation, spectral features and the RNN itself, feeding a speech-probability detector that replaces the old SpeechDetector. Also switches the volume-gate threshold from raw dBFS to InputLevel's scale, matching TS3's own slider and range, with a migration for settings saved under the old key.
This commit is contained in:
@@ -8,21 +8,28 @@ import java.awt.Graphics2D;
|
||||
import java.awt.RenderingHints;
|
||||
|
||||
/**
|
||||
* Horizontal audio level meter (dBFS) with an optional VAD threshold marker.
|
||||
* The filled portion turns green once the level crosses the threshold, giving
|
||||
* immediate visual feedback while tuning voice activation.
|
||||
* Horizontal audio level meter with an optional VAD threshold marker. The filled portion
|
||||
* turns green once the level crosses the threshold, giving immediate visual feedback while
|
||||
* tuning voice activation.
|
||||
*
|
||||
* <p>Scaled to {@link com.ts3client.audio.InputLevel}, matching the TS3 client's slider.
|
||||
*/
|
||||
public final class LevelMeter extends JComponent {
|
||||
|
||||
private static final double MIN_DB = -70.0;
|
||||
private static final double MAX_DB = 0.0;
|
||||
private static final double MIN_DB = com.ts3client.audio.InputLevel.MIN_DB;
|
||||
private static final double MAX_DB = com.ts3client.audio.InputLevel.MAX_DB;
|
||||
|
||||
private volatile double levelDb = MIN_DB;
|
||||
private volatile double thresholdDb = -45.0;
|
||||
private volatile double thresholdDb = -40.0;
|
||||
private volatile boolean showThreshold = true;
|
||||
private volatile boolean transmitting;
|
||||
|
||||
public LevelMeter() {
|
||||
setPreferredSize(new Dimension(240, 18));
|
||||
// A bare JComponent reports no minimum of its own, so a layout tight on space
|
||||
// collapses the bar to nothing. Keep the height and let only the width give.
|
||||
setMinimumSize(new Dimension(60, 18));
|
||||
setMaximumSize(new Dimension(Integer.MAX_VALUE, 18));
|
||||
}
|
||||
|
||||
public void setLevel(double db) {
|
||||
@@ -40,6 +47,16 @@ public final class LevelMeter extends JComponent {
|
||||
repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the gate is currently open. This is the real transmit decision, which in the
|
||||
* Automatic and Hybrid modes depends on the speech detector and the hangover as well as
|
||||
* on the level, so the bar cannot infer it from the threshold alone.
|
||||
*/
|
||||
public void setTransmitting(boolean transmitting) {
|
||||
this.transmitting = transmitting;
|
||||
repaint();
|
||||
}
|
||||
|
||||
private int dbToX(double db, int w) {
|
||||
double clamped = Math.max(MIN_DB, Math.min(MAX_DB, db));
|
||||
return (int) ((clamped - MIN_DB) / (MAX_DB - MIN_DB) * w);
|
||||
@@ -56,8 +73,7 @@ public final class LevelMeter extends JComponent {
|
||||
g.fillRoundRect(0, 0, w - 1, h - 1, 6, 6);
|
||||
|
||||
int level = dbToX(levelDb, w - 2);
|
||||
boolean over = levelDb >= thresholdDb;
|
||||
g.setColor(over ? Theme.TALKING : new Color(0x5A9BD4));
|
||||
g.setColor(transmitting ? Theme.TALKING : new Color(0x5A9BD4));
|
||||
g.fillRoundRect(1, 1, Math.max(0, level), h - 3, 5, 5);
|
||||
|
||||
if (showThreshold) {
|
||||
|
||||
Reference in New Issue
Block a user