added very limited experimental improved sound/throttling code to windows build. windows users, please use 44100 16bit sound for now and test the stability.
This commit is contained in:
parent
d81578e52f
commit
e991e6f0ca
|
@ -30,7 +30,7 @@ print "platform: ", env['PLATFORM']
|
|||
if env['PLATFORM'] == 'cygwin':
|
||||
env.Append(CCFLAGS = " -mno-cygwin")
|
||||
env.Append(LINKFLAGS = " -mno-cygwin")
|
||||
env['LIBS'] = ['ddraw','dinput','dsound','gdi32','dxguid','winmm','shell32','wsock32','comdlg32','ole32'];
|
||||
env['LIBS'] = ['wsock32'];
|
||||
|
||||
conf = Configure(env)
|
||||
if not conf.CheckLib('SDL'):
|
||||
|
@ -60,6 +60,8 @@ if env['FRAMESKIP']:
|
|||
# parse SDL cflags/libs
|
||||
env.ParseConfig('sdl-config --cflags --libs')
|
||||
|
||||
print "LIBS:",env['CCFLAGS']
|
||||
#env['IBS'] = ['wsock32', 'SDL', 'z', 'mingw32', 'SDL']
|
||||
Export('env')
|
||||
|
||||
SConscript(['src/SConscript'])
|
||||
|
|
|
@ -2,6 +2,8 @@ Items to be completed before 2.0 release
|
|||
|
||||
FASTAPASS / FP_FASTAPASS / Are these archaic? They suck - ??
|
||||
|
||||
Separate frameskip/pause from EmulationPaused - zeromus
|
||||
|
||||
Make ALL Debugging code conditional - zeromus
|
||||
|
||||
Doxygen integration - DONE
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
fceu_SOURCES += drivers/common/args.cpp drivers/common/cheat.cpp drivers/common/config.cpp drivers/common/vidblit.cpp drivers/common/hq2x.cpp drivers/common/hq3x.cpp drivers/common/scale2x.cpp drivers/common/scale3x.cpp drivers/common/scalebit.cpp
|
|
@ -0,0 +1,288 @@
|
|||
#include "oakra.h"
|
||||
|
||||
#include "dsound.h"
|
||||
#include <vector>
|
||||
|
||||
#define LATENCY_MS (50)
|
||||
|
||||
|
||||
int voltbl[] = {
|
||||
-10000,-8750,-8018,-7499,-7097,-6768,-6490,-6250,-6037,-5847,-5675,-5518,-5374,-5240,-5116,-5000,
|
||||
-4890,-4787,-4690,-4597,-4509,-4425,-4345,-4268,-4195,-4124,-4056,-3990,-3927,-3866,-3807,-3749,
|
||||
-3694,-3640,-3588,-3537,-3488,-3440,-3393,-3347,-3303,-3259,-3217,-3175,-3135,-3095,-3056,-3018,
|
||||
-2981,-2945,-2909,-2874,-2840,-2806,-2773,-2740,-2708,-2677,-2646,-2616,-2586,-2557,-2528,-2500,
|
||||
-2472,-2444,-2417,-2390,-2364,-2338,-2312,-2287,-2262,-2238,-2213,-2190,-2166,-2143,-2120,-2097,
|
||||
-2075,-2053,-2031,-2009,-1988,-1967,-1946,-1925,-1905,-1885,-1865,-1845,-1826,-1806,-1787,-1768,
|
||||
-1750,-1731,-1713,-1695,-1677,-1659,-1641,-1624,-1607,-1590,-1573,-1556,-1539,-1523,-1506,-1490,
|
||||
-1474,-1458,-1443,-1427,-1412,-1396,-1381,-1366,-1351,-1336,-1321,-1307,-1292,-1278,-1264,-1250,
|
||||
-1235,-1222,-1208,-1194,-1180,-1167,-1153,-1140,-1127,-1114,-1101,-1088,-1075,-1062,-1050,-1037,
|
||||
-1025,-1012,-1000,-988,-976,-963,-951,-940,-928,-916,-904,-893,-881,-870,-858,-847,
|
||||
-836,-825,-814,-803,-792,-781,-770,-759,-748,-738,-727,-717,-706,-696,-685,-675,
|
||||
-665,-655,-645,-635,-625,-615,-605,-595,-585,-576,-566,-556,-547,-537,-528,-518,
|
||||
-509,-500,-490,-481,-472,-463,-454,-445,-436,-427,-418,-409,-400,-391,-383,-374,
|
||||
-365,-357,-348,-340,-331,-323,-314,-306,-298,-289,-281,-273,-265,-256,-248,-240,
|
||||
-232,-224,-216,-208,-200,-193,-185,-177,-169,-162,-154,-146,-139,-131,-123,-116,
|
||||
-108,-101,-93,-86,-79,-71,-64,-57,-49,-42,-35,-28,-21,-14,-7,0};
|
||||
|
||||
class DSVoice : public OAKRA_Voice {
|
||||
public:
|
||||
OAKRA_Module_OutputDS *driver;
|
||||
OAKRA_Format format;
|
||||
int formatShift;
|
||||
IDirectSoundBuffer *ds_buf;
|
||||
int buflen;
|
||||
unsigned int cPlay;
|
||||
int vol,pan;
|
||||
|
||||
virtual void setPan(int pan) {
|
||||
this->pan = pan;
|
||||
if(pan==0) ds_buf->SetPan(0);
|
||||
else if(pan>0) ds_buf->SetPan(-voltbl[255-pan]);
|
||||
else ds_buf->SetPan(voltbl[255+pan]);
|
||||
}
|
||||
virtual void setVol(int vol) {
|
||||
this->vol = vol;
|
||||
ds_buf->SetVolume(voltbl[vol]);
|
||||
}
|
||||
virtual int getVol() { return vol; }
|
||||
virtual int getPan() { return pan; }
|
||||
void setSource(OAKRA_Module *source) {
|
||||
this->source = source;
|
||||
}
|
||||
virtual ~DSVoice() {
|
||||
driver->freeVoiceInternal(this,true);
|
||||
ds_buf->Release();
|
||||
}
|
||||
DSVoice(OAKRA_Module_OutputDS *driver, OAKRA_Format &format, IDirectSound *ds_dev, bool global) {
|
||||
this->driver = driver;
|
||||
vol = 255;
|
||||
pan = 0;
|
||||
source = 0;
|
||||
this->format = format;
|
||||
formatShift = getFormatShift(format);
|
||||
buflen = (format.rate * LATENCY_MS / 1000);
|
||||
|
||||
WAVEFORMATEX wfx;
|
||||
memset(&wfx, 0, sizeof(wfx));
|
||||
wfx.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfx.nChannels = format.channels;
|
||||
wfx.nSamplesPerSec = format.rate;
|
||||
wfx.nAvgBytesPerSec = format.rate * format.size;
|
||||
wfx.nBlockAlign = format.size;
|
||||
wfx.wBitsPerSample = (format.format==OAKRA_S16?16:8);
|
||||
wfx.cbSize = sizeof(wfx);
|
||||
|
||||
DSBUFFERDESC dsbd;
|
||||
memset(&dsbd, 0, sizeof(dsbd));
|
||||
dsbd.dwSize = sizeof(dsbd);
|
||||
dsbd.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_LOCSOFTWARE | DSBCAPS_CTRLVOLUME ;
|
||||
if(global) dsbd.dwFlags |= DSBCAPS_GLOBALFOCUS ;
|
||||
dsbd.dwBufferBytes = buflen * format.size;
|
||||
dsbd.lpwfxFormat = &wfx;
|
||||
|
||||
HRESULT hr = ds_dev->CreateSoundBuffer(&dsbd,&ds_buf,0);
|
||||
cPlay = 0;
|
||||
|
||||
hr = ds_buf->Play(0,0,DSBPLAY_LOOPING);
|
||||
int xxx=9;
|
||||
}
|
||||
|
||||
//not supported
|
||||
virtual void volFade(int start, int end, int ms) {}
|
||||
|
||||
void update() {
|
||||
DWORD play, write;
|
||||
HRESULT hr = ds_buf->GetCurrentPosition(&play, &write);
|
||||
play >>= formatShift;
|
||||
write >>= formatShift;
|
||||
|
||||
int todo;
|
||||
if(play<cPlay) todo = play + buflen - cPlay;
|
||||
else todo = play - cPlay;
|
||||
|
||||
if(!todo) return;
|
||||
|
||||
|
||||
void* buffer1;
|
||||
void* buffer2;
|
||||
DWORD buffer1_length;
|
||||
DWORD buffer2_length;
|
||||
hr = ds_buf->Lock(
|
||||
cPlay<<formatShift,todo<<formatShift,
|
||||
&buffer1, &buffer1_length,
|
||||
&buffer2, &buffer2_length,0
|
||||
);
|
||||
|
||||
buffer1_length >>= formatShift;
|
||||
buffer2_length >>= formatShift;
|
||||
int done = 0;
|
||||
if(source) {
|
||||
done = source->generate(buffer1_length,buffer1);
|
||||
if(done != buffer1_length) {
|
||||
generateSilence(buffer1_length - done,(char *)buffer1 + (done<<formatShift),format.size);
|
||||
generateSilence(buffer2_length,buffer2,format.size);
|
||||
die();
|
||||
} else {
|
||||
if(buffer2_length) {
|
||||
done = source->generate(buffer2_length,buffer2);
|
||||
if(done != buffer2_length) {
|
||||
generateSilence(buffer2_length - done,(char *)buffer2 + (done<<formatShift),format.size);
|
||||
die();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ds_buf->Unlock(
|
||||
buffer1, buffer1_length,
|
||||
buffer2, buffer2_length);
|
||||
|
||||
cPlay = play;
|
||||
}
|
||||
};
|
||||
|
||||
class Data {
|
||||
public:
|
||||
bool global;
|
||||
IDirectSound* ds_dev;
|
||||
std::vector<DSVoice *> voices;
|
||||
CRITICAL_SECTION criticalSection;
|
||||
};
|
||||
|
||||
|
||||
class ThreadData {
|
||||
public:
|
||||
ThreadData() { kill = dead = false; }
|
||||
OAKRA_Module_OutputDS *ds;
|
||||
bool kill,dead;
|
||||
};
|
||||
|
||||
OAKRA_Module_OutputDS::OAKRA_Module_OutputDS() {
|
||||
data = new Data();
|
||||
((Data *)data)->global = false;
|
||||
InitializeCriticalSection(&((Data *)data)->criticalSection);
|
||||
}
|
||||
|
||||
OAKRA_Module_OutputDS::~OAKRA_Module_OutputDS() {
|
||||
//ask the driver to shutdown, and wait for it to do so
|
||||
((ThreadData *)threadData)->kill = true;
|
||||
while(!((ThreadData *)threadData)->dead) Sleep(1);
|
||||
|
||||
////kill all the voices
|
||||
std::vector<DSVoice *> voicesCopy = ((Data *)data)->voices;
|
||||
int voices = (int)voicesCopy.size();
|
||||
for(int i=0;i<voices;i++)
|
||||
delete voicesCopy[i];
|
||||
|
||||
////free other resources
|
||||
DeleteCriticalSection(&((Data *)data)->criticalSection);
|
||||
((Data *)data)->ds_dev->Release();
|
||||
delete (Data *)data;
|
||||
delete (ThreadData *)threadData;
|
||||
}
|
||||
|
||||
OAKRA_Voice *OAKRA_Module_OutputDS::getVoice(OAKRA_Format &format, OAKRA_Module *source) {
|
||||
DSVoice *dsv = (DSVoice *)getVoice(format);
|
||||
dsv->setSource(source);
|
||||
return dsv;
|
||||
}
|
||||
|
||||
OAKRA_Voice *OAKRA_Module_OutputDS::getVoice(OAKRA_Format &format) {
|
||||
DSVoice *voice = new DSVoice(this,format,((Data *)data)->ds_dev,((Data *)data)->global);
|
||||
((Data *)data)->voices.push_back(voice);
|
||||
return voice;
|
||||
}
|
||||
void OAKRA_Module_OutputDS::freeVoice(OAKRA_Voice *voice) {
|
||||
freeVoiceInternal(voice,false);
|
||||
}
|
||||
|
||||
void OAKRA_Module_OutputDS::freeVoiceInternal(OAKRA_Voice *voice, bool internal) {
|
||||
lock();
|
||||
Data *data = (Data *)this->data;
|
||||
int j = -1;
|
||||
for(int i=0;i<(int)data->voices.size();i++)
|
||||
if(data->voices[i] == voice) j = i;
|
||||
if(j!=-1)
|
||||
data->voices.erase(data->voices.begin()+j);
|
||||
if(!internal)
|
||||
delete voice;
|
||||
unlock();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void OAKRA_Module_OutputDS::start(void *hwnd) {
|
||||
HRESULT hr = CoInitialize(NULL);
|
||||
IDirectSound* ds_dev;
|
||||
hr = CoCreateInstance(CLSID_DirectSound,0,CLSCTX_INPROC_SERVER,IID_IDirectSound,(void**)&ds_dev);
|
||||
|
||||
if(!hwnd) {
|
||||
hwnd = GetDesktopWindow();
|
||||
((Data *)data)->global = true;
|
||||
}
|
||||
|
||||
//use default device
|
||||
hr = ds_dev->Initialize(0);
|
||||
hr = ds_dev->SetCooperativeLevel((HWND)hwnd, DSSCL_NORMAL);
|
||||
|
||||
((Data *)data)->ds_dev = ds_dev;
|
||||
}
|
||||
|
||||
|
||||
DWORD WINAPI updateProc(LPVOID lpParameter) {
|
||||
ThreadData *data = (ThreadData *)lpParameter;
|
||||
for(;;) {
|
||||
if(data->kill) break;
|
||||
data->ds->update();
|
||||
Sleep(1);
|
||||
}
|
||||
data->dead = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OAKRA_Module_OutputDS::beginThread() {
|
||||
DWORD updateThreadId;
|
||||
threadData = new ThreadData();
|
||||
((ThreadData *)threadData)->ds = this;
|
||||
HANDLE updateThread = CreateThread(0,0,updateProc,threadData,0,&updateThreadId);
|
||||
SetThreadPriority(updateThread,THREAD_PRIORITY_TIME_CRITICAL);
|
||||
//SetThreadPriority(updateThread,THREAD_PRIORITY_HIGHEST);
|
||||
}
|
||||
|
||||
void OAKRA_Module_OutputDS::endThread() {
|
||||
((ThreadData *)threadData)->kill = true;
|
||||
}
|
||||
|
||||
void OAKRA_Module_OutputDS::update() {
|
||||
lock();
|
||||
int voices = (int)((Data *)data)->voices.size();
|
||||
|
||||
//render all the voices
|
||||
for(int i=0;i<voices;i++)
|
||||
((Data *)data)->voices[i]->update();
|
||||
|
||||
//look for voices that are dead
|
||||
std::vector<DSVoice *> deaders;
|
||||
for(int i=0;i<voices;i++)
|
||||
if(((Data *)data)->voices[i]->dead)
|
||||
deaders.push_back(((Data *)data)->voices[i]);
|
||||
|
||||
//unlock the driver before killing voices!
|
||||
//that way, the voice's death callback won't occur within the driver lock
|
||||
unlock();
|
||||
|
||||
//kill those voices
|
||||
for(int i=0;i<(int)deaders.size();i++) {
|
||||
deaders[i]->callbackDied();
|
||||
freeVoice(deaders[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void OAKRA_Module_OutputDS::lock() {
|
||||
EnterCriticalSection( &((Data *)this->data)->criticalSection );
|
||||
}
|
||||
|
||||
void OAKRA_Module_OutputDS::unlock() {
|
||||
LeaveCriticalSection( &((Data *)this->data)->criticalSection );
|
||||
}
|
||||
|
|
@ -125,6 +125,7 @@ static void UpdateTopRider(void);
|
|||
|
||||
static uint32 JSreturn=0;
|
||||
int NoWaiting=0;
|
||||
bool turbo = false;
|
||||
|
||||
#include "keyscan.h"
|
||||
static unsigned char *keys=0;
|
||||
|
@ -1226,8 +1227,8 @@ static struct
|
|||
{ EMUCMD_FRAME_ADVANCE, SCAN_TAB, },
|
||||
{ EMUCMD_SCREENSHOT, SCAN_F9 },
|
||||
{ EMUCMD_HIDE_MENU_TOGGLE, SCAN_ESCAPE },
|
||||
//{ EMUCMD_SPEED_SLOWER, SCAN_MINUS, }, // think about these
|
||||
//{ EMUCMD_SPEED_FASTER, SCAN_EQUAL, }, // think about these
|
||||
{ EMUCMD_SPEED_SLOWER, SCAN_MINUS, }, // think about these
|
||||
{ EMUCMD_SPEED_FASTER, SCAN_EQUAL, }, // think about these
|
||||
{ EMUCMD_SPEED_TURBO, SCAN_GRAVE, }, //tilde
|
||||
{ EMUCMD_SAVE_SLOT_0, SCAN_0, },
|
||||
{ EMUCMD_SAVE_SLOT_1, SCAN_1, },
|
||||
|
@ -1826,11 +1827,13 @@ void MapInput(void)
|
|||
|
||||
void FCEUD_TurboOn(void)
|
||||
{
|
||||
NoWaiting|=1;
|
||||
//NoWaiting|=1;
|
||||
turbo = 1;
|
||||
}
|
||||
|
||||
void FCEUD_TurboOff(void)
|
||||
{
|
||||
NoWaiting&=~1;
|
||||
//NoWaiting&=~1;
|
||||
turbo = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -490,18 +490,17 @@ doloopy:
|
|||
{
|
||||
while(GameInfo)
|
||||
{
|
||||
uint8 *gfx=0;
|
||||
int32 *sound=0;
|
||||
int32 ssize=0;
|
||||
uint8 *gfx=0; ///contains framebuffer
|
||||
int32 *sound=0; ///contains sound data buffer
|
||||
int32 ssize=0; ///contains sound samples count
|
||||
|
||||
#ifdef _USE_SHARED_MEMORY_
|
||||
UpdateBasicBot();
|
||||
#endif
|
||||
FCEU_UpdateBot();
|
||||
|
||||
FCEUI_Emulate(&gfx, &sound, &ssize, 0);
|
||||
xbsave = gfx;
|
||||
FCEUD_Update(gfx, sound, ssize);
|
||||
FCEUI_Emulate(&gfx, &sound, &ssize, 0); //emulate a single frame
|
||||
FCEUD_Update(gfx, sound, ssize); //update displays and debug tools
|
||||
|
||||
//mbg 6/30/06 - close game if we were commanded to by calls nested in FCEUI_Emulate()
|
||||
if(closeGame)
|
||||
|
@ -510,7 +509,21 @@ doloopy:
|
|||
GameInfo = 0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
//xbsave = NULL;
|
||||
RedrawWindow(hAppWnd,0,0,RDW_ERASE|RDW_INVALIDATE);
|
||||
StopSound();
|
||||
}
|
||||
Sleep(50);
|
||||
if(!exiting)
|
||||
goto doloopy;
|
||||
|
||||
doexito:
|
||||
DriverKill();
|
||||
timeEndPeriod(1);
|
||||
FCEUI_Kill();
|
||||
return(0);
|
||||
}
|
||||
|
||||
//mbg merge 7/19/06
|
||||
//--------this code was added by tasbuild
|
||||
|
@ -549,21 +562,8 @@ doloopy:
|
|||
stopCount=0;
|
||||
}*/
|
||||
//-----------------------------------
|
||||
}
|
||||
xbsave = NULL;
|
||||
RedrawWindow(hAppWnd,0,0,RDW_ERASE|RDW_INVALIDATE);
|
||||
StopSound();
|
||||
}
|
||||
Sleep(50);
|
||||
if(!exiting)
|
||||
goto doloopy;
|
||||
|
||||
doexito:
|
||||
DriverKill();
|
||||
timeEndPeriod(1);
|
||||
FCEUI_Kill();
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
//mbg merge 7/19/06 - the function that contains the code that used to just be UpdateFCEUWindow() and FCEUD_UpdateInput()
|
||||
void _updateWindow() {
|
||||
|
@ -780,15 +780,10 @@ void _updateWindow() {
|
|||
|
||||
void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count)
|
||||
{
|
||||
static int skipcount = 0;
|
||||
int temp_fps_scale=(NoWaiting&1)?(256*16):fps_scale;
|
||||
int maxskip = (temp_fps_scale<=256) ? 0 : temp_fps_scale>>8;
|
||||
|
||||
int ocount = Count;
|
||||
//mbg merge 7/19/06 - leaving this untouched but untested
|
||||
/*int ocount = Count;
|
||||
// apply frame scaling to Count
|
||||
Count = (Count<<8)/temp_fps_scale;
|
||||
|
||||
//mbg merge 7/19/06 - leaving this untouched but untested
|
||||
//Disable sound and throttling for BotMode--we want max speed!
|
||||
if(FCEU_BotMode())
|
||||
{
|
||||
|
@ -804,19 +799,41 @@ void FCEUD_Update(uint8 *XBuf, int32 *Buffer, int Count)
|
|||
UpdateFCEUWindow();
|
||||
FCEUD_UpdateInput();
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
|
||||
//mbg naive code
|
||||
extern bool turbo; //hack
|
||||
|
||||
//write all the sound we generated.
|
||||
if(soundo && Buffer && Count) {
|
||||
int32 writeSize = GetWriteSound();
|
||||
int32 writeCount = Count;
|
||||
FCEUD_WriteSoundData(Buffer,temp_fps_scale,MAX(writeSize,writeCount));
|
||||
void FCEUD_WriteSoundData_new(int32 *Buffer, int scale, int Count, bool turbo);
|
||||
FCEUD_WriteSoundData_new(Buffer,fps_scale,Count,turbo);
|
||||
//FCEUD_WriteSoundData(Buffer,fps_scale,Count);
|
||||
}
|
||||
|
||||
//blit the framebuffer
|
||||
if(XBuf)
|
||||
FCEUD_BlitScreen(XBuf);
|
||||
|
||||
//update debugging displays
|
||||
_updateWindow();
|
||||
|
||||
|
||||
//throttle
|
||||
bool skip = false;
|
||||
for(;;) {
|
||||
if(!(eoptions&EO_NOTHROTTLE)) //if throttling is enabled..
|
||||
if(!turbo) //and turbo is disabled..
|
||||
if(!FCEUI_EmulationPaused()) //and we're not paused..
|
||||
//if(SpeedThrottle()) {//...then check whether we need to throttle
|
||||
// //idle..
|
||||
// Sleep(0);
|
||||
// continue;
|
||||
//}
|
||||
{}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//delay until we unpause. we will only stick here if we're paused by a breakpoint or debug command
|
||||
while(FCEUI_EmulationPaused() && inDebugger)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,209 @@
|
|||
//this code is sloppily ripped from an unfinished sound system written for internal use by m.gambrell
|
||||
//it is released into the public domain and its stability is not warranted
|
||||
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <map>
|
||||
#include <stack>
|
||||
#include <ctype.h>
|
||||
#include <queue>
|
||||
|
||||
|
||||
const int OAKRA_U8 = 0;
|
||||
const int OAKRA_S16 = 1;
|
||||
const int OAKRA_S32 = 2;
|
||||
|
||||
const int OAKRA_STATUS_STOPPED = 0;
|
||||
const int OAKRA_STATUS_PLAYING = 1;
|
||||
|
||||
struct OAKRA_Format {
|
||||
int channels, format, rate, size;
|
||||
};
|
||||
|
||||
//implements an easy to use, bland callback
|
||||
template <typename T> struct OAKRA_Callback {
|
||||
OAKRA_Callback() { func = 0; param = 0; }
|
||||
T operator()() { if(func) return func(param); }
|
||||
T (*func)(void *param);
|
||||
void *param;
|
||||
};
|
||||
template <typename T, typename TARG> struct OAKRA_ArgumentCallback {
|
||||
OAKRA_ArgumentCallback() { func = 0; param = 0; }
|
||||
T operator()(TARG arg) { if(func) return func(param,arg); }
|
||||
T (*func)(void *param, TARG arg);
|
||||
void *param;
|
||||
};
|
||||
|
||||
class OAKRA_Module {
|
||||
public:
|
||||
virtual int generate(int samples, void *buf) { return 0; }
|
||||
|
||||
int adapt_to_2S16(int samples, void *buf, OAKRA_Format &sourceFormat) {
|
||||
short *sbuf = (short *)buf;
|
||||
unsigned char *bbuf = (unsigned char *)buf;
|
||||
if(sourceFormat.format == OAKRA_S16) {
|
||||
if(sourceFormat.channels == 2) return samples;
|
||||
for(int i=samples-1,j=samples*2-2;i>=0;i--,j-=2)
|
||||
sbuf[j] = sbuf[j+1] = sbuf[i];
|
||||
} else {
|
||||
if(sourceFormat.channels == 1)
|
||||
for(int i=samples-1,j=samples*2-2;i>=0;i--,j-=2)
|
||||
sbuf[j] = sbuf[j+1] = ((int)bbuf[i]-128)<<8;
|
||||
else
|
||||
for(int j=samples*2-2;j>=0;j--)
|
||||
sbuf[j] = sbuf[j+1] = ((int)bbuf[j]-128)<<8;
|
||||
}
|
||||
return samples;
|
||||
}
|
||||
|
||||
//trashes some samples using the buffer provided
|
||||
void trash(int samples, void *buf, int bufsamples) {
|
||||
while(samples) {
|
||||
int todo = std::min(samples,bufsamples);
|
||||
generate(todo,buf);
|
||||
samples -= todo;
|
||||
}
|
||||
}
|
||||
|
||||
static int calcSize(OAKRA_Format &format) {
|
||||
int size = format.channels;
|
||||
if(format.format == OAKRA_S16) size *= 2;
|
||||
return size;
|
||||
}
|
||||
|
||||
static int getFormatShift(OAKRA_Format &format) {
|
||||
if(format.size==1) return 0;
|
||||
else if(format.size==2) return 1;
|
||||
else if(format.size==4) return 2;
|
||||
return -1; //try and crash!
|
||||
}
|
||||
|
||||
static void *malloc(int len) {
|
||||
void *ptr = ::malloc(len);
|
||||
return ptr;
|
||||
}
|
||||
void *malloc(int sampsize, int len) { return malloc(sampsize*len); }
|
||||
void *malloc(int sampsize, int channels, int len) { return malloc(sampsize*len*channels); }
|
||||
void *realloc(void *ptr, int len) {
|
||||
ptr = ::realloc(ptr,len);
|
||||
return ptr;
|
||||
}
|
||||
void free(void *ptr) {
|
||||
::free(ptr);
|
||||
}
|
||||
|
||||
|
||||
static int generateNoise(int samples, void *buf, int sampleSize) {
|
||||
for(int i=0;i<samples;i++)
|
||||
for(int j=0;j<sampleSize;j++)
|
||||
((char *)buf)[i*sampleSize+j] = rand();
|
||||
return samples;
|
||||
}
|
||||
|
||||
static int generateSilence(int samples, void *buf, int sampleSize) {
|
||||
char *cbuf = (char *)buf;
|
||||
int n = sampleSize*samples;
|
||||
memset(buf,0,n);
|
||||
return samples;
|
||||
}
|
||||
|
||||
static int generateSilence(int samples, void *buf, OAKRA_Format &format) {
|
||||
char *cbuf = (char *)buf;
|
||||
int n = format.size*samples;
|
||||
memset(buf,0,n);
|
||||
return samples;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
T *malloc() {
|
||||
return (T *)malloc(sizeof(T));
|
||||
}
|
||||
template<typename T>
|
||||
T *malloc(int amt) {
|
||||
return (T *)malloc(sizeof(T)*amt);
|
||||
}
|
||||
template<typename T>
|
||||
T **nmalloc(int number) {
|
||||
return (T **)malloc(sizeof(T)*number);
|
||||
}
|
||||
};
|
||||
|
||||
class OAKRA_IQueryFormat {
|
||||
public:
|
||||
virtual OAKRA_Format &queryFormat() = 0;
|
||||
};
|
||||
|
||||
//this is basically a filter class
|
||||
//one source, one sink
|
||||
class OAKRA_BasicModule : public OAKRA_Module {
|
||||
public:
|
||||
OAKRA_Module *source, *sink;
|
||||
OAKRA_BasicModule() { source = sink = 0; }
|
||||
};
|
||||
|
||||
class OAKRA_Voice : public OAKRA_BasicModule {
|
||||
public:
|
||||
OAKRA_Voice() { dead = false; }
|
||||
virtual ~OAKRA_Voice() { }
|
||||
virtual void setPan(int pan) = 0;
|
||||
virtual int getPan() =0;
|
||||
virtual void setVol(int vol) = 0;
|
||||
virtual int getVol()=0;
|
||||
virtual void setSource(OAKRA_Module *source) = 0;
|
||||
|
||||
virtual void volFade(int start, int end, int ms)=0;
|
||||
|
||||
//call this when youre in the middle of rendering the voice, but have decided to quit
|
||||
//the driver will then trash the voice as soon as it gets the chance.
|
||||
//you dont have to have the driver locked to call it. that would be illogical,
|
||||
//as the driver is currently locked while it is rendering!
|
||||
virtual void die() {
|
||||
dead = true;
|
||||
}
|
||||
|
||||
//indicates whether a voice is dead
|
||||
bool dead;
|
||||
|
||||
//callback fired when a voice dies
|
||||
OAKRA_Callback<void> callbackDied;
|
||||
};
|
||||
|
||||
|
||||
class OAKRA_OutputDriver : public OAKRA_BasicModule {
|
||||
public:
|
||||
virtual ~OAKRA_OutputDriver() {} ;
|
||||
virtual OAKRA_Voice *getVoice(OAKRA_Format &format) = 0;
|
||||
virtual OAKRA_Voice *getVoice(OAKRA_Format &format, OAKRA_Module *source) = 0;
|
||||
|
||||
//this should be safe to call from within a driver callback. in general, nothing else will be.
|
||||
//even if you dont delete the voice (if youre recycling it) you should clear out the source asap
|
||||
virtual void freeVoice(OAKRA_Voice *voice) = 0;
|
||||
|
||||
virtual void lock() = 0;
|
||||
virtual void unlock() = 0;
|
||||
};
|
||||
|
||||
|
||||
class OAKRA_Module_OutputDS : public OAKRA_OutputDriver {
|
||||
|
||||
void *threadData;
|
||||
void *data;
|
||||
|
||||
public:
|
||||
|
||||
OAKRA_Module_OutputDS();
|
||||
~OAKRA_Module_OutputDS();
|
||||
OAKRA_Voice *getVoice(OAKRA_Format &format);
|
||||
OAKRA_Voice *getVoice(OAKRA_Format &format, OAKRA_Module *source);
|
||||
void freeVoice(OAKRA_Voice *voice);
|
||||
void freeVoiceInternal(OAKRA_Voice *voice, bool internal);
|
||||
void start(void *hwnd);
|
||||
void update();
|
||||
void beginThread();
|
||||
void endThread();
|
||||
void lock();
|
||||
void unlock();
|
||||
};
|
|
@ -18,6 +18,7 @@
|
|||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <list>
|
||||
|
||||
LPDIRECTSOUND ppDS=0; /* DirectSound object. */
|
||||
LPDIRECTSOUNDBUFFER ppbuf=0; /* Primary buffer object. */
|
||||
|
@ -131,6 +132,10 @@ int32 GetMaxSound(void)
|
|||
return( BufHowMuch >> bittage);
|
||||
}
|
||||
|
||||
///enqueues the given samples for playback
|
||||
static void EnqueueSamples(void *data, uint32 len) {
|
||||
}
|
||||
|
||||
static int RawWrite(void *data, uint32 len)
|
||||
{
|
||||
//uint32 cw; //mbg merge 7/17/06 removed
|
||||
|
@ -156,11 +161,12 @@ static int RawWrite(void *data, uint32 len)
|
|||
|
||||
|
||||
// THIS LIMITS THE EMULATION SPEED
|
||||
if((!NoWaiting) || (soundoptions&SO_OLDUP))
|
||||
while(!(curlen=RawCanWrite()))
|
||||
{
|
||||
Sleep(1);
|
||||
}
|
||||
//if((!NoWaiting) || (soundoptions&SO_OLDUP))
|
||||
//printf("RawCanWrite(): %d\n",RawCanWrite());
|
||||
//while(!(curlen=RawCanWrite()))
|
||||
//{
|
||||
// Sleep(1);
|
||||
//}
|
||||
|
||||
if(curlen>len) curlen=len;
|
||||
|
||||
|
@ -211,8 +217,8 @@ static int RawWrite(void *data, uint32 len)
|
|||
len-=curlen;
|
||||
data=(uint8 *)data+curlen; //mbg merge 7/17/06 reworked to be type proper
|
||||
|
||||
if(len && !NoWaiting && (fps_scale <= 256 || (soundoptions&SO_OLDUP)))
|
||||
Sleep(1); // do some extra sleeping if we think there's time and we're not scaling up the FPS or in turbo mode
|
||||
//if(len && !NoWaiting && (fps_scale <= 256 || (soundoptions&SO_OLDUP)))
|
||||
// Sleep(1); // do some extra sleeping if we think there's time and we're not scaling up the FPS or in turbo mode
|
||||
|
||||
} // end while(len) loop
|
||||
|
||||
|
@ -222,6 +228,212 @@ static int RawWrite(void *data, uint32 len)
|
|||
|
||||
int silencer=0;
|
||||
|
||||
#undef min
|
||||
#undef max
|
||||
#include "oakra.h"
|
||||
|
||||
OAKRA_Module_OutputDS *dsout;
|
||||
|
||||
class BufferSet {
|
||||
public:
|
||||
|
||||
static const int BufferSize = 1024;
|
||||
static const int BufferSizeBits = 10;
|
||||
static const int BufferSizeBitmask = 1023;
|
||||
|
||||
class Buffer {
|
||||
public:
|
||||
int decay, size, length;
|
||||
Buffer(int size) { length = 0; this->size = size; data = OAKRA_Module::malloc(size); }
|
||||
int getRemaining() { return size-length; }
|
||||
void *data;
|
||||
~Buffer() { delete data; }
|
||||
};
|
||||
|
||||
std::vector<Buffer*> liveBuffers;
|
||||
std::vector<Buffer*> freeBuffers;
|
||||
int length;
|
||||
int offset; //offset of beginning of addressing into current buffer
|
||||
int bufferCount;
|
||||
|
||||
BufferSet() {
|
||||
offset = length = bufferCount = 0;
|
||||
}
|
||||
|
||||
//causes the oldest free buffer to decay one unit. kills it if it gets too old
|
||||
void decay(int threshold) {
|
||||
if(freeBuffers.empty()) return;
|
||||
if(freeBuffers[0]->decay++>=threshold) {
|
||||
delete freeBuffers[0];
|
||||
freeBuffers.erase(freeBuffers.begin());
|
||||
}
|
||||
}
|
||||
|
||||
Buffer *getBuffer() {
|
||||
//try to get a buffer from the free pool first
|
||||
//if theres nothing in the free pool, get a new buffer
|
||||
if(!freeBuffers.size()) return getNewBuffer();
|
||||
//otherwise, return the last thing in the free pool (most recently freed)
|
||||
Buffer *ret = *--freeBuffers.end();
|
||||
freeBuffers.erase(--freeBuffers.end());
|
||||
return ret;
|
||||
}
|
||||
|
||||
//adds the buffer to the free list
|
||||
void freeBuffer(Buffer *buf) {
|
||||
freeBuffers.push_back(buf);
|
||||
buf->decay = 0;
|
||||
buf->length = 0;
|
||||
}
|
||||
|
||||
Buffer *getNewBuffer() {
|
||||
bufferCount++;
|
||||
return new Buffer(BufferSize);
|
||||
}
|
||||
|
||||
short getShortAtIndex(int addr) {
|
||||
addr <<= 1; //shorts are 2bytes
|
||||
int buffer = (addr+offset)>>BufferSizeBits;
|
||||
int ofs = (addr+offset) & BufferSizeBitmask;
|
||||
return *(short*)((char*)liveBuffers[buffer]->data+ofs);
|
||||
}
|
||||
|
||||
//dequeues the specified number of bytes
|
||||
void dequeue(int length) {
|
||||
offset += length;
|
||||
while(offset >= BufferSize) {
|
||||
Buffer *front = liveBuffers[0];
|
||||
freeBuffer(front);
|
||||
liveBuffers.erase(liveBuffers.begin());
|
||||
offset -= BufferSize;
|
||||
}
|
||||
this->length -= length;
|
||||
}
|
||||
|
||||
|
||||
void enqueue(int length, void *data) {
|
||||
int todo = length;
|
||||
int done = 0;
|
||||
|
||||
//if there are no buffers in the queue, then we definitely need one before we start
|
||||
if(liveBuffers.empty()) liveBuffers.push_back(getBuffer());
|
||||
|
||||
while(todo) {
|
||||
//check the frontmost buffer
|
||||
Buffer *end = *--liveBuffers.end();
|
||||
int available = std::min(todo,end->getRemaining());
|
||||
memcpy((char*)end->data + end->length,(char*)data + done,available);
|
||||
end->length += available;
|
||||
todo -= available;
|
||||
done += available;
|
||||
|
||||
//we're going to need another buffer
|
||||
if(todo != 0)
|
||||
liveBuffers.push_back(getBuffer());
|
||||
}
|
||||
|
||||
this->length += length;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Player : public OAKRA_Module {
|
||||
public:
|
||||
|
||||
BufferSet buffers;
|
||||
int cursor;
|
||||
|
||||
bool turbo;
|
||||
int scale;
|
||||
|
||||
//not interpolating! someday it will!
|
||||
int generate(int samples, void *buf) {
|
||||
|
||||
int incr = 256;
|
||||
int bufferSamples = buffers.length>>1;
|
||||
|
||||
//if we're we're too far behind, playback faster
|
||||
if(bufferSamples > 44100*3/60) {
|
||||
int behind = bufferSamples - 44100/60;
|
||||
incr = behind*256*60/44100/2;
|
||||
//we multiply our playback rate by 1/2 the number of frames we're behind
|
||||
}
|
||||
if(incr<256) printf("OHNO -- %d -- shouldnt be less than 256!\n",incr); //sanity check: should never be less than 256
|
||||
|
||||
incr = (incr*scale)>>8; //apply scaling factor
|
||||
|
||||
//figure out how many dest samples we can generate at this rate without running out of source samples
|
||||
int destSamplesCanGenerate = (bufferSamples<<8) / incr;
|
||||
|
||||
int todo = std::min(destSamplesCanGenerate,samples);
|
||||
short *sbuf = (short*)buf;
|
||||
for(int i=0;i<todo;i++) {
|
||||
sbuf[i] = buffers.getShortAtIndex(cursor>>8);
|
||||
cursor += incr;
|
||||
}
|
||||
buffers.dequeue((cursor>>8)<<1);
|
||||
cursor &= 255;
|
||||
memset(sbuf+todo,0,(samples-todo)<<1);
|
||||
return samples;
|
||||
}
|
||||
|
||||
Player() {
|
||||
scale = 256;
|
||||
cursor = 0;
|
||||
turbo = false;
|
||||
}
|
||||
|
||||
///receives and enqueues s16 stereo samples
|
||||
void receive(int samples, short *buf, bool turbo, int scale) {
|
||||
|
||||
dsout->lock();
|
||||
buffers.enqueue(samples*2,buf);
|
||||
buffers.decay(60);
|
||||
this->scale = scale;
|
||||
dsout->unlock();
|
||||
|
||||
//throttle
|
||||
// //wait for the buffer to be satisfactorily low before continuing
|
||||
if(!turbo) {
|
||||
for(;;) {
|
||||
dsout->lock();
|
||||
int remain = buffers.length>>1;
|
||||
dsout->unlock();
|
||||
if(remain<44100/60) break;
|
||||
Sleep(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
Player *player;
|
||||
|
||||
|
||||
void sound_init_new() {
|
||||
dsout = new OAKRA_Module_OutputDS();
|
||||
dsout->start(0);
|
||||
dsout->beginThread();
|
||||
OAKRA_Format fmt;
|
||||
fmt.format = OAKRA_S16;
|
||||
fmt.channels = 1;
|
||||
fmt.rate = 44100;
|
||||
fmt.size = 2;
|
||||
OAKRA_Voice *voice = dsout->getVoice(fmt);
|
||||
player = new Player();
|
||||
dsout->lock();
|
||||
voice->setSource(player);
|
||||
dsout->unlock();
|
||||
}
|
||||
|
||||
void FCEUD_WriteSoundData_new(int32 *Buffer, int scale, int Count, bool turbo) {
|
||||
#define WSD_BUFSIZE (2 * 96000 / 50)
|
||||
static int16 MBuffer[WSD_BUFSIZE*2];
|
||||
|
||||
for(int i=0;i<Count;i++)
|
||||
MBuffer[i] = Buffer[i];
|
||||
player->receive(Count,MBuffer,turbo,scale);
|
||||
}
|
||||
|
||||
int FCEUD_WriteSoundData(int32 *Buffer, int scale, int Count)
|
||||
{
|
||||
#define WSD_BUFSIZE (2 * 96000 / 50)
|
||||
|
@ -230,21 +442,25 @@ int FCEUD_WriteSoundData(int32 *Buffer, int scale, int Count)
|
|||
int iCount=0;
|
||||
static int16 MBuffer[WSD_BUFSIZE*2];
|
||||
|
||||
if(!(soundoptions&SO_OLDUP))
|
||||
{
|
||||
if(FCEUI_EmulationPaused())
|
||||
memset(MBuffer, 0, WSD_BUFSIZE); // slow and/or unnecessary
|
||||
//if(!(soundoptions&SO_OLDUP))
|
||||
//{
|
||||
// if(FCEUI_EmulationPaused())
|
||||
// memset(MBuffer, 0, WSD_BUFSIZE); // slow and/or unnecessary
|
||||
|
||||
if(FCEUI_EmulationPaused()) scale >>= 1;
|
||||
// if(FCEUI_EmulationPaused()) scale >>= 1;
|
||||
|
||||
// limit frequency change to between 50% and 200%
|
||||
if(scale > 512) scale = 512;
|
||||
if(scale < 128) scale = 128;
|
||||
}
|
||||
// // limit frequency change to between 50% and 200%
|
||||
// if(scale > 512) scale = 512;
|
||||
// if(scale < 128) scale = 128;
|
||||
//}
|
||||
|
||||
// for(;Count>0;Count-=WSD_BUFSIZE)
|
||||
{
|
||||
int amt = (soundoptions&SO_OLDUP) ? Count : (Count > WSD_BUFSIZE ? WSD_BUFSIZE : Count);
|
||||
//int amt = (soundoptions&SO_OLDUP) ? Count : (Count > WSD_BUFSIZE ? WSD_BUFSIZE : Count);
|
||||
int amt = Count;
|
||||
|
||||
int cando = RawCanWrite();
|
||||
printf("Count/cando %d/%d\n",amt,cando);
|
||||
|
||||
if(!bittage)
|
||||
{
|
||||
|
@ -258,7 +474,7 @@ int FCEUD_WriteSoundData(int32 *Buffer, int scale, int Count)
|
|||
for(P=0;P<amt;P++)
|
||||
*(((uint8*)MBuffer)+P)=((int8)(Buffer[P*scale/256]>>8))^128;
|
||||
|
||||
RawWrite(MBuffer,amt);
|
||||
RawWrite(MBuffer,cando);
|
||||
}
|
||||
else // force 8-bit sound is off:
|
||||
{
|
||||
|
@ -272,7 +488,7 @@ int FCEUD_WriteSoundData(int32 *Buffer, int scale, int Count)
|
|||
for(P=0;P<amt;P++)
|
||||
MBuffer[P]=Buffer[P*scale/256];
|
||||
|
||||
RawWrite(MBuffer,amt * 2);
|
||||
RawWrite(MBuffer,cando * 2);
|
||||
}
|
||||
|
||||
iCount+=amt;
|
||||
|
@ -364,6 +580,8 @@ int InitSound()
|
|||
DSCAPS dscaps;
|
||||
DSBCAPS dsbcaps;
|
||||
|
||||
sound_init_new();
|
||||
|
||||
memset(&wf,0x00,sizeof(wf));
|
||||
wf.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wf.nChannels = 1;
|
||||
|
@ -744,4 +962,7 @@ void FCEUD_SoundVolumeAdjust(int n)
|
|||
FCEU_DispMessage("Sound volume %d.", soundvolume);
|
||||
}
|
||||
|
||||
//-----------
|
||||
|
||||
|
||||
#include "wave.cpp"
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
//http://www.geisswerks.com/ryan/FAQS/timing.html
|
||||
|
||||
static uint64 tmethod,tfreq;
|
||||
static uint64 desiredfps;
|
||||
|
||||
|
@ -27,8 +29,11 @@ int32 fps_scale = 256;
|
|||
|
||||
static void RefreshThrottleFPS(void)
|
||||
{
|
||||
printf("WTF\n");
|
||||
fflush(stdout);
|
||||
desiredfps=FCEUI_GetDesiredFPS()>>8;
|
||||
desiredfps=(desiredfps*fps_scale)>>8;
|
||||
|
||||
}
|
||||
|
||||
static uint64 GetCurTime(void)
|
||||
|
@ -47,56 +52,102 @@ static uint64 GetCurTime(void)
|
|||
|
||||
}
|
||||
|
||||
static uint64 ttime,ltime;
|
||||
|
||||
static void InitSpeedThrottle(void)
|
||||
{
|
||||
tmethod=0;
|
||||
if(QueryPerformanceFrequency((LARGE_INTEGER*)&tfreq))
|
||||
{
|
||||
tmethod=1;
|
||||
}
|
||||
else
|
||||
tfreq=1000;
|
||||
tfreq<<=16; /* Adjustment for fps returned from FCEUI_GetDesiredFPS(). */
|
||||
timeBeginPeriod(1);
|
||||
SetThreadAffinityMask(GetCurrentThread(),1);
|
||||
|
||||
|
||||
tmethod=0;
|
||||
if(QueryPerformanceFrequency((LARGE_INTEGER*)&tfreq)) {
|
||||
tmethod=1;
|
||||
}
|
||||
else tfreq=1000;
|
||||
|
||||
tfreq<<=16; /* Adjustment for fps returned from FCEUI_GetDesiredFPS(). */
|
||||
ltime = 0; //mbg
|
||||
}
|
||||
|
||||
///Resets the throttle timing. use this when the player releases the turbo
|
||||
void ResetSpeedThrottle() {
|
||||
ltime = 0;
|
||||
}
|
||||
|
||||
|
||||
static int SpeedThrottle(void)
|
||||
{
|
||||
static uint64 ttime,ltime;
|
||||
//the desired running time for this frame
|
||||
uint64 desiredRunningTime = tfreq/desiredfps;
|
||||
|
||||
waiter:
|
||||
ttime = GetCurTime();
|
||||
|
||||
ttime=GetCurTime();
|
||||
//if this is our first time, save ltime and bail out
|
||||
if(ltime == 0) {
|
||||
ltime = ttime;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( (ttime-ltime) < (tfreq/desiredfps) )
|
||||
{
|
||||
uint64 sleepy;
|
||||
sleepy=(tfreq/desiredfps)-(ttime-ltime);
|
||||
sleepy*=1000;
|
||||
if(tfreq>=65536)
|
||||
sleepy/=tfreq>>16;
|
||||
else
|
||||
sleepy=0;
|
||||
if(sleepy>100)
|
||||
{
|
||||
// block for a max of 100ms to
|
||||
// keep the gui responsive
|
||||
Sleep(100);
|
||||
return 1;
|
||||
}
|
||||
Sleep(sleepy);
|
||||
goto waiter;
|
||||
}
|
||||
if( (ttime-ltime) >= (tfreq*4/desiredfps))
|
||||
ltime=ttime;
|
||||
else
|
||||
{
|
||||
ltime+=tfreq/desiredfps;
|
||||
//otherwise calculate our delta
|
||||
uint64 delta = ttime-ltime;
|
||||
|
||||
/*printf("%20I64d %20I64d\n",delta,desiredRunningTime);
|
||||
fflush(stdout);*/
|
||||
if( delta < desiredRunningTime ) {
|
||||
//if the elapsed time is less than the desired running time
|
||||
|
||||
if( (ttime-ltime) >= (tfreq/desiredfps) ) // Oops, we're behind!
|
||||
return(1);
|
||||
}
|
||||
return(0);
|
||||
//sleepy gets the time that needs to be slept.
|
||||
//it is then converted to ms<<16
|
||||
uint64 sleepy = desiredRunningTime-delta;
|
||||
//sleepy *= 1000;
|
||||
//if we have more than 1 ms to sleep, sleep 1 ms and return
|
||||
if(sleepy>=65536) {
|
||||
Sleep(1);
|
||||
return 1;
|
||||
} else {
|
||||
//otherwise, we can't throttle for less than 1ms. assume we're close enough and return
|
||||
ltime += desiredRunningTime;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//sleepy*=1000;
|
||||
//if(tfreq>=65536)
|
||||
// sleepy/=tfreq>>16;
|
||||
//else
|
||||
// sleepy=0;
|
||||
//if(sleepy>100)
|
||||
//{
|
||||
// // block for a max of 100ms to
|
||||
// // keep the gui responsive
|
||||
// Sleep(100);
|
||||
// return 1;
|
||||
//}
|
||||
//Sleep(sleepy);
|
||||
//goto waiter;
|
||||
} else {
|
||||
//we're behind...
|
||||
if(delta > 2*desiredRunningTime) {
|
||||
//if we're behind by 2 frames, then reset the throttling
|
||||
ResetSpeedThrottle();
|
||||
} else {
|
||||
//we're only behind by part of a frame
|
||||
//just don't throttle!
|
||||
ltime += desiredRunningTime;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
//}
|
||||
//if( (ttime-ltime) >= (tfreq*4/desiredfps))
|
||||
// ltime=ttime;
|
||||
//else
|
||||
//{
|
||||
// ltime+=tfreq/desiredfps;
|
||||
|
||||
// if( (ttime-ltime) >= (tfreq/desiredfps) ) // Oops, we're behind!
|
||||
// return(1);
|
||||
//}
|
||||
//return(0);
|
||||
}
|
||||
|
||||
// Quick code for internal FPS display.
|
||||
|
|
|
@ -426,6 +426,9 @@ void AutoFire(void)
|
|||
|
||||
void UpdateRewind(void);
|
||||
|
||||
///Emulates a single frame.
|
||||
|
||||
///Skip may be passed in, if FRAMESKIP is #defined, to cause this to emulate more than one frame
|
||||
void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int skip)
|
||||
{
|
||||
int r,ssize;
|
||||
|
@ -452,7 +455,7 @@ void FCEUI_Emulate(uint8 **pXBuf, int32 **SoundBuf, int32 *SoundBufSize, int ski
|
|||
FCEU_UpdateInput();
|
||||
if(geniestage!=1) FCEU_ApplyPeriodicCheats();
|
||||
r=FCEUPPU_Loop(skip);
|
||||
|
||||
|
||||
ssize=FlushEmulateSound();
|
||||
|
||||
//#ifdef WIN32
|
||||
|
|
|
@ -53,6 +53,7 @@ typedef signed int int32;
|
|||
#define fstat _fstat
|
||||
#define mkdir _mkdir
|
||||
#define alloca _alloca
|
||||
#define snprintf _snprintf
|
||||
#define W_OK 2
|
||||
#define R_OK 2
|
||||
#define X_OK 1
|
||||
|
|
|
@ -594,6 +594,9 @@
|
|||
<File
|
||||
RelativePath="..\src\drivers\win\ntview.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\drivers\win\OutputDS.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\drivers\win\ppuview.cpp">
|
||||
</File>
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
AdditionalDependencies="comctl32.lib vfw32.lib dxguid.lib winmm.lib dinput.lib ws2_32.lib ddraw.lib dsound.lib"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
SubSystem="2"
|
||||
SubSystem="1"
|
||||
EntryPointSymbol="mainCRTStartup"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
|
@ -211,12 +211,12 @@
|
|||
EnableIntrinsicFunctions="true"
|
||||
FavorSizeOrSpeed="1"
|
||||
OmitFramePointers="true"
|
||||
AdditionalIncludeDirectories="../zlib"
|
||||
AdditionalIncludeDirectories="../src/drivers/win/zlib"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;MSVC;_CRT_SECURE_NO_DEPRECATE;_WIN32_WINDOWS=0x0410;WINVER=0x0410;NETWORK;LSB_FIRST;_USE_32BIT_TIME_T;FCEUDEF_DEBUGGER;_USE_SHARED_MEMORY_"
|
||||
RuntimeLibrary="0"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
Detect64BitPortabilityProblems="true"
|
||||
Detect64BitPortabilityProblems="false"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
|
@ -634,6 +634,14 @@
|
|||
RelativePath="..\src\drivers\common\config.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\drivers\common\configSys.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\drivers\common\configSys.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\drivers\common\hq2x.cpp"
|
||||
>
|
||||
|
@ -686,10 +694,6 @@
|
|||
<Filter
|
||||
Name="win"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\src\asm.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\drivers\win\aviout.cpp"
|
||||
>
|
||||
|
@ -698,6 +702,10 @@
|
|||
RelativePath="..\src\drivers\win\basicbot.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\drivers\win\basicbot.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\drivers\win\cdlogger.cpp"
|
||||
>
|
||||
|
@ -914,6 +922,14 @@
|
|||
RelativePath="..\src\drivers\win\ntview.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\drivers\win\oakra.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\drivers\win\OutputDS.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\src\drivers\win\ppuview.cpp"
|
||||
>
|
||||
|
|
Loading…
Reference in New Issue