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 /************************************************************************************/
LVCS_ReverbGeneratorInit(LVCS_Handle_t hInstance,LVCS_Params_t * pParams)60 LVCS_ReturnStatus_en LVCS_ReverbGeneratorInit(LVCS_Handle_t     hInstance,
61                                               LVCS_Params_t     *pParams)
62 {
63 
64     LVM_UINT16              Delay;
65     LVM_UINT16              Offset;
66     LVCS_Instance_t         *pInstance = (LVCS_Instance_t  *)hInstance;
67     LVCS_ReverbGenerator_t  *pConfig   = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation;
68     LVCS_Data_t             *pData;
69     LVCS_Coefficient_t      *pCoefficients;
70     BQ_FLOAT_Coefs_t         Coeffs;
71     const BiquadA012B12CoefsSP_t  *pReverbCoefTable;
72 
73     pData = (LVCS_Data_t *) \
74                  pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
75 
76     pCoefficients = (LVCS_Coefficient_t *) \
77                  pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
78 
79     /*
80      * Initialise the delay and filters if:
81      *  - the sample rate has changed
82      *  - the speaker type has changed to or from the mobile speaker
83      */
84     if(pInstance->Params.SampleRate != pParams->SampleRate )      /* Sample rate change test */
85 
86     {
87         /*
88          * Setup the delay
89          */
90         Delay = (LVM_UINT16)LVCS_StereoDelayCS[(LVM_UINT16)pParams->SampleRate];
91 
92         pConfig->DelaySize      = (LVM_INT16)(2 * Delay);
93         pConfig->DelayOffset    = 0;
94         LoadConst_Float(0,                                            /* Value */
95                         (LVM_FLOAT *)&pConfig->StereoSamples[0],      /* Destination */
96                         /* Number of words */
97                         (LVM_UINT16)(sizeof(pConfig->StereoSamples) / sizeof(LVM_FLOAT)));
98         /*
99          * Setup the filters
100          */
101         Offset = (LVM_UINT16)pParams->SampleRate;
102         pReverbCoefTable = (BiquadA012B12CoefsSP_t*)&LVCS_ReverbCoefTable[0];
103 
104         /* Convert incoming coefficients to the required format/ordering */
105         Coeffs.A0 = (LVM_FLOAT)pReverbCoefTable[Offset].A0;
106         Coeffs.A1 = (LVM_FLOAT)pReverbCoefTable[Offset].A1;
107         Coeffs.A2 = (LVM_FLOAT)pReverbCoefTable[Offset].A2;
108         Coeffs.B1 = (LVM_FLOAT)-pReverbCoefTable[Offset].B1;
109         Coeffs.B2 = (LVM_FLOAT)-pReverbCoefTable[Offset].B2;
110 
111         LoadConst_Float(0,                                 /* Value */
112                         (LVM_FLOAT *)&pData->ReverbBiquadTaps, /* Destination */
113                         /* Number of words */
114                         (LVM_UINT16)(sizeof(pData->ReverbBiquadTaps) / sizeof(LVM_FLOAT)));
115 
116         BQ_2I_D16F16Css_TRC_WRA_01_Init(&pCoefficients->ReverbBiquadInstance,
117                                         &pData->ReverbBiquadTaps,
118                                         &Coeffs);
119 
120         /* Callbacks */
121         switch(pReverbCoefTable[Offset].Scale)
122         {
123             case 14:
124                 pConfig->pBiquadCallBack  = BQ_2I_D16F16C14_TRC_WRA_01;
125                 break;
126             case 15:
127                 pConfig->pBiquadCallBack  = BQ_2I_D16F16C15_TRC_WRA_01;
128                 break;
129         }
130 
131         /*
132          * Setup the mixer
133          */
134         pConfig->ProcGain = (LVM_UINT16)(HEADPHONEGAINPROC);
135         pConfig->UnprocGain  = (LVM_UINT16)(HEADPHONEGAINUNPROC);
136     }
137 
138     if(pInstance->Params.ReverbLevel != pParams->ReverbLevel)
139     {
140         LVM_INT32   ReverbPercentage = 83886;      // 1 Percent Reverb i.e 1/100 in Q 23 format
141         ReverbPercentage *= pParams->ReverbLevel;  // Actual Reverb Level in Q 23 format
142         pConfig->ReverbLevel = ((LVM_FLOAT)(ReverbPercentage>>8)) / 32767.0f;
143     }
144     return(LVCS_SUCCESS);
145 }
146 /************************************************************************************/
147 /*                                                                                  */
148 /* FUNCTION:                LVCS_Reverb                                             */
149 /*                                                                                  */
150 /* DESCRIPTION:                                                                     */
151 /*  Create reverb using the block of input samples based on the following block     */
152 /*  diagram:                                                                        */
153 /*                           ________              ________                         */
154 /*                          |        |            |        |                        */
155 /*     _____     _______    |        |----------->|        |    ______     ___      */
156 /*    |     |   |       |   | Stereo |            | L & R  |   |      |   |   |     */
157 /* -->| LPF |-->| Delay |-->|   to   |    ____    |   to   |-->| Gain |-->| + |-->  */
158 /*  | |_____|   |_______|   | L & R  |   |    |   | Stereo |   |______|   |___|     */
159 /*  |                       |        |-->| -1 |-->|        |                |       */
160 /*  |                       |________|   |____|   |________|                |       */
161 /*  |                                                                       |       */
162 /*  |-----------------------------------------------------------------------|       */
163 /*                                                                                  */
164 /*  The input buffer is broken in to sub-blocks of the size of the delay or less.   */
165 /*  This allows the delay buffer to be treated as a circular buffer but processed   */
166 /*  as a linear buffer.                                                             */
167 /*                                                                                  */
168 /*                                                                                  */
169 /* PARAMETERS:                                                                      */
170 /*  hInstance               Instance Handle                                         */
171 /*  pInData                 Pointer to the input buffer                             */
172 /*  pOutData                Pointer to the output buffer                            */
173 /*  NumSamples              Number of samples to process                            */
174 /*                                                                                  */
175 /* RETURNS:                                                                         */
176 /*  LVCS_Success            Always succeeds                                         */
177 /*                                                                                  */
178 /* NOTES:                                                                           */
179 /*  1.  Process in blocks of samples the size of the delay where possible, if not   */
180 /*      the number of samples left over                                             */
181 /*  2.  The Gain is combined with the LPF and incorporated in to the coefficients   */
182 /*                                                                                  */
183 /************************************************************************************/
LVCS_ReverbGenerator(LVCS_Handle_t hInstance,const LVM_FLOAT * pInData,LVM_FLOAT * pOutData,LVM_UINT16 NumSamples)184 LVCS_ReturnStatus_en LVCS_ReverbGenerator(LVCS_Handle_t         hInstance,
185                                           const LVM_FLOAT       *pInData,
186                                           LVM_FLOAT             *pOutData,
187                                           LVM_UINT16            NumSamples)
188 {
189 
190     LVCS_Instance_t         *pInstance = (LVCS_Instance_t  *)hInstance;
191     LVCS_ReverbGenerator_t  *pConfig   = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation;
192     LVCS_Coefficient_t      *pCoefficients;
193     LVM_FLOAT               *pScratch;
194 
195     pCoefficients = (LVCS_Coefficient_t *)\
196                    pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
197 
198     pScratch  = (LVM_FLOAT *)\
199                     pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
200 
201     /*
202      * Copy the data to the output in outplace processing
203      */
204     if (pInData != pOutData)
205     {
206         /*
207          * Reverb not required so just copy the data
208          */
209         Copy_Float((LVM_FLOAT *)pInData,                                       /* Source */
210                    (LVM_FLOAT *)pOutData,                                      /* Destination */
211                    (LVM_INT16)(2 * NumSamples));                                 /* Left and right */
212     }
213 
214     /*
215      * Check if the reverb is required
216      */
217     /* Disable when CS4MS in stereo mode */
218     if ((((LVCS_OutputDevice_en)pInstance->Params.SpeakerType == LVCS_HEADPHONE) || \
219          (pInstance->Params.SpeakerType == LVCS_EX_HEADPHONES) ||
220          (pInstance->Params.SourceFormat != LVCS_STEREO))  &&
221                                     /* For validation testing */
222         ((pInstance->Params.OperatingMode & LVCS_REVERBSWITCH) !=0))
223     {
224         /********************************************************************************/
225         /*                                                                              */
226         /* Copy the input data to scratch memory and filter it                          */
227         /*                                                                              */
228         /********************************************************************************/
229 
230         /*
231          * Copy the input data to the scratch memory
232          */
233         Copy_Float((LVM_FLOAT *)pInData,                                     /* Source */
234                    (LVM_FLOAT *)pScratch,                                    /* Destination */
235                    (LVM_INT16)(2 * NumSamples));                               /* Left and right */
236 
237         /*
238          * Filter the data
239          */
240         (pConfig->pBiquadCallBack)((Biquad_FLOAT_Instance_t*)&pCoefficients->ReverbBiquadInstance,
241                                    (LVM_FLOAT *)pScratch,
242                                    (LVM_FLOAT *)pScratch,
243                                    (LVM_INT16)NumSamples);
244 
245         Mult3s_Float( (LVM_FLOAT *)pScratch,
246                       pConfig->ReverbLevel,
247                       (LVM_FLOAT *)pScratch,
248                       (LVM_INT16)(2 * NumSamples));
249 
250         /*
251          * Apply the delay mix
252          */
253         DelayMix_Float((LVM_FLOAT *)pScratch,
254                        &pConfig->StereoSamples[0],
255                        pConfig->DelaySize,
256                        pOutData,
257                        &pConfig->DelayOffset,
258                        (LVM_INT16)NumSamples);
259 
260     }
261 
262     return(LVCS_SUCCESS);
263 }
264