aboutsummaryrefslogtreecommitdiff
path: root/src/libui_sdl
diff options
context:
space:
mode:
Diffstat (limited to 'src/libui_sdl')
-rw-r--r--src/libui_sdl/CMakeLists.txt12
-rw-r--r--src/libui_sdl/DlgInputConfig.cpp37
-rw-r--r--src/libui_sdl/DlgVideoSettings.cpp32
-rw-r--r--src/libui_sdl/PlatformConfig.cpp6
-rw-r--r--src/libui_sdl/PlatformConfig.h2
-rw-r--r--src/libui_sdl/libui/ui.h1
-rw-r--r--src/libui_sdl/libui/unix/gl.c5
-rw-r--r--src/libui_sdl/libui/windows/CMakeLists.txt2
-rw-r--r--src/libui_sdl/libui/windows/gl.cpp35
-rw-r--r--src/libui_sdl/libui/windows/window.cpp2
-rw-r--r--src/libui_sdl/main.cpp242
11 files changed, 298 insertions, 78 deletions
diff --git a/src/libui_sdl/CMakeLists.txt b/src/libui_sdl/CMakeLists.txt
index 63e9f48..64206bf 100644
--- a/src/libui_sdl/CMakeLists.txt
+++ b/src/libui_sdl/CMakeLists.txt
@@ -14,6 +14,10 @@ SET(SOURCES_LIBUI
OSD.cpp
)
+if (WIN32)
+ set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> -i <SOURCE> -o <OBJECT>")
+endif()
+
option(BUILD_SHARED_LIBS "Whether to build libui as a shared library or a static library" ON)
set(BUILD_SHARED_LIBS OFF)
add_subdirectory(libui)
@@ -39,11 +43,11 @@ if (UNIX)
ADD_DEFINITIONS(${GTK3_CFLAGS_OTHER})
add_custom_command(OUTPUT melon_grc.c
- COMMAND glib-compile-resources --sourcedir="${CMAKE_SOURCE_DIR}"
- --target="${CMAKE_CURRENT_BINARY_DIR}/melon_grc.c"
+ COMMAND glib-compile-resources --sourcedir=${CMAKE_SOURCE_DIR}
+ --target=${CMAKE_CURRENT_BINARY_DIR}/melon_grc.c
--generate-source "${CMAKE_SOURCE_DIR}/melon_grc.xml"
- COMMAND glib-compile-resources --sourcedir="${CMAKE_SOURCE_DIR}"
- --target="${CMAKE_CURRENT_BINARY_DIR}/melon_grc.h"
+ COMMAND glib-compile-resources --sourcedir=${CMAKE_SOURCE_DIR}
+ --target=${CMAKE_CURRENT_BINARY_DIR}/melon_grc.h
--generate-header "${CMAKE_SOURCE_DIR}/melon_grc.xml")
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
diff --git a/src/libui_sdl/DlgInputConfig.cpp b/src/libui_sdl/DlgInputConfig.cpp
index 8882275..a80e2ec 100644
--- a/src/libui_sdl/DlgInputConfig.cpp
+++ b/src/libui_sdl/DlgInputConfig.cpp
@@ -125,21 +125,30 @@ void JoyMappingName(int id, char* str)
return;
}
- if (id & 0x100)
+ bool hasbtn = ((id & 0xFFFF) != 0xFFFF);
+
+ if (hasbtn)
{
- int hatnum = ((id >> 4) & 0xF) + 1;
+ if (id & 0x100)
+ {
+ int hatnum = ((id >> 4) & 0xF) + 1;
- switch (id & 0xF)
+ switch (id & 0xF)
+ {
+ case 0x1: sprintf(str, "Hat %d up", hatnum); break;
+ case 0x2: sprintf(str, "Hat %d right", hatnum); break;
+ case 0x4: sprintf(str, "Hat %d down", hatnum); break;
+ case 0x8: sprintf(str, "Hat %d left", hatnum); break;
+ }
+ }
+ else
{
- case 0x1: sprintf(str, "Hat %d up", hatnum); break;
- case 0x2: sprintf(str, "Hat %d right", hatnum); break;
- case 0x4: sprintf(str, "Hat %d down", hatnum); break;
- case 0x8: sprintf(str, "Hat %d left", hatnum); break;
+ sprintf(str, "Button %d", (id & 0xFFFF) + 1);
}
}
else
{
- sprintf(str, "Button %d", (id & 0xFFFF) + 1);
+ strcpy(str, "");
}
if (id & 0x10000)
@@ -151,9 +160,9 @@ void JoyMappingName(int id, char* str)
switch ((id >> 20) & 0xF)
{
- case 0: sprintf(str, "%s / Axis %d +", tmp, axisnum); break;
- case 1: sprintf(str, "%s / Axis %d -", tmp, axisnum); break;
- case 2: sprintf(str, "%s / Trigger %d", tmp, axisnum); break;
+ case 0: sprintf(str, "%s%sAxis %d +", tmp, hasbtn?" / ":"", axisnum); break;
+ case 1: sprintf(str, "%s%sAxis %d -", tmp, hasbtn?" / ":"", axisnum); break;
+ case 2: sprintf(str, "%s%sTrigger %d", tmp, hasbtn?" / ":"", axisnum); break;
}
}
}
@@ -223,10 +232,12 @@ int OnAreaKeyEvent(uiAreaHandler* handler, uiArea* area, uiAreaKeyEvent* evt)
// set key.
if (evt->Scancode != 0x1 || evt->Modifiers != 0) // ESC
{
+ int mod = (dlg->type == 0) ? 0 : evt->Modifiers;
+
if (evt->Scancode == 0xE && evt->Modifiers == 0) // backspace
dlg->keymap[dlg->pollid] = -1;
else
- dlg->keymap[dlg->pollid] = evt->Scancode | (evt->Modifiers << 16);
+ dlg->keymap[dlg->pollid] = evt->Scancode | (mod << 16);
}
char keyname[64];
@@ -287,7 +298,7 @@ Uint32 JoyPoll(Uint32 interval, void* param)
}
int oldmap;
- if (dlg->joymap[id] == -1) oldmap = 0;
+ if (dlg->joymap[id] == -1) oldmap = 0xFFFF;
else oldmap = dlg->joymap[id];
int nbuttons = SDL_JoystickNumButtons(joy);
diff --git a/src/libui_sdl/DlgVideoSettings.cpp b/src/libui_sdl/DlgVideoSettings.cpp
index 7d876e2..ff88ba8 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;
@@ -130,21 +137,33 @@ void OnRendererChanged(uiRadioButtons* rb, void* blarg)
UpdateControls();
bool new_usegl = (Config::ScreenUseGL != 0) || (Config::_3DRenderer != 0);
+
+ if (new_usegl) uiControlEnable(uiControl(cbVSync));
+ else uiControlDisable(uiControl(cbVSync));
+
if (new_usegl != old_usegl)
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 +251,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 +323,24 @@ 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 || Config::_3DRenderer != 0)
+ 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..c8ec19f 100644
--- a/src/libui_sdl/PlatformConfig.cpp
+++ b/src/libui_sdl/PlatformConfig.cpp
@@ -43,9 +43,11 @@ int ScreenSizing;
int ScreenFilter;
int ScreenUseGL;
+int ScreenVSync;
int ScreenRatio;
int LimitFPS;
+int AudioSync;
int ShowOSD;
int DirectBoot;
@@ -118,9 +120,11 @@ 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},
+ {"LimitFPS", 0, &LimitFPS, 0, NULL, 0},
+ {"AudioSync", 0, &AudioSync, 1, NULL, 0},
{"ShowOSD", 0, &ShowOSD, 1, NULL, 0},
{"DirectBoot", 0, &DirectBoot, 1, NULL, 0},
diff --git a/src/libui_sdl/PlatformConfig.h b/src/libui_sdl/PlatformConfig.h
index 2c59e5d..842e72a 100644
--- a/src/libui_sdl/PlatformConfig.h
+++ b/src/libui_sdl/PlatformConfig.h
@@ -54,9 +54,11 @@ extern int ScreenSizing;
extern int ScreenFilter;
extern int ScreenUseGL;
+extern int ScreenVSync;
extern int ScreenRatio;
extern int LimitFPS;
+extern int AudioSync;
extern int ShowOSD;
extern int DirectBoot;
diff --git a/src/libui_sdl/libui/ui.h b/src/libui_sdl/libui/ui.h
index e15c127..03aef5d 100644
--- a/src/libui_sdl/libui/ui.h
+++ b/src/libui_sdl/libui/ui.h
@@ -620,6 +620,7 @@ _UI_EXTERN void *uiGLGetProcAddress(const char* proc);
_UI_EXTERN int uiGLGetFramebuffer(uiGLContext* ctx);
_UI_EXTERN float uiGLGetFramebufferScale(uiGLContext* ctx);
_UI_EXTERN void uiGLSwapBuffers(uiGLContext* ctx);
+_UI_EXTERN void uiGLSetVSync(int sync);
_UI_ENUM(uiModifiers) {
diff --git a/src/libui_sdl/libui/unix/gl.c b/src/libui_sdl/libui/unix/gl.c
index e1665ee..e15cf4f 100644
--- a/src/libui_sdl/libui/unix/gl.c
+++ b/src/libui_sdl/libui/unix/gl.c
@@ -193,6 +193,11 @@ void uiGLSwapBuffers(uiGLContext* ctx)
ctx->backbuffer = ctx->backbuffer ? 0 : 1;
}
+void uiGLSetVSync(int sync)
+{
+ // TODO
+}
+
void uiGLMakeContextCurrent(uiGLContext* ctx)
{
if (!ctx)
diff --git a/src/libui_sdl/libui/windows/CMakeLists.txt b/src/libui_sdl/libui/windows/CMakeLists.txt
index 9d5313a..24d4ad9 100644
--- a/src/libui_sdl/libui/windows/CMakeLists.txt
+++ b/src/libui_sdl/libui/windows/CMakeLists.txt
@@ -73,7 +73,7 @@ macro(_handle_static)
add_custom_command(
TARGET libui POST_BUILD
COMMAND
- ${CMAKE_COMMAND} -E copy $<TARGET_PROPERTY:libui,BINARY_DIR>/CMakeFiles/libui.dir/windows/resources.rc.* ${_LIBUI_STATIC_RES}
+ ${CMAKE_COMMAND} -E copy $<TARGET_PROPERTY:libui,BINARY_DIR>/CMakeFiles/libui.dir/windows/resources.rc.obj ${_LIBUI_STATIC_RES}
COMMENT "Copying libui.res")
endmacro()
diff --git a/src/libui_sdl/libui/windows/gl.cpp b/src/libui_sdl/libui/windows/gl.cpp
index c621721..07ef19b 100644
--- a/src/libui_sdl/libui/windows/gl.cpp
+++ b/src/libui_sdl/libui/windows/gl.cpp
@@ -3,6 +3,7 @@
#include "area.hpp"
#include <GL/gl.h>
+#include <GL/glext.h>
#include <GL/wglext.h>
struct uiGLContext
@@ -159,3 +160,37 @@ float uiGLGetFramebufferScale(uiGLContext* ctx)
// TODO
return 1;
}
+
+void uiGLSetVSync(int sync)
+{
+ static PFNWGLSWAPINTERVALEXTPROC _wglSwapIntervalEXT = NULL;
+ static bool symloaded = false;
+
+ if (!symloaded)
+ {
+ PFNGLGETSTRINGIPROC _glGetStringi = (PFNGLGETSTRINGIPROC)wglGetProcAddress("glGetStringi");
+ if (_glGetStringi == NULL) return;
+
+ GLint numext;
+ glGetIntegerv(GL_NUM_EXTENSIONS, &numext);
+
+ bool hasswapctrl = false;
+ for (GLint i = 0; i < numext; i++)
+ {
+ const char* ext = (const char*)_glGetStringi(GL_EXTENSIONS, i);
+ if (!stricmp(ext, "WGL_EXT_swap_control"))
+ {
+ hasswapctrl = true;
+ break;
+ }
+ }
+
+ if (hasswapctrl)
+ _wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
+
+ symloaded = true;
+ }
+
+ if (_wglSwapIntervalEXT)
+ _wglSwapIntervalEXT(sync);
+}
diff --git a/src/libui_sdl/libui/windows/window.cpp b/src/libui_sdl/libui/windows/window.cpp
index 18d1171..a8f7f23 100644
--- a/src/libui_sdl/libui/windows/window.cpp
+++ b/src/libui_sdl/libui/windows/window.cpp
@@ -95,7 +95,7 @@ static LRESULT CALLBACK windowWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARA
// not a menu
if (lParam != 0)
break;
- if (HIWORD(wParam) != 0)
+ if (HIWORD(wParam) != 0 || LOWORD(wParam) <= IDCANCEL)
break;
runMenuEvent(LOWORD(wParam), uiWindow(w));
return 0;
diff --git a/src/libui_sdl/main.cpp b/src/libui_sdl/main.cpp
index 34e838c..d3f9024 100644
--- a/src/libui_sdl/main.cpp
+++ b/src/libui_sdl/main.cpp
@@ -93,6 +93,7 @@ uiMenuItem* MenuItem_ScreenSizing[4];
uiMenuItem* MenuItem_ScreenFilter;
uiMenuItem* MenuItem_LimitFPS;
+uiMenuItem* MenuItem_AudioSync;
uiMenuItem* MenuItem_ShowOSD;
SDL_Thread* EmuThread;
@@ -129,6 +130,8 @@ bool GL_ScreenSizeDirty;
int GL_3DScale;
+bool GL_VSyncStatus;
+
int ScreenGap = 0;
int ScreenLayout = 0;
int ScreenSizing = 0;
@@ -158,8 +161,13 @@ bool LidStatus;
int JoystickID;
SDL_Joystick* Joystick;
+int AudioFreq;
+float AudioSampleFrac;
SDL_AudioDeviceID AudioDevice, MicDevice;
+SDL_cond* AudioSync;
+SDL_mutex* AudioSyncLock;
+
u32 MicBufferLength = 2048;
s16 MicBuffer[2048];
u32 MicBufferReadPos, MicBufferWritePos;
@@ -236,6 +244,8 @@ bool GLScreen_InitOSDShader(GLuint* shader)
bool GLScreen_Init()
{
+ GL_VSyncStatus = Config::ScreenVSync;
+
// TODO: consider using epoxy?
if (!OpenGL_Init())
return false;
@@ -298,6 +308,13 @@ void GLScreen_DeInit()
void GLScreen_DrawScreen()
{
+ bool vsync = Config::ScreenVSync && !HotkeyDown(HK_FastForward);
+ if (vsync != GL_VSyncStatus)
+ {
+ GL_VSyncStatus = vsync;
+ uiGLSetVSync(vsync);
+ }
+
float scale = uiGLGetFramebufferScale(GLContext);
glBindFramebuffer(GL_FRAMEBUFFER, uiGLGetFramebuffer(GLContext));
@@ -560,26 +577,42 @@ 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);
+
+ // resample incoming audio to match the output sample rate
- s16 buf_in[710*2];
+ 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;
+ int num_in;
+ int num_out = len;
+
+ SDL_LockMutex(AudioSyncLock);
+ num_in = SPU::ReadOutput(buf_in, len_in);
+ SDL_CondSignal(AudioSync);
+ SDL_UnlockMutex(AudioSyncLock);
+
+ 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 +621,22 @@ void AudioCallback(void* data, Uint8* stream, int len)
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)
{
@@ -710,26 +753,31 @@ bool JoystickButtonDown(int val)
{
if (val == -1) return false;
- if (val & 0x100)
+ bool hasbtn = ((val & 0xFFFF) != 0xFFFF);
+
+ if (hasbtn)
{
- int hatnum = (val >> 4) & 0xF;
- int hatdir = val & 0xF;
- Uint8 hatval = SDL_JoystickGetHat(Joystick, hatnum);
+ if (val & 0x100)
+ {
+ int hatnum = (val >> 4) & 0xF;
+ int hatdir = val & 0xF;
+ Uint8 hatval = SDL_JoystickGetHat(Joystick, hatnum);
- bool pressed = false;
- if (hatdir == 0x1) pressed = (hatval & SDL_HAT_UP);
- else if (hatdir == 0x4) pressed = (hatval & SDL_HAT_DOWN);
- else if (hatdir == 0x2) pressed = (hatval & SDL_HAT_RIGHT);
- else if (hatdir == 0x8) pressed = (hatval & SDL_HAT_LEFT);
+ bool pressed = false;
+ if (hatdir == 0x1) pressed = (hatval & SDL_HAT_UP);
+ else if (hatdir == 0x4) pressed = (hatval & SDL_HAT_DOWN);
+ else if (hatdir == 0x2) pressed = (hatval & SDL_HAT_RIGHT);
+ else if (hatdir == 0x8) pressed = (hatval & SDL_HAT_LEFT);
- if (pressed) return true;
- }
- else
- {
- int btnnum = val & 0xFFFF;
- Uint8 btnval = SDL_JoystickGetButton(Joystick, btnnum);
+ if (pressed) return true;
+ }
+ else
+ {
+ int btnnum = val & 0xFFFF;
+ Uint8 btnval = SDL_JoystickGetButton(Joystick, btnnum);
- if (btnval) return true;
+ if (btnval) return true;
+ }
}
if (val & 0x10000)
@@ -833,6 +881,7 @@ bool JoyButtonHeld(int btnid, int njoybuttons, Uint8* joybuttons, Uint32 hat)
void UpdateWindowTitle(void* data)
{
+ if (EmuStatus == 0) return;
uiWindowSetTitle(MainWindow, (const char*)data);
}
@@ -875,6 +924,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)
@@ -886,6 +939,7 @@ int EmuThreadFunc(void* burp)
Config::LimitFPS = !Config::LimitFPS;
uiQueueMain(UpdateFPSLimit, NULL);
}
+ // TODO: similar hotkeys for video/audio sync?
if (HotkeyPressed(HK_Pause)) uiQueueMain(TogglePause, NULL);
if (HotkeyPressed(HK_Reset)) uiQueueMain(Reset, NULL);
@@ -954,25 +1008,46 @@ 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 fastforward = HotkeyDown(HK_FastForward);
- bool limitfps = Config::LimitFPS && !HotkeyDown(HK_FastForward);
-
- u32 wantedtick = starttick + (u32)((float)fpslimitcount * framerate);
- if (curtick < wantedtick && limitfps)
+ if (Config::AudioSync && !fastforward)
{
- SDL_Delay(wantedtick - curtick);
+ SDL_LockMutex(AudioSyncLock);
+ while (SPU::GetOutputSize() > 1024)
+ {
+ int ret = SDL_CondWaitTimeout(AudioSync, AudioSyncLock, 500);
+ if (ret == SDL_MUTEX_TIMEDOUT) break;
+ }
+ SDL_UnlockMutex(AudioSyncLock);
}
else
{
- fpslimitcount = 0;
- starttick = curtick;
+ // ensure the audio FIFO doesn't overflow
+ //SPU::TrimOutput();
+ }
+
+ float framerate = (1000.0f * nlines) / (60.0f * 263.0f);
+
+ {
+ u32 curtick = SDL_GetTicks();
+ u32 delay = curtick - lasttick;
+
+ bool limitfps = Config::LimitFPS && !fastforward;
+ if (limitfps)
+ {
+ 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;
+ }
+ }
}
nframes++;
@@ -1044,6 +1119,12 @@ int EmuThreadFunc(void* burp)
return 44203;
}
+void StopEmuThread()
+{
+ EmuRunning = 0;
+ SDL_WaitThread(EmuThread, NULL);
+}
+
void OnAreaDraw(uiAreaHandler* handler, uiArea* area, uiAreaDrawParams* params)
{
@@ -1155,13 +1236,13 @@ void OnAreaDragBroken(uiAreaHandler* handler, uiArea* area)
{
}
-bool EventMatchesKey(uiAreaKeyEvent* evt, int val)
+bool EventMatchesKey(uiAreaKeyEvent* evt, int val, bool checkmod)
{
if (val == -1) return false;
int key = val & 0xFFFF;
int mod = val >> 16;
- return evt->Scancode == key && evt->Modifiers == mod;
+ return evt->Scancode == key && (!checkmod || evt->Modifiers == mod);
}
int OnAreaKeyEvent(uiAreaHandler* handler, uiArea* area, uiAreaKeyEvent* evt)
@@ -1175,11 +1256,11 @@ int OnAreaKeyEvent(uiAreaHandler* handler, uiArea* area, uiAreaKeyEvent* evt)
if (evt->Up)
{
for (int i = 0; i < 12; i++)
- if (EventMatchesKey(evt, Config::KeyMapping[i]))
+ if (EventMatchesKey(evt, Config::KeyMapping[i], false))
KeyInputMask |= (1<<i);
for (int i = 0; i < HK_MAX; i++)
- if (EventMatchesKey(evt, Config::HKKeyMapping[i]))
+ if (EventMatchesKey(evt, Config::HKKeyMapping[i], true))
KeyHotkeyMask &= ~(1<<i);
}
else if (!evt->Repeat)
@@ -1202,16 +1283,16 @@ int OnAreaKeyEvent(uiAreaHandler* handler, uiArea* area, uiAreaKeyEvent* evt)
}
for (int i = 0; i < 12; i++)
- if (EventMatchesKey(evt, Config::KeyMapping[i]))
+ if (EventMatchesKey(evt, Config::KeyMapping[i], false))
KeyInputMask &= ~(1<<i);
for (int i = 0; i < HK_MAX; i++)
- if (EventMatchesKey(evt, Config::HKKeyMapping[i]))
+ if (EventMatchesKey(evt, Config::HKKeyMapping[i], true))
KeyHotkeyMask |= (1<<i);
// REMOVE ME
- if (evt->Scancode == 0x57) // F11
- NDS::debug(0);
+ //if (evt->Scancode == 0x57) // F11
+ // NDS::debug(0);
}
return 1;
@@ -1486,6 +1567,8 @@ void Run()
EmuRunning = 1;
RunningSomething = true;
+ SPU::InitOutput();
+ AudioSampleFrac = 0;
SDL_PauseAudioDevice(AudioDevice, 0);
SDL_PauseAudioDevice(MicDevice, 0);
@@ -1524,6 +1607,7 @@ void TogglePause(void* blarg)
EmuRunning = 2;
uiMenuItemSetChecked(MenuItem_Pause, 1);
+ SPU::DrainOutput();
SDL_PauseAudioDevice(AudioDevice, 1);
SDL_PauseAudioDevice(MicDevice, 1);
@@ -1535,6 +1619,8 @@ void TogglePause(void* blarg)
EmuRunning = 1;
uiMenuItemSetChecked(MenuItem_Pause, 0);
+ SPU::InitOutput();
+ AudioSampleFrac = 0;
SDL_PauseAudioDevice(AudioDevice, 0);
SDL_PauseAudioDevice(MicDevice, 0);
@@ -1585,6 +1671,7 @@ void Stop(bool internal)
uiAreaQueueRedrawAll(MainDrawArea);
+ SPU::DrainOutput();
SDL_PauseAudioDevice(AudioDevice, 1);
SDL_PauseAudioDevice(MicDevice, 1);
@@ -1849,6 +1936,7 @@ int OnCloseWindow(uiWindow* window, void* blarg)
while (EmuStatus != 3);
CloseAllDialogs();
+ StopEmuThread();
uiQuit();
return 1;
}
@@ -1886,6 +1974,7 @@ void OnCloseByMenu(uiMenuItem* item, uiWindow* window, void* blarg)
while (EmuStatus != 3);
CloseAllDialogs();
+ StopEmuThread();
DestroyMainWindow();
uiQuit();
}
@@ -2143,6 +2232,13 @@ void OnSetLimitFPS(uiMenuItem* item, uiWindow* window, void* blarg)
else Config::LimitFPS = false;
}
+void OnSetAudioSync(uiMenuItem* item, uiWindow* window, void* blarg)
+{
+ int chk = uiMenuItemChecked(item);
+ if (chk != 0) Config::AudioSync = true;
+ else Config::AudioSync = false;
+}
+
void OnSetShowOSD(uiMenuItem* item, uiWindow* window, void* blarg)
{
int chk = uiMenuItemChecked(item);
@@ -2206,6 +2302,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;
}
@@ -2374,11 +2483,16 @@ void CreateMainWindowMenu()
MenuItem_ScreenFilter = uiMenuAppendCheckItem(menu, "Screen filtering");
uiMenuItemOnClicked(MenuItem_ScreenFilter, OnSetScreenFiltering, NULL);
+ MenuItem_ShowOSD = uiMenuAppendCheckItem(menu, "Show OSD");
+ uiMenuItemOnClicked(MenuItem_ShowOSD, OnSetShowOSD, NULL);
+
+ uiMenuAppendSeparator(menu);
+
MenuItem_LimitFPS = uiMenuAppendCheckItem(menu, "Limit framerate");
uiMenuItemOnClicked(MenuItem_LimitFPS, OnSetLimitFPS, NULL);
- MenuItem_ShowOSD = uiMenuAppendCheckItem(menu, "Show OSD");
- uiMenuItemOnClicked(MenuItem_ShowOSD, OnSetShowOSD, NULL);
+ MenuItem_AudioSync = uiMenuAppendCheckItem(menu, "Audio sync");
+ uiMenuItemOnClicked(MenuItem_AudioSync, OnSetAudioSync, NULL);
}
void CreateMainWindow(bool opengl)
@@ -2415,6 +2529,7 @@ void CreateMainWindow(bool opengl)
if (opengl_good)
{
uiGLMakeContextCurrent(GLContext);
+ uiGLSetVSync(Config::ScreenVSync);
if (!GLScreen_Init()) opengl_good = false;
if (opengl_good)
{
@@ -2539,7 +2654,6 @@ int main(int argc, char** argv)
SDL_Quit();
return 0;
}
-
{
FILE* f = Platform::OpenLocalFile("romlist.bin", "rb");
if (f)
@@ -2556,6 +2670,13 @@ int main(int argc, char** argv)
"You should use the latest version of romlist.bin (provided in melonDS release packages).");
}
}
+ else
+ {
+ uiMsgBoxError(NULL,
+ "romlist.bin not found.",
+ "Save memory type detection will not work correctly.\n\n"
+ "You should use the latest version of romlist.bin (provided in melonDS release packages).");
+ }
}
CreateMainWindowMenu();
@@ -2613,22 +2734,29 @@ int main(int argc, char** argv)
uiMenuItemSetChecked(MenuItem_ScreenFilter, Config::ScreenFilter==1);
uiMenuItemSetChecked(MenuItem_LimitFPS, Config::LimitFPS==1);
+ uiMenuItemSetChecked(MenuItem_AudioSync, Config::AudioSync==1);
uiMenuItemSetChecked(MenuItem_ShowOSD, Config::ShowOSD==1);
+ AudioSync = SDL_CreateCond();
+ AudioSyncLock = SDL_CreateMutex();
+
+ 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);
}
@@ -2683,13 +2811,13 @@ int main(int argc, char** argv)
uiMain();
- EmuRunning = 0;
- SDL_WaitThread(EmuThread, NULL);
-
if (Joystick) SDL_JoystickClose(Joystick);
if (AudioDevice) SDL_CloseAudioDevice(AudioDevice);
if (MicDevice) SDL_CloseAudioDevice(MicDevice);
+ SDL_DestroyCond(AudioSync);
+ SDL_DestroyMutex(AudioSyncLock);
+
if (MicWavBuffer) delete[] MicWavBuffer;
if (ScreenBitmap[0]) uiDrawFreeBitmap(ScreenBitmap[0]);