diff --git a/src/components/AudioDetail.vue b/src/components/AudioDetail.vue index 26b1a706d4..9bc252ace2 100644 --- a/src/components/AudioDetail.vue +++ b/src/components/AudioDetail.vue @@ -5,8 +5,20 @@
- - + +
@@ -260,7 +272,7 @@ import AudioAccent from "./AudioAccent.vue"; import AudioParameter from "./AudioParameter.vue"; import { HotkeyAction, HotkeyReturnType, MoraDataType } from "@/type/preload"; import { setHotkeyFunctions } from "@/store/setting"; -import { Mora } from "@/openapi/models"; +import { EngineManifest, Mora } from "@/openapi/models"; export default defineComponent({ components: { AudioAccent, AudioParameter, Tip }, @@ -349,6 +361,32 @@ export default defineComponent({ const query = computed(() => audioItem.value?.query); const accentPhrases = computed(() => query.value?.accentPhrases); + const supportedFeatures = computed( + () => + (audioItem.value?.engineId && + store.state.engineManifests[audioItem.value?.engineId] + .supportedFeatures) as + | EngineManifest["supportedFeatures"] + | undefined + ); + + // エンジンが変わったとき、selectedDetailが対応していないものを選択している場合はaccentに戻す + // TODO: 連続再生するとアクセントに移動してしまうため、タブの中身を全てdisabledにする、半透明divをかぶせるなど + // タブ自体の無効化&移動以外の方法で無効化する + watch( + supportedFeatures, + (newFeatures) => { + if ( + (!newFeatures?.adjustMoraPitch && selectedDetail.value === "pitch") || + (!newFeatures?.adjustPhonemeLength && + selectedDetail.value === "length") + ) { + selectedDetail.value = "accent"; + } + }, + { immediate: true } + ); + const activePointScrollMode = computed( () => store.state.activePointScrollMode ); @@ -767,6 +805,7 @@ export default defineComponent({ activePoint, setPlayAndStartPoint, uiLocked, + supportedFeatures, audioItem, query, accentPhrases, diff --git a/src/components/AudioInfo.vue b/src/components/AudioInfo.vue index 772faa107c..e35a7cbea8 100644 --- a/src/components/AudioInfo.vue +++ b/src/components/AudioInfo.vue @@ -165,7 +165,11 @@
- 話速 {{ speedScaleSlider.state.currentValue.value?.toFixed(2) }}
- 音高 {{ pitchScaleSlider.state.currentValue.value?.toFixed(2) }}
- 抑揚 {{ intonationScaleSlider.state.currentValue.value?.toFixed(2) }} @@ -232,7 +244,11 @@ />
- 音量 {{ volumeScaleSlider.state.currentValue.value?.toFixed(2) }}
- 開始無音 {{ prePhonemeLengthSlider.state.currentValue.value?.toFixed(2) }} @@ -277,7 +297,11 @@ />
- 終了無音 {{ postPhonemeLengthSlider.state.currentValue.value?.toFixed(2) }} @@ -310,6 +334,7 @@ import { useStore } from "@/store"; import { Preset } from "@/type/preload"; import { previewSliderHelper } from "@/helpers/previewSliderHelper"; import PresetManageDialog from "./PresetManageDialog.vue"; +import { EngineManifest } from "@/openapi"; export default defineComponent({ name: "AudioInfo", @@ -333,6 +358,15 @@ export default defineComponent({ ); const query = computed(() => audioItem.value?.query); + const supportedFeatures = computed( + () => + (audioItem.value?.engineId && + store.state.engineManifests[audioItem.value?.engineId] + .supportedFeatures) as + | EngineManifest["supportedFeatures"] + | undefined + ); + const applyPreset = () => { store.dispatch("COMMAND_APPLY_AUDIO_PRESET", { audioKey: props.activeAudioKey, @@ -383,7 +417,8 @@ export default defineComponent({ const speedScaleSlider = previewSliderHelper({ modelValue: () => query.value?.speedScale ?? null, - disable: () => uiLocked.value, + disable: () => + uiLocked.value || supportedFeatures.value?.adjustSpeedScale === false, onChange: setAudioSpeedScale, max: () => 2, min: () => 0.5, @@ -393,7 +428,8 @@ export default defineComponent({ }); const pitchScaleSlider = previewSliderHelper({ modelValue: () => query.value?.pitchScale ?? null, - disable: () => uiLocked.value, + disable: () => + uiLocked.value || supportedFeatures.value?.adjustPitchScale === false, onChange: setAudioPitchScale, max: () => 0.15, min: () => -0.15, @@ -402,7 +438,9 @@ export default defineComponent({ }); const intonationScaleSlider = previewSliderHelper({ modelValue: () => query.value?.intonationScale ?? null, - disable: () => uiLocked.value, + disable: () => + uiLocked.value || + supportedFeatures.value?.adjustIntonationScale === false, onChange: setAudioIntonationScale, max: () => 2, min: () => 0, @@ -412,7 +450,8 @@ export default defineComponent({ }); const volumeScaleSlider = previewSliderHelper({ modelValue: () => query.value?.volumeScale ?? null, - disable: () => uiLocked.value, + disable: () => + uiLocked.value || supportedFeatures.value?.adjustVolumeScale === false, onChange: setAudioVolumeScale, max: () => 2, min: () => 0, diff --git a/src/store/setting.ts b/src/store/setting.ts index 71e2710691..0ab9fb25af 100644 --- a/src/store/setting.ts +++ b/src/store/setting.ts @@ -39,6 +39,7 @@ export const settingStoreState: SettingStoreState = { toolbarSetting: [], engineIds: [], engineInfos: {}, + engineManifests: {}, themeSetting: { currentTheme: "Default", availableThemes: [], diff --git a/src/store/type.ts b/src/store/type.ts index 5327488d7a..8a21cfbf60 100644 --- a/src/store/type.ts +++ b/src/store/type.ts @@ -6,7 +6,12 @@ import { StoreOptions, } from "./vuex"; import { Patch } from "immer"; -import { AccentPhrase, AudioQuery, UserDictWord } from "@/openapi"; +import { + AccentPhrase, + AudioQuery, + EngineManifest, + UserDictWord, +} from "@/openapi"; import { createCommandMutationTree, PayloadRecipeTree } from "./command"; import { CharacterInfo, @@ -843,6 +848,7 @@ export type SettingStoreState = { toolbarSetting: ToolbarSetting; engineIds: string[]; engineInfos: Record; + engineManifests: Record; themeSetting: ThemeSetting; acceptRetrieveTelemetry: AcceptRetrieveTelemetryStatus; experimentalSetting: ExperimentalSetting; @@ -1042,6 +1048,12 @@ type UiStoreTypes = { SET_ENGINE_INFOS: { mutation: { engineInfos: EngineInfo[] } }; + SET_ENGINE_MANIFESTS: { + mutation: { engineManifests: Record }; + }; + + FETCH_AND_SET_ENGINE_MANIFESTS: { action(): void }; + SET_INHERIT_AUDIOINFO: { mutation: { inheritAudioInfo: boolean }; action(payload: { inheritAudioInfo: boolean }): void; diff --git a/src/store/ui.ts b/src/store/ui.ts index b0a4b107e4..da23755fc3 100644 --- a/src/store/ui.ts +++ b/src/store/ui.ts @@ -10,6 +10,7 @@ import { VoiceVoxStoreOptions, } from "./type"; import { ActivePointScrollMode, EngineInfo } from "@/type/preload"; +import { EngineManifest } from "@/openapi"; export function createUILockAction( action: ( @@ -147,6 +148,12 @@ export const uiStore: VoiceVoxStoreOptions = engineInfos.map((engineInfo) => [engineInfo.uuid, "STARTING"]) ); }, + SET_ENGINE_MANIFESTS( + state, + { engineManifests }: { engineManifests: Record } + ) { + state.engineManifests = engineManifests; + }, SET_INHERIT_AUDIOINFO( state, { inheritAudioInfo }: { inheritAudioInfo: boolean } @@ -387,6 +394,25 @@ export const uiStore: VoiceVoxStoreOptions = engineInfos: await window.electron.engineInfos(), }); }, + async FETCH_AND_SET_ENGINE_MANIFESTS({ state, commit }) { + commit("SET_ENGINE_MANIFESTS", { + engineManifests: Object.fromEntries( + await Promise.all( + state.engineIds.map( + async (engineId) => + await this.dispatch("INSTANTIATE_ENGINE_CONNECTOR", { + engineId, + }).then(async (instance) => [ + engineId, + await instance.invoke("engineManifestEngineManifestGet")( + {} + ), + ]) + ) + ) + ), + }); + }, async SET_INHERIT_AUDIOINFO( { commit }, { inheritAudioInfo }: { inheritAudioInfo: boolean } diff --git a/src/views/Home.vue b/src/views/Home.vue index 4b09148f41..d2886d387f 100644 --- a/src/views/Home.vue +++ b/src/views/Home.vue @@ -469,6 +469,7 @@ export default defineComponent({ const isCompletedInitialStartup = ref(false); onMounted(async () => { await store.dispatch("GET_ENGINE_INFOS"); + await store.dispatch("FETCH_AND_SET_ENGINE_MANIFESTS"); await store.dispatch("START_WAITING_ENGINE_ALL"); await store.dispatch("LOAD_CHARACTER_ALL"); diff --git a/tests/unit/store/Vuex.spec.ts b/tests/unit/store/Vuex.spec.ts index d37e5fc47b..6b5417274f 100644 --- a/tests/unit/store/Vuex.spec.ts +++ b/tests/unit/store/Vuex.spec.ts @@ -81,6 +81,28 @@ describe("store/vuex.js test", () => { host: "http://127.0.0.1", }, }, + engineManifests: { + "88022f86-c823-436e-85a3-500c629749c4": { + manifestVersion: "0.13.0", + name: "DUMMY VOICEVOX ENGINE", + uuid: "c7b58856-bd56-4aa1-afb7-b8415f824b06", + url: "https://github.com/VOICEVOX/voicevox_engine", + icon: "engine_manifest_assets/icon.png", + defaultSamplingRate: 24000, + termsOfService: "engine_manifest_assets/terms_of_service.md", + updateInfos: [], + dependencyLicenses: [], + supportedFeatures: { + adjustMoraPitch: true, + adjustPhonemeLength: true, + adjustSpeedScale: true, + adjustPitchScale: true, + adjustIntonationScale: true, + adjustVolumeScale: true, + interrogativeUpspeak: true, + }, + }, + }, experimentalSetting: { enablePreset: false, enableInterrogativeUpspeak: false,