ProjectMorse is a cross-platform SDL2 desktop app for multi-threaded CW (Morse) monitoring over a 3 kHz audio passband.
- Capture live audio (48 kHz mono) from radio/soundcard input.
- Render a large real-time waterfall for ~300-3300 Hz.
- Detect multiple CW carriers and decode them in parallel worker threads.
- Show per-carrier decoded text, SNR estimate, and WPM estimate.
Audio thread(SDL2 capture callback): pushes samples into an SPSC ring buffer.DSP thread: STFT/FFT, waterfall row generation, carrier peak detection/tracking.Decoder worker pool: per-carrier state machines (hysteretic keying + timing to dits/dahs).UI thread: SDL2 rendering of waterfall + decode panel.
- Master implementation plan and tracking checklist:
docs/decoder_master_plan.md
- Current UI/log output includes decoder confidence (
0.00to1.00) per track update.
cmake -S . -B build
cmake --build build -j
./build/projectmorseRun reproducible replay scoring against a corpus manifest:
chmod +x tools/score_replays.sh
tools/score_replays.sh bench/replay_corpus.tsvOutput columns include:
TRACKS: spawned tracks (TRACK_NEW)DECODES: emitted decode updatesTOKENS: expected keyword hit ratio from manifestCALLSIGNS: expected callsign hit ratioCHAR: character recovery ratio (subsequence-based) againstexpected_text
Manifest format (tab separated):
file seconds expected_tokens expected_callsigns expected_text
Generate synthetic CW replays (with smooth keying + optional noise):
tools/inject_cw_f32.py \
--output synthetic_known_perfect.f32 \
--duration-sec 30 \
--preamble "VVV VVV" \
--text "CQ CQ DE PM0TEST PM0TEST K" \
--start-sec 4.0 \
--freq 984 \
--wpm 18 \
--level-db -14 \
--ramp-auto \
--ramp-shape cosine \
--noise-db -42 \
--seed 7Choose capture input at startup without editing code:
# List input devices
./build/projectmorse --list-inputs
# Select by index from --list-inputs
./build/projectmorse --input-index 0
# Select by exact device name
./build/projectmorse --input-device "Built-in Audio Analog Stereo"
# Force synthetic demo source (no live audio capture)
./build/projectmorse --demo
Use ./build/projectmorse --help to view all options.
Replay diagnostics helper:
# Save timestamped replay logs under logs/
tools/capture_replay_logs.sh synthetic_smooth_v1.f32 2 50In-app settings window:
- Click
OPEN SETTINGSin the bottom bar (or pressF1) to open/close the settings window. - Mouse controls inside settings are fully clickable: device
</>,APPLY, mode toggle, gain-/+,REFRESH,SAVE, andCLOSE. - Press
F1to open/close a dedicated settings window. Left/Rightcycles available input devices from the currently loaded list.Enterapplies the selected device immediately.[/](or-/=) adjusts waterfall display gain.Dtoggles demo mode on/off.Rrefreshes the device list on demand.Ssaves settings.
Settings are persisted to SDL's pref path (settings.ini) and reloaded on next launch.
The bottom bar in the main window always shows the current hotkeys.
If a newly applied live device stalls, ProjectMorse attempts to restore the previous live input and reports status.
Input diagnostics:
- Runtime input switching now prints detailed logs to stderr with prefixes:
[ProjectMorse/Input]for app-level selection/apply/restore decisions[ProjectMorse/AudioCapture]for SDL device open/close and negotiated formats
- Date noted: February 14, 2026.
- Symptom: applying/reopening a live input can leave capture stuck after successful open (
Opened ...appears, but no callbacks/audio data arrive, waterfall freezes). - Repro (current): start live capture, open settings, select
DEFAULT(or same physical input), clickAPPLY. - Current diagnostic signature:
No callbacks received ... within timeoutTimeout diagnostics: status=1 queued_bytes=0
- Impact: live input can end in
NO INPUTafter retries/restore attempts. - Workaround for now: restart app to resume live capture.
- CMake >= 3.20
- C++20 compiler
- SDL2 development package
This scaffold already runs the full threaded pipeline and renders live data. The Morse decoder is intentionally conservative and should be treated as a baseline for refinement (timing adaptation, tracking, denoise, and symbol confidence tuning).