diff options
-rw-r--r-- | src/crepe/api/AudioSource.h | 15 | ||||
-rw-r--r-- | src/crepe/facade/Sound.h | 6 | ||||
-rw-r--r-- | src/crepe/facade/SoundContext.cpp | 23 | ||||
-rw-r--r-- | src/crepe/facade/SoundContext.h | 15 | ||||
-rw-r--r-- | src/crepe/facade/SoundHandle.h | 13 | ||||
-rw-r--r-- | src/crepe/system/AudioSystem.cpp | 44 | ||||
-rw-r--r-- | src/crepe/system/AudioSystem.h | 29 | ||||
-rw-r--r-- | src/crepe/util/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/crepe/util/Private.cpp | 27 | ||||
-rw-r--r-- | src/crepe/util/Private.h | 89 | ||||
-rw-r--r-- | src/crepe/util/Private.hpp | 31 | ||||
-rw-r--r-- | src/test/AudioTest.cpp | 8 | ||||
-rw-r--r-- | src/test/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/test/PrivateTest.cpp | 155 |
14 files changed, 78 insertions, 381 deletions
diff --git a/src/crepe/api/AudioSource.h b/src/crepe/api/AudioSource.h index 330e8e1..7c1f161 100644 --- a/src/crepe/api/AudioSource.h +++ b/src/crepe/api/AudioSource.h @@ -2,7 +2,7 @@ #include "../Component.h" #include "../types.h" -#include "../util/Private.h" +#include "../facade/SoundHandle.h" #include "Asset.h" #include "GameObject.h" @@ -59,10 +59,17 @@ private: //! Stop this sample bool oneshot_stop = false; //! \} + /** + * \name State diffing variables + * \{ + */ + typeof(active) last_active = false; + typeof(volume) last_volume = volume; + typeof(loop) last_loop = loop; + //! \} + //! This source's voice handle + SoundHandle voice{}; -private: - //! AudioSystem::ComponentPrivate - Private private_data; }; } // namespace crepe diff --git a/src/crepe/facade/Sound.h b/src/crepe/facade/Sound.h index a78a2a7..85d141b 100644 --- a/src/crepe/facade/Sound.h +++ b/src/crepe/facade/Sound.h @@ -20,12 +20,6 @@ public: Sound(const Asset & src); ~Sound(); // dbg_trace - //! Voice handle wrapper - struct Handle { - //! Voice handle (soloud), used by SoundContext - SoLoud::handle handle; - }; - private: //! Deserialized resource (soloud) SoLoud::Wav sample; diff --git a/src/crepe/facade/SoundContext.cpp b/src/crepe/facade/SoundContext.cpp index 8bd7e74..d18afc6 100644 --- a/src/crepe/facade/SoundContext.cpp +++ b/src/crepe/facade/SoundContext.cpp @@ -15,18 +15,23 @@ SoundContext::~SoundContext() { this->engine.deinit(); } -Sound::Handle SoundContext::play(Sound & resource) { - return { - .handle = this->engine.play(resource.sample, 1.0f), - }; +SoundHandle SoundContext::play(Sound & resource) { + SoLoud::handle real_handle = this->engine.play(resource.sample, 1.0f); + SoundHandle handle = this->next_handle; + this->registry[handle] = real_handle; + this->next_handle++; + return handle; } -void SoundContext::stop(Sound::Handle & handle) { this->engine.stop(handle.handle); } +void SoundContext::stop(const SoundHandle & handle) { + this->engine.stop(this->registry[handle]); +} -void SoundContext::set_volume(Sound::Handle & handle, float volume) { - this->engine.setVolume(handle.handle, volume); +void SoundContext::set_volume(const SoundHandle & handle, float volume) { + this->engine.setVolume(this->registry[handle], volume); } -void SoundContext::set_loop(Sound::Handle & handle, bool loop) { - this->engine.setLooping(handle.handle, loop); +void SoundContext::set_loop(const SoundHandle & handle, bool loop) { + this->engine.setLooping(this->registry[handle], loop); } + diff --git a/src/crepe/facade/SoundContext.h b/src/crepe/facade/SoundContext.h index 3bc8be5..102f928 100644 --- a/src/crepe/facade/SoundContext.h +++ b/src/crepe/facade/SoundContext.h @@ -4,6 +4,7 @@ #include "../api/Config.h" +#include "SoundHandle.h" #include "Sound.h" namespace crepe { @@ -33,7 +34,7 @@ public: * * \returns Handle to control this voice */ - virtual Sound::Handle play(Sound & resource); + virtual SoundHandle play(Sound & resource); /** * \brief Stop a voice immediately if it is still playing * @@ -42,7 +43,7 @@ public: * * \param handle Voice handle returned by SoundContext::play */ - virtual void stop(Sound::Handle & handle); + virtual void stop(const SoundHandle & handle); /** * \brief Change the volume of a voice * @@ -52,7 +53,7 @@ public: * \param handle Voice handle returned by SoundContext::play * \param volume New gain value (0=silent, 1=default) */ - virtual void set_volume(Sound::Handle & handle, float volume); + virtual void set_volume(const SoundHandle & handle, float volume); /** * \brief Set the looping behavior of a voice * @@ -62,7 +63,7 @@ public: * \param handle Voice handle returned by SoundContext::play * \param loop Looping behavior (false=oneshot, true=loop) */ - virtual void set_loop(Sound::Handle & handle, bool loop); + virtual void set_loop(const SoundHandle & handle, bool loop); private: //! Abstracted class @@ -70,6 +71,12 @@ private: //! Config reference Config & config = Config::get_instance(); + + //! Sound handle registry + std::unordered_map<SoundHandle, SoLoud::handle> registry; + //! Unique handle counter + SoundHandle next_handle = 0; + }; } // namespace crepe diff --git a/src/crepe/facade/SoundHandle.h b/src/crepe/facade/SoundHandle.h new file mode 100644 index 0000000..131d28c --- /dev/null +++ b/src/crepe/facade/SoundHandle.h @@ -0,0 +1,13 @@ +#pragma once + +#include <cstddef> + +namespace crepe { + +/** + * \brief Voice handle returned by + */ +typedef size_t SoundHandle; + +} + diff --git a/src/crepe/system/AudioSystem.cpp b/src/crepe/system/AudioSystem.cpp index 26913c0..c1cde8b 100644 --- a/src/crepe/system/AudioSystem.cpp +++ b/src/crepe/system/AudioSystem.cpp @@ -16,56 +16,50 @@ void AudioSystem::update() { for (AudioSource & component : components) { Sound & resource = resource_manager.get<Sound>(component.source); - if (component.private_data.empty()) { - auto & data = component.private_data.set<ComponentPrivate>(); - this->update_last(component, data); - data.last_active = false; - } - auto & data = component.private_data.get<ComponentPrivate>(); - - this->diff_update(component, data, resource); + this->diff_update(component, resource); - this->update_last(component, data); + this->update_last(component); } } -void AudioSystem::diff_update(AudioSource & component, ComponentPrivate & data, - Sound & resource) { +void AudioSystem::diff_update(AudioSource & component, Sound & resource) { SoundContext & context = this->get_context(); - if (component.active != data.last_active) { + if (component.active != component.last_active) { if (component.active) { component.oneshot_play = component.play_on_awake; } else { - context.stop(data.handle); + context.stop(component.voice); return; } } if (!component.active) return; if (component.oneshot_play) { - data.handle = context.play(resource); + component.voice = context.play(resource); component.oneshot_play = false; } if (component.oneshot_stop) { - context.stop(data.handle); + context.stop(component.voice); component.oneshot_stop = false; } - if (component.volume != data.last_volume) { - context.set_volume(data.handle, component.volume); + if (component.volume != component.last_volume) { + context.set_volume(component.voice, component.volume); } - if (component.loop != data.last_loop) { - context.set_loop(data.handle, component.loop); + if (component.loop != component.last_loop) { + context.set_loop(component.voice, component.loop); } } -void AudioSystem::update_last(const AudioSource & component, ComponentPrivate & data) { - data.last_active = component.active; - data.last_loop = component.loop; - data.last_volume = component.volume; +void AudioSystem::update_last(AudioSource & component) { + component.last_active = component.active; + component.last_loop = component.loop; + component.last_volume = component.volume; } SoundContext & AudioSystem::get_context() { - if (this->context.empty()) this->context.set<SoundContext>(); - return this->context.get<SoundContext>(); + if (this->context == nullptr) + this->context = make_unique<SoundContext>(); + return *this->context.get(); } + diff --git a/src/crepe/system/AudioSystem.h b/src/crepe/system/AudioSystem.h index 4d21883..2ddc443 100644 --- a/src/crepe/system/AudioSystem.h +++ b/src/crepe/system/AudioSystem.h @@ -14,30 +14,14 @@ public: void update() override; private: - //! Private data stored by AudioSystem on AudioSource component - struct ComponentPrivate { - //! This sample's voice handle - Sound::Handle handle; - - /** - * \name State diffing variables - * \{ - */ - typeof(AudioSource::active) last_active; - typeof(AudioSource::volume) last_volume; - typeof(AudioSource::loop) last_loop; - //! \} - }; - /** - * \brief Update `last_*` members of \c data + * \brief Update `last_*` members of \c component * * Copies all component properties stored for comparison between AudioSystem::update() calls * - * \param component Source properties - * \param data Destination properties + * \param component AudioSource component to update */ - void update_last(const AudioSource & component, ComponentPrivate & data); + void update_last(AudioSource & component); /** * \brief Compare update component @@ -46,10 +30,9 @@ private: * applicable. * * \param component AudioSource component to update - * \param data AudioSource's private data * \param resource Sound instance for AudioSource's Asset */ - void diff_update(AudioSource & component, ComponentPrivate & data, Sound & resource); + void diff_update(AudioSource & component, Sound & resource); protected: /** @@ -61,8 +44,8 @@ protected: virtual SoundContext & get_context(); private: - //! Actually stores SoundContext if the base AudioSystem::get_context implementation is used - Private context; + //! SoundContext + std::unique_ptr<SoundContext> context = nullptr; }; } // namespace crepe diff --git a/src/crepe/util/CMakeLists.txt b/src/crepe/util/CMakeLists.txt index f49d851..94ed906 100644 --- a/src/crepe/util/CMakeLists.txt +++ b/src/crepe/util/CMakeLists.txt @@ -1,7 +1,6 @@ target_sources(crepe PUBLIC LogColor.cpp Log.cpp - Private.cpp ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES @@ -12,7 +11,5 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES Proxy.hpp OptionalRef.h OptionalRef.hpp - Private.h - Private.hpp ) diff --git a/src/crepe/util/Private.cpp b/src/crepe/util/Private.cpp deleted file mode 100644 index 262620d..0000000 --- a/src/crepe/util/Private.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include "Private.h" - -using namespace crepe; - -bool Private::empty() const noexcept { return this->instance == nullptr; } - -Private::~Private() { - if (this->instance == nullptr) return; - this->destructor(this->instance); -} - -Private::Private(Private && other) { *this = std::move(other); } - -Private & Private::operator=(Private && other) { - // TODO: ideally this function checks for self-assignment - this->instance = other.instance; - this->destructor = other.destructor; - this->type = other.type; - - other.instance = nullptr; - other.destructor = [](void *) {}; - - return *this; -} - -Private::Private(const Private & other) {} -Private & Private::operator=(const Private & other) { return *this; } diff --git a/src/crepe/util/Private.h b/src/crepe/util/Private.h deleted file mode 100644 index d725a5e..0000000 --- a/src/crepe/util/Private.h +++ /dev/null @@ -1,89 +0,0 @@ -#pragma once - -#include <functional> -#include <typeindex> - -namespace crepe { - -/** - * \brief Utility for storing type hidden from user - * - * This class can be used to store types which cannot be used in the API directly due to header - * distribution limitations. This class is similar to `std::any`, but provides a method for - * retrieving a mutable reference to the stored object. - */ -class Private { -public: - Private() = default; - ~Private(); - /** - * \name Copy - * - * \note These functions do not do anything, resulting in `*this` being an empty (default) - * instance. - * - * \{ - */ - Private(const Private &); - Private & operator=(const Private &); - //! \} - /** - * \name Move - * - * These functions actually move the stored type if present. - * - * \{ - */ - Private(Private &&); - Private & operator=(Private &&); - //! \} - - /** - * \brief Get the stored object - * - * \tparam T Type of stored object - * - * \returns Mutable reference to stored object - * - * \throws std::out_of_range if this instance does not contain any object - * \throws std::logic_error if the stored type and requested type differ - */ - template <typename T> - T & get() const; - - /** - * \brief Create and store an arbitrary object - * - * \tparam T Type of object - * \tparam Args Perfect forwarding arguments - * \param args Perfect forwarding arguments - * - * All arguments to this function are forwarded using `std::forward` to the constructor of T. - * - * \returns Mutable reference to stored object - * - * \note If this instance already contained an object, this function implicitly destroys the - * previous object. - */ - template <typename T, typename... Args> - T & set(Args &&... args); - - /** - * \brief Check if this instance contains an object - * - * \returns `true` if this instance is empty, `false` if it contains an object - */ - bool empty() const noexcept; - -private: - //! Wrapper for destructor call of stored object type - std::function<void(void *)> destructor; - //! Stored object's type - std::type_index type = typeid(void); - //! Stored object - void * instance = nullptr; -}; - -} // namespace crepe - -#include "Private.hpp" diff --git a/src/crepe/util/Private.hpp b/src/crepe/util/Private.hpp deleted file mode 100644 index b2174c0..0000000 --- a/src/crepe/util/Private.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include <format> -#include <stdexcept> - -#include "Private.h" - -namespace crepe { - -template <typename T, typename... Args> -T & Private::set(Args &&... args) { - if (!this->empty()) this->destructor(this->instance); - T * instance = new T(std::forward<Args>(args)...); - this->instance = static_cast<void *>(instance); - this->destructor = [](void * instance) { delete static_cast<T *>(instance); }; - this->type = typeid(T); - return *instance; -} - -template <typename T> -T & Private::get() const { - using namespace std; - if (this->empty()) throw out_of_range("Private: get() called on empty object"); - type_index requested_type = typeid(T); - if (this->type != requested_type) - throw logic_error(format("Private: get() called with [T = {}] (actual is [T = {}])", - requested_type.name(), this->type.name())); - return *static_cast<T *>(this->instance); -} - -} // namespace crepe diff --git a/src/test/AudioTest.cpp b/src/test/AudioTest.cpp index 7644ab7..774fdb8 100644 --- a/src/test/AudioTest.cpp +++ b/src/test/AudioTest.cpp @@ -16,10 +16,10 @@ class AudioTest : public Test { private: class TestSoundContext : public SoundContext { public: - MOCK_METHOD(Sound::Handle, play, (Sound & resource), (override)); - MOCK_METHOD(void, stop, (Sound::Handle &), (override)); - MOCK_METHOD(void, set_volume, (Sound::Handle &, float), (override)); - MOCK_METHOD(void, set_loop, (Sound::Handle &, bool), (override)); + MOCK_METHOD(SoundHandle, play, (Sound & resource), (override)); + MOCK_METHOD(void, stop, (const SoundHandle &), (override)); + MOCK_METHOD(void, set_volume, (const SoundHandle &, float), (override)); + MOCK_METHOD(void, set_loop, (const SoundHandle &, bool), (override)); }; class TestAudioSystem : public AudioSystem { diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 8c4b855..4174926 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -16,5 +16,4 @@ target_sources(test_main PUBLIC Vector2Test.cpp ScriptEventTest.cpp ScriptSceneTest.cpp - PrivateTest.cpp ) diff --git a/src/test/PrivateTest.cpp b/src/test/PrivateTest.cpp deleted file mode 100644 index 454789e..0000000 --- a/src/test/PrivateTest.cpp +++ /dev/null @@ -1,155 +0,0 @@ -#include <gtest/gtest.h> - -#include <crepe/util/Private.h> - -using namespace std; -using namespace crepe; -using namespace testing; - -class PrivateTest : public Test { -public: - static unsigned constructors; - static unsigned destructors; - - void SetUp() override { - PrivateTest::constructors = 0; - PrivateTest::destructors = 0; - } - - class TestClass { - public: - TestClass() { PrivateTest::constructors++; } - ~TestClass() { PrivateTest::destructors++; } - }; - class Unrelated {}; -}; -unsigned PrivateTest::constructors; -unsigned PrivateTest::destructors; - -TEST_F(PrivateTest, Empty) { - { Private foo; } - - EXPECT_EQ(PrivateTest::constructors, 0); - EXPECT_EQ(PrivateTest::destructors, 0); -} - -TEST_F(PrivateTest, WithObject) { - { - Private foo; - foo.set<TestClass>(); - - EXPECT_EQ(PrivateTest::constructors, 1); - EXPECT_EQ(PrivateTest::destructors, 0); - } - - EXPECT_EQ(PrivateTest::constructors, 1); - EXPECT_EQ(PrivateTest::destructors, 1); -} - -TEST_F(PrivateTest, EmptyException) { - Private foo; - EXPECT_THROW(foo.get<TestClass>(), std::out_of_range); - - foo.set<TestClass>(); - EXPECT_NO_THROW(foo.get<TestClass>()); -} - -TEST_F(PrivateTest, IncorrectTypeException) { - Private foo; - foo.set<TestClass>(); - - EXPECT_THROW(foo.get<Unrelated>(), std::logic_error); - EXPECT_NO_THROW(foo.get<TestClass>()); -} - -TEST_F(PrivateTest, MoveConstructor) { - { - Private foo; - foo.set<TestClass>(); - - EXPECT_EQ(PrivateTest::constructors, 1); - EXPECT_EQ(PrivateTest::destructors, 0); - - Private bar(std::move(foo)); - - EXPECT_EQ(PrivateTest::constructors, 1); - EXPECT_EQ(PrivateTest::destructors, 0); - } - - EXPECT_EQ(PrivateTest::constructors, 1); - EXPECT_EQ(PrivateTest::destructors, 1); -} - -TEST_F(PrivateTest, MoveOperator) { - { - Private foo; - foo.set<TestClass>(); - - EXPECT_EQ(PrivateTest::constructors, 1); - EXPECT_EQ(PrivateTest::destructors, 0); - - Private bar = std::move(foo); - - EXPECT_EQ(PrivateTest::constructors, 1); - EXPECT_EQ(PrivateTest::destructors, 0); - } - - EXPECT_EQ(PrivateTest::constructors, 1); - EXPECT_EQ(PrivateTest::destructors, 1); -} - -TEST_F(PrivateTest, CopyConstructor) { - { - Private foo; - foo.set<TestClass>(); - - EXPECT_EQ(PrivateTest::constructors, 1); - EXPECT_EQ(PrivateTest::destructors, 0); - - Private bar(foo); - - EXPECT_TRUE(bar.empty()); - EXPECT_EQ(PrivateTest::constructors, 1); - EXPECT_EQ(PrivateTest::destructors, 0); - } - - EXPECT_EQ(PrivateTest::constructors, 1); - EXPECT_EQ(PrivateTest::destructors, 1); -} - -TEST_F(PrivateTest, CopyOperator) { - { - Private foo; - foo.set<TestClass>(); - - EXPECT_EQ(PrivateTest::constructors, 1); - EXPECT_EQ(PrivateTest::destructors, 0); - - Private bar = foo; - - EXPECT_TRUE(bar.empty()); - EXPECT_EQ(PrivateTest::constructors, 1); - EXPECT_EQ(PrivateTest::destructors, 0); - } - - EXPECT_EQ(PrivateTest::constructors, 1); - EXPECT_EQ(PrivateTest::destructors, 1); -} - -TEST_F(PrivateTest, DoubleAssignment) { - { - Private foo; - foo.set<TestClass>(); - - EXPECT_EQ(PrivateTest::constructors, 1); - EXPECT_EQ(PrivateTest::destructors, 0); - - foo.set<TestClass>(); - - EXPECT_EQ(PrivateTest::constructors, 2); - EXPECT_EQ(PrivateTest::destructors, 1); - } - - EXPECT_EQ(PrivateTest::constructors, 2); - EXPECT_EQ(PrivateTest::destructors, 2); -} |