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,
})
}