A small FM radio client for the Omarchy bar. Connect to an SDR++ native server, tune a frequency, and listen through the desktop's default audio output. The QML panel belongs to Omarchy's existing shell; a bundled Rust executable handles the network stream, FM demodulation, and playback.
Version 1.2.0 supports stereo broadcast FM, 65–108 MHz, with European 50 µs
de-emphasis. Stations transmitting a 19 kHz pilot play in stereo; weak or mono
stations fade to mono on their own. Enter either 102.4 or 102,4. The −/+ buttons tune in 100 kHz
steps. Volume affects only the radio. Closing the panel keeps audio playing;
Disconnect, disabling the plugin, or unloading it stops reception.
Weak stations fade toward mono as the signal degrades. Noise reduction in the panel trades stereo away entirely for a much quieter signal — it removes the pilot along with the noise, so it is mono only.
Save the station or server in the field with + and give it a name; the saved
names appear as a row of shortcuts. Click one to switch to it, right-click it —
or press F2 while it is under the pointer — to rename or remove it, or press
Alt+1…9 for the first nine stations. Servers can be renamed and removed while
connected; only switching waits for Disconnect. Bookmarks live in
~/.local/state/omarchy/omafm.json.
For x86-64 Omarchy with the Quattro shell. The plugin includes
bin/omafm; users do not install Rust, compile anything, or install extra
packages. It uses the shell's Qt Quick Controls and the normal Omarchy
PipeWire/PulseAudio audio stack (libpulse-simple.so.0, libpulse.so.0) plus
standard Linux system libraries. It is not a standalone static Linux binary.
omarchy plugin add https://github.com/marvreichmann/omafm --enableThe prebuilt executable is committed with executable permissions: Omarchy clones the repository and does not execute installers or build hooks.
To install a locally built archive instead, extract the
omafm-<version>-linux-x86_64.tar.gz that scripts/build.sh writes to
dist/ into ~/.config/omarchy/plugins/. It contains a
com.github.marvreichmann.omafm/ folder. Then run:
omarchy plugin validate ~/.config/omarchy/plugins/com.github.marvreichmann.omafm
omarchy-shell shell rescanPlugins
omarchy plugin enable com.github.marvreichmann.omafm- Click the radio icon in the bar.
- Enter the server as
host:port(SDR++ normally uses port5259). - Enter a frequency in MHz and press Connect.
- Press Enter after editing a frequency, or use −/+. Adjust Volume as needed.
- Mute leaves the volume slider where it is; moving the slider unmutes.
- Press Escape or click outside to close the panel. Use Disconnect to stop.
The server must already have a working radio source selected and a sample rate between 240 kHz and 20 MHz. This client leaves source selection, gain, and sample-rate configuration to SDR++. SDR++ normally permits one client at a time; disconnect other clients first. This is the native SDR++ server protocol, not rtl_tcp, SpyServer, or an audio streaming URL.
The initial server is 127.0.0.1:5259, frequency 102.4, and volume 30%.
Panel edits last for the current widget instance. Optional server,
frequency, and volume settings in this widget's shell.json bar entry
override those starting values. It never connects automatically on load.
omarchy-shell shell summon com.github.marvreichmann.omafm '{}'
omarchy-shell shell hide com.github.marvreichmann.omafm
omarchy plugin disable com.github.marvreichmann.omafm
omarchy plugin enable com.github.marvreichmann.omafm
omarchy plugin remove com.github.marvreichmann.omafmDevelop in this repository. Copy only the packaged folder to the user plugin directory for testing; never edit Omarchy's packaged source.
Build requirements: x86-64 Linux, Rust 1.88+ with Cargo, PulseAudio development
linker files (Arch's libpulse), Python 3.11+, and Omarchy for plugin validation.
Cargo downloads the locked Rust dependencies on the first build. There are no
runtime downloads, install hooks, privileged operations, background services,
or separately installed SDR drivers.
cargo test --locked
cargo clippy --locked --all-targets -- -D warnings
bash scripts/build.sh
bash scripts/lint-qml.shscripts/build.sh creates bin/omafm, its checksum/build metadata and third
party notices, dist/com.github.marvreichmann.omafm/, and a versioned
archive. Keep bin/omafm,
bin/SHA256SUMS, bin/build-info.json, and licenses/ in the published repo.
The archive includes the Rust source, lockfile, tests, and build scripts.
Tests cover fragmented/invalid packets, busy-server handling, start/tune/stop commands, the QML control pipe, FM tone recovery at several input rates, and stereo-pilot rejection. Integration tests open local TCP sockets.
For a bounded live test (the WAV path must not already exist):
bin/omafm --server HOST:5259 --frequency 102.4 --seconds 12 --wav /tmp/fm-test.wav--no-audio tests decoding without an audio device. Backend stdout contains
JSON status and sample/drop counters. The panel sends newline-delimited JSON
over stdin: {"frequency":102.4}, {"volume":0.3}, {"stop":true}. EOF stops
the backend, except during an explicit --seconds test. WAV capture is a
developer diagnostic, not a plugin UI feature.
The Rust receiver requests uncompressed signed 16-bit IQ, decodes SDR++'s sample framing, applies staged anti-alias and channel filters, demodulates FM, recovers the 19 kHz pilot with a phase-locked loop to matrix left and right, filters each channel to 15 kHz, applies 50 µs de-emphasis, and resamples to 48 kHz with a fractional-delay filter bank. A bounded audio queue prevents memory and latency growth if the audio device stalls. Errors appear in the panel.
No spectrum/waterfall, scanning, presets, RDS, narrow FM, AM, SSB, source-control UI, or automatic reconnect is included. No packets are sent outside the server chosen by the user; SDR++ connections are plain TCP.
The sdrtop project informed the initial
Rust/DSP investigation. Its implementation is not copied or linked. Wire
compatibility was checked against SDR++'s
protocol definitions
and sample framing. QML integration follows the
Omarchy development guide.
The visual reference is Omathought.
Rust dependency licenses are included in licenses/.
See PUBLISHING.md for the release checklist. Building here does not publish a repository or submit a marketplace listing.
