Skip to content

Commit

Permalink
複数選択:キャラクターを変更できるように (#1546)
Browse files Browse the repository at this point in the history
  • Loading branch information
sevenc-nanashi authored Sep 19, 2023
1 parent 5145f5d commit 6c683c8
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 106 deletions.
10 changes: 6 additions & 4 deletions src/components/AudioCell.vue
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,8 @@ const userOrderedCharacterInfos = computed(() => {
throw new Error("USER_ORDERED_CHARACTER_INFOS == undefined");
return infos;
});
const isInitializingSpeaker = computed(
() => store.state.audioKeyInitializingSpeaker === props.audioKey
const isInitializingSpeaker = computed(() =>
store.state.audioKeysWithInitializingSpeaker.includes(props.audioKey)
);
const audioItem = computed(() => store.state.audioItems[props.audioKey]);
Expand Down Expand Up @@ -262,8 +262,10 @@ const selectedVoice = computed<Voice | undefined>({
},
set(voice: Voice | undefined) {
if (voice == undefined) return;
store.dispatch("COMMAND_CHANGE_VOICE", {
audioKey: props.audioKey,
store.dispatch("COMMAND_MULTI_CHANGE_VOICE", {
audioKeys: isMultiSelectEnabled.value
? store.getters.SELECTED_AUDIO_KEYS
: [props.audioKey],
voice,
});
},
Expand Down
5 changes: 4 additions & 1 deletion src/components/CharacterPortrait.vue
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,10 @@ const portraitPath = computed(
const isInitializingSpeaker = computed(() => {
const activeAudioKey = store.getters.ACTIVE_AUDIO_KEY;
return store.state.audioKeyInitializingSpeaker === activeAudioKey;
return (
activeAudioKey &&
store.state.audioKeysWithInitializingSpeaker.includes(activeAudioKey)
);
});
const isMultipleEngine = computed(() => store.state.engineIds.length > 1);
Expand Down
172 changes: 90 additions & 82 deletions src/store/audio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ const getAudioElement = (() => {

export const audioStoreState: AudioStoreState = {
characterInfos: {},
audioKeysWithInitializingSpeaker: [],
morphableTargetsInfo: {},
audioItems: {},
audioKeys: [],
Expand Down Expand Up @@ -504,30 +505,30 @@ export const audioStore = createPartialStore<AudioStoreTypes>({
/**
* AudioItemに設定される話者(スタイルID)に対してエンジン側の初期化を行い、即座に音声合成ができるようにする。
*/
async action({ commit, dispatch }, { engineId, audioKey, styleId }) {
async action({ commit, dispatch }, { engineId, audioKeys, styleId }) {
const isInitialized = await dispatch("IS_INITIALIZED_ENGINE_SPEAKER", {
engineId,
styleId,
});
if (isInitialized) return;

commit("SET_AUDIO_KEY_INITIALIZING_SPEAKER", {
audioKey,
commit("SET_AUDIO_KEYS_WITH_INITIALIZING_SPEAKER", {
audioKeys,
});
await dispatch("INITIALIZE_ENGINE_SPEAKER", {
engineId,
styleId,
}).finally(() => {
commit("SET_AUDIO_KEY_INITIALIZING_SPEAKER", {
audioKey: undefined,
commit("SET_AUDIO_KEYS_WITH_INITIALIZING_SPEAKER", {
audioKeys: [],
});
});
},
},

SET_AUDIO_KEY_INITIALIZING_SPEAKER: {
mutation(state, { audioKey }: { audioKey?: AudioKey }) {
state.audioKeyInitializingSpeaker = audioKey;
SET_AUDIO_KEYS_WITH_INITIALIZING_SPEAKER: {
mutation(state, { audioKeys }: { audioKeys: AudioKey[] }) {
state.audioKeysWithInitializingSpeaker = audioKeys;
},
},

Expand Down Expand Up @@ -2095,10 +2096,10 @@ export const audioCommandStore = transformCommandStore(
},
},

COMMAND_CHANGE_VOICE: {
COMMAND_MULTI_CHANGE_VOICE: {
mutation(
draft,
payload: { audioKey: AudioKey; voice: Voice } & (
payload: { audioKeys: AudioKey[]; voice: Voice } & (
| { update: "RollbackStyleId" }
| {
update: "AccentPhrases";
Expand All @@ -2110,93 +2111,100 @@ export const audioCommandStore = transformCommandStore(
}
)
) {
audioStore.mutations.SET_AUDIO_VOICE(draft, {
audioKey: payload.audioKey,
voice: payload.voice,
});
for (const audioKey of payload.audioKeys) {
audioStore.mutations.SET_AUDIO_VOICE(draft, {
audioKey,
voice: payload.voice,
});
}

if (payload.update === "RollbackStyleId") return;

const presetKey = draft.audioItems[payload.audioKey].presetKey;

const { nextPresetKey, shouldApplyPreset } = determineNextPresetKey(
draft,
payload.voice,
presetKey,
"changeVoice"
);
for (const audioKey of payload.audioKeys) {
const presetKey = draft.audioItems[audioKey].presetKey;

audioStore.mutations.SET_AUDIO_PRESET_KEY(draft, {
audioKey: payload.audioKey,
presetKey: nextPresetKey,
});
const { nextPresetKey, shouldApplyPreset } = determineNextPresetKey(
draft,
payload.voice,
presetKey,
"changeVoice"
);

if (payload.update == "AccentPhrases") {
audioStore.mutations.SET_ACCENT_PHRASES(draft, {
audioKey: payload.audioKey,
accentPhrases: payload.accentPhrases,
});
} else if (payload.update == "AudioQuery") {
audioStore.mutations.SET_AUDIO_QUERY(draft, {
audioKey: payload.audioKey,
audioQuery: payload.query,
audioStore.mutations.SET_AUDIO_PRESET_KEY(draft, {
audioKey,
presetKey: nextPresetKey,
});
}

if (shouldApplyPreset) {
audioStore.mutations.APPLY_AUDIO_PRESET(draft, {
audioKey: payload.audioKey,
});
if (payload.update == "AccentPhrases") {
audioStore.mutations.SET_ACCENT_PHRASES(draft, {
audioKey,
accentPhrases: payload.accentPhrases,
});
} else if (payload.update == "AudioQuery") {
audioStore.mutations.SET_AUDIO_QUERY(draft, {
audioKey,
audioQuery: payload.query,
});
}

if (shouldApplyPreset) {
audioStore.mutations.APPLY_AUDIO_PRESET(draft, {
audioKey,
});
}
}
},
async action(
{ state, dispatch, commit },
{ audioKey, voice }: { audioKey: AudioKey; voice: Voice }
{ audioKeys, voice }: { audioKeys: AudioKey[]; voice: Voice }
) {
const query = state.audioItems[audioKey].query;
const engineId = voice.engineId;
const styleId = voice.styleId;
try {
await dispatch("SETUP_SPEAKER", { audioKey, engineId, styleId });

if (query !== undefined) {
const accentPhrases = query.accentPhrases;
const newAccentPhrases: AccentPhrase[] = await dispatch(
"FETCH_MORA_DATA",
{
accentPhrases,
engineId,
styleId,
await dispatch("SETUP_SPEAKER", { audioKeys, engineId, styleId });
await Promise.all(
audioKeys.map(async (audioKey) => {
try {
const query = state.audioItems[audioKey].query;
if (query !== undefined) {
const accentPhrases = query.accentPhrases;
const newAccentPhrases: AccentPhrase[] = await dispatch(
"FETCH_MORA_DATA",
{
accentPhrases,
engineId,
styleId,
}
);
commit("COMMAND_MULTI_CHANGE_VOICE", {
audioKeys,
voice,
update: "AccentPhrases",
accentPhrases: newAccentPhrases,
});
} else {
const text = state.audioItems[audioKey].text;
const query: AudioQuery = await dispatch("FETCH_AUDIO_QUERY", {
text: text,
engineId,
styleId,
});
commit("COMMAND_MULTI_CHANGE_VOICE", {
audioKeys,
voice,
update: "AudioQuery",
query,
});
}
);
commit("COMMAND_CHANGE_VOICE", {
audioKey,
voice,
update: "AccentPhrases",
accentPhrases: newAccentPhrases,
});
} else {
const text = state.audioItems[audioKey].text;
const query: AudioQuery = await dispatch("FETCH_AUDIO_QUERY", {
text: text,
engineId,
styleId,
});
commit("COMMAND_CHANGE_VOICE", {
audioKey,
voice,
update: "AudioQuery",
query,
});
}
} catch (error) {
commit("COMMAND_CHANGE_VOICE", {
audioKey,
voice,
update: "RollbackStyleId",
});
throw error;
}
} catch (error) {
commit("COMMAND_MULTI_CHANGE_VOICE", {
audioKeys,
voice,
update: "RollbackStyleId",
});
throw error;
}
})
);
},
},

Expand Down
14 changes: 7 additions & 7 deletions src/store/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export type StoreType<T, U extends "getter" | "mutation" | "action"> = {
export type AudioStoreState = {
characterInfos: Record<EngineId, CharacterInfo[]>;
morphableTargetsInfo: Record<EngineId, MorphableTargetInfoTable>;
audioKeyInitializingSpeaker?: string;
audioKeysWithInitializingSpeaker: AudioKey[];
audioItems: Record<AudioKey, AudioItem>;
audioKeys: AudioKey[];
audioStates: Record<AudioKey, AudioState>;
Expand Down Expand Up @@ -182,14 +182,14 @@ export type AudioStoreTypes = {

SETUP_SPEAKER: {
action(payload: {
audioKey: AudioKey;
audioKeys: AudioKey[];
engineId: EngineId;
styleId: StyleId;
}): void;
};

SET_AUDIO_KEY_INITIALIZING_SPEAKER: {
mutation: { audioKey?: AudioKey };
SET_AUDIO_KEYS_WITH_INITIALIZING_SPEAKER: {
mutation: { audioKeys: AudioKey[] };
};

SET_ACTIVE_AUDIO_KEY: {
Expand Down Expand Up @@ -529,8 +529,8 @@ export type AudioCommandStoreTypes = {
action(payload: { audioKey: AudioKey; text: string }): void;
};

COMMAND_CHANGE_VOICE: {
mutation: { audioKey: AudioKey; voice: Voice } & (
COMMAND_MULTI_CHANGE_VOICE: {
mutation: { audioKeys: AudioKey[]; voice: Voice } & (
| { update: "RollbackStyleId" }
| {
update: "AccentPhrases";
Expand All @@ -541,7 +541,7 @@ export type AudioCommandStoreTypes = {
query: AudioQuery;
}
);
action(payload: { audioKey: AudioKey; voice: Voice }): void;
action(payload: { audioKeys: AudioKey[]; voice: Voice }): void;
};

COMMAND_CHANGE_ACCENT: {
Expand Down
7 changes: 5 additions & 2 deletions src/views/EditorHome.vue
Original file line number Diff line number Diff line change
Expand Up @@ -526,7 +526,10 @@ watch(userOrderedCharacterInfos, (userOrderedCharacterInfos) => {
};
// FIXME: UNDOができてしまうのでできれば直したい
store.dispatch("COMMAND_CHANGE_VOICE", { audioKey: first, voice: voice });
store.dispatch("COMMAND_MULTI_CHANGE_VOICE", {
audioKeys: [first],
voice: voice,
});
}
});
Expand Down Expand Up @@ -574,7 +577,7 @@ onMounted(async () => {
// 最初の話者を初期化
store.dispatch("SETUP_SPEAKER", {
audioKey: newAudioKey,
audioKeys: [newAudioKey],
engineId: audioItem.voice.engineId,
styleId: audioItem.voice.styleId,
});
Expand Down
10 changes: 10 additions & 0 deletions tests/e2e/browser/複数選択/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Page } from "@playwright/test";

export async function addAudioCells(page: Page, count: number) {
for (let i = 0; i < count; i++) {
await page.getByRole("button", { name: "テキストを追加" }).click();
await page.waitForTimeout(100);
}
}

export const ctrlLike = process.platform === "darwin" ? "Meta" : "Control";
Loading

0 comments on commit 6c683c8

Please sign in to comment.