diff --git a/audio/compositors.go b/audio/compositors.go
new file mode 100644
index 0000000000000000000000000000000000000000..bb4740f249307bf7d9390a7cecc6fcb2c53f9685
--- /dev/null
+++ b/audio/compositors.go
@@ -0,0 +1,17 @@
+package audio
+
+// Seq takes zero or more Streamers and returns a Streamer which streams them one by one without pauses.
+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
+	})
+}
diff --git a/audio/compositors_test.go b/audio/compositors_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..4114b9221a38fcc8ed7ba23f659b3a7ad1cb8d25
--- /dev/null
+++ b/audio/compositors_test.go
@@ -0,0 +1,63 @@
+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 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")
+	}
+}