[{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch2\u003eOverview\u003c/h2\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"user_image","content":"https://cdn-learn.adafruit.com/user_assets/assets/000/001/922/original/midi-test-screenshot.png?1752736572","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003cp\u003eThis is a CircuitPython-in-the-middle MIDI filter and visualizer project for Fruit Jam. When you plug a USB MIDI controller into the Fruit Jam, MIDI input events will be shown on the DVI visualizer display and echoed on the usb_midi output port to the Fruit Jam's host computer. You could use this as the starting point for a USB MIDI\u0026nbsp;filtering project.\u003c/p\u003e\n\u003cp\u003eThe note visualizer has a grid of channels and notes to cover the range of a full size piano (midi notes 21 to 108). Dots indicate a note that hasn't played yet. Note-On messages turn the dot into a white rectangle. Note-Off messages turn the rectangle black. It works like a 1-bit heat map showing which notes and channels are active. Pitch bend, CC, aftertouch, etc. get shown as text in the bottom left of the visualizer and echoed to the serial console. USB host port connection status gets shown in the bottom right of the visualizer.\u003c/p\u003e\n\u003cp\u003e\u003cspan\u003eThis code was developed and tested on CircuitPython 10.0.0-beta.0 with a pre-release revision B Fruit Jam prototype. Keep in mind that things may change by the time CircuitPython 10.0.0 is released.\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan\u003eRelated guide: \u003ca title=\"Fruit Jam Gamepad Tester\" href=\"https://adafruit-playground.com/u/SamBlenny/pages/fruit-jam-gamepad-tester\" target=\"_blank\"\u003eFruit Jam Gamepad Tester\u003c/a\u003e\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan\u003eTransparency note: Adafruit provided the Fruit Jam rev B prototype board I used for this guide (Thanks Adafruit!).\u003c/span\u003e\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n        \u003ch3\u003eDemo Video\u003c/h3\u003e\n\u003cp\u003e\u003cspan\u003eThis video shows my code running with a BeatStep Pro plugged into the Fruit Jam and the Fruit Jam plugged into a Mac. The Mac is running VCV Rack 2 with a simple drum and lead patch. To avoid possible power or ground loop troubles, I used the BeatStep Pro's bundled ground loop fixer dongle along with a separate 2.5A USB power supply. A powered USB hub would also work.\u003c/span\u003e\u003c/p\u003e\n      ","metadata":{}},{"element_type":"embed","content":"https://www.youtube.com/watch?v=O1BcIFmea3w"},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch2\u003eParts\u003c/h2\u003e\n\u003cp\u003e\u003cspan\u003eI used a pre-release revision B Fruit Jam prototype board. A Metro RP2350 might also work, but I haven't tested that. To use a Metro RP2350, you would need to add an HSTX to DVI adapter, solder USB host header pins, wire up a USB hub breakout, and so on. For more information on setting up a Metro RP2350 as a pseudo-Fruit Jam, you can check out some of the recent guides by \u003ca href=\"https://learn.adafruit.com/match3-game-on-metro-rp2350\" target=\"_blank\"\u003eTim C.\u003c/a\u003e\u0026nbsp;and\u0026nbsp;\u003ca href=\"https://learn.adafruit.com/minesweeper-on-metro-rp2350\" target=\"_blank\"\u003eM. LeBlanc-Williams\u003c/a\u003e.\u003c/span\u003e\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/6200","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003cp\u003eYou will also need a MIDI controller with USB MIDI output. I tested this code with an Arturia \u003ca href=\"https://www.arturia.com/products/hybrid-synths/beatstep-pro/overview\" target=\"_blank\"\u003eBeatStep Pro\u003c/a\u003e and an Arturia \u003ca href=\"https://www.arturia.com/products/hybrid-synths/keystep/overview\" target=\"_blank\"\u003eKeystep\u003c/a\u003e. Many other types of MIDI controllers will probably also work because the code detects USB MIDI devices by USB device class rather than relying on vendor and product ID.\u003c/p\u003e\n\u003cp\u003eDepending on the current required by your MIDI controller, a powered USB hub may be helpful. Keep in mind that many cheap USB hubs are not suitable for streaming audio devices. For best results, you want a hub with a chipset that supports \"Multi-TT\". Ideally, the hub should also be built to avoid backfeeding power to its upstream host port, but it's usually kind of difficult to determine that from product marketing descriptions. I've been using a Tripp Lite \u003ca href=\"https://tripplite.eaton.com/rugged-industrial-usb-2-0-high-speed-hub-15kv-esd-immunity-metal-case-mountable-4-port~U223004IND\" target=\"_blank\"\u003eU223-004-IND\u003c/a\u003e industrial USB 2.0 hub and 5VDC power adapter which work well.\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch2\u003eUpdating CircuitPython\u003c/h2\u003e\n\u003cp\u003eAs I write this (July 17, 2025), CircuitPython 10.0.0-beta.0 is the most recent build for Fruit Jam. I'm not sure what will change by the time 10.0.0 is released. To keep your board up to date, you can use the \"DOWNLOAD .UF2 NOW\" buttons on the appropriate download page of circuitpython.org:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\n\u003ca href=\"https://circuitpython.org/board/adafruit_metro_rp2350/\" target=\"_blank\"\u003eMetro RP2350 Download\u003c/a\u003e\u003cspan\u003e\u0026nbsp;\u003c/span\u003epage\u003c/li\u003e\n\u003cli\u003e\n\u003ca href=\"https://circuitpython.org/board/adafruit_fruit_jam/\" target=\"_blank\"\u003eFruit Jam Download\u003c/a\u003e\u003cspan\u003e\u0026nbsp;\u003c/span\u003epage\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003eTo install the UF2 File:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eConnect your board to a computer with a USB data cable (\u003cem\u003echarge-only cables won't work!\u003cspan\u003e\u0026nbsp;\u003c/span\u003e\u003c/em\u003e)\u003c/li\u003e\n\u003cli\u003ePress and hold the board's boot button (Button 1 on Fruit Jam)\u003c/li\u003e\n\u003cli\u003ePress and release the reset button\u003c/li\u003e\n\u003cli\u003eRelease the boot button\u003c/li\u003e\n\u003cli\u003eWhen the removable drive named\u003cspan\u003e\u0026nbsp;\u003c/span\u003e\u003cstrong\u003eRP2350\u003c/strong\u003e\u003cspan\u003e\u0026nbsp;\u003c/span\u003eappears, copy the UF2 file onto it. After the copy finishes, you should see the\u003cspan\u003e\u0026nbsp;\u003c/span\u003e\u003cstrong\u003eRP2350\u003c/strong\u003e\u003cspan\u003e\u0026nbsp;\u003c/span\u003edrive disappear and soon after that a new\u003cspan\u003e\u0026nbsp;\u003c/span\u003e\u003cstrong\u003eCIRCUITPY\u003c/strong\u003e\u003cspan\u003e\u0026nbsp;\u003c/span\u003edrive should appear.\u003c/li\u003e\n\u003c/ol\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch2\u003eCircuitPython Code\u003c/h2\u003e\n\u003cp\u003eYou can view the code at the\u003cspan\u003e\u0026nbsp;\u003ca href=\"https://github.com/samblenny/fruit-jam-usb-midi-tester\" target=\"_blank\"\u003esamblenny/fruit-jam-usb-midi-tester\u003c/a\u003e\u0026nbsp;\u003c/span\u003eGitHub repository. To download a zip archive project bundle with the code and all the necessary libraries, use the \"Download Project Bundle\" button:\u003c/p\u003e\n      \n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"button","content":"https://github.com/samblenny/fruit-jam-usb-midi-tester/releases/download/v0.2.1/fruit-jam-usb-midi-tester-0b8994f.zip","metadata":{"class":"btn btn-large btn-block btn-primary","button_type":"primary","target":"_blank","zip_folder":"false"}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch3\u003eInstall Project Bundle\u003c/h3\u003e\n\u003cp class=\"p2\"\u003e\u003cspan class=\"s1\"\u003eTo copy the project bundle files to your CIRCUITPY drive:\u003c/span\u003e\u003c/p\u003e\n\u003col class=\"ol1\"\u003e\n\u003cli class=\"li3\"\u003e\u003cspan class=\"s1\"\u003eDownload the project bundle .zip file using the \"Download Project Bundle\" button above.\u003c/span\u003e\u003c/li\u003e\n\u003cli class=\"li3\"\u003e\u003cspan class=\"s1\"\u003eExpand the zip file by opening it, or use unzip in a Terminal. The zip archive should expand to a folder. When you open the folder, it should contain a README.txt file and a CircuitPython 10.x folder.\u003c/span\u003e\u003c/li\u003e\n\u003cli class=\"li3\"\u003e\u003cspan class=\"s1\"\u003eOpen the CircuitPython 10.x folder and copy all of its contents to your CIRCUITPY drive.\u003c/span\u003e\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp class=\"p2\"\u003e\u003cspan class=\"s1\"\u003eTo learn more about copying libraries to your\u003cspan\u003e\u0026nbsp;\u003c/span\u003e\u003cstrong\u003eCIRCUITPY\u003c/strong\u003e\u003cspan\u003e\u0026nbsp;\u003c/span\u003edrive, check out the\u0026nbsp;\u003ca href=\"https://learn.adafruit.com/welcome-to-circuitpython/circuitpython-libraries\" target=\"_blank\"\u003e\u003cspan class=\"s2\"\u003eCircuitPython Libraries\u003c/span\u003e\u003c/a\u003e\u0026nbsp;section of the\u0026nbsp;\u003ca href=\"https://learn.adafruit.com/welcome-to-circuitpython\" target=\"_blank\"\u003e\u003cspan class=\"s2\"\u003eWelcome to CircuitPython!\u003c/span\u003e\u003c/a\u003e\u0026nbsp;learn guide.\u003c/span\u003e\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch3\u003eUsage\u003c/h3\u003e\n\u003col\u003e\n\u003cli\u003eInstall the project bundle files onto your Fruit Jam board or a suitably prepared Metro RP2350. (This will leave your Fruit Jam connected to a computer by USB)\u003c/li\u003e\n\u003cli\u003eConnect an HDMI display or capture card to the Fruit Jam's DVI port.\u003c/li\u003e\n\u003cli\u003e[Optional] Connect to the Fruit Jam's USB serial console with a serial monitor program such as \u003ccode\u003etio\u003c/code\u003e, \u003ccode\u003escreen\u003c/code\u003e, or whatever you normally use for CircuitPython coding.\u003c/li\u003e\n\u003cli\u003eAt this point, you should see a \"USB Host scanning bus...\" message in the lower right pane of the visualizer screen on the DVI display. Connect your USB MIDI controller to one of the Fruit Jam's host ports (use powered hub if needed). After a few seconds, you should see a message like \"USB Host MIDI Device vid:pid ...\" in the visualizer. If not, check the serial console for debug messages.\u003c/li\u003e\n\u003cli\u003eUse the controller to send MIDI to the Fruit Jam. You should see the visualizer's note grid update for note on and note off messages. Other message types will be displayed in the bottom left pane of the visualizer (CC for Control Change, PB for Pitch Bend, PP for Polyphonic key Pressure, CP for Channel key Pressure, etc.). The first number after the message type is the channel (e.g. \"CC 1 ...\" for channel 1). The remaining numbers are whatever comes next in the standard MIDI message of that type (note or control number, velocity or value, etc). The MIDI messages will also be echoed to the Fruit Jam's usb_device interface (output to the host computer powering the Fruit Jam).\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eThis code uses the Fruit Jam's USB device MIDI output port to act as a MIDI thru (technically there's also some filtering) for input events received from the controller on the USB host port. So, if you start a software synthesizer on your host computer, it should see MIDI events coming through from the Fruit Jam.\u003c/p\u003e\n\u003cp\u003eNOTE: To maintain reasonably acceptable latency, this code filters out all System Real-Time messages and some aftertouch messages. Check the code for details.\u003c/p\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch3\u003eCIRCUITPY/code.py\u003c/h3\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"embed","content":"https://github.com/samblenny/fruit-jam-usb-midi-tester/blob/v0.2.1/code.py"},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch3\u003eCIRCUITPY/\u003cspan\u003esb_usb_midi.py\u003c/span\u003e\n\u003c/h3\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"embed","content":"https://github.com/samblenny/fruit-jam-usb-midi-tester/blob/v0.2.1/sb_usb_midi.py"},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch3\u003eCIRCUITPY/\u003cspan\u003esb_usb_descriptor.py\u003c/span\u003e\n\u003c/h3\u003e\n      \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","metadata":{}},{"element_type":"embed","content":"https://github.com/samblenny/fruit-jam-usb-midi-tester/blob/v0.2.1/sb_usb_descriptor.py"}]