ACIDCAT . FILE FORMAT REFERENCE

S3P Anatomy

Akai S1000 / S3000program dump . SysEx
rev 2026.09
magic PSYSSS30
endian big + little
container MIDI SysEx
samples by name only

An .s3p is an Akai S1000 or S3000 program. It is not a file layout: it is a recording of a conversation. The sampler had no program file format, only a MIDI System Exclusive dump, so the program was captured message by message and each message written to disk with its length in front of it. Everything strange about the format follows from that.

a file wrapped around a MIDI transcript

Two layers, written by two different things. The outer layer is a file: a magic, a count, then a length in front of each message, all big-endian. The inner layer is MIDI, and the multi-byte values inside it are little-endian, because that is the byte order of the processor inside the sampler. A reader that picks one endianness for the whole file gets one of the two layers wrong.

the container header, and the first length

Twelve bytes of header, then the first message with its length in front. There is no index and no total size: the messages are walked, not looked up.

▸the messageF0 47 . 48 . F7

Every message is a complete MIDI System Exclusive frame, exactly as it came down the cable.

F0exclusive message start
47Akai's manufacturer id
ccexclusive channel
fffunction: 07 = program common, 09 = keygroup
48the S1000 model byte
F7end of exclusive, always the last byte

A program is one function-07 message followed by one function-09 message per keygroup, in that order. The selector bytes between the model byte and the payload say which program and which keygroup, which is what a sampler needs and a file does not.

▸the nibble split2 bytes on the wire = 1 byte of data

A System Exclusive message may not contain a byte with bit 7 set, because that is how MIDI marks the start of a new message. So a data byte cannot travel as itself. Each one is sent as two bytes, low nibble first:

on the wire06 09
low nibble06
high nibble09
the data byte0x96 = 150

This is the format's one real trap. A reader that skips the step does not crash and does not read zeros: it reads a stream of small numbers that look like plausible parameters, and names that decode to strings of the digit zero. The failure is quiet, which is the worst kind.

A block is 192 bytes once rejoined and the sampler fills the first 150; the rest is padding on the wire.

▸the program common block150 bytes

One per program. It opens with 01, the block identifier, and carries what applies to the whole program rather than to one key range.

0PRIDENT, 1 = program common block
1-2KGRP1@, first keygroup address
3-14PRNAME, 12 characters
15-18program number, MIDI channel, polyphony, priority
19-20play range low and high
22-28output, level, pan, loudness and its modulators
29-38pan LFO and the main LFO
42GROUPS, how many keygroups the program has

GROUPS is the honest check on the whole format. It sits inside a block, and the number of keygroup messages is a property of the container around it. The two are written by different parts of the sampler and have no reason to agree unless the block layout is being read correctly.

▸a keygroup, and its four zones150 bytes

One per key range. It opens with 02 and holds the key span, the filter, two envelopes, and then four velocity zones.

0KGIDENT, 2 = keygroup block
3-4key range low and high, 24-127 = C0 to G8
7-11filter frequency and its modulators
12-19amplitude envelope: attack, decay, sustain, release
20-27filter envelope, same four
34, 58, 82, 106velocity zones 1 to 4, 24 bytes each

A zone opens with a 12-character sample name and then its velocity range and offsets. The name is all there is: the sample data lives elsewhere entirely, so a program without its bank is a set of instructions referring to things that are not there. An unused zone is a name of twelve spaces.

+0SNAME, 12 characters
+12, +13velocity range low and high
+16, +17, +18loudness, filter and pan offsets
+19what to do with the sample's own loop

The commonest use of two zones is not velocity layering at all. It is stereo: one zone panned hard left and one hard right, over the same velocity range, naming the two halves of a stereo sample.

▸names are not ASCII41 characters

The sampler has its own character set, and it is not a superset of anything. There are forty-one characters and no lower case.

0 - 9the digits 0 to 9
10space
11 - 36A to Z
37 - 40# + - .

Read as ASCII the codes are control characters, so a name comes out as invisible junk rather than as wrong text. Read correctly, code 11 is A: the set is an index, not an encoding.

▸the pointers that are not offsetsKGRP1@, NXTKG@, SBADD

Three fields look like they point at something and none of them point at anything in the file. KGRP1@, NXTKG@ and SBADD are addresses in the sampler's own memory, captured along with everything else because the dump is a memory dump.

KGRP1@ reads as 150 in ordinary files, which is exactly the block size and looks convincingly like an offset to the next block. It is not. Following it lands on nothing, and the only correct use of these fields is to notice they are there.

▸byte orderboth

The container's lengths and counts are big-endian. The words inside a block, once the nibbles are rejoined, are little-endian. The two layers were written by different machines and neither was asked to agree with the other.