More fixes, better lifetime management

This commit is contained in:
Jack Andersen 2016-05-13 20:33:21 -10:00
parent ccefe60a9d
commit 2341b6b7d0
7 changed files with 86 additions and 20 deletions

View File

@ -2,6 +2,7 @@
#define __AMUSE_EMITTER_HPP__ #define __AMUSE_EMITTER_HPP__
#include "Entity.hpp" #include "Entity.hpp"
#include <memory>
namespace amuse namespace amuse
{ {
@ -11,9 +12,12 @@ using Vector3f = float[3];
class Emitter : public Entity class Emitter : public Entity
{ {
Voice& m_vox; std::shared_ptr<Voice> m_vox;
friend class Engine;
void _destroy();
public: public:
Emitter(Engine& engine, const AudioGroup& group, Voice& vox); Emitter(Engine& engine, const AudioGroup& group, std::shared_ptr<Voice>&& vox);
void setPos(const Vector3f& pos); void setPos(const Vector3f& pos);
void setDir(const Vector3f& dir); void setDir(const Vector3f& dir);
@ -21,6 +25,8 @@ public:
void setMaxVol(float maxVol); void setMaxVol(float maxVol);
void setMinVol(float minVol); void setMinVol(float minVol);
void setFalloff(float falloff); void setFalloff(float falloff);
std::shared_ptr<Voice>& getVoice() {return m_vox;}
}; };
} }

View File

@ -23,6 +23,7 @@ class AudioGroupData;
class Engine class Engine
{ {
friend class Voice; friend class Voice;
friend class Emitter;
IBackendVoiceAllocator& m_backend; IBackendVoiceAllocator& m_backend;
std::unordered_map<int, std::unique_ptr<AudioGroup>> m_audioGroups; std::unordered_map<int, std::unique_ptr<AudioGroup>> m_audioGroups;

View File

@ -32,7 +32,13 @@ class Entity
friend class SoundMacroState; friend class SoundMacroState;
bool m_destroyed = false; bool m_destroyed = false;
protected: protected:
void _destroy() {m_destroyed = true;} void _destroy()
{
#ifndef NDEBUG
assert(!m_destroyed);
#endif
m_destroyed = true;
}
Engine& m_engine; Engine& m_engine;
const AudioGroup& m_audioGroup; const AudioGroup& m_audioGroup;
ObjectId m_objectId; /* if applicable */ ObjectId m_objectId; /* if applicable */

View File

@ -19,9 +19,9 @@ class Submix;
/** State of voice over lifetime */ /** State of voice over lifetime */
enum class VoiceState enum class VoiceState
{ {
Playing, Playing, /**< SoundMacro actively executing, not in KeyOff */
KeyOff, KeyOff, /**< KeyOff event issued, macro beginning fade-out */
Finished Finished /**< Default state, causes Engine to remove voice at end of pump cycle */
}; };
/** Individual source of audio */ /** Individual source of audio */
@ -104,8 +104,6 @@ class Voice : public Entity
float m_lfoPeriods[2]; /**< time-periods for LFO1 and LFO2 */ 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 _destroy();
void _reset(); void _reset();
bool _checkSamplePos(); bool _checkSamplePos();
@ -113,6 +111,7 @@ class Voice : public Entity
bool _advanceSample(int16_t& samp); bool _advanceSample(int16_t& samp);
void _setTotalPitch(int32_t cents); void _setTotalPitch(int32_t cents);
void _bringOutYourDead(); void _bringOutYourDead();
std::shared_ptr<Voice> _findVoice(int vid, std::weak_ptr<Voice> thisPtr);
std::shared_ptr<Voice> _allocateVoice(double sampleRate, bool dynamicPitch); std::shared_ptr<Voice> _allocateVoice(double sampleRate, bool dynamicPitch);
std::list<std::shared_ptr<Voice>>::iterator _destroyVoice(Voice* voice); std::list<std::shared_ptr<Voice>>::iterator _destroyVoice(Voice* voice);

View File

@ -1,14 +1,21 @@
#include "amuse/Emitter.hpp" #include "amuse/Emitter.hpp"
#include "amuse/Voice.hpp" #include "amuse/Voice.hpp"
#include "amuse/Engine.hpp"
namespace amuse namespace amuse
{ {
Emitter::Emitter(Engine& engine, const AudioGroup& group, Voice& vox) Emitter::Emitter(Engine& engine, const AudioGroup& group, std::shared_ptr<Voice>&& vox)
: Entity(engine, group, vox.getObjectId()), m_vox(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) void Emitter::setPos(const Vector3f& pos)
{ {
} }

View File

@ -53,11 +53,21 @@ std::list<Submix>::iterator Engine::_destroySubmix(Submix* smx)
void Engine::_bringOutYourDead() 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() ;) for (auto it = m_activeVoices.begin() ; it != m_activeVoices.end() ;)
{ {
Voice* vox = it->get(); Voice* vox = it->get();
vox->_bringOutYourDead(); vox->_bringOutYourDead();
if (vox->m_dead) if (vox->m_voxState == VoiceState::Finished)
{ {
it = _destroyVoice(vox); it = _destroyVoice(vox);
continue; continue;
@ -209,6 +219,11 @@ std::shared_ptr<Voice> Engine::fxStart(int sfxId, float vol, float pan, Submix*
return nullptr; return nullptr;
std::shared_ptr<Voice> ret = _allocateVoice(*grp, 32000.0, true, false, smx); std::shared_ptr<Voice> 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->setVolume(vol);
ret->setPan(pan); ret->setPan(pan);
return ret; return ret;
@ -227,8 +242,14 @@ std::shared_ptr<Emitter> Engine::addEmitter(const Vector3f& pos, const Vector3f&
return nullptr; return nullptr;
std::shared_ptr<Voice> vox = _allocateVoice(*grp, 32000.0, true, true, smx); std::shared_ptr<Voice> 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(); 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.setPos(pos);
ret.setDir(dir); ret.setDir(dir);
ret.setMaxDist(maxDist); ret.setMaxDist(maxDist);
@ -249,8 +270,11 @@ std::shared_ptr<Sequencer> Engine::seqPlay(int groupId, int songId, const unsign
std::shared_ptr<Voice> Engine::findVoice(int vid) std::shared_ptr<Voice> Engine::findVoice(int vid)
{ {
for (std::shared_ptr<Voice>& vox : m_activeVoices) for (std::shared_ptr<Voice>& vox : m_activeVoices)
if (vox->vid() == vid) {
return vox; std::shared_ptr<Voice> ret = vox->_findVoice(vid, vox);
if (ret)
return ret;
}
return {}; return {};
} }

View File

@ -17,6 +17,9 @@ void Voice::_destroy()
Entity::_destroy(); Entity::_destroy();
if (m_submix) if (m_submix)
m_submix->m_activeVoices.erase(this); m_submix->m_activeVoices.erase(this);
for (std::shared_ptr<Voice>& vox : m_childVoices)
vox->_destroy();
} }
Voice::Voice(Engine& engine, const AudioGroup& group, int vid, bool emitter, Submix* smx) Voice::Voice(Engine& engine, const AudioGroup& group, int vid, bool emitter, Submix* smx)
@ -96,7 +99,7 @@ void Voice::_bringOutYourDead()
{ {
Voice* vox = it->get(); Voice* vox = it->get();
vox->_bringOutYourDead(); vox->_bringOutYourDead();
if (vox->m_dead) if (vox->m_voxState == VoiceState::Finished)
{ {
it = _destroyVoice(vox); it = _destroyVoice(vox);
continue; continue;
@ -105,6 +108,21 @@ void Voice::_bringOutYourDead()
} }
} }
std::shared_ptr<Voice> Voice::_findVoice(int vid, std::weak_ptr<Voice> thisPtr)
{
if (m_vid == vid)
return thisPtr.lock();
for (std::shared_ptr<Voice>& vox : m_childVoices)
{
std::shared_ptr<Voice> ret = vox->_findVoice(vid, vox);
if (ret)
return ret;
}
return {};
}
std::shared_ptr<Voice> Voice::_allocateVoice(double sampleRate, bool dynamicPitch) std::shared_ptr<Voice> Voice::_allocateVoice(double sampleRate, bool dynamicPitch)
{ {
auto it = m_childVoices.emplace(m_childVoices.end(), new Voice(m_engine, m_audioGroup, 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; uint32_t samplesRem = samples;
size_t samplesProc = 0; size_t samplesProc = 0;
bool dead = false;
if (m_curSample) 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 block = m_curSamplePos / 14;
uint32_t rem = m_curSamplePos % 14; uint32_t rem = m_curSamplePos % 14;
@ -344,11 +363,11 @@ size_t Voice::supplyAudio(size_t samples, int16_t* data)
} }
else else
{ {
m_dead = m_state.advance(*this, 0.0); dead = m_state.advance(*this, 0.0);
memset(data, 0, sizeof(int16_t) * samples); memset(data, 0, sizeof(int16_t) * samples);
} }
if (m_dead) if (dead)
m_voxState = VoiceState::Finished; m_voxState = VoiceState::Finished;
return samples; return samples;
} }
@ -364,8 +383,12 @@ int Voice::maxVid() const
std::shared_ptr<Voice> Voice::startChildMacro(int8_t addNote, ObjectId macroId, int macroStep) std::shared_ptr<Voice> Voice::startChildMacro(int8_t addNote, ObjectId macroId, int macroStep)
{ {
std::shared_ptr<Voice> vox = _allocateVoice(32000.0, true); std::shared_ptr<Voice> vox = _allocateVoice(32000.0, true);
vox->loadSoundMacro(macroId, macroStep, 1000.0, m_state.m_initKey + addNote, if (!vox->loadSoundMacro(macroId, macroStep, 1000.0, m_state.m_initKey + addNote,
m_state.m_initVel, m_state.m_initMod); m_state.m_initVel, m_state.m_initMod))
{
_destroyVoice(vox.get());
return {};
}
return vox; return vox;
} }