61 lines
1.5 KiB
Go
61 lines
1.5 KiB
Go
package sine
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"math"
|
|
"time"
|
|
)
|
|
|
|
type SineStream struct {
|
|
Frequency float64
|
|
Samplerate int
|
|
State uint64
|
|
Beep bool
|
|
Timestamp time.Time
|
|
}
|
|
|
|
func makeSample(channelValues ...float64) (ret []byte) {
|
|
// target format: s16le
|
|
buf := new(bytes.Buffer)
|
|
for _, value := range channelValues {
|
|
intValue := int16(value * math.MaxInt16)
|
|
binary.Write(buf, binary.LittleEndian, intValue)
|
|
}
|
|
return buf.Bytes()
|
|
}
|
|
|
|
func (stream *SineStream) Read(data []byte) (n int, err error) {
|
|
n = 0
|
|
for (len(data) - n) >= 4 { // at least 2 bytes per channel need to be available
|
|
var sampleValue float64
|
|
if stream.Beep && stream.State%uint64(stream.Samplerate) > uint64(float64(stream.Samplerate)*0.15) {
|
|
sampleValue = 0
|
|
} else {
|
|
sampleValue = math.Sin(stream.Frequency * 2. * math.Pi * (float64(stream.State) / float64(stream.Samplerate)))
|
|
}
|
|
|
|
b := makeSample(sampleValue, sampleValue)
|
|
copy(data[n:], b)
|
|
|
|
n += len(b)
|
|
|
|
targetTime := stream.Timestamp.
|
|
Add(time.Duration(float64(time.Second) * float64(stream.State) / float64(stream.Samplerate)))
|
|
delay := targetTime.Sub(time.Now())
|
|
/*log.Println("state", stream.State, "value", sampleValue, "time", targetTime, "delay", delay)
|
|
time.Sleep(time.Second)*/
|
|
if delay > 0 {
|
|
<-time.After(delay)
|
|
}
|
|
|
|
/*if stream.State%uint64(stream.Samplerate) == 0 {
|
|
log.Println("state", stream.State, "value", sampleValue, "time", targetTime, "delay", delay)
|
|
}*/
|
|
|
|
stream.State++
|
|
}
|
|
|
|
return
|
|
}
|