mirror of https://github.com/AxioDL/boo.git
Implement AudioSubmix
This commit is contained in:
parent
4ecea8ac3f
commit
4b969fd475
|
@ -187,10 +187,14 @@ add_library(boo
|
|||
lib/audiodev/AudioVoiceEngine.cpp
|
||||
lib/audiodev/AudioVoice.hpp
|
||||
lib/audiodev/AudioVoice.cpp
|
||||
lib/audiodev/AudioSubmix.hpp
|
||||
lib/audiodev/AudioSubmix.cpp
|
||||
lib/audiodev/IAudioHost.hpp
|
||||
include/boo/inputdev/IHIDListener.hpp
|
||||
include/boo/IGraphicsContext.hpp
|
||||
include/boo/graphicsdev/IGraphicsDataFactory.hpp
|
||||
include/boo/graphicsdev/IGraphicsCommandQueue.hpp
|
||||
include/boo/audiodev/IAudioSubmix.hpp
|
||||
include/boo/audiodev/IAudioVoice.hpp
|
||||
include/boo/audiodev/IAudioVoiceEngine.hpp
|
||||
include/boo/IWindow.hpp
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
#ifndef BOO_IAUDIOSUBMIX_HPP
|
||||
#define BOO_IAUDIOSUBMIX_HPP
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <memory>
|
||||
|
||||
namespace boo
|
||||
{
|
||||
class IAudioVoice;
|
||||
class IAudioVoiceCallback;
|
||||
struct ChannelMap;
|
||||
struct IAudioSubmixCallback;
|
||||
|
||||
struct IAudioSubmix
|
||||
{
|
||||
virtual ~IAudioSubmix() = default;
|
||||
|
||||
/** Same as the IAudioVoice allocator, but produces audio within the submix */
|
||||
virtual std::unique_ptr<IAudioVoice> allocateNewMonoVoice(double sampleRate,
|
||||
IAudioVoiceCallback* cb,
|
||||
bool dynamicPitch=false)=0;
|
||||
|
||||
/** Same as allocateNewMonoVoice, but source audio is stereo-interleaved */
|
||||
virtual std::unique_ptr<IAudioVoice> allocateNewStereoVoice(double sampleRate,
|
||||
IAudioVoiceCallback* cb,
|
||||
bool dynamicPitch=false)=0;
|
||||
|
||||
/** Same as the IAudioVoice allocator, but produces audio recursively within the submix */
|
||||
virtual std::unique_ptr<IAudioSubmix> allocateNewSubmix(IAudioSubmixCallback* cb=nullptr)=0;
|
||||
};
|
||||
|
||||
struct IAudioSubmixCallback
|
||||
{
|
||||
/** Client-provided claim to implement / is ready to call applyEffect() */
|
||||
virtual bool canApplyEffect() const=0;
|
||||
|
||||
/** Client-provided effect solution for interleaved, master sample-rate audio */
|
||||
virtual void applyEffect(int16_t* audio, const ChannelMap& chanMap, double sampleRate) const=0;
|
||||
virtual void applyEffect(int32_t* audio, const ChannelMap& chanMap, double sampleRate) const=0;
|
||||
virtual void applyEffect(float* audio, const ChannelMap& chanMap, double sampleRate) const=0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // BOO_IAUDIOVOICE_HPP
|
|
@ -2,6 +2,7 @@
|
|||
#define BOO_IAUDIOVOICEENGINE_HPP
|
||||
|
||||
#include "IAudioVoice.hpp"
|
||||
#include "IAudioSubmix.hpp"
|
||||
#include <memory>
|
||||
|
||||
namespace boo
|
||||
|
@ -18,7 +19,8 @@ struct IAudioVoiceEngine
|
|||
* ChannelLayout automatically reduces to maximum-supported layout by HW.
|
||||
*
|
||||
* Client must be prepared to supply audio frames via the callback when this is called;
|
||||
* the backing audio-buffers are primed with initial data for low-latency playback start */
|
||||
* the backing audio-buffers are primed with initial data for low-latency playback start
|
||||
*/
|
||||
virtual std::unique_ptr<IAudioVoice> allocateNewMonoVoice(double sampleRate,
|
||||
IAudioVoiceCallback* cb,
|
||||
bool dynamicPitch=false)=0;
|
||||
|
@ -28,6 +30,9 @@ struct IAudioVoiceEngine
|
|||
IAudioVoiceCallback* cb,
|
||||
bool dynamicPitch=false)=0;
|
||||
|
||||
/** Client calls this to allocate a Submix for gathering audio together for effects processing */
|
||||
virtual std::unique_ptr<IAudioSubmix> allocateNewSubmix(IAudioSubmixCallback* cb=nullptr)=0;
|
||||
|
||||
/** Client may use this to determine current speaker-setup */
|
||||
virtual AudioChannelSet getAvailableSet()=0;
|
||||
|
||||
|
|
|
@ -1,38 +1,10 @@
|
|||
#include "AudioMatrix.hpp"
|
||||
#include "AudioVoiceEngine.hpp"
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
namespace boo
|
||||
{
|
||||
|
||||
static inline int16_t Clamp16(float in)
|
||||
{
|
||||
if (in < SHRT_MIN)
|
||||
return SHRT_MIN;
|
||||
else if (in > SHRT_MAX)
|
||||
return SHRT_MAX;
|
||||
return in;
|
||||
}
|
||||
|
||||
static inline int32_t Clamp32(float in)
|
||||
{
|
||||
if (in < INT_MIN)
|
||||
return INT_MIN;
|
||||
else if (in > INT_MAX)
|
||||
return INT_MAX;
|
||||
return in;
|
||||
}
|
||||
|
||||
static inline float ClampFlt(float in)
|
||||
{
|
||||
if (in < -1.f)
|
||||
return -1.f;
|
||||
else if (in > 1.f)
|
||||
return 1.f;
|
||||
return in;
|
||||
}
|
||||
|
||||
void AudioMatrixMono::setDefaultMatrixCoefficients(AudioChannelSet acSet)
|
||||
{
|
||||
memset(m_coefs, 0, sizeof(m_coefs));
|
||||
|
|
|
@ -4,11 +4,39 @@
|
|||
#include "boo/audiodev/IAudioVoice.hpp"
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
|
||||
namespace boo
|
||||
{
|
||||
struct AudioVoiceEngineMixInfo;
|
||||
|
||||
static inline int16_t Clamp16(float in)
|
||||
{
|
||||
if (in < SHRT_MIN)
|
||||
return SHRT_MIN;
|
||||
else if (in > SHRT_MAX)
|
||||
return SHRT_MAX;
|
||||
return in;
|
||||
}
|
||||
|
||||
static inline int32_t Clamp32(float in)
|
||||
{
|
||||
if (in < INT_MIN)
|
||||
return INT_MIN;
|
||||
else if (in > INT_MAX)
|
||||
return INT_MAX;
|
||||
return in;
|
||||
}
|
||||
|
||||
static inline float ClampFlt(float in)
|
||||
{
|
||||
if (in < -1.f)
|
||||
return -1.f;
|
||||
else if (in > 1.f)
|
||||
return 1.f;
|
||||
return in;
|
||||
}
|
||||
|
||||
class AudioMatrixMono
|
||||
{
|
||||
float m_coefs[8];
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
#include "AudioSubmix.hpp"
|
||||
#include "AudioVoiceEngine.hpp"
|
||||
#include "AudioVoice.hpp"
|
||||
#include <string.h>
|
||||
|
||||
namespace boo
|
||||
{
|
||||
|
||||
static std::vector<int16_t> scratch16;
|
||||
static std::vector<int32_t> scratch32;
|
||||
static std::vector<float> scratchFlt;
|
||||
|
||||
AudioSubmix::AudioSubmix(IAudioHost& parent, IAudioSubmixCallback* cb)
|
||||
: m_parent(parent), m_cb(cb) {}
|
||||
|
||||
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;
|
||||
if (scratch16.size() < sampleCount)
|
||||
scratch16.resize(sampleCount);
|
||||
|
||||
/* Clear target buffer */
|
||||
memset(scratch16.data(), 0, sizeof(int16_t) * sampleCount);
|
||||
|
||||
/* Pump child voices */
|
||||
for (AudioVoice* vox : m_activeVoices)
|
||||
if (vox->m_running)
|
||||
vox->pumpAndMix(m_parent.mixInfo(), frames, scratch16.data());
|
||||
|
||||
/* Pump child submixes */
|
||||
for (AudioSubmix* smx : m_activeSubmixes)
|
||||
smx->_pumpAndMixVoices(frames, scratch16.data());
|
||||
|
||||
/* Apply submix effect (if available) */
|
||||
if (m_cb && m_cb->canApplyEffect())
|
||||
m_cb->applyEffect(scratch16.data(), info.m_channelMap, info.m_sampleRate);
|
||||
|
||||
/* Merge into output mix */
|
||||
auto it = scratch16.begin();
|
||||
for (size_t f=0 ; f<frames ; ++f)
|
||||
for (size_t c=0 ; c<info.m_channelMap.m_channelCount ; ++c)
|
||||
*dataOut++ = Clamp16(*it++ * m_gains[c]);
|
||||
}
|
||||
|
||||
void AudioSubmix::_pumpAndMixVoices(size_t frames, int32_t* dataOut)
|
||||
{
|
||||
const AudioVoiceEngineMixInfo& info = mixInfo();
|
||||
size_t sampleCount = frames * info.m_channelMap.m_channelCount;
|
||||
if (scratch32.size() < sampleCount)
|
||||
scratch32.resize(sampleCount);
|
||||
|
||||
/* Clear target buffer */
|
||||
memset(scratch32.data(), 0, sizeof(int32_t) * sampleCount);
|
||||
|
||||
/* Pump child voices */
|
||||
for (AudioVoice* vox : m_activeVoices)
|
||||
if (vox->m_running)
|
||||
vox->pumpAndMix(m_parent.mixInfo(), frames, scratch32.data());
|
||||
|
||||
/* Pump child submixes */
|
||||
for (AudioSubmix* smx : m_activeSubmixes)
|
||||
smx->_pumpAndMixVoices(frames, scratch32.data());
|
||||
|
||||
/* Apply submix effect (if available) */
|
||||
if (m_cb && m_cb->canApplyEffect())
|
||||
m_cb->applyEffect(scratch32.data(), info.m_channelMap, info.m_sampleRate);
|
||||
|
||||
/* Merge into output mix */
|
||||
auto it = scratch32.begin();
|
||||
for (size_t f=0 ; f<frames ; ++f)
|
||||
for (size_t c=0 ; c<info.m_channelMap.m_channelCount ; ++c)
|
||||
*dataOut++ = Clamp32(*it++ * m_gains[c]);
|
||||
}
|
||||
|
||||
void AudioSubmix::_pumpAndMixVoices(size_t frames, float* dataOut)
|
||||
{
|
||||
const AudioVoiceEngineMixInfo& info = mixInfo();
|
||||
size_t sampleCount = frames * info.m_channelMap.m_channelCount;
|
||||
if (scratchFlt.size() < sampleCount)
|
||||
scratchFlt.resize(sampleCount);
|
||||
|
||||
/* Clear target buffer */
|
||||
memset(scratchFlt.data(), 0, sizeof(float) * sampleCount);
|
||||
|
||||
/* Pump child voices */
|
||||
for (AudioVoice* vox : m_activeVoices)
|
||||
if (vox->m_running)
|
||||
vox->pumpAndMix(m_parent.mixInfo(), frames, scratchFlt.data());
|
||||
|
||||
/* Pump child submixes */
|
||||
for (AudioSubmix* smx : m_activeSubmixes)
|
||||
smx->_pumpAndMixVoices(frames, scratchFlt.data());
|
||||
|
||||
/* Apply submix effect (if available) */
|
||||
if (m_cb && m_cb->canApplyEffect())
|
||||
m_cb->applyEffect(scratchFlt.data(), info.m_channelMap, info.m_sampleRate);
|
||||
|
||||
/* Merge into output mix */
|
||||
auto it = scratchFlt.begin();
|
||||
for (size_t f=0 ; f<frames ; ++f)
|
||||
for (size_t c=0 ; c<info.m_channelMap.m_channelCount ; ++c)
|
||||
*dataOut++ = ClampFlt(*it++ * m_gains[c]);
|
||||
}
|
||||
|
||||
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 =
|
||||
std::make_unique<AudioVoiceMono>(*this, cb, sampleRate, dynamicPitch);
|
||||
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 =
|
||||
std::make_unique<AudioVoiceStereo>(*this, cb, sampleRate, dynamicPitch);
|
||||
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 =
|
||||
std::make_unique<AudioSubmix>(*this, cb);
|
||||
AudioSubmix* retIntern = static_cast<AudioSubmix*>(ret.get());
|
||||
retIntern->bindSubmix(m_activeSubmixes.insert(m_activeSubmixes.end(), retIntern));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AudioSubmix::unbindSubmix()
|
||||
{
|
||||
if (m_bound)
|
||||
{
|
||||
m_parent._unbindFrom(m_parentIt);
|
||||
m_bound = false;
|
||||
}
|
||||
}
|
||||
|
||||
const AudioVoiceEngineMixInfo& AudioSubmix::mixInfo() const
|
||||
{
|
||||
return m_parent.mixInfo();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
#ifndef BOO_AUDIOSUBMIX_HPP
|
||||
#define BOO_AUDIOSUBMIX_HPP
|
||||
|
||||
#include "boo/audiodev/IAudioSubmix.hpp"
|
||||
#include "IAudioHost.hpp"
|
||||
#include <list>
|
||||
|
||||
namespace boo
|
||||
{
|
||||
class BaseAudioVoiceEngine;
|
||||
class AudioVoice;
|
||||
|
||||
class AudioSubmix : public IAudioSubmix, public IAudioHost
|
||||
{
|
||||
friend class BaseAudioVoiceEngine;
|
||||
|
||||
/* Mixer-engine relationships */
|
||||
IAudioHost& m_parent;
|
||||
std::list<AudioSubmix*>::iterator m_parentIt;
|
||||
bool m_bound = false;
|
||||
void bindSubmix(std::list<AudioSubmix*>::iterator pIt)
|
||||
{
|
||||
m_bound = true;
|
||||
m_parentIt = pIt;
|
||||
}
|
||||
|
||||
/* Callback (effect source, optional) */
|
||||
IAudioSubmixCallback* m_cb;
|
||||
|
||||
/* Audio sources */
|
||||
std::list<AudioVoice*> m_activeVoices;
|
||||
std::list<AudioSubmix*> m_activeSubmixes;
|
||||
|
||||
/* Output gains for each channel */
|
||||
float m_gains[8];
|
||||
|
||||
void _pumpAndMixVoices(size_t frames, int16_t* dataOut);
|
||||
void _pumpAndMixVoices(size_t frames, int32_t* dataOut);
|
||||
void _pumpAndMixVoices(size_t frames, float* dataOut);
|
||||
|
||||
void _unbindFrom(std::list<AudioVoice*>::iterator it);
|
||||
void _unbindFrom(std::list<AudioSubmix*>::iterator it);
|
||||
|
||||
public:
|
||||
~AudioSubmix();
|
||||
AudioSubmix(IAudioHost& parent, IAudioSubmixCallback* cb);
|
||||
|
||||
std::unique_ptr<IAudioVoice> allocateNewMonoVoice(double sampleRate,
|
||||
IAudioVoiceCallback* cb,
|
||||
bool dynamicPitch=false);
|
||||
|
||||
std::unique_ptr<IAudioVoice> allocateNewStereoVoice(double sampleRate,
|
||||
IAudioVoiceCallback* cb,
|
||||
bool dynamicPitch=false);
|
||||
|
||||
virtual std::unique_ptr<IAudioSubmix> allocateNewSubmix(IAudioSubmixCallback* cb=nullptr);
|
||||
|
||||
void unbindSubmix();
|
||||
|
||||
const AudioVoiceEngineMixInfo& mixInfo() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // BOO_AUDIOSUBMIX_HPP
|
|
@ -11,7 +11,7 @@ static std::vector<int16_t> scratch16;
|
|||
static std::vector<int32_t> scratch32;
|
||||
static std::vector<float> scratchFlt;
|
||||
|
||||
AudioVoice::AudioVoice(BaseAudioVoiceEngine& parent, IAudioVoiceCallback* cb, bool dynamicRate)
|
||||
AudioVoice::AudioVoice(IAudioHost& parent, IAudioVoiceCallback* cb, bool dynamicRate)
|
||||
: m_parent(parent), m_cb(cb), m_dynamicRate(dynamicRate) {}
|
||||
|
||||
AudioVoice::~AudioVoice()
|
||||
|
@ -47,12 +47,12 @@ void AudioVoice::unbindVoice()
|
|||
{
|
||||
if (m_bound)
|
||||
{
|
||||
m_parent.m_activeVoices.erase(m_parentIt);
|
||||
m_parent._unbindFrom(m_parentIt);
|
||||
m_bound = false;
|
||||
}
|
||||
}
|
||||
|
||||
AudioVoiceMono::AudioVoiceMono(BaseAudioVoiceEngine& parent, IAudioVoiceCallback* cb,
|
||||
AudioVoiceMono::AudioVoiceMono(IAudioHost& parent, IAudioVoiceCallback* cb,
|
||||
double sampleRate, bool dynamicRate)
|
||||
: AudioVoice(parent, cb, dynamicRate)
|
||||
{
|
||||
|
@ -142,7 +142,7 @@ void AudioVoiceMono::setStereoMatrixCoefficients(const float coefs[8][2])
|
|||
m_matrix.setMatrixCoefficients(newCoefs);
|
||||
}
|
||||
|
||||
AudioVoiceStereo::AudioVoiceStereo(BaseAudioVoiceEngine& parent, IAudioVoiceCallback* cb,
|
||||
AudioVoiceStereo::AudioVoiceStereo(IAudioHost& parent, IAudioVoiceCallback* cb,
|
||||
double sampleRate, bool dynamicRate)
|
||||
: AudioVoice(parent, cb, dynamicRate)
|
||||
{
|
||||
|
|
|
@ -10,14 +10,16 @@ namespace boo
|
|||
{
|
||||
class BaseAudioVoiceEngine;
|
||||
struct AudioVoiceEngineMixInfo;
|
||||
class IAudioHost;
|
||||
|
||||
class AudioVoice : public IAudioVoice
|
||||
{
|
||||
friend class BaseAudioVoiceEngine;
|
||||
friend class AudioSubmix;
|
||||
|
||||
protected:
|
||||
/* Mixer-engine relationships */
|
||||
BaseAudioVoiceEngine& m_parent;
|
||||
IAudioHost& m_parent;
|
||||
std::list<AudioVoice*>::iterator m_parentIt;
|
||||
bool m_bound = false;
|
||||
void bindVoice(std::list<AudioVoice*>::iterator pIt)
|
||||
|
@ -39,7 +41,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, int32_t* buf)=0;
|
||||
virtual size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, float* buf)=0;
|
||||
AudioVoice(BaseAudioVoiceEngine& parent, IAudioVoiceCallback* cb, bool dynamicRate);
|
||||
AudioVoice(IAudioHost& parent, IAudioVoiceCallback* cb, bool dynamicRate);
|
||||
|
||||
public:
|
||||
~AudioVoice();
|
||||
|
@ -62,7 +64,7 @@ class AudioVoiceMono : public AudioVoice
|
|||
size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, float* buf);
|
||||
|
||||
public:
|
||||
AudioVoiceMono(BaseAudioVoiceEngine& parent, IAudioVoiceCallback* cb,
|
||||
AudioVoiceMono(IAudioHost& parent, IAudioVoiceCallback* cb,
|
||||
double sampleRate, bool dynamicRate);
|
||||
void setDefaultMatrixCoefficients();
|
||||
void setMonoMatrixCoefficients(const float coefs[8]);
|
||||
|
@ -81,7 +83,7 @@ class AudioVoiceStereo : public AudioVoice
|
|||
size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, float* buf);
|
||||
|
||||
public:
|
||||
AudioVoiceStereo(BaseAudioVoiceEngine& parent, IAudioVoiceCallback* cb,
|
||||
AudioVoiceStereo(IAudioHost& parent, IAudioVoiceCallback* cb,
|
||||
double sampleRate, bool dynamicRate);
|
||||
void setDefaultMatrixCoefficients();
|
||||
void setMonoMatrixCoefficients(const float coefs[8]);
|
||||
|
|
|
@ -10,6 +10,8 @@ void BaseAudioVoiceEngine::_pumpAndMixVoices(size_t frames, int16_t* dataOut)
|
|||
for (AudioVoice* vox : m_activeVoices)
|
||||
if (vox->m_running)
|
||||
vox->pumpAndMix(m_mixInfo, frames, dataOut);
|
||||
for (AudioSubmix* smx : m_activeSubmixes)
|
||||
smx->_pumpAndMixVoices(frames, dataOut);
|
||||
}
|
||||
|
||||
void BaseAudioVoiceEngine::_pumpAndMixVoices(size_t frames, int32_t* dataOut)
|
||||
|
@ -18,6 +20,8 @@ void BaseAudioVoiceEngine::_pumpAndMixVoices(size_t frames, int32_t* dataOut)
|
|||
for (AudioVoice* vox : m_activeVoices)
|
||||
if (vox->m_running)
|
||||
vox->pumpAndMix(m_mixInfo, frames, dataOut);
|
||||
for (AudioSubmix* smx : m_activeSubmixes)
|
||||
smx->_pumpAndMixVoices(frames, dataOut);
|
||||
}
|
||||
|
||||
void BaseAudioVoiceEngine::_pumpAndMixVoices(size_t frames, float* dataOut)
|
||||
|
@ -26,6 +30,18 @@ void BaseAudioVoiceEngine::_pumpAndMixVoices(size_t frames, float* dataOut)
|
|||
for (AudioVoice* vox : m_activeVoices)
|
||||
if (vox->m_running)
|
||||
vox->pumpAndMix(m_mixInfo, frames, dataOut);
|
||||
for (AudioSubmix* smx : m_activeSubmixes)
|
||||
smx->_pumpAndMixVoices(frames, dataOut);
|
||||
}
|
||||
|
||||
void BaseAudioVoiceEngine::_unbindFrom(std::list<AudioVoice*>::iterator it)
|
||||
{
|
||||
m_activeVoices.erase(it);
|
||||
}
|
||||
|
||||
void BaseAudioVoiceEngine::_unbindFrom(std::list<AudioSubmix*>::iterator it)
|
||||
{
|
||||
m_activeSubmixes.erase(it);
|
||||
}
|
||||
|
||||
std::unique_ptr<IAudioVoice>
|
||||
|
@ -52,4 +68,19 @@ BaseAudioVoiceEngine::allocateNewStereoVoice(double sampleRate,
|
|||
return ret;
|
||||
}
|
||||
|
||||
std::unique_ptr<IAudioSubmix>
|
||||
BaseAudioVoiceEngine::allocateNewSubmix(IAudioSubmixCallback* cb)
|
||||
{
|
||||
std::unique_ptr<IAudioSubmix> ret =
|
||||
std::make_unique<AudioSubmix>(*this, cb);
|
||||
AudioSubmix* retIntern = static_cast<AudioSubmix*>(ret.get());
|
||||
retIntern->bindSubmix(m_activeSubmixes.insert(m_activeSubmixes.end(), retIntern));
|
||||
return ret;
|
||||
}
|
||||
|
||||
const AudioVoiceEngineMixInfo& BaseAudioVoiceEngine::mixInfo() const
|
||||
{
|
||||
return m_mixInfo;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include "boo/audiodev/IAudioVoiceEngine.hpp"
|
||||
#include "AudioVoice.hpp"
|
||||
#include "AudioSubmix.hpp"
|
||||
#include "IAudioHost.hpp"
|
||||
|
||||
namespace boo
|
||||
{
|
||||
|
@ -19,17 +21,22 @@ struct AudioVoiceEngineMixInfo
|
|||
};
|
||||
|
||||
/** Base class for managing mixing and sample-rate-conversion amongst active voices */
|
||||
class BaseAudioVoiceEngine : public IAudioVoiceEngine
|
||||
class BaseAudioVoiceEngine : public IAudioVoiceEngine, public IAudioHost
|
||||
{
|
||||
protected:
|
||||
friend class AudioVoice;
|
||||
friend class AudioSubmix;
|
||||
AudioVoiceEngineMixInfo m_mixInfo;
|
||||
std::list<AudioVoice*> m_activeVoices;
|
||||
std::list<AudioSubmix*> m_activeSubmixes;
|
||||
|
||||
void _pumpAndMixVoices(size_t frames, int16_t* dataOut);
|
||||
void _pumpAndMixVoices(size_t frames, int32_t* dataOut);
|
||||
void _pumpAndMixVoices(size_t frames, float* dataOut);
|
||||
|
||||
void _unbindFrom(std::list<AudioVoice*>::iterator it);
|
||||
void _unbindFrom(std::list<AudioSubmix*>::iterator it);
|
||||
|
||||
public:
|
||||
std::unique_ptr<IAudioVoice> allocateNewMonoVoice(double sampleRate,
|
||||
IAudioVoiceCallback* cb,
|
||||
|
@ -39,7 +46,9 @@ public:
|
|||
IAudioVoiceCallback* cb,
|
||||
bool dynamicPitch=false);
|
||||
|
||||
const AudioVoiceEngineMixInfo& mixInfo() const {return m_mixInfo;}
|
||||
std::unique_ptr<IAudioSubmix> allocateNewSubmix(IAudioSubmixCallback* cb);
|
||||
|
||||
const AudioVoiceEngineMixInfo& mixInfo() const;
|
||||
AudioChannelSet getAvailableSet() {return m_mixInfo.m_channels;}
|
||||
void pumpAndMixVoices() {}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
#ifndef BOO_IAUDIOHOST_HPP
|
||||
#define BOO_IAUDIOHOST_HPP
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace boo
|
||||
{
|
||||
class AudioVoiceEngineMixInfo;
|
||||
class AudioVoice;
|
||||
class AudioSubmix;
|
||||
|
||||
/** Entity that mixes audio from several child sources (engine root or submix) */
|
||||
class IAudioHost
|
||||
{
|
||||
friend class AudioVoice;
|
||||
friend class AudioSubmix;
|
||||
virtual void _unbindFrom(std::list<AudioVoice*>::iterator it)=0;
|
||||
virtual void _unbindFrom(std::list<AudioSubmix*>::iterator it)=0;
|
||||
public:
|
||||
virtual const AudioVoiceEngineMixInfo& mixInfo() const=0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // BOO_IAUDIOHOST_HPP
|
Loading…
Reference in New Issue