audio/vorbis: refactoring

This commit is contained in:
Hajime Hoshi 2024-07-21 09:59:06 +09:00
parent abc056ab29
commit 4689d656aa
3 changed files with 23 additions and 22 deletions

View File

@ -18,22 +18,22 @@ import (
"io" "io"
) )
type Stereo16 struct { type StereoI16 struct {
source io.ReadSeeker source io.ReadSeeker
mono bool mono bool
eight bool eight bool
buf []byte buf []byte
} }
func NewStereo16(source io.ReadSeeker, mono, eight bool) *Stereo16 { func NewStereoI16(source io.ReadSeeker, mono, eight bool) *StereoI16 {
return &Stereo16{ return &StereoI16{
source: source, source: source,
mono: mono, mono: mono,
eight: eight, eight: eight,
} }
} }
func (s *Stereo16) Read(b []byte) (int, error) { func (s *StereoI16) Read(b []byte) (int, error) {
l := len(b) l := len(b)
if s.mono { if s.mono {
l /= 2 l /= 2
@ -85,7 +85,7 @@ func (s *Stereo16) Read(b []byte) (int, error) {
return n, err return n, err
} }
func (s *Stereo16) Seek(offset int64, whence int) (int64, error) { func (s *StereoI16) Seek(offset int64, whence int) (int64, error) {
if s.mono { if s.mono {
offset /= 2 offset /= 2
} }

View File

@ -121,14 +121,14 @@ func (s *i16Stream) Length() int64 {
return int64(s.totalBytes) return int64(s.totalBytes)
} }
// decode accepts an ogg stream and returns a decorded stream. // decodeI16 accepts an ogg stream and returns a decorded stream.
func decode(in io.Reader) (*i16Stream, int, int, error) { func decodeI16(in io.Reader) (*i16Stream, error) {
r, err := oggvorbis.NewReader(in) r, err := oggvorbis.NewReader(in)
if err != nil { if err != nil {
return nil, 0, 0, err return nil, err
} }
if r.Channels() != 1 && r.Channels() != 2 { 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()) return nil, fmt.Errorf("vorbis: number of channels must be 1 or 2 but was %d", r.Channels())
} }
s := &i16Stream{ s := &i16Stream{
@ -138,15 +138,16 @@ func decode(in io.Reader) (*i16Stream, int, int, error) {
posInBytes: 0, posInBytes: 0,
vorbisReader: r, vorbisReader: r,
} }
// Read some data for performance (#297).
if _, ok := in.(io.Seeker); ok { if _, ok := in.(io.Seeker); ok {
if _, err := s.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 return nil, err
} }
if _, err := s.Seek(0, io.SeekStart); err != nil { if _, err := s.Seek(0, io.SeekStart); err != nil {
return nil, 0, 0, err return nil, err
} }
} }
return s, r.Channels(), r.SampleRate(), nil return s, nil
} }
// DecodeWithoutResampling decodes Ogg/Vorbis data to playable stream. // DecodeWithoutResampling decodes Ogg/Vorbis data to playable stream.
@ -158,22 +159,22 @@ func decode(in io.Reader) (*i16Stream, int, int, error) {
// A Stream doesn't close src even if src implements io.Closer. // A Stream doesn't close src even if src implements io.Closer.
// Closing the source is src owner's responsibility. // Closing the source is src owner's responsibility.
func DecodeWithoutResampling(src io.Reader) (*Stream, error) { func DecodeWithoutResampling(src io.Reader) (*Stream, error) {
i16Stream, channelCount, sampleRate, err := decode(src) i16Stream, err := decodeI16(src)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var s io.ReadSeeker = i16Stream var s io.ReadSeeker = i16Stream
length := i16Stream.Length() length := i16Stream.Length()
if channelCount == 1 { if i16Stream.vorbisReader.Channels() == 1 {
s = convert.NewStereo16(s, true, false) s = convert.NewStereoI16(s, true, false)
length *= 2 length *= 2
} }
stream := &Stream{ stream := &Stream{
readSeeker: s, readSeeker: s,
length: length, length: length,
sampleRate: sampleRate, sampleRate: i16Stream.vorbisReader.SampleRate(),
} }
return stream, nil return stream, nil
} }
@ -192,19 +193,19 @@ 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. // 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. // Do not expect that Stream has a resampling cache even after whole data is played.
func DecodeWithSampleRate(sampleRate int, src io.Reader) (*Stream, error) { func DecodeWithSampleRate(sampleRate int, src io.Reader) (*Stream, error) {
i16Stream, channelCount, origSampleRate, err := decode(src) i16Stream, err := decodeI16(src)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var s io.ReadSeeker = i16Stream var s io.ReadSeeker = i16Stream
length := i16Stream.Length() length := i16Stream.Length()
if channelCount == 1 { if i16Stream.vorbisReader.Channels() == 1 {
s = convert.NewStereo16(s, true, false) s = convert.NewStereoI16(s, true, false)
length *= 2 length *= 2
} }
if origSampleRate != sampleRate { if i16Stream.vorbisReader.SampleRate() != sampleRate {
r := convert.NewResampling(s, length, origSampleRate, sampleRate, bitDepthInBytesInt16) r := convert.NewResampling(s, length, i16Stream.vorbisReader.SampleRate(), sampleRate, bitDepthInBytesInt16)
s = r s = r
length = r.Length() length = r.Length()
} }

View File

@ -198,7 +198,7 @@ chunks:
var s io.ReadSeeker = newSectionReader(src, headerSize, dataSize) var s io.ReadSeeker = newSectionReader(src, headerSize, dataSize)
if mono || bitsPerSample != 16 { if mono || bitsPerSample != 16 {
s = convert.NewStereo16(s, mono, bitsPerSample != 16) s = convert.NewStereoI16(s, mono, bitsPerSample != 16)
if mono { if mono {
dataSize *= 2 dataSize *= 2
} }