1/* -----------------------------------------------------------------------------
2Software License for The Fraunhofer FDK AAC Codec Library for Android
3
4© Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
5Forschung e.V. All rights reserved.
6
7 1.    INTRODUCTION
8The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software
9that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding
10scheme for digital audio. This FDK AAC Codec software is intended to be used on
11a wide variety of Android devices.
12
13AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient
14general perceptual audio codecs. AAC-ELD is considered the best-performing
15full-bandwidth communications codec by independent studies and is widely
16deployed. AAC has been standardized by ISO and IEC as part of the MPEG
17specifications.
18
19Patent licenses for necessary patent claims for the FDK AAC Codec (including
20those of Fraunhofer) may be obtained through Via Licensing
21(www.vialicensing.com) or through the respective patent owners individually for
22the purpose of encoding or decoding bit streams in products that are compliant
23with the ISO/IEC MPEG audio standards. Please note that most manufacturers of
24Android devices already license these patent claims through Via Licensing or
25directly from the patent owners, and therefore FDK AAC Codec software may
26already be covered under those patent licenses when it is used for those
27licensed purposes only.
28
29Commercially-licensed AAC software libraries, including floating-point versions
30with enhanced sound quality, are also available from Fraunhofer. Users are
31encouraged to check the Fraunhofer website for additional applications
32information and documentation.
33
342.    COPYRIGHT LICENSE
35
36Redistribution and use in source and binary forms, with or without modification,
37are permitted without payment of copyright license fees provided that you
38satisfy the following conditions:
39
40You must retain the complete text of this software license in redistributions of
41the FDK AAC Codec or your modifications thereto in source code form.
42
43You must retain the complete text of this software license in the documentation
44and/or other materials provided with redistributions of the FDK AAC Codec or
45your modifications thereto in binary form. You must make available free of
46charge copies of the complete source code of the FDK AAC Codec and your
47modifications thereto to recipients of copies in binary form.
48
49The name of Fraunhofer may not be used to endorse or promote products derived
50from this library without prior written permission.
51
52You may not charge copyright license fees for anyone to use, copy or distribute
53the FDK AAC Codec software or your modifications thereto.
54
55Your modified versions of the FDK AAC Codec must carry prominent notices stating
56that you changed the software and the date of any change. For modified versions
57of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android"
58must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK
59AAC Codec Library for Android."
60
613.    NO PATENT LICENSE
62
63NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without
64limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.
65Fraunhofer provides no warranty of patent non-infringement with respect to this
66software.
67
68You may use this FDK AAC Codec software or modifications thereto only for
69purposes that are authorized by appropriate patent licenses.
70
714.    DISCLAIMER
72
73This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright
74holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
75including but not limited to the implied warranties of merchantability and
76fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
77CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary,
78or consequential damages, including but not limited to procurement of substitute
79goods or services; loss of use, data, or profits, or business interruption,
80however caused and on any theory of liability, whether in contract, strict
81liability, or tort (including negligence), arising in any way out of the use of
82this software, even if advised of the possibility of such damage.
83
845.    CONTACT INFORMATION
85
86Fraunhofer Institute for Integrated Circuits IIS
87Attention: Audio and Multimedia Departments - FDK AAC LL
88Am Wolfsmantel 33
8991058 Erlangen, Germany
90
91www.iis.fraunhofer.de/amm
92amm-info@iis.fraunhofer.de
93----------------------------------------------------------------------------- */
94
95/*********************** MPEG surround encoder library *************************
96
97   Author(s):   Max Neuendorf
98
99   Description: Encoder Library Interface
100                Get windows for framing
101
102*******************************************************************************/
103
104/**************************************************************************/ /**
105   \file
106   Description of file contents
107 ******************************************************************************/
108
109/* Includes ******************************************************************/
110#include "sacenc_framewindowing.h"
111#include "sacenc_vectorfunctions.h"
112
113/* Defines *******************************************************************/
114
115/* Data Types ****************************************************************/
116typedef struct T_FRAMEWINDOW {
117  INT nTimeSlotsMax;
118  INT bFrameKeep;
119  INT startSlope;
120  INT stopSlope;
121  INT startRect;
122  INT stopRect;
123
124  INT taperAnaLen;
125  INT taperSynLen;
126  FIXP_WIN pTaperAna__FDK[MAX_TIME_SLOTS];
127  FIXP_WIN pTaperSyn__FDK[MAX_TIME_SLOTS];
128
129} FRAMEWINDOW;
130
131typedef enum {
132  FIX_INVALID = -1,
133  FIX_RECT_SMOOTH = 0,
134  FIX_SMOOTH_RECT = 1,
135  FIX_LARGE_SMOOTH = 2,
136  FIX_RECT_TRIANG = 3
137
138} FIX_TYPE;
139
140typedef enum {
141  VAR_INVALID = -1,
142  VAR_HOLD = 0,
143  VAR_ISOLATE = 1
144
145} VAR_TYPE;
146
147/* Constants *****************************************************************/
148
149/* Function / Class Declarations *********************************************/
150
151/* Function / Class Definition ***********************************************/
152static void calcTaperWin(FIXP_WIN *pTaperWin, INT timeSlots) {
153  FIXP_DBL x;
154  int i, scale;
155
156  for (i = 0; i < timeSlots; i++) {
157    x = fDivNormHighPrec((FIXP_DBL)i, (FIXP_DBL)timeSlots, &scale);
158
159    if (scale < 0) {
160      pTaperWin[i] = FX_DBL2FX_WIN(x >> (-scale));
161    } else {
162      pTaperWin[i] = FX_DBL2FX_WIN(x << (scale));
163    }
164  }
165  pTaperWin[timeSlots] = FX_DBL2FX_WIN((FIXP_DBL)MAXVAL_DBL);
166}
167
168FDK_SACENC_ERROR fdk_sacenc_frameWindow_Create(
169    HANDLE_FRAMEWINDOW *phFrameWindow) {
170  FDK_SACENC_ERROR error = SACENC_OK;
171
172  if (NULL == phFrameWindow) {
173    error = SACENC_INVALID_HANDLE;
174  } else {
175    /* Memory Allocation */
176    FDK_ALLOCATE_MEMORY_1D(*phFrameWindow, 1, FRAMEWINDOW);
177  }
178  return error;
179
180bail:
181  fdk_sacenc_frameWindow_Destroy(phFrameWindow);
182  return ((SACENC_OK == error) ? SACENC_MEMORY_ERROR : error);
183}
184
185FDK_SACENC_ERROR fdk_sacenc_frameWindow_Init(
186    HANDLE_FRAMEWINDOW hFrameWindow,
187    const FRAMEWINDOW_CONFIG *const pFrameWindowConfig) {
188  FDK_SACENC_ERROR error = SACENC_OK;
189
190  if ((hFrameWindow == NULL) || (pFrameWindowConfig == NULL)) {
191    error = SACENC_INVALID_HANDLE;
192  } else if (pFrameWindowConfig->nTimeSlotsMax < 0) {
193    error = SACENC_INIT_ERROR;
194  } else {
195    int ts;
196    hFrameWindow->bFrameKeep = pFrameWindowConfig->bFrameKeep;
197    hFrameWindow->nTimeSlotsMax = pFrameWindowConfig->nTimeSlotsMax;
198
199    FIXP_WIN winMaxVal = FX_DBL2FX_WIN((FIXP_DBL)MAXVAL_DBL);
200    int timeSlots = pFrameWindowConfig->nTimeSlotsMax;
201    {
202      hFrameWindow->startSlope = 0;
203      hFrameWindow->stopSlope = ((3 * timeSlots) >> 1) - 1;
204      hFrameWindow->startRect = timeSlots >> 1;
205      hFrameWindow->stopRect = timeSlots;
206      calcTaperWin(hFrameWindow->pTaperSyn__FDK, timeSlots >> 1);
207      hFrameWindow->taperSynLen = timeSlots >> 1;
208    }
209
210    /* Calculate Taper for non-rect. ana. windows */
211    hFrameWindow->taperAnaLen =
212        hFrameWindow->startRect - hFrameWindow->startSlope;
213    for (ts = 0; ts < hFrameWindow->taperAnaLen; ts++) {
214      { hFrameWindow->pTaperAna__FDK[ts] = winMaxVal; }
215    }
216  }
217
218  return error;
219}
220
221FDK_SACENC_ERROR fdk_sacenc_frameWindow_Destroy(
222    HANDLE_FRAMEWINDOW *phFrameWindow) {
223  FDK_SACENC_ERROR error = SACENC_OK;
224
225  if ((NULL != phFrameWindow) && (NULL != *phFrameWindow)) {
226    FDKfree(*phFrameWindow);
227    *phFrameWindow = NULL;
228  }
229  return error;
230}
231
232static FDK_SACENC_ERROR FrameWinList_Reset(FRAMEWIN_LIST *const pFrameWinList) {
233  FDK_SACENC_ERROR error = SACENC_OK;
234
235  if (NULL == pFrameWinList) {
236    error = SACENC_INVALID_HANDLE;
237  } else {
238    int k = 0;
239    for (k = 0; k < MAX_NUM_PARAMS; k++) {
240      pFrameWinList->dat[k].slot = -1;
241      pFrameWinList->dat[k].hold = FW_INTP;
242    }
243    pFrameWinList->n = 0;
244  }
245  return error;
246}
247
248static FDK_SACENC_ERROR FrameWindowList_Add(FRAMEWIN_LIST *const pFrameWinList,
249                                            const INT slot,
250                                            const FW_SLOTTYPE hold) {
251  FDK_SACENC_ERROR error = SACENC_OK;
252
253  if (NULL == pFrameWinList) {
254    error = SACENC_INVALID_HANDLE;
255  } else {
256    if (pFrameWinList->n >= MAX_NUM_PARAMS) { /* Place left in List ?*/
257      error = SACENC_PARAM_ERROR;
258    } else if (pFrameWinList->n > 0 &&
259               pFrameWinList->dat[pFrameWinList->n - 1].slot - slot > 0) {
260      error = SACENC_PARAM_ERROR;
261    } else {
262      pFrameWinList->dat[pFrameWinList->n].slot = slot;
263      pFrameWinList->dat[pFrameWinList->n].hold = hold;
264      pFrameWinList->n++;
265    }
266  }
267  return error;
268}
269
270static FDK_SACENC_ERROR FrameWindowList_Remove(
271    FRAMEWIN_LIST *const pFrameWinList, const INT idx) {
272  FDK_SACENC_ERROR error = SACENC_OK;
273
274  if (NULL == pFrameWinList) {
275    error = SACENC_INVALID_HANDLE;
276  } else {
277    int k = 0;
278    if (idx < 0 || idx >= MAX_NUM_PARAMS) {
279      error = SACENC_PARAM_ERROR;
280    } else if (pFrameWinList->n > 0) {
281      if (idx == MAX_NUM_PARAMS - 1) {
282        pFrameWinList->dat[idx].slot = -1;
283        pFrameWinList->dat[idx].hold = FW_INTP;
284      } else {
285        for (k = idx; k < MAX_NUM_PARAMS - 1; k++) {
286          pFrameWinList->dat[k] = pFrameWinList->dat[k + 1];
287        }
288      }
289      pFrameWinList->n--;
290    }
291  }
292  return error;
293}
294
295static FDK_SACENC_ERROR FrameWindowList_Limit(
296    FRAMEWIN_LIST *const pFrameWinList, const INT ll /*lower limit*/,
297    const INT ul /*upper limit*/
298) {
299  FDK_SACENC_ERROR error = SACENC_OK;
300
301  if (NULL == pFrameWinList) {
302    error = SACENC_INVALID_HANDLE;
303  } else {
304    int k = 0;
305    for (k = 0; k < pFrameWinList->n; k++) {
306      if (pFrameWinList->dat[k].slot < ll || pFrameWinList->dat[k].slot > ul) {
307        FrameWindowList_Remove(pFrameWinList, k);
308        --k;
309      }
310    }
311  }
312  return error;
313}
314
315FDK_SACENC_ERROR fdk_sacenc_frameWindow_GetWindow(
316    HANDLE_FRAMEWINDOW hFrameWindow, INT tr_pos[MAX_NUM_PARAMS],
317    const INT timeSlots, FRAMINGINFO *const pFramingInfo,
318    FIXP_WIN *pWindowAna__FDK[MAX_NUM_PARAMS],
319    FRAMEWIN_LIST *const pFrameWinList, const INT avoid_keep) {
320  FDK_SACENC_ERROR error = SACENC_OK;
321
322  if ((hFrameWindow == NULL) || (tr_pos == NULL) || (pFramingInfo == NULL) ||
323      (pFrameWinList == NULL) || (pWindowAna__FDK == NULL)) {
324    error = SACENC_INVALID_HANDLE;
325  } else {
326    const VAR_TYPE varType = VAR_HOLD;
327    const int tranL = 4;
328    int winCnt = 0;
329    int w, ps;
330
331    int startSlope = hFrameWindow->startSlope;
332    int stopSlope = hFrameWindow->stopSlope;
333    int startRect = hFrameWindow->startRect;
334    int stopRect = hFrameWindow->stopRect;
335    int taperAnaLen = hFrameWindow->taperAnaLen;
336
337    FIXP_WIN winMaxVal = FX_DBL2FX_WIN((FIXP_DBL)MAXVAL_DBL);
338    FIXP_WIN applyRightWindowGain__FDK[MAX_NUM_PARAMS];
339    FIXP_WIN *pTaperAna__FDK = hFrameWindow->pTaperAna__FDK;
340
341    /* sanity check */
342    for (ps = 0; ps < MAX_NUM_PARAMS; ps++) {
343      if (pWindowAna__FDK[ps] == NULL) {
344        error = SACENC_INVALID_HANDLE;
345        goto bail;
346      }
347    }
348
349    if ((timeSlots > hFrameWindow->nTimeSlotsMax) || (timeSlots < 0)) {
350      error = SACENC_INVALID_CONFIG;
351      goto bail;
352    }
353
354    /* Reset */
355    if (SACENC_OK != (error = FrameWinList_Reset(pFrameWinList))) goto bail;
356
357    FDKmemclear(applyRightWindowGain__FDK, sizeof(applyRightWindowGain__FDK));
358
359    if (tr_pos[0] > -1) { /* Transients in first (left) half? */
360      int p_l = tr_pos[0];
361      winCnt = 0;
362
363      /* Create Parameter Positions */
364      switch (varType) {
365        case VAR_HOLD:
366          if (SACENC_OK !=
367              (error = FrameWindowList_Add(pFrameWinList, p_l - 1, FW_HOLD)))
368            goto bail;
369          if (SACENC_OK !=
370              (error = FrameWindowList_Add(pFrameWinList, p_l, FW_INTP)))
371            goto bail;
372          break;
373        case VAR_ISOLATE:
374          if (SACENC_OK !=
375              (error = FrameWindowList_Add(pFrameWinList, p_l - 1, FW_HOLD)))
376            goto bail;
377          if (SACENC_OK !=
378              (error = FrameWindowList_Add(pFrameWinList, p_l, FW_INTP)))
379            goto bail;
380          if (SACENC_OK != (error = FrameWindowList_Add(pFrameWinList,
381                                                        p_l + tranL, FW_HOLD)))
382            goto bail;
383          if (SACENC_OK != (error = FrameWindowList_Add(
384                                pFrameWinList, p_l + tranL + 1, FW_INTP)))
385            goto bail;
386          break;
387        default:
388          error = SACENC_INVALID_CONFIG;
389          break;
390      }
391
392      /* Outside of frame? => Kick Out */
393      if (SACENC_OK !=
394          (error = FrameWindowList_Limit(pFrameWinList, 0, timeSlots - 1)))
395        goto bail;
396
397      /* Add timeSlots as temporary border for window creation */
398      if (SACENC_OK !=
399          (error = FrameWindowList_Add(pFrameWinList, timeSlots - 1, FW_HOLD)))
400        goto bail;
401
402      /* Create Windows */
403      for (ps = 0; ps < pFrameWinList->n - 1; ps++) {
404        if (FW_HOLD != pFrameWinList->dat[ps].hold) {
405          int const start = pFrameWinList->dat[ps].slot;
406          int const stop = pFrameWinList->dat[ps + 1].slot;
407
408          /* Analysis Window */
409          FDKmemset_flex(pWindowAna__FDK[winCnt], FX_DBL2FX_WIN((FIXP_DBL)0),
410                         start);
411          FDKmemset_flex(&pWindowAna__FDK[winCnt][start], winMaxVal,
412                         stop - start + 1);
413          FDKmemset_flex(&pWindowAna__FDK[winCnt][stop + 1],
414                         FX_DBL2FX_WIN((FIXP_DBL)0), timeSlots - stop - 1);
415
416          applyRightWindowGain__FDK[winCnt] =
417              pWindowAna__FDK[winCnt][timeSlots - 1];
418          winCnt++;
419        }
420      } /* ps */
421
422      /* Pop temporary frame border */
423      if (SACENC_OK !=
424          (error = FrameWindowList_Remove(pFrameWinList, pFrameWinList->n - 1)))
425        goto bail;
426    } else { /* No transient in left half of ana. window */
427      winCnt = 0;
428
429      /* Add paramter set at end of frame */
430      if (SACENC_OK !=
431          (error = FrameWindowList_Add(pFrameWinList, timeSlots - 1, FW_INTP)))
432        goto bail;
433      /* Analysis Window */
434      FDKmemset_flex(pWindowAna__FDK[winCnt], FX_DBL2FX_WIN((FIXP_DBL)0),
435                     startSlope);
436      FDKmemcpy_flex(&pWindowAna__FDK[winCnt][startSlope], 1, pTaperAna__FDK, 1,
437                     taperAnaLen);
438      FDKmemset_flex(&pWindowAna__FDK[winCnt][startRect], winMaxVal,
439                     timeSlots - startRect);
440
441      applyRightWindowGain__FDK[winCnt] = winMaxVal;
442      winCnt++;
443    } /* if (tr_pos[0] > -1) */
444
445    for (w = 0; w < winCnt; w++) {
446      if (applyRightWindowGain__FDK[w] > (FIXP_WIN)0) {
447        if (tr_pos[1] > -1) { /* Transients in second (right) half? */
448          int p_r = tr_pos[1];
449
450          /* Analysis Window */
451          FDKmemset_flex(&pWindowAna__FDK[w][timeSlots], winMaxVal,
452                         p_r - timeSlots);
453          FDKmemset_flex(&pWindowAna__FDK[w][p_r], FX_DBL2FX_WIN((FIXP_DBL)0),
454                         2 * timeSlots - p_r);
455
456        } else { /* No transient in right half of ana. window */
457          /* Analysis Window */
458          FDKmemset_flex(&pWindowAna__FDK[w][timeSlots], winMaxVal,
459                         stopRect - timeSlots + 1);
460          FDKmemcpy_flex(&pWindowAna__FDK[w][stopRect], 1,
461                         &pTaperAna__FDK[taperAnaLen - 1], -1, taperAnaLen);
462          FDKmemset_flex(&pWindowAna__FDK[w][stopSlope + 1],
463                         FX_DBL2FX_WIN((FIXP_DBL)0),
464                         2 * timeSlots - stopSlope - 1);
465
466        } /* if (tr_pos[1] > -1) */
467
468        /* Weight */
469        if (applyRightWindowGain__FDK[w] < winMaxVal) {
470          int ts;
471          for (ts = 0; ts < timeSlots; ts++) {
472            pWindowAna__FDK[w][timeSlots + ts] =
473                FX_DBL2FX_WIN(fMult(pWindowAna__FDK[w][timeSlots + ts],
474                                    applyRightWindowGain__FDK[w]));
475          }
476        }
477      } /* if (applyRightWindowGain[w] > 0.0f) */
478      else {
479        /* All Zero */
480        FDKmemset_flex(&pWindowAna__FDK[w][timeSlots],
481                       FX_DBL2FX_WIN((FIXP_DBL)0), timeSlots);
482      }
483    } /* loop over windows */
484
485    if (hFrameWindow->bFrameKeep == 1) {
486      FDKmemcpy_flex(&pWindowAna__FDK[0][2 * timeSlots], 1,
487                     &pWindowAna__FDK[0][timeSlots], 1, timeSlots);
488      FDKmemcpy_flex(&pWindowAna__FDK[0][timeSlots], 1, pWindowAna__FDK[0], 1,
489                     timeSlots);
490
491      if (avoid_keep != 0) {
492        FDKmemset_flex(pWindowAna__FDK[0], FX_DBL2FX_WIN((FIXP_DBL)0),
493                       timeSlots);
494      } else {
495        FDKmemset_flex(pWindowAna__FDK[0], winMaxVal, timeSlots);
496      }
497    } /* if (hFrameWindow->bFrameKeep==1) */
498
499    /* Feed Info to Bitstream Formatter */
500    pFramingInfo->numParamSets = pFrameWinList->n;
501    pFramingInfo->bsFramingType = 1; /* variable framing */
502    for (ps = 0; ps < pFramingInfo->numParamSets; ps++) {
503      pFramingInfo->bsParamSlots[ps] = pFrameWinList->dat[ps].slot;
504    }
505
506    /* if there is just one param set at last slot,
507       use fixed framing to save some bits */
508    if ((pFramingInfo->numParamSets == 1) &&
509        (pFramingInfo->bsParamSlots[0] == timeSlots - 1)) {
510      pFramingInfo->bsFramingType = 0;
511    }
512
513  } /* valid handle */
514
515bail:
516
517  return error;
518}
519
520FDK_SACENC_ERROR fdk_sacenc_analysisWindowing(
521    const INT nTimeSlots, const INT startTimeSlot,
522    FIXP_WIN *pFrameWindowAna__FDK, const FIXP_DPK *const *const ppDataIn__FDK,
523    FIXP_DPK *const *const ppDataOut__FDK, const INT nHybridBands,
524    const INT dim) {
525  FDK_SACENC_ERROR error = SACENC_OK;
526
527  if ((pFrameWindowAna__FDK == NULL) || (ppDataIn__FDK == NULL) ||
528      (ppDataOut__FDK == NULL)) {
529    error = SACENC_INVALID_HANDLE;
530  } else {
531    int i, ts;
532    FIXP_WIN maxVal = FX_DBL2FX_WIN((FIXP_DBL)MAXVAL_DBL);
533
534    if (dim == FW_CHANGE_DIM) {
535      for (ts = startTimeSlot; ts < nTimeSlots; ts++) {
536        FIXP_WIN win = pFrameWindowAna__FDK[ts];
537        if (win == maxVal) {
538          for (i = 0; i < nHybridBands; i++) {
539            ppDataOut__FDK[i][ts].v.re = ppDataIn__FDK[ts][i].v.re;
540            ppDataOut__FDK[i][ts].v.im = ppDataIn__FDK[ts][i].v.im;
541          }
542        } else {
543          for (i = 0; i < nHybridBands; i++) {
544            ppDataOut__FDK[i][ts].v.re = fMult(win, ppDataIn__FDK[ts][i].v.re);
545            ppDataOut__FDK[i][ts].v.im = fMult(win, ppDataIn__FDK[ts][i].v.im);
546          }
547        }
548      } /* ts */
549    } else {
550      for (ts = startTimeSlot; ts < nTimeSlots; ts++) {
551        FIXP_WIN win = pFrameWindowAna__FDK[ts];
552        if (win == maxVal) {
553          for (i = 0; i < nHybridBands; i++) {
554            ppDataOut__FDK[ts][i].v.re = ppDataIn__FDK[ts][i].v.re;
555            ppDataOut__FDK[ts][i].v.im = ppDataIn__FDK[ts][i].v.im;
556          }
557        } else {
558          for (i = 0; i < nHybridBands; i++) {
559            ppDataOut__FDK[ts][i].v.re = fMult(win, ppDataIn__FDK[ts][i].v.re);
560            ppDataOut__FDK[ts][i].v.im = fMult(win, ppDataIn__FDK[ts][i].v.im);
561          }
562        }
563      } /* ts */
564    }
565  }
566
567  return error;
568}
569