Introduce an optional ITU-R BS.412 MPX power limiter, tighten the low-pass/notch filter design around the protected composite path, and document the full DSP architecture and recommended Pluto configuration in detail.
Rework the DSP chain to a clip-filter-clip architecture with cascaded 14 kHz low-pass stages, double 19/57 kHz protection notches, fixed pilot/RDS injection semantics, and explicit MPX gain calibration support. Update config defaults and tests to match the new broadcast-style modulation budgeting and protected composite path.
Upgrade the audio path to a broadcast-style chain with a 4th-order 15 kHz low-pass, 19 kHz pilot notch, audio-only composite clipping, and post-clip protection notches at 19/57 kHz before adding clean pilot and RDS carriers. This reorders the processing so pilot and RDS stay fixed and unclipped while audio dynamics are constrained within the available modulation budget.
Add a lock-free stdin PCM ingest path, streaming resampler, stereo-linked limiting and pre-MPX audio filtering, plus the engine/control wiring needed to drive live audio into TX mode. Also document the ingest API and include a helper batch script for piping ffmpeg audio into fmrtx.
Embed a browser-based control surface into the HTTP server and document the live-control API. The new UI exposes TX start/stop, runtime telemetry, frequency, levels, toggles, and RDS text updates against the existing live-config endpoints.
Cache altvoltage1 during Configure(), clear it in cleanup(), and use the cached channel for Tune() instead of calling findChannel on every retune. Tune() now checks the direct iio_channel_attr_write_longlong return code and reports LO write failures back to the caller with the failing frequency and libiio error code.
All major TX parameters are now hot-swappable during transmission:
- DSP params (drive, stereo, pilot, RDS levels, limiter) via
atomic.Pointer[LiveParams], loaded once per chunk (~50ms)
- RDS text (PS, RT) via atomic.Value in encoder, applied at
RDS group boundaries (~88ms)
- TX frequency via driver.Tune(), applied between chunks
Zero locks in DSP path. HTTP handler writes atomics, run loop
reads them. Validation happens before store.
New: SoapyDriver.Tune() for live frequency changes.
New: LiveConfigUpdate/LivePatch types for type-safe patching.
New: 4 engine tests for live DSP/freq/RDS updates + validation.