Initial commit: TS3J TeamSpeak 3 Java client
Swing desktop client (core/desktop/swing Maven modules) built on the ts3j protocol library, included as a submodule. Native Opus voice with voice-activation detection, push-to-talk, and audio pre-processing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
package com.ts3client.ui;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
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.
|
||||
*/
|
||||
public final class LevelMeter extends JComponent {
|
||||
|
||||
private static final double MIN_DB = -70.0;
|
||||
private static final double MAX_DB = 0.0;
|
||||
|
||||
private volatile double levelDb = MIN_DB;
|
||||
private volatile double thresholdDb = -45.0;
|
||||
private volatile boolean showThreshold = true;
|
||||
|
||||
public LevelMeter() {
|
||||
setPreferredSize(new Dimension(240, 18));
|
||||
}
|
||||
|
||||
public void setLevel(double db) {
|
||||
this.levelDb = db;
|
||||
repaint();
|
||||
}
|
||||
|
||||
public void setThreshold(double db) {
|
||||
this.thresholdDb = db;
|
||||
repaint();
|
||||
}
|
||||
|
||||
public void setShowThreshold(boolean show) {
|
||||
this.showThreshold = show;
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g0) {
|
||||
Graphics2D g = (Graphics2D) g0;
|
||||
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
int w = getWidth();
|
||||
int h = getHeight();
|
||||
|
||||
g.setColor(new Color(0x2B2B2B));
|
||||
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.fillRoundRect(1, 1, Math.max(0, level), h - 3, 5, 5);
|
||||
|
||||
if (showThreshold) {
|
||||
int tx = dbToX(thresholdDb, w - 2);
|
||||
g.setColor(new Color(0xF0C419));
|
||||
g.fillRect(tx, 1, 2, h - 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user