| /* |
| * 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. |
| */ |
| |
| /****************************************************************************************/ |
| /* */ |
| /* Includes */ |
| /* */ |
| /****************************************************************************************/ |
| |
| #include "LVDBE.h" |
| #include "LVDBE_Private.h" |
| #include "VectorArithmetic.h" |
| #include "AGC.h" |
| #include "LVDBE_Coeffs.h" /* Filter coefficients */ |
| |
| /********************************************************************************************/ |
| /* */ |
| /* FUNCTION: LVDBE_Process */ |
| /* */ |
| /* DESCRIPTION: */ |
| /* Process function for the Bass Enhancement module. */ |
| /* */ |
| /* Data can be processed in two formats, stereo or mono-in-stereo. Data in mono */ |
| /* format is not supported, the calling routine must convert the mono stream to */ |
| /* mono-in-stereo. */ |
| /* ___________ */ |
| /* ________ | | ________ */ |
| /* | | _____ |------------------------->| | | | */ |
| /* | 16-bit | | | | ________ | | | 32-bit | */ |
| /* -+-->| to |-->| HPF |--| | | _____ | AGC Mixer |-->| to |--| */ |
| /* | | 32-bit | |_____| | | Stereo | | | | | | 16-bit | | */ |
| /* | |________| |-->| to |-->| BPF |-->| | |________| 0 */ |
| /* | | Mono | |_____| |___________| \--> */ |
| /* | |________| */ |
| /* | _________ 0 */ |
| /* | | | | */ |
| /* |----------------------------------------------------| Volume |-----------------| */ |
| /* | Control | */ |
| /* |_________| */ |
| /* */ |
| /* 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: */ |
| /* LVDBE_SUCCESS Succeeded */ |
| /* LVDBE_TOOMANYSAMPLES NumSamples was larger than the maximum block size */ |
| /* */ |
| /* NOTES: */ |
| /* 1. The input and output data must be 32-bit format. The input is scaled by a shift */ |
| /* when converting from 16-bit format, this scaling allows for internal headroom in the */ |
| /* bass enhancement algorithm. */ |
| /* 2. For a 16-bit implementation the converstion to 32-bit is removed and replaced with */ |
| /* the headroom loss. This headroom loss is compensated in the volume control so the */ |
| /* overall end to end gain is odB. */ |
| /* */ |
| /********************************************************************************************/ |
| #ifndef BUILD_FLOAT |
| LVDBE_ReturnStatus_en LVDBE_Process(LVDBE_Handle_t hInstance, |
| const LVM_INT16 *pInData, LVM_INT16 *pOutData, LVM_UINT16 NumSamples) { |
| |
| LVDBE_Instance_t *pInstance = (LVDBE_Instance_t *) hInstance; |
| LVM_INT32 *pScratch = |
| (LVM_INT32 *) pInstance->MemoryTable.Region[LVDBE_MEMREGION_SCRATCH].pBaseAddress; |
| LVM_INT32 *pMono; |
| LVM_INT16 *pInput = (LVM_INT16 *) pInData; |
| |
| /* Scratch for Volume Control starts at offset of 2*NumSamples short values from pScratch */ |
| LVM_INT16 *pScratchVol = (LVM_INT16 *) (&pScratch[NumSamples]); |
| |
| /* Scratch for Mono path starts at offset of 2*NumSamples 32-bit values from pScratch */ |
| pMono = &pScratch[2 * NumSamples]; |
| |
| /* |
| * Check the number of samples is not too large |
| */ |
| if (NumSamples > pInstance->Capabilities.MaxBlockSize) { |
| return (LVDBE_TOOMANYSAMPLES); |
| } |
| |
| /* |
| * Check if the algorithm is enabled |
| */ |
| /* DBE path is processed when DBE is ON or during On/Off transitions */ |
| if ((pInstance->Params.OperatingMode == LVDBE_ON) |
| || (LVC_Mixer_GetCurrent( |
| &pInstance->pData->BypassMixer.MixerStream[0]) |
| != LVC_Mixer_GetTarget( |
| &pInstance->pData->BypassMixer.MixerStream[0]))) { |
| |
| /* |
| * Convert 16-bit samples to 32-bit and scale |
| * (For a 16-bit implementation apply headroom loss here) |
| */ |
| Int16LShiftToInt32_16x32(pInput, /* Source 16-bit data */ |
| pScratch, /* Dest. 32-bit data */ |
| (LVM_INT16) (2 * NumSamples), /* Left and right */ |
| LVDBE_SCALESHIFT); /* Shift scale */ |
| |
| /* |
| * Apply the high pass filter if selected |
| */ |
| if (pInstance->Params.HPFSelect == LVDBE_HPF_ON) { |
| BQ_2I_D32F32C30_TRC_WRA_01(&pInstance->pCoef->HPFInstance,/* Filter instance */ |
| (LVM_INT32 *) pScratch, /* Source */ |
| (LVM_INT32 *) pScratch, /* Destination */ |
| (LVM_INT16) NumSamples); /* Number of samples */ |
| } |
| |
| /* |
| * Create the mono stream |
| */ |
| From2iToMono_32(pScratch, /* Stereo source */ |
| pMono, /* Mono destination */ |
| (LVM_INT16) NumSamples); /* Number of samples */ |
| |
| /* |
| * Apply the band pass filter |
| */ |
| BP_1I_D32F32C30_TRC_WRA_02(&pInstance->pCoef->BPFInstance, /* Filter instance */ |
| (LVM_INT32 *) pMono, /* Source */ |
| (LVM_INT32 *) pMono, /* Destination */ |
| (LVM_INT16) NumSamples); /* Number of samples */ |
| |
| /* |
| * Apply the AGC and mix |
| */ |
| AGC_MIX_VOL_2St1Mon_D32_WRA(&pInstance->pData->AGCInstance, /* Instance pointer */ |
| pScratch, /* Stereo source */ |
| pMono, /* Mono band pass source */ |
| pScratch, /* Stereo destination */ |
| NumSamples); /* Number of samples */ |
| |
| /* |
| * Convert 32-bit samples to 16-bit and saturate |
| * (Not required for 16-bit implemenations) |
| */ |
| Int32RShiftToInt16_Sat_32x16(pScratch, /* Source 32-bit data */ |
| (LVM_INT16 *) pScratch, /* Dest. 16-bit data */ |
| (LVM_INT16) (2 * NumSamples), /* Left and right */ |
| LVDBE_SCALESHIFT); /* Shift scale */ |
| |
| } |
| |
| /* Bypass Volume path is processed when DBE is OFF or during On/Off transitions */ |
| if ((pInstance->Params.OperatingMode == LVDBE_OFF) |
| || (LVC_Mixer_GetCurrent( |
| &pInstance->pData->BypassMixer.MixerStream[1]) |
| != LVC_Mixer_GetTarget( |
| &pInstance->pData->BypassMixer.MixerStream[1]))) { |
| |
| /* |
| * The algorithm is disabled but volume management is required to compensate for |
| * headroom and volume (if enabled) |
| */ |
| LVC_MixSoft_1St_D16C31_SAT(&pInstance->pData->BypassVolume, pInData, |
| pScratchVol, (LVM_INT16) (2 * NumSamples)); /* Left and right */ |
| |
| } |
| |
| /* |
| * Mix DBE processed path and bypass volume path |
| */ |
| LVC_MixSoft_2St_D16C31_SAT(&pInstance->pData->BypassMixer, |
| (LVM_INT16 *) pScratch, pScratchVol, pOutData, |
| (LVM_INT16) (2 * NumSamples)); |
| |
| return (LVDBE_SUCCESS); |
| } |
| #else /*BUILD_FLOAT*/ |
| LVDBE_ReturnStatus_en LVDBE_Process(LVDBE_Handle_t hInstance, |
| const LVM_FLOAT *pInData, |
| LVM_FLOAT *pOutData, |
| LVM_UINT16 NumSamples) |
| { |
| |
| LVDBE_Instance_t *pInstance =(LVDBE_Instance_t *)hInstance; |
| LVM_FLOAT *pScratch_in = (LVM_FLOAT *)pInstance->MemoryTable.Region |
| [LVDBE_MEMREGION_SCRATCH].pBaseAddress; |
| LVM_FLOAT *pScratch = pScratch_in + 2 * NumSamples; |
| LVM_FLOAT *pMono; |
| LVM_INT32 ii = 0; |
| |
| /* Scratch for Volume Control starts at offset of 4*NumSamples float values from pScratch */ |
| LVM_FLOAT *pScratchVol = (LVM_FLOAT *)(&pScratch_in[4 * NumSamples]); |
| // LVM_INT16 *pScratchVol_int = (LVM_INT16 *)(pScratchVol); |
| |
| /* Scratch for Mono path starts at offset of 6*NumSamples 32-bit values from pScratch */ |
| pMono = &pScratch_in[4 * NumSamples]; |
| |
| /* |
| * Check the number of samples is not too large |
| */ |
| if (NumSamples > pInstance->Capabilities.MaxBlockSize) |
| { |
| return(LVDBE_TOOMANYSAMPLES); |
| } |
| |
| /* |
| * Convert 16-bit samples to Float |
| */ |
| Copy_Float(pInData, /* Source 16-bit data */ |
| pScratch_in, /* Dest. 32-bit data */ |
| (LVM_INT16)(2 * NumSamples)); /* Left and right */ |
| |
| for (ii = 0; ii < 2 * NumSamples; ii++) { |
| pScratch[ii] = pScratch_in[ii]; |
| } |
| /* |
| * Check if the algorithm is enabled |
| */ |
| /* DBE path is processed when DBE is ON or during On/Off transitions */ |
| if ((pInstance->Params.OperatingMode == LVDBE_ON)|| |
| (LVC_Mixer_GetCurrent(&pInstance->pData->BypassMixer.MixerStream[0]) |
| !=LVC_Mixer_GetTarget(&pInstance->pData->BypassMixer.MixerStream[0]))) |
| { |
| |
| /* |
| * Apply the high pass filter if selected |
| */ |
| if (pInstance->Params.HPFSelect == LVDBE_HPF_ON) |
| { |
| BQ_2I_D32F32C30_TRC_WRA_01(&pInstance->pCoef->HPFInstance,/* Filter instance */ |
| (LVM_FLOAT *)pScratch, /* Source */ |
| (LVM_FLOAT *)pScratch, /* Destination */ |
| (LVM_INT16)NumSamples); /* Number of samples */ |
| } |
| |
| /* |
| * Create the mono stream |
| */ |
| From2iToMono_Float((LVM_FLOAT *)pScratch, /* Stereo source */ |
| pMono, /* Mono destination */ |
| (LVM_INT16)NumSamples); /* Number of samples */ |
| |
| /* |
| * Apply the band pass filter |
| */ |
| BP_1I_D32F32C30_TRC_WRA_02(&pInstance->pCoef->BPFInstance, /* Filter instance */ |
| (LVM_FLOAT *)pMono, /* Source */ |
| (LVM_FLOAT *)pMono, /* Destination */ |
| (LVM_INT16)NumSamples); /* Number of samples */ |
| |
| /* |
| * Apply the AGC and mix |
| */ |
| AGC_MIX_VOL_2St1Mon_D32_WRA(&pInstance->pData->AGCInstance, /* Instance pointer */ |
| pScratch, /* Stereo source */ |
| pMono, /* Mono band pass source */ |
| pScratch, /* Stereo destination */ |
| NumSamples); /* Number of samples */ |
| |
| for (ii = 0; ii < 2 * NumSamples; ii++) { |
| //TODO: replace with existing clamping function |
| if(pScratch[ii] < -1.0) { |
| pScratch[ii] = -1.0; |
| } else if(pScratch[ii] > 1.0) { |
| pScratch[ii] = 1.0; |
| } |
| } |
| } |
| |
| /* Bypass Volume path is processed when DBE is OFF or during On/Off transitions */ |
| if ((pInstance->Params.OperatingMode == LVDBE_OFF)|| |
| (LVC_Mixer_GetCurrent(&pInstance->pData->BypassMixer.MixerStream[1]) |
| !=LVC_Mixer_GetTarget(&pInstance->pData->BypassMixer.MixerStream[1]))) |
| { |
| |
| /* |
| * The algorithm is disabled but volume management is required to compensate for |
| * headroom and volume (if enabled) |
| */ |
| LVC_MixSoft_1St_D16C31_SAT(&pInstance->pData->BypassVolume, |
| pScratch_in, |
| pScratchVol, |
| (LVM_INT16)(2 * NumSamples)); /* Left and right */ |
| } |
| |
| /* |
| * Mix DBE processed path and bypass volume path |
| */ |
| LVC_MixSoft_2St_D16C31_SAT(&pInstance->pData->BypassMixer, |
| pScratch, |
| pScratchVol, |
| pOutData, |
| (LVM_INT16)(2 * NumSamples)); |
| |
| return(LVDBE_SUCCESS); |
| } |
| #endif |