[Scummvm-cvs-logs] SF.net SVN: scummvm: [25659] scummvm/trunk/engines/scumm/player_nes.cpp

fingolfin at users.sourceforge.net fingolfin at users.sourceforge.net
Sat Feb 17 19:52:22 CET 2007


Revision: 25659
          http://scummvm.svn.sourceforge.net/scummvm/?rev=25659&view=rev
Author:   fingolfin
Date:     2007-02-17 10:52:21 -0800 (Sat, 17 Feb 2007)

Log Message:
-----------
Speed up the Player_NES code quite a bit (still is rather slow without compiler optimizations on my 1.5Ghz PowerBook G4, but at least it's not unbearably slow anymore, and with -O2 it's running smoothly)

Modified Paths:
--------------
    scummvm/trunk/engines/scumm/player_nes.cpp

Modified: scummvm/trunk/engines/scumm/player_nes.cpp
===================================================================
--- scummvm/trunk/engines/scumm/player_nes.cpp	2007-02-17 16:59:06 UTC (rev 25658)
+++ scummvm/trunk/engines/scumm/player_nes.cpp	2007-02-17 18:52:21 UTC (rev 25659)
@@ -89,30 +89,36 @@
 	0x20,0x1E
 };
 
+class SoundGen {
+protected:
+	byte wavehold;
+	uint32 freq;	// short
+	uint32 CurD;
+ 
+public:
+	byte Timer;
+	int32 Pos;
+	uint32 Cycles;	// short
+	
+	inline byte GetTimer() const { return Timer; };
+};
 
-class Square {
+class Square : public SoundGen {
 protected:
-	byte volume, envelope, wavehold, duty, swpspeed, swpdir, swpstep, swpenab;
-	uint32 freq;	// short
+	byte volume, envelope, duty, swpspeed, swpdir, swpstep, swpenab;
 	byte Vol;
-	byte CurD;
-	byte Timer;
 	byte EnvCtr, Envelope, BendCtr;
 	bool Enabled, ValidFreq, Active;
 	bool EnvClk, SwpClk;
-	uint32 Cycles;	// short
-	int32 Pos;
 
 	void CheckActive(void);
 
 public:
 	void Reset(void);
 	void Write(int Reg, byte Val);
-	int32 Run(void);
+	void Run(void);
 	void QuarterFrame(void);
 	void HalfFrame(void);
-	
-	inline byte GetTimer() const { return Timer; };
 };
 
 static const int8 Duties[4][8] = {
@@ -177,16 +183,12 @@
 	CheckActive();
 }
 
-int32 Square::Run(void) {
-	Cycles--;
-	if (!Cycles) {
-		Cycles = (freq + 1) << 1;
-		CurD = (CurD + 1) & 0x7;
-	
-		if (Active)
-			Pos = Duties[duty][CurD] * Vol;
-	}
-	return Pos;
+void Square::Run(void) {
+	Cycles = (freq + 1) << 1;
+	CurD = (CurD + 1) & 0x7;
+
+	if (Active)
+		Pos = Duties[duty][CurD] * Vol;
 }
 
 void Square::QuarterFrame(void) {
@@ -230,27 +232,21 @@
 }
 
 
-class Triangle {
+class Triangle : public SoundGen {
 protected:
-	byte linear, wavehold;
-	uint32 freq;	// short
-	byte CurD;
-	byte Timer, LinCtr;
+	byte linear;
+	byte LinCtr;
 	bool Enabled, Active;
 	bool LinClk;
-	uint32 Cycles;	// short
-	int32 Pos;
 
 	void CheckActive(void);
 
 public:
 	void Reset(void);
 	void Write(int Reg, byte Val);
-	int32 Run(void);
+	void Run(void);
 	void QuarterFrame(void);
 	void HalfFrame(void);
-	
-	inline byte GetTimer() const { return Timer; };
 };
 
 static const int8 TriDuty[32] = {
@@ -304,22 +300,18 @@
 	CheckActive();
 }
 
-int32 Triangle::Run(void) {
-	Cycles--;
-	if (!Cycles) {
-		Cycles = freq + 1;
-	
-		if (Active) {
-			CurD++;
-			CurD &= 0x1F;
-	
-			if (freq < 4)
-				Pos = 0;	// beyond hearing range
-			else
-				Pos = TriDuty[CurD] * 8;
-		}
+void Triangle::Run(void) {
+	Cycles = freq + 1;
+
+	if (Active) {
+		CurD++;
+		CurD &= 0x1F;
+
+		if (freq < 4)
+			Pos = 0;	// beyond hearing range
+		else
+			Pos = TriDuty[CurD] * 8;
 	}
-	return Pos;
 }
 
 void Triangle::QuarterFrame(void) {
@@ -341,29 +333,22 @@
 	CheckActive();
 }
 
-class Noise {
+class Noise : public SoundGen {
 protected:
-	byte volume, envelope, wavehold, datatype;
-	uint32 freq;	// short
-	uint32 CurD;	// short
+	byte volume, envelope, datatype;
 	byte Vol;
-	byte Timer;
 	byte EnvCtr, Envelope;
 	bool Enabled;
 	bool EnvClk;
-	uint32 Cycles;	// short
-	int32 Pos;
 
 	void CheckActive(void);
 
 public:
 	void Reset(void);
 	void Write(int Reg, byte Val);
-	int32 Run(void);
+	void Run(void);
 	void QuarterFrame(void);
 	void HalfFrame(void);
-	
-	inline byte GetTimer() const { return Timer; };
 };
 
 static const uint32 NoiseFreq[16] = {
@@ -410,20 +395,16 @@
 	}
 }
 
-int32 Noise::Run(void) {
-	Cycles--;
-	if (!Cycles) {
-		Cycles = NoiseFreq[freq];	/* no + 1 here */
-	
-		if (datatype)
-			CurD = (CurD << 1) | (((CurD >> 14) ^ (CurD >> 8)) & 0x1);
-		else
-			CurD = (CurD << 1) | (((CurD >> 14) ^ (CurD >> 13)) & 0x1);
-	
-		if (Timer)
-			Pos = ((CurD & 0x4000) ? -2 : 2) * Vol;
-	}
-	return Pos;
+void Noise::Run(void) {
+	Cycles = NoiseFreq[freq];	/* no + 1 here */
+
+	if (datatype)
+		CurD = (CurD << 1) | (((CurD >> 14) ^ (CurD >> 8)) & 0x1);
+	else
+		CurD = (CurD << 1) | (((CurD >> 14) ^ (CurD >> 13)) & 0x1);
+
+	if (Timer)
+		Pos = ((CurD & 0x4000) ? -2 : 2) * Vol;
 }
 
 void Noise::QuarterFrame(void) {
@@ -466,8 +447,6 @@
 		int Num;
 	} Frame;
 	
-	void Frame_Run(void);
-
 public:
 	APU(int rate) : SampleRate(rate) {
 		Reset();
@@ -479,33 +458,6 @@
 	int16 GetSample(void);
 };
 
-void APU::Frame_Run(void) {
-	Frame.Cycles = 7457;
-
-	if (Frame.Num < 4) {
-		_square0.QuarterFrame();
-		_square1.QuarterFrame();
-		_triangle.QuarterFrame();
-		_noise.QuarterFrame();
-
-		if (!(Frame.Num & 1)) {
-			_square0.HalfFrame();
-			_square1.HalfFrame();
-			_triangle.HalfFrame();
-			_noise.HalfFrame();
-		}
-	}
-
-	if (Frame.Num & 1)
-		Frame.Cycles++;
-
-	Frame.Num++;
-
-	if (Frame.Num == 5)
-		Frame.Num = 0;
-}
-
-
 void APU::WriteReg(int Addr, byte Val) {
 	switch (Addr) {
 	case 0x000:	_square0.Write(0,Val);	break;
@@ -553,25 +505,84 @@
 	Frame.Cycles = 1;
 }
 
+template <class T>
+int step(T &obj, int sampcycles, uint frame_Cycles, int frame_Num) {
+	int samppos = 0;
+	while (sampcycles) {
+		// Compute the maximal amount we can step ahead before triggering
+		// an action (i.e. compute the minimum of sampcycles, frame_Cycles
+		// and obj.Cycles).
+		uint max_step = sampcycles;
+		if (max_step > frame_Cycles)
+			max_step = frame_Cycles;
+		if (max_step > obj.Cycles)
+			max_step = obj.Cycles;
+
+		// During all but the last of these steps, we just add the value of obj.Pos
+		// to samppos -- so we can to that all at once with a simple multiplication:
+		samppos += obj.Pos * (max_step - 1);
+
+		// Now step ahead...
+		sampcycles -= max_step;
+		frame_Cycles -= max_step;
+		obj.Cycles -= max_step;
+
+		if (!frame_Cycles) {
+			frame_Cycles = 7457;
+		
+			if (frame_Num < 4) {
+				obj.QuarterFrame();
+		
+				if (!(frame_Num & 1)) {
+					obj.HalfFrame();
+				}
+			}
+		
+			if (frame_Num & 1)
+				frame_Cycles++;
+		
+			if (frame_Num == 4)
+				frame_Num = 0;
+			else
+				frame_Num++;
+		}
+	
+		if (!obj.Cycles)
+			obj.Run();
+
+		samppos += obj.Pos;
+	}
+	
+	return samppos;
+}
+
 int16 APU::GetSample(void) {
-	int sampcycles = 0, samppos = 0;
+	int samppos = 0;
 	
-	while (BufPos < 1789773) {
-		BufPos += SampleRate;
+	const int sampcycles = 1+(1789773-BufPos-1)/SampleRate;
+	BufPos = BufPos + sampcycles * SampleRate - 1789773;
 
-		if (!--Frame.Cycles)
-			Frame_Run();
+	samppos += step( _square0, sampcycles, Frame.Cycles, Frame.Num);
+	samppos += step( _square1, sampcycles, Frame.Cycles, Frame.Num);
+	samppos += step(_triangle, sampcycles, Frame.Cycles, Frame.Num);
+	samppos += step(   _noise, sampcycles, Frame.Cycles, Frame.Num);
 
-		samppos += _square0.Run();
-		samppos += _square1.Run();
-		samppos += _triangle.Run();
-		samppos += _noise.Run();
+	uint tmp = sampcycles;
+	while (tmp >= Frame.Cycles) {
+		tmp -= Frame.Cycles;
+		Frame.Cycles = 7457;
+	
+		if (Frame.Num & 1)
+			Frame.Cycles++;
+	
+		if (Frame.Num == 4)
+			Frame.Num = 0;
+		else
+			Frame.Num++;
+	}
 
-		sampcycles++;
-	}
+	Frame.Cycles -= tmp;
 	
-	BufPos -= 1789773;
-
 	return (samppos << 6) / sampcycles;
 }
 


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list