11---
22filename: Palladix.zip
3- flags: " M "
3+ flags: "A M "
44extension: .PLX
5- desc: Palladix System
5+ desc: Palladix Sound System
66---
7- < p > This music format is used in Logical game by Rainbow Arts Software.</ p >
7+ < p > This music format is used in Logical game by Rainbow Arts Software,
8+ as well as a few others of the time.</ p >
89
9- < p > The archive contains test music files.</ p >
10+ < p > Here is a description of the file format, as reverse-engineered from
11+ the Logical game:</ p >
12+
13+ < pre >
14+ Header
15+ ------
16+ Bytes 0-2: 'PLX' header
17+
18+ Byte 3: Bottom bit selects rhythm mode (on if set). All other bits MBZ.
19+ If bigger than 2, it seems to bail out.
20+
21+ Byte 4: Scale factor for timer info. Result = Timer * (scale_factor * 64)
22+
23+ Bytes 5-6 (WORD): Timer info (programmed to PIT via OUT 43h, 36h and then OUT 40h, low byte, OUT 40h, high byte)
24+
25+ Bytes 7-16: Array of 9 WORDS: Per-channel note data offset pointers from beginning of file
26+ If offset pointer is 0, skip this channel
27+
28+ Bytes 17...: Instruments
29+
30+ Instruments
31+ -----------
32+ Byte 0: AdLib operator data for index base C0h. Change index from base, according to channel number (see OPL2 manual).
33+ Byte 1: ? (1h in my first investigation)
34+ Bytes 2..6: AdLib modulator data for index base 20h, 40h, 60h, 80h, E0h.
35+ Bytes 7..11: AdLib carrier data for index base 23h, 43h, 63h, 83h, E3h.
36+
37+ Per-channel note data
38+ ---------------------
39+ BYTE: Contains flags
40+ Bit 0: Set instrument
41+ Load instrument to AdLib operators from file offset, specified in next WORD
42+ Bit 1: Set volume
43+ load following BYTE, store in chan_init[channel#], and in 43h + channel# (plus other stuff, depending on whether Algorithm is 0 for this channel)
44+ Bit 2: Key off
45+ Rewrite frequency block (B0h + channel#) without "key on" bit
46+ Bit 3: Set note (exclusive with "set frequency")
47+ Load next BYTE, which is the note# (must be between 0..95). Look up resulting frequency in array.
48+ AX = Get state of both frequency registers (A0 and B0 + chan#)
49+ Bit 4: Set frequency (exclusive with "set note")
50+ Load following WORD and set directly into both frequency registers
51+ Bit 5: Key on
52+ If "key on" is set, we set the "key on" bit for the channel
53+ Bit 6: Set global tempo
54+ Tempo loaded from next WORD and stored in timer
55+ Bit 7: Skip. All other bits MBZ (BYTE = 80h)
56+
57+ If BYTE = 0h, then this channel resets (restart at pattern offset 0, key off)
58+
59+ Notes
60+ -----
61+ On init, the playroutine:
62+ * Sets WAVE SELECT ENABLE in OPL2 (index 1, value 20h)
63+ * Resets all AdLib registers according to the data in
64+ opl2_init_regs.bin (found in plx.cpp in AdPlug source tree)
65+ * Byte x at offset y indicates that value x should be written into AdLib at index y, unless x == FFh, in which case we skip it
66+
67+ * Sets rhythm mode according to Byte 3.
68+
69+ * Writes 3F to all AdLib operators.
70+
71+ * Sets up timer according to timer info and scale factor
72+
73+ * Starts playing song in interrupt handler
74+ For all active channels:
75+ Read per-channel note data
76+ Reads the flag byte, processes flags from bottom to top, reading additional BYTEs and WORDs, depending on flags
77+ Read BYTE that indicates how many pattern positions to skip
78+ </ pre >
79+
80+ < p > The archive contains test music files, ripped from the Logical game.</ p >
0 commit comments