Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 7 of 7

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

  1. #1

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

    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();
    }

  2. #2
    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.

  3. #3
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,002
    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 by el_supremo; 01-11-2019 at 05:27 PM.

  4. #4
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,002
    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

  5. #5
    Quote Originally Posted by kippertoffee View Post
    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.


    Quote Originally Posted by el_supremo View Post
    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();
    }


    Quote Originally Posted by el_supremo View Post
    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.

  6. #6
    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.

  7. #7
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,002
    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

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •