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

Thread: Inverting midi range with analog read expression pedal

  1. #1

    Inverting midi range with analog read expression pedal

    Hi, I'm adding an expression pedal port to me midistomp pedal so I've done a little test sketch based on an analog pot example sketch. I know some expression pedals are inverted, some have a polarity switch, and some don't.

    Two questions:
    1. Is there are better way to write this code? (don't want it to be too messy)
    2. Can you show me how to make a user-editable 'virtual polarity switch' which will invert the midi range so it would read 127 to 0 OR 0 to 127 ?

    Thank you

    Code:
    #include <Bounce.h>
    
    // the MIDI channel number to send messages
    const int channel = 1;
    
    // the MIDI continuous controller for each analog input
    const int controllerA10 = 98;
    
    
    void setup() {
    }
    // store previously sent values, to detect changes
    int previousA0 = -1;
    
    elapsedMillis msec = 0;
    
    void loop() {
      // only check the analog inputs 50 times per second,
      // to prevent a flood of MIDI messages
      if (msec >= 20) {
        msec = 0;
        int n0 = analogRead(A10) / 8;
        // only transmit MIDI messages if analog input changed
        if (n0 != previousA0) {
          usbMIDI.sendControlChange(controllerA10, n0, channel);
          previousA0 = n0;
        }
      }
      
      while (usbMIDI.read()) {
        // ignore incoming messages
      }
    }

  2. #2
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,326
    Your variable names puzzle me, is it on A10 or A1? Do you care in the code?

    Other than that it's passable MIDI code well written by my amature standards. You may occasionally find your code still chattering at your max rare between two adjacent values due to noise and rounding but as you do have it time limited it should be fine.

  3. #3
    I did notice some chattering. I thought maybe it was my cheap pot, but it is brand new.
    How would I fix that? And can I invert the range?

  4. #4
    How to invert the pedal polarity:

    analogRead returns 0-1023 , right?

    uninverted = analogRead(A10) / 8;
    inverted = (1023- analogRead(A10)) / 8;

  5. #5
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,326
    If you leave the pot near a threshold between two rounding points in the 12 bit data then even modest noise will cause alternation between two midi values.

    A better approach is to write the raw value to your lagged varable and compare that with the current raw reading and if the (absolute value of the) difference is greater than some threshold then reduce to seven bit and update the CC value. You can likely use a shorter, or even no ellapsed minimum.

    Search 'hysteresis'

    The ResponsiveAnalogRead library does a great job of taming pot signals without needing to handle all the details. It's used extensively in midi projects here.

    Invert as last step:

    ccInv = 127 - cc

    ...but only to save dividing by 8 twice.

  6. #6
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,326
    The analog section of my original midi project uses a mostly usable moving deadband hysteresis system
    Code:
    //************ANALOG SECTION**************
    void getAnalogData(){
      v0 = analogRead(0);
      if (v0D > thrshld) // if delta variable from last pass shows change past threshold - recalulate
      {
        usbMIDI.sendControlChange(cc0, v0/8, chnl); // calculate D2 and send
        v0L = v0; // lag only on update
      }
      v0D = abs(v0L-v0);
    }
    The last line is key... the size of the change between the raw value and its lagged reading (from when the last midi was sent) is stored on one pass to test on the next.

    The limits are set at update but changes are tracked at every pass (there is no time based limits on midi updates which can allow flooding midi queues with data.

    Search for ResponsiveAnalogRead library if you don't want to roll your own hysteresis method.

    To allow the for toggled directionality you can use a linear equation. In one setting the x intercept is zero and the slope 1 and in the other the intercept is 127 and the slope is minus one. In both the output can be calculated:

    CCOut = m * CC + b .

    So you just set the m and b parameters based on the selected polarity.

    Increasing

    m=1 b=0

    Decreasing

    m=-1 b=127

  7. #7
    Junior Member
    Join Date
    Jan 2020
    Posts
    7
    Re ResponsiveAnalogRead

    Hello all, thanks oddson for much useful code.

    Its weird how often you find other working on the same coding problem at the same time.

    Anyway I am interfacing a couple of expression pedals (M-audio Ex-P ) and

    a)still had some chattering.
    b)contending with the usual pot problems of them not quite getting to zero or maximum value.

    As I just needed a workable solution so I can concentrate on another project this worked for me.

    Code:
     
    
    ResponsiveAnalogRead analogZero(A0, true);
    
    
    //in setup
        analogZero.setActivityThreshold(25);  //tried various values but this worked ok for me
    //in the update
        analogZero.update();
        adcValue = analogZero.getValue();
        valX = (map(adcValue, 60, 980, 0, 127));
        valX = constrain(valX, 0, 127);
    The map values were 60 for pedal at its lowest and 980 for pedal at maximum.

    Though sometimes the pedal managed to get down to 50.

    Hence map sometimes would return -ve numbers, constrain makes sure we dont go below zero.

    Yes its (very) clunky but its giving me sensible non jittery values.

    Hope this helps someone.

    regards

  8. #8
    Thanks for your help. The mapping 0-127 and constraining would be very helpful for my project as I'm expecting people to use different types/brands of expression pedals which all respond slightly differently and show different CC ranges with just a simple analogread > CC arrangement.

    I've tried combining these myself with the code I'm using but it's no use. I don't really know what I'm doing.

    Here's the main code I'm using for testing:
    Code:
    /* 
    Many Buttons and Knobs with CC toggle buttons
    
       You must select MIDI from the "Tools > USB Type" menu
    
       This example code is in the public domain.
    */
    
    
    //************LIBRARIES USED**************
    // include the ResponsiveAnalogRead library for analog smoothing
    #include <ResponsiveAnalogRead.h>
    // include the Bounce library for 'de-bouncing' switches -- removing electrical chatter as contacts settle
    #include <Bounce.h> 
    //usbMIDI.h library is added automatically when code is compiled as a MIDI device
    
    // ******CONSTANT VALUES******** 
    // customize code behaviour here!
    const int channel = 1; // MIDI channel
    const int A_PINS = 1; // number of Analog PINS
    
    // define the pins you want to use and the CC ID numbers on which to send them..
    const int ANALOG_PINS[A_PINS] = {A10};
    const int CCID[A_PINS] = {98};
    
    //******VARIABLES***********
    // a data array and a lagged copy to tell when MIDI changes are required
    byte data[A_PINS];
    byte dataLag[A_PINS]; // when lag and new are not the same then update MIDI CC value
    
    // initialize the ReponsiveAnalogRead objects
    ResponsiveAnalogRead analog[]{
      {ANALOG_PINS[0],true},
    }; 
    
    //************SETUP**************
    void setup() {
      
    }
    
    //************LOOP**************
    void loop() {
      getAnalogData();
     // getDigitalData();
      while (usbMIDI.read()) {
         // controllers must call .read() to keep the queue clear even if they are not responding to MIDI
      }
    }
    
    //************ANALOG SECTION**************
    void getAnalogData(){  
      for (int i=0;i<A_PINS;i++){
        // update the ResponsiveAnalogRead object every loop
        analog[i].update(); 
        // if the repsonsive value has change, print out 'changed'
        if(analog[i].hasChanged()) {
          data[i] = analog[i].getValue()>>3;
          if (data[i] != dataLag[i]){
            dataLag[i] = data[i];
            usbMIDI.sendControlChange(CCID[i], data[i], channel);
          }
        }
      }
    }
    The code works, but it's too jittery and doesn't work with full 0-127 range for my pedal. If

    Code:
    //in setup
        analogZero.setActivityThreshold(25);  //tried various values but this worked ok for me
    //in the update
        analogZero.update();
        adcValue = analogZero.getValue();
        valX = (map(adcValue, 60, 980, 0, 127));
        valX = constrain(valX, 0, 127);
    these parts could be added it would help greatly! I tested the threshold thing and it works really well to keep the values less jittery, but then the mapping and constraing needs to be added.

    Can someone please help me combine the two?
    cheers
    Last edited by Aussie_CrocHunter; 01-06-2020 at 11:56 PM.

  9. #9
    Also, someone once mentioned I should put a small capacitor on the power line. could that be a jittering issue as well?

  10. #10
    Member
    Join Date
    Aug 2019
    Location
    Melbourne Australia
    Posts
    66
    A few tips:-

    Ground any pot metalwork. Fairly straightforward in a non-conductive housing. In a metal housing you need to be mindful of any potential ground loops in your grounding strategy.

    A 10 nF cap from respective Analog pin to ground. Then 4.7k resistor from A pin to wiper of 10k pot with said resistor and Cap physically as close as possible to the A pin.

    If using a multiplexer, the 10nF cap and 4.7k need to be on the input of the mux. Don't put caps on it's output.

    Some pot supply rail bypass can be helpful. Say 150 Ohm resistor from board V+ to pot V+. Then 100nF bypass from pot V+ to ground. In thinking on it, possibly the best place to ground both of these caps is the AnalogGND pin if your board has one.

    If your project has noisy digital stuff like displays, Midi in optocoupler or whatever then try to keep analog and digital wiring separate and at 90 degrees.

    Hope there's something useful to play with.

  11. #11
    Junior Member
    Join Date
    Jan 2020
    Posts
    7
    Quote Originally Posted by Aussie_CrocHunter View Post
    Thanks for your help. The mapping 0-127 and constraining would be very helpful for my project as I'm expecting people to use different types/brands of expression pedals which all respond slightly differently and show different CC ranges with just a simple analogread > CC arrangement.

    I've tried combining these myself with the code I'm using but it's no use. I don't really know what I'm doing.

    Here's the main code I'm using for testing:
    Code:
    /* 
    Many Buttons and Knobs with CC toggle buttons
    
       You must select MIDI from the "Tools > USB Type" menu
    
       This example code is in the public domain.
    */
    
    
    //************LIBRARIES USED**************
    // include the ResponsiveAnalogRead library for analog smoothing
    #include <ResponsiveAnalogRead.h>
    // include the Bounce library for 'de-bouncing' switches -- removing electrical chatter as contacts settle
    #include <Bounce.h> 
    //usbMIDI.h library is added automatically when code is compiled as a MIDI device
    
    // ******CONSTANT VALUES******** 
    // customize code behaviour here!
    const int channel = 1; // MIDI channel
    const int A_PINS = 1; // number of Analog PINS
    
    // define the pins you want to use and the CC ID numbers on which to send them..
    const int ANALOG_PINS[A_PINS] = {A10};
    const int CCID[A_PINS] = {98};
    
    //******VARIABLES***********
    // a data array and a lagged copy to tell when MIDI changes are required
    byte data[A_PINS];
    byte dataLag[A_PINS]; // when lag and new are not the same then update MIDI CC value
    
    // initialize the ReponsiveAnalogRead objects
    ResponsiveAnalogRead analog[]{
      {ANALOG_PINS[0],true},
    }; 
    
    //************SETUP**************
    void setup() {
      
    }
    
    //************LOOP**************
    void loop() {
      getAnalogData();
     // getDigitalData();
      while (usbMIDI.read()) {
         // controllers must call .read() to keep the queue clear even if they are not responding to MIDI
      }
    }
    
    //************ANALOG SECTION**************
    void getAnalogData(){  
      for (int i=0;i<A_PINS;i++){
        // update the ResponsiveAnalogRead object every loop
        analog[i].update(); 
        // if the repsonsive value has change, print out 'changed'
        if(analog[i].hasChanged()) {
          data[i] = analog[i].getValue()>>3;
          if (data[i] != dataLag[i]){
            dataLag[i] = data[i];
            usbMIDI.sendControlChange(CCID[i], data[i], channel);
          }
        }
      }
    }
    The code works, but it's too jittery and doesn't work with full 0-127 range for my pedal. If

    Code:
    //in setup
        analogZero.setActivityThreshold(25);  //tried various values but this worked ok for me
    //in the update
        analogZero.update();
        adcValue = analogZero.getValue();
        valX = (map(adcValue, 60, 980, 0, 127));
        valX = constrain(valX, 0, 127);
    these parts could be added it would help greatly! I tested the threshold thing and it works really well to keep the values less jittery, but then the mapping and constraing needs to be added.

    Can someone please help me combine the two?
    cheers

    Does this help, Ive changed a couple of things I use a0 rather than 10, put the responsiveness hack I used in and tried it here and it seems to work.

    I was getting confused by some of the variable naming so there may be a glaring error in here but no-doubt if there is someone will spot it.

    let me know how you get on or if what I did doesnt make sense :-)




    Code:
    *
      Many Buttons and Knobs with CC toggle buttons
    
       You must select MIDI from the "Tools > USB Type" menu
    
       This example code is in the public domain.
    
       hacky mods to help  Aussie_CrocHunter jont<at>ninelocks.com January 2020
    
    */
    
    
    //************LIBRARIES USED**************
    // include the ResponsiveAnalogRead library for analog smoothing
    #include <ResponsiveAnalogRead.h>
    // include the Bounce library for 'de-bouncing' switches -- removing electrical chatter as contacts settle
    #include <Bounce.h>
    //usbMIDI.h library is added automatically when code is compiled as a MIDI device
    
    // ******CONSTANT VALUES********
    // customize code behaviour here!
    const int channel = 1; // MIDI channel
    const int NUM_SLIDERS = 1; // number of Analog PINS
    
    // define the pins you want to use and the CC ID numbers on which to send them..
    const int ANALOG_PINS[NUM_SLIDERS] = {A0};  //for my test module
    const int CCID[NUM_SLIDERS] = {98};
    
    //******VARIABLES***********
    // a data array and a lagged copy to tell when MIDI changes are required
    byte data[NUM_SLIDERS];
    byte dataLag[NUM_SLIDERS]; // when lag and new are not the same then update MIDI CC value
    
    // initialize the ReponsiveAnalogRead objects
    ResponsiveAnalogRead analog[NUM_SLIDERS] {
      ResponsiveAnalogRead(ANALOG_PINS[0], true),
    };
    
    //************SETUP**************
    void setup() {
      // init the thresholds for the ResponsiveAnalogeRead objects
      for (int n = 0; n < NUM_SLIDERS; n++) {
        analog[n].setActivityThreshold(25);
      }
    
    }
    
    //************LOOP**************
    void loop() {
      getAnalogData();
      // getDigitalData();
      while (usbMIDI.read()) {
        // controllers must call .read() to keep the queue clear even if they are not responding to MIDI
      }
    }
    
    //************ANALOG SECTION**************
    
    void getAnalogData() {
      int valX;
      int adcValue = 0;
      for (int i = 0; i < NUM_SLIDERS; i++) {
        // update the ResponsiveAnalogRead object every loop
        analog[i].update();
        // if the repsonsive value has change, print out 'changed'
        if (analog[i].hasChanged()) {
    
          //jons hacky mod start
          adcValue = analog[i].getValue();
          valX = (map(adcValue, 60, 980, 0, 127));
          valX = constrain(valX, 0, 127);
    
          data[i] = valX;
    //jons hacky mod end
          
          if (data[i] != dataLag[i]) {
            dataLag[i] = data[i];
            usbMIDI.sendControlChange(CCID[i], data[i], channel);
          }
        }
      }
    }

  12. #12
    Member
    Join Date
    Aug 2019
    Location
    Melbourne Australia
    Posts
    66
    Hey @AussieCrochunter from another Aussie. Here's the code from my Pedalboard. Note that each pedal has individual map.

    Code:
    // MatrixRat's Teensy LC USB Midi 5-Pedal board.
    // Board type = Teensy LC, USB Type Serial+Midi.
    // Four pedals were hacked out of discarded organs and use a light source and LDR.
    // Incandescent lamps were removed and replaced with ultra bright yellow LEDs.
    // The fifth also came out of an organ, had a well worn out 90 Degree large pot.
    // The guts out of an old Waa Waa pedal was transplanted into that one.
    #include <ResponsiveAnalogRead.h>
    const int channel = 1;                              // MIDI channel
    const int A_PINS = 5;                               // number of Analog PINS
    const int ANALOG_PINS[A_PINS] = {A2,A3,A6, A8, A9}; //Analog Pins used
    const int CCID[A_PINS] =                {1,     2,    4,   11,    7  };  // CC numbers for respective pedals.
    const uint16_t INPUT_MINIMUM[A_PINS]  = {90,    8,    8,   44,    50 };  // These four arrays contain
    const uint16_t INPUT_MAXIMUM[A_PINS]  = {1022,  1018, 940, 956,   650};  // parameters used in map() function
    const uint16_t OUTPUT_MINIMUM[A_PINS] = {0,     0,    0,   0,     0  };  // per Pedal element. 
    const uint16_t OUTPUT_MAXIMUM[A_PINS] = {127,   127,  127, 127,   127};  //
    //******VARIABLES***********
    //uint16_t readValue[A_PINS];
    uint16_t data[A_PINS];
    uint16_t dataLag[A_PINS]; // when lag and new are not the same then update MIDI CC value
    
    ResponsiveAnalogRead analog[]{
      {ANALOG_PINS[0],true},
      {ANALOG_PINS[1],true},
      {ANALOG_PINS[2],true},
      {ANALOG_PINS[3],true},
      {ANALOG_PINS[4],true},
    }; 
    
    
    //************SETUP**************
    void setup() {
     // Serial.begin (38400);
    }
    
    //************LOOP**************
    void loop() {
      getAnalogData();
      while (usbMIDI.read()) {
         // controllers must call .read() to keep the queue clear even if they are not responding to MIDI
      }
    }
    
    
    //************ANALOG SECTION**************
    void getAnalogData(){  
      for (int i=0;i<A_PINS;i++){
        // update the ResponsiveAnalogRead object every loop
        analog[i].update(); 
              
              // if the repsonsive value has change, print out 'changed'
              if(analog[i].hasChanged()) {
                  
                  data[i]=(analog[i].getValue());
                  uint16_t temp=data[i];
                  data[i]=constrain(data[i],INPUT_MINIMUM[i],INPUT_MAXIMUM[i]);
                  data[i] = map(data[i],INPUT_MINIMUM[i],INPUT_MAXIMUM[i],OUTPUT_MINIMUM[i],OUTPUT_MAXIMUM[i]);
                        
                        if (data[i] != dataLag[i]){
                        dataLag[i] = data[i];
    
                              usbMIDI.sendControlChange(CCID[i], data[i], channel);
                             // Serial.print data[i];
                              //Serial.println();
    
                                                  }
                                         }
                                }
                          }
    To reverse the action, Swap the values like so for CCID 1
    Code:
    const int CCID[A_PINS] =                {1,     2,    4,   11,    7  };  // CC numbers for respective pedals.
    const uint16_t INPUT_MINIMUM[A_PINS]  = {1022,    8,    8,   44,    50 };  // These four arrays contain
    const uint16_t INPUT_MAXIMUM[A_PINS]  = {90,  1018, 940, 956,   650};  // parameters used in map() function
    const uint16_t OUTPUT_MINIMUM[A_PINS] = {0,     0,    0,   0,     0  };  // per Pedal element. 
    const uint16_t OUTPUT_MAXIMUM[A_PINS] = {127,   127,  127, 127,   127};  //
    Hope this is useful.

  13. #13
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,326
    Sundry observations... not an EE and prone to blunders so I may have any number of things wrong here.

    The m audio issue is likely due to the wiring not being a simple cross of Vcc and GND. I believe it's the wiper and upper leg that are crossed by the polarity switch. If the polarity switch is in the correct position and the floor knob is zeroed then you should be able to sweep near enough rail to rail.

    Attention to detail in the wiring is likely more benificial than adding filtering.

    Adding a resistor in series on either side of a mux would make it much slower to read correctly.

    If you are going to filter in analog you'd best make it with a very low cutoff if your intent us to remove signal other than the nearly static voltage level since it will largely be mains hum and its harmonics.

    The ResponsiveAnalogRead library is usually sufficient to remove noise for 7 bit midi just with stock settings but with custom settings it should be able to tame any reasonable signal.
    Last edited by oddson; 01-07-2020 at 07:27 AM.

  14. #14
    Junior Member
    Join Date
    Jan 2020
    Posts
    7
    Quote Originally Posted by oddson View Post
    Sundry observations... not an EE and prone to blunders so I may have any number of things wrong here.

    The m audio issue is likely due to the wiring not being a simple cross of Vcc and GND. I believe it's the wiper and upper leg that are crossed by the polarity switch. If the polarity switch is in the correct position and the floor knob is zeroed then you should be able to sweep near enough rail to rail.

    .
    Thats interesting,

    I'd done most of the dev work using a normal pot and havent put the maudios into full time use. But I did notice that the polarity switch was doing something odd, when I metered the plug.
    Sadly no sign of a circuit online anywhere so far , I shall dismantle/document/report back later.

  15. #15
    re: the M-Audio EX-P

    The article linked below mentions:
    Note that some manufacturers choose TIP for the measurement and RING for the reference voltage, and others do the exact opposite. You can measure the resistance with a multi-meter between RING/SLEEVE and TIP/SLEEVE while moving the pedal to figure it out. Only one of those two will measure a resistance that changes as the pedal moves.

    Anyway, for this application, just leave the switch in the OTHER position, and set the limit knob to the full anti-clockwise position to yield the full range. The resistance ring-to-sleeve varies from about 1K to about 11k as the pedal is moved.

    If you need the resistance to get all the way to 0, rewire the pedal with the limit pot removed.

    http://blackaddr.com/expression-pedal-repair-and-mod/

  16. #16
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,326
    I could not find a semantic for it online and mine is elsewhere but I recall the ground is the sleave in both.

    An ohm reading across the tip and sleave while you move the pedal will tell you if ts the wiper or not. Flip the polarity switch and you should be able to see which is which.

    If hot and ground were reversed the polarity switch would leave the reading at the total resistance of the pot (/ resistor network).

    I think there is a resistor in series on the wiper that is forming part of the bottom leg of a voltage divider so the polarity can't cause the pot to fully short the hot and ground. I think this would produce the observed behaviour.

  17. #17
    Junior Member
    Join Date
    Jan 2020
    Posts
    7
    To me (with my engineers hat on), the only sensible place for a ground is the sleeve. Thats mostly why I want to take a double check inside :-)

    A bit of me thinks best place for the top of the pot (and the connection to the supply rail) is on the tip, so that if someone decides to plug a mono jack in your dont short down the supply.
    (though on mine I do the feed to the pot via a small resistor to protect from that).

    These may be of use/interest to someone

    https://www.soundonsound.com/forum/v...php?f=35&t=800
    https://missionengineering.com/under...ession-pedals/

  18. #18
    Update: I examined my EX-P a bit more closely, and found a schematic online (which only shows the circuit in the OTHER position).
    Click image for larger version. 

Name:	4129065822_4afb4d41ba_o.png 
Views:	5 
Size:	21.8 KB 
ID:	18665

    So - with the limit pot at minimum, it's effectively out of circuit.
    It's the 1K resistor on the wiper which causes the values to never reach 0.

  19. #19
    Junior Member
    Join Date
    Jan 2020
    Posts
    7
    Quote Originally Posted by tele_player View Post
    Update: I examined my EX-P a bit more closely, and found a schematic online (which only shows the circuit in the OTHER position).
    Click image for larger version. 

Name:	4129065822_4afb4d41ba_o.png 
Views:	5 
Size:	21.8 KB 
ID:	18665

    So - with the limit pot at minimum, it's effectively out of circuit.
    It's the 1K resistor on the wiper which causes the values to never reach 0.
    much appreciated , had taken mine to bits to have a quick look as well :-)

  20. #20
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,326
    Quote Originally Posted by ninelocks View Post
    To me (with my engineers hat on), the only sensible place for a ground is the sleeve. ...
    My engineer's hat is blue and white striped and has a brim and a puffy top.. choo woooo…

    But even I know the ground belongs on the sleeve (even if I don't know how to spell it).

    ...Re: on one of the original topics... I did make a MIDI guitar pick that needed to be configured as the slide-thumb-joystick I used is limited in its range. So I made it self-configuring:
    https://forum.pjrc.com/threads/43143...r-Pick-project

  21. #21
    Junior Member
    Join Date
    Jan 2020
    Posts
    7
    very impressed , by both hat and the pick. :-).
    Re sleeve and grounds, Ive seen some very odd variations.

  22. #22
    Quote Originally Posted by ninelocks View Post
    Does this help, Ive changed a couple of things I use a0 rather than 10, put the responsiveness hack I used in and tried it here and it seems to work.

    I was getting confused by some of the variable naming so there may be a glaring error in here but no-doubt if there is someone will spot it.

    let me know how you get on or if what I did doesnt make sense :-)




    Code:
    *
      Many Buttons and Knobs with CC toggle buttons
    
       You must select MIDI from the "Tools > USB Type" menu
    
       This example code is in the public domain.
    
       hacky mods to help  Aussie_CrocHunter jont<at>ninelocks.com January 2020
    
    */
    
    
    //************LIBRARIES USED**************
    // include the ResponsiveAnalogRead library for analog smoothing
    #include <ResponsiveAnalogRead.h>
    // include the Bounce library for 'de-bouncing' switches -- removing electrical chatter as contacts settle
    #include <Bounce.h>
    //usbMIDI.h library is added automatically when code is compiled as a MIDI device
    
    // ******CONSTANT VALUES********
    // customize code behaviour here!
    const int channel = 1; // MIDI channel
    const int NUM_SLIDERS = 1; // number of Analog PINS
    
    // define the pins you want to use and the CC ID numbers on which to send them..
    const int ANALOG_PINS[NUM_SLIDERS] = {A0};  //for my test module
    const int CCID[NUM_SLIDERS] = {98};
    
    //******VARIABLES***********
    // a data array and a lagged copy to tell when MIDI changes are required
    byte data[NUM_SLIDERS];
    byte dataLag[NUM_SLIDERS]; // when lag and new are not the same then update MIDI CC value
    
    // initialize the ReponsiveAnalogRead objects
    ResponsiveAnalogRead analog[NUM_SLIDERS] {
      ResponsiveAnalogRead(ANALOG_PINS[0], true),
    };
    
    //************SETUP**************
    void setup() {
      // init the thresholds for the ResponsiveAnalogeRead objects
      for (int n = 0; n < NUM_SLIDERS; n++) {
        analog[n].setActivityThreshold(25);
      }
    
    }
    
    //************LOOP**************
    void loop() {
      getAnalogData();
      // getDigitalData();
      while (usbMIDI.read()) {
        // controllers must call .read() to keep the queue clear even if they are not responding to MIDI
      }
    }
    
    //************ANALOG SECTION**************
    
    void getAnalogData() {
      int valX;
      int adcValue = 0;
      for (int i = 0; i < NUM_SLIDERS; i++) {
        // update the ResponsiveAnalogRead object every loop
        analog[i].update();
        // if the repsonsive value has change, print out 'changed'
        if (analog[i].hasChanged()) {
    
          //jons hacky mod start
          adcValue = analog[i].getValue();
          valX = (map(adcValue, 60, 980, 0, 127));
          valX = constrain(valX, 0, 127);
    
          data[i] = valX;
    //jons hacky mod end
          
          if (data[i] != dataLag[i]) {
            dataLag[i] = data[i];
            usbMIDI.sendControlChange(CCID[i], data[i], channel);
          }
        }
      }
    }
    Perfect! Works beautifully thank you! No chatter and I can change the parameters to get full range fantastic

  23. #23
    Quote Originally Posted by MatrixRat View Post
    Hey @AussieCrochunter from another Aussie. Here's the code from my Pedalboard. Note that each pedal has individual map.

    Code:
    // MatrixRat's Teensy LC USB Midi 5-Pedal board.
    // Board type = Teensy LC, USB Type Serial+Midi.
    // Four pedals were hacked out of discarded organs and use a light source and LDR.
    // Incandescent lamps were removed and replaced with ultra bright yellow LEDs.
    // The fifth also came out of an organ, had a well worn out 90 Degree large pot.
    // The guts out of an old Waa Waa pedal was transplanted into that one.
    #include <ResponsiveAnalogRead.h>
    const int channel = 1;                              // MIDI channel
    const int A_PINS = 5;                               // number of Analog PINS
    const int ANALOG_PINS[A_PINS] = {A2,A3,A6, A8, A9}; //Analog Pins used
    const int CCID[A_PINS] =                {1,     2,    4,   11,    7  };  // CC numbers for respective pedals.
    const uint16_t INPUT_MINIMUM[A_PINS]  = {90,    8,    8,   44,    50 };  // These four arrays contain
    const uint16_t INPUT_MAXIMUM[A_PINS]  = {1022,  1018, 940, 956,   650};  // parameters used in map() function
    const uint16_t OUTPUT_MINIMUM[A_PINS] = {0,     0,    0,   0,     0  };  // per Pedal element. 
    const uint16_t OUTPUT_MAXIMUM[A_PINS] = {127,   127,  127, 127,   127};  //
    //******VARIABLES***********
    //uint16_t readValue[A_PINS];
    uint16_t data[A_PINS];
    uint16_t dataLag[A_PINS]; // when lag and new are not the same then update MIDI CC value
    
    ResponsiveAnalogRead analog[]{
      {ANALOG_PINS[0],true},
      {ANALOG_PINS[1],true},
      {ANALOG_PINS[2],true},
      {ANALOG_PINS[3],true},
      {ANALOG_PINS[4],true},
    }; 
    
    
    //************SETUP**************
    void setup() {
     // Serial.begin (38400);
    }
    
    //************LOOP**************
    void loop() {
      getAnalogData();
      while (usbMIDI.read()) {
         // controllers must call .read() to keep the queue clear even if they are not responding to MIDI
      }
    }
    
    
    //************ANALOG SECTION**************
    void getAnalogData(){  
      for (int i=0;i<A_PINS;i++){
        // update the ResponsiveAnalogRead object every loop
        analog[i].update(); 
              
              // if the repsonsive value has change, print out 'changed'
              if(analog[i].hasChanged()) {
                  
                  data[i]=(analog[i].getValue());
                  uint16_t temp=data[i];
                  data[i]=constrain(data[i],INPUT_MINIMUM[i],INPUT_MAXIMUM[i]);
                  data[i] = map(data[i],INPUT_MINIMUM[i],INPUT_MAXIMUM[i],OUTPUT_MINIMUM[i],OUTPUT_MAXIMUM[i]);
                        
                        if (data[i] != dataLag[i]){
                        dataLag[i] = data[i];
    
                              usbMIDI.sendControlChange(CCID[i], data[i], channel);
                             // Serial.print data[i];
                              //Serial.println();
    
                                                  }
                                         }
                                }
                          }
    To reverse the action, Swap the values like so for CCID 1
    Code:
    const int CCID[A_PINS] =                {1,     2,    4,   11,    7  };  // CC numbers for respective pedals.
    const uint16_t INPUT_MINIMUM[A_PINS]  = {1022,    8,    8,   44,    50 };  // These four arrays contain
    const uint16_t INPUT_MAXIMUM[A_PINS]  = {90,  1018, 940, 956,   650};  // parameters used in map() function
    const uint16_t OUTPUT_MINIMUM[A_PINS] = {0,     0,    0,   0,     0  };  // per Pedal element. 
    const uint16_t OUTPUT_MAXIMUM[A_PINS] = {127,   127,  127, 127,   127};  //
    Hope this is useful.
    Thanks heaps! I'll be trying this out too

  24. #24
    Junior Member
    Join Date
    Jan 2020
    Posts
    7
    Quote Originally Posted by Aussie_CrocHunter View Post
    Thanks heaps! I'll be trying this out too

    If of any use/interest Ive put my pedal code on github
    https://github.com/ninelocks/JTMidiPedal2020

    Along with some examples of sending sysex from linux.

    There a windows utility on the way when I find more time.

Posting Permissions

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