X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?p=fceu.git;a=blobdiff_plain;f=nsf.c;h=9e09cfb3727767d25b6a57924bbfd86d5c7cc976;hp=2db647cac7d8fb47c0bd6db782c4fca862d48b44;hb=d97315ac0bca825d2d50a44453bc5652946e2c67;hpb=890e37ba2b8ea1c7593dc05926d7431e3bd00bfb diff --git a/nsf.c b/nsf.c index 2db647c..9e09cfb 100644 --- a/nsf.c +++ b/nsf.c @@ -1,412 +1,570 @@ -/* FCE Ultra - NES/Famicom Emulator - * - * Copyright notice for this file: - * Copyright (C) 2002 Ben Parnell - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include - -#include "types.h" -#include "x6502.h" -#include "fce.h" -#include "svga.h" -#include "video.h" -#include "sound.h" -#include "ines.h" -#include "nsf.h" -#include "nsfbgnew.h" -#include "general.h" -#include "memory.h" -#include "file.h" -#include "fds.h" -#include "cart.h" -#include "input.h" - -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -uint8 SongReload; -uint8 CurrentSong; - -static int sinetable[32]; - - -static uint8 NSFROM[0x30+6]= -{ -/* 0x00 */ - -0x08,0x48,0x8A,0x48,0x98,0x48, /* Store regs */ -0xA9,0xFF, -0x8D,0xF2,0x5F, /* NMI has occured */ -0x68,0xA8,0x68,0xAA,0x68,0x28, -0x40, /* Restore regs */ - -/* 0x12 */ - -0xAD,0xF2,0x5F, /* See if an NMI occured */ -0xF0,0xFB, /* If it hasn't, loop */ - -0xA9,0x00, -0x8D,0xF2,0x5F, /* Clear play pending reg*/ - - -0xAD,0xF0,0x5F, /* See if we need to init. */ -0xF0,0x09, /* If 0, go to JMP */ - -0xAD,0xF1,0x5F, /* Confirm and load A */ -0xAE,0xF3,0x5F, /* Load X with PAL/NTSC byte */ - -0x20,0x00,0x00, /* JSR to init routine */ - -0x20,0x00,0x00, /* JSR to play routine */ - -0x4C,0x12,0x38, /* Loop */ - -0xA2,0xFF,0x9A, /* Initialize the stack pointer. */ -0x4C,0x12,0x38 -}; - -static DECLFR(NSFROMRead) -{ - return (NSFROM-0x3800)[A]; -} - - - -static uint8 *NSFDATA=0; -static int NSFMaxBank; - -static int NSFSize; -static uint8 BSon; -static uint16 PlayAddr; -static uint16 InitAddr; -static uint16 LoadAddr; - -NSF_HEADER NSFHeader; - -void NSFGI(int h) -{ - switch(h) - { - case GI_CLOSE: - if(NSFDATA) {free(NSFDATA);NSFDATA=0;} - break; - case GI_POWER: NSF_init();break; - } -} - -// First 32KB is reserved for sound chip emulation in the iNES mapper code. - -#define WRAM (GameMemBlock+32768) -#define FDSMEM (GameMemBlock+32768) - -static INLINE void BANKSET(uint32 A, uint32 bank) -{ - bank&=NSFMaxBank; - if(NSFHeader.SoundChip&4) - memcpy(FDSMEM+(A-0x6000),NSFDATA+(bank<<12),4096); - else - setprg4(A,bank); -} - -int NSFLoad(int fp) -{ - int x; - - FCEU_fseek(fp,0,SEEK_SET); - FCEU_fread(&NSFHeader,1,0x80,fp); - if (memcmp(NSFHeader.ID,"NESM\x1a",5)) - return 0; - NSFHeader.SongName[31]=NSFHeader.Artist[31]=NSFHeader.Copyright[31]=0; - - LoadAddr=NSFHeader.LoadAddressLow; - LoadAddr|=NSFHeader.LoadAddressHigh<<8; - - InitAddr=NSFHeader.InitAddressLow; - InitAddr|=NSFHeader.InitAddressHigh<<8; - - PlayAddr=NSFHeader.PlayAddressLow; - PlayAddr|=NSFHeader.PlayAddressHigh<<8; - - NSFSize=FCEU_fgetsize(fp)-0x80; - - NSFMaxBank=((NSFSize+(LoadAddr&0xfff)+4095)/4096); - NSFMaxBank=uppow2(NSFMaxBank); - - if(!(NSFDATA=(uint8 *)FCEU_malloc(NSFMaxBank*4096))) - return 0; - - FCEU_fseek(fp,0x80,SEEK_SET); - memset(NSFDATA,0x00,NSFMaxBank*4096); - FCEU_fread(NSFDATA+(LoadAddr&0xfff),1,NSFSize,fp); - - NSFMaxBank--; - - BSon=0; - for(x=0;x<8;x++) - BSon|=NSFHeader.BankSwitch[x]; - - FCEUGameInfo.type=GIT_NSF; - FCEUGameInfo.input[0]=FCEUGameInfo.input[1]=SI_NONE; - - for(x=0;;x++) - { - if(NSFROM[x]==0x20) - { - NSFROM[x+1]=InitAddr&0xFF; - NSFROM[x+2]=InitAddr>>8; - NSFROM[x+4]=PlayAddr&0xFF; - NSFROM[x+5]=PlayAddr>>8; - break; - } - } - - if(NSFHeader.VideoSystem==0) - FCEUGameInfo.vidsys=GIV_NTSC; - else if(NSFHeader.VideoSystem==1) - FCEUGameInfo.vidsys=GIV_PAL; - - { - double fruit=0; - for(x=0;x<32;x++) - { - double ta,no; - - ta=sin(fruit)*7; - ta+=modf(ta,&no); - sinetable[x]=ta; - fruit+=(double)M_PI*2/32; - } - } - GameInterface=NSFGI; - - puts("NSF Loaded. File information:\n"); - printf(" Name: %s\n Artist: %s\n Copyright: %s\n\n",NSFHeader.SongName,NSFHeader.Artist,NSFHeader.Copyright); - if(NSFHeader.SoundChip) - { - static char *tab[6]={"Konami VRCVI","Konami VRCVII","Nintendo FDS","Nintendo MMC5","Namco 106","Sunsoft FME-07"}; - for(x=0;x<6;x++) - if(NSFHeader.SoundChip&(1<=6) - BANKSET(0x6000+(x-6)*4096,NSFHeader.BankSwitch[x]); - BANKSET(0x8000+x*4096,NSFHeader.BankSwitch[x]); - } - } - else - { - int32 x; - for(x=(LoadAddr&0x7000);x<0x8000;x+=0x1000) - BANKSET(0x8000+x,((x-(LoadAddr&0x7000))>>12)); - } - - SetWriteHandler(0x2000,0x3fff,0); - SetReadHandler(0x2000,0x37ff,0); - SetReadHandler(0x3836,0x3FFF,0); - SetReadHandler(0x3800,0x3835,NSFROMRead); - - SetWriteHandler(0x4020,0x5fff,NSF_write); - SetReadHandler(0x4020,0x5fff,NSF_read); - - - if(NSFHeader.SoundChip&1) { - VRC6_ESI(0); - } else if (NSFHeader.SoundChip&2) { - VRC7_ESI(); - } else if (NSFHeader.SoundChip&4) { - FDSSoundReset(); - } else if (NSFHeader.SoundChip&8) { - Mapper5_ESI(); - } else if (NSFHeader.SoundChip&0x10) { - Mapper19_ESI(); - } else if (NSFHeader.SoundChip&0x20) { - Mapper69_ESI(); - } - CurrentSong=NSFHeader.StartingSong; - SongReload=1; -} - -static uint8 DoUpdateStuff=0; -DECLFW(NSF_write) -{ -switch(A) -{ - case 0x5FF2:if((X.PC&0xF000)==0x3000) DoUpdateStuff=V;break; - - case 0x5FF6: - case 0x5FF7:if(!(NSFHeader.SoundChip&4)) return; - case 0x5FF8: - case 0x5FF9: - case 0x5FFA: - case 0x5FFB: - case 0x5FFC: - case 0x5FFD: - case 0x5FFE: - case 0x5FFF:if(!BSon) return; - A&=0xF; - BANKSET((A*4096),V); - X6502_Rebase(); - break; -} -} - -DECLFR(NSF_read) -{ - int x; - - if((X.PC&0xF000)==0x3000) - switch(A) - { - case 0x5ff0:x=SongReload;SongReload=0;return x; - case 0x5ff1: - { - memset(RAM,0x00,0x800); - memset(WRAM,0x00,8192); - BWrite[0x4015](0x4015,0xF); - for(x=0;x<0x14;x++) - {if(x!=0x11) BWrite[0x4015](0x4015,0);} - BWrite[0x4015](0x4015,0x0); - for(x=0;x<0x14;x++) - {if(x!=0x11) BWrite[0x4015](0x4015,0);} - BWrite[0x4011](0x4011,0x40); - BWrite[0x4015](0x4015,0xF); - BWrite[0x4017](0x4017,0x40); - if(NSFHeader.SoundChip&4) - BWrite[0x4089](0x4089,0x80); - if(BSon) - { - for(x=0;x<8;x++) - BANKSET(0x8000+x*4096,NSFHeader.BankSwitch[x]); - X6502_Rebase(); - } - return (CurrentSong-1); - } - case 0x5FF2:return DoUpdateStuff; - case 0x5FF3:return PAL; - } - return 0; -} -static int32 *Bufpl; -void DrawNSF(uint8 *XBuf) -{ - char snbuf[16]; - static int z=0; - int x,y; - uint8 *XBuf2,*tmpb; - - XBuf+=8; - XBuf2=XBuf; - - tmpb=NSFBG+8; - for(y=120;y;y--) - { - uint8 *offs; - - offs=tmpb+sinetable[((z+y)>>2)&31]; - memcpy(XBuf2,offs,256); - memcpy(XBuf2+(120*272),offs,256); - - XBuf2+=272; - tmpb+=272; - } - tmpb=NSFBG+8; - z=(z+1)&127; - - DrawTextTrans(XBuf+10*272+4+(((31-strlen((char *)(NSFHeader.SongName)))<<2)), 272, NSFHeader.SongName, 38); - DrawTextTrans(XBuf+30*272+4+(((31-strlen((char *)(NSFHeader.Artist)))<<2)), 272, NSFHeader.Artist, 38); - DrawTextTrans(XBuf+50*272+4+(((31-strlen((char *)(NSFHeader.Copyright)))<<2)), 272, NSFHeader.Copyright, 38); - - DrawTextTrans(XBuf+90*272+4+(((31-strlen("Song:"))<<2)), 272, (uint8 *)"Song:", 38); - sprintf(snbuf,"<%d/%d>",CurrentSong,NSFHeader.TotalSongs); - DrawTextTrans(XBuf+102*272+4+(((31-strlen(snbuf))<<2)), 272, (uint8 *)snbuf, 38); - - GetSoundBuffer(&Bufpl); - for(x=0;x<256;x++) - XBuf[x+(224-((((Bufpl[x]>>(7)^128)&255)*3)>>3))*272]=38; -} - -void NSFControl(int z) -{ - if(z==1) - { - if(CurrentSong1) CurrentSong--; - } - SongReload=0xFF; -} +/* FCE Ultra - NES/Famicom Emulator + * + * Copyright notice for this file: + * Copyright (C) 2002 Xodnizel + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include + +#include "types.h" +#include "x6502.h" +#include "fce.h" +#include "video.h" +#include "sound.h" +#include "nsf.h" +#include "general.h" +#include "memory.h" +#include "file.h" +#include "fds.h" +#include "cart.h" +#include "input.h" + +#include "svga.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +static uint8 SongReload; +static int CurrentSong; + +static DECLFW(NSF_write); +static DECLFR(NSF_read); + +static int vismode=1; + +static uint8 NSFROM[0x30+6]= +{ +/* 0x00 - NMI */ +0x8D,0xF4,0x3F, /* Stop play routine NMIs. */ +0xA2,0xFF,0x9A, /* Initialize the stack pointer. */ +0xAD,0xF0,0x3F, /* See if we need to init. */ +0xF0,0x09, /* If 0, go to play routine playing. */ + +0xAD,0xF1,0x3F, /* Confirm and load A */ +0xAE,0xF3,0x3F, /* Load X with PAL/NTSC byte */ + +0x20,0x00,0x00, /* JSR to init routine */ + +0xA9,0x00, +0xAA, +0xA8, +0x20,0x00,0x00, /* JSR to play routine */ +0x8D,0xF5,0x3F, /* Start play routine NMIs. */ +0x90,0xFE, /* Loopie time. */ + +/* 0x20 */ +0x8D,0xF3,0x3F, /* Init init NMIs */ +0x18, +0x90,0xFE /* Loopie time. */ +}; + +static DECLFR(NSFROMRead) +{ + return (NSFROM-0x3800)[A]; +} + +static int doreset=0; +static int NSFNMIFlags; +static uint8 *NSFDATA=0; +static int NSFMaxBank; + +static int NSFSize; +static uint8 BSon; +static uint16 PlayAddr; +static uint16 InitAddr; +static uint16 LoadAddr; + +static NSF_HEADER NSFHeader; + +void NSFMMC5_Close(void); +static uint8 *ExWRAM=0; + +void NSFGI(int h) +{ + switch(h) + { + case GI_CLOSE: + if(NSFDATA) {free(NSFDATA);NSFDATA=0;} + if(ExWRAM) {free(ExWRAM);ExWRAM=0;} + if(NSFHeader.SoundChip&1) { +// NSFVRC6_Init(); + } else if(NSFHeader.SoundChip&2) { +// NSFVRC7_Init(); + } else if(NSFHeader.SoundChip&4) { +// FDSSoundReset(); + } else if(NSFHeader.SoundChip&8) { + NSFMMC5_Close(); + } else if(NSFHeader.SoundChip&0x10) { +// NSFN106_Init(); + } else if(NSFHeader.SoundChip&0x20) { +// NSFAY_Init(); + } + break; + case GI_RESETM2: + case GI_POWER: NSF_init();break; + } +} + +// First 32KB is reserved for sound chip emulation in the iNES mapper code. + +static INLINE void BANKSET(uint32 A, uint32 bank) +{ + bank&=NSFMaxBank; + if(NSFHeader.SoundChip&4) + memcpy(ExWRAM+(A-0x6000),NSFDATA+(bank<<12),4096); + else + setprg4(A,bank); +} + +int NSFLoad(int fp) +{ + int x; + + FCEU_fseek(fp,0,SEEK_SET); + FCEU_fread(&NSFHeader,1,0x80,fp); + if(memcmp(NSFHeader.ID,"NESM\x1a",5)) + return 0; + NSFHeader.SongName[31]=NSFHeader.Artist[31]=NSFHeader.Copyright[31]=0; + + LoadAddr=NSFHeader.LoadAddressLow; + LoadAddr|=NSFHeader.LoadAddressHigh<<8; + + if(LoadAddr<0x6000) + { + FCEUD_PrintError("Invalid load address."); + return(0); + } + InitAddr=NSFHeader.InitAddressLow; + InitAddr|=NSFHeader.InitAddressHigh<<8; + + PlayAddr=NSFHeader.PlayAddressLow; + PlayAddr|=NSFHeader.PlayAddressHigh<<8; + + NSFSize=FCEU_fgetsize(fp)-0x80; + + NSFMaxBank=((NSFSize+(LoadAddr&0xfff)+4095)/4096); + NSFMaxBank=uppow2(NSFMaxBank); + + if(!(NSFDATA=(uint8 *)FCEU_malloc(NSFMaxBank*4096))) + return 0; + + FCEU_fseek(fp,0x80,SEEK_SET); + memset(NSFDATA,0x00,NSFMaxBank*4096); + FCEU_fread(NSFDATA+(LoadAddr&0xfff),1,NSFSize,fp); + + NSFMaxBank--; + + BSon=0; + for(x=0;x<8;x++) + BSon|=NSFHeader.BankSwitch[x]; + + FCEUGameInfo.type=GIT_NSF; + FCEUGameInfo.input[0]=FCEUGameInfo.input[1]=SI_GAMEPAD; + FCEUGameInfo.cspecial=SIS_NSF; + + for(x=0;;x++) + { + if(NSFROM[x]==0x20) + { + NSFROM[x+1]=InitAddr&0xFF; + NSFROM[x+2]=InitAddr>>8; + NSFROM[x+8]=PlayAddr&0xFF; + NSFROM[x+9]=PlayAddr>>8; + break; + } + } + + if(NSFHeader.VideoSystem==0) + FCEUGameInfo.vidsys=GIV_NTSC; + else if(NSFHeader.VideoSystem==1) + FCEUGameInfo.vidsys=GIV_PAL; + + GameInterface=NSFGI; + + FCEU_printf("NSF Loaded. File information:\n\n"); + FCEU_printf(" Name: %s\n Artist: %s\n Copyright: %s\n\n",NSFHeader.SongName,NSFHeader.Artist,NSFHeader.Copyright); + if(NSFHeader.SoundChip) + { + static char *tab[6]={"Konami VRCVI","Konami VRCVII","Nintendo FDS","Nintendo MMC5","Namco 106","Sunsoft FME-07"}; + + for(x=0;x<6;x++) + if(NSFHeader.SoundChip&(1<=6) + BANKSET(0x6000+(x-6)*4096,NSFHeader.BankSwitch[x]); + BANKSET(0x8000+x*4096,NSFHeader.BankSwitch[x]); + } + } + else + { + int32 x; + for(x=(LoadAddr&0xF000);x<0x10000;x+=0x1000) + BANKSET(x,((x-(LoadAddr&0x7000))>>12)); + } + + SetReadHandler(0xFFFA,0xFFFD,NSFVectorRead); + + SetWriteHandler(0x2000,0x3fff,0); + SetReadHandler(0x2000,0x37ff,0); + SetReadHandler(0x3836,0x3FFF,0); + SetReadHandler(0x3800,0x3835,NSFROMRead); + + SetWriteHandler(0x5ff6,0x5fff,NSF_write); + + SetWriteHandler(0x3ff0,0x3fff,NSF_write); + SetReadHandler(0x3ff0,0x3fff,NSF_read); + + + if(NSFHeader.SoundChip&1) { + NSFVRC6_Init(); + } else if(NSFHeader.SoundChip&2) { + NSFVRC7_Init(); + } else if(NSFHeader.SoundChip&4) { + FDSSoundReset(); + } else if(NSFHeader.SoundChip&8) { + NSFMMC5_Init(); + } else if(NSFHeader.SoundChip&0x10) { + NSFN106_Init(); + } else if(NSFHeader.SoundChip&0x20) { + NSFAY_Init(); + } + CurrentSong=NSFHeader.StartingSong; + SongReload=0xFF; + NSFNMIFlags=0; +} + +static DECLFW(NSF_write) +{ + switch(A) + { + case 0x3FF3:NSFNMIFlags|=1;break; + case 0x3FF4:NSFNMIFlags&=~2;break; + case 0x3FF5:NSFNMIFlags|=2;break; + + case 0x5FF6: + case 0x5FF7:if(!(NSFHeader.SoundChip&4)) return; + case 0x5FF8: + case 0x5FF9: + case 0x5FFA: + case 0x5FFB: + case 0x5FFC: + case 0x5FFD: + case 0x5FFE: + case 0x5FFF:if(!BSon) return; + A&=0xF; + BANKSET((A*4096),V); + break; + } +} + +static DECLFR(NSF_read) +{ + int x; + + switch(A) + { + case 0x3ff0:x=SongReload; + if(!fceuindbg) + SongReload=0; + return x; + case 0x3ff1: + if(!fceuindbg) + { + memset(RAM,0x00,0x800); + + BWrite[0x4015](0x4015,0x0); + for(x=0;x<0x14;x++) + BWrite[0x4000+x](0x4000+x,0); + BWrite[0x4015](0x4015,0xF); + + if(NSFHeader.SoundChip&4) + { + BWrite[0x4017](0x4017,0xC0); /* FDS BIOS writes $C0 */ + BWrite[0x4089](0x4089,0x80); + BWrite[0x408A](0x408A,0xE8); + } + else + { + memset(ExWRAM,0x00,8192); + BWrite[0x4017](0x4017,0xC0); + BWrite[0x4017](0x4017,0xC0); + BWrite[0x4017](0x4017,0x40); + } + + if(BSon) + { + for(x=0;x<8;x++) + BANKSET(0x8000+x*4096,NSFHeader.BankSwitch[x]); + } + return (CurrentSong-1); + } + case 0x3FF3:return PAL; + } + return 0; +} + +uint8 FCEU_GetJoyJoy(void); + +static int special=0; + +void DrawNSF(uint8 *XBuf) +{ + char snbuf[16]; + int x; + + if(vismode==0) return; + + memset(XBuf,0,256*240); + + + { + int32 *Bufpl; + int32 mul=0; + + int l; + l=GetSoundBuffer(&Bufpl); + + if(special==0) + { + if(FSettings.SoundVolume) + mul=8192*240/(16384*FSettings.SoundVolume/50); + for(x=0;x<256;x++) + { + uint32 y; + y=142+((Bufpl[(x*l)>>8]*mul)>>14); + if(y<240) + XBuf[x+y*256]=3; + } + } + else if(special==1) + { + if(FSettings.SoundVolume) + mul=8192*240/(8192*FSettings.SoundVolume/50); + for(x=0;x<256;x++) + { + double r; + uint32 xp,yp; + + r=(Bufpl[(x*l)>>8]*mul)>>14; + xp=128+r*cos(x*M_PI*2/256); + yp=120+r*sin(x*M_PI*2/256); + xp&=255; + yp%=240; + XBuf[xp+yp*256]=3; + } + } + else if(special==2) + { + static double theta=0; + if(FSettings.SoundVolume) + mul=8192*240/(16384*FSettings.SoundVolume/50); + for(x=0;x<128;x++) + { + double xc,yc; + double r,t; + uint32 m,n; + + xc=(double)128-x; + yc=0-((double)( ((Bufpl[(x*l)>>8]) *mul)>>14)); + t=M_PI+atan(yc/xc); + r=sqrt(xc*xc+yc*yc); + + t+=theta; + m=128+r*cos(t); + n=120+r*sin(t); + + if(m<256 && n<240) + XBuf[m+n*256]=3; + + } + for(x=128;x<256;x++) + { + double xc,yc; + double r,t; + uint32 m,n; + + xc=(double)x-128; + yc=(double)((Bufpl[(x*l)>>8]*mul)>>14); + t=atan(yc/xc); + r=sqrt(xc*xc+yc*yc); + + t+=theta; + m=128+r*cos(t); + n=120+r*sin(t); + + if(m<256 && n<240) + XBuf[m+n*256]=3; + + } + theta+=(double)M_PI/256; + } + } + + DrawTextTrans(XBuf+10*256+4+(((31-strlen((char*)NSFHeader.SongName))<<2)), 256, NSFHeader.SongName, 6); + DrawTextTrans(XBuf+26*256+4+(((31-strlen((char*)NSFHeader.Artist))<<2)), 256,NSFHeader.Artist, 6); + DrawTextTrans(XBuf+42*256+4+(((31-strlen((char*)NSFHeader.Copyright))<<2)), 256,NSFHeader.Copyright, 6); + + DrawTextTrans(XBuf+70*256+4+(((31-strlen("Song:"))<<2)), 256, (uint8*)"Song:", 6); + sprintf(snbuf,"<%d/%d>",CurrentSong,NSFHeader.TotalSongs); + DrawTextTrans(XBuf+82*256+4+(((31-strlen(snbuf))<<2)), 256, (uint8*)snbuf, 6); + + { + static uint8 last=0; + uint8 tmp; + tmp=FCEU_GetJoyJoy(); + if((tmp&JOY_RIGHT) && !(last&JOY_RIGHT)) + { + if(CurrentSong1) + { + CurrentSong--; + SongReload=0xFF; + } + } + else if((tmp&JOY_UP) && !(last&JOY_UP)) + { + CurrentSong+=10; + if(CurrentSong>NSFHeader.TotalSongs) CurrentSong=NSFHeader.TotalSongs; + SongReload=0xFF; + } + else if((tmp&JOY_DOWN) && !(last&JOY_DOWN)) + { + CurrentSong-=10; + if(CurrentSong<1) CurrentSong=1; + SongReload=0xFF; + } + else if((tmp&JOY_START) && !(last&JOY_START)) + SongReload=0xFF; + else if((tmp&JOY_A) && !(last&JOY_A)) + { + special=(special+1)%3; + } + last=tmp; + } +} + +void DoNSFFrame(void) +{ + if(((NSFNMIFlags&1) && SongReload) || (NSFNMIFlags&2)) + TriggerNMI(); +} + +void FCEUI_NSFSetVis(int mode) +{ + vismode=mode; +} + +int FCEUI_NSFChange(int amount) +{ + CurrentSong+=amount; + if(CurrentSong<1) CurrentSong=1; + else if(CurrentSong>NSFHeader.TotalSongs) CurrentSong=NSFHeader.TotalSongs; + SongReload=0xFF; + + return(CurrentSong); +} + +/* Returns total songs */ +int FCEUI_NSFGetInfo(uint8 *name, uint8 *artist, uint8 *copyright, int maxlen) +{ + strncpy((char*)name,(char*)NSFHeader.SongName,maxlen); + strncpy((char*)artist,(char*)NSFHeader.Artist,maxlen); + strncpy((char*)copyright,(char*)NSFHeader.Copyright,maxlen); + return(NSFHeader.TotalSongs); +}