From c0ad9bb60f5f26414eb4a99d63ba6dd1e158e22c Mon Sep 17 00:00:00 2001 From: FIX94 Date: Tue, 27 Jun 2017 06:44:22 +0200 Subject: [PATCH] -added nsf track display instead of it being console only -made audio 16-bit short instead of 32-bit float to improve performance -added some actual messages when it didnt find a file or had a problem with it instead of instantly closing the emulator --- apu.c | 119 +++++++++++++++++++++++++++++------- audio.c | 7 ++- build_linux.sh | 2 +- build_msys32.sh | 2 +- build_windows_console.bat | 2 +- build_windows_noconsole.bat | 2 +- main.c | 111 +++++++++++++++++++++++---------- mapper/nsf.c | 30 +++++---- mapper_h/nsf.h | 1 + ppu.c | 96 +++++++++++++++++++++++++++++ ppu.h | 2 + 11 files changed, 301 insertions(+), 73 deletions(-) diff --git a/apu.c b/apu.c index 692a8fb..160befc 100644 --- a/apu.c +++ b/apu.c @@ -34,10 +34,15 @@ #define DMC_IRQ_ENABLE (1<<7) static uint8_t APU_IO_Reg[0x18]; - +#if AUDIO_FLOAT static float lpVal; static float hpVal; static float *apuOutBuf; +#else +static int32_t lpVal; +static int32_t hpVal; +static int16_t *apuOutBuf; +#endif static uint32_t apuBufSize; static uint32_t apuBufSizeBytes; static uint32_t curBufPos; @@ -80,10 +85,13 @@ typedef struct _sweep_t { } sweep_t; static sweep_t p1Sweep, p2Sweep; - +#if AUDIO_FLOAT static float pulseLookupTbl[32]; static float tndLookupTbl[204]; - +#else +static int32_t pulseLookupTbl[32]; +static int32_t tndLookupTbl[204]; +#endif //used externally const uint8_t lengthLookupTbl[0x20] = { 10,254, 20, 2, 40, 4, 80, 6, 160, 8, 60, 10, 14, 12, 26, 14, @@ -155,26 +163,48 @@ void apuInitBufs() //effective frequencies for 50.000Hz and 60.000Hz Video out //apuFrequency = nesPAL ? 831187 : 893415; //effective frequencies for Original PPU Video out - apuFrequency = nesPAL ? 831303 : 894886; + //apuFrequency = nesPAL ? 831303 : 894886; + apuFrequency = nesPAL ? 207825 : 223721; double dt = 1.0/((double)apuFrequency); //LP at 22kHz double rc = 1.0/(M_2_PI * 22000.0); +#if AUDIO_FLOAT lpVal = dt / (rc + dt); +#else + //convert to 32bit int for calcs later + lpVal = (int32_t)((dt / (rc + dt))*32768.0); +#endif //HP at 40Hz rc = 1.0/(M_2_PI * 40.0); +#if AUDIO_FLOAT hpVal = rc / (rc + dt); - - apuBufSize = apuFrequency/60; +#else + //convert to 32bit int for calcs later + hpVal = (int32_t)((rc / (rc + dt))*32768.0); +#endif + apuBufSize = apuFrequency/60*2; +#if AUDIO_FLOAT apuBufSizeBytes = apuBufSize*sizeof(float); - apuOutBuf = (float*)malloc(apuBufSizeBytes); - + printf("Audio: 32-bit Float Output\n"); +#else + apuBufSizeBytes = apuBufSize*sizeof(int16_t); + apuOutBuf = (int16_t*)malloc(apuBufSizeBytes); + printf("Audio: 16-bit Short Output\n"); +#endif /* https://wiki.nesdev.com/w/index.php/APU_Mixer#Lookup_Table */ uint8_t i; +#if AUDIO_FLOAT + for(i = 0; i < 32; i++) + pulseLookupTbl[i] = (95.52 / ((8128.0 / i) + 100)); + for(i = 0; i < 204; i++) + tndLookupTbl[i] = (163.67 / ((24329.0 / i) + 100)); +#else for(i = 0; i < 32; i++) - pulseLookupTbl[i] = 95.52 / ((8128.0 / i) + 100); + pulseLookupTbl[i] = (int32_t)((95.52 / ((8128.0 / i) + 100))*32768.0); for(i = 0; i < 204; i++) - tndLookupTbl[i] = 163.67 / ((24329.0 / i) + 100); + tndLookupTbl[i] = (int32_t)((163.67 / ((24329.0 / i) + 100))*32768.0); +#endif } void apuDeinitBufs() @@ -312,8 +342,11 @@ void apuClockTimers() } } } - +#if AUDIO_FLOAT static float lastHPOut = 0, lastLPOut = 0; +#else +static int32_t lastHPOut = 0, lastLPOut = 0; +#endif static uint8_t lastP1Out = 0, lastP2Out = 0, lastTriOut = 0, lastNoiseOut = 0; extern bool emuSkipVsync, emuSkipFrame; @@ -374,37 +407,81 @@ bool apuCycle() else noiseOut = 0; } +#if AUDIO_FLOAT float curIn = pulseLookupTbl[p1Out + p2Out] + tndLookupTbl[(3*triOut) + (2*noiseOut) + dmcVol]; //very rough still if(vrc6enabled) { vrc6AudioCycle(); curIn += ((float)vrc6Out)*0.008f; - curIn *= 0.665f; + curIn *= 0.6667f; } if(fdsEnabled) { fdsAudioCycle(); curIn += ((float)fdsOut)*0.00617f; - curIn *= 0.72f; + curIn *= 0.75f; } if(mmc5enabled) { mmc5AudioCycle(); curIn += pulseLookupTbl[mmc5Out]; - curIn *= 0.78f; + curIn *= 0.75f; + } + if(vrc7enabled) + { + curIn += (((float)(vrc7Out>>7))/32768.f); + curIn *= 0.75f; } + //amplify input + curIn *= 2.0f; float curLPout = lastLPOut+(lpVal*(curIn-lastLPOut)); - float curHPOut = hpVal*(lastHPOut+curLPout-curIn); + float curHPOut = hpVal*(lastHPOut+lastLPOut-curLPout); //set output - if(vrc7enabled) - apuOutBuf[curBufPos] = ((((float)vrc7Out)*0.0000019f)+(-curHPOut))*0.5f; - else - apuOutBuf[curBufPos] = -curHPOut; + apuOutBuf[curBufPos] = curHPOut; lastLPOut = curLPout; lastHPOut = curHPOut; - curBufPos++; - +#else + int32_t curIn = pulseLookupTbl[p1Out + p2Out] + tndLookupTbl[(3*triOut) + (2*noiseOut) + dmcVol]; + //very rough still + if(vrc6enabled) + { + vrc6AudioCycle(); + curIn += ((int32_t)vrc6Out)*262; + curIn <<= 1; curIn /= 3; + } + if(fdsEnabled) + { + fdsAudioCycle(); + curIn += ((int32_t)fdsOut)*202; + curIn *= 3; curIn >>= 2; + } + if(mmc5enabled) + { + mmc5AudioCycle(); + curIn += pulseLookupTbl[mmc5Out]; + curIn *= 3; curIn >>= 2; + } + if(vrc7enabled) + { + curIn += vrc7Out>>7; + curIn *= 3; curIn >>= 2; + } + //amplify input + curIn <<= 1; + int32_t curOut; + //gen output + curOut = lastLPOut+((lpVal*(curIn-lastLPOut))>>15); //Set Lowpass Output + curIn = (lastHPOut+lastLPOut-curOut); //Set Highpass Input + curIn += (curIn>>31)&1; //Add Sign Bit for proper Downshift later + lastLPOut = curOut; //Save Lowpass Output + curOut = (hpVal*curIn)>>15; //Set Highpass Output + lastHPOut = curOut; //Save Highpass Output + //Save Clipped Highpass Output + apuOutBuf[curBufPos] = (curOut > 32767)?(32767):((curOut < -32768)?(-32768):curOut); +#endif + apuOutBuf[curBufPos+1] = apuOutBuf[curBufPos]; + curBufPos+=2; return true; } diff --git a/audio.c b/audio.c index 0f66e79..a73bd1c 100644 --- a/audio.c +++ b/audio.c @@ -134,10 +134,13 @@ int audioInit() player = NewPlayer(); - player->channels = AL_MONO_SOFT; + player->channels = AL_STEREO_SOFT; player->rate = apuGetFrequency(); +#if AUDIO_FLOAT player->type = AL_FLOAT_SOFT; - +#else + player->type = AL_SHORT_SOFT; +#endif player->format = GetFormat(player->channels, player->type, alIsBufferFormatSupportedSOFT); if(player->format == 0) { diff --git a/build_linux.sh b/build_linux.sh index e321d6a..8938bd3 100755 --- a/build_linux.sh +++ b/build_linux.sh @@ -2,6 +2,6 @@ #Need to replace this with a makefile -gcc main.c apu.c audio.c audio_fds.c audio_mmc5.c audio_vrc6.c audio_vrc7.c alhelpers.c cpu.c ppu.c mem.c input.c mapper.c mapperList.c fm2play.c vrc_irq.c mapper/*.c -DFREEGLUT_STATIC -lglut -lopenal -lGL -lGLU -lm -Wall -Wextra -O3 -flto -msse -mfpmath=sse -ffast-math -s -o fixNES +gcc main.c apu.c audio.c audio_fds.c audio_mmc5.c audio_vrc6.c audio_vrc7.c alhelpers.c cpu.c ppu.c mem.c input.c mapper.c mapperList.c fm2play.c vrc_irq.c mapper/*.c -DFREEGLUT_STATIC -lglut -lopenal -lGL -lGLU -lm -Wall -Wextra -O3 -flto -s -o fixNES echo "Succesfully built fixNES" diff --git a/build_msys32.sh b/build_msys32.sh index 85312f4..6daf6b4 100644 --- a/build_msys32.sh +++ b/build_msys32.sh @@ -1,2 +1,2 @@ #!/bin/sh -gcc -DWINDOWS_BUILD main.c apu.c audio.c audio_fds.c audio_mmc5.c audio_vrc6.c audio_vrc7.c alhelpers.c cpu.c ppu.c mem.c input.c mapper.c mapperList.c fm2play.c vrc_irq.c mapper/*.c -DFREEGLUT_STATIC -lfreeglut_static -lopenal32 -lopengl32 -lglu32 -lgdi32 -lwinmm -Wall -Wextra -O3 -flto -msse -mfpmath=sse -ffast-math -s -o fixNES \ No newline at end of file +gcc -DWINDOWS_BUILD main.c apu.c audio.c audio_fds.c audio_mmc5.c audio_vrc6.c audio_vrc7.c alhelpers.c cpu.c ppu.c mem.c input.c mapper.c mapperList.c fm2play.c vrc_irq.c mapper/*.c -DFREEGLUT_STATIC -lfreeglut_static -lopenal32 -lopengl32 -lglu32 -lgdi32 -lwinmm -Wall -Wextra -O3 -flto -s -o fixNES \ No newline at end of file diff --git a/build_windows_console.bat b/build_windows_console.bat index cea8b45..4062f35 100644 --- a/build_windows_console.bat +++ b/build_windows_console.bat @@ -1,2 +1,2 @@ -gcc -DWINDOWS_BUILD main.c apu.c audio.c audio_fds.c audio_mmc5.c audio_vrc6.c audio_vrc7.c alhelpers.c cpu.c ppu.c mem.c input.c mapper.c mapperList.c fm2play.c vrc_irq.c mapper/*.c -DFREEGLUT_STATIC -lfreeglut_static -lopenal32 -lopengl32 -lglu32 -lgdi32 -lwinmm -Wall -Wextra -O3 -flto -msse -mfpmath=sse -ffast-math -s -o fixNES +gcc -DWINDOWS_BUILD main.c apu.c audio.c audio_fds.c audio_mmc5.c audio_vrc6.c audio_vrc7.c alhelpers.c cpu.c ppu.c mem.c input.c mapper.c mapperList.c fm2play.c vrc_irq.c mapper/*.c -DFREEGLUT_STATIC -lfreeglut_static -lopenal32 -lopengl32 -lglu32 -lgdi32 -lwinmm -Wall -Wextra -O3 -flto -s -o fixNES pause \ No newline at end of file diff --git a/build_windows_noconsole.bat b/build_windows_noconsole.bat index 41a62e6..cccbbf7 100644 --- a/build_windows_noconsole.bat +++ b/build_windows_noconsole.bat @@ -1,2 +1,2 @@ -gcc -DWINDOWS_BUILD main.c apu.c audio.c audio_fds.c audio_mmc5.c audio_vrc6.c audio_vrc7.c alhelpers.c cpu.c ppu.c mem.c input.c mapper.c mapperList.c fm2play.c vrc_irq.c mapper/*.c -DFREEGLUT_STATIC -lfreeglut_static -lopenal32 -lopengl32 -lglu32 -lgdi32 -lwinmm -Wall -Wextra -O3 -flto -msse -mfpmath=sse -ffast-math -s -o fixNES -Wl,--subsystem,windows +gcc -DWINDOWS_BUILD main.c apu.c audio.c audio_fds.c audio_mmc5.c audio_vrc6.c audio_vrc7.c alhelpers.c cpu.c ppu.c mem.c input.c mapper.c mapperList.c fm2play.c vrc_irq.c mapper/*.c -DFREEGLUT_STATIC -lfreeglut_static -lopenal32 -lopengl32 -lglu32 -lgdi32 -lwinmm -Wall -Wextra -O3 -flto -s -o fixNES -Wl,--subsystem,windows pause diff --git a/main.c b/main.c index 31d89ba..803cb02 100644 --- a/main.c +++ b/main.c @@ -25,13 +25,16 @@ #include "audio.h" #include "audio_fds.h" #include "audio_vrc7.h" +#include "mapper_h/nsf.h" #define DEBUG_HZ 0 #define DEBUG_MAIN_CALLS 0 #define DEBUG_KEY 0 #define DEBUG_LOAD_INFO 1 -static const char *VERSION_STRING = "fixNES Alpha v0.8.3"; +static const char *VERSION_STRING = "fixNES Alpha v0.9"; +static char window_title[256]; +static char window_title_pause[256]; static void nesEmuDisplayFrame(void); static void nesEmuMainLoop(void); @@ -82,6 +85,7 @@ static DWORD emuMainTotalElapsed = 0; #define VISIBLE_DOTS 256 #define VISIBLE_LINES 240 +static uint32_t linesToDraw = VISIBLE_LINES; static const uint32_t visibleImg = VISIBLE_DOTS*VISIBLE_LINES*4; static uint8_t scaleFactor = 2; static bool emuSaveEnabled = false; @@ -96,11 +100,19 @@ extern uint8_t inValReads[8]; int main(int argc, char** argv) { puts(VERSION_STRING); + strcpy(window_title, VERSION_STRING); + memset(textureImage,0,visibleImg); if(argc >= 2 && (strstr(argv[1],".nes") != NULL || strstr(argv[1],".NES") != NULL)) { nesPAL = (strstr(argv[1],"(E)") != NULL); FILE *nesF = fopen(argv[1],"rb"); - if(!nesF) return EXIT_SUCCESS; + if(!nesF) + { + printf("Main: Could not open %s!\n", argv[1]); + puts("Press enter to exit"); + getc(stdin); + return EXIT_SUCCESS; + } fseek(nesF,0,SEEK_END); size_t fsize = ftell(nesF); rewind(nesF); @@ -142,7 +154,8 @@ int main(int argc, char** argv) { printf("Mapper init failed!\n"); free(emuNesROM); - emuNesROM = NULL; + puts("Press enter to exit"); + getc(stdin); return EXIT_SUCCESS; } if(emuNesROM[6] & 8) @@ -155,6 +168,7 @@ int main(int argc, char** argv) printf("Trainer: %i Saving: %i VRAM Mode: %s\n", trainer, emuSaveEnabled, (emuNesROM[6] & 1) ? "Vertical" : ((!(emuNesROM[6] & 1)) ? "Horizontal" : "4-Screen")); #endif + sprintf(window_title, "%s NES - %s\n", nesPAL ? "PAL" : "NTSC", VERSION_STRING); if(emuSaveEnabled) { emuSaveName = strdup(argv[1]); @@ -172,7 +186,13 @@ int main(int argc, char** argv) else if(argc >= 2 && (strstr(argv[1],".nsf") != NULL || strstr(argv[1],".NSF") != NULL)) { FILE *nesF = fopen(argv[1],"rb"); - if(!nesF) return EXIT_SUCCESS; + if(!nesF) + { + printf("Main: Could not open %s!\n", argv[1]); + puts("Press enter to exit"); + getc(stdin); + return EXIT_SUCCESS; + } fseek(nesF,0,SEEK_END); size_t fsize = ftell(nesF); rewind(nesF); @@ -185,9 +205,14 @@ int main(int argc, char** argv) { printf("NSF init failed!\n"); free(emuNesROM); + puts("Press enter to exit"); + getc(stdin); return EXIT_SUCCESS; } + if(emuNesROM[0xE] != 0) + sprintf(window_title, "%.32s (%s NSF) - %s\n", (char*)(emuNesROM+0xE), nesPAL ? "PAL" : "NTSC", VERSION_STRING); nesEmuNSFPlayback = true; + linesToDraw = 30; } else if(argc >= 2 && (strstr(argv[1],".fds") != NULL || strstr(argv[1],".FDS") != NULL || strstr(argv[1],".qd") != NULL || strstr(argv[1],".QD") != NULL)) @@ -216,7 +241,13 @@ int main(int argc, char** argv) if(!saveValid) { FILE *nesF = fopen(argv[1],"rb"); - if(!nesF) return EXIT_SUCCESS; + if(!nesF) + { + printf("Main: Could not open %s!\n", argv[1]); + puts("Press enter to exit"); + getc(stdin); + return EXIT_SUCCESS; + } fseek(nesF,0,SEEK_END); size_t fsize = ftell(nesF); rewind(nesF); @@ -282,12 +313,20 @@ int main(int argc, char** argv) { printf("FDS init failed!\n"); free(emuNesROM); - emuNesROM = NULL; + puts("Press enter to exit"); + getc(stdin); return EXIT_SUCCESS; } + sprintf(window_title, "Famicom Disk System - %s\n", VERSION_STRING); } if(emuNesROM == NULL) + { + printf("Main: No File to Open! Make sure to call fixNES with a .nes/.nsf/.fds/.qd File as Argument.\n"); + puts("Press enter to exit"); + getc(stdin); return EXIT_SUCCESS; + } + sprintf(window_title_pause, "%s (Pause)", window_title); #if WINDOWS_BUILD #if DEBUG_HZ emuFrameStart = GetTickCount(); @@ -296,16 +335,15 @@ int main(int argc, char** argv) emuMainFrameStart = GetTickCount(); #endif #endif - memset(textureImage,0,visibleImg); cpuCycleTimer = nesPAL ? 16 : 12; //do one scanline per idle loop ppuCycleTimer = nesPAL ? 5 : 4; mainLoopRuns = nesPAL ? DOTS*ppuCycleTimer : DOTS*ppuCycleTimer; mainLoopPos = mainLoopRuns; glutInit(&argc, argv); - glutInitWindowSize(VISIBLE_DOTS*scaleFactor, VISIBLE_LINES*scaleFactor); + glutInitWindowSize(VISIBLE_DOTS*scaleFactor, linesToDraw*scaleFactor); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); - glutCreateWindow(VERSION_STRING); + glutCreateWindow(nesPause ? window_title_pause : window_title); audioInit(); atexit(&nesEmuDeinit); glutKeyboardFunc(&nesEmuHandleKeyDown); @@ -320,7 +358,7 @@ int main(int argc, char** argv) wglSwapIntervalEXT(1); #endif glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - glTexImage2D(GL_TEXTURE_2D, 0, 4, VISIBLE_DOTS, VISIBLE_LINES, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, textureImage); + glTexImage2D(GL_TEXTURE_2D, 0, 4, VISIBLE_DOTS, linesToDraw, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, textureImage); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); @@ -380,9 +418,8 @@ bool emuSkipVsync = false; bool emuSkipFrame = false; //static uint32_t mCycles = 0; -static bool emuApuDoCycle = false; - static uint16_t mainClock = 1; +static uint16_t apuClock = 1; static uint16_t ppuClock = 1; static uint16_t vrc7Clock = 1; @@ -400,16 +437,21 @@ static void nesEmuMainLoop(void) } if(mainClock == cpuCycleTimer) { - //runs every second cpu clock - if(emuApuDoCycle && !apuCycle()) + //runs every 8th cpu clock + if(apuClock == 8) { - #if (WINDOWS_BUILD && DEBUG_MAIN_CALLS) - emuMainTimesSkipped++; - #endif - audioSleep(); - return; + if(!apuCycle()) + { + #if (WINDOWS_BUILD && DEBUG_MAIN_CALLS) + emuMainTimesSkipped++; + #endif + audioSleep(); + return; + } + apuClock = 1; } - emuApuDoCycle ^= true; + else + apuClock++; //runs every cpu cycle apuClockTimers(); //main CPU clock @@ -429,7 +471,7 @@ static void nesEmuMainLoop(void) { if(!ppuCycle()) exit(EXIT_SUCCESS); - if(!nesEmuNSFPlayback && ppuDrawDone()) + if(ppuDrawDone()) { //printf("%i\n",mCycles); //mCycles = 0; @@ -451,6 +493,8 @@ static void nesEmuMainLoop(void) glutPostRedisplay(); if(ppuDebugPauseFrame) nesPause = true; + if(nesEmuNSFPlayback) + nsfVsync(); } ppuClock = 1; } @@ -556,69 +600,70 @@ static void nesEmuHandleKeyDown(unsigned char key, int x, int y) #endif inPause = true; nesPause ^= true; + glutSetWindowTitle(nesPause ? window_title_pause : window_title); } break; case '1': if(!inResize) { inResize = true; - glutReshapeWindow(VISIBLE_DOTS*1, VISIBLE_LINES*1); + glutReshapeWindow(VISIBLE_DOTS*1, linesToDraw*1); } break; case '2': if(!inResize) { inResize = true; - glutReshapeWindow(VISIBLE_DOTS*2, VISIBLE_LINES*2); + glutReshapeWindow(VISIBLE_DOTS*2, linesToDraw*2); } break; case '3': if(!inResize) { inResize = true; - glutReshapeWindow(VISIBLE_DOTS*3, VISIBLE_LINES*3); + glutReshapeWindow(VISIBLE_DOTS*3, linesToDraw*3); } break; case '4': if(!inResize) { inResize = true; - glutReshapeWindow(VISIBLE_DOTS*4, VISIBLE_LINES*4); + glutReshapeWindow(VISIBLE_DOTS*4, linesToDraw*4); } break; case '5': if(!inResize) { inResize = true; - glutReshapeWindow(VISIBLE_DOTS*5, VISIBLE_LINES*5); + glutReshapeWindow(VISIBLE_DOTS*5, linesToDraw*5); } break; case '6': if(!inResize) { inResize = true; - glutReshapeWindow(VISIBLE_DOTS*6, VISIBLE_LINES*6); + glutReshapeWindow(VISIBLE_DOTS*6, linesToDraw*6); } break; case '7': if(!inResize) { inResize = true; - glutReshapeWindow(VISIBLE_DOTS*7, VISIBLE_LINES*7); + glutReshapeWindow(VISIBLE_DOTS*7, linesToDraw*7); } break; case '8': if(!inResize) { inResize = true; - glutReshapeWindow(VISIBLE_DOTS*8, VISIBLE_LINES*8); + glutReshapeWindow(VISIBLE_DOTS*8, linesToDraw*8); } break; case '9': if(!inResize) { inResize = true; - glutReshapeWindow(VISIBLE_DOTS*9, VISIBLE_LINES*9); + glutReshapeWindow(VISIBLE_DOTS*9, linesToDraw*9); } break; case 'o': @@ -802,7 +847,7 @@ static void nesEmuDisplayFrame() emuRenderFrame = false; return; } - glTexImage2D(GL_TEXTURE_2D, 0, 4, VISIBLE_DOTS, VISIBLE_LINES, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, textureImage); + glTexImage2D(GL_TEXTURE_2D, 0, 4, VISIBLE_DOTS, linesToDraw, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, textureImage); emuRenderFrame = false; } @@ -814,10 +859,10 @@ static void nesEmuDisplayFrame() glMatrixMode(GL_MODELVIEW); glLoadIdentity(); - double upscaleVal = round((((double)glutGet(GLUT_WINDOW_HEIGHT))/((double)VISIBLE_LINES))*20.0)/20.0; + double upscaleVal = round((((double)glutGet(GLUT_WINDOW_HEIGHT))/((double)linesToDraw))*20.0)/20.0; double windowMiddle = ((double)glutGet(GLUT_WINDOW_WIDTH))/2.0; double drawMiddle = (((double)VISIBLE_DOTS)*upscaleVal)/2.0; - double drawHeight = ((double)VISIBLE_LINES)*upscaleVal; + double drawHeight = ((double)linesToDraw)*upscaleVal; glBegin(GL_QUADS); glTexCoord2f(0,0); glVertex2f(windowMiddle-drawMiddle,drawHeight); diff --git a/mapper/nsf.c b/mapper/nsf.c index a52edb4..002f04d 100644 --- a/mapper/nsf.c +++ b/mapper/nsf.c @@ -14,6 +14,7 @@ #include "../input.h" #include "../mem.h" #include "../apu.h" +#include "../ppu.h" #include "../audio_fds.h" #include "../audio_mmc5.h" #include "../audio_vrc6.h" @@ -101,7 +102,8 @@ void nsfinit(uint8_t *nsfBIN, uint32_t nsfBINsize, uint8_t *prgRAMin, uint32_t p printf("NSF Player inited in %s Mode (VRC6 %s, VRC7 %s, FDS %s, MMC5 %s) %s banking\n", nesPAL ? "PAL" : "NTSC", onOff(vrc6enabled), onOff(vrc7enabled), onOff(fdsEnabled), onOff(mmc5enabled), nsf_bankEnable ? "with" : "without"); if(nsfBIN[0xE] != 0) printf("Playing back %.32s\n", nsfBIN+0xE); - printf("Track %i/%i ", nsf_curTrack, nsf_trackTotal); + //printf("Track %i/%i ", nsf_curTrack, nsf_trackTotal); + ppuDrawNSFTrackNum(nsf_curTrack, nsf_trackTotal); inputInit(); nsfInitPlayback(); } @@ -321,7 +323,8 @@ void nsfcycle() nsf_curTrack++; if(nsf_curTrack > nsf_trackTotal) nsf_curTrack = 1; - printf("\rTrack %i/%i ", nsf_curTrack, nsf_trackTotal); + //printf("\rTrack %i/%i ", nsf_curTrack, nsf_trackTotal); + ppuDrawNSFTrackNum(nsf_curTrack, nsf_trackTotal); nsfInitPlayback(); } else if(!inValReads[BUTTON_RIGHT]) @@ -333,27 +336,28 @@ void nsfcycle() nsf_curTrack--; if(nsf_curTrack < 1) nsf_curTrack = nsf_trackTotal; - printf("\rTrack %i/%i ", nsf_curTrack, nsf_trackTotal); + //printf("\rTrack %i/%i ", nsf_curTrack, nsf_trackTotal); + ppuDrawNSFTrackNum(nsf_curTrack, nsf_trackTotal); nsfInitPlayback(); } else if(!inValReads[BUTTON_LEFT]) nsf_prevValReads[BUTTON_LEFT] = 0; +} +void nsfVsync() +{ if(nsf_playing) return; - if(ppuDrawDone()) + //wait for init return + if(nsf_init_timeout) { - //wait for init return - if(nsf_init_timeout) - { - nsf_init_timeout--; - return; - } - //will get started on next CPU_GET_INSTRUCTION state - nsf_startPlayback = true; - nsf_playing = true; + nsf_init_timeout--; + return; } + //will get started on next CPU_GET_INSTRUCTION state + nsf_startPlayback = true; + nsf_playing = true; } uint16_t nsfGetPlayAddr() diff --git a/mapper_h/nsf.h b/mapper_h/nsf.h index 4d40972..abe3bbf 100644 --- a/mapper_h/nsf.h +++ b/mapper_h/nsf.h @@ -15,6 +15,7 @@ void nsfset8(uint16_t addr, uint8_t val); uint8_t nsfchrGet8(uint16_t addr); void nsfchrSet8(uint16_t addr, uint8_t val); void nsfcycle(); +void nsfVsync(); extern bool nsf_startPlayback; extern bool nsf_endPlayback; diff --git a/ppu.c b/ppu.c index a26d87a..11ca437 100644 --- a/ppu.c +++ b/ppu.c @@ -820,3 +820,99 @@ void ppuSetNameTblCustom(uint16_t addrA, uint16_t addrB, uint16_t addrC, uint16_ { ppuNameTbl[0] = addrA; ppuNameTbl[1] = addrB; ppuNameTbl[2] = addrC; ppuNameTbl[3] = addrD; } + + +//64x12 1BPP "Track" +static const uint8_t ppuNSFTextTrack[96] = +{ + 0x0C, 0x1C, 0x03, 0xD8, 0x7C, 0x71, 0xC0, 0x00, 0x0C, 0x1C, 0x07, 0xF8, 0xFE, 0x73, 0x80, 0x00, + 0x0C, 0x1C, 0x06, 0x39, 0xE2, 0x77, 0x00, 0x00, 0x0C, 0x1C, 0x07, 0x39, 0xC0, 0x7E, 0x00, 0x00, + 0x0C, 0x1C, 0x07, 0xF9, 0xC0, 0x7C, 0x00, 0x00, 0x0C, 0x1C, 0x01, 0xF9, 0xC0, 0x7C, 0x00, 0x00, + 0x0C, 0x1E, 0x60, 0x38, 0xE2, 0x7E, 0x00, 0x00, 0x0C, 0x1F, 0xE3, 0xF8, 0xFE, 0x77, 0x00, 0x00, + 0x0C, 0x1D, 0xC3, 0xF0, 0x3C, 0x73, 0xC0, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, +}; + +//128x12 1BPP "0123456789/" +static const uint8_t ppuNsfTextRest[192] = +{ + 0x0E, 0x1F, 0xF7, 0xF8, 0xF8, 0x03, 0x9F, 0x01, 0xF0, 0x60, 0x1F, 0x0F, 0x83, 0x00, 0x00, 0x00, + 0x3F, 0x9F, 0xF7, 0xF9, 0xFC, 0x03, 0x9F, 0xC3, 0xF8, 0x70, 0x3F, 0x8F, 0xC3, 0x00, 0x00, 0x00, + 0x3B, 0x83, 0x83, 0x80, 0x0E, 0x7F, 0xC1, 0xE7, 0x1C, 0x70, 0x71, 0xC0, 0xE1, 0x80, 0x00, 0x00, + 0x71, 0xC3, 0x81, 0xC0, 0x0E, 0x7F, 0xC0, 0xE7, 0x1C, 0x30, 0x71, 0xC0, 0x71, 0x80, 0x00, 0x00, + 0x79, 0xC3, 0x80, 0xE0, 0x0E, 0x63, 0x80, 0xE7, 0x1C, 0x38, 0x71, 0xC7, 0x70, 0xC0, 0x00, 0x00, + 0x7D, 0xC3, 0x80, 0x70, 0x7E, 0x33, 0x81, 0xE7, 0x1C, 0x18, 0x3F, 0x8F, 0xF0, 0xC0, 0x00, 0x00, + 0x77, 0xC3, 0x80, 0x70, 0x7C, 0x13, 0x9F, 0xC7, 0xF8, 0x1C, 0x1F, 0x1C, 0x70, 0x60, 0x00, 0x00, + 0x73, 0xC3, 0x80, 0x38, 0x0E, 0x1B, 0x9F, 0x87, 0x70, 0x1C, 0x31, 0x9C, 0x70, 0x60, 0x00, 0x00, + 0x71, 0xC3, 0x80, 0x38, 0x0E, 0x0B, 0x9C, 0x07, 0x00, 0x0C, 0x71, 0xDC, 0x70, 0x30, 0x00, 0x00, + 0x3B, 0x9F, 0x80, 0x38, 0x0E, 0x0F, 0x9C, 0x03, 0x80, 0x0E, 0x71, 0xDC, 0x70, 0x30, 0x00, 0x00, + 0x3F, 0x8F, 0x83, 0xF1, 0xFC, 0x07, 0x9F, 0xC1, 0xF9, 0xFE, 0x3F, 0x8F, 0xE0, 0x18, 0x00, 0x00, + 0x0E, 0x03, 0x81, 0xE0, 0xF8, 0x03, 0x9F, 0xC0, 0xF9, 0xFE, 0x1F, 0x07, 0xC0, 0x18, 0x00, 0x00, +}; + +static void ppuDrawRest(uint8_t curX, uint8_t sym) +{ + uint8_t i, j; + for(i = 0; i < 12; i++) + { + for(j = 0; j < 10; j++) + { + size_t drawPos = (j+curX)+((i+9)*256); + uint8_t xSel = (j+(sym*10)); + if(ppuNsfTextRest[((11-i)<<4)+(xSel>>3)]&(0x80>>(xSel&7))) + textureImage[drawPos] = 0xFFFFFFFF; //White + else + textureImage[drawPos] = 0xFF000000; //Black + } + } +} + +void ppuDrawNSFTrackNum(uint8_t cTrack, uint8_t trackTotal) +{ + memset(textureImage,0,0x16800); + uint8_t curX = 4; + //draw "Track" + uint8_t i, j; + for(i = 0; i < 12; i++) + { + for(j = 0; j < 50; j++) + { + size_t drawPos = (j+curX)+((i+9)*256); + if(ppuNSFTextTrack[((11-i)<<3)+(j>>3)]&(0x80>>(j&7))) + textureImage[drawPos] = 0xFFFFFFFF; //White + else + textureImage[drawPos] = 0xFF000000; //Black + } + } + //"Track" len+space + curX+=60; + //draw current num + if(cTrack > 99) + { + ppuDrawRest(curX, (cTrack/100)%10); + curX+=10; + } + if(cTrack > 9) + { + ppuDrawRest(curX, (cTrack/10)%10); + curX+=10; + } + ppuDrawRest(curX, cTrack%10); + curX+=10; + //draw the "/" + ppuDrawRest(curX, 10); + curX+=10; + //draw total num + if(trackTotal > 99) + { + ppuDrawRest(curX, (trackTotal/100)%10); + curX+=10; + } + if(trackTotal > 9) + { + ppuDrawRest(curX, (trackTotal/10)%10); + curX+=10; + } + ppuDrawRest(curX, trackTotal%10); + curX+=10; +} diff --git a/ppu.h b/ppu.h index 3ef94eb..de87038 100644 --- a/ppu.h +++ b/ppu.h @@ -25,6 +25,8 @@ void ppuSetNameTblHorizontal(); void ppuSetNameTbl4Screen(); void ppuSetNameTblCustom(uint16_t addrA, uint16_t addrB, uint16_t addrC, uint16_t addrD); +void ppuDrawNSFTrackNum(uint8_t cTrack, uint8_t trackTotal); + extern bool ppu4Screen; #endif