• 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 /************************************************************************************/
19 /*                                                                                  */
20 /*  Includes                                                                        */
21 /*                                                                                  */
22 /************************************************************************************/
23 
24 #include "LVCS.h"
25 #include "LVCS_Private.h"
26 #include "LVCS_ReverbGenerator.h"
27 #include "LVC_Mixer.h"
28 #include "VectorArithmetic.h"
29 #include "BIQUAD.h"
30 #include "LVCS_Tables.h"
31 
32 /************************************************************************************/
33 /*                                                                                  */
34 /* FUNCTION:                LVCS_ReverbGeneratorInit                                */
35 /*                                                                                  */
36 /* DESCRIPTION:                                                                     */
37 /*  Initialises the reverb module. The delay buffer size is configured for the      */
38 /*  sample rate and the speaker type.                                               */
39 /*                                                                                  */
40 /*  The routine may also be called for re-initialisation, i.e. when one of the      */
41 /*  control parameters has changed. In this case the delay and filters are only     */
42 /*  re-initialised if one of the following two conditions is met:                   */
43 /*      -   the sample rate has changed                                             */
44 /*      -   the speaker type changes to/from the mobile speaker                     */
45 /*                                                                                  */
46 /*                                                                                  */
47 /* PARAMETERS:                                                                      */
48 /*  hInstance               Instance Handle                                         */
49 /*  pParams                 Pointer to the inialisation parameters                  */
50 /*                                                                                  */
51 /* RETURNS:                                                                         */
52 /*  LVCS_Success            Always succeeds                                         */
53 /*                                                                                  */
54 /* NOTES:                                                                           */
55 /*  1.  In the delay settings 'Samples' is the number of samples to the end of the  */
56 /*      buffer.                                                                     */
57 /*  2.  The numerator coefficients of the filter are negated to cause an inversion. */
58 /*                                                                                  */
59 /************************************************************************************/
60 #ifdef BUILD_FLOAT
LVCS_ReverbGeneratorInit(LVCS_Handle_t hInstance,LVCS_Params_t * pParams)61 LVCS_ReturnStatus_en LVCS_ReverbGeneratorInit(LVCS_Handle_t     hInstance,
62                                               LVCS_Params_t     *pParams)
63 {
64 
65     LVM_UINT16              Delay;
66     LVM_UINT16              Offset;
67     LVCS_Instance_t         *pInstance = (LVCS_Instance_t  *)hInstance;
68     LVCS_ReverbGenerator_t  *pConfig   = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation;
69     LVCS_Data_t             *pData;
70     LVCS_Coefficient_t      *pCoefficients;
71     BQ_FLOAT_Coefs_t         Coeffs;
72     const BiquadA012B12CoefsSP_t  *pReverbCoefTable;
73 
74 
75     pData = (LVCS_Data_t *) \
76                  pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
77 
78     pCoefficients = (LVCS_Coefficient_t *) \
79                  pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
80 
81     /*
82      * Initialise the delay and filters if:
83      *  - the sample rate has changed
84      *  - the speaker type has changed to or from the mobile speaker
85      */
86     if(pInstance->Params.SampleRate != pParams->SampleRate )      /* Sample rate change test */
87 
88     {
89         /*
90          * Setup the delay
91          */
92         Delay = (LVM_UINT16)LVCS_StereoDelayCS[(LVM_UINT16)pParams->SampleRate];
93 
94 
95         pConfig->DelaySize      = (LVM_INT16)(2 * Delay);
96         pConfig->DelayOffset    = 0;
97         LoadConst_Float(0,                                            /* Value */
98                         (LVM_FLOAT *)&pConfig->StereoSamples[0],      /* Destination */
99                         /* Number of words */
100                         (LVM_UINT16)(sizeof(pConfig->StereoSamples) / sizeof(LVM_FLOAT)));
101         /*
102          * Setup the filters
103          */
104         Offset = (LVM_UINT16)pParams->SampleRate;
105         pReverbCoefTable = (BiquadA012B12CoefsSP_t*)&LVCS_ReverbCoefTable[0];
106 
107         /* Convert incoming coefficients to the required format/ordering */
108         Coeffs.A0 = (LVM_FLOAT)pReverbCoefTable[Offset].A0;
109         Coeffs.A1 = (LVM_FLOAT)pReverbCoefTable[Offset].A1;
110         Coeffs.A2 = (LVM_FLOAT)pReverbCoefTable[Offset].A2;
111         Coeffs.B1 = (LVM_FLOAT)-pReverbCoefTable[Offset].B1;
112         Coeffs.B2 = (LVM_FLOAT)-pReverbCoefTable[Offset].B2;
113 
114         LoadConst_Float(0,                                 /* Value */
115                         (void *)&pData->ReverbBiquadTaps,  /* Destination Cast to void:
116                                                              no dereferencing in function*/
117                         /* Number of words */
118                         (LVM_UINT16)(sizeof(pData->ReverbBiquadTaps) / sizeof(LVM_FLOAT)));
119 
120         BQ_2I_D16F16Css_TRC_WRA_01_Init(&pCoefficients->ReverbBiquadInstance,
121                                         &pData->ReverbBiquadTaps,
122                                         &Coeffs);
123 
124         /* Callbacks */
125         switch(pReverbCoefTable[Offset].Scale)
126         {
127             case 14:
128                 pConfig->pBiquadCallBack  = BQ_2I_D16F16C14_TRC_WRA_01;
129                 break;
130             case 15:
131                 pConfig->pBiquadCallBack  = BQ_2I_D16F16C15_TRC_WRA_01;
132                 break;
133         }
134 
135 
136         /*
137          * Setup the mixer
138          */
139         pConfig->ProcGain = (LVM_UINT16)(HEADPHONEGAINPROC);
140         pConfig->UnprocGain  = (LVM_UINT16)(HEADPHONEGAINUNPROC);
141     }
142 
143     if(pInstance->Params.ReverbLevel != pParams->ReverbLevel)
144     {
145         LVM_INT32   ReverbPercentage = 83886;      // 1 Percent Reverb i.e 1/100 in Q 23 format
146         ReverbPercentage *= pParams->ReverbLevel;  // Actual Reverb Level in Q 23 format
147         pConfig->ReverbLevel = ((LVM_FLOAT)(ReverbPercentage>>8)) / 32767.0f;
148     }
149     return(LVCS_SUCCESS);
150 }
151 #else
LVCS_ReverbGeneratorInit(LVCS_Handle_t hInstance,LVCS_Params_t * pParams)152 LVCS_ReturnStatus_en LVCS_ReverbGeneratorInit(LVCS_Handle_t     hInstance,
153                                               LVCS_Params_t     *pParams)
154 {
155 
156     LVM_UINT16              Delay;
157     LVM_UINT16              Offset;
158     LVCS_Instance_t         *pInstance = (LVCS_Instance_t  *)hInstance;
159     LVCS_ReverbGenerator_t  *pConfig   = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation;
160     LVCS_Data_t             *pData     = (LVCS_Data_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
161     LVCS_Coefficient_t      *pCoefficients = (LVCS_Coefficient_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
162     BQ_C16_Coefs_t          Coeffs;
163     const BiquadA012B12CoefsSP_t  *pReverbCoefTable;
164 
165     /*
166      * Initialise the delay and filters if:
167      *  - the sample rate has changed
168      *  - the speaker type has changed to or from the mobile speaker
169      */
170     if(pInstance->Params.SampleRate != pParams->SampleRate )      /* Sample rate change test */
171 
172     {
173         /*
174          * Setup the delay
175          */
176         Delay = (LVM_UINT16)LVCS_StereoDelayCS[(LVM_UINT16)pParams->SampleRate];
177 
178 
179         pConfig->DelaySize      = (LVM_INT16)(2 * Delay);
180         pConfig->DelayOffset    = 0;
181         LoadConst_16(0,                                                                 /* Value */
182                      (LVM_INT16 *)&pConfig->StereoSamples[0],                           /* Destination */
183                      (LVM_UINT16)(sizeof(pConfig->StereoSamples)/sizeof(LVM_INT16)));   /* Number of words */
184 
185         /*
186          * Setup the filters
187          */
188         Offset = (LVM_UINT16)pParams->SampleRate;
189         pReverbCoefTable = (BiquadA012B12CoefsSP_t*)&LVCS_ReverbCoefTable[0];
190 
191         /* Convert incoming coefficients to the required format/ordering */
192         Coeffs.A0 = (LVM_INT16)pReverbCoefTable[Offset].A0;
193         Coeffs.A1 = (LVM_INT16)pReverbCoefTable[Offset].A1;
194         Coeffs.A2 = (LVM_INT16)pReverbCoefTable[Offset].A2;
195         Coeffs.B1 = (LVM_INT16)-pReverbCoefTable[Offset].B1;
196         Coeffs.B2 = (LVM_INT16)-pReverbCoefTable[Offset].B2;
197 
198         LoadConst_16(0,                                                                 /* Value */
199                      (void *)&pData->ReverbBiquadTaps,                             /* Destination Cast to void: no dereferencing in function*/
200                      (LVM_UINT16)(sizeof(pData->ReverbBiquadTaps)/sizeof(LVM_INT16)));  /* Number of words */
201 
202         BQ_2I_D16F16Css_TRC_WRA_01_Init(&pCoefficients->ReverbBiquadInstance,
203                                         &pData->ReverbBiquadTaps,
204                                         &Coeffs);
205 
206         /* Callbacks */
207         switch(pReverbCoefTable[Offset].Scale)
208         {
209             case 14:
210                 pConfig->pBiquadCallBack  = BQ_2I_D16F16C14_TRC_WRA_01;
211                 break;
212             case 15:
213                 pConfig->pBiquadCallBack  = BQ_2I_D16F16C15_TRC_WRA_01;
214                 break;
215         }
216 
217 
218         /*
219          * Setup the mixer
220          */
221         pConfig->ProcGain = (LVM_UINT16)(HEADPHONEGAINPROC);
222         pConfig->UnprocGain  = (LVM_UINT16)(HEADPHONEGAINUNPROC);
223     }
224 
225     if(pInstance->Params.ReverbLevel != pParams->ReverbLevel)
226     {
227         LVM_INT32   ReverbPercentage=83886;                     // 1 Percent Reverb i.e 1/100 in Q 23 format
228         ReverbPercentage*=pParams->ReverbLevel;                 // Actual Reverb Level in Q 23 format
229         pConfig->ReverbLevel=(LVM_INT16)(ReverbPercentage>>8);  // Reverb Level in Q 15 format
230     }
231 
232     return(LVCS_SUCCESS);
233 }
234 #endif
235 /************************************************************************************/
236 /*                                                                                  */
237 /* FUNCTION:                LVCS_Reverb                                             */
238 /*                                                                                  */
239 /* DESCRIPTION:                                                                     */
240 /*  Create reverb using the block of input samples based on the following block     */
241 /*  diagram:                                                                        */
242 /*                           ________              ________                         */
243 /*                          |        |            |        |                        */
244 /*     _____     _______    |        |----------->|        |    ______     ___      */
245 /*    |     |   |       |   | Stereo |            | L & R  |   |      |   |   |     */
246 /* -->| LPF |-->| Delay |-->|   to   |    ____    |   to   |-->| Gain |-->| + |-->  */
247 /*  | |_____|   |_______|   | L & R  |   |    |   | Stereo |   |______|   |___|     */
248 /*  |                       |        |-->| -1 |-->|        |                |       */
249 /*  |                       |________|   |____|   |________|                |       */
250 /*  |                                                                       |       */
251 /*  |-----------------------------------------------------------------------|       */
252 /*                                                                                  */
253 /*  The input buffer is broken in to sub-blocks of the size of the delay or less.   */
254 /*  This allows the delay buffer to be treated as a circular buffer but processed   */
255 /*  as a linear buffer.                                                             */
256 /*                                                                                  */
257 /*                                                                                  */
258 /* PARAMETERS:                                                                      */
259 /*  hInstance               Instance Handle                                         */
260 /*  pInData                 Pointer to the input buffer                             */
261 /*  pOutData                Pointer to the output buffer                            */
262 /*  NumSamples              Number of samples to process                            */
263 /*                                                                                  */
264 /* RETURNS:                                                                         */
265 /*  LVCS_Success            Always succeeds                                         */
266 /*                                                                                  */
267 /* NOTES:                                                                           */
268 /*  1.  Process in blocks of samples the size of the delay where possible, if not   */
269 /*      the number of samples left over                                             */
270 /*  2.  The Gain is combined with the LPF and incorporated in to the coefficients   */
271 /*                                                                                  */
272 /************************************************************************************/
273 #ifdef BUILD_FLOAT
LVCS_ReverbGenerator(LVCS_Handle_t hInstance,const LVM_FLOAT * pInData,LVM_FLOAT * pOutData,LVM_UINT16 NumSamples)274 LVCS_ReturnStatus_en LVCS_ReverbGenerator(LVCS_Handle_t         hInstance,
275                                           const LVM_FLOAT       *pInData,
276                                           LVM_FLOAT             *pOutData,
277                                           LVM_UINT16            NumSamples)
278 {
279 
280     LVCS_Instance_t         *pInstance = (LVCS_Instance_t  *)hInstance;
281     LVCS_ReverbGenerator_t  *pConfig   = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation;
282     LVCS_Coefficient_t      *pCoefficients;
283     LVM_FLOAT               *pScratch;
284 
285     pCoefficients = (LVCS_Coefficient_t *)\
286                    pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
287 
288     pScratch  = (LVM_FLOAT *)\
289                     pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
290 
291     /*
292      * Copy the data to the output in outplace processing
293      */
294     if (pInData != pOutData)
295     {
296         /*
297          * Reverb not required so just copy the data
298          */
299         Copy_Float((LVM_FLOAT *)pInData,                                       /* Source */
300                    (LVM_FLOAT *)pOutData,                                      /* Destination */
301                    (LVM_INT16)(2 * NumSamples));                                 /* Left and right */
302     }
303 
304 
305     /*
306      * Check if the reverb is required
307      */
308     /* Disable when CS4MS in stereo mode */
309     if (((pInstance->Params.SpeakerType == LVCS_HEADPHONE) || \
310          (pInstance->Params.SpeakerType == LVCS_EX_HEADPHONES) ||
311          (pInstance->Params.SourceFormat != LVCS_STEREO))  &&
312                                     /* For validation testing */
313         ((pInstance->Params.OperatingMode & LVCS_REVERBSWITCH) !=0))
314     {
315         /********************************************************************************/
316         /*                                                                              */
317         /* Copy the input data to scratch memory and filter it                          */
318         /*                                                                              */
319         /********************************************************************************/
320 
321         /*
322          * Copy the input data to the scratch memory
323          */
324         Copy_Float((LVM_FLOAT *)pInData,                                     /* Source */
325                    (LVM_FLOAT *)pScratch,                                    /* Destination */
326                    (LVM_INT16)(2 * NumSamples));                               /* Left and right */
327 
328         /*
329          * Filter the data
330          */
331         (pConfig->pBiquadCallBack)((Biquad_FLOAT_Instance_t*)&pCoefficients->ReverbBiquadInstance,
332                                    (LVM_FLOAT *)pScratch,
333                                    (LVM_FLOAT *)pScratch,
334                                    (LVM_INT16)NumSamples);
335 
336         Mult3s_Float( (LVM_FLOAT *)pScratch,
337                       pConfig->ReverbLevel,
338                       (LVM_FLOAT *)pScratch,
339                       (LVM_INT16)(2 * NumSamples));
340 
341 
342         /*
343          * Apply the delay mix
344          */
345         DelayMix_Float((LVM_FLOAT *)pScratch,
346                        &pConfig->StereoSamples[0],
347                        pConfig->DelaySize,
348                        pOutData,
349                        &pConfig->DelayOffset,
350                        (LVM_INT16)NumSamples);
351 
352 
353     }
354 
355     return(LVCS_SUCCESS);
356 }
357 #else
LVCS_ReverbGenerator(LVCS_Handle_t hInstance,const LVM_INT16 * pInData,LVM_INT16 * pOutData,LVM_UINT16 NumSamples)358 LVCS_ReturnStatus_en LVCS_ReverbGenerator(LVCS_Handle_t         hInstance,
359                                           const LVM_INT16       *pInData,
360                                           LVM_INT16             *pOutData,
361                                           LVM_UINT16            NumSamples)
362 {
363 
364     LVCS_Instance_t         *pInstance = (LVCS_Instance_t  *)hInstance;
365     LVCS_ReverbGenerator_t  *pConfig   = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation;
366     LVCS_Coefficient_t      *pCoefficients = (LVCS_Coefficient_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
367     LVM_INT16               *pScratch  = (LVM_INT16 *)pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
368 
369 
370     /*
371      * Copy the data to the output in outplace processing
372      */
373     if (pInData != pOutData)
374     {
375         /*
376          * Reverb not required so just copy the data
377          */
378         Copy_16((LVM_INT16 *)pInData,                                       /* Source */
379                 (LVM_INT16 *)pOutData,                                      /* Destination */
380                 (LVM_INT16)(2*NumSamples));                                 /* Left and right */
381     }
382 
383 
384     /*
385      * Check if the reverb is required
386      */
387     if (((pInstance->Params.SpeakerType == LVCS_HEADPHONE) ||           /* Disable when CS4MS in stereo mode */
388          (pInstance->Params.SpeakerType == LVCS_EX_HEADPHONES) ||
389          (pInstance->Params.SourceFormat != LVCS_STEREO))  &&
390         ((pInstance->Params.OperatingMode & LVCS_REVERBSWITCH) !=0))    /* For validation testing */
391     {
392         /********************************************************************************/
393         /*                                                                              */
394         /* Copy the input data to scratch memory and filter it                          */
395         /*                                                                              */
396         /********************************************************************************/
397 
398         /*
399          * Copy the input data to the scratch memory
400          */
401         Copy_16((LVM_INT16 *)pInData,                                     /* Source */
402                 (LVM_INT16 *)pScratch,                                    /* Destination */
403                 (LVM_INT16)(2*NumSamples));                               /* Left and right */
404 
405 
406         /*
407          * Filter the data
408          */
409         (pConfig->pBiquadCallBack)((Biquad_Instance_t*)&pCoefficients->ReverbBiquadInstance,
410                                    (LVM_INT16 *)pScratch,
411                                    (LVM_INT16 *)pScratch,
412                                    (LVM_INT16)NumSamples);
413 
414         Mult3s_16x16( (LVM_INT16 *)pScratch,
415                       pConfig->ReverbLevel,
416                       (LVM_INT16 *)pScratch,
417                       (LVM_INT16)(2*NumSamples));
418 
419 
420         /*
421          * Apply the delay mix
422          */
423         DelayMix_16x16((LVM_INT16 *)pScratch,
424                        &pConfig->StereoSamples[0],
425                        pConfig->DelaySize,
426                        pOutData,
427                        &pConfig->DelayOffset,
428                        (LVM_INT16)NumSamples);
429 
430 
431     }
432 
433     return(LVCS_SUCCESS);
434 }
435 #endif
436