Open jhsa opened 3 years ago
Not sure I understand what you mean.
Check the return code.
uint8_t rc;
rc = Midi1.SendData(msg, 0);
if( rc != 0 ){
// Error code in rc. Check the value of rc in some way.
}
rc = Midi2.SendData(msg, 0);
if( rc != 0 ){
// Error code in rc. Check the value of rc in some way.
}
I can't. the only device I have that works with this library is the pro-mini which only have one serial port. To use the serial port for something else, I cannot send MIDI. And without midi I cannot check the problem.. Is there any other way?
I will try to find out more. I think the problem is related to sending midi messages that include DataByte2 as well. And somehow the problem seems to occur only on the first device. If I comment the code to send the second device, everything seems to work fine.
Software serial is always an option...
Ok, I used software serial on pins 4 and 5 of the arduino pro-mini. I take it they aren't being used by the library? Could you please check the following code is ok?
void loop()
{
// uint8_t msg[4];
// uint8_t msg1[4];
Usb.Task();
uint8_t msg[4];
uint8_t rc1;
uint8_t rc2;
uint32_t t1 = (uint32_t)micros();
if (MIDI.read()) {
msg[0] = MIDI.getType();
switch (msg[0]) {
case midi::ActiveSensing :
break;
case midi::SystemExclusive :
//SysEx is handled by event.
break;
default :
// If this is a channel messages, set the channel number.
if ( msg[0] < 0xf0 ) {
// The getchannel() returns 1-16, but the MIDI status byte starts at 0.
msg[0] |= MIDI.getChannel() - 1;
}
msg[1] = MIDI.getData1();
msg[2] = MIDI.getData2();
break;
}
if ( Midi1 ) Midi1.SendData(msg, 0);
rc1 = Midi1.SendData(msg, 0);
if( rc1 != 0 ){
mySerial.print("MIDI 1 - ");
mySerial.println(rc1);
}
if ( Midi2 ) Midi2.SendData(msg, 0);
rc2 = Midi2.SendData(msg, 0);
if( rc2 != 0 ){
mySerial.print("MIDI 2 - ");
mySerial.println(rc2);
}
}
if ( Midi1 ) {
MIDI_poll(Midi1);
}
if ( Midi2 ) {
MIDI_poll(Midi2);
}
//delay(1ms)
//doDelay(t1, (uint32_t)micros(), 1000);
}
ok, let me try to explain what I am seeing .
If no hub is connected to the host and I send midi I get an RC value of 14 for each device.
If a Hub is connected, but no devices connected to it, i get an RC value of 13 for each device.
If both devices are connected I get nothing meaning RC = 0.
If I disconnect a device from the hub, I get an RC value of 219 every time I send a midi message.
This seems to be the expected behavior, right?
Now the weird stuff, which I suspect it is related toi my guitar effects pedalboard.
I am sending Presets from another controller, through the Host to the guitar effects pedalboard, and also have a USB/MIDI converter connected to the Hub as device number 2.
the Bypass preset I am sending has several MIDI type messages. PC, CC and Note. The other presets send mainly PC, and some send PC and CC.
Most of the times when i press some preset, and then press bypass I get an RC value of 4. if I connect the pedalboard as device 2, the RC value of 4 also changes to RC2. So it seems to be related to the pedalboard. If I connect another device instead, I get RC = 0 for both devices every time I send a midi message. So, what does an RC value of 4 mean? It seems my pedalboard is sending something back for some reason?
Something else, since i am using the software serial for displaying the values of RC in the serial monitor, the MIDI seems to be behaving correctly. I haven't seen it fail yet. Sometimes it doesn't change or it takes a while to respond, but I haven't seen it go out of sync with what I am sending like it did before. So, why this? needs some delay somewhere?
I hope all this info makes sense, and it helps finding the problem Thank you so much for your help...
Ok, replaced the USB MIDI converter with another device and now the problem is back.. Will check serial now.
Ok, With this device connected to MIDI2, every time I send a MIDI message, RC2 = 4. If I connect it to MIDI1, I get RC1 = 4 every time I send a midi message through the USB Hub.
So, what does this mean?
Without knowing what RC = 4 means, we can't find the problem. :)
https://github.com/felis/USB_Host_Shield_2.0/blob/master/max3421e.h#L213-L229
The NAK means receiving device cannot accept data or transmitting device cannot send data.
Your code is wrong. The error code has not been checked correctly.
if ( Midi1 ) {
rc1 = Midi1.SendData(msg, 0);
if( rc1 != 0 ){
mySerial.print("MIDI 1 - ");
mySerial.println(rc1);
}
}
if ( Midi2 ) {
rc2 = Midi2.SendData(msg, 0);
if( rc2 != 0 ){
mySerial.print("MIDI 2 - ");
mySerial.println(rc2);
}
}
Thanks, but which code is wrong? the serial code to check RC? I am a beginner and i do apologize, but do you have some right code then? :)
4 : NAK from peripheral The NAK means receiving device cannot accept data or transmitting device cannot send data.
Well, the device receives and send data, but I will check that device as it is a DIY MIDI controller and uses another USB composite library for the STM32F1. The funny thing is that the same library used on the same processor, but with the USB / MIDI converter code works fine and doesn't throw any error. So, perhaps it is the controller's code. Perhaps not. Also, as you said above that you don't have more midi devices, I guess that the library is also not fully tested, at least with a hub and several midi devices??
which code is wrong?
Your code
if ( Midi1 ) Midi1.SendData(msg, 0); // <- What is the return code for this?
rc1 = Midi1.SendData(msg, 0);
This:
if ( Midi1 ) Midi1.SendData(msg, 0);
is the same as this as far as I know.
if ( Midi1 ) { Midi1.SendData(msg, 0); }
I still don't see how it is wrong?? Or am I missing something here?
you are missing the return code :-)
do this:
if ( Midi1 ) {
uint8_t ret = Midi1.SendData(msg, 0);
Serial.println(ret);
}
if ret is NAK, that's a temporary failure, just retry with the same message. Also, shouldn't the second arg be the length of msg?
Sorry guys, I am an idiot obviously. Now I see what I have done wrong. Is it ok now?
if ( Midi1 ) Midi1.SendData(msg, 0);
if ( Midi1 ) {
rc1 = Midi1.SendData(msg, 0);
if( rc1 != 0 ){
mySerial.print("MIDI 1 = ");
mySerial.println(rc1);
}
}
if ( Midi2 ) Midi2.SendData(msg, 0);
if ( Midi2 ) {
rc2 = Midi2.SendData(msg, 0);
if( rc2 != 0 ){
mySerial.print("MIDI 2 = ");
mySerial.println(rc2);
}
}
And I get the same
MIDI 2 = 4 MIDI 2 = 4 MIDI 2 = 4 MIDI 2 = 4 MIDI 2 = 4 every time I send a midi message. I think it might be related to my DIY controller because if I swap devices I get:
MIDI 1 = 4 MIDI 1 = 4 MIDI 1 = 4 MIDI 1 = 4 MIDI 1 = 4
every time I send a message. So, this seems to be related to my controller itself.
But what is weird is that I mad a USB to MIDI converter (Not Host) using the same library and processor of my controller and it doesn't have the same problem. No errors. I think the USB composite library I am using might have problems when used with other libraries. Perhaps some i2c stuff. Need to investigate better.. Meanwhile if some one know another USB composite library library that works with the STM32F103 chip, please let me know.. I can't find another. This is the one I am using:
But the thing is. If i connect this device directly to my computer it works well.. It is just through the Host and hub that it doesn't. I am at loss with this. :(
A lot of BSP that have USB support have quirks because they follow quirks in PC USB stacks. If you can, try a different USB stack on the STM device.
A lot of BSP that have USB support have quirks because they follow quirks in PC USB stacks. If you can, try a different USB stack on the STM device.
I wouldn't know how to do that.. Don't even know what a BSP is. As I said, I am a beginner on Arduino. I try to learn though, and it brought me this far. But still not enough to be an advanced Arduino coder. I am still very new to this.
But I think there might also be some issue when sending several different MIDI messages together. And i think I can get proof of that.. I am setting up some serial to monitor what is being sent. So far I can see that sometimes the DATA2 byte is sent with the same value of the Type byte. Will try to post the results in a while
BSP == Board Support Package, much like Arduino has different BSP foir the various boards, ST has different support for their MCUs. I have an ST based MIDI device here, which constantly drops data, reverse of your issue. Trouble with it is that it wants high speed USB, and low/full speed, while it works, isn't fast enough, and the MCU should be queuing the key presses for up to 100ms or so, and doesn't.
I think the poor F103 is not the problem here. I am just uploading a video showing the problem. I had to make a video as writing a post would take too much space here. While is uploading I explain what I did.
My setup is a Midi controller on the breadboard, sending midi to MidiOX on the computer via an USB / Midi adapter, and also to the Arduino Pro-Mini connected to the USB Host shield.
I am pressing only the bypass button on my controller, and comparing the data between what is sent to MidiOX, which is the real data being sent by the controller, and the serial monitor, which is the data sent by the USB Host. As you will see, the data that is sent is wrong by the Host, and it seems to be out off sync. Sometimes, it gets in sync and it sends the correct data. will post the video as soon as it finishes uploading.
Ok, here is the video.. Please have a look. I have no idea why this is behaving like this :( It is driving me crazy at this point.. :( Thank you so much for your help.
https://www.youtube.com/watch?v=_OhkCo3w9Jw
Also, here is the code I used to get the serial data.
Usb.Task();
uint8_t msg[4];
uint8_t rc1;
uint8_t rc2;
uint32_t t1 = (uint32_t)micros();
if (MIDI.read()) {
msg[0] = MIDI.getType();
mySerial.print("MIDI Type(hex) = ");
mySerial.println(msg[0], HEX);
switch (msg[0]) {
case midi::ActiveSensing :
break;
case midi::SystemExclusive :
//SysEx is handled by event.
break;
default :
// If this is a channel messages, set the channel number.
if ( msg[0] < 0xf0 ) {
// The getchannel() returns 1-16, but the MIDI status byte starts at 0.
msg[0] |= MIDI.getChannel() - 1;
mySerial.print("Channel = ");
mySerial.println(MIDI.getChannel());
mySerial.println();
}
msg[1] = MIDI.getData1();
msg[2] = MIDI.getData2();
if ( Midi1 )
{
Midi1.SendData(msg, 0);
mySerial.println("MIDI 1");
mySerial.print("Status Byte = ");
mySerial.println(msg[0]);
mySerial.print("DataByte 1 = ");
mySerial.println(msg[1]);
mySerial.print("DataByte 2 = ");
mySerial.println(msg[2]);
mySerial.println();
}
if ( Midi2 ) {
Midi2.SendData(msg, 0);
mySerial.println("MIDI 2");
mySerial.print("Status Byte = ");
mySerial.println(msg[0]);
mySerial.print("DataByte 1 = ");
mySerial.println(msg[1]);
mySerial.print("DataByte 2 = ");
mySerial.println(msg[2]);
mySerial.println("************************");
mySerial.println();
}
break;
}
if ( Midi1 ) {
rc1 = Midi1.SendData(msg, 0);
if ( rc1 != 0 ) {
mySerial.print("MIDI 1 = ");
mySerial.println(rc1);
}
}
if ( Midi2 ) {
rc2 = Midi2.SendData(msg, 0);
if ( rc2 != 0 ) {
mySerial.print("MIDI 2 = ");
mySerial.println(rc2);
}
}
}
I think I see what is happening.
MIDI messages have a variable size. :-) You need to accommodate this fact, based on the message type.
isn't the midi library supposed to do that?
Yes, but you are ignoring it when you are reading from serial. I do have a solution for how you are doing this, if you only want to pass messages from serial to both midi. 1: when you read from serial, check the midi type. 2: based on the type, read in the remaining part of the message. 3: send it to both.
Thanks.. But what about using the librarie's callbacks like the one used for Sysex?? Possible?
Hmmm, could it be a Running Status problem??
I'm testing with the following code. Your code isn't made exactly as we pointed out. https://gist.github.com/YuuichiAkagawa/52710af4bc013d1af7248b1aaa80f7f2
It looks like it's working fine for sending program changes. https://youtu.be/s7ci5oXFu7g
Testing is ongoing as there seems to be a problem in the case of NAK.
You need to accommodate this fact, based on the message type.
The USBH_MIDI library correctly determines the length of the message from the message type and processes it. MIDI.read() returns one message at a time.
Thank you so much for looking into this.
I'm testing with the following code. Your code isn't made exactly as we pointed out. https://gist.github.com/YuuichiAkagawa/52710af4bc013d1af7248b1aaa80f7f2
This code has just one direction. I am working on a bidirectional device. From MIDI devices to serial it seems to work, but not from serial to both midi devices. That is what i am trying to do.
It looks like it's working fine for sending program changes. https://youtu.be/s7ci5oXFu7g
Program change only seems to kinda work. the problem is when I try to send different messages together.
Ok, I am testing this simple MIDI code, just to try to narrow the problem.. I am sending midi from the computer using an USB to MIDI adapter. There are definitely problems, either with my Pro-Mini boards or the MIDI library itself. I have written a script on the midi tool i am using to send the same midi as the Bypass preset of my controller. If I keep sending the same data (see below), program 1 72 noteon 2 61 72 control 1 16 0 control 1 7 0 it displays the data correctly once, and then wrong for a few times, and then correctly once again. I think it is cyclic.. Will now use another MIDI to USB adapter, to also rule it out ass a problem.
#include <MIDI.h>
#include <SoftwareSerial.h>
SoftwareSerial mySerial(4, 5); // RX, TX
//Arduino MIDI library v4.2 compatibility
//MIDI_CREATE_DEFAULT_INSTANCE
MIDI_CREATE_DEFAULT_INSTANCE();
void handle_sysex( byte* sysexmsg, unsigned sizeofsysex) {
}
void setup()
{
// _MIDI_SERIAL_PORT.begin(31250);
MIDI.begin(MIDI_CHANNEL_OMNI);
MIDI.turnThruOff();
MIDI.setHandleSystemExclusive(handle_sysex);
mySerial.begin(9600);
mySerial.println("Hello, world?");
}
void loop()
{
uint32_t t1 = (uint32_t)micros();
if (MIDI.read()) {
uint8_t msg[4];
msg[0] = MIDI.getType();
mySerial.print("MIDI Type = ");
mySerial.println(msg[0], HEX);
switch (msg[0]) {
case midi::ActiveSensing :
break;
case midi::SystemExclusive :
//SysEx is handled by event.
break;
default :
// If this is a channel messages, set the channel number.
if ( msg[0] < 0xf0 ) {
// The getchannel() returns 1-16, but the MIDI status byte starts at 0.
msg[0] |= MIDI.getChannel() - 1;
mySerial.print("Channel = ");
mySerial.println(MIDI.getChannel());
mySerial.println();
}
msg[1] = MIDI.getData1();
msg[2] = MIDI.getData2();
mySerial.print("Status Byte = ");
mySerial.println(msg[0]);
mySerial.print("DataByte 1 = ");
mySerial.println(msg[1]);
mySerial.print("DataByte 2 = ");
mySerial.println(msg[2]);
mySerial.println();
break;
}
}
//delay(1ms)
//doDelay(t1, (uint32_t)micros(), 1000);
}
// Delay time (max 16383 us)
void doDelay(uint32_t t1, uint32_t t2, uint32_t delayTime)
{
uint32_t t3;
t3 = t2 - t1;
if ( t3 < delayTime ) {
delayMicroseconds(delayTime - t3);
}
}
Well, I think I have managed to kinda make it work. 1) Do not use software serial to debug this thing, just don't.. I have lost 2 days for nothing becasuse of it.. All those MIDI messages with wrong values seem to have been caused by the software serial. it is not reliable, just don't use it. 2) The pro-mini board, at least the one I was using, just can't cope with this kinda stuff. I ended up using a 5V 16MHz board, but running at 3.3V.. It still works. Even like this, I think ir just lacks the power needed.
3) the Pro-Mini doesn't seem to like the MIDI signal from my DIY Midi controller. This was the main problem I think. I connected another STM32 Blue Pill board between the Midi controller and the Pro-Mini, flashed it with the exact same MIDI input code as the USB Host serial MIDI, using the same library of course, but with Midi Thru enabled. So, Midi output from my controller into Blue Pill RX pin, and then out of the TX pin to the Pro-Mini input. It seems to work. at least I was playing with it for a while, with 2 USB devices connected to the Hub, and still haven't seen it fail. More testing needed of course.
This is weird because my DIY MIDI controller, uses exactly the same library as both the other blue pill connected as repeater, and the pro-Mini. the Controller is also based on a Blue Pill board. So, i don't understand why it does not like the controller's signal. The computer and other devices work well with it.
Having said this, I would really appreciate if the Blue Pill board (STM32F103C8) was supported in the future by the USB Host project, so I could build my little device to make my controller more complete. I am a musician, and this controller is an open project for guitar players that cannot afford commercial stuff and like to build their own stuff.. I will continue testing and report here. Will also try to add a 3rd device if I can repair the junk hub :) Thank you so much for your help and your patience..
And here is the full code I am using at the moment.
#include <MIDI.h>
#include <usbh_midi.h>
#include <usbhub.h>
// Satisfy the IDE, which needs to see the include statment in the ino too.
#ifdef dobogusinclude
#include <spi4teensy3.h>
#endif
#include <SPI.h>
//Arduino MIDI library v4.2 compatibility
#ifdef MIDI_CREATE_DEFAULT_INSTANCE
MIDI_CREATE_DEFAULT_INSTANCE();
#endif
#ifdef USBCON
#define _MIDI_SERIAL_PORT Serial1
#else
#define _MIDI_SERIAL_PORT Serial
#endif
// Set to 1 if you want to wait for the Serial MIDI transmission to complete.
// For more information, see https://github.com/felis/USB_Host_Shield_2.0/issues/570
#define ENABLE_MIDI_SERIAL_FLUSH 0
USB Usb;
USBHub Hub1(&Usb);
USBH_MIDI Midi1(&Usb);
USBH_MIDI Midi2(&Usb);
void MIDI_poll();
void doDelay(uint32_t t1, uint32_t t2, uint32_t delayTime);
//If you want handle System Exclusive message, enable this #define otherwise comment out it.
//#define USBH_MIDI_SYSEX_ENABLE
#ifdef USBH_MIDI_SYSEX_ENABLE
//SysEx:
void handle_sysex( byte* sysexmsg, unsigned sizeofsysex) {
Midi1.SendSysEx(sysexmsg, sizeofsysex);
Midi2.SendSysEx(sysexmsg, sizeofsysex);
}
#endif
uint8_t msg[4];
void setup()
{
MIDI.begin(MIDI_CHANNEL_OMNI);
MIDI.turnThruOff();
#ifdef USBH_MIDI_SYSEX_ENABLE
MIDI.setHandleSystemExclusive(handle_sysex);
#endif
if (Usb.Init() == -1) {
while (1); //halt
}//if (Usb.Init() == -1...
delay( 200 );
}
void loop()
{
Usb.Task();
uint32_t t1 = (uint32_t)micros();
if (MIDI.read()) {
msg[0] = MIDI.getType();
switch (msg[0]) {
case midi::ActiveSensing :
break;
case midi::SystemExclusive :
//SysEx is handled by event.
break;
default :
// If this is a channel messages, set the channel number.
if ( msg[0] < 0xf0 ) {
// The getchannel() returns 1-16, but the MIDI status byte starts at 0.
msg[0] |= MIDI.getChannel() - 1;
}
msg[1] = MIDI.getData1();
msg[2] = MIDI.getData2();
if ( Midi1 )
{
Midi1.SendData(msg, 0);
}
if ( Midi2 ) {
Midi2.SendData(msg, 0);
}
break;
}
}
if ( Midi1 ) {
MIDI_poll(Midi1);
}
if ( Midi2 ) {
MIDI_poll(Midi2);
}
//delay(1ms)
//doDelay(t1, (uint32_t)micros(), 1000);
}
// Poll USB MIDI Controler and send to serial MIDI
void MIDI_poll(USBH_MIDI &Midi)
{
uint8_t size;
#ifdef USBH_MIDI_SYSEX_ENABLE
uint8_t recvBuf[MIDI_EVENT_PACKET_SIZE];
uint8_t rcode = 0; //return code
uint16_t rcvd;
uint8_t readPtr = 0;
rcode = Midi.RecvData( &rcvd, recvBuf);
//data check
if (rcode != 0) return;
if ( recvBuf[0] == 0 && recvBuf[1] == 0 && recvBuf[2] == 0 && recvBuf[3] == 0 ) {
return ;
}
uint8_t *p = recvBuf;
while (readPtr < MIDI_EVENT_PACKET_SIZE) {
if (*p == 0 && *(p + 1) == 0) break; //data end
uint8_t outbuf[3];
uint8_t rc = Midi.extractSysExData(p, outbuf);
if ( rc == 0 ) {
p++;
size = Midi.lookupMsgSize(*p);
_MIDI_SERIAL_PORT.write(p, size);
p += 3;
} else {
_MIDI_SERIAL_PORT.write(outbuf, rc);
p += 4;
}
#if ENABLE_MIDI_SERIAL_FLUSH
_MIDI_SERIAL_PORT.flush();
#endif
readPtr += 4;
}
#else
uint8_t outBuf[3];
do {
if ( (size = Midi.RecvData(outBuf)) > 0 ) {
//MIDI Output
_MIDI_SERIAL_PORT.write(outBuf, size);
#if ENABLE_MIDI_SERIAL_FLUSH
_MIDI_SERIAL_PORT.flush();
#endif
}
} while (size > 0);
#endif
}
// Delay time (max 16383 us)
void doDelay(uint32_t t1, uint32_t t2, uint32_t delayTime)
{
uint32_t t3;
t3 = t2 - t1;
if ( t3 < delayTime ) {
delayMicroseconds(delayTime - t3);
}
}
cool, I might get a chance to play with this tonight :-)
Here is some code with 3 devices. My Hub wasn't broken after all, but one of the ports doesn't work on the PC. It works with this device, go figure :) Sometimes, one of the devices still gets out of sync, and I cannot understand why. I must reboot the Host to get it working correctly again. I think it is still the same problem. It would really be nice if the devs would support the STM32F103, as they are way cheaper than water ;) You can get a Blue Pill or a black pill STM32 board for a couple of Dollars.
#include <MIDI.h>
#include <usbh_midi.h>
#include <usbhub.h>
// Satisfy the IDE, which needs to see the include statment in the ino too.
#ifdef dobogusinclude
#include <spi4teensy3.h>
#endif
#include <SPI.h>
//Arduino MIDI library v4.2 compatibility
#ifdef MIDI_CREATE_DEFAULT_INSTANCE
MIDI_CREATE_DEFAULT_INSTANCE();
#endif
#ifdef USBCON
#define _MIDI_SERIAL_PORT Serial1
#else
#define _MIDI_SERIAL_PORT Serial
#endif
// Set to 1 if you want to wait for the Serial MIDI transmission to complete.
// For more information, see https://github.com/felis/USB_Host_Shield_2.0/issues/570
#define ENABLE_MIDI_SERIAL_FLUSH 0
USB Usb;
USBHub Hub1(&Usb);
USBH_MIDI Midi1(&Usb);
USBH_MIDI Midi2(&Usb);
USBH_MIDI Midi3(&Usb);
void MIDI_poll();
void doDelay(uint32_t t1, uint32_t t2, uint32_t delayTime);
//If you want handle System Exclusive message, enable this #define otherwise comment out it.
//#define USBH_MIDI_SYSEX_ENABLE
#ifdef USBH_MIDI_SYSEX_ENABLE
//SysEx:
void handle_sysex( byte* sysexmsg, unsigned sizeofsysex) {
Midi1.SendSysEx(sysexmsg, sizeofsysex);
Midi2.SendSysEx(sysexmsg, sizeofsysex);
Midi3.SendSysEx(sysexmsg, sizeofsysex);
}
#endif
uint8_t msg[4];
void setup()
{
// _MIDI_SERIAL_PORT.begin(31250);
MIDI.begin(MIDI_CHANNEL_OMNI);
MIDI.turnThruOff();
#ifdef USBH_MIDI_SYSEX_ENABLE
MIDI.setHandleSystemExclusive(handle_sysex);
#endif
if (Usb.Init() == -1) {
while (1); //halt
}//if (Usb.Init() == -1...
delay( 200 );
}
void loop()
{
Usb.Task();
uint32_t t1 = (uint32_t)micros();
if (MIDI.read()) {
msg[0] = MIDI.getType();
switch (msg[0]) {
case midi::ActiveSensing :
break;
case midi::SystemExclusive :
//SysEx is handled by event.
break;
default :
// If this is a channel messages, set the channel number.
if ( msg[0] < 0xf0 ) {
// The getchannel() returns 1-16, but the MIDI status byte starts at 0.
msg[0] |= MIDI.getChannel() - 1;
}
msg[1] = MIDI.getData1();
msg[2] = MIDI.getData2();
if ( Midi1 )
{
Midi1.SendData(msg, 0);
}
if ( Midi2 ) {
Midi2.SendData(msg, 0);
}
if ( Midi3 ) {
Midi3.SendData(msg, 0);
}
break;
}
}
if ( Midi1 ) {
MIDI_poll(Midi1);
}
if ( Midi2 ) {
MIDI_poll(Midi2);
}
if ( Midi3 ) {
MIDI_poll(Midi3);
}
//delay(1ms)
//doDelay(t1, (uint32_t)micros(), 1000);
}
// Poll USB MIDI Controler and send to serial MIDI
void MIDI_poll(USBH_MIDI &Midi)
{
uint8_t size;
#ifdef USBH_MIDI_SYSEX_ENABLE
uint8_t recvBuf[MIDI_EVENT_PACKET_SIZE];
uint8_t rcode = 0; //return code
uint16_t rcvd;
uint8_t readPtr = 0;
rcode = Midi.RecvData( &rcvd, recvBuf);
//data check
if (rcode != 0) return;
if ( recvBuf[0] == 0 && recvBuf[1] == 0 && recvBuf[2] == 0 && recvBuf[3] == 0 ) {
return ;
}
uint8_t *p = recvBuf;
while (readPtr < MIDI_EVENT_PACKET_SIZE) {
if (*p == 0 && *(p + 1) == 0) break; //data end
uint8_t outbuf[3];
uint8_t rc = Midi.extractSysExData(p, outbuf);
if ( rc == 0 ) {
p++;
size = Midi.lookupMsgSize(*p);
_MIDI_SERIAL_PORT.write(p, size);
p += 3;
} else {
_MIDI_SERIAL_PORT.write(outbuf, rc);
p += 4;
}
#if ENABLE_MIDI_SERIAL_FLUSH
_MIDI_SERIAL_PORT.flush();
#endif
readPtr += 4;
}
#else
uint8_t outBuf[3];
do {
if ( (size = Midi.RecvData(outBuf)) > 0 ) {
//MIDI Output
_MIDI_SERIAL_PORT.write(outBuf, size);
#if ENABLE_MIDI_SERIAL_FLUSH
_MIDI_SERIAL_PORT.flush();
#endif
}
} while (size > 0);
#endif
}
// Delay time (max 16383 us)
void doDelay(uint32_t t1, uint32_t t2, uint32_t delayTime)
{
uint32_t t3;
t3 = t2 - t1;
if ( t3 < delayTime ) {
delayMicroseconds(delayTime - t3);
}
}
And I have made a little video showing where I'm at. I would really like to be able to remove the other board that is used only to pass the midi signal thru :( It doesn't do anything else :( Anyway, thank you so much for your help so far.
Nahh, still not good. After a while Midi 1 gets out of sync and stays always one midi message behind. It seems to affect Midi 1 only. It gets out of sync, and it only recovers after reboot. What could cause this?
I am getting tired of this thing and not very far from giving up.
I think you might have overthought the project. What I would do is skip all of the midi-specific protocol parts, and just raw copy everything to each direction.
I think that wouldn't work.. Serial MIDI and USB MIDI use different baudrates?? Or am I misunderstanding your comment?
Don't worry about baud rates. Here's what I would do. Open serial with the standard MIDI baudrate. Check if there is something that came in, and if so, read it in, and send it raw to BOTH UHS MIDI (this is a method in UHS midi, should do what you want!) then check each midi and send that data to serial.
Should work.
thanks for hanging in there. I could try that, but there is a problem. As i said I am a beginner. Do you have an example to put me on the right track? I did try raw MIDI (No Library), but it didn't work. perhaps I did something wrong. Thanks again. Oh, and I found an EP32 board that I am using on another project.. Do I still need the Host shield if i try with it? or can it handle USB Host directly?
Don't bother with the ESP32, especially since you are a beginner. You just need to do Serial.read() and Serial.write(), there are examples for this built-in on the Arduino IDE. It's very simple to do, See under Communication SerialPassthrough example, and just change it to do midi with the proper baud rate... 31250 It's honestly as simple as that :-)
So, if I understand, that instead of:
if (MIDI.read()) {
msg[0] = MIDI.getType();
switch (msg[0]) {
case midi::ActiveSensing :
break;
case midi::SystemExclusive :
//SysEx is handled by event.
break;
default :
// If this is a channel messages, set the channel number.
if ( msg[0] < 0xf0 ) {
// The getchannel() returns 1-16, but the MIDI status byte starts at 0.
msg[0] |= MIDI.getChannel() - 1;
}
msg[1] = MIDI.getData1();
msg[2] = MIDI.getData2();
if ( Midi1 )
{
Midi1.SendData(msg, 0);
}
if ( Midi2 ) {
Midi2.SendData(msg, 0);
}
if ( Midi3 ) {
Midi3.SendData(msg, 0);
}
break;
}
}
Is this what you mean? by the way, I did a project with an ESP32. And i am also quite familiar with the Blue Pill STM32 board. Shame that the blue pill is not supported by the Host library :(
Close. when a midi message comes in from the midi instance, just send the entire message as-is. I'll put together some stuff here, I got a MIDI keyboard, and I can always program an arm chip I have here as MIDI output. I'm working on a bunch of stuff here currently (work, producing hardware) but will have a chance in a few hours to do this.
Thank you so much.. I am just about to check the example you mentioned. Although I suspect that there might also be some problem with the USB Host library or the MIDI library. The reason I want to try the STM32F103 chip I have, or the EP32 is that they are way faster than the Arduino Pro-Mini..
I think it would be better to use a Teensy, you can even get them with host built in, and use UHS3, however right now UHS3 is a touch broken, and I have to fix that yet. :-/
Yeah a teensy would definitely be better. But I am a bit broke at the moment (musician in a Pandemic :( ). I already have some STM32 boards and Pro Minis :) I have a black pill STM32F103, Maple board, and Blue Pills. I had an F401 that I used on another project already. You mean something like this?
void loop() {
if (Serial.available()) { // If anything comes in Serial (USB),
if ( Midi1 ) {
Midi1.SendData(Serial.read(), 0);
}
}
}
Again, I'll have an example after I'm done with what I have to do here. This might be a good "example" for the midi driver.
Ok thanks.. i will wait then. Anyway, the code on my last post didn't work :(
Right, it needs just a touch of post-processing, probably some routing? I'm not all that familiar with midi, or what you are actually attempting to do.
Hi, If I disconnect the USB device from the shield and reconnect, or connect another USB device, most of the times I don't get a connection unless I reboot the Arduino and Shield assembly. Here is a picture of how I connected an Arduino Pro-Mini 8Mhz at 3.3V to the shield. the green numbers are the Arduino Pins. Any ideas why this would happen? Thank you very much for your help...