diff --git a/snowboy-2022/go.mod b/snowboy-2022/go.mod new file mode 100644 index 0000000..dcb4c91 --- /dev/null +++ b/snowboy-2022/go.mod @@ -0,0 +1,13 @@ +module snowboy + +go 1.19 + +require ( + github.com/brentnd/go-snowboy v0.0.0-20190301212623-e19133c572af + github.com/gordonklaus/portaudio v0.0.0-20221027163845-7c3b689db3cc +) + +require ( + github.com/Kitt-AI/snowboy v1.3.0 // indirect + github.com/stretchr/testify v1.8.1 // indirect +) diff --git a/snowboy-2022/go.sum b/snowboy-2022/go.sum new file mode 100644 index 0000000..0fbc5b0 --- /dev/null +++ b/snowboy-2022/go.sum @@ -0,0 +1,22 @@ +github.com/Kitt-AI/snowboy v1.3.0 h1:PjBVN84M/9tAzDBQXILAKMoJMxt/fT0nhJ1rhKtVRUc= +github.com/Kitt-AI/snowboy v1.3.0/go.mod h1:sDzzMXFQ1wFkXkZaX/ant0xJsizGVq/9hyKb7ZB3cNI= +github.com/brentnd/go-snowboy v0.0.0-20190301212623-e19133c572af h1:ijY5OHNQs3CdzTN2XT+zByIsR1QVyXTvOUSkQcBm6pw= +github.com/brentnd/go-snowboy v0.0.0-20190301212623-e19133c572af/go.mod h1:XcT4k8Tn9hrM5SLVvu5hNQbAC6GojXM0MXz1Rt8CL68= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gordonklaus/portaudio v0.0.0-20221027163845-7c3b689db3cc h1:yYLpN7bJxKYILKnk20oczGQOQd2h3/7z7/cxdD9Se/I= +github.com/gordonklaus/portaudio v0.0.0-20221027163845-7c3b689db3cc/go.mod h1:WY8R6YKlI2ZI3UyzFk7P6yGSuS+hFwNtEzrexRyD7Es= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/snowboy-2022/main.go b/snowboy-2022/main.go new file mode 100644 index 0000000..41588a8 --- /dev/null +++ b/snowboy-2022/main.go @@ -0,0 +1,110 @@ +// 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" + "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("resources", "", "path to the .res file") + model := flag.String("model", "", "path to the .?mdl file") + sensitivity := flag.Float64("sensitivity", 0.75, "0..1") + flag.Parse() + + if *resources == "" || *model == "" { + 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 + d.HandleFunc(snowboy.NewHotword(*model, float32(*sensitivity)), func(string) { + fmt.Println(time.Now(), "GOTCHA!") + }) + + d.HandleSilenceFunc(1*time.Second, func(string) { + fmt.Println("...") + }) + + // display the detector's expected audio format + sr, nc, bd := d.AudioFormat() + fmt.Printf("sample rate=%d, num channels=%d, bit depth=%d\n", sr, nc, bd) + + // start detecting using the microphone + d.ReadAndDetect(mic) +}