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.

OffsetSizeFieldNotes
0x0016magic"FORM", four zero bytes, then "DPS1SMPA"
0x107version / unknownCopy it verbatim. See below.
0x174tempoBPM × 24. 120 BPM is 2880.
0x1B4trim lengthbars × 100. 4 bars is 400.
0x1F4loop lengthbars × 100, same scaling
0x234stretch0 off · 2 normal · 3 beat
0x274loop0 off · 1 on · 2 ping-pong
0x2B2gain0–96, where 48 is 0 dB
0x2D1quantize0xFF = direct / pattern length
0x2E4trim startframes
0x324trim endframes — normally the WAV's exact frame count
0x364loop pointframes
0x3A768slices64 × { start u32, end u32, loopPoint u32 }
0x33A4slice counthow many of the 64 are real
0x33E2checksumsee below

The three scalings that trip people up

  1. Tempo is multiplied by 24. Not by 100, not stored as a float. A chain at 120 BPM writes 2880.
  2. Lengths are in bars × 100, but trim points are in frames. Two different units in adjacent fields. trim_len of 12800 means 128 bars; trim_end of 11289600 means frame 11,289,600.
  3. Gain is not dB. It is a 0–96 scale with unity at 48. Writing 0 there 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. Tempo 2880 = 120 × 24. trim_end 11,289,600, exactly the WAV's frame count. trim_len 12800 = 128 bars × 100.
  • SAWMinorChain.ot — 15 slices at 120 BPM. trim_end 352,800, which is 8 seconds at 44.1 kHz. trim_len 400 = 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_end is 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.

← All guides