diff --git a/front/components/VirtualPiano/Octave.tsx b/front/components/VirtualPiano/Octave.tsx index bec5028..2c18796 100644 --- a/front/components/VirtualPiano/Octave.tsx +++ b/front/components/VirtualPiano/Octave.tsx @@ -3,7 +3,7 @@ import { PianoKey, NoteNameBehavior, octaveKeys, - Accidental, + isAccidental, HighlightedKey, } from "../../models/Piano"; import { Box, Row, Pressable, Text } from "native-base"; @@ -74,15 +74,15 @@ const Octave = (props: OctaveProps) => { onNoteUp, } = props; const oK: PianoKey[] = octaveKeys.map((k) => { - return new PianoKey(k.note, k.accidental, number); + return new PianoKey(k.note, number); }); const startNoteIndex = getKeyIndex(startNote, oK); const endNoteIndex = getKeyIndex(endNote, oK); const keys = oK.slice(startNoteIndex, endNoteIndex + 1); - const whiteKeys = keys.filter((k) => k?.accidental === undefined); - const blackKeys = keys.filter((k) => k?.accidental !== undefined); + const whiteKeys = keys.filter((k) => !isAccidental(k)); + const blackKeys = keys.filter(isAccidental); const whiteKeyWidthExpr = "calc(100% / 7)"; const whiteKeyHeightExpr = "100%"; @@ -94,18 +94,17 @@ const Octave = (props: OctaveProps) => { {whiteKeys.map((key, i) => { const highlightedKey = highlightedNotes.find( - (h) => - h.key.note === key.note && h.key.accidental === key.accidental + (h) => h.key.note === key.note ); const isHighlighted = highlightedKey !== undefined; const highlightColor = highlightedKey?.bgColor ?? defaultHighlightColor; return ( onNoteDown(key)} @@ -114,14 +113,12 @@ const Octave = (props: OctaveProps) => { width: whiteKeyWidthExpr, height: whiteKeyHeightExpr, }} - /> ); })} {blackKeys.map((key, i) => { const highlightedKey = highlightedNotes.find( - (h) => - h.key.note === key.note && h.key.accidental === key.accidental + (h) => h.key.note === key.note ); const isHighlighted = highlightedKey !== undefined; const highlightColor = diff --git a/front/components/VirtualPiano/PianoKeyComp.tsx b/front/components/VirtualPiano/PianoKeyComp.tsx index f1bd7f9..4b2d859 100644 --- a/front/components/VirtualPiano/PianoKeyComp.tsx +++ b/front/components/VirtualPiano/PianoKeyComp.tsx @@ -6,8 +6,6 @@ import { PianoKey, NoteNameBehavior, octaveKeys, - Accidental, - HighlightedKey, keyToStr, } from "../../models/Piano"; diff --git a/front/components/VirtualPiano/VirtualPiano.tsx b/front/components/VirtualPiano/VirtualPiano.tsx index 77c93af..4c5ae1b 100644 --- a/front/components/VirtualPiano/VirtualPiano.tsx +++ b/front/components/VirtualPiano/VirtualPiano.tsx @@ -1,7 +1,13 @@ import { Row, Box } from "native-base"; import React, { useState, useEffect } from "react"; import Octave from "./Octave"; -import { Note, PianoKey, NoteNameBehavior, KeyPressStyle, keyToStr } from "../../models/Piano"; +import { + Note, + PianoKey, + NoteNameBehavior, + KeyPressStyle, + keyToStr, +} from "../../models/Piano"; type VirtualPianoProps = Parameters[0] & { onNoteDown: (note: PianoKey) => void; @@ -21,71 +27,74 @@ type VirtualPianoProps = Parameters[0] & { }; const VirtualPiano = ({ - onNoteDown, - onNoteUp, - startOctave, - startNote, - endOctave, - endNote, - showNoteNames, - highlightedNotes, - highlightColor, - specialHighlightedNotes, - specialHighlightColor, - showOctaveNumbers, - keyPressStyle, - vividKeyPressColor, + onNoteDown, + onNoteUp, + startOctave, + startNote, + endOctave, + endNote, + showNoteNames, + highlightedNotes, + highlightColor, + specialHighlightedNotes, + specialHighlightColor, + showOctaveNumbers, + keyPressStyle, + vividKeyPressColor, }: VirtualPianoProps) => { - const notesList: Array = [ - Note.C, - Note.D, - Note.E, - Note.F, - Note.G, - Note.A, - Note.B, - ]; - const octaveList = []; + const notesList: Array = [ + Note.C, + Note.D, + Note.E, + Note.F, + Note.G, + Note.A, + Note.B, + ]; + const octaveList = []; - for (let octaveNum = startOctave; octaveNum <= endOctave; octaveNum++) { - octaveList.push(octaveNum); - }; + for (let octaveNum = startOctave; octaveNum <= endOctave; octaveNum++) { + octaveList.push(octaveNum); + } return ( - {octaveList.map((octaveNum) => { - return ( - - ); - })} - + {octaveList.map((octaveNum) => { + return ( + + ); + })} + ); }; VirtualPiano.defaultProps = { - onNoteDown: (n) => { - console.log("Note down: " + keyToStr(n)); - }, - onNoteUp: (n) => { - console.log("Note up: " + keyToStr(n)); - }, + onNoteDown: (n) => { + console.log("Note down: " + keyToStr(n)); + }, + onNoteUp: (n) => { + console.log("Note up: " + keyToStr(n)); + }, startOctave: 2, startNote: Note.C, endOctave: 2, endNote: Note.B, showNoteNames: NoteNameBehavior.onpress, - highlightedNotes: [], + highlightedNotes: [{ key: Note.D }, { key: Note.G, bgColor: "blue" }], highlightColor: "red", specialHighlightedNotes: [Note.D, Note.G], specialHighlightColor: "blue", diff --git a/front/models/Piano.ts b/front/models/Piano.ts index 71e4182..f15d0f2 100644 --- a/front/models/Piano.ts +++ b/front/models/Piano.ts @@ -1,20 +1,18 @@ export enum Note { "C", + "C#", "D", + "D#", "E", "F", + "F#", "G", + "G#", "A", + "A#", "B", } -export enum Accidental { - "#", - "b", - "##", - "bb", -} - export enum NoteNameBehavior { "always", "onpress", @@ -25,7 +23,7 @@ export enum NoteNameBehavior { export enum KeyPressStyle { "subtle", "vivid", -}; +} export type HighlightedKey = { key: PianoKey; // if not specified, the default color for highlighted notes will be used @@ -34,83 +32,136 @@ export type HighlightedKey = { export class PianoKey { public note: Note; - public accidental?: Accidental; public octave?: number; - constructor(note: Note, accidental?: Accidental, octave?: number) { + constructor(note: Note, octave?: number) { this.note = note; - this.accidental = accidental; this.octave = octave; } public toString = () => { - return this.note as unknown as string + (this.accidental || "") + (this.octave || ""); + return (this.note as unknown as string) + (this.octave || ""); }; } export const strToKey = (str: string): PianoKey => { - let note : Note; - switch (str[0]) { - case "C": note = Note.C; break; - case "D": note = Note.D; break; - case "E": note = Note.E; break; - case "F": note = Note.F; break; - case "G": note = Note.G; break; - case "A": note = Note.A; break; - case "B": note = Note.B; break; - default: throw new Error("Invalid note name"); - } - if (str.length === 1) { - return new PianoKey(note); - } - let accidental : Accidental; - switch (str[1]) { - case "#": accidental = Accidental["#"]; break; - case "b": accidental = Accidental["b"]; break; - case "x": accidental = Accidental["##"]; break; - case "n": accidental = Accidental["bb"]; break; - default: throw new Error("Invalid accidental"); - } - if (str.length === 2) { - return new PianoKey(note, accidental); - } - const octave = parseInt(str[2] as unknown as string); - return new PianoKey(note, accidental, octave); + let note: Note; + switch (str[0]) { + case "C": + note = Note.C; + break; + case "D": + note = Note.D; + break; + case "E": + note = Note.E; + break; + case "F": + note = Note.F; + break; + case "G": + note = Note.G; + break; + case "A": + note = Note.A; + break; + case "B": + note = Note.B; + break; + case "C#": + note = Note["C#"]; + break; + case "D#": + note = Note["D#"]; + break; + case "F#": + note = Note["F#"]; + break; + case "G#": + note = Note["G#"]; + break; + case "A#": + note = Note["A#"]; + break; + default: + throw new Error("Invalid note name"); + } + if (str.length < 3) { + return new PianoKey(note); + } + const octave = parseInt(str[2] as unknown as string); + return new PianoKey(note, octave); }; export const keyToStr = (key: PianoKey, showOctave: boolean = true): string => { - let s = ""; - switch (key.note) { - case Note.C: s += "C"; break; - case Note.D: s += "D"; break; - case Note.E: s += "E"; break; - case Note.F: s += "F"; break; - case Note.G: s += "G"; break; - case Note.A: s += "A"; break; - case Note.B: s += "B"; break; - } - if (key.accidental !== undefined) { - switch (key.accidental) { - default: s += "#"; break; - } - } - if (showOctave && key.octave) { - s += key.octave; - } - return s; + let s = ""; + switch (key.note) { + case Note.C: + s += "C"; + break; + case Note.D: + s += "D"; + break; + case Note.E: + s += "E"; + break; + case Note.F: + s += "F"; + break; + case Note.G: + s += "G"; + break; + case Note.A: + s += "A"; + break; + case Note.B: + s += "B"; + break; + case Note["C#"]: + s += "C#"; + break; + case Note["D#"]: + s += "D#"; + break; + case Note["F#"]: + s += "F#"; + break; + case Note["G#"]: + s += "G#"; + break; + case Note["A#"]: + s += "A#"; + break; + default: + throw new Error("Invalid note name"); + } + if (showOctave && key.octave) { + s += key.octave; + } + return s; +}; + +export const isAccidental = (key: PianoKey): boolean => { + return ( + key.note === Note["C#"] || + key.note === Note["D#"] || + key.note === Note["F#"] || + key.note === Note["G#"] || + key.note === Note["A#"] + ); }; export const octaveKeys: Array = [ new PianoKey(Note.C), - new PianoKey(Note.C, Accidental["#"]), - new PianoKey(Note.D), - new PianoKey(Note.D, Accidental["#"]), - new PianoKey(Note.E), - new PianoKey(Note.F), - new PianoKey(Note.F, Accidental["#"]), - new PianoKey(Note.G), - new PianoKey(Note.G, Accidental["#"]), - new PianoKey(Note.A), - new PianoKey(Note.A, Accidental["#"]), - new PianoKey(Note.B), -]; \ No newline at end of file + new PianoKey(Note["C#"]), + new PianoKey(Note.D), + new PianoKey(Note["D#"]), + new PianoKey(Note.E), + new PianoKey(Note.F), + new PianoKey(Note["F#"]), + new PianoKey(Note.G), + new PianoKey(Note["G#"]), + new PianoKey(Note.A), + new PianoKey(Note["A#"]), + new PianoKey(Note.B), +];