trunk/src/osd/modules/lib/osdobj_common.c
| r243095 | r243096 | |
| 11 | 11 | |
| 12 | 12 | #include "emu.h" |
| 13 | 13 | #include "osdepend.h" |
| 14 | | #include "modules/sound/none.h" |
| 15 | 14 | #include "modules/debugger/none.h" |
| 16 | 15 | #include "modules/debugger/debugint.h" |
| 17 | 16 | #include "modules/lib/osdobj_common.h" |
| r243095 | r243096 | |
| 119 | 118 | REGISTER_MODULE(m_mod_man, FONT_SDL); |
| 120 | 119 | REGISTER_MODULE(m_mod_man, FONT_NONE); |
| 121 | 120 | |
| 121 | REGISTER_MODULE(m_mod_man, SOUND_DSOUND); |
| 122 | REGISTER_MODULE(m_mod_man, SOUND_JS); |
| 123 | REGISTER_MODULE(m_mod_man, SOUND_SDL); |
| 124 | REGISTER_MODULE(m_mod_man, SOUND_NONE); |
| 125 | |
| 122 | 126 | // after initialization we know which modules are supported |
| 123 | 127 | |
| 124 | 128 | const char *names[20]; |
| r243095 | r243096 | |
| 129 | 133 | dnames.append(names[i]); |
| 130 | 134 | update_option(OSD_FONT_PROVIDER, dnames); |
| 131 | 135 | |
| 136 | m_mod_man.get_module_names(OSD_SOUND_PROVIDER, 20, &num, names); |
| 137 | dnames.reset(); |
| 138 | for (int i = 0; i < num; i++) |
| 139 | dnames.append(names[i]); |
| 140 | update_option(OSD_SOUND_PROVIDER, dnames); |
| 132 | 141 | |
| 133 | | |
| 134 | | |
| 135 | | |
| 136 | 142 | // Register video options and update options |
| 137 | 143 | video_options_add("none", NULL); |
| 138 | 144 | video_register(); |
| 139 | 145 | update_option(OSDOPTION_VIDEO, m_video_names); |
| 140 | 146 | |
| 141 | | // Register sound options and update options |
| 142 | | sound_options_add("none", OSD_SOUND_NONE); |
| 143 | | sound_register(); |
| 144 | | update_option(OSDOPTION_SOUND, m_sound_names); |
| 145 | | |
| 146 | 147 | // Register debugger options and update options |
| 147 | 148 | debugger_options_add("none", OSD_DEBUGGER_NONE); |
| 148 | 149 | debugger_options_add("internal", OSD_DEBUGGER_INTERNAL); |
| r243095 | r243096 | |
| 180 | 181 | osd_free(const_cast<char*>(m_video_names[i])); |
| 181 | 182 | //m_video_options,reset(); |
| 182 | 183 | |
| 183 | | for(int i= 0; i < m_sound_names.count(); ++i) |
| 184 | | osd_free(const_cast<char*>(m_sound_names[i])); |
| 185 | | m_sound_options.reset(); |
| 186 | | |
| 187 | 184 | for(int i= 0; i < m_debugger_names.count(); ++i) |
| 188 | 185 | osd_free(const_cast<char*>(m_debugger_names[i])); |
| 189 | 186 | m_debugger_options.reset(); |
| r243095 | r243096 | |
| 233 | 230 | if (options.verbose()) |
| 234 | 231 | g_print_verbose = true; |
| 235 | 232 | |
| 236 | | m_font_module = select_module_options<font_module *>(options, OSD_FONT_PROVIDER); |
| 237 | | |
| 238 | | m_mod_man.init(); |
| 239 | | |
| 240 | | |
| 241 | 233 | // ensure we get called on the way out |
| 242 | 234 | machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(osd_common_t::osd_exit), this)); |
| 243 | 235 | } |
| r243095 | r243096 | |
| 327 | 319 | // It provides an array of stereo samples in L-R order which should be |
| 328 | 320 | // output at the configured sample_rate. |
| 329 | 321 | // |
| 330 | | if (m_sound != NULL) |
| 331 | | m_sound->update_audio_stream(buffer,samples_this_frame); |
| 322 | m_sound->update_audio_stream(m_machine->video().throttled(), buffer,samples_this_frame); |
| 332 | 323 | } |
| 333 | 324 | |
| 334 | 325 | |
| r243095 | r243096 | |
| 449 | 440 | exit(-1); |
| 450 | 441 | } |
| 451 | 442 | |
| 452 | | sound_init(); |
| 453 | 443 | input_init(); |
| 454 | 444 | // we need pause callbacks |
| 455 | 445 | machine().add_notifier(MACHINE_NOTIFY_PAUSE, machine_notify_delegate(FUNC(osd_common_t::input_pause), this)); |
| r243095 | r243096 | |
| 460 | 450 | network_init(); |
| 461 | 451 | #endif |
| 462 | 452 | midi_init(); |
| 453 | |
| 454 | m_font_module = select_module_options<font_module *>(options(), OSD_FONT_PROVIDER); |
| 455 | |
| 456 | m_sound = select_module_options<sound_module *>(options(), OSD_SOUND_PROVIDER); |
| 457 | m_sound->m_sample_rate = options().sample_rate(); |
| 458 | m_sound->m_audio_latency = options().audio_latency(); |
| 459 | |
| 460 | m_mod_man.init(); |
| 461 | |
| 463 | 462 | } |
| 464 | 463 | |
| 465 | 464 | bool osd_common_t::video_init() |
| r243095 | r243096 | |
| 472 | 471 | return true; |
| 473 | 472 | } |
| 474 | 473 | |
| 475 | | bool osd_common_t::sound_init() |
| 476 | | { |
| 477 | | osd_sound_type sound = m_sound_options.find(options().sound()); |
| 478 | | if (sound==NULL) |
| 479 | | { |
| 480 | | osd_printf_warning("sound_init: option %s not found switching to auto\n",options().sound()); |
| 481 | | sound = m_sound_options.find("auto"); |
| 482 | | } |
| 483 | | if (sound != NULL) |
| 484 | | m_sound = (*sound)(*this, machine()); |
| 485 | | else |
| 486 | | m_sound = NULL; |
| 487 | | return true; |
| 488 | | } |
| 489 | | |
| 490 | 474 | bool osd_common_t::no_sound() |
| 491 | 475 | { |
| 492 | 476 | return (strcmp(options().sound(),"none")==0) ? true : false; |
| r243095 | r243096 | |
| 496 | 480 | { |
| 497 | 481 | } |
| 498 | 482 | |
| 499 | | void osd_common_t::sound_register() |
| 500 | | { |
| 501 | | } |
| 502 | | |
| 503 | 483 | void osd_common_t::debugger_register() |
| 504 | 484 | { |
| 505 | 485 | } |
| r243095 | r243096 | |
| 530 | 510 | void osd_common_t::exit_subsystems() |
| 531 | 511 | { |
| 532 | 512 | video_exit(); |
| 533 | | sound_exit(); |
| 534 | 513 | input_exit(); |
| 535 | 514 | output_exit(); |
| 536 | 515 | #ifdef USE_NETWORK |
| r243095 | r243096 | |
| 548 | 527 | { |
| 549 | 528 | } |
| 550 | 529 | |
| 551 | | void osd_common_t::sound_exit() |
| 552 | | { |
| 553 | | if (m_sound != NULL) |
| 554 | | global_free(m_sound); |
| 555 | | } |
| 556 | | |
| 557 | 530 | void osd_common_t::input_exit() |
| 558 | 531 | { |
| 559 | 532 | } |
| r243095 | r243096 | |
| 579 | 552 | m_video_names.append(core_strdup(name)); |
| 580 | 553 | } |
| 581 | 554 | |
| 582 | | void osd_common_t::sound_options_add(const char *name, osd_sound_type type) |
| 583 | | { |
| 584 | | m_sound_options.add(name, type, false); |
| 585 | | m_sound_names.append(core_strdup(name)); |
| 586 | | } |
| 587 | | |
| 588 | 555 | void osd_common_t::debugger_options_add(const char *name, osd_debugger_type type) |
| 589 | 556 | { |
| 590 | 557 | m_debugger_options.add(name, type, false); |
| r243095 | r243096 | |
| 603 | 570 | } |
| 604 | 571 | |
| 605 | 572 | //------------------------------------------------- |
| 606 | | // osd_sound_interface - constructor |
| 607 | | //------------------------------------------------- |
| 608 | | |
| 609 | | osd_sound_interface::osd_sound_interface(const osd_interface &osd, running_machine &machine) |
| 610 | | : m_osd(osd), m_machine(machine) |
| 611 | | { |
| 612 | | } |
| 613 | | |
| 614 | | //------------------------------------------------- |
| 615 | | // osd_sound_interface - destructor |
| 616 | | //------------------------------------------------- |
| 617 | | |
| 618 | | osd_sound_interface::~osd_sound_interface() |
| 619 | | { |
| 620 | | } |
| 621 | | |
| 622 | | //------------------------------------------------- |
| 623 | 573 | // osd_debugger_interface - constructor |
| 624 | 574 | //------------------------------------------------- |
| 625 | 575 | |
trunk/src/osd/modules/sound/direct_sound.c
| r243095 | r243096 | |
| 6 | 6 | // |
| 7 | 7 | //============================================================ |
| 8 | 8 | |
| 9 | #include "sound_module.h" |
| 10 | #include "modules/osdmodule.h" |
| 11 | |
| 12 | #if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32) |
| 13 | |
| 9 | 14 | // standard windows headers |
| 10 | 15 | #define WIN32_LEAN_AND_MEAN |
| 11 | 16 | #include <windows.h> |
| r243095 | r243096 | |
| 21 | 26 | #include "osdepend.h" |
| 22 | 27 | #include "emuopts.h" |
| 23 | 28 | |
| 24 | | // MAMEOS headers |
| 25 | | #include "direct_sound.h" |
| 26 | | |
| 27 | 29 | #ifdef SDLMAME_WIN32 |
| 28 | 30 | #include "../../sdl/osdsdl.h" |
| 29 | 31 | #if (SDLMAME_SDL2) |
| r243095 | r243096 | |
| 45 | 47 | |
| 46 | 48 | #define LOG(x) do { if (LOG_SOUND) logerror x; } while(0) |
| 47 | 49 | |
| 50 | class sound_direct_sound : public osd_module, public sound_module |
| 51 | { |
| 52 | public: |
| 48 | 53 | |
| 54 | sound_direct_sound() |
| 55 | : osd_module(OSD_SOUND_PROVIDER, "dsound"), sound_module() |
| 56 | { |
| 57 | } |
| 58 | virtual ~sound_direct_sound() { } |
| 59 | |
| 60 | virtual int init(); |
| 61 | virtual void exit(); |
| 62 | |
| 63 | // sound_module |
| 64 | |
| 65 | virtual void update_audio_stream(bool is_throttled, const INT16 *buffer, int samples_this_frame); |
| 66 | virtual void set_mastervolume(int attenuation); |
| 67 | |
| 68 | private: |
| 69 | HRESULT dsound_init(); |
| 70 | void dsound_kill(); |
| 71 | HRESULT dsound_create_buffers(); |
| 72 | void dsound_destroy_buffers(); |
| 73 | void copy_sample_data(const INT16 *data, int bytes_to_copy); |
| 74 | |
| 75 | }; |
| 76 | |
| 77 | |
| 78 | |
| 49 | 79 | //============================================================ |
| 50 | 80 | // LOCAL VARIABLES |
| 51 | 81 | //============================================================ |
| r243095 | r243096 | |
| 69 | 99 | // buffer over/underflow counts |
| 70 | 100 | static int buffer_underflows; |
| 71 | 101 | static int buffer_overflows; |
| 102 | |
| 72 | 103 | //============================================================ |
| 73 | 104 | // PROTOTYPES |
| 74 | 105 | //============================================================ |
| 75 | 106 | |
| 76 | | const osd_sound_type OSD_SOUND_DIRECT_SOUND = &osd_sound_creator<sound_direct_sound>; |
| 77 | | |
| 78 | 107 | //------------------------------------------------- |
| 79 | 108 | // sound_direct_sound - constructor |
| 80 | 109 | //------------------------------------------------- |
| 81 | | sound_direct_sound::sound_direct_sound(const osd_interface &osd, running_machine &machine) |
| 82 | | : osd_sound_interface(osd, machine) |
| 110 | |
| 111 | int sound_direct_sound::init() |
| 83 | 112 | { |
| 84 | 113 | // attempt to initialize directsound |
| 85 | 114 | // don't make it fatal if we can't -- we'll just run without sound |
| 86 | 115 | dsound_init(); |
| 116 | return 0; |
| 87 | 117 | } |
| 88 | 118 | |
| 89 | 119 | |
| 90 | | sound_direct_sound::~sound_direct_sound() |
| 120 | void sound_direct_sound::exit() |
| 91 | 121 | { |
| 92 | 122 | // kill the buffers and dsound |
| 93 | 123 | dsound_destroy_buffers(); |
| r243095 | r243096 | |
| 149 | 179 | // update_audio_stream |
| 150 | 180 | //============================================================ |
| 151 | 181 | |
| 152 | | void sound_direct_sound::update_audio_stream(const INT16 *buffer, int samples_this_frame) |
| 182 | void sound_direct_sound::update_audio_stream(bool is_throttled, const INT16 *buffer, int samples_this_frame) |
| 153 | 183 | { |
| 154 | 184 | int bytes_this_frame = samples_this_frame * stream_format.nBlockAlign; |
| 155 | 185 | DWORD play_position, write_position; |
| r243095 | r243096 | |
| 268 | 298 | stream_format.wBitsPerSample = 16; |
| 269 | 299 | stream_format.wFormatTag = WAVE_FORMAT_PCM; |
| 270 | 300 | stream_format.nChannels = 2; |
| 271 | | stream_format.nSamplesPerSec = m_machine.sample_rate(); |
| 301 | stream_format.nSamplesPerSec = sample_rate(); |
| 272 | 302 | stream_format.nBlockAlign = stream_format.wBitsPerSample * stream_format.nChannels / 8; |
| 273 | 303 | stream_format.nAvgBytesPerSec = stream_format.nSamplesPerSec * stream_format.nBlockAlign; |
| 274 | 304 | |
| 275 | 305 | |
| 276 | 306 | // compute the buffer size based on the output sample rate |
| 277 | 307 | int audio_latency; |
| 278 | | #ifdef SDLMAME_WIN32 |
| 279 | | audio_latency = downcast<sdl_options &>(m_machine.options()).audio_latency(); |
| 280 | | #else |
| 281 | | audio_latency = downcast<windows_options &>(m_machine.options()).audio_latency(); |
| 282 | | #endif |
| 308 | audio_latency = m_audio_latency; |
| 309 | |
| 283 | 310 | stream_buffer_size = stream_format.nSamplesPerSec * stream_format.nBlockAlign * audio_latency / 10; |
| 284 | 311 | stream_buffer_size = (stream_buffer_size / 1024) * 1024; |
| 285 | 312 | if (stream_buffer_size < 1024) |
| r243095 | r243096 | |
| 419 | 446 | IDirectSoundBuffer_Release(primary_buffer); |
| 420 | 447 | primary_buffer = NULL; |
| 421 | 448 | } |
| 449 | |
| 450 | #else /* SDLMAME_UNIX */ |
| 451 | MODULE_NOT_SUPPORTED(sound_direct_sound, OSD_SOUND_PROVIDER, "dsound") |
| 452 | #endif |
| 453 | |
| 454 | MODULE_DEFINITION(SOUND_DSOUND, sound_direct_sound) |
trunk/src/osd/modules/sound/sdl_sound.c
| r243095 | r243096 | |
| 9 | 9 | // |
| 10 | 10 | //============================================================ |
| 11 | 11 | |
| 12 | #include "sound_module.h" |
| 13 | #include "modules/osdmodule.h" |
| 14 | |
| 15 | #if (!defined(SDLMAME_EMSCRIPTEN)) && (!defined(OSD_WINDOWS)) |
| 16 | |
| 12 | 17 | // standard sdl header |
| 13 | 18 | #include "../../sdl/sdlinc.h" |
| 14 | 19 | |
| r243095 | r243096 | |
| 16 | 21 | #include "emu.h" |
| 17 | 22 | #include "emuopts.h" |
| 18 | 23 | |
| 19 | | #include "sdl_sound.h" |
| 20 | 24 | #include "../../sdl/osdsdl.h" |
| 21 | 25 | |
| 22 | 26 | //============================================================ |
| r243095 | r243096 | |
| 26 | 30 | #define LOG_SOUND 0 |
| 27 | 31 | |
| 28 | 32 | //============================================================ |
| 29 | | // PARAMETERS |
| 33 | // PROTOTYPES |
| 30 | 34 | //============================================================ |
| 31 | 35 | |
| 32 | | // number of samples per SDL callback |
| 33 | | #define SDL_XFER_SAMPLES (512) |
| 36 | static void sdl_callback(void *userdata, Uint8 *stream, int len); |
| 34 | 37 | |
| 35 | | static int sdl_xfer_samples = SDL_XFER_SAMPLES; |
| 36 | | static int stream_in_initialized = 0; |
| 37 | | static int stream_loop = 0; |
| 38 | | |
| 39 | | // maximum audio latency |
| 40 | | #define MAX_AUDIO_LATENCY 5 |
| 41 | | |
| 42 | 38 | //============================================================ |
| 43 | | // LOCAL VARIABLES |
| 39 | // CLASS |
| 44 | 40 | //============================================================ |
| 45 | 41 | |
| 46 | | static int attenuation = 0; |
| 42 | class sound_sdl : public osd_module, public sound_module |
| 43 | { |
| 44 | public: |
| 47 | 45 | |
| 48 | | static int initialized_audio = 0; |
| 49 | | static int buf_locked; |
| 46 | friend void sdl_callback(void *userdata, Uint8 *stream, int len); |
| 50 | 47 | |
| 51 | | static INT8 *stream_buffer; |
| 52 | | static volatile INT32 stream_playpos; |
| 48 | // number of samples per SDL callback |
| 49 | static const int SDL_XFER_SAMPLES = 512; |
| 53 | 50 | |
| 54 | | static UINT32 stream_buffer_size; |
| 55 | | static UINT32 stream_buffer_in; |
| 51 | sound_sdl() |
| 52 | : osd_module(OSD_SOUND_PROVIDER, "sdl"), sound_module(), |
| 53 | stream_in_initialized(0), |
| 54 | stream_loop(0), |
| 55 | attenuation(0) |
| 56 | { |
| 57 | sdl_xfer_samples = SDL_XFER_SAMPLES; |
| 58 | } |
| 59 | virtual ~sound_sdl() { } |
| 56 | 60 | |
| 57 | | // buffer over/underflow counts |
| 58 | | static int buffer_underflows; |
| 59 | | static int buffer_overflows; |
| 61 | virtual int init(); |
| 62 | virtual void exit(); |
| 60 | 63 | |
| 61 | | // debugging |
| 62 | | static FILE *sound_log; |
| 64 | // sound_module |
| 63 | 65 | |
| 66 | virtual void update_audio_stream(bool is_throttled, const INT16 *buffer, int samples_this_frame); |
| 67 | virtual void set_mastervolume(int attenuation); |
| 64 | 68 | |
| 65 | | // sound enable |
| 66 | | static int snd_enabled; |
| 69 | private: |
| 70 | int lock_buffer(bool is_throttled, long offset, long size, void **buffer1, long *length1, void **buffer2, long *length2); |
| 71 | void unlock_buffer(void); |
| 72 | void att_memcpy(void *dest, const INT16 *data, int bytes_to_copy); |
| 73 | void copy_sample_data(bool is_throttled, const INT16 *data, int bytes_to_copy); |
| 74 | int sdl_create_buffers(void); |
| 75 | void sdl_destroy_buffers(void); |
| 67 | 76 | |
| 68 | | //============================================================ |
| 69 | | // PROTOTYPES |
| 70 | | //============================================================ |
| 77 | int sdl_xfer_samples; |
| 78 | int stream_in_initialized; |
| 79 | int stream_loop; |
| 80 | int attenuation; |
| 71 | 81 | |
| 72 | | static int sdl_init(running_machine &machine); |
| 73 | | static void sdl_kill(running_machine &machine); |
| 74 | | static int sdl_create_buffers(void); |
| 75 | | static void sdl_destroy_buffers(void); |
| 76 | | static void SDLCALL sdl_callback(void *userdata, Uint8 *stream, int len); |
| 82 | int buf_locked; |
| 77 | 83 | |
| 78 | | const osd_sound_type OSD_SOUND_SDL = &osd_sound_creator<sound_sdl>; |
| 84 | INT8 *stream_buffer; |
| 85 | volatile INT32 stream_playpos; |
| 79 | 86 | |
| 80 | | //------------------------------------------------- |
| 81 | | // sound_sdl - constructor |
| 82 | | //------------------------------------------------- |
| 83 | | sound_sdl::sound_sdl(const osd_interface &osd, running_machine &machine) |
| 84 | | : osd_sound_interface(osd, machine) |
| 85 | | { |
| 86 | | if (LOG_SOUND) |
| 87 | | sound_log = fopen(SDLMAME_SOUND_LOG, "w"); |
| 87 | UINT32 stream_buffer_size; |
| 88 | UINT32 stream_buffer_in; |
| 88 | 89 | |
| 89 | | // skip if sound disabled |
| 90 | | if (m_machine.sample_rate() != 0) |
| 91 | | { |
| 92 | | if (initialized_audio) |
| 93 | | { |
| 94 | | //sound_exit(); |
| 95 | | } |
| 90 | // buffer over/underflow counts |
| 91 | int buffer_underflows; |
| 92 | int buffer_overflows; |
| 96 | 93 | |
| 97 | | // attempt to initialize SDL |
| 98 | | if (sdl_init(m_machine)) |
| 99 | | return; |
| 100 | 94 | |
| 101 | | // set the startup volume |
| 102 | | set_mastervolume(attenuation); |
| 103 | | } |
| 104 | | } |
| 95 | }; |
| 105 | 96 | |
| 106 | 97 | |
| 107 | | |
| 108 | 98 | //============================================================ |
| 109 | | // sound_sdl - destructor |
| 99 | // PARAMETERS |
| 110 | 100 | //============================================================ |
| 111 | 101 | |
| 112 | | sound_sdl::~sound_sdl() |
| 113 | | { |
| 114 | | // if nothing to do, don't do it |
| 115 | | if (m_machine.sample_rate() == 0) |
| 116 | | return; |
| 102 | // maximum audio latency |
| 103 | #define MAX_AUDIO_LATENCY 5 |
| 117 | 104 | |
| 118 | | // kill the buffers and dsound |
| 119 | | sdl_kill(m_machine); |
| 120 | | sdl_destroy_buffers(); |
| 105 | //============================================================ |
| 106 | // LOCAL VARIABLES |
| 107 | //============================================================ |
| 121 | 108 | |
| 122 | | // print out over/underflow stats |
| 123 | | if (buffer_overflows || buffer_underflows) |
| 124 | | osd_printf_verbose("Sound buffer: overflows=%d underflows=%d\n", buffer_overflows, buffer_underflows); |
| 109 | // debugging |
| 110 | static FILE *sound_log; |
| 125 | 111 | |
| 126 | | if (LOG_SOUND) |
| 127 | | { |
| 128 | | fprintf(sound_log, "Sound buffer: overflows=%d underflows=%d\n", buffer_overflows, buffer_underflows); |
| 129 | | fclose(sound_log); |
| 130 | | } |
| 131 | | } |
| 112 | //============================================================ |
| 113 | // sound_sdl - destructor |
| 114 | //============================================================ |
| 132 | 115 | |
| 133 | 116 | //============================================================ |
| 134 | 117 | // lock_buffer |
| 135 | 118 | //============================================================ |
| 136 | | static int lock_buffer(running_machine &machine, long offset, long size, void **buffer1, long *length1, void **buffer2, long *length2) |
| 119 | int sound_sdl::lock_buffer(bool is_throttled, long offset, long size, void **buffer1, long *length1, void **buffer2, long *length2) |
| 137 | 120 | { |
| 138 | 121 | volatile long pstart, pend, lstart, lend; |
| 139 | 122 | |
| 140 | 123 | if (!buf_locked) |
| 141 | 124 | { |
| 142 | | if (machine.video().throttled()) |
| 125 | if (is_throttled) |
| 143 | 126 | { |
| 144 | 127 | pstart = stream_playpos; |
| 145 | 128 | pend = (pstart + sdl_xfer_samples); |
| r243095 | r243096 | |
| 185 | 168 | //============================================================ |
| 186 | 169 | // unlock_buffer |
| 187 | 170 | //============================================================ |
| 188 | | static void unlock_buffer(void) |
| 171 | void sound_sdl::unlock_buffer(void) |
| 189 | 172 | { |
| 190 | 173 | buf_locked--; |
| 191 | 174 | if (!buf_locked) |
| r243095 | r243096 | |
| 200 | 183 | // Apply attenuation |
| 201 | 184 | //============================================================ |
| 202 | 185 | |
| 203 | | static void att_memcpy(void *dest, const INT16 *data, int bytes_to_copy) |
| 186 | void sound_sdl::att_memcpy(void *dest, const INT16 *data, int bytes_to_copy) |
| 204 | 187 | { |
| 205 | 188 | int level= (int) (pow(10.0, (float) attenuation / 20.0) * 128.0); |
| 206 | 189 | INT16 *d = (INT16 *) dest; |
| r243095 | r243096 | |
| 216 | 199 | // copy_sample_data |
| 217 | 200 | //============================================================ |
| 218 | 201 | |
| 219 | | static void copy_sample_data(running_machine &machine, const INT16 *data, int bytes_to_copy) |
| 202 | void sound_sdl::copy_sample_data(bool is_throttled, const INT16 *data, int bytes_to_copy) |
| 220 | 203 | { |
| 221 | 204 | void *buffer1, *buffer2 = (void *)NULL; |
| 222 | 205 | long length1, length2; |
| 223 | 206 | int cur_bytes; |
| 224 | 207 | |
| 225 | 208 | // attempt to lock the stream buffer |
| 226 | | if (lock_buffer(machine, stream_buffer_in, bytes_to_copy, &buffer1, &length1, &buffer2, &length2) < 0) |
| 209 | if (lock_buffer(is_throttled, stream_buffer_in, bytes_to_copy, &buffer1, &length1, &buffer2, &length2) < 0) |
| 227 | 210 | { |
| 228 | 211 | buffer_underflows++; |
| 229 | 212 | return; |
| r243095 | r243096 | |
| 264 | 247 | // update_audio_stream |
| 265 | 248 | //============================================================ |
| 266 | 249 | |
| 267 | | void sound_sdl::update_audio_stream(const INT16 *buffer, int samples_this_frame) |
| 250 | void sound_sdl::update_audio_stream(bool is_throttled, const INT16 *buffer, int samples_this_frame) |
| 268 | 251 | { |
| 269 | 252 | // if nothing to do, don't do it |
| 270 | | if (m_machine.sample_rate() != 0 && stream_buffer) |
| 253 | if (sample_rate() != 0 && stream_buffer) |
| 271 | 254 | { |
| 272 | 255 | int bytes_this_frame = samples_this_frame * sizeof(INT16) * 2; |
| 273 | 256 | int play_position, write_position, stream_in; |
| r243095 | r243096 | |
| 275 | 258 | |
| 276 | 259 | play_position = stream_playpos; |
| 277 | 260 | |
| 278 | | write_position = stream_playpos + ((m_machine.sample_rate() / 50) * sizeof(INT16) * 2); |
| 261 | write_position = stream_playpos + ((sample_rate() / 50) * sizeof(INT16) * 2); |
| 279 | 262 | orig_write = write_position; |
| 280 | 263 | |
| 281 | 264 | if (!stream_in_initialized) |
| r243095 | r243096 | |
| 336 | 319 | |
| 337 | 320 | // now we know where to copy; let's do it |
| 338 | 321 | stream_buffer_in = stream_in; |
| 339 | | copy_sample_data(m_machine, buffer, bytes_this_frame); |
| 322 | copy_sample_data(is_throttled, buffer, bytes_this_frame); |
| 340 | 323 | } |
| 341 | 324 | } |
| 342 | 325 | |
| r243095 | r243096 | |
| 371 | 354 | //============================================================ |
| 372 | 355 | static void sdl_callback(void *userdata, Uint8 *stream, int len) |
| 373 | 356 | { |
| 357 | sound_sdl *thiz = (sound_sdl *) userdata; |
| 374 | 358 | int len1, len2, sb_in; |
| 375 | 359 | |
| 376 | | sb_in = stream_buffer_in; |
| 377 | | if (stream_loop) |
| 378 | | sb_in += stream_buffer_size; |
| 360 | sb_in = thiz->stream_buffer_in; |
| 361 | if (thiz->stream_loop) |
| 362 | sb_in += thiz->stream_buffer_size; |
| 379 | 363 | |
| 380 | | if (sb_in < (stream_playpos+len)) |
| 364 | if (sb_in < (thiz->stream_playpos+len)) |
| 381 | 365 | { |
| 382 | 366 | if (LOG_SOUND) |
| 383 | | fprintf(sound_log, "Underflow at sdl_callback: SPP=%d SBI=%d(%d) Len=%d\n", (int)stream_playpos, (int)sb_in, (int)stream_buffer_in, (int)len); |
| 367 | fprintf(sound_log, "Underflow at sdl_callback: SPP=%d SBI=%d(%d) Len=%d\n", (int)thiz->stream_playpos, (int)sb_in, (int)thiz->stream_buffer_in, (int)len); |
| 384 | 368 | |
| 385 | 369 | return; |
| 386 | 370 | } |
| 387 | | else if ((stream_playpos+len) > stream_buffer_size) |
| 371 | else if ((thiz->stream_playpos+len) > thiz->stream_buffer_size) |
| 388 | 372 | { |
| 389 | | len1 = stream_buffer_size - stream_playpos; |
| 373 | len1 = thiz->stream_buffer_size - thiz->stream_playpos; |
| 390 | 374 | len2 = len - len1; |
| 391 | 375 | } |
| 392 | 376 | else |
| r243095 | r243096 | |
| 395 | 379 | len2 = 0; |
| 396 | 380 | } |
| 397 | 381 | |
| 398 | | if (snd_enabled) |
| 399 | | { |
| 400 | | memcpy(stream, stream_buffer + stream_playpos, len1); |
| 401 | | memset(stream_buffer + stream_playpos, 0, len1); // no longer needed |
| 402 | | if (len2) |
| 403 | | { |
| 404 | | memcpy(stream+len1, stream_buffer, len2); |
| 405 | | memset(stream_buffer, 0, len2); // no longer needed |
| 406 | | } |
| 382 | memcpy(stream, thiz->stream_buffer + thiz->stream_playpos, len1); |
| 383 | memset(thiz->stream_buffer + thiz->stream_playpos, 0, len1); // no longer needed |
| 384 | if (len2) |
| 385 | { |
| 386 | memcpy(stream+len1, thiz->stream_buffer, len2); |
| 387 | memset(thiz->stream_buffer, 0, len2); // no longer needed |
| 388 | } |
| 407 | 389 | |
| 408 | | } |
| 409 | | else |
| 410 | | { |
| 411 | | memset(stream, 0, len); |
| 412 | | } |
| 413 | 390 | |
| 414 | 391 | // move the play cursor |
| 415 | | stream_playpos += len1 + len2; |
| 416 | | if (stream_playpos >= stream_buffer_size) |
| 392 | thiz->stream_playpos += len1 + len2; |
| 393 | if (thiz->stream_playpos >= thiz->stream_buffer_size) |
| 417 | 394 | { |
| 418 | | stream_playpos -= stream_buffer_size; |
| 419 | | stream_loop = 0; |
| 395 | thiz->stream_playpos -= thiz->stream_buffer_size; |
| 396 | thiz->stream_loop = 0; |
| 420 | 397 | |
| 421 | 398 | if (LOG_SOUND) |
| 422 | 399 | fprintf(sound_log, "stream_loop set to 0 (stream_playpos looped)\n"); |
| r243095 | r243096 | |
| 424 | 401 | |
| 425 | 402 | if (LOG_SOUND) |
| 426 | 403 | fprintf(sound_log, "callback: xfer len1 %d len2 %d, playpos %d\n", |
| 427 | | len1, len2, stream_playpos); |
| 404 | len1, len2, thiz->stream_playpos); |
| 428 | 405 | } |
| 429 | 406 | |
| 430 | 407 | |
| 431 | 408 | //============================================================ |
| 432 | | // sdl_init |
| 409 | // sound_sdl::init |
| 433 | 410 | //============================================================ |
| 434 | | static int sdl_init(running_machine &machine) |
| 411 | |
| 412 | int sound_sdl::init() |
| 435 | 413 | { |
| 436 | 414 | int n_channels = 2; |
| 437 | 415 | int audio_latency; |
| 438 | 416 | SDL_AudioSpec aspec, obtained; |
| 439 | 417 | char audio_driver[16] = ""; |
| 440 | 418 | |
| 441 | | if (SDL_InitSubSystem(SDL_INIT_AUDIO)) { |
| 442 | | osd_printf_error("Could not initialize SDL %s\n", SDL_GetError()); |
| 443 | | exit(-1); |
| 444 | | } |
| 419 | if (LOG_SOUND) |
| 420 | sound_log = fopen(SDLMAME_SOUND_LOG, "w"); |
| 445 | 421 | |
| 446 | | osd_printf_verbose("Audio: Start initialization\n"); |
| 447 | | #if (SDLMAME_SDL2) |
| 448 | | strncpy(audio_driver, SDL_GetCurrentAudioDriver(), sizeof(audio_driver)); |
| 449 | | #else |
| 450 | | SDL_AudioDriverName(audio_driver, sizeof(audio_driver)); |
| 451 | | #endif |
| 452 | | osd_printf_verbose("Audio: Driver is %s\n", audio_driver); |
| 422 | // skip if sound disabled |
| 423 | if (sample_rate() != 0) |
| 424 | { |
| 425 | if (SDL_InitSubSystem(SDL_INIT_AUDIO)) { |
| 426 | osd_printf_error("Could not initialize SDL %s\n", SDL_GetError()); |
| 427 | return -1; |
| 428 | } |
| 453 | 429 | |
| 454 | | initialized_audio = 0; |
| 430 | osd_printf_verbose("Audio: Start initialization\n"); |
| 431 | #if (SDLMAME_SDL2) |
| 432 | strncpy(audio_driver, SDL_GetCurrentAudioDriver(), sizeof(audio_driver)); |
| 433 | #else |
| 434 | SDL_AudioDriverName(audio_driver, sizeof(audio_driver)); |
| 435 | #endif |
| 436 | osd_printf_verbose("Audio: Driver is %s\n", audio_driver); |
| 455 | 437 | |
| 456 | | sdl_xfer_samples = SDL_XFER_SAMPLES; |
| 457 | | stream_in_initialized = 0; |
| 458 | | stream_loop = 0; |
| 438 | sdl_xfer_samples = SDL_XFER_SAMPLES; |
| 439 | stream_in_initialized = 0; |
| 440 | stream_loop = 0; |
| 459 | 441 | |
| 460 | | // set up the audio specs |
| 461 | | aspec.freq = machine.sample_rate(); |
| 462 | | aspec.format = AUDIO_S16SYS; // keep endian independent |
| 463 | | aspec.channels = n_channels; |
| 464 | | aspec.samples = sdl_xfer_samples; |
| 465 | | aspec.callback = sdl_callback; |
| 466 | | aspec.userdata = 0; |
| 442 | // set up the audio specs |
| 443 | aspec.freq = sample_rate(); |
| 444 | aspec.format = AUDIO_S16SYS; // keep endian independent |
| 445 | aspec.channels = n_channels; |
| 446 | aspec.samples = sdl_xfer_samples; |
| 447 | aspec.callback = sdl_callback; |
| 448 | aspec.userdata = this; |
| 467 | 449 | |
| 468 | | if (SDL_OpenAudio(&aspec, &obtained) < 0) |
| 469 | | goto cant_start_audio; |
| 450 | if (SDL_OpenAudio(&aspec, &obtained) < 0) |
| 451 | goto cant_start_audio; |
| 470 | 452 | |
| 471 | | initialized_audio = 1; |
| 472 | | snd_enabled = 1; |
| 453 | osd_printf_verbose("Audio: frequency: %d, channels: %d, samples: %d\n", |
| 454 | obtained.freq, obtained.channels, obtained.samples); |
| 473 | 455 | |
| 474 | | osd_printf_verbose("Audio: frequency: %d, channels: %d, samples: %d\n", |
| 475 | | obtained.freq, obtained.channels, obtained.samples); |
| 456 | sdl_xfer_samples = obtained.samples; |
| 476 | 457 | |
| 477 | | sdl_xfer_samples = obtained.samples; |
| 458 | audio_latency = m_audio_latency; |
| 478 | 459 | |
| 479 | | audio_latency = downcast<sdl_options &>(machine.options()).audio_latency(); |
| 460 | // pin audio latency |
| 461 | if (audio_latency > MAX_AUDIO_LATENCY) |
| 462 | { |
| 463 | audio_latency = MAX_AUDIO_LATENCY; |
| 464 | } |
| 465 | else if (audio_latency < 1) |
| 466 | { |
| 467 | audio_latency = 1; |
| 468 | } |
| 480 | 469 | |
| 481 | | // pin audio latency |
| 482 | | if (audio_latency > MAX_AUDIO_LATENCY) |
| 483 | | { |
| 484 | | audio_latency = MAX_AUDIO_LATENCY; |
| 485 | | } |
| 486 | | else if (audio_latency < 1) |
| 487 | | { |
| 488 | | audio_latency = 1; |
| 489 | | } |
| 470 | // compute the buffer sizes |
| 471 | stream_buffer_size = (sample_rate() * 2 * sizeof(INT16) * (2 + audio_latency)) / 30; |
| 472 | stream_buffer_size = (stream_buffer_size / 1024) * 1024; |
| 473 | if (stream_buffer_size < 1024) |
| 474 | stream_buffer_size = 1024; |
| 490 | 475 | |
| 491 | | // compute the buffer sizes |
| 492 | | stream_buffer_size = (machine.sample_rate() * 2 * sizeof(INT16) * (2 + audio_latency)) / 30; |
| 493 | | stream_buffer_size = (stream_buffer_size / 1024) * 1024; |
| 494 | | if (stream_buffer_size < 1024) |
| 495 | | stream_buffer_size = 1024; |
| 476 | // create the buffers |
| 477 | if (sdl_create_buffers()) |
| 478 | goto cant_create_buffers; |
| 496 | 479 | |
| 497 | | // create the buffers |
| 498 | | if (sdl_create_buffers()) |
| 499 | | goto cant_create_buffers; |
| 480 | // set the startup volume |
| 481 | set_mastervolume(attenuation); |
| 482 | osd_printf_verbose("Audio: End initialization\n"); |
| 483 | return 0; |
| 500 | 484 | |
| 501 | | osd_printf_verbose("Audio: End initialization\n"); |
| 502 | | return 0; |
| 485 | // error handling |
| 486 | cant_create_buffers: |
| 487 | cant_start_audio: |
| 488 | osd_printf_verbose("Audio: Initialization failed. SDL error: %s\n", SDL_GetError()); |
| 503 | 489 | |
| 504 | | // error handling |
| 505 | | cant_create_buffers: |
| 506 | | cant_start_audio: |
| 507 | | osd_printf_verbose("Audio: Initialization failed. SDL error: %s\n", SDL_GetError()); |
| 490 | return -1; |
| 491 | } |
| 508 | 492 | |
| 509 | | return 0; |
| 493 | return 0; |
| 510 | 494 | } |
| 511 | 495 | |
| 512 | 496 | |
| r243095 | r243096 | |
| 515 | 499 | // sdl_kill |
| 516 | 500 | //============================================================ |
| 517 | 501 | |
| 518 | | static void sdl_kill(running_machine &machine) |
| 502 | void sound_sdl::exit() |
| 519 | 503 | { |
| 520 | | if (initialized_audio) |
| 521 | | { |
| 522 | | osd_printf_verbose("sdl_kill: closing audio\n"); |
| 504 | // if nothing to do, don't do it |
| 505 | if (sample_rate() == 0) |
| 506 | return; |
| 523 | 507 | |
| 524 | | SDL_CloseAudio(); |
| 525 | | } |
| 508 | osd_printf_verbose("sdl_kill: closing audio\n"); |
| 509 | SDL_CloseAudio(); |
| 510 | |
| 526 | 511 | SDL_QuitSubSystem(SDL_INIT_AUDIO); |
| 512 | |
| 513 | // kill the buffers |
| 514 | sdl_destroy_buffers(); |
| 515 | |
| 516 | // print out over/underflow stats |
| 517 | if (buffer_overflows || buffer_underflows) |
| 518 | osd_printf_verbose("Sound buffer: overflows=%d underflows=%d\n", buffer_overflows, buffer_underflows); |
| 519 | |
| 520 | if (LOG_SOUND) |
| 521 | { |
| 522 | fprintf(sound_log, "Sound buffer: overflows=%d underflows=%d\n", buffer_overflows, buffer_underflows); |
| 523 | fclose(sound_log); |
| 524 | } |
| 527 | 525 | } |
| 528 | 526 | |
| 529 | 527 | |
| r243095 | r243096 | |
| 532 | 530 | // dsound_create_buffers |
| 533 | 531 | //============================================================ |
| 534 | 532 | |
| 535 | | static int sdl_create_buffers(void) |
| 533 | int sound_sdl::sdl_create_buffers(void) |
| 536 | 534 | { |
| 537 | 535 | osd_printf_verbose("sdl_create_buffers: creating stream buffer of %u bytes\n", stream_buffer_size); |
| 538 | 536 | |
| r243095 | r243096 | |
| 542 | 540 | return 0; |
| 543 | 541 | } |
| 544 | 542 | |
| 545 | | |
| 546 | | |
| 547 | 543 | //============================================================ |
| 548 | 544 | // sdl_destroy_buffers |
| 549 | 545 | //============================================================ |
| 550 | 546 | |
| 551 | | static void sdl_destroy_buffers(void) |
| 547 | void sound_sdl::sdl_destroy_buffers(void) |
| 552 | 548 | { |
| 553 | 549 | // release the buffer |
| 554 | 550 | if (stream_buffer) |
| 555 | 551 | global_free_array(stream_buffer); |
| 556 | 552 | stream_buffer = NULL; |
| 557 | 553 | } |
| 554 | |
| 555 | |
| 556 | |
| 557 | #else /* SDLMAME_UNIX */ |
| 558 | MODULE_NOT_SUPPORTED(sound_sdl, OSD_SOUND_PROVIDER, "sdl") |
| 559 | #endif |
| 560 | |
| 561 | MODULE_DEFINITION(SOUND_SDL, sound_sdl) |