diff --git a/CMakeLists.txt b/CMakeLists.txt index 50f43e0..96f0c5a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,10 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8) SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) +# there are functions present on wiki, but not yet in stable SDL2 releases; +# we hide these under following options +OPTION(SDL2PP_NEW_2_0_4 "Enable new SDL2 functions present since SDL2 2.0.4" OFF) + IF(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) OPTION(SDL2PP_WITH_IMAGE "Enable SDL2_image support" ON) ELSE(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR) @@ -45,6 +49,9 @@ INCLUDE_DIRECTORIES(BEFORE ${PROJECT_BINARY_DIR}) # sources SET(LIBRARY_SOURCES + SDL2pp/AudioDevice.cc + SDL2pp/AudioLock.cc + SDL2pp/AudioSpec.cc SDL2pp/Exception.cc SDL2pp/Point.cc SDL2pp/RWops.cc @@ -57,6 +64,7 @@ SET(LIBRARY_SOURCES ) SET(LIBRARY_HEADERS + SDL2pp/Audio.hh SDL2pp/Exception.hh SDL2pp/ExtraRWops.hh SDL2pp/Point.hh diff --git a/SDL2pp/Audio.hh b/SDL2pp/Audio.hh new file mode 100644 index 0000000..6158753 --- /dev/null +++ b/SDL2pp/Audio.hh @@ -0,0 +1,108 @@ +/* + libSDL2pp - C++ wrapper for libSDL2 + Copyright (C) 2014 Dmitry Marakasov + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL2PP_AUDIO_HH +#define SDL2PP_AUDIO_HH + +#include +#include + +#include + +#include + +namespace SDL2pp { + +class AudioSpec : public SDL_AudioSpec { +public: + typedef std::function AudioCallback; + +private: + AudioCallback callback_; + +private: + static void SDLCallback(void *userdata, Uint8* stream, int len); + +public: + AudioSpec(int freq, SDL_AudioFormat format, Uint8 channels, Uint16 samples, AudioCallback&& callback); + ~AudioSpec(); + + AudioSpec(AudioSpec&& other) noexcept; + AudioSpec& operator=(AudioSpec&& other) noexcept; + AudioSpec(const AudioSpec& other) = delete; + AudioSpec& operator=(const AudioSpec& other) = delete; + + void ChangeCallback(AudioCallback&& callback); // should be called with audio device using this spec locked! + + void MergeChanges(const SDL_AudioSpec& obtained); + const SDL_AudioSpec* Get() const; +}; + +class AudioDevice { +private: + SDL_AudioDeviceID device_id_; + +public: + class LockHandle { + friend class AudioDevice; + private: + AudioDevice* device_; + + private: + LockHandle(AudioDevice* device); + + public: + ~LockHandle(); + + LockHandle(LockHandle&& other) noexcept; + LockHandle& operator=(LockHandle&& other) noexcept; + + LockHandle(const LockHandle& other) = delete; + LockHandle& operator=(const LockHandle& other) = delete; + }; + +public: + AudioDevice(const std::string& device, bool iscapture, const AudioSpec& spec); + AudioDevice(const std::string& device, bool iscapture, AudioSpec& spec, int allowed_changes); + virtual ~AudioDevice(); + + AudioDevice(const AudioDevice& other) = delete; + AudioDevice(AudioDevice&& other) noexcept; + AudioDevice& operator=(const AudioDevice& other) = delete; + AudioDevice& operator=(AudioDevice&& other) noexcept; + + SDL_AudioDeviceID Get() const; + + void Pause(bool pause_on); + SDL_AudioStatus GetStatus() const; + + LockHandle Lock(); + +#ifdef SDL2PP_NEW_2_0_4 + void QueueAudio(const void* data, Uint32 len); + void ClearQueuedAudio(); + Uint32 GetQueuedAudioSize() const; +#endif +}; + +} + +#endif diff --git a/SDL2pp/AudioDevice.cc b/SDL2pp/AudioDevice.cc new file mode 100644 index 0000000..b30b4e6 --- /dev/null +++ b/SDL2pp/AudioDevice.cc @@ -0,0 +1,94 @@ +/* + libSDL2pp - C++ wrapper for libSDL2 + Copyright (C) 2014 Dmitry Marakasov + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include + +#include + +namespace SDL2pp { + +AudioDevice::AudioDevice(const std::string& device, bool iscapture, const AudioSpec& spec) { + SDL_AudioSpec obtained; + + if ((device_id_ = SDL_OpenAudioDevice(device.empty() ? nullptr : device.c_str(), iscapture ? 1 : 0, &spec, &obtained, 0)) == 0) + throw Exception("SDL_OpenAudioDevice failed"); +} + +AudioDevice::AudioDevice(const std::string& device, bool iscapture, AudioSpec& spec, int allowed_changes) { + SDL_AudioSpec obtained; + + if ((device_id_ = SDL_OpenAudioDevice(device.empty() ? nullptr : device.c_str(), iscapture ? 1 : 0, &spec, &obtained, allowed_changes)) == 0) + throw Exception("SDL_OpenAudioDevice failed"); + + spec.MergeChanges(obtained); +} + +AudioDevice::~AudioDevice() { + if (device_id_ != 0) + SDL_CloseAudioDevice(device_id_); +} + +AudioDevice::AudioDevice(AudioDevice&& other) noexcept : device_id_(other.device_id_) { + other.device_id_ = 0; +} + +AudioDevice& AudioDevice::operator=(AudioDevice&& other) noexcept { + if (device_id_) + SDL_CloseAudioDevice(device_id_); + + device_id_ = other.device_id_; + other.device_id_ = 0; + + return *this; +} + +SDL_AudioDeviceID AudioDevice::Get() const { + return device_id_; +} + +void AudioDevice::Pause(bool pause_on) { + SDL_PauseAudioDevice(device_id_, pause_on ? 1 : 0); +} + +SDL_AudioStatus AudioDevice::GetStatus() const { + return SDL_GetAudioDeviceStatus(device_id_); +} + +AudioDevice::LockHandle AudioDevice::Lock() { + return LockHandle(this); +} + +#ifdef SDL2PP_NEW_2_0_4 +void AudioDevice::QueueAudio(const void* data, Uint32 len) { + if (SDL_QueueAudio(device_id_, data, len) == 0) + throw Exception("SDL_QueueAudio failed"); +} + +void AudioDevice::ClearQueuedAudio() { + SDL_ClearQueuedAudio(device_id_); +} + +Uint32 GetQueuedAudioSize() const { + return SDL_GetQueuedAudioSize(device_id_); +} +#endif + +} diff --git a/SDL2pp/AudioLock.cc b/SDL2pp/AudioLock.cc new file mode 100644 index 0000000..3709da4 --- /dev/null +++ b/SDL2pp/AudioLock.cc @@ -0,0 +1,47 @@ +/* + libSDL2pp - C++ wrapper for libSDL2 + Copyright (C) 2014 Dmitry Marakasov + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include + +namespace SDL2pp { + +AudioDevice::LockHandle::LockHandle(AudioDevice* device) : device_(device) { + SDL_LockAudioDevice(device_->device_id_); +} + +AudioDevice::LockHandle::~LockHandle() { + if (device_ != nullptr) + SDL_UnlockAudioDevice(device_->device_id_); +} + +AudioDevice::LockHandle::LockHandle(AudioDevice::LockHandle&& other) noexcept : device_(other.device_) { + other.device_ = nullptr; +} + +AudioDevice::LockHandle& AudioDevice::LockHandle::operator=(AudioDevice::LockHandle&& other) noexcept { + device_ = other.device_; + + other.device_ = nullptr; + + return *this; +} + +} diff --git a/SDL2pp/AudioSpec.cc b/SDL2pp/AudioSpec.cc new file mode 100644 index 0000000..2e75e9d --- /dev/null +++ b/SDL2pp/AudioSpec.cc @@ -0,0 +1,65 @@ +/* + libSDL2pp - C++ wrapper for libSDL2 + Copyright (C) 2014 Dmitry Marakasov + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include + +#include + +namespace SDL2pp { + +void AudioSpec::SDLCallback(void *userdata, Uint8* stream, int len) { + AudioSpec* audiospec = static_cast(userdata); + audiospec->callback_(stream, len); +} + +AudioSpec::AudioSpec(int freq, SDL_AudioFormat format, Uint8 channels, Uint16 samples, AudioCallback&& callback) + : callback_(std::move(callback)) { + std::fill((char*)this, (char*)this + sizeof(SDL_AudioSpec), 0); + SDL_AudioSpec::freq = freq; + SDL_AudioSpec::format = format; + SDL_AudioSpec::channels = channels; + SDL_AudioSpec::samples = samples; + SDL_AudioSpec::callback = SDLCallback; + SDL_AudioSpec::userdata = static_cast(this); +} + +AudioSpec::~AudioSpec() { +} + +AudioSpec::AudioSpec(AudioSpec&&) noexcept = default; +AudioSpec& AudioSpec::operator=(AudioSpec&&) noexcept = default; + +void AudioSpec::ChangeCallback(AudioCallback&& callback) { + callback_ = callback; +} + +void AudioSpec::MergeChanges(const SDL_AudioSpec& obtained) { + freq = obtained.freq; + format = obtained.format; + channels = obtained.channels; + samples = obtained.samples; +} + +const SDL_AudioSpec* AudioSpec::Get() const { + return static_cast(this); +} + +} diff --git a/SDL2pp/Config.hh.in b/SDL2pp/Config.hh.in index 75af7f2..394f4b3 100644 --- a/SDL2pp/Config.hh.in +++ b/SDL2pp/Config.hh.in @@ -23,5 +23,6 @@ #define SDL2PP_CONFIG_HH #cmakedefine SDL2PP_WITH_IMAGE +#cmakedefine SDL2PP_NEW_2_0_4 #endif diff --git a/SDL2pp/SDL2pp.hh b/SDL2pp/SDL2pp.hh index a4ffd40..19c063e 100644 --- a/SDL2pp/SDL2pp.hh +++ b/SDL2pp/SDL2pp.hh @@ -26,6 +26,7 @@ #include #include +#include #include #include #include diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 7041e12..c06bd0e 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -2,6 +2,7 @@ # they are compilable (e.g., includes and forward declarations are # complete and do not require extra includes) SET(HEADER_TESTS + header_audio header_exception header_point header_rect diff --git a/tests/header_audio.cc b/tests/header_audio.cc new file mode 100644 index 0000000..fd3178a --- /dev/null +++ b/tests/header_audio.cc @@ -0,0 +1,5 @@ +#include + +int main() { + return 0; +}