From a9421de994266d8d752df53dbdc5d167ee0f1e35 Mon Sep 17 00:00:00 2001 From: Mark Kremer Date: Sun, 5 Nov 2023 16:55:07 +0100 Subject: [PATCH 1/6] Split Decode into DecodeStreamer and DecodeStreamSeeker for mp3 --- examples/doppler-stereo-room/main.go | 3 +- examples/speedy-player/main.go | 3 +- examples/tutorial/1-hello-beep/a/main.go | 2 +- examples/tutorial/1-hello-beep/b/main.go | 2 +- .../2-composing-and-controlling/a/main.go | 2 +- .../2-composing-and-controlling/b/main.go | 2 +- .../2-composing-and-controlling/c/main.go | 2 +- .../2-composing-and-controlling/d/main.go | 2 +- .../3-to-buffer-or-not-to-buffer/main.go | 2 +- .../tutorial/4-making-own-streamers/b/main.go | 2 +- mp3/decode.go | 88 ++++++++++++++----- mp3/decode_test.go | 2 +- 12 files changed, 80 insertions(+), 32 deletions(-) diff --git a/examples/doppler-stereo-room/main.go b/examples/doppler-stereo-room/main.go index a2dea27..e763653 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" @@ -161,7 +162,7 @@ func main() { if err != nil { report(err) } - streamer, format, err := mp3.Decode(f) + streamer, format, err := mp3.DecodeReader(f) if err != nil { report(err) } diff --git a/examples/speedy-player/main.go b/examples/speedy-player/main.go index 97bf5a7..d6720ee 100644 --- a/examples/speedy-player/main.go +++ b/examples/speedy-player/main.go @@ -7,6 +7,7 @@ import ( "unicode" "github.com/gdamore/tcell/v2" + "github.com/gopxl/beep" "github.com/gopxl/beep/effects" "github.com/gopxl/beep/mp3" @@ -151,7 +152,7 @@ func main() { if err != nil { report(err) } - streamer, format, err := mp3.Decode(f) + streamer, format, err := mp3.DecodeReadSeeker(f) if err != nil { report(err) } diff --git a/examples/tutorial/1-hello-beep/a/main.go b/examples/tutorial/1-hello-beep/a/main.go index a5f397d..3a9f52f 100644 --- a/examples/tutorial/1-hello-beep/a/main.go +++ b/examples/tutorial/1-hello-beep/a/main.go @@ -16,7 +16,7 @@ func main() { log.Fatal(err) } - streamer, format, err := mp3.Decode(f) + streamer, format, err := mp3.DecodeReader(f) if err != nil { log.Fatal(err) } diff --git a/examples/tutorial/1-hello-beep/b/main.go b/examples/tutorial/1-hello-beep/b/main.go index 0f56653..1b183cd 100644 --- a/examples/tutorial/1-hello-beep/b/main.go +++ b/examples/tutorial/1-hello-beep/b/main.go @@ -16,7 +16,7 @@ func main() { log.Fatal(err) } - streamer, format, err := mp3.Decode(f) + streamer, format, err := mp3.DecodeReader(f) if err != nil { log.Fatal(err) } diff --git a/examples/tutorial/2-composing-and-controlling/a/main.go b/examples/tutorial/2-composing-and-controlling/a/main.go index afcac2a..f879772 100644 --- a/examples/tutorial/2-composing-and-controlling/a/main.go +++ b/examples/tutorial/2-composing-and-controlling/a/main.go @@ -17,7 +17,7 @@ func main() { log.Fatal(err) } - streamer, format, err := mp3.Decode(f) + streamer, format, err := mp3.DecodeReader(f) if err != nil { log.Fatal(err) } diff --git a/examples/tutorial/2-composing-and-controlling/b/main.go b/examples/tutorial/2-composing-and-controlling/b/main.go index b959b73..f53d2d4 100644 --- a/examples/tutorial/2-composing-and-controlling/b/main.go +++ b/examples/tutorial/2-composing-and-controlling/b/main.go @@ -17,7 +17,7 @@ func main() { log.Fatal(err) } - streamer, format, err := mp3.Decode(f) + streamer, format, err := mp3.DecodeReadSeeker(f) if err != nil { log.Fatal(err) } diff --git a/examples/tutorial/2-composing-and-controlling/c/main.go b/examples/tutorial/2-composing-and-controlling/c/main.go index 7332ff4..a5713ae 100644 --- a/examples/tutorial/2-composing-and-controlling/c/main.go +++ b/examples/tutorial/2-composing-and-controlling/c/main.go @@ -17,7 +17,7 @@ func main() { log.Fatal(err) } - streamer, format, err := mp3.Decode(f) + streamer, format, err := mp3.DecodeReadSeeker(f) if err != nil { log.Fatal(err) } diff --git a/examples/tutorial/2-composing-and-controlling/d/main.go b/examples/tutorial/2-composing-and-controlling/d/main.go index 1a02c82..dafc033 100644 --- a/examples/tutorial/2-composing-and-controlling/d/main.go +++ b/examples/tutorial/2-composing-and-controlling/d/main.go @@ -18,7 +18,7 @@ func main() { log.Fatal(err) } - streamer, format, err := mp3.Decode(f) + streamer, format, err := mp3.DecodeReadSeeker(f) if err != nil { log.Fatal(err) } 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..06ac6a0 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 @@ -17,7 +17,7 @@ func main() { log.Fatal(err) } - streamer, format, err := mp3.Decode(f) + streamer, format, err := mp3.DecodeReader(f) if err != nil { log.Fatal(err) } diff --git a/examples/tutorial/4-making-own-streamers/b/main.go b/examples/tutorial/4-making-own-streamers/b/main.go index 89d1c78..f88c3b1 100644 --- a/examples/tutorial/4-making-own-streamers/b/main.go +++ b/examples/tutorial/4-making-own-streamers/b/main.go @@ -70,7 +70,7 @@ func main() { } // Decode it. - streamer, format, err := mp3.Decode(f) + streamer, format, err := mp3.DecodeReader(f) if err != nil { fmt.Println(err) continue diff --git a/mp3/decode.go b/mp3/decode.go index f56c8d3..475e36f 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 ( @@ -21,22 +22,63 @@ const ( // // 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) { - defer func() { - if err != nil { - err = errors.Wrap(err, "mp3") - } - }() - d, err := gomp3.NewDecoder(rc) +// +// Deprecated: Decode has been replaced with DecodeReader and DecodeReadSeeker. +func Decode(rc io.ReadCloser) (ssc beep.StreamSeekCloser, format beep.Format, err error) { + sc, format, err := DecodeReader(rc) if err != nil { return nil, beep.Format{}, err } + + // Even though rc may not be an io.Seeker, Decode will return a Seeker for backward compatibility. + ssc = &seekWrapper{ + decoder: *sc.(*decoder), + } + return +} + +// DecodeReader takes an io.ReadCloser containing audio data in MP3 format and returns a beep.StreamCloser, +// which streams that audio. See DecodeReadSeeker when Len() and Seek() functionality is required. +// +// Do not close the supplied StreamCloser, instead, use the Close method of the returned +// StreamSeekCloser when you want to release the resources. +func DecodeReader(r io.ReadCloser) (sc beep.StreamCloser, format beep.Format, err error) { + d, err := gomp3.NewDecoder(r) + if err != nil { + return nil, beep.Format{}, errors.Wrap(err, "mp3") + } + format = beep.Format{ SampleRate: beep.SampleRate(d.SampleRate()), NumChannels: gomp3NumChannels, Precision: gomp3Precision, } - return &decoder{rc, d, format, 0, nil}, format, nil + sc = &decoder{ + closer: r, + d: d, + f: format, + pos: 0, + err: nil, + } + return +} + +// DecodeReadSeeker takes an ReadSeekCloser containing audio data in MP3 format and returns a beep.StreamSeekCloser, +// which streams that audio. See DecodeReader when the io.Reader isn't seekable. +// +// Do not close the supplied StreamCloser, instead, use the Close method of the returned +// StreamSeekCloser when you want to release the resources. +func DecodeReadSeeker(rc io.ReadSeekCloser) (ssc beep.StreamSeekCloser, format beep.Format, err error) { + var sc beep.StreamCloser + sc, format, err = DecodeReader(rc) + if err != nil { + return nil, beep.Format{}, err + } + + ssc = &seekWrapper{ + decoder: *sc.(*decoder), + } + return } type decoder struct { @@ -75,30 +117,34 @@ func (d *decoder) Err() error { return d.err } -func (d *decoder) Len() int { - return int(d.d.Length()) / gomp3BytesPerFrame -} - func (d *decoder) Position() int { return d.pos / gomp3BytesPerFrame } -func (d *decoder) Seek(p int) error { - if p < 0 || d.Len() < p { - return fmt.Errorf("mp3: seek position %v out of range [%v, %v]", p, 0, d.Len()) - } - _, err := d.d.Seek(int64(p)*gomp3BytesPerFrame, io.SeekStart) +func (d *decoder) Close() error { + err := d.closer.Close() if err != nil { return errors.Wrap(err, "mp3") } - d.pos = p * gomp3BytesPerFrame return nil } -func (d *decoder) Close() error { - err := d.closer.Close() +type seekWrapper struct { + decoder +} + +func (d *seekWrapper) Len() int { + return int(d.d.Length()) / gomp3BytesPerFrame +} + +func (d *seekWrapper) Seek(p int) error { + if p < 0 || d.Len() < p { + return fmt.Errorf("mp3: seek position %v out of range [%v, %v]", p, 0, d.Len()) + } + _, err := d.d.Seek(int64(p)*gomp3BytesPerFrame, io.SeekStart) if err != nil { return errors.Wrap(err, "mp3") } + d.pos = p * gomp3BytesPerFrame return nil } diff --git a/mp3/decode_test.go b/mp3/decode_test.go index 3384f7e..c350bee 100644 --- a/mp3/decode_test.go +++ b/mp3/decode_test.go @@ -15,7 +15,7 @@ func TestDecoder_ReturnBehaviour(t *testing.T) { assert.NoError(t, err) defer f.Close() - s, _, err := mp3.Decode(f) + s, _, err := mp3.DecodeReadSeeker(f) assert.NoError(t, err) // The length of the streamer isn't tested because mp3 files have // a different padding depending on the decoder used. From 54c78174d81b185fbbdc26e0d61986d7a3918529 Mon Sep 17 00:00:00 2001 From: Mark Kremer Date: Tue, 28 Nov 2023 21:25:27 +0100 Subject: [PATCH 2/6] Return structs instead of interfaces from mp3 decode functions --- mp3/decode.go | 77 ++++++++++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 34 deletions(-) diff --git a/mp3/decode.go b/mp3/decode.go index 475e36f..defa935 100644 --- a/mp3/decode.go +++ b/mp3/decode.go @@ -24,17 +24,14 @@ const ( // StreamSeekCloser when you want to release the resources. // // Deprecated: Decode has been replaced with DecodeReader and DecodeReadSeeker. -func Decode(rc io.ReadCloser) (ssc beep.StreamSeekCloser, format beep.Format, err error) { - sc, format, err := DecodeReader(rc) +func Decode(rc io.ReadCloser) (beep.StreamSeekCloser, beep.Format, error) { + d, format, err := DecodeReader(rc) if err != nil { return nil, beep.Format{}, err } // Even though rc may not be an io.Seeker, Decode will return a Seeker for backward compatibility. - ssc = &seekWrapper{ - decoder: *sc.(*decoder), - } - return + return &SeekableDecoder{d: *d}, format, nil } // DecodeReader takes an io.ReadCloser containing audio data in MP3 format and returns a beep.StreamCloser, @@ -42,25 +39,25 @@ func Decode(rc io.ReadCloser) (ssc beep.StreamSeekCloser, format beep.Format, er // // Do not close the supplied StreamCloser, instead, use the Close method of the returned // StreamSeekCloser when you want to release the resources. -func DecodeReader(r io.ReadCloser) (sc beep.StreamCloser, format beep.Format, err error) { - d, err := gomp3.NewDecoder(r) +func DecodeReader(r io.ReadCloser) (*Decoder, beep.Format, error) { + decoder, err := gomp3.NewDecoder(r) if err != nil { return nil, beep.Format{}, errors.Wrap(err, "mp3") } - format = beep.Format{ - SampleRate: beep.SampleRate(d.SampleRate()), + format := beep.Format{ + SampleRate: beep.SampleRate(decoder.SampleRate()), NumChannels: gomp3NumChannels, Precision: gomp3Precision, } - sc = &decoder{ + d := &Decoder{ closer: r, - d: d, + d: decoder, f: format, pos: 0, err: nil, } - return + return d, format, nil } // DecodeReadSeeker takes an ReadSeekCloser containing audio data in MP3 format and returns a beep.StreamSeekCloser, @@ -68,20 +65,16 @@ func DecodeReader(r io.ReadCloser) (sc beep.StreamCloser, format beep.Format, er // // Do not close the supplied StreamCloser, instead, use the Close method of the returned // StreamSeekCloser when you want to release the resources. -func DecodeReadSeeker(rc io.ReadSeekCloser) (ssc beep.StreamSeekCloser, format beep.Format, err error) { - var sc beep.StreamCloser - sc, format, err = DecodeReader(rc) +func DecodeReadSeeker(rc io.ReadSeekCloser) (*SeekableDecoder, beep.Format, error) { + d, format, err := DecodeReader(rc) if err != nil { return nil, beep.Format{}, err } - ssc = &seekWrapper{ - decoder: *sc.(*decoder), - } - return + return &SeekableDecoder{d: *d}, format, nil } -type decoder struct { +type Decoder struct { closer io.Closer d *gomp3.Decoder f beep.Format @@ -89,7 +82,7 @@ type decoder struct { err error } -func (d *decoder) Stream(samples [][2]float64) (n int, ok bool) { +func (d *Decoder) Stream(samples [][2]float64) (n int, ok bool) { if d.err != nil { return 0, false } @@ -113,15 +106,15 @@ func (d *decoder) Stream(samples [][2]float64) (n int, ok bool) { return n, ok } -func (d *decoder) Err() error { +func (d *Decoder) Err() error { return d.err } -func (d *decoder) Position() int { +func (d *Decoder) Position() int { return d.pos / gomp3BytesPerFrame } -func (d *decoder) Close() error { +func (d *Decoder) Close() error { err := d.closer.Close() if err != nil { return errors.Wrap(err, "mp3") @@ -129,22 +122,38 @@ func (d *decoder) Close() error { return nil } -type seekWrapper struct { - decoder +type SeekableDecoder struct { + d Decoder +} + +func (sd *SeekableDecoder) Stream(samples [][2]float64) (n int, ok bool) { + return sd.d.Stream(samples) +} + +func (sd *SeekableDecoder) Err() error { + return sd.d.Err() +} + +func (sd *SeekableDecoder) Position() int { + return sd.d.Position() +} + +func (sd *SeekableDecoder) Close() error { + return sd.d.Close() } -func (d *seekWrapper) Len() int { - return int(d.d.Length()) / gomp3BytesPerFrame +func (sd *SeekableDecoder) Len() int { + return int(sd.d.d.Length()) / gomp3BytesPerFrame } -func (d *seekWrapper) Seek(p int) error { - if p < 0 || d.Len() < p { - return fmt.Errorf("mp3: seek position %v out of range [%v, %v]", p, 0, d.Len()) +func (sd *SeekableDecoder) Seek(p int) error { + if p < 0 || sd.Len() < p { + return fmt.Errorf("mp3: seek position %v out of range [%v, %v]", p, 0, sd.Len()) } - _, err := d.d.Seek(int64(p)*gomp3BytesPerFrame, io.SeekStart) + _, err := sd.d.d.Seek(int64(p)*gomp3BytesPerFrame, io.SeekStart) if err != nil { return errors.Wrap(err, "mp3") } - d.pos = p * gomp3BytesPerFrame + sd.d.pos = p * gomp3BytesPerFrame return nil } From a0abee30d8c7668792dc98418d8e12ecae68df7c Mon Sep 17 00:00:00 2001 From: Mark Kremer Date: Wed, 29 Nov 2023 14:01:57 +0100 Subject: [PATCH 3/6] Improve Flac decoder.Seek doc comment --- flac/decode.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flac/decode.go b/flac/decode.go index 324172b..f787fd9 100644 --- a/flac/decode.go +++ b/flac/decode.go @@ -151,7 +151,7 @@ func (d *decoder) Position() int { return d.pos } -// p represents flac sample num perhaps? +// Seek seeks to the start of the frame containing the given absolute sample number. func (d *decoder) Seek(p int) error { if !d.seekEnabled { return errors.New("flac.decoder.Seek: not enabled") From 9d146b6ebc1897cb985bb601bf735c24a0794325 Mon Sep 17 00:00:00 2001 From: Mark Kremer Date: Wed, 29 Nov 2023 14:21:15 +0100 Subject: [PATCH 4/6] Return structs instead of interfaces from flac decode functions --- flac/decode.go | 123 +++++++++++++++++++++++++++++++------------- flac/decode_test.go | 2 +- 2 files changed, 89 insertions(+), 36 deletions(-) diff --git a/flac/decode.go b/flac/decode.go index f787fd9..e13b3b3 100644 --- a/flac/decode.go +++ b/flac/decode.go @@ -15,36 +15,57 @@ import ( // // 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) { - 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() - } - } - }() +// +// Deprecated: Decode has been replaced with DecodeReader and DecodeReadSeeker. +func Decode(r io.Reader) (beep.StreamSeekCloser, beep.Format, error) { + d := SeekableDecoder{d: Decoder{r: r}} + var err error rs, seeker := r.(io.ReadSeeker) if seeker { - d.stream, err = flac.NewSeek(rs) - d.seekEnabled = true + d.d.stream, err = flac.NewSeek(rs) + d.d.seekEnabled = true } else { - d.stream, err = flac.New(r) + d.d.stream, err = flac.New(r) } if err != nil { + if closer, ok := r.(io.Closer); ok { + if err != nil { + closer.Close() + } + } return nil, beep.Format{}, errors.Wrap(err, "flac") } - format = beep.Format{ - SampleRate: beep.SampleRate(d.stream.Info.SampleRate), - NumChannels: int(d.stream.Info.NChannels), - Precision: int(d.stream.Info.BitsPerSample / 8), + + return &d, d.d.format(), nil +} + +func DecodeReader(r io.ReadCloser) (*Decoder, beep.Format, error) { + d := Decoder{r: r} + var err error + d.stream, err = flac.New(r) + if err != nil { + r.Close() + return nil, beep.Format{}, errors.Wrap(err, "flac") + } + + return &d, d.format(), nil +} + +func DecodeReadSeeker(r io.ReadSeekCloser) (*SeekableDecoder, beep.Format, error) { + d := SeekableDecoder{d: Decoder{r: r, seekEnabled: true}} + var err error + d.d.stream, err = flac.NewSeek(r) + if err != nil { + r.Close() + return nil, beep.Format{}, errors.Wrap(err, "flac") } - return &d, format, nil + + return &d, d.d.format(), nil } -type decoder struct { +type Decoder struct { r io.Reader stream *flac.Stream buf [][2]float64 @@ -53,7 +74,7 @@ type decoder struct { seekEnabled bool } -func (d *decoder) Stream(samples [][2]float64) (n int, ok bool) { +func (d *Decoder) Stream(samples [][2]float64) (n int, ok bool) { if d.err != nil { return 0, false } @@ -82,7 +103,7 @@ func (d *decoder) Stream(samples [][2]float64) (n int, ok bool) { } // refill decodes audio samples to fill the decode buffer. -func (d *decoder) refill() error { +func (d *Decoder) refill() error { // Empty buffer. d.buf = d.buf[:0] // Parse audio frame. @@ -139,30 +160,19 @@ func (d *decoder) refill() error { return nil } -func (d *decoder) Err() error { +func (d *Decoder) Err() error { return d.err } -func (d *decoder) Len() int { +func (d *Decoder) Len() int { return int(d.stream.Info.NSamples) } -func (d *decoder) Position() int { +func (d *Decoder) Position() int { return d.pos } -// Seek seeks to the start of the frame containing the given absolute sample number. -func (d *decoder) Seek(p int) error { - if !d.seekEnabled { - return errors.New("flac.decoder.Seek: not enabled") - } - - pos, err := d.stream.Seek(uint64(p)) - d.pos = int(pos) - return err -} - -func (d *decoder) Close() error { +func (d *Decoder) Close() error { if closer, ok := d.r.(io.Closer); ok { err := closer.Close() if err != nil { @@ -171,3 +181,46 @@ func (d *decoder) Close() error { } return nil } + +func (d *Decoder) format() beep.Format { + return beep.Format{ + SampleRate: beep.SampleRate(d.stream.Info.SampleRate), + NumChannels: int(d.stream.Info.NChannels), + Precision: int(d.stream.Info.BitsPerSample / 8), + } +} + +type SeekableDecoder struct { + d Decoder +} + +func (sd *SeekableDecoder) Stream(samples [][2]float64) (n int, ok bool) { + return sd.d.Stream(samples) +} + +func (sd *SeekableDecoder) Err() error { + return sd.d.Err() +} + +func (sd *SeekableDecoder) Len() int { + return sd.d.Len() +} + +func (sd *SeekableDecoder) Position() int { + return sd.d.Position() +} + +func (sd *SeekableDecoder) Close() error { + return sd.d.Close() +} + +// Seek seeks to the start of the frame containing the given absolute sample number. +func (sd *SeekableDecoder) Seek(p int) error { + if !sd.d.seekEnabled { + return errors.New("flac.decoder.Seek: not enabled") + } + + pos, err := sd.d.stream.Seek(uint64(p)) + sd.d.pos = int(pos) + return err +} diff --git a/flac/decode_test.go b/flac/decode_test.go index 6fb16fe..08deeb6 100644 --- a/flac/decode_test.go +++ b/flac/decode_test.go @@ -15,7 +15,7 @@ func TestDecoder_ReturnBehaviour(t *testing.T) { assert.NoError(t, err) defer f.Close() - s, _, err := flac.Decode(f) + s, _, err := flac.DecodeReadSeeker(f) assert.NoError(t, err) assert.Equal(t, 22050, s.Len()) From 02692d8a784de5b118f4490e35a9032b41781d92 Mon Sep 17 00:00:00 2001 From: Mark Kremer Date: Wed, 29 Nov 2023 14:21:55 +0100 Subject: [PATCH 5/6] Rename mp3.DecodeReadSeeker argument --- mp3/decode.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mp3/decode.go b/mp3/decode.go index defa935..49bcf4f 100644 --- a/mp3/decode.go +++ b/mp3/decode.go @@ -65,8 +65,8 @@ func DecodeReader(r io.ReadCloser) (*Decoder, beep.Format, error) { // // Do not close the supplied StreamCloser, instead, use the Close method of the returned // StreamSeekCloser when you want to release the resources. -func DecodeReadSeeker(rc io.ReadSeekCloser) (*SeekableDecoder, beep.Format, error) { - d, format, err := DecodeReader(rc) +func DecodeReadSeeker(r io.ReadSeekCloser) (*SeekableDecoder, beep.Format, error) { + d, format, err := DecodeReader(r) if err != nil { return nil, beep.Format{}, err } From 97f077f52807b2772fe9697da359ada3149db191 Mon Sep 17 00:00:00 2001 From: Mark Kremer Date: Wed, 29 Nov 2023 14:26:32 +0100 Subject: [PATCH 6/6] Remove redundant error check --- flac/decode.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/flac/decode.go b/flac/decode.go index e13b3b3..e5aa621 100644 --- a/flac/decode.go +++ b/flac/decode.go @@ -31,9 +31,7 @@ func Decode(r io.Reader) (beep.StreamSeekCloser, beep.Format, error) { if err != nil { if closer, ok := r.(io.Closer); ok { - if err != nil { - closer.Close() - } + closer.Close() } return nil, beep.Format{}, errors.Wrap(err, "flac") }