Firmware

fm1-linux-update

Hype27/100

Update the M-VAVE FM-1 synth from stock V14 to V15 on Linux (USB-MIDI SysEx), with verification

fm1-linux-update is custom firmware for the M-VAVE FM-1, by @fuleo. Open source under MIT.

forM-VAVE FM-1·by@fuleo

Unclaimed. Is this yours? Sign in with GitHub as @fuleo to claim it.

Downloads
0
Stars
0
Forks
0
Commits
2
Last commit
Get the source

No release files yet. Build from source.

MIT· fuleo/fm1-linux-update·fuleo.github.io/fm1-guide/linux-update.html·downloads come from the creator’s GitHub releases

2
Commits
0
Releases
2 commits and 0 releases in the last year
Activity · last 12 months

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_014 to FM-1_015 on 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:
    1. The running firmware reads parts of the package, checks it, and restarts into its update loader.
    2. 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-audio driver, which is loaded automatically. The SysEx side uses Felucca's tools/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: lsusb should list 4c4a:c755 Jieli Technology USB Composite Device. After V15 the product name reads FM-1.
  • No root is needed if your user can open ALSA sequencer ports (usually the audio group).

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:

  1. sets the reverb over MIDI CC (4 on, 5 type, 6 decay, 7 mix, on the Effect Channel, default 2)
  2. plays a note
  3. records the synth with ffmpeg from plughw:FM1 (24-bit packed audio, so hw: fails)
  4. 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)

CheckValue
Sourceyms-file-store.oss-cn-hongkong.aliyuncs.com/software/firmware/FM-1.fwsc (Last-Modified 2026-07-30, 699,956 bytes; server Content-MD5 matched)
sha256db1642b2b6fa5c2cccb11ffd13878068bb28601678d3644049f99dc40e7edb8a
Embedded nameFM-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 --force for stock packages. It refuses packages without its own loader marker unless forced. fm1-update.sh passes --force only 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).