Skip to content

Commit

Permalink
Merge pull request #68 from mewpull/wav-reader-no-closer
Browse files Browse the repository at this point in the history
flac,wav: relax Decode input to support io.Reader without Close method
  • Loading branch information
faiface authored Oct 26, 2019
2 parents 76df446 + 7249d75 commit b573886
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 38 deletions.
30 changes: 17 additions & 13 deletions flac/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,21 @@ import (
"github.com/pkg/errors"
)

// Decode takes a ReadCloser containing audio data in FLAC format and returns a StreamSeekCloser,
// which streams that audio. The Seek method will panic if rc is not io.Seeker.
// Decode takes a Reader containing audio data in FLAC format and returns a StreamSeekCloser,
// which streams that audio. The Seek method will panic if r is not io.Seeker.
//
// Do not close the supplied ReadSeekCloser, instead, use the Close method of the returned
// Do not close the supplied Reader, instead, use the Close method of the returned
// StreamSeekCloser when you want to release the resources.
func Decode(rc io.ReadCloser) (s beep.StreamSeekCloser, format beep.Format, err error) {
d := decoder{rc: rc}
defer func() { // hacky way to always close rc if an error occurred
if err != nil {
d.rc.Close()
func Decode(r io.Reader) (s beep.StreamSeekCloser, format beep.Format, err error) {
d := decoder{r: r}
defer func() { // hacky way to always close r if an error occurred
if closer, ok := d.r.(io.Closer); ok {
if err != nil {
closer.Close()
}
}
}()
d.stream, err = flac.New(rc)
d.stream, err = flac.New(r)
if err != nil {
return nil, beep.Format{}, errors.Wrap(err, "flac")
}
Expand All @@ -34,7 +36,7 @@ func Decode(rc io.ReadCloser) (s beep.StreamSeekCloser, format beep.Format, err
}

type decoder struct {
rc io.ReadCloser
r io.Reader
stream *flac.Stream
buf [][2]float64
pos int
Expand Down Expand Up @@ -141,9 +143,11 @@ func (d *decoder) Seek(p int) error {
}

func (d *decoder) Close() error {
err := d.rc.Close()
if err != nil {
return errors.Wrap(err, "flac")
if closer, ok := d.r.(io.Closer); ok {
err := closer.Close()
if err != nil {
return errors.Wrap(err, "flac")
}
}
return nil
}
54 changes: 29 additions & 25 deletions wav/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,34 @@ import (
"github.com/pkg/errors"
)

// Decode takes a ReadCloser containing audio data in WAVE format and returns a StreamSeekCloser,
// Decode takes a Reader containing audio data in WAVE format and returns a StreamSeekCloser,
// which streams that audio. The Seek method will panic if rc is not io.Seeker.
//
// Do not close the supplied ReadSeekCloser, instead, use the Close method of the returned
// Do not close the supplied Reader, instead, use the Close method of the returned
// StreamSeekCloser when you want to release the resources.
func Decode(rc io.ReadCloser) (s beep.StreamSeekCloser, format beep.Format, err error) {
d := decoder{rc: rc}
defer func() { // hacky way to always close rsc if an error occurred
if err != nil {
d.rc.Close()
func Decode(r io.Reader) (s beep.StreamSeekCloser, format beep.Format, err error) {
d := decoder{r: r}
defer func() { // hacky way to always close r if an error occurred
if closer, ok := d.r.(io.Closer); ok {
if err != nil {
closer.Close()
}
}
}()

// READ "RIFF" header
if err := binary.Read(rc, binary.LittleEndian, d.h.RiffMark[:]); err != nil {
if err := binary.Read(r, binary.LittleEndian, d.h.RiffMark[:]); err != nil {
return nil, beep.Format{}, errors.Wrap(err, "wav")
}
if string(d.h.RiffMark[:]) != "RIFF" {
return nil, beep.Format{}, fmt.Errorf("wav: missing RIFF at the beginning > %s", string(d.h.RiffMark[:]))
}

// READ Total file size
if err := binary.Read(rc, binary.LittleEndian, &d.h.FileSize); err != nil {
if err := binary.Read(r, binary.LittleEndian, &d.h.FileSize); err != nil {
return nil, beep.Format{}, errors.Wrap(err, "wav: missing RIFF file size")
}
if err := binary.Read(rc, binary.LittleEndian, d.h.WaveMark[:]); err != nil {
if err := binary.Read(r, binary.LittleEndian, d.h.WaveMark[:]); err != nil {
return nil, beep.Format{}, errors.Wrap(err, "wav: missing RIFF file type")
}
if string(d.h.WaveMark[:]) != "WAVE" {
Expand All @@ -48,17 +50,17 @@ func Decode(rc io.ReadCloser) (s beep.StreamSeekCloser, format beep.Format, err
var fs int32
d.hsz = 4 + 4 + 4 // add size of (RiffMark + FileSize + WaveMark)
for string(ft[:]) != "data" {
if err = binary.Read(rc, binary.LittleEndian, ft[:]); err != nil {
if err = binary.Read(r, binary.LittleEndian, ft[:]); err != nil {
return nil, beep.Format{}, errors.Wrap(err, "wav: missing chunk type")
}
switch {
case string(ft[:]) == "fmt ":
d.h.FmtMark = ft
if err := binary.Read(rc, binary.LittleEndian, &d.h.FormatSize); err != nil {
if err := binary.Read(r, binary.LittleEndian, &d.h.FormatSize); err != nil {
return nil, beep.Format{}, errors.New("wav: missing format chunk size")
}
d.hsz += 4 + 4 + d.h.FormatSize // add size of (FmtMark + FormatSize + its trailing size)
if err := binary.Read(rc, binary.LittleEndian, &d.h.FormatType); err != nil {
if err := binary.Read(r, binary.LittleEndian, &d.h.FormatType); err != nil {
return nil, beep.Format{}, errors.New("wav: missing format type")
}
if d.h.FormatType == -2 {
Expand All @@ -67,7 +69,7 @@ func Decode(rc io.ReadCloser) (s beep.StreamSeekCloser, format beep.Format, err
formatchunk{0, 0, 0, 0, 0}, 0, 0, 0,
guid{0, 0, 0, [8]byte{0, 0, 0, 0, 0, 0, 0, 0}},
}
if err := binary.Read(rc, binary.LittleEndian, &fmtchunk); err != nil {
if err := binary.Read(r, binary.LittleEndian, &fmtchunk); err != nil {
return nil, beep.Format{}, errors.New("wav: missing format chunk body")
}
d.h.NumChans = fmtchunk.NumChans
Expand All @@ -92,7 +94,7 @@ func Decode(rc io.ReadCloser) (s beep.StreamSeekCloser, format beep.Format, err
} else {
// WAVEFORMAT or WAVEFORMATEX
fmtchunk := formatchunk{0, 0, 0, 0, 0}
if err := binary.Read(rc, binary.LittleEndian, &fmtchunk); err != nil {
if err := binary.Read(r, binary.LittleEndian, &fmtchunk); err != nil {
return nil, beep.Format{}, errors.New("wav: missing format chunk body")
}
d.h.NumChans = fmtchunk.NumChans
Expand All @@ -104,23 +106,23 @@ func Decode(rc io.ReadCloser) (s beep.StreamSeekCloser, format beep.Format, err
// it would be skipping cbSize (WAVEFORMATEX's last member).
if d.h.FormatSize > 16 {
trash := make([]byte, d.h.FormatSize-16)
if err := binary.Read(rc, binary.LittleEndian, trash); err != nil {
if err := binary.Read(r, binary.LittleEndian, trash); err != nil {
return nil, beep.Format{}, errors.Wrap(err, "wav: missing extended format chunk body")
}
}
}
case string(ft[:]) == "data":
d.h.DataMark = ft
if err := binary.Read(rc, binary.LittleEndian, &d.h.DataSize); err != nil {
if err := binary.Read(r, binary.LittleEndian, &d.h.DataSize); err != nil {
return nil, beep.Format{}, errors.Wrap(err, "wav: missing data chunk size")
}
d.hsz += 4 + 4 //add size of (DataMark + DataSize)
default:
if err := binary.Read(rc, binary.LittleEndian, &fs); err != nil {
if err := binary.Read(r, binary.LittleEndian, &fs); err != nil {
return nil, beep.Format{}, errors.Wrap(err, "wav: missing unknown chunk size")
}
trash := make([]byte, fs)
if err := binary.Read(rc, binary.LittleEndian, trash); err != nil {
if err := binary.Read(r, binary.LittleEndian, trash); err != nil {
return nil, beep.Format{}, errors.Wrap(err, "wav: missing unknown chunk body")
}
d.hsz += 4 + fs //add size of (Unknown formtype + formsize)
Expand Down Expand Up @@ -190,7 +192,7 @@ type header struct {
}

type decoder struct {
rc io.ReadCloser
r io.Reader
h header
hsz int32
pos int32
Expand All @@ -207,7 +209,7 @@ func (d *decoder) Stream(samples [][2]float64) (n int, ok bool) {
numBytes = d.h.DataSize - d.pos
}
p := make([]byte, numBytes)
n, err := d.rc.Read(p)
n, err := d.r.Read(p)
if err != nil && err != io.EOF {
d.err = err
}
Expand Down Expand Up @@ -265,7 +267,7 @@ func (d *decoder) Position() int {
}

func (d *decoder) Seek(p int) error {
seeker, ok := d.rc.(io.Seeker)
seeker, ok := d.r.(io.Seeker)
if !ok {
panic(fmt.Errorf("wav: seek: resource is not io.Seeker"))
}
Expand All @@ -282,9 +284,11 @@ func (d *decoder) Seek(p int) error {
}

func (d *decoder) Close() error {
err := d.rc.Close()
if err != nil {
return errors.Wrap(err, "wav")
if closer, ok := d.r.(io.Closer); ok {
err := closer.Close()
if err != nil {
return errors.Wrap(err, "wav")
}
}
return nil
}

0 comments on commit b573886

Please sign in to comment.