Skip to content

Commit 19ffd09

Browse files
author
Matt Shirley
committed
🎉 Initial commit
1 parent 78e9486 commit 19ffd09

File tree

15 files changed

+220
-35
lines changed

15 files changed

+220
-35
lines changed

.prettierrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"singleQuote": true,
33
"jsxSingleQuote": true,
4-
"semi": false,
4+
"semi": true,
55
"tabWidth": 2,
66
"bracketSpacing": true,
77
"jsxBracketSameLine": false,

.travis.yml

Lines changed: 0 additions & 4 deletions
This file was deleted.

README.md

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,26 @@
11
# react-midi-hook
2-
3-
> Made with create-react-library
4-
5-
[![NPM](https://img.shields.io/npm/v/react-midi-hook.svg)](https://www.npmjs.com/package/react-midi-hook) [![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
2+
Hook to communicate with MIDI devices using MIDIAccess.
63

74
## Install
85

96
```bash
10-
npm install --save react-midi-hook
7+
yarn add --save react-midi-hook
118
```
129

1310
## Usage
1411

1512
```jsx
1613
import React, { Component } from 'react'
14+
import useMidi from 'react-midi-hook'
15+
16+
export default function App() {}
17+
const { inputs, activeKeys, listenToInputs } = useMidi();
1718

18-
import MyComponent from 'react-midi-hook'
19-
import 'react-midi-hook/dist/index.css'
19+
if (inputs) listenToInputs();
2020

21-
class Example extends Component {
22-
render() {
23-
return <MyComponent />
24-
}
21+
return (
22+
<p>{activeKeys[0].letter}</p>
23+
);
2524
}
2625
```
2726

example/src/App.js

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,29 @@
11
import React from 'react'
2-
3-
import { ExampleComponent } from 'react-midi-hook'
4-
import 'react-midi-hook/dist/index.css'
2+
import useMidi from 'react-midi-hook'
3+
import './index.css';
54

65
const App = () => {
7-
return <ExampleComponent text="Create React Library Example 😄" />
6+
const { inputs, activeKeys, listenToInputs } = useMidi();
7+
8+
if (!inputs) {
9+
return <p>There are no detected devices.</p>
10+
} else {
11+
listenToInputs();
12+
}
13+
14+
const keysToRender = activeKeys.map((key, index) => {
15+
const keyNote = key.letter + key.octave;
16+
17+
if (index === activeKeys.length - 1) {
18+
return (<h1 key={keyNote}>{keyNote}</h1>)
19+
}
20+
21+
return (<h2 key={keyNote}>{keyNote}</h2>)
22+
});
23+
24+
const instructions = <p>Press a key on your keyboard</p>
25+
26+
return <div className="main">{keysToRender.length ? keysToRender : instructions}</div>
827
}
928

1029
export default App

example/src/index.css

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,23 @@ code {
1212
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
1313
monospace;
1414
}
15+
16+
h1 {
17+
font-size: 12rem;
18+
padding-left: 1rem;
19+
padding-right: 1rem;
20+
}
21+
22+
h2 {
23+
font-size: 10rem;
24+
padding-left: 1rem;
25+
padding-right: 1rem;
26+
}
27+
28+
.main {
29+
display: flex;
30+
flex-direction: row;
31+
justify-content: center;
32+
align-items: center;
33+
height: 100vh;
34+
}

src/constants/commands.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
export const NOTE_OFF = 'NOTE_OFF';
2+
export const NOTE_ON = 'NOTE_ON';
3+
export const POLY_KEY_PRESSURE = 'POLY_KEY_PRESSURE';
4+
export const CONTROL_CHANGE = 'CONTROL_CHANGE';
5+
export const PROGRAM_CHANGE = 'PROGRAM_CHANGE';
6+
export const MONO_KEY_PRESSURE = 'MONO_KEY_PRESSURE';
7+
export const PITCH_BEND = 'PITCH_BEND';
8+
export const SYSTEM = 'SYSTEM';
9+
10+
export default {
11+
NOTE_OFF,
12+
NOTE_ON,
13+
POLY_KEY_PRESSURE,
14+
CONTROL_CHANGE,
15+
PROGRAM_CHANGE,
16+
MONO_KEY_PRESSURE,
17+
PITCH_BEND,
18+
SYSTEM
19+
};

src/constants/notes.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export const NOTES = [
2+
'A',
3+
'A#',
4+
'B',
5+
'C',
6+
'C#',
7+
'D',
8+
'D#',
9+
'E',
10+
'F',
11+
'F#',
12+
'G',
13+
'G#'
14+
];
15+
16+
export default NOTES;
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import COMMANDS from '../../constants/commands';
2+
3+
import { useCallback, useState } from 'react';
4+
import { getNoteLetter, getMIDICommand } from '../../utils/conversions';
5+
6+
export default function useHandleOnMessage(inputs) {
7+
const [activeKeys, setActiveKeys] = useState([]);
8+
9+
const noteOn = useCallback(
10+
({ position, velocity }) => {
11+
const octave = parseInt(position / 12 + 1, 10);
12+
const letter = getNoteLetter(position % 12);
13+
14+
return setActiveKeys((keysStillPressed) => [
15+
...keysStillPressed,
16+
{ position, octave, letter, velocity }
17+
]);
18+
},
19+
[setActiveKeys]
20+
);
21+
22+
const noteOff = useCallback(
23+
({ position }) => {
24+
return setActiveKeys((keysStillPressed) => [
25+
...keysStillPressed.filter((key) => key.position !== position)
26+
]);
27+
},
28+
[setActiveKeys]
29+
);
30+
31+
const onMidiMessage = useCallback(
32+
(event) => {
33+
const [command, note, velocity] = event.data;
34+
35+
const position = note - 21;
36+
const type = getMIDICommand(command);
37+
38+
if (type === COMMANDS.NOTE_ON) return noteOn({ position, velocity });
39+
if (type === COMMANDS.NOTE_OFF) return noteOff({ position });
40+
},
41+
[noteOn, noteOff]
42+
);
43+
44+
const listenToInputs = useCallback(() => {
45+
if (!inputs) throw new Error('Caught.NoInput');
46+
47+
for (
48+
let input = inputs.next();
49+
input && !input.done;
50+
input = inputs.next()
51+
) {
52+
input.value.onmidimessage = onMidiMessage;
53+
}
54+
}, [inputs, onMidiMessage]);
55+
56+
return { listenToInputs, activeKeys };
57+
}

src/hooks/useInputs/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from './useInputs'

src/hooks/useInputs/useInputs.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { useEffect, useState } from 'react'
2+
3+
export default function useInputs() {
4+
const [inputs, setInputs] = useState(null)
5+
6+
useEffect(() => {
7+
navigator.requestMIDIAccess({ sysex: true }).then(
8+
(event) => setInputs(event.inputs.values()),
9+
(event) => console.warn('error')
10+
)
11+
}, [setInputs])
12+
13+
return inputs
14+
}

0 commit comments

Comments
 (0)