Read and write Elektron SidStation patch (.syx) SysEx files
Project description
pysidstation
Read and write Elektron SidStation patch (.syx) SysEx files in pure
Python — no dependencies.
The SidStation is a synthesizer built around the MOS 6581/8580 "SID" chip from
the Commodore 64. Its patches are exchanged as MIDI System Exclusive dumps.
pysidstation parses those dumps into editable Patch objects and writes them
back byte-for-byte.
The complete, corrected file format is documented in
docs/FORMAT.md.
Install
pip install pysidstation
Requires Python 3.10+.
Quick start
import sidstation
bank = sidstation.read("SidStation_Presets_r1.syx")
print(len(bank), "patches") # 90 patches
for patch in bank:
print(patch.name) # Anpanman, Krutong, Floating-7, ...
# Edit a patch
lead = bank[0]
lead.name = "My Lead"
lead.poly = True
lead.filter_cutoff = 90
lead.oscillators[0].waveform = sidstation.Waveform.SAW
lead.oscillators[0].ring_mod = True
lead.lfos[0].lfo_type = sidstation.LfoType.RAMP
bank.write("edited.syx")
An unmodified file round-trips exactly:
data = open("SidStation_Presets_r1.syx", "rb").read()
assert sidstation.loads(data).to_bytes() == data
Building a bank from scratch
from sidstation import Bank, Patch, Waveform
p = Patch(name="Init")
p.osc1_enabled = True
p.oscillators[0].waveform = Waveform.PULSE
p.oscillators[0].attack = 2
p.oscillators[0].sustain = 12
bank = Bank.from_patches([p]) # prepends the all-clear message by default
bank.write("init.syx")
What you can read and write
Each Patch exposes the full parameter set as plain attributes that read and
write the underlying patch bytes directly:
- Name —
patch.name(andpatch.name_bytesfor the raw 10 bytes) - Mode —
osc1_enabled,osc2_enabled,osc3_enabled,poly,legato,filter_wrap,filter_env_invert - Filter —
filter_routing,filter_osc1/2/3,resonance,filter_type,filter_lfo,filter_cutoff,filter_env_attack/decay/sustain/release,filter_env_depth,filter_lfo_depth,filter_lfo_wheel_depth - Per-patch sync —
sync_speed,sync_hcut - Oscillators —
patch.oscillators[0..2]withwaveform,ring_mod,sync,test,sync_pwm,gate,track,arp_speed,transpose,detune,pitchbend_range,attack,decay,sustain,release,delay,pwm_start,pwm_add,pwm_lfo,pwm_lfo_depth,portamento,vibrato_lfo,vibrato_depth,vibrato_wheel_depth,table_speed, plus decode helperstranspose_semitones,detune_value,detune_cents - LFOs —
patch.lfos[0..3]withlfo_type,ctrl_source,ctrl_dest,sync,invert,above_zero,sync_note_off,speed,sample_hold,depth,add_lfo,lace,lace_with,add_depth,ctrl_value,fade_in - Direct controllers —
patch.direct_controllers[0..3]withvalue,limit_down,limit_up - Tables —
patch.tables(threeTables ofTableSteps) andpatch.replace_tables(...)
Need the raw bytes? patch.data is the mutable, decoded bytearray that backs
every attribute above, indexed exactly as in docs/FORMAT.md.
Command line
sidstation info SidStation_Presets_r1.syx # summary table
sidstation names SidStation_Presets_r1.syx # one name per line
sidstation show SidStation_Presets_r1.syx 0 # detail for patch 0
(Equivalently python -m sidstation ....)
A couple of things the manual gets wrong
pysidstation is built from the owner's manual and verified against a real
bank. A few corrections matter in practice:
- Every stored parameter byte is nibble-swapped relative to the synth's
working value. The library undoes this on load (and re-applies on save), so
patch.dataand every attribute hold the synth's true values while files still round-trip byte-for-byte. This single fact is why the manual's waveform, LFO-type and detune layouts looked off — once un-swapped they line up. (e.g. the waveform is really in the OSC_WAVE high nibble, SID-control style.) - LFO type 5 is "Flat", not 7, and detune spans ≈ ±1 semitone, not ±½ — both corrections to the manual's tables.
- The size field in each patch header is unreliable (54 of 90 patches in the reference bank disagree with it). The library parses by message boundary and preserves the stored value so files still round-trip exactly.
All are explained in docs/FORMAT.md.
Development
pip install -e ".[dev,lint]"
pytest
ruff check .
ruff format --check .
The test suite uses Elektron's factory preset bank as a fixture. That file is
Elektron's copyrighted content and is not committed here — tests/conftest.py
downloads it on demand from Elektron's official SidStation Sound Pack
archive, verifies its
SHA-256, and caches it locally. To run offline, point SIDSTATION_PRESETS at a
local copy; if it can't be obtained, the dependent tests are skipped.
All tests run in CI (GitHub Actions) across Python 3.10–3.13, and the
distribution is built and checked there too. The lint job uses the pinned
ruff from the lint extra, which Dependabot keeps current.
License
Apache-2.0. See LICENSE.
SidStation and Elektron are trademarks of Elektron Music Machines. This is an independent, unofficial library and is not affiliated with or endorsed by Elektron.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pysidstation-0.2.0.tar.gz.
File metadata
- Download URL: pysidstation-0.2.0.tar.gz
- Upload date:
- Size: 35.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a96fb38e842ff54fa535b2ca0d6cf4cf42346b1f8fc2c26402160ed1db4150a6
|
|
| MD5 |
23473165bc0f6750ea72b3c163ae5d31
|
|
| BLAKE2b-256 |
7a872b10bbe9835e3d8ce3c718f5a90210ae81c25906bb5450d9c8f26bf70ae0
|
Provenance
The following attestation bundles were made for pysidstation-0.2.0.tar.gz:
Publisher:
publish.yml on anarkiwi/pysidstation
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pysidstation-0.2.0.tar.gz -
Subject digest:
a96fb38e842ff54fa535b2ca0d6cf4cf42346b1f8fc2c26402160ed1db4150a6 - Sigstore transparency entry: 1868004403
- Sigstore integration time:
-
Permalink:
anarkiwi/pysidstation@b4759b0e03d325378d4ae779f9ff5a4d6ba8e12f -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/anarkiwi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b4759b0e03d325378d4ae779f9ff5a4d6ba8e12f -
Trigger Event:
release
-
Statement type:
File details
Details for the file pysidstation-0.2.0-py3-none-any.whl.
File metadata
- Download URL: pysidstation-0.2.0-py3-none-any.whl
- Upload date:
- Size: 23.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a85f07928ed8251423614018c833c0b540b7394a25aa519de7909c1399323d2c
|
|
| MD5 |
c56ca8329aa4c09bfa2b2ea9a0c7e0d5
|
|
| BLAKE2b-256 |
bb2131f4fb3ee6624832070b19a05af8067f9a2b6650874712a74cec353e1df3
|
Provenance
The following attestation bundles were made for pysidstation-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on anarkiwi/pysidstation
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pysidstation-0.2.0-py3-none-any.whl -
Subject digest:
a85f07928ed8251423614018c833c0b540b7394a25aa519de7909c1399323d2c - Sigstore transparency entry: 1868004429
- Sigstore integration time:
-
Permalink:
anarkiwi/pysidstation@b4759b0e03d325378d4ae779f9ff5a4d6ba8e12f -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/anarkiwi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b4759b0e03d325378d4ae779f9ff5a4d6ba8e12f -
Trigger Event:
release
-
Statement type: