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__
#include "Entity.hpp"
#include <memory>
namespace amuse
{
@ -11,9 +12,12 @@ using Vector3f = float[3];
class Emitter : public Entity
{
Voice& m_vox;
std::shared_ptr<Voice> 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<Voice>&& 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<Voice>& getVoice() {return m_vox;}
};
}

View File

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

View File

@ -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 */

View File

@ -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<Voice> _findVoice(int vid, std::weak_ptr<Voice> thisPtr);
std::shared_ptr<Voice> _allocateVoice(double sampleRate, bool dynamicPitch);
std::list<std::shared_ptr<Voice>>::iterator _destroyVoice(Voice* voice);

View File

@ -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<Voice>&& 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)
{
}

View File

@ -53,11 +53,21 @@ std::list<Submix>::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<Voice> Engine::fxStart(int sfxId, float vol, float pan, Submix*
return nullptr;
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->setPan(pan);
return ret;
@ -227,8 +242,14 @@ std::shared_ptr<Emitter> Engine::addEmitter(const Vector3f& pos, const Vector3f&
return nullptr;
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();
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<Sequencer> Engine::seqPlay(int groupId, int songId, const unsign
std::shared_ptr<Voice> Engine::findVoice(int vid)
{
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 {};
}

View File

@ -17,6 +17,9 @@ void Voice::_destroy()
Entity::_destroy();
if (m_submix)
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)
@ -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> 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)
{
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> Voice::startChildMacro(int8_t addNote, ObjectId macroId, int macroStep)
{
std::shared_ptr<Voice> 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;
}