Commits

spencercw committed e2c8b20

#29 Improve the accuracy of the timing of the idle loop.

The audio generated at pretty much exactly 48kHz now, rather than a couple of hundred Hz below as before; this massively reduces the audio skipping.

  • Participants
  • Parent commits 7075bcc

Comments (0)

Files changed (4)

gb_emulator/include/gb_emulator/constants.hpp

 const uint8_t  HUC1_RAM_BAT             = 0xff;
 
 /* Interesting durations */
-const unsigned FRAME_DURATION           = 16742706;  /* Frame duration in nanoseconds */
 const unsigned CPU_CLOCK                = 4194304;   /* CPU clock frequency */
+const unsigned CYCLES_PER_FRAME         = 70224;     /* Number of clock cycles per frame */
+const double   FRAME_DURATION           = static_cast<double>(CYCLES_PER_FRAME) / CPU_CLOCK;  /* Frame duration in seconds */
 const unsigned SAMPLE_RATE              = 48000;     /* Audio sample rate */
-                                                     /* Number of CPU cycles per audio sample */
-const double SAMPLE_CYCLES              = static_cast<double>(CPU_CLOCK) / 4 / SAMPLE_RATE; 
+const double   SAMPLE_CYCLES            = CPU_CLOCK / 4. / SAMPLE_RATE;  /* Number of CPU cycles per audio sample */
 
 /* Memory map */
 const uint16_t BIOS1_END                = 0x0100;

gb_emulator/include/gb_emulator/gb.hpp

 	std::basic_string<uint8_t> rom_;
 
 #ifdef _WIN32
-	LARGE_INTEGER timeLast_, frameDuration_;
+	LARGE_INTEGER timeFrequency_, timeLast_;
 #else
 	timespec timeLast_, frameDuration_;
 #endif
+	double excessFrames_;
+
 	GbCpu cpu_;
 	GbTimers timers_;
 	GbInput input_;

gb_emulator/src/gb.cpp

 static const unsigned RAM_SIZES[] = { 0, 2048, 8192, 32768 };
 
 Gb::Gb():
+	excessFrames_(0),
 	cpu_(*this),
 	timers_(*this),
 	input_(*this),
 void Gb::run()
 {
 #ifdef _WIN32
-	// Get the number of counts per frame
+	// Get the clock frequency
+	if (!QueryPerformanceFrequency(&timeFrequency_) || !timeFrequency_.QuadPart)
 	{
-		LARGE_INTEGER frequency;
-		if (!QueryPerformanceFrequency(&frequency) || !frequency.QuadPart)
-		{
-			throw runtime_error("high performance timer not available");
-		}
-		frameDuration_.QuadPart = static_cast<LONGLONG>(
-			round(FRAME_DURATION / 1000000000. * frequency.QuadPart));
+		throw runtime_error("high performance timer not available");
 	}
 
 	// Get the time
 
 void Gb::spin()
 {
+	// Calculate the time to spin for
+	double realDuration = FRAME_DURATION * timeFrequency_.QuadPart + excessFrames_;
+	LARGE_INTEGER frameDuration;
+	frameDuration.QuadPart = static_cast<LONGLONG>(realDuration);
+
 	// Spin until the appropriate time has elapsed
 #ifdef _WIN32
 	LARGE_INTEGER timeNow, timeTmp;
 		}
 		timeTmp = timeNow;
 		// Subtract 1 frames' worth of counts
-		timeNow.QuadPart -= frameDuration_.QuadPart;
+		timeNow.QuadPart -= frameDuration.QuadPart;
 	}
 	while (timeNow.QuadPart <= timeLast_.QuadPart);
+	excessFrames_ = realDuration - (timeTmp.QuadPart - timeLast_.QuadPart);
 	timeLast_ = timeTmp;
 #else
 	timespec timeNow, result;

gb_emulator/src/gb_sound.cpp

 using std::vector;
 
 static const double PI = 3.14159265358979323846264338327950288;
-static const unsigned SOUND_BUF_SIZE = 4096;
+static const unsigned SOUND_BUF_SIZE = 8192;
 static const double DUTY_RATIOS[] = { 0.25, 0.5, 1, 1.5 };
 
 // Constants for channel 4