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