How to access usbMIDI.PitchBend as a variable for a Function

Status
Not open for further replies.

sargentpilcher

Well-known member
Hello all,

I have a set of LED strips that I am using MIDI to trigger the lights to come off and on. I am for the most part very pleased with the setup and how everything works, but there is a feature I'm trying to add that I can't get to work. In my code I have it written so that the velocity controls the brightness value, and it works great. However, I want to be able to fade the lights in and out, and I'm attempting to make it so that the Pitch Bend wheel will control how bright all the LED's become. In my code it's written like

colorMatrix[light][note%3] = velocity+usbMIDI.PitchBend;

But it doesn't work. It works GREAT if I put

colorMatrix[light][note%3] = velocity*2;


Putting "usbMIDI.PitchBend" into the function makes it not respond to velocity and brightness at all. It "breaks" the code completely even having it in there (No errors or anything, it just doesn't DO anything.) Is there an alternate variable or call function I should use?

Is the amount of MIDI related commands limited to what exists on this page: https://www.pjrc.com/teensy/td_midi.html

Because I don't see anything involving a Mod wheel command on that page, but I would love to be able to use my Mod wheel with the Teensy.


Code:
 #include <Adafruit_DotStar.h> 
#define NUMPIXELS 240 //Dotstar pixels
#define DATAPIN    36
#define CLOCKPIN   35

byte colorMatrix[16*42][3] ; // 2D matrix to hold velocity readings - index is for light number 
unsigned int light; // light is cacluatated by multiplying zero-indexed channel ID * 42 lights per channel + integer trunc of note/3

Adafruit_DotStar  strip1 = Adafruit_DotStar(NUMPIXELS, DATAPIN, CLOCKPIN, DOTSTAR_BRG); // initialize pixel object

void setup(){
  usbMIDI.setHandleNoteOn(OnNoteOn);
    usbMIDI.setHandleNoteOff(OnNoteOff);
  strip1.begin();
  strip1.show(); // Initialize all pixels to 'off'
}



void OnNoteOn(byte channel, byte note, byte velocity){
  light = (channel*42)-(42) + note/3; // calculate which light the message is for
  // note%3 returns an index for the three RGB positions 0,1,2 based on the remainder when the note is divided by three!
  colorMatrix[light][note%3] = velocity*usbMIDI.PitchBend; // read the velocity and scale to 8-bit from 7 and write to matrix
  // could make set pixel conditional to blue updates (if (note%3 = 2)...) if you make sure all three are sent in order when a light's values are changed
  // this wouild prevent updates before all values are available to avoid incorrect colors being displayed wiht R and G valeues being sent
  strip1.setPixelColor(light,colorMatrix[light][0],colorMatrix[light][1],colorMatrix[light][2]);
}

void OnNoteOff(byte channel, byte note, byte velocity){
  light = (channel*42)-(42) + note/3; // calculate which light the message is for
  // note%3 returns an index for the three RGB positions 0,1,2 based on the remainder when the note is divided by three!
  colorMatrix[light][note%3] = 0; // read the velocity and scale to 8-bit from 7 and write to matrix
  // could make set pixel conditional to blue updates (if (note%3 = 2)...) if you make sure all three are sent in order when a light's values are changed
  // this wouild prevent updates before all values are available to avoid incorrect colors being displayed wiht R and G valeues being sent
  strip1.setPixelColor(light,colorMatrix[light][0],colorMatrix[light][1],colorMatrix[light][2]);
}




void loop() {
  while (usbMIDI.read()) {
    // keep reading until all incoming messages read
  }
  strip1.show();
}
 
In your code you write:

Code:
colorMatrix[light][note%3] = velocity*usbMIDI.PitchBend;

instead of:

Code:
colorMatrix[light][note%3] = velocity+usbMIDI.PitchBend;

What do you wat to do? Multiply or Add.

Also, pitchbend is an int, not a byte like velocity (because pitch bend is a 14-bit value in the MIDI spec), so it seems you ar multiplying an int (with a max value of 16383) by your velocity and expecting a value within byte range... this just won't work. You need to do some scaling would be my guess.
 
usbMIDI.PitchBend is not the current value of the Pitch Bend wheel. It is a constant and has the value 0xE0 which is the value of the MIDI pitchbend message command. i.e. it is the value of the first byte sent when you send a pitchbend command (to channel zero). If you are being sent pitch bend commands, you have to receive and decode them in the same way as you do with note on and note off.
In setup you would have to set the handle:
Code:
usbMIDI.setHandlePitchBend(onPitchBend);

and before setup define your onPitchBend function:
Code:
// global variable to hold the current pitchbend value
// it will default t ozero until a pitchbend message is received
int cur_pitchbend = 0;
void onPitchBend(byte inChannel, int inValue)
{
  cur_pitchbend = inValue;
}

Where you have used usbMIDI.PitchBend in your code, change it to cur_pitchbend.

I can't test this right now. Maybe later today.

Pete
edit: Changed usbMidi to usbMIDI
 
Last edited:
P.S. it looks like this question follows on from your other thread. You should have asked it in there instead of starting a new thread.

Pete
 
In your code you write:

Code:
colorMatrix[light][note%3] = velocity*usbMIDI.PitchBend;

instead of:

Code:
colorMatrix[light][note%3] = velocity+usbMIDI.PitchBend;

What do you wat to do? Multiply or Add.

Also, pitchbend is an int, not a byte like velocity (because pitch bend is a 14-bit value in the MIDI spec), so it seems you ar multiplying an int (with a max value of 16383) by your velocity and expecting a value within byte range... this just won't work. You need to do some scaling would be my guess.

Oh man, this makes so much sense. I had just assumed that the pitch bend was the same resolution as everything else (7-bit). I will try the scaling idea you mentioned and divide instead of multiply.

I do ultimately want to multiply it, but I was working under the incorrect assumption that the pitch bend was 7 bit, and didn't want to multiply 40*40 or something huge that would make it outside the range of values, so I had thought if I had 40+40 I'd be fine to test if the code worked.


usbMIDI.PitchBend is not the current value of the Pitch Bend wheel. It is a constant and has the value 0xE0 which is the value of the MIDI pitchbend message command. i.e. it is the value of the first byte sent when you send a pitchbend command (to channel zero). If you are being sent pitch bend commands, you have to receive and decode them in the same way as you do with note on and note off.
In setup you would have to set the handle:
Code:
usbMIDI.setHandlePitchBend(onPitchBend);

and before setup define your onPitchBend function:
Code:
// global variable to hold the current pitchbend value
// it will default t ozero until a pitchbend message is received
int cur_pitchbend = 0;
void onPitchBend(byte inChannel, int inValue)
{
  cur_pitchbend = inValue;
}

Where you have used usbMIDI.PitchBend in your code, change it to cur_pitchbend.

I can't test this right now. Maybe later today.

Pete
edit: Changed usbMidi to usbMIDI

Ok this makes a ton of sense. I even had some code that wasn't very far off from what you have there, but I didn't do it right at all. I am getting an error code saying "'class usb_midi_class' has no member named 'setHandlePitchBend'" and in the code I had written using "usbMIDI.setHandlePitchChange(myPitchChange)" as seen on this list https://www.pjrc.com/teensy/td_midi.html but I'm not totally sure if it reads from the pitchbend command from ableton live.

I'm wondering if that's the reason for my error code because "setHandlePitchBend" isn't listed? Except "setHandlePitchBend" comes up as orange colored so it makes it seem like the IDE recognizes it?

If I write the code like this, it compiles and runs. I even get SOME kind of change in the brightness of my LED's, but it's not terribly consistent. That is, I'm automating the value of pitch bend inside of ableton live, and it's not as smooth as I would like (It might not even be possible to get it how I want). Perhaps if I can get the scaling right it might work? I have it divided by 1000 right now as kippertoffee said the pitch bend is a 14 bit integer. I tried dividing by 10000 and the lights were just off so it was probably too high. I will continue experimenting but have to go to work soon.

Code:
 #include <Adafruit_DotStar.h> 
#define NUMPIXELS 240 //Dotstar pixels
#define DATAPIN    36
#define CLOCKPIN   35

byte colorMatrix[16*42][3] ; // 2D matrix to hold velocity readings - index is for light number 
unsigned int light; // light is cacluatated by multiplying zero-indexed channel ID * 42 lights per channel + integer trunc of note/3
int cur_pitchbend = 0;

Adafruit_DotStar  strip1 = Adafruit_DotStar(NUMPIXELS, DATAPIN, CLOCKPIN, DOTSTAR_BRG); // initialize pixel object

void setup(){ 
  usbMIDI.setHandleNoteOn(OnNoteOn);
    usbMIDI.setHandleNoteOff(OnNoteOff);
     usbMIDI.setHandlePitchChange(myPitchChange); 
   
  strip1.begin();
  strip1.show(); // Initialize all pixels to 'off'
}

// global variable to hold the current pitchbend value
// it will default t ozero until a pitchbend message is received

void myPitchChange(byte channel, int pitch)
{
  cur_pitchbend = pitch;
} 

void OnNoteOn(byte channel, byte note, byte velocity){
  light = (channel*42)-(42) + note/3; // calculate which light the message is for
  // note%3 returns an index for the three RGB positions 0,1,2 based on the remainder when the note is divided by three!
  colorMatrix[light][note%3] = velocity*cur_pitchbend/1000; // read the velocity and scale to 8-bit from 7 and write to matrix
  // could make set pixel conditional to blue updates (if (note%3 = 2)...) if you make sure all three are sent in order when a light's values are changed
  // this wouild prevent updates before all values are available to avoid incorrect colors being displayed wiht R and G valeues being sent
  strip1.setPixelColor(light,colorMatrix[light][0],colorMatrix[light][1],colorMatrix[light][2]); 
} 
 
void OnNoteOff(byte channel, byte note, byte velocity){ 
  light = (channel*42)-(42) + note/3; // calculate which light the message is for 
  // note%3 returns an index for the three RGB positions 0,1,2 based on the remainder when the note is divided by three! 
  colorMatrix[light][note%3] = 0; // read the velocity and scale to 8-bit from 7 and write to matrix 
  // could make set pixel conditional to blue updates (if (note%3 = 2)...) if you make sure all three are sent in order when a light's values are changed
  // this wouild prevent updates before all values are available to avoid incorrect colors being displayed wiht R and G valeues being sent
  strip1.setPixelColor(light,colorMatrix[light][0],colorMatrix[light][1],colorMatrix[light][2]); 
} 




void loop() {
  while (usbMIDI.read()) {
    // keep reading until all incoming messages read
  }
  strip1.show();
}



P.S. it looks like this question follows on from your other thread. You should have asked it in there instead of starting a new thread.

Pete

It is related to the other thread in that it's the same project, but it's an entirely seperate issue/problem. That is a fade in/out and the other one is for a panic button. I'm having trouble implementing both.
 
IT WORKS!! With both of your help I was able to properly scale it down from 14 bits (Using divide by 1,000), and I was able to get the code correct. I essentially took what you wrote but switched it out with "pitchchange" instead of "pitchbend" and it actually worked!!! Thank you both so much for your help! I was initially having trouble because the scale goes positive and negative, and 0 is the middle value, so it must be a bipolar value? Anyways, my lights shut off if I automate the pitch bend to the center value, and they get brighter if I automate the pitch bend to a higher value! Awesome.

Now I just need to figure out the panic button.
 
Glad you got it working.

FYI: It would appear that USB midi and serial midi use different names for the function which sets the pitch bend callback function used to receive a pitch bend message. In USB MIDI it is setHandlePitchChange but in serial MIDI it is setHandlePitchBend. They will both show up as orange in the IDE because the usb MIDI library specifies setHandlePitchChange as a keyword and the serial library specifies setHandlePitchBend as a keyword.
But when you send a pitch bend message, they both use sendPitchBend.

Pete
 
Status
Not open for further replies.
Back
Top