package offline import ( "testing" "time" cfgpkg "github.com/jan/fm-rds-tx/internal/config" "github.com/jan/fm-rds-tx/internal/dsp" ) func extractComposite(g *Generator, duration time.Duration) ([]float64, float64) { cfg := g.cfg cfg.FM.FMModulationEnabled = false gen := NewGenerator(cfg) frame := gen.GenerateFrame(duration) samples := make([]float64, len(frame.Samples)) for i, s := range frame.Samples { samples[i] = float64(s.I) } return samples, frame.SampleRateHz } func TestCompositeHasPilotAt19kHz(t *testing.T) { cfg := cfgpkg.Default() cfg.FM.FMModulationEnabled = false cfg.FM.StereoEnabled = true samples, rate := extractComposite(NewGenerator(cfg), 200*time.Millisecond) pilotEnergy := dsp.BandEnergy(samples, rate, 19000, 500) noiseEnergy := dsp.BandEnergy(samples, rate, 12000, 500) if pilotEnergy < noiseEnergy*10 { t.Fatalf("missing 19 kHz pilot: pilot=%.6f noise=%.6f", pilotEnergy, noiseEnergy) } } func TestCompositeHasStereoAt38kHz(t *testing.T) { cfg := cfgpkg.Default() cfg.FM.FMModulationEnabled = false cfg.FM.StereoEnabled = true cfg.Audio.ToneLeftHz = 1000 cfg.Audio.ToneRightHz = 1600 // different L/R -> stereo energy samples, rate := extractComposite(NewGenerator(cfg), 200*time.Millisecond) stereoEnergy := dsp.BandEnergy(samples, rate, 38000, 3000) noiseEnergy := dsp.BandEnergy(samples, rate, 80000, 500) if stereoEnergy < noiseEnergy*1 { t.Fatalf("missing 38 kHz stereo energy: stereo=%.6f noise=%.6f", stereoEnergy, noiseEnergy) } } func TestCompositeHasRDSAt57kHz(t *testing.T) { cfg := cfgpkg.Default() cfg.FM.FMModulationEnabled = false cfg.RDS.Enabled = true samples, rate := extractComposite(NewGenerator(cfg), 200*time.Millisecond) rdsEnergy := dsp.BandEnergy(samples, rate, 57000, 3000) noiseEnergy := dsp.BandEnergy(samples, rate, 45000, 500) if rdsEnergy < noiseEnergy*5 { t.Fatalf("missing 57 kHz RDS energy: rds=%.6f noise=%.6f", rdsEnergy, noiseEnergy) } } func TestCompositeNoStereoWhenDisabled(t *testing.T) { cfg := cfgpkg.Default() cfg.FM.FMModulationEnabled = false cfg.FM.StereoEnabled = false samples, rate := extractComposite(NewGenerator(cfg), 200*time.Millisecond) pilotEnergy := dsp.BandEnergy(samples, rate, 19000, 500) // Should be near-zero compared to mono energy monoEnergy := dsp.BandEnergy(samples, rate, 1000, 500) if monoEnergy > 0 && pilotEnergy > monoEnergy*0.01 { t.Fatalf("pilot should be suppressed: pilot=%.6f mono=%.6f", pilotEnergy, monoEnergy) } } func TestCompositeNoRDSWhenDisabled(t *testing.T) { cfg := cfgpkg.Default() cfg.FM.FMModulationEnabled = false cfg.RDS.Enabled = false samples, rate := extractComposite(NewGenerator(cfg), 200*time.Millisecond) rdsEnergy := dsp.BandEnergy(samples, rate, 57000, 3000) monoEnergy := dsp.BandEnergy(samples, rate, 1000, 500) if monoEnergy > 0 && rdsEnergy > monoEnergy*0.001 { t.Fatalf("RDS should be suppressed: rds=%.6f mono=%.6f", rdsEnergy, monoEnergy) } }