d97315ac |
1 | /* FCE Ultra - NES/Famicom Emulator\r |
2 | *\r |
3 | * Copyright notice for this file:\r |
4 | * Copyright (C) 2002 Xodnizel\r |
5 | *\r |
6 | * This program is free software; you can redistribute it and/or modify\r |
7 | * it under the terms of the GNU General Public License as published by\r |
8 | * the Free Software Foundation; either version 2 of the License, or\r |
9 | * (at your option) any later version.\r |
10 | *\r |
11 | * This program is distributed in the hope that it will be useful,\r |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of\r |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r |
14 | * GNU General Public License for more details.\r |
15 | *\r |
16 | * You should have received a copy of the GNU General Public License\r |
17 | * along with this program; if not, write to the Free Software\r |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r |
19 | */\r |
20 | \r |
21 | #include <stdio.h>\r |
22 | #include <stdlib.h>\r |
23 | #include <string.h>\r |
24 | #include <math.h>\r |
25 | \r |
26 | #include "types.h"\r |
27 | #include "x6502.h"\r |
28 | #include "fce.h"\r |
29 | #include "video.h"\r |
30 | #include "sound.h"\r |
31 | #include "nsf.h"\r |
32 | #include "general.h"\r |
33 | #include "memory.h"\r |
34 | #include "file.h"\r |
35 | #include "fds.h"\r |
36 | #include "cart.h"\r |
37 | #include "input.h"\r |
38 | \r |
39 | #include "svga.h"\r |
40 | \r |
41 | #ifndef M_PI\r |
42 | #define M_PI 3.14159265358979323846\r |
43 | #endif\r |
44 | \r |
45 | static uint8 SongReload;\r |
46 | static int CurrentSong;\r |
47 | \r |
48 | static DECLFW(NSF_write);\r |
49 | static DECLFR(NSF_read);\r |
50 | \r |
51 | static int vismode=1;\r |
52 | \r |
53 | static uint8 NSFROM[0x30+6]=\r |
54 | {\r |
55 | /* 0x00 - NMI */\r |
56 | 0x8D,0xF4,0x3F, /* Stop play routine NMIs. */\r |
57 | 0xA2,0xFF,0x9A, /* Initialize the stack pointer. */\r |
58 | 0xAD,0xF0,0x3F, /* See if we need to init. */\r |
59 | 0xF0,0x09, /* If 0, go to play routine playing. */\r |
60 | \r |
61 | 0xAD,0xF1,0x3F, /* Confirm and load A */\r |
62 | 0xAE,0xF3,0x3F, /* Load X with PAL/NTSC byte */\r |
63 | \r |
64 | 0x20,0x00,0x00, /* JSR to init routine */\r |
65 | \r |
66 | 0xA9,0x00,\r |
67 | 0xAA,\r |
68 | 0xA8,\r |
69 | 0x20,0x00,0x00, /* JSR to play routine */\r |
70 | 0x8D,0xF5,0x3F, /* Start play routine NMIs. */\r |
71 | 0x90,0xFE, /* Loopie time. */\r |
72 | \r |
73 | /* 0x20 */\r |
74 | 0x8D,0xF3,0x3F, /* Init init NMIs */\r |
75 | 0x18,\r |
76 | 0x90,0xFE /* Loopie time. */\r |
77 | };\r |
78 | \r |
79 | static DECLFR(NSFROMRead)\r |
80 | {\r |
81 | return (NSFROM-0x3800)[A];\r |
82 | }\r |
83 | \r |
84 | static int doreset=0;\r |
85 | static int NSFNMIFlags;\r |
86 | static uint8 *NSFDATA=0;\r |
87 | static int NSFMaxBank;\r |
88 | \r |
89 | static int NSFSize;\r |
90 | static uint8 BSon;\r |
91 | static uint16 PlayAddr;\r |
92 | static uint16 InitAddr;\r |
93 | static uint16 LoadAddr;\r |
94 | \r |
95 | static NSF_HEADER NSFHeader;\r |
96 | \r |
97 | void NSFMMC5_Close(void);\r |
98 | static uint8 *ExWRAM=0;\r |
99 | \r |
100 | void NSFGI(int h)\r |
101 | {\r |
102 | switch(h)\r |
103 | {\r |
104 | case GI_CLOSE:\r |
105 | if(NSFDATA) {free(NSFDATA);NSFDATA=0;}\r |
106 | if(ExWRAM) {free(ExWRAM);ExWRAM=0;}\r |
107 | if(NSFHeader.SoundChip&1) {\r |
108 | // NSFVRC6_Init();\r |
109 | } else if(NSFHeader.SoundChip&2) {\r |
110 | // NSFVRC7_Init();\r |
111 | } else if(NSFHeader.SoundChip&4) {\r |
112 | // FDSSoundReset();\r |
113 | } else if(NSFHeader.SoundChip&8) {\r |
114 | NSFMMC5_Close();\r |
115 | } else if(NSFHeader.SoundChip&0x10) {\r |
116 | // NSFN106_Init();\r |
117 | } else if(NSFHeader.SoundChip&0x20) {\r |
118 | // NSFAY_Init();\r |
119 | }\r |
120 | break;\r |
121 | case GI_RESETM2:\r |
122 | case GI_POWER: NSF_init();break;\r |
123 | }\r |
124 | }\r |
125 | \r |
126 | // First 32KB is reserved for sound chip emulation in the iNES mapper code.\r |
127 | \r |
128 | static INLINE void BANKSET(uint32 A, uint32 bank)\r |
129 | {\r |
130 | bank&=NSFMaxBank;\r |
131 | if(NSFHeader.SoundChip&4)\r |
132 | memcpy(ExWRAM+(A-0x6000),NSFDATA+(bank<<12),4096);\r |
133 | else\r |
134 | setprg4(A,bank);\r |
135 | }\r |
136 | \r |
137 | int NSFLoad(int fp)\r |
138 | {\r |
139 | int x;\r |
140 | \r |
141 | FCEU_fseek(fp,0,SEEK_SET);\r |
142 | FCEU_fread(&NSFHeader,1,0x80,fp);\r |
143 | if(memcmp(NSFHeader.ID,"NESM\x1a",5))\r |
144 | return 0;\r |
145 | NSFHeader.SongName[31]=NSFHeader.Artist[31]=NSFHeader.Copyright[31]=0;\r |
146 | \r |
147 | LoadAddr=NSFHeader.LoadAddressLow;\r |
148 | LoadAddr|=NSFHeader.LoadAddressHigh<<8;\r |
149 | \r |
150 | if(LoadAddr<0x6000)\r |
151 | {\r |
152 | FCEUD_PrintError("Invalid load address.");\r |
153 | return(0);\r |
154 | }\r |
155 | InitAddr=NSFHeader.InitAddressLow;\r |
156 | InitAddr|=NSFHeader.InitAddressHigh<<8;\r |
157 | \r |
158 | PlayAddr=NSFHeader.PlayAddressLow;\r |
159 | PlayAddr|=NSFHeader.PlayAddressHigh<<8;\r |
160 | \r |
161 | NSFSize=FCEU_fgetsize(fp)-0x80;\r |
162 | \r |
163 | NSFMaxBank=((NSFSize+(LoadAddr&0xfff)+4095)/4096);\r |
164 | NSFMaxBank=uppow2(NSFMaxBank);\r |
165 | \r |
166 | if(!(NSFDATA=(uint8 *)FCEU_malloc(NSFMaxBank*4096)))\r |
167 | return 0;\r |
168 | \r |
169 | FCEU_fseek(fp,0x80,SEEK_SET);\r |
170 | memset(NSFDATA,0x00,NSFMaxBank*4096);\r |
171 | FCEU_fread(NSFDATA+(LoadAddr&0xfff),1,NSFSize,fp);\r |
172 | \r |
173 | NSFMaxBank--;\r |
174 | \r |
175 | BSon=0;\r |
176 | for(x=0;x<8;x++)\r |
177 | BSon|=NSFHeader.BankSwitch[x];\r |
178 | \r |
179 | FCEUGameInfo.type=GIT_NSF;\r |
180 | FCEUGameInfo.input[0]=FCEUGameInfo.input[1]=SI_GAMEPAD;\r |
181 | FCEUGameInfo.cspecial=SIS_NSF;\r |
182 | \r |
183 | for(x=0;;x++)\r |
184 | {\r |
185 | if(NSFROM[x]==0x20)\r |
186 | {\r |
187 | NSFROM[x+1]=InitAddr&0xFF;\r |
188 | NSFROM[x+2]=InitAddr>>8;\r |
189 | NSFROM[x+8]=PlayAddr&0xFF;\r |
190 | NSFROM[x+9]=PlayAddr>>8;\r |
191 | break;\r |
192 | }\r |
193 | }\r |
194 | \r |
195 | if(NSFHeader.VideoSystem==0)\r |
196 | FCEUGameInfo.vidsys=GIV_NTSC;\r |
197 | else if(NSFHeader.VideoSystem==1)\r |
198 | FCEUGameInfo.vidsys=GIV_PAL;\r |
199 | \r |
200 | GameInterface=NSFGI;\r |
201 | \r |
202 | FCEU_printf("NSF Loaded. File information:\n\n");\r |
203 | FCEU_printf(" Name: %s\n Artist: %s\n Copyright: %s\n\n",NSFHeader.SongName,NSFHeader.Artist,NSFHeader.Copyright);\r |
204 | if(NSFHeader.SoundChip)\r |
205 | {\r |
206 | static char *tab[6]={"Konami VRCVI","Konami VRCVII","Nintendo FDS","Nintendo MMC5","Namco 106","Sunsoft FME-07"};\r |
207 | \r |
208 | for(x=0;x<6;x++)\r |
209 | if(NSFHeader.SoundChip&(1<<x))\r |
210 | {\r |
211 | FCEU_printf(" Expansion hardware: %s\n",tab[x]);\r |
212 | NSFHeader.SoundChip=1<<x; /* Prevent confusing weirdness if more than one bit is set. */\r |
213 | break;\r |
214 | }\r |
215 | }\r |
216 | if(BSon)\r |
217 | FCEU_printf(" Bank-switched.\n");\r |
218 | FCEU_printf(" Load address: $%04x\n Init address: $%04x\n Play address: $%04x\n",LoadAddr,InitAddr,PlayAddr);\r |
219 | FCEU_printf(" %s\n",(NSFHeader.VideoSystem&1)?"PAL":"NTSC");\r |
220 | FCEU_printf(" Starting song: %d / %d\n\n",NSFHeader.StartingSong,NSFHeader.TotalSongs);\r |
221 | \r |
222 | if(NSFHeader.SoundChip&4)\r |
223 | ExWRAM=FCEU_gmalloc(32768+8192);\r |
224 | else\r |
225 | ExWRAM=FCEU_gmalloc(8192);\r |
226 | \r |
227 | FCEUI_SetVidSystem(NSFHeader.VideoSystem);\r |
228 | \r |
229 | return 1;\r |
230 | }\r |
231 | \r |
232 | static DECLFR(NSFVectorRead)\r |
233 | {\r |
234 | if(((NSFNMIFlags&1) && SongReload) || (NSFNMIFlags&2) || doreset)\r |
235 | {\r |
236 | if(A==0xFFFA) return(0x00);\r |
237 | else if(A==0xFFFB) return(0x38);\r |
238 | else if(A==0xFFFC) return(0x20);\r |
239 | else if(A==0xFFFD) {doreset=0;return(0x38);}\r |
240 | return(X.DB);\r |
241 | }\r |
242 | else\r |
243 | return(CartBR(A));\r |
244 | }\r |
245 | \r |
246 | void NSFVRC6_Init(void);\r |
247 | void NSFVRC7_Init(void);\r |
248 | void NSFMMC5_Init(void);\r |
249 | void NSFN106_Init(void);\r |
250 | void NSFAY_Init(void);\r |
251 | \r |
252 | void NSF_init(void)\r |
253 | {\r |
254 | doreset=1;\r |
255 | \r |
256 | ResetCartMapping();\r |
257 | if(NSFHeader.SoundChip&4)\r |
258 | {\r |
259 | SetupCartPRGMapping(0,ExWRAM,32768+8192,1);\r |
260 | setprg32(0x6000,0);\r |
261 | setprg8(0xE000,4);\r |
262 | memset(ExWRAM,0x00,32768+8192);\r |
263 | SetWriteHandler(0x6000,0xDFFF,CartBW);\r |
264 | SetReadHandler(0x6000,0xFFFF,CartBR);\r |
265 | }\r |
266 | else\r |
267 | {\r |
268 | memset(ExWRAM,0x00,8192);\r |
269 | SetReadHandler(0x6000,0x7FFF,CartBR);\r |
270 | SetWriteHandler(0x6000,0x7FFF,CartBW);\r |
271 | SetupCartPRGMapping(0,NSFDATA,((NSFMaxBank+1)*4096),0);\r |
272 | SetupCartPRGMapping(1,ExWRAM,8192,1);\r |
273 | setprg8r(1,0x6000,0);\r |
274 | SetReadHandler(0x8000,0xFFFF,CartBR);\r |
275 | }\r |
276 | \r |
277 | if(BSon)\r |
278 | {\r |
279 | int32 x;\r |
280 | for(x=0;x<8;x++)\r |
281 | {\r |
282 | if(NSFHeader.SoundChip&4 && x>=6)\r |
283 | BANKSET(0x6000+(x-6)*4096,NSFHeader.BankSwitch[x]);\r |
284 | BANKSET(0x8000+x*4096,NSFHeader.BankSwitch[x]);\r |
285 | }\r |
286 | }\r |
287 | else\r |
288 | {\r |
289 | int32 x;\r |
290 | for(x=(LoadAddr&0xF000);x<0x10000;x+=0x1000)\r |
291 | BANKSET(x,((x-(LoadAddr&0x7000))>>12));\r |
292 | }\r |
293 | \r |
294 | SetReadHandler(0xFFFA,0xFFFD,NSFVectorRead);\r |
295 | \r |
296 | SetWriteHandler(0x2000,0x3fff,0);\r |
297 | SetReadHandler(0x2000,0x37ff,0);\r |
298 | SetReadHandler(0x3836,0x3FFF,0);\r |
299 | SetReadHandler(0x3800,0x3835,NSFROMRead);\r |
300 | \r |
301 | SetWriteHandler(0x5ff6,0x5fff,NSF_write);\r |
302 | \r |
303 | SetWriteHandler(0x3ff0,0x3fff,NSF_write);\r |
304 | SetReadHandler(0x3ff0,0x3fff,NSF_read);\r |
305 | \r |
306 | \r |
307 | if(NSFHeader.SoundChip&1) {\r |
308 | NSFVRC6_Init();\r |
309 | } else if(NSFHeader.SoundChip&2) {\r |
310 | NSFVRC7_Init();\r |
311 | } else if(NSFHeader.SoundChip&4) {\r |
312 | FDSSoundReset();\r |
313 | } else if(NSFHeader.SoundChip&8) {\r |
314 | NSFMMC5_Init();\r |
315 | } else if(NSFHeader.SoundChip&0x10) {\r |
316 | NSFN106_Init();\r |
317 | } else if(NSFHeader.SoundChip&0x20) {\r |
318 | NSFAY_Init();\r |
319 | }\r |
320 | CurrentSong=NSFHeader.StartingSong;\r |
321 | SongReload=0xFF;\r |
322 | NSFNMIFlags=0;\r |
323 | }\r |
324 | \r |
325 | static DECLFW(NSF_write)\r |
326 | {\r |
327 | switch(A)\r |
328 | {\r |
329 | case 0x3FF3:NSFNMIFlags|=1;break;\r |
330 | case 0x3FF4:NSFNMIFlags&=~2;break;\r |
331 | case 0x3FF5:NSFNMIFlags|=2;break;\r |
332 | \r |
333 | case 0x5FF6:\r |
334 | case 0x5FF7:if(!(NSFHeader.SoundChip&4)) return;\r |
335 | case 0x5FF8:\r |
336 | case 0x5FF9:\r |
337 | case 0x5FFA:\r |
338 | case 0x5FFB:\r |
339 | case 0x5FFC:\r |
340 | case 0x5FFD:\r |
341 | case 0x5FFE:\r |
342 | case 0x5FFF:if(!BSon) return;\r |
343 | A&=0xF;\r |
344 | BANKSET((A*4096),V);\r |
345 | break;\r |
346 | }\r |
347 | }\r |
348 | \r |
349 | static DECLFR(NSF_read)\r |
350 | {\r |
351 | int x;\r |
352 | \r |
353 | switch(A)\r |
354 | {\r |
355 | case 0x3ff0:x=SongReload;\r |
356 | if(!fceuindbg)\r |
357 | SongReload=0;\r |
358 | return x;\r |
359 | case 0x3ff1:\r |
360 | if(!fceuindbg)\r |
361 | {\r |
362 | memset(RAM,0x00,0x800);\r |
363 | \r |
364 | BWrite[0x4015](0x4015,0x0);\r |
365 | for(x=0;x<0x14;x++)\r |
366 | BWrite[0x4000+x](0x4000+x,0);\r |
367 | BWrite[0x4015](0x4015,0xF);\r |
368 | \r |
369 | if(NSFHeader.SoundChip&4)\r |
370 | {\r |
371 | BWrite[0x4017](0x4017,0xC0); /* FDS BIOS writes $C0 */\r |
372 | BWrite[0x4089](0x4089,0x80);\r |
373 | BWrite[0x408A](0x408A,0xE8);\r |
374 | }\r |
375 | else\r |
376 | {\r |
377 | memset(ExWRAM,0x00,8192);\r |
378 | BWrite[0x4017](0x4017,0xC0);\r |
379 | BWrite[0x4017](0x4017,0xC0);\r |
380 | BWrite[0x4017](0x4017,0x40);\r |
381 | }\r |
382 | \r |
383 | if(BSon)\r |
384 | {\r |
385 | for(x=0;x<8;x++)\r |
386 | BANKSET(0x8000+x*4096,NSFHeader.BankSwitch[x]);\r |
387 | }\r |
388 | return (CurrentSong-1);\r |
389 | }\r |
390 | case 0x3FF3:return PAL;\r |
391 | }\r |
392 | return 0;\r |
393 | }\r |
394 | \r |
395 | uint8 FCEU_GetJoyJoy(void);\r |
396 | \r |
397 | static int special=0;\r |
398 | \r |
399 | void DrawNSF(uint8 *XBuf)\r |
400 | {\r |
401 | char snbuf[16];\r |
402 | int x;\r |
403 | \r |
404 | if(vismode==0) return;\r |
405 | \r |
406 | memset(XBuf,0,256*240);\r |
407 | \r |
408 | \r |
409 | {\r |
410 | int32 *Bufpl;\r |
411 | int32 mul=0;\r |
412 | \r |
413 | int l;\r |
414 | l=GetSoundBuffer(&Bufpl);\r |
415 | \r |
416 | if(special==0)\r |
417 | {\r |
418 | if(FSettings.SoundVolume)\r |
419 | mul=8192*240/(16384*FSettings.SoundVolume/50);\r |
420 | for(x=0;x<256;x++)\r |
421 | {\r |
422 | uint32 y;\r |
423 | y=142+((Bufpl[(x*l)>>8]*mul)>>14);\r |
424 | if(y<240)\r |
425 | XBuf[x+y*256]=3;\r |
426 | }\r |
427 | }\r |
428 | else if(special==1)\r |
429 | {\r |
430 | if(FSettings.SoundVolume)\r |
431 | mul=8192*240/(8192*FSettings.SoundVolume/50);\r |
432 | for(x=0;x<256;x++)\r |
433 | {\r |
434 | double r;\r |
435 | uint32 xp,yp;\r |
436 | \r |
437 | r=(Bufpl[(x*l)>>8]*mul)>>14;\r |
438 | xp=128+r*cos(x*M_PI*2/256);\r |
439 | yp=120+r*sin(x*M_PI*2/256);\r |
440 | xp&=255;\r |
441 | yp%=240;\r |
442 | XBuf[xp+yp*256]=3;\r |
443 | }\r |
444 | }\r |
445 | else if(special==2)\r |
446 | {\r |
447 | static double theta=0;\r |
448 | if(FSettings.SoundVolume)\r |
449 | mul=8192*240/(16384*FSettings.SoundVolume/50);\r |
450 | for(x=0;x<128;x++)\r |
451 | {\r |
452 | double xc,yc;\r |
453 | double r,t;\r |
454 | uint32 m,n;\r |
455 | \r |
456 | xc=(double)128-x;\r |
457 | yc=0-((double)( ((Bufpl[(x*l)>>8]) *mul)>>14));\r |
458 | t=M_PI+atan(yc/xc);\r |
459 | r=sqrt(xc*xc+yc*yc);\r |
460 | \r |
461 | t+=theta;\r |
462 | m=128+r*cos(t);\r |
463 | n=120+r*sin(t);\r |
464 | \r |
465 | if(m<256 && n<240)\r |
466 | XBuf[m+n*256]=3;\r |
467 | \r |
468 | }\r |
469 | for(x=128;x<256;x++)\r |
470 | {\r |
471 | double xc,yc;\r |
472 | double r,t;\r |
473 | uint32 m,n;\r |
474 | \r |
475 | xc=(double)x-128;\r |
476 | yc=(double)((Bufpl[(x*l)>>8]*mul)>>14);\r |
477 | t=atan(yc/xc);\r |
478 | r=sqrt(xc*xc+yc*yc);\r |
479 | \r |
480 | t+=theta;\r |
481 | m=128+r*cos(t);\r |
482 | n=120+r*sin(t);\r |
483 | \r |
484 | if(m<256 && n<240)\r |
485 | XBuf[m+n*256]=3;\r |
486 | \r |
487 | }\r |
488 | theta+=(double)M_PI/256;\r |
489 | }\r |
490 | }\r |
491 | \r |
492 | DrawTextTrans(XBuf+10*256+4+(((31-strlen((char*)NSFHeader.SongName))<<2)), 256, NSFHeader.SongName, 6);\r |
493 | DrawTextTrans(XBuf+26*256+4+(((31-strlen((char*)NSFHeader.Artist))<<2)), 256,NSFHeader.Artist, 6);\r |
494 | DrawTextTrans(XBuf+42*256+4+(((31-strlen((char*)NSFHeader.Copyright))<<2)), 256,NSFHeader.Copyright, 6);\r |
495 | \r |
496 | DrawTextTrans(XBuf+70*256+4+(((31-strlen("Song:"))<<2)), 256, (uint8*)"Song:", 6);\r |
497 | sprintf(snbuf,"<%d/%d>",CurrentSong,NSFHeader.TotalSongs);\r |
498 | DrawTextTrans(XBuf+82*256+4+(((31-strlen(snbuf))<<2)), 256, (uint8*)snbuf, 6);\r |
499 | \r |
500 | {\r |
501 | static uint8 last=0;\r |
502 | uint8 tmp;\r |
503 | tmp=FCEU_GetJoyJoy();\r |
504 | if((tmp&JOY_RIGHT) && !(last&JOY_RIGHT))\r |
505 | {\r |
506 | if(CurrentSong<NSFHeader.TotalSongs)\r |
507 | {\r |
508 | CurrentSong++;\r |
509 | SongReload=0xFF;\r |
510 | }\r |
511 | }\r |
512 | else if((tmp&JOY_LEFT) && !(last&JOY_LEFT))\r |
513 | {\r |
514 | if(CurrentSong>1)\r |
515 | {\r |
516 | CurrentSong--;\r |
517 | SongReload=0xFF;\r |
518 | }\r |
519 | }\r |
520 | else if((tmp&JOY_UP) && !(last&JOY_UP))\r |
521 | {\r |
522 | CurrentSong+=10;\r |
523 | if(CurrentSong>NSFHeader.TotalSongs) CurrentSong=NSFHeader.TotalSongs;\r |
524 | SongReload=0xFF;\r |
525 | }\r |
526 | else if((tmp&JOY_DOWN) && !(last&JOY_DOWN))\r |
527 | {\r |
528 | CurrentSong-=10;\r |
529 | if(CurrentSong<1) CurrentSong=1;\r |
530 | SongReload=0xFF;\r |
531 | }\r |
532 | else if((tmp&JOY_START) && !(last&JOY_START))\r |
533 | SongReload=0xFF;\r |
534 | else if((tmp&JOY_A) && !(last&JOY_A))\r |
535 | {\r |
536 | special=(special+1)%3;\r |
537 | }\r |
538 | last=tmp;\r |
539 | }\r |
540 | }\r |
541 | \r |
542 | void DoNSFFrame(void)\r |
543 | {\r |
544 | if(((NSFNMIFlags&1) && SongReload) || (NSFNMIFlags&2))\r |
545 | TriggerNMI();\r |
546 | }\r |
547 | \r |
548 | void FCEUI_NSFSetVis(int mode)\r |
549 | {\r |
550 | vismode=mode;\r |
551 | }\r |
552 | \r |
553 | int FCEUI_NSFChange(int amount)\r |
554 | {\r |
555 | CurrentSong+=amount;\r |
556 | if(CurrentSong<1) CurrentSong=1;\r |
557 | else if(CurrentSong>NSFHeader.TotalSongs) CurrentSong=NSFHeader.TotalSongs;\r |
558 | SongReload=0xFF;\r |
559 | \r |
560 | return(CurrentSong);\r |
561 | }\r |
562 | \r |
563 | /* Returns total songs */\r |
564 | int FCEUI_NSFGetInfo(uint8 *name, uint8 *artist, uint8 *copyright, int maxlen)\r |
565 | {\r |
566 | strncpy((char*)name,(char*)NSFHeader.SongName,maxlen);\r |
567 | strncpy((char*)artist,(char*)NSFHeader.Artist,maxlen);\r |
568 | strncpy((char*)copyright,(char*)NSFHeader.Copyright,maxlen);\r |
569 | return(NSFHeader.TotalSongs);\r |
570 | }\r |