A work-in-progress baremetal Roland MT-32 and CM-32L emulator for the Raspberry Pi 3 or above, based on Munt and Circle. Turn your Raspberry Pi into a dedicated emulation of the famous multi-timbre sound module used by countless classic MS-DOS and Sharp X68000 games, that starts up in seconds!
- ✔️ Project status
- ✨ Quick-start guide
- 📝 Configuration file
- 🎹 MIDI connectivity
- 🔊 I2S DAC support
- 📺 LCD and OLED displays
- 🧠 ROM support
- 🔩 Custom hardware
- 💬 Custom System Exclusive messages
- ❓ FAQ
- ⚖️ Disclaimer
- 🙌 Acknowledgments
- Tested on Raspberry Pi 4 Model B and Raspberry Pi 3 Model B & B+.
- Pi 2 works, but only with concessions on playback quality.
- Pi 0 and 1 are unfortunately too slow, even with an overclock.
- PWM headphone jack audio.
- Quality is known to be poor (aliasing/distortion on quieter sounds).
- It is not currently known whether this can be improved or not.
- I2S Hi-Fi DAC support.
- This is the recommended audio output method for the best quality audio.
- USB or GPIO MIDI interface.
- Config file for selecting hardware options and fine tuning.
- LCD status screen support (for MT-32 SysEx messages and status information).
- Control buttons, rotary encoder etc. is planned.
- A port of FluidSynth is planned.
- Network MIDI and auto-update is planned.
- Download the latest release from the Releases section.
- Extract contents to a blank FAT32-formatted SD card.
- If you are updating an old version, you can just replace the
kernel*.img
files. The other boot files will not change often; but keep an eye on the changelog just in case.
- If you are updating an old version, you can just replace the
- Add your MT-32 or CM-32L ROM images to the
roms
directory - you have to provide these for copyright reasons.- You will need at least one control ROM and one PCM ROM. For information on using multiple ROM sets and switching between them, see the ROM support section.
- The file names or extensions don't matter;
mt32-pi
will scan and detect their types automatically.
- Connect a USB MIDI interface or GPIO MIDI circuit to the Pi, and connect some speakers to the headphone jack.
- Connect your vintage PC's MIDI OUT to the Pi's MIDI IN and (optionally) vice versa.
mt32-pi
tries to read a configuration file from the root of the SD card named mt32-pi.cfg
. Please read the file for a description of all the available options.
⚠️ Note: Don't confuse this file withconfig.txt
orcmdline.txt
- they are for configuring the Raspberry Pi itself, and you should not need to alter these when usingmt32-pi
.
For the Raspberry Pi to be able to receive MIDI data, it needs a MIDI interface. The simplest way is to connect an off-the-shelf USB MIDI interface to one of its USB ports. More advanced users or electronics enthusiasts may wish to build a GPIO MIDI interface instead.
Here are some typical connection examples:
[ Pi ] --> [ USB/GPIO MIDI ] <===> [ USB MIDI ] <-- [ Modern PC ]
[ Pi ] --> [ USB/GPIO MIDI ] <===> [ Gameport MIDI cable ] <-- [ Vintage PC ]
[ Pi ] --> [ USB/GPIO MIDI ] <===> [ Atari ST or other machine with built-in MIDI ]
[ Pi ] --> [ USB/GPIO MIDI ] <===> [ Synthesizer keyboard or controller ]
If you want to receive MIDI on the Pi using a USB MIDI interface, any class-compliant interface should work fine. If the interface works on Windows or Linux PCs without requiring any drivers, there's a high chance it will work with mt32-pi
.
Please check our wiki page for recommended interfaces and compatibility reports.
⚠️ Beware: cheap no-name interfaces are not recommended; they have reliability issues not unique to this project [1, 2, 3].
You can build a simple circuit based on an opto-isolator, a diode, and a few resistors. If mt32-pi
does not detect any USB MIDI devices present on startup, it will expect to receive input on the UART RX pin (pin 10).
💡 Tip: You can disable detection of USB MIDI interfaces by setting
usb = off
in the config file. This can shave off a couple of seconds of boot time as USB initialization is then skipped on startup.
You can also skip the MIDI circuitry and drive mt32-pi
using a serial port directly using software such as Hairless MIDI or SoftMPU and suitable cabling. Use the gpio_baud_rate
option in the configuration file to match up mt32-pi
with your host's serial port baud rate.
⚠️ Note: Remember that the Raspberry Pi expects no more than 3.3V on its GPIO pins, so make sure that you use appropriate level shifting when interfacing with other hardware to prevent damage to the Pi.
The Raspberry Pi's headphone jack is a simple PWM device, and not designed for high-fidelity audio. This becomes very obvious when you use mt32-pi
- distortion in the sound is apparent when quieter sounds are playing.
Luckily, a plethora of inexpensive DAC (digital-to-analog converter) hardware is available for the Raspberry Pi, giving it true hi-fi quality audio output. These often take the form of an easy-to-install "HAT" board that you place onto the Raspberry Pi's GPIO pins. They make use of the Raspberry Pi's I2S bus for interfacing.
⚠️ Note: We do not support any kind of USB DAC audio output device, due to the lack of drivers in the Circle baremetal framework that we depend on. Adding USB audio support to Circle would be a huge undertaking, although if that changes in the future and Circle gains USB audio support, we could certainly make use of it.
mt32-pi
defaults to PWM (headphone) output. Editmt32-pi.cfg
and changeoutput_device
toi2s
to enable the I2S DAC driver.- If your DAC requires software configuration, you may need to edit the
i2c_dac_address
andi2c_dac_init
options to suit your particular DAC. Continue reading for further details.
Currently, we have been targeting DACs based on the Texas Instruments PCM5xxx series of chips due to their popularity, but other DACs could be supported quite easily. The NXP UDA1334 is also reportedly working well.
Some more advanced DACs are configured by software (normally a Linux driver), whereas others need no configuration as they are preconfigured in hardware. This will vary between manufacturers, and so some editing of mt32-pi.cfg
may be required.
⚠️ Note: If a DAC requires software configuration, they will not produce any sound until they have been properly initialized. This initialization is done by sending it a special sequence of commands over the I2C (not I2S) bus. For the PCM5xxx family, you can seti2c_dac_init = pcm51xx
to enable this.
Feel free to open an issue if you'd like to help us support your DAC, or even just to report success or failure so that we can build a list of supported DACs.
The following models of DAC have been confirmed as working by our testers. Please note the necessary configuration file options.
Manufacturer | Device | DAC chip | Config file options | Comments |
---|---|---|---|---|
Arananet | PI-MIDI | UDA1334 | None required | Stereo RCA output. Custom design by @arananet also with GPIO MIDI in. Tested by @dwhinham. |
Generic | GY-PCM5102 | PCM5102A | None required | Stereo 3.5mm output. Found very cheaply on AliExpress and other sites. Tested by @dwhinham. |
Generic | Pi-Fi DAC+ v2.0 | PCM5122 | i2c_dac_init = pcm51xx , i2c_dac_address = 4d |
Stereo RCA and 3.5mm output. Tested by @rc55. |
innomaker | HiFi DAC HAT | PCM5122 | i2c_dac_init = pcm51xx , i2c_dac_address = 4d |
Stereo RCA and 3.5mm output. Tested by @calvinmorrow. |
IQaudIO | Pi-DAC Pro | PCM5242 | i2c_dac_init = pcm51xx , i2c_dac_address = 4c |
Stereo RCA and 3.5mm output. Tested by @dwhinham. |
The i2c_dac_address
configuration file option determines what address on the I2C bus that mt32-pi
will send initialization commands to, if i2c_dac_init
is not set to none
.
If your DAC does not appear in the compatibility table above, you can help by carrying out the following:
- Connect the DAC to your Raspberry Pi.
- Insert an SD card containing the latest version of Raspberry Pi OS (aka. Raspbian) and boot the Pi.
- Run the command
sudo raspi-config
. - Select "Interfacing Options", followed by "I2C" and "Yes" to enable the I2C kernel modules.
- Exit
raspi-config
, and run the commandsudo apt-get install i2c-tools
to install some I2C utilities. - Run the command
i2cdetect -y 1
. The output should be like the following:0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- UU -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
- In this example, the address is 4d. Make a note of this and set
i2c_dac_address
inmt32-pi.cfg
. - If your DAC now works, open an issue to let us know, and we can add it to the table! Otherwise, open an issue anyway, and we can try to work out how to support it.
mt32-pi
supports various LCD and OLED displays, both traditional character displays like the original MT-32, and modern graphical displays.
The MT-32 had a single row, 20 column display, but these are hard to find nowadays. 20x2 and 20x4 displays are common however, and mt32-pi
can use the extra rows to display additional information.
To enable a display, you will need to edit mt32-pi.cfg
accordingly, and correctly connect your display to the Raspberry Pi.
There are currently three different LCD drivers, which are detailed in the following sections.
This driver is for connecting a traditional HD44780 or compatible (e.g. Winstar WS0010/Raystar RS0010) character display directly to the Pi's GPIO pins in 4-bit mode. Currently, only 20x2 and 20x4 displays have been tested. In theory, other widths should work, but there is currently no special handling/scrolling for narrower displays.
Consult your display's datasheet to determine the correct LCD pins to connect to the GPIOs. The current pinout is as follows:
LCD signal | Physical Raspberry Pi pin | BCM pin |
---|---|---|
RS |
19 | 10 |
RW |
21 | 9 |
EN |
23 | 11 |
D4 |
27 | 0 |
D5 |
29 | 5 |
D6 |
31 | 6 |
D7 |
33 | 13 |
You will also need to connect a power source and ground to your display. Consult its datasheet to see if it requires 3.3V or 5V. You should be able to use the Pi's 3.3V, 5V, and ground pins as necessary, but check the datasheet to ensure the display doesn't draw more current than the Pi can deliver safely.
⚠️ Note: The GPIO assignment could change in later versions as more functionality is added, so BE WARNED if you are thinking about designing hardware.
This driver is functionally equivalent to the 4-bit driver, but instead of using GPIOs to drive the LCD's data signals directly, the Pi communicates with the display via an I2C-connected I/O expander. Some vendors refer to these as an "I2C backpack".
These displays are very convenient as they only need 4 wires to connect to the Pi. Your display will connect to the Pi's SDA
and SCL
lines (pins 3 and 5 respectively), as well as power and ground. As always, check your display's datasheet for power requirements.
As with all I2C devices, you must know the LCD's I2C address in order for it to work. You should be able to find its address on the datasheet, or the "backpack" may have jumpers to configure the address. In case of doubt, you can connect the display and use Linux to discover your display using the same procedure described in the DAC section.
The SSD1306 controller is found in mini 128x32 and 128x64 OLED displays, which are well-known for their use in FlashFloppy/Gotek devices. They can be found for very little money on eBay and AliExpress.
Currently, only the 32-pixel high version is supported, although if someone were to send me a 64-pixel high model, I'd be glad to test it and add support!
These displays usually have an I2C address of 0x3c
.
The following displays and configurations have been confirmed as working by our testers. Please note the necessary configuration file options.
Manufacturer | Device | Config file options | Comments |
---|---|---|---|
BuyDisplay.com | 2002-1 Series | type = hd44780_i2c , width = 20 , height = 2 , i2c_lcd_address = 27 |
Very bright and inexpensive 20x2 LCD. Tested by @dwhinham. |
Generic | 128x32 OLED | type = ssd1306_i2c , width = 128 , height = 32 , i2c_lcd_address = 3c |
Extremely cheap yet nice and bright mini OLED. Widely available on AliExpress and eBay. Tested by @dwhinham. |
Raystar | REC002004B | type = hd44780_4bit , width = 20 , height = 4 |
High-contrast 20x4 OLED display. Tested by @dwhinham. |
mt32-pi
can make use of all ROMs that Munt supports, and allows switching between ROM sets on-the-fly for greater compatibility with various games. For further information about which games work best with each ROM set, consult the MT-32 game compatibility list.
A ROM set consists of:
- a control ROM (contains the code that runs on the MT-32's CPU).
- a PCM ROM (contains the sound samples).
For simplicity, mt32-pi
categorises the known control ROMs into three types:
- MT-32 (old): The original version of the MT-32, ROM versions 1.xx.
- MT-32 (new): The later version of the MT-32, ROM versions 2.xx.
- CM-32L: A "computer music" module compatible with the MT-32, but with additional sound effects for games, and the LCD/buttons removed.
As for PCM ROMs, there are only two known versions - the MT-32 version (common to both models of MT-32), and the CM-32L version.
To summarize, to get the most out of mt32-pi
, you'll need 5 ROM files in total - old/new/CM-32L control ROMs, and MT-32/CM-32L PCM ROMs.
On startup, mt32-pi
will scan the roms
directory and load the first ROM it encounters that matches each category. In other words, if you have two "old" control ROMs (e.g. version 1.05 and 1.07), only one of them will be used and assigned to the "old" category slot. Therefore, it's recommended that you only place one ROM per category in the roms
directory.
When multiple ROM sets are available, the default set to load on startup can be set in the configuration file.
You can use a custom SysEx message to make mt32-pi
quickly swap ROM sets at runtime. If the ROM set is available and loaded, the emulated MT-32 will be restarted with the new ROMs active.
It may be useful to create scripts (e.g. a DOS batch file) that send mt32-pi
ROM set swap messages before launching a game.
In the future, mt32-pi
will allow you to switch ROM sets from a menu or button combination.
The community has been designing some excellent custom hardware for use with mt32-pi
. The PI-MIDI by @arananet is the first example, which provides an OLED display, MIDI input, and a DAC for a complete plug 'n' play experience!
If you have created something cool with mt32-pi
, please get in touch if you'd like to share it and have it featured here.
⚠️ Note: If you are designing custom hardware formt32-pi
, and want to add features that are not documented here, open an issue so we can work together on supporting it.
mt32-pi
responds to MT-32 SysEx messages as you would expect, but it can also respond to its own commands. mt32-pi
listens for manufacturer ID 0x7D
, or the "non-commercial/educational use" special ID. Therefore, a complete mt32-pi
SysEx message looks like:
F0 7D { command } { parameters } F7
⚠️ Note: These commands are subject to change until the project reaches a mature state.
Command | Description | Parameters |
---|---|---|
00 |
Reboot the Raspberry Pi. | None |
01 xx |
Switch ROM set. | xx = 00 : MT-32 (old)xx = 01 : MT-32 (new)xx = 02 : CM-32L |
- Q: I'm trying to play sounds on
mt32-pi
using my MIDI keyboard controller but I'm not hearing anything - what's wrong?
A: Your keyboard is probably sending note data on channel 1, but by default, on power-up the MT-32 is set to receive on MIDI channels 2-10. Check your keyboard's documentation to see if you can change the transmit channel. If this isn't possible, see this wiki page for more information on how to reassign the emulated MT-32's channels. - Q: I'm getting sound distortion and/or the power LED on my Raspberry Pi is blinking - why?
A: It's possible that the Pi is not receiving enough power. Try swapping the USB cable being used to power the Pi, or try another power supply. Check the Raspberry Pi power supply page for recommended power supply specifications. - Q: Why don't I see any video output on my HDMI-connected monitor or television? Has the Pi has failed to boot?
A: This is completely normal -mt32-pi
is designed to run headless and therefore there is no video output. For troubleshooting purposes, it's possible to compilemt32-pi
with HDMI debug logs enabled, but these builds will hang on a Raspberry Pi 4 if no HDMI display is attached due to a quirk of the Pi 4 and Circle. Hence, for regular use, video output is disabled. - Q: What happened to the old
mt32-pi
project that was based on a minimal Linux distro built with Buildroot?
A: That's been archived in theold-buildroot
branch.
This project, just like Munt, has no affiliation with Roland Corporation. Use of "Roland" or other registered trademarks is purely for informational purposes only, and implies no endorsement by or affiliation with their respective owners.
- Many thanks go out to @rc55 and @nswaldman for their encouragement and testing! ❤️
- The Munt team for their incredible work reverse-engineering the Roland MT-32 and producing an excellent emulation and well-structured project.
- The Circle and circle-stdlib projects for providing the best C++ baremetal framework for the Raspberry Pi.
- The inih project for a nice, lightweight config file parser.