diff --git a/audio/compositors.go b/audio/compositors.go
deleted file mode 100644
index 2d2b89bc812b8dfd28f3c4ae1c26638d3344a3ac..0000000000000000000000000000000000000000
--- a/audio/compositors.go
+++ /dev/null
@@ -1,102 +0,0 @@
-package audio
-
-import (
-	"math"
-	"time"
-)
-
-// Take returns a Streamer which streams s for at most d duration.
-//
-// The returned Streamer propagates s's errors throught Err.
-func Take(d time.Duration, s Streamer) Streamer {
-	return &take{
-		s:          s,
-		currSample: 0,
-		numSamples: int(math.Ceil(d.Seconds() * SampleRate)),
-	}
-}
-
-type take struct {
-	s          Streamer
-	currSample int
-	numSamples int
-}
-
-func (t *take) Stream(samples [][2]float64) (n int, ok bool) {
-	if t.currSample >= t.numSamples {
-		return 0, false
-	}
-	toStream := t.numSamples - t.currSample
-	if len(samples) < toStream {
-		toStream = len(samples)
-	}
-	n, ok = t.s.Stream(samples[:toStream])
-	t.currSample += n
-	return n, ok
-}
-
-func (t *take) Err() error {
-	return t.s.Err()
-}
-
-// Seq takes zero or more Streamers and returns a Streamer which streams them one by one without pauses.
-//
-// Seq does not propagate errors from the Streamers.
-func Seq(s ...Streamer) Streamer {
-	i := 0
-	return StreamerFunc(func(samples [][2]float64) (n int, ok bool) {
-		for i < len(s) && len(samples) > 0 {
-			sn, sok := s[i].Stream(samples)
-			samples = samples[sn:]
-			n, ok = n+sn, ok || sok
-			if !sok {
-				i++
-			}
-		}
-		return n, ok
-	})
-}
-
-// Mix takes zero or more Streamers and returns a Streamer which streames them mixed together.
-//
-// Mix does not propagate errors from the Streamers.
-func Mix(s ...Streamer) Streamer {
-	return StreamerFunc(func(samples [][2]float64) (n int, ok bool) {
-		var tmp [512][2]float64
-
-		for len(samples) > 0 {
-			toStream := len(tmp)
-			if toStream > len(samples) {
-				toStream = len(samples)
-			}
-
-			// clear the samples
-			for i := range samples[:toStream] {
-				samples[i] = [2]float64{}
-			}
-
-			snMax := 0 // max number of streamed samples in this iteration
-			for _, st := range s {
-				// mix the stream
-				sn, sok := st.Stream(tmp[:toStream])
-				if sn > snMax {
-					snMax = sn
-				}
-				ok = ok || sok
-
-				for i := range tmp[:sn] {
-					samples[i][0] += tmp[i][0]
-					samples[i][1] += tmp[i][1]
-				}
-			}
-
-			n += snMax
-			if snMax < len(tmp) {
-				break
-			}
-			samples = samples[snMax:]
-		}
-
-		return n, ok
-	})
-}
diff --git a/audio/compositors_test.go b/audio/compositors_test.go
deleted file mode 100644
index 6842d8920104c142f550827bfd4ecc822bccc53d..0000000000000000000000000000000000000000
--- a/audio/compositors_test.go
+++ /dev/null
@@ -1,104 +0,0 @@
-package audio_test
-
-import (
-	"math"
-	"math/rand"
-	"reflect"
-	"testing"
-	"time"
-
-	"github.com/faiface/pixel/audio"
-)
-
-// randomDataStreamer generates random samples of duration d and returns a Streamer which streams
-// them and the data itself.
-func randomDataStreamer(d time.Duration) (s audio.Streamer, data [][2]float64) {
-	numSamples := int(math.Ceil(d.Seconds() * audio.SampleRate))
-	data = make([][2]float64, numSamples)
-	for i := range data {
-		data[i][0] = rand.Float64()*2 - 1
-		data[i][1] = rand.Float64()*2 - 1
-	}
-	return audio.StreamerFunc(func(samples [][2]float64) (n int, ok bool) {
-		if len(data) == 0 {
-			return 0, false
-		}
-		n = copy(samples, data)
-		data = data[n:]
-		return n, true
-	}), data
-}
-
-// collect drains Streamer s and returns all of the samples it streamed.
-func collect(s audio.Streamer) [][2]float64 {
-	var (
-		result [][2]float64
-		buf    [512][2]float64
-	)
-	for {
-		n, ok := s.Stream(buf[:])
-		if !ok {
-			return result
-		}
-		result = append(result, buf[:n]...)
-	}
-}
-
-func TestTake(t *testing.T) {
-	for i := 0; i < 7; i++ {
-		total := time.Nanosecond * time.Duration(1e8+rand.Intn(1e9))
-		s, data := randomDataStreamer(total)
-		d := time.Nanosecond * time.Duration(rand.Int63n(total.Nanoseconds()))
-		numSamples := int(math.Ceil(d.Seconds() * audio.SampleRate))
-
-		want := data[:numSamples]
-		got := collect(audio.Take(d, s))
-
-		if !reflect.DeepEqual(want, got) {
-			t.Error("Take not working correctly")
-		}
-	}
-}
-
-func TestSeq(t *testing.T) {
-	var (
-		s    = make([]audio.Streamer, 7)
-		want [][2]float64
-	)
-	for i := range s {
-		var data [][2]float64
-		s[i], data = randomDataStreamer(time.Nanosecond * time.Duration(1e8+rand.Intn(1e9)))
-		want = append(want, data...)
-	}
-
-	got := collect(audio.Seq(s...))
-
-	if !reflect.DeepEqual(want, got) {
-		t.Error("Seq not working correctly")
-	}
-}
-
-func TestMix(t *testing.T) {
-	var (
-		s    = make([]audio.Streamer, 7)
-		want [][2]float64
-	)
-	for i := range s {
-		var data [][2]float64
-		s[i], data = randomDataStreamer(time.Nanosecond * time.Duration(1e8+rand.Intn(1e9)))
-		for j := range data {
-			if j >= len(want) {
-				want = append(want, data[j])
-				continue
-			}
-			want[j][0] += data[j][0]
-			want[j][1] += data[j][1]
-		}
-	}
-
-	got := collect(audio.Mix(s...))
-
-	if !reflect.DeepEqual(want, got) {
-		t.Error("Mix not working correctly")
-	}
-}
diff --git a/audio/ctrl.go b/audio/ctrl.go
deleted file mode 100644
index 54d1b30f157b52f19b8a2822cad38d8eba7b629f..0000000000000000000000000000000000000000
--- a/audio/ctrl.go
+++ /dev/null
@@ -1,66 +0,0 @@
-package audio
-
-import "time"
-
-// Ctrl allows for pausing and tracking a Streamer.
-//
-// Wrap a Streamer in a Ctrl.
-//
-//   ctrl := &audio.Ctrl{Streamer: s}
-//
-// Then, we can pause the streaming (this will cause Ctrl to stream silence).
-//
-//   ctrl.Paused = true
-//
-// And we can check how much has already been streamed. Position is not incremented when the Ctrl is
-// paused.
-//
-//   fmt.Println(ctrl.Position)
-//
-// To completely stop a Ctrl before the wrapped Streamer is drained, just set the wrapped Streamer
-// to nil.
-//
-//   ctrl.Streamer = nil
-//
-// If you're playing a Streamer wrapped in a Ctrl through the speaker, you need to lock and unlock
-// the speaker when modifying the Ctrl to avoid race conditions.
-//
-//   speaker.Play(ctrl)
-//   // ...
-//   speaker.Lock()
-//   ctrl.Paused = true
-//   speaker.Unlock()
-//   // ...
-//   speaker.Lock()
-//   fmt.Println(ctrl.Position)
-//   speaker.Unlock()
-type Ctrl struct {
-	Streamer Streamer
-	Paused   bool
-	Position time.Duration
-}
-
-// Stream streams the wrapped Streamer, if not nil. If the Streamer is nil, Ctrl acts as drained.
-// When paused, Ctrl streams silence.
-func (c *Ctrl) Stream(samples [][2]float64) (n int, ok bool) {
-	if c.Streamer == nil {
-		return 0, false
-	}
-	if c.Paused {
-		for i := range samples {
-			samples[i] = [2]float64{}
-		}
-		return len(samples), true
-	}
-	n, ok = c.Streamer.Stream(samples)
-	c.Position += time.Duration(n) * time.Second / time.Duration(SampleRate)
-	return n, ok
-}
-
-// Err returns the error of the wrapped Streamer, if not nil.
-func (c *Ctrl) Err() error {
-	if c.Streamer == nil {
-		return nil
-	}
-	return c.Err()
-}
diff --git a/audio/effects.go b/audio/effects.go
deleted file mode 100644
index 9a86478e0de3b9576781968bff4949024dedb827..0000000000000000000000000000000000000000
--- a/audio/effects.go
+++ /dev/null
@@ -1,26 +0,0 @@
-package audio
-
-// Gain amplifies the wrapped Streamer. The output of the wrapped Streamer gets multiplied by
-// 1+Gain.
-//
-// Note that gain is not equivalent to the human perception of volume. Human perception of volume is
-// roughly exponential, while gain only amplifies linearly.
-type Gain struct {
-	Streamer Streamer
-	Gain     float64
-}
-
-// Stream streams the wrapped Streamer amplified by Gain.
-func (g *Gain) Stream(samples [][2]float64) (n int, ok bool) {
-	n, ok = g.Streamer.Stream(samples)
-	for i := range samples[:n] {
-		samples[i][0] *= 1 + g.Gain
-		samples[i][1] *= 1 + g.Gain
-	}
-	return n, ok
-}
-
-// Err propagates the wrapped Streamer's errors.
-func (g *Gain) Err() error {
-	return g.Streamer.Err()
-}
diff --git a/audio/interface.go b/audio/interface.go
deleted file mode 100644
index ad05342f10f7288363282a1fc797a9fcf8f2777a..0000000000000000000000000000000000000000
--- a/audio/interface.go
+++ /dev/null
@@ -1,112 +0,0 @@
-package audio
-
-import "time"
-
-// SampleRate is the number of audio samples a Streamer should produce per one second of audio.
-//
-// This value should be set at most once before using audio package. It is safe to assume that this
-// value does not change during runtime.
-var SampleRate float64 = 48000
-
-// Streamer is able to stream a finite or infinite sequence of audio samples.
-type Streamer interface {
-	// Stream copies at most len(samples) next audio samples to the samples slice.
-	//
-	// The sample rate of the samples is specified by the global SampleRate variable/constant.
-	// The value at samples[i][0] is the value of the left channel of the i-th sample.
-	// Similarly, samples[i][1] is the value of the right channel of the i-th sample.
-	//
-	// Stream returns the number of streamed samples. If the Streamer is drained and no more
-	// samples will be produced, it returns 0 and false. Stream must not touch any samples
-	// outside samples[:n].
-	//
-	// There are 3 valid return pattterns of the Stream method:
-	//
-	//   1. n == len(samples) && ok
-	//
-	// Stream streamed all of the requested samples. Cases 1, 2 and 3 may occur in the following
-	// calls.
-	//
-	//   2. 0 < n && n < len(samples) && ok
-	//
-	// Stream streamed n samples and drained the Streamer. Only case 3 may occur in the
-	// following calls. If Err return a non-nil error, only this case is valid.
-	//
-	//   3. n == 0 && !ok
-	//
-	// The Streamer is drained and no more samples will come. Only this case may occur in the
-	// following calls.
-	Stream(samples [][2]float64) (n int, ok bool)
-
-	// Err returns an error which occured during streaming. If no error occured, nil is
-	// returned.
-	//
-	// When an error occurs, Streamer must become drained and Stream must return 0, false
-	// forever.
-	//
-	// The reason why Stream doesn't return an error is that it dramatically simplifies
-	// programming with Streamer. It's not very important to catch the error right when it
-	// happens.
-	Err() error
-}
-
-// StreamSeeker is a finite duration Streamer which supports seeking to an arbitrary position.
-type StreamSeeker interface {
-	Streamer
-
-	// Duration returns the total duration of the Streamer.
-	Duration() time.Duration
-
-	// Position returns the current position of the Streamer. This value is between 0 and the
-	// total duration.
-	Position() time.Duration
-
-	// Seek sets the position of the Streamer to the provided value.
-	//
-	// If an error occurs during seeking, the position remains unchanged. This error will not be
-	// returned through the Streamer's Err method.
-	Seek(d time.Duration) 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
-	Duration() time.Duration
-	Position() time.Duration
-	Seek(d time.Duration) 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.
-//
-// Example:
-//
-//   noise := StreamerFunc(func(samples [][2]float64) (n int, ok bool) {
-//       for i := range samples {
-//           samples[i][0] = rand.Float64()*2 - 1
-//           samples[i][1] = rand.Float64()*2 - 1
-//       }
-//       return len(samples), true
-//   })
-type StreamerFunc func(samples [][2]float64) (n int, ok bool)
-
-// Stream calls the wrapped streaming function.
-func (sf StreamerFunc) Stream(samples [][2]float64) (n int, ok bool) {
-	return sf(samples)
-}
-
-// Err always returns nil.
-func (sf StreamerFunc) Err() error {
-	return nil
-}
diff --git a/audio/mixer.go b/audio/mixer.go
deleted file mode 100644
index 1de0fa5792d1a91129936d7d3d6258983df518ed..0000000000000000000000000000000000000000
--- a/audio/mixer.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package audio
-
-// Mixer allows for dynamic mixing of arbitrary number of Streamers. Mixer automatically removes
-// drained Streamers. Mixer's stream never drains, when empty, Mixer streams silence.
-type Mixer struct {
-	streamers []Streamer
-}
-
-// Len returns the number of Streamers currently playing in the Mixer.
-func (m *Mixer) Len() int {
-	return len(m.streamers)
-}
-
-// Play adds Streamers to the Mixer.
-func (m *Mixer) Play(s ...Streamer) {
-	m.streamers = append(m.streamers, s...)
-}
-
-// Stream streams all Streamers currently in the Mixer mixed together. This method always returns
-// len(samples), true. If there are no Streamers available, this methods streams silence.
-func (m *Mixer) Stream(samples [][2]float64) (n int, ok bool) {
-	var tmp [512][2]float64
-
-	for len(samples) > 0 {
-		toStream := len(tmp)
-		if toStream > len(samples) {
-			toStream = len(samples)
-		}
-
-		// clear the samples
-		for i := range samples[:toStream] {
-			samples[i] = [2]float64{}
-		}
-
-		for si := 0; si < len(m.streamers); si++ {
-			// mix the stream
-			sn, sok := m.streamers[si].Stream(tmp[:toStream])
-			for i := range tmp[:sn] {
-				samples[i][0] += tmp[i][0]
-				samples[i][1] += tmp[i][1]
-			}
-			if !sok {
-				// remove drained streamer
-				sj := len(m.streamers) - 1
-				m.streamers[si], m.streamers[sj] = m.streamers[sj], m.streamers[si]
-				m.streamers = m.streamers[:sj]
-				si--
-			}
-		}
-
-		samples = samples[toStream:]
-		n += toStream
-	}
-
-	return n, true
-}
-
-// Err always returns nil for Mixer.
-//
-// There are two reasons. The first one is that erroring Streamers are immediately drained and
-// removed from the Mixer. The second one is that one Streamer shouldn't break the whole Mixer and
-// you should handle the errors right where they can happen.
-func (m *Mixer) Err() error {
-	return nil
-}
diff --git a/audio/speaker/speaker.go b/audio/speaker/speaker.go
deleted file mode 100644
index dbb153c7e8de22c348f9b9e604b9f565101f6374..0000000000000000000000000000000000000000
--- a/audio/speaker/speaker.go
+++ /dev/null
@@ -1,110 +0,0 @@
-package speaker
-
-import (
-	"math"
-	"sync"
-	"time"
-
-	"github.com/faiface/pixel/audio"
-	"github.com/hajimehoshi/oto"
-	"github.com/pkg/errors"
-)
-
-var (
-	mu      sync.Mutex
-	mixer   audio.Mixer
-	samples [][2]float64
-	buf     []byte
-	player  *oto.Player
-	done    chan struct{}
-)
-
-// Init initializes audio playback through speaker. Must be called before using this package. The
-// value of audio.SampleRate must be set (or left to the default) before calling this function.
-//
-// The bufferSize argument specifies the length of the speaker's buffer. Bigger bufferSize means
-// lower CPU usage and more reliable playback. Lower bufferSize means better responsiveness and less
-// delay.
-func Init(bufferSize time.Duration) error {
-	mu.Lock()
-	defer mu.Unlock()
-
-	if player != nil {
-		done <- struct{}{}
-		player.Close()
-	}
-
-	mixer = audio.Mixer{}
-
-	numSamples := int(math.Ceil(bufferSize.Seconds() * audio.SampleRate))
-	numBytes := numSamples * 4
-
-	samples = make([][2]float64, numSamples)
-	buf = make([]byte, numBytes)
-
-	var err error
-	player, err = oto.NewPlayer(int(audio.SampleRate), 2, 2, numBytes)
-	if err != nil {
-		return errors.Wrap(err, "failed to initialize speaker")
-	}
-
-	done = make(chan struct{})
-
-	go func() {
-		for {
-			select {
-			default:
-				update()
-			case <-done:
-				return
-			}
-		}
-	}()
-
-	return nil
-}
-
-// Lock locks the speaker. While locked, speaker won't pull new data from the playing Stramers. Lock
-// if you want to modify any currently playing Streamers to avoid race conditions.
-func Lock() {
-	mu.Lock()
-}
-
-// Unlock unlocks the speaker. Call after modifying any currently playing Streamer.
-func Unlock() {
-	mu.Unlock()
-}
-
-// Play starts playing all provided Streamers through the speaker.
-func Play(s ...audio.Streamer) {
-	mu.Lock()
-	mixer.Play(s...)
-	mu.Unlock()
-}
-
-// update pulls new data from the playing Streamers and sends it to the speaker. Blocks until the
-// data is sent and started playing.
-func update() {
-	mu.Lock()
-	mixer.Stream(samples)
-	mu.Unlock()
-
-	for i := range samples {
-		for c := range samples[i] {
-			val := samples[i][c]
-			if val < -1 {
-				val = -1
-			}
-			if val > +1 {
-				val = +1
-			}
-			valInt16 := int16(val * (1<<15 - 1))
-			low := byte(valInt16)
-			high := byte(valInt16 >> 8)
-			buf[i*4+c*2+0] = low
-			buf[i*4+c*2+1] = high
-		}
-	}
-
-	player.Write(buf)
-}
diff --git a/audio/wav/decode.go b/audio/wav/decode.go
deleted file mode 100644
index eb0502db7a634cd01c4e4274fde90add443e5851..0000000000000000000000000000000000000000
--- a/audio/wav/decode.go
+++ /dev/null
@@ -1,158 +0,0 @@
-// Package wav implements audio data decoding in WAVE format through an audio.StreamSeekCloser.
-package wav
-
-import (
-	"encoding/binary"
-	"fmt"
-	"io"
-	"time"
-
-	"github.com/faiface/pixel/audio"
-	"github.com/pkg/errors"
-)
-
-// ReadSeekCloser is a union of io.Reader, io.Seeker and io.Closer.
-type ReadSeekCloser interface {
-	io.Reader
-	io.Seeker
-	io.Closer
-}
-
-// Decode takes a ReadSeekCloser containing audio data in WAVE format and returns a
-// StreamSeekCloser, which streams that audio.
-//
-// Do not close the supplied ReadSeekCloser, instead, use the Close method of the returned
-// StreamSeekCloser when you want to release the resources.
-func Decode(rsc ReadSeekCloser) (s audio.StreamSeekCloser, err error) {
-	d := decoder{rsc: rsc}
-	defer func() { // hacky way to always close rsc if an error occured
-		if err != nil {
-			d.rsc.Close()
-		}
-	}()
-	herr := binary.Read(rsc, binary.LittleEndian, &d.h)
-	if herr != nil {
-		return nil, errors.Wrap(herr, "wav")
-	}
-	if string(d.h.RiffMark[:]) != "RIFF" {
-		return nil, errors.New("wav: missing RIFF at the beginning")
-	}
-	if string(d.h.WaveMark[:]) != "WAVE" {
-		return nil, errors.New("wav: unsupported file type")
-	}
-	if string(d.h.FmtMark[:]) != "fmt " {
-		return nil, errors.New("wav: missing format chunk marker")
-	}
-	if string(d.h.DataMark[:]) != "data" {
-		return nil, errors.New("wav: missing data chunk marker")
-	}
-	if d.h.FormatType != 1 {
-		return nil, errors.New("wav: unsupported format type")
-	}
-	if d.h.NumChans <= 0 {
-		return nil, errors.New("wav: invalid number of channels (less than 1)")
-	}
-	if d.h.BitsPerSample != 8 && d.h.BitsPerSample != 16 {
-		return nil, errors.New("wav: unsupported number of bits per sample, 8 or 16 are supported")
-	}
-	return &d, nil
-}
-
-type header struct {
-	RiffMark      [4]byte
-	FileSize      int32
-	WaveMark      [4]byte
-	FmtMark       [4]byte
-	FormatSize    int32
-	FormatType    int16
-	NumChans      int16
-	SampleRate    int32
-	ByteRate      int32
-	BytesPerFrame int16
-	BitsPerSample int16
-	DataMark      [4]byte
-	DataSize      int32
-}
-
-type decoder struct {
-	rsc ReadSeekCloser
-	h   header
-	pos int32
-	err error
-}
-
-func (s *decoder) Err() error {
-	return s.err
-}
-
-func (s *decoder) Duration() time.Duration {
-	numBytes := time.Duration(s.h.DataSize)
-	perFrame := time.Duration(s.h.BytesPerFrame)
-	sampRate := time.Duration(s.h.SampleRate)
-	return numBytes / perFrame * time.Second / sampRate
-}
-
-func (s *decoder) Position() time.Duration {
-	frameIndex := time.Duration(s.pos / int32(s.h.BytesPerFrame))
-	return frameIndex * time.Second / time.Duration(s.h.SampleRate)
-}
-
-func (s *decoder) Seek(d time.Duration) error {
-	if d < 0 || s.Duration() < d {
-		return fmt.Errorf("wav: seek duration %v out of range [%v, %v]", d, 0, s.Duration())
-	}
-	frame := int32(d * time.Duration(s.h.SampleRate) / time.Second)
-	pos := frame * int32(s.h.BytesPerFrame)
-	_, err := s.rsc.Seek(int64(pos)+44, io.SeekStart) // 44 is the size of the header
-	if err != nil {
-		return errors.Wrap(err, "wav: seek error")
-	}
-	s.pos = pos
-	return nil
-}
-
-func (s *decoder) Stream(samples [][2]float64) (n int, ok bool) {
-	if s.err != nil || s.pos >= s.h.DataSize {
-		return 0, false
-	}
-	bytesPerFrame := int(s.h.BytesPerFrame)
-	p := make([]byte, len(samples)*bytesPerFrame)
-	n, err := s.rsc.Read(p)
-	if err != nil {
-		s.err = err
-	}
-	switch {
-	case s.h.BitsPerSample == 8 && s.h.NumChans == 1:
-		for i, j := 0, 0; i <= n-bytesPerFrame; i, j = i+bytesPerFrame, j+1 {
-			val := float64(p[i])/(1<<8-1)*2 - 1
-			samples[j][0] = val
-			samples[j][1] = val
-		}
-	case s.h.BitsPerSample == 8 && s.h.NumChans >= 2:
-		for i, j := 0, 0; i <= n-bytesPerFrame; i, j = i+bytesPerFrame, j+1 {
-			samples[j][0] = float64(p[i+0])/(1<<8-1)*2 - 1
-			samples[j][1] = float64(p[i+1])/(1<<8-1)*2 - 1
-		}
-	case s.h.BitsPerSample == 16 && s.h.NumChans == 1:
-		for i, j := 0, 0; i <= n-bytesPerFrame; i, j = i+bytesPerFrame, j+1 {
-			val := float64(int16(p[i+0])+int16(p[i+1])*(1<<8)) / (1<<15 - 1)
-			samples[j][0] = val
-			samples[j][1] = val
-		}
-	case s.h.BitsPerSample == 16 && s.h.NumChans >= 2:
-		for i, j := 0, 0; i <= n-bytesPerFrame; i, j = i+bytesPerFrame, j+1 {
-			samples[j][0] = float64(int16(p[i+0])+int16(p[i+1])*(1<<8)) / (1<<15 - 1)
-			samples[j][1] = float64(int16(p[i+2])+int16(p[i+3])*(1<<8)) / (1<<15 - 1)
-		}
-	}
-	s.pos += int32(n)
-	return n / bytesPerFrame, true
-}
-
-func (s *decoder) Close() error {
-	err := s.rsc.Close()
-	if err != nil {
-		return errors.Wrap(err, "wav")
-	}
-	return nil
-}