PSC

Introduction

These are compiled modules of Pro Sound Creator, the project of Viktor Kuzmin (KVA). The ideology is similar to ASC Sound Master, most of the features are inherited from ASM with almost no changes. And together with the new ones, it turned out to be a good tool for musicians who either already had experience in ASM, or wanted to, but could not approach it (see the list of ASM problems in the description of the ASC format).

Module format

Pro Sound Creator is similar to ASM, including the features of the compiled module format: in some ways initially, and in some ways as it develops. So, starting from version 1.04, the samples and ornaments data offsets began to be made not relative to the beginning of the module, but relative to the beginning of these structures (as in ASM), but here the PSC author clearly did not understand the idea why this was done in ASC, since it does not give the same advantages in PSC.

Therefore, first of all it is necessary to familiarize yourself with the ASC format, because without this, some of the points described below without too much detail may seem incomprehensible.

OffsetSizeDesignationDescription
+025ID"PSC V1.00 COMPILATION OF " identifier (may differ in versions, latest 1.07).
+2520TitleTitle (unused characters are filled with spaces).
+454BYString " BY " (visual field separator).
+4920AuthorAuthor (unused characters are filled with spaces).
+692SamplesThe sample area pointer (not used in the player).
+712PatsPtrPointer to the patterns playing order area.
+731DelayPlayback speed.
+742OrnsPtrPointer to the ornaments' offsets.
+76?SamPtrsOffsets (relative to +76 since version 1.04) to each sample body (there can be up to 32 samples in total).
+OrnsPtr?OrnPtrsOffsets (relative to +OrnsPtr since version 1.04) to each ornament body (there can be up to 32 ornaments in total).
+Samples?SamsAreaSamples area: samples one after another (the structure of each is described below).
+Ornaments?OrnsAreaOrnaments area: ornaments one after another (the structure of each is described below). The offset +Ornaments is not explicitly stored in the format, but it can be calculated from the zero ornament offset by reducing it by 1, or by going through all the samples in order (apparently the editor's decompiler works according to the second variant).
+Patterns?PatsAreaPatterns area: patterns one after another (the structure of each is described below). The offset +Patterns is not explicitly stored in the format, but it can be calculated by going through all the ornaments in order.
+PatsPtr?PlayOrderArea of the order in which patterns are played (the structure is described below).

As you can see, the format is designed so that the decompiler does not seek in different areas of the structure when loading the module into the editor, but goes in order, unwinding area by area. As a result, a lot of redundant (unnecessary for playback) information is stored inside the module.

I usually look at the format through the eyes of the player in order to take only what is really necessary from the format and ignore everything that does not affect the sound. But in the case of PSC, this approach leaves too many questions. Therefore, we will make an exception for PSC and describe the format from the decompiler point of view.

Samples area

The first pointer in the format is not used in the player. So this is the decompiler's entry point: a pointer to the samples area.

The samples area is a list of paired fields "Number:Data". The end of the list is defined by byte 0xFF.

Number field is the original (before compilation) sample number (it is in the range 0..31), is not used by the player, because the compiled pattern stores the relative numbers of the saved samples. If only two samples are stored in the module, for example, the 4th and 8th, then their numbering in the compiled pattern will be 0 and 1, respectively.

The sample's Data field consists of 6-byte ticks of the following structure:

OffsetDescription
+0Two-byte deviation accumulation (signed number) for the tone period.
+2Deviation accumulation (signed number) for noise or envelopes (the latter only if envelopes are simultaneously allowed in both the track and the sample).
+3Bits 7–4: unknown. Bits 3–0: amplitude.
+4Bit 7: 0, if this tick is a looping point. Bit 6: 0, if this tick is the last tick in the loop body. Bit 5: 0, if this tick is the last tick in the sample. Bit 4: 0, if envelopes are allowed. Bit 3 is the noise mask. Bit 2: 1 for channel volume decrease by 1. Bit 1: 1 for channel volume increase by 1. Bit 0 is the tone mask.
+5Unknown.

Analyzing samples tick by tick, the decompiler reaches byte 0xFF instead of the sample number. And this means that there are no more samples, and then the ornaments area begins.

Ornaments area

The ornaments area is also a list of paired fields "Number:Data". And also, the end of the list is defined by byte 0xFF.

Number field is the original number of the ornament before compilation (it is in the range 0..31), not used by the player (see the description of the samples area, the reason is the same).

The ornament's Data field consists of 2-byte ticks of the following structure:

OffsetDescription
+0Bit 7: 0, if this tick is a looping point. Bit 6: 0, if this tick is the last tick in the loop body. Bit 5: 0, if this tick is the last tick of the ornament. Bits 4–0 is deviation accumulation for the noise period (high bit is signed).
+1Deviation accumulation for the note in semitones (a signed number).

Patterns area

The patterns area, although a rather complex structure, is also a list that allows the decompiler to unwind the module further pattern by pattern. But this list consists of five elements: "Size:Number:Channel Data:Channel Data:Channel data". The end of the list is determined similarly by the byte 0xFF.

Size field is the number of lines in the pattern in the range 1..64 (not used in the player). Number field is the pattern number (also not used in the player). Then there are three identical structures describing each pattern channel in the A, B, C order.

The pattern's Channel data field is a sequence of bytes ending with a 0xFE marker. The structure is as follows:

BytesDescription
0x00..0x56Set the note.
0x57Set the channel volume 15. Turn on the envelope.
0x58..0x66Set the channel volume 1..15. Turn off the envelope.
0x67..0x6a, UnknReserve for special commands with the parameter.
0x6b, TonesStart the tone slide up. Tones is the amount of changes in the tone register units per each interrupt.
0x6c, TonesStart the tone slide down. Tones is the amount of changes in the tone register units per each interrupt.
0x6d, TonesRun the portamento from the current tone frequency to the frequency of the note being set. Tones is the amount of changes in the tone register units per each interrupt.
0x6e, DelaySet a new playback speed value (Delay in interrupts).
0x6f, UnknDisable the ornament. In the Unkn byte is a random value.
0x70, PeriodStart a periodic increase or decrease of channel volume by 1. Period is a 7-bit number (the 6th bit is signed), i.e. theoretically the range is -64..63. Negative Period for decreasing the volume, positive for increasing, absolute value is the volume changes period in interrupts.
0x71, UnknBreak the ornament loop. In the Unkn byte is a random value.
0x72..0x79, UnknReserve for special commands with the parameter.
0x7a, EnvT, [EnvPL, EnvPH]Set the envelope type (if it is channel B). EnvT is ignored in other channels. Two bytes following are extracted in channel B: EnvPL and EnvPH (the lowest and highest bytes of the envelope period). Note: a failure is potentially possible, but in fact this data should not get into channel A or C, because the PSC format does not optimize the saving of identical channels.
0x7b, NoiseSet the noise period base (if it is channel B).
0x7cTurn off the sound.
0x7dBreak the sample loop.
0x7e..0x7fIs a reserve for commands without a parameter.
0x80..0x9fSet the sample to 0..31.
0xa0..0xbfSet the ornament to 0..31.
0xc0..0xffFrom now on do skipping the specified number of lines (0..63). 0 by default.

Patterns playing order area

The order of playback is determined by the positions list, each position occupies 8 bytes. A two-byte marker ends the list: the first byte is the position number for looping, the second byte is 0xFF. After the marker there is a two-byte pointer to the loop position, which number was specified in the first byte of the marker.

The structure of one position is as follows:

OffsetDescription
+0Position number starting from 0.
+1The number of lines in this pattern.
+2A two-byte pointer to the channel A data of this pattern.
+4A two-byte pointer to the channel B data of this pattern.
+6A two-byte pointer to the channel C data of this pattern.

Conclusion

The Vortex Tracker II documentation suggests that the format is not optimal, leading to large module sizes. Later, a clarification was added that, perhaps, the large size of those modules that are simply saved, and not compiled through the compilation menu.

Now, after a detailed study of the "extra" information in the module, we can state both.

Nevertheless, if you do not focus on the size of the module, you can sum up some results.

Advantages of PSC in comparison with ASC

Disadvantages of PSC in comparison with ASC

Disadvantages in the PSC format itself