diff --git a/examples/doppler-stereo-room/main.go b/examples/doppler-stereo-room/main.go index a2dea27..969ff93 100644 --- a/examples/doppler-stereo-room/main.go +++ b/examples/doppler-stereo-room/main.go @@ -8,6 +8,7 @@ import ( "unicode" "github.com/gdamore/tcell/v2" + "github.com/gopxl/beep" "github.com/gopxl/beep/effects" "github.com/gopxl/beep/mp3" @@ -157,15 +158,17 @@ func main() { fmt.Fprintf(os.Stderr, "Usage: %s song.mp3\n", os.Args[0]) os.Exit(1) } + f, err := os.Open(os.Args[1]) if err != nil { report(err) } + defer f.Close() + streamer, format, err := mp3.Decode(f) if err != nil { report(err) } - defer streamer.Close() speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/30)) diff --git a/examples/midi/main.go b/examples/midi/main.go index b7bb837..ac9fd55 100644 --- a/examples/midi/main.go +++ b/examples/midi/main.go @@ -24,6 +24,8 @@ func main() { if err != nil { log.Fatal(err) } + defer soundFontFile.Close() + soundFont, err := midi.NewSoundFont(soundFontFile) if err != nil { log.Fatal(err) @@ -34,6 +36,8 @@ func main() { if err != nil { log.Fatal(err) } + defer midiFile.Close() + s, format, err := midi.Decode(midiFile, soundFont, sampleRate) if err != nil { log.Fatal(err) diff --git a/examples/speedy-player/main.go b/examples/speedy-player/main.go index bf199d6..ad4a529 100644 --- a/examples/speedy-player/main.go +++ b/examples/speedy-player/main.go @@ -156,15 +156,17 @@ func main() { fmt.Fprintf(os.Stderr, "Usage: %s song.mp3\n", os.Args[0]) os.Exit(1) } + f, err := os.Open(os.Args[1]) if err != nil { report(err) } + defer f.Close() + streamer, format, err := mp3.Decode(f) if err != nil { report(err) } - defer streamer.Close() speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/30)) diff --git a/examples/tutorial/1-hello-beep/a/main.go b/examples/tutorial/1-hello-beep/a/main.go index a5f397d..837365e 100644 --- a/examples/tutorial/1-hello-beep/a/main.go +++ b/examples/tutorial/1-hello-beep/a/main.go @@ -15,12 +15,12 @@ func main() { if err != nil { log.Fatal(err) } + defer f.Close() streamer, format, err := mp3.Decode(f) if err != nil { log.Fatal(err) } - defer streamer.Close() speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10)) diff --git a/examples/tutorial/1-hello-beep/b/main.go b/examples/tutorial/1-hello-beep/b/main.go index 0f56653..16e6e2a 100644 --- a/examples/tutorial/1-hello-beep/b/main.go +++ b/examples/tutorial/1-hello-beep/b/main.go @@ -15,12 +15,12 @@ func main() { if err != nil { log.Fatal(err) } + defer f.Close() streamer, format, err := mp3.Decode(f) if err != nil { log.Fatal(err) } - defer streamer.Close() sr := format.SampleRate * 2 speaker.Init(sr, sr.N(time.Second/10)) diff --git a/examples/tutorial/2-composing-and-controlling/a/main.go b/examples/tutorial/2-composing-and-controlling/a/main.go index afcac2a..ada06ad 100644 --- a/examples/tutorial/2-composing-and-controlling/a/main.go +++ b/examples/tutorial/2-composing-and-controlling/a/main.go @@ -16,12 +16,12 @@ func main() { if err != nil { log.Fatal(err) } + defer f.Close() streamer, format, err := mp3.Decode(f) if err != nil { log.Fatal(err) } - defer streamer.Close() speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10)) diff --git a/examples/tutorial/2-composing-and-controlling/b/main.go b/examples/tutorial/2-composing-and-controlling/b/main.go index b959b73..5855258 100644 --- a/examples/tutorial/2-composing-and-controlling/b/main.go +++ b/examples/tutorial/2-composing-and-controlling/b/main.go @@ -16,12 +16,12 @@ func main() { if err != nil { log.Fatal(err) } + defer f.Close() streamer, format, err := mp3.Decode(f) if err != nil { log.Fatal(err) } - defer streamer.Close() speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10)) diff --git a/examples/tutorial/2-composing-and-controlling/c/main.go b/examples/tutorial/2-composing-and-controlling/c/main.go index 7332ff4..9116dc3 100644 --- a/examples/tutorial/2-composing-and-controlling/c/main.go +++ b/examples/tutorial/2-composing-and-controlling/c/main.go @@ -16,12 +16,12 @@ func main() { if err != nil { log.Fatal(err) } + defer f.Close() streamer, format, err := mp3.Decode(f) if err != nil { log.Fatal(err) } - defer streamer.Close() speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10)) diff --git a/examples/tutorial/2-composing-and-controlling/d/main.go b/examples/tutorial/2-composing-and-controlling/d/main.go index 1a02c82..6f72558 100644 --- a/examples/tutorial/2-composing-and-controlling/d/main.go +++ b/examples/tutorial/2-composing-and-controlling/d/main.go @@ -17,12 +17,12 @@ func main() { if err != nil { log.Fatal(err) } + defer f.Close() streamer, format, err := mp3.Decode(f) if err != nil { log.Fatal(err) } - defer streamer.Close() speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/10)) diff --git a/examples/tutorial/3-to-buffer-or-not-to-buffer/main.go b/examples/tutorial/3-to-buffer-or-not-to-buffer/main.go index 29ae85c..a69ca34 100644 --- a/examples/tutorial/3-to-buffer-or-not-to-buffer/main.go +++ b/examples/tutorial/3-to-buffer-or-not-to-buffer/main.go @@ -26,7 +26,7 @@ func main() { buffer := beep.NewBuffer(format) buffer.Append(streamer) - streamer.Close() + f.Close() for { fmt.Print("Press [ENTER] to fire a gunshot! ") diff --git a/flac/decode.go b/flac/decode.go index 324172b..1ec707f 100644 --- a/flac/decode.go +++ b/flac/decode.go @@ -10,20 +10,10 @@ import ( "github.com/gopxl/beep" ) -// Decode takes a Reader containing audio data in FLAC format and returns a StreamSeekCloser, +// Decode takes an io.Reader containing audio data in FLAC format and returns a StreamSeeker, // which streams that audio. The Seek method will panic if r is not io.Seeker. -// -// Do not close the supplied Reader, instead, use the Close method of the returned -// StreamSeekCloser when you want to release the resources. -func Decode(r io.Reader) (s beep.StreamSeekCloser, format beep.Format, err error) { +func Decode(r io.Reader) (s beep.StreamSeeker, 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() - } - } - }() rs, seeker := r.(io.ReadSeeker) if seeker { @@ -161,13 +151,3 @@ func (d *decoder) Seek(p int) error { d.pos = int(pos) return err } - -func (d *decoder) Close() error { - if closer, ok := d.r.(io.Closer); ok { - err := closer.Close() - if err != nil { - return errors.Wrap(err, "flac") - } - } - return nil -} diff --git a/interface.go b/interface.go index 93ab4f1..954adde 100644 --- a/interface.go +++ b/interface.go @@ -62,25 +62,6 @@ type StreamSeeker interface { Seek(p int) error } -// StreamCloser is a Streamer streaming from a resource which needs to be released, such as a file -// or a network connection. -type StreamCloser interface { - Streamer - - // Close closes the Streamer and releases it's resources. Streamer will no longer stream any - // samples. - Close() error -} - -// StreamSeekCloser is a union of StreamSeeker and StreamCloser. -type StreamSeekCloser interface { - Streamer - Len() int - Position() int - Seek(p int) error - Close() error -} - // StreamerFunc is a Streamer created by simply wrapping a streaming function (usually a closure, // which encloses a time tracking variable). This sometimes simplifies creating new streamers. // diff --git a/midi/decode.go b/midi/decode.go index 057e5c7..6ec05f0 100644 --- a/midi/decode.go +++ b/midi/decode.go @@ -17,17 +17,11 @@ const ( ) // NewSoundFont reads a sound font containing instruments. A sound font is required in order to play MIDI files. -// -// NewSoundFont closes the supplied ReadCloser. -func NewSoundFont(r io.ReadCloser) (*SoundFont, error) { +func NewSoundFont(r io.Reader) (*SoundFont, error) { sf, err := meltysynth.NewSoundFont(r) if err != nil { return nil, err } - err = r.Close() - if err != nil { - return nil, err - } return &SoundFont{sf}, nil } @@ -35,11 +29,9 @@ type SoundFont struct { sf *meltysynth.SoundFont } -// Decode takes a ReadCloser containing audio data in MIDI format and a SoundFont to synthesize the sounds +// Decode takes an io.Reader containing audio data in MIDI format and a SoundFont to synthesize the sounds // and returns a beep.StreamSeeker, which streams the audio. -// -// Decode closes the supplied ReadCloser. -func Decode(rc io.ReadCloser, sf *SoundFont, sampleRate beep.SampleRate) (s beep.StreamSeeker, format beep.Format, err error) { +func Decode(r io.Reader, sf *SoundFont, sampleRate beep.SampleRate) (s beep.StreamSeeker, format beep.Format, err error) { defer func() { if err != nil { err = errors.Wrap(err, "midi") @@ -52,11 +44,7 @@ func Decode(rc io.ReadCloser, sf *SoundFont, sampleRate beep.SampleRate) (s beep return nil, beep.Format{}, err } - mf, err := meltysynth.NewMidiFile(rc) - if err != nil { - return nil, beep.Format{}, err - } - err = rc.Close() + mf, err := meltysynth.NewMidiFile(r) if err != nil { return nil, beep.Format{}, err } diff --git a/mp3/decode.go b/mp3/decode.go index f56c8d3..3d7de72 100644 --- a/mp3/decode.go +++ b/mp3/decode.go @@ -5,9 +5,10 @@ import ( "fmt" "io" - "github.com/gopxl/beep" gomp3 "github.com/hajimehoshi/go-mp3" "github.com/pkg/errors" + + "github.com/gopxl/beep" ) const ( @@ -16,18 +17,15 @@ const ( gomp3BytesPerFrame = gomp3NumChannels * gomp3Precision ) -// Decode takes a ReadCloser containing audio data in MP3 format and returns a StreamSeekCloser, +// Decode takes an io.Reader containing audio data in MP3 format and returns a StreamSeeker, // 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 -// StreamSeekCloser when you want to release the resources. -func Decode(rc io.ReadCloser) (s beep.StreamSeekCloser, format beep.Format, err error) { +func Decode(r io.Reader) (s beep.StreamSeeker, format beep.Format, err error) { defer func() { if err != nil { err = errors.Wrap(err, "mp3") } }() - d, err := gomp3.NewDecoder(rc) + d, err := gomp3.NewDecoder(r) if err != nil { return nil, beep.Format{}, err } @@ -36,15 +34,14 @@ func Decode(rc io.ReadCloser) (s beep.StreamSeekCloser, format beep.Format, err NumChannels: gomp3NumChannels, Precision: gomp3Precision, } - return &decoder{rc, d, format, 0, nil}, format, nil + return &decoder{d, format, 0, nil}, format, nil } type decoder struct { - closer io.Closer - d *gomp3.Decoder - f beep.Format - pos int - err error + d *gomp3.Decoder + f beep.Format + pos int + err error } func (d *decoder) Stream(samples [][2]float64) (n int, ok bool) { @@ -94,11 +91,3 @@ func (d *decoder) Seek(p int) error { d.pos = p * gomp3BytesPerFrame return nil } - -func (d *decoder) Close() error { - err := d.closer.Close() - if err != nil { - return errors.Wrap(err, "mp3") - } - return nil -} diff --git a/vorbis/decode.go b/vorbis/decode.go index e2ebd7d..98cf677 100644 --- a/vorbis/decode.go +++ b/vorbis/decode.go @@ -14,18 +14,15 @@ const ( govorbisPrecision = 2 ) -// Decode takes a ReadCloser containing audio data in ogg/vorbis format and returns a StreamSeekCloser, +// Decode takes an io.Reader containing audio data in ogg/vorbis format and returns a StreamSeeker, // 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 -// StreamSeekCloser when you want to release the resources. -func Decode(rc io.ReadCloser) (s beep.StreamSeekCloser, format beep.Format, err error) { +func Decode(r io.Reader) (s beep.StreamSeeker, format beep.Format, err error) { defer func() { if err != nil { err = errors.Wrap(err, "ogg/vorbis") } }() - d, err := oggvorbis.NewReader(rc) + d, err := oggvorbis.NewReader(r) if err != nil { return nil, beep.Format{}, err } @@ -41,14 +38,13 @@ func Decode(rc io.ReadCloser) (s beep.StreamSeekCloser, format beep.Format, err Precision: govorbisPrecision, } - return &decoder{rc, d, make([]float32, d.Channels()), nil}, format, nil + return &decoder{d, make([]float32, d.Channels()), nil}, format, nil } type decoder struct { - closer io.Closer - d *oggvorbis.Reader - tmp []float32 - err error + d *oggvorbis.Reader + tmp []float32 + err error } func (d *decoder) Stream(samples [][2]float64) (n int, ok bool) { @@ -123,11 +119,3 @@ func (d *decoder) Seek(p int) error { } return nil } - -func (d *decoder) Close() error { - err := d.closer.Close() - if err != nil { - return errors.Wrap(err, "ogg/vorbis") - } - return nil -} diff --git a/wav/decode.go b/wav/decode.go index c52fa8f..529c643 100644 --- a/wav/decode.go +++ b/wav/decode.go @@ -7,24 +7,15 @@ import ( "io" "time" - "github.com/gopxl/beep" "github.com/pkg/errors" + + "github.com/gopxl/beep" ) -// Decode takes a Reader containing audio data in WAVE format and returns a StreamSeekCloser, +// Decode takes an io.Reader containing audio data in WAVE format and returns a StreamSeeker, // which streams that audio. The Seek method will panic if rc is not io.Seeker. -// -// Do not close the supplied Reader, instead, use the Close method of the returned -// StreamSeekCloser when you want to release the resources. -func Decode(r io.Reader) (s beep.StreamSeekCloser, format beep.Format, err error) { +func Decode(r io.Reader) (s beep.StreamSeeker, 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(r, binary.LittleEndian, d.h.RiffMark[:]); err != nil { @@ -285,13 +276,3 @@ func (d *decoder) Seek(p int) error { d.pos = pos return nil } - -func (d *decoder) Close() error { - if closer, ok := d.r.(io.Closer); ok { - err := closer.Close() - if err != nil { - return errors.Wrap(err, "wav") - } - } - return nil -}