Complete solution for remote ham radio control: operate your shack from anywhere on earth. Tune frequencies, transmit (CW / RTTY / PSK31 / Olivia / APRS / voice / SSTV / WEFAX images), watch the SDR panadapter, decode twelve digital modes, and stream broadcast-quality audio to a Windows desktop, web browser, iOS / Android phone, or Home Assistant dashboard. Single port for full remote access through Cloudflare Tunnel, Tailscale Funnel, nginx, or a port-forward, with optional HMAC-SHA-256 authentication.
From my shack to yours
I love building apps, and ShackLink is what happens when I get to blend my two favorite worlds: software and ham radio. It began as a scratch-my-own-itch project. I wanted to run my own station from anywhere, exactly the way I like it, so I built it. It grew into something I’m glad to share, so the Windows server and desktop client are completely free. When the iOS and Android apps arrive, a small charge may apply on those platforms, just enough to cover the app-store costs.
It’s still under active development and heavily in beta, so you’ll meet the odd rough edge here and there. Feedback is hugely appreciated. It genuinely steers where this goes. One friendly heads-up: there’s a lot of information on screen, so a large monitor is highly recommended. What can I say? I like my eye candy. 😄
📻 Why ShackLink?
Everything you need to control your ham radio remotely over your local network, or anywhere on the internet.
🌐 Operate From Anywhere
One unified HTTP + WebSocket port (8084) carries the entire client experience: control, audio, transmit, SDR spectrum. Wrap it in a Cloudflare Tunnel, Tailscale Funnel, or plain reverse proxy and your shack travels with you. HMAC-SHA-256 authentication (optional) gates every connection so unauthorized clients are dropped before any state is sent.
🎧 Dual Audio Streams
Two parallel audio paths: low-latency 12 kHz PCM for tuning and digital-mode work (~200 ms), and 192 kbps stereo MP3 (HiFi) for broadcast-quality listening. Clients toggle between them per-session; HiFi works in any browser / VLC / mpv just by opening the URL.
🔢 Twelve Server-Side Decoders
CW (40+ WPM), RTTY (auto-detect baud + shift, two demod algorithms), PSK31 (9 BPSK / QPSK variants with AFC and FEC), FT8 / FT4 (a native in-process decoder, or relayed from a co-located WSJT-X via UDP 2237: your choice, identical downstream), SSTV (20 modes across Robot, Martin, Scottie, PD, Wraase, Pasokon with progressive image rendering), WEFAX (weather-fax decoder with phasing-lock detector, IOC 576 / 288 at 60 / 120 LPM), NAVTEX (SITOR-B FEC, 100 baud, 170 Hz shift, maritime safety messages), APRS (AX.25 1200 baud Bell 202 AFSK packet radio with position and message decoding), WSPR (propagation spots via WSJT-X, enriched with country, distance and bearing), JS8 (keyboard-to-keyboard traffic bridged from JS8Call over its TCP API), and Olivia / Contestia (native MFSK, 4–64 tones across 125–2000 Hz, transmit included). Ten of the twelve are native: ShackLink does the DSP itself, on the server, immune to network jitter, with nothing else to install. Only WSPR and JS8 are strictly bridged, from WSJT-X and JS8Call, which must be running.
🧩 Plug-in Decoders
A drop-in decoder framework: add a new decode mode by dropping a DLL into the server’s Decoders\ folder, no recompile. The server discovers it at startup and lists it in the decode-mode picker on the server and every connected client (desktop, web, mobile), complete with generated settings and optional centre-frequency tuning. Decoders are self-describing over the wire, so a client can render a plug-in it has never seen. Output can be text, progressive image, structured records, or transformed audio (the path a future voice codec such as FreeDV will use). Your selection persists across restarts. Two worked examples ship in source (a self-contained NAVTEX decoder and an audio echo effect. Plug-ins run in-process, full-trust) install only what you trust.
🔎 Band Skimmer
A CW-Skimmer-style wideband decoder: decode every signal of a mode across a whole band segment at once (one lane per signal) off a running SDR slot’s raw I/Q, with live callsign spots. Modes: CW, RTTY, PSK31 / PSK63, Olivia / Contestia, NAVTEX, FT8 / FT4: tick any combination and the skimmer classifies each signal and attaches the right decoder per lane. (FT8/FT4 lanes are 3 kHz windows rather than single signals, because that decoder is wideband by nature; the stations land in the spot list.) Confirmed calls chip the waterfall, feed the Band Activity dashboard, fire watch-list webhooks, and dim when worked-before. It runs alongside the slot’s normal decoder (an instrument, not a decode mode), and streams to the desktop, web, and mobile clients as a live view console.
📡 Native FT8 / FT4, No WSJT-X Required
ShackLink has its own FT8 and FT4 decoder, written from the protocol up: synchronisation, LDPC error correction, ordered-statistics decoding and multi-pass signal subtraction. Pick it with the Engine selector and nothing else has to be running. The WSJT-X bridge stays available and the two are indistinguishable downstream (same list, same wire, same clients) and two compare settings run both at once, logging the A/B difference cycle by cycle to CSV. Extras that come with it: an RX-frequency focus that pulls just the traffic you care about into its own pane, a cycle-locked wide graph with a rectangle drawn around every decode, optional a-priori decoding (ships off), and per-slot FT8/FT4 so several bands decode at once.
📻 FT8 Wideband Skim
Park one SDR and decode every FT8 and FT4 sub-band that fits in its capture, in parallel, cycle after cycle: several bands at once from a single receiver. Spots are keyed by their real on-air frequency rather than an audio offset, so two decodes at 1500 Hz in different windows are correctly different stations. The planner discloses the LO, the span it needs, every window it will watch, and honest warnings about ADC bit depth and calibration, before it starts. Watch it live from the desktop client.
📜 Slot Decoders Console
Each of the 8 SDR slots can run its own decoder on its own audio, and one window shows all of them at once: a lane per text-mode slot with its live transcript, and a table of FT8/FT4 records. Lanes retire dimmed rather than vanishing when you stop a decoder, so the transcript stays attributable. Set a slot’s decoder from the server or any client; the mode list is shipped by the server, so it can never drift out of date. On the server, the desktop client, the web client and the mobile app.
📶 Wideband Scan
Sweep one or several SDRs at once across a range far wider than any of them can see (a whole HF spectrum, every ham band, or the FM broadcast band) into a stitched panorama, a sweep-by-sweep waterfall, and a list of hits you can park a receiver on. Tick more radios and the range is split between them: sweep time falls and probability of intercept rises by about the number of radios, and one radio can be kept out as a listener so the search never stops while you listen. A mandatory preflight discloses hops, sweep time, achieved resolution and probability of intercept per radio before anything moves. Unmeasured frequencies are drawn as gaps rather than interpolated, hits are one row per signal rather than one per detection, and zoom is always a view: the sweep and detector run the full plan regardless. Hold out one more radio as a classifier and it visits the hits and labels them by mode, marking anything it cannot identify honestly rather than guessing. The desktop client can watch it live from another machine.
🔊 Full Transmit Subsystem
Server-owned TX pipeline for CW, PSK31, RTTY, Olivia, APRS, voice, FT8 / FT4, and image modes (SSTV all 18 sub-modes + WEFAX), plus the Waterfall Painter‘s spectrum art and the Lab’s six transmitting instruments. PTT via OmniRig. Single-owner lock prevents collisions across clients. TX:CONFIG protocol broadcasts every TX setting so server, desktop, web, and mobile clients stay in sync. Voice uplink uses 16-bit PCM (port 8082 on the LAN, channel-tagged binary on the unified WebSocket for remote). Image upload is chunked + SHA-256 verified. Test-no-RF mode lets you rehearse without keying the rig.
📡 FT8 / FT4 Transmit & QSO Console
Transmit FT8 and FT4 natively, no WSJT-X in the loop. A compose strip under the decode lists carries the TX frequency (Shift+click the wide graph to aim it) and a message box that verifies as you type, through the same packer the transmitter uses, so a message that would pack to something else is refused rather than truncated. Beside it, a full QSO sequencer: double-click a decode, arm Enable TX, and the station answers, reports, rogers and offers to log itself, with Tx1–Tx6, Auto-seq and Hold-TX-freq. A desktop client can drive the whole console remotely: arming is exclusive and one-at-a-time, and disconnecting releases the arm and halts the sequence. Nothing ever starts a sequence on its own.
🔧 TX Instruments: the Lab’s stimulus half
Six server-side instruments that transmit something known so the rest of the Lab has a controlled signal to measure. A Signal Generator (eleven waveforms: carrier, two-tone, multitone comb, noise, burst, square, sinc, pulse train, gaussian pulse, chirp, arbitrary from file, each optionally AM / DSB / FM modulated), rehearsed silently into the Test Tone slot before anything is keyed. Two calibration wizards (level calibration and source characterization). A TX Health Check purity bench scoring six measurements against the ARRL Clean Signal Initiative masks. An SWR Sweep using the radio’s own bridge. A WSPR Beacon with a who-heard-me map fed by three independent spot feeds. And IQ Replay of a recorded scene, rate-converted with the residual stated. Every one of them confirms before each transmission, never remembers consent to radiate, and states its level in dBFS until you have calibrated it.
📡 SDR Panadapter
Up to 8 SDR devices simultaneously, each in its own slot with independent spectrum, demodulator, and optional per-slot decoder. Supports ExtIO plugins (Airspy, SDRplay, etc.), RTL-SDR (via rtl_tcp, local or remote dongles), HackRF (in-process, RX+TX with WFM/NFM demod and polyphase FIR decimation), Hermes Lite 2 (Ethernet, HPSDR Protocol 1, 48–384 kHz, full-duplex RX+TX, N2ADR LPF auto-select, SWR protection), native sound-card I/Q, or a synthetic test source. Click-to-tune and drag-to-pan on every display surface (server, desktop, web, mobile, HA card). All clients can select which slot to view and switch the audio source between slots. Two modes: RF (independent SDR receiver) and IF panadapter (radio’s IF tap, displayed center tracks the rig’s CAT frequency). Per-client server-side zoom with a navigator overview channel. Configurable FFT size (4K–32K). Run multiple identical devices at once (several HackRF, SDRplay, RTL, or Hermes Lite 2 units), each bound to its own serial/MAC, with automatic recovery from device stalls, service hiccups, and sleep/resume.
📈 Lab Measurements
Professional RF measurement workstation built on up to 8 simultaneous SDR sources. Multi-trace overlay with per-trace modes (ClearWrite, MaxHold, MinHold, Average, RMS), 8 markers with peak search and N-dB bandwidth, automated measurements (channel power, OBW, ACPR, SNR, harmonics/THD, IMD/IP3), DPX persistence display, spectrogram waterfall, two-SDR transfer function (S21) with limit masks, CSV and Touchstone S1P/S2P export, and C# scripting via Roslyn with a full MeasurementApi for measurement automation. Wheel-zoom at the cursor with zoom history, and a stitched multi-band view that splices disjoint SDR bands side by side, with a per-trace segment lane editor to keep just the slice of each band you care about. Plus eleven dedicated instruments: five that measure what arrives (modulation analyzer, phase noise, noise figure, zero-span scope, and a mask-trigger black-box I/Q recorder) and six that transmit something known to measure against, and one-click video recording of the display. The trace and marker grids dock to any edge, as does the SDR tab’s control band.
🔌 Multi-Rig Support & Sync Rules
Control up to 4 radios through OmniRig v2 with custom names, each maintaining independent state. Drag-and-drop rig-to-rig sync rules (offset / invert sideband / sync frequency / sync mode) drive transverters, dual-radio diversity, or monitoring receivers automatically.
💻 Multi-Platform Clients
Windows desktop client, web browser, iOS / Android (.NET MAUI), and Home Assistant Lovelace cards. Auto-detect picks the lowest-latency LAN path when the server is local; manual hostname entry switches mobile to the auth-gated unified WebSocket for remote access.
💾 48 Server-Synced Memory Slots
Frequency/mode/label memories stored on the server and synchronized to all connected clients in real-time. Save, recall, clear, and label from any client, and changes propagate instantly. An All Memories window shows the whole bank at once as a wall of tiles.
📍 Band Plan / Frequency Table
Built-in searchable reference of amateur allocations, calling frequencies, and mode segments for HF/VHF/UHF. Click any row to tune the radio instantly.
🎥 Recording & Visualization
Local audio recording (WAV / MP3) on every client. Live audio visualization with 4 modes (waterfall, spectrum, spectrum LED, oscilloscope) and 6 themes (Classic, Neon, Grayscale, Ham Radio, Semaphore, Rainbow), full peak-hold + gain / contrast / range controls.
🎨 A Radio-Panel Interface
Every button, dropdown, list and tab header is drawn by ShackLink itself, not by Windows, so the whole application follows one finish (glossy, matte, satin or flat: the material) times one of 19 colour themes (the colour), and the two are independent. The VFO frequency readout is a real instrument display with sixteen styles: transflective LCD with unlit ghost segments, vacuum fluorescent, amber LED, Nixie tubes, dot matrix, split-flap, with per-digit tuning, direct keyboard entry, and its own band / mode / step fields. Bands and modes are segmented button strips, memory buttons show label, frequency and mode at a glance, and a mini band scope sits in the tab row so the spectrum is visible from every tab. VFO windows can be opened per radio and per SDR slot and left across two monitors.
📅 Scheduler & Automation
Program multi-step radio operations: tune, decode (all twelve modes), record, transmit, on a schedule (one-time, daily, weekly, interval) or on demand. Chain programs together, use built-in templates (CW Beacon, FT8 Session, WEFAX Receiver, equipment test demos), import/export program sets. A step’s source can be an SDR slot as well as a rig: a step can take over an RX-capable slot or transmit from a TX-capable slot, not just an OmniRig radio. Scheduled TX modes: CW, RTTY, PSK31, Olivia/Contestia, APRS, SSTV (19 modes), WEFAX, and voice from file. Band plan validation, listen-before-transmit, max TX time cap, and auto station ID for Part 97 compliance.
🚀 System Architecture
A unified server architecture with multiple client connection options.
Open the full interactive architecture →Click the diagram for the full plate: 108 blocks and 65 data paths, with hover-to-trace, a detail panel on every block, layer filters, and poster printing up to A0.
Network Ports
/, HiFi MP3 at /hifi.mp3, and WebSocket at /ws carrying control + audio + voice TX + SDR for browsers, HA cards, and remote mobile. Optional HMAC auth gate. The only port to expose for full remote access.📡 End-to-End Data Flow
Antenna to rendered pixel in eight stages. The transmit half of the same picture is in the TX Subsystem section below.
Open the full signal-flow plate →Click the diagram for the full plate: both pipelines stage by stage, and the guarantee that holds at each hand-off. LAN clients (desktop, and mobile once it has discovered a server) take the multi-port path — 8080 control, 8081 audio, 8082 voice, 8085 spectrum — while browser, Home Assistant and remote mobile clients ride a single unified WebSocket on port 8084.
🔊 TX Subsystem
One shared transmit pipeline on the server. Clients never touch PTT or the soundcard directly. They remote-control the server’s TxEngine. Supports CW, RTTY, PSK31, Olivia, APRS, voice, SSTV (19 modes), WEFAX (IOC 576/288 at 60/120 LPM), and the Waterfall Painter’s spectrum art. All TX settings are server-owned and broadcast to every client via the TX:CONFIG protocol.
CW: QSO chat panel with CQ/QSL/73 quick-send and TX/RX VU meters
Voice: hold-to-talk PTT, mic device picker, and test-no-RF mode
SSTV / WEFAX: the image TX panel with preview and live build-up as the encoder transmits
Nothing here starts by itself. A single-owner lock means only one client keys the radio at a time and everyone is told who holds it; text modes go through an encoder, voice pipes PCM into the same output buffer, and FT8 / FT4 arm and wait for the cycle boundary rather than keying straight away.
Digital-mode TX lifecycle
TX:SEND is the normal flush-and-stop path, and the sink is drained before the transmitter is unkeyed. TX:UNKEY aborts mid-character; TX:ABORT releases a stuck lock from any caller.
Voice TX: binary uplink handshake
The token lets the voice uplink stream with no per-packet framing while still enforcing “only the current lock owner writes audio”. Over the WebSocket the session itself is the authentication, so there is no token at all.
Lock state machine
Only one client owns the lock at a time; a non-owner is answered TX:LOCKED with the owner’s name. Every abort path — unkey, abort, a dropped socket, the on-time watchdog — ends back at Idle.
📦 Components
The ShackLink ecosystem includes multiple client applications for different platforms.
Server (Windows)
Main server connects to your radio via OmniRig. Manages all clients, audio streaming, and all twelve digital decoders.
Desktop Client
Native Windows app with VFO knob control, frequency display, audio playback, all twelve decoders, and full TX support via TCP.
Web Client
Browser-based interface with tabbed work area. Frequency tuning, memory channels, audio streaming, all twelve decoders, and image TX.
Home Assistant
Two custom Lovelace cards: radio control surface with all twelve decoders and TX, plus standalone SDR waterfall card.
Cross-Platform App
.NET MAUI app for Windows, iOS, and Android. Touch-friendly controls, all twelve decoders, voice TX, and SDR panadapter.
Arduino Integration
USB serial protocol for hardware projects. Build controllers with physical knobs and buttons.
📷 Screenshots
See ShackLink in action across different platforms.
Server Application – Main window with frequency display, meters, and controls
SDR Panadapter – Real-time spectrum scope and waterfall with click-to-tune and markers
Spectrum Analyzer (Bars) – Classic bar-style spectrum display with peak hold indicators
Spectrum Analyzer (LEDs) – Retro LED-style spectrum display with segmented bars and peak indicators
Client Management – Monitor and manage all connected WebSocket clients in real-time
Desktop Client – Windows client with SDR panadapter and 3D waterfall
Web Client – Browser interface with frequency control and digital decoders
Home Assistant – Lovelace dashboard integration
Cross-Platform App – Windows, iOS, and Android with SDR panadapter and 3D waterfall
👥 Client Management
Monitor and manage all connected clients from the server.
🌐 WebSocket Clients
View all connected web browsers and Home Assistant instances. See client IP addresses, connection time, and real-time status.
🕑 Auto-Refresh
Client list updates automatically every few seconds. New connections appear instantly, disconnected clients are removed.
🔒 Connection Control
Disconnect individual clients when needed. Useful for troubleshooting or managing server resources.
📊 Status Monitoring
Track audio streaming status and subscription state for each client. Identify which clients are actively receiving audio.
Accessing the Clients List
- Click the Show WS Clients button on the server main window
- A dialog opens showing all currently connected WebSocket clients
- The list auto-refreshes to show real-time connection status
- Select a client and click Disconnect to terminate its connection
WebSocket clients dialog showing connected browsers and their status
💡 Client Types
WebSocket clients include web browsers accessing the built-in web client, Home Assistant Lovelace cards, the mobile app’s remote (unified) transport, and any custom integrations using the WebSocket API on the unified port 8084 (path /ws). When authentication is enabled, every connecting client must answer an HMAC-SHA-256 nonce challenge before any state or audio is delivered.
🛠 Installation
Get up and running in minutes with these simple steps.
Step 1: Install OmniRig v2.0 or later
OmniRig v2 is required for up to 4-rig support.
Download OmniRig v2.0 or later
Get it from hb9ryz.ch/omnirig
Configure Radio
Set COM port, baud rate, and select your radio model
Test Connection
Verify frequency updates when tuning your radio
Step 2: Install ShackLink Server
- Download the latest release from ditdots.com
- Extract all files to a folder (e.g.,
C:\ShackLink) - Run
ShackLinkServer.exe - When prompted by Windows Firewall, click Allow Access
📦 Required Files
Ensure all DLL files are in the same folder: NAudio.dll, NAudio.Core.dll, NAudio.Wasapi.dll, NAudio.WinMM.dll, NAudio.Lame.dll, Fleck.dll
Step 3: Configure Firewall (Tools → Configure Firewall)
Allow incoming connections on these ports:
- 8080 – TCP radio control
- 8081 – TCP audio streaming and UDP auto-discovery
- 8082 – Voice TX uplink (LAN)
- 8084 – Unified HTTP + WebSocket (web client, HiFi MP3,
/ws), only port needed for remote access - 8085 – SDR spectrum stream (LAN)
Step 4: Connect Clients
Open a browser to http://[SERVER_IP]:8084 for web client, or install desktop/mobile client and enter server IP.
🎧 Audio Streaming
Setup
- Connect radio audio output to your sound card’s line input
- Select the audio input device from the dropdown
- Click Start Streaming to begin broadcasting
🎙 Audio Format
Audio is streamed as 12kHz, 16-bit, mono PCM. This provides good quality while minimizing bandwidth (24 KB/sec).
HiFi MP3 Stream (192 kbps stereo)
The server simultaneously exposes a broadcast-quality MP3 stream at http://server:8084/hifi.mp3, served from the same unified port that hosts the web client and the WebSocket endpoint. One shared LAME encoder feeds every connected listener, no extra CPU per client. The encoder spins up automatically when the first client connects and idles when nobody’s listening.
- Works in any browser / VLC / mpv: paste the URL and go. No client install needed.
- ICY “Now Playing” metadata: clients that send
Icy-MetaData: 1receive the current rig / frequency / mode as a Shoutcast-style title, updated on every state broadcast. - Discovery-aware: the UDP broadcast on port 8081 advertises the server hostname, HiFi, SDR, WebSocket ports, and LAN auth requirement (
ShackLink Server;name=<hostname>;hifi=8084;sdr=8085;ws=8084;auth=<required|none>) so non-default configurations still auto-detect, clients can display servers by name, and native clients know up-front whether they need to authenticate. - When to prefer which stream: use 12 kHz PCM for low-latency work (CW, digital modes, hearing your own TX), HiFi for casual listening or voice reception where broadcast fidelity matters more than ~1 s buffer latency.
Volume Control
The Audio tab includes a system volume slider that controls the default audio output device level. The volume level and the audio monitor on/off state are persisted across sessions.
Demo Mode
Enable demo mode to generate synthetic Morse code audio for testing without a connected radio. Useful for development, demonstrations, and learning.
📡 SDR Panadapter
Real-time spectrum and waterfall display from an SDR receiver.
SDR tab: scope, navigator, and 2D waterfall
3D terrain waterfall: the 2D scope stays live above it
SDR Management: assign a source, audio input, and per-slot decode mode (the eight modes that can run per slot: CW, RTTY, PSK31, NAVTEX, APRS, Olivia, FT8, FT4) to each of 8 slots. The mode can also be set from the desktop, web and mobile clients, and every slot’s output is visible in the Slot Decoders console.
Panadapter Settings: RF mode or IF mode with sideband offsets and pan policy
Waterfall popout: independent 3D view for a second monitor
Phosphor spectrum persistence over the 3D terrain
The same view under a different palette
Channel Monitor: per-bank frequency lists with range scan
Source Types
- ExtIO Plugin (DLL): Load any ExtIO-compatible plugin (Airspy, SDRplay, etc.). Device selection for adapters with multiple units is done through the plugin’s native GUI: click “Show Native GUI” after opening to access the plugin’s device picker.
- RTL-SDR (via rtl_tcp): Drives dongles through rtl_tcp, a small open-source driver server; because librtlsdr/rtl_tcp are GPL they are not bundled: download once and drop into the server’s folder. Each local dongle is its own source entry; a network entry connects to a remote rtl_tcp instance (e.g. a dongle on a Raspberry Pi at the antenna). Direct sampling (HF on V3/V4 dongles) and bias-T are applied for real.
- HackRF: In-process via libhackrf. RX + TX, half-duplex, 1 MHz – 6 GHz, up to 20 MHz bandwidth. WFM / NFM demodulation with polyphase FIR decimation for high sample rates.
- Hermes Lite 2: Ethernet SDR transceiver via HPSDR Protocol 1. Full-duplex RX + TX, 48–384 kHz sample rates, N2ADR LPF/HPF filter board auto-selection, SWR protection with auto-unkey, and temperature monitoring. Live frequency changes via C&C registers.
- Native Sound-Card I/Q: A regular sound card capturing baseband I/Q from an external IF tap or quadrature converter. Pick the input device, set the sample rate, off you go.
- Icom Native CI-V: Control an Icom CI-V radio (e.g. IC-705) directly, with no OmniRig required, and use its built-in spectrum scope as a first-class SDR slot. Works over USB serial or over the network (Wi-Fi) via Icom’s RS-BA1 protocol, which carries control, scope, RX audio, and TX voice. The scope reassembles from the radio’s CI-V waveform frames; center mode spans VFO ± span, fixed mode uses the configured edges.
- IQ File Playback Slot: Map a slot to a saved I/Q recording (a SigMF pair, a
.sigmfarchive, or a legacy.sliqfile) that loops forever, replaying captured spectrum like a virtual SDR. The LO is fixed at the recording’s center; click-to-tune moves the demod listen point, and FFT size stays adjustable. - Test Signal (synthetic): Sine + Gaussian noise generator for development and testing without hardware.
Sources are assigned to slots from the SDR Management dialog (there is no longer a single source dropdown). Most drivers run in-process; only ExtIO plugins go through the 32-bit broker subprocess; RTL-SDR runs through the separate, user-supplied rtl_tcp process instead.
FFT Size
The FFT combo on the SDR tab controls frequency resolution (4096 / 8192 / 16384 / 32768). Larger FFT = sharper waterfall when zoomed, at the cost of more CPU. Default is 16384. Changes take effect immediately and persist per-device.
Display Features
- Embedded + Popout: Scope + waterfall on the SDR tab, plus a “Popout Spectrum” button for a resizable window
- Auto-center: The waterfall automatically follows rig frequency changes for all SDR sources (HackRF, Hermes Lite 2, Sound Card I/Q, ExtIO/Broker), keeping the current signal centered on the display
- Click-to-tune: Click on the waterfall to set the rig frequency (or the SDR LO in RF mode)
- Drag-to-pan: Drag the spectrum or the frequency strip to slide the band; in IF mode the policy follows the server’s Pan mode setting
- Memory markers: Toggle “Show memory markers” to overlay stored memory frequencies on the spectrum
- DX spot markers, Live DX cluster spots drawn on the waterfall with callsign labels, color-coded by age
- Broadcast station markers: Known broadcast station frequencies overlaid on the waterfall with station name labels
- Gain / Contrast / dB floor: Adjustable via sliders on the popout toolbar
- Per-client zoom, Each connected client requests its own zoom span; a navigator overview channel shows where you are in the full band
- Navigator overview: A miniature full-band view showing the current zoom window position, enabling quick orientation within the band
- Phosphor spectrum: Persistence-overlay mode that accumulates spectrum traces over time, visualizing signal density and intermittent signals
- Phosphor histogram (experimental): An optional GQRX-style density/histogram color mode for the phosphor overlay (coarse cells + IIR smoothing), alongside the existing amplitude-hue and Gaussian-spread modes. Still an A/B experiment pending a verdict
- 3D waterfall (terrain view): Toggle the waterfall pane between the flat 2D scroll and a rotatable 3D perspective terrain of spectrum history (right-click → 3D Waterfall, or the corner 3D/2D button). Orbit camera by dragging, plus Reset 3D View and an optional Fit Height to Pane. GPU-accelerated via OpenGL with a silent CPU fallback; heights and colors reuse the 2D waterfall palette for exact parity
- Waterfall Ref (max-level): A Ref slider sets the top of the waterfall color scale (default 0 dBFS) so strong signals actually reach the top of the palette; gain headroom now runs to +60. Mirrored on the Lab spectrogram
- Zoom FFT: Server-side NCO + decimation zoom providing high-resolution narrow-band views without increasing overall FFT size
- AGC speed / IF gain / Filter presets: SDR receiver controls for AGC attack/decay speed, IF gain adjustment, and predefined filter bandwidth presets
- Multi-SDR slots, Up to 8 devices simultaneously, each in its own slot with independent LO, FFT size, demod settings, and optional per-slot decoder. Slot selector appears in all clients when multiple devices are active. One slot at a time feeds the audio output.
- Multiple identical devices: Run several of the same kind at once (multiple HackRF, SDRplay, Hermes Lite 2, or RTL-SDR units), each bound to its own slot by serial number (MAC address for Hermes Lite 2) so it keeps pointing at the same physical unit across USB re-ordering.
- SDRplay two-stage gain: RSP devices expose both gain stages on the panel: the IF Gain combo (0–59 dB) plus an RF LNA state combo (0 = max front-end gain; dB per state is band/model dependent: the SDR log’s “Gain report” line shows the real figures). Max sensitivity = IF 59 dB + LNA 0. Hardware AGC runs a 50 Hz loop at a −30 dBFS setpoint; switching AGC off returns to the last manual gain, and picking a manual gain switches AGC off. All of it persists per device and restores at slot start.
- Automatic recovery: A slot whose device dies or whose stream stalls restarts itself automatically (RTL, HackRF, Hermes Lite 2, SDRplay); the SDRplay API service self-heals if it stops or wedges; and streaming SDR slots restart automatically after the PC wakes from sleep.
Auto-Identify Signals (AI Recognition)
A neural-network classifier can scan the panadapter continuously and label every signal with its recognized mode. Right-click the spectrum display → Auto-Identify Signals to start a background scan of the selected slot; each confidently identified signal gets a small colour-coded chip centred on its carrier, with a guide line through the scope and waterfall.
- Colour-coded by family: CW, RTTY/FSK, PSK, MFSK, FT8/FT4, image (SSTV/WEFAX), packet/APRS, and voice each get a distinct chip colour
- Hover card: resting on a chip shows the top candidate modes with confidence, plus the measured frequency, bandwidth, SNR, and any decoder cross-check result
- Confident only: noise, unknown signals, and cross-check mismatches are hidden; a chip clears automatically the moment its signal goes off the air, and identified signals scrolled out of view are summarised by an edge arrow + count
- Show Signal Labels: a separate right-click toggle hides / shows the chips locally without stopping the scan
- Server-authoritative: the scan runs on the server and the chips are broadcast to the desktop client, which renders them identically. The classifier recognizes the modes in the installed model package; a signal outside that set is left unlabelled rather than guessed
Auto-Identify needs raw I/Q, so it is available on IQ-capable sources (ExtIO/broker, RTL-SDR, HackRF, Hermes Lite 2, SDRplay, sound-card I/Q, and the synthetic test band); Icom scope slots and IQ-file playback are excluded, and it is refused while a slot is in IF-panadapter mode. A one-shot Identify Signal right-click option identifies a single signal (with optional decoder confirmation) even when the continuous scan is off.
RDS (Radio Data System)
RDS auto-activates whenever the SDR demodulator is in WFM: it is not a decode mode you select. It decodes the 57 kHz subcarrier for the station name (PS), programme identification (PI), RadioText, programme type, clock time, and traffic/network data.
It surfaces in the same idiom as the Auto-Identify chips above: a teal chip at the tuning marker on the SDR spectrum display reading “RDS <station name>”, dim until sync, with the full detail (PI, PTY, RadioText, clock, ECC / language, TMC / EON) on the hover card. The chip appears on the embedded SDR tab, on slot popouts, and in the SDR grid cells.
Architecture
ExtIO-based SDR sources use a 32-bit broker subprocess (ShackLinkSdrHost.exe) that loads the plugin, captures IQ data into a shared memory-mapped ring buffer. The server (64-bit) reads the ring, runs a windowed complex FFT, and produces dB-scaled spectrum lines at 30 fps. HackRF, Hermes Lite 2, and Sound Card I/Q run in-process (no broker), feeding IQ samples directly into the same FFT pipeline. Lines fan out to: the embedded display, the popout window, TCP 8085 stream (desktop client), and WebSocket binary frames (web/mobile/HA clients).
IQ Recording (SigMF)
Record live SDR I/Q to SigMF (the open Signal Metadata Format): either a SigMF meta+data pair or a single .sigmf tar archive, for later analysis or replay. The archive writer transcodes between sample formats (ci16, ci32, cf64, cu16). Zoomed (NCO + decimated) recordings are captured correctly and in real time. The legacy .sliq writer has been retired, but old .sliq files still play back. A recording can be replayed one-shot, or mapped to a looping IQ File Playback Slot (see Source Types above).
Per-Slot Audio Input
Each SDR slot can carry its own audio input device (an “Audio In” column per slot row in the SDR Management dialog) instead of one global input, so switching between, say, a USB-rig slot and an SDR slot no longer grabs the wrong sound device. Leave it empty to inherit the global Audio-tab device; SDR slots default to the SDR demodulator. The setting follows the audio-active slot (the one you hear).
🔬 Lab Measurements (RF Workstation)
Professional multi-trace spectrum analysis built on up to 8 simultaneous SDR sources. Available on both the server and the desktop client.
Lab tab: multi-trace analyzer, Traces/Markers grid, and spectrogram
3D spectrogram terrain
Peak markers on the selected trace
Spectral CCDF panel below the analyzer
Stitch segments: the lane-strip editor composes a gap-free multi-band view
The same composed view in the independent Lab popout
Palette variation
Palette variation
Palette variation
Multi-Trace Overlay (8 Traces)
The Lab tab provides a SkiaSharp-rendered spectrum display with up to 8 independent traces, each bindable to a different SDR slot. Per-trace controls include:
- Trace modes: ClearWrite (live), MaxHold (peak envelope), MinHold (noise floor), Average (configurable N), RMS
- Math traces: A+B and A−B operations between any two traces for comparison and delta measurements
- Per-trace gain offset (−60 to +60 dB) and noise floor (−160 to −20 dB) via slider columns in the Traces grid
- Color customization: independent trace color and peak-hold color per trace, chosen via color picker
Zoom & Stitched Multi-Band View
The mouse wheel zooms at the cursor on both the analyzer and the waterfall (Ctrl+wheel = gain, Ctrl+Shift+wheel = floor), backed by a zoom history (Zoom Back via right-click or the mouse’s back button), a Zoom Out ×2 action, a log-scale toolbar Zoom slider, and draggable navigator edge grips. Stitch mode deletes the empty gaps between disjoint SDR bands and splices the covered ranges into one continuous axis: a 40 m slice directly beside a 20 m slice.
- Stitch segments (kept ranges): each trace can contribute just a chosen slice of its span to the stitched view, so you compose exactly the multi-band picture you want (e.g. only the FT8 windows of three bands, side by side).
- Segment lane editor: the Segments toolbar toggle opens one lane per visible SDR trace: a live mini-spectrum of the slot’s full span with the kept range as a draggable band (drag edges to resize, body to move, empty space to draw, double-click for full span). The plot re-stitches live while you drag.
- Quick actions: or simply zoom into a slice and right-click → Stitch Segment ▸ Keep Current View.
- Honest by design: segments are render-side only (markers, measurements, and exports still read the full trace at real frequencies), kept ranges survive retunes (they ghost while the slot is away and re-apply when it returns), and no LOs move, so it works on rig-tracking and IF-locked slots too.
Marker System (8 Markers)
Up to 8 simultaneous markers with real-time frequency and amplitude readout:
- Normal: frequency and amplitude at the marker position
- Delta: frequency and amplitude difference between two markers
- Band Power: integrated power within a specified bandwidth
- Noise: noise density in dBFS/Hz
- Peak search / min search: jump to the highest or lowest point, navigate left/right between peaks
- N-dB bandwidth: find the −3/6/10/20/40/60 dB bandwidth around the current marker
The spectrum right-click menu adds Place Marker Here (drop a marker at the clicked frequency) and Clear All Markers (remove every placed marker and clear the marker grid in one action).
Automated Measurements
An eight-row Measurements grid (a label tab beside Markers) computes a chosen measurement per trace on every sweep, with blank-for-auto parameters and live Result/Detail columns; a quick readout also appears in the toolbar. Available measurements:
Channel Power
Total power within a defined channel bandwidth.
OBW
Occupied bandwidth containing 99% of signal power.
ACPR
Adjacent channel power ratio for transmitter testing.
SNR
Signal-to-noise ratio measurement.
Harmonics / THD
Harmonic distortion analysis with individual harmonic levels.
IMD / IP3
Intermodulation distortion and third-order intercept point.
CFO
Carrier frequency offset vs a reference, in Hz and ppm.
Occupancy
Percent of a band above the noise floor, averaged over a time window.
Duty Cycle
Percent of time a channel is keyed (active) over a time window.
Envelope
Peak / current / floor at a frequency, held across sweeps.
Image Rejection
I/Q image-rejection ratio: a signal versus its mirror across the receiver’s DC, in dBc.
Noise-Floor Rise
Close-in noise floor near a strong carrier versus the far floor: a reciprocal-mixing proxy.
Spurious vs SM.329
Spurs reported as dBc below the carrier against a simplified ITU-R SM.329 mask, with a PASS/FAIL count.
Spectral Flatness
Spectral flatness (Wiener entropy) over a band, with passband ripple.
A Log to CSV toggle on the Measurements tab appends every enabled row to %LocalAppData%\ShackLink\Lab\measurements.csv about once per second for trend analysis. Readings are relative (dB/dBFS/dBc/%/Hz) by default.
Amplitude calibration (approximate dBm). There is no traceable power calibration, so the Lab is relative (dBFS) by default. You can assert an approximate reference per SDR slot: set the amplitude unit to dBm, then type a per-slot offset or use the Cal drop-down’s “Set from marker” helper (offset = known dBm − marker dBFS). Absolute readouts then show dBm*: the * marks it user-asserted, not traceable. Relative metrics are unaffected. Any gain change on the slot (MGC / LNA / AGC, conservatively IF gain) marks the calibration stale and reverts it to dBFS, so a stale offset never silently lies; the server also broadcasts a per-slot gain-change pulse so remote desktop clients invalidate their own calibration.
Display Modes
- DPX persistence: temporal density display showing signal persistence over time. Color palettes (unified with the SDR tab): Classic (blue), Classic (green), CoolWarm, Viridis, Plasma, Inferno, Grayscale, Neon (cyan)
- Spectrogram waterfall: time-frequency display with gain, contrast, floor, and speed controls. Synchronized frequency axis with the main spectrum. Toggles to a 3D perspective terrain view of the spectrogram history (GPU-accelerated, with a silent CPU fallback)
- Spectral CCDF: complementary cumulative distribution of spectrum-bin amplitude vs the mean (frequency-domain spectral peak-to-mean, not time-domain PAPR / crest factor)
- PSK constellation + EVM/MER: live I/Q scatter of recovered PSK31 symbols (2 points BPSK-31, 4 QPSK-31) with persistence, ideal-point overlay, lock indicator, and a true modulation-quality readout (Error Vector Magnitude %, Modulation Error Ratio dB). PSK31-only; honestly shows “—” when not locked. Computed server-side and streamed to the desktop client. A VSA summary adds peak EVM, a magnitude/phase-error split, residual carrier frequency error (after AFC), and I/Q offset, with a 60-second EVM trend
- Audio SINAD: true signal-to-noise-and-distortion ratio of a steady tone in the demodulated audio of the active SDR slot (a CW/SSB beat-note, an AM/FM tone, or a test tone). Measured from the actual demod audio, not the spectrum; a ratio, so no calibration needed; honestly shows “—” with no tone. Computed server-side and broadcast to the desktop client
Instruments (Dedicated Instrument Windows)
An Instruments toolbar dropdown opens eleven focused, single-purpose windows, each a popout running alongside the analyzer, modeled on professional spectrum-analyzer application firmware. Five measure whatever arrives at the receiver; six transmit something known so there is a controlled signal worth measuring. The transmitting six are server-only (only the server has a transmitter), as are the Zero-Span Scope and the recorder; everything else also runs on the desktop client.
A rule that runs through all eleven: they never invent a number. Where an instrument cannot honestly measure it shows an em dash, a named warning badge, or refuses to start, and until the level-calibration wizard has been run, every transmitting instrument states its level in dBFS and says why rather than printing a dBm figure it cannot support.
Signal Generator (server)
Eleven waveforms: carrier, two-tone, multitone comb, band-limited noise, pulsed burst, square, sinc, pulse train, gaussian pulse, chirp, arbitrary from WAV/CSV, each optionally AM / DSB / FM modulated, picked from grids of drawn pictures rather than dropdowns. Rehearse renders it silently into the Test Tone slot first, exactly (not approximately) as it will go out, so it appears on every client’s waterfall with nothing on the antenna.
TX Calibration (server)
Two wizards in one bench session. Level calibration builds the transmitter’s gain × frequency table: a loopback through a known pad gives the curve’s shape, your power meter supplies the one absolute anchor, and until that anchor exists everything honestly reads dBFS. Source characterization measures the transmitter’s own harmonics, spurs and IMD3, so later measurements can say “source-limited” instead of quietly reporting the generator.
TX Health Check (server)
The purity bench: two-tone IMD, CW keying, ALC overshoot and PTT timing, harmonics and spurious, modulation quality, and composite noise, six measurements onto one dated report card, scored against the ARRL Clean Signal Initiative masks. A reading within 6 dB of the analyzer’s own noise comes back as the floor with a “≤” in front of it, never as a result.
SWR Sweep (server)
Sweeps SWR across a span using the radio’s own bridge: a resonance finder rather than an impedance instrument. A radio whose meter curve is not in this build still sweeps in raw meter units and declines to claim a VSWR number, because the dip’s position does not need the curve and the magnitude does.
WSPR Beacon (server)
Beacons WSPR on the bands you pick and collects who heard you from three independent spot feeds, drawn as paths out of your station on the greyline map. A reception seen by two feeds is marked corroborated and carries both; where they disagree the spread stays beside the figure. The transmitted power is always your declaration; calibration only caps a claim above the radio’s measured maximum.
IQ Replay (server)
Transmits a recorded or synthesized I/Q scene out of the HackRF or Hermes Lite 2. The rate conversion is the honest core: exact ratios where the arithmetic allows one, a stated residual in ppm where it does not, and a refusal past 1000 ppm, because a scene at the wrong rate is a signal at the wrong bandwidth and looks entirely plausible on a waterfall.
Modulation Analyzer
AM depth / FM deviation (peak & RMS) / carrier offset / modulation rate of the slot you are hearing, on an analog needle face. Tapped from the demodulator, not the spectrum; AM/FM only; honest “—” with no carrier. (FSW-K7-style.)
Mask Trigger
Arm a limit mask over a trace; a violation fires a black-box pre/post I/Q capture to SigMF, a spectrum snapshot, and webhooks, with an event list and slot timeline. (Tek RSA FMT-style.) The client is a view-only console.
Zero-Span Scope (server)
An RF oscilloscope: envelope vs time of an IQ slot with scope triggering (Auto / Normal / Single / Free-run) and automatic burst measurements: rise/fall, width, period, duty, overshoot, on/off ratio.
Phase Noise
Carrier-tracked SSB phase noise L(f) dBc/Hz vs log offset: ENBW-correct, spur-excluded, window-skirt-masked, with a decade table (10 Hz–1 MHz), integrated jitter, and reference compare. (FSW-K40-style.)
Noise Figure
Guided Y-factor NF with a calibrated noise head: system NF (Mode A) or DUT NF + gain via Friis (Mode B), NF(f)/gain(f) curves, ENR head profiles, and gain-change voiding. (NFA / FSW-K30-style.)
Video Recording (server)
A ● Rec button records the Lab display (or the whole window) + system audio to MP4 in Videos\ShackLink, with selectable scope and 30/60 fps. Also on the SDR and Lab popout windows.
Modulation Analyzer: AM depth / FM deviation on an analog meter face, with the VSA table and trend
Mask Trigger: an armed limit mask with the event list and slot-lane timeline
Zero-Span Scope: RF envelope vs time with scope triggering and burst measurements
Phase Noise: L(f) in dBc/Hz vs log offset with the decade table and jitter
Noise Figure: the guided Y-factor wizard with the NF(f) / gain curves and ENR head profiles
Advanced Tools
- Transfer function (S21): two-SDR stimulus/response measurement with calibration and limit-mask overlays. Export as Touchstone S1P/S2P
- Limit masks: regulatory and user-defined spectral masks for compliance visualization (spurious emission, harmonic suppression, bandpass)
- C# scripting: Roslyn-powered scripting engine with a MeasurementApi providing programmatic access to traces, markers, and measurements. Editor in a separate popup window with example scripts
- Cable loss compensation: predefined cable types and custom entry for length-based loss correction
- Export: CSV (all traces with frequency/amplitude columns), Touchstone S1P/S2P, PNG screenshot, and measurement log
Tune From Spectrum
Enabled from the spectrum right-click menu (Tune From Spectrum), this turns the passive Lab display into an interactive listening surface that drives the SDR back-end:
- Select a trace: click a trace to highlight it; audio-follow switches to that trace’s SDR slot, so you now hear that device.
- Tune within the band: click again inside the selected trace’s band to move that slot’s demodulator (the listen point) to the clicked frequency.
- No re-center: tuning moves the listen point only; the SDR LO is not re-centered, so the trace stays put instead of jumping (previously the LO auto-centered on the click, which shifted the whole trace by megahertz on wide / FM-band spans). You tune within the currently captured span; to listen outside it, use Band Browse to move the window.
- Overlays: the selected trace can show a VFO frequency readout (Show Frequency) and a passband box (Show Passband).
- Peak markers: mark the top-N peaks on the selected trace. The Peak Markers submenu configures count (3–10), color, size (2–8 px), style (filled circle / outline / square / diamond), and optional frequency labels.
Band Browse
Active while Tune From Spectrum is on, Band Browse shifts a slot’s SDR LO so you can sweep across the band:
- Grab and drag a trace line horizontally, or click the plot then press Left/Right arrow keys, to shift that slot’s LO.
- Held listen frequency: if the slot is the audio-active (listening) one, the absolute listen frequency is held by compensating the demod offset. Audio mutes when the held frequency leaves the captured span and resumes when a later shift brings it back into span.
- Step size: with arrow keys, Shift = ×10 coarse step, Ctrl = fine step.
- Refused for rig-tracking slots and IF-panadapter mode, with a brief on-display “Locked” notice.
Shift Station to Edge
Also part of Tune From Spectrum, Shift Station to Edge parks a slot’s tuned signal at the left or right edge of its span (the server computes the LO from the listen frequency and demod mode). Pair a Right shift on a lower trace with a Left shift on a higher trace to butt two bands together for a wide, gap-free side-by-side view.
Popout Independence (Link Toggle)
The Lab popout window carries a Link toggle. Linked, it mirrors the tab: mode, settings, and data stay in lock-step. Unlinked, the popout becomes fully independent, with its own zoom, amplitude scale, palette, 3D camera, and pane layout (all persisted separately), so you can keep a wide overview on the tab and a zoomed detail view in the popout at the same time.
No-Data Legend Status
A checked (visible) trace whose SDR source is not delivering data still appears in the spectrum legend, its name shown dimmed with a short status word (Not started, No data, or Unavailable) in place of a frequency range, so you can see the trace is selected but waiting on its device.
Desktop Client Support
The full Lab tab is available on the desktop client with identical functionality. All UI code is shared via <Compile Include> links. The client’s SdrStreamPlayer feeds the same TraceEngine with SDL1 frames from the server’s spectrum stream (TCP 8085). Persistence, popout, scripting, transfer function, and export all work identically on both server and client.
Architecture
The Lab tab is a passive overlay on existing SDR spectrum data by default. When Tune From Spectrum is enabled it can select the audio slot (which device you hear), tune a slot’s demodulator listen point, and (for Band Browse) shift a slot’s LO; it still never alters the SDR capture pipeline or FFT. The desktop client uses dedicated commands for these actions (SDR:<n>:DEMODTUNE:<absHz> / SDR:<n>:LOSHIFT:<Hz> over TCP, sdrDemodTune / sdrLoShift over WebSocket); the server’s own SDR-tab panadapter click still re-centers as before, so only the Lab tune is no-re-center. The engine library (ShackLinkLab, netstandard2.0) provides TraceEngine, MarkerEngine, MeasurementEngine, PersistenceEngine, TransferFunctionEngine, LimitMaskEngine, CcdfEngine, and ScriptHost. UI rendering uses SkiaSharp with double-buffered offscreen compositing and GDI+ blit. Total CPU budget at full load (8 traces, 8 markers, persistence, spectrogram): ~15–20 ms per 33 ms frame.
📊 Audio Visualization
Real-time audio visualization with multiple display modes and customizable themes.
Waterfall (2D) on the Audio tab
Waterfall (3D terrain)
Oscilloscope: time-domain waveform
Visualization popout: 2D waterfall in its own window
Visualization popout: 3D terrain waterfall on a second monitor
Opening the Visualization Window
Click the Visualization button in the Audio Streaming section to open a modeless visualization window. The window stays open while you work with other controls.
Visualization Modes
🌊 Waterfall
Scrolling spectrogram display showing frequency over time. New data appears at top and scrolls down. Includes a smooth spectrum curve overlay. Great for identifying signals and monitoring band activity.
📈 Spectrum (Bars)
Classic bar-style spectrum analyzer with peak hold indicators. Shows real-time frequency amplitude across the audio passband. Peaks slowly decay to show recent maximum levels.
💡 Spectrum (LEDs)
Retro LED-style segmented display reminiscent of vintage audio equipment. 32 segments per bar with configurable peak indicators. Adjustable peak height from 1-10 pixels.
💨 Oscilloscope
Time-domain waveform display showing the raw audio signal. Useful for monitoring signal levels and identifying modulation patterns.
Tuning from the Waterfall
The audio waterfall is tunable everywhere it appears: the Audio tab, the photo panel, and the Visualization popout.
Hover the audio waterfall and a dim ghost cursor follows the pointer, reading out the frequency under it, and, for modes you can retune, a preview of the decoder’s passband centred on the cursor, so you can see how it would sit on the signal before you commit. Click to place the decoder there. The marker then shows where the decoder actually landed, so if the value was out of range you see the clamp rather than a marker that quietly disagrees.
Only PSK31, Olivia and NAVTEX have a centre frequency to move; in other modes the click just parks the marker. Note that this sets the decoder’s centre frequency inside the audio passband: it is not the SDR waterfall’s click-to-tune, and the radio does not move.
Decoder Passband
A translucent decoder passband rectangle shows the span the active decoder is listening across: Olivia’s exact bandwidth (16/500 = 500 Hz), PSK31’s symbol rate, RTTY’s live auto-detected mark/space rails, and the fixed tone rails for NAVTEX, APRS, SSTV, WEFAX and CW. It is the nominal occupied span: an alignment aid, not a measured bandwidth. Right-click → Decoder Passband toggles it.
FT8, WSPR and JS8 show no passband: those are decoded by WSJT-X / JS8Call, not by ShackLink, so there is nothing honest to draw.
Color Themes
- Classic – Traditional green VU-meter style (green/yellow/red gradient)
- Neon – Vibrant cyan/magenta cyberpunk aesthetic
- Grayscale – Clean black and white display
- Ham Radio – Blue waterfall with green spectrum, optimized for radio use (default for Waterfall mode)
- Semaphore – Traffic-light style: green at low levels, yellow at mid, red near the top
- Rainbow – Bars colored by frequency position across the spectrum (left to right)
Display Settings
- Sensitivity – Adjust input gain for optimal display levels
- Contrast – Control the dynamic range of the visualization
- Freq Range – Set the maximum displayed frequency
- Peak Color – Choose peak indicator color (theme-based options)
- Peak Height – Set peak indicator height (1-10 pixels)
- Reverse – Flip waterfall scroll direction (new data at bottom)
💡 Settings Persistence
All visualization settings are automatically saved and restored between sessions. The window also remembers its position and size.
🔢 Digital Decoders
The server decodes twelve digital modes: CW (Morse), RTTY, PSK31, FT8, FT4, SSTV, WEFAX, NAVTEX, APRS, WSPR (relayed from WSJT-X), JS8 (bridged from JS8Call), and Olivia/Contestia. Select the decoder mode from the dropdown to switch between them: the choice is broadcast to every connected client.
Ten of the twelve are native: ShackLink does the DSP itself, so nothing else needs to be installed. WSPR and JS8 are bridged (from WSJT-X and JS8Call respectively) and only produce anything while that program is running. FT8 and FT4 can be either: the Engine picker on the FT8 panel selects the native decoder or the WSJT-X bridge, and the two are indistinguishable downstream. The bridge remains the shipped default while the native engine accumulates on-air hours.
CW (Morse): signal scope, element display, and decoded text
SSTV: image on the left, live audio-band waterfall on the right
A decoded image mirrored in the dashboard panel
Decoder popout: CW in its own window
Expand to Window: the detachable full-size decoder with image + waterfall
Morse (CW) Decoder
- Select CW (Morse) from the decoder mode dropdown
- Enable the decoder checkbox
- Choose decoder algorithm: Speed Priority or Accuracy Priority
- Decoded text appears in the display and streams to clients
RTTY Decoder
- Select RTTY from the decoder mode dropdown
- Enable the decoder checkbox
- The decoder auto-detects baud rate (45.45 or 50 baud) and shift (170/425/850 Hz)
- Monitor signal quality and lock status indicators
- Decoded text appears in the display and streams to clients
PSK31 Decoder
- Select PSK31 from the decoder mode dropdown
- Pick a modulation mode (9 variants):
- BPSK-31 / BPSK-63 / BPSK-125: binary PSK at 31.25, 62.5, or 125 baud
- QPSK-L-31/63/125: quadrature PSK with Viterbi FEC, lower sideband
- QPSK-U-31/63/125: quadrature PSK with Viterbi FEC, upper sideband
- Set the center frequency (200–3000 Hz) to match the signal in the audio passband
- Enable AFC to automatically track frequency drift
- Enable FEC for Viterbi forward error correction on QPSK modes
- Adjust squelch to filter noise when no signal is present
- Decoded text appears in the display and streams to clients
SSTV Decoder
Receives Slow Scan Television images on voice modes (typically USB). The SSTV panel embeds a split view directly in the Decoder tab: decoded image on the left, live waterfall of the SSTV audio band (1200–2300 Hz) on the right, with a draggable splitter between the two so you can rebalance their sizes. A thin status strip at the bottom shows detected mode, current line, and progress.
- Select SSTV from the decoder mode dropdown
- Tune to a known SSTV frequency (e.g., 14.230 MHz USB on 20 m)
- The decoder auto-detects the mode from the VIS header and renders the image line-by-line alongside the waterfall
- For weak signals where VIS detection fails, pick a Forced Mode (e.g.,
Robot36). ChooseAUTOto return to detection. - Right-click the image for Save / Clear / “Expand to Window” (the last opens a detachable full-size decoder window with the same layout).
- Clients that connect mid-decode receive a catch-up stream so their display syncs with the server.
Supported modes (20 total): Robot 36 / 72 / 8BW / 24BW, Martin M1 / M2, Scottie S1 / S2 / DX, PD 90 / 120 / 160 / 180 / 240 / 290, Wraase SC2-120 / SC2-180, Pasokon P3 / P5 / P7. (PD50 also decodes when auto-detected from the VIS header, but is not offered in the forced-mode picker. Transmit covers 19: the Robot BW modes are receive-only.)
FT8 / FT4 (via WSJT-X)
The server does not decode FT8/FT4 directly. It listens on UDP port 2237 for decode messages from an WSJT-X instance running on the same machine, and forwards each decode to connected clients.
- Run WSJT-X configured for your radio as usual
- In WSJT-X: File → Settings → Reporting → enable UDP Server on port
2237 - On the server, select FT8/FT4 from the decoder dropdown
- Decodes (time, SNR, DT, Δf, message) appear in the list and are broadcast to clients with SNR-based color coding
WEFAX Decoder (Weather Facsimile)
Receives grayscale weather charts on HF marine bands. The WEFAX panel uses the same split layout as SSTV: image on the left, live waterfall of the WEFAX audio band on the right, draggable splitter, status strip showing line / progress at the bottom. Slant / shift sliders correct any residual alignment drift.
- Select WEFAX from the decoder dropdown
- Tune to a known WEFAX broadcast (e.g. NOAA: 4346 / 8503.9 / 12789.9 kHz USB; DWD Hamburg: 3855 / 7880 / 13882.5 kHz USB)
- The decoder runs a phasing-lock detector first: looks for the white phasing pulse pattern that precedes the image and aligns the line phase from it. Mid-stream joins fall back to the legacy fold/cluster sync path automatically.
- Use the slant / shift sliders on noisy captures with broadcaster clock drift
- Save / Clear / Expand to Window via the toolbar or right-click on the image
NAVTEX Decoder (Maritime Safety)
Receives NAVTEX maritime safety broadcasts on 490 / 518 / 4209.5 kHz. The decoder implements the SITOR-B forward error correction protocol (CCIR 476, 100 baud, 170 Hz shift).
- Select NAVTEX from the decoder dropdown
- Tune to a NAVTEX broadcast frequency (e.g. 518 kHz for international English, 490 kHz for national language)
- Decoded characters appear in the text display and stream to all connected clients
APRS Decoder (Packet Radio)
Decodes AX.25 1200 baud Bell 202 AFSK packets. Displays callsign, position, and message data from APRS beacons.
- Select APRS from the decoder dropdown
- Tune to 144.390 MHz (North America) or 144.800 MHz (Europe/most regions) on FM
- Decoded packets appear as one-line summaries showing source callsign, position coordinates, and beacon text
WSPR (via WSJT-X)
Weak-signal propagation spots relayed from a co-located WSJT-X running in WSPR mode, over the same UDP port 2237 that carries FT8. Each spot is enriched on the server with the DXCC country plus the distance and bearing from your grid square, so no client has to do lookups of its own.
- Run WSJT-X in WSPR mode, with File → Settings → Reporting → UDP Server enabled on port
2237 - On the server, select WSPR from the decoder dropdown
- Spots (time, SNR, drift, frequency, callsign, grid, power, distance, bearing, country) appear in the list and stream to every client
- The last 100 spots replay when a client subscribes, so a client that joins late still sees the recent picture
Spots also draw greyline paths on the map (transmitter at the spot’s grid, receiver at your QTH) and can fire a webhook for watch-list callsigns or a new DXCC this run. The webhook is off by default.
⚠️ One WSJT-X instance decodes either FT8 or WSPR
A single WSJT-X does one or the other, never both at once. To run WSPR alongside FT8, start a second instance with --rig-name; ShackLink tracks the two separately. Like FT8, WSPR is a bridged mode, so it cannot be assigned to an individual SDR slot.
JS8 (via JS8Call)
Keyboard-to-keyboard JS8 traffic bridged from a running JS8Call instance over its TCP API (default 127.0.0.1:2442). ShackLink mirrors JS8Call’s state rather than decoding the audio itself.
- Run JS8Call and enable Settings → Reporting → TCP Server API. Without it there is nothing for ShackLink to connect to.
- On the server, select JS8 from the decoder dropdown. The host and port are settings, if you moved JS8Call off its defaults.
- Directed messages arrive DXCC-enriched, with the last 50 replayed when a client subscribes. Traffic addressed to your callsign is highlighted and can fire a webhook.
- Band activity shows raw frames as they land (often fragments, mid-word) rendered as-is rather than parsed
- Spots, the station’s identity, and the current speed (normal / fast / turbo / slow) mirror alongside
- Transmit: type a message and ShackLink queues it for JS8Call’s next cycle
⚠️ JS8Call owns its own keying
JS8 transmit is not one of the TX-mode picks: it queues through the bridge. While JS8Call keys the rig, ShackLink’s own transmit paths refuse with TX:LOCKED:JS8CALL. That is an advisory lock inside ShackLink, not a hardware interlock. JS8 is a bridged mode, so it cannot be assigned to an individual SDR slot.
Olivia / Contestia Decoder
A native MFSK decoder: no external program needed. Tone sets run from 4 to 64 tones across 125–2000 Hz of bandwidth, with 8/250, 16/500 and 32/1000 the common on-air presets. Contestia is a family setting inside this mode, not a separate mode. Transmit is supported as well.
- Select Olivia/Contestia from the decoder dropdown
- Pick the family (Olivia or Contestia) and the format (tones / bandwidth) to match the signal
- Set the center frequency onto the signal, or click it straight off the audio waterfall (see Tuning from the Waterfall above)
- Leave Squelch at its default of 3 unless you have a specific reason not to (see below)
- Decoded text appears in the display and streams to clients
⚠️ Squelch is a sync-confidence threshold, not an audio level
This is the setting that catches people out. Olivia’s Squelch is a sync-confidence threshold, not an audio level. The default (3) is junk-free: it will not print garbage when the signal drops. Setting it to 1 turns it off, which buys roughly 2 dB more sensitivity but prints junk on sync loss. 10 only decodes solid signals.
Measured sensitivity, strict full-text decode, AWGN, 2.5 kHz reference:
| Format | Default squelch 3 | Squelch 1 (off) |
|---|---|---|
| 8/250 | −14 dB | −16 dB |
| 16/500 | −12 dB | −14 dB |
| 32/1000 | −12 dB | −14 dB |
| Contestia | −12 dB | −12 dB |
Image TX (SSTV + WEFAX)
The TX tab supports sending images directly from the server (or any client). When you switch the TX-mode picker to SSTV or WEFAX, the chat panel swaps in an ImageTxPanel:
- Pick mode (SSTV: 18 sub-modes; WEFAX: IOC 576/288, LPM 60/120)
- Choose Image: the panel resamples and shows a preview
- Click Send: the encoder runs, PTT keys via OmniRig, the live build-up appears in the preview as the encoder transmits
- Test (no RF) mode: encoder runs but PTT stays low, for offline rehearsal. A WAV is saved next to the source image automatically.
- Non-transmitting clients see
TX:STATUSandTX:PROGRESSso they can follow the line counter
From a remote client (web / mobile), the image is uploaded chunked over the WebSocket binary channel 0x04, SHA-256 verified, then staged server-side (per-client cap of 4, 10-min idle GC, 5 MB max). After staging, TX:KEY:SSTV:<imageId>:<mode> or TX:KEY:WEFAX:<imageId>:<ioc>:<lpm> kicks off the encoder.
💡 Why Server-Side Decoding?
Server-side decoding is more accurate than client-side because it processes the original audio without network jitter artifacts. CW works reliably at speeds up to 40+ WPM, RTTY auto-detects standard amateur radio parameters, PSK31 tracks drifting signals with AFC, and SSTV catches every image in full resolution.
Saving Decoded Text
Click the Save… button to save decoded text to a file. The default filename includes the decoder mode (cw/rtty/psk31) and timestamp. SSTV images can be saved via the Save button above the split, by right-clicking the image, or from the detached “Expand to Window” view.
📍 Band Plan (Frequency Table)
Built-in searchable reference of amateur allocations and common operating frequencies.
Band Plan embedded in the tab area
Popped out to its own window alongside the main UI
Click Freq. Table in the Audio Streaming panel to open the Band Plan window. It stays open alongside the main UI so you can hop around the band quickly.
Using the Band Plan
- Filter by band category (HF, VHF, UHF) and by mode with the quick-filter buttons
- Search by frequency, band name, or description
- Select a row and click Tune (or double-click) to set the radio to that frequency and mode
- The current row auto-highlights as the radio frequency changes
- Calling frequencies are visually distinguished
🛠 Tools & Dashboards
Additional server-side tools accessible from the Tools tab.
The Tools tab: dashboard launchers, integration settings, Security, Colors, and the tooltips toggle
Custom Colors
Click the Colors button on the Tools tab to open a color customization dialog. Personalize the frequency display, meters, background, accent colors, and other UI elements. Changes are saved and restored between sessions. Beyond individual accents, several complete color themes re-tint the whole window in one click from the Colors dialog or the title-bar Theme menu.
Color Settings: 19 accent colors in five groups, previewed live
Neon theme
Green theme
Plasma theme
Theme Submenu (Title Bar)
A Theme submenu is added to the window’s title-bar system menu on both the server and the desktop client, so you can pick a color theme straight from the system menu without opening the full Colors dialog.
Photo Panel (Right-Click Modes)
The panel beside the callsign strip is no longer a static photo. Right-click it to cycle its modes: Photo (the operator’s picture), Audio Visualization (live spectrum / waterfall / scope), Knob (a Freq-Knob rotary VFO dial), SDR Spectrum (a full spectrum-and-waterfall view of the slot you are listening to, with the SDR tab’s own right-click menu), Propagation (live solar data), Signal Alerts (the threshold monitor), Decoder (a display-only mirror of the current decoder’s output), and Greyline (a day/night terminator map). The selected mode is saved between sessions. The desktop client shares the panel and the Knob mode.
Audio Visualization mode
Knob mode: rotary VFO dial with monitor knobs
Propagation mode: live solar data
Decoder mode: mirror of the active decoder
Greyline mode: day/night terminator map (the Photo mode default is shown at the top of this page)
Tooltips Toggle
Toggle Show Tooltips on the Tools tab to enable or disable hover tooltips across all controls. Useful for learning the UI, then turning them off once familiar. Main form uses ApplyTooltips(); separate dialogs have their own ToolTip instances with dark-themed custom draw.
Broadcast Guide
A searchable station database covering shortwave broadcasts (EiBi + HFCC), local FM and AM stations (FCC, filtered by operator location), and NOAA weather channels. Quick-select band buttons span LW through 11 m plus FM and WX. Filter by frequency range, country, language, source, or station name. The On Now toggle shows only stations currently broadcasting based on UTC schedule. Track VFO auto-filters to the rig’s current frequency. Double-click any row to tune the radio (sets both frequency and mode). All filter settings persist between sessions. Available on both server and desktop client.
Broadcast Guide: shortwave / FM / AM / NOAA station database with band buttons, On Now filtering, and click-to-tune
Dashboards & Popouts
The Tools tab also launches a set of standalone operations dashboards, each in its own window for multi-monitor use:
- Propagation: live solar data from hamqsl.com (solar flux, A/K indices, band conditions).
- Greyline Map: day/night terminator showing where HF propagation peaks, with your logged contacts plotted as callsign chips and great-circle arcs to your QTH.
- Band Activity: aggregated DX-cluster and FT8 activity across the bands.
- Signal Alerts: frequency / threshold / duration rules that fire Discord and Telegram webhooks or auto-record.
- Logbook (ADIF): built-in ADIF logbook viewer with search, sort, and DXCC country enrichment. Two-way QRZ.com sync (Tools tab → QRZ Logbook, needs a QRZ XML subscription and a per-logbook API key) uploads new QSOs and downloads QRZ’s, with auto-upload and a manual Sync Now.
- Spectrum Snapshots: a gallery of captured waterfall snapshots.
Greyline Map: day/night terminator with operator location
A later moment as the terminator sweeps across
Callsign Strip & UTC Clock
The callsign strip shows the operator callsign next to an NTP-synced UTC clock (shared by server and desktop client), with configurable layout, font, and colors. The same NTP-synced UTC clock also appears in the server and client window titles.
Rotary Frequency Knob & Memories
The frequency-entry popup is resizeable and includes a Freq-Knob rotary dial: an endless VFO knob with per-digit stepping and flywheel spin, the same shared SkiaSharp knob library that powers the photo panel’s Knob mode. Twenty-four memory presets (two pages of twelve) store frequency, mode, and a label, and open in an All Memories list for quick recall.
Frequency entry: keypad plus the rotary Freq-Knob for per-digit tuning
All Memories: all 48 channels as a resizable tile grid, click to recall, right-click to store / label / clear
Waterfall Painter (Spectrum Art)
The Waterfall Painter rasterizes text, an image, vector primitives, or an animation into audio tones across an SSB passband, so each tone lights one pixel column on a receiver’s waterfall: “waterfall art” drawn straight into the spectrum. Rehearse silently by painting into the Test Tone synth slot (every client sees it on the SDR stream), then transmit one-shot on air through the TX engine. It is SSB-only by physics: the sideband auto-follows the rig and there is deliberately no AM/FM (FM would smear the art).
The Waterfall Painter window: source, gamma, and passband controls
Rasterizing text into the passband
The art as received on the 2D waterfall
The same received art on the 3D terrain waterfall
Another camera angle on the received 3D art
Band Skimmer (Multi-Signal Decode)
A CW-Skimmer-style wideband decoder on the Tools tab. Instead of listening to one signal, it decodes every signal of a mode across a whole band segment at once (one decode lane per signal) off the raw I/Q of an SDR slot you already have running, and extracts callsigns into a live spot list. Point it at a slot, pick a CW band-plan preset or type a from/to range, choose a mode (CW, RTTY, PSK31 / PSK63, Olivia / Contestia, or Mixed, which classifies each signal and attaches the right decoder per lane), and hit Start. Because it taps the I/Q, it runs alongside the slot’s normal decoder and never touches the audio you’re listening to.
Confirmed callsigns show up as amber chips on the SDR waterfall (hover card + click-to-tune), spots feed the Band Activity dashboard and a session CSV, a watch-list callsign can fire a Discord / Telegram webhook, and stations you’ve worked before on the same band (from your ADIF log) are dimmed. The skimmer is server-owned, but the desktop, web, and mobile clients all show a live view console of the running skim: the same lanes, spots, and chips. CW copies best around 10–45 WPM; signals closer than ~50–75 Hz merge into one lane; bridge modes (FT8 / WSPR / JS8) are never skimmed since WSJT-X and JS8Call already decode their own passband.
🔄 Device Sync (Sync Tab)
Link rigs and SDR slots together so frequency and/or mode changes on one push through to another.
The Sync tab: four rig tiles and eight SDR slot tiles wired with rule arrows (amber dashed = automatic Track Rig)
The Sync tab lets you wire up rules between equivalent devices: OmniRig’s four rigs and the eight SDR slots (rig→rig, rig→slot, slot→rig, slot→slot). Useful for transverters (source on IF frequency, target on RF with a fixed offset), dual-radio diversity setups, a monitoring receiver or panadapter that should always track the main rig, or making one SDR’s Lab trace follow another. For rigs a rule reads/writes VFO-A; for SDR slots it reads/writes the slot’s LO / center frequency (in-span demod retunes don’t fire rules).
Creating a Rule
- Open the Sync tab: you’ll see four rig tiles (Rig 1 – Rig 4) and eight SDR slot tiles (S0 – S7, empty slots dimmed)
- Drag between any two tiles. An arrow appears representing the rule.
- Click the arrow to select it. The rule’s properties appear on the right.
- Build chains by adding more rules (Rig 1 → Rig 2 → Slot 3): a change at the head applies to every hop in one pass. Bidirectional pairs and accidental cycles are safe: each device is written at most once per change.
Per-Rule Properties
- Offset: Frequency offset (MHz) added to the source before writing to the target. Can be negative. Typical use: transverter IF offset.
- Invert Sideband: USB↔LSB, CW-U↔CW-L, DIG-U↔DIG-L. Applied when Sync Mode is on.
- Sync Frequency: Copy source frequency (+ Offset) to target (rig VFO or slot LO).
- Sync Mode: Copy source mode (optionally inverted) to target. Rig→slot maps onto the slot demodulator; slot→rig maps the demod mode back.
- Enabled: Per-rule on/off, disables without deleting.
Automatic Rules
SDR slots with Track Rig on show an amber dashed AUTO arrow from the currently selected rig, the rig-tracking mechanism made visible. Auto rules are read-only; deleting one turns Track Rig off for that slot. Slot tiles carry AUD (audio-active), TRK (Track Rig) and IF (IF-mode panadapter, LO pinned) badges.
Global Enable + Logic
The Enable Sync toggle at the top right is a master kill switch for the whole engine. For a change on the source device to propagate to target, three conditions must all be true:
- Global Enable Sync = on
- Per-rule Enabled = on
- At least one of Sync Frequency / Sync Mode = on
The engine separates genuine changes from its own echoes by value (a device reporting back the value just written to it is ignored), rate-limits each rule to ~3 writes/s, and cuts rule cycles deterministically (each device written at most once per change). Rules targeting a rig-tracking or IF-locked slot are skipped (those mechanisms own that slot’s LO); a tracked slot’s machinery moves don’t fire its outgoing rules. Manual moves do. All rule data (offsets, toggles, enabled states, global enable) is saved automatically on every change and restored on the next run.
📋 System Requirements
What you need to run ShackLink Server and clients.
🖥 Server Computer
- ✓ Windows 7/8/10/11
- ✓ .NET Framework 4.7.2+
- ✓ OmniRig v2.0 or later installed (hb9ryz.ch/omnirig)
- ✓ Sound card (for audio)
- ✓ Network connection
💻 Desktop Client
- ✓ Windows 7/8/10/11
- ✓ .NET Framework 4.7.2+
- ✓ Network to server
- ✓ Audio output device
🌐 Web Client
- ✓ Chrome 66+ / Firefox 76+
- ✓ Safari 14.1+ / Edge 79+
- ✓ Network to server
- ✓ Any OS supported
🏠 Home Assistant
- ✓ HA 2021.12 or newer
- ✓ Network to port 8084
- ✓ Lovelace dashboard
📱 Cross-Platform App
- ✓ Windows 10+, iOS 14+, Android 8+
- ✓ Network to port 8080
- ✓ WiFi recommended
📻 Radio Equipment
- ✓ OmniRig-supported radio
- ✓ CAT interface
- ✓ Audio cables (optional)
🔧 Troubleshooting
OmniRig Won’t Connect
- Check if OmniRig is running and configured properly
- Verify COM port settings match your radio
- Restart OmniRig and the server application
Clients Cannot Connect
- Verify the server is running and accessible
- Check firewall allows ports 8080, 8081, 8082, 8084, 8085 (and UDP 8081 for service discovery). Tools → Configure Firewall does this for you
- Ensure client has correct server IP address
- Try pinging the server IP from the client machine
No Audio
- Select correct audio input device on server
- Check sound card levels in Windows Mixer
- Verify audio cables are connected
- Ensure audio streaming is started on server
- Check client volume is not muted
Digital Decoder Not Working
- Enable the decoder checkbox on server
- For CW: Adjust decoder mode (Speed/Accuracy) based on signal conditions
- For RTTY: Ensure the signal uses standard amateur radio parameters (45.45/50 baud, 170/425/850 Hz shift)
- Ensure audio streaming is active
- Check audio levels (too quiet or too loud affects decoding)
- Monitor the signal scope and quality indicators