122 lines
2.7 KiB
Go
122 lines
2.7 KiB
Go
// This example streams the microphone thru Snowboy to listen for the hotword,
|
|
// by using the PortAudio interface.
|
|
//
|
|
// HOW TO USE:
|
|
// go run examples/Go/listen/main.go [path to snowboy resource file] [path to snowboy hotword file]
|
|
//
|
|
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"path"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/brentnd/go-snowboy"
|
|
"github.com/gordonklaus/portaudio"
|
|
)
|
|
|
|
// Sound represents a sound stream implementing the io.Reader interface
|
|
// that provides the microphone data.
|
|
type Sound struct {
|
|
stream *portaudio.Stream
|
|
data []int16
|
|
}
|
|
|
|
// Init initializes the Sound's PortAudio stream.
|
|
func (s *Sound) Init() {
|
|
inputChannels := 1
|
|
outputChannels := 0
|
|
sampleRate := 16000
|
|
s.data = make([]int16, 1024)
|
|
|
|
// initialize the audio recording interface
|
|
err := portaudio.Initialize()
|
|
if err != nil {
|
|
fmt.Errorf("Error initialize audio interface: %s", err)
|
|
return
|
|
}
|
|
|
|
// open the sound input stream for the microphone
|
|
stream, err := portaudio.OpenDefaultStream(inputChannels, outputChannels, float64(sampleRate), len(s.data), s.data)
|
|
if err != nil {
|
|
fmt.Errorf("Error open default audio stream: %s", err)
|
|
return
|
|
}
|
|
|
|
err = stream.Start()
|
|
if err != nil {
|
|
fmt.Errorf("Error on stream start: %s", err)
|
|
return
|
|
}
|
|
|
|
s.stream = stream
|
|
}
|
|
|
|
// Close closes down the Sound's PortAudio connection.
|
|
func (s *Sound) Close() {
|
|
s.stream.Close()
|
|
portaudio.Terminate()
|
|
}
|
|
|
|
// Read is the Sound's implementation of the io.Reader interface.
|
|
func (s *Sound) Read(p []byte) (int, error) {
|
|
s.stream.Read()
|
|
|
|
buf := &bytes.Buffer{}
|
|
for _, v := range s.data {
|
|
binary.Write(buf, binary.LittleEndian, v)
|
|
}
|
|
|
|
copy(p, buf.Bytes())
|
|
return len(p), nil
|
|
}
|
|
|
|
func main() {
|
|
resources := flag.String("r", "", "path to the .res file")
|
|
models := flag.String("ms", "", "comma delimited path to the .?mdl file/output")
|
|
sensitivity := flag.Float64("s", 0.45, "0..1")
|
|
quiet := flag.Bool("q", false, "emit '1' on detect else silent")
|
|
flag.Parse()
|
|
|
|
if *resources == "" || *models == "" {
|
|
panic("all flags must be set")
|
|
}
|
|
|
|
// open the mic
|
|
mic := &Sound{}
|
|
mic.Init()
|
|
defer mic.Close()
|
|
|
|
// open the snowboy detector
|
|
d := snowboy.NewDetector(*resources)
|
|
defer d.Close()
|
|
|
|
// set the handlers
|
|
for _, modelStr := range strings.Split(*models, ",") {
|
|
d.HandleFunc(snowboy.NewHotword(path.Dir(modelStr), float32(*sensitivity)), func(string) {
|
|
if !*quiet {
|
|
log.Println("GOTCHA!")
|
|
}
|
|
fmt.Println(path.Base(modelStr))
|
|
})
|
|
}
|
|
|
|
d.HandleSilenceFunc(1*time.Second, func(string) {
|
|
if !*quiet {
|
|
log.Println("...")
|
|
}
|
|
})
|
|
|
|
// display the detector's expected audio format
|
|
sr, nc, bd := d.AudioFormat()
|
|
log.Printf("sample rate=%d, num channels=%d, bit depth=%d\n", sr, nc, bd)
|
|
|
|
// start detecting using the microphone
|
|
d.ReadAndDetect(mic)
|
|
}
|