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") + } +}