Fix some submix issues

This commit is contained in:
Jack Andersen 2016-05-07 12:11:45 -10:00
parent 4b969fd475
commit 08a4c5d7a8
9 changed files with 104 additions and 64 deletions

View File

@ -189,7 +189,7 @@ add_library(boo
lib/audiodev/AudioVoice.cpp lib/audiodev/AudioVoice.cpp
lib/audiodev/AudioSubmix.hpp lib/audiodev/AudioSubmix.hpp
lib/audiodev/AudioSubmix.cpp lib/audiodev/AudioSubmix.cpp
lib/audiodev/IAudioHost.hpp lib/audiodev/IAudioMix.hpp
include/boo/inputdev/IHIDListener.hpp include/boo/inputdev/IHIDListener.hpp
include/boo/IGraphicsContext.hpp include/boo/IGraphicsContext.hpp
include/boo/graphicsdev/IGraphicsDataFactory.hpp include/boo/graphicsdev/IGraphicsDataFactory.hpp

View File

@ -28,6 +28,9 @@ struct IAudioSubmix
/** Same as the IAudioVoice allocator, but produces audio recursively within the submix */ /** Same as the IAudioVoice allocator, but produces audio recursively within the submix */
virtual std::unique_ptr<IAudioSubmix> allocateNewSubmix(IAudioSubmixCallback* cb=nullptr)=0; virtual std::unique_ptr<IAudioSubmix> allocateNewSubmix(IAudioSubmixCallback* cb=nullptr)=0;
/** Sets gain factors for each channel once accumulated by the submix */
virtual void setChannelGains(const float gains[8])=0;
}; };
struct IAudioSubmixCallback struct IAudioSubmixCallback

View File

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

View File

@ -2,20 +2,22 @@
#define BOO_AUDIOSUBMIX_HPP #define BOO_AUDIOSUBMIX_HPP
#include "boo/audiodev/IAudioSubmix.hpp" #include "boo/audiodev/IAudioSubmix.hpp"
#include "IAudioHost.hpp" #include "IAudioMix.hpp"
#include <list> #include <list>
#include <vector>
namespace boo namespace boo
{ {
class BaseAudioVoiceEngine; class BaseAudioVoiceEngine;
class AudioVoice; class AudioVoice;
class AudioSubmix : public IAudioSubmix, public IAudioHost class AudioSubmix : public IAudioSubmix, public IAudioMix
{ {
friend class BaseAudioVoiceEngine; friend class BaseAudioVoiceEngine;
/* Mixer-engine relationships */ /* Mixer-engine relationships */
IAudioHost& m_parent; BaseAudioVoiceEngine& m_root;
IAudioMix& m_parent;
std::list<AudioSubmix*>::iterator m_parentIt; std::list<AudioSubmix*>::iterator m_parentIt;
bool m_bound = false; bool m_bound = false;
void bindSubmix(std::list<AudioSubmix*>::iterator pIt) void bindSubmix(std::list<AudioSubmix*>::iterator pIt)
@ -34,6 +36,11 @@ class AudioSubmix : public IAudioSubmix, public IAudioHost
/* Output gains for each channel */ /* Output gains for each channel */
float m_gains[8]; float m_gains[8];
/* Temporary scratch buffers for accumulating submix audio */
std::vector<int16_t> m_scratch16;
std::vector<int32_t> m_scratch32;
std::vector<float> m_scratchFlt;
void _pumpAndMixVoices(size_t frames, int16_t* dataOut); void _pumpAndMixVoices(size_t frames, int16_t* dataOut);
void _pumpAndMixVoices(size_t frames, int32_t* dataOut); void _pumpAndMixVoices(size_t frames, int32_t* dataOut);
void _pumpAndMixVoices(size_t frames, float* dataOut); void _pumpAndMixVoices(size_t frames, float* dataOut);
@ -43,7 +50,7 @@ class AudioSubmix : public IAudioSubmix, public IAudioHost
public: public:
~AudioSubmix(); ~AudioSubmix();
AudioSubmix(IAudioHost& parent, IAudioSubmixCallback* cb); AudioSubmix(BaseAudioVoiceEngine& root, IAudioMix& parent, IAudioSubmixCallback* cb);
std::unique_ptr<IAudioVoice> allocateNewMonoVoice(double sampleRate, std::unique_ptr<IAudioVoice> allocateNewMonoVoice(double sampleRate,
IAudioVoiceCallback* cb, IAudioVoiceCallback* cb,
@ -53,7 +60,9 @@ public:
IAudioVoiceCallback* cb, IAudioVoiceCallback* cb,
bool dynamicPitch=false); bool dynamicPitch=false);
virtual std::unique_ptr<IAudioSubmix> allocateNewSubmix(IAudioSubmixCallback* cb=nullptr); std::unique_ptr<IAudioSubmix> allocateNewSubmix(IAudioSubmixCallback* cb=nullptr);
void setChannelGains(const float gains[8]);
void unbindSubmix(); void unbindSubmix();

View File

@ -6,13 +6,9 @@ namespace boo
{ {
static logvisor::Module Log("boo::AudioVoice"); static logvisor::Module Log("boo::AudioVoice");
static std::vector<int16_t> scratchIn; AudioVoice::AudioVoice(BaseAudioVoiceEngine& root, IAudioMix& parent,
static std::vector<int16_t> scratch16; IAudioVoiceCallback* cb, bool dynamicRate)
static std::vector<int32_t> scratch32; : m_root(root), m_parent(parent), m_cb(cb), m_dynamicRate(dynamicRate) {}
static std::vector<float> scratchFlt;
AudioVoice::AudioVoice(IAudioHost& parent, IAudioVoiceCallback* cb, bool dynamicRate)
: m_parent(parent), m_cb(cb), m_dynamicRate(dynamicRate) {}
AudioVoice::~AudioVoice() AudioVoice::~AudioVoice()
{ {
@ -52,9 +48,9 @@ void AudioVoice::unbindVoice()
} }
} }
AudioVoiceMono::AudioVoiceMono(IAudioHost& parent, IAudioVoiceCallback* cb, AudioVoiceMono::AudioVoiceMono(BaseAudioVoiceEngine& root, IAudioMix& parent, IAudioVoiceCallback* cb,
double sampleRate, bool dynamicRate) double sampleRate, bool dynamicRate)
: AudioVoice(parent, cb, dynamicRate) : AudioVoice(root, parent, cb, dynamicRate)
{ {
soxr_io_spec_t ioSpec = soxr_io_spec(SOXR_INT16_I, parent.mixInfo().m_sampleFormat); soxr_io_spec_t ioSpec = soxr_io_spec(SOXR_INT16_I, parent.mixInfo().m_sampleFormat);
soxr_quality_spec_t qSpec = soxr_quality_spec(SOXR_20_BITQ, dynamicRate ? SOXR_VR : 0); soxr_quality_spec_t qSpec = soxr_quality_spec(SOXR_20_BITQ, dynamicRate ? SOXR_VR : 0);
@ -74,6 +70,7 @@ AudioVoiceMono::AudioVoiceMono(IAudioHost& parent, IAudioVoiceCallback* cb,
size_t AudioVoiceMono::SRCCallback(AudioVoiceMono* ctx, int16_t** data, size_t frames) size_t AudioVoiceMono::SRCCallback(AudioVoiceMono* ctx, int16_t** data, size_t frames)
{ {
std::vector<int16_t>& scratchIn = ctx->m_root.m_scratchIn;
if (scratchIn.size() < frames) if (scratchIn.size() < frames)
scratchIn.resize(frames); scratchIn.resize(frames);
*data = scratchIn.data(); *data = scratchIn.data();
@ -83,6 +80,7 @@ size_t AudioVoiceMono::SRCCallback(AudioVoiceMono* ctx, int16_t** data, size_t f
size_t AudioVoiceMono::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t AudioVoiceMono::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo,
size_t frames, int16_t* buf) size_t frames, int16_t* buf)
{ {
std::vector<int16_t>& scratch16 = m_root.m_scratch16;
if (scratch16.size() < frames) if (scratch16.size() < frames)
scratch16.resize(frames); scratch16.resize(frames);
@ -95,6 +93,7 @@ size_t AudioVoiceMono::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo,
size_t AudioVoiceMono::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t AudioVoiceMono::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo,
size_t frames, int32_t* buf) size_t frames, int32_t* buf)
{ {
std::vector<int32_t>& scratch32 = m_root.m_scratch32;
if (scratch32.size() < frames) if (scratch32.size() < frames)
scratch32.resize(frames); scratch32.resize(frames);
@ -107,6 +106,7 @@ size_t AudioVoiceMono::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo,
size_t AudioVoiceMono::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t AudioVoiceMono::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo,
size_t frames, float* buf) size_t frames, float* buf)
{ {
std::vector<float>& scratchFlt = m_root.m_scratchFlt;
if (scratchFlt.size() < frames) if (scratchFlt.size() < frames)
scratchFlt.resize(frames); scratchFlt.resize(frames);
@ -142,9 +142,9 @@ void AudioVoiceMono::setStereoMatrixCoefficients(const float coefs[8][2])
m_matrix.setMatrixCoefficients(newCoefs); m_matrix.setMatrixCoefficients(newCoefs);
} }
AudioVoiceStereo::AudioVoiceStereo(IAudioHost& parent, IAudioVoiceCallback* cb, AudioVoiceStereo::AudioVoiceStereo(BaseAudioVoiceEngine& root, IAudioMix& parent, IAudioVoiceCallback* cb,
double sampleRate, bool dynamicRate) double sampleRate, bool dynamicRate)
: AudioVoice(parent, cb, dynamicRate) : AudioVoice(root, parent, cb, dynamicRate)
{ {
soxr_io_spec_t ioSpec = soxr_io_spec(SOXR_INT16_I, parent.mixInfo().m_sampleFormat); soxr_io_spec_t ioSpec = soxr_io_spec(SOXR_INT16_I, parent.mixInfo().m_sampleFormat);
soxr_quality_spec_t qSpec = soxr_quality_spec(SOXR_20_BITQ, dynamicRate ? SOXR_VR : 0); soxr_quality_spec_t qSpec = soxr_quality_spec(SOXR_20_BITQ, dynamicRate ? SOXR_VR : 0);
@ -164,6 +164,7 @@ AudioVoiceStereo::AudioVoiceStereo(IAudioHost& parent, IAudioVoiceCallback* cb,
size_t AudioVoiceStereo::SRCCallback(AudioVoiceStereo* ctx, int16_t** data, size_t frames) size_t AudioVoiceStereo::SRCCallback(AudioVoiceStereo* ctx, int16_t** data, size_t frames)
{ {
std::vector<int16_t>& scratchIn = ctx->m_root.m_scratchIn;
size_t samples = frames * 2; size_t samples = frames * 2;
if (scratchIn.size() < samples) if (scratchIn.size() < samples)
scratchIn.resize(samples); scratchIn.resize(samples);
@ -174,6 +175,7 @@ size_t AudioVoiceStereo::SRCCallback(AudioVoiceStereo* ctx, int16_t** data, size
size_t AudioVoiceStereo::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t AudioVoiceStereo::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo,
size_t frames, int16_t* buf) size_t frames, int16_t* buf)
{ {
std::vector<int16_t>& scratch16 = m_root.m_scratch16;
size_t samples = frames * 2; size_t samples = frames * 2;
if (scratch16.size() < samples) if (scratch16.size() < samples)
scratch16.resize(samples); scratch16.resize(samples);
@ -187,6 +189,7 @@ size_t AudioVoiceStereo::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo,
size_t AudioVoiceStereo::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t AudioVoiceStereo::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo,
size_t frames, int32_t* buf) size_t frames, int32_t* buf)
{ {
std::vector<int32_t>& scratch32 = m_root.m_scratch32;
size_t samples = frames * 2; size_t samples = frames * 2;
if (scratch32.size() < samples) if (scratch32.size() < samples)
scratch32.resize(samples); scratch32.resize(samples);
@ -200,6 +203,7 @@ size_t AudioVoiceStereo::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo,
size_t AudioVoiceStereo::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t AudioVoiceStereo::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo,
size_t frames, float* buf) size_t frames, float* buf)
{ {
std::vector<float>& scratchFlt = m_root.m_scratchFlt;
size_t samples = frames * 2; size_t samples = frames * 2;
if (scratchFlt.size() < samples) if (scratchFlt.size() < samples)
scratchFlt.resize(samples); scratchFlt.resize(samples);

View File

@ -10,7 +10,7 @@ namespace boo
{ {
class BaseAudioVoiceEngine; class BaseAudioVoiceEngine;
struct AudioVoiceEngineMixInfo; struct AudioVoiceEngineMixInfo;
class IAudioHost; class IAudioMix;
class AudioVoice : public IAudioVoice class AudioVoice : public IAudioVoice
{ {
@ -19,7 +19,8 @@ class AudioVoice : public IAudioVoice
protected: protected:
/* Mixer-engine relationships */ /* Mixer-engine relationships */
IAudioHost& m_parent; BaseAudioVoiceEngine& m_root;
IAudioMix& m_parent;
std::list<AudioVoice*>::iterator m_parentIt; std::list<AudioVoice*>::iterator m_parentIt;
bool m_bound = false; bool m_bound = false;
void bindVoice(std::list<AudioVoice*>::iterator pIt) void bindVoice(std::list<AudioVoice*>::iterator pIt)
@ -41,7 +42,7 @@ protected:
virtual size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, int16_t* buf)=0; virtual size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, int16_t* buf)=0;
virtual size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, int32_t* buf)=0; virtual size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, int32_t* buf)=0;
virtual size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, float* buf)=0; virtual size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, float* buf)=0;
AudioVoice(IAudioHost& parent, IAudioVoiceCallback* cb, bool dynamicRate); AudioVoice(BaseAudioVoiceEngine& root, IAudioMix& parent, IAudioVoiceCallback* cb, bool dynamicRate);
public: public:
~AudioVoice(); ~AudioVoice();
@ -64,7 +65,7 @@ class AudioVoiceMono : public AudioVoice
size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, float* buf); size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, float* buf);
public: public:
AudioVoiceMono(IAudioHost& parent, IAudioVoiceCallback* cb, AudioVoiceMono(BaseAudioVoiceEngine& root, IAudioMix& parent, IAudioVoiceCallback* cb,
double sampleRate, bool dynamicRate); double sampleRate, bool dynamicRate);
void setDefaultMatrixCoefficients(); void setDefaultMatrixCoefficients();
void setMonoMatrixCoefficients(const float coefs[8]); void setMonoMatrixCoefficients(const float coefs[8]);
@ -83,7 +84,7 @@ class AudioVoiceStereo : public AudioVoice
size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, float* buf); size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, float* buf);
public: public:
AudioVoiceStereo(IAudioHost& parent, IAudioVoiceCallback* cb, AudioVoiceStereo(BaseAudioVoiceEngine& root, IAudioMix& parent, IAudioVoiceCallback* cb,
double sampleRate, bool dynamicRate); double sampleRate, bool dynamicRate);
void setDefaultMatrixCoefficients(); void setDefaultMatrixCoefficients();
void setMonoMatrixCoefficients(const float coefs[8]); void setMonoMatrixCoefficients(const float coefs[8]);

View File

@ -50,7 +50,7 @@ BaseAudioVoiceEngine::allocateNewMonoVoice(double sampleRate,
bool dynamicPitch) bool dynamicPitch)
{ {
std::unique_ptr<IAudioVoice> ret = std::unique_ptr<IAudioVoice> ret =
std::make_unique<AudioVoiceMono>(*this, cb, sampleRate, dynamicPitch); std::make_unique<AudioVoiceMono>(*this, *this, cb, sampleRate, dynamicPitch);
AudioVoiceMono* retMono = static_cast<AudioVoiceMono*>(ret.get()); AudioVoiceMono* retMono = static_cast<AudioVoiceMono*>(ret.get());
retMono->bindVoice(m_activeVoices.insert(m_activeVoices.end(), retMono)); retMono->bindVoice(m_activeVoices.insert(m_activeVoices.end(), retMono));
return ret; return ret;
@ -62,7 +62,7 @@ BaseAudioVoiceEngine::allocateNewStereoVoice(double sampleRate,
bool dynamicPitch) bool dynamicPitch)
{ {
std::unique_ptr<IAudioVoice> ret = std::unique_ptr<IAudioVoice> ret =
std::make_unique<AudioVoiceStereo>(*this, cb, sampleRate, dynamicPitch); std::make_unique<AudioVoiceStereo>(*this, *this, cb, sampleRate, dynamicPitch);
AudioVoiceStereo* retStereo = static_cast<AudioVoiceStereo*>(ret.get()); AudioVoiceStereo* retStereo = static_cast<AudioVoiceStereo*>(ret.get());
retStereo->bindVoice(m_activeVoices.insert(m_activeVoices.end(), retStereo)); retStereo->bindVoice(m_activeVoices.insert(m_activeVoices.end(), retStereo));
return ret; return ret;
@ -72,7 +72,7 @@ std::unique_ptr<IAudioSubmix>
BaseAudioVoiceEngine::allocateNewSubmix(IAudioSubmixCallback* cb) BaseAudioVoiceEngine::allocateNewSubmix(IAudioSubmixCallback* cb)
{ {
std::unique_ptr<IAudioSubmix> ret = std::unique_ptr<IAudioSubmix> ret =
std::make_unique<AudioSubmix>(*this, cb); std::make_unique<AudioSubmix>(*this, *this, cb);
AudioSubmix* retIntern = static_cast<AudioSubmix*>(ret.get()); AudioSubmix* retIntern = static_cast<AudioSubmix*>(ret.get());
retIntern->bindSubmix(m_activeSubmixes.insert(m_activeSubmixes.end(), retIntern)); retIntern->bindSubmix(m_activeSubmixes.insert(m_activeSubmixes.end(), retIntern));
return ret; return ret;

View File

@ -4,7 +4,7 @@
#include "boo/audiodev/IAudioVoiceEngine.hpp" #include "boo/audiodev/IAudioVoiceEngine.hpp"
#include "AudioVoice.hpp" #include "AudioVoice.hpp"
#include "AudioSubmix.hpp" #include "AudioSubmix.hpp"
#include "IAudioHost.hpp" #include "IAudioMix.hpp"
namespace boo namespace boo
{ {
@ -21,15 +21,23 @@ struct AudioVoiceEngineMixInfo
}; };
/** Base class for managing mixing and sample-rate-conversion amongst active voices */ /** Base class for managing mixing and sample-rate-conversion amongst active voices */
class BaseAudioVoiceEngine : public IAudioVoiceEngine, public IAudioHost class BaseAudioVoiceEngine : public IAudioVoiceEngine, public IAudioMix
{ {
protected: protected:
friend class AudioVoice; friend class AudioVoice;
friend class AudioSubmix; friend class AudioSubmix;
friend class AudioVoiceMono;
friend class AudioVoiceStereo;
AudioVoiceEngineMixInfo m_mixInfo; AudioVoiceEngineMixInfo m_mixInfo;
std::list<AudioVoice*> m_activeVoices; std::list<AudioVoice*> m_activeVoices;
std::list<AudioSubmix*> m_activeSubmixes; std::list<AudioSubmix*> m_activeSubmixes;
/* Shared scratch buffers for accumulating audio data for resampling */
std::vector<int16_t> m_scratchIn;
std::vector<int16_t> m_scratch16;
std::vector<int32_t> m_scratch32;
std::vector<float> m_scratchFlt;
void _pumpAndMixVoices(size_t frames, int16_t* dataOut); void _pumpAndMixVoices(size_t frames, int16_t* dataOut);
void _pumpAndMixVoices(size_t frames, int32_t* dataOut); void _pumpAndMixVoices(size_t frames, int32_t* dataOut);
void _pumpAndMixVoices(size_t frames, float* dataOut); void _pumpAndMixVoices(size_t frames, float* dataOut);

View File

@ -1,5 +1,5 @@
#ifndef BOO_IAUDIOHOST_HPP #ifndef BOO_IAUDIOMIX_HPP
#define BOO_IAUDIOHOST_HPP #define BOO_IAUDIOMIX_HPP
#include <list> #include <list>
@ -10,7 +10,7 @@ class AudioVoice;
class AudioSubmix; class AudioSubmix;
/** Entity that mixes audio from several child sources (engine root or submix) */ /** Entity that mixes audio from several child sources (engine root or submix) */
class IAudioHost class IAudioMix
{ {
friend class AudioVoice; friend class AudioVoice;
friend class AudioSubmix; friend class AudioSubmix;
@ -22,4 +22,4 @@ public:
} }
#endif // BOO_IAUDIOHOST_HPP #endif // BOO_IAUDIOMIX_HPP