The project's motivation was for a software implementation of an FM synthesizer popular in the days of yore which would enable my embedded projects to have rich silly sounds and not require a boatload of precious flash to deliver the jokes. (e.g. my never-ending calculator project **demands** that when pressing down a special key it plays a little melody. And faithfully rendered, at that.) But the joke's on me if that flourish consumes all the flash and ram and cpu. What's a jester to do?
To make a library you need a testbed application to exercise its parts, and in this case that testbed started growing legs and became first an emulation of old PC sound cards and shortly thereafter a MIDI synthesizer. I decided to polish that testbed into a standalone project to be considered on its own merits. So here it is.
My goal was to support what we would now consider modest hardware in the form of my beloved 'BluePill' -- a breakout board sporting an STM32F103 (ARM Cortex-M3, 72 MHz, 64 KiB flash, 20 KiB ram, no fpu or instruction stream acceleration). So a $3 board. I think I largely achieve the goal, though the fm core compiles down to about 20 KiB flash, and you need ram for the rendered pcm, so that's a few KiB.
This supports an El Cheapo output option of stereo PWM, but also a De Luxe option of PCM5102A I2S DAC (though the F103 has no I2S so a hack has to be done using SPI and a timer peripheral). In absolute costs it's a wash because the PWM requires an external filter and amp, whereas the DAC costs the same or cheaper. But you might have your reasons. If you opt for PWM you get about 10-11 bits dynamic range and a 8-10 kHz bandwidth. If you opt for DAC you get a delicious 16-bits and sweet, sweet, 17 kHz bandwidth. Mmmmhh -- bits and bandwidth, baby!
For tire-kicking I have provided built firmware you can flash on your board. The F103 build is very tight, and the BOOT1 jumper is used to select at boot time between the PWM output (in the normal '0' position) and the PCM5012A output (the alternative '1' position). Either way, the firmware will enumerate to USB as a multi class device supporting USB CDC and also USB MIDI.
The USB CDC supports DRO streaming from DOSBox-X and other things using a common and obvious protocol like in the Nuke.YKT and opl3board. It supports those register sets and I added custom ones to support a few things like reset, volume, and identification, and also tunneling bulk transport for richer capabilities.
The MIDI is standard midi and should work with whatever controller, and there are some SysEx messages for transporting 'banks' to the device to set up the FM parameters for instruments.
In addition to the tire-kicking firmware build I have included some python scripts for sending DRO and MIDI (and banks) to the device. I created a bespoke bank format *.fmb for this project. There are an ocean of existing banks and formats out there, but I added to that noise because I found them lacking some features I wanted. There is an existing tool 'OPL3 Bank Editor' that can translate between all of those and has and native format 'WOPL'. I considered making 'wopl' the native format for this device, but it lacks some capability so regretfully I could not do that. Instead I have a tool that convert to/from wopl (somewhat lossily, alas), so that is the gateway path to existing bank definitions.
Dev work is done on the the F411. I consider the F103 'done' barring bugs I do not expect. The F411 has more space for features and there is a full interactive console there and I can develop support for additional codecs since it has proper I2S. The F401 build exists as well, but I now keep that as a 'device' build like the F103. It has slightly greater functionality in being able to support proper I2S and optional external SPI flash storage for files. But since the F411 'BlackPill' costs about the same I figure that's were folks will go, but hey maybe you have some F401's on hand, so we've got you.
Fair warning: I did build this with AI code generation assistance. Though I wouldn't characterize this as 'vibe coded' as I was very much hands on in the process to get the math, structure, and performance I required. I think the git history will bear that out. But I was more than happy to let the tool emit lines of code that achieved my criteria, and the tool was much faster than my typing it in and similarly more thorough in generating and executing tests. But I understand that this may be off-putting to some, so I want to be forthcoming about its provenance.
ziggurat29