Commit to test list iterator against STL with better asserts

This commit is contained in:
Jack Andersen 2016-05-31 10:40:51 -10:00
parent 0c8d8f571c
commit 16c105fadb
8 changed files with 127 additions and 103 deletions

View File

@ -50,15 +50,17 @@ class Engine
std::pair<AudioGroup*, const SongGroupIndex*> _findSongGroup(int groupId) const; std::pair<AudioGroup*, const SongGroupIndex*> _findSongGroup(int groupId) const;
std::pair<AudioGroup*, const SFXGroupIndex*> _findSFXGroup(int groupId) const; std::pair<AudioGroup*, const SFXGroupIndex*> _findSFXGroup(int groupId) const;
std::shared_ptr<Voice> _allocateVoice(const AudioGroup& group, int groupId, double sampleRate, std::list<std::shared_ptr<Voice>>::iterator
bool dynamicPitch, bool emitter, Submix* smx); _allocateVoice(const AudioGroup& group, int groupId, double sampleRate,
std::shared_ptr<Sequencer> _allocateSequencer(const AudioGroup& group, int groupId, bool dynamicPitch, bool emitter, Submix* smx);
int setupId, Submix* smx); std::list<std::shared_ptr<Sequencer>>::iterator
Submix* _allocateSubmix(Submix* smx); _allocateSequencer(const AudioGroup& group, int groupId,
std::list<std::shared_ptr<Voice>>::iterator _destroyVoice(Voice* voice); int setupId, Submix* smx);
std::list<std::shared_ptr<Sequencer>>::iterator _destroySequencer(Sequencer* sequencer); std::list<Submix>::iterator _allocateSubmix(Submix* smx);
std::list<Submix>::iterator _destroySubmix(Submix* smx); std::list<std::shared_ptr<Voice>>::iterator _destroyVoice(std::list<std::shared_ptr<Voice>>::iterator it);
std::list<Submix>::iterator _removeSubmix(Submix* smx); std::list<std::shared_ptr<Sequencer>>::iterator _destroySequencer(std::list<std::shared_ptr<Sequencer>>::iterator it);
std::list<Submix>::iterator _destroySubmix(std::list<Submix>::iterator it);
std::list<Submix>::iterator _removeSubmix(std::list<Submix>::iterator it);
void _bringOutYourDead(); void _bringOutYourDead();
void _5MsCallback(double dt); void _5MsCallback(double dt);
public: public:

View File

@ -30,7 +30,6 @@ class Sequencer : public Entity
const SongGroupIndex& m_songGroup; /**< Quick access to song group project index */ const SongGroupIndex& m_songGroup; /**< Quick access to song group project index */
const SongGroupIndex::MIDISetup* m_midiSetup = nullptr; /**< Selected MIDI setup */ const SongGroupIndex::MIDISetup* m_midiSetup = nullptr; /**< Selected MIDI setup */
Submix* m_submix = nullptr; /**< Submix this sequencer outputs to (or NULL for the main output mix) */ Submix* m_submix = nullptr; /**< Submix this sequencer outputs to (or NULL for the main output mix) */
std::list<std::shared_ptr<Sequencer>>::iterator m_engineIt; /**< Iterator to self within Engine's list for quick deletion */
const unsigned char* m_arrData = nullptr; /**< Current playing arrangement data */ const unsigned char* m_arrData = nullptr; /**< Current playing arrangement data */
SongState m_songState; /**< State of current arrangement playback */ SongState m_songState; /**< State of current arrangement playback */

View File

@ -24,7 +24,6 @@ class Submix
friend class Sequencer; friend class Sequencer;
Engine& m_root; Engine& m_root;
Submix* m_submix = nullptr; /**< Parent submix of this submix (or NULL if mixing to main output) */ Submix* m_submix = nullptr; /**< Parent submix of this submix (or NULL if mixing to main output) */
std::list<Submix>::iterator m_engineIt; /**< Iterator to self within Engine's list for quick deletion */
std::unique_ptr<IBackendSubmix> m_backendSubmix; /**< Handle to client-implemented backend submix */ std::unique_ptr<IBackendSubmix> m_backendSubmix; /**< Handle to client-implemented backend submix */
std::vector<std::unique_ptr<EffectBaseTypeless>> m_effectStack; /**< Ordered list of effects to apply to submix */ std::vector<std::unique_ptr<EffectBaseTypeless>> m_effectStack; /**< Ordered list of effects to apply to submix */
bool m_destroyed = false; bool m_destroyed = false;

View File

@ -35,7 +35,6 @@ class Voice : public Entity
int m_vid; /**< VoiceID of this voice instance */ int m_vid; /**< VoiceID of this voice instance */
bool m_emitter; /**< Voice is part of an Emitter */ bool m_emitter; /**< Voice is part of an Emitter */
Submix* m_submix = nullptr; /**< Submix this voice outputs to (or NULL for the main output mix) */ Submix* m_submix = nullptr; /**< Submix this voice outputs to (or NULL for the main output mix) */
std::list<std::shared_ptr<Voice>>::iterator m_engineIt; /**< Iterator to self within Engine's list for quick deletion */
std::unique_ptr<IBackendVoice> m_backendVoice; /**< Handle to client-implemented backend voice */ std::unique_ptr<IBackendVoice> m_backendVoice; /**< Handle to client-implemented backend voice */
SoundMacroState m_state; /**< State container for SoundMacro playback */ SoundMacroState m_state; /**< State container for SoundMacro playback */
@ -142,8 +141,8 @@ class Voice : public Entity
std::shared_ptr<Voice> _findVoice(int vid, std::weak_ptr<Voice> thisPtr); std::shared_ptr<Voice> _findVoice(int vid, std::weak_ptr<Voice> thisPtr);
std::unique_ptr<int8_t[]>& _ensureCtrlVals(); std::unique_ptr<int8_t[]>& _ensureCtrlVals();
std::shared_ptr<Voice> _allocateVoice(double sampleRate, bool dynamicPitch); std::list<std::shared_ptr<Voice>>::iterator _allocateVoice(double sampleRate, bool dynamicPitch);
std::list<std::shared_ptr<Voice>>::iterator _destroyVoice(Voice* voice); std::list<std::shared_ptr<Voice>>::iterator _destroyVoice(std::list<std::shared_ptr<Voice>>::iterator it);
bool _loadSoundMacro(const unsigned char* macroData, int macroStep, double ticksPerSec, bool _loadSoundMacro(const unsigned char* macroData, int macroStep, double ticksPerSec,
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod, bool pushPc=false); uint8_t midiKey, uint8_t midiVel, uint8_t midiMod, bool pushPc=false);
@ -320,6 +319,9 @@ public:
/** Get count of all voices in hierarchy, including this one */ /** Get count of all voices in hierarchy, including this one */
size_t getTotalVoices() const; size_t getTotalVoices() const;
/** Recursively mark voice as dead for Engine to deallocate on next cycle */
void kill();
}; };
} }

View File

@ -15,7 +15,7 @@ Emitter::Emitter(Engine& engine, const AudioGroup& group, std::shared_ptr<Voice>
void Emitter::_destroy() void Emitter::_destroy()
{ {
Entity::_destroy(); Entity::_destroy();
m_engine._destroyVoice(m_vox.get()); m_vox->kill();
} }
void Emitter::setPos(const Vector3f& pos) void Emitter::setPos(const Vector3f& pos)

View File

@ -52,8 +52,9 @@ std::pair<AudioGroup*, const SFXGroupIndex*> Engine::_findSFXGroup(int groupId)
return {}; return {};
} }
std::shared_ptr<Voice> Engine::_allocateVoice(const AudioGroup& group, int groupId, double sampleRate, std::list<std::shared_ptr<Voice>>::iterator
bool dynamicPitch, bool emitter, Submix* smx) Engine::_allocateVoice(const AudioGroup& group, int groupId, double sampleRate,
bool dynamicPitch, bool emitter, Submix* smx)
{ {
auto it = m_activeVoices.emplace(m_activeVoices.end(), auto it = m_activeVoices.emplace(m_activeVoices.end(),
new Voice(*this, group, groupId, m_nextVid++, emitter, smx)); new Voice(*this, group, groupId, m_nextVid++, emitter, smx));
@ -63,61 +64,62 @@ std::shared_ptr<Voice> Engine::_allocateVoice(const AudioGroup& group, int group
else else
m_activeVoices.back()->m_backendVoice = m_activeVoices.back()->m_backendVoice =
m_backend.allocateVoice(*m_activeVoices.back(), sampleRate, dynamicPitch); m_backend.allocateVoice(*m_activeVoices.back(), sampleRate, dynamicPitch);
m_activeVoices.back()->m_engineIt = it; return it;
return m_activeVoices.back();
} }
std::shared_ptr<Sequencer> Engine::_allocateSequencer(const AudioGroup& group, int groupId, std::list<std::shared_ptr<Sequencer>>::iterator
int setupId, Submix* smx) Engine::_allocateSequencer(const AudioGroup& group, int groupId,
int setupId, Submix* smx)
{ {
const SongGroupIndex* songGroup = group.getProj().getSongGroupIndex(groupId); const SongGroupIndex* songGroup = group.getProj().getSongGroupIndex(groupId);
if (!songGroup) if (!songGroup)
return {}; return {};
auto it = m_activeSequencers.emplace(m_activeSequencers.end(), auto it = m_activeSequencers.emplace(m_activeSequencers.end(),
new Sequencer(*this, group, groupId, *songGroup, setupId, smx)); new Sequencer(*this, group, groupId, *songGroup, setupId, smx));
m_activeSequencers.back()->m_engineIt = it; printf("INSERT %p\n", it->get());
return m_activeSequencers.back(); return it;
} }
Submix* Engine::_allocateSubmix(Submix* smx) std::list<Submix>::iterator Engine::_allocateSubmix(Submix* smx)
{ {
auto it = m_activeSubmixes.emplace(m_activeSubmixes.end(), *this, smx); auto it = m_activeSubmixes.emplace(m_activeSubmixes.end(), *this, smx);
m_activeSubmixes.back().m_backendSubmix = m_backend.allocateSubmix(m_activeSubmixes.back()); m_activeSubmixes.back().m_backendSubmix = m_backend.allocateSubmix(m_activeSubmixes.back());
m_activeSubmixes.back().m_engineIt = it; return it;
return &m_activeSubmixes.back();
} }
std::list<std::shared_ptr<Voice>>::iterator Engine::_destroyVoice(Voice* voice) std::list<std::shared_ptr<Voice>>::iterator Engine::_destroyVoice(std::list<std::shared_ptr<Voice>>::iterator it)
{ {
#ifndef NDEBUG #ifndef NDEBUG
assert(this == &voice->getEngine()); assert(this == &(*it)->getEngine());
#endif #endif
if (voice->m_destroyed) if ((*it)->m_destroyed)
return m_activeVoices.begin(); return m_activeVoices.begin();
voice->_destroy(); (*it)->_destroy();
return m_activeVoices.erase(voice->m_engineIt); return m_activeVoices.erase(it);
} }
std::list<std::shared_ptr<Sequencer>>::iterator Engine::_destroySequencer(Sequencer* sequencer) std::list<std::shared_ptr<Sequencer>>::iterator Engine::_destroySequencer(std::list<std::shared_ptr<Sequencer>>::iterator it)
{ {
#ifndef NDEBUG #ifndef NDEBUG
assert(this == &sequencer->getEngine()); assert(this == &(*it)->getEngine());
#endif #endif
if (sequencer->m_destroyed) if ((*it)->m_destroyed)
return m_activeSequencers.begin(); return m_activeSequencers.begin();
sequencer->_destroy(); printf("TO DESTROY %p\n", it->get());
return m_activeSequencers.erase(sequencer->m_engineIt); (*it)->_destroy();
printf("ERASE %p\n", it->get());
return m_activeSequencers.erase(it);
} }
std::list<Submix>::iterator Engine::_destroySubmix(Submix* smx) std::list<Submix>::iterator Engine::_destroySubmix(std::list<Submix>::iterator it)
{ {
#ifndef NDEBUG #ifndef NDEBUG
assert(this == &smx->getEngine()); assert(this == &it->getEngine());
#endif #endif
if (smx->m_destroyed) if (it->m_destroyed)
return m_activeSubmixes.begin(); return m_activeSubmixes.begin();
smx->_destroy(); it->_destroy();
return m_activeSubmixes.erase(smx->m_engineIt); return m_activeSubmixes.erase(it);
} }
void Engine::_bringOutYourDead() void Engine::_bringOutYourDead()
@ -140,7 +142,7 @@ void Engine::_bringOutYourDead()
vox->_bringOutYourDead(); vox->_bringOutYourDead();
if (vox->_isRecursivelyDead()) if (vox->_isRecursivelyDead())
{ {
it = _destroyVoice(vox); it = _destroyVoice(it);
continue; continue;
} }
++it; ++it;
@ -152,7 +154,7 @@ void Engine::_bringOutYourDead()
seq->_bringOutYourDead(); seq->_bringOutYourDead();
if (seq->m_state == SequencerState::Dead) if (seq->m_state == SequencerState::Dead)
{ {
it = _destroySequencer(seq); it = _destroySequencer(it);
continue; continue;
} }
++it; ++it;
@ -280,10 +282,10 @@ void Engine::removeAudioGroup(const AudioGroupData& data)
/** Create new Submix (a.k.a 'Studio') within root mix engine */ /** Create new Submix (a.k.a 'Studio') within root mix engine */
Submix* Engine::addSubmix(Submix* smx) Submix* Engine::addSubmix(Submix* smx)
{ {
return _allocateSubmix(smx); return &*_allocateSubmix(smx);
} }
std::list<Submix>::iterator Engine::_removeSubmix(Submix* smx) std::list<Submix>::iterator Engine::_removeSubmix(std::list<Submix>::iterator smx)
{ {
/* Delete all voices bound to submix */ /* Delete all voices bound to submix */
for (auto it = m_activeVoices.begin() ; it != m_activeVoices.end() ;) for (auto it = m_activeVoices.begin() ; it != m_activeVoices.end() ;)
@ -291,7 +293,7 @@ std::list<Submix>::iterator Engine::_removeSubmix(Submix* smx)
Voice* vox = it->get(); Voice* vox = it->get();
Submix* vsmx = vox->getSubmix(); Submix* vsmx = vox->getSubmix();
if (vsmx == smx) if (vsmx == &*smx)
{ {
vox->_destroy(); vox->_destroy();
it = m_activeVoices.erase(it); it = m_activeVoices.erase(it);
@ -306,7 +308,7 @@ std::list<Submix>::iterator Engine::_removeSubmix(Submix* smx)
Sequencer* seq = it->get(); Sequencer* seq = it->get();
Submix* ssmx = seq->getSubmix(); Submix* ssmx = seq->getSubmix();
if (ssmx == smx) if (ssmx == &*smx)
{ {
if (!seq->m_destroyed) if (!seq->m_destroyed)
seq->_destroy(); seq->_destroy();
@ -320,9 +322,9 @@ std::list<Submix>::iterator Engine::_removeSubmix(Submix* smx)
for (auto it = m_activeSubmixes.begin() ; it != m_activeSubmixes.end() ;) for (auto it = m_activeSubmixes.begin() ; it != m_activeSubmixes.end() ;)
{ {
Submix* ssmx = it->getParentSubmix(); Submix* ssmx = it->getParentSubmix();
if (ssmx == smx) if (ssmx == &*smx)
{ {
it = _removeSubmix(&*it); it = _removeSubmix(it);
continue; continue;
} }
++it; ++it;
@ -337,7 +339,16 @@ void Engine::removeSubmix(Submix* smx)
{ {
if (!smx) if (!smx)
return; return;
_removeSubmix(smx);
for (auto it = m_activeSubmixes.begin() ; it != m_activeSubmixes.end() ;)
{
if (&*it == &*smx)
{
it = _removeSubmix(it);
break;
}
++it;
}
} }
/** Start soundFX playing from loaded audio groups */ /** Start soundFX playing from loaded audio groups */
@ -352,19 +363,20 @@ std::shared_ptr<Voice> Engine::fxStart(int sfxId, float vol, float pan, Submix*
if (!grp) if (!grp)
return nullptr; return nullptr;
std::shared_ptr<Voice> ret = _allocateVoice(*grp, std::get<1>(search->second), std::list<std::shared_ptr<Voice>>::iterator ret =
32000.0, true, false, smx); _allocateVoice(*grp, std::get<1>(search->second),
32000.0, true, false, smx);
ObjectId oid = (grp->getDataFormat() == DataFormat::PC) ? entry->objId : SBig(entry->objId); ObjectId oid = (grp->getDataFormat() == DataFormat::PC) ? entry->objId : SBig(entry->objId);
if (!ret->loadSoundObject(oid, 0, 1000.f, entry->defKey, entry->defVel, 0)) if (!(*ret)->loadSoundObject(oid, 0, 1000.f, entry->defKey, entry->defVel, 0))
{ {
_destroyVoice(ret.get()); _destroyVoice(ret);
return {}; return {};
} }
ret->setVolume(vol); (*ret)->setVolume(vol);
ret->setPan(pan); (*ret)->setPan(pan);
return ret; return *ret;
} }
/** Start soundFX playing from loaded audio groups, attach to positional emitter */ /** Start soundFX playing from loaded audio groups, attach to positional emitter */
@ -380,20 +392,21 @@ std::shared_ptr<Emitter> Engine::addEmitter(const Vector3f& pos, const Vector3f&
if (!grp) if (!grp)
return nullptr; return nullptr;
std::shared_ptr<Voice> vox = _allocateVoice(*grp, std::get<1>(search->second), std::list<std::shared_ptr<Voice>>::iterator vox =
32000.0, true, true, smx); _allocateVoice(*grp, std::get<1>(search->second),
m_activeEmitters.emplace(m_activeEmitters.end(), new Emitter(*this, *grp, std::move(vox))); 32000.0, true, true, smx);
Emitter& ret = *m_activeEmitters.back(); auto emitIt = m_activeEmitters.emplace(m_activeEmitters.end(), new Emitter(*this, *grp, std::move(*vox)));
Emitter& ret = *(*emitIt);
ObjectId oid = (grp->getDataFormat() == DataFormat::PC) ? entry->objId : SBig(entry->objId); ObjectId oid = (grp->getDataFormat() == DataFormat::PC) ? entry->objId : SBig(entry->objId);
if (!ret.getVoice()->loadSoundObject(oid, 0, 1000.f, entry->defKey, entry->defVel, 0)) if (!ret.getVoice()->loadSoundObject(oid, 0, 1000.f, entry->defKey, entry->defVel, 0))
{ {
ret._destroy(); ret._destroy();
m_activeEmitters.pop_back(); m_activeEmitters.erase(emitIt);
return {}; return {};
} }
vox->setPan(entry->panning); (*vox)->setPan(entry->panning);
ret.setPos(pos); ret.setPos(pos);
ret.setDir(dir); ret.setDir(dir);
ret.setMaxDist(maxDist); ret.setMaxDist(maxDist);
@ -401,7 +414,7 @@ std::shared_ptr<Emitter> Engine::addEmitter(const Vector3f& pos, const Vector3f&
ret.setMinVol(minVol); ret.setMinVol(minVol);
ret.setMaxVol(maxVol); ret.setMaxVol(maxVol);
return m_activeEmitters.back(); return *emitIt;
} }
/** Start song playing from loaded audio groups */ /** Start song playing from loaded audio groups */
@ -412,13 +425,13 @@ std::shared_ptr<Sequencer> Engine::seqPlay(int groupId, int songId,
if (!songGrp.second) if (!songGrp.second)
return {}; return {};
std::shared_ptr<Sequencer> ret = _allocateSequencer(*songGrp.first, groupId, songId, smx); std::list<std::shared_ptr<Sequencer>>::iterator ret = _allocateSequencer(*songGrp.first, groupId, songId, smx);
if (!ret) if (!*ret)
return {}; return {};
if (arrData) if (arrData)
ret->playSong(arrData); (*ret)->playSong(arrData);
return ret; return *ret;
} }
/** Find voice from VoiceId */ /** Find voice from VoiceId */
@ -451,7 +464,7 @@ void Engine::killKeygroup(uint8_t kg, bool now)
{ {
if (now) if (now)
{ {
it = _destroyVoice(vox); it = _destroyVoice(it);
continue; continue;
} }
vox->keyOff(); vox->keyOff();

View File

@ -45,6 +45,7 @@ void Sequencer::_bringOutYourDead()
void Sequencer::_destroy() void Sequencer::_destroy()
{ {
printf("DESTROY %p\n", this);
Entity::_destroy(); Entity::_destroy();
if (m_submix) if (m_submix)
{ {
@ -55,6 +56,7 @@ void Sequencer::_destroy()
Sequencer::~Sequencer() Sequencer::~Sequencer()
{ {
printf("DEALLOC %p\n", this);
if (m_submix) if (m_submix)
m_engine.removeSubmix(m_submix); m_engine.removeSubmix(m_submix);
} }
@ -142,30 +144,31 @@ std::shared_ptr<Voice> Sequencer::ChannelState::keyOn(uint8_t note, uint8_t velo
m_chanVoxs.erase(keySearch); m_chanVoxs.erase(keySearch);
} }
std::shared_ptr<Voice> ret = m_parent.m_engine._allocateVoice(m_parent.m_audioGroup, std::list<std::shared_ptr<Voice>>::iterator ret =
m_parent.m_groupId, 32000.0, m_parent.m_engine._allocateVoice(m_parent.m_audioGroup,
true, false, m_parent.m_submix); m_parent.m_groupId, 32000.0,
if (ret) true, false, m_parent.m_submix);
if (*ret)
{ {
m_chanVoxs[note] = ret; m_chanVoxs[note] = *ret;
ret->installCtrlValues(m_ctrlVals); (*ret)->installCtrlValues(m_ctrlVals);
ObjectId oid = (m_parent.m_audioGroup.getDataFormat() == DataFormat::PC) ? m_page->objId : SBig(m_page->objId); ObjectId oid = (m_parent.m_audioGroup.getDataFormat() == DataFormat::PC) ? m_page->objId : SBig(m_page->objId);
if (!ret->loadSoundObject(oid, 0, 1000.f, note, velocity, m_ctrlVals[1])) if (!(*ret)->loadSoundObject(oid, 0, 1000.f, note, velocity, m_ctrlVals[1]))
{ {
m_parent.m_engine._destroyVoice(ret.get()); m_parent.m_engine._destroyVoice(ret);
return {}; return {};
} }
ret->setVolume(m_parent.m_curVol * m_curVol); (*ret)->setVolume(m_parent.m_curVol * m_curVol);
ret->setReverbVol(m_ctrlVals[0x5b] / 127.f); (*ret)->setReverbVol(m_ctrlVals[0x5b] / 127.f);
ret->setPan(m_curPan); (*ret)->setPan(m_curPan);
ret->setPitchWheel(m_curPitchWheel); (*ret)->setPitchWheel(m_curPitchWheel);
if (m_ctrlVals[64] > 64) if (m_ctrlVals[64] > 64)
ret->setPedal(true); (*ret)->setPedal(true);
} }
return ret; return *ret;
} }
std::shared_ptr<Voice> Sequencer::keyOn(uint8_t chan, uint8_t note, uint8_t velocity) std::shared_ptr<Voice> Sequencer::keyOn(uint8_t chan, uint8_t note, uint8_t velocity)
@ -313,9 +316,9 @@ void Sequencer::allOff(bool now)
if (chan) if (chan)
{ {
for (const auto& vox : chan->m_chanVoxs) for (const auto& vox : chan->m_chanVoxs)
m_engine._destroyVoice(vox.second.get()); vox.second->kill();
for (const auto& vox : chan->m_keyoffVoxs) for (const auto& vox : chan->m_keyoffVoxs)
m_engine._destroyVoice(vox.get()); vox->kill();
chan->m_chanVoxs.clear(); chan->m_chanVoxs.clear();
chan->m_keyoffVoxs.clear(); chan->m_keyoffVoxs.clear();
} }
@ -334,9 +337,9 @@ void Sequencer::allOff(uint8_t chan, bool now)
if (now) if (now)
{ {
for (const auto& vox : m_chanStates[chan]->m_chanVoxs) for (const auto& vox : m_chanStates[chan]->m_chanVoxs)
m_engine._destroyVoice(vox.second.get()); vox.second->kill();
for (const auto& vox : m_chanStates[chan]->m_keyoffVoxs) for (const auto& vox : m_chanStates[chan]->m_keyoffVoxs)
m_engine._destroyVoice(vox.get()); vox->kill();
m_chanStates[chan]->m_chanVoxs.clear(); m_chanStates[chan]->m_chanVoxs.clear();
m_chanStates[chan]->m_keyoffVoxs.clear(); m_chanStates[chan]->m_keyoffVoxs.clear();
} }

View File

@ -155,7 +155,7 @@ void Voice::_bringOutYourDead()
vox->_bringOutYourDead(); vox->_bringOutYourDead();
if (vox->_isRecursivelyDead()) if (vox->_isRecursivelyDead())
{ {
it = _destroyVoice(vox); it = _destroyVoice(it);
continue; continue;
} }
++it; ++it;
@ -186,7 +186,7 @@ std::unique_ptr<int8_t[]>& Voice::_ensureCtrlVals()
return m_ctrlValsSelf; return m_ctrlValsSelf;
} }
std::shared_ptr<Voice> Voice::_allocateVoice(double sampleRate, bool dynamicPitch) std::list<std::shared_ptr<Voice>>::iterator 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,
m_groupId, m_engine.m_nextVid++, m_emitter, m_submix)); m_groupId, m_engine.m_nextVid++, m_emitter, m_submix));
@ -196,17 +196,16 @@ std::shared_ptr<Voice> Voice::_allocateVoice(double sampleRate, bool dynamicPitc
else else
m_childVoices.back()->m_backendVoice = m_childVoices.back()->m_backendVoice =
m_engine.getBackend().allocateVoice(*m_childVoices.back(), sampleRate, dynamicPitch); m_engine.getBackend().allocateVoice(*m_childVoices.back(), sampleRate, dynamicPitch);
m_childVoices.back()->m_engineIt = it; return it;
return m_childVoices.back();
} }
std::list<std::shared_ptr<Voice>>::iterator Voice::_destroyVoice(Voice* voice) std::list<std::shared_ptr<Voice>>::iterator Voice::_destroyVoice(std::list<std::shared_ptr<Voice>>::iterator it)
{ {
if (voice->m_destroyed) if ((*it)->m_destroyed)
return m_childVoices.begin(); return m_childVoices.begin();
voice->_destroy(); (*it)->_destroy();
return m_childVoices.erase(voice->m_engineIt); return m_childVoices.erase(it);
} }
static void ApplyVolume(float vol, int16_t& samp) static void ApplyVolume(float vol, int16_t& samp)
@ -553,17 +552,17 @@ int Voice::maxVid() const
std::shared_ptr<Voice> Voice::_startChildMacro(ObjectId macroId, int macroStep, double ticksPerSec, std::shared_ptr<Voice> Voice::_startChildMacro(ObjectId macroId, int macroStep, double ticksPerSec,
uint8_t midiKey, uint8_t midiVel, uint8_t midiMod, bool pushPc) uint8_t midiKey, uint8_t midiVel, uint8_t midiMod, bool pushPc)
{ {
std::shared_ptr<Voice> vox = _allocateVoice(32000.0, true); std::list<std::shared_ptr<Voice>>::iterator vox = _allocateVoice(32000.0, true);
if (!vox->loadSoundObject(macroId, macroStep, ticksPerSec, midiKey, if (!(*vox)->loadSoundObject(macroId, macroStep, ticksPerSec, midiKey,
midiVel, midiMod, pushPc)) midiVel, midiMod, pushPc))
{ {
_destroyVoice(vox.get()); _destroyVoice(vox);
return {}; return {};
} }
vox->setVolume(m_userVol); (*vox)->setVolume(m_userVol);
vox->setPan(m_userPan); (*vox)->setPan(m_userPan);
vox->setSurroundPan(m_userSpan); (*vox)->setSurroundPan(m_userSpan);
return vox; return *vox;
} }
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)
@ -1046,4 +1045,11 @@ size_t Voice::getTotalVoices() const
return ret; return ret;
} }
void Voice::kill()
{
m_voxState = VoiceState::Dead;
for (const std::shared_ptr<Voice>& vox : m_childVoices)
vox->kill();
}
} }