2

I have a an Arduino Uno doing PWM on an RGB analog LED strip ala the Adafruit guide: https://learn.adafruit.com/rgb-led-strips?view=all. I've written a sketch that accepts MIDI data over USB and uses it to control the LEDs.

#include <MIDI.h>
#include <midi_Defs.h>
#include <midi_Message.h>
#include <midi_Namespace.h>
#include <midi_Settings.h>

#include <MIDI.h>

MIDI_CREATE_DEFAULT_INSTANCE();

#define REDPIN 5
#define GREENPIN 6
#define BLUEPIN 3

byte commandByte;
byte noteByte;
byte velocityByte;

byte noteOn = 144;
byte noteOff = 128;

int colorGroup;
int pColor;
int sColor;

void setup()
{
    pinMode(REDPIN, OUTPUT);
    pinMode(GREENPIN, OUTPUT);
    pinMode(BLUEPIN, OUTPUT);
    MIDI.begin(1);
    Serial.begin(115200);
}

void checkMIDI(){
  do{
    if (Serial.available()){
      commandByte = Serial.read();//read first byte
      noteByte = Serial.read();//read next byte
      velocityByte = Serial.read();//read final byte       
      }
    }
  while (Serial.available() > 2);//when at least three bytes available
}

void updateLights(){
  colorGroup = noteByte/42;
  pColor = noteByte%41*127/41;
  sColor = 127 - pColor;
  pColor = pColor*velocityByte/127;
  sColor = sColor*velocityByte/127;
  if (commandByte == noteOn && velocityByte > 0){
    if (colorGroup == 1){
      analogWrite(REDPIN, pColor);
      analogWrite(GREENPIN, sColor);
      analogWrite(BLUEPIN, 0);
    }
    else if(colorGroup == 1){
      analogWrite(GREENPIN, pColor);
      analogWrite(BLUEPIN, sColor);
      analogWrite(REDPIN, 0);
    }
    else{
      analogWrite(BLUEPIN, pColor);
      analogWrite(REDPIN, sColor);
      analogWrite(GREENPIN, 0);
    }
  }
  else if(commandByte == noteOff || velocityByte == 0){
    analogWrite(REDPIN, 0);
    analogWrite(GREENPIN, 0);
    analogWrite(BLUEPIN, 0);
  }
}

void loop()
{
    checkMIDI();
    updateLights();
}

Currently this code will turn the lights on and off in accordance with noteOn and noteOff messages. However, the color doesn't seem responsive to the note value and the brightness doesn't seem responsive to the velocity value. I suspect that the problem has to do with my arithmetic combined with the data type (maybe a problem with the order of operations), but I haven't been successful in debugging this.

The idea behind the RGB control is that I take the possible note values (0–127) and map it onto three different combinations of colors: R+G, G+B, and B+R. That's three groups of 42 values: 0-41, 42-84, and 85-127. Then I rescale the 42 values onto 0-127 for the intensity values of the LEDs. Finally I scale the intensity of all the colors by the velocity value over its possible max value.

1

I suggest that you write separate test programs for MIDI input and LED control, before trying to combine them together. That is, write a sketch to report back on Serial what MIDI data was read, and a sketch to cycle the LEDs through obvious patterns.

For example, if you read 10,20,30 as the three MIDI bytes, output "Got 10,20,30" (or similar). If that appears to be working, then add your arithmetic and output the results of colorGroup, pColor, and sColor calculations.

Note, the comment after do{ ...} while (Serial.available() > 2); says //when at least three bytes available, which does not correctly represent what that do loop does. When one or more bytes are available, that loop immediately reads three bytes (getting a value of -1 for any not-available byte). To do the read only if three bytes are available, get rid of the do{ ...} while construct, and instead say if (Serial.available() > 2) { <read 3 bytes> }.

Note, use parentheses in expressions like pColor*velocityByte/127. IIRC the C spec allows evaluation of that as either (pColor*velocityByte)/127 or as pColor*(velocityByte/127). Since velocityByte/127 can only evaluate to 0 or 1, the result of the latter form is either pColor or 0.

Note, your code shows if (colorGroup == 1){ twice. Change 1 to some other number in the second instance.

To cycle the LEDs through obvious patterns, you could have three different sketches, one that gradually raises and lowers the PWM level on Red, one that does the same for Green, and another for Blue.

  • Thanks. I haven't tried these suggestions yet, but I'm fairly certain a combination of the errors you pointed out is the source of problems, and also I was unaware that you could print with the Arduino back to the computer over USB. That will be very helpful for debugging (which I'll do w/ the functions separate/piecemeal as you suggested). – Dylan B May 31 '16 at 18:09
  • Okay – slight problem. Because I am sending MIDI over the USB, I think the serial monitor is not working properly, or is interfering with the incoming MIDI data. I was able to use the serial monitor to check that the arithmetic is working properly, but when I use it to simply print the incoming MIDI data bytes, it will print different sorts of nonsense (e.g. it will print "144" [noteOn] as "14" and then it will pause and print another "4"). I'm unsure how to use the serial monitor concurrently with a MIDI to serial converter. – Dylan B Jun 1 '16 at 18:58
  • 2
    I figured out a solution. Hairless has a debug window that interprets MIDI data outgoing and incoming. If I use Serial.write (rather than print) then Hairless will show both the outgoing MIDI and the MIDI that's echoed back from the Arduino! – Dylan B Jun 1 '16 at 20:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.