| /* | |
| * 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 |