359
|
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "rat.h"
|
|
33 #include "debug.h"
|
|
34
|
|
35 const unsigned char CxadratPlayer::rat_adlib_bases[18] =
|
|
36 {
|
|
37 0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11, 0x12,
|
|
38 0x03, 0x04, 0x05, 0x0B, 0x0C, 0x0D, 0x13, 0x14, 0x15
|
|
39 };
|
|
40
|
|
41 const unsigned short CxadratPlayer::rat_notes[16] =
|
|
42 {
|
|
43 0x157, 0x16B, 0x181, 0x198, 0x1B0, 0x1CA, 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287,
|
|
44 0x000, 0x000, 0x000, 0x000 // by riven
|
|
45 };
|
|
46
|
|
47 CPlayer *CxadratPlayer::factory(Copl *newopl)
|
|
48 {
|
|
49 return new CxadratPlayer(newopl);
|
|
50 }
|
|
51
|
|
52 bool CxadratPlayer::xadplayer_load()
|
|
53 {
|
|
54 if(xad.fmt != RAT)
|
|
55 return false;
|
|
56
|
|
57 // load header
|
|
58 memcpy(&rat.hdr, &tune[0], sizeof(rat_header));
|
|
59
|
|
60 // is 'RAT'-signed ?
|
|
61 if (strncmp(rat.hdr.id,"RAT",3))
|
|
62 return false;
|
|
63
|
|
64 // is version 1.0 ?
|
|
65 if (rat.hdr.version != 0x10)
|
|
66 return false;
|
|
67
|
|
68 // load order
|
|
69 rat.order = &tune[0x40];
|
|
70
|
|
71 // load instruments
|
|
72 rat.inst = (rat_instrument *)&tune[0x140];
|
|
73
|
|
74 // load pattern data
|
|
75 unsigned char *event_ptr = &tune[rat.hdr.patseg << 4];
|
|
76
|
|
77 for(int i=0;i<rat.hdr.numpat;i++)
|
|
78 for(int j=0;j<64;j++)
|
|
79 for(int k=0;k<rat.hdr.numchan;k++)
|
|
80 {
|
|
81 memcpy(&rat.tracks[i][j][k], event_ptr, sizeof(rat_event));
|
|
82
|
|
83 event_ptr += sizeof(rat_event);
|
|
84 }
|
|
85
|
|
86 return true;
|
|
87 }
|
|
88
|
|
89 void CxadratPlayer::xadplayer_rewind(int subsong)
|
|
90 {
|
|
91 int i;
|
|
92
|
|
93 rat.order_pos = rat.hdr.order_start;
|
|
94 rat.pattern_pos = 0;
|
|
95 rat.volume = rat.hdr.volume;
|
|
96
|
|
97 plr.speed = rat.hdr.speed;
|
|
98
|
|
99 // clear channel data
|
|
100 memset(&rat.channel, 0, sizeof(rat.channel[0])*9);
|
|
101
|
|
102 // init OPL
|
|
103 opl_write(0x01, 0x20);
|
|
104 opl_write(0x08, 0x00);
|
|
105 opl_write(0xBD, 0x00);
|
|
106
|
|
107 // set default frequencies
|
|
108 for(i=0;i<9;i++)
|
|
109 {
|
|
110 opl_write(0xA0+i, 0x00);
|
|
111 opl_write(0xA3+i, 0x00);
|
|
112 opl_write(0xB0+i, 0x00);
|
|
113 opl_write(0xB3+i, 0x00);
|
|
114 }
|
|
115
|
|
116 // set default volumes
|
|
117 for(i=0;i<0x1F;i++)
|
|
118 opl_write(0x40+i, 0x3F);
|
|
119 }
|
|
120
|
|
121 void CxadratPlayer::xadplayer_update()
|
|
122 {
|
|
123 int i;
|
|
124
|
|
125 rat_event event;
|
|
126
|
|
127 // process events
|
|
128 for(i=0;i<rat.hdr.numchan;i++)
|
|
129 {
|
|
130 memcpy(&event,&rat.tracks[rat.order[rat.order_pos]][rat.pattern_pos][i],sizeof(rat_event));
|
|
131 #ifdef DEBUG
|
|
132 AdPlug_LogWrite("order %02X, pattern %02X, row %02X, channel %02X, event %02X %02X %02X %02X %02X:\n",
|
|
133 rat.order_pos, rat.order[rat.order_pos], rat.pattern_pos, i, event.note, event.instrument, event.volume, event.fx, event.fxp
|
|
134 );
|
|
135 #endif
|
|
136
|
|
137 // is instrument ?
|
|
138 if (event.instrument != 0xFF)
|
|
139 {
|
|
140 rat.channel[i].instrument = event.instrument - 1;
|
|
141 rat.channel[i].volume = rat.inst[event.instrument - 1].volume;
|
|
142 }
|
|
143
|
|
144 // is volume ?
|
|
145 if (event.volume != 0xFF)
|
|
146 rat.channel[i].volume = event.volume;
|
|
147
|
|
148 // is note ?
|
|
149 if (event.note != 0xFF)
|
|
150 {
|
|
151 // mute channel
|
|
152 opl_write(0xB0+i, 0x00);
|
|
153 opl_write(0xA0+i, 0x00);
|
|
154
|
|
155 // if note != 0xFE then play
|
|
156 if (event.note != 0xFE)
|
|
157 {
|
|
158 unsigned char ins = rat.channel[i].instrument;
|
|
159
|
|
160 // synthesis/feedback
|
|
161 opl_write(0xC0+i, rat.inst[ins].connect);
|
|
162
|
|
163 // controls
|
|
164 opl_write(0x20+rat_adlib_bases[i], rat.inst[ins].mod_ctrl);
|
|
165 opl_write(0x20+rat_adlib_bases[i+9], rat.inst[ins].car_ctrl);
|
|
166
|
|
167 // volumes
|
|
168 opl_write(0x40+rat_adlib_bases[i], __rat_calc_volume(rat.inst[ins].mod_volume,rat.channel[i].volume,rat.volume));
|
|
169 opl_write(0x40+rat_adlib_bases[i+9], __rat_calc_volume(rat.inst[ins].car_volume,rat.channel[i].volume,rat.volume));
|
|
170
|
|
171 // attack/decay
|
|
172 opl_write(0x60+rat_adlib_bases[i], rat.inst[ins].mod_AD);
|
|
173 opl_write(0x60+rat_adlib_bases[i+9], rat.inst[ins].car_AD);
|
|
174
|
|
175 // sustain/release
|
|
176 opl_write(0x80+rat_adlib_bases[i], rat.inst[ins].mod_SR);
|
|
177 opl_write(0x80+rat_adlib_bases[i+9], rat.inst[ins].car_SR);
|
|
178
|
|
179 // waveforms
|
|
180 opl_write(0xE0+rat_adlib_bases[i], rat.inst[ins].mod_wave);
|
|
181 opl_write(0xE0+rat_adlib_bases[i+9], rat.inst[ins].car_wave);
|
|
182
|
|
183 // octave/frequency
|
|
184 unsigned short freq = rat.inst[ins].freq * rat_notes[event.note & 0x0F] / 0x20AB;
|
|
185
|
|
186 opl_write(0xA0+i, freq & 0xFF);
|
|
187 opl_write(0xB0+i, (freq >> 8) | ((event.note & 0xF0) >> 2) | 0x20);
|
|
188 }
|
|
189 }
|
|
190
|
|
191 // is effect ?
|
|
192 if (event.fx != 0xFF)
|
|
193 {
|
|
194 rat.channel[i].fx = event.fx;
|
|
195 rat.channel[i].fxp = event.fxp;
|
|
196 }
|
|
197 }
|
|
198
|
|
199 // next row
|
|
200 rat.pattern_pos++;
|
|
201
|
|
202 // process effects
|
|
203 for(i=0;i<rat.hdr.numchan;i++)
|
|
204 {
|
|
205 unsigned char old_order_pos = rat.order_pos;
|
|
206
|
|
207 switch (rat.channel[i].fx)
|
|
208 {
|
|
209 case 0x01: // 0x01: Set Speed
|
|
210 plr.speed = rat.channel[i].fxp;
|
|
211 break;
|
|
212 case 0x02: // 0x02: Position Jump
|
|
213 if (rat.channel[i].fxp < rat.hdr.order_end)
|
|
214 rat.order_pos = rat.channel[i].fxp;
|
|
215 else
|
|
216 rat.order_pos = 0;
|
|
217
|
|
218 // jumpback ?
|
|
219 if (rat.order_pos <= old_order_pos)
|
|
220 plr.looping = 1;
|
|
221
|
|
222 rat.pattern_pos = 0;
|
|
223 break;
|
|
224 case 0x03: // 0x03: Pattern Break (?)
|
|
225 rat.pattern_pos = 0x40;
|
|
226 break;
|
|
227 }
|
|
228
|
|
229 rat.channel[i].fx = 0;
|
|
230 }
|
|
231
|
|
232 // end of pattern ?
|
|
233 if (rat.pattern_pos >= 0x40)
|
|
234 {
|
|
235 rat.pattern_pos = 0;
|
|
236
|
|
237 rat.order_pos++;
|
|
238
|
|
239 // end of module ?
|
|
240 if (rat.order_pos == rat.hdr.order_end)
|
|
241 {
|
|
242 rat.order_pos = rat.hdr.order_loop;
|
|
243
|
|
244 plr.looping = 1;
|
|
245 }
|
|
246 }
|
|
247 }
|
|
248
|
|
249 float CxadratPlayer::xadplayer_getrefresh()
|
|
250 {
|
|
251 return 60.0f;
|
|
252 }
|
|
253
|
|
254 std::string CxadratPlayer::xadplayer_gettype()
|
|
255 {
|
|
256 return (std::string("xad: rat player"));
|
|
257 }
|
|
258
|
|
259 std::string CxadratPlayer::xadplayer_gettitle()
|
|
260 {
|
|
261 return (std::string(rat.hdr.title,32));
|
|
262 }
|
|
263
|
|
264 unsigned int CxadratPlayer::xadplayer_getinstruments()
|
|
265 {
|
|
266 return rat.hdr.numinst;
|
|
267 }
|
|
268
|
|
269 /* -------- Internal Functions ---------------------------- */
|
|
270
|
|
271 unsigned char CxadratPlayer::__rat_calc_volume(unsigned char ivol, unsigned char cvol, unsigned char gvol)
|
|
272 {
|
|
273 #ifdef DEBUG
|
|
274 AdPlug_LogWrite("volumes: instrument %02X, channel %02X, global %02X:\n", ivol, cvol, gvol);
|
|
275 #endif
|
|
276 unsigned short vol;
|
|
277
|
|
278 vol = ivol;
|
|
279 vol &= 0x3F;
|
|
280 vol ^= 0x3F;
|
|
281 vol *= cvol;
|
|
282 vol >>= 6;
|
|
283 vol *= gvol;
|
|
284 vol >>= 6;
|
|
285 vol ^= 0x3F;
|
|
286
|
|
287 vol |= ivol & 0xC0;
|
|
288
|
|
289 return vol;
|
|
290 }
|