brainstate

jbschooley/Virtual-FM-1 · source

Snapshot 0 · 2026-11-04T12:47:28Z · C · GPL-3.0

Content fingerprint8792825485ab69c8df1b2556351d9033a3a703c205187ce1074382c45d8153ef

GitHub description at capture

A software M-VAVE FM-1: FM synth app and VST3/AU plugin with two-way preset and pattern sync over the FM-1+VA firmware

README at capture

# Virtual FM-1

A software M-VAVE FM-1: a Standalone app and VST3/AU plugin that plays the
FM-1's FM engine, edits every sound setting, runs its sequencer and
arpeggiator, and syncs presets and patterns with the hardware, much as
Yamaha's Expanded Softsynth Plugin does with the Montage M and MODX M. Pull or push the preset you're
playing, send an edit to the synth without saving it, or sync the whole
128-preset library in either direction.

Each instance is set to one of the FM-1's firmwares: M-VAVE's own, baud girl's
FM-1+VA, Felucca, Hügelton's multi-engine firmware, SLOOP, isod89's
groovebox built on Felucca, or Melodee, Kerem Kilic's multi-engine firmware
built on Felucca. The plugin runs Felucca, SLOOP and Melodee from their own
source, with their screen, front panel, sequencer and projects. It also plays
**FM1 Open**, M-VAVE's own open firmware, from its source, and pulls from and
sends to an FM-1 running it (no Live), and **ChoralRoot**, Quixotic7's chord
instrument built from Felucca, from its source, syncing its backup with an
FM-1 running it.

It works on its own as a synth too; the FM-1 is only needed for syncing.

> Not affiliated with M-VAVE, baud girl or Hügelton Instruments. Use at your own risk.

## Screenshots

The library beside a preset's FM page (FM-1+VA):

![The preset list beside the FM page of the selected preset](docs/images/fm-editor.png)

Felucca: its user presets and projects beside a part's sound, and its own front panel:

![Felucca's Library tab: the user presets beside the Sound page](docs/images/felucca-library.png)

![Felucca's Device tab: its screen on the HOME page, its knobs, buttons and keys](docs/images/felucca-device.png)

At phone size (the iOS app builds from source):

![Felucca's Device and Library tabs at phone size](docs/images/phone-felucca.png)

## What you need

- **macOS 11 or later** (Apple Silicon or Intel), **Windows 10/11** (64-bit) or
  **Linux** (x86-64, built on Ubuntu 24.04; X11 and ALSA).
- To sync with a synth: an **M-VAVE FM-1** on USB running baud girl's
  **[FM-1+VA firmware](https://baudgirl.com/work/FM-1+VA)** (101; 0.97, 0.96,
  0.93 and 0.94 too), **[Felucca](https://github.com/hugelton/Felucca)**
  1.6.1 (1.6 too, untried; 1.0 to 1.5.1 pulled from only; one on 1.0.3 syncs with an
  instance set to Felucca 1.0.3), **[SLOOP](https://github.com/isod89/sloop-fm1)** 2.7 (2.6
  too, without Live; 2.3 to 2.5 pulled from only) or
  **[Melodee](https://github.com/keremimo/melodee)** 1.4.1 (1.4.0 synced as 1.4.1,
  untried; its Synth only build is not supported; 0.12 to 1.3.6 pulled from only;
  one on 0.13 or 1.1.0 syncs with an instance set to that release) or
  **[ChoralRoot](https://github.com/Quixotic7/ChoralRootFM1)** 0.23 (0.24-beta1
  synced as 0.23; its backup only) or M-VAVE's
  **[FM1 Open](https://github.com/m-vave/fm1_open)** V12 (pull and send, no
  Live). On M-VAVE's own
  firmware the plugin still plays and edits sounds, but cannot read anything
  back from the synth.

## Install

Download the installer for your system from the
[Releases](https://github.com/jbschooley/Virtual-FM-1/releases) page.

- **macOS**: open `Virtual-FM-1-…-macOS.pkg`. The **Installation Type** step
  lists the **Standalone app**, the **VST3 plugin** and the **Audio Unit
  plugin**, all ticked; untick any you don't want. The installer is not signed
  yet, so macOS will say it cannot verify it: open **System Settings ›
  Privacy & Security** and click **Open Anyway**.
- **Windows**: run `Virtual-FM-1-…-Windows.exe` and choose the **Standalone
  app** and/or the **VST3 plugin**. Windows SmartScreen may warn about an
  unknown publisher: click **More info › Run anyway**.
- **Linux**: unpack `Virtual-FM-1-…-Linux-x86_64.tar.gz` and run
  `./install.sh` for your own account, or `sudo ./install.sh --system` for
  everyone. It installs the **Standalone app**, the **VST3** and the **LV2**;
  leave any out with `--no-app`, `--no-vst3` or `--no-lv2`. `./uninstall.sh`
  removes them. Syncing with an FM-1 on Linux has not been tested with the
  hardware yet.

Then rescan plugins in your host. It appears as **Virtual FM-1** by Bockage.
Logic needs a restart to pick up a new Audio Unit.

## Using it

1. Connect the FM-1 with USB and switch it on. The Standalone app finds it by
   itself; in a plugin, click **Find FM-1** (or pick its MIDI ports and
   **Connect**). The line beside it shows the synth's firmware and version.
   Set the firmware menu at the top to the one your FM-1 runs.
2. **Pull all 128** (Library tab, Sync page) copies the synth's presets into
   the plugin. The library is shared by the Standalone and every plugin
   instance in every host, so you do this once. Until then it holds the stock
   presets: M-VAVE's, with baud girl's VA packs in D01-D32. **Import** loads
   either stock bank again (every slot; the library as it was goes to its
   `.trash` folder first).
3. Pick a preset in the list to play it. **Pull what the FM-1 is playing**
   loads the synth's current sound, unsaved changes included.
4. Edit in the **FM** (or **VA**) and **Effects & Envelope** pages beside the
   list. Changes stay unsaved until **Store**, as on the FM-1; **Revert** drops
   them.
5. **Send to FM-1** plays your sound on the synth without saving it there;
   **Live** (top bar) sends every change as you make it. **Store to FM-1** saves the
   preset on the synth. **Push changed** writes every preset that differs.
6. The **Sequencer** tab pulls and pushes patterns; **Arpeggiator** works like
   the FM-1's. Both follow your host's tempo and transport.
   **Settings** holds the pitch-bend range, the MIDI channel the plugin
   plays, the on-screen keyboard's velocity and **Hardware character** (the
   FM-1's 16-bit output and softer high end), saved with the project, with
   Save as default for new instances.
7. **Export...** saves presets as JSON: one, a group (Shift- or Cmd-click the
   list), a bank, all 128, or everything with the patterns. The Sequencer
   tab's **Export...** saves one pattern or all 16, as JSON or as a MIDI
   file. **Import...** reads them back, `.syx` files too, and puts a MIDI
   file's notes into the selected pattern.

Every sound setting is a host parameter, so it can be automated, and a host
project saves its own current preset, edits, patterns and arpeggiator.

## What's in it

- **Engine**: the same FM engine the FM-1 uses (Google's msfa, the core of
  Dexed), 12 voices, matched to the hardware where it was measured: pitch,
  per-preset transpose, velocity response, detune and LFO speed.
- **FM Editor** in Dexed's layout: six operators, algorithm diagram, pitch
  envelope, LFO.
- **Effects and envelope**: the FM-1's filter, reverb, delay, distortion,
  chorus and phaser in each preset's chain order, its global ADSR, and the
  per-note filter FM presets gained in FM-1_092. Settings sync exactly; the
  effects' sound is an approximation of the firmware's.
- **Sequencer**: 16 patterns of up to 64 steps, up to nine notes a step,
  ratchet, chance, gate, transpose, accent, Tie & Slide per step and per
  note, per-pattern Chain, swing, step recording and real-time recording.
- **Arpeggiator**: Up, Down, Inclusive, Exclusive, Random, Order and Repeat
  over 1 to 4 octaves.
- **Sync**: identify, pull and push one preset or all 128, push only what
  changed, send unsaved edits, show a preset on the synth, `.syx` import and
  export (FM-1+VA backups, DX7 banks and voices).
- **JSON presets and patterns**: a readable, editable format for backups and
  for writing sounds and patterns by hand or by script, with a JSON Schema
  editors can check against. See [`docs/JSON-FORMAT.md`](docs/JSON-FORMAT.md).
- **MIDI out**: what the sequencer and arpeggiator play leaves the plugin as
  MIDI, so a host can route it to the synth as well.
- **Felucca 1.6.1**, built from its source: its thirteen engines on four parts,
  each part's parameters in an editor and as host parameters. Its Library tab
  lists the 32 user presets and four projects to load, save, rename and erase;
  its Device tab shows its own screen, buttons, knobs and keys, so its
  sequencer, projects and user presets work as on the device. Its projects and
  user presets are kept in the library as the file Felucca's web editor uses
  for backups. With an FM-1
  running Felucca 1.6.1: pull everything, send everything, or keep both in step live
  (tried with an FM-1 on 1.6.1); the Sequencer tab carries steps' ratchets,
  nudges and conditions, parameter locks and songs with a slot per track. **Felucca 1.0.3** stays
  beside it, its own firmware choice, for the projects made with it: a project saved
  with 1.0.x opens on it, and it syncs fully with an FM-1 still on 1.0.3.
- **SLOOP 2.7**, built from its source the same way: its twelve engines (FM6,
  PHYS and NOISE among them) on three parts and a drum track, each with its
  INSERT, in the same editor and as host parameters, Library and Device tabs.
  Its projects, user presets, FM6 bank, SYN drum kits and MIDI setup are kept in
  the library as the file SLOOP's web editor uses for backups
  (`SLOOP/SLOOP device.json`). With an FM-1 running SLOOP 2.7: pull, send and
  live, as with Felucca; one on 2.3 to 2.5,
  which cannot read 2.6's projects, is pulled from only.
- **Melodee 1.4.1**, built from its source the same way: its engines on four
  parts, PROPHET (with Sequential's Prophet-5 factory programs), CZ-1 (with
  Casio's CZ-1 tones), FM6, SID (with its C64 models) and the 808, 909, SID KIT
  and SID DIGI DRUM kits, three insert effects and three sends on each part into
  a shared return of three effects, each with its TONE, its 32 pattern banks, in
  the same editor and as host parameters, Library and Device tabs. Its projects,
  its shared U001-U384 preset bank and its settings are kept in the library as
  the file Melodee's web editor uses for backups (`Melodee/Melodee device.json`;
  one from 1.3 is taken and its preset banks moved into the shared bank, as the
  FM-1 does it). With an FM-1 running Melodee 1.4.1: pull, send and live, a part's
  own CZ-1 tone or PROPHET patch included (tried with an FM-1 on 1.4.1).
  An FM-1 on 1.3, which cannot read 1.4's projects, is pulled from only. **Melodee
  0.13** and **Melodee 1.1.0** stay beside it, each its own firmware choice, for
  the projects made with them (1.0 retired 0.13's LOFI, PHASE, VOICE and NOISE;
  1.2 removed 1.1's delay, reverb, chorus and slicer): a project saved with one
  opens on it, and it syncs fully with an FM-1 still on that release.
- **FM1 Open V12**, M-VAVE's own firmware ([m-vave/fm1_open](https://github.com/m-vave/fm1_open)),
  built from the open source of its browser preview: its eight tracks and six
  sound sources (DX7-style FM, 303 bass, 808 drums, PSG, Pluck, the sampler with
  its demo samples), its sequencer and its 16 demo projects, played on its own
  front panel and screen (the Device view). Its projects are saved with your
  host's project. With an FM-1 running FM1 Open V12 (its FM-1 tab): pull or send
  the project it plays (and keep it in one of its 16 slots), a track's sound,
  a slot loaded and pulled, and its sample bank. The project a Send replaces, and
  the sample bank a sample Send replaces, are saved in the library first
  (`FM1 Open/Backups`, as `.fm1` and `.fm1s` files M-VAVE's workbench imports);
  what a slot held before a Send saves into it is not kept. A sample Send cannot
  be stopped once writing starts (FM1 Open erases its bank first). No Live: FM1
  Open has no message for one value changed, and a sound sent whole would cut
  what plays. Tried with an FM-1 running V12: Pull, Send, a track's sound, the
  slots' names and the sample bank (saving into a slot not yet).
- **ChoralRoot 0.23**, Quixotic7's chord instrument built from Felucca
  ([Quixotic7/ChoralRootFM1](https://github.com/Quixotic7/ChoralRootFM1)),
  built from its source as its own emulator builds it: played on its own front
  panel and screen (the Device tab). Its Sync page pulls from and sends to an
  FM-1 running it what its backup carries (the sound pool, favourites, loop
  slots, CZ-1 banks and FM6 bank; each side keeps its settings), the FM-1's own
  backed up to the library first (`ChoralRoot/Backups`), and restarts it after
  a Send as its own page does. While it restarts it leaves USB: the app connects
  to it again by itself, a plugin when asked (Find FM-1). Its stored objects are kept in the file its page
  uses for backups (`ChoralRoot/ChoralRoot device.json`). Tried with an FM-1
  running 0.23.

## Not done yet

- **Virtual Analog presets** sync but play through the FM engine. baud girl
  has announced her firmware's source; the VA engine waits for it.
- Some settings have no MIDI control on the synth (the FM filter, distortion
  type, effect order), so they reach it only with **Store to FM-1**.
- Ties, ratchet, chance and accent stay in the plugin; how the synth stores
  them is not known yet. Per-pattern Chain can be read from the synth but not
  written.
- Knob assignments and mono/glide are kept as stored but not edited.
- **AAX** (Pro Tools) is planned; see [`docs/AAX.md`](docs/AAX.md).
- **iPad and iPhone**: the app and AUv3 build from source and sync with the
  FM-1 over USB-C, but are not distributed; see [`docs/IOS.md`](docs/IOS.md).
- **Felucca** and **SLOOP**: their user sample slots are empty.
- **Melodee**: its Sequencer tab edits, pulls and sends the pattern bank each
  part plays (the Sync page's Pull and Send carry all of them).
- **FM1 Open**: no Live with an FM-1 running it, no host parameters, and its
  clock is its own (not the host's tempo); its sample bank is its demo bank
  until one is pulled from an FM-1. It runs the code of M-VAVE's browser
  preview, whose sound M-VAVE says may differ from the device's.
- **ChoralRoot**: its protocol has only its backup, so no host parameters,
  Live, sound copies or patterns; what it plays now (its session) is not saved
  with the host's project.

[`docs/FIRMWARE-GAPS.md`](docs/FIRMWARE-GAPS.md) lists each gap and what to
look for in baud girl's source once it is published.

## Build

Requires CMake 3.22+, a C++20 compiler and Ninja on macOS (`brew install cmake
ninja`), or Visual Studio 2022 on Windows. The Felucca, SLOOP and Melodee
engines need Clang and Python 3 (on Linux, configure with `CC=clang
CXX=clang++`; on Windows, Visual Studio's ClangCL toolset: `cmake -B build -G
"Visual Studio 17 2022" -A x64 -T ClangCL`, with "C++ Clang tools for Windows"
installed); built without them, the plugin leaves them out. JUCE 9.0.3 is a submodule:

```
git clone --recurse-submodules https://github.com/jbschooley/Virtual-FM-1
cd Virtual-FM-1
cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build
ctest --test-dir build
```

The plugins are copied into your user plug-in folders after building
(`-DFM1_COPY_PLUGIN=OFF` to skip). `scripts/package-macos.sh` and
`scripts/installer.iss` build the installers. CI builds, tests and packages
on macOS, Windows and Linux for a version tag (making a draft release), or
when started by hand. [`docs/CONTRIBUTING.md`](docs/CONTRIBUTING.md) explains
the tests and the rules for working with a real FM-1;
[`docs/ADDING-A-FIRMWARE.md`](docs/ADDING-A-FIRMWARE.md) how the firmwares fit
in and how to add one.

Source layout:

- `core/` the MIDI link, the sync session and the firmware profile interface
- `firmwares/` the firmware list and each firmware's releases
  (`Firmwares.cpp`), and one folder per firmware: `fm1_common/` the FM-1
  protocols stock and FM-1+VA share (no JUCE), `fm1_stock/`, `baudgirl_fm1va/`,
  and `felucca/` (its profile and its sync over its editor protocol, Felucca's,
  SLOOP's and Melodee's)
- `engines/` the sound, without JUCE: `dx7/` msfa (Apache-2.0, from Dexed;
  changes in `engines/dx7/msfa/NOTICE.md`) and the voice, envelope and filter
  code around it; `fm1_fx/` the FM-1's effects, the Hardware character stage
  and the rate converter; `felucca/`, `sloop/`, `melodee/` and `choralroot/` Felucca's, SLOOP's, Melodee's
  and ChoralRoot's firmware
  (GPL-3.0, vendored, see their `UPSTREAM.md`) built as libraries
- `plugin/` the processor, editor, parameters, library, sequencer and
  arpeggiator, and Felucca's editor, host parameters and device file;
  `plugin/dexed_ui/` Dexed's look-and-feel and panels
- `tests/` see [`docs/CONTRIBUTING.md`](docs/CONTRIBUTING.md); `fm1_probe` is the
  command-line check against a real FM-1
- `docs/` [contributing](docs/CONTRIBUTING.md), [adding a firmware](docs/ADDING-A-FIRMWARE.md),
  [hardware notes](docs/HARDWARE-NOTES.md), [firmware gaps](docs/FIRMWARE-GAPS.md),
  [AAX plan](docs/AAX.md), [iOS](docs/IOS.md), [JSON format](docs/JSON-FORMAT.md)
  and a [shared protocol proposal](docs/PROTOCOL-PROPOSAL.md) for FM-1 firmwares

## Credits

- **baud girl** for the [FM-1+VA firmware](https://baudgirl.com/work/FM-1+VA),
  whose read-back protocol makes two-way sync possible.
- **Leo Kuroshita** (Hügelton Instruments) for
  [Felucca](https://github.com/hugelton/Felucca), which the plugin builds from
  its source with its author's agreement, its sample pack included.
- **isod89** for [SLOOP](https://github.com/isod89/sloop-fm1), which the plugin
  also builds from its source.
- **Kerem Kilic** for [Melodee](https://github.com/keremimo/melodee), which the
  plugin also builds from its source.
- **Quixotic7** for [ChoralRoot](https://github.com/Quixotic7/ChoralRootFM1),
  which the plugin also builds from its source.
- **Google's music-synthesizer-for-android** (msfa) and **Dexed** by Pascal
  Gauthier and contributors, for the FM engine and the editor's look.
- Reverse-engineering work on the FM-1 by
  [AL-255](https://github.com/AL-255/FM-1-RE),
  [ip2k](https://github.com/ip2k/mvave-fm1-open-firmware),
  [aroum](https://github.com/aroum/fm1-custom-fw) and
  [kagaimiq](https://github.com/kagaimiq/jl-misctools).
- Built with [JUCE](https://juce.com).

## License

GPL-3.0-or-later (see `LICENSE`). Third-party code and its licenses are listed
in [`THIRD_PARTY.md`](THIRD_PARTY.md): msfa is Apache-2.0, the Dexed UI parts
are GPL-3.0-or-later, Felucca, SLOOP, Melodee and ChoralRoot are GPL-3.0-only, JUCE is used under the AGPLv3 and the VST3 SDK is under
the MIT licence. Melodee and ChoralRoot include Casio's CZ-1 tones and Sequential's Prophet-5
programs as sound data, with no licence granted; see `THIRD_PARTY.md`.