refactor: switch the whole project to English
talk is going to be published. Code comments, CLI output, error messages,
daemon log lines, MCP descriptions and results, test names and assertions,
README, spec, skill, build scripts and flake are now English. Only the
spoken announcement texts stay bilingual: the wrap result and the test
sentence are German or English depending on the detected language.
Language fallback is now configurable: `lang = "en" | "de"` (env
TALK_LANG, default en) is used when detection cannot tell (numbers, single
words, ties) and for talk's own announcements. langdetect.Detect takes the
fallback as an argument instead of hard-coding German. `talk setup` asks for
it; `talk doctor` and `talk status` show it.
Vocabulary pinned across packages so the process-boundary tests observe
stable strings: chain log lines ("chain: tier X skipped (not available)",
"falling back to the next tier", "spoken via X"), queue lines ("discarded:
quiet hours ... active", "replaced by toast", "max_age"), CLI notes
("speaking directly", "daemon started at", "no daemon", "nothing to cancel"),
status block with aligned English labels, MCP messages, origin guard 403.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
4d30bd95ad
commit
85fa64cfe6
95 files changed
+4707
-4854
No files matched your search
+17
-18
@@ -5,28 +5,27 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// pcmFormat beschreibt rohe PCM-Samples, wie sie oto zur Wiedergabe
|
||||
// braucht.
|
||||
// pcmFormat describes raw PCM samples as oto needs them for playback.
|
||||
type pcmFormat struct {
|
||||
SampleRate int
|
||||
Channels int
|
||||
BitsPerCoded int // 8 (unsigned), 16 (signed LE), 32 (nur IEEE float)
|
||||
BitsPerCoded int // 8 (unsigned), 16 (signed LE), 32 (IEEE float only)
|
||||
Float bool
|
||||
}
|
||||
|
||||
// decodeWAV zerlegt RIFF/WAVE-Bytes in Format und PCM-Daten.
|
||||
// decodeWAV splits RIFF/WAVE bytes into format and PCM data.
|
||||
//
|
||||
// Unterstützt: PCM (AudioFormat 1) mit 8/16 Bit sowie IEEE-Float
|
||||
// (AudioFormat 3) mit 32 Bit; Mono und Stereo. Alles andere — erst recht
|
||||
// komprimierte Formate — ist ein klarer Fehler; die OS-TTS-Wege von
|
||||
// osbuiltin liefern ausschließlich 16-Bit-PCM-WAV.
|
||||
// Supported: PCM (AudioFormat 1) with 8/16 bit and IEEE float (AudioFormat
|
||||
// 3) with 32 bit; mono and stereo. Everything else, compressed formats in
|
||||
// particular, is a clear error; the OS TTS paths of osbuiltin deliver
|
||||
// 16-bit PCM WAV exclusively.
|
||||
func decodeWAV(data []byte) (pcmFormat, []byte, error) {
|
||||
var f pcmFormat
|
||||
if len(data) < 12 {
|
||||
return f, nil, fmt.Errorf("wav: zu kurz für RIFF-Header (%d Bytes)", len(data))
|
||||
return f, nil, fmt.Errorf("wav: too short for a RIFF header (%d bytes)", len(data))
|
||||
}
|
||||
if string(data[0:4]) != "RIFF" || string(data[8:12]) != "WAVE" {
|
||||
return f, nil, fmt.Errorf("wav: kein RIFF/WAVE-Header")
|
||||
return f, nil, fmt.Errorf("wav: no RIFF/WAVE header")
|
||||
}
|
||||
|
||||
var haveFmt bool
|
||||
@@ -37,12 +36,12 @@ func decodeWAV(data []byte) (pcmFormat, []byte, error) {
|
||||
size := int(binary.LittleEndian.Uint32(data[pos+4 : pos+8]))
|
||||
body := pos + 8
|
||||
if body+size > len(data) {
|
||||
return f, nil, fmt.Errorf("wav: Chunk %q überragt die Datei (Size %d)", id, size)
|
||||
return f, nil, fmt.Errorf("wav: chunk %q exceeds the data (size %d)", id, size)
|
||||
}
|
||||
switch id {
|
||||
case "fmt ":
|
||||
if size < 16 {
|
||||
return f, nil, fmt.Errorf("wav: fmt-Chunk zu kurz (%d)", size)
|
||||
return f, nil, fmt.Errorf("wav: fmt chunk too short (%d)", size)
|
||||
}
|
||||
audioFormat := binary.LittleEndian.Uint16(data[body : body+2])
|
||||
f.Channels = int(binary.LittleEndian.Uint16(data[body+2 : body+4]))
|
||||
@@ -53,29 +52,29 @@ func decodeWAV(data []byte) (pcmFormat, []byte, error) {
|
||||
case audioFormat == 3 && f.BitsPerCoded == 32:
|
||||
f.Float = true
|
||||
default:
|
||||
return f, nil, fmt.Errorf("wav: nicht unterstütztes Format (AudioFormat %d, %d Bit) — erlaubt: PCM 8/16 Bit, Float 32 Bit",
|
||||
return f, nil, fmt.Errorf("wav: unsupported format (AudioFormat %d, %d bit); allowed: PCM 8/16 bit, float 32 bit",
|
||||
audioFormat, f.BitsPerCoded)
|
||||
}
|
||||
if f.Channels < 1 || f.Channels > 2 {
|
||||
return f, nil, fmt.Errorf("wav: %d Kanäle (erlaubt: 1, 2)", f.Channels)
|
||||
return f, nil, fmt.Errorf("wav: %d channels (allowed: 1, 2)", f.Channels)
|
||||
}
|
||||
if f.SampleRate <= 0 {
|
||||
return f, nil, fmt.Errorf("wav: SampleRate %d", f.SampleRate)
|
||||
return f, nil, fmt.Errorf("wav: sample rate %d", f.SampleRate)
|
||||
}
|
||||
haveFmt = true
|
||||
case "data":
|
||||
payload = data[body : body+size]
|
||||
}
|
||||
pos = body + size
|
||||
if size%2 == 1 { // Chunks sind word-aligned
|
||||
if size%2 == 1 { // chunks are word-aligned
|
||||
pos++
|
||||
}
|
||||
}
|
||||
if !haveFmt {
|
||||
return f, nil, fmt.Errorf("wav: kein fmt-Chunk")
|
||||
return f, nil, fmt.Errorf("wav: no fmt chunk")
|
||||
}
|
||||
if payload == nil {
|
||||
return f, nil, fmt.Errorf("wav: kein data-Chunk")
|
||||
return f, nil, fmt.Errorf("wav: no data chunk")
|
||||
}
|
||||
return f, payload, nil
|
||||
}
|
||||
Reference in new issue
Block a user