Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

65 change keyboard voices #80

Merged
merged 4 commits into from
Dec 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/common/interfaces/ConfigFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export interface Card {
title?: string;
audioPath?: string;
audioText?: string;
audioVoice?: string
answer?: true
}

Expand Down
52 changes: 32 additions & 20 deletions src/frontend/components/EditorView/TTSDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
<v-card-text>
<v-form>
<v-select
v-model="voice"
:items="voices"
v-model="currentVoice"
:items="voiceOptions"
label="Голос"
item-value="value"
item-title="text"
Expand Down Expand Up @@ -63,44 +63,56 @@
</template>

<script lang="ts" setup>
import { ref, watch, defineProps, defineEmits, computed } from "vue";
import { ref, watch, defineProps, defineEmits, computed, Ref } from "vue";
import { useStore } from "vuex";
import { storageService } from "@/frontend/services/card-storage-service";
import { TTS } from "@/frontend/utils/TTS";

const store = useStore();
const props = defineProps<{ file: string, audioText?: string }>();
const emit = defineEmits<{(e: "audio", payload: { audioSrcFile: string, audioText: string }): void }>();
const props = defineProps<{ file: string, audioText?: string, audioVoice?: string }>();
const emit = defineEmits<{(e: "audio", payload: { audioSrcFile: string, audioText: string, audioVoice: string }): void }>();

const ui_disabled = computed(() => store.state.ui.disabled);

const voices = [
{ value: "zahar", text: "Захар" },
{ value: "ermil", text: "Емиль" },
{ value: "jane", text: "Джейн" },
{ value: "oksana", text: "Оксана" },
{ value: "alena", text: "Алёна" },
{ value: "filipp", text: "Филипп" },
{ value: "omazh", text: "Ома" }
];
const dialog = ref(false);
const audioText = ref(props.audioText ?? "");
const voice = ref("alena");

const audioText: Ref<(string)> = ref("");
const currentAudioText = computed({
get () {
return audioText.value;
},
set (v: string) {
audioText.value = v;
}
});

const voiceOptions = TTS.voices;
const defaultSettingsVoice = computed(() => store.state.voice);
const voice: Ref<(string)> = ref("");
const currentVoice = computed({
get () {
return voice.value;
},
set (v: string) {
voice.value = v;
}
});

watch(dialog, onDialog);

function create () {
store.dispatch("disable_ui");
storageService.createAudioFromText(props.file, audioText.value, voice.value).then((audioSrcFile: string) => {
emit("audio", { audioSrcFile, audioText: audioText.value });
storageService.createAudioFromText(props.file, currentAudioText.value, currentVoice.value).then((audioSrcFile: string) => {
emit("audio", { audioSrcFile, audioText: audioText.value, audioVoice: voice.value });
store.dispatch("enable_ui");
dialog.value = false;
});
}

function onDialog (v: boolean) {
if (!v) {
audioText.value = "";
if (v) {
currentVoice.value = props.audioVoice ?? defaultSettingsVoice.value;
currentAudioText.value = props.audioText ?? "";
}
}

Expand Down
7 changes: 6 additions & 1 deletion src/frontend/components/OutputLine.vue
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ const buttonEnabled = computed(() => {
return store.state.button.enabled;
});

const voiceToPlay = computed(() => {
return store.state.voice;
});

const withoutSpace = computed(() => {
return props.config?.withoutSpace;
});
Expand Down Expand Up @@ -144,9 +148,10 @@ function backspace () {
}

async function say () {
if (isPlaying.value) return;
isPlaying.value = true;
if (props.config?.withoutSpace) {
if (text.value) await TTS.instance.playText(text.value);
if (text.value) await TTS.instance.playText(text.value, voiceToPlay.value);
} else await TTS.instance.playCards(props.file, props.cards);
isPlaying.value = false;
}
Expand Down
53 changes: 53 additions & 0 deletions src/frontend/components/Settings/VoiceSettings.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<template>
<v-sheet>
<v-card>
<v-card-title> Голос озвучки </v-card-title>
<v-card-text>
<v-form>
<v-select
v-model="voice"
:items="voices"
label="Голос"
item-value="value"
item-title="text"
/>
<v-btn
color="success"
@click="playExample"
>
Прослушать
</v-btn>
</v-form>
</v-card-text>
</v-card>
</v-sheet>
</template>
<script lang="ts" setup>
import { TTS } from "@/frontend/utils/TTS";
import { computed, ref } from "vue";
import { useStore } from "vuex";

const store = useStore();
const isPlayingExample = ref(false);

const voices = TTS.voices;

const voice = computed({
get () {
return store.state.voice;
},
set (value: string) {
store.dispatch("voice_change", value);
}
});

function playExample () {
if (isPlayingExample.value) return;
isPlayingExample.value = true;
const selected = voices.find((v) => v.value === voice.value);
if (!selected) return;
TTS.instance.playText(selected.text, selected.value).finally(() => {
isPlayingExample.value = false;
});
}
</script>
1 change: 1 addition & 0 deletions src/frontend/store/LINKaStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export interface LINKaStore {
accent: string,
secondary: string
}
voice: string,

keyMapping: KeyMap
selectedKey?: Side;
Expand Down
8 changes: 8 additions & 0 deletions src/frontend/store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const fields = [
{ commit: "colors_primary", default: "#197377" } as Field<string>,
{ commit: "colors_accent", default: "#7DF6FA" } as Field<string>,
{ commit: "colors_secondary", default: "#FFAF00" } as Field<string>,
{ commit: "voice", default: "alena" } as Field<string>,
{ commit: "button_timeout", default: 1000 } as Field<number>,
{ commit: "button_eyeSelect", default: true } as Field<boolean>,
{ commit: "button_eyeActivation", default: true } as Field<boolean>,
Expand Down Expand Up @@ -40,6 +41,7 @@ const store = createStore<LINKaStore>({
accent: "",
primary: "#197377"
},
voice: "alena",
button: {
timeout: 1000,
enabled: true,
Expand Down Expand Up @@ -126,6 +128,9 @@ const store = createStore<LINKaStore>({
colors_secondary ({ colors }, value) {
colors.secondary = value;
},
voice ({ voice }, value) {
voice = value;
},
editor_current ({ editor }, value) {
editor.current = value;
},
Expand Down Expand Up @@ -228,6 +233,9 @@ const store = createStore<LINKaStore>({
commit("keyMapping_" + side, state.keyMapping[side].filter((c) => c !== code));
state.selectedKey = undefined;
},
voice_change ({ state }, voice: string) {
state.voice = voice;
},

interface_outputLine ({ state, commit }) {
commit("interface_outputLine", !state.ui.outputLine);
Expand Down
10 changes: 10 additions & 0 deletions src/frontend/utils/TTS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,16 @@ export class TTS {
return TTS._instance;
}

static voices = [
{ value: "zahar", text: "Захар" },
{ value: "ermil", text: "Емиль" },
{ value: "jane", text: "Джейн" },
{ value: "oksana", text: "Оксана" },
{ value: "alena", text: "Алёна" },
{ value: "filipp", text: "Филипп" },
{ value: "omazh", text: "Ома" }
];

public async playCards (file: string, cards: Card[], force = false) {
if (this.isPlaying) {
this.isPlaying = false;
Expand Down
10 changes: 8 additions & 2 deletions src/frontend/views/EditorView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,12 @@
<v-card-text>
<v-container>
<v-row>
<TTSDialog :file="filename" @audio="onAudioFromTTS" />
<TTSDialog
:file="filename"
@audio="onAudioFromTTS"
:audioText="selected.audioText"
:audioVoice="selected.audioVoice"
/>
</v-row>
<v-row>
<v-btn block class="mb-1" :disabled="ui_disabled" @click="selectAudio">
Expand Down Expand Up @@ -391,10 +396,11 @@ async function selectImage () {
store.dispatch("enable_ui");
}

function onAudioFromTTS ({ audioSrcFile, audioText }: { audioSrcFile: string, audioText: string }) {
function onAudioFromTTS ({ audioSrcFile, audioText, audioVoice }: { audioSrcFile: string, audioText: string, audioVoice: string }) {
if (!selected.value) throw new Error("Setting audio from TTSDialog to a nullish selected card");
selected.value.audioPath = audioSrcFile;
selected.value.audioText = audioText;
selected.value.audioVoice = audioVoice;
}
/**
* Called each time the user decides to open the fs navigator and use an .mp3
Expand Down
9 changes: 9 additions & 0 deletions src/frontend/views/SettingsView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,14 @@
<color-settings />
</v-col>
</v-row>
<v-row>
<v-col
cols="12"
md="8"
>
<voice-settings />
</v-col>
</v-row>
<v-row>
<v-col
cols="12"
Expand All @@ -104,6 +112,7 @@ import { computed, onMounted } from "vue";
import { useStore } from "vuex";

import ColorSettings from "@/frontend/components/Settings/ColorsSettings.vue";
import VoiceSettings from "@/frontend/components/Settings/VoiceSettings.vue";
import InputSettings from "@/frontend/components/Settings/InputSettings.vue";
import { Metric } from "@/frontend/utils/Metric";

Expand Down
Loading