[feat](trx-rs): expose WFM stereo denoise toggle in UI
Wire the StereoDenoise processor through the full stack: - Add SetWfmDenoise command variant and RigCat trait method (trx-core) - Add wfm_denoise field to RigFilterState with default true - Add protocol command and bidirectional mapping (trx-protocol) - Add rig_task command handler (trx-server) - Implement set_wfm_denoise in SoapySdrRig backend - Add /set_wfm_denoise API endpoint (trx-frontend-http) - Add denoise checkbox in WFM controls with SSE sync and localStorage persistence Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -1373,6 +1373,12 @@ function render(update) {
|
||||
saveSetting("wfmAudioMode", nextMode);
|
||||
}
|
||||
}
|
||||
if (wfmDenoiseEl && typeof update.filter.wfm_denoise === "boolean") {
|
||||
if (wfmDenoiseEl.checked !== update.filter.wfm_denoise) {
|
||||
wfmDenoiseEl.checked = update.filter.wfm_denoise;
|
||||
saveSetting("wfmDenoise", update.filter.wfm_denoise ? "true" : "false");
|
||||
}
|
||||
}
|
||||
if (wfmStFlagEl && typeof update.filter.wfm_stereo_detected === "boolean") {
|
||||
const detected = update.filter.wfm_stereo_detected;
|
||||
wfmStFlagEl.textContent = detected ? "ST" : "MO";
|
||||
@@ -2680,6 +2686,7 @@ const audioRow = document.getElementById("audio-row");
|
||||
const wfmControlsCol = document.getElementById("wfm-controls-col");
|
||||
const wfmDeemphasisEl = document.getElementById("wfm-deemphasis");
|
||||
const wfmAudioModeEl = document.getElementById("wfm-audio-mode");
|
||||
const wfmDenoiseEl = document.getElementById("wfm-denoise");
|
||||
const sdrGainControlsEl = document.getElementById("sdr-gain-controls");
|
||||
const sdrGainEl = document.getElementById("sdr-gain-db");
|
||||
const sdrGainSetBtn = document.getElementById("sdr-gain-set");
|
||||
@@ -2748,6 +2755,14 @@ if (wfmAudioModeEl) {
|
||||
postPath(`/set_wfm_stereo?enabled=${enabled ? "true" : "false"}`).catch(() => {});
|
||||
});
|
||||
}
|
||||
if (wfmDenoiseEl) {
|
||||
wfmDenoiseEl.checked = loadSetting("wfmDenoise", "true") === "true";
|
||||
wfmDenoiseEl.addEventListener("change", () => {
|
||||
const enabled = wfmDenoiseEl.checked;
|
||||
saveSetting("wfmDenoise", enabled ? "true" : "false");
|
||||
postPath(`/set_wfm_denoise?enabled=${enabled ? "true" : "false"}`).catch(() => {});
|
||||
});
|
||||
}
|
||||
if (wfmDeemphasisEl) {
|
||||
wfmDeemphasisEl.addEventListener("change", () => {
|
||||
postPath(`/set_wfm_deemphasis?us=${encodeURIComponent(wfmDeemphasisEl.value)}`).catch(() => {});
|
||||
|
||||
@@ -172,6 +172,10 @@
|
||||
<option value="mono">Mono</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="wfm-control">
|
||||
<span class="wfm-control-label">Denoise</span>
|
||||
<input type="checkbox" id="wfm-denoise" checked />
|
||||
</label>
|
||||
<div class="wfm-gain-group" id="sdr-gain-controls">
|
||||
<label class="wfm-control">
|
||||
<span class="wfm-control-label">RF Gain</span>
|
||||
|
||||
@@ -522,6 +522,19 @@ pub async fn set_wfm_stereo(
|
||||
send_command(&rig_tx, RigCommand::SetWfmStereo(query.enabled)).await
|
||||
}
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
pub struct WfmDenoiseQuery {
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
#[post("/set_wfm_denoise")]
|
||||
pub async fn set_wfm_denoise(
|
||||
query: web::Query<WfmDenoiseQuery>,
|
||||
rig_tx: web::Data<mpsc::Sender<RigRequest>>,
|
||||
) -> Result<HttpResponse, Error> {
|
||||
send_command(&rig_tx, RigCommand::SetWfmDenoise(query.enabled)).await
|
||||
}
|
||||
|
||||
#[post("/toggle_aprs_decode")]
|
||||
pub async fn toggle_aprs_decode(
|
||||
state: web::Data<watch::Receiver<RigState>>,
|
||||
@@ -736,6 +749,7 @@ pub fn configure(cfg: &mut web::ServiceConfig) {
|
||||
.service(set_sdr_gain)
|
||||
.service(set_wfm_deemphasis)
|
||||
.service(set_wfm_stereo)
|
||||
.service(set_wfm_denoise)
|
||||
.service(toggle_aprs_decode)
|
||||
.service(toggle_cw_decode)
|
||||
.service(set_cw_auto)
|
||||
|
||||
@@ -36,5 +36,6 @@ pub enum RigCommand {
|
||||
SetSdrGain(f64),
|
||||
SetWfmDeemphasis(u32),
|
||||
SetWfmStereo(bool),
|
||||
SetWfmDenoise(bool),
|
||||
GetSpectrum,
|
||||
}
|
||||
|
||||
@@ -519,6 +519,7 @@ pub fn command_from_rig_command(cmd: RigCommand) -> Box<dyn RigCommandHandler> {
|
||||
| RigCommand::SetSdrGain(_)
|
||||
| RigCommand::SetWfmDeemphasis(_)
|
||||
| RigCommand::SetWfmStereo(_)
|
||||
| RigCommand::SetWfmDenoise(_)
|
||||
| RigCommand::GetSpectrum => Box::new(GetSnapshotCommand),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,6 +185,16 @@ pub trait RigCat: Rig + Send {
|
||||
)))
|
||||
}
|
||||
|
||||
fn set_wfm_denoise<'a>(
|
||||
&'a mut self,
|
||||
_enabled: bool,
|
||||
) -> Pin<Box<dyn Future<Output = DynResult<()>> + Send + 'a>> {
|
||||
Box::pin(std::future::ready(Err(
|
||||
Box::new(response::RigError::not_supported("set_wfm_denoise"))
|
||||
as Box<dyn std::error::Error + Send + Sync>,
|
||||
)))
|
||||
}
|
||||
|
||||
/// Return the current filter state if this backend supports filter controls.
|
||||
fn filter_state(&self) -> Option<state::RigFilterState> {
|
||||
None
|
||||
|
||||
@@ -277,6 +277,8 @@ pub struct RigFilterState {
|
||||
pub wfm_stereo: bool,
|
||||
#[serde(default)]
|
||||
pub wfm_stereo_detected: bool,
|
||||
#[serde(default = "default_wfm_denoise")]
|
||||
pub wfm_denoise: bool,
|
||||
}
|
||||
|
||||
fn default_wfm_deemphasis_us() -> u32 {
|
||||
@@ -287,6 +289,10 @@ fn default_wfm_stereo() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn default_wfm_denoise() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Spectrum data from SDR backends (FFT magnitude over the full capture bandwidth).
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SpectrumData {
|
||||
|
||||
@@ -301,6 +301,7 @@ mod tests {
|
||||
wfm_deemphasis_us: 75,
|
||||
wfm_stereo: true,
|
||||
wfm_stereo_detected: false,
|
||||
wfm_denoise: true,
|
||||
}),
|
||||
..minimal_snapshot()
|
||||
})
|
||||
@@ -340,6 +341,7 @@ mod tests {
|
||||
wfm_deemphasis_us: 50,
|
||||
wfm_stereo: true,
|
||||
wfm_stereo_detected: true,
|
||||
wfm_denoise: true,
|
||||
}),
|
||||
..minimal_snapshot()
|
||||
};
|
||||
|
||||
@@ -53,6 +53,7 @@ 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,
|
||||
}
|
||||
}
|
||||
@@ -99,6 +100,7 @@ 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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ pub enum ClientCommand {
|
||||
SetSdrGain { gain_db: f64 },
|
||||
SetWfmDeemphasis { deemphasis_us: u32 },
|
||||
SetWfmStereo { enabled: bool },
|
||||
SetWfmDenoise { enabled: bool },
|
||||
GetSpectrum,
|
||||
}
|
||||
|
||||
|
||||
@@ -480,6 +480,16 @@ 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}")));
|
||||
|
||||
@@ -41,6 +41,8 @@ pub struct SoapySdrRig {
|
||||
wfm_deemphasis_us: u32,
|
||||
/// Whether WFM stereo decode is enabled.
|
||||
wfm_stereo: bool,
|
||||
/// Whether WFM stereo denoise is enabled.
|
||||
wfm_denoise: bool,
|
||||
/// Requested hardware gain setting in dB.
|
||||
gain_db: f64,
|
||||
/// Optional hard ceiling for the applied hardware gain in dB.
|
||||
@@ -204,6 +206,7 @@ impl SoapySdrRig {
|
||||
retune_cmd,
|
||||
wfm_deemphasis_us,
|
||||
wfm_stereo: true,
|
||||
wfm_denoise: true,
|
||||
gain_db,
|
||||
max_gain_db,
|
||||
})
|
||||
@@ -521,6 +524,19 @@ impl RigCat for SoapySdrRig {
|
||||
})
|
||||
}
|
||||
|
||||
fn set_wfm_denoise<'a>(
|
||||
&'a mut self,
|
||||
enabled: bool,
|
||||
) -> Pin<Box<dyn std::future::Future<Output = DynResult<()>> + 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<RigFilterState> {
|
||||
let wfm_stereo_detected = self
|
||||
.pipeline
|
||||
@@ -540,6 +556,7 @@ impl RigCat for SoapySdrRig {
|
||||
wfm_deemphasis_us: self.wfm_deemphasis_us,
|
||||
wfm_stereo: self.wfm_stereo,
|
||||
wfm_stereo_detected,
|
||||
wfm_denoise: self.wfm_denoise,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user