From fdf878d4586393d1425e34b9f30eb1e9015c6db9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 11 Aug 2013 11:17:31 +0200 Subject: [PATCH] Audio: added Source class. --- src/Audio/Audio.h | 1 + src/Audio/CMakeLists.txt | 4 +- src/Audio/Source.cpp | 123 +++++++ src/Audio/Source.h | 596 ++++++++++++++++++++++++++++++++++ src/Audio/Test/CMakeLists.txt | 1 + src/Audio/Test/SourceTest.cpp | 51 +++ 6 files changed, 775 insertions(+), 1 deletion(-) create mode 100644 src/Audio/Source.cpp create mode 100644 src/Audio/Source.h create mode 100644 src/Audio/Test/SourceTest.cpp diff --git a/src/Audio/Audio.h b/src/Audio/Audio.h index c02b8d6be..5fc044cd0 100644 --- a/src/Audio/Audio.h +++ b/src/Audio/Audio.h @@ -31,6 +31,7 @@ namespace Magnum { namespace Audio { class Buffer; +class Source; /* Renderer used only statically */ }} diff --git a/src/Audio/CMakeLists.txt b/src/Audio/CMakeLists.txt index 0c4691014..eeafc6e22 100644 --- a/src/Audio/CMakeLists.txt +++ b/src/Audio/CMakeLists.txt @@ -29,12 +29,14 @@ include_directories(${OPENAL_INCLUDE_DIR}) set(MagnumAudio_SOURCES Audio.cpp Buffer.cpp - Renderer.cpp) + Renderer.cpp + Source.cpp) set(MagnumAudio_HEADERS Audio.h Buffer.h Renderer.h + Source.h magnumAudioVisibility.h) diff --git a/src/Audio/Source.cpp b/src/Audio/Source.cpp new file mode 100644 index 000000000..8eba148bc --- /dev/null +++ b/src/Audio/Source.cpp @@ -0,0 +1,123 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include "Source.h" + +#include "Audio/Buffer.h" + +namespace Magnum { namespace Audio { + +/** @todo C++14: use VLA to avoid unnecessary allocations */ + +Source& Source::setBuffer(Buffer* buffer) { + alSourcei(_id, AL_BUFFER, buffer ? buffer->id() : 0); + return *this; +} + +namespace { + +const ALuint* sourceIds(const std::initializer_list& sources) { + ALuint* const ids = new ALuint[sources.size()]; + for(auto it = sources.begin(); it != sources.end(); ++it) { + CORRADE_INTERNAL_ASSERT(*it); + ids[it-sources.begin()] = (*it)->id(); + } + return ids; +} + +const ALuint* sourceIds(const std::vector& sources) { + ALuint* const ids = new ALuint[sources.size()]; + for(auto it = sources.begin(); it != sources.end(); ++it) { + CORRADE_INTERNAL_ASSERT(*it); + ids[it-sources.begin()] = (*it)->id(); + } + return ids; +} + +} + +/** @todo Okay, this is too much code copying even for me */ + +void Source::play(std::initializer_list sources) { + const ALuint* const ids = sourceIds(sources); + alSourcePlayv(sources.size(), ids); + delete[] ids; +} + +void Source::play(const std::vector& sources) { + const ALuint* const ids = sourceIds(sources); + alSourcePlayv(sources.size(), ids); + delete[] ids; +} + +void Source::pause(std::initializer_list sources) { + const ALuint* const ids = sourceIds(sources); + alSourcePausev(sources.size(), ids); + delete[] ids; +} + +void Source::pause(const std::vector& sources) { + const ALuint* const ids = sourceIds(sources); + alSourcePausev(sources.size(), ids); + delete[] ids; +} + +void Source::stop(std::initializer_list sources) { + const ALuint* const ids = sourceIds(sources); + alSourceStopv(sources.size(), ids); + delete[] ids; +} + +void Source::stop(const std::vector& sources) { + const ALuint* const ids = sourceIds(sources); + alSourceStopv(sources.size(), ids); + delete[] ids; +} + +void Source::rewind(std::initializer_list sources) { + const ALuint* const ids = sourceIds(sources); + alSourceRewindv(sources.size(), ids); + delete[] ids; +} + +void Source::rewind(const std::vector& sources) { + const ALuint* const ids = sourceIds(sources); + alSourceRewindv(sources.size(), ids); + delete[] ids; +} + +Debug operator<<(Debug debug, const Source::State value) { + switch(value) { + #define _c(value) case Source::State::value: return debug << "Audio::Source::State::" #value; + _c(Initial) + _c(Playing) + _c(Paused) + _c(Stopped) + #undef _c + } + + return debug << "Audio::Source::State::(invalid)"; +} + +}} diff --git a/src/Audio/Source.h b/src/Audio/Source.h new file mode 100644 index 000000000..f96de05c1 --- /dev/null +++ b/src/Audio/Source.h @@ -0,0 +1,596 @@ +#ifndef Magnum_Audio_Source_h +#define Magnum_Audio_Source_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +/** @file + * @brief Class Magnum::Audio::Source + */ + +#include +#include +#include + +#include "Math/Vector3.h" +#include "Magnum.h" +#include "Audio/Audio.h" +#include "Audio/magnumAudioVisibility.h" + +namespace Magnum { namespace Audio { + +/** +@brief %Source + +Manages positional audio source. +@todo Expose convenient API for buffer queuing +*/ +class MAGNUM_AUDIO_EXPORT Source { + public: + /** + * @brief Constructor + * + * Creates OpenAL source object. + * @see @fn_al{GenSources} + */ + explicit Source() { alGenSources(1, &_id); } + + /** + * @brief Destructor + * + * Deletes OpenAL source object. + * @see @fn_al{DeleteSources} + */ + ~Source() { if(_id) alDeleteSources(1, &_id); } + + /** @brief Copying is not allowed */ + Source(const Source&) = delete; + + /** @brief Move constructor */ + Source(Source&& other); + + /** @brief Copying is not allowed */ + Source& operator=(const Source&) = delete; + + /** @brief Move assignment */ + Source& operator=(Source&& other); + + /** @brief OpenAL source ID */ + ALuint id() const { return _id; } + + /** @{ @name Source positioning */ + + /** + * @brief Set position + * @return Reference to self (for method chaining) + * + * Default is `{0.0f, 0.0f, 0.0f}`. + * @see @ref setRelative(), @fn_al{Sourcefv} with @def_al{POSITION} + */ + Source& setPosition(const Vector3& position) { + alSourcefv(_id, AL_POSITION, position.data()); + return *this; + } + + /** @overload + * @see @fn_al{Sourceiv} with @def_al{POSITION} + */ + Source& setPosition(const Vector3i& position) { + alSourceiv(_id, AL_POSITION, position.data()); + return *this; + } + + /** + * @brief Set velocity + * @return Reference to self (for method chaining) + * + * Default is `{0.0f, 0.0f, 0.0f}`. + * @see @ref setRelative(), @fn_al{Sourcefv} with @def_al{VELOCITY} + */ + Source& setVelocity(const Vector3& velocity) { + alSourcefv(_id, AL_VELOCITY, velocity.data()); + return *this; + } + + /** @overload + * @see @fn_al{Sourceiv} with @def_al{VELOCITY} + */ + Source& setVelocity(const Vector3i& velocity) { + alSourceiv(_id, AL_VELOCITY, velocity.data()); + return *this; + } + + /** + * @brief Interpret source relatively to listener + * + * When enabled, source position, direction and velocity will be + * interpreted relatively to listener. Default is `false`. + * @see @ref setPosition(), @ref setDirection(), @ref setVelocity(), + * @fn_al{Sourcei} with @def_al{SOURCE_RELATIVE} + */ + Source& setRelative(bool relative) { + alSourcei(_id, AL_SOURCE_RELATIVE, relative); + return *this; + } + + /*@}*/ + + /** @{ @name Source behavior */ + + /** + * @brief Set gain + * @return Reference to self (for method chaining) + * + * Default is `1.0f`, which means that the sound is unattenuated. + * If set to `0.0f`, the source is muted. + * @see @ref setMinGain(), @ref setMaxGain(), @fn_al{Sourcef} with + * @def_al{GAIN} + */ + Source& setGain(Float gain) { + alSourcef(_id, AL_GAIN, gain); + return *this; + } + + /** + * @brief Set min gain + * @return Reference to self (for method chaining) + * + * If effective gain is lower than min gain, min gain is used. Note + * that this is done before listener gain is applied. Default is + * `0.0f`. + * @see @ref setMinGain(), @ref setGain(), @fn_al{Sourcef} with + * @def_al{MIN_GAIN} + */ + Source& setMinGain(Float gain) { + alSourcef(_id, AL_MIN_GAIN, gain); + return *this; + } + + /** + * @brief Set max gain + * @return Reference to self (for method chaining) + * + * If effective gain is higher than max gain, max gain is used. Note + * that this is done before listener gain is applied. Default is + * `1.0f`. If set to `0.0f`, the source is muted. + * @see @ref setMinGain(), @ref setGain(), @fn_al{Sourcef} with + * @def_al{MIN_GAIN} + */ + Source& setMaxGain(Float gain) { + alSourcef(_id, AL_MAX_GAIN, gain); + return *this; + } + + /** + * @brief Set reference distance + * @return Reference to self (for method chaining) + * + * Default is `1.0f`. + * @see @ref setRolloffFactor(), @fn_al{Sourcef} with + * @def_al{REFERENCE_DISTANCE} + */ + Source& setReferenceDistance(Float distance) { + alSourcef(_id, AL_REFERENCE_DISTANCE, distance); + return *this; + } + + /** @overload + * @see @fn_al{Sourcei} with @def_al{REFERENCE_DISTANCE} + */ + Source& setReferenceDistance(Int distance) { + alSourcei(_id, AL_REFERENCE_DISTANCE, distance); + return *this; + } + + /** + * @brief Set rolloff factor + * @return Reference to self (for method chaining) + * + * Default is `1.0f`. + * @see @ref setReferenceDistance(), @fn_al{Sourcef} with + * @def_al{ROLLOFF_FACTOR} + */ + Source& setRolloffFactor(Float factor) { + alSourcef(_id, AL_ROLLOFF_FACTOR, factor); + return *this; + } + + /** @overload + * @see @fn_al{Sourcei} with @def_al{ROLLOFF_FACTOR} + */ + Source& setRolloffFactor(Int factor) { + alSourcei(_id, AL_ROLLOFF_FACTOR, factor); + return *this; + } + + /** + * @brief Set max distance + * @return Reference to self (for method chaining) + * + * Default is max representable value. + * @see @fn_al{Sourcef} with @def_al{MAX_DISTANCE} + */ + Source& setMaxDistance(Float distance) { + alSourcef(_id, AL_MAX_DISTANCE, distance); + return *this; + } + + /** @overload + * @see @fn_al{Sourcei} with @def_al{MAX_DISTANCE} + */ + Source& setMaxDistance(Int distance) { + alSourcef(_id, AL_MAX_DISTANCE, distance); + return *this; + } + + /** + * @brief Set direction + * @return Reference to self (for method chaining) + * + * Default is `{0.0f, 0.0f, 0.0f}`, which means that the source is not + * directional. + * @see @ref setInnerConeAngle(), @ref setOuterConeAngle(), + * @ref setRelative(), @fn_al{Sourcefv} with @def_al{DIRECTION} + */ + Source& setDirection(const Vector3& direction) { + alSourcefv(_id, AL_DIRECTION, direction.data()); + return *this; + } + + /** @overload + * @see @fn_al{Sourceiv} with @def_al{DIRECTION} + */ + Source& setDirection(const Vector3i& direction) { + alSourceiv(_id, AL_DIRECTION, direction.data()); + return *this; + } + + /** + * @brief Set inner cone angle + * @return Reference to self (for method chaining) + * + * Has effect only if the source is directional. Default is + * `360.0_degf`. + * @see @ref setOuterConeAngle(), @ref setDirection(), @fn_al{Sourcef} + * with @def_al{CONE_INNER_ANGLE} + */ + Source& setInnerConeAngle(Deg angle) { + alSourcef(_id, AL_CONE_INNER_ANGLE, Float(angle)); + return *this; + } + + /** + * @brief Set outer cone angle + * @return Reference to self (for method chaining) + * + * Has effect only if the source is directional. Default is + * `360.0_degf`. + * @see @ref setInnerConeAngle(), @ref setDirection(), + * @ref setOuterConeGain() @fn_al{Sourcef} with + * @def_al{CONE_OUTER_ANGLE} + */ + Source& setOuterConeAngle(Deg angle) { + alSourcef(_id, AL_CONE_OUTER_ANGLE, Float(angle)); + return *this; + } + + /** + * @brief Set outer cone gain multiplier + * @return Reference to self (for method chaining) + * + * The factor with which the gain is multiplied outside the outer cone. + * Default is `0.0f`. + * @see @ref setGain(), @ref setOuterConeAngle(), @fn_al{Sourcef} with + * @def_al{CONE_OUTER_GAIN} + */ + Source& setOuterConeGain(Float multiplier) { + alSourcef(_id, AL_CONE_OUTER_ANGLE, multiplier); + return *this; + } + + /** + * @brief Set pitch + * @return Reference to self (for method chaining) + * + * Default is `1.0f`. + * @see @fn_al{Sourcef} with @def_al{PITCH} + */ + Source& setPitch(Float pitch) { + alSourcef(_id, AL_PITCH, pitch); + return *this; + } + + /*@}*/ + + /** @{ @name Buffer management */ + + /** + * @brief %Source type + * + * @see @ref type() + */ + enum class Type: ALint { + Undetermined = AL_UNDETERMINED, /**< Undetermined (default) */ + Static = AL_STATIC, /**< Static source */ + Streaming = AL_STREAMING /**< Streaming source */ + }; + + /** + * @brief Source type + * + * @see @ref setBuffer(), @fn_al{GetSourcei} with @def_al{SOURCE_TYPE} + */ + Type type() const; + + /** + * @brief Attach buffer + * @param buffer Buffer to attach or `nullptr` + * @return Reference to self (for method chaining) + * + * If an buffer is attached, changes source type to + * @ref Type "Type::Static", if detached, changes source type to + * @ref Type "Type::Undetermined". The buffer must be already filled + * with data. + * @see @ref type(), @fn_al{Sourcei} with @def_al{BUFFER} + */ + Source& setBuffer(Buffer* buffer); + + /*@}*/ + + /** @{ @name State management */ + + /** + * @brief %Source state + * + * @see @ref state(), @ref play(), @ref pause(), @ref stop(), + * @ref rewind() + */ + enum class State: ALint { + Initial = AL_INITIAL, /**< Initial state (default) */ + Playing = AL_PLAYING, /**< The source is playing */ + Paused = AL_PAUSED, /**< The source is paused */ + Stopped = AL_STOPPED /**< The source is stopped */ + }; + + /** + * @brief Play more sources at once + * + * The operation is guaranteed to be done for all sources at the same + * time. `nullptr` is not allowed. + * @see @ref play(), @ref pause(std::initializer_list), + * @ref stop(std::initializer_list), + * @ref rewind(std::initializer_list), + * @fn_al{SourcePlayv} + */ + static void play(std::initializer_list sources); + static void play(const std::vector& sources); /**< @overload */ + + /** + * @brief Pause more sources at once + * + * The operation is guaranteed to be done for all sources at the same + * time. `nullptr` is not allowed. + * @see @ref pause(), @ref play(std::initializer_list), + * @ref stop(std::initializer_list), + * @ref rewind(std::initializer_list), + * @fn_al{SourcePausev} + */ + static void pause(std::initializer_list sources); + static void pause(const std::vector& sources); /**< @overload */ + + /** + * @brief Stop more sources at once + * + * The operation is guaranteed to be done for all sources at the same + * time. `nullptr` is not allowed. + * @see @ref stop(), @ref play(std::initializer_list), + * @ref pause(std::initializer_list), + * @ref rewind(std::initializer_list), + * @fn_al{SourceStopv} + */ + static void stop(std::initializer_list sources); + static void stop(const std::vector& sources); /**< @overload */ + + /** + * @brief Rewind more sources at once + * + * The operation is guaranteed to be done for all sources at the same + * time. `nullptr` is not allowed. + * @see @ref rewind(), @ref play(std::initializer_list), + * @ref pause(std::initializer_list), + * @ref stop(std::initializer_list), + * @fn_al{SourceRewindv} + */ + static void rewind(std::initializer_list sources); + static void rewind(const std::vector& sources); /**< @overload */ + + /** + * @brief State + * + * @see @ref play(), @ref pause(), @ref stop(), @ref rewind(), + * @fn_al{GetSourcei} with @def_al{SOURCE_STATE} + */ + State state() const; + + /** + * @brief Play + * + * @see @ref play(std::initializer_list), @ref state(), + * @ref pause(), @ref stop(), @ref rewind(), @fn_al{SourcePlay} + */ + void play() { alSourcePlay(_id); } + + /** + * @brief Pause + * + * @see @ref pause(std::initializer_list), @ref state(), + * @ref play(), @ref stop(), @ref rewind(), @fn_al{SourcePause} + */ + void pause() { alSourcePause(_id); } + + /** + * @brief Stop + * + * @see @ref stop(std::initializer_list), @ref state(), + * @ref play(), @ref pause(), @ref rewind(), @fn_al{SourceStop} + */ + void stop() { alSourceStop(_id); } + + /** + * @brief Rewind + * + * @see @ref rewind(std::initializer_list), @ref state(), + * @ref play(), @ref pause(), @ref stop(), @fn_al{SourceRewind} + */ + void rewind() { alSourceRewind(_id); } + + /** + * @brief Whether the source is looping + * + * @see @fn_al{GetSourcei} with @def_al{LOOPING} + */ + bool isLooping() const; + + /** + * @brief Set source looping + * @return Reference to self (for method chaining) + * + * Default is `false`. + * @see @fn_al{Sourcei} with @def_al{LOOPING} + */ + Source& setLooping(bool loop) { + alSourcei(_id, AL_LOOPING, loop); + return *this; + } + + /** + * @brief Offset in seconds + * + * @see @ref offsetInBytes(), @ref offsetInSamples(), + * @fn_al{GetSourcef} with @def_al{SEC_OFFSET} + */ + Float offsetInSeconds() const; + + /** + * @brief Set offset in seconds + * @return Reference to self (for method chaining) + * + * @see @ref setOffsetInBytes(), @ref setOffsetInSamples(), + * @fn_al{Sourcef} with @def_al{SEC_OFFSET} + */ + Source& setOffsetInSeconds(Float offset) { + alSourcef(_id, AL_SEC_OFFSET, offset); + return *this; + } + + /** + * @brief Offset in bytes + * + * @see @ref offsetInSeconds(), @ref offsetInSamples(), + * @fn_al{GetSourcei} with @def_al{BYTE_OFFSET} + */ + Int offsetInBytes() const; + + /** + * @brief Set offset in bytes + * @return Reference to self (for method chaining) + * + * @see @ref setOffsetInSeconds(), @ref setOffsetInSamples(), + * @fn_al{Sourcei} with @def_al{SEC_OFFSET} + */ + Source& setOffsetInBytes(Int offset) { + alSourcei(_id, AL_BYTE_OFFSET, offset); + return *this; + } + + /** + * @brief Offset in samples + * + * @see @ref offsetInSeconds(), @ref offsetInBytes(), + * @fn_al{GetSourcei} with @def_al{SAMPLE_OFFSET} + */ + Int offsetInSamples() const; + + /** + * @brief Set offset in samples + * @return Reference to self (for method chaining) + * + * @see @ref setOffsetInSeconds(), @ref setOffsetInBytes(), + * @fn_al{Sourcei} with @def_al{SEC_OFFSET} + */ + Source& setOffsetInSamples(Int offset) { + alSourcei(_id, AL_SAMPLE_OFFSET, offset); + return *this; + } + + /*@}*/ + + private: + ALuint _id; +}; + +/** @debugoperator{Magnum::Audio::Source} */ +Debug MAGNUM_AUDIO_EXPORT operator<<(Debug debug, Source::State value); + +inline Source::Source(Source&& other): _id(other._id) { + other._id = 0; +} + +inline Source& Source::operator=(Source&& other) { + std::swap(_id, other._id); + return *this; +} + +auto Source::state() const -> State { + ALint state; + alGetSourcei(_id, AL_SOURCE_STATE, &state); + return State(state); +} + +inline bool Source::isLooping() const { + ALint looping; + alGetSourcei(_id, AL_LOOPING, &looping); + return looping; +} + +inline Float Source::offsetInSeconds() const { + Float offset; + alGetSourcef(_id, AL_SEC_OFFSET, &offset); + return offset; +} + +inline Int Source::offsetInBytes() const { + Int offset; + alGetSourcei(_id, AL_BYTE_OFFSET, &offset); + return offset; +} + +inline Int Source::offsetInSamples() const { + Int offset; + alGetSourcei(_id, AL_SAMPLE_OFFSET, &offset); + return offset; +} + +}} + +#endif diff --git a/src/Audio/Test/CMakeLists.txt b/src/Audio/Test/CMakeLists.txt index 869f75ce7..c53624b53 100644 --- a/src/Audio/Test/CMakeLists.txt +++ b/src/Audio/Test/CMakeLists.txt @@ -24,3 +24,4 @@ corrade_add_test(AudioBufferTest BufferTest.cpp LIBRARIES MagnumAudio) corrade_add_test(AudioRendererTest RendererTest.cpp LIBRARIES MagnumAudio) +corrade_add_test(AudioSourceTest SourceTest.cpp LIBRARIES MagnumAudio) diff --git a/src/Audio/Test/SourceTest.cpp b/src/Audio/Test/SourceTest.cpp new file mode 100644 index 000000000..90424ce29 --- /dev/null +++ b/src/Audio/Test/SourceTest.cpp @@ -0,0 +1,51 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013 Vladimír Vondruš + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include +#include + +#include "Audio/Source.h" + +namespace Magnum { namespace Audio { namespace Test { + +class SourceTest: public TestSuite::Tester { + public: + explicit SourceTest(); + + void debugState(); +}; + +SourceTest::SourceTest() { + addTests({&SourceTest::debugState}); +} + +void SourceTest::debugState() { + std::ostringstream out; + Debug(&out) << Source::State::Playing; + CORRADE_COMPARE(out.str(), "Audio::Source::State::Playing\n"); +} + +}}} + +CORRADE_TEST_MAIN(Magnum::Audio::Test::SourceTest)