Files
mayhem-party/src/device/input/parse/v01/tts.go
2023-03-27 06:19:39 -06:00

77 lines
1.5 KiB
Go

package v01
import (
"bytes"
"fmt"
"io"
"log"
"net/http"
"net/url"
"sync"
"time"
"github.com/faiface/beep"
"github.com/faiface/beep/effects"
"github.com/faiface/beep/speaker"
"github.com/faiface/beep/wav"
)
var (
ttsLock = &sync.RWMutex{}
)
func (v01 *V01) tts(text string) {
if err := v01._tts(text); err != nil {
log.Printf("failed to tts: %s: %v", text, err)
}
}
func (v01 *V01) _tts(text string) error {
if v01.cfg.Feedback.TTSURL == "" {
return nil
}
url, err := url.Parse(v01.cfg.Feedback.TTSURL)
if err != nil {
return err
}
if len(url.Path) < 2 {
url.Path = "/api/tts"
}
q := url.Query()
if q.Get("voice") == "" {
q.Set("voice", "en-us/glados-glow_tts")
}
if q.Get("lengthScale") == "" {
q.Set("lengthScale", "1")
}
q.Set("text", text)
url.RawQuery = q.Encode()
resp, err := http.Get(url.String())
if err != nil {
return err
}
defer resp.Body.Close()
b, _ := io.ReadAll(resp.Body)
if resp.StatusCode != http.StatusOK || resp.Header.Get("Content-Type") != "audio/wav" {
return fmt.Errorf("failed to call ttsurl: (%d) %s", resp.StatusCode, b)
}
decoder, format, err := wav.Decode(bytes.NewReader(b))
if err != nil {
return err
}
ttsLock.Lock()
defer ttsLock.Unlock()
speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/30))
speaker.Play(&effects.Volume{Streamer: beep.ResampleRatio(4, 1, &beep.Ctrl{Streamer: beep.Loop(1, decoder)})})
duration := time.Duration(decoder.Len()) * format.SampleRate.D(1)
select {
case <-v01.ctx.Done():
case <-time.After(duration):
}
return nil
}