A Pico W interconnects USB MIDI devices and 2 old school MIDI ports with web browser routing control.
This is an example of the web interface.
.
This code was originally supposed to be part of the the midi2usbhub project, but the hardware and features were different enough that it deserved a project of its own.
This project uses a Pico W board, a micro USB to USB A adapter, and a powered USB hub to run software that routes MIDI data among all the devices connected to the hub. There are 2 UART DIN MIDI INs and 2 UART DIN MIDI OUTs, so you can connect to old school MIDI too. You can route the UART MIDI the same way your route USB MIDI. You configure the routing with an embedded web server. You can use a 128x64 OLED and USB keyboard connected to the USB hub to manage the Wi-Fi connection. You can also use command line interpreter (CLI) commands through a serial port terminal to manage Wi-Fi connection and MIDI routing. If you only want to use the CLI, you can omit the OLED, but you have to change the software configuration
The software uses some of the Pico W board's program flash for a file system to store configurations in presets. If you save your settings to a preset, then the midi2usbhub-web software will automatically reload the last saved preset on startup and when you plug a Connected MIDI Device to the hub. You can back up any or all of your presets to a USB Flash drive connected to the USB hub. Presets are stored in JSON format. You can use a USB keyboard and the OLED to recall other presets, or you can use the serial port terminal CLI.
My programming career has focused on low-level embedded programming, so my web programming skills are weak. If you can write better HTML/CSS/Javascript code or just think a different web interface would work better, you can find the files the embedded web server serves in the fsdata/fs directory. Just note that one goal of the web interface is to work even if the Wi-Fi provides no connection to the Internet, so no relying on styles, fonts or other content pulled from from the Web. The other goal is to have everything you need on one page so you don't have to go digging.
This shows the midi2usbhub-web device fully assembled. All the holes and cutouts are made with a non-electric drill, a knife and some files. The lower left display attachment screw interferes with the debug connector, so I had to leave the screw out. Also, the debug connector had to be low profile or else the case won't close. Try to take issues into account if you build your own. With better tools or just more patience than I had, you could probably make this look pretty nice.
This is how I placed the components on the perforated board. You should be able to see from the photo that only the power pins for the USB C connector are wired.
I am sorry, but I didn't actually draw a wiring diagram to build this. If you really need one, please file an issue and I will try to get to it.
I used standard 3.3V MIDI IN and MIDI OUT circuits. The code shows to what Pico W pins I wired the outputs of the MIDI IN circuits and the inputs of MIDI OUT circuits. Because the code uses PIO for the MIDI UART TX, I was able to make the UART output pins that drive MIDI OUT circuits behave like open drain pins. It also allowed me to have 2 old school MIDI ports without using the native RP2040 UART hardware.
The Pico W gets 5V power from the USB C connector. The 5V is wired directly to VBus.
The OLED is wired to the 3.3VDC output of the Pico W board. The code shows which pins are SCL and SDA.
This is how I wired the USB host port to the Pico W (I wound up moving the red VBus wire to the Pico W connector to make the assmebly a litte nicer).
I connected the host port to a 4-port powered USB 2.0 hub and I connected the USB C breakout board to an old USB phone C charger I had.
Please test everything carefully before you connect this to your expensive MIDI gear or even your moderately expensive USB hub.
I am running Ubuntu Linux 22.04LTS on an old PC. I have Visual Studio Code (VS Code) installed and went through the tutorial in Chapter 7 or Getting started with Raspberry Pi Pico to make sure it was working first. I use a picoprobe for debugging, so I have openocd running in a terminal window. I use minicom for the serial port terminal (make sure your linux account is in the dialup group).
The Wi-Fi support code is in early days and is changing rapdily. Make sure the very
latest pico-sdk code found in the develop
branch is in the pico-sdk directory,
which I assume is in ${PICO_SDK_PATH}
.
cd ${PICO_SDK_PATH}
git checkout -b develop origin/develop
git pull
git submodule update lib/lwip
git submodule update lib/cyw43-driver
git submodule update lib/mbedtls
The USB MIDI host driver is currently not part of the TinyUSB stack. It is an
application host driver found in this project's lib/usb_midi_host
directory.
The Pico SDK uses the main repository for TinyUSB as a git submodule. The version
of TinyUSB that ships with the Pico SDK 1.5.1 does not support application host
drivers. That feature was added 15-Aug-2023. You will likely need the latest version
of the TinyUSB library for this code to work correctly. The following describes
how to make sure your Pico SDK version's TinyUSB library supports application host
drivers.
PICO_SDK_PATH
is set to the directory where you installed the pico-sdk.cd ${PICO_SDK_PATH}/lib/tinyusb
git checkout master
If you get warnings about directories not being able to be deleted, it is because TinyUSB removed a lot of git submodules after 0.15.0. You may safely remove them to free up drive space.
git log -1
Date:
is >= 15-Aug-2023, your TinyUSB library should be fine. If not, get the latest
git pull
Clone the midiusb2hub project to a directory at the same level as the pico-sdk directory.
cd cd ${PICO_SDK_PATH}/..
git clone --recurse-submodules https://github.com/rppicomidi/midi2usbhub-web.git
In the file CMakeLists.txt
, you will find the lines
target_compile_definitions(${target_proj} PRIVATE
RPPICOMIDI_PICO_W
# Uncomment the definition of RPPICOMIDI_NO_LCD to use this project with no OLED
# RPPICOMIDI_NO_LCD
)
Delete the #
character next to the RPPICOMIDI_NO_LCD
option and rebuild.
Enter this series of commands (assumes you installed the pico-sdk and the midid2usbhub-web project in the ${PICO_MIDI_PROJECTS} directory)
export PICO_BOARD=pico_w
export PICO_SDK_PATH=${PICO_MIDI_PROJECTS}/pico-sdk/
cd ${PICO_MIDI_PROJECTS}/midi2usbhub-web
mkdir build
cd build
cmake ..
make
The build should complete with no errors. The build output is in the build directory you created in the steps above.
If your project works for some USB MIDI devices and not others, one
thing to check is the size of buffer to hold USB descriptors and other
data used for USB enumeration. Look in the file tusb_config.h
for
#define CFG_TUH_ENUMERATION_BUFSIZE 512
Very complex MIDI devices or USB Audio+MIDI devices like DSP guitar pedals or MIDI workstation keyboards may have large USB configuration descriptors. This project assumes 512 bytes is enough, but it may not be for your device.
To check if the descriptor size is the issue, use your development computer to dump the USB descriptor for your device and then add up the wTotalLength field values for each configuration in the descriptor.
For Linux and MacOS Homebrew, the command is lsusb -d [vid]:[pid] -v For Windows, it is simplest to install a program like Thesycon USB Descriptor Dumper.
For example, this is the important information from lsusb -d 0944:0117 -v
from a Korg nanoKONTROL2:
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 0x0053
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 100mA
This is the important information from the Thesycon USB Descriptor Dumper for a Valeton NUX MG-400
0x01 bNumConfigurations
Device Qualifier Descriptor is not available. Error code: 0x0000001F
-------------------------
Configuration Descriptor:
-------------------------
0x09 bLength
0x02 bDescriptorType
0x0158 wTotalLength (344 bytes)
0x04 bNumInterfaces
0x01 bConfigurationValue
0x00 iConfiguration
0xC0 bmAttributes (Self-powered Device)
0x00 bMaxPower (0 mA)
You can see that if CFG_TUH_ENUMERATION_BUFSIZE
were 256 instead of 512,
the Korg nanoKONTROL2 would have no trouble enumerating but the Valeton
NUX MG-400 would fail because TinyUSB couldn't load the whole configuration
descriptor to memory.
You use the menus on the OLED display for configuring the WiFi connection. You can also use the CLI to do this, but if you have the CLI you don't really need Wi-Fi
and can use the simpler midi2usbhub
project instead. The reasons there are no
buttons for menu navigation on this project are I wanted to keep the project,
low cost and small, and really most Wi-Fi setup requires entering
a password; using up/down/left/right arrows for entering text is awful.
The OLED displays status and simple test menus. You navigate the menus with the up arrow key and the down arrow key on a HID keyboard that you attach to the USB hub. The OLED shows the selected menu item in reverse video. If you press the Enter key on your keyboard, you will trigger the action associated with the select menu item. The action either toggles a value, sends you to sub-menu, or triggers a command like "Connect..." If a submenu calls for entering text, then the Enter key finalizes text input. To exit a submenu, press the Escape key to exit up one level or the Home key to go back to the home screen.
This section shows the initial setup process using the keyboard and the OLED.
Navigate the other items in Wi-Fi setup...
for more features and options.
Wi-Fi setup...
rppicomidi wi-fi router
http://[the IP address shown].index.html
and you
should see a display similar to the web interface at the beginning of this document.Once Wi-Fi is set up, you probably don't need to keep the HID keyboard connected. The midi2usbhub-web will remember the last Wi-Fi setup even if you cycle power and will attempt to reconnect to it on power up.
If you don't need to keep the Wi-Fi interface live or otherwise can't connect to Wi-Fi, you can still use save presets if you have a keyboard handy. From the home screen, navigate to the current preset name and press the Enter key. Choose the preset you want and press the Enter key again. The Pico W will load the selected preset and display its name on the home screen.
Refer to the figure at the top of the page. The Web Interface has been tested with Chrome and Safari on a Mac, Firefox on a Windows 10 PC and on Linux, Edge on Windows 10, Safari on an iPad and Chrome on an Android phone. YMMV for other browser/host configurations.
The menu bar is used for preset management. You can Save, Load, Rename and Delete presets. You choose the mode by clicking/touching the upper left label and then choosing one of 4 buttons to select the mode.
The Routing section shows the sources of MIDI data to the left and sinks of MIDI data on top. If a checkbox at the intersection between a source row and and sink column is checked, then MIDI data from the source will be sent to the sink. If multiple sources are checked for a single sink, then the MIDI streams from all checked sources will be merged to the sink.
The Connected Devices section show a list of all of the sources and sinks. You can edit the Nickname field by clicking on it, editing it, and clicking rename. It is strongly recommended that you do this for USB MIDI devices unless you care to learn the USB IDs. If you save your changes to a preset, then you will only have to do this once.
Show a list of all available commands and brief help text.
List all Connected MIDI Devices currently connected to the USB hub. For example:
USB ID Port Direction Nickname Product Name
0000-0000 1 FROM Drumpads MIDI IN A
0000-0000 1 TO TR-707 MIDI OUT A
0499-1622 1 FROM lead-out reface CS
0499-1622 1 TO lead reface CS
1C75-02CA 1 FROM keys Arturia Keylab Essential 88
1C75-02CA 1 TO keys-in Arturia Keylab Essential 88
1C75-02CA 2 FROM faders Arturia Keylab Essential 88
1C75-02CA 2 TO faders-in Arturia Keylab Essential 88
Rename the nickname for a product's port. All nicknames must be unique. If you need to hook up more than one device with the same USB ID, then you must do so one at a time and change the nickname for each port before attaching the next one to the hub.
Send data from the MIDI Out port of the MIDI device with nickname \<From Nickname> to the MIDI IN port of the device with nickname \<To Nickname>. If more than one device connects to the TO terminal of a particular device, then the streams are merged.
Break a connection previously made using the connect
command.
Disconnect all routings.
Show a connection matrix of all MIDI devices connected to the hub. A blank box means "not
connected" and an x
in the box means "connected." For example, the following shows
MIDI OUT of the "keys" device connected to the MIDI IN of the "lead" device.
TO-> | | | |
| | | |
| | | |
| | | f |
| | | a |
| l | k | d |
| e | e | e |
FROM | | a | y | r |
v | d | s | s |
| - | - | - |
| i | i | i |
| n | n | n |
------------+---+---+---+
lead | | | |
------------+---+---+---+
keys | x | | |
------------+---+---+---+
faders | | | |
------------+---+---+---+
Save the current setup to the given \<preset name>. If there is already a preset with that name, then it will be overwritten.
Load the current setup from the given \<preset name>. If the preset was not previously saved using the save command, then print an error message to the console.
Copy the specified preset to USB flash drive to a file on the drive named /rppicomidi-midi2usbhub/<preset name>
. If no preset name is given, then all presets are copied to the
flash drive.
Copy the specified preset from the USB flash drive directory /rppicomidi-midi2usbhub/<preset name>
to the file system on Pico board's program flash.
Reformat the LittleFs file system in the Pico's program memory. It delete all presets.
Print information about the LittleFs file system
List all files in the LittleFs file system. If you specify a path
, then list the contents
of the path
directory. For now, the only directory path is /
.
Deletes the file with name \<filename> in the LitteFs file system
Change current directory of the current USB flash drive to path
. If path
is not specified,
equivalent to f-cd /
(i.e., set to the drive root directory).
Change current drive number for the USB flash drive. Will only need to do this if you have more than one flash drive plugged in. When you plug in a drive, the code automatically sets the drive number to the latest drive.
List contents of the current directory on the current USB flash drive if path
is not
specified. Otherwise, list the contents of the specified path.
Print the current directory path of the current USB flash drive.
Change real-time clock date. The date and time is used for external flash drive file timestamps.
Change the real-time clock time of day. The date and time is used for external flash drive file timestamps.
Print the current date and time as read from the on-chip real-time clock. The time has a resolution of 2 seconds as because that is what is required for flash drive file timestamps. The initial date and time will be the last time you built the msc-rp2040rtc library.