166 lines
2.9 KiB
Go
166 lines
2.9 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"github.com/faiface/beep"
|
||
|
"github.com/faiface/beep/effects"
|
||
|
"github.com/faiface/beep/speaker"
|
||
|
"github.com/faiface/beep/wav"
|
||
|
"github.com/tarm/serial"
|
||
|
"log"
|
||
|
"math"
|
||
|
"os"
|
||
|
"sync"
|
||
|
"time"
|
||
|
)
|
||
|
|
||
|
var sounds = []*beep.Buffer{
|
||
|
mustLoadStream("./mini_grand/mini_grand-001.wav"),
|
||
|
mustLoadStream("./mini_grand/mini_grand-003.wav"),
|
||
|
mustLoadStream("./mini_grand/mini_grand-005.wav"),
|
||
|
mustLoadStream("./mini_grand/mini_grand-006.wav"),
|
||
|
mustLoadStream("./mini_grand/mini_grand-008.wav"),
|
||
|
mustLoadStream("./mini_grand/mini_grand-010.wav"),
|
||
|
mustLoadStream("./mini_grand/mini_grand-012.wav"),
|
||
|
mustLoadStream("./mini_grand/mini_grand-013.wav"),
|
||
|
}
|
||
|
|
||
|
func mustLoadStream(p string) *beep.Buffer {
|
||
|
f, err := os.Open(p)
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
defer f.Close()
|
||
|
|
||
|
streamer, format, err := wav.Decode(f)
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
defer streamer.Close()
|
||
|
|
||
|
newFormat := format
|
||
|
newFormat.SampleRate = format.SampleRate / 4
|
||
|
resample := beep.Resample(4, format.SampleRate, newFormat.SampleRate, streamer)
|
||
|
|
||
|
buffer := beep.NewBuffer(newFormat)
|
||
|
buffer.Append(resample)
|
||
|
|
||
|
return buffer
|
||
|
}
|
||
|
|
||
|
type soundWorker struct {
|
||
|
buffer *beep.Buffer
|
||
|
ctrl *beep.Ctrl
|
||
|
volume *effects.Volume
|
||
|
isRunning bool
|
||
|
isStopping bool
|
||
|
forceEnd bool
|
||
|
mtx sync.Mutex
|
||
|
}
|
||
|
|
||
|
func (w *soundWorker) End() {
|
||
|
w.isStopping = true
|
||
|
w.mtx.Lock()
|
||
|
defer w.mtx.Unlock()
|
||
|
|
||
|
i := 1
|
||
|
for w.isRunning {
|
||
|
if i >= 80 || w.forceEnd {
|
||
|
break
|
||
|
}
|
||
|
|
||
|
w.volume.Volume = float64(1) / math.Pow(10, float64(i))
|
||
|
i++
|
||
|
}
|
||
|
w.isRunning = false
|
||
|
w.isStopping = false
|
||
|
w.forceEnd = false
|
||
|
w.ctrl.Paused = true
|
||
|
}
|
||
|
|
||
|
func (w *soundWorker) Start() {
|
||
|
if w.isRunning {
|
||
|
w.forceEnd = true
|
||
|
}
|
||
|
|
||
|
w.mtx.Lock()
|
||
|
defer w.mtx.Unlock()
|
||
|
|
||
|
w.isRunning = true
|
||
|
w.ctrl.Streamer.(beep.StreamSeeker).Seek(0)
|
||
|
w.volume.Volume = 1
|
||
|
w.ctrl.Paused = false
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
config := &serial.Config{
|
||
|
Name: "/dev/ttyS0",
|
||
|
Baud: 115200,
|
||
|
Size: 8,
|
||
|
}
|
||
|
|
||
|
stream, err := serial.OpenPort(config)
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
|
||
|
format := sounds[0].Format()
|
||
|
if err := speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/100)); err != nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
var soundWorkers []*soundWorker
|
||
|
|
||
|
mixer := beep.Mixer{}
|
||
|
for _, buffer := range sounds {
|
||
|
c := &beep.Ctrl{
|
||
|
Streamer: buffer.Streamer(0, buffer.Len()),
|
||
|
Paused: true,
|
||
|
}
|
||
|
|
||
|
volume := &effects.Volume{
|
||
|
Streamer: c,
|
||
|
Base: 2,
|
||
|
Volume: 1,
|
||
|
}
|
||
|
|
||
|
mixer.Add(volume)
|
||
|
|
||
|
soundWorkers = append(soundWorkers, &soundWorker{
|
||
|
buffer: buffer,
|
||
|
ctrl: c,
|
||
|
volume: volume,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
speaker.Play(&mixer)
|
||
|
|
||
|
c := make(chan byte)
|
||
|
|
||
|
go func() {
|
||
|
for b := range c {
|
||
|
for i, w := range soundWorkers {
|
||
|
setStop := (b&(1<<i))>>i == 0
|
||
|
|
||
|
if w.isRunning && !w.isStopping && setStop {
|
||
|
w.End()
|
||
|
}
|
||
|
|
||
|
if !w.isRunning && !setStop {
|
||
|
w.Start()
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}()
|
||
|
|
||
|
for {
|
||
|
buf := make([]byte, 1)
|
||
|
_, err := stream.Read(buf)
|
||
|
if err != nil {
|
||
|
log.Fatal(err)
|
||
|
}
|
||
|
|
||
|
c <- buf[0]
|
||
|
}
|
||
|
|
||
|
}
|