mirror of
https://github.com/AxioDL/boo.git
synced 2025-07-03 11:45:55 +00:00
Fix some submix issues
This commit is contained in:
parent
4b969fd475
commit
08a4c5d7a8
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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]);
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
Loading…
x
Reference in New Issue
Block a user