FM-1 Linux update
Update an M-VAVE FM-1 from stock firmware V14 to V15 on Linux, with no Windows or macOS updater app.
Both custom firmwares for the FM-1, Baud Girl FM-1+VA and Felucca, need stock V15 first. M-VAVE only ships a Windows/macOS updater. This repo is the Linux route.
Tested once, on 2026-10-03: one FM-1 updated from
FM-1_014toFM-1_015on Ubuntu 22.04 (kernel 5.15, Python 3.10). It worked first time. Unofficial; use at your own risk.
How it works
- The protocol. The FM-1 updates over plain USB-MIDI SysEx, using a JieLi AC791N two-step protocol:
- The running firmware reads parts of the package, checks it, and restarts into its update loader.
- The loader reads the whole package and writes it to flash, then restarts.
- What the computer does. In both steps the synth asks for byte ranges and the computer answers. M-VAVE's own loader, shipped inside the package, does all the flash writes. This is the same process M-VAVE's app runs.
- The tools. Linux needs only the stock
snd-usb-audiodriver, which is loaded automatically. The SysEx side uses Felucca'stools/fm1_install.py(GPL-3.0). It is downloaded at a pinned commit and checked by sha256, not copied into this repo. - The firmware. The package is M-VAVE's own, downloaded from their file store and checked by sha256. It is not redistributed here.
Use
git clone <this repo> && cd fm1-linux-update
./fm1-update.sh setup # venv (mido + python-rtmidi), installer, firmware -- all verified
./fm1-update.sh info # read-only identity check, e.g. "FM-1_014 [running]"
./fm1-update.sh flash # asks, then flashes in the background; tail -f fm1-update.log
./fm1-update.sh info # expect "FM-1_015 [running]"
Before you start:
- Use a USB data cable. A charge-only cable never shows up in
lsusb. - Switch the FM-1 on.
- Check it is detected:
lsusbshould list4c4a:c755 Jieli Technology USB Composite Device. After V15 the product name readsFM-1. - No root is needed if your user can open ALSA sequencer ports (usually the
audiogroup).
What a good run looks like:
starting the update on FM-1_014
checking the package (1..9 reads)
switching to update mode
writing ... 100% <- jumps around: the loader asks for the image from the end backwards
restarting
done: the FM-1 runs FM-1_015
If it stops partway, the FM-1 stays in its update loader (--info shows update loader). Run flash again to finish the write.
Measuring the reverb tail (reverb_sweep.py)
V15 changed effect values from 0–10 to 0–100 without converting stored values, so old reverb settings ring short. The FM-1 is also a USB audio device. reverb_sweep.py uses that:
- sets the reverb over MIDI CC (4 on, 5 type, 6 decay, 7 mix, on the Effect Channel, default 2)
- plays a note
- records the synth with ffmpeg from
plughw:FM1(24-bit packed audio, sohw:fails) - reports how long the tail takes to fall 20 and 40 dB
venv/bin/python reverb_sweep.py --off --decays 0,25,50,75,100 --type 1 --mix 60
Measured: Hall at decay 8 falls 40 dB in 0.5 s; at decay 100 it takes about 5 s. Needs ffmpeg.
The checks (verify_fwsc.py)
| Check | Value |
|---|---|
| Source | yms-file-store.oss-cn-hongkong.aliyuncs.com/software/firmware/FM-1.fwsc (Last-Modified 2026-07-30, 699,956 bytes; server Content-MD5 matched) |
| sha256 | db1642b2b6fa5c2cccb11ffd13878068bb28601678d3644049f99dc40e7edb8a |
| Embedded name | FM-1_015 |
| 16 KB flash head (bootloader + chip config) | sha256 d9f43191…bd67. This is the same stock-V15 constant Baud Girl's installer refuses any change to |
The file's internal JieLi CRCs (UFW header, entry list, flash.bin, app_area_head, app.bin, cfg) were also checked, using Baud Girl's fwsc.js derive(). That check isn't included here.
Caveats
- There is no hardware recovery path. The FM-1 has no JTAG/SWD/UART header and no recovery button. If an update goes badly wrong, the only known recovery is forcing the AC791N's built-in USB download mode with an RP2040-based dongle.
- Keep the run detached and the machine awake. Don't unplug mid-write.
- Back up presets first if you can. The stock update keeps presets, and V14 has no known SysEx dump.
- Felucca's installer needs
--forcefor stock packages. It refuses packages without its own loader marker unless forced.fm1-update.shpasses--forceonly for this verified stock file.
Credits
- AL-255/FM-1-RE: reverse-engineering of the update protocol.
- Felucca by Leo Kuroshita / Hügelton Instruments:
fm1_install.py. - Baud Girl: the stock-head gate constant and the package-format notes.
- aroum/fm1-custom-fw: the location of the V15 package.
M-VAVE and FM-1 are trademarks of their owners. Not affiliated with M-VAVE, Felucca or Baud Girl.
Licence: MIT (this repo's own scripts only).
