diff options
author | Nebuleon Fumika | 2013-02-08 05:50:22 -0500 |
---|---|---|
committer | Nebuleon Fumika | 2013-02-08 05:50:22 -0500 |
commit | 927d456306672110870eb3386742c1c1ef8eb4f6 (patch) | |
tree | 509da9ac1727570b02572068aefb9cdf102ad75b /source/nds | |
parent | 433749b6ef1e2b070755c3bb7fc0d81b5ecaa7b1 (diff) | |
parent | d4fcf2697c9a45594e3ee0b8bf82e480ddd0b69b (diff) | |
download | snesemu-927d456306672110870eb3386742c1c1ef8eb4f6.tar.gz snesemu-927d456306672110870eb3386742c1c1ef8eb4f6.tar.bz2 snesemu-927d456306672110870eb3386742c1c1ef8eb4f6.zip |
Merge branch 'master' into 8bitsound
Conflicts:
source/nds/entry.cpp
Diffstat (limited to 'source/nds')
-rw-r--r-- | source/nds/dma_adj.c | 26 | ||||
-rw-r--r-- | source/nds/dma_adj.h | 29 | ||||
-rw-r--r-- | source/nds/ds2_main.c | 5 | ||||
-rw-r--r-- | source/nds/ds2sound.h | 21 | ||||
-rw-r--r-- | source/nds/entry.cpp | 620 | ||||
-rw-r--r-- | source/nds/entry.h | 4 | ||||
-rw-r--r-- | source/nds/gui.c | 704 | ||||
-rw-r--r-- | source/nds/gui.h | 22 | ||||
-rw-r--r-- | source/nds/message.h | 37 |
9 files changed, 893 insertions, 575 deletions
diff --git a/source/nds/dma_adj.c b/source/nds/dma_adj.c new file mode 100644 index 0000000..8b6f9ad --- /dev/null +++ b/source/nds/dma_adj.c @@ -0,0 +1,26 @@ +#include "ds2_malloc.h" +#include "dma_adj.h" + +#ifdef DS2_DMA + +struct SPointerAdjustments PtrAdj; + +void* AlignedMalloc (unsigned int Size, unsigned int Alignment, unsigned int* Adjustment) +{ + if (Alignment == 0) Alignment = 1; + + unsigned char* result = (unsigned char*) malloc(Size + Alignment); + if (!result) { + return result; + } else { + *Adjustment = Alignment - ((unsigned int) result & (Alignment - 1)); + return (void*) (result + *Adjustment); + } +} + +void AlignedFree (void* Memory, unsigned int Adjustment) +{ + free((void*) ((unsigned char*) Memory - Adjustment)); +} + +#endif // DS2_DMA diff --git a/source/nds/dma_adj.h b/source/nds/dma_adj.h new file mode 100644 index 0000000..3852f09 --- /dev/null +++ b/source/nds/dma_adj.h @@ -0,0 +1,29 @@ +#ifndef _DMA_ADJ_H_ +#define _DMA_ADJ_H_ + +#ifdef DS2_DMA + +#ifdef __cplusplus +extern "C" { +#endif + +struct SPointerAdjustments { + /* These are used by the DSTWO-NDS side code. */ + unsigned int GFXScreen; + + /* These are used by Snes9x. */ + unsigned int ROM; +}; + +extern struct SPointerAdjustments PtrAdj; + +extern void* AlignedMalloc (unsigned int Size, unsigned int Alignment, unsigned int* Adjustment); +extern void AlignedFree (void* Memory, unsigned int Adjustment); + +#ifdef __cplusplus +} +#endif + +#endif // DS2_DMA + +#endif // !_DMA_ADJ_H_ diff --git a/source/nds/ds2_main.c b/source/nds/ds2_main.c index f9b29d5..af81df3 100644 --- a/source/nds/ds2_main.c +++ b/source/nds/ds2_main.c @@ -17,6 +17,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "port.h" + #include <stdio.h> #include "console.h" #include "fs_api.h" @@ -25,6 +27,7 @@ #include "ds2_timer.h" #include "ds2_malloc.h" #include "ds2sound.h" +#include "gui.h" #define BLACK_COLOR RGB15(0, 0, 0) #define WHITE_COLOR RGB15(31, 31, 31) @@ -47,7 +50,7 @@ void ddump_mem(unsigned char* addr, unsigned int len) void ds2_main(void) { int err; - ds2_setCPUclocklevel(13); + HighFrequencyCPU(); //Initial video and audio and other input and output err = ds2io_initb(DS2_BUFFER_SIZE, SND_SAMPLE_RATE, 0, 0); if(err) goto _failure; diff --git a/source/nds/ds2sound.h b/source/nds/ds2sound.h index f51a6e1..8c0e2bf 100644 --- a/source/nds/ds2sound.h +++ b/source/nds/ds2sound.h @@ -1,21 +1,24 @@ // The sound buffer sizes used on the DS2's side, for each value of // Settings.SoundPlaybackRate. +// * Don't buffer too much, otherwise audio is delayed from video. +// * Don't go below one frame (20 milliseconds). +// * Buffer sizes must be multiples of 128. #define DS2_BUFFER_SIZE_4 512 /* tested working */ -#define DS2_BUFFER_SIZE_5 1024 /* like the SNES! tested working, but slow */ -#define DS2_BUFFER_SIZE_6 1024 /* tested working, slow because of upsampling */ -#define DS2_BUFFER_SIZE_7 1024 /* tested working, slow because of upsampling */ +#define DS2_BUFFER_SIZE_5 640 /* like the SNES! tested working */ +#define DS2_BUFFER_SIZE_6 896 /* tested working */ +#define DS2_BUFFER_SIZE_7 1024 /* tested working */ // The sampling rate for the sound, in Hz, for each value of // Settings.SoundPlaybackRate. #define SND_SAMPLE_RATE_1 8000 #define SND_SAMPLE_RATE_2 11025 #define SND_SAMPLE_RATE_3 16000 -#define SND_SAMPLE_RATE_4 22050 -#define SND_SAMPLE_RATE_5 32000 +#define SND_SAMPLE_RATE_4 22050 /* NDSSFC 1.06 - CATSFC 1.28 used this one */ +#define SND_SAMPLE_RATE_5 32000 /* like the SNES! */ #define SND_SAMPLE_RATE_6 44100 -#define SND_SAMPLE_RATE_7 48000 +#define SND_SAMPLE_RATE_7 48000 /* CATSFC 1.25 made using this one possible */ // Settings in use. The number should match in all three settings. -#define DS2_BUFFER_SIZE DS2_BUFFER_SIZE_4 -#define SND_SAMPLE_RATE SND_SAMPLE_RATE_4 -#define SNES9X_SRATE_ID 4 +#define DS2_BUFFER_SIZE DS2_BUFFER_SIZE_5 +#define SND_SAMPLE_RATE SND_SAMPLE_RATE_5 +#define SNES9X_SRATE_ID 5 diff --git a/source/nds/entry.cpp b/source/nds/entry.cpp index 702442e..c4cc389 100644 --- a/source/nds/entry.cpp +++ b/source/nds/entry.cpp @@ -23,6 +23,11 @@ #include "entry.h" #include "ds2sound.h" +#ifdef DS2_DMA +#include "ds2_dma.h" +#include "dma_adj.h" +#endif + void S9xProcessSound (unsigned int); char *rom_filename = NULL; @@ -58,7 +63,11 @@ void S9xExtraUsage () */ void S9xDeinitDisplay (void) { +#ifdef DS2_DMA + if(GFX.Screen) AlignedFree(GFX.Screen, PtrAdj.GFXScreen); +#else if(GFX.Screen) free(GFX.Screen); +#endif if(GFX.SubScreen) free(GFX.SubScreen); if(GFX.ZBuffer) free(GFX.ZBuffer); if(GFX.SubZBuffer) free(GFX.SubZBuffer); @@ -69,7 +78,11 @@ void S9xInitDisplay (int, char **) int h = IMAGE_HEIGHT; GFX.Pitch = IMAGE_WIDTH * 2; +#ifdef DS2_DMA + GFX.Screen = (unsigned char*) AlignedMalloc (GFX.Pitch * h, 32, &PtrAdj.GFXScreen); +#else GFX.Screen = (unsigned char*) malloc (GFX.Pitch * h); +#endif GFX.SubScreen = (unsigned char*) malloc (GFX.Pitch * h); GFX.ZBuffer = (unsigned char*) malloc ((GFX.Pitch >> 1) * h); GFX.SubZBuffer =(unsigned char*) malloc ((GFX.Pitch >> 1) * h); @@ -86,7 +99,7 @@ void S9xParseDisplayArg (char **argv, int &ind, int) void S9xExit () { - ds2_setCPUclocklevel(13); // Crank it up to exit quickly + HighFrequencyCPU(); // Crank it up to exit quickly if(Settings.SPC7110) (*CleanUp7110)(); @@ -130,17 +143,38 @@ bool8 S9xDeinitUpdate (int Width, int Height, bool8 /*sixteen_bit*/) { //Up case 1: +#ifdef DS2_DMA + __dcache_writeback_all(); + ds2_DMAcopy_32Byte(1 /* channel: graphics */, up_screen_addr, GFX.Screen + 256 * 32 * 2, 256 * 192 * 2); + ds2_DMA_wait(1); + ds2_DMA_stop(1); +#else memcpy(up_screen_addr, GFX.Screen+256*32*2, 256*192*2); +#endif break; //Down case 2: +#ifdef DS2_DMA + __dcache_writeback_all(); + ds2_DMAcopy_32Byte(1 /* channel: graphics */, up_screen_addr, GFX.Screen, 256 * 192 * 2); + ds2_DMA_wait(1); + ds2_DMA_stop(1); +#else memcpy(up_screen_addr, GFX.Screen, 256*192*2); +#endif break; //Both case 3: +#ifdef DS2_DMA + __dcache_writeback_all(); + ds2_DMAcopy_32Byte(1 /* channel: graphics */, up_screen_addr, GFX.Screen + 256 * 16 * 2, 256 * 192 * 2); + ds2_DMA_wait(1); + ds2_DMA_stop(1); +#else memcpy(up_screen_addr, GFX.Screen+256*16*2, 256*192*2); +#endif break; case 4: @@ -150,14 +184,23 @@ bool8 S9xDeinitUpdate (int Width, int Height, bool8 /*sixteen_bit*/) default: { - unsigned char *src, *dst; - unsigned int m; +#ifdef DS2_DMA + __dcache_writeback_all(); +#endif + register unsigned char *src, *dst; + register unsigned int m; src = GFX.Screen; dst = (unsigned char*)up_screen_addr; for(m = 0; m < 32; m++) { +#ifdef DS2_DMA + ds2_DMAcopy_32Byte(1 /* channel: graphics */, dst, src, 256 * 6 * 2); + ds2_DMA_wait(1); + ds2_DMA_stop(1); +#else memcpy(dst, src, 256*6*2); +#endif dst += 256*6*2; src += 256*7*2; } @@ -350,6 +393,18 @@ void game_set_frameskip() Settings.SkipFrames = game_config.frameskip_value - 1 /* 1 -> 0 and so on */; } } + +void game_set_fluidity() +{ + if( game_config.SoundSync == 1) + { + Settings.SoundSync = TRUE; + } + else + { + Settings.SoundSync = FALSE; + } +} void init_sfc_setting(void) { @@ -370,6 +425,7 @@ void init_sfc_setting(void) //sound settings Settings.APUEnabled = Settings.NextAPUEnabled = TRUE; Settings.FixFrequency = 1; + S9xSetEightBitConsoleSound (TRUE); @@ -403,7 +459,7 @@ void init_sfc_setting(void) #endif Settings.ApplyCheats = TRUE; Settings.TurboMode = FALSE; - Settings.TurboSkipFrames = 40; + Settings.TurboSkipFrames = 10; Settings.StretchScreenshots = 1; Settings.HBlankStart = (256 * Settings.H_Max) / SNES_HCOUNTER_MAX; @@ -444,7 +500,7 @@ void game_restart(void) S9xReset (); } -int load_gamepak(char* file) +int load_gamepak(const char* file) { CPU.Flags = 0; // mdelay(50); // Delete this delay @@ -540,6 +596,7 @@ int sfc_main (int argc, char **argv) #endif Settings.Paused = 1; + bool8 FirstInvocation = TRUE; while (1) { @@ -564,7 +621,8 @@ int sfc_main (int argc, char **argv) unsigned short screen[256*192]; copy_screen((void*)screen, up_screen_addr, 0, 0, 256, 192); - menu(screen); + menu(screen, FirstInvocation); + FirstInvocation = FALSE; game_disableAudio(); Settings.Paused = 0; } @@ -582,7 +640,6 @@ int sfc_main (int argc, char **argv) static unsigned int sync_last= 0; static unsigned int sync_next = 0; -static unsigned int auto_equivalent_skip = 0; static unsigned int skip_rate= 0; @@ -590,6 +647,7 @@ void S9xSyncSpeed () { uint32 syncnow; int32 syncdif; + unsigned int LastAutoCPUFrequency = AutoCPUFrequency; #if 0 if (Settings.SoundSync == 2) @@ -601,12 +659,14 @@ void S9xSyncSpeed () #endif syncnow = getSysTime(); - if (game_fast_forward || temporary_fast_forward /* hotkey is held */) + bool8 FastForward = game_fast_forward || temporary_fast_forward /* hotkey is held */; + + if (FastForward) { sync_last = syncnow; sync_next = syncnow; - if(++skip_rate < 10) + if(++skip_rate < Settings.TurboSkipFrames) IPPU.RenderThisFrame = false; else { @@ -614,110 +674,132 @@ void S9xSyncSpeed () IPPU.RenderThisFrame = true; } } - else if (Settings.SkipFrames == AUTO_FRAMERATE /* && !game_fast_forward && !temporary_fast_forward */) + else { - // frame_time is in getSysTime units: 42.667 microseconds. - int32 frame_time = Settings.PAL ? 468 /* = 20.0 ms */ : 391 /* = 16.67 ms */; - if (sync_last > syncnow) // Overflow occurred! (every 50 hrs) + // Manual or automatic frame skipping, no fast-forward. + if (Settings.SkipFrames == AUTO_FRAMERATE) { - // Render this frame regardless, set the - // sync_next, and get the hell out. - IPPU.RenderThisFrame = TRUE; + // frame_time is in getSysTime units: 42.667 microseconds. + int32 frame_time = Settings.PAL ? 468 /* = 20.0 ms */ : 391 /* = 16.67 ms */; + if (sync_last > syncnow) // Overflow occurred! (every 50 hrs) + { + // Render this frame regardless, set the + // sync_next, and get the hell out. + IPPU.RenderThisFrame = TRUE; + sync_last = syncnow; + sync_next = syncnow + frame_time; + return; + } sync_last = syncnow; - sync_next = syncnow + frame_time; - return; - } - sync_last = syncnow; - // If this is positive, we have syncdif*42.66 microseconds to - // spare. - // If this is negative, we're late by syncdif*42.66 - // microseconds. - syncdif = sync_next - syncnow; - if (syncdif < 0 && syncdif >= -(frame_time / 2)) - { - // We're late, but by less than half a frame. Draw it - // anyway. If the next frame is too late, it'll be - // skipped. - skip_rate = 0; - IPPU.RenderThisFrame = true; - sync_next += frame_time; - } - else if(syncdif < 0) - { - /* - * If we're consistently late, delay up to 8 frames. - * - * That really helps with certain games, such as - * Super Mario RPG and Yoshi's Island. - */ - if(++skip_rate < 10) + // If this is positive, we have syncdif*42.66 microseconds to + // spare. + // If this is negative, we're late by syncdif*42.66 + // microseconds. + syncdif = sync_next - syncnow; + if(skip_rate < 2 /* did not skip 2 frames yet */) { - if(syncdif >= -11719 /* not more than 500.0 ms late */) + // Skip a minimum of 2 frames between rendered frames. + // This prevents the DSTwo-DS link from being too busy + // to return button statuses. + ++skip_rate; + IPPU.RenderThisFrame = FALSE; + sync_next += frame_time; + } + else if(syncdif < 0) + { + /* + * If we're consistently late, delay up to 8 frames. + * + * That really helps with certain games, such as + * Super Mario RPG and Yoshi's Island. + */ + if(++skip_rate < 10) { - IPPU.RenderThisFrame = FALSE; - sync_next += frame_time; + if(syncdif >= -11719 /* not more than 500.0 ms late */) + { + IPPU.RenderThisFrame = FALSE; + sync_next += frame_time; + } + else + { //lag more than 0.5s, maybe paused + IPPU.RenderThisFrame = TRUE; + sync_next = syncnow + frame_time; + } } else - { //lag more than 0.5s, maybe paused + { + skip_rate = 0; IPPU.RenderThisFrame = TRUE; sync_next = syncnow + frame_time; } } - else + else // Early { skip_rate = 0; + if (syncdif > 0) + { + do { + S9xProcessSound (0); +#ifdef ACCUMULATE_JOYPAD +/* + * This call allows NDSSFC to synchronise the DS controller more often. + * If porting a later version of Snes9x into NDSSFC, it is essential to + * preserve it. + */ + NDSSFCAccumulateJoypad (); +#endif + syncdif = sync_next - getSysTime(); + } while (syncdif > 0); + } + IPPU.RenderThisFrame = TRUE; - sync_next = syncnow + frame_time; + sync_next += frame_time; } - } - else // Early - { - skip_rate = 0; - ds2_setCPUclocklevel(0); - if (syncdif > 0) - udelay(syncdif * 128 / 3 /* times 42 + 2/3 microseconds */); - set_cpu_clock(clock_speed_number); - S9xProcessSound (0); - - IPPU.RenderThisFrame = TRUE; - sync_next += frame_time; - } #if 0 - if(++framenum >= 60) + if(++framenum >= 60) + { + syncdif = syncnow - sync_last; + sync_last = syncnow; + framenum = 0; + //printf("T %d %d\n", syncdif*42667/1000, realframe); + realframe = 0; + } +#endif + } + else /* if (Settings.SkipFrames != AUTO_FRAMERATE) */ { - syncdif = syncnow - sync_last; + // frame_time is in getSysTime units: 42.667 microseconds. + uint32 frame_time = Settings.PAL ? 468 /* = 20.0 ms */ : 391 /* = 16.67 ms */; sync_last = syncnow; - framenum = 0; - //printf("T %d %d\n", syncdif*42667/1000, realframe); - realframe = 0; - } + if (++skip_rate > Settings.SkipFrames) + { + skip_rate = 0; + IPPU.RenderThisFrame = TRUE; + // Are we early? + syncdif = sync_next - syncnow; + if (syncdif > 0) + { + do { + S9xProcessSound (0); +#ifdef ACCUMULATE_JOYPAD +/* + * This call allows NDSSFC to synchronise the DS controller more often. + * If porting a later version of Snes9x into NDSSFC, it is essential to + * preserve it. + */ + NDSSFCAccumulateJoypad (); #endif - } - else /* if (Settings.SkipFrames != AUTO_FRAMERATE && !game_fast_forward && !temporary_fast_forward) */ - { - // frame_time is in getSysTime units: 42.667 microseconds. - uint32 frame_time = Settings.PAL ? 468 /* = 20.0 ms */ : 391 /* = 16.67 ms */; - sync_last = syncnow; - if (++skip_rate > Settings.SkipFrames) - { - skip_rate = 0; - IPPU.RenderThisFrame = TRUE; - // Are we early? - syncdif = sync_next - syncnow; - if (syncdif > 0) + syncdif = sync_next - getSysTime(); + } while (syncdif > 0); + // After that little delay, what time is it? + syncnow = getSysTime(); + } + sync_next = syncnow + frame_time * (Settings.SkipFrames + 1); + } + else { - ds2_setCPUclocklevel(0); - udelay(syncdif * 128 / 3 /* times 42 + 2/3 microseconds */); - set_cpu_clock(clock_speed_number); - S9xProcessSound (0); - // After that little delay, what time is it? - syncnow = getSysTime(); + IPPU.RenderThisFrame = FALSE; } - sync_next = syncnow + frame_time * (Settings.SkipFrames + 1); - } - else - { - IPPU.RenderThisFrame = FALSE; } } @@ -901,150 +983,189 @@ void S9xGenerateSound () } } -void S9xProcessSound (unsigned int) -{ - unsigned short *audiobuff; +#define SOUND_EMISSION_INTERVAL ((unsigned int) ((((unsigned long long) DS2_BUFFER_SIZE * 1000000) / SND_SAMPLE_RATE) * 3 / 128)) +#define TRUE_SOUND_EMISSION_INTERVAL ((((double) DS2_BUFFER_SIZE * 1000000) / SND_SAMPLE_RATE) * 3 / 128) +#define SOUND_EMISSION_INTERVAL_ERROR ((int) ((TRUE_SOUND_EMISSION_INTERVAL - SOUND_EMISSION_INTERVAL) * FIXED_POINT)) +static unsigned int LastSoundEmissionTime = 0; - if (so.mute_sound || !game_enable_audio) - return; +/* + * Accumulated error in the sound emission time. The unit is as follows: + * FIXED_POINT = 42.667 microseconds. + * As the error goes past FIXED_POINT, the new target for sound emission + * becomes 42.667 microseconds LATER. This helps with sound buffer overruns, + * correctly dealing with the fact that 42.667 microseconds does not fit + * an integer number of times in 1/32000 second (or whatever sampling rate). + */ +static unsigned int SoundEmissionTimeError = 0; - if(ds2_checkAudiobuff() > 4) +void S9xProcessSound (unsigned int) +{ + if (!game_enable_audio) return; - /* Number of samples to generate now */ - int sample_count; - sample_count = so.buffer_size; -#ifndef FOREVER_16_BIT_SOUND - if (so.sixteen_bit) + unsigned int Now = getSysTime(); + if (Now - LastSoundEmissionTime >= SOUND_EMISSION_INTERVAL) { -#endif - /* to prevent running out of buffer space, - * create less samples - */ - sample_count >>= 1; -#ifndef FOREVER_16_BIT_SOUND - } -#endif + if(ds2_checkAudiobuff() > AUDIO_BUFFER_COUNT - 1) + { + LastSoundEmissionTime++; + return; + } - audiobuff = (unsigned short*)ds2_getAudiobuff(); - if(NULL == audiobuff) //There are audio queue in sending or wait to send - { - return; - } + unsigned short *audiobuff; - /* If we need more audio samples */ - if (so.samples_mixed_so_far < sample_count) - { - /* Where to put the samples to */ + if (Now - LastSoundEmissionTime >= 11719 /* 500 milliseconds */) + { + LastSoundEmissionTime = Now; + // We were probably paused. Restart sending sound, + // synchronising from now. + } + else + { + LastSoundEmissionTime += SOUND_EMISSION_INTERVAL; + SoundEmissionTimeError += SOUND_EMISSION_INTERVAL_ERROR; + if (SoundEmissionTimeError >= FIXED_POINT) + { + LastSoundEmissionTime += SoundEmissionTimeError >> FIXED_POINT_SHIFT; + SoundEmissionTimeError &= FIXED_POINT_REMAINDER; + } + } + /* Number of samples to generate now */ + int sample_count = so.buffer_size; #ifndef FOREVER_16_BIT_SOUND - unsigned byte_offset = (so.play_position + - (so.sixteen_bit ? (so.samples_mixed_so_far << 1) : so.samples_mixed_so_far)) & SOUND_BUFFER_SIZE_MASK; -#else - unsigned byte_offset = (so.play_position + - (so.samples_mixed_so_far << 1)) & SOUND_BUFFER_SIZE_MASK; + if (so.sixteen_bit) + { +#endif + /* to prevent running out of buffer space, + * create less samples + */ + sample_count >>= 1; +#ifndef FOREVER_16_BIT_SOUND + } #endif - //printf ("%d:", sample_count - so.samples_mixed_so_far); fflush (stdout); - if (Settings.SoundSync == 2) + audiobuff = (unsigned short*)ds2_getAudiobuff(); + while (audiobuff == NULL) //There are audio queue in sending or wait to send { - /*memset (Buf + (byte_offset & SOUND_BUFFER_SIZE_MASK), 0, - sample_count - so.samples_mixed_so_far);*/ +#ifdef ACCUMULATE_JOYPAD + NDSSFCAccumulateJoypad (); +#endif + audiobuff = (unsigned short*)ds2_getAudiobuff(); } - else + + /* If we need more audio samples */ + if (so.samples_mixed_so_far < sample_count) { - /* Mix the missing samples */ + /* Where to put the samples to */ #ifndef FOREVER_16_BIT_SOUND - int bytes_so_far = so.sixteen_bit ? (so.samples_mixed_so_far << 1) : - so.samples_mixed_so_far; + unsigned byte_offset = (so.play_position + + (so.sixteen_bit ? (so.samples_mixed_so_far << 1) : so.samples_mixed_so_far)) & SOUND_BUFFER_SIZE_MASK; #else - int bytes_so_far = so.samples_mixed_so_far << 1; + unsigned byte_offset = (so.play_position + + (so.samples_mixed_so_far << 1)) & SOUND_BUFFER_SIZE_MASK; #endif - uint32 samples_to_write = sample_count - so.samples_mixed_so_far; - do + if (Settings.SoundSync == 2) { - int bytes_this_run = samples_to_write; + /*memset (Buf + (byte_offset & SOUND_BUFFER_SIZE_MASK), 0, + sample_count - so.samples_mixed_so_far);*/ + } + else + { + /* Mix the missing samples */ #ifndef FOREVER_16_BIT_SOUND - if (so.sixteen_bit) + int bytes_so_far = so.sixteen_bit ? (so.samples_mixed_so_far << 1) : + so.samples_mixed_so_far; +#else + int bytes_so_far = so.samples_mixed_so_far << 1; #endif - bytes_this_run <<= 1; - if (byte_offset + bytes_this_run > SOUND_BUFFER_SIZE) + uint32 samples_to_write = sample_count - so.samples_mixed_so_far; + do { - bytes_this_run = SOUND_BUFFER_SIZE - byte_offset; - } + int bytes_this_run = samples_to_write; +#ifndef FOREVER_16_BIT_SOUND + if (so.sixteen_bit) +#endif + bytes_this_run <<= 1; - if (bytes_so_far + bytes_this_run > so.buffer_size) - { - bytes_this_run = so.buffer_size - bytes_so_far; - if (bytes_this_run == 0) - break; - } + if (byte_offset + bytes_this_run > SOUND_BUFFER_SIZE) + { + bytes_this_run = SOUND_BUFFER_SIZE - byte_offset; + } - int samples_this_run = bytes_this_run; + if (bytes_so_far + bytes_this_run > so.buffer_size) + { + bytes_this_run = so.buffer_size - bytes_so_far; + if (bytes_this_run == 0) + break; + } + + int samples_this_run = bytes_this_run; #ifndef FOREVER_16_BIT_SOUND - if (so.sixteen_bit) + if (so.sixteen_bit) #endif - samples_this_run >>= 1; + samples_this_run >>= 1; - S9xMixSamples (Buf + byte_offset, samples_this_run); - so.samples_mixed_so_far += samples_this_run; - samples_to_write -= samples_this_run; + S9xMixSamples (Buf + byte_offset, samples_this_run); + so.samples_mixed_so_far += samples_this_run; + samples_to_write -= samples_this_run; #ifndef FOREVER_16_BIT_SOUND - bytes_so_far += so.sixteen_bit ? (samples_this_run << 1) : - samples_this_run; + bytes_so_far += so.sixteen_bit ? (samples_this_run << 1) : + samples_this_run; #else - bytes_so_far += samples_this_run << 1; + bytes_so_far += samples_this_run << 1; #endif - byte_offset = (byte_offset + bytes_this_run) & SOUND_BUFFER_SIZE_MASK; - } while (samples_to_write > 0); + byte_offset = (byte_offset + bytes_this_run) & SOUND_BUFFER_SIZE_MASK; + } while (samples_to_write > 0); + } } - } -// if (!so.mute_sound) - { - unsigned bytes_to_write = sample_count; + // if (!so.mute_sound) + { + unsigned bytes_to_write = sample_count; #ifndef FOREVER_16_BIT_SOUND - if(so.sixteen_bit) + if(so.sixteen_bit) #endif - bytes_to_write <<= 1; + bytes_to_write <<= 1; - unsigned byte_offset = so.play_position; - so.play_position = (so.play_position + bytes_to_write) & SOUND_BUFFER_SIZE_MASK; /* wrap to beginning */ + unsigned byte_offset = so.play_position; + so.play_position = (so.play_position + bytes_to_write) & SOUND_BUFFER_SIZE_MASK; /* wrap to beginning */ - unsigned short *dst_pt = audiobuff; - unsigned short *dst_pt1 = dst_pt + DS2_BUFFER_SIZE; + unsigned short *dst_pt = audiobuff; + unsigned short *dst_pt1 = dst_pt + DS2_BUFFER_SIZE; - /* Feed the samples to the soundcard until nothing is left */ - for(;;) - { - int I = bytes_to_write; - if (byte_offset + I > SOUND_BUFFER_SIZE) + /* Feed the samples to the soundcard until nothing is left */ + for(;;) { - I = SOUND_BUFFER_SIZE - byte_offset; - } - if(I == 0) break; + int I = bytes_to_write; + if (byte_offset + I > SOUND_BUFFER_SIZE) + { + I = SOUND_BUFFER_SIZE - byte_offset; + } + if(I == 0) break; -// memcpy(dst_pt, (char *) Buf + byte_offset, I); -// dst_pt += I; + // memcpy(dst_pt, (char *) Buf + byte_offset, I); + // dst_pt += I; - unsigned short *src_pt= (unsigned short*)(Buf + byte_offset); - for(int m= 0; m < I/4; m++) - { - *dst_pt++= *src_pt++;//(*src_pt++) <<1; - *dst_pt1++= *src_pt++;//(*src_pt++) <<1; + unsigned short *src_pt= (unsigned short*)(Buf + byte_offset); + for(int m= 0; m < I/4; m++) + { + *dst_pt++= *src_pt++;//(*src_pt++) <<1; + *dst_pt1++= *src_pt++;//(*src_pt++) <<1; + } + + bytes_to_write -= I; + byte_offset = (byte_offset + I) & SOUND_BUFFER_SIZE_MASK; /* wrap */ } - bytes_to_write -= I; - byte_offset = (byte_offset + I) & SOUND_BUFFER_SIZE_MASK; /* wrap */ - } + ds2_updateAudio(); - ds2_updateAudio(); + /* All data sent. */ + } - /* All data sent. */ + so.samples_mixed_so_far -= sample_count; } - - so.samples_mixed_so_far -= sample_count; } /* @@ -1066,68 +1187,99 @@ const unsigned int keymap[12] = { static bool8 SoundToggleWasHeld = FALSE; -unsigned int S9xReadJoypad (int which1) -{ - struct key_buf inputdata; +#ifdef ACCUMULATE_JOYPAD +// These are kept as DS key bitfields until it's time to send them to Snes9x. +static uint32 PreviousControls = 0x00000000; +static uint32 ControlsPressed = 0x00000000; +static uint32 ControlsReleased = 0x00000000; +void NDSSFCAccumulateJoypad () +{ + struct key_buf inputdata; ds2_getrawInput(&inputdata); - if (inputdata.key & KEY_LID) + ControlsPressed |= inputdata.key & ~PreviousControls; + ControlsReleased |= PreviousControls & ~inputdata.key; +} +#endif // ACCUMULATE_JOYPAD + +uint32 S9xReadJoypad (int which1) +{ + if(which1 < 1) { - ds2_setCPUclocklevel(0); - ds2_setSupend(); - do { + uint32 Controls; +#ifdef ACCUMULATE_JOYPAD + Controls = (PreviousControls | ControlsPressed) & ~ControlsReleased; + PreviousControls = Controls; + ControlsPressed = ControlsReleased = 0x00000000; +#else + { + struct key_buf inputdata; ds2_getrawInput(&inputdata); - mdelay(1); - } while (inputdata.key & KEY_LID); - ds2_wakeup(); - set_cpu_clock(clock_speed_number); - } - u32 HotkeyReturnToMenu = game_config.HotkeyReturnToMenu != 0 ? game_config.HotkeyReturnToMenu : emu_config.HotkeyReturnToMenu; - u32 HotkeyTemporaryFastForward = game_config.HotkeyTemporaryFastForward != 0 ? game_config.HotkeyTemporaryFastForward : emu_config.HotkeyTemporaryFastForward; - u32 HotkeyToggleSound = game_config.HotkeyToggleSound != 0 ? game_config.HotkeyToggleSound : emu_config.HotkeyToggleSound; + Controls = inputdata.key; + } +#endif - if(inputdata.key & KEY_TOUCH || - (HotkeyReturnToMenu && ((inputdata.key & HotkeyReturnToMenu) == HotkeyReturnToMenu)) - ) //Active menu - Settings.Paused = 1; + if (Controls & KEY_LID) + { + LowFrequencyCPU(); + ds2_setSupend(); + struct key_buf inputdata; + do { + ds2_getrawInput(&inputdata); + mdelay(1); + } while (inputdata.key & KEY_LID); + ds2_wakeup(); + // Before starting to emulate again, turn off the lower + // screen's backlight. + mdelay(100); // needed to avoid ds2_setBacklight crashing + ds2_setBacklight(2); + GameFrequencyCPU(); + } - temporary_fast_forward = - (HotkeyTemporaryFastForward && ((inputdata.key & HotkeyTemporaryFastForward) == HotkeyTemporaryFastForward)) - ; + u32 HotkeyReturnToMenu = game_config.HotkeyReturnToMenu != 0 ? game_config.HotkeyReturnToMenu : emu_config.HotkeyReturnToMenu; + u32 HotkeyTemporaryFastForward = game_config.HotkeyTemporaryFastForward != 0 ? game_config.HotkeyTemporaryFastForward : emu_config.HotkeyTemporaryFastForward; + u32 HotkeyToggleSound = game_config.HotkeyToggleSound != 0 ? game_config.HotkeyToggleSound : emu_config.HotkeyToggleSound; - bool8 SoundToggleIsHeld = - (HotkeyToggleSound && ((inputdata.key & HotkeyToggleSound) == HotkeyToggleSound)) - ; + if(Controls & KEY_TOUCH || + (HotkeyReturnToMenu && ((Controls & HotkeyReturnToMenu) == HotkeyReturnToMenu)) + ) //Active menu + Settings.Paused = 1; - if (SoundToggleIsHeld && !SoundToggleWasHeld) - { - game_enable_audio = !game_enable_audio; - game_disableAudio(); - } + temporary_fast_forward = + (HotkeyTemporaryFastForward && ((Controls & HotkeyTemporaryFastForward) == HotkeyTemporaryFastForward)) + ; - SoundToggleWasHeld = SoundToggleIsHeld; + bool8 SoundToggleIsHeld = + (HotkeyToggleSound && ((Controls & HotkeyToggleSound) == HotkeyToggleSound)) + ; - if(which1 < 1) - { - unsigned int key; + if (SoundToggleIsHeld && !SoundToggleWasHeld) + { + game_enable_audio = !game_enable_audio; + game_disableAudio(); + } + + SoundToggleWasHeld = SoundToggleIsHeld; + + uint32 key = 0x80000000; // Required by Snes9x // DS -> SNES - key = (inputdata.key & KEY_A ) << 7; // 0x0001 -> 0x0080 - key |= (inputdata.key & KEY_B ) << 14; // 0x0002 -> 0x8000 - key |= (inputdata.key & KEY_SELECT) << 11; // 0x0004 -> 0x2000 - key |= (inputdata.key & KEY_START ) << 9; // 0x0008 -> 0x1000 - key |= (inputdata.key & KEY_UP ) << 5; // 0x0040 -> 0x0800 + key |= (Controls & KEY_A ) << 7; // 0x0001 -> 0x0080 + key |= (Controls & KEY_B ) << 14; // 0x0002 -> 0x8000 + key |= (Controls & KEY_SELECT) << 11; // 0x0004 -> 0x2000 + key |= (Controls & KEY_START ) << 9; // 0x0008 -> 0x1000 + key |= (Controls & KEY_UP ) << 5; // 0x0040 -> 0x0800 // 0x0010 -> 0x0100; 0x0020 -> 0x0200 // 0x0030 -> 0x0300 - key |= (inputdata.key & (KEY_RIGHT | KEY_LEFT)) << 4; + key |= (Controls & (KEY_RIGHT | KEY_LEFT)) << 4; // 0x0100 -> 0x0010; 0x0200 -> 0x0020; 0x0400 -> 0x0040 // 0x0700 -> 0x0070 - key |= (inputdata.key & (KEY_R | KEY_L | KEY_X)) >> 4; + key |= (Controls & (KEY_R | KEY_L | KEY_X)) >> 4; // 0x0080 -> 0x0400; 0x0800 -> 0x4000 // 0x0880 -> 0x4400 - key |= (inputdata.key & (KEY_DOWN | KEY_Y)) << 3; + key |= (Controls & (KEY_DOWN | KEY_Y)) << 3; /* for(i= 0; i < 12; i++) //remap key { @@ -1135,7 +1287,7 @@ unsigned int S9xReadJoypad (int which1) } */ - return (key | 0x80000000); + return key; } else return 0; diff --git a/source/nds/entry.h b/source/nds/entry.h index a6bd350..0728768 100644 --- a/source/nds/entry.h +++ b/source/nds/entry.h @@ -7,7 +7,9 @@ extern "C" { void game_restart(void); - int load_gamepak(char* file); + int load_gamepak(const char* file); + + extern unsigned int AutoCPUFrequency; #ifdef __cplusplus } #endif diff --git a/source/nds/gui.c b/source/nds/gui.c index 09e01ac..4299db2 100644 --- a/source/nds/gui.c +++ b/source/nds/gui.c @@ -45,23 +45,27 @@ char rom_path[MAX_PATH]; char gamepak_name[MAX_PATH]; char gcheat_filename[MAX_PATH]; +//program arguments +char argv[2][MAX_PATH]; + // If adding a language, make sure you update the size of the array in // message.h too. -char *lang[3] = - { +char *lang[4] = + { "English", // 0 "简体中文", // 1 - "Français", // 2 + "Français", // 2 + "Deutsch", // 3 }; -char *language_options[] = { (char *) &lang[0], (char *) &lang[1], (char *) &lang[2] }; +char *language_options[] = { (char *) &lang[0], (char *) &lang[1], (char *) &lang[2], (char *) &lang[3] }; /****************************************************************************** * Macro definition ******************************************************************************/ #define SUBMENU_ROW_NUM 6 -#define NDSSFC_VERSION "1.23" +#define NDSSFC_VERSION "1.28" #define SAVE_STATE_SLOT_NUM 16 @@ -289,7 +293,6 @@ u32 game_enable_audio = 1; /****************************************************************************** ******************************************************************************/ static u32 menu_cheat_page = 0; -u32 clock_speed_number = 5; u32 gamepad_config_menu; /****************************************************************************** @@ -324,6 +327,21 @@ gui_action_type get_gui_input(void) key = getKey(); + if (key & KEY_LID) + { + ds2_setSupend(); + struct key_buf inputdata; + do { + ds2_getrawInput(&inputdata); + mdelay(1); + } while (inputdata.key & KEY_LID); + ds2_wakeup(); + // In the menu, the lower screen's backlight needs to be on, + // and it is on right away after resuming from suspend. + // mdelay(100); // needed to avoid ds2_setBacklight crashing + // ds2_setBacklight(3); + } + switch(key) { case KEY_UP: @@ -420,53 +438,52 @@ void change_ext(char *src, char *buffer, char *extension) --------------------------------------------------------*/ static int sort_function(const void *dest_str_ptr, const void *src_str_ptr) { - char *dest_str = *((char **)dest_str_ptr); - char *src_str = *((char **)src_str_ptr); + char *dest_str = ((char *)dest_str_ptr); + char *src_str = ((char *)src_str_ptr); // For files and directories, . and .. sort first. - if(src_str[0] == '.') + if(src_str[0] == '.' && dest_str[0] != '.') return 1; - if(dest_str[0] == '.') + if(dest_str[0] == '.' && src_str[0] != '.') return -1; return strcasecmp(dest_str, src_str); } -static int my_array_partion(void *array, int left, int right) +static int my_array_partion(void **array, int left, int right) { - unsigned int pivot= *((unsigned int*)array + left); - - while(left < right) - { - while(sort_function((void*)((unsigned int*)array+left), (void*)((unsigned int *)array+right)) < 0) { - right--; - } - - if(right== left) break; - *((unsigned int*)array + left) = *((unsigned int*)array + right); - *((unsigned int*)array + right) = pivot; - - if(left < right) - { - left++; - if(right== left) break; - } - - while(sort_function((void*)((unsigned int*)array+right), (void*)((unsigned int *)array+left)) > 0) { - left++; - } + // Choose a pivot, left <= pivot <= right + unsigned int pivotIndex = left + (right - left) / 2; + + // Move pivot value to the end + void *temp = array[pivotIndex]; + array[pivotIndex] = array[right]; + array[right] = temp; + + // Move values that sort before the pivot value to before the new + // pivot's location + unsigned int storeIndex = left, i; + for (i = left; i <= right - 1; i++) + { + if (sort_function(array[i], array[right]) < 0) + { + temp = array[i]; + array[i] = array[storeIndex]; + array[storeIndex] = temp; + storeIndex++; + } + } - if(left== right) break; - *((unsigned int*)array + right) = *((unsigned int*)array + left); - *((unsigned int*)array + left) = pivot; - right--; - } + // Move the pivot value to its correct location + temp = array[storeIndex]; + array[storeIndex] = array[right]; + array[right] = temp; - return left; + return storeIndex; } -static void my_qsort(void *array, int left, int right) +static void my_qsort(void **array, int left, int right) { if(left < right) { @@ -558,7 +575,7 @@ static int manage_filelist_info(struct FILE_LIST_INFO *filelist_infop, int flag) int i; void *pt; - //Increase all + //Increase all if(flag & 0x1) { i = NAME_MEM_SIZE; @@ -733,9 +750,9 @@ static int load_file_list(struct FILE_LIST_INFO *filelist_infop) #if 0 my_qsort((void *)file_list, 0, num_files-1); #else //to support ".." directory, but take it as file - my_qsort((void *)file_list, 1, num_files-1); + my_qsort((void **)file_list, 1, num_files-1); #endif - my_qsort((void *)dir_list, 0, num_dirs-1); + my_qsort((void **)dir_list, 0, num_dirs-1); return 0; } @@ -820,6 +837,7 @@ s32 load_file(char **wildcards, char *result, char *default_dir_name) { case CURSOR_TOUCH: ds2_getrawInput(&inputdata); + wait_Allkey_release(0); // ___ 33 This screen has 6 possible rows. Touches // ___ 60 above or below these are ignored. // . . . (+27) @@ -985,6 +1003,7 @@ s32 load_file(char **wildcards, char *result, char *default_dir_name) break; case CURSOR_SELECT: + wait_Allkey_release(0); //file selected if(selected_item_on_list + 1 <= num_files) { @@ -1024,6 +1043,7 @@ s32 load_file(char **wildcards, char *result, char *default_dir_name) case CURSOR_BACK: { + wait_Allkey_release(0); char *ext_pos; strcpy(filelist_info.current_path, default_dir_name); @@ -1041,6 +1061,7 @@ s32 load_file(char **wildcards, char *result, char *default_dir_name) } case CURSOR_EXIT: + wait_Allkey_release(0); return_value = -1; repeat = 0; break; @@ -1082,7 +1103,7 @@ s32 load_file(char **wildcards, char *result, char *default_dir_name) //Path if(-1 == redraw) { draw_hscroll_over(0); - draw_hscroll_init(down_screen_addr, 49, 10, 170, COLOR_TRANS, + draw_hscroll_init(down_screen_addr, 49, 10, 170, COLOR_TRANS, COLOR_WHITE, default_dir_name); path_scroll = 0x8000; //first scroll left } @@ -1129,7 +1150,7 @@ s32 load_file(char **wildcards, char *result, char *default_dir_name) pt = file_list[m]; } - draw_hscroll_init(down_screen_addr, 41, 40 + k*27, 185, + draw_hscroll_init(down_screen_addr, 41, 40 + k*27, 185, COLOR_TRANS, color, pt); } @@ -1260,7 +1281,7 @@ u32 play_screen_snapshot(void) if(draw_yesno_dialog(DOWN_SCREEN, 115, msg[MSG_GENERAL_CONFIRM_WITH_A], msg[MSG_GENERAL_CANCEL_WITH_B])) return 1; - else + else return 0; } @@ -1365,7 +1386,7 @@ u32 play_screen_snapshot(void) time1= time0; } break; - + case CURSOR_DOWN: if(!pause) { @@ -1373,21 +1394,21 @@ u32 play_screen_snapshot(void) time1= time0; } break; - + case CURSOR_LEFT: time1 = ticks; if(i > 1) i -= 2; else if(i == 1) i= file_num -1; else i= file_num -2; break; - + case CURSOR_RIGHT: time1 = ticks; break; - + case CURSOR_SELECT: if(!pause) - { + { time1 = -1; pause= 1; } @@ -1395,15 +1416,15 @@ u32 play_screen_snapshot(void) { time1 = ticks; pause= 0; - } + } break; - - case CURSOR_BACK: + + case CURSOR_BACK: if(screenp) free((void*)screenp); //deconstruct filelist_info struct manage_filelist_info(&filelist_info, -1); repeat = 0; - break; + break; default: gui_action= CURSOR_NONE; break; @@ -1443,7 +1464,7 @@ int search_dir(char *directory, char* directory_path) //while((current_file = readdir(current_dir)) != NULL) while((current_file = readdir_ex(current_dir, &st)) != NULL) { - //Is directory + //Is directory if(S_ISDIR(st.st_mode)) { if(strcmp(".", current_file->d_name) || strcmp("..", current_file->d_name)) @@ -1622,7 +1643,7 @@ int save_state(char* file, void* screen) n = ftell(fp); ds2_getTime(&time); - sprintf(str, "%02d-%02d %02d:%02d:%02d", + sprintf(str, "%02d-%02d %02d:%02d:%02d", time.month, time.day, time.hours, time.minutes, time.seconds); PRINT_STRING_BG(screen, str, COLOR_WHITE, COLOR_BLACK, 0, 0); @@ -1637,12 +1658,22 @@ int save_state(char* file, void* screen) return 0; } -void set_cpu_clock(u32 num) +void LowFrequencyCPU() { - u32 clock_speed_table[6] = {6, 9, 10, 11, 12, 13}; //240, 300, 336, 360, 384, 394 + ds2_setCPUclocklevel(0); // 60 MHz +} - if(num <= 5) - ds2_setCPUclocklevel(clock_speed_table[num]); +void HighFrequencyCPU() +{ + ds2_setCPUclocklevel(13); // 396 MHz +} + +void GameFrequencyCPU() +{ + u32 clock_speed_table[6] = {6, 9, 10, 11, 12, 13}; //240, 300, 336, 360, 384, 396 + + if(game_config.clock_speed_number <= 5) + ds2_setCPUclocklevel(clock_speed_table[game_config.clock_speed_number]); } void savefast_int(void) @@ -1668,7 +1699,7 @@ unsigned int frame_interval; /*-------------------------------------------------------- Main Menu --------------------------------------------------------*/ -u32 menu(u16 *screen) +u32 menu(u16 *screen, bool8 FirstInvocation) { gui_action_type gui_action; u32 i; @@ -1684,7 +1715,7 @@ u32 menu(u16 *screen) MENU_TYPE *current_menu = NULL; MENU_OPTION_TYPE *current_option = NULL; MENU_OPTION_TYPE *display_option = NULL; - + u32 current_option_num; // u32 parent_option_num; u32 string_select; @@ -1692,6 +1723,9 @@ u32 menu(u16 *screen) u16 *bg_screenp; u32 bg_screenp_color; + GAME_CONFIG PreviousGameConfig; // Compared with current settings to + EMU_CONFIG PreviousEmuConfig; // determine if they need to be saved + auto void choose_menu(); auto void menu_return(); auto void menu_exit(); @@ -1732,7 +1766,9 @@ u32 menu(u16 *screen) auto void latest_game_menu_end(); auto void language_set(); auto void game_fastforward(); +#ifdef ENABLE_FREE_SPACE auto void show_card_space(); +#endif auto void savestate_selitem(u32 sel, u32 y_pos); auto void game_state_menu_passive(); auto void gamestate_delette_menu_passive(); @@ -1747,131 +1783,94 @@ u32 menu(u16 *screen) void menu_exit() { - ds2_setCPUclocklevel(13); // Crank it up, leave quickly - if(gamepak_name[0] != 0) - { - game_config.clock_speed_number = clock_speed_number; - - reorder_latest_file(); + HighFrequencyCPU(); // Crank it up, leave quickly + if(gamepak_name[0] != 0) + { S9xAutoSaveSRAM (); - save_game_config_file(); } - save_emu_config_file(); quit(); } - void menu_load() + void SaveConfigsIfNeeded() { - char *file_ext[] = { ".smc", ".sfc", ".zip", NULL }; - - if(gamepak_name[0] != 0) - { - S9xAutoSaveSRAM (); + if (memcmp(&PreviousGameConfig, &game_config, sizeof(GAME_CONFIG)) != 0) save_game_config_file(); - } + if (memcmp(&PreviousEmuConfig, &emu_config, sizeof(EMU_CONFIG)) != 0) + save_emu_config_file(); + } - if(load_file(file_ext, tmp_filename, g_default_rom_dir) != -1) - { - strcpy(line_buffer, g_default_rom_dir); - strcat(line_buffer, "/"); - strcat(line_buffer, tmp_filename); + void PreserveConfigs() + { + memcpy(&PreviousGameConfig, &game_config, sizeof(GAME_CONFIG)); + memcpy(&PreviousEmuConfig, &emu_config, sizeof(EMU_CONFIG)); + } - draw_message(down_screen_addr, bg_screenp, 28, 31, 227, 165, bg_screenp_color); - draw_string_vcenter(down_screen_addr, 36, 100, 190, COLOR_MSSG, msg[MSG_PROGRESS_LOADING_GAME]); - ds2_flipScreen(DOWN_SCREEN, DOWN_SCREEN_UPDATE_METHOD); + int LoadGameAndItsData(char *filename){ + if (gamepak_name[0] != '\0') { + S9xAutoSaveSRAM(); + } - ds2_setCPUclocklevel(13); - int load_result = load_gamepak(line_buffer); - ds2_setCPUclocklevel(0); - if(load_result == -1) - { - first_load = 1; - gamepak_name[0] = '\0'; - return; - } + draw_message(down_screen_addr, bg_screenp, 28, 31, 227, 165, bg_screenp_color); + draw_string_vcenter(down_screen_addr, 36, 100, 190, COLOR_MSSG, msg[MSG_PROGRESS_LOADING_GAME]); + ds2_flipScreen(DOWN_SCREEN, DOWN_SCREEN_UPDATE_METHOD); - strcpy(gamepak_name, tmp_filename); - first_load = 0; - load_game_config_file(); -// time_period_action(); + HighFrequencyCPU(); + int load_result = load_gamepak(filename); + LowFrequencyCPU(); - return_value = 1; - repeat = 0; + if(load_result == -1) + { + first_load = 1; + gamepak_name[0] = '\0'; + return 0; + } - reorder_latest_file(); - get_savestate_filelist(); + char tempPath[MAX_PATH]; + strcpy(tempPath, filename); - game_fast_forward= 0; - } - else - { - choose_menu(current_menu); - } - } - - bool Get_Args(char *file, char **filebuf) - { - FILE* dat = fat_fopen(file, "rb"); - if(dat) - { - int i = 0; - while(!fat_feof (dat)) - { - fat_fgets(filebuf[i], 512, dat); - int len = strlen(filebuf[i]); - if(filebuf[i][len - 1] == '\n') - filebuf[i][len - 1] = '\0'; - i++; - } - - fat_fclose(dat); - fat_remove(file); - return i; - } - return 0; - } + //update folders and names for settings/config uses + char *dirEnd = strrchr(tempPath, '/'); + //make sure a valid path was provided + if(!dirEnd) + return 0; - int CheckLoad_Arg() - { - char args[2][512]; - char *argarray[2]; - - argarray[0] = args[0]; - argarray[1] = args[1]; - - if(!Get_Args("/plgargs.dat", argarray)) - return 0; - - fat_remove("plgargs.dat"); - - draw_message(down_screen_addr, bg_screenp, 28, 31, 227, 165, bg_screenp_color); - draw_string_vcenter(down_screen_addr, 36, 100, 190, COLOR_MSSG, msg[MSG_PROGRESS_LOADING_GAME]); - ds2_flipScreen(DOWN_SCREEN, DOWN_SCREEN_UPDATE_METHOD); + //copy file name as gamepak_name + strcpy(gamepak_name, dirEnd+1); + //then strip filename from directory path and set it + *dirEnd = '\0'; + strcpy(g_default_rom_dir, tempPath); - ds2_setCPUclocklevel(13); - int load_result = load_gamepak(args[1]); - ds2_setCPUclocklevel(0); + first_load = 0; + load_game_config_file(); + PreserveConfigs(); // Make the emulator not save what we've JUST read + // but it will save the emulator configuration below for latest files - if(load_result == -1) - { - first_load = 1; - gamepak_name[0] = '\0'; - return 0; - } + return_value = 1; + repeat = 0; - strcpy(gamepak_name, args[1]); - first_load = 0; - load_game_config_file(); + reorder_latest_file(); + get_savestate_filelist(); - return_value = 1; - repeat = 0; + game_fast_forward= 0; + return 1; + } - reorder_latest_file(); - get_savestate_filelist(); + void menu_load() + { + char *file_ext[] = { ".smc", ".sfc", ".zip", NULL }; + + if(load_file(file_ext, tmp_filename, g_default_rom_dir) != -1) + { + strcpy(line_buffer, g_default_rom_dir); + strcat(line_buffer, "/"); + strcat(line_buffer, tmp_filename); - game_fast_forward= 0; - return 1; - + LoadGameAndItsData(line_buffer); + } + else + { + choose_menu(current_menu); + } } void menu_restart() @@ -2060,9 +2059,9 @@ u32 menu(u16 *screen) draw_string_vcenter(down_screen_addr, 36, 100, 190, COLOR_MSSG, msg[MSG_PROGRESS_SAVED_STATE_CREATING]); ds2_flipScreen(DOWN_SCREEN, DOWN_SCREEN_UPDATE_METHOD); - ds2_setCPUclocklevel(13); + HighFrequencyCPU(); int flag = save_state(tmp_filename, (void*)screen); - ds2_setCPUclocklevel(0); + LowFrequencyCPU(); //clear message draw_message(down_screen_addr, NULL, 28, 31, 227, 96, 0); if(flag < 0) @@ -2076,17 +2075,13 @@ u32 menu(u16 *screen) ds2_flipScreen(DOWN_SCREEN, DOWN_SCREEN_UPDATE_METHOD); - //save game config - reorder_latest_file(); - save_game_config_file(); - SavedStateCacheInvalidate (); mdelay(500); // let the progress message linger } } } - + void menu_load_state() { if(!first_load) @@ -2126,12 +2121,12 @@ u32 menu(u16 *screen) //right if(gui_action == CURSOR_SELECT) { - draw_message(down_screen_addr, bg_screenp, 28, 31, 227, 165, bg_screenp_color); + draw_message(down_screen_addr, bg_screenp, 28, 31, 227, 165, bg_screenp_color); draw_string_vcenter(up_screen_addr, 36, 75, 190, COLOR_MSSG, msg[MSG_PROGRESS_SAVED_STATE_LOADING]); - ds2_setCPUclocklevel(13); + HighFrequencyCPU(); int flag = load_state(tmp_filename); - ds2_setCPUclocklevel(0); + LowFrequencyCPU(); if(0 == flag) { return_value = 1; @@ -2146,9 +2141,9 @@ u32 menu(u16 *screen) } else //load screen snapshot { - ds2_setCPUclocklevel(13); + HighFrequencyCPU(); load_game_stat_snapshot(tmp_filename); - ds2_setCPUclocklevel(0); + LowFrequencyCPU(); } } else @@ -2210,7 +2205,7 @@ u32 menu(u16 *screen) } else if(current_option_num == 2) //delette single { - draw_message(down_screen_addr, bg_screenp, 28, 31, 227, 165, bg_screenp_color); + draw_message(down_screen_addr, bg_screenp, 28, 31, 227, 165, bg_screenp_color); if(SavedStateFileExists(delette_savestate_num)) { @@ -2278,7 +2273,7 @@ u32 menu(u16 *screen) { m= current_menu->screen_focus -1; draw_hscroll_over(m+1); - draw_hscroll_init(down_screen_addr, 23, 40 + m*27, 200, + draw_hscroll_init(down_screen_addr, 23, 40 + m*27, 200, COLOR_TRANS, COLOR_INACTIVE_ITEM, *dynamic_cheat_options[current_option_num].display_string); } else @@ -2288,7 +2283,7 @@ u32 menu(u16 *screen) m= current_menu->focus_option - current_menu->screen_focus+2; for(n= 0; n < SUBMENU_ROW_NUM-1; n++) - draw_hscroll_init(down_screen_addr, 23, 40 + n*27, 200, + draw_hscroll_init(down_screen_addr, 23, 40 + n*27, 200, COLOR_TRANS, COLOR_INACTIVE_ITEM, *dynamic_cheat_options[m+n].display_string); } } @@ -2296,7 +2291,7 @@ u32 menu(u16 *screen) if(current_option_num == 0) { draw_hscroll_over(0); - draw_hscroll_init(down_screen_addr, 50, 9, 180, + draw_hscroll_init(down_screen_addr, 50, 9, 180, COLOR_TRANS, COLOR_ACTIVE_ITEM, *dynamic_cheat_options[0].display_string); } @@ -2309,7 +2304,7 @@ u32 menu(u16 *screen) if(m >= SUBMENU_ROW_NUM) m -= 1; draw_hscroll_over(m+1); - draw_hscroll_init(down_screen_addr, 23, 40 + m*27, 200, + draw_hscroll_init(down_screen_addr, 23, 40 + m*27, 200, COLOR_TRANS, COLOR_ACTIVE_ITEM, *dynamic_cheat_options[current_option_num].display_string); } @@ -2323,7 +2318,7 @@ u32 menu(u16 *screen) { m = current_menu->screen_focus -1; draw_hscroll_over(m+1); - draw_hscroll_init(down_screen_addr, 23, 40 + m*27, 200, + draw_hscroll_init(down_screen_addr, 23, 40 + m*27, 200, COLOR_TRANS, COLOR_INACTIVE_ITEM, *dynamic_cheat_options[current_option_num].display_string); } else @@ -2338,7 +2333,7 @@ u32 menu(u16 *screen) if(k > SUBMENU_ROW_NUM) k = SUBMENU_ROW_NUM; for(n= 1; n < k; n++) - draw_hscroll_init(down_screen_addr, 23, 40 + n*27, 200, + draw_hscroll_init(down_screen_addr, 23, 40 + n*27, 200, COLOR_TRANS, COLOR_INACTIVE_ITEM, *dynamic_cheat_options[m+n].display_string); } } @@ -2350,7 +2345,7 @@ u32 menu(u16 *screen) if(current_option_num == 0) { draw_hscroll_over(0); - draw_hscroll_init(down_screen_addr, 50, 9, 180, + draw_hscroll_init(down_screen_addr, 50, 9, 180, COLOR_TRANS, COLOR_ACTIVE_ITEM, *dynamic_cheat_options[0].display_string); } } @@ -2365,7 +2360,7 @@ u32 menu(u16 *screen) m = current_menu->screen_focus -1; draw_hscroll_over(m+1); - draw_hscroll_init(down_screen_addr, 23, 40 + m*27, 200, + draw_hscroll_init(down_screen_addr, 23, 40 + m*27, 200, COLOR_TRANS, COLOR_ACTIVE_ITEM, *dynamic_cheat_options[current_option_num].display_string); } break; @@ -2641,7 +2636,7 @@ u32 menu(u16 *screen) mm = *(display_option->current_option); sprintf(line_buffer, *(display_option->display_string), str[mm]); - + PRINT_STRING_BG(down_screen_addr, line_buffer, color, COLOR_TRANS, 27, 38 + (display_option-> line_number)*32); } @@ -2718,22 +2713,9 @@ u32 menu(u16 *screen) { if(gui_action == CURSOR_LEFT || gui_action == CURSOR_RIGHT) { - ds2_setCPUclocklevel(13); // crank it up - if(bg_screenp != NULL) - { - bg_screenp_color = COLOR16(43, 11, 11); - memcpy(bg_screenp, down_screen_addr, 256*192*2); - } - else - bg_screenp_color = COLOR_BG; + HighFrequencyCPU(); // crank it up - draw_message(down_screen_addr, bg_screenp, 28, 31, 227, 165, bg_screenp_color); - draw_string_vcenter(down_screen_addr, 36, 75, 190, COLOR_MSSG, msg[MSG_CHANGE_LANGUAGE]); - draw_string_vcenter(down_screen_addr, 36, 95, 190, COLOR_MSSG, msg[MSG_CHANGE_LANGUAGE_WAITING]); - ds2_flipScreen(DOWN_SCREEN, DOWN_SCREEN_UPDATE_METHOD); - - load_language_msg(LANGUAGE_PACK, emu_config.language); - // gui_change_icon(emu_config.language); // uncomment if images change per language [Neb] + load_language_msg(LANGUAGE_PACK, emu_config.language); if(first_load) { @@ -2742,12 +2724,11 @@ u32 menu(u16 *screen) ds2_flipScreen(UP_SCREEN, 1); } - save_emu_config_file(); - ds2_setCPUclocklevel(0); // and back down - wait_Allkey_release(0); + LowFrequencyCPU(); // and back down } } +#ifdef ENABLE_FREE_SPACE unsigned int freespace; void show_card_space () { @@ -2791,6 +2772,7 @@ u32 menu(u16 *screen) PRINT_STRING_BG(down_screen_addr, line_buffer, COLOR_INACTIVE_ITEM, COLOR_TRANS, 147, 40 + (display_option->line_number)*27); } +#endif char *screen_ratio_options[] = { (char*)&msg[MSG_VIDEO_ASPECT_RATIO_0], (char*)&msg[MSG_VIDEO_ASPECT_RATIO_1], @@ -2800,6 +2782,10 @@ u32 menu(u16 *screen) char *frameskip_options[] = { (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_AUTOMATIC], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_0], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_1], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_2], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_3], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_4], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_5], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_6], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_7], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_8], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_9], (char*)&msg[MSG_VIDEO_FRAME_SKIPPING_10] }; + char *cpu_frequency_options[] = { (char*)&msg[MSG_OPTIONS_CPU_FREQUENCY_0], (char*)&msg[MSG_OPTIONS_CPU_FREQUENCY_1], (char*)&msg[MSG_OPTIONS_CPU_FREQUENCY_2], (char*)&msg[MSG_OPTIONS_CPU_FREQUENCY_3], (char*)&msg[MSG_OPTIONS_CPU_FREQUENCY_4], (char*)&msg[MSG_OPTIONS_CPU_FREQUENCY_5] }; + + char *fluidity_options[] = { (char*)&msg[MSG_VIDEO_AUDIO_FLUIDITY_PREFER_VIDEO], (char*)&msg[MSG_VIDEO_AUDIO_FLUIDITY_PREFER_AUDIO] }; + char *on_off_options[] = { (char*)&msg[MSG_GENERAL_OFF], (char*)&msg[MSG_GENERAL_ON] }; char *sound_seletion[] = { (char*)&msg[MSG_AUDIO_MUTED], (char*)&msg[MSG_AUDIO_ENABLED] }; @@ -2815,17 +2801,20 @@ u32 menu(u16 *screen) { /* 00 */ SUBMENU_OPTION(NULL, &msg[MSG_MAIN_MENU_VIDEO_AUDIO], NULL, 0), - /* 01 */ STRING_SELECTION_OPTION(NULL, NULL, &msg[FMT_VIDEO_ASPECT_RATIO], screen_ratio_options, + /* 01 */ STRING_SELECTION_OPTION(NULL, NULL, &msg[FMT_VIDEO_ASPECT_RATIO], screen_ratio_options, &game_config.graphic, 5, NULL, PASSIVE_TYPE, 1), - /* 02 */ STRING_SELECTION_OPTION(game_fastforward, NULL, &msg[FMT_VIDEO_FAST_FORWARD], on_off_options, + /* 02 */ STRING_SELECTION_OPTION(game_fastforward, NULL, &msg[FMT_VIDEO_FAST_FORWARD], on_off_options, &game_fast_forward, 2, NULL, ACTION_TYPE, 2), - + /* 03 */ STRING_SELECTION_OPTION(game_disableAudio, NULL, &msg[FMT_AUDIO_SOUND], sound_seletion, &game_enable_audio, 2, NULL, ACTION_TYPE, 3), - - /* 04 */ STRING_SELECTION_OPTION(game_set_frameskip, NULL, &msg[FMT_VIDEO_FRAME_SKIPPING], frameskip_options, - &game_config.frameskip_value, 12 /* auto (0) and 0..10 (1..11) make 12 option values */, NULL, ACTION_TYPE, 4) + + /* 04 */ STRING_SELECTION_OPTION(game_set_fluidity, NULL, &msg[FMT_VIDEO_AUDIO_FLUIDITY_PREFERENCE], fluidity_options, + &game_config.SoundSync, 2, NULL, ACTION_TYPE, 4), + + /* 05 */ STRING_SELECTION_OPTION(game_set_frameskip, NULL, &msg[FMT_VIDEO_FRAME_SKIPPING], frameskip_options, + &game_config.frameskip_value, 12 /* auto (0) and 0..10 (1..11) make 12 option values */, NULL, ACTION_TYPE, 5) }; MAKE_MENU(graphics, NULL, NULL, NULL, NULL, 0, 0); @@ -2854,10 +2843,12 @@ u32 menu(u16 *screen) { /* 00 */ SUBMENU_OPTION(NULL, &msg[MSG_MAIN_MENU_SAVED_STATES], NULL, 0), - /* 01 */ NUMERIC_SELECTION_ACTION_OPTION(menu_save_state, NULL, &msg[FMT_SAVED_STATE_CREATE], &savestate_index, SAVE_STATE_SLOT_NUM, NULL, 1), + // savestate_index is still a signed int + /* 01 */ NUMERIC_SELECTION_ACTION_OPTION(menu_save_state, NULL, &msg[FMT_SAVED_STATE_CREATE], (u32*) &savestate_index, SAVE_STATE_SLOT_NUM, NULL, 1), + // savestate_index is still a signed int /* 02 */ NUMERIC_SELECTION_ACTION_OPTION(menu_load_state, NULL, - &msg[FMT_SAVED_STATE_LOAD], &savestate_index, SAVE_STATE_SLOT_NUM, NULL, 2), + &msg[FMT_SAVED_STATE_LOAD], (u32*) &savestate_index, SAVE_STATE_SLOT_NUM, NULL, 2), /* 03 */ SUBMENU_OPTION(&gamestate_delette_menu, &msg[MSG_SAVED_STATE_DELETE_GENERAL], NULL, 5), }; @@ -2871,9 +2862,9 @@ u32 menu(u16 *screen) { /* 00 */ SUBMENU_OPTION(NULL, &msg[MSG_MAIN_MENU_CHEATS], NULL,0), - /* 01 */ CHEAT_OPTION(cheat_option_action, cheat_option_passive, + /* 01 */ CHEAT_OPTION(cheat_option_action, cheat_option_passive, ((CHEATS_PER_PAGE * menu_cheat_page) + 0), 1), - /* 02 */ CHEAT_OPTION(cheat_option_action, cheat_option_passive, + /* 02 */ CHEAT_OPTION(cheat_option_action, cheat_option_passive, ((CHEATS_PER_PAGE * menu_cheat_page) + 1), 2), /* 03 */ CHEAT_OPTION(cheat_option_action, cheat_option_passive, ((CHEATS_PER_PAGE * menu_cheat_page) + 2), 3), @@ -2940,7 +2931,7 @@ u32 menu(u16 *screen) /*-------------------------------------------------------- Tools --------------------------------------------------------*/ - MENU_OPTION_TYPE tools_options[] = + MENU_OPTION_TYPE tools_options[] = { /* 00 */ SUBMENU_OPTION(NULL, &msg[MSG_MAIN_MENU_TOOLS], NULL, 0), @@ -2952,10 +2943,10 @@ u32 menu(u16 *screen) // /* 02 */ SUBMENU_OPTION(&tools_keyremap_menu, &msg[MSG_SUB_MENU_31], NULL, 2), -// /* 03 */ STRING_SELECTION_OPTION(time_backward_action, NULL, &msg[MSG_SUB_MENU_302], on_off_options, +// /* 03 */ STRING_SELECTION_OPTION(time_backward_action, NULL, &msg[MSG_SUB_MENU_302], on_off_options, // &game_config.backward, 2, NULL, ACTION_TYPE, 3), -// /* 04 */ NUMERIC_SELECTION_ACTION_OPTION(time_period_action, time_period_passive, &msg[MSG_SUB_MENU_32], +// /* 04 */ NUMERIC_SELECTION_ACTION_OPTION(time_period_action, time_period_passive, &msg[MSG_SUB_MENU_32], // &game_config.backward_time, 6, NULL, 4) }; @@ -2969,18 +2960,33 @@ u32 menu(u16 *screen) { /* 00 */ SUBMENU_OPTION(NULL, &msg[MSG_MAIN_MENU_OPTIONS], NULL, 0), - //CPU speed - /* 01 */ NUMERIC_SELECTION_OPTION(NULL, &msg[FMT_OPTIONS_CPU_FREQUENCY], &clock_speed_number, 6, NULL, 1), + //CPU speed (string: shows MHz) + /* 01 */ STRING_SELECTION_OPTION(NULL, NULL, &msg[FMT_OPTIONS_CPU_FREQUENCY], cpu_frequency_options, + &game_config.clock_speed_number, 6, NULL, PASSIVE_TYPE, 1), /* 02 */ STRING_SELECTION_OPTION(language_set, NULL, &msg[FMT_OPTIONS_LANGUAGE], language_options, &emu_config.language, sizeof(language_options) / sizeof(language_options[0]) /* number of possible languages */, NULL, ACTION_TYPE, 2), +#ifdef ENABLE_FREE_SPACE /* 03 */ STRING_SELECTION_OPTION(NULL, show_card_space, &msg[MSG_OPTIONS_CARD_CAPACITY], NULL, &desert, 2, NULL, PASSIVE_TYPE | HIDEN_TYPE, 3), +#endif - /* 04 */ ACTION_OPTION(load_default_setting, NULL, &msg[MSG_OPTIONS_RESET], NULL, 4), + /* 04 */ ACTION_OPTION(load_default_setting, NULL, &msg[MSG_OPTIONS_RESET], NULL, +#ifdef ENABLE_FREE_SPACE + 4 +#else + 3 +#endif + ), - /* 05 */ ACTION_OPTION(check_gbaemu_version, NULL, &msg[MSG_OPTIONS_VERSION], NULL, 5), + /* 05 */ ACTION_OPTION(check_gbaemu_version, NULL, &msg[MSG_OPTIONS_VERSION], NULL, +#ifdef ENABLE_FREE_SPACE + 5 +#else + 4 +#endif + ), }; MAKE_MENU(others, others_menu_init, NULL, NULL, NULL, 1, 1); @@ -2989,7 +2995,7 @@ u32 menu(u16 *screen) Load_game --------------------------------------------------------*/ MENU_TYPE latest_game_menu; - + MENU_OPTION_TYPE load_game_options[] = { /* 00 */ SUBMENU_OPTION(NULL, &msg[MSG_LOAD_GAME_MENU_TITLE], NULL, 0), @@ -3120,7 +3126,7 @@ u32 menu(u16 *screen) show_icon(down_screen_addr, &ICON_MSEL, 173, 131); } else { - show_icon(down_screen_addr, &ICON_NEXIT, 187, 75); + show_icon(down_screen_addr, &ICON_NEXIT, 187, 75); show_icon(down_screen_addr, &ICON_MNSEL, 173, 131); } draw_string_vcenter(down_screen_addr, 175, 131, 75, COLOR_WHITE, line_buffer); @@ -3315,7 +3321,7 @@ u32 menu(u16 *screen) { ext_pos= strrchr(emu_config.latest_file[k], '/'); if(ext_pos != NULL) - draw_hscroll_init(down_screen_addr, 26, 40 + k*27, 200, + draw_hscroll_init(down_screen_addr, 26, 40 + k*27, 200, COLOR_TRANS, COLOR_INACTIVE_ITEM, ext_pos+1); else break; @@ -3373,7 +3379,7 @@ u32 menu(u16 *screen) void latest_game_menu_end() { u32 k; - + for(k= 0; k < 5; k++) { if(emu_config.latest_file[k][0] != '\0') @@ -3393,12 +3399,12 @@ u32 menu(u16 *screen) { draw_hscroll_over(current_option_num-1); ext_pos= strrchr(emu_config.latest_file[current_option_num-1], '/'); - draw_hscroll_init(down_screen_addr, 26, 40 + (current_option_num-1)*27, 200, + draw_hscroll_init(down_screen_addr, 26, 40 + (current_option_num-1)*27, 200, COLOR_TRANS, COLOR_INACTIVE_ITEM, ext_pos+1); } current_option_num += 1; - if(current_option_num >= latest_game_menu.num_options) + if(current_option_num >= latest_game_menu.num_options) current_option_num = 0; current_option = current_menu->options + current_option_num; @@ -3407,7 +3413,7 @@ u32 menu(u16 *screen) { draw_hscroll_over(current_option_num-1); ext_pos= strrchr(emu_config.latest_file[current_option_num-1], '/'); - draw_hscroll_init(down_screen_addr, 26, 40 + (current_option_num-1)*27, 200, + draw_hscroll_init(down_screen_addr, 26, 40 + (current_option_num-1)*27, 200, COLOR_TRANS, COLOR_ACTIVE_ITEM, ext_pos+1); } @@ -3419,7 +3425,7 @@ u32 menu(u16 *screen) { draw_hscroll_over(current_option_num-1); ext_pos= strrchr(emu_config.latest_file[current_option_num-1], '/'); - draw_hscroll_init(down_screen_addr, 26, 40 + (current_option_num-1)*27, 200, + draw_hscroll_init(down_screen_addr, 26, 40 + (current_option_num-1)*27, 200, COLOR_TRANS, COLOR_INACTIVE_ITEM, ext_pos+1); } @@ -3432,7 +3438,7 @@ u32 menu(u16 *screen) { draw_hscroll_over(current_option_num-1); ext_pos= strrchr(emu_config.latest_file[current_option_num-1], '/'); - draw_hscroll_init(down_screen_addr, 26, 40 + (current_option_num-1)*27, 200, + draw_hscroll_init(down_screen_addr, 26, 40 + (current_option_num-1)*27, 200, COLOR_TRANS, COLOR_ACTIVE_ITEM, ext_pos+1); } @@ -3455,16 +3461,6 @@ u32 menu(u16 *screen) { char *ext_pos; - draw_message(down_screen_addr, bg_screenp, 28, 31, 227, 165, 0); - draw_string_vcenter(down_screen_addr, 36, 100, 190, COLOR_MSSG, msg[MSG_PROGRESS_LOADING_GAME]); - ds2_flipScreen(DOWN_SCREEN, DOWN_SCREEN_UPDATE_METHOD); - - if(gamepak_name[0] != 0) - { - S9xAutoSaveSRAM (); - save_game_config_file(); - } - if(bg_screenp != NULL) { bg_screenp_color = COLOR16(43, 11, 11); } @@ -3478,42 +3474,19 @@ u32 menu(u16 *screen) ext_pos = emu_config.latest_file[current_option_num -1]; - ds2_setCPUclocklevel(13); - int load_result = load_gamepak(ext_pos); - ds2_setCPUclocklevel(0); - - if(load_result == -1) { - first_load = 1; - return; - } - - strcpy(g_default_rom_dir, ext_pos); - ext_pos = strrchr(g_default_rom_dir, '/'); - *ext_pos= '\0'; - strcpy(gamepak_name, ext_pos+1); - - - load_game_config_file(); -// time_period_action(); - - reorder_latest_file(); - get_savestate_filelist(); - game_fast_forward= 0; + LoadGameAndItsData(ext_pos); get_newest_savestate(tmp_filename); if(tmp_filename[0] != '\0') { load_state(tmp_filename); } - - return_value = 1; - repeat = 0; } void game_fastforward() { } - + void reload_cheats_page() @@ -3527,11 +3500,13 @@ u32 menu(u16 *screen) void others_menu_init() { +#ifdef ENABLE_FREE_SPACE unsigned int total, used; //get card space info freespace = 0; fat_getDiskSpaceInfo("fat:", &total, &used, &freespace); +#endif } void choose_menu(MENU_TYPE *new_menu) @@ -3542,23 +3517,28 @@ u32 menu(u16 *screen) if(NULL != current_menu) { if(current_menu->end_function) current_menu->end_function(); + SaveConfigsIfNeeded(); } current_menu = new_menu; current_option_num= current_menu -> focus_option; current_option = new_menu->options + current_option_num; + PreserveConfigs(); if(current_menu->init_function) current_menu->init_function(); } //----------------------------------------------------------------------------// // Menu Start - ds2_setCPUclocklevel(0); - mdelay(100); // to prevent ds2_setBacklight() from crashing - ds2_setBacklight(3); - - - wait_Allkey_release(0); + LowFrequencyCPU(); + if (!FirstInvocation) + { // assume that the backlight is already at 3 when the emulator starts + mdelay(100); // to prevent ds2_setBacklight() from crashing + ds2_setBacklight(3); + // also allow the user to press A for New Game right away + wait_Allkey_release(0); + } + bg_screenp= (u16*)malloc(256*192*2); repeat = 1; @@ -3566,7 +3546,8 @@ u32 menu(u16 *screen) if(gamepak_name[0] == 0) { first_load = 1; - if(CheckLoad_Arg()) + //try auto loading games passed through argv first + if(strlen(argv[1]) > 0 && LoadGameAndItsData(argv[1])) repeat = 0; else { @@ -3589,7 +3570,7 @@ u32 menu(u16 *screen) choose_menu(&main_menu); // Menu loop - + while(repeat) { display_option = current_menu->options; @@ -3638,7 +3619,7 @@ u32 menu(u16 *screen) focus_option = line_num; } current_menu -> focus_option = focus_option; - + i = focus_option - screen_focus; display_option += i +1; @@ -3684,7 +3665,7 @@ u32 menu(u16 *screen) color= COLOR_ACTIVE_ITEM; else color= COLOR_INACTIVE_ITEM; - + PRINT_STRING_BG(down_screen_addr, line_buffer, color, COLOR_TRANS, 23, 40 + i*27); } } @@ -3697,6 +3678,7 @@ u32 menu(u16 *screen) { case CURSOR_TOUCH: ds2_getrawInput(&inputdata); + wait_Allkey_release(0); /* Back button at the top of every menu but the main one */ if(current_menu != &main_menu && inputdata.x > 231 && inputdata.y <= 25) { @@ -3714,7 +3696,7 @@ u32 menu(u16 *screen) current_option_num = (inputdata.y / 80) * 3 + (inputdata.x / 86); current_option = current_menu->options + current_option_num; - + if(current_option -> option_type & HIDEN_TYPE) break; else if(current_option->option_type & ACTION_TYPE) @@ -3723,11 +3705,10 @@ u32 menu(u16 *screen) choose_menu(current_option->sub_menu); } /* This is the majority case, covering all menus except save states, screen shots, and game loading */ - else if(current_menu != (main_menu.options + 1)->sub_menu + else if(current_menu != (main_menu.options + 1)->sub_menu && current_menu != ((main_menu.options +1)->sub_menu->options + 3)->sub_menu - && current_menu != (main_menu.options +3)->sub_menu + && current_menu != (main_menu.options +3)->sub_menu && current_menu != ((main_menu.options +3)->sub_menu->options + 1)->sub_menu - && current_menu != ((main_menu.options +3)->sub_menu->options + 2)->sub_menu && current_menu != (main_menu.options +6)->sub_menu && current_menu != ((main_menu.options +6)->sub_menu->options + 2)->sub_menu) { @@ -3794,9 +3775,9 @@ u32 menu(u16 *screen) next_option_num = 3; else break; - + struct _MENU_OPTION_TYPE *next_option = current_menu->options + next_option_num; - + if(next_option_num == 1 /* write */ || next_option_num == 2 /* read */) { u32 current_option_val = *(next_option->current_option); @@ -3841,7 +3822,7 @@ u32 menu(u16 *screen) } break; } - + gui_action = CURSOR_SELECT; if(next_option -> option_type & HIDEN_TYPE) break; @@ -3868,9 +3849,9 @@ u32 menu(u16 *screen) next_option_num = 2; else break; - + struct _MENU_OPTION_TYPE *next_option = current_menu->options + next_option_num; - + if(next_option_num == 2) { u32 current_option_val = *(next_option->current_option); @@ -3908,7 +3889,7 @@ u32 menu(u16 *screen) } break; } - + gui_action = CURSOR_SELECT; if(next_option -> option_type & HIDEN_TYPE) break; @@ -4032,16 +4013,19 @@ u32 menu(u16 *screen) break; case CURSOR_EXIT: + wait_Allkey_release(0); break; case CURSOR_SELECT: + wait_Allkey_release(0); if(current_option->option_type & ACTION_TYPE) current_option->action_function(); else if(current_option->option_type & SUBMENU_TYPE) choose_menu(current_option->sub_menu); break; - case CURSOR_BACK: + case CURSOR_BACK: + wait_Allkey_release(0); if(current_menu != &main_menu) choose_menu(current_menu->options->sub_menu); else @@ -4057,20 +4041,11 @@ u32 menu(u16 *screen) if (current_menu && current_menu->end_function) current_menu->end_function(); + SaveConfigsIfNeeded(); destroy_dynamic_cheats(); if(bg_screenp != NULL) free((void*)bg_screenp); - - if(gamepak_name[0] != 0) - { - game_config.clock_speed_number = clock_speed_number; - reorder_latest_file(); - S9xAutoSaveSRAM (); - save_game_config_file(); - } - save_emu_config_file(); - ds2_clearScreen(DOWN_SCREEN, 0); ds2_flipScreen(DOWN_SCREEN, DOWN_SCREEN_UPDATE_METHOD); copy_screen(up_screen_addr, (void*) screen, 0, 0, 256, 192); @@ -4080,7 +4055,7 @@ u32 menu(u16 *screen) mdelay(100); // to prevent ds2_setBacklight() from crashing ds2_setBacklight(2); - set_cpu_clock(clock_speed_number); + GameFrequencyCPU(); return return_value; } @@ -4132,6 +4107,10 @@ int load_language_msg(char *filename, u32 language) strcpy(start, "STARTFRENCH"); strcpy(end, "ENDFRENCH"); break; + case GERMAN: + strcpy(start, "STARTGERMAN"); + strcpy(end, "ENDGERMAN"); + break; } u32 cmplen = strlen(start); @@ -4175,7 +4154,61 @@ int load_language_msg(char *filename, u32 language) break; len= strlen(pt); - memcpy(dst, pt, len); + // memcpy(dst, pt, len); + + // Replace key definitions (*letter) with Pictochat icons + // while copying. + unsigned int curChar; + for (curChar = 0; curChar < len; curChar++) + { + if (pt[curChar] == '*') + { + switch (pt[curChar + 1]) + { + case 'A': + memcpy(&dst[curChar], HOTKEY_A_DISPLAY, 2); + curChar++; + break; + case 'B': + memcpy(&dst[curChar], HOTKEY_B_DISPLAY, 2); + curChar++; + break; + case 'X': + memcpy(&dst[curChar], HOTKEY_X_DISPLAY, 2); + curChar++; + break; + case 'Y': + memcpy(&dst[curChar], HOTKEY_Y_DISPLAY, 2); + curChar++; + break; + case 'L': + memcpy(&dst[curChar], HOTKEY_L_DISPLAY, 2); + curChar++; + break; + case 'R': + memcpy(&dst[curChar], HOTKEY_R_DISPLAY, 2); + curChar++; + break; + case 'S': + memcpy(&dst[curChar], HOTKEY_START_DISPLAY, 2); + curChar++; + break; + case 's': + memcpy(&dst[curChar], HOTKEY_SELECT_DISPLAY, 2); + curChar++; + break; + case '\0': + dst[curChar] = pt[curChar]; + break; + default: + memcpy(&dst[curChar], &pt[curChar], 2); + curChar++; + break; + } + } + else + dst[curChar] = pt[curChar]; + } dst += len; //at a line return, when "\n" paded, this message not end @@ -4198,7 +4231,7 @@ int load_language_msg(char *filename, u32 language) else//a message end { if(*(dst-2) == 0x0D) - dst -= 1; + dst -= 1; *(dst-1) = '\0'; msg[++loop] = dst; } @@ -4235,9 +4268,9 @@ u32 load_font() void init_game_config(void) { game_config.clock_speed_number = 5; // 396 MHz by default - clock_speed_number = 5; game_config.graphic = 3; // By default, have a good-looking aspect ratio game_config.frameskip_value = 0; // Automatic frame skipping + game_config.SoundSync = 0; // Prefer fluid images by default game_config.backward = 0; //time backward disable game_config.backward_time = 2; //time backward granularity 1s @@ -4290,8 +4323,8 @@ void load_game_config_file(void) { fread(&game_config, 1, sizeof(GAME_CONFIG), fp); - clock_speed_number = game_config.clock_speed_number; - Settings.SkipFrames = (game_config.frameskip_value == 0 ? AUTO_FRAMERATE : game_config.frameskip_value - 1 /* 1 -> 0 and so on */); + game_set_frameskip(); + game_set_fluidity(); } fclose(fp); @@ -4322,6 +4355,10 @@ int load_emu_config_file(void) fclose(fp); return 0; } + else + { + fclose(fp); + } } //have no confiure file, set default @@ -4342,7 +4379,7 @@ int save_game_config_file(void) sprintf(game_config_filename, "%s/%s", DEFAULT_CFG_DIR, gamepak_name); pt = strrchr(game_config_filename, '.'); - if(NULL == pt) + if(NULL == pt) return -1; *pt = '\0'; @@ -4418,7 +4455,7 @@ void reorder_latest_file(void) else break; } - + strcpy(emu_config.latest_file[i-1], full_file); } return ; @@ -4584,7 +4621,7 @@ void get_newest_savestate(char *name_buffer) get_savestate_filename(latest_save, name_buffer); } -static void get_timestamp_string(char *buffer, u16 msg_id, u16 year, u16 mon, +static void get_timestamp_string(char *buffer, u16 msg_id, u16 year, u16 mon, u16 day, u16 wday, u16 hour, u16 min, u16 sec, u32 msec) { char *weekday_strings[] = @@ -4592,7 +4629,7 @@ static void get_timestamp_string(char *buffer, u16 msg_id, u16 year, u16 mon, "SUN", "MON", "TUE", "WED", "TUR", "FRI", "SAT" }; - sprintf(buffer, "%s %02d/%02d/%04d %02d:%02d:%02d", weekday_strings[wday], + sprintf(buffer, "%s %02d/%02d/%04d %02d:%02d:%02d", weekday_strings[wday], day, mon, year, hour, min, sec); } @@ -4617,7 +4654,7 @@ static u32 save_ss_bmp(u16 *image) change_ext(gamepak_name, ss_filename, "_"); ds2_getTime(¤t_time); - sprintf(save_ss_path, "%s/%s%02d%02d%02d%02d%02d.bmp", DEFAULT_SS_DIR, ss_filename, + sprintf(save_ss_path, "%s/%s%02d%02d%02d%02d%02d.bmp", DEFAULT_SS_DIR, ss_filename, current_time.month, current_time.day, current_time.hours, current_time.minutes, current_time.seconds); for(y = 0; y < 192; y++) @@ -4652,7 +4689,7 @@ void quit(void) __asm__ __volatile__("or %0, $0, $ra" : "=r" (reg_ra) :); - + dbg_printf("return address= %08x\n", reg_ra); */ @@ -4678,11 +4715,44 @@ u32 file_length(FILE* file) /* * GUI Initialize */ +static bool Get_Args(char *file, char **filebuf){ + FILE* dat = fat_fopen(file, "rb"); + if(dat){ + int i = 0; + while(!fat_feof (dat)){ + fat_fgets(filebuf[i], 512, dat); + int len = strlen(filebuf[i]); + if(filebuf[i][len - 1] == '\n') + filebuf[i][len - 1] = '\0'; + i++; + } + + fat_fclose(dat); + fat_remove(file); + return i; + } + return 0; +} + +int CheckLoad_Arg(){ + argv[0][0] = '\0'; // Initialise the first byte to be a NULL in case + argv[1][0] = '\0'; // there are no arguments to avoid uninit. memory + char *argarray[2]; + argarray[0] = argv[0]; + argarray[1] = argv[1]; + + if(!Get_Args("/plgargs.dat", argarray)) + return 0; + + fat_remove("plgargs.dat"); + return 1; +} + void gui_init(u32 lang_id) { int flag; - ds2_setCPUclocklevel(13); // Crank it up. When the menu starts, -> 0. + HighFrequencyCPU(); // Crank it up. When the menu starts, -> 0. // Start with no saved state existing, as no game is loaded yet. int i; @@ -4695,7 +4765,17 @@ void gui_init(u32 lang_id) //Find the "CATSFC" system directory DIR *current_dir; - strcpy(main_path, "fat:/CATSFC"); + if(CheckLoad_Arg()){ + //copy new folder location + strcpy(main_path, "fat:"); + strcat(main_path, argv[0]); + //strip off the binary name + char *endStr = strrchr(main_path, '/'); + *endStr = '\0'; + } + else + strcpy(main_path, "fat:/CATSFC"); + current_dir = opendir(main_path); if(current_dir) closedir(current_dir); diff --git a/source/nds/gui.h b/source/nds/gui.h index 87c14e4..290a927 100644 --- a/source/nds/gui.h +++ b/source/nds/gui.h @@ -59,7 +59,20 @@ struct _GAME_CONFIG u32 HotkeyReturnToMenu; u32 HotkeyTemporaryFastForward; u32 HotkeyToggleSound; - u32 Reserved2[45]; + u32 SoundSync; + /* + * PreviouslyUsed_20130206_1 was for a second meaning of + * frameskip_value that is now dropped. + * THIS VALUE IS NOT GUARANTEED TO BE RESERVED AND SET TO 0. + */ + u32 PreviouslyUsed_20130206_1; + /* + * PreviouslyUsed_20130206_2 was for a second meaning of + * clock_speed_number that is now dropped. + * THIS VALUE IS NOT GUARANTEED TO BE RESERVED AND SET TO 0. + */ + u32 PreviouslyUsed_20130206_2; + u32 Reserved2[42]; }; typedef enum @@ -124,10 +137,13 @@ extern GAME_CONFIG game_config; /****************************************************************************** ******************************************************************************/ extern void gui_init(u32 lang_id); -extern u32 menu(u16 *original_screen); +extern u32 menu(u16 *original_screen, bool8 FirstInvocation); extern void game_disableAudio(); extern void game_set_frameskip(); -extern void set_cpu_clock(u32 num); +extern void game_set_fluidity(); +extern void LowFrequencyCPU(); +extern void HighFrequencyCPU(); +extern void GameFrequencyCPU(); extern int load_language_msg(char *filename, u32 language); #ifdef __cplusplus diff --git a/source/nds/message.h b/source/nds/message.h index 0aff8d9..538bc3b 100644 --- a/source/nds/message.h +++ b/source/nds/message.h @@ -31,6 +31,9 @@ enum MSG MSG_MAIN_MENU_TOOLS, MSG_MAIN_MENU_OPTIONS, MSG_MAIN_MENU_EXIT, + FMT_VIDEO_AUDIO_FLUIDITY_PREFERENCE, + MSG_VIDEO_AUDIO_FLUIDITY_PREFER_VIDEO, + MSG_VIDEO_AUDIO_FLUIDITY_PREFER_AUDIO, FMT_VIDEO_ASPECT_RATIO, FMT_VIDEO_FAST_FORWARD, FMT_VIDEO_FRAME_SKIPPING, @@ -41,21 +44,27 @@ enum MSG FMT_CHEAT_PAGE, MSG_CHEAT_LOAD_FROM_FILE, MSG_TOOLS_SCREENSHOT_GENERAL, - MSG_TOOLS_GLOBAL_HOTKEY_GENERAL, // currently unused - MSG_TOOLS_GAME_HOTKEY_GENERAL, // currently unused + MSG_TOOLS_GLOBAL_HOTKEY_GENERAL, + MSG_TOOLS_GAME_HOTKEY_GENERAL, FMT_OPTIONS_LANGUAGE, FMT_OPTIONS_CPU_FREQUENCY, - MSG_OPTIONS_CARD_CAPACITY, + MSG_OPTIONS_CPU_FREQUENCY_0, + MSG_OPTIONS_CPU_FREQUENCY_1, + MSG_OPTIONS_CPU_FREQUENCY_2, + MSG_OPTIONS_CPU_FREQUENCY_3, + MSG_OPTIONS_CPU_FREQUENCY_4, + MSG_OPTIONS_CPU_FREQUENCY_5, + MSG_OPTIONS_CARD_CAPACITY /* unused if !defined(ENABLE_FREE_SPACE) */, MSG_OPTIONS_RESET, MSG_OPTIONS_VERSION, MSG_SCREENSHOT_CREATE, MSG_SCREENSHOT_BROWSE, - MSG_HOTKEY_MAIN_MENU, // currently unused - MSG_HOTKEY_TEMPORARY_FAST_FORWARD, // currently unused - MSG_HOTKEY_SOUND_TOGGLE, // currently unused - MSG_PROGRESS_HOTKEY_WAITING_FOR_KEYS, // currently unused - MSG_HOTKEY_DELETE_WITH_A, // currently unused - MSG_HOTKEY_CANCEL_WITH_B, // currently unused + MSG_HOTKEY_MAIN_MENU, + MSG_HOTKEY_TEMPORARY_FAST_FORWARD, + MSG_HOTKEY_SOUND_TOGGLE, + MSG_PROGRESS_HOTKEY_WAITING_FOR_KEYS, + MSG_HOTKEY_DELETE_WITH_A, + MSG_HOTKEY_CANCEL_WITH_B, MSG_LOAD_GAME_RECENTLY_PLAYED, MSG_LOAD_GAME_FROM_CARD, MSG_LOAD_GAME_MENU_TITLE, @@ -112,9 +121,6 @@ enum MSG MSG_PROGRESS_SCREENSHOT_CREATION_SUCCEEDED, MSG_PROGRESS_SCREENSHOT_CREATION_FAILED, - MSG_CHANGE_LANGUAGE, - MSG_CHANGE_LANGUAGE_WAITING, - MSG_NO_SLIDE, MSG_PLAYING_SLIDE, MSG_PAUSE_SLIDE, @@ -139,13 +145,14 @@ enum MSG enum LANGUAGE { ENGLISH, CHINESE_SIMPLIFIED, - FRENCH + FRENCH, + GERMAN }; -extern char* lang[3]; // Allocated in gui.c, needs to match the languages ^ +extern char* lang[4]; // Allocated in gui.c, needs to match the languages ^ char *msg[MSG_END+1]; -char msg_data[16 * 1024]; +char msg_data[32 * 1024]; #endif //__MESSAGE_H__ |