-
Notifications
You must be signed in to change notification settings - Fork 0
File Format: MUS and SAM
.mus
/.sam
files are a proprietary format developed by Crystal Dynamics. It stores sequences, custom attributes, etc.. It is similar in concept to Sony's seq
, vh
, vb
, and vab
files developed for the PlayStation, and MIDI files with their respective SoundFonts or DownLoadable Sounds (.mid
/.sf2
/.dls
). It was used in Crystal Dynamics game that were developed from 2000 to 2007.
Names can be up to 20 ASCII characters. If not all 20 are used then the name terminates when non-printable or junk ASCII characters are found. It is also possible that the name could be padded with spaces.
There are currently three known versions of the mus
header, 1.8 and 1.14 used in early 2000s Crystal Dynamics games while 1.20 is used in later games.
The magic number should be "Mus!".
Name | Type | Endianness |
---|---|---|
Magic number | ASCII character x4 | N/A |
Header size | Unsigned 32 bit integer | Little |
Bank version | Unsigned 32 bit integer | Little |
Reverb volume | Signed 32 bit integer | Little |
Reverb type | Signed 32 bit integer | Little |
Reverb multiply | Signed 32 bit integer | Little |
Number of sequences | Unsigned 32 bit integer | Little |
Number of labels | Unsigned 32 bit integer | Little |
Label offsets table start | Unsigned 32 bit integer | Little |
Number of waves | Unsigned 32 bit integer | Little |
Number of programs | Unsigned 32 bit integer | Little |
Number of presets | Unsigned 32 bit integer | Little |
Name | Type | Endianness |
---|---|---|
Magic number | ASCII character x4 | N/A |
Header size | Unsigned 32 bit integer | Little |
Bank version | Unsigned 32 bit integer | Little |
Reverb volume | Signed 32 bit integer | Little |
Reverb type | Signed 32 bit integer | Little |
Reverb multiply | Signed 32 bit integer | Little |
Number of sequences | Unsigned 32 bit integer | Little |
Number of streams | Unsigned 32 bit integer | Little |
Stream BPM | Unsigned 32 bit integer | Little |
Stream Info Offset | Unsigned 32 bit integer | Little |
Number of labels | Unsigned 32 bit integer | Little |
Label offsets table start | Unsigned 32 bit integer | Little |
Number of waves | Unsigned 32 bit integer | Little |
Number of programs | Unsigned 32 bit integer | Little |
Number of presets | Unsigned 32 bit integer | Little |
The number of sequences is specified in the header
Name | Type | Endianness |
---|---|---|
Sequence number | Unsigned 32 bit integer | Little |
Sequence offset | Unsigned 32 bit integer | Little |
The header specifies the number of programs.
Name | Type | Endianness |
---|---|---|
Program Offset | Unsigned 32 bit integer | Little |
The header specifies the number of presets.
Name | Type | Endianness |
---|---|---|
Preset Offset | Unsigned 32 bit integer | Little |
There are as many waves as specified in the header. The raw data is stored in a headerless sam
file of the same name.
Wave size counts in 16-bit words, so to get the actual size in bytes, it needs to be multiplied by 2.
Wave loop start and Wave loop end refer to the 16-bit sample units when a wave is decoded into PCM.
Wave loop info can be one of the following values:
- No loop
- Loop
- Exit loop region after key is released
Wave fine tuning specifies both the note in which the sample is tuned to and the fine tuning at the same time. The note it's tuned to is integer part of the number divided by 256. Since the fine tuning uses a scale based on 256, we need to scale it down to 100 due to it usually being specified in cents. We lose accuracy doing this, but it is needed for compatibility. The equation is
(100 * (wave_finetuning % 256)) / 256
The use for Wave SFX handle is not well documented.
Name | Type | Endianness |
---|---|---|
Wave name | Name | N/A |
Wave offset | Unsigned 32 bit integer | Little |
Wave loop start | Unsigned 32 bit integer | Little |
Wave size | Unsigned 32 bit integer | Little |
Wave loop end | Unsigned 32 bit integer | Little |
Wave sample rate | Unsigned 32 bit integer | Little |
Wave fine tuning | Signed 32 bit integer | Little |
Wave loop info | Unsigned 32 bit integer | Little |
Wave SFX handle | Signed 32 bit integer | Little |
There are as many programs as specified in the header. Inside each entry is a certain number of zones.
Name | Type | Endianness |
---|---|---|
Program name | Name | N/A |
Number of program zones | Unsigned 32 bit integer | Little |
Program zone | Program zone array | N/A |
There are as many program zones as specified in the program entry.
Program zone fine tuning follows the same logic as the variable Wave fine tuning found in the Wave entry structure.
Panning can continuously range from 0 (left) to 1 (right), with 0.5 being the center. To convert the Volume envelope attenuation value into units of decibels, you need to divide the value by 2.5.
If Program zone root key is -1, then it means there will be no root key applied to the zone. Otherwise it gets applied and overrides the note from the original Wave.
Program zone key high must always be greater or equal to Program zone key low. Same applies for the program zone velocity.
Rather than having a resolution of 100 steps between notes (as in cents), the following entries have 256 steps between notes. To convert to cents, the steps must be scaled to fit.
- Keynum hold
- Keynum decay
- Modulation envelope to pitch
- Vibrato to pitch
"Program zone velocity low/high" are present, however they are not used.
Name | Type | Endianness |
---|---|---|
Program zone fine tuning | Signed 32 bit integer | Little |
Program zone reverb | Signed 32 bit integer | Little |
Panning | 32 bit float | Little |
Keynum hold | Unsigned 32 bit integer | Little |
Keynum decay | Unsigned 32 bit integer | Little |
Volume envelope | Envelope | N/A |
Volume envelope attenuation | 32 bit float | Little |
Vibrato delay | 32 bit float | Little |
Vibrato frequency | 32 bit float | Little |
Vibrato to pitch | 32 bit float | Little |
Program zone root key | Signed 32 bit integer | Little |
Program zone key low | Unsigned 8 bit integer | N/A |
Program zone key high | Unsigned 8 bit integer | N/A |
Program zone velocity low | Unsigned 8 bit integer | N/A |
Program zone velocity high | Unsigned 8 bit integer | N/A |
Wave index | Unsigned 32 bit integer | Little |
Name | Type | Endianness |
---|---|---|
Program zone fine tuning | Signed 32 bit integer | Little |
Program zone reverb | Signed 32 bit integer | Little |
Panning | 32 bit float | Little |
Keynum hold | Unsigned 32 bit integer | Little |
Keynum decay | Unsigned 32 bit integer | Little |
Volume envelope | Envelope | N/A |
Volume envelope attenuation | 32 bit float | Little |
Vibrato delay | 32 bit float | Little |
Vibrato frequency | 32 bit float | Little |
Vibrato to pitch | 32 bit float | Little |
Program zone root key | Signed 32 bit integer | Little |
Program zone key low | Unsigned 8 bit integer | N/A |
Program zone key high | Unsigned 8 bit integer | N/A |
Program zone velocity low | Unsigned 8 bit integer | N/A |
Program zone velocity high | Unsigned 8 bit integer | N/A |
Wave index | Unsigned 32 bit integer | Little |
Base priority | 32 bit float | Little |
Modulation envelope | Envelope | N/A |
Modulation envelope to pitch | 32 bit float | Little |
All variables indicate seconds, except for sustain which indicates decibels in a volume envelope, and a percentage in a modulation envelope.
Name | Type | Endianness |
---|---|---|
Delay | 32 bit float | Little |
Attack | 32 bit float | Little |
Hold | 32 bit float | Little |
Decay | 32 bit float | Little |
Sustain | 32 bit float | Little |
Release | 32 bit float | Little |
There are as many presets as specified in the header.
Name | Type | Endianness |
---|---|---|
Preset name | Name | N/A |
MIDI bank number | Unsigned 32 bit integer | Little |
MIDI preset number | Unsigned 32 bit integer | Little |
Number of preset zones | Unsigned 32 bit integer | Little |
Preset zones | Preset zone array | N/A |
Preset zone root key is handled the same way as Program zone root key, if equal to -1 don't use it. In version 1.8, "Preset zone velocity low/high" are present, however they are unused.
Preset zone key high must always be greater than or equal to Preset zone key low, the same applies to the Preset zone velocity.
Name | Type | Endianness |
---|---|---|
Preset zone root key | Unsigned 32 bit integer | Little |
Preset zone key low | Unsigned 8 bit integer | N/A |
Preset zone key high | Unsigned 8 bit integer | N/A |
Preset zone velocity low | Unsigned 8 bit integer | N/A |
Preset zone velocity high | Unsigned 8 bit integer | N/A |
Program index | Unsigned 32 bit integer | Little |
After the last preset zone has been loaded the header of the first sequence starts. Load and split all the sequences using the offsets provided in the header.
There are as many labels as specified in the header. The use of labels is not well documented. If they are not needed they can be skipped. After loading them you should reach the end of the file.
Occasionally can have a header if the magic number "Sam!" is detected. The body size is never correct and should not be used.
Name | Type | Endianness |
---|---|---|
Magic number | ASCII character x4 | N/A |
Body size | Unsigned 32 bit integer | Little |