LVPSA_Process.c revision 2c8e5cab3faa6d360e222b7a6c40a80083d021ac
1/*
2 * Copyright (C) 2004-2010 NXP Software
3 * Copyright (C) 2010 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18/************************************************************************/
19/*                                                                      */
20/*     Project::   PSA_01_ARMC_01                                       */
21/*     $Author: beq07716 $*/
22/*     $Revision: 1006 $*/
23/*     $Date: 2010-06-28 14:01:47 +0200 (Mon, 28 Jun 2010) $*/
24/*                                                                      */
25/************************************************************************/
26#include    "LVPSA.h"
27#include    "LVPSA_Private.h"
28#include    "LVM_Macros.h"
29#include    "VectorArithmetic.h"
30
31#define LVM_MININT_32   0x80000000
32
33
34/************************************************************************************/
35/*                                                                                  */
36/* FUNCTION:            LVPSA_Process                                               */
37/*                                                                                  */
38/* DESCRIPTION:                                                                     */
39/*  The process applies band pass filters to the signal. Each output                */
40/*  feeds a quasi peak filter for level detection.                                  */
41/*                                                                                  */
42/* PARAMETERS:                                                                      */
43/*  hInstance           Pointer to the instance                                     */
44/*  pLVPSA_InputSamples Pointer to the input samples buffer                         */
45/*  InputBlockSize      Number of mono samples to process                           */
46/*  AudioTime           Playback time of the input samples                          */
47/*                                                                                  */
48/*                                                                                  */
49/* RETURNS:                                                                         */
50/*  LVPSA_OK            Succeeds                                                    */
51/*  otherwise           Error due to bad parameters                                 */
52/*                                                                                  */
53/************************************************************************************/
54LVPSA_RETURN LVPSA_Process           ( pLVPSA_Handle_t      hInstance,
55                                       LVM_INT16           *pLVPSA_InputSamples,
56                                       LVM_UINT16           InputBlockSize,
57                                       LVPSA_Time           AudioTime            )
58
59{
60    LVPSA_InstancePr_t     *pLVPSA_Inst = (LVPSA_InstancePr_t*)hInstance;
61    LVM_INT16               *pScratch;
62    LVM_INT16               ii;
63    LVM_INT32               AudioTimeInc;
64    extern LVM_UINT32       LVPSA_SampleRateInvTab[];
65    LVM_UINT8               *pWrite_Save;         /* Position of the write pointer at the beginning of the process  */
66
67    /******************************************************************************
68       CHECK PARAMETERS
69    *******************************************************************************/
70    if(hInstance == LVM_NULL || pLVPSA_InputSamples == LVM_NULL)
71    {
72        return(LVPSA_ERROR_NULLADDRESS);
73    }
74    if(InputBlockSize == 0 || InputBlockSize > pLVPSA_Inst->MaxInputBlockSize)
75    {
76        return(LVPSA_ERROR_INVALIDPARAM);
77    }
78
79    pScratch = (LVM_INT16*)pLVPSA_Inst->MemoryTable.Region[LVPSA_MEMREGION_SCRATCH].pBaseAddress;
80    pWrite_Save = pLVPSA_Inst->pSpectralDataBufferWritePointer;
81
82    /******************************************************************************
83       APPLY NEW SETTINGS IF NEEDED
84    *******************************************************************************/
85    if (pLVPSA_Inst->bControlPending == LVM_TRUE)
86    {
87        pLVPSA_Inst->bControlPending = 0;
88        LVPSA_ApplyNewSettings( pLVPSA_Inst);
89    }
90
91    /******************************************************************************
92       PROCESS SAMPLES
93    *******************************************************************************/
94    /* Put samples in range [-0.5;0.5[ for BP filters (see Biquads documentation) */
95    Copy_16( pLVPSA_InputSamples,pScratch,(LVM_INT16)InputBlockSize);
96    Shift_Sat_v16xv16(-1,pScratch,pScratch,(LVM_INT16)InputBlockSize);
97
98    for (ii = 0; ii < pLVPSA_Inst->nRelevantFilters; ii++)
99    {
100        switch(pLVPSA_Inst->pBPFiltersPrecision[ii])
101        {
102            case LVPSA_SimplePrecisionFilter:
103                BP_1I_D16F16C14_TRC_WRA_01  ( &pLVPSA_Inst->pBP_Instances[ii],
104                                              pScratch,
105                                              pScratch + InputBlockSize,
106                                              (LVM_INT16)InputBlockSize);
107                break;
108
109            case LVPSA_DoublePrecisionFilter:
110                BP_1I_D16F32C30_TRC_WRA_01  ( &pLVPSA_Inst->pBP_Instances[ii],
111                                              pScratch,
112                                              pScratch + InputBlockSize,
113                                              (LVM_INT16)InputBlockSize);
114                break;
115            default:
116                break;
117        }
118
119
120        LVPSA_QPD_Process   ( pLVPSA_Inst,
121                              pScratch + InputBlockSize,
122                              (LVM_INT16)InputBlockSize,
123                              ii);
124    }
125
126    /******************************************************************************
127       UPDATE SpectralDataBufferAudioTime
128    *******************************************************************************/
129
130    if(pLVPSA_Inst->pSpectralDataBufferWritePointer != pWrite_Save)
131    {
132        MUL32x32INTO32((AudioTime + (LVM_INT32)((LVM_INT32)pLVPSA_Inst->LocalSamplesCount*1000)),
133                        (LVM_INT32)LVPSA_SampleRateInvTab[pLVPSA_Inst->CurrentParams.Fs],
134                        AudioTimeInc,
135                        LVPSA_FsInvertShift)
136        pLVPSA_Inst->SpectralDataBufferAudioTime = AudioTime + AudioTimeInc;
137    }
138
139    return(LVPSA_OK);
140}
141
142
143/************************************************************************************/
144/*                                                                                  */
145/* FUNCTION:            LVPSA_GetSpectrum                                           */
146/*                                                                                  */
147/* DESCRIPTION:                                                                     */
148/*  Gets the levels values at a certain point in time                               */
149/*                                                                                  */
150/*                                                                                  */
151/* PARAMETERS:                                                                      */
152/*  hInstance            Pointer to the instance                                    */
153/*  GetSpectrumAudioTime Retrieve the values at this time                           */
154/*  pCurrentValues       Pointer to a buffer that will contain levels' values       */
155/*  pMaxValues           Pointer to a buffer that will contain max levels' values   */
156/*                                                                                  */
157/*                                                                                  */
158/* RETURNS:                                                                         */
159/*  LVPSA_OK            Succeeds                                                    */
160/*  otherwise           Error due to bad parameters                                 */
161/*                                                                                  */
162/************************************************************************************/
163LVPSA_RETURN LVPSA_GetSpectrum       ( pLVPSA_Handle_t      hInstance,
164                                       LVPSA_Time           GetSpectrumAudioTime,
165                                       LVM_UINT8           *pCurrentValues,
166                                       LVM_UINT8           *pPeakValues           )
167
168{
169
170    LVPSA_InstancePr_t      *pLVPSA_Inst = (LVPSA_InstancePr_t*)hInstance;
171    LVM_INT32               StatusDelta, ii;
172    LVM_UINT8               *pRead;
173
174    if(hInstance == LVM_NULL || pCurrentValues == LVM_NULL || pPeakValues == LVM_NULL)
175    {
176        return(LVPSA_ERROR_NULLADDRESS);
177    }
178
179
180    /* First find the place where to look in the status buffer */
181    if(GetSpectrumAudioTime <= pLVPSA_Inst->SpectralDataBufferAudioTime)
182    {
183        MUL32x32INTO32((pLVPSA_Inst->SpectralDataBufferAudioTime - GetSpectrumAudioTime),LVPSA_InternalRefreshTimeInv,StatusDelta,LVPSA_InternalRefreshTimeShift);
184        if((StatusDelta * LVPSA_InternalRefreshTime) != (pLVPSA_Inst->SpectralDataBufferAudioTime - GetSpectrumAudioTime))
185        {
186            StatusDelta += 1;
187        }
188    }
189    else
190    {
191        /* This part handles the wrap around */
192        MUL32x32INTO32(((pLVPSA_Inst->SpectralDataBufferAudioTime - (LVM_INT32)LVM_MININT_32) + ((LVM_INT32)LVM_MAXINT_32 - GetSpectrumAudioTime)),LVPSA_InternalRefreshTimeInv,StatusDelta,LVPSA_InternalRefreshTimeShift)
193        if(((LVM_INT32)(StatusDelta * LVPSA_InternalRefreshTime)) != ((LVM_INT32)((pLVPSA_Inst->SpectralDataBufferAudioTime - (LVM_INT32)LVM_MININT_32) + ((LVM_INT32)LVM_MAXINT_32 - GetSpectrumAudioTime))))
194        {
195            StatusDelta += 1;
196        }
197    }
198    /* Check whether the desired level is not too "old" (see 2.10 in LVPSA_DesignNotes.doc)*/
199    if(
200        ((GetSpectrumAudioTime < pLVPSA_Inst->SpectralDataBufferAudioTime)&&
201         ((GetSpectrumAudioTime<0)&&(pLVPSA_Inst->SpectralDataBufferAudioTime>0))&&
202         (((LVM_INT32)(-GetSpectrumAudioTime + pLVPSA_Inst->SpectralDataBufferAudioTime))>LVM_MAXINT_32))||
203
204         ((GetSpectrumAudioTime > pLVPSA_Inst->SpectralDataBufferAudioTime)&&
205         (((GetSpectrumAudioTime>=0)&&(pLVPSA_Inst->SpectralDataBufferAudioTime>=0))||
206          ((GetSpectrumAudioTime<=0)&&(pLVPSA_Inst->SpectralDataBufferAudioTime<=0))||
207         (((GetSpectrumAudioTime>=0)&&(pLVPSA_Inst->SpectralDataBufferAudioTime<=0))&&
208         (((LVM_INT32)(GetSpectrumAudioTime - pLVPSA_Inst->SpectralDataBufferAudioTime))<LVM_MAXINT_32))))||
209
210        (StatusDelta > (LVM_INT32)pLVPSA_Inst->SpectralDataBufferLength) ||
211        (!StatusDelta))
212    {
213        for(ii = 0; ii < pLVPSA_Inst->nBands; ii++)
214        {
215            pCurrentValues[ii]  = 0;
216            pPeakValues[ii]      = 0;
217        }
218        return(LVPSA_OK);
219    }
220    /* Set the reading pointer */
221    if((LVM_INT32)(StatusDelta * pLVPSA_Inst->nBands) > (pLVPSA_Inst->pSpectralDataBufferWritePointer - pLVPSA_Inst->pSpectralDataBufferStart))
222    {
223        pRead = pLVPSA_Inst->pSpectralDataBufferWritePointer + (pLVPSA_Inst->SpectralDataBufferLength - (LVM_UINT32)StatusDelta) * pLVPSA_Inst->nBands;
224    }
225    else
226    {
227        pRead = pLVPSA_Inst->pSpectralDataBufferWritePointer  - StatusDelta * pLVPSA_Inst->nBands;
228    }
229
230
231    /* Read the status buffer and fill the output buffers */
232    for(ii = 0; ii < pLVPSA_Inst->nBands; ii++)
233    {
234        pCurrentValues[ii] = pRead[ii];
235        if(pLVPSA_Inst->pPreviousPeaks[ii] <= pRead[ii])
236        {
237            pLVPSA_Inst->pPreviousPeaks[ii] = pRead[ii];
238        }
239        else if(pLVPSA_Inst->pPreviousPeaks[ii] != 0)
240        {
241            LVM_INT32 temp;
242            /*Re-compute max values for decay */
243            temp = (LVM_INT32)(LVPSA_MAXUNSIGNEDCHAR - pLVPSA_Inst->pPreviousPeaks[ii]);
244            temp = ((temp * LVPSA_MAXLEVELDECAYFACTOR)>>LVPSA_MAXLEVELDECAYSHIFT);
245            /* If the gain has no effect, "help" the value to increase */
246            if(temp == (LVPSA_MAXUNSIGNEDCHAR - pLVPSA_Inst->pPreviousPeaks[ii]))
247            {
248                temp += 1;
249            }
250            /* Saturate */
251            temp = (temp > LVPSA_MAXUNSIGNEDCHAR) ? LVPSA_MAXUNSIGNEDCHAR : temp;
252            /* Store new max level */
253            pLVPSA_Inst->pPreviousPeaks[ii] =  (LVM_UINT8)(LVPSA_MAXUNSIGNEDCHAR - temp);
254        }
255
256        pPeakValues[ii] = pLVPSA_Inst->pPreviousPeaks[ii];
257    }
258
259    return(LVPSA_OK);
260}
261