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