Arduino midi project doesn't work

hi Guys,

I'm working on an arduino project with an arduino pro micro, 2 buttons and an 5 pins din connector. my buttons are on pin 2 and 3, and I want to send midi via the usb port of the pro micro and via the din connector. the din connector is connected to the TX line, 5v and ground (ofcoarse with resistors).

the arduino is sending midi via the usb port to my laptop, that works. now I also want to send midi note 120 and 121 to the din connector, but that doesn't work. I've tried a different code, and that does work, so the hardware isn't the problem. this is my code:

#include <MIDIUSB.h>
#include <MIDI.h>

const int N_BUTTONS = 2;
int ButtonPin[N_BUTTONS] = { 2, 3 };
int buttonNote[N_BUTTONS] = {36, 38, };

int ButtonPortNote[N_BUTTONS] = {120, 121,};

int ButtonState[N_BUTTONS] = { 0 };
int ButtonPState[N_BUTTONS] = { 0 };

MIDI_CREATE_DEFAULT_INSTANCE();

unsigned long lastDebounceTime[N_BUTTONS] = { 0 };
unsigned long debounceTimer[N_BUTTONS] = { 0 };
int debounceDelay = 30;

int BUTTON_CH = 0;

void setup() {
  Serial.begin(9600);

  for (int i = 0; i < N_BUTTONS; i++) {


    pinMode(ButtonPin[i], INPUT_PULLUP);
  }
  MIDI.begin(MIDI_CHANNEL_OFF);
}

void loop(){
  for (int i = 0; i < N_BUTTONS; i++) {

  ButtonState[i] = digitalRead(ButtonPin[i]);

  debounceTimer[i] = millis() - lastDebounceTime[i];
  if (debounceTimer[i] > debounceDelay) {
    if (ButtonState[i] != ButtonPState[i]) {

      lastDebounceTime[i] = millis();


      if (ButtonState[i] == LOW) {

        noteOn(BUTTON_CH, buttonNote[i], 127);
        MIDI.sendNoteOn(ButtonPortNote[i], 127, 1);
        MidiUSB.flush();

        Serial.print("Button ");
        Serial.print(i);
        Serial.print(" ");
        Serial.println("on");

      } else {

        noteOn(BUTTON_CH, buttonNote[i], 0);
        MIDI.sendNoteOn(ButtonPortNote[i], 0, 1);
        MidiUSB.flush();

        Serial.print("Button ");
        Serial.print(i);
        Serial.print(" ");
        Serial.println("off");
      }
      ButtonPState[i] = ButtonState[i];
    }
  }
}
}

//-------
void noteOn(byte channel, byte pitch, byte velocity) {
  midiEventPacket_t noteOn = { 0x09, 0x90 | channel, pitch, velocity };
  MidiUSB.sendMIDI(noteOn);
}

void controlChange(byte channel, byte control, byte value) {
  midiEventPacket_t event = { 0x0B, 0xB0 | channel, control, value };
  MidiUSB.sendMIDI(event);
}

this is the code that I used to test the port:

#include <MIDI.h>

#define LED 13

MIDI_CREATE_DEFAULT_INSTANCE();

void setup()
{
  pinMode(LED, OUTPUT);
  MIDI.begin(MIDI_CHANNEL_OFF);
}

void loop()
{
  digitalWrite(LED, HIGH);
  MIDI.sendNoteOn(120, 127, 1);
  delay(1000);		       
  MIDI.sendNoteOff(120, 0, 1);
  digitalWrite(LED, LOW);
  delay(1000);
}

already thanks!

Please take a few minutes and read this: How to get the best out of this forum

It will help others help you. After you finished reading it, go back and edit your post and put your code inside code tags so people can easily copy/paste.

Also, post the code that does work properly so people can potentially spot the important differences.

Thanks! i've changed it.

Can you change your working code to include MidiUSB.h and send a note to both without the buttons? This will isolate the issue either with your button/debounce code or two midi libraries.

#include <MIDIUSB.h>
#include <MIDI.h>

#define LED 13

MIDI_CREATE_DEFAULT_INSTANCE();

void setup()
{
  pinMode(LED, OUTPUT);
  MIDI.begin(MIDI_CHANNEL_OFF);
}

void loop()
{
  digitalWrite(LED, HIGH);
  MIDI.sendNoteOn(120, 127, 1);
  noteOn(0, 36, 127);
  MIDI.sendNoteOn(ButtonPortNote[i], 127, 1);
  MidiUSB.flush();
  delay(1000);
  noteOn(0, 38, 127);
  MIDI.sendNoteOff(120, 0, 1);
  digitalWrite(LED, LOW);
  delay(1000);
}

void noteOn(byte channel, byte pitch, byte velocity) {
  midiEventPacket_t noteOn = { 0x09, 0x90 | channel, pitch, velocity };
  MidiUSB.sendMIDI(noteOn);
}

thanks for your awnser, ive checked your code (and edited

MIDI.sendNoteOn(ButtonPortNote[i], 127, 1);

to

MIDI.sendNoteOn(120, 127, 1);

and this works on the physical din port and on the usb midi port.

so it's probably the button code or the debouncer, have you got any ideas what it could be?

At a glance through the tiny window it looks like you shoukd be able to confirm that you button code, which looks plausible, is functioning correctly.

Or are you unable to use the serial monitor whilst also talking MIDI? I'm not clear on how the two MIDI parts are connecting to the Arduion nor to whatever is on the other end of them.

Post a block diagram of the project. Put pin numbers on the parts so we can see who's talking, or trying, to whom.

a7

If you look at the debounce example in the IDE, you will notice that resetting the debounce timer is independent of checking if the button state has changed. Something like this

#include <MIDIUSB.h>
#include <MIDI.h>

const int N_BUTTONS = 2;
int ButtonPin[N_BUTTONS] = { 2, 3 };
int buttonNote[N_BUTTONS] = {36, 38, };

int ButtonPortNote[N_BUTTONS] = {120, 121,};

int ButtonState[N_BUTTONS] = { 0 };

MIDI_CREATE_DEFAULT_INSTANCE();

unsigned long lastDebounceTime[N_BUTTONS] = { 0 };
//unsigned long debounceTimer[N_BUTTONS] = { 0 };
const unsigned long debounceDelay = 30;

int BUTTON_CH = 0;

void setup() {
  Serial.begin(9600);

  for (int i = 0; i < N_BUTTONS; i++) {
    pinMode(ButtonPin[i], INPUT_PULLUP);
  }
  MIDI.begin(MIDI_CHANNEL_OFF);
}

void loop() {
  for (int i = 0; i < N_BUTTONS; i++) {

    int state = digitalRead(ButtonPin[i]);
    if (state != ButtonState[i]) {
      // reset debounce timer
      lastDebounceTime[i] = millis();
    }
    if (millis() - lastDebounceTime[i] >= debounceDelay) {
      // done debouncing

      if (state != ButtonState[i]) {
        // button has changed so deal with it

        Serial.print("Button ");
        Serial.print(i);
        Serial.print(" ");
        
        if (state == LOW) {
          noteOn(BUTTON_CH, buttonNote[i], 127);
          MIDI.sendNoteOn(ButtonPortNote[i], 127, 1);
          MidiUSB.flush();
          Serial.println("on");
        } else {
          noteOn(BUTTON_CH, buttonNote[i], 0);
          MIDI.sendNoteOn(ButtonPortNote[i], 0, 1);
          MidiUSB.flush();
          Serial.println("off");
        }
      }
    }
    ButtonState[i] = state;
  }
}

//-------
void noteOn(byte channel, byte pitch, byte velocity) {
  midiEventPacket_t noteOn = { 0x09, 0x90 | channel, pitch, velocity };
  MidiUSB.sendMIDI(noteOn);
}

void controlChange(byte channel, byte control, byte value) {
  midiEventPacket_t event = { 0x0B, 0xB0 | channel, control, value };
  MidiUSB.sendMIDI(event);
}

I can read the serial monitor to see witch state my button is. I want my project to send midi data through usb and an din port simultaniously, this because I work in the lighting industy and de physical din port goes to my lighting desk, and the usb midi goes to my laptop witch controls visuals. so I can use the buttons for a tap tempo. here is a scheme how I wired everything.

Thanks. Nice diagram.

This

may well be true, I have not looked closely at the implications of doing it elsewhere.

But I did run your code for the buttons.

Here's your sketch with the MIDI stuff blocked out. In my tests it shows the buttons responding correctly to being pressed and released independently

Button 1 on
Button 1 off
Button 0 on
Button 0 off
Button 1 on
Button 0 on
Button 0 off
Button 1 off
Button 1 on
Button 0 on
Button 1 off
Button 0 off

Try this yourself.
//#include <MIDIUSB.h>
//#include <MIDI.h>

const int N_BUTTONS = 2;
int ButtonPin[N_BUTTONS] = { 2, 3 };
int buttonNote[N_BUTTONS] = {36, 38, };

int ButtonPortNote[N_BUTTONS] = {120, 121,};

int ButtonState[N_BUTTONS] = { 0 };
int ButtonPState[N_BUTTONS] = { 0 };

//MIDI_CREATE_DEFAULT_INSTANCE();

unsigned long lastDebounceTime[N_BUTTONS] = { 0 };
unsigned long debounceTimer[N_BUTTONS] = { 0 };
int debounceDelay = 30;

int BUTTON_CH = 0;

void setup() {
  Serial.begin(9600);

  for (int i = 0; i < N_BUTTONS; i++) {


    pinMode(ButtonPin[i], INPUT_PULLUP);
  }
//  MIDI.begin(MIDI_CHANNEL_OFF);
}

void loop(){
  for (int i = 0; i < N_BUTTONS; i++) {

  ButtonState[i] = digitalRead(ButtonPin[i]);

  debounceTimer[i] = millis() - lastDebounceTime[i];
  if (debounceTimer[i] > debounceDelay) {
    if (ButtonState[i] != ButtonPState[i]) {

      lastDebounceTime[i] = millis();


      if (ButtonState[i] == LOW) {

//        noteOn(BUTTON_CH, buttonNote[i], 127);
//       MIDI.sendNoteOn(ButtonPortNote[i], 127, 1);
//        MidiUSB.flush();

        Serial.print("Button ");
        Serial.print(i);
        Serial.print(" ");
        Serial.println("on");

      } else {

//        noteOn(BUTTON_CH, buttonNote[i], 0);
//        MIDI.sendNoteOn(ButtonPortNote[i], 0, 1);
//        MidiUSB.flush();

        Serial.print("Button ");
        Serial.print(i);
        Serial.print(" ");
        Serial.println("off");
      }
      ButtonPState[i] = ButtonState[i];
    }
  }
}
}
/*
//-------
void noteOn(byte channel, byte pitch, byte velocity) {
  midiEventPacket_t noteOn = { 0x09, 0x90 | channel, pitch, velocity };
  MidiUSB.sendMIDI(noteOn);
}

void controlChange(byte channel, byte control, byte value) {
  midiEventPacket_t event = { 0x0B, 0xB0 | channel, control, value };
  MidiUSB.sendMIDI(event);
}
*/

When I can take some time I will examine the code to see if @blh64 is on to something, there are quite a few debouncing schemes, so it's hard to say in what ways your code might ever be a problem.

debounceDelay = 30;

should handle most switches; I do have some crappy arcade switches where 50 is necessary for perfect repsonse - just crank it up to 50 in the buttons-only test I ran to eliminate any possibility that there is some bouncing problem.


I got nothing on the MIDI matter, but I wonder if using TX0, which is connected to the USB system, is a problem.

Here's a place where

# include <SendOnlySoftwareSerial.h>

might be tried. It works at high speeds, unlike the send-receive software serial solutions. I've been using it at 115200 w/o any trouble.

HTH

a7

Thanks! The button presses in the serial monitor are the same as mine, and it sends those messages correctly to the usb midi. It only doesn't send it through the physical midi port. I'l try the code tomorrow and let you know if it works on both the ports!

Nope. No problem at all. If you look at the examples in the MidiUSB library, they all user Serial print statements along with Midi commands.

OK, THX. Good to know.

It does (or how does it not) make a mess of the serial monitor window. If it does, that alone would make me think about not using it.


The button handling follows a classic pattern. The timer is used to ignore the button for the debounce period after seeing the state change.

If necessary, handle the button, then just don't look at it for the debounce period.

It is an algorithm that responds immediately with a press or release event. Pushbuttons that read LOW are on their way to being closed and stable and LOW, Pushbuttons that read HIGH are on their way to being open and stable, so why wait?

Its best repsonse needs a name, like the musician's (or gamer's) debounce.

With the exception of moving a line of code or two what would have no effect on the outcome, this is what is being done, stripped out of the loop and de-arrayified.

# define buttonPin  2

void setup() {
  Serial.begin(9600);
  pinMode(buttonPin, INPUT_PULLUP);
}

unsigned long now;

void loop() {
  now = millis();


  static unsigned long lastTime;
  static bool buttonWas;
  bool gotPresst = false;
  bool gotReleased = false;

  if (now - lastTime > 20) {
    bool buttonIs = digitalRead(buttonPin) == LOW;
    if (buttonIs != buttonWas) {
      lastTime = now;
      if (buttonIs) gotPresst = true;
      if (buttonWas) gotReleased = true;

      lastTime = now;
    }
    buttonWas = buttonIs;
  }


  if (gotPresst) Serial.print("Button Down!\n");
  if (gotReleased) Serial.print("             Button Up!\n");
}

a7

I've checked this code, but still the midi does only sent through the usb and not the physical port. any other problems in my code?

TBH I'm a bit confused (resting state). :expressionless:

Can you post two sketches, each of which deals with the MIDI, one for the serial port, one for USB?

I can see how one, or the other, would work, but I cannot see why using both the USB and the serial TX line, which is part of the USB system, would not automatically be a non-starter.

As an alternative, or in addition, try the Send Only on a software port for the part talking to the TX line. It won't take long. The only thing I don't see is how to direct the MIDI that is not on USB to use the software UART, or the UAT so to speak as Send Only does not R anythjng. There must be a way to use another port, and the way ports work it would not know or care whether you were using a legit hardware port on a Mega or a software port on an UNO.

These comments are made in almost total ignorance of MIDI - just the things I see as potential areas of concern and experiments that should not be hard to do.

a7

okay, I have made 2 scetches. the first for the usb midi. this is the code:

#include <MIDIUSB.h>

const int N_BUTTONS = 2;
int ButtonPin[N_BUTTONS] = { 2, 3 };
int buttonNote[N_BUTTONS] = {
  36,
  38,
};

int ButtonState[N_BUTTONS] = { 0 };
int ButtonPState[N_BUTTONS] = { 0 };

unsigned long lastDebounceTime[N_BUTTONS] = { 0 };
unsigned long debounceTimer[N_BUTTONS] = { 0 };
int debounceDelay = 30;

int BUTTON_CH = 0;

void setup() {
  Serial.begin(9600);

  for (int i = 0; i < N_BUTTONS; i++) {


    pinMode(ButtonPin[i], INPUT_PULLUP);
  }
}

void loop() {

  for (int i = 0; i < N_BUTTONS; i++) {

    ButtonState[i] = digitalRead(ButtonPin[i]);

    debounceTimer[i] = millis() - lastDebounceTime[i];
    if (debounceTimer[i] > debounceDelay) {
      if (ButtonState[i] != ButtonPState[i]) {

        lastDebounceTime[i] = millis();


        if (ButtonState[i] == LOW) {

          noteOn(BUTTON_CH, buttonNote[i], 127);
          MidiUSB.flush();

          Serial.print("Button ");
          Serial.print(i);
          Serial.print(" ");
          Serial.println("on");

        } else {

          noteOn(BUTTON_CH, buttonNote[i], 0);
          MidiUSB.flush();

          Serial.print("Button ");
          Serial.print(i);
          Serial.print(" ");
          Serial.println("off");
        }
        ButtonPState[i] = ButtonState[i];
      }
    }
  }
}

//-------
void noteOn(byte channel, byte pitch, byte velocity) {
  midiEventPacket_t noteOn = { 0x09, 0x90 | channel, pitch, velocity };
  MidiUSB.sendMIDI(noteOn);
}

void controlChange(byte channel, byte control, byte value) {
  midiEventPacket_t event = { 0x0B, 0xB0 | channel, control, value };
  MidiUSB.sendMIDI(event);
}

I have also made a code for the physical midi, and what is interesting is that the code works with simple programming (like the code below) but it doesn't work when I work with array's. maybe there lies the problem in my other code? any sugestions how I can fix that? Thanks!

#include <MIDI.h>

#define BUTTON_PIN 2
#define LED_PIN 13

MIDI_CREATE_DEFAULT_INSTANCE();

bool buttonState = false;
bool lastButtonState = false;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 30;

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);
  MIDI.begin(MIDI_CHANNEL_OFF);
}

void loop() {
  int reading = digitalRead(BUTTON_PIN);

  if (reading != lastButtonState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {
      buttonState = reading;

      if (buttonState == HIGH) {
        MIDI.sendNoteOn(60, 127, 1); // MIDI note-on message (change 60 to the desired note number)
        digitalWrite(LED_PIN, HIGH);
      } else {
        MIDI.sendNoteOff(60, 0, 1); // MIDI note-off message (change 60 to the same note number used in the note-on message)
        digitalWrite(LED_PIN, LOW);
      }
    }
  }

  lastButtonState = reading;
}

What doesn't work? Certainly using

int someNote[] = {36, 38};

in you calls like

        int ii = 1;
        MIDI.sendNoteOn(someNote[ii], 127, 1); // MIDI note-on message (change 60 to the desired note number)

will work, as in general arrays do work, nothing special here. I see nothing in your code that isn't logically equivalent.

Post code that should do only what the last thing you posted does, but with arrays that make it not work. I think maybe you have some simple error.

a7

How can the code back in post #5 work correctly and send to MIDI and MIDIUSB but not work here?

If the (editted) code of post #5 does work, start there and introduce your buttons and make sure it works. Build up until it doesn't work to figure out the problem.

I've made 2 different codes, and I think I found the problem. my first code looks like this, and this works and sends an output when it has to:

#include <MIDI.h>
#define button 2
MIDI_CREATE_DEFAULT_INSTANCE();
int port1[button] = {120};

void setup()
{
  MIDI.begin(MIDI_CHANNEL_OFF);
  pinMode (button, INPUT_PULLUP);
}

void loop()
{
  Serial.println(digitalRead(button));
  delay(100);

  if (digitalRead(button) == HIGH) {
  MIDI.sendNoteOn(port1[button], 127, 1);
  }    

  else {
  MIDI.sendNoteOff(120, 0, 1);
  }
  
}

My second code introduces an array, and now it doesn't work. have I overlooked anything?

#include <MIDI.h>
#define button 2
MIDI_CREATE_DEFAULT_INSTANCE();
int port1[button] = {120};

void setup()
{
  MIDI.begin(MIDI_CHANNEL_OFF);
  pinMode (button, INPUT_PULLUP);
}

void loop()
{
  Serial.println(digitalRead(button));
  delay(100);

  if (digitalRead(button) == HIGH) {
  MIDI.sendNoteOn(port1[button], 127, 1);
  }    

  else {
  MIDI.sendNoteOff(120, 0, 1);
  }
  
}

Yes. You have a problem, let us hope that has been hiding all along. Three lines from the array-ized sketch:

#define button 2



int port1[button] = {120};



  MIDI.sendNoteOn(port1[button], 

The first defines a symbol button, which will be replaced by 2 everywhere it appears subsequently

The second makes an array with two elements, and assigns them the value of 120 and 0.

The third attempts to access the third element in the array, array indices run from 0 to N - 1, where N is the number of elements in the array.

There is no third element, and accessing it it not only nonsense, but can literally cause anything to happen anywhere in the entire sketch at any time.

This is a good catch if indeed that's what we've been missing all along.

added: I have rapidly reviewed the previous posted sketches and do not see the same mistake made - also it is the type of mistake everyone looks for right away when arrays cause grief. I may still be missing it, but the latest sketch def has a problem.

a7