77 lines
1.5 KiB
Go
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
|
|
}
|