Noise suppression tweaks.
This commit is contained in:
103
noise/suppression_test.go
Normal file
103
noise/suppression_test.go
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
package noise
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSuppressorDisabledBypassesSamples(t *testing.T) {
|
||||||
|
suppressor := NewSuppressor()
|
||||||
|
samples := []int16{100, -200, 300, -400, 500}
|
||||||
|
original := append([]int16(nil), samples...)
|
||||||
|
|
||||||
|
suppressor.ProcessSamples(samples)
|
||||||
|
|
||||||
|
for i := range samples {
|
||||||
|
if samples[i] != original[i] {
|
||||||
|
t.Fatalf("expected sample %d to remain unchanged, got %d want %d", i, samples[i], original[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSuppressorAttenuatesLowLevelNoise(t *testing.T) {
|
||||||
|
suppressor := NewSuppressor()
|
||||||
|
suppressor.SetEnabled(true)
|
||||||
|
suppressor.SetThreshold(0.08)
|
||||||
|
|
||||||
|
input := makeSineFrame(600, 700)
|
||||||
|
originalRMS := frameRMS(input)
|
||||||
|
processed := append([]int16(nil), input...)
|
||||||
|
suppressor.ProcessSamples(processed)
|
||||||
|
processedRMS := frameRMS(processed)
|
||||||
|
|
||||||
|
if processedRMS >= originalRMS*0.8 {
|
||||||
|
t.Fatalf("expected low-level noise attenuation, got RMS %.2f from %.2f", processedRMS, originalRMS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSuppressorPreservesSpeechLikeSignal(t *testing.T) {
|
||||||
|
suppressor := NewSuppressor()
|
||||||
|
suppressor.SetEnabled(true)
|
||||||
|
suppressor.SetThreshold(0.08)
|
||||||
|
|
||||||
|
voice := makeSineFrame(1000, 9000)
|
||||||
|
originalRMS := frameRMS(voice)
|
||||||
|
processed := append([]int16(nil), voice...)
|
||||||
|
suppressor.ProcessSamples(processed)
|
||||||
|
processedRMS := frameRMS(processed)
|
||||||
|
|
||||||
|
if processedRMS <= originalRMS*0.6 {
|
||||||
|
t.Fatalf("expected speech-like signal to be mostly preserved, got RMS %.2f from %.2f", processedRMS, originalRMS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHigherThresholdAppliesStrongerSuppression(t *testing.T) {
|
||||||
|
lowSuppressor := NewSuppressor()
|
||||||
|
lowSuppressor.SetEnabled(true)
|
||||||
|
lowSuppressor.SetThreshold(0.02)
|
||||||
|
|
||||||
|
highSuppressor := NewSuppressor()
|
||||||
|
highSuppressor.SetEnabled(true)
|
||||||
|
highSuppressor.SetThreshold(0.20)
|
||||||
|
|
||||||
|
noiseFrame := makeSineFrame(500, 700)
|
||||||
|
lowRMS := runFrameWarmup(lowSuppressor, noiseFrame, 8)
|
||||||
|
highRMS := runFrameWarmup(highSuppressor, noiseFrame, 8)
|
||||||
|
|
||||||
|
if highRMS >= lowRMS*0.8 {
|
||||||
|
t.Fatalf("expected stronger suppression at higher threshold, got low %.2f high %.2f", lowRMS, highRMS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func runFrameWarmup(suppressor *Suppressor, frame []int16, repeats int) float64 {
|
||||||
|
var processed []int16
|
||||||
|
for i := 0; i < repeats; i++ {
|
||||||
|
processed = append([]int16(nil), frame...)
|
||||||
|
suppressor.ProcessSamples(processed)
|
||||||
|
}
|
||||||
|
return frameRMS(processed)
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeSineFrame(frequency float64, amplitude float64) []int16 {
|
||||||
|
const sampleRate = 48000.0
|
||||||
|
const frameSize = 480
|
||||||
|
|
||||||
|
frame := make([]int16, frameSize)
|
||||||
|
for i := 0; i < frameSize; i++ {
|
||||||
|
value := math.Sin((2.0 * math.Pi * frequency * float64(i)) / sampleRate)
|
||||||
|
frame[i] = int16(value * amplitude)
|
||||||
|
}
|
||||||
|
return frame
|
||||||
|
}
|
||||||
|
|
||||||
|
func frameRMS(samples []int16) float64 {
|
||||||
|
if len(samples) == 0 {
|
||||||
|
return 0.0
|
||||||
|
}
|
||||||
|
var sumSquares float64
|
||||||
|
for _, sample := range samples {
|
||||||
|
normalized := float64(sample) / 32768.0
|
||||||
|
sumSquares += normalized * normalized
|
||||||
|
}
|
||||||
|
return math.Sqrt(sumSquares / float64(len(samples)))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user