diff --git a/public/howtouse.md b/public/howtouse.md index 9ac56da6b1..f90bd232b3 100644 --- a/public/howtouse.md +++ b/public/howtouse.md @@ -322,12 +322,12 @@ VOICEVOX では、歌声合成機能がプロトタイプ版として提供さ 「音域調整」の値と中央のキーの関係はおおよそ以下の通りです。 | 音域調整の値 | 中央のキー | -| --- | --- | -| 0 | G4(ソ4) | -| -7 | C4(ド4) | -| -12 | G3(ソ3) | -| -19 | C3(ド3) | -| -24 | G2(ソ2) | +| ------------ | ---------- | +| 0 | G4(ソ4) | +| -7 | C4(ド4) | +| -12 | G3(ソ3) | +| -19 | C3(ド3) | +| -24 | G2(ソ2) | ### 声量調整 @@ -346,7 +346,7 @@ VOICEVOX では、歌声合成機能がプロトタイプ版として提供さ ### マルチトラック -「設定」→「オプション」→「実験的機能」から「ソング:マルチトラック機能」をONにすることで、複数のトラックを編集・再生できるようになります。 +画面左上のハンバーガーメニュー ☰ をクリックすることでトラック一覧を表示できます。トラック一覧の+ボタンでトラックを追加することで、複数のトラックを編集・再生できるようになります。 ### ソング機能のよくある質問 diff --git a/public/updateInfos.json b/public/updateInfos.json index 49770a50d8..2903a2bf8b 100644 --- a/public/updateInfos.json +++ b/public/updateInfos.json @@ -1,4 +1,30 @@ [ + { + "version": "0.21.0", + "descriptions": [ + "ソング:立ち絵表示の有無を切り替え可能に", + "ソング:エディタのデザインを刷新", + "ソング:マルチトラックを通常機能に", + "ソング:書き出し時の詳細設定機能", + "設定ダイアログのデザインを刷新", + "開発環境の向上", + "バグ修正" + ], + "contributors": [ + "gigi434", + "Hiroshiba", + "honey32", + "jdkfx", + "MT224244", + "naga-na", + "romot-co", + "sabonerune", + "Segu-g", + "sevenc-nanashi", + "sigprogramming", + "takusea" + ] + }, { "version": "0.20.0", "descriptions": [ diff --git a/src/backend/common/ConfigManager.ts b/src/backend/common/ConfigManager.ts index 75172c8133..408b012df1 100644 --- a/src/backend/common/ConfigManager.ts +++ b/src/backend/common/ConfigManager.ts @@ -262,6 +262,11 @@ const migrations: [string, (store: Record) => unknown][] = [ "", ); + // マルチトラック機能を実験的機能じゃなくす + if ("enableMultiTrack" in experimentalSetting) { + delete experimentalSetting.enableMultiTrack; + } + return config; }, ], diff --git a/src/components/Dialog/ExportSongAudioDialog/Presentation.vue b/src/components/Dialog/ExportSongAudioDialog/Presentation.vue index 0a049e78b9..79b2b2cc11 100644 --- a/src/components/Dialog/ExportSongAudioDialog/Presentation.vue +++ b/src/components/Dialog/ExportSongAudioDialog/Presentation.vue @@ -2,15 +2,15 @@ -
書き出し
+
音声書き出し
(); -// 書き出し対象選択 +// 書き出し方法選択 const exportTargets = [ { - label: "すべてのトラック", + label: "まとめる(ミックス)", value: "master", }, { - label: "トラックごと", + label: "トラック別", value: "stem", }, ]; diff --git a/src/components/Dialog/SettingDialog/SettingDialog.vue b/src/components/Dialog/SettingDialog/SettingDialog.vue index 054024edd4..c090c0567a 100644 --- a/src/components/Dialog/SettingDialog/SettingDialog.vue +++ b/src/components/Dialog/SettingDialog/SettingDialog.vue @@ -258,7 +258,7 @@ /> (key: T) => { - const state = computed(() => store.state[key]); - const setter = (value: RootMiscSettingType[T]) => { - // Vuexの型処理でUnionが解かれてしまうのを迂回している - // FIXME: このワークアラウンドをなくす - void store.dispatch("SET_ROOT_MISC_SETTING", { key: key as never, value }); - }; - return [state, setter] as const; -}; - const props = defineProps<{ modelValue: boolean; }>(); @@ -583,29 +573,40 @@ const availableThemeNameComputed = computed(() => { }); }); -const [editorFont, changeEditorFont] = useRootMiscSetting("editorFont"); +const [editorFont, changeEditorFont] = useRootMiscSetting(store, "editorFont"); -const [enableMultiEngine, setEnableMultiEngine] = - useRootMiscSetting("enableMultiEngine"); +const [enableMultiEngine, setEnableMultiEngine] = useRootMiscSetting( + store, + "enableMultiEngine", +); -const [showTextLineNumber, changeShowTextLineNumber] = - useRootMiscSetting("showTextLineNumber"); +const [showTextLineNumber, changeShowTextLineNumber] = useRootMiscSetting( + store, + "showTextLineNumber", +); const [showAddAudioItemButton, changeShowAddAudioItemButton] = - useRootMiscSetting("showAddAudioItemButton"); + useRootMiscSetting(store, "showAddAudioItemButton"); -const [enableMemoNotation, changeEnableMemoNotation] = - useRootMiscSetting("enableMemoNotation"); +const [enableMemoNotation, changeEnableMemoNotation] = useRootMiscSetting( + store, + "enableMemoNotation", +); -const [enableRubyNotation, changeEnableRubyNotation] = - useRootMiscSetting("enableRubyNotation"); +const [enableRubyNotation, changeEnableRubyNotation] = useRootMiscSetting( + store, + "enableRubyNotation", +); -const [enablePreset, _changeEnablePreset] = useRootMiscSetting("enablePreset"); +const [enablePreset, _changeEnablePreset] = useRootMiscSetting( + store, + "enablePreset", +); const [ shouldApplyDefaultPresetOnVoiceChanged, changeShouldApplyDefaultPresetOnVoiceChanged, -] = useRootMiscSetting("shouldApplyDefaultPresetOnVoiceChanged"); +] = useRootMiscSetting(store, "shouldApplyDefaultPresetOnVoiceChanged"); const canSetAudioOutputDevice = computed(() => { return !!HTMLAudioElement.prototype.setSinkId; @@ -817,8 +818,10 @@ watchEffect(async () => { } }); -const [splitTextWhenPaste, changeSplitTextWhenPaste] = - useRootMiscSetting("splitTextWhenPaste"); +const [splitTextWhenPaste, changeSplitTextWhenPaste] = useRootMiscSetting( + store, + "splitTextWhenPaste", +); const showAudioFilePatternEditDialog = ref(false); const showSongTrackAudioFilePatternEditDialog = ref(false); diff --git a/src/components/Sing/CharacterPortrait.vue b/src/components/Sing/CharacterPortrait.vue index 9d41309911..9456d1f539 100644 --- a/src/components/Sing/CharacterPortrait.vue +++ b/src/components/Sing/CharacterPortrait.vue @@ -1,5 +1,5 @@ @@ -9,7 +9,9 @@ import { computed } from "vue"; import { useStore } from "@/store"; const store = useStore(); -const showSinger = computed(() => store.state.showSinger); +const showSingCharacterPortrait = computed( + () => store.state.showSingCharacterPortrait, +); const portraitPath = computed(() => { const userOrderedCharacterInfos = diff --git a/src/components/Sing/menuBarData.ts b/src/components/Sing/menuBarData.ts index 6823c3e053..fc06ba9a78 100644 --- a/src/components/Sing/menuBarData.ts +++ b/src/components/Sing/menuBarData.ts @@ -1,6 +1,7 @@ import { computed } from "vue"; import { useStore } from "@/store"; import { MenuItemData } from "@/components/Menu/type"; +import { useRootMiscSetting } from "@/composables/useRootMiscSetting"; export const useMenuBarData = () => { const store = useStore(); @@ -8,15 +9,6 @@ export const useMenuBarData = () => { const isNotesSelected = computed( () => store.getters.SELECTED_NOTE_IDS.size > 0, ); - const showSinger = computed({ - get: () => store.state.showSinger, - set: (showSinger: boolean) => { - void store.dispatch("SET_ROOT_MISC_SETTING", { - key: "showSinger", - value: showSinger, - }); - }, - }); const importExternalSongProject = async () => { if (uiLocked.value) return; @@ -32,6 +24,7 @@ export const useMenuBarData = () => { }); }; + // 「ファイル」メニュー const fileSubMenuData = computed(() => [ { type: "button", @@ -52,6 +45,7 @@ export const useMenuBarData = () => { }, ]); + // 「編集」メニュー const editSubMenuData = computed(() => [ { type: "separator" }, { @@ -116,12 +110,17 @@ export const useMenuBarData = () => { }, ]); + // 「表示」メニュー + const [showSingCharacterPortrait, setShowSingCharacterPortrait] = + useRootMiscSetting(store, "showSingCharacterPortrait"); const viewSubMenuData = computed(() => [ { type: "button", - label: showSinger.value ? "立ち絵を非表示" : "立ち絵を表示", + label: showSingCharacterPortrait.value + ? "立ち絵を非表示" + : "立ち絵を表示", onClick: () => { - showSinger.value = !showSinger.value; + setShowSingCharacterPortrait(!showSingCharacterPortrait.value); }, disableWhenUiLocked: true, }, diff --git a/src/components/Talk/menuBarData.ts b/src/components/Talk/menuBarData.ts index c0bd892dad..5a9b73c2ea 100644 --- a/src/components/Talk/menuBarData.ts +++ b/src/components/Talk/menuBarData.ts @@ -2,6 +2,7 @@ import { computed } from "vue"; import { MenuItemData } from "@/components/Menu/type"; import { useStore } from "@/store"; +import { useRootMiscSetting } from "@/composables/useRootMiscSetting"; export const useMenuBarData = () => { const store = useStore(); @@ -55,7 +56,20 @@ export const useMenuBarData = () => { const editSubMenuData = computed(() => []); // 「表示」メニュー - const viewSubMenuData = computed(() => []); + const [showTextLineNumber, changeShowTextLineNumber] = useRootMiscSetting( + store, + "showTextLineNumber", + ); + const viewSubMenuData = computed(() => [ + { + type: "button", + label: showTextLineNumber.value ? "行番号を非表示" : "行番号を表示", + onClick: () => { + changeShowTextLineNumber(!showTextLineNumber.value); + }, + disableWhenUiLocked: true, + }, + ]); return { fileSubMenuData, diff --git a/src/composables/useRootMiscSetting.ts b/src/composables/useRootMiscSetting.ts new file mode 100644 index 0000000000..b87ff0eafd --- /dev/null +++ b/src/composables/useRootMiscSetting.ts @@ -0,0 +1,20 @@ +import { computed } from "vue"; +import { Store } from "@/store"; +import { RootMiscSettingType } from "@/type/preload"; + +/** ルート直下にある雑多な設定値を簡単に扱える便利コンポーザブル */ +export const useRootMiscSetting = ( + store: Store, + key: T, +) => { + const state = computed(() => store.state[key]); + const setter = (value: RootMiscSettingType[T]) => { + // Vuexの型処理でUnionが解かれてしまうのを迂回している + // FIXME: このワークアラウンドをなくす + void store.dispatch("SET_ROOT_MISC_SETTING", { + key: key as never, + value, + }); + }; + return [state, setter] as const; +}; diff --git a/src/store/index.ts b/src/store/index.ts index 239ee78f88..16d9f14834 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -1,5 +1,9 @@ import { InjectionKey } from "vue"; -import { createStore, Store, useStore as baseUseStore } from "./vuex"; +import { + createStore, + Store as BaseStore, + useStore as baseUseStore, +} from "./vuex"; import { AllActions, @@ -42,9 +46,8 @@ import { isProduction, } from "@/type/preload"; -export const storeKey: InjectionKey< - Store -> = Symbol(); +export type Store = BaseStore; +export const storeKey: InjectionKey = Symbol(); export const indexStoreState: IndexStoreState = { defaultStyleIds: [], @@ -412,11 +415,6 @@ export const store = createStore({ strict: !isProduction, }); -export const useStore = (): Store< - State, - AllGetters, - AllActions, - AllMutations -> => { +export const useStore = (): Store => { return baseUseStore(storeKey); }; diff --git a/src/store/setting.ts b/src/store/setting.ts index a3611e0397..69ee25c03b 100644 --- a/src/store/setting.ts +++ b/src/store/setting.ts @@ -64,7 +64,7 @@ export const settingStoreState: SettingStoreState = { soloAndMute: true, panAndGain: true, }, - showSinger: true, + showSingCharacterPortrait: true, }; export const settingStore = createPartialStore({ @@ -140,7 +140,7 @@ export const settingStore = createPartialStore({ "enableMemoNotation", "skipUpdateVersion", "undoableTrackOperations", - "showSinger", + "showSingCharacterPortrait", ] as const; // rootMiscSettingKeysに値を足し忘れていたときに型エラーを出す検出用コード diff --git a/src/type/preload.ts b/src/type/preload.ts index 77e8ab748d..8dc1d7cfad 100644 --- a/src/type/preload.ts +++ b/src/type/preload.ts @@ -599,7 +599,7 @@ export const rootMiscSettingSchema = z.object({ panAndGain: z.boolean().default(true), }) .default({}), - showSinger: z.boolean().default(true), + showSingCharacterPortrait: z.boolean().default(true), // ソングエディタで立ち絵を表示するか }); export type RootMiscSettingType = z.infer; diff --git "a/tests/e2e/browser/\350\250\255\345\256\232\343\203\200\343\202\244\343\202\242\343\203\255\343\202\260/\346\233\270\343\201\215\345\207\272\343\201\227\343\203\225\343\202\241\343\202\244\343\203\253\345\220\215\343\203\221\343\202\277\343\203\274\343\203\263.spec.ts" "b/tests/e2e/browser/\350\250\255\345\256\232\343\203\200\343\202\244\343\202\242\343\203\255\343\202\260/\346\233\270\343\201\215\345\207\272\343\201\227\343\203\225\343\202\241\343\202\244\343\203\253\345\220\215\343\203\221\343\202\277\343\203\274\343\203\263.spec.ts" index e9dc0a36b3..0650df41e9 100644 --- "a/tests/e2e/browser/\350\250\255\345\256\232\343\203\200\343\202\244\343\202\242\343\203\255\343\202\260/\346\233\270\343\201\215\345\207\272\343\201\227\343\203\225\343\202\241\343\202\244\343\203\253\345\220\215\343\203\221\343\202\277\343\203\274\343\203\263.spec.ts" +++ "b/tests/e2e/browser/\350\250\255\345\256\232\343\203\200\343\202\244\343\202\242\343\203\255\343\202\260/\346\233\270\343\201\215\345\207\272\343\201\227\343\203\225\343\202\241\343\202\244\343\203\253\345\220\215\343\203\221\343\202\277\343\203\274\343\203\263.spec.ts" @@ -10,7 +10,7 @@ test.beforeEach(gotoHome); */ const moveToFilenameDialog = async (page: Page, settingDialog: Locator) => { await settingDialog - .locator(".row-card", { hasText: "書き出しファイル名パターン" }) + .locator(".row-card", { hasText: "トーク:書き出しファイル名パターン" }) .getByRole("button", { name: "編集する" }) .click(); await page.waitForTimeout(500); diff --git "a/tests/e2e/browser/\350\250\255\345\256\232\343\203\200\343\202\244\343\202\242\343\203\255\343\202\260/\350\250\255\345\256\232\343\203\200\343\202\244\343\202\242\343\203\255\343\202\260.spec.ts-snapshots/\343\202\271\343\202\257\343\203\252\343\203\274\343\203\263\343\202\267\343\203\247\343\203\203\343\203\210-1-browser-win32.png" "b/tests/e2e/browser/\350\250\255\345\256\232\343\203\200\343\202\244\343\202\242\343\203\255\343\202\260/\350\250\255\345\256\232\343\203\200\343\202\244\343\202\242\343\203\255\343\202\260.spec.ts-snapshots/\343\202\271\343\202\257\343\203\252\343\203\274\343\203\263\343\202\267\343\203\247\343\203\203\343\203\210-1-browser-win32.png" index eb34b04607..fb17f84399 100644 Binary files "a/tests/e2e/browser/\350\250\255\345\256\232\343\203\200\343\202\244\343\202\242\343\203\255\343\202\260/\350\250\255\345\256\232\343\203\200\343\202\244\343\202\242\343\203\255\343\202\260.spec.ts-snapshots/\343\202\271\343\202\257\343\203\252\343\203\274\343\203\263\343\202\267\343\203\247\343\203\203\343\203\210-1-browser-win32.png" and "b/tests/e2e/browser/\350\250\255\345\256\232\343\203\200\343\202\244\343\202\242\343\203\255\343\202\260/\350\250\255\345\256\232\343\203\200\343\202\244\343\202\242\343\203\255\343\202\260.spec.ts-snapshots/\343\202\271\343\202\257\343\203\252\343\203\274\343\203\263\343\202\267\343\203\247\343\203\203\343\203\210-1-browser-win32.png" differ diff --git "a/tests/e2e/browser/\350\250\255\345\256\232\343\203\200\343\202\244\343\202\242\343\203\255\343\202\260/\350\250\255\345\256\232\343\203\200\343\202\244\343\202\242\343\203\255\343\202\260.spec.ts-snapshots/\343\202\271\343\202\257\343\203\252\343\203\274\343\203\263\343\202\267\343\203\247\343\203\203\343\203\210-2-browser-win32.png" "b/tests/e2e/browser/\350\250\255\345\256\232\343\203\200\343\202\244\343\202\242\343\203\255\343\202\260/\350\250\255\345\256\232\343\203\200\343\202\244\343\202\242\343\203\255\343\202\260.spec.ts-snapshots/\343\202\271\343\202\257\343\203\252\343\203\274\343\203\263\343\202\267\343\203\247\343\203\203\343\203\210-2-browser-win32.png" index f26e603a8a..65dc00209a 100644 Binary files "a/tests/e2e/browser/\350\250\255\345\256\232\343\203\200\343\202\244\343\202\242\343\203\255\343\202\260/\350\250\255\345\256\232\343\203\200\343\202\244\343\202\242\343\203\255\343\202\260.spec.ts-snapshots/\343\202\271\343\202\257\343\203\252\343\203\274\343\203\263\343\202\267\343\203\247\343\203\203\343\203\210-2-browser-win32.png" and "b/tests/e2e/browser/\350\250\255\345\256\232\343\203\200\343\202\244\343\202\242\343\203\255\343\202\260/\350\250\255\345\256\232\343\203\200\343\202\244\343\202\242\343\203\255\343\202\260.spec.ts-snapshots/\343\202\271\343\202\257\343\203\252\343\203\274\343\203\263\343\202\267\343\203\247\343\203\203\343\203\210-2-browser-win32.png" differ