Go Down

Topic: Fast CC Messages causing Realtime "STOP"  (Read 626 times) previous topic - next topic

artkid719

Hello: longtime tinkerer, first time poster...

TL;DR Fast incoming CC messages during MIDI out operations will cause a "stop"

I'm building an Arduino MIDI controller using the Sparkfun MIDI shield.
I went by their documentation and am using the "MIDI Library by Fourty Seven Effects"
Got pretty deep before I realized that more modern libraries were available. 

For the most part I'm able to do everything I need, save one thing, utilize fast CC messages coming into the Ardunio UNO, from another MIDI controller, an expression pedal. 

I'm able to see the CC data coming into the arduino properly on the serial monitor.  But if I'm running another operation, such as, sending notes to an external synthesizer.  The incoming CC data from the expression pedal will cause a MIDI realtime "STOP" to be triggered.

My setup is this:
1. Expression Pedal -> (trs cable) ->
2. Morningstar MC 6 Midi controller -> (midi cable OUT) ->
3. arduino -> (midi cable OUT) ->
4. Simple Synth

I would post my code but its extensive.  I'm guessing this has something to do with filtering?  I've done plenty of digging, tried having the CC data received on different channels.  Asked for a Midi read infrequently.  But still scrubbing the expression pedal will cause a note playing sequence to stop after a few scrubs.  Which I'm guessing is a data logjam issue. 

Thanks for reading.  I've tried to find resources on filtering but I'm not sure what to try besides updating my project to a different library.

I'm using software serial ports, and have Serial printing active.

Thanks for reading, please let me know if there's more information that would be helpful to diagnose or anything you can.  Much appreciated!

Grumpy_Mike

Quote
I'm guessing this has something to do with filtering?
No.

Quote
I'm using software serial ports, and have Serial printing active.
That's your problem. Serial printing takes time what baud rate are you running at?
Software serial takes longer to receive data than the hardware serial.

It sounds like you are filling the buffer up with the large number of CC messages. What are you doing with them?

Quote
I would post my code but its extensive
The usual answer to this is to write a minimum sketch that just shows your problem. Often doing this is enough for you to sort out your own problem.

artkid719

I appreciate your insight Grumpy_Mike.  I've learned from a dozen or so forum posts with your feedback while writing my code, thanks.

I currently have a Serial.begin(9600); in the setup. 
Not sure if this is possible but I think a SoftSerial.begin(31250); is also defined in the library I'm using.

I'm using the CC data from an expression pedal to scrub through some scales associated with the chords the synth is playing.  The synth has 4 note polyphony so i'm using 3 notes for chords and the last one for kind of a randomized solo I can scrub while playing.  And to be clear, the CC messages, and clock are coming from an external device, to the arduino, then out to a synth.

I took your advice and tried to boil down my code as far as possible, always good advice... and was able to make that work as desired.  Aka, a note sequence is playing over time, and a second note is played with it, as defined by the expression pedal.

I found a couple things:

1. I was getting some outlier CC data from my expression pedal.  Because I'm calling the "MIDI.GetType2()" to pull the CC data, I was pulling some things I didn't want.  I didn't see this initially.  Usually the CC data would be in the range I was asking for, but occasionally I would get some number above 127.  I will try clamping that so those outliers don't get out, or call the CC data differently. 

2. I could see how much the Serial.printing of the expression pedal CC data was adding latency in the serial monitor.

I currently trying to apply this concept to my current full sketch, without any luck.
I do have a fair amount of Serial printing happening, giving me readouts of note numbers/velocity, tempo ticks and the like.  Perhaps cutting down on that would help?

I will see if I can unclog whats happening with the Serial information, and report back.  In the meantime let me know if there's anything in what I just said that seems suspect.  :) Thanks.
 
The below code is like a very basic version of what I'm looking for, and appears to be working: 

Code: [Select]
#include <SoftwareSerial.h>
#include <MsTimer2.h>
#include <MIDI.h>

#define PIN_LED_PLAYING 6
#define PIN_LED_TEMPO 7
#define PIN_PLAY_INPUT 2
#define PIN_CONTINUE_INPUT 3

SoftwareSerial SoftSerial(8, 9);
MIDI_CREATE_INSTANCE(SoftwareSerial, SoftSerial, MIDI);

int ticks = 0;
const int song01[] = {45, 46, 47, 48, 49, 50, 51, 52}; //midi note numbers
int note1 = 0;
int prevnote1 = 0;
int note2 = 0;
int prevnote2 = 0;
int songStep = 0;
int playflag1 = 0;

int crazyNote = 0;

void setup() {
  //tempo visual LEDS
  pinMode(PIN_LED_PLAYING, OUTPUT);
  pinMode(PIN_LED_TEMPO, OUTPUT);
  digitalWrite(PIN_LED_PLAYING, HIGH);
  digitalWrite(PIN_LED_TEMPO, HIGH);

  Serial.begin(9600);
  //the below comments are from the library example sketch
  //SoftSerial.begin(31250);
  // do I need to init the soft serial port?
  // No - MIDI will do it.

#if 1
  MIDI.begin();
  //MIDI.setHandleControlChange(myCCfunction);
  MIDI.turnThruOff();
#endif
}

void loop() {

  //these three values I'm not sure if I need, copied from other code//
  static uint32_t loops = 0;
  static uint8_t  ticks = 0;
  static uint8_t  prev_ticks = 0;

  //define note numbers
  note1 = song01[songStep];
  note2 = crazyNote;

  //note player
  if (playflag1 == 1) {
    //turn off if new note values are different
    if (prevnote1 != note1 || prevnote2 != note2) {
      MIDI.sendNoteOff(prevnote1, 0, 1);
      MIDI.sendNoteOff(prevnote2, 0, 1);
    }
    MIDI.sendNoteOn(note1, 127, 1);
    MIDI.sendNoteOn(note2, 127, 1);
    prevnote1 = note1;
    prevnote2 = note2;
    playflag1 = 0; //set note player to off when note has played
  }


  if (  MIDI.read())
  {
    switch (MIDI.getType())
    {
      case midi::Clock: //driven by external midi clock

        MIDI.sendRealTime(MIDI_NAMESPACE::Clock); //send to external synth for visualization of tempo
        ticks ++;
        Serial.print('.');
        Serial.println(ticks);
        if (ticks < 6)
        {
          digitalWrite(PIN_LED_TEMPO, LOW); //tempo LED flash
        }
        if (ticks == 6)
        {
          digitalWrite(PIN_LED_TEMPO, HIGH); //tempo LED flash
        }
        if (ticks >= 24)
        {
          ticks = 0;
          songStep++;
          Serial.print("SONGSTEP = ");
          Serial.println(songStep);
          playflag1 = 1;
        }
        break;

      case midi::Start:
        playflag1 = 1; //start note player
        break;

      case midi::Stop:
        playflag1 = 0; //stop note player
        break;

      case midi::ControlChange:
        //get CC value of expression pedal output
        crazyNote = MIDI.getData2(); //CC number = 1, value = 50-62, channel = 1
        //Serial.print("crazyNote = ");Serial.println(crazyNote); //lag if on
        break;

      default:
        break;
    }
  }

  if (songStep >= 7) {
    songStep = 0; //reset song note array
  }
}

Grumpy_Mike

Quote
I could see how much the Serial.printing of the expression pedal CC data was adding latency in the serial monitor.
Well the first thing you should do is to up the speed of the serial port to at least 115200 baud as 9600 is very much slower than the MIDI rate. It looks that might fill up the transit buffer and that will cause it to wait until it empties and that will stop the MIDI getting through.

Another thing is you are not being very efficient getting the Arduino to read in and then spit out the MIDI, you might try and get it into your system by some other route, like a separate MIDI interface lead. You don't want to implement a MIDI through however as that would interfere with the Arduino generated messages.

Go Up