From 930c3a7c40e1b1e5fa834167d4fc79a067c322f4 Mon Sep 17 00:00:00 2001 From: s-ol Date: Mon, 20 Dec 2021 16:22:57 +0100 Subject: add chord display --- app/app.js | 189 +++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 114 insertions(+), 75 deletions(-) (limited to 'app/app.js') diff --git a/app/app.js b/app/app.js index 5fa04b4..172a908 100644 --- a/app/app.js +++ b/app/app.js @@ -1,6 +1,6 @@ import React from 'react'; -import { pos, height } from './style'; -import notes from './notes'; +import { pos, width, height } from './style'; +import * as notes from './notes'; const statbyte = (stat, chan) => (stat << 4) | chan; const NOTE_ON = 0b1001; @@ -78,61 +78,74 @@ const layouts = { const range = i => new Array(i).fill(true); -class Keyboard extends React.Component { - state = {}; +const Keyboard = ({ w, h, send, layout: { major, map }, showMidi, state }) => ( +
+ {range(w).map((_, x) => ( + range(h).map((_, y) => { + const note = map([x, y], [w, h]); + return ( + + {showMidi ? note : notes.music[note % 12]} + + ); + }) + ))} +
+); + +const ChordView = ({ chord }) => { + const min = chord[0]; - onmessage = (message) => { - switch (message.cmd) { - case NOTE_ON: - this.setState(old => ({ ...old, [message.note]: true })); - break; - - case NOTE_OFF: - this.setState(old => ({ ...old, [message.note]: false })); - break; - } - } - - render() { - const { w, h, send, layout, showMidi } = this.props; - const { major, map } = layouts[layout]; - - return ( -
- {range(w).map((_, x) => ( - range(h).map((_, y) => { - const note = map([x, y], [w, h]); - return ( - - {showMidi ? notes[note % 12] : note} - - ); - }) - ))} -
- ); - } -} + return ( +
+ {range(13).map((_,i) => ( +
+ ))} + {chord.map((n) => ( +
+ {(n - min) && (+{n - min})} +
+ ))} +
+ ); +}; export default class App extends React.Component { - keyboardRef = React.createRef(); - state = { layout: 'wicki_hayden', + notes: {}, }; + componentDidMount() { + document.addEventListener("keydown", this.onkeydown); + document.addEventListener("keyup", this.onkeyup); + } + + componentWillUnmount() { + document.removeEventListener("keydown", this.onkeydown); + document.removeEventListener("keyup", this.onkeyup); + } + componentDidUpdate(prevProps) { if (prevProps.midiin) prevProps.midiin.onmidimessage = null; @@ -142,41 +155,62 @@ export default class App extends React.Component { } blink = (note) => { - if (this.keyboardRef.current) { - const { current } = this.keyboardRef; - current.onmessage({ cmd: NOTE_ON, note }); - setTimeout(() => current.onmessage({ cmd: NOTE_OFF, note }), 250); - } + this.onmessage({ cmd: NOTE_ON, note }); + setTimeout(() => this.onmessage({ cmd: NOTE_OFF, note }), 250); + } + + send = (command, note) => { + if (!this.props.midiout) + return; + + const msg = [statbyte(command, 0), note, 127]; + this.props.midiout.send(msg); + } + + onlayout = (e) => { + this.setState({ layout: e.target.value }); } onmessage = (e) => { const message = parse(e); - if (this.keyboardRef.current) - this.keyboardRef.current.onmessage(message); - switch (message.cmd) { case NOTE_ON: console.info(message.note); break; } - } - send = (command, note) => { - if (!this.props.midiout) - return; + switch (message.cmd) { + case NOTE_ON: + this.setState(({ notes }) => ({ notes: { ...notes, [message.note]: true } })); + break; - const msg = [statbyte(command, 0), note, 127]; - this.props.midiout.send(msg); + case NOTE_OFF: + this.setState(({ notes }) => ({ notes: { ...notes, [message.note]: false } })); + break; + } } - onlayout = (e) => { - this.setState({ layout: e.target.value }); + onkeydown = (e) => { + const note = notes.key2midi[e.code]; + if (!note) return; + e.preventDefault(); + this.setState(({ notes }) => ({ notes: { ...notes, [note]: true } })); + } + + onkeyup = (e) => { + const note = notes.key2midi[e.code]; + if (!note) return; + e.preventDefault(); + this.setState(({ notes }) => ({ notes: { ...notes, [note]: false } })); } render() { const { configure, showMidi } = this.props; - const { layout } = this.state; + const { layout, notes } = this.state; + + const chord = Object.entries(notes).filter(([note, on]) => on).map(([k, _]) => k); + chord.sort(); return (
@@ -189,14 +223,19 @@ export default class App extends React.Component { - +
+ + +
); } -- cgit v1.2.3