Potentiometers to MIDI

Hello! Long time lurker, first time poster. This is my first Arduino project. I have a little experience working with electronics and programming, but never together on the same project. For now, I'm starting simple: just trying to read some 10k pots and spit out midi messages.

I have 2 potentiometers wired up through a 4051 multiplexer (so I can add more later). Far as I can tell, I've wired up and programmed the 4051 properly, it seems to function as it should. I've wired up a MIDI din connector. From this, I have a MIDI cable running to a MIDI to USB adapter which is running back to my computer. Now, I've gotten it to work... kinda. When I go to map the knob to a parameter, it automatically maps the first knob (because data is constantly being sent, I think it's just arbitrarily stuck on the first one). Now, when I use the knob, it works pretty much exactly how I want it to (aside from a tiny bit of jitter now and then on the finer parameters), but a bigger part of this project is how to get more than one knob working.

TL;DR: I'm thinking I need to write in a little piece of code so that the knobs only send MIDI data when they've been turned. I'm thinking that this same piece of code could prevent jitter. Does anyone know how this might be accomplished? Or, at least, could somebody point me in the right direction? My current code is as follows.

int knobval1 = 0;
int knobval2 = 0;

void setup(){
  //4051 digital control pins
  pinMode(8, OUTPUT);    // s0
  pinMode(9, OUTPUT);    // s1
  pinMode(10, OUTPUT);    // s2
  
  //Set Baud Rate (midi:31250,serial:9600)
  Serial.begin(31250); 
}
 
void loop(){
 
  //Read Value of 4051 and send midi accordingly
  //Knob 1
  digitalWrite(8, LOW); 
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);
  delay(10); //not sure if this delay is strictly necessary
  int knobval1 = analogRead(0)/8;  // read the input pin (divide by 8 for midi)
  midiMsg(0xb0|1,1,knobval1); //send midi
  //Knob 2
  digitalWrite(8, HIGH);
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);
  delay(10);
  int knobval2= analogRead(0)/8;
  midiMsg(0xb0|1,1,knobval2);
  
}

//Send general midi message
void midiMsg(byte cmd, byte data1, byte data2){
  digitalWrite(13,HIGH);  // indicate we're sending MIDI data
  Serial.print(cmd, BYTE);
  Serial.print(data1, BYTE);
  Serial.print(data2, BYTE);
  digitalWrite(13,LOW);
}

Hi, a few things

  1. The data you read from the ADC is 10bit wide.
    first shift it 3 times to the right, so you get a value between 0 and 127.
    In your code, you can replace

int knobval2= analogRead(0)/8;

by

int knobval2= analogRead(0)>>3;
  1. Calculate the mean between x consecutive samples before updating the Midi value.
    x shall be a tradeoff of your choice: the higher it is,
  • The better is your debouncing
  • The greater is your Midi device response time

Thanks for your help! I now have the functionality I was talking about. MIDI is only being sent when I turn the knob, and it's averaged, no more jitter. Great!

My only concern now is how I can implement this functionality for multiple pots. I'm thinking maybe I could store the values used for averaging as arrays so that each pot could be averaged on its own. The issue there, however, would be calling up the array of analog readings used for averaging... I'm just not familiar with how C deals with multidimensional arrays (or if there are any limitations to how those are implemented in an Arduino). Also, if I'm already using arrays to store everything, I suppose I might as well automate the process a bit. There must be some clever way to iterate through the 4051's inputs rather than calling them up manually as I am now.

Current code:

int knobval1 = 0;
int knobval2 = 0;

const int numReadings = 10;

int readings[numReadings];      // the readings from the analog input
int index = 0;                  // the index of the current reading
int total = 0;                  // the running total
int average = 0;                // the average
int newAverage = 0;

void setup(){
  //4051 digital control pins
  pinMode(8, OUTPUT);    // s0
  pinMode(9, OUTPUT);    // s1
  pinMode(10, OUTPUT);    // s2
  
  //Set Baud Rate (midi:31250,serial:9600)
  Serial.begin(31250);
  
  for (int thisReading = 0; thisReading < numReadings; thisReading++)
    readings[thisReading] = 0;          
}
 
void loop(){
 
  //Read Value of 4051 and send midi accordingly
  //Knob 1
  digitalWrite(8, LOW); 
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);
  delay(10); //not sure if this delay is strictly necessary
  int knobval1 = analogRead(0)>>3;  // read the input pin (shift to the right for value between 0 and 127)
  checkKnob(knobval1,1); 

  //Knob 2
  //digitalWrite(8, HIGH);
  //digitalWrite(9, LOW);
  //digitalWrite(10, LOW);
  //delay(10);
  //int knobval2= analogRead(0)>>3;
  //midiMsg(0xb0|1,1,knobval2);
  
}

//Find out if knob has been turned
void checkKnob(int knobValue, int controlNum){
  // subtract the last reading:
  total= total - readings[index];        
  // read from the sensor:  
  readings[index] = knobValue;
  // add the reading to the total:
  total= total + readings[index];      
  // advance to the next position in the array:  
  index = index + 1;                    

  // if we're at the end of the array...
  if (index >= numReadings)              
    // ...wrap around to the beginning:
    index = 0;
    
  newAverage = total / numReadings;

  // see if average is different from last time:
  if(newAverage != average){
    //update average
    average = newAverage;
    //send midi
    midiMsg(0xb0|1,controlNum,average);
  }
}

//Send general midi message
void midiMsg(byte cmd, byte data1, byte data2){
  digitalWrite(13,HIGH);  // indicate we're sending MIDI data
  Serial.print(cmd, BYTE);
  Serial.print(data1, BYTE);
  Serial.print(data2, BYTE);
  digitalWrite(13,LOW);
}

Obvious answer : depending on your pot number, you might want to avoid multiple dimensioning by creating multiple variables. This shall not be to a certain extent different in terms of memory usage from the multidimensional stuff.

Multi dimension arrays are just as easy as single ones:-

int readings[numReadings][numbOfPots];

However you should not need an array for just taking the average. Just accumulate the value into one variable (add it in) and then after say ten times take the average by dividing by 10. Then you only need:-

int readings[numbOfPots];