comparison src/adplug/core/rat.cxx @ 12:3da1b8942b8b trunk

[svn] - remove src/Input src/Output src/Effect src/General src/Visualization src/Container
author nenolod
date Mon, 18 Sep 2006 03:14:20 -0700
parents src/Input/adplug/core/rat.cxx@13389e613d67
children 4709ce4e209e
comparison
equal deleted inserted replaced
11:cff1d04026ae 12:3da1b8942b8b
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 "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 short patseg = (rat.hdr.patseg[1] << 8) + rat.hdr.patseg[0];
76 unsigned char *event_ptr = &tune[patseg << 4];
77
78 for(int i=0;i<rat.hdr.numpat;i++)
79 for(int j=0;j<64;j++)
80 for(int k=0;k<rat.hdr.numchan;k++)
81 {
82 memcpy(&rat.tracks[i][j][k], event_ptr, sizeof(rat_event));
83
84 event_ptr += sizeof(rat_event);
85 }
86
87 return true;
88 }
89
90 void CxadratPlayer::xadplayer_rewind(int subsong)
91 {
92 int i;
93
94 rat.order_pos = rat.hdr.order_start;
95 rat.pattern_pos = 0;
96 rat.volume = rat.hdr.volume;
97
98 plr.speed = rat.hdr.speed;
99
100 // clear channel data
101 memset(&rat.channel, 0, sizeof(rat.channel[0])*9);
102
103 // init OPL
104 opl_write(0x01, 0x20);
105 opl_write(0x08, 0x00);
106 opl_write(0xBD, 0x00);
107
108 // set default frequencies
109 for(i=0;i<9;i++)
110 {
111 opl_write(0xA0+i, 0x00);
112 opl_write(0xA3+i, 0x00);
113 opl_write(0xB0+i, 0x00);
114 opl_write(0xB3+i, 0x00);
115 }
116
117 // set default volumes
118 for(i=0;i<0x1F;i++)
119 opl_write(0x40+i, 0x3F);
120 }
121
122 void CxadratPlayer::xadplayer_update()
123 {
124 int i;
125
126 rat_event event;
127
128 // process events
129 for(i=0;i<rat.hdr.numchan;i++)
130 {
131 memcpy(&event,&rat.tracks[rat.order[rat.order_pos]][rat.pattern_pos][i],sizeof(rat_event));
132 #ifdef DEBUG
133 AdPlug_LogWrite("order %02X, pattern %02X, row %02X, channel %02X, event %02X %02X %02X %02X %02X:\n",
134 rat.order_pos, rat.order[rat.order_pos], rat.pattern_pos, i, event.note, event.instrument, event.volume, event.fx, event.fxp
135 );
136 #endif
137
138 // is instrument ?
139 if (event.instrument != 0xFF)
140 {
141 rat.channel[i].instrument = event.instrument - 1;
142 rat.channel[i].volume = rat.inst[event.instrument - 1].volume;
143 }
144
145 // is volume ?
146 if (event.volume != 0xFF)
147 rat.channel[i].volume = event.volume;
148
149 // is note ?
150 if (event.note != 0xFF)
151 {
152 // mute channel
153 opl_write(0xB0+i, 0x00);
154 opl_write(0xA0+i, 0x00);
155
156 // if note != 0xFE then play
157 if (event.note != 0xFE)
158 {
159 unsigned char ins = rat.channel[i].instrument;
160
161 // synthesis/feedback
162 opl_write(0xC0+i, rat.inst[ins].connect);
163
164 // controls
165 opl_write(0x20+rat_adlib_bases[i], rat.inst[ins].mod_ctrl);
166 opl_write(0x20+rat_adlib_bases[i+9], rat.inst[ins].car_ctrl);
167
168 // volumes
169 opl_write(0x40+rat_adlib_bases[i], __rat_calc_volume(rat.inst[ins].mod_volume,rat.channel[i].volume,rat.volume));
170 opl_write(0x40+rat_adlib_bases[i+9], __rat_calc_volume(rat.inst[ins].car_volume,rat.channel[i].volume,rat.volume));
171
172 // attack/decay
173 opl_write(0x60+rat_adlib_bases[i], rat.inst[ins].mod_AD);
174 opl_write(0x60+rat_adlib_bases[i+9], rat.inst[ins].car_AD);
175
176 // sustain/release
177 opl_write(0x80+rat_adlib_bases[i], rat.inst[ins].mod_SR);
178 opl_write(0x80+rat_adlib_bases[i+9], rat.inst[ins].car_SR);
179
180 // waveforms
181 opl_write(0xE0+rat_adlib_bases[i], rat.inst[ins].mod_wave);
182 opl_write(0xE0+rat_adlib_bases[i+9], rat.inst[ins].car_wave);
183
184 // octave/frequency
185 unsigned short insfreq = (rat.inst[ins].freq[1] << 8) + rat.inst[ins].freq[0];
186 unsigned short freq = insfreq * rat_notes[event.note & 0x0F] / 0x20AB;
187
188 opl_write(0xA0+i, freq & 0xFF);
189 opl_write(0xB0+i, (freq >> 8) | ((event.note & 0xF0) >> 2) | 0x20);
190 }
191 }
192
193 // is effect ?
194 if (event.fx != 0xFF)
195 {
196 rat.channel[i].fx = event.fx;
197 rat.channel[i].fxp = event.fxp;
198 }
199 }
200
201 // next row
202 rat.pattern_pos++;
203
204 // process effects
205 for(i=0;i<rat.hdr.numchan;i++)
206 {
207 unsigned char old_order_pos = rat.order_pos;
208
209 switch (rat.channel[i].fx)
210 {
211 case 0x01: // 0x01: Set Speed
212 plr.speed = rat.channel[i].fxp;
213 break;
214 case 0x02: // 0x02: Position Jump
215 if (rat.channel[i].fxp < rat.hdr.order_end)
216 rat.order_pos = rat.channel[i].fxp;
217 else
218 rat.order_pos = 0;
219
220 // jumpback ?
221 if (rat.order_pos <= old_order_pos)
222 plr.looping = 1;
223
224 rat.pattern_pos = 0;
225 break;
226 case 0x03: // 0x03: Pattern Break (?)
227 rat.pattern_pos = 0x40;
228 break;
229 }
230
231 rat.channel[i].fx = 0;
232 }
233
234 // end of pattern ?
235 if (rat.pattern_pos >= 0x40)
236 {
237 rat.pattern_pos = 0;
238
239 rat.order_pos++;
240
241 // end of module ?
242 if (rat.order_pos == rat.hdr.order_end)
243 {
244 rat.order_pos = rat.hdr.order_loop;
245
246 plr.looping = 1;
247 }
248 }
249 }
250
251 float CxadratPlayer::xadplayer_getrefresh()
252 {
253 return 60.0f;
254 }
255
256 std::string CxadratPlayer::xadplayer_gettype()
257 {
258 return (std::string("xad: rat player"));
259 }
260
261 std::string CxadratPlayer::xadplayer_gettitle()
262 {
263 return (std::string(rat.hdr.title,32));
264 }
265
266 unsigned int CxadratPlayer::xadplayer_getinstruments()
267 {
268 return rat.hdr.numinst;
269 }
270
271 /* -------- Internal Functions ---------------------------- */
272
273 unsigned char CxadratPlayer::__rat_calc_volume(unsigned char ivol, unsigned char cvol, unsigned char gvol)
274 {
275 #ifdef DEBUG
276 AdPlug_LogWrite("volumes: instrument %02X, channel %02X, global %02X:\n", ivol, cvol, gvol);
277 #endif
278 unsigned short vol;
279
280 vol = ivol;
281 vol &= 0x3F;
282 vol ^= 0x3F;
283 vol *= cvol;
284 vol >>= 6;
285 vol *= gvol;
286 vol >>= 6;
287 vol ^= 0x3F;
288
289 vol |= ivol & 0xC0;
290
291 return vol;
292 }