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