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