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 "LVREV_Private.h"
24 #include "VectorArithmetic.h"
25
26 /****************************************************************************************/
27 /* */
28 /* FUNCTION: LVREV_Process */
29 /* */
30 /* DESCRIPTION: */
31 /* Process function for the LVREV module. */
32 /* */
33 /* PARAMETERS: */
34 /* hInstance Instance handle */
35 /* pInData Pointer to the input data */
36 /* pOutData Pointer to the output data */
37 /* NumSamples Number of samples in the input buffer */
38 /* */
39 /* RETURNS: */
40 /* LVREV_Success Succeeded */
41 /* LVREV_INVALIDNUMSAMPLES NumSamples was larger than the maximum block size */
42 /* LVREV_NULLADDRESS When one of hInstance, pInData or pOutData is NULL */
43 /* */
44 /* NOTES: */
45 /* 1. The input and output buffers must be 32-bit aligned */
46 /* */
47 /****************************************************************************************/
LVREV_Process(LVREV_Handle_t hInstance,const LVM_FLOAT * pInData,LVM_FLOAT * pOutData,const LVM_UINT16 NumSamples)48 LVREV_ReturnStatus_en LVREV_Process(LVREV_Handle_t hInstance, const LVM_FLOAT* pInData,
49 LVM_FLOAT* pOutData, const LVM_UINT16 NumSamples) {
50 LVREV_Instance_st* pLVREV_Private = (LVREV_Instance_st*)hInstance;
51 LVM_FLOAT* pInput = (LVM_FLOAT*)pInData;
52 LVM_FLOAT* pOutput = pOutData;
53 LVM_INT32 SamplesToProcess, RemainingSamples;
54 LVM_INT32 format = 1;
55
56 /*
57 * Check for error conditions
58 */
59
60 /* Check for NULL pointers */
61 if ((hInstance == LVM_NULL) || (pInData == LVM_NULL) || (pOutData == LVM_NULL)) {
62 return LVREV_NULLADDRESS;
63 }
64
65 /*
66 * Apply the new controls settings if required
67 */
68 if (pLVREV_Private->bControlPending == LVM_TRUE) {
69 LVREV_ReturnStatus_en errorCode;
70
71 /*
72 * Clear the pending flag and update the control settings
73 */
74 pLVREV_Private->bControlPending = LVM_FALSE;
75
76 errorCode = LVREV_ApplyNewSettings(pLVREV_Private);
77
78 if (errorCode != LVREV_SUCCESS) {
79 return errorCode;
80 }
81 }
82
83 /*
84 * Trap the case where the number of samples is zero.
85 */
86 if (NumSamples == 0) {
87 return LVREV_SUCCESS;
88 }
89
90 /*
91 * If OFF copy and reformat the data as necessary
92 */
93 if (pLVREV_Private->CurrentParams.OperatingMode == LVM_MODE_OFF) {
94 if (pInput != pOutput) {
95 /*
96 * Copy the data to the output buffer, convert to stereo is required
97 */
98 if (pLVREV_Private->CurrentParams.SourceFormat == LVM_MONO) {
99 MonoTo2I_Float(pInput, pOutput, NumSamples);
100 } else {
101 Copy_Float(pInput, pOutput,
102 (LVM_INT16)(NumSamples << 1)); // 32 bit data, stereo
103 }
104 }
105
106 return LVREV_SUCCESS;
107 }
108
109 RemainingSamples = (LVM_INT32)NumSamples;
110
111 if (pLVREV_Private->CurrentParams.SourceFormat != LVM_MONO) {
112 format = 2;
113 }
114
115 while (RemainingSamples != 0) {
116 /*
117 * Process the data
118 */
119
120 if (RemainingSamples > pLVREV_Private->MaxBlkLen) {
121 SamplesToProcess = pLVREV_Private->MaxBlkLen;
122 RemainingSamples = (LVM_INT16)(RemainingSamples - SamplesToProcess);
123 } else {
124 SamplesToProcess = RemainingSamples;
125 RemainingSamples = 0;
126 }
127
128 ReverbBlock(pInput, pOutput, pLVREV_Private, (LVM_UINT16)SamplesToProcess);
129 pInput = (LVM_FLOAT*)(pInput + (SamplesToProcess * format));
130 pOutput = (LVM_FLOAT*)(pOutput + (SamplesToProcess * 2)); // Always stereo output
131 }
132
133 return LVREV_SUCCESS;
134 }
135
136 /****************************************************************************************/
137 /* */
138 /* FUNCTION: ReverbBlock */
139 /* */
140 /* DESCRIPTION: */
141 /* Process function for the LVREV module. */
142 /* */
143 /* PARAMETERS: */
144 /* hInstance Instance handle */
145 /* pInData Pointer to the input data */
146 /* pOutData Pointer to the output data */
147 /* NumSamples Number of samples in the input buffer */
148 /* */
149 /* RETURNS: */
150 /* LVREV_Success Succeeded */
151 /* LVREV_INVALIDNUMSAMPLES NumSamples was larger than the maximum block size */
152 /* LVREV_NULLADDRESS When one of hInstance, pInData or pOutData is NULL */
153 /* */
154 /* NOTES: */
155 /* 1. The input and output buffers must be 32-bit aligned */
156 /* */
157 /****************************************************************************************/
ReverbBlock(LVM_FLOAT * pInput,LVM_FLOAT * pOutput,LVREV_Instance_st * pPrivate,LVM_UINT16 NumSamples)158 void ReverbBlock(LVM_FLOAT* pInput, LVM_FLOAT* pOutput, LVREV_Instance_st* pPrivate,
159 LVM_UINT16 NumSamples) {
160 LVM_INT16 j, size;
161 LVM_FLOAT* pDelayLine;
162 LVM_FLOAT* pDelayLineInput = pPrivate->pScratch;
163 LVM_FLOAT* pScratch = pPrivate->pScratch;
164 LVM_FLOAT* pIn;
165 LVM_FLOAT* pTemp = pPrivate->pInputSave;
166 LVM_INT32 NumberOfDelayLines;
167
168 /******************************************************************************
169 * All calculations will go into the buffer pointed to by pTemp, this will *
170 * then be mixed with the original input to create the final output. *
171 * *
172 * When INPLACE processing is selected this must be a temporary buffer and *
173 * hence this is the worst case, so for simplicity this will ALWAYS be so *
174 * *
175 * The input buffer will remain untouched until the output of the mixer if *
176 * INPLACE processing is selected. *
177 * *
178 * The temp buffer will always be NumSamples in size regardless of MONO or *
179 * STEREO input. In the case of stereo input all processing is done in MONO *
180 * and the final output is converted to STEREO after the mixer *
181 ******************************************************************************/
182
183 if (pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4) {
184 NumberOfDelayLines = 4;
185 } else if (pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_2) {
186 NumberOfDelayLines = 2;
187 } else {
188 NumberOfDelayLines = 1;
189 }
190
191 if (pPrivate->CurrentParams.SourceFormat == LVM_MONO) {
192 pIn = pInput;
193 } else {
194 /*
195 * Stereo to mono conversion
196 */
197
198 From2iToMono_Float(pInput, pTemp, (LVM_INT16)NumSamples);
199 pIn = pTemp;
200 }
201
202 Mult3s_Float(pIn, (LVM_FLOAT)LVREV_HEADROOM, pTemp, (LVM_INT16)NumSamples);
203
204 /*
205 * High pass filter
206 */
207 pPrivate->pRevHPFBiquad->process(pTemp, pTemp, NumSamples);
208
209 /*
210 * Low pass filter
211 */
212 pPrivate->pRevLPFBiquad->process(pTemp, pTemp, NumSamples);
213
214 /*
215 * Process all delay lines
216 */
217
218 for (j = 0; j < NumberOfDelayLines; j++) {
219 pDelayLine = pPrivate->pScratchDelayLine[j];
220
221 /*
222 * All-pass filter with pop and click suppression
223 */
224 /* Get the smoothed, delayed output. Put it in the output buffer */
225 MixSoft_2St_D32C31_SAT(&pPrivate->Mixer_APTaps[j], pPrivate->pOffsetA[j],
226 pPrivate->pOffsetB[j], pDelayLine, (LVM_INT16)NumSamples);
227 /* Re-align the all pass filter delay buffer and copying the fixed delay data \
228 to the AP delay in the process */
229 Copy_Float(&pPrivate->pDelay_T[j][NumSamples], pPrivate->pDelay_T[j],
230 (LVM_INT16)(pPrivate->T[j] - NumSamples)); /* 32-bit data */
231 /* Apply the smoothed feedback and save to fixed delay input (currently empty) */
232 MixSoft_1St_D32C31_WRA(&pPrivate->Mixer_SGFeedback[j], pDelayLine,
233 &pPrivate->pDelay_T[j][pPrivate->T[j] - NumSamples],
234 (LVM_INT16)NumSamples);
235 /* Sum into the AP delay line */
236 Mac3s_Sat_Float(&pPrivate->pDelay_T[j][pPrivate->T[j] - NumSamples],
237 -1.0f, /* Invert since the feedback coefficient is negative */
238 &pPrivate->pDelay_T[j][pPrivate->Delay_AP[j] - NumSamples],
239 (LVM_INT16)NumSamples);
240 /* Apply smoothed feedforward sand save to fixed delay input (currently empty) */
241 MixSoft_1St_D32C31_WRA(&pPrivate->Mixer_SGFeedforward[j],
242 &pPrivate->pDelay_T[j][pPrivate->Delay_AP[j] - NumSamples],
243 &pPrivate->pDelay_T[j][pPrivate->T[j] - NumSamples],
244 (LVM_INT16)NumSamples);
245 /* Sum into the AP output */
246 Mac3s_Sat_Float(&pPrivate->pDelay_T[j][pPrivate->T[j] - NumSamples], 1.0f, pDelayLine,
247 (LVM_INT16)NumSamples);
248
249 /*
250 * Feedback gain
251 */
252 MixSoft_1St_D32C31_WRA(&pPrivate->FeedbackMixer[j], pDelayLine, pDelayLine, NumSamples);
253
254 /*
255 * Low pass filter
256 */
257 pPrivate->revLPFBiquad[j]->process(pDelayLine, pDelayLine, NumSamples);
258 }
259
260 /*
261 * Apply rotation matrix and delay samples
262 */
263 for (j = 0; j < NumberOfDelayLines; j++) {
264 Copy_Float(pTemp, pDelayLineInput, (LVM_INT16)(NumSamples));
265 /*
266 * Rotation matrix mix
267 */
268 switch (j) {
269 case 3:
270 /*
271 * Add delay line 1 and 2 contribution
272 */
273 Mac3s_Sat_Float(pPrivate->pScratchDelayLine[1], -1.0f, pDelayLineInput,
274 (LVM_INT16)NumSamples);
275 Mac3s_Sat_Float(pPrivate->pScratchDelayLine[2], -1.0f, pDelayLineInput,
276 (LVM_INT16)NumSamples);
277
278 break;
279 case 2:
280
281 /*
282 * Add delay line 0 and 3 contribution
283 */
284 Mac3s_Sat_Float(pPrivate->pScratchDelayLine[0], -1.0f, pDelayLineInput,
285 (LVM_INT16)NumSamples);
286 Mac3s_Sat_Float(pPrivate->pScratchDelayLine[3], -1.0f, pDelayLineInput,
287 (LVM_INT16)NumSamples);
288
289 break;
290 case 1:
291 if (pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4) {
292 /*
293 * Add delay line 0 and 3 contribution
294 */
295 Mac3s_Sat_Float(pPrivate->pScratchDelayLine[0], -1.0f, pDelayLineInput,
296 (LVM_INT16)NumSamples);
297 Add2_Sat_Float(pPrivate->pScratchDelayLine[3], pDelayLineInput,
298 (LVM_INT16)NumSamples);
299
300 } else {
301 /*
302 * Add delay line 0 and 1 contribution
303 */
304 Mac3s_Sat_Float(pPrivate->pScratchDelayLine[0], -1.0f, pDelayLineInput,
305 (LVM_INT16)NumSamples);
306 Mac3s_Sat_Float(pPrivate->pScratchDelayLine[1], -1.0f, pDelayLineInput,
307 (LVM_INT16)NumSamples);
308 }
309 break;
310 case 0:
311 if (pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4) {
312 /*
313 * Add delay line 1 and 2 contribution
314 */
315 Mac3s_Sat_Float(pPrivate->pScratchDelayLine[1], -1.0f, pDelayLineInput,
316 (LVM_INT16)NumSamples);
317 Add2_Sat_Float(pPrivate->pScratchDelayLine[2], pDelayLineInput,
318 (LVM_INT16)NumSamples);
319
320 } else if (pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_2) {
321 /*
322 * Add delay line 0 and 1 contribution
323 */
324 Add2_Sat_Float(pPrivate->pScratchDelayLine[0], pDelayLineInput,
325 (LVM_INT16)NumSamples);
326 Mac3s_Sat_Float(pPrivate->pScratchDelayLine[1], -1.0f, pDelayLineInput,
327 (LVM_INT16)NumSamples);
328
329 } else {
330 /*
331 * Add delay line 0 contribution
332 */
333
334 /* SOURCE DESTINATION*/
335 Add2_Sat_Float(pPrivate->pScratchDelayLine[0], pDelayLineInput,
336 (LVM_INT16)NumSamples);
337 }
338 break;
339 default:
340 break;
341 }
342
343 /*
344 * Delay samples
345 */
346 Copy_Float(pDelayLineInput, &pPrivate->pDelay_T[j][pPrivate->T[j] - NumSamples],
347 (LVM_INT16)(NumSamples)); /* 32-bit data */
348 }
349
350 /*
351 * Create stereo output
352 */
353 switch (pPrivate->InstanceParams.NumDelays) {
354 case LVREV_DELAYLINES_4:
355 Add2_Sat_Float(pPrivate->pScratchDelayLine[3], pPrivate->pScratchDelayLine[0],
356 (LVM_INT16)NumSamples);
357 Add2_Sat_Float(pPrivate->pScratchDelayLine[2], pPrivate->pScratchDelayLine[1],
358 (LVM_INT16)NumSamples);
359
360 JoinTo2i_Float(pPrivate->pScratchDelayLine[0], pPrivate->pScratchDelayLine[1], pTemp,
361 (LVM_INT16)NumSamples);
362
363 break;
364 case LVREV_DELAYLINES_2:
365
366 Copy_Float(pPrivate->pScratchDelayLine[1], pScratch, (LVM_INT16)(NumSamples));
367
368 Mac3s_Sat_Float(pPrivate->pScratchDelayLine[0], -1.0f, pScratch, (LVM_INT16)NumSamples);
369
370 Add2_Sat_Float(pPrivate->pScratchDelayLine[1], pPrivate->pScratchDelayLine[0],
371 (LVM_INT16)NumSamples);
372
373 JoinTo2i_Float(pPrivate->pScratchDelayLine[0], pScratch, pTemp, (LVM_INT16)NumSamples);
374 break;
375 case LVREV_DELAYLINES_1:
376 MonoTo2I_Float(pPrivate->pScratchDelayLine[0], pTemp, (LVM_INT16)NumSamples);
377 break;
378 default:
379 break;
380 }
381
382 /*
383 * Dry/wet mixer
384 */
385
386 size = (LVM_INT16)(NumSamples << 1);
387 MixSoft_2St_D32C31_SAT(&pPrivate->BypassMixer, pTemp, pTemp, pOutput, size);
388
389 /* Apply Gain*/
390
391 Shift_Sat_Float(LVREV_OUTPUTGAIN_SHIFT, pOutput, pOutput, size);
392
393 MixSoft_1St_D32C31_WRA(&pPrivate->GainMixer, pOutput, pOutput, size);
394
395 return;
396 }
397 /* End of file */
398