Giter VIP home page Giter VIP logo

react-midi-hooks's Introduction

@react-midi/hooks

This package provides hooks for building MIDI-capable React applications and components.

npm install --save @react-midi/hooks

<MIDIProvider>

The MIDIProvider component serves as the cornerstone of our MIDI integration, enabling seamless interaction with MIDI devices directly within your React application. By leveraging the Web MIDI API, MIDIProvider offers a comprehensive solution for managing MIDI connections, inputs, outputs, and real-time MIDI events, all within a reactively designed context.

MIDIProvider is a prerequisite for utilizing any of the other MIDI-related hooks within our library, as they depend on the context it establishes to function correctly.

Getting Started:

To begin working with @react-midi/hooks, wrap your component tree with MIDIProvider:

import { MIDIProvider } from '@react-midi/hooks'

function App() {
  return (
    <MIDIProvider>
      <YourMIDIEnabledComponent />
    </MIDIProvider>
  )
}

useMIDIInputs():

The useMIDIInputs hook is designed to simplify the process of accessing and managing MIDI input devices. It provides an interface for obtaining the list of available MIDI inputs, identifying the currently selected input device, and selecting an input device by its ID.

const { input, inputs, selectInput, selectedInputId } = useMIDIInputs()

// Example: Select a MIDI input by ID
selectInput('desired-input-device-id')

useMIDIOutputs():

The useMIDIOutputs hook is almost the exact same as useMIDIInputs, but handles MIDI outputs instead. It provides an interface for obtaining the list of available MIDI outputs, identifying the currently selected output device, and selecting an output device by its ID.

const { output, outputs, selectOutput, selectedOutputId } = useMIDIOutputs()

// Example: Select a MIDI output by ID
selectInput('desired-output-device-id')

useMIDIOutput():

The useMIDIOutput hook provides methods to send MIDI messages (note on, note off, and control change) to the selected MIDI output. It simplifies the process of sending MIDI messages by abstracting the details of constructing MIDI message arrays.

// To use this hook in a component to send a 'note on' and 'note off' message
const { noteOn, noteOff, cc } = useMIDIOutput()
noteOn(60, { velocity: 127, channel: 1 }) // Send 'note on' for note 60 with velocity 127 on channel 1
noteOff(60, { channel: 1 }) // Send 'note off' for note 60 on channel 1
cc(64, 127, 1) // Send control change message with control number 64, value 127, on channel 1

useMIDINote():

The useMIDINote hook allows you to listen for MIDI note messages and updates its state with the message details if the message matches the specified note and channel filters. If no filters are provided, it will update the state with every note message received.

// To use this hook to listen for note C3 (MIDI note number 60) on channel 1
const midiNote = useMIDINote({ note: 60, channel: 1 })
if (midiNote) {
  console.log(
    `Note ${midiNote.note} with velocity ${midiNote.velocity} received on channel ${midiNote.channel}`
  )
}

useMIDINotes():

The useMIDINotes hook subscribes to MIDI note messages that satisfy specified filtering criteria (such as note number and channel). It maintains an array of active (i.e., currently pressed) MIDI notes. When a note-on message is received, the note is added to the array. When a note-off message for an active note is received, that note is removed from the array. This allows for tracking of currently active MIDI notes that match the filter.

// To use this hook to monitor active notes for MIDI channel 1
const activeNotes = useMIDINotes({ channel: 1 })
// activeNotes will be an array of objects, each representing an active MIDI note on channel 1.

useMIDIControl():

The useMIDIControl hook listens for MIDI control change (CC) messages and updates its state with the details of the message if it matches the specified control number and channel filters. If no filters are provided, it will update the state with every control change message received. This can be useful for components that need to react to specific control change messages.

// To use this hook to listen for control change number 7 on channel 1
const midiControl = useMIDIControl({ cc: 7, channel: 1 })
if (midiControl) {
  console.log(
    `Control change ${midiControl.control} with value ${midiControl.value} received on channel ${midiControl.channel}`
  )
}

useMIDIControls():

The useMIDIControls hook listens for MIDI control change messages that match a provided filter, and maintains an array of values corresponding to a predefined set of control numbers (controls). Each control's value in the array is updated when a matching control change message is received. This is useful for components that need to keep track of and react to changes in multiple MIDI control values simultaneously.

// To use this hook to monitor control changes for MIDI controls 7 and 10 on channel 1
const controlValues = useMIDIControls([7, 10], { channel: 1 })
// controlValues will be an array of two numbers, initially [0, 0], updated with the latest values for controls 7 and 10.

useMIDIMessage():

The useMIDIMessage hook listens for any MIDI messages and updates its state with the latest message received. It is useful for components that need to react to or display information based on incoming MIDI messages.

// To use this hook in a component to display the latest MIDI message
const midiMessage = useMIDIMessage()
if (midiMessage) {
  console.log(`MIDI message received:`, midiMessage)
}

react-midi-hooks's People

Contributors

nicorobo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

react-midi-hooks's Issues

Possible to grab velocity in the `useMIDINotes` hook?

Hi Nick,

It seems as if it is not possible to grab the velocity of the midi notes being played using the useMIDINotes hook, but it IS possible using the useMIDINote hook...is it possible to do with the useMIDINotes hook?

Status of this library?

Curious what the status and/or commitment to this library is...would like to learn how to use it, but hope that it will be maintained into the future...

Having trouble making this work...

Trying to set this up in a Gatsby app and having trouble, getting this error message in the console:

Screen Shot 2020-06-08 at 1 21 34 PM

not sure if this is what is stopping your hooks from working for me...trying to make it work in Chrome 83...

I am trying to use it in a Gatsby JS / Netlify Web App, with the following code in the layout component, first as it's own component, then inside the main layout component:

const MIDINoteLog = ({ input }) => {
  const event = useMIDINote(input, { channel: 1 }) // Intially returns {}
  const { on, note, velocity, channel } = event
  return (
    <p>
      Note {note} {on ? 'on' : 'off'} ({velocity}) on channel {channel}
    </p>
  )
}
const Layout = ({ children, location }) => {

  const [inputs, outputs] = useMIDI(); // Initially returns [[], []]
  console.log(inputs)

  return (
    <>
      // other stuff...
      <MIDIInfo/>
      // other stuff...
  )
}

...but when i play my midi keyboard, no midi info pops up in my <MIDIInfo> component.

When I go to other websites, like this one, in chrome:

https://www.onlinemusictools.com/kb/

...my MIDI keyboard works just fine.

So, I don't know what I should do or how I should approach this next...dunno if there is an issue with the library, or with my code, as I really don't understand it well enough yet.

Thank you for your time and help NIck!

How do I access individual midi notes inside of the `useMIDINotes` hook...

Hi Nick,

I'm trying to make a piano that lights up individual (or multiple at the same time) notes as they are pressed on a MIDI keyboard. This is me trying to make a simple proof of concept but I cannot seem to figure out how to make it work. What I want is for each <div> to light up with a different background color when a specific midi note is pressed, but also have multiple <div>'s light up at the same time when multiple notes are pressed. Don't know how to do that, however. This is what I have so far, but it does not work. Have any idea how one might go about doing that? As a bonus I would also like the saturation of the note to be lighter or darker depending on the velocity of the note(s) as well. Burt on and off is the first goal. The approach below worked with the useMIDINote hook, but would only light up one note at a time, hence why I'm trying to do this with the useMIDINotes hook:

const MIDINotesLog = ({ input }) => {
  const notes = useMIDINotes(input, { channel: 1 })
  return (
    <div style={{display: `flex`, border: `1px solid black`}}>
      {
        notes.note === 60 ?
          <div style={{width: '2rem', height: '4rem', border: `1px solid black`, background: 'red'}}></div>
        :
          <div style={{width: '2rem', height: '4rem', border: `1px solid black`, background: 'white'}}></div>
      }
      {
        notes.note === 61 ?
          <div style={{width: '2rem', height: '4rem', border: `1px solid black`, background: 'red'}}></div>
        :
          <div style={{width: '2rem', height: '4rem', border: `1px solid black`, background: 'white'}}></div>
      }
      {
        notes.note === 62 ?
          <div style={{width: '2rem', height: '4rem', border: `1px solid black`, background: 'red'}}></div>
        :
          <div style={{width: '2rem', height: '4rem', border: `1px solid black`, background: 'white'}}></div>
      }
      </div>
  )
}

Check for window available before setting up midi access

I would like to start to say that this library is really good and very welcome. It helps me get stuff done with MIDI and React 16+ really fast.

However using it with nextjs a SSR framework for react I had issues with window is not defined errors. This could probably be easily fixed by a simple if(typeof window !== 'undefined check before doing anything.

Let me know your thoughts.

Running into an issue with GatsbyJS...

Recently ran npm update on a project and now midi doesn't seem to work anymore. Here is the error I'm getting:

Screen Shot 2020-10-07 at 12 59 24 PM

...no idea what's going on, but I thought you might have some idea what's happening and what I might be able to do about it...

Can I send MIDI info to two components at the same time?

Hi @nickroberts404! XD

I have a component that looks like this:

const Piano = (props) => {

  const { inputs } = useMIDI()

  return (
    <Container>
      <PianoUI>
        <MIDINotesInfo input={inputs[0]}/>
        <KeyboardBox>
          <PianoKeyboard
            octaves={[`0`,`1`, `2`, `3`, `4`, `5`, `6`]}
            notes={['']}
            input={inputs[0]}
          />
        </KeyboardBox>
      </PianoUI>
    </Container>
  )
}
export default Piano

...which contains a <PianoKeyboard>' component and a ' component, both using the useMIDINotes hook within themselves, and they both work individually if I turn one off by commenting it out, but if I try to send MIDI to both of them at the same time only the first component that is receiving an input is working. Is it possible to send the same MIDI data from the same channel to two or more useMIDINotes components in the same view/page?

They both work great individually, but only one seems to work at a time, not both...

It seems as if I can do this if I am not using the same hook twice in the same component. If I use useMIDINote and useMIDINotes together they do not seem to step on each others toes. But if I use useMIDINotes twice in tow different child components then that seems to be where the incompatibility lies. Not sure if that is ultimately the issue, but I can indeed have the two different hooks co-exist, but not the same hook twice, it would seem...

These two components work together if used in the same parent component. This one:

const MIDINoteInfo = (props) => {

  const event = useMIDINote(props.input, { channel: 1 })

  const { on, note, velocity, channel } = event

  return (
    <div>
      <p>Status: {on ? 'on' : 'off'}</p>
      <p>Note: {note}</p>
      <p>Velocity: {velocity}</p>
      <p>Channel: {channel}</p>
    </div>
  )
}

...and this one:

const MIDINotesInfo = (props) => {

  const info = useMIDINotes(props.input, { channel: 1 })

  const noteNums = info.map((event) => event.note).join(', ')
  const noteVelos = info.map((event) => event.velocity).join(', ')
  const noteOn = info.map((event) => event.on).join(', ')

  return (
    <MIDIInfo>
      <MIDILabel>MIDI</MIDILabel>
      <MIDIStatus
        style={noteOn ? {background: `#87ffc5`, boxShadow: `0px 0px 4px #87ffc5`} : {background: `black`} }
      />
      <MIDILabel>Name(s)</MIDILabel>
      <MIDIValue></MIDIValue>
      <MIDILabel>Number(s)</MIDILabel>
      <MIDIValue>{noteNums}</MIDIValue>
      <MIDILabel>Velocit(ies)</MIDILabel>
      <MIDIValue>{noteVelos}</MIDIValue>
      <MIDILabel>Harmony</MIDILabel>
      <MIDIValue></MIDIValue>
    </MIDIInfo>
  )
}

...but the previous one and this following one do not work together in the same parent component:

const Keyboard = (props) => {

  const notes = useMIDINotes(props.input, { channel: 1 })
  const noteNumbers = notes.map((event) => event.note).join(', ')

  // const Octaves = [...Array(parseInt(props.octaves, 10)).keys()]

  const Octaves = props.octaves

  return (

    <Container {...props}>

        {Octaves.map((octave) => {
          return (
            <>
              <Zone1Grid {...props}>
                <Zone1WhiteKeyGrid {...props}>
                  <C {...props} octave={octave} noteNumbers={noteNumbers}>
                    {
                      (
                        props.notes.includes(`b#${octave}dim`) ||

// ...and a whole lot more...this component is big...

I wonder if it's the case that the useMIDINotes hook needs to use the UniqueID thing that the useMIDINote hook uses...not sure how that would be added, though. Maybe two or more instances of the useMIDINotes hook are stepping on each other in the same parent component because of that ๐Ÿค”

note on midi messages with velocity == 0 should be treated as note off messages as per Web MIDI standards

Context

I ran into an issue when using this library, primarily when processing a lot of midi messages in a short time (read: going back and forth on all piano keys in my midi controller).

After implementing midi handling manually using plain old Javascript I noticed I ran int the same issue. After reading through the Web MIDI API documentation I noticed something interesting in their examples:

image

source: https://webaudio.github.io/web-midi-api/#a-simple-monophonic-sine-wave-midi-synthesizer

turns out we have to fall through when the velocity of a note is 0. This is currently missing in the useConnectInput hook from what I could see:

https://github.com/nickroberts404/react-midi-hooks/blob/master/src/use-connect-input.ts#L33L50

thought I'd bring it to your attention so you can fix it ๐Ÿ™‚

Don't initialize midi controls with 0

Hi,

First of all, thanks for making midi-interactions with your awesome hooks! Thanks for putting in the effort.

I have an interface controlled by a midi controller. The interface has a lot of sensible default values for the different encoders. These are all set to zero by the useMIDIControl hook. So in order to return the interface to a workable state I need to wiggle all midi-knobs whenever the app is loaded. That's tiresome.

Is there a reason to initialize with 0 even though the value is unknown at that point? Wouldn't undefined better match the state?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.