Self calibrating scaled output: MIDI Guitar Pick project

Status
Not open for further replies.

oddson

Well-known member
2017-04-05 21.54.57.jpg2017-04-05 21.55.30.jpg
Here's my MIDI-xy-guitar-pick. As a physical build it's super minimal.

Hot glue holds the pick to the slide-thumb-joystick (and is insulation for the contacts). I'll make a better wire harness later.

The slide-thumb joystick has two potentiometer wiper outputs but the output voltage is constrained to a circular range that does not cover the full range from ground to supply but some fraction instead.

My code keeps track of the minimum and maximum read values on each pot and uses these limits in mapping the output. This gives me full MIDI range (but it's still limited movement to a circular area). So it self-calibrating... you just need to move it around across its range.

I built it from the 'simple midi controller' I posted recently; hence the use of arrays despite there being only two pots...

It uses ResponsiveAnalogRead() to tame the signals but also limits output by some minimum time between two values for the same CC.

Code:
// include the ResponsiveAnalogRead library for analog smoothing
#include <ResponsiveAnalogRead.h>
// include the Bounce library for debouncing switches for clean messages
#include <Bounce.h> 
// ******CONSTANT VALUES******** - customize code behaviour here!
const int channel = 1; // MIDI channel
const int A_PINS = 2; // 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] = {23,22};
const int CCID[A_PINS] = {25,26};
const int MIDIdelay = 10;
//******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
elapsedMillis  CCsentElapsed[A_PINS]; // timers for each analog to set limit by time
int pinRead[A_PINS]; // need to store the pin readings to make the mapping easier
int maxRead[A_PINS]; // neet to store max/min readings for each pot 
int minRead[A_PINS]; 


// ititialize the ReponsiveAnalogRead objects
ResponsiveAnalogRead analog[]{
  {ANALOG_PINS[0],true},
  {ANALOG_PINS[1],true}/*,
  {ANALOG_PINS[2],true},
  {ANALOG_PINS[3],true},
  {ANALOG_PINS[4],true},
  {ANALOG_PINS[5],true},
  {ANALOG_PINS[6],true},
  {ANALOG_PINS[7],true},
  {ANALOG_PINS[8],true},*/
}; // not sure if there is a better way... some way run a setup loop on global array??



void setup() {
  // begin serial so we can see analog read values through the serial monitor
  Serial.begin(9600);
  for (int i=0;i<A_PINS;i++){
    maxRead[i] = 768; // initialize max/min values so starting difference is non zero 
    minRead[i] = 256;
  }
}

void loop() {
  getAnalogData();
  while (usbMIDI.read()) {
  }
}


//************ANALOG SECTION**************
void getAnalogData(){  
  
  for (int i=0;i<A_PINS;i++){
    // update the ResponsiveAnalogRead object every loop
    analog[i].update(); 
    if(analog[i].hasChanged()) {
      // if the repsonsive value has changed check if new max/min values set
[COLOR="#FF0000"]      pinRead[i] = analog[i].getValue();
      if (pinRead[i]>maxRead[i]){
        maxRead[i] = pinRead[i];
      }else if(pinRead[i]<minRead[i]){
        minRead[i] = pinRead[i];
      }[/COLOR]
      // remap to output data and send if changed and MIDIdelay has lapsed since last update for that parameter
      [COLOR="#FF0000"]data[i] = map(pinRead[i],minRead[i],maxRead[i],0,127);[/COLOR]
      if (data[i] != dataLag[i] && CCsentElapsed[i] > MIDIdelay ){
        dataLag[i] = data[i];
        usbMIDI.sendControlChange(CCID[i], data[i], channel);
        CCsentElapsed[i] = 0;
      }
    }
  }
}

From here I'm thinking of a polar coordinates option or two. One that ranges 0-1 with a discontinuity as the angle rolls over (so magnitude and phase) and a second where it does the same but cycles from 0-1 in 180 degrees and then back to zero on the second half (for panning or similar effects).
 
Status
Not open for further replies.
Back
Top