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