diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/GPU2D.cpp | 18 | ||||
-rw-r--r-- | src/SPU.cpp | 64 | ||||
-rw-r--r-- | src/SPU.h | 3 | ||||
-rw-r--r-- | src/libui_sdl/DlgVideoSettings.cpp | 26 | ||||
-rw-r--r-- | src/libui_sdl/PlatformConfig.cpp | 2 | ||||
-rw-r--r-- | src/libui_sdl/PlatformConfig.h | 1 | ||||
-rw-r--r-- | src/libui_sdl/main.cpp | 124 |
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; @@ -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); } |