Magic Pockets Music Format
| Format type | Music |
|---|---|
| Notation type | MIDI |
| Instruments | OPL / Roland, depending on bank |
| Max channel count | Unknown |
| Max track count | 1 |
| Max pattern count | 0 |
| Max order count | 0 |
| Tags? | None |
| Games |
Music and many sound effects in Magic Pockets are MIDI sequences inside .pin cue banks. Decompress the RNC method 1 wrapper first. Some cues have a second compression layer: a dictionary of two-byte words.
| File | Entries | Plain MIDI | Dictionary MIDI | Decompressed bytes |
|---|---|---|---|---|
| adlib.pin | 82 | 78 | 4: IDs 11, 52, 59, 69 | 20655 |
| adlib2.pin | 1 | 0 | 1: ID 0 | 10328 |
| adlib3.pin | 1 | 0 | 1: ID 0 | 10328 |
| roland.pin | 82 | 81 | 1: ID 19 | 8028 |
| roland2.pin | 1 | 1 | 0 | 17201 |
| soundbnk.pin | 1 | 1 | 0 | 17320 |
All 168 sequences in this collection have format-0, one-track MIDI headers after the dictionary entries are expanded. This is a property of the checked files, not a restriction that can replace parsing the MIDI header. The basic viewer/extractor exposes only the 161 plain entries; the newer RE checks and original-driver playback also recognise compressed entries.
The name soundbnk.pin does not establish that all of its contents are MIDI: data follows the short sequence and remains unclassified. Likewise, the program and screen that use adlib2.pin and adlib3.pin are not established; the GAMEU loader does not select them.
File format
Container
| Data type | Name | Description |
|---|---|---|
| UINT16LE | count | Number of cue entries |
| UINT32LE[count] | offsets | Offsets from the start of the decompressed bank |
| UINT16LE | pad | 0x0080 in the checked files |
| BYTE[] | data | Cue data and any additional payload |
The table index is the zero-based cue ID. Entries have a fixed four-byte stride; missing or compressed entries must not be removed from the numbering. The verified AdLib driver reads the complete 32-bit offset. The older RE notes' offset/flags/tempo interpretation applies to a different backend path and should not replace this layout.
The first cue is at byte 332 for an 82-entry bank and byte 8 for the ordinary single-entry banks. soundbnk.pin has an additional UINT32LE at byte 8, with value 61; its MIDI begins at byte 12. The 49-byte MIDI ends at byte 61, followed by 17259 bytes whose interpretation is unknown. The extra word's wider purpose is not established.
Offsets provide a containing interval up to the next entry or EOF, but the actual SMF ends at its declared track-chunk boundary. Do not export trailing bank data as part of a MIDI sequence.
Entries
Plain entries begin with MThd and contain normal big-endian MIDI chunk lengths, division values and variable-length event deltas. AdLib cues use 420 ticks per quarter note; the checked Roland bank uses divisions 96 and 192, roland2.pin uses 96, and soundbnk.pin uses 192.
AdLib source tracks omit the End-of-Track meta event. The original sequencer stops at the declared track length. For standalone export, append a zero-delta FF 2F 00 event to a track that lacks it and update that track's chunk length.
AdLib instrument events
The AdLib sequencer reads a proprietary sequencer-specific meta event:
FF 7F <variable-length payload length> 00 00 3F <type: UINT16BE> <argument> ...
Type 1 defines an OPL2 voice: the argument is a voice number followed by 28 timbre bytes, making a 34-byte payload. Types 2 and 3 are single-argument driver commands. Program-change messages alone do not describe these instruments. A generic MIDI synthesizer can play the notes while producing different timbres from the original AdLib driver.
Compressed entries
| Data type | Name | Description |
|---|---|---|
| UINT8 | tag | ASCII C (0x43) or c (0x63) |
| UINT16LE[256] | dictionary | 256 pairs of output bytes |
| UINT8[] | codes | One dictionary index per output pair |
For each code n, append the low then high byte of dictionary[n]. With tag c, discard the first output byte; with C, keep it. Dictionary indices start at offset 0x201 relative to the tagged cue.
The expanded result starts with MThd. Its chunk lengths determine the meaningful output extent; there is no separate decoded-length field in this dictionary wrapper. AdLib IDs 11, 52 and 59 use c, ID 69 uses C; Roland ID 19 uses C and the two single-cue AdLib song banks use c.
These compressed cues were once labelled possible hardware-reset streams in the older notes. That classification is superseded by dictionary expansion and the original-driver analysis.
Source code
From re-magicpockets, the open-source browser port and reverse-engineering project:
- web/core/pin-sound.js – plain-MIDI bank decoder and End-of-Track repair
- web/core/midi.js – MIDI event parser
- tools/extract-pin.js – legacy MIDI exporter
- web/verify/checks.js – dictionary expansion in decodeCue and original-driver checks
- web/audio/pin-driver.js – original driver command interface
- docs/formats/pin-sound.md – newer AdLib and dictionary findings
- docs/formats/pin.md – bank layout and historical hypotheses
Credits
This file format was reverse engineered by VorticonCmdr. Please credit this work in projects that use it; a link back to this wiki is appreciated.