FortySevenEffects / arduino_midi_library

MIDI for Arduino
MIT License
1.59k stars 255 forks source link

Help with MIDI.sendRealTime() #115

Open jpclaude opened 5 years ago

jpclaude commented 5 years ago

Hello: I am using an Arduino Micro to build a MIDI box used to control other non-MIDI guitar pedals with MIDI commands. Also, I want to translate other MIDI messages to real time messages to control a sequencer / MIDI file player. I am using Note On messages generated from a MIDI capable device to control relays from the Arduino. That part works well.

The problem is with translating Note On messages into Real Time messages. Specifically, Start, Stop and Continue. I can detect the triggering Note On messages and send a Real Time message with MIDI.sendRealTime(). The problem is that there seems to be a timing issue. Most of the time, the sequencer ignores the Start, Stop, Continue messages, but if I keep pressing the triggering button, eventually the timing is right and the sequencer responds. So the messages are getting through, just not when they should. I am new to MIDI programming so I am probably missing some information. I would appreciate any help to get this working.

Just in case, the sequencer is set to accept Start, Stop, Continue messages and it is using its internal clock. That is a supported configuration. Also sending the real time messages with the SendMidi utility from my computer works fine.

Here is my Arduino program so that you can see what I am doing and not doing.

Thanks!

#include <MIDI.h>
#include <midi_UsbTransport.h>

#define OPEN HIGH
#define CLOSED LOW

// Constants:
const byte c3 = 48; // Relay 1
const byte d3 = 50; // Relay 2
const byte e3 = 52; // Relay 1 & 2
const byte f3 = 53; // Relay 3
const byte g3 = 55; // Relay 4
const byte a3 = 57; // Relay 3 & 4
//const byte b3 = 59;
const byte c4 = 60; // Start
const byte d4 = 62; // Continue
const byte e4 = 64; // Stop
//const byte f4 = 65;
//const byte g4 = 67;
//const byte a4 = 69;
//const byte b4 = 71;
const byte velocity1 = 1;

// Pins for relays:
const byte jack1Tip = 4;   // Relay 1 = jack 1 tip
const byte jack1Ring = 5;  // Relay 2 = jack 1 ring
const byte jack2Tip = 6;   // Relay 3 = jack 2 tip
const byte jack2Ring = 7;  // Relay 4 = jack 2 ring

// Create MIDI instance with USB connection:
static const unsigned sUsbTransportBufferSize = 16;
typedef midi::UsbTransport<sUsbTransportBufferSize> UsbTransport;
UsbTransport sUsbTransport;
MIDI_CREATE_INSTANCE(UsbTransport, sUsbTransport, MIDI);

void manageRelays(uint8_t state, byte note, byte velocity) {
    // Only velocity 1 messages are handled:
    if (velocity != velocity1) return;

    // Handle Jack 1:
    if (note == c3) {
        digitalWrite(jack1Tip, state);
    }
    if (note == d3) {
        digitalWrite(jack1Ring, state);
    }
    if (note == e3) {
        digitalWrite(jack1Tip, state);
        digitalWrite(jack1Ring, state);
    }

    // Handle Jack 2:
    if (note == f3) {
        digitalWrite(jack2Tip, state);
    }
    if (note == g3) {
        digitalWrite(jack2Ring, state);
    }
    if (note == a3) {
        digitalWrite(jack2Tip, state);
        digitalWrite(jack2Ring, state);
    }
}

void handleNoteOn(byte inChannel, byte note, byte velocity) {   
    manageRelays(CLOSED, note, velocity);

    // Handle Real-Time Messages:
    if ((note == c4) && (velocity == velocity1)) {
        MIDI.sendRealTime(MIDI_NAMESPACE::Start);
    }
    if ((note == d4) && (velocity == velocity1)) {
        MIDI.sendRealTime(MIDI_NAMESPACE::Continue);
    }
    if ((note == e4) && (velocity == velocity1)) {
        MIDI.sendRealTime(MIDI_NAMESPACE::Stop);
    }
}

void handleNoteOff(byte inChannel, byte note, byte velocity) {
     manageRelays(OPEN, note, velocity);
}

void setup() {
    pinMode(jack1Ring, OUTPUT);
    pinMode(jack1Tip, OUTPUT);
    pinMode(jack2Ring, OUTPUT);
    pinMode(jack2Tip, OUTPUT);
    digitalWrite(jack1Ring, OPEN);
    digitalWrite(jack1Tip, OPEN);
    digitalWrite(jack2Ring, OPEN);
    digitalWrite(jack2Tip, OPEN);

    MIDI.begin();
    MIDI.setHandleNoteOn(handleNoteOn);
    MIDI.setHandleNoteOff(handleNoteOff);
}

void loop() {
    MIDI.read();
}
franky47 commented 5 years ago

What sends the MIDI noteOn messages coming into your device ? I see you only send the real-time messages when the velocity is 1, which is unlikely to happen reliably if using a keyboard or a non-programmed device.

The other thing might be that some real time messages could be coming into your device and Thru'd back to the sequencer, racing with the ones you generate. This could be detected by adding real-time callbacks, and mitigated by turning off the Thru feature.

jpclaude commented 5 years ago

Thanks for your quick reply! The noteOn messages are being generated by a Line 6 Helix preamp. The floorboard can be programmed to send noteOn messages with precise velocity values. The relay commands work great, so I know the messages are being sent and received correctly.

All my MIDI devices are connected to an iConnectivity mio10 hub. The Line 6 Helix and the Arduino box are connected through USB, and the sequencer through a classic DIN jack. The routing connects the Helix to the Arduino, and the Arduino to the sequencer. The Arduino is basically a MIDI translator between the HELIX and the sequencer. I will check for the possibility of MIDI thru messages.

Thanks again.