|
| 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 | +} |
0 commit comments