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 <string.h> // memset
25 #include "LVDBE.h"
26 #include "LVDBE_Private.h"
27 #include "VectorArithmetic.h"
28 #include "AGC.h"
29 #include "LVDBE_Coeffs.h"               /* Filter coefficients */
30 #include <log/log.h>
31 
32 /********************************************************************************************/
33 /*                                                                                          */
34 /* FUNCTION:                 LVDBE_Process                                                  */
35 /*                                                                                          */
36 /* DESCRIPTION:                                                                             */
37 /*  Process function for the Bass Enhancement module.                                       */
38 /*                                                                                          */
39 /*  Data can be processed in two formats, stereo or mono-in-stereo. Data in mono            */
40 /*  format is not supported, the calling routine must convert the mono stream to            */
41 /*  mono-in-stereo.                                                                         */
42 /*                                                        ___________                       */
43 /*       ________                                        |           |    ________          */
44 /*      |        |    _____   |------------------------->|           |   |        |         */
45 /*      | 16-bit |   |     |  |    ________              |           |   | 32-bit |         */
46 /* -+-->|   to   |-->| HPF |--|   |        |    _____    | AGC Mixer |-->|   to   |--|      */
47 /*  |   | 32-bit |   |_____|  |   | Stereo |   |     |   |           |   | 16-bit |  |      */
48 /*  |   |________|            |-->|   to   |-->| BPF |-->|           |   |________|  0      */
49 /*  |                             |  Mono  |   |_____|   |___________|                \-->  */
50 /*  |                             |________|                                                */
51 /*  |                                                     _________                  0      */
52 /*  |                                                    |         |                 |      */
53 /*  |----------------------------------------------------| Volume  |-----------------|      */
54 /*                                                       | Control |                        */
55 /*                                                       |_________|                        */
56 /*                                                                                          */
57 /* PARAMETERS:                                                                              */
58 /*  hInstance                 Instance handle                                               */
59 /*  pInData                  Pointer to the input data                                      */
60 /*  pOutData                 Pointer to the output data                                     */
61 /*  NumSamples                 Number of samples in the input buffer                        */
62 /*                                                                                          */
63 /* RETURNS:                                                                                 */
64 /*  LVDBE_SUCCESS            Succeeded                                                      */
65 /*    LVDBE_TOOMANYSAMPLES    NumSamples was larger than the maximum block size             */
66 /*                                                                                          */
67 /* NOTES:                                                                                   */
68 /*  1. The input and output data must be 32-bit format. The input is scaled by a shift      */
69 /*     when converting from 16-bit format, this scaling allows for internal headroom in the */
70 /*     bass enhancement algorithm.                                                          */
71 /*  2. For a 16-bit implementation the converstion to 32-bit is removed and replaced with   */
72 /*     the headroom loss. This headroom loss is compensated in the volume control so the    */
73 /*     overall end to end gain is odB.                                                      */
74 /*                                                                                          */
75 /********************************************************************************************/
LVDBE_Process(LVDBE_Handle_t hInstance,const LVM_FLOAT * pInData,LVM_FLOAT * pOutData,const LVM_UINT16 NrFrames)76 LVDBE_ReturnStatus_en LVDBE_Process(LVDBE_Handle_t hInstance,
77     const LVM_FLOAT *pInData,
78     LVM_FLOAT *pOutData,
79     const LVM_UINT16 NrFrames) // updated to use samples = frames * channels.
80 {
81   LVDBE_Instance_t *pInstance =(LVDBE_Instance_t *)hInstance;
82 
83   /*Extract number of Channels info*/
84 #ifdef SUPPORT_MC
85   // Mono passed in as stereo
86   const LVM_INT32 NrChannels = pInstance->Params.NrChannels == 1
87       ? 2 : pInstance->Params.NrChannels;
88 #else
89   const LVM_INT32 NrChannels = 2; // FCC_2
90 #endif
91   const LVM_INT32 NrSamples = NrChannels * NrFrames;
92 
93   /* Space to store DBE path computation */
94   LVM_FLOAT * const pScratch =
95           (LVM_FLOAT *)pInstance->MemoryTable.Region[LVDBE_MEMREGION_SCRATCH].pBaseAddress;
96 
97   /*
98    * Scratch for Mono path starts at offset of
99    * NrSamples float values from pScratch.
100    */
101   LVM_FLOAT * const pMono = pScratch + NrSamples;
102 
103   /*
104    * TRICKY: pMono is used and discarded by the DBE path.
105    *         so it is available for use for the pScratchVol
106    *         path which is computed afterwards.
107    *
108    * Space to store Volume Control path computation.
109    * This is identical to pMono (see TRICKY comment).
110    */
111   LVM_FLOAT * const pScratchVol = pMono;
112 
113   /*
114    * Check the number of frames is not too large
115    */
116   if (NrFrames > pInstance->Capabilities.MaxBlockSize)
117   {
118     return LVDBE_TOOMANYSAMPLES;
119   }
120 
121   /*
122    * Check if the algorithm is enabled
123    */
124   /* DBE path is processed when DBE is ON or during On/Off transitions */
125   if ((pInstance->Params.OperatingMode == LVDBE_ON)||
126       (LVC_Mixer_GetCurrent(&pInstance->pData->BypassMixer.MixerStream[0])
127           !=LVC_Mixer_GetTarget(&pInstance->pData->BypassMixer.MixerStream[0])))
128   {
129     // make copy of input data
130     Copy_Float(pInData,
131         pScratch,
132         (LVM_INT16)NrSamples);
133 
134     /*
135      * Apply the high pass filter if selected
136      */
137     if (pInstance->Params.HPFSelect == LVDBE_HPF_ON)
138     {
139 #ifdef SUPPORT_MC
140       BQ_MC_D32F32C30_TRC_WRA_01(&pInstance->pCoef->HPFInstance, /* Filter instance      */
141           pScratch, /* Source               */
142           pScratch, /* Destination          */
143           (LVM_INT16)NrFrames,
144           (LVM_INT16)NrChannels);
145 #else
146       BQ_2I_D32F32C30_TRC_WRA_01(&pInstance->pCoef->HPFInstance,/* Filter instance      */
147           pScratch, /* Source               */
148           pScratch, /* Destination          */
149           (LVM_INT16)NrFrames);
150 #endif
151     }
152 
153     /*
154      * Create the mono stream
155      */
156 #ifdef SUPPORT_MC
157     FromMcToMono_Float(pScratch, /* Source */
158         pMono, /* Mono destination */
159         (LVM_INT16)NrFrames,  /* Number of frames */
160         (LVM_INT16)NrChannels);
161 #else
162     From2iToMono_Float(pScratch, /* Stereo source         */
163         pMono, /* Mono destination      */
164         (LVM_INT16)NrFrames);
165 #endif
166 
167     /*
168      * Apply the band pass filter
169      */
170     BP_1I_D32F32C30_TRC_WRA_02(&pInstance->pCoef->BPFInstance, /* Filter instance       */
171         pMono, /* Source                */
172         pMono, /* Destination           */
173         (LVM_INT16)NrFrames);
174 
175     /*
176      * Apply the AGC and mix
177      */
178 #ifdef SUPPORT_MC
179     AGC_MIX_VOL_Mc1Mon_D32_WRA(&pInstance->pData->AGCInstance, /* Instance pointer      */
180         pScratch, /* Source         */
181         pMono, /* Mono band pass source */
182         pScratch, /* Destination    */
183         NrFrames, /* Number of frames     */
184         NrChannels); /* Number of channels     */
185 #else
186     AGC_MIX_VOL_2St1Mon_D32_WRA(&pInstance->pData->AGCInstance, /* Instance pointer      */
187         pScratch, /* Stereo source         */
188         pMono, /* Mono band pass source */
189         pScratch, /* Stereo destination    */
190         NrFrames);
191 #endif
192 
193     for (LVM_INT32 ii = 0; ii < NrSamples; ++ii) {
194       //TODO: replace with existing clamping function
195       if (pScratch[ii] < -1.0) {
196         pScratch[ii] = -1.0;
197       } else if (pScratch[ii] > 1.0) {
198         pScratch[ii] = 1.0;
199       }
200     }
201   } else {
202     // clear DBE processed path
203     memset(pScratch, 0, sizeof(*pScratch) * NrSamples);
204   }
205 
206   /* Bypass Volume path is processed when DBE is OFF or during On/Off transitions */
207   if ((pInstance->Params.OperatingMode == LVDBE_OFF)||
208       (LVC_Mixer_GetCurrent(&pInstance->pData->BypassMixer.MixerStream[1])
209           !=LVC_Mixer_GetTarget(&pInstance->pData->BypassMixer.MixerStream[1])))
210   {
211 
212     /*
213      * The algorithm is disabled but volume management is required to compensate for
214      * headroom and volume (if enabled)
215      */
216 #ifdef SUPPORT_MC
217     LVC_MixSoft_Mc_D16C31_SAT(&pInstance->pData->BypassVolume,
218         pInData,
219         pScratchVol,
220         (LVM_INT16)NrFrames,
221         (LVM_INT16)NrChannels);
222 #else
223     LVC_MixSoft_1St_D16C31_SAT(&pInstance->pData->BypassVolume,
224         pInData,
225         pScratchVol,
226         (LVM_INT16)NrSamples); /* Left and right, really # samples */
227 #endif
228   } else {
229     // clear bypass volume path
230     memset(pScratchVol, 0, sizeof(*pScratchVol) * NrSamples);
231   }
232 
233   /*
234    * Mix DBE processed path and bypass volume path
235    */
236 #ifdef SUPPORT_MC
237   LVC_MixSoft_2Mc_D16C31_SAT(&pInstance->pData->BypassMixer,
238       pScratch,
239       pScratchVol,
240       pOutData,
241       (LVM_INT16)NrFrames,
242       (LVM_INT16)NrChannels);
243 #else
244   LVC_MixSoft_2St_D16C31_SAT(&pInstance->pData->BypassMixer,
245       pScratch,
246       pScratchVol,
247       pOutData,
248       (LVM_INT16)NrSamples);
249 #endif
250   return LVDBE_SUCCESS;
251 }
252