/* | |
* Copyright (C) 2011 NXP Software | |
* Copyright (C) 2011 The Android Open Source Project | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
#define LOG_NDEBUG 1 | |
#define LOG_TAG "VideoEditorBGAudioProcessing" | |
#include <utils/Log.h> | |
#include "VideoEditorBGAudioProcessing.h" | |
namespace android { | |
VideoEditorBGAudioProcessing::VideoEditorBGAudioProcessing() { | |
LOGV("VideoEditorBGAudioProcessing:: Construct VideoEditorBGAudioProcessing "); | |
mAudVolArrIndex = 0; | |
mDoDucking = 0; | |
mDucking_enable = 0; | |
mDucking_lowVolume = 0; | |
mDucking_threshold = 0; | |
mDuckingFactor = 0; | |
mBTVolLevel = 0; | |
mPTVolLevel = 0; | |
mIsSSRCneeded = 0; | |
mChannelConversion = 0; | |
mBTFormat = MONO_16_BIT; | |
mInSampleRate = 8000; | |
mOutSampleRate = 16000; | |
mPTChannelCount = 2; | |
mBTChannelCount = 1; | |
} | |
M4OSA_Int32 VideoEditorBGAudioProcessing::veProcessAudioMixNDuck( | |
void *pPTBuffer, void *pBTBuffer, void *pOutBuffer) { | |
M4AM_Buffer16* pPrimaryTrack = (M4AM_Buffer16*)pPTBuffer; | |
M4AM_Buffer16* pBackgroundTrack = (M4AM_Buffer16*)pBTBuffer; | |
M4AM_Buffer16* pMixedOutBuffer = (M4AM_Buffer16*)pOutBuffer; | |
LOGV("VideoEditorBGAudioProcessing::lvProcessAudioMixNDuck \ | |
pPTBuffer 0x%x pBTBuffer 0x%x pOutBuffer 0x%x", pPTBuffer, | |
pBTBuffer, pOutBuffer); | |
M4OSA_ERR result = M4NO_ERROR; | |
M4OSA_Int16 *pBTMdata1; | |
M4OSA_Int16 *pPTMdata2; | |
M4OSA_UInt32 uiPCMsize; | |
// Ducking variable | |
M4OSA_UInt16 loopIndex = 0; | |
M4OSA_Int16 *pPCM16Sample = M4OSA_NULL; | |
M4OSA_Int32 peakDbValue = 0; | |
M4OSA_Int32 previousDbValue = 0; | |
M4OSA_UInt32 i; | |
// Output size if same as PT size | |
pMixedOutBuffer->m_bufferSize = pPrimaryTrack->m_bufferSize; | |
// Before mixing, we need to have only PT as out buffer | |
memcpy((void *)pMixedOutBuffer->m_dataAddress, | |
(void *)pPrimaryTrack->m_dataAddress, pMixedOutBuffer->m_bufferSize); | |
// Initially contains the input primary track | |
pPTMdata2 = (M4OSA_Int16*)pMixedOutBuffer->m_dataAddress; | |
// Contains BG track processed data(like channel conversion etc.. | |
pBTMdata1 = (M4OSA_Int16*) pBackgroundTrack->m_dataAddress; | |
// Since we need to give sample count and not buffer size | |
uiPCMsize = pMixedOutBuffer->m_bufferSize/2 ; | |
if ((mDucking_enable) && (mPTVolLevel != 0.0)) { | |
// LOGI("VideoEditorBGAudioProcessing:: In Ducking analysis "); | |
loopIndex = 0; | |
peakDbValue = 0; | |
previousDbValue = peakDbValue; | |
pPCM16Sample = (M4OSA_Int16*)pPrimaryTrack->m_dataAddress; | |
while (loopIndex < pPrimaryTrack->m_bufferSize/sizeof(M4OSA_Int16)) { | |
if (pPCM16Sample[loopIndex] >= 0) { | |
peakDbValue = previousDbValue > pPCM16Sample[loopIndex] ? | |
previousDbValue : pPCM16Sample[loopIndex]; | |
previousDbValue = peakDbValue; | |
} else { | |
peakDbValue = previousDbValue > -pPCM16Sample[loopIndex] ? | |
previousDbValue: -pPCM16Sample[loopIndex]; | |
previousDbValue = peakDbValue; | |
} | |
loopIndex++; | |
} | |
mAudioVolumeArray[mAudVolArrIndex] = getDecibelSound(peakDbValue); | |
LOGV("VideoEditorBGAudioProcessing:: getDecibelSound %d", | |
mAudioVolumeArray[mAudVolArrIndex]); | |
// WINDOW_SIZE is 10 by default | |
// Check for threshold is done after 10 cycles | |
if (mAudVolArrIndex >= WINDOW_SIZE - 1) { | |
mDoDucking = isThresholdBreached(mAudioVolumeArray, | |
mAudVolArrIndex,mDucking_threshold ); | |
mAudVolArrIndex = 0; | |
} else { | |
mAudVolArrIndex++; | |
} | |
// | |
// Below logic controls the mixing weightage | |
// for Background and Primary Tracks | |
// for the duration of window under analysis, | |
// to give fade-out for Background and fade-in for primary | |
// Current fading factor is distributed in equal range over | |
// the defined window size. | |
// For a window size = 25 | |
// (500 ms (window under analysis) / 20 ms (sample duration)) | |
// | |
if (mDoDucking) { | |
if (mDuckingFactor > mDucking_lowVolume) { | |
// FADE OUT BG Track | |
// Increment ducking factor in total steps in factor | |
// of low volume steps to reach low volume level | |
mDuckingFactor -= (mDucking_lowVolume); | |
} else { | |
mDuckingFactor = mDucking_lowVolume; | |
} | |
} else { | |
if (mDuckingFactor < 1.0 ) { | |
// FADE IN BG Track | |
// Increment ducking factor in total steps of | |
// low volume factor to reach orig.volume level | |
mDuckingFactor += (mDucking_lowVolume); | |
} else { | |
mDuckingFactor = 1.0; | |
} | |
} | |
} // end if - mDucking_enable | |
// Mixing Logic | |
LOGV("VideoEditorBGAudioProcessing:: Out of Ducking analysis uiPCMsize\ | |
%d %f %f", mDoDucking, mDuckingFactor,mBTVolLevel); | |
while (uiPCMsize-- > 0) { | |
M4OSA_Int32 temp; | |
// Set vol factor for BT and PT | |
*pBTMdata1 = (M4OSA_Int16)(*pBTMdata1*mBTVolLevel); | |
*pPTMdata2 = (M4OSA_Int16)(*pPTMdata2*mPTVolLevel); | |
// Mix the two samples | |
if (mDoDucking) { | |
// Duck the BG track to ducking factor value before mixing | |
*pBTMdata1 = (M4OSA_Int16)((*pBTMdata1)*(mDuckingFactor)); | |
// mix as normal case | |
*pBTMdata1 = (M4OSA_Int16)(*pBTMdata1 /2 + *pPTMdata2 /2); | |
} else { | |
*pBTMdata1 = (M4OSA_Int16)((*pBTMdata1)*(mDuckingFactor)); | |
*pBTMdata1 = (M4OSA_Int16)(*pBTMdata1 /2 + *pPTMdata2 /2); | |
} | |
if (*pBTMdata1 < 0) { | |
temp = -(*pBTMdata1) * 2; // bring to original Amplitude level | |
if (temp > 32767) { | |
*pBTMdata1 = -32766; // less then max allowed value | |
} else { | |
*pBTMdata1 = (M4OSA_Int16)(-temp); | |
} | |
} else { | |
temp = (*pBTMdata1) * 2; // bring to original Amplitude level | |
if ( temp > 32768) { | |
*pBTMdata1 = 32767; // less than max allowed value | |
} else { | |
*pBTMdata1 = (M4OSA_Int16)temp; | |
} | |
} | |
pBTMdata1++; | |
pPTMdata2++; | |
} | |
//LOGV("VideoEditorBGAudioProcessing:: Copy final out "); | |
memcpy((void *)pMixedOutBuffer->m_dataAddress, | |
(void *)pBackgroundTrack->m_dataAddress, | |
pBackgroundTrack->m_bufferSize); | |
LOGV("VideoEditorBGAudioProcessing::lvProcessAudioMixNDuck EXIT"); | |
return result; | |
} | |
VideoEditorBGAudioProcessing::~VideoEditorBGAudioProcessing() { | |
} | |
M4OSA_Int32 VideoEditorBGAudioProcessing::calculateOutResampleBufSize() { | |
// This already takes care of channel count in mBTBuffer.m_bufferSize | |
return (mOutSampleRate / mInSampleRate) * mBTBuffer.m_bufferSize; | |
} | |
void VideoEditorBGAudioProcessing ::veSetAudioProcessingParams( | |
const veAudMixSettings& gInputParams) { | |
LOGV("VideoEditorBGAudioProcessing:: ENTER lvSetAudioProcessingParams "); | |
mDucking_enable = gInputParams.lvInDucking_enable; | |
mDucking_lowVolume = gInputParams.lvInDucking_lowVolume; | |
mDucking_threshold = gInputParams.lvInDucking_threshold; | |
mPTVolLevel = gInputParams.lvPTVolLevel; | |
mBTVolLevel = gInputParams.lvBTVolLevel ; | |
mBTChannelCount = gInputParams.lvBTChannelCount; | |
mPTChannelCount = gInputParams.lvPTChannelCount; | |
mBTFormat = gInputParams.lvBTFormat; | |
mInSampleRate = gInputParams.lvInSampleRate; | |
mOutSampleRate = gInputParams.lvOutSampleRate; | |
mAudVolArrIndex = 0; | |
mDoDucking = 0; | |
mDuckingFactor = 1.0; // default | |
LOGV("VideoEditorBGAudioProcessing:: ducking_enable 0x%x \ | |
ducking_lowVolume %f ducking_threshold %d fPTVolLevel %f BTVolLevel %f", | |
mDucking_enable, mDucking_lowVolume, mDucking_threshold, | |
mPTVolLevel, mPTVolLevel); | |
// Following logc decides if SSRC support is needed for this mixing | |
mIsSSRCneeded = (gInputParams.lvInSampleRate != gInputParams.lvOutSampleRate); | |
if (gInputParams.lvBTChannelCount != gInputParams.lvPTChannelCount){ | |
if (gInputParams.lvBTChannelCount == 2){ | |
mChannelConversion = 1; // convert to MONO | |
} else { | |
mChannelConversion = 2; // Convert to STEREO | |
} | |
} else { | |
mChannelConversion = 0; | |
} | |
LOGV("VideoEditorBGAudioProcessing:: EXIT veSetAudioProcessingParams "); | |
} | |
// Fast way to compute 10 * log(value) | |
M4OSA_Int32 VideoEditorBGAudioProcessing::getDecibelSound(M4OSA_UInt32 value) { | |
if (value <= 0 || value > 0x8000) { | |
return 0; | |
} else if (value > 0x4000) { // 32768 | |
return 90; | |
} else if (value > 0x2000) { // 16384 | |
return 84; | |
} else if (value > 0x1000) { // 8192 | |
return 78; | |
} else if (value > 0x0800) { // 4028 | |
return 72; | |
} else if (value > 0x0400) { // 2048 | |
return 66; | |
} else if (value > 0x0200) { // 1024 | |
return 60; | |
} else if (value > 0x0100) { // 512 | |
return 54; | |
} else if (value > 0x0080) { // 256 | |
return 48; | |
} else if (value > 0x0040) { // 128 | |
return 42; | |
} else if (value > 0x0020) { // 64 | |
return 36; | |
} else if (value > 0x0010) { // 32 | |
return 30; | |
} else if (value > 0x0008) { // 16 | |
return 24; | |
} else if (value > 0x0007) { // 8 | |
return 24; | |
} else if (value > 0x0003) { // 4 | |
return 18; | |
} else if (value > 0x0001) { // 2 | |
return 12; | |
} else { // 1 | |
return 6; | |
} | |
} | |
M4OSA_Bool VideoEditorBGAudioProcessing::isThresholdBreached( | |
M4OSA_Int32* averageValue, | |
M4OSA_Int32 storeCount, | |
M4OSA_Int32 thresholdValue) { | |
int totalValue = 0; | |
for (int i = 0; i < storeCount; ++i) { | |
totalValue += averageValue[i]; | |
} | |
return (totalValue / storeCount > thresholdValue); | |
} | |
}//namespace android |