Mercurial > audlegacy
comparison Plugins/Input/adplug/core/cff.cpp @ 359:8df427a314a8 trunk
[svn] Adlib synthesizer (AdPlug) support.
| author | chainsaw |
|---|---|
| date | Fri, 30 Dec 2005 16:31:39 -0800 |
| parents | |
| children | c71e2ef2dcf4 |
comparison
equal
deleted
inserted
replaced
| 358:70075730e187 | 359:8df427a314a8 |
|---|---|
| 1 /* | |
| 2 AdPlug - Replayer for many OPL2/OPL3 audio file formats. | |
| 3 Copyright (C) 1999 - 2002 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 cff.cpp - BoomTracker loader by Riven the Mage <riven@ok.ru> | |
| 20 */ | |
| 21 /* | |
| 22 NOTE: Conversion of slides is not 100% accurate. Original volume slides | |
| 23 have effect on carrier volume only. Also, original arpeggio, frequency & volume | |
| 24 slides use previous effect data instead of current. | |
| 25 */ | |
| 26 | |
| 27 #include <stdlib.h> | |
| 28 | |
| 29 #include "cff.h" | |
| 30 | |
| 31 /* -------- Public Methods -------------------------------- */ | |
| 32 | |
| 33 CPlayer *CcffLoader::factory(Copl *newopl) | |
| 34 { | |
| 35 return new CcffLoader(newopl); | |
| 36 } | |
| 37 | |
| 38 bool CcffLoader::load(const std::string &filename, const CFileProvider &fp) | |
| 39 { | |
| 40 binistream *f = fp.open(filename); if(!f) return false; | |
| 41 const unsigned char conv_inst[11] = { 2,1,10,9,4,3,6,5,0,8,7 }; | |
| 42 const unsigned short conv_note[12] = { 0x16B, 0x181, 0x198, 0x1B0, 0x1CA, 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287, 0x2AE }; | |
| 43 | |
| 44 int i,j,k,t=0; | |
| 45 | |
| 46 // '<CUD-FM-File>' - signed ? | |
| 47 f->readString(header.id, 16); | |
| 48 header.version = f->readInt(1); header.size = f->readInt(2); | |
| 49 header.packed = f->readInt(1); f->readString((char *)header.reserved, 12); | |
| 50 if (memcmp(header.id,"<CUD-FM-File>""\x1A\xDE\xE0",16)) | |
| 51 { fp.close(f); return false; } | |
| 52 | |
| 53 unsigned char *module = new unsigned char [0x10000]; | |
| 54 | |
| 55 // packed ? | |
| 56 if (header.packed) | |
| 57 { | |
| 58 cff_unpacker *unpacker = new cff_unpacker; | |
| 59 | |
| 60 unsigned char *packed_module = new unsigned char [header.size + 4]; | |
| 61 | |
| 62 memset(packed_module,0,header.size + 4); | |
| 63 | |
| 64 f->readString((char *)packed_module, header.size); | |
| 65 fp.close(f); | |
| 66 | |
| 67 if (!unpacker->unpack(packed_module,module)) | |
| 68 { | |
| 69 delete unpacker; | |
| 70 delete packed_module; | |
| 71 delete module; | |
| 72 return false; | |
| 73 } | |
| 74 | |
| 75 delete unpacker; | |
| 76 delete packed_module; | |
| 77 | |
| 78 if (memcmp(&module[0x5E1],"CUD-FM-File - SEND A POSTCARD -",31)) | |
| 79 { | |
| 80 delete module; | |
| 81 return false; | |
| 82 } | |
| 83 } | |
| 84 else | |
| 85 { | |
| 86 f->readString((char *)module, header.size); | |
| 87 fp.close(f); | |
| 88 } | |
| 89 | |
| 90 // init CmodPlayer | |
| 91 realloc_instruments(47); | |
| 92 realloc_order(64); | |
| 93 realloc_patterns(36,64,9); | |
| 94 init_notetable(conv_note); | |
| 95 init_trackord(); | |
| 96 | |
| 97 // load instruments | |
| 98 for (i=0;i<47;i++) | |
| 99 { | |
| 100 memcpy(&instruments[i],&module[i*32],sizeof(cff_instrument)); | |
| 101 | |
| 102 for (j=0;j<11;j++) | |
| 103 inst[i].data[conv_inst[j]] = instruments[i].data[j]; | |
| 104 | |
| 105 instruments[i].name[20] = 0; | |
| 106 } | |
| 107 | |
| 108 // number of patterns | |
| 109 nop = module[0x5E0]; | |
| 110 | |
| 111 // load title & author | |
| 112 memcpy(song_title,&module[0x614],20); | |
| 113 memcpy(song_author,&module[0x600],20); | |
| 114 | |
| 115 // load order | |
| 116 memcpy(order,&module[0x628],64); | |
| 117 | |
| 118 // load tracks | |
| 119 for (i=0;i<nop;i++) | |
| 120 { | |
| 121 unsigned char old_event_byte2[9]; | |
| 122 | |
| 123 memset(old_event_byte2,0,9); | |
| 124 | |
| 125 for (j=0;j<9;j++) | |
| 126 { | |
| 127 for (k=0;k<64;k++) | |
| 128 { | |
| 129 cff_event *event = (cff_event *)&module[0x669 + ((i*64+k)*9+j)*3]; | |
| 130 | |
| 131 // convert note | |
| 132 if (event->byte0 == 0x6D) | |
| 133 tracks[t][k].note = 127; | |
| 134 else | |
| 135 if (event->byte0) | |
| 136 tracks[t][k].note = event->byte0; | |
| 137 | |
| 138 if (event->byte2) | |
| 139 old_event_byte2[j] = event->byte2; | |
| 140 | |
| 141 // convert effect | |
| 142 switch (event->byte1) | |
| 143 { | |
| 144 case 'I': // set instrument | |
| 145 tracks[t][k].inst = event->byte2 + 1; | |
| 146 tracks[t][k].param1 = tracks[t][k].param2 = 0; | |
| 147 break; | |
| 148 | |
| 149 case 'H': // set tempo | |
| 150 tracks[t][k].command = 7; | |
| 151 if (event->byte2 < 16) | |
| 152 { | |
| 153 tracks[t][k].param1 = 0x07; | |
| 154 tracks[t][k].param2 = 0x0D; | |
| 155 } | |
| 156 break; | |
| 157 | |
| 158 case 'A': // set speed | |
| 159 tracks[t][k].command = 19; | |
| 160 tracks[t][k].param1 = event->byte2 >> 4; | |
| 161 tracks[t][k].param2 = event->byte2 & 15; | |
| 162 break; | |
| 163 | |
| 164 case 'L': // pattern break | |
| 165 tracks[t][k].command = 13; | |
| 166 tracks[t][k].param1 = event->byte2 >> 4; | |
| 167 tracks[t][k].param2 = event->byte2 & 15; | |
| 168 break; | |
| 169 | |
| 170 case 'K': // order jump | |
| 171 tracks[t][k].command = 11; | |
| 172 tracks[t][k].param1 = event->byte2 >> 4; | |
| 173 tracks[t][k].param2 = event->byte2 & 15; | |
| 174 break; | |
| 175 | |
| 176 case 'M': // set vibrato/tremolo | |
| 177 tracks[t][k].command = 27; | |
| 178 tracks[t][k].param1 = event->byte2 >> 4; | |
| 179 tracks[t][k].param2 = event->byte2 & 15; | |
| 180 break; | |
| 181 | |
| 182 case 'C': // set modulator volume | |
| 183 tracks[t][k].command = 21; | |
| 184 tracks[t][k].param1 = (0x3F - event->byte2) >> 4; | |
| 185 tracks[t][k].param2 = (0x3F - event->byte2) & 15; | |
| 186 break; | |
| 187 | |
| 188 case 'G': // set carrier volume | |
| 189 tracks[t][k].command = 22; | |
| 190 tracks[t][k].param1 = (0x3F - event->byte2) >> 4; | |
| 191 tracks[t][k].param2 = (0x3F - event->byte2) & 15; | |
| 192 break; | |
| 193 | |
| 194 case 'B': // set carrier waveform | |
| 195 tracks[t][k].command = 25; | |
| 196 tracks[t][k].param1 = event->byte2; | |
| 197 tracks[t][k].param2 = 0x0F; | |
| 198 break; | |
| 199 | |
| 200 case 'E': // fine frequency slide down | |
| 201 tracks[t][k].command = 24; | |
| 202 tracks[t][k].param1 = old_event_byte2[j] >> 4; | |
| 203 tracks[t][k].param2 = old_event_byte2[j] & 15; | |
| 204 break; | |
| 205 | |
| 206 case 'F': // fine frequency slide up | |
| 207 tracks[t][k].command = 23; | |
| 208 tracks[t][k].param1 = old_event_byte2[j] >> 4; | |
| 209 tracks[t][k].param2 = old_event_byte2[j] & 15; | |
| 210 break; | |
| 211 | |
| 212 case 'D': // fine volume slide | |
| 213 tracks[t][k].command = 14; | |
| 214 if (old_event_byte2[j] & 15) | |
| 215 { | |
| 216 // slide down | |
| 217 tracks[t][k].param1 = 5; | |
| 218 tracks[t][k].param2 = old_event_byte2[j] & 15; | |
| 219 } | |
| 220 else | |
| 221 { | |
| 222 // slide up | |
| 223 tracks[t][k].param1 = 4; | |
| 224 tracks[t][k].param2 = old_event_byte2[j] >> 4; | |
| 225 } | |
| 226 break; | |
| 227 | |
| 228 case 'J': // arpeggio | |
| 229 tracks[t][k].param1 = old_event_byte2[j] >> 4; | |
| 230 tracks[t][k].param2 = old_event_byte2[j] & 15; | |
| 231 break; | |
| 232 } | |
| 233 } | |
| 234 | |
| 235 t++; | |
| 236 } | |
| 237 } | |
| 238 | |
| 239 delete [] module; | |
| 240 | |
| 241 // order loop | |
| 242 restartpos = 0; | |
| 243 | |
| 244 // order length | |
| 245 for (i=0;i<64;i++) | |
| 246 { | |
| 247 if (order[i] >= 0x80) | |
| 248 { | |
| 249 length = i; | |
| 250 break; | |
| 251 } | |
| 252 } | |
| 253 | |
| 254 // default tempo | |
| 255 bpm = 0x7D; | |
| 256 | |
| 257 rewind(0); | |
| 258 | |
| 259 return true; | |
| 260 } | |
| 261 | |
| 262 void CcffLoader::rewind(int subsong) | |
| 263 { | |
| 264 CmodPlayer::rewind(subsong); | |
| 265 | |
| 266 // default instruments | |
| 267 for (int i=0;i<9;i++) | |
| 268 { | |
| 269 channel[i].inst = i; | |
| 270 | |
| 271 channel[i].vol1 = 63 - (inst[i].data[10] & 63); | |
| 272 channel[i].vol2 = 63 - (inst[i].data[9] & 63); | |
| 273 } | |
| 274 } | |
| 275 | |
| 276 std::string CcffLoader::gettype() | |
| 277 { | |
| 278 if (header.packed) | |
| 279 return std::string("BoomTracker 4, packed"); | |
| 280 else | |
| 281 return std::string("BoomTracker 4"); | |
| 282 } | |
| 283 | |
| 284 std::string CcffLoader::gettitle() | |
| 285 { | |
| 286 return std::string(song_title,20); | |
| 287 } | |
| 288 | |
| 289 std::string CcffLoader::getauthor() | |
| 290 { | |
| 291 return std::string(song_author,20); | |
| 292 } | |
| 293 | |
| 294 std::string CcffLoader::getinstrument(unsigned int n) | |
| 295 { | |
| 296 return std::string(instruments[n].name); | |
| 297 } | |
| 298 | |
| 299 unsigned int CcffLoader::getinstruments() | |
| 300 { | |
| 301 return 47; | |
| 302 } | |
| 303 | |
| 304 /* -------- Private Methods ------------------------------- */ | |
| 305 | |
| 306 #ifdef _WIN32 | |
| 307 #pragma warning(disable:4244) | |
| 308 #pragma warning(disable:4018) | |
| 309 #endif | |
| 310 | |
| 311 /* | |
| 312 Lempel-Ziv-Tyr ;-) | |
| 313 */ | |
| 314 long CcffLoader::cff_unpacker::unpack(unsigned char *ibuf, unsigned char *obuf) | |
| 315 { | |
| 316 if (memcmp(ibuf,"YsComp""\x07""CUD1997""\x1A\x04",16)) | |
| 317 return 0; | |
| 318 | |
| 319 input = ibuf + 16; | |
| 320 output = obuf; | |
| 321 | |
| 322 output_length = 0; | |
| 323 | |
| 324 heap = (unsigned char *)malloc(0x10000); | |
| 325 dictionary = (unsigned char **)malloc(sizeof(unsigned char *)*0x8000); | |
| 326 | |
| 327 memset(heap,0,0x10000); | |
| 328 memset(dictionary,0,0x8000); | |
| 329 | |
| 330 cleanup(); | |
| 331 startup(); | |
| 332 | |
| 333 // LZW | |
| 334 while (1) | |
| 335 { | |
| 336 new_code = get_code(); | |
| 337 | |
| 338 // 0x00: end of data | |
| 339 if (new_code == 0) | |
| 340 break; | |
| 341 | |
| 342 // 0x01: end of block | |
| 343 if (new_code == 1) | |
| 344 { | |
| 345 cleanup(); | |
| 346 startup(); | |
| 347 | |
| 348 continue; | |
| 349 } | |
| 350 | |
| 351 // 0x02: expand code length | |
| 352 if (new_code == 2) | |
| 353 { | |
| 354 code_length++; | |
| 355 | |
| 356 continue; | |
| 357 } | |
| 358 | |
| 359 // 0x03: RLE | |
| 360 if (new_code == 3) | |
| 361 { | |
| 362 unsigned char old_code_length = code_length; | |
| 363 | |
| 364 code_length = 2; | |
| 365 | |
| 366 unsigned char repeat_length = get_code() + 1; | |
| 367 | |
| 368 code_length = 4 << get_code(); | |
| 369 | |
| 370 unsigned long repeat_counter = get_code(); | |
| 371 | |
| 372 for (unsigned int i=0;i<repeat_counter*repeat_length;i++) | |
| 373 output[output_length++] = output[output_length - repeat_length]; | |
| 374 | |
| 375 code_length = old_code_length; | |
| 376 | |
| 377 startup(); | |
| 378 | |
| 379 continue; | |
| 380 } | |
| 381 | |
| 382 if (new_code >= (0x104 + dictionary_length)) | |
| 383 { | |
| 384 // dictionary <- old.code.string + old.code.char | |
| 385 the_string[++the_string[0]] = the_string[1]; | |
| 386 } | |
| 387 else | |
| 388 { | |
| 389 // dictionary <- old.code.string + new.code.char | |
| 390 unsigned char temp_string[256]; | |
| 391 | |
| 392 translate_code(new_code,temp_string); | |
| 393 | |
| 394 the_string[++the_string[0]] = temp_string[1]; | |
| 395 } | |
| 396 | |
| 397 expand_dictionary(the_string); | |
| 398 | |
| 399 // output <- new.code.string | |
| 400 translate_code(new_code,the_string); | |
| 401 | |
| 402 for (int i=0;i<the_string[0];i++) | |
| 403 output[output_length++] = the_string[i+1]; | |
| 404 | |
| 405 old_code = new_code; | |
| 406 } | |
| 407 | |
| 408 free(heap); | |
| 409 free(dictionary); | |
| 410 | |
| 411 return output_length; | |
| 412 } | |
| 413 | |
| 414 unsigned long CcffLoader::cff_unpacker::get_code() | |
| 415 { | |
| 416 unsigned long code; | |
| 417 | |
| 418 while (bits_left < code_length) | |
| 419 { | |
| 420 bits_buffer |= ((*input++) << bits_left); | |
| 421 bits_left += 8; | |
| 422 } | |
| 423 | |
| 424 code = bits_buffer & ((1 << code_length) - 1); | |
| 425 | |
| 426 bits_buffer >>= code_length; | |
| 427 bits_left -= code_length; | |
| 428 | |
| 429 return code; | |
| 430 } | |
| 431 | |
| 432 void CcffLoader::cff_unpacker::translate_code(unsigned long code, unsigned char *string) | |
| 433 { | |
| 434 unsigned char translated_string[256]; | |
| 435 | |
| 436 if (code >= 0x104) | |
| 437 { | |
| 438 memcpy(translated_string,dictionary[code - 0x104],(*(dictionary[code - 0x104])) + 1); | |
| 439 } | |
| 440 else | |
| 441 { | |
| 442 translated_string[0] = 1; | |
| 443 translated_string[1] = (code - 4) & 0xFF; | |
| 444 } | |
| 445 | |
| 446 memcpy(string,translated_string,256); | |
| 447 } | |
| 448 | |
| 449 void CcffLoader::cff_unpacker::cleanup() | |
| 450 { | |
| 451 code_length = 9; | |
| 452 | |
| 453 bits_buffer = 0; | |
| 454 bits_left = 0; | |
| 455 | |
| 456 heap_length = 0; | |
| 457 dictionary_length = 0; | |
| 458 } | |
| 459 | |
| 460 void CcffLoader::cff_unpacker::startup() | |
| 461 { | |
| 462 old_code = get_code(); | |
| 463 | |
| 464 translate_code(old_code,the_string); | |
| 465 | |
| 466 for (int i=0;i<the_string[0];i++) | |
| 467 output[output_length++] = the_string[i+1]; | |
| 468 } | |
| 469 | |
| 470 void CcffLoader::cff_unpacker::expand_dictionary(unsigned char *string) | |
| 471 { | |
| 472 if (string[0] >= 0xF0) | |
| 473 return; | |
| 474 | |
| 475 memcpy(&heap[heap_length],string,string[0] + 1); | |
| 476 | |
| 477 dictionary[dictionary_length] = &heap[heap_length]; | |
| 478 | |
| 479 dictionary_length++; | |
| 480 | |
| 481 heap_length += (string[0] + 1); | |
| 482 } | |
| 483 | |
| 484 #ifdef _WIN32 | |
| 485 #pragma warning(default:4244) | |
| 486 #pragma warning(default:4018) | |
| 487 #endif |
