git.s-ol.nu isomorphic-kb-explorer / f3818e1
more things? s-ol 2 years ago
1 changed file(s) with 69 addition(s) and 36 deletion(s). Raw diff Collapse all Expand all
11 import css from './css';
22
33 const statbyte = (stat, chan) => (stat << 4) | chan;
4 const noteon = (key, vel=127, chan=0) => [statbyte(0b1001, chan), key, vel];
5 const noteoff = (key, vel=127, chan=0) => [statbyte(0b1000, chan), key, vel];
6 const ccchange = (ctl, val, chan=0) => [statbyte(0b1011, chan), ctl, val];
4 const NOTE_ON = 0b1001;
5 const NOTE_OFF = 0b1000;
6 const CCHANGE = 0b1011;
7
8 /*
9 const noteon = (key, vel=127, chan=0) => [statbyte(0b1001, chan), key, vel];
10 const noteoff = (key, vel=127, chan=0) => [statbyte(0b1000, chan), key, vel];
11 const ccchange = (ctl, val, chan=0) => [statbyte(0b1011, chan), ctl, val];
12 */
713
814 const clamp = (val, min=0, max=1) => Math.max(min, Math.min(val, max));
915 const ramp = i => new Array(i).fill(true).map((_, i) => i);
1016 const mix = (i, a, b) => i * a + (1-i) * b;
11
12 window.ccchange = ccchange;
13 window.noteon = noteon;
1417
1518 const parse = message => ({
1619 cmd: message.data[0] >> 4,
3538 font-family: sans-serif;
3639 }
3740
38 .app {
41 .app, .keyboard {
3942 position: relative;
4043 }
4144
7073 }
7174 `);
7275
73 const Hexagon = ({ x, y, children, state }) => {
76 const Hexagon = ({ x, y, children, state, note, send }) => {
7477 if (rowStaggered) {
7578 if (y % 2 == 0)
7679 x += 0.5;
8992 >
9093 <div
9194 className="inner"
92 onClick={() => console.info(x,y)}
95 onMouseDown={() => send(NOTE_ON, note)}
96 onMouseUp ={() => send(NOTE_OFF, note)}
9397 >
9498 {children}
9599 </div>
99103
100104
101105 const range = i => new Array(i).fill(true);
106 class Keyboard extends React.Component {
107 state = {};
108
109 onmessage = (message) => {
110 switch (message.cmd) {
111 case NOTE_ON:
112 this.setState(old => ({ ...old, [message.note]: true }));
113 break;
114
115 case NOTE_OFF:
116 this.setState(old => ({ ...old, [message.note]: false }));
117 break;
118 }
119 }
120
121 render() {
122 const { w, h, send } = this.props;
123
124 return (
125 <div className="keyboard">
126 {range(w).map((_, x) => (
127 range(h).map((_, y) => {
128 let note = 36 + 2 * x + 6 * (h - y);
129 if (y % 2 == 0) note += 1;
130 return (
131 <Hexagon
132 key={x + ',' + y}
133 x={x} y={y}
134 note={note}
135 state={this.state[note]}
136 send={send}
137 >
138 {note}
139 </Hexagon>
140 );
141 })
142 ))}
143 </div>
144 );
145 }
146 }
102147
103148 export default class App extends React.Component {
104 state = {};
149 keyboardRef = React.createRef();
105150
106151 componentDidUpdate(prevProps) {
107152 if (prevProps.midiin)
114159 onmessage = (e) => {
115160 const message = parse(e);
116161
162 if (this.keyboardRef.current)
163 this.keyboardRef.current.onmessage(message);
164
117165 switch (message.cmd) {
118 case 9:
119 // NOTE_ON
120 this.setState(old => ({ ...old, [message.note]: true }));
121 break;
122
123 case 8:
124 // NOTE_OFF
125 this.setState(old => ({ ...old, [message.note]: false }));
126 break;
127
128 case 11:
129 // CC
166 case NOTE_ON:
167 console.info(message.note);
130168 break;
131169 }
132170 }
133171
172 send = (command, note) => {
173 if (!this.props.midiout)
174 return;
175
176 const msg = [statbyte(command, 0), note, 127];
177 this.props.midiout.send(msg);
178 }
179
134180 render() {
135 const xs = 10;
136 const ys = 4;
137
138181 return (
139182 <div className="app">
140 {range(xs).map((_, x) => (
141 range(ys).map((_, y) => {
142 let note = 36 + 2 * x + 6 * (ys - y);
143 if (y % 2 == 0) note += 1;
144 return (
145 <Hexagon key={x + ',' + y} x={x} y={y} note={note} state={this.state[note]}>
146 {note}
147 </Hexagon>
148 );
149 })
150 ))}
183 <Keyboard ref={this.keyboardRef} w={10} h={4} send={this.send} />
151184 </div>
152185 );
153186 }