From db9a5953e645c6c06ab314625dafda17389860f1 Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Sun, 1 Oct 2017 14:59:18 -1000 Subject: [PATCH] 12kHz LPF and bug fixes for LtRt matrixing --- lib/audiodev/AudioSubmix.cpp | 14 +-- lib/audiodev/AudioVoiceEngine.cpp | 9 ++ lib/audiodev/LtRtProcessing.cpp | 173 +++++++++++++++++++++--------- lib/audiodev/LtRtProcessing.hpp | 29 +++-- 4 files changed, 157 insertions(+), 68 deletions(-) diff --git a/lib/audiodev/AudioSubmix.cpp b/lib/audiodev/AudioSubmix.cpp index bf8143a..ae2b6b9 100644 --- a/lib/audiodev/AudioSubmix.cpp +++ b/lib/audiodev/AudioSubmix.cpp @@ -87,7 +87,7 @@ void AudioSubmix::_zeroFill32() void AudioSubmix::_zeroFillFlt() { if (m_scratchFlt.size()) - std::fill(m_scratchFlt.begin(), m_scratchFlt.end(), 0); + std::fill(m_scratchFlt.begin(), m_scratchFlt.end(), 0.f); } int16_t* AudioSubmix::_getMergeBuf16(size_t frames) @@ -134,7 +134,7 @@ size_t AudioSubmix::_pumpAndMix16(size_t frames) if (m_redirect16) { if (m_cb && m_cb->canApplyEffect()) - m_cb->applyEffect(m_redirect16, frames, chMap, m_root.clientMixInfo().m_sampleRate); + m_cb->applyEffect(m_redirect16, frames, chMap, m_root.mixInfo().m_sampleRate); m_redirect16 += chanCount * frames; } else @@ -143,7 +143,7 @@ size_t AudioSubmix::_pumpAndMix16(size_t frames) if (m_scratch16.size() < sampleCount) m_scratch16.resize(sampleCount); if (m_cb && m_cb->canApplyEffect()) - m_cb->applyEffect(m_scratch16.data(), frames, chMap, m_root.clientMixInfo().m_sampleRate); + m_cb->applyEffect(m_scratch16.data(), frames, chMap, m_root.mixInfo().m_sampleRate); size_t curSlewFrame = m_slewFrames; for (auto& smx : m_sendGains) @@ -194,7 +194,7 @@ size_t AudioSubmix::_pumpAndMix32(size_t frames) if (m_redirect32) { if (m_cb && m_cb->canApplyEffect()) - m_cb->applyEffect(m_redirect32, frames, chMap, m_root.clientMixInfo().m_sampleRate); + m_cb->applyEffect(m_redirect32, frames, chMap, m_root.mixInfo().m_sampleRate); m_redirect32 += chanCount * frames; } else @@ -203,7 +203,7 @@ size_t AudioSubmix::_pumpAndMix32(size_t frames) if (m_scratch32.size() < sampleCount) m_scratch32.resize(sampleCount); if (m_cb && m_cb->canApplyEffect()) - m_cb->applyEffect(m_scratch32.data(), frames, chMap, m_root.clientMixInfo().m_sampleRate); + m_cb->applyEffect(m_scratch32.data(), frames, chMap, m_root.mixInfo().m_sampleRate); size_t curSlewFrame = m_slewFrames; for (auto& smx : m_sendGains) @@ -254,7 +254,7 @@ size_t AudioSubmix::_pumpAndMixFlt(size_t frames) if (m_redirectFlt) { if (m_cb && m_cb->canApplyEffect()) - m_cb->applyEffect(m_redirectFlt, frames, chMap, m_root.clientMixInfo().m_sampleRate); + m_cb->applyEffect(m_redirectFlt, frames, chMap, m_root.mixInfo().m_sampleRate); m_redirectFlt += chanCount * frames; } else @@ -263,7 +263,7 @@ size_t AudioSubmix::_pumpAndMixFlt(size_t frames) if (m_scratchFlt.size() < sampleCount) m_scratchFlt.resize(sampleCount); if (m_cb && m_cb->canApplyEffect()) - m_cb->applyEffect(m_scratchFlt.data(), frames, chMap, m_root.clientMixInfo().m_sampleRate); + m_cb->applyEffect(m_scratchFlt.data(), frames, chMap, m_root.mixInfo().m_sampleRate); size_t curSlewFrame = m_slewFrames; for (auto& smx : m_sendGains) diff --git a/lib/audiodev/AudioVoiceEngine.cpp b/lib/audiodev/AudioVoiceEngine.cpp index f5986ab..d6ac450 100644 --- a/lib/audiodev/AudioVoiceEngine.cpp +++ b/lib/audiodev/AudioVoiceEngine.cpp @@ -49,6 +49,9 @@ void BaseAudioVoiceEngine::_pumpAndMixVoices(size_t frames, int16_t* dataOut) m_engineCallback->on5MsInterval(*this, 5.0 / 1000.0); } + if (m_ltRtProcessing) + std::fill(m_ltRtIn16.begin(), m_ltRtIn16.end(), 0); + for (auto it = m_linearizedSubmixes.rbegin() ; it != m_linearizedSubmixes.rend() ; ++it) (*it)->_zeroFill16(); @@ -115,6 +118,9 @@ void BaseAudioVoiceEngine::_pumpAndMixVoices(size_t frames, int32_t* dataOut) m_engineCallback->on5MsInterval(*this, 5.0 / 1000.0); } + if (m_ltRtProcessing) + std::fill(m_ltRtIn32.begin(), m_ltRtIn32.end(), 0); + for (auto it = m_linearizedSubmixes.rbegin() ; it != m_linearizedSubmixes.rend() ; ++it) (*it)->_zeroFill32(); @@ -181,6 +187,9 @@ void BaseAudioVoiceEngine::_pumpAndMixVoices(size_t frames, float* dataOut) m_engineCallback->on5MsInterval(*this, 5.0 / 1000.0); } + if (m_ltRtProcessing) + std::fill(m_ltRtInFlt.begin(), m_ltRtInFlt.end(), 0.f); + for (auto it = m_linearizedSubmixes.rbegin() ; it != m_linearizedSubmixes.rend() ; ++it) (*it)->_zeroFillFlt(); diff --git a/lib/audiodev/LtRtProcessing.cpp b/lib/audiodev/LtRtProcessing.cpp index 9253cee..9267778 100644 --- a/lib/audiodev/LtRtProcessing.cpp +++ b/lib/audiodev/LtRtProcessing.cpp @@ -35,52 +35,100 @@ inline T ClampFull(float in) #define M_PI 3.14159265358979323846 /* pi */ #endif -WindowedHilbert::WindowedHilbert(int windowSamples) -: m_windowSamples(windowSamples), m_halfSamples(windowSamples / 2), - m_inputBuf(new Ipp32f[m_windowSamples * 2 + m_halfSamples]), - m_outputBuf(new Ipp32fc[m_windowSamples * 4]), - m_hammingTable(new Ipp32f[m_halfSamples]) +static constexpr int FirTaps = 27; + +FIRFilter12k::FIRFilter12k(int windowFrames, double sampleRate) { - memset(m_inputBuf.get(), 0, sizeof(Ipp32fc) * m_windowSamples * 2 + m_halfSamples); - memset(m_outputBuf.get(), 0, sizeof(Ipp32fc) * m_windowSamples * 4); - m_output[0] = m_outputBuf.get(); - m_output[1] = m_output[0] + m_windowSamples; - m_output[2] = m_output[1] + m_windowSamples; - m_output[3] = m_output[2] + m_windowSamples; + Ipp64f* taps = ippsMalloc_64f(FirTaps); + Ipp32f* taps32 = ippsMalloc_32f(FirTaps); int sizeSpec, sizeBuf; - ippsHilbertGetSize_32f32fc(m_windowSamples, ippAlgHintNone, &sizeSpec, &sizeBuf); + + ippsFIRGenGetBufferSize(FirTaps, &sizeBuf); + m_firBuffer = ippsMalloc_8u(sizeBuf); + ippsFIRGenLowpass_64f(12000.0 / sampleRate, taps, FirTaps, ippWinBartlett, ippTrue, m_firBuffer); + ippsConvert_64f32f(taps, taps32, FirTaps); + ippsFree(taps); + ippsFree(m_firBuffer); + + m_dlySrc = ippsMalloc_32f(FirTaps); + + ippsFIRSRGetSize(FirTaps, ipp32f, &sizeSpec, &sizeBuf); + m_firSpec = (IppsFIRSpec_32f*)ippsMalloc_8u(sizeSpec); + m_firBuffer = ippsMalloc_8u(sizeBuf); + ippsFIRSRInit_32f(taps32, FirTaps, ippAlgDirect, m_firSpec); + ippsFree(taps32); + + m_inBuf = ippsMalloc_32f(windowFrames); +} + +FIRFilter12k::~FIRFilter12k() +{ + ippsFree(m_firSpec); + ippsFree(m_firBuffer); + ippsFree(m_dlySrc); + ippsFree(m_inBuf); +} + +void FIRFilter12k::Process(Ipp32f* buf, int windowFrames) +{ + ippsZero_32f(m_dlySrc, FirTaps); + ippsMove_32f(buf, m_inBuf, windowFrames); + ippsFIRSR_32f(m_inBuf, buf, windowFrames, m_firSpec, m_dlySrc, nullptr, m_firBuffer); +} + +WindowedHilbert::WindowedHilbert(int windowFrames, double sampleRate) +: m_fir(windowFrames, sampleRate), m_windowFrames(windowFrames), + m_halfFrames(windowFrames / 2), + m_inputBuf(ippsMalloc_32f(m_windowFrames * 2 + m_halfFrames)), + m_outputBuf(ippsMalloc_32fc(m_windowFrames * 4)), + m_hammingTable(ippsMalloc_32f(m_halfFrames)) +{ + ippsZero_32f(m_inputBuf, m_windowFrames * 2 + m_halfFrames); + ippsZero_32fc(m_outputBuf, m_windowFrames * 4); + m_output[0] = m_outputBuf; + m_output[1] = m_output[0] + m_windowFrames; + m_output[2] = m_output[1] + m_windowFrames; + m_output[3] = m_output[2] + m_windowFrames; + int sizeSpec, sizeBuf; + ippsHilbertGetSize_32f32fc(m_windowFrames, ippAlgHintFast, &sizeSpec, &sizeBuf); m_spec = (IppsHilbertSpec*)ippMalloc(sizeSpec); m_buffer = (Ipp8u*)ippMalloc(sizeBuf); - ippsHilbertInit_32f32fc(m_windowSamples, ippAlgHintNone, m_spec, m_buffer); + ippsHilbertInit_32f32fc(m_windowFrames, ippAlgHintFast, m_spec, m_buffer); - for (int i=0 ; i(output[i*2] + tmp * lCoef); + output[i*2+1] = ClampFull(output[i*2+1] + tmp * rCoef); + } + return; +#endif + int i, t; - for (i=0, t=0 ; i(output[i*2] + tmp * lCoef); output[i*2+1] = ClampFull(output[i*2+1] + tmp * rCoef); } - for (; i(output[i*2] + tmp * lCoef); output[i*2+1] = ClampFull(output[i*2+1] + tmp * rCoef); } - for (t=0 ; i int32_t* LtRtProcessing::_getOutBuf() { return m_32Buffer.g template <> float* LtRtProcessing::_getOutBuf() { return m_fltBuffer.get() + m_outputOffset; } LtRtProcessing::LtRtProcessing(int _5msFrames, const AudioVoiceEngineMixInfo& mixInfo) -: m_inMixInfo(mixInfo), m_5msFrames(_5msFrames), m_5msFramesHalf(_5msFrames / 2), - m_outputOffset(m_5msFrames * 5 * 2) +: m_inMixInfo(mixInfo), m_windowFrames(_5msFrames), m_halfFrames(m_windowFrames / 2), + m_outputOffset(m_windowFrames * 5 * 2) #if INTEL_IPP -, m_hilbertSL(_5msFrames), m_hilbertSR(_5msFrames) +, m_hilbertSL(m_windowFrames, mixInfo.m_sampleRate), + m_hilbertSR(m_windowFrames, mixInfo.m_sampleRate) #endif { m_inMixInfo.m_channels = AudioChannelSet::Surround51; @@ -179,7 +238,7 @@ LtRtProcessing::LtRtProcessing(int _5msFrames, const AudioVoiceEngineMixInfo& mi m_inMixInfo.m_channelMap.m_channels[3] = AudioChannel::RearLeft; m_inMixInfo.m_channelMap.m_channels[4] = AudioChannel::RearRight; - int samples = m_5msFrames * (5 * 2 + 2 * 2); + int samples = m_windowFrames * (5 * 2 + 2 * 2); switch (mixInfo.m_sampleFormat) { case SOXR_INT16_I: @@ -205,17 +264,25 @@ void LtRtProcessing::Process(const T* input, T* output, int frameCount) int outFramesRem = frameCount; T* inBuf = _getInBuf(); T* outBuf = _getOutBuf(); - int tail = std::min(m_5msFrames * 2, m_bufferTail + frameCount); + int tail = std::min(m_windowFrames * 2, m_bufferTail + frameCount); int samples = (tail - m_bufferTail) * 5; - memmove(&inBuf[m_bufferTail * 5], input, samples * sizeof(float)); + memmove(&inBuf[m_bufferTail * 5], input, samples * sizeof(T)); + //printf("input %d to %d\n", tail - m_bufferTail, m_bufferTail); input += samples; frameCount -= tail - m_bufferTail; - int bufIdx = m_bufferTail / m_5msFrames; - if (tail / m_5msFrames > bufIdx) + int head = std::min(m_windowFrames * 2, m_bufferHead + outFramesRem); + samples = (head - m_bufferHead) * 2; + memmove(output, outBuf + m_bufferHead * 2, samples * sizeof(T)); + //printf("output %d from %d\n", head - m_bufferHead, m_bufferHead); + output += samples; + outFramesRem -= head - m_bufferHead; + + int bufIdx = m_bufferTail / m_windowFrames; + if (tail / m_windowFrames > bufIdx) { - T* in = &inBuf[bufIdx * m_5msFrames * 5]; - T* out = &outBuf[bufIdx * m_5msFrames * 2]; + T* in = &inBuf[bufIdx * m_windowFrames * 5]; + T* out = &outBuf[bufIdx * m_windowFrames * 2]; #if INTEL_IPP m_hilbertSL.AddWindow(in + 3, 5); m_hilbertSR.AddWindow(in + 4, 5); @@ -225,27 +292,30 @@ void LtRtProcessing::Process(const T* input, T* output, int frameCount) // x(:,2) + sqrt(.5)*x(:,3) - sqrt(6/25)*x(:,4) - sqrt(19/25)*x(:,5) if (bufIdx) { - int delayI = -m_5msFramesHalf; - for (int i=0 ; i(in[delayI * 5] + 0.7071068f * in[delayI * 5 + 2]); out[i * 2 + 1] = ClampFull(in[delayI * 5 + 1] + 0.7071068f * in[delayI * 5 + 2]); + //printf("in %d out %d\n", bufIdx * m_5msFrames + delayI, bufIdx * m_5msFrames + i); } } else { - int delayI = m_5msFrames * 2 - m_5msFramesHalf; + int delayI = m_windowFrames * 2 - m_halfFrames; int i; - for (i=0 ; i(in[delayI * 5] + 0.7071068f * in[delayI * 5 + 2]); out[i * 2 + 1] = ClampFull(in[delayI * 5 + 1] + 0.7071068f * in[delayI * 5 + 2]); + //printf("in %d out %d\n", bufIdx * m_5msFrames + delayI, bufIdx * m_5msFrames + i); } delayI = 0; - for (; i(in[delayI * 5] + 0.7071068f * in[delayI * 5 + 2]); out[i * 2 + 1] = ClampFull(in[delayI * 5 + 1] + 0.7071068f * in[delayI * 5 + 2]); + //printf("in %d out %d\n", bufIdx * m_5msFrames + delayI, bufIdx * m_5msFrames + i); } } #if INTEL_IPP @@ -253,25 +323,22 @@ void LtRtProcessing::Process(const T* input, T* output, int frameCount) m_hilbertSR.Output(out, -0.4898979f, -0.8717798f); #endif } - m_bufferTail = tail; + m_bufferTail = (tail == m_windowFrames * 2) ? 0 : tail; + m_bufferHead = (head == m_windowFrames * 2) ? 0 : head; if (frameCount) { samples = frameCount * 5; - memmove(inBuf, input, samples * sizeof(float)); + memmove(inBuf, input, samples * sizeof(T)); + //printf("input %d to %d\n", frameCount, 0); m_bufferTail = frameCount; } - int head = std::min(m_5msFrames * 2, m_bufferHead + outFramesRem); - samples = (head - m_bufferHead) * 2; - memmove(output, outBuf + m_bufferHead * 2, samples * sizeof(float)); - output += samples; - outFramesRem -= head - m_bufferHead; - m_bufferHead = head; if (outFramesRem) { samples = outFramesRem * 2; - memmove(output, outBuf, samples * sizeof(float)); + memmove(output, outBuf, samples * sizeof(T)); + //printf("output %d from %d\n", outFramesRem, 0); m_bufferHead = outFramesRem; } } diff --git a/lib/audiodev/LtRtProcessing.hpp b/lib/audiodev/LtRtProcessing.hpp index 7f08fa2..17a2caa 100644 --- a/lib/audiodev/LtRtProcessing.hpp +++ b/lib/audiodev/LtRtProcessing.hpp @@ -14,20 +14,33 @@ namespace boo { #if INTEL_IPP + +class FIRFilter12k +{ + IppsFIRSpec_32f* m_firSpec; + Ipp8u* m_firBuffer; + Ipp32f* m_dlySrc; + Ipp32f* m_inBuf; +public: + explicit FIRFilter12k(int windowFrames, double sampleRate); + ~FIRFilter12k(); + void Process(Ipp32f* buf, int windowFrames); +}; + class WindowedHilbert { + FIRFilter12k m_fir; IppsHilbertSpec* m_spec; Ipp8u* m_buffer; - int m_windowSamples, m_halfSamples; + int m_windowFrames, m_halfFrames; int m_bufIdx = 0; - int m_bufferTail = 0; - std::unique_ptr m_inputBuf; - std::unique_ptr m_outputBuf; + Ipp32f* m_inputBuf; + Ipp32fc* m_outputBuf; Ipp32fc* m_output[4]; - std::unique_ptr m_hammingTable; + Ipp32f* m_hammingTable; void _AddWindow(); public: - explicit WindowedHilbert(int windowSamples); + explicit WindowedHilbert(int windowFrames, double sampleRate); ~WindowedHilbert(); void AddWindow(const float* input, int stride); void AddWindow(const int32_t* input, int stride); @@ -40,8 +53,8 @@ public: class LtRtProcessing { AudioVoiceEngineMixInfo m_inMixInfo; - int m_5msFrames; - int m_5msFramesHalf; + int m_windowFrames; + int m_halfFrames; int m_outputOffset; int m_bufferTail = 0; int m_bufferHead = 0;