guide
How Octatrack .ot slice files actually work
The 832-byte sidecar, field by field — decoded byte-by-byte from real files written by two different tools.
The Elektron Octatrack will happily play a WAV with nothing beside it. Drop one on the CF card, set the machine to Slice mode, tell it "64", and it divides the file into 64 equal parts. That works, and for a lot of chains it is all you need.
The .ot file is what you add when equal parts are not good enough — when you want the
machine to jump to the exact frame each hit begins on and stop where the audio actually
ends. It is a small, fixed, slightly strange binary file, and almost nothing is written
down about it. Here is the whole thing.
What an .ot is
An attribute file. It sits next to Chain.wav as Chain.ot, same folder, same base
name, and the Octatrack picks it up automatically when it loads the sample. It contains
no audio. It holds the sample's tempo, its trim points, its loop settings, and up to 64
slice points.
Delete it and the WAV still loads. Rename the WAV without renaming the .ot and the
attributes are silently lost — that is the single most common way people lose their
slices.
The layout
Fixed 832 bytes. Everything multi-byte is big-endian, which is the single easiest thing to get wrong: this is a format from the RIFF era, where little-endian is the norm, and a byte-swapped tempo field produces a file the machine accepts and then behaves bizarrely with.
| Offset | Size | Field | Notes |
|---|---|---|---|
0x00 | 16 | magic | "FORM", four zero bytes, then "DPS1SMPA" |
0x10 | 7 | version / unknown | Copy it verbatim. See below. |
0x17 | 4 | tempo | BPM × 24. 120 BPM is 2880. |
0x1B | 4 | trim length | bars × 100. 4 bars is 400. |
0x1F | 4 | loop length | bars × 100, same scaling |
0x23 | 4 | stretch | 0 off · 2 normal · 3 beat |
0x27 | 4 | loop | 0 off · 1 on · 2 ping-pong |
0x2B | 2 | gain | 0–96, where 48 is 0 dB |
0x2D | 1 | quantize | 0xFF = direct / pattern length |
0x2E | 4 | trim start | frames |
0x32 | 4 | trim end | frames — normally the WAV's exact frame count |
0x36 | 4 | loop point | frames |
0x3A | 768 | slices | 64 × { start u32, end u32, loopPoint u32 } |
0x33A | 4 | slice count | how many of the 64 are real |
0x33E | 2 | checksum | see below |
The three scalings that trip people up
- Tempo is multiplied by 24. Not by 100, not stored as a float. A chain at 120 BPM
writes
2880. - Lengths are in bars × 100, but trim points are in frames. Two different units in
adjacent fields.
trim_lenof12800means 128 bars;trim_endof11289600means frame 11,289,600. - Gain is not dB. It is a 0–96 scale with unity at 48. Writing
0there is silence, not "no change".
The slice table
768 bytes, always — 64 slots whether you use them or not. Each slot is three
big-endian u32s: the first frame of the slice, the last frame, and a loop point.
Unused slots are zeroes. For a chain of one-shots the loop point is 0xFFFFFFFF in
every slice; both reference files written by two unrelated tools agree on that.
slice_count at 0x33A is what the machine reads to know how many trigs to lay out.
A mismatch between it and the populated slots is the other common corruption.
The checksum
A 16-bit sum of every byte from 0x10 to 0x33E — that is, everything after the
magic and before the checksum field itself — masked to 0xFFFF. No CRC, no polynomial.
Just add the bytes.
checksum = sum(bytes[0x10 .. 0x33E]) & 0xFFFF
Get it wrong and the Octatrack ignores the file rather than telling you.
The seven bytes at 0x10
Meaning unknown. Two files written by two different tools agree on all seven except one vendor flag byte. The honest answer is to copy the value real files use and move on; it does not appear to affect playback.
How this was worked out
Not from memory and not from another blog post. Two real .ot files, written by two
different tools, decoded byte by byte and then reproduced:
HH1-64-120.ot— 64 slices at 120 BPM. Tempo2880= 120 × 24.trim_end11,289,600, exactly the WAV's frame count.trim_len12800= 128 bars × 100.SAWMinorChain.ot— 15 slices at 120 BPM.trim_end352,800, which is 8 seconds at 44.1 kHz.trim_len400= 4 bars.
The test that matters is not "does it load" but byte-identical round-tripping: feed a
reference file's own parameters back into your writer and diff the output against the
original. Both files above reproduce byte for byte apart from that one vendor flag at
0x16 and its knock-on effect on the checksum. If your writer cannot do that, it has a
bug you have not found yet — a file can load fine and still have a wrong field.
Writing one, in practice
- Work out your slice points in frames, from the audio, before you think about anything else.
trim_endis the WAV's frame count. Not its byte length, not its duration.- If the chain is one-shots, leave stretch off. Timestretch is right for a musical loop and wrong for a row of drum hits.
- Never normalise the chain up to fit. If it clips, limit it down — lifting quiet samples rewrites the balance you chose when you picked them.
- Write the checksum last, obviously, and over the right range.
And the thing the .ot does not fix
A .ot makes playback sample-accurate. It does not make a badly built chain good. If the
hits inside your WAV are of wildly different lengths, anyone who loads the chain without
the .ot — or who reslices it on the machine — gets a grid that lands in the middle of
sounds. The fix is in how the WAV itself is laid out, which is
its own guide.
WeaveTone builds both halves in one step: a padded chain WAV and a real .ot with the
exact, unpadded slice points. See what it does or
get the macOS build.