Merge branch 'audio'

This commit is contained in:
Dmitry Marakasov 2014-11-30 01:08:22 +03:00
commit 8471330bbb
17 changed files with 654 additions and 0 deletions

View File

@ -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
@ -53,10 +60,12 @@ SET(LIBRARY_SOURCES
SDL2pp/SDL.cc
SDL2pp/Texture.cc
SDL2pp/TextureLock.cc
SDL2pp/Wav.cc
SDL2pp/Window.cc
)
SET(LIBRARY_HEADERS
SDL2pp/Audio.hh
SDL2pp/Exception.hh
SDL2pp/ExtraRWops.hh
SDL2pp/Point.hh
@ -66,6 +75,7 @@ SET(LIBRARY_HEADERS
SDL2pp/SDL.hh
SDL2pp/SDL2pp.hh
SDL2pp/Texture.hh
SDL2pp/Wav.hh
SDL2pp/Window.hh
)

112
SDL2pp/Audio.hh Normal file
View File

@ -0,0 +1,112 @@
/*
libSDL2pp - C++ wrapper for libSDL2
Copyright (C) 2014 Dmitry Marakasov <amdmi3@amdmi3.ru>
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 <functional>
#include <string>
#include <SDL2/SDL_audio.h>
#include <SDL2pp/Config.hh>
namespace SDL2pp {
class AudioSpec : public SDL_AudioSpec {
public:
typedef std::function<void(Uint8* stream, int len)> AudioCallback;
private:
AudioCallback callback_;
private:
static void SDLCallback(void *userdata, Uint8* stream, int len);
public:
AudioSpec();
AudioSpec(int freq, SDL_AudioFormat format, Uint8 channels, Uint16 samples, AudioCallback&& callback = AudioCallback());
AudioSpec(const AudioSpec& other, AudioCallback&& callback = AudioCallback());
~AudioSpec();
AudioSpec(AudioSpec&& other);
AudioSpec& operator=(AudioSpec&& other);
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;
bool IsSameFormat(const AudioSpec& other) 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

94
SDL2pp/AudioDevice.cc Normal file
View File

@ -0,0 +1,94 @@
/*
libSDL2pp - C++ wrapper for libSDL2
Copyright (C) 2014 Dmitry Marakasov <amdmi3@amdmi3.ru>
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 <SDL2pp/Exception.hh>
#include <SDL2pp/Audio.hh>
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
}

47
SDL2pp/AudioLock.cc Normal file
View File

@ -0,0 +1,47 @@
/*
libSDL2pp - C++ wrapper for libSDL2
Copyright (C) 2014 Dmitry Marakasov <amdmi3@amdmi3.ru>
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 <SDL2pp/Audio.hh>
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;
}
}

82
SDL2pp/AudioSpec.cc Normal file
View File

@ -0,0 +1,82 @@
/*
libSDL2pp - C++ wrapper for libSDL2
Copyright (C) 2014 Dmitry Marakasov <amdmi3@amdmi3.ru>
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 <algorithm>
#include <SDL2pp/Audio.hh>
namespace SDL2pp {
void AudioSpec::SDLCallback(void *userdata, Uint8* stream, int len) {
AudioSpec* audiospec = static_cast<AudioSpec*>(userdata);
audiospec->callback_(stream, len);
}
AudioSpec::AudioSpec() {
std::fill((char*)this, (char*)this + sizeof(SDL_AudioSpec), 0);
}
AudioSpec::AudioSpec(int freq, SDL_AudioFormat format, Uint8 channels, Uint16 samples, AudioSpec::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;
if (callback) {
SDL_AudioSpec::callback = SDLCallback;
SDL_AudioSpec::userdata = static_cast<void*>(this);
}
}
AudioSpec::AudioSpec(const AudioSpec& other, AudioSpec::AudioCallback&& callback) : SDL_AudioSpec(*other.Get()), callback_(std::move(callback)) {
if (callback) {
SDL_AudioSpec::callback = SDLCallback;
SDL_AudioSpec::userdata = static_cast<void*>(this);
}
}
AudioSpec::~AudioSpec() {
}
AudioSpec::AudioSpec(AudioSpec&&) = default;
AudioSpec& AudioSpec::operator=(AudioSpec&&) = 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<const SDL_AudioSpec*>(this);
}
bool AudioSpec::IsSameFormat(const AudioSpec& other) const {
return freq == other.freq && format == other.format && channels == other.channels;
}
}

View File

@ -23,5 +23,6 @@
#define SDL2PP_CONFIG_HH
#cmakedefine SDL2PP_WITH_IMAGE
#cmakedefine SDL2PP_NEW_2_0_4
#endif

View File

@ -26,6 +26,7 @@
#include <SDL2pp/Config.hh>
#include <SDL2pp/SDL.hh>
#include <SDL2pp/Audio.hh>
#include <SDL2pp/Window.hh>
#include <SDL2pp/Renderer.hh>
#include <SDL2pp/Texture.hh>
@ -33,5 +34,6 @@
#include <SDL2pp/Point.hh>
#include <SDL2pp/RWops.hh>
#include <SDL2pp/ExtraRWops.hh>
#include <SDL2pp/Wav.hh>
#endif

76
SDL2pp/Wav.cc Normal file
View File

@ -0,0 +1,76 @@
/*
libSDL2pp - C++ wrapper for libSDL2
Copyright (C) 2014 Dmitry Marakasov <amdmi3@amdmi3.ru>
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 <SDL2pp/Exception.hh>
#include <SDL2pp/RWops.hh>
#include <SDL2pp/Wav.hh>
namespace SDL2pp {
Wav::Wav(const std::string& file) {
if (SDL_LoadWAV(file.c_str(), &spec_, &audio_buffer_, &audio_length_) == nullptr)
throw Exception("SDL_LoadWAV failed");
}
Wav::Wav(RWops& rwops) {
if (SDL_LoadWAV_RW(rwops.Get(), 0, &spec_, &audio_buffer_, &audio_length_) == nullptr)
throw Exception("SDL_LoadWAV failed");
}
Wav::~Wav() {
if (audio_buffer_ != nullptr)
SDL_FreeWAV(audio_buffer_);
}
Wav::Wav(Wav&& other) : audio_buffer_(other.audio_buffer_), audio_length_(other.audio_length_), spec_(std::move(other.spec_)) {
other.audio_buffer_ = nullptr;
other.audio_length_ = 0;
}
Wav& Wav::operator=(Wav&& other) {
spec_ = std::move(other.spec_);
audio_buffer_ = other.audio_buffer_;
audio_length_ = other.audio_length_;
other.audio_buffer_ = nullptr;
other.audio_length_ = 0;
return *this;
}
Uint32 Wav::GetLength() const {
return audio_length_;
}
Uint8* Wav::GetBuffer() {
return audio_buffer_;
}
const Uint8* Wav::GetBuffer() const {
return audio_buffer_;
}
const AudioSpec& Wav::GetSpec() const {
return spec_;
}
}

57
SDL2pp/Wav.hh Normal file
View File

@ -0,0 +1,57 @@
/*
libSDL2pp - C++ wrapper for libSDL2
Copyright (C) 2014 Dmitry Marakasov <amdmi3@amdmi3.ru>
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_WAV_HH
#define SDL2PP_WAV_HH
#include <SDL2pp/Audio.hh>
namespace SDL2pp {
class RWops;
class Wav {
private:
Uint8* audio_buffer_;
Uint32 audio_length_;
AudioSpec spec_;
public:
Wav(const std::string& file);
Wav(RWops& rwops);
~Wav();
Wav(Wav&& other);
Wav& operator=(Wav&& other);
Wav(const Wav& other) = delete;
Wav& operator=(const Wav& other) = delete;
Uint32 GetLength() const;
Uint8* GetBuffer();
const Uint8* GetBuffer() const;
const AudioSpec& GetSpec() const;
};
}
#endif

View File

@ -9,6 +9,12 @@ TARGET_LINK_LIBRARIES(lines SDL2pp)
ADD_EXECUTABLE(rendertarget rendertarget.cc)
TARGET_LINK_LIBRARIES(rendertarget SDL2pp)
ADD_EXECUTABLE(audio_sine audio_sine.cc)
TARGET_LINK_LIBRARIES(audio_sine SDL2pp)
ADD_EXECUTABLE(audio_wav audio_wav.cc)
TARGET_LINK_LIBRARIES(audio_wav SDL2pp)
IF(SDL2PP_WITH_IMAGE)
ADD_EXECUTABLE(image image.cc)
TARGET_LINK_LIBRARIES(image SDL2pp)

67
demos/audio_sine.cc Normal file
View File

@ -0,0 +1,67 @@
/*
libSDL2pp - C++ wrapper for libSDL2
Copyright (C) 2013-2014 Dmitry Marakasov <amdmi3@amdmi3.ru>
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 <iostream>
#include <SDL2/SDL.h>
#include <SDL2pp/SDL2pp.hh>
using namespace SDL2pp;
int Run() {
SDL sdl(SDL_INIT_AUDIO);
const int samplerate = 48000;
float frequency = 2093.00f; // C7 tone
int64_t nsample = 0;
// Setup audio device, and provide callback which plays sine wave with specified frequency
AudioSpec spec(samplerate, AUDIO_S16SYS, 1, 4096, [&nsample, frequency, samplerate](Uint8* stream, int len) {
// fill provided buffer with sine wave
for (Uint8* ptr = stream; ptr < stream + len; ptr += 2)
*(Uint16*)ptr = (Uint16)(32766.0f * sin(nsample++ / (float)samplerate * frequency));
}
);
// Open audio device
AudioDevice dev("", 0, spec);
// Sound plays after this call
dev.Pause(false);
// Play for 1 second, after which everything is stopped and closed
SDL_Delay(1000);
return 0;
}
int main() {
try {
return Run();
} catch (Exception& e) {
std::cerr << "Error: " << e.what() << " (" << e.GetSDLError() << ")" << std::endl;
} catch (std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
return -1;
}

83
demos/audio_wav.cc Normal file
View File

@ -0,0 +1,83 @@
/*
libSDL2pp - C++ wrapper for libSDL2
Copyright (C) 2013-2014 Dmitry Marakasov <amdmi3@amdmi3.ru>
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 <iostream>
#include <stdexcept>
#include <SDL2/SDL.h>
#include <SDL2pp/SDL2pp.hh>
using namespace SDL2pp;
int Run() {
SDL sdl(SDL_INIT_AUDIO);
Wav wav(TESTDATA_DIR "/test.wav");
// Setup audio device, and provide callback which plays looped wave sound
Uint8* wav_pos = wav.GetBuffer();
AudioSpec spec(wav.GetSpec(), [&wav, &wav_pos](Uint8* stream, int len) {
// Fill provided buffer with wave contents
Uint8* stream_pos = stream;
Uint8* stream_end = stream + len;
while (stream_pos < stream_end) {
Uint8* wav_end = wav.GetBuffer() + wav.GetLength();
int copylen = std::min(wav_end - wav_pos, stream_end - stream_pos);
std::copy(wav_pos, wav_pos + copylen, stream_pos);
stream_pos += copylen;
wav_pos += copylen;
if (wav_pos >= wav_end)
wav_pos = wav.GetBuffer();
}
}
);
// Open audio device
AudioDevice dev("", 0, spec);
// Ensure SDL has set up format conversion for us
if (!spec.IsSameFormat(wav.GetSpec()))
throw std::runtime_error("WAV format is not the same as output format");
// Sound plays after this call
dev.Pause(false);
// Play for 5 seconds, after which everything is stopped and closed
SDL_Delay(5000);
return 0;
}
int main() {
try {
return Run();
} catch (Exception& e) {
std::cerr << "Error: " << e.what() << " (" << e.GetSDLError() << ")" << std::endl;
} catch (std::exception& e) {
std::cerr << "Error: " << e.what() << std::endl;
}
return -1;
}

5
testdata/README.md vendored Normal file
View File

@ -0,0 +1,5 @@
Some test data was taken from third party sources:
* ```test.wav``` is (C) CC-by Martin "JaZzy Jun69le" Pesek
* https://www.freesound.org/people/junggle/sounds/30341/
* http://profiles.google.com/jun66le

BIN
testdata/test.wav vendored Normal file

Binary file not shown.

View File

@ -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
@ -11,6 +12,7 @@ SET(HEADER_TESTS
header_sdl
header_sdl2pp
header_texture
header_wav
header_window
)

5
tests/header_audio.cc Normal file
View File

@ -0,0 +1,5 @@
#include <SDL2pp/Audio.hh>
int main() {
return 0;
}

5
tests/header_wav.cc Normal file
View File

@ -0,0 +1,5 @@
#include <SDL2pp/Wav.hh>
int main() {
return 0;
}