diff options
Diffstat (limited to 'media/libeffects/lvm/lib/Reverb/src/LVREV_Process.c')
-rwxr-xr-x | media/libeffects/lvm/lib/Reverb/src/LVREV_Process.c | 550 |
1 files changed, 550 insertions, 0 deletions
diff --git a/media/libeffects/lvm/lib/Reverb/src/LVREV_Process.c b/media/libeffects/lvm/lib/Reverb/src/LVREV_Process.c new file mode 100755 index 0000000..822ac8f --- /dev/null +++ b/media/libeffects/lvm/lib/Reverb/src/LVREV_Process.c @@ -0,0 +1,550 @@ +/* + * Copyright (C) 2004-2010 NXP Software + * Copyright (C) 2010 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. + */ + +/****************************************************************************************/ +/* */ +/* Project:: */ +/* $Author: nxp007753 $ */ +/* $Revision: 1316 $ */ +/* $Date: 2010-07-23 11:53:24 +0200 (Fri, 23 Jul 2010) $ */ +/* */ +/****************************************************************************************/ + +/****************************************************************************************/ +/* */ +/* Includes */ +/* */ +/****************************************************************************************/ +#include "LVREV_Private.h" +#include "VectorArithmetic.h" + + +/****************************************************************************************/ +/* */ +/* FUNCTION: LVREV_Process */ +/* */ +/* DESCRIPTION: */ +/* Process function for the LVREV module. */ +/* */ +/* PARAMETERS: */ +/* hInstance Instance handle */ +/* pInData Pointer to the input data */ +/* pOutData Pointer to the output data */ +/* NumSamples Number of samples in the input buffer */ +/* */ +/* RETURNS: */ +/* LVREV_Success Succeeded */ +/* LVREV_INVALIDNUMSAMPLES NumSamples was larger than the maximum block size */ +/* LVREV_NULLADDRESS When one of hInstance, pInData or pOutData is NULL */ +/* */ +/* NOTES: */ +/* 1. The input and output buffers must be 32-bit aligned */ +/* */ +/****************************************************************************************/ +LVREV_ReturnStatus_en LVREV_Process(LVREV_Handle_t hInstance, + const LVM_INT32 *pInData, + LVM_INT32 *pOutData, + const LVM_UINT16 NumSamples) +{ + LVREV_Instance_st *pLVREV_Private = (LVREV_Instance_st *)hInstance; + LVM_INT32 *pInput = (LVM_INT32 *)pInData; + LVM_INT32 *pOutput = pOutData; + LVM_INT32 SamplesToProcess, RemainingSamples, format; + + /* + * Check for error conditions + */ + + /* Check for NULL pointers */ + if((hInstance == LVM_NULL) || (pInData == LVM_NULL) || (pOutData == LVM_NULL)) + { + return LVREV_NULLADDRESS; + } + + + /* + * Apply the new controls settings if required + */ + if(pLVREV_Private->bControlPending == LVM_TRUE) + { + LVREV_ReturnStatus_en errorCode; + + /* + * Clear the pending flag and update the control settings + */ + pLVREV_Private->bControlPending = LVM_FALSE; + + errorCode = LVREV_ApplyNewSettings (pLVREV_Private); + + if(errorCode != LVREV_SUCCESS) + { + return errorCode; + } + } + + /* + * Trap the case where the number of samples is zero. + */ + if (NumSamples == 0) + { + return LVREV_SUCCESS; + } + + RemainingSamples = (LVM_INT32)NumSamples; + + format = 1; + if (pLVREV_Private->CurrentParams.SourceFormat != LVM_MONO) + { + format = 2; + } + + while (RemainingSamples!=0) + { + /* + * If OFF copy and reformat the data as necessary + */ + if (pLVREV_Private->CurrentParams.OperatingMode == LVM_MODE_OFF) + { + if((pInput != pOutput) || (pLVREV_Private->CurrentParams.SourceFormat == LVM_MONO)) + { + /* + * Copy the data to the output buffer + */ + + if (pLVREV_Private->CurrentParams.SourceFormat != LVM_MONO) + { + RemainingSamples = (RemainingSamples << 1); /* Stereo data */ + } + + Copy_16((LVM_INT16 *)pInput, + (LVM_INT16 *)pOutput, + (LVM_INT16)(RemainingSamples << 1)); + } + + RemainingSamples = 0; + } + + /* + * Process the data + */ + else + { + + if(RemainingSamples > pLVREV_Private->MaxBlkLen) + { + SamplesToProcess = pLVREV_Private->MaxBlkLen; + RemainingSamples = (LVM_INT16)(RemainingSamples - SamplesToProcess); + } + else + { + SamplesToProcess = RemainingSamples; + RemainingSamples = 0; + } + + ReverbBlock(pInput, pOutput, pLVREV_Private, (LVM_UINT16)SamplesToProcess); + + pInput = (LVM_INT32 *)(pInput +(SamplesToProcess*format)); + pOutput = (LVM_INT32 *)(pOutput+(SamplesToProcess*format)); + } + } + + return LVREV_SUCCESS; +} + + + +/****************************************************************************************/ +/* */ +/* FUNCTION: ReverbBlock */ +/* */ +/* DESCRIPTION: */ +/* Process function for the LVREV module. */ +/* */ +/* PARAMETERS: */ +/* hInstance Instance handle */ +/* pInData Pointer to the input data */ +/* pOutData Pointer to the output data */ +/* NumSamples Number of samples in the input buffer */ +/* */ +/* RETURNS: */ +/* LVREV_Success Succeeded */ +/* LVREV_INVALIDNUMSAMPLES NumSamples was larger than the maximum block size */ +/* LVREV_NULLADDRESS When one of hInstance, pInData or pOutData is NULL */ +/* */ +/* NOTES: */ +/* 1. The input and output buffers must be 32-bit aligned */ +/* */ +/****************************************************************************************/ + +void ReverbBlock(LVM_INT32 *pInput, LVM_INT32 *pOutput, LVREV_Instance_st *pPrivate, LVM_UINT16 NumSamples) +{ + LVM_INT16 j, size; + LVM_INT32 *pDelayLine; + LVM_INT32 *pDelayLineInput = pPrivate->pScratch; + LVM_INT32 *pScratch = pPrivate->pScratch; + LVM_INT32 *pIn; + LVM_INT32 *pTemp = pPrivate->pInputSave; + LVM_INT32 NumberOfDelayLines; + + /****************************************************************************** + * All calculations will go into the buffer pointed to by pTemp, this will * + * then be mixed with the original input to create the final output. * + * * + * When INPLACE processing is selected this must be a temporary buffer and * + * hence this is the worst case, so for simplicity this will ALWAYS be so * + * * + * The input buffer will remain untouched until the output of the mixer if * + * INPLACE processing is selected. * + * * + * The temp buffer will always be NumSamples in size regardless of MONO or * + * STEREO input. In the case of stereo input all processing is done in MONO * + * and the final output is converted to STEREO after the mixer * + ******************************************************************************/ + + if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4 ) + { + NumberOfDelayLines = 4; + } + else if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_2 ) + { + NumberOfDelayLines = 2; + } + else + { + NumberOfDelayLines = 1; + } + + if(pPrivate->CurrentParams.SourceFormat == LVM_MONO) + { + pIn = pInput; + } + else + { + /* + * Stereo to mono conversion + */ + + From2iToMono_32( pInput, + pTemp, + (LVM_INT16)NumSamples); + + pIn = pTemp; + } + + Mult3s_32x16(pIn, + (LVM_INT16)LVREV_HEADROOM, + pTemp, + (LVM_INT16)NumSamples); + + /* + * High pass filter + */ + FO_1I_D32F32C31_TRC_WRA_01( &pPrivate->pFastCoef->HPCoefs, + pTemp, + pTemp, + (LVM_INT16)NumSamples); + /* + * Low pass filter + */ + FO_1I_D32F32C31_TRC_WRA_01( &pPrivate->pFastCoef->LPCoefs, + pTemp, + pTemp, + (LVM_INT16)NumSamples); + + /* + * Process all delay lines + */ + + for(j = 0; j < NumberOfDelayLines; j++) + { + pDelayLine = pPrivate->pScratchDelayLine[j]; + + /* + * All-pass filter with pop and click suppression + */ + /* Get the smoothed, delayed output. Put it in the output buffer */ + MixSoft_2St_D32C31_SAT(&pPrivate->Mixer_APTaps[j], + pPrivate->pOffsetA[j], + pPrivate->pOffsetB[j], + pDelayLine, + (LVM_INT16)NumSamples); + /* Re-align the all pass filter delay buffer and copying the fixed delay data to the AP delay in the process */ + Copy_16((LVM_INT16 *)&pPrivate->pDelay_T[j][NumSamples], + (LVM_INT16 *)pPrivate->pDelay_T[j], + (LVM_INT16)((pPrivate->T[j]-NumSamples) << 1)); /* 32-bit data */ + /* Apply the smoothed feedback and save to fixed delay input (currently empty) */ + MixSoft_1St_D32C31_WRA(&pPrivate->Mixer_SGFeedback[j], + pDelayLine, + &pPrivate->pDelay_T[j][pPrivate->T[j]-NumSamples], + (LVM_INT16)NumSamples); + /* Sum into the AP delay line */ + Mac3s_Sat_32x16(&pPrivate->pDelay_T[j][pPrivate->T[j]-NumSamples], + -0x7fff, /* Invert since the feedback coefficient is negative */ + &pPrivate->pDelay_T[j][pPrivate->Delay_AP[j]-NumSamples], + (LVM_INT16)NumSamples); + /* Apply smoothed feedforward sand save to fixed delay input (currently empty) */ + MixSoft_1St_D32C31_WRA(&pPrivate->Mixer_SGFeedforward[j], + &pPrivate->pDelay_T[j][pPrivate->Delay_AP[j]-NumSamples], + &pPrivate->pDelay_T[j][pPrivate->T[j]-NumSamples], + (LVM_INT16)NumSamples); + /* Sum into the AP output */ + Mac3s_Sat_32x16(&pPrivate->pDelay_T[j][pPrivate->T[j]-NumSamples], + 0x7fff, + pDelayLine, + (LVM_INT16)NumSamples); + + /* + * Feedback gain + */ + MixSoft_1St_D32C31_WRA(&pPrivate->FeedbackMixer[j], pDelayLine, pDelayLine, NumSamples); + + /* + * Low pass filter + */ + FO_1I_D32F32C31_TRC_WRA_01( &pPrivate->pFastCoef->RevLPCoefs[j], + pDelayLine, + pDelayLine, + (LVM_INT16)NumSamples); + } + + /* + * Apply rotation matrix and delay samples + */ + for(j = 0; j < NumberOfDelayLines; j++) + { + + Copy_16( (LVM_INT16*)(pTemp), + (LVM_INT16*)(pDelayLineInput), + (LVM_INT16)(NumSamples << 1)); + + /* + * Rotation matrix mix + */ + switch(j) + { + case 3: + /* + * Add delay line 1 and 2 contribution + */ + Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[1], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples); + Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[2], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples); + + break; + case 2: + + /* + * Add delay line 0 and 3 contribution + */ + Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[0], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples); + Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[3], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples); + + break; + case 1: + if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4) + { + /* + * Add delay line 0 and 3 contribution + */ + Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[0], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples); + Add2_Sat_32x32(pPrivate->pScratchDelayLine[3], pDelayLineInput, (LVM_INT16)NumSamples); + + } + else + { + /* + * Add delay line 0 and 1 contribution + */ + Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[0], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples); + Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[1], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples); + + } + break; + case 0: + if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4) + { + /* + * Add delay line 1 and 2 contribution + */ + Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[1], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples); + Add2_Sat_32x32(pPrivate->pScratchDelayLine[2], pDelayLineInput, (LVM_INT16)NumSamples); + + } + else if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_2) + { + /* + * Add delay line 0 and 1 contribution + */ + Add2_Sat_32x32(pPrivate->pScratchDelayLine[0], pDelayLineInput, (LVM_INT16)NumSamples); + Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[1], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples); + + } + else + { + /* + * Add delay line 0 contribution + */ + + /* SOURCE DESTINATION*/ + Add2_Sat_32x32(pPrivate->pScratchDelayLine[0], pDelayLineInput, (LVM_INT16)NumSamples); + } + break; + default: + break; + } + + /* + * Delay samples + */ + Copy_16((LVM_INT16 *)pDelayLineInput, + (LVM_INT16 *)&pPrivate->pDelay_T[j][pPrivate->T[j]-NumSamples], + (LVM_INT16)(NumSamples << 1)); /* 32-bit data */ + + } + + + /* + * Create stereo output + */ + switch(pPrivate->InstanceParams.NumDelays) + { + case LVREV_DELAYLINES_4: + Add2_Sat_32x32(pPrivate->pScratchDelayLine[3], + pPrivate->pScratchDelayLine[0], + (LVM_INT16)NumSamples); + Add2_Sat_32x32(pPrivate->pScratchDelayLine[2], + pPrivate->pScratchDelayLine[1], + (LVM_INT16)NumSamples); + + if(pPrivate->CurrentParams.SourceFormat != LVM_MONO) + { + JoinTo2i_32x32(pPrivate->pScratchDelayLine[0], + pPrivate->pScratchDelayLine[1], + pTemp, + (LVM_INT16)NumSamples); + + } + else + { + Add2_Sat_32x32(pPrivate->pScratchDelayLine[1], + pPrivate->pScratchDelayLine[0], + (LVM_INT16)NumSamples); + + /*Apply 3-dB gain in-order to compensate for the gain change in stereo mode*/ + Mult3s_32x16(pPrivate->pScratchDelayLine[0], + LVREV_MIN3DB, + pTemp, + (LVM_INT16)NumSamples); + } + break; + case LVREV_DELAYLINES_2: + + Copy_16( (LVM_INT16*)pPrivate->pScratchDelayLine[1], + (LVM_INT16*)pScratch, + (LVM_INT16)(NumSamples << 1)); + + + + if(pPrivate->CurrentParams.SourceFormat != LVM_MONO) + { + + Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[0], + -0x8000, + pScratch, + (LVM_INT16)NumSamples); + } + + Add2_Sat_32x32(pPrivate->pScratchDelayLine[1], + pPrivate->pScratchDelayLine[0], + (LVM_INT16)NumSamples); + + + if(pPrivate->CurrentParams.SourceFormat != LVM_MONO) + { + JoinTo2i_32x32(pPrivate->pScratchDelayLine[0], + pScratch, + pTemp, + (LVM_INT16)NumSamples); + } + else + { + Copy_16( (LVM_INT16*)pPrivate->pScratchDelayLine[0], + (LVM_INT16*)pTemp, + (LVM_INT16)(NumSamples << 1)); + + } + break; + case LVREV_DELAYLINES_1: + if(pPrivate->CurrentParams.SourceFormat != LVM_MONO) + { + + MonoTo2I_32(pPrivate->pScratchDelayLine[0], + pTemp, + (LVM_INT16)NumSamples); + } + else + { + pTemp = pPrivate->pScratchDelayLine[0]; + } + break; + default: + break; + } + + + /* + * Dry/wet mixer + */ + if(pPrivate->CurrentParams.SourceFormat != LVM_MONO) + { + size = (LVM_INT16)(NumSamples << 1); + } + else + { + size = (LVM_INT16)NumSamples; + } + + MixSoft_2St_D32C31_SAT(&pPrivate->BypassMixer, + pInput, + pTemp, + pOutput, + size); + + /* Apply Gain*/ + if(pPrivate->CurrentParams.SourceFormat != LVM_MONO) + { + size = (LVM_INT16)(NumSamples << 1); + } + else + { + size = (LVM_INT16)NumSamples; + } + + Shift_Sat_v32xv32 (LVREV_OUTPUTGAIN_SHIFT, + pOutput, + pOutput, + size); + + MixSoft_1St_D32C31_WRA(&pPrivate->GainMixer, + pOutput, + pOutput, + size); + return; +} + + +/* End of file */ + |