package cwdecode import ( "math" "strings" "testing" ) // reverse Morse map for the synthesizer. func charToMorse() map[byte]string { m := map[byte]string{} for code, ch := range morse { m[ch] = code } return m } // keyMessage synthesizes a clean keyed tone for msg at the given WPM/pitch. func keyMessage(msg string, fs, wpm int, pitch float64) []int16 { dot := fs * 1200 / (wpm * 1000) // samples per dot c2m := charToMorse() var out []int16 phase := 0.0 dphi := 2 * math.Pi * pitch / float64(fs) tone := func(n int) { for i := 0; i < n; i++ { out = append(out, int16(9000*math.Sin(phase))) phase += dphi } } silence := func(n int) { for i := 0; i < n; i++ { out = append(out, 0) } } silence(fs / 4) // 250 ms lead-in for AGC warmup for i := 0; i < len(msg); i++ { ch := msg[i] if ch == ' ' { silence(7 * dot) continue } code := c2m[ch] for j := 0; j < len(code); j++ { if code[j] == '.' { tone(dot) } else { tone(3 * dot) } silence(dot) // inter-element gap } silence(3 * dot) // inter-character gap (on top of the trailing element gap) } silence(fs / 4) return out } func TestDecodeCleanSignal(t *testing.T) { const fs = 16000 var sb strings.Builder d := New(fs, func(s string) { sb.WriteString(s) }, nil) // Repeat so AGC warm-up only costs the first word. samples := keyMessage("PARIS PARIS PARIS", fs, 22, 700) // Feed in small chunks like the live capture would. for i := 0; i < len(samples); i += 256 { end := i + 256 if end > len(samples) { end = len(samples) } d.Process(samples[i:end]) } got := strings.ToUpper(sb.String()) if !strings.Contains(got, "PARIS") { t.Fatalf("decoded %q, want it to contain PARIS", got) } } func TestDecodeNumbersAndProsign(t *testing.T) { const fs = 16000 var sb strings.Builder d := New(fs, func(s string) { sb.WriteString(s) }, nil) samples := keyMessage("TEST 599 TEST", fs, 18, 650) for i := 0; i < len(samples); i += 200 { end := i + 200 if end > len(samples) { end = len(samples) } d.Process(samples[i:end]) } got := strings.ToUpper(sb.String()) if !strings.Contains(got, "599") { t.Fatalf("decoded %q, want it to contain 599", got) } }