aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/GPU2D.cpp18
-rw-r--r--src/SPU.cpp64
-rw-r--r--src/SPU.h3
-rw-r--r--src/libui_sdl/DlgVideoSettings.cpp26
-rw-r--r--src/libui_sdl/PlatformConfig.cpp2
-rw-r--r--src/libui_sdl/PlatformConfig.h1
-rw-r--r--src/libui_sdl/main.cpp124
7 files changed, 170 insertions, 68 deletions
diff --git a/src/GPU2D.cpp b/src/GPU2D.cpp
index 1ce62c6..288ee58 100644
--- a/src/GPU2D.cpp
+++ b/src/GPU2D.cpp
@@ -2192,21 +2192,19 @@ void GPU2D::DrawSprites(u32 line)
const s32 spritewidth[16] =
{
- 8, 16, 8, 0,
- 16, 32, 8, 0,
- 32, 32, 16, 0,
- 64, 64, 32, 0
+ 8, 16, 8, 8,
+ 16, 32, 8, 8,
+ 32, 32, 16, 8,
+ 64, 64, 32, 8
};
const s32 spriteheight[16] =
{
- 8, 8, 16, 0,
- 16, 8, 32, 0,
- 32, 16, 32, 0,
- 64, 32, 64, 0
+ 8, 8, 16, 8,
+ 16, 8, 32, 8,
+ 32, 16, 32, 8,
+ 64, 32, 64, 8
};
- u32 nsprites = 0;
-
for (int bgnum = 0x0C00; bgnum >= 0x0000; bgnum -= 0x0400)
{
for (int sprnum = 127; sprnum >= 0; sprnum--)
diff --git a/src/SPU.cpp b/src/SPU.cpp
index b25b8d0..b36becf 100644
--- a/src/SPU.cpp
+++ b/src/SPU.cpp
@@ -26,7 +26,6 @@
// * capture addition modes, overflow bugs
// * channel hold
// * 'length less than 4' glitch
-int brap = 0;
namespace SPU
{
@@ -63,10 +62,10 @@ const s16 PSGTable[8][8] =
const u32 kSamplesPerRun = 1;
-const u32 OutputBufferSize = 2*2*1024;
+const u32 OutputBufferSize = 2*1024;
s16 OutputBuffer[2 * OutputBufferSize];
-u32 OutputReadOffset;
-u32 OutputWriteOffset;
+volatile u32 OutputReadOffset;
+volatile u32 OutputWriteOffset;
u16 Cnt;
@@ -99,9 +98,7 @@ void DeInit()
void Reset()
{
- memset(OutputBuffer, 0, 2*OutputBufferSize*2);
- OutputReadOffset = 0;
- OutputWriteOffset = 0;//OutputBufferSize;
+ InitOutput();
Cnt = 0;
MasterVolume = 0;
@@ -579,7 +576,7 @@ void CaptureUnit::Run(s32 sample)
}
}
-int zog = 0, zig = 0;
+
void Mix(u32 samples)
{
s32 channelbuf[32];
@@ -629,7 +626,7 @@ void Mix(u32 samples)
else if (val > 0x7FFF) val = 0x7FFF;
Capture[0]->Run(val);
- if (!((Capture[0]->Cnt & (1<<7)))) break;
+ if (!(Capture[0]->Cnt & (1<<7))) break;
}
}
@@ -644,7 +641,7 @@ void Mix(u32 samples)
else if (val > 0x7FFF) val = 0x7FFF;
Capture[1]->Run(val);
- if (!((Capture[1]->Cnt & (1<<7)))) break;
+ if (!(Capture[1]->Cnt & (1<<7))) break;
}
}
@@ -735,22 +732,61 @@ void Mix(u32 samples)
OutputWriteOffset += 2;
OutputWriteOffset &= ((2*OutputBufferSize)-1);
if (OutputWriteOffset == OutputReadOffset) printf("!! SOUND FIFO OVERFLOW %d\n", OutputWriteOffset>>1);
- zog++; zig++; brap++;
}
NDS::ScheduleEvent(NDS::Event_SPU, true, 1024*kSamplesPerRun, Mix, kSamplesPerRun);
}
+void DrainOutput()
+{
+ OutputReadOffset = 0;
+ OutputWriteOffset = 0;
+}
+
+void InitOutput()
+{
+ memset(OutputBuffer, 0, 2*OutputBufferSize*2);
+ OutputReadOffset = 0;
+ OutputWriteOffset = OutputBufferSize;
+}
+
int GetOutputSize()
{
- return zog; // derp
+ int ret;
+ if (OutputWriteOffset >= OutputReadOffset)
+ ret = OutputWriteOffset - OutputReadOffset;
+ else
+ ret = (OutputBufferSize*2) - OutputReadOffset + OutputWriteOffset;
+
+ ret >>= 1;
+ return ret;
+}
+
+void Sync(bool wait)
+{
+ // sync to audio output in case the core is running too fast
+ // * wait=true: wait until enough audio data has been played
+ // * wait=false: merely skip some audio data to avoid a FIFO overflow
+
+ const int halflimit = (OutputBufferSize / 2);
+
+ if (wait)
+ {
+ // TODO: less CPU-intensive wait?
+ while (GetOutputSize() > halflimit);
+ }
+ else if (GetOutputSize() > halflimit)
+ {
+ int readpos = OutputWriteOffset - (halflimit*2);
+ if (readpos < 0) readpos += (OutputBufferSize*2);
+
+ OutputReadOffset = readpos;
+ }
}
int ReadOutput(s16* data, int samples)
{
- printf("ReadOutput(%d): wrote=%d level=%d ReadOffset=%d WriteOffset=%d\n", samples, zog, zig, OutputReadOffset>>1, OutputWriteOffset>>1);
- zog = 0; zig -= (zig<samples ? zig : samples);
if (OutputReadOffset == OutputWriteOffset)
return 0;
diff --git a/src/SPU.h b/src/SPU.h
index ddd235a..7c99887 100644
--- a/src/SPU.h
+++ b/src/SPU.h
@@ -35,7 +35,10 @@ void SetBias(u16 bias);
void Mix(u32 samples);
+void DrainOutput();
+void InitOutput();
int GetOutputSize();
+void Sync(bool wait);
int ReadOutput(s16* data, int samples);
u8 Read8(u32 addr);
diff --git a/src/libui_sdl/DlgVideoSettings.cpp b/src/libui_sdl/DlgVideoSettings.cpp
index 7d876e2..155fe8b 100644
--- a/src/libui_sdl/DlgVideoSettings.cpp
+++ b/src/libui_sdl/DlgVideoSettings.cpp
@@ -39,12 +39,14 @@ uiWindow* win;
uiRadioButtons* rbRenderer;
uiCheckbox* cbGLDisplay;
+uiCheckbox* cbVSync;
uiCheckbox* cbThreaded3D;
uiCombobox* cbResolution;
uiCheckbox* cbAntialias;
int old_renderer;
int old_gldisplay;
+int old_vsync;
int old_threaded3D;
int old_resolution;
int old_antialias;
@@ -89,6 +91,11 @@ void RevertSettings()
{
Config::ScreenUseGL = old_gldisplay;
}
+ if (old_vsync != Config::ScreenVSync)
+ {
+ Config::ScreenVSync = old_vsync;
+ ApplyNewSettings(4);
+ }
if (old_usegl != new_usegl)
{
apply2 = true;
@@ -134,17 +141,25 @@ void OnRendererChanged(uiRadioButtons* rb, void* blarg)
ApplyNewSettings(2);
else
ApplyNewSettings(3);
-
+
uiControlSetFocus(uiControl(win));
}
void OnGLDisplayChanged(uiCheckbox* cb, void* blarg)
{
Config::ScreenUseGL = uiCheckboxChecked(cb);
+ if (Config::ScreenUseGL) uiControlEnable(uiControl(cbVSync));
+ else uiControlDisable(uiControl(cbVSync));
ApplyNewSettings(2);
uiControlSetFocus(uiControl(win));
}
+void OnVSyncChanged(uiCheckbox* cb, void* blarg)
+{
+ Config::ScreenVSync = uiCheckboxChecked(cb);
+ ApplyNewSettings(4);
+}
+
void OnThreaded3DChanged(uiCheckbox* cb, void* blarg)
{
Config::Threaded3D = uiCheckboxChecked(cb);
@@ -232,6 +247,10 @@ void Open()
cbGLDisplay = uiNewCheckbox("OpenGL display");
uiCheckboxOnToggled(cbGLDisplay, OnGLDisplayChanged, NULL);
uiBoxAppend(in_ctrl, uiControl(cbGLDisplay), 0);
+
+ cbVSync = uiNewCheckbox("VSync");
+ uiCheckboxOnToggled(cbVSync, OnVSyncChanged, NULL);
+ uiBoxAppend(in_ctrl, uiControl(cbVSync), 0);
}
{
@@ -300,17 +319,22 @@ void Open()
old_renderer = Config::_3DRenderer;
old_gldisplay = Config::ScreenUseGL;
+ old_vsync = Config::ScreenVSync;
old_threaded3D = Config::Threaded3D;
old_resolution = Config::GL_ScaleFactor;
old_antialias = Config::GL_Antialias;
uiCheckboxSetChecked(cbGLDisplay, Config::ScreenUseGL);
+ uiCheckboxSetChecked(cbVSync, Config::ScreenVSync);
uiCheckboxSetChecked(cbThreaded3D, Config::Threaded3D);
uiComboboxSetSelected(cbResolution, Config::GL_ScaleFactor-1);
//uiCheckboxSetChecked(cbAntialias, Config::GL_Antialias);
uiRadioButtonsSetSelected(rbRenderer, Config::_3DRenderer);
UpdateControls();
+ if (Config::ScreenUseGL) uiControlEnable(uiControl(cbVSync));
+ else uiControlDisable(uiControl(cbVSync));
+
uiControlShow(uiControl(win));
}
diff --git a/src/libui_sdl/PlatformConfig.cpp b/src/libui_sdl/PlatformConfig.cpp
index 7f45b59..fb31ccd 100644
--- a/src/libui_sdl/PlatformConfig.cpp
+++ b/src/libui_sdl/PlatformConfig.cpp
@@ -43,6 +43,7 @@ int ScreenSizing;
int ScreenFilter;
int ScreenUseGL;
+int ScreenVSync;
int ScreenRatio;
int LimitFPS;
@@ -118,6 +119,7 @@ ConfigEntry PlatformConfigFile[] =
{"ScreenFilter", 0, &ScreenFilter, 1, NULL, 0},
{"ScreenUseGL", 0, &ScreenUseGL, 1, NULL, 0},
+ {"ScreenVSync", 0, &ScreenVSync, 0, NULL, 0},
{"ScreenRatio", 0, &ScreenRatio, 0, NULL, 0},
{"LimitFPS", 0, &LimitFPS, 1, NULL, 0},
diff --git a/src/libui_sdl/PlatformConfig.h b/src/libui_sdl/PlatformConfig.h
index 2c59e5d..2aede24 100644
--- a/src/libui_sdl/PlatformConfig.h
+++ b/src/libui_sdl/PlatformConfig.h
@@ -54,6 +54,7 @@ extern int ScreenSizing;
extern int ScreenFilter;
extern int ScreenUseGL;
+extern int ScreenVSync;
extern int ScreenRatio;
extern int LimitFPS;
diff --git a/src/libui_sdl/main.cpp b/src/libui_sdl/main.cpp
index a19495b..24febf6 100644
--- a/src/libui_sdl/main.cpp
+++ b/src/libui_sdl/main.cpp
@@ -158,6 +158,8 @@ bool LidStatus;
int JoystickID;
SDL_Joystick* Joystick;
+int AudioFreq;
+float AudioSampleFrac;
SDL_AudioDeviceID AudioDevice, MicDevice;
u32 MicBufferLength = 2048;
@@ -560,26 +562,37 @@ void MicLoadWav(char* name)
void AudioCallback(void* data, Uint8* stream, int len)
{
- // resampling:
- // buffer length is 1024 samples
- // which is 710 samples at the original sample rate
+ len /= (sizeof(s16) * 2);
- s16 buf_in[710*2];
+ // resample incoming audio to match the output sample rate
+
+ float f_len_in = (len * 32823.6328125) / (float)AudioFreq;
+ f_len_in += AudioSampleFrac;
+ int len_in = (int)floor(f_len_in);
+ AudioSampleFrac = f_len_in - len_in;
+
+ s16 buf_in[1024*2];
s16* buf_out = (s16*)stream;
- int num_in = SPU::ReadOutput(buf_in, 710);
- int num_out = 1024;
-printf("took %d/%d samples\n", num_in, 710);
+ int num_in = SPU::ReadOutput(buf_in, len_in);
+ int num_out = len;
+
+ if (num_in < 1)
+ {
+ memset(stream, 0, len*sizeof(s16)*2);
+ return;
+ }
+
int margin = 6;
- if (num_in < 710-margin)
+ if (num_in < len_in-margin)
{
int last = num_in-1;
if (last < 0) last = 0;
- for (int i = num_in; i < 710-margin; i++)
+ for (int i = num_in; i < len_in-margin; i++)
((u32*)buf_in)[i] = ((u32*)buf_in)[last];
- num_in = 710-margin;
+ num_in = len_in-margin;
}
float res_incr = num_in / (float)num_out;
@@ -588,12 +601,22 @@ printf("took %d/%d samples\n", num_in, 710);
int volume = Config::AudioVolume;
- for (int i = 0; i < 1024; i++)
+ for (int i = 0; i < len; i++)
{
- // TODO: interp!!
buf_out[i*2 ] = (buf_in[res_pos*2 ] * volume) >> 8;
buf_out[i*2+1] = (buf_in[res_pos*2+1] * volume) >> 8;
+ /*s16 s_l = buf_in[res_pos*2 ];
+ s16 s_r = buf_in[res_pos*2+1];
+
+ float a = res_timer;
+ float b = 1.0 - a;
+ s_l = (s_l * a) + (buf_in[(res_pos-1)*2 ] * b);
+ s_r = (s_r * a) + (buf_in[(res_pos-1)*2+1] * b);
+
+ buf_out[i*2 ] = (s_l * volume) >> 8;
+ buf_out[i*2+1] = (s_r * volume) >> 8;*/
+
res_timer += res_incr;
while (res_timer >= 1.0)
{
@@ -838,6 +861,7 @@ bool JoyButtonHeld(int btnid, int njoybuttons, Uint8* joybuttons, Uint32 hat)
void UpdateWindowTitle(void* data)
{
+ if (EmuStatus == 0) return;
uiWindowSetTitle(MainWindow, (const char*)data);
}
@@ -880,6 +904,10 @@ int EmuThreadFunc(void* burp)
u32 lasttick = starttick;
u32 lastmeasuretick = lasttick;
u32 fpslimitcount = 0;
+ u64 perfcount = SDL_GetPerformanceCounter();
+ u64 perffreq = SDL_GetPerformanceFrequency();
+ float samplesleft = 0;
+ u32 nsamples = 0;
char melontitle[100];
while (EmuRunning != 0)
@@ -959,43 +987,31 @@ int EmuThreadFunc(void* burp)
}
uiAreaQueueRedrawAll(MainDrawArea);
- // framerate limiter based off SDL2_gfx
- float framerate = (1000.0f * nlines) / (60.0f * 263.0f);
-
- /*fpslimitcount++;
- u32 curtick = SDL_GetTicks();
- u32 delay = curtick - lasttick;
- lasttick = curtick;
-
bool limitfps = Config::LimitFPS && !HotkeyDown(HK_FastForward);
+ bool vsync = Config::ScreenVSync && Screen_UseGL;
+ SPU::Sync(limitfps || vsync);
- u32 wantedtick = starttick + (u32)((float)fpslimitcount * framerate);
- if (curtick < wantedtick && limitfps)
- {
- SDL_Delay(wantedtick - curtick);
- }
- else
- {
- fpslimitcount = 0;
- starttick = curtick;
- }*/
+ float framerate = (1000.0f * nlines) / (60.0f * 263.0f);
- fpslimitcount++;
- if (fpslimitcount >= 3)
{
u32 curtick = SDL_GetTicks();
u32 delay = curtick - lasttick;
- bool limitfps = Config::LimitFPS && !HotkeyDown(HK_FastForward);
-
- u32 wantedtick = lasttick + (u32)((float)fpslimitcount * framerate);
- if (curtick < wantedtick && limitfps)
+ if (limitfps)
{
- SDL_Delay(wantedtick - curtick);
+ float wantedtickF = starttick + (framerate * (fpslimitcount+1));
+ u32 wantedtick = (u32)ceil(wantedtickF);
+ if (curtick < wantedtick) SDL_Delay(wantedtick - curtick);
+
+ lasttick = SDL_GetTicks();
+ fpslimitcount++;
+ if ((abs(wantedtickF - (float)wantedtick) < 0.001312) || (fpslimitcount > 60))
+ {
+ fpslimitcount = 0;
+ nsamples = 0;
+ starttick = lasttick;
+ }
}
-
- lasttick = SDL_GetTicks();
- fpslimitcount = 0;
}
nframes++;
@@ -1517,6 +1533,8 @@ void Run()
EmuRunning = 1;
RunningSomething = true;
+ SPU::InitOutput();
+ AudioSampleFrac = 0;
SDL_PauseAudioDevice(AudioDevice, 0);
SDL_PauseAudioDevice(MicDevice, 0);
@@ -1555,6 +1573,7 @@ void TogglePause(void* blarg)
EmuRunning = 2;
uiMenuItemSetChecked(MenuItem_Pause, 1);
+ SPU::DrainOutput();
SDL_PauseAudioDevice(AudioDevice, 1);
SDL_PauseAudioDevice(MicDevice, 1);
@@ -1566,6 +1585,8 @@ void TogglePause(void* blarg)
EmuRunning = 1;
uiMenuItemSetChecked(MenuItem_Pause, 0);
+ SPU::InitOutput();
+ AudioSampleFrac = 0;
SDL_PauseAudioDevice(AudioDevice, 0);
SDL_PauseAudioDevice(MicDevice, 0);
@@ -1616,6 +1637,7 @@ void Stop(bool internal)
uiAreaQueueRedrawAll(MainDrawArea);
+ SPU::DrainOutput();
SDL_PauseAudioDevice(AudioDevice, 1);
SDL_PauseAudioDevice(MicDevice, 1);
@@ -2239,6 +2261,19 @@ void ApplyNewSettings(int type)
GPU3D::InitRenderer(Screen_UseGL);
if (Screen_UseGL) uiGLMakeContextCurrent(NULL);
}
+ else if (type == 4) // vsync
+ {
+ if (Screen_UseGL)
+ {
+ uiGLMakeContextCurrent(GLContext);
+ uiGLSetVSync(Config::ScreenVSync);
+ uiGLMakeContextCurrent(NULL);
+ }
+ else
+ {
+ // TODO eventually: VSync for non-GL screen?
+ }
+ }
EmuRunning = prevstatus;
}
@@ -2448,7 +2483,7 @@ void CreateMainWindow(bool opengl)
if (opengl_good)
{
uiGLMakeContextCurrent(GLContext);
- uiGLSetVSync(0); // TODO: make configurable?
+ uiGLSetVSync(Config::ScreenVSync);
if (!GLScreen_Init()) opengl_good = false;
if (opengl_good)
{
@@ -2649,20 +2684,23 @@ int main(int argc, char** argv)
uiMenuItemSetChecked(MenuItem_LimitFPS, Config::LimitFPS==1);
uiMenuItemSetChecked(MenuItem_ShowOSD, Config::ShowOSD==1);
+ AudioFreq = 48000; // TODO: make configurable?
SDL_AudioSpec whatIwant, whatIget;
memset(&whatIwant, 0, sizeof(SDL_AudioSpec));
- whatIwant.freq = 47340;
+ whatIwant.freq = AudioFreq;
whatIwant.format = AUDIO_S16LSB;
whatIwant.channels = 2;
whatIwant.samples = 1024;
whatIwant.callback = AudioCallback;
- AudioDevice = SDL_OpenAudioDevice(NULL, 0, &whatIwant, &whatIget, 0);
+ AudioDevice = SDL_OpenAudioDevice(NULL, 0, &whatIwant, &whatIget, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
if (!AudioDevice)
{
printf("Audio init failed: %s\n", SDL_GetError());
}
else
{
+ AudioFreq = whatIget.freq;
+ printf("Audio output frequency: %d Hz\n", AudioFreq);
SDL_PauseAudioDevice(AudioDevice, 1);
}