Go-based FM stereo transmitter with RDS, Windows-first and cross-platform
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

79 строки
2.4KB

  1. package dryrun
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "os"
  6. "path/filepath"
  7. cfgpkg "github.com/jan/fm-rds-tx/internal/config"
  8. )
  9. type FrameSummary struct {
  10. Mode string `json:"mode"`
  11. FrequencyMHz float64 `json:"frequencyMHz"`
  12. StereoEnabled bool `json:"stereoEnabled"`
  13. RDSEnabled bool `json:"rdsEnabled"`
  14. InputSampleRateHz int `json:"inputSampleRateHz"`
  15. CompositeRate int `json:"compositeRateHz"`
  16. DeviceRate float64 `json:"deviceSampleRateHz"`
  17. PilotLevel float64 `json:"pilotLevel"`
  18. RDSInjection float64 `json:"rdsInjection"`
  19. OutputDrive float64 `json:"outputDrive"`
  20. PreEmphasisTauUS float64 `json:"preEmphasisTauUS"`
  21. MaxDeviationHz float64 `json:"maxDeviationHz"`
  22. LimiterEnabled bool `json:"limiterEnabled"`
  23. FMModulation bool `json:"fmModulationEnabled"`
  24. Source string `json:"source"`
  25. PreviewSamples []float64 `json:"previewSamples"`
  26. }
  27. func Generate(cfg cfgpkg.Config) FrameSummary {
  28. preview := make([]float64, 16)
  29. base := cfg.Audio.Gain * cfg.FM.OutputDrive
  30. for i := range preview {
  31. sign := 1.0
  32. if i%2 == 1 {
  33. sign = -1.0
  34. }
  35. preview[i] = sign * base * float64(i+1) / 16.0
  36. }
  37. source := "tones"
  38. if cfg.Audio.InputPath != "" {
  39. source = cfg.Audio.InputPath
  40. }
  41. return FrameSummary{
  42. Mode: "dry-run",
  43. FrequencyMHz: cfg.FM.FrequencyMHz,
  44. StereoEnabled: cfg.FM.StereoEnabled,
  45. RDSEnabled: cfg.RDS.Enabled,
  46. InputSampleRateHz: cfg.Audio.InputSampleRate,
  47. CompositeRate: cfg.FM.CompositeRateHz,
  48. DeviceRate: cfg.EffectiveDeviceRate(),
  49. PilotLevel: cfg.FM.PilotLevel,
  50. RDSInjection: cfg.FM.RDSInjection,
  51. OutputDrive: cfg.FM.OutputDrive,
  52. PreEmphasisTauUS: cfg.FM.PreEmphasisTauUS,
  53. MaxDeviationHz: cfg.FM.MaxDeviationHz,
  54. LimiterEnabled: cfg.FM.LimiterEnabled,
  55. FMModulation: cfg.FM.FMModulationEnabled,
  56. Source: source,
  57. PreviewSamples: preview,
  58. }
  59. }
  60. func WriteJSON(path string, frame FrameSummary) error {
  61. data, err := json.MarshalIndent(frame, "", " ")
  62. if err != nil {
  63. return fmt.Errorf("marshal dry-run frame: %w", err)
  64. }
  65. if path == "" || path == "-" {
  66. _, err = os.Stdout.Write(append(data, '\n'))
  67. return err
  68. }
  69. if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
  70. return fmt.Errorf("create output dir: %w", err)
  71. }
  72. return os.WriteFile(path, append(data, '\n'), 0o644)
  73. }