LVCS_ReverbGenerator.c revision 2c8e5cab3faa6d360e222b7a6c40a80083d021ac
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     $Author: beq07716 $
21     $Revision: 1001 $
22     $Date: 2010-06-28 13:23:02 +0200 (Mon, 28 Jun 2010) $
23
24*************************************************************************************/
25
26/************************************************************************************/
27/*                                                                                  */
28/*  Includes                                                                        */
29/*                                                                                  */
30/************************************************************************************/
31
32#include "LVCS.h"
33#include "LVCS_Private.h"
34#include "LVCS_ReverbGenerator.h"
35#include "LVC_Mixer.h"
36#include "VectorArithmetic.h"
37#include "BIQUAD.h"
38#include "LVCS_Tables.h"
39
40/************************************************************************************/
41/*                                                                                  */
42/* FUNCTION:                LVCS_ReverbGeneratorInit                                */
43/*                                                                                  */
44/* DESCRIPTION:                                                                     */
45/*  Initialises the reverb module. The delay buffer size is configured for the      */
46/*  sample rate and the speaker type.                                               */
47/*                                                                                  */
48/*  The routine may also be called for re-initialisation, i.e. when one of the      */
49/*  control parameters has changed. In this case the delay and filters are only     */
50/*  re-initialised if one of the following two conditions is met:                   */
51/*      -   the sample rate has changed                                             */
52/*      -   the speaker type changes to/from the mobile speaker                     */
53/*                                                                                  */
54/*                                                                                  */
55/* PARAMETERS:                                                                      */
56/*  hInstance               Instance Handle                                         */
57/*  pParams                 Pointer to the inialisation parameters                  */
58/*                                                                                  */
59/* RETURNS:                                                                         */
60/*  LVCS_Success            Always succeeds                                         */
61/*                                                                                  */
62/* NOTES:                                                                           */
63/*  1.  In the delay settings 'Samples' is the number of samples to the end of the  */
64/*      buffer.                                                                     */
65/*  2.  The numerator coefficients of the filter are negated to cause an inversion. */
66/*                                                                                  */
67/************************************************************************************/
68
69LVCS_ReturnStatus_en LVCS_ReverbGeneratorInit(LVCS_Handle_t     hInstance,
70                                              LVCS_Params_t     *pParams)
71{
72
73    LVM_UINT16              Delay;
74    LVM_UINT16              Offset;
75    LVCS_Instance_t         *pInstance = (LVCS_Instance_t  *)hInstance;
76    LVCS_ReverbGenerator_t  *pConfig   = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation;
77    LVCS_Data_t             *pData     = (LVCS_Data_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_DATA].pBaseAddress;
78    LVCS_Coefficient_t      *pCoefficients = (LVCS_Coefficient_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
79    BQ_C16_Coefs_t          Coeffs;
80    const BiquadA012B12CoefsSP_t  *pReverbCoefTable;
81
82    /*
83     * Initialise the delay and filters if:
84     *  - the sample rate has changed
85     *  - the speaker type has changed to or from the mobile speaker
86     */
87    if(pInstance->Params.SampleRate != pParams->SampleRate )      /* Sample rate change test */
88
89    {
90        /*
91         * Setup the delay
92         */
93        Delay = (LVM_UINT16)LVCS_StereoDelayCS[(LVM_UINT16)pParams->SampleRate];
94
95
96        pConfig->DelaySize      = (LVM_INT16)(2 * Delay);
97        pConfig->DelayOffset    = 0;
98        LoadConst_16(0,                                                                 /* Value */
99                     (LVM_INT16 *)&pConfig->StereoSamples[0],                           /* Destination */
100                     (LVM_UINT16)(sizeof(pConfig->StereoSamples)/sizeof(LVM_INT16)));   /* Number of words */
101
102        /*
103         * Setup the filters
104         */
105        Offset = (LVM_UINT16)pParams->SampleRate;
106        pReverbCoefTable = (BiquadA012B12CoefsSP_t*)&LVCS_ReverbCoefTable[0];
107
108        /* Convert incoming coefficients to the required format/ordering */
109        Coeffs.A0 = (LVM_INT16)pReverbCoefTable[Offset].A0;
110        Coeffs.A1 = (LVM_INT16)pReverbCoefTable[Offset].A1;
111        Coeffs.A2 = (LVM_INT16)pReverbCoefTable[Offset].A2;
112        Coeffs.B1 = (LVM_INT16)-pReverbCoefTable[Offset].B1;
113        Coeffs.B2 = (LVM_INT16)-pReverbCoefTable[Offset].B2;
114
115        LoadConst_16(0,                                                                 /* Value */
116                     (LVM_INT16 *)&pData->ReverbBiquadTaps,                             /* Destination */
117                     (LVM_UINT16)(sizeof(pData->ReverbBiquadTaps)/sizeof(LVM_INT16)));  /* Number of words */
118
119        BQ_2I_D16F16Css_TRC_WRA_01_Init(&pCoefficients->ReverbBiquadInstance,
120                                        &pData->ReverbBiquadTaps,
121                                        &Coeffs);
122
123        /* Callbacks */
124        switch(pReverbCoefTable[Offset].Scale)
125        {
126            case 14:
127                pConfig->pBiquadCallBack  = BQ_2I_D16F16C14_TRC_WRA_01;
128                break;
129            case 15:
130                pConfig->pBiquadCallBack  = BQ_2I_D16F16C15_TRC_WRA_01;
131                break;
132        }
133
134
135        /*
136         * Setup the mixer
137         */
138        pConfig->ProcGain = (LVM_UINT16)(HEADPHONEGAINPROC);
139        pConfig->UnprocGain  = (LVM_UINT16)(HEADPHONEGAINUNPROC);
140    }
141
142    if(pInstance->Params.ReverbLevel != pParams->ReverbLevel)
143    {
144        LVM_INT32   ReverbPercentage=83886;                     // 1 Percent Reverb i.e 1/100 in Q 23 format
145        ReverbPercentage*=pParams->ReverbLevel;                 // Actual Reverb Level in Q 23 format
146        pConfig->ReverbLevel=(LVM_INT16)(ReverbPercentage>>8);  // Reverb Level in Q 15 format
147    }
148
149    return(LVCS_SUCCESS);
150}
151
152/************************************************************************************/
153/*                                                                                  */
154/* FUNCTION:                LVCS_Reverb                                             */
155/*                                                                                  */
156/* DESCRIPTION:                                                                     */
157/*  Create reverb using the block of input samples based on the following block     */
158/*  diagram:                                                                        */
159/*                           ________              ________                         */
160/*                          |        |            |        |                        */
161/*     _____     _______    |        |----------->|        |    ______     ___      */
162/*    |     |   |       |   | Stereo |            | L & R  |   |      |   |   |     */
163/* -->| LPF |-->| Delay |-->|   to   |    ____    |   to   |-->| Gain |-->| + |-->  */
164/*  | |_____|   |_______|   | L & R  |   |    |   | Stereo |   |______|   |___|     */
165/*  |                       |        |-->| -1 |-->|        |                |       */
166/*  |                       |________|   |____|   |________|                |       */
167/*  |                                                                       |       */
168/*  |-----------------------------------------------------------------------|       */
169/*                                                                                  */
170/*  The input buffer is broken in to sub-blocks of the size of the delay or less.   */
171/*  This allows the delay buffer to be treated as a circular buffer but processed   */
172/*  as a linear buffer.                                                             */
173/*                                                                                  */
174/*                                                                                  */
175/* PARAMETERS:                                                                      */
176/*  hInstance               Instance Handle                                         */
177/*  pInData                 Pointer to the input buffer                             */
178/*  pOutData                Pointer to the output buffer                            */
179/*  NumSamples              Number of samples to process                            */
180/*                                                                                  */
181/* RETURNS:                                                                         */
182/*  LVCS_Success            Always succeeds                                         */
183/*                                                                                  */
184/* NOTES:                                                                           */
185/*  1.  Process in blocks of samples the size of the delay where possible, if not   */
186/*      the number of samples left over                                             */
187/*  2.  The Gain is combined with the LPF and incorporated in to the coefficients   */
188/*                                                                                  */
189/************************************************************************************/
190
191LVCS_ReturnStatus_en LVCS_ReverbGenerator(LVCS_Handle_t         hInstance,
192                                          const LVM_INT16       *pInData,
193                                          LVM_INT16             *pOutData,
194                                          LVM_UINT16            NumSamples)
195{
196
197    LVCS_Instance_t         *pInstance = (LVCS_Instance_t  *)hInstance;
198    LVCS_ReverbGenerator_t  *pConfig   = (LVCS_ReverbGenerator_t *)&pInstance->Reverberation;
199    LVCS_Coefficient_t      *pCoefficients = (LVCS_Coefficient_t *)pInstance->MemoryTable.Region[LVCS_MEMREGION_PERSISTENT_FAST_COEF].pBaseAddress;
200    LVM_INT16               *pScratch  = (LVM_INT16 *)pInstance->MemoryTable.Region[LVCS_MEMREGION_TEMPORARY_FAST].pBaseAddress;
201
202
203    /*
204     * Copy the data to the output in outplace processing
205     */
206    if (pInData != pOutData)
207    {
208        /*
209         * Reverb not required so just copy the data
210         */
211        Copy_16((LVM_INT16 *)pInData,                                       /* Source */
212                (LVM_INT16 *)pOutData,                                      /* Destination */
213                (LVM_INT16)(2*NumSamples));                                 /* Left and right */
214    }
215
216
217    /*
218     * Check if the reverb is required
219     */
220    if (((pInstance->Params.SpeakerType == LVCS_HEADPHONE) ||           /* Disable when CS4MS in stereo mode */
221         (pInstance->Params.SpeakerType == LVCS_EX_HEADPHONES) ||
222         (pInstance->Params.SourceFormat != LVCS_STEREO))  &&
223        ((pInstance->Params.OperatingMode & LVCS_REVERBSWITCH) !=0))    /* For validation testing */
224    {
225        /********************************************************************************/
226        /*                                                                              */
227        /* Copy the input data to scratch memory and filter it                          */
228        /*                                                                              */
229        /********************************************************************************/
230
231        /*
232         * Copy the input data to the scratch memory
233         */
234        Copy_16((LVM_INT16 *)pInData,                                     /* Source */
235                (LVM_INT16 *)pScratch,                                    /* Destination */
236                (LVM_INT16)(2*NumSamples));                               /* Left and right */
237
238
239        /*
240         * Filter the data
241         */
242        (pConfig->pBiquadCallBack)((Biquad_Instance_t*)&pCoefficients->ReverbBiquadInstance,
243                                   (LVM_INT16 *)pScratch,
244                                   (LVM_INT16 *)pScratch,
245                                   (LVM_INT16)NumSamples);
246
247        Mult3s_16x16( (LVM_INT16 *)pScratch,
248                      pConfig->ReverbLevel,
249                      (LVM_INT16 *)pScratch,
250                      (LVM_INT16)(2*NumSamples));
251
252
253        /*
254         * Apply the delay mix
255         */
256        DelayMix_16x16((LVM_INT16 *)pScratch,
257                       &pConfig->StereoSamples[0],
258                       pConfig->DelaySize,
259                       pOutData,
260                       &pConfig->DelayOffset,
261                       (LVM_INT16)NumSamples);
262
263
264    }
265
266    return(LVCS_SUCCESS);
267}
268
269
270
271
272
273