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