Skip to content

Commit

Permalink
Fix: エンジンが起動していないと画面が真っ白になるのを修正 (VOICEVOX#1799)
Browse files Browse the repository at this point in the history
* Fix: エンジンが起動していないと画面が真っ白になるのを修正

* Fix: 型周りを修正

Co-Authored-By: y-chan <[email protected]>

* Fix: talk周りのハンドリングを修正

Co-Authored-By: y-chan <[email protected]>

* Add: テストを追加

* Fix: speakerUuidのインクリメントを修正

* `filterCharacterInfosByStyleType`をstoreでも使うようにする (#2)

* Add: コメントを追加

Co-authored-by: Hiroshiba <[email protected]>

* Refactor: filterCharacterInfosByStyleTypeのテストを整理

* Code: コードのスタイルを修正

* テストコード削減

* ドキュメント調整

---------

Co-authored-by: y-chan <[email protected]>
Co-authored-by: Yuto Ashida <[email protected]>
Co-authored-by: Hiroshiba <[email protected]>
  • Loading branch information
4 people authored Jan 31, 2024
1 parent 5115c12 commit 123e555
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 28 deletions.
10 changes: 5 additions & 5 deletions src/components/Talk/EditorHome.vue
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ import {
SplitterPositionType,
Voice,
} from "@/type/preload";
import { filterCharacterInfosByStyleType } from "@/store/utility";
import { parseCombo, setHotkeyFunctions } from "@/store/setting";
const props =
Expand Down Expand Up @@ -726,11 +727,10 @@ const isCharacterOrderDialogOpenComputed = computed({
// TODO: デフォルトスタイル選択(ソング)の実装
// デフォルトスタイル選択(トーク)
const orderedTalkCharacterInfos = computed(() => {
const userOrderedCharacterInfos =
store.getters.USER_ORDERED_CHARACTER_INFOS("talk");
if (userOrderedCharacterInfos == undefined)
throw new Error("userOrderedCharacterInfos == undefined");
return userOrderedCharacterInfos;
return filterCharacterInfosByStyleType(
store.getters.GET_ORDERED_ALL_CHARACTER_INFOS,
"talk"
);
});
const isDefaultStyleSelectDialogOpenComputed = computed({
get: () =>
Expand Down
32 changes: 11 additions & 21 deletions src/store/audio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
DEFAULT_STYLE_NAME,
formatCharacterStyleName,
TuningTranscription,
filterCharacterInfosByStyleType,
} from "./utility";
import { convertAudioQueryFromEditorToEngine } from "./proxy";
import { createPartialStore } from "./vuex";
Expand Down Expand Up @@ -476,30 +477,19 @@ export const audioStore = createPartialStore<AudioStoreTypes>({
* `singerLike`の場合はhummingかsingなスタイルのみを返す。
*/
getter: (state, getters) => (styleType: "all" | "singerLike" | "talk") => {
const isSingingStyle = (styleInfo: StyleInfo) => {
return (
styleInfo.styleType === "humming" || styleInfo.styleType === "sing"
);
};

const allCharacterInfos = getters.GET_ALL_CHARACTER_INFOS;
if (allCharacterInfos.size === 0) return undefined;

let flattenCharacterInfos = [...allCharacterInfos.values()];
// "all"以外の場合は、スタイル・キャラクターをフィルタリングする
if (styleType !== "all") {
flattenCharacterInfos = filterCharacterInfosByStyleType(
flattenCharacterInfos,
styleType
);
}
return (
[...allCharacterInfos.values()]
// スタイルタイプでフィルタリング
.map((info) => {
info.metas.styles = info.metas.styles.filter((style) => {
const isSinging = isSingingStyle(style);
return (
styleType === "all" ||
(styleType === "singerLike" && isSinging) ||
(styleType === "talk" && !isSinging)
);
});
return info;
})
// スタイルがなくなったキャラクターを除外
.filter((info) => info.metas.styles.length !== 0)
flattenCharacterInfos
// ユーザーが並び替えた順番に並び替え
.sort(
(a, b) =>
Expand Down
52 changes: 51 additions & 1 deletion src/store/utility.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import path from "path";
import { Platform } from "quasar";
import { diffArrays } from "diff";
import { ToolbarButtonTagType, isMac } from "@/type/preload";
import {
CharacterInfo,
StyleInfo,
StyleType,
ToolbarButtonTagType,
isMac,
} from "@/type/preload";
import { AccentPhrase, Mora } from "@/openapi";

export const DEFAULT_STYLE_NAME = "ノーマル";
Expand Down Expand Up @@ -478,3 +484,47 @@ export const isOnCommandOrCtrlKeyDown = (event: {
metaKey: boolean;
ctrlKey: boolean;
}) => (isMac && event.metaKey) || (!isMac && event.ctrlKey);

/**
* スタイルがシングエディタで利用可能なスタイルかどうかを判定します。
*/
export const isSingingStyle = (styleInfo: StyleInfo) => {
return (
styleInfo.styleType === "humming" ||
styleInfo.styleType === "sing" ||
styleInfo.styleType === "sing_teacher"
);
};

/**
* CharacterInfoの配列を、指定されたスタイルタイプでフィルタリングします。
* singerLikeはソング系スタイルのみを残します。
* talkはソング系スタイルをすべて除外します。
* FIXME: 上記以外のフィルタリング機能はテストでしか使っていないので、しばらくそのままなら削除する
*/
export const filterCharacterInfosByStyleType = (
characterInfos: CharacterInfo[],
styleType: StyleType | "singerLike"
): CharacterInfo[] => {
const withStylesFiltered: CharacterInfo[] = characterInfos.map(
(characterInfo) => {
const styles = characterInfo.metas.styles.filter((styleInfo) => {
if (styleType === "singerLike") {
return isSingingStyle(styleInfo);
}
// 過去のエンジンにはstyleTypeが存在しないので、「singerLike以外」をtalkとして扱っている。
if (styleType === "talk") {
return !isSingingStyle(styleInfo);
}
return styleInfo.styleType === styleType;
});
return { ...characterInfo, metas: { ...characterInfo.metas, styles } };
}
);

const withoutEmptyStyles = withStylesFiltered.filter(
(characterInfo) => characterInfo.metas.styles.length > 0
);

return withoutEmptyStyles;
};
80 changes: 79 additions & 1 deletion tests/unit/store/utility.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import { v4 as uuidv4 } from "uuid";
import { AccentPhrase, Mora } from "@/openapi";
import { ToolbarButtonTagType, isMac } from "@/type/preload";
import {
CharacterInfo,
StyleInfo,
EngineId,
SpeakerId,
StyleId,
ToolbarButtonTagType,
isMac,
} from "@/type/preload";
import {
formatCharacterStyleName,
sanitizeFileName,
Expand All @@ -16,6 +25,7 @@ import {
convertLongVowel,
getBaseName,
isOnCommandOrCtrlKeyDown,
filterCharacterInfosByStyleType,
} from "@/store/utility";

function createDummyMora(text: string): Mora {
Expand Down Expand Up @@ -319,3 +329,71 @@ test("isOnCommandOrCtrlKeyDown", () => {
false
);
});

describe("filterCharacterInfosByStyleType", () => {
const createCharacterInfo = (
styleTypes: (undefined | "talk" | "humming" | "sing")[]
): CharacterInfo => {
const engineId = EngineId(uuidv4());
return {
portraitPath: "path/to/portrait",
metas: {
policy: "policy",
speakerName: "speakerName",
speakerUuid: SpeakerId(uuidv4()),
styles: styleTypes.map((styleType) => ({
styleType,
styleName: "styleName",
engineId,
styleId: StyleId(Math.random()),
iconPath: "path/to/icon",
portraitPath: "path/to/portrait",
voiceSamplePaths: [],
})),
},
};
};
const characterInfos: CharacterInfo[] = [
createCharacterInfo(["talk"]),
createCharacterInfo(["humming"]),
createCharacterInfo(["sing"]),
createCharacterInfo(["talk", "humming", "sing"]),
createCharacterInfo([undefined]),
];

for (const styleType of ["humming", "sing"] as const) {
test(`${styleType}のキャラクターが取得できる`, () => {
const filtered = filterCharacterInfosByStyleType(
characterInfos,
styleType
);
// talkしかないキャラクターは除外される
expect(filtered.length).toBe(2);
filtered.forEach((c) => {
// styleTypeが指定したものになっている
expect(c.metas.styles[0].styleType).toBe(styleType);
// stylesの数が正しい
expect(c.metas.styles.length).toBe(1);
});
});
}

test(`singerLikeを指定するとsingとhummingのキャラクターが取得できる`, () => {
const filtered = filterCharacterInfosByStyleType(
characterInfos,
"singerLike"
);
expect(filtered.length).toBe(3);
expect(filtered[0].metas.styles.length).toBe(1);
expect(filtered[1].metas.styles.length).toBe(1);
expect(filtered[2].metas.styles.length).toBe(2);
});

test(`talkを指定するとsingerLike以外のキャラクターが取得できる`, () => {
const filtered = filterCharacterInfosByStyleType(characterInfos, "talk");
expect(filtered.length).toBe(3);
expect(filtered[0].metas.styles.length).toBe(1);
expect(filtered[1].metas.styles.length).toBe(1);
expect(filtered[2].metas.styles.length).toBe(1);
});
});

0 comments on commit 123e555

Please sign in to comment.