From 2341b6b7d0e429d618906072483e779515ce0c6e Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Fri, 13 May 2016 20:33:21 -1000 Subject: [PATCH] More fixes, better lifetime management --- include/amuse/Emitter.hpp | 10 ++++++++-- include/amuse/Engine.hpp | 1 + include/amuse/Entity.hpp | 8 +++++++- include/amuse/Voice.hpp | 9 ++++----- lib/Emitter.cpp | 11 +++++++++-- lib/Engine.cpp | 32 ++++++++++++++++++++++++++++---- lib/Voice.cpp | 35 +++++++++++++++++++++++++++++------ 7 files changed, 86 insertions(+), 20 deletions(-) diff --git a/include/amuse/Emitter.hpp b/include/amuse/Emitter.hpp index 993f705..52ff734 100644 --- a/include/amuse/Emitter.hpp +++ b/include/amuse/Emitter.hpp @@ -2,6 +2,7 @@ #define __AMUSE_EMITTER_HPP__ #include "Entity.hpp" +#include namespace amuse { @@ -11,9 +12,12 @@ using Vector3f = float[3]; class Emitter : public Entity { - Voice& m_vox; + std::shared_ptr m_vox; + + friend class Engine; + void _destroy(); public: - Emitter(Engine& engine, const AudioGroup& group, Voice& vox); + Emitter(Engine& engine, const AudioGroup& group, std::shared_ptr&& vox); void setPos(const Vector3f& pos); void setDir(const Vector3f& dir); @@ -21,6 +25,8 @@ public: void setMaxVol(float maxVol); void setMinVol(float minVol); void setFalloff(float falloff); + + std::shared_ptr& getVoice() {return m_vox;} }; } diff --git a/include/amuse/Engine.hpp b/include/amuse/Engine.hpp index de501ea..e61af07 100644 --- a/include/amuse/Engine.hpp +++ b/include/amuse/Engine.hpp @@ -23,6 +23,7 @@ class AudioGroupData; class Engine { friend class Voice; + friend class Emitter; IBackendVoiceAllocator& m_backend; std::unordered_map> m_audioGroups; diff --git a/include/amuse/Entity.hpp b/include/amuse/Entity.hpp index 74dabc6..6988950 100644 --- a/include/amuse/Entity.hpp +++ b/include/amuse/Entity.hpp @@ -32,7 +32,13 @@ class Entity friend class SoundMacroState; bool m_destroyed = false; protected: - void _destroy() {m_destroyed = true;} + void _destroy() + { +#ifndef NDEBUG + assert(!m_destroyed); +#endif + m_destroyed = true; + } Engine& m_engine; const AudioGroup& m_audioGroup; ObjectId m_objectId; /* if applicable */ diff --git a/include/amuse/Voice.hpp b/include/amuse/Voice.hpp index eeaed2d..ccc9154 100644 --- a/include/amuse/Voice.hpp +++ b/include/amuse/Voice.hpp @@ -19,9 +19,9 @@ class Submix; /** State of voice over lifetime */ enum class VoiceState { - Playing, - KeyOff, - Finished + Playing, /**< SoundMacro actively executing, not in KeyOff */ + KeyOff, /**< KeyOff event issued, macro beginning fade-out */ + Finished /**< Default state, causes Engine to remove voice at end of pump cycle */ }; /** Individual source of audio */ @@ -104,8 +104,6 @@ class Voice : public Entity float m_lfoPeriods[2]; /**< time-periods for LFO1 and LFO2 */ - bool m_dead = false; /**< sound macro has reached END, voice should be deallocated at end of update cycle */ - void _destroy(); void _reset(); bool _checkSamplePos(); @@ -113,6 +111,7 @@ class Voice : public Entity bool _advanceSample(int16_t& samp); void _setTotalPitch(int32_t cents); void _bringOutYourDead(); + std::shared_ptr _findVoice(int vid, std::weak_ptr thisPtr); std::shared_ptr _allocateVoice(double sampleRate, bool dynamicPitch); std::list>::iterator _destroyVoice(Voice* voice); diff --git a/lib/Emitter.cpp b/lib/Emitter.cpp index c20a7ec..f8517dc 100644 --- a/lib/Emitter.cpp +++ b/lib/Emitter.cpp @@ -1,14 +1,21 @@ #include "amuse/Emitter.hpp" #include "amuse/Voice.hpp" +#include "amuse/Engine.hpp" namespace amuse { -Emitter::Emitter(Engine& engine, const AudioGroup& group, Voice& vox) -: Entity(engine, group, vox.getObjectId()), m_vox(vox) +Emitter::Emitter(Engine& engine, const AudioGroup& group, std::shared_ptr&& vox) +: Entity(engine, group, vox->getObjectId()), m_vox(std::move(vox)) { } +void Emitter::_destroy() +{ + Entity::_destroy(); + m_engine._destroyVoice(m_vox.get()); +} + void Emitter::setPos(const Vector3f& pos) { } diff --git a/lib/Engine.cpp b/lib/Engine.cpp index 7826ebc..999ba57 100644 --- a/lib/Engine.cpp +++ b/lib/Engine.cpp @@ -53,11 +53,21 @@ std::list::iterator Engine::_destroySubmix(Submix* smx) void Engine::_bringOutYourDead() { + for (auto it = m_activeEmitters.begin() ; it != m_activeEmitters.end() ;) + { + Emitter* emitter = it->get(); + if (emitter->getVoice()->m_voxState == VoiceState::Finished) + { + emitter->_destroy(); + it = m_activeEmitters.erase(it); + } + } + for (auto it = m_activeVoices.begin() ; it != m_activeVoices.end() ;) { Voice* vox = it->get(); vox->_bringOutYourDead(); - if (vox->m_dead) + if (vox->m_voxState == VoiceState::Finished) { it = _destroyVoice(vox); continue; @@ -209,6 +219,11 @@ std::shared_ptr Engine::fxStart(int sfxId, float vol, float pan, Submix* return nullptr; std::shared_ptr ret = _allocateVoice(*grp, 32000.0, true, false, smx); + if (!ret->loadSoundMacro(search->second.second, 0, 1000.f, 0x3c, 0, 0)) + { + _destroyVoice(ret.get()); + return {}; + } ret->setVolume(vol); ret->setPan(pan); return ret; @@ -227,8 +242,14 @@ std::shared_ptr Engine::addEmitter(const Vector3f& pos, const Vector3f& return nullptr; std::shared_ptr vox = _allocateVoice(*grp, 32000.0, true, true, smx); - m_activeEmitters.emplace(m_activeEmitters.end(), new Emitter(*this, *grp, *vox)); + m_activeEmitters.emplace(m_activeEmitters.end(), new Emitter(*this, *grp, std::move(vox))); Emitter& ret = *m_activeEmitters.back(); + if (!ret.getVoice()->loadSoundMacro(search->second.second, 0, 1000.f, 0x3c, 0, 0)) + { + ret._destroy(); + m_activeEmitters.pop_back(); + return {}; + } ret.setPos(pos); ret.setDir(dir); ret.setMaxDist(maxDist); @@ -249,8 +270,11 @@ std::shared_ptr Engine::seqPlay(int groupId, int songId, const unsign std::shared_ptr Engine::findVoice(int vid) { for (std::shared_ptr& vox : m_activeVoices) - if (vox->vid() == vid) - return vox; + { + std::shared_ptr ret = vox->_findVoice(vid, vox); + if (ret) + return ret; + } return {}; } diff --git a/lib/Voice.cpp b/lib/Voice.cpp index d375804..0f855c5 100644 --- a/lib/Voice.cpp +++ b/lib/Voice.cpp @@ -17,6 +17,9 @@ void Voice::_destroy() Entity::_destroy(); if (m_submix) m_submix->m_activeVoices.erase(this); + + for (std::shared_ptr& vox : m_childVoices) + vox->_destroy(); } Voice::Voice(Engine& engine, const AudioGroup& group, int vid, bool emitter, Submix* smx) @@ -96,7 +99,7 @@ void Voice::_bringOutYourDead() { Voice* vox = it->get(); vox->_bringOutYourDead(); - if (vox->m_dead) + if (vox->m_voxState == VoiceState::Finished) { it = _destroyVoice(vox); continue; @@ -105,6 +108,21 @@ void Voice::_bringOutYourDead() } } +std::shared_ptr Voice::_findVoice(int vid, std::weak_ptr thisPtr) +{ + if (m_vid == vid) + return thisPtr.lock(); + + for (std::shared_ptr& vox : m_childVoices) + { + std::shared_ptr ret = vox->_findVoice(vid, vox); + if (ret) + return ret; + } + + return {}; +} + std::shared_ptr Voice::_allocateVoice(double sampleRate, bool dynamicPitch) { auto it = m_childVoices.emplace(m_childVoices.end(), new Voice(m_engine, m_audioGroup, @@ -244,9 +262,10 @@ size_t Voice::supplyAudio(size_t samples, int16_t* data) { uint32_t samplesRem = samples; size_t samplesProc = 0; + bool dead = false; if (m_curSample) { - m_dead = m_state.advance(*this, samples / m_sampleRate); + dead = m_state.advance(*this, samples / m_sampleRate); uint32_t block = m_curSamplePos / 14; uint32_t rem = m_curSamplePos % 14; @@ -344,11 +363,11 @@ size_t Voice::supplyAudio(size_t samples, int16_t* data) } else { - m_dead = m_state.advance(*this, 0.0); + dead = m_state.advance(*this, 0.0); memset(data, 0, sizeof(int16_t) * samples); } - if (m_dead) + if (dead) m_voxState = VoiceState::Finished; return samples; } @@ -364,8 +383,12 @@ int Voice::maxVid() const std::shared_ptr Voice::startChildMacro(int8_t addNote, ObjectId macroId, int macroStep) { std::shared_ptr vox = _allocateVoice(32000.0, true); - vox->loadSoundMacro(macroId, macroStep, 1000.0, m_state.m_initKey + addNote, - m_state.m_initVel, m_state.m_initMod); + if (!vox->loadSoundMacro(macroId, macroStep, 1000.0, m_state.m_initKey + addNote, + m_state.m_initVel, m_state.m_initMod)) + { + _destroyVoice(vox.get()); + return {}; + } return vox; }