Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rethinking the beep.Streamer interfaces #170

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion examples/doppler-stereo-room/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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))

Expand Down
4 changes: 4 additions & 0 deletions examples/midi/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
Expand Down
4 changes: 3 additions & 1 deletion examples/speedy-player/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down
2 changes: 1 addition & 1 deletion examples/tutorial/1-hello-beep/a/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down
2 changes: 1 addition & 1 deletion examples/tutorial/1-hello-beep/b/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
2 changes: 1 addition & 1 deletion examples/tutorial/2-composing-and-controlling/a/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down
2 changes: 1 addition & 1 deletion examples/tutorial/2-composing-and-controlling/b/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down
2 changes: 1 addition & 1 deletion examples/tutorial/2-composing-and-controlling/c/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down
2 changes: 1 addition & 1 deletion examples/tutorial/2-composing-and-controlling/d/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down
2 changes: 1 addition & 1 deletion examples/tutorial/3-to-buffer-or-not-to-buffer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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! ")
Expand Down
24 changes: 2 additions & 22 deletions flac/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
}
19 changes: 0 additions & 19 deletions interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
//
Expand Down
20 changes: 4 additions & 16 deletions midi/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,21 @@ 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
}

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")
Expand All @@ -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
}
Expand Down
31 changes: 10 additions & 21 deletions mp3/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -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
}
Expand All @@ -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) {
Expand Down Expand Up @@ -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
}
26 changes: 7 additions & 19 deletions vorbis/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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) {
Expand Down Expand Up @@ -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
}
Loading
Loading