diff --git a/internal/offline/generator.go b/internal/offline/generator.go index bfad59b..cf42a6b 100644 --- a/internal/offline/generator.go +++ b/internal/offline/generator.go @@ -8,8 +8,12 @@ import ( "path/filepath" "time" + "github.com/jan/fm-rds-tx/internal/audio" cfgpkg "github.com/jan/fm-rds-tx/internal/config" + "github.com/jan/fm-rds-tx/internal/mpx" "github.com/jan/fm-rds-tx/internal/output" + "github.com/jan/fm-rds-tx/internal/rds" + "github.com/jan/fm-rds-tx/internal/stereo" ) type Generator struct { @@ -37,20 +41,35 @@ func (g *Generator) GenerateFrame(duration time.Duration) *output.CompositeFrame Sequence: 1, } + stereoEncoder := stereo.NewStereoEncoder(sampleRate) + combiner := mpx.NewDefaultCombiner() + combiner.PilotGain = g.cfg.FM.PilotLevel + combiner.RDSGain = g.cfg.FM.RDSInjection + + rdsEnc, _ := rds.NewEncoder(rds.RDSConfig{ + PI: 0x1234, + PS: g.cfg.RDS.PS, + RT: g.cfg.RDS.RadioText, + PTY: uint8(g.cfg.RDS.PTY), + SampleRate: sampleRate, + }) + rdsSamples := rdsEnc.Generate(samples) + leftFreq := 1000.0 rightFreq := 1600.0 - pilotFreq := 19000.0 - rdsFreq := 57000.0 + stereoCarrierFreq := 38000.0 for i := 0; i < samples; i++ { t := float64(i) / sampleRate - left := 0.4 * math.Sin(2*math.Pi*leftFreq*t) - right := 0.4 * math.Sin(2*math.Pi*rightFreq*t+math.Pi/3) - mono := (left + right) / 2 - stereo := (left - right) / 2 * 0.8 * math.Sin(2*math.Pi*38000*t) - pilot := g.cfg.FM.PilotLevel * math.Sin(2*math.Pi*pilotFreq*t) - rds := g.cfg.FM.RDSInjection * math.Sin(2*math.Pi*rdsFreq*t) - composite := (mono + stereo + pilot + rds) * g.cfg.FM.OutputDrive + left := audio.Sample(0.4 * math.Sin(2*math.Pi*leftFreq*t)) + right := audio.Sample(0.4 * math.Sin(2*math.Pi*rightFreq*t+math.Pi/3)) + comps := stereoEncoder.Encode(audio.NewFrame(left, right)) + stereoDSB := comps.Stereo * math.Sin(2*math.Pi*stereoCarrierFreq*t) + rdsValue := 0.0 + if g.cfg.RDS.Enabled && i < len(rdsSamples) { + rdsValue = rdsSamples[i] + } + composite := combiner.Combine(comps.Mono, stereoDSB, comps.Pilot, rdsValue) * g.cfg.FM.OutputDrive frame.Samples[i] = output.IQSample{I: float32(composite), Q: 0} } @@ -92,5 +111,5 @@ func (g *Generator) WriteFile(path string, duration time.Duration) error { } func (g *Generator) Summary(duration time.Duration) string { - return fmt.Sprintf("offline frame: freq=%.1fMHz sampleRate=%d duration=%s outputDrive=%.2f", g.cfg.FM.FrequencyMHz, g.cfg.FM.CompositeRateHz, duration.String(), g.cfg.FM.OutputDrive) + return fmt.Sprintf("offline frame: freq=%.1fMHz sampleRate=%d duration=%s outputDrive=%.2f stereo=%t rds=%t", g.cfg.FM.FrequencyMHz, g.cfg.FM.CompositeRateHz, duration.String(), g.cfg.FM.OutputDrive, g.cfg.FM.StereoEnabled, g.cfg.RDS.Enabled) }