diff --git a/desmume/README.MAC b/desmume/README.MAC index 31667acd4..da5b945c6 100644 --- a/desmume/README.MAC +++ b/desmume/README.MAC @@ -2,7 +2,7 @@ _________________________________________ Copyright (C) 2006 yopyop Copyright (C) 2006-2013 DeSmuME team - Last Updated: November 27, 2013 + Last Updated: December 17, 2013 Contents: 1) System Requirements ..................................................... 15 @@ -248,7 +248,7 @@ possible. The better your descriptions are, the faster we can test and fix bugs. For example, if you observed a bug in the game Golden Sun: Dark Dawn, then the bug report could look something like this: - App Version: v0.9.10 + App Version: v0.9.10b Operating System: OS X v10.8.3 (12D78) Mac Model Identifier: iMac11,2 ROM Name: GOLDENSUN_DD diff --git a/desmume/src/cocoa/Info (Debug).plist b/desmume/src/cocoa/Info (Debug).plist index d697ab4f0..fd7451fe5 100644 --- a/desmume/src/cocoa/Info (Debug).plist +++ b/desmume/src/cocoa/Info (Debug).plist @@ -240,7 +240,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - v0.9.10 (Debug) + v0.9.10b (Debug) CFBundleSignature DSmM CFBundleVersion diff --git a/desmume/src/cocoa/Info.plist b/desmume/src/cocoa/Info.plist index 241776900..338b6b6fc 100644 --- a/desmume/src/cocoa/Info.plist +++ b/desmume/src/cocoa/Info.plist @@ -240,7 +240,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - v0.9.10 + v0.9.10b CFBundleSignature DSmM CFBundleVersion diff --git a/desmume/src/cocoa/cocoa_core.h b/desmume/src/cocoa/cocoa_core.h index d5b5c7c48..8d3151e1b 100644 --- a/desmume/src/cocoa/cocoa_core.h +++ b/desmume/src/cocoa/cocoa_core.h @@ -35,7 +35,7 @@ typedef struct int state; bool isFrameSkipEnabled; size_t frameCount; - unsigned int framesToSkip; + int framesToSkip; uint64_t timeBudgetMachAbsTime; bool exitThread; pthread_mutex_t mutexCoreExecute; @@ -145,4 +145,5 @@ typedef struct @end static void* RunCoreThread(void *arg); -static void CoreFrameSkip(uint64_t timeBudgetMachAbsoluteTime, uint64_t frameStartMachAbsoluteTime, unsigned int *outFramesToSkip); +static int CalculateFrameSkip(uint64_t timeBudgetMachAbsTime, uint64_t frameStartMachAbsTime); +uint64_t GetFrameAbsoluteTime(const double frameTimeScalar); diff --git a/desmume/src/cocoa/cocoa_core.mm b/desmume/src/cocoa/cocoa_core.mm index c1b555ee6..9c330adce 100644 --- a/desmume/src/cocoa/cocoa_core.mm +++ b/desmume/src/cocoa/cocoa_core.mm @@ -620,16 +620,9 @@ static BOOL isCoreStarted = NO; { if (self.isSpeedLimitEnabled) { - CGFloat theSpeed = self.speedScalar; - if(theSpeed <= SPEED_SCALAR_MIN) - { - theSpeed = SPEED_SCALAR_MIN; - } - + const CGFloat theSpeed = ([self speedScalar] > SPEED_SCALAR_MIN) ? [self speedScalar] : SPEED_SCALAR_MIN; pthread_mutex_lock(&threadParam.mutexThreadExecute); - uint64_t timeBudgetNanoseconds = (uint64_t)(DS_SECONDS_PER_FRAME * 1000000000.0 / theSpeed); - AbsoluteTime timeBudgetAbsTime = NanosecondsToAbsolute(*(Nanoseconds *)&timeBudgetNanoseconds); - threadParam.timeBudgetMachAbsTime = *(uint64_t *)&timeBudgetAbsTime; + threadParam.timeBudgetMachAbsTime = GetFrameAbsoluteTime(1.0/theSpeed); pthread_mutex_unlock(&threadParam.mutexThreadExecute); } else @@ -893,7 +886,15 @@ static void* RunCoreThread(void *arg) // we owe on timeBudget. if (param->isFrameSkipEnabled) { - CoreFrameSkip(timeBudget, startTime, ¶m->framesToSkip); + if (param->framesToSkip > 0) + { + NDS_SkipNextFrame(); + param->framesToSkip--; + } + else + { + param->framesToSkip = CalculateFrameSkip(timeBudget, startTime); + } } pthread_mutex_unlock(¶m->mutexThreadExecute); @@ -906,52 +907,76 @@ static void* RunCoreThread(void *arg) return nil; } -static void CoreFrameSkip(uint64_t timeBudgetMachAbsTime, uint64_t frameStartMachAbsTime, unsigned int *outFramesToSkip) +static int CalculateFrameSkip(uint64_t timeBudgetMachAbsTime, uint64_t frameStartMachAbsTime) { - if (*outFramesToSkip > 0) + static const double skipCurve[10] = {0.60, 0.58, 0.55, 0.51, 0.46, 0.40, 0.30, 0.20, 0.10, 0.00}; + static const double unskipCurve[10] = {0.75, 0.70, 0.65, 0.60, 0.50, 0.40, 0.30, 0.20, 0.10, 0.00}; + static size_t skipStep = 0; + static size_t unskipStep = 0; + static int lastSetFrameSkip = 0; + + // Calculate the time remaining. + const uint64_t elapsed = mach_absolute_time() - frameStartMachAbsTime; + int framesToSkip = 0; + + if (elapsed > timeBudgetMachAbsTime) { - NDS_SkipNextFrame(); - (*outFramesToSkip)--; - } - else - { - // Calculate the time remaining. - uint64_t elapsed = mach_absolute_time() - frameStartMachAbsTime; - - if (elapsed > timeBudgetMachAbsTime) + if (timeBudgetMachAbsTime > 0) { - static unsigned int lastSetFrameSkip = 0; - unsigned int framesToSkip = 0; + framesToSkip = (int)( (((double)(elapsed - timeBudgetMachAbsTime) * FRAME_SKIP_AGGRESSIVENESS) / (double)timeBudgetMachAbsTime) + FRAME_SKIP_BIAS ); - if (timeBudgetMachAbsTime > 0) + if (framesToSkip > lastSetFrameSkip) { - framesToSkip = (unsigned int)( (((double)(elapsed - timeBudgetMachAbsTime) * FRAME_SKIP_AGGRESSIVENESS) / (double)timeBudgetMachAbsTime) + FRAME_SKIP_BIAS ); - if (framesToSkip < lastSetFrameSkip) + framesToSkip -= (int)((double)(framesToSkip - lastSetFrameSkip) * skipCurve[skipStep]); + if (skipStep < 9) { - framesToSkip += (unsigned int)((double)(lastSetFrameSkip - framesToSkip) * FRAME_SKIP_SMOOTHNESS); + skipStep++; } - - lastSetFrameSkip = framesToSkip; } else { - framesToSkip = (unsigned int)( (((double)(elapsed - timeBudgetMachAbsTime) * FRAME_SKIP_AGGRESSIVENESS * 100.0) / DS_SECONDS_PER_FRAME) + FRAME_SKIP_BIAS ); - // Don't need to save lastSetFrameSkip here since this code path assumes that - // the frame limiter is disabled. + framesToSkip += (int)((double)(lastSetFrameSkip - framesToSkip) * skipCurve[skipStep]); + if (skipStep > 0) + { + skipStep--; + } } - - // Bound the frame skip. - if (framesToSkip > (unsigned int)MAX_FRAME_SKIP) - { - framesToSkip = (unsigned int)MAX_FRAME_SKIP; - lastSetFrameSkip = framesToSkip; - } - - *outFramesToSkip = framesToSkip; } else { - *outFramesToSkip = 0; + static const double frameRate100x = (double)FRAME_SKIP_AGGRESSIVENESS / (double)GetFrameAbsoluteTime(1.0/100.0); + framesToSkip = (int)((double)elapsed * frameRate100x); } + + unskipStep = 0; } + else + { + framesToSkip = (int)((double)lastSetFrameSkip * unskipCurve[unskipStep]); + if (unskipStep < 9) + { + unskipStep++; + } + + skipStep = 0; + } + + // Bound the frame skip. + static const int kMaxFrameSkip = (int)MAX_FRAME_SKIP; + if (framesToSkip > kMaxFrameSkip) + { + framesToSkip = kMaxFrameSkip; + } + + lastSetFrameSkip = framesToSkip; + + return framesToSkip; +} + +uint64_t GetFrameAbsoluteTime(const double frameTimeScalar) +{ + const uint64_t frameTimeNanoseconds = (uint64_t)(DS_SECONDS_PER_FRAME * 1000000000.0 * frameTimeScalar); + const AbsoluteTime frameTimeAbsTime = NanosecondsToAbsolute(*(Nanoseconds *)&frameTimeNanoseconds); + + return *(uint64_t *)&frameTimeAbsTime; } diff --git a/desmume/src/cocoa/cocoa_globals.h b/desmume/src/cocoa/cocoa_globals.h index 5b2fca61d..e2591504e 100644 --- a/desmume/src/cocoa/cocoa_globals.h +++ b/desmume/src/cocoa/cocoa_globals.h @@ -194,12 +194,9 @@ #define DS_FRAMES_PER_SECOND 59.8261 // Number of DS frames per second. #define DS_SECONDS_PER_FRAME (1.0 / DS_FRAMES_PER_SECOND) // The length of time in seconds that, ideally, a frame should be processed within. -#define FRAME_SKIP_AGGRESSIVENESS 10.0 // Must be a value between 0.0 (inclusive) and positive infinity. +#define FRAME_SKIP_AGGRESSIVENESS 9.0 // Must be a value between 0.0 (inclusive) and positive infinity. // This value acts as a scalar multiple of the frame skip. -#define FRAME_SKIP_SMOOTHNESS 0.90 // Must be a value between 0.00 (inclusive) and 1.00 (exclusive). - // Values closer to 0.00 give better video smoothness, but makes the emulation timing more "jumpy." - // Values closer to 1.00 makes the emulation timing more accurate, but makes the video look more "choppy." -#define FRAME_SKIP_BIAS 0.5 // May be any real number. This value acts as a vector addition to the frame skip. +#define FRAME_SKIP_BIAS 0.1 // May be any real number. This value acts as a vector addition to the frame skip. #define MAX_FRAME_SKIP (DS_FRAMES_PER_SECOND / 3.0) #define SPU_SAMPLE_RATE 44100.0 // Samples per second