diff --git a/public/draw-cursor.png b/public/draw-cursor.png new file mode 100644 index 0000000000..0bcf5ab112 Binary files /dev/null and b/public/draw-cursor.png differ diff --git a/src/components/Dialog/SettingDialog.vue b/src/components/Dialog/SettingDialog.vue index 0c1ff313b7..7f776502ae 100644 --- a/src/components/Dialog/SettingDialog.vue +++ b/src/components/Dialog/SettingDialog.vue @@ -955,9 +955,9 @@ -
ソング:ピッチを表示
+
ソング:ピッチ編集機能
ONの場合、ソングエディターでピッチ(音の高さ)が表示されます。ピッチ編集機能を有効にします。ピッチ編集モードに切り替えられるようになります。
diff --git a/src/components/Sing/ScoreSequencer.vue b/src/components/Sing/ScoreSequencer.vue index 006977035b..fa6dad911b 100644 --- a/src/components/Sing/ScoreSequencer.vue +++ b/src/components/Sing/ScoreSequencer.vue @@ -18,7 +18,10 @@
- +
@@ -234,13 +244,15 @@ import ContextMenu, { } from "@/components/Menu/ContextMenu.vue"; import { isMac } from "@/type/preload"; import { useStore } from "@/store"; -import { Note } from "@/store/type"; +import { Note, SequencerEditTarget } from "@/store/type"; import { getEndTicksOfPhrase, getMeasureDuration, getNoteDuration, getNumOfMeasures, getStartTicksOfPhrase, + noteNumberToFrequency, + tickToSecond, } from "@/sing/domain"; import { getKeyBaseHeight, @@ -260,6 +272,7 @@ import { DoubleClickDetector, NoteAreaInfo, GridAreaInfo, + getButton, } from "@/sing/viewHelper"; import SequencerRuler from "@/components/Sing/SequencerRuler.vue"; import SequencerKeys from "@/components/Sing/SequencerKeys.vue"; @@ -270,10 +283,21 @@ import SequencerPitch from "@/components/Sing/SequencerPitch.vue"; import { isOnCommandOrCtrlKeyDown } from "@/store/utility"; import { createLogger } from "@/domain/frontend/log"; import { useHotkeyManager } from "@/plugins/hotkeyPlugin"; -import { useShiftKey } from "@/composables/useModifierKey"; +import { + useCommandOrControlKey, + useShiftKey, +} from "@/composables/useModifierKey"; +import { applyGaussianFilter, linearInterpolation } from "@/sing/utility"; import { useLyricInput } from "@/composables/useLyricInput"; +import { ExhaustiveError } from "@/type/utility"; -type PreviewMode = "ADD" | "MOVE" | "RESIZE_RIGHT" | "RESIZE_LEFT"; +type PreviewMode = + | "ADD" + | "MOVE" + | "RESIZE_RIGHT" + | "RESIZE_LEFT" + | "DRAW_PITCH" + | "ERASE_PITCH"; // 直接イベントが来ているかどうか const isSelfEventTarget = (event: UIEvent) => { @@ -392,9 +416,9 @@ const phraseInfos = computed(() => { }); }); -const showPitch = computed(() => { - return state.experimentalSetting.showPitchInSongEditor; -}); +const ctrlKey = useCommandOrControlKey(); +const editTarget = computed(() => state.sequencerEditTarget); +const editFrameRate = computed(() => state.editFrameRate); const scrollBarWidth = ref(12); const sequencerBody = ref(null); @@ -417,16 +441,25 @@ const onNoteLyricBlur = () => { // プレビュー // FIXME: 関連する値を1つのobjectにまとめる const nowPreviewing = ref(false); -const previewNotes = ref([]); -const copiedNotesForPreview = new Map(); let previewMode: PreviewMode = "ADD"; let previewRequestId = 0; +let previewStartEditTarget: SequencerEditTarget = "NOTE"; +let executePreviewProcess = false; +// ノート編集のプレビュー +const previewNotes = ref([]); +const copiedNotesForPreview = new Map(); let dragStartTicks = 0; let dragStartNoteNumber = 0; let dragStartGuideLineTicks = 0; let draggingNoteId = ""; // FIXME: 無効状態はstring以外の型にする -let executePreviewProcess = false; let edited = false; // プレビュー終了時にstore.stateの更新を行うかどうかを表す変数 +// ピッチ編集のプレビュー +const previewPitchEdit = ref< + | { type: "draw"; data: number[]; startFrame: number } + | { type: "erase"; startFrame: number; frameLength: number } + | undefined +>(undefined); +const prevCursorPos = { frame: 0, frequency: 0 }; // 前のカーソル位置 // ダブルクリック let mouseDownAreaInfo: NoteAreaInfo | GridAreaInfo | undefined; @@ -607,6 +640,112 @@ const previewResizeLeft = () => { guideLineX.value = guideLineBaseX * zoomX.value; }; +// ピッチを描く処理を行う +const previewDrawPitch = () => { + if (previewPitchEdit.value == undefined) { + throw new Error("previewPitchEdit.value is undefined."); + } + if (previewPitchEdit.value.type !== "draw") { + throw new Error("previewPitchEdit.value.type is not draw."); + } + const frameRate = editFrameRate.value; + const cursorBaseX = (scrollX.value + cursorX.value) / zoomX.value; + const cursorBaseY = (scrollY.value + cursorY.value) / zoomY.value; + const cursorTicks = baseXToTick(cursorBaseX, tpqn.value); + const cursorSeconds = tickToSecond(cursorTicks, tempos.value, tpqn.value); + const cursorFrame = Math.round(cursorSeconds * frameRate); + const cursorNoteNumber = baseYToNoteNumber(cursorBaseY, false); + const cursorFrequency = noteNumberToFrequency(cursorNoteNumber); + if (cursorFrame < 0) { + return; + } + const tempPitchEdit = { + ...previewPitchEdit.value, + data: [...previewPitchEdit.value.data], + }; + + if (cursorFrame < tempPitchEdit.startFrame) { + const numOfFramesToUnshift = tempPitchEdit.startFrame - cursorFrame; + tempPitchEdit.data = new Array(numOfFramesToUnshift) + .fill(0) + .concat(tempPitchEdit.data); + tempPitchEdit.startFrame = cursorFrame; + } + + const lastFrame = tempPitchEdit.startFrame + tempPitchEdit.data.length - 1; + if (cursorFrame > lastFrame) { + const numOfFramesToPush = cursorFrame - lastFrame; + tempPitchEdit.data = tempPitchEdit.data.concat( + new Array(numOfFramesToPush).fill(0), + ); + } + + if (cursorFrame === prevCursorPos.frame) { + const i = cursorFrame - tempPitchEdit.startFrame; + tempPitchEdit.data[i] = cursorFrequency; + } else if (cursorFrame < prevCursorPos.frame) { + for (let i = cursorFrame; i <= prevCursorPos.frame; i++) { + tempPitchEdit.data[i - tempPitchEdit.startFrame] = Math.exp( + linearInterpolation( + cursorFrame, + Math.log(cursorFrequency), + prevCursorPos.frame, + Math.log(prevCursorPos.frequency), + i, + ), + ); + } + } else { + for (let i = prevCursorPos.frame; i <= cursorFrame; i++) { + tempPitchEdit.data[i - tempPitchEdit.startFrame] = Math.exp( + linearInterpolation( + prevCursorPos.frame, + Math.log(prevCursorPos.frequency), + cursorFrame, + Math.log(cursorFrequency), + i, + ), + ); + } + } + + previewPitchEdit.value = tempPitchEdit; + prevCursorPos.frame = cursorFrame; + prevCursorPos.frequency = cursorFrequency; +}; + +// ドラッグした範囲のピッチ編集データを消去する処理を行う +const previewErasePitch = () => { + if (previewPitchEdit.value == undefined) { + throw new Error("previewPitchEdit.value is undefined."); + } + if (previewPitchEdit.value.type !== "erase") { + throw new Error("previewPitchEdit.value.type is not erase."); + } + const frameRate = editFrameRate.value; + const cursorBaseX = (scrollX.value + cursorX.value) / zoomX.value; + const cursorTicks = baseXToTick(cursorBaseX, tpqn.value); + const cursorSeconds = tickToSecond(cursorTicks, tempos.value, tpqn.value); + const cursorFrame = Math.round(cursorSeconds * frameRate); + if (cursorFrame < 0) { + return; + } + const tempPitchEdit = { ...previewPitchEdit.value }; + + if (tempPitchEdit.startFrame > cursorFrame) { + tempPitchEdit.frameLength += tempPitchEdit.startFrame - cursorFrame; + tempPitchEdit.startFrame = cursorFrame; + } + + const lastFrame = tempPitchEdit.startFrame + tempPitchEdit.frameLength - 1; + if (lastFrame < cursorFrame) { + tempPitchEdit.frameLength += cursorFrame - lastFrame; + } + + previewPitchEdit.value = tempPitchEdit; + prevCursorPos.frame = cursorFrame; +}; + const preview = () => { if (executePreviewProcess) { if (previewMode === "ADD") { @@ -621,6 +760,12 @@ const preview = () => { if (previewMode === "RESIZE_LEFT") { previewResizeLeft(); } + if (previewMode === "DRAW_PITCH") { + previewDrawPitch(); + } + if (previewMode === "ERASE_PITCH") { + previewErasePitch(); + } executePreviewProcess = false; } previewRequestId = requestAnimationFrame(preview); @@ -662,78 +807,175 @@ const startPreview = (event: MouseEvent, mode: PreviewMode, note?: Note) => { } const cursorBaseX = (scrollX.value + cursorX.value) / zoomX.value; const cursorBaseY = (scrollY.value + cursorY.value) / zoomY.value; - const cursorTicks = baseXToTick(cursorBaseX, tpqn.value); - const cursorNoteNumber = baseYToNoteNumber(cursorBaseY); - // NOTE: 入力を補助する線の判定の境目はスナップ幅の3/4の位置 - const guideLineTicks = - Math.round(cursorTicks / snapTicks.value - 0.25) * snapTicks.value; - const copiedNotes: Note[] = []; - if (mode === "ADD") { - if (cursorNoteNumber < 0) { - return; - } - note = { - id: uuidv4(), - position: guideLineTicks, - duration: snapTicks.value, - noteNumber: cursorNoteNumber, - lyric: getDoremiFromNoteNumber(cursorNoteNumber), - }; - store.dispatch("DESELECT_ALL_NOTES"); - copiedNotes.push(note); - } else { - if (!note) { - throw new Error("note is undefined."); - } - if (event.shiftKey) { - let minIndex = notes.value.length - 1; - let maxIndex = 0; - for (let i = 0; i < notes.value.length; i++) { - const noteId = notes.value[i].id; - if (state.selectedNoteIds.has(noteId) || noteId === note.id) { - minIndex = Math.min(minIndex, i); - maxIndex = Math.max(maxIndex, i); - } + + if (editTarget.value === "NOTE") { + // 編集ターゲットがノートのときの処理 + + const cursorTicks = baseXToTick(cursorBaseX, tpqn.value); + const cursorNoteNumber = baseYToNoteNumber(cursorBaseY, true); + // NOTE: 入力を補助する線の判定の境目はスナップ幅の3/4の位置 + const guideLineTicks = + Math.round(cursorTicks / snapTicks.value - 0.25) * snapTicks.value; + const copiedNotes: Note[] = []; + if (mode === "ADD") { + if (cursorNoteNumber < 0) { + return; } - const noteIdsToSelect: string[] = []; - for (let i = minIndex; i <= maxIndex; i++) { - const noteId = notes.value[i].id; - if (!state.selectedNoteIds.has(noteId)) { - noteIdsToSelect.push(noteId); + note = { + id: uuidv4(), + position: guideLineTicks, + duration: snapTicks.value, + noteNumber: cursorNoteNumber, + lyric: getDoremiFromNoteNumber(cursorNoteNumber), + }; + store.dispatch("DESELECT_ALL_NOTES"); + copiedNotes.push(note); + } else { + if (!note) { + throw new Error("note is undefined."); + } + if (event.shiftKey) { + let minIndex = notes.value.length - 1; + let maxIndex = 0; + for (let i = 0; i < notes.value.length; i++) { + const noteId = notes.value[i].id; + if (state.selectedNoteIds.has(noteId) || noteId === note.id) { + minIndex = Math.min(minIndex, i); + maxIndex = Math.max(maxIndex, i); + } + } + const noteIdsToSelect: string[] = []; + for (let i = minIndex; i <= maxIndex; i++) { + const noteId = notes.value[i].id; + if (!state.selectedNoteIds.has(noteId)) { + noteIdsToSelect.push(noteId); + } } + store.dispatch("SELECT_NOTES", { noteIds: noteIdsToSelect }); + } else if (isOnCommandOrCtrlKeyDown(event)) { + store.dispatch("SELECT_NOTES", { noteIds: [note.id] }); + } else if (!state.selectedNoteIds.has(note.id)) { + selectOnlyThis(note); + } + for (const note of selectedNotes.value) { + copiedNotes.push({ ...note }); } - store.dispatch("SELECT_NOTES", { noteIds: noteIdsToSelect }); - } else if (isOnCommandOrCtrlKeyDown(event)) { - store.dispatch("SELECT_NOTES", { noteIds: [note.id] }); - } else if (!state.selectedNoteIds.has(note.id)) { - selectOnlyThis(note); } - for (const note of selectedNotes.value) { - copiedNotes.push({ ...note }); + dragStartTicks = cursorTicks; + dragStartNoteNumber = cursorNoteNumber; + dragStartGuideLineTicks = guideLineTicks; + draggingNoteId = note.id; + edited = mode === "ADD"; + copiedNotesForPreview.clear(); + for (const copiedNote of copiedNotes) { + copiedNotesForPreview.set(copiedNote.id, copiedNote); } + previewNotes.value = copiedNotes; + } else if (editTarget.value === "PITCH") { + // 編集ターゲットがピッチのときの処理 + + const frameRate = editFrameRate.value; + const cursorTicks = baseXToTick(cursorBaseX, tpqn.value); + const cursorSeconds = tickToSecond(cursorTicks, tempos.value, tpqn.value); + const cursorFrame = Math.round(cursorSeconds * frameRate); + const cursorNoteNumber = baseYToNoteNumber(cursorBaseY, false); + const cursorFrequency = noteNumberToFrequency(cursorNoteNumber); + if (mode === "DRAW_PITCH") { + previewPitchEdit.value = { + type: "draw", + data: [cursorFrequency], + startFrame: cursorFrame, + }; + } else if (mode === "ERASE_PITCH") { + previewPitchEdit.value = { + type: "erase", + startFrame: cursorFrame, + frameLength: 1, + }; + } else { + throw new Error("Unknown preview mode."); + } + prevCursorPos.frame = cursorFrame; + prevCursorPos.frequency = cursorFrequency; + } else { + throw new ExhaustiveError(editTarget.value); } previewMode = mode; - dragStartTicks = cursorTicks; - dragStartNoteNumber = cursorNoteNumber; - dragStartGuideLineTicks = guideLineTicks; - draggingNoteId = note.id; + previewStartEditTarget = editTarget.value; executePreviewProcess = true; - edited = mode === "ADD"; - copiedNotesForPreview.clear(); - for (const copiedNote of copiedNotes) { - copiedNotesForPreview.set(copiedNote.id, copiedNote); - } - previewNotes.value = copiedNotes; nowPreviewing.value = true; previewRequestId = requestAnimationFrame(preview); }; +const endPreview = () => { + cancelAnimationFrame(previewRequestId); + if (previewStartEditTarget === "NOTE") { + // 編集ターゲットがノートのときにプレビューを開始した場合の処理 + + if (edited) { + if (previewMode === "ADD") { + store.dispatch("COMMAND_ADD_NOTES", { notes: previewNotes.value }); + store.dispatch("SELECT_NOTES", { + noteIds: previewNotes.value.map((value) => value.id), + }); + } else { + store.dispatch("COMMAND_UPDATE_NOTES", { notes: previewNotes.value }); + } + if (previewNotes.value.length === 1) { + store.dispatch("PLAY_PREVIEW_SOUND", { + noteNumber: previewNotes.value[0].noteNumber, + duration: PREVIEW_SOUND_DURATION, + }); + } + } + } else if (previewStartEditTarget === "PITCH") { + // 編集ターゲットがピッチのときにプレビューを開始した場合の処理 + + if (previewPitchEdit.value == undefined) { + throw new Error("previewPitchEdit.value is undefined."); + } + const previewPitchEditType = previewPitchEdit.value.type; + if (previewPitchEditType === "draw") { + // カーソルを動かさずにマウスのボタンを離したときに1フレームのみの変更になり、 + // 1フレームの変更はピッチ編集ラインとして表示されないので、無視する + if (previewPitchEdit.value.data.length >= 2) { + // 平滑化を行う + let data = previewPitchEdit.value.data; + data = data.map((value) => Math.log(value)); + applyGaussianFilter(data, 0.7); + data = data.map((value) => Math.exp(value)); + + store.dispatch("COMMAND_SET_PITCH_EDIT_DATA", { + data, + startFrame: previewPitchEdit.value.startFrame, + }); + } + } else if (previewPitchEditType === "erase") { + store.dispatch("COMMAND_ERASE_PITCH_EDIT_DATA", { + startFrame: previewPitchEdit.value.startFrame, + frameLength: previewPitchEdit.value.frameLength, + }); + } else { + throw new ExhaustiveError(previewPitchEditType); + } + previewPitchEdit.value = undefined; + } else { + throw new ExhaustiveError(previewStartEditTarget); + } + nowPreviewing.value = false; +}; + const onNoteBarMouseDown = (event: MouseEvent, note: Note) => { - if (!isSelfEventTarget(event)) { + if (editTarget.value !== "NOTE" || !isSelfEventTarget(event)) { return; } - if (event.button === 0) { + const mouseButton = getButton(event); + // ダブルクリック用の処理を行う + if (mouseButton === "LEFT_BUTTON") { mouseDownAreaInfo = new NoteAreaInfo(note.id); + } + + if (mouseButton === "LEFT_BUTTON") { startPreview(event, "MOVE", note); } else if (!state.selectedNoteIds.has(note.id)) { selectOnlyThis(note); @@ -741,11 +983,16 @@ const onNoteBarMouseDown = (event: MouseEvent, note: Note) => { }; const onNoteLeftEdgeMouseDown = (event: MouseEvent, note: Note) => { - if (!isSelfEventTarget(event)) { + if (editTarget.value !== "NOTE" || !isSelfEventTarget(event)) { return; } - if (event.button === 0) { + const mouseButton = getButton(event); + // ダブルクリック用の処理を行う + if (mouseButton === "LEFT_BUTTON") { mouseDownAreaInfo = new NoteAreaInfo(note.id); + } + + if (mouseButton === "LEFT_BUTTON") { startPreview(event, "RESIZE_LEFT", note); } else if (!state.selectedNoteIds.has(note.id)) { selectOnlyThis(note); @@ -753,11 +1000,16 @@ const onNoteLeftEdgeMouseDown = (event: MouseEvent, note: Note) => { }; const onNoteRightEdgeMouseDown = (event: MouseEvent, note: Note) => { - if (!isSelfEventTarget(event)) { + if (editTarget.value !== "NOTE" || !isSelfEventTarget(event)) { return; } - if (event.button === 0) { + const mouseButton = getButton(event); + // ダブルクリック用の処理を行う + if (mouseButton === "LEFT_BUTTON") { mouseDownAreaInfo = new NoteAreaInfo(note.id); + } + + if (mouseButton === "LEFT_BUTTON") { startPreview(event, "RESIZE_RIGHT", note); } else if (!state.selectedNoteIds.has(note.id)) { selectOnlyThis(note); @@ -765,41 +1017,61 @@ const onNoteRightEdgeMouseDown = (event: MouseEvent, note: Note) => { }; const onNoteLyricMouseDown = (event: MouseEvent, note: Note) => { - if (!isSelfEventTarget(event)) { + if (editTarget.value !== "NOTE" || !isSelfEventTarget(event)) { return; } - if (event.button === 0) { + const mouseButton = getButton(event); + // ダブルクリック用の処理を行う + if (mouseButton === "LEFT_BUTTON") { mouseDownAreaInfo = new NoteAreaInfo(note.id); } + if (!state.selectedNoteIds.has(note.id)) { selectOnlyThis(note); } }; const onMouseDown = (event: MouseEvent) => { - if (!isSelfEventTarget(event)) { + if (editTarget.value === "NOTE" && !isSelfEventTarget(event)) { return; } - - // macOSの場合、Ctrl+クリックが右クリックのため、その場合はノートを追加しない - if (isMac && event.ctrlKey && event.button === 0) { - return; + const mouseButton = getButton(event); + // ダブルクリック用の処理を行う + if (mouseButton === "LEFT_BUTTON") { + mouseDownAreaInfo = new GridAreaInfo(); } // TODO: メニューが表示されている場合はメニュー非表示のみ行いたい - - // 選択中のノートが無い場合、プレビューを開始しノートIDをリセット - if (event.button === 0) { - mouseDownAreaInfo = new GridAreaInfo(); - if (event.shiftKey) { - isRectSelecting.value = true; - rectSelectStartX.value = cursorX.value; - rectSelectStartY.value = cursorY.value; + if (editTarget.value === "NOTE") { + if (mouseButton === "LEFT_BUTTON") { + if (event.shiftKey) { + isRectSelecting.value = true; + rectSelectStartX.value = cursorX.value; + rectSelectStartY.value = cursorY.value; + } else { + startPreview(event, "ADD"); + } } else { - startPreview(event, "ADD"); + store.dispatch("DESELECT_ALL_NOTES"); + } + } else if (editTarget.value === "PITCH") { + if (isMac) { + // Macの場合、左ボタンでDRAW、右ボタンでERASE + if (mouseButton === "LEFT_BUTTON") { + startPreview(event, "DRAW_PITCH"); + } else if (mouseButton === "RIGHT_BUTTON") { + startPreview(event, "ERASE_PITCH"); + } + } else if (mouseButton === "LEFT_BUTTON") { + // Mac以外の場合、左ボタンでDRAW、左ボタン+CtrlでERASE + if (event.ctrlKey) { + startPreview(event, "ERASE_PITCH"); + } else { + startPreview(event, "DRAW_PITCH"); + } } } else { - store.dispatch("DESELECT_ALL_NOTES"); + throw new ExhaustiveError(editTarget.value); } }; @@ -826,39 +1098,22 @@ const onMouseMove = (event: MouseEvent) => { }; const onMouseUp = (event: MouseEvent) => { - if (event.button !== 0) { + const mouseButton = getButton(event); + if (mouseButton !== "LEFT_BUTTON") { return; } + // ダブルクリック用の処理を行う if (mouseDownAreaInfo) { doubleClickDetector.recordClick(event.detail, mouseDownAreaInfo); } - ignoreDoubleClick = nowPreviewing.value && edited; + ignoreDoubleClick = + editTarget.value !== "NOTE" || (nowPreviewing.value && edited); if (isRectSelecting.value) { rectSelect(isOnCommandOrCtrlKeyDown(event)); - return; - } - if (!nowPreviewing.value) { - return; - } - cancelAnimationFrame(previewRequestId); - if (edited) { - if (previewMode === "ADD") { - store.dispatch("COMMAND_ADD_NOTES", { notes: previewNotes.value }); - store.dispatch("SELECT_NOTES", { - noteIds: previewNotes.value.map((value) => value.id), - }); - } else { - store.dispatch("COMMAND_UPDATE_NOTES", { notes: previewNotes.value }); - } - if (previewNotes.value.length === 1) { - store.dispatch("PLAY_PREVIEW_SOUND", { - noteNumber: previewNotes.value[0].noteNumber, - duration: PREVIEW_SOUND_DURATION, - }); - } + } else if (nowPreviewing.value) { + endPreview(); } - nowPreviewing.value = false; }; /** @@ -1451,4 +1706,10 @@ const contextMenuData = ref([ border: 2px solid rgba(colors.$primary-rgb, 0.5); background: rgba(colors.$primary-rgb, 0.25); } + +.cursor-draw { + cursor: + url("/draw-cursor.png") 2 30, + auto; +} diff --git a/src/components/Sing/SequencerNote.vue b/src/components/Sing/SequencerNote.vue index 6467bc9289..0523e2452f 100644 --- a/src/components/Sing/SequencerNote.vue +++ b/src/components/Sing/SequencerNote.vue @@ -6,7 +6,7 @@ 'preview-lyric': props.previewLyric != undefined, overlapping: hasOverlappingError, 'invalid-phrase': hasPhraseError, - 'below-pitch': showPitch, + 'below-pitch': editTargetIsPitch, }" :style="{ width: `${width}px`, @@ -14,10 +14,32 @@ transform: `translate3d(${positionX}px,${positionY}px,0)`, }" > -
-
-
- +
+
+
+
{ } return "NORMAL"; }); +const editTargetIsNote = computed(() => { + return state.sequencerEditTarget === "NOTE"; +}); +const editTargetIsPitch = computed(() => { + return state.sequencerEditTarget === "PITCH"; +}); // ノートの重なりエラー const hasOverlappingError = computed(() => { @@ -159,9 +187,6 @@ const temporaryLyric = ref(undefined); const showLyricInput = computed(() => { return state.editingLyricNoteId === props.note.id; }); -const showPitch = computed(() => { - return state.experimentalSetting.showPitchInSongEditor; -}); const contextMenu = ref>(); const contextMenuData = ref([ { @@ -290,7 +315,7 @@ const onLyricInput = (event: Event) => { &.below-pitch { .note-bar { - background-color: rgba(hsl(33, 100%, 50%), 0.18); + background-color: rgba(colors.$primary-rgb, 0.18); } } } @@ -353,7 +378,6 @@ const onLyricInput = (event: Event) => { background-color: colors.$primary; border: 1px solid rgba(colors.$background-rgb, 0.5); border-radius: 2px; - cursor: move; } .note-left-edge { @@ -362,7 +386,6 @@ const onLyricInput = (event: Event) => { left: -1px; width: 5px; height: 100%; - cursor: ew-resize; } .note-right-edge { @@ -371,7 +394,6 @@ const onLyricInput = (event: Event) => { right: -1px; width: 5px; height: 100%; - cursor: ew-resize; } .note-lyric-input { @@ -384,4 +406,12 @@ const onLyricInput = (event: Event) => { outline: 2px solid colors.$primary; border-radius: 0.25rem; } + +.cursor-move { + cursor: move; +} + +.cursor-ew-resize { + cursor: ew-resize; +} diff --git a/src/components/Sing/SequencerPitch.vue b/src/components/Sing/SequencerPitch.vue index 3a4b7878eb..0a2cca7da5 100644 --- a/src/components/Sing/SequencerPitch.vue +++ b/src/components/Sing/SequencerPitch.vue @@ -5,39 +5,56 @@