/*  Copyright (c) MediaArea.net SARL. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license that can
 *  be found in the License.html file in the root of the source tree.
 */

//---------------------------------------------------------------------------
// Pre-compilation
#include "MediaInfo/PreComp.h"
#ifdef __BORLANDC__
    #pragma hdrstop
#endif
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#include "MediaInfo/Setup.h"
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#if defined(MEDIAINFO_AAC_YES) || defined(MEDIAINFO_MPEGH3DA_YES)
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#include "MediaInfo/Audio/File_Usac.h"
#include "MediaInfo/Audio/File_Aac_GeneralAudio.h"
#include "MediaInfo/Audio/File_Aac_GeneralAudio_Sbr.h"
#include <algorithm>
#include <cmath>

using namespace std;

#define ARITH_ESCAPE 16

//---------------------------------------------------------------------------

namespace MediaInfoLib
{
//***************************************************************************
// Tables
//***************************************************************************

struct stts_struct
{
    int32u                      SampleCount;
    int32u                      SampleDuration;
};

struct sgpd_prol_struct
{
    int16s                      roll_distance;
};

struct sbgp_struct
{
    int64u                      FirstSample;
    int64u                      LastSample;
    int32u                      group_description_index;

    bool operator==(int64u SamplePos) const
    {
        return SamplePos>=FirstSample && SamplePos<LastSample;
    }
};

//***************************************************************************
//---------------------------------------------------------------------------
static const int16u huffman_scl[][4]=
{
    {0x00f3, 0x00f3, 0x0004, 0x0008},
    {0x00ef, 0x00ef, 0x00f5, 0x00e9},
    {0x00f9, 0x000c, 0x0010, 0x0014},
    {0x00e7, 0x00e7, 0x00ff, 0x00ff},
    {0x00e1, 0x0101, 0x00dd, 0x0105},
    {0x0018, 0x001c, 0x0020, 0x0028},
    {0x010b, 0x010b, 0x00db, 0x00db},
    {0x010f, 0x010f, 0x00d5, 0x0111},
    {0x00d1, 0x0115, 0x00cd, 0x0024},
    {0x011b, 0x011b, 0x00cb, 0x00cb},
    {0x002c, 0x0030, 0x0034, 0x0040},
    {0x00c7, 0x00c7, 0x011f, 0x011f},
    {0x0121, 0x00c1, 0x0125, 0x00bd},
    {0x0129, 0x00b9, 0x0038, 0x003c},
    {0x0133, 0x0133, 0x012f, 0x012f},
    {0x0137, 0x0137, 0x013b, 0x013b},
    {0x0044, 0x0048, 0x004c, 0x0058},
    {0x00b7, 0x00b7, 0x00af, 0x00af},
    {0x00b1, 0x013d, 0x00a9, 0x00a5},
    {0x0141, 0x00a1, 0x0050, 0x0054},
    {0x0147, 0x0147, 0x009f, 0x009f},
    {0x014b, 0x014b, 0x009b, 0x009b},
    {0x005c, 0x0060, 0x0064, 0x0070},
    {0x014f, 0x014f, 0x0095, 0x008d},
    {0x0155, 0x0085, 0x0091, 0x0089},
    {0x0151, 0x0081, 0x0068, 0x006c},
    {0x015f, 0x015f, 0x0167, 0x0167},
    {0x007b, 0x007b, 0x007f, 0x007f},
    {0x0074, 0x0078, 0x0080, 0x00b0},
    {0x0159, 0x0075, 0x0069, 0x006d},
    {0x0071, 0x0061, 0x0161, 0x007c},
    {0x0067, 0x0067, 0x005b, 0x005b},
    {0x0084, 0x0088, 0x008c, 0x009c},
    {0x005f, 0x005f, 0x0169, 0x0055},
    {0x004d, 0x000d, 0x0005, 0x0009},
    {0x0001, 0x0090, 0x0094, 0x0098},
    {0x018b, 0x018b, 0x018f, 0x018f},
    {0x0193, 0x0193, 0x0197, 0x0197},
    {0x019b, 0x019b, 0x01d7, 0x01d7},
    {0x00a0, 0x00a4, 0x00a8, 0x00ac},
    {0x0187, 0x0187, 0x016f, 0x016f},
    {0x0173, 0x0173, 0x0177, 0x0177},
    {0x017b, 0x017b, 0x017f, 0x017f},
    {0x0183, 0x0183, 0x01a3, 0x01a3},
    {0x00b4, 0x00c8, 0x00dc, 0x00f0},
    {0x00b8, 0x00bc, 0x00c0, 0x00c4},
    {0x01bf, 0x01bf, 0x01c3, 0x01c3},
    {0x01c7, 0x01c7, 0x01cb, 0x01cb},
    {0x01cf, 0x01cf, 0x01d3, 0x01d3},
    {0x01bb, 0x01bb, 0x01a7, 0x01a7},
    {0x00cc, 0x00d0, 0x00d4, 0x00d8},
    {0x01ab, 0x01ab, 0x01af, 0x01af},
    {0x01b3, 0x01b3, 0x01b7, 0x01b7},
    {0x01db, 0x01db, 0x001b, 0x001b},
    {0x0023, 0x0023, 0x0027, 0x0027},
    {0x00e0, 0x00e4, 0x00e8, 0x00ec},
    {0x002b, 0x002b, 0x0017, 0x0017},
    {0x019f, 0x019f, 0x01e3, 0x01e3},
    {0x01df, 0x01df, 0x0013, 0x0013},
    {0x001f, 0x001f, 0x003f, 0x003f},
    {0x00f4, 0x00f8, 0x00fc, 0x0100},
    {0x0043, 0x0043, 0x004b, 0x004b},
    {0x0053, 0x0053, 0x0047, 0x0047},
    {0x002f, 0x002f, 0x0033, 0x0033},
    {0x003b, 0x003b, 0x0037, 0x0037}
};

//---------------------------------------------------------------------------
static const int16u arith_lookup_m[]=
{
    0x01,0x34,0x0D,0x13,0x12,0x25,0x00,0x3A,0x05,0x00,0x21,0x13,0x1F,0x1A,0x1D,0x36,
    0x24,0x2B,0x1B,0x33,0x37,0x29,0x1D,0x33,0x37,0x33,0x37,0x33,0x37,0x33,0x2C,0x00,
    0x21,0x13,0x25,0x2A,0x00,0x21,0x24,0x12,0x2C,0x1E,0x37,0x24,0x1F,0x35,0x37,0x24,
    0x35,0x37,0x35,0x37,0x38,0x2D,0x21,0x29,0x1E,0x21,0x13,0x2D,0x36,0x38,0x29,0x36,
    0x37,0x24,0x36,0x38,0x37,0x38,0x00,0x20,0x23,0x20,0x23,0x36,0x38,0x24,0x3B,0x24,
    0x26,0x29,0x1F,0x30,0x2D,0x0D,0x12,0x3F,0x2D,0x21,0x1C,0x2A,0x00,0x21,0x12,0x1E,
    0x36,0x38,0x36,0x37,0x3F,0x1E,0x0D,0x1F,0x2A,0x1E,0x21,0x24,0x12,0x2A,0x3C,0x21,
    0x24,0x1F,0x3C,0x21,0x29,0x36,0x38,0x36,0x37,0x38,0x21,0x1E,0x00,0x3B,0x25,0x1E,
    0x20,0x10,0x1F,0x3C,0x20,0x23,0x29,0x08,0x23,0x12,0x08,0x23,0x21,0x38,0x00,0x20,
    0x13,0x20,0x3B,0x1C,0x20,0x3B,0x29,0x20,0x23,0x24,0x21,0x24,0x21,0x24,0x3B,0x13,
    0x23,0x26,0x23,0x13,0x21,0x24,0x26,0x29,0x12,0x22,0x2B,0x02,0x1E,0x0D,0x1F,0x2D,
    0x00,0x0D,0x12,0x00,0x3C,0x21,0x29,0x3C,0x21,0x2A,0x3C,0x3B,0x22,0x1E,0x20,0x10,
    0x1F,0x3C,0x0D,0x29,0x3C,0x21,0x24,0x08,0x23,0x20,0x38,0x39,0x3C,0x20,0x13,0x3C,
    0x00,0x0D,0x13,0x1F,0x3C,0x09,0x26,0x1F,0x08,0x09,0x26,0x12,0x08,0x23,0x29,0x20,
    0x23,0x21,0x24,0x20,0x13,0x20,0x3B,0x16,0x20,0x3B,0x29,0x20,0x3B,0x29,0x20,0x3B,
    0x13,0x21,0x24,0x29,0x0B,0x13,0x09,0x3B,0x13,0x09,0x3B,0x13,0x21,0x3B,0x13,0x0D,
    0x26,0x29,0x26,0x29,0x3D,0x12,0x22,0x28,0x2E,0x04,0x08,0x13,0x3C,0x3B,0x3C,0x20,
    0x10,0x3C,0x21,0x07,0x08,0x10,0x00,0x08,0x0D,0x29,0x08,0x0D,0x29,0x08,0x09,0x13,
    0x20,0x23,0x39,0x08,0x09,0x13,0x08,0x09,0x16,0x08,0x09,0x10,0x12,0x20,0x3B,0x3D,
    0x09,0x26,0x20,0x3B,0x24,0x39,0x09,0x26,0x20,0x0D,0x13,0x00,0x09,0x13,0x20,0x0D,
    0x26,0x12,0x20,0x3B,0x13,0x21,0x26,0x0B,0x12,0x09,0x3B,0x16,0x09,0x3B,0x3D,0x09,
    0x26,0x0D,0x13,0x26,0x3D,0x1C,0x12,0x1F,0x28,0x2E,0x07,0x0B,0x08,0x09,0x00,0x39,
    0x0B,0x08,0x26,0x08,0x09,0x13,0x20,0x0B,0x39,0x10,0x39,0x0D,0x13,0x20,0x10,0x12,
    0x09,0x13,0x20,0x3B,0x13,0x09,0x26,0x0B,0x09,0x3B,0x1C,0x09,0x3B,0x13,0x20,0x3B,
    0x13,0x09,0x26,0x0B,0x16,0x0D,0x13,0x09,0x13,0x09,0x13,0x26,0x3D,0x1C,0x1F,0x28,
    0x2E,0x07,0x10,0x39,0x0B,0x39,0x39,0x13,0x39,0x0B,0x39,0x0B,0x39,0x26,0x39,0x10,
    0x20,0x3B,0x16,0x20,0x10,0x09,0x26,0x0B,0x13,0x09,0x13,0x26,0x1C,0x0B,0x3D,0x1C,
    0x1F,0x28,0x2B,0x07,0x0C,0x39,0x0B,0x39,0x0B,0x0C,0x0B,0x26,0x0B,0x26,0x3D,0x0D,
    0x1C,0x14,0x28,0x2B,0x39,0x0B,0x0C,0x0E,0x3D,0x1C,0x0D,0x12,0x22,0x2B,0x07,0x0C,
    0x0E,0x3D,0x1C,0x10,0x1F,0x2B,0x0C,0x0E,0x19,0x14,0x10,0x1F,0x28,0x0C,0x0E,0x19,
    0x14,0x26,0x22,0x2B,0x0C,0x0E,0x19,0x14,0x26,0x28,0x0E,0x19,0x14,0x26,0x28,0x0E,
    0x19,0x14,0x28,0x0E,0x19,0x14,0x22,0x28,0x2B,0x0E,0x14,0x2B,0x31,0x00,0x3A,0x3A,
    0x05,0x05,0x1B,0x1D,0x33,0x06,0x35,0x35,0x20,0x21,0x37,0x21,0x24,0x05,0x1B,0x2C,
    0x2C,0x2C,0x06,0x34,0x1E,0x34,0x00,0x08,0x36,0x09,0x21,0x26,0x1C,0x2C,0x00,0x02,
    0x02,0x02,0x3F,0x04,0x04,0x04,0x34,0x39,0x20,0x0A,0x0C,0x39,0x0B,0x0F,0x07,0x07,
    0x07,0x07,0x34,0x39,0x39,0x0A,0x0C,0x39,0x0C,0x0F,0x07,0x07,0x07,0x00,0x39,0x39,
    0x0C,0x0F,0x07,0x07,0x39,0x0C,0x0F,0x07,0x39,0x0C,0x0F,0x39,0x39,0x0C,0x0F,0x39,
    0x0C,0x39,0x0C,0x0F,0x00,0x11,0x27,0x17,0x2F,0x27,0x00,0x27,0x17,0x00,0x11,0x17,
    0x00,0x11,0x17,0x11,0x00,0x27,0x15,0x11,0x17,0x01,0x15,0x11,0x15,0x11,0x15,0x15,
    0x17,0x00,0x27,0x01,0x27,0x27,0x15,0x00,0x27,0x11,0x27,0x15,0x15,0x15,0x27,0x15,
    0x15,0x15,0x15,0x17,0x2F,0x11,0x17,0x27,0x27,0x27,0x11,0x27,0x15,0x27,0x27,0x15,
    0x15,0x27,0x17,0x2F,0x27,0x17,0x2F,0x27,0x17,0x2F,0x27,0x17,0x2F,0x27,0x17,0x2F,
    0x27,0x17,0x2F,0x27,0x17,0x2F,0x27,0x17,0x2F,0x27,0x17,0x2F,0x27,0x17,0x2F,0x27,
    0x17,0x2F,0x27,0x17,0x2F,0x27,0x17,0x2F,0x17,0x2F,0x2B,0x00,0x27,0x00,0x00,0x11,
    0x15,0x00,0x11,0x11,0x27,0x27,0x15,0x17,0x15,0x17,0x15,0x17,0x27,0x17,0x27,0x17,
    0x27,0x17,0x27,0x17,0x27,0x17,0x27,0x17,0x27,0x17,0x27,0x17,0x27,0x17,0x27,0x17,
    0x27,0x15,0x27,0x27,0x15,0x27
};

//---------------------------------------------------------------------------
static const int32u arith_hash_m[]=
{
    0x00000104UL,0x0000030AUL,0x00000510UL,0x00000716UL,0x00000A1FUL,0x00000F2EUL,
    0x00011100UL,0x00111103UL,0x00111306UL,0x00111436UL,0x00111623UL,0x00111929UL,
    0x00111F2EUL,0x0011221BUL,0x00112435UL,0x00112621UL,0x00112D12UL,0x00113130UL,
    0x0011331DUL,0x00113535UL,0x00113938UL,0x0011411BUL,0x00114433UL,0x00114635UL,
    0x00114F29UL,0x00116635UL,0x00116F24UL,0x00117433UL,0x0011FF0FUL,0x00121102UL,
    0x0012132DUL,0x00121436UL,0x00121623UL,0x00121912UL,0x0012213FUL,0x0012232DUL,
    0x00122436UL,0x00122638UL,0x00122A29UL,0x00122F2BUL,0x0012322DUL,0x00123436UL,
    0x00123738UL,0x00123B29UL,0x0012411DUL,0x00124536UL,0x00124938UL,0x00124F12UL,
    0x00125535UL,0x00125F29UL,0x00126535UL,0x0012B837UL,0x0013112AUL,0x0013131EUL,
    0x0013163BUL,0x0013212DUL,0x0013233CUL,0x00132623UL,0x00132F2EUL,0x0013321EUL,
    0x00133521UL,0x00133824UL,0x0013411EUL,0x00134336UL,0x00134838UL,0x00135135UL,
    0x00135537UL,0x00135F12UL,0x00137637UL,0x0013FF29UL,0x00140024UL,0x00142321UL,
    0x00143136UL,0x00143321UL,0x00143F25UL,0x00144321UL,0x00148638UL,0x0014FF29UL,
    0x00154323UL,0x0015FF12UL,0x0016F20CUL,0x0018A529UL,0x00210031UL,0x0021122CUL,
    0x00211408UL,0x00211713UL,0x00211F2EUL,0x0021222AUL,0x00212408UL,0x00212710UL,
    0x00212F2EUL,0x0021331EUL,0x00213436UL,0x00213824UL,0x0021412DUL,0x0021431EUL,
    0x00214536UL,0x00214F1FUL,0x00216637UL,0x00220004UL,0x0022122AUL,0x00221420UL,
    0x00221829UL,0x00221F2EUL,0x0022222DUL,0x00222408UL,0x00222623UL,0x00222929UL,
    0x00222F2BUL,0x0022321EUL,0x00223408UL,0x00223724UL,0x00223A29UL,0x0022411EUL,
    0x00224436UL,0x00224823UL,0x00225134UL,0x00225621UL,0x00225F12UL,0x00226336UL,
    0x00227637UL,0x0022FF29UL,0x0023112DUL,0x0023133CUL,0x00231420UL,0x00231916UL,
    0x0023212DUL,0x0023233CUL,0x00232509UL,0x00232929UL,0x0023312DUL,0x00233308UL,
    0x00233509UL,0x00233724UL,0x0023413CUL,0x00234421UL,0x00234A13UL,0x0023513CUL,
    0x00235421UL,0x00235F1FUL,0x00236421UL,0x0023FF29UL,0x00240024UL,0x0024153BUL,
    0x00242108UL,0x00242409UL,0x00242726UL,0x00243108UL,0x00243409UL,0x00243610UL,
    0x00244136UL,0x00244321UL,0x00244523UL,0x00244F1FUL,0x00245423UL,0x0024610AUL,
    0x00246423UL,0x0024FF29UL,0x00252510UL,0x00253121UL,0x0025343BUL,0x00254121UL,
    0x00254510UL,0x00254F25UL,0x00255221UL,0x0025FF12UL,0x00266513UL,0x0027F529UL,
    0x0029F101UL,0x002CF224UL,0x00310030UL,0x0031122AUL,0x00311420UL,0x00311816UL,
    0x0031212CUL,0x0031231EUL,0x00312408UL,0x00312710UL,0x0031312AUL,0x0031321EUL,
    0x00313408UL,0x00313623UL,0x0031411EUL,0x0031433CUL,0x00320007UL,0x0032122DUL,
    0x00321420UL,0x00321816UL,0x0032212DUL,0x0032233CUL,0x00322509UL,0x00322916UL,
    0x0032312DUL,0x00323420UL,0x00323710UL,0x00323F2BUL,0x00324308UL,0x00324623UL,
    0x00324F25UL,0x00325421UL,0x00325F1FUL,0x00326421UL,0x0032FF29UL,0x00331107UL,
    0x00331308UL,0x0033150DUL,0x0033211EUL,0x00332308UL,0x00332420UL,0x00332610UL,
    0x00332929UL,0x0033311EUL,0x00333308UL,0x0033363BUL,0x00333A29UL,0x0033413CUL,
    0x00334320UL,0x0033463BUL,0x00334A29UL,0x0033510AUL,0x00335320UL,0x00335824UL,
    0x0033610AUL,0x00336321UL,0x00336F12UL,0x00337623UL,0x00341139UL,0x0034153BUL,
    0x00342108UL,0x00342409UL,0x00342610UL,0x00343108UL,0x00343409UL,0x00343610UL,
    0x00344108UL,0x0034440DUL,0x00344610UL,0x0034510AUL,0x00345309UL,0x0034553BUL,
    0x0034610AUL,0x00346309UL,0x0034F824UL,0x00350029UL,0x00352510UL,0x00353120UL,
    0x0035330DUL,0x00353510UL,0x00354120UL,0x0035430DUL,0x00354510UL,0x00354F28UL,
    0x0035530DUL,0x00355510UL,0x00355F1FUL,0x00356410UL,0x00359626UL,0x0035FF12UL,
    0x00366426UL,0x0036FF12UL,0x0037F426UL,0x0039D712UL,0x003BF612UL,0x003DF81FUL,
    0x00410004UL,0x00411207UL,0x0041150DUL,0x0041212AUL,0x00412420UL,0x0041311EUL,
    0x00413308UL,0x00413509UL,0x00413F2BUL,0x00414208UL,0x00420007UL,0x0042123CUL,
    0x00421409UL,0x00422107UL,0x0042223CUL,0x00422409UL,0x00422610UL,0x0042313CUL,
    0x00423409UL,0x0042363BUL,0x0042413CUL,0x00424320UL,0x0042463BUL,0x00425108UL,
    0x00425409UL,0x0042FF29UL,0x00431107UL,0x00431320UL,0x0043153BUL,0x0043213CUL,
    0x00432320UL,0x00432610UL,0x0043313CUL,0x00433320UL,0x0043353BUL,0x00433813UL,
    0x00434108UL,0x00434409UL,0x00434610UL,0x00435108UL,0x0043553BUL,0x00435F25UL,
    0x00436309UL,0x0043753BUL,0x0043FF29UL,0x00441239UL,0x0044143BUL,0x00442139UL,
    0x00442309UL,0x0044253BUL,0x00443108UL,0x00443220UL,0x0044353BUL,0x0044410AUL,
    0x00444309UL,0x0044453BUL,0x00444813UL,0x0044510AUL,0x00445309UL,0x00445510UL,
    0x00445F25UL,0x0044630DUL,0x00450026UL,0x00452713UL,0x00453120UL,0x0045330DUL,
    0x00453510UL,0x00454120UL,0x0045430DUL,0x00454510UL,0x00455120UL,0x0045530DUL,
    0x00456209UL,0x00456410UL,0x0045FF12UL,0x00466513UL,0x0047FF22UL,0x0048FF25UL,
    0x0049F43DUL,0x004BFB25UL,0x004EF825UL,0x004FFF18UL,0x00511339UL,0x00512107UL,
    0x00513409UL,0x00520007UL,0x00521107UL,0x00521320UL,0x00522107UL,0x00522409UL,
    0x0052313CUL,0x00523320UL,0x0052353BUL,0x00524108UL,0x00524320UL,0x00531139UL,
    0x00531309UL,0x00532139UL,0x00532309UL,0x0053253BUL,0x00533108UL,0x0053340DUL,
    0x00533713UL,0x00534108UL,0x0053453BUL,0x00534F2BUL,0x00535309UL,0x00535610UL,
    0x00535F25UL,0x0053643BUL,0x00541139UL,0x00542139UL,0x00542309UL,0x00542613UL,
    0x00543139UL,0x00543309UL,0x00543510UL,0x00543F2BUL,0x00544309UL,0x00544510UL,
    0x00544F28UL,0x0054530DUL,0x0054FF12UL,0x00553613UL,0x00553F2BUL,0x00554410UL,
    0x0055510AUL,0x0055543BUL,0x00555F25UL,0x0055633BUL,0x0055FF12UL,0x00566513UL,
    0x00577413UL,0x0059FF28UL,0x005CC33DUL,0x005EFB28UL,0x005FFF18UL,0x00611339UL,
    0x00612107UL,0x00613320UL,0x0061A724UL,0x00621107UL,0x0062140BUL,0x00622107UL,
    0x00622320UL,0x00623139UL,0x00623320UL,0x00631139UL,0x0063130CUL,0x00632139UL,
    0x00632309UL,0x00633139UL,0x00633309UL,0x00633626UL,0x00633F2BUL,0x00634309UL,
    0x00634F2BUL,0x0063543BUL,0x0063FF12UL,0x0064343BUL,0x00643F2BUL,0x0064443BUL,
    0x00645209UL,0x00665513UL,0x0066610AUL,0x00666526UL,0x0067A616UL,0x0069843DUL,
    0x006CF612UL,0x006EF326UL,0x006FFF18UL,0x0071130CUL,0x00721107UL,0x00722239UL,
    0x0072291CUL,0x0072340BUL,0x00731139UL,0x00732239UL,0x0073630BUL,0x0073FF12UL,
    0x0074430BUL,0x00755426UL,0x00776F28UL,0x00777410UL,0x0078843DUL,0x007CF416UL,
    0x007EF326UL,0x007FFF18UL,0x00822239UL,0x00831139UL,0x0083430BUL,0x0084530BUL,
    0x0087561CUL,0x00887F25UL,0x00888426UL,0x008AF61CUL,0x008F0018UL,0x008FFF18UL,
    0x00911107UL,0x0093230BUL,0x0094530BUL,0x0097743DUL,0x00998C25UL,0x00999616UL,
    0x009EF825UL,0x009FFF18UL,0x00A3430BUL,0x00A4530BUL,0x00A7743DUL,0x00AA9F2BUL,
    0x00AAA616UL,0x00ABD61FUL,0x00AFFF18UL,0x00B3330BUL,0x00B44426UL,0x00B7643DUL,
    0x00BB971FUL,0x00BBB53DUL,0x00BEF512UL,0x00BFFF18UL,0x00C22139UL,0x00C5330EUL,
    0x00C7633DUL,0x00CCAF2EUL,0x00CCC616UL,0x00CFFF18UL,0x00D4440EUL,0x00D6420EUL,
    0x00DDCF2EUL,0x00DDD516UL,0x00DFFF18UL,0x00E4330EUL,0x00E6841CUL,0x00EEE61CUL,
    0x00EFFF18UL,0x00F3320EUL,0x00F55319UL,0x00F8F41CUL,0x00FAFF2EUL,0x00FF002EUL,
    0x00FFF10CUL,0x00FFF33DUL,0x00FFF722UL,0x00FFFF18UL,0x01000232UL,0x0111113EUL,
    0x01112103UL,0x0111311AUL,0x0112111AUL,0x01122130UL,0x01123130UL,0x0112411DUL,
    0x01131102UL,0x01132102UL,0x01133102UL,0x01141108UL,0x01142136UL,0x01143136UL,
    0x01144135UL,0x0115223BUL,0x01211103UL,0x0121211AUL,0x01213130UL,0x01221130UL,
    0x01222130UL,0x01223102UL,0x01231104UL,0x01232104UL,0x01233104UL,0x01241139UL,
    0x01241220UL,0x01242220UL,0x01251109UL,0x0125223BUL,0x0125810AUL,0x01283212UL,
    0x0131111AUL,0x01312130UL,0x0131222CUL,0x0131322AUL,0x0132122AUL,0x0132222DUL,
    0x0132322DUL,0x01331207UL,0x01332234UL,0x01333234UL,0x01341139UL,0x01343134UL,
    0x01344134UL,0x01348134UL,0x0135220BUL,0x0136110BUL,0x01365224UL,0x01411102UL,
    0x01412104UL,0x01431239UL,0x01432239UL,0x0143320AUL,0x01435134UL,0x01443107UL,
    0x01444134UL,0x01446134UL,0x0145220EUL,0x01455134UL,0x0147110EUL,0x01511102UL,
    0x01521239UL,0x01531239UL,0x01532239UL,0x01533107UL,0x0155220EUL,0x01555134UL,
    0x0157110EUL,0x01611107UL,0x01621239UL,0x01631239UL,0x01661139UL,0x01666134UL,
    0x01711107UL,0x01721239UL,0x01745107UL,0x0177110CUL,0x01811107UL,0x01821107UL,
    0x0185110CUL,0x0188210CUL,0x01911107UL,0x01933139UL,0x01A11107UL,0x01A31139UL,
    0x01F5220EUL,0x02000001UL,0x02000127UL,0x02000427UL,0x02000727UL,0x02000E2FUL,
    0x02110000UL,0x02111200UL,0x02111411UL,0x02111827UL,0x02111F2FUL,0x02112411UL,
    0x02112715UL,0x02113200UL,0x02113411UL,0x02113715UL,0x02114200UL,0x02121200UL,
    0x02121301UL,0x02121F2FUL,0x02122200UL,0x02122615UL,0x02122F2FUL,0x02123311UL,
    0x02123F2FUL,0x02124411UL,0x02131211UL,0x02132311UL,0x02133211UL,0x02184415UL,
    0x02211200UL,0x02211311UL,0x02211F2FUL,0x02212311UL,0x02212F2FUL,0x02213211UL,
    0x02221201UL,0x02221311UL,0x02221F2FUL,0x02222311UL,0x02222F2FUL,0x02223211UL,
    0x02223F2FUL,0x02231211UL,0x02232211UL,0x02232F2FUL,0x02233211UL,0x02233F2FUL,
    0x02287515UL,0x022DAB17UL,0x02311211UL,0x02311527UL,0x02312211UL,0x02321211UL,
    0x02322211UL,0x02322F2FUL,0x02323311UL,0x02323F2FUL,0x02331211UL,0x02332211UL,
    0x02332F2FUL,0x02333F2FUL,0x0237FF17UL,0x02385615UL,0x023D9517UL,0x02410027UL,
    0x02487827UL,0x024E3117UL,0x024FFF2FUL,0x02598627UL,0x025DFF2FUL,0x025FFF2FUL,
    0x02687827UL,0x026DFA17UL,0x026FFF2FUL,0x02796427UL,0x027E4217UL,0x027FFF2FUL,
    0x02888727UL,0x028EFF2FUL,0x028FFF2FUL,0x02984327UL,0x029F112FUL,0x029FFF2FUL,
    0x02A76527UL,0x02AEF717UL,0x02AFFF2FUL,0x02B7C827UL,0x02BEF917UL,0x02BFFF2FUL,
    0x02C66527UL,0x02CD5517UL,0x02CFFF2FUL,0x02D63227UL,0x02DDD527UL,0x02DFFF2BUL,
    0x02E84717UL,0x02EEE327UL,0x02EFFF2FUL,0x02F54527UL,0x02FCF817UL,0x02FFEF2BUL,
    0x02FFFA2FUL,0x02FFFE2FUL,0x03000127UL,0x03000201UL,0x03111200UL,0x03122115UL,
    0x03123200UL,0x03133211UL,0x03211200UL,0x03213127UL,0x03221200UL,0x03345215UL,
    0x04000F17UL,0x04122F17UL,0x043F6515UL,0x043FFF17UL,0x044F5527UL,0x044FFF17UL,
    0x045F0017UL,0x045FFF17UL,0x046F6517UL,0x04710027UL,0x047F4427UL,0x04810027UL,
    0x048EFA15UL,0x048FFF2FUL,0x049F4427UL,0x049FFF2FUL,0x04AEA727UL,0x04AFFF2FUL,
    0x04BE9C15UL,0x04BFFF2FUL,0x04CE5427UL,0x04CFFF2FUL,0x04DE3527UL,0x04DFFF17UL,
    0x04EE4627UL,0x04EFFF17UL,0x04FEF327UL,0x04FFFF2FUL,0x06000F27UL,0x069FFF17UL,
    0x06FFFF17UL,0x08110017UL,0x08EFFF15UL,0xFFFFFF00UL
};

//---------------------------------------------------------------------------
static const int16u arith_cf_m[][17]=
{
    {  708,  706,  579,  569,  568,  567,  479,  469,  297,  138,   97,   91,   72,   52,   38,   34,    0},
    { 7619, 6917, 6519, 6412, 5514, 5003, 4683, 4563, 3907, 3297, 3125, 3060, 2904, 2718, 2631, 2590,    0},
    { 7263, 4888, 4810, 4803, 1889,  415,  335,  327,  195,   72,   52,   49,   36,   20,   15,   14,    0},
    { 3626, 2197, 2188, 2187,  582,   57,   47,   46,   30,   12,    9,    8,    6,    4,    3,    2,    0},
    { 7806, 5541, 5451, 5441, 2720,  834,  691,  674,  487,  243,  179,  167,  139,   98,   77,   70,    0},
    { 6684, 4101, 4058, 4055, 1748,  426,  368,  364,  322,  257,  235,  232,  228,  222,  217,  215,    0},
    { 9162, 5964, 5831, 5819, 3269,  866,  658,  638,  535,  348,  258,  244,  234,  214,  195,  186,    0},
    {10638, 8491, 8365, 8351, 4418, 2067, 1859, 1834, 1190,  601,  495,  478,  356,  217,  174,  164,    0},
    {13389,10514,10032, 9961, 7166, 3488, 2655, 2524, 2015, 1140,  760,  672,  585,  426,  325,  283,    0},
    {14861,12788,12115,11952, 9987, 6657, 5323, 4984, 4324, 3001, 2205, 1943, 1764, 1394, 1115,  978,    0},
    {12876,10004, 9661, 9610, 7107, 3435, 2711, 2595, 2257, 1508, 1059,  952,  893,  753,  609,  538,    0},
    {15125,13591,13049,12874,11192, 8543, 7406, 7023, 6291, 4922, 4104, 3769, 3465, 2890, 2486, 2275,    0},
    {14574,13106,12731,12638,10453, 7947, 7233, 7037, 6031, 4618, 4081, 3906, 3465, 2802, 2476, 2349,    0},
    {15070,13179,12517,12351,10742, 7657, 6200, 5825, 5264, 3998, 3014, 2662, 2510, 2153, 1799, 1564,    0},
    {15542,14466,14007,13844,12489,10409, 9481, 9132, 8305, 6940, 6193, 5867, 5458, 4743, 4291, 4047,    0},
    {15165,14384,14084,13934,12911,11485,10844,10513,10002, 8993, 8380, 8051, 7711, 7036, 6514, 6233,    0},
    {15642,14279,13625,13393,12348, 9971, 8405, 7858, 7335, 6119, 4918, 4376, 4185, 3719, 3231, 2860,    0},
    {13408,13407,11471,11218,11217,11216, 9473, 9216, 6480, 3689, 2857, 2690, 2256, 1732, 1405, 1302,    0},
    {16098,15584,15191,14931,14514,13578,12703,12103,11830,11172,10475, 9867, 9695, 9281, 8825, 8389,    0},
    {15844,14873,14277,13996,13230,11535,10205, 9543, 9107, 8086, 7085, 6419, 6214, 5713, 5195, 4731,    0},
    {16131,15720,15443,15276,14848,13971,13314,12910,12591,11874,11225,10788,10573,10077, 9585, 9209,    0},
    {16331,16330,12283,11435,11434,11433, 8725, 8049, 6065, 4138, 3187, 2842, 2529, 2171, 1907, 1745,    0},
    {16011,15292,14782,14528,14008,12767,11556,10921,10591, 9759, 8813, 8043, 7855, 7383, 6863, 6282,    0},
    {16380,16379,15159,14610,14609,14608,12859,12111,11046, 9536, 8348, 7713, 7216, 6533, 5964, 5546,    0},
    {16367,16333,16294,16253,16222,16143,16048,15947,15915,15832,15731,15619,15589,15512,15416,15310,    0},
    {15967,15319,14937,14753,14010,12638,11787,11360,10805, 9706, 8934, 8515, 8166, 7456, 6911, 6575,    0},
    { 4906, 3005, 2985, 2984,  875,  102,   83,   81,   47,   17,   12,   11,    8,    5,    4,    3,    0},
    { 7217, 4346, 4269, 4264, 1924,  428,  340,  332,  280,  203,  179,  175,  171,  164,  159,  157,    0},
    {16010,15415,15032,14805,14228,13043,12168,11634,11265,10419, 9645, 9110, 8892, 8378, 7850, 7437,    0},
    { 8573, 5218, 5046, 5032, 2787,  771,  555,  533,  443,  286,  218,  205,  197,  181,  168,  162,    0},
    {11474, 8095, 7822, 7796, 4632, 1443, 1046, 1004,  748,  351,  218,  194,  167,  121,   93,   83,    0},
    {16152,15764,15463,15264,14925,14189,13536,13070,12846,12314,11763,11277,11131,10777,10383,10011,    0},
    {14187,11654,11043,10919, 8498, 4885, 3778, 3552, 2947, 1835, 1283, 1134,  998,  749,  585,  514,    0},
    {14162,11527,10759,10557, 8601, 5417, 4105, 3753, 3286, 2353, 1708, 1473, 1370, 1148,  959,  840,    0},
    {16205,15902,15669,15498,15213,14601,14068,13674,13463,12970,12471,12061,11916,11564,11183,10841,    0},
    {15043,12972,12092,11792,10265, 7446, 5934, 5379, 4883, 3825, 3036, 2647, 2507, 2185, 1901, 1699,    0},
    {15320,13694,12782,12352,11191, 8936, 7433, 6671, 6255, 5366, 4622, 4158, 4020, 3712, 3420, 3198,    0},
    {16255,16020,15768,15600,15416,14963,14440,14006,13875,13534,13137,12697,12602,12364,12084,11781,    0},
    {15627,14503,13906,13622,12557,10527, 9269, 8661, 8117, 6933, 5994, 5474, 5222, 4664, 4166, 3841,    0},
    {16366,16365,14547,14160,14159,14158,11969,11473, 8735, 6147, 4911, 4530, 3865, 3180, 2710, 2473,    0},
    {16257,16038,15871,15754,15536,15071,14673,14390,14230,13842,13452,13136,13021,12745,12434,12154,    0},
    {15855,14971,14338,13939,13239,11782,10585, 9805, 9444, 8623, 7846, 7254, 7079, 6673, 6262, 5923,    0},
    { 9492, 6318, 6197, 6189, 3004,  652,  489,  477,  333,  143,   96,   90,   78,   60,   50,   47,    0},
    {16313,16191,16063,15968,15851,15590,15303,15082,14968,14704,14427,14177,14095,13899,13674,13457,    0},
    { 8485, 5473, 5389, 5383, 2411,  494,  386,  377,  278,  150,  117,  112,  103,   89,   81,   78,    0},
    {10497, 7154, 6959, 6943, 3788, 1004,  734,  709,  517,  238,  152,  138,  120,   90,   72,   66,    0},
    {16317,16226,16127,16040,15955,15762,15547,15345,15277,15111,14922,14723,14671,14546,14396,14239,    0},
    {16382,16381,15858,15540,15539,15538,14704,14168,13768,13092,12452,11925,11683,11268,10841,10460,    0},
    { 5974, 3798, 3758, 3755, 1275,  205,  166,  162,   95,   35,   26,   24,   18,   11,    8,    7,    0},
    { 3532, 2258, 2246, 2244,  731,  135,  118,  115,   87,   45,   36,   34,   29,   21,   17,   16,    0},
    { 7466, 4882, 4821, 4811, 2476,  886,  788,  771,  688,  531,  469,  457,  437,  400,  369,  361,    0},
    { 9580, 5772, 5291, 5216, 3444, 1496, 1025,  928,  806,  578,  433,  384,  366,  331,  296,  273,    0},
    {10692, 7730, 7543, 7521, 4679, 1746, 1391, 1346, 1128,  692,  495,  458,  424,  353,  291,  268,    0},
    {11040, 7132, 6549, 6452, 4377, 1875, 1253, 1130,  958,  631,  431,  370,  346,  296,  253,  227,    0},
    {12687, 9332, 8701, 8585, 6266, 3093, 2182, 2004, 1683, 1072,  712,  608,  559,  458,  373,  323,    0},
    {13429, 9853, 8860, 8584, 6806, 4039, 2862, 2478, 2239, 1764, 1409, 1224, 1178, 1077,  979,  903,    0},
    {14685,12163,11061,10668, 9101, 6345, 4871, 4263, 3908, 3200, 2668, 2368, 2285, 2106, 1942, 1819,    0},
    {13295,11302,10999,10945, 7947, 5036, 4490, 4385, 3391, 2185, 1836, 1757, 1424,  998,  833,  785,    0},
    { 4992, 2993, 2972, 2970, 1269,  575,  552,  549,  530,  505,  497,  495,  493,  489,  486,  485,    0},
    {15419,13862,13104,12819,11429, 8753, 7220, 6651, 6020, 4667, 3663, 3220, 2995, 2511, 2107, 1871,    0},
    {12468, 9263, 8912, 8873, 5758, 2193, 1625, 1556, 1187,  589,  371,  330,  283,  200,  149,  131,    0},
    {15870,15076,14615,14369,13586,12034,10990,10423, 9953, 8908, 8031, 7488, 7233, 6648, 6101, 5712,    0},
    { 1693,  978,  976,  975,  194,   18,   16,   15,   11,    7,    6,    5,    4,    3,    2,    1,    0},
    { 7992, 5218, 5147, 5143, 2152,  366,  282,  276,  173,   59,   38,   35,   27,   16,   11,   10,    0}
};

//---------------------------------------------------------------------------
static const int16u arith_cf_r[][4]=
{
    {12571, 10569,  3696,     0},
    {12661,  5700,  3751,     0},
    {10827,  6884,  2929,     0}
};

//---------------------------------------------------------------------------
static const int8u freq_res[]=
{
    0, 28, 20, 14, 10,  7,  5,  4
};

//---------------------------------------------------------------------------
static const int8u freq_res_ld[]=
{
    0, 23, 15, 12,  9,  7,  5,  4
};

//---------------------------------------------------------------------------
static const int8u pb_stride[]=
{
    1,  2,  5, 28
};

//---------------------------------------------------------------------------
static const int16s hcodFirstBand_CLD[][2]=
{
    {   2,   1}, {   4,   3}, {   6,   5}, {   8,   7}, {  10,   9}, {  12,  11},
    {  14,  13}, {  -8,  15}, {  -9,  16}, { -10,  17}, { -18,  18}, { -17, -19},
    { -16,  19}, { -11, -20}, { -15, -21}, {  -7,  20}, { -22,  21}, { -12, -14},
    { -13, -23}, {  23,  22}, { -24, -31}, {  -6,  24}, { -25, -26}, {  26,  25},
    { -5,  -27}, { -28,  27}, {  -4,  28}, { -29,  29}, {  -1, -30}, {  -2,  -3}
};

//---------------------------------------------------------------------------
static const int16s hcodFirstBand_ICC[][2]=
{
    {   2,   1}, {  -5,   3}, {  -4,  -6}, {  -3,   4}, {  -2,   5}, {  -1,   6},
    {  -7,  -8}
};

//---------------------------------------------------------------------------
static const int16s hcodFirstBand_IPD[][2]=
{
    {  -1,   1}, {  -8,   2}, {  -2,   3}, {   5,   4}, {  -7,   6}, {  -3,  -5},
    {  -4,  -6}
};

//---------------------------------------------------------------------------
static const int16s hcod1D_CLD_DF[][2]=
{
    {  -1,   1}, {  -2,   2}, {  -3,   3}, {  -4,   4}, {  -5,   5}, {  -6,   6},
    {  -7,   7}, {  -8,   8}, {  -9,   9}, { -10,  10}, { -11,  11}, { -12,  12},
    { -13,  13}, {  15,  14}, { -14,  16}, { -15,  17}, { -16,  18}, { -17,  19},
    { -18,  20}, { -19,  21}, { -20, -21}, { -23,  22}, { -22,  23}, { -24,  24},
    { -25,  25}, {  27,  26}, {  29,  28}, { -30, -31}, { -28, -29}, { -26, -27}
};

//---------------------------------------------------------------------------
static const int16s hcod1D_CLD_DT[][2]=
{
    {  -1,   1}, {  -2,   2}, {  -3,   3}, {  -4,   4}, {  -5,   5}, {  -6,   6},
    {  -7,   7}, {   9,   8}, {  -8,  10}, {  -9,  11}, { -10,  12}, { -11,  13},
    { -12,  14}, { -13,  15}, { -14,  16}, { -15,  17}, { -16,  18}, { -17,  19},
    { -18,  20}, { -19, -20}, { -21,  21}, { -22,  22}, { -23,  23}, {  25,  24},
    { -24,  26}, { -25,  27}, {  29,  28}, { -26, -31}, { -29, -30}, { -27, -28}
};

//---------------------------------------------------------------------------
static const int16s hcod1D_ICC_YY[][2]=
{
    {  -1,   1}, {  -2,   2}, {  -3,   3}, {  -4,   4}, {  -5,   5}, {  -6,   6},
    {  -7,  -8}
};

//---------------------------------------------------------------------------
static const int16s hcod1D_IPD_DF[][2]=
{
    {  -1,   1}, {  -8,   2}, {  -2,   3}, {   5,   4}, {  -3,  -7}, {  -6,   6},
    {  -4,  -5}
};

//---------------------------------------------------------------------------
static const int16s hcod1D_IPD_DT[][2]=
{
    {  -1,   1}, {  -2,   2}, {  -8,   3}, {  -3,   4}, {  -7,   5}, {  -4,   6},
    {  -5,  -6}
};

//---------------------------------------------------------------------------
static const int16s hcodLavIdx[][2]=
{
    {  -1,   1}, {  -2,   2}, {  -3,  -4}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_CLD_DF_FP_03[][2]=
{
    {   2,   1}, {  -1, -52}, {   4,   3}, {  -2,   5}, { -51,   6}, { -17, -18},
    {   8,   7}, {  10,   9}, {  -3, -36}, { -19,  11}, { -35, -50}, { -34,  12},
    {  -4,  13}, { -33,  14}, { -20, -49}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_CLD_DF_FP_05[][2]=
{
    {   2,   1}, {   4,   3}, { -86,   5}, {   7,   6}, {   9,   8}, {  -1,  -2},
    { -85,  10}, { -18,  11}, { -17,  12}, {  14,  13}, { -70,  15}, {  17,  16},
    { -19, -69}, { -84,  18}, {  -3,  19}, {  21,  20}, { -34, -68}, { -20,  22},
    { -35,  23}, { -83,  24}, { -33,  25}, {  -4,  26}, { -53,  27}, { -54, -67},
    { -36,  28}, { -21, -52}, { -82,  29}, {  -5, -50}, { -51,  30}, { -38,  31},
    { -37, -49}, {  -6,  32}, { -66,  33}, { -65,  34}, { -22, -81}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_CLD_DF_FP_07[][2]=
{
    {   2,   1}, {   4,   3}, {-120,   5}, {   7,   6}, {   9,   8}, {  11,  10},
    {  -1,  12}, { -18,-119}, {  -2,  13}, {  15,  14}, { -17,  16}, {-104,  17},
    {  19,  18}, { -19,  20}, {-103,  21}, {-118,  22}, {  24,  23}, {  -3,  25},
    {  27,  26}, { -34,  28}, {-102,  29}, { -20,  30}, { -35,  31}, {  33,  32},
    {-117,  34}, { -33,  35}, { -88,  36}, {  -4,  37}, { -87,  38}, {  40,  39},
    { -36,-101}, { -86,  41}, { -21, -37}, { -85,-100}, { -52,  42}, { -22,  43},
    {-116,  44}, { -50 , 45}, {  47,  46}, {  -5, -51}, {-115,  48}, { -70,  49},
    { -84,  50}, { -38, -49}, { -72, -99}, { -53,  51}, { -69, -71}, { -23,  52},
    {  -6, -67}, {-114,  53}, {  -7,  54}, { -66, -68}, { -55,  55}, {  57,  56},
    { -54, -65}, {  -8, -56}, { -82, -83}, {  59,  58}, { -39, -40}, { -81,  60},
    { -98,  61}, { -97,  62}, { -24,-113}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_CLD_DF_FP_09[][2]=
{
    {   2,   1}, {   4,   3}, {   6,   5}, {-154,   7}, {   9,   8}, {  11,  10},
    {  13,  12}, {  15,  14}, { -18,  16}, {-153,  17}, {  -1,  -2}, {  19,  18},
    {-138,  20}, { -17,  21}, {  23,  22}, {  25,  24}, { -19,-137}, {  27,  26},
    {-152,  28}, {  30,  29}, {  -3, -34}, {  32,  31}, {  34,  33}, {  36,  35},
    {-136,  37}, { -35,  38}, { -20,  39}, {-122,  40}, {-151,  41}, { -33,  42},
    {-121,  43}, {  45,  44}, {  47,  46}, {  -4,  48}, { -36,-120}, {-135,  49},
    {  51,  50}, { -21,  52}, {  54,  53}, {  56,  55}, { -50,-150}, {  58,  57},
    { -51,  59}, {  61,  60}, {-119,  62}, { -52,  63}, {  -5,  64}, { -37,  65},
    {-117,-134}, { -39, -54}, { -22,  66}, {-106,  67}, { -69,-102}, {-132,  68},
    {-105,  69}, { -49,  70}, {-149,  71}, { -24,-104}, {  73,  72}, { -53,  74},
    { -38,-118}, {-103,  75}, {  -6,  76}, { -66, -87}, {-133,-147}, { -23,  77},
    { -67,  78}, { -68, -86}, { -70,-101}, { -40,-148}, {-116,  79}, { -55,  80},
    { -84,-131}, {  82,  81}, { -89, -90}, {  -7, -25}, { -85, -88}, { -65,  83},
    { -72,-146}, {  85,  84}, {  -9, -71}, { -83,  86}, { -82,  87}, {  -8,  88},
    {-100,  89}, { -74, -99}, { -73,  90}, { -10, -81}, { -56,  91}, { -57, -98},
    {  93,  92}, { -58,-114}, { -97,-115}, {  95,  94}, { -41,  96}, { -42,  97},
    { -26,-129}, {-113,  98}, {-130,-145}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_CLD_DT_FP_03[][2]=
{
    {  -1,   1}, { -52,   2}, { -17,   3}, {   5,   4}, {  -2, -36}, { -18,   6},
    {   8,   7}, { -51,   9}, { -33,  10}, { -34,  11}, { -20, -35}, { -19,  12},
    {  -3,  13}, { -49,  14},
    {  -4, -50}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_CLD_DT_FP_05[][2]=
{
    {2   ,   1}, { -86,   3}, {  -1,   4}, { -17,   5}, {   7,   6}, { -70,   8},
    {  -2, -18}, {  10,   9}, {  12,  11}, { -85,  13}, { -33,  14}, { -34, -54},
    {  16,  15}, { -69,  17}, {  19,  18}, { -50, -53}, { -19,  20}, { -38,  21},
    { -35, -49}, {  -3,  22}, {  24,  23}, { -68,  25}, { -84,  26}, { -65,  27},
    { -51, -66}, { -22, -37}, { -52,  28}, { -20,  29}, { -36,  30}, { -81,  31},
    {  -4, -83}, { -67,  32}, { -21,  33}, {  -5,  34}, {  -6, -82}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_CLD_DT_FP_07[][2]=
{
    {   2,   1}, {-120,   3}, {  -1,   4}, {   6,   5}, { -17,   7}, {-104,   8},
    { -18,   9}, {  -2,  10}, {  12,  11}, {  14,  13}, {-119,  15}, { -33,  16},
    { -34, -88}, {-103,  17}, {  19,  18}, {  21,  20}, {  23,  22}, {  25,  24},
    { -19, -72}, { -50,  26}, { -49,  27}, { -87,  28}, {  30,  29}, {  32,  31},
    {  -3, -35}, {  34,  33}, { -56,  35}, { -65, -66}, { -40,  36}, { -82,-118},
    { -71,  37}, { -55,  38}, { -67,-102}, { -51,  39}, { -70,  40}, {  42,  41},
    { -81,  43}, { -86,  44}, { -52, -97}, { -98,  45}, { -24, -39}, { -20,  46},
    { -54, -83}, { -36,  47}, { -85,  48}, { -68,  49}, {  -4,  50}, { -69,-113},
    {-117,  51}, { -37,-101}, { -53,  52}, { -21,  53}, {  55,  54}, { -84,-100},
    {  -5,  56}, {-116,  57}, { -22,  58}, { -38,-115}, {  60,  59}, {  -6, -99},
    { -23,  61}, {-114,  62}, {  -7,  -8}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_CLD_DT_FP_09[][2]=
{
    {   2,   1}, {-154,   3}, {   5,   4}, {  -1,   6}, {   8,   7}, { -17,   9},
    {-138,  10}, { -18,  11}, {  -2,  12}, {  14,  13}, {  16,  15}, {-153,  17},
    { -34,  18}, { -33,-122}, {  20,  19}, {  22,  21}, {-137,  23}, {  25,  24},
    {  27,  26}, {-106,  28}, {  30,  29}, { -50,  31}, { -19,  32}, { -49,-121},
    {  34,  33}, {  36,  35}, { -35,  37}, { -90,  38}, { -66,  39}, {  -3,  40},
    {  42,  41}, { -65,  43}, {-105,  44}, {  46,  45}, { -74,  47}, { -51,  48},
    { -82,-152}, {-136,  49}, { -81,  50}, { -42, -89}, {-114,  51}, {  53,  52},
    { -57, -58}, {-120,  54}, { -98,  55}, { -67,  56}, { -97,  57}, {  59,  58},
    { -99,  60}, { -73,-104}, { -72,  61}, {-113,  62}, { -20, -83}, { -84,-130},
    { -36,  63}, { -26,  64}, { -41,  65}, { -52,-129}, { -87, -88}, {  67,  66},
    {-115,  68}, { -68,  69}, { -56, -69}, {  -4,-100}, {-151,  70}, {-135,  71},
    {-103,-119}, {  73,  72}, { -71,-145}, {-102,  74}, {  76,  75}, { -53, -85},
    { -37,  77}, { -21, -86}, {  79,  78}, {  -5,  80}, { -54,-134}, {-150,  81},
    {-118,  82}, { -70,  83}, {-117,  84}, { -22, -38}, {-101,  85}, { -55,  86},
    {-149,  87}, { -39,  88}, {-133,  89}, {  -6,  90}, {-116,  91}, { -24,  92},
    {  -7,-132}, { -23,  93}, { -40,  94}, {-131,-148}, { -25,  95}, {-147,  96},
    {-146,  97}, {  -8,   0}, {   0,   0}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_CLD_DF_TP_03[][2]=
{
    {  -1,   1}, { -52,   2}, { -17,   3}, {   5,   4}, { -36,   6}, { -33,   7},
    {  -2, -18}, { -20,   8}, {  10,   9}, { -34, -49}, { -51,  11}, { -35,  12},
    { -19,  13}, {  -3,  14}, {  -4, -50}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_CLD_DF_TP_05[][2]=
{
    {   2,   1}, {   4,   3}, { -86,   5}, {  -1,   6}, { -17,   7}, { -70,   8},
    {  10,   9}, { -18,  11}, { -33,  12}, { -54,  13}, {  -2,  14}, { -34,  15},
    { -38,  16}, { -49,  17}, { -85,  18}, { -50,  19}, { -69,  20}, { -53, -65},
    { -22,  21}, { -66,  22}, { -19,  23}, { -37,  24}, { -35, -81}, {  -3,  25},
    { -51,  26}, { -68, -84}, { -52,  27}, {  29,  28}, { -20,  30}, {  -4, -36},
    { -83,  31}, { -67,  32}, { -21,  33}, {  -5,  34}, {  -6, -82}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_CLD_DF_TP_07[][2]=
{
    {   2,   1}, {   4,   3}, {   6,   5}, {-120,   7}, { -17,   8}, {  -1,-104},
    {  10,   9}, {  12,  11}, { -18,  13}, { -33, -88}, {  15,  14}, {  17,  16},
    {  -2,  18}, { -34,  19}, { -72,  20}, { -49,  21}, {-119,  22}, { -50,  23},
    {-103,  24}, { -56,  25}, { -65,  26}, {  28,  27}, { -40, -87}, { -66,  29},
    { -82,  30}, {  32,  31}, { -19, -81}, { -71,  33}, { -97,  34}, { -35, -55},
    { -24,  35}, {  37,  36}, {  -3, -98}, { -51,  38}, { -67,  39}, { -39,-118},
    {-113,  40}, {-102,  41}, { -86,  42}, { -70, -83}, {  44,  43}, { -20, -54},
    { -52,  45}, { -36,  46}, {  -4,  47}, { -68,  48}, { -85,  49}, {-101,-117},
    { -69,  50}, {  52,  51}, { -21, -37}, { -53,  53}, {  55,  54}, {  -5,-100},
    {-116,  56}, { -84,  57}, { -38,  58}, { -22, -99}, {-115,  59}, {  -6,  60},
    { -23,  61}, {  -7,  62}, {-114,   0}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_CLD_DF_TP_09[][2]=
{
    {   2,   1}, {   4,   3}, {   6,   5}, {-154,   7}, {   9,   8}, { -17,  10},
    {-138,  11}, {  -1,  12}, {  14,  13}, {  16,  15}, { -33,-122}, { -18,  17},
    {  19,  18}, { -34,  20}, {  -2,  21}, {-106,  22}, { -49,  23}, {  25,  24},
    { -50,  26}, {-153,  27}, { -90,  28}, {-137,  29}, { -65,  30}, {  32,  31},
    { -66,  33}, {-121,  34}, { -74,  35}, { -81,  36}, {  38,  37}, { -42,  39},
    { -82,  40}, {-105,  41}, { -19,-114}, { -58,  42}, { -35,  43}, { -97,  44},
    {  46,  45}, {-129,  47}, { -26, -89}, { -57, -98}, { -51,  48}, {  -3,  49},
    {-113,  50}, {-130,  51}, {-152,  52}, { -67, -73}, { -99,-136}, {-145,  53},
    {-120,  54}, { -41,  55}, { -83,  56}, { -72,  57}, {-104,  58}, {-115,  59},
    { -20,  60}, {  62,  61}, { -36, -88}, { -84,  63}, { -52, -56}, {  65,  64},
    {  -4, -87}, { -68,  66}, {-151,  67}, {-100,-135}, {  69,  68}, { -69,-119},
    {-103,  70}, { -71,  71}, {  73,  72}, { -21,  74}, { -85,  75}, { -37, -53},
    { -86,  76}, {  78,  77}, {-102,-150}, {  -5,  79}, {-134,  80}, {-118,  81},
    { -54,-117}, {  83,  82}, { -38, -70}, { -22,  84}, {  -6,  85}, {  87,  86},
    { -55,  88}, {-101,  89}, {-133,-149}, { -24, -39}, {  91,  90}, {-132,  92},
    { -23,  93}, {  -7,  94}, {-147,-148}, {-116,-131}, { -25,  95}, { -40,   0},
    {   0,   0}, {   0,   0}, {   0,   0}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_CLD_DT_TP_03[][2]=
{
    {  -1,   1}, { -52,   2}, {   4,   3}, {  -2,   5}, { -17,   6}, { -18,   7},
    { -36, -51}, {   9,   8}, { -35,  10}, { -34,  11}, { -19, -33}, {  -3,  12},
    { -20,  13}, { -50,  14}, {  -4, -49}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_CLD_DT_TP_05[][2]=
{
    {   2,   1}, { -86,   3}, {   5,   4}, {  -1,   6}, {   8,   7}, { -17, -18},
    {  -2,   9}, { -70,  10}, { -85,  11}, {  13,  12}, { -69,  14}, { -34,  15},
    {  17,  16}, { -19,  18}, { -33, -35}, { -54,  19}, { -53,  20}, {  -3,  21},
    { -68,  22}, { -84,  23}, { -50,  24}, { -52,  25}, { -51,  26}, { -20, -36},
    { -49,  27}, { -38,  28}, { -37,  29}, {  -4, -83}, { -67,  30}, { -66,  31},
    { -21,  32}, { -22, -65}, {  -5,  33}, { -82,  34}, {  -6, -81}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_CLD_DT_TP_07[][2]=
{
    {   2,   1}, {   4,   3}, {-120,   5}, {   7,   6}, {   9,   8}, {  -1,  10},
    { -18,  11}, { -17,  12}, {  -2,-104}, {-119,  13}, {  15,  14}, {-103,  16},
    {  18,  17}, { -34,  19}, { -19,  20}, {  22,  21}, { -35,  23}, { -33,  24},
    { -88,  25}, { -87,  26}, {  28,  27}, {  -3,-102}, { -86,  29}, { -52,-118},
    {  31,  30}, { -50,  32}, { -51,  33}, { -70,  34}, { -36,  35}, { -85,  36},
    { -20,  37}, {  39,  38}, { -69, -71}, { -72,  40}, { -49, -67}, {  42,  41},
    { -68,  43}, {  -4,-101}, { -53,-117}, { -37,  44}, { -66,  45}, { -55,  46},
    {  48,  47}, { -54,  49}, { -21,  50}, { -84,-100}, { -56, -65}, {  52,  51},
    { -82, -83}, {  54,  53}, {  -5,-116}, { -22,  55}, { -38,  56}, { -39, -40},
    {  58,  57}, { -81,-115}, { -98, -99}, {  -6,  59}, { -23,  60}, { -24,  61},
    {  -7, -97}, {-114,  62}, {  -8,-113}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_CLD_DT_TP_09[][2]=
{
    {   2,   1}, {   4,   3}, {-154,   5}, {   7,   6}, {   9,   8}, {  11,  10},
    {  -1,  12}, { -18,  13}, { -17,  14}, {  -2,-138}, {  16,  15}, {-153,  17},
    {-137,  18}, {  20,  19}, {  22,  21}, { -34,  23}, { -19,  24}, { -35,  25},
    {  27,  26}, {  29,  28}, {-121,  30}, {-120,  31}, {-136,  32}, { -33,-122},
    {  34,  33}, {-152,  35}, {  -3,  36}, { -51,  37}, { -52,  38}, { -69,  39},
    { -36,  40}, { -50,  41}, {  43,  42}, { -20,  44}, {-104,  45}, {-103,  46},
    { -87,  47}, {-119,  48}, {-105,  49}, { -86,  50}, {-102,  51}, {-106,  52},
    { -49,-135}, { -68,  53}, {  55,  54}, { -53,  56}, { -67,-151}, {  -4,  57},
    { -84,  58}, { -85,  59}, { -66,  60}, { -37,  61}, { -70,  62}, { -54, -88},
    { -21,  63}, {  65,  64}, { -89,  66}, {-118,  67}, { -72,  68}, { -90,  69},
    { -71,  70}, { -65,-134}, {-150,  71}, { -83,  72}, {  -5,  73}, {-101,-117},
    { -82,  74}, {  76,  75}, { -99,  77}, { -38,  78}, {-100,  79}, { -22,  80},
    { -73,  81}, { -39, -74}, {  83,  82}, { -55, -81}, { -57,  84}, {-133,-149},
    { -56,  85}, {  -6,  86}, { -98,  87}, {-132,  88}, { -23,  89}, {-114,  90},
    {-116,  91}, { -58,-115}, { -24,  92}, { -97,-148}, { -40, -41}, {  -7, -42},
    {-147,  93}, {  95,  94}, {-131,  96}, {  -8,-130}, { -25,-113}, {  -9,  97},
    { -26,-129}, {-146,  98}, { -10,-145}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_ICC_DF_FP_01[][2]=
{
    {  -1,   1}, { -18,   2}, {  -2, -17}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_ICC_DF_FP_03[][2]=
{
    {   2,   1}, {  -1, -52}, {  -2,   3}, {   5,   4}, { -51,   6}, { -18,   7},
    { -17,   8}, {  -3,   9}, { -36,  10}, { -19, -50}, { -35,  11}, {  -4,  12},
    { -34,  13}, { -33,  14}, { -20, -49}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_ICC_DF_FP_05[][2]=
{
    {   2,   1}, { -86,   3}, {  -1,   4}, {   6,   5}, {  -2,   7}, { -85,   8},
    { -18,   9}, {  11,  10}, { -17,  12}, {  14,  13}, { -70,  15}, {  -3, -19},
    { -69,  16}, { -84,  17}, { -68,  18}, { -20, -35}, { -34, -83}, {  20,  19},
    {  -4,  21}, { -33,  22}, {  -5,  23}, { -53,  24}, { -36, -52}, { -67,  25},
    { -21, -82}, { -54,  26}, {  -6,  27}, { -51,  28}, { -50,  29}, { -49,  30},
    { -37,  31}, { -38,   0}, {   0,   0}, {   0,   0}, {   0,   0}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_ICC_DF_FP_07[][2]=
{
    {   2,   1}, {   4,   3}, {  -1,-120}, {   6,   5}, {   8,   7}, { -18,   9},
    {  -2,  10}, {  12,  11}, {  14,  13}, { -17,-119}, {  16,  15}, {-103,  17},
    {-104,  18}, { -52,  19}, {  21,  20}, { -69,  22}, {  24,  23}, {  -3, -35},
    { -19,  25}, { -34, -85}, {  27,  26}, { -86,  28}, {-118,  29}, { -37,  30},
    {  32,  31}, {-102,  33}, { -20, -22}, {  -4,-117}, { -87,  34}, {-100,  35},
    { -33, -36}, {  37,  36}, { -70, -88}, {-101,  38}, {  -5,  39}, { -51, -53},
    { -50,  40}, {-115,  41}, { -21,  42}, {-116,  43}, { -38,  44}, { -23, -84},
    { -49, -99}, {  46,  45}, {  -6,-114}, {  -7, -72}, { -71,  47}, {  -8,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_ICC_DT_FP_01[][2]=
{
    {  -1,   1}, { -18,   2}, {  -2, -17}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_ICC_DT_FP_03[][2]=
{
    { -52,   1}, {  -1,   2}, {   4,   3}, {  -2, -17}, { -18,   5}, { -36,   6},
    { -51,   7}, {   9,   8}, { -33,  10}, { -34,  11}, { -35,  12}, { -19, -20},
    {  -3,  13}, { -49,  14}, {  -4, -50}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_ICC_DT_FP_05[][2]=
{
    {  -1,   1}, { -86,   2}, {   4,   3}, { -17,   5}, {  -2,   6}, { -18,   7},
    { -70,   8}, { -85,   9}, {  11,  10}, {  13,  12}, { -33,  14}, {  16,  15},
    { -34, -54}, { -69,  17}, { -38,  18}, { -50,  19}, { -35, -53}, { -49,  20},
    { -19,  21}, {  -3,  22}, { -65,  23}, { -68,  24}, { -22,  25}, { -81, -84},
    { -66,  26}, { -37,  27}, { -20, -51}, {  29,  28}, { -52,  30}, {  -4, -83},
    { -36,  31}, { -67,  32}, {  -5,  33}, { -82,  34}, { -21,   0}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_ICC_DT_FP_07[][2]=
{
    {  -1,   1}, {-120,   2}, {   4,   3}, { -17,   5}, {  -2,   6}, {   8,   7},
    { -18,   9}, {-104,  10}, {  12,  11}, {  14,  13}, {  16,  15}, {-119,  17},
    { -81,  18}, {  20,  19}, { -33,  21}, { -88,  22}, {-103,  23}, { -34,  24},
    { -56,  25}, { -72,  26}, { -49,  27}, { -82,  28}, { -50,  29}, { -65,  30},
    { -55, -87}, { -19,  31}, { -67,  32}, { -35, -40}, {  34,  33}, { -52, -71},
    { -66,  35}, { -70,  36}, {  38,  37}, { -51, -97}, { -86,-102}, {  -3,  39},
    {-118,  40}, {  42,  41}, { -24, -85}, { -54,  43}, { -39,  44}, { -98,-113},
    { -36, -37}, { -20, -69}, {  -4,  45}, {  -5,  46}, { -21,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_ICC_DF_TP_01[][2]=
{
    {  -1,   1}, { -18,   2}, {  -2, -17}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_ICC_DF_TP_03[][2]=
{
    {   2,   1}, {  -1, -52}, { -17,   3}, {   5,   4}, { -36,   6}, {  -2,   7},
    { -18, -33}, {   9,   8}, { -20,  10}, { -34, -51}, { -49,  11}, { -35,  12},
    { -19,  13}, {  -3,  14}, {  -4, -50}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_ICC_DF_TP_05[][2]=
{
    {   2,   1}, { -86,   3}, {  -1,   4}, { -17,   5}, {   7,   6}, { -70,   8},
    { -33,   9}, { -18,  10}, {  -2,  11}, { -54,  12}, { -49,  13}, { -38,  14},
    { -34, -65}, { -85,  15}, { -50,  16}, { -69,  17}, { -22,  18}, { -53,  19},
    {  21,  20}, { -19, -81}, { -66,  22}, {  -3, -35}, {  24,  23}, { -37,  25},
    { -68, -84}, { -51,  26}, {  28,  27}, { -20, -52}, {  30,  29}, {  -4, -36},
    { -83,  31}, { -67,  32}, { -82,  33}, { -21,  34}, {  -5,  -6}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_ICC_DF_TP_07[][2]=
{
    {   2,   1}, {   4,   3}, {  -1,-120}, {   6,   5}, {   8,   7}, { -18,   9},
    {  -2,  10}, {  12,  11}, {  14,  13}, { -17,-119}, {  16,  15}, {-103,  17},
    {-104,  18}, { -52,  19}, {  21,  20}, { -69,  22}, {  24,  23}, {  -3, -35},
    { -19,  25}, { -34, -85}, {  27,  26}, { -86,  28}, {-118,  29}, { -37,  30},
    {  32,  31}, {-102,  33}, { -20, -22}, {  -4,-117}, { -87,  34}, {-100,  35},
    { -33, -36}, {  37,  36}, { -70, -88}, {-101,  38}, {  -5,  39}, { -51, -53},
    { -50,  40}, {-115,  41}, { -21,  42}, {-116,  43}, { -38,  44}, { -23, -84},
    { -49, -99}, {  46,  45}, {  -6,-114}, {  -7, -72}, { -71,  47}, {  -8,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_ICC_DT_TP_01[][2]=
{
    {  -1,   1}, { -18,   2}, {  -2, -17}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_ICC_DT_TP_03[][2]=
{
    { -52,   1}, {  -1,   2}, {   4,   3}, {  -2,   5}, { -17, -18}, { -51,   6},
    { -36,   7}, {   9,   8}, { -35,  10}, {  -3,  11}, { -19, -34}, { -33,  12},
    { -50,  13}, { -20,  14}, {  -4, -49}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_ICC_DT_TP_05[][2]=
{
    {   2,   1}, { -86,   3}, {  -1,   4}, {   6,   5}, { -18,   7}, {  -2, -17},
    {   9,   8}, { -70,  10}, { -69, -85}, { -35,  11}, {  13,  12}, { -34,  14},
    { -19,  15}, { -53,  16}, { -68,  17}, { -33,  18}, {  -3, -52}, {  20,  19},
    { -54,  21}, { -84,  22}, { -50,  23}, { -20, -51}, { -36,  24}, {  26,  25},
    { -83,  27}, {  -4, -38}, { -49,  28}, { -37,  29}, { -67,  30}, {  -5,  31},
    { -21,  32}, { -65, -66}, { -82,  33}, { -22,  34}, {  -6, -81}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_ICC_DT_TP_07[][2]=
{
    {   2,   1}, {  -1,-120}, {   4,   3}, {   6,   5}, { -18,   7}, {   9,   8},
    { -17,  10}, {  -2,  11}, {-103,  12}, { -52,  13}, { -35,-104}, {-119,  14},
    {  16,  15}, { -69, -86}, {  18,  17}, { -34,  19}, { -19,  20}, {  22,  21},
    { -70,  23}, { -87,  24}, {-102,  25}, { -85,  26}, { -33,  27}, { -36,  28},
    {  -3,  29}, { -88,  30}, { -51,  31}, {-118,  32}, {  34,  33}, { -68,  35},
    { -53,  36}, { -67,  37}, { -20,  38}, {-101,  39}, { -50,  40}, {  42,  41},
    { -37,  43}, {-116,  44}, {-117,  45}, { -49,  46}, { -21,-100}, {  48,  47},
    { -55, -71}, {  -4,  49}, { -22, -84}, {-115,  50}, { -66, -82}, { -72,  51},
    {  -5,  -6}, { -54,  52}, { -38,  53}, { -83,  54}, { -40,  55}, { -39,  56},
    { -99,  57}, { -23, -56}, {  -7,  58}, { -65, -97}, {  -8,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_IPD_DF_FP_07[][2]=
{
    {   2,   1}, {   4,   3}, {  -1,   5}, { -69,   6}, {-120,   7}, { -68,   8},
    {  10,   9}, {  12,  11}, {  14,  13}, { -52, -54}, { -18,  15}, { -70,  16},
    { -67,  17}, {  19,  18}, { -17,  20}, {-113,  21}, {  23,  22}, { -83,  24},
    { -24,  25}, {-103,-104}, { -51, -55}, {  27,  26}, { -71,  28}, { -86,  29},
    { -35,  30}, { -66,  31}, { -39, -50}, { -82, -98}, { -72,  32}, { -56, -87},
    { -34,  33}, { -33, -88}, { -40, -97}, { -65,  34}, { -49,  35}, { -81,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_IPD_DF_FP_01[][2]=
{
    {  -1,   1}, { -18,   2}, { -17,   0}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_IPD_DF_FP_03[][2]=
{
    {  -1,   1}, { -36,   2}, { -18,   3}, { -35,   4}, { -52,   5}, {   7,   6},
    { -34,   8}, { -33, -49}, { -20,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_IPD_DF_FP_05[][2]=
{
    {  -1,   1}, {   3,   2}, {   5,   4}, { -86,   6}, { -66,   7}, {   9,   8},
    {  11,  10}, { -18,  12}, { -51,  13}, { -37, -52}, { -69,  14}, { -38,  15},
    { -53,  16}, { -35,  17}, { -50, -70}, { -22, -49}, { -33,  18}, { -17,  19},
    { -34, -65}, { -81,  20}, { -54,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_IPD_DT_FP_07[][2]=
{
    {  -1,   1}, { -69,   2}, {   4,   3}, {-120,   5}, {   7,   6}, {-113,   8},
    { -68,   9}, {  11,  10}, { -17,  12}, { -52,  13}, { -24,  14}, { -18,  15},
    {  17,  16}, {-104,  18}, {  20,  19}, { -54, -70}, {  22,  21}, {  24,  23},
    { -86, -97}, {-103,  25}, { -83,  26}, { -35,  27}, { -34, -98}, { -40,  28},
    { -39, -67}, {  30,  29}, { -33, -51}, { -87,  31}, { -88,  32}, { -82,  33},
    { -55, -81}, { -56, -71}, { -72,  34}, { -50, -66}, { -65,  35}, { -49,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_IPD_DT_FP_01[][2]=
{
    {  -1,   1}, { -18,   2}, { -17,   0}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_IPD_DT_FP_03[][2]=
{
    {  -1,   1}, {   3,   2}, { -18,   4}, { -52,   5}, { -34, -36}, { -35,   6},
    { -17,   7}, { -33,   8}, { -20,   9}, { -49,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_IPD_DT_FP_05[][2]=
{
    {  -1,   1}, {   3,   2}, { -52,   4}, { -86,   5}, { -35,   6}, { -53,   7},
    { -70,   8}, { -17,   9}, { -37,  10}, {  12,  11}, { -38, -66}, { -18,  13},
    { -51,  14}, {  16,  15}, { -34, -69}, {  18,  17}, { -54, -65}, { -50,  19},
    { -33, -49}, { -22,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_IPD_DF_TP_07[][2]=
{
    {   2,   1}, {   4,   3}, {  -1,   5}, { -69,   6}, {-120,   7}, { -68,   8},
    {  10,   9}, {  12,  11}, {  14,  13}, { -52, -54}, { -18,  15}, { -70,  16},
    { -67,  17}, {  19,  18}, { -17,  20}, {-113,  21}, {  23,  22}, { -83,  24},
    { -24,  25}, {-103,-104}, { -51, -55}, {  27,  26}, { -71,  28}, { -86,  29},
    { -35,  30}, { -66,  31}, { -39, -50}, { -82, -98}, { -72,  32}, { -56, -87},
    { -34,  33}, { -33, -88}, { -40, -97}, { -65,  34}, { -49,  35}, { -81,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_IPD_DF_TP_01[][2]=
{
    {  -1,   1}, { -18,   2}, { -17,   0}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_IPD_DF_TP_03[][2]=
{
    {  -1,   1}, { -36,   2}, { -18,   3}, { -35,   4}, { -52,   5}, {   7,   6},
    { -34,   8}, { -33, -49}, { -20,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_IPD_DF_TP_05[][2]=
{
    {  -1,   1}, {   3,   2}, {   5,   4}, { -86,   6}, { -66,   7}, {   9,   8},
    {  11,  10}, { -18,  12}, { -51,  13}, { -37, -52}, { -69,  14}, { -38,  15},
    { -53,  16}, { -35,  17}, { -50, -70}, { -22, -49}, { -33,  18}, { -17,  19},
    { -34, -65}, { -81,  20}, { -54,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_IPD_DT_TP_07[][2]=
{
    {  -1,   1}, { -69,   2}, {   4,   3}, {-120,   5}, {   7,   6}, {-113,   8},
    { -68,   9}, {  11,  10}, { -17,  12}, { -52,  13}, { -24,  14}, { -18,  15},
    {  17,  16}, {-104,  18}, {  20,  19}, { -54, -70}, {  22,  21}, {  24,  23},
    { -86, -97}, {-103,  25}, { -83,  26}, { -35,  27}, { -34, -98}, { -40,  28},
    { -39, -67}, {  30,  29}, { -33, -51}, { -87,  31}, { -88,  32}, { -82,  33},
    { -55, -81}, { -56, -71}, { -72,  34}, { -50, -66}, { -65,  35}, { -49,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_IPD_DT_TP_01[][2]=
{
    {  -1,   1}, { -18,   2}, { -17,   0}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_IPD_DT_TP_03[][2]=
{
    {  -1,   1}, {   3,   2}, { -18,   4}, { -52,   5}, { -34, -36}, { -35,   6},
    { -17,   7}, { -33,   8}, { -20,   9}, { -49,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}
};

//---------------------------------------------------------------------------
static const int16s hcod2D_IPD_DT_TP_05[][2]=
{
    {  -1,   1}, {   3,   2}, { -52,   4}, { -86,   5}, { -35,   6}, { -53,   7},
    { -70,   8}, { -17,   9}, { -37,  10}, {  12,  11}, { -38, -66}, { -18,  13},
    { -51,  14}, {  16,  15}, { -34, -69}, {  18,  17}, { -54, -65}, { -50,  19},
    { -33, -49}, { -22,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0},
    {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}, {   0,   0}
};

//---------------------------------------------------------------------------
static const int16s hcod2DReshape[][2]=
{
    {   2,   1}, {   4,   3}, {   6,   5}, { -33,   7}, { -17,   8}, { -49,   9},
    { -34,  10}, {  12,  11}, { -18, -35}, { -50,  13}, {  15,  14}, { -40,  16},
    { -36,  17}, { -19,  18}, {  -1, -37}, { -51,  19}, {  21,  20}, { -38, -65},
    {  -2, -39}, { -20,  22}, { -52,  23}, {  25,  24}, { -21,  26}, { -66,  27},
    { -53,  28}, {  -3,  29}, {  31,  30}, { -22,  32}, { -54,  33}, {  -4,  34},
    { -56,  35}, { -24, -67}, { -23, -55}, {  -8, -72}, {  -5,  36}, { -68,  37},
    {  -6,  38}, {  -7, -69}, { -70, -71}
};


//---------------------------------------------------------------------------
static const int8u lavTabXXX[][4]=
{
    {3, 5, 7, 9},
    {1, 3, 5, 7},
    {7, 1, 3, 5}
};

//---------------------------------------------------------------------------
static const int8u nBitsTsdCWTab32[]=
{
     5,  9, 13, 16, 18, 20, 22, 24, 25, 26, 27, 28, 29, 29, 30, 30,
    30, 29, 29, 28, 27, 26, 25, 24, 22, 20, 18, 16, 13,  9,  5,  0
};

static const int8u  nBitsTsdCWTab64[]=
{
     6, 11, 16, 20, 23, 27, 30, 33, 35, 38, 40, 42, 44, 46, 48, 49,
    51, 52, 53, 55, 56, 57, 58, 58, 59, 60, 60, 60, 61, 61, 61, 61,
    61, 61, 61, 60, 60, 60, 59, 58, 58, 57, 56, 55, 53, 52, 51, 49,
    48, 46, 44, 42, 40, 38, 35, 33, 30, 27, 23, 20, 16, 11,  6,  0
};

//***************************************************************************
// Info
//***************************************************************************

//---------------------------------------------------------------------------
#if MEDIAINFO_CONFORMANCE
const char* ConformanceLevel_Strings[]=
{
    "Errors",
    "Warnings",
    "Infos",
};
static_assert(sizeof(ConformanceLevel_Strings)/sizeof(const char*)==File_Usac::ConformanceLevel_Max, "");
#endif

//---------------------------------------------------------------------------
extern int8u Aac_AudioSpecificConfig_sampling_frequency_index(const int64s sampling_frequency, bool usac=false);
extern const int32u Aac_sampling_frequency[];
extern const int8u Aac_Channels[];
extern string Aac_Channels_GetString(int8u ChannelLayout);
extern string Aac_ChannelConfiguration_GetString(int8u ChannelLayout);
extern string Aac_ChannelConfiguration2_GetString(int8u ChannelLayout);
extern string Aac_ChannelLayout_GetString(int8u ChannelLayout, bool IsMpegh3da=false, bool IsTip=false);
extern string Aac_OutputChannelPosition_GetString(int8u OutputChannelPosition);
extern bool Aac_Sbr_Compute(sbr_handler *sbr, int64s sampling_frequency, bool usac);
extern string Mpeg4_Descriptors_AudioProfileLevelString(const profilelevel_struct& ProfileLevel);

//---------------------------------------------------------------------------
enum usacElementType_Value
{
    ID_USAC_SCE,
    ID_USAC_CPE,
    ID_USAC_LFE,
    ID_USAC_EXT,
    ID_USAC_Max
};
static const char* usacElementType_IdNames[]=
{
    "SCE",
    "CPE",
    "LFE",
    "EXT",
};
static_assert(sizeof(usacElementType_IdNames)/sizeof(const char*)==ID_USAC_Max, "");

//---------------------------------------------------------------------------
enum usacExtElementType_Value
{
    ID_EXT_ELE_FILL,
    ID_EXT_ELE_MPEGS,
    ID_EXT_ELE_SAOC,
    ID_EXT_ELE_AUDIOPREROLL,
    ID_EXT_ELE_UNI_DRC,
    ID_EXT_ELE_Max
};
const char* usacExtElementType_IdNames[]=
{
    "ID_EXT_ELE_FILL",
    "ID_EXT_ELE_MPEGS",
    "ID_EXT_ELE_SAOC",
    "ID_EXT_ELE_AUDIOPREROLL",
    "ID_EXT_ELE_UNI_DRC",
};
static_assert(sizeof(usacExtElementType_IdNames)/sizeof(const char*)==ID_EXT_ELE_Max, "");
const char* usacExtElementType_Names[] =
{
    "Fill",
    "SpatialFrame",
    "SaocFrame",
    "AudioPreRoll",
    "uniDrcGain",
};
static_assert(sizeof(usacExtElementType_Names)/sizeof(const char*)==ID_EXT_ELE_Max, "");
const char* usacExtElementType_ConfigNames[] =
{
    nullptr,
    "SpatialSpecificConfig",
    "SaocSpecificConfig",
    nullptr,
    "uniDrcConfig",
};
static_assert(sizeof(usacExtElementType_ConfigNames)/sizeof(const char*)==ID_EXT_ELE_Max, "");

//---------------------------------------------------------------------------
enum loudnessInfoSetExtType_Value
{
    UNIDRCLOUDEXT_TERM,
    UNIDRCLOUDEXT_EQ,
    UNIDRCLOUDEXT_Max
};
static const char* loudnessInfoSetExtType_IdNames[]=
{
    "UNIDRCLOUDEXT_TERM",
    "UNIDRCLOUDEXT_EQ",
};
static_assert(sizeof(loudnessInfoSetExtType_IdNames)/sizeof(const char*)==UNIDRCLOUDEXT_Max, "");
static const char* loudnessInfoSetExtType_ConfNames[]=
{
    "",
    "V1loudnessInfo",
};
static_assert(sizeof(loudnessInfoSetExtType_ConfNames)/sizeof(const char*)==UNIDRCLOUDEXT_Max, "");

//---------------------------------------------------------------------------
enum uniDrcConfigExtType_Value
{
    UNIDRCCONFEXT_TERM,
    UNIDRCCONFEXT_PARAM_DRC,
    UNIDRCCONFEXT_V1,
    UNIDRCCONFEXT_Max
};
static const char* uniDrcConfigExtType_IdNames[]=
{
    "UNIDRCCONFEXT_TERM",
    "UNIDRCCONFEXT_PARAM_DRC",
    "UNIDRCCONFEXT_V1",
};
static_assert(sizeof(uniDrcConfigExtType_IdNames)/sizeof(const char*)==UNIDRCCONFEXT_Max, "");
static const char* uniDrcConfigExtType_ConfNames[]=
{
    "",
    "ParametricDrc",
    "V1Drc",
};
static_assert(sizeof(uniDrcConfigExtType_ConfNames)/sizeof(const char*)==UNIDRCCONFEXT_Max, "");

//---------------------------------------------------------------------------
enum usacConfigExtType_Value
{
    ID_CONFIG_EXT_FILL,
    ID_CONFIG_EXT_1,
    ID_CONFIG_EXT_LOUDNESS_INFO,
    ID_CONFIG_EXT_3,
    ID_CONFIG_EXT_4,
    ID_CONFIG_EXT_5,
    ID_CONFIG_EXT_6,
    ID_CONFIG_EXT_STREAM_ID,
    ID_CONFIG_EXT_Max
};
static const char* usacConfigExtType_IdNames[]=
{
    "ID_CONFIG_EXT_FILL",
    "",
    "ID_CONFIG_EXT_LOUDNESS_INFO",
    "",
    "",
    "",
    "",
    "ID_CONFIG_EXT_STREAM_ID",
};
static_assert(sizeof(usacConfigExtType_IdNames)/sizeof(const char*)==ID_CONFIG_EXT_Max, "");
static const char* usacConfigExtType_ConfNames[]=
{
    "ConfigExtFill",
    "",
    "loudnessInfoSet",
    "",
    "",
    "",
    "",
    "streamId",
};
static_assert(sizeof(usacConfigExtType_ConfNames)/sizeof(const char*)==ID_CONFIG_EXT_Max, "");

//---------------------------------------------------------------------------
struct coreSbrFrameLengthIndex_mapping
{
    int8u    sbrRatioIndex;
    int16u   coreCoderFrameLength;
    int8u    outputFrameLengthDivided256;
};
const size_t coreSbrFrameLengthIndex_Mapping_Size=5;
coreSbrFrameLengthIndex_mapping coreSbrFrameLengthIndex_Mapping[coreSbrFrameLengthIndex_Mapping_Size]=
{
    { 0, 768,   3 },
    { 0, 1024,  4 },
    { 2, 768,   8 },
    { 3, 1024,  8 },
    { 1, 1024, 16 },
};

//---------------------------------------------------------------------------
static const size_t LoudnessMeaning_Size=9;
static const char* LoudnessMeaning[LoudnessMeaning_Size]=
{
    "Program",
    "Anchor",
    "MaximumOfRange",
    "MaximumMomentary",
    "MaximumShortTerm",
    "Range",
    "ProductionMixingLevel",
    "RoomType",
    "ShortTerm",
};

static Ztring Loudness_Value(int8u methodDefinition, int8u methodValue)
{
    switch (methodDefinition)
    {
        case 0:
                return Ztring();
        case 1:
        case 2:
        case 3:
        case 4:
        case 5:
                return Ztring::ToZtring(-57.75+((double)methodValue)/4, 2)+__T(" LKFS");
        case 6: 
                {
                int8u Value;
                if (methodValue==0)
                    Value=0;
                else if (methodValue<=128)
                    Value=methodValue/4;
                else if (methodValue<=204)
                    Value=methodValue/2-32;
                else
                    Value=methodValue-134; 
                return Ztring::ToZtring(Value)+__T(" LU");
                }
        case 7: 
                return Ztring::ToZtring(80+methodValue)+__T(" dB");
        case 8:
                switch(methodValue)
                {
                    case 0: return Ztring();
                    case 1: return __T("Large room");
                    case 2: return __T("Small room");
                    default: return Ztring::ToZtring(methodValue);
                }
        case 9:
                return Ztring::ToZtring(-116+((double)methodValue)/2, 1)+__T(" LKFS");
        default:
                return Ztring().From_Number(methodValue);
    }
}

//---------------------------------------------------------------------------
static const char* measurementSystems[]=
{
    "",
    "EBU R-128",
    "ITU-R BS.1770-4",
    "ITU-R BS.1770-4 with pre-processing",
    "User",
    "Expert/panel",
    "ITU-R BS.1771-1",
    "Reserved Measurement System A",
    "Reserved Measurement System B",
    "Reserved Measurement System C",
    "Reserved Measurement System D",
    "Reserved Measurement System E",
};
auto measurementSystems_Size=sizeof(measurementSystems)/sizeof(const char*);

//---------------------------------------------------------------------------
static const char* reliabilities[]=
{
    "",
    "Unverified",
    "Not to exceed ceiling",
    "Accurate",
};
auto reliabilities_Size=sizeof(reliabilities)/sizeof(const char*);

//---------------------------------------------------------------------------
static const char* drcSetEffect_List[]=
{
    "Night",
    "Noisy",
    "Limited",
    "LowLevel",
    "Dialog",
    "General",
    "Expand",
    "Artistic",
    "Clipping",
    "Fade",
    "DuckOther",
    "DuckSelf",
};
auto drcSetEffect_List_Size=sizeof(drcSetEffect_List)/sizeof(const char*);

//---------------------------------------------------------------------------
#if MEDIAINFO_CONFORMANCE
struct profile_constraints
{
    int8u   MaxChannels;
    int8u   MaxSamplingRate;              // 1 = 24 kHz, 2 = 48 kHz, 3 = 96 kHz
};
static profile_constraints xHEAAC_Constraints[] = // Frame tables in chapter "Extended HE AAC profile" (comments are from table "Levels for the extended HE AAC profile")
{
    {  1, 2},
    {  2, 2},
    {  2, 2},
    {  2, 2}, // {  6, 2},
    {  2, 2}, // {  6, 3},
    {  2, 2}, // {  8, 2},
    {  2, 2}, // {  8, 3},
};
struct measurement_present
{
    int8u                       methodDefinition;
    int8u                       measurementSystem;

    friend bool operator<(const measurement_present& l, const measurement_present& r)
    {
        if (l.methodDefinition < r.methodDefinition)
            return true;
        if (l.methodDefinition != r.methodDefinition)
            return false;
        return l.measurementSystem < r.measurementSystem;
    }
};
#endif


//---------------------------------------------------------------------------
#if MEDIAINFO_CONFORMANCE
static constexpr int8u channelConfiguration_Orders[] =
{
    0, 1, 2, 4, 7, 10, 14, 19, 21, 23, 25, 30, 35, 51, // Offset
    // 1
    ID_USAC_SCE,
    // 2
    ID_USAC_CPE,
    // 3
    ID_USAC_SCE,
    ID_USAC_CPE,
    // 4
    ID_USAC_SCE,
    ID_USAC_CPE,
    ID_USAC_SCE,
    // 5
    ID_USAC_SCE,
    ID_USAC_CPE,
    ID_USAC_CPE,
    // 6
    ID_USAC_SCE,
    ID_USAC_CPE,
    ID_USAC_CPE,
    ID_USAC_LFE,
    // 7
    ID_USAC_SCE,
    ID_USAC_CPE,
    ID_USAC_CPE,
    ID_USAC_CPE,
    ID_USAC_LFE,
    // 8
    ID_USAC_SCE,
    ID_USAC_SCE,
    // 9
    ID_USAC_CPE,
    ID_USAC_SCE,
    // 10
    ID_USAC_CPE,
    ID_USAC_CPE,
    // 11
    ID_USAC_SCE,
    ID_USAC_CPE,
    ID_USAC_CPE,
    ID_USAC_SCE,
    ID_USAC_LFE,
    // 12
    ID_USAC_SCE,
    ID_USAC_CPE,
    ID_USAC_CPE,
    ID_USAC_CPE,
    ID_USAC_LFE,
    // 13
    ID_USAC_SCE,
    ID_USAC_CPE,
    ID_USAC_CPE,
    ID_USAC_CPE,
    ID_USAC_CPE,
    ID_USAC_SCE,
    ID_USAC_LFE,
    ID_USAC_LFE,
    ID_USAC_SCE,
    ID_USAC_CPE,
    ID_USAC_CPE,
    ID_USAC_SCE,
    ID_USAC_CPE,
    ID_USAC_SCE,
    ID_USAC_SCE,
    ID_USAC_CPE,
};
static_assert(sizeof(channelConfiguration_Orders) / sizeof(int8u) == Aac_Channels_Size_Usac + channelConfiguration_Orders[Aac_Channels_Size_Usac - 1], "");
#endif

//***************************************************************************
// Constructor/Destructor
//***************************************************************************

//---------------------------------------------------------------------------
File_Usac::File_Usac()
:File__Analyze()
{
    channelConfiguration=(int8u)-1;
    sampling_frequency_index=(int8u)-1;
    extension_sampling_frequency_index=(int8u)-1;
    IsParsingRaw=0;
    #if MEDIAINFO_CONFORMANCE
        ProfileLevel = { UnknownAudio, 0 };
        Immediate_FramePos=nullptr;
        Immediate_FramePos_IsPresent=nullptr;
        IsCmaf=nullptr;
        outputFrameLength=nullptr;
        FirstOutputtedDecodedSample=nullptr;
        roll_distance_Values=nullptr;
        roll_distance_FramePos=nullptr;
        roll_distance_FramePos_IsPresent=nullptr;
    #endif
}

//---------------------------------------------------------------------------
File_Usac::~File_Usac()
{
}

//***************************************************************************
// Buffer - Global
//***************************************************************************

//---------------------------------------------------------------------------
void File_Usac::Read_Buffer_Init()
{
    #if MEDIAINFO_CONFORMANCE
        Warning_Error=MediaInfoLib::Config.WarningError();
    #endif
}

//***********************************************************************
// Temp
//***********************************************************************

//---------------------------------------------------------------------------
void File_Usac::hcod_sf(const char* Name)
{
    Element_Begin1(Name);
    int16u Pos=0;
    int32u index=0;

    for (;;)
    {
        int8u h;
        Peek_S1(2, h);
        index = huffman_scl[index][h];
        if (index & 1)
        {
            if (index & 2)
                Skip_SB(                                        "huffman");
            else
                Skip_S1(2,                                      "huffman");
            break;
        }
        Skip_S1(2,                                              "huffman");
        index >>= 2;

        if (Pos>240)
        {
            #if MEDIAINFO_CONFORMANCE
                Fill_Conformance("UsacCoreCoderData GeneralCompliance", "Issue detected while parsing hcod_sf");
            #endif
            C.IFrameParsed=false;
            Element_End0();
            return;
        }
    }
    Element_Info1(huffman_scl[Pos][0]-60);
    Element_End0();
}

//----------------------------------------------------------------------------
int32u File_Usac::arith_decode(int16u& low, int16u& high, int16u& value, const int16u* cf, int32u cfl, size_t* TooMuch)
{
    int32u range=(int32u)(high-low+1), value32=value;
    int32u cm=((((int)(value32-low+1))<<14)-((int)1))/range;
    const int16u* p=cf-1;

    do
    {
        const int16u* q=p+(cfl>>1);
        if (*q>cm)
        {
            p=q;
            cfl++;
        }
        cfl>>=1;
    }
    while (cfl>1);

    int32u symbol=(int32u)(p-cf+1);
    if (symbol)
        high=low+((range*cf[symbol-1])>>14)-1;
    low+=(range*cf[symbol])>>14;

    for (;;)
    {
        if (high&0x8000)
        {
            if (!(low&0x8000))
            {
                 if (low&0x4000 && !(high&0x4000))
                 {
                     low-=0x4000;
                     high-=0x4000;
                     value32-=0x4000;
                 }
                 else
                     break;
            }
        }

        low=low<<1;
        high=(high<<1) | 1;

        value32<<=1;
        if (Data_BS_Remain())
        {
            bool bit;
            Get_SB (bit,                                        "arith_data");
            value32|=(int)bit;
        }
        else
        {
            (*TooMuch)++;
        }
    }

    value=(int16u)value32;
    return symbol;
}

//---------------------------------------------------------------------------
int16u File_Usac::sbr_huff_dec(const int8s(*Table)[2], const char* Name)
{
    int8u bit;
    int8s index=0;

    Element_Begin1(Name);
    while (index>=0)
    {
        Get_S1(1, bit,                                          "bit");
        index=Table[index][bit];
    }
    Element_End0();

    return index+64;
}

//---------------------------------------------------------------------------
int16s File_Usac::huff_dec_1D(const int16s (*Table)[2], const char* Name)
{
    Element_Begin1(Name);

    int8u bit;
    int16s index=0;
    do
    {
        Get_S1(1, bit,                                          "bit");
        index=Table[index][bit];
    }
    while (index>0);
    Element_End0();

    return index;
}

//---------------------------------------------------------------------------
bool File_Usac::huff_dec_2D(const int16s (*Table)[2], int8s (&aTmp)[2], const char* Name)
{
    int16s index=huff_dec_1D(Table, Name);

    if (index==0) //Escape
    {
        aTmp[0]=0;
        aTmp[1]=1;
        return true;
    }

    index=-(index+1);
    aTmp[0]=index>>4;
    aTmp[1]=index&0xf;

    return false;
}

//***********************************************************************
// BS_Bookmark
//***********************************************************************

//---------------------------------------------------------------------------
File_Usac::bs_bookmark File_Usac::BS_Bookmark(size_t NewSize)
{
    bs_bookmark B;
    auto RemainingSize=Data_BS_Remain();
    #if !MEDIAINFO_TRACE
        size_t BS_Size=(Element_Size-Element_Offset)*8;
    #endif //MEDIAINFO_TRACE
    auto AlreadyParsed=BS_Size-RemainingSize;
    if (NewSize>RemainingSize)
        NewSize=RemainingSize;
    B.Element_Offset=Element_Offset;
    B.Element_Size=Element_Size;
    B.Trusted=Trusted;
    B.UnTrusted=Element[Element_Level].UnTrusted;
    B.End=RemainingSize-NewSize;
    B.BitsNotIncluded=B.End%8;
    B.NewSize=NewSize+B.BitsNotIncluded;
    BS->Resize(B.NewSize);
    BS_Size=AlreadyParsed+B.NewSize;
    Element_Size=Element_Offset+(BS_Size+7)/8;
    #if MEDIAINFO_CONFORMANCE
        for (size_t Level=0; Level<ConformanceLevel_Max; Level++)
            B.ConformanceErrors[Level]=ConformanceErrors[Level];
    #endif
    return B;
}

//---------------------------------------------------------------------------
#if MEDIAINFO_CONFORMANCE
bool File_Usac::BS_Bookmark(File_Usac::bs_bookmark& B, const string& ConformanceFieldName)
#else
bool File_Usac::BS_Bookmark(File_Usac::bs_bookmark& B)
#endif
{
    if (Data_BS_Remain()>B.BitsNotIncluded)
    {
        int8u LastByte;
        auto BitsRemaining=Data_BS_Remain()-B.BitsNotIncluded;
        if (BitsRemaining<8)
        {
            //Peek_S1((int8u)BitsRemaining, LastByte);
            //#if MEDIAINFO_CONFORMANCE
            //    if (LastByte)
            //        Fill_Conformance((ConformanceFieldName+" GeneralCompliance").c_str(), "Padding bits are not 0, the bitstream may be malformed", bitset8(), Warning);
            //#endif
            LastByte=0;
        }
        else
        {
            #if MEDIAINFO_CONFORMANCE
                bool IsZeroed=false;
                if (BitsRemaining<=32) //TODO: more than 32 bits
                {
                    int32u Probe;
                    Peek_S4(BitsRemaining, Probe);
                    IsZeroed=!Probe;
                }
                if (IsZeroed)
                    Fill_Conformance((ConformanceFieldName+" GeneralCompliance").c_str(), "Extra zero bytes after the end of the syntax was reached", bitset8(), Warning);
                else
                    Fill_Conformance((ConformanceFieldName+" GeneralCompliance").c_str(), "Extra bytes after the end of the syntax was reached", bitset8(), Warning);
            #endif
            LastByte=1;
        }
        Skip_BS(BitsRemaining,                                  LastByte?"Unknown":"Padding");
    }
    else if (C.IFrameParsed && Data_BS_Remain()<B.BitsNotIncluded)
        Trusted_IsNot("Too big");
    bool IsNotValid=!Trusted_Get();
    #if MEDIAINFO_CONFORMANCE
        if (IsNotValid)
        {
            for (size_t Level=0; Level<ConformanceLevel_Max; Level++)
                ConformanceErrors[Level]=B.ConformanceErrors[Level];
            Fill_Conformance((ConformanceFieldName + " GeneralCompliance").c_str(), "Bitstream parsing ran out of data to read before the end of the syntax was reached, most probably the bitstream is malformed");
        }
    #endif
    BS->Resize(B.End);
    Element_Offset=B.Element_Offset;
    Element_Size=B.Element_Size;
    #if MEDIAINFO_TRACE
        BS_Size=(Element_Size-Element_Offset)*8;
    #endif //MEDIAINFO_TRACE
    Trusted=B.Trusted;
    Element[Element_Level].UnTrusted=B.UnTrusted;
    return IsNotValid;
}

//***********************************************************************
// Conformance
//***********************************************************************

//---------------------------------------------------------------------------
#if MEDIAINFO_CONFORMANCE
void File_Usac::Fill_Conformance(const char* Field, const char* Value, bitset8 Flags, conformance_level Level)
{
    if (Level == Warning && Warning_Error)
        Level = Error;
    field_value FieldValue(Field, Value, Flags, (int64u)-1, IsParsingRaw>=2?(IsParsingRaw-2):(int64u)-1);
    auto& Conformance = ConformanceErrors[Level];
    auto Current = find(Conformance.begin(), Conformance.end(), FieldValue);
    if (Current != Conformance.end())
        return;
    Conformance.emplace_back(FieldValue);
}
#endif

//---------------------------------------------------------------------------
#if MEDIAINFO_CONFORMANCE
void File_Usac::Clear_Conformance()
{
    for (size_t Level = 0; Level < ConformanceLevel_Max; Level++)
    {
        auto& Conformance = ConformanceErrors[Level];
        Conformance.clear();
    }
}
#endif

//---------------------------------------------------------------------------
#if MEDIAINFO_CONFORMANCE
void File_Usac::Merge_Conformance(bool FromConfig)
{
    for (size_t Level = 0; Level < ConformanceLevel_Max; Level++)
    {
        auto& Conformance = ConformanceErrors[Level];
        auto& Conformance_Total = ConformanceErrors_Total[Level];
        for (const auto& FieldValue : Conformance)
        {
            auto Current = find(Conformance_Total.begin(), Conformance_Total.end(), FieldValue);
            if (Current != Conformance_Total.end())
            {
                if (Current->FramePoss.size() < 8)
                {
                    if (FromConfig)
                    {
                        if (Current->FramePoss.empty() || Current->FramePoss[0].Main != (int64u)-1)
                            Current->FramePoss.insert(Current->FramePoss.begin(), {(int64u)-1, (int64u)-1});
                    }
                    else
                        Current->FramePoss.push_back({Frame_Count_NotParsedIncluded, FieldValue.FramePoss[0].Sub});
                }
                else if (Current->FramePoss.size() == 8)
                    Current->FramePoss.push_back({(int64u)-1, (int64u)-1}); //Indicating "..."
                continue;
            }
            if (!CheckIf(FieldValue.Flags))
                continue;
            Conformance_Total.push_back(FieldValue);
            if (!FromConfig)
                Conformance_Total.back().FramePoss.front() = {Frame_Count_NotParsedIncluded, FieldValue.FramePoss[0].Sub};
        }
        Conformance.clear();
    }
}
#endif

//---------------------------------------------------------------------------
#if MEDIAINFO_CONFORMANCE
const profilelevel_struct& Mpeg4_Descriptors_ToProfileLevel(int8u AudioProfileLevelIndication);
void File_Usac::SetProfileLevel(int8u AudioProfileLevelIndication)
{
    ProfileLevel = Mpeg4_Descriptors_ToProfileLevel(AudioProfileLevelIndication);
    switch (ProfileLevel.profile)
    {
        case Baseline_USAC                    : ConformanceFlags.set(BaselineUsac); break;
        case Extended_HE_AAC                  : ConformanceFlags.set(xHEAAC); break;
        default:;
    }
}
#endif

//---------------------------------------------------------------------------
#if MEDIAINFO_CONFORMANCE
void File_Usac::Streams_Finish_Conformance_Profile(usac_config& CurrentConf)
{
    if (ProfileLevel.profile == UnknownAudio)
    {
        auto AudioProfileLevelIndication = MediaInfoLib::Config.UsacProfile();
        if (!AudioProfileLevelIndication)
            SetProfileLevel(AudioProfileLevelIndication);
        else if (!IsSub)
            ConformanceFlags.set(xHEAAC); // TODO: remove this check (initially done for LATM without the profile option)
    }

    if (ConformanceFlags[xHEAAC] && ProfileLevel.profile == Extended_HE_AAC && ProfileLevel.level > 1 && ProfileLevel.level <= 5)
    {
        if (CurrentConf.sampling_frequency && xHEAAC_Constraints[ProfileLevel.level].MaxSamplingRate)
        {
            int32u MaxSamplingRate = 24000 << (xHEAAC_Constraints[ProfileLevel.level].MaxSamplingRate - 1);
            if (CurrentConf.sampling_frequency > MaxSamplingRate)
                Fill_Conformance("Crosscheck InitialObjectDescriptor audioProfileLevelIndication", ("MP4 InitialObjectDescriptor audioProfileLevelIndication " + Mpeg4_Descriptors_AudioProfileLevelString(ProfileLevel) + " does not permit USAC UsacConfig usacSamplingFrequency " + to_string(CurrentConf.sampling_frequency) + ", max is " + to_string(MaxSamplingRate)).c_str());
        }
        else if (CurrentConf.sampling_frequency > 48000)
            Fill_Conformance("Crosscheck InitialObjectDescriptor audioProfileLevelIndication", ("MP4 InitialObjectDescriptor audioProfileLevelIndication " + Mpeg4_Descriptors_AudioProfileLevelString(ProfileLevel) + " does not permit USAC UsacConfig usacSamplingFrequency " + to_string(CurrentConf.sampling_frequency) + ", max is 48000").c_str());
        else if (CurrentConf.sampling_frequency_index < Aac_sampling_frequency_Size && Aac_sampling_frequency[CurrentConf.sampling_frequency_index] == CurrentConf.sampling_frequency
         && ((CurrentConf.sampling_frequency_index < 0x03 || CurrentConf.sampling_frequency_index > 0x0C) && (CurrentConf.sampling_frequency_index < 0x11 || CurrentConf.sampling_frequency_index > 0x1B)))
            Fill_Conformance("Crosscheck InitialObjectDescriptor audioProfileLevelIndication", ("MP4 InitialObjectDescriptor audioProfileLevelIndication " + Mpeg4_Descriptors_AudioProfileLevelString(ProfileLevel) + " does not permit USAC UsacConfig usacSamplingFrequency " + to_string(CurrentConf.sampling_frequency)).c_str());
        if (!CurrentConf.channelConfigurationIndex)
        {
            if (CurrentConf.numOutChannels && CurrentConf.numOutChannels > xHEAAC_Constraints[ProfileLevel.level].MaxChannels)
                Fill_Conformance("Crosscheck InitialObjectDescriptor audioProfileLevelIndication", ("MP4 InitialObjectDescriptor audioProfileLevelIndication " + Mpeg4_Descriptors_AudioProfileLevelString(ProfileLevel) + " does not permit USAC UsacConfig numOutChannels " + to_string(CurrentConf.numOutChannels) + ", max is " + to_string(xHEAAC_Constraints[ProfileLevel.level].MaxChannels)).c_str());
        }
        else
        {
            switch (CurrentConf.channelConfigurationIndex)
            {
                case 1 :
                case 2 :
                case 8 :
                        break;
                default:
                    Fill_Conformance("Crosscheck InitialObjectDescriptor audioProfileLevelIndication", ("MP4 InitialObjectDescriptor audioProfileLevelIndication " + Mpeg4_Descriptors_AudioProfileLevelString(ProfileLevel) + " does not permit USAC UsacConfig channelConfigurationIndex " + to_string(CurrentConf.channelConfigurationIndex)).c_str());
            }
        }
    }
    if (IsCmaf && *IsCmaf && CurrentConf.channelConfigurationIndex != 1 && CurrentConf.channelConfigurationIndex != 2)
        Fill_Conformance("Crosscheck CMAF channelConfiguration", ("CMAF does not permit USAC UsacConfig channelConfigurationIndex " + to_string(CurrentConf.channelConfigurationIndex) + ", permitted values are 1 and 2").c_str());
}
void File_Usac::Streams_Finish_Conformance()
{
    Streams_Finish_Conformance_Profile(Conf);
    Merge_Conformance(true);

    for (size_t Level = 0; Level < ConformanceLevel_Max; Level++)
    {
        auto& Conformance_Total = ConformanceErrors_Total[Level];
        if (Conformance_Total.empty())
            continue;
        for (size_t i = Conformance_Total.size(); i-- > 0;) {
            if (!CheckIf(Conformance_Total[i].Flags)) {
                Conformance_Total.erase(Conformance_Total.begin() + i);
            }
        }
        if (Conformance_Total.empty())
            continue;
        string Conformance_String = "Conformance";
        Conformance_String += ConformanceLevel_Strings[Level];
        Fill(Stream_Audio, 0, Conformance_String.c_str(), Conformance_Total.size());
        Conformance_String += ' ';
        for (const auto& ConformanceError : Conformance_Total) {
            size_t Space = 0;
            for (;;) {
                Space = ConformanceError.Field.find(' ', Space + 1);
                if (Space == string::npos) {
                    break;
                }
                const auto Field = Conformance_String + ConformanceError.Field.substr(0, Space);
                const auto& Value = Retrieve_Const(StreamKind_Last, StreamPos_Last, Field.c_str());
                if (Value.empty()) {
                    Fill(StreamKind_Last, StreamPos_Last, Field.c_str(), "Yes");
                }
            }
            auto Value = ConformanceError.Value;
            if (!ConformanceError.FramePoss.empty() && (ConformanceError.FramePoss.size() != 1 || ConformanceError.FramePoss[0].Main != (int64u)-1))
            {
                auto HasConfError = ConformanceError.FramePoss[0].Main == (int64u)-1;
                Value += " (";
                if (HasConfError)
                    Value += "conf & ";
                Value += "frame";
                if (ConformanceError.FramePoss.size() - HasConfError > 1)
                    Value += 's';
                Value += ' ';
                for (size_t i = HasConfError; i < ConformanceError.FramePoss.size(); i++)
                {
                    auto FramePos = ConformanceError.FramePoss[i];
                    if (FramePos.Main == (int64u)-1)
                        Value += "...";
                    else
                    {
                        Value += to_string(FramePos.Main);
                        if (FramePos.Sub != (int64u)-1)
                        {
                            Value += '.';
                            Value += to_string(FramePos.Sub);
                        }
                    }
                    Value += '+';
                }
                Value.back() = ')';
            }
            Fill(Stream_Audio, 0, (Conformance_String + ConformanceError.Field).c_str(), Value);
        }
        Conformance_Total.clear();
    }
}
#endif

//---------------------------------------------------------------------------
#if MEDIAINFO_CONFORMANCE
void File_Usac::numPreRollFrames_Check(usac_config& CurrentConf, int32u numPreRollFrames, const string& numPreRollFramesConchString)
{
    string FieldName = numPreRollFramesConchString.substr(numPreRollFramesConchString.rfind(' ') + 1);
    int numPreRollFrames_Max;
    if (CurrentConf.coreSbrFrameLengthIndex >= coreSbrFrameLengthIndex_Mapping_Size || coreSbrFrameLengthIndex_Mapping[CurrentConf.coreSbrFrameLengthIndex].sbrRatioIndex)
    {
        if (CurrentConf.harmonicSBR)
            numPreRollFrames_Max = 3;
        else
            numPreRollFrames_Max = 2;
    }
    else
        numPreRollFrames_Max = 1;
    if (numPreRollFrames != numPreRollFrames_Max)
    {
        auto Value = FieldName + " is " + to_string(numPreRollFrames) + " but ";
        if (numPreRollFrames > numPreRollFrames_Max)
            Value += "<= ";
        if (numPreRollFrames > 3)
        {
            Value += "3 is required";
        }
        else
        {
            Value += to_string(numPreRollFrames_Max) + " is recommended";
            if (CurrentConf.coreSbrFrameLengthIndex >= coreSbrFrameLengthIndex_Mapping_Size || coreSbrFrameLengthIndex_Mapping[CurrentConf.coreSbrFrameLengthIndex].sbrRatioIndex)
            {
                if (CurrentConf.harmonicSBR)
                {
                    if (numPreRollFrames < numPreRollFrames_Max)
                        Value += " due to SBR with harmonic patching";
                }
                else
                    Value += " due to SBR without harmonic patching";
            }
            else
                Value += " due to no SBR";
        }
        Fill_Conformance(numPreRollFramesConchString.c_str(), Value, bitset8(), numPreRollFrames > numPreRollFrames_Max ? Error : Warning);
    }
}
#endif

//***************************************************************************
// Elements - USAC - Config
//***************************************************************************

//---------------------------------------------------------------------------
void File_Usac::UsacConfig(size_t BitsNotIncluded)
{
    // Init
    C = usac_config();
    #if MEDIAINFO_CONFORMANCE
        C.Reset();
    #endif

    Element_Begin1("UsacConfig");
    bool usacConfigExtensionPresent;
    Get_S1 (5, C.sampling_frequency_index,                      "usacSamplingFrequencyIndex"); Param_Info1C(C.sampling_frequency_index<Aac_sampling_frequency_Size_Usac && Aac_sampling_frequency[C.sampling_frequency_index], Aac_sampling_frequency[C.sampling_frequency_index]);
    if (C.sampling_frequency_index==0x1F)
    {
        int32u samplingFrequency;
        Get_S3 (24, samplingFrequency,                          "usacSamplingFrequency");
        C.sampling_frequency_index=Aac_AudioSpecificConfig_sampling_frequency_index(samplingFrequency, true);
        C.sampling_frequency=samplingFrequency;
        #if MEDIAINFO_CONFORMANCE
            if (C.sampling_frequency == Aac_sampling_frequency[C.sampling_frequency_index]) {
                Fill_Conformance("UsacConfig usacSamplingFrequencyIndex", ("usacSamplingFrequency is used but usacSamplingFrequencyIndex " + to_string(C.sampling_frequency_index) + " could be used instead").c_str(), bitset8(), Warning);
            }
        #endif
    }
    else
    {
        C.sampling_frequency=Aac_sampling_frequency[C.sampling_frequency_index];
        #if MEDIAINFO_CONFORMANCE
            if (!C.sampling_frequency) {
                Fill_Conformance("UsacConfig usacSamplingFrequencyIndex", ("usacSamplingFrequencyIndex " + to_string(C.sampling_frequency_index) + " is known as reserved in ISO/IEC 23003-3:2020, bitstream parsing is partial and may be wrong").c_str(), bitset8(), Info);
                if (Frequency_b)
                {
                    for (size_t i = 0; i < Aac_sampling_frequency_Size_Usac; i++)
                        if (Aac_sampling_frequency[i] == Frequency_b)
                            Fill_Conformance("Crosscheck AudioSpecificConfig samplingFrequency", ("MP4 AudioSpecificConfig samplingFrequency " + to_string(Frequency_b) + " does not match USAC UsacConfig usacSamplingFrequencyIndex " + to_string(C.sampling_frequency_index)).c_str());
                }
            }
        #endif
    }
    #if MEDIAINFO_CONFORMANCE
        if (Frequency_b && C.sampling_frequency && C.sampling_frequency != Frequency_b)
            Fill_Conformance("Crosscheck AudioSpecificConfig samplingFrequency", ("MP4 AudioSpecificConfig samplingFrequency " + to_string(Frequency_b) + " does not match USAC UsacConfig usacSamplingFrequency " + to_string(C.sampling_frequency)).c_str());
    #endif
    Get_S1 (3, C.coreSbrFrameLengthIndex,                       "coreSbrFrameLengthIndex");
    Get_S1 (5, C.channelConfigurationIndex,                     "channelConfigurationIndex"); Param_Info1C(C.channelConfigurationIndex, Aac_ChannelLayout_GetString(C.channelConfigurationIndex));
    #if MEDIAINFO_CONFORMANCE
        if (channelConfiguration && C.channelConfigurationIndex && C.channelConfigurationIndex != channelConfiguration)
            Fill_Conformance("Crosscheck AudioSpecificConfig channelConfiguration", ("MP4 AudioSpecificConfig channelConfiguration " + to_string(channelConfiguration) + Aac_ChannelLayout_GetString(channelConfiguration, false, true) + " does not match USAC UsacConfig channelConfigurationIndex " + to_string(C.channelConfigurationIndex) + Aac_ChannelLayout_GetString(C.channelConfigurationIndex, false, true)).c_str());
    #endif
    if (!C.channelConfigurationIndex)
    {
        escapedValue(C.numOutChannels, 5, 8, 16,                "numOutChannels");
        #if MEDIAINFO_CONFORMANCE
            C.numOutChannels_Lfe.clear();
            string ExpectedOrder;
            if (channelConfiguration)
                ExpectedOrder = Aac_ChannelLayout_GetString(channelConfiguration);
            string ActualOrder;
            set<int32u> bsOutChannelPos_List;
        #endif
        for (int32u i=0; i<C.numOutChannels; i++)
        {
            int8u bsOutputChannelPos;
            Get_S1 (5, bsOutputChannelPos,                         "bsOutputChannelPos"); Param_Info1(Aac_OutputChannelPosition_GetString(bsOutputChannelPos));
            #if MEDIAINFO_CONFORMANCE
                if (bsOutChannelPos_List.find(bsOutputChannelPos) != bsOutChannelPos_List.end())
                {
                    string Value = Aac_OutputChannelPosition_GetString(bsOutputChannelPos);
                    if (Value.empty())
                        Value = to_string(bsOutputChannelPos);
                    else
                        Value = to_string(bsOutputChannelPos) + " (" + Value + ')';
                    Fill_Conformance("UsacConfig bsOutputChannelPos", ("bsOutputChannelPos " + Value + " is present 2 times but only 1 instance is permitted").c_str());
                }
                else
                    bsOutChannelPos_List.insert(bsOutputChannelPos);
                size_t ActualOrder_Previous = ActualOrder.size();
                ActualOrder += Aac_OutputChannelPosition_GetString(bsOutputChannelPos);
                if (ActualOrder.find("LFE", ActualOrder_Previous) != string::npos)
                    C.numOutChannels_Lfe.push_back(i);
                ActualOrder += ' ';
            #endif
        }
        #if MEDIAINFO_CONFORMANCE
            if (!ActualOrder.empty())
            {
                ActualOrder.pop_back();
                for (size_t i = 1; i < Aac_Channels_Size_Usac; i++)
                {
                    string PossibleOrder = Aac_ChannelLayout_GetString(i);
                    if (PossibleOrder == ActualOrder)
                        Fill_Conformance("UsacConfig channelConfigurationIndex", ("channelConfigurationIndex is 0 but channelConfigurationIndex " + to_string(i) + " could be used for channel mapping " + ActualOrder).c_str(), bitset8(), Warning);
                }
                if (ConformanceFlags[xHEAAC] && ProfileLevel.profile == Extended_HE_AAC && ProfileLevel.level > 1 && ProfileLevel.level <= 5)
                {
                    if (C.numOutChannels == 2 && ActualOrder != "L R")
                        Fill_Conformance("Crosscheck InitialObjectDescriptor audioProfileLevelIndication", ("MP4 InitialObjectDescriptor audioProfileLevelIndication " + Mpeg4_Descriptors_AudioProfileLevelString(ProfileLevel) + " implies a channel layout of L R, a channel layout of " + ActualOrder + " is not recommended").c_str(), bitset8(), Warning);
                }
            }
            if (!C.numOutChannels)
                Fill_Conformance("numOutChannels GeneralCompliance", "numOutChannels is 0");
            else if (!ExpectedOrder.empty())
            {
                if (ExpectedOrder != ActualOrder)
                    Fill_Conformance("Crosscheck AudioSpecificConfig channelConfigurationIndex", ("MP4 AudioSpecificConfig channelConfigurationIndex " + to_string(channelConfiguration) + " (" + ExpectedOrder + ") does not match USAC UsacConfig channel mapping " + ActualOrder).c_str());
            }
        #endif
    }
    else if (C.channelConfigurationIndex<Aac_Channels_Size_Usac)
        C.numOutChannels=Aac_Channels[C.channelConfigurationIndex];
    else
    {
        C.numOutChannels=0;
        #if MEDIAINFO_CONFORMANCE
            Fill_Conformance("UsacConfig channelConfigurationIndex", ("channelConfigurationIndex " + to_string(C.channelConfigurationIndex) + " is known as reserved in ISO/IEC 23003-3:2020, bitstream parsing is partial and may be wrong").c_str(), bitset8(), Info);
        #endif
    }
    channelConfiguration=C.channelConfigurationIndex;
    #if MEDIAINFO_CONFORMANCE
        Streams_Finish_Conformance_Profile(C);
        if (C.coreSbrFrameLengthIndex >= coreSbrFrameLengthIndex_Mapping_Size)
            Fill_Conformance("UsacConfig coreSbrFrameLengthIndex", ("coreSbrFrameLengthIndex " + to_string(C.coreSbrFrameLengthIndex) + " is known as reserved in ISO/IEC 23003-3:2020, bitstream parsing is partial and may be wrong").c_str(), bitset8(), Info);
    #endif
    UsacDecoderConfig();
    if (!C.IFrameParsed)
    {
        Element_End0();
        return;
    }
    Get_SB (usacConfigExtensionPresent,                         "usacConfigExtensionPresent");
    if (usacConfigExtensionPresent)
        UsacConfigExtension();
    Element_End0();

    if (BitsNotIncluded!=(size_t)-1)
    {
        if (Data_BS_Remain()>BitsNotIncluded)
        {
            int8u LastByte;
            auto BitsRemaining=Data_BS_Remain()-BitsNotIncluded;
            if (BitsRemaining<8)
            {
                //Peek_S1((int8u)BitsRemaining, LastByte);
                //#if MEDIAINFO_CONFORMANCE
                //    if (LastByte)
                //        Fill_Conformance((ConformanceFieldName+" GeneralCompliance").c_str(), "Padding bits are not 0, the bitstream may be malformed", bitset8(), Warning);
                //#endif
                LastByte=0;
            }
            else
            {
                #if MEDIAINFO_CONFORMANCE
                    bool IsZeroed=false;
                    if (BitsRemaining<=32) //TODO: more than 32 bits
                    {
                        int32u Probe;
                        Peek_S4(BitsRemaining, Probe);
                        IsZeroed=!Probe;
                    }
                    if (IsZeroed)
                        Fill_Conformance("UsacConfig GeneralCompliance", "Extra zero bytes after the end of the syntax was reached", bitset8(), Warning);
                    else
                        Fill_Conformance("UsacConfig GeneralCompliance", "Extra bytes after the end of the syntax was reached", bitset8(), Warning);
                #endif
                LastByte=1;
            }
            Skip_BS(BitsRemaining,                              LastByte?"Unknown":"Padding");
        }
        else if (C.IFrameParsed && Data_BS_Remain()<BitsNotIncluded)
            Trusted_IsNot("Too big");
    }

    if (Trusted_Get())
    {
        // Filling
        if (!IsParsingRaw)
        {
            if (C.coreSbrFrameLengthIndex<coreSbrFrameLengthIndex_Mapping_Size)
                Fill(Stream_Audio, 0, Audio_SamplesPerFrame, coreSbrFrameLengthIndex_Mapping[C.coreSbrFrameLengthIndex].outputFrameLengthDivided256<<8, 10, true);
            Fill_DRC();
            Fill_Loudness();
            #if MEDIAINFO_CONFORMANCE
                Merge_Conformance(true);
            #endif
            Conf=C;
        }
    }
    else
    {
        C.usacElements.clear();
        #if MEDIAINFO_CONFORMANCE
            if (!IsParsingRaw)
            {
                Clear_Conformance();
                Fill_Conformance("UsacConfig GeneralCompliance", "Bitstream parsing ran out of data to read before the end of the syntax was reached, most probably the bitstream is malformed.");
                Merge_Conformance();
            }
        #endif
    }
    #if !MEDIAINFO_CONFORMANCE && MEDIAINFO_TRACE
        if (!Trace_Activated)
            Finish();
    #endif
    C.IFrameParsed=false;
}

//---------------------------------------------------------------------------
void File_Usac::Fill_DRC(const char* Prefix)
{
    if (!C.drcInstructionsUniDrc_Data.empty())
    {
        string FieldPrefix;
        if (Prefix)
        {
            FieldPrefix+=Prefix;
            FieldPrefix += ' ';
        }

        Fill(Stream_Audio, 0, (FieldPrefix+"DrcSets_Count").c_str(), C.drcInstructionsUniDrc_Data.size());
        Fill_SetOptions(Stream_Audio, 0, (FieldPrefix + "DrcSets_Count").c_str(), "N NI"); // Hidden in text output
        ZtringList Ids, Data;
        for (const auto& Item : C.drcInstructionsUniDrc_Data)
        {
            int8u drcSetId=Item.first.drcSetId;
            int8u downmixId=Item.first.downmixId;
            Ztring Id;
            if (drcSetId || downmixId)
                Id=Ztring::ToZtring(drcSetId)+=__T('-')+Ztring::ToZtring(downmixId);
            Ids.push_back(Id);
            Data.push_back(Ztring().From_UTF8(Item.second.drcSetEffectTotal));
        }
        Fill(Stream_Audio, 0, (FieldPrefix+"DrcSets_Effects").c_str(), Data, Ids);
    }
}

//---------------------------------------------------------------------------
void File_Usac::Fill_Loudness(const char* Prefix, bool NoConCh)
{
    string FieldPrefix;
    if (Prefix)
    {
        FieldPrefix += Prefix;
        FieldPrefix += ' ';
    }
    string FieldSuffix;

    bool DefaultIdPresent = false;
    for (int8u i = 0; i < 2; i++)
    {
        if (i)
            FieldSuffix = "_Album";
        if (!C.loudnessInfo_Data[i].empty())
        {
            Fill(Stream_Audio, 0, (FieldPrefix + "Loudness_Count" + FieldSuffix).c_str(), C.loudnessInfo_Data[i].size());
            Fill_SetOptions(Stream_Audio, 0, (FieldPrefix + "Loudness_Count" + FieldSuffix).c_str(), "N NI"); // Hidden in text output
        }
        vector<drc_id> Ids;
        ZtringList SamplePeakLevel;
        ZtringList TruePeakLevel;
        ZtringList Measurements[16];
        for (const auto& Item : C.loudnessInfo_Data[i])
        {
            Ids.push_back(Item.first);
            SamplePeakLevel.push_back(Item.second.SamplePeakLevel);
            TruePeakLevel.push_back(Item.second.TruePeakLevel);
            for (int8u j = 1; j < 16; j++)
                Measurements[j].push_back(Item.second.Measurements.Values[j]);
        }
        if (Ids.size() >= 1 && Ids.front().empty())
        {
            if (!i)
                DefaultIdPresent = true;
        }
        ZtringList Ids_Ztring;
        for (const auto& Id : Ids)
            Ids_Ztring.emplace_back(Ztring().From_UTF8(Id.to_string()));
        if (Ids_Ztring.empty())
            continue;
        Fill(Stream_Audio, 0, (FieldPrefix + "SamplePeakLevel" + FieldSuffix).c_str(), SamplePeakLevel, Ids_Ztring);
        Fill(Stream_Audio, 0, (FieldPrefix + "TruePeakLevel" + FieldSuffix).c_str(), TruePeakLevel, Ids_Ztring);
        for (int8u j = 0; j < 16; j++)
        {
            string Field;
            if (j && j <= LoudnessMeaning_Size)
                Field = LoudnessMeaning[j - 1];
            else
                Field = Ztring::ToZtring(j).To_UTF8();
            Fill(Stream_Audio, 0, (FieldPrefix + "Loudness_" + Field + FieldSuffix).c_str(), Measurements[j], Ids_Ztring);
        }
    }

    #if MEDIAINFO_CONFORMANCE
        if (NoConCh || !C.IFrameParsed)
            return;
        auto loudnessInfoSet_Present_Total=C.loudnessInfoSet_Present[0]+C.loudnessInfoSet_Present[1];
        if (C.loudnessInfoSet_HasContent[0] && C.loudnessInfoSet_HasContent[1])
            Fill_Conformance("loudnessInfoSet GeneralCompliance", "loudnessInfoSet contains a mix of v0 and v1 loudnessInfo", bitset8(), Warning);
        if (C.loudnessInfoSet_Present[0]>1)
            Fill_Conformance("loudnessInfoSet GeneralCompliance", ("loudnessInfoSet is present " + to_string(C.loudnessInfoSet_Present[0]) + " times but only 1 instance is recommended").c_str(), bitset8(), Warning);
        constexpr14 auto CheckFlags = bitset8().set(xHEAAC).set(MpegH);
        if (false)
        {
        }
        else if (!loudnessInfoSet_Present_Total)
        {
            Fill_Conformance("loudnessInfoSet GeneralCompliance", "loudnessInfoSet is missing", CheckFlags);
            if (ConformanceFlags & CheckFlags)
            {
                Fill(Stream_Audio, 0, (FieldPrefix + "ConformanceCheck").c_str(), "Invalid: loudnessInfoSet is missing");
                Fill(Stream_Audio, 0, "ConformanceCheck/Short", "Invalid: loudnessInfoSet missing");
            }
        }
        else if (C.loudnessInfo_Data[0].empty())
        {
            Fill_Conformance("loudnessInfoSet loudnessInfoCount", "loudnessInfoCount is 0", CheckFlags);
            if (ConformanceFlags & CheckFlags)
            {
                Fill(Stream_Audio, 0, (FieldPrefix + "ConformanceCheck").c_str(), "Invalid: loudnessInfoSet is empty");
                Fill(Stream_Audio, 0, "ConformanceCheck/Short", "Invalid: loudnessInfoSet empty");
            }
        }
        else if (!DefaultIdPresent)
        {
            Fill_Conformance("loudnessInfoSet GeneralCompliance", "Default loudnessInfo is missing", CheckFlags);
            if (ConformanceFlags & CheckFlags)
            {
                Fill(Stream_Audio, 0, (FieldPrefix + "ConformanceCheck").c_str(), "Invalid: Default loudnessInfo is missing");
                Fill(Stream_Audio, 0, "ConformanceCheck/Short", "Invalid: Default loudnessInfo missing");
            }
        }
        else if (!C.LoudnessInfoIsNotValid && C.loudnessInfo_Data[0].begin()->second.Measurements.Values[1].empty() && C.loudnessInfo_Data[0].begin()->second.Measurements.Values[2].empty())
        {
            Fill_Conformance("loudnessInfoSet GeneralCompliance", "None of program loudness or anchor loudness is present in default loudnessInfo", CheckFlags);
            if (ConformanceFlags & CheckFlags)
            {
                Fill(Stream_Audio, 0, (FieldPrefix + "ConformanceCheck").c_str(), "Invalid: None of program loudness or anchor loudness is present in default loudnessInfo");
                Fill(Stream_Audio, 0, "ConformanceCheck/Short", "Invalid: Default loudnessInfo incomplete");
            }
        }
        if (!Retrieve_Const(Stream_Audio, 0, "ConformanceCheck/Short").empty())
        {
            Fill_SetOptions(Stream_Audio, 0, "ConformanceCheck", "N NT"); // Hidden in text output (deprecated)
            Fill_SetOptions(Stream_Audio, 0, "ConformanceCheck/Short", "N NT"); // Hidden in text output
        }
    #endif
}

//---------------------------------------------------------------------------
void File_Usac::UsacDecoderConfig()
{
    #if MEDIAINFO_CONFORMANCE
        usacExtElementType_Present.clear();
        int8u channelConfiguration_Orders_Pos;
        int8u channelConfiguration_Orders_Max;
        int8u CheckChannelConfiguration = (int8u)(C.channelConfigurationIndex && C.channelConfigurationIndex < Aac_Channels_Size_Usac);
        if (CheckChannelConfiguration)
        {
            channelConfiguration_Orders_Pos = Aac_Channels_Size_Usac + channelConfiguration_Orders[C.channelConfigurationIndex - 1];
            channelConfiguration_Orders_Max = Aac_Channels_Size_Usac + channelConfiguration_Orders[C.channelConfigurationIndex];
        }
    #endif

    Element_Begin1("UsacDecoderConfig");
    int32u numElements;
    escapedValue(numElements, 4, 8, 16,                         "numElements minus 1");

    C.IFrameParsed=true;
    for (int32u elemIdx=0; elemIdx<=numElements; elemIdx++)
    {
        Element_Begin1("usacElement");
        int8u usacElementType;
        Get_S1(2, usacElementType,                              "usacElementType"); Element_Info1(usacElementType_IdNames[usacElementType]);
        #if MEDIAINFO_CONFORMANCE
            if (CheckChannelConfiguration == 1 && usacElementType != ID_USAC_EXT)
            {
                if (channelConfiguration_Orders_Pos == channelConfiguration_Orders_Max || usacElementType != channelConfiguration_Orders[channelConfiguration_Orders_Pos])
                    CheckChannelConfiguration = 2;
                else
                    channelConfiguration_Orders_Pos++;
            }
        #endif
        C.usacElements.push_back({usacElementType, 0});
        switch (usacElementType)
        {
            case ID_USAC_SCE                                    : UsacSingleChannelElementConfig(); break;
            case ID_USAC_CPE                                    : UsacChannelPairElementConfig(); break;
            case ID_USAC_LFE                                    : UsacLfeElementConfig(); break;
            case ID_USAC_EXT                                    : UsacExtElementConfig(); break;
        }
        Element_End0();
        if (!Trusted_Get() || !C.IFrameParsed)
            break;
    }
    #if MEDIAINFO_CONFORMANCE
        if (!C.channelConfigurationIndex)
        {
            size_t ChannelCount_NonLfe=0;
            vector<size_t> Channels_Lfe;
            bool AccrossCpe = false;
            for (size_t i = 0 ; i < C.usacElements.size(); i++)
            {
                auto& usacElement = C.usacElements[i];
                switch (usacElement.usacElementType)
                {
                    case ID_USAC_SCE                          : ChannelCount_NonLfe++; break;
                    case ID_USAC_CPE                          : ChannelCount_NonLfe+=2; break;
                    case ID_USAC_LFE                          : Channels_Lfe.push_back(ChannelCount_NonLfe + Channels_Lfe.size()); break;
                }
                if (usacElement.usacElementType == ID_USAC_CPE && C.numOutChannels == ChannelCount_NonLfe + Channels_Lfe.size() - 1)
                    AccrossCpe = true;
            }
            auto ChannelCount = ChannelCount_NonLfe + Channels_Lfe.size();
            if (ChannelCount < C.numOutChannels)
                Fill_Conformance("UsacConfig numOutChannels", ("numOutChannels is " + to_string(C.numOutChannels) + " but the usacElementType sequence contains " + to_string(ChannelCount) + " channels").c_str());
            if (ChannelCount > C.numOutChannels)
            {
                if (AccrossCpe)
                {
                    if (ConformanceFlags[xHEAAC] && ProfileLevel.profile == Extended_HE_AAC && ProfileLevel.level > 1 && ProfileLevel.level <= 5)
                        Fill_Conformance("Crosscheck InitialObjectDescriptor audioProfileLevelIndication", ("MP4 InitialObjectDescriptor audioProfileLevelIndication " + Mpeg4_Descriptors_AudioProfileLevelString(ProfileLevel) + " does not permit that the usacElementType sequence starts with SCE CPE").c_str());
                    else
                        Fill_Conformance("UsacConfig numOutChannels", ("numOutChannels is " + to_string(C.numOutChannels) + ", it is not recommended that the usacElementType sequence contains " + to_string(ChannelCount) + " channels, especially when only one channel of a CPE is included in numOutChannels").c_str(), bitset8(), Warning);
                }
                else
                    Fill_Conformance("UsacConfig numOutChannels", ("numOutChannels is " + to_string(C.numOutChannels) + ", it is not recommended that the usacElementType sequence contains " + to_string(ChannelCount) + " channels").c_str(), bitset8(), Warning);
            }
            if (ChannelCount == C.numOutChannels)
            {
                auto C_ChannelCount_NonLfe = C.numOutChannels - C.numOutChannels_Lfe.size();
                if (ChannelCount_NonLfe != C_ChannelCount_NonLfe && Channels_Lfe.size() == C.numOutChannels_Lfe.size())
                    Fill_Conformance("UsacConfig numOutChannels", ("numOutChannels minus LFE channel count is " + to_string(C_ChannelCount_NonLfe) + " but the usacElementType sequence contains " + to_string(ChannelCount_NonLfe) + " non LFE channels").c_str());
                if (Channels_Lfe.size() != C.numOutChannels_Lfe.size())
                    Fill_Conformance("UsacConfig numOutChannels", ("non LFE channel count is " + to_string(C_ChannelCount_NonLfe) + " and LFE channel count is " + to_string(C.numOutChannels_Lfe.size()) + " but the usacElementType sequence contains " + to_string(ChannelCount_NonLfe) + " non LFE channels and " + to_string(Channels_Lfe.size()) + " LFE channels").c_str());
            }
            if (Channels_Lfe.size() > C.numOutChannels_Lfe.size())
                Channels_Lfe.resize(C.numOutChannels_Lfe.size());
            if (C.numOutChannels_Lfe.size() > Channels_Lfe.size())
                C.numOutChannels_Lfe.resize(Channels_Lfe.size());
            for (size_t i = C.numOutChannels_Lfe.size() - 1; (int)i >= 0; i--)
            {
                auto Lfe = C.numOutChannels_Lfe[i];
                for (size_t j = Channels_Lfe.size() - 1; (int)j >= 0; j--)
                    if (Channels_Lfe[j] == Lfe)
                    {
                        C.numOutChannels_Lfe.erase(C.numOutChannels_Lfe.begin() + j);
                        Channels_Lfe.erase(Channels_Lfe.begin() + i);
                    }
            }
            for (size_t i = C.numOutChannels_Lfe.size() - 1; (int)i >= 0; i--)
                Fill_Conformance("UsacConfig numOutChannels", ("LFE channel is expected at position " + to_string(C.numOutChannels_Lfe[i]) + " but the usacElementType sequence contains a LFE channel at position " + to_string(Channels_Lfe[i])).c_str());
        }
        if (C.channelConfigurationIndex >= Aac_Channels_Size_Usac)
        {
            channelConfiguration_Orders_Max = 0;
            for (int8u i = 0; i < Aac_Channels_Size_Usac; i++)
            {
                auto IsNotMatch = false;
                channelConfiguration_Orders_Pos = channelConfiguration_Orders_Max;
                channelConfiguration_Orders_Max = channelConfiguration_Orders[i];
                auto channelConfiguration_Orders_Base = channelConfiguration_Orders + Aac_Channels_Size_Usac;
                for (auto& usacElement : C.usacElements)
                {
                    if (usacElement.usacElementType >= ID_USAC_EXT)
                        continue;
                    if (channelConfiguration_Orders_Pos == channelConfiguration_Orders_Max || usacElement.usacElementType != channelConfiguration_Orders_Base[channelConfiguration_Orders_Pos])
                        IsNotMatch = true;
                    else
                        channelConfiguration_Orders_Pos++;
                }
                if (!IsNotMatch)
                {
                    string ActualOrder;
                    for (auto& usacElement : C.usacElements)
                    {
                        if (usacElement.usacElementType >= ID_USAC_EXT)
                            continue;
                        ActualOrder += usacElementType_IdNames[usacElement.usacElementType];
                        ActualOrder += ' ';
                    }
                    if (!ActualOrder.empty()) ActualOrder.pop_back();
                    Fill_Conformance("UsacConfig channelConfigurationIndex", ("channelConfigurationIndex " + to_string(C.channelConfigurationIndex) + " is used but the usacElementType sequence contains " + ActualOrder + ", which is the configuration indicated by channelConfigurationIndex " + to_string(i)).c_str(), bitset8(), Warning);
                    break;
                }
            }
        }
        else if (CheckChannelConfiguration == 2)
        {
            channelConfiguration_Orders_Pos = channelConfiguration_Orders[C.channelConfigurationIndex - 1];
            channelConfiguration_Orders_Max = channelConfiguration_Orders[C.channelConfigurationIndex];
            string ExpectedOrder;
            auto channelConfiguration_Orders_Base = channelConfiguration_Orders + Aac_Channels_Size_Usac;
            for (; channelConfiguration_Orders_Pos < channelConfiguration_Orders_Max; channelConfiguration_Orders_Pos++)
            {
                ExpectedOrder += usacElementType_IdNames[channelConfiguration_Orders_Base[channelConfiguration_Orders_Pos]];
                ExpectedOrder += ' ';
            }
            if (!ExpectedOrder.empty()) ExpectedOrder.pop_back();
            string ActualOrder;
            for (auto& usacElement : C.usacElements)
            {
                if (usacElement.usacElementType >= ID_USAC_EXT)
                    continue;
                ActualOrder += usacElementType_IdNames[usacElement.usacElementType];
                ActualOrder += ' ';
            }
            if (!ActualOrder.empty()) ActualOrder.pop_back();
            Fill_Conformance("UsacConfig channelConfigurationIndex", ("channelConfigurationIndex " + to_string(C.channelConfigurationIndex) + " implies element order " + ExpectedOrder + " but actual element order is " + ActualOrder).c_str());
        }
    #endif

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::UsacSingleChannelElementConfig()
{
    Element_Begin1("UsacSingleChannelElementConfig");

    UsacCoreConfig();
    if (C.coreSbrFrameLengthIndex>=coreSbrFrameLengthIndex_Mapping_Size || coreSbrFrameLengthIndex_Mapping[C.coreSbrFrameLengthIndex].sbrRatioIndex)
        SbrConfig();

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::UsacChannelPairElementConfig()
{
    Element_Begin1("UsacChannelPairElementConfig");
    C.stereoConfigIndex=0;

    UsacCoreConfig();
    if (C.coreSbrFrameLengthIndex>=coreSbrFrameLengthIndex_Mapping_Size || coreSbrFrameLengthIndex_Mapping[C.coreSbrFrameLengthIndex].sbrRatioIndex)
    {
        SbrConfig();
        Get_S1(2, C.stereoConfigIndex,                           "stereoConfigIndex");
        if (C.stereoConfigIndex)
            Mps212Config(C.stereoConfigIndex);
    }

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::UsacLfeElementConfig()
{
    // Nothing here
}

//---------------------------------------------------------------------------
void File_Usac::UsacExtElementConfig()
{
    Element_Begin1("UsacExtElementConfig");

    int32u usacExtElementType, usacExtElementConfigLength;
    bool usacExtElementDefaultLengthPresent, usacExtElementPayloadFrag;
    escapedValue(usacExtElementType, 4, 8, 16,                  "usacExtElementType"); Element_Level--; Element_Info1C(usacExtElementType<ID_EXT_ELE_Max, usacExtElementType_IdNames[usacExtElementType]); Element_Level++;
    C.usacElements.back().usacElementType+=usacExtElementType<<2;
    #if MEDIAINFO_CONFORMANCE
        if (usacExtElementType_Present.find(usacExtElementType) != usacExtElementType_Present.end() && usacExtElementType < ID_EXT_ELE_Max && usacExtElementType_ConfigNames[usacExtElementType])
        {
            auto FieldName = string(usacExtElementType_ConfigNames[usacExtElementType]);
            Fill_Conformance("UsacExtElementConfig GeneralCompliance", (FieldName + " is present 2 times but only 1 instance is recommended").c_str(), bitset8(), Warning);
        }
        else
        {
            usacExtElementType_Present.insert(usacExtElementType);
            if (usacExtElementType == ID_EXT_ELE_AUDIOPREROLL && C.usacElements.size() != 1)
                Fill_Conformance("UsacExtElementConfig GeneralCompliance", ("AudioPreRoll is present in position "+to_string(C.usacElements.size()-1)+" but only presence in position 0 is allowed").c_str());
        }
    #endif
    escapedValue(usacExtElementConfigLength, 4, 8, 16,          "usacExtElementConfigLength");
    #if MEDIAINFO_CONFORMANCE
        if (usacExtElementType == ID_EXT_ELE_AUDIOPREROLL && usacExtElementConfigLength)
            Fill_Conformance("UsacExtElementConfig usacExtElementConfigLength", ("AudioPreRoll usacExtElementConfigLength is "+to_string(usacExtElementConfigLength)+" but only 0 is allowed").c_str());
    #endif
    Get_SB (usacExtElementDefaultLengthPresent,                 "usacExtElementDefaultLengthPresent");
    if (usacExtElementDefaultLengthPresent)
    {
        #if MEDIAINFO_CONFORMANCE
            if (usacExtElementType == ID_EXT_ELE_AUDIOPREROLL)
                Fill_Conformance("UsacExtElementConfig usacExtElementDefaultLengthPresent", "AudioPreRoll usacExtElementDefaultLengthPresent is 1 but only 0 is allowed");
        #endif
        int32u usacExtElementDefaultLength;
        escapedValue(usacExtElementDefaultLength, 8, 16, 0,     "usacExtElementDefaultLength");
        C.usacElements.back().usacExtElementDefaultLength=usacExtElementDefaultLength+1;
    }
    else
        C.usacElements.back().usacExtElementDefaultLength=0;
    Get_SB (usacExtElementPayloadFrag,                          "usacExtElementPayloadFlag");
    #if MEDIAINFO_CONFORMANCE
        if (usacExtElementType == ID_EXT_ELE_AUDIOPREROLL && usacExtElementPayloadFrag)
            Fill_Conformance("UsacExtElementConfig usacExtElementPayloadFrag", "AudioPreRoll usacExtElementPayloadFrag is 1 but only 0 is allowed");
    #endif
    C.usacElements.back().usacExtElementPayloadFrag=usacExtElementPayloadFrag;

    if (usacExtElementConfigLength)
    {
        usacExtElementConfigLength*=8;
        if (usacExtElementConfigLength>Data_BS_Remain())
        {
            Trusted_IsNot("Too big");
            Element_End0();
            return;
        }
        auto B=BS_Bookmark(usacExtElementConfigLength);
        switch (usacExtElementType)
        {
            case ID_EXT_ELE_FILL                              : break;
            case ID_EXT_ELE_UNI_DRC                           : uniDrcConfig(); break;
            case ID_EXT_ELE_AUDIOPREROLL                      :
            default                                           : if (usacExtElementConfigLength)
                                                                    Skip_BS(usacExtElementConfigLength, "Unknown");
        }
        BS_Bookmark(B, (usacExtElementType<ID_EXT_ELE_Max?string(usacExtElementType_Names[usacExtElementType]):("usacExtElementType"+to_string(usacExtElementType)))+"Config");
    }

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::UsacCoreConfig()
{
    Element_Begin1("UsacCoreConfig");

    Get_SB (C.tw_mdct,                                          "tw_mdct");
    Get_SB (C.noiseFilling,                                     "noiseFilling");

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::SbrConfig()
{
    Element_Begin1("SbrConfig");

    Get_SB (C.harmonicSBR,                                      "harmonicSBR");
    Get_SB (C.bs_interTes,                                      "bs_interTes");
    Get_SB(C.bs_pvc,                                            "bs_pvc");
    SbrDlftHeader();

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::SbrDlftHeader()
{
    Element_Begin1("SbrDlftHeader");

    bool dflt_header_extra2;
    Get_S1 (4, C.dlftHandler.dflt_start_freq,                   "dflt_start_freq");
    Get_S1 (4, C.dlftHandler.dflt_stop_freq,                    "dflt_stop_freq");
    Get_SB (   C.dlftHandler.dflt_header_extra1,                "dflt_header_extra1");
    Get_SB (   dflt_header_extra2,                              "dflt_header_extra2");
    if (C.dlftHandler.dflt_header_extra1)
    {
        Get_S1 (2, C.dlftHandler.dflt_freq_scale,               "dflt_freq_scale");
        Get_SB (   C.dlftHandler.dflt_alter_scale,              "dflt_alter_scale");
        Get_S1 (2, C.dlftHandler.dflt_noise_bands,              "dflt_noise_bands");
    }
    else
    {
        C.dlftHandler.dflt_freq_scale=2;
        C.dlftHandler.dflt_alter_scale=1;
        C.dlftHandler.dflt_noise_bands=2;
    }
    if (dflt_header_extra2)
    {
        Skip_S1(2,                                              "dflt_limiter_bands");
        Skip_S1(2,                                              "dflt_limiter_gains");
        Skip_SB(                                                "dflt_interpol_freq");
        Skip_SB(                                                "dflt_smoothing_mode");
    }

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::Mps212Config(int8u StereoConfigindex)
{
    Element_Begin1("Mps212Config");

    int8u bsFreqRes; 
    Get_S1 (3, bsFreqRes,                                       "bsFreqRes");
    C.mps212Handler.numBands=freq_res[bsFreqRes]; //TODO: freq_res_ld???

    Skip_S1(3,                                                  "bsFixedGainDMX");
    Get_S1 (2, C.mps212Handler.bsTempShapeConfig,               "bsTempShapeConfig");
    Skip_S1(2,                                                  "bsDecorrConfig");
    Get_SB (C.mps212Handler.bsHighRatelMode,                    "bsHighRatelMode");
    Get_SB (C.mps212Handler.bsPhaseCoding,                      "bsPhaseCoding");
    TESTELSE_SB_SKIP (                                          "bsOttBandsPhasePresent");
        Get_S1 (5, C.mps212Handler.bsOttBandsPhase,             "bsOttBandsPhase");
    TESTELSE_SB_ELSE(                                           "bsOttBandsPhasePresent");
        switch (C.mps212Handler.numBands)
        {
        case 4:
        case 5:
            C.mps212Handler.bsOttBandsPhase=2;
            break;
        case 7:
            C.mps212Handler.bsOttBandsPhase=3;
            break;
        case 10:
            C.mps212Handler.bsOttBandsPhase=5;
            break;
        case 14:
            C.mps212Handler.bsOttBandsPhase=7;
            break;
        case 20:
        case 28:
            C.mps212Handler.bsOttBandsPhase=10;
            break;
        default:
            #if MEDIAINFO_CONFORMANCE
                Fill_Conformance("Mps212Config bsFreqRes", "bsFreqRes shall not be encoded with a value of 0");
            #endif
            C.IFrameParsed=false;
            Element_End0();
            return;
        }
    TESTELSE_SB_END();
    if (StereoConfigindex>1)
    {
        int8u bsResidualBands;
        Get_S1(5, bsResidualBands,                              "bsResidualBands");
        if (C.mps212Handler.bsOttBandsPhase<bsResidualBands)
            C.mps212Handler.bsOttBandsPhase=bsResidualBands;

        Skip_SB(                                                "bSPseudor");
    }
    if (C.mps212Handler.bsTempShapeConfig==2)
    {
        Skip_SB(                                                "bSEnvQuantMode");
    }

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::uniDrcConfig()
{
    C.downmixInstructions_Data.clear();
    C.drcInstructionsUniDrc_Data.clear();
    C.loudnessInfo_Data[0].clear();
    C.loudnessInfo_Data[1].clear();

    Element_Begin1("uniDrcConfig");

    int8u downmixInstructionsCount, drcCoefficientsBasicCount, drcInstructionsBasicCount, drcCoefficientsUniDrcCount, drcInstructionsUniDrcCount;
    TEST_SB_SKIP(                                               "sampleRatePresent");
        int32u bsSampleRate;
        Get_S3 (18, bsSampleRate ,                              "bsSampleRate"); bsSampleRate+=1000; Param_Info2(bsSampleRate, " Hz");
        #if MEDIAINFO_CONFORMANCE
            if (C.sampling_frequency && bsSampleRate != C.sampling_frequency)
                Fill_Conformance("Crosscheck UsacConfig usacSamplingFrequency", ("USAC UsacConfig usacSamplingFrequency " + to_string(C.sampling_frequency) + " does not match DRC uniDrcConfig bsSampleRate " + to_string(bsSampleRate)).c_str());
        #endif
    TEST_SB_END();
    Get_S1 (7, downmixInstructionsCount,                        "downmixInstructionsCount");
    TESTELSE_SB_SKIP(                                           "drcDescriptionBasicPresent");
        Get_S1 (3, drcCoefficientsBasicCount,                   "drcCoefficientsBasicCount");
        Get_S1 (4, drcInstructionsBasicCount,                   "drcInstructionsBasicCount");
    TESTELSE_SB_ELSE(                                           "drcDescriptionBasicPresent");
        drcCoefficientsBasicCount=0;
        drcInstructionsBasicCount=0;
    TESTELSE_SB_END();
    Get_S1 (3, drcCoefficientsUniDrcCount,                      "drcCoefficientsUniDrcCount");
    Get_S1 (6, drcInstructionsUniDrcCount,                      "drcInstructionsUniDrcCount");
    #if MEDIAINFO_CONFORMANCE
        if (downmixInstructionsCount)
            Fill_Conformance("uniDrcConfig downmixInstructionsCount", "Version 0 shall not be used");
        if (drcCoefficientsBasicCount)
            Fill_Conformance("uniDrcConfig drcCoefficientsBasicCount", "Version 0 shall not be used");
        if (drcInstructionsBasicCount)
            Fill_Conformance("uniDrcConfig drcInstructionsBasicCount", "Version 0 shall not be used");
        if (drcCoefficientsUniDrcCount)
            Fill_Conformance("uniDrcConfig drcCoefficientsUniDrcCount", "Version 0 shall not be used");
        if (drcInstructionsUniDrcCount)
            Fill_Conformance("uniDrcConfig drcInstructionsUniDrcCount", "Version 0 shall not be used");
    #endif
    channelLayout();
    for (int8u i=0; i<downmixInstructionsCount; i++)
        downmixInstructions();
    for (int8u i=0; i<drcCoefficientsBasicCount; i++)
        drcCoefficientsBasic();
    for (int8u i=0; i<drcInstructionsBasicCount; i++)
        drcInstructionsBasic();
    for (int8u i=0; i<drcCoefficientsUniDrcCount; i++)
        drcCoefficientsUniDrc();
    for (int8u i=0; i<drcInstructionsUniDrcCount; i++)
        drcInstructionsUniDrc();
    bool uniDrcConfigExtPresent;
    Get_SB (   uniDrcConfigExtPresent,                          "uniDrcConfigExtPresent");
    if (uniDrcConfigExtPresent)
        uniDrcConfigExtension();

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::uniDrcConfigExtension()
{
    for (;;)
    {
        Element_Begin1("uniDrcConfigExtension");
        int32u bitSize;
        int8u uniDrcConfigExtType, extSizeBits;
        Get_S1 (4, uniDrcConfigExtType,                         "uniDrcConfigExtType"); Element_Info1C(uniDrcConfigExtType<UNIDRCCONFEXT_Max, uniDrcConfigExtType_IdNames[uniDrcConfigExtType]);
        if (!uniDrcConfigExtType) // UNIDRCCONFEXT_TERM
        {
            Element_End0();
            break;
        }
        Get_S1 (4, extSizeBits,                                 "bitSizeLen");
        extSizeBits+=4;
        Get_S4 (extSizeBits, bitSize,                           "bitSize");
        bitSize++;
        if (bitSize>Data_BS_Remain())
        {
            Trusted_IsNot("Too big");
            Element_End0();
            break;
        }

        auto B=BS_Bookmark(bitSize);
        switch (uniDrcConfigExtType)
        {
            /*
            case UNIDRCCONFEXT_PARAM_DRC :
                {
                drcCoefficientsParametricDrc();
                int8u parametricDrcInstructionsCount;
                Get_S1 (4, parametricDrcInstructionsCount,      "parametricDrcInstructionsCount");
                for (int8u i=0; i<parametricDrcInstructionsCount; i++)
                    parametricDrcInstructions();
                Skip_BS(Data_BS_Remain(),                       "(Not implemented)");
                }
                break;
            */
            case UNIDRCCONFEXT_V1 :
                {
                TEST_SB_SKIP(                                   "downmixInstructionsV1Present");
                    int8u downmixInstructionsV1Count;
                    Get_S1 (7, downmixInstructionsV1Count,      "downmixInstructionsV1Count");
                    for (int8u i=0; i<downmixInstructionsV1Count; i++)
                        downmixInstructions(true);
                TEST_SB_END();
                TEST_SB_SKIP(                                   "drcCoeffsAndInstructionsUniDrcV1Present");
                    int8u drcCoefficientsUniDrcV1Count;
                    Get_S1 (3, drcCoefficientsUniDrcV1Count,    "drcCoefficientsUniDrcV1Count");
                    for (int8u i=0; i<drcCoefficientsUniDrcV1Count; i++)
                        drcCoefficientsUniDrc(true);
                    int8u drcInstructionsUniDrcV1Count;
                    Get_S1 (6, drcInstructionsUniDrcV1Count,    "drcInstructionsUniDrcV1Count");
                    #if MEDIAINFO_CONFORMANCE
                        C.drcSetEffect = 0;
                    #endif
                    for (int8u i=0; i<drcInstructionsUniDrcV1Count; i++)
                        drcInstructionsUniDrc(true);
                    #if MEDIAINFO_CONFORMANCE
                        if (C.drcSetEffect && (C.drcSetEffect & 0x27) != 0x27) // If one of the 8 first bits is set, bits (1 is LSB) 1, 2, 3, 6 must be set
                        {
                            string Value;
                            for (int8u i = 0; i < 6; i++)
                            {
                                if (!(C.drcSetEffect & (1 << i)))
                                    Fill_Conformance("drcInstructions drcSetEffect", (string(drcSetEffect_List[i]) + " isn't in at least one DRC").c_str());
                                if (i == 2)
                                    i += 2;
                            }
                        }
                    #endif
                TEST_SB_END();
                bool MustSkip=false;
                TEST_SB_SKIP(                                   "loudEqInstructionsPresent");
                    int8u loudEqInstructionsCount;
                    Get_S1 (4, loudEqInstructionsCount,         "loudEqInstructionsCount");
                    for (int8u i=0; i<loudEqInstructionsCount; i++)
                        MustSkip=true; // Not yet implemented
                    //    loudEqInstructions();
                TEST_SB_END();
                if (!MustSkip)
                TEST_SB_SKIP(                                   "eqPresent");
                    // Not yet implemented
                    //int8u eqInstructionsCount;
                    //eqCoefficients();
                    //Get_S1 (4, eqInstructionsCount,             "eqInstructionsCount");
                    //for (int8u i=0; i<eqInstructionsCount; i++)
                    //    eqInstructions();
                TEST_SB_END();
                if (Data_BS_Remain()>B.BitsNotIncluded)
                    Skip_BS(Data_BS_Remain()-B.BitsNotIncluded, "(Not implemented)");
                }
                break;
            default:
                Skip_BS(bitSize,                                "Unknown");
        }
        #pragma warning (suppress : 6385) //Visual Studio fail to detect 'uniDrcConfigExtType<UNIDRCCONFEXT_Max' check when it is inside function parameter and warns about reading invalid data
        BS_Bookmark(B, uniDrcConfigExtType<UNIDRCCONFEXT_Max?string(uniDrcConfigExtType_ConfNames[uniDrcConfigExtType]):("uniDrcConfigExtType"+to_string(uniDrcConfigExtType)));
        Element_End0();
    }
}

//---------------------------------------------------------------------------
void File_Usac::downmixInstructions(bool V1)
{
    Element_Begin1("downmixInstructionsV1");

    bool layoutSignalingPresent;
    int8u downmixId, targetChannelCount;
    Get_S1 (7, downmixId,                                       "downmixId");
    Get_S1 (7, targetChannelCount,                              "targetChannelCount");
    Skip_S1(8,                                                  "targetLayout");
    Get_SB (   layoutSignalingPresent,                          "layoutSignalingPresent");
    if (layoutSignalingPresent)
    {
        if (V1)
            Skip_S1(4,                                          "bsDownmixOffset");
        for (int8u i=0; i<targetChannelCount; i++)
            for (int8u j=0; j<C.baseChannelCount; j++)
                Skip_S1(V1?5:4,                                 V1?"bsDownmixCoefficientV1":"bsDownmixCoefficient");
    }
    C.downmixInstructions_Data[downmixId].targetChannelCount=targetChannelCount;
    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::drcCoefficientsBasic()
{
    Element_Begin1("drcCoefficientsBasic");

    Skip_S1(4,                                                  "drcLocation");
    Skip_S1(7,                                                  "drcCharacteristic");

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::drcCoefficientsUniDrc(bool V1)
{
    Element_Begin1(V1?"drcCoefficientsUniDrcV1":"drcCoefficientsUniDrc");

    bool drcFrameSizePresent;
    Skip_S1(4,                                                  "drcLocation");
    Get_SB (   drcFrameSizePresent,                             "drcFrameSizePresent");
    if (drcFrameSizePresent)
        Skip_S2(15,                                             "bsDrcFrameSize");
    if (V1)
    {
        bool drcCharacteristicLeftPresent;
        Get_SB (   drcCharacteristicLeftPresent,                "drcCharacteristicLeftPresent");
        if (drcCharacteristicLeftPresent)
        {
            int8u characteristicLeftCount;
            Get_S1 (4, characteristicLeftCount,                 "characteristicLeftCount");
            for (int8u k=0; k<characteristicLeftCount; k++)
            {
                bool characteristicFormat;
                Get_SB (   characteristicFormat,                "characteristicFormat");
                if (!characteristicFormat)
                {
                    Skip_S1(6,                                  "bsGainLeft");
                    Skip_S1(4,                                  "bsIoRatioLeft");
                    Skip_S1(4,                                  "bsExpLeft");
                    Skip_SB(                                    "flipSignLeft");
                }
                else
                {
                    int8u bsCharNodeCount;
                    Get_S1 (2, bsCharNodeCount,                 "bsCharNodeCount");
                    for (int8u n=0; n<=bsCharNodeCount; n++)
                    {
                        Skip_S1(5,                              "bsNodeLevelDelta");
                        Skip_S1(8,                              "bsNodeGain");
                    }
                }
            }
        }
        bool drcCharacteristicRightPresent;
        Get_SB (   drcCharacteristicRightPresent,               "drcCharacteristicRightPresent");
        if (drcCharacteristicLeftPresent)
        {
            int8u characteristicRightCount;
            Get_S1 (4, characteristicRightCount,                "characteristicRightCount");
            for (int8u k=0; k<characteristicRightCount; k++)
            {
                bool characteristicFormat;
                Get_SB (   characteristicFormat,                "characteristicFormat");
                if (!characteristicFormat)
                {
                    Skip_S1(6,                                  "bsGainLeft");
                    Skip_S1(4,                                  "bsIoRatioLeft");
                    Skip_S1(4,                                  "bsExpLeft");
                    Skip_SB(                                    "flipSignLeft");
                }
                else
                {
                    int8u bsCharNodeCount;
                    Get_S1 (2, bsCharNodeCount,                 "bsCharNodeCount");
                    for (int8u n=0; n<=bsCharNodeCount; n++)
                    {
                        Skip_S1(5,                              "bsNodeLevelDelta");
                        Skip_S1(8,                              "bsNodeGain");
                    }
                }
            }
        }
        bool shapeFiltersPresent;
        Get_SB (   shapeFiltersPresent,                         "shapeFiltersPresent");
        if (shapeFiltersPresent)
        {
            int8u shapeFilterCount;
            Get_S1 (4, shapeFilterCount,                        "shapeFilterCount");
            for (int8u k=0; k<shapeFilterCount; k++)
            {
                TEST_SB_SKIP(                                   "lfCutFilterPresent");
                    Skip_S1(3,                                  "lfCornerFreqIndex");
                    Skip_S1(2,                                  "lfFilterStrengthIndex");
                TEST_SB_END();
                TEST_SB_SKIP(                                   "lfBoostFilterPresent");
                    Skip_S1(3,                                  "lfCornerFreqIndex");
                    Skip_S1(2,                                  "lfFilterStrengthIndex");
                TEST_SB_END();
                TEST_SB_SKIP(                                   "hfCutFilterPresent");
                    Skip_S1(3,                                  "lfCornerFreqIndex");
                    Skip_S1(2,                                  "lfFilterStrengthIndex");
                TEST_SB_END();
                TEST_SB_SKIP(                                   "hfBoostFilterPresent");
                    Skip_S1(3,                                  "lfCornerFreqIndex");
                    Skip_S1(2,                                  "lfFilterStrengthIndex");
                TEST_SB_END();
            }
        }
        Skip_S1(6,                                              "gainSequenceCount");
    }
    int8u gainSetCount;
    Get_S1 (6, gainSetCount,                                    "gainSetCount");
    C.gainSets.clear();
    for (int8u i=0; i<gainSetCount; i++)
    {
        Element_Begin1("gainSet");
        gain_set gainSet;
        int8u gainCodingProfile;
        Get_S1 (2, gainCodingProfile,                           "gainCodingProfile");
        Skip_SB(                                                "gainInterpolationType");
        Skip_SB(                                                "fullFrame");
        Skip_SB(                                                "timeAlignment");
        TEST_SB_SKIP(                                           "timeDeltaMinPresent");
            Skip_S2(11,                                         "bsTimeDeltaMin");
        TEST_SB_END();
        if (gainCodingProfile != 3)
        {
            bool drcBandType;
            Get_S1 (4, gainSet.bandCount,                       "bandCount");
            if (gainSet.bandCount>1)
                Get_SB (drcBandType,                            "drcBandType");
            for (int8u i=0; i<gainSet.bandCount; i++)
            {
                Element_Begin1("bandCount");
                if (V1)
                {
                    TEST_SB_SKIP(                               "indexPresent");
                        Skip_S1(6,                              "bsIndex");
                    TEST_SB_END();
                }
                if (!V1)
                {
                    Skip_S1(7,                                  "drcCharacteristic");
                }
                else //V1
                {
                    TEST_SB_SKIP(                               "drcCharacteristicPresent");
                        bool drcCharacteristicFormatIsCICP;
                        Get_SB (drcCharacteristicFormatIsCICP,  "drcCharacteristicFormatIsCICP");
                        if (drcCharacteristicFormatIsCICP)
                        {
                            Skip_S1(7,                          "drcCharacteristic");
                        }
                        else
                        {
                            Skip_S1(4,                          "drcCharacteristicLeftIndex");
                            Skip_S1(4,                          "drcCharacteristicRightIndex");
                        }
                    TEST_SB_END();
                }
                Element_End0();
            }
            for (int8u i=1; i <gainSet.bandCount; i++)
            {
                if (drcBandType)
                    Skip_S1( 4,                                 "crossoverFreqIndex");
                else
                    Skip_S2(10,                                 "startSubBandIndex");
            }
        }
        else
            gainSet.bandCount=1;
        C.gainSets.push_back(gainSet);
        Element_End0();
    }

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::drcInstructionsBasic()
{
    Element_Begin1("drcInstructionsBasic");

    int16u drcSetEffect;
    Skip_S1(6,                                                  "drcSetId");
    Skip_S1(4,                                                  "drcLocation");
    Skip_S1(7,                                                  "downmixId");
    TEST_SB_SKIP(                                               "additionalDownmixIdPresent");
        int8u additionalDownmixIdCount;
        Get_S1 (3, additionalDownmixIdCount,                    "additionalDownmixIdCount");
        for (int8u i=1; i <additionalDownmixIdCount; i++)
            Skip_S1(7,                                          "additionalDownmixId");
    TEST_SB_END();
    Get_S2 (16, drcSetEffect,                                   "drcSetEffect");
    if ((drcSetEffect & (3<<10)) == 0)
    {
        TEST_SB_SKIP(                                           "limiterPeakTargetPresent");
            Skip_S1(8,                                          "bsLimiterPeakTarget");
        TEST_SB_END();
    }
    TEST_SB_SKIP(                                               "drcSetTargetLoudnessPresent");
        Skip_S1(6,                                              "bsDrcSetTargetLoudnessValueUpper");
        TEST_SB_SKIP(                                           "drcSetTargetLoudnessValueLowerPresent");
            Skip_S1(6,                                          "bsDrcSetTargetLoudnessValueLower");
        TEST_SB_END();
    TEST_SB_END();

    Element_End0();
}

//---------------------------------------------------------------------------
bool File_Usac::drcInstructionsUniDrc(bool V1, bool NoV0)
{
    Element_Begin1(V1?"drcInstructionsUniDrcV1":"drcInstructionsUniDrc");

    int8u channelCount=C.baseChannelCount;
    vector<int8s> gainSetIndex;
    int16u drcSetEffect;
    int8u drcSetId, downmixId;
    bool downmixIdPresent;
    Get_S1 (6, drcSetId,                                        "drcSetId");
    if (V1)
        Skip_S1(4,                                              "drcSetComplexityLevel");
    Skip_S1(4,                                                  "drcLocation");
    if (V1)
        Get_SB (downmixIdPresent,                               "downmixIdPresent");
    else
        downmixIdPresent=true;
    if (downmixIdPresent)
    {
        bool drcApplyToDownmix;
        Get_S1(7, downmixId,                                    "downmixId");
        if (V1)
            Get_SB (   drcApplyToDownmix,                       "drcApplyToDownmix");
        else
            drcApplyToDownmix=downmixId?true:false;
        int8u additionalDownmixIdCount;
        TESTELSE_SB_SKIP(                                       "additionalDownmixIdPresent");
            Get_S1 (3, additionalDownmixIdCount,                "additionalDownmixIdCount");
            for (int8u i=0; i<additionalDownmixIdCount; i++)
                Skip_S1(7,                                      "additionalDownmixId");
        TESTELSE_SB_ELSE(                                       "additionalDownmixIdPresent");
            additionalDownmixIdCount=0;
        TESTELSE_SB_END();
        if ((!V1 || drcApplyToDownmix) && downmixId && downmixId!=0x7F && !additionalDownmixIdCount)
        {
            std::map<int8u, downmix_instruction>::iterator downmixInstruction_Data=C.downmixInstructions_Data.find(downmixId);
            if (downmixInstruction_Data!=C.downmixInstructions_Data.end())
                channelCount=downmixInstruction_Data->second.targetChannelCount;
            else
                channelCount=1;
        }
        else if ((!V1 || drcApplyToDownmix) && (downmixId==0x7F || additionalDownmixIdCount))
            channelCount=1;
    }
    else
        downmixId=0; // 0 is default
    Get_S2 (16, drcSetEffect,                                   "drcSetEffect");
    #if MEDIAINFO_CONFORMANCE
        C.drcSetEffect |= (int8u)drcSetEffect; // We need only the 8 first bits
    #endif
    bool IsNOK=false;
    if ((drcSetEffect & (3<<10)) == 0)
    {
        TESTELSE_SB_SKIP(                                       "limiterPeakTargetPresent");
            Skip_S1(8,                                          "bsLimiterPeakTarget");
        TESTELSE_SB_ELSE(                                       "limiterPeakTargetPresent");
            #if MEDIAINFO_CONFORMANCE
                //Fill_Conformance("drcInstructions limiterPeakTargetPresent", "limiterPeakTargetPresent is 0", bitset8(), Warning);
            #endif
        TESTELSE_SB_END();
    }
    else
        channelCount=C.baseChannelCount; // TEMP
    TEST_SB_SKIP(                                               "drcSetTargetLoudnessPresent");
        Skip_S1(6,                                              "bsDrcSetTargetLoudnessValueUpper");
        TEST_SB_SKIP(                                           "drcSetTargetLoudnessValueLowerPresent");
            Skip_S1(6,                                          "bsDrcSetTargetLoudnessValueLower");
        TEST_SB_END();
    TEST_SB_END();
    TESTELSE_SB_SKIP(                                           "dependsOnDrcSetPresent");
        Skip_S1(6,                                              "dependsOnDrcSet");
    TESTELSE_SB_ELSE(                                           "dependsOnDrcSetPresent");
        Skip_SB(                                                "noIndependentUse");
    TESTELSE_SB_END();
    if (V1)
        Skip_SB(                                                "requiresEq");
    for (int8u c=0; c<channelCount; c++)
    {
        Element_Begin1("channel");
        int8u bsGainSetIndex;
        Get_S1 (6, bsGainSetIndex,                              "bsGainSetIndex");
        gainSetIndex.push_back(bsGainSetIndex);
        if ((drcSetEffect & (3<<10)) != 0)
        {
            TEST_SB_SKIP(                                       "duckingScalingPresent");
                Skip_S1(4,                                      "bsDuckingScaling");
            TEST_SB_END();
        }
        TEST_SB_SKIP(                                           "repeatGainSetIndex");
            int8u bsRepeatGainSetIndexCount;
            Get_S1 (5, bsRepeatGainSetIndexCount,               "bsRepeatGainSetIndexCount");
            bsRepeatGainSetIndexCount++;
            gainSetIndex.resize(gainSetIndex.size()+bsRepeatGainSetIndexCount, bsGainSetIndex);
            c+=bsRepeatGainSetIndexCount;
        TEST_SB_END();
        Element_End0();
    }

    set<int8s> DrcChannelGroups=set<int8s>(gainSetIndex.begin(), gainSetIndex.end());

    for (set<int8s>::iterator DrcChannelGroup=DrcChannelGroups.begin(); DrcChannelGroup!=DrcChannelGroups.end(); ++DrcChannelGroup)
    {
        if (!*DrcChannelGroup || (drcSetEffect & (3<<10)))
            continue; // 0 means not present
        Element_Begin1("DrcChannel");
        int8s gainSetIndex=*DrcChannelGroup-1;
        int8u bandCount=V1?(gainSetIndex<C.gainSets.size()?C.gainSets[gainSetIndex].bandCount:0):1;
        for (int8u k=0; k<bandCount; k++)
        {
            Element_Begin1("band");
            if (V1)
            {
            TEST_SB_SKIP(                                       "targetCharacteristicLeftPresent");
                Skip_S1(4,                                      "targetCharacteristicLeftIndex");
            TEST_SB_END();
            TEST_SB_SKIP(                                       "targetCharacteristicRightPresent");
                Skip_S1(4,                                      "targetCharacteristicRightIndex");
            TEST_SB_END();
            }
            TEST_SB_SKIP(                                       "gainScalingPresent");
                Skip_S1(4,                                      "bsAttenuationScaling");
                Skip_S1(4,                                      "bsAmplificationScaling");
            TEST_SB_END();
            TEST_SB_SKIP(                                       "gainOffsetPresent");
                Skip_SB(                                        "bsGainSign");
                Skip_S1(5,                                      "bsGainOffset");
            TEST_SB_END();
            Element_End0();
        }
        if (V1 && bandCount==1)
        {
            TEST_SB_SKIP(                                       "shapeFilterPresent");
                Skip_S1(4,                                      "shapeFilterIndex");
            TEST_SB_END();
        }
        Element_End0();
    }

    Element_End0();

    if (V1 || NoV0) //We want to display only V1 information
    {
        string Value;
        for (int8u i=0; i<16; i++)
            if (drcSetEffect&(1<<i))
            {
                if (!Value.empty())
                    Value+=" & ";
                if (i<drcSetEffect_List_Size)
                    Value+=drcSetEffect_List[i];
                else
                {
                    if (i>=10)
                        Value+='1';
                    Value+='0'+(i%10);
                }
            }
        drc_id Id={drcSetId, downmixId, 0};
        C.drcInstructionsUniDrc_Data[Id].drcSetEffectTotal=Value;
    }

    return false;
}

//---------------------------------------------------------------------------
void File_Usac::channelLayout()
{
    Element_Begin1("channelLayout");

    bool layoutSignalingPresent;
    Get_S1 (7, C.baseChannelCount,                              "C.baseChannelCount");
    #if MEDIAINFO_CONFORMANCE
        if (C.channelConfigurationIndex && C.channelConfigurationIndex < Aac_Channels_Size_Usac && Aac_Channels[C.channelConfigurationIndex] != C.baseChannelCount)
            Fill_Conformance("Crosscheck UsacConfig numOutChannels", ("USAC UsacConfig numOutChannels " + to_string(Aac_Channels[C.channelConfigurationIndex]) + " does not match DRC uniDrcConfig baseChannelCount " + to_string(C.baseChannelCount)).c_str());
    #endif
    Get_SB (   layoutSignalingPresent,                          "layoutSignalingPresent");
    if (layoutSignalingPresent)
    {
        int8u definedLayout;
        Get_S1 (8, definedLayout,                               "definedLayout");
        if (!definedLayout)
        {
            for (int8u i=0; i<C.baseChannelCount; i++)
            {
                Info_S1(7, speakerPosition,                     "speakerPosition"); Param_Info1(Aac_OutputChannelPosition_GetString(speakerPosition));
            }
        }
    }

    Element_End0();
}

//---------------------------------------------------------------------------
static const size_t UsacConfigExtension_usacConfigExtType_Size=8;
static const char* UsacConfigExtension_usacConfigExtType[UsacConfigExtension_usacConfigExtType_Size]=
{
    "FILL",
    NULL,
    "LOUDNESS_INFO",
    NULL,
    NULL,
    NULL,
    NULL,
    "STREAM_ID",
};
void File_Usac::UsacConfigExtension()
{
    Element_Begin1("UsacConfigExtension");

    int32u numConfigExtensions;
    escapedValue(numConfigExtensions, 2, 4, 8,                  "numConfigExtensions minus 1");

    for (int32u confExtIdx=0; confExtIdx<=numConfigExtensions; confExtIdx++) 
    {
        Element_Begin1("usacConfigExtension");
        int32u usacConfigExtType, usacConfigExtLength;
        escapedValue(usacConfigExtType, 4, 8, 16,               "usacConfigExtType"); Param_Info1C(usacConfigExtType<UsacConfigExtension_usacConfigExtType_Size && UsacConfigExtension_usacConfigExtType[usacConfigExtType], UsacConfigExtension_usacConfigExtType[usacConfigExtType]);
        escapedValue(usacConfigExtLength, 4, 8, 16,             "usacExtElementConfigLength");

        if (usacConfigExtLength)
        {
            usacConfigExtLength*=8;
            if (usacConfigExtLength>Data_BS_Remain())
            {
                Trusted_IsNot("Too big");
                Element_End0();
                break;
            }
            auto B=BS_Bookmark(usacConfigExtLength);
            switch (usacConfigExtType)
            {
                case ID_CONFIG_EXT_FILL                       : fill_bytes(usacConfigExtLength); break;
                case ID_CONFIG_EXT_LOUDNESS_INFO              : loudnessInfoSet(); break;
                case ID_CONFIG_EXT_STREAM_ID                  : streamId(); break;
                default                                       : Skip_BS(usacConfigExtLength,                "Unknown");
            }
            #pragma warning (suppress : 6385) //Visual Studio fail to detect 'usacConfigExtType<ID_CONFIG_EXT_Max' check when it is inside function parameter and warns about reading invalid data
            if (BS_Bookmark(B, usacConfigExtType<ID_CONFIG_EXT_Max?string(usacConfigExtType_ConfNames[usacConfigExtType]):("usacConfigExtType"+to_string(usacConfigExtType))))
            {
                #if MEDIAINFO_CONFORMANCE
                    if (usacConfigExtType==ID_CONFIG_EXT_LOUDNESS_INFO)
                        C.LoudnessInfoIsNotValid=true;
                #endif
            }
        }
        Element_End0();
    }

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::fill_bytes(size_t usacConfigExtLength)
{
    #if MEDIAINFO_CONFORMANCE
        Element_Begin1("fill_bytes");
        map<int8u, size_t> fill_bytes;
        for (; usacConfigExtLength; usacConfigExtLength -= 8)
        {
            int8u fill_byte;
            Get_S1 (8, fill_byte,                               "fill_byte");
            if (fill_byte != 0b10100101)
                fill_bytes[fill_byte]++;
        }
        if (!fill_bytes.empty())
            Fill_Conformance("UsacConfigExtension fill_byte", "fill_byte is "+(fill_bytes.size()==1?("0b"+Ztring::ToZtring(fill_bytes.begin()->first, 2).To_UTF8()):"with different values")+" but only 0b10100101 is expected", bitset8(), Warning);
        Element_End0();
    #else
        Skip_BS(usacConfigExtLength,                            "0b10100101");
    #endif
}

//---------------------------------------------------------------------------
void File_Usac::loudnessInfoSet(bool V1)
{
    Element_Begin1(V1?"loudnessInfoSetV1":"loudnessInfoSet");

    #if MEDIAINFO_CONFORMANCE
        C.loudnessInfoSet_Present[V1]++;
    #endif

    int8u loudnessInfoAlbumCount, loudnessInfoCount;
    bool loudnessInfoSetExtPresent;
    Get_S1 (6, loudnessInfoAlbumCount,                          "loudnessInfoAlbumCount");
    Get_S1 (6, loudnessInfoCount,                               "loudnessInfoCount");
    #if MEDIAINFO_CONFORMANCE
        if (loudnessInfoAlbumCount || loudnessInfoCount)
            C.loudnessInfoSet_HasContent[V1]=true;
    #endif

    for (int8u i=0; i<loudnessInfoAlbumCount; i++)
        loudnessInfo(true, V1);
    for (int8u i=0; i<loudnessInfoCount; i++)
        loudnessInfo(false, V1);
    if (!V1)
    {
        Get_SB (loudnessInfoSetExtPresent,                      "loudnessInfoSetExtPresent");
        if (loudnessInfoSetExtPresent)
            loudnessInfoSetExtension();
    }

    Element_End0();
}

//---------------------------------------------------------------------------
static const size_t methodDefinition_Format_Size=10;
static const int8u methodDefinition_Format[methodDefinition_Format_Size]=
{
    8, 8, 8, 8, 8, 8, 8, 5, 2, 8,
};
bool File_Usac::loudnessInfo(bool FromAlbum, bool V1)
{
    Element_Begin1(V1?"loudnessInfoV1":"loudnessInfo");

    loudness_info::measurements Measurements;
    int16u bsSamplePeakLevel, bsTruePeakLevel;
    int8u measurementCount;
    bool samplePeakLevelPresent, truePeakLevelPresent;
    int8u drcSetId, eqSetId, downmixId;
    Get_S1 (6, drcSetId,                                        "drcSetId");
    if (V1)
        Get_S1 (6, eqSetId,                                     "eqSetId");
    else
        eqSetId=0;
    Get_S1 (7, downmixId,                                       "downmixId");
    Get_SB (samplePeakLevelPresent,                             "samplePeakLevelPresent");
    if (samplePeakLevelPresent)
    {
        Get_S2(12, bsSamplePeakLevel,                           "bsSamplePeakLevel"); Param_Info1C(bsSamplePeakLevel, Ztring::ToZtring(20-((double)bsSamplePeakLevel)/32)+__T(" dBTP"));
    }
    Get_SB (truePeakLevelPresent,                               "truePeakLevelPresent");
    if (truePeakLevelPresent)
    {
        int8u measurementSystem, reliability;
        Get_S2 (12, bsTruePeakLevel,                            "bsTruePeakLevel"); Param_Info1C(bsTruePeakLevel, Ztring::ToZtring(20-((double)bsTruePeakLevel)/32)+__T(" dBTP"));
        Get_S1 ( 4, measurementSystem,                          "measurementSystem"); Param_Info1C(measurementSystem<measurementSystems_Size, measurementSystems[measurementSystem]);
        Get_S1 ( 2, reliability,                                "reliability"); Param_Info1(reliabilities[reliability]);
            #if MEDIAINFO_CONFORMANCE
            if (measurementSystem == 4)
                Fill_Conformance("loudnessInfo measurementSystem", ("measurementSystem " + to_string(measurementSystem) + (measurementSystem < measurementSystems_Size ? (string(" (") + measurementSystems[measurementSystem] + ')') : string()) + " is known as reserved in ISO/IEC 23003-3:2020").c_str(), bitset8(), Warning);
            if (reliability == 1)
                Fill_Conformance("loudnessInfo reliability", (to_string(reliability) + " (" + reliabilities[reliability] + ") is known as reserved in ISO/IEC 23003-3:2020").c_str(), bitset8(), Warning);
        #endif
    }
    #if MEDIAINFO_CONFORMANCE
        if (!drcSetId && !samplePeakLevelPresent && !truePeakLevelPresent)
            Fill_Conformance("loudnessInfo GeneralCompliance", "None of samplePeakLevelPresent or truePeakLevelPresent is present", bitset8().set(Usac), Warning);
    #endif
    Get_S1 (4, measurementCount,                                "measurementCount");
    bool IsNOK=false;
    #if MEDIAINFO_CONFORMANCE
        set<measurement_present> Measurements_Present;
    #endif
    for (int8u i=0; i<measurementCount; i++)
    {
        Element_Begin1("measurement");
        int8u methodDefinition, methodValue, measurementSystem, reliability;
        Get_S1 (4, methodDefinition,                            "methodDefinition"); Param_Info1C(methodDefinition && methodDefinition<=LoudnessMeaning_Size, LoudnessMeaning[methodDefinition-1]);
        int8u Size;
        if (methodDefinition>=methodDefinition_Format_Size)
        {
            Param_Info1("(Unsupported)");
            Measurements.Values[methodDefinition].From_UTF8("(Unsupported)");
            IsNOK=true;
            Element_End0();
            break;
        }
        Get_S1 (methodDefinition_Format[methodDefinition], methodValue, "methodValue");
        Ztring measurement=Loudness_Value(methodDefinition, methodValue);
        Param_Info1(measurement);
        Get_S1 (4, measurementSystem,                           "measurementSystem"); Param_Info1C(measurementSystem<measurementSystems_Size, measurementSystems[measurementSystem]);
        Get_S1 (2, reliability,                                 "reliability"); Param_Info1(reliabilities[reliability]);
        #if MEDIAINFO_CONFORMANCE
            if (measurementSystem >= 7 && measurementSystem <= 11) // || measurementSystem == 4
                Fill_Conformance("loudnessInfo measurementSystem", ("measurementSystem " + to_string(measurementSystem) + (measurementSystem < measurementSystems_Size ? (string(" (") + measurementSystems[measurementSystem] + ')') : string()) + " is known as reserved in ISO/IEC 23003-3:2020").c_str(), bitset8(), Warning);
            //if (reliability == 1)
            //    Fill_Conformance("loudnessInfo reliability", (to_string(reliability) + " (" + reliabilities[reliability] + ") is incorrect").c_str(), bitset8(), Warning);
            measurement_present Measurement_Present = { methodDefinition, measurementSystem };
            if (Measurements_Present.find(Measurement_Present) != Measurements_Present.end())
            {
                string Field = "methodDefinition-measurementSystem " + to_string(methodDefinition) + '-' + to_string(measurementSystem);
                if ((methodDefinition && methodDefinition <= LoudnessMeaning_Size) || measurementSystem < measurementSystems_Size)
                {
                    Field += " (";
                    if (methodDefinition && methodDefinition <= LoudnessMeaning_Size)
                        Field += LoudnessMeaning[methodDefinition - 1];
                    else
                        Field += to_string(methodDefinition);
                    Field += ", ";
                    if (measurementSystem < measurementSystems_Size)
                        Field += measurementSystems[measurementSystem];
                    else
                        Field += to_string(measurementSystem);
                    Field += ')';
                }
                Fill_Conformance("loudnessInfo methodDefinition", (Field + " is present 2 times but only 1 instance is recommended").c_str(), bitset8(), Warning);
            }
            else
                Measurements_Present.insert(Measurement_Present);
        #endif

        if (methodDefinition)
        {
            Ztring& Content=Measurements.Values[methodDefinition];
            if (!Content.empty())
                Content+=__T(" & ");
            Content+=measurement;
        }
        Element_End0();
    }

    drc_id Id={drcSetId, downmixId, eqSetId};
    #if MEDIAINFO_CONFORMANCE
        if (C.loudnessInfo_Data[FromAlbum].find(Id) != C.loudnessInfo_Data[FromAlbum].end())
            Fill_Conformance("loudnessInfo GeneralCompliance", ((Id.empty() ? string("Default loudness") : Id.to_string()) + " is present 2 times but only 1 instance is recommended").c_str(), bitset8(), Warning);
    #endif
    C.loudnessInfo_Data[FromAlbum][Id].SamplePeakLevel=((samplePeakLevelPresent && bsSamplePeakLevel)?(Ztring::ToZtring(20-((double)bsSamplePeakLevel)/32)+__T(" dBFS")):Ztring());
    C.loudnessInfo_Data[FromAlbum][Id].TruePeakLevel=((truePeakLevelPresent && bsTruePeakLevel)?(Ztring::ToZtring(20-((double)bsTruePeakLevel)/32)+__T(" dBTP")):Ztring());
    C.loudnessInfo_Data[FromAlbum][Id].Measurements=Measurements;
    Element_End0();

    return IsNOK;
}

//---------------------------------------------------------------------------
void File_Usac::loudnessInfoSetExtension()
{
    for (;;)
    {
        Element_Begin1("loudnessInfoSetExtension");
        int32u bitSize;
        int8u loudnessInfoSetExtType, extSizeBits;
        Get_S1 (4, loudnessInfoSetExtType,                      "loudnessInfoSetExtType"); Element_Info1C(loudnessInfoSetExtType<UNIDRCLOUDEXT_Max, loudnessInfoSetExtType_IdNames[loudnessInfoSetExtType]);
        if (!loudnessInfoSetExtType) // UNIDRCLOUDEXT_TERM
        {
            Element_End0();
            break;
        }
        Get_S1 (4, extSizeBits,                                 "bitSizeLen");
        extSizeBits+=4;
        Get_S4 (extSizeBits, bitSize,                           "bitSize");
        bitSize++;
        if (bitSize>Data_BS_Remain())
        {
            Trusted_IsNot("Too big");
            Element_End0();
            break;
        }

        auto B=BS_Bookmark(bitSize);
        switch (loudnessInfoSetExtType)
        {
            case UNIDRCLOUDEXT_EQ                               : loudnessInfoSet(true); break;
            default:
                Skip_BS(bitSize,                                "Unknown");
        }
        BS_Bookmark(B, loudnessInfoSetExtType<UNIDRCLOUDEXT_Max?string(uniDrcConfigExtType_ConfNames[loudnessInfoSetExtType]):("loudnessInfoSetExtType"+to_string(loudnessInfoSetExtType)));
        Element_End0();
    }
}

//---------------------------------------------------------------------------
void File_Usac::streamId()
{
    Element_Begin1("streamId");

    int16u streamIdentifier;
    Get_S2 (16, streamIdentifier,                               "streamIdentifier");

    if (!IsParsingRaw)
        Fill(Stream_Audio, 0,  "streamIdentifier", streamIdentifier, 10, true);
    Element_End0();
}

//***************************************************************************
// Elements - USAC - Frame
//***************************************************************************
#if MEDIAINFO_TRACE || MEDIAINFO_CONFORMANCE

//---------------------------------------------------------------------------
void File_Usac::UsacFrame(size_t BitsNotIncluded)
{
    #if MEDIAINFO_CONFORMANCE
        if (roll_distance_FramePos_IsPresent && *roll_distance_FramePos_IsPresent && roll_distance_Values && roll_distance_FramePos && roll_distance_Values && !roll_distance_Values->empty())
        {
            if (find(roll_distance_FramePos->begin(), roll_distance_FramePos->end(), Frame_Count_NotParsedIncluded) != roll_distance_FramePos->end())
            {
                auto numPreRollFrames = (*roll_distance_Values)[0].roll_distance;
                if (numPreRollFrames <= 0)
                    Fill_Conformance("sgpd_prol roll_distance", "roll_distance is " + to_string(numPreRollFrames) + " but > 0 is required");
                else
                    numPreRollFrames_Check(Conf, (int32u)numPreRollFrames, "sgpd_prol roll_distance");
            }
        }
    #endif

    Element_Begin1("UsacFrame");
    Element_Info1(Frame_Count_NotParsedIncluded==(int64u)-1? Frame_Count :Frame_Count_NotParsedIncluded);
    bool usacIndependencyFlag;
    Get_SB (usacIndependencyFlag,                               "usacIndependencyFlag");
    #if MEDIAINFO_CONFORMANCE
        F.numPreRollFrames = (int32u)-1;
        if (IsParsingRaw <= 1)
        {
            if (Immediate_FramePos && roll_distance_FramePos)
            {
                auto ContainerSaysImmediate = (Immediate_FramePos_IsPresent && !*Immediate_FramePos_IsPresent) || find(Immediate_FramePos->begin(), Immediate_FramePos->end(), Frame_Count_NotParsedIncluded) != Immediate_FramePos->end();
                auto ContainerSaysNonImmediate = find(roll_distance_FramePos->begin(), roll_distance_FramePos->end(), Frame_Count_NotParsedIncluded) != roll_distance_FramePos->end();
                if (usacIndependencyFlag)
                {
                    if (!ContainerSaysImmediate && !ContainerSaysNonImmediate && roll_distance_FramePos_IsPresent && *roll_distance_FramePos_IsPresent)
                        Fill_Conformance("Crosscheck stss sample_number", "MP4 stss or MP4 sbgp does not indicate this frame is independent but USAC UsacFrame usacIndependencyFlag 1 indicates this frame is independent");
                }
                else
                {
                    if (ContainerSaysImmediate)
                        Fill_Conformance("Crosscheck stss sample_number", "MP4 stss indicates this frame is an immediate play-out frame (IPF) but USAC UsacFrame usacIndependencyFlag 0 indicates this frame is not an immediate play-out frame (IPF)");
                    if (ContainerSaysNonImmediate && roll_distance_FramePos_IsPresent && *roll_distance_FramePos_IsPresent)
                        Fill_Conformance("Crosscheck sbgp group_description_index", "MP4 sbgp indicates this frame is an independent frame (IF) but USAC UsacFrame usacIndependencyFlag 0 indicates this frame is not an independent frame (IF)");
                }
            }
            if (!Frame_Count_NotParsedIncluded && !usacIndependencyFlag)
                Fill_Conformance("Crosscheck UsacFrame usacIndependencyFlag", "This is the first frame in this stream but USAC UsacFrame usacIndependencyFlag is 0 so this frame is not decodable", bitset8(), Warning);
        }
        if (IsParsingRaw == 2) //If from AudioPreRoll() and first frame
        {
            if (!usacIndependencyFlag)
                Fill_Conformance("UsacFrame usacIndependencyFlag", "usacIndependencyFlag is 0 for first UsacFrame inside AudioPreRoll");
        }
        Merge_Conformance();
    #endif
    if (usacIndependencyFlag)
         C.IFrameParsed=usacIndependencyFlag;
    if (!IsParsingRaw)
        IsParsingRaw++;

    for (size_t elemIdx=0; elemIdx<C.usacElements.size(); elemIdx++)
    {
        if (!Trusted_Get() || (!C.IFrameParsed && (!usacIndependencyFlag || elemIdx || C.usacElements[0].usacElementType!=((ID_USAC_EXT<<2)|ID_EXT_ELE_AUDIOPREROLL))))
        {
            Skip_BS(Data_BS_Remain(),                           "Skipped due to error or non support in previous frame");
            break;
        }
        switch (C.usacElements[elemIdx].usacElementType&3)
        {
            case ID_USAC_SCE:
                UsacSingleChannelElement(usacIndependencyFlag);
                break;
            case ID_USAC_CPE:
                UsacChannelPairElement(usacIndependencyFlag);
                break;
            case ID_USAC_LFE:
                UsacLfeElement(usacIndependencyFlag);
                break;
            case ID_USAC_EXT:
                UsacExtElement(elemIdx, usacIndependencyFlag);
                break;
            default:
                ; //Not parsed
        }
        if (!C.IFrameParsed)
        {
            Skip_BS(Data_BS_Remain(),                           "Skipped due to error or non support in previous frame");
            break;
        }
    }

    if (BitsNotIncluded!=(size_t)-1)
    {
        if (Data_BS_Remain()>BitsNotIncluded)
        {
            int8u LastByte;
            auto BitsRemaining=Data_BS_Remain()-BitsNotIncluded;
            if (BitsRemaining<8)
            {
                //Peek_S1((int8u)BitsRemaining, LastByte);
                //#if MEDIAINFO_CONFORMANCE
                //    if (LastByte)
                //        Fill_Conformance((ConformanceFieldName+" GeneralCompliance").c_str(), "Padding bits are not 0, the bitstream may be malformed", bitset8(), Warning);
                //#endif
                LastByte=0;
            }
            else
            {
                #if MEDIAINFO_CONFORMANCE
                    bool IsZeroed=false;
                    if (BitsRemaining<=32) //TODO: more than 32 bits
                    {
                        int32u Probe;
                        Peek_S4(BitsRemaining, Probe);
                        IsZeroed=!Probe;
                    }
                    if (IsZeroed)
                        Fill_Conformance("UsacFrame GeneralCompliance", "Extra zero bytes after the end of the syntax was reached", bitset8(), Warning);
                    else
                        Fill_Conformance("UsacFrame GeneralCompliance", "Extra bytes after the end of the syntax was reached", bitset8(), Warning);
                #endif
                LastByte=1;
            }
            Skip_BS(BitsRemaining,                              LastByte?"Unknown":"Padding");
        }
        else if (C.IFrameParsed && Data_BS_Remain()<BitsNotIncluded)
            Trusted_IsNot("Too big");
    }
    else if (IsParsingRaw <= 1)
    {
        #if MEDIAINFO_CONFORMANCE
            if (Data_BS_Remain() >= 8)
            {
                auto Size = (Data_BS_Remain() + 7) / 8;
                auto Buffer_Temp = Buffer + (size_t)Element_Size - Size;
                size_t i = 0;
                for (; i < Size; i++)
                    if (Buffer_Temp[i])
                        break;
                if (i == Size)
                    Fill_Conformance("UsacFrame GeneralCompliance", "Extra zero bytes after the end of the syntax was reached", bitset8(), Warning);
                else
                    Fill_Conformance("UsacFrame GeneralCompliance", "Extra bytes after the end of the syntax was reached", bitset8(), Warning);
            }
        #endif
    }
    Element_End0();

    #if MEDIAINFO_CONFORMANCE
        if (IsParsingRaw <= 1 && Frame_Count_NotParsedIncluded != (int64u)-1)
        {
            if (C.coreSbrFrameLengthIndex < coreSbrFrameLengthIndex_Mapping_Size && outputFrameLength && !outputFrameLength->empty())
            {
                size_t i = 0;
                int64u outputFrameLength_FrameTotal = 0;
                for (; i < outputFrameLength->size() && Frame_Count_NotParsedIncluded >= outputFrameLength_FrameTotal; i++)
                    outputFrameLength_FrameTotal += (*outputFrameLength)[i].SampleCount;
                if (i <= outputFrameLength->size() && Frame_Count_NotParsedIncluded < outputFrameLength_FrameTotal)
                {
                    auto SampleDuration_FromContainer = (*outputFrameLength)[i - 1].SampleDuration;
                    auto SampleDuration_FromStream = ((int32u)coreSbrFrameLengthIndex_Mapping[C.coreSbrFrameLengthIndex].outputFrameLengthDivided256) * 256;
                    bool IsLastFrame = i == outputFrameLength->size() && Frame_Count_NotParsedIncluded == outputFrameLength_FrameTotal - 1;
                    if (SampleDuration_FromContainer != SampleDuration_FromStream && (!IsLastFrame || SampleDuration_FromContainer > SampleDuration_FromStream))
                        Fill_Conformance("Crosscheck stts sample_count", ("MP4 stts sample_count " + to_string(SampleDuration_FromContainer) + " does not match USAC UsacConfig coreCoderFrameLength " + to_string(SampleDuration_FromStream)).c_str());
                }
            }
            if (roll_distance_FramePos && usacIndependencyFlag)
            {
                if (!Frame_Count_NotParsedIncluded && F.numPreRollFrames == (int32u)-1)
                {
                    auto ContainerSaysNonImmediate = find(roll_distance_FramePos->begin(), roll_distance_FramePos->end(), Frame_Count_NotParsedIncluded) != roll_distance_FramePos->end();
                    if (ContainerSaysNonImmediate && (!FirstOutputtedDecodedSample || !*FirstOutputtedDecodedSample))
                    {
                        Fill_Conformance("AudioPreRoll GeneralCompliance", "This is the first frame in this stream but USAC AudioPreRoll is not present", bitset8(), Warning);
                    }
                }
                if (Immediate_FramePos)
                {
                    auto ContainerSaysImmediate = (Immediate_FramePos_IsPresent && !*Immediate_FramePos_IsPresent) || find(Immediate_FramePos->begin(), Immediate_FramePos->end(), Frame_Count_NotParsedIncluded) != Immediate_FramePos->end();
                    auto ContainerSaysNonImmediate = find(roll_distance_FramePos->begin(), roll_distance_FramePos->end(), Frame_Count_NotParsedIncluded) != roll_distance_FramePos->end();
                    if (F.numPreRollFrames != (int32u)-1)
                    {
                        //Immediate
                        if (!ContainerSaysImmediate)
                            Fill_Conformance("Crosscheck stss sample_number", "MP4 stss does not indicate this frame is an immediate play-out frame (IPF) but USAC AudioPreRoll is present");
                        if (ContainerSaysNonImmediate && roll_distance_FramePos_IsPresent && *roll_distance_FramePos_IsPresent)
                            Fill_Conformance("Crosscheck sbgp group_description_index", "MP4 sbgp indicates this frame is an independent frame (IF) but USAC AudioPreRoll is present");
                    }
                    else
                    {
                        //NonImmediate
                        if (ContainerSaysImmediate)
                            Fill_Conformance("Crosscheck stss sample_number", "MP4 stss indicates this frame is an immediate play-out frame (IPF) but USAC AudioPreRoll is not present");
                        if (!ContainerSaysNonImmediate && roll_distance_FramePos_IsPresent && *roll_distance_FramePos_IsPresent)
                            Fill_Conformance("Crosscheck sbgp group_description_index", "MP4 sbgp does not indicate this frame is an independent frame (IF) but USAC AudioPreRoll is not present");
                    }
                }
            }
        }
        Merge_Conformance();
    #endif

    if (Trusted_Get())
    {
        #if MEDIAINFO_CONFORMANCE
            if (IsParsingRaw==1)
                Merge_Conformance();
        #endif
    }
    else if (IsParsingRaw==1)
    {
        #if MEDIAINFO_CONFORMANCE
            Clear_Conformance();
            Fill_Conformance("UsacFrame GeneralCompliance", "Bitstream parsing ran out of data to read before the end of the syntax was reached, most probably the bitstream is malformed");
            Merge_Conformance();
        #endif
        C.IFrameParsed=false;

        //Counting, TODO: remove duplicate of this code due to not executed in case of parsing issue
        Frame_Count++;
        if (Frame_Count_NotParsedIncluded!=(int64u)-1)
            Frame_Count_NotParsedIncluded++;
    }
}

//---------------------------------------------------------------------------
void File_Usac::UsacSingleChannelElement(bool usacIndependencyFlag)
{
    Element_Begin1("UsacSingleChannelElement");

    UsacCoreCoderData(1, usacIndependencyFlag);
    if (!C.IFrameParsed)
    {
        Element_End0();
        return;
    }
    if (C.coreSbrFrameLengthIndex>=coreSbrFrameLengthIndex_Mapping_Size || coreSbrFrameLengthIndex_Mapping[C.coreSbrFrameLengthIndex].sbrRatioIndex)
    {
        UsacSbrData(1, usacIndependencyFlag);
        if (!C.IFrameParsed)
        {
            Element_End0();
            return;
        }
    }

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::UsacChannelPairElement(bool usacIndependencyFlag)
{
    Element_Begin1("UsacChannelPairElement");

    UsacCoreCoderData(C.stereoConfigIndex==1?1:2, usacIndependencyFlag);
    if (!C.IFrameParsed)
    {
        Element_End0();
        return;
    }
    if (C.coreSbrFrameLengthIndex>=coreSbrFrameLengthIndex_Mapping_Size || coreSbrFrameLengthIndex_Mapping[C.coreSbrFrameLengthIndex].sbrRatioIndex)
    {
        UsacSbrData((C.stereoConfigIndex==0 || C.stereoConfigIndex==3)?2:1, usacIndependencyFlag);
        if (!C.IFrameParsed)
        {
            Element_End0();
            return;
        }
    }

    if (C.stereoConfigIndex)
    {
        Mps212Data(usacIndependencyFlag);
    }

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::twData()
{
    Element_Begin1("tw_data");

    TEST_SB_SKIP(                                               "tw_data_present");
        for (int8u node=0; node<16/*NUM_TW_NODES*/; node++)
            Skip_S1(3,                                          "tw_ratio");
    TEST_SB_END();

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::icsInfo()
{
    Element_Begin1("ics_info");

    int8u window_sequence, scale_factor_grouping;
    Get_S1 (2, window_sequence,                                 "window_sequence");
    Skip_SB(                                                    "window_shape");

    if (window_sequence==2)
    {
        Get_S1 (4, max_sfb,                                     "max_sfb");
        Get_S1 (7, scale_factor_grouping,                       "scale_factor_grouping");
    }
    else
    {
        Get_S1(6, max_sfb,                                      "max_sfb");
    }
    max_sfb1=max_sfb;

    Element_End0();

    //Calculation of windows
    switch (window_sequence)
    {
        case 0 :    //ONLY_LONG_SEQUENCE
        case 1 :    //LONG_START_SEQUENCE
        case 3 :    //LONG_STOP_SEQUENCE
                    num_windows=1;
                    num_window_groups=1;
                    break;
        case 2 :    //EIGHT_SHORT_SEQUENCE
                    num_windows=8;
                    num_window_groups=1;
                    for (int8u win=0; win<num_windows-1; win++)
                    {
                        if (!(scale_factor_grouping&(1<<(6-win))))
                            num_window_groups++;
                    }
                    break;
        default:    ;
    }
}

//---------------------------------------------------------------------------
void File_Usac::scaleFactorData(size_t ch)
{
    Element_Begin1("scale_factor_data");

    #if MEDIAINFO_TRACE
        bool Trace_Activated_Save=Trace_Activated;
        Trace_Activated=false; //It is too big, disabling trace for now for full USAC parsing
    #endif //MEDIAINFO_TRACE

    for (int8u group=0; group<num_window_groups; group++)
    {
        for (int8u sfb=0; sfb<(ch?max_sfb1:max_sfb); sfb++)
        {
            if (group || sfb)
                hcod_sf(                                        "hcod_sf[dpcm_sf[g][sfb]]");
        }
    }
        #if MEDIAINFO_TRACE
            Trace_Activated=Trace_Activated_Save;
        #endif //MEDIAINFO_TRACE

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::arithData(size_t ch, int16u N, int16u lg, int16u lg_max, bool arith_reset_flag)
{
    if (lg>1024 || N>4096) // Preserve arrays boundaries
    {
        #if MEDIAINFO_CONFORMANCE
            if (lg>1024)
                Fill_Conformance("arithData GeneralCompliance", "lg is more than 1024");
            if (N>4096)
                Fill_Conformance("arithData GeneralCompliance", "N is more than 4096");
        #endif
        C.IFrameParsed=false;
        return;
    }

    if (!arith_reset_flag && C.arithContext[ch].previous_window_size==(int16u)-1)
        return; //TODO: conformance error?

    // arith_map_context
    {
        if (arith_reset_flag)
            memset(&C.arithContext[ch].q[0], 0, sizeof(C.arithContext[ch].q[0]));
        else
        {
            if (!N && lg)
            {
                #if MEDIAINFO_CONFORMANCE
                    Fill_Conformance("arithData GeneralCompliance", "N is 0");
                #endif
                C.IFrameParsed=false;
                return;
            }

            float ratio=((float)C.arithContext[ch].previous_window_size)/((float)N);
            if (ratio>1)
            {
                for (int pos=0; pos<N/4; pos++)
                    C.arithContext[ch].q[0][pos]=C.arithContext[ch].q[1][(int)((float)pos*ratio)];
            }
            else
            {
                for (int pos=N/4-1; pos>=0; pos--)
                    C.arithContext[ch].q[0][pos]=C.arithContext[ch].q[1][(int)((float)pos*ratio)];
            }

        }
        C.arithContext[ch].previous_window_size=N;
    }

    if (lg==0)
    {
        memset(&C.arithContext[ch].q[1], 1, sizeof(C.arithContext[ch].q[1]));
        return;
    }

    Element_Begin1("arithData");

    auto BS_Sav=*BS;
    int16u low=0, high=65535, value, offset;
    size_t TooMuch=0;
    if (Data_BS_Remain()>=16)
        Get_S2(16, value,                                           "initial arith_data");
    else
    {
        TooMuch=16-Data_BS_Remain();
        Get_S2(Data_BS_Remain(), value,                             "initial arith_data");
        value<<=TooMuch;
    }

    int16u context=C.arithContext[ch].q[0][0] << 12;
    int32u state=0;
    vector<int32s> x_ac_dec(lg);

    for (offset=0; offset<lg/2; offset++)
    {
        Element_Begin1(to_string(offset).c_str());
        // arith_get_context
        {
            state=context>>8;
            state=state+((offset>=lg_max/2-1?0:C.arithContext[ch].q[0][offset+1])<<8);
            state=(state<<4)+(offset?C.arithContext[ch].q[1][offset-1]:0);

            context=state;
            if (offset>3 && (C.arithContext[ch].q[1][offset-3]+C.arithContext[ch].q[1][offset-2]+C.arithContext[ch].q[1][offset-1])<5)
                state+=0x10000;
        }

        int32u lev=0, esc_nb=0, m, a, b;
        for (;;)
        {
            int16u pki=(int16u)-1;
            // arith_get_pk
            {
                size_t i_min=-1;
                size_t i_max=sizeof(arith_lookup_m)/sizeof(int16u)-1;
                size_t i=i_min;
                size_t j;
                while (i_max-i_min>1)
                {
                    i=i_min+((i_max-i_min)/2);
                    j=arith_hash_m[i];
                    if (state+(esc_nb<<17)<(j>>8))
                        i_max=i;
                    else if (state+(esc_nb<<17)>(j>>8))
                        i_min=i;
                    else
                    {
                        pki=j&0xFF;
                        break;
                    }
                }
                if (pki==(int16u)-1)
                    pki=arith_lookup_m[i_max];
            }

            Element_Begin1("acod_m");
            m=arith_decode(low, high, value, arith_cf_m[pki], sizeof(arith_cf_m[pki])/sizeof(int16u), &TooMuch);
            Element_End0();

            if (m<ARITH_ESCAPE)
                break;

            if ((esc_nb=++lev)>7)
                esc_nb=7;

            if (lev>23)
            {
                #if MEDIAINFO_CONFORMANCE
                    Fill_Conformance("arithData GeneralCompliance", "Issue detected while computing lev");
                #endif
                C.IFrameParsed=false;
                Element_End0();
                Element_End0();
                return;
            }
        }

        b=m>>2;
        a=m-(b<<2);

        if (m==0)
        {
            if (lev) // ARITH_STOP symbol detected
            {
                Element_End0();
                break;
            }

            C.arithContext[ch].q[1][offset]=((a+b+1)<=0x000F?(a+b+1):0x000F); // arith_update_context
            Element_End0();
            continue;
        }

        for (int32u l=lev; l>0; l--)
        {
            Element_Begin1("acod_l");
            int8u lsbidx=(a==0)?1:((b==0)?0:2);
            int32u r=arith_decode(low, high, value, arith_cf_r[lsbidx], sizeof(arith_cf_r[lsbidx])/sizeof(int16u), &TooMuch);

            a=(a<<1)|(r&1);
            b=(b<<1)|((r>>1)&1);
            Element_End0();
        }

        x_ac_dec[2*offset]=a;
        x_ac_dec[2*offset+1]=b;
        C.arithContext[ch].q[1][offset]=((a+b+1)<=0x000F?(a+b+1):0x000F); // arith_update_context
        Element_End0();
    }

     // arith_finish
     if (offset<sizeof(C.arithContext[ch].q[1]))
         memset(&C.arithContext[ch].q[1][offset], 1, sizeof(C.arithContext[ch].q[1])-offset);

     //Hacky way to rewind by 14
     auto BS_Diff=BS_Sav.Remain()-BS->Remain();
     size_t ToRewind=14-TooMuch;
     if (BS_Diff>=ToRewind)
         BS_Diff-=ToRewind;
     *BS=BS_Sav;
     BS->Skip(BS_Diff);

     for (int16u i=0; i<lg; i++)
     {
         if (x_ac_dec[i]!=0)
         {
             bool s;
             Get_SB (s,                                         "s"); Param_Info1(i/2);
             if (!s)
                 x_ac_dec[i]*=-1;
         }
     }

     Element_End0();
 }

//---------------------------------------------------------------------------
void File_Usac::acSpectralData(size_t ch, bool usacIndependencyFlag)
{
    Element_Begin1("ac_spectral_data");

    bool arith_reset_flag=true;
    if (!usacIndependencyFlag)
        Get_SB (arith_reset_flag,                               "arith_reset_flag");

    #if MEDIAINFO_TRACE
        bool Trace_Activated_Save=Trace_Activated;
        Trace_Activated=false; //It is too big, disabling trace for now for full USAC parsing
    #endif //MEDIAINFO_TRACE

    int16u N=0, lg=0;
    int8u sampling_frequency_index_swb;
    if (coreSbrFrameLengthIndex_Mapping[C.coreSbrFrameLengthIndex].coreCoderFrameLength==768 || coreSbrFrameLengthIndex_Mapping[C.coreSbrFrameLengthIndex].sbrRatioIndex)
    {
        float64 sampling_frequency_swb=Aac_sampling_frequency[C.sampling_frequency_index];
        if (coreSbrFrameLengthIndex_Mapping[C.coreSbrFrameLengthIndex].coreCoderFrameLength==768)
        {
            //From specs: "For a transform length of 768 samples, the same 1024-based scalefactor band tables are used, but those corresponding to 4 / 3 * sampling frequency."
            sampling_frequency_swb*=4;
            sampling_frequency_swb/=3;
        }
        if (coreSbrFrameLengthIndex_Mapping[C.coreSbrFrameLengthIndex].sbrRatioIndex)
        {
            sampling_frequency_swb*=coreSbrFrameLengthIndex_Mapping[C.coreSbrFrameLengthIndex].coreCoderFrameLength/256;
            sampling_frequency_swb/=coreSbrFrameLengthIndex_Mapping[C.coreSbrFrameLengthIndex].outputFrameLengthDivided256;
        }
        sampling_frequency_index_swb=Aac_AudioSpecificConfig_sampling_frequency_index(float64_int64s(sampling_frequency_swb)); // Not USAC index on purpose
    }
    else
        sampling_frequency_index_swb=C.sampling_frequency_index;
    if (!Aac_sampling_frequency[sampling_frequency_index_swb] || sampling_frequency_index_swb>=13)
    {
        #if MEDIAINFO_TRACE
            Trace_Activated=Trace_Activated_Save;
        #endif //MEDIAINFO_TRACE

        #if MEDIAINFO_CONFORMANCE
            if (Aac_sampling_frequency[C.sampling_frequency_index]) // Only if there wasn't already information from sampling_frequency_index
            {
                if (Aac_sampling_frequency[sampling_frequency_index_swb])
                    ;//Fill_Conformance("acSpectralData", "acSpectralData is not implemented for this sampling_frequency_index_swb", bitset8(), Info);
                else
                    Fill_Conformance("acSpectralData Cohenrecy", "Issue in acSpectralData while computing sampling_frequency_index_swb");
            }
        #endif
        C.IFrameParsed=false;
        Element_End0();
        return;
    }

    if (num_windows==1)
    {
        if (C.coreSbrFrameLengthIndex<coreSbrFrameLengthIndex_Mapping_Size)
            N=2*coreSbrFrameLengthIndex_Mapping[C.coreSbrFrameLengthIndex].coreCoderFrameLength;

        if ((ch?max_sfb1:max_sfb)<=Aac_swb_offset_long_window[sampling_frequency_index_swb]->num_swb)
            lg=Aac_swb_offset_long_window[sampling_frequency_index_swb]->swb_offset[(ch?max_sfb1:max_sfb)];
    }
    else
    {
        if (C.coreSbrFrameLengthIndex<coreSbrFrameLengthIndex_Mapping_Size)
            N=2*coreSbrFrameLengthIndex_Mapping[C.coreSbrFrameLengthIndex].coreCoderFrameLength/8;

        if ((ch?max_sfb1:max_sfb)<=Aac_swb_offset_short_window[sampling_frequency_index_swb]->num_swb)
            lg=Aac_swb_offset_short_window[sampling_frequency_index_swb]->swb_offset[(ch?max_sfb1:max_sfb)];
    }
    int16u lg_max=N/2;
    if (lg>lg_max)
        lg=lg_max;

    for (int8u win=0; win<num_windows; win++)
    {
        arithData(ch, N, lg, lg_max, arith_reset_flag&&(win==0));
        if (!C.IFrameParsed)
            break;
    }

    #if MEDIAINFO_TRACE
        Trace_Activated=Trace_Activated_Save;
    #endif //MEDIAINFO_TRACE

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::tnsData()
{
    Element_Begin1("tns_data");

    #if MEDIAINFO_TRACE
        bool Trace_Activated_Save=Trace_Activated;
        Trace_Activated=false; //It is too big, disabling trace for now for full USAC parsing
    #endif //MEDIAINFO_TRACE

    for (int8u win=0; win<num_windows; win++)
    {
        int8u n_filt, coef_res;
        if (num_windows==1)
            Get_S1 (2, n_filt,                                  "n_filt[w]");
        else
            Get_S1 (1, n_filt,                                  "n_filt[w]");

        if (n_filt)
            Get_S1 (1, coef_res,                                "coef_res[w]");

        for (int8u filt=0; filt<n_filt; filt++)
        {
            int8u order;

            if (num_windows==1)
            {
                Skip_S1(6,                                       "length[w][filt]");
                Get_S1 (4, order,                                "order[w][filt]");
            }
            else
            {
                Skip_S1(4,                                       "length[w][filt]");
                Get_S1 (3, order,                                "order[w][filt]");
            }

            if (order)
            {
                int8u coef_compress;
                Skip_SB(                                        "direction[w][filt]");
                Get_S1 (1, coef_compress,                       "coef_compress[w][filt]");

                for (int8u i=0; i<order; i++)
                    Skip_S1(coef_res+3-coef_compress,           "coef[w][filt][i]");
            }
        }
    }

    #if MEDIAINFO_TRACE
        Trace_Activated=Trace_Activated_Save;
    #endif //MEDIAINFO_TRACE

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::fdChannelStream(size_t ch, bool commonWindow, bool commonTw, bool tnsDataPresent, bool usacIndependencyFlag)
{
    Element_Begin1("fd_channel_stream");

    Skip_S1(8,                                                  "global_gain");
    if (C.noiseFilling)
    {
        Skip_S1(3,                                              "noise_level");
        Skip_S1(5,                                              "noise_offset");
    }

    if (!commonWindow)
        icsInfo();

    if (C.tw_mdct && !commonTw)
        twData();

    scaleFactorData(ch);

    if (tnsDataPresent)
        tnsData();

    acSpectralData(ch, usacIndependencyFlag);
    if (!C.IFrameParsed)
    {
        Element_End0();
        return;
    }

    TEST_SB_SKIP(                                               "fac_data_present");
        #if MEDIAINFO_CONFORMANCE
            //Fill_Conformance("fdChannelStream", "facData support not implemented", bitset8(), Info);
        #endif
        C.IFrameParsed=false;
        //TODO: facData(true, coreSbrFrameLengthIndex_Mapping[C.coreSbrFrameLengthIndex].coreCoderFrameLength/(num_windows==1?8:16));
    TEST_SB_END();

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::cplxPredData(int8u max_sfb_ste, bool usacIndependencyFlag)
{
    Element_Begin1("cplx_pred_data");

    map<int8u, map<int8u, bool>> cplx_pred_used;
    bool complex_coef;

    TESTELSE_SB_SKIP(                                           "cplx_pred_all");
        for (int8u group=0; group<num_window_groups; group++)
            for (int8u sfb=0; sfb<max_sfb_ste; sfb++)
                cplx_pred_used[group][sfb]=true;
    TESTELSE_SB_ELSE(                                           "cplx_pred_all");
        for (int8u group=0; group<num_window_groups; group++)
            for (int8u sfb=0; sfb<max_sfb_ste; sfb+=2)
            {
                Get_SB(cplx_pred_used[group][sfb],              "cplx_pred_used[group][sfb]");
                if ((sfb+1)<max_sfb_ste)
                    cplx_pred_used[group][sfb+1]=cplx_pred_used[group][sfb];
            }
    TESTELSE_SB_END();

    Skip_SB(                                                    "pred_dir");

    TEST_SB_GET(complex_coef,                                   "complex_coef");
        if (!usacIndependencyFlag)
            Skip_SB(                                            "use_prev_frame");
    TEST_SB_END();

    if (!usacIndependencyFlag)
        Skip_SB(                                                "delta_code_time");


    for (int8u group=0; group<num_window_groups; group++)
        for (int8u sfb=0; sfb<max_sfb_ste; sfb+=2)
        {
            if (cplx_pred_used[group][sfb])
            {
                hcod_sf(                                        "dpcm_alpha_q_re[g][sfb]");
                if (complex_coef)
                    hcod_sf(                                    "dpcm_alpha_q_im[g][sfb]");
            }
        }

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::StereoCoreToolInfo(bool& tns_data_present0, bool& tns_data_present1, bool core_mode0, bool core_mode1, bool usacIndependencyFlag)
{
    Element_Begin1("StereoCoreToolInfo");

    int8u max_sfb_ste, ms_mask_present;
    bool tns_active;

    if (!core_mode0 && !core_mode1)
    {
        Get_SB(tns_active,                                      "tns_active");
        TEST_SB_GET(C.common_window,                            "common_window");
            icsInfo();
            max_sfb_ste=max_sfb;
            TESTELSE_SB_SKIP(                                   "common_max_sfb");
                max_sfb1=max_sfb;
            TESTELSE_SB_ELSE(                                   "common_max_sfb");
                if (num_windows==1)
                    Get_S1(6, max_sfb1,                         "max_sfb1");
                else //EIGHT_SHORT_SEQUENCE
                    Get_S1(4, max_sfb1,                         "max_sfb1");
                if(max_sfb1>max_sfb)
                    max_sfb_ste=max_sfb1;
            TESTELSE_SB_END();
            Get_S1(2, ms_mask_present,                          "ms_mask_present");
            if (ms_mask_present==1)
            {
                for (int8u group=0; group<num_window_groups; group++)
                    for (int8u sfb=0; sfb<max_sfb_ste; sfb++)
                        Skip_SB(                                "ms_used[g][sfb]");
            }
            else if (ms_mask_present==3 && C.stereoConfigIndex==0)
                cplxPredData(max_sfb_ste, usacIndependencyFlag);
        TEST_SB_END();
        if (C.tw_mdct)
        {
            TEST_SB_GET(C.common_tw,                            "common_tw");
                twData();
            TEST_SB_END();
        }

        if (tns_active)
        {
            bool common_tns=false;
            if (C.common_window)
                Get_SB(common_tns,                              "common_tns");
            Skip_SB(                                            "tns_on_lr");

            if (common_tns)
            {
                tnsData();
                tns_data_present0=false;
                tns_data_present1=false;
            }
            else
            {
                TESTELSE_SB_SKIP(                               "tns_present_both");
                    tns_data_present0=true;
                    tns_data_present1=true;
                TESTELSE_SB_ELSE(                               "tns_present_both");
                    Get_SB(tns_data_present1,                   "tns_data_present[1]");
                    tns_data_present0=!tns_data_present1;
                TESTELSE_SB_END();
            }
        }
        else
        {
            tns_data_present0=0;
            tns_data_present1=0;
        }
    }
    else
    {
        C.common_window=false;
        C.common_tw=false;
    }

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::UsacCoreCoderData(size_t nrChannels, bool usacIndependencyFlag)
{
    Element_Begin1("UsacCoreCoderData");

    bool coreModes[2];
    bool tnsDataPresent[2]{};

    for (size_t ch=0; ch<nrChannels; ch++)
        Get_SB(coreModes[ch],                                   "core_mode");

    if (nrChannels==2)
        StereoCoreToolInfo(tnsDataPresent[0], tnsDataPresent[1], coreModes[0], coreModes[1], usacIndependencyFlag);

    for (size_t ch=0; ch<nrChannels; ch++)
    {
        if (coreModes[ch])
        {
            #if MEDIAINFO_CONFORMANCE
                //Fill_Conformance("UsacCoreCoderData", "lpd_channel_stream() support not implemented", bitset8(), Info);
            #endif
            C.IFrameParsed=false;
            //TODO: lpd_channel_stream(indepFlag);
        }
        else
        {
            if (nrChannels==1 || coreModes[0]!=coreModes[1])
                Get_SB(tnsDataPresent[ch],                      "tns_data_present");

            fdChannelStream(ch, C.common_window, C.common_tw, tnsDataPresent[ch], usacIndependencyFlag);
        }
        if (!C.IFrameParsed)
            break;
    }

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::sbrInfo()
{
    Element_Begin1("sbrInfo");

    Get_S1 (1, C.sbrHandler.bs_amp_res_FromHeader,              "bs_amp_res");
    Get_S1 (4, C.sbrHandler.bs_xover_band,                      "bs_xover_band");
    Skip_SB(                                                    "bs_sbr_preprocessing");
    if (C.bs_pvc)
        Get_S1(2, C.sbrHandler.bs_pvc_mode,                     "bs_pvc_mode");
    else
        C.sbrHandler.bs_pvc_mode=0;

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::sbrHeader()
{
    Element_Begin1("sbrHeader");

    C.sbrHandler.present=true;

    bool bs_header_extra_1, bs_header_extra_2;

    Get_S1 (4, C.sbrHandler.bs_start_freq,                      "bs_start_freq");
    Get_S1 (4, C.sbrHandler.bs_stop_freq,                       "bs_stop_freq");
    Get_SB (bs_header_extra_1,                                  "bs_header_extra_1");
    Get_SB (bs_header_extra_2,                                  "bs_header_extra_2");

    if (bs_header_extra_1)
    {
        Get_S1 (2, C.sbrHandler.bs_freq_scale,                  "bs_freq_scale");
        Get_S1 (1, C.sbrHandler.bs_alter_scale,                 "bs_alter_scale");
        Get_S1 (2, C.sbrHandler.bs_noise_bands,                 "bs_noise_bands");
    }
    else
    {
        C.sbrHandler.bs_freq_scale=2;
        C.sbrHandler.bs_alter_scale=1;
        C.sbrHandler.bs_noise_bands=2;
    }

    if (bs_header_extra_2)
    {
        Skip_S1(2,                                              "bs_limiter_band");
        Skip_S1(2,                                              "bs_limiter_gain");
        Skip_SB(                                                "bs_interpol_freq");
        Skip_SB(                                                "bs_smoothing_mode");
    }

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::sbrGrid(size_t ch)
{
    Element_Begin1("sbr_grid");

    if (!C.sbrHandler.bs_pvc_mode)
    {
        int8u bs_num_rel_0, bs_num_rel_1;
        Get_S1(2, C.sbrHandler.bs_frame_class[ch],              "bs_frame_class[ch]");

        switch ((frame_class)C.sbrHandler.bs_frame_class[ch])
        {
        case FIXFIX:
            Get_S1 (2, C.sbrHandler.bs_num_env[ch],             "bs_num_env[ch]");
            C.sbrHandler.bs_num_env[ch]=1<<C.sbrHandler.bs_num_env[ch];

            Get_SB (C.sbrHandler.bs_freq_res[ch][0],            "bs_freq_res[ch][0]");
            for (int8u env=1; env<C.sbrHandler.bs_num_env[ch]; env++)
                C.sbrHandler.bs_freq_res[ch][env]=C.sbrHandler.bs_freq_res[ch][0];
            break;
        case FIXVAR:
            Skip_S1(2,                                          "bs_var_bord_1[ch]");
            Get_S1 (2, C.sbrHandler.bs_num_env[ch],             "bs_num_rel_1[ch]");
            C.sbrHandler.bs_num_env[ch]++;

            for (int8u rel=0; rel<C.sbrHandler.bs_num_env[ch]-1; rel++)
                Skip_S1(2,                                      "bs_rel_bord_1[ch][rel]");

            Skip_S1(ceil(log(C.sbrHandler.bs_num_env[ch]+1)/log(2)),
                                                                "bs_pointer[ch]");

            for (int8u env=0; env<C.sbrHandler.bs_num_env[ch]; env++)
                Get_SB(C.sbrHandler.bs_freq_res[ch][C.sbrHandler.bs_num_env[ch]-1-env],
                                                                "bs_freq_res[ch][bs_num_env[ch]–1–env]");
            break;
        case VARFIX:
            Skip_S1(2,                                          "bs_var_bord_0[ch]");
            Get_S1 (2, C.sbrHandler.bs_num_env[ch],             "bs_num_rel_0[ch]");
            C.sbrHandler.bs_num_env[ch]++;

            for (int8u rel=0; rel<C.sbrHandler.bs_num_env[ch]-1; rel++)
                Skip_S1(2,                                      "bs_rel_bord_0[ch][rel]");

            Skip_S1(ceil(log(C.sbrHandler.bs_num_env[ch]+1)/log(2)),
                                                                "bs_pointer[ch]");

            for (int8u env=0; env<C.sbrHandler.bs_num_env[ch]; env++)
                Get_SB (C.sbrHandler.bs_freq_res[ch][env],      "bs_freq_res[ch][env]");
            break;
        case VARVAR:
            Skip_S1(2,                                          "bs_var_bord_0[ch]");
            Skip_S1(2,                                          "bs_var_bord_1[ch]");
            Get_S1 (2, bs_num_rel_0,                            "bs_num_rel_0[ch]");
            Get_S1 (2, bs_num_rel_1,                            "bs_num_rel_1[ch]");
            C.sbrHandler.bs_num_env[ch]=bs_num_rel_0+bs_num_rel_1+1;

            for (int8u rel=0; rel<bs_num_rel_0; rel++)
                Skip_S1(2,                                      "bs_rel_bord_0[ch][rel]");

            for (int8u rel=0; rel<bs_num_rel_1; rel++)
                Skip_S1(2,                                      "bs_rel_bord_1[ch][rel]");

            Skip_S1(ceil(log(C.sbrHandler.bs_num_env[ch]+1)/log(2)),
                                                                "bs_pointer[ch]");

            for (int8u env=0; env<C.sbrHandler.bs_num_env[ch]; env++)
                Get_SB (C.sbrHandler.bs_freq_res[ch][env],      "bs_freq_res[ch][env]");

            break;
        }

        if (C.sbrHandler.bs_num_env[ch]>1)
            C.sbrHandler.bs_num_noise[ch]=2;
        else
            C.sbrHandler.bs_num_noise[ch]=1;
    }
    else
    {
        int8u bs_noise_position;
        Get_S1 (4, bs_noise_position,                           "bs_noise_position[ch]");
        if(!Peek_SB())
            Skip_SB(                                            "bs_var_len_hf[ch]");
        else
            Skip_S1(3,                                          "bs_var_len_hf[ch]");

        if (!bs_noise_position)
        {
            C.sbrHandler.bs_num_env[ch]=1;
            C.sbrHandler.bs_num_noise[ch]=1;
        }
        else
        {
            C.sbrHandler.bs_num_env[ch]=2;
            C.sbrHandler.bs_num_noise[ch]=2;
        }
    }

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::sbrDtdf(size_t ch, bool usacIndependencyFlag)
{
    Element_Begin1("sbr_dtdf");

    if (!C.sbrHandler.bs_pvc_mode)
    {
        if (!usacIndependencyFlag)
            Get_S1(1, C.sbrHandler.bs_df_env[ch][0],             "bs_df_env[ch][0]");
        else
            C.sbrHandler.bs_df_env[ch][0]=false;

        for (int8u env=1; env<C.sbrHandler.bs_num_env[ch]; env++)
            Get_S1(1, C.sbrHandler.bs_df_env[ch][env],           "bs_df_env[ch][env]");
    }

    if(!usacIndependencyFlag)
        Get_S1(1, C.sbrHandler.bs_df_noise[ch][0],               "bs_df_noise[ch][0]");
    else
        C.sbrHandler.bs_df_noise[ch][0]=false;

    for (int8u n=1; n<C.sbrHandler.bs_num_noise[ch]; n++)
        Get_S1(1, C.sbrHandler.bs_df_noise[ch][n],               "bs_df_noise[ch][noise]");

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::sbrInvf(size_t ch)
{
    Element_Begin1("sbr_invf");
    for (int8u n=0; n<C.sbrHandler.num_noise_bands; n++ )
        Skip_S1(2,                                              "bs_invf_mode[ch][n]");

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::pvcEnvelope(bool usacIndependencyFlag)
{
    Element_Begin1("pvc_envelope");

    int8u divMode;
    Get_S1(3, divMode,                                          "divMode");
    Skip_SB(                                                    "nsMode");

    if (divMode<=3)
    {
        bool reuse_pvcID=false;
        if (!usacIndependencyFlag)
            Get_SB(reuse_pvcID,                                 "reuse_pvcID");

        if (!reuse_pvcID)
            Skip_S1(7,                                          "pvcID[0]");

        int8u sum_length=0;
        for (int8u i=0; i<divMode; i++)
        {
            int8u length;
            if (sum_length>=13)
                Get_S1(1, length,                               "length");
            else if (sum_length>=11)
                Get_S1(2, length,                               "length");
            else if (sum_length>=7)
                Get_S1(3, length,                               "length");
            else
                Get_S1(4, length,                               "length");

            sum_length+=length+1;

            Skip_S1(7,                                          "pvcID[k++]");
        }
    }
    else
    {
        int8u num_grid_info{};
        switch (divMode)
        {
        case 4:
            num_grid_info=2;
            break;
        case 5:
            num_grid_info=4;
            break;
        case 6:
            num_grid_info=8;
            break;
        case 7:
            num_grid_info=16;
            break;
        default:
            break;
        }

        for (int8u i=0; i<num_grid_info; i++)
        {
            bool grid_info;
            if (i==0 && usacIndependencyFlag)
                grid_info=true;
            else
                Get_SB(grid_info,                               "grid_info");

            if (grid_info)
                Skip_S1(7,                                      "pvcID[k++]");
        }
    }

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::sbrEnvelope(bool ch, bool bs_coupling)
{
    const int8s (*t_huff)[2], (*f_huff)[2];

    bool amp_res=C.sbrHandler.bs_amp_res_FromHeader;
    if (!C.sbrHandler.bs_frame_class[ch] && C.sbrHandler.bs_num_env[ch]==1)
        amp_res=false;

    Element_Begin1("sbr_envelope");

    if (bs_coupling && ch)
    {
        if (amp_res)
        {
            t_huff=t_huffman_env_bal_3_0dB;
            f_huff=f_huffman_env_bal_3_0dB;
        }
        else
        {
            t_huff=t_huffman_env_bal_1_5dB;
            f_huff=f_huffman_env_bal_1_5dB;
        }
        
    }
    else
    {
        if (amp_res)
        {
            t_huff=t_huffman_env_3_0dB;
            f_huff=f_huffman_env_3_0dB;
        }
        else
        {
            t_huff=t_huffman_env_1_5dB;
            f_huff=f_huffman_env_1_5dB;
        }
    }

    for (int8u env=0; env<C.sbrHandler.bs_num_env[ch]; env++)
    {
        if (!C.sbrHandler.bs_df_env[ch][env])
        {
            if (bs_coupling && ch)
                Skip_S1(amp_res?5:6,                            "bs_env_start_value_balance");
            else
                Skip_S1(amp_res?6:7,                            "bs_env_start_value_level");

            for (int8u band=1; band<C.sbrHandler.num_env_bands[C.sbrHandler.bs_freq_res[ch][env]]; band++)
                sbr_huff_dec(f_huff,                            "bs_data_env[ch][env][band]");
        }
        else
        {
            for (int8u band=0; band<C.sbrHandler.num_env_bands[C.sbrHandler.bs_freq_res[ch][env]]; band++)
                sbr_huff_dec(t_huff,                            "bs_data_env[ch][env][band]");
        }

        if (C.bs_interTes)
        {
            TEST_SB_SKIP(                                       "bs_temp_shape[ch][env]");
                Skip_S1(2,                                      "bs_inter_temp_shape_mode[ch][env]");
            TEST_SB_END();
        }
    }
    Element_End0();
}


//---------------------------------------------------------------------------
void File_Usac::sbrNoise(bool ch, bool bs_coupling)
{
    const int8s (*t_huff)[2], (*f_huff)[2];

    Element_Begin1("sbr_noise");
    if (bs_coupling && ch)
    {
        t_huff=t_huffman_noise_bal_3_0dB;
        f_huff=f_huffman_env_bal_3_0dB;
    }
    else
    {
        t_huff=t_huffman_noise_3_0dB;
        f_huff=f_huffman_env_3_0dB;
    }

    for (int noise=0; noise<C.sbrHandler.bs_num_noise[ch]; noise++)
    {
        if (!C.sbrHandler.bs_df_noise[ch][noise])
        {
            Skip_S1(5,                        (bs_coupling&&ch)?"bs_noise_start_value_balance":"bs_noise_start_value_level");
            for (int8u band=1; band<C.sbrHandler.num_noise_bands; band++)
                sbr_huff_dec(f_huff,                            "bs_data_noise[ch][noise][band]");
        }
        else
        {
            for (int8u band=0; band<C.sbrHandler.num_noise_bands; band++)
                sbr_huff_dec(t_huff,                            "bs_data_noise[ch][noise][band]");
        }
    }
    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::sbrSinusoidalCoding(bool, int8u bs_pvc_mode)
{

    Element_Begin1("sbr_sinusoidal_coding");

    for (int8u n=0; n<C.sbrHandler.num_env_bands[1]; n++)
        Skip_SB(                                                "bs_add_harmonic[ch][n]");

    if (bs_pvc_mode)
    {
        TEST_SB_SKIP(                                           "bs_sinusoidal_position_flag");
            Skip_S1(5,                                          "bs_sinusoidal_position");
        TEST_SB_END();
    }

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::sbrSingleChannelElement(bool usacIndependencyFlag)
{
    Element_Begin1("sbr_single_channel_element");

    if (C.harmonicSBR)
    {
        TESTELSE_SB_SKIP(                                       "sbrPatchingMode[0]");
        TESTELSE_SB_ELSE(                                       "sbrPatchingMode[0]");
            Skip_SB(                                            "sbrOversamplingFlag[0]");
            TEST_SB_SKIP(                                       "sbrPitchInBinsFlag[0]");
                Skip_S1(7,                                      "sbrPitchInBins[0]");
            TEST_SB_END();
        TESTELSE_SB_END();
    }

    sbrGrid(0);
    sbrDtdf(0, usacIndependencyFlag);
    sbrInvf(0);

    if (C.sbrHandler.bs_pvc_mode)
        pvcEnvelope(usacIndependencyFlag);
    else
        sbrEnvelope(0, false);

    sbrNoise(0, false);

    TEST_SB_SKIP(                                               "bs_add_harmonic_flag[0]");
        sbrSinusoidalCoding(0, C.sbrHandler.bs_pvc_mode);
    TEST_SB_END();

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::sbrChannelPairElement(bool usacIndependencyFlag)
{
    Element_Begin1("sbr_channel_pair_element");

    TESTELSE_SB_SKIP(                                           "bs_coupling");
        if (C.harmonicSBR)
        {
            TESTELSE_SB_SKIP(                                   "sbrPatchingMode[0,1]");
            TESTELSE_SB_ELSE(                                   "sbrPatchingMode[0,1]");
                Skip_SB(                                        "sbrOversamplingFlag[0,1]");
                TEST_SB_SKIP(                                   "sbrOversamplingFlag[0,1]");
                Skip_S1(7,                                      "sbrPitchInBins[0,1]");
                TEST_SB_END();
            TESTELSE_SB_END();
        }

        sbrGrid(0);
        //Coupling
        C.sbrHandler.bs_frame_class[1]=C.sbrHandler.bs_frame_class[0];
        C.sbrHandler.bs_num_env    [1]=C.sbrHandler.bs_num_env    [0];
        C.sbrHandler.bs_num_noise  [1]=C.sbrHandler.bs_num_noise  [0];
        C.sbrHandler.bs_amp_res    [1]=C.sbrHandler.bs_amp_res    [0];
        for (int8u env=0; env<C.sbrHandler.bs_num_env[0]; env++)
            C.sbrHandler.bs_freq_res[1][env]=C.sbrHandler.bs_freq_res[0][env];
        sbrDtdf(0, usacIndependencyFlag);
        sbrDtdf(1, usacIndependencyFlag);
        sbrInvf(0);
        sbrEnvelope(0, true);
        sbrNoise(0, true);
        sbrEnvelope(1, true);
        sbrNoise(1, true);
    TESTELSE_SB_ELSE(                                           "bs_coupling");
        if (C.harmonicSBR)
        {
            TESTELSE_SB_SKIP(                                   "sbrPatchingMode[0]");
            TESTELSE_SB_ELSE(                                   "sbrPatchingMode[0]");
                Skip_SB(                                        "sbrOversamplingFlag[0]");
                TEST_SB_SKIP(                                   "sbrOversamplingFlag[0]");
                Skip_S1(7,                                      "sbrPitchInBins[0]");
                TEST_SB_END();
            TESTELSE_SB_END();
            TESTELSE_SB_SKIP(                                   "sbrPatchingMode[1]");
            TESTELSE_SB_ELSE(                                   "sbrPatchingMode[1]");
                Skip_SB(                                        "sbrOversamplingFlag[1]");
                TEST_SB_SKIP(                                   "sbrOversamplingFlag[1]");
                Skip_S1(7,                                      "sbrPitchInBins[1]");
                TEST_SB_END();
            TESTELSE_SB_END();
        }

        sbrGrid(0);
        sbrGrid(1);
        sbrDtdf(0, usacIndependencyFlag);
        sbrDtdf(1, usacIndependencyFlag);
        sbrInvf(0);
        sbrInvf(1);
        sbrEnvelope(0, false);
        sbrEnvelope(1, false);
        sbrNoise(0, false);
        sbrNoise(1, false);
    TESTELSE_SB_END();

    TEST_SB_SKIP(                                               "bs_add_harmonic_flag[0]");
        sbrSinusoidalCoding(0, 0);
    TEST_SB_END();
    TEST_SB_SKIP(                                               "bs_add_harmonic_flag[1]");
        sbrSinusoidalCoding(1, 0);
    TEST_SB_END();

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::sbrData(size_t nrSbrChannels, bool usacIndependencyFlag)
{
    Element_Begin1("sbr_data");

    switch (nrSbrChannels)
    {
        case 1:
            sbrSingleChannelElement(usacIndependencyFlag);
            break;
        case 2:
            sbrChannelPairElement(usacIndependencyFlag);
            break;
        default:
            ; //TODO: Handle invalid value
    }

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::UsacSbrData(size_t nrSbrChannels, bool usacIndependencyFlag)
{
    Element_Begin1("UsacSbrData");

    bool sbrInfoPresent=true, sbrHeaderPresent=true;

    if (!usacIndependencyFlag)
    {
        TESTELSE_SB_GET(sbrInfoPresent,                         "sbrInfoPresent");
            Get_SB(sbrHeaderPresent,                            "sbrHeaderPresent");
        TESTELSE_SB_ELSE(                                       "sbrInfoPresent");
            sbrHeaderPresent=false;
        TESTELSE_SB_END();
    }

    if (sbrInfoPresent)
        sbrInfo();

    if (sbrHeaderPresent)
    {
        TESTELSE_SB_SKIP(                                        "sbrUseDfltHeader");
            C.sbrHandler.present=true;
            C.sbrHandler.bs_start_freq=C.dlftHandler.dflt_start_freq;
            C.sbrHandler.bs_stop_freq=C.dlftHandler.dflt_stop_freq;
            C.sbrHandler.bs_freq_scale=C.dlftHandler.dflt_freq_scale;
            C.sbrHandler.bs_alter_scale=C.dlftHandler.dflt_alter_scale;
            C.sbrHandler.bs_noise_bands=C.dlftHandler.dflt_noise_bands;
        TESTELSE_SB_ELSE(                                        "sbrUseDfltHeader");
            sbrHeader();
        TESTELSE_SB_END();
    }

    int64s sampling_frequency=C.sampling_frequency;
    if (C.coreSbrFrameLengthIndex==4)
    {
        if (Frequency_b!=0) sampling_frequency=Frequency_b/2;
        C.sbrHandler.ratio=QUAD;
    }

    if (C.sbrHandler.present)
    {
        if (C.coreSbrFrameLengthIndex>=coreSbrFrameLengthIndex_Mapping_Size)
        {
            Element_End0();
            C.IFrameParsed=false;
            return;
        }
        if (!Aac_Sbr_Compute(&C.sbrHandler, sampling_frequency, true))
        {
            Element_End0();
            #if MEDIAINFO_CONFORMANCE
                Fill_Conformance("UsacSbrData GeneralCompliance", "Issue detected while computing SBR bands");
            #endif
            C.IFrameParsed=false;
            return;
        }
        sbrData(nrSbrChannels, usacIndependencyFlag);
    }

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::FramingInfo()
{
    Element_Begin1("FramingInfo");

    bool bsFramingType;
    if (C.mps212Handler.bsHighRatelMode)
    {
        Get_SB (bsFramingType,                                  "bsFramingType");
        Get_S1 (3, C.mps212Handler.numParamSets,                "bsNumParamSets");
    }
    else
    {
        bsFramingType=false;
        C.mps212Handler.numParamSets=0;
    }
    C.mps212Handler.numParamSets++;
    int8u nBitsParamSlot=ceil(log2(C.mps212Handler.numSlots));
    if (bsFramingType)
    {
        for (int8u ps=0; ps<C.mps212Handler.numParamSets; ps++)
            Skip_BS(nBitsParamSlot,                             "bsParamSlot[ps]");
    }

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::EcData(ec_data_type dataType, int8u paramIdx, int8u startBand, int8u stopBand, bool usacIndependencyFlag)
{
    Element_Begin1("EcData");

    int8u dataSets=0;
    for (int8u ps=0; ps<C.mps212Handler.numParamSets;ps++)
    {
        int8u bsXXXdataMode;
        Get_S1 (2, bsXXXdataMode,                               "bsXXXdataMode[paramIdx][ps]");
        if (bsXXXdataMode==3)
            dataSets++;
    }

    for (int8u setIdx=0; setIdx<dataSets;)
    {
        bool bsDataPairXXX, bsQuantCoarseXXX;
        int8u bsFreqResStrideXXX;
        Get_SB (bsDataPairXXX,                                  "bsDataPairXXX[paramIdx][setIdx]");
        Get_SB (bsQuantCoarseXXX,                               "bsQuantCoarseXXX[paramIdx][setIdx]");
        Get_S1 (2, bsFreqResStrideXXX,                          "bsFreqResStrideXXX[paramIdx][setIdx]");
        EcDataPair(dataType, paramIdx, setIdx, (stopBand-startBand-1)/pb_stride[bsFreqResStrideXXX]+1, bsDataPairXXX, bsQuantCoarseXXX, usacIndependencyFlag);

        setIdx+=bsDataPairXXX?2:1;
    }

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::GroupedPcmData(ec_data_type dataType, bool pairFlag, int8u numQuantSteps, int8u dataBands)
{
    //TODO: Check this code
    if (pairFlag)
        dataBands*=2;

    int8u maxGroupLen=0;
    switch (numQuantSteps)
    {
    case 4:
    case 8:
    case 15:
    case 16:
    case 26:
    case 31:
        maxGroupLen=1;
        break;
    case 11:
        maxGroupLen=2;
        break;
    case 25:
        maxGroupLen=3;
        break;
    case 13:
    case 19:
    case 51:
        maxGroupLen=4;
        break;
    case 3:
        maxGroupLen=5;
        break;
    case 7:
        maxGroupLen=6;
        break;
    default:
        ;
    }

    int32u Temp=1;
    int32u chunkSize[7]={0};
    for (int8u pos=1; pos<=maxGroupLen; pos++)
    {
        Temp*=numQuantSteps;
        chunkSize[pos]=ceil(log2(Temp));
    }

    Element_Begin1("GroupedPcmData");

    for (int8u val=0; val<dataBands; val+=maxGroupLen)
    {
        int8u groupLen=min((int)maxGroupLen, dataBands-val);
        Skip_BS(chunkSize[groupLen],                            "pcm_data");
    }

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::HuffData1D(ec_data_type dataType, int8u diffType, int8u dataBands)
{
    Element_Begin1("HuffData1D");

    const int16s(*hcodFirstBand_XXX)[2] = {};
    const int16s (*hcod1D_XXX_YY)[2] = {};
    switch (dataType)
    {
    case CLD:
        hcodFirstBand_XXX=hcodFirstBand_CLD;
        if (diffType==0) //DF
            hcod1D_XXX_YY=hcod1D_CLD_DF;
        else //DT
            hcod1D_XXX_YY=hcod1D_CLD_DT;
        break;
    case ICC:
        hcodFirstBand_XXX=hcodFirstBand_ICC;
        hcod1D_XXX_YY=hcod1D_ICC_YY;
        break;
    case IPD:
        hcodFirstBand_XXX=hcodFirstBand_IPD;
        if (diffType==0) //DF
            hcod1D_XXX_YY=hcod1D_IPD_DF;
        else //DT
            hcod1D_XXX_YY=hcod1D_IPD_DT;
        break;
    }

    if (diffType==0) //DIFF_FREQ
        huff_dec_1D(hcodFirstBand_XXX, "1Dhuff_dec");

    for (int8u i=(diffType==0?1:0); i<dataBands; i++)
    {
        int16s data=huff_dec_1D(hcod1D_XXX_YY, "1Dhuff_dec");
        if (-(data+1) && dataType!=IPD)
            Skip_SB(                                            "bsSign");
    }

    Element_End0();
}


//---------------------------------------------------------------------------
void File_Usac::HuffData2DFreqPair(ec_data_type dataType, int8u diffType, int8u dataBands)
{
    Element_Begin1("HuffData2DFreqPair");

    int8s lavIdx=huff_dec_1D(hcodLavIdx, "1Dhuff_dec");
    int8u lav=lavTabXXX[(int8u)dataType][-(lavIdx+1)];

    const int16s (*hcodFirstBand_XXX)[2] = {};
    const int16s (*hcod1D_XXX_YY)[2] = {};
    const int16s (*hcod2D_XXX_YY_FP_LL)[2] = {};
    switch (dataType)
    {
    case CLD:
        hcodFirstBand_XXX=hcodFirstBand_CLD;
        if (diffType==0) //DF
            hcod1D_XXX_YY=hcod1D_CLD_DF;
        else //DT
            hcod1D_XXX_YY=hcod1D_CLD_DT;
        switch (lav)
        {
        case 3:
            if (diffType==0) //DF
                hcod2D_XXX_YY_FP_LL=hcod2D_CLD_DF_FP_03;
            else //DT
                hcod2D_XXX_YY_FP_LL=hcod2D_CLD_DT_FP_03;
            break;
        case 5:
            if (diffType==0) //DF
                hcod2D_XXX_YY_FP_LL=hcod2D_CLD_DF_FP_05;
            else //DT
                hcod2D_XXX_YY_FP_LL=hcod2D_CLD_DT_FP_05;
            break;
        case 7:
            if (diffType==0) //DF
                hcod2D_XXX_YY_FP_LL=hcod2D_CLD_DF_FP_07;
            else //DT
                hcod2D_XXX_YY_FP_LL=hcod2D_CLD_DT_FP_07;
            break;
        case 9:
            if (diffType==0) //DF
                hcod2D_XXX_YY_FP_LL=hcod2D_CLD_DF_FP_09;
            else //DT
                hcod2D_XXX_YY_FP_LL=hcod2D_CLD_DT_FP_09;
            break;
        default:
            ;
        }
        break;
    case ICC:
        hcod1D_XXX_YY=hcod1D_ICC_YY;
        hcodFirstBand_XXX=hcodFirstBand_ICC;
        switch (lav)
        {
        case 1:
            if (diffType==0) //DF
                hcod2D_XXX_YY_FP_LL=hcod2D_ICC_DF_FP_01;
            else //DT
                hcod2D_XXX_YY_FP_LL=hcod2D_ICC_DT_FP_01;
            break;
        case 3:
            if (diffType==0) //DF
                hcod2D_XXX_YY_FP_LL=hcod2D_ICC_DF_FP_03;
            else //DT
                hcod2D_XXX_YY_FP_LL=hcod2D_ICC_DT_FP_03;
            break;
        case 5:
            if (diffType==0) //DF
                hcod2D_XXX_YY_FP_LL=hcod2D_ICC_DF_FP_05;
            else //DT
                hcod2D_XXX_YY_FP_LL=hcod2D_ICC_DT_FP_05;
            break;
        case 7:
            if (diffType==0) //DF
                hcod2D_XXX_YY_FP_LL=hcod2D_ICC_DF_FP_07;
            else //DT
                hcod2D_XXX_YY_FP_LL=hcod2D_ICC_DT_FP_07;
            break;
        default:
            ;
        }
        break;
    case IPD:
        hcodFirstBand_XXX=hcodFirstBand_IPD;
        if (diffType==0) //DF
            hcod1D_XXX_YY=hcod1D_IPD_DF;
        else //DT
            hcod1D_XXX_YY=hcod1D_IPD_DT;
        switch (lav)
        {
        case 7:
            if (diffType==0) //DF
                hcod2D_XXX_YY_FP_LL=hcod2D_IPD_DF_FP_07;
            else //DT
                hcod2D_XXX_YY_FP_LL=hcod2D_IPD_DT_FP_07;
            break;
        case 1:
            if (diffType==0) //DF
                hcod2D_XXX_YY_FP_LL=hcod2D_IPD_DF_FP_01;
            else //DT
                hcod2D_XXX_YY_FP_LL=hcod2D_IPD_DT_FP_01;
            break;
        case 3:
            if (diffType==0) //DF
                hcod2D_XXX_YY_FP_LL=hcod2D_IPD_DF_FP_03;
            else //DT
                hcod2D_XXX_YY_FP_LL=hcod2D_IPD_DT_FP_03;
            break;
        case 5:
            if (diffType==0) //DF
                hcod2D_XXX_YY_FP_LL=hcod2D_IPD_DF_FP_05;
            else //DT
                hcod2D_XXX_YY_FP_LL=hcod2D_IPD_DT_FP_05;
            break;
        default:
            ;
        }
        break;
    }

    if (diffType==0) //DIFF_FREQ
    {
        huff_dec_1D(hcodFirstBand_XXX, "1Dhuff_dec");
        dataBands--;
    }

    bool remains=false;
    if (dataBands%2)
    {
        dataBands--;
        remains=true;
    }

    int8s aTmp[2];
    int8u escCounter=0;
    for (int8u i=(diffType==0?1:0); i<dataBands; i+=2)
    {
        bool escape=huff_dec_2D(hcod2D_XXX_YY_FP_LL, aTmp, "2Dhuff_dec");
        if (escape)
            escCounter++;
        else
            SymmetryData(dataType, aTmp, lav);

    }

    if (escCounter)
        GroupedPcmData(dataType, true, 2*lav+1, escCounter);

    if (remains)
    {
        int16s data=huff_dec_1D(hcod1D_XXX_YY, "1Dhuff_dec");
        if (-(data+1) && dataType!=IPD)
            Skip_SB(                                            "bsSign");
    }

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::HuffData2DTimePair(ec_data_type dataType, int8u* aDiffType, int8u dataBands)
{
    Element_Begin1("HuffData2DTimePair");

    int8u diffType=0;
    if (aDiffType[0] || aDiffType[1])
        diffType=1;

    int8s lavIdx=huff_dec_1D(hcodLavIdx, "1Dhuff_dec");
    int8u lav=lavTabXXX[(int8u)dataType][-(lavIdx+1)];

    const int16s (*hcodFirstBand_XXX)[2] = {};
    const int16s (*hcod2D_XXX_YY_TP_LL)[2] = {};
    switch (dataType)
    {
    case CLD:
        hcodFirstBand_XXX=hcodFirstBand_CLD;
        switch (lav)
        {
        case 3:
            if (diffType==0) //DF
                hcod2D_XXX_YY_TP_LL=hcod2D_CLD_DF_TP_03;
            else //DT
                hcod2D_XXX_YY_TP_LL=hcod2D_CLD_DT_TP_03;
            break;
        case 5:
            if (diffType==0) //DF
                hcod2D_XXX_YY_TP_LL=hcod2D_CLD_DF_TP_05;
            else //DT
                hcod2D_XXX_YY_TP_LL=hcod2D_CLD_DT_TP_05;
            break;
        case 7:
            if (diffType==0) //DF
                hcod2D_XXX_YY_TP_LL=hcod2D_CLD_DF_TP_07;
            else //DT
                hcod2D_XXX_YY_TP_LL=hcod2D_CLD_DT_TP_07;
            break;
        case 9:
            if (diffType==0) //DF
                hcod2D_XXX_YY_TP_LL=hcod2D_CLD_DF_TP_09;
            else //DT
                hcod2D_XXX_YY_TP_LL=hcod2D_CLD_DT_TP_09;
            break;
        default:
            ;
        }
        break;
    case ICC:
        hcodFirstBand_XXX=hcodFirstBand_ICC;
        switch (lav)
        {
        case 1:
            if (diffType==0) //DF
                hcod2D_XXX_YY_TP_LL=hcod2D_ICC_DF_TP_01;
            else //DT
                hcod2D_XXX_YY_TP_LL=hcod2D_ICC_DT_TP_01;
            break;
        case 3:
            if (diffType==0) //DF
                hcod2D_XXX_YY_TP_LL=hcod2D_ICC_DF_TP_03;
            else //DT
                hcod2D_XXX_YY_TP_LL=hcod2D_ICC_DT_TP_03;
            break;
        case 5:
            if (diffType==0) //DF
                hcod2D_XXX_YY_TP_LL=hcod2D_ICC_DF_TP_05;
            else //DT
                hcod2D_XXX_YY_TP_LL=hcod2D_ICC_DT_TP_05;
            break;
        case 7:
            if (diffType==0) //DF
                hcod2D_XXX_YY_TP_LL=hcod2D_ICC_DF_TP_07;
            else //DT
                hcod2D_XXX_YY_TP_LL=hcod2D_ICC_DT_TP_07;
            break;
        default:
            ;
        }
        break;
    case IPD:
        hcodFirstBand_XXX=hcodFirstBand_IPD;
        switch (lav)
        {
        case 7:
            if (diffType==0) //DF
                hcod2D_XXX_YY_TP_LL=hcod2D_IPD_DF_TP_07;
            else //DT
                hcod2D_XXX_YY_TP_LL=hcod2D_IPD_DT_TP_07;
            break;
        case 1:
            if (diffType==0) //DF
                hcod2D_XXX_YY_TP_LL=hcod2D_IPD_DF_TP_01;
            else //DT
                hcod2D_XXX_YY_TP_LL=hcod2D_IPD_DT_TP_01;
            break;
        case 3:
            if (diffType==0) //DF
                hcod2D_XXX_YY_TP_LL=hcod2D_IPD_DF_TP_03;
            else //DT
                hcod2D_XXX_YY_TP_LL=hcod2D_IPD_DT_TP_03;
            break;
        case 5:
            if (diffType==0) //DF
                hcod2D_XXX_YY_TP_LL=hcod2D_IPD_DF_TP_05;
            else //DT
                hcod2D_XXX_YY_TP_LL=hcod2D_IPD_DT_TP_05;
            break;
        default:
            ;
        }
        break;
    }

    if (!aDiffType[0] || !aDiffType[1]) //DIFF_FREQ
    {
        huff_dec_1D(hcodFirstBand_XXX, "1Dhuff_dec");
        huff_dec_1D(hcodFirstBand_XXX, "1Dhuff_dec");
    }

    int8s aTmp[2];
    int8u escCounter=0;
    for (int8u i=((!aDiffType[0] || !aDiffType[1])?1:0); i<dataBands; i++)
    {
        bool escape=huff_dec_2D(hcod2D_XXX_YY_TP_LL, aTmp, "2Dhuff_dec");
        if (escape)
            escCounter++;
        else
            SymmetryData(dataType, aTmp, lav);

    }

    if (escCounter)
        GroupedPcmData(dataType, true, 2*lav+1, escCounter);

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::DiffHuffData(ec_data_type dataType, bool bsDataPairXXX, bool allowDiffTimeBackFlag, int8u dataBands)
{
    Element_Begin1("DiffHuffData");

    int8u bsDiffType[2] = { 0, 0 };
    if (bsDataPairXXX || allowDiffTimeBackFlag)
        Get_S1(1, bsDiffType[0],                                "bsDiffType[0]");

    if (bsDataPairXXX && (!bsDiffType[0] || allowDiffTimeBackFlag))
        Get_S1(1, bsDiffType[1],                                "bsDiffType[1]");

    TESTELSE_SB_SKIP(                                           "bsCodingScheme"); //HUFF-2D
        bool bsPairing=false;
        if (bsDataPairXXX)
            Get_SB(bsPairing,                                   "bsPairing");

        if (!bsPairing) //FREQ_PAIR
        {
            HuffData2DFreqPair(dataType, bsDiffType[0], dataBands);
            if (bsDataPairXXX)
                HuffData2DFreqPair(dataType, bsDiffType[1], dataBands);
        }
        else //TIME_PAIR
            HuffData2DTimePair(dataType, bsDiffType, dataBands);
    TESTELSE_SB_ELSE(                                           "bsCodingScheme"); //HUFF-1D
        HuffData1D(dataType, bsDiffType[0], dataBands);
        if (bsDataPairXXX)
            HuffData1D(dataType, bsDiffType[1], dataBands);
    TESTELSE_SB_END();

    // Inverse differential coding
    if ((bsDiffType[0] || bsDiffType[1]) &&
       !(!allowDiffTimeBackFlag && bsDiffType[0]) &&
       !(!bsDataPairXXX || (bsDataPairXXX && bsDiffType[1])))
       Skip_SB(                                                 "bsDiffTimeDirection[0]");

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::LsbData(ec_data_type dataType, bool bsQuantCoarseXXX, int8u dataBands)
{
    if (dataType!=IPD || bsQuantCoarseXXX)
        return;

    Element_Begin1("LsbData");

    for (int8u band=0; band<dataBands; band++)
        Skip_SB(                                                "bsLsb");

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::EcDataPair(ec_data_type dataType, int8u paramIdx, int8u setIdx, int8u dataBands, bool bsDataPairXXX, bool bsQuantCoarseXXX, bool usacIndependencyFlag)
{
    int8u numQuantSteps{};
    switch (dataType)
    {
    case CLD:
        numQuantSteps=bsQuantCoarseXXX?15:31;
        break;
    case ICC:
        numQuantSteps=bsQuantCoarseXXX?4:8;
        break;
    case IPD:
        numQuantSteps=bsQuantCoarseXXX?8:16;
        break;
    }

    Element_Begin1("EcDataPair");

    TESTELSE_SB_SKIP(                                           "bsPcmCodingXXX[paramIdx][setIdx]");
        GroupedPcmData(dataType, bsDataPairXXX, numQuantSteps, dataBands);
    TESTELSE_SB_ELSE(                                           "bsPcmCodingXXX[paramIdx][setIdx]");
        DiffHuffData(dataType, bsDataPairXXX, !usacIndependencyFlag || setIdx, dataBands);
        LsbData(dataType, bsQuantCoarseXXX, dataBands);
        if (bsDataPairXXX)
            LsbData(dataType, bsQuantCoarseXXX, dataBands);
    TESTELSE_SB_END();

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::SymmetryData(ec_data_type dataType, int8s (&aTmp)[2], int8u lav)
{
    Element_Begin1("SymmetryData");

    int16s sumVal=aTmp[0]+aTmp[1];
    int16s diffVal=aTmp[0]-aTmp[1];

    if (sumVal>lav)
    {
        aTmp[0]=(2*lav+1)-sumVal;
        aTmp[1]=-diffVal;
    }
    else
    {
        aTmp[0]=sumVal;
        aTmp[1]=diffVal;
    }

    if (aTmp[0]+aTmp[1]!=0 && dataType!=IPD)
    {
        TEST_SB_SKIP(                                               "bsSymBit[0]");
            aTmp[0]=-aTmp[0];
            aTmp[1]=-aTmp[1];
        TEST_SB_END();
    }

    if (aTmp[0]-aTmp[1]!=0)
    {
        TEST_SB_SKIP(                                               "bsSymBit[1]");
            int8s tmpVal=aTmp[0];
            aTmp[0]=aTmp[1];
            aTmp[1]=tmpVal;
        TEST_SB_END();
    }

    Element_End0();
}

void File_Usac::EnvelopeReshapeHuff(bool (&bsTempShapeEnableChannel)[2])
{
    Element_Begin1("EnvelopeReshapeHuff");

    for (int8u ch=0; ch<2; ch++)
    {
        if (!bsTempShapeEnableChannel[ch])
            continue;

        int i=0;
        while (i<C.mps212Handler.numSlots)
        {
            int8s aTmp[2];
            huff_dec_2D(hcod2DReshape, aTmp, "2Dhuff_dec");
            auto len=aTmp[1]+1;
            if (i+len>C.mps212Handler.numSlots)
            {
                #if MEDIAINFO_CONFORMANCE
                    Fill_Conformance("EnvelopeReshapeHuff GeneralCompliance", "Issue detected while computing 2Dhuff_dec");
                #endif
                C.IFrameParsed=false;
                return;
            }
            i += len;
        }
    }

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::TempShapeData(bool& bsTsdEnable)
{
    Element_Begin1("TempShapeData");

    bsTsdEnable=false;
    if (C.mps212Handler.bsTempShapeConfig==3)
        Get_SB(bsTsdEnable,                                     "bsTsdEnable");
    else if (C.mps212Handler.bsTempShapeConfig==1 || C.mps212Handler.bsTempShapeConfig==2)
    {
        TEST_SB_SKIP(                                           "bsTempShapeEnable");
            //numTempShapeChan has a fixed size of 2 in the USAC context
            bool bsTempShapeEnableChannel[2];
            Get_SB(bsTempShapeEnableChannel[0],                 "bsTempShapeEnableChannel[ch]");
            Get_SB(bsTempShapeEnableChannel[1],                 "bsTempShapeEnableChannel[ch]");

            if (C.mps212Handler.bsTempShapeConfig==2)
                EnvelopeReshapeHuff(bsTempShapeEnableChannel);
        TEST_SB_END();
    }

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::SmgData()
{
    if (!C.mps212Handler.bsHighRatelMode)
        return;

    Element_Begin1("SmgData");

    for (int8u ps=0; ps<C.mps212Handler.numParamSets; ps++)
    {
        int8u bsSmoothMode;
        Get_S1(2, bsSmoothMode,                                 "bsSmoothMode[ps]");
        if (bsSmoothMode>=2)
            Skip_S1(2,                                          "bsSmoothTime[ps]");

        if(bsSmoothMode==3)
        {
            int8u bsFreqResStrideSmg, dataBands;
            Get_S1(2, bsFreqResStrideSmg,                       "bsFreqResStrideSmg[ps]");

            dataBands=(C.mps212Handler.numBands-1)/pb_stride[bsFreqResStrideSmg]+1;
            for (int8u pg=0; pg<dataBands; pg++)
                Skip_SB(                                        "bsSmgData[ps][pg]");
        }
    }

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::TsdData()
{
    Element_Begin1("TsdData");

    int8u bsTsdNumTrSlots, nBitsTsdCW;
    int64u bsTsdCodedPos;
    Get_S1(C.mps212Handler.numSlots==32?4:5, bsTsdNumTrSlots,   "bsTsdNumTrSlots");

    if (C.mps212Handler.numSlots==32)
        nBitsTsdCW=nBitsTsdCWTab32[bsTsdNumTrSlots];
    else //64
        nBitsTsdCW=nBitsTsdCWTab64[bsTsdNumTrSlots];

    Get_S8(nBitsTsdCW, bsTsdCodedPos,                           "bsTsdCodedPos");

    int8u TsdSepData[64]={0};
    //TsdTrPos_dec
    {
        int64u s=bsTsdCodedPos;
        int8u p=bsTsdNumTrSlots+1;

        for (int k=C.mps212Handler.numSlots-1; k>=0; k--)
        {
            if (p>k)
            {
                for (;k>=0; k--)
                    TsdSepData[k]=1;
                break;
            }

            int64u c=k-p+1;
            for (int8u h=2; h<=p; h++)
            {
                c*=k-p+h;
                c/=h;
            }

            if (s>=c)
            {
                s-=c;
                TsdSepData[k]=1;
                if (--p==0)
                    break;
            }
        }
    }

    for (int i = 0; i < C.mps212Handler.numSlots; i++)
        if (TsdSepData[i] == 1)
            Skip_BS(3,                                          "bsTsdTrPhaseData");

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::OttData(bool usacIndependencyFlag)
{
    Element_Begin1("OttData");

    EcData(CLD, 0, 0, C.mps212Handler.numBands, usacIndependencyFlag);
    EcData(ICC, 0, 0, C.mps212Handler.numBands, usacIndependencyFlag);
    if (C.mps212Handler.bsPhaseCoding)
    {
        TEST_SB_SKIP(                                           "bsPhaseMode");
            Skip_SB(                                            "bsOPDSmoothingMode");
            EcData(IPD, 0, 0, C.mps212Handler.bsOttBandsPhase, usacIndependencyFlag);
        TEST_SB_END();
    }

    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::Mps212Data(bool usacIndependencyFlag)
{
    bool bsTsdEnable;
    switch (C.coreSbrFrameLengthIndex)
    {
    case 2:
    case 3:
        C.mps212Handler.numSlots=32;
        break;
    case 4:
        C.mps212Handler.numSlots=64;
        break;
    default:
        #if MEDIAINFO_CONFORMANCE
            Fill_Conformance("Mps212Data", "Mps212Data support not implemented for this coreSbrFrameLengthIndex", bitset8(), Info);
        #endif
        C.IFrameParsed=false;
        return;
    }

    Element_Begin1("Mps212Data");

    FramingInfo();

    bool usacIndependency_Local=usacIndependencyFlag;
    if (!usacIndependencyFlag)
        Get_SB (usacIndependency_Local,                         "bsIndependencyFlag");

    OttData(usacIndependency_Local);
    SmgData();
    TempShapeData(bsTsdEnable);
    if (bsTsdEnable)
        TsdData();
    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::UsacLfeElement(bool usacIndependencyFlag)
{
    Element_Begin1("UsacLfeElement");
        //fdChannelStream(0, false, false, false, usacIndependencyFlag);
        #if MEDIAINFO_CONFORMANCE
            Fill_Conformance("UsacLfeElement", "UsacLfeElement support not implemented", bitset8(), Info);
        #endif
        C.IFrameParsed=false;
    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::UsacExtElement(size_t elemIdx, bool usacIndependencyFlag)
{
    Element_Begin1("UsacExtElement");
    int8u usacExtElementType;
    usacExtElementType=C.usacElements[elemIdx].usacElementType>>2;
    Element_Info1C(usacExtElementType<ID_EXT_ELE_Max, usacExtElementType_IdNames[usacExtElementType]);
    bool usacExtElementPresent;
    Get_SB (usacExtElementPresent,                              "usacExtElementPresent");
    if (usacExtElementPresent)
    {
        int32u usacExtElementPayloadLength;
        bool usacExtElementUseDefaultLength;;
        Get_SB (usacExtElementUseDefaultLength,                 "usacExtElementUseDefaultLength");
        if (usacExtElementUseDefaultLength)
        {
            #if MEDIAINFO_CONFORMANCE
                if (usacExtElementType == ID_EXT_ELE_AUDIOPREROLL)
                    Fill_Conformance("UsacExtElement usacExtElementUseDefaultLength", "AudioPreRoll usacExtElementUseDefaultLength is 1 but only 0 is allowed");
            #endif
            usacExtElementPayloadLength=C.usacElements[elemIdx].usacExtElementDefaultLength;
        }
        else
        {
            Get_S4 (8, usacExtElementPayloadLength,             "usacExtElementPayloadLength");
            if (usacExtElementPayloadLength==0xFF)
            {
                Get_S4 (16, usacExtElementPayloadLength,        "usacExtElementPayloadLength");
                usacExtElementPayloadLength+=255-2;
            }
        }
        if (C.usacElements[elemIdx].usacExtElementPayloadFrag)
        {
            Skip_SB(                                            "usacExtElementStart");
            Skip_SB(                                            "usacExtElementStop");
        }

        #if MEDIAINFO_CONFORMANCE
            if (usacExtElementType == ID_EXT_ELE_AUDIOPREROLL)
            {
                if (IsParsingRaw > 1)
                    Fill_Conformance("UsacExtElement usacExtElementPresent", "AudioPreRoll usacExtElementPresent is 1 for AudioPreRoll inside AudioPreRoll");
                else if (!usacExtElementPayloadLength)
                {
                    F.numPreRollFrames = 0;
                    if (!Frame_Count && IsParsingRaw <= 1)
                        numPreRollFrames_Check(Conf, 0, "AudioPreRoll numPreRollFrames");
                }
            }
        #endif
        if (usacExtElementPayloadLength)
        {
            usacExtElementPayloadLength*=8;
            if (usacExtElementPayloadLength>Data_BS_Remain())
            {
                Trusted_IsNot("Too big");
                Element_End0();
                return;
            }
            auto B=BS_Bookmark(usacExtElementPayloadLength);
            switch (usacExtElementType)
            {
                case ID_EXT_ELE_AUDIOPREROLL                    : AudioPreRoll(); break;
                default:
                    Skip_BS(usacExtElementPayloadLength,        usacExtElementType==ID_EXT_ELE_FILL?"(Not parsed)":"Unknown");
            }
            #pragma warning (suppress : 6385) //Visual Studio fail to detect 'usacExtElementType<ID_EXT_ELE_Max' check when it is inside function parameter and warns about reading invalid data
            BS_Bookmark(B, usacExtElementType<ID_EXT_ELE_Max?string(usacExtElementType_Names[usacExtElementType]):("usacExtElementType"+to_string(usacExtElementType)));
        }
    }
    else
    {
        #if MEDIAINFO_CONFORMANCE
            if (usacIndependencyFlag && usacExtElementType == ID_EXT_ELE_AUDIOPREROLL && IsParsingRaw == 1 && roll_distance_FramePos_IsPresent && !*roll_distance_FramePos_IsPresent)
            {
                Fill_Conformance("Crosscheck sbgp roll_distance", "MP4 sbgp is not present and this is an independent frame (IF), seeking is not optimal", bitset8(), Info);
            }
        #endif
    }
    Element_End0();
}

//---------------------------------------------------------------------------
void File_Usac::AudioPreRoll()
{
    Element_Begin1("AudioPreRoll");
    int32u configLen;
    escapedValue(configLen, 4, 4, 8,                            "configLen");
    if (configLen)
    {
        configLen*=8;
        if (configLen>Data_BS_Remain())
        {
            Trusted_IsNot("Too big");
            Element_End0();
            C.IFrameParsed=false;
            return;
        }
        if (IsParsingRaw<=1)
        {
            Element_Begin1("Config");
            auto B=BS_Bookmark(configLen);
            UsacConfig(B.BitsNotIncluded);
            if (!Trusted_Get())
                C.IFrameParsed=false;
            BS_Bookmark(B, "AudioPreRoll UsacConfig");
            Element_End0();
        }
        else
        {
            //No nested in nested
            Skip_BS(configLen,                                  "Config");
        }
    }
    else
    {
        if (IsParsingRaw <= 1)
            C = Conf; //Using default conf if there is no replacing conf
        #if MEDIAINFO_CONFORMANCE
            if (IsParsingRaw <= 1)
                Fill_Conformance("AudioPreRoll configLen", "configLen is 0 but it is recommended to have a preroll config", bitset8(), Warning);
        #endif
    }
    Skip_SB(                                                    "applyCrossfade");
    Skip_SB(                                                    "reserved");
    escapedValue(F.numPreRollFrames, 2, 4, 0,                   "numPreRollFrames");
    #if MEDIAINFO_CONFORMANCE
        numPreRollFrames_Check(C, F.numPreRollFrames, "AudioPreRoll numPreRollFrames");
    #endif
    for (int32u frameIdx=0; frameIdx<F.numPreRollFrames; frameIdx++)
    {
        Element_Begin1("PreRollFrame");
            int32u auLen;
            escapedValue(auLen, 16, 16, 0,                      "auLen");
            auLen*=8;
            if (auLen)
            {
                if (auLen>Data_BS_Remain())
                {
                    Trusted_IsNot("Too big");
                    Element_End0();
                    C.IFrameParsed=false;
                    break;
                }
                if (IsParsingRaw<=1)
                {
                    auto FSav=F;
                    IsParsingRaw+=frameIdx+1;
                    Element_Begin1("AccessUnit");
                    auto B=BS_Bookmark(auLen);
                    UsacFrame(B.BitsNotIncluded);
                    if (!Trusted_Get())
                        C.IFrameParsed=false;
                    BS_Bookmark(B, "UsacFrame");
                    Element_End0();
                    IsParsingRaw-=frameIdx+1;
                    F=FSav;
                }
                else
                {
                    //No nested in nested
                    Skip_BS(auLen,                              "AccessUnit");
                }
            }
            else
            {
                #if MEDIAINFO_CONFORMANCE
                    Fill_Conformance("AudioPreRoll auLen", "auLen is 0 but preroll frame shall not be empty");
                #endif
            }
        Element_End0();
    }
    Element_End0();
    if (!Trusted_Get())
    {
        C=Conf; //If there was an issue in the Preroll parsing, we disable the parsing of next frame but we take the default config for catching next preroll
        C.IFrameParsed=false;
    }
}

//---------------------------------------------------------------------------
#endif //MEDIAINFO_TRACE || MEDIAINFO_CONFORMANCE

//***************************************************************************
// Utils
//***************************************************************************

//---------------------------------------------------------------------------
void File_Usac::escapedValue(int32u &Value, int8u nBits1, int8u nBits2, int8u nBits3, const char* Name)
{
    Element_Begin1(Name);
    Get_S4(nBits1, Value,                                       "nBits1");
    if (Value==((1<<nBits1)-1))
    {
        int32u ValueAdd;
        Get_S4(nBits2, ValueAdd,                                "nBits2");
        Value+=ValueAdd;
        if (nBits3 && ValueAdd==((1<<nBits2)-1))
        {
            Get_S4(nBits3, ValueAdd,                            "nBits3");
            Value+=ValueAdd;
        }
    }
    Element_Info1(Value);
    Element_End0();
}

//***************************************************************************
// C++
//***************************************************************************

} //NameSpace

#endif //defined(MEDIAINFO_AAC_YES) || defined(MEDIAINFO_MPEGH3DA_YES)
