From 5942192b66645d22d6e058586642fc8e58598afc Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Tue, 21 May 2024 02:34:54 +0900 Subject: [PATCH] audio/vorbis: refactoring --- audio/vorbis/vorbis.go | 115 +++++++++++++++++++---------------------- 1 file changed, 54 insertions(+), 61 deletions(-) diff --git a/audio/vorbis/vorbis.go b/audio/vorbis/vorbis.go index 919bda10e..6751c499d 100644 --- a/audio/vorbis/vorbis.go +++ b/audio/vorbis/vorbis.go @@ -27,28 +27,28 @@ import ( // Stream is a decoded audio stream. type Stream struct { - decoded io.ReadSeeker - size int64 + readSeeker io.ReadSeeker + length int64 sampleRate int } // Read is implementation of io.Reader's Read. func (s *Stream) Read(p []byte) (int, error) { - return s.decoded.Read(p) + return s.readSeeker.Read(p) } // Seek is implementation of io.Seeker's Seek. // // Note that Seek can take long since decoding is a relatively heavy task. func (s *Stream) Seek(offset int64, whence int) (int64, error) { - return s.decoded.Seek(offset, whence) + return s.readSeeker.Seek(offset, whence) } // Length returns the size of decoded stream in bytes. // // If the source is not io.Seeker, Length returns 0. func (s *Stream) Length() int64 { - return s.size + return s.length } // SampleRate returns the sample rate of the decoded stream. @@ -56,27 +56,19 @@ func (s *Stream) SampleRate() int { return s.sampleRate } -type decoder interface { - Read([]float32) (int, error) - SetPosition(int64) error - Length() int64 - Channels() int - SampleRate() int +type i16Stream struct { + totalBytes int + posInBytes int + vorbisReader *oggvorbis.Reader + i16Reader io.Reader } -type decoded struct { - totalBytes int - posInBytes int - decoder decoder - decoderr io.Reader -} - -func (d *decoded) Read(b []byte) (int, error) { - if d.decoderr == nil { - d.decoderr = convert.NewReaderFromFloat32Reader(d.decoder) +func (s *i16Stream) Read(b []byte) (int, error) { + if s.i16Reader == nil { + s.i16Reader = convert.NewReaderFromFloat32Reader(s.vorbisReader) } - l := d.totalBytes - d.posInBytes + l := s.totalBytes - s.posInBytes if l > len(b) { l = len(b) } @@ -85,7 +77,7 @@ func (d *decoded) Read(b []byte) (int, error) { } retry: - n, err := d.decoderr.Read(b[:l]) + n, err := s.i16Reader.Read(b[:l]) if err != nil && err != io.EOF { return 0, err } @@ -94,59 +86,63 @@ retry: goto retry } - d.posInBytes += n - if d.posInBytes == d.totalBytes || err == io.EOF { + s.posInBytes += n + if s.posInBytes == s.totalBytes || err == io.EOF { return n, io.EOF } return n, nil } -func (d *decoded) Seek(offset int64, whence int) (int64, error) { +func (s *i16Stream) Seek(offset int64, whence int) (int64, error) { next := int64(0) switch whence { case io.SeekStart: next = offset case io.SeekCurrent: - next = int64(d.posInBytes) + offset + next = int64(s.posInBytes) + offset case io.SeekEnd: - next = int64(d.totalBytes) + offset + next = int64(s.totalBytes) + offset } // pos should be always even next = next / 2 * 2 - d.posInBytes = int(next) - if err := d.decoder.SetPosition(next / int64(d.decoder.Channels()) / 2); err != nil { + s.posInBytes = int(next) + if err := s.vorbisReader.SetPosition(next / int64(s.vorbisReader.Channels()) / 2); err != nil { return 0, err } - d.decoderr = nil + s.i16Reader = nil return next, nil } -func (d *decoded) Length() int64 { - return int64(d.totalBytes) +func (s *i16Stream) Length() int64 { + return int64(s.totalBytes) } // decode accepts an ogg stream and returns a decorded stream. -func decode(in io.Reader) (*decoded, int, int, error) { +func decode(in io.Reader) (*i16Stream, int, int, error) { r, err := oggvorbis.NewReader(in) if err != nil { return nil, 0, 0, err } - d := &decoded{ + if r.Channels() != 1 && r.Channels() != 2 { + return nil, 0, 0, fmt.Errorf("vorbis: number of channels must be 1 or 2 but was %d", r.Channels()) + } + + s := &i16Stream{ // TODO: r.Length() returns 0 when the format is unknown. // Should we check that? - totalBytes: int(r.Length()) * r.Channels() * 2, // 2 means 16bit per sample. - posInBytes: 0, - decoder: r, + totalBytes: int(r.Length()) * r.Channels() * 2, // 2 means 16bit per sample. + posInBytes: 0, + vorbisReader: r, } if _, ok := in.(io.Seeker); ok { - if _, err := d.Read(make([]byte, 65536)); err != nil && err != io.EOF { + if _, err := s.Read(make([]byte, 65536)); err != nil && err != io.EOF { return nil, 0, 0, err } - if _, err := d.Seek(0, io.SeekStart); err != nil { + if _, err := s.Seek(0, io.SeekStart); err != nil { return nil, 0, 0, err } } - return d, r.Channels(), r.SampleRate(), nil + return s, r.Channels(), r.SampleRate(), nil } // DecodeWithoutResampling decodes Ogg/Vorbis data to playable stream. @@ -158,22 +154,21 @@ func decode(in io.Reader) (*decoded, int, int, error) { // A Stream doesn't close src even if src implements io.Closer. // Closing the source is src owner's responsibility. func DecodeWithoutResampling(src io.Reader) (*Stream, error) { - decoded, channelCount, sampleRate, err := decode(src) + i16Stream, channelCount, sampleRate, err := decode(src) if err != nil { return nil, err } - if channelCount != 1 && channelCount != 2 { - return nil, fmt.Errorf("vorbis: number of channels must be 1 or 2 but was %d", channelCount) - } - var s io.ReadSeeker = decoded - size := decoded.Length() + + var s io.ReadSeeker = i16Stream + length := i16Stream.Length() if channelCount == 1 { s = convert.NewStereo16(s, true, false) - size *= 2 + length *= 2 } + stream := &Stream{ - decoded: s, - size: size, + readSeeker: s, + length: length, sampleRate: sampleRate, } return stream, nil @@ -193,27 +188,25 @@ func DecodeWithoutResampling(src io.Reader) (*Stream, error) { // Resampling can be a very heavy task. Stream has a cache for resampling, but the size is limited. // Do not expect that Stream has a resampling cache even after whole data is played. func DecodeWithSampleRate(sampleRate int, src io.Reader) (*Stream, error) { - decoded, channelCount, origSampleRate, err := decode(src) + i16Stream, channelCount, origSampleRate, err := decode(src) if err != nil { return nil, err } - if channelCount != 1 && channelCount != 2 { - return nil, fmt.Errorf("vorbis: number of channels must be 1 or 2 but was %d", channelCount) - } - var s io.ReadSeeker = decoded - size := decoded.Length() + + var s io.ReadSeeker = i16Stream + length := i16Stream.Length() if channelCount == 1 { s = convert.NewStereo16(s, true, false) - size *= 2 + length *= 2 } if origSampleRate != sampleRate { - r := convert.NewResampling(s, size, origSampleRate, sampleRate) + r := convert.NewResampling(s, length, origSampleRate, sampleRate) s = r - size = r.Length() + length = r.Length() } stream := &Stream{ - decoded: s, - size: size, + readSeeker: s, + length: length, sampleRate: sampleRate, } return stream, nil