react-midi-controls
v1.0.2
Published
React hooks and components for MIDI controller integration
Maintainers
Readme
🎹 react-midi-controls
React hooks and components for MIDI controllers. Build responsive, interactive interfaces that connect directly to MIDI hardware with ease.
Features
- Unified MIDI Hook:
useSliderfor all absolute controls (sliders, knobs, faders) - Button Controls:
useButtonfor pads, switches, and buttons - Pre-built Components: Ready-to-use MIDI-responsive UI components
- TypeScript Support: Full type safety and IntelliSense
- Context-based: Efficient MIDI message handling across components
- CC-Only Focus: Simplified for Control Change messages only
- Real-time Debugging: Built-in MIDI message inspector
Quick Start
npm install react-midi-controlsBasic Usage
import {
MidiProvider,
SliderComponent,
KnobComponent,
ButtonComponent,
} from "react-midi-controls"
function App() {
return (
<MidiProvider>
<DeviceSelector />
<MidiControlPanel>
<SliderComponent ccNumber={7} label="Volume" range={[0, 100]} />
<KnobComponent ccNumber={74} label="Filter Cutoff" range={[0, 127]} />
<ButtonComponent ccNumber={64} label="Sustain Pedal" />
</MidiControlPanel>
</MidiProvider>
)
}Hooks
useSlider({ ccNumber, range, defaultValue })
Creates an absolute MIDI control that returns the mapped value directly.
const volume = useSlider({ ccNumber: 7, range: [0, 100] })
const cutoff = useSlider({
ccNumber: 74,
range: [20, 20000],
defaultValue: 1000,
})
// Returns: number (the mapped value)useButton({ ccNumber, defaultValue })
Creates a button/pad control that returns a boolean value directly.
const sustain = useButton({ ccNumber: 64 })
const mute = useButton({ ccNumber: 65, defaultValue: true })
// Returns: boolean (true when pressed, false when released)useDebugger(filter)
Debug MIDI messages with optional filtering.
const debugger = useDebugger({
type: 'controller'
})
// Returns: { messages, isRecording, clear, startRecording, stopRecording }Components
<SliderComponent>
A visual slider that responds to MIDI CC messages.
<SliderComponent
ccNumber={1} // MIDI CC number
label="Modulation" // Display label
range={[0, 100]} // Output range
/><KnobComponent>
A rotary knob for absolute controls (uses useSlider internally).
<KnobComponent ccNumber={74} label="Cutoff" range={[0, 127]} /><ButtonComponent>
A button that lights up when pressed.
<ButtonComponent ccNumber={64} label="Sustain" /><DebuggerComponent>
Real-time MIDI message inspector.
<DebuggerComponent
filter={{
type: "controller",
}}
/>Advanced Usage
Custom Hook Implementation
import { useMidiContext } from "react-midi-controls"
import { useEffect, useState } from "react"
function useCustomMidiControl(ccNumber) {
const [value, setValue] = useState(0)
const { addMessageHandler } = useMidiContext()
useEffect(() => {
const handleMessage = (event) => {
const message = parseMIDIMessage(event.data)
if (message.type === "controller" && message.ccNumber === ccNumber) {
setValue(message.value)
}
}
return addMessageHandler(handleMessage)
}, [ccNumber, addMessageHandler])
return value
}Configuration Options
Range Mapping
Map MIDI values (0-127) to any range:
// Bipolar control (-50 to +50)
<SliderComponent range={[-50, 50]} />
// Frequency range (20Hz to 20kHz)
<SliderComponent range={[20, 20000]} />
// Percentage (0% to 100%)
<SliderComponent range={[0, 100]} />Browser Support
- Chrome/Edge: ✅ Full support
- Firefox: ⚠️ Behind flag (
dom.webaudio.enabled) - Safari: ❌ Not supported
TypeScript
Full TypeScript support included:
import { useSlider } from "react-midi-controls"
// Example: Type-safe usage in a functional component
function VolumeControl() {
// TypeScript infers the correct types for value and setValue
const volume = useSlider({ ccNumber: 7, range: [0, 100] })
return <div>Volume: {volume}</div>
}License
MIT
Contributing
- Fork the repository at https://github.com/eeeurico/react-midi-controls
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
Built with ❤️ for the MIDI community by Eurico Sá Fernandes
