MIDI instrument - controlling Neopixels (ws2812) with softpots - only 2 out of 3 softpots are controlling pixels as expected

Neopixel bits from this variant, 'Modified by hyz'



/*
* Arduino Ribbon Synth MIDI controller
* ------------------------------------
* ©2015 Dean Miller
* Modified by hyz
*/

#include <EEPROM.h>
#include <Wire.h>
#include <Adafruit_NeoPixel.h>
#include <QuickStats.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif

#define PIN_LED   13
#define NEO_PIN   21
#define N_PIXELS  29      //# of LEDS
#define TRANSPOSE_UP 4    //D4
#define TRANSPOSE_DOWN 2  //D2
#define VOLUME    A8      //Master volume
#define MODAL     A1      //Switch between the 7 musical modes
#define S0        A2      //String 0
#define M0        A3      //Modulation 0
#define S1        A4      //String 1
#define M1        A5      //Modulation 1

/*Here for legacy*/
#define T0        A0
#define T1        A0
#define T2        A0
#define T3        A0

#define JSX       A7
#define JSY       A6

//#define JSSEL     7


#define THRESH    600
#define N_STR     2
#define N_FRET    25
#define S_PAD     3
#define T_PAD     300

#define MOD_THRESHOLD 30  //Modulation is not send under this value

//---Midi CC----
#define VOLUME_CC 7
#define MOD_CC 1
#define MIDI_CHANNEL 0
#define VOLCA_VOLUME_CC 11
#define VOLCA_MOD_CC 46
#define VOLCA_MIDI_CHANNEL 10
#define MUTE_CC 123 

long noteDebounceTime = 0;
int noteDebounceDelay = 25;

long lastDebounceTime = 0;
int debounceDelay = 200;

long ledDebounceTime = 0;
int ledDebounceDelay = 20;

short fretDefs[N_STR][N_FRET];

int mod_final;
int vol;
int vol_buffer;
int modal;
int modal_buffer;
int buffer_mod[2];
int mod[2];
int mod_init[2]; //initial values for modulation
int s_init[2];   //intial values for string position
int pre_vol;     //previous volume
int pre_mod;     //previous modulation
bool volca = false;
int volume_cc = VOLUME_CC;
int mod_cc = MOD_CC;
int channel = MIDI_CHANNEL;
bool isPitchBend = false;
unsigned int pitchBendLight = 0;
bool dim = false;


int modal_array [6][7] =  {{0,2,4,5,7,9,11},   //ionian
                           {0,2,3,5,7,9,10},   //dorian
                           {0,1,3,5,7,8,10},   //phyrgian
                           {0,2,4,6,7,9,11},   //lydian
                           {0,2,4,5,7,9,10},   //mxyolydian
                           {0,2,3,5,7,8,10}};    //aeolian
                           //{0,1,3,5,6,8,10}};

short T_vals[N_STR];
bool T_active[] = {false, false, false, false}; //is it currently active
short T_hit[N_STR];                             //has it been hit on this loop
int T_pins[] = {T0, T1, T2, T3};

short S_vals[N_STR];                            //current sensor values
short S_old[N_STR];                             //old sensor values for comparison
int S_active[N_STR];                            //currently active notes
int S_pins[] = {S0,S1};
int fretTouched[N_STR];

bool modreset = true;

//E A D G
int offsets_default[] = {40, 45, 50, 55};

//B E A D
int offsets_transposed[] = {35, 40, 45, 50};

//default offsets
int offsets[] = {40, 45, 50, 55};


Adafruit_NeoPixel pixels = Adafruit_NeoPixel(N_PIXELS, NEO_PIN, NEO_GRB + NEO_KHZ800);
int led_number[2] = {0,0};
int led_color;
int led;
int prev_led;

bool stickActive = false;
bool stickState = false;
bool btnState = false;
int stickZeroX;
int stickZeroY;

unsigned long last_read;

QuickStats stats;

void setup() {
  //read fret definitions from EEPROM
  for (int i=0; i<N_STR; i++){
    for (int j=0; j<N_FRET; j++){
      fretDefs[i][j] = EEPROMReadShort(j * sizeof(short) + (N_FRET*i*sizeof(short)));
    }
  }
  Serial.begin(31250);
  //Serial.begin(115200);
  
  for(int i=0; i<N_STR; i++){
    pinMode(T_pins[i], INPUT);
    pinMode(S_pins[i], INPUT);
  }
  
  pinMode(JSX, INPUT);
  pinMode(JSY, INPUT);
  //pinMode(JSSEL, INPUT);
  //digitalWrite(JSSEL, HIGH);

  pinMode(PIN_LED, OUTPUT);

  pixels.begin();
  pixels.setBrightness(50);
  pixels.show();
  //calibrate joystick
  stickZeroX = analogRead(JSX);
  stickZeroY = analogRead(JSY);

  //Uncomment for re-calibration. Should be done only once
  //calibrate();

  pinMode(TRANSPOSE_UP, INPUT_PULLUP);
  pinMode(TRANSPOSE_DOWN, INPUT_PULLUP);
  pinMode(A0,INPUT);
  pinMode(3,INPUT_PULLUP);
  pinMode(VOLUME,INPUT);
  pinMode(M0,INPUT);
  pinMode(M1,INPUT);
  mod_init[0] = analogRead(M0);
  mod_init[1] = analogRead(M1);
  s_init[1] = analogRead(S1);
  s_init[0] = analogRead(S0);
}

void loop() {
  readJoystick();
  readButtons();
  readModulationAndVol();
  readControls();
  determineFrets();
  legatoTest();
  pickNotes();
  cleanUp();
  delay(1);
}

void readModulationAndVol(){
  buffer_mod[0] = analogRead(M0);
  buffer_mod[1] = analogRead(M1);
  vol_buffer = analogRead(VOLUME);
  modal_buffer = analogRead(MODAL);
  modal_buffer = map(modal_buffer, 0, 700, 0, 7);
  mod[1] = map(buffer_mod[1],mod_init[1],mod_init[1]+400,0,127);
  mod[0] = map(buffer_mod[0], 500,500+300, 0, 127);
  mod_final = max(mod[0],mod[1]);
  vol = map(vol_buffer, 0, 300, 0, 127);
  if(abs(modal_buffer != modal)){
    if(modal_buffer > 7){
      modal = 7;
      modal_buffer = 7;      
    }

    else
      modal = modal_buffer;
    onLED(modal+1,0,255,0);
    delay(500);
    onLED(N_PIXELS,0,0,0);
    //Serial.println(modal);
  }
  
  if(abs(vol - pre_vol) > 1 && vol <= 127){
    //Serial.println("vol");
    if (vol >= 127)
      vol = 127;
    if (vol <= 1)
      vol = 0;
    controllerChange(volume_cc,vol);
    pre_vol = vol;
  }
  if(abs(mod_final - pre_mod) > 5){
   
    if (mod_final < MOD_THRESHOLD )
      controllerChange(mod_cc,0);
    else if ( mod_final <= 127 )
      controllerChange(mod_cc,mod_final);
       //Serial.println("mod");
    pre_mod = mod_final;    
  }
}

void readButtons(){
  int up = digitalRead(TRANSPOSE_UP);
  int down = digitalRead(TRANSPOSE_DOWN);
  int clear_notes = digitalRead(3);
  //Serial.println(up);
  if((millis() - lastDebounceTime ) > debounceDelay){
    //Serial.println("tranposeing");
    if (!down && !clear_notes)
      transpose(-2);
    else if (!up && !clear_notes)
      transpose(2);
    else if(!up && down)
      transpose(1);
    else if(!down && up)
      transpose(-1);
    else if(!up && !down){
      if(!volca){
        volume_cc = VOLCA_VOLUME_CC;
        mod_cc = VOLCA_MOD_CC;
        channel = VOLCA_MIDI_CHANNEL;
        volca = true;
        //Serial.println("volca");
      }
      else if (volca){
        volume_cc = VOLUME_CC;
        mod_cc = MOD_CC;
        channel = MIDI_CHANNEL;
        volca = false;
        //Serial.println("!volca");
      }         
    }
  
//    else if (!clear_notes){
//      controllerChange(MUTE_CC,0);
//    }
    lastDebounceTime = millis();
  }
}


void pickNotes(){
  for (int i=0; i<N_STR; i++){
    if(T_hit[i]){
      if(S_active[i]){
        //turn off active note on this string
        noteOff(0x80 + channel, S_active[i]);
        //Serial.println("picknoteoff");
      }
      if (fretTouched[i] == 1){
        noteOff(0x80 + channel, S_active[i]);
        continue;
      }
      else{
        S_active[i] = fretTouched[i] + offsets[i];
        noteOn(0x90 + channel, S_active[i], 100);
        //Serial.println("picknoteon");        
      }

    }
  }
}

void legatoTest(){
  for(int i=0; i<N_STR; i++){
    if(S_active[i]){

      int note = fretTouched[i] + offsets[i];
      if (note != S_active[i] && fretTouched[i] == -1){
        noteOff(0x80 + channel, S_active[i]);
        
        S_active[i] = note;
        //clrLED();
        continue;
        
      }

      if(note != S_active[i] && (fretTouched[i] || T_active[i])){
        //Serial.println("legatonote");
        int volume = mod_final * 2;
        if(volume > 127)
          volume = 127;
        noteOn(0x90 + channel, note, 127);
        noteOff(0x80 + channel, S_active[i]);
        S_active[i] = note;
      }
    }
  }

  led = max(led_number[0],led_number[1]);
  //Serial.println(led_number[0]);
   //Serial.println(led_number[1]);
  if (led == -1){
    led = 0;
    onLED(N_PIXELS,0,0,0);
  }
    
  else{
    led = led + 1;
    led = map(led,0,N_FRET - 1,0,N_PIXELS);
    led_color = map(led,0,30,0,255);
    //Serial.println(led_number);
    if((millis() - ledDebounceTime ) > ledDebounceDelay){
      for(int i=0;i<led;i++){
        //pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
        pixels.setPixelColor(i, Wheel(led_color));
      }
      if(prev_led > led)
        for(int i=led;i<N_PIXELS;i++){
          //pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
          pixels.setPixelColor(i, (pixels.Color(0, 0, 0)));
        }
        pixels.show();
        ledDebounceTime = millis(); 
        prev_led = led ;
    }
  }
}

void cleanUp(){
  for (int i=0; i<N_STR; i++){
    if(S_active[i] && !fretTouched[i] && !T_active[i]){
        noteOff(0x80 + channel, S_active[i]);
        S_active[i] = 0;
    }
  }
}

void readControls(){
  //read the strings and the triggers
  for (int i=0; i<N_STR; i++){
    T_hit[i] = checkTriggered(i);
    //Serial.println(T_hit[i]);
    //if(i == 1 && abs(buffer_mod[i] - mod_init[i] > 1)){
    float temp[3];
    for (int k = 0 ; k < 3; k++){
      temp[k] = analogRead(S_pins[i]);
      delay(3);
    }
     S_vals[i] = stats.minimum(temp,3);
  }
}

void determineFrets () {
 //---------Get Fret Numbers------
 for (int i=0; i< N_STR; i++) {
   
   short s_val = S_vals[i];
   
    //check for open strings
   if (s_val == 0 ) {
    S_old[i] = s_val;
    fretTouched[i]=-1;
    led_number[i] = fretTouched[i];
  }

  else{
      //loop through the array of fret definitions
    for (int j=1; j<N_FRET; j++) {
      int k = j - 1;
      if (s_val >= fretDefs[i][j] && 
        s_val < fretDefs[i][k] &&
      abs((int)s_val-(int)S_old[i]) > S_PAD) {
        
        S_old[i] = s_val;
        fretTouched[i] = j - 1;
        led_number[i] = fretTouched[i];
        if(modal < 7){
          // not chromatic mode
          if(i == 0) 
            fretTouched[i] = modal_array[modal][fretTouched[i]%7] + (fretTouched[i]/7) * 12;
          else if(i == 1)
          {
             if(modal == 3)
              fretTouched[i] = (modal_array[(modal+3)%6][fretTouched[i]%7] + (fretTouched[i]/7) * 12) + 2; //fix for locrian
             else if(modal > 3){
              fretTouched[i] = (modal_array[(modal+2)%6][fretTouched[i]%7] + (fretTouched[i]/7) * 12);
             }
             else{
              fretTouched[i] = modal_array[(modal+3)%6][fretTouched[i]%7] + (fretTouched[i]/7) * 12;
             }
          }

        }          
//        Serial.println("fret");
//        Serial.println(i);
//        Serial.println(fretTouched[i]);
//        Serial.println("");
       }
     }
   }
 }

}


void unset(int i){
  //this function doesn't even do anything!!
}



void calibrate(){
  if (1) {
  int btn = 1;
  Serial.println("calibrating...");
  for (int i=0; i<N_STR; i++) {
    //Flash the LED too indicate calibration
    onLED(10,250,0,0);
    delay(100);
    clrLED();
    onLED(10,250,0,0);
    delay(100);
    clrLED();
    onLED(10,250,0,0);
    delay(100);
    clrLED();
  
    short sensorMax = 0;
    short sensorMin = 1023;
    short val;
    
    //loop through the array of fret definitions
    for (int j=N_FRET - 1; j>=0; j--) {
      int response = false;
      //wait for response
      Serial.println("waiting");
      while (!response) { 
        if (checkTriggered(i)) {
          val = (analogRead(S_pins[i]));
          response = true;
          //write to memory
          clrLED();
          int addr = j * sizeof(short) + (N_FRET*i*sizeof(short));
          Serial.print("Writing ");
          Serial.print(val);
          Serial.print(" to address: ");
          Serial.println(addr);
          EEPROMWriteShort(addr, val);
        }
        delay(10);
      } 
      delay(100);
      onLED(10,250,0,0);
    }
    for (int j=0; j<N_FRET; j++) {
      short v = EEPROMReadShort(j * sizeof(short) + (N_FRET*i*sizeof(short)));
      fretDefs[i][j] = v;
    }
  }
  clrLED();
  }
}

void EEPROMWriteShort(int address, int value){
  //One = Most significant -> Two = Least significant byte
  byte two = (value & 0xFF);
  byte one = ((value >> 8) & 0xFF);

  //Write the 4 bytes into the eeprom memory.
  EEPROM.write(address, two);
  EEPROM.write(address + 1, one);
}

short EEPROMReadShort(int address){
  //Read the 2 bytes from the eeprom memory.
  long two = EEPROM.read(address);
  long one = EEPROM.read(address + 1);

  //Return the recomposed short by using bitshift.
  return ((two << 0) & 0xFF) + ((one << 8) & 0xFFFF);
}

void onLED(int led,int red,int green, int blue){
  for(int i=0;i<led;i++){
    //pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
    pixels.setPixelColor(i, pixels.Color(red, green, blue));
  }
  pixels.show();
}

void clrLED(){
  for(int i=0;i<N_PIXELS;i++){
    pixels.setPixelColor(i, pixels.Color(0,0,0)); // turn off
  }
  pixels.show();
}

//check if a trigger has been hit. Return 0 if not, the value of the trigger if it has
short checkTriggered(int i){
  
  short v = analogRead(T_pins[i]);
  //Serial.println(v);
  T_vals[i] = v;
  short ret = 0;
  if(!T_active[i] && v > THRESH){
    T_active[i] = true;
    ret = v;
    //Serial.println("triggered");
  }
  else if(T_active[i] && v < THRESH - T_PAD){
    T_active[i] = false;
    //Serial.println("un-triggered");
  }
  //Serial.println(ret);
  return ret;
}

void transpose(int dir){
  switch(dir){
    case 1:
      for (int i=0; i<N_STR; i++) {
        offsets[i] = offsets[i] + 1;
        //Serial.println(offsets[0]);
      }
      break;
  
    case -1:
      for (int i=0; i<N_STR; i++) {
        offsets[i] = offsets[i] - 1;
        //Serial.println(offsets[0]);
      }
      break;
   case 2:
      for (int i=0; i<N_STR; i++) {
        offsets[i] = offsets[i] + 12;
        //Serial.println(offsets[0]);
      }
      break;
   case -2:
      for (int i=0; i<N_STR; i++) {
        offsets[i] = offsets[i] - 12;
        //Serial.println(offsets[0]);
      }
      break;   
  }
}

void readJoystick(){
  unsigned int joyx = analogRead(JSX);
  pitchBendLight = (abs(joyx - 512) / 10);
  if(abs(joyx - 512) > 15){
    isPitchBend = true;
    PitchWheelChange(map(joyx,0, 1023, -8192, 8180));
  }
  else if(isPitchBend){
    PitchWheelChange(512);
    isPitchBend = false;  
  }
}

//note-on message
void noteOn(int cmd, int pitch, int velocity) {
  
  Serial.write(byte(cmd));
  Serial.write(byte(pitch));
  Serial.write(byte(velocity));
  Serial.flush();
  digitalWrite(PIN_LED, HIGH);
}
//note-off message
void noteOff(int cmd, int pitch) {
  
  Serial.write(byte(cmd));
  Serial.write(byte(pitch));
  Serial.write(byte(0));
  Serial.flush();
  digitalWrite(PIN_LED, LOW);
}

//Sends controller change to the specified controller
void controllerChange(int controller, int value) {
  //Serial.println("cc");
  int ch = 176 + channel;
  Serial.write(byte(ch));
  Serial.write(byte(controller));
  Serial.write(byte(value));
  Serial.flush();
}



// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return pixels.Color(255 - WheelPos * 3 + pitchBendLight, 0, WheelPos * 3 + pitchBendLight);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return pixels.Color(0, WheelPos * 3 + pitchBendLight , 255 - WheelPos * 3 + pitchBendLight);
  }
  else{
    WheelPos -= 170;
    return pixels.Color(WheelPos * 3 + pitchBendLight , 255 - WheelPos * 3 + pitchBendLight , 0 );
  }
  if(mod_final> 50){
  }
}


void PitchWheelChange(int value) {
  unsigned int change = 0x2000 + value;  //  0x2000 == No Change
  unsigned char low = change & 0x7F;  // Low 7 bits
  unsigned char high = (change >> 7) & 0x7F;  // High 7 bits

  Serial.write(0xE0);
  Serial.write(low);
  Serial.write(high);
  Serial.flush();
}

I've attached a schematic to this post showing the hardware connections.

The Arduino MEGA 2560 I'm using has the chip shown in the schematic and is being powered with its USB connection to my laptop's USB port.

The MIDI output shown in the schematic is then connected through a MIDI > USB adapter cable to my laptop to interface with my DAW.

Please let me know if you would rather have a diagram made with Fritzing instead of the schematic or if you notice any mistakes. Thanks again

SoftpotGTR_Schematic.pdf (35.6 KB)

Additional info for anyone who may be following along:

  • I added a third 8 pixel strip for a total of 24 pixels and changed the N_PIXELS variable to 21 and also tried 24. The extra pixels work, but the third softpot still does not trigger them

  • After adding the 100k pulldown resistors shown in the schematic from my last post and recalibrating the softpots - the first 6 frets no longer work. Would love to know what I'm doing wrong if anyone has any theories

  • Below are screenshots from my DAW (and other pics) that show the actual note values being triggered and which frets/note values are missing. There's also 3 frets missing at the high end of all the softpots with and without the pulldown resistors.

NoResistors_FirstFrets

NoResistors_LastFrets



PullDown100k_FirstFrets

PullDown100k_LastFrets

No I am asking you to print out the contents of the EEPROM. There is a bit of the code that reads the EEPROM and puts it into the two arrays. In addition to saving this data into the arrays I would like you to print it out so that I can see what those arrays contain.

Thank you for the schematic, I will study it and get back to you.

I would rather gnaw my left leg off that have to deal with a Fritzing representation.

1 Like

Not that I can see from the code. The 3 drum pads would seem to send notes that are not connected with the ribbon pots. It is also looks like that on the video.
It would seem that the drum pads have been replaced by piezoelectric transducers and replaced in such a bad way as to endanger the Arduino it is connected to. Do you know where this bodge originated from?

The code itself is monumentally bad, it has sections of code that are totally over elaborate, sections that are wrong but will work because of a fluke. The readings of the piezoelectric transducers is plain stupid. This has 400 readings of each sensor and at 0.1mS per reading is going to add 40mS latency for each pad.

The code I managed on line was at:- https://github.com/deanm1278/Arduino-ribbon-synth/blob/master/ribbon_synth_3ch.ino but is quite different to what you said was the original code.

I am still waiting for you to post the contents of the EEPROM, without this I can't even begin to attempt to fix this.

I got it from this thread - also linked in the first post of this thread. You actually helped that individual with some of their requested custom features.

It's a variant of Dean's first sketch that was a Piezo/drum pad-based sketch. I was unable to get Dean's original piezo based sketch to work, but I was able to get this variant to work without false triggered notes (with some minor modifications - most notably I had to use Dean's original int offsets arrays).

The Neopixel aspects of the code I got from here, and it is a variant of Dean's other softpot guitar sketch that uses force sensitive resistors instead of Piezos. I would love to have just used this one, but with this one - I could not get notes to turn off - even when setup exactly as his wiring diagram shows, with all resistors in place. I was unable to get Dean's original FSR-based softpot guitar sketch to work because I could not able to figure out how to substitute the Adafruit Trellis with functional switches.

As I mentioned in posts #20 and #21, both of the sketches are variants of Dean Miller's two sketches.

I have already learned a lot from this thread, and I hope to simplify the sketch so that it can run much more efficiently! With that said, if you think it would be easier to troubleshoot one of the above sketches (and have neopixels) instead of working with this atrocity of a sketch - then I would be all for giving that a try too.

Please forgive my technical ignorance, but I thought drum pads were basically piezo transuders/elements. I've made a few MIDI drum projects with arduino using piezo elements. Am I wrong?

Yes I've been fiddling with this all day and will be posting my results shortly. Hopefully it'll at least be closer to the info you need this time. Thanks again for your guidance!

They are basically but not specifically. You don’t know exactly what is in a drum pad except you know it has a sensor. Without looking at the circuit inside it then it is impossible to know.

The thing about just the raw sensor is that it generates an AC signal that can be plus and minus several hundred volts. The 1M resistor soaks up a lot of that voltage but it doesn’t do anything about the negative voltage and that will eventually kill an Arduino pin. Maybe not immediately but each hit will chip away at the pin until it fails. You need at least a reverse diode across the input as well. I tend to use also a 3V3 zener diode and a FET as well.

1 Like

Ah, that's very good to know. I need to try to find a schematic for that; I may have those components on hand

I added Serial.println into the following two EEPROM.read sections of the sketch as shown below

void setup() {

  //read fret definitions from EEPROM
  for (int i = 0; i < N_STR; i++) {
    fretDefs[i][0] = F0;
    for (int j = 1; j < 21; j++) {
      fretDefs[i][j] = EEPROM.read(j + (21 * i));
      Serial.println(j + (21 * i));
    }
    fretDefs[i][N_FRET] = 0;
    calibrationMin[i] = EEPROM.read(21 + (21 * i));
    Serial.println(21 + (21 * i));
  }
    calibrationMin[i] = EEPROM.read(N_FRET + (N_FRET * i));
    Serial.println(N_FRET + (N_FRET * i));
    for (int j = 1; j < 21; j++) {
      fretDefs[i][j] = EEPROM.read(j + (i * N_FRET));
      Serial.println(j + (i * N_FRET));

Afterwards, I re-calibrated the softpots with the Serial Monitor open on baudrate 9600 and observed the following values printed from EEPROM:

- After calibrating softpot A0 -

21

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

- After calibrating softpot A1 - 

42

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41


- After calibrating softpot A2 - 

63

43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

  • And to be thorough - Complete Serial Monitor messages during calibration (with EEPROM print readings included between the calibration of each softpot) below
  • I fixed the calibration readings by adding a Serial.println (val) in the calibration section.
  • Notice the 255 readings for the lowest 6 fret values - that number represents an open note, hence the missing 6 frets when 100k pulldown resistors are on the softpots.
  • I did not see any clues for the missing 3 frets on the high end of the softpots
  • I noticed there's only 20 frets listed, and I'll put the details/results of my attempt to fix this in my next post
calibrating...

waiting
17
waiting
27
waiting
54
waiting
76
waiting
94
waiting
108
waiting
124
waiting
140
waiting
153
waiting
165
waiting
177
waiting
194
waiting
210
waiting
229
waiting
244
waiting
255
waiting
255
waiting
255
waiting
255
waiting
255
waiting
255

21

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

waiting
26
waiting
27
waiting
50
waiting
68
waiting
83
waiting
98
waiting
113
waiting
127
waiting
141
waiting
154
waiting
170
waiting
182
waiting
193
waiting
207
waiting
219
waiting
231
waiting
247
waiting
255
waiting
255
waiting
255
waiting
255

42

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41

waiting
31
waiting
24
waiting
47
waiting
66
waiting
88
waiting
109
waiting
127
waiting
149
waiting
164
waiting
180
waiting
194
waiting
209
waiting
225
waiting
239
waiting
255
waiting
255
waiting
255
waiting
255
waiting
255
waiting
255
waiting
255

63

43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
  • After I noticed that the EEPROM was only showing 20 frets for each softpot I modified the EEPROM.read sections from:
for (int j = 1; j < 21; j++) {


to

for (int j = 1; j < 22; j++) {



  • Afterwards, I re-calibrated and got the following values from EEPROM in the Serial Monitor (showing 21 frets now) - still working about the same though
21

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

------

42

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

--------

63

43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

Thank you, but you have done it wrong again.

Do these results surprise you?
Were they what you expected?

What you have done is to print out only the addresses of the EEPROM that are read. You have not printed out the CONTENTS of that address.
All you need to do is to is this

//read fret definitions from EEPROM
  for (int i = 0; i < N_STR; i++) {
    fretDefs[i][0] = F0;
    for (int j = 1; j < 21; j++) {
      fretDefs[i][j] = EEPROM.read(j + (21 * i));
      Serial.print(j + (21 * i)); Serial.print(" - ");  Serial.println(fretDefs[i][j]);
    }
    fretDefs[i][N_FRET] = 0;
    calibrationMin[i] = EEPROM.read(21 + (21 * i));
    Serial.println(21 + (21 * i)); Serial.print(" - ");  Serial.println(calibrationMin[i]);
  }

That is odd because with the pull down resistor I would have expected these values to be 0. This might be something to do with the calibration values stored causing something weird to happen with the mapping function.

As a MEGA has four serial ports, why not move the MIDI output socket to Serial1 (physical pin 46, data pin 19) and run that at MIDI speed and have Serial just for debug information to your console? You need to change the Serial.write calls in the MIDI output functions to Serial1.write. And call Serial1.begin in the setup function.

1 Like

Ok, yes the results did surprise me. I was expecting more data for sure but thought it best to give you the results I was getting after a complete day of trying. Thanks very much for supplying that bit of code for this particular hurdle.

I now realize that while it was showing the calibration values for each fret during the calibration process, that did not necessarily mean that it was being saved into the EEPROM - hence the reason it was important to verify the values by reading/printing actual contents of the EEPROM. Thanks again for showing me how.

After changing the EEPROM.read section to the below (with the serial.println and 'j < 22' modifications):

  //read fret definitions from EEPROM
  for (int i = 0; i < N_STR; i++) {
    fretDefs[i][0] = F0;
    for (int j = 1; j < 22; j++) {
      fretDefs[i][j] = EEPROM.read(j + (21 * i));
      Serial.println(j + (21 * i)); Serial.print(" - ");  Serial.println(fretDefs[i][j]);
    }
    fretDefs[i][N_FRET] = 0;
    calibrationMin[i] = EEPROM.read(21 + (21 * i));
    Serial.println(21 + (21 * i)); Serial.print(" - ");  Serial.println(calibrationMin[i]);
  }




  • I get the following EEPROM contents (with 100k pulldown resistors in place)
  • It's certainly possible that I might not be calibrating it just right. The only directions I've seen for it are in the calibration section of the sketch and are sort of confusing to me (no surprise there right). I will explain the method I'm using for the calibration process in my next post
  • And the only difference in EEPROM readings when no pulldown resistors are used on the softpots is only Fret 1 of each softpot has the 255 value (not the first 6 as shown below with the pulldowns). This would still be wrong and explains why the last centimeter of the low end of the softpots are still an open note without the pulldowns
After calibrating softpot A0:

1
- 255

2
- 255

3
- 255

4
- 255

5
- 255

6
- 255

7
- 240

8
- 225

9
- 207

10
- 192

11
- 176

12
- 159

13
- 143

14
- 126

15
- 110

16
- 91

17
- 73

18
- 52

19
- 34

20
- 17

21
- 23
-------

After calibrating softpot A1:

22
- 255

23
- 255

24
- 255

25
- 255

26
- 255

27
- 255

28
- 242

29
- 227

30
- 213

31
- 198

32
- 182

33
- 170

34
- 154

35
- 138

36
- 122

37
- 101

38
- 80

39
- 62

40
- 43

41
- 21

42
- 144

-----------

After calibrating softpot A2:

43
- 255

44
- 255

45
- 255

46
- 255

47
- 255

48
- 255

49
- 255

50
- 243

51
- 228

52
- 212

53
- 195

54
- 177

55
- 160

56
- 142

57
- 125

58
- 106

59
- 86

60
- 69

61
- 44

62
- 22

63
- 43

Thanks for the tip! I was able to get this accomplished, but not without a strange issue: When I used data pin 19 TX1, I did not get any MIDI signal from the Arduino. After re-checking my modifications to the sketch (all the Serial1 mods), I decided to try data pin 18 RX1 - and that does work. Maybe the board is just mislabelled? If so, that makes me wonder what else is mislabelled which could be causing issues

I actually spoke a little too soon on this one, as I noticed yesterday that when I put any value larger than 16 for the N_PIXELS variable, the very first pixel of the 24 pixel string stays orange even when no notes are being triggered. The second pixel is triggered by Fret 1 and so on (pixel number 22 out of the 24 pixel strand is triggered by Fret 21). I'm not bothered by this bug at the moment but figure I should make note in case it offers up any clues.

Below is the updated sketch, which allows for debugging through the serial monitor at 9600 baud rate, while simultaneously outputting MIDI through RX1.

/*
  Arduino Ribbon Synth MIDI controller
   ------------------------------------
   ©2014 Dean Miller
*/

#include <EEPROM.h>
#include <Wire.h>
#include <Adafruit_NeoPixel.h>
#include <QuickStats.h>
#ifdef __AVR__
#include <avr/power.h>
#endif

//------- Constants -------//
#define PIEZO_THRESHOLD_ON 12

#define PIN_LED 13
#define NEO_PIN   21
#define N_PIXELS  21      //# of LEDS

#define PIN_SOFTPOT_1 A0
#define PIN_SOFTPOT_2 A1
#define PIN_SOFTPOT_3 A2
#define PIN_PIEZO_1 A3
#define PIN_PIEZO_2 A4
#define PIN_PIEZO_3 A5
#define PIN_POT_1 8
#define PIN_POT_2 6

#define PIN_BUTTON_STICK 3

#define PIN_BUTTON_RIGHT 11
#define PIN_BUTTON_UP 5
#define PIN_BUTTON_DOWN 2
#define PIN_BUTTON_LEFT 7

//Joystick
#define PIN_JOYSTICK_X 9
#define PIN_JOYSTICK_Y 10

//Joystick
#define UP 0
#define RIGHT 1
#define DOWN 2
#define LEFT 3
#define STICK 4

#define PIEZO_SAMPLES 400
#define PADDING 2

#define THRESH    200
#define N_STR     3
#define N_FRET    21


//#define MOD_THRESHOLD 30  //Modulation is not send under this value

long noteDebounceTime = 0;
int noteDebounceDelay = 25;

long lastDebounceTime = 0;
int debounceDelay = 200;


long ledDebounceTime = 0;
int ledDebounceDelay = 20;

int mod_final;

//bool isPitchBend = false;
unsigned int pitchBendLight = 0;
//bool dim = false;


//------Note Class---------//
/*
  A note class that stores some info about each note played is necessary
   to ensure that open strings are held for the specified amount of time.
   That is a problem with using the piezos as triggers instead of FSRs, they
   only register momentary impact or vibration, creating a problem for open strings.
*/

class Note {
    int _number;
    int _velocity;
    int _startTime;
    int _fretted;

  public:
    void init(int number, int velocity, int startTime, int fretted) {
      _number = number;
      _velocity = velocity;
      _startTime = startTime;
      _fretted = fretted;
    }

    int number() {
      return _number;
    }

    int velocity() {
      return _velocity;
    }

    int fretted() {
      return _fretted;
    }

    int timeActive() {
      return millis() - _startTime;
    }
};

//------ Global Variables ---------//

/*
  fret defs stored in EEPROM for calibration purposes.
  Lower output voltages from USB ports result in different values read from
  SoftPots and wonky fret definitions.*/

int F0 = 250;  // all bigger softpot values will be treated as open string
int F21 = 0;

int fretDefs[N_STR][N_FRET];
//short fretDefs[N_STR][N_FRET];

int piezoVals[] = {
  0, 0, 0
};
int piezoPins[] = {
  PIN_PIEZO_1, PIN_PIEZO_2, PIN_PIEZO_3
};

int softPotVals[] = {
  0, 0, 0
};
int softPotPins[] = {
  PIN_SOFTPOT_1, PIN_SOFTPOT_2, PIN_SOFTPOT_3
};

int potVal1Old = -1;
int potVal2Old = -1;
int softPotValsOld[] = {
  0, 0, 0
};

int fretTouched[N_STR];
int noteFretted[N_STR];

int stringActive[] = {
  false, false, false
};
int stringPlucked[] = {
  false, false, false
};

Note *activeNotes[N_STR];

int calibrationMax[] = {
  0, 0, 0
};
int calibrationMin[N_STR];

//true for low strings, false for high strings
int stringSetLow = true;
int octave = 3;


//E A D
int offsets_low[] = {16, 21, 26};

//G B E
int offsets_high[] = {19, 23, 28};

//default offsets
int offsets[] = {52, 57, 62};

//states of control buttons
int buttonStates[] = {
  false, false, false, false, false
};
int stickActive = false;
int stickZeroX = 0;
int stickZeroY = 0;
int stickState = false;

int altControlSet = false;
int stickXY = false;
int fullLegatoMode = false;

int minDurationOpen = 75;
int minVelocity = 75;

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(N_PIXELS, NEO_PIN, NEO_GRB + NEO_KHZ800);
int led_number[3] = {0, 0, 0};
int led_color;
int led;
int prev_led;

unsigned long last_read;

QuickStats stats;

//--------- Setup ----------------//
void setup() {

  //read fret definitions from EEPROM
  for (int i = 0; i < N_STR; i++) {
    fretDefs[i][0] = F0;
    for (int j = 1; j < 22; j++) {
      fretDefs[i][j] = EEPROM.read(j + (21 * i));
      Serial.println(j + (21 * i)); Serial.print(" - ");  Serial.println(fretDefs[i][j]);
    }
    fretDefs[i][N_FRET] = 0;
    calibrationMin[i] = EEPROM.read(21 + (21 * i));
    Serial.println(21 + (21 * i)); Serial.print(" - ");  Serial.println(calibrationMin[i]);
  }

  //For Calibration, use 9600
  Serial.begin(9600);
  //Serial.println("START");

  //Use 31250 MIDI spec baud rate during normal use
  Serial1.begin(31250);
  
  pinMode(PIN_SOFTPOT_1, INPUT);
  pinMode(PIN_SOFTPOT_2, INPUT);
  pinMode(PIN_SOFTPOT_3, INPUT);
  pinMode(PIN_PIEZO_1, INPUT);
  pinMode(PIN_PIEZO_2, INPUT);
  pinMode(PIN_PIEZO_3, INPUT);
  digitalWrite(PIN_SOFTPOT_1, HIGH);
  digitalWrite(PIN_SOFTPOT_2, HIGH);
  digitalWrite(PIN_SOFTPOT_3, HIGH);

  pinMode(PIN_BUTTON_RIGHT, INPUT);
  digitalWrite(PIN_BUTTON_RIGHT, HIGH);

  pinMode(PIN_BUTTON_LEFT, INPUT);
  digitalWrite(PIN_BUTTON_LEFT, HIGH);

  pinMode(PIN_BUTTON_UP, INPUT);
  digitalWrite(PIN_BUTTON_UP, HIGH);

  pinMode(PIN_BUTTON_DOWN, INPUT);
  digitalWrite(PIN_BUTTON_DOWN, HIGH);

  pinMode(PIN_BUTTON_STICK, INPUT);
  digitalWrite(PIN_BUTTON_STICK, HIGH);

  pixels.Color(0, 0, 0);
  pinMode(PIN_LED, OUTPUT);

  pixels.begin();
  pixels.setBrightness(50);
  pixels.show();
  
  while (millis() < 500) {
    for (int i = 0; i < N_STR; i++) {
      int val = analogRead(softPotPins[i]);
      if (val > calibrationMax[i]) calibrationMax[i] = val;
    }

    //calibrate joystick
    stickZeroX = analogRead(PIN_JOYSTICK_X);
    stickZeroY = analogRead(PIN_JOYSTICK_Y);
  }
}

//----------Main Loop---------------//
void loop() {
  //reset
  for (int i = 0; i < N_STR; i++) {
    stringPlucked[i] = false;
    piezoVals[i] = false;
  }

  //read values of all sensors
  readSensors();

  determineFrets();

  //if we are in full legato mode, run the function
  if (fullLegatoMode) {
    fullLegato();
  }

  //otherwise just do the regular thing
  else {
    //test for legato action
    legatoTest();
   // onLED(N_PIXELS, 0, 0, 0);
    //use this info to determine which notes to pluck
    pickNotes();
    onLED(N_PIXELS, 0, 0, 0);
  }

  //send not off messages and reset necessary things
  cleanUp();

  //check for control changes
  readControls();
}

void readSensors() {
  for (int i = 0; i < N_STR; i++) {

    //read piezo vals
    int piezoVal = analogRead(piezoPins[i]);
    

    //if the value breaks the threshold read for max amplitude
    /* TODO: this is less than ideal. Have it determine which piezos were triggered and
       then sample them all at once for better support for polyphonic stuff.
    */

    if (piezoVal > PIEZO_THRESHOLD_ON) {
      int v_new = piezoVal;
      for (int sample = 0; sample < PIEZO_SAMPLES; sample++) {
        piezoVal = analogRead(piezoPins[i]);
        if (piezoVal > v_new) {
          v_new = piezoVal;
        }
      }
      piezoVals[i] = v_new;
      piezoVals[i] = map(piezoVals[i], 0, 500, 0, 127);
      piezoVals[i] = constrain(piezoVals[i], minVelocity, 127);
    }

    //read the value of all the softPots
    softPotVals[i] = analogRead(softPotPins[i]);
    softPotVals[i] = map(softPotVals[i], calibrationMin[i], calibrationMax[i], 0, 255);
    softPotVals[i] = constrain(softPotVals[i], 0, 255);
  }
}

void determineFrets () {
  static int count = 0;

  //---------Get Fret Numbers------
  for (int i = 0; i < N_STR; i++) {
  
    int softPotVal = softPotVals[i];

    //check for open strings
    if (softPotVal >= F0) {
      softPotValsOld[i] = softPotVal;
      fretTouched[i] = 0;
      led_number[i] = fretTouched[i];
    }

    //loop through the array of fret definitions
    for (int j = 1; j < N_FRET; j++) {

      int k = j - 1;
      if (softPotVal <= fretDefs[i][k] &&
          softPotVal > fretDefs[i][j] &&
          abs(softPotVal - softPotValsOld[i]) > PADDING) {

        softPotValsOld[i] = softPotVal;
        fretTouched[i] = j-2;
        led_number[i] = fretTouched[i];
        // Serial.print("string= ");  Serial.print(i);  Serial.print("  FretTouched= ");  Serial.print(j); Serial.print("  softpotval = ");  Serial.println(softPotVal);  //count=0;}
      }
    }
    if (softPotVal <= fretDefs[i][20]) {
      softPotValsOld[i] = softPotVal;
      fretTouched[i] = N_FRET;
      led_number[i] = fretTouched[i];
    }
  }
}

void pickNotes() {
  for (int i = 0; i < N_STR; i++) {

    //if the piezo was hit, play the fretted note
    if (piezoVals[i]) {
      switch (i) {
        case 0:
          noteFretted[i] = fretTouched[i] + offsets[i];
          break;
        case 1:
          noteFretted[i] = fretTouched[i] + offsets[i];
          break;
        case 2:
          noteFretted[i] = fretTouched[i] + offsets[i];
          break;
      }

      if (stringActive[i]) {

        //turn off the currently active note on that string
        noteOff(0x80 + i, activeNotes[i]->number(), 0);
        free(activeNotes[i]);
      }

      if (!stringActive[i]) {

        //mark string as active
        stringActive[i] = true;
      }
      //register with active notes
      activeNotes[i] = (Note *) malloc(sizeof(Note));

      if (fretTouched[i] > 0) activeNotes[i]->init(noteFretted[i], piezoVals[i], millis(), true);

      else activeNotes[i]->init(noteFretted[i], piezoVals[i], millis(), false);

      //turn on fretted note
      noteOn(0x90 + i, activeNotes[i]->number(), activeNotes[i]->velocity());

      //mark that the string was plucked
      stringPlucked[i] = true;
    }
  }
}

void legatoTest() {
  for (int i = 0; i < N_STR; i++) {
    if (stringActive[i]) {
      switch (i) {
        case 0:
          noteFretted[i] = fretTouched[i] + offsets[i];
          break;
        case 1:
          noteFretted[i] = fretTouched[i] + offsets[i];
          break;
        case 2:
          noteFretted[i] = fretTouched[i] + offsets[i];
          break;
      }

      if (noteFretted[i] != activeNotes[i]->number() && fretTouched[i]) {
        //turn on new note
        int vel = activeNotes[i]->velocity();
        noteOn(0x90 + i, noteFretted[i], vel);

        //turn off old note
        noteOff(0x80 + i, activeNotes[i]->number(), 0);
        free(activeNotes[i]);

        //register new note as the active one
        activeNotes[i] = (Note *) malloc(sizeof(Note));
        activeNotes[i]->init(noteFretted[i], vel, millis(), true);
      }
    }
  }
}
/*


*/
void fullLegato() {
  for (int i = 0; i < N_STR; i++) {
    if (fretTouched[i]) {

      switch (i) {
        case 0:
          noteFretted[i] = fretTouched[i] + offsets[i];
          break;
        case 1:
          noteFretted[i] = fretTouched[i] + offsets[i];
          break;
        case 2:
          noteFretted[i] = fretTouched[i] + offsets[i];
          break;
      }

      int vel = 127;

      if (!stringActive[i]) {
        noteOn(0x90 + i, noteFretted[i], vel);

        //register new note as the active one
        activeNotes[i] = (Note *) malloc(sizeof(Note));
        activeNotes[i]->init(noteFretted[i], vel, millis(), true);
        stringActive[i] = true;
      }
      else {

        if (noteFretted[i] != activeNotes[i]->number()) {
          int vel = 80;
          noteOn(0x90 + i, noteFretted[i], vel);

          //turn off old note
          noteOff(0x80 + i, activeNotes[i]->number(), 0);
          free(activeNotes[i]);

          //register new note as the active one
          activeNotes[i] = (Note *) malloc(sizeof(Note));
          activeNotes[i]->init(noteFretted[i], vel, millis(), true);
        }
      }
    }
  }
}

 
void cleanUp() {
  for (int i = 0; i < N_STR; i++) {

    //no fret is touched and the string is marked active
    if (!fretTouched[i] && stringActive[i]) {

      //if open string
      if (!activeNotes[i]->fretted()) {
        if (activeNotes[i]->timeActive() > minDurationOpen) {
          //turn off the active note
          noteOff(0x80 + i, activeNotes[i]->number(), 0);

          //mark as inactive
          stringActive[i] = false;
          free(activeNotes[i]);
        }
      }
      else {
        //turn off the active note
        noteOff(0x80 + i, activeNotes[i]->number(), 0);

        //mark as inactive
        stringActive[i] = false;
        free(activeNotes[i]);
      }
    }
  }
}

void readControls() {

  if (altControlSet) {
    minDurationOpen = analogRead(PIN_POT_1);
    minDurationOpen = map(minDurationOpen, 0, 1023, 0, 255 );

    minVelocity = analogRead(PIN_POT_2);
    minVelocity = map(minVelocity, 0, 1023, 0, 127);
  }

  //Potentiometers set the values for controllers 69 and 7
  else {
    int potVal1New = analogRead(PIN_POT_1);
    int potVal2New = analogRead(PIN_POT_2);

    if (abs(potVal1New - potVal1Old) > 30 || potVal1New == 0 || potVal1New == 1023 ) {
      if ((potVal1New - potVal1Old) != 0) {
        //Send MIDI control change message
        int val = map(potVal1New, 0, 1023, 0, 127);
        val = constrain(val, 0, 127);
        controllerChange(69, val);
        potVal1Old = potVal1New;
      }
    }

    if (abs(potVal2New - potVal2Old) > 30 || potVal2New == 0 || potVal2New == 1023) {
      if ((potVal2New - potVal2Old) != 0) {
        //Send MIDI control change message
        int val = map(potVal2New, 0, 1023, 0, 127);
        val = constrain(val, 0, 127);
        controllerChange(7, val);
        potVal2Old = potVal2New;
      }
    }
  }

  //-----ENGAGE FULL LEGATO MODE-----
  //removes the need for triggering with piezo for fretted notes
  if (digitalRead(PIN_BUTTON_LEFT) == LOW && !buttonStates[LEFT]) {
    fullLegatoMode = true;
    buttonStates[LEFT] = true;
  }
  if (digitalRead(PIN_BUTTON_LEFT) == HIGH && buttonStates[LEFT]) {
    fullLegatoMode = false;
    buttonStates[LEFT] = false;
  }

  led = max(led_number[0],led_number[1]);
  Serial.println(led_number[0]);
   //Serial.println(led_number[1]);
  if (led == -1){
    led = 0;
    onLED(N_PIXELS,0,0,0);
  }
    
  else{
    led = led + 1;
    led = map(led,0,N_FRET - 1,0,N_PIXELS);
    led_color = map(led,0,30,0,255);
    //Serial.println(led_number);
    if((millis() - ledDebounceTime ) > ledDebounceDelay){
      for(int i=0;i<led;i++){
        //pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
        pixels.setPixelColor(i, Wheel(led_color));
      }
      if(prev_led > led)
        for(int i=led;i<N_PIXELS;i++){
          //pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
          pixels.setPixelColor(i, (pixels.Color(0, 0, 0)));
        }
        pixels.show();
        ledDebounceTime = millis(); 
        prev_led = led ;
    }
  }



  //switch to alt control set
  if (digitalRead(PIN_BUTTON_LEFT) == LOW && !buttonStates[LEFT]) {
    altControlSet = !altControlSet;
    buttonStates[LEFT] = true;
  }
  if (digitalRead(PIN_BUTTON_LEFT) == HIGH && buttonStates[LEFT]) buttonStates[LEFT] = false;


  //Right button triggers calibration
  if (digitalRead(PIN_BUTTON_RIGHT) == LOW && !buttonStates[RIGHT]) {
    buttonStates[RIGHT] = true;
    calibrate();
  }



  //---- CHANGING THE OCTAVE -------//
  //UP and down buttons used to change offset/octave. Cycles through EAD and GBE like an infinite guitar neck.

  //---- UP BUTTON ----
  if (digitalRead(PIN_BUTTON_UP) == LOW) {
    //change the set of strings
    if (!buttonStates[UP]) {

      octave = octave - 1;

      stringSetLow = !stringSetLow;

      for (int i = 0; i < N_STR; i++) {
        //if low
        if (stringSetLow) {
          offsets[i] = offsets_low[i] + (12 * octave);
        }
        //if high
        if (!stringSetLow) {
          offsets[i] = offsets_high[i] + (12 * octave);
        }
      }
    }

    buttonStates[UP] = true;
  }
  //reset state once button is no longer being pressed
  if (digitalRead(PIN_BUTTON_UP) == HIGH && buttonStates[UP]) buttonStates[UP] = false;

  //----DOWN BUTTON----
  if (digitalRead(PIN_BUTTON_DOWN) == LOW) {
    //change the set of strings
    if (!buttonStates[DOWN]) {

      octave = octave + 1;

      stringSetLow = !stringSetLow;

      for (int i = 0; i < N_STR; i++) {
        //if low
        if (stringSetLow) {
          offsets[i] = offsets_low[i] + (12 * octave);
        }
        //if high
        if (!stringSetLow) {
          offsets[i] = offsets_high[i] + (12 * octave);
        }
      }
    }

    buttonStates[DOWN] = true;
  }
  //reset state once button is no longer being pressed
  if (digitalRead(PIN_BUTTON_DOWN) == HIGH && buttonStates[DOWN]) buttonStates[DOWN] = false;

  //switch stick to xy mode
  if (digitalRead(PIN_BUTTON_RIGHT) == LOW && !buttonStates[RIGHT]) {
    stickXY = !stickXY;
    buttonStates[RIGHT] = true;
  }
  if (digitalRead(PIN_BUTTON_RIGHT) == HIGH && buttonStates[RIGHT]) buttonStates[RIGHT] = false;

  //--------JOYSTICK-------//
  /* Click down the joystick to activate it. In regular mode it will read absolute position from the
     center in any direction (sends to modwheel, MIDI controller 1), and in XY mode the x axis
     sends to controller 2 (breath) and the y axis sends to controller 4 (foot).  */

  if (digitalRead(PIN_BUTTON_STICK) == LOW) {
    //activate joystick
    if (!buttonStates[STICK]) {
      //make sure modwheel value is set to 0 when stick is off
      if (stickActive) controllerChange(1, 0);
      stickActive = !stickActive;
    }
    buttonStates[STICK] = true;
  }
  //reset once stick is no longer being pressed
  if (digitalRead(PIN_BUTTON_STICK) == HIGH && buttonStates[STICK]) buttonStates[STICK] = false;

  if (stickActive) {
    //read positions from center
    float xPos = map(analogRead(PIN_JOYSTICK_X), stickZeroX, 1023, 0, 127);
    float yPos = map(analogRead(PIN_JOYSTICK_Y), stickZeroY, 1023, 0, 127);

    //get absolute position from center
    float z = sqrt(sq(xPos) + sq(yPos));
    int stickVal = (int)constrain(z, 0, 127);

    if (stickVal > 0) {
      stickState = true;
      if (stickXY) {
        controllerChange(2, abs(xPos));
        controllerChange(4, abs(yPos));
      }
      else controllerChange(1, stickVal);
    }
    else if (stickState && stickVal == 0) {
      stickState = false;
      if (stickXY) {
        controllerChange(2, 0);
        controllerChange(4, 0);
      }
      else controllerChange(1, 0);
    }
  }
}

//----CALIBRATION----//
/* Likely will only have to calibrate once. This is done by activating calibration mode and
   "plucking" each note on each string starting with the upper bound (after the 21st fret) and descending down
   to just after the 1st fret. Starts with the low E string, then the A string and then the D string.
   fret definitions are stored in EEPROM. Once it is calibrated for the voltage put out by the MIDI --> USB board
   you can just have the calibration button do something else because you probably won't need it again.
*/
void unset(int i){
  //this function doesn't even do anything!!
}

void calibrate() {
  
  Serial.println("calibrating...");
  
  for (int i = 0; i < N_STR; i++) {
    //Flash the LED too indicate calibration
    /*
      digitalWrite(PIN_LED, HIGH);
      delay(100);
      digitalWrite(PIN_LED, LOW);
      delay(100);
      digitalWrite(PIN_LED, HIGH);
      delay(100);
      digitalWrite(PIN_LED, LOW);
      delay(100);
      digitalWrite(PIN_LED, HIGH);
    */
    //Flash the LED too indicate calibration
    onLED(10, 250, 0, 0);
    delay(100);
    clrLED();
    onLED(10, 250, 0, 0);
    delay(100);
    clrLED();
    onLED(10, 250, 0, 0);
    delay(100);
    clrLED();
  
    int sensorMax = 0;
    int sensorMin = 1023;
    int val;

    //loop through the array of fret definitions
    for (int j = N_FRET; j > 0; j--) {

      int response = false;
      //wait for response
      Serial.println("waiting");
      //wait for response
      while (!response) {

        //read piezo val
        int piezoVal = analogRead(piezoPins[i]);

        //get the sensor min value (highest fret) on the first round
        if (j == N_FRET) {
          int fretVal = analogRead(softPotPins[i]);
          if (fretVal > sensorMax) (sensorMax = fretVal);
           clrLED();
          //if the piezo is hit, register this as the definition for this fret
          if (piezoVal > PIEZO_THRESHOLD_ON) {
            int fretVal = analogRead(softPotPins[i]);
            sensorMin = fretVal;
            val = fretVal;
            response = true;
            clrLED();
       /*   int addr = j * sizeof(short) + (N_FRET*i*sizeof(short));
          Serial.print("Writing ");
          Serial.print(val);
          Serial.print(" to address: ");
          Serial.println(addr);
          EEPROM.write(addr, val); */
          }
        }

        else {
          //get the rest of the fret definitions
          //if the piezo is hit, register this as the definition for this fret
          if (piezoVal > PIEZO_THRESHOLD_ON) {
            int fretVal = analogRead(softPotPins[i]);
            fretVal = map(fretVal, sensorMin, sensorMax, 0, 255);
            fretVal = constrain(fretVal, 0, 255);
            val = fretVal;
            response = true;
            clrLED();
          }
        }
      }

      //write to memory
      digitalWrite(PIN_LED, LOW);
      EEPROM.write(j + (N_FRET * i), val);
      Serial.println(val);
      delay(100);
      onLED(10, 250, 0, 0);
//      delay(100);
      digitalWrite(PIN_LED, HIGH);
    }


    //update global definitions
    calibrationMin[i] = EEPROM.read(N_FRET + (N_FRET * i));
   // Serial.println(N_FRET + (N_FRET * i)); Serial.print(" - ");  Serial.println(calibrationMin[i]);
    for (int j = 1; j < 22; j++) {
      fretDefs[i][j] = EEPROM.read(j + (i * N_FRET));
      Serial.println(j + (i * N_FRET)); Serial.print(" - ");  Serial.println(fretDefs[i][j]);
    }
    clrLED();
  }
  delay(100);
  onLED(10, 250, 0, 0);
  buttonStates[RIGHT] = false;
  digitalWrite(PIN_LED, LOW);
}
void onLED(int led, int red, int green, int blue) {
  for (int i = 0; i < N_STR; i++) {
  
    //pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
    pixels.setPixelColor(i, pixels.Color(red, green, blue));
  }
  pixels.show();
}

void clrLED() {
  for (int i = 0; i < N_PIXELS; i++){
    pixels.setPixelColor(i, pixels.Color(0, 0, 0)); // turn off
  }
  pixels.show();
}
//-------------MIDI functions-----------------

//note-on message
void noteOn(int cmd, int pitch, int velocity) {

  Serial1.write(byte(cmd));
  Serial1.write(byte(pitch));
  Serial1.write(byte(velocity));
  digitalWrite(PIN_LED, HIGH);
}
//note-off message
void noteOff(int cmd, int pitch, int velocity) {

  Serial1.write(byte(cmd));
  Serial1.write(byte(pitch));
  Serial1.write(byte(0));
  digitalWrite(PIN_LED, LOW);
}

//Sends controller change to the specified controller
void controllerChange(int controller, int value) {
  Serial1.write(byte(0xb0));
  Serial1.write(byte(controller));
  Serial1.write(byte(value));

  Serial1.write(byte(0xb1));
  Serial1.write(byte(controller));
  Serial1.write(byte(value));

  Serial1.write(byte(0xb2));
  Serial1.write(byte(controller));
  Serial1.write(byte(value));
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return pixels.Color(255 - WheelPos * 3 + pitchBendLight, 0, WheelPos * 3 + pitchBendLight);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return pixels.Color(0, WheelPos * 3 + pitchBendLight , 255 - WheelPos * 3 + pitchBendLight);
  }
  else{
    WheelPos -= 170;
    return pixels.Color(WheelPos * 3 + pitchBendLight , 255 - WheelPos * 3 + pitchBendLight , 0 );
  }
  if(mod_final> 50){
  }
}
1 Like

For the calibration procedure, I'm using the instructions from the sketch as a guide. Here's what I've been doing; please let me know if you think I should try a different method:

  • First I uncomment the calibrate() section of the sketch
  • Next I open the Serial Monitor and set it to 9600 baud rate
  • Then I press the calibrate button connected as shown in the schematic
  • After entering calibration mode the orange stuck neopixel mentioned in the previous post goes away so that all pixels are clear at this point
  • After I see the 'calibration waiting' message in the Serial Monitor, I press on the highest fret position (Fret 21, closest to the softpots' terminal connectors) and tap the piezo element that corresponds to the softpot I'm currently calibrating
  • This first tap lights up the first few pixels in a solid red color (even on softpot A2)
  • Then I continue down the softpot towards the low end (Fret 1) twenty more times for a total of 21 calibration points per softpot
  • Each additional time I move down the softpot and tap the piezo for a new calibration point, the red pixels flash and then remain solid again until the next tap
  • After tapping the 21st calibration point at the low end of the softpot (Fret 1 that registers as value 255), the red neopixels flash twice and then turn off until I tap the first calibration point of the next softpot (Fret 21)
  • After the 21st calibration point of the last softpot - A2, the red neopixels turn off (the stuck orange first pixel returns).
  • Then I comment out the calibrate section of the sketch and re-upload the sketch for testing with my DAW.

The calibration points seem to remain, but the pixels no longer respond to softpot A2 after exiting calibration mode

@jim81

can you please use code-section for the serial outputs too?

if you have copied the serial-output to the clipboard
click on the </>-button
then paste the clipboard.
this will create a code-section where it is very easy to copy the exact full content of the code-section and at the same time keeps the visible lines short.

After calibrating softpot A0:

1

    255

2

    255

3

    255

4

    255

5

    255

6

    255

7

    240

8

    225

9

    207

10

    192

11

    176

12

    159

13

    143

14

    126

15

    110

16

    91

17

    73

18

    52

19

    34

20

    17

21

    23

After calibrating softpot A1:

22

    255

23

    255

24

    255

25

    255

26

    255

27

    255

28

    242

29

    227

30

    213

31

    198

32

    182

33

    170

34

    154

35

    138

36

    122

37

    101

38

    80

39

    62

40

    43

41

    21

42

    144

After calibrating softpot A2:

43

    255

44

    255

45

    255

46

    255

47

    255

48

    255

49

    255

50

    243

51

    228

52

    212

53

    195

54

    177

55

    160

56

    142

57

    125

58

    106

59

    86

60

    69

61

    44

62

    22

63

    43

best regards Stefan

1 Like

Yes, I wasn't sure if that was allowed - Thanks!

OK can we try again, that print out was not what I was expecting.
First off the printing was before you initialised the serial port. Second what is all the
After calibrating softpot A1:
about, that should not appearer in the printout?

The use of print and println was wrong I want to see each location on one line, address then data. I have added a separator so it clearly shows which is which.
This is the new section of code. Copy it and then highlight the start of the setup function in your code and paste it in so it is replaced by this new code.

void setup() {

  //For Calibration, use 9600
  Serial.begin(9600);
  //Serial.println("START");

  //Use 31250 MIDI spec baud rate during normal use
  Serial1.begin(31250);

  //read fret definitions from EEPROM
  for (int i = 0; i < N_STR; i++) {
    fretDefs[i][0] = F0;
    for (int j = 1; j < 22; j++) {
      fretDefs[i][j] = EEPROM.read(j + (21 * i));
      Serial.print(j + (21 * i)); Serial.print(" -fret- ");  Serial.println(fretDefs[i][j]);
    }
    fretDefs[i][N_FRET] = 0;
    calibrationMin[i] = EEPROM.read(21 + (21 * i));
    Serial.print(21 + (21 * i)); Serial.print(" -cal- ");  Serial.println(calibrationMin[i]);
  }

Not only it is allowed, why should it not be, but it is not sensible to do anything else.
So when the code runs copy all the output of the serial monitor using the copy for forum option and then paste it into your reply.

I am not interested in seeing the calibration process, there is no need to show it. Also at this stage I am not interested in what happens with the rest of the code. When fault finding you have to take tiny steps, every thing else, at this stage, is not relevant. So please don't describe what the rest of the code does yet.

It is not the board it is your schematic that is wrong. You have used the schematic for the actual chip, not for the Mega board. While the two are similar they are not the same. A beginner might expect the TX to be an output and the RX an input, but depending on how the processor chip is defined it could be an input or an output.
I admit this is confusing and it is not well, if at all, understood in hobby circles.
From
[Data terminal equipment](Data - Wikipedia Terminal Equipment)

The upshot is that the Mega board's pin labels are reversed from how the chip itself is defined. See this small section of the Mega boards reference diagram.

Ok I see what you mean about the need to initialize the serial port before the EEPROM is read. After I pasted the code from your post into the sketch (and remove the originally placed serial.begin's) I am able to see the serial monitor results for the EEPROM contents right when the sketch starts up, unlike before. The sketch would start, and just keep showing repeating 0's until I started up the calibration process.

While I get the below results in the serial monitor right when the sketch starts up now, the instrument no longer works at all - has tons of false triggered midi messages and no longer produces sound through the DAW. Feel free to ignore that if it's not pertinent during this step of the troubleshooting process.

Notice the repeating 21's at the bottom; they keep going for infinity. Before putting the serial.begin's at the beginning of the setup section, it was repeating 0's - not 21's. Again, I'm only pointing things like this out because I am just not sure if this is normal behavior.

2⸮1 -fret- 255
2 -fret- 255
3 -fret- 255
4 -fret- 255
5 -fret- 255
6 -fret- 255
7 -fret- 255
8 -fret- 255
9 -fret- 248
10 -fret- 236
11 -fret- 225
12 -fret- 208
13 -fret- 192
14 -fret- 176
15 -fret- 161
16 -fret- 140
17 -fret- 114
18 -fret- 83
19 -fret- 51
20 -fret- 24
21 -fret- 20
21 -cal- 20
22 -fret- 255
23 -fret- 255
24 -fret- 255
25 -fret- 255
26 -fret- 255
27 -fret- 255
28 -fret- 242
29 -fret- 226
30 -fret- 212
31 -fret- 198
32 -fret- 182
33 -fret- 164
34 -fret- 146
35 -fret- 127
36 -fret- 112
37 -fret- 97
38 -fret- 84
39 -fret- 66
40 -fret- 47
41 -fret- 23
42 -fret- 59
42 -cal- 59
43 -fret- 255
44 -fret- 255
45 -fret- 255
46 -fret- 255
47 -fret- 255
48 -fret- 255
49 -fret- 248
50 -fret- 233
51 -fret- 216
52 -fret- 203
53 -fret- 184
54 -fret- 168
55 -fret- 151
56 -fret- 136
57 -fret- 119
58 -fret- 104
59 -fret- 86
60 -fret- 65
61 -fret- 45
62 -fret- 22
63 -fret- 24
63 -cal- 24
21
21
21
21
21
21
21
21
21
21


Those lines were inserted by me for clarity purposes. The reason I added those 3 lines stating that the serial monitor results were after calibrating each softpot was because I was only able to print the EEPROM.read values after calibration of each softpot and you had stated that you did not want to see the calibration data. So I copied the EEPROM parts after the calibration of each softpot.

I was trying to show that I was only getting EEPROM values during the calibration process and not when the sketch started. It appears the reason I was not getting the EEPROM contents in the serial monitor when the sketch started was because of the above issue with not initializing the serial ports before EEPROM.read in the setup section of the sketch

Yeah that is extremely confusing and I feel the need to study up on this subject for a while before I can even formulate a response or follow up questions.

Setup section of sketch has been updated as shown below:

//--------- Setup ----------------//
void setup() {

  //For Calibration, use 9600
  Serial.begin(9600);
  //Serial.println("START");

  //Use 31250 MIDI spec baud rate during normal use
  Serial1.begin(31250);

  //read fret definitions from EEPROM
  for (int i = 0; i < N_STR; i++) {
    fretDefs[i][0] = F0;
    for (int j = 1; j < 22; j++) {
      fretDefs[i][j] = EEPROM.read(j + (21 * i));
      Serial.print(j + (21 * i)); Serial.print(" -fret- ");  Serial.println(fretDefs[i][j]);
    }
    fretDefs[i][N_FRET] = 0;
    calibrationMin[i] = EEPROM.read(21 + (21 * i));
    Serial.print(21 + (21 * i)); Serial.print(" -cal- ");  Serial.println(calibrationMin[i]);
  }


  pinMode(PIN_SOFTPOT_1, INPUT);
  pinMode(PIN_SOFTPOT_2, INPUT);
  pinMode(PIN_SOFTPOT_3, INPUT);
  pinMode(PIN_PIEZO_1, INPUT);
  pinMode(PIN_PIEZO_2, INPUT);
  pinMode(PIN_PIEZO_3, INPUT);
  digitalWrite(PIN_SOFTPOT_1, HIGH);
  digitalWrite(PIN_SOFTPOT_2, HIGH);
  digitalWrite(PIN_SOFTPOT_3, HIGH);

  pinMode(PIN_BUTTON_RIGHT, INPUT);
  digitalWrite(PIN_BUTTON_RIGHT, HIGH);

  pinMode(PIN_BUTTON_LEFT, INPUT);
  digitalWrite(PIN_BUTTON_LEFT, HIGH);

  pinMode(PIN_BUTTON_UP, INPUT);
  digitalWrite(PIN_BUTTON_UP, HIGH);

  pinMode(PIN_BUTTON_DOWN, INPUT);
  digitalWrite(PIN_BUTTON_DOWN, HIGH);

  pinMode(PIN_BUTTON_STICK, INPUT);
  digitalWrite(PIN_BUTTON_STICK, HIGH);

  pixels.Color(0, 0, 0);
  pinMode(PIN_LED, OUTPUT);

  pixels.begin();
  pixels.setBrightness(50);
  pixels.show();
  
  while (millis() < 500) {
    for (int i = 0; i < N_STR; i++) {
      int val = analogRead(softPotPins[i]);
      if (val > calibrationMax[i]) calibrationMax[i] = val;
    }

    //calibrate joystick
    stickZeroX = analogRead(PIN_JOYSTICK_X);
    stickZeroY = analogRead(PIN_JOYSTICK_Y);
  }
}

You should always post your full code
using this method

There is an automatic function for doing this in the Arduino-IDE
just three steps

  1. press Ctrl-T for autoformatting your code
  2. do a rightclick with the mouse and choose "copy for forum"
  3. paste clipboard into write-window of a posting

I made a modification to your code to show in much more detail which eeprom-value gets stored where to
but I'm unable to compile your code so you have to insert my modificated code of the for- loop into your code

  //read fret definitions from EEPROM
  for (int i = 0; i < N_STR; i++) {
    fretDefs[i][0] = F0;
    for (int j = 1; j < 22; j++) {
      fretDefs[i][j] = EEPROM.read(j + (21 * i));
      Serial.print("EEPROM.read(");
      Serial.print(j);
      Serial.print(" + (21 * ");
      Serial.print(i);
      Serial.print("))");
      Serial.print(" EEPROM.read(");
      Serial.print(j + (21 * i));
      Serial.print(")");
      
      Serial.print(" -fret- ");  
      Serial.print("fretDefs[")
      Serial.print(i);
      Serial.print("][");
      Serial.print(j);
      Serial.print("]=");
      Serial.println(fretDefs[i][j]);
    }
    fretDefs[i][N_FRET] = 0;
    calibrationMin[i] = EEPROM.read(21 + (21 * i));
    Serial.print(21 + (21 * i)); Serial.print(" -cal- ");  Serial.println(calibrationMin[i]);
  }

the modification shows the values of each detail in each iteration

You can apply the same principle to the serial-printing at the botto, of the loop
It might be good to put all the serial.prints into its own function

best regards Stefan

1 Like

Sure will do, thanks very much for your assistance! Below is the full code including the serial print changes you recommended

[code]
/*
  Arduino Ribbon Synth MIDI controller
   ------------------------------------
   ©2014 Dean Miller
*/

#include <EEPROM.h>
#include <Wire.h>
#include <Adafruit_NeoPixel.h>
#include <QuickStats.h>
#ifdef __AVR__
#include <avr/power.h>
#endif

//------- Constants -------//
#define PIEZO_THRESHOLD_ON 12

#define PIN_LED 13
#define NEO_PIN   21
#define N_PIXELS  21      //# of LEDS

#define PIN_SOFTPOT_1 A0
#define PIN_SOFTPOT_2 A1
#define PIN_SOFTPOT_3 A2
#define PIN_PIEZO_1 A3
#define PIN_PIEZO_2 A4
#define PIN_PIEZO_3 A5
#define PIN_POT_1 8
#define PIN_POT_2 6

#define PIN_BUTTON_STICK 3

#define PIN_BUTTON_RIGHT 11
#define PIN_BUTTON_UP 5
#define PIN_BUTTON_DOWN 2
#define PIN_BUTTON_LEFT 7

//Joystick
#define PIN_JOYSTICK_X 9
#define PIN_JOYSTICK_Y 10

//Joystick
#define UP 0
#define RIGHT 1
#define DOWN 2
#define LEFT 3
#define STICK 4

#define PIEZO_SAMPLES 400
#define PADDING 2

#define THRESH    200
#define N_STR     3
#define N_FRET    21


//#define MOD_THRESHOLD 30  //Modulation is not send under this value

long noteDebounceTime = 0;
int noteDebounceDelay = 25;

long lastDebounceTime = 0;
int debounceDelay = 200;


long ledDebounceTime = 0;
int ledDebounceDelay = 20;

int mod_final;

//bool isPitchBend = false;
unsigned int pitchBendLight = 0;
//bool dim = false;


//------Note Class---------//
/*
  A note class that stores some info about each note played is necessary
   to ensure that open strings are held for the specified amount of time.
   That is a problem with using the piezos as triggers instead of FSRs, they
   only register momentary impact or vibration, creating a problem for open strings.
*/

class Note {
    int _number;
    int _velocity;
    int _startTime;
    int _fretted;

  public:
    void init(int number, int velocity, int startTime, int fretted) {
      _number = number;
      _velocity = velocity;
      _startTime = startTime;
      _fretted = fretted;
    }

    int number() {
      return _number;
    }

    int velocity() {
      return _velocity;
    }

    int fretted() {
      return _fretted;
    }

    int timeActive() {
      return millis() - _startTime;
    }
};

//------ Global Variables ---------//

/*
  fret defs stored in EEPROM for calibration purposes.
  Lower output voltages from USB ports result in different values read from
  SoftPots and wonky fret definitions.*/

int F0 = 250;  // all bigger softpot values will be treated as open string
int F21 = 0;

int fretDefs[N_STR][N_FRET];
//short fretDefs[N_STR][N_FRET];

int piezoVals[] = {
  0, 0, 0
};
int piezoPins[] = {
  PIN_PIEZO_1, PIN_PIEZO_2, PIN_PIEZO_3
};

int softPotVals[] = {
  0, 0, 0
};
int softPotPins[] = {
  PIN_SOFTPOT_1, PIN_SOFTPOT_2, PIN_SOFTPOT_3
};

int potVal1Old = -1;
int potVal2Old = -1;
int softPotValsOld[] = {
  0, 0, 0
};

int fretTouched[N_STR];
int noteFretted[N_STR];

int stringActive[] = {
  false, false, false
};
int stringPlucked[] = {
  false, false, false
};

Note *activeNotes[N_STR];

int calibrationMax[] = {
  0, 0, 0
};
int calibrationMin[N_STR];

//true for low strings, false for high strings
int stringSetLow = true;
int octave = 3;


//E A D
int offsets_low[] = {16, 21, 26};

//G B E
int offsets_high[] = {19, 23, 28};

//default offsets
int offsets[] = {52, 57, 62};

//states of control buttons
int buttonStates[] = {
  false, false, false, false, false
};
int stickActive = false;
int stickZeroX = 0;
int stickZeroY = 0;
int stickState = false;

int altControlSet = false;
int stickXY = false;
int fullLegatoMode = false;

int minDurationOpen = 75;
int minVelocity = 75;

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(N_PIXELS, NEO_PIN, NEO_GRB + NEO_KHZ800);
int led_number[3] = {0, 0, 0};
int led_color;
int led;
int prev_led;

unsigned long last_read;

QuickStats stats;

//--------- Setup ----------------//
void setup() {

  //For Calibration, use 9600
  Serial.begin(9600);
  //Serial.println("START");

  //Use 31250 MIDI spec baud rate during normal use
  Serial1.begin(31250);

  //read fret definitions from EEPROM
  for (int i = 0; i < N_STR; i++) {
    fretDefs[i][0] = F0;
    for (int j = 1; j < 22; j++) {
      fretDefs[i][j] = EEPROM.read(j + (21 * i));
      Serial.print("EEPROM.read(");
      Serial.print(j);
      Serial.print(" + (21 * ");
      Serial.print(i);
      Serial.print("))");
      Serial.print(" EEPROM.read(");
      Serial.print(j + (21 * i));
      Serial.print(")");

      Serial.print(" -fret- ");
      Serial.print("fretDefs[");
      Serial.print(i);
      Serial.print("][");
      Serial.print(j);
      Serial.print("]=");
      Serial.println(fretDefs[i][j]);
    }
    fretDefs[i][N_FRET] = 0;
    calibrationMin[i] = EEPROM.read(21 + (21 * i));
    Serial.print(21 + (21 * i)); Serial.print(" -cal- ");  Serial.println(calibrationMin[i]);
  }


  pinMode(PIN_SOFTPOT_1, INPUT);
  pinMode(PIN_SOFTPOT_2, INPUT);
  pinMode(PIN_SOFTPOT_3, INPUT);
  pinMode(PIN_PIEZO_1, INPUT);
  pinMode(PIN_PIEZO_2, INPUT);
  pinMode(PIN_PIEZO_3, INPUT);
  digitalWrite(PIN_SOFTPOT_1, HIGH);
  digitalWrite(PIN_SOFTPOT_2, HIGH);
  digitalWrite(PIN_SOFTPOT_3, HIGH);

  pinMode(PIN_BUTTON_RIGHT, INPUT);
  digitalWrite(PIN_BUTTON_RIGHT, HIGH);

  pinMode(PIN_BUTTON_LEFT, INPUT);
  digitalWrite(PIN_BUTTON_LEFT, HIGH);

  pinMode(PIN_BUTTON_UP, INPUT);
  digitalWrite(PIN_BUTTON_UP, HIGH);

  pinMode(PIN_BUTTON_DOWN, INPUT);
  digitalWrite(PIN_BUTTON_DOWN, HIGH);

  pinMode(PIN_BUTTON_STICK, INPUT);
  digitalWrite(PIN_BUTTON_STICK, HIGH);

  pixels.Color(0, 0, 0);
  pinMode(PIN_LED, OUTPUT);

  pixels.begin();
  pixels.setBrightness(50);
  pixels.show();

  while (millis() < 500) {
    for (int i = 0; i < N_STR; i++) {
      int val = analogRead(softPotPins[i]);
      if (val > calibrationMax[i]) calibrationMax[i] = val;
    }

    //calibrate joystick
    stickZeroX = analogRead(PIN_JOYSTICK_X);
    stickZeroY = analogRead(PIN_JOYSTICK_Y);
  }
}

//----------Main Loop---------------//
void loop() {
  //reset
  for (int i = 0; i < N_STR; i++) {
    stringPlucked[i] = false;
    piezoVals[i] = false;
  }

  //read values of all sensors
  readSensors();

  determineFrets();

  //if we are in full legato mode, run the function
  if (fullLegatoMode) {
    fullLegato();
  }

  //otherwise just do the regular thing
  else {
    //test for legato action
    legatoTest();
    // onLED(N_PIXELS, 0, 0, 0);
    //use this info to determine which notes to pluck
    pickNotes();
    onLED(N_PIXELS, 0, 0, 0);
  }

  //send not off messages and reset necessary things
  cleanUp();

  //check for control changes
  readControls();
}

void readSensors() {
  for (int i = 0; i < N_STR; i++) {

    //read piezo vals
    int piezoVal = analogRead(piezoPins[i]);


    //if the value breaks the threshold read for max amplitude
    /* TODO: this is less than ideal. Have it determine which piezos were triggered and
       then sample them all at once for better support for polyphonic stuff.
    */

    if (piezoVal > PIEZO_THRESHOLD_ON) {
      int v_new = piezoVal;
      for (int sample = 0; sample < PIEZO_SAMPLES; sample++) {
        piezoVal = analogRead(piezoPins[i]);
        if (piezoVal > v_new) {
          v_new = piezoVal;
        }
      }
      piezoVals[i] = v_new;
      piezoVals[i] = map(piezoVals[i], 0, 500, 0, 127);
      piezoVals[i] = constrain(piezoVals[i], minVelocity, 127);
    }

    //read the value of all the softPots
    softPotVals[i] = analogRead(softPotPins[i]);
    softPotVals[i] = map(softPotVals[i], calibrationMin[i], calibrationMax[i], 0, 255);
    softPotVals[i] = constrain(softPotVals[i], 0, 255);
  }
}

void determineFrets () {
  static int count = 0;

  //---------Get Fret Numbers------
  for (int i = 0; i < N_STR; i++) {

    int softPotVal = softPotVals[i];

    //check for open strings
    if (softPotVal >= F0) {
      softPotValsOld[i] = softPotVal;
      fretTouched[i] = 0;
      led_number[i] = fretTouched[i];
    }

    //loop through the array of fret definitions
    for (int j = 1; j < N_FRET; j++) {

      int k = j - 1;
      if (softPotVal <= fretDefs[i][k] &&
          softPotVal > fretDefs[i][j] &&
          abs(softPotVal - softPotValsOld[i]) > PADDING) {

        softPotValsOld[i] = softPotVal;
        fretTouched[i] = j - 2;
        led_number[i] = fretTouched[i];
        // Serial.print("string= ");  Serial.print(i);  Serial.print("  FretTouched= ");  Serial.print(j); Serial.print("  softpotval = ");  Serial.println(softPotVal);  //count=0;}
      }
    }
    if (softPotVal <= fretDefs[i][20]) {
      softPotValsOld[i] = softPotVal;
      fretTouched[i] = N_FRET;
      led_number[i] = fretTouched[i];
    }
  }
}

void pickNotes() {
  for (int i = 0; i < N_STR; i++) {

    //if the piezo was hit, play the fretted note
    if (piezoVals[i]) {
      switch (i) {
        case 0:
          noteFretted[i] = fretTouched[i] + offsets[i];
          break;
        case 1:
          noteFretted[i] = fretTouched[i] + offsets[i];
          break;
        case 2:
          noteFretted[i] = fretTouched[i] + offsets[i];
          break;
      }

      if (stringActive[i]) {

        //turn off the currently active note on that string
        noteOff(0x80 + i, activeNotes[i]->number(), 0);
        free(activeNotes[i]);
      }

      if (!stringActive[i]) {

        //mark string as active
        stringActive[i] = true;
      }
      //register with active notes
      activeNotes[i] = (Note *) malloc(sizeof(Note));

      if (fretTouched[i] > 0) activeNotes[i]->init(noteFretted[i], piezoVals[i], millis(), true);

      else activeNotes[i]->init(noteFretted[i], piezoVals[i], millis(), false);

      //turn on fretted note
      noteOn(0x90 + i, activeNotes[i]->number(), activeNotes[i]->velocity());

      //mark that the string was plucked
      stringPlucked[i] = true;
    }
  }
}

void legatoTest() {
  for (int i = 0; i < N_STR; i++) {
    if (stringActive[i]) {
      switch (i) {
        case 0:
          noteFretted[i] = fretTouched[i] + offsets[i];
          break;
        case 1:
          noteFretted[i] = fretTouched[i] + offsets[i];
          break;
        case 2:
          noteFretted[i] = fretTouched[i] + offsets[i];
          break;
      }

      if (noteFretted[i] != activeNotes[i]->number() && fretTouched[i]) {
        //turn on new note
        int vel = activeNotes[i]->velocity();
        noteOn(0x90 + i, noteFretted[i], vel);

        //turn off old note
        noteOff(0x80 + i, activeNotes[i]->number(), 0);
        free(activeNotes[i]);

        //register new note as the active one
        activeNotes[i] = (Note *) malloc(sizeof(Note));
        activeNotes[i]->init(noteFretted[i], vel, millis(), true);
      }
    }
  }
}
/*


*/
void fullLegato() {
  for (int i = 0; i < N_STR; i++) {
    if (fretTouched[i]) {

      switch (i) {
        case 0:
          noteFretted[i] = fretTouched[i] + offsets[i];
          break;
        case 1:
          noteFretted[i] = fretTouched[i] + offsets[i];
          break;
        case 2:
          noteFretted[i] = fretTouched[i] + offsets[i];
          break;
      }

      int vel = 127;

      if (!stringActive[i]) {
        noteOn(0x90 + i, noteFretted[i], vel);

        //register new note as the active one
        activeNotes[i] = (Note *) malloc(sizeof(Note));
        activeNotes[i]->init(noteFretted[i], vel, millis(), true);
        stringActive[i] = true;
      }
      else {

        if (noteFretted[i] != activeNotes[i]->number()) {
          int vel = 80;
          noteOn(0x90 + i, noteFretted[i], vel);

          //turn off old note
          noteOff(0x80 + i, activeNotes[i]->number(), 0);
          free(activeNotes[i]);

          //register new note as the active one
          activeNotes[i] = (Note *) malloc(sizeof(Note));
          activeNotes[i]->init(noteFretted[i], vel, millis(), true);
        }
      }
    }
  }
}


void cleanUp() {
  for (int i = 0; i < N_STR; i++) {

    //no fret is touched and the string is marked active
    if (!fretTouched[i] && stringActive[i]) {

      //if open string
      if (!activeNotes[i]->fretted()) {
        if (activeNotes[i]->timeActive() > minDurationOpen) {
          //turn off the active note
          noteOff(0x80 + i, activeNotes[i]->number(), 0);

          //mark as inactive
          stringActive[i] = false;
          free(activeNotes[i]);
        }
      }
      else {
        //turn off the active note
        noteOff(0x80 + i, activeNotes[i]->number(), 0);

        //mark as inactive
        stringActive[i] = false;
        free(activeNotes[i]);
      }
    }
  }
}

void readControls() {

  if (altControlSet) {
    minDurationOpen = analogRead(PIN_POT_1);
    minDurationOpen = map(minDurationOpen, 0, 1023, 0, 255 );

    minVelocity = analogRead(PIN_POT_2);
    minVelocity = map(minVelocity, 0, 1023, 0, 127);
  }

  //Potentiometers set the values for controllers 69 and 7
  else {
    int potVal1New = analogRead(PIN_POT_1);
    int potVal2New = analogRead(PIN_POT_2);

    if (abs(potVal1New - potVal1Old) > 30 || potVal1New == 0 || potVal1New == 1023 ) {
      if ((potVal1New - potVal1Old) != 0) {
        //Send MIDI control change message
        int val = map(potVal1New, 0, 1023, 0, 127);
        val = constrain(val, 0, 127);
        controllerChange(69, val);
        potVal1Old = potVal1New;
      }
    }

    if (abs(potVal2New - potVal2Old) > 30 || potVal2New == 0 || potVal2New == 1023) {
      if ((potVal2New - potVal2Old) != 0) {
        //Send MIDI control change message
        int val = map(potVal2New, 0, 1023, 0, 127);
        val = constrain(val, 0, 127);
        controllerChange(7, val);
        potVal2Old = potVal2New;
      }
    }
  }

  //-----ENGAGE FULL LEGATO MODE-----
  //removes the need for triggering with piezo for fretted notes
  if (digitalRead(PIN_BUTTON_LEFT) == LOW && !buttonStates[LEFT]) {
    fullLegatoMode = true;
    buttonStates[LEFT] = true;
  }
  if (digitalRead(PIN_BUTTON_LEFT) == HIGH && buttonStates[LEFT]) {
    fullLegatoMode = false;
    buttonStates[LEFT] = false;
  }

  led = max(led_number[0], led_number[1]);
  Serial.println(led_number[0]);
  //Serial.println(led_number[1]);
  if (led == -1) {
    led = 0;
    onLED(N_PIXELS, 0, 0, 0);
  }

  else {
    led = led + 1;
    led = map(led, 0, N_FRET - 1, 0, N_PIXELS);
    led_color = map(led, 0, 30, 0, 255);
    //Serial.println(led_number);
    if ((millis() - ledDebounceTime ) > ledDebounceDelay) {
      for (int i = 0; i < led; i++) {
        //pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
        pixels.setPixelColor(i, Wheel(led_color));
      }
      if (prev_led > led)
        for (int i = led; i < N_PIXELS; i++) {
          //pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
          pixels.setPixelColor(i, (pixels.Color(0, 0, 0)));
        }
      pixels.show();
      ledDebounceTime = millis();
      prev_led = led ;
    }
  }


  /*
    //switch to alt control set
    if (digitalRead(PIN_BUTTON_LEFT) == LOW && !buttonStates[LEFT]) {
      altControlSet = !altControlSet;
      buttonStates[LEFT] = true;
    }
    if (digitalRead(PIN_BUTTON_LEFT) == HIGH && buttonStates[LEFT]) buttonStates[LEFT] = false;


    //Right button triggers calibration
    if (digitalRead(PIN_BUTTON_RIGHT) == LOW && !buttonStates[RIGHT]) {
      buttonStates[RIGHT] = true;
      calibrate();
    }


  */

  //---- CHANGING THE OCTAVE -------//
  //UP and down buttons used to change offset/octave. Cycles through EAD and GBE like an infinite guitar neck.

  //---- UP BUTTON ----
  if (digitalRead(PIN_BUTTON_UP) == LOW) {
    //change the set of strings
    if (!buttonStates[UP]) {

      octave = octave - 1;

      stringSetLow = !stringSetLow;

      for (int i = 0; i < N_STR; i++) {
        //if low
        if (stringSetLow) {
          offsets[i] = offsets_low[i] + (12 * octave);
        }
        //if high
        if (!stringSetLow) {
          offsets[i] = offsets_high[i] + (12 * octave);
        }
      }
    }

    buttonStates[UP] = true;
  }
  //reset state once button is no longer being pressed
  if (digitalRead(PIN_BUTTON_UP) == HIGH && buttonStates[UP]) buttonStates[UP] = false;

  //----DOWN BUTTON----
  if (digitalRead(PIN_BUTTON_DOWN) == LOW) {
    //change the set of strings
    if (!buttonStates[DOWN]) {

      octave = octave + 1;

      stringSetLow = !stringSetLow;

      for (int i = 0; i < N_STR; i++) {
        //if low
        if (stringSetLow) {
          offsets[i] = offsets_low[i] + (12 * octave);
        }
        //if high
        if (!stringSetLow) {
          offsets[i] = offsets_high[i] + (12 * octave);
        }
      }
    }

    buttonStates[DOWN] = true;
  }
  //reset state once button is no longer being pressed
  if (digitalRead(PIN_BUTTON_DOWN) == HIGH && buttonStates[DOWN]) buttonStates[DOWN] = false;

  //switch stick to xy mode
  if (digitalRead(PIN_BUTTON_RIGHT) == LOW && !buttonStates[RIGHT]) {
    stickXY = !stickXY;
    buttonStates[RIGHT] = true;
  }
  if (digitalRead(PIN_BUTTON_RIGHT) == HIGH && buttonStates[RIGHT]) buttonStates[RIGHT] = false;

  //--------JOYSTICK-------//
  /* Click down the joystick to activate it. In regular mode it will read absolute position from the
     center in any direction (sends to modwheel, MIDI controller 1), and in XY mode the x axis
     sends to controller 2 (breath) and the y axis sends to controller 4 (foot).  */

  if (digitalRead(PIN_BUTTON_STICK) == LOW) {
    //activate joystick
    if (!buttonStates[STICK]) {
      //make sure modwheel value is set to 0 when stick is off
      if (stickActive) controllerChange(1, 0);
      stickActive = !stickActive;
    }
    buttonStates[STICK] = true;
  }
  //reset once stick is no longer being pressed
  if (digitalRead(PIN_BUTTON_STICK) == HIGH && buttonStates[STICK]) buttonStates[STICK] = false;

  if (stickActive) {
    //read positions from center
    float xPos = map(analogRead(PIN_JOYSTICK_X), stickZeroX, 1023, 0, 127);
    float yPos = map(analogRead(PIN_JOYSTICK_Y), stickZeroY, 1023, 0, 127);

    //get absolute position from center
    float z = sqrt(sq(xPos) + sq(yPos));
    int stickVal = (int)constrain(z, 0, 127);

    if (stickVal > 0) {
      stickState = true;
      if (stickXY) {
        controllerChange(2, abs(xPos));
        controllerChange(4, abs(yPos));
      }
      else controllerChange(1, stickVal);
    }
    else if (stickState && stickVal == 0) {
      stickState = false;
      if (stickXY) {
        controllerChange(2, 0);
        controllerChange(4, 0);
      }
      else controllerChange(1, 0);
    }
  }
}

//----CALIBRATION----//
/* Likely will only have to calibrate once. This is done by activating calibration mode and
   "plucking" each note on each string starting with the upper bound (after the 21st fret) and descending down
   to just after the 1st fret. Starts with the low E string, then the A string and then the D string.
   fret definitions are stored in EEPROM. Once it is calibrated for the voltage put out by the MIDI --> USB board
   you can just have the calibration button do something else because you probably won't need it again.
*/
void unset(int i) {
  //this function doesn't even do anything!!
}

void calibrate() {

  Serial.println("calibrating...");

  for (int i = 0; i < N_STR; i++) {
    //Flash the LED too indicate calibration
    /*
      digitalWrite(PIN_LED, HIGH);
      delay(100);
      digitalWrite(PIN_LED, LOW);
      delay(100);
      digitalWrite(PIN_LED, HIGH);
      delay(100);
      digitalWrite(PIN_LED, LOW);
      delay(100);
      digitalWrite(PIN_LED, HIGH);
    */
    //Flash the LED too indicate calibration
    onLED(10, 250, 0, 0);
    delay(100);
    clrLED();
    onLED(10, 250, 0, 0);
    delay(100);
    clrLED();
    onLED(10, 250, 0, 0);
    delay(100);
    clrLED();

    int sensorMax = 0;
    int sensorMin = 1023;
    int val;

    //loop through the array of fret definitions
    for (int j = N_FRET; j > 0; j--) {

      int response = false;
      //wait for response
      Serial.println("waiting");
      //wait for response
      while (!response) {

        //read piezo val
        int piezoVal = analogRead(piezoPins[i]);

        //get the sensor min value (highest fret) on the first round
        if (j == N_FRET) {
          int fretVal = analogRead(softPotPins[i]);
          if (fretVal > sensorMax) (sensorMax = fretVal);
          clrLED();
          //if the piezo is hit, register this as the definition for this fret
          if (piezoVal > PIEZO_THRESHOLD_ON) {
            int fretVal = analogRead(softPotPins[i]);
            sensorMin = fretVal;
            val = fretVal;
            response = true;
            clrLED();
            /*   int addr = j * sizeof(short) + (N_FRET*i*sizeof(short));
               Serial.print("Writing ");
               Serial.print(val);
               Serial.print(" to address: ");
               Serial.println(addr);
               EEPROM.write(addr, val); */
          }
        }

        else {
          //get the rest of the fret definitions
          //if the piezo is hit, register this as the definition for this fret
          if (piezoVal > PIEZO_THRESHOLD_ON) {
            int fretVal = analogRead(softPotPins[i]);
            fretVal = map(fretVal, sensorMin, sensorMax, 0, 255);
            fretVal = constrain(fretVal, 0, 255);
            val = fretVal;
            response = true;
            clrLED();
          }
        }
      }

      //write to memory
      digitalWrite(PIN_LED, LOW);
      EEPROM.write(j + (N_FRET * i), val);
      Serial.println(val);
      delay(100);
      onLED(10, 250, 0, 0);
      //      delay(100);
      digitalWrite(PIN_LED, HIGH);
    }


    //update global definitions
    calibrationMin[i] = EEPROM.read(N_FRET + (N_FRET * i));
    Serial.print(21 + (21 * i)); Serial.print(" -cal- ");  Serial.println(calibrationMin[i]);
    for (int j = 1; j < 22; j++) {
      fretDefs[i][j] = EEPROM.read(j + (21 * i));
      Serial.print("EEPROM.read(");
      Serial.print(j);
      Serial.print(" + (21 * ");
      Serial.print(i);
      Serial.print("))");
      Serial.print(" EEPROM.read(");
      Serial.print(j + (21 * i));
      Serial.print(")");

      Serial.print(" -fret- ");
      Serial.print("fretDefs[");
      Serial.print(i);
      Serial.print("][");
      Serial.print(j);
      Serial.print("]=");
      Serial.println(fretDefs[i][j]);
    }
    clrLED();
  }
  delay(100);
  onLED(10, 250, 0, 0);
  buttonStates[RIGHT] = false;
  digitalWrite(PIN_LED, LOW);
}
void onLED(int led, int red, int green, int blue) {
  for (int i = 0; i < N_STR; i++) {

    //pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
    pixels.setPixelColor(i, pixels.Color(red, green, blue));
  }
  pixels.show();
}

void clrLED() {
  for (int i = 0; i < N_PIXELS; i++) {
    pixels.setPixelColor(i, pixels.Color(0, 0, 0)); // turn off
  }
  pixels.show();
}
//-------------MIDI functions-----------------

//note-on message
void noteOn(int cmd, int pitch, int velocity) {

  Serial1.write(byte(cmd));
  Serial1.write(byte(pitch));
  Serial1.write(byte(velocity));
  digitalWrite(PIN_LED, HIGH);
}
//note-off message
void noteOff(int cmd, int pitch, int velocity) {

  Serial1.write(byte(cmd));
  Serial1.write(byte(pitch));
  Serial1.write(byte(0));
  digitalWrite(PIN_LED, LOW);
}

//Sends controller change to the specified controller
void controllerChange(int controller, int value) {
  Serial1.write(byte(0xb0));
  Serial1.write(byte(controller));
  Serial1.write(byte(value));

  Serial1.write(byte(0xb1));
  Serial1.write(byte(controller));
  Serial1.write(byte(value));

  Serial1.write(byte(0xb2));
  Serial1.write(byte(controller));
  Serial1.write(byte(value));
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if (WheelPos < 85) {
    return pixels.Color(255 - WheelPos * 3 + pitchBendLight, 0, WheelPos * 3 + pitchBendLight);
  }
  if (WheelPos < 170) {
    WheelPos -= 85;
    return pixels.Color(0, WheelPos * 3 + pitchBendLight , 255 - WheelPos * 3 + pitchBendLight);
  }
  else {
    WheelPos -= 170;
    return pixels.Color(WheelPos * 3 + pitchBendLight , 255 - WheelPos * 3 + pitchBendLight , 0 );
  }
  if (mod_final > 50) {
  }
}
[/code]

And the results from the serial monitor EEPROM contents with the above changes:

EEPROM.read(1 + (21 * 0)) EEPROM.read(1) -fret- fretDefs[0][1]=255
EEPROM.read(2 + (21 * 0)) EEPROM.read(2) -fret- fretDefs[0][2]=255
EEPROM.read(3 + (21 * 0)) EEPROM.read(3) -fret- fretDefs[0][3]=255
EEPROM.read(4 + (21 * 0)) EEPROM.read(4) -fret- fretDefs[0][4]=255
EEPROM.read(5 + (21 * 0)) EEPROM.read(5) -fret- fretDefs[0][5]=255
EEPROM.read(6 + (21 * 0)) EEPROM.read(6) -fret- fretDefs[0][6]=255
EEPROM.read(7 + (21 * 0)) EEPROM.read(7) -fret- fretDefs[0][7]=255
EEPROM.read(8 + (21 * 0)) EEPROM.read(8) -fret- fretDefs[0][8]=255
EEPROM.read(9 + (21 * 0)) EEPROM.read(9) -fret- fretDefs[0][9]=248
EEPROM.read(10 + (21 * 0)) EEPROM.read(10) -fret- fretDefs[0][10]=236
EEPROM.read(11 + (21 * 0)) EEPROM.read(11) -fret- fretDefs[0][11]=225
EEPROM.read(12 + (21 * 0)) EEPROM.read(12) -fret- fretDefs[0][12]=208
EEPROM.read(13 + (21 * 0)) EEPROM.read(13) -fret- fretDefs[0][13]=192
EEPROM.read(14 + (21 * 0)) EEPROM.read(14) -fret- fretDefs[0][14]=176
EEPROM.read(15 + (21 * 0)) EEPROM.read(15) -fret- fretDefs[0][15]=161
EEPROM.read(16 + (21 * 0)) EEPROM.read(16) -fret- fretDefs[0][16]=140
EEPROM.read(17 + (21 * 0)) EEPROM.read(17) -fret- fretDefs[0][17]=114
EEPROM.read(18 + (21 * 0)) EEPROM.read(18) -fret- fretDefs[0][18]=83
EEPROM.read(19 + (21 * 0)) EEPROM.read(19) -fret- fretDefs[0][19]=51
EEPROM.read(20 + (21 * 0)) EEPROM.read(20) -fret- fretDefs[0][20]=24
EEPROM.read(21 + (21 * 0)) EEPROM.read(21) -fret- fretDefs[0][21]=20
21 -cal- 20
EEPROM.read(1 + (21 * 1)) EEPROM.read(22) -fret- fretDefs[1][1]=255
EEPROM.read(2 + (21 * 1)) EEPROM.read(23) -fret- fretDefs[1][2]=255
EEPROM.read(3 + (21 * 1)) EEPROM.read(24) -fret- fretDefs[1][3]=255
EEPROM.read(4 + (21 * 1)) EEPROM.read(25) -fret- fretDefs[1][4]=255
EEPROM.read(5 + (21 * 1)) EEPROM.read(26) -fret- fretDefs[1][5]=255
EEPROM.read(6 + (21 * 1)) EEPROM.read(27) -fret- fretDefs[1][6]=255
EEPROM.read(7 + (21 * 1)) EEPROM.read(28) -fret- fretDefs[1][7]=242
EEPROM.read(8 + (21 * 1)) EEPROM.read(29) -fret- fretDefs[1][8]=226
EEPROM.read(9 + (21 * 1)) EEPROM.read(30) -fret- fretDefs[1][9]=212
EEPROM.read(10 + (21 * 1)) EEPROM.read(31) -fret- fretDefs[1][10]=198
EEPROM.read(11 + (21 * 1)) EEPROM.read(32) -fret- fretDefs[1][11]=182
EEPROM.read(12 + (21 * 1)) EEPROM.read(33) -fret- fretDefs[1][12]=164
EEPROM.read(13 + (21 * 1)) EEPROM.read(34) -fret- fretDefs[1][13]=146
EEPROM.read(14 + (21 * 1)) EEPROM.read(35) -fret- fretDefs[1][14]=127
EEPROM.read(15 + (21 * 1)) EEPROM.read(36) -fret- fretDefs[1][15]=112
EEPROM.read(16 + (21 * 1)) EEPROM.read(37) -fret- fretDefs[1][16]=97
EEPROM.read(17 + (21 * 1)) EEPROM.read(38) -fret- fretDefs[1][17]=84
EEPROM.read(18 + (21 * 1)) EEPROM.read(39) -fret- fretDefs[1][18]=66
EEPROM.read(19 + (21 * 1)) EEPROM.read(40) -fret- fretDefs[1][19]=47
EEPROM.read(20 + (21 * 1)) EEPROM.read(41) -fret- fretDefs[1][20]=23
EEPROM.read(21 + (21 * 1)) EEPROM.read(42) -fret- fretDefs[1][21]=59
42 -cal- 59
EEPROM.read(1 + (21 * 2)) EEPROM.read(43) -fret- fretDefs[2][1]=255
EEPROM.read(2 + (21 * 2)) EEPROM.read(44) -fret- fretDefs[2][2]=255
EEPROM.read(3 + (21 * 2)) EEPROM.read(45) -fret- fretDefs[2][3]=255
EEPROM.read(4 + (21 * 2)) EEPROM.read(46) -fret- fretDefs[2][4]=255
EEPROM.read(5 + (21 * 2)) EEPROM.read(47) -fret- fretDefs[2][5]=255
EEPROM.read(6 + (21 * 2)) EEPROM.read(48) -fret- fretDefs[2][6]=255
EEPROM.read(7 + (21 * 2)) EEPROM.read(49) -fret- fretDefs[2][7]=248
EEPROM.read(8 + (21 * 2)) EEPROM.read(50) -fret- fretDefs[2][8]=233
EEPROM.read(9 + (21 * 2)) EEPROM.read(51) -fret- fretDefs[2][9]=216
EEPROM.read(10 + (21 * 2)) EEPROM.read(52) -fret- fretDefs[2][10]=203
EEPROM.read(11 + (21 * 2)) EEPROM.read(53) -fret- fretDefs[2][11]=184
EEPROM.read(12 + (21 * 2)) EEPROM.read(54) -fret- fretDefs[2][12]=168
EEPROM.read(13 + (21 * 2)) EEPROM.read(55) -fret- fretDefs[2][13]=151
EEPROM.read(14 + (21 * 2)) EEPROM.read(56) -fret- fretDefs[2][14]=136
EEPROM.read(15 + (21 * 2)) EEPROM.read(57) -fret- fretDefs[2][15]=119
EEPROM.read(16 + (21 * 2)) EEPROM.read(58) -fret- fretDefs[2][16]=104
EEPROM.read(17 + (21 * 2)) EEPROM.read(59) -fret- fretDefs[2][17]=86
EEPROM.read(18 + (21 * 2)) EEPROM.read(60) -fret- fretDefs[2][18]=65
EEPROM.read(19 + (21 * 2)) EEPROM.read(61) -fret- fretDefs[2][19]=45
EEPROM.read(20 + (21 * 2)) EEPROM.read(62) -fret- fretDefs[2][20]=22
EEPROM.read(21 + (21 * 2)) EEPROM.read(63) -fret- fretDefs[2][21]=24
63 -cal- 24