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