Go Down

Topic: MIDI to DMX converter - strange behavior / timing problems? (Read 736 times) previous topic - next topic

grnr

Mar 10, 2013, 03:07 pm Last Edit: Mar 11, 2013, 01:01 pm by grnr Reason: 1
Hi - I am building a MIDI to DMX converter in order to control some LED lights from ableton live.

I have used the schematics from Sonic Robots here:
http://sonicrobots.com/2013/01/24/midi-to-dmx-arduino-control-shield/

Unfortunately the code posted on that page didn't work for me, so I've been hacking together my own. The code below works, but it has problems.

If I send two (or more) midi notes at the same time, it will only respond to one (or none) of them. I can work around this by delaying notes by ~1ms, but it's not ideal.

As far as I can work out, each time a note on is received, the DmxSimple.write is sending a full DMX frame, which takes over 1ms from what I can work out! So while this is being sent, the MIDI.read is missing out on the next midi message.

Any idea on how to fix this? Ideally I'd like to be able to receive 24 notes simultaneously...

g

Code: [Select]
#include <DmxSimple.h>

#include <MIDI.h>  // add midi library



// This is the function that will be called by Note on messages.

void ISayGo(byte channel, byte pitch, byte velocity) {
              digitalWrite(13,HIGH)   ;   //switch on LED for debugging
DmxSimple.write(pitch, (velocity * 2));         // send DMX on channel equal to note pitch, value equal to twice the velocity
                                                // (MIDI velocity is in range 0-127 and DMX is in range 0-255)
}



// ...and this one handles Note off)
void ISayStop(byte channel, byte pitch, byte velocity){
 
   
digitalWrite(13,LOW);       // Switch off debug LED
DmxSimple.write(pitch,0);    // Set the DMX channel equal to the note pitch to 0 as in OFF!
}

void setup() {
  DmxSimple.maxChannel(24);
pinMode(13, OUTPUT);
MIDI.begin(1);
  MIDI.setHandleNoteOn(ISayGo); // Call function ISayGo when a NoteOn is received
  MIDI.setHandleNoteOff(ISayStop); //Call function ISayStop when a NoteOff is received
}

void loop() {
  MIDI.read();   // Listen for MIDI...
}





astrofrostbyte

#1
Mar 10, 2013, 03:28 pm Last Edit: Mar 10, 2013, 03:30 pm by astrofrostbyte Reason: 1
Maybe you can add checks to make sure the first byte is really a commandbyte before you start reading the rest of the frame,  
add some way to get back into sync with your frame.
If the Commandbyte is not what you expect, flush it and try to resync the communication.
Code: [Select]
void checkMIDI(){
 do{
   if (Serial.available()){
     commandByte = Serial.read();
     noteByte = Serial.read();
     velocityByte = Serial.read();
     if (commandByte == 144)        {  DmxSimple.write(noteByte,255);    }
     if (commandByte == 128)        {  DmxSimple.write(noteByte,0);        }
   }
 }
 while (Serial.available() > 24);//when three bytes available
}

Sometimes depending on the protocol there is ways to recognize the frame structure and than you can recover from bad communication.

PS.
- Maybe this post fits better in the group "Networking, Protocols, and Devices" since this is more serial protocol stuff
- Put code in code brackets
Gear: Arduino- Uno,Due,Ethernet,  OLS, Buspirate, J-Link, TDS1002, Rigol DG1022

grnr

thanks for your suggestions - I've actually managed to get it working better using the midi library. my problem now is that it doesn't respond to note on or off messages that are sent simultaneously - I can work around this by delaying notes by tiny amounts in my sequencer, but would love to get the arduino code to recognise notes that come in together!

here's the code anyway:

Code: [Select]
#include <DmxSimple.h>

#include <MIDI.h>  // add midi library



// This is the function that will be called by Note on messages.

void ISayGo(byte channel, byte pitch, byte velocity) {
              digitalWrite(13,HIGH)   ;   //switch on LED for debugging
DmxSimple.write(pitch, (velocity * 2));         // send DMX on channel equal to note pitch, value equal to twice the velocity
                                                // (MIDI velocity is in range 0-127 and DMX is in range 0-255)
}



// ...and this one handles Note off)
void ISayStop(byte channel, byte pitch, byte velocity){
 
   
digitalWrite(13,LOW);       // Switch off debug LED
DmxSimple.write(pitch,0);    // Set the DMX channel equal to the note pitch to 0 as in OFF!


}


void setup() {
  DmxSimple.maxChannel(24);
pinMode(13, OUTPUT);
MIDI.begin(1);
  MIDI.setHandleNoteOn(ISayGo); // Call function ISayGo when a NoteOn is received
  MIDI.setHandleNoteOff(ISayStop); //Call function ISayStop when a NoteOff is received
}

void loop() {
  MIDI.read();   // Listen for MIDI...
}





grnr

#3
Mar 10, 2013, 04:46 pm Last Edit: Mar 11, 2013, 12:57 pm by grnr Reason: 1
-edit - removed for clarity, added to original post...


grnr

Having done a bit of reading into the DMX protocol, I think I can understand better what my problem is, I'm just not sure how to fix it!

When a MIDI note is received, the Dmxsimple.write command will send a full DMX frame - this takes 44us per channel, which is 1056us - I think it will be a little more with the break and start byte.

So if two notes are received at once (which will actually be one after the other since MIDI is serial data) the first one causes the code to miss the next one, since it's busy for ~1ms sending a full DMX frame. I guess I could look into coding in some sort of buffer that waits for notes over a given timeframe then sends a DMX frame? I'm open to suggestion!

Go Up