commit
e7a7b16be2
|
@ -9,6 +9,7 @@ addons:
|
||||||
- libxinerama-dev
|
- libxinerama-dev
|
||||||
- libxcursor-dev
|
- libxcursor-dev
|
||||||
- libxi-dev
|
- libxi-dev
|
||||||
|
- libasound2-dev
|
||||||
go:
|
go:
|
||||||
- 1.8
|
- 1.8
|
||||||
- 1.7.4
|
- 1.7.4
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
package audio
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Take returns a Streamer which streams s for at most d duration.
|
||||||
|
func Take(d time.Duration, s Streamer) Streamer {
|
||||||
|
currSample := 0
|
||||||
|
numSamples := int(math.Ceil(d.Seconds() * SampleRate))
|
||||||
|
return StreamerFunc(func(samples [][2]float64) (n int, ok bool) {
|
||||||
|
if currSample >= numSamples {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
toStream := numSamples - currSample
|
||||||
|
if len(samples) < toStream {
|
||||||
|
toStream = len(samples)
|
||||||
|
}
|
||||||
|
sn, sok := s.Stream(samples[:toStream])
|
||||||
|
currSample += sn
|
||||||
|
return sn, sok
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,9 +2,9 @@ package audio
|
||||||
|
|
||||||
// SampleRate is the number of audio samples a Streamer should produce per one second of audio.
|
// 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 rely on the fact,
|
// This value should be set at most once before using audio package. It is safe to assume that this
|
||||||
// that this value does not change during runtime.
|
// value does not change during runtime.
|
||||||
var SampleRate = 48000
|
var SampleRate float64 = 48000
|
||||||
|
|
||||||
// Streamer is able to stream a finite or infinite sequence of audio samples.
|
// Streamer is able to stream a finite or infinite sequence of audio samples.
|
||||||
type Streamer interface {
|
type Streamer interface {
|
||||||
|
@ -36,3 +36,22 @@ type Streamer interface {
|
||||||
// following calls.
|
// following calls.
|
||||||
Stream(samples [][2]float64) (n int, ok bool)
|
Stream(samples [][2]float64) (n int, ok bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue