Mercurial > audlegacy
annotate Plugins/Input/adplug/core/rat.cpp @ 713:cf7b5a288564 trunk
[svn] rule for installing data
| author | nenolod |
|---|---|
| date | Sun, 26 Feb 2006 20:14:08 -0800 |
| parents | 15ca2ea93a30 |
| children | f12d7e208b43 |
| rev | line source |
|---|---|
| 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 | |
|
428
15ca2ea93a30
[svn] Sync with upstream CVS. This implements RIX playback.
chainsaw
parents:
359
diff
changeset
|
75 unsigned short patseg = (rat.hdr.patseg[1] << 8) + rat.hdr.patseg[0]; |
|
15ca2ea93a30
[svn] Sync with upstream CVS. This implements RIX playback.
chainsaw
parents:
359
diff
changeset
|
76 unsigned char *event_ptr = &tune[patseg << 4]; |
| 359 | 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 | |
|
428
15ca2ea93a30
[svn] Sync with upstream CVS. This implements RIX playback.
chainsaw
parents:
359
diff
changeset
|
185 unsigned short insfreq = (rat.inst[ins].freq[1] << 8) + rat.inst[ins].freq[0]; |
|
15ca2ea93a30
[svn] Sync with upstream CVS. This implements RIX playback.
chainsaw
parents:
359
diff
changeset
|
186 unsigned short freq = insfreq * rat_notes[event.note & 0x0F] / 0x20AB; |
| 359 | 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 } |
