removed accidental as it's own type and integrated it with note type
This commit is contained in:
@@ -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) => {
|
||||
<Row height={"100%"} width={"100%"}>
|
||||
{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 (
|
||||
<PianoKeyComp
|
||||
key={i}
|
||||
key={i}
|
||||
pianoKey={key}
|
||||
showNoteName={showNoteNames}
|
||||
bg={isHighlighted ? highlightColor :whiteKeyBg}
|
||||
bg={isHighlighted ? highlightColor : whiteKeyBg}
|
||||
bgPressed={isHighlighted ? highlightColor : whiteKeyBgPressed}
|
||||
bgHovered={isHighlighted ? highlightColor : whiteKeyBgHovered}
|
||||
onKeyDown={() => 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 =
|
||||
|
||||
@@ -6,8 +6,6 @@ import {
|
||||
PianoKey,
|
||||
NoteNameBehavior,
|
||||
octaveKeys,
|
||||
Accidental,
|
||||
HighlightedKey,
|
||||
keyToStr,
|
||||
} from "../../models/Piano";
|
||||
|
||||
|
||||
@@ -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<typeof Row>[0] & {
|
||||
onNoteDown: (note: PianoKey) => void;
|
||||
@@ -21,71 +27,74 @@ type VirtualPianoProps = Parameters<typeof Row>[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> = [
|
||||
Note.C,
|
||||
Note.D,
|
||||
Note.E,
|
||||
Note.F,
|
||||
Note.G,
|
||||
Note.A,
|
||||
Note.B,
|
||||
];
|
||||
const octaveList = [];
|
||||
const notesList: Array<Note> = [
|
||||
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 (
|
||||
<Row>
|
||||
{octaveList.map((octaveNum) => {
|
||||
return (
|
||||
<Octave
|
||||
width={"350px"}
|
||||
height={"200px"}
|
||||
key={octaveNum}
|
||||
number={octaveNum}
|
||||
showNoteNames={showNoteNames}
|
||||
showOctaveNumber={showOctaveNumbers}
|
||||
startNote={octaveNum == startOctave ? startNote : notesList[0]}
|
||||
endNote={octaveNum == endOctave ? endNote : notesList[notesList.length - 1]}
|
||||
onNoteDown={onNoteDown}
|
||||
onNoteUp={onNoteUp}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Row>
|
||||
{octaveList.map((octaveNum) => {
|
||||
return (
|
||||
<Octave
|
||||
width={"350px"}
|
||||
height={"200px"}
|
||||
key={octaveNum}
|
||||
number={octaveNum}
|
||||
showNoteNames={showNoteNames}
|
||||
showOctaveNumber={showOctaveNumbers}
|
||||
highlightedNotes={highlightedNotes}
|
||||
startNote={octaveNum == startOctave ? startNote : notesList[0]}
|
||||
endNote={
|
||||
octaveNum == endOctave ? endNote : notesList[notesList.length - 1]
|
||||
}
|
||||
onNoteDown={onNoteDown}
|
||||
onNoteUp={onNoteUp}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
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",
|
||||
|
||||
@@ -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<PianoKey> = [
|
||||
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),
|
||||
];
|
||||
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),
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user