A few hex midi notes on A4 and A5 aren't playing the proper note

Ive started trying to make this work:

We exchanged a few emails a couple of weeks ago when I asked him about his project, but so far he hasnt responded to my most current email about this.

Basically the 12 frets are wired up to be a bottom section of a voltage divider circuit, for the top section of the voltage divider I have 6 resistors of the same value which are also attached to steel strings on the guitar(the strings are A0-A5). this makes for a unique analog value per string, per fret, that the Arduino reads and translates to a midi note.

Ive modified the code so it works with 12 frets and all 6 strings. I also had to update the code to work with the current IDE version(a few minor things having to do with the BYTE command). The first four strings E,A,D,G work perfectly and play the correct notes according to the voltage divider values I soldered to the guitar and assigned to the my table.

The B and high e string on the other hand are giving me a few issues and I cant seem to figure them out

The high e string's notes SHOULD be as follows: F, F# ,G ,G# ,A ,A# ,B ,C ,C# ,D, D#, and E.

The notes I'm getting for high e are: F#, G, G, G#, A, A#, B, C, C#, D, D#,and E.

I'm having a similar problem with the b string,
It SHOULD read: C, C#, D, D#, E, F, F#, G, G#, A, A#, and B.

But again im getting: C#, D, D#, E, F, F#,G, G, G#, A, A#, and B.

Notice how both strings are starting a sharp too high, and how there are double Gs on each string.
The hex table is correct, all of my resistor readings are correct and the E,A,D,G strings are reading the correct notes across all of the frets, so it cant really be an incorrect resistance value issue of some sort.

I tried the arduino with different guitars, different strings, having all the strings being the same gauge, I've tried altering the code, but when i do it alters the the four working strings as well as the two non-working ones.

/* Monohonic MIDI Guitar Project

Description:
Guitar that is accompanied by a synthesizer while being played. Only
one not at a time is to be played (for the time being);
The guitar functions best as a monophonic guitar
but it can play more than one note. This is due to it's current resistance
reading setup. So it is a cross between polyphonic and monophonic;

Psuedo Code Approach:

-Read and store analog-in values from each of the strings
(E, A, D, G, B, e);
Determine which note is being played on each string;
Convert notes-analog-value to hexadecimal MIDI value;
Output MIDI

-The Array AF set is "variable" in the sense that it depends on the resistances you have
chosen to solder to the frets. I have already calculated and measured what the analog
reading will be. Since the same input resistance is used, analog readings for all
strings are the same. These values are not the exact measured value, padding has been applied arbitrarily to
make sure that the desired note, when pressed, is chosen correctly. To summarize, there
has been a percentage error or tolerance that needs to be accounted for.
[floor(tolerance(analog-in(fret1))), floor(tolerance(analog-in(fret2))), ... cont'd (12)]

MIDI Conversion Chart:
Guitar, up to the 12th fret plays from E2 - E5
String (open)
[Pitch - Frets 1 to 12]
[MIDI - 0x prefix (HEX)]

E(E2):
[F2, Gb2, G2, Ab2, A2, Bb2, B2, C3, Db3, D3, Eb3, E3]
[29, 2A, 2B, 2C, 2D, 2E, 2F, 30, 31, 32, 33, 34]

A(A2):
[Bb2, B2, C3, Db3, D3, Eb3, E3, F3, Gb3, G3, Ab3, A3]
[ 2E, 2F, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39]

D(D3):
[Eb3, E3, F3, Gb3, G3, Ab3, A3, Bb3, B3, C4, Db4, D4]
[ 33, 34, 35, 36, 37, 38, 39, 3A, 3B, 3C, 3D, 3E]

G(G3):
[Ab3, A3, Bb3, B3, C4, Db4, D4, Eb4, E4, F4 Gb4, G4 ]
[ 38, 39, 3A, 3B, 3C, 3D, 3E, 3F, 40, 41, 42, 43 ]

B(B3)
[C4, Db4, D4, Eb4, E4, F4 Gb4, G4, Ab4, A4, Bb4, B4 ]
[3C, 3D, 3E, 3F, 40, 41, 42, 43, 44, 45, 46, 47 ]

e(E4)
[F4, Gb4, G4, Ab4, A4, Bb4, B4, C5, Db5, D5, Eb5, E5]
[41, 42, 43, 44, 45, 46, 47, 48, 49, 4A, 4B, 4C]

*/
/* my resistor values=801,761,716,666,609,545,475,399,320,238,156,76*/
const int AF[12] = {780,760,710,660,600,540,470,390,310,230,150,70} ;
const int midiNotesHex[37] = {0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34,
0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43,
0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C}; //All the notes from F2-C4
const int analogPins[6] = {A0, A1, A2, A3, A4, A5};
const int playNote = 0x90;
const int stopNote = 0x80;
const int velocity = 0x50;


//----Variables-------
int analogString[6] = {1023, 1023, 1023, 1023, 1023, 1023}; // [E, A, D, G, B, e] stores values 0 - 1023 bits
int midiNotesOut[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; //Midi notes that will be played
int prevNotesOut[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; //Notes from previous round
int marker[6] = {0, 0, 0, 0, 0, 0};
int average[1000];



#include <MIDI.h>

void setup() {
MIDI.begin();
//This makes sure all sounds/tones are off
for(int x = 0; x < 37; x++){
MIDIOutput( stopNote, midiNotesHex[x], velocity);
}
}


void loop(){
float delay(.7);
for( int x = 0; x < 6; x++){
int temp = 0;
prevNotesOut[x] = midiNotesOut[x];
for( int ave = 0; ave < 30; ave++){
analogString[x] = analogRead(analogPins[x]); //
temp = temp+analogString[x];
}
analogString[x] = temp/30;

if(analogString[x] < 830){
  
for( int y = 0; y < 12; y++){ //find the fret position (8 is AF length)
if(analogString[x] > AF[y]){
midiNotesOut[x] = midiNotesHex[y+x*5]; //Pull the hex note from the table
y = 12; // Break out of the loop
marker[x] = 1;
}
}//inner for
}else if(analogString[x] > 850){
  
if ((marker[x] == 1)){
MIDIOutput( stopNote, midiNotesOut[x], 0x00);
marker[x] = 0;
}
midiNotesOut[x] = 0x00;

}

if((prevNotesOut[x] != midiNotesOut[x]) && (midiNotesOut[x] != 0x00)){
if(prevNotesOut[x] != 0x00){
MIDIOutput( stopNote, prevNotesOut[x], 0x00);
}
MIDIOutput( playNote, midiNotesOut[x], velocity);

}
}//outter for
}//loop

void MIDIOutput( int command, int note, int velocity){
  Serial.write(command);
  Serial.write(note);
  Serial.write(velocity);
}

Have you checked the actual values that you get from analogRead() ?

By the way, I assume that   float delay(.7); is meant to delay for 0.7 of a millisecond, but it won't because delay() takes an unsigned long integer as its argument and why did you preceeded it with float which prevents the delay working anyway, although it does compile.

Have you got a schematic of how it is wired up along with the resistor values you have used?

UKHeliBob:
Have you checked the actual values that you get from analogRead() ?

By the way, I assume that   float delay(.7); is meant to delay for 0.7 of a millisecond, but it won't because delay() takes an unsigned long integer as its argument and why did you preceeded it with float which prevents the delay working anyway, although it does compile.

no delay causes some external hardware bounce(strings pressing downs on the frets caused a slight bounce)

a delay(1) was causing an input delay that was slightly too long when I played notes quickly, it caused the notes to bleed into each other.

float delay(.7) seemed to be just enough delay to allow me to play quickly without bleed, but it seems like it was just my imagination hah. I used to the float so i could make it less than a value of one.

Grumpy_Mike:
Have you got a schematic of how it is wired up along with the resistor values you have used?

yes, here are the values and schematic

these are the values on the resistors:

r1= 82k
r2=68k
r3=56k
r4=47k
r5=39k
r6=33k
r7=27k
r8=22k
r9=18k
r10=15k
r11=12k
r12=10k

each string has a 120k resistor on it completing the top section of the voltage divider.

I also have 104 caps on each of the strings before the 120k resistors going to ground(they smooth the analog reading of each string).

Thanks for the schematic.

I used to the float so i could make it less than a value of one.

Yes but it won't work.
If you want a delay less than a millisecond use delayMicroseconds()

Grumpy_Mike:
Thanks for the schematic.

I used to the float so i could make it less than a value of one.

Yes but it won't work.
If you want a delay less than a millisecond use delayMicroseconds()

Excellent, thank you. I wasn't aware of this.

Does your string only touch one fret? I think it does not. Therefore when the higher frets are used then a lot of the fret resistors are in parallel effectively reducing their resistance.
Also other strings touching frets will effect the values received by a string, they form convoluted conduction paths.
I don't think this can work for anything but a monophonic situation.

float delay(.7) seemed to be just enough delay to allow me to play quickly without bleed, but it seems like it was just my imagination hah. I used to the float so i could make it less than a value of one.

The value in the parentheses would have been rounded to 0 IF a function call had actually been made.

The float in front told the compiler that you were defining the prototype for a new function, NOT calling an existing one. That code caused absolutely NO delay.

Grumpy_Mike:
Does your string only touch one fret? I think it does not. Therefore when the higher frets are used then a lot of the fret resistors are in parallel effectively reducing their resistance.
Also other strings touching frets will effect the values received by a string, they form convoluted conduction paths.
I don't think this can work for anything but a monophonic situation.

actually yes, when pressing down on any fret except fret 1, the two resistors attached to that fret (and only those two) come into play. when a note is pressed the voltage divider is comprised of the 120k ohm going to 5v and the 2 fret resistors in parallel(making up the bottom voltage divider value). The only notes that use one resistor are the notes across fret 1.

Its a mix between monophonic and polyphonic, i can play multiple notes as long as they are a whole fret apart...but thats an issue ill have to fix once I correct this current issue. If I play each note on each fret individually, i am presented with the problem in the OP.

Have you done the thing from reply #1

Have you checked the actual values that you get from analogRead() ?

If so what readings did you get?

Grumpy_Mike:
Have you done the thing from reply #1

Have you checked the actual values that you get from analogRead() ?

If so what readings did you get?

Oh sorry yes i did, they are as follows:

801,761,716,666,609,545,475,399,320,238,156,76

These are the analog values i get when testing using the analog read function.
801 being when my finger is on the first fret, 761 when my finger is on the second fret and so on, all the way down to 76 on fret 12

I can't see anything obviously wrong but it is hard because the code is unnecessarily complicated.

For example:-

analogString[x] = analogRead(analogPins[x]);

why not

analogString[x] = analogRead(x);

Why use a look up table

const int midiNotesHex[37] = {0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34,
0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43,
0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C}; //All the notes from F2-C4

if the result is only going to be your index plus 0x29.

the thresholds look a bit close to the readings, try spreading them out.

const int AF[12] = {780,760,710,660,600,540,470,390,310,230,150,70} ;
   your readings      801,761,716,666,609,545,475,399,320,238,156,76

Do not do this:-

int temp = 0;

You are creating multiple variables. Just

temp = 0;

is good enough with

int temp = 0;

only at the start of the function.
Try some debug prints to see if the readings actually are producing the right MIDI notes

Grumpy_Mike:
I can't see anything obviously wrong but it is hard because the code is unnecessarily complicated.

For example:-

analogString[x] = analogRead(analogPins[x]);

why not

analogString[x] = analogRead(x);

Why use a look up table

const int midiNotesHex[37] = {0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34,

0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43,
0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C}; //All the notes from F2-C4



if the result is only going to be your index plus 0x29.

the thresholds look a bit close to the readings, try spreading them out.


const int AF[12] = {780,760,710,660,600,540,470,390,310,230,150,70} ;
   your readings      801,761,716,666,609,545,475,399,320,238,156,76




Do not do this:-


int temp = 0;



You are creating multiple variables. Just


temp = 0;



is good enough with


int temp = 0;



only at the start of the function.
Try some debug prints to see if the readings actually are producing the right MIDI notes

thanks for all of your input, I really appreciate it. Im going to implement everything you suggested, i just have a few questions.

  1. how do I know how far I can space the thresholds in relation to the readings?(i just kinda guessed, I didn't really have a method to how much i spaced them out).

  2. I never not considered using the note look up table, but index plus 0x29 sounds way simpler. I'll try to rewrite working that concept in instead of the table.

  3. Well the notes I had correct(and incorrect)in the OP were verified using a MIDI monitor program and logic studio pro on my macbook.

Set the threshold values to be the values between your readings. So if you gave readings of 100 and 200 you would set the threshold exactly half way between the two at 150.
Using MIDI can make debugging difficult so for the testing just serial print the numbers in hex. Only when you have got it working right should you switch to the MIDI baud rate and the serial write.

Grumpy_Mike:
Set the threshold values to be the values between your readings. So if you gave readings of 100 and 200 you would set the threshold exactly half way between the two at 150.
Using MIDI can make debugging difficult so for the testing just serial print the numbers in hex. Only when you have got it working right should you switch to the MIDI baud rate and the serial write.

ok i will adjust the thresholds, thank you for clarifying. Just out of curiosity, what makes midi harder to work with for debugging rather than serial?

what makes midi harder to work with for debugging rather than serial?

Because you can't print out messages like "I am in this function now" or "the value of the Val variable is ..",
all you can do is to send MIDI messages which have limited scope.
In your case you want to print out each variable that makes up the note look up table index along with the reading you have from the string in order to see why it is producing the wrong note.

Grumpy_Mike:

what makes midi harder to work with for debugging rather than serial?

Because you can't print out messages like "I am in this function now" or "the value of the Val variable is ..",
all you can do is to send MIDI messages which have limited scope.
In your case you want to print out each variable that makes up the note look up table index along with the reading you have from the string in order to see why it is producing the wrong note.

ah ok that makes sense. Thank you.

I figured out 1 of the problems with some help from the guy whos blog i got this from...Somehow i missed that there were two 0x43's right next to each other in the look up table...which was obviously giving a double G reading....I swear I went up and down every inch of that code 50 times before posting it on here. Embarrassing, but i guess it took a fresh pair of eyes.

I am still having the issue of on the last two strings (B and high e) starting a fret lower than they should be, for example on fret1 of the high e string, its giving me F#, when it should be giving me F.

the b string is giving me C# when it should be giving me C.

any input has been and will be appreciated!

You need to print out the readings you are getting. It could be that these two strings are actually reading differently to the others.