How Transpose note of a MIDI keyboard with Arduino Mega

Hello,I'm new of this Forum, and like programmer too. I have a question to solve....
I took a sketch of a midi keyboard controller, that you can control VST instruments and their pots and buttons. I ask you guys, How control transposition of keyboards note with two buttons to control Up and Down octave, as follow I loaded the sketch I was talking about before...

@dagh82 , your topic has been moved to a more suitable location on the forum. Installation and Troubleshooting is not for problems with (nor for advise on) your project :wink: See About the Installation & Troubleshooting category.

Where it says this

    Serial.write(status_byte);
    Serial.write(key);
    Serial.write(vel);

is where the actual midi message is sent.
The parameter 'key' has the value between 0 & 127 where every octave has 12 notes.

    int8_t oct = 0;
    Serial.write(status_byte);
    Serial.write(key + oct * 12);
    Serial.write(vel);

and you should probably constrain that value before you send it.

1 Like

yes it work:
for example if I change the value of int8_t oct = 0; with int8_t oct = 1
I ve got 1 octave up.
But how can I command this function with push button?

How would you normally control a variable with a push button ?
Have a look at the digital -> debounce example that comes with the IDE

I will try, if even Im not expert
thanks so much

None of us were experts at first.

I've tried without success

Show me what you've tried.

The example i referred to is this one



// constants won't change. They're used here to set pin numbers:
const int buttonPin = 2;    // the number of the pushbutton pin
const int ledPin = 13;      // the number of the LED pin

// Variables will change:
int ledState = HIGH;         // the current state of the output pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);  
  digitalWrite(ledPin, ledState); // set initial LED state
}

void loop() {  
  int reading = digitalRead(buttonPin); // read the state of the switch into a local variable:  
  if (reading != lastButtonState) {   // If the switch changed, due to noise or pressing:
    lastDebounceTime = millis();  // reset the debouncing timer
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {  // if the button state has changed:
      buttonState = reading;      
      if (buttonState == HIGH) {  // only toggle the LED if the new button state is HIGH
        ledState = !ledState;
      }
    }
  }
  digitalWrite(ledPin, ledState);  
  lastButtonState = reading; // save the reading. Next time through the loop, it'll be the lastButtonState:
}

I removed some of the comments because it was obstructing my view of the code, But code wise it's the same.
Did you get that to work ?
Then with a small modification you can get a button press (or release) to modify a variable. You make a function from what is in loop(). Since we don't want the led to change state but modify a variable, that part can be removed

const int buttonPin = 2;    // the number of the pushbutton pin

void setup() {
  pinMode(buttonPin, INPUT_PULLUP);
}

void loop() {
  CheckButton();
}

void CheckButton() {

  static int buttonState;             // the current reading from the input pin
  static int lastButtonState = HIGH;   // the previous reading from the input pin
  static unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
  static unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

  int reading = digitalRead(buttonPin); // read the state of the switch into a local variable:
  if (reading != lastButtonState) {   // If the switch changed, due to noise or pressing:
    lastDebounceTime = millis();  // reset the debouncing timer
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {  // if the button state has changed:
      buttonState = reading;
      if (buttonState == HIGH) {  
        // change the variable that you want changed.
      }
    }
  }
  lastButtonState = reading; // save the reading. Next time through the loop, it'll be the lastButtonState:
}

Now it depends a little on how you wire your button, but the most common way is to set the pinMode to INPUT_PULLUP (as it is in the last example) and connect the button with 1 side to GND, so pressing will result in the pin would be LOW when the button is pressed. It is when the buttonstate is HIGH that all the condition are met and we can modify the variable there.

Of course ideally you will want 2 buttons. 1 for octave up & 1 for octave down. Actually you'll want loads of buttons really. But that is a different matter. Let's start with one.

The buttons are connected in pin mode to INPUT_PULLUP, i've tried to write like you told,
but nothing happened, i've tried to adding the " Serial.write(key +1 *12); " function as status, but it no work. I let my sketch modified
Maudio_firmwarey.ino (12.5 KB)

Please post your full sketch so we can see where key is declared. Please use code tags when posting your code; if you haven't read it yet, it's described in How to get the best out of this forum, search for code.

Do you see the button at the right in your image? Use it to post the full error; please use code tags for that as well.

did you first example get the to work ?

In your sketch, you should first add the octave as a global variable.

int octave = 0;

then in your send_midi_event() you have to implement that here

byte key = 36 + key_index;

should become instead

int key = 36 + key_index + octave * 12;
if ((key < 0) || (key > 127))  return;  // if key is out of range don't send anything.

and within the CkeckButtons() function
you can modify 'octave' to the value you want.

      if (buttonState == HIGH) {
        octave++;  // increase octave
        if (octave > 4) octave = -3;  // and let it roll over
      }

you would want 2 buttons of course, 1 for up and 1 for down, but for now this should work.

ok, now it work, but there is a little trouble. I made the 2 buttons Up and Down for octave but i don't know if it right to make 2 function in a separate void.
if you can take a look if there are mistakes in this sketch
Maudio_firmwarey.ino (13.9 KB)

It is a perfectly fine method. A little inefficient for program memory and not the most elegant, but fine. no problem with it as long as it's 2 buttons... when there are more, you may be better of doing it differently.

Just a small note.

if (buttonState == HIGH) {
        octave++;  // increase octave
        if (octave > 0) octave = 4;  // and let it roll over
      }

For the button up function. You don't want it rolling over anymore, you just want it not to go to high. so

if (buttonState == HIGH) {        
        if (octave < 4)  octave++;  // increase octave to  maximum of 4
      }

and for the down function

if (buttonState == HIGH) {        
        if (octave > -3)  octave--;  // decrease octave to  minimum of -3
      }

For multiple buttons i usually let every button refer to a bit in a variable, that i then compare to it's previous state. Like that i can use the same variable for debounce time, and i can test also for combination of presses.
But as i said, your solution is fine.

thankyou very much :hugs:

you are usefull for all, I don't know how I could thank you

1 Like

May I ask you another thing?
if i want have a new midi command with pushbutton in toggle way, How can I do it?

I told you..,

So by now you want 3 buttons. How confident are you that you will not want 4 buttons ?
Or use combinations of button presses ?

About that, you could simply do something like

  static bool toggle = true;

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {  // if the button state has changed:
      buttonState = reading;
      if (buttonState == HIGH) {  
       if (toggle) {
         // send the 1st command 
      }
      else {
        //send the other command
      }
      toggle = !toggle;
    }
  }
void CHECK() {

  static int buttonState;             // the current reading from the input pin
  static int lastButtonState = HIGH;   // the previous reading from the input pin
  static bool toggle = true;   // the previous reading from the input pin
  static unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
  static unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

  int reading = digitalRead(buttonToggle); // read the state of the switch into a local variable:
 if (reading != lastButtonState) {   // If the switch changed, due to noise or pressing:
    lastDebounceTime = millis();  // reset the debouncing timer
  }
     
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {  // if the button state has changed:
      buttonState = reading;
      if (buttonState == HIGH) {
             if (toggle) {
         send_midi_eventcc(0xB0, 80, 127); // send the 1st command 
      }
      else {
      
         send_midi_eventcc(0xB0, 80, 0); // send the 1st command //send the other command
      }
      toggle = !toggle;
    }
  }
 lastButtonState = reading; // save the reading. Next time through the loop, it'll be the lastButtonState:
}