Guitar Midi Controller - Question about defining string banks

Hello everyone,

I am very new to this forum, to Arduino, and to coding. That said, I am not new to electronics in general.

My interests mostly lie with the electric guitar, and that is what drew me here. A dream. To make an uber-midi synth guitar.

Along that road to progress, I have aqcuired a Power Gig Playstation controller which consists of a short-scale plastic fingerboard with divided frets and a circuit board which turns each fret into a switch and embeds them in a standard diode bridge keyboard matrix. Pictures included for the curious. It also has a hexatonic pickup, but that is another story for a later day.

I found this post: http://www.cibomahto.com/2010/01/converting-an-old-organ-to-midi/

Here, Matt Metts is using a simple program to convert an old analog organ keyboard to output midi signals. His code and schematic are right on that page. I have got most of the code in order, but I am having trouble with this bit:

// Set up the instrument data for the keys

// first off, clear everything.
for (unsigned char bank = 0; bank < numKeyBanks; bank ++) {
for (unsigned char key = 0; key < numKeysPerBank; key++) {
noteChannels[bank][key] = 0;
noteValues[bank][key] = 0;
}
}

// The bottom half of the keyboard comprised of banks 4-6, starting at F
unsigned char noteValue = 24; // Octave 2, C note
for (unsigned char bank = 4; bank < 7; bank ++) {
for (unsigned char key = 0; key < 12; key++) {
noteChannels[bank][key] = keyboardChannel;
noteValues[bank][key] = noteValue++;
}
}

// The top keyboard row is comprised of banks 0-3, starting at F
for (unsigned char bank = 0; bank < 4; bank ++) {
for (unsigned char key = 0; key < 12; key++) {
noteChannels[bank][key] = keyboardChannel;
noteValues[bank][key] = noteValue++;
}
}

I know this is a newbie question, but I have been reading C++ tutorials and I cannot figure out how to change this so as to define each string as a separate bank starting on their respective midi notes (i.e. string 6 = E = 40; string 5 = A = 45; etc.).

Can anyone give me a hint as to how to do this? I know that I am showing my ignorance, but I do not know how to look this up otherwise.

Thanks

Dave

I know this is a newbie question,

No it is not. That is some code you are getting into.
It is hard to say as you have only posted a bit of your code but the first thing that springs to mind is to use a three dimensional array.
So instead of:-

noteValues[bank][key] = noteValue++;

you would have an extra nested for loop and use:-

 for (int bank = 0; bank < 4; bank ++) {
    for (int key = 0; key < 12; key++) {
      for (int string = 0; key < 6; string++) {
      noteChannels[string][bank][key] = keyboardChannel;
      noteValues[string][bank][key] = noteValue++;
    }
 }
}

First off, let me post the code in its entirety. I didn’t want to because it isn’t mine per say, but belongs to Matt Mets:

// Sketch to convert an older electric organ (Eminent S20) into a MIDI instrument.
// By Matt Mets, completed in 2009
//
// This code is released into the public domain.  Attribution is appreciated.
//
// MIDI source code from the ITP website:
// http://itp.nyu.edu/physcomp/Labs/MIDIOutput
 
#include <Wire.h>
 
 
#define LEDpin 13                  // Just the standard output LED
#define volumePedal 1              // The analog input for the volume control
 
char velocity;                     // Use the foot pedal to determine this
 
// Define the MIDI channels that each instrument transmits on
#define keyboardChannel 0
 
// Number of key banks to scan.  There are eight 'normal' key banks, and 2 special ones.
#define numKeyBanks 6
#define numKeysPerBank 12
 
// Lookup table, used to determine the select line to turn on to read the keys in that key bank.
static char keyBankSelectLines[] = {2,3,4,5,6,7};
 
// Storage for the previous value of each bank of keys.  There are 10 access lines, with a maximum of 12 inputs per line.
// The 12 bits of data on each line are split into low and high banks.
unsigned char noteStatesL[numKeyBanks];
unsigned char noteStatesH[numKeyBanks];
 
// Storage for the instrument data associated with each key.  Must be filled in at startup.
unsigned char noteChannels[numKeyBanks][numKeysPerBank];
unsigned char noteValues[numKeyBanks][numKeysPerBank];
 
 
// Initialize IO ports
void setup()
{
  // Setup the I2C bus (analog pins 4&5) in master mode.  This bus is used to talk to the IO expander chips.
  Wire.begin();
 
  //  Set the serial port to the correct baud rate for MIDI
  Serial.begin(31250);
 
  // Set all initial note bank vales to 0
  for (unsigned int i = 0; i < numKeyBanks; i++) {
    noteStatesL[i] = 0;
    noteStatesH[i] = 0;
  }
 
  pinMode(LEDpin, OUTPUT);    // Status LED
 
  // Set all of the bank select lines to outputs
  for (unsigned char bankNo = 0; bankNo < numKeyBanks; bankNo++) {
    pinMode(keyBankSelectLines[bankNo], OUTPUT);
  }
 
  // Set up the instrument data for the keys
 
  // first off, clear everything.
  for (unsigned char bank = 0; bank < numKeyBanks; bank ++) {
    for (unsigned char key = 0; key < numKeysPerBank; key++) {
      noteChannels[bank][key] = 0;
      noteValues[bank][key] = 0;
    }
  }
 
  // The bottom half of the keyboard comprised of banks 4-6, starting at F
  unsigned char noteValue = 24;    // Octave 2, C note
  for (unsigned char bank = 4; bank < 7; bank ++) {
    for (unsigned char key = 0; key < 12; key++) {
      noteChannels[bank][key] = keyboardChannel;
      noteValues[bank][key] = noteValue++;
    }
  }
 
  // The top keyboard row is comprised of banks 0-3, starting at F
  for (unsigned char bank = 0; bank < 4; bank ++) {
    for (unsigned char key = 0; key < 12; key++) {
      noteChannels[bank][key] = keyboardChannel;
      noteValues[bank][key] = noteValue++;
    }
  }
  // And one extra one on bank 9 note 1
  //noteChannels[7][1] = keyboardChannel;
  //noteValues[7][1] = noteValue++;
}
 
//  Send a MIDI command.
//  cmd is the command and channel (0x90 for channel 1 note on)
//  data1 is the note
//  data2 is the velocity
void midiCommand(char cmd, char data1, char data2) {
  Serial.print(cmd, BYTE);
  Serial.print(data1, BYTE);
  Serial.print(data2, BYTE);
}
 
// Map an integer into a charater given a set range
unsigned char mapInteger(int input, int min, int max) {
  return (((input - min)*255)/(max-min));
}
 
 
// Main loop
unsigned char newNoteStateL;
unsigned char newNoteStateH;
 
void loop()
{ 
  // Read the velocity in
//  velocity = mapInteger(analogRead(volumePedal),400,900);
  velocity = 90;
 
  for (char bankNo = 0; bankNo < numKeyBanks; bankNo++) {
 
    digitalWrite(keyBankSelectLines[bankNo], HIGH);    // Select the key bank
 
    Wire.requestFrom(0x38, 1);                      // Read the low data
    while (Wire.available()) {
      newNoteStateL = Wire.receive();
    }
 
    Wire.requestFrom(0x39, 1);                      // Read the high data
    while (Wire.available()) {
      newNoteStateH = Wire.receive();
    }
 
    digitalWrite(keyBankSelectLines[bankNo], LOW);     // Deselect the key bank
 
    if (newNoteStateL != noteStatesL[bankNo]) {      // Check if any notes in this bank are different
      char stateDelta = newNoteStateL ^ noteStatesL[bankNo];
      for (unsigned char i = 0; i < 8; i++) {
        if ((stateDelta >> i) & 1) {
          if ((newNoteStateL >> i) & 1) {
            // Send a MIDI on message
            midiCommand(0x90 + noteChannels[bankNo][i], noteValues[bankNo][i], velocity);
          }
          else {
            // Send a MIDI off message
            midiCommand(0x80 + noteChannels[bankNo][i], noteValues[bankNo][i], velocity);
          }
        }
      }
    }
 
    if (newNoteStateH != noteStatesH[bankNo]) {      // Check if any notes in this bank are different
      digitalWrite(LEDpin, HIGH);
      char stateDelta = newNoteStateH ^ noteStatesH[bankNo];
      for (unsigned char i = 0; i < 8; i++) {
        if ((stateDelta >> i) & 1) {
          if ((newNoteStateH >> i) & 1) {
            // Send a MIDI on message
            midiCommand(0x90 + noteChannels[bankNo][i+8], noteValues[bankNo][i+8], velocity);
          }
          else {
            // Send a MIDI off message
            midiCommand(0x80 + noteChannels[bankNo][i+8], noteValues[bankNo][i+8], velocity);
          }
        }
      }
    }

    noteStatesL[bankNo] = newNoteStateL;
    noteStatesH[bankNo] = newNoteStateH;
  }
}

Thanks for the reply Grumpy_Mike. Do I need a three dimensional array? There are still only two parameters, lines (frets) and rows (strings). Is there a way to address each row or bank and define it independently from the others? So that they start on differing midi values, and not on octaves?

What is needed is [u]your[/u] schematic, then you can write [u]your[/u] code. This is much easier than trying to modify some on elses code that does something totally different. I can't see any similarity between what you are trying to do and what that link was trying to do so you are better off forgetting that code.

Like all development it helps if you build it up in stages testing as you go. The trick is never to write too much code without testing.

You need first to work out how you are going to read each string in and translate that to a fret number for each string.

After that the rest is simple. You have a fret number and a string number, each string will have a starting point, the MIDI note number of the open string. Then for each fret number you will add one to that starting number. The code you produce will be a whole lot simpler than the code you got from that site.

I know that writing my own code for my specific project would be ideal, but I do not possess the skills or knowledge to do that at this point. I was hoping to adapt something that someone else had previously accomplished that was along the same lines. I did not realize that this would be a losing battle.

I can't see any similarity between what you are trying to do and what that link was trying to do so you are better off forgetting that code.

But it is quite similar. I am using exactly the same wiring as that of an analog organ, a keyboard matrix with diodes and switches. Each row corresponds to one of the frets, and each column (or select line) would correspond to one of the strings. The only difference is that with a keyboard, each column would designate an octave, or 12 tones higher/lower. I just want to change it so that the lines designate a different note, one a 4th higher to correspond with each string, rather than an 8ve.

Thanks for your reply and your time, but I guess I do not understand and this project is out of my reach.

I am using exactly the same wiring as that of an analog organ,

Maybe if you posted a schematic. I mean a real one, one where it would show what you have wired to what and not the abortion in that link. It is fine for you because you have it in front of you we only have to guess what changes you made.

Ok, here is my schematic, still rough, but hopefully not equivalent to unwanted offspring.

I do ask for patience, I am having trouble getting a handle on this coding buisness.

So basically, the Arduino sends a signal through each of the 6 strings on Digital Pins 2-7. This signal gets sent to the matrix, and when a string contacts a specific fret, it closes a switch and sends that ON signal to the i/o expander chips. The chips determine which string and which fret were pressed and send that information to Analog pins 4 and 5 on the Arduino. The Arduino then interprets the position on the matrix as a MIDI number, and sends a MIDI On signal to the MIDI Output. When the string is released from the fret, it sends a MIDI off signal to the Arduino.

So, this is what I meant when I said it was like an analog organ keyboard. I apologize for presuming, that was silly. I’ve just been staring at a whole bunch of organ keyboards lately.

So, my question originally should have been something like this:

Where in that original coding does it specify that each row corresponds to an octave (12 half steps or MIDI notes), and how can I change it so that each row instead refers to a MIDI note one fourth higher instead (5 half steps or MIDI notes).

I’ll try to be less obtuse in the future :sweat_smile:

OK thanks good start. Now while you can detect when a string is being held to a fret how do you know when to send a MIDI note.

Basically get it working for one string first. Forget MIDI for the moment.
Start at the lowest string and look at each fret in turn until you see one connected. When you find that then print out the fret number. Try that and post the code.