Files
supersonic/backend/autoeq_interpolate_test.go
T

181 lines
5.6 KiB
Go

package backend
import (
"math"
"testing"
)
func TestInterpolateAutoEQTo15Band_FlatProfile(t *testing.T) {
// Test with a flat profile (all zeros)
flatProfile := [10]float64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
result := InterpolateAutoEQTo15Band(flatProfile)
for i, gain := range result {
if math.Abs(gain) > 0.001 {
t.Errorf("Flat profile should result in zero gains, got %f at index %d", gain, i)
}
}
}
func TestInterpolateAutoEQTo15Band_ExactMatches(t *testing.T) {
// Test that exact frequency matches use the AutoEQ gain directly
// AutoEQ bands: 31, 62, 125, 250, 500, 1k, 2k, 4k, 8k, 16k Hz
// Supersonic bands: 25, 40, 63, 100, 160, 250, 400, 630, 1k, 1.6k, 2.5k, 4k, 6.3k, 10k, 16k Hz
// Exact matches: 250 (idx 5→3), 1k (idx 5→8), 4k (idx 7→11), 16k (idx 9→14)
testProfile := [10]float64{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
result := InterpolateAutoEQTo15Band(testProfile)
tests := []struct {
supersonicIdx int
autoEQIdx int
expectedGain float64
}{
{5, 3, 4}, // 250 Hz
{8, 5, 6}, // 1000 Hz
{11, 7, 8}, // 4000 Hz
{14, 9, 10}, // 16000 Hz
}
for _, tt := range tests {
if math.Abs(result[tt.supersonicIdx]-tt.expectedGain) > 0.001 {
t.Errorf("Exact match at index %d (AutoEQ idx %d): expected %f, got %f",
tt.supersonicIdx, tt.autoEQIdx, tt.expectedGain, result[tt.supersonicIdx])
}
}
}
func TestInterpolateAutoEQTo15Band_Interpolation(t *testing.T) {
// Test interpolation between bands
// Use a profile with known values to verify interpolation
testProfile := [10]float64{0, 0, 0, 0, 0, 10, 0, 0, 0, 0}
// Only 1000 Hz (index 5) has gain of 10 dB
result := InterpolateAutoEQTo15Band(testProfile)
// Check that 1000 Hz (index 8) has the exact value
if math.Abs(result[8]-10) > 0.001 {
t.Errorf("1000 Hz should be 10 dB, got %f", result[8])
}
// Check that nearby frequencies are interpolated (should be between 0 and 10)
// 630 Hz (index 7) should be between 500 Hz (0 dB) and 1000 Hz (10 dB)
if result[7] < 0 || result[7] > 10 {
t.Errorf("630 Hz interpolation out of range: %f", result[7])
}
// 1600 Hz (index 9) should be between 1000 Hz (10 dB) and 2000 Hz (0 dB)
if result[9] < 0 || result[9] > 10 {
t.Errorf("1600 Hz interpolation out of range: %f", result[9])
}
}
func TestInterpolateAutoEQTo15Band_Extrapolation(t *testing.T) {
// Test extrapolation for 25 Hz (below lowest AutoEQ band of 31.25 Hz)
testProfile := [10]float64{5, 10, 0, 0, 0, 0, 0, 0, 0, 0}
// 31.25 Hz = 5 dB, 62.5 Hz = 10 dB
result := InterpolateAutoEQTo15Band(testProfile)
// 25 Hz should be extrapolated below 31.25 Hz
// Since the slope is positive (5 to 10), 25 Hz should be < 5 dB
if result[0] > 5 {
t.Errorf("25 Hz extrapolation should be < 5 dB, got %f", result[0])
}
// It should be a reasonable value (not too extreme)
if math.Abs(result[0]) > 20 {
t.Errorf("25 Hz extrapolation too extreme: %f", result[0])
}
}
func TestInterpolateAutoEQTo15Band_RealProfile(t *testing.T) {
// Test with a realistic profile shape (bass and treble boost)
// Approximating a V-shaped response
testProfile := [10]float64{6, 5, 3, 1, 0, 0, 1, 3, 5, 6}
result := InterpolateAutoEQTo15Band(testProfile)
// Verify output is reasonable
if len(result) != 15 {
t.Errorf("Expected 15 bands, got %d", len(result))
}
// Check that interpolated values are between neighboring AutoEQ values
// For example, 40 Hz (index 1) should be between 31.25 Hz and 62.5 Hz values
if result[1] < math.Min(testProfile[0], testProfile[1])-1 ||
result[1] > math.Max(testProfile[0], testProfile[1])+1 {
t.Errorf("40 Hz interpolation out of reasonable range: %f (between %f and %f)",
result[1], testProfile[0], testProfile[1])
}
}
func TestInterpolateAutoEQTo15Band_MonotonicPreservation(t *testing.T) {
// Test that monotonic sections are preserved
// If AutoEQ gains are monotonically increasing, interpolated values should also increase
monotonicProfile := [10]float64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
result := InterpolateAutoEQTo15Band(monotonicProfile)
// Check general increasing trend (allowing for some extrapolation variance at edges)
for i := 2; i < len(result)-1; i++ {
if result[i] < result[i-1]-0.5 {
t.Errorf("Monotonicity not preserved at index %d: %f < %f",
i, result[i], result[i-1])
}
}
}
func TestFindSurroundingBands_ExactMatches(t *testing.T) {
tests := []struct {
freq float64
expectedLower int
expectedUpper int
}{
{31.25, 0, 0},
{62.5, 1, 1},
{125, 2, 2},
{250, 3, 3},
{1000, 5, 5},
{4000, 7, 7},
{16000, 9, 9},
}
for _, tt := range tests {
lower, upper := findSurroundingBands(tt.freq)
if lower != tt.expectedLower || upper != tt.expectedUpper {
t.Errorf("findSurroundingBands(%f): expected (%d, %d), got (%d, %d)",
tt.freq, tt.expectedLower, tt.expectedUpper, lower, upper)
}
}
}
func TestFindSurroundingBands_BetweenBands(t *testing.T) {
tests := []struct {
freq float64
expectedLower int
expectedUpper int
}{
{40, 0, 1}, // Between 31.25 and 62.5
{100, 1, 2}, // Between 62.5 and 125
{500, 4, 4}, // Exact match at 500
{2000, 6, 6}, // Exact match at 2000
{10000, 8, 9}, // Between 8000 and 16000
}
for _, tt := range tests {
lower, upper := findSurroundingBands(tt.freq)
if lower != tt.expectedLower || upper != tt.expectedUpper {
t.Errorf("findSurroundingBands(%f): expected (%d, %d), got (%d, %d)",
tt.freq, tt.expectedLower, tt.expectedUpper, lower, upper)
}
}
}
func TestFindSurroundingBands_BelowRange(t *testing.T) {
lower, upper := findSurroundingBands(25)
if lower != -1 || upper != 0 {
t.Errorf("findSurroundingBands(25): expected (-1, 0), got (%d, %d)", lower, upper)
}
}