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

perf: 非同期処理を改良 #1973

Merged
merged 10 commits into from
May 13, 2024
146 changes: 89 additions & 57 deletions src/store/audio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,27 +278,16 @@ export const audioStore = createPartialStore<AudioStoreTypes>({
},
},

/**
* CharacterInfoをエンジンから取得する。
* GETクエリとBASE64のデコードがそこそこ重いため並行処理をしている。
*/
LOAD_CHARACTER: {
sabonerune marked this conversation as resolved.
Show resolved Hide resolved
action: createUILockAction(
async ({ commit, dispatch, state }, { engineId }) => {
const { speakers, singers } = await dispatch(
"INSTANTIATE_ENGINE_CONNECTOR",
{
engineId,
},
)
.then(async (instance) => {
return {
speakers: await instance.invoke("speakersSpeakersGet")({}),
singers: state.engineManifests[engineId].supportedFeatures.sing
? await instance.invoke("singersSingersGet")({})
: [],
};
})
.catch((error) => {
window.backend.logError(error, `Failed to get speakers.`);
throw error;
});
const instance = await dispatch("INSTANTIATE_ENGINE_CONNECTOR", {
engineId,
});
const base64ToUrl = function (base64: string, type: string) {
const buffer = Buffer.from(base64, "base64");
const iconBlob = new Blob([buffer.buffer], { type: type });
Expand Down Expand Up @@ -333,57 +322,100 @@ export const audioStore = createPartialStore<AudioStoreTypes>({
});
return styles;
};
const getSpeakerInfo = async function (speaker: Speaker) {
const getCharacterInfo = async (
speaker: Speaker | undefined,
singer: Speaker | undefined,
) => {
// 同じIDの歌手がいる場合は歌手情報を取得し、スタイルをマージする
// FIXME: ソングのみのキャラも考慮する
const singer = singers.find(
(singer) => singer.speakerUuid === speaker.speakerUuid,
);
const { speakerInfo, singerInfo } = await dispatch(
"INSTANTIATE_ENGINE_CONNECTOR",
{
engineId,
},
)
.then(async (instance) => {
const speakerInfo = await instance.invoke(
"speakerInfoSpeakerInfoGet",
)({
let speakerInfoPromise: Promise<SpeakerInfo> | undefined = undefined;
let speakerStylePromise: Promise<StyleInfo[]> | undefined = undefined;
if (speaker != undefined) {
speakerInfoPromise = instance
.invoke("speakerInfoSpeakerInfoGet")({
speakerUuid: speaker.speakerUuid,
})
.catch((error) => {
window.backend.logError(error, `Failed to get speakerInfo.`);
throw error;
});
let singerInfo: SpeakerInfo | undefined = undefined;
if (singer) {
singerInfo = await instance.invoke("singerInfoSingerInfoGet")({
speakerUuid: singer.speakerUuid,
});
}
return { speakerInfo, singerInfo };
})
.catch((error) => {
window.backend.logError(error, `Failed to get speakers.`);
throw error;
});
const styles = getStyles(speaker, speakerInfo);
if (singer && singerInfo) {
styles.push(...getStyles(singer, singerInfo));
speakerStylePromise = speakerInfoPromise.then((speakerInfo) =>
getStyles(speaker, speakerInfo),
);
}

let singerInfoPromise: Promise<SpeakerInfo> | undefined = undefined;
let singerStylePromise: Promise<StyleInfo[]> | undefined = undefined;
if (singer != undefined) {
singerInfoPromise = instance
.invoke("singerInfoSingerInfoGet")({
speakerUuid: singer.speakerUuid,
})
.catch((error) => {
window.backend.logError(error, `Failed to get singerInfo.`);
Hiroshiba marked this conversation as resolved.
Show resolved Hide resolved
throw error;
});
singerStylePromise = singerInfoPromise.then((singerInfo) =>
getStyles(singer, singerInfo),
);
}

const baseSpeaker = speaker ?? singer;
if (baseSpeaker == undefined) {
throw new Error("assert baseSpeaker != undefined");
}
const baseCharacterInfo = await (speakerInfoPromise ??
singerInfoPromise);
if (baseCharacterInfo == undefined) {
throw new Error("assert baseSpeakerInfo != undefined");
}

const stylesPromise = Promise.all([
speakerStylePromise ?? [],
singerStylePromise ?? [],
]).then((styles) => styles.flat());

const characterInfo: CharacterInfo = {
portraitPath: base64ImageToUri(speakerInfo.portrait),
portraitPath: base64ImageToUri(baseCharacterInfo.portrait),
metas: {
speakerUuid: SpeakerId(speaker.speakerUuid),
speakerName: speaker.name,
styles,
policy: speakerInfo.policy,
speakerUuid: SpeakerId(baseSpeaker.speakerUuid),
speakerName: baseSpeaker.name,
styles: await stylesPromise,
policy: baseCharacterInfo.policy,
},
};
return characterInfo;
};
const characterInfos: CharacterInfo[] = await Promise.all(
speakers.map(async (speaker) => {
return await getSpeakerInfo(speaker);
}),

const [speakers, singers] = await Promise.all([
instance.invoke("speakersSpeakersGet")({}),
state.engineManifests[engineId].supportedFeatures.sing
? await instance.invoke("singersSingersGet")({})
: [],
]).catch((error) => {
window.backend.logError(error, `Failed to get Speakers.`);
throw error;
});

// エンジン側の順番を保ってCharacterInfoを作る
const allUuids = new Set([
...speakers.map((speaker) => speaker.speakerUuid),
...singers.map((singer) => singer.speakerUuid),
]);
Hiroshiba marked this conversation as resolved.
Show resolved Hide resolved

const characterInfoPromises = Array.from(allUuids).map(
(speakerUuid) => {
const speaker = speakers.find(
(speaker) => speaker.speakerUuid === speakerUuid,
);
const singer = singers.find(
(singer) => singer.speakerUuid === speakerUuid,
);
return getCharacterInfo(speaker, singer);
},
);

const characterInfos = await Promise.all(characterInfoPromises);

commit("SET_CHARACTER_INFOS", { engineId, characterInfos });
},
),
Expand Down
Loading