Midi filtertering of stop start messages

Hello to all!
I need to create a midi filter to block stop and start messages sent from a master clock sent to any other connected midi equipment. I am only interested in maintaining continual clock messages and other midi note messages. Can this code example be a good place to start?
Thanks in advance for any help

#include <MIDI.h>


  MIDI_CREATE_INSTANCE(HardwareSerial, Serial, MIDI);        //Use this instance for Hardware Serial at Arduino boards

void setup() {
  MIDI.begin(MIDI_CHANNEL_OMNI);  // all channels
  MIDI.turnThruOff();             // MIDI Thru Off
}

void loop() {
  if (MIDI.read())                //receive msg
  {
    switch (MIDI.getType()) {     //recognize MIDI Type as MIDI Clock and MIDI Clock start, stop, continue msg's
      case midi::Clock:
        break;
      case midi::Start:
        break;
      case midi::Continue:
        break;
      case midi::Stop:
        break;
      default:                    //sends other types of msg's
        MIDI.send(
          MIDI.getType(),
          MIDI.getData1(),
          MIDI.getData2(),
          MIDI.getChannel()
          );
        break;
    }
  }
}

I did at first think this code was filtering out midi clock, start, stop and continue messages but testing it has always allowed those messages through. In fact, all messages get through including notes! Not sure what it's supposed to be filtering now. Can anyone help?

How is everything wired together? If every device is listening on the same Tx pin from the master, you are not filtering anything. If you have an Arduino Mega, you would listen on one serial port and then resend on another port to broadcast those messages "downstream" to other devices.

So using the mega I could listen for the stop start messages and then resend everything i need to on a second port minus the start stop messages? Shouldn't I be able to just filter out messages I don't want through the one port?
Is it the case that clock messages aren't specific to any channel? Or do they send across all channels at the same time?

You did not specify how everything is wired together. That point is critical.

Sorry I forgot to mention that....Midi clock out to arduino uno, midi from thru then to loop pedal

I don't understand what that means, How about a schematic, even hand drawn.

Did you look at the Merger example that comes with the library? arduino_midi_library/examples/DualMerger at master · FortySevenEffects/arduino_midi_library · GitHub

It is close to what you want. except you just read from A, filter and send out on B

ArdMidi.pdf (1.7 MB)
Not sure if a schematic is needed. Simply put, midi cable connecting my master midi clock to the input of the midi shield, and from the shield's thru connection a midi cable connects to, in this instance, a midi loop pedal.
While my master clock is on, my loop pedal is synced perfectly. The problem arises when a stop message is sent from the master clock. My looper then stops even though it's still in sync receiving clock messages. Unfortunately I am unable to block these messages at the pedal and so I'm hoping that i can do that with code on the arduino. I haven't the foggiest notion on how to tell the arduino to not send those messages and just let the others through.

The midi-thru connection does exactly what it is supposed to, It passes all thru. (it is actually just hardware)

Just draw us how you've connected the devices and cables please. I think we can trust that the midi shield connects properly to the arduino.

Your code should work, though if you want to keep passing midi-sync (most clocks will stop sending that after sending stop though, but this is a different matter)
then your case for clock should look like this

      case midi::Clock:
        MIDI.sendRealTime(midi::Clock);
        break;

Is it still receiving midi clock messages ?
Best practice is to use the onboard LED on the Arduino to show midi-clock messages coming in. For that you need to count them as they come in,
so

void setup() {
  MIDI.begin(MIDI_CHANNEL_OMNI);  // all channels
  MIDI.turnThruOff();             // MIDI Thru Off
 pinMode(13, OUTPUT);
}

void loop() {
  static uint8_t clk = 0;
  if (MIDI.read())                //receive msg
  {
    switch (MIDI.getType()) {     //recognize MIDI Type as MIDI Clock and MIDI Clock start, stop, continue msg's
      case midi::Clock:
        MIDI.sendRealTime(midi::Clock);
        clk++;
        clk = clk % 24;                                 // 24 clock messages per beat
        if (clk / 6) digitalWrite(13, LOW);  // this should light it up for 25% of the time
        else digitalWrite(13, HIGH);
        break;
      case midi::Start:
        break;
      case midi::Continue:
        break;
      case midi::Stop:
        break;
      default:                    //sends other types of msg's
        MIDI.send(
          MIDI.getType(),
          MIDI.getData1(),
          MIDI.getData2(),
          MIDI.getChannel()
          );
        break;
    }
  }
}

Well I really have to thank you for taking the trouble to look at this!
Of course your right about midi thru. I had confused the function of midi thru with midi out.
I modified the code with your suggestion...

case midi::clock:
MIDI.sendRealTime(midi::Clock);
break;

And this made all the difference!
My loop pedal has an indication led for incoming clock and that's how i knew clock signals were always reaching it.
I do appreciate the help :smiley:

You are welcome !

Deva_Rishi, As I understand it

Is allowing the midi clock data to pass through 'midi out' with very little latency (is this correct?). I have compared it with 'midi thru' and there is a noticeable difference. Is there possibly another way to allow the clock to pass through the filter with less latency?

It makes it 'cut the cue'

hardware midi-thru ? yes there would be a noticeable difference, even just the reception and transmission will take a couple of ms. A faster way i do not know, but in my experience, a little 'groove' from the midi sync actually is beneficial to create a live feel.

If it really is about the sync, there is also another approach. You can receive the sync, derive a speed, and resend the sync with a compensation.

I couldn't agree more Deva_Rishi!
Though just for now it is about the sync. Originally I was going to use a master clock to sync four musicians, each musician taking their own connection from a splitter box connected to the master clock. However, that plan changed to using a sequencer with some pre-programmed material as the master clock. So the latency due to filtering concerned me a little especially as any number of splitters or further filtering by individual musicians potentially could be added. Your solution by re-sending a sync with compensation I'm guessing would lie with the sequencer as clock I'm guessing? I can look that up but thanks for the interest!!

The idea i had was that you could simply have a device receive midi-sync, let it calculate the speed, and let it be 'just a little less' than a whole bar late., which would make it a tad early. Personally i don't bother, we are talking ms here, and any distance from the speakers will also incur latency at about 3ms per meter.

Appreciate that idea! I'll be doing some testing shortly with all equipment involved and will let you know how it works out. Thanks again Deva_Rishi

1 Like

Deva_Rishi, in case your still watching this I'd like to pick your brains on another issue using similar code. Except, this time I'm not filtering out stop and start messages as I need them. Once again I'm using a master clock to control my Uno. From my Uno I have a keyboard plugged in which responds to stop and start as well as tempo change without issue. However, each time I stop and start the master clock the LED on the Uno doesn't really sync with the master clock's LED but the keyboard does perfectly. How might I modify the code to have the Uno's LED sync with the master clock after every stop and start?


// MIDI clock as per Little Scale
byte midi_start = 0xfa;
byte midi_stop = 0xfc;
byte midi_clock = 0xf8;
byte midi_continue = 0xfb;

static uint8_t clk = 0;


// Variables
int tempoled = 13;
int play_flag = 0;
byte data;


// Setup
void setup() {
  Serial.begin(31250);
  pinMode(tempoled, OUTPUT);
}


// Program
void loop() {

  if (Serial.available() > 0) {
    data = Serial.read();

    if (data == midi_start) { // if midi in start
      Serial.write(midi_start); // send midi out start

      play_flag = 1;
    }

    if (data == midi_continue) { // if midi in continue
      Serial.write(midi_continue); // send midi out continue

      play_flag = 1;
    }

    if (data == midi_stop) { // if midi in stop
      Serial.write(midi_stop); // send midi out stop
      play_flag = 0;
    }



    else if ((data == midi_clock) && (play_flag == 1)) {
      clk++;
      clk = clk % 24;                                 // 24 clock messages per beat
      if (clk / 6) digitalWrite(tempoled, LOW);  // this should light it up for 25% of the time
      else digitalWrite(tempoled, HIGH);
      Serial.write(midi_clock); // send midi clock to out... Provides tempo!

    }
  }
}

You need to reset clk when you begin so the LED is always on the first 25% of the beat.

// MIDI clock as per Little Scale
byte midi_start = 0xfa;
byte midi_stop = 0xfc;
byte midi_clock = 0xf8;
byte midi_continue = 0xfb;

static uint8_t clk = 0;


// Variables
int tempoled = 13;
int play_flag = 0;
byte data;


// Setup
void setup() {
  Serial.begin(31250);
  pinMode(tempoled, OUTPUT);
}


// Program
void loop() {

  if (Serial.available() > 0) {
    data = Serial.read();

    if (data == midi_start) { // if midi in start
      Serial.write(midi_start); // send midi out start
      play_flag = 1;
      clk=0;
    }

    if (data == midi_continue) { // if midi in continue
      Serial.write(midi_continue); // send midi out continue
      play_flag = 1;
      clk=0;
    }

    if (data == midi_stop) { // if midi in stop
      Serial.write(midi_stop); // send midi out stop
      play_flag = 0;
    }
    
    if ((data == midi_clock) && (play_flag == 1)) {
      clk++;
      clk = clk % 24;                                 // 24 clock messages per beat
      if (clk / 6) digitalWrite(tempoled, LOW);  // this should light it up for 25% of the time
      else digitalWrite(tempoled, HIGH);
      Serial.write(midi_clock); // send midi clock to out... Provides tempo!
    }
  }
}

blh64, can't thank you enough!
Works like a charm now, but one thing puzzles me.
Whilst

begins with every new start after stopping, it appears to just come in early every time afterwards, just before the beat and therefore before the led on the master clock. What could be causing this? Is it possibly sitting in the wrong place within the code?