Skip to content

Instantly share code, notes, and snippets.

@arteme
Last active December 11, 2023 14:54
Show Gist options
  • Save arteme/76f59209db3fe263c82ee151e35a1723 to your computer and use it in GitHub Desktop.
Save arteme/76f59209db3fe263c82ee151e35a1723 to your computer and use it in GitHub Desktop.

Sounddiver LIB File Format

Even in 2021 Sounddiver keeps being a tool used to collect, edit and archive MIDI patches, loading them to various devices. There is other legacy software built around programming MIDI devices -such as Line6 Edit- that use Sounddiver LIB file formats.

This is an effort to reverse-engineer the Sounddiver LIB file format with the hope of writing open-source libraries for working with these LIB files.

General Layout

Sounddiver LIB file is based on the IFF generic container file format withas a few key differences:

  • it can be big-endian or little-endian ('FORM' and 'SSLB' type-ids appears as 'MROF' and 'BLSS' in the file);
  • the chunks are not 16-bit word-aligned.
Chunk Type ID Type ID # Description
FORM group SSLB 1 The outer group chunk
LHDR data 1 Library header ???
WSEQ data 1 Library window layout (columns order, widths, parameters pane?)
LENT data * Library entry chunk

Data types

Integer. Integers can be 8-, 16- or 32-bit long. All integers longer than 8-bit are subject to the endianness of the system that created the LIB file. Both big-endian and little-endian LIB files have been observed and all long integers (IFF chunk length, LENT header date/time fields) need to be converted to native endianness.

String. Strings are encoded as Pascal strings (or UCSD strings). That is, first comes a byte specifying the legth of the string, which is followed by the actual string content.

Chunks

FORM chunk

FORM chunk is a generic container that should contain the LHDR/WSEQ/LENT data chunks. Sometimes Sounddiver 3.0.5 doesn't place LHDR/WSEQ/LENT data chunks inside the FORM chunk. Instead the FORM chunk is empty (type-id: FORM, length: 4, id: SSLB) and the data chunks follow the FORM container chunk, which goes against the IFF standard.

WSEQ chunk

Library window layout. Looks like it consists of 70 16-bit words. Content???

LENT chunk

This is the actual library entry chunk containing program/tone/etc.

The layout of the LENT chunk goes as follows:

+--------+--------------+ - - + - - - - - - - +
| Header | Data block 1 | ... | Data block N  |
+--------+--------------+ - - + - - - - - - - +

Where a 12-byte header is followed by any number of data blocks (1 or more?) of the following layout (with the exception of the "end of data" block with id=0x00):

Short block:

 0
 0 1 2 . . .  
+-+-+-+- - - - -+
|I|L|     D...  |
+-+-+-+- - - - -+

Long block:

 0
 0 1 2 . . .  
+-+-+-+- - - - -+
|I| L |   D...  |
+-+-+-+- - - - -+

Where:

Field Bits Name Description
I 8 Id Data block id
L 1/2x8 Length Data length
D Lx8 Data L bytes of data

The length of the data block is encoded in 1 or 2 bytes. When the first byte (L1) is read, if the most significant bit (MSB) is 0, then the length is 1 byte long, the value as-is (L = L1); if MSB is 1, then length is 2 bytes long, the value calculated as L = (L1 & 0x7F) << 7 + L2.

The following data blocks are known:

Block id Name Description
0 End of data This id comes last. That id=0x00 can still be followed with 1 or 2 bytes of data. *Is there any signifficane to them?
1 Entry name String. Block data length is the string length.
2 Location String. Block data length is the string length.
3 Data Data layout module-specific?
4 Uses References to other entries used by this one
5 ? ?
6 Comment String. Block data length is the string length.

NOTE: *Also observed in the wild are LENT chunks with size 2 and contents [0x00, 0x00].

Header

Layout:

 0                   1
 0 1 2 3 4 5 6 7 8 9 0 1 
+-+-+-+-+-+-+-+-+-+-+-+-+
|X| M |?|   D   |?|?|N|?|
+-+-+-+-+-+-+-+-+-+-+-+-+

Where:

Offset Field Bits Name Description
0 X 8 Entry type? 0x80 if program, 0x00 if title ???
1 M 2x8 Module/Model Two 8-bit identifiers - module & model. See appendix A.
3 ? 8 ? ?
4 D 32 Date/Time 32-bit value: (MSB to LSB) 7 bits for year-1980 (0-127), 4 bits for month (1-12), 5 bits for day (1-31), 5 bits for hour (0-23), 6 bits for minutes (0-59), 5 bits for seconds/2 (0-29). NOTE: Sounddiver takes 2 digits for year input (80-99 = 1980-1999, 00-79 = 2000-2079), but it will read 7-bit year showing dates up to 2017-12-31. If the value is outside the ranges shown in brackets SD will not show date/time.
8 ? 8 ? ?
9 ? 8 ? ?
10 N 8 Device ID 8-bit value, device id - 1. Sounddiver allows user to input 1-128, but will read 8-bit device id showing maximum device id of 256.
11 ? 8 ? ?

Uses

The uses block is a list of entries used by the current one. The list consists of 6 byte entries:

 0
 0 1 2 3 4 5  
+-+-+-+-+-+-+
| S |   E   |
+-+-+-+-+-+-+

Where:

Offset Field Bits Name Description
0 N 16 Slot The number of the slot for this entry
2 E 32 Entry The number of the LENT entry used in this slot

If an entry uses 4 other entries, it will have 4 entries in the "uses" list, where slot is a sequential number from 0 to 3 and entry is the number (entry 0 referes to the first LENT chunk in the LIB file) of the entry used there.

Appendix

A. Module table

Sounddiver crashes whenever it encounters an unknown module/model. The models which have been checked and are known to crash are marked as "~" in the table below.

Module Model Name
02 00 SY77 / SY77
02 01 SY77 / TG77
02 ? SY77 / SY99
09 00 M1 / M1
0F 00 D50 / D-50
14 00 JV / JV-80
29 00 DMPRO / DM Pro
2A 00 POD / POD
01 POD / Flextone II
02 POD / POD Pro
03 POD / POD 2.0
04 ~
2B 00 FS1R / FS1R
3B 01 BASSPOD / Bass POD
3B 02 BASSPOD / Bass POD Pro
03 ~
FF xx UNI

B. UNI module

UNI module seems to not care for that the model byte is, Sounddiver doesn't crash when it is changed. Intead, the actual model name is stored as a NUL-terminated string inside the data block of the LENT-chunk.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment