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