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
61LVCS_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
152LVCS_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
274LVCS_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
358LVCS_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