From f27fb5801fcee0135c6bf6524c071efea99d5d9a Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Fri, 28 Oct 2011 20:26:40 +0300 Subject: [PATCH] Split platform sound and graphics parts This is in preparation for supporting sound-only APIs like portaudio, OpenAL and such. --- Makefile | 2 +- SDL/sound-sdl.cpp | 181 +++++++++++++++++++++++++++++++++++++++++ SDL/window-sdl.cpp | 150 +--------------------------------- dummy/sound-dummy.cpp | 9 ++ dummy/window-dummy.cpp | 10 +-- generic/window.cpp | 12 +++ generic/window.hpp | 8 ++ 7 files changed, 216 insertions(+), 156 deletions(-) create mode 100644 SDL/sound-sdl.cpp create mode 100644 dummy/sound-dummy.cpp diff --git a/Makefile b/Makefile index e448797e..4d31c39d 100644 --- a/Makefile +++ b/Makefile @@ -72,7 +72,7 @@ lsnes.$(OBJECT_SUFFIX): endif -%.$(EXECUTABLE_SUFFIX): %.$(OBJECT_SUFFIX) $(OBJECTS) dummy/window-dummy.$(OBJECT_SUFFIX) +%.$(EXECUTABLE_SUFFIX): %.$(OBJECT_SUFFIX) $(OBJECTS) $(patsubst %.cpp,%.$(OBJECT_SUFFIX),$(wildcard dummy/*.cpp)) $(CC) -o $@ $^ $(BSNES_PATH)/out/libsnes.$(ARCHIVE_SUFFIX) $(LDFLAGS) %.$(OBJECT_SUFFIX): %.cpp diff --git a/SDL/sound-sdl.cpp b/SDL/sound-sdl.cpp new file mode 100644 index 00000000..5d729b2f --- /dev/null +++ b/SDL/sound-sdl.cpp @@ -0,0 +1,181 @@ +#include "window.hpp" +#include "render.hpp" +#include "command.hpp" +#include "framerate.hpp" +#include "misc.hpp" +#include "lsnes.hpp" +#include "settings.hpp" +#include +#include +#include +#include "keymapper.hpp" +#include "framerate.hpp" +#include +#include +#include + +#define WATCHDOG_TIMEOUT 15 +#define MAXMESSAGES 6 +#define MSGHISTORY 1000 +#define MAXHISTORY 1000 + +#include +#include +#include +#include + +namespace +{ + uint32_t audio_playback_freq = 0; + const size_t audiobuf_size = 8192; + uint16_t audiobuf[audiobuf_size]; + volatile size_t audiobuf_get = 0; + volatile size_t audiobuf_put = 0; + uint64_t sampledup_ctr = 0; + uint64_t sampledup_inc = 0; + uint64_t sampledup_mod = 1; + Uint16 format = AUDIO_S16SYS; + bool stereo = true; + bool sound_enabled = true; + + void calculate_sampledup(uint32_t rate_n, uint32_t rate_d) + { + if(!audio_playback_freq) { + //Sound disabled. + sampledup_ctr = 0; + sampledup_inc = 0; + sampledup_mod = 0; + } else { + sampledup_ctr = 0; + sampledup_inc = rate_n; + sampledup_mod = rate_d * audio_playback_freq + rate_n; + } + } + + function_ptr_command enable_sound("enable-sound", "Enable/Disable sound", + "Syntax: enable-sound \nEnable or disable sound.\n", + [](const std::string& args) throw(std::bad_alloc, std::runtime_error) { + std::string s = args; + if(s == "on" || s == "true" || s == "1" || s == "enable" || s == "enabled") + window::sound_enable(true); + else if(s == "off" || s == "false" || s == "0" || s == "disable" || s == "disabled") + window::sound_enable(false); + else + throw std::runtime_error("Bad sound setting"); + }); + + void audiocb(void* dummy, Uint8* stream, int len) + { + static uint16_t lprev = 32768; + static uint16_t rprev = 32768; + if(!sound_enabled) + lprev = rprev = 32768; + uint16_t bias = (format == AUDIO_S8 || format == AUDIO_S16LSB || format == AUDIO_S16MSB || format == + AUDIO_S16SYS) ? 32768 : 0; + while(len > 0) { + uint16_t l, r; + if(audiobuf_get == audiobuf_put) { + l = lprev; + r = rprev; + } else { + l = lprev = audiobuf[audiobuf_get++]; + r = rprev = audiobuf[audiobuf_get++]; + if(audiobuf_get == audiobuf_size) + audiobuf_get = 0; + } + if(!stereo) + l = l / 2 + r / 2; + if(format == AUDIO_U8 || format == AUDIO_S8) { + stream[0] = (l - bias) >> 8; + if(stereo) + stream[1] = (r - bias) >> 8; + stream += (stereo ? 2 : 1); + len -= (stereo ? 2 : 1); + } else if(format == AUDIO_S16SYS || format == AUDIO_U16SYS) { + reinterpret_cast(stream)[0] = (l - bias); + if(stereo) + reinterpret_cast(stream)[1] = (r - bias); + stream += (stereo ? 4 : 2); + len -= (stereo ? 4 : 2); + } else if(format == AUDIO_S16LSB || format == AUDIO_U16LSB) { + stream[0] = (l - bias); + stream[1] = (l - bias) >> 8; + if(stereo) { + stream[2] = (r - bias); + stream[3] = (r - bias) >> 8; + } + stream += (stereo ? 4 : 2); + len -= (stereo ? 4 : 2); + } else if(format == AUDIO_S16MSB || format == AUDIO_U16MSB) { + stream[1] = (l - bias); + stream[0] = (l - bias) >> 8; + if(stereo) { + stream[3] = (r - bias); + stream[2] = (r - bias) >> 8; + } + stream += (stereo ? 4 : 2); + len -= (stereo ? 4 : 2); + } + } + } +} + +void window::sound_enable(bool enable) throw() +{ + sound_enabled = enable; + SDL_PauseAudio(enable ? 0 : 1); +} + +void sound_init() +{ + SDL_AudioSpec* desired = new SDL_AudioSpec(); + SDL_AudioSpec* obtained = new SDL_AudioSpec(); + + desired->freq = 44100; + desired->format = AUDIO_S16SYS; + desired->channels = 2; + desired->samples = 8192; + desired->callback = audiocb; + desired->userdata = NULL; + + if(SDL_OpenAudio(desired, obtained) < 0) { + window::message("Audio can't be initialized, audio playback disabled"); + //Disable audio. + audio_playback_freq = 0; + calculate_sampledup(32000, 1); + return; + } + + //Fill the parameters. + audio_playback_freq = obtained->freq; + calculate_sampledup(32000, 1); + format = obtained->format; + stereo = (obtained->channels == 2); + //GO!!! + SDL_PauseAudio(0); +} + +void sound_quit() +{ + SDL_PauseAudio(1); + SDL_Delay(100); +} + +void window::play_audio_sample(uint16_t left, uint16_t right) throw() +{ + sampledup_ctr += sampledup_inc; + while(sampledup_ctr < sampledup_mod) { + audiobuf[audiobuf_put++] = left; + audiobuf[audiobuf_put++] = right; + if(audiobuf_put == audiobuf_size) + audiobuf_put = 0; + sampledup_ctr += sampledup_inc; + } + sampledup_ctr -= sampledup_mod; +} + +void window::set_sound_rate(uint32_t rate_n, uint32_t rate_d) +{ + uint32_t g = gcd(rate_n, rate_d); + calculate_sampledup(rate_n / g, rate_d / g); +} diff --git a/SDL/window-sdl.cpp b/SDL/window-sdl.cpp index 35c1fade..28dd1784 100644 --- a/SDL/window-sdl.cpp +++ b/SDL/window-sdl.cpp @@ -30,7 +30,6 @@ namespace { - uint32_t audio_playback_freq = 0; bool wait_canceled; SDL_TimerID tid; @@ -507,86 +506,6 @@ void poll_inputs_internal() throw(std::bad_alloc); namespace { - const size_t audiobuf_size = 8192; - uint16_t audiobuf[audiobuf_size]; - volatile size_t audiobuf_get = 0; - volatile size_t audiobuf_put = 0; - uint64_t sampledup_ctr = 0; - uint64_t sampledup_inc = 0; - uint64_t sampledup_mod = 1; - Uint16 format = AUDIO_S16SYS; - bool stereo = true; - bool sound_enabled = true; - - void calculate_sampledup(uint32_t rate_n, uint32_t rate_d) - { - if(!audio_playback_freq) { - //Sound disabled. - sampledup_ctr = 0; - sampledup_inc = 0; - sampledup_mod = 0; - } else { - sampledup_ctr = 0; - sampledup_inc = rate_n; - sampledup_mod = rate_d * audio_playback_freq + rate_n; - } - } - - void audiocb(void* dummy, Uint8* stream, int len) - { - static uint16_t lprev = 32768; - static uint16_t rprev = 32768; - if(!sound_enabled) - lprev = rprev = 32768; - uint16_t bias = (format == AUDIO_S8 || format == AUDIO_S16LSB || format == AUDIO_S16MSB || format == - AUDIO_S16SYS) ? 32768 : 0; - while(len > 0) { - uint16_t l, r; - if(audiobuf_get == audiobuf_put) { - l = lprev; - r = rprev; - } else { - l = lprev = audiobuf[audiobuf_get++]; - r = rprev = audiobuf[audiobuf_get++]; - if(audiobuf_get == audiobuf_size) - audiobuf_get = 0; - } - if(!stereo) - l = l / 2 + r / 2; - if(format == AUDIO_U8 || format == AUDIO_S8) { - stream[0] = (l - bias) >> 8; - if(stereo) - stream[1] = (r - bias) >> 8; - stream += (stereo ? 2 : 1); - len -= (stereo ? 2 : 1); - } else if(format == AUDIO_S16SYS || format == AUDIO_U16SYS) { - reinterpret_cast(stream)[0] = (l - bias); - if(stereo) - reinterpret_cast(stream)[1] = (r - bias); - stream += (stereo ? 4 : 2); - len -= (stereo ? 4 : 2); - } else if(format == AUDIO_S16LSB || format == AUDIO_U16LSB) { - stream[0] = (l - bias); - stream[1] = (l - bias) >> 8; - if(stereo) { - stream[2] = (r - bias); - stream[3] = (r - bias) >> 8; - } - stream += (stereo ? 4 : 2); - len -= (stereo ? 4 : 2); - } else if(format == AUDIO_S16MSB || format == AUDIO_U16MSB) { - stream[1] = (l - bias); - stream[0] = (l - bias) >> 8; - if(stereo) { - stream[3] = (r - bias); - stream[2] = (r - bias) >> 8; - } - stream += (stereo ? 4 : 2); - len -= (stereo ? 4 : 2); - } - } - } - void identify() { state = WINSTATE_IDENTIFY; @@ -1068,7 +987,7 @@ namespace } } -void window::init() +void graphics_init() { SDL_initialized = true; #ifdef SIGALRM @@ -1106,40 +1025,14 @@ void window::init() console_mode = false; maxmessages = MAXMESSAGES; - notify_screen_update(); + window::notify_screen_update(); std::string windowname = "lsnes-" + lsnes_version + "[" + bsnes_core_version + "]"; SDL_WM_SetCaption(windowname.c_str(), "lsnes"); init_joysticks(); - - SDL_AudioSpec* desired = new SDL_AudioSpec(); - SDL_AudioSpec* obtained = new SDL_AudioSpec(); - - desired->freq = 44100; - desired->format = AUDIO_S16SYS; - desired->channels = 2; - desired->samples = 8192; - desired->callback = audiocb; - desired->userdata = NULL; - - if(SDL_OpenAudio(desired, obtained) < 0) { - message("Audio can't be initialized, audio playback disabled"); - //Disable audio. - audio_playback_freq = 0; - calculate_sampledup(32000, 1); - return; - } - - //Fill the parameters. - audio_playback_freq = obtained->freq; - calculate_sampledup(32000, 1); - format = obtained->format; - stereo = (obtained->channels == 2); - //GO!!! - SDL_PauseAudio(0); } -void window::quit() +void graphics_quit() { time_t curtime = time(NULL); struct tm* tm = localtime(&curtime); @@ -1458,26 +1351,8 @@ void window::paused(bool enable) throw() notify_screen_update(); } -void window::sound_enable(bool enable) throw() -{ - sound_enabled = enable; - SDL_PauseAudio(enable ? 0 : 1); -} - namespace { - function_ptr_command enable_sound("enable-sound", "Enable/Disable sound", - "Syntax: enable-sound \nEnable or disable sound.\n", - [](const std::string& args) throw(std::bad_alloc, std::runtime_error) { - std::string s = args; - if(s == "on" || s == "true" || s == "1" || s == "enable" || s == "enabled") - window::sound_enable(true); - else if(s == "off" || s == "false" || s == "0" || s == "disable" || s == "disabled") - window::sound_enable(false); - else - throw std::runtime_error("Bad sound setting"); - }); - function_ptr_command<> identify_key("identify-key", "Identify a key", "Syntax: identify-key\nIdentifies a (pseudo-)key.\n", []() throw(std::bad_alloc, std::runtime_error) { @@ -1593,19 +1468,6 @@ void window::cancel_wait() throw() wait_canceled = true; } -void window::play_audio_sample(uint16_t left, uint16_t right) throw() -{ - sampledup_ctr += sampledup_inc; - while(sampledup_ctr < sampledup_mod) { - audiobuf[audiobuf_put++] = left; - audiobuf[audiobuf_put++] = right; - if(audiobuf_put == audiobuf_size) - audiobuf_put = 0; - sampledup_ctr += sampledup_inc; - } - sampledup_ctr -= sampledup_mod; -} - void window::set_window_compensation(uint32_t xoffset, uint32_t yoffset, uint32_t hscl, uint32_t vscl) { vc_xoffset = xoffset; @@ -1613,9 +1475,3 @@ void window::set_window_compensation(uint32_t xoffset, uint32_t yoffset, uint32_ vc_hscl = hscl; vc_vscl = vscl; } - -void window::set_sound_rate(uint32_t rate_n, uint32_t rate_d) -{ - uint32_t g = gcd(rate_n, rate_d); - calculate_sampledup(rate_n / g, rate_d / g); -} diff --git a/dummy/sound-dummy.cpp b/dummy/sound-dummy.cpp new file mode 100644 index 00000000..bf8ae4de --- /dev/null +++ b/dummy/sound-dummy.cpp @@ -0,0 +1,9 @@ +#include "window.hpp" +#include +#include + +void sound_init() {} +void sound_quit() {} +void window::sound_enable(bool enable) throw() {} +void window::play_audio_sample(uint16_t left, uint16_t right) throw() {} +void window::set_sound_rate(uint32_t rate_n, uint32_t rate_d) {} diff --git a/dummy/window-dummy.cpp b/dummy/window-dummy.cpp index 263d84ed..0937a455 100644 --- a/dummy/window-dummy.cpp +++ b/dummy/window-dummy.cpp @@ -7,16 +7,14 @@ namespace std::map status; } -void window::init() {} -void window::quit() {} +void graphics_init() {} +void graphics_quit() {} void window::poll_inputs() throw(std::bad_alloc) {} void window::notify_screen_update(bool full) throw() {} void window::set_main_surface(screen& scr) throw() {} void window::paused(bool enable) throw() {} void window::wait_usec(uint64_t usec) throw(std::bad_alloc) {} void window::cancel_wait() throw() {} -void window::sound_enable(bool enable) throw() {} -void window::play_audio_sample(uint16_t left, uint16_t right) throw() {} void window::set_window_compensation(uint32_t xoffset, uint32_t yoffset, uint32_t hscl, uint32_t vscl) {} bool window::modal_message(const std::string& msg, bool confirm) throw(std::bad_alloc) @@ -49,7 +47,3 @@ uint64_t get_ticks_msec() throw() static uint64_t c = 0; return c++; } - -void window::set_sound_rate(uint32_t rate_n, uint32_t rate_d) -{ -} diff --git a/generic/window.cpp b/generic/window.cpp index b0cb9bee..d8879b1d 100644 --- a/generic/window.cpp +++ b/generic/window.cpp @@ -52,6 +52,18 @@ namespace window_callback* wcb = NULL; } +void window::init() +{ + graphics_init(); + sound_init(); +} + +void window::quit() +{ + sound_quit(); + graphics_quit(); +} + std::ostream& window::out() throw(std::bad_alloc) { static std::ostream* cached = NULL; diff --git a/generic/window.hpp b/generic/window.hpp index 637df32c..0d06295c 100644 --- a/generic/window.hpp +++ b/generic/window.hpp @@ -43,6 +43,14 @@ public: static void set_callback_handler(window_callback& cb) throw(); }; +/** + * Sound/Graphics init/quit functions. Sound init is called after graphics init, and vice versa for quit. + */ +void graphics_init(); +void sound_init(); +void sound_quit(); +void graphics_quit(); + /** * This is a handle to graphics system. Note that creating multiple contexts produces undefined results. */