From ebe2b26ae9b5f48c62a0ae80df6d33eec2276f92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jose=20Luis=20Monta=C3=B1es=20Ojados?= Date: Sat, 17 Jan 2026 16:41:17 +0100 Subject: [PATCH] Improve microphone level sensitivity using logarithmic (dB) scaling --- pkg/audio/level.go | 47 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/pkg/audio/level.go b/pkg/audio/level.go index b2d52dd..d0c4bb6 100644 --- a/pkg/audio/level.go +++ b/pkg/audio/level.go @@ -4,7 +4,7 @@ import ( "math" ) -// CalculateRMSLevel calculates the RMS level of PCM samples and returns 0-100 +// CalculateRMSLevel calculates the RMS level of PCM samples and returns 0-100 (Logarithmic/dB) func CalculateRMSLevel(samples []int16) int { if len(samples) == 0 { return 0 @@ -16,15 +16,33 @@ func CalculateRMSLevel(samples []int16) int { } rms := math.Sqrt(sum / float64(len(samples))) - // Normalize to 0-100 (max int16 is 32767) - level := int(rms / 32767.0 * 100.0) + + // Normalize to 0.0 - 1.0 + val := rms / 32768.0 + if val < 0.000001 { // Avoid log(0) + return 0 + } + + // Convert to dB + db := 20 * math.Log10(val) + + // Map -50dB (silence floor) to 0dB (max) to 0-100 + const minDB = -50.0 + + if db < minDB { + return 0 + } + + // Scale + level := int((db - minDB) * (100.0 / (0 - minDB))) + if level > 100 { level = 100 } return level } -// CalculatePeakLevel returns the peak level of PCM samples as 0-100 +// CalculatePeakLevel returns the peak level of PCM samples as 0-100 (Logarithmic/dB) func CalculatePeakLevel(samples []int16) int { if len(samples) == 0 { return 0 @@ -40,7 +58,26 @@ func CalculatePeakLevel(samples []int16) int { } } - return int(float64(peak) / 32767.0 * 100.0) + // Normalize + val := float64(peak) / 32768.0 + if val < 0.000001 { + return 0 + } + + db := 20 * math.Log10(val) + const minDB = -50.0 + + if db < minDB { + // Linear falloff for very low signals to avoid clutter + return 0 + } + + level := int((db - minDB) * (100.0 / (0 - minDB))) + if level > 100 { + level = 100 + } + + return level } // LevelToBar converts a 0-100 level to a visual bar string