]> 4ch.mooo.com Git - 16.git/blob - 16/adplug/adplug-2.2.1/src/rat.cpp
Please enter the commit message for your changes. Lines starting
[16.git] / 16 / adplug / adplug-2.2.1 / src / rat.cpp
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 <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
48 CPlayer *CxadratPlayer::factory(Copl *newopl)
49 {
50   return new CxadratPlayer(newopl);
51 }
52
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
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
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
252 float CxadratPlayer::xadplayer_getrefresh()
253 {
254   return 60.0f;
255 }
256
257 std::string CxadratPlayer::xadplayer_gettype()
258 {
259   return (std::string("xad: rat player"));
260 }
261
262 std::string CxadratPlayer::xadplayer_gettitle()
263 {
264   return (std::string(rat.hdr.title,32));
265 }
266
267 unsigned int CxadratPlayer::xadplayer_getinstruments()
268 {
269   return rat.hdr.numinst;
270 }
271
272 /* -------- Internal Functions ---------------------------- */
273
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 }