Go Down

Topic: MIDI.h Missing Messages / stuck notes (Read 1 time) previous topic - next topic

jbeuckm

Mar 11, 2016, 04:41 am Last Edit: Mar 11, 2016, 05:53 pm by cougar_shuttle
I am using the Arduino platform to write an Atmega328-based MIDI to CV interface for my synthesizers. I have built many similar Arduino-based MIDI>CV interfaces in the past, but this one is occasionally missing messages, leaving notes stuck on and incorrect controller values.

The complete code is included below. I'm hoping that someone here can point me to a reason that some MIDI messages (maybe 1/100) are being misread.

Here is the MIDI In circuit I used:



Code: [Select]
#include <MIDI.h>
#include "AH_MCP4922.h"

#define GATE_PIN 4
#define GATE_LED A5

#define ENV_MOD_CTRL 1
#define ENV_MOD_PIN 3

#define CUTOFF_CTRL 74
#define CUTOFF_PIN 5

#define SAW_CTRL 70
#define SAW_PIN 6
#define SQR_CTRL 71
#define SQR_PIN 9

#define SLIDE_CTRL 65
#define SLIDE_TIME_CTRL 5
#define SLIDE_IN_PIN 13
#define SLIDE_OUT_PIN 12

#define DECAY_CTRL 72
#define DECAY_PIN 11

#define ACCENT_CTRL 11
#define ACCENT_PIN 10


#define ALL_NOTES_OFF 123
#define CTRL_RESET 121

AH_MCP4922 PitchDac(A1,A2,A3,LOW,LOW);

// Velocity gets assigned to the analog cutoff voltage because
// the PWM pins have some latency. Whatever velocity controls cannot
// afford latency since the note is beginning simultaneously.
AH_MCP4922 CutoffDac(A1,A2,A3,HIGH,LOW);

int liveNoteCount = 0;
int pitchbendOffset = 0;
int baseNoteFrequency;

byte selectedChannel;

MIDI_CREATE_DEFAULT_INSTANCE();


void handleNoteOn(byte channel, byte pitch, byte velocity)

  liveNoteCount++;
 
  baseNoteFrequency = (pitch - 12) * 42;
  PitchDac.setValue(baseNoteFrequency + pitchbendOffset);

  CutoffDac.setValue(velocity * 32);

  digitalWrite(GATE_PIN, HIGH);
  digitalWrite(GATE_LED, HIGH);

 }


void handleNoteOff(byte channel, byte pitch, byte velocity)
{
  liveNoteCount--;
 
  if (liveNoteCount <= 0) {
    digitalWrite(GATE_PIN, LOW);
    digitalWrite(GATE_LED, LOW);
  }
}




void handleControlChange(byte channel, byte number, byte value)

  int scaledValue = int(value) << 1;
 
  switch (number) {

    case CUTOFF_CTRL:
      analogWrite(CUTOFF_PIN, scaledValue);
      break;

    case ENV_MOD_CTRL:
      analogWrite(ENV_MOD_PIN, scaledValue);
      break;

    case SAW_CTRL:
      analogWrite(SAW_PIN, scaledValue);
      break;

    case SQR_CTRL:
      analogWrite(SQR_PIN, scaledValue);
      break;

    case DECAY_CTRL:
      analogWrite(DECAY_PIN, 255 - scaledValue);
      break;

    case ACCENT_CTRL:
      analogWrite(ACCENT_PIN, scaledValue);
      break;

    case SLIDE_CTRL:
      if (value >= 64) {
        digitalWrite(SLIDE_IN_PIN, HIGH);
        digitalWrite(SLIDE_OUT_PIN, LOW);
      } else {
        digitalWrite(SLIDE_IN_PIN, LOW);
        digitalWrite(SLIDE_OUT_PIN, HIGH);
      }
      break;
     
    case ALL_NOTES_OFF:
      liveNoteCount = 0;
      digitalWrite(GATE_PIN, LOW);
      digitalWrite(GATE_LED, LOW);
      break;
  }

}


void handlePitchBend(byte channel, int bend)
{
  pitchbendOffset = bend >> 4;

  PitchDac.setValue(baseNoteFrequency + pitchbendOffset);
}


// -----------------------------------------------------------------------------

void setup()
{
    int channelSpan = 1024 / 16;
    int channelInput = analogRead(0);
    selectedChannel = channelInput / channelSpan;
   
    pinMode(GATE_PIN, OUTPUT);
    digitalWrite(GATE_PIN, LOW);
    pinMode(GATE_LED, OUTPUT);
    digitalWrite(GATE_LED, LOW);


    digitalWrite(SLIDE_IN_PIN, OUTPUT);
    digitalWrite(SLIDE_IN_PIN, LOW);
    digitalWrite(SLIDE_OUT_PIN, OUTPUT);
    digitalWrite(SLIDE_OUT_PIN, HIGH);

    pinMode(ENV_MOD_PIN, OUTPUT);
    digitalWrite(ENV_MOD_PIN, HIGH);

    pinMode(SAW_PIN, OUTPUT);
    digitalWrite(SAW_PIN, HIGH);

    pinMode(SQR_PIN, OUTPUT);
    digitalWrite(SQR_PIN, LOW);

    pinMode(CUTOFF_PIN, OUTPUT);
    digitalWrite(CUTOFF_PIN, HIGH);

    pinMode(DECAY_PIN, OUTPUT);
    digitalWrite(DECAY_PIN, LOW);

    pinMode(ACCENT_PIN, OUTPUT);
    digitalWrite(ACCENT_PIN, LOW);


    TCCR0B = (TCCR0B & 0b11111000) | 0x01;
    TCCR1B = (TCCR1B & 0b11111000) | 0x01;
    TCCR2B = (TCCR2B & 0b11111000) | 0x01;
 
    delay(1000);

    playScale(selectedChannel);

    // calibrate 8V
    baseNoteFrequency = (108 - 12) * 42;
    PitchDac.setValue(baseNoteFrequency);
    // calibrate full cutoff
    CutoffDac.setValue(32 * 127);

    MIDI.setHandleNoteOn(handleNoteOn);
    MIDI.setHandleNoteOff(handleNoteOff);
    MIDI.setHandlePitchBend(handlePitchBend);
    MIDI.setHandleControlChange(handleControlChange);
   
    MIDI.begin(selectedChannel);
}


void playScale(int channel) {

  int note = 60;

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

      handleNoteOn(channel, note, 100);
      delay(5000);
      handleNoteOff(channel, note, 100);
      delay(5000);
      note++;
  }

}


void loop()
{
    MIDI.read();
}

pinchme

did you get to the bottom of the problem (I have the same thing happening) ?

zn59

I have the same or similar problem. I made a continous sustain pedal where pedal movements are merged with incoming midi data. This application has worked for years with a Studilogic masterkeyboard.
Yesterday I connected the unit to a Yamaha Motif ES to monitor the midi data in Pianoteq midi monitor to see if Aftertouch is working. I noticed that notes got stuck when playing hard AND pressing the keys to generate Afterouch messeges. Playing the keys more softly worked fine thow!

My first thougts was that maybe there was something wrong with the Yamaha ES but when I bypassed the "Arduino" then everything forked nicely with Yamaha ES!

I suspect that MIDI.h do not handle runnings status correctly. Checked settings, running status is set to true.

Maybe a newer version of MIDI.h will work better?
 

theobsoletemovement

#3
Dec 13, 2018, 11:43 am Last Edit: Dec 13, 2018, 11:49 am by theobsoletemovement
Try adding a delay of about 30ms at the very end of the script.

Otherwise the speed at which you are playing notes in may be too fast for the Arduino to handle.

This way it'll still read all the notes you play but will wait for the next 30ms interval before taking each reading. This is a small enough of an interval to not make a noticeable difference to musical timing but long enough for the Arduino to gain stability.

you can increase the delay time in order to increase stability but if you go too high you might start messing up musical timings and/ or missing notes all together.


The end of your script would look like this: -

void loop()
{
    MIDI.read();

delay(30);

}


if this doesn't work then sorry I don't have any other idea but I'm fairly confident it will.

Grumpy_Mike

Quote
Otherwise the speed at which you are playing notes in may be too fast for the Arduino to handle.
So your soloution to the Arduino not being fast enough is to make it slower?
Can you explain the way that would work?

Your explanation so far lacks logic.

MarkT

I bet the MIDI DIN sockets have loose springs in the Yamaha Motif ES.

DIN connectors like this are not particularly robust in my experience, easily becoming intermittent
with heavy use, or their soldering to the PCB inside the unit cracks...
[ I will NOT respond to personal messages, I WILL delete them, use the forum please ]

theobsoletemovement

That's pretty rude Mike.  And actually I had this exact problem and the delay did fix it.  I suggest you try my suggestion before writing  it off. Especially when you don't seem to be offering any other solution.

Grumpy_Mike

Quote
And actually I had this exact problem and the delay did fix it
Either it was a different problem or the delay did not fix it.

Quote
That's pretty rude Mike.
OK so let me get ruder, I gave you the opportunity of explaining why the delay fixed things, what was your thinking. No such explanation has been forthcoming so I conclude that you don't know what you are doing.

Electronics and code work on logic not guess work and scattering random delays all over the place with no theory is no way for a knowable person to proceed.

This forum is for solid information not flaky superstition.

blender-

i am having similar issues, any progress here? i cant imagine the main arduino midi library being so slow and unprecise?

i am using the sparkfun midi shield, and a lot of times when playing short notes or chords arduino misses some note-offs from the midi in. the controller is definately sending them. i tried several baud rates for the hardware serial port which i use to debug, while the midi TX is handled over alternate software pins as proposed by sparkfun. i'll try using the hardware pins instead..

also testing the midi monitor it seems like there are a lot of midi "system reset" messages every now and then which also cause stuck notes, but they'renot the main cause.

blender-

ok so i finally got the shield to work on the hardware pins and it seems to be fine for now.

i'll try run it on a due next to see if i can use several of them on parallel TX pins...

Go Up