-
Notifications
You must be signed in to change notification settings - Fork 1
/
SpeechSystem.ts
50 lines (43 loc) · 1.42 KB
/
SpeechSystem.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import _ from "lodash"
import type { ReadingLine, FillblankLine } from "./Pattern"
import { sprachdex } from "./sprachdex"
export class SpeechSystem {
voice: SpeechSynthesisVoice | null = null
constructor() { }
async loadVoices(): Promise<SpeechSynthesisVoice[]> {
const voices = speechSynthesis.getVoices()
if (voices.length > 0)
return voices
// Voices haven't loaded yet, wait for them
return await new Promise((resolve) => {
speechSynthesis.onvoiceschanged = () => {
resolve(speechSynthesis.getVoices())
}
})
}
async getVoice() {
if (this.voice) return this.voice
const allVoices = await this.loadVoices()
const germanVoices = allVoices.filter((v) => v.lang === "de-DE")
const voicePrefs = _.sortBy(germanVoices, (v) =>
v.name.startsWith("Google") ? -1 : 0
)
this.voice = voicePrefs[0] || null
return this.voice
}
async speak(line: ReadingLine | FillblankLine) {
const voice = await this.getVoice()
if (!voice) return
await new Promise<void>((resolve) => {
const text = line.message.replace(/[[_*]+/g, "")
const utter = new SpeechSynthesisUtterance(text)
utter.lang = "de"
utter.voice = voice
const character = sprachdex.getCharacter(line.from)
utter.rate = character.rate || 1.0
utter.pitch = character.pitch || 1.0
utter.onend = () => resolve()
speechSynthesis.speak(utter)
})
}
}