blob: e3bbdf2964db091a06c8b7a5eb9bacee5cff8992 [file] [log] [blame]
/*
* 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