From 17d59f945b8a18c320e825763738d7ea4c2f588a Mon Sep 17 00:00:00 2001 From: "wilckerson.ganda" Date: Mon, 10 Jun 2024 19:04:50 -0700 Subject: [PATCH] PR feedbacks --- CHANGELOG.md | 1 + src/components/GridLattice.vue | 3 +- src/components/JustIntonationLattice.vue | 4 +- src/components/VirtualKeyboard.vue | 5 +- src/components/VirtualKeyboardKey.vue | 103 ++--------- src/components/VirtualPiano.vue | 128 +++---------- src/components/VirtualTypingKeyboard.vue | 222 +++-------------------- src/components/hooks/usePlayNote.ts | 84 +++++++++ src/types.ts | 2 + src/views/LatticeView.vue | 99 +++------- src/views/VirtualKeyboardView.vue | 4 +- src/views/VirtualQwerty.vue | 4 +- 12 files changed, 181 insertions(+), 478 deletions(-) create mode 100644 src/components/hooks/usePlayNote.ts create mode 100644 src/types.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b8258d7..c251a5e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ * Style fix: Make checkbox and radio button labels more consistent [#644](https://github.com/xenharmonic-devs/scale-workshop/issues/644) * Beta cycle issues: [#643](https://github.com/xenharmonic-devs/scale-workshop/issues/643), [#640](https://github.com/xenharmonic-devs/scale-workshop/issues/640), [#577](https://github.com/xenharmonic-devs/scale-workshop/issues/577), [#513](https://github.com/xenharmonic-devs/scale-workshop/issues/513), [#658](https://github.com/xenharmonic-devs/scale-workshop/issues/658), [#664](https://github.com/xenharmonic-devs/scale-workshop/issues/664), [#666](https://github.com/xenharmonic-devs/scale-workshop/issues/666) * Alpha cycle issues: [#574](https://github.com/xenharmonic-devs/scale-workshop/issues/574), [#579](https://github.com/xenharmonic-devs/scale-workshop/issues/579) + * Feature: Adding click and play note for Lattices [#701](https://github.com/xenharmonic-devs/scale-workshop/pull/701), [#38](https://github.com/xenharmonic-devs/scale-workshop/issues/38) ## 2.4.1 * Bug fix: Unison is no longer affected by random variance [#613](https://github.com/xenharmonic-devs/scale-workshop/issues/613) diff --git a/src/components/GridLattice.vue b/src/components/GridLattice.vue index 6fec5a92..0fffc9fa 100644 --- a/src/components/GridLattice.vue +++ b/src/components/GridLattice.vue @@ -1,5 +1,6 @@ @@ -104,13 +25,13 @@ onUnmounted(() => { :data-key-number="index" :style="'background-color:' + color" :class="{ active, light, dark: !light }" - @touchstart="onTouchStart" - @touchend="onTouchEnd" - @touchcancel="onTouchEnd" - @mousedown="onMouseDown" - @mouseup="onMouseUp" - @mouseenter="onMouseEnter" - @mouseleave="onMouseLeave" + @touchstart="playNote.onTouchStart" + @touchend="playNote.onTouchEnd" + @touchcancel="playNote.onTouchEnd" + @mousedown="playNote.onMouseDown" + @mouseup="playNote.onMouseUp" + @mouseenter="playNote.onMouseEnter" + @mouseleave="playNote.onMouseLeave" > diff --git a/src/components/VirtualPiano.vue b/src/components/VirtualPiano.vue index dea89fd0..5b95ce0d 100644 --- a/src/components/VirtualPiano.vue +++ b/src/components/VirtualPiano.vue @@ -1,9 +1,8 @@ @@ -333,13 +257,13 @@ onUnmounted(() => { { { void -type NoteOnCallback = (index: number) => NoteOff type ColorMap = (index: number) => string const props = defineProps<{ @@ -174,227 +172,62 @@ function windowKeyUp(event: KeyboardEvent) { shiftRightFill.value = 'lightgray' } } - -// Synth interactive state and properties - -const noteOffs: Map = new Map() - -const isMousePressed = ref(false) - -function start(index: number) { - noteOffs.set(index, props.noteOn(index)) -} - -function end(index: number) { - if (noteOffs.has(index)) { - noteOffs.get(index)!() - noteOffs.delete(index) - } -} - -function onTouchEnd(event: TouchEvent, index: number) { - event.preventDefault() - end(index) -} - -function onTouchStart(event: TouchEvent, index: number) { - event.preventDefault() - // Make sure that we start a new note. - end(index) - - start(index) -} - -function onMouseDown(event: MouseEvent, index: number) { - if (event.button !== LEFT_MOUSE_BTN) { - return - } - event.preventDefault() - isMousePressed.value = true - start(index) -} - -function onMouseUp(event: MouseEvent, index: number) { - if (event.button !== LEFT_MOUSE_BTN) { - return - } - event.preventDefault() - isMousePressed.value = false - end(index) -} - -function onMouseEnter(event: MouseEvent, index: number) { - if (!isMousePressed.value) { - return - } - event.preventDefault() - start(index) -} - -function onMouseLeave(event: MouseEvent, index: number) { - if (!isMousePressed.value) { - return - } - event.preventDefault() - end(index) -} - -function windowMouseUp(event: MouseEvent) { - if (event.button === LEFT_MOUSE_BTN) { - isMousePressed.value = false - } -} +const playNote = usePlayNote(props.noteOn); onMounted(() => { props.typingKeyboard.addKeydownListener(typingKeyDown) - window.addEventListener('keydown', windowKeyDown) - window.addEventListener('keyup', windowKeyUp) - window.addEventListener('mouseup', windowMouseUp) }) onUnmounted(() => { props.typingKeyboard.removeEventListener(typingKeyDown) window.removeEventListener('keydown', windowKeyDown) window.removeEventListener('keyup', windowKeyUp) - noteOffs.forEach((off) => { - if (off !== null) { - off() - } - }) - window.removeEventListener('mouseup', windowMouseUp) + playNote.onUnmounted(); }) @@ -402,12 +235,15 @@ onUnmounted(() => { svg { user-select: none; } + svg rect.white.active { fill: lightgreen !important; } + svg rect.black.active { fill: green; } + .click-not-implemented { cursor: not-allowed; } diff --git a/src/components/hooks/usePlayNote.ts b/src/components/hooks/usePlayNote.ts new file mode 100644 index 00000000..2e294398 --- /dev/null +++ b/src/components/hooks/usePlayNote.ts @@ -0,0 +1,84 @@ +import { ref } from 'vue' +import { LEFT_MOUSE_BTN } from '@/constants' +import type { NoteOff, NoteOnCallback } from 'xen-midi' + +export function usePlayNote(noteOn: NoteOnCallback) { + const isMousePressed = ref(false) + const noteOffs: Map = new Map() + + function start(index: number) { + noteOffs.set(index, noteOn(index,0,0)) + } + + function end(index: number) { + if (noteOffs.has(index)) { + noteOffs.get(index)!() + noteOffs.delete(index) + } + } + + function onTouchEnd(event: TouchEvent, index: number) { + event.preventDefault() + end(index) + } + + function onTouchStart(event: TouchEvent, index: number) { + event.preventDefault() + // Make sure that we start a new note. + end(index) + + start(index) + } + + function onMouseDown(event: MouseEvent, index: number) { + if (event.button !== LEFT_MOUSE_BTN) { + return + } + event.preventDefault() + isMousePressed.value = true + start(index) + } + + function onMouseUp(event: MouseEvent, index: number) { + if (event.button !== LEFT_MOUSE_BTN) { + return + } + event.preventDefault() + isMousePressed.value = false + end(index) + } + + function onMouseEnter(event: MouseEvent, index: number) { + if (!isMousePressed.value) { + return + } + event.preventDefault() + start(index) + } + + function onMouseLeave(event: MouseEvent, index: number) { + if (!isMousePressed.value) { + return + } + event.preventDefault() + end(index) + } + + function onUnmounted(){ + noteOffs.forEach((off) => { + if (off !== null) { + off() + } + }) + } + + return{ + onMouseEnter, + onMouseDown, + onMouseUp, + onTouchStart, + onTouchEnd, + onMouseLeave, + onUnmounted + } +} diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 00000000..31b3f745 --- /dev/null +++ b/src/types.ts @@ -0,0 +1,2 @@ +export type TouchEventCallback = (event: TouchEvent, index: number) => void +export type MouseEventCallback = (event: MouseEvent, index: number) => void diff --git a/src/views/LatticeView.vue b/src/views/LatticeView.vue index 8ca61e3a..b5c0aec4 100644 --- a/src/views/LatticeView.vue +++ b/src/views/LatticeView.vue @@ -1,5 +1,5 @@