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 #include <system/audio.h>
24 #include <stdlib.h>
25 #include "LVCS.h"
26 #include "LVCS_Private.h"
27 #include "LVCS_ReverbGenerator.h"
28 #include "LVC_Mixer.h"
29 #include "VectorArithmetic.h"
30 #include "BIQUAD.h"
31 #include "LVCS_Tables.h"
32
33 /************************************************************************************/
34 /* */
35 /* FUNCTION: LVCS_ReverbGeneratorInit */
36 /* */
37 /* DESCRIPTION: */
38 /* Initialises the reverb module. The delay buffer size is configured for the */
39 /* sample rate and the speaker type. */
40 /* */
41 /* The routine may also be called for re-initialisation, i.e. when one of the */
42 /* control parameters has changed. In this case the delay and filters are only */
43 /* re-initialised if one of the following two conditions is met: */
44 /* - the sample rate has changed */
45 /* - the speaker type changes to/from the mobile speaker */
46 /* */
47 /* */
48 /* PARAMETERS: */
49 /* hInstance Instance Handle */
50 /* pParams Pointer to the inialisation parameters */
51 /* */
52 /* RETURNS: */
53 /* LVCS_Success Always succeeds */
54 /* */
55 /* NOTES: */
56 /* 1. In the delay settings 'Samples' is the number of samples to the end of the */
57 /* buffer. */
58 /* 2. The numerator coefficients of the filter are negated to cause an inversion. */
59 /* */
60 /************************************************************************************/
LVCS_ReverbGeneratorInit(LVCS_Handle_t hInstance,LVCS_Params_t * pParams)61 LVCS_ReturnStatus_en LVCS_ReverbGeneratorInit(LVCS_Handle_t hInstance, LVCS_Params_t* pParams) {
62 LVM_UINT16 Delay;
63 LVM_UINT16 Offset;
64 LVCS_Instance_t* pInstance = (LVCS_Instance_t*)hInstance;
65 LVCS_ReverbGenerator_t* pConfig = (LVCS_ReverbGenerator_t*)&pInstance->Reverberation;
66 const BiquadA012B12CoefsSP_t* pReverbCoefTable;
67
68 /*
69 * Initialise the delay and filters if:
70 * - the sample rate has changed
71 * - the speaker type has changed to or from the mobile speaker
72 */
73 if (pInstance->Params.SampleRate != pParams->SampleRate) /* Sample rate change test */
74
75 {
76 /*
77 * Setup the delay
78 */
79 Delay = (LVM_UINT16)LVCS_StereoDelayCS[(LVM_UINT16)pParams->SampleRate];
80
81 pConfig->DelaySize =
82 (pParams->NrChannels == FCC_1) ? (LVM_INT16)Delay : (LVM_INT16)(FCC_2 * Delay);
83 pConfig->DelayOffset = 0;
84 memset(pConfig->StereoSamples, 0, sizeof(pConfig->StereoSamples));
85 /*
86 * Setup the filters
87 */
88 Offset = (LVM_UINT16)pParams->SampleRate;
89 pReverbCoefTable = (BiquadA012B12CoefsSP_t*)&LVCS_ReverbCoefTable[0];
90
91 std::array<LVM_FLOAT, android::audio_utils::kBiquadNumCoefs> coefs = {
92 pReverbCoefTable[Offset].A0, pReverbCoefTable[Offset].A1,
93 pReverbCoefTable[Offset].A2, pReverbCoefTable[Offset].B1,
94 pReverbCoefTable[Offset].B2};
95 pInstance->pRevBiquad.reset(new android::audio_utils::BiquadFilter<LVM_FLOAT>(
96 (pParams->NrChannels == FCC_1) ? FCC_1 : FCC_2, coefs));
97
98 /*
99 * Setup the mixer
100 */
101 pConfig->ProcGain = (LVM_UINT16)(HEADPHONEGAINPROC);
102 pConfig->UnprocGain = (LVM_UINT16)(HEADPHONEGAINUNPROC);
103 }
104
105 if (pInstance->Params.ReverbLevel != pParams->ReverbLevel) {
106 LVM_INT32 ReverbPercentage = 83886; // 1 Percent Reverb i.e 1/100 in Q 23 format
107 ReverbPercentage *= pParams->ReverbLevel; // Actual Reverb Level in Q 23 format
108 pConfig->ReverbLevel = ((LVM_FLOAT)(ReverbPercentage >> 8)) / 32767.0f;
109 }
110 return (LVCS_SUCCESS);
111 }
112 /************************************************************************************/
113 /* */
114 /* FUNCTION: LVCS_Reverb */
115 /* */
116 /* DESCRIPTION: */
117 /* Create reverb using the block of input samples based on the following block */
118 /* diagram: */
119 /* ________ ________ */
120 /* | | | | */
121 /* _____ _______ | |----------->| | ______ ___ */
122 /* | | | | | Stereo | | L & R | | | | | */
123 /* -->| LPF |-->| Delay |-->| to | ____ | to |-->| Gain |-->| + |--> */
124 /* | |_____| |_______| | L & R | | | | Stereo | |______| |___| */
125 /* | | |-->| -1 |-->| | | */
126 /* | |________| |____| |________| | */
127 /* | | */
128 /* |-----------------------------------------------------------------------| */
129 /* */
130 /* The input buffer is broken in to sub-blocks of the size of the delay or less. */
131 /* This allows the delay buffer to be treated as a circular buffer but processed */
132 /* as a linear buffer. */
133 /* */
134 /* */
135 /* PARAMETERS: */
136 /* hInstance Instance Handle */
137 /* pInData Pointer to the input buffer */
138 /* pOutData Pointer to the output buffer */
139 /* NumSamples Number of samples to process */
140 /* */
141 /* RETURNS: */
142 /* LVCS_Success Always succeeds */
143 /* */
144 /* NOTES: */
145 /* 1. Process in blocks of samples the size of the delay where possible, if not */
146 /* the number of samples left over */
147 /* 2. The Gain is combined with the LPF and incorporated in to the coefficients */
148 /* */
149 /************************************************************************************/
LVCS_ReverbGenerator(LVCS_Handle_t hInstance,const LVM_FLOAT * pInData,LVM_FLOAT * pOutData,LVM_UINT16 NumSamples)150 LVCS_ReturnStatus_en LVCS_ReverbGenerator(LVCS_Handle_t hInstance, const LVM_FLOAT* pInData,
151 LVM_FLOAT* pOutData, LVM_UINT16 NumSamples) {
152 LVCS_Instance_t* pInstance = (LVCS_Instance_t*)hInstance;
153 LVCS_ReverbGenerator_t* pConfig = (LVCS_ReverbGenerator_t*)&pInstance->Reverberation;
154 LVM_FLOAT* pScratch;
155 LVM_INT32 NumChannels = pInstance->Params.NrChannels;
156 LVM_UINT16 destNumSamples =
157 (pInstance->Params.NrChannels == FCC_1) ? NumSamples : FCC_2 * NumSamples;
158
159 pScratch = (LVM_FLOAT*)pInstance->pScratch;
160
161 /*
162 * Copy the data to the output in outplace processing
163 */
164 if (pInData != pOutData) {
165 /*
166 * Reverb not required so just copy the data
167 */
168 Copy_Float((LVM_FLOAT*)pInData, /* Source */
169 (LVM_FLOAT*)pOutData, /* Destination */
170 (LVM_INT16)destNumSamples); /* Number of frames */
171 }
172
173 /*
174 * Check if the reverb is required
175 */
176 /* Disable when CS4MS in stereo mode */
177 if ((((LVCS_OutputDevice_en)pInstance->Params.SpeakerType == LVCS_HEADPHONE) ||
178 (pInstance->Params.SpeakerType == LVCS_EX_HEADPHONES) ||
179 (pInstance->Params.SourceFormat != LVCS_STEREO)) &&
180 /* For validation testing */
181 ((pInstance->Params.OperatingMode & LVCS_REVERBSWITCH) != 0)) {
182 /********************************************************************************/
183 /* */
184 /* Copy the input data to scratch memory and filter it */
185 /* */
186 /********************************************************************************/
187
188 /*
189 * Copy the input data to the scratch memory
190 */
191 Copy_Float((LVM_FLOAT*)pInData, /* Source */
192 (LVM_FLOAT*)pScratch, /* Destination */
193 (LVM_INT16)destNumSamples); /* Number of frames */
194
195 /*
196 * Filter the data
197 */
198 pInstance->pRevBiquad->process(pScratch, pScratch, NumSamples);
199
200 Mult3s_Float((LVM_FLOAT*)pScratch, pConfig->ReverbLevel, (LVM_FLOAT*)pScratch,
201 (LVM_INT16)destNumSamples); /* Number of frames */
202
203 /*
204 * Apply the delay mix
205 */
206 DelayMix_Float((LVM_FLOAT*)pScratch, &pConfig->StereoSamples[0], pConfig->DelaySize,
207 pOutData, &pConfig->DelayOffset, (LVM_INT16)NumSamples, NumChannels);
208 }
209
210 return (LVCS_SUCCESS);
211 }
212