Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

85 строки
2.0KB

  1. package recorder
  2. import (
  3. "bytes"
  4. "errors"
  5. "log"
  6. "math"
  7. "time"
  8. "sdr-visual-suite/internal/demod"
  9. "sdr-visual-suite/internal/dsp"
  10. )
  11. // DemodLive demodulates a recent window and returns WAV bytes.
  12. func (m *Manager) DemodLive(centerHz float64, bw float64, mode string, seconds int) ([]byte, int, error) {
  13. if m == nil || m.ring == nil {
  14. return nil, 0, errors.New("recorder not ready")
  15. }
  16. if seconds <= 0 {
  17. seconds = 2
  18. }
  19. end := time.Now()
  20. start := end.Add(-time.Duration(seconds) * time.Second)
  21. segment := m.ring.Slice(start, end)
  22. if len(segment) == 0 {
  23. return nil, 0, errors.New("no iq in ring")
  24. }
  25. name := mode
  26. if name == "" {
  27. name = "NFM"
  28. }
  29. switch name {
  30. case "AM", "NFM", "WFM", "WFM_STEREO", "USB", "LSB", "CW":
  31. default:
  32. name = "NFM"
  33. }
  34. d := demod.Get(name)
  35. if d == nil {
  36. return nil, 0, errors.New("demodulator not found")
  37. }
  38. offset := centerHz - m.centerHz
  39. if bw <= 0 {
  40. bw = 12000
  41. }
  42. var audio []float32
  43. var inputRate int
  44. gpu := m.gpuEngine()
  45. if gpu != nil {
  46. gpuMode, useGPU := gpuModeFor(name)
  47. if useGPU {
  48. if gpuAudio, gpuRate, ok := tryGPUAudio(gpu, name, segment, offset, bw, gpuMode); ok {
  49. audio = gpuAudio
  50. inputRate = gpuRate
  51. }
  52. }
  53. }
  54. if audio == nil {
  55. if name == "WFM_STEREO" {
  56. log.Printf("gpudemod: WFM_STEREO live path using CPU stereo/RDS post-process")
  57. } else {
  58. log.Printf("gpudemod: CPU live demod fallback used (%s)", name)
  59. }
  60. shifted := dsp.FreqShift(segment, m.sampleRate, offset)
  61. cutoff := bw / 2
  62. if cutoff < 200 {
  63. cutoff = 200
  64. }
  65. taps := dsp.LowpassFIR(cutoff, m.sampleRate, 101)
  66. filtered := dsp.ApplyFIR(shifted, taps)
  67. decim := int(math.Round(float64(m.sampleRate) / float64(d.OutputSampleRate())))
  68. if decim < 1 {
  69. decim = 1
  70. }
  71. dec := dsp.Decimate(filtered, decim)
  72. inputRate = m.sampleRate / decim
  73. audio = d.Demod(dec, inputRate)
  74. }
  75. buf := &bytes.Buffer{}
  76. if err := writeWAVTo(buf, audio, inputRate, d.Channels()); err != nil {
  77. return nil, 0, err
  78. }
  79. return buf.Bytes(), inputRate, nil
  80. }