[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