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