From 10eef10b9f89965eed21b45c1a1cf5d10261e001 Mon Sep 17 00:00:00 2001 From: Jan Svabenik Date: Thu, 19 Mar 2026 11:44:38 +0100 Subject: [PATCH] Use fused GPU demod for live demod endpoint --- internal/recorder/demod_live.go | 57 ++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/internal/recorder/demod_live.go b/internal/recorder/demod_live.go index 6f5fdae..1ee794f 100644 --- a/internal/recorder/demod_live.go +++ b/internal/recorder/demod_live.go @@ -7,6 +7,7 @@ import ( "time" "sdr-visual-suite/internal/demod" + "sdr-visual-suite/internal/demod/gpudemod" "sdr-visual-suite/internal/dsp" ) @@ -38,23 +39,55 @@ func (m *Manager) DemodLive(centerHz float64, bw float64, mode string, seconds i return nil, 0, errors.New("demodulator not found") } offset := centerHz - m.centerHz - shifted := dsp.FreqShift(segment, m.sampleRate, offset) if bw <= 0 { bw = 12000 } - cutoff := bw / 2 - if cutoff < 200 { - cutoff = 200 + + var audio []float32 + var inputRate int + if m.gpuDemod != nil { + var gpuMode gpudemod.DemodType + var useGPU bool + switch name { + case "NFM": + gpuMode, useGPU = gpudemod.DemodNFM, true + case "WFM": + gpuMode, useGPU = gpudemod.DemodWFM, true + case "AM": + gpuMode, useGPU = gpudemod.DemodAM, true + case "USB": + gpuMode, useGPU = gpudemod.DemodUSB, true + case "LSB": + gpuMode, useGPU = gpudemod.DemodLSB, true + case "CW": + gpuMode, useGPU = gpudemod.DemodCW, true + } + if useGPU { + if gpuAudio, gpuRate, err := m.gpuDemod.DemodFused(segment, offset, bw, gpuMode); err == nil { + audio = gpuAudio + inputRate = gpuRate + } else if gpuAudio, gpuRate, err := m.gpuDemod.Demod(segment, offset, bw, gpuMode); err == nil { + audio = gpuAudio + inputRate = gpuRate + } + } } - taps := dsp.LowpassFIR(cutoff, m.sampleRate, 101) - filtered := dsp.ApplyFIR(shifted, taps) - decim := int(math.Round(float64(m.sampleRate) / float64(d.OutputSampleRate()))) - if decim < 1 { - decim = 1 + if audio == nil { + shifted := dsp.FreqShift(segment, m.sampleRate, offset) + cutoff := bw / 2 + if cutoff < 200 { + cutoff = 200 + } + taps := dsp.LowpassFIR(cutoff, m.sampleRate, 101) + filtered := dsp.ApplyFIR(shifted, taps) + decim := int(math.Round(float64(m.sampleRate) / float64(d.OutputSampleRate()))) + if decim < 1 { + decim = 1 + } + dec := dsp.Decimate(filtered, decim) + inputRate = m.sampleRate / decim + audio = d.Demod(dec, inputRate) } - dec := dsp.Decimate(filtered, decim) - inputRate := m.sampleRate / decim - audio := d.Demod(dec, inputRate) buf := &bytes.Buffer{} if err := writeWAVTo(buf, audio, inputRate, d.Channels()); err != nil { return nil, 0, err