osmose-preset-loader #
Bulk-install EaganMatrix presets (e.g. from Patchstorage) into an Expressive E Osmose, instead of dragging them into the Haken Editor one at a time.
Firmware 2.x: just convert them #
One-time setup — read the preset key out of your own Osmose Updater install:
python tools/extract_key.py --save
The key is Expressive E's and is not shipped with this project. The Updater
has to decrypt presets to do its job, so it carries the key; the script finds
it, verifies it by decrypting a real preset, and caches it to key.txt
(gitignored — don't commit or publish it). Point it at the installed binary,
not the downloaded installer, which is packed. Method documented in
OSMOSE_2X_FORMAT_REFERENCE.md §12.
Then convert:
python mid2eepst.py --dir <patchstorage folder> --recursive --dedupe \
--out <snapshot>/preset/ --template <snapshot>/preset/<any factory>.eepst
Then restore that snapshot with the Osmose Updater (Advanced Mode). The presets appear in the browser under real names and play. No dragging, no Haken Editor, no touching the device.
Where to get presets worth converting #
The obvious source is Patchstorage, but temper expectations: it holds 134 entries, one author wrote 101 of them, and a large share are deliberately minimal teaching examples ("Simple Preset Series", "SimpleFilter01"). It is a tutorial archive more than a sound library.
The far better source is already on your disk if you have the Haken Editor:
<editor>/Firmware/SysPresets/{Continuum,ContinuuMini,EaganMatrixModule,EaganMatrixMicro}
<editor>/Explorations/{Eagan,Duquesne,Kram}
These are Haken's own system presets for the other EaganMatrix instruments. They
are plain .mid archives, so mid2eepst.py converts them directly. Deduplicated
against the Osmose system set, they yield ~711 presets the Osmose does not ship.
Editor-version presets load fine on an older engine. A Haken Editor 10.73
preset using s_MacroHi/s_MacroLo/s_Form_Poke/s_Mat_Poke renders correctly
on an Osmose running EaganMatrix 10.52 -- verified on hardware. Those stream ids
are absent from the Osmose factory set only because Expressive E's presets do not
use them, not because the engine lacks them; presets shipping with the 10.52
editor use them freely. Do not filter by stream vocabulary.
Two things that are genuinely not portable, and are easy to misread as version skew:
- Processing patches make no sound. Names like
Disto CabinetorBitCrushUncolour an audio input the Continuum has and the Osmose does not. Silence here is the patch, not the engine. - Same name, different patch. Haken revises presets between releases, so a
10.73
Music Box Bellslegitimately differs from the 10.52 one. A changed sound is not evidence of a failed load.
The .eepst preset format is documented in
OSMOSE_2X_FORMAT_REFERENCE.md: AES-128-CTR with
the IV in the last 16 bytes, wrapping a Protocol Buffers message whose field 13
carries the archive's MIDI stream verbatim. eepst.py reads and writes it;
mid2eepst.py converts .mid archives into it.
Because the name is plaintext inside, renaming is a string edit —
eepst.rename() on a snapshot renames as many presets as you like, offline,
instead of thumbing each one in on the encoder.
Take a snapshot before restoring. Any factory preset can be restored byte-exact
from factory_pack.zip inside the firmware package, so mistakes are cheap.
Older routes #
These predate the .eepst format being documented and are kept because they
still work and need no key.
Firmware 1.x: the Advanced Mode export is a folder of plain .mid files
plus group*.txt indexes. install fills every free slot directly in the
export, which is then re-imported. Format learned from
segfault16/osmose-usersettings.
Firmware 2.x without converting: make-groups turns a folder of .mid
presets into Haken Editor "Preset Group" folders, and each group loads 16
presets into DSP user slots with a single drag-and-drop. Note that on 2.x the
Osmose browser reads the mainboard, not DSP flash, so this gets sounds onto the
EaganMatrix but not into the preset list — see the format reference §11.
make-groups (via Haken Editor) #
python osmose_bulk.py make-groups --presets <mid-folder> --out <folder>
[--per-group 16] [--name "PS Group"] [--order-file list.txt]
Each output folder holds a group .txt (index,"file.mid" lines, CRLF —
the editor's native Preset Group format per the Continuum User Guide sec. 8.7)
plus the member .mid files. In the Haken Editor, drag the .txt onto the
user preset slot the group should start at. Loading a group overwrites the
slots it lands on — aim at empty ranges and snapshot your user data first.
install / status (firmware 1.x export) #
python osmose_bulk.py status --state <exported-state-dir>
python osmose_bulk.py install --state <exported-state-dir> --presets <mid-dir>
[--order-file list.txt] [--dry-run]
Fills slots referencing the Empty.mid placeholder, rewrites the groupN.txt
indexes byte-identically, and zips a backup of the untouched export first.
Talking to the device directly #
python osmose_probe.py names # read-only: DSP user slot names
python osmose_probe.py ask --task userToMidi # read-only ccTask requests
python osmose_flash.py load --port "MIDIOUT2 (Osmose)" --mid preset.mid
python osmose_flash.py name --port "MIDIOUT2 (Osmose)" --text "New Name"
python osmose_flash.py store --port "MIDIOUT2 (Osmose)" --slot 10
python osmose_flash.py diff <before>/preset <after>/preset --expect "New Name"
osmose_probe.py only ever asks the device for information and whitelists the
ccTask values documented as read-only, so a typo can't trigger a calibration
or reboot. osmose_flash.py is the write side.
These reach the EaganMatrix DSP (Port 2), not the Osmose preset browser. Storing works and persists, but 2.x reads its presets from the mainboard, which never looks at DSP flash. See OSMOSE_2X_FORMAT_REFERENCE.md §11.
Read the Updater log, not the dialog #
The Updater reports the same "failed to upload user presets" whether one preset was rejected or every one was. Three separate runs here looked identical in the UI: one where 848 of 849 succeeded, one where nothing was wrong at all, and one where the operation never started. The log is the only signal worth acting on.
~/AppData/Roaming/OsmoseUpdater/logs/osmoseFirmwareUpdater.log (Windows)
grep -E "process error|insert fail" osmoseFirmwareUpdater.log
| log line | meaning |
|---|---|
Success to transfer file X |
installed |
fails due to content already exists |
identical content already on the device; harmless |
fails due to insert fail |
name collision -- another preset already uses that name |
fails due to process error |
the device refused the file itself (see the oversized-expansion note below) |
Two things that read as catastrophic and are not:
- A tail that stops mid-line means the log is still being written, not that the Updater crashed. Counting successes from a truncated log undercounts them. Wait for the operation to finish before drawing conclusions.
insert failon every preset means the content is already installed -- see the non-idempotency note below. It is what a redundant retry looks like, not a broken snapshot.
Verify against the device rather than the dialog: if the presets are in the browser and play, the restore worked regardless of what the UI said.
Gotchas that cost real time #
- An archive
.midis not self-contained. It stops atarchiveToFileand carries no name, no commit and no terminator. The Haken Editor follows every archive withs_Name, thenccBankH=catEdBuf; ccBankL=0; ccStore=0, thenccTask=curGloToFlash(8). Miss theccStoreand nothing is committed — the patch evaporates within seconds. Miss theccTask=8and the DSP sits parked in Archive Retrieve, completely silent, until you change presets on the panel.stream_midsends the whole sequence now viahaken.commit_archive(). - MIDI auditioning does work once the sequence is right: the loaded patch holds indefinitely and is displaced only by selecting a preset on the panel. It overrides the sound without becoming a named preset — the panel still shows whatever was selected before.
- Clear the Osmose screen before running the Updater. While a vendor SysEx
20 01status message is displayed, snapshots silently produce an emptypreset/directory. Sendf0 00 21 26 20 02 f7first. - Don't bake names into archives.
osmose_name.pyinserts messages inside the regionarchiveEofverifies and uses the wrong sData carrier. Sends_Nameas a separate stream after the retrieve closes instead. - The device drops characters it doesn't like, silently. All 635 factory
preset names use only
space & + - 0-9 a-z— not one uppercase letter. The Osmose does not fold case, it deletes:Acoustic Bassarrives ascoustic ass.mid2eepst.sanitize_name()handles it. - User preset names must be unique, or the whole upload fails. A colliding
name is rejected with
Transfer of file <name>_<handle> fails due to insert failin the Updater log, and the operation reports "failed to upload user presets" even though most files transferred. The handle makes a preset distinct; the name must additionally not collide. This is scoped to the user insert path -- the factory collection itself ships 11 duplicate name pairs and the device accepts them.mid2eepstnow seeds its uniquing set from the output directory (existing_names), so a converted batch cannot collide with presets already in the snapshot. - Restore is additive, not a sync. It pushes what is missing and skips what is present ("content already exists"); it never deletes a preset absent from the snapshot. Repeated restores layer up. To actually replace the user bank, clear user presets on the device first (there is a clear user presets item on the Osmose itself) -- or use the Updater's overwrite all user presets mode rather than Restore User Data, which only overwrites duplicates.
- A user restore is not idempotent. Never retry a successful one. Once a user
preset named N is installed, pushing anything named N again is rejected. Re-run
a restore that already succeeded and every preset fails with
insert fail-- correctly, and the UI reports the same generic error as a real failure. If a run reports failure, read the log before retrying: the retry cannot succeed and will bury the original cause under hundreds of spurious rejections. - Some expansion presets can only be installed by Push Factory Collection.
The eleven
va *(virtual analog) presets decrypt to ~7.7-8.1 KB against a median of 2.7 KB, and pushing one through Restore User Data fails withprocess error. They arrive via Push Osmose Factory Collection instead. If a snapshot restore fails on exactly one oversizedexpansion 01preset, drop it frompreset/and re-push the factory collection afterwards. restore-user-datakeys on the handle inside the file, not the filename. A byte-copy under a new filename is deduplicated and never appears. Mint a fresh handle (eepst.new_handle()) to add a genuinely new preset.
Notes #
- Filenames become on-device preset names: lowercased and filtered to the
device's character set, hyphens/underscores to spaces, duplicates get numeric
suffixes,
Empty.midis reserved. - Source files are validated as MIDI (
MThdheader). - Python 3 standard library, plus
midofor.midparsing andcryptographyfor AES.tools/pe_xref.pyandtools/extract_key.pyalso needcapstone. - Preset
.midfiles are recordings of the editor-to-device MIDI stream, and a.eepstpayload turns out to carry that same stream verbatim in protobuf field 13 — which is why conversion is a transcode rather than a synthesis.
If you fork or republish this #
The .eepst key is Expressive E's. This project ships the method for reading
it out of your own Updater, never the key itself. Keep it that way: key.txt is
gitignored, and if you rewrite history or export this repo, check that no
earlier commit or scratch file carries the literal value.
Disclaimer #
Reverse-engineered formats; back up your user data (Osmose Updater Advanced Mode) before bulk operations. Use at your own risk.
- Python 100%