diff --git a/app.go b/app.go
index 8ade62d..c16018a 100644
--- a/app.go
+++ b/app.go
@@ -4237,6 +4237,18 @@ func (a *App) QSOAudioRestart() bool {
return a.qsoRec.Active()
}
+// QSOAudioResetClock restarts the in-progress recording from zero, dropping
+// everything captured so far (pre-roll included). Lets the operator click the
+// REC timer to record only their own exchange when the station was already in a
+// long QSO before they entered the call. Returns whether a recording is active.
+func (a *App) QSOAudioResetClock() bool {
+ if a.qsoRec == nil {
+ return false
+ }
+ a.qsoRec.ResetQSOClock()
+ return a.qsoRec.Active()
+}
+
// QSOAudioCancel drops the in-progress recording (callsign cleared, QSO
// abandoned without logging).
func (a *App) QSOAudioCancel() {
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index fdc1383..6e792fa 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -32,7 +32,7 @@ import {
GetDVKMessages, GetDVKStatus, DVKPlay, DVKStop,
StartCWDecoder, StopCWDecoder, SetCWDecoderPitch,
ChatAvailable, GetChatHistory, SendChatMessage, GetOnlineOperators,
- QSOAudioBegin, QSOAudioCancel, QSOAudioRestart,
+ QSOAudioBegin, QSOAudioCancel, QSOAudioRestart, QSOAudioResetClock,
GetAwardDefs,
GetUIPref,
ReportLiveActivity,
@@ -507,6 +507,12 @@ export default function App() {
if (forCall !== undefined) recordingCallRef.current = forCall.trim().toUpperCase();
QSOAudioRestart().then((active) => { setRecording(active); setRecTick((t) => t + 1); }).catch(() => {});
};
+ // Reset the recording to zero (drop everything so far, pre-roll included) —
+ // bound to clicking the REC timer. Use when the station was already in a long
+ // QSO and you only want your own exchange in the file.
+ const resetRecordingClock = () => {
+ QSOAudioResetClock().then((active) => { setRecording(active); setRecTick((t) => t + 1); }).catch(() => {});
+ };
const [saving, setSaving] = useState(false);
const [filterCallsign, setFilterCallsign] = useState('');
// Advanced filter builder (replaces the old band/mode dropdowns).
@@ -2247,10 +2253,16 @@ export default function App() {
{recording && RECORDABLE_MODES.has(mode.toUpperCase()) && (
-
+
+
)}
;
export function QSOAudioCancel():Promise;
+export function QSOAudioResetClock():Promise;
+
export function QSOAudioRestart():Promise;
export function QuitApp():Promise;
diff --git a/frontend/wailsjs/go/main/App.js b/frontend/wailsjs/go/main/App.js
index 4b44987..48d451d 100644
--- a/frontend/wailsjs/go/main/App.js
+++ b/frontend/wailsjs/go/main/App.js
@@ -826,6 +826,10 @@ export function QSOAudioCancel() {
return window['go']['main']['App']['QSOAudioCancel']();
}
+export function QSOAudioResetClock() {
+ return window['go']['main']['App']['QSOAudioResetClock']();
+}
+
export function QSOAudioRestart() {
return window['go']['main']['App']['QSOAudioRestart']();
}
diff --git a/internal/audio/recorder.go b/internal/audio/recorder.go
index 1bf384e..d3b700a 100644
--- a/internal/audio/recorder.go
+++ b/internal/audio/recorder.go
@@ -239,6 +239,22 @@ func (r *Recorder) RestartQSO() {
r.active = true
}
+// ResetQSOClock restarts the active accumulation from ZERO — discarding
+// everything captured so far INCLUDING the pre-roll. Unlike RestartQSO (which
+// re-seeds from the pre-roll ring), this keeps nothing: the saved file will
+// contain only audio from this moment onward. Used when the contact you entered
+// was already in a long QSO and you want to record just your own exchange.
+// No-op if not running; if no take is active it begins one (empty).
+func (r *Recorder) ResetQSOClock() {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+ if !r.running {
+ return
+ }
+ r.acc = nil
+ r.active = true
+}
+
// TakeQSO snapshots the accumulated recording as raw 16 kHz mono PCM bytes and
// stops accumulating — fast, no encoding. The next BeginQSO can safely start a
// new take immediately. Pair with WritePCM to encode/write off the hot path so