# gocw **Repository Path**: bigsk/gocw ## Basic Information - **Project Name**: gocw - **Description**: Go Morse Code Generator - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-23 - **Last Updated**: 2026-09-04 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # gocw A zero-dependency Go CLI tool that converts text into Morse code (CW) audio WAV files. Designed for amateur radio operators to generate practice CW audio at configurable speeds, tones, and volumes. ## Features - Converts any ASCII text to International Morse code audio - **Decodes Morse audio back to text** with a tiny neural model (embedded `model.bin`, ~374KB, no external dependencies; robust to noise, fading and hand-key jitter down to -8 dB SNR) - Outputs standard 16-bit mono PCM WAV files - Configurable speed (WPM), tone frequency, volume, and sample rate - Accepts input from file, command-line argument, or stdin - Smooth sine-wave synthesis with fade-in/fade-out envelopes to prevent clicks - Standard PARIS-method timing (`dit = 1.2 / WPM`) - Supports 47 characters: `a-z`, `0-9`, and common punctuation - Zero external dependencies — uses only the Go standard library ## Installation ```bash go install github.com/bigsk05/gocw/cmd/cw@latest ``` Or build from source: ```bash git clone https://github.com/bigsk05/gocw.git cd gocw go build -o cw ./cmd/cw/ ``` ## Usage ``` cw -o output.wav [options] [input] ``` ### Flags | Flag | Type | Default | Description | |------|------|---------|-------------| | `-o` | string | *(required)* | Output WAV file path | | `-d` | string | `""` | Decode this WAV file into Morse text (overrides other flags; `-n` used only if explicitly given) | | `-t` | string | `""` | Direct text input | | `-i` | string | `""` | Input text file path | | `-s` | int | `12` | Speed in words per minute | | `-n` | int | `800` | Tone frequency in Hz | | `-v` | float64 | `1.0` | Volume (0.0 to 1.0) | | `-r` | int | `44100` | Audio sample rate in Hz | **Input priority:** `-t` (text flag) > `-i` (file) > stdin. ### Examples Generate CW audio from a text argument: ```bash ./cw -t "cq cq de w1aw" -o cq.wav ``` Generate from a file at 20 WPM with a 600 Hz tone: ```bash ./cw -i message.txt -o message.wav -s 20 -n 600 ``` Pipe from stdin: ```bash echo "sos" | ./cw -o sos.wav ``` Decode a recording (tone auto-detected, any sample rate): ```bash ./cw -d received.wav ./cw -d received.wav -n 700 # force the tone frequency ``` Generate then decode (round trip): ```bash ./cw -t "cq cq de bd8cmn" -s 20 -n 700 -r 16000 -o t.wav ./cw -d t.wav # prints: cq cq de bd8cmn ``` Adjust volume and sample rate: ```bash ./cw -t "hello world" -o hello.wav -v 0.5 -r 48000 ``` ## Supported Characters Letters: `a-z` Digits: `0-9` Punctuation: `. , / ? = ' ! ( ) & : ; + - _ " $` Unsupported characters will cause a panic. ## Project Structure ``` gocw/ ├── cmd/cw/main.go — CLI entry point, flag parsing, I/O ├── cw/ │ ├── cw.go — Core CW engine, timing, WAV output │ ├── morse.go — Morse code table and text normalization │ ├── synth.go — Sine wave and silence sample generation │ └── cw_test.go — Tests ├── go.mod ├── LICENSE — Apache 2.0 └── README.md ``` ## Library Usage The `cw` package can be used as a library in other Go projects: ```go package main import "github.com/bigsk05/gocw/cw" func main() { opts := cw.DefaultOptions() opts.Tone = 700 // Hz opts.Volume = 0.8 // 80% // Write a WAV file directly cw.OutputWave("Intro.wav", "CQ CQ CQ DE BD8CMN BD8CMN BD8CMN PSE K", 15, opts) // Or get raw PCM bytes for further processing pcm := cw.Generate("sos", 20, opts) _ = pcm // Or stream to any io.Writer cw.StreamWave(someWriter, "CQ CQ CQ DE BD8CMN BD8CMN BD8CMN PSE K", 12, opts) } ``` ### Decode API ```go text, err := cw.DecodeWaveFile("received.wav") // auto tone detect text, err = cw.DecodePCM(pcm, 16000) // raw 16-bit PCM text, err = cw.DecodeWaveFileOpts("received.wav", cw.DecodeOptions{Tone: 700}) // force tone ``` ### `cw.Options` ```go type Options struct { Tone int // Tone frequency in Hz (default: 800) Volume float64 // Volume multiplier 0.0–1.0 (default: 1.0) SampleRate int // Audio sample rate in Hz (default: 44100) } ``` ### Key Functions | Function | Description | |----------|-------------| | `cw.OutputWave(filename, text, wpm, opts)` | Write a WAV file to disk | | `cw.StreamWave(w, text, wpm, opts)` | Stream WAV data to an `io.Writer` | | `cw.Generate(text, wpm, opts)` | Return raw PCM bytes (no WAV header) | | `cw.DecodePCM(pcm, sampleRate)` | Decode raw 16-bit PCM bytes to text | | `cw.DecodeWaveFile(path)` | Decode a WAV file to text (tone auto-detected) | | `cw.DecodeWaveFileOpts(path, opts)` | Decode with `DecodeOptions{Tone: 700}` override | ## Testing ```bash go test ./cw/ # unit + golden parity (torch reference, 6 clips) # + generate -> decode round trip ``` CLI round trip: ```bash go build -o cw ./cmd/cw ./cw -t "cq cq de bd8cmn" -s 20 -n 700 -r 16000 -o t.wav ./cw -d t.wav # prints: cq cq de bd8cmn ``` ## Morse Timing The tool uses the standard PARIS method for WPM calculation: - **Dit duration** = `1.2 / WPM` seconds - **Dah duration** = 3 × dit - **Symbol space** (between elements) = 1 × dit - **Letter space** (between characters) = 3 × dit - **Word space** (between words) = 7 × dit At the default 12 WPM, a dit is 100 ms. ## License Apache License 2.0 — see [LICENSE](LICENSE) for details. ## Decoding notes - The decoder uses the same cross-runtime weights as pycw and the cw-train repository (`artifacts/model.bin` is the single source of truth). All three implementations (PyTorch / pycw numpy / gocw stdlib) reproduce the golden vectors byte-for-byte — see `cw/decoder_test.go` (golden parity) and [cw-train](https://git-direct.ghink.net/bigsk/cw-train) for the contract. - Inference runs in pure stdlib (float64 math); the model is embedded into the binary with `go:embed`, so the finished program is offline and self-contained.