• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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