diff --git a/internal/audio/source.go b/internal/audio/source.go new file mode 100644 index 0000000..cad96ce --- /dev/null +++ b/internal/audio/source.go @@ -0,0 +1,37 @@ +package audio + +import ( + "math" +) + +type ToneSource struct { + LeftFreq float64 + RightFreq float64 + SampleRate float64 + LeftPhase float64 + RightPhase float64 + Amplitude float64 +} + +func NewToneSource(sampleRate float64) *ToneSource { + return &ToneSource{ + LeftFreq: 1000, + RightFreq: 1600, + SampleRate: sampleRate, + Amplitude: 0.4, + } +} + +func (s *ToneSource) NextFrame() Frame { + left := s.Amplitude * math.Sin(2*math.Pi*s.LeftPhase) + right := s.Amplitude * math.Sin(2*math.Pi*s.RightPhase) + s.LeftPhase += s.LeftFreq / s.SampleRate + s.RightPhase += s.RightFreq / s.SampleRate + if s.LeftPhase >= 1 { + s.LeftPhase -= math.Floor(s.LeftPhase) + } + if s.RightPhase >= 1 { + s.RightPhase -= math.Floor(s.RightPhase) + } + return NewFrame(Sample(left), Sample(right)) +} diff --git a/internal/audio/source_test.go b/internal/audio/source_test.go new file mode 100644 index 0000000..e92a8c6 --- /dev/null +++ b/internal/audio/source_test.go @@ -0,0 +1,12 @@ +package audio + +import "testing" + +func TestToneSourceNextFrame(t *testing.T) { + src := NewToneSource(48000) + a := src.NextFrame() + b := src.NextFrame() + if a == b { + t.Fatal("expected varying frames") + } +} diff --git a/internal/offline/generator.go b/internal/offline/generator.go index cf42a6b..99e5ef7 100644 --- a/internal/offline/generator.go +++ b/internal/offline/generator.go @@ -55,16 +55,13 @@ func (g *Generator) GenerateFrame(duration time.Duration) *output.CompositeFrame }) rdsSamples := rdsEnc.Generate(samples) - leftFreq := 1000.0 - rightFreq := 1600.0 - stereoCarrierFreq := 38000.0 + source := audio.NewToneSource(sampleRate) for i := 0; i < samples; i++ { t := float64(i) / sampleRate - 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) + in := source.NextFrame() + comps := stereoEncoder.Encode(in) + stereoDSB := comps.Stereo * math.Sin(2*math.Pi*38000.0*t) rdsValue := 0.0 if g.cfg.RDS.Enabled && i < len(rdsSamples) { rdsValue = rdsSamples[i]