{"id":25629112,"url":"https://github.com/rppicomidi/usb_midi_host","last_synced_at":"2026-06-10T09:30:21.233Z","repository":{"id":188619043,"uuid":"678969087","full_name":"rppicomidi/usb_midi_host","owner":"rppicomidi","description":"An application level TinyUSB USB MIDI Host driver for the RP2040","archived":false,"fork":false,"pushed_at":"2023-12-18T23:25:30.000Z","size":135,"stargazers_count":21,"open_issues_count":1,"forks_count":3,"subscribers_count":1,"default_branch":"main","last_synced_at":"2023-12-19T16:55:15.367Z","etag":null,"topics":["arduino","midi","raspberry-pi-pico","rp2040","tinyusb","usb-midi-host"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rppicomidi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2023-08-15T20:09:06.000Z","updated_at":"2024-01-04T02:11:39.121Z","dependencies_parsed_at":"2023-08-16T06:06:11.952Z","dependency_job_id":"3b98017d-ab05-4dd3-a12f-ade383af11d7","html_url":"https://github.com/rppicomidi/usb_midi_host","commit_stats":null,"previous_names":["rppicomidi/usb_midi_host"],"tags_count":1,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rppicomidi%2Fusb_midi_host","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rppicomidi%2Fusb_midi_host/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rppicomidi%2Fusb_midi_host/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rppicomidi%2Fusb_midi_host/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rppicomidi","download_url":"https://codeload.github.com/rppicomidi/usb_midi_host/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240222474,"owners_count":19767458,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arduino","midi","raspberry-pi-pico","rp2040","tinyusb","usb-midi-host"],"created_at":"2025-02-22T19:17:01.973Z","updated_at":"2026-06-10T09:30:21.057Z","avatar_url":"https://github.com/rppicomidi.png","language":"C","funding_links":[],"categories":["C"],"sub_categories":[],"readme":"# usb_midi_host\nThis README file contains the design notes and limitations of the\nusb_midi_host application driver for TinyUSB. This driver supports\nboth C/C++ development and Arduino development.\nThe code in this project should run on any TinyUSB supported\nprocessor with USB Host Bulk endpoint support, but the driver and\nexample code have only been tested on a RP2040 in a Raspberry Pi\nPico board.\n\nBy default, this driver supports up to 4 USB MIDI devices connected\nthrough a USB hub, or a single device that may or may not be connected\nthrough a hub.\n\n# Table of Contents\n- [ACKNOWLEDGEMENTS](#acknowledgements)\n- [BUILDING APPLICATIONS WITH THIS DRIVER](#building-applications-with-this-driver)\n- [HARDWARE](#hardware)\n- [API](#api)\n- [EXAMPLE PROGRAMS](#example-programs)\n- [TROUBLESHOOTING, CONFIGURATION, and DESIGN DETAILS](#troubleshooting-configuration-and-design-details)\n- [About USB MIDI 1.0](#about-usb-midi-10)\n\n# ACKNOWLEDGEMENTS\nThe application driver code is based on code that rppicomidi submitted\nto TinyUSB as pull request #1219. The pull request was never merged and\ngot stale. TinyUSB pull request #1627 by atoktoto started with pull request\n#1219, but used simpler RP2040 bulk endpoint support from TinyUSB pull request\n#1434. Pull request #1627 was reviewed by todbot, AndrewCapon, PaulHamsh,\nand rppicomidi and was substantially functional. This driver copied\nthe `midi_host.c/h` files from pull request #1627 and renamed them\n`usb_midi_host.c/h`. It also fixed some minor issues in the driver\nAPI and added the application driver wrapper `usb_midi_host_app_driver.c`.\nThe driver C example code code is adapted from TinyUSB pull request #1219. \n\n# BUILDING APPLICATIONS WITH THIS DRIVER\nAlthough it is possible in the future for the TinyUSB stack to\nincorporate this driver into its builtin driver support, right now\nit is used as an application driver external to the stack. Installing\nthe driver to the TinyUSB stack requires adding it to the array\nof application drivers returned by the `usbh_app_driver_get_cb()`\nfunction.\n\n## Building C/C++ Applications\n\n### Basic Environment Setup\nBefore you attempt to build any C/C++ applications, be sure\nyou have the toolchain properly installed and the `pico-sdk`\ninstalled. Please make sure you can build and\nrun the blink example found in the [Getting Started Guide](https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf).\nVersion 2.0 or later of the `pico-sdk` offers the best support\nfor this project.\n\n### ${PICO_SDK_PATH}\nIf you are following Chapter 3 of the [Getting Started Guide](https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf),\nyou installed VS Code and the Official Raspberry Pi Pico VS Code extension.\nThe VS Code extension installed the `pico-sdk` in the\n`${HOME}/.pico-sdk/sdk/2.0.0` directory. If you followed the manual\ntoolchain installation per Appendix C of the [Getting Started Guide](https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf),\nthen you installed the `pico-sdk` in `${HOME}/pico`.\n\n### TinyUSB Library\nYou will also need to make sure that the the TinyUSB library is installed.\nIf there is nothing in the directory `${PICO_SDK_PATH}/lib/tinyusb`, or\nthe directory does not exist, please run the following commands\n```\ncd ${PICO_SDK_PATH}/pico-sdk\ngit submodule update --init\n```\n### TinyUSB for Pre-Version 2.0 `pico-sdk`\nYou will need a version of the TinyUSB library that supports\nUSB Host Application drivers. This feature was introduced to TinyUSB on\n15-Aug-2023 with commit 7537985c080e439f6f97a021ce49f5ef48979c78\nwhich is release 0.16.0 or later. Version 2.0 of the `pico-sdk` is\ncompatible with this. Older versions are not.\n\nIf you must use an older version of the of the `pico-sdk`, it ships\nconfigured to use TinyUSB 0.14 or earlier. You will need to update the\nTinyUSB library.  Please make sure you have a current TinyUSB code\nlibrary in your pico-sdk by using the following commands:\n\n```\ncd ${PICO_SDK_PATH}/lib/tinyusb\ngit fetch origin\ngit checkout 525406597627fb9307425539b86dddf10278eca8\n```\n\n### `Pico-PIO-USB` Library\nIf you are using the `Pico-PIO-USB` Library to implement the\nUSB Host hardware (see the [HARDWARE](#hardware) section, below),\nyou need to manually install the `Pico-PIO-USB` Library where\nTinyUSB can find it.\n\nTinyUSB provides python script that TinyUSB to install it, but the script\nin the version of TinyUSB that ships with `pico-sdk` version 2.0\nwill install a version of the library that won't build with\n`pico-sdk` version 2.0. Use these commands instead.\n\n```\ncd ${PICO_SDK_PATH}/lib/tinyusb/hw/mcu\nmkdir -p raspberry_pi/Pico-PIO-USB\ncd raspberry_pi/Pico-PIO-USB\ngit init\ngit remote add origin https://github.com/sekigon-gonnoc/Pico-PIO-USB.git\ngit fetch --depth 1 origin 7902e9fa8ed4a271d8d1d5e7e50516c2292b7bc2\ngit checkout FETCH_HEAD \n```\n\nIf you are using an older version of the `pico-sdk`, and you do not\nhave python installed, please run the above but replace the `git fetch` line with\n```\ngit fetch --depth 1 origin fe3b1e22436386f3b2be6c1c5f66658cbc32e1ba\n```\n\nIf you do have python installed and you are using an older pico-sdk,\nit is easier to run the Python script, see [Dependencies](https://docs.tinyusb.org/en/latest/reference/getting_started.html#dependencies).\n```\ncd ${PICO_SDK_PATH}/lib/tinyusb\npython3 tools/get_deps.py rp2040\n```\n\nHopefully, the `pico-sdk` will someday do all of this for you.\n\n### Building the `usb_midi_host` Library in Your Project\nThe `CMakeLists.txt` file contains two `INTERFACE` libraries.\nIf this driver is your only application USB host driver external\nto the TinyUSB stack, you should install this driver by\nadding the `usb_midi_host_app_driver` library to your main\napplication's `CMakeLists.txt` file's `target_link_libraries`.\nIf you want to add multiple host drivers, you must implement\nyour own `usbh_app_driver_get_cb()` function and you should\nadd the `usb_midi_host` library to your main application's\n`CMakeLists.txt` file's `target_link_libraries` instead.\nNote that the functon `usbh_app_driver_get_cb()` returns a\npointer to the first element of an array of `usbh_class_driver_t` objects.\nFor example, if you need the `usb_midi_host` app host driver plus one more, add\nthe second app driver to the array the function returns and set `*driver_count=2`.\n\nSee the files in `examples/C-code/usb_midi_host_example`\nor `examples/C-code/usb_midi_host_pio_example`\nfor examples.\n\n## Building Arduino Applications\nInclude this library, the Adafruit TinyUSB Arduino Library,\nand, if your host port hardware requires it, the Pico_PIO_USB\nLibrary using the Arduino IDE Library Manager. If this library\nis not available in the Arduino IDE Library Manager yet,\nplease copy this library code to a `usb_midi_host` directory\nunder your sketech folder `libraries` directory.\n\nTo build any Arduino application on the RP2040, you should\ninstall the Earle Philhower [arduino-pico](https://github.com/earlephilhower/arduino-pico) core for the Arduino IDE.\n\nYou need to set up the board under the Tools Menu.\nIf you are using the `Pico-PIO-USB` Library to implement your\nUSB Host hardware:\n```\nTools-\u003eCPU Speed-\u003e120 MHz (or 240 MHz (Overclock))\nTools-\u003eUSB Stack-\u003e\"Adafruit TinyUSB\"\nTools-\u003eDebug Port-\u003eSerial\nTools-\u003eOptimize: You can choose any option except Small (-Os) (Standard). I generally use Optimize Even More (-O3)\n```\n\nIf you are using the native RP2040 USB hardware to implement\nyour USB Host hardware, please configure the core as follows:\n```\nTools-\u003eCPU Speed-\u003e133 MHz (or faster, if you wish)\nTools-\u003eUSB Stack-\u003e\"Adafruit TinyUSB Host\"\nTools-\u003eDebug Port-\u003eSerial1\nTools-\u003eOptimize: (Choose anything)\n```\nNOTE: The USB Stack option \"Adafruit TinyUSB Host\" is not\navailable in the `arduino-pico` package 3.6.2 and earlier.\nYou must install version 3.6.3 or later to make this option\navailable.\n\n# HARDWARE\nThe example programs have been tested on a Raspberry Pi Pico board,\na Pico W board, and an Adafruit RP2040 Feather with USB A Host board.\nThe Pico boards, like most RP2040-based boards, do not ship with a\nUSB Host friendly connector, and the development environments\ngenerally assume you are using the USB connector in Device mode\nto provide power to the board, and to allow software update, to\nprovide a serial port interface for a serial console monitor, etc.\nYou will likely have to modify your board to add a USB Host interface\nconnector. The RP2040-based boards offer two approaches.\n\n## Software-based USB Host Port: `Pico-PIO-USB` Library\nThe `Pico-PIO-USB` library, which works for both C/C++ and Arduino,\nuses the RP2040 PIO 0 and CPU core 1 to to efficiently\nbit-bang a full-speed USB host port on 2 GPIO pins. Adafruit makes\na [RP2040 board](https://www.adafruit.com/product/5723) that uses\nthis method for USB Host.\n\nIf you are not using the Adafruit or similar board, you need to\nwire up something yourself. Wire a USB A jack to the GPIO and\npower pins on the Pico board as follows:\n```\nPico/Pico W board pin   USB A connector pin\n23 (or any GND pin)  -\u003e     GND\n21 (GP16)            -\u003e     D+  (via a 22 ohm resistor should improve things)\n22 (GP17)            -\u003e     D-  (via a 22 ohm resistor should improve things)\n24 (GP18)            -\u003e     TinyUSB drives this pin high to enable VBus on the Adafruit Feather board\n40 (VBus)            -\u003e     VBus (safer if it has current limiting on the pin)\n```\nI use a low-cost USB breakout board and solder the 22 ohm resistors to cut\ntraces on the D+ and D- lines. I leave GP18 unconnected.\n\nTODO Insert photos of my setup here.\n\nThe main advantages of this approach are:\n- Your board will have both a USB Device port and\na USB Host port, which, in an Arduino environment\nespecially, is convenient. For example, the Arduino\n`Serial` object will work with the Serial Monitor\nconsole, and firmware update via the Arduino IDE\nis supported. \n- If you need both a USB MIDI Host port\nand a USB MIDI Device port at the same time, you can\ndo it. See the [pico-usb-midi-filter](https://github.com/rppicomidi/pico-usb-midi-filter),\n[pico-usb-midi-processor](https://github.com/rppicomidi/pico-usb-midi-processor),\nand [midi2piousbhub](https://github.com/rppicomidi/midi2piousbhub) projects\nfor examples of this.\n- You can buy\n[off-the-shelf hardware](https://www.adafruit.com/product/5723)\nalready wired to support a Host port using this method.\n\nThe disadvantages of this approach are:\n- The RP2040 clock must run at a multiple of 120MHz. This\n  is a bit slower than the default of 133MHz.\n- It consumes 2 GPIO pins\n- It consumes the PIO 0 module\n- It consumes CPU 1\n- It takes a bit more code storage space and RAM space.\n- The Pico_PIO_USB library can conflict with the drivers for the\nPico W WiFi/Bluetooth module. To prevent the conflicts, please\ninitialze the TinyUSB library before the WiFi/Bluetooth module lbiraries.\n\n## RP2040 Native USB Hardware\nThe RP2040 USB core natively supports a host mode that is\ngood enough for MIDI. The minimum modification to a Pico\nboard is to connect a USB OTG adapter to the Micro USB\nB connector and add an external 5V power supply between\nthe VBus pin (pin 40 on the Pico board) and any ground pin\non the Pico board. As long as your 5V power supply is clean\nand protected against short circuit, it should be OK. It is\nhow I test native hardware USB Host.\n\nTODO Insert photo of my setup here.\n\nThe main advantages of this approach are\n- It does not consume 3 GPIO pins\n- It does not consume PIO 0\n- It does not restrict CPU operating speed\n- It does not consume CPU 1\n- It does not need the memory the Pico_PIO_USB library uses\n\nThe disadvantages of this approach are\n- Serial port console now has to use a UART; you have to\nprovide external hardware to interface that UART to your\ncomputer terminal software (e.g., a Picoprobe). In Arduino,\nyou have to use `Serial1` or `Serial2` UARTs for serial\nmonitor to work.\n- Software update either requires you to unplug the OTG\nconnector and connect the RP2040 in flash drive mode,\nor you have to use a Picoprobe or similar debug interface.\n- Depending on how you want to mount the development board, adapting\nthe board's native USB connector to USB A may be harder than just\nsoldering to a few GPIO pins.\n- There appears to be a [bug in the RP2040 USB controller\nhardware](https://github.com/rppicomidi/usb_midi_host/issues/14)\nthat prevents connection with the Arturia Beatstep Pro.\nOther MIDI hardware may have the same problem.\n\nNOTE: If you are using native USB hardware in USB Host mode\nfor an Arduino project, please look at the note in the\n[Building Arduino Applications](#building-arduino-applications)\nsection.\n\n# API\n\n## Connection Management\nThere are two connection management functions every application must implement:\n- `tuh_midi_mount_cb()`\n- `tuh_midi_unmount_cb()`\n\nEach device connected to the USB Host, either directly, or through\na hub, is identified by its device address, which is an 8-bit number.\nIn addition, during enumeration, the host discovers how many virtual\nMIDI IN cables and how many virtual MIDI OUT cables the device has.\nWhen someone plugs a MIDI device to the USB Host, this driver will\ncall the `tuh_midi_mount_cb()` function so the application can save\nthe device address and virtual cable information.\n\nWhen someone unplugs a MIDI device from the USB Host, this driver\nwill call the `tuh_midi_unmount_cb()` function so the application\ncan mark the previous device address as invalid.\n\n## MIDI Message Communication\nThere is one function that every application that supports MIDI IN\nmust implement\n- `tuh_midi_rx_cb()`\n\nWhen the USB Host receives MIDI IN packets from the MIDI device,\nthis driver calls `tuh_midi_rx_cb()` to notify the application\nthat MIDI data is available. The application should read that\nMIDI data as soon as possible.\n\nThere are two ways to handle USB MIDI messages:\n- As 4-byte raw USB MIDI 1.0 packets\n    - `tuh_midi_packet_read()`\n    - `tuh_midi_packet_write()`\n\n- As serial MIDI 1.0 byte streams\n    - `tuh_midi_stream_read()`\n    - `tuh_midi_stream_write()`\n\nBoth `tuh_midi_packet_write()` and `tuh_midi_stream_write()`\nonly write MIDI data to a queue. Once you are done writing\nall MIDI messages that you want to send in a single\nUSB Bulk transfer (usually 64 bytes but sometimes only\n8 bytes), you must call `tuh_midi_stream_flush()`. \n\nThe `examples` folder contains both C-Code and Arduino\ncode examples of how to use the API.\n\n## Sending long sysex messages or lots of short ones\nThe tuh_midi_stream_flush() function causes data to be sent out over\nthe USB host port. The RP2040 hardware has to send a complete endpoint\nbuffer to the attached device before more data can be sent. Due to the\nTinyUSB HCD driver implementation and limitations of the\nRP2040 chip, the Pico's USB host port is relatively slow. It can take a couple\nof milliseconds for tuh_midi_stream_flush() to complete because the system only\nscans through the pending transfers once per millisecond. If you are sending\na lot of data, keep in mind that Each MIDI packet is 4 bytes, so most devices\ncan handle 16 packets can in one buffer. If you have a long sysex message, take\nthe length of a sysex message in bytes, including the starting 0xF0 and 0xF7,\nmultiply by 4, divide by 3, and round up. That will tell you how many packets\nyou need to send the sysex message.\n\nYou can reduce latency by packing the Host's OUT endpoint buffer up to the device's\nOUT endpoint buffer size with data before flushing. Your best bet is to configure\nthe usb_midi_host driver to use larger buffers and call tuh_midi_stream_flush()\nonly once in your main loop. Yes, you will have latency, but it is fine to break\nup sysex messages across multiple USB packets. The application does not have to flush\nfor every write.\n\n## MIDI Device Strings API\nA USB MIDI device can attach a string descriptor to any or\nall virtual MIDI cables. This driver can retrieve the indices\nto the strings using these functions:\n```\ntuh_midi_get_rx_cable_istrings();\ntuh_midi_get_tx_cable_istrings();\ntuh_midi_get_all_istrings()\n```\n\nYou can then use the TinyUSB API for retrieving a device string\nby string index to get the UTF-16LE string.\n\nNOTE: For non-Arduino builds, to save space and to speed up\nenumeration, by default, `CFG_MIDI_HOST_DEVSTRINGS` is set to 0,\nso the MIDI Device String API is disabled by default. If you want\nto use the MIDI Device String API, please add, either before you\ninclude this library, or to your C/C++ application project `tusb_config.h`\n```\n#define CFG_MIDI_HOST_DEVSTRINGS 1\n```\nFor Arduino builds, because the Arduino IDE does not allow letting library\nfiles include files from the sketch directory, the default is to enable the\nMIDI Device String API. Disabling it requires adding\n```\n#define  CFG_MIDI_HOST_DEVSTRINGS 0\n```\nin the library file `usb_midi_host.h`.\n\n## Arduino MIDI Library API\nThis library API is designed to be relatively low level and is well\nsuited for applications that require the application to touch\nall MIDI messages (for example, bridging and filtering). If you want\nyour application to use the Arduino MIDI library API\nto access the devices attached to your USB MIDI host,\ninstall the [EZ_USB_MIDI_HOST](https://github.com/rppicomidi/EZ_USB_MIDI_HOST) wrapper library in addition\nto this library. See that repository for more information.\n\n# EXAMPLE PROGRAMS\n\n## Software\nEach example program does the same thing:\n- play a 5 note sequence on MIDI cable 0\n- print out every MIDI message it receives on cable 0.\n\nThe only difference among them is whether they are C/C++\nexamples or Arduino examples, and whether they use native\nrp2040 hardware (in directory with name `usb_midi_host_example`)\nor the Pico_PIO_USB software USB Host (in directory with name\n`usb_midi_host_pio_example`).\n\n## Building C-Code Examples\nFirst, set up your environment for command line `pico-sdk`\nprogram builds. If you are new to this, please see\nthe [Getting Started Guide](https://datasheets.raspberrypi.com/pico/getting-started-with-pico.pdf) and build the blink example\nbefore you try this.\n\nNext, install the libraries as described in the [Building C/C++\nApplications](#building-cc-applications) section.\n\n### Command Line Build\nTo build via command line (see Appendix C of the `Getting Started Guide`);\n\n```\ncd examples/C-code/[example program directory name]\nmkdir build\ncd build\ncmake ..\nmake\n```\nNote: if you are building the `usb_midi_host_pio_example` for\nthe Adafruit RP2040 Feather with USB\nType A Host board, you should replace `cmake ..` with\n```\n-DPICO_BOARD=adafruit_feather_rp2040_usb_host ..\n```\nIf you don't do this, then the board will work right after you\nprogram it, and will not work on reset or reboot. If you are\nusing any other board other than a Pico board, change\n`adafruit_feather_rp2040_usb_host` to the name of the\nfile for your board (without the `.h` extension)\nfound in `${PICO_SDK_PATH}/src/boards/include/boards`.\n\n### VS Code Build\nTo build using VS Code, for Version 2.0 of the `pico-sdk`, import the project to VS Code.\n1. Click the `Raspberry Pi Pico Project` icon in the left toolbar.\n2. Click `Import Project`\n3. Chenge the Location to point to the `examples/C-code/[example program directory name]` directory\n4. Make sure Pico-SDK version is 2.0.0.\n5. Choose the Debugger and any advanced options\n6. Click Import. If you are not using a Pico board and your Raspberry Pi\n   Pico Extenstion for VS Code is 0.15.2 or later, do this:\n    1. Click the Click the `Raspberry Pi Pico Project` icon in the left toolbar.\n    2. Under `Project` click `Switch Board`.\n    3. Find your board in the board list and click on the name.\n7. Click the CMake icon in the left toolbar. If you are not using a Pico board\n    and your Raspberry Pi Pico Extenstion for VS Code is 0.15.1 or earlier, do this:\n    1. On the `PROJECT STATUS` line of the CMAKE window, click the `Open CMake Tool Extenstions Settings` gear icon. You have to mouse over\n    the `PROJECT STATUS` line for the icon to appear.\n    2. In the new Settings tab that opened in the editor pane, click the `Workspace` tab.\n    3. Scroll down to the `CMake:Configure Args` item and click the `Add Item` button.\n    4. Enter `-DPICO_BOARD=[your board name goes here]` and click OK. The board name is the file name without\n       extension from `${PICO_SDK_PATH}/src/boards/include/boards`. For example, if you are using a\n       adafruit_feather_rp2040_usb_host board, you would enter `-DPICO_BOARD=adafruit_feather_rp2040_usb_host`\n8. On the `PROJECT STATUS` line of the CMAKE window,\n   select the `Delete Cache and Reconfigure` icon.\n   You have to mouse over the `PROJECT STATUS` line for the icon to appear.\n9. Under the `Configure` option, select the Pico Kit.\n10. Choose whether you want `Debug`, `Release` or `RelWithDebugInfo`. The `MinSizeRel` option can cause issues, so do not choose it.\n11. Click Build\n\nIf you are using an older version of the `pico-sdk`, then the project\nis already set up for VS Code. Just use the VS Code `File` menu to\nopen the project. Select the toolchain when prompted, and use the\nCMake icon on the left toolbar to build the code (see steps 7-11, above).\n\n## Testing C-Code Examples\nTo test, first prepare your development board as described\nin the [Hardware](#hardware) section of this document. Next,\ncopy the UF2 file to the Pico board using whatever\nmethod you prefer. Make sure the board powers up and displays the message\n```\nPico MIDI Host Example\n```\nbefore you attach your USB MIDI device.\n\nAttach your USB MIDI device to the USB A connector your\nhardware provides. You should see a message similar\nto\n```\nMIDI device address = 1, IN endpoint 2 has 1 cables, OUT endpoint 1 has 1 cables\n```\nIf your MIDI device can generate sound, you should start hearing a pattern\nof notes from B-flat to D. If your device is Mackie Control compatible, then\nthe transport LEDs should sequence. If you use a control on your MIDI device, you\nshould see the message traffic displayed on the serial console.\n\nNOTE: Unfortunately, the `pico-sdk` does not currently allow you to use the\nUSB device port for console I/O and the PIO USB host port at the same time.\nYou can install a [library](https://github.com/rppicomidi/cdc_stdio_lib)\nthat lets you do this for you own projects. In these examples,\nall printf() output goes to the UART 0 serial port. If you want an\nexample that uses this library and uses the native USB port for both\nMIDI device and console output, see the [midi2piousbhub](https://github.com/rppicomidi/midi2piousbhub) project.\n\n## Building and Testing Arduino Examples\nTo build and run the Arduino examples, in the Arduino IDE,\nuse the Library Manager to install this library and accept\nall of its dependencies. If your hardware requires it,\ninstall the Pico PIO USB library too. Next, in the IDE, select\nFile-\u003eExamples-\u003eusb_midi_host-\u003earduino-\u003e[your example program name]\n\nUse the Arduino IDE to build and run the code. Make sure to start a serial\nmonitor or else the code will appear to lock up.\n\nAttach a MIDI device to the USB A port.\nYou should see something like this in the Serial Port Monitor (of course,\nyour connected MIDI device will likely be different).\n```\nMIDI device address = 1, IN endpoint 1 has 1 cables, OUT endpoint 2 has 1 cables\nDevice attached, address = 1\n  iManufacturer       1     KORG INC.\n  iProduct            2     nanoKONTROL2\n  iSerialNumber       0\n\n```\nIf your MIDI device can generate sound, you should start hearing a pattern\nof notes from B-flat to D. If your device is Mackie Control compatible, then\nthe transport LEDs should sequence. If you use a control on your MIDI device, you\nshould see the message traffic displayed on the Serial Port Monitor.\n\n# TROUBLESHOOTING, CONFIGURATION, and DESIGN DETAILS\nIn addition to this section, you might find\n[this guide](https://github.com/rppicomidi/pico_usb_host_troubleshooting)\nhelpful.\n\n## Config (Configuration) File\nIn C/C++, the config file for your project is called `tusb_config.h`.\nIt should be in the include path of your project.\n\nIn Arduino code,the config file is stored in the `libraries` directory of\nyour sketch directory as the file\n`Adafruit_TinyUSB/src/arduino/ports/${target}/tusb_config_${target}.h`,\nwhere `${target}` is the processor name of the processor on the target\nhardware. For example, for a Rapsberry Pi Pico board, the file is\n`libraries/Adafruit_TinyUSB/src/arduino/ports/rp2040/tusb_config_rp2040.h`.\nSadly, any changes you make to the config file will disappear if you update\n`Adafruit_TinyUSB_Library`.\n\nTo make configuring parameters specific to the USB MIDI Host a bit simpler\nfor Arduino IDE users, see the function `tuh_midih_define_limits()`.\n\n## Size of the Enumeration Buffer\nWhen the USB Host driver tries to enumerate a device, it reads the\nUSB descriptors into a byte buffer. By default, that buffer is 256 bytes\nlong. Complete MIDI devices, or device that also have audio interfaces,\ntend to have much longer USB descriptors. If a device fails to enumerate,\nlocate the line in your config file that contains `#define CFG_TUH_ENUMERATION_BUFSIZE` and change the default 256 to something larger\n(for example, 512).\n## Debug Log\nIf a device fails to enumerate, a debug log printout may be helpful.\nDebug log levels go from 0 (no debug logging) to 3 (very verbose). The\ndefault log level is 0. The most direct way to set the debug level is to\ndefine `CFG_TUSB_DEBUG` in your config file. For example, to set the log\nlevel to 2, make sure your config file contains the lines\n```\n#ifndef CFG_TUSB_DEBUG\n#define CFG_TUSB_DEBUG 2\n#endif\n```\nThe conditional is in case you choose to change the debug level by\nsetting an environment variable.\n\n### Bug #384 in RP2040/Raspberry Pi Pico and Adafruit_TinyUSB_Library 3.0\nFor Arduino, the `Adafruit TinyUSB Host` option seems to require you to define\nthe function `log_printf` if you use a debug log level other than 0. Adding\nthe following function to your program sketch should suffice as long as none\nof the debug log output lines is longer than 256 bytes.\n```\n// Debugging\nint log_printf(const char * format, ...)\n{\n  char outstr[256];\n  va_list va;\n  va_start(va, format);\n  int ret = vsprintf(outstr, format, va);\n  // Uncomment the next line to send the debug log to the Serial1 output\n  return Serial1.print(outstr);\n}\n```\n\n## Maximum Number of MIDI Devices Attached to the Host\nYou should define the value `CFG_TUH_DEVICE_MAX` in the tuh_config.h file to\nmatch the number of USB hub ports attached to the USB host port. For\nexample\n```\n// max device support (excluding hub device)\n#define CFG_TUH_DEVICE_MAX          (CFG_TUH_HUB ? 4 : 1) // hub typically has 4 ports\n```\nThe Arduino IDE makes configuring this is difficult because tuh_config.h is part\nof the processor core (for RP2040, anyway)\n\n## Maximum Number of USB Endpoints\nAlthough the USB MIDI 1.0 Class specification allows an arbitrary number\nof endpoints, this driver supports at most one USB BULK DATA IN endpoint\nand one USB BULK DATA OUT endpoint. Each endpoint can support up to 16 \nvirtual cables. If a device has multiple IN endpoints or multiple OUT\nendpoints, it will fail to enumerate.\n\nMost USB MIDI devices contain both an IN endpoint and an OUT endpoint,\nbut not all do. For example, some USB pedals only support an IN endpoint.\nThis driver allows that.\n\n## Maximum Number of Virtual Cables\nA USB MIDI 1.0 Class message can support up to 16 virtual cables. The function\n`tuh_midi_stream_write()` uses 6 bytes of data stored in an array in\nan internal data structure to deserialize a MIDI byte stream to a\nparticular virtual cable. To properly handle all 16 possible virtual cables,\n`CFG_TUH_DEVICE_MAX*16*6` data bytes are required. If the application\nneeds to save memory, in file `tusb_cfg.h` set `CFG_TUH_CABLE_MAX` to\nsomething less than 16 as long as it is at least 1.\n\nFor Arduino builds, you can configure this parameter at runtime by calling\ntuh_midih_define_limits().\n\n## Subclass of Audio Control\nA MIDI device is supposed to have an Audio Control Interface and it may\nhave an Audio Streaming Interface before the the MIDI Streaming Interface,\nthat this driver supports. Many commercial devices do not have even the\nAudio Control Interface. To support these devices, the descriptor parser\nin this driver will skip past Audio Control Interface and Audio Streaming\nInterface descriptors and open only the MIDI Interface.\n\nAn audio streaming host driver can use this driver by passing a pointer\nto the MIDI interface descriptor that is found after the audio streaming\ninterface to the midih_open() function. That is, an audio streaming host\ndriver would parse the audio control interface descriptor and then the\naudio streaming interface and endpoint descriptors. When the next descriptor\npointer points to a MIDI interface descriptor, call midih_open() with that\ndescriptor pointer.\n\n## Class Specific Interface and Requests\nThe host driver only makes use of the informaton in the class specific\ninterface descriptors to extract string descriptors from each IN JACK and\nOUT JACK. To use these, you must set `CFG_MIDI_HOST_DEVSTRINGS` to 1 in\nyour application's tusb_config.h file. It does not parse ELEMENT items\nfor string descriptors.\n\nThis driver does not support class specific requests to control\nELEMENT items, nor does it support non-MIDI Streaming bulk endpoints.\n\n## MIDI Class Specific Descriptor Total Length Field Ignored\nI have observed at least one keyboard by a leading manufacturer that\nsets the wTotalLength field of the Class-Specific MS Interface Header\nDescriptor to include the length of the MIDIStreaming Endpoint\nDescriptors. This is wrong per my reading of the specification.\n\n## Message Buffer Details\nMessages buffers composed from USB data received on the IN endpoint will never\ncontain running status because USB MIDI 1.0 class does not support that. Messages\nbuffers to be sent to the device on the OUT endpont can contain running status\n(the message might come from a UART data stream from a 5-pin DIN MIDI IN\ncable on the host, for example), and thanks to pull request#3 from @moseltronics,\nthis driver should correctly parse or\ncompose 4-byte USB MIDI Class packets from streams encoded with running status.\n\nMessage buffers to be sent to the device may contain real time messages\nsuch as MIDI clock. Real time messages may be inserted in the message \nbyte stream between status and data bytes of another message without disrupting\nthe running status. However, because MIDI 1.0 class messages are sent \nas four byte packets, a real-time message so inserted will be re-ordered\nto be sent to the device in a new 4-byte packet immediately before the\ninterrupted data stream.\n\nReal time messages the device sends to the host can only appear between\nthe status byte and data bytes of the message in System Exclusive messages\nthat are longer than 3 bytes.\n\n## Poorly Formed USB MIDI Data Packets from the Device\nSome devices do not properly encode the code index number (CIN) for the\nMIDI message status byte even though the 3-byte data payload correctly encodes\nthe MIDI message. This driver looks to the byte after the CIN byte to decide\nhow many bytes to place in the message buffer.\n\nSome devices do not properly encode the virtual cable number. If the virtual\ncable number in the CIN data byte of the packet is not less than bNumEmbMIDIJack\nfor that endpoint, then the host driver assumes virtual cable 0 and does not\nreport an error.\n\nSome MIDI devices will always send back exactly wMaxPacketSize bytes on\nevery endpoint even if only one 4-byte packet is required (e.g., NOTE ON).\nThese devices send packets with 4 packet bytes 0. This driver ignores all\nzero packets without reporting an error.\n\n## Enumeration Failures\nThe host may fail to enumerate a device if it has too many endpoints, if it has\nif it has a Standard MS Transfer Bulk Data Endpoint Descriptor (not supported),\nif it has a poorly formed descriptor, or if the configuration\ndescriptor is too long for the host to read the whole thing.\nThe most common failure, though, is the descriptor is too long. See\n[Size of the Enumeration Buffer](#size-of-the-enumeration-buffer) for\nhow to address that.\n\n# About USB MIDI 1.0\nThe original MIDI specification was designed to carry a MIDI data stream\nover a UART-based serial port at 31.25 kbps. USB MIDI 1.0 is a transport for\ncarrying the same MIDI messages between a USB Host and a USB Device. Unlike\nthe byte-serial transport of a UART serial port, USB sends data in packets,\nwhich are groups of bytes. Understanding how this driver encodes a MIDI\ndata stream into USB packets will help you properly size data buffers\nand should help you to understand the sizes returned from the driver's\nMIDI stream read and write functions.\n\nYou can download the [USB Device Class Specification for MIDI Devices 1.0](https://www.usb.org/sites/default/files/midi10.pdf)\nfor free for all of the details. If you are a user of this driver, it will\nprobably help you to review the specification, especially section 4.\nKey concepts:\n\n- MIDI data flows between a USB MIDI Host and a USB MIDI Device using Bulk\nendpoints. The path from Host to Device uses Bulk Out endpoints, and the\npath from Device to Host uses Bulk In endponts.\n- On a RP2040 or RP2350, USB MIDI is Full-speed (12Mbps).\n- Full Speed Bulk endpoints are have a maximum payload of 64 bytes but can\nbe as small as 8 bytes. Some USB MIDI devices are designed for MIDI 2.0 high\nspeed and can support bulk transfers up to 512 bytes per packet,\nbut if you connect such a device to this USB 2.0 Full Speed host, then\ndata transfers will still be limited to 64 bytes.\n- The serial MIDI byte data stream is encoded into 4-byte packets that move\non a Bulk endpoint data transfer.\n    - The first byte in the packet is divided into two 4-bit values.\n        - The most significant 4 bits encode a virtual cable number (CN) 0-15.\n        When you plug a USB MIDI device to a computer and it shows multiple\n        \"MIDI Ports\" for a single device, each \"MIDI Port\" is a virtual cable.\n        - The least significant 4 bits contain a Code Index Number (CIN) 0-15.\n        The CIN encodes how many of the remaining 3 bytes of the MIDI packet\n        contain a whole MIDI message or just a part of a system exclusive message.\n        For channel messages, the CIN is the same number as the most significant\n        4 bits of the status byte.\n    - The remaining 3 bytes in a packet can contain a 1-byte, 2-byte or\n    3-byte MIDI message, or they can contain data bytes of an ongoing\n    system exclusive message.\n- Since devices support between 8 and 64 bytes per bulk endpoint transfer, \nUSB MIDI devices can handle between 2 and 16 MIDI messages (or sections of\na system exclusive message) in one Bulk transfer packet.\n\nThe host learns the maximum number of bytes per Bulk endpoint transfer,\nthe number of virtual cables, the product name string, the string labels\nfor each virtual cable, etc. by reading the USB MIDI device's Device\nDescriptor, Configuration Descriptor, and String descriptors during enumeration. The host\nenumerates each device after the device is attached directly or via a hub.\nDescriptors are just data structures that describe device capabilities in\na standard way. For more details, see the USB MIDI Device spec cited\nabove and chapter 9 of [The USB Specification version 2.0](https://www.usb.org/document-library/usb-20-specification).\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frppicomidi%2Fusb_midi_host","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frppicomidi%2Fusb_midi_host","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frppicomidi%2Fusb_midi_host/lists"}