mirror of
https://github.com/AxioDL/boo.git
synced 2025-12-20 18:29:16 +00:00
Object tracker list refactor; add object tracker to audio system
This commit is contained in:
@@ -8,17 +8,21 @@ namespace boo
|
||||
{
|
||||
|
||||
AudioSubmix::AudioSubmix(BaseAudioVoiceEngine& root, IAudioSubmixCallback* cb, int busId, bool mainOut)
|
||||
: m_root(root), m_busId(busId), m_cb(cb), m_mainOut(mainOut)
|
||||
: ListNode<AudioSubmix, BaseAudioVoiceEngine*, IAudioSubmix>(&root), m_busId(busId), m_cb(cb), m_mainOut(mainOut)
|
||||
{
|
||||
if (mainOut)
|
||||
setSendLevel(&m_root.m_mainSubmix, 1.f, false);
|
||||
setSendLevel(m_head->m_mainSubmix.get(), 1.f, false);
|
||||
}
|
||||
|
||||
AudioSubmix::~AudioSubmix()
|
||||
{
|
||||
unbindSubmix();
|
||||
m_head->m_submixesDirty = true;
|
||||
}
|
||||
|
||||
AudioSubmix*& AudioSubmix::_getHeadPtr(BaseAudioVoiceEngine* head) { return head->m_submixHead; }
|
||||
std::unique_lock<std::recursive_mutex> AudioSubmix::_getHeadLock(BaseAudioVoiceEngine* head)
|
||||
{ return std::unique_lock<std::recursive_mutex>{head->m_dataMutex}; }
|
||||
|
||||
bool AudioSubmix::_isDirectDependencyOf(AudioSubmix* send)
|
||||
{
|
||||
return m_sendGains.find(send) != m_sendGains.cend();
|
||||
@@ -56,13 +60,14 @@ bool AudioSubmix::_mergeC3(std::list<AudioSubmix*>& output,
|
||||
std::list<AudioSubmix*> AudioSubmix::_linearizeC3()
|
||||
{
|
||||
std::vector<std::list<AudioSubmix*>> lists = {{}};
|
||||
for (AudioSubmix* smx : m_root.m_activeSubmixes)
|
||||
{
|
||||
if (smx == this)
|
||||
continue;
|
||||
if (smx->_isDirectDependencyOf(this))
|
||||
lists[0].push_back(smx);
|
||||
}
|
||||
if (m_head->m_submixHead)
|
||||
for (AudioSubmix& smx : *m_head->m_submixHead)
|
||||
{
|
||||
if (&smx == this)
|
||||
continue;
|
||||
if (smx._isDirectDependencyOf(this))
|
||||
lists[0].push_back(&smx);
|
||||
}
|
||||
lists.reserve(lists[0].size() + 1);
|
||||
for (AudioSubmix* smx : lists[0])
|
||||
lists.push_back(smx->_linearizeC3());
|
||||
@@ -72,86 +77,82 @@ std::list<AudioSubmix*> AudioSubmix::_linearizeC3()
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AudioSubmix::_zeroFill16()
|
||||
template <typename T>
|
||||
void AudioSubmix::_zeroFill()
|
||||
{
|
||||
if (m_scratch16.size())
|
||||
std::fill(m_scratch16.begin(), m_scratch16.end(), 0);
|
||||
if (_getScratch<T>().size())
|
||||
std::fill(_getScratch<T>().begin(), _getScratch<T>().end(), 0);
|
||||
}
|
||||
|
||||
void AudioSubmix::_zeroFill32()
|
||||
template void AudioSubmix::_zeroFill<int16_t>();
|
||||
template void AudioSubmix::_zeroFill<int32_t>();
|
||||
template void AudioSubmix::_zeroFill<float>();
|
||||
|
||||
template <typename T>
|
||||
T* AudioSubmix::_getMergeBuf(size_t frames)
|
||||
{
|
||||
if (m_scratch32.size())
|
||||
std::fill(m_scratch32.begin(), m_scratch32.end(), 0);
|
||||
if (_getRedirect<T>())
|
||||
return _getRedirect<T>();
|
||||
|
||||
size_t sampleCount = frames * m_head->clientMixInfo().m_channelMap.m_channelCount;
|
||||
if (_getScratch<T>().size() < sampleCount)
|
||||
_getScratch<T>().resize(sampleCount);
|
||||
|
||||
return _getScratch<T>().data();
|
||||
}
|
||||
|
||||
void AudioSubmix::_zeroFillFlt()
|
||||
template int16_t* AudioSubmix::_getMergeBuf<int16_t>(size_t frames);
|
||||
template int32_t* AudioSubmix::_getMergeBuf<int32_t>(size_t frames);
|
||||
template float* AudioSubmix::_getMergeBuf<float>(size_t frames);
|
||||
|
||||
template <typename T>
|
||||
static inline T ClampInt(float in)
|
||||
{
|
||||
if (m_scratchFlt.size())
|
||||
std::fill(m_scratchFlt.begin(), m_scratchFlt.end(), 0.f);
|
||||
if (std::is_floating_point<T>())
|
||||
{
|
||||
return in; // Allow subsequent mixing stages to work with over-saturated values
|
||||
}
|
||||
else
|
||||
{
|
||||
constexpr T MAX = std::numeric_limits<T>::max();
|
||||
constexpr T MIN = std::numeric_limits<T>::min();
|
||||
|
||||
if (in < MIN)
|
||||
return MIN;
|
||||
else if (in > MAX)
|
||||
return MAX;
|
||||
else
|
||||
return in;
|
||||
}
|
||||
}
|
||||
|
||||
int16_t* AudioSubmix::_getMergeBuf16(size_t frames)
|
||||
template <typename T>
|
||||
size_t AudioSubmix::_pumpAndMix(size_t frames)
|
||||
{
|
||||
if (m_redirect16)
|
||||
return m_redirect16;
|
||||
|
||||
size_t sampleCount = frames * m_root.clientMixInfo().m_channelMap.m_channelCount;
|
||||
if (m_scratch16.size() < sampleCount)
|
||||
m_scratch16.resize(sampleCount);
|
||||
|
||||
return m_scratch16.data();
|
||||
}
|
||||
|
||||
int32_t* AudioSubmix::_getMergeBuf32(size_t frames)
|
||||
{
|
||||
if (m_redirect32)
|
||||
return m_redirect32;
|
||||
|
||||
size_t sampleCount = frames * m_root.clientMixInfo().m_channelMap.m_channelCount;
|
||||
if (m_scratch32.size() < sampleCount)
|
||||
m_scratch32.resize(sampleCount);
|
||||
|
||||
return m_scratch32.data();
|
||||
}
|
||||
|
||||
float* AudioSubmix::_getMergeBufFlt(size_t frames)
|
||||
{
|
||||
if (m_redirectFlt)
|
||||
return m_redirectFlt;
|
||||
|
||||
size_t sampleCount = frames * m_root.clientMixInfo().m_channelMap.m_channelCount;
|
||||
if (m_scratchFlt.size() < sampleCount)
|
||||
m_scratchFlt.resize(sampleCount);
|
||||
|
||||
return m_scratchFlt.data();
|
||||
}
|
||||
|
||||
size_t AudioSubmix::_pumpAndMix16(size_t frames)
|
||||
{
|
||||
const ChannelMap& chMap = m_root.clientMixInfo().m_channelMap;
|
||||
const ChannelMap& chMap = m_head->clientMixInfo().m_channelMap;
|
||||
size_t chanCount = chMap.m_channelCount;
|
||||
|
||||
if (m_redirect16)
|
||||
if (_getRedirect<T>())
|
||||
{
|
||||
if (m_cb && m_cb->canApplyEffect())
|
||||
m_cb->applyEffect(m_redirect16, frames, chMap, m_root.mixInfo().m_sampleRate);
|
||||
m_redirect16 += chanCount * frames;
|
||||
m_cb->applyEffect(_getRedirect<T>(), frames, chMap, m_head->mixInfo().m_sampleRate);
|
||||
_getRedirect<T>() += chanCount * frames;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t sampleCount = frames * chanCount;
|
||||
if (m_scratch16.size() < sampleCount)
|
||||
m_scratch16.resize(sampleCount);
|
||||
if (_getScratch<T>().size() < sampleCount)
|
||||
_getScratch<T>().resize(sampleCount);
|
||||
if (m_cb && m_cb->canApplyEffect())
|
||||
m_cb->applyEffect(m_scratch16.data(), frames, chMap, m_root.mixInfo().m_sampleRate);
|
||||
m_cb->applyEffect(_getScratch<T>().data(), frames, chMap, m_head->mixInfo().m_sampleRate);
|
||||
|
||||
size_t curSlewFrame = m_slewFrames;
|
||||
for (auto& smx : m_sendGains)
|
||||
{
|
||||
curSlewFrame = m_curSlewFrame;
|
||||
AudioSubmix& sm = *reinterpret_cast<AudioSubmix*>(smx.first);
|
||||
auto it = m_scratch16.begin();
|
||||
int16_t* dataOut = sm._getMergeBuf16(frames);
|
||||
auto it = _getScratch<T>().begin();
|
||||
T* dataOut = sm._getMergeBuf<T>(frames);
|
||||
|
||||
for (size_t f=0 ; f<frames ; ++f)
|
||||
{
|
||||
@@ -162,7 +163,7 @@ size_t AudioSubmix::_pumpAndMix16(size_t frames)
|
||||
|
||||
for (unsigned c=0 ; c<chanCount ; ++c)
|
||||
{
|
||||
*dataOut = Clamp16(*dataOut + *it * (smx.second[1] * t + smx.second[0] * omt));
|
||||
*dataOut = ClampInt<T>(*dataOut + *it * (smx.second[1] * t + smx.second[0] * omt));
|
||||
++it;
|
||||
++dataOut;
|
||||
}
|
||||
@@ -173,7 +174,7 @@ size_t AudioSubmix::_pumpAndMix16(size_t frames)
|
||||
{
|
||||
for (unsigned c=0 ; c<chanCount ; ++c)
|
||||
{
|
||||
*dataOut = Clamp16(*dataOut + *it * smx.second[1]);
|
||||
*dataOut = ClampInt<T>(*dataOut + *it * smx.second[1]);
|
||||
++it;
|
||||
++dataOut;
|
||||
}
|
||||
@@ -186,130 +187,14 @@ size_t AudioSubmix::_pumpAndMix16(size_t frames)
|
||||
return frames;
|
||||
}
|
||||
|
||||
size_t AudioSubmix::_pumpAndMix32(size_t frames)
|
||||
{
|
||||
const ChannelMap& chMap = m_root.clientMixInfo().m_channelMap;
|
||||
size_t chanCount = chMap.m_channelCount;
|
||||
|
||||
if (m_redirect32)
|
||||
{
|
||||
if (m_cb && m_cb->canApplyEffect())
|
||||
m_cb->applyEffect(m_redirect32, frames, chMap, m_root.mixInfo().m_sampleRate);
|
||||
m_redirect32 += chanCount * frames;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t sampleCount = frames * chanCount;
|
||||
if (m_scratch32.size() < sampleCount)
|
||||
m_scratch32.resize(sampleCount);
|
||||
if (m_cb && m_cb->canApplyEffect())
|
||||
m_cb->applyEffect(m_scratch32.data(), frames, chMap, m_root.mixInfo().m_sampleRate);
|
||||
|
||||
size_t curSlewFrame = m_slewFrames;
|
||||
for (auto& smx : m_sendGains)
|
||||
{
|
||||
curSlewFrame = m_curSlewFrame;
|
||||
AudioSubmix& sm = *reinterpret_cast<AudioSubmix*>(smx.first);
|
||||
auto it = m_scratch32.begin();
|
||||
int32_t* dataOut = sm._getMergeBuf32(frames);
|
||||
|
||||
for (size_t f=0 ; f<frames ; ++f)
|
||||
{
|
||||
if (m_slewFrames && curSlewFrame < m_slewFrames)
|
||||
{
|
||||
double t = curSlewFrame / double(m_slewFrames);
|
||||
double omt = 1.0 - t;
|
||||
|
||||
for (unsigned c=0 ; c<chanCount ; ++c)
|
||||
{
|
||||
*dataOut = Clamp32(*dataOut + *it * (smx.second[1] * t + smx.second[0] * omt));
|
||||
++it;
|
||||
++dataOut;
|
||||
}
|
||||
|
||||
++curSlewFrame;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned c=0 ; c<chanCount ; ++c)
|
||||
{
|
||||
*dataOut = Clamp32(*dataOut + *it * smx.second[1]);
|
||||
++it;
|
||||
++dataOut;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_curSlewFrame += curSlewFrame;
|
||||
}
|
||||
|
||||
return frames;
|
||||
}
|
||||
|
||||
size_t AudioSubmix::_pumpAndMixFlt(size_t frames)
|
||||
{
|
||||
const ChannelMap& chMap = m_root.clientMixInfo().m_channelMap;
|
||||
size_t chanCount = chMap.m_channelCount;
|
||||
|
||||
if (m_redirectFlt)
|
||||
{
|
||||
if (m_cb && m_cb->canApplyEffect())
|
||||
m_cb->applyEffect(m_redirectFlt, frames, chMap, m_root.mixInfo().m_sampleRate);
|
||||
m_redirectFlt += chanCount * frames;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t sampleCount = frames * chanCount;
|
||||
if (m_scratchFlt.size() < sampleCount)
|
||||
m_scratchFlt.resize(sampleCount);
|
||||
if (m_cb && m_cb->canApplyEffect())
|
||||
m_cb->applyEffect(m_scratchFlt.data(), frames, chMap, m_root.mixInfo().m_sampleRate);
|
||||
|
||||
size_t curSlewFrame = m_slewFrames;
|
||||
for (auto& smx : m_sendGains)
|
||||
{
|
||||
curSlewFrame = m_curSlewFrame;
|
||||
AudioSubmix& sm = *reinterpret_cast<AudioSubmix*>(smx.first);
|
||||
auto it = m_scratchFlt.begin();
|
||||
float* dataOut = sm._getMergeBufFlt(frames);
|
||||
|
||||
for (size_t f=0 ; f<frames ; ++f)
|
||||
{
|
||||
if (m_slewFrames && curSlewFrame < m_slewFrames)
|
||||
{
|
||||
double t = curSlewFrame / double(m_slewFrames);
|
||||
double omt = 1.0 - t;
|
||||
|
||||
for (unsigned c=0 ; c<chanCount ; ++c)
|
||||
{
|
||||
*dataOut = *dataOut + *it * (smx.second[1] * t + smx.second[0] * omt);
|
||||
++it;
|
||||
++dataOut;
|
||||
}
|
||||
|
||||
++curSlewFrame;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (unsigned c=0 ; c<chanCount ; ++c)
|
||||
{
|
||||
*dataOut = *dataOut + *it * smx.second[1];
|
||||
++it;
|
||||
++dataOut;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_curSlewFrame += curSlewFrame;
|
||||
}
|
||||
|
||||
return frames;
|
||||
}
|
||||
template size_t AudioSubmix::_pumpAndMix<int16_t>(size_t frames);
|
||||
template size_t AudioSubmix::_pumpAndMix<int32_t>(size_t frames);
|
||||
template size_t AudioSubmix::_pumpAndMix<float>(size_t frames);
|
||||
|
||||
void AudioSubmix::_resetOutputSampleRate()
|
||||
{
|
||||
if (m_cb)
|
||||
m_cb->resetOutputSampleRate(m_root.mixInfo().m_sampleRate);
|
||||
m_cb->resetOutputSampleRate(m_head->mixInfo().m_sampleRate);
|
||||
}
|
||||
|
||||
void AudioSubmix::resetSendLevels()
|
||||
@@ -317,7 +202,7 @@ void AudioSubmix::resetSendLevels()
|
||||
if (m_sendGains.empty())
|
||||
return;
|
||||
m_sendGains.clear();
|
||||
m_root.m_submixesDirty = true;
|
||||
m_head->m_submixesDirty = true;
|
||||
}
|
||||
|
||||
void AudioSubmix::setSendLevel(IAudioSubmix* submix, float level, bool slew)
|
||||
@@ -326,28 +211,19 @@ void AudioSubmix::setSendLevel(IAudioSubmix* submix, float level, bool slew)
|
||||
if (search == m_sendGains.cend())
|
||||
{
|
||||
search = m_sendGains.emplace(submix, std::array<float, 2>{1.f, 1.f}).first;
|
||||
m_root.m_submixesDirty = true;
|
||||
m_head->m_submixesDirty = true;
|
||||
}
|
||||
|
||||
m_slewFrames = slew ? m_root.m_5msFrames : 0;
|
||||
m_slewFrames = slew ? m_head->m_5msFrames : 0;
|
||||
m_curSlewFrame = 0;
|
||||
|
||||
search->second[0] = search->second[1];
|
||||
search->second[1] = level;
|
||||
}
|
||||
|
||||
void AudioSubmix::unbindSubmix()
|
||||
{
|
||||
if (m_bound)
|
||||
{
|
||||
m_root._unbindFrom(m_parentIt);
|
||||
m_bound = false;
|
||||
}
|
||||
}
|
||||
|
||||
const AudioVoiceEngineMixInfo& AudioSubmix::mixInfo() const
|
||||
{
|
||||
return m_root.mixInfo();
|
||||
return m_head->mixInfo();
|
||||
}
|
||||
|
||||
double AudioSubmix::getSampleRate() const
|
||||
|
||||
Reference in New Issue
Block a user