package synth import ( "math" "testing" ) func TestPanGainsCenter(t *testing.T) { gainL, gainR := PanGains(0.0) expected := math.Sqrt2 / 2 // cos(pi/4) = sin(pi/4) = 0.707... if math.Abs(gainL-expected) > 1e-9 { t.Errorf("PanGains(0.0) gainL = %v, want ~%v", gainL, expected) } if math.Abs(gainR-expected) > 1e-9 { t.Errorf("PanGains(0.0) gainR = %v, want ~%v", gainR, expected) } } func TestPanGainsFullLeft(t *testing.T) { gainL, gainR := PanGains(-1.0) if math.Abs(gainL-1.0) > 1e-9 { t.Errorf("PanGains(-1.0) gainL = %v, want ~1.0", gainL) } if math.Abs(gainR-0.0) > 1e-9 { t.Errorf("PanGains(-1.0) gainR = %v, want ~0.0", gainR) } } func TestPanGainsFullRight(t *testing.T) { gainL, gainR := PanGains(1.0) if math.Abs(gainL-0.0) > 1e-9 { t.Errorf("PanGains(1.0) gainL = %v, want ~0.0", gainL) } if math.Abs(gainR-1.0) > 1e-9 { t.Errorf("PanGains(1.0) gainR = %v, want ~1.0", gainR) } } func TestPanGainsPowerPreserved(t *testing.T) { pans := []float64{-1.0, -0.75, -0.5, -0.25, 0.0, 0.25, 0.5, 0.75, 1.0} for _, p := range pans { gainL, gainR := PanGains(p) power := gainL*gainL + gainR*gainR if math.Abs(power-1.0) > 1e-9 { t.Errorf("PanGains(%v) power = %v, want 1.0 (constant power law)", p, power) } } } func TestStereoFramesToInt16Bytes(t *testing.T) { frames := [][2]float64{{1.0, -1.0}} buf := StereoFramesToInt16Bytes(frames) if len(buf) != 4 { t.Fatalf("expected 4 bytes, got %d", len(buf)) } // int16(32767) in little-endian = [0xFF, 0x7F] // int16(-32767) in little-endian = [0x01, 0x80] expectedL := int16(32767) expectedR := int16(-32767) gotL := int16(uint16(buf[0]) | uint16(buf[1])<<8) gotR := int16(uint16(buf[2]) | uint16(buf[3])<<8) if gotL != expectedL { t.Errorf("left channel = %d, want %d", gotL, expectedL) } if gotR != expectedR { t.Errorf("right channel = %d, want %d", gotR, expectedR) } } func TestStereoFramesToInt16BytesZero(t *testing.T) { frames := [][2]float64{{0.0, 0.0}} buf := StereoFramesToInt16Bytes(frames) if len(buf) != 4 { t.Fatalf("expected 4 bytes, got %d", len(buf)) } for i, b := range buf { if b != 0 { t.Errorf("byte[%d] = %d, want 0", i, b) } } } func TestClampPreventsOverflow(t *testing.T) { // Values > 1.0 should be clamped to 1.0 before int16 conversion frames := [][2]float64{{2.0, -2.0}} buf := StereoFramesToInt16Bytes(frames) gotL := int16(uint16(buf[0]) | uint16(buf[1])<<8) gotR := int16(uint16(buf[2]) | uint16(buf[3])<<8) // Should be clamped to max int16 positive / negative if gotL != int16(32767) { t.Errorf("clamped left = %d, want 32767", gotL) } if gotR != int16(-32767) { t.Errorf("clamped right = %d, want -32767", gotR) } }