package ingest import ( "fmt" "math" "github.com/jan/fm-rds-tx/internal/audio" ) const int32AbsMax = 2147483648.0 func ChunkToFrames(chunk PCMChunk) ([]audio.Frame, error) { if chunk.Channels != 1 && chunk.Channels != 2 { return nil, fmt.Errorf("unsupported channel count: %d", chunk.Channels) } if chunk.Channels <= 0 { return nil, fmt.Errorf("invalid channel count: %d", chunk.Channels) } if len(chunk.Samples)%chunk.Channels != 0 { return nil, fmt.Errorf("invalid interleaved sample count: %d for channels=%d", len(chunk.Samples), chunk.Channels) } frames := make([]audio.Frame, len(chunk.Samples)/chunk.Channels) switch chunk.Channels { case 1: for i := range frames { s := normalizePCM(chunk.Samples[i]) frames[i] = audio.NewFrame(s, s) } case 2: for i := range frames { off := i * 2 l := normalizePCM(chunk.Samples[off]) r := normalizePCM(chunk.Samples[off+1]) frames[i] = audio.NewFrame(l, r) } } return frames, nil } func normalizePCM(v int32) audio.Sample { norm := float64(v) / int32AbsMax norm = math.Max(float64(audio.SampleMin), math.Min(float64(audio.SampleMax), norm)) return audio.Sample(norm) }