STP

Introduction

STP is the native format of the compiled ZX Spectrum Sound Tracker Pro module (see the description of STF).

The compiler is built into the editor and in different versions of Sound Tracker Pro it has certain errors.

In some compilers, this is an optimization error, in which, removing a seemingly superfluous (repetitive) ornament, they forget about the slide command turned on before, and it begins to be duplicated on subsequent notes. A striking example: the module "IMP49:FOOLISH GIRL", or Sumea_FN.stp by Visual (for second one, there is no source STF anywhere to recompile without errors).

In others, there is no such error, but there is a lot of extra garbage and the commands to set the volume 1 disappear (although this is no longer noticeable by ear since the volume is too low).

Unfortunately, there is no numbering of the editor versions, so you will have to choose for yourself which one you have on hand is better by trial and error.

If your goal is just to compile STF, then this can be done using the built-in compiler of Ay_Emul: I fixed all the errors found in native compilers and worked out the optimization by size.

The STP format was well described by VfNG in the Echo #3 e-paper (given at the end). Therefore, if there are some unclear points in the further text, you can read it first.

Some notes on the format

When I chose the STP extension to use this format in Ay_Emul, I did not voice one important point (in other things, I made this mistake with some other formats). Many compiled module formats have two states: initialized and non-initialized. There is a special initialization routine is called before starting playback in the native player. In the most formats, it simply prepares internal variables for the start of playback and does not make any changes to the module itself. But there are players of some formats in which the module data is bound to the load address during initialization, and there are even those that use the header area for their needs (and, therefore, spoil it).

A part of the offsets is bound to the load address during the initialization of the compiled Sound Tracker Pro module. Moreover, there is a byte identifier inside the file to signal that the module has already been initialized.

The STP extension is given only to those modules that are either not initialized (that is, they are in the state in which they were saved from the editor), or the reverse operation of unbinding from the load address was performed.

Ay_Emul, while saving the found modules (this applies not only to STP), does everything necessary to return them to the "pre-initialization" state.

Unfortunately, in recent years, modules have begun to appear on the Internet that are saved without observing this rule, and even with incorrectly inserted author's strings (see below).

Therefore, I had to add additional checks into Ay_Emul for some formats (including STP) after loading to take into account this feature of modern time.

The author's string in the body of the module

The first tracker formats on the ZX Spectrum suffered from the similar disease: the authors of the editors either did not provide a place for the author's string (Sound Tracker) in the format at all, or they provided, but not in the format, but in the player. At the same time, if there is a hint in an editor like ASC Sound Master that the player and the data (module) are one indivisible whole, then in STP it is mentioned directly in the documentation that different modules can be played with one player (and in such a use case it becomes unclear which module the author's string belongs to).

We discussed this problem with Ilya Kudryavtsev (Himik's ZXZ), and he suggested modifying the ASC modules a little. I, in turn, suggested doing the same with STP. Thus, we have agreed on two new formats, the main advantage of which is full compatibility with the originals. The new STP and ASC are easily played by the original players, since they do not even know about the presence of additional information in the body of the data block.

To insert the author's string (length 53 bytes, starts with "KSA SOFTWARE COMPILATION OF ") from the player into the body of the module, it is necessary:

  1. The area starting at offset +10 should be moved 53 bytes forward.
  2. The author's string is inserted into the gap that has appeared.
  3. All offsets in the module (4 main ones at the beginning of the module, and everything starting with pattern offsets at the end) are increased by 53.

Compiled module format

The following is a slightly edited excerpt from the VfNG article in the Echo #3 e-paper.

---------------------------cut here-------------------

There may be some inaccuracies in the description, so be careful. This description is not written to eliminate all the issues, but only to help you figure out some things when working with the player.

+0Playback speed;
+1Offset to TABL1;
+3,4Offset to TABL2;
+5,6Offset to TABL3;
+7,8Offset to TABL4;
+9This byte contains the number of offsets to which you need to add the real address +0 in memory. This is done by the initialization section. If this byte=0, then initialization has already been performed. The first offset that requires initialization is from the address TABL2. Each offset size is 2 bytes (minor, major bytes of offset from +0);
+10The first pattern;
TABL1+0length of music in positions;
TABL1+1position number for looping;
TABL1+22 bytes/position:
+0 6*PATTERN number;
+1 HEIGHT (deviations in notes from the usual sounding PATTERN);
TABL2PATTERN descriptors: 2 bytes of offset for each channel, which means 6 bytes/PATTERN;
TABL3offsets to ornaments. The 0th ornament is used to disable ornaments in the channel;
ŇABL4offsets to samples;

Ornament format:

+0looping point;
+1full length;
+2, 1*(+1)deviations from the note value;

Sample format:

+0looping point;
+1full length;
+24 bytes/QUARK:
+0 bits 0-3 amplitude; bit 4 tone mask; bit 7 noise mask;
+1 bit 0 envelope mask; bits 1-5 noise frequency;
+2,3 bytes of frequency vibrato;

Each PATTERN descriptor contains pointers to channel descriptors. Channels are analyzed as follows:

        LD   HL,CHAN_POS
        LD   A,(HL)
        OR   A
        JR   Z,PATTERN end
        LD   C,#10
LOOP    LD   A,(HL)
        INC  HL
        CP   #C0
        JR   C,L9
        SUB  C
        JR   NC,L1
        SUB  C
        JR   NC,L2
        SUB  C
        JR   NC,L3
        SUB  C
        JR   L4
L9      SUB  #80
        JR   NC,L5
        SUB  C
        JR   NC,L6
        SBC  A,C
        JR   NC,L7
L8      ADD  A,#60

in A is the note number. Its installation, exit;

L7

in A is the sample number. LOOP;

L6

in A is the number of the ornament. LOOP;

L5

in A is how many INTs you don't need to analyze the channel. LOOP;

L4

in A is the type of envelope. Its period in the next byte. Setting the amplitude register to #1F, LOOP;

L3

mute channel, exit;

L2

setting the value obtained in L5, exit;

L1      JR   Z,L0
        DEC  A

in A is the number that must be subtracted from #0F to get the volume value. LOOP;

L0

glissade in the next byte. LOOP;

---------------------------cut here-------------------