I prefer crossplatform solutions whenver possible. Both of those are Windows-specific. Most crossplatform libs worth using offer some sort of "get tick" funciton.
If sticking to just Windows, I always just used GetTickCount(). You really don't need more than millisecond granularity, IMO.
I remember hearing that timing problems on laptops are common, though I never actually tested any of my programs on a laptop.
From what what you're describing it just sounds like your framerate code is just messed up. Here's generally what I do:
The idea is, you keep a var which counts the passing milliseconds. You multiply these milliseconds by the framerate (ie: 60 on NTSC, 50 on PAL -- yes I know it's not exactly 60 -- if you want to do 60.1 you can). When that var reaches 1000, one frame's worth of time has passed, so you do a frame, and subtract 1000. This also has a benefit of seeing how many frames behind you are. IE if the counter is >5000 you know you're 5 frames behind.
Since CPU attention may vary due to sleep times, processor availability and other factors, you NEED wiggle room. If you start skipping frames to catch up when you're only 2 frames behind, the display will get incredibly jerky because you'll end up skipping to catching up, then sleeping too long, then skipping to catch up, then sleeping too long, etc.
Because of this, you want to give yourself a window where you say "don't catch up until I'm X frames behind). You can make this an option in the emulator if you want the user to be able to configure it. I find that 5 frames is pretty good.
It basically works like this:
Code:
DWORD ms_passed; // number of milliseconds passed since last iteration
DWORD frametimer; // timer to count when to do the next frame
DWORD lasttime; // record of time of last iteration
DWORD FPS; // 60 (NTSC) or 50 (PAL)
while(emulator_is_running)
{
// process user input
PumpMessages_ProcessInput_etc_etc();
// see how many milliseconds have passed since the last iteration
ms_passed = GetTickCount() - lasttime;
// update 'lasttime' tracker to mark current time
lasttime += ms_passed;
// accumulate time difference in our frametimer
frametimer += ms_passed * FPS;
// if frametimer is < 1000, we're ahead of schedule
if(frametimer < 1000)
{
Sleep(1);
continue;
}
// otherwise see if we're falling WAY behind
int frames_skipped = 0;
while(frametimer > 1000 * FRAME_SKIP_THRESHHOLD)
{
if(frames_skipped > MAX_FRAMES_TO_SKIP)
{
ResyncFrameTimer(); // give up on trying to catch up, just resync
continue; // --- this continue is pseudo-code, the intent here is to
// jump back to the while(emu_is_running) outer loop,
// not this inner loop. Whoops. You get the idea.
}
SkipAFrame(); // emulate a frame, but don't draw it
frametimer -= 1000;
++frames_skipped;
}
// now that too-slow and too-fast conditions are covered
// just do a normal frame
DoAFrame();
frametimer -= 1000;
}
//----------------------------------------------
// The ResyncFrameTimer() function should be called when the user has
// exited the emulation loop for a long peroid of time. Like if they
// entered a menu, or if a new ROM was loaded, etc.
void ResyncFrameTimer()
{
lasttime = GetTickCount();
frametimer = 0;
}
Of course ideally you'd want to sync to sound. That can be done the same way, but instead of:
Code:
timer += ms_passed * FPS;
if(timer < 1000) {...}
You do:
Code:
timer += samples_passed * FPS;
if(timer < sample_rate) {...}
You can find the number of sampled passed by polling your audio's CanWrite style function. Of course this doesn't work very well if audio is output in very large chunks (*cough*SDL*cough*allegro*cough*). For those such cases, I made a wrapper for audio which uses a millisecond timer to "simulate" audio being played back at a smoother rate.
But that's another topic.
EDIT -- made note about continue goof