[{"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  \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\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/940/original/fruit-jam-portable-midi-synth.jpeg?1753557359","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003cp\u003e[\u003cstrong\u003eUpdate 2025-10-13: revised for CircuitPython 10.0.1, including a fix for the stuck notes issue\u003c/strong\u003e]\u003c/p\u003e\n\u003cp\u003eThis is a minimalist polyphonic square wave synth for Fruit Jam that's intended for portable use with a USB power bank. The only output is audio to the board's headphone jack. The only input is from a USB MIDI controller connected to the board's USB host port. To set the volume, you can edit the code.\u003c/p\u003e\n\u003cp\u003eThe main interesting thing about this project is that it demonstrates how to make a CircuitPython synth with MIDI events coming from the USB host interface rather than a USB device interface or UART MIDI. Also, this works as a good stress test of the CircuitPython USB host stack in combination with audio output using I2S and synthio.\u003c/p\u003e\n\u003cp\u003eThis code was developed and tested on CircuitPython 10.0.0-beta.0 with a pre-release rev B Fruit Jam prototype which uses a different I2S pinout from the current rev D boards. Keep in mind that what's written here may be out of date by the time CircuitPython 10.0.0 is released and the production revision of the Fruit Jam board becomes available in the shop.\u003c/p\u003e\n\u003cp\u003e\u003cspan\u003eRelated guides: \u003ca href=\"https://adafruit-playground.com/u/SamBlenny/pages/fruit-jam-usb-host-midi-tester\" target=\"_blank\"\u003eFruit Jam USB Host MIDI Tester\u003c/a\u003e,\u0026nbsp;\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","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        \u003ch3\u003eVideo Demo\u003c/h3\u003e\n\u003cp\u003eThis video shows the original version of the code running an a pre-production rev B Fruit Jam prototype board. The old version has some problems that have since been fixed, but I didn't make a new video.\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","metadata":{}},{"element_type":"embed","content":"https://www.youtube.com/watch?v=7PB7a25HEcs"},{"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\u003eKnown Issues\u003c/h3\u003e\n\u003cp\u003eEarly versions of this project had problems with stuck or dropped notes along with missing audio on the right channel, but that's all been fixed.\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","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        \u003ch2\u003eProject Ideas\u003c/h2\u003e\n\u003cp\u003eThis project is pretty basic, but it provides the foundation of a \u003ccode\u003esynthio\u003c/code\u003e synthesizer with USB host MIDI controller input. Some ideas for improvements you could make include:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eAdd volume control using two of the Fruit Jam board's built in buttons\u003c/li\u003e\n\u003cli\u003eAdd volume control using an I2C rotary encoder knob\u003c/li\u003e\n\u003cli\u003eAdd an \"All stop\" (panic) function to stop stuck notes by pressing a Fruit Jam built in button or rotary encoder knob\u003c/li\u003e\n\u003cli\u003eUse \u003ccode\u003esynthio.Note\u003c/code\u003e to implement fancier synth patches (see todbot's \u003ca href=\"https://github.com/todbot/circuitpython-synthio-tricks\" target=\"_blank\"\u003ecircuitpython-synthio-tricks\u003c/a\u003e page)\u003c/li\u003e\n\u003c/ul\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","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        \u003ch2\u003eParts\u003c/h2\u003e\n\u003cp\u003e\u003cspan\u003eI originally developed this on a pre-release revision B Fruit Jam prototype board, but the current code release is meant for the Fruit Jam rev D board that's now available in the Adafruit shop.\u003c/span\u003e\u003c/p\u003e\n\u003cp\u003e\u003cspan\u003eYou will also need a MIDI controller, headphones or speakers, USB cables, and perhaps a USB power bank.\u003c/span\u003e\u003c/p\u003e\n\u003ch3\u003e\u003cspan\u003eFrom the Adafruit Shop\u003c/span\u003e\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":"product","content":"https://www.adafruit.com/product/6200","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/1966","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/1363","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/4288","metadata":{}},{"element_type":"product","content":"https://www.adafruit.com/product/6278","metadata":{}},{"element_type":"text","content":"\n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n        \u003ch3\u003eMIDI Controllers\u003c/h3\u003e\n\u003cp\u003eFor a portable battery powered setup, you'll want a MIDI controller that is relatively small and that doesn't draw too much current. For discussion of the pros and cons of various controllers, you can check forums like reddit or modwiggler.\u003c/p\u003e\n\u003cp\u003eBased on my reading of forums, reviews, and manufacturer websites, I made the list below with some controllers that might be suitable. I've only tried a couple of these, but I've seen people online say that they like them (others disagree). Keep in mind that 25 key keyboards have some inherent limitations, caveat emptor, etc. Anyhow, in alphabetical order...\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eArturia MicroLab mk3\u003c/li\u003e\n\u003cli\u003eKorg MicroKEY-25\u003c/li\u003e\n\u003cli\u003eKorg NanoKEY2\u003c/li\u003e\n\u003cli\u003eKorg NanoKEY Fold\u003c/li\u003e\n\u003cli\u003eKorg NanoPAD2\u003c/li\u003e\n\u003cli\u003eMuse Kinetics (Keith McMillen) K-Board C\u003c/li\u003e\n\u003c/ul\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  \n  \n        \u003ch3\u003eSpeakers or Headphones\u003c/h3\u003e\n\u003cp\u003eYou will need some kind of speakers or headphones that can connect to a 3.5mm headphone jack. Currently, the code defaults to a line level volume that works with a mixer or powered headphones. To adjust the volume for headphones, you can edit the code.\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003eI've mostly been testing with a line-level signal out of the Fruit Jam into a small desktop mixer to drive a pair of cheap JVC Gumy earbuds.\u003c/li\u003e\n\u003cli\u003eIt also works to plug the earbuds directly into the board if you edit the code to lower the volume.\u003c/li\u003e\n\u003cli\u003eYou could use a Bluetooth speaker with 3.5mm aux input jack. But, watch out for speakers with silly DSP features that add lots of latency (some speakers have high latency even on the aux jack, so check reviews).\u003c/li\u003e\n\u003cli\u003eYou could use small computer speakers that have a 3.5mm audio plug and a USB plug for power. For this to work, you might want a USB power bank with two charging output ports (one for speakers, one for Fruit Jam).\u003c/li\u003e\n\u003c/ul\u003e\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  \n  \n        \u003ch2\u003eUpdating CircuitPython\u003c/h2\u003e\n\u003cp\u003eOriginally (July 26, 2025), this was written for CircuitPython 10.0.0-beta.0 and a rev B prototype Fruit Jam board. The current code (October 13, 2025) is meant for CircuitPython 10.0.1 and the production rev D Fruit Jam board that's available in the Adafruit Shop. To get the current version of CircuitPython, you can use the \"DOWNLOAD .UF2 NOW\" button on Fruit Jam Download page of circuitpython.org:\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://circuitpython.org/board/adafruit_fruit_jam/\" target=\"_blank\"\u003eFruit Jam Download\u003c/a\u003e\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\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  \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\u003eInstall Project Bundle\u003c/h2\u003e\n\u003cp\u003eYou can view the code at the\u003cspan\u003e \u003ca href=\"https://github.com/samblenny/fruit-jam-portable-midi-synth\" target=\"_blank\"\u003esamblenny/fruit-jam-portable-midi-synth\u003c/a\u003e \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\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":"button","content":"https://github.com/samblenny/fruit-jam-portable-midi-synth/releases/download/v0.3.0/fruit-jam-portable-midi-synth-8024978.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  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \n  \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\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        \u003ch2\u003eUsage\u003c/h2\u003e\n      \n\n\n\n\n\n","metadata":{}},{"element_type":"alert","content":"\u003cp\u003eThe default volume is set for line level output to use with speakers or a mixer. This will be WAY TOO LOUD for headphones. If you want to use headphones, edit the code to reduce the volume.\u003c/p\u003e","metadata":{"class":"element alert-element build-alert alert-warning","markdown":"The default volume is set for line level output to use with speakers or a mixer. This will be WAY TOO LOUD for headphones. If you want to use headphones, edit the code to reduce the volume.","alert_type":"warning"}},{"element_type":"text","content":"\n        \u003cp\u003eOnce you've installed the code onto your CIRCUITPY drive, you may want to edit the code to adjust the volume.\u003c/p\u003e\n\u003cp\u003eConfiguration Notes:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003e\n\u003cp\u003eThe default DAC volume is set for line level output to use with a mixer or powered speakers.\u003cspan\u003e \u003c/span\u003eIf you want to use headphones, edit\u003cspan\u003e\u0026nbsp;\u003c/span\u003e\u003ca href=\"https://github.com/samblenny/fruit-jam-portable-midi-synth/blob/main/code.py\" target=\"_blank\"\u003ecode.py\u003c/a\u003e\u003cspan\u003e\u0026nbsp;\u003c/span\u003eto set\u003cspan\u003e\u0026nbsp;\u003c/span\u003e\u003ccode\u003eLINE_LEVEL = False\u003c/code\u003e to use the default headphone volume set by CircuitPython's TLV320 DAC driver library. To personalize the volume setting for your headphones, you might also want to add code to adjust\u003cspan\u003e\u0026nbsp;\u003c/span\u003e\u003ccode\u003edac.dac_volume\u003c/code\u003e\u003cspan\u003e\u0026nbsp;\u003c/span\u003eor\u003cspan\u003e\u0026nbsp;\u003c/span\u003e\u003ccode\u003edac.headphone_volume\u003c/code\u003e.\u003c/p\u003e\n\u003c/li\u003e\n\u003cli\u003e\n\u003cp\u003eThe default\u003cspan\u003e\u0026nbsp;\u003c/span\u003e\u003ccode\u003edac.dac_volume\u003c/code\u003e\u003cspan\u003e\u0026nbsp;\u003c/span\u003elevel is somewhat low which allows for several simultaneous notes without clipping. If you want louder output and don't care about high polyphony, you could increase the DAC volume with something like\u003cspan\u003e\u0026nbsp;\u003c/span\u003e\u003ccode\u003edac.dac_volume += 10.0\u003c/code\u003e, or you could adjust the ADSR envelope levels by editing\u003cspan\u003e\u0026nbsp;\u003c/span\u003e\u003ccode\u003evca = synthio.Envelope(...)\u003c/code\u003e.\u003c/p\u003e\n\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eAfter Configuration:\u003c/p\u003e\n\u003col\u003e\n\u003cli\u003eConnect a powered speaker, mixer, or whatever to the headphone jack\u003c/li\u003e\n\u003cli\u003ePlug a USB MIDI controller to the USB host port\u003c/li\u003e\n\u003cli\u003ePower the board with a USB power bank\u003c/li\u003e\n\u003cli\u003eWait a few seconds for the USB MIDI device to be detected (the code will listen on all MIDI channels of the first USB MIDI device it finds)\u003c/li\u003e\n\u003cli\u003ePlay some notes\u003c/li\u003e\n\u003c/ol\u003e\n\u003cp\u003eTroubleshooting:\u003c/p\u003e\n\u003cp\u003eIf the above steps don't work for you, you can try connecting to the CircuitPython serial console using a serial monitor program like PyCharm, Mu, tio, or screen. On the serial console, check for status or error messages. If you try to use a MIDI controller that requires the full 500 mA for USB 2.0, you might have problems. In that case, you could try a powered USB hub or a USB OTG style cable that splits power and data onto two different jacks.\u003c/p\u003e\n\u003cp\u003e\u0026nbsp;\u003c/p\u003e\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  \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\u003eCircuitPython Code\u003c/h2\u003e\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\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":"embed","content":"https://github.com/samblenny/fruit-jam-portable-midi-synth/blob/v0.3.0/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  \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\u003eCIRCUITPY/sb_usb_midi.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\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":"embed","content":"https://github.com/samblenny/fruit-jam-portable-midi-synth/blob/v0.3.0/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  \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\u003eCIRCUITPY/sb_usb_descriptor.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\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":"embed","content":"https://github.com/samblenny/fruit-jam-portable-midi-synth/blob/v0.3.0/sb_usb_descriptor.py"}]