|
|
@@ -5,6 +5,8 @@ import ( |
|
|
"encoding/binary" |
|
|
"encoding/binary" |
|
|
"fmt" |
|
|
"fmt" |
|
|
"path/filepath" |
|
|
"path/filepath" |
|
|
|
|
|
"strconv" |
|
|
|
|
|
"strings" |
|
|
"time" |
|
|
"time" |
|
|
|
|
|
|
|
|
"github.com/jan/fm-rds-tx/internal/audio" |
|
|
"github.com/jan/fm-rds-tx/internal/audio" |
|
|
@@ -44,6 +46,20 @@ func (g *Generator) sourceFor(sampleRate float64) (frameSource, SourceInfo) { |
|
|
return audio.NewConfiguredToneSource(sampleRate, g.cfg.Audio.ToneLeftHz, g.cfg.Audio.ToneRightHz, g.cfg.Audio.ToneAmplitude), SourceInfo{Kind: "tones", SampleRate: sampleRate, Detail: "generated"} |
|
|
return audio.NewConfiguredToneSource(sampleRate, g.cfg.Audio.ToneLeftHz, g.cfg.Audio.ToneRightHz, g.cfg.Audio.ToneAmplitude), SourceInfo{Kind: "tones", SampleRate: sampleRate, Detail: "generated"} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func parsePI(pi string) uint16 { |
|
|
|
|
|
trimmed := strings.TrimSpace(pi) |
|
|
|
|
|
if trimmed == "" { |
|
|
|
|
|
return 0x1234 |
|
|
|
|
|
} |
|
|
|
|
|
trimmed = strings.TrimPrefix(trimmed, "0x") |
|
|
|
|
|
trimmed = strings.TrimPrefix(trimmed, "0X") |
|
|
|
|
|
v, err := strconv.ParseUint(trimmed, 16, 16) |
|
|
|
|
|
if err != nil { |
|
|
|
|
|
return 0x1234 |
|
|
|
|
|
} |
|
|
|
|
|
return uint16(v) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
func (g *Generator) GenerateFrame(duration time.Duration) *output.CompositeFrame { |
|
|
func (g *Generator) GenerateFrame(duration time.Duration) *output.CompositeFrame { |
|
|
sampleRate := float64(g.cfg.FM.CompositeRateHz) |
|
|
sampleRate := float64(g.cfg.FM.CompositeRateHz) |
|
|
if sampleRate <= 0 { |
|
|
if sampleRate <= 0 { |
|
|
@@ -80,7 +96,7 @@ func (g *Generator) GenerateFrame(duration time.Duration) *output.CompositeFrame |
|
|
|
|
|
|
|
|
// RDS encoder (standards-grade group framing + CRC + diff encoding) |
|
|
// RDS encoder (standards-grade group framing + CRC + diff encoding) |
|
|
rdsEnc, _ := rds.NewEncoder(rds.RDSConfig{ |
|
|
rdsEnc, _ := rds.NewEncoder(rds.RDSConfig{ |
|
|
PI: 0x1234, |
|
|
|
|
|
|
|
|
PI: parsePI(g.cfg.RDS.PI), |
|
|
PS: g.cfg.RDS.PS, |
|
|
PS: g.cfg.RDS.PS, |
|
|
RT: g.cfg.RDS.RadioText, |
|
|
RT: g.cfg.RDS.RadioText, |
|
|
PTY: uint8(g.cfg.RDS.PTY), |
|
|
PTY: uint8(g.cfg.RDS.PTY), |
|
|
|