Go-based FM stereo transmitter with RDS, Windows-first and cross-platform
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
Jan Svabenik 38a6cf3d70 Make runtime indicator drop stale late alerts 1ヶ月前
cmd feat: add runtime health alert 1ヶ月前
docs Make runtime indicator drop stale late alerts 1ヶ月前
examples Add output backend abstractions 1ヶ月前
internal Make runtime indicator drop stale late alerts 1ヶ月前
libiio feat: add hardware TX mode with PlutoSDR and SoapySDR drivers 1ヶ月前
scripts feat: add Linux PlutoSDR support and Orange Pi build tooling 1ヶ月前
.gitignore feat: add driver/uri/deviceArgs backend config plumbing 1ヶ月前
CHANGELOG.md docs: mark current hardware baseline as v0.7.0-pre 1ヶ月前
PROJECT_PLAN.md docs: switch plan to windows-first and soapy-first 1ヶ月前
README.md docs: polish README structure and control-plane notes 1ヶ月前
RELEASE.md docs: mark current hardware baseline as v0.7.0-pre 1ヶ月前
fm-rds-tx_pro_runtime_hardening_concept.json docs: add pro runtime hardening concept 1ヶ月前
go.mod feat: add pre-emphasis, MPX limiter and FM IQ modulation DSP blocks 1ヶ月前
stream_tx.bat config: switch stream_tx.bat to svabi.ch source 1ヶ月前

README.md

fm-rds-tx

Go-based FM stereo transmitter with RDS. Supports ADALM-Pluto (PlutoSDR) and SoapySDR-compatible TX devices.

Status

Current status: v0.7.0-pre — hardware bring-up milestone

What is already in place:

  • complete DSP chain: audio -> pre-emphasis -> stereo encoding -> RDS -> MPX -> limiter -> FM modulation
  • real hardware TX paths for PlutoSDR / SoapySDR backends
  • continuous TX engine with runtime telemetry
  • dry-run, offline generation, and simulated TX modes
  • HTTP control plane with live config patching and runtime/status endpoints
  • browser UI on /
  • live audio ingestion via stdin or HTTP stream input

Current engineering focus:

  • deterministic runtime behavior
  • fault handling / recovery
  • observability and runtime telemetry
  • hardware-validated signal quality

For the active runtime-hardening track, see:

  • docs/pro-runtime-hardening-workboard.md

Signal path

Audio Source -> PreEmphasis(50us/75us/off) -> StereoEncoder(19k + 38k DSB-SC)
-> RDS(57k BPSK) -> MPX Combiner -> Limiter -> FM Modulator(+/-75kHz)
-> optional split-rate FM upsampling -> SDR backend -> RF output

For deeper DSP details, see:

  • docs/DSP-CHAIN.md

Prerequisites

Go

  • Go version from go.mod (currently Go 1.22)

Native SDR dependencies

Depending on backend, native libraries are required:

  • SoapySDR backend

    • build with -tags soapy
    • requires SoapySDR native library (SoapySDR.dll / libSoapySDR.so / libSoapySDR.dylib)
    • on Windows, PothosSDR is the expected setup
  • Pluto backend

    • uses native libiio
    • Windows expects libiio.dll
    • Linux build/runtime expects pkg-config + libiio
  • validate RF output, deviation, filtering, and power with proper measurement equipment
  • use only within applicable legal and regulatory constraints

Quick start

Build

# Build CLI tools without hardware-specific build tags:
go build ./cmd/fmrtx
go build ./cmd/offline

# Build fmrtx with SoapySDR support:
go build -tags soapy ./cmd/fmrtx

Quick verification

# Print effective config
go run ./cmd/fmrtx -print-config

# Run tests
go test ./...

# Basic dry-run summary
go run ./cmd/fmrtx --dry-run --dry-output build/dryrun/frame.json

For additional build/test commands, see:

  • docs/README.md

Common usage flows

1) List available SDR devices

.\fmrtx.exe --list-devices

2) Dry-run / config verification

.\fmrtx.exe --dry-run --dry-output build/dryrun/frame.json

# Write dry-run JSON to stdout
.\fmrtx.exe --dry-run --dry-output -

3) Offline IQ/composite generation

go run ./cmd/offline -duration 2s -output build/offline/composite.iqf32

# Optional output rate override
go run ./cmd/offline -duration 500ms -output build/offline/composite.iqf32 -output-rate 228000

4) Simulated transmit path

go run ./cmd/fmrtx --simulate-tx --simulate-output build/sim/simulated-soapy.iqf32 --simulate-duration 250ms

5) Real TX with config file

# Start TX service with manual start over HTTP
.\fmrtx.exe --tx --config docs/config.plutosdr.json

# Start and begin transmitting immediately
.\fmrtx.exe --tx --tx-auto-start --config docs/config.plutosdr.json

6) Live audio via stdin

ffmpeg -i "http://svabi.ch:8443/stream" -f s16le -ar 44100 -ac 2 - | .\fmrtx.exe --tx --tx-auto-start --audio-stdin --config docs/config.plutosdr.json

7) Custom audio input rate

ffmpeg -i source.wav -f s16le -ar 48000 -ac 2 - | .\fmrtx.exe --tx --tx-auto-start --audio-stdin --audio-rate 48000 --config docs/config.plutosdr.json

CLI overview

fmrtx

Important runtime modes and flags include:

  • --tx
  • --tx-auto-start
  • --dry-run
  • --dry-output <path|- >
  • --simulate-tx
  • --simulate-output <path>
  • --simulate-duration <duration>
  • --config <path>
  • --print-config
  • --list-devices
  • --audio-stdin
  • --audio-rate <hz>

offline

Useful flags include:

  • -duration <duration>
  • -output <path>
  • -output-rate <hz>

If the README is too high-level for the exact CLI surface, check:

  • cmd/fmrtx/main.go
  • cmd/offline/main.go

HTTP control plane

Base URL: http://{listenAddress} (default typically 127.0.0.1:8088)

Security note:

  • keep the control plane bound locally unless you intentionally place it behind a trusted and hardened access layer

Main endpoints

GET  /              browser UI
GET  /healthz       health check
GET  /status        current config/status snapshot
GET  /runtime       live engine / driver / audio telemetry
GET  /config        full config
POST /config        patch config / live updates
GET  /dry-run       synthetic frame summary
POST /tx/start      start transmission
POST /tx/stop       stop transmission
POST /audio/stream  push raw S16LE stereo PCM into live stream buffer

What the control plane covers

  • TX start / stop
  • runtime status and driver telemetry
  • config inspection
  • live patching of selected parameters
  • dry-run inspection
  • browser-accessible control UI
  • optional HTTP audio ingest

Live config notes

POST /config supports live updates for selected fields such as:

  • frequency
  • stereo enable/disable
  • pilot / RDS injection levels
  • RDS enable/disable
  • limiter settings
  • PS / RadioText

Some parameters are saved but not live-applied and require restart.

For the full API contract, examples, live-patch semantics, and /audio/stream details, see:

  • docs/API.md

Configuration

Sample configs:

  • docs/config.sample.json
  • docs/config.plutosdr.json
  • docs/config.orangepi-pluto-soapy.json

Important config areas include:

  • fm.*
  • rds.*
  • audio.*
  • backend.*
  • control.*

Examples of relevant fields you may want to inspect:

  • fm.outputDrive
  • fm.mpxGain
  • fm.bs412Enabled
  • fm.bs412ThresholdDBr
  • fm.fmModulationEnabled
  • backend.kind
  • backend.driver
  • backend.deviceArgs
  • backend.uri
  • backend.deviceSampleRateHz
  • backend.outputPath
  • control.listenAddress

For deeper config/API behavior, refer to:

  • internal/config/config.go
  • docs/API.md
  • docs/config.sample.json

Development and testing

Useful commands:

go test ./...
go run ./cmd/fmrtx -print-config
go run ./cmd/fmrtx -config docs/config.sample.json
go run ./cmd/fmrtx --dry-run --dry-output build/dryrun/frame.json
go run ./cmd/fmrtx --simulate-tx --simulate-output build/sim/simulated-soapy.iqf32 --simulate-duration 250ms
go run ./cmd/offline -duration 500ms -output build/offline/composite.iqf32

See also:

  • docs/README.md

PlutoSDR / backend notes

  • PlutoSDR commonly runs with a device-side sample rate above composite rate, so split-rate mode may be used automatically
  • SoapySDR backend is suitable for Soapy-compatible TX hardware
  • backend/device settings are selected through config rather than hardcoded paths
  • runtime telemetry should be used to inspect effective TX state during operation

Repository layout

cmd/
  fmrtx/                     main CLI
  offline/                   offline generator
internal/
  app/                       TX engine + runtime state
  audio/                     audio input, resampling, tone generation, stream buffering
  config/                    config schema and validation
  control/                   HTTP control plane + browser UI
  dryrun/                    dry-run JSON summaries
  dsp/                       DSP primitives
  mpx/                       MPX combiner
  offline/                   full offline composite generation
  output/                    output/backend abstractions
  platform/                  backend abstractions and device/runtime stats
  platform/soapysdr/         CGO SoapySDR binding
  platform/plutosdr/         Pluto/libiio backend code
  rds/                       RDS encoder
  stereo/                    stereo encoder
docs/
  API.md
  DSP-CHAIN.md
  README.md
  config.sample.json
  config.plutosdr.json
  config.orangepi-pluto-soapy.json
  pro-runtime-hardening-workboard.md
scripts/
examples/

Planning / workboard

For the current runtime-hardening / professionalization track, see:

  • docs/pro-runtime-hardening-workboard.md

This is the living workboard for:

  • status tracking
  • confirmed findings
  • open technical decisions
  • verification notes
  • implementation progress

Release / project docs

Additional project docs:

  • CHANGELOG.md
  • RELEASE.md
  • docs/README.md
  • docs/API.md
  • docs/DSP-CHAIN.md
  • docs/NOTES.md

This project is intended only for lawful use within relevant license and regulatory constraints. RF output, deviation, filtering, and transmitted power must be validated with proper measurement equipment.