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 /* */
29 /* FUNCTION: LVREV_Process */
30 /* */
31 /* DESCRIPTION: */
32 /* Process function for the LVREV module. */
33 /* */
34 /* PARAMETERS: */
35 /* hInstance Instance handle */
36 /* pInData Pointer to the input data */
37 /* pOutData Pointer to the output data */
38 /* NumSamples Number of samples in the input buffer */
39 /* */
40 /* RETURNS: */
41 /* LVREV_Success Succeeded */
42 /* LVREV_INVALIDNUMSAMPLES NumSamples was larger than the maximum block size */
43 /* LVREV_NULLADDRESS When one of hInstance, pInData or pOutData is NULL */
44 /* */
45 /* NOTES: */
46 /* 1. The input and output buffers must be 32-bit aligned */
47 /* */
48 /****************************************************************************************/
49 #ifdef BUILD_FLOAT
LVREV_Process(LVREV_Handle_t hInstance,const LVM_FLOAT * pInData,LVM_FLOAT * pOutData,const LVM_UINT16 NumSamples)50 LVREV_ReturnStatus_en LVREV_Process(LVREV_Handle_t hInstance,
51 const LVM_FLOAT *pInData,
52 LVM_FLOAT *pOutData,
53 const LVM_UINT16 NumSamples)
54 #else
55 LVREV_ReturnStatus_en LVREV_Process(LVREV_Handle_t hInstance,
56 const LVM_INT32 *pInData,
57 LVM_INT32 *pOutData,
58 const LVM_UINT16 NumSamples)
59 #endif
60 {
61 LVREV_Instance_st *pLVREV_Private = (LVREV_Instance_st *)hInstance;
62 #ifdef BUILD_FLOAT
63 LVM_FLOAT *pInput = (LVM_FLOAT *)pInData;
64 LVM_FLOAT *pOutput = pOutData;
65 #else
66 LVM_INT32 *pInput = (LVM_INT32 *)pInData;
67 LVM_INT32 *pOutput = pOutData;
68 #endif
69 LVM_INT32 SamplesToProcess, RemainingSamples;
70 LVM_INT32 format = 1;
71
72 /*
73 * Check for error conditions
74 */
75
76 /* Check for NULL pointers */
77 if((hInstance == LVM_NULL) || (pInData == LVM_NULL) || (pOutData == LVM_NULL))
78 {
79 return LVREV_NULLADDRESS;
80 }
81
82 /*
83 * Apply the new controls settings if required
84 */
85 if(pLVREV_Private->bControlPending == LVM_TRUE)
86 {
87 LVREV_ReturnStatus_en errorCode;
88
89 /*
90 * Clear the pending flag and update the control settings
91 */
92 pLVREV_Private->bControlPending = LVM_FALSE;
93
94 errorCode = LVREV_ApplyNewSettings (pLVREV_Private);
95
96 if(errorCode != LVREV_SUCCESS)
97 {
98 return errorCode;
99 }
100 }
101
102 /*
103 * Trap the case where the number of samples is zero.
104 */
105 if (NumSamples == 0)
106 {
107 return LVREV_SUCCESS;
108 }
109
110 /*
111 * If OFF copy and reformat the data as necessary
112 */
113 if (pLVREV_Private->CurrentParams.OperatingMode == LVM_MODE_OFF)
114 {
115 if(pInput != pOutput)
116 {
117 /*
118 * Copy the data to the output buffer, convert to stereo is required
119 */
120 #ifndef BUILD_FLOAT
121 if(pLVREV_Private->CurrentParams.SourceFormat == LVM_MONO){
122 MonoTo2I_32(pInput, pOutput, NumSamples);
123 } else {
124 Copy_16((LVM_INT16 *)pInput,
125 (LVM_INT16 *)pOutput,
126 (LVM_INT16)(NumSamples << 2)); // 32 bit data, stereo
127 }
128 #else
129 if(pLVREV_Private->CurrentParams.SourceFormat == LVM_MONO){
130 MonoTo2I_Float(pInput, pOutput, NumSamples);
131 } else {
132 Copy_Float(pInput,
133 pOutput,
134 (LVM_INT16)(NumSamples << 1)); // 32 bit data, stereo
135 }
136 #endif
137 }
138
139 return LVREV_SUCCESS;
140 }
141
142 RemainingSamples = (LVM_INT32)NumSamples;
143
144 if (pLVREV_Private->CurrentParams.SourceFormat != LVM_MONO)
145 {
146 format = 2;
147 }
148
149 while (RemainingSamples!=0)
150 {
151 /*
152 * Process the data
153 */
154
155 if(RemainingSamples > pLVREV_Private->MaxBlkLen)
156 {
157 SamplesToProcess = pLVREV_Private->MaxBlkLen;
158 RemainingSamples = (LVM_INT16)(RemainingSamples - SamplesToProcess);
159 }
160 else
161 {
162 SamplesToProcess = RemainingSamples;
163 RemainingSamples = 0;
164 }
165
166 ReverbBlock(pInput, pOutput, pLVREV_Private, (LVM_UINT16)SamplesToProcess);
167 #ifdef BUILD_FLOAT
168 pInput = (LVM_FLOAT *)(pInput + (SamplesToProcess * format));
169 pOutput = (LVM_FLOAT *)(pOutput + (SamplesToProcess * 2)); // Always stereo output
170 #else
171 pInput = (LVM_INT32 *)(pInput +(SamplesToProcess*format));
172 pOutput = (LVM_INT32 *)(pOutput+(SamplesToProcess*2));
173 #endif
174 }
175
176 return LVREV_SUCCESS;
177 }
178
179
180
181 /****************************************************************************************/
182 /* */
183 /* FUNCTION: ReverbBlock */
184 /* */
185 /* DESCRIPTION: */
186 /* Process function for the LVREV module. */
187 /* */
188 /* PARAMETERS: */
189 /* hInstance Instance handle */
190 /* pInData Pointer to the input data */
191 /* pOutData Pointer to the output data */
192 /* NumSamples Number of samples in the input buffer */
193 /* */
194 /* RETURNS: */
195 /* LVREV_Success Succeeded */
196 /* LVREV_INVALIDNUMSAMPLES NumSamples was larger than the maximum block size */
197 /* LVREV_NULLADDRESS When one of hInstance, pInData or pOutData is NULL */
198 /* */
199 /* NOTES: */
200 /* 1. The input and output buffers must be 32-bit aligned */
201 /* */
202 /****************************************************************************************/
203 #ifndef BUILD_FLOAT
ReverbBlock(LVM_INT32 * pInput,LVM_INT32 * pOutput,LVREV_Instance_st * pPrivate,LVM_UINT16 NumSamples)204 void ReverbBlock(LVM_INT32 *pInput, LVM_INT32 *pOutput, LVREV_Instance_st *pPrivate, LVM_UINT16 NumSamples)
205 {
206 LVM_INT16 j, size;
207 LVM_INT32 *pDelayLine;
208 LVM_INT32 *pDelayLineInput = pPrivate->pScratch;
209 LVM_INT32 *pScratch = pPrivate->pScratch;
210 LVM_INT32 *pIn;
211 LVM_INT32 *pTemp = pPrivate->pInputSave;
212 LVM_INT32 NumberOfDelayLines;
213
214 /******************************************************************************
215 * All calculations will go into the buffer pointed to by pTemp, this will *
216 * then be mixed with the original input to create the final output. *
217 * *
218 * When INPLACE processing is selected this must be a temporary buffer and *
219 * hence this is the worst case, so for simplicity this will ALWAYS be so *
220 * *
221 * The input buffer will remain untouched until the output of the mixer if *
222 * INPLACE processing is selected. *
223 * *
224 * The temp buffer will always be NumSamples in size regardless of MONO or *
225 * STEREO input. In the case of stereo input all processing is done in MONO *
226 * and the final output is converted to STEREO after the mixer *
227 ******************************************************************************/
228
229 if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4 )
230 {
231 NumberOfDelayLines = 4;
232 }
233 else if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_2 )
234 {
235 NumberOfDelayLines = 2;
236 }
237 else
238 {
239 NumberOfDelayLines = 1;
240 }
241
242 if(pPrivate->CurrentParams.SourceFormat == LVM_MONO)
243 {
244 pIn = pInput;
245 }
246 else
247 {
248 /*
249 * Stereo to mono conversion
250 */
251
252 From2iToMono_32( pInput,
253 pTemp,
254 (LVM_INT16)NumSamples);
255
256 pIn = pTemp;
257 }
258
259 Mult3s_32x16(pIn,
260 (LVM_INT16)LVREV_HEADROOM,
261 pTemp,
262 (LVM_INT16)NumSamples);
263
264 /*
265 * High pass filter
266 */
267 FO_1I_D32F32C31_TRC_WRA_01( &pPrivate->pFastCoef->HPCoefs,
268 pTemp,
269 pTemp,
270 (LVM_INT16)NumSamples);
271 /*
272 * Low pass filter
273 */
274 FO_1I_D32F32C31_TRC_WRA_01( &pPrivate->pFastCoef->LPCoefs,
275 pTemp,
276 pTemp,
277 (LVM_INT16)NumSamples);
278
279 /*
280 * Process all delay lines
281 */
282
283 for(j = 0; j < NumberOfDelayLines; j++)
284 {
285 pDelayLine = pPrivate->pScratchDelayLine[j];
286
287 /*
288 * All-pass filter with pop and click suppression
289 */
290 /* Get the smoothed, delayed output. Put it in the output buffer */
291 MixSoft_2St_D32C31_SAT(&pPrivate->Mixer_APTaps[j],
292 pPrivate->pOffsetA[j],
293 pPrivate->pOffsetB[j],
294 pDelayLine,
295 (LVM_INT16)NumSamples);
296 /* Re-align the all pass filter delay buffer and copying the fixed delay data to the AP delay in the process */
297 Copy_16((LVM_INT16 *)&pPrivate->pDelay_T[j][NumSamples],
298 (LVM_INT16 *)pPrivate->pDelay_T[j],
299 (LVM_INT16)((pPrivate->T[j]-NumSamples) << 1)); /* 32-bit data */
300 /* Apply the smoothed feedback and save to fixed delay input (currently empty) */
301 MixSoft_1St_D32C31_WRA(&pPrivate->Mixer_SGFeedback[j],
302 pDelayLine,
303 &pPrivate->pDelay_T[j][pPrivate->T[j]-NumSamples],
304 (LVM_INT16)NumSamples);
305 /* Sum into the AP delay line */
306 Mac3s_Sat_32x16(&pPrivate->pDelay_T[j][pPrivate->T[j]-NumSamples],
307 -0x7fff, /* Invert since the feedback coefficient is negative */
308 &pPrivate->pDelay_T[j][pPrivate->Delay_AP[j]-NumSamples],
309 (LVM_INT16)NumSamples);
310 /* Apply smoothed feedforward sand save to fixed delay input (currently empty) */
311 MixSoft_1St_D32C31_WRA(&pPrivate->Mixer_SGFeedforward[j],
312 &pPrivate->pDelay_T[j][pPrivate->Delay_AP[j]-NumSamples],
313 &pPrivate->pDelay_T[j][pPrivate->T[j]-NumSamples],
314 (LVM_INT16)NumSamples);
315 /* Sum into the AP output */
316 Mac3s_Sat_32x16(&pPrivate->pDelay_T[j][pPrivate->T[j]-NumSamples],
317 0x7fff,
318 pDelayLine,
319 (LVM_INT16)NumSamples);
320
321 /*
322 * Feedback gain
323 */
324 MixSoft_1St_D32C31_WRA(&pPrivate->FeedbackMixer[j], pDelayLine, pDelayLine, NumSamples);
325
326 /*
327 * Low pass filter
328 */
329 FO_1I_D32F32C31_TRC_WRA_01( &pPrivate->pFastCoef->RevLPCoefs[j],
330 pDelayLine,
331 pDelayLine,
332 (LVM_INT16)NumSamples);
333 }
334
335 /*
336 * Apply rotation matrix and delay samples
337 */
338 for(j = 0; j < NumberOfDelayLines; j++)
339 {
340
341 Copy_16( (LVM_INT16*)(pTemp),
342 (LVM_INT16*)(pDelayLineInput),
343 (LVM_INT16)(NumSamples << 1));
344
345 /*
346 * Rotation matrix mix
347 */
348 switch(j)
349 {
350 case 3:
351 /*
352 * Add delay line 1 and 2 contribution
353 */
354 Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[1], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples);
355 Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[2], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples);
356
357 break;
358 case 2:
359
360 /*
361 * Add delay line 0 and 3 contribution
362 */
363 Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[0], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples);
364 Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[3], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples);
365
366 break;
367 case 1:
368 if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4)
369 {
370 /*
371 * Add delay line 0 and 3 contribution
372 */
373 Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[0], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples);
374 Add2_Sat_32x32(pPrivate->pScratchDelayLine[3], pDelayLineInput, (LVM_INT16)NumSamples);
375
376 }
377 else
378 {
379 /*
380 * Add delay line 0 and 1 contribution
381 */
382 Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[0], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples);
383 Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[1], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples);
384
385 }
386 break;
387 case 0:
388 if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4)
389 {
390 /*
391 * Add delay line 1 and 2 contribution
392 */
393 Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[1], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples);
394 Add2_Sat_32x32(pPrivate->pScratchDelayLine[2], pDelayLineInput, (LVM_INT16)NumSamples);
395
396 }
397 else if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_2)
398 {
399 /*
400 * Add delay line 0 and 1 contribution
401 */
402 Add2_Sat_32x32(pPrivate->pScratchDelayLine[0], pDelayLineInput, (LVM_INT16)NumSamples);
403 Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[1], -0x8000, pDelayLineInput, (LVM_INT16)NumSamples);
404
405 }
406 else
407 {
408 /*
409 * Add delay line 0 contribution
410 */
411
412 /* SOURCE DESTINATION*/
413 Add2_Sat_32x32(pPrivate->pScratchDelayLine[0], pDelayLineInput, (LVM_INT16)NumSamples);
414 }
415 break;
416 default:
417 break;
418 }
419
420 /*
421 * Delay samples
422 */
423 Copy_16((LVM_INT16 *)pDelayLineInput,
424 (LVM_INT16 *)&pPrivate->pDelay_T[j][pPrivate->T[j]-NumSamples],
425 (LVM_INT16)(NumSamples << 1)); /* 32-bit data */
426
427 }
428
429
430 /*
431 * Create stereo output
432 */
433 switch(pPrivate->InstanceParams.NumDelays)
434 {
435 case LVREV_DELAYLINES_4:
436 Add2_Sat_32x32(pPrivate->pScratchDelayLine[3],
437 pPrivate->pScratchDelayLine[0],
438 (LVM_INT16)NumSamples);
439 Add2_Sat_32x32(pPrivate->pScratchDelayLine[2],
440 pPrivate->pScratchDelayLine[1],
441 (LVM_INT16)NumSamples);
442
443
444 JoinTo2i_32x32(pPrivate->pScratchDelayLine[0],
445 pPrivate->pScratchDelayLine[1],
446 pTemp,
447 (LVM_INT16)NumSamples);
448
449
450 break;
451 case LVREV_DELAYLINES_2:
452
453 Copy_16( (LVM_INT16*)pPrivate->pScratchDelayLine[1],
454 (LVM_INT16*)pScratch,
455 (LVM_INT16)(NumSamples << 1));
456
457 Mac3s_Sat_32x16(pPrivate->pScratchDelayLine[0],
458 -0x8000,
459 pScratch,
460 (LVM_INT16)NumSamples);
461
462 Add2_Sat_32x32(pPrivate->pScratchDelayLine[1],
463 pPrivate->pScratchDelayLine[0],
464 (LVM_INT16)NumSamples);
465
466
467 JoinTo2i_32x32(pPrivate->pScratchDelayLine[0],
468 pScratch,
469 pTemp,
470 (LVM_INT16)NumSamples);
471 break;
472 case LVREV_DELAYLINES_1:
473 MonoTo2I_32(pPrivate->pScratchDelayLine[0],
474 pTemp,
475 (LVM_INT16)NumSamples);
476 break;
477 default:
478 break;
479 }
480
481
482 /*
483 * Dry/wet mixer
484 */
485
486 size = (LVM_INT16)(NumSamples << 1);
487 MixSoft_2St_D32C31_SAT(&pPrivate->BypassMixer,
488 pTemp,
489 pTemp,
490 pOutput,
491 size);
492
493 /* Apply Gain*/
494
495 Shift_Sat_v32xv32 (LVREV_OUTPUTGAIN_SHIFT,
496 pOutput,
497 pOutput,
498 size);
499
500 MixSoft_1St_D32C31_WRA(&pPrivate->GainMixer,
501 pOutput,
502 pOutput,
503 size);
504
505 return;
506 }
507 #else
ReverbBlock(LVM_FLOAT * pInput,LVM_FLOAT * pOutput,LVREV_Instance_st * pPrivate,LVM_UINT16 NumSamples)508 void ReverbBlock(LVM_FLOAT *pInput, LVM_FLOAT *pOutput,
509 LVREV_Instance_st *pPrivate, LVM_UINT16 NumSamples)
510 {
511 LVM_INT16 j, size;
512 LVM_FLOAT *pDelayLine;
513 LVM_FLOAT *pDelayLineInput = pPrivate->pScratch;
514 LVM_FLOAT *pScratch = pPrivate->pScratch;
515 LVM_FLOAT *pIn;
516 LVM_FLOAT *pTemp = pPrivate->pInputSave;
517 LVM_INT32 NumberOfDelayLines;
518
519 /******************************************************************************
520 * All calculations will go into the buffer pointed to by pTemp, this will *
521 * then be mixed with the original input to create the final output. *
522 * *
523 * When INPLACE processing is selected this must be a temporary buffer and *
524 * hence this is the worst case, so for simplicity this will ALWAYS be so *
525 * *
526 * The input buffer will remain untouched until the output of the mixer if *
527 * INPLACE processing is selected. *
528 * *
529 * The temp buffer will always be NumSamples in size regardless of MONO or *
530 * STEREO input. In the case of stereo input all processing is done in MONO *
531 * and the final output is converted to STEREO after the mixer *
532 ******************************************************************************/
533
534 if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4)
535 {
536 NumberOfDelayLines = 4;
537 }
538 else if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_2)
539 {
540 NumberOfDelayLines = 2;
541 }
542 else
543 {
544 NumberOfDelayLines = 1;
545 }
546
547 if(pPrivate->CurrentParams.SourceFormat == LVM_MONO)
548 {
549 pIn = pInput;
550 }
551 else
552 {
553 /*
554 * Stereo to mono conversion
555 */
556
557 From2iToMono_Float(pInput,
558 pTemp,
559 (LVM_INT16)NumSamples);
560 pIn = pTemp;
561 }
562
563 Mult3s_Float(pIn,
564 (LVM_FLOAT)LVREV_HEADROOM,
565 pTemp,
566 (LVM_INT16)NumSamples);
567
568 /*
569 * High pass filter
570 */
571 FO_1I_D32F32C31_TRC_WRA_01(&pPrivate->pFastCoef->HPCoefs,
572 pTemp,
573 pTemp,
574 (LVM_INT16)NumSamples);
575 /*
576 * Low pass filter
577 */
578 FO_1I_D32F32C31_TRC_WRA_01(&pPrivate->pFastCoef->LPCoefs,
579 pTemp,
580 pTemp,
581 (LVM_INT16)NumSamples);
582
583 /*
584 * Process all delay lines
585 */
586
587 for(j = 0; j < NumberOfDelayLines; j++)
588 {
589 pDelayLine = pPrivate->pScratchDelayLine[j];
590
591 /*
592 * All-pass filter with pop and click suppression
593 */
594 /* Get the smoothed, delayed output. Put it in the output buffer */
595 MixSoft_2St_D32C31_SAT(&pPrivate->Mixer_APTaps[j],
596 pPrivate->pOffsetA[j],
597 pPrivate->pOffsetB[j],
598 pDelayLine,
599 (LVM_INT16)NumSamples);
600 /* Re-align the all pass filter delay buffer and copying the fixed delay data \
601 to the AP delay in the process */
602 Copy_Float(&pPrivate->pDelay_T[j][NumSamples],
603 pPrivate->pDelay_T[j],
604 (LVM_INT16)(pPrivate->T[j] - NumSamples)); /* 32-bit data */
605 /* Apply the smoothed feedback and save to fixed delay input (currently empty) */
606 MixSoft_1St_D32C31_WRA(&pPrivate->Mixer_SGFeedback[j],
607 pDelayLine,
608 &pPrivate->pDelay_T[j][pPrivate->T[j] - NumSamples],
609 (LVM_INT16)NumSamples);
610 /* Sum into the AP delay line */
611 Mac3s_Sat_Float(&pPrivate->pDelay_T[j][pPrivate->T[j] - NumSamples],
612 -1.0f, /* Invert since the feedback coefficient is negative */
613 &pPrivate->pDelay_T[j][pPrivate->Delay_AP[j] - NumSamples],
614 (LVM_INT16)NumSamples);
615 /* Apply smoothed feedforward sand save to fixed delay input (currently empty) */
616 MixSoft_1St_D32C31_WRA(&pPrivate->Mixer_SGFeedforward[j],
617 &pPrivate->pDelay_T[j][pPrivate->Delay_AP[j] - NumSamples],
618 &pPrivate->pDelay_T[j][pPrivate->T[j] - NumSamples],
619 (LVM_INT16)NumSamples);
620 /* Sum into the AP output */
621 Mac3s_Sat_Float(&pPrivate->pDelay_T[j][pPrivate->T[j] - NumSamples],
622 1.0f,
623 pDelayLine,
624 (LVM_INT16)NumSamples);
625
626 /*
627 * Feedback gain
628 */
629 MixSoft_1St_D32C31_WRA(&pPrivate->FeedbackMixer[j], pDelayLine, pDelayLine, NumSamples);
630
631 /*
632 * Low pass filter
633 */
634 FO_1I_D32F32C31_TRC_WRA_01(&pPrivate->pFastCoef->RevLPCoefs[j],
635 pDelayLine,
636 pDelayLine,
637 (LVM_INT16)NumSamples);
638 }
639
640 /*
641 * Apply rotation matrix and delay samples
642 */
643 for(j = 0; j < NumberOfDelayLines; j++)
644 {
645
646 Copy_Float(pTemp,
647 pDelayLineInput,
648 (LVM_INT16)(NumSamples));
649 /*
650 * Rotation matrix mix
651 */
652 switch(j)
653 {
654 case 3:
655 /*
656 * Add delay line 1 and 2 contribution
657 */
658 Mac3s_Sat_Float(pPrivate->pScratchDelayLine[1], -1.0f,
659 pDelayLineInput, (LVM_INT16)NumSamples);
660 Mac3s_Sat_Float(pPrivate->pScratchDelayLine[2], -1.0f,
661 pDelayLineInput, (LVM_INT16)NumSamples);
662
663 break;
664 case 2:
665
666 /*
667 * Add delay line 0 and 3 contribution
668 */
669 Mac3s_Sat_Float(pPrivate->pScratchDelayLine[0], -1.0f,
670 pDelayLineInput, (LVM_INT16)NumSamples);
671 Mac3s_Sat_Float(pPrivate->pScratchDelayLine[3], -1.0f,
672 pDelayLineInput, (LVM_INT16)NumSamples);
673
674 break;
675 case 1:
676 if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4)
677 {
678 /*
679 * Add delay line 0 and 3 contribution
680 */
681 Mac3s_Sat_Float(pPrivate->pScratchDelayLine[0], -1.0f,
682 pDelayLineInput, (LVM_INT16)NumSamples);
683 Add2_Sat_Float(pPrivate->pScratchDelayLine[3], pDelayLineInput,
684 (LVM_INT16)NumSamples);
685
686 }
687 else
688 {
689 /*
690 * Add delay line 0 and 1 contribution
691 */
692 Mac3s_Sat_Float(pPrivate->pScratchDelayLine[0], -1.0f,
693 pDelayLineInput, (LVM_INT16)NumSamples);
694 Mac3s_Sat_Float(pPrivate->pScratchDelayLine[1], -1.0f,
695 pDelayLineInput, (LVM_INT16)NumSamples);
696
697 }
698 break;
699 case 0:
700 if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_4)
701 {
702 /*
703 * Add delay line 1 and 2 contribution
704 */
705 Mac3s_Sat_Float(pPrivate->pScratchDelayLine[1], -1.0f,
706 pDelayLineInput, (LVM_INT16)NumSamples);
707 Add2_Sat_Float(pPrivate->pScratchDelayLine[2], pDelayLineInput,
708 (LVM_INT16)NumSamples);
709
710 }
711 else if(pPrivate->InstanceParams.NumDelays == LVREV_DELAYLINES_2)
712 {
713 /*
714 * Add delay line 0 and 1 contribution
715 */
716 Add2_Sat_Float(pPrivate->pScratchDelayLine[0], pDelayLineInput,
717 (LVM_INT16)NumSamples);
718 Mac3s_Sat_Float(pPrivate->pScratchDelayLine[1], -1.0f,
719 pDelayLineInput, (LVM_INT16)NumSamples);
720
721 }
722 else
723 {
724 /*
725 * Add delay line 0 contribution
726 */
727
728 /* SOURCE DESTINATION*/
729 Add2_Sat_Float(pPrivate->pScratchDelayLine[0], pDelayLineInput,
730 (LVM_INT16)NumSamples);
731 }
732 break;
733 default:
734 break;
735 }
736
737 /*
738 * Delay samples
739 */
740 Copy_Float(pDelayLineInput,
741 &pPrivate->pDelay_T[j][pPrivate->T[j] - NumSamples],
742 (LVM_INT16)(NumSamples)); /* 32-bit data */
743 }
744
745
746 /*
747 * Create stereo output
748 */
749 switch(pPrivate->InstanceParams.NumDelays)
750 {
751 case LVREV_DELAYLINES_4:
752 Add2_Sat_Float(pPrivate->pScratchDelayLine[3],
753 pPrivate->pScratchDelayLine[0],
754 (LVM_INT16)NumSamples);
755 Add2_Sat_Float(pPrivate->pScratchDelayLine[2],
756 pPrivate->pScratchDelayLine[1],
757 (LVM_INT16)NumSamples);
758
759
760 JoinTo2i_Float(pPrivate->pScratchDelayLine[0],
761 pPrivate->pScratchDelayLine[1],
762 pTemp,
763 (LVM_INT16)NumSamples);
764
765
766 break;
767 case LVREV_DELAYLINES_2:
768
769 Copy_Float(pPrivate->pScratchDelayLine[1],
770 pScratch,
771 (LVM_INT16)(NumSamples));
772
773 Mac3s_Sat_Float(pPrivate->pScratchDelayLine[0],
774 -1.0f,
775 pScratch,
776 (LVM_INT16)NumSamples);
777
778 Add2_Sat_Float(pPrivate->pScratchDelayLine[1],
779 pPrivate->pScratchDelayLine[0],
780 (LVM_INT16)NumSamples);
781
782
783 JoinTo2i_Float(pPrivate->pScratchDelayLine[0],
784 pScratch,
785 pTemp,
786 (LVM_INT16)NumSamples);
787 break;
788 case LVREV_DELAYLINES_1:
789 MonoTo2I_Float(pPrivate->pScratchDelayLine[0],
790 pTemp,
791 (LVM_INT16)NumSamples);
792 break;
793 default:
794 break;
795 }
796
797
798 /*
799 * Dry/wet mixer
800 */
801
802 size = (LVM_INT16)(NumSamples << 1);
803 MixSoft_2St_D32C31_SAT(&pPrivate->BypassMixer,
804 pTemp,
805 pTemp,
806 pOutput,
807 size);
808
809 /* Apply Gain*/
810
811 Shift_Sat_Float(LVREV_OUTPUTGAIN_SHIFT,
812 pOutput,
813 pOutput,
814 size);
815
816 MixSoft_1St_D32C31_WRA(&pPrivate->GainMixer,
817 pOutput,
818 pOutput,
819 size);
820
821 return;
822 }
823 #endif
824 /* End of file */
825
826