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