diff --git a/.rive_head b/.rive_head index ed40a47c..406e3a5e 100644 --- a/.rive_head +++ b/.rive_head @@ -1 +1 @@ -0bc446fad2a568a7088fdaa122af0de2de1dc940 +8ecc99130db737d49ce0889501c421bd53b58f9e diff --git a/include/rive/animation/state_machine_instance.hpp b/include/rive/animation/state_machine_instance.hpp index 67369e69..98a56935 100644 --- a/include/rive/animation/state_machine_instance.hpp +++ b/include/rive/animation/state_machine_instance.hpp @@ -51,7 +51,7 @@ class StateMachineInstance : public Scene template InstType* getNamedInput(const std::string& name) const; - void notifyEventListeners(std::vector events, NestedArtboard* source); + void notifyEventListeners(const std::vector& events, NestedArtboard* source); void sortHitComponents(); public: @@ -120,6 +120,7 @@ class StateMachineInstance : public Scene /// Gets a reported event at an index < reportedEventCount(). const EventReport reportedEventAt(std::size_t index) const; + bool playsAudio() override { return true; } private: std::vector m_reportedEvents; diff --git a/include/rive/audio/audio_engine.hpp b/include/rive/audio/audio_engine.hpp index e23f5393..a49f6693 100644 --- a/include/rive/audio/audio_engine.hpp +++ b/include/rive/audio/audio_engine.hpp @@ -7,6 +7,7 @@ #include #include #include +#include typedef struct ma_engine ma_engine; typedef struct ma_sound ma_sound; @@ -60,6 +61,9 @@ class AudioEngine : public RefCnt AudioEngine(ma_engine* engine); ma_device* m_device; ma_engine* m_engine; + std::mutex m_mutex; + + void soundCompleted(rcp sound); std::vector> m_completedSounds; rcp m_playingSoundsHead; diff --git a/include/rive/audio_event.hpp b/include/rive/audio_event.hpp index cd67c6c5..2844e9c6 100644 --- a/include/rive/audio_event.hpp +++ b/include/rive/audio_event.hpp @@ -13,6 +13,7 @@ class AudioEvent : public AudioEventBase, public FileAssetReferencer void setAsset(FileAsset* asset) override; uint32_t assetId() override; void trigger(const CallbackData& value) override; + void play(); #ifdef TESTING AudioAsset* asset() const { return (AudioAsset*)m_fileAsset; } diff --git a/include/rive/core/field_types/core_callback_type.hpp b/include/rive/core/field_types/core_callback_type.hpp index 1c8ba627..a6bb93f4 100644 --- a/include/rive/core/field_types/core_callback_type.hpp +++ b/include/rive/core/field_types/core_callback_type.hpp @@ -9,6 +9,7 @@ class CallbackContext public: virtual ~CallbackContext() {} virtual void reportEvent(Event* event, float secondsDelay = 0.0f) {} + virtual bool playsAudio() { return false; } }; class CallbackData diff --git a/include/rive/relative_local_asset_loader.hpp b/include/rive/relative_local_asset_loader.hpp index 6056c9c9..c4dc317a 100644 --- a/include/rive/relative_local_asset_loader.hpp +++ b/include/rive/relative_local_asset_loader.hpp @@ -36,6 +36,11 @@ class RelativeLocalAssetLoader : public FileAssetLoader { std::string filename = m_Path + asset.uniqueFilename(); FILE* fp = fopen(filename.c_str(), "rb"); + if (fp == nullptr) + { + fprintf(stderr, "Failed to find file at %s\n", filename.c_str()); + return false; + } fseek(fp, 0, SEEK_END); const size_t length = ftell(fp); diff --git a/src/animation/state_machine_instance.cpp b/src/animation/state_machine_instance.cpp index 0348c6e9..b75642a8 100644 --- a/src/animation/state_machine_instance.cpp +++ b/src/animation/state_machine_instance.cpp @@ -24,6 +24,7 @@ #include "rive/nested_artboard.hpp" #include "rive/shapes/shape.hpp" #include "rive/math/math_types.hpp" +#include "rive/audio_event.hpp" #include using namespace rive; @@ -782,7 +783,7 @@ const EventReport StateMachineInstance::reportedEventAt(std::size_t index) const return m_reportedEvents[index]; } -void StateMachineInstance::notifyEventListeners(std::vector events, +void StateMachineInstance::notifyEventListeners(const std::vector& events, NestedArtboard* source) { if (events.size() > 0) @@ -826,5 +827,14 @@ void StateMachineInstance::notifyEventListeners(std::vector events, { m_parentStateMachineInstance->notifyEventListeners(events, m_parentNestedArtboard); } + + for (auto report : events) + { + auto event = report.event(); + if (event->is()) + { + event->as()->play(); + } + } } } diff --git a/src/audio/audio_engine.cpp b/src/audio/audio_engine.cpp index 268e22e8..c63bb693 100644 --- a/src/audio/audio_engine.cpp +++ b/src/audio/audio_engine.cpp @@ -25,9 +25,17 @@ using namespace rive; void AudioEngine::SoundCompleted(void* pUserData, ma_sound* pSound) { AudioSound* audioSound = (AudioSound*)pUserData; + auto engine = audioSound->m_engine; + engine->soundCompleted(ref_rcp(audioSound)); +} - auto next = audioSound->m_nextPlaying; - auto prev = audioSound->m_prevPlaying; +void AudioEngine::soundCompleted(rcp sound) +{ + std::unique_lock lock(m_mutex); + m_completedSounds.push_back(sound); + + auto next = sound->m_nextPlaying; + auto prev = sound->m_prevPlaying; if (next != nullptr) { next->m_prevPlaying = prev; @@ -37,16 +45,13 @@ void AudioEngine::SoundCompleted(void* pUserData, ma_sound* pSound) prev->m_nextPlaying = next; } - auto engine = audioSound->m_engine; - if (engine->m_playingSoundsHead.get() == audioSound) + if (m_playingSoundsHead == sound) { - engine->m_playingSoundsHead = next; + m_playingSoundsHead = next; } - // Unlink audio sound. - engine->m_completedSounds.push_back(ref_rcp(audioSound)); - audioSound->m_nextPlaying = nullptr; - audioSound->m_prevPlaying = nullptr; + sound->m_nextPlaying = nullptr; + sound->m_prevPlaying = nullptr; } #ifdef WITH_RIVE_AUDIO_TOOLS @@ -182,6 +187,7 @@ rcp AudioEngine::play(rcp source, uint64_t endTime, uint64_t soundStartTime) { + std::unique_lock lock(m_mutex); // We have to dispose completed sounds out of the completed callback. So we // do it on next play or at destruct. for (auto sound : m_completedSounds) diff --git a/src/audio_event.cpp b/src/audio_event.cpp index 1ba130b3..d0d8098e 100644 --- a/src/audio_event.cpp +++ b/src/audio_event.cpp @@ -6,10 +6,8 @@ using namespace rive; -void AudioEvent::trigger(const CallbackData& value) +void AudioEvent::play() { - Super::trigger(value); - #ifdef WITH_RIVE_AUDIO auto audioAsset = (AudioAsset*)m_fileAsset; if (audioAsset == nullptr) @@ -36,6 +34,16 @@ void AudioEvent::trigger(const CallbackData& value) #endif } +void AudioEvent::trigger(const CallbackData& value) +{ + Super::trigger(value); + if (!value.context()->playsAudio()) + { + // Context won't play audio, we'll do it ourselves. + play(); + } +} + StatusCode AudioEvent::import(ImportStack& importStack) { auto result = registerReferencer(importStack);