Home | History | Annotate | Download | only in src
      1 /* -----------------------------------------------------------------------------
      2 Software License for The Fraunhofer FDK AAC Codec Library for Android
      3 
      4  Copyright  1995 - 2018 Fraunhofer-Gesellschaft zur Frderung der angewandten
      5 Forschung e.V. All rights reserved.
      6 
      7  1.    INTRODUCTION
      8 The Fraunhofer FDK AAC Codec Library for Android ("FDK AAC Codec") is software
      9 that implements the MPEG Advanced Audio Coding ("AAC") encoding and decoding
     10 scheme for digital audio. This FDK AAC Codec software is intended to be used on
     11 a wide variety of Android devices.
     12 
     13 AAC's HE-AAC and HE-AAC v2 versions are regarded as today's most efficient
     14 general perceptual audio codecs. AAC-ELD is considered the best-performing
     15 full-bandwidth communications codec by independent studies and is widely
     16 deployed. AAC has been standardized by ISO and IEC as part of the MPEG
     17 specifications.
     18 
     19 Patent licenses for necessary patent claims for the FDK AAC Codec (including
     20 those of Fraunhofer) may be obtained through Via Licensing
     21 (www.vialicensing.com) or through the respective patent owners individually for
     22 the purpose of encoding or decoding bit streams in products that are compliant
     23 with the ISO/IEC MPEG audio standards. Please note that most manufacturers of
     24 Android devices already license these patent claims through Via Licensing or
     25 directly from the patent owners, and therefore FDK AAC Codec software may
     26 already be covered under those patent licenses when it is used for those
     27 licensed purposes only.
     28 
     29 Commercially-licensed AAC software libraries, including floating-point versions
     30 with enhanced sound quality, are also available from Fraunhofer. Users are
     31 encouraged to check the Fraunhofer website for additional applications
     32 information and documentation.
     33 
     34 2.    COPYRIGHT LICENSE
     35 
     36 Redistribution and use in source and binary forms, with or without modification,
     37 are permitted without payment of copyright license fees provided that you
     38 satisfy the following conditions:
     39 
     40 You must retain the complete text of this software license in redistributions of
     41 the FDK AAC Codec or your modifications thereto in source code form.
     42 
     43 You must retain the complete text of this software license in the documentation
     44 and/or other materials provided with redistributions of the FDK AAC Codec or
     45 your modifications thereto in binary form. You must make available free of
     46 charge copies of the complete source code of the FDK AAC Codec and your
     47 modifications thereto to recipients of copies in binary form.
     48 
     49 The name of Fraunhofer may not be used to endorse or promote products derived
     50 from this library without prior written permission.
     51 
     52 You may not charge copyright license fees for anyone to use, copy or distribute
     53 the FDK AAC Codec software or your modifications thereto.
     54 
     55 Your modified versions of the FDK AAC Codec must carry prominent notices stating
     56 that you changed the software and the date of any change. For modified versions
     57 of the FDK AAC Codec, the term "Fraunhofer FDK AAC Codec Library for Android"
     58 must be replaced by the term "Third-Party Modified Version of the Fraunhofer FDK
     59 AAC Codec Library for Android."
     60 
     61 3.    NO PATENT LICENSE
     62 
     63 NO EXPRESS OR IMPLIED LICENSES TO ANY PATENT CLAIMS, including without
     64 limitation the patents of Fraunhofer, ARE GRANTED BY THIS SOFTWARE LICENSE.
     65 Fraunhofer provides no warranty of patent non-infringement with respect to this
     66 software.
     67 
     68 You may use this FDK AAC Codec software or modifications thereto only for
     69 purposes that are authorized by appropriate patent licenses.
     70 
     71 4.    DISCLAIMER
     72 
     73 This FDK AAC Codec software is provided by Fraunhofer on behalf of the copyright
     74 holders and contributors "AS IS" and WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
     75 including but not limited to the implied warranties of merchantability and
     76 fitness for a particular purpose. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
     77 CONTRIBUTORS BE LIABLE for any direct, indirect, incidental, special, exemplary,
     78 or consequential damages, including but not limited to procurement of substitute
     79 goods or services; loss of use, data, or profits, or business interruption,
     80 however caused and on any theory of liability, whether in contract, strict
     81 liability, or tort (including negligence), arising in any way out of the use of
     82 this software, even if advised of the possibility of such damage.
     83 
     84 5.    CONTACT INFORMATION
     85 
     86 Fraunhofer Institute for Integrated Circuits IIS
     87 Attention: Audio and Multimedia Departments - FDK AAC LL
     88 Am Wolfsmantel 33
     89 91058 Erlangen, Germany
     90 
     91 www.iis.fraunhofer.de/amm
     92 amm-info (at) iis.fraunhofer.de
     93 ----------------------------------------------------------------------------- */
     94 
     95 /*********************** MPEG surround encoder library *************************
     96 
     97    Author(s):   Max Neuendorf
     98 
     99    Description: Encoder Library Interface
    100                 Interface to Spacial Audio Coding Encoder lib
    101 
    102 *******************************************************************************/
    103 
    104 /****************************************************************************
    105 \file
    106 Description of file contents
    107 ******************************************************************************/
    108 
    109 /* Includes ******************************************************************/
    110 #include "sacenc_lib.h"
    111 #include "sacenc_const.h"
    112 #include "genericStds.h"
    113 #include "FDK_core.h"
    114 #include "sacenc_tree.h"
    115 #include "sacenc_bitstream.h"
    116 #include "sacenc_onsetdetect.h"
    117 #include "sacenc_framewindowing.h"
    118 #include "sacenc_filter.h"
    119 #include "sacenc_paramextract.h"
    120 #include "sacenc_staticgain.h"
    121 #include "sacenc_delay.h"
    122 #include "sacenc_dmx_tdom_enh.h"
    123 #include "sacenc_vectorfunctions.h"
    124 #include "qmf.h"
    125 
    126 /* Defines *******************************************************************/
    127 
    128 /* Encoder library info */
    129 #define SACENC_LIB_VL0 2
    130 #define SACENC_LIB_VL1 0
    131 #define SACENC_LIB_VL2 0
    132 #define SACENC_LIB_TITLE "MPEG Surround Encoder"
    133 #ifdef __ANDROID__
    134 #define SACENC_LIB_BUILD_DATE ""
    135 #define SACENC_LIB_BUILD_TIME ""
    136 #else
    137 #define SACENC_LIB_BUILD_DATE __DATE__
    138 #define SACENC_LIB_BUILD_TIME __TIME__
    139 #endif
    140 
    141 #define MAX_MPEGS_BYTES (1 << 14)
    142 #define MAX_SSC_BYTES (1 << 6)
    143 
    144 #define MAX_SPACE_TREE_CHANNELS 2
    145 #define NUM_KEEP_WINDOWS 3
    146 
    147 /* Data Types ****************************************************************/
    148 typedef struct {
    149   MP4SPACEENC_MODE encMode;
    150   MP4SPACEENC_BANDS_CONFIG nParamBands;
    151   MP4SPACEENC_QUANTMODE quantMode;
    152   UCHAR bUseCoarseQuant;
    153   UCHAR bLdMode;
    154   UCHAR bTimeDomainDmx;
    155   UINT sampleRate;
    156   UINT frameTimeSlots;     /* e.g. 32 when used with HE-AAC */
    157   UINT independencyFactor; /* how often should we set the independency flag */
    158   INT timeAlignment;       /* additional delay for downmix */
    159 
    160 } MP4SPACEENC_SETUP, *HANDLE_MP4SPACEENC_SETUP;
    161 
    162 struct ENC_CONFIG_SETUP {
    163   UCHAR bEncMode_212;
    164   UCHAR maxHybridInStaticSlots;
    165   LONG maxSamplingrate;
    166   INT maxAnalysisLengthTimeSlots;
    167   INT maxHybridBands;
    168   INT maxQmfBands;
    169   INT maxChIn;
    170   INT maxFrameTimeSlots;
    171   INT maxFrameLength;
    172   INT maxChOut;
    173   INT maxChTotOut;
    174 };
    175 
    176 struct MP4SPACE_ENCODER {
    177   MP4SPACEENC_SETUP user;
    178 
    179   ENC_CONFIG_SETUP setup; /* describe allocated instance */
    180 
    181   HANDLE_FRAMEWINDOW
    182   hFrameWindow;      /* Windowing, only created+updated, but not used */
    183   INT nSamplesValid; /* Input Buffer Handling */
    184 
    185   /* Routing Sensible Switches/Variables */
    186   MP4SPACEENC_BANDS_CONFIG nParamBands;
    187   UCHAR useTimeDomDownmix;
    188 
    189   /* not Routing Sensible Switches/Varibles - must be contained in Check */
    190   MP4SPACEENC_MODE encMode;
    191   UCHAR bEncMode_212_only;
    192 
    193   /* not Routing Sensible Switches/Varibles + lower Classes */
    194   UCHAR useFrameKeep;
    195   UINT independencyFactor;
    196   UINT nSampleRate;
    197   UCHAR nInputChannels;
    198   UCHAR nOutputChannels;
    199   UCHAR nFrameTimeSlots; /* e.g. 32 when used with HE-AAC */
    200   UCHAR nQmfBands;
    201   UCHAR nHybridBands;
    202   UINT nFrameLength; /* number of output waveform samples/channel/frame */
    203 
    204   /* not Routing Sensible Switches/Varibles + lower Classes, secondary computed
    205    */
    206   INT nSamplesNext;
    207   INT nAnalysisLengthTimeSlots;
    208   INT nAnalysisLookaheadTimeSlots;
    209   INT nUpdateHybridPositionTimeSlots;
    210   INT *pnOutputBits;
    211   INT nInputDelay;
    212   INT nOutputBufferDelay;
    213   INT nSurroundAnalysisBufferDelay;
    214   INT nBitstreamDelayBuffer;
    215   INT nBitstreamBufferRead;
    216   INT nBitstreamBufferWrite;
    217   INT nDiscardOutFrames;
    218   INT avoid_keep;
    219 
    220   /* not Routing Sensible Switches/Varibles -> moved to lower Classes */
    221   UCHAR useCoarseQuantCld;    /* Only Used in SpaceTreeSetup */
    222   UCHAR useCoarseQuantIcc;    /* Only Used in SpaceTreeSetup */
    223   UCHAR useCoarseQuantCpc;    /* Only Used in SpaceTreeSetup */
    224   UCHAR useCoarseQuantArbDmx; /* ArbitraryDmx,... not available yet */
    225   MP4SPACEENC_QUANTMODE
    226   quantMode;          /* Used for quanitzation and in bitstream writer */
    227   INT coreCoderDelay; /* Used in delay compensation */
    228   INT timeAlignment;  /* Used in delay compensation */
    229 
    230   /* Local Processing Variables */
    231   INT independencyCount;
    232   INT independencyFlag;
    233   INT **ppTrCurrPos;                /* belongs somehow to Onset Detection */
    234   INT trPrevPos[2 * MAX_NUM_TRANS]; /* belongs somehow to Onset Detection */
    235 
    236   FRAMEWIN_LIST frameWinList;
    237   SPATIALFRAME saveFrame;
    238 
    239   /* Module-Handles */
    240   SPACE_TREE_SETUP spaceTreeSetup;
    241   MPEG4SPACEENC_SSCBUF sscBuf;
    242   FIXP_WIN *pFrameWindowAna__FDK[MAX_NUM_PARAMS];
    243   HANDLE_QMF_FILTER_BANK *phQmfFiltIn__FDK;
    244   HANDLE_DC_FILTER phDCFilterSigIn[SACENC_MAX_INPUT_CHANNELS];
    245   HANDLE_ONSET_DETECT phOnset[SACENC_MAX_INPUT_CHANNELS];
    246   HANDLE_SPACE_TREE hSpaceTree;
    247   HANDLE_BSF_INSTANCE hBitstreamFormatter;
    248   HANDLE_STATIC_GAIN_CONFIG hStaticGainConfig;
    249   HANDLE_STATIC_GAIN hStaticGain;
    250   HANDLE_DELAY hDelay;
    251 
    252   /* enhanced time domain downmix (for stereo input) */
    253   HANDLE_ENHANCED_TIME_DOMAIN_DMX hEnhancedTimeDmx;
    254 
    255   /* Data Buffers */
    256   INT_PCM **ppTimeSigIn__FDK;
    257   INT_PCM **ppTimeSigDelayIn__FDK;
    258   INT_PCM **ppTimeSigOut__FDK;
    259   FIXP_DPK ***pppHybridIn__FDK;
    260   FIXP_DPK ***pppHybridInStatic__FDK;
    261   FIXP_DPK ***pppProcDataIn__FDK;
    262   INT_PCM *pOutputDelayBuffer__FDK;
    263 
    264   UCHAR **ppBitstreamDelayBuffer;
    265 
    266   UCHAR *pParameterBand2HybridBandOffset;
    267   INT staticGainScale;
    268 
    269   INT *pEncoderInputChScale;
    270   INT *staticTimeDomainDmxInScale;
    271 };
    272 
    273 /* Constants *****************************************************************/
    274 static const UCHAR pValidBands_Ld[8] = {4, 5, 7, 9, 12, 15, 23, 40};
    275 
    276 static const UCHAR qmf2qmf[] = /* Bypass the HybridAnylyis/Synthesis*/
    277     {0,   1,   2,   3,   4,   5,   6,   7,   8,   9,   10,  11,  12,  13,  14,
    278      15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,
    279      30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,
    280      45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,
    281      60,  61,  62,  63,  64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,
    282      75,  76,  77,  78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,
    283      90,  91,  92,  93,  94,  95,  96,  97,  98,  99,  100, 101, 102, 103, 104,
    284      105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
    285      120, 121, 122, 123, 124, 125, 126, 127};
    286 
    287 /* Function / Class Declarations *********************************************/
    288 static FDK_SACENC_ERROR mp4SpaceEnc_create(
    289     HANDLE_MP4SPACE_ENCODER *phMp4SpaceEnc);
    290 
    291 static FDK_SACENC_ERROR FillSpatialSpecificConfig(
    292     const HANDLE_MP4SPACE_ENCODER hEnc, SPATIALSPECIFICCONFIG *const hSsc);
    293 
    294 static FDK_SACENC_ERROR mp4SpaceEnc_FillSpaceTreeSetup(
    295     const HANDLE_MP4SPACE_ENCODER hEnc,
    296     SPACE_TREE_SETUP *const hSpaceTreeSetup);
    297 
    298 static FDK_SACENC_ERROR mp4SpaceEnc_InitDelayCompensation(
    299     HANDLE_MP4SPACE_ENCODER hMp4SpaceEnc, const INT coreCoderDelay);
    300 
    301 static FDK_SACENC_ERROR mp4SpaceEnc_InitDefault(
    302     HANDLE_MP4SPACE_ENCODER hMp4SpaceEnc);
    303 
    304 static DECORRCONFIG mp4SpaceEnc_GetDecorrConfig(const MP4SPACEENC_MODE encMode);
    305 
    306 static FDK_SACENC_ERROR mp4SpaceEnc_InitNumParamBands(
    307     HANDLE_MP4SPACE_ENCODER hEnc, const MP4SPACEENC_BANDS_CONFIG nParamBands);
    308 
    309 /* Function / Class Definition ***********************************************/
    310 static UINT mp4SpaceEnc_GetNumQmfBands(const UINT nSampleRate) {
    311   UINT nQmfBands = 0;
    312 
    313   if (nSampleRate < 27713)
    314     nQmfBands = 32;
    315   else if (nSampleRate < 55426)
    316     nQmfBands = 64;
    317 
    318   return nQmfBands;
    319 }
    320 
    321 static UINT updateQmfFlags(const UINT flags, const INT keepStates) {
    322   UINT qmfFlags = flags;
    323 
    324   qmfFlags = (qmfFlags & (~(UINT)QMF_FLAG_LP));
    325   qmfFlags = (qmfFlags | QMF_FLAG_MPSLDFB);
    326   qmfFlags = (keepStates) ? (qmfFlags | QMF_FLAG_KEEP_STATES)
    327                           : (qmfFlags & (~(UINT)QMF_FLAG_KEEP_STATES));
    328 
    329   return qmfFlags;
    330 }
    331 
    332 static INT freq2HybridBand(const UINT nFrequency, const UINT nSampleRate,
    333                            const UINT nQmfBands) {
    334   /*
    335     nQmfSlotWidth = (nSampleRate/2) / nQmfBands;
    336     nQmfBand      = nFrequency / nQmfSlotWidth;
    337   */
    338   int nHybridBand = -1;
    339   int scale = 0;
    340   const FIXP_DBL temp = fDivNorm((FIXP_DBL)(2 * nFrequency * nQmfBands),
    341                                  (FIXP_DBL)nSampleRate, &scale);
    342   const int nQmfBand = scaleValue(temp, scale - (DFRACT_BITS - 1));
    343 
    344   if ((nQmfBand > -1) && (nQmfBand < (int)nQmfBands)) {
    345     nHybridBand = qmf2qmf[nQmfBand];
    346   }
    347 
    348   return nHybridBand;
    349 }
    350 
    351 /*
    352  * Examine buffer descriptor regarding choosen type.
    353  *
    354  * \param pBufDesc              Pointer to buffer descriptor
    355  * \param type                  Buffer type to look for.
    356 
    357  * \return - Buffer descriptor index.
    358  *         -1, if there is no entry available.
    359  */
    360 static INT getBufDescIdx(const FDK_bufDescr *pBufDesc, const UINT type) {
    361   INT i, idx = -1;
    362 
    363   for (i = 0; i < (int)pBufDesc->numBufs; i++) {
    364     if (pBufDesc->pBufType[i] == type) {
    365       idx = i;
    366       break;
    367     }
    368   }
    369   return idx;
    370 }
    371 
    372 FDK_SACENC_ERROR FDK_sacenc_open(HANDLE_MP4SPACE_ENCODER *phMp4SpaceEnc) {
    373   return mp4SpaceEnc_create(phMp4SpaceEnc);
    374 }
    375 
    376 static FDK_SACENC_ERROR mp4SpaceEnc_create(
    377     HANDLE_MP4SPACE_ENCODER *phMp4SpaceEnc) {
    378   FDK_SACENC_ERROR error = SACENC_OK;
    379   HANDLE_MP4SPACE_ENCODER hEnc = NULL;
    380   ENC_CONFIG_SETUP setup;
    381 
    382   if (NULL == phMp4SpaceEnc) {
    383     error = SACENC_INVALID_HANDLE;
    384   } else {
    385     int i, ch;
    386     FDKmemclear(&setup, sizeof(ENC_CONFIG_SETUP));
    387 
    388     /* Allocate Encoder Instance */
    389     FDK_ALLOCATE_MEMORY_1D(hEnc, 1, struct MP4SPACE_ENCODER);
    390 
    391     /* Clear everything, also pointers. */
    392     if (NULL != hEnc) {
    393       FDKmemclear(hEnc, sizeof(struct MP4SPACE_ENCODER));
    394     }
    395 
    396     setup.maxSamplingrate = 48000;
    397     setup.maxFrameTimeSlots = 16;
    398 
    399     setup.maxAnalysisLengthTimeSlots = 3 * setup.maxFrameTimeSlots;
    400     setup.maxQmfBands = mp4SpaceEnc_GetNumQmfBands(setup.maxSamplingrate);
    401     ;
    402     setup.maxHybridBands = setup.maxQmfBands;
    403     setup.maxFrameLength = setup.maxQmfBands * setup.maxFrameTimeSlots;
    404 
    405     setup.maxChIn = 2;
    406     setup.maxChOut = 1;
    407     setup.maxChTotOut = setup.maxChOut;
    408     setup.bEncMode_212 = 1;
    409     setup.maxHybridInStaticSlots = 24;
    410 
    411     /* Open Static Gain*/
    412     if (SACENC_OK !=
    413         (error = fdk_sacenc_staticGain_OpenConfig(&hEnc->hStaticGainConfig))) {
    414       goto bail;
    415     }
    416 
    417     /* enhanced time domain downmix (for stereo input) */
    418     if (SACENC_OK != (error = fdk_sacenc_open_enhancedTimeDomainDmx(
    419                           &hEnc->hEnhancedTimeDmx, setup.maxFrameLength))) {
    420       goto bail;
    421     }
    422 
    423     FDK_ALLOCATE_MEMORY_1D(hEnc->pParameterBand2HybridBandOffset,
    424                            MAX_NUM_PARAM_BANDS, UCHAR);
    425 
    426     /* Create Space Tree first, to get number of in-/output channels */
    427     if (SACENC_OK != (error = fdk_sacenc_spaceTree_Open(&hEnc->hSpaceTree))) {
    428       goto bail;
    429     }
    430 
    431     FDK_ALLOCATE_MEMORY_1D(hEnc->pEncoderInputChScale, setup.maxChIn, INT);
    432     FDK_ALLOCATE_MEMORY_1D(hEnc->staticTimeDomainDmxInScale, setup.maxChIn,
    433                            INT);
    434 
    435     FDK_ALLOCATE_MEMORY_1D(hEnc->phQmfFiltIn__FDK, setup.maxChIn,
    436                            HANDLE_QMF_FILTER_BANK);
    437 
    438     /* Allocate Analysis Filterbank Structs */
    439     for (ch = 0; ch < setup.maxChIn; ch++) {
    440       FDK_ALLOCATE_MEMORY_1D_INT(hEnc->phQmfFiltIn__FDK[ch], 1,
    441                                  struct QMF_FILTER_BANK, SECT_DATA_L2)
    442       FDK_ALLOCATE_MEMORY_1D_INT(hEnc->phQmfFiltIn__FDK[ch]->FilterStates,
    443                                  2 * 5 * setup.maxQmfBands, FIXP_QAS,
    444                                  SECT_DATA_L2)
    445     }
    446 
    447     /* Allocate Synthesis Filterbank Structs for arbitrary downmix */
    448 
    449     /* Allocate DC Filter Struct for normal signal input */
    450     for (ch = 0; ch < setup.maxChIn; ch++) {
    451       if (SACENC_OK !=
    452           (error = fdk_sacenc_createDCFilter(&hEnc->phDCFilterSigIn[ch]))) {
    453         goto bail;
    454       }
    455     }
    456 
    457     /* Open Onset Detection */
    458     for (ch = 0; ch < setup.maxChIn; ch++) {
    459       if (SACENC_OK != (error = fdk_sacenc_onsetDetect_Open(
    460                             &hEnc->phOnset[ch], setup.maxFrameTimeSlots))) {
    461         goto bail;
    462       }
    463     }
    464 
    465     FDK_ALLOCATE_MEMORY_2D(hEnc->ppTrCurrPos, setup.maxChIn, MAX_NUM_TRANS,
    466                            INT);
    467 
    468     /* Create Windowing */
    469     if (SACENC_OK !=
    470         (error = fdk_sacenc_frameWindow_Create(&hEnc->hFrameWindow))) {
    471       goto bail;
    472     }
    473 
    474     /* Open static gain */
    475     if (SACENC_OK != (error = fdk_sacenc_staticGain_Open(&hEnc->hStaticGain))) {
    476       goto bail;
    477     }
    478 
    479     /* create bitstream encoder */
    480     if (SACENC_OK != (error = fdk_sacenc_createSpatialBitstreamEncoder(
    481                           &hEnc->hBitstreamFormatter))) {
    482       goto bail;
    483     }
    484 
    485     FDK_ALLOCATE_MEMORY_1D(hEnc->sscBuf.pSsc, MAX_SSC_BYTES, UCHAR);
    486 
    487     {
    488       FDK_ALLOCATE_MEMORY_2D(hEnc->ppTimeSigIn__FDK, setup.maxChIn,
    489                              setup.maxFrameLength + MAX_DELAY_SURROUND_ANALYSIS,
    490                              INT_PCM);
    491     }
    492     FDK_ALLOCATE_MEMORY_2D(hEnc->ppTimeSigDelayIn__FDK, setup.maxChIn,
    493                            MAX_DELAY_SURROUND_ANALYSIS, INT_PCM);
    494 
    495     /* Create new buffers for several signals (including arbitrary downmix) */
    496     if (setup.bEncMode_212 == 0) {
    497       /* pOutputDelayBuffer__FDK buffer is not needed for SACENC_212 mode */
    498       FDK_ALLOCATE_MEMORY_1D(
    499           hEnc->pOutputDelayBuffer__FDK,
    500           (setup.maxFrameLength + MAX_DELAY_OUTPUT) * setup.maxChOut, INT_PCM);
    501     }
    502 
    503     /* allocate buffers */
    504     if (setup.bEncMode_212 == 0) {
    505       /* ppTimeSigOut__FDK buffer is not needed for SACENC_212 mode */
    506       FDK_ALLOCATE_MEMORY_2D(hEnc->ppTimeSigOut__FDK, setup.maxChTotOut,
    507                              setup.maxFrameLength, INT_PCM);
    508     }
    509 
    510     if (setup.bEncMode_212 == 1) {
    511       /* pppHybridIn__FDK buffer can be reduced by maxFrameTimeSlots/2 slots for
    512        * SACENC_212 mode */
    513       FDK_ALLOCATE_MEMORY_3D(
    514           hEnc->pppHybridIn__FDK, setup.maxChIn,
    515           setup.maxAnalysisLengthTimeSlots - (setup.maxFrameTimeSlots >> 1),
    516           setup.maxHybridBands, FIXP_DPK);
    517       FDK_ALLOCATE_MEMORY_3D(hEnc->pppHybridInStatic__FDK, setup.maxChIn,
    518                              setup.maxHybridInStaticSlots, setup.maxHybridBands,
    519                              FIXP_DPK);
    520     } else {
    521       FDK_ALLOCATE_MEMORY_3D(hEnc->pppHybridIn__FDK, setup.maxChIn,
    522                              setup.maxAnalysisLengthTimeSlots,
    523                              setup.maxHybridBands, FIXP_DPK);
    524     }
    525 
    526     if (setup.bEncMode_212 == 0) {
    527       /* pppProcDataIn__FDK buffer is not needed for SACENC_212 mode */
    528       FDK_ALLOCATE_MEMORY_3D(hEnc->pppProcDataIn__FDK, MAX_SPACE_TREE_CHANNELS,
    529                              setup.maxAnalysisLengthTimeSlots,
    530                              setup.maxHybridBands, FIXP_DPK);
    531     }
    532     for (i = 0; i < MAX_NUM_PARAMS; i++) {
    533       FDK_ALLOCATE_MEMORY_1D(hEnc->pFrameWindowAna__FDK[i],
    534                              setup.maxAnalysisLengthTimeSlots, FIXP_WIN);
    535     } /* for i */
    536 
    537     if (SACENC_OK != (error = fdk_sacenc_delay_Open(&hEnc->hDelay))) {
    538       goto bail;
    539     }
    540 
    541     if (setup.bEncMode_212 == 0) {
    542       /* ppBitstreamDelayBuffer buffer is not needed for SACENC_212 mode */
    543       FDK_ALLOCATE_MEMORY_2D(hEnc->ppBitstreamDelayBuffer, MAX_BITSTREAM_DELAY,
    544                              MAX_MPEGS_BYTES, UCHAR);
    545     }
    546     FDK_ALLOCATE_MEMORY_1D(hEnc->pnOutputBits, MAX_BITSTREAM_DELAY, INT);
    547 
    548     hEnc->setup = setup; /* save configuration used while encoder allocation. */
    549     mp4SpaceEnc_InitDefault(hEnc);
    550 
    551     if (NULL != phMp4SpaceEnc) {
    552       *phMp4SpaceEnc = hEnc; /* return encoder handle */
    553     }
    554 
    555   } /* valid handle */
    556 
    557   return error;
    558 
    559 bail:
    560   if (NULL != hEnc) {
    561     hEnc->setup = setup;
    562     FDK_sacenc_close(&hEnc);
    563   }
    564   return ((SACENC_OK == error) ? SACENC_MEMORY_ERROR : error);
    565 }
    566 
    567 static FDK_SACENC_ERROR mp4SpaceEnc_InitDefault(HANDLE_MP4SPACE_ENCODER hEnc) {
    568   FDK_SACENC_ERROR err = SACENC_OK;
    569 
    570   /* Get default static gain configuration. */
    571   if (SACENC_OK != (err = fdk_sacenc_staticGain_InitDefaultConfig(
    572                         hEnc->hStaticGainConfig))) {
    573     goto bail;
    574   }
    575 
    576 bail:
    577   return err;
    578 }
    579 
    580 static FDK_SACENC_ERROR FDK_sacenc_configure(
    581     HANDLE_MP4SPACE_ENCODER hEnc, const HANDLE_MP4SPACEENC_SETUP hSetup) {
    582   FDK_SACENC_ERROR error = SACENC_OK;
    583 
    584   hEnc->nSampleRate = hSetup->sampleRate;
    585   hEnc->encMode = hSetup->encMode;
    586   hEnc->nQmfBands = mp4SpaceEnc_GetNumQmfBands(hEnc->nSampleRate);
    587 
    588   /* Make sure that we have set time domain downmix for 212 */
    589   if (hSetup->encMode == SACENC_212 && hSetup->bTimeDomainDmx == 0) {
    590     error = SACENC_INVALID_CONFIG;
    591   } else {
    592     hEnc->useTimeDomDownmix = hSetup->bTimeDomainDmx;
    593   }
    594 
    595   hEnc->timeAlignment = hSetup->timeAlignment;
    596   hEnc->quantMode = hSetup->quantMode;
    597 
    598   hEnc->useCoarseQuantCld = hSetup->bUseCoarseQuant;
    599   hEnc->useCoarseQuantCpc = hSetup->bUseCoarseQuant;
    600   hEnc->useFrameKeep = (hSetup->bLdMode == 2);
    601   hEnc->useCoarseQuantIcc = 0;    /* not available */
    602   hEnc->useCoarseQuantArbDmx = 0; /* not available for user right now */
    603   hEnc->independencyFactor = hSetup->independencyFactor;
    604   hEnc->independencyCount = 0;
    605   hEnc->independencyFlag = 1;
    606 
    607   /* set number of Hybrid bands */
    608   hEnc->nHybridBands = hEnc->nQmfBands;
    609   hEnc->nFrameTimeSlots = hSetup->frameTimeSlots;
    610   mp4SpaceEnc_InitNumParamBands(hEnc, hSetup->nParamBands);
    611 
    612   return error;
    613 }
    614 
    615 FDK_SACENC_ERROR FDK_sacenc_init(HANDLE_MP4SPACE_ENCODER hEnc,
    616                                  const INT dmxDelay) {
    617   FDK_SACENC_ERROR error = SACENC_OK;
    618 
    619   /* Sanity Checks */
    620   if (NULL == hEnc) {
    621     error = SACENC_INVALID_HANDLE;
    622   } else {
    623     const int initStatesFlag = 1;
    624 
    625     int ch; /* loop counter */
    626     int nChInArbDmx;
    627 
    628     if (SACENC_OK != (error = FDK_sacenc_configure(hEnc, &hEnc->user))) {
    629       goto bail;
    630     }
    631 
    632     hEnc->bEncMode_212_only = hEnc->setup.bEncMode_212;
    633 
    634     /* Slots per Frame and Frame Length */
    635     if (hEnc->nFrameTimeSlots < 1) {
    636       error = SACENC_INVALID_CONFIG;
    637       goto bail;
    638     }
    639     hEnc->nFrameLength = hEnc->nQmfBands * hEnc->nFrameTimeSlots;
    640 
    641     if (hEnc->useFrameKeep == 1) {
    642       hEnc->nAnalysisLengthTimeSlots = 3 * hEnc->nFrameTimeSlots;
    643       hEnc->nUpdateHybridPositionTimeSlots = hEnc->nFrameTimeSlots;
    644     } else {
    645       hEnc->nAnalysisLengthTimeSlots = 2 * hEnc->nFrameTimeSlots;
    646       hEnc->nUpdateHybridPositionTimeSlots = 0;
    647     }
    648 
    649     {
    650       hEnc->nAnalysisLookaheadTimeSlots =
    651           hEnc->nAnalysisLengthTimeSlots - 3 * hEnc->nFrameTimeSlots / 2;
    652     }
    653 
    654     /* init parameterBand2hybridBandOffset table */
    655     fdk_sacenc_calcParameterBand2HybridBandOffset(
    656         (BOX_SUBBAND_CONFIG)hEnc->nParamBands, hEnc->nHybridBands,
    657         hEnc->pParameterBand2HybridBandOffset);
    658 
    659     /* Fill Setup structure for Space Tree */
    660     if (SACENC_OK !=
    661         (error = mp4SpaceEnc_FillSpaceTreeSetup(hEnc, &hEnc->spaceTreeSetup))) {
    662       goto bail;
    663     }
    664 
    665     /* Init space tree configuration */
    666     if (SACENC_OK !=
    667         (error = fdk_sacenc_spaceTree_Init(
    668              hEnc->hSpaceTree, &hEnc->spaceTreeSetup,
    669              hEnc->pParameterBand2HybridBandOffset, hEnc->useFrameKeep))) {
    670       goto bail;
    671     }
    672 
    673     /* Get space tree description and resulting number of input/output channels
    674      */
    675     {
    676       SPACE_TREE_DESCRIPTION spaceTreeDescription;
    677 
    678       if (SACENC_OK != (error = fdk_sacenc_spaceTree_GetDescription(
    679                             hEnc->hSpaceTree, &spaceTreeDescription))) {
    680         goto bail;
    681       }
    682 
    683       hEnc->nInputChannels =
    684           spaceTreeDescription.nOutChannels; /* space tree description
    685                                                 describes decoder
    686                                                 configuration */
    687       hEnc->nOutputChannels =
    688           spaceTreeDescription.nInChannels; /* space tree description
    689                                                describes decoder
    690                                                configuration */
    691     }
    692 
    693     nChInArbDmx = 0;
    694 
    695     /* INITIALIZATION */
    696     for (ch = 0; ch < hEnc->nInputChannels; ch++) {
    697       /* scaling in analysis qmf filterbank (7) */
    698       hEnc->pEncoderInputChScale[ch] = 7;
    699 
    700       {
    701         /* additional scaling in qmf prototype filter for low delay */
    702         hEnc->pEncoderInputChScale[ch] += 1;
    703       }
    704 
    705       { hEnc->pEncoderInputChScale[ch] += DC_FILTER_SF; }
    706     } /* nInputChannels */
    707 
    708     /* Init analysis filterbank */
    709     for (ch = 0; ch < hEnc->nInputChannels; ch++) {
    710       hEnc->phQmfFiltIn__FDK[ch]->flags =
    711           updateQmfFlags(hEnc->phQmfFiltIn__FDK[ch]->flags, !initStatesFlag);
    712 
    713       if (0 != qmfInitAnalysisFilterBank(
    714                    hEnc->phQmfFiltIn__FDK[ch],
    715                    (FIXP_QAS *)hEnc->phQmfFiltIn__FDK[ch]->FilterStates, 1,
    716                    hEnc->nQmfBands, hEnc->nQmfBands, hEnc->nQmfBands,
    717                    hEnc->phQmfFiltIn__FDK[ch]->flags)) {
    718         error = SACENC_INIT_ERROR;
    719         goto bail;
    720       }
    721     }
    722 
    723     /* Initialize DC Filter. */
    724     {
    725       for (ch = 0; ch < hEnc->nInputChannels; ch++) {
    726         if (SACENC_OK != (error = fdk_sacenc_initDCFilter(
    727                               hEnc->phDCFilterSigIn[ch], hEnc->nSampleRate))) {
    728           goto bail;
    729         }
    730       }
    731     }
    732 
    733     /* Init onset detect. */
    734     {
    735       /* init onset detect configuration struct */
    736       ONSET_DETECT_CONFIG onsetDetectConfig;
    737       onsetDetectConfig.maxTimeSlots = hEnc->nFrameTimeSlots;
    738       onsetDetectConfig.lowerBoundOnsetDetection =
    739           freq2HybridBand(1725, hEnc->nSampleRate, hEnc->nQmfBands);
    740       onsetDetectConfig.upperBoundOnsetDetection = hEnc->nHybridBands;
    741 
    742       for (ch = 0; ch < hEnc->nInputChannels; ch++) {
    743         if (SACENC_OK != (error = fdk_sacenc_onsetDetect_Init(
    744                               hEnc->phOnset[ch], &onsetDetectConfig, 1))) {
    745           goto bail;
    746         }
    747       }
    748     }
    749 
    750     {
    751       /* init windowing */
    752       FRAMEWINDOW_CONFIG framewindowConfig;
    753       framewindowConfig.nTimeSlotsMax = hEnc->nFrameTimeSlots;
    754       framewindowConfig.bFrameKeep = hEnc->useFrameKeep;
    755 
    756       if (SACENC_OK != (error = fdk_sacenc_frameWindow_Init(
    757                             hEnc->hFrameWindow, &framewindowConfig))) {
    758         goto bail;
    759       }
    760     }
    761 
    762     /* Set encoder mode for static gain initialization. */
    763     if (SACENC_OK != (error = fdk_sacenc_staticGain_SetEncMode(
    764                           hEnc->hStaticGainConfig, hEnc->encMode))) {
    765       goto bail;
    766     }
    767 
    768     /* Init static gain. */
    769     if (SACENC_OK != (error = fdk_sacenc_staticGain_Init(
    770                           hEnc->hStaticGain, hEnc->hStaticGainConfig,
    771                           &(hEnc->staticGainScale)))) {
    772       goto bail;
    773     }
    774 
    775     for (ch = 0; ch < hEnc->nInputChannels; ch++) {
    776       hEnc->pEncoderInputChScale[ch] += hEnc->staticGainScale;
    777     }
    778 
    779     /* enhanced downmix for stereo input*/
    780     if (hEnc->useTimeDomDownmix != 0) {
    781       if (SACENC_OK != (error = fdk_sacenc_init_enhancedTimeDomainDmx(
    782                             hEnc->hEnhancedTimeDmx,
    783                             fdk_sacenc_getPreGainPtrFDK(hEnc->hStaticGain),
    784                             hEnc->staticGainScale,
    785                             fdk_sacenc_getPostGainFDK(hEnc->hStaticGain),
    786                             hEnc->staticGainScale, hEnc->nFrameLength))) {
    787         goto bail;
    788       }
    789     }
    790 
    791     /* Create config structure for bitstream formatter including arbitrary
    792      * downmix residual */
    793     if (SACENC_OK != (error = fdk_sacenc_initSpatialBitstreamEncoder(
    794                           hEnc->hBitstreamFormatter))) {
    795       goto bail;
    796     }
    797 
    798     if (SACENC_OK != (error = FillSpatialSpecificConfig(
    799                           hEnc, fdk_sacenc_getSpatialSpecificConfig(
    800                                     hEnc->hBitstreamFormatter)))) {
    801       goto bail;
    802     }
    803 
    804     if (SACENC_OK !=
    805         (error = fdk_sacenc_writeSpatialSpecificConfig(
    806              fdk_sacenc_getSpatialSpecificConfig(hEnc->hBitstreamFormatter),
    807              hEnc->sscBuf.pSsc, MAX_SSC_BYTES, &hEnc->sscBuf.nSscSizeBits))) {
    808       goto bail;
    809     }
    810 
    811     /* init delay compensation with dmx core coder delay; if no core coder is
    812      * used, many other buffers are initialized nevertheless */
    813     if (SACENC_OK !=
    814         (error = mp4SpaceEnc_InitDelayCompensation(hEnc, dmxDelay))) {
    815       goto bail;
    816     }
    817 
    818     /* How much input do we need? */
    819     hEnc->nSamplesNext =
    820         hEnc->nFrameLength * (hEnc->nInputChannels + nChInArbDmx);
    821     hEnc->nSamplesValid = 0;
    822   } /* valid handle */
    823 
    824 bail:
    825   return error;
    826 }
    827 
    828 static INT getAnalysisLengthTimeSlots(FIXP_WIN *pFrameWindowAna,
    829                                       INT nTimeSlots) {
    830   int i;
    831   for (i = nTimeSlots - 1; i >= 0; i--) {
    832     if (pFrameWindowAna[i] != (FIXP_WIN)0) {
    833       break;
    834     }
    835   }
    836   nTimeSlots = i + 1;
    837   return nTimeSlots;
    838 }
    839 
    840 static INT getAnalysisStartTimeSlot(FIXP_WIN *pFrameWindowAna, INT nTimeSlots) {
    841   int startTimeSlot = 0;
    842   int i;
    843   for (i = 0; i < nTimeSlots; i++) {
    844     if (pFrameWindowAna[i] != (FIXP_WIN)0) {
    845       break;
    846     }
    847   }
    848   startTimeSlot = i;
    849   return startTimeSlot;
    850 }
    851 
    852 static FDK_SACENC_ERROR __FeedDeinterPreScale(
    853     HANDLE_MP4SPACE_ENCODER hEnc, INT_PCM const *const pSamples,
    854     INT_PCM *const pOutputSamples, INT const nSamples,
    855     UINT const isInputInterleaved, UINT const inputBufferSizePerChannel,
    856     UINT *const pnSamplesFed) {
    857   FDK_SACENC_ERROR error = SACENC_OK;
    858 
    859   if ((hEnc == NULL) || (pSamples == NULL) || (pnSamplesFed == NULL)) {
    860     error = SACENC_INVALID_HANDLE;
    861   } else if (nSamples == 0) {
    862     error = SACENC_INVALID_CONFIG; /* Flushing not implemented */
    863   } else {
    864     int ch;
    865     const INT nChIn = hEnc->nInputChannels;
    866     const INT nChInWithDmx = nChIn;
    867     const INT samplesToFeed =
    868         FDKmin(nSamples, hEnc->nSamplesNext - hEnc->nSamplesValid);
    869     const INT nSamplesPerChannel = samplesToFeed / nChInWithDmx;
    870 
    871     if ((samplesToFeed < 0) || (samplesToFeed % nChInWithDmx != 0) ||
    872         (samplesToFeed > nChInWithDmx * (INT)hEnc->nFrameLength)) {
    873       error = SACENC_INVALID_CONFIG;
    874       goto bail;
    875     }
    876     int i;
    877 
    878     const INT_PCM *pInput__FDK;
    879     const INT_PCM *pInput2__FDK;
    880 
    881     { /* no dmx align = default*/
    882       pInput__FDK = pSamples;
    883       pInput2__FDK = pSamples + (hEnc->nInputDelay * nChInWithDmx);
    884     }
    885 
    886     for (i = 0; i < hEnc->nInputChannels; i++) {
    887       hEnc->staticTimeDomainDmxInScale[i] = hEnc->staticGainScale;
    888     }
    889 
    890     /*****        N-channel-input     *****/
    891     for (ch = 0; ch < nChIn; ch++) {
    892       /* Write delayed time signal into time signal buffer */
    893       FDKmemcpy(&(hEnc->ppTimeSigIn__FDK[ch][0]),
    894                 &(hEnc->ppTimeSigDelayIn__FDK[ch][0]),
    895                 hEnc->nSurroundAnalysisBufferDelay * sizeof(INT_PCM));
    896 
    897       if (isInputInterleaved) {
    898         /* Add the new frame de-interleaved. Apply nSurroundAnalysisBufferDelay.
    899          */
    900         FDKmemcpy_flex(
    901             &(hEnc->ppTimeSigIn__FDK[ch][hEnc->nSurroundAnalysisBufferDelay]),
    902             1, pInput__FDK + ch, nChInWithDmx, hEnc->nInputDelay);
    903         FDKmemcpy_flex(
    904             &(hEnc->ppTimeSigIn__FDK[ch][hEnc->nSurroundAnalysisBufferDelay +
    905                                          hEnc->nInputDelay]),
    906             1, pInput2__FDK + ch, nChInWithDmx,
    907             nSamplesPerChannel - hEnc->nInputDelay);
    908       } else {
    909         /* Input is already deinterleaved, just copy */
    910         FDKmemcpy(
    911             &(hEnc->ppTimeSigIn__FDK[ch][hEnc->nSurroundAnalysisBufferDelay]),
    912             pInput__FDK + ch * inputBufferSizePerChannel,
    913             hEnc->nInputDelay * sizeof(INT_PCM));
    914         FDKmemcpy(
    915             &(hEnc->ppTimeSigIn__FDK[ch][hEnc->nSurroundAnalysisBufferDelay +
    916                                          hEnc->nInputDelay]),
    917             pInput2__FDK + ch * inputBufferSizePerChannel,
    918             (nSamplesPerChannel - hEnc->nInputDelay) * sizeof(INT_PCM));
    919       }
    920 
    921       /* Update time signal delay buffer */
    922       FDKmemcpy(&(hEnc->ppTimeSigDelayIn__FDK[ch][0]),
    923                 &(hEnc->ppTimeSigIn__FDK[ch][hEnc->nFrameLength]),
    924                 hEnc->nSurroundAnalysisBufferDelay * sizeof(INT_PCM));
    925     } /* for ch */
    926 
    927     /*****      No Arbitrary Downmix      *****/
    928     /* "Crude TD Dmx": Time DomainDownmix + NO Arbitrary Downmix, Delay Added at
    929      * pOutputBuffer */
    930     if ((hEnc->useTimeDomDownmix > 0)) {
    931       if ((hEnc->useTimeDomDownmix == 1) || (hEnc->nInputChannels != 2)) {
    932         error = SACENC_INVALID_CONFIG;
    933         goto bail;
    934       } else {
    935         /* enhanced time domain downmix (for stereo input) */
    936         if (hEnc->encMode == SACENC_212) {
    937           if (pOutputSamples == NULL) {
    938             error = SACENC_INVALID_HANDLE;
    939             goto bail;
    940           }
    941 
    942           fdk_sacenc_apply_enhancedTimeDomainDmx(
    943               hEnc->hEnhancedTimeDmx, hEnc->ppTimeSigIn__FDK, pOutputSamples,
    944               hEnc->nSurroundAnalysisBufferDelay);
    945         } else {
    946           if (&hEnc->ppTimeSigOut__FDK[0][0] == NULL) {
    947             error = SACENC_INVALID_HANDLE;
    948             goto bail;
    949           }
    950 
    951           fdk_sacenc_apply_enhancedTimeDomainDmx(
    952               hEnc->hEnhancedTimeDmx, hEnc->ppTimeSigIn__FDK,
    953               &hEnc->ppTimeSigOut__FDK[0][0],
    954               hEnc->nSurroundAnalysisBufferDelay);
    955         }
    956       }
    957     }
    958 
    959     /* update number of samples still to process */
    960     hEnc->nSamplesValid += samplesToFeed;
    961 
    962     /*return number of fed samples */
    963     *pnSamplesFed = samplesToFeed;
    964   }
    965 bail:
    966   return error;
    967 }
    968 
    969 FDK_SACENC_ERROR FDK_sacenc_encode(const HANDLE_MP4SPACE_ENCODER hMp4SpaceEnc,
    970                                    const FDK_bufDescr *inBufDesc,
    971                                    const FDK_bufDescr *outBufDesc,
    972                                    const SACENC_InArgs *inargs,
    973                                    SACENC_OutArgs *outargs) {
    974   FDK_SACENC_ERROR error = SACENC_OK;
    975 
    976   const INT_PCM *pInputSamples =
    977       (const INT_PCM *)inBufDesc->ppBase[getBufDescIdx(
    978           inBufDesc, (FDK_BUF_TYPE_INPUT | FDK_BUF_TYPE_PCM_DATA))];
    979 
    980   INT_PCM *const pOutputSamples = (INT_PCM *)outBufDesc->ppBase[getBufDescIdx(
    981       outBufDesc, (FDK_BUF_TYPE_OUTPUT | FDK_BUF_TYPE_PCM_DATA))];
    982 
    983   const int nOutputSamplesBufferSize =
    984       outBufDesc->pBufSize[getBufDescIdx(
    985           outBufDesc, (FDK_BUF_TYPE_OUTPUT | FDK_BUF_TYPE_PCM_DATA))] /
    986       outBufDesc->pEleSize[getBufDescIdx(
    987           outBufDesc, (FDK_BUF_TYPE_OUTPUT | FDK_BUF_TYPE_PCM_DATA))];
    988 
    989   if ((hMp4SpaceEnc == NULL) || (pInputSamples == NULL)) {
    990     error = SACENC_INVALID_HANDLE;
    991   } else {
    992     int nOutputSamples;
    993     int i, ch, ps, winCnt, ts, slot;
    994     INT currTransPos = -1;
    995     SPATIALFRAME *pFrameData = NULL;
    996 
    997     /* Improve Code Readability */
    998     const int nChIn = hMp4SpaceEnc->nInputChannels;
    999     const int nChInWithDmx = nChIn;
   1000     const int nChOut = hMp4SpaceEnc->nOutputChannels;
   1001     const int nSamplesPerChannel = inargs->nInputSamples / nChInWithDmx;
   1002     const int nOutputSamplesMax = nSamplesPerChannel * nChOut;
   1003     const int nFrameTimeSlots = hMp4SpaceEnc->nFrameTimeSlots;
   1004 
   1005     INT encoderInputChScale[SACENC_MAX_INPUT_CHANNELS];
   1006     INT nFrameTimeSlotsReduction = 0;
   1007 
   1008     if (hMp4SpaceEnc->encMode == SACENC_212) {
   1009       nFrameTimeSlotsReduction = hMp4SpaceEnc->nFrameTimeSlots >> 1;
   1010     }
   1011 
   1012     for (i = 0; i < nChIn; i++)
   1013       encoderInputChScale[i] = hMp4SpaceEnc->pEncoderInputChScale[i];
   1014 
   1015     /* Sanity Check */
   1016     if ((0 != inargs->nInputSamples % nChInWithDmx)) {
   1017       error = SACENC_INVALID_CONFIG;
   1018       goto bail;
   1019     }
   1020 
   1021     /*
   1022      * Get Frame Data Handle.
   1023      */
   1024 
   1025     /* get bitstream handle (for storage of cld's, icc's and so on)
   1026      * get spatialframe 2 frames in the future; NOTE: this is necessary to
   1027      * synchronise spatial data and audio data */
   1028     if (NULL == (pFrameData = fdk_sacenc_getSpatialFrame(
   1029                      hMp4SpaceEnc->hBitstreamFormatter, WRITE_SPATIALFRAME))) {
   1030       error = SACENC_INVALID_HANDLE;
   1031       goto bail;
   1032     }
   1033 
   1034     /* Independent Frames Counters*/
   1035     if (hMp4SpaceEnc->nDiscardOutFrames >
   1036         0) { /* Independent Frames if they should be discarded, Reset Counter*/
   1037       hMp4SpaceEnc->independencyCount =
   1038           0; /* Reset the counter, first valid frame is an independent one*/
   1039       hMp4SpaceEnc->independencyFlag = 1;
   1040     } else { /*hMp4SpaceEnc->nDiscardOutFrames == 0*/
   1041       hMp4SpaceEnc->independencyFlag =
   1042           (hMp4SpaceEnc->independencyCount == 0) ? 1 : 0;
   1043       if (hMp4SpaceEnc->independencyFactor > 0) {
   1044         hMp4SpaceEnc->independencyCount++;
   1045         hMp4SpaceEnc->independencyCount =
   1046             hMp4SpaceEnc->independencyCount %
   1047             ((int)hMp4SpaceEnc->independencyFactor);
   1048       } else { /* independencyFactor == 0 */
   1049         hMp4SpaceEnc->independencyCount = -1;
   1050       }
   1051     }
   1052 
   1053     /*
   1054      * Time signal preprocessing:
   1055      * - Feed input buffer
   1056      * - Prescale time signal
   1057      * - Apply DC filter on input signal
   1058      */
   1059 
   1060     /* Feed, Deinterleave, Pre-Scale the input time signals */
   1061     if (SACENC_OK !=
   1062         (error = __FeedDeinterPreScale(
   1063              hMp4SpaceEnc, pInputSamples, pOutputSamples, inargs->nInputSamples,
   1064              inargs->isInputInterleaved, inargs->inputBufferSizePerChannel,
   1065              &outargs->nSamplesConsumed))) {
   1066       goto bail;
   1067     }
   1068 
   1069     if (hMp4SpaceEnc->nSamplesNext != hMp4SpaceEnc->nSamplesValid) {
   1070       error = SACENC_INVALID_CONFIG;
   1071       goto bail;
   1072     }
   1073 
   1074     if (hMp4SpaceEnc->encMode == SACENC_212 &&
   1075         hMp4SpaceEnc->bEncMode_212_only) {
   1076       for (ch = 0; ch < nChIn; ch++) {
   1077         for (slot = 0; slot < nFrameTimeSlots; slot++) {
   1078           setCplxVec(
   1079               hMp4SpaceEnc->pppHybridIn__FDK
   1080                   [ch][hMp4SpaceEnc->nUpdateHybridPositionTimeSlots +
   1081                        nFrameTimeSlots - nFrameTimeSlotsReduction + slot],
   1082               (FIXP_DBL)0, hMp4SpaceEnc->nHybridBands);
   1083         }
   1084       }
   1085     }
   1086 
   1087     /*
   1088      * Time / Frequency:
   1089      * - T/F audio input channels
   1090      * - T/F arbitrary downmix input channels
   1091      */
   1092     for (ch = 0; ch < nChIn; ch++) {
   1093       C_AALLOC_SCRATCH_START(pQmfInReal, FIXP_DBL, MAX_QMF_BANDS)
   1094       C_AALLOC_SCRATCH_START(pQmfInImag, FIXP_DBL, MAX_QMF_BANDS)
   1095       FIXP_GAIN *pPreGain =
   1096           fdk_sacenc_getPreGainPtrFDK(hMp4SpaceEnc->hStaticGain);
   1097 
   1098       for (ts = 0; ts < nFrameTimeSlots; ts++) {
   1099         FIXP_DBL *pSpecReal;
   1100         FIXP_DBL *pSpecImag;
   1101 
   1102         INT_PCM *pTimeIn =
   1103             &hMp4SpaceEnc->ppTimeSigIn__FDK[ch][(ts * hMp4SpaceEnc->nQmfBands)];
   1104 
   1105         {
   1106           /* Apply DC filter on input channels */
   1107           if (SACENC_OK != (error = fdk_sacenc_applyDCFilter(
   1108                                 hMp4SpaceEnc->phDCFilterSigIn[ch], pTimeIn,
   1109                                 pTimeIn, hMp4SpaceEnc->nQmfBands))) {
   1110             goto bail;
   1111           }
   1112         }
   1113 
   1114         /* QMF filterbank */
   1115         C_ALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL, (MAX_QMF_BANDS << 1));
   1116 
   1117         qmfAnalysisFilteringSlot(hMp4SpaceEnc->phQmfFiltIn__FDK[ch], pQmfInReal,
   1118                                  pQmfInImag, pTimeIn, 1, pWorkBuffer);
   1119 
   1120         C_ALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, (MAX_QMF_BANDS << 1));
   1121 
   1122         pSpecReal = pQmfInReal;
   1123         pSpecImag = pQmfInImag;
   1124 
   1125         /* Apply pre-scale after filterbank */
   1126         if (MAXVAL_GAIN != pPreGain[ch]) {
   1127           for (i = 0; i < hMp4SpaceEnc->nHybridBands; i++) {
   1128             hMp4SpaceEnc
   1129                 ->pppHybridIn__FDK[ch]
   1130                                   [hMp4SpaceEnc->nAnalysisLookaheadTimeSlots +
   1131                                    ts][i]
   1132                 .v.re = fMult(pSpecReal[i], pPreGain[ch]);
   1133             hMp4SpaceEnc
   1134                 ->pppHybridIn__FDK[ch]
   1135                                   [hMp4SpaceEnc->nAnalysisLookaheadTimeSlots +
   1136                                    ts][i]
   1137                 .v.im = fMult(pSpecImag[i], pPreGain[ch]);
   1138           }
   1139         } else {
   1140           for (i = 0; i < hMp4SpaceEnc->nHybridBands; i++) {
   1141             hMp4SpaceEnc
   1142                 ->pppHybridIn__FDK[ch]
   1143                                   [hMp4SpaceEnc->nAnalysisLookaheadTimeSlots +
   1144                                    ts][i]
   1145                 .v.re = pSpecReal[i];
   1146             hMp4SpaceEnc
   1147                 ->pppHybridIn__FDK[ch]
   1148                                   [hMp4SpaceEnc->nAnalysisLookaheadTimeSlots +
   1149                                    ts][i]
   1150                 .v.im = pSpecImag[i];
   1151           }
   1152         }
   1153       } /* ts */
   1154       C_AALLOC_SCRATCH_END(pQmfInImag, FIXP_DBL, MAX_QMF_BANDS)
   1155       C_AALLOC_SCRATCH_END(pQmfInReal, FIXP_DBL, MAX_QMF_BANDS)
   1156 
   1157       if (SACENC_OK != error) {
   1158         goto bail;
   1159       }
   1160     } /* ch */
   1161 
   1162     if (hMp4SpaceEnc->encMode == SACENC_212 &&
   1163         hMp4SpaceEnc->bEncMode_212_only) {
   1164       for (ch = 0; ch < nChIn; ch++) {
   1165         for (slot = 0;
   1166              slot < (int)(hMp4SpaceEnc->nUpdateHybridPositionTimeSlots +
   1167                           nFrameTimeSlots - nFrameTimeSlotsReduction);
   1168              slot++) {
   1169           copyCplxVec(hMp4SpaceEnc->pppHybridIn__FDK[ch][slot],
   1170                       hMp4SpaceEnc->pppHybridInStatic__FDK[ch][slot],
   1171                       hMp4SpaceEnc->nHybridBands);
   1172         }
   1173       }
   1174       for (ch = 0; ch < nChIn; ch++) {
   1175         for (slot = 0;
   1176              slot < (int)(hMp4SpaceEnc->nUpdateHybridPositionTimeSlots +
   1177                           nFrameTimeSlots - nFrameTimeSlotsReduction);
   1178              slot++) {
   1179           copyCplxVec(
   1180               hMp4SpaceEnc->pppHybridInStatic__FDK[ch][slot],
   1181               hMp4SpaceEnc->pppHybridIn__FDK[ch][nFrameTimeSlots + slot],
   1182               hMp4SpaceEnc->nHybridBands);
   1183         }
   1184       }
   1185     }
   1186 
   1187     /*
   1188      * Onset Detection:
   1189      * - detection of transients
   1190      * - build framing
   1191      */
   1192     for (ch = 0; ch < nChIn; ch++) {
   1193       if (ch != 3) { /* !LFE */
   1194         if (SACENC_OK !=
   1195             (error = fdk_sacenc_onsetDetect_Apply(
   1196                  hMp4SpaceEnc->phOnset[ch], nFrameTimeSlots,
   1197                  hMp4SpaceEnc->nHybridBands,
   1198                  &hMp4SpaceEnc->pppHybridIn__FDK
   1199                       [ch][hMp4SpaceEnc->nAnalysisLookaheadTimeSlots],
   1200                  encoderInputChScale[ch],
   1201                  hMp4SpaceEnc->trPrevPos[1], /* contains previous Transient */
   1202                  hMp4SpaceEnc->ppTrCurrPos[ch]))) {
   1203           goto bail;
   1204         }
   1205 
   1206         if ((1) && (hMp4SpaceEnc->useFrameKeep == 0)) {
   1207           hMp4SpaceEnc->ppTrCurrPos[ch][0] = -1;
   1208         }
   1209 
   1210         /* Find first Transient Position */
   1211         if ((hMp4SpaceEnc->ppTrCurrPos[ch][0] >= 0) &&
   1212             ((currTransPos < 0) ||
   1213              (hMp4SpaceEnc->ppTrCurrPos[ch][0] < currTransPos))) {
   1214           currTransPos = hMp4SpaceEnc->ppTrCurrPos[ch][0];
   1215         }
   1216       } /* !LFE */
   1217     }   /* ch */
   1218 
   1219     if (hMp4SpaceEnc->useFrameKeep == 1) {
   1220       if ((currTransPos != -1) || (hMp4SpaceEnc->independencyFlag == 1)) {
   1221         hMp4SpaceEnc->avoid_keep = NUM_KEEP_WINDOWS;
   1222         currTransPos = -1;
   1223       }
   1224     }
   1225 
   1226     /* Save previous Transient Position */
   1227     hMp4SpaceEnc->trPrevPos[0] =
   1228         FDKmax(-1, hMp4SpaceEnc->trPrevPos[1] - (INT)nFrameTimeSlots);
   1229     hMp4SpaceEnc->trPrevPos[1] = currTransPos;
   1230 
   1231     /* Update Onset Detection Energy Buffer */
   1232     for (ch = 0; ch < nChIn; ch++) {
   1233       if (SACENC_OK != (error = fdk_sacenc_onsetDetect_Update(
   1234                             hMp4SpaceEnc->phOnset[ch], nFrameTimeSlots))) {
   1235         goto bail;
   1236       }
   1237     }
   1238 
   1239     /* Framing */
   1240     if (SACENC_OK !=
   1241         (error = fdk_sacenc_frameWindow_GetWindow(
   1242              hMp4SpaceEnc->hFrameWindow, hMp4SpaceEnc->trPrevPos,
   1243              nFrameTimeSlots, &pFrameData->framingInfo,
   1244              hMp4SpaceEnc->pFrameWindowAna__FDK, &hMp4SpaceEnc->frameWinList,
   1245              hMp4SpaceEnc->avoid_keep))) {
   1246       goto bail;
   1247     }
   1248 
   1249     /*
   1250      * MPS Processing:
   1251      */
   1252     for (ps = 0, winCnt = 0; ps < hMp4SpaceEnc->frameWinList.n; ++ps) {
   1253       /* Analysis Windowing */
   1254       if (hMp4SpaceEnc->frameWinList.dat[ps].hold == FW_HOLD) {
   1255         /* ************************************** */
   1256         /* ONLY COPY AND HOLD PREVIOUS PARAMETERS */
   1257         if (SACENC_OK != (error = fdk_sacenc_duplicateParameterSet(
   1258                               &hMp4SpaceEnc->saveFrame, 0, pFrameData, ps))) {
   1259           goto bail;
   1260         }
   1261 
   1262       } else { /* !FW_HOLD */
   1263         /* ************************************** */
   1264         /* NEW WINDOW */
   1265 
   1266         INT nAnalysisLengthTimeSlots, analysisStartTimeSlot;
   1267 
   1268         nAnalysisLengthTimeSlots = getAnalysisLengthTimeSlots(
   1269             hMp4SpaceEnc->pFrameWindowAna__FDK[winCnt],
   1270             hMp4SpaceEnc->nAnalysisLengthTimeSlots);
   1271 
   1272         analysisStartTimeSlot =
   1273             getAnalysisStartTimeSlot(hMp4SpaceEnc->pFrameWindowAna__FDK[winCnt],
   1274                                      hMp4SpaceEnc->nAnalysisLengthTimeSlots);
   1275 
   1276         /* perform main signal analysis windowing in
   1277          * fdk_sacenc_spaceTree_Apply() */
   1278         FIXP_WIN *pFrameWindowAna__FDK =
   1279             hMp4SpaceEnc->pFrameWindowAna__FDK[winCnt];
   1280         FIXP_DPK ***pppHybridIn__FDK = hMp4SpaceEnc->pppHybridIn__FDK;
   1281         FIXP_DPK ***pppProcDataIn__FDK = hMp4SpaceEnc->pppProcDataIn__FDK;
   1282 
   1283         if (hMp4SpaceEnc->encMode == SACENC_212 &&
   1284             hMp4SpaceEnc->bEncMode_212_only) {
   1285           pppProcDataIn__FDK = pppHybridIn__FDK;
   1286         }
   1287 
   1288         if (SACENC_OK !=
   1289             (error = fdk_sacenc_spaceTree_Apply(
   1290                  hMp4SpaceEnc->hSpaceTree, ps, nChIn, nAnalysisLengthTimeSlots,
   1291                  analysisStartTimeSlot, hMp4SpaceEnc->nHybridBands,
   1292                  pFrameWindowAna__FDK, pppHybridIn__FDK,
   1293                  pppProcDataIn__FDK, /* multi-channel input */
   1294                  pFrameData, hMp4SpaceEnc->avoid_keep, encoderInputChScale))) {
   1295           goto bail;
   1296         }
   1297 
   1298         /* Save spatial frame for potential hold parameter set */
   1299         if (SACENC_OK != (error = fdk_sacenc_duplicateParameterSet(
   1300                               pFrameData, ps, &hMp4SpaceEnc->saveFrame, 0))) {
   1301           goto bail;
   1302         }
   1303 
   1304         ++winCnt;
   1305       }
   1306       if (hMp4SpaceEnc->avoid_keep > 0) {
   1307         hMp4SpaceEnc->avoid_keep--;
   1308       }
   1309     } /* Loop over Parameter Sets */
   1310     /* ---- End of Processing Loop ---- */
   1311 
   1312     /*
   1313      * Update hybridInReal/Imag buffer and do the same for arbDmx
   1314      * this means to move the hybrid data of the current frame to the beginning
   1315      * of the 2*nFrameLength-long buffer
   1316      */
   1317     if (!(hMp4SpaceEnc->encMode == SACENC_212 &&
   1318           hMp4SpaceEnc->bEncMode_212_only)) {
   1319       for (ch = 0; ch < nChIn; ch++) { /* for automatic downmix */
   1320         for (slot = 0;
   1321              slot < (int)(hMp4SpaceEnc->nUpdateHybridPositionTimeSlots +
   1322                           nFrameTimeSlots - nFrameTimeSlotsReduction);
   1323              slot++) {
   1324           copyCplxVec(
   1325               hMp4SpaceEnc->pppHybridIn__FDK[ch][slot],
   1326               hMp4SpaceEnc->pppHybridIn__FDK[ch][nFrameTimeSlots + slot],
   1327               hMp4SpaceEnc->nHybridBands);
   1328         }
   1329         for (slot = 0; slot < nFrameTimeSlots; slot++) {
   1330           setCplxVec(
   1331               hMp4SpaceEnc->pppHybridIn__FDK
   1332                   [ch][hMp4SpaceEnc->nUpdateHybridPositionTimeSlots +
   1333                        nFrameTimeSlots - nFrameTimeSlotsReduction + slot],
   1334               (FIXP_DBL)0, hMp4SpaceEnc->nHybridBands);
   1335         }
   1336       }
   1337     }
   1338     /*
   1339      * Spatial Tonality:
   1340      */
   1341     {
   1342       /* Smooth config off. */
   1343       FDKmemclear(&pFrameData->smgData, sizeof(pFrameData->smgData));
   1344     }
   1345 
   1346     /*
   1347      * Create bitstream
   1348      * - control independecy flag
   1349      * - write spatial frame
   1350      * - return bitstream
   1351      */
   1352     UCHAR *pBitstreamDelayBuffer;
   1353 
   1354     if (hMp4SpaceEnc->encMode == SACENC_212) {
   1355       /* no bitstream delay buffer for SACENC_212 mode, write bitstream directly
   1356        * into the sacOutBuffer buffer which is provided by the core routine */
   1357       pBitstreamDelayBuffer = (UCHAR *)outBufDesc->ppBase[1];
   1358     } else {
   1359       /* bitstream delay is handled in ppBitstreamDelayBuffer buffer */
   1360       pBitstreamDelayBuffer =
   1361           hMp4SpaceEnc
   1362               ->ppBitstreamDelayBuffer[hMp4SpaceEnc->nBitstreamBufferWrite];
   1363     }
   1364     if (pBitstreamDelayBuffer == NULL) {
   1365       error = SACENC_INVALID_HANDLE;
   1366       goto bail;
   1367     }
   1368 
   1369     pFrameData->bsIndependencyFlag = hMp4SpaceEnc->independencyFlag;
   1370 
   1371     if (SACENC_OK !=
   1372         (error = fdk_sacenc_writeSpatialFrame(
   1373              pBitstreamDelayBuffer, MAX_MPEGS_BYTES,
   1374              &hMp4SpaceEnc->pnOutputBits[hMp4SpaceEnc->nBitstreamBufferWrite],
   1375              hMp4SpaceEnc->hBitstreamFormatter))) {
   1376       goto bail;
   1377     }
   1378 
   1379     /* return bitstream info */
   1380     if ((hMp4SpaceEnc->nDiscardOutFrames == 0) &&
   1381         (getBufDescIdx(outBufDesc,
   1382                        (FDK_BUF_TYPE_OUTPUT | FDK_BUF_TYPE_BS_DATA)) != -1)) {
   1383       const INT idx = getBufDescIdx(
   1384           outBufDesc, (FDK_BUF_TYPE_OUTPUT | FDK_BUF_TYPE_BS_DATA));
   1385       const INT outBits =
   1386           hMp4SpaceEnc->pnOutputBits[hMp4SpaceEnc->nBitstreamBufferRead];
   1387 
   1388       if (((outBits + 7) / 8) >
   1389           (INT)(outBufDesc->pBufSize[idx] / outBufDesc->pEleSize[idx])) {
   1390         outargs->nOutputBits = 0;
   1391         error = SACENC_ENCODE_ERROR;
   1392         goto bail;
   1393       }
   1394 
   1395       /* return bitstream buffer, copy delayed bitstream for all configurations
   1396        * except for the SACENC_212 mode */
   1397       if (hMp4SpaceEnc->encMode != SACENC_212) {
   1398         FDKmemcpy(
   1399             outBufDesc->ppBase[idx],
   1400             hMp4SpaceEnc
   1401                 ->ppBitstreamDelayBuffer[hMp4SpaceEnc->nBitstreamBufferRead],
   1402             (outBits + 7) / 8);
   1403       }
   1404 
   1405       /* return number of valid bits */
   1406       outargs->nOutputBits = outBits;
   1407     } else { /* No spatial data should be returned if the current frame is to be
   1408                 discarded. */
   1409       outargs->nOutputBits = 0;
   1410     }
   1411 
   1412     /* update pointers */
   1413     hMp4SpaceEnc->nBitstreamBufferRead =
   1414         (hMp4SpaceEnc->nBitstreamBufferRead + 1) %
   1415         hMp4SpaceEnc->nBitstreamDelayBuffer;
   1416     hMp4SpaceEnc->nBitstreamBufferWrite =
   1417         (hMp4SpaceEnc->nBitstreamBufferWrite + 1) %
   1418         hMp4SpaceEnc->nBitstreamDelayBuffer;
   1419 
   1420     /* Set Output Parameters */
   1421     nOutputSamples =
   1422         (hMp4SpaceEnc->nDiscardOutFrames == 0)
   1423             ? (nOutputSamplesMax)
   1424             : 0; /* don't output samples in case frames to be discarded */
   1425     if (nOutputSamples > nOutputSamplesBufferSize) {
   1426       error = SACENC_INVALID_CONFIG;
   1427       goto bail;
   1428     }
   1429     outargs->nOutputSamples = nOutputSamples;
   1430 
   1431     { /* !bQmfOutput */
   1432 
   1433       if (hMp4SpaceEnc->encMode != SACENC_212) {
   1434         /* delay output samples and interleave them */
   1435         /* note: in case of arbitrary downmix this will always be processed,
   1436          * because nOutputSamples != 0, even if bDMXAlign is switched on */
   1437         /* always run copy-func, so nOutputSamplesMax instead of nOutputSamples
   1438          */
   1439         for (ch = 0; ch < nChOut; ch++) {
   1440           FDKmemcpy_flex(
   1441               &hMp4SpaceEnc->pOutputDelayBuffer__FDK
   1442                    [ch + (hMp4SpaceEnc->nOutputBufferDelay) * nChOut],
   1443               nChOut, hMp4SpaceEnc->ppTimeSigOut__FDK[ch], 1,
   1444               nOutputSamplesMax / nChOut);
   1445         }
   1446 
   1447         /* write delayed data in output pcm stream */
   1448         /* always calculate, limiter must have a lookahead!!! */
   1449         FDKmemcpy(pOutputSamples, hMp4SpaceEnc->pOutputDelayBuffer__FDK,
   1450                   nOutputSamplesMax * sizeof(INT_PCM));
   1451 
   1452         /* update delay buffer (move back end to the beginning of the buffer) */
   1453         FDKmemmove(
   1454             hMp4SpaceEnc->pOutputDelayBuffer__FDK,
   1455             &hMp4SpaceEnc->pOutputDelayBuffer__FDK[nOutputSamplesMax],
   1456             nChOut * (hMp4SpaceEnc->nOutputBufferDelay) * sizeof(INT_PCM));
   1457       }
   1458 
   1459       if (hMp4SpaceEnc->useTimeDomDownmix <= 0) {
   1460         if (SACENC_OK != (error = fdk_sacenc_staticPostGain_ApplyFDK(
   1461                               hMp4SpaceEnc->hStaticGain, pOutputSamples,
   1462                               nOutputSamplesMax, 0))) {
   1463           goto bail;
   1464         }
   1465       }
   1466 
   1467     } /* !bQmfOutput */
   1468 
   1469     if (hMp4SpaceEnc->nDiscardOutFrames > 0) {
   1470       hMp4SpaceEnc->nDiscardOutFrames--;
   1471     }
   1472 
   1473     /* Invalidate Input Buffer */
   1474     hMp4SpaceEnc->nSamplesValid = 0;
   1475 
   1476   } /* valid handle */
   1477 bail:
   1478   return error;
   1479 }
   1480 
   1481 FDK_SACENC_ERROR FDK_sacenc_close(HANDLE_MP4SPACE_ENCODER *phMp4SpaceEnc) {
   1482   FDK_SACENC_ERROR error = SACENC_OK;
   1483 
   1484   if (NULL != phMp4SpaceEnc) {
   1485     if (NULL != *phMp4SpaceEnc) {
   1486       int ch, i;
   1487       HANDLE_MP4SPACE_ENCODER const hEnc = *phMp4SpaceEnc;
   1488 
   1489       if (hEnc->pParameterBand2HybridBandOffset != NULL) {
   1490         FDK_FREE_MEMORY_1D(hEnc->pParameterBand2HybridBandOffset);
   1491       }
   1492       /* Free Analysis Filterbank Structs */
   1493       if (hEnc->pEncoderInputChScale != NULL) {
   1494         FDK_FREE_MEMORY_1D(hEnc->pEncoderInputChScale);
   1495       }
   1496       if (hEnc->staticTimeDomainDmxInScale != NULL) {
   1497         FDK_FREE_MEMORY_1D(hEnc->staticTimeDomainDmxInScale);
   1498       }
   1499       if (hEnc->phQmfFiltIn__FDK != NULL) {
   1500         for (ch = 0; ch < hEnc->setup.maxChIn; ch++) {
   1501           if (hEnc->phQmfFiltIn__FDK[ch] != NULL) {
   1502             if (hEnc->phQmfFiltIn__FDK[ch]->FilterStates != NULL) {
   1503               FDK_FREE_MEMORY_1D(hEnc->phQmfFiltIn__FDK[ch]->FilterStates);
   1504             }
   1505             FDK_FREE_MEMORY_1D(hEnc->phQmfFiltIn__FDK[ch]);
   1506           }
   1507         }
   1508         FDK_FREE_MEMORY_1D(hEnc->phQmfFiltIn__FDK);
   1509       }
   1510       for (ch = 0; ch < hEnc->setup.maxChIn; ch++) {
   1511         if (NULL != hEnc->phDCFilterSigIn[ch]) {
   1512           fdk_sacenc_destroyDCFilter(&hEnc->phDCFilterSigIn[ch]);
   1513         }
   1514       }
   1515       /* Close Onset Detection */
   1516       for (ch = 0; ch < hEnc->setup.maxChIn; ch++) {
   1517         if (NULL != hEnc->phOnset[ch]) {
   1518           fdk_sacenc_onsetDetect_Close(&hEnc->phOnset[ch]);
   1519         }
   1520       }
   1521       if (hEnc->ppTrCurrPos) {
   1522         FDK_FREE_MEMORY_2D(hEnc->ppTrCurrPos);
   1523       }
   1524       if (hEnc->hFrameWindow) {
   1525         fdk_sacenc_frameWindow_Destroy(&hEnc->hFrameWindow);
   1526       }
   1527       /* Close Space Tree */
   1528       if (NULL != hEnc->hSpaceTree) {
   1529         fdk_sacenc_spaceTree_Close(&hEnc->hSpaceTree);
   1530       }
   1531       if (NULL != hEnc->hEnhancedTimeDmx) {
   1532         fdk_sacenc_close_enhancedTimeDomainDmx(&hEnc->hEnhancedTimeDmx);
   1533       }
   1534       /* Close Static Gain */
   1535       if (NULL != hEnc->hStaticGain) {
   1536         fdk_sacenc_staticGain_Close(&hEnc->hStaticGain);
   1537       }
   1538       if (NULL != hEnc->hStaticGainConfig) {
   1539         fdk_sacenc_staticGain_CloseConfig(&hEnc->hStaticGainConfig);
   1540       }
   1541       /* Close Delay*/
   1542       if (NULL != hEnc->hDelay) {
   1543         fdk_sacenc_delay_Close(&hEnc->hDelay);
   1544       }
   1545       /* Delete Bitstream Stuff */
   1546       if (NULL != hEnc->hBitstreamFormatter) {
   1547         fdk_sacenc_destroySpatialBitstreamEncoder(&(hEnc->hBitstreamFormatter));
   1548       }
   1549       if (hEnc->pppHybridIn__FDK != NULL) {
   1550         if (hEnc->setup.bEncMode_212 == 1) {
   1551           FDK_FREE_MEMORY_3D(hEnc->pppHybridIn__FDK);
   1552           FDK_FREE_MEMORY_3D(hEnc->pppHybridInStatic__FDK);
   1553         } else {
   1554           FDK_FREE_MEMORY_3D(hEnc->pppHybridIn__FDK);
   1555         }
   1556       }
   1557       if (hEnc->pppProcDataIn__FDK != NULL) {
   1558         FDK_FREE_MEMORY_3D(hEnc->pppProcDataIn__FDK);
   1559       }
   1560       if (hEnc->pOutputDelayBuffer__FDK != NULL) {
   1561         FDK_FREE_MEMORY_1D(hEnc->pOutputDelayBuffer__FDK);
   1562       }
   1563       if (hEnc->ppTimeSigIn__FDK != NULL) {
   1564         { FDK_FREE_MEMORY_2D(hEnc->ppTimeSigIn__FDK); }
   1565       }
   1566       if (hEnc->ppTimeSigDelayIn__FDK != NULL) {
   1567         FDK_FREE_MEMORY_2D(hEnc->ppTimeSigDelayIn__FDK);
   1568       }
   1569       if (hEnc->ppTimeSigOut__FDK != NULL) {
   1570         FDK_FREE_MEMORY_2D(hEnc->ppTimeSigOut__FDK);
   1571       }
   1572       for (i = 0; i < MAX_NUM_PARAMS; i++) {
   1573         if (hEnc->pFrameWindowAna__FDK[i] != NULL) {
   1574           FDK_FREE_MEMORY_1D(hEnc->pFrameWindowAna__FDK[i]);
   1575         }
   1576       }
   1577       if (hEnc->pnOutputBits != NULL) {
   1578         FDK_FREE_MEMORY_1D(hEnc->pnOutputBits);
   1579       }
   1580       if (hEnc->ppBitstreamDelayBuffer != NULL) {
   1581         FDK_FREE_MEMORY_2D(hEnc->ppBitstreamDelayBuffer);
   1582       }
   1583       if (hEnc->sscBuf.pSsc != NULL) {
   1584         FDK_FREE_MEMORY_1D(hEnc->sscBuf.pSsc);
   1585       }
   1586       FDK_FREE_MEMORY_1D(*phMp4SpaceEnc);
   1587     }
   1588   }
   1589 
   1590   return error;
   1591 }
   1592 
   1593 /*-----------------------------------------------------------------------------
   1594   functionname: mp4SpaceEnc_InitDelayCompensation()
   1595   description:  initialzes delay compensation
   1596   returns:      noError on success, an apropriate error code else
   1597   -----------------------------------------------------------------------------*/
   1598 static FDK_SACENC_ERROR mp4SpaceEnc_InitDelayCompensation(
   1599     HANDLE_MP4SPACE_ENCODER hMp4SpaceEnc, const INT coreCoderDelay) {
   1600   FDK_SACENC_ERROR error = SACENC_OK;
   1601 
   1602   /* Sanity Check */
   1603   if (hMp4SpaceEnc == NULL) {
   1604     error = SACENC_INVALID_HANDLE;
   1605   } else {
   1606     hMp4SpaceEnc->coreCoderDelay = coreCoderDelay;
   1607 
   1608     if (SACENC_OK != (error = fdk_sacenc_delay_Init(
   1609                           hMp4SpaceEnc->hDelay, hMp4SpaceEnc->nQmfBands,
   1610                           hMp4SpaceEnc->nFrameLength, coreCoderDelay,
   1611                           hMp4SpaceEnc->timeAlignment))) {
   1612       goto bail;
   1613     }
   1614 
   1615     fdk_sacenc_delay_SetDmxAlign(hMp4SpaceEnc->hDelay, 0);
   1616     fdk_sacenc_delay_SetTimeDomDmx(
   1617         hMp4SpaceEnc->hDelay, (hMp4SpaceEnc->useTimeDomDownmix >= 1) ? 1 : 0);
   1618     fdk_sacenc_delay_SetMinimizeDelay(hMp4SpaceEnc->hDelay, 1);
   1619 
   1620     if (SACENC_OK != (error = fdk_sacenc_delay_SubCalulateBufferDelays(
   1621                           hMp4SpaceEnc->hDelay))) {
   1622       goto bail;
   1623     }
   1624 
   1625     /* init output delay compensation */
   1626     hMp4SpaceEnc->nBitstreamDelayBuffer =
   1627         fdk_sacenc_delay_GetBitstreamFrameBufferSize(hMp4SpaceEnc->hDelay);
   1628     hMp4SpaceEnc->nOutputBufferDelay =
   1629         fdk_sacenc_delay_GetOutputAudioBufferDelay(hMp4SpaceEnc->hDelay);
   1630     hMp4SpaceEnc->nSurroundAnalysisBufferDelay =
   1631         fdk_sacenc_delay_GetSurroundAnalysisBufferDelay(hMp4SpaceEnc->hDelay);
   1632     hMp4SpaceEnc->nBitstreamBufferRead = 0;
   1633     hMp4SpaceEnc->nBitstreamBufferWrite =
   1634         hMp4SpaceEnc->nBitstreamDelayBuffer - 1;
   1635 
   1636     if (hMp4SpaceEnc->encMode == SACENC_212) {
   1637       /* mode 212 expects no bitstream delay */
   1638       if (hMp4SpaceEnc->nBitstreamBufferWrite !=
   1639           hMp4SpaceEnc->nBitstreamBufferRead) {
   1640         error = SACENC_PARAM_ERROR;
   1641         goto bail;
   1642       }
   1643 
   1644       /* mode 212 expects no output buffer delay */
   1645       if (hMp4SpaceEnc->nOutputBufferDelay != 0) {
   1646         error = SACENC_PARAM_ERROR;
   1647         goto bail;
   1648       }
   1649     }
   1650 
   1651     /*** Input delay to obtain a net encoder delay that is a multiple
   1652     of the used framelength to ensure synchronization of framing
   1653     in artistic down-mix with the corresponding spatial data.      ***/
   1654     hMp4SpaceEnc->nDiscardOutFrames =
   1655         fdk_sacenc_delay_GetDiscardOutFrames(hMp4SpaceEnc->hDelay);
   1656     hMp4SpaceEnc->nInputDelay =
   1657         fdk_sacenc_delay_GetDmxAlignBufferDelay(hMp4SpaceEnc->hDelay);
   1658 
   1659     /* reset independency Flag counter */
   1660     hMp4SpaceEnc->independencyCount = 0;
   1661     hMp4SpaceEnc->independencyFlag = 1;
   1662 
   1663     int i;
   1664 
   1665     /* write some parameters to bitstream */
   1666     for (i = 0; i < hMp4SpaceEnc->nBitstreamDelayBuffer - 1; i++) {
   1667       SPATIALFRAME *pFrameData = NULL;
   1668 
   1669       if (NULL == (pFrameData = fdk_sacenc_getSpatialFrame(
   1670                        hMp4SpaceEnc->hBitstreamFormatter, READ_SPATIALFRAME))) {
   1671         error = SACENC_INVALID_HANDLE;
   1672         goto bail;
   1673       }
   1674 
   1675       pFrameData->bsIndependencyFlag = 1;
   1676       pFrameData->framingInfo.numParamSets = 1;
   1677       pFrameData->framingInfo.bsFramingType = 0;
   1678 
   1679       fdk_sacenc_writeSpatialFrame(
   1680           hMp4SpaceEnc->ppBitstreamDelayBuffer[i], MAX_MPEGS_BYTES,
   1681           &hMp4SpaceEnc->pnOutputBits[i], hMp4SpaceEnc->hBitstreamFormatter);
   1682     }
   1683 
   1684     if ((hMp4SpaceEnc->nInputDelay > MAX_DELAY_INPUT) ||
   1685         (hMp4SpaceEnc->nOutputBufferDelay > MAX_DELAY_OUTPUT) ||
   1686         (hMp4SpaceEnc->nSurroundAnalysisBufferDelay >
   1687          MAX_DELAY_SURROUND_ANALYSIS) ||
   1688         (hMp4SpaceEnc->nBitstreamDelayBuffer > MAX_BITSTREAM_DELAY)) {
   1689       error = SACENC_INIT_ERROR;
   1690       goto bail;
   1691     }
   1692   }
   1693 
   1694 bail:
   1695 
   1696   return error;
   1697 }
   1698 
   1699 static QUANTMODE __mapQuantMode(const MP4SPACEENC_QUANTMODE quantMode) {
   1700   QUANTMODE bsQuantMode = QUANTMODE_INVALID;
   1701 
   1702   switch (quantMode) {
   1703     case SACENC_QUANTMODE_FINE:
   1704       bsQuantMode = QUANTMODE_FINE;
   1705       break;
   1706     case SACENC_QUANTMODE_EBQ1:
   1707       bsQuantMode = QUANTMODE_EBQ1;
   1708       break;
   1709     case SACENC_QUANTMODE_EBQ2:
   1710       bsQuantMode = QUANTMODE_EBQ2;
   1711       break;
   1712     case SACENC_QUANTMODE_RSVD3:
   1713     case SACENC_QUANTMODE_INVALID:
   1714     default:
   1715       bsQuantMode = QUANTMODE_INVALID;
   1716   } /* switch hEnc->quantMode */
   1717 
   1718   return bsQuantMode;
   1719 }
   1720 
   1721 static FDK_SACENC_ERROR FillSpatialSpecificConfig(
   1722     const HANDLE_MP4SPACE_ENCODER hEnc, SPATIALSPECIFICCONFIG *const hSsc) {
   1723   FDK_SACENC_ERROR error = SACENC_OK;
   1724 
   1725   if ((NULL == hEnc) || (NULL == hSsc)) {
   1726     error = SACENC_INVALID_HANDLE;
   1727   } else {
   1728     SPACE_TREE_DESCRIPTION spaceTreeDescription;
   1729     int i;
   1730 
   1731     /* Get tree description */
   1732     if (SACENC_OK != (error = fdk_sacenc_spaceTree_GetDescription(
   1733                           hEnc->hSpaceTree, &spaceTreeDescription))) {
   1734       goto bail;
   1735     }
   1736 
   1737     /* Fill SSC */
   1738     FDKmemclear(hSsc, sizeof(SPATIALSPECIFICCONFIG)); /* reset */
   1739 
   1740     hSsc->numBands = hEnc->spaceTreeSetup.nParamBands; /* for bsFreqRes */
   1741 
   1742     /* Fill tree configuration */
   1743     hSsc->treeDescription.numOttBoxes = spaceTreeDescription.nOttBoxes;
   1744     hSsc->treeDescription.numInChan = spaceTreeDescription.nInChannels;
   1745     hSsc->treeDescription.numOutChan = spaceTreeDescription.nOutChannels;
   1746 
   1747     for (i = 0; i < SACENC_MAX_NUM_BOXES; i++) {
   1748       hSsc->ottConfig[i].bsOttBands = hSsc->numBands;
   1749     }
   1750 
   1751     switch (hEnc->encMode) {
   1752       case SACENC_212:
   1753         hSsc->bsTreeConfig = TREE_212;
   1754         break;
   1755       case SACENC_INVALID_MODE:
   1756       default:
   1757         error = SACENC_INVALID_CONFIG;
   1758         goto bail;
   1759     }
   1760 
   1761     hSsc->bsSamplingFrequency =
   1762         hEnc->nSampleRate; /* for bsSamplingFrequencyIndex */
   1763     hSsc->bsFrameLength = hEnc->nFrameTimeSlots - 1;
   1764 
   1765     /* map decorr type */
   1766     if (DECORR_INVALID ==
   1767         (hSsc->bsDecorrConfig = mp4SpaceEnc_GetDecorrConfig(hEnc->encMode))) {
   1768       error = SACENC_INVALID_CONFIG;
   1769       goto bail;
   1770     }
   1771 
   1772     /* map quantMode */
   1773     if (QUANTMODE_INVALID ==
   1774         (hSsc->bsQuantMode = __mapQuantMode(hEnc->quantMode))) {
   1775       error = SACENC_INVALID_CONFIG;
   1776       goto bail;
   1777     }
   1778 
   1779     /* Configure Gains*/
   1780     hSsc->bsFixedGainDMX = fdk_sacenc_staticGain_GetDmxGain(hEnc->hStaticGain);
   1781     hSsc->bsEnvQuantMode = 0;
   1782 
   1783   } /* valid handle */
   1784 
   1785 bail:
   1786   return error;
   1787 }
   1788 
   1789 static FDK_SACENC_ERROR mp4SpaceEnc_FillSpaceTreeSetup(
   1790     const HANDLE_MP4SPACE_ENCODER hEnc,
   1791     SPACE_TREE_SETUP *const hSpaceTreeSetup) {
   1792   FDK_SACENC_ERROR error = SACENC_OK;
   1793 
   1794   /* Sanity Check */
   1795   if (NULL == hEnc || NULL == hSpaceTreeSetup) {
   1796     error = SACENC_INVALID_HANDLE;
   1797   } else {
   1798     QUANTMODE tmpQuantmode = QUANTMODE_INVALID;
   1799 
   1800     /* map quantMode */
   1801     if (QUANTMODE_INVALID == (tmpQuantmode = __mapQuantMode(hEnc->quantMode))) {
   1802       error = SACENC_INVALID_CONFIG;
   1803       goto bail;
   1804     }
   1805 
   1806     hSpaceTreeSetup->nParamBands = hEnc->nParamBands;
   1807     hSpaceTreeSetup->bUseCoarseQuantTtoCld = hEnc->useCoarseQuantCld;
   1808     hSpaceTreeSetup->bUseCoarseQuantTtoIcc = hEnc->useCoarseQuantIcc;
   1809     hSpaceTreeSetup->quantMode = tmpQuantmode;
   1810     hSpaceTreeSetup->nHybridBandsMax = hEnc->nHybridBands;
   1811 
   1812     switch (hEnc->encMode) {
   1813       case SACENC_212:
   1814         hSpaceTreeSetup->mode = SPACETREE_212;
   1815         hSpaceTreeSetup->nChannelsInMax = 2;
   1816         break;
   1817       case SACENC_INVALID_MODE:
   1818       default:
   1819         error = SACENC_INVALID_CONFIG;
   1820         goto bail;
   1821     } /* switch hEnc->encMode */
   1822 
   1823   } /* valid handle */
   1824 bail:
   1825   return error;
   1826 }
   1827 
   1828 FDK_SACENC_ERROR FDK_sacenc_getInfo(const HANDLE_MP4SPACE_ENCODER hMp4SpaceEnc,
   1829                                     MP4SPACEENC_INFO *const pInfo) {
   1830   FDK_SACENC_ERROR error = SACENC_OK;
   1831 
   1832   if ((NULL == hMp4SpaceEnc) || (NULL == pInfo)) {
   1833     error = SACENC_INVALID_HANDLE;
   1834   } else {
   1835     pInfo->nSampleRate = hMp4SpaceEnc->nSampleRate;
   1836     pInfo->nSamplesFrame = hMp4SpaceEnc->nFrameLength;
   1837     pInfo->nTotalInputChannels = hMp4SpaceEnc->nInputChannels;
   1838     pInfo->nDmxDelay = fdk_sacenc_delay_GetInfoDmxDelay(hMp4SpaceEnc->hDelay);
   1839     pInfo->nCodecDelay =
   1840         fdk_sacenc_delay_GetInfoCodecDelay(hMp4SpaceEnc->hDelay);
   1841     pInfo->nDecoderDelay =
   1842         fdk_sacenc_delay_GetInfoDecoderDelay(hMp4SpaceEnc->hDelay);
   1843     pInfo->nPayloadDelay =
   1844         fdk_sacenc_delay_GetBitstreamFrameBufferSize(hMp4SpaceEnc->hDelay) - 1;
   1845     pInfo->nDiscardOutFrames = hMp4SpaceEnc->nDiscardOutFrames;
   1846 
   1847     pInfo->pSscBuf = &hMp4SpaceEnc->sscBuf;
   1848   }
   1849   return error;
   1850 }
   1851 
   1852 FDK_SACENC_ERROR FDK_sacenc_setParam(HANDLE_MP4SPACE_ENCODER hMp4SpaceEnc,
   1853                                      const SPACEENC_PARAM param,
   1854                                      const UINT value) {
   1855   FDK_SACENC_ERROR error = SACENC_OK;
   1856 
   1857   /* check encoder handle */
   1858   if (hMp4SpaceEnc == NULL) {
   1859     error = SACENC_INVALID_HANDLE;
   1860     goto bail;
   1861   }
   1862 
   1863   /* apply param value */
   1864   switch (param) {
   1865     case SACENC_LOWDELAY:
   1866       if (!((value == 0) || (value == 1) || (value == 2))) {
   1867         error = SACENC_INVALID_CONFIG;
   1868         break;
   1869       }
   1870       hMp4SpaceEnc->user.bLdMode = value;
   1871       break;
   1872 
   1873     case SACENC_ENC_MODE:
   1874       switch ((MP4SPACEENC_MODE)value) {
   1875         case SACENC_212:
   1876           hMp4SpaceEnc->user.encMode = (MP4SPACEENC_MODE)value;
   1877           break;
   1878         default:
   1879           error = SACENC_INVALID_CONFIG;
   1880       }
   1881       break;
   1882 
   1883     case SACENC_SAMPLERATE:
   1884       if (((int)value < 0) ||
   1885           ((int)value > hMp4SpaceEnc->setup.maxSamplingrate)) {
   1886         error = SACENC_INVALID_CONFIG;
   1887         break;
   1888       }
   1889       hMp4SpaceEnc->user.sampleRate = value;
   1890       break;
   1891 
   1892     case SACENC_FRAME_TIME_SLOTS:
   1893       if (((int)value < 0) ||
   1894           ((int)value > hMp4SpaceEnc->setup.maxFrameTimeSlots)) {
   1895         error = SACENC_INVALID_CONFIG;
   1896         break;
   1897       }
   1898       hMp4SpaceEnc->user.frameTimeSlots = value;
   1899       break;
   1900 
   1901     case SACENC_PARAM_BANDS:
   1902       switch ((MP4SPACEENC_BANDS_CONFIG)value) {
   1903         case SACENC_BANDS_4:
   1904         case SACENC_BANDS_5:
   1905         case SACENC_BANDS_7:
   1906         case SACENC_BANDS_9:
   1907         case SACENC_BANDS_12:
   1908         case SACENC_BANDS_15:
   1909         case SACENC_BANDS_23:
   1910           hMp4SpaceEnc->user.nParamBands = (MP4SPACEENC_BANDS_CONFIG)value;
   1911           break;
   1912         default:
   1913           error = SACENC_INVALID_CONFIG;
   1914       }
   1915       break;
   1916 
   1917     case SACENC_TIME_DOM_DMX:
   1918       if (!((value == 0) || (value == 2))) {
   1919         error = SACENC_INVALID_CONFIG;
   1920         break;
   1921       }
   1922       hMp4SpaceEnc->user.bTimeDomainDmx = value;
   1923       break;
   1924 
   1925     case SACENC_DMX_GAIN:
   1926       if (!((value == 0) || (value == 1) || (value == 2) || (value == 3) ||
   1927             (value == 4) || (value == 5) || (value == 6) || (value == 7))) {
   1928         error = SACENC_INVALID_CONFIG;
   1929         break;
   1930       }
   1931       error = fdk_sacenc_staticGain_SetDmxGain(hMp4SpaceEnc->hStaticGainConfig,
   1932                                                (MP4SPACEENC_DMX_GAIN)value);
   1933       break;
   1934 
   1935     case SACENC_COARSE_QUANT:
   1936       if (!((value == 0) || (value == 1))) {
   1937         error = SACENC_INVALID_CONFIG;
   1938         break;
   1939       }
   1940       hMp4SpaceEnc->user.bUseCoarseQuant = value;
   1941       break;
   1942 
   1943     case SACENC_QUANT_MODE:
   1944       switch ((MP4SPACEENC_QUANTMODE)value) {
   1945         case SACENC_QUANTMODE_FINE:
   1946         case SACENC_QUANTMODE_EBQ1:
   1947         case SACENC_QUANTMODE_EBQ2:
   1948           hMp4SpaceEnc->user.quantMode = (MP4SPACEENC_QUANTMODE)value;
   1949           break;
   1950         default:
   1951           error = SACENC_INVALID_CONFIG;
   1952       }
   1953       break;
   1954 
   1955     case SACENC_TIME_ALIGNMENT:
   1956       if ((INT)value < -32768 || (INT)value > 32767) {
   1957         error = SACENC_INVALID_CONFIG;
   1958         break;
   1959       }
   1960       hMp4SpaceEnc->user.timeAlignment = value;
   1961       break;
   1962 
   1963     case SACENC_INDEPENDENCY_COUNT:
   1964       hMp4SpaceEnc->independencyCount = value;
   1965       break;
   1966 
   1967     case SACENC_INDEPENDENCY_FACTOR:
   1968       hMp4SpaceEnc->user.independencyFactor = value;
   1969       break;
   1970 
   1971     default:
   1972       error = SACENC_UNSUPPORTED_PARAMETER;
   1973       break;
   1974   } /* switch(param) */
   1975 bail:
   1976   return error;
   1977 }
   1978 
   1979 FDK_SACENC_ERROR FDK_sacenc_getLibInfo(LIB_INFO *info) {
   1980   int i = 0;
   1981 
   1982   if (info == NULL) {
   1983     return SACENC_INVALID_HANDLE;
   1984   }
   1985 
   1986   FDK_toolsGetLibInfo(info);
   1987 
   1988   /* search for next free tab */
   1989   for (i = 0; i < FDK_MODULE_LAST; i++) {
   1990     if (info[i].module_id == FDK_NONE) break;
   1991   }
   1992   if (i == FDK_MODULE_LAST) {
   1993     return SACENC_INIT_ERROR;
   1994   }
   1995 
   1996   info[i].module_id = FDK_MPSENC;
   1997   info[i].build_date = SACENC_LIB_BUILD_DATE;
   1998   info[i].build_time = SACENC_LIB_BUILD_TIME;
   1999   info[i].title = SACENC_LIB_TITLE;
   2000   info[i].version = LIB_VERSION(SACENC_LIB_VL0, SACENC_LIB_VL1, SACENC_LIB_VL2);
   2001   LIB_VERSION_STRING(&info[i]);
   2002 
   2003   /* Capability flags */
   2004   info[i].flags = 0;
   2005   /* End of flags */
   2006 
   2007   return SACENC_OK;
   2008 }
   2009 
   2010 static DECORRCONFIG mp4SpaceEnc_GetDecorrConfig(
   2011     const MP4SPACEENC_MODE encMode) {
   2012   DECORRCONFIG decorrConfig = DECORR_INVALID;
   2013 
   2014   /* set decorrConfig dependent on tree mode */
   2015   switch (encMode) {
   2016     case SACENC_212:
   2017       decorrConfig = DECORR_QMFSPLIT0;
   2018       break;
   2019     case SACENC_INVALID_MODE:
   2020     default:
   2021       decorrConfig = DECORR_INVALID;
   2022   }
   2023   return decorrConfig;
   2024 }
   2025 
   2026 static FDK_SACENC_ERROR mp4SpaceEnc_InitNumParamBands(
   2027     HANDLE_MP4SPACE_ENCODER hEnc, const MP4SPACEENC_BANDS_CONFIG nParamBands) {
   2028   FDK_SACENC_ERROR error = SACENC_OK;
   2029 
   2030   /* Set/Check nParamBands */
   2031   int k = 0;
   2032   const int n = sizeof(pValidBands_Ld) / sizeof(UCHAR);
   2033   const UCHAR *pBands = pValidBands_Ld;
   2034 
   2035   while (k < n && pBands[k] != (UCHAR)nParamBands) ++k;
   2036   if (k == n) {
   2037     hEnc->nParamBands = SACENC_BANDS_INVALID;
   2038   } else {
   2039     hEnc->nParamBands = nParamBands;
   2040   }
   2041   return error;
   2042 }
   2043