Controlling Lights Via MIDI

First time posting here, first Arduino project. :slight_smile: I am trying to decipher the MIDI Library from the Playground, but the documentation is… well, there isn’t any real documentation, just function refs. I’ve searched the forum for answers but haven’t been able to come up with anything helpful yet, so I’d appreciate some help coding this project:

INTENDED OUTCOME

  • MIDI keyboard sends a CC or Note On message to Arduino
  • Arduino controls an LED based on specific MIDI message (i.e. “CC 25, value 127, channel 15” would tell the Arduino to blink the LED 3 times)

EQUIPMENT USED

  • Arduino UNO R3
  • MIDI Library v3.2 compiled on device
  • Sparkfun MIDI Shield
  • Any MIDI keyboard (M-Audio Oxygen8 II in this case)
  • Standard MIDI cable from keyboard MIDI Out to shield MIDI In
  • LED on Pin 6

WHAT I CAN ALREADY DO
Using one of the MIDI Library’s built-in example sketches, I’ve been able to make the LED blink upon ANY NoteOn message. Unfortunately, I can’t figure out how to discern a specific note on a specific channel so I can turn that into an if loop. I would prefer to use CC messages so I can control lighting via buttons or pedals.

I can already control the LED via push-button wired to the Arduino, I just need to know how to listen for specific MIDI messages and use those as virtual push-buttons.

WHAT I NEED
To replace a single line in the code below (case NoteOn:) with something that will detect specific values for CC 25 on Channel 15.

Once I can get this script reacting to specific values on a single CC message, I can tell the effect lighting to do whatever I want at that point.

CODE I HAVE SO FAR
Based on Franky’s MIDI_Input example script that comes with the Library.

#include <MIDI.h>        // Compile the MIDI Library

const int LED = 6;   		// LED pin on Sparkfun Shield

void BlinkLed(byte num) { 	// Basic blink function
  for (byte i=0;i<num;i++) {
    digitalWrite(LED,HIGH);
    delay(20);
    digitalWrite(LED,LOW);
  }
}


void setup() {
  pinMode(LED, OUTPUT);
  MIDI.begin();            	// Launch MIDI with default options
				// (input channel is default set to 1)
}

void loop() {
  if (MIDI.read()) {                    // Is there a MIDI message incoming ?
    switch(MIDI.getType()) {		// Get the type of the message we caught

      case NoteOn:                        // If it's ANY NoteOn message.
                                                // THIS IS THE PART I NEED TO REPLACE
                                                // WITH SOMETHING USEFUL!

	BlinkLed(1);	                // Blink the LED once 

        break;
      default:
        break;
    }
  }
}

Any help you can offer would be greatly appreciated! Comments like “just use a physical push-button” or “read the reference files” will be ignored and/or reported… believe me, I’ve already read the reference files and can’t decipher much of it. Thanks for your help!

with getType you get the type of message, if its a CC, PC, Note, etc. If you know a bit of the theory of MIDI, the NoteOn is a 3byte message. The first byte is the type of message, status. And channel. So in your code:

  switch(MIDI.getType()) {     // Get the type of the message we caught

      case NoteOn:

it'll do anything inside the switch when a noteon byte arrives. The 2nd byte is the note value, and the third, the velocity. In the reference you have: kMIDIType getType () const Get the last received message's type. byte getChannel () const Get the channel of the message stored in the structure. byte getData1 () const Get the first data byte of the last received message. byte getData2 () const with these functions you can do lot of different things with just a noteon message. For example, to your switch case, inside case NoteOn, you could put an condition to blink led1 with note 40 and led2 with note 50. You have to use getData1(); for example

if(MIDI.getData1() == 40){
//led on}
if you want to shut off the led
if(MIDI.getData1() == 40 && MIDI.getData2() == 0){
//led off}

getData2() is velocity, noteoff is a noteon with 0 velocity(sometimes it depends on the synthesizer...) instead of using getData2() == 0 you can use getType == NoteOff too...

I didn't read you wanted to do it with a CC well... inside the switch case, instead of using case NoteOn you use case ControlChange

if (MIDI.read()) {                    // Is there a MIDI message incoming ?
    switch(MIDI.getType()) {      // Get the type of the message we caught

      case ControlChange:                        // If it's ANY NoteOn message.
                                                // THIS IS THE PART I NEED TO REPLACE
          if(getChannel() == 15 && getData1() == 25){                                      // WITH SOMETHING USEFUL!

                        // Blink the LED once 
}
        break;
      default:
        break;
    }
  }

that's not tested, but you get the idea. getData2() on a controlchange message will give you the value 0-127, you could use that for ie, to vary the PWM and change the intensity of the led depending on the value of CC. The reference is a bit hard to read at first, maybe they should put more examples...

Thanks, Capicoso! Example code goes a LONG way toward understanding this stuff better.

You know, I may actually want to use note messages after all... the more I think about it, the more versatile that could be for light triggering. The note number could determine which color or pattern is being triggered, the velocity could be the intensity of the light itself. This will take some experimenting!

I'll mess around with this more tonight... if it works, I'll get a video posted. :)

No problem. If you use NoteOn messages remember that you'll need also NoteOff messages to shut off the LEDs, if you just use NoteOn the led will never go off. Also, if your program sends MIDI Clock you could do something with that too

So, so many thanks to Capicoso for some help here. I now have a functioning controller!

The very, very basic script is as follows:

#include <MIDI.h>

const int LEDInput = 6;              // LED that signals incoming MIDI CC data
const int LEDTester = 7;             // LED that's being manipulated by MIDI CC data
int BlinkRate = 227;                 // Speed in ms at which LEDTester will blink

void BlinkLed(byte num) { 	     // Basic blink function by Franky,
  for (byte i=0;i<num;i++) {         // modified by Matthew Ebel
    digitalWrite(LEDTester,LOW);
    delay(BlinkRate);
    digitalWrite(LEDTester,HIGH);
    delay(BlinkRate);
  }
}


void setup() {
  pinMode(LEDInput, OUTPUT);
  pinMode(LEDTester, OUTPUT);
  digitalWrite(LEDInput,HIGH);      // Sparkfun LED's are, for some reason,
  digitalWrite(LEDTester,HIGH);     // wired backwards: HIGH = Off.
  
  BlinkLed(3);                      // Just to let us know it's running
  
  MIDI.begin();            	// Launch MIDI with default options
				// (input channel is default set to 1)
}

void loop() {
  if (MIDI.read()) {                    // Is there a MIDI message incoming ?
    digitalWrite(LEDInput,LOW);         // Light up whenever there's any data.
    switch(MIDI.getType()) {		// Get the type of the message we caught
      case ControlChange:               // Is it CC data, note data or other data?
      
        if(MIDI.getChannel() == 1 && MIDI.getData1() == 20) {
        // MIDI CC 20, Channel 1
      
	  BlinkLed(MIDI.getData2());
          // Blink LEDTester as many times as the incoming CC value
          break;
        
        } else if(MIDI.getChannel() == 1 && MIDI.getData1() == 21) {
        // MIDI CC 21, Channel 1
        
          BlinkRate = 400 - (MIDI.getData2() * 3);
          // Multiply the value by 3 (giving a range of 0-381),
          // then subtract that from 400 (an arbitrary number I
          // picked to give a final blink delay range of 19-400 ms)
          
        }
        
        delay(2);                        // Let LEDInput stay on a short time...
        
      default:
        digitalWrite(LEDInput,HIGH);     // ...then turn LEDInput off when all's clear.

        break;
    }
  }
}

…and what it does:

  • I have three foot pedals set to give three different values on MIDI CC 20
  • My Modulation wheel gives values of 0-127 on MIDI CC 21
  • When I step on one of the pedals, the red LED blinks according to the value of that pedal, and at a speed according to the modulation wheel.

Now that this basic framework is set up, I can spend time working on awesome lighting cues that can be triggered by song cues, button presses, pedal presses, even note velocity or tempo changes. I’ll post some examples as this system grows. Thanks so much!

Screen Shot 2013-09-23 at 11.32.27 PM.png

1 Like