How do I specify a channel for the USBMIDI protocol?

Status
Not open for further replies.

sargentpilcher

Well-known member
So I have a meter strip of DotStar LED's at 144 LED's per meter, and I'm lighting them up with MIDI messages. The problem I am currently facing is that MIDI maxes out at 128 numerical values, yet in my 144 LED strip since they are RGB's there are effectively 432 LED's. So my MIDI commands that I currently have only light up 1/4 of the entire strip.

I am trying to figure out how I can use MIDI Channel 1 to control 1/4 of the strip, MIDI Channel 2 to control the next 1/4 etc.

Currently the code goes like this:

Code:
void OnNoteOn(byte channel, byte note, byte velocity)
{

  {
    if (note == 0)
    {
      red0 = velocity*2;
    }
    if (note == 1)
    {
      green0 = velocity*2; 
    }
    if (note == 2)
    {
      blue0 = velocity*2;
    }
    strip2.setPixelColor(0, red0, green0, blue0);
  {
  {
    if (note == 3)
    {
      red1 = velocity*2;
    }
    if (note == 4)
    {
      green1 = velocity*2;
    }
    if (note == 5)
    {
      blue1 = velocity*2;
    }
    strip2.setPixelColor(1, red1, green1, blue1);

I tried 2 different things and neither worked. One of them was changing the header at the top to say "Channel 3" like

Code:
void OnNoteOn(byte channel3, byte note, byte velocity)

and the other thing I tried was including the channel variable in with the note variable, but it also did not work.

Code:
void OnNoteOn(byte channel, byte note, byte velocity)
{

  {
    if (Channel == 1, note == 0)
    {
      red0 = velocity*2;
    }
    if (Channel == 1, note == 1)
    {
      green0 = velocity*2; 
    }
    if (Channel == 1, note == 2)
    {
      blue0 = velocity*2;
    }
    strip2.setPixelColor(0, red0, green0, blue0);
  {
  {
    if (Channel == 2,  note == 3)
    {
      red1 = velocity*2;
    }
    if (Channel == 2,  note == 4)
    {
      green1 = velocity*2;
    }
    if (Channel == 2,  note == 5)
    {
      blue1 = velocity*2;
    }
    strip2.setPixelColor(1, red1, green1, blue1);

Any help pushing me in the right direction, or an article, or a relevant sketch would be so helpful! I haven't found any sketches that require the use of more than 1 channel of MIDI.

Thanks in advance for any help!
 
Last edited:
Your last code example is the right way. There is just a multiple typo which prevents it from working. When there is a NoteOn event incoming, its Channel# is passed to the variable channel, the Note# to note, and the Velocity# to velocity.

Thus, your code will naturally not work if you write: if(Channel==1... because the variable Channel with a uppercase C is not declared. Using if(channel==1... with a lowercase c should work. Variable names are case sensitive in C and in C++.

Second, if you want to handle more than one condition in an if() clause, a comma is not at all the correct operator. Since you want both conditions to be fulfilled at the same time, you have to logic AND these by writing if(channel==0 && note ==1)

Normally, the compiler should have issued an error or at least a warning pointing you towards these simple errors
 
Last edited:
Thank you so much! It works perfectly now! That solved it! And thank you for the syntax lesson :) I don't know how long it would have taken me to figure out the && thing.
 
As I said in your other thread I don't think this is the best approach for a massive light controller; but if you did want to set RGB values with MIDI in this way you would want to use arrays to get rid of the repeating code structures.


Code:
...
light = channel*42+note/3;
// rgb = note%3;
colorMatrix[light][note%3] = velocity;

...
strip2.setPixelColor(light,colorMatrix[light][0],colorMatrix[light][1],colorMatrix[light][2]);

The matrix would store the velocity reading by building a light number index based on the channel and note value.

The each channel can support 42 lights (n<=128/3) so the second channel (byte value = 1) with note=0 will be light 42 R value (43rd light with zero based index).

You have to integer divide by 3 as you have three notes per light. Modulo division of the note by 3 finds which color it's for.

If you made sure you always sent all three values for each light and in order you could make the light update conditional on it being the third color (note%3=2).

This is entirely untested but the logic should be something like this... but getting it to work might be a bit tricky... still it's better than declaring 2000+ variables separately and managing so many conditionals.
 
As I said in your other thread I don't think this is the best approach for a massive light controller; but if you did want to set RGB values with MIDI in this way you would want to use arrays to get rid of the repeating code structures.


Code:
...
light = channel*42+note/3;
// rgb = note%3;
colorMatrix[light][note%3] = velocity;

...
strip2.setPixelColor(light,colorMatrix[light][0],colorMatrix[light][1],colorMatrix[light][2]);

The matrix would store the velocity reading by building a light number index based on the channel and note value.

The each channel can support 42 lights (n<=128/3) so the second channel (byte value = 1) with note=0 will be light 42 R value (43rd light with zero based index).

You have to integer divide by 3 as you have three notes per light. Modulo division of the note by 3 finds which color it's for.

If you made sure you always sent all three values for each light and in order you could make the light update conditional on it being the third color (note%3=2).

This is entirely untested but the logic should be something like this... but getting it to work might be a bit tricky... still it's better than declaring 2000+ variables separately and managing so many conditionals.


Wow, did you just condense 2,500 lines of code down to 4? hahaha that's crazy. It took me rereading it like 10 times piece by piece before I really got what you were doing (And googling the modulo command) but it makes so much sense! That first line "light = channel*42+note/3;" eliminates soooooooo much junk code. Thank you so much for this! It may take me a little while to figure out how to implement it properly but this helps so much! Thank you so much for your help!!

Only question is what would it do with a decimal point? I see that's what's good about the % symbol. Like in that first line, what if the channel is 2, and the note is 1, making it 2*42+1= 85. Then dividing 85 by 3 gives 28.3. Would the % be better here? I noticed you used the % symbol everywhere except that first line. Is there a reason for that?
 
You have to integer divide by 3 as you have three notes per light...

Arduino is based on C and so is a strongly-typed language.

The light variable should be an integer of some type so there is no decimal part.

(Edit - 'light' needs to be whatever type the LED library function you are using requires)

Since it can't be negative you can use unsigned integer.

If you mix your types up the compiler will error... I have not compiled this or even worked out what else is needed...

I'm terrible at this so I'm all hit and miss until I work through the details
 
Last edited:
Well I think the logic is solid, but I'm having some difficulty implementing it. I keep getting things like "channel was not declared in this scope", "Note was not declared in this scope", "colorMatrix does not name a type".

I'm going to look into building an array for all the variables. I think it's a great idea to use the channel number*42+note approach, but I'm not sure how I could achieve the "0" value from it either which I believe I'll need to do because of needing to light up "LED 0" and hitting the MIDI note 0 as well.

You've at least pointed me in the right direction! I see how I could make this code far more efficient, but the implementation seems to be far more difficult than I had imagined.
 
******DELETED JUNK CODE********

This is my attempt to get something that compiles... but I don't have the LEDs to test it out and I have almost no LED library experience.

I just copied a minimal example and adjusted that... I'm not a C programmer so I'm not 100% sure about any of the data types and whether the data is being presented to the library routines in the form they expect.

Alternately you can use the .getType and .getData() functions in which case I believe this is your main loop:

Code:
void loop() {
  // put your main code here, to run repeatedly:
if (usbMIDI.read() && usbMIDI.getType()==0){
  channel = usbMIDI.getChannel();
  note =   usbMIDI.getData1();
  velocity = usbMIDI.getData2();
  light = channel*42+note/3;
  colorMatrix[light][note%3] = velocity;
}
strip2.setPixelColor(light,colorMatrix[light][0],colorMatrix[light][1],colorMatrix[light][2]);
}


I hope this helps.
 
Last edited:
It's absolutely wrong to declare the variables channel, note and velocity as global at the beginning of the sketch. These variables will conflict with those declared and initialized locally by the onNoteOn() function. You have to understand that it's the function (an event handler) which "lends" you the variables with new actual values each time that event occurs for further use within that function where they are locally available. If you can't handle everything within the function, and you'd need the last note, channel, and velocity values outside that event handler, you'd have to save these in global variables having different names to avoid conflicts, but that's bad practice.

I wonder why so many people dare "assembling" complex projects just by including libraries and copy-pasting code from here and there without making the effort to learn C/C++ systematically before. That's highly illogical.
 
Last edited:
Apologies.

I threw that together quickly and I had originally used the .getData1() method... when I tried to rewrite it for the 'standard' event handler method I made a mess of it... I think I my have been drinking :p

I posted a slightly better version in the thread below but it's still is based on incomplete understanding of the LED library and no hardware to test.
https://forum.pjrc.com/threads/42088-USBMIDI-quot-note-quot-was-not-declared-in-this-scope#6
 
Last edited:
Thank God for forums! You guys just answered my question! I had my syntax coded incorrectly! Thanks to all who contributed!
 
Status
Not open for further replies.
Back
Top