Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 22 of 22

Thread: Teensy 2.0, USB MIDI and SysEx

  1. #1
    Junior Member
    Join Date
    Feb 2016
    Location
    Los Angeles
    Posts
    10

    Teensy 2.0, USB MIDI and SysEx

    I recently purchased a Teensy 2.0 as I am migrating a project that started with an Arduino but I wanted to keep my hardware at +5 Vdc while making use of the extra output pins and the USB MIDI features. I am hitting wall with trying to read System Exclusive messages from a DAW on a macintosh and need some guidance.

    Firstly, the serial MIDI library supports a callback function to read System Exclusive messages but I don't see that functionality duplicated with USB MIDI. Is this correct? If so, is it forthcoming?

    Secondly, as a test I wrote a very small program to test and see if an incoming message is System Exclusive and I seem to be getting a lot of data with nothing else on my computer sending MIDI. I'm making use of the macintosh utility MIDI Monitor to keep an eye on things and it looks like the Teensy is currently seeing a ton of phantom SysEx data.

    Here's my simple program:

    Code:
    void setup() {
      // put your setup code here, to run once:
        Serial.begin(38400);
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
      usbMIDI.read();
    Serial.print("Message is of type ");Serial.println(usbMIDI.getType());
    }
    The output to serial is attached as a screencap. Any advice would be greatly appreciated!

    Click image for larger version. 

Name:	Screen Shot 2016-10-18 at 9.55.26 PM.png 
Views:	188 
Size:	81.6 KB 
ID:	8498

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    21,821
    You need to check the number returned by usbMIDI.read(). Zero (false) indicates the PC hasn't sent anything new. You don't want to keep printing info and calling things like usbMIDI.getType() when there's nothing new to read.

  3. #3
    Junior Member
    Join Date
    Feb 2016
    Location
    Los Angeles
    Posts
    10
    Thank you, Paul! Clearly a rookie mistake. This should clean things up quickly.

    Let's see what I can break next.

    Thanks again!

  4. #4
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,340
    Firstly, the serial MIDI library supports a callback function to read System Exclusive messages but I don't see that functionality duplicated with USB MIDI. Is this correct? If so, is it forthcoming?
    usbMIDI page does reference usbMIDI.getSysExArray() but doesn't really show you how to use it. The trick I stole is to use this line of code that defines a data array variable as a pointer.

    byte *sysExBytes = usbMIDI.getSysExArray();

    I used it in my Footsy project and the code shows how you then can refer to the individual bytes. Here's the snippet:
    Code:
    //************SYSEX SECTION**************
    void doSysEx(){
      byte *sysExBytes = usbMIDI.getSysExArray();
      if (sysExBytes[0] == 0xf0 
      && sysExBytes[15] == 0xf7 
      && sysExBytes[1] == 0x7D // 7D is private use (non-commercial)
      && sysExBytes[2] == 0x4C // 4-byte 'key' - not really needed if via USB but why not!
      && sysExBytes[3] == 0x65
      && sysExBytes[4] == 0x69
      && sysExBytes[5] == 0x66){ // read and compare static bytes to ensure valid msg
          for (int i = 0; i < 10; i++) {
          EEPROM.write(i, sysExBytes[i+6]);
          mem[i] = sysExBytes[i+6];
        }  
        byte data[] = { 0xF0, 0x7D, 0xF7 }; // ACK msg - should be safe for any device even if listening for 7D
        usbMIDI.sendSysEx(3, data);         // SEND
        for (int i = 0; i < 3; i++) {
          toggled[i] = false; // for consistant behaviour, start in OFF position
        }
      }
    But that's looking for a known length message... I never did experiment with how you scan for the end byte efficiently.

    I believe this was length limited at some point but I think that may have been fixed.

    BTW the code writes a simple chain of settings to EEPROM so my controller can be configured via midi sysex and retain settings after reboot.

  5. #5
    Junior Member
    Join Date
    Feb 2016
    Location
    Los Angeles
    Posts
    10
    After some time being pulled and distracted by various projects, I finally have time to work on this again.
    Unfortunately, it appears the teensy is dropping sysex packets. I'm not exactly sure what to try to fix and I'm hoping someone smarter than me may have a suggestion. I'm sending sysex messages from protools. In addition to the teensy, I'm using the macOS native application MIDI Monitor to help keep track of things.

    Here's my code…

    Code:
    unsigned long time;
    
    
    void setup() {
      // put your setup code here, to run once:
        Serial.begin(250000);
        Serial.println("midiUsbSysexVer03");
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
      usbMIDI.read();
      if (usbMIDI.read() == 1 && usbMIDI.getType() == 7 ) {//check for sysex 
        handleSysEx();
        }
    
    }
    
    void handleSysEx(){
      Serial.print(millis());Serial.print("\t");
      byte inSize = usbMIDI.getData1();
      byte *sysExBytes = usbMIDI.getSysExArray();
          Serial.print("The sysex length is ");Serial.print(inSize);Serial.print(" bytes\t");
          Serial.print("MIDI sysex message   \t");
           for(int i=0; i!=inSize; i++){
        Serial.print(*sysExBytes++, HEX);Serial.print(" ");
        }
       
       Serial.println(" ");
          
    }
    The following two screencaps come from MIDI Monitor and the Arduino serial monitor. Notice the various sysex messages that are in the MIDI Monitor screencap that don't make it to the Teensy.
    Click image for larger version. 

Name:	MIDI monitor.png 
Views:	233 
Size:	177.2 KB 
ID:	8943Click image for larger version. 

Name:	Arduino serial monitor.png 
Views:	336 
Size:	64.3 KB 
ID:	8944
    Thoughts?

  6. #6
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    21,821
    If I try to recreate this problem, what software do I use to sent the sysex messages? Remember, I'm not a musician and I don't regularly use this sort of software... so specific info & steps would help.

  7. #7
    Junior Member
    Join Date
    Feb 2016
    Location
    Los Angeles
    Posts
    10
    Hi, Paul. This may not be so easy to replicate on your end as I am using ProTools to send Mackie HUI messages.

    An explanation of the spec (via a pdf link) can be found at this page http://forum.cockos.com/showthread.php?t=101328

    In other news, I borrowed a friend's teensy 3.2 and ran my code on it. Both teensy's exhibit the same behavior.

  8. #8
    Junior Member
    Join Date
    Feb 2016
    Location
    Los Angeles
    Posts
    10
    Paul,

    I'm kinda stuck on things. If I remove the sysex test "usbMIDI.getType() == 7" I see TONS of MIDI data, much of it repeated multiple times. When I add back in "usbMIDI.getType() == 7", I see packets of sysex data getting dropped on occasion. Is it possible that the "usbMIDI.getType() == 7" function (or however that may work) is occasionally not seeing new sysex data arrive?

    My next step would be to keep reading "usbMIDI.getSysExArray()" into two different pointers and attempt to compare new vs old data. I'm currently a bit hung up. Any thoughts?

  9. #9
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    6,628
    Sorry, I don't know anything about midi code, so probably won't help much.

    But looking at your loop code. You first do a read not testing anything, then you do read checking for result of 1, followed by your other test. If both reads do actually read a packet might you be skipping some?

  10. #10
    Senior Member
    Join Date
    Jan 2017
    Location
    Maastricht
    Posts
    170
    Hi all,

    I'm new to this forum and this thread is one of the reasons I signed up. I'm also working on MIDI controllers and the Teensy seems like the perfect choice for this application, especially with the newer versions with the larger RAM.
    To give an idea, here's a picture of a project I'm working on:

    Click image for larger version. 

Name:	ZeusPC3.jpg 
Views:	80 
Size:	141.8 KB 
ID:	9541

    A little device for sending program change messages to hardware synths, what sets this one apart is the (planned) ability to show the program names. For this I need to be able to send a program dump request(got that working) and extract the program names from the response. The current limit of 60 bytes is far too small, a typical program dump is about 10-20kB. A Teensy 3.2 should be able to handle this, of course the Arduino Uno on the right has far to little memory for this.
    Using blake's code I can get this response:
    Code:
    18580	The sysex length is 60 bytes	MIDI sysex message   	F0 3E 0 0 50 20 0 40 2 0 0 9 4A 3 36 0 40 0 42 2 0 0 9 4A 3 36 0 0 1E 3F 6A 40 40 40 0 0 40 0 40 1 5 3F 0 40 40 40 0 0 40 0 40 0 0 70 0 0 7F 70 40 40
    When I change the limit in usb_midi.h to 16000 or even 160 the sysex is no longer processed. Any help would be greatly appreciated.
    Tools for sending MIDI sysex mesages:
    For Windows: MIDI-OX
    For Mac: SysEx Librarian
    Examples of large MIDI sysex files can be found here: Waldorf Microwave I Sounds, get the plain_sysex zip. The content can be loaded in one of the tools and sent to the Teensy.

    When I get this up and running I would be more than happy to document it somewhere so that others can have a look at it, use it, learn from it or whatever. Any suggestions as to what would be a good place to document such a project?

    king regards,

    Gerrit

  11. #11
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,340
    byte inSize = usbMIDI.getData1();

    You will overflow this byte after 256 bytes of data.... not sure why it would fail by 160 bytes.

    https://forum.pjrc.com/threads/32369...over-255-bytes

    (...and do you need to use .getData1 to read the size of the array or could you just read from the pointer until you hit the terminating byte?)

    Note also that KurtE is correct that Blakes code should not use two .read commands and that is almost certainly where his missing sysex messages were going.
    Last edited by oddson; 01-30-2017 at 10:25 PM.

  12. #12
    Senior Member
    Join Date
    Jun 2013
    Posts
    323
    Maybe you're not reading the sysex quickly enough? Could all the writing to the serial monitor be taking to long? Why don't you simply track the lengths of the messages?

  13. #13
    Senior Member
    Join Date
    Jun 2013
    Posts
    323
    Also, wouldn't it make more sense to do this for your loop. Perhaps it's possible the usbMIDI.read() returns something that's not 1.
    Code:
    if (usbMIDI.read() && usbMIDI.getType() == 7 )

  14. #14
    Senior Member
    Join Date
    Jan 2017
    Location
    Maastricht
    Posts
    170
    Thanks for the replies!

    To simplify things I reduced the code in the main loop to:
    Code:
      while (usbMIDI.read()) {
       if (usbMIDI.getType() == 7 ) {   //check for sysex 
        Serial.print("The sysex length is ");Serial.print(usbMIDI.getData1());
        Serial.println(" "); 
       }
      }
    Now it works as expected up to sysex length 255:
    Code:
    The sysex length is 255
    When the size in usb_midi.h is 256 or more I get:
    Code:
    The sysex length is 7
    The 7 bytes are always the last seven bytes of the 11527 byte large file irrespective of the size set in usb_midi.h:
    Code:
    .....
    2CD0  00 07 40 15 01 00 28 00  32 00 40 00 00 00 40 00  |  @   ( 2 @   @ |
    2CE0  40 00 20 01 00 33 36 61  20 50 50 47 20 77 61 76  |@    36a PPG wav|
    2CF0  65 20 32 2E 33 00 00 00  00 00 00 00 00 00 00 00  |e 2.3           |
    2D00  00 00 00 00 55 4C F7                              |    UL |
    This is from the mwave2_3.syx file contained in the examples I mentioned earlier.

    IMHO this looks like there's a byte limitation somewhere or am I missing something?

    kind regards,

    Gerrit

  15. #15
    Senior Member
    Join Date
    Jun 2013
    Posts
    323
    The max length is defined as a byte, so you are capped at 256 unless you're ready to edit the usb_midi.h and usb_midi.c files.

  16. #16
    Senior Member
    Join Date
    Jan 2017
    Location
    Maastricht
    Posts
    170
    Quote Originally Posted by yeahtuna View Post
    The max length is defined as a byte, so you are capped at 256 unless you're ready to edit the usb_midi.h and usb_midi.c files.
    Well, that explains it. Thanks.
    I'll look if I can figure out the required changes although I think the 255 byte limit should not be there in the first place. A conservative default size is a good idea though, it doesn't even need to be as much as 255 bytes, 160 bytes is enough for simple sysex applications and even Mackie/HUI control emulations.

    kind regards,

    Gerrit

  17. #17
    Senior Member
    Join Date
    Jun 2013
    Posts
    323
    That library was written back in the day when on board memory was in short supply.

    I've rewritten parts of the library so that I can forward full length sysEx messages from the USB port to a MIDI din out, and vice versa from a MIDI din In to USB MIDI.

  18. #18
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,340
    Quote Originally Posted by oddson View Post
    ...and do you need to use .getData1 to read the size of the array or could you just read from the pointer until you hit the terminating byte?...
    Can anyone say whether this is feasible... to just increase the memory limit and exit a 'while' loop when the extracted byte equals F7?

  19. #19
    Senior Member
    Join Date
    Jun 2013
    Posts
    323
    Perhaps, but what's the problem with using getData1?

  20. #20
    Senior Member
    Join Date
    Jan 2017
    Location
    Maastricht
    Posts
    170
    Quote Originally Posted by yeahtuna View Post
    That library was written back in the day when on board memory was in short supply.

    I've rewritten parts of the library so that I can forward full length sysEx messages from the USB port to a MIDI din out, and vice versa from a MIDI din In to USB MIDI.
    Are these changes available somewhere? Given the increased amount of RAM it makes sense to me to incorporate these changes in the core.

    kind regards,

    Gerrit

  21. #21
    Senior Member
    Join Date
    Jun 2013
    Posts
    323
    It's been customized to meet my particular needs and might not be suitable for everyone as it adds a bit of complexity. And in terms of RAM, it actually uses less. I'll think about posting it.

  22. #22
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,340
    Quote Originally Posted by yeahtuna View Post
    ...and do you need to use .getData1 to read the size of the array or could you just read from the pointer until you hit the terminating byte?...
    Perhaps, but what's the problem with using getData1?
    Other than it doesn't work?

    If you use a 'do while' you should only need to alter one line in the .h file:

    #define USB_MIDI_SYSEX_MAX 60 // maximum sysex length we can receive

    Unless there's a way to do it in the sketch like with the MIDI device display string, which would be better still.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •