removed accidental as it's own type and integrated it with note type

This commit is contained in:
Clément Le Bihan
2023-03-20 00:40:01 +01:00
parent c3d2e0a4e5
commit 885c819ab5
4 changed files with 190 additions and 135 deletions

View File

@@ -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 =

View File

@@ -6,8 +6,6 @@ import {
PianoKey,
NoteNameBehavior,
octaveKeys,
Accidental,
HighlightedKey,
keyToStr,
} from "../../models/Piano";

View File

@@ -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",

View File

@@ -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),
];