diff --git a/examples/audiopanning/main.go b/examples/audiopanning/main.go index 511f9f093..957cfae45 100644 --- a/examples/audiopanning/main.go +++ b/examples/audiopanning/main.go @@ -145,14 +145,29 @@ func main() { type StereoPanStream struct { io.ReadSeeker pan float64 // -1: left; 0: center; 1: right + buf []byte } -func (s *StereoPanStream) Read(p []byte) (n int, err error) { - n, err = s.ReadSeeker.Read(p) - if err != nil { - return +func (s *StereoPanStream) Read(p []byte) (int, error) { + // If the stream has a buffer that was read in the previous time, use this first. + var bufN int + if len(s.buf) > 0 { + bufN = copy(p, s.buf) + s.buf = s.buf[bufN:] } + readN, err := s.ReadSeeker.Read(p[bufN:]) + if err != nil && err != io.EOF { + return 0, err + } + + // Align the buffer size in multiples of 4. The extra part is pushed to the buffer for the + // next time. + totalN := bufN + readN + extra := totalN - totalN/4*4 + s.buf = append(s.buf, p[totalN-extra:totalN]...) + alignedN := totalN - extra + // This implementation uses a linear scale, ranging from -1 to 1, for stereo or mono sounds. // If pan = 0.0, the balance for the sound in each speaker is at 100% left and 100% right. // When pan is -1.0, only the left channel of the stereo sound is audible, when pan is 1.0, @@ -160,7 +175,7 @@ func (s *StereoPanStream) Read(p []byte) (n int, err error) { // https://docs.unity3d.com/ScriptReference/AudioSource-panStereo.html ls := math.Min(s.pan*-1+1, 1) rs := math.Min(s.pan+1, 1) - for i := 0; i < len(p); i += 4 { + for i := 0; i < alignedN; i += 4 { lc := int16(float64(int16(p[i])|int16(p[i+1])<<8) * ls) rc := int16(float64(int16(p[i+2])|int16(p[i+3])<<8) * rs) @@ -169,7 +184,7 @@ func (s *StereoPanStream) Read(p []byte) (n int, err error) { p[i+2] = byte(rc) p[i+3] = byte(rc >> 8) } - return + return alignedN, err } func (s *StereoPanStream) SetPan(pan float64) {