What is CodeMonkey?
CodeMonkey is a desktop application for Linux that decodes and transmits Morse code (CW) in real time. It listens to your radio through the sound card, displays a live scrolling waterfall of the received audio spectrum, and continuously decodes any CW signal you click on. When transmitting, it encodes plain text to Morse and keys your radio through a serial port line or a GPIO pin — with full Farnsworth timing for slow practice. If you have a Hamlib-compatible transceiver, CodeMonkey connects to it automatically and lets you retune to the center of any signal with a single click.
What it does
- ►Real-time scrolling waterfall from 0–4 kHz (configurable range and gain)
- ►Continuous CW decode at 5–50 WPM with adaptive speed tracking
- ►Click anywhere on the waterfall to lock the decoder to that frequency
- ►Send any text as Morse code through the audio output
- ►Farnsworth timing — full character speed at reduced word spacing for learning
- ►Hardware keying via RTS or DTR serial line, or Raspberry Pi GPIO (sysfs)
- ►Hamlib radio control — connects automatically on startup; one-click frequency centering
- ►Prosign support:
<AR>,<SK>,<BT>,<KN>,<AS> - ►Command-line tools:
codemonkey-decodeandcodemonkey-encodefor scripting and pipelines - ►Full WebSocket API on port 2104 — expose decoded CW, decoder status, and radio control to scripts and external tools
WebSocket API
CodeMonkey exposes a full WebSocket API on TCP port 2104 (configurable). Decoded characters, decoder status, radio frequency, PTT state, and transmission control are all available programmatically. The API uses plain JSON over WebSocket.
View WebSocket API documentation →OTA Integration
CodeMonkey integrates with OTA, our SOTA/POTA spot hunter, via a built-in WebSocket bridge. OTA connects to CodeMonkey and delegates all radio control to it. When OTA selects a CW spot, it sends the frequency to CodeMonkey via the bridge; CodeMonkey automatically adjusts the VFO to place the incoming signal under the decoder tone marker. No manual offset calculation required.
- ►CodeMonkey takes full control of the radio when the OTA bridge is active
- ►VFO offset is calculated automatically for every CW spot — zero manual tuning
- ►
● OTA linkedstatus bar indicator shows when the bridge is active - ►If OTA disconnects, CodeMonkey continues operating normally
Alpha notice
CodeMonkey is early alpha software. The decoder works and is used on the air, but the interface is still evolving and there are known rough edges. Alpha builds expire 30 days after their compile date — download a fresh build when yours expires.
Bug reports and feedback are welcome.
Download
Linux x86-64 only for now. All binaries are unsigned alpha builds.
Installation
Linux GUI (AppImage)
- 1.Download the AppImage and make it executable:
chmod +x CodeMonkey-*.AppImage - 2.Run it:
./CodeMonkey-*.AppImage - 3.No installation required. Qt, Hamlib, and PortAudio are bundled inside the AppImage.
- ›The AppImage also includes the
codemonkey-decodeandcodemonkey-encodeCLI tools.
CLI tools
- 1.Download and make executable:
chmod +x codemonkey-decode codemonkey-encode - 2.The CLI tools link against system libraries. Install:
sudo apt-get install -y libportaudio2 - ›Pipe audio data to
codemonkey-decode, or pass text tocodemonkey-encodeto produce a WAV file.
How the decoder works
CodeMonkey’s decoder is built around a narrow-band I/Q demodulator and a probabilistic character matcher, inspired by the approach used in VE3NEA’s CW Skimmer. Rather than making hard threshold decisions at each step, it propagates confidence scores through the decoding pipeline so that ambiguous timing and noisy signals produce the most likely interpretation rather than garbage.
1. Resampling
Audio from the sound card (at any sample rate the system provides) is resampled to an internal rate of 8 000 Hz. The lower rate reduces CPU load for all downstream stages while comfortably covering the 0–4 kHz audio passband used on HF.
2. I/Q demodulation
The resampled audio is mixed with a cosine and a sine at the selected
tone frequency to produce in-phase (I) and quadrature (Q) components.
A low-pass Butterworth IIR filter (cutoff ≈ 200 Hz)
is applied to both channels to isolate the baseband signal from adjacent
QRM. The instantaneous signal strength (envelope) is computed as
√(I² + Q²).
This narrow, phase-coherent demodulation rejects adjacent signals and
achieves a much cleaner envelope than simple rectification or energy
detection.
3. Automatic gain control
An AGC stage normalizes the envelope to the 0–1 range using asymmetric time constants: fast attack (proportional to the estimated dit length) to track a suddenly stronger signal, and slow decay to avoid misreading the spaces between characters as signal loss. This makes the decoder insensitive to absolute signal level and allows it to follow fading without requiring manual gain adjustment.
4. Dual-threshold keying detection
A hysteresis comparator with upper threshold 0.60 and lower threshold 0.35 converts the normalized envelope to a binary key stream (mark / space). The gap between thresholds suppresses chatter at transitions caused by noise or signal flutter, producing a clean key-up / key-down event stream.
5. Adaptive timing analysis
The durations of successive marks and spaces form a bimodal histogram: one cluster for dits (and inter-element spaces), another for dahs (and inter-character/inter-word spaces). The decoder continuously fits this histogram to extract the current dit length in real time, tracking speed changes from approximately 5 WPM to 50 WPM without any manual adjustment. The PARIS standard (50 dit-equivalents per word) is used to convert dit length to words per minute.
6. Probabilistic character matching
Each mark or space is scored against the current timing model as a probability of being a dit, dah, inter-element space, inter-character space, or word space. These probabilities propagate through a Morse trie (binary decision tree, depth ≤ 6) to produce a weighted score for every candidate character at each branch. The highest-scoring leaf node wins. This approach — never making a hard timing decision early — is the core insight from CW Skimmer that lets it outperform threshold-only decoders on marginal signals and irregular fists.
7. Farnsworth timing (TX)
When sending, Farnsworth mode transmits each character at the full selected WPM but stretches inter-character and inter-word spaces so that the effective throughput matches a lower “Farnsworth WPM”. The spacing is computed from the PARIS formula: inter-character space = 3× a scaled unit, word space = 7×, where the unit is chosen so that the overall average matches the target Farnsworth rate. This is the standard method used by ARRL code courses for building copy speed.
Radio control & hardware keying
Hamlib rig control
CodeMonkey integrates with Hamlib, the universal amateur radio control library, which supports over 400 radio models from Icom, Kenwood, Yaesu, Elecraft, FlexRadio, and many others. Set your rig model, serial port, and baud rate in the Radio Setup dialog; CodeMonkey will connect automatically on startup and reconnect every 15 seconds if the link is lost.
Once connected, the frequency display in the status bar shows the current VFO frequency in real time. The Center button retunes the radio so that the decoded signal aligns with your TX tone frequency — one click to zero-beat any station you can hear.
Serial port keying (RTS / DTR)
CodeMonkey can key a CW interface wired to the RTS or DTR line of any serial port. Use the Hamlib-connected rig port (shared mode) or a separate USB-serial adapter for a standalone keyer interface. Both lines support polarity inversion for interfaces that require an active-low key signal. Keying is synchronized with audio output so both paths fire simultaneously.
GPIO keying (Raspberry Pi)
On Raspberry Pi and other Linux single-board computers, CodeMonkey can
key a transistor or relay directly from a GPIO pin using the Linux
/sys/class/gpio
sysfs interface. Select any BCM pin number in the Keying Setup dialog
(default: GPIO 17). Polarity inversion is supported for active-low
circuits. No additional drivers or libraries are required.
Requirements
- ►Linux x86-64 (Ubuntu 22.04 or later recommended)
- ►A sound card or USB audio interface connected to your radio’s receive audio output
- ►A Hamlib-compatible transceiver is optional — the decoder and keyer work without one
- ►For hardware keying: a USB-serial adapter (RS-232 RTS/DTR) or a Raspberry Pi GPIO pin
About Ordo Artificum
Ordo Artificum LLC is a small software company building amateur radio tools.