mirror of https://github.com/AxioDL/amuse.git
More fixes, better lifetime management
This commit is contained in:
parent
ccefe60a9d
commit
2341b6b7d0
|
@ -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;}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue