Python code for reading, writing, and exporting Logic Pro Sampler / EXS24 (.exs) instrument files.
exsfile.py— read/write.exsinstruments (read_exsfile,write_exsfile). The writer can round-trip a parsed instrument byte-for-byte by passing the original block data through.exsclasses.py— the instrument / zone / group / sample dataclasses and their (de)serialization.exsparams.py,sampler_param_table.py— the Sampler parameter set: ids, names, ranges, defaults.consolidate.py— replicate Logic's Save with Audio → Consolidated (a single monolithic.cafholding every sample, with the instrument's zones re-pointed at frame offsets). LPCM, ALAC, or AAC.set_polyphony.py— set an instrument's polyphony (max voices), including values above the UI cap.samplesearch.py,samplepackmenu.py,akais9xx.py— sample relinking, packing, and Akai import helpers.
Polyphony is parameter id 5, a plain per-instrument voice count. The Sampler UI only lets you pick
values up to its dropdown maximum (≈99), but a larger stored value is accepted as-is — this is how
Logic's Studio Piano instruments ship at 256. set_polyphony.py writes the value with a 2-byte
overlay, leaving the rest of the file byte-identical:
python3 set_polyphony.py "Grand Piano.exs" 256
# -> writes "Grand Piano (256 voices).exs" next to the sourceThe field is a 16-bit integer (max 32767); 256 matches Logic's own Studio Piano.
The instrument's polyphony value is only a per-instrument voice budget. Sampler also has an internal
voice pool that is the real ceiling on simultaneous voices, and by default it tracks the same ≈99–100.
So raising an instrument's polyphony alone is not enough — past ≈100 voices you also have to enlarge
the pool, which Logic governs with a hidden preference, EXSVoiceLimit:
# quit Logic first; the value is read once when the first Sampler loads in a session
defaults write com.apple.logic10 EXSVoiceLimit -int 999EXSVoiceLimit ranges 16–999 (values outside that are clamped; absent ≈ 99). With it raised, a
patched high-polyphony instrument can play well past 100 voices; without it, you stay near ≈100
regardless of the value you patch in. Either way the practical limit is your CPU.
python3 consolidate.py "Instrument.exs" ./out_dir --codec lpcm # lpcm (default) | alac | aaclpcm matches Logic's interactive "Save with Audio → Consolidated" byte layout; alac is
lossless (frame-exact, 0 priming); aac is lossy but stays frame-accurate because CoreAudio
trims the encoder priming via the CAF pakt chunk.
# true VBR at quality 64 -- what Logic's "VBR 64" consolidation produces
python3 consolidate.py "Instrument.exs" ./out --codec aac --aac-mode vbr --aac-quality 64
# constant / average / constrained-variable, driven by a total bitrate
python3 consolidate.py "Instrument.exs" ./out --codec aac --aac-mode cbr --aac-bitrate 256000
python3 consolidate.py "Instrument.exs" ./out --codec aac --aac-mode abr --aac-bitrate 256000
python3 consolidate.py "Instrument.exs" ./out --codec aac --aac-mode vbr_constrained --aac-bitrate 256000--aac-mode—cbr,abr,vbr_constrained, orvbr. Omit it for afconvert's own default (ABR ≈128 kbit/s on stereo).--aac-bitrate— bits/sec total across channels (256000 ≈ 128k per channel on stereo). Used bycbr/abr/vbr_constrained.--aac-quality— 0–127, only for--aac-mode vbr(default 64).
Safety: at too low a bitrate or quality, CoreAudio silently resamples (e.g. 44100 → 32000 Hz),
which would invalidate every zone's frame offset. That is detected after encoding and refused
with an explanatory error rather than written out, so a consolidated instrument can never be
silently corrupted — raise the bitrate/quality, or use alac/lpcm.