rppicomidi / midi2usbhost

Make a Raspberry Pi Pico a USB Host to bridge modern USB MIDI to old school MIDI IN and MIDI OUT
MIT License
128 stars 22 forks source link

Info request #11

Open Alefrasca90 opened 1 year ago

Alefrasca90 commented 1 year ago

Hello everybody, I'm new to Pico world, that project looks like the one for me but for a thing, I need to send midi messages on a guitar pedalboard that uses usb type c but only works as a device. Would I be able to interact with it just sending midi signals with this code? I don't need to translate from din pins on UART, but just be able to send CCs and PCs over usb but without setting up a midi software on Pc. As I know already all the messages I need to sent, would be possible to just setup a midi host over the native usb of the Pico?

rppicomidi commented 1 year ago

@Alefrasca90 Welcome to the Pico world. I assume you are a C programmer. I encourage you to read the Getting Started Guide and follow the tutorial. Once you have the example code in the tutorial running, have a go at this. Once you have done that, I can say...

Yes, this code could be a good starting point for a project like that. You can copy this project to a new directory and hack it.

Find the routine poll_midi_uart()_rx around line 87 in the file midi2usbhost.c. Near Line 92 reads

uint8_t nread = midi_uart_poll_rx_buffer(midi_uart_instance, rx, sizeof(rx));

That line will fill the byte buffer rx[] with up to 48 bytes of MIDI message. Comment out or delete that line. What you need to do to send data is to use your own code to fill that rx buffer with your own Control Change, Program Change, etc. messages and set nread to the number of bytes of MIDI messages in the buffer. The if block that follows will write the message out as long as there is a device connected and the message contains at least one byte.

If your pedal has a MIDI out but you don't care what it is sending, around line 166 is the function void tuh_midi_rx_cb(uint8_t dev_addr, uint32_t num_packets). You need to keep this so the USB MIDI receive buffer does not overflow. However, you do not have to do anything with the receive bytes. To discard the bytes, simply delete or comment out the if block that starts if (cable_num ==0) {.

Around line 115 you can delete or comment out midi_uart_instance = midi_uart_configure(MIDI_UART_NUM, MIDI_UART_TX_GPIO, MIDI_UART_RX_GPIO);

I hope that is helpful.

Alefrasca90 commented 1 year ago

Awesome! Thanks! I'll try as soon as go back on project!

Alefrasca90 commented 1 year ago

One more thing, that Rx array that contains up to 48 bytes, why can contains that amount and if I have to send multiple signals can I parse them one after the other inside Rx or is better to call the method more times? That's for understanding how to build my method, thanks.

rppicomidi commented 1 year ago

@Alefrasca90 The longest USB bulk transfer in USB Full Speed mode is 64 bytes, so the buffer that composes USB packets is for transmission is 64 bytes long (CFG_TUH_MIDI_TX_BUFSIZE). All USB MIDI messages are exactly 4 bytes long even though the serial port MIDI stream messages can be 1, 2 or 3 bytes (or sysex, which can be any length and which in USB MIDI is broken down into a collection of 4-byte packets). You should look at the USB MIDI 1.0 Class Specification for details on how the data is packaged.

So you can send at most 64 bytes/4bytes/message =16 messages at once before you overflow the driver's transmitter FIFO. You need 16x3=48 bytes to store 16 3-byte messages, so the size is 48 bytes. In practice, the USB is much faster than the serial port UART, so the 48 bytes is enough.

The call to tuh_midi_stream_write() writes to the USB transmitter buffer. It returns the number of bytes successfully written. If it writes fewer bytes than you wanted to, you can write the rest of them the next time around the main loop. The sequence of calls that sends the data is tuh_midi_stream_write(), tuh_stream_flush() (in the main loop), and then tuh_task() (also in the main loop).

How many Control Change (3-byte) and Program Change (2-byte) messages are required to configure your guitar pedalboard? Do you need SysEx? If it is more than 16 messages at once, put them in a big buffer and change poll_midi_uart_rx() to pull bytes from your buffer instead of the uart receive buffer. Make sure your routine can recover if it could not send all 48 bytes, which can happen if more than 16 messages fits in 48 bytes (e.g., 24 channel pressure messages or program change messages fit in 48 bytes).

I hope this helps and didn't confuse you. When you are done, please publish your project on GitHub. Sounds cool.

Alefrasca90 commented 1 year ago

You're very kind, I'm going to send a CC message per time every time I need to change some parameters so no problems at all, mine was just curiosity about the complicated (for me) usb protocol, thanks so much!