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

マルチトラック:最終調整 #2176

Merged
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
abdd921
Change: shouldPlayTracksがSetを返すようにする
sevenc-nanashi Jul 23, 2024
009b89a
Change: 実験的機能に隔離
sevenc-nanashi Jul 23, 2024
e59454e
Change: 条件を修正
sevenc-nanashi Jul 23, 2024
5dc4c01
Code: コメントを追加
sevenc-nanashi Jul 23, 2024
c71d9c8
Add: TODOを追加
sevenc-nanashi Jul 23, 2024
47c9c28
(スナップショットを更新)
github-actions[bot] Jul 23, 2024
4ab7c67
Change: トグルの変数を変える
sevenc-nanashi Jul 24, 2024
3af1168
Change: 抜け穴をふさぐ
sevenc-nanashi Jul 24, 2024
fd9e256
Delete: セーフガードをなくす
sevenc-nanashi Jul 24, 2024
8da3ae5
Change: solo/muteの代入方法を変える
sevenc-nanashi Jul 24, 2024
a3ee7fc
Change: CLEAR_UNDO_HISTORYにする
sevenc-nanashi Jul 24, 2024
a8db0ca
Change: disable周りを揃える
sevenc-nanashi Jul 24, 2024
a31cabe
Change: number | nullにする
sevenc-nanashi Jul 24, 2024
9dc0d9d
Change: findIndicesを消す
sevenc-nanashi Jul 24, 2024
f801a18
Change: テキストをほんのり変える
sevenc-nanashi Jul 24, 2024
0d9e6eb
Fix: overlappingNoteIdsをコピーする
sevenc-nanashi Jul 24, 2024
0792525
Change: RENDERでChannelStripを更新するようにする
sevenc-nanashi Jul 25, 2024
2efc9c3
Code: RENDERの前に空行を開ける
sevenc-nanashi Jul 25, 2024
cf66bc3
Merge: main -> multitrack/final-adjustment
sevenc-nanashi Jul 25, 2024
93e5a4f
Fix: 合成状態の順序を修正
sevenc-nanashi Jul 26, 2024
4b9806f
Fix: ピッチが見えなかったのを修正
sevenc-nanashi Jul 26, 2024
c24d5d7
Change: toSortedをかける
sevenc-nanashi Jul 26, 2024
73c3411
Change: SET_TRACKまわりを変える
sevenc-nanashi Jul 27, 2024
15409f9
Fix: ソートするものが間違ってた
sevenc-nanashi Jul 27, 2024
32dd8fb
Delete: watch周りのやつを削除
sevenc-nanashi Jul 27, 2024
4c27d3e
Change: 変数名を変える
sevenc-nanashi Jul 27, 2024
42710c6
Delete: 使われてない型を削除
sevenc-nanashi Jul 27, 2024
40741d9
Code: 注意を追加
sevenc-nanashi Jul 27, 2024
619c045
Code: コメントを変える
sevenc-nanashi Jul 28, 2024
6aca4bd
Code: コメントをいい感じにする
sevenc-nanashi Jul 28, 2024
2fff4d5
Change: SELECT_ALL_NOTES_IN_SELECTED_TRACK -> SELECT_ALL_NOTES_IN_TRACK
sevenc-nanashi Jul 28, 2024
65525fc
Fix: 挙動を揃える
sevenc-nanashi Jul 28, 2024
6645f5c
Fix: ガバ
sevenc-nanashi Jul 28, 2024
80d9ab7
Fix: Render忘れ
sevenc-nanashi Jul 29, 2024
a3db2c2
Apply suggestions from code review
Hiroshiba Jul 29, 2024
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
28 changes: 28 additions & 0 deletions src/components/Dialog/ImportSongProjectDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,17 @@
>
<QItemSection avatar>
<QCheckbox
v-if="multiTrackEnabled"
v-model="selectedTrackIndexes"
:val="track.value"
:disable="track.disable"
/>
<QRadio
v-else
v-model="selectedTrackIndex"
:val="track.value"
:disable="track.disable"
/>
</QItemSection>
<QItemSection>
<QItemLabel>
Expand Down Expand Up @@ -110,6 +117,10 @@ const { dialogRef, onDialogOK, onDialogCancel } = useDialogPluginComponent();
const store = useStore();
const log = createLogger("ImportExternalProjectDialog");

const multiTrackEnabled = computed(
() => store.state.experimentalSetting.enableMultiTrack,
);

// 受け入れる拡張子
const acceptExtensions = computed(
() => supportedExtensions.map((ext) => `.${ext}`).join(",") + ",.vvproj",
Expand Down Expand Up @@ -232,6 +243,23 @@ const trackOptions = computed(() => {
});
// 選択中のトラック
const selectedTrackIndexes = ref<number[] | null>(null);
const selectedTrackIndex = computed<number | null>({
get: () => {
if (selectedTrackIndexes.value == null) {
return null;
}
if (selectedTrackIndexes.value.length === 0) {
return null;
}
return selectedTrackIndexes.value[0];
},
set: (index: number | null) => {
if (index == null) {
throw new Error("assert: index != null");
}
selectedTrackIndexes.value = [index];
},
});

// データ初期化
const initializeValues = () => {
Expand Down
29 changes: 29 additions & 0 deletions src/components/Dialog/SettingDialog/SettingDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@
</QBtn>
</QCardActions>
<BaseCell
v-if="experimentalSetting.enableMultiTrack"
title="ソング:元に戻す対象のトラックの設定"
description="トラックの設定のうち、「元に戻す」機能の対象にする設定を指定します。"
>
Expand Down Expand Up @@ -524,6 +525,17 @@
)
"
/>
<ToggleCell
title="ソング:マルチトラック機能"
description="ONの場合、一つのプロジェクト内に複数のトラックを作成できるようになります。"
Hiroshiba marked this conversation as resolved.
Show resolved Hide resolved
:modelValue="experimentalSetting.enableMultiTrack"
:disable="!canToggleMultiTrack"
@update:modelValue="setMultiTrack($event)"
>
<QTooltip v-if="!canToggleMultiTrack" :delay="500">
現在のプロジェクトに複数のトラックが存在するため、無効化できません。
</QTooltip>
</ToggleCell>
</QCard>
<QCard flat class="setting-card">
<QCardActions>
Expand Down Expand Up @@ -896,6 +908,23 @@ const selectedEngineId = computed({
const renderEngineNameLabel = (engineId: EngineId) => {
return engineInfos.value[engineId].name;
};

// トラックが複数あるときはマルチトラック機能を無効化できないようにする
sevenc-nanashi marked this conversation as resolved.
Show resolved Hide resolved
const canToggleMultiTrack = computed(() => {
if (!experimentalSetting.value.enableMultiTrack) {
return true;
}

return store.state.tracks.size <= 1;
});

const setMultiTrack = (enableMultiTrack: boolean) => {
changeExperimentalSetting("enableMultiTrack", enableMultiTrack);
// 無効化するときはUndo/Redoをクリアする
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

こーーーーーーーーれってなんででしたっけ。。。
一応ここのコメントにメモだけ残しておきたく。。

if (!enableMultiTrack) {
store.dispatch("CLEAR_UNDO_HISTORY");
}
};
</script>

<style scoped lang="scss">
Expand Down
7 changes: 6 additions & 1 deletion src/components/Dialog/SettingDialog/ToggleCell.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

<template>
<BaseCell :title :description>
<QToggle :modelValue @update:modelValue="props['onUpdate:modelValue']">
<QToggle
:modelValue
:disable
@update:modelValue="props['onUpdate:modelValue']"
>
<slot />
</QToggle>
</BaseCell>
Expand All @@ -16,6 +20,7 @@ const props = defineProps<
modelValue: boolean;
// eslint-disable-next-line vue/prop-name-casing
"onUpdate:modelValue"?: (value: boolean) => void;
disable?: boolean;
}
>();
</script>
28 changes: 24 additions & 4 deletions src/components/Sing/ScoreSequencer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,21 @@
}"
></div>
<SequencerPhraseIndicator
v-for="phraseInfo in phraseInfos"
v-for="phraseInfo in phraseInfosInOtherTracks"
:key="phraseInfo.key"
:phraseKey="phraseInfo.key"
:isInSelectedTrack="phraseInfo.trackId === selectedTrackId"
:isInSelectedTrack="false"
class="sequencer-phrase-indicator"
:style="{
width: `${phraseInfo.width}px`,
transform: `translateX(${phraseInfo.x - scrollX}px)`,
}"
/>
<SequencerPhraseIndicator
v-for="phraseInfo in phraseInfosInSelectedTrack"
:key="phraseInfo.key"
:phraseKey="phraseInfo.key"
isInSelectedTrack
Comment on lines 104 to +119
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

これ2つに分けた理由って何でしたっけ。
phraseInfosInOtherTracksphraseInfosInSelectedTrackをtemplateの中でくっつけた後
:isInSelectedTrack="phraseInfo.trackId === selectedTrackId"で判定させる手もありそう。

なんか色々あった結果そういうこともできるようになったんでしたっけ。
それとも意図あってこうなったんでしたっけ。

class="sequencer-phrase-indicator"
:style="{
width: `${phraseInfo.width}px`,
Expand Down Expand Up @@ -204,7 +215,6 @@ import {
import { applyGaussianFilter, linearInterpolation } from "@/sing/utility";
import { useLyricInput } from "@/composables/useLyricInput";
import { ExhaustiveError } from "@/type/utility";
import { getOrThrow } from "@/helpers/mapHelper";

type PreviewMode =
| "ADD_NOTE"
Expand Down Expand Up @@ -236,7 +246,7 @@ const notesInOtherTracks = computed(() =>
),
);
const overlappingNoteIdsInSelectedTrack = computed(() =>
getOrThrow(store.state.overlappingNoteIds, selectedTrackId.value),
store.getters.OVERLAPPING_NOTE_IDS(selectedTrackId.value),
);
const selectedNotes = computed(() =>
store.getters.SELECTED_TRACK.notes.filter((note) =>
Expand Down Expand Up @@ -336,6 +346,16 @@ const phraseInfos = computed(() => {
return { key, x: startX, width: endX - startX, trackId };
});
});
const phraseInfosInSelectedTrack = computed(() => {
return phraseInfos.value.filter(
(info) => info.trackId === selectedTrackId.value,
);
});
const phraseInfosInOtherTracks = computed(() => {
return phraseInfos.value.filter(
(info) => info.trackId !== selectedTrackId.value,
);
});

const ctrlKey = useCommandOrControlKey();
const editTarget = computed(() => state.sequencerEditTarget);
Expand Down
2 changes: 1 addition & 1 deletion src/components/Sing/SequencerPitch.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const pitchEditData = computed(() => {
return store.getters.SELECTED_TRACK.pitchEditData;
});
const previewPitchEdit = computed(() => props.previewPitchEdit);
const selectedTrackId = computed(() => store.state.selectedTrackId);
const selectedTrackId = computed(() => store.getters.SELECTED_TRACK_ID);
const editFrameRate = computed(() => store.state.editFrameRate);
const singingGuidesInSelectedTrack = computed(() => {
const singingGuides = [];
Expand Down
3 changes: 1 addition & 2 deletions src/components/Sing/SideBar/TrackItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,6 @@ import { useStore } from "@/store";
import ContextMenu from "@/components/Menu/ContextMenu.vue";
import { shouldPlayTracks } from "@/sing/domain";
import { CharacterInfo, StyleInfo, TrackId } from "@/type/preload";
import { getOrThrow } from "@/helpers/mapHelper";

const props = defineProps<{
trackId: TrackId;
Expand All @@ -179,7 +178,7 @@ const isThereSoloTrack = computed(() =>
[...tracks.value.values()].some((track) => track.solo),
);
const shouldPlayTrack = computed(() =>
getOrThrow(shouldPlayTracks(store.state.tracks), props.trackId),
shouldPlayTracks(store.state.tracks).has(props.trackId),
);

const setTrackPan = (pan: number) => {
Expand Down
6 changes: 5 additions & 1 deletion src/components/Sing/SingEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,11 @@ const props = defineProps<{

const store = useStore();

const isSidebarOpen = computed(() => store.state.isSongSidebarOpen);
const isSidebarOpen = computed(
() =>
store.state.experimentalSetting.enableMultiTrack &&
store.state.isSongSidebarOpen,
);
const sidebarWidth = ref(300);

const setSidebarWidth = (width: number) => {
Expand Down
5 changes: 5 additions & 0 deletions src/components/Sing/ToolBar/ToolBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<!-- configs for entire song -->
<div class="sing-configs">
<QBtn
v-if="multiTrackEnabled"
class="q-mx-xs"
:icon="isSidebarOpen ? 'menu_open' : 'menu'"
round
Expand Down Expand Up @@ -168,6 +169,10 @@ const editor = "song";
const canUndo = computed(() => store.getters.CAN_UNDO(editor));
const canRedo = computed(() => store.getters.CAN_REDO(editor));

const multiTrackEnabled = computed(
() => store.state.experimentalSetting.enableMultiTrack,
);

const { registerHotkeyWithCleanup } = useHotkeyManager();
registerHotkeyWithCleanup({
editor,
Expand Down
3 changes: 1 addition & 2 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createApp } from "vue";
import { createGtm } from "@gtm-support/vue-gtm";
import { Quasar, Dialog, Loading, Notify } from "quasar";
import iconSet from "quasar/icon-set/material-icons";
import { store, watchStoreStatePlugin, storeKey } from "./store";
import { store, storeKey } from "./store";
import { ipcMessageReceiver } from "./plugins/ipcMessageReceiverPlugin";
import { hotkeyPlugin } from "./plugins/hotkeyPlugin";
import App from "@/components/App.vue";
Expand All @@ -18,7 +18,6 @@ window.dataLayer = [];

createApp(App)
.use(store, storeKey)
.use(watchStoreStatePlugin, { store })
.use(
createGtm({
id: import.meta.env.VITE_GTM_CONTAINER_ID ?? "GTM-DUMMY",
Expand Down
19 changes: 8 additions & 11 deletions src/sing/domain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,8 @@ export function getNumMeasures(
maxTicks = Math.max(maxTicks, lastTsPosition);
maxTicks = Math.max(maxTicks, lastTempoPosition);
if (notes.length > 0) {
const lastNote = notes[notes.length - 1];
const lastNoteEndPosition = lastNote.position + lastNote.duration;
const noteEndPositions = notes.map((note) => note.position + note.duration);
const lastNoteEndPosition = Math.max(...noteEndPositions);
Comment on lines +234 to +235
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(別にこれでもいいんですが)
たぶんreduceでmax書けるはず。

maxTicks = Math.max(maxTicks, lastNoteEndPosition);
}
sevenc-nanashi marked this conversation as resolved.
Show resolved Hide resolved
return tickToMeasureNumber(maxTicks, timeSignatures, tpqn);
Expand Down Expand Up @@ -573,14 +573,11 @@ export const splitLyricsByMoras = (
* ソロのトラックが存在する場合は、ソロのトラックのみ再生する。(ミュートは無視される)
* ソロのトラックが存在しない場合は、ミュートされていないトラックを再生する。
*/
export const shouldPlayTracks = (
tracks: Map<TrackId, Track>,
): Map<TrackId, boolean> => {
export const shouldPlayTracks = (tracks: Map<TrackId, Track>): Set<TrackId> => {
const soloTrackExists = [...tracks.values()].some((track) => track.solo);
const shouldPlayMap = new Map<TrackId, boolean>();
for (const [trackKey, track] of tracks) {
shouldPlayMap.set(trackKey, soloTrackExists ? track.solo : !track.mute);
}

return shouldPlayMap;
return new Set(
[...tracks.entries()]
.filter(([, track]) => (soloTrackExists ? track.solo : !track.mute))
.map(([trackId]) => trackId),
);
};
13 changes: 1 addition & 12 deletions src/store/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { InjectionKey, Plugin } from "vue";
import { InjectionKey } from "vue";
import { createStore, Store, useStore as baseUseStore } from "./vuex";

import {
Expand All @@ -23,7 +23,6 @@ import {
singingStore,
singingCommandStoreState,
singingCommandStore,
singingStorePlugin,
} from "./singing";
import { projectStoreState, projectStore } from "./project";
import { uiStoreState, uiStore } from "./ui";
Expand Down Expand Up @@ -413,16 +412,6 @@ export const store = createStore<State, AllGetters, AllActions, AllMutations>({
strict: !isProduction,
});

// Storeをwatchするためのプラグインをまとめたもの。
export const watchStoreStatePlugin: Plugin = {
install(
app,
{ store }: { store: Store<State, AllGetters, AllActions, AllMutations> },
) {
singingStorePlugin(store);
},
};

export const useStore = (): Store<
State,
AllGetters,
Expand Down
29 changes: 24 additions & 5 deletions src/store/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,7 @@ export const projectStore = createPartialStore<ProjectStoreTypes>({
await context.dispatch("CLEAR_PITCH_EDIT_DATA", { trackId });

context.commit("SET_PROJECT_FILEPATH", { filePath: undefined });
context.commit("RESET_SAVED_LAST_COMMAND_IDS");
context.commit("CLEAR_COMMANDS");
context.dispatch("CLEAR_UNDO_HISTORY");
},
),
},
Expand Down Expand Up @@ -170,7 +169,7 @@ export const projectStore = createPartialStore<ProjectStoreTypes>({
*/
action: createUILockAction(
async (
{ dispatch, commit, getters },
{ dispatch, commit, state, getters },
{ filePath, confirm }: { filePath?: string; confirm?: boolean },
) => {
if (!filePath) {
Expand Down Expand Up @@ -199,6 +198,20 @@ export const projectStore = createPartialStore<ProjectStoreTypes>({
projectJson: text,
});

if (
!state.experimentalSetting.enableMultiTrack &&
parsedProjectData.song.trackOrder.length > 1
) {
await window.backend.showMessageDialog({
type: "error",
title: "エラー",
message:
"このプロジェクトはマルチトラック機能を使用して作成されていますが、現在の設定ではマルチトラック機能を使用できません。\n" +
"設定の「ソング:マルチトラック機能」を有効にしてからプロジェクトを読み込んでください。",
});
return false;
}

if (confirm !== false && getters.IS_EDITED) {
const result = await dispatch("SAVE_OR_DISCARD_PROJECT_FILE", {
additionalMessage:
Expand All @@ -213,8 +226,7 @@ export const projectStore = createPartialStore<ProjectStoreTypes>({
await applySongProjectToStore(dispatch, parsedProjectData.song);

commit("SET_PROJECT_FILEPATH", { filePath });
commit("RESET_SAVED_LAST_COMMAND_IDS");
commit("CLEAR_COMMANDS");
dispatch("CLEAR_UNDO_HISTORY");
return true;
} catch (err) {
window.backend.logError(err);
Expand Down Expand Up @@ -401,4 +413,11 @@ export const projectStore = createPartialStore<ProjectStoreTypes>({
state.savedLastCommandIds = { talk: null, song: null };
},
},

CLEAR_UNDO_HISTORY: {
action({ commit }) {
commit("RESET_SAVED_LAST_COMMAND_IDS");
commit("CLEAR_COMMANDS");
},
},
});
1 change: 1 addition & 0 deletions src/store/setting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export const settingStoreState: SettingStoreState = {
enableMultiSelect: false,
shouldKeepTuningOnTextChange: false,
enablePitchEditInSongEditor: false,
enableMultiTrack: false,
},
splitTextWhenPaste: "PERIOD_AND_NEW_LINE",
splitterPosition: {
Expand Down
Loading
Loading