diff --git a/src/sing/sequencerStateMachine/states/addNoteState.ts b/src/sing/sequencerStateMachine/states/addNoteState.ts index a56fdd2421..c2c35e9acf 100644 --- a/src/sing/sequencerStateMachine/states/addNoteState.ts +++ b/src/sing/sequencerStateMachine/states/addNoteState.ts @@ -26,6 +26,8 @@ export class AddNoteState private readonly returnStateId: IdleStateId; private currentCursorPos: PositionOnSequencer; + private applyPreview: boolean; + private innerContext: | { noteToAdd: Note; @@ -44,6 +46,7 @@ export class AddNoteState this.returnStateId = args.returnStateId; this.currentCursorPos = args.cursorPosAtStart; + this.applyPreview = false; } private previewAdd(context: Context) { @@ -81,8 +84,10 @@ export class AddNoteState noteNumber: clamp(this.cursorPosAtStart.noteNumber, 0, 127), lyric: getDoremiFromNoteNumber(this.cursorPosAtStart.noteNumber), }; + const noteEndPos = noteToAdd.position + noteToAdd.duration; context.previewNotes.value = [noteToAdd]; + context.guideLineTicks.value = noteEndPos; context.nowPreviewing.value = true; const previewIfNeeded = () => { @@ -121,10 +126,12 @@ export class AddNoteState if (input.mouseEvent.type === "mousemove") { this.currentCursorPos = input.cursorPos; this.innerContext.executePreviewProcess = true; - } else if (input.mouseEvent.type === "mouseup") { - if (mouseButton === "LEFT_BUTTON") { - setNextState(this.returnStateId, undefined); - } + } else if ( + input.mouseEvent.type === "mouseup" && + mouseButton === "LEFT_BUTTON" + ) { + this.applyPreview = true; + setNextState(this.returnStateId, undefined); } } } @@ -138,18 +145,21 @@ export class AddNoteState cancelAnimationFrame(this.innerContext.previewRequestId); - void context.store.actions.COMMAND_ADD_NOTES({ - notes: context.previewNotes.value, - trackId: this.targetTrackId, - }); - void context.store.actions.SELECT_NOTES({ noteIds: previewNoteIds }); - - if (previewNotes.length === 1) { - void context.store.actions.PLAY_PREVIEW_SOUND({ - noteNumber: previewNotes[0].noteNumber, - duration: PREVIEW_SOUND_DURATION, + if (this.applyPreview) { + void context.store.actions.COMMAND_ADD_NOTES({ + notes: context.previewNotes.value, + trackId: this.targetTrackId, }); + void context.store.actions.SELECT_NOTES({ noteIds: previewNoteIds }); + + if (previewNotes.length === 1) { + void context.store.actions.PLAY_PREVIEW_SOUND({ + noteNumber: previewNotes[0].noteNumber, + duration: PREVIEW_SOUND_DURATION, + }); + } } + context.previewNotes.value = []; context.nowPreviewing.value = false; } diff --git a/src/sing/sequencerStateMachine/states/drawPitchState.ts b/src/sing/sequencerStateMachine/states/drawPitchState.ts index ac8a7006e3..74e924ade8 100644 --- a/src/sing/sequencerStateMachine/states/drawPitchState.ts +++ b/src/sing/sequencerStateMachine/states/drawPitchState.ts @@ -24,6 +24,7 @@ export class DrawPitchState private readonly returnStateId: IdleStateId; private currentCursorPos: PositionOnSequencer; + private applyPreview: boolean; private innerContext: | { @@ -43,6 +44,7 @@ export class DrawPitchState this.returnStateId = args.returnStateId; this.currentCursorPos = args.cursorPosAtStart; + this.applyPreview = false; } private previewDrawPitch(context: Context) { @@ -146,6 +148,7 @@ export class DrawPitchState process({ input, + context, setNextState, }: { input: Input; @@ -155,15 +158,27 @@ export class DrawPitchState if (this.innerContext == undefined) { throw new Error("innerContext is undefined."); } + if (context.previewPitchEdit.value == undefined) { + throw new Error("previewPitchEdit is undefined."); + } + if (context.previewPitchEdit.value.type !== "draw") { + throw new Error("previewPitchEdit.type is not draw."); + } const mouseButton = getButton(input.mouseEvent); if (input.targetArea === "SequencerBody") { if (input.mouseEvent.type === "mousemove") { this.currentCursorPos = input.cursorPos; this.innerContext.executePreviewProcess = true; - } else if (input.mouseEvent.type === "mouseup") { - if (mouseButton === "LEFT_BUTTON") { - setNextState(this.returnStateId, undefined); - } + } else if ( + input.mouseEvent.type === "mouseup" && + mouseButton === "LEFT_BUTTON" + ) { + // カーソルを動かさずにマウスのボタンを離したときに1フレームのみの変更になり、 + // 1フレームの変更はピッチ編集ラインとして表示されないので、無視する + const previewPitchEditDataLength = + context.previewPitchEdit.value.data.length; + this.applyPreview = previewPitchEditDataLength >= 2; + setNextState(this.returnStateId, undefined); } } } @@ -181,9 +196,7 @@ export class DrawPitchState cancelAnimationFrame(this.innerContext.previewRequestId); - // カーソルを動かさずにマウスのボタンを離したときに1フレームのみの変更になり、 - // 1フレームの変更はピッチ編集ラインとして表示されないので、無視する - if (context.previewPitchEdit.value.data.length >= 2) { + if (this.applyPreview) { // 平滑化を行う let data = context.previewPitchEdit.value.data; data = data.map((value) => Math.log(value)); diff --git a/src/sing/sequencerStateMachine/states/erasePitchState.ts b/src/sing/sequencerStateMachine/states/erasePitchState.ts index ec5289c286..dc44c572d1 100644 --- a/src/sing/sequencerStateMachine/states/erasePitchState.ts +++ b/src/sing/sequencerStateMachine/states/erasePitchState.ts @@ -19,6 +19,7 @@ export class ErasePitchState private readonly returnStateId: IdleStateId; private currentCursorPos: PositionOnSequencer; + private applyPreview: boolean; private innerContext: | { @@ -37,6 +38,7 @@ export class ErasePitchState this.returnStateId = args.returnStateId; this.currentCursorPos = args.cursorPosAtStart; + this.applyPreview = false; } private previewErasePitch(context: Context) { @@ -108,10 +110,12 @@ export class ErasePitchState if (input.mouseEvent.type === "mousemove") { this.currentCursorPos = input.cursorPos; this.innerContext.executePreviewProcess = true; - } else if (input.mouseEvent.type === "mouseup") { - if (mouseButton === "LEFT_BUTTON") { - setNextState(this.returnStateId, undefined); - } + } else if ( + input.mouseEvent.type === "mouseup" && + mouseButton === "LEFT_BUTTON" + ) { + this.applyPreview = true; + setNextState(this.returnStateId, undefined); } } } @@ -129,11 +133,13 @@ export class ErasePitchState cancelAnimationFrame(this.innerContext.previewRequestId); - void context.store.actions.COMMAND_ERASE_PITCH_EDIT_DATA({ - startFrame: context.previewPitchEdit.value.startFrame, - frameLength: context.previewPitchEdit.value.frameLength, - trackId: this.targetTrackId, - }); + if (this.applyPreview) { + void context.store.actions.COMMAND_ERASE_PITCH_EDIT_DATA({ + startFrame: context.previewPitchEdit.value.startFrame, + frameLength: context.previewPitchEdit.value.frameLength, + trackId: this.targetTrackId, + }); + } context.previewPitchEdit.value = undefined; context.nowPreviewing.value = false; diff --git a/src/sing/sequencerStateMachine/states/moveNoteState.ts b/src/sing/sequencerStateMachine/states/moveNoteState.ts index 5f6eb4b379..52a4caa90e 100644 --- a/src/sing/sequencerStateMachine/states/moveNoteState.ts +++ b/src/sing/sequencerStateMachine/states/moveNoteState.ts @@ -25,6 +25,7 @@ export class MoveNoteState private readonly returnStateId: IdleStateId; private currentCursorPos: PositionOnSequencer; + private applyPreview: boolean; private innerContext: | { @@ -53,6 +54,7 @@ export class MoveNoteState this.returnStateId = args.returnStateId; this.currentCursorPos = args.cursorPosAtStart; + this.applyPreview = false; } private previewMove(context: Context) { @@ -108,6 +110,7 @@ export class MoveNoteState } context.previewNotes.value = [...targetNotesArray]; + context.guideLineTicks.value = guideLineTicks; context.nowPreviewing.value = true; const previewIfNeeded = () => { @@ -148,10 +151,12 @@ export class MoveNoteState if (input.mouseEvent.type === "mousemove") { this.currentCursorPos = input.cursorPos; this.innerContext.executePreviewProcess = true; - } else if (input.mouseEvent.type === "mouseup") { - if (mouseButton === "LEFT_BUTTON") { - setNextState(this.returnStateId, undefined); - } + } else if ( + input.mouseEvent.type === "mouseup" && + mouseButton === "LEFT_BUTTON" + ) { + this.applyPreview = this.innerContext.edited; + setNextState(this.returnStateId, undefined); } } } @@ -165,20 +170,23 @@ export class MoveNoteState cancelAnimationFrame(this.innerContext.previewRequestId); - void context.store.actions.COMMAND_UPDATE_NOTES({ - notes: previewNotes, - trackId: this.targetTrackId, - }); - void context.store.actions.SELECT_NOTES({ - noteIds: previewNoteIds, - }); - - if (previewNotes.length === 1) { - void context.store.actions.PLAY_PREVIEW_SOUND({ - noteNumber: previewNotes[0].noteNumber, - duration: PREVIEW_SOUND_DURATION, + if (this.applyPreview) { + void context.store.actions.COMMAND_UPDATE_NOTES({ + notes: previewNotes, + trackId: this.targetTrackId, }); + void context.store.actions.SELECT_NOTES({ + noteIds: previewNoteIds, + }); + + if (previewNotes.length === 1) { + void context.store.actions.PLAY_PREVIEW_SOUND({ + noteNumber: previewNotes[0].noteNumber, + duration: PREVIEW_SOUND_DURATION, + }); + } } + context.previewNotes.value = []; context.nowPreviewing.value = false; } diff --git a/src/sing/sequencerStateMachine/states/resizeNoteLeftState.ts b/src/sing/sequencerStateMachine/states/resizeNoteLeftState.ts index be8ae3494b..1c56874e05 100644 --- a/src/sing/sequencerStateMachine/states/resizeNoteLeftState.ts +++ b/src/sing/sequencerStateMachine/states/resizeNoteLeftState.ts @@ -25,6 +25,7 @@ export class ResizeNoteLeftState private readonly returnStateId: IdleStateId; private currentCursorPos: PositionOnSequencer; + private applyPreview: boolean; private innerContext: | { @@ -53,6 +54,7 @@ export class ResizeNoteLeftState this.returnStateId = args.returnStateId; this.currentCursorPos = args.cursorPosAtStart; + this.applyPreview = false; } private previewResizeLeft(context: Context) { @@ -101,8 +103,10 @@ export class ResizeNoteLeftState for (const targetNote of targetNotesArray) { targetNotesMap.set(targetNote.id, targetNote); } + const mouseDownNote = getOrThrow(targetNotesMap, this.mouseDownNoteId); context.previewNotes.value = [...targetNotesArray]; + context.guideLineTicks.value = mouseDownNote.position; context.nowPreviewing.value = true; const previewIfNeeded = () => { @@ -147,6 +151,7 @@ export class ResizeNoteLeftState input.mouseEvent.type === "mouseup" && mouseButton === "LEFT_BUTTON" ) { + this.applyPreview = this.innerContext.edited; setNextState(this.returnStateId, undefined); } } @@ -161,18 +166,21 @@ export class ResizeNoteLeftState cancelAnimationFrame(this.innerContext.previewRequestId); - void context.store.actions.COMMAND_UPDATE_NOTES({ - notes: previewNotes, - trackId: this.targetTrackId, - }); - void context.store.actions.SELECT_NOTES({ noteIds: previewNoteIds }); - - if (previewNotes.length === 1) { - void context.store.actions.PLAY_PREVIEW_SOUND({ - noteNumber: previewNotes[0].noteNumber, - duration: PREVIEW_SOUND_DURATION, + if (this.applyPreview) { + void context.store.actions.COMMAND_UPDATE_NOTES({ + notes: previewNotes, + trackId: this.targetTrackId, }); + void context.store.actions.SELECT_NOTES({ noteIds: previewNoteIds }); + + if (previewNotes.length === 1) { + void context.store.actions.PLAY_PREVIEW_SOUND({ + noteNumber: previewNotes[0].noteNumber, + duration: PREVIEW_SOUND_DURATION, + }); + } } + context.previewNotes.value = []; context.nowPreviewing.value = false; } diff --git a/src/sing/sequencerStateMachine/states/resizeNoteRightState.ts b/src/sing/sequencerStateMachine/states/resizeNoteRightState.ts index 4cd1df8335..2e6e653348 100644 --- a/src/sing/sequencerStateMachine/states/resizeNoteRightState.ts +++ b/src/sing/sequencerStateMachine/states/resizeNoteRightState.ts @@ -24,6 +24,7 @@ export class ResizeNoteRightState private readonly returnStateId: IdleStateId; private currentCursorPos: PositionOnSequencer; + private applyPreview: boolean; private innerContext: | { @@ -52,6 +53,7 @@ export class ResizeNoteRightState this.returnStateId = args.returnStateId; this.currentCursorPos = args.cursorPosAtStart; + this.applyPreview = false; } private previewResizeRight(context: Context) { @@ -99,8 +101,11 @@ export class ResizeNoteRightState for (const targetNote of targetNotesArray) { targetNotesMap.set(targetNote.id, targetNote); } + const mouseDownNote = getOrThrow(targetNotesMap, this.mouseDownNoteId); + const noteEndPos = mouseDownNote.position + mouseDownNote.duration; context.previewNotes.value = [...targetNotesArray]; + context.guideLineTicks.value = noteEndPos; context.nowPreviewing.value = true; const previewIfNeeded = () => { @@ -145,6 +150,7 @@ export class ResizeNoteRightState input.mouseEvent.type === "mouseup" && mouseButton === "LEFT_BUTTON" ) { + this.applyPreview = this.innerContext.edited; setNextState(this.returnStateId, undefined); } } @@ -159,20 +165,23 @@ export class ResizeNoteRightState cancelAnimationFrame(this.innerContext.previewRequestId); - void context.store.actions.COMMAND_UPDATE_NOTES({ - notes: previewNotes, - trackId: this.targetTrackId, - }); - void context.store.actions.SELECT_NOTES({ - noteIds: previewNoteIds, - }); - - if (previewNotes.length === 1) { - void context.store.actions.PLAY_PREVIEW_SOUND({ - noteNumber: previewNotes[0].noteNumber, - duration: PREVIEW_SOUND_DURATION, + if (this.applyPreview) { + void context.store.actions.COMMAND_UPDATE_NOTES({ + notes: previewNotes, + trackId: this.targetTrackId, + }); + void context.store.actions.SELECT_NOTES({ + noteIds: previewNoteIds, }); + + if (previewNotes.length === 1) { + void context.store.actions.PLAY_PREVIEW_SOUND({ + noteNumber: previewNotes[0].noteNumber, + duration: PREVIEW_SOUND_DURATION, + }); + } } + context.previewNotes.value = []; context.nowPreviewing.value = false; } diff --git a/src/sing/sequencerStateMachine/states/selectNotesWithRectState.ts b/src/sing/sequencerStateMachine/states/selectNotesWithRectState.ts index fd8beaf2ac..4afe8ec1b0 100644 --- a/src/sing/sequencerStateMachine/states/selectNotesWithRectState.ts +++ b/src/sing/sequencerStateMachine/states/selectNotesWithRectState.ts @@ -19,6 +19,7 @@ export class SelectNotesWithRectState private readonly returnStateId: IdleStateId; private currentCursorPos: PositionOnSequencer; + private applyPreview: boolean; private additive: boolean; constructor(args: { @@ -29,6 +30,7 @@ export class SelectNotesWithRectState this.returnStateId = args.returnStateId; this.currentCursorPos = args.cursorPosAtStart; + this.applyPreview = false; this.additive = false; } @@ -48,6 +50,9 @@ export class SelectNotesWithRectState onEnter(context: Context) { this.updatePreviewRect(context); + + // TODO: ScoreSequencer.vueのコードをnowPreview == trueを考慮したコードにする + context.nowPreviewing.value = true; } process({ @@ -68,6 +73,7 @@ export class SelectNotesWithRectState input.mouseEvent.type === "mouseup" && mouseButton === "LEFT_BUTTON" ) { + this.applyPreview = true; this.additive = isOnCommandOrCtrlKeyDown(input.mouseEvent); setNextState(this.returnStateId, undefined); } @@ -75,39 +81,42 @@ export class SelectNotesWithRectState } onExit(context: Context) { - context.previewRectForRectSelect.value = undefined; + if (this.applyPreview) { + const startTicks = Math.min( + this.cursorPosAtStart.ticks, + this.currentCursorPos.ticks, + ); + const endTicks = Math.max( + this.cursorPosAtStart.ticks, + this.currentCursorPos.ticks, + ); + const startNoteNumber = Math.min( + this.cursorPosAtStart.noteNumber, + this.currentCursorPos.noteNumber, + ); + const endNoteNumber = Math.max( + this.cursorPosAtStart.noteNumber, + this.currentCursorPos.noteNumber, + ); - const startTicks = Math.min( - this.cursorPosAtStart.ticks, - this.currentCursorPos.ticks, - ); - const endTicks = Math.max( - this.cursorPosAtStart.ticks, - this.currentCursorPos.ticks, - ); - const startNoteNumber = Math.min( - this.cursorPosAtStart.noteNumber, - this.currentCursorPos.noteNumber, - ); - const endNoteNumber = Math.max( - this.cursorPosAtStart.noteNumber, - this.currentCursorPos.noteNumber, - ); - - const noteIdsToSelect: NoteId[] = []; - for (const note of context.notesInSelectedTrack.value) { - if ( - note.position + note.duration >= startTicks && - note.position <= endTicks && - note.noteNumber >= startNoteNumber && - note.noteNumber <= endNoteNumber - ) { - noteIdsToSelect.push(note.id); + const noteIdsToSelect: NoteId[] = []; + for (const note of context.notesInSelectedTrack.value) { + if ( + note.position + note.duration >= startTicks && + note.position <= endTicks && + note.noteNumber >= startNoteNumber && + note.noteNumber <= endNoteNumber + ) { + noteIdsToSelect.push(note.id); + } } + if (!this.additive) { + void context.store.actions.DESELECT_ALL_NOTES(); + } + void context.store.actions.SELECT_NOTES({ noteIds: noteIdsToSelect }); } - if (!this.additive) { - void context.store.actions.DESELECT_ALL_NOTES(); - } - void context.store.actions.SELECT_NOTES({ noteIds: noteIdsToSelect }); + + context.previewRectForRectSelect.value = undefined; + context.nowPreviewing.value = false; } }