diff options
Diffstat (limited to 'src/osd/modules/sound/direct_sound.cpp')
-rw-r--r-- | src/osd/modules/sound/direct_sound.cpp | 459 |
1 files changed, 227 insertions, 232 deletions
diff --git a/src/osd/modules/sound/direct_sound.cpp b/src/osd/modules/sound/direct_sound.cpp index 4d6c8c26c50..7417def934c 100644 --- a/src/osd/modules/sound/direct_sound.cpp +++ b/src/osd/modules/sound/direct_sound.cpp @@ -11,236 +11,235 @@ #if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32) -// standard windows headers -#include <windows.h> -#include <mmsystem.h> - -// undef WINNT for dsound.h to prevent duplicate definition -#undef WINNT -#include <dsound.h> -#undef interface - // MAME headers -#include "emu.h" -#include "osdepend.h" #include "emuopts.h" +// osd headers +#include "modules/lib/osdobj_common.h" +#include "osdepend.h" +#include "osdcore.h" + #ifdef SDLMAME_WIN32 -#include "../../sdl/osdsdl.h" +#include "sdl/window.h" #include <SDL2/SDL_syswm.h> -#include "../../sdl/window.h" #else #include "winmain.h" #include "window.h" #endif + #include <utility> +// standard windows headers + +#include <windows.h> + +#include <mmreg.h> +#include <mmsystem.h> + +#include <dsound.h> + +#include <wrl/client.h> + + //============================================================ // DEBUGGING //============================================================ #define LOG_SOUND 0 -#define LOG(x) do { if (LOG_SOUND) osd_printf_verbose x; } while(0) +#define LOG(...) do { if (LOG_SOUND) osd_printf_verbose(__VA_ARGS__); } while(0) -class sound_direct_sound : public osd_module, public sound_module +namespace osd { + +namespace { + +class buffer_base { public: + explicit operator bool() const { return bool(m_buffer); } - sound_direct_sound() : - osd_module(OSD_SOUND_PROVIDER, "dsound"), - sound_module(), - m_dsound(nullptr), - m_bytes_per_sample(0), - m_primary_buffer(), - m_stream_buffer(), - m_stream_buffer_in(0), - m_buffer_underflows(0), - m_buffer_overflows(0) - { - } - virtual ~sound_direct_sound() { } + unsigned long release() { return m_buffer.Reset(); } - virtual int init(osd_options const &options) override; - virtual void exit() override; +protected: + Microsoft::WRL::ComPtr<IDirectSoundBuffer> m_buffer; +}; - // sound_module - virtual void update_audio_stream(bool is_throttled, int16_t const *buffer, int samples_this_frame) override; - virtual void set_mastervolume(int attenuation) override; -private: - class buffer +class primary_buffer : public buffer_base +{ +public: + HRESULT create(LPDIRECTSOUND dsound) { - public: - buffer() : m_buffer(nullptr) { } - ~buffer() { release(); } + assert(!m_buffer); + DSBUFFERDESC desc; + memset(&desc, 0, sizeof(desc)); + desc.dwSize = sizeof(desc); + desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_GETCURRENTPOSITION2; + desc.lpwfxFormat = nullptr; + return dsound->CreateSoundBuffer(&desc, &m_buffer, nullptr); + } - ULONG release() - { - ULONG const result = m_buffer ? m_buffer->Release() : 0; - m_buffer = nullptr; - return result; - } + HRESULT get_format(WAVEFORMATEX &format) const + { + assert(m_buffer); + return m_buffer->GetFormat(&format, sizeof(format), nullptr); + } - operator bool() const { return m_buffer; } + HRESULT set_format(WAVEFORMATEX const &format) const + { + assert(m_buffer); + return m_buffer->SetFormat(&format); + } +}; - protected: - LPDIRECTSOUNDBUFFER m_buffer; - }; - class primary_buffer : public buffer +class stream_buffer : public buffer_base +{ +public: + HRESULT create(LPDIRECTSOUND dsound, DWORD size, WAVEFORMATEX &format) { - public: - HRESULT create(LPDIRECTSOUND dsound) - { - assert(!m_buffer); - DSBUFFERDESC desc; - memset(&desc, 0, sizeof(desc)); - desc.dwSize = sizeof(desc); - desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_GETCURRENTPOSITION2; - desc.lpwfxFormat = nullptr; - return dsound->CreateSoundBuffer(&desc, &m_buffer, nullptr); - } + assert(!m_buffer); + DSBUFFERDESC desc; + memset(&desc, 0, sizeof(desc)); + desc.dwSize = sizeof(desc); + desc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2; + desc.dwBufferBytes = size; + desc.lpwfxFormat = &format; + m_size = size; + return dsound->CreateSoundBuffer(&desc, &m_buffer, nullptr); + } - HRESULT get_format(WAVEFORMATEX &format) const - { - assert(m_buffer); - return m_buffer->GetFormat(&format, sizeof(format), nullptr); - } - HRESULT set_format(WAVEFORMATEX const &format) const + HRESULT play_looping() const + { + assert(m_buffer); + return m_buffer->Play(0, 0, DSBPLAY_LOOPING); + } + HRESULT stop() const + { + assert(m_buffer); + return m_buffer->Stop(); + } + HRESULT get_current_positions(DWORD &play_pos, DWORD &write_pos) const + { + assert(m_buffer); + return m_buffer->GetCurrentPosition(&play_pos, &write_pos); + } + HRESULT copy_data(DWORD cursor, DWORD bytes, void const *data) + { + HRESULT result = lock(cursor, bytes); + if (DS_OK != result) + return result; + + assert(m_bytes1); + assert((m_locked1 + m_locked2) >= bytes); + memcpy(m_bytes1, data, std::min(m_locked1, bytes)); + if (m_locked1 < bytes) { - assert(m_buffer); - return m_buffer->SetFormat(&format); + assert(m_bytes2); + memcpy(m_bytes2, (uint8_t const *)data + m_locked1, bytes - m_locked1); } - }; - class stream_buffer : public buffer + unlock(); + return DS_OK; + } + HRESULT clear() { - public: - stream_buffer() : m_size(0), m_bytes1(nullptr), m_bytes2(nullptr), m_locked1(0), m_locked2(0) { } + HRESULT result = lock_all(); + if (DS_OK != result) + return result; - HRESULT create(LPDIRECTSOUND dsound, DWORD size, WAVEFORMATEX &format) - { - assert(!m_buffer); - DSBUFFERDESC desc; - memset(&desc, 0, sizeof(desc)); - desc.dwSize = sizeof(desc); - desc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2; - desc.dwBufferBytes = size; - desc.lpwfxFormat = &format; - m_size = size; - return dsound->CreateSoundBuffer(&desc, &m_buffer, nullptr); - } + assert(m_bytes1); + assert(!m_bytes2); + assert(m_size == m_locked1); + assert(0U == m_locked2); + memset(m_bytes1, 0, m_locked1); - HRESULT play_looping() const - { - assert(m_buffer); - return m_buffer->Play(0, 0, DSBPLAY_LOOPING); - } - HRESULT stop() const - { - assert(m_buffer); - return m_buffer->Stop(); - } - HRESULT set_volume(LONG volume) const - { - assert(m_buffer); - return m_buffer->SetVolume(volume); - } - HRESULT set_min_volume() { return set_volume(DSBVOLUME_MIN); } + unlock(); + return DS_OK; + } - HRESULT get_current_positions(DWORD &play_pos, DWORD &write_pos) const - { - assert(m_buffer); - return m_buffer->GetCurrentPosition(&play_pos, &write_pos); - } - HRESULT copy_data(DWORD cursor, DWORD bytes, void const *data) - { - HRESULT result = lock(cursor, bytes); - if (DS_OK != result) - return result; - - assert(m_bytes1); - assert((m_locked1 + m_locked2) >= bytes); - memcpy(m_bytes1, data, std::min(m_locked1, bytes)); - if (m_locked1 < bytes) - { - assert(m_bytes2); - memcpy(m_bytes2, (uint8_t const *)data + m_locked1, bytes - m_locked1); - } - - unlock(); - return DS_OK; - } - HRESULT clear() - { - HRESULT result = lock_all(); - if (DS_OK != result) - return result; - - assert(m_bytes1); - assert(!m_bytes2); - assert(m_size == m_locked1); - assert(0U == m_locked2); - memset(m_bytes1, 0, m_locked1); - - unlock(); - return DS_OK; - } + DWORD size() const { return m_size; } - DWORD size() const { return m_size; } +private: + HRESULT lock(DWORD cursor, DWORD bytes) + { + assert(cursor < m_size); + assert(bytes <= m_size); + assert(m_buffer); + assert(!m_bytes1); + return m_buffer->Lock( + cursor, bytes, + &m_bytes1, + &m_locked1, + &m_bytes2, + &m_locked2, + 0); + } + HRESULT lock_all() { return lock(0, m_size); } + HRESULT unlock() + { + assert(m_buffer); + assert(m_bytes1); + HRESULT const result = m_buffer->Unlock( + m_bytes1, + m_locked1, + m_bytes2, + m_locked2); + m_bytes1 = m_bytes2 = nullptr; + m_locked1 = m_locked2 = 0; + return result; + } - protected: - HRESULT lock(DWORD cursor, DWORD bytes) - { - assert(cursor < m_size); - assert(bytes <= m_size); - assert(m_buffer); - assert(!m_bytes1); - return m_buffer->Lock( - cursor, bytes, - &m_bytes1, - &m_locked1, - &m_bytes2, - &m_locked2, - 0); - } - HRESULT lock_all() { return lock(0, m_size); } - HRESULT unlock() - { - assert(m_buffer); - assert(m_bytes1); - HRESULT const result = m_buffer->Unlock( - m_bytes1, - m_locked1, - m_bytes2, - m_locked2); - m_bytes1 = m_bytes2 = nullptr; - m_locked1 = m_locked2 = 0; - return result; - } + DWORD m_size = 0; + void *m_bytes1 = nullptr, *m_bytes2 = nullptr; + DWORD m_locked1 = 0, m_locked2 = 0; +}; - DWORD m_size; - void *m_bytes1, *m_bytes2; - DWORD m_locked1, m_locked2; - }; +class sound_direct_sound : public osd_module, public sound_module +{ +public: + sound_direct_sound() : + osd_module(OSD_SOUND_PROVIDER, "dsound"), + sound_module(), + m_sample_rate(0), + m_audio_latency(0), + m_bytes_per_sample(0), + m_primary_buffer(), + m_stream_buffer(), + m_stream_buffer_in(0), + m_buffer_underflows(0), + m_buffer_overflows(0) + { + } + + virtual int init(osd_interface &osd, osd_options const &options) override; + virtual void exit() override; + + // sound_module + virtual void stream_sink_update(uint32_t, int16_t const *buffer, int samples_this_frame) override; + +private: HRESULT dsound_init(); void dsound_kill(); HRESULT create_buffers(DWORD size, WAVEFORMATEX &format); void destroy_buffers(); // DirectSound objects - LPDIRECTSOUND m_dsound; + Microsoft::WRL::ComPtr<IDirectSound> m_dsound; + + // configuration + int m_sample_rate; + int m_audio_latency; // descriptors and formats - uint32_t m_bytes_per_sample; + uint32_t m_bytes_per_sample; // sound buffers primary_buffer m_primary_buffer; stream_buffer m_stream_buffer; - uint32_t m_stream_buffer_in; + uint32_t m_stream_buffer_in; // buffer over/underflow counts unsigned m_buffer_underflows; @@ -252,12 +251,16 @@ private: // init //============================================================ -int sound_direct_sound::init(osd_options const &options) +int sound_direct_sound::init(osd_interface &osd, osd_options const &options) { - // attempt to initialize directsound - // don't make it fatal if we can't -- we'll just run without sound - dsound_init(); + m_sample_rate = options.sample_rate(); + m_audio_latency = options.audio_latency(); m_buffer_underflows = m_buffer_overflows = 0; + + // attempt to initialize DirectSound + if (dsound_init() != DS_OK) + return -1; + return 0; } @@ -281,16 +284,16 @@ void sound_direct_sound::exit() m_buffer_underflows); } - LOG(("Sound buffer: overflows=%u underflows=%u\n", m_buffer_overflows, m_buffer_underflows)); + LOG("Sound buffer: overflows=%u underflows=%u\n", m_buffer_overflows, m_buffer_underflows); } //============================================================ -// update_audio_stream +// stream_sink_update //============================================================ -void sound_direct_sound::update_audio_stream( - bool is_throttled, +void sound_direct_sound::stream_sink_update( + uint32_t, int16_t const *buffer, int samples_this_frame) { @@ -307,7 +310,7 @@ void sound_direct_sound::update_audio_stream( if (DS_OK != result) return; -//DWORD orig_write = write_position; + //DWORD orig_write = write_position; // normalize the write position so it is always after the play position if (write_position < play_position) write_position += m_stream_buffer.size(); @@ -323,7 +326,7 @@ void sound_direct_sound::update_audio_stream( // if we're between play and write positions, then bump forward, but only in full chunks while (stream_in < write_position) { -//printf("Underflow: PP=%d WP=%d(%d) SI=%d(%d) BTF=%d\n", (int)play_position, (int)write_position, (int)orig_write, (int)stream_in, (int)m_stream_buffer_in, (int)bytes_this_frame); + //printf("Underflow: PP=%d WP=%d(%d) SI=%d(%d) BTF=%d\n", (int)play_position, (int)write_position, (int)orig_write, (int)stream_in, (int)m_stream_buffer_in, (int)bytes_this_frame); m_buffer_underflows++; stream_in += bytes_this_frame; } @@ -331,7 +334,7 @@ void sound_direct_sound::update_audio_stream( // if we're going to overlap the play position, just skip this chunk if ((stream_in + bytes_this_frame) > (play_position + m_stream_buffer.size())) { -//printf("Overflow: PP=%d WP=%d(%d) SI=%d(%d) BTF=%d\n", (int)play_position, (int)write_position, (int)orig_write, (int)stream_in, (int)m_stream_buffer_in, (int)bytes_this_frame); + //printf("Overflow: PP=%d WP=%d(%d) SI=%d(%d) BTF=%d\n", (int)play_position, (int)write_position, (int)orig_write, (int)stream_in, (int)m_stream_buffer_in, (int)bytes_this_frame); m_buffer_overflows++; return; } @@ -353,26 +356,6 @@ void sound_direct_sound::update_audio_stream( //============================================================ -// set_mastervolume -//============================================================ - -void sound_direct_sound::set_mastervolume(int attenuation) -{ - // clamp the attenuation to 0-32 range - attenuation = std::max(std::min(attenuation, 0), -32); - - // set the master volume - if (m_stream_buffer) - { - if (-32 == attenuation) - m_stream_buffer.set_min_volume(); - else - m_stream_buffer.set_volume(100 * attenuation); - } -} - - -//============================================================ // dsound_init //============================================================ @@ -385,7 +368,7 @@ HRESULT sound_direct_sound::dsound_init() result = DirectSoundCreate(nullptr, &m_dsound, nullptr); if (result != DS_OK) { - osd_printf_error("Error creating DirectSound: %08x\n", (unsigned)result); + osd_printf_error("Error creating DirectSound: %08x\n", result); goto error; } @@ -395,7 +378,7 @@ HRESULT sound_direct_sound::dsound_init() result = m_dsound->GetCaps(&dsound_caps); if (result != DS_OK) { - osd_printf_error("Error getting DirectSound capabilities: %08x\n", (unsigned)result); + osd_printf_error("Error getting DirectSound capabilities: %08x\n", result); goto error; } @@ -404,34 +387,40 @@ HRESULT sound_direct_sound::dsound_init() #ifdef SDLMAME_WIN32 SDL_SysWMinfo wminfo; SDL_VERSION(&wminfo.version); - SDL_GetWindowWMInfo(std::dynamic_pointer_cast<sdl_window_info>(osd_common_t::s_window_list.front())->platform_window(), &wminfo); + if (!SDL_GetWindowWMInfo(dynamic_cast<sdl_window_info &>(*osd_common_t::window_list().front()).platform_window(), &wminfo)) + { + result = DSERR_UNSUPPORTED; // just so it has something to return + goto error; + } HWND const window = wminfo.info.win.window; #else // SDLMAME_WIN32 - HWND const window = std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front())->platform_window(); + HWND const window = dynamic_cast<win_window_info &>(*osd_common_t::window_list().front()).platform_window(); #endif // SDLMAME_WIN32 result = m_dsound->SetCooperativeLevel(window, DSSCL_PRIORITY); } if (result != DS_OK) { - osd_printf_error("Error setting DirectSound cooperative level: %08x\n", (unsigned)result); + osd_printf_error("Error setting DirectSound cooperative level: %08x\n", result); goto error; } { // make a format description for what we want WAVEFORMATEX stream_format; - stream_format.wBitsPerSample = 16; stream_format.wFormatTag = WAVE_FORMAT_PCM; stream_format.nChannels = 2; - stream_format.nSamplesPerSec = sample_rate(); + stream_format.nSamplesPerSec = m_sample_rate; + stream_format.wBitsPerSample = 16; stream_format.nBlockAlign = stream_format.wBitsPerSample * stream_format.nChannels / 8; stream_format.nAvgBytesPerSec = stream_format.nSamplesPerSec * stream_format.nBlockAlign; + stream_format.cbSize = 0; // compute the buffer size based on the output sample rate - DWORD stream_buffer_size = stream_format.nSamplesPerSec * stream_format.nBlockAlign * m_audio_latency / 10; + int audio_latency = std::max(m_audio_latency, 1); + DWORD stream_buffer_size = stream_format.nSamplesPerSec * stream_format.nBlockAlign * audio_latency / 10; stream_buffer_size = std::max(DWORD(1024), (stream_buffer_size / 1024) * 1024); - LOG(("stream_buffer_size = %u\n", (unsigned)stream_buffer_size)); + LOG("stream_buffer_size = %u\n", stream_buffer_size); // create the buffers m_bytes_per_sample = stream_format.nBlockAlign; @@ -445,7 +434,7 @@ HRESULT sound_direct_sound::dsound_init() result = m_stream_buffer.play_looping(); if (result != DS_OK) { - osd_printf_error("Error playing: %08x\n", (uint32_t)result); + osd_printf_error("Error playing: %08x\n", result); goto error; } return DS_OK; @@ -465,9 +454,7 @@ error: void sound_direct_sound::dsound_kill() { // release the object - if (m_dsound) - m_dsound->Release(); - m_dsound = nullptr; + m_dsound.Reset(); } @@ -483,10 +470,10 @@ HRESULT sound_direct_sound::create_buffers(DWORD size, WAVEFORMATEX &format) HRESULT result; // create the primary buffer - result = m_primary_buffer.create(m_dsound); + result = m_primary_buffer.create(m_dsound.Get()); if (result != DS_OK) { - osd_printf_error("Error creating primary DirectSound buffer: %08x\n", (unsigned)result); + osd_printf_error("Error creating primary DirectSound buffer: %08x\n", result); goto error; } @@ -494,7 +481,7 @@ HRESULT sound_direct_sound::create_buffers(DWORD size, WAVEFORMATEX &format) result = m_primary_buffer.set_format(format); if (result != DS_OK) { - osd_printf_error("Error setting primary DirectSound buffer format: %08x\n", (unsigned)result); + osd_printf_error("Error setting primary DirectSound buffer format: %08x\n", result); goto error; } @@ -503,20 +490,20 @@ HRESULT sound_direct_sound::create_buffers(DWORD size, WAVEFORMATEX &format) result = m_primary_buffer.get_format(primary_format); if (result != DS_OK) { - osd_printf_error("Error getting primary DirectSound buffer format: %08x\n", (unsigned)result); + osd_printf_error("Error getting primary DirectSound buffer format: %08x\n", result); goto error; } osd_printf_verbose( "DirectSound: Primary buffer: %d Hz, %d bits, %d channels\n", - (int)primary_format.nSamplesPerSec, - (int)primary_format.wBitsPerSample, - (int)primary_format.nChannels); + primary_format.nSamplesPerSec, + primary_format.wBitsPerSample, + primary_format.nChannels); // create the stream buffer - result = m_stream_buffer.create(m_dsound, size, format); + result = m_stream_buffer.create(m_dsound.Get(), size, format); if (result != DS_OK) { - osd_printf_error("Error creating DirectSound stream buffer: %08x\n", (unsigned)result); + osd_printf_error("Error creating DirectSound stream buffer: %08x\n", result); goto error; } @@ -524,7 +511,7 @@ HRESULT sound_direct_sound::create_buffers(DWORD size, WAVEFORMATEX &format) result = m_stream_buffer.clear(); if (result != DS_OK) { - osd_printf_error("Error locking DirectSound stream buffer: %08x\n", (unsigned)result); + osd_printf_error("Error locking DirectSound stream buffer: %08x\n", result); goto error; } @@ -541,7 +528,7 @@ error: // destroy_buffers //============================================================ -void sound_direct_sound::destroy_buffers(void) +void sound_direct_sound::destroy_buffers() { // stop any playback if (m_stream_buffer) @@ -554,8 +541,16 @@ void sound_direct_sound::destroy_buffers(void) m_primary_buffer.release(); } +} // anonymous namespace + +} // namespace osd + + #else // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32) - MODULE_NOT_SUPPORTED(sound_direct_sound, OSD_SOUND_PROVIDER, "dsound") + +namespace osd { namespace { MODULE_NOT_SUPPORTED(sound_direct_sound, OSD_SOUND_PROVIDER, "dsound") } } + #endif // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32) -MODULE_DEFINITION(SOUND_DSOUND, sound_direct_sound) + +MODULE_DEFINITION(SOUND_DSOUND, osd::sound_direct_sound) |