Skip to content

secup/ProjectMorse

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ProjectMorse

ProjectMorse is a cross-platform SDL2 desktop app for multi-threaded CW (Morse) monitoring over a 3 kHz audio passband.

Goals (v1)

  • 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.

Architecture

  • 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.

Decoder Roadmap

  • Master implementation plan and tracking checklist:
    • docs/decoder_master_plan.md
  • Current UI/log output includes decoder confidence (0.00 to 1.00) per track update.

Build

cmake -S . -B build
cmake --build build -j
./build/projectmorse

Replay Benchmark Harness

Run reproducible replay scoring against a corpus manifest:

chmod +x tools/score_replays.sh
tools/score_replays.sh bench/replay_corpus.tsv

Output columns include:

  • TRACKS: spawned tracks (TRACK_NEW)
  • DECODES: emitted decode updates
  • TOKENS: expected keyword hit ratio from manifest
  • CALLSIGNS: expected callsign hit ratio
  • CHAR: character recovery ratio (subsequence-based) against expected_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 7

Audio Input Settings

Choose 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 50

In-app settings window:

  • Click OPEN SETTINGS in the bottom bar (or press F1) to open/close the settings window.
  • Mouse controls inside settings are fully clickable: device </>, APPLY, mode toggle, gain -/+, REFRESH, SAVE, and CLOSE.
  • Press F1 to open/close a dedicated settings window.
  • Left/Right cycles available input devices from the currently loaded list.
  • Enter applies the selected device immediately.
  • [ / ] (or - / =) adjusts waterfall display gain.
  • D toggles demo mode on/off.
  • R refreshes the device list on demand.
  • S saves 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

Known issue (queued for revisit)

  • 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), click APPLY.
  • Current diagnostic signature:
    • No callbacks received ... within timeout
    • Timeout diagnostics: status=1 queued_bytes=0
  • Impact: live input can end in NO INPUT after retries/restore attempts.
  • Workaround for now: restart app to resume live capture.

Dependencies

  • CMake >= 3.20
  • C++20 compiler
  • SDL2 development package

Current state

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).

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published