From c86834b8f67650edd7be90be9d2e04b4a6698278 Mon Sep 17 00:00:00 2001
From: faiface <faiface@ksp.sk>
Date: Wed, 5 Jul 2017 17:59:43 +0200
Subject: [PATCH] add Seq compositor

---
 audio/compositors.go      | 17 +++++++++++
 audio/compositors_test.go | 63 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 80 insertions(+)
 create mode 100644 audio/compositors.go
 create mode 100644 audio/compositors_test.go

diff --git a/audio/compositors.go b/audio/compositors.go
new file mode 100644
index 0000000..bb4740f
--- /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 0000000..4114b92
--- /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")
+	}
+}
-- 
GitLab