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

デフォルトプリセット周りのリファクタ #1274

Merged
merged 17 commits into from
Apr 8, 2023
Merged
Show file tree
Hide file tree
Changes from 16 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
5 changes: 1 addition & 4 deletions src/composables/useDefaultPreset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,14 @@ export const useDefaultPreset = () => {
const store = useStore();

const defaultPresetKeys = computed(() => store.state.defaultPresetKeys);
const defaultPresetKeySets = computed(
() => new Set(Object.values(store.state.defaultPresetKeys))
);

const getDefaultPresetKeyForVoice = (voice: Voice): string => {
const voiceId = VoiceId(voice);
return defaultPresetKeys.value[voiceId];
};

const isDefaultPresetKey = (presetKey: PresetKey): boolean => {
return defaultPresetKeySets.value.has(presetKey);
return store.getters.DEFAULT_PRESET_KEY_SETS.has(presetKey);
};

return {
Expand Down
168 changes: 56 additions & 112 deletions src/store/audio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
} from "./utility";
import { convertAudioQueryFromEditorToEngine } from "./proxy";
import { createPartialStore } from "./vuex";
import { determineNextPresetKey } from "./preset";
import {
AudioKey,
CharacterInfo,
Expand All @@ -31,12 +32,12 @@ import {
EngineId,
MoraDataType,
MorphingInfo,
Preset,
PresetKey,
SpeakerId,
StyleId,
StyleInfo,
Voice,
VoiceId,
WriteFileErrorResult,
} from "@/type/preload";
import { AudioQuery, AccentPhrase, Speaker, SpeakerInfo } from "@/openapi";
Expand Down Expand Up @@ -188,69 +189,30 @@ export function getCharacterInfo(
}

/**
* configを参照して割り当てるべきpresetKeyとそのPresetを適用すべきかどうかを返す
* 与えたAudioItemを元に、Presetを適用した新しいAudioItemを返す
*/
export function determineNextPresetKey(
state: State,
voice: Voice,
presetKeyCandidate: PresetKey | undefined,
shouldCopyBaseAudioItem: boolean,
isVoiceChanged = false
): {
nextPresetKey: PresetKey | undefined;
shouldApplyPreset: boolean;
} {
const defaultPresetKeyForCurrentVoice =
state.defaultPresetKeys[VoiceId(voice)];

const isDefaultPreset = Object.values(state.defaultPresetKeys).some(
(key) => key === presetKeyCandidate
);

// コピーすべきBaseAudioItemがない=初回作成時
if (!shouldCopyBaseAudioItem) {
return {
nextPresetKey: defaultPresetKeyForCurrentVoice,
shouldApplyPreset: state.experimentalSetting.enablePreset,
};
export function applyAudioPresetToAudioItem(
audioItem: AudioItem,
presetItem: Preset
): AudioItem {
if (audioItem.query == undefined) {
throw new Error("audioItem.query is undefined");
}

// ボイス切り替え時
if (isVoiceChanged) {
if (state.experimentalSetting.shouldApplyDefaultPresetOnVoiceChanged) {
// デフォルトプリセットを適用する
return {
nextPresetKey: defaultPresetKeyForCurrentVoice,
shouldApplyPreset: true,
};
}

// 引き継ぎ元が他スタイルのデフォルトプリセットだった場合
// 別キャラのデフォルトプリセットを引き継がないようにする
// それ以外は指定そのまま
return {
nextPresetKey: isDefaultPreset
? defaultPresetKeyForCurrentVoice
: presetKeyCandidate,
shouldApplyPreset: false,
};
}
// Filter name property from presetItem in order to extract audioInfos.
const { name: _, morphingInfo, ...presetAudioInfos } = presetItem;

// 以下はAudioItemコピー時
// Type Assertion
const audioInfos: Omit<
AudioQuery,
"accentPhrases" | "outputSamplingRate" | "outputStereo" | "kana"
> = presetAudioInfos;

if (state.inheritAudioInfo) {
// パラメータ引継ぎがONならそのまま引き継ぐ
return {
nextPresetKey: presetKeyCandidate,
shouldApplyPreset: false,
};
}
const newAudioItem = { ...audioItem };
newAudioItem.query = { ...audioItem.query, ...audioInfos };
newAudioItem.morphingInfo = morphingInfo ? { ...morphingInfo } : undefined;

// それ以外はデフォルトプリセットを割り当て、適用するかはプリセットのON/OFFに依存
return {
nextPresetKey: defaultPresetKeyForCurrentVoice,
shouldApplyPreset: state.experimentalSetting.enablePreset,
};
return newAudioItem;
}

const audioBlobCache: Record<string, Blob> = {};
Expand Down Expand Up @@ -603,9 +565,9 @@ export const audioStore = createPartialStore<AudioStoreTypes>({
}).catch(() => undefined)
: undefined;

const audioItem: AudioItem = { text, voice };
const newAudioItem: AudioItem = { text, voice };
if (query != undefined) {
audioItem.query = query;
newAudioItem.query = query;
}

const presetKeyCandidate = payload.baseAudioItem?.presetKey;
Expand All @@ -614,37 +576,45 @@ export const audioStore = createPartialStore<AudioStoreTypes>({
state,
voice,
presetKeyCandidate,
state.inheritAudioInfo && baseAudioItem !== undefined
baseAudioItem ? "copy" : "generate"
);
audioItem.presetKey = nextPresetKey;
newAudioItem.presetKey = nextPresetKey;

// audioItemに対してプリセットを適用する
if (shouldApplyPreset) {
if (nextPresetKey) {
const preset = state.presetItems[nextPresetKey];
return applyAudioPresetToAudioItem(newAudioItem, preset);
}
}

// プリセットを適用しないならパラメータを引き継ぐ
if (
state.inheritAudioInfo &&
baseAudioItem &&
baseAudioItem.query &&
audioItem.query
newAudioItem.query
) {
//引数にbaseAudioItemがある場合、話速等のパラメータを引き継いだAudioItemを返す
//baseAudioItem.queryが未設定の場合は引き継がない(起動直後等?)
audioItem.query.speedScale = baseAudioItem.query.speedScale;
audioItem.query.pitchScale = baseAudioItem.query.pitchScale;
audioItem.query.intonationScale = baseAudioItem.query.intonationScale;
audioItem.query.volumeScale = baseAudioItem.query.volumeScale;
audioItem.query.prePhonemeLength = baseAudioItem.query.prePhonemeLength;
audioItem.query.postPhonemeLength =
newAudioItem.query.speedScale = baseAudioItem.query.speedScale;
newAudioItem.query.pitchScale = baseAudioItem.query.pitchScale;
newAudioItem.query.intonationScale =
baseAudioItem.query.intonationScale;
newAudioItem.query.volumeScale = baseAudioItem.query.volumeScale;
newAudioItem.query.prePhonemeLength =
baseAudioItem.query.prePhonemeLength;
newAudioItem.query.postPhonemeLength =
baseAudioItem.query.postPhonemeLength;
audioItem.query.outputSamplingRate =
newAudioItem.query.outputSamplingRate =
baseAudioItem.query.outputSamplingRate;
audioItem.query.outputStereo = baseAudioItem.query.outputStereo;
audioItem.morphingInfo = baseAudioItem.morphingInfo;
}

// audioItemに対してプリセットを適用する
if (shouldApplyPreset) {
await dispatch("APPLY_AUDIO_PRESET_TO_AUDIO_ITEM", { audioItem });
newAudioItem.query.outputStereo = baseAudioItem.query.outputStereo;
newAudioItem.morphingInfo = baseAudioItem.morphingInfo
? { ...baseAudioItem.morphingInfo }
: undefined;
}

return audioItem;
return newAudioItem;
},
},

Expand Down Expand Up @@ -1045,41 +1015,16 @@ export const audioStore = createPartialStore<AudioStoreTypes>({
},
},

APPLY_AUDIO_PRESET_TO_AUDIO_ITEM: {
// FIXME: audioItemを直接書き換えないようにするか、関数化する
mutation(state, { audioItem }) {
if (
audioItem == undefined ||
audioItem.presetKey == undefined ||
audioItem.query == undefined
)
return;
const presetItem = state.presetItems[audioItem.presetKey];
if (presetItem == undefined) return;

// Filter name property from presetItem in order to extract audioInfos.
const { name: _, morphingInfo, ...presetAudioInfos } = presetItem;

// Type Assertion
const audioInfos: Omit<
AudioQuery,
"accentPhrases" | "outputSamplingRate" | "outputStereo" | "kana"
> = presetAudioInfos;
APPLY_AUDIO_PRESET: {
mutation(state, { audioKey }: { audioKey: AudioKey }) {
const audioItem = state.audioItems[audioKey];

audioItem.query = { ...audioItem.query, ...audioInfos };
if (!audioItem || !audioItem.presetKey) return;
k-chop marked this conversation as resolved.
Show resolved Hide resolved

audioItem.morphingInfo = morphingInfo;
},
action({ commit }, { audioItem }) {
commit("APPLY_AUDIO_PRESET_TO_AUDIO_ITEM", { audioItem });
},
},
const presetItem = state.presetItems[audioItem.presetKey];
const newAudioItem = applyAudioPresetToAudioItem(audioItem, presetItem);

APPLY_AUDIO_PRESET: {
mutation(state, { audioKey }: { audioKey: AudioKey }) {
audioStore.mutations.APPLY_AUDIO_PRESET_TO_AUDIO_ITEM(state, {
audioItem: state.audioItems[audioKey],
});
state.audioItems[audioKey] = newAudioItem;
},
},

Expand Down Expand Up @@ -2120,8 +2065,7 @@ export const audioCommandStore = transformCommandStore(
draft,
payload.voice,
presetKey,
true,
true
"changeVoice"
);

audioStore.mutations.SET_AUDIO_PRESET_KEY(draft, {
Expand Down
83 changes: 81 additions & 2 deletions src/store/preset.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,80 @@
import { v4 as uuidv4 } from "uuid";
import { createPartialStore } from "./vuex";
import { PresetStoreState, PresetStoreTypes } from "@/store/type";
import { Preset, PresetKey, VoiceId } from "@/type/preload";
import { PresetStoreState, PresetStoreTypes, State } from "@/store/type";
import { Preset, PresetKey, Voice, VoiceId } from "@/type/preload";

/**
* configを参照して割り当てるべきpresetKeyとそのPresetを適用すべきかどうかを返す
*
* generate: プロジェクト新規作成時、空のAudioItemを作成する場合
* copy: 元となるAudioItemがある場合(+ボタンで作成したとき)
* changeVoice: ボイス切り替え時
*/
export function determineNextPresetKey(
state: Pick<
State,
"defaultPresetKeys" | "experimentalSetting" | "inheritAudioInfo"
>,
voice: Voice,
presetKeyCandidate: PresetKey | undefined,
operation: "generate" | "copy" | "changeVoice"
): {
nextPresetKey: PresetKey | undefined;
shouldApplyPreset: boolean;
} {
const defaultPresetKeyForCurrentVoice =
state.defaultPresetKeys[VoiceId(voice)];

switch (operation) {
case "generate": {
// 初回作成時
return {
nextPresetKey: defaultPresetKeyForCurrentVoice,
shouldApplyPreset: state.experimentalSetting.enablePreset,
};
}
case "copy": {
// 元となるAudioItemがある場合
if (state.inheritAudioInfo) {
// パラメータ引継ぎがONならそのまま引き継ぐ
return {
nextPresetKey: presetKeyCandidate,
shouldApplyPreset: false,
};
}

// それ以外はデフォルトプリセットを割り当て、適用するかはプリセットのON/OFFに依存
return {
nextPresetKey: defaultPresetKeyForCurrentVoice,
shouldApplyPreset: state.experimentalSetting.enablePreset,
};
}
case "changeVoice": {
// ボイス切り替え時
if (state.experimentalSetting.shouldApplyDefaultPresetOnVoiceChanged) {
// デフォルトプリセットを適用する
return {
nextPresetKey: defaultPresetKeyForCurrentVoice,
shouldApplyPreset: true,
};
}

const isDefaultPreset = Object.values(state.defaultPresetKeys).some(
(key) => key === presetKeyCandidate
);
Hiroshiba marked this conversation as resolved.
Show resolved Hide resolved

// 引き継ぎ元が他スタイルのデフォルトプリセットだった場合
// 別キャラのデフォルトプリセットを引き継がないようにする
// それ以外は指定そのまま
return {
nextPresetKey: isDefaultPreset
? defaultPresetKeyForCurrentVoice
: presetKeyCandidate,
shouldApplyPreset: false,
};
}
}
}

export const presetStoreState: PresetStoreState = {
presetItems: {},
Expand All @@ -10,6 +83,12 @@ export const presetStoreState: PresetStoreState = {
};

export const presetStore = createPartialStore<PresetStoreTypes>({
DEFAULT_PRESET_KEY_SETS: {
getter: (state) => {
return new Set(Object.values(state.defaultPresetKeys));
},
},

SET_PRESET_ITEMS: {
mutation(
state,
Expand Down
8 changes: 3 additions & 5 deletions src/store/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -359,11 +359,6 @@ export type AudioStoreTypes = {
};
};

APPLY_AUDIO_PRESET_TO_AUDIO_ITEM: {
mutation: { audioItem: AudioItem };
action(payload: { audioItem: AudioItem }): void;
};

APPLY_AUDIO_PRESET: {
mutation: { audioKey: AudioKey };
};
Expand Down Expand Up @@ -1263,6 +1258,9 @@ export type PresetStoreState = {
};

export type PresetStoreTypes = {
DEFAULT_PRESET_KEY_SETS: {
getter: Set<PresetKey>;
};
SET_PRESET_ITEMS: {
mutation: {
presetItems: Record<PresetKey, Preset>;
Expand Down