Written from devices/preenfm/preenfm2.vendor.fw-3.10-alpha.jsonEdit on GitHubJSONMIDNAMOSCQuery

PreenFM2 (3.10 alpha) MIDI CC chart, NRPN and OSC map

The PreenFM2 MIDI implementation: 84 CC, 8 NRPN, each named, for Claude (MCP), SuperCollider or any OSC app.

  • sourcemaker's documentation
  • firmware3.10-alpha
  • real unitnot yet checked

Not checked on a real PreenFM2 yet. Own one? Load a sound or send a control, and tell us whether it worked.

Maker
PreenFM
Version
3.10 alpha (alternative firmware by sscheidl)
Source
maker's documentation
OSC prefix
/preenfm2_310alpha
README.mdfrom the author's repository; not claimed yet, anyone can improve itEdit

From the README of sscheidl/preenfm2-vosim-editor-firmware at 1107a62, licence GPL (as upstream, per the README).

PreenFM2 3.10 alpha firmware — VOSIM + editor protocol + PolyAT/MPE

⚠ Experimental developer firmware — hardware validation of the new expression work is still pending

This repository contains the PreenFM2 VOSIM firmware plus the editor remote-store protocol and true MIDI Polyphonic Key Pressure and Lower-Zone MPE. The source version is 3.10 alpha (Makefile, shown on the boot screen as preenfm2 v3.10 alpha).

3.10 alpha binaries are available as the pre-release v3.10alpha, built with GCC 4.7.4 from commit f6fe06c. They contain PolyAT and Lower-Zone MPE but have not yet been validated on hardware. The earlier v3.00alpha-full-mpe-rc1 pre-release carries the same code labelled 3.00 alpha. The only binaries in the repository itself (release/editor-protocol-3.00alpha/) are the older editor-protocol-only 3.00 alpha build without PolyAT/MPE, which has run successfully on a physical PreenFM2.

Do not flash the GCC-13 cloud binaries. The build gate (clean local build of 3.10 alpha with gcc-arm-none-eabi 4.7-2014q2 / GCC 4.7.4) is passed; the open gate is manual hardware validation.

PreenFM2 test hardware running the 3.00 alpha firmware (photo of the earlier build)


Current development status — 2026-10-02

Default branch: feature/editor-remote-store, which contains feature/full-mpe (fast-forward, source commit 374be62f05ead717b1fa674abbd97a2deac643d8, pre-release v3.00alpha-full-mpe-rc1) plus the version change to 3.10 alpha. Apart from the version string the source is identical to that release candidate. The 3.10 alpha binaries (pre-release v3.10alpha) were built from commit f6fe06c2677afe82b92c480f1671d79120b13c21.

Current state:

  • VOSIM / editor remote protocol (3.00 alpha base): retained.
  • Version 3.10 alpha: the minor bump marks the PolyAT and Lower-Zone MPE work on top of the 3.00 alpha editor-protocol base.
  • True MIDI Polyphonic Key Pressure: implemented and independently source-reviewed. Existing AftT matrix routes become note-local when MIDI Polyphonic Key Pressure is received; ordinary Channel Pressure keeps the timbre-wide behaviour.
  • Lower-Zone MPE: implemented for the intended ROLI workflow:
  • Strike → Note-On velocity
  • Press → per-voice AftT
  • Glide → per-voice pitch bend
  • Slide → per-voice CC74 / MPESLIDE
  • Member pitch-bend range: supported up to ±48 semitones. Larger member RPN-0 values are clamped because the current exp2_harm frequency representation cannot reproduce ±96 without saturation.
  • Host verification: mpe_state_test.py 325 checks, polyat_state_test.py 79 checks, protocol_sim_test.py 115 checks; these are simulations / structural tests, not firmware unit tests and not hardware tests.
  • Comparative cloud builds: pfm, pfmo, pfmcv, pfmcvo compile/link with the GCC-13.2 substitute environment and no new warnings. These binaries are not release-valid and must not be flashed.

Known MPE limitations are documented rather than hidden: Lower Zone only, RPN 6 with n=0 is consumed but does not deactivate MPE, manager-channel pitch-bend sensitivity is recorded but not applied as a semitone range, no Lift/release-velocity expression, and MPE with Unison or the arpeggiator is not supported.

Detailed reports:

Hardware-test tools:

  • tools/polyat_test.py — deterministic MIDI Polyphonic Key Pressure / Channel Pressure sender
  • tools/midi_monitor.py — MIDI input monitor to verify what the controller actually transmits
  • tools/mpe_test.py — deterministic Lower-Zone MPE sender for Press / Glide / Slide / sustain / voice-allocation scenarios
  • test/midi/ — Standard MIDI Files with the Lower-Zone MPE scenarios A–J for DAW playback, generated from tools/mpe_test.py (not yet verified in a DAW or on hardware)
Next gate

The next step is deliberately not more feature work. Steps 1–5 are done for 3.10 alpha; the builds and their SHA-256 values are in the v3.10alpha pre-release. Steps 6 and 7 remain:

  1. check out the final feature/full-mpe source locally;
  2. build cleanly with the historical gcc-arm-none-eabi 4.7-2014q2 / GCC 4.7.4 toolchain;
  3. build all four targets separately (pfm, pfmo, pfmcv, pfmcvo) with a clean build directory between targets;
  4. record the exact output filename and SHA-256 of every resulting binary;
  5. identify the correct hardware image for the physical PreenFM2;
  6. flash manually — never automatically;
  7. validate ordinary MIDI and Channel Aftertouch first, then PolyAT, then Lower-Zone MPE with LUMI / Seaboard RISE.

See docs/POLYAT_HARDWARE_TEST_CHECKLIST.md and §18 of docs/MPE_IMPLEMENTATION_REPORT.md.


What this repository is

This repository started as a focused extension of the PreenFM2 VOSIM firmware: a MIDI protocol that lets PreenFM+ store the current edit buffer, query the current bank/preset position and detect firmware capability support. That 3.00-alpha base is still preserved.

The current development branch additionally carries the PolyAT and Lower-Zone MPE work described above. It remains a standalone firmware repository; it is not a GitHub fork or a submodule of the editor project. Original history, GPL headers and author attribution are retained.

[!IMPORTANT] Experimental AI-assisted development. This tAUREON project explores the practical benefits and limits of AI-assisted work on audio and synthesizer software. Development has been human-directed with OpenAI Codex / ChatGPT and Anthropic Claude Code used in separate implementation and review roles. Treat the current expression branch as developer firmware until the historical-toolchain build and physical-hardware gates have passed.

origin of the code pvig/preenfm2
VOSIM base branch vosim
VOSIM base commit 6ed604a43636c00bfbac9613c8f5a79a7582dfa7
editor-protocol baseline branch feature/editor-remote-store
reviewed PolyAT checkpoint feature/true-poly-aftertouch @ f503e7fd34c1df887e421f782520275a7b807632
PolyAT/MPE branch (merged into the default branch) feature/full-mpe @ 374be62f05ead717b1fa674abbd97a2deac643d8
firmware version 3.10 alpha (pre-release; the editor-protocol build was 3.00 alpha, original base was 2.21b)

Remotes are set up as:

upstream -> https://github.com/pvig/preenfm2.git
origin   -> https://github.com/sscheidl/preenfm2-vosim-editor-firmware.git
Why the VOSIM branch

pvig/preenfm2 vosim carries VOSIM algorithms 29–32 and the additional LFO shapes 6–8. They are part of the base and are preserved by the 3.00-alpha work. The reference material for the historical VOSIM build is under release/fw_2.21b_lfo_vosim/.


Editor remote protocol

The editor extension uses NRPN page 4, which older firmware silently ignores:

NRPN page / LSB command
4 / 0 capability query
4 / 1 current-position query
4 / 2 store current edit buffer to a bank/preset target

Responses use page 4, LSB 64 and above, with explicit status codes. The protocol specification and the earlier editor-protocol-only build are in release/editor-protocol-3.00alpha/. That directory is historical: it holds the hardware-tested 3.00 alpha binaries without PolyAT/MPE, and its SHA256SUMS belong to those files only. It is not updated for 3.10 alpha.

PreenFM+ 4.0.4 implements capability detection, position query, guarded Store and status reporting. On the device, Receives: must include NRPN for those requests.

Existing patch format and ordinary program/bank loading remain compatible with the underlying 2.21/VOSIM format.


Building

The historical toolchain is arm-gcc 4.7-2014q2. It is not bundled in this repository.

GCC_PATH in the Makefile still points to the original author's environment, so normally place the historical toolchain on PATH and override the tools on the command line:

export PATH="/path/to/gcc-arm-none-eabi-4_7-2014q2/bin:$PATH"

MK='make CC=arm-none-eabi-c++ AS=arm-none-eabi-as NM=arm-none-eabi-nm \
        READELF=arm-none-eabi-readelf CP=arm-none-eabi-objcopy'

$MK clean && $MK pfm
$MK clean && $MK pfmo
$MK clean && $MK pfmcv
$MK clean && $MK pfmcvo

For the current hardware-validation build, also clear stale build outputs between targets and record the filename from .binfirmware; do not assume that the last .bin in build/ belongs to the target just built.

Useful host checks:

python test/host/protocol_sim_test.py
python test/host/polyat_state_test.py
python test/host/mpe_state_test.py
python tools/polyat_test.py --self-test
python tools/mpe_test.py --self-test

These checks complement — and never replace — the historical-toolchain build and physical-hardware test.


Authors and license

The PreenFM2 firmware is the work of Xavier Hosxe. The VOSIM branch used as the base is maintained by pvig. The tAUREON editor protocol (3.00 alpha), PolyAT and MPE (3.10 alpha) development in this repository were produced through human-directed development with AI assistance.

The boot screen for the 3.x alpha line credits By Hosxe & tAUREON.

GPL, as upstream. Original source-file copyright and GPL headers remain intact; the USB manufacturer string continues to identify the device as Xavier Hosxe's design.


Upstream README summary

The official PreenFM2 firmware repository is Ixox/preenfm2. The upstream project uses ARM GCC 4.7 and provides the original hardware, firmware and flashing documentation. For first-time flashing and bootloader details, follow the upstream PreenFM2 instructions rather than treating this development README as a replacement for them.

Use it

Find the MIDI ports, then start the bridge with this driver:

osc-bridge detect        # prints the ready-to-run line for what is plugged in
osc-bridge run --device devices/preenfm/preenfm2.vendor.fw-3.10-alpha.json --out-port <N> --in-port <M>

Then send OSC to 127.0.0.1:7777, for example:

osc-bridge osc-send /preenfm2_310alpha/bank 63

From Claude or any MCP client, the osc-bridge mcp server exposes this driver as preenfm2_310alpha: ask “what can the PreenFM2 do?” and it reads this map with list_routes. See the MCP guide.

MIDI controls

92 controls, each with its number, its range and the name to send

CC

Control CC Range Name to send
Bank 0 discrete /preenfm2_310alpha/bank
Bank lsb 32 discrete /preenfm2_310alpha/bank_lsb
Mod wheel 1 0–127 /preenfm2_310alpha/mod_wheel
Breath 2 0–127 /preenfm2_310alpha/breath
Volume 7 0–127 /preenfm2_310alpha/volume
Pan 10 0–127 /preenfm2_310alpha/pan
Scala enable 12 switch /preenfm2_310alpha/scala/enable
Unison detune 13 0–127 /preenfm2_310alpha/unison/detune
Unison spread 14 0–127 /preenfm2_310alpha/unison/spread
Engine algo 16 discrete /preenfm2_310alpha/engine/algo
Hold pedal 64 switch /preenfm2_310alpha/hold_pedal
Filter type 70 discrete /preenfm2_310alpha/filter/type
Filter param1 71 0–127 /preenfm2_310alpha/filter/param1
Filter param2 72 0–127 /preenfm2_310alpha/filter/param2
Filter gain 73 0–127 /preenfm2_310alpha/filter/gain
Mpe slide 74 0–127 /preenfm2_310alpha/mpe/slide
Lfo env2 silence 59 0–127 /preenfm2_310alpha/lfo_env2/silence
Env attack carriers 80 0–127 /preenfm2_310alpha/env/attack_carriers
Env attack modulators 62 0–127 /preenfm2_310alpha/env/attack_modulators
Env release carriers 81 0–127 /preenfm2_310alpha/env/release_carriers
Env release modulators 63 0–127 /preenfm2_310alpha/env/release_modulators
Arp clock 100 discrete /preenfm2_310alpha/arp/clock
Arp direction 101 discrete /preenfm2_310alpha/arp/direction
Arp octave 102 discrete /preenfm2_310alpha/arp/octave
Arp pattern 103 discrete /preenfm2_310alpha/arp/pattern
Arp division 104 discrete /preenfm2_310alpha/arp/division
Arp duration 105 discrete /preenfm2_310alpha/arp/duration
Current instrument 119 discrete /preenfm2_310alpha/current_instrument
All sound off 120 trigger /preenfm2_310alpha/all_sound_off
All notes off 123 trigger /preenfm2_310alpha/all_notes_off
Reset 127 trigger /preenfm2_310alpha/reset
Engine im1 17 0–127 /preenfm2_310alpha/engine/im1
Engine im2 18 0–127 /preenfm2_310alpha/engine/im2
Engine im3 19 0–127 /preenfm2_310alpha/engine/im3
Engine im4 20 0–127 /preenfm2_310alpha/engine/im4
Engine im5 21 0–127 /preenfm2_310alpha/engine/im5
Mix level1 22 0–127 /preenfm2_310alpha/mix/level1
Mix level2 24 0–127 /preenfm2_310alpha/mix/level2
Mix level3 26 0–127 /preenfm2_310alpha/mix/level3
Mix level4 28 0–127 /preenfm2_310alpha/mix/level4
Mix pan1 23 0–127 /preenfm2_310alpha/mix/pan1
Mix pan2 25 0–127 /preenfm2_310alpha/mix/pan2
Mix pan3 27 0–127 /preenfm2_310alpha/mix/pan3
Mix pan4 29 0–127 /preenfm2_310alpha/mix/pan4
Osc1 freq 50 0–127 /preenfm2_310alpha/osc1/freq
Osc2 freq 51 0–127 /preenfm2_310alpha/osc2/freq
Osc3 freq 52 0–127 /preenfm2_310alpha/osc3/freq
Osc4 freq 53 0–127 /preenfm2_310alpha/osc4/freq
Osc5 freq 54 0–127 /preenfm2_310alpha/osc5/freq
Osc6 freq 55 0–127 /preenfm2_310alpha/osc6/freq
Matrix1 mul 46 0–127 /preenfm2_310alpha/matrix1/mul
Matrix2 mul 47 0–127 /preenfm2_310alpha/matrix2/mul
Matrix3 mul 48 0–127 /preenfm2_310alpha/matrix3/mul
Matrix4 mul 49 0–127 /preenfm2_310alpha/matrix4/mul
Lfo1 freq 56 0–127 /preenfm2_310alpha/lfo1/freq
Lfo2 freq 57 0–127 /preenfm2_310alpha/lfo2/freq
Lfo3 freq 58 0–127 /preenfm2_310alpha/lfo3/freq
Stepseq1 gate 60 0–127 /preenfm2_310alpha/stepseq1/gate
Stepseq2 gate 61 0–127 /preenfm2_310alpha/stepseq2/gate
Performance cc1 115 0–127 /preenfm2_310alpha/performance/cc1
Performance cc2 116 0–127 /preenfm2_310alpha/performance/cc2
Performance cc3 117 0–127 /preenfm2_310alpha/performance/cc3
Performance cc4 118 0–127 /preenfm2_310alpha/performance/cc4
Env1 attack 65 0–127 /preenfm2_310alpha/env1/attack
Env2 attack 75 0–127 /preenfm2_310alpha/env2/attack
Env3 attack 76 0–127 /preenfm2_310alpha/env3/attack
Env4 attack 77 0–127 /preenfm2_310alpha/env4/attack
Env5 attack 78 0–127 /preenfm2_310alpha/env5/attack
Env6 attack 79 0–127 /preenfm2_310alpha/env6/attack
Env1 release 82 0–127 /preenfm2_310alpha/env1/release
Env2 release 83 0–127 /preenfm2_310alpha/env2/release
Env3 release 84 0–127 /preenfm2_310alpha/env3/release
Env4 release 85 0–127 /preenfm2_310alpha/env4/release
Env5 release 86 0–127 /preenfm2_310alpha/env5/release
Env6 release 87 0–127 /preenfm2_310alpha/env6/release
Lfo1 phase 88 0–127 /preenfm2_310alpha/lfo1/phase
Lfo2 phase 89 0–127 /preenfm2_310alpha/lfo2/phase
Lfo3 phase 90 0–127 /preenfm2_310alpha/lfo3/phase
Lfo1 bias 91 0–127 /preenfm2_310alpha/lfo1/bias
Lfo2 bias 92 0–127 /preenfm2_310alpha/lfo2/bias
Lfo3 bias 93 0–127 /preenfm2_310alpha/lfo3/bias
Lfo1 shape 94 0–127 /preenfm2_310alpha/lfo1/shape
Lfo2 shape 95 0–127 /preenfm2_310alpha/lfo2/shape
Lfo3 shape 96 0–127 /preenfm2_310alpha/lfo3/shape

NRPN

Control CC NRPN (MSB/LSB) Range Name to send
Param 0 / 0–127 0–16383 /preenfm2_310alpha/nrpn/param
Param page1 1 / 0–127 0–16383 /preenfm2_310alpha/nrpn/param_page1
Stepseq1 step 2 / 0–15 0–16383 /preenfm2_310alpha/nrpn/stepseq1_step
Stepseq2 step 3 / 0–15 0–16383 /preenfm2_310alpha/nrpn/stepseq2_step
Dump request 127 / 127 trigger /preenfm2_310alpha/nrpn/dump_request

Editor protocol

Control CC NRPN (MSB/LSB) Range Name to send
Editor capability query 4 / 0 trigger /preenfm2_310alpha/editor/capability_query
Editor position query 4 / 1 trigger /preenfm2_310alpha/editor/position_query
Editor store 4 / 2 0–16383 /preenfm2_310alpha/editor/store

Performance MIDI

Notes, pitch bend and any CC are also available: /preenfm2_310alpha/note/on <note> <velocity>, /preenfm2_310alpha/cc/<number> <value>, /preenfm2_310alpha/pitchbend <0-16383>, /preenfm2_310alpha/program_change <n>.

JSON

Limitations

PreenFM2 3.10 alpha (pre-release of 2026-10-02, built on Patrice Vigouroux's VOSIM branch). Against the official 2.21: true polyphonic key pressure (send it with /poly_aftertouch; the AftT matrix routes become per note), Lower-Zone MPE (master channel 1, member channels set in the menu; per-note bend up to +/-48, slide on CC 74), and the editor protocol on NRPN page 4 (capability, position and store). Each of the 4 timbres listens on its channel set in the menu; routes default to channel 1. CCs are received when the menu's Receive setting includes CC, NRPNs when it includes NRPN. The values and their scaling are those of the decoder (shown on each route). Replies of the editor protocol and the NRPN dump come back as CCs 99/98/6/38 and are not decoded. Not mapped: CC 12/13 Scala (CC 13 is also unison detune), omni on/off, the synth parameter list behind NRPN pages 0 and 1, SysEx patch transfers. Untested on hardware.

Firmwares

The PreenFM2 runs 2 firmwares SynthHub maps, each with its own MIDI or another's it shares. All the devices with several: firmwares.

Firmware From Licence MIDI Sounds
3.10 alpha github.com/sscheidl its own
pfm2sid github.com/patrickdowling its own

Frequently asked questions

Which MIDI CC controls the filter cutoff on the PreenFM2?

CC 70 (0–127), named /preenfm2_310alpha/filter/type in SynthHub's map.

How many parameters of the PreenFM2 can be controlled over MIDI?

SynthHub's map of the PreenFM2 lists 84 MIDI CC and 8 NRPN parameters, each with its number, range and a readable name; the full chart is on this page.

Can an AI agent like Claude control the PreenFM2?

Yes: SynthHub's hosted MCP server knows the PreenFM2's MIDI map, and its browser relay lets the agent send it parameter changes or load a sound, each sound change confirmed by you.