1 /*
2 * Adplug - Replayer for many OPL2/OPL3 audio file formats.
3 * Copyright (C) 1999 - 2003 Simon Peter, <dn.tlp@gmx.net>, et al.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 * [xad] RAT player, by Riven the Mage <riven@ok.ru>
20 */
21
22 /*
23 - discovery -
24
25 file(s) : PINA.EXE
26 type : Experimental Connection BBStro tune
27 tune : by (?)Ratt/GRIF
28 player : by (?)Ratt/GRIF
29 comment : there are bug in original replayer's adlib_init(): wrong frequency registers.
30 */
31
32 #include <cstring>
33 #include "rat.h"
34 #include "debug.h"
35
36 const unsigned char CxadratPlayer::rat_adlib_bases[18] =
37 {
38 0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11, 0x12,
39 0x03, 0x04, 0x05, 0x0B, 0x0C, 0x0D, 0x13, 0x14, 0x15
40 };
41
42 const unsigned short CxadratPlayer::rat_notes[16] =
43 {
44 0x157, 0x16B, 0x181, 0x198, 0x1B0, 0x1CA, 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287,
45 0x000, 0x000, 0x000, 0x000 // by riven
46 };
47
factory(Copl * newopl)48 CPlayer *CxadratPlayer::factory(Copl *newopl)
49 {
50 return new CxadratPlayer(newopl);
51 }
52
xadplayer_load()53 bool CxadratPlayer::xadplayer_load()
54 {
55 if(xad.fmt != RAT)
56 return false;
57
58 // load header
59 memcpy(&rat.hdr, &tune[0], sizeof(rat_header));
60
61 // is 'RAT'-signed ?
62 if (strncmp(rat.hdr.id,"RAT",3))
63 return false;
64
65 // is version 1.0 ?
66 if (rat.hdr.version != 0x10)
67 return false;
68
69 // load order
70 rat.order = &tune[0x40];
71
72 // load instruments
73 rat.inst = (rat_instrument *)&tune[0x140];
74
75 // load pattern data
76 unsigned short patseg = (rat.hdr.patseg[1] << 8) + rat.hdr.patseg[0];
77 unsigned char *event_ptr = &tune[patseg << 4];
78
79 for(int i=0;i<rat.hdr.numpat;i++)
80 for(int j=0;j<64;j++)
81 for(int k=0;k<rat.hdr.numchan;k++)
82 {
83 memcpy(&rat.tracks[i][j][k], event_ptr, sizeof(rat_event));
84
85 event_ptr += sizeof(rat_event);
86 }
87
88 return true;
89 }
90
xadplayer_rewind(int subsong)91 void CxadratPlayer::xadplayer_rewind(int subsong)
92 {
93 int i;
94
95 rat.order_pos = rat.hdr.order_start;
96 rat.pattern_pos = 0;
97 rat.volume = rat.hdr.volume;
98
99 plr.speed = rat.hdr.speed;
100
101 // clear channel data
102 memset(&rat.channel, 0, sizeof(rat.channel[0])*9);
103
104 // init OPL
105 opl_write(0x01, 0x20);
106 opl_write(0x08, 0x00);
107 opl_write(0xBD, 0x00);
108
109 // set default frequencies
110 for(i=0;i<9;i++)
111 {
112 opl_write(0xA0+i, 0x00);
113 opl_write(0xA3+i, 0x00);
114 opl_write(0xB0+i, 0x00);
115 opl_write(0xB3+i, 0x00);
116 }
117
118 // set default volumes
119 for(i=0;i<0x1F;i++)
120 opl_write(0x40+i, 0x3F);
121 }
122
xadplayer_update()123 void CxadratPlayer::xadplayer_update()
124 {
125 int i;
126
127 rat_event event;
128
129 // process events
130 for(i=0;i<rat.hdr.numchan;i++)
131 {
132 memcpy(&event,&rat.tracks[rat.order[rat.order_pos]][rat.pattern_pos][i],sizeof(rat_event));
133 #ifdef DEBUG
134 AdPlug_LogWrite("order %02X, pattern %02X, row %02X, channel %02X, event %02X %02X %02X %02X %02X:\n",
135 rat.order_pos, rat.order[rat.order_pos], rat.pattern_pos, i, event.note, event.instrument, event.volume, event.fx, event.fxp
136 );
137 #endif
138
139 // is instrument ?
140 if (event.instrument != 0xFF)
141 {
142 rat.channel[i].instrument = event.instrument - 1;
143 rat.channel[i].volume = rat.inst[event.instrument - 1].volume;
144 }
145
146 // is volume ?
147 if (event.volume != 0xFF)
148 rat.channel[i].volume = event.volume;
149
150 // is note ?
151 if (event.note != 0xFF)
152 {
153 // mute channel
154 opl_write(0xB0+i, 0x00);
155 opl_write(0xA0+i, 0x00);
156
157 // if note != 0xFE then play
158 if (event.note != 0xFE)
159 {
160 unsigned char ins = rat.channel[i].instrument;
161
162 // synthesis/feedback
163 opl_write(0xC0+i, rat.inst[ins].connect);
164
165 // controls
166 opl_write(0x20+rat_adlib_bases[i], rat.inst[ins].mod_ctrl);
167 opl_write(0x20+rat_adlib_bases[i+9], rat.inst[ins].car_ctrl);
168
169 // volumes
170 opl_write(0x40+rat_adlib_bases[i], __rat_calc_volume(rat.inst[ins].mod_volume,rat.channel[i].volume,rat.volume));
171 opl_write(0x40+rat_adlib_bases[i+9], __rat_calc_volume(rat.inst[ins].car_volume,rat.channel[i].volume,rat.volume));
172
173 // attack/decay
174 opl_write(0x60+rat_adlib_bases[i], rat.inst[ins].mod_AD);
175 opl_write(0x60+rat_adlib_bases[i+9], rat.inst[ins].car_AD);
176
177 // sustain/release
178 opl_write(0x80+rat_adlib_bases[i], rat.inst[ins].mod_SR);
179 opl_write(0x80+rat_adlib_bases[i+9], rat.inst[ins].car_SR);
180
181 // waveforms
182 opl_write(0xE0+rat_adlib_bases[i], rat.inst[ins].mod_wave);
183 opl_write(0xE0+rat_adlib_bases[i+9], rat.inst[ins].car_wave);
184
185 // octave/frequency
186 unsigned short insfreq = (rat.inst[ins].freq[1] << 8) + rat.inst[ins].freq[0];
187 unsigned short freq = insfreq * rat_notes[event.note & 0x0F] / 0x20AB;
188
189 opl_write(0xA0+i, freq & 0xFF);
190 opl_write(0xB0+i, (freq >> 8) | ((event.note & 0xF0) >> 2) | 0x20);
191 }
192 }
193
194 // is effect ?
195 if (event.fx != 0xFF)
196 {
197 rat.channel[i].fx = event.fx;
198 rat.channel[i].fxp = event.fxp;
199 }
200 }
201
202 // next row
203 rat.pattern_pos++;
204
205 // process effects
206 for(i=0;i<rat.hdr.numchan;i++)
207 {
208 unsigned char old_order_pos = rat.order_pos;
209
210 switch (rat.channel[i].fx)
211 {
212 case 0x01: // 0x01: Set Speed
213 plr.speed = rat.channel[i].fxp;
214 break;
215 case 0x02: // 0x02: Position Jump
216 if (rat.channel[i].fxp < rat.hdr.order_end)
217 rat.order_pos = rat.channel[i].fxp;
218 else
219 rat.order_pos = 0;
220
221 // jumpback ?
222 if (rat.order_pos <= old_order_pos)
223 plr.looping = 1;
224
225 rat.pattern_pos = 0;
226 break;
227 case 0x03: // 0x03: Pattern Break (?)
228 rat.pattern_pos = 0x40;
229 break;
230 }
231
232 rat.channel[i].fx = 0;
233 }
234
235 // end of pattern ?
236 if (rat.pattern_pos >= 0x40)
237 {
238 rat.pattern_pos = 0;
239
240 rat.order_pos++;
241
242 // end of module ?
243 if (rat.order_pos == rat.hdr.order_end)
244 {
245 rat.order_pos = rat.hdr.order_loop;
246
247 plr.looping = 1;
248 }
249 }
250 }
251
xadplayer_getrefresh()252 float CxadratPlayer::xadplayer_getrefresh()
253 {
254 return 60.0f;
255 }
256
xadplayer_gettype()257 std::string CxadratPlayer::xadplayer_gettype()
258 {
259 return (std::string("xad: rat player"));
260 }
261
xadplayer_gettitle()262 std::string CxadratPlayer::xadplayer_gettitle()
263 {
264 return (std::string(rat.hdr.title,32));
265 }
266
xadplayer_getinstruments()267 unsigned int CxadratPlayer::xadplayer_getinstruments()
268 {
269 return rat.hdr.numinst;
270 }
271
272 /* -------- Internal Functions ---------------------------- */
273
__rat_calc_volume(unsigned char ivol,unsigned char cvol,unsigned char gvol)274 unsigned char CxadratPlayer::__rat_calc_volume(unsigned char ivol, unsigned char cvol, unsigned char gvol)
275 {
276 #ifdef DEBUG
277 AdPlug_LogWrite("volumes: instrument %02X, channel %02X, global %02X:\n", ivol, cvol, gvol);
278 #endif
279 unsigned short vol;
280
281 vol = ivol;
282 vol &= 0x3F;
283 vol ^= 0x3F;
284 vol *= cvol;
285 vol >>= 6;
286 vol *= gvol;
287 vol >>= 6;
288 vol ^= 0x3F;
289
290 vol |= ivol & 0xC0;
291
292 return vol;
293 }
294