summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/codecs/aacdec/long_term_prediction.cpp
blob: 69e4c466fedf1ca80fc74c174a1adde155fbb691 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
/* ------------------------------------------------------------------
 * Copyright (C) 1998-2009 PacketVideo
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 * -------------------------------------------------------------------
 */
/*

 Pathname: long_term_prediction.c

------------------------------------------------------------------------------
 REVISION HISTORY

 Description: Made changes based on comments and experiment results.

 Description: Passed in buffer sizes based on review comments and prototype
              agreements.

 Description: 1. Passed in "weight_index" instead of "weight".
              2. Added weight table.

 Description: 1. Removed some passed in buffer size variables since they are
                 not used for long window.
              2. Modified comments format.

 Description:
    Modified casting to ensure proper operations for different platforms

 Description:
    Implemented circular buffer techniques, which save 4096 memmoves per
    frame.

 Description:
    Implemented some optimizations found during the code review of this
    module.  The optimizations related to the rules on the range of
    ltp_buffer_index and num_samples, which allows for a simpler
    code construct to be used in the processing of the predicted samples.

 Description:
    Add max calculation on the filter implementation, this to eliminate
    function buffer_adaptation() on the time to frequency transformation.
    Function interface changed. It now return the amount of shifting needed
    to garb only the top 16 MSB.

 Description:
     Replace clearing memory with for-loop with pvmemset function

 Description:

------------------------------------------------------------------------------
 INPUT AND OUTPUT DEFINITIONS

 Inputs:
    win_seq = type of window sequence (WINDOW_SEQUENCE).

    weight_index = index (Int) of LTP coefficient table for all windows in
                   current frame.

    delay = buffer (Int) containing delays for each window.

    buffer = history buffer (Int16) containing the reconstructed time domain
             signals of previous frames.

    buffer_offset = value (Int) that indicates the location of the first
                    element in the LTP circular buffer.  (Either 0 or 1024)

    time_quant    = filterbank buffer (Int32) This buffer is used by the
                    filterbank, but it's first 1024 elements are equivalent
                    to the last 1024 elements in the conventionally
                    implemented LTP buffer.  Using this buffer directly avoids
                    costly duplication of memory.

    predicted_samples = buffer (Int32) with length of 2048 to hold
                        predicted time domain signals.

    buffer_index = index into buffer where the first sample of data from
                   the frame (t-2) (two frames ago) resides.  (Int)

    frame_length = length of one frame, type of Int.

 Local Stores/Buffers/Pointers Needed:
    None

 Global Stores/Buffers/Pointers Needed:
    None

 Outputs:
    Amount of shifting needed to grab the top 16 MSB from teh predicted buffer

 Pointers and Buffers Modified:
    predicted_samples contents are the newly calculated predicted time
    domain signals

 Local Stores Modified:
    None

 Global Stores Modified:
    None

------------------------------------------------------------------------------
 FUNCTION DESCRIPTION

 Long term prediction (LTP) is used to reduce the redundancy of a signal
 between successive coding frames. This function performs prediction by
 applying 1-tap IIR filtering to calculate the predicted time domain
 signals of current frame from previous reconstructed frames stored in
 time domain history buffer.

 The equation used for IIR filter is as following.

            y(n) = weight * x(n - delay)

    where   y(n) ----- predicted time domain signals
            x(n) ----- reconstructed time domain signals
            weight ----- LTP coefficient
            delay ----- optimal delay from 0 to 2047

------------------------------------------------------------------------------
 REQUIREMENTS

 None

------------------------------------------------------------------------------
 REFERENCES

 (1) ISO/IEC 14496-3:1999(E)
     Part 3: Audio
        Subpart 4.6.6   Long Term Prediction (LTP)

 (2) MPEG-2 NBC Audio Decoder
     "This software module was originally developed by Nokia in the course
     of development of the MPEG-2 AAC/MPEG-4 Audio standard ISO/IEC13818-7,
     14496-1, 2 and 3. This software module is an implementation of a part
     of one or more MPEG-2 AAC/MPEG-4 Audio tools as specified by the MPEG-2
     aac/MPEG-4 Audio standard. ISO/IEC  gives users of the MPEG-2aac/MPEG-4
     Audio standards free license to this software module or modifications
     thereof for use in hardware or software products claiming conformance
     to the MPEG-2 aac/MPEG-4 Audio  standards. Those intending to use this
     software module in hardware or software products are advised that this
     use may infringe existing patents. The original developer of this
     software module, the subsequent editors and their companies, and ISO/IEC
     have no liability for use of this software module or modifications
     thereof in an implementation. Copyright is not released for non MPEG-2
     aac/MPEG-4 Audio conforming products. The original developer retains
     full right to use the code for the developer's own purpose, assign or
     donate the code to a third party and to inhibit third party from using
     the code for non MPEG-2 aac/MPEG-4 Audio conforming products. This
     copyright notice must be included in all copies or derivative works.
     Copyright (c)1997.

------------------------------------------------------------------------------
 PSEUDO-CODE

    pPredicted_samples = &predicted_samples[0];

    weight = codebook[weight_index];

    IF (win_seq != EIGHT_SHORT_SEQUENCE)
    THEN

        block_length = frame_length << 1;

        lag = delay[0];

        j = block_length - lag;

        IF (lag < frame_length)
        THEN

            num_samples = frame_length + lag;

        ELSE

            num_samples = block_length;

        ENDIF

        pBuffer = &buffer[j];

        FOR (i = num_samples; i>0; i--)

            *pPredicted_samples = weight * (*pBuffer);
            pPredicted_samples = pPredicted_samples + 1;
            pBuffer = pBuffer + 1;

        ENDFOR

        FOR (i = block_length - num_samples; i>0; i--)

            *pPredicted_samples = 0;
            pPredicted_samples = pPredicted_samples + 1;

        ENDFOR

    ELSE

        FOR (wnd = 0; wnd < short_window_num; wnd++)

            IF (win_prediction_used[wnd] != FALSE)
            THEN

                delay[wnd] = delay[0] + ltp_short_lag[wnd];

                lag = delay[wnd];

                j = wnd*short_block_length - lag;

                IF (lag < short_frame_length)
                THEN

                    num_samples = short_frame_length + lag;

                ELSE

                    num_samples = short_block_length;

                ENDIF

                pBuffer = &buffer[j];

                FOR (i = num_samples; i>0; i--)

                    *pPredicted_samples = weight * (*pBuffer);
                    pPredicted_samples = pPredicted_samples + 1;
                    pBuffer = pBuffer + 1;

                ENDFOR

                FOR (i = short_block_length - num_samples; i>0; i--)

                    *pPredicted_samples = 0;
                    pPredicted_samples = pPredicted_samples + 1;

                ENDFOR

            ELSE

                CALL pv_memset(
                        pPredicted_samples,
                        0,
                        sizeof(*pPredicted_samples)*short_block_length);
                MODIFYING (predicted_samples[]);

                pPredicted_samples = pPredicted_samples + short_block_length;

            ENDIF [ IF (win_prediction_used[wnd] != FALSE) ]

        ENDFOR [ FOR (wnd=0; wnd<short_window_num; wnd++) ]

    ENDIF [ IF (win_seq != EIGHT_SHORT_SEQUENCE) ]

    RETURN

------------------------------------------------------------------------------
 RESOURCES USED
   When the code is written for a specific target processor the
     the resources used should be documented below.

 STACK USAGE: [stack count for this module] + [variable to represent
          stack usage for each subroutine called]

     where: [stack usage variable] = stack usage for [subroutine
         name] (see [filename].ext)

 DATA MEMORY USED: x words

 PROGRAM MEMORY USED: x words

 CLOCK CYCLES: [cycle count equation for this module] + [variable
           used to represent cycle count for each subroutine
           called]

     where: [cycle count variable] = cycle count for [subroutine
        name] (see [filename].ext)

------------------------------------------------------------------------------
*/


/*----------------------------------------------------------------------------
; INCLUDES
----------------------------------------------------------------------------*/
#include "pv_audio_type_defs.h"
#include "e_window_sequence.h"
#include "ltp_common_internal.h"
#include "long_term_prediction.h"
#include "aac_mem_funcs.h"
#include "pv_normalize.h"
#include "window_block_fxp.h"


/*----------------------------------------------------------------------------
; MACROS
; Define module specific macros here
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
; DEFINES
; Include all pre-processor statements here. Include conditional
; compile variables also.
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
; LOCAL FUNCTION DEFINITIONS
; Function Prototype declaration
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
; LOCAL STORE/BUFFER/POINTER DEFINITIONS
; Variable declaration - defined here and used outside this module
----------------------------------------------------------------------------*/
/* Purpose: Codebook for LTP weight coefficients. Stored in Q15 format */
const UInt codebook[CODESIZE] =
{
    18705,  /* 0 */
    22827,  /* 1 */
    26641,  /* 2 */
    29862,  /* 3 */
    32273,  /* 4 */
    34993,  /* 5 */
    39145,  /* 6 */
    44877   /* 7 */
};

/*----------------------------------------------------------------------------
; EXTERNAL FUNCTION REFERENCES
; Declare functions defined elsewhere and referenced in this module
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
; EXTERNAL GLOBAL STORE/BUFFER/POINTER REFERENCES
; Declare variables used in this module but defined elsewhere
----------------------------------------------------------------------------*/

/*----------------------------------------------------------------------------
; FUNCTION CODE
----------------------------------------------------------------------------*/
Int long_term_prediction(
    WINDOW_SEQUENCE     win_seq,
    const Int           weight_index,
    const Int           delay[],
    const Int16         buffer[],
    const Int           buffer_offset,
    const Int32         time_quant[],
    Int32         predicted_samples[],    /* Q15 */
    const Int           frame_length)
{
    /*----------------------------------------------------------------------------
    ; Define all local variables
    ----------------------------------------------------------------------------*/
    /*
     * Window index
     *
     * Int wnd;
     *
     * will be enabled when short window information is available.
     */

    /* Pointer to time domain history buffer */

    const Int16 *pBuffer;

    const Int32 *pTimeQuant = time_quant;

    /* Pointer to array containing predicted samples */
    Int32 *pPredicted_samples;

    Int32   test;
    Int32   datum;

    /* IIR coefficient with Q15 format */
    UInt    weight;

    /* Length of one block (two frames) */
    Int     block_length;

    Int     shift;
    Int     k;
    Int     ltp_buffer_index;
    Int     jump_point;
    Int     lag;
    Int     num_samples;

    Int32   max = 0;

    /*----------------------------------------------------------------------------
    ; Function body here
    ----------------------------------------------------------------------------*/
    /* Initialize pointers */
    pPredicted_samples = &predicted_samples[0];

    weight = codebook[weight_index];

    /****************************************/
    /* LTP decoding process for long window */
    /****************************************/

    if (win_seq != EIGHT_SHORT_SEQUENCE)
    {
        /****************************************************/
        /* Prediction based on previous time domain signals */
        /****************************************************/
        block_length = frame_length << 1;

        /* Calculate time lag for 1-tap IIR filter */
        lag = delay[0];

        ltp_buffer_index = block_length - lag;

        /* Calculate number of samples used in IIR filter */
        if (lag < frame_length)
        {
            num_samples = frame_length + lag;
        }
        else
        {
            num_samples = block_length;
        }


        /*
         * Calculate the predicted time domain signals from the
         * reconstructed time domain signals of previous frames.
         */

        /* The data is stored in TWO buffers, either as...
         *
         *                                       [   t ==  0  ]
         *
         * [   t == -1   ][   t == -2   ]
         *
         * OR...
         *                                       [   t ==  0  ]
         *
         * [   t == -2   ][   t == -1   ]
         *
         *
         *
         * In the first case, all of the buffers are non-contiguous,
         * and each must be handled separately.  Code for this first case
         * will function correctly for both cases.
         *
         * In the second case, the buffers storing t == -2, and t == -1
         * data are contiguous, and an optimization could take advantage
         * of this, at the cost of an increase in code size for this function.
         */

        /* Decrement block_length by num_samples.  This is important
         * for the loop at the end of the "ACCESS DATA IN THE LTP BUFFERS"
         * section that sets all remaining samples in the block to zero.
         */

        block_length -= num_samples;






        /*
         ************************************ ACCESS DATA IN THE LTP BUFFERS
         */

        /*
         * This section of the code handles the t == -2
         * buffer, which corresponds to 0 <= ltp_buffer_index < 1024
         *
         * BUFFER t == -2
         *
         * [0][][][][][][][][][][][...][][][][][][][][][][][][1023]
         *
         */

        jump_point = (frame_length - ltp_buffer_index);

        if (jump_point > 0)
        {
            pBuffer = &(buffer[ltp_buffer_index + buffer_offset]);

            for (k = jump_point; k > 0; k--)
            {
                /* Q15 = Q15 * Q0 */
                test = (Int32) weight * (*(pBuffer++));
                *(pPredicted_samples++) =  test;
                max                   |= (test >> 31) ^ test;
            }

            num_samples -= jump_point;

            ltp_buffer_index += jump_point;
        }

        /*
         * This section of the code handles the t == -1
         * buffer, which corresponds to 1024 <= ltp_buffer_index < 2048
         *
         * BUFFER t == -1
         *
         * [1024][][][][][][][][][][][...][][][][][][][][][][][][2047]
         *
         */

        jump_point = 2 * frame_length - ltp_buffer_index;

        pBuffer = &(buffer[ltp_buffer_index - buffer_offset]);

        if (num_samples < jump_point)
        {
            jump_point = num_samples;
        }

        for (k = jump_point; k > 0; k--)
        {
            /* Q15 = Q15 * Q0 */
            test = (Int32) weight * (*(pBuffer++));
            *(pPredicted_samples++) =  test;
            max                   |= (test >> 31) ^ test;
        }

        num_samples -= jump_point;

        ltp_buffer_index += jump_point;

        /*
         * This section of the code handles the t == 0
         * buffer, which corresponds to 2048 <= ltp_buffer_index < 3072
         *
         * BUFFER t == 0
         *
         * [2048][][][][][][][][][][][...][][][][][][][][][][][][3071]
         *
         */
        for (k = num_samples; k > 0; k--)
        {

            datum = *(pTimeQuant++) >> SCALING;

            /*
             * Limit the values in the 32-bit filterbank's buffer to
             * 16-bit resolution.
             *
             * Value's greater than 32767 or less than -32768 are saturated
             * to 32767 and -32768, respectively.
             */

            test                    = (Int32)datum * weight;
            *(pPredicted_samples++) =  test;
            max                    |= (test >> 31) ^ test;

        }

        /* Set any remaining samples in the block to 0. */

        pv_memset(
            pPredicted_samples,
            0,
            block_length*sizeof(*pPredicted_samples));

    } /* if (win_seq != EIGHT_SHORT_SEQUENCE) */


    /*****************************************/
    /* LTP decoding process for short window */
    /*****************************************/

    /*
     * For short window LTP, since there is no "ltp_short_lag"
     * information being passed, the following code for short
     * window LTP will be applied in the future when those
     * information are available.
     */

    /*
     *----------------------------------------------------------------------------
     *  else
     *  {
     *      for (wnd = 0; wnd < short_window_num; wnd++)
     *      {
     *          if (win_prediction_used[wnd] != FALSE)
     *          {
     *              delay[wnd] = delay[0] + ltp_short_lag[wnd];
     *
     *              lag = delay[wnd];
     *
     *              j = wnd*short_block_length - lag;
     *
     *              if (lag < short_frame_length)
     *              {
     *                  num_samples = short_frame_length + lag;
     *              }
     *              else
     *              {
     *                  num_samples = short_block_length;
     *              }
     *
     *              pBuffer = &buffer[j];
     *
     *              for(i = num_samples; i>0; i--)
     *              {
     *                  *(pPredicted_samples++) = weight * (*(pBuffer++));
     *              }
     *
     *              for(i = short_block_length - num_samples; i>0; i--)
     *              {
     *                  *(pPredicted_samples++) = 0;
     *              }
     *          }
     *          else
     *          {
     *              pv_memset(
     *                  pPredicted_samples,
     *                  0,
     *                  sizeof(*pPredicted_samples)*short_block_length);
     *
     *              pPredicted_samples += short_block_length;
     *          }
     *      }
     *  }
     *----------------------------------------------------------------------------
     */

    shift = 16 - pv_normalize(max);

    if (shift < 0)
    {
        shift = 0;
    }

    /*----------------------------------------------------------------------------
    ; Return nothing or data or data pointer
    ----------------------------------------------------------------------------*/
    return (shift);
} /* long_term_prediction */