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