package stereo import ( "github.com/jan/fm-rds-tx/internal/audio" "github.com/jan/fm-rds-tx/internal/dsp" ) // Components holds the individual MPX components produced by the stereo encoder. // All outputs are unity-normalized. The combiner controls actual injection levels. type Components struct { Mono float64 // (L+R)/2 baseband Stereo float64 // (L-R)/2 * sin(2π·38kHz·t), unity subcarrier Pilot float64 // sin(2π·19kHz·t), unity amplitude } // StereoEncoder generates stereo MPX primitives from stereo audio frames. type StereoEncoder struct { pilot dsp.PilotGenerator subcarrier dsp.Oscillator } // NewStereoEncoder creates a StereoEncoder configured for the provided sample rate. func NewStereoEncoder(sampleRate float64) StereoEncoder { return StereoEncoder{ pilot: dsp.NewPilotGenerator(sampleRate), subcarrier: dsp.Oscillator{Frequency: 38000, SampleRate: sampleRate}, } } // Encode converts a stereo frame into MPX components. func (s *StereoEncoder) Encode(frame audio.Frame) Components { pilot := s.pilot.Sample() sub38 := s.subcarrier.Tick() return Components{ Mono: float64(frame.Mono()), Stereo: float64(frame.Difference()) * sub38, Pilot: pilot, } } // Reset restarts the pilot and subcarrier generators. func (s *StereoEncoder) Reset() { s.pilot.Reset() s.subcarrier.Reset() }