After commit c018f5fd29 Fenrir is being switched over to go. If you do not want to be part of the testing process, please switch to master.
This commit is contained in:
1 parent
c018f5fd29
commit
0e50de4c76
1047 files changed
+58364
-63747
No files matched your search
@@ -0,0 +1,106 @@
|
||||
// Copyright (c) 2026 Storm Dragon
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"git.stormux.org/storm/fenrir/internal/config"
|
||||
"git.stormux.org/storm/fenrir/internal/speech"
|
||||
)
|
||||
|
||||
type speechChangeResult struct {
|
||||
err error
|
||||
done func(error)
|
||||
}
|
||||
|
||||
func same_speech_selection(a, b config.Speech) bool {
|
||||
return a.Driver == b.Driver && a.Module == b.Module && a.Language == b.Language && a.Voice == b.Voice
|
||||
}
|
||||
|
||||
func copy_speech_selection(target *config.Speech, source config.Speech) {
|
||||
target.Module, target.Language, target.Voice = source.Module, source.Language, source.Voice
|
||||
}
|
||||
|
||||
func prepare_speech(selected config.Speech) (speech.Transport, error) {
|
||||
return speech.Prepare(selected.Driver, speech_options(selected))
|
||||
}
|
||||
|
||||
func speech_options(selected config.Speech) speech.Options {
|
||||
return speech.Options{Rate: selected.Rate, Pitch: &selected.Pitch, Volume: &selected.Volume, Module: selected.Module, Language: selected.Language, Voice: selected.Voice, Hardware: speech.HardwareOptions{Device: selected.HardwareDevice, BaudRate: selected.HardwareBaudRate}}
|
||||
}
|
||||
|
||||
func (a *application) replace_speech(prepared speech.Transport) error {
|
||||
if service, ok := a.voice.Speaker.(interface{ Replace(speech.Transport) error }); ok {
|
||||
return service.Replace(prepared)
|
||||
}
|
||||
prepared.Close()
|
||||
return fmt.Errorf("speech service does not support live selection")
|
||||
}
|
||||
|
||||
// Only the result callback mutates reader state. Preparing a silent candidate
|
||||
// and committing it through the speech worker never blocks the input loop.
|
||||
func (a *application) change_speech(selected config.Speech, done func(error)) {
|
||||
if a.speechPending || a.saver.busy {
|
||||
done(fmt.Errorf("settings are busy"))
|
||||
return
|
||||
}
|
||||
if !a.settings.speechAvailable {
|
||||
done(fmt.Errorf("speech was disabled at startup"))
|
||||
return
|
||||
}
|
||||
a.speechPending = true
|
||||
go func() {
|
||||
prepared, err := a.prepareSpeech(selected)
|
||||
if err == nil {
|
||||
err = a.replace_speech(prepared)
|
||||
}
|
||||
select {
|
||||
case a.speechResults <- speechChangeResult{err: err, done: done}:
|
||||
case <-a.ctx.Done():
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func speech_choice(source string) bool {
|
||||
return source == "speech-module" || source == "speech-language" || source == "speech-voice"
|
||||
}
|
||||
|
||||
func (a *application) speech_result(result speechChangeResult) {
|
||||
a.speechPending = false
|
||||
result.done(result.err)
|
||||
// Reapply numeric overrides made while the silent candidate was prepared.
|
||||
a.voice.Configure(speech_parameters(a.settings.live))
|
||||
}
|
||||
|
||||
type savedSpeechError struct{ err error }
|
||||
|
||||
func (e *savedSpeechError) Error() string {
|
||||
return "settings saved; speech selection was not applied: " + e.err.Error()
|
||||
}
|
||||
func (e *savedSpeechError) Unwrap() error { return e.err }
|
||||
func settings_committed(err error) bool {
|
||||
var saved *savedSpeechError
|
||||
return err == nil || errors.As(err, &saved)
|
||||
}
|
||||
|
||||
func open_speech(selected config.Speech) (speech.Transport, config.Speech, error) {
|
||||
options := speech_options(selected)
|
||||
if selected.Module == "" && selected.Language == "" && selected.Voice == "" {
|
||||
client, err := speech.Open_driver(selected.Driver, options)
|
||||
return client, selected, err
|
||||
}
|
||||
client, err := prepare_speech(selected)
|
||||
if err == nil {
|
||||
return client, selected, nil
|
||||
}
|
||||
slog.Warn("saved speech selection unavailable; using server default", "error", err, "at", time.Now())
|
||||
selected.Module, selected.Language, selected.Voice = "", "", ""
|
||||
options.Module, options.Language, options.Voice = "", "", ""
|
||||
client, err = speech.Open_driver(selected.Driver, options)
|
||||
return client, selected, err
|
||||
}
|
||||
Reference in new issue
Block a user