diff --git a/include/boo/audiodev/IAudioVoice.hpp b/include/boo/audiodev/IAudioVoice.hpp index f0e5b5e..d169212 100644 --- a/include/boo/audiodev/IAudioVoice.hpp +++ b/include/boo/audiodev/IAudioVoice.hpp @@ -68,6 +68,12 @@ struct IAudioVoice /** Set channel-gains for stereo audio source (AudioChannel enum for array index) */ virtual void setStereoMatrixCoefficients(const float coefs[8][2], bool slew)=0; + /** Set submix-channel-gains for mono audio source (AudioChannel enum for array index) */ + virtual void setMonoSubmixMatrixCoefficients(const float coefs[8], bool slew)=0; + + /** Set submix-channel-gains for stereo audio source (AudioChannel enum for array index) */ + virtual void setStereoSubmixMatrixCoefficients(const float coefs[8][2], bool slew)=0; + /** Called by client to dynamically adjust the pitch of voices with dynamic pitch enabled */ virtual void setPitchRatio(double ratio, bool slew)=0; diff --git a/lib/audiodev/AudioSubmix.cpp b/lib/audiodev/AudioSubmix.cpp index f409818..122c2cd 100644 --- a/lib/audiodev/AudioSubmix.cpp +++ b/lib/audiodev/AudioSubmix.cpp @@ -22,7 +22,7 @@ AudioSubmix::~AudioSubmix() unbindSubmix(); } -void AudioSubmix::_pumpAndMixVoices(size_t frames, int16_t* dataOut) +void AudioSubmix::_pumpAndMixVoices(size_t frames, int16_t* dataOut, int16_t* mainOut) { const AudioVoiceEngineMixInfo& info = mixInfo(); size_t sampleCount = frames * info.m_channelMap.m_channelCount; @@ -35,11 +35,11 @@ void AudioSubmix::_pumpAndMixVoices(size_t frames, int16_t* dataOut) /* Pump child voices */ for (AudioVoice* vox : m_activeVoices) if (vox->m_running) - vox->pumpAndMix(m_parent.mixInfo(), frames, m_scratch16.data()); + vox->pumpAndMix(m_parent.mixInfo(), frames, mainOut, m_scratch16.data()); /* Pump child submixes */ for (AudioSubmix* smx : m_activeSubmixes) - smx->_pumpAndMixVoices(frames, m_scratch16.data()); + smx->_pumpAndMixVoices(frames, m_scratch16.data(), mainOut); /* Apply submix effect (if available) */ if (m_cb && m_cb->canApplyEffect()) @@ -55,7 +55,7 @@ void AudioSubmix::_pumpAndMixVoices(size_t frames, int16_t* dataOut) } } -void AudioSubmix::_pumpAndMixVoices(size_t frames, int32_t* dataOut) +void AudioSubmix::_pumpAndMixVoices(size_t frames, int32_t* dataOut, int32_t* mainOut) { const AudioVoiceEngineMixInfo& info = mixInfo(); size_t sampleCount = frames * info.m_channelMap.m_channelCount; @@ -68,11 +68,11 @@ void AudioSubmix::_pumpAndMixVoices(size_t frames, int32_t* dataOut) /* Pump child voices */ for (AudioVoice* vox : m_activeVoices) if (vox->m_running) - vox->pumpAndMix(m_parent.mixInfo(), frames, m_scratch32.data()); + vox->pumpAndMix(m_parent.mixInfo(), frames, mainOut, m_scratch32.data()); /* Pump child submixes */ for (AudioSubmix* smx : m_activeSubmixes) - smx->_pumpAndMixVoices(frames, m_scratch32.data()); + smx->_pumpAndMixVoices(frames, m_scratch32.data(), mainOut); /* Apply submix effect (if available) */ if (m_cb && m_cb->canApplyEffect()) @@ -88,7 +88,7 @@ void AudioSubmix::_pumpAndMixVoices(size_t frames, int32_t* dataOut) } } -void AudioSubmix::_pumpAndMixVoices(size_t frames, float* dataOut) +void AudioSubmix::_pumpAndMixVoices(size_t frames, float* dataOut, float* mainOut) { const AudioVoiceEngineMixInfo& info = mixInfo(); size_t sampleCount = frames * info.m_channelMap.m_channelCount; @@ -101,11 +101,11 @@ void AudioSubmix::_pumpAndMixVoices(size_t frames, float* dataOut) /* Pump child voices */ for (AudioVoice* vox : m_activeVoices) if (vox->m_running) - vox->pumpAndMix(m_parent.mixInfo(), frames, m_scratchFlt.data()); + vox->pumpAndMix(m_parent.mixInfo(), frames, mainOut, m_scratchFlt.data()); /* Pump child submixes */ for (AudioSubmix* smx : m_activeSubmixes) - smx->_pumpAndMixVoices(frames, m_scratchFlt.data()); + smx->_pumpAndMixVoices(frames, m_scratchFlt.data(), mainOut); /* Apply submix effect (if available) */ if (m_cb && m_cb->canApplyEffect()) diff --git a/lib/audiodev/AudioSubmix.hpp b/lib/audiodev/AudioSubmix.hpp index 6892d22..a19c982 100644 --- a/lib/audiodev/AudioSubmix.hpp +++ b/lib/audiodev/AudioSubmix.hpp @@ -41,9 +41,9 @@ class AudioSubmix : public IAudioSubmix, public IAudioMix std::vector m_scratch32; std::vector m_scratchFlt; - void _pumpAndMixVoices(size_t frames, int16_t* dataOut); - void _pumpAndMixVoices(size_t frames, int32_t* dataOut); - void _pumpAndMixVoices(size_t frames, float* dataOut); + void _pumpAndMixVoices(size_t frames, int16_t* dataOut, int16_t* mainOut); + void _pumpAndMixVoices(size_t frames, int32_t* dataOut, int32_t* mainOut); + void _pumpAndMixVoices(size_t frames, float* dataOut, float* mainOut); void _unbindFrom(std::list::iterator it); void _unbindFrom(std::list::iterator it); diff --git a/lib/audiodev/AudioVoice.cpp b/lib/audiodev/AudioVoice.cpp index 0cde7f3..1b875fd 100644 --- a/lib/audiodev/AudioVoice.cpp +++ b/lib/audiodev/AudioVoice.cpp @@ -114,7 +114,7 @@ size_t AudioVoiceMono::SRCCallback(AudioVoiceMono* ctx, int16_t** data, size_t f } size_t AudioVoiceMono::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, - size_t frames, int16_t* buf) + size_t frames, int16_t* buf, int16_t* rbuf) { std::vector& scratch16 = m_root.m_scratch16; if (scratch16.size() < frames) @@ -124,13 +124,17 @@ size_t AudioVoiceMono::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, _midUpdate(); if (oDone) + { m_matrix.mixMonoSampleData(mixInfo, scratch16.data(), buf, oDone); + if (rbuf) + m_subMatrix.mixMonoSampleData(mixInfo, scratch16.data(), rbuf, oDone); + } return oDone; } size_t AudioVoiceMono::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, - size_t frames, int32_t* buf) + size_t frames, int32_t* buf, int32_t* rbuf) { std::vector& scratch32 = m_root.m_scratch32; if (scratch32.size() < frames) @@ -140,13 +144,17 @@ size_t AudioVoiceMono::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, _midUpdate(); if (oDone) + { m_matrix.mixMonoSampleData(mixInfo, scratch32.data(), buf, oDone); + if (rbuf) + m_subMatrix.mixMonoSampleData(mixInfo, scratch32.data(), rbuf, oDone); + } return oDone; } size_t AudioVoiceMono::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, - size_t frames, float* buf) + size_t frames, float* buf, float* rbuf) { std::vector& scratchFlt = m_root.m_scratchFlt; if (scratchFlt.size() < frames) @@ -156,7 +164,11 @@ size_t AudioVoiceMono::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, _midUpdate(); if (oDone) + { m_matrix.mixMonoSampleData(mixInfo, scratchFlt.data(), buf, oDone); + if (rbuf) + m_subMatrix.mixMonoSampleData(mixInfo, scratchFlt.data(), rbuf, oDone); + } return oDone; } @@ -164,6 +176,8 @@ size_t AudioVoiceMono::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, void AudioVoiceMono::setDefaultMatrixCoefficients() { m_matrix.setDefaultMatrixCoefficients(m_parent.mixInfo().m_channels); + float zero[8] = {}; + m_subMatrix.setMatrixCoefficients(zero); } void AudioVoiceMono::setMonoMatrixCoefficients(const float coefs[8], bool slew) @@ -187,6 +201,27 @@ void AudioVoiceMono::setStereoMatrixCoefficients(const float coefs[8][2], bool s m_matrix.setMatrixCoefficients(newCoefs, slew ? m_root.m_5msFrames : 0); } +void AudioVoiceMono::setMonoSubmixMatrixCoefficients(const float coefs[8], bool slew) +{ + m_subMatrix.setMatrixCoefficients(coefs, slew ? m_root.m_5msFrames : 0); +} + +void AudioVoiceMono::setStereoSubmixMatrixCoefficients(const float coefs[8][2], bool slew) +{ + float newCoefs[8] = + { + coefs[0][0], + coefs[1][0], + coefs[2][0], + coefs[3][0], + coefs[4][0], + coefs[5][0], + coefs[6][0], + coefs[7][0] + }; + m_subMatrix.setMatrixCoefficients(newCoefs, slew ? m_root.m_5msFrames : 0); +} + AudioVoiceStereo::AudioVoiceStereo(BaseAudioVoiceEngine& root, IAudioMix& parent, IAudioVoiceCallback* cb, double sampleRate, bool dynamicRate) : AudioVoice(root, parent, cb, dynamicRate) @@ -231,7 +266,7 @@ size_t AudioVoiceStereo::SRCCallback(AudioVoiceStereo* ctx, int16_t** data, size } size_t AudioVoiceStereo::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, - size_t frames, int16_t* buf) + size_t frames, int16_t* buf, int16_t* rbuf) { std::vector& scratch16 = m_root.m_scratch16; size_t samples = frames * 2; @@ -242,13 +277,17 @@ size_t AudioVoiceStereo::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, _midUpdate(); if (oDone) + { m_matrix.mixStereoSampleData(mixInfo, scratch16.data(), buf, oDone); + if (rbuf) + m_subMatrix.mixStereoSampleData(mixInfo, scratch16.data(), rbuf, oDone); + } return oDone; } size_t AudioVoiceStereo::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, - size_t frames, int32_t* buf) + size_t frames, int32_t* buf, int32_t* rbuf) { std::vector& scratch32 = m_root.m_scratch32; size_t samples = frames * 2; @@ -259,13 +298,17 @@ size_t AudioVoiceStereo::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, _midUpdate(); if (oDone) + { m_matrix.mixStereoSampleData(mixInfo, scratch32.data(), buf, oDone); + if (rbuf) + m_subMatrix.mixStereoSampleData(mixInfo, scratch32.data(), rbuf, oDone); + } return oDone; } size_t AudioVoiceStereo::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, - size_t frames, float* buf) + size_t frames, float* buf, float* rbuf) { std::vector& scratchFlt = m_root.m_scratchFlt; size_t samples = frames * 2; @@ -276,7 +319,11 @@ size_t AudioVoiceStereo::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, _midUpdate(); if (oDone) + { m_matrix.mixStereoSampleData(mixInfo, scratchFlt.data(), buf, oDone); + if (rbuf) + m_subMatrix.mixStereoSampleData(mixInfo, scratchFlt.data(), rbuf, oDone); + } return oDone; } @@ -284,6 +331,8 @@ size_t AudioVoiceStereo::pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, void AudioVoiceStereo::setDefaultMatrixCoefficients() { m_matrix.setDefaultMatrixCoefficients(m_parent.mixInfo().m_channels); + float zero[8][2] = {{}}; + m_subMatrix.setMatrixCoefficients(zero); } void AudioVoiceStereo::setMonoMatrixCoefficients(const float coefs[8], bool slew) @@ -307,4 +356,25 @@ void AudioVoiceStereo::setStereoMatrixCoefficients(const float coefs[8][2], bool m_matrix.setMatrixCoefficients(coefs, slew ? m_root.m_5msFrames : 0); } +void AudioVoiceStereo::setMonoSubmixMatrixCoefficients(const float coefs[8], bool slew) +{ + float newCoefs[8][2] = + { + {coefs[0], coefs[0]}, + {coefs[1], coefs[1]}, + {coefs[2], coefs[2]}, + {coefs[3], coefs[3]}, + {coefs[4], coefs[4]}, + {coefs[5], coefs[5]}, + {coefs[6], coefs[6]}, + {coefs[7], coefs[7]} + }; + m_subMatrix.setMatrixCoefficients(newCoefs, slew ? m_root.m_5msFrames : 0); +} + +void AudioVoiceStereo::setStereoSubmixMatrixCoefficients(const float coefs[8][2], bool slew) +{ + m_subMatrix.setMatrixCoefficients(coefs, slew ? m_root.m_5msFrames : 0); +} + } diff --git a/lib/audiodev/AudioVoice.hpp b/lib/audiodev/AudioVoice.hpp index c9491b9..fb41c0c 100644 --- a/lib/audiodev/AudioVoice.hpp +++ b/lib/audiodev/AudioVoice.hpp @@ -55,9 +55,9 @@ protected: /* Mid-pump update */ void _midUpdate(); - 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; + virtual size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, int16_t* buf, int16_t* rbuf)=0; + virtual size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, int32_t* buf, int32_t* rbuf)=0; + virtual size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, float* buf, float* rbuf)=0; AudioVoice(BaseAudioVoiceEngine& root, IAudioMix& parent, IAudioVoiceCallback* cb, bool dynamicRate); public: @@ -72,14 +72,15 @@ public: class AudioVoiceMono : public AudioVoice { AudioMatrixMono m_matrix; + AudioMatrixMono m_subMatrix; void _resetSampleRate(double sampleRate); static size_t SRCCallback(AudioVoiceMono* ctx, int16_t** data, size_t requestedLen); - size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, int16_t* buf); - size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, int32_t* buf); - size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, float* buf); + size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, int16_t* buf, int16_t* rbuf); + size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, int32_t* buf, int32_t* rbuf); + size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, float* buf, float* rbuf); public: AudioVoiceMono(BaseAudioVoiceEngine& root, IAudioMix& parent, IAudioVoiceCallback* cb, @@ -87,19 +88,22 @@ public: void setDefaultMatrixCoefficients(); void setMonoMatrixCoefficients(const float coefs[8], bool slew); void setStereoMatrixCoefficients(const float coefs[8][2], bool slew); + void setMonoSubmixMatrixCoefficients(const float coefs[8], bool slew); + void setStereoSubmixMatrixCoefficients(const float coefs[8][2], bool slew); }; class AudioVoiceStereo : public AudioVoice { AudioMatrixStereo m_matrix; + AudioMatrixStereo m_subMatrix; void _resetSampleRate(double sampleRate); static size_t SRCCallback(AudioVoiceStereo* ctx, int16_t** data, size_t requestedLen); - size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, int16_t* buf); - size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, int32_t* buf); - size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, float* buf); + size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, int16_t* buf, int16_t* rbuf); + size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, int32_t* buf, int32_t* rbuf); + size_t pumpAndMix(const AudioVoiceEngineMixInfo& mixInfo, size_t frames, float* buf, float* rbuf); public: AudioVoiceStereo(BaseAudioVoiceEngine& root, IAudioMix& parent, IAudioVoiceCallback* cb, @@ -107,6 +111,8 @@ public: void setDefaultMatrixCoefficients(); void setMonoMatrixCoefficients(const float coefs[8], bool slew); void setStereoMatrixCoefficients(const float coefs[8][2], bool slew); + void setMonoSubmixMatrixCoefficients(const float coefs[8], bool slew); + void setStereoSubmixMatrixCoefficients(const float coefs[8][2], bool slew); }; } diff --git a/lib/audiodev/AudioVoiceEngine.cpp b/lib/audiodev/AudioVoiceEngine.cpp index 5b1d6ca..d7c2daa 100644 --- a/lib/audiodev/AudioVoiceEngine.cpp +++ b/lib/audiodev/AudioVoiceEngine.cpp @@ -35,9 +35,9 @@ void BaseAudioVoiceEngine::_pumpAndMixVoices(size_t frames, int16_t* dataOut) for (AudioVoice* vox : m_activeVoices) if (vox->m_running) - vox->pumpAndMix(m_mixInfo, thisFrames, dataOut); + vox->pumpAndMix(m_mixInfo, thisFrames, dataOut, nullptr); for (AudioSubmix* smx : m_activeSubmixes) - smx->_pumpAndMixVoices(thisFrames, dataOut); + smx->_pumpAndMixVoices(thisFrames, dataOut, dataOut); remFrames -= thisFrames; dataOut += thisFrames * m_mixInfo.m_channelMap.m_channelCount; } @@ -66,9 +66,9 @@ void BaseAudioVoiceEngine::_pumpAndMixVoices(size_t frames, int32_t* dataOut) for (AudioVoice* vox : m_activeVoices) if (vox->m_running) - vox->pumpAndMix(m_mixInfo, thisFrames, dataOut); + vox->pumpAndMix(m_mixInfo, thisFrames, dataOut, nullptr); for (AudioSubmix* smx : m_activeSubmixes) - smx->_pumpAndMixVoices(thisFrames, dataOut); + smx->_pumpAndMixVoices(thisFrames, dataOut, dataOut); remFrames -= thisFrames; dataOut += thisFrames * m_mixInfo.m_channelMap.m_channelCount; } @@ -97,9 +97,9 @@ void BaseAudioVoiceEngine::_pumpAndMixVoices(size_t frames, float* dataOut) for (AudioVoice* vox : m_activeVoices) if (vox->m_running) - vox->pumpAndMix(m_mixInfo, thisFrames, dataOut); + vox->pumpAndMix(m_mixInfo, thisFrames, dataOut, nullptr); for (AudioSubmix* smx : m_activeSubmixes) - smx->_pumpAndMixVoices(thisFrames, dataOut); + smx->_pumpAndMixVoices(thisFrames, dataOut, dataOut); remFrames -= thisFrames; dataOut += thisFrames * m_mixInfo.m_channelMap.m_channelCount; }