MIDI controller

Hi,
I'm currently working on a project to create a midi controller to control guitar rig and other guitar software. I have designed and manufactured my pedal board and gathered all of the components I need. I am now just struggling to master the code

My aim is to have 14 foot switches, 1 potentiometer and 5 LEDs. I am using an arduous nano.

So far I am struggling to get 1 button working. All I want it to do is select the previous preset. In guitar rig, it does this once then resets the action. It is not reconsigned as a midi command in any other program.

Here is my code so far.

// set pin numbers:
const int buttonPin = 2;     // the number of the pushbutton pin
const int ledPin =  13;      // the number of the LED pin
int buttonState = 0;         // variable for reading the pushbutton status

void setup() {
  //  Set MIDI baud rate:
  Serial.begin(31250);
  pinMode(ledPin, OUTPUT);
}

void loop() {
    
    // assign midi note
    int Cnote = 0x30;
    
    // read the state of the pushbutton value:
    buttonState = digitalRead(buttonPin);

    // check if the pushbutton is pressed.
    // if it is, the buttonState is HIGH:
    if (buttonState == HIGH) {     
      // Play midi note: Note on channel 1 (0x90), some note variable in this case (Cnote), middle velocity (0x45):
      noteOn(0xB1, 70, 127);
      // turn LED on to indicate successful button press:
      digitalWrite(ledPin, HIGH);
     // delay to supress stuttering 
      delay(1000); 
    } 
    else {
      // turn LED off:

      digitalWrite(ledPin, LOW);  
    }
}

//  plays a MIDI note.  Doesn't check to see that
//  cmd is greater than 127, or that data values are less than 127:
void noteOn(int cmd, int pitch, int velocity) {
  Serial.write(cmd);
  Serial.write(pitch);
  Serial.write(velocity);
}

I'd suggest that you strip down your project into basic tasks. E.g. when the button is pressed send a fixed (valid for sure) midi command, so that it is recognized by the receiver. Then add more buttons to emit the same command, then assign a different command to every button.

That code is sending a CC message to controller 70 on channel 2 with a value of 127. How are you testing it?
A good way is to get a midi monitor on your computer and see if it is sending this.

The comments in the code are nothing to do with what the code does, I assume you have adapted it from something you did not write. Do you know what CC messages you have to send to do what you want?

Also the way that code reads the button is less than impressive. You need to have a state change program where you compair the current state of the button with the previous state last time round the loop and only trigger the message when it changes and is high.

Grumpy_Mike:
Also the way that code reads the button is less than impressive. You need to have a state change program where you compair the current state of the button with the previous state last time round the loop and only trigger the message when it changes and is high.

Right, actions always should occur on state transitions only. Either as onEnterStateX() or onExitStateX(), or more detailed in onEnterStateXfromY(). Only timed events should be checked based on the current state, e.g. if (State==X && timeoutX) switchToNextState.

Hi, thanks for the reply, yes I did adept the code, I think I first need to understand what midi messages I want to send. I want to control allot functions within guitar rig but cannot figure out what commands to send.

guitar rig has a learn feature but I don't know what commands to send for it to pick them up.

Thanks
Joe

Is your guitar rig set up on channel 2?
The four least significant bits of a command are the channel number, but four zeros is channel 1, and 0001 as you have it is channel 2.

I think I first need to understand what midi messages I want to send.

Yes that would help a lot.

Thanks for the help so far, I've gotten a little further, I have found a more suitable code to adapt to my needs.

I have modified this code but cannot it to send 1 midi message per 1 button press, instead it sends continuous signals until the button is released.

does anyone know how could stop this?, thanks in advance.

// libraries

#include <SoftwareSerial.h>

// We will use the SoftwareSerial library instead of the Serial library, as this will let us control which pins our MIDI interface is connected to.

SoftwareSerial mySerial(0, 1); // RX, TX



// constants

const int ped1 = 4;
const int ped2 = 5;

const byte midiNoteOn = 144;
const byte midiNoteOff = 128;

const int midiSendDelay = 100; // give MIDI-device a short time to "digest" MIDI messages

// note lengths
const int bpm = 128; // tempo, BPM (beats per minute), a value that makes t16 an integer
const int t1 = 1024 * (bpm/64); // 1 whole beat = 512
const int t2 = t1/2; // 256
const int t4 = t2/2; // 128
const int t8 = t4/2; // 64
const int t16 = t8/2; // 32

const int voiceMidiChannel = 0;
const int voiceMidiPatch = 86;
const int voiceMidiVolume = 80;
const int voiceMidiPan = 100;
const int midiVelocity = 100;



//  Play a MIDI note

void midiNote(int aMidiCommand, int aMidiPitch, int aMidiVelocity) {
mySerial.write(aMidiCommand);
mySerial.write(aMidiPitch);
mySerial.write(aMidiVelocity);
}

// Send MIDI command with 1 data byte

void midiData1(int aMidiCommand, int aData1) {
mySerial.write(aMidiCommand);
mySerial.write(aData1);
}

// Send MIDI command with 2 data bytes

void midiData2(int aMidiCommand, int aData1, int aData2) {
mySerial.write(aMidiCommand);
mySerial.write(aData1);
mySerial.write(aData2);
}



void setup() {

pinMode(ped1, INPUT);
pinMode(ped2, INPUT);

// setup SoftSerial for MIDI control
mySerial.begin(31250);
delay(midiSendDelay);

// all sounds off on all 16 channels (can be synth-specific)
for (int i = 0; i < 16; i++) {
midiData2((0xB0 | i), 0x78, 0);
delay(midiSendDelay);
midiData1((0xB0 | i), 0x7B);
delay(midiSendDelay);
}

// volume
midiData2((0xB0 | voiceMidiChannel), 07, voiceMidiVolume);
delay(midiSendDelay);

// sound/patch
midiData1((0xC0 | voiceMidiChannel), voiceMidiPatch);
delay(midiSendDelay);

// pan
midiData2((0xB0 | voiceMidiChannel), 10, voiceMidiPan);
delay(midiSendDelay);

}



void loop() {

// if user presses 1st button play a short note  
if (digitalRead(ped1) == HIGH)
{
midiNote(midiNoteOn + voiceMidiChannel, 1, midiVelocity);
delay(t4);
midiNote(midiNoteOff + voiceMidiChannel, 1, midiVelocity); 
}

// if user presses 2nd button play a short note  
if (digitalRead(ped2) == HIGH)
{
midiNote(midiNoteOn + voiceMidiChannel, 2, midiVelocity);
delay(t4);
midiNote(midiNoteOff + voiceMidiChannel, 2, midiVelocity); 
}

}

Loop runs many thousands of times a second. You want to send the message not when the button is pressed but when it becomes pressed for the first time.
So make a note of the current state of the button as the last thing in the loop function. Then at the start read the button and only send the message when the new state is not the same as the old state, and the new state is high.
You can use a compound if statement to test for those two things.

Thanks Mike, I have got 1 button working in this way but I am struggling to duplicate the code as I need 14 buttons

I also need to program a potentiometer to use as a CC and 5 LEDs that will toggle on and off with 5 of the buttons.

This is what I have:

void loop() {
  {
    int newState = digitalRead(ped1);
    if(newState != oldState)
    {
        // the state has changed
        if(newState == HIGH)
       
        {
           midiNote(midiNoteOn + voiceMidiChannel, 1, midiVelocity);
 delay(250);
 midiNote(midiNoteOff + voiceMidiChannel, 1, midiVelocity); 
        }
        
    }
    oldState = newState;
}



}

If you want 14 of these buttons then you need 14 oldState variables. Writing the code for that gets very tedious so what you do is to use an array to hold each old state for each switch. Then you can use a for loop and look at each button in turn and use the loop index as the array pointer and the controller number.

As to pots it is exactly the same thing, you have a lastReading variable and when that changes by some threshold ammount you send the CC message. An analog reade gives values between 0 and 1023 so you need to divide the reading by eight before you send it out but use the raw values in your lastReading variable. Use the abs() function like this.

if( abs(lastReading - newReading) > 8) {
// send the CC message with newReading / 8 as the value
lastReading = newReading; // only do this when new value sent not all the time
}