boo/lib/audiodev/AudioSubmix.cpp

182 lines
5.7 KiB
C++
Raw Normal View History

2016-05-07 04:28:32 +00:00
#include "AudioSubmix.hpp"
#include "AudioVoiceEngine.hpp"
#include "AudioVoice.hpp"
#include <string.h>
2016-05-07 22:11:45 +00:00
#include <algorithm>
2016-05-07 04:28:32 +00:00
namespace boo
{
2016-05-07 22:11:45 +00:00
AudioSubmix::AudioSubmix(BaseAudioVoiceEngine& root, IAudioMix& parent, IAudioSubmixCallback* cb)
: m_root(root), m_parent(parent), m_cb(cb)
{
std::fill(std::begin(m_gains), std::end(m_gains), 1.f);
}
2016-05-07 04:28:32 +00:00
AudioSubmix::~AudioSubmix()
{
unbindSubmix();
}
void AudioSubmix::_pumpAndMixVoices(size_t frames, int16_t* dataOut)
{
const AudioVoiceEngineMixInfo& info = mixInfo();
size_t sampleCount = frames * info.m_channelMap.m_channelCount;
2016-05-07 22:11:45 +00:00
if (m_scratch16.size() < sampleCount)
m_scratch16.resize(sampleCount);
2016-05-07 04:28:32 +00:00
/* Clear target buffer */
2016-05-07 22:11:45 +00:00
memset(m_scratch16.data(), 0, sizeof(int16_t) * sampleCount);
2016-05-07 04:28:32 +00:00
/* Pump child voices */
for (AudioVoice* vox : m_activeVoices)
if (vox->m_running)
2016-05-07 22:11:45 +00:00
vox->pumpAndMix(m_parent.mixInfo(), frames, m_scratch16.data());
2016-05-07 04:28:32 +00:00
/* Pump child submixes */
for (AudioSubmix* smx : m_activeSubmixes)
2016-05-07 22:11:45 +00:00
smx->_pumpAndMixVoices(frames, m_scratch16.data());
2016-05-07 04:28:32 +00:00
/* Apply submix effect (if available) */
if (m_cb && m_cb->canApplyEffect())
2016-05-07 22:11:45 +00:00
m_cb->applyEffect(m_scratch16.data(), info.m_channelMap, info.m_sampleRate);
2016-05-07 04:28:32 +00:00
/* Merge into output mix */
2016-05-07 22:11:45 +00:00
auto it = m_scratch16.begin();
2016-05-07 04:28:32 +00:00
for (size_t f=0 ; f<frames ; ++f)
for (size_t c=0 ; c<info.m_channelMap.m_channelCount ; ++c)
2016-05-07 22:11:45 +00:00
{
*dataOut = Clamp16(*dataOut + *it++ * m_gains[c]);
++dataOut;
}
2016-05-07 04:28:32 +00:00
}
void AudioSubmix::_pumpAndMixVoices(size_t frames, int32_t* dataOut)
{
const AudioVoiceEngineMixInfo& info = mixInfo();
size_t sampleCount = frames * info.m_channelMap.m_channelCount;
2016-05-07 22:11:45 +00:00
if (m_scratch32.size() < sampleCount)
m_scratch32.resize(sampleCount);
2016-05-07 04:28:32 +00:00
/* Clear target buffer */
2016-05-07 22:11:45 +00:00
memset(m_scratch32.data(), 0, sizeof(int32_t) * sampleCount);
2016-05-07 04:28:32 +00:00
/* Pump child voices */
for (AudioVoice* vox : m_activeVoices)
if (vox->m_running)
2016-05-07 22:11:45 +00:00
vox->pumpAndMix(m_parent.mixInfo(), frames, m_scratch32.data());
2016-05-07 04:28:32 +00:00
/* Pump child submixes */
for (AudioSubmix* smx : m_activeSubmixes)
2016-05-07 22:11:45 +00:00
smx->_pumpAndMixVoices(frames, m_scratch32.data());
2016-05-07 04:28:32 +00:00
/* Apply submix effect (if available) */
if (m_cb && m_cb->canApplyEffect())
2016-05-07 22:11:45 +00:00
m_cb->applyEffect(m_scratch32.data(), info.m_channelMap, info.m_sampleRate);
2016-05-07 04:28:32 +00:00
/* Merge into output mix */
2016-05-07 22:11:45 +00:00
auto it = m_scratch32.begin();
2016-05-07 04:28:32 +00:00
for (size_t f=0 ; f<frames ; ++f)
for (size_t c=0 ; c<info.m_channelMap.m_channelCount ; ++c)
2016-05-07 22:11:45 +00:00
{
*dataOut = Clamp32(*dataOut + *it++ * m_gains[c]);
++dataOut;
}
2016-05-07 04:28:32 +00:00
}
void AudioSubmix::_pumpAndMixVoices(size_t frames, float* dataOut)
{
const AudioVoiceEngineMixInfo& info = mixInfo();
size_t sampleCount = frames * info.m_channelMap.m_channelCount;
2016-05-07 22:11:45 +00:00
if (m_scratchFlt.size() < sampleCount)
m_scratchFlt.resize(sampleCount);
2016-05-07 04:28:32 +00:00
/* Clear target buffer */
2016-05-07 22:11:45 +00:00
memset(m_scratchFlt.data(), 0, sizeof(float) * sampleCount);
2016-05-07 04:28:32 +00:00
/* Pump child voices */
for (AudioVoice* vox : m_activeVoices)
if (vox->m_running)
2016-05-07 22:11:45 +00:00
vox->pumpAndMix(m_parent.mixInfo(), frames, m_scratchFlt.data());
2016-05-07 04:28:32 +00:00
/* Pump child submixes */
for (AudioSubmix* smx : m_activeSubmixes)
2016-05-07 22:11:45 +00:00
smx->_pumpAndMixVoices(frames, m_scratchFlt.data());
2016-05-07 04:28:32 +00:00
/* Apply submix effect (if available) */
if (m_cb && m_cb->canApplyEffect())
2016-05-07 22:11:45 +00:00
m_cb->applyEffect(m_scratchFlt.data(), info.m_channelMap, info.m_sampleRate);
2016-05-07 04:28:32 +00:00
/* Merge into output mix */
2016-05-07 22:11:45 +00:00
auto it = m_scratchFlt.begin();
2016-05-07 04:28:32 +00:00
for (size_t f=0 ; f<frames ; ++f)
for (size_t c=0 ; c<info.m_channelMap.m_channelCount ; ++c)
2016-05-07 22:11:45 +00:00
{
*dataOut = ClampFlt(*dataOut + *it++ * m_gains[c]);
++dataOut;
}
2016-05-07 04:28:32 +00:00
}
void AudioSubmix::_unbindFrom(std::list<AudioVoice*>::iterator it)
{
m_activeVoices.erase(it);
}
void AudioSubmix::_unbindFrom(std::list<AudioSubmix*>::iterator it)
{
m_activeSubmixes.erase(it);
}
std::unique_ptr<IAudioVoice> AudioSubmix::allocateNewMonoVoice(double sampleRate,
IAudioVoiceCallback* cb,
bool dynamicPitch)
{
std::unique_ptr<IAudioVoice> ret =
2016-05-07 22:11:45 +00:00
std::make_unique<AudioVoiceMono>(m_root, *this, cb, sampleRate, dynamicPitch);
2016-05-07 04:28:32 +00:00
AudioVoiceMono* retMono = static_cast<AudioVoiceMono*>(ret.get());
retMono->bindVoice(m_activeVoices.insert(m_activeVoices.end(), retMono));
return ret;
}
std::unique_ptr<IAudioVoice> AudioSubmix::allocateNewStereoVoice(double sampleRate,
IAudioVoiceCallback* cb,
bool dynamicPitch)
{
std::unique_ptr<IAudioVoice> ret =
2016-05-07 22:11:45 +00:00
std::make_unique<AudioVoiceStereo>(m_root, *this, cb, sampleRate, dynamicPitch);
2016-05-07 04:28:32 +00:00
AudioVoiceStereo* retStereo = static_cast<AudioVoiceStereo*>(ret.get());
retStereo->bindVoice(m_activeVoices.insert(m_activeVoices.end(), retStereo));
return ret;
}
std::unique_ptr<IAudioSubmix> AudioSubmix::allocateNewSubmix(IAudioSubmixCallback* cb)
{
std::unique_ptr<IAudioSubmix> ret =
2016-05-07 22:11:45 +00:00
std::make_unique<AudioSubmix>(m_root, *this, cb);
2016-05-07 04:28:32 +00:00
AudioSubmix* retIntern = static_cast<AudioSubmix*>(ret.get());
retIntern->bindSubmix(m_activeSubmixes.insert(m_activeSubmixes.end(), retIntern));
return ret;
}
2016-05-07 22:11:45 +00:00
void AudioSubmix::setChannelGains(const float gains[8])
{
for (int i=0 ; i<8 ; ++i)
m_gains[i] = gains[i];
}
2016-05-07 04:28:32 +00:00
void AudioSubmix::unbindSubmix()
{
if (m_bound)
{
m_parent._unbindFrom(m_parentIt);
m_bound = false;
}
}
const AudioVoiceEngineMixInfo& AudioSubmix::mixInfo() const
{
return m_parent.mixInfo();
}
}