From e152ef0ee0a4a5314da852463253d8e28ef1672a Mon Sep 17 00:00:00 2001 From: rouggy Date: Thu, 30 Jul 2026 23:13:21 +0200 Subject: [PATCH] feat: record CW QSOs again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CW was excluded because SmartSDR does not route the operator's own sidetone through DAX, so the recording sounds one-sided. The audio path is open all the same and the other station IS captured — which is the half worth keeping. The frontend had ONE list serving two purposes: which modes may be recorded, and which modes the voice keyer may transmit on. Adding CW to it would have let the DVK key the rig with speech on a CW frequency. They are now two lists: PHONE_MODES for the keyer, RECORDABLE_MODES (phone + CW) for the recorder. Digital modes stay out of both: their audio is a modem tone nobody will replay. --- app.go | 15 +++++++++------ changelog.json | 6 ++++-- frontend/src/App.tsx | 12 ++++++++++-- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/app.go b/app.go index 16122d9..3ae8307 100644 --- a/app.go +++ b/app.go @@ -7107,14 +7107,17 @@ func (a *App) qsoRecDir() string { // be e-mailed later), and auto-sends it to the contacted operator when enabled // and an e-mail is known. Called right after a QSO is inserted (manual + UDP); // q must have its ID set. -// recordableMode reports whether a QSO mode is worth an audio recording — -// only voice (SSB/AM/FM) and CW. Digital modes (FT8/FT4/RTTY/PSK/JT…) carry no -// useful audio, so they are never recorded. +// recordableMode reports whether a QSO mode is worth an audio recording: voice +// and CW. Digital modes (FT8/FT4/RTTY/PSK/JT…) carry only modem tones, which +// nobody will ever replay, so they are never recorded. +// +// CW was excluded for a while because SmartSDR does not route the operator's own +// sidetone through DAX, making the recording sound one-sided. The audio path is +// open all the same and the other station IS captured — which is the half worth +// keeping. Operator's call. func recordableMode(mode string) bool { switch strings.ToUpper(strings.TrimSpace(mode)) { - // CW is intentionally excluded: SmartSDR doesn't route CW audio through DAX, - // so the recording is empty/useless. Phone modes only. - case "SSB", "USB", "LSB", "AM", "FM", "DV": + case "SSB", "USB", "LSB", "AM", "FM", "DV", "CW": return true } return false diff --git a/changelog.json b/changelog.json index 043de07..35ee29b 100644 --- a/changelog.json +++ b/changelog.json @@ -3,10 +3,12 @@ "version": "0.22.4", "date": "", "en": [ - "FlexRadio: in split, OpsLog stays on the receive slice instead of following the transmitter." + "FlexRadio: in split, OpsLog stays on the receive slice instead of following the transmitter.", + "QSO recording works on CW again. Your own sidetone is not in the file, the other station is." ], "fr": [ - "FlexRadio : en split, OpsLog reste sur la slice de réception au lieu de suivre l'émission." + "FlexRadio : en split, OpsLog reste sur la slice de réception au lieu de suivre l'émission.", + "L'enregistrement des QSO fonctionne à nouveau en CW. Votre propre signal d'écoute n'est pas dans le fichier, celui du correspondant l'est." ] }, { diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 680c9de..ae256c0 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -137,7 +137,15 @@ const DEFAULT_MODES = ['SSB','CW','FT8','FT4','RTTY','PSK31','AM','FM','DIGITALV // Modes the QSO recorder captures (phone only). Mirrors recordableMode() in // app.go — digital modes carry no useful audio, and CW has no DAX audio on Flex, // so neither is recorded (no REC badge / timer for them). -const RECORDABLE_MODES = new Set(['SSB','USB','LSB','AM','FM','DV']); +// Modes a VOICE keyer may transmit on. Not a recording list — the DVK plays +// speech, and sending it on CW or a data slot keys the rig with a human voice. +const PHONE_MODES = new Set(['SSB','USB','LSB','AM','FM','DV']); + +// Modes worth recording. Phone, plus CW: the audio path stays open in CW, so +// the other station's signal is captured. Your own sidetone is not in it — +// SmartSDR does not route it through DAX — and that is accepted. Digital modes +// stay out: their audio is a modem tone nobody will ever replay. +const RECORDABLE_MODES = new Set([...PHONE_MODES, 'CW']); const emptyDetails: DetailsState = { state: '', cnty: '', address: '', @@ -1233,7 +1241,7 @@ export default function App() { useEffect(() => { dvkAutoCqSecsRef.current = dvkAutoCqSecs; localStorage.setItem('opslog.dvkAutoCqSecs', String(dvkAutoCqSecs)); }, [dvkAutoCqSecs]); // The DVK is a VOICE keyer — transmitting it on CW/FT8/RTTY would key the rig // with speech on a data slot. Only allow it on phone modes. - const isPhoneMode = (m: string) => RECORDABLE_MODES.has((m || '').toUpperCase()); + const isPhoneMode = (m: string) => PHONE_MODES.has((m || '').toUpperCase()); const modeRef = useRef(mode); useEffect(() => { modeRef.current = mode; }, [mode]); function stopDvkAutoCq() { dvkAutoCqSlotRef.current = -1; dvkAutoCqGenRef.current++; }