From cbfe65bdede0011ff110a290f5215866347fa567 Mon Sep 17 00:00:00 2001 From: Nadavbh Date: Sat, 25 Feb 2017 19:51:44 +0200 Subject: [PATCH] implemented sound for SDL interface. closes #2 --- CMakeLists.txt | 2 +- doc/examples/python_example.py | 6 +-- .../sharedLibraryInterfaceExample.cpp | 6 +-- src/environment/RetroAgent.cpp | 51 +++++++++++++++---- src/environment/RetroAgent.h | 2 + src/environment/Settings.cxx | 1 + src/environment/retro_environment.cpp | 3 ++ src/environment/retro_environment.hpp | 1 - 8 files changed, 52 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 306307b..4e98b1f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,7 +31,7 @@ if(USE_SDL) find_package(SDL) if(SDL_FOUND AND ${SDL_VERSION_STRING} VERSION_LESS 2) include_directories(${SDL_INCLUDE_DIR}) - list(APPEND LINK_LIBS ${SDL_LIBRARY} ${SDL_MAIN_LIBRARY} SDL_gfx) + list(APPEND LINK_LIBS ${SDL_LIBRARY} ${SDL_MAIN_LIBRARY} SDL_gfx asound) message("sdl_library:" ${SDL_LIBRARY} ${SDL_MAIN_LIBRARY}) else() # Uncomment below to specify the path to your SDL library. Run "locate libSDL" if unsure. diff --git a/doc/examples/python_example.py b/doc/examples/python_example.py index 53cafd3..486aedc 100755 --- a/doc/examples/python_example.py +++ b/doc/examples/python_example.py @@ -26,9 +26,9 @@ if sys.platform == 'darwin': import pygame pygame.init() -# rle.setBool('sound', False) # Sound doesn't work on OSX -# elif sys.platform.startswith('linux'): -# rle.setBool('sound', True) + rle.setBool('sound', False) # Sound doesn't work on OSX + elif sys.platform.startswith('linux'): + rle.setBool('sound', True) rle.setBool('display_screen', True) # Load the ROM file diff --git a/doc/examples/sharedLibraryInterfaceExample.cpp b/doc/examples/sharedLibraryInterfaceExample.cpp index 549e675..0bf783c 100644 --- a/doc/examples/sharedLibraryInterfaceExample.cpp +++ b/doc/examples/sharedLibraryInterfaceExample.cpp @@ -43,12 +43,8 @@ int main(int argc, char** argv) { #ifdef __USE_SDL rle.setBool("display_screen", true); -// rle.setBool("sound", true); + rle.setBool("sound", true); #endif - - rle.setString("MK_player1_character", "cage"); -// rle.setString("MK_player2_character", "scorpion"); - rle.setInt("MK_opponent_character", 4); // Load the ROM file. (Also resets the system for new settings to // take effect.) rle.loadROM(argv[1], argv[2]); diff --git a/src/environment/RetroAgent.cpp b/src/environment/RetroAgent.cpp index 9e431ce..cc4b1e4 100644 --- a/src/environment/RetroAgent.cpp +++ b/src/environment/RetroAgent.cpp @@ -17,11 +17,15 @@ #include "Serializer.hxx" #include "Deserializer.hxx" +#include +#include + using namespace rle; std::atomic_uint RetroAgent::numAgents{0}; thread_local struct RetroAgent::g_retro_ RetroAgent::g_retro; thread_local struct RetroAgent::g_video_ RetroAgent::g_video; +thread_local static snd_pcm_t *g_pcm = NULL; struct keymap { unsigned k; @@ -219,10 +223,32 @@ static void video_refresh(const void *data, unsigned width, unsigned height, uns } static void audio_init(int frequency) { -} + int err; + + if ((err = snd_pcm_open(&g_pcm, "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0) + die("Failed to open playback device: %s", snd_strerror(err)); + err = snd_pcm_set_params(g_pcm, SND_PCM_FORMAT_S16, SND_PCM_ACCESS_RW_INTERLEAVED, 2, frequency, 1, 64 * 1000); + + if (err < 0) + die("Failed to configure playback device: %s", snd_strerror(err)); +} static void audio_deinit() { + snd_pcm_close(g_pcm); +} + +static size_t audio_write(const void *buf, unsigned frames) { + int written = snd_pcm_writei(g_pcm, buf, frames); + + if (written < 0) { + printf("Alsa warning/error #%i: ", -written); + snd_pcm_recover(g_pcm, written, 0); + + return 0; + } + + return written; } static void core_log(enum retro_log_level level, const char *fmt, ...) { @@ -290,13 +316,11 @@ static bool core_environment(unsigned cmd, void *data) { return true; } - static void core_video_refresh(const void *data, unsigned width, unsigned height, size_t pitch) { if (data) video_refresh(data, width, height, pitch); } - static void core_input_poll(void) { int i; for (i = 0; g_binds[i].k || g_binds[i].rk; ++i){ @@ -311,7 +335,6 @@ static void core_input_poll(void) { } - // port == player number static int16_t core_input_state(unsigned port, unsigned device, unsigned index, unsigned id) { if (index || device != RETRO_DEVICE_JOYPAD) @@ -319,15 +342,22 @@ static int16_t core_input_state(unsigned port, unsigned device, unsigned index, return RetroAgent::g_joy[port][id]; } - static void core_audio_sample(int16_t left, int16_t right) { + int16_t buf[2] = {left, right}; + if(RetroAgent::g_retro.audioEnabled){ + audio_write(buf, 1); + } } static size_t core_audio_sample_batch(const int16_t *data, size_t frames) { + if(RetroAgent::g_retro.audioEnabled){ + return audio_write(data, frames); + }else{ + return 0; + } } - static void core_load(const char *sofile) { void (*set_environment)(retro_environment_t) = NULL; void (*set_video_refresh)(retro_video_refresh_t) = NULL; @@ -380,7 +410,6 @@ static void core_load(const char *sofile) { puts("Core loaded"); } - static void core_load_game(const char *filename) { struct retro_system_av_info av = {0}; struct retro_system_info system = {0}; @@ -419,7 +448,6 @@ static void core_load_game(const char *filename) { die("Failed to load content '%s': %s", filename, strerror(errno)); } - static void core_unload() { if (RetroAgent::g_retro.initialized) RetroAgent::g_retro.retro_deinit(); @@ -435,7 +463,6 @@ RetroAgent::RetroAgent() : coreLoaded(false), romLoaded(false){ RetroAgent::~RetroAgent(){ unloadRom(); core_unload(); -// --numAgents; } static bool replace(std::string& str, const std::string& from, const std::string& to) { @@ -480,6 +507,7 @@ void RetroAgent::loadCore(const string& coreName){ void RetroAgent::unloadCore(){ core_unload(); + audio_deinit(); coreLoaded = false; } @@ -504,6 +532,10 @@ void RetroAgent::run(){ RetroAgent::g_retro.retro_run(); } +void RetroAgent::audioEnable(bool audioState){ + RetroAgent::g_retro.audioEnabled = audioState; +} + int RetroAgent::getHeight(){ return RetroAgent::g_video.rGeom.base_height; } @@ -574,7 +606,6 @@ void RetroAgent::getRgbMask(uint32_t& rmask, uint32_t& gmask, uint32_t& bmask, u amask = RetroAgent::g_video.amask; } - uint32_t RetroAgent::getBufferSize() const{ return RetroAgent::g_video.rGeom.base_width * RetroAgent::g_video.rGeom.base_height; diff --git a/src/environment/RetroAgent.h b/src/environment/RetroAgent.h index 937e811..bf74bd0 100644 --- a/src/environment/RetroAgent.h +++ b/src/environment/RetroAgent.h @@ -24,6 +24,7 @@ class RetroAgent{ void loadCore(const string& corePath); void loadRom(const string& romPath); void run(); + void audioEnable(bool audioState); void videoRender(); void swapBuffers(); void videoDeinit(); @@ -76,6 +77,7 @@ class RetroAgent{ // string saveFolder = "/home/administrator/DQN/rle-nano/SNES-Learning-Environment/saves/"; string corePath; size_t serializeSize; + bool audioEnabled; }; thread_local static struct g_retro_ g_retro; diff --git a/src/environment/Settings.cxx b/src/environment/Settings.cxx index 077f2e7..61464e4 100644 --- a/src/environment/Settings.cxx +++ b/src/environment/Settings.cxx @@ -325,6 +325,7 @@ void Settings::setDefaultSettings() { // Display Settings boolSettings.emplace(std::make_pair("display_screen", false)); + boolSettings.emplace(std::make_pair("sound", false)); // Game-Specific Settings diff --git a/src/environment/retro_environment.cpp b/src/environment/retro_environment.cpp index 5dd7e20..40cb28e 100644 --- a/src/environment/retro_environment.cpp +++ b/src/environment/retro_environment.cpp @@ -102,6 +102,8 @@ void RetroEnvironment::reset() { // Reset the emulator m_rlesystem->getRetroAgent()->reset(); + bool audio = m_rlesystem->settings()->getBool("sound", true); + m_rlesystem->getRetroAgent()->audioEnable(false); // NOOP for 60 steps in the deterministic environment setting, or some random amount otherwise int noopSteps; @@ -125,6 +127,7 @@ void RetroEnvironment::reset() { // m_rlesystem->p_display_screen->display_screen(); } m_settings->startingOperations(*m_rlesystem); + m_rlesystem->getRetroAgent()->audioEnable(audio); } /** Save/restore the environment state. */ diff --git a/src/environment/retro_environment.hpp b/src/environment/retro_environment.hpp index dcd17c0..5c2d166 100644 --- a/src/environment/retro_environment.hpp +++ b/src/environment/retro_environment.hpp @@ -122,7 +122,6 @@ class RetroEnvironment { pRleSystem m_rlesystem; pRomSettings m_settings; PhosphorBlend m_phosphor_blend; // For performing phosphor colour averaging, if so desired -// std::string m_cartridge_md5; // Necessary for saving and loading emulator state std::stack m_saved_states; // States are saved on a stack