1
by Amaury Carvalho
Commit on 06/06/2020 05:32:36 -03 by amaury |
1 |
How to decode a Vortex Tracker II "PT3" File |
2 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
3 |
||
4 |
by Vince "Deater" Weaver, <vince@deater.net> |
|
5 |
http://www.deater.net/weave/vmwprod/pt3_player/ |
|
6 |
10 September 2019 |
|
7 |
||
8 |
Background: |
|
9 |
~~~~~~~~~~~ |
|
10 |
Vortex Tracker II ( https://bulba.untergrund.net/vortex_e.htm ) |
|
11 |
is a music tracker (tool for writing music) that targets systems |
|
12 |
with the AY-3-8910 sound chip. The music made is most popular |
|
13 |
on various ZX Spectrum (z80) and Atari ST systems. |
|
14 |
||
15 |
I wanted to make a decoder for a 6502-based Apple II with a |
|
16 |
AY-3-8910 based Mockingboard sound card. The challenge was |
|
17 |
all the low-level Vortex Tracker documentation is in Russian, |
|
18 |
and the source code available is either uncommented z80 assembly |
|
19 |
language or Russian-commented Pascal source code. |
|
20 |
||
21 |
This document is based at least partly on the writeup here: |
|
22 |
http://karoshi.auic.es/index.php?topic=397.msg4641#msg4641 |
|
23 |
as well as the AY_emul source code, and lastly just from reverse |
|
24 |
engineering things while trying to get my code to match the output |
|
25 |
of AY_emul exactly. |
|
26 |
||
27 |
||
28 |
The PT3 Format |
|
29 |
~~~~~~~~~~~~~~ |
|
30 |
||
31 |
||
32 |
* File Header |
|
33 |
||
34 |
Note: 16-bit values are little-endian |
|
35 |
||
36 |
Offset : Size : Description : Contents |
|
37 |
---------- ---------- -------------- ---------------- |
|
38 |
$00 - $0C : 13 bytes : Magic : "ProTracker 3." |
|
39 |
$0D : 1 byte : Version : '5' for Vortex Tracker II |
|
40 |
$0E - $1D : 16 bytes : String : " compilation of " |
|
41 |
$1E - $3E : 32 bytes : Name : Name of the module |
|
42 |
$3E - $41 : 4 bytes : String : " by " |
|
43 |
$42 - $62 : 32 bytes : Author : Author of the module. |
|
44 |
$63 : 1 byte : Frequency table (from 0 to 3) |
|
45 |
$64 : 1 byte : Speed/Delay |
|
46 |
$65 : 1 byte : Number of patterns+1 (Max Patterns) |
|
47 |
$66 : 1 byte : LPosPtr : Pattern Loop Pointer |
|
48 |
$67 - $68 : 2 bytes : PatsPtrs : Pointers to the patterns |
|
49 |
$69 - $A8 : 64 bytes : SamPtrs[32] : Pointers to the samples |
|
50 |
$A9 - $C8 : 32 bytes : OrnPtrs[16] : Pointers to the ornaments |
|
51 |
$C9 - ??? : : Patterns[] : $FF terminated, More on this below |
|
52 |
||
53 |
Version: is at offset $0D, which is just the ASCII value of |
|
54 |
the version number from the magic. Usually you |
|
55 |
subtract off '0' to get the proper value. |
|
56 |
If the value is not a valid number, '6' is assumed. |
|
57 |
||
58 |
* Pattern list |
|
59 |
||
60 |
The pattern list starts at $C9 and is terminated by $FF |
|
61 |
||
62 |
The pattern is multiplied by 3. |
|
63 |
||
64 |
A sample pattern list might look like |
|
65 |
$03, $06, $09, $FF |
|
66 |
which corresponds to playing in order patterns |
|
67 |
1, 2, 3 |
|
68 |
||
69 |
||
70 |
* Samples |
|
71 |
||
72 |
The pt3 file allows for 32 samples. These samples contain |
|
73 |
values that are applied to the music notes as they are playing. |
|
74 |
||
75 |
The 16-bit address of a sample X can be found by getting the |
|
76 |
16-bit little-endian address at offsets |
|
77 |
$6A+(X*2) and $6B+(X*2) in the header. |
|
78 |
||
79 |
Byte 0: LOOP VALUE -- sample offset to return to once hit the end |
|
80 |
Byte 1: LENGTH -- number of 32-bit sample values |
|
81 |
Byte 2+: VALUES -- list of 4-byte (32-bit samples) |
|
82 |
||
83 |
* Sample format |
|
84 |
||
85 |
+ Byte 0 --- 7 6 5 4321 0 |
|
86 |
Bit 7 - Amplitude sliding |
|
87 |
Bit 6 - 1/0 amplitude slide up/down |
|
88 |
Bit 5 - 1/0 envelope slide up/down |
|
89 |
Bits 4321 - sign extend, envelope slide value |
|
90 |
Bit 0 - Sample has envelope |
|
91 |
||
92 |
+ Byte 1 --- 7 6 5 4 3210 |
|
93 |
Bit 7 - Envelope sliding |
|
94 |
Bit 6 - Accumulate Tone |
|
95 |
Bit 5 - parameter to envelope sliding? |
|
96 |
Bit 4 - Bit 6+4 used to set Noise/Channel |
|
97 |
mixer value |
|
98 |
Bits 3210 - Amplitude |
|
99 |
||
100 |
+ Byte 2 --- Freq Low -\ |
|
101 |
+ Byte 3 --- Freq High----- Used as base tone |
|
102 |
||
103 |
* Ornaments |
|
104 |
||
105 |
The PT3 file format has 16 ornaments, which are patterns applied |
|
106 |
to the note. This can be used for ?? effects. |
|
107 |
||
108 |
The 16-bit address of an ornament X can be found by getting the |
|
109 |
16-bit little-endian address at offsets |
|
110 |
$A9+(X*2) and $AA+(X*2) in the header. |
|
111 |
||
112 |
Byte 0: LOOP VALUE -- ornament offset to return to once hit the end |
|
113 |
Byte 1: LENGTH -- number of ornament values |
|
114 |
Byte 2+: VALUES -- list of single-byte values applied to the notes |
|
115 |
||
116 |
||
117 |
* Pattern data |
|
118 |
||
119 |
For each of three channels (A,B,C) there is a nul-terminated |
|
120 |
stream of bytes that gives the pattern data. |
|
121 |
||
122 |
To find the pattern data for a pattern, look it up in |
|
123 |
||
124 |
A 6-byte chunk with the 16-bit addresses for A,B,C for pattern |
|
125 |
X can be found by |
|
126 |
a_addr_l = [address in ($68/$67)] + (X*6)+0 |
|
127 |
a_addr_h = [address in ($68/$67)] + (X*6)+1 |
|
128 |
b_addr_l = [address in ($68/$67)] + (X*6)+2 |
|
129 |
b_addr_h = [address in ($68/$67)] + (X*6)+3 |
|
130 |
c_addr_l = [address in ($68/$67)] + (X*6)+4 |
|
131 |
c_addr_h = [address in ($68/$67)] + (X*6)+5 |
|
132 |
||
133 |
Follow that address to find the nul-terminated pattern data. |
|
134 |
||
135 |
The data can be interpreted this way: |
|
136 |
||
137 |
+ $00 - NUL termination, end of pattern |
|
138 |
+ $01-$0f - effects, see later. |
|
139 |
Note that parameters to the effect appear in the |
|
140 |
bytestream *after* the note to play |
|
141 |
+ $10-$1f - set envelope type |
|
142 |
+ $10 means disable envelope |
|
143 |
- sample number is next byte |
|
144 |
+ $11-$1F |
|
145 |
- envelope type is bottom 4 bits |
|
146 |
- envelope period is next 2 bytes (big endian) |
|
147 |
- envelope delay is next 1 byte |
|
148 |
- sample number is next byte |
|
149 |
||
150 |
+ $20-$3f - set noise |
|
151 |
- Noise set to the ($20...$3F) value - $20 |
|
152 |
+ $40-$4f - set ornament |
|
153 |
- ornament sent to bottom 4 bits |
|
154 |
- possibly setting 0 counts as disabling |
|
155 |
+ $50-$af - play note |
|
156 |
||
157 |
0 1 2 3 4 5 6 7 8 9 a b c d e f |
|
158 |
50: C-1 C#1 D-1 D#1 E-1 F-1 F#1 G-1 G#1 A-1 A#1 B-1 C-2 C#2 D-2 D#2 |
|
159 |
60: E-2 F-2 F#2 G-2 G#2 A-2 A#2 B-2 C-3 C#3 D-3 D#3 E-3 F-3 F#3 G-3 |
|
160 |
70: G#3 A-3 A#3 B-3 C-4 C#4 D-4 D#4 E-4 F-2 F#4 G-4 G#4 A-4 A#4 B-4 |
|
161 |
80: C-5 C#5 D-5 D#5 E-5 F-5 F#5 G-5 G#5 A-5 A#5 B-5 C-6 C#6 D-6 D#6 |
|
162 |
90: E-6 F-6 F#6 G-6 G#6 A-6 A#6 B-6 C-7 C#7 D-7 D#7 E-7 F-7 F#7 G-7 |
|
163 |
a0: G#7 A-7 A#7 B-7 C-8 C#8 D-8 D#8 E-8 F-8 F#8 G-8 G#8 A-8 A#8 B-8 |
|
164 |
||
165 |
+ $b0 - disable envelope, reset ornament position |
|
166 |
+ $b1 - set skip value |
|
167 |
- next byte is how many lines to skip for |
|
168 |
this note |
|
169 |
+ $b2-$bf - set envelope |
|
170 |
- envelope type to (bottom 4 bits - 1) |
|
171 |
- envelope period next 2 bytes (big endian) |
|
172 |
||
173 |
||
174 |
+ $c0 - turn off note (volume=0 and disable everything) |
|
175 |
+ $c1-$cf - set volume |
|
176 |
- volume set to bottom 4 bits |
|
177 |
||
178 |
+ $d0 - done processing this note (end note) |
|
179 |
+ $d1-$ef - set sample |
|
180 |
- sample set to value-$d0. |
|
181 |
+ f0-$ff - initialize ornament/sample. Envelope is disabled |
|
182 |
- ornament is bottom 4 bits |
|
183 |
- next byte is sample*2 |
|
184 |
||
185 |
Note when parsing if you reach a note, a $D0 or a $C0 then you |
|
186 |
are done parsing the note for this line and should move on |
|
187 |
to parsing the effects. |
|
188 |
||
189 |
Effects |
|
190 |
~~~~~~~ |
|
191 |
||
192 |
AY_emul supports having up to one of each effect for each line, and |
|
193 |
tracks the order in which to apply them. However in the wild |
|
194 |
I have not seen more than one effect applied per line/channel |
|
195 |
(I don't think Vortex Tracker lets you add multiple?) |
|
196 |
||
197 |
The bytes for the effects follow after the byte that ended the note. |
|
198 |
||
199 |
The effect value on disk is not the same as that displayed when |
|
200 |
viewed in the tracker. |
|
201 |
||
202 |
On In |
|
203 |
Disk Tracker |
|
204 |
~~~~ ~~~~~~~ |
|
205 |
||
206 |
$01 $01: Glissando (slide through discrete notes) / Tone Down |
|
207 |
||
208 |
First byte: delay |
|
209 |
Next 2 bytes: frequency to add (is negative) |
|
210 |
||
211 |
$01 $02: Glissando (slide) / Tone Up |
|
212 |
||
213 |
This appears differently in tracker, but is just |
|
214 |
the same as above but with a positive frequency. |
|
215 |
||
216 |
$02 $03: Tone portamento (continuous slide) |
|
217 |
||
218 |
First byte: delay |
|
219 |
Next 2 bytes: ignored? |
|
220 |
Next 2 bytes: slide step (little-endian) |
|
221 |
||
222 |
$03 $04: Sample Offset |
|
223 |
First byte: value to set the sample position offset |
|
224 |
||
225 |
$04 $05: Ornament offset |
|
226 |
First byte: value to set the ornament offset |
|
227 |
||
228 |
$05 $06: Vibrato |
|
229 |
Periodic sound off/on in that channel |
|
230 |
First byte: OffOn delay (frames to stay off) |
|
231 |
Second byte: OnOff delay (frames to stay on) |
|
232 |
||
233 |
$08 $09: Envelope Glissando -- Frequency decreasing |
|
234 |
First byte: delay |
|
235 |
Next two bytes: Slide add (little-endian) |
|
236 |
||
237 |
$08 $0A: Envelope Glissando -- Frequency increasing. |
|
238 |
Like previous but with sign switched? |
|
239 |
||
240 |
$09 $0B: Set playing speed (new Delay). |
|
241 |
First byte: new delay (global number of frames per line) |
|
242 |
||
243 |
||
244 |
* Frequency Tables |
|
245 |
||
246 |
Various versions of the tracker use different frequency tables. |
|
247 |
Players lookup notes in these tables to get the proper frequency. |
|
248 |
||
249 |
The value in the frequency table field specifies up to 4 (0...3) |
|
250 |
tables, but there is an alternate set of tables if the tracker version |
|
251 |
PT3_VERSION is 3 or less. |
|
252 |
||
253 |
Presumably for space reasons, some players only support tables |
|
254 |
one and two from the newer set. |
|
255 |
||
256 |
These tables in theory can be calculated at runtime, but usually |
|
257 |
they aren't unless you are extremely space constrained. |
|
258 |
The z80 player has code to do this in z80 assembly. |
|
259 |
||
260 |
The tables are a set of 96 16-bit values (8 octaves of 12 notes) |
|
261 |
||
262 |
The frequency tables supported by Ay_Emul: |
|
263 |
||
264 |
PT3Version# Table# Frequency Table |
|
265 |
----------- ------ ====================== |
|
266 |
<=3.3 0 PT3NoteTable_PT_33_34r |
|
267 |
all 1 PT3NoteTable_ST |
|
268 |
<=3.3 2 PT3NoteTable_ASM_34r |
|
269 |
<=3.3 3 PT3NoteTable_REAL_34r |
|
270 |
||
271 |
3.4+ 0 PT3NoteTable_PT_34_35 |
|
272 |
all 1 PT3NoteTable_ST |
|
273 |
3.4+ 2 PT3NoteTable_ASM_34_35 |
|
274 |
3.4+ 3 PT3NoteTable_REAL_34_35 |
|
275 |
||
276 |
* Volume Tables |
|
277 |
||
278 |
There are multiple 256-byte amplitude/volume lookup tables |
|
279 |
These seem to have changed with different versions of Vortex Tracker |
|
280 |
so to be complete you need to contain them all and use the proper |
|
281 |
one at run time |
|
282 |
||
283 |
||
284 |
* Corner cases seen in the wild: |
|
285 |
+ What to do if the delay on an effect is set to zero? |
|
286 |
||
287 |
||
288 |
* 6-channel PT3 Files |
|
289 |
||
290 |
In the Protracker 3.7 format you can look for a turbosound header |
|
291 |
at the very end of the file. |
|
292 |
||
293 |
Type1 (4 bytes), Size (16-bits, little-endian) |
|
294 |
Type2 (4 bytes), Size (16-bits, little endian) |
|
295 |
TSID: (4 bytes) 02TS |
|
296 |
||
297 |
If the type of these files is PT3! then these are describing |
|
298 |
PT3 subfiles, and can be read as two 3-channel files which can |
|
299 |
be interpreted together as one 6-channel file. |
|
300 |
||
301 |
||
302 |
============================================================================ |
|
303 |
||
304 |
Example 1* |
|
305 |
||
306 |
So if we have this in the module: $D2,$CF,$B1,$05,$50 we will have this in the |
|
307 |
tracker: |
|
308 |
||
309 |
C-1 2..F .... |
|
310 |
--- .... .... |
|
311 |
--- .... .... |
|
312 |
--- .... .... |
|
313 |
--- .... .... |
|
314 |
||
315 |
$D2: Sample 2 ($Dx samples) |
|
316 |
$CF: Volume 15 ($Cx volume) |
|
317 |
$B1: No envelope ($Bx envelope) |
|
318 |
$05,$50: Play note $50 (C1) during five tracker lines. |
|
319 |
||
320 |
*Example 2* |
|
321 |
||
322 |
If we have this in the module: $D1,$CE,$09,$B1,$08,$50,$07 |
|
323 |
||
324 |
$D1: Sample 1. |
|
325 |
$CE: Volume 14. |
|
326 |
$09: New delay will be set. See after note is set. |
|
327 |
$B1: No envelope. |
|
328 |
$08,$50: Play note $50 (C1) during eight tracker lines. |
|
329 |
$07: New Delay. |
|
330 |
||
331 |
||
332 |
||
333 |