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