ProTracker Studio Module
The ProTracker Studio Module (PSM) file format is used for the music in Jazz Jackrabbit, Epic Pinball, Extreme Pinball, Silverball, Sinaria and One Must Fall. The file format is named after ProTracker, an Amiga program, though this program was probably actually not used to write PSM files. One Must Fall's music was written in Multitracker, and the music for Jazz Jackrabbit, Epic Pinball and Extreme Pinball probably in Scream Tracker.
There are two file types that use the extension .PSM; they are both used by Epic Megagames' MASI sound system, but are used by different versions of the system. The two formats are:
- PSM New Format: Used by Jazz Jackrabbit, Epic Pinball, Extreme Pinball, One Must Fall, Sinaria (in this game with slight differences, see below), newest PSM format
- PSM 16: Used by Silverball, an older version of the format which is closer to ScreamTracker-style modules.
The most common of the two PSM formats is the new format, and most programs that try to interpret PSM files will be expecting this. For example, ModPlug Player cannot open Silverball files as these are in the PSM 16 format.
There are actually two slightly different variants of the new formats: A common one used in several games, and one used in the game Sinaria. It is not entirely clear if the format used in Sinaria is newer or older - in some ways, like the effect interpretation, it resembles PSM16 more than the new format, so it could be an earlier version of the new PSM format. But Sinaria was released later than or around the same time as most other games using the new PSM format, so maybe it just took really long to develop.
- 1 PSM New Format
- 2 PSM 16
- 3 Utilities
- 4 Notes
PSM New Format
This format is used by Epic games in Jazz Jackrabbit, Epic Pinball, Extreme Pinball, Silverball, Sinaria and One Must Fall. It is notable for consisting of a number of segments (chunks) and sub segments. It bears the 4-byte signature 'PSM ' at the file start.
File structure: Header Pattern segment Song segment Samples
The file header is 12 bytes long:
File header: 0 4 ID 'PSM '; indicates file is PSM format 4 4 Size Filesize - 12 8 4 ID2 'FILE'; indicates start of file info
After the header, some chunks follow in IFF-style. You should not expect chunks to come up in the same order as they are described here. A good way to handle chunks is to read the 4-Byte ID and the 4-Byte size field first, then evaluate the ID and decide what to do next based on this ID. Note that the size field does not include the ID and itself; it only holds the size of the chunk content.
This segment is optional, and one of the few segments that can be absent when playing PSM files in most programs. (Most programs expect all other segments to exist, even if they are not vital.)
0 4 ID 'TITL'; indicates a title follows 4 4 Size Size of title as dword after this dword 8 ? Title Song title
Song info segment
This segment seems to indicate the beginning of the song data and is not really relevant when parsing.
12 4 ID 'SDFT'; indicates start of format info 16 4 Size Size of next header as dword, (8) 20 8 Song 'MAINSONG'; indicates song type. No other song types are known.
Each pattern is stored in its own PBOD chunk. Note that there are two possible formats for this chunk; one is used in the "old" format (as used in Epic Pinball, Extreme Pinball, Jazz Jackrabbit, One Must Fall) and the other in the "new" format (as used in Sinaria)
Pattern segment: 0 4 ID 'PBOD'; indicates a pattern follows (Pattern BODy) 4 4 Size Length of pattern data as dword, after this dword 4 4 Size Same value again.
Pattern: 0 4/8 Number Pattern ID. See note below. 4 2 Row n Number of rows in ALL channels in pattern (64 usually, but can differ.) as word. 6 ? Data Contains pattern data as a number of rows of interlaced channels (12341234...) Usual settings is 64 rows of 4 channels. Epic Pinball has shorter patterns for example, but they also include a "break to row" command at the end of the pattern.
Note: There are two variants of the format. In the most common variant, the pattern ID is 4 bytes long and starts with a 'P', followed by an integer number which is the pattern number, padded to 4 bytes with spaces. Caution: This number might or might not be zero-padded; In some files, the ID of the first pattern could be 'P0 ', but there are also files where it is 'P00 '!. In C/C++, you could use atoi() to parse this value. In the format used in the game Sinaria, This field is 8 bytes long instead of 4 bytes, and the first 4 bytes read "PATT", so the first pattern could be for example 'PATT0 '.
Pattern row channel entry: ? 1 Flags Contains four flags that indicate which pattern data follows +1 1 Chan The channel this data belongs to. +2 1 Note Present if bit 7 in Flags is set. Pitch, $01 is C-1, etc... The octaves are aligned by 16, i.e. B-1 is $0C but the next note, C-2, is $10. +3 1 Ins Present if bit 6 in Flags is set. Instrument used, 0-31 +4 1 Vol Present if bit 5 in Flags is set. Volume change to, 0-63 = 0-127; optional +5 1 Effect Present if bit 4 in Flags is set. Effect to use, volume slide, Portamanto... +6 x Eff Am Present if bit 4 in Flags is set. Parameter of effect, e.g amount of slide
Each row consists of a word giving the size of the row (Including the word) followed by the channel data. A channel is only included if it has data in it, but a totally empty row is still included. So an 'empty' row (Where none of the channels have data.) thus consists of just a word of value 2.
Each channel entry consists of between 3-7 bytes. The first byte is a flag that shows what data follows. (The highest four bits indicate whether there are bytes for the following four variables; Note ($80), Instrument ($40), Volume ($20), Effect AND Effect parameter ($10). Thus 5 bytes are represented by a combination of 4 possibilities.) The next byte identifies the channel (Since each channel may or may not be present.) starting at 0 for channel 1. The remaining 5 bytes may or may not be present depending on their flag and contain data for Note, Instrument(Sample) used, Volume change for channel, Effect and Effect parameter.
There are several things to note about this; Effect and Effect magnitude MUST occur together. Sample numbers, like channels are numbered starting at 0, not 1. Magnitudes (For effect AND volume) are from 0-127, not 0-64 as in other formats.
Note that this table is guaranteed to be correct; Most effects seem to be converted correctly, though. Note that these values are not correct for the PSM files that can be found in the game Sinaria. Leave out all divisions and it will be correct again.
PSM Command Param length S3M Command Volume commands 1 1 Byte DxF - fine volside up 2 1 Byte Dx0 - volslide up 3 1 Byte DFx - fine volslide down 4 1 Byte D0x - volslide down Portamento commands B 1 Byte FFx - fine porta up (divide x by 4) C 1 Byte Fxx - porta up (if x < 4, use FFx, else divide x by 4) D 1 Byte EFx - fine porta down (divide x by 4) E 1 Byte Exx - porta down (if x < 4, use EFx, else divide x by 4) F 1 Byte Gxx - portamento (divide x by 4) 10 1 Byte S1x - glissando control 11 1 Byte Lx0 - tone porta + volslide up 12 1 Byte L0x - tone porta + volslide down Vibrato 15 1 Byte Hxy - vibrato 16 1 Byte S3x - vibrato waveform 17 1 Byte K0x - vibrato + volslide up 18 1 Byte Kx0 - vibrato + volslide down Tremolo 1F 1 Byte Rxy - tremolo 20 1 Byte S4x - tremolo waveform Sample commands 29 3 Bytes Oxx - offset (xx corresponds to the 2nd byte) 2A 1 Byte Q0x - retrigger 2B 1 Byte SCx - note cut 2C 1 Byte SDx - note delay Position change 33 2 Bytes Bxx - position jump - ignored by PLAY.EXE 34 1 Byte Cxx - break to row PLAY.EXE entirely ignores the parameter (it always breaks to the first row), so it is maybe best to do this in your own player as well. If the original file was an S3M, the parameter is double-BCD-encoded, i.e. on top of the original format's BCD encoding, the same encoding is applied again. to translate into the correct target row in binary, apply this twice: param = (param & 0xF0) * 10 + (param & 0x0F) For MOD files, the parameter is a normal binary number. 35 1 Byte SBx - pattern loop 36 1 Byte SEx - pattern delay Speed change 3D 1 Byte Axx - set speed 3E 1 Byte Txx - set tempo Misc. commands 47 1 Byte Jxy - arpeggio 48 1 Byte S2x - set finetune 49 1 Byte S8x - set balance
Effect interpretation is slightly different in Sinaria's format. Slide command parameters are more like in PSM16.
This segment contains most of the important data used to play the song. It contains several sub-segments, each of the same format as a normal segment, but contained in the song segment. Note that there might be more than one song segment and thus, more than one order list, default speed, default tempo, etc... For example, in Extreme Pinball, all the different jingles and mission songs are stored as separate SONG chunks. It is up to the developer to find a clever way of managing / playing several sub songs.
Segment structure: 0 4 ID 'SONG' indicates start of song structure 4 4 Size Size of song structure, including all sub-segments 8 9 Type Type of song this is for; This is 'MAINSONG ' in almost all PSM files. Extreme Pinball has several SONG items with different types! 17 1 Comp Compression, for PSM = 1 (Uncompressed) 18 1 Chan Number of channels, usually, but not always, 4
This dates the file and is used by some programs. It is usually the first sub-segment.
0 4 ID 'DATE' indicates date data 4 4 Size Size of date segment (6) 8 6 Date Date as text, YYMMDD
This can also be used as a way to heuristically detect if the new version of the format is being used. Sinaria's song dates are: 800211, 940902, 940903, 940906, 940914, 941213
The order list describes how patterns are arranged in the song. This allows the same pattern of instruments to be played more than once in a song (e.g. a chorus). without the pattern data having to be duplicated. There should be only one order. In most module formats, the order list only consists of pattern indices, but in the PSM format it resembles a tiny scripting language that can do more than just list patterns. For example, It typically contains chunks that set the tempo of the song and the channel panning. In theory, these chunks can occur between two pattern chunks, changing the tempo or panning of a pattern without having to duplicate the pattern data, but in practice this feature is not used, so it can be ignored when writing a PSM loader.
0 4 ID 'OPLH' indicates start of pattern placement order 4 4 Size Size of order segment 8 2 Cnt. Number of following chunks
Now, the following chunks may follow until the end of the "OPLH" chunk is reached. Every chunk is identified by its first byte:
- $00 (1 Byte): End (Nothing follows)
- $01 (5/9 Bytes): Order list item follows (e.g. "P0 ", "P12 " in old format or "PATT0 " in Sinaria format, see above) - join those to get the complete order list.
- $02: Play Range: N/A
- $03: Jump Loop: N/A
- $04 (3 Bytes): This 16-bit value indicates the "restart chunk". If the end of the subsong is reached, it will jump back to this chunk. In many cases, this would be 4th chunk (not 3rd chunk, as the chunk index is starting at 0!), which is a panning index in most PSMs - So you would just go to the nearest order list item that's following this chunk. However, this can also point to a valid order list chunk.
- $05: Channel Flip: N/A
- $06: Transpose: N/A
- $07 (2 Bytes): Next byte sets the speed (ticks/row) for this subtune
- $08 (2 Bytes): Next byte sets the tempo for this subtune
- $0C (7 Bytes): Sample map table: This chunk is always $0C $00 $FF $00 $00 $01 $00. This seems to be an unfinished feature of the order list scripting language. It appears that this maps e.g. what is "I0" in the file to sample 1. Only the fourth and fifth byte ($00 $00) actually seem to do something: They translate the sample number in the pattern to different instruments in the file.
- $0D (4 Bytes): Channel panning index. Next byte is channel number (Start at 0), then initial pan ($00 ... $FF) and a byte follow. The byte seems to tell what to do with the previous pan position (0 - use it, 2 - ignore it, make this channel surround, 4 - set to center).
- $0E (3 Bytes): Channel volume index. Next byte is channel number (Start at 0), then volume ($00 ... $FF). $FF in most cases. Some OMF 2097 tracks use a lower volume.
N/A: This chunk does nothing or freezes MASI. There is no need to implement this.
This is simply a list of all the patterns used in the file. You do not really need to parse this, it seems to be a purely informational chunk.
0 4 ID 'PATT' indicates start of pattern list 4 4 Size Size of pattern list after this 8 4 Size Same as above 12 4x Pat An ordered list 'P0 ', 'P1 '... for all patterns in the file, each entry 4 bytes
Sample list sub-segment
Similar to the above, this is a list of all the samples used in the file. It is usually the last sub-segment in the song segment and you do not really need to parse this.
0 4 ID 'DSAM'; indicates start of sample list, used to say what samples are 'full' Any samples not on this list will be ignored, even if they have data 4 4 Size Size of list after this 8 4 Size Same value as above 12 15x Entry Sample entries, one for each sample in the file, each entry 15 bytes
Sample entry: 0 8 Format Sample format, padded with spaces (END, RAG2...) This is important to some programs 8 4 ID 'I0 ', 'I1 '... the sample ID ('I' means 'Instrument'). Again, be sure to accept both 'I0 ' and 'I00 '! 12 2 Num The sample number, 0,1,2... for the sample
Samples are the raw sound data that makes up the instruments on the song. The actual format depends on the sample format. Samples have information in their headers which allows data to be played at different pitches (Speeds.) and to loop from and to various points in the data. This is by far the largest part of the file, since the raw data takes up so much space.
0 4 ID 'DSMP' indicates start of sample 4 4 Size Size of following sample as 'DSMP' + dword from end of word 8 9 Flags If highest bit is set, then sample is looped 9 8 Songn. Filename of the original module (without extension) 17 4 INSx Last digit of sample (Instrument) number, 0-9; with 31 instruments possible Only last digit is shown. E.g 1st, 11th, 21st and 31st sample is 'INS0' 21 33 Name Defines the instrument name or file, usually a .st or line of text 54 51 Header Sample parameters (Can also 58 bytes long, padded with nuls) Byte 1-6 are unknown (but apparently always $00 $00 $00 $00 $00 $FF) Bytes 7-8 is instrument number Bytes 9-12 are sample length Bytes 13-16 are loop start Bytes 17-20 are loop end (all $FF means at end of sample) Bytes 21-22 are unknown (second byte could be finetune in Sinaria, but seems to be unused) Byte 23 is default volume Bytes 24-27 are unknwon Bytes 28-31 is frequency (Sample rate). MASI ignores the upper 16 bits, even if they are non-zero. 19 $00-bytes follow (padding?) 105 ? Data Music data in 8-bit mono format
The sample header is slightly different in Sinaria's format: INSx is 8 bytes long (like the PATT IDs), and the last 21 $00-bytes are just 16 bytes (so that the struct is 96 bytes large in both formats).
The PSM new format, along with the PSM 16 format use delta-encoded samples, something to make the file smaller when zipped. 'Deltas', convert a string of bytes into another by storing the DIFFERENCE between a byte and the previous byte. It has the effect that if a single byte in the sample is changed, the entire sample will be degraded. This use of deltas varies slightly from that of the PSM 16. The 'start value' of the string is assumed to be $80 (128) and the first byte will thus turn this into the first desired value, the second delta converts the first value to the second, and so on.) All deltas are signed, 1-byte values, but loop (Thus 10 - 20 = -10 can also be considered as 10 + 236 = 246). An example of this is as follows:
RAW: (128) 64 66 67 68 69 70 71 73 75 77 76 DELTAS: -64 0 2 1 1 1 1 1 2 2 2 -1
CONVERT.EXE can produce "encrypted" PSM files with the /K command line switch. The encryption scheme is simple: It adds 1 to the first byte, 2 to the second, 3 to the third, and so until, for the entire file. It does not appear like any game made use of this feature, though.
This is the format used in Silverball, early versions of Epic Pinball and possibly other games. The designation 'Protracker Studio 16 format' was given to it by the only reliable source of information on this format, and may not be the official designation.
The format bears many similarities to the S3M format; the file is set out roughly the same, patterns and samples are similar, indeed, near identical and the functionality is similar. It also shows many similarities to the ProTracker MOD format and retains vestiges of Amiga compatibility.
This format can be identified by its signature 'PSMþ', though files may lack this and still function.
File structure: Header Order Pan segment Pattern segment Sample data Sample headers
0 4 Sig Signature, 'PSMþ' 4 59 Title Song title, padded with nulls. Unlike other formats, this must also be terminated with a null byte. (It sometimes is not terminated, though.) 62 1 This must be $1A to end the song name, like in S3M format. 64 1 Type Song type, First bit: 0 - Module (w/samp.), 1 - Song (w/o samples) Second bit: 0 - 3 octave Protracker, 1 - 5 octave; remaining bits reserved. 65 1 PSM v PSM format version, $10 for this format (Hence the name PSM 16) = 'v1.00'. Sometimes, this is also $01, but there's no difference in the format itself. 66 1 Patt v Pattern version, 0 or 1. 0 means the pattern is stored in the module are in the 32 channel file format. A 1 signifies the patterns as being stored as a 255 channel format. (I have not found any PSM16 modules that have this format.) 67 1 Speed Song speed 68 1 BPM Beats per minute, the default Amiga BPM value. (The only reason that the Amiga BPM format is still followed here is that it allows more control over the final hz value.) Range: 32 to 255. 69 1 Vol Master volume of song, 0-255 70 2 Len Song length, 0-255. The number of patterns to play in the song, in total. 72 2 Ordlen The number of orders actually stored at the order offset. It was hoped that the PSM 16 format would allow multiple orders, so this would be the length of the first order. This doesn't appea to ahve happened, and is usually the same as the previous value. 74 2 Patnum Number of patterns in the song. 1-255 76 2 Sampnum Number of samples and 'sample structures' in song, 1-255 78 2 NCIS Number of channels in song to PLAY. 1-32. 80 2 NCP Number of Channels to Process; describes the MAXIMUM number of channels to process. As an example, when converting 669 files, NCP = 9 because some track information is in Channel 8, but the Number of Channels to Play was set to 8, (Channel numbers to play from 0 to 7.) 1-32 82 4 Ordoff Location of order in header 86 4 Panoff Location of pan positions in header 90 4 Patoff Location of patterns in header 94 4 Sampoff Location of sample headers in header 98 4 Commoff Location of comments in header 102 4 Patsiz Total pattern size; the total size of all the patterns loaded from the pattern offset. 106 40 Fillers 10 fillers, to be used for any possible expansions.
It is important to notice that the offsets point to the first byte after the chunk ID, i.e. "Ordoff" points to the first byte after "PORD".
Order and Pan positions
These are two separate segments, pointed to in the header. They may be anywhere, but usually follow the header sometimes after an amount of blank space. They are often padded with blank space. They are basically lists.
Order: This segment is pointed to in the header, and sets the PSM 16 format apart. The PSM 16 format was designed to be much more like the MOD format, allowing game designers to set flags to switch from one set of patterns to another, in effect allowing one file to contain more than one song. (For example a boss flag might make the music switch from a clam patterns 1-4 to a racy and dangerous patterns 5-7.)
0 4 Sig Signature, not needed, 'PORD' 4 ? Ords Pattern numbers and order. There will be [Ordlen] bytes of patterns ? 2 Lang Order language, not implemented, so left blank.
0 4 Sig 'PPAN' 4 12 Pan Pan positions; empty positions left blank.
0 2 Size Size of pattern, including these bytes 2 1 Len Length of pattern, in rows. Max length is 64 rows. 3 1 Chan Number of channels in pattern, 1-32 4 ? Data Pattern data
This is similar to the previous two segments, except actual pattern data is stored here. Patterns are very similar to the S3M format, and consist of y rows of x channels. Each row contains a number of channels and ends with a byte of value 0. Each channel is between 2-6+ bytes long. A totally empty channel is represented by a single byte of value 0.
Each channel starts with a flag byte, abcddddd, where a,b and c indicate whether there is a note and instrument, volume or special effect and effect magnitude in the following data, and dddd is the channel number (0-31, used since a given channel may or may not be present in a row.)
The usual maximum length of a channel entry is 6 bytes (1 flag byte, 2 Note AND instrument bytes, 1 volume byte and two Effect and Effect magnitude bytes.) Thus Note&ins\Eff&Eff mag must always occur together.
Like S3M, volume range is 0-64, as is special magnitude. However, special effects range from 0-255, like PSM New Format.
### Co MOD Description Arguments --- -- --- ----------- --------- Volume Commands 1 A1 EA Fine Volume Slide Up B xx xx=speed 2 A2 A Volume Slide Up B xx xx=speed 3 A3 EB Fine Volume Slide Down B xx xx=speed 4 A4 A Volume Slide Down B xx xx=speed Portamento Commands 10 B0 E1 Fine Porta Up B xx xx=speed 11 B1 1 Portamento Up B xx xx=speed 12 B2 E2 Fine Porta Down B xx xx=speed 13 B3 2 Portamento Down B xx xx=speed 14 B4 3 Tone Portamento B xx xx=speed 15 B5 E3 Set Glissando Control B xx xx=0 - Off, 1 - On 16 B6 5 Tone Port+Vol Slide Up B xx xx=speed 17 B7 5 Tone Port+Vol Slide Down B xx xx=speed Vibrato Commands 20 C0 4 Vibrato B xy x=speed, y=depth 21 C1 E4 Set Vibrato Waveform B x x=Waveform 21 C2 6 Vibrato+Vol Slide Up B xx xx=speed 22 C3 6 Vibrato+Vol Slide Down B xx xx=speed Tremolo Commands 30 D0 7 Tremolo B xy x=speed, y=depth 31 D1 E7 Set Tremolo Control B x x=Waveform Sample Commands 40 E0 9 Sample Offset 3B Position for offset change (0-1,048,575) 41 E1 E9 Retrig Note B xx xx=tick to retrigger sample 42 E2 EC Note Cut B xx xx=tick to cut note 43 E3 ED Note Delay B xx xx=ticks to delay note Pos. Change Commands 50 F0 B Position Jump B xx xx=order position 51 F1 D Pattern Break B xx Skip to line xx in next pattern 52 F2 E6 Jump Loop B xx xx=number of loops 0 Set 53 F3 EE Pattern Delay B xx xx=notes to delay pattern Speed Change Cmds 60 G0 F Set Regular Speed B xx xx=speed 61 G1 F Set BPM B xx xx=BPM (32-255) Misc. Commands 70 H0 0 Arpeggio B xy x=semitone #1, y=semitone #2 71 H1 E5 Set Finetune B xx xx=finetune 72 H2 Set Balance B xx xx=Balance (0-15)
Sample segment 0 4 ID 'PSAM' (Psm SAMple) 4 ? Data Sample data
Sample header segment 0 4 ID 'PSAH' (Psm SAmple Header) 4 ? Data Sample headers
Sample header 0 13 Name Sample filename, terminated with a null. 13 24 Desc Sample description or comments. 37 4 Offs Location of raw sample data in file 43 4 Mem This is the physical offset in RAM/DRAM of the sample. (Often blank.) 45 2 Num Sample number, 1-255 47 1 Type Sample type: (In some games left blank; if this is the case then the sample format is END, as used in most PSM New Format files) Bit 0: 0 - Digital, 1 - Synthesized Bit 2: 0 - 8-bit, 1 - 16-bit Bit 3: 0 - Signed, 1 - Unsigned Bit 4: 0 - Deltas, 1 - Raw Bit 5: 0 - Loop normally, 1 - Bidirectional Bit 6: 1 - Gravis patch (unsupported) Bit 7: 0 - No loop, 1 - Loop sample 48 4 Len Sample length, in bytes. 52 4 Rep st Sample repeat start; if sample loops, the loop starts here. 56 4 Rep fn Sample repeat end, if sample loops, it ends here. If this is less than the sample repeat start, the sample loops backwards. 60 1 Tune Fine tune; range 0-15, Tune 0-7 = 0-7; tune -1 - -8 = 8-15 61 1 Vol Sample volume, 0-64 62 2 Freq This is the frequency for the sample at a C of Octave 2. Typical values are 8,000 hz to 8,448 hz.
Like in S3M, sample headers are stored separately from the raw sample data.
A type of sample storage used often, like in the PSM New Format is 'Deltas', which converts a string of bytes into another by storing the DIFFERENCE between a byte and the previous byte, often making them compress better using general-purpose file compression tools. Thus:
RAW: 64 66 67 68 69 70 71 73 75 77 76 DELTAS: 11 64 2 1 1 1 1 1 2 2 2 -1
This is done to make files more compressible, but doesn't seem to be used much.
- Download psm2scrm.zip - DOS program to convert .PSM songs into ScreamTracker .S3M format, suitable for playing in your favourite tracker/module player. Works only with PSM New Format and is not nearly as accurate as OpenMPT.
- OpenMPT 1.18 and newer can load all PSM and PSM16 files.
- ModPlug Tracker and OpenMPT 1.17 can play the files and save them as S3M. More complex songs don't load correctly though. Works only with new format.
- foo_dumb is a plugin for various module formats for the Foobar2k media player. It supports both PSM16 and PSM and is similar to OpenMPT in playback quality.
- EPICTEST is a demonstration of the Epic Megagames MASI. It contains CONVERT.EXE which can be used to convert modules to the new PSM format.
-  JJ1MOD can convert S3M files to new PSM, though often with errors (Though these are usually only detectable with older programs such as game executables.) It is currently the only utility able to do this, and works only with New Format.
The New PSM format was reverse engineered by Levellord and tidied up by Levellass. It is possible there may be minor errors in the sample format information, especially since this is poorly documented. Some format definitions have been updated and corrected by Johannes Schultz of the OpenMPT development team.
The PSM16 format documentation was found on Wotsit and written up by Levellass (this appears to be an official document from the MASI developer). More info is needed.
In all formats the following table shows how note bytes are converted into actual notes: (PSM new format has the widest range, 0-255)
+---------+---------+---------+---------+---------+ | C-0 0 | C-1 12 | C-2 24 | C-3 36 | C-4 48 | | C#0 1 | C#1 13 | C#2 25 | C#3 37 | C#4 49 | | D-0 2 | D-1 14 | D-2 26 | D-3 38 | D-4 50 | | D#0 3 | D#1 15 | D#2 27 | D#3 39 | D#4 51 | | E-0 4 | E-1 16 | E-2 28 | E-3 40 | E-4 52 | | F-0 5 | F-1 17 | F-2 29 | F-3 41 | F-4 53 | | F#0 6 | F#1 18 | F#2 30 | F#3 42 | F#4 54 | | G-0 7 | G-1 19 | G-2 31 | G-3 43 | G-4 55 | | G#0 8 | G#1 20 | G#2 32 | G#3 44 | G#4 56 | | A-0 9 | A-1 21 | A-2 33 | A-3 45 | A-4 57 | | A#0 10 | A#1 22 | A#2 34 | A#3 46 | A#4 58 | | B-0 11 | B-1 23 | B-2 35 | B-3 47 | B-4 59 | +---------+---------+---------+---------+---------+