1 /* 2 ** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com) 3 ** 4 ** 5 ** This program is free software; you can redistribute it and/or 6 ** modify it under the terms of version 2 of the GNU Library General 7 ** Public License as published by the Free Software Foundation. 8 ** 9 ** This program is distributed in the hope that it will be useful, 10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of 11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 ** Library General Public License for more details. To obtain a 13 ** copy of the GNU Library General Public License, write to the Free 14 ** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 15 ** 16 ** Any permitted reproduction of these routines, in whole or in part, 17 ** must bear this legend. 18 ** 19 ** 20 ** nsf.c 21 ** 22 ** NSF loading/saving related functions 23 ** $Id: nsf.c,v 1.3 2003/05/01 22:34:20 benjihan Exp $ 24 */ 25 26 27 #include <stdio.h> 28 #include <string.h> 29 #include "types.h" 30 #include "nsf.h" 31 #include "log.h" 32 #include "nes6502.h" 33 #include "nes_apu.h" 34 #include "vrcvisnd.h" 35 #include "vrc7_snd.h" 36 #include "mmc5_snd.h" 37 #include "fds_snd.h" 38 39 /* TODO: bleh! should encapsulate in NSF */ 40 #define MAX_ADDRESS_HANDLERS 32 41 static nes6502_memread nsf_readhandler[MAX_ADDRESS_HANDLERS]; 42 static nes6502_memwrite nsf_writehandler[MAX_ADDRESS_HANDLERS]; 43 44 static nsf_t *cur_nsf = NULL; 45 46 static void nsf_setcontext(nsf_t *nsf) 47 { 48 ASSERT(nsf); 49 cur_nsf = nsf; 50 } 51 52 static uint8 read_mirrored_ram(uint32 address) 53 { 54 nes6502_chk_mem_access(&cur_nsf->cpu->acc_mem_page[0][address & 0x7FF], 55 NES6502_READ_ACCESS); 56 return cur_nsf->cpu->mem_page[0][address & 0x7FF]; 57 } 58 59 static void write_mirrored_ram(uint32 address, uint8 value) 60 { 61 nes6502_chk_mem_access(&cur_nsf->cpu->acc_mem_page[0][address & 0x7FF], 62 NES6502_WRITE_ACCESS); 63 cur_nsf->cpu->mem_page[0][address & 0x7FF] = value; 64 } 65 66 /* can be used for both banked and non-bankswitched NSFs */ 67 static void nsf_bankswitch(uint32 address, uint8 value) 68 { 69 int cpu_page; 70 int roffset; 71 uint8 *offset; 72 73 cpu_page = address & 0x0F; 74 roffset = -(cur_nsf->load_addr & 0x0FFF) + ((int)value << 12); 75 offset = cur_nsf->data + roffset; 76 77 nes6502_getcontext(cur_nsf->cpu); 78 cur_nsf->cpu->mem_page[cpu_page] = offset; 79 #ifdef NES6502_MEM_ACCESS_CTRL 80 cur_nsf->cpu->acc_mem_page[cpu_page] = offset + cur_nsf->length; 81 #endif 82 nes6502_setcontext(cur_nsf->cpu); 83 } 84 85 static nes6502_memread default_readhandler[] = 86 { 87 { 0x0800, 0x1FFF, read_mirrored_ram }, 88 { 0x4000, 0x4017, apu_read }, 89 { -1, -1, NULL } 90 }; 91 92 static nes6502_memwrite default_writehandler[] = 93 { 94 { 0x0800, 0x1FFF, write_mirrored_ram }, 95 { 0x4000, 0x4017, apu_write }, 96 { 0x5FF6, 0x5FFF, nsf_bankswitch }, 97 { -1, -1, NULL} 98 }; 99 100 static uint8 invalid_read(uint32 address) 101 { 102 #ifdef NOFRENDO_DEBUG 103 log_printf("filthy NSF read from $%04X\n", address); 104 #endif /* NOFRENDO_DEBUG */ 105 106 return 0xFF; 107 } 108 109 static void invalid_write(uint32 address, uint8 value) 110 { 111 #ifdef NOFRENDO_DEBUG 112 log_printf("filthy NSF tried to write $%02X to $%04X\n", value, address); 113 #endif /* NOFRENDO_DEBUG */ 114 } 115 116 /* set up the address handlers that the CPU uses */ 117 static void build_address_handlers(nsf_t *nsf) 118 { 119 int count, num_handlers; 120 121 memset(nsf_readhandler, 0, sizeof(nsf_readhandler)); 122 memset(nsf_writehandler, 0, sizeof(nsf_writehandler)); 123 124 num_handlers = 0; 125 for (count = 0; num_handlers < MAX_ADDRESS_HANDLERS; count++, num_handlers++) 126 { 127 if (NULL == default_readhandler[count].read_func) 128 break; 129 130 memcpy(&nsf_readhandler[num_handlers], &default_readhandler[count], 131 sizeof(nes6502_memread)); 132 } 133 134 if (nsf->apu->ext) 135 { 136 if (NULL != nsf->apu->ext->mem_read) 137 { 138 for (count = 0; num_handlers < MAX_ADDRESS_HANDLERS; count++, num_handlers++) 139 { 140 if (NULL == nsf->apu->ext->mem_read[count].read_func) 141 break; 142 143 memcpy(&nsf_readhandler[num_handlers], &nsf->apu->ext->mem_read[count], 144 sizeof(nes6502_memread)); 145 } 146 } 147 } 148 149 /* catch-all for bad reads */ 150 nsf_readhandler[num_handlers].min_range = 0x2000; /* min address */ 151 nsf_readhandler[num_handlers].max_range = 0x5BFF; /* max address */ 152 nsf_readhandler[num_handlers].read_func = invalid_read; /* handler */ 153 num_handlers++; 154 nsf_readhandler[num_handlers].min_range = -1; 155 nsf_readhandler[num_handlers].max_range = -1; 156 nsf_readhandler[num_handlers].read_func = NULL; 157 num_handlers++; 158 ASSERT(num_handlers <= MAX_ADDRESS_HANDLERS); 159 160 num_handlers = 0; 161 for (count = 0; num_handlers < MAX_ADDRESS_HANDLERS; count++, num_handlers++) 162 { 163 if (NULL == default_writehandler[count].write_func) 164 break; 165 166 memcpy(&nsf_writehandler[num_handlers], &default_writehandler[count], 167 sizeof(nes6502_memwrite)); 168 } 169 170 if (nsf->apu->ext) 171 { 172 if (NULL != nsf->apu->ext->mem_write) 173 { 174 for (count = 0; num_handlers < MAX_ADDRESS_HANDLERS; count++, num_handlers++) 175 { 176 if (NULL == nsf->apu->ext->mem_write[count].write_func) 177 break; 178 179 memcpy(&nsf_writehandler[num_handlers], &nsf->apu->ext->mem_write[count], 180 sizeof(nes6502_memwrite)); 181 } 182 } 183 } 184 185 /* catch-all for bad writes */ 186 nsf_writehandler[num_handlers].min_range = 0x2000; /* min address */ 187 nsf_writehandler[num_handlers].max_range = 0x5BFF; /* max address */ 188 nsf_writehandler[num_handlers].write_func = invalid_write; /* handler */ 189 num_handlers++; 190 /* protect region at $8000-$FFFF */ 191 nsf_writehandler[num_handlers].min_range = 0x8000; /* min address */ 192 nsf_writehandler[num_handlers].max_range = 0xFFFF; /* max address */ 193 nsf_writehandler[num_handlers].write_func = invalid_write; /* handler */ 194 num_handlers++; 195 nsf_writehandler[num_handlers].min_range = -1; 196 nsf_writehandler[num_handlers].max_range = -1; 197 nsf_writehandler[num_handlers].write_func = NULL; 198 num_handlers++; 199 ASSERT(num_handlers <= MAX_ADDRESS_HANDLERS); 200 } 201 202 #define NSF_ROUTINE_LOC 0x5000 203 204 /* sets up a simple loop that calls the desired routine and spins */ 205 static void nsf_setup_routine(uint32 address, uint8 a_reg, uint8 x_reg) 206 { 207 uint8 *mem; 208 209 nes6502_getcontext(cur_nsf->cpu); 210 mem = cur_nsf->cpu->mem_page[NSF_ROUTINE_LOC >> 12] + (NSF_ROUTINE_LOC & 0x0FFF); 211 212 /* our lovely 4-byte 6502 NSF player */ 213 mem[0] = 0x20; /* JSR address */ 214 mem[1] = address & 0xFF; 215 mem[2] = address >> 8; 216 mem[3] = 0xF2; /* JAM (cpu kill op) */ 217 218 cur_nsf->cpu->pc_reg = NSF_ROUTINE_LOC; 219 cur_nsf->cpu->a_reg = a_reg; 220 cur_nsf->cpu->x_reg = x_reg; 221 cur_nsf->cpu->y_reg = 0; 222 cur_nsf->cpu->s_reg = 0xFF; 223 224 nes6502_setcontext(cur_nsf->cpu); 225 } 226 227 /* retrieve any external soundchip driver */ 228 static apuext_t *nsf_getext(nsf_t *nsf) 229 { 230 switch (nsf->ext_sound_type) 231 { 232 case EXT_SOUND_VRCVI: 233 return &vrcvi_ext; 234 235 case EXT_SOUND_VRCVII: 236 return &vrc7_ext; 237 238 case EXT_SOUND_FDS: 239 return &fds_ext; 240 241 case EXT_SOUND_MMC5: 242 return &mmc5_ext; 243 244 case EXT_SOUND_NAMCO106: 245 case EXT_SOUND_SUNSOFT_FME07: 246 case EXT_SOUND_NONE: 247 default: 248 return NULL; 249 } 250 } 251 252 static void nsf_inittune(nsf_t *nsf) 253 { 254 uint8 bank, x_reg; 255 uint8 start_bank, num_banks; 256 257 memset(nsf->cpu->mem_page[0], 0, 0x800); 258 memset(nsf->cpu->mem_page[6], 0, 0x1000); 259 memset(nsf->cpu->mem_page[7], 0, 0x1000); 260 261 #ifdef NES6502_MEM_ACCESS_CTRL 262 memset(nsf->cpu->acc_mem_page[0], 0, 0x800); 263 memset(nsf->cpu->acc_mem_page[6], 0, 0x1000); 264 memset(nsf->cpu->acc_mem_page[7], 0, 0x1000); 265 memset(nsf->data+nsf->length, 0, nsf->length); 266 #endif 267 nsf->cur_frame = 0; 268 /* nsf->last_access_frame = 0; */ 269 nsf->cur_frame_end = !nsf->song_frames 270 ? 0 271 : nsf->song_frames[nsf->current_song]; 272 273 if (nsf->bankswitched) 274 { 275 /* the first hack of the NSF spec! */ 276 if (EXT_SOUND_FDS == nsf->ext_sound_type) 277 { 278 nsf_bankswitch(0x5FF6, nsf->bankswitch_info[6]); 279 nsf_bankswitch(0x5FF7, nsf->bankswitch_info[7]); 280 } 281 282 for (bank = 0; bank < 8; bank++) 283 nsf_bankswitch(0x5FF8 + bank, nsf->bankswitch_info[bank]); 284 } 285 else 286 { 287 /* not bankswitched, just page in our standard stuff */ 288 ASSERT(nsf->load_addr + nsf->length <= 0x10000); 289 290 /* avoid ripper filth */ 291 for (bank = 0; bank < 8; bank++) 292 nsf_bankswitch(0x5FF8 + bank, bank); 293 294 start_bank = nsf->load_addr >> 12; 295 num_banks = ((nsf->load_addr + nsf->length - 1) >> 12) - start_bank + 1; 296 297 for (bank = 0; bank < num_banks; bank++) 298 nsf_bankswitch(0x5FF0 + start_bank + bank, bank); 299 } 300 301 /* determine PAL/NTSC compatibility shite */ 302 if (nsf->pal_ntsc_bits & NSF_DEDICATED_PAL) 303 x_reg = 1; 304 else 305 x_reg = 0; 306 307 /* execute 1 frame or so; let init routine run free */ 308 nsf_setup_routine(nsf->init_addr, (uint8) (nsf->current_song - 1), x_reg); 309 nes6502_execute((int) NES_FRAME_CYCLES); 310 } 311 312 void nsf_frame(nsf_t *nsf) 313 { 314 //nsf_setcontext(nsf); /* future expansion =) */ 315 316 317 /* one frame of NES processing */ 318 nsf_setup_routine(nsf->play_addr, 0, 0); 319 nes6502_execute((int) NES_FRAME_CYCLES); 320 321 ++nsf->cur_frame; 322 #if defined(NES6502_MEM_ACCESS_CTRL) && 0 323 if (nes6502_mem_access) { 324 uint32 sec = 325 (nsf->last_access_frame + nsf->playback_rate - 1) / nsf->playback_rate; 326 nsf->last_access_frame = nsf->cur_frame; 327 fprintf(stderr,"nsf : memory access [%x] at frame #%u [%u:%02u]\n", 328 nes6502_mem_access, 329 nsf->last_access_frame, 330 sec/60, sec%60); 331 } 332 #endif 333 334 } 335 336 /* Deallocate memory */ 337 void nes_shutdown(nsf_t *nsf) 338 { 339 int i; 340 341 ASSERT(nsf); 342 343 if (nsf->cpu) 344 { 345 if (nsf->cpu->mem_page[0]) 346 free(nsf->cpu->mem_page[0]); 347 for (i = 5; i <= 7; i++) { 348 if (nsf->cpu->mem_page[i]) 349 free(nsf->cpu->mem_page[i]); 350 } 351 352 #ifdef NES6502_MEM_ACCESS_CTRL 353 if (nsf->cpu->acc_mem_page[0]) 354 free(nsf->cpu->acc_mem_page[0]); 355 for (i = 5; i <= 7; i++) { 356 if (nsf->cpu->acc_mem_page[i]) 357 free(nsf->cpu->acc_mem_page[i]); 358 } 359 #endif 360 free(nsf->cpu); 361 } 362 } 363 364 int nsf_init(void) 365 { 366 nes6502_init(); 367 return 0; 368 } 369 370 /* Initialize NES CPU, hardware, etc. */ 371 static int nsf_cpuinit(nsf_t *nsf) 372 { 373 int i; 374 375 nsf->cpu = malloc(sizeof(nes6502_context)); 376 if (NULL == nsf->cpu) 377 return -1; 378 379 memset(nsf->cpu, 0, sizeof(nes6502_context)); 380 381 nsf->cpu->mem_page[0] = malloc(0x800); 382 if (NULL == nsf->cpu->mem_page[0]) 383 return -1; 384 385 /* allocate some space for the NSF "player" MMC5 EXRAM, and WRAM */ 386 for (i = 5; i <= 7; i++) 387 { 388 nsf->cpu->mem_page[i] = malloc(0x1000); 389 if (NULL == nsf->cpu->mem_page[i]) 390 return -1; 391 } 392 393 #ifdef NES6502_MEM_ACCESS_CTRL 394 nsf->cpu->acc_mem_page[0] = malloc(0x800); 395 if (NULL == nsf->cpu->acc_mem_page[0]) 396 return -1; 397 /* allocate some space for the NSF "player" MMC5 EXRAM, and WRAM */ 398 for (i = 5; i <= 7; i++) 399 { 400 nsf->cpu->acc_mem_page[i] = malloc(0x1000); 401 if (NULL == nsf->cpu->acc_mem_page[i]) 402 return -1; 403 } 404 #endif 405 406 nsf->cpu->read_handler = nsf_readhandler; 407 nsf->cpu->write_handler = nsf_writehandler; 408 409 return 0; 410 } 411 412 static unsigned int nsf_playback_rate(nsf_t *nsf) 413 { 414 if (nsf->pal_ntsc_bits & NSF_DEDICATED_PAL) 415 { 416 if (nsf->pal_speed) 417 nsf->playback_rate = 1000000 / nsf->pal_speed; 418 else 419 nsf->playback_rate = 50; /* 50 Hz */ 420 } 421 else 422 { 423 if (nsf->ntsc_speed) 424 nsf->playback_rate = 1000000 / nsf->ntsc_speed; 425 else 426 nsf->playback_rate = 60; /* 60 Hz */ 427 } 428 } 429 430 static void nsf_setup(nsf_t *nsf) 431 { 432 int i; 433 434 nsf->current_song = nsf->start_song; 435 nsf_playback_rate(nsf); 436 437 nsf->bankswitched = FALSE; 438 for (i = 0; i < 8; i++) 439 { 440 if (nsf->bankswitch_info[i]) 441 { 442 nsf->bankswitched = TRUE; 443 break; 444 } 445 } 446 } 447 448 #ifdef HOST_LITTLE_ENDIAN 449 #define SWAP_16(x) (x) 450 #else /* !HOST_LITTLE_ENDIAN */ 451 #define SWAP_16(x) (((uint16) x >> 8) | (((uint16) x & 0xFF) << 8)) 452 #endif /* !HOST_LITTLE_ENDIAN */ 453 454 /* $$$ ben : find extension. Should be OK with DOS, but not with some 455 * OS like RiscOS ... */ 456 static char * find_ext(char *fn) 457 { 458 char * a, * b, * c; 459 a = strrchr(fn,'.'); 460 b = strrchr(fn,'/'); 461 c = strrchr(fn,'\\'); 462 if (a <= b || a <= c) { 463 a = 0; 464 } 465 return a; 466 } 467 468 /* $$$ ben : FILE loader */ 469 struct nsf_file_loader_t { 470 struct nsf_loader_t loader; 471 FILE *fp; 472 char * fname; 473 int name_allocated; 474 }; 475 476 static int nfs_open_file(struct nsf_loader_t *loader) 477 { 478 struct nsf_file_loader_t * floader = (struct nsf_file_loader_t *)loader; 479 480 floader->name_allocated = 0; 481 floader->fp = 0; 482 if (!floader->fname) { 483 return -1; 484 } 485 floader->fp = fopen(floader->fname,"rb"); 486 if (!floader->fp) { 487 char * fname, * ext; 488 ext = find_ext(floader->fname); 489 if (ext) { 490 /* There was an extension, so we do not change it */ 491 return -1; 492 } 493 fname = malloc(strlen(floader->fname) + 5); 494 if (!fname) { 495 return -1; 496 } 497 /* try with .nsf extension. */ 498 strcpy(fname, floader->fname); 499 strcat(fname, ".nsf"); 500 floader->fp = fopen(fname,"rb"); 501 if (!floader->fp) { 502 free(fname); 503 return -1; 504 } 505 floader->fname = fname; 506 floader->name_allocated = 1; 507 } 508 return 0; 509 } 510 511 static void nfs_close_file(struct nsf_loader_t *loader) 512 { 513 struct nsf_file_loader_t * floader = (struct nsf_file_loader_t *)loader; 514 if (floader->fp) { 515 fclose(floader->fp); 516 floader->fp = 0; 517 } 518 if (floader->fname && floader->name_allocated) { 519 free(floader->fname); 520 floader->fname = 0; 521 floader->name_allocated = 0; 522 } 523 } 524 525 static int nfs_read_file(struct nsf_loader_t *loader, void *data, int n) 526 { 527 struct nsf_file_loader_t * floader = (struct nsf_file_loader_t *)loader; 528 int r = fread(data, 1, n, floader->fp); 529 if (r >= 0) { 530 r = n-r; 531 } 532 return r; 533 } 534 535 static int nfs_length_file(struct nsf_loader_t *loader) 536 { 537 struct nsf_file_loader_t * floader = (struct nsf_file_loader_t *)loader; 538 long save, pos; 539 save = ftell(floader->fp); 540 fseek(floader->fp, 0, SEEK_END); 541 pos = ftell(floader->fp); 542 fseek(floader->fp, save, SEEK_SET); 543 return pos; 544 } 545 546 static int nfs_skip_file(struct nsf_loader_t *loader, int n) 547 { 548 struct nsf_file_loader_t * floader = (struct nsf_file_loader_t *)loader; 549 int r; 550 r = fseek(floader->fp, n, SEEK_CUR); 551 return r; 552 } 553 554 static const char * nfs_fname_file(struct nsf_loader_t *loader) 555 { 556 struct nsf_file_loader_t * floader = (struct nsf_file_loader_t *)loader; 557 return floader->fname ? floader->fname : "<null>"; 558 } 559 560 static struct nsf_file_loader_t nsf_file_loader = { 561 { 562 nfs_open_file, 563 nfs_close_file, 564 nfs_read_file, 565 nfs_length_file, 566 nfs_skip_file, 567 nfs_fname_file 568 }, 569 0,0,0 570 }; 571 572 struct nsf_mem_loader_t { 573 struct nsf_loader_t loader; 574 uint8 *data; 575 unsigned long cur; 576 unsigned long len; 577 char fname[32]; 578 }; 579 580 static int nfs_open_mem(struct nsf_loader_t *loader) 581 { 582 struct nsf_mem_loader_t * mloader = (struct nsf_mem_loader_t *)loader; 583 if (!mloader->data) { 584 return -1; 585 } 586 mloader->cur = 0; 587 sprintf(mloader->fname,"<mem(%p,%u)>", 588 mloader->data, (unsigned int)mloader->len); 589 return 0; 590 } 591 592 static void nfs_close_mem(struct nsf_loader_t *loader) 593 { 594 struct nsf_mem_loader_t * mloader = (struct nsf_mem_loader_t *)loader; 595 mloader->data = 0; 596 mloader->cur = 0; 597 mloader->len = 0; 598 } 599 600 static int nfs_read_mem(struct nsf_loader_t *loader, void *data, int n) 601 { 602 struct nsf_mem_loader_t * mloader = (struct nsf_mem_loader_t *)loader; 603 int rem; 604 if (n <= 0) { 605 return n; 606 } 607 if (!mloader->data) { 608 return -1; 609 } 610 rem = mloader->len - mloader->cur; 611 if (rem > n) { 612 rem = n; 613 } 614 memcpy(data, mloader->data + mloader->cur, rem); 615 mloader->cur += rem; 616 return n - rem; 617 } 618 619 static int nfs_length_mem(struct nsf_loader_t *loader) 620 { 621 struct nsf_mem_loader_t * mloader = (struct nsf_mem_loader_t *)loader; 622 return mloader->len; 623 } 624 625 static int nfs_skip_mem(struct nsf_loader_t *loader, int n) 626 { 627 struct nsf_mem_loader_t * mloader = (struct nsf_mem_loader_t *)loader; 628 unsigned long goal = mloader->cur + n; 629 mloader->cur = (goal > mloader->len) ? mloader->len : goal; 630 return goal - mloader->cur; 631 } 632 633 static const char * nfs_fname_mem(struct nsf_loader_t *loader) 634 { 635 struct nsf_mem_loader_t * mloader = (struct nsf_mem_loader_t *)loader; 636 return mloader->fname; 637 } 638 639 static struct nsf_mem_loader_t nsf_mem_loader = { 640 { nfs_open_mem, nfs_close_mem, nfs_read_mem, nfs_length_mem, nfs_skip_mem }, 641 0,0,0 642 }; 643 644 nsf_t * nsf_load_extended(struct nsf_loader_t * loader) 645 { 646 nsf_t *temp_nsf = 0; 647 int length; 648 char id[6]; 649 650 struct { 651 uint8 magic[4]; /* always "NESM" */ 652 uint8 type[4]; /* defines extension type */ 653 uint8 size[4]; /* extension data size (this struct include) */ 654 } nsf_file_ext; 655 656 /* no loader ! */ 657 if (!loader) { 658 return NULL; 659 } 660 661 /* Open the "file" */ 662 if (loader->open(loader) < 0) { 663 return NULL; 664 } 665 666 /* Get file size, and exit if there is not enought data for NSF header 667 * and more since it does not make sens to have header without data. 668 */ 669 length = loader->length(loader); 670 /* For version 2, we do not need file length. just check error later. */ 671 #if 0 672 if (length <= NSF_HEADER_SIZE) { 673 log_printf("nsf : [%s] not an NSF format file\n", 674 loader->fname(loader)); 675 goto error; 676 } 677 #endif 678 679 /* Read magic */ 680 if (loader->read(loader, id, 5)) { 681 log_printf("nsf : [%s] error reading magic number\n", 682 loader->fname(loader)); 683 goto error; 684 } 685 686 /* Check magic */ 687 if (memcmp(id, NSF_MAGIC, 5)) { 688 log_printf("nsf : [%s] is not an NSF format file\n", 689 loader->fname(loader)); 690 goto error; 691 } 692 693 /* $$$ ben : Now the file should be an NSF, we can start allocating. 694 * first : the nsf struct 695 */ 696 temp_nsf = malloc(sizeof(nsf_t)); 697 if (NULL == temp_nsf) { 698 log_printf("nsf : [%s] error allocating nsf header\n", 699 loader->fname(loader)); 700 goto error; 701 } 702 /* $$$ ben : safety net */ 703 memset(temp_nsf,0,sizeof(nsf_t)); 704 /* Copy magic ID */ 705 memcpy(temp_nsf,id,5); 706 707 /* Read header (without MAGIC) */ 708 if (loader->read(loader, (int8 *)temp_nsf+5, NSF_HEADER_SIZE - 5)) { 709 log_printf("nsf : [%s] error reading nsf header\n", 710 loader->fname(loader)); 711 goto error; 712 } 713 714 /* fixup endianness */ 715 temp_nsf->load_addr = SWAP_16(temp_nsf->load_addr); 716 temp_nsf->init_addr = SWAP_16(temp_nsf->init_addr); 717 temp_nsf->play_addr = SWAP_16(temp_nsf->play_addr); 718 temp_nsf->ntsc_speed = SWAP_16(temp_nsf->ntsc_speed); 719 temp_nsf->pal_speed = SWAP_16(temp_nsf->pal_speed); 720 721 /* we're now at position 80h */ 722 723 724 /* Here comes the specific codes for spec version 2 */ 725 726 temp_nsf->length = 0; 727 728 if (temp_nsf->version > 1) { 729 /* Get specified data size in reserved field (3 bytes). */ 730 temp_nsf->length = 0 731 + temp_nsf->reserved[0] 732 + (temp_nsf->reserved[1]<<8) 733 + (temp_nsf->reserved[2]<<16); 734 735 } 736 /* no specified size : try to guess with file length. */ 737 if (!temp_nsf->length) { 738 temp_nsf->length = length - NSF_HEADER_SIZE; 739 } 740 741 if (temp_nsf->length <= 0) { 742 log_printf("nsf : [%s] not an NSF format file (missing data)\n", 743 loader->fname(loader)); 744 goto error; 745 } 746 747 /* Allocate NSF space, and load it up! */ 748 { 749 int len = temp_nsf->length; 750 #ifdef NES6502_MEM_ACCESS_CTRL 751 /* $$$ twice memory for access control shadow mem. */ 752 len <<= 1; 753 #endif 754 temp_nsf->data = malloc(len); 755 } 756 if (NULL == temp_nsf->data) { 757 log_printf("nsf : [%s] error allocating nsf data\n", 758 loader->fname(loader)); 759 goto error; 760 } 761 762 /* Read data */ 763 if (loader->read(loader, temp_nsf->data, temp_nsf->length)) { 764 log_printf("nsf : [%s] error reading NSF data\n", 765 loader->fname(loader)); 766 goto error; 767 } 768 769 /* Here comes the second part of spec > 1 : get extension */ 770 while (!loader->read(loader, &nsf_file_ext, sizeof(nsf_file_ext)) 771 && !memcmp(nsf_file_ext.magic,id,4)) { 772 /* Got a NESM extension here. Checks for known extension type : 773 * right now, the only extension is "TIME" which give songs length. 774 * in frames. 775 */ 776 int size; 777 size = 0 778 + nsf_file_ext.size[0] 779 + (nsf_file_ext.size[1] << 8) 780 + (nsf_file_ext.size[2] << 16) 781 + (nsf_file_ext.size[3] << 24); 782 783 if (size < sizeof(nsf_file_ext)) { 784 log_printf("nsf : [%s] corrupt extension size (%d)\n", 785 loader->fname(loader), size); 786 /* Not a fatal error here. Just skip extension loading. */ 787 break; 788 } 789 size -= sizeof(nsf_file_ext); 790 791 if (!temp_nsf->song_frames 792 && !memcmp(nsf_file_ext.type,"TIME", 4) 793 && !(size & 3) 794 && (size >= 2*4) 795 && (size <= 256*4)) { 796 797 uint8 tmp_time[256][4]; 798 int tsongs = size >> 2; 799 int i; 800 int songs = temp_nsf->num_songs; 801 802 /* Add 1 for 0 which contains total time for all songs. */ 803 ++songs; 804 805 if (loader->read(loader, tmp_time, size)) { 806 log_printf("nsf : [%s] missing extension data\n", 807 loader->fname(loader)); 808 /* Not a fatal error here. Just skip extension loading. */ 809 break; 810 } 811 /* Alloc song_frames for songs (not tsongs). */ 812 temp_nsf->song_frames = malloc(sizeof(*temp_nsf->song_frames) * songs); 813 if (!temp_nsf->song_frames) { 814 log_printf("nsf : [%s] extension alloc failed\n", 815 loader->fname(loader)); 816 /* Not a fatal error here. Just skip extension loading. */ 817 break; 818 } 819 820 if (tsongs > songs) { 821 tsongs = songs; 822 } 823 824 /* Copy time info. */ 825 for (i=0; i<tsongs; ++i) { 826 temp_nsf->song_frames[i] = 0 827 | tmp_time[i][0] 828 | (tmp_time[i][1] << 8) 829 | (tmp_time[i][2] << 16) 830 | (tmp_time[i][2] << 24); 831 } 832 /* Clear missing (safety net). */ 833 for (; i<songs; ++i) { 834 temp_nsf->song_frames[i] = 0; 835 } 836 } else if (loader->skip(loader, size)) { 837 log_printf("nsf : [%s] extension skip failed\n", 838 loader->fname(loader)); 839 /* Not a fatal error here. Just skip extension loading. */ 840 break; 841 } 842 } 843 844 845 /* Close "file" */ 846 loader->close(loader); 847 loader = 0; 848 849 /* Set up some variables */ 850 nsf_setup(temp_nsf); 851 temp_nsf->apu = NULL; /* just make sure */ 852 853 if (nsf_cpuinit(temp_nsf)) { 854 log_printf("nsf : error cpu init\n"); 855 goto error; 856 } 857 return temp_nsf; 858 859 /* $$$ ben : some people tell that goto are not clean. I am not agree with 860 * them. In most case, it allow to avoid code duplications, which are as 861 * most people know a source of error... Here we are sure of being ckean 862 */ 863 error: 864 if (loader) { 865 loader->close(loader); 866 } 867 if (temp_nsf) { 868 nsf_free(&temp_nsf); 869 } 870 return 0; 871 } 872 873 /* Load a ROM image into memory */ 874 nsf_t *nsf_load(const char *filename, void *source, int length) 875 { 876 struct nsf_loader_t * loader = 0; 877 878 /* $$$ ben : new loader */ 879 if (filename) { 880 nsf_file_loader.fname = (char *)filename; 881 loader = &nsf_file_loader.loader; 882 } else { 883 nsf_mem_loader.data = source; 884 nsf_mem_loader.len = length; 885 nsf_mem_loader.fname[0] = 0; 886 loader = &nsf_mem_loader.loader; 887 } 888 return nsf_load_extended(loader); 889 } 890 891 /* Free an NSF */ 892 void nsf_free(nsf_t **pnsf) 893 { 894 nsf_t *nsf; 895 896 if (!pnsf) { 897 return; 898 } 899 900 nsf = *pnsf; 901 /* $$$ ben : Don't see why passing a pointer to pointer 902 * is not to clear it :) */ 903 *pnsf = 0; 904 905 if (nsf) { 906 if (nsf->apu) 907 apu_destroy(nsf->apu); 908 909 nes_shutdown(nsf); 910 911 if (nsf->data) 912 free(nsf->data); 913 914 if (nsf->song_frames) { 915 free (nsf->song_frames); 916 } 917 918 free(nsf); 919 920 } 921 } 922 923 int nsf_setchan(nsf_t *nsf, int chan, boolean enabled) 924 { 925 if (!nsf) 926 return -1; 927 928 nsf_setcontext(nsf); 929 return apu_setchan(chan, enabled); 930 } 931 932 int nsf_playtrack(nsf_t *nsf, int track, int sample_rate, int sample_bits, 933 boolean stereo) 934 { 935 if (!nsf) { 936 return -1; 937 } 938 939 /* make this NSF the current context */ 940 nsf_setcontext(nsf); 941 942 /* create the APU */ 943 if (nsf->apu) { 944 apu_destroy(nsf->apu); 945 } 946 947 nsf->apu = apu_create(sample_rate, nsf->playback_rate, sample_bits, stereo); 948 if (NULL == nsf->apu) 949 { 950 /* $$$ ben : from my point of view this is not clean. Function should 951 * never destroy object it has not created... 952 */ 953 /* nsf_free(&nsf); */ 954 return -1; 955 } 956 957 apu_setext(nsf->apu, nsf_getext(nsf)); 958 959 /* go ahead and init all the read/write handlers */ 960 build_address_handlers(nsf); 961 962 /* convenience? */ 963 nsf->process = nsf->apu->process; 964 965 nes6502_setcontext(nsf->cpu); 966 967 if (track > nsf->num_songs) 968 track = nsf->num_songs; 969 else if (track < 1) 970 track = 1; 971 972 nsf->current_song = track; 973 974 apu_reset(); 975 976 nsf_inittune(nsf); 977 978 return nsf->current_song; 979 } 980 981 int nsf_setfilter(nsf_t *nsf, int filter_type) 982 { 983 if (!nsf) { 984 return -1; 985 } 986 nsf_setcontext(nsf); 987 return apu_setfilter(filter_type); 988 } 989 990 /* 991 ** $Log: nsf.c,v $ 992 ** Revision 1.3 2003/05/01 22:34:20 benjihan 993 ** New NSF plugin 994 ** 995 ** Revision 1.2 2003/04/09 14:50:32 ben 996 ** Clean NSF api. 997 ** 998 ** Revision 1.1 2003/04/08 20:53:00 ben 999 ** Adding more files... 1000 ** 1001 ** Revision 1.14 2000/07/05 14:54:45 matt 1002 ** fix for naughty Crystalis rip 1003 ** 1004 ** Revision 1.13 2000/07/04 04:59:38 matt 1005 ** removed DOS-specific stuff, fixed bug in address handlers 1006 ** 1007 ** Revision 1.12 2000/07/03 02:19:36 matt 1008 ** dynamic address range handlers, cleaner and faster 1009 ** 1010 ** Revision 1.11 2000/06/23 03:27:58 matt 1011 ** cleaned up external sound inteface 1012 ** 1013 ** Revision 1.10 2000/06/20 20:42:47 matt 1014 ** accuracy changes 1015 ** 1016 ** Revision 1.9 2000/06/20 00:05:58 matt 1017 ** changed to driver-based external sound generation 1018 ** 1019 ** Revision 1.8 2000/06/13 03:51:54 matt 1020 ** update API to take freq/sample data on nsf_playtrack 1021 ** 1022 ** Revision 1.7 2000/06/12 03:57:14 matt 1023 ** more robust checking for winamp plugin 1024 ** 1025 ** Revision 1.6 2000/06/12 01:13:00 matt 1026 ** added CPU/APU as members of the nsf struct 1027 ** 1028 ** Revision 1.5 2000/06/11 16:09:21 matt 1029 ** nsf_free is more robust 1030 ** 1031 ** Revision 1.4 2000/06/09 15:12:26 matt 1032 ** initial revision 1033 ** 1034 */ 1035