package main import ( "fmt" "hamlog/internal/applog" "hamlog/internal/audio" "hamlog/internal/cwdecode" wruntime "github.com/wailsapp/wails/v2/pkg/runtime" ) // CW decoder: taps the RX audio device (the same "From radio" capture the DVK // and QSO recorder use) and streams decoded Morse text to the UI. It is started // only by the frontend, and only while the entry mode is CW. // StartCWDecoder begins decoding CW from the configured RX audio device. The // frontend calls this when the decoder toggle is on AND the mode is CW. Safe to // call repeatedly; a second call is a no-op while already running. func (a *App) StartCWDecoder() error { a.cwMu.Lock() defer a.cwMu.Unlock() if a.cwStop != nil { return nil // already running } dev := "" if a.settings != nil { dev, _ = a.settings.Get(a.ctx, keyAudioFromRadio) } if dev == "" { return fmt.Errorf("no RX audio device configured (set \"From radio\" in Audio settings)") } dec := cwdecode.New(audio.SampleRate, func(text string) { if a.ctx != nil { wruntime.EventsEmit(a.ctx, "cw:text", text) } }, func(st cwdecode.Status) { if a.ctx != nil { wruntime.EventsEmit(a.ctx, "cw:status", st) } }, ) stop := make(chan struct{}) a.cwStop = stop go func() { if err := audio.StreamCapture(dev, stop, dec.Process); err != nil { applog.Printf("cw: capture failed: %v", err) if a.ctx != nil { wruntime.EventsEmit(a.ctx, "cw:error", err.Error()) } } // Capture ended (stopped or errored) — clear state so a restart works. a.cwMu.Lock() if a.cwStop == stop { a.cwStop = nil } a.cwMu.Unlock() }() return nil } // StopCWDecoder halts the CW decoder if running. func (a *App) StopCWDecoder() { a.cwMu.Lock() stop := a.cwStop a.cwStop = nil a.cwMu.Unlock() if stop != nil { close(stop) } } // CWDecoderRunning reports whether the decoder is currently capturing. func (a *App) CWDecoderRunning() bool { a.cwMu.Lock() defer a.cwMu.Unlock() return a.cwStop != nil }