From df1bbf8f5bd1b50621cfb295b2f7d4b4a5a54dd2 Mon Sep 17 00:00:00 2001 From: Stan Grams Date: Sat, 28 Feb 2026 22:01:17 +0100 Subject: [PATCH] [fix](trx-rs): remove wfm denoise and default stereo audio Co-authored-by: Codex Signed-off-by: Stan Grams --- .../trx-frontend-http/assets/web/app.js | 13 ---- .../trx-frontend-http/assets/web/index.html | 3 - .../trx-frontend/trx-frontend-http/src/api.rs | 16 ---- src/trx-core/src/rig/command.rs | 1 - src/trx-core/src/rig/controller/handlers.rs | 1 - src/trx-core/src/rig/mod.rs | 10 --- src/trx-core/src/rig/state.rs | 6 -- src/trx-protocol/src/codec.rs | 2 - src/trx-protocol/src/mapping.rs | 2 - src/trx-protocol/src/types.rs | 1 - src/trx-server/src/config.rs | 2 +- src/trx-server/src/rig_task.rs | 10 --- .../trx-backend-soapysdr/src/demod.rs | 73 +------------------ .../trx-backend-soapysdr/src/dsp.rs | 15 ---- .../trx-backend-soapysdr/src/lib.rs | 18 ----- 15 files changed, 4 insertions(+), 169 deletions(-) diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js index bbc8b3c..026e451 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js +++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/app.js @@ -1259,12 +1259,6 @@ function render(update) { saveSetting("wfmAudioMode", nextMode); } } - if (wfmDenoiseBtn && typeof update.filter.wfm_denoise === "boolean") { - const on = update.filter.wfm_denoise; - wfmDenoiseBtn.textContent = on ? "On" : "Off"; - wfmDenoiseBtn.style.borderColor = on ? "" : "var(--accent-warn, #f0a500)"; - wfmDenoiseBtn.style.color = on ? "" : "var(--accent-warn, #f0a500)"; - } if (wfmStFlagEl && typeof update.filter.wfm_stereo_detected === "boolean") { const detected = update.filter.wfm_stereo_detected; wfmStFlagEl.textContent = detected ? "ST" : "MO"; @@ -2566,7 +2560,6 @@ const wfmControlsCol = document.getElementById("wfm-controls-col"); const wfmDeemphasisEl = document.getElementById("wfm-deemphasis"); const wfmAudioModeEl = document.getElementById("wfm-audio-mode"); const wfmStFlagEl = document.getElementById("wfm-st-flag"); -const wfmDenoiseBtn = document.getElementById("wfm-denoise-btn"); // Hide audio row if audio is not configured on the server fetch("/audio", { method: "GET" }).then((r) => { @@ -2610,12 +2603,6 @@ if (wfmDeemphasisEl) { postPath(`/set_wfm_deemphasis?us=${encodeURIComponent(wfmDeemphasisEl.value)}`).catch(() => {}); }); } -if (wfmDenoiseBtn) { - wfmDenoiseBtn.addEventListener("click", () => { - postPath("/toggle_wfm_denoise").catch(() => {}); - }); -} - function updateWfmControls() { if (!wfmControlsCol) return; const mode = (modeEl && modeEl.value ? modeEl.value : "").toUpperCase(); diff --git a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html index 0e872e8..c58f93a 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html +++ b/src/trx-client/trx-frontend/trx-frontend-http/assets/web/index.html @@ -168,9 +168,6 @@ -
WFM
diff --git a/src/trx-client/trx-frontend/trx-frontend-http/src/api.rs b/src/trx-client/trx-frontend/trx-frontend-http/src/api.rs index 33580af..67dc8f1 100644 --- a/src/trx-client/trx-frontend/trx-frontend-http/src/api.rs +++ b/src/trx-client/trx-frontend/trx-frontend-http/src/api.rs @@ -499,21 +499,6 @@ pub async fn set_wfm_stereo( send_command(&rig_tx, RigCommand::SetWfmStereo(query.enabled)).await } -#[post("/toggle_wfm_denoise")] -pub async fn toggle_wfm_denoise( - state: web::Data>, - rig_tx: web::Data>, -) -> Result { - let enabled = state - .get_ref() - .borrow() - .filter - .as_ref() - .map(|f| f.wfm_denoise) - .unwrap_or(true); - send_command(&rig_tx, RigCommand::SetWfmDenoise(!enabled)).await -} - #[post("/toggle_aprs_decode")] pub async fn toggle_aprs_decode( state: web::Data>, @@ -727,7 +712,6 @@ pub fn configure(cfg: &mut web::ServiceConfig) { .service(set_fir_taps) .service(set_wfm_deemphasis) .service(set_wfm_stereo) - .service(toggle_wfm_denoise) .service(toggle_aprs_decode) .service(toggle_cw_decode) .service(set_cw_auto) diff --git a/src/trx-core/src/rig/command.rs b/src/trx-core/src/rig/command.rs index fff460d..bc04636 100644 --- a/src/trx-core/src/rig/command.rs +++ b/src/trx-core/src/rig/command.rs @@ -35,6 +35,5 @@ pub enum RigCommand { SetFirTaps(u32), SetWfmDeemphasis(u32), SetWfmStereo(bool), - SetWfmDenoise(bool), GetSpectrum, } diff --git a/src/trx-core/src/rig/controller/handlers.rs b/src/trx-core/src/rig/controller/handlers.rs index cf3adf8..8d5e42b 100644 --- a/src/trx-core/src/rig/controller/handlers.rs +++ b/src/trx-core/src/rig/controller/handlers.rs @@ -518,7 +518,6 @@ pub fn command_from_rig_command(cmd: RigCommand) -> Box { | RigCommand::SetFirTaps(_) | RigCommand::SetWfmDeemphasis(_) | RigCommand::SetWfmStereo(_) - | RigCommand::SetWfmDenoise(_) | RigCommand::GetSpectrum => Box::new(GetSnapshotCommand), } } diff --git a/src/trx-core/src/rig/mod.rs b/src/trx-core/src/rig/mod.rs index 37c4bce..7eb675f 100644 --- a/src/trx-core/src/rig/mod.rs +++ b/src/trx-core/src/rig/mod.rs @@ -165,16 +165,6 @@ pub trait RigCat: Rig + Send { ))) } - fn set_wfm_denoise<'a>( - &'a mut self, - _enabled: bool, - ) -> Pin> + Send + 'a>> { - Box::pin(std::future::ready(Err( - Box::new(response::RigError::not_supported("set_wfm_denoise")) - as Box, - ))) - } - fn set_wfm_stereo<'a>( &'a mut self, _enabled: bool, diff --git a/src/trx-core/src/rig/state.rs b/src/trx-core/src/rig/state.rs index c392957..cc6fa46 100644 --- a/src/trx-core/src/rig/state.rs +++ b/src/trx-core/src/rig/state.rs @@ -273,8 +273,6 @@ pub struct RigFilterState { pub wfm_deemphasis_us: u32, #[serde(default = "default_wfm_stereo")] pub wfm_stereo: bool, - #[serde(default = "default_wfm_denoise")] - pub wfm_denoise: bool, #[serde(default)] pub wfm_stereo_detected: bool, } @@ -283,10 +281,6 @@ fn default_wfm_deemphasis_us() -> u32 { 75 } -fn default_wfm_denoise() -> bool { - true -} - fn default_wfm_stereo() -> bool { true } diff --git a/src/trx-protocol/src/codec.rs b/src/trx-protocol/src/codec.rs index 0eaeb83..c2214e3 100644 --- a/src/trx-protocol/src/codec.rs +++ b/src/trx-protocol/src/codec.rs @@ -299,7 +299,6 @@ mod tests { cw_center_hz: 700, wfm_deemphasis_us: 75, wfm_stereo: true, - wfm_denoise: true, wfm_stereo_detected: false, }), ..minimal_snapshot() @@ -338,7 +337,6 @@ mod tests { cw_center_hz: 700, wfm_deemphasis_us: 50, wfm_stereo: true, - wfm_denoise: true, wfm_stereo_detected: true, }), ..minimal_snapshot() diff --git a/src/trx-protocol/src/mapping.rs b/src/trx-protocol/src/mapping.rs index 2420c28..5ae4530 100644 --- a/src/trx-protocol/src/mapping.rs +++ b/src/trx-protocol/src/mapping.rs @@ -52,7 +52,6 @@ pub fn client_command_to_rig(cmd: ClientCommand) -> RigCommand { RigCommand::SetWfmDeemphasis(deemphasis_us) } ClientCommand::SetWfmStereo { enabled } => RigCommand::SetWfmStereo(enabled), - ClientCommand::SetWfmDenoise { enabled } => RigCommand::SetWfmDenoise(enabled), ClientCommand::GetSpectrum => RigCommand::GetSpectrum, } } @@ -98,7 +97,6 @@ pub fn rig_command_to_client(cmd: RigCommand) -> ClientCommand { ClientCommand::SetWfmDeemphasis { deemphasis_us } } RigCommand::SetWfmStereo(enabled) => ClientCommand::SetWfmStereo { enabled }, - RigCommand::SetWfmDenoise(enabled) => ClientCommand::SetWfmDenoise { enabled }, RigCommand::GetSpectrum => ClientCommand::GetSpectrum, } } diff --git a/src/trx-protocol/src/types.rs b/src/trx-protocol/src/types.rs index 968ba3f..f118b56 100644 --- a/src/trx-protocol/src/types.rs +++ b/src/trx-protocol/src/types.rs @@ -40,7 +40,6 @@ pub enum ClientCommand { SetFirTaps { taps: u32 }, SetWfmDeemphasis { deemphasis_us: u32 }, SetWfmStereo { enabled: bool }, - SetWfmDenoise { enabled: bool }, GetSpectrum, } diff --git a/src/trx-server/src/config.rs b/src/trx-server/src/config.rs index b1c9706..b9874e5 100644 --- a/src/trx-server/src/config.rs +++ b/src/trx-server/src/config.rs @@ -265,7 +265,7 @@ impl Default for AudioConfig { tx_enabled: true, device: None, sample_rate: 48000, - channels: 1, + channels: 2, frame_duration_ms: 20, bitrate_bps: 192000, } diff --git a/src/trx-server/src/rig_task.rs b/src/trx-server/src/rig_task.rs index aae5e15..16da8fd 100644 --- a/src/trx-server/src/rig_task.rs +++ b/src/trx-server/src/rig_task.rs @@ -472,16 +472,6 @@ async fn process_command( let _ = ctx.state_tx.send(ctx.state.clone()); return snapshot_from(ctx.state); } - RigCommand::SetWfmDenoise(enabled) => { - if let Err(e) = ctx.rig.set_wfm_denoise(enabled).await { - return Err(RigError::communication(format!("set_wfm_denoise: {e}"))); - } - if let Some(f) = ctx.state.filter.as_mut() { - f.wfm_denoise = enabled; - } - let _ = ctx.state_tx.send(ctx.state.clone()); - return snapshot_from(ctx.state); - } RigCommand::SetCenterFreq(freq) => { if let Err(e) = ctx.rig.set_center_freq(freq).await { return Err(RigError::communication(format!("set_center_freq: {e}"))); diff --git a/src/trx-server/trx-backend/trx-backend-soapysdr/src/demod.rs b/src/trx-server/trx-backend/trx-backend-soapysdr/src/demod.rs index b95b677..bb39fe0 100644 --- a/src/trx-server/trx-backend/trx-backend-soapysdr/src/demod.rs +++ b/src/trx-server/trx-backend/trx-backend-soapysdr/src/demod.rs @@ -297,52 +297,6 @@ impl BiquadNotch { } } -/// Three-band stereo blend for WFM. -/// -/// Splits the L-R diff signal into three bands at audio rate and applies -/// SNR-dependent blending per band. Weaker pilot → more aggressive noise -/// reduction at higher frequencies while low frequencies retain more stereo. -/// -/// | Band | Frequency | Blend factor | -/// |-----------|-------------|--------------| -/// | Low | 0 – 2 kHz | `blend` | -/// | Mid | 2 – 8 kHz | `blend²` | -/// | High | 8 – 15 kHz | `blend⁴` | -#[derive(Debug, Clone)] -struct MultibandStereoBlend { - /// 2nd-order Butterworth LPF at the low/mid crossover (2 kHz). - lo_lp: BiquadLowPass, - /// 2nd-order Butterworth LPF at the mid/high crossover (8 kHz). - hi_lp: BiquadLowPass, -} - -impl MultibandStereoBlend { - fn new(audio_rate: f32) -> Self { - // Q = 1/√2 ≈ 0.7071 — maximally flat (Butterworth) 2nd-order response. - let q = std::f32::consts::FRAC_1_SQRT_2; - Self { - lo_lp: BiquadLowPass::new(audio_rate, 2_000.0, q), - hi_lp: BiquadLowPass::new(audio_rate, 8_000.0, q), - } - } - - /// Apply multiband blend to a single diff sample. - /// - /// `blend` is the pilot SNR estimate in [0, 1] (0 = mono, 1 = full stereo). - fn process(&mut self, diff: f32, blend: f32) -> f32 { - // Band-split via complementary LPFs. - let lo = self.lo_lp.process(diff); // 0 – 2 kHz - let lo_hi = self.hi_lp.process(diff); // 0 – 8 kHz - let mid = lo_hi - lo; // 2 – 8 kHz - let hi = diff - lo_hi; // 8 – 15 kHz - - let blend2 = blend * blend; - let blend4 = blend2 * blend2; - - lo * blend + mid * blend2 + hi * blend4 - } -} - impl OnePoleLowPass { fn new(sample_rate: f32, cutoff_hz: f32) -> Self { let sr = sample_rate.max(1.0); @@ -414,10 +368,6 @@ pub struct WfmStereoDecoder { deemph_m: Deemphasis, deemph_l: Deemphasis, deemph_r: Deemphasis, - /// Multiband stereo blending applied at audio rate to the L-R diff channel. - diff_denoise: MultibandStereoBlend, - /// Whether multiband stereo denoising is active. - denoise_enabled: bool, /// Smoothed pilot-derived stereo detection strength in [0, 1]. stereo_detect_level: f32, /// Hysteretic pilot-lock result used by the UI. @@ -453,7 +403,6 @@ impl WfmStereoDecoder { output_channels: usize, stereo_enabled: bool, deemphasis_us: u32, - denoise_enabled: bool, ) -> Self { let composite_rate_f = composite_rate.max(1) as f32; let output_phase_inc = audio_rate.max(1) as f64 / composite_rate.max(1) as f64; @@ -487,8 +436,6 @@ impl WfmStereoDecoder { deemph_m: Deemphasis::new(audio_rate.max(1) as f32, deemphasis_us), deemph_l: Deemphasis::new(audio_rate.max(1) as f32, deemphasis_us), deemph_r: Deemphasis::new(audio_rate.max(1) as f32, deemphasis_us), - diff_denoise: MultibandStereoBlend::new(audio_rate.max(1) as f32), - denoise_enabled, stereo_detect_level: 0.0, stereo_detected: false, fm_gain: composite_rate_f / (2.0 * 75_000.0), @@ -601,17 +548,9 @@ impl WfmStereoDecoder { // --- Deemphasis + DC block + output --- if self.output_channels >= 2 && self.stereo_enabled { - // Apply multiband or single-band stereo blend at audio rate. - let diff_denoised = if self.denoise_enabled { - // Multiband: attenuates high-frequency diff more aggressively - // when the pilot is weak, preserving the low-frequency stereo image. - self.diff_denoise.process(diff_i, blend_i) - } else { - // Single-band: uniform blend across all frequencies. - diff_i * blend_i - }; - let left_corr = (sum_i + diff_denoised) * 0.5; - let right_corr = (sum_i - diff_denoised) * 0.5; + let diff = diff_i * blend_i; + let left_corr = (sum_i + diff) * 0.5; + let right_corr = (sum_i - diff) * 0.5; let left = self .dc_l .process(self.pilot_notch_l.process(self.deemph_l.process(left_corr))) @@ -640,10 +579,6 @@ impl WfmStereoDecoder { output } - pub fn set_denoise_enabled(&mut self, enabled: bool) { - self.denoise_enabled = enabled; - } - pub fn set_stereo_enabled(&mut self, enabled: bool) { self.stereo_enabled = enabled; } @@ -987,7 +922,6 @@ mod tests { 2, // stereo output true, // stereo enabled 50, // 50 µs deemphasis - false, // no denoise — test raw separation ); let output = decoder.process_iq(&iq); @@ -1069,7 +1003,6 @@ mod tests { 2, true, 50, - false, ); let output = decoder.process_iq(&iq); diff --git a/src/trx-server/trx-backend/trx-backend-soapysdr/src/dsp.rs b/src/trx-server/trx-backend/trx-backend-soapysdr/src/dsp.rs index 925781f..4910e83 100644 --- a/src/trx-server/trx-backend/trx-backend-soapysdr/src/dsp.rs +++ b/src/trx-server/trx-backend/trx-backend-soapysdr/src/dsp.rs @@ -311,8 +311,6 @@ pub struct ChannelDsp { wfm_deemphasis_us: u32, /// Whether WFM stereo decoding is enabled. wfm_stereo: bool, - /// Whether multiband stereo denoising is enabled for WFM. - wfm_denoise: bool, /// Decimation factor: `sdr_sample_rate / audio_sample_rate`. pub decim_factor: usize, /// Number of PCM channels emitted in each frame. @@ -414,7 +412,6 @@ impl ChannelDsp { self.output_channels, self.wfm_stereo, self.wfm_deemphasis_us, - self.wfm_denoise, )); } } else { @@ -436,7 +433,6 @@ impl ChannelDsp { audio_bandwidth_hz: u32, wfm_deemphasis_us: u32, wfm_stereo: bool, - wfm_denoise: bool, fir_taps: usize, pcm_tx: broadcast::Sender>, ) -> Self { @@ -482,7 +478,6 @@ impl ChannelDsp { fir_taps: taps, wfm_deemphasis_us, wfm_stereo, - wfm_denoise, decim_factor, output_channels, frame_buf: Vec::with_capacity(frame_size + output_channels), @@ -504,7 +499,6 @@ impl ChannelDsp { output_channels, wfm_stereo, wfm_deemphasis_us, - wfm_denoise, )) } else { None @@ -557,13 +551,6 @@ impl ChannelDsp { } } - pub fn set_wfm_denoise(&mut self, enabled: bool) { - self.wfm_denoise = enabled; - if let Some(decoder) = &mut self.wfm_decoder { - decoder.set_denoise_enabled(enabled); - } - } - pub fn rds_data(&self) -> Option { self.wfm_decoder.as_ref().and_then(WfmStereoDecoder::rds_data) } @@ -724,7 +711,6 @@ impl SdrPipeline { frame_duration_ms: u16, wfm_deemphasis_us: u32, wfm_stereo: bool, - wfm_denoise: bool, channels: &[(f64, RigMode, u32, usize)], ) -> Self { const IQ_BROADCAST_CAPACITY: usize = 64; @@ -747,7 +733,6 @@ impl SdrPipeline { audio_bandwidth_hz, wfm_deemphasis_us, wfm_stereo, - wfm_denoise, fir_taps, pcm_tx.clone(), ); diff --git a/src/trx-server/trx-backend/trx-backend-soapysdr/src/lib.rs b/src/trx-server/trx-backend/trx-backend-soapysdr/src/lib.rs index d6b786e..a398a55 100644 --- a/src/trx-server/trx-backend/trx-backend-soapysdr/src/lib.rs +++ b/src/trx-server/trx-backend/trx-backend-soapysdr/src/lib.rs @@ -41,8 +41,6 @@ pub struct SoapySdrRig { wfm_deemphasis_us: u32, /// Whether WFM stereo decode is enabled. wfm_stereo: bool, - /// Whether multiband WFM stereo denoising is enabled. - wfm_denoise: bool, } impl SoapySdrRig { @@ -120,7 +118,6 @@ impl SoapySdrRig { frame_duration_ms, wfm_deemphasis_us, true, // wfm_stereo: enabled by default - true, // wfm_denoise: enabled by default channels, ); @@ -189,7 +186,6 @@ impl SoapySdrRig { retune_cmd, wfm_deemphasis_us, wfm_stereo: true, - wfm_denoise: true, }) } @@ -481,19 +477,6 @@ impl RigCat for SoapySdrRig { }) } - fn set_wfm_denoise<'a>( - &'a mut self, - enabled: bool, - ) -> Pin> + Send + 'a>> { - Box::pin(async move { - self.wfm_denoise = enabled; - if let Some(dsp_arc) = self.pipeline.channel_dsps.get(self.primary_channel_idx) { - dsp_arc.lock().unwrap().set_wfm_denoise(enabled); - } - Ok(()) - }) - } - fn filter_state(&self) -> Option { let wfm_stereo_detected = self .pipeline @@ -507,7 +490,6 @@ impl RigCat for SoapySdrRig { cw_center_hz: 700, wfm_deemphasis_us: self.wfm_deemphasis_us, wfm_stereo: self.wfm_stereo, - wfm_denoise: self.wfm_denoise, wfm_stereo_detected, }) }