big merge

This commit is contained in:
Philippe G
2021-12-18 21:04:23 -08:00
parent 955692f8ad
commit 898998efb0
583 changed files with 84472 additions and 1965 deletions

View File

@@ -0,0 +1,213 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: aaccommon.h,v 1.1 2005/02/26 01:47:34 jrecker Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* aaccommon.h - implementation-independent API's, datatypes, and definitions
**************************************************************************************/
#ifndef _AACCOMMON_H
#define _AACCOMMON_H
#ifdef ESP8266
# include "pgmspace.h"
#elif defined(ESP_PLATFORM) && __has_include(<pgm_space.h>)
# include <pgm_space.h>
#else
# define PROGMEM
# define pgm_read_byte(addr) (*(const unsigned char *)(addr))
# define pgm_read_word(addr) (*(const unsigned short *)(addr))
#endif
// Can't fit in ESP8266 RAM
#ifndef ESP8266
#define AAC_ENABLE_SBR 1
#endif
#pragma GCC optimize ("O3")
#include "aacdec.h"
#include "statname.h"
/* 12-bit syncword */
#define SYNCWORDH 0xff
#define SYNCWORDL 0xf0
#define MAX_NCHANS_ELEM 2 /* max number of channels in any single bitstream element (SCE,CPE,CCE,LFE) */
#define ADTS_HEADER_BYTES 7
#define NUM_SAMPLE_RATES 12
#define NUM_DEF_CHAN_MAPS 8
#define NUM_ELEMENTS 8
#define MAX_NUM_PCE_ADIF 16
#define MAX_WIN_GROUPS 8
#define MAX_SFB_SHORT 15
#define MAX_SF_BANDS (MAX_SFB_SHORT*MAX_WIN_GROUPS) /* worst case = 15 sfb's * 8 windows for short block */
#define MAX_MS_MASK_BYTES ((MAX_SF_BANDS + 7) >> 3)
#define MAX_PRED_SFB 41
#define MAX_TNS_FILTERS 8
#define MAX_TNS_COEFS 60
#define MAX_TNS_ORDER 20
#define MAX_PULSES 4
#define MAX_GAIN_BANDS 3
#define MAX_GAIN_WIN 8
#define MAX_GAIN_ADJUST 7
#define NSAMPS_LONG 1024
#define NSAMPS_SHORT 128
#define NUM_SYN_ID_BITS 3
#define NUM_INST_TAG_BITS 4
#define EXT_SBR_DATA 0x0d
#define EXT_SBR_DATA_CRC 0x0e
#define IS_ADIF(p) ((p)[0] == 'A' && (p)[1] == 'D' && (p)[2] == 'I' && (p)[3] == 'F')
#define GET_ELE_ID(p) ((AACElementID)(*(p) >> (8-NUM_SYN_ID_BITS)))
/* AAC file format */
enum {
AAC_FF_Unknown = 0, /* should be 0 on init */
AAC_FF_ADTS = 1,
AAC_FF_ADIF = 2,
AAC_FF_RAW = 3
};
/* syntactic element type */
enum {
AAC_ID_INVALID = -1,
AAC_ID_SCE = 0,
AAC_ID_CPE = 1,
AAC_ID_CCE = 2,
AAC_ID_LFE = 3,
AAC_ID_DSE = 4,
AAC_ID_PCE = 5,
AAC_ID_FIL = 6,
AAC_ID_END = 7
};
typedef struct _AACDecInfo {
/* pointers to platform-specific state information */
void *psInfoBase; /* baseline MPEG-4 LC decoding */
void *psInfoSBR; /* MPEG-4 SBR decoding */
/* raw decoded data, before rounding to 16-bit PCM (for postprocessing such as SBR) */
void *rawSampleBuf[AAC_MAX_NCHANS];
int rawSampleBytes;
int rawSampleFBits;
/* fill data (can be used for processing SBR or other extensions) */
unsigned char *fillBuf;
int fillCount;
int fillExtType;
/* block information */
int prevBlockID;
int currBlockID;
int currInstTag;
int sbDeinterleaveReqd[MAX_NCHANS_ELEM];
int adtsBlocksLeft;
/* user-accessible info */
int bitRate;
int nChans;
int sampRate;
int profile;
int format;
int sbrEnabled;
int tnsUsed;
int pnsUsed;
int frameCount;
} AACDecInfo;
/* decoder functions which must be implemented for each platform */
AACDecInfo *AllocateBuffers(void);
AACDecInfo *AllocateBuffersPre(void **space, int *len);
void FreeBuffers(AACDecInfo *aacDecInfo);
void ClearBuffer(void *buf, int nBytes);
int UnpackADTSHeader(AACDecInfo *aacDecInfo, unsigned char **buf, int *bitOffset, int *bitsAvail);
int GetADTSChannelMapping(AACDecInfo *aacDecInfo, unsigned char *buf, int bitOffset, int bitsAvail);
int UnpackADIFHeader(AACDecInfo *aacDecInfo, unsigned char **buf, int *bitOffset, int *bitsAvail);
int SetRawBlockParams(AACDecInfo *aacDecInfo, int copyLast, int nChans, int sampRate, int profile);
int PrepareRawBlock(AACDecInfo *aacDecInfo);
int FlushCodec(AACDecInfo *aacDecInfo);
int DecodeNextElement(AACDecInfo *aacDecInfo, unsigned char **buf, int *bitOffset, int *bitsAvail);
int DecodeNoiselessData(AACDecInfo *aacDecInfo, unsigned char **buf, int *bitOffset, int *bitsAvail, int ch);
int Dequantize(AACDecInfo *aacDecInfo, int ch);
int StereoProcess(AACDecInfo *aacDecInfo);
int DeinterleaveShortBlocks(AACDecInfo *aacDecInfo, int ch);
int PNS(AACDecInfo *aacDecInfo, int ch);
int TNSFilter(AACDecInfo *aacDecInfo, int ch);
int IMDCT(AACDecInfo *aacDecInfo, int ch, int chBase, short *outbuf);
/* SBR specific functions */
int InitSBR(AACDecInfo *aacDecInfo);
int InitSBRPre(AACDecInfo *aacDecInfo, void **ptr, int *sz);
void FreeSBR(AACDecInfo *aacDecInfo);
int DecodeSBRBitstream(AACDecInfo *aacDecInfo, int chBase);
int DecodeSBRData(AACDecInfo *aacDecInfo, int chBase, short *outbuf);
int FlushCodecSBR(AACDecInfo *aacDecInfo);
/* aactabs.c - global ROM tables */
extern const int sampRateTab[NUM_SAMPLE_RATES];
extern const int predSFBMax[NUM_SAMPLE_RATES];
extern const int channelMapTab[NUM_DEF_CHAN_MAPS];
extern const int elementNumChans[NUM_ELEMENTS];
extern const unsigned /*char*/ int sfBandTotalShort[NUM_SAMPLE_RATES];
extern const unsigned /*char*/ int sfBandTotalLong[NUM_SAMPLE_RATES];
extern const int sfBandTabShortOffset[NUM_SAMPLE_RATES];
extern const /*short*/ int sfBandTabShort[76];
extern const int sfBandTabLongOffset[NUM_SAMPLE_RATES];
extern const /*short*/ int sfBandTabLong[325];
extern const int tnsMaxBandsShortOffset[AAC_NUM_PROFILES];
extern const unsigned /*char*/ int tnsMaxBandsShort[2*NUM_SAMPLE_RATES];
extern const unsigned /*char*/ int tnsMaxOrderShort[AAC_NUM_PROFILES];
extern const int tnsMaxBandsLongOffset[AAC_NUM_PROFILES];
extern const unsigned /*char*/ int tnsMaxBandsLong[2*NUM_SAMPLE_RATES];
extern const unsigned /*char*/ int tnsMaxOrderLong[AAC_NUM_PROFILES];
#endif /* _AACCOMMON_H */

View File

@@ -0,0 +1,476 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: aacdec.c,v 1.1 2005/02/26 01:47:31 jrecker Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com)
* February 2005
*
* aacdec.c - platform-independent top level decoder API
**************************************************************************************/
#include "aaccommon.h"
//#include "profile.h"
#define PROFILE_START(x)
#define PROFILE_END()
/**************************************************************************************
* Function: AACInitDecoder
*
* Description: allocate memory for platform-specific data
* clear all the user-accessible fields
* initialize SBR decoder if enabled
*
* Inputs: none
*
* Outputs: none
*
* Return: handle to AAC decoder instance, 0 if malloc fails
**************************************************************************************/
HAACDecoder AACInitDecoder(void)
{
AACDecInfo *aacDecInfo;
aacDecInfo = AllocateBuffers();
if (!aacDecInfo)
return 0;
#ifdef AAC_ENABLE_SBR
if (InitSBR(aacDecInfo)) {
AACFreeDecoder(aacDecInfo);
return 0;
}
#endif
return (HAACDecoder)aacDecInfo;
}
HAACDecoder AACInitDecoderPre(void *ptr, int sz)
{
AACDecInfo *aacDecInfo;
aacDecInfo = AllocateBuffersPre(&ptr, &sz);
if (!aacDecInfo)
return 0;
#ifdef AAC_ENABLE_SBR
if (InitSBRPre(aacDecInfo, &ptr, &sz)) {
return 0;
}
#endif
return (HAACDecoder)aacDecInfo;
}
/**************************************************************************************
* Function: AACFreeDecoder
*
* Description: free platform-specific data allocated by AACInitDecoder
* free SBR decoder if enabled
*
* Inputs: valid AAC decoder instance pointer (HAACDecoder)
*
* Outputs: none
*
* Return: none
**************************************************************************************/
void AACFreeDecoder(HAACDecoder hAACDecoder)
{
AACDecInfo *aacDecInfo = (AACDecInfo *)hAACDecoder;
if (!aacDecInfo)
return;
#ifdef AAC_ENABLE_SBR
FreeSBR(aacDecInfo);
#endif
FreeBuffers(aacDecInfo);
}
/**************************************************************************************
* Function: AACFindSyncWord
*
* Description: locate the next byte-alinged sync word in the raw AAC stream
*
* Inputs: buffer to search for sync word
* max number of bytes to search in buffer
*
* Outputs: none
*
* Return: offset to first sync word (bytes from start of buf)
* -1 if sync not found after searching nBytes
**************************************************************************************/
int AACFindSyncWord(unsigned char *buf, int nBytes)
{
int i;
/* find byte-aligned syncword (12 bits = 0xFFF) */
for (i = 0; i < nBytes - 1; i++) {
if ( (buf[i+0] & SYNCWORDH) == SYNCWORDH && (buf[i+1] & SYNCWORDL) == SYNCWORDL )
return i;
}
return -1;
}
/**************************************************************************************
* Function: AACGetLastFrameInfo
*
* Description: get info about last AAC frame decoded (number of samples decoded,
* sample rate, bit rate, etc.)
*
* Inputs: valid AAC decoder instance pointer (HAACDecoder)
* pointer to AACFrameInfo struct
*
* Outputs: filled-in AACFrameInfo struct
*
* Return: none
*
* Notes: call this right after calling AACDecode()
**************************************************************************************/
void AACGetLastFrameInfo(HAACDecoder hAACDecoder, AACFrameInfo *aacFrameInfo)
{
AACDecInfo *aacDecInfo = (AACDecInfo *)hAACDecoder;
if (!aacDecInfo) {
aacFrameInfo->bitRate = 0;
aacFrameInfo->nChans = 0;
aacFrameInfo->sampRateCore = 0;
aacFrameInfo->sampRateOut = 0;
aacFrameInfo->bitsPerSample = 0;
aacFrameInfo->outputSamps = 0;
aacFrameInfo->profile = 0;
aacFrameInfo->tnsUsed = 0;
aacFrameInfo->pnsUsed = 0;
} else {
aacFrameInfo->bitRate = aacDecInfo->bitRate;
aacFrameInfo->nChans = aacDecInfo->nChans;
aacFrameInfo->sampRateCore = aacDecInfo->sampRate;
aacFrameInfo->sampRateOut = aacDecInfo->sampRate * (aacDecInfo->sbrEnabled ? 2 : 1);
aacFrameInfo->bitsPerSample = 16;
aacFrameInfo->outputSamps = aacDecInfo->nChans * AAC_MAX_NSAMPS * (aacDecInfo->sbrEnabled ? 2 : 1);
aacFrameInfo->profile = aacDecInfo->profile;
aacFrameInfo->tnsUsed = aacDecInfo->tnsUsed;
aacFrameInfo->pnsUsed = aacDecInfo->pnsUsed;
}
}
/**************************************************************************************
* Function: AACSetRawBlockParams
*
* Description: set internal state variables for decoding a stream of raw data blocks
*
* Inputs: valid AAC decoder instance pointer (HAACDecoder)
* flag indicating source of parameters
* AACFrameInfo struct, with the members nChans, sampRate, and profile
* optionally filled-in
*
* Outputs: updated codec state
*
* Return: 0 if successful, error code (< 0) if error
*
* Notes: if copyLast == 1, then the codec sets up its internal state (for
* decoding raw blocks) based on previously-decoded ADTS header info
* if copyLast == 0, then the codec uses the values passed in
* aacFrameInfo to configure its internal state (useful when the
* source is MP4 format, for example)
**************************************************************************************/
int AACSetRawBlockParams(HAACDecoder hAACDecoder, int copyLast, AACFrameInfo *aacFrameInfo)
{
AACDecInfo *aacDecInfo = (AACDecInfo *)hAACDecoder;
if (!aacDecInfo)
return ERR_AAC_NULL_POINTER;
aacDecInfo->format = AAC_FF_RAW;
if (copyLast)
return SetRawBlockParams(aacDecInfo, 1, 0, 0, 0);
else
return SetRawBlockParams(aacDecInfo, 0, aacFrameInfo->nChans, aacFrameInfo->sampRateCore, aacFrameInfo->profile);
}
/**************************************************************************************
* Function: AACFlushCodec
*
* Description: flush internal codec state (after seeking, for example)
*
* Inputs: valid AAC decoder instance pointer (HAACDecoder)
*
* Outputs: updated state variables in aacDecInfo
*
* Return: 0 if successful, error code (< 0) if error
**************************************************************************************/
int AACFlushCodec(HAACDecoder hAACDecoder)
{
int ch;
AACDecInfo *aacDecInfo = (AACDecInfo *)hAACDecoder;
if (!aacDecInfo)
return ERR_AAC_NULL_POINTER;
/* reset common state variables which change per-frame
* don't touch state variables which are (usually) constant for entire clip
* (nChans, sampRate, profile, format, sbrEnabled)
*/
aacDecInfo->prevBlockID = AAC_ID_INVALID;
aacDecInfo->currBlockID = AAC_ID_INVALID;
aacDecInfo->currInstTag = -1;
for (ch = 0; ch < MAX_NCHANS_ELEM; ch++)
aacDecInfo->sbDeinterleaveReqd[ch] = 0;
aacDecInfo->adtsBlocksLeft = 0;
aacDecInfo->tnsUsed = 0;
aacDecInfo->pnsUsed = 0;
/* reset internal codec state (flush overlap buffers, etc.) */
FlushCodec(aacDecInfo);
#ifdef AAC_ENABLE_SBR
FlushCodecSBR(aacDecInfo);
#endif
return ERR_AAC_NONE;
}
/**************************************************************************************
* Function: AACDecode
*
* Description: decode AAC frame
*
* Inputs: valid AAC decoder instance pointer (HAACDecoder)
* double pointer to buffer of AAC data
* pointer to number of valid bytes remaining in inbuf
* pointer to outbuf, big enough to hold one frame of decoded PCM samples
* (outbuf must be double-sized if SBR enabled)
*
* Outputs: PCM data in outbuf, interleaved LRLRLR... if stereo
* number of output samples = 1024 per channel (2048 if SBR enabled)
* updated inbuf pointer
* updated bytesLeft
*
* Return: 0 if successful, error code (< 0) if error
*
* Notes: inbuf pointer and bytesLeft are not updated until whole frame is
* successfully decoded, so if ERR_AAC_INDATA_UNDERFLOW is returned
* just call AACDecode again with more data in inbuf
**************************************************************************************/
int AACDecode(HAACDecoder hAACDecoder, unsigned char **inbuf, int *bytesLeft, short *outbuf)
{
int err, offset, bitOffset, bitsAvail;
int ch, baseChan, elementChans;
unsigned char *inptr;
AACDecInfo *aacDecInfo = (AACDecInfo *)hAACDecoder;
#ifdef AAC_ENABLE_SBR
int baseChanSBR, elementChansSBR;
#endif
if (!aacDecInfo)
return ERR_AAC_NULL_POINTER;
/* make local copies (see "Notes" above) */
inptr = *inbuf;
bitOffset = 0;
bitsAvail = (*bytesLeft) << 3;
/* first time through figure out what the file format is */
if (aacDecInfo->format == AAC_FF_Unknown) {
if (bitsAvail < 32)
return ERR_AAC_INDATA_UNDERFLOW;
if (IS_ADIF(inptr)) {
/* unpack ADIF header */
aacDecInfo->format = AAC_FF_ADIF;
err = UnpackADIFHeader(aacDecInfo, &inptr, &bitOffset, &bitsAvail);
if (err)
return err;
} else {
/* assume ADTS by default */
aacDecInfo->format = AAC_FF_ADTS;
}
}
/* if ADTS, search for start of next frame */
if (aacDecInfo->format == AAC_FF_ADTS) {
/* can have 1-4 raw data blocks per ADTS frame (header only present for first one) */
if (aacDecInfo->adtsBlocksLeft == 0) {
offset = AACFindSyncWord(inptr, bitsAvail >> 3);
if (offset < 0)
return ERR_AAC_INDATA_UNDERFLOW;
inptr += offset;
bitsAvail -= (offset << 3);
err = UnpackADTSHeader(aacDecInfo, &inptr, &bitOffset, &bitsAvail);
if (err)
return err;
if (aacDecInfo->nChans == -1) {
/* figure out implicit channel mapping if necessary */
err = GetADTSChannelMapping(aacDecInfo, inptr, bitOffset, bitsAvail);
if (err)
return err;
}
}
aacDecInfo->adtsBlocksLeft--;
} else if (aacDecInfo->format == AAC_FF_RAW) {
err = PrepareRawBlock(aacDecInfo);
if (err)
return err;
}
/* check for valid number of channels */
if (aacDecInfo->nChans > AAC_MAX_NCHANS || aacDecInfo->nChans <= 0)
return ERR_AAC_NCHANS_TOO_HIGH;
/* will be set later if active in this frame */
aacDecInfo->tnsUsed = 0;
aacDecInfo->pnsUsed = 0;
bitOffset = 0;
baseChan = 0;
#ifdef AAC_ENABLE_SBR
baseChanSBR = 0;
#endif
do {
/* parse next syntactic element */
err = DecodeNextElement(aacDecInfo, &inptr, &bitOffset, &bitsAvail);
if (err)
return err;
elementChans = elementNumChans[aacDecInfo->currBlockID];
if (baseChan + elementChans > AAC_MAX_NCHANS)
return ERR_AAC_NCHANS_TOO_HIGH;
/* noiseless decoder and dequantizer */
for (ch = 0; ch < elementChans; ch++) {
PROFILE_START("noiseless decoder");
err = DecodeNoiselessData(aacDecInfo, &inptr, &bitOffset, &bitsAvail, ch);
PROFILE_END();
if (err)
return err;
PROFILE_START("dequant");
if (Dequantize(aacDecInfo, ch))
return ERR_AAC_DEQUANT;
PROFILE_END();
}
PROFILE_START("mid-side and intensity stereo");
/* mid-side and intensity stereo */
if (aacDecInfo->currBlockID == AAC_ID_CPE) {
if (StereoProcess(aacDecInfo))
return ERR_AAC_STEREO_PROCESS;
}
PROFILE_END();
/* PNS, TNS, inverse transform */
for (ch = 0; ch < elementChans; ch++) {
PROFILE_START("PNS");
if (PNS(aacDecInfo, ch))
return ERR_AAC_PNS;
PROFILE_END();
if (aacDecInfo->sbDeinterleaveReqd[ch]) {
/* deinterleave short blocks, if required */
if (DeinterleaveShortBlocks(aacDecInfo, ch))
return ERR_AAC_SHORT_BLOCK_DEINT;
aacDecInfo->sbDeinterleaveReqd[ch] = 0;
}
PROFILE_START("TNS");
if (TNSFilter(aacDecInfo, ch))
return ERR_AAC_TNS;
PROFILE_END();
PROFILE_START("IMDCT");
if (IMDCT(aacDecInfo, ch, baseChan + ch, outbuf))
return ERR_AAC_IMDCT;
PROFILE_END();
}
#ifdef AAC_ENABLE_SBR
if (aacDecInfo->sbrEnabled && (aacDecInfo->currBlockID == AAC_ID_FIL || aacDecInfo->currBlockID == AAC_ID_LFE)) {
if (aacDecInfo->currBlockID == AAC_ID_LFE)
elementChansSBR = elementNumChans[AAC_ID_LFE];
else if (aacDecInfo->currBlockID == AAC_ID_FIL && (aacDecInfo->prevBlockID == AAC_ID_SCE || aacDecInfo->prevBlockID == AAC_ID_CPE))
elementChansSBR = elementNumChans[aacDecInfo->prevBlockID];
else
elementChansSBR = 0;
if (baseChanSBR + elementChansSBR > AAC_MAX_NCHANS)
return ERR_AAC_SBR_NCHANS_TOO_HIGH;
/* parse SBR extension data if present (contained in a fill element) */
if (DecodeSBRBitstream(aacDecInfo, baseChanSBR))
return ERR_AAC_SBR_BITSTREAM;
/* apply SBR */
if (DecodeSBRData(aacDecInfo, baseChanSBR, outbuf))
return ERR_AAC_SBR_DATA;
baseChanSBR += elementChansSBR;
}
#endif
baseChan += elementChans;
} while (aacDecInfo->currBlockID != AAC_ID_END);
/* byte align after each raw_data_block */
if (bitOffset) {
inptr++;
bitsAvail -= (8-bitOffset);
bitOffset = 0;
if (bitsAvail < 0)
return ERR_AAC_INDATA_UNDERFLOW;
}
/* update pointers */
aacDecInfo->frameCount++;
*bytesLeft -= (inptr - *inbuf);
*inbuf = inptr;
return ERR_AAC_NONE;
}

View File

@@ -0,0 +1,175 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: aacdec.h,v 1.8 2005/11/10 00:15:08 margotm Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* aacdec.h - public C API for AAC decoder
**************************************************************************************/
#ifndef _AACDEC_H
#define _AACDEC_H
#if defined(_WIN32) && !defined(_WIN32_WCE)
#
#elif defined(_WIN32) && defined(_WIN32_WCE) && defined(ARM)
#
#elif defined(_WIN32) && defined(WINCE_EMULATOR)
#
#elif defined (__arm) && defined (__ARMCC_VERSION)
#
#elif defined(_SYMBIAN) && defined(__WINS__)
#
#elif defined(__GNUC__) && defined(__arm__)
#
#elif defined(__GNUC__) && defined(__i386__)
#
#elif defined(__APPLE__)
#
#elif defined(__GNUC__) && defined(__amd64__)
#
#elif defined(__GNUC__) && (defined(__powerpc__) || defined(__POWERPC__))
#
#elif defined(_OPENWAVE_SIMULATOR) || defined(_OPENWAVE_ARMULATOR)
#
#elif defined(_SOLARIS) && !defined(__GNUC__)
#
#elif defined(ESP_PLATFORM)
#
#else
#error No platform defined. See valid options in aacdec.h
#endif
#ifndef USE_DEFAULT_STDLIB
#define USE_DEFAULT_STDLIB
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* according to spec (13818-7 section 8.2.2, 14496-3 section 4.5.3)
* max size of input buffer =
* 6144 bits = 768 bytes per SCE or CCE-I
* 12288 bits = 1536 bytes per CPE
* 0 bits = 0 bytes per CCE-D (uses bits from the SCE/CPE/CCE-I it is coupled to)
*/
#ifndef AAC_MAX_NCHANS /* if max channels isn't set in makefile, */
#define AAC_MAX_NCHANS 2 /* set to default max number of channels */
#endif
#define AAC_MAX_NSAMPS 1024
#define AAC_MAINBUF_SIZE (768 * AAC_MAX_NCHANS)
#define AAC_NUM_PROFILES 3
#define AAC_PROFILE_MP 0
#define AAC_PROFILE_LC 1
#define AAC_PROFILE_SSR 2
/* define these to enable decoder features */
#if defined(HELIX_FEATURE_AUDIO_CODEC_AAC_SBR)
#define AAC_ENABLE_SBR
#endif // HELIX_FEATURE_AUDIO_CODEC_AAC_SBR.
#define AAC_ENABLE_MPEG4
enum {
ERR_AAC_NONE = 0,
ERR_AAC_INDATA_UNDERFLOW = -1,
ERR_AAC_NULL_POINTER = -2,
ERR_AAC_INVALID_ADTS_HEADER = -3,
ERR_AAC_INVALID_ADIF_HEADER = -4,
ERR_AAC_INVALID_FRAME = -5,
ERR_AAC_MPEG4_UNSUPPORTED = -6,
ERR_AAC_CHANNEL_MAP = -7,
ERR_AAC_SYNTAX_ELEMENT = -8,
ERR_AAC_DEQUANT = -9,
ERR_AAC_STEREO_PROCESS = -10,
ERR_AAC_PNS = -11,
ERR_AAC_SHORT_BLOCK_DEINT = -12,
ERR_AAC_TNS = -13,
ERR_AAC_IMDCT = -14,
ERR_AAC_NCHANS_TOO_HIGH = -15,
ERR_AAC_SBR_INIT = -16,
ERR_AAC_SBR_BITSTREAM = -17,
ERR_AAC_SBR_DATA = -18,
ERR_AAC_SBR_PCM_FORMAT = -19,
ERR_AAC_SBR_NCHANS_TOO_HIGH = -20,
ERR_AAC_SBR_SINGLERATE_UNSUPPORTED = -21,
ERR_AAC_RAWBLOCK_PARAMS = -22,
ERR_AAC_UNKNOWN = -9999
};
typedef struct _AACFrameInfo {
int bitRate;
int nChans;
int sampRateCore;
int sampRateOut;
int bitsPerSample;
int outputSamps;
int profile;
int tnsUsed;
int pnsUsed;
} AACFrameInfo;
typedef void *HAACDecoder;
/* public C API */
HAACDecoder AACInitDecoder(void);
HAACDecoder AACInitDecoderPre(void *ptr, int sz);
void AACFreeDecoder(HAACDecoder hAACDecoder);
int AACDecode(HAACDecoder hAACDecoder, unsigned char **inbuf, int *bytesLeft, short *outbuf);
int AACFindSyncWord(unsigned char *buf, int nBytes);
void AACGetLastFrameInfo(HAACDecoder hAACDecoder, AACFrameInfo *aacFrameInfo);
int AACSetRawBlockParams(HAACDecoder hAACDecoder, int copyLast, AACFrameInfo *aacFrameInfo);
int AACFlushCodec(HAACDecoder hAACDecoder);
#ifdef HELIX_CONFIG_AAC_GENERATE_TRIGTABS_FLOAT
int AACInitTrigtabsFloat(void);
void AACFreeTrigtabsFloat(void);
#endif
#ifdef __cplusplus
}
#endif
#endif /* _AACDEC_H */

View File

@@ -0,0 +1,157 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: aactabs.c,v 1.1 2005/02/26 01:47:31 jrecker Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com)
* February 2005
*
* aactabs.c - platform-independent tables for AAC decoder (global, read-only)
**************************************************************************************/
#include "aaccommon.h"
/* sample rates (table 4.5.1) */
const int sampRateTab[NUM_SAMPLE_RATES] PROGMEM = {
96000, 88200, 64000, 48000, 44100, 32000,
24000, 22050, 16000, 12000, 11025, 8000
};
/* max scalefactor band for prediction (main profile only) */
const int predSFBMax[NUM_SAMPLE_RATES] PROGMEM = {
33, 33, 38, 40, 40, 40, 41, 41, 37, 37, 37, 34
};
/* channel mapping (table 1.6.3.4) (-1 = unknown, so need to determine mapping based on rules in 8.5.1) */
const int channelMapTab[NUM_DEF_CHAN_MAPS] PROGMEM = {
-1, 1, 2, 3, 4, 5, 6, 8
};
/* number of channels in each element (SCE, CPE, etc.)
* see AACElementID in aaccommon.h
*/
const int elementNumChans[NUM_ELEMENTS] PROGMEM = {
1, 2, 0, 1, 0, 0, 0, 0
};
/* total number of scale factor bands in one window */
const unsigned int /*char*/ sfBandTotalShort[NUM_SAMPLE_RATES] PROGMEM = {
12, 12, 12, 14, 14, 14, 15, 15, 15, 15, 15, 15
};
const unsigned int /*char*/ sfBandTotalLong[NUM_SAMPLE_RATES] PROGMEM = {
41, 41, 47, 49, 49, 51, 47, 47, 43, 43, 43, 40
};
/* scale factor band tables */
const int sfBandTabShortOffset[NUM_SAMPLE_RATES] PROGMEM = {0, 0, 0, 13, 13, 13, 28, 28, 44, 44, 44, 60};
const /*short*/ int sfBandTabShort[76] PROGMEM = {
/* short block 64, 88, 96 kHz [13] (tables 4.5.24, 4.5.26) */
0, 4, 8, 12, 16, 20, 24, 32, 40, 48, 64, 92, 128,
/* short block 32, 44, 48 kHz [15] (table 4.5.15) */
0, 4, 8, 12, 16, 20, 28, 36, 44, 56, 68, 80, 96, 112, 128,
/* short block 22, 24 kHz [16] (table 4.5.22) */
0, 4, 8, 12, 16, 20, 24, 28, 36, 44, 52, 64, 76, 92, 108, 128,
/* short block 11, 12, 16 kHz [16] (table 4.5.20) */
0, 4, 8, 12, 16, 20, 24, 28, 32, 40, 48, 60, 72, 88, 108, 128,
/* short block 8 kHz [16] (table 4.5.18) */
0, 4, 8, 12, 16, 20, 24, 28, 36, 44, 52, 60, 72, 88, 108, 128
};
const int sfBandTabLongOffset[NUM_SAMPLE_RATES] PROGMEM = {0, 0, 42, 90, 90, 140, 192, 192, 240, 240, 240, 284};
const /*short*/ int sfBandTabLong[325] PROGMEM = {
/* long block 88, 96 kHz [42] (table 4.5.25) */
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52,
56, 64, 72, 80, 88, 96, 108, 120, 132, 144, 156, 172, 188, 212,
240, 276, 320, 384, 448, 512, 576, 640, 704, 768, 832, 896, 960, 1024,
/* long block 64 kHz [48] (table 4.5.13) */
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 64,
72, 80, 88, 100, 112, 124, 140, 156, 172, 192, 216, 240, 268, 304, 344, 384,
424, 464, 504, 544, 584, 624, 664, 704, 744, 784, 824, 864, 904, 944, 984, 1024,
/* long block 44, 48 kHz [50] (table 4.5.14) */
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 48, 56, 64, 72, 80, 88,
96, 108, 120, 132, 144, 160, 176, 196, 216, 240, 264, 292, 320, 352, 384, 416, 448,
480, 512, 544, 576, 608, 640, 672, 704, 736, 768, 800, 832, 864, 896, 928, 1024,
/* long block 32 kHz [52] (table 4.5.16) */
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 48, 56, 64, 72, 80, 88, 96,
108, 120, 132, 144, 160, 176, 196, 216, 240, 264, 292, 320, 352, 384, 416, 448, 480, 512,
544, 576, 608, 640, 672, 704, 736, 768, 800, 832, 864, 896, 928, 960, 992, 1024,
/* long block 22, 24 kHz [48] (table 4.5.21) */
0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 52, 60, 68, 76,
84, 92, 100, 108, 116, 124, 136, 148, 160, 172, 188, 204, 220, 240, 260, 284,
308, 336, 364, 396, 432, 468, 508, 552, 600, 652, 704, 768, 832, 896, 960, 1024,
/* long block 11, 12, 16 kHz [44] (table 4.5.19) */
0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 100, 112, 124,
136, 148, 160, 172, 184, 196, 212, 228, 244, 260, 280, 300, 320, 344, 368,
396, 424, 456, 492, 532, 572, 616, 664, 716, 772, 832, 896, 960, 1024,
/* long block 8 kHz [41] (table 4.5.17) */
0, 12, 24, 36, 48, 60, 72, 84, 96, 108, 120, 132, 144, 156,
172, 188, 204, 220, 236, 252, 268, 288, 308, 328, 348, 372, 396, 420,
448, 476, 508, 544, 580, 620, 664, 712, 764, 820, 880, 944, 1024
};
/* TNS max bands (table 4.139) and max order (table 4.138) */
const int tnsMaxBandsShortOffset[AAC_NUM_PROFILES] PROGMEM = {0, 0, 12};
const unsigned /*char*/ int tnsMaxBandsShort[2*NUM_SAMPLE_RATES] PROGMEM = {
9, 9, 10, 14, 14, 14, 14, 14, 14, 14, 14, 14, /* short block, Main/LC */
7, 7, 7, 6, 6, 6, 7, 7, 8, 8, 8, 7 /* short block, SSR */
};
const unsigned /*char*/ int tnsMaxOrderShort[AAC_NUM_PROFILES] PROGMEM = {7, 7, 7};
const int tnsMaxBandsLongOffset[AAC_NUM_PROFILES] PROGMEM = {0, 0, 12};
const unsigned int /*char*/ tnsMaxBandsLong[2*NUM_SAMPLE_RATES] PROGMEM = {
31, 31, 34, 40, 42, 51, 46, 46, 42, 42, 42, 39, /* long block, Main/LC */
28, 28, 27, 26, 26, 26, 29, 29, 23, 23, 23, 19, /* long block, SSR */
};
const unsigned /*char*/ int tnsMaxOrderLong[AAC_NUM_PROFILES] PROGMEM = {20, 12, 12};

View File

@@ -0,0 +1,638 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: assembly.h,v 1.7 2005/11/10 00:04:40 margotm Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* assembly.h - inline assembly language functions and prototypes
*
* MULSHIFT32(x, y) signed multiply of two 32-bit integers (x and y),
* returns top 32-bits of 64-bit result
* CLIPTOSHORT(x) convert 32-bit integer to 16-bit short,
* clipping to [-32768, 32767]
* FASTABS(x) branchless absolute value of signed integer x
* CLZ(x) count leading zeros on signed integer x
* MADD64(sum64, x, y) 64-bit multiply accumulate: sum64 += (x*y)
**************************************************************************************/
#ifndef _ASSEMBLY_H
#define _ASSEMBLY_H
/* toolchain: MSFT Visual C++
* target architecture: x86
*/
#if (defined (_WIN32) && !defined (_WIN32_WCE)) || (defined (__WINS__) && defined (_SYMBIAN)) || (defined (WINCE_EMULATOR)) || (defined (_OPENWAVE_SIMULATOR))
#pragma warning( disable : 4035 ) /* complains about inline asm not returning a value */
static __inline int MULSHIFT32(int x, int y)
{
__asm {
mov eax, x
imul y
mov eax, edx
}
}
static __inline short CLIPTOSHORT(int x)
{
int sign;
/* clip to [-32768, 32767] */
sign = x >> 31;
if (sign != (x >> 15))
x = sign ^ ((1 << 15) - 1);
return (short)x;
}
static __inline int FASTABS(int x)
{
int sign;
sign = x >> (sizeof(int) * 8 - 1);
x ^= sign;
x -= sign;
return x;
}
static __inline int CLZ(int x)
{
int numZeros;
if (!x)
return 32;
/* count leading zeros with binary search */
numZeros = 1;
if (!((unsigned int)x >> 16)) { numZeros += 16; x <<= 16; }
if (!((unsigned int)x >> 24)) { numZeros += 8; x <<= 8; }
if (!((unsigned int)x >> 28)) { numZeros += 4; x <<= 4; }
if (!((unsigned int)x >> 30)) { numZeros += 2; x <<= 2; }
numZeros -= ((unsigned int)x >> 31);
return numZeros;
}
#ifdef __CW32__
typedef long long Word64;
#else
typedef __int64 Word64;
#endif
typedef union _U64 {
Word64 w64;
struct {
/* x86 = little endian */
unsigned int lo32;
signed int hi32;
} r;
} U64;
/* returns 64-bit value in [edx:eax] */
static __inline Word64 MADD64(Word64 sum64, int x, int y)
{
#if (defined (_SYMBIAN_61_) || defined (_SYMBIAN_70_)) && defined (__WINS__) && !defined (__CW32__)
/* Workaround for the Symbian emulator because of non existing longlong.lib and
* hence __allmul not defined. */
__asm {
mov eax, x
imul y
add dword ptr sum64, eax
adc dword ptr sum64 + 4, edx
}
#else
sum64 += (Word64)x * (Word64)y;
#endif
return sum64;
}
/* toolchain: MSFT Embedded Visual C++
* target architecture: ARM v.4 and above (require 'M' type processor for 32x32->64 multiplier)
*/
#elif defined (_WIN32) && defined (_WIN32_WCE) && defined (ARM)
static __inline short CLIPTOSHORT(int x)
{
int sign;
/* clip to [-32768, 32767] */
sign = x >> 31;
if (sign != (x >> 15))
x = sign ^ ((1 << 15) - 1);
return (short)x;
}
static __inline int FASTABS(int x)
{
int sign;
sign = x >> (sizeof(int) * 8 - 1);
x ^= sign;
x -= sign;
return x;
}
static __inline int CLZ(int x)
{
int numZeros;
if (!x)
return 32;
/* count leading zeros with binary search (function should be 17 ARM instructions total) */
numZeros = 1;
if (!((unsigned int)x >> 16)) { numZeros += 16; x <<= 16; }
if (!((unsigned int)x >> 24)) { numZeros += 8; x <<= 8; }
if (!((unsigned int)x >> 28)) { numZeros += 4; x <<= 4; }
if (!((unsigned int)x >> 30)) { numZeros += 2; x <<= 2; }
numZeros -= ((unsigned int)x >> 31);
return numZeros;
}
/* implemented in asmfunc.s */
#ifdef __cplusplus
extern "C" {
#endif
typedef __int64 Word64;
typedef union _U64 {
Word64 w64;
struct {
/* ARM WinCE = little endian */
unsigned int lo32;
signed int hi32;
} r;
} U64;
/* manual name mangling for just this platform (must match labels in .s file) */
#define MULSHIFT32 raac_MULSHIFT32
#define MADD64 raac_MADD64
int MULSHIFT32(int x, int y);
Word64 MADD64(Word64 sum64, int x, int y);
#ifdef __cplusplus
}
#endif
/* toolchain: ARM ADS or RealView
* target architecture: ARM v.4 and above (requires 'M' type processor for 32x32->64 multiplier)
*/
#elif defined (XXX__arm) && defined (__ARMCC_VERSION)
static __inline int MULSHIFT32(int x, int y)
{
/* rules for smull RdLo, RdHi, Rm, Rs:
* RdHi != Rm
* RdLo != Rm
* RdHi != RdLo
*/
int zlow;
__asm {
smull zlow,y,x,y
}
return y;
}
static __inline short CLIPTOSHORT(int x)
{
int sign;
/* clip to [-32768, 32767] */
sign = x >> 31;
if (sign != (x >> 15))
x = sign ^ ((1 << 15) - 1);
return (short)x;
}
static __inline int FASTABS(int x)
{
int sign;
sign = x >> (sizeof(int) * 8 - 1);
x ^= sign;
x -= sign;
return x;
}
static __inline int CLZ(int x)
{
int numZeros;
if (!x)
return 32;
/* count leading zeros with binary search (function should be 17 ARM instructions total) */
numZeros = 1;
if (!((unsigned int)x >> 16)) { numZeros += 16; x <<= 16; }
if (!((unsigned int)x >> 24)) { numZeros += 8; x <<= 8; }
if (!((unsigned int)x >> 28)) { numZeros += 4; x <<= 4; }
if (!((unsigned int)x >> 30)) { numZeros += 2; x <<= 2; }
numZeros -= ((unsigned int)x >> 31);
return numZeros;
/* ARM code would look like this, but do NOT use inline asm in ADS for this,
because you can't safely use the status register flags intermixed with C code
__asm {
mov numZeros, #1
tst x, 0xffff0000
addeq numZeros, numZeros, #16
moveq x, x, lsl #16
tst x, 0xff000000
addeq numZeros, numZeros, #8
moveq x, x, lsl #8
tst x, 0xf0000000
addeq numZeros, numZeros, #4
moveq x, x, lsl #4
tst x, 0xc0000000
addeq numZeros, numZeros, #2
moveq x, x, lsl #2
sub numZeros, numZeros, x, lsr #31
}
*/
/* reference:
numZeros = 0;
while (!(x & 0x80000000)) {
numZeros++;
x <<= 1;
}
*/
}
typedef __int64 Word64;
typedef union _U64 {
Word64 w64;
struct {
/* ARM ADS = little endian */
unsigned int lo32;
signed int hi32;
} r;
} U64;
static __inline Word64 MADD64(Word64 sum64, int x, int y)
{
U64 u;
u.w64 = sum64;
__asm {
smlal u.r.lo32, u.r.hi32, x, y
}
return u.w64;
}
/* toolchain: ARM gcc
* target architecture: ARM v.4 and above (requires 'M' type processor for 32x32->64 multiplier)
*/
#elif defined(__GNUC__) && defined(XXXX__arm__)
static inline int MULSHIFT32(int x, int y)
{
int zlow;
asm ("smull %0,%1,%2,%3" : "=&r" (zlow), "=r" (y) : "r" (x), "1" (y) : "cc");
return y;
}
/*
static inline short CLIPTOSHORT(int x)
{
int sign;
// clip to [-32768, 32767] //
sign = x >> 31;
if (sign != (x >> 15))
x = sign ^ ((1 << 15) - 1);
return (short)x;
}
*/
static inline short CLIPTOSHORT(int x)
{
asm ("ssat %0, #16, %1" : "=r" (x) : "r" (x));
return x;
}
/* From coder.h, ORIGINAL:
clip to [-2^n, 2^n-1], valid range of n = [1, 30]
//TODO (FB) Is there a better way ?
*/
#define CLIP_2N(y, n) { \
int sign = (y) >> 31; \
if (sign != (y) >> (n)) { \
(y) = sign ^ ((1 << (n)) - 1); \
} \
}
/* From coder.h, ORIGINAL:
do y <<= n, clipping to range [-2^30, 2^30 - 1] (i.e. output has one guard bit)
*/
//TODO (FB) Is there a better way ?
#define CLIP_2N_SHIFT(y, n) { \
int sign = (y) >> 31; \
if (sign != (y) >> (30 - (n))) { \
(y) = sign ^ (0x3fffffff); \
} else { \
(y) = (y) << (n); \
} \
}
#define FASTABS(x) abs(x) //FB
#define CLZ(x) __builtin_clz(x) //FB
//Reverse byte order (16 bit) //FB
static inline unsigned int REV16( unsigned int value)
{
asm ("rev16 %0, %1" : "=r" (value) : "r" (value) );
return(value);
}
//Reverse byte order (32 bit) //FB
static inline unsigned int REV32( unsigned int value)
{
asm ("rev %0, %1" : "=r" (value) : "r" (value) );
return(value);
}
typedef long long Word64;
typedef union _U64 {
Word64 w64;
struct {
/* little endian */
unsigned int lo32;
signed int hi32;
} r;
} U64;
static inline Word64 MADD64(Word64 sum64, int x, int y)
{
U64 u;
u.w64 = sum64;
asm ("smlal %0,%1,%2,%3" : "+&r" (u.r.lo32), "+&r" (u.r.hi32) : "r" (x), "r" (y) : "cc");
return u.w64;
}
/* toolchain: x86 gcc
* target architecture: x86
*/
#elif defined(__APPLE__) || defined(__GNUC__) && (defined(__i386__) || defined(__amd64__)) || (defined (_SOLARIS) && !defined (__GNUC__) && defined(_SOLARISX86))
typedef long long Word64;
static __inline__ int MULSHIFT32(int x, int y)
{
int z;
z = (Word64)x * (Word64)y >> 32;
return z;
}
static __inline short CLIPTOSHORT(int x)
{
int sign;
/* clip to [-32768, 32767] */
sign = x >> 31;
if (sign != (x >> 15))
x = sign ^ ((1 << 15) - 1);
return (short)x;
}
static __inline int FASTABS(int x)
{
int sign;
sign = x >> (sizeof(int) * 8 - 1);
x ^= sign;
x -= sign;
return x;
}
static __inline int CLZ(int x)
{
int numZeros;
if (!x)
return 32;
/* count leading zeros with binary search (function should be 17 ARM instructions total) */
numZeros = 1;
if (!((unsigned int)x >> 16)) { numZeros += 16; x <<= 16; }
if (!((unsigned int)x >> 24)) { numZeros += 8; x <<= 8; }
if (!((unsigned int)x >> 28)) { numZeros += 4; x <<= 4; }
if (!((unsigned int)x >> 30)) { numZeros += 2; x <<= 2; }
numZeros -= ((unsigned int)x >> 31);
return numZeros;
}
typedef union _U64 {
Word64 w64;
struct {
/* x86 = little endian */
unsigned int lo32;
signed int hi32;
} r;
} U64;
static __inline Word64 MADD64(Word64 sum64, int x, int y)
{
sum64 += (Word64)x * (Word64)y;
return sum64;
}
#elif defined(ESP_PLATFORM) || defined(__GNUC__) && (defined(__powerpc__) || defined(__POWERPC__)) || (defined (_SOLARIS) && !defined (__GNUC__) && !defined (_SOLARISX86))
typedef long long Word64;
static __inline__ int MULSHIFT32(int x, int y)
{
int z;
z = (Word64)x * (Word64)y >> 32;
return z;
}
static __inline short CLIPTOSHORT(int x)
{
int sign;
/* clip to [-32768, 32767] */
sign = x >> 31;
if (sign != (x >> 15))
x = sign ^ ((1 << 15) - 1);
return (short)x;
}
static __inline int FASTABS(int x)
{
int sign;
sign = x >> (sizeof(int) * 8 - 1);
x ^= sign;
x -= sign;
return x;
}
static __inline int CLZ(int x)
{
int numZeros;
if (!x)
return 32;
/* count leading zeros with binary search (function should be 17 ARM instructions total) */
numZeros = 1;
if (!((unsigned int)x >> 16)) { numZeros += 16; x <<= 16; }
if (!((unsigned int)x >> 24)) { numZeros += 8; x <<= 8; }
if (!((unsigned int)x >> 28)) { numZeros += 4; x <<= 4; }
if (!((unsigned int)x >> 30)) { numZeros += 2; x <<= 2; }
numZeros -= ((unsigned int)x >> 31);
return numZeros;
}
typedef union _U64 {
Word64 w64;
struct {
#ifdef __XTENSA__
unsigned int lo32;
signed int hi32;
#else
/* PowerPC = big endian */
signed int hi32;
unsigned int lo32;
#endif
} r;
} U64;
static __inline Word64 MADD64(Word64 sum64, int x, int y)
{
sum64 += (Word64)x * (Word64)y;
return sum64;
}
/* From coder.h, ORIGINAL:
clip to [-2^n, 2^n-1], valid range of n = [1, 30]
//TODO (FB) Is there a better way ?
*/
#define CLIP_2N(y, n) { \
int sign = (y) >> 31; \
if (sign != (y) >> (n)) { \
(y) = sign ^ ((1 << (n)) - 1); \
} \
}
/* From coder.h, ORIGINAL:
do y <<= n, clipping to range [-2^30, 2^30 - 1] (i.e. output has one guard bit)
*/
//TODO (FB) Is there a better way ?
#define CLIP_2N_SHIFT(y, n) { \
int sign = (y) >> 31; \
if (sign != (y) >> (30 - (n))) { \
(y) = sign ^ (0x3fffffff); \
} else { \
(y) = (y) << (n); \
} \
}
//#define FASTABS(x) abs(x) //FB
//#define CLZ(x) __builtin_clz(x) //FB
#else
#error Unsupported platform in assembly.h
#endif /* platforms */
#ifndef CLIP_2N
#define CLIP_2N(y, n) { \
int sign = (y) >> 31; \
if (sign != (y) >> (n)) { \
(y) = sign ^ ((1 << (n)) - 1); \
} \
}
#endif
#ifndef CLIP_2N_SHIFT
/* From coder.h, ORIGINAL:
do y <<= n, clipping to range [-2^30, 2^30 - 1] (i.e. output has one guard bit)
*/
//TODO (FB) Is there a better way ?
#define CLIP_2N_SHIFT(y, n) { \
int sign = (y) >> 31; \
if (sign != (y) >> (30 - (n))) { \
(y) = sign ^ (0x3fffffff); \
} else { \
(y) = (y) << (n); \
} \
}
#endif
#endif /* _ASSEMBLY_H */

View File

@@ -0,0 +1,261 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: bitstream.c,v 1.2 2005/09/27 20:31:11 jrecker Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* bitstream.c - bitstream parsing functions
**************************************************************************************/
#include "bitstream.h"
/**************************************************************************************
* Function: SetBitstreamPointer
*
* Description: initialize bitstream reader
*
* Inputs: pointer to BitStreamInfo struct
* number of bytes in bitstream
* pointer to byte-aligned buffer of data to read from
*
* Outputs: initialized bitstream info struct
*
* Return: none
**************************************************************************************/
void SetBitstreamPointer(BitStreamInfo *bsi, int nBytes, unsigned char *buf)
{
/* init bitstream */
bsi->bytePtr = buf;
bsi->iCache = 0; /* 4-byte unsigned int */
bsi->cachedBits = 0; /* i.e. zero bits in cache */
bsi->nBytes = nBytes;
}
/**************************************************************************************
* Function: RefillBitstreamCache
*
* Description: read new data from bitstream buffer into 32-bit cache
*
* Inputs: pointer to initialized BitStreamInfo struct
*
* Outputs: updated bitstream info struct
*
* Return: none
*
* Notes: only call when iCache is completely drained (resets bitOffset to 0)
* always loads 4 new bytes except when bsi->nBytes < 4 (end of buffer)
* stores data as big-endian in cache, regardless of machine endian-ness
**************************************************************************************/
//Optimized for REV16, REV32 (FB)
static __inline void RefillBitstreamCache(BitStreamInfo *bsi)
{
int nBytes = bsi->nBytes;
if (nBytes >= 4) {
/* optimize for common case, independent of machine endian-ness */
bsi->iCache = (*bsi->bytePtr++) << 24;
bsi->iCache |= (*bsi->bytePtr++) << 16;
bsi->iCache |= (*bsi->bytePtr++) << 8;
bsi->iCache |= (*bsi->bytePtr++);
bsi->cachedBits = 32;
bsi->nBytes -= 4;
} else {
bsi->iCache = 0;
while (nBytes--) {
bsi->iCache |= (*bsi->bytePtr++);
bsi->iCache <<= 8;
}
bsi->iCache <<= ((3 - bsi->nBytes)*8);
bsi->cachedBits = 8*bsi->nBytes;
bsi->nBytes = 0;
}
}
/**************************************************************************************
* Function: GetBits
*
* Description: get bits from bitstream, advance bitstream pointer
*
* Inputs: pointer to initialized BitStreamInfo struct
* number of bits to get from bitstream
*
* Outputs: updated bitstream info struct
*
* Return: the next nBits bits of data from bitstream buffer
*
* Notes: nBits must be in range [0, 31], nBits outside this range masked by 0x1f
* for speed, does not indicate error if you overrun bit buffer
* if nBits == 0, returns 0
**************************************************************************************/
unsigned int GetBits(BitStreamInfo *bsi, int nBits)
{
unsigned int data, lowBits;
nBits &= 0x1f; /* nBits mod 32 to avoid unpredictable results like >> by negative amount */
data = bsi->iCache >> (31 - nBits); /* unsigned >> so zero-extend */
data >>= 1; /* do as >> 31, >> 1 so that nBits = 0 works okay (returns 0) */
bsi->iCache <<= nBits; /* left-justify cache */
bsi->cachedBits -= nBits; /* how many bits have we drawn from the cache so far */
/* if we cross an int boundary, refill the cache */
if (bsi->cachedBits < 0) {
lowBits = -bsi->cachedBits;
RefillBitstreamCache(bsi);
data |= bsi->iCache >> (32 - lowBits); /* get the low-order bits */
bsi->cachedBits -= lowBits; /* how many bits have we drawn from the cache so far */
bsi->iCache <<= lowBits; /* left-justify cache */
}
return data;
}
/**************************************************************************************
* Function: GetBitsNoAdvance
*
* Description: get bits from bitstream, do not advance bitstream pointer
*
* Inputs: pointer to initialized BitStreamInfo struct
* number of bits to get from bitstream
*
* Outputs: none (state of BitStreamInfo struct left unchanged)
*
* Return: the next nBits bits of data from bitstream buffer
*
* Notes: nBits must be in range [0, 31], nBits outside this range masked by 0x1f
* for speed, does not indicate error if you overrun bit buffer
* if nBits == 0, returns 0
**************************************************************************************/
unsigned int GetBitsNoAdvance(BitStreamInfo *bsi, int nBits)
{
unsigned char *buf;
unsigned int data, iCache;
signed int lowBits;
nBits &= 0x1f; /* nBits mod 32 to avoid unpredictable results like >> by negative amount */
data = bsi->iCache >> (31 - nBits); /* unsigned >> so zero-extend */
data >>= 1; /* do as >> 31, >> 1 so that nBits = 0 works okay (returns 0) */
lowBits = nBits - bsi->cachedBits; /* how many bits do we have left to read */
/* if we cross an int boundary, read next bytes in buffer */
if (lowBits > 0) {
iCache = 0;
buf = bsi->bytePtr;
while (lowBits > 0) {
iCache <<= 8;
if (buf < bsi->bytePtr + bsi->nBytes)
iCache |= (unsigned int)*buf++;
lowBits -= 8;
}
lowBits = -lowBits;
data |= iCache >> lowBits;
}
return data;
}
/**************************************************************************************
* Function: AdvanceBitstream
*
* Description: move bitstream pointer ahead
*
* Inputs: pointer to initialized BitStreamInfo struct
* number of bits to advance bitstream
*
* Outputs: updated bitstream info struct
*
* Return: none
*
* Notes: generally used following GetBitsNoAdvance(bsi, maxBits)
**************************************************************************************/
void AdvanceBitstream(BitStreamInfo *bsi, int nBits)
{
nBits &= 0x1f;
if (nBits > bsi->cachedBits) {
nBits -= bsi->cachedBits;
RefillBitstreamCache(bsi);
}
bsi->iCache <<= nBits;
bsi->cachedBits -= nBits;
}
/**************************************************************************************
* Function: CalcBitsUsed
*
* Description: calculate how many bits have been read from bitstream
*
* Inputs: pointer to initialized BitStreamInfo struct
* pointer to start of bitstream buffer
* bit offset into first byte of startBuf (0-7)
*
* Outputs: none
*
* Return: number of bits read from bitstream, as offset from startBuf:startOffset
**************************************************************************************/
int CalcBitsUsed(BitStreamInfo *bsi, unsigned char *startBuf, int startOffset)
{
int bitsUsed;
bitsUsed = (bsi->bytePtr - startBuf) * 8;
bitsUsed -= bsi->cachedBits;
bitsUsed -= startOffset;
return bitsUsed;
}
/**************************************************************************************
* Function: ByteAlignBitstream
*
* Description: bump bitstream pointer to start of next byte
*
* Inputs: pointer to initialized BitStreamInfo struct
*
* Outputs: byte-aligned bitstream BitStreamInfo struct
*
* Return: none
*
* Notes: if bitstream is already byte-aligned, do nothing
**************************************************************************************/
void ByteAlignBitstream(BitStreamInfo *bsi)
{
int offset;
offset = bsi->cachedBits & 0x07;
AdvanceBitstream(bsi, offset);
}

View File

@@ -0,0 +1,74 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: bitstream.h,v 1.1 2005/02/26 01:47:34 jrecker Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* bitstream.h - definitions of bitstream handling functions
**************************************************************************************/
#ifndef _BITSTREAM_H
#define _BITSTREAM_H
#include "aaccommon.h"
/* additional external symbols to name-mangle for static linking */
#define SetBitstreamPointer STATNAME(SetBitstreamPointer)
#define GetBits STATNAME(GetBits)
#define GetBitsNoAdvance STATNAME(GetBitsNoAdvance)
#define AdvanceBitstream STATNAME(AdvanceBitstream)
#define CalcBitsUsed STATNAME(CalcBitsUsed)
#define ByteAlignBitstream STATNAME(ByteAlignBitstream)
typedef struct _BitStreamInfo {
unsigned char *bytePtr;
unsigned int iCache;
int cachedBits;
int nBytes;
} BitStreamInfo;
/* bitstream.c */
void SetBitstreamPointer(BitStreamInfo *bsi, int nBytes, unsigned char *buf);
unsigned int GetBits(BitStreamInfo *bsi, int nBits);
unsigned int GetBitsNoAdvance(BitStreamInfo *bsi, int nBits);
void AdvanceBitstream(BitStreamInfo *bsi, int nBits);
int CalcBitsUsed(BitStreamInfo *bsi, unsigned char *startBuf, int startOffset);
void ByteAlignBitstream(BitStreamInfo *bsi);
#endif /* _BITSTREAM_H */

View File

@@ -0,0 +1,165 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: buffers.c,v 1.1 2005/02/26 01:47:34 jrecker Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* buffers.c - allocation and deallocation of internal AAC decoder buffers
**************************************************************************************/
#if defined(USE_DEFAULT_STDLIB) || defined(ESP_PLATFORM)
#include <stdlib.h>
#else
#include "hlxclib/stdlib.h"
#endif
#include "coder.h"
/**************************************************************************************
* Function: ClearBuffer
*
* Description: fill buffer with 0's
*
* Inputs: pointer to buffer
* number of bytes to fill with 0
*
* Outputs: cleared buffer
*
* Return: none
*
* Notes: slow, platform-independent equivalent to memset(buf, 0, nBytes)
**************************************************************************************/
#include <string.h>
void ClearBuffer(void *buf, int nBytes)
{
/* int i;
unsigned char *cbuf = (unsigned char *)buf;
for (i = 0; i < nBytes; i++)
cbuf[i] = 0;
return;
*/
memset(buf, 0, nBytes);
}
/**************************************************************************************
* Function: AllocateBuffers
*
* Description: allocate all the memory needed for the AAC decoder
*
* Inputs: none
*
* Outputs: none
*
* Return: pointer to AACDecInfo structure, cleared to all 0's (except for
* pointer to platform-specific data structure)
*
* Notes: if one or more mallocs fail, function frees any buffers already
* allocated before returning
**************************************************************************************/
AACDecInfo *AllocateBuffers(void)
{
AACDecInfo *aacDecInfo;
aacDecInfo = (AACDecInfo *)malloc(sizeof(AACDecInfo));
if (!aacDecInfo)
return 0;
ClearBuffer(aacDecInfo, sizeof(AACDecInfo));
aacDecInfo->psInfoBase = malloc(sizeof(PSInfoBase));
if (!aacDecInfo->psInfoBase) {
FreeBuffers(aacDecInfo);
return 0;
}
ClearBuffer(aacDecInfo->psInfoBase, sizeof(PSInfoBase));
return aacDecInfo;
}
AACDecInfo *AllocateBuffersPre(void **ptr, int *sz)
{
AACDecInfo *aacDecInfo;
char *p = (char*)*ptr;
aacDecInfo = (AACDecInfo *)p;
p += (sizeof(AACDecInfo) +7 ) & ~7;
*sz -= (sizeof(AACDecInfo) +7 ) & ~7;
if (*sz < 0)
return 0;
ClearBuffer(aacDecInfo, sizeof(AACDecInfo));
aacDecInfo->psInfoBase = (PSInfoBase*)p;
p += (sizeof(PSInfoBase) + 7) & ~7;
*sz -= (sizeof(PSInfoBase) + 7) & ~7;
if (*sz <0) {
return 0;
}
ClearBuffer(aacDecInfo->psInfoBase, sizeof(PSInfoBase));
*ptr = p;
return aacDecInfo;
}
#ifndef SAFE_FREE
#define SAFE_FREE(x) {if (x) free(x); (x) = 0;} /* helper macro */
#endif
/**************************************************************************************
* Function: FreeBuffers
*
* Description: frees all the memory used by the AAC decoder
*
* Inputs: pointer to initialized AACDecInfo structure
*
* Outputs: none
*
* Return: none
*
* Notes: safe to call even if some buffers were not allocated (uses SAFE_FREE)
**************************************************************************************/
void FreeBuffers(AACDecInfo *aacDecInfo)
{
if (!aacDecInfo)
return;
SAFE_FREE(aacDecInfo->psInfoBase);
SAFE_FREE(aacDecInfo);
}

View File

@@ -0,0 +1,373 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: coder.h,v 1.2 2005/06/27 21:06:00 gwright Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* coder.h - definitions of platform-specific data structures, functions, and tables
**************************************************************************************/
#ifndef _CODER_H
#define _CODER_H
#include "aaccommon.h"
#include "bitstream.h"
#ifndef ASSERT
#if defined(_WIN32) && defined(_M_IX86) && (defined (_DEBUG) || defined (REL_ENABLE_ASSERTS))
#define ASSERT(x) if (!(x)) __asm int 3;
#else
#define ASSERT(x) /* do nothing */
#endif
#endif
#ifndef MAX
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
#define NWINDOWS_LONG 1
#define NWINDOWS_SHORT 8
#define DATA_BUF_SIZE 510 /* max count = 255 + 255 */
#define FILL_BUF_SIZE 269 /* max count = 15 + 255 - 1*/
#define ADIF_COPYID_SIZE 9
#define MAX_COMMENT_BYTES 255
#define MAX_NUM_FCE 15
#define MAX_NUM_SCE 15
#define MAX_NUM_BCE 15
#define MAX_NUM_LCE 3
#define MAX_NUM_ADE 7
#define MAX_NUM_CCE 15
#define CHAN_ELEM_IS_CPE(x) (((x) & 0x10) >> 4) /* bit 4 = SCE/CPE flag */
#define CHAN_ELEM_GET_TAG(x) (((x) & 0x0f) >> 0) /* bits 3-0 = instance tag */
#define CHAN_ELEM_SET_CPE(x) (((x) & 0x01) << 4) /* bit 4 = SCE/CPE flag */
#define CHAN_ELEM_SET_TAG(x) (((x) & 0x0f) << 0) /* bits 3-0 = instance tag */
#define MAX_HUFF_BITS 20
#define HUFFTAB_SPEC_OFFSET 1
/* do y <<= n, clipping to range [-2^30, 2^30 - 1] (i.e. output has one guard bit) */
/*
#define CLIP_2N_SHIFT(y, n) { \
int sign = (y) >> 31; \
if (sign != (y) >> (30 - (n))) { \
(y) = sign ^ (0x3fffffff); \
} else { \
(y) = (y) << (n); \
} \
}
*/
/* clip to [-2^n, 2^n-1], valid range of n = [1, 30] */
/*
#define CLIP_2N(val, n) { \
if ((val) >> 31 != (val) >> (n)) \
(val) = ((val) >> 31) ^ ((1 << (n)) - 1); \
}
*/
#define SF_DQ_OFFSET 15
#define FBITS_OUT_DQ 20
#define FBITS_OUT_DQ_OFF (FBITS_OUT_DQ - SF_DQ_OFFSET) /* number of fraction bits out of dequant, including 2^15 bias */
#define FBITS_IN_IMDCT FBITS_OUT_DQ_OFF /* number of fraction bits into IMDCT */
#define GBITS_IN_DCT4 4 /* min guard bits in for DCT4 */
#define FBITS_LOST_DCT4 1 /* number of fraction bits lost (>> out) in DCT-IV */
#define FBITS_LOST_WND 1 /* number of fraction bits lost (>> out) in synthesis window (neg = gain frac bits) */
#define FBITS_LOST_IMDCT (FBITS_LOST_DCT4 + FBITS_LOST_WND)
#define FBITS_OUT_IMDCT (FBITS_IN_IMDCT - FBITS_LOST_IMDCT)
#define NUM_IMDCT_SIZES 2
/* additional external symbols to name-mangle for static linking */
#define DecodeProgramConfigElement STATNAME(DecodeProgramConfigElement)
#define DecodeHuffmanScalar STATNAME(DecodeHuffmanScalar)
#define DecodeSpectrumLong STATNAME(DecodeSpectrumLong)
#define DecodeSpectrumShort STATNAME(DecodeSpectrumShort)
#define DecodeICSInfo STATNAME(DecodeICSInfo)
#define DCT4 STATNAME(DCT4)
#define R4FFT STATNAME(R4FFT)
#define DecWindowOverlapNoClip STATNAME(DecWindowOverlapNoClip)
#define DecWindowOverlapLongStartNoClip STATNAME(DecWindowOverlapLongStartNoClip)
#define DecWindowOverlapLongStopNoClip STATNAME(DecWindowOverlapLongStopNoClip)
#define DecWindowOverlapShortNoClip STATNAME(DecWindowOverlapShortNoClip)
#define huffTabSpecInfo STATNAME(huffTabSpecInfo)
#define huffTabSpec STATNAME(huffTabSpec)
#define huffTabScaleFactInfo STATNAME(huffTabScaleFactInfo)
#define huffTabScaleFact STATNAME(huffTabScaleFact)
#define cos4sin4tab STATNAME(cos4sin4tab)
#define cos4sin4tabOffset STATNAME(cos4sin4tabOffset)
#define cos1sin1tab STATNAME(cos1sin1tab)
#define sinWindow STATNAME(sinWindow)
#define sinWindowOffset STATNAME(sinWindowOffset)
#define kbdWindow STATNAME(kbdWindow)
#define kbdWindowOffset STATNAME(kbdWindowOffset)
#define bitrevtab STATNAME(bitrevtab)
#define bitrevtabOffset STATNAME(bitrevtabOffset)
#define uniqueIDTab STATNAME(uniqueIDTab)
#define twidTabEven STATNAME(twidTabEven)
#define twidTabOdd STATNAME(twidTabOdd)
typedef struct _HuffInfo {
int maxBits; /* number of bits in longest codeword */
unsigned /*char*/ int count[MAX_HUFF_BITS]; /* count[i] = number of codes with length i+1 bits */
int offset; /* offset into symbol table */
} HuffInfo;
typedef struct _PulseInfo {
unsigned char pulseDataPresent;
unsigned char numPulse;
unsigned char startSFB;
unsigned char offset[MAX_PULSES];
unsigned char amp[MAX_PULSES];
} PulseInfo;
typedef struct _TNSInfo {
unsigned char tnsDataPresent;
unsigned char numFilt[MAX_TNS_FILTERS]; /* max 1 filter each for 8 short windows, or 3 filters for 1 long window */
unsigned char coefRes[MAX_TNS_FILTERS];
unsigned char length[MAX_TNS_FILTERS];
unsigned char order[MAX_TNS_FILTERS];
unsigned char dir[MAX_TNS_FILTERS];
signed char coef[MAX_TNS_COEFS]; /* max 3 filters * 20 coefs for 1 long window, or 1 filter * 7 coefs for each of 8 short windows */
} TNSInfo;
typedef struct _GainControlInfo {
unsigned char gainControlDataPresent;
unsigned char maxBand;
unsigned char adjNum[MAX_GAIN_BANDS][MAX_GAIN_WIN];
unsigned char alevCode[MAX_GAIN_BANDS][MAX_GAIN_WIN][MAX_GAIN_ADJUST];
unsigned char alocCode[MAX_GAIN_BANDS][MAX_GAIN_WIN][MAX_GAIN_ADJUST];
} GainControlInfo;
typedef struct _ICSInfo {
unsigned char icsResBit;
unsigned char winSequence;
unsigned char winShape;
unsigned char maxSFB;
unsigned char sfGroup;
unsigned char predictorDataPresent;
unsigned char predictorReset;
unsigned char predictorResetGroupNum;
unsigned char predictionUsed[MAX_PRED_SFB];
unsigned char numWinGroup;
unsigned char winGroupLen[MAX_WIN_GROUPS];
} ICSInfo;
typedef struct _ADTSHeader {
/* fixed */
unsigned char id; /* MPEG bit - should be 1 */
unsigned char layer; /* MPEG layer - should be 0 */
unsigned char protectBit; /* 0 = CRC word follows, 1 = no CRC word */
unsigned char profile; /* 0 = main, 1 = LC, 2 = SSR, 3 = reserved */
unsigned char sampRateIdx; /* sample rate index range = [0, 11] */
unsigned char privateBit; /* ignore */
unsigned char channelConfig; /* 0 = implicit, >0 = use default table */
unsigned char origCopy; /* 0 = copy, 1 = original */
unsigned char home; /* ignore */
/* variable */
unsigned char copyBit; /* 1 bit of the 72-bit copyright ID (transmitted as 1 bit per frame) */
unsigned char copyStart; /* 1 = this bit starts the 72-bit ID, 0 = it does not */
int frameLength; /* length of frame */
int bufferFull; /* number of 32-bit words left in enc buffer, 0x7FF = VBR */
unsigned char numRawDataBlocks; /* number of raw data blocks in frame */
/* CRC */
int crcCheckWord; /* 16-bit CRC check word (present if protectBit == 0) */
} ADTSHeader;
typedef struct _ADIFHeader {
unsigned char copyBit; /* 0 = no copyright ID, 1 = 72-bit copyright ID follows immediately */
unsigned char origCopy; /* 0 = copy, 1 = original */
unsigned char home; /* ignore */
unsigned char bsType; /* bitstream type: 0 = CBR, 1 = VBR */
int bitRate; /* bitRate: CBR = bits/sec, VBR = peak bits/frame, 0 = unknown */
unsigned char numPCE; /* number of program config elements (max = 16) */
int bufferFull; /* bits left in bit reservoir */
unsigned char copyID[ADIF_COPYID_SIZE]; /* optional 72-bit copyright ID */
} ADIFHeader;
/* sizeof(ProgConfigElement) = 82 bytes (if KEEP_PCE_COMMENTS not defined) */
typedef struct _ProgConfigElement {
unsigned char elemInstTag; /* element instance tag */
unsigned char profile; /* 0 = main, 1 = LC, 2 = SSR, 3 = reserved */
unsigned char sampRateIdx; /* sample rate index range = [0, 11] */
unsigned char numFCE; /* number of front channel elements (max = 15) */
unsigned char numSCE; /* number of side channel elements (max = 15) */
unsigned char numBCE; /* number of back channel elements (max = 15) */
unsigned char numLCE; /* number of LFE channel elements (max = 3) */
unsigned char numADE; /* number of associated data elements (max = 7) */
unsigned char numCCE; /* number of valid channel coupling elements (max = 15) */
unsigned char monoMixdown; /* mono mixdown: bit 4 = present flag, bits 3-0 = element number */
unsigned char stereoMixdown; /* stereo mixdown: bit 4 = present flag, bits 3-0 = element number */
unsigned char matrixMixdown; /* matrix mixdown: bit 4 = present flag, bit 3 = unused,
bits 2-1 = index, bit 0 = pseudo-surround enable */
unsigned char fce[MAX_NUM_FCE]; /* front element channel pair: bit 4 = SCE/CPE flag, bits 3-0 = inst tag */
unsigned char sce[MAX_NUM_SCE]; /* side element channel pair: bit 4 = SCE/CPE flag, bits 3-0 = inst tag */
unsigned char bce[MAX_NUM_BCE]; /* back element channel pair: bit 4 = SCE/CPE flag, bits 3-0 = inst tag */
unsigned char lce[MAX_NUM_LCE]; /* instance tag for LFE elements */
unsigned char ade[MAX_NUM_ADE]; /* instance tag for ADE elements */
unsigned char cce[MAX_NUM_BCE]; /* channel coupling elements: bit 4 = switching flag, bits 3-0 = inst tag */
#ifdef KEEP_PCE_COMMENTS
/* make this optional - if not enabled, decoder will just skip comments */
unsigned char commentBytes;
unsigned char commentField[MAX_COMMENT_BYTES];
#endif
} ProgConfigElement;
/* state info struct for baseline (MPEG-4 LC) decoding */
typedef struct _PSInfoBase {
/* header information */
ADTSHeader fhADTS;
ADIFHeader fhADIF;
ProgConfigElement pce[MAX_NUM_PCE_ADIF];
int dataCount;
unsigned char dataBuf[DATA_BUF_SIZE];
int fillCount;
unsigned char fillBuf[FILL_BUF_SIZE];
/* state information which is the same throughout whole frame */
int nChans;
int useImpChanMap;
int sampRateIdx;
/* state information which can be overwritten by subsequent elements within frame */
ICSInfo icsInfo[MAX_NCHANS_ELEM];
int commonWin;
short scaleFactors[MAX_NCHANS_ELEM][MAX_SF_BANDS];
unsigned char sfbCodeBook[MAX_NCHANS_ELEM][MAX_SF_BANDS];
int msMaskPresent;
unsigned char msMaskBits[MAX_MS_MASK_BYTES];
int pnsUsed[MAX_NCHANS_ELEM];
int pnsLastVal;
int intensityUsed[MAX_NCHANS_ELEM];
PulseInfo pulseInfo[MAX_NCHANS_ELEM];
TNSInfo tnsInfo[MAX_NCHANS_ELEM];
int tnsLPCBuf[MAX_TNS_ORDER];
int tnsWorkBuf[MAX_TNS_ORDER];
GainControlInfo gainControlInfo[MAX_NCHANS_ELEM];
int gbCurrent[MAX_NCHANS_ELEM];
int coef[MAX_NCHANS_ELEM][AAC_MAX_NSAMPS];
#ifdef AAC_ENABLE_SBR
int sbrWorkBuf[MAX_NCHANS_ELEM][AAC_MAX_NSAMPS];
#endif
/* state information which must be saved for each element and used in next frame */
int overlap[AAC_MAX_NCHANS][AAC_MAX_NSAMPS];
int prevWinShape[AAC_MAX_NCHANS];
} PSInfoBase;
/* private implementation-specific functions */
/* decelmnt.c */
int DecodeProgramConfigElement(ProgConfigElement *pce, BitStreamInfo *bsi);
/* huffman.c */
int DecodeHuffmanScalar(const signed short *huffTab, const HuffInfo *huffTabInfo, unsigned int bitBuf, signed int *val);
void DecodeSpectrumLong(PSInfoBase *psi, BitStreamInfo *bsi, int ch);
void DecodeSpectrumShort(PSInfoBase *psi, BitStreamInfo *bsi, int ch);
/* noiseless.c */
void DecodeICSInfo(BitStreamInfo *bsi, ICSInfo *icsInfo, int sampRateIdx);
/* dct4.c */
void DCT4(int tabidx, int *coef, int gb);
/* fft.c */
void R4FFT(int tabidx, int *x);
/* sbrimdct.c */
void DecWindowOverlapNoClip(int *buf0, int *over0, int *out0, int winTypeCurr, int winTypePrev);
void DecWindowOverlapLongStartNoClip(int *buf0, int *over0, int *out0, int winTypeCurr, int winTypePrev);
void DecWindowOverlapLongStopNoClip(int *buf0, int *over0, int *out0, int winTypeCurr, int winTypePrev);
void DecWindowOverlapShortNoClip(int *buf0, int *over0, int *out0, int winTypeCurr, int winTypePrev);
/* hufftabs.c */
extern const HuffInfo huffTabSpecInfo[11];
extern const signed short huffTabSpec[1241];
extern const HuffInfo huffTabScaleFactInfo;
extern const signed short huffTabScaleFact[121];
/* trigtabs.c */
extern const int cos4sin4tabOffset[NUM_IMDCT_SIZES];
extern const int sinWindowOffset[NUM_IMDCT_SIZES];
extern const int kbdWindowOffset[NUM_IMDCT_SIZES];
extern const unsigned char bitrevtab[17 + 129];
extern const int bitrevtabOffset[NUM_IMDCT_SIZES];
#ifdef HELIX_CONFIG_AAC_GENERATE_TRIGTABS_FLOAT
/* trigtabs_fltgen.c */
extern int cos4sin4tab[128 + 1024];
extern int cos1sin1tab[514];
extern int sinWindow[128 + 1024];
extern int kbdWindow[128 + 1024];
extern int twidTabEven[4*6 + 16*6 + 64*6];
extern int twidTabOdd[8*6 + 32*6 + 128*6];
#else
/* trigtabs.c */
extern const int cos4sin4tab[128 + 1024];
extern const int cos1sin1tab[514];
extern const int sinWindow[128 + 1024];
extern const int kbdWindow[128 + 1024];
extern const int twidTabEven[4*6 + 16*6 + 64*6];
extern const int twidTabOdd[8*6 + 32*6 + 128*6];
#endif
#endif /* _CODER_H */

View File

@@ -0,0 +1,337 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: dct4.c,v 1.1 2005/02/26 01:47:34 jrecker Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com)
* February 2005
*
* dct4.c - optimized DCT-IV
**************************************************************************************/
#include "coder.h"
#include "assembly.h"
static const int nmdctTab[NUM_IMDCT_SIZES] PROGMEM = {128, 1024};
static const int postSkip[NUM_IMDCT_SIZES] PROGMEM = {15, 1};
/**************************************************************************************
* Function: PreMultiply
*
* Description: pre-twiddle stage of DCT4
*
* Inputs: table index (for transform size)
* buffer of nmdct samples
*
* Outputs: processed samples in same buffer
*
* Return: none
*
* Notes: minimum 1 GB in, 2 GB out, gains 5 (short) or 8 (long) frac bits
* i.e. gains 2-7= -5 int bits (short) or 2-10 = -8 int bits (long)
* normalization by -1/N is rolled into tables here (see trigtabs.c)
* uses 3-mul, 3-add butterflies instead of 4-mul, 2-add
**************************************************************************************/
static void PreMultiply(int tabidx, int *zbuf1)
{
int i, nmdct, ar1, ai1, ar2, ai2, z1, z2;
int t, cms2, cps2a, sin2a, cps2b, sin2b;
int *zbuf2;
const int *csptr;
nmdct = nmdctTab[tabidx];
zbuf2 = zbuf1 + nmdct - 1;
csptr = cos4sin4tab + cos4sin4tabOffset[tabidx];
/* whole thing should fit in registers - verify that compiler does this */
for (i = nmdct >> 2; i != 0; i--) {
/* cps2 = (cos+sin), sin2 = sin, cms2 = (cos-sin) */
cps2a = *csptr++;
sin2a = *csptr++;
cps2b = *csptr++;
sin2b = *csptr++;
ar1 = *(zbuf1 + 0);
ai2 = *(zbuf1 + 1);
ai1 = *(zbuf2 + 0);
ar2 = *(zbuf2 - 1);
/* gain 2 ints bit from MULSHIFT32 by Q30, but drop 7 or 10 int bits from table scaling of 1/M
* max per-sample gain (ignoring implicit scaling) = MAX(sin(angle)+cos(angle)) = 1.414
* i.e. gain 1 GB since worst case is sin(angle) = cos(angle) = 0.707 (Q30), gain 2 from
* extra sign bits, and eat one in adding
*/
t = MULSHIFT32(sin2a, ar1 + ai1);
z2 = MULSHIFT32(cps2a, ai1) - t;
cms2 = cps2a - 2*sin2a;
z1 = MULSHIFT32(cms2, ar1) + t;
*zbuf1++ = z1; /* cos*ar1 + sin*ai1 */
*zbuf1++ = z2; /* cos*ai1 - sin*ar1 */
t = MULSHIFT32(sin2b, ar2 + ai2);
z2 = MULSHIFT32(cps2b, ai2) - t;
cms2 = cps2b - 2*sin2b;
z1 = MULSHIFT32(cms2, ar2) + t;
*zbuf2-- = z2; /* cos*ai2 - sin*ar2 */
*zbuf2-- = z1; /* cos*ar2 + sin*ai2 */
}
}
/**************************************************************************************
* Function: PostMultiply
*
* Description: post-twiddle stage of DCT4
*
* Inputs: table index (for transform size)
* buffer of nmdct samples
*
* Outputs: processed samples in same buffer
*
* Return: none
*
* Notes: minimum 1 GB in, 2 GB out - gains 2 int bits
* uses 3-mul, 3-add butterflies instead of 4-mul, 2-add
**************************************************************************************/
static void PostMultiply(int tabidx, int *fft1)
{
int i, nmdct, ar1, ai1, ar2, ai2, skipFactor;
int t, cms2, cps2, sin2;
int *fft2;
const int *csptr;
nmdct = nmdctTab[tabidx];
csptr = cos1sin1tab;
skipFactor = postSkip[tabidx];
fft2 = fft1 + nmdct - 1;
/* load coeffs for first pass
* cps2 = (cos+sin), sin2 = sin, cms2 = (cos-sin)
*/
cps2 = *csptr++;
sin2 = *csptr;
csptr += skipFactor;
cms2 = cps2 - 2*sin2;
for (i = nmdct >> 2; i != 0; i--) {
ar1 = *(fft1 + 0);
ai1 = *(fft1 + 1);
ar2 = *(fft2 - 1);
ai2 = *(fft2 + 0);
/* gain 2 ints bit from MULSHIFT32 by Q30
* max per-sample gain = MAX(sin(angle)+cos(angle)) = 1.414
* i.e. gain 1 GB since worst case is sin(angle) = cos(angle) = 0.707 (Q30), gain 2 from
* extra sign bits, and eat one in adding
*/
t = MULSHIFT32(sin2, ar1 + ai1);
*fft2-- = t - MULSHIFT32(cps2, ai1); /* sin*ar1 - cos*ai1 */
*fft1++ = t + MULSHIFT32(cms2, ar1); /* cos*ar1 + sin*ai1 */
cps2 = *csptr++;
sin2 = *csptr;
csptr += skipFactor;
ai2 = -ai2;
t = MULSHIFT32(sin2, ar2 + ai2);
*fft2-- = t - MULSHIFT32(cps2, ai2); /* sin*ar1 - cos*ai1 */
cms2 = cps2 - 2*sin2;
*fft1++ = t + MULSHIFT32(cms2, ar2); /* cos*ar1 + sin*ai1 */
}
}
/**************************************************************************************
* Function: PreMultiplyRescale
*
* Description: pre-twiddle stage of DCT4, with rescaling for extra guard bits
*
* Inputs: table index (for transform size)
* buffer of nmdct samples
* number of guard bits to add to input before processing
*
* Outputs: processed samples in same buffer
*
* Return: none
*
* Notes: see notes on PreMultiply(), above
**************************************************************************************/
/* __attribute__ ((section (".data"))) */ static void PreMultiplyRescale(int tabidx, int *zbuf1, int es)
{
int i, nmdct, ar1, ai1, ar2, ai2, z1, z2;
int t, cms2, cps2a, sin2a, cps2b, sin2b;
int *zbuf2;
const int *csptr;
nmdct = nmdctTab[tabidx];
zbuf2 = zbuf1 + nmdct - 1;
csptr = cos4sin4tab + cos4sin4tabOffset[tabidx];
/* whole thing should fit in registers - verify that compiler does this */
for (i = nmdct >> 2; i != 0; i--) {
/* cps2 = (cos+sin), sin2 = sin, cms2 = (cos-sin) */
cps2a = *csptr++;
sin2a = *csptr++;
cps2b = *csptr++;
sin2b = *csptr++;
ar1 = *(zbuf1 + 0) >> es;
ai1 = *(zbuf2 + 0) >> es;
ai2 = *(zbuf1 + 1) >> es;
t = MULSHIFT32(sin2a, ar1 + ai1);
z2 = MULSHIFT32(cps2a, ai1) - t;
cms2 = cps2a - 2*sin2a;
z1 = MULSHIFT32(cms2, ar1) + t;
*zbuf1++ = z1;
*zbuf1++ = z2;
ar2 = *(zbuf2 - 1) >> es; /* do here to free up register used for es */
t = MULSHIFT32(sin2b, ar2 + ai2);
z2 = MULSHIFT32(cps2b, ai2) - t;
cms2 = cps2b - 2*sin2b;
z1 = MULSHIFT32(cms2, ar2) + t;
*zbuf2-- = z2;
*zbuf2-- = z1;
}
}
/**************************************************************************************
* Function: PostMultiplyRescale
*
* Description: post-twiddle stage of DCT4, with rescaling for extra guard bits
*
* Inputs: table index (for transform size)
* buffer of nmdct samples
* number of guard bits to remove from output
*
* Outputs: processed samples in same buffer
*
* Return: none
*
* Notes: clips output to [-2^30, 2^30 - 1], guaranteeing at least 1 guard bit
* see notes on PostMultiply(), above
**************************************************************************************/
/* __attribute__ ((section (".data"))) */ static void PostMultiplyRescale(int tabidx, int *fft1, int es)
{
int i, nmdct, ar1, ai1, ar2, ai2, skipFactor, z;
int t, cs2, sin2;
int *fft2;
const int *csptr;
nmdct = nmdctTab[tabidx];
csptr = cos1sin1tab;
skipFactor = postSkip[tabidx];
fft2 = fft1 + nmdct - 1;
/* load coeffs for first pass
* cps2 = (cos+sin), sin2 = sin, cms2 = (cos-sin)
*/
cs2 = *csptr++;
sin2 = *csptr;
csptr += skipFactor;
for (i = nmdct >> 2; i != 0; i--) {
ar1 = *(fft1 + 0);
ai1 = *(fft1 + 1);
ai2 = *(fft2 + 0);
t = MULSHIFT32(sin2, ar1 + ai1);
z = t - MULSHIFT32(cs2, ai1);
CLIP_2N_SHIFT(z, es);
*fft2-- = z;
cs2 -= 2*sin2;
z = t + MULSHIFT32(cs2, ar1);
CLIP_2N_SHIFT(z, es);
*fft1++ = z;
cs2 = *csptr++;
sin2 = *csptr;
csptr += skipFactor;
ar2 = *fft2;
ai2 = -ai2;
t = MULSHIFT32(sin2, ar2 + ai2);
z = t - MULSHIFT32(cs2, ai2);
CLIP_2N_SHIFT(z, es);
*fft2-- = z;
cs2 -= 2*sin2;
z = t + MULSHIFT32(cs2, ar2);
CLIP_2N_SHIFT(z, es);
*fft1++ = z;
cs2 += 2*sin2;
}
}
/**************************************************************************************
* Function: DCT4
*
* Description: type-IV DCT
*
* Inputs: table index (for transform size)
* buffer of nmdct samples
* number of guard bits in the input buffer
*
* Outputs: processed samples in same buffer
*
* Return: none
*
* Notes: operates in-place
* if number of guard bits in input is < GBITS_IN_DCT4, the input is
* scaled (>>) before the DCT4 and rescaled (<<, with clipping) after
* the DCT4 (rare)
* the output has FBITS_LOST_DCT4 fewer fraction bits than the input
* the output will always have at least 1 guard bit (GBITS_IN_DCT4 >= 4)
* int bits gained per stage (PreMul + FFT + PostMul)
* short blocks = (-5 + 4 + 2) = 1 total
* long blocks = (-8 + 7 + 2) = 1 total
**************************************************************************************/
void DCT4(int tabidx, int *coef, int gb)
{
int es;
/* fast in-place DCT-IV - adds guard bits if necessary */
if (gb < GBITS_IN_DCT4) {
es = GBITS_IN_DCT4 - gb;
PreMultiplyRescale(tabidx, coef, es);
R4FFT(tabidx, coef);
PostMultiplyRescale(tabidx, coef, es);
} else {
PreMultiply(tabidx, coef);
R4FFT(tabidx, coef);
PostMultiply(tabidx, coef);
}
}

View File

@@ -0,0 +1,425 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: decelmnt.c,v 1.1 2005/02/26 01:47:34 jrecker Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* decelmnt.c - syntactic element decoding
**************************************************************************************/
#include "coder.h"
/**************************************************************************************
* Function: DecodeSingleChannelElement
*
* Description: decode one SCE
*
* Inputs: BitStreamInfo struct pointing to start of SCE (14496-3, table 4.4.4)
*
* Outputs: updated element instance tag
*
* Return: 0 if successful, -1 if error
*
* Notes: doesn't decode individual channel stream (part of DecodeNoiselessData)
**************************************************************************************/
static int DecodeSingleChannelElement(AACDecInfo *aacDecInfo, BitStreamInfo *bsi)
{
/* validate pointers */
if (!aacDecInfo || !aacDecInfo->psInfoBase)
return -1;
/* read instance tag */
aacDecInfo->currInstTag = GetBits(bsi, NUM_INST_TAG_BITS);
return 0;
}
/**************************************************************************************
* Function: DecodeChannelPairElement
*
* Description: decode one CPE
*
* Inputs: BitStreamInfo struct pointing to start of CPE (14496-3, table 4.4.5)
*
* Outputs: updated element instance tag
* updated commonWin
* updated ICS info, if commonWin == 1
* updated mid-side stereo info, if commonWin == 1
*
* Return: 0 if successful, -1 if error
*
* Notes: doesn't decode individual channel stream (part of DecodeNoiselessData)
**************************************************************************************/
static int DecodeChannelPairElement(AACDecInfo *aacDecInfo, BitStreamInfo *bsi)
{
int sfb, gp, maskOffset;
unsigned char currBit, *maskPtr;
PSInfoBase *psi;
ICSInfo *icsInfo;
/* validate pointers */
if (!aacDecInfo || !aacDecInfo->psInfoBase)
return -1;
psi = (PSInfoBase *)(aacDecInfo->psInfoBase);
icsInfo = psi->icsInfo;
/* read instance tag */
aacDecInfo->currInstTag = GetBits(bsi, NUM_INST_TAG_BITS);
/* read common window flag and mid-side info (if present)
* store msMask bits in psi->msMaskBits[] as follows:
* long blocks - pack bits for each SFB in range [0, maxSFB) starting with lsb of msMaskBits[0]
* short blocks - pack bits for each SFB in range [0, maxSFB), for each group [0, 7]
* msMaskPresent = 0 means no M/S coding
* = 1 means psi->msMaskBits contains 1 bit per SFB to toggle M/S coding
* = 2 means all SFB's are M/S coded (so psi->msMaskBits is not needed)
*/
psi->commonWin = GetBits(bsi, 1);
if (psi->commonWin) {
DecodeICSInfo(bsi, icsInfo, psi->sampRateIdx);
psi->msMaskPresent = GetBits(bsi, 2);
if (psi->msMaskPresent == 1) {
maskPtr = psi->msMaskBits;
*maskPtr = 0;
maskOffset = 0;
for (gp = 0; gp < icsInfo->numWinGroup; gp++) {
for (sfb = 0; sfb < icsInfo->maxSFB; sfb++) {
currBit = (unsigned char)GetBits(bsi, 1);
*maskPtr |= currBit << maskOffset;
if (++maskOffset == 8) {
maskPtr++;
*maskPtr = 0;
maskOffset = 0;
}
}
}
}
}
return 0;
}
/**************************************************************************************
* Function: DecodeLFEChannelElement
*
* Description: decode one LFE
*
* Inputs: BitStreamInfo struct pointing to start of LFE (14496-3, table 4.4.9)
*
* Outputs: updated element instance tag
*
* Return: 0 if successful, -1 if error
*
* Notes: doesn't decode individual channel stream (part of DecodeNoiselessData)
**************************************************************************************/
static int DecodeLFEChannelElement(AACDecInfo *aacDecInfo, BitStreamInfo *bsi)
{
/* validate pointers */
if (!aacDecInfo || !aacDecInfo->psInfoBase)
return -1;
/* read instance tag */
aacDecInfo->currInstTag = GetBits(bsi, NUM_INST_TAG_BITS);
return 0;
}
/**************************************************************************************
* Function: DecodeDataStreamElement
*
* Description: decode one DSE
*
* Inputs: BitStreamInfo struct pointing to start of DSE (14496-3, table 4.4.10)
*
* Outputs: updated element instance tag
* filled in data stream buffer
*
* Return: 0 if successful, -1 if error
**************************************************************************************/
static int DecodeDataStreamElement(AACDecInfo *aacDecInfo, BitStreamInfo *bsi)
{
unsigned int byteAlign, dataCount;
unsigned char *dataBuf;
PSInfoBase *psi;
/* validate pointers */
if (!aacDecInfo || !aacDecInfo->psInfoBase)
return -1;
psi = (PSInfoBase *)(aacDecInfo->psInfoBase);
aacDecInfo->currInstTag = GetBits(bsi, NUM_INST_TAG_BITS);
byteAlign = GetBits(bsi, 1);
dataCount = GetBits(bsi, 8);
if (dataCount == 255)
dataCount += GetBits(bsi, 8);
if (byteAlign)
ByteAlignBitstream(bsi);
psi->dataCount = dataCount;
dataBuf = psi->dataBuf;
while (dataCount--)
*dataBuf++ = GetBits(bsi, 8);
return 0;
}
/**************************************************************************************
* Function: DecodeProgramConfigElement
*
* Description: decode one PCE
*
* Inputs: BitStreamInfo struct pointing to start of PCE (14496-3, table 4.4.2)
*
* Outputs: filled-in ProgConfigElement struct
* updated BitStreamInfo struct
*
* Return: 0 if successful, error code (< 0) if error
*
* Notes: #define KEEP_PCE_COMMENTS to save the comment field of the PCE
* (otherwise we just skip it in the bitstream, to save memory)
**************************************************************************************/
int DecodeProgramConfigElement(ProgConfigElement *pce, BitStreamInfo *bsi)
{
int i;
pce->elemInstTag = GetBits(bsi, 4);
pce->profile = GetBits(bsi, 2);
pce->sampRateIdx = GetBits(bsi, 4);
pce->numFCE = GetBits(bsi, 4);
pce->numSCE = GetBits(bsi, 4);
pce->numBCE = GetBits(bsi, 4);
pce->numLCE = GetBits(bsi, 2);
pce->numADE = GetBits(bsi, 3);
pce->numCCE = GetBits(bsi, 4);
pce->monoMixdown = GetBits(bsi, 1) << 4; /* present flag */
if (pce->monoMixdown)
pce->monoMixdown |= GetBits(bsi, 4); /* element number */
pce->stereoMixdown = GetBits(bsi, 1) << 4; /* present flag */
if (pce->stereoMixdown)
pce->stereoMixdown |= GetBits(bsi, 4); /* element number */
pce->matrixMixdown = GetBits(bsi, 1) << 4; /* present flag */
if (pce->matrixMixdown) {
pce->matrixMixdown |= GetBits(bsi, 2) << 1; /* index */
pce->matrixMixdown |= GetBits(bsi, 1); /* pseudo-surround enable */
}
for (i = 0; i < pce->numFCE; i++) {
pce->fce[i] = GetBits(bsi, 1) << 4; /* is_cpe flag */
pce->fce[i] |= GetBits(bsi, 4); /* tag select */
}
for (i = 0; i < pce->numSCE; i++) {
pce->sce[i] = GetBits(bsi, 1) << 4; /* is_cpe flag */
pce->sce[i] |= GetBits(bsi, 4); /* tag select */
}
for (i = 0; i < pce->numBCE; i++) {
pce->bce[i] = GetBits(bsi, 1) << 4; /* is_cpe flag */
pce->bce[i] |= GetBits(bsi, 4); /* tag select */
}
for (i = 0; i < pce->numLCE; i++)
pce->lce[i] = GetBits(bsi, 4); /* tag select */
for (i = 0; i < pce->numADE; i++)
pce->ade[i] = GetBits(bsi, 4); /* tag select */
for (i = 0; i < pce->numCCE; i++) {
pce->cce[i] = GetBits(bsi, 1) << 4; /* independent/dependent flag */
pce->cce[i] |= GetBits(bsi, 4); /* tag select */
}
ByteAlignBitstream(bsi);
#ifdef KEEP_PCE_COMMENTS
pce->commentBytes = GetBits(bsi, 8);
for (i = 0; i < pce->commentBytes; i++)
pce->commentField[i] = GetBits(bsi, 8);
#else
/* eat comment bytes and throw away */
i = GetBits(bsi, 8);
while (i--)
GetBits(bsi, 8);
#endif
return 0;
}
/**************************************************************************************
* Function: DecodeFillElement
*
* Description: decode one fill element
*
* Inputs: BitStreamInfo struct pointing to start of fill element
* (14496-3, table 4.4.11)
*
* Outputs: updated element instance tag
* unpacked extension payload
*
* Return: 0 if successful, -1 if error
**************************************************************************************/
static int DecodeFillElement(AACDecInfo *aacDecInfo, BitStreamInfo *bsi)
{
unsigned int fillCount;
unsigned char *fillBuf;
PSInfoBase *psi;
/* validate pointers */
if (!aacDecInfo || !aacDecInfo->psInfoBase)
return -1;
psi = (PSInfoBase *)(aacDecInfo->psInfoBase);
fillCount = GetBits(bsi, 4);
if (fillCount == 15)
fillCount += (GetBits(bsi, 8) - 1);
psi->fillCount = fillCount;
fillBuf = psi->fillBuf;
while (fillCount--)
*fillBuf++ = GetBits(bsi, 8);
aacDecInfo->currInstTag = -1; /* fill elements don't have instance tag */
aacDecInfo->fillExtType = 0;
#ifdef AAC_ENABLE_SBR
/* check for SBR
* aacDecInfo->sbrEnabled is sticky (reset each raw_data_block), so for multichannel
* need to verify that all SCE/CPE/ICCE have valid SBR fill element following, and
* must upsample by 2 for LFE
*/
if (psi->fillCount > 0) {
aacDecInfo->fillExtType = (int)((psi->fillBuf[0] >> 4) & 0x0f);
if (aacDecInfo->fillExtType == EXT_SBR_DATA || aacDecInfo->fillExtType == EXT_SBR_DATA_CRC)
aacDecInfo->sbrEnabled = 1;
}
#endif
aacDecInfo->fillBuf = psi->fillBuf;
aacDecInfo->fillCount = psi->fillCount;
return 0;
}
/**************************************************************************************
* Function: DecodeNextElement
*
* Description: decode next syntactic element in AAC frame
*
* Inputs: valid AACDecInfo struct
* double pointer to buffer containing next element
* pointer to bit offset
* pointer to number of valid bits remaining in buf
*
* Outputs: type of element decoded (aacDecInfo->currBlockID)
* type of element decoded last time (aacDecInfo->prevBlockID)
* updated aacDecInfo state, depending on which element was decoded
* updated buffer pointer
* updated bit offset
* updated number of available bits
*
* Return: 0 if successful, error code (< 0) if error
**************************************************************************************/
int DecodeNextElement(AACDecInfo *aacDecInfo, unsigned char **buf, int *bitOffset, int *bitsAvail)
{
int err, bitsUsed;
PSInfoBase *psi;
BitStreamInfo bsi;
/* validate pointers */
if (!aacDecInfo || !aacDecInfo->psInfoBase)
return ERR_AAC_NULL_POINTER;
psi = (PSInfoBase *)(aacDecInfo->psInfoBase);
/* init bitstream reader */
SetBitstreamPointer(&bsi, (*bitsAvail + 7) >> 3, *buf);
GetBits(&bsi, *bitOffset);
/* read element ID (save last ID for SBR purposes) */
aacDecInfo->prevBlockID = aacDecInfo->currBlockID;
aacDecInfo->currBlockID = GetBits(&bsi, NUM_SYN_ID_BITS);
/* set defaults (could be overwritten by DecodeXXXElement(), depending on currBlockID) */
psi->commonWin = 0;
err = 0;
switch (aacDecInfo->currBlockID) {
case AAC_ID_SCE:
err = DecodeSingleChannelElement(aacDecInfo, &bsi);
break;
case AAC_ID_CPE:
err = DecodeChannelPairElement(aacDecInfo, &bsi);
break;
case AAC_ID_CCE:
/* TODO - implement CCE decoding */
break;
case AAC_ID_LFE:
err = DecodeLFEChannelElement(aacDecInfo, &bsi);
break;
case AAC_ID_DSE:
err = DecodeDataStreamElement(aacDecInfo, &bsi);
break;
case AAC_ID_PCE:
err = DecodeProgramConfigElement(psi->pce + 0, &bsi);
break;
case AAC_ID_FIL:
err = DecodeFillElement(aacDecInfo, &bsi);
break;
case AAC_ID_END:
break;
}
if (err)
return ERR_AAC_SYNTAX_ELEMENT;
/* update bitstream reader */
bitsUsed = CalcBitsUsed(&bsi, *buf, *bitOffset);
*buf += (bitsUsed + *bitOffset) >> 3;
*bitOffset = (bitsUsed + *bitOffset) & 0x07;
*bitsAvail -= bitsUsed;
if (*bitsAvail < 0)
return ERR_AAC_INDATA_UNDERFLOW;
return ERR_AAC_NONE;
}

View File

@@ -0,0 +1,373 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: dequant.c,v 1.2 2005/05/20 18:05:41 jrecker Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com)
* February 2005
*
* dequant.c - transform coefficient dequantization and short-block deinterleaving
**************************************************************************************/
#include "coder.h"
#include "assembly.h"
#define SF_OFFSET 100
/* pow(2, i/4.0) for i = [0,1,2,3], format = Q30 */
static const int pow14[4] PROGMEM = {
0x40000000, 0x4c1bf829, 0x5a82799a, 0x6ba27e65
};
/* pow(2, i/4.0) * pow(j, 4.0/3.0) for i = [0,1,2,3], j = [0,1,2,...,15]
* format = Q28 for j = [0-3], Q25 for j = [4-15]
*/
static const int pow43_14[4][16] PROGMEM = {
{
0x00000000, 0x10000000, 0x285145f3, 0x453a5cdb, /* Q28 */
0x0cb2ff53, 0x111989d6, 0x15ce31c8, 0x1ac7f203, /* Q25 */
0x20000000, 0x257106b9, 0x2b16b4a3, 0x30ed74b4, /* Q25 */
0x36f23fa5, 0x3d227bd3, 0x437be656, 0x49fc823c, /* Q25 */
},
{
0x00000000, 0x1306fe0a, 0x2ff221af, 0x52538f52,
0x0f1a1bf4, 0x1455ccc2, 0x19ee62a8, 0x1fd92396,
0x260dfc14, 0x2c8694d8, 0x333dcb29, 0x3a2f5c7a,
0x4157aed5, 0x48b3aaa3, 0x50409f76, 0x57fc3010,
},
{
0x00000000, 0x16a09e66, 0x39047c0f, 0x61e734aa,
0x11f59ac4, 0x182ec633, 0x1ed66a45, 0x25dfc55a,
0x2d413ccd, 0x34f3462d, 0x3cefc603, 0x4531ab69,
0x4db4adf8, 0x56752054, 0x5f6fcfcd, 0x68a1eca1,
},
{
0x00000000, 0x1ae89f99, 0x43ce3e4b, 0x746d57b2,
0x155b8109, 0x1cc21cdc, 0x24ac1839, 0x2d0a479e,
0x35d13f33, 0x3ef80748, 0x48775c93, 0x524938cd,
0x5c68841d, 0x66d0df0a, 0x717e7bfe, 0x7c6e0305,
},
};
/* pow(j, 4.0 / 3.0) for j = [16,17,18,...,63], format = Q23 */
static const int pow43[48] PROGMEM = {
0x1428a2fa, 0x15db1bd6, 0x1796302c, 0x19598d85,
0x1b24e8bb, 0x1cf7fcfa, 0x1ed28af2, 0x20b4582a,
0x229d2e6e, 0x248cdb55, 0x26832fda, 0x28800000,
0x2a832287, 0x2c8c70a8, 0x2e9bc5d8, 0x30b0ff99,
0x32cbfd4a, 0x34eca001, 0x3712ca62, 0x393e6088,
0x3b6f47e0, 0x3da56717, 0x3fe0a5fc, 0x4220ed72,
0x44662758, 0x46b03e7c, 0x48ff1e87, 0x4b52b3f3,
0x4daaebfd, 0x5007b497, 0x5268fc62, 0x54ceb29c,
0x5738c721, 0x59a72a59, 0x5c19cd35, 0x5e90a129,
0x610b9821, 0x638aa47f, 0x660db90f, 0x6894c90b,
0x6b1fc80c, 0x6daeaa0d, 0x70416360, 0x72d7e8b0,
0x75722ef9, 0x78102b85, 0x7ab1d3ec, 0x7d571e09,
};
/* sqrt(0.5), format = Q31 */
#define SQRTHALF 0x5a82799a
/* Minimax polynomial approximation to pow(x, 4/3), over the range
* poly43lo: x = [0.5, 0.7071]
* poly43hi: x = [0.7071, 1.0]
*
* Relative error < 1E-7
* Coefs are scaled by 4, 2, 1, 0.5, 0.25
*/
//fb
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnarrowing"
static const int poly43lo[5] PROGMEM = { 0x29a0bda9, 0xb02e4828, 0x5957aa1b, 0x236c498d, 0xff581859 };
static const int poly43hi[5] PROGMEM = { 0x10852163, 0xd333f6a4, 0x46e9408b, 0x27c2cef0, 0xfef577b4 };
#pragma GCC diagnostic pop
/* pow2exp[i] = pow(2, i*4/3) exponent */
static const int pow2exp[8] PROGMEM = { 14, 13, 11, 10, 9, 7, 6, 5 };
/* pow2exp[i] = pow(2, i*4/3) fraction */
static const int pow2frac[8] PROGMEM = {
0x6597fa94, 0x50a28be6, 0x7fffffff, 0x6597fa94,
0x50a28be6, 0x7fffffff, 0x6597fa94, 0x50a28be6
};
/**************************************************************************************
* Function: DequantBlock
*
* Description: dequantize one block of transform coefficients (in-place)
*
* Inputs: quantized transform coefficients, range = [0, 8191]
* number of samples to dequantize
* scalefactor for this block of data, range = [0, 256]
*
* Outputs: dequantized transform coefficients in Q(FBITS_OUT_DQ_OFF)
*
* Return: guard bit mask (OR of abs value of all dequantized coefs)
*
* Notes: applies dequant formula y = pow(x, 4.0/3.0) * pow(2, (scale - 100)/4.0)
* * pow(2, FBITS_OUT_DQ_OFF)
* clips outputs to Q(FBITS_OUT_DQ_OFF)
* output has no minimum number of guard bits
**************************************************************************************/
static int DequantBlock(int *inbuf, int nSamps, int scale)
{
int iSamp, scalef, scalei, x, y, gbMask, shift, tab4[4];
const int *tab16, *coef;
if (nSamps <= 0)
return 0;
scale -= SF_OFFSET; /* new range = [-100, 156] */
/* with two's complement numbers, scalei/scalef factorization works for pos and neg values of scale:
* [+4...+7] >> 2 = +1, [ 0...+3] >> 2 = 0, [-4...-1] >> 2 = -1, [-8...-5] >> 2 = -2 ...
* (-1 & 0x3) = 3, (-2 & 0x3) = 2, (-3 & 0x3) = 1, (0 & 0x3) = 0
*
* Example: 2^(-5/4) = 2^(-1) * 2^(-1/4) = 2^-2 * 2^(3/4)
*/
tab16 = pow43_14[scale & 0x3];
scalef = pow14[scale & 0x3];
scalei = (scale >> 2) + FBITS_OUT_DQ_OFF;
/* cache first 4 values:
* tab16[j] = Q28 for j = [0,3]
* tab4[x] = x^(4.0/3.0) * 2^(0.25*scale), Q(FBITS_OUT_DQ_OFF)
*/
shift = 28 - scalei;
if (shift > 31) {
tab4[0] = tab4[1] = tab4[2] = tab4[3] = 0;
} else if (shift <= 0) {
shift = -shift;
if (shift > 31)
shift = 31;
for (x = 0; x < 4; x++) {
y = tab16[x];
if (y > (0x7fffffff >> shift))
y = 0x7fffffff; /* clip (rare) */
else
y <<= shift;
tab4[x] = y;
}
} else {
tab4[0] = 0;
tab4[1] = tab16[1] >> shift;
tab4[2] = tab16[2] >> shift;
tab4[3] = tab16[3] >> shift;
}
gbMask = 0;
do {
iSamp = *inbuf;
x = FASTABS(iSamp);
if (x < 4) {
y = tab4[x];
} else {
if (x < 16) {
/* result: y = Q25 (tab16 = Q25) */
y = tab16[x];
shift = 25 - scalei;
} else if (x < 64) {
/* result: y = Q21 (pow43tab[j] = Q23, scalef = Q30) */
y = pow43[x-16];
shift = 21 - scalei;
y = MULSHIFT32(y, scalef);
} else {
/* normalize to [0x40000000, 0x7fffffff]
* input x = [64, 8191] = [64, 2^13-1]
* ranges:
* shift = 7: 64 - 127
* shift = 6: 128 - 255
* shift = 5: 256 - 511
* shift = 4: 512 - 1023
* shift = 3: 1024 - 2047
* shift = 2: 2048 - 4095
* shift = 1: 4096 - 8191
*/
x <<= 17;
shift = 0;
if (x < 0x08000000)
x <<= 4, shift += 4;
if (x < 0x20000000)
x <<= 2, shift += 2;
if (x < 0x40000000)
x <<= 1, shift += 1;
coef = (x < SQRTHALF) ? poly43lo : poly43hi;
/* polynomial */
y = coef[0];
y = MULSHIFT32(y, x) + coef[1];
y = MULSHIFT32(y, x) + coef[2];
y = MULSHIFT32(y, x) + coef[3];
y = MULSHIFT32(y, x) + coef[4];
y = MULSHIFT32(y, pow2frac[shift]) << 3;
/* fractional scale
* result: y = Q21 (pow43tab[j] = Q23, scalef = Q30)
*/
y = MULSHIFT32(y, scalef); /* now y is Q24 */
shift = 24 - scalei - pow2exp[shift];
}
/* integer scale */
if (shift <= 0) {
shift = -shift;
if (shift > 31)
shift = 31;
if (y > (0x7fffffff >> shift))
y = 0x7fffffff; /* clip (rare) */
else
y <<= shift;
} else {
if (shift > 31)
shift = 31;
y >>= shift;
}
}
/* sign and store (gbMask used to count GB's) */
gbMask |= y;
/* apply sign */
iSamp >>= 31;
y ^= iSamp;
y -= iSamp;
*inbuf++ = y;
} while (--nSamps);
return gbMask;
}
/**************************************************************************************
* Function: Dequantize
*
* Description: dequantize all transform coefficients for one channel
*
* Inputs: valid AACDecInfo struct (including unpacked, quantized coefficients)
* index of current channel
*
* Outputs: dequantized coefficients, including short-block deinterleaving
* flags indicating if intensity and/or PNS is active
* minimum guard bit count for dequantized coefficients
*
* Return: 0 if successful, error code (< 0) if error
**************************************************************************************/
int Dequantize(AACDecInfo *aacDecInfo, int ch)
{
int gp, cb, sfb, win, width, nSamps, gbMask;
int *coef;
const int /*short*/ *sfbTab;
unsigned char *sfbCodeBook;
short *scaleFactors;
PSInfoBase *psi;
ICSInfo *icsInfo;
/* validate pointers */
if (!aacDecInfo || !aacDecInfo->psInfoBase)
return ERR_AAC_NULL_POINTER;
psi = (PSInfoBase *)(aacDecInfo->psInfoBase);
icsInfo = (ch == 1 && psi->commonWin == 1) ? &(psi->icsInfo[0]) : &(psi->icsInfo[ch]);
if (icsInfo->winSequence == 2) {
sfbTab = sfBandTabShort + sfBandTabShortOffset[psi->sampRateIdx];
nSamps = NSAMPS_SHORT;
} else {
sfbTab = sfBandTabLong + sfBandTabLongOffset[psi->sampRateIdx];
nSamps = NSAMPS_LONG;
}
coef = psi->coef[ch];
sfbCodeBook = psi->sfbCodeBook[ch];
scaleFactors = psi->scaleFactors[ch];
psi->intensityUsed[ch] = 0;
psi->pnsUsed[ch] = 0;
gbMask = 0;
for (gp = 0; gp < icsInfo->numWinGroup; gp++) {
for (win = 0; win < icsInfo->winGroupLen[gp]; win++) {
for (sfb = 0; sfb < icsInfo->maxSFB; sfb++) {
/* dequantize one scalefactor band (not necessary if codebook is intensity or PNS)
* for zero codebook, still run dequantizer in case non-zero pulse data was added
*/
cb = (int)(sfbCodeBook[sfb]);
width = sfbTab[sfb+1] - sfbTab[sfb];
if (cb >= 0 && cb <= 11)
gbMask |= DequantBlock(coef, width, scaleFactors[sfb]);
else if (cb == 13)
psi->pnsUsed[ch] = 1;
else if (cb == 14 || cb == 15)
psi->intensityUsed[ch] = 1; /* should only happen if ch == 1 */
coef += width;
}
coef += (nSamps - sfbTab[icsInfo->maxSFB]);
}
sfbCodeBook += icsInfo->maxSFB;
scaleFactors += icsInfo->maxSFB;
}
aacDecInfo->pnsUsed |= psi->pnsUsed[ch]; /* set flag if PNS used for any channel */
/* calculate number of guard bits in dequantized data */
psi->gbCurrent[ch] = CLZ(gbMask) - 1;
return ERR_AAC_NONE;
}
/**************************************************************************************
* Function: DeinterleaveShortBlocks
*
* Description: deinterleave transform coefficients in short blocks for one channel
*
* Inputs: valid AACDecInfo struct (including unpacked, quantized coefficients)
* index of current channel
*
* Outputs: deinterleaved coefficients (window groups into 8 separate windows)
*
* Return: 0 if successful, error code (< 0) if error
*
* Notes: only necessary if deinterleaving not part of Huffman decoding
**************************************************************************************/
int DeinterleaveShortBlocks(AACDecInfo *aacDecInfo, int ch)
{
(void)aacDecInfo;
(void)ch;
/* not used for this implementation - short block deinterleaving performed during Huffman decoding */
return ERR_AAC_NONE;
}

View File

@@ -0,0 +1,393 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: fft.c,v 1.1 2005/02/26 01:47:34 jrecker Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com)
* February 2005
*
* fft.c - Ken's optimized radix-4 DIT FFT, optional radix-8 first pass for odd log2(N)
**************************************************************************************/
#include "coder.h"
#include "assembly.h"
#define NUM_FFT_SIZES 2
static const int nfftTab[NUM_FFT_SIZES] PROGMEM ={64, 512};
static const int nfftlog2Tab[NUM_FFT_SIZES] PROGMEM = {6, 9};
#define SQRT1_2 0x5a82799a /* sqrt(1/2) in Q31 */
#define swapcplx(p0,p1) \
t = p0; t1 = *(&(p0)+1); p0 = p1; *(&(p0)+1) = *(&(p1)+1); p1 = t; *(&(p1)+1) = t1
/**************************************************************************************
* Function: BitReverse
*
* Description: Ken's fast in-place bit reverse, using super-small table
*
* Inputs: buffer of samples
* table index (for transform size)
*
* Outputs: bit-reversed samples in same buffer
*
* Return: none
**************************************************************************************/
/*__attribute__ ((section (".data"))) */ static void BitReverse(int *inout, int tabidx)
{
int *part0, *part1;
int a,b, t,t1;
const unsigned char* tab = bitrevtab + bitrevtabOffset[tabidx];
int nbits = nfftlog2Tab[tabidx];
part0 = inout;
part1 = inout + (1 << nbits);
while ((a = pgm_read_byte(tab++)) != 0) {
b = pgm_read_byte(tab++);
swapcplx(part0[4*a+0], part0[4*b+0]); /* 0xxx0 <-> 0yyy0 */
swapcplx(part0[4*a+2], part1[4*b+0]); /* 0xxx1 <-> 1yyy0 */
swapcplx(part1[4*a+0], part0[4*b+2]); /* 1xxx0 <-> 0yyy1 */
swapcplx(part1[4*a+2], part1[4*b+2]); /* 1xxx1 <-> 1yyy1 */
}
do {
swapcplx(part0[4*a+2], part1[4*a+0]); /* 0xxx1 <-> 1xxx0 */
} while ((a = pgm_read_byte(tab++)) != 0);
}
/**************************************************************************************
* Function: R4FirstPass
*
* Description: radix-4 trivial pass for decimation-in-time FFT
*
* Inputs: buffer of (bit-reversed) samples
* number of R4 butterflies per group (i.e. nfft / 4)
*
* Outputs: processed samples in same buffer
*
* Return: none
*
* Notes: assumes 2 guard bits, gains no integer bits,
* guard bits out = guard bits in - 2
**************************************************************************************/
/* __attribute__ ((section (".data"))) */ static void R4FirstPass(int *x, int bg)
{
int ar, ai, br, bi, cr, ci, dr, di;
for (; bg != 0; bg--) {
ar = x[0] + x[2];
br = x[0] - x[2];
ai = x[1] + x[3];
bi = x[1] - x[3];
cr = x[4] + x[6];
dr = x[4] - x[6];
ci = x[5] + x[7];
di = x[5] - x[7];
/* max per-sample gain = 4.0 (adding 4 inputs together) */
x[0] = ar + cr;
x[4] = ar - cr;
x[1] = ai + ci;
x[5] = ai - ci;
x[2] = br + di;
x[6] = br - di;
x[3] = bi - dr;
x[7] = bi + dr;
x += 8;
}
}
/**************************************************************************************
* Function: R8FirstPass
*
* Description: radix-8 trivial pass for decimation-in-time FFT
*
* Inputs: buffer of (bit-reversed) samples
* number of R8 butterflies per group (i.e. nfft / 8)
*
* Outputs: processed samples in same buffer
*
* Return: none
*
* Notes: assumes 3 guard bits, gains 1 integer bit
* guard bits out = guard bits in - 3 (if inputs are full scale)
* or guard bits in - 2 (if inputs bounded to +/- sqrt(2)/2)
* see scaling comments in code
**************************************************************************************/
/* __attribute__ ((section (".data"))) */ static void R8FirstPass(int *x, int bg)
{
int ar, ai, br, bi, cr, ci, dr, di;
int sr, si, tr, ti, ur, ui, vr, vi;
int wr, wi, xr, xi, yr, yi, zr, zi;
for (; bg != 0; bg--) {
ar = x[0] + x[2];
br = x[0] - x[2];
ai = x[1] + x[3];
bi = x[1] - x[3];
cr = x[4] + x[6];
dr = x[4] - x[6];
ci = x[5] + x[7];
di = x[5] - x[7];
sr = ar + cr;
ur = ar - cr;
si = ai + ci;
ui = ai - ci;
tr = br - di;
vr = br + di;
ti = bi + dr;
vi = bi - dr;
ar = x[ 8] + x[10];
br = x[ 8] - x[10];
ai = x[ 9] + x[11];
bi = x[ 9] - x[11];
cr = x[12] + x[14];
dr = x[12] - x[14];
ci = x[13] + x[15];
di = x[13] - x[15];
/* max gain of wr/wi/yr/yi vs input = 2
* (sum of 4 samples >> 1)
*/
wr = (ar + cr) >> 1;
yr = (ar - cr) >> 1;
wi = (ai + ci) >> 1;
yi = (ai - ci) >> 1;
/* max gain of output vs input = 4
* (sum of 4 samples >> 1 + sum of 4 samples >> 1)
*/
x[ 0] = (sr >> 1) + wr;
x[ 8] = (sr >> 1) - wr;
x[ 1] = (si >> 1) + wi;
x[ 9] = (si >> 1) - wi;
x[ 4] = (ur >> 1) + yi;
x[12] = (ur >> 1) - yi;
x[ 5] = (ui >> 1) - yr;
x[13] = (ui >> 1) + yr;
ar = br - di;
cr = br + di;
ai = bi + dr;
ci = bi - dr;
/* max gain of xr/xi/zr/zi vs input = 4*sqrt(2)/2 = 2*sqrt(2)
* (sum of 8 samples, multiply by sqrt(2)/2, implicit >> 1 from Q31)
*/
xr = MULSHIFT32(SQRT1_2, ar - ai);
xi = MULSHIFT32(SQRT1_2, ar + ai);
zr = MULSHIFT32(SQRT1_2, cr - ci);
zi = MULSHIFT32(SQRT1_2, cr + ci);
/* max gain of output vs input = (2 + 2*sqrt(2) ~= 4.83)
* (sum of 4 samples >> 1, plus xr/xi/zr/zi with gain of 2*sqrt(2))
* in absolute terms, we have max gain of appx 9.656 (4 + 0.707*8)
* but we also gain 1 int bit (from MULSHIFT32 or from explicit >> 1)
*/
x[ 6] = (tr >> 1) - xr;
x[14] = (tr >> 1) + xr;
x[ 7] = (ti >> 1) - xi;
x[15] = (ti >> 1) + xi;
x[ 2] = (vr >> 1) + zi;
x[10] = (vr >> 1) - zi;
x[ 3] = (vi >> 1) - zr;
x[11] = (vi >> 1) + zr;
x += 16;
}
}
/**************************************************************************************
* Function: R4Core
*
* Description: radix-4 pass for decimation-in-time FFT
*
* Inputs: buffer of samples
* number of R4 butterflies per group
* number of R4 groups per pass
* pointer to twiddle factors tables
*
* Outputs: processed samples in same buffer
*
* Return: none
*
* Notes: gain 2 integer bits per pass (see scaling comments in code)
* min 1 GB in
* gbOut = gbIn - 1 (short block) or gbIn - 2 (long block)
* uses 3-mul, 3-add butterflies instead of 4-mul, 2-add
**************************************************************************************/
/* __attribute__ ((section (".data"))) */ static void R4Core(int *x, int bg, int gp, int *wtab)
{
int ar, ai, br, bi, cr, ci, dr, di, tr, ti;
int wd, ws, wi;
int i, j, step;
int *xptr, *wptr;
for (; bg != 0; gp <<= 2, bg >>= 2) {
step = 2*gp;
xptr = x;
/* max per-sample gain, per group < 1 + 3*sqrt(2) ~= 5.25 if inputs x are full-scale
* do 3 groups for long block, 2 groups for short block (gain 2 int bits per group)
*
* very conservative scaling:
* group 1: max gain = 5.25, int bits gained = 2, gb used = 1 (2^3 = 8)
* group 2: max gain = 5.25^2 = 27.6, int bits gained = 4, gb used = 1 (2^5 = 32)
* group 3: max gain = 5.25^3 = 144.7, int bits gained = 6, gb used = 2 (2^8 = 256)
*/
for (i = bg; i != 0; i--) {
wptr = wtab;
for (j = gp; j != 0; j--) {
ar = xptr[0];
ai = xptr[1];
xptr += step;
/* gain 2 int bits for br/bi, cr/ci, dr/di (MULSHIFT32 by Q30)
* gain 1 net GB
*/
ws = wptr[0];
wi = wptr[1];
br = xptr[0];
bi = xptr[1];
wd = ws + 2*wi;
tr = MULSHIFT32(wi, br + bi);
br = MULSHIFT32(wd, br) - tr; /* cos*br + sin*bi */
bi = MULSHIFT32(ws, bi) + tr; /* cos*bi - sin*br */
xptr += step;
ws = wptr[2];
wi = wptr[3];
cr = xptr[0];
ci = xptr[1];
wd = ws + 2*wi;
tr = MULSHIFT32(wi, cr + ci);
cr = MULSHIFT32(wd, cr) - tr;
ci = MULSHIFT32(ws, ci) + tr;
xptr += step;
ws = wptr[4];
wi = wptr[5];
dr = xptr[0];
di = xptr[1];
wd = ws + 2*wi;
tr = MULSHIFT32(wi, dr + di);
dr = MULSHIFT32(wd, dr) - tr;
di = MULSHIFT32(ws, di) + tr;
wptr += 6;
tr = ar;
ti = ai;
ar = (tr >> 2) - br;
ai = (ti >> 2) - bi;
br = (tr >> 2) + br;
bi = (ti >> 2) + bi;
tr = cr;
ti = ci;
cr = tr + dr;
ci = di - ti;
dr = tr - dr;
di = di + ti;
xptr[0] = ar + ci;
xptr[1] = ai + dr;
xptr -= step;
xptr[0] = br - cr;
xptr[1] = bi - di;
xptr -= step;
xptr[0] = ar - ci;
xptr[1] = ai - dr;
xptr -= step;
xptr[0] = br + cr;
xptr[1] = bi + di;
xptr += 2;
}
xptr += 3*step;
}
wtab += 3*step;
}
}
/**************************************************************************************
* Function: R4FFT
*
* Description: Ken's very fast in-place radix-4 decimation-in-time FFT
*
* Inputs: table index (for transform size)
* buffer of samples (non bit-reversed)
*
* Outputs: processed samples in same buffer
*
* Return: none
*
* Notes: assumes 5 guard bits in for nfft <= 512
* gbOut = gbIn - 4 (assuming input is from PreMultiply)
* gains log2(nfft) - 2 int bits total
* so gain 7 int bits (LONG), 4 int bits (SHORT)
**************************************************************************************/
void R4FFT(int tabidx, int *x)
{
int order = nfftlog2Tab[tabidx];
int nfft = nfftTab[tabidx];
/* decimation in time */
BitReverse(x, tabidx);
if (order & 0x1) {
/* long block: order = 9, nfft = 512 */
R8FirstPass(x, nfft >> 3); /* gain 1 int bit, lose 2 GB */
R4Core(x, nfft >> 5, 8, (int *)twidTabOdd); /* gain 6 int bits, lose 2 GB */
} else {
/* short block: order = 6, nfft = 64 */
R4FirstPass(x, nfft >> 2); /* gain 0 int bits, lose 2 GB */
R4Core(x, nfft >> 4, 4, (int *)twidTabEven); /* gain 4 int bits, lose 1 GB */
}
}

View File

@@ -0,0 +1,496 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: filefmt.c,v 1.1 2005/02/26 01:47:34 jrecker Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* filefmt.c - ADIF and ADTS header decoding, raw block handling
**************************************************************************************/
#include "coder.h"
/**************************************************************************************
* Function: UnpackADTSHeader
*
* Description: parse the ADTS frame header and initialize decoder state
*
* Inputs: valid AACDecInfo struct
* double pointer to buffer with complete ADTS frame header (byte aligned)
* header size = 7 bytes, plus 2 if CRC
*
* Outputs: filled in ADTS struct
* updated buffer pointer
* updated bit offset
* updated number of available bits
*
* Return: 0 if successful, error code (< 0) if error
*
* TODO: test CRC
* verify that fixed fields don't change between frames
**************************************************************************************/
int UnpackADTSHeader(AACDecInfo *aacDecInfo, unsigned char **buf, int *bitOffset, int *bitsAvail)
{
int bitsUsed;
PSInfoBase *psi;
BitStreamInfo bsi;
ADTSHeader *fhADTS;
/* validate pointers */
if (!aacDecInfo || !aacDecInfo->psInfoBase)
return ERR_AAC_NULL_POINTER;
psi = (PSInfoBase *)(aacDecInfo->psInfoBase);
fhADTS = &(psi->fhADTS);
/* init bitstream reader */
SetBitstreamPointer(&bsi, (*bitsAvail + 7) >> 3, *buf);
GetBits(&bsi, *bitOffset);
/* verify that first 12 bits of header are syncword */
if (GetBits(&bsi, 12) != 0x0fff) {
return ERR_AAC_INVALID_ADTS_HEADER;
}
/* fixed fields - should not change from frame to frame */
fhADTS->id = GetBits(&bsi, 1);
fhADTS->layer = GetBits(&bsi, 2);
fhADTS->protectBit = GetBits(&bsi, 1);
fhADTS->profile = GetBits(&bsi, 2);
fhADTS->sampRateIdx = GetBits(&bsi, 4);
fhADTS->privateBit = GetBits(&bsi, 1);
fhADTS->channelConfig = GetBits(&bsi, 3);
fhADTS->origCopy = GetBits(&bsi, 1);
fhADTS->home = GetBits(&bsi, 1);
/* variable fields - can change from frame to frame */
fhADTS->copyBit = GetBits(&bsi, 1);
fhADTS->copyStart = GetBits(&bsi, 1);
fhADTS->frameLength = GetBits(&bsi, 13);
fhADTS->bufferFull = GetBits(&bsi, 11);
fhADTS->numRawDataBlocks = GetBits(&bsi, 2) + 1;
/* note - MPEG4 spec, correction 1 changes how CRC is handled when protectBit == 0 and numRawDataBlocks > 1 */
if (fhADTS->protectBit == 0)
fhADTS->crcCheckWord = GetBits(&bsi, 16);
/* byte align */
ByteAlignBitstream(&bsi); /* should always be aligned anyway */
/* check validity of header */
if (fhADTS->layer != 0 || fhADTS->profile != AAC_PROFILE_LC ||
fhADTS->sampRateIdx >= NUM_SAMPLE_RATES || fhADTS->channelConfig >= NUM_DEF_CHAN_MAPS)
return ERR_AAC_INVALID_ADTS_HEADER;
#ifndef AAC_ENABLE_MPEG4
if (fhADTS->id != 1)
return ERR_AAC_MPEG4_UNSUPPORTED;
#endif
/* update codec info */
psi->sampRateIdx = fhADTS->sampRateIdx;
if (!psi->useImpChanMap)
psi->nChans = channelMapTab[fhADTS->channelConfig];
/* syntactic element fields will be read from bitstream for each element */
aacDecInfo->prevBlockID = AAC_ID_INVALID;
aacDecInfo->currBlockID = AAC_ID_INVALID;
aacDecInfo->currInstTag = -1;
/* fill in user-accessible data (TODO - calc bitrate, handle tricky channel config cases) */
aacDecInfo->bitRate = 0;
aacDecInfo->nChans = psi->nChans;
aacDecInfo->sampRate = sampRateTab[psi->sampRateIdx];
aacDecInfo->profile = fhADTS->profile;
aacDecInfo->sbrEnabled = 0;
aacDecInfo->adtsBlocksLeft = fhADTS->numRawDataBlocks;
/* update bitstream reader */
bitsUsed = CalcBitsUsed(&bsi, *buf, *bitOffset);
*buf += (bitsUsed + *bitOffset) >> 3;
*bitOffset = (bitsUsed + *bitOffset) & 0x07;
*bitsAvail -= bitsUsed ;
if (*bitsAvail < 0)
return ERR_AAC_INDATA_UNDERFLOW;
return ERR_AAC_NONE;
}
/**************************************************************************************
* Function: GetADTSChannelMapping
*
* Description: determine the number of channels from implicit mapping rules
*
* Inputs: valid AACDecInfo struct
* pointer to start of raw_data_block
* bit offset
* bits available
*
* Outputs: updated number of channels
*
* Return: 0 if successful, error code (< 0) if error
*
* Notes: calculates total number of channels using rules in 14496-3, 4.5.1.2.1
* does not attempt to deduce speaker geometry
**************************************************************************************/
int GetADTSChannelMapping(AACDecInfo *aacDecInfo, unsigned char *buf, int bitOffset, int bitsAvail)
{
int ch, nChans, elementChans, err;
PSInfoBase *psi;
/* validate pointers */
if (!aacDecInfo || !aacDecInfo->psInfoBase)
return ERR_AAC_NULL_POINTER;
psi = (PSInfoBase *)(aacDecInfo->psInfoBase);
nChans = 0;
do {
/* parse next syntactic element */
err = DecodeNextElement(aacDecInfo, &buf, &bitOffset, &bitsAvail);
if (err)
return err;
elementChans = elementNumChans[aacDecInfo->currBlockID];
nChans += elementChans;
for (ch = 0; ch < elementChans; ch++) {
err = DecodeNoiselessData(aacDecInfo, &buf, &bitOffset, &bitsAvail, ch);
if (err)
return err;
}
} while (aacDecInfo->currBlockID != AAC_ID_END);
if (nChans <= 0)
return ERR_AAC_CHANNEL_MAP;
/* update number of channels in codec state and user-accessible info structs */
psi->nChans = nChans;
aacDecInfo->nChans = psi->nChans;
psi->useImpChanMap = 1;
return ERR_AAC_NONE;
}
/**************************************************************************************
* Function: GetNumChannelsADIF
*
* Description: get number of channels from program config elements in an ADIF file
*
* Inputs: array of filled-in program config element structures
* number of PCE's
*
* Outputs: none
*
* Return: total number of channels in file
* -1 if error (invalid number of PCE's or unsupported mode)
**************************************************************************************/
static int GetNumChannelsADIF(ProgConfigElement *fhPCE, int nPCE)
{
int i, j, nChans;
if (nPCE < 1 || nPCE > MAX_NUM_PCE_ADIF)
return -1;
nChans = 0;
for (i = 0; i < nPCE; i++) {
/* for now: only support LC, no channel coupling */
if (fhPCE[i].profile != AAC_PROFILE_LC || fhPCE[i].numCCE > 0)
return -1;
/* add up number of channels in all channel elements (assume all single-channel) */
nChans += fhPCE[i].numFCE;
nChans += fhPCE[i].numSCE;
nChans += fhPCE[i].numBCE;
nChans += fhPCE[i].numLCE;
/* add one more for every element which is a channel pair */
for (j = 0; j < fhPCE[i].numFCE; j++) {
if (CHAN_ELEM_IS_CPE(fhPCE[i].fce[j]))
nChans++;
}
for (j = 0; j < fhPCE[i].numSCE; j++) {
if (CHAN_ELEM_IS_CPE(fhPCE[i].sce[j]))
nChans++;
}
for (j = 0; j < fhPCE[i].numBCE; j++) {
if (CHAN_ELEM_IS_CPE(fhPCE[i].bce[j]))
nChans++;
}
}
return nChans;
}
/**************************************************************************************
* Function: GetSampleRateIdxADIF
*
* Description: get sampling rate index from program config elements in an ADIF file
*
* Inputs: array of filled-in program config element structures
* number of PCE's
*
* Outputs: none
*
* Return: sample rate of file
* -1 if error (invalid number of PCE's or sample rate mismatch)
**************************************************************************************/
static int GetSampleRateIdxADIF(ProgConfigElement *fhPCE, int nPCE)
{
int i, idx;
if (nPCE < 1 || nPCE > MAX_NUM_PCE_ADIF)
return -1;
/* make sure all PCE's have the same sample rate */
idx = fhPCE[0].sampRateIdx;
for (i = 1; i < nPCE; i++) {
if (fhPCE[i].sampRateIdx != idx)
return -1;
}
return idx;
}
/**************************************************************************************
* Function: UnpackADIFHeader
*
* Description: parse the ADIF file header and initialize decoder state
*
* Inputs: valid AACDecInfo struct
* double pointer to buffer with complete ADIF header
* (starting at 'A' in 'ADIF' tag)
* pointer to bit offset
* pointer to number of valid bits remaining in inbuf
*
* Outputs: filled-in ADIF struct
* updated buffer pointer
* updated bit offset
* updated number of available bits
*
* Return: 0 if successful, error code (< 0) if error
**************************************************************************************/
int UnpackADIFHeader(AACDecInfo *aacDecInfo, unsigned char **buf, int *bitOffset, int *bitsAvail)
{
int i, bitsUsed;
PSInfoBase *psi;
BitStreamInfo bsi;
ADIFHeader *fhADIF;
ProgConfigElement *pce;
/* validate pointers */
if (!aacDecInfo || !aacDecInfo->psInfoBase)
return ERR_AAC_NULL_POINTER;
psi = (PSInfoBase *)(aacDecInfo->psInfoBase);
/* init bitstream reader */
SetBitstreamPointer(&bsi, (*bitsAvail + 7) >> 3, *buf);
GetBits(&bsi, *bitOffset);
/* unpack ADIF file header */
fhADIF = &(psi->fhADIF);
pce = psi->pce;
/* verify that first 32 bits of header are "ADIF" */
if (GetBits(&bsi, 8) != 'A' || GetBits(&bsi, 8) != 'D' || GetBits(&bsi, 8) != 'I' || GetBits(&bsi, 8) != 'F')
return ERR_AAC_INVALID_ADIF_HEADER;
/* read ADIF header fields */
fhADIF->copyBit = GetBits(&bsi, 1);
if (fhADIF->copyBit) {
for (i = 0; i < ADIF_COPYID_SIZE; i++)
fhADIF->copyID[i] = GetBits(&bsi, 8);
}
fhADIF->origCopy = GetBits(&bsi, 1);
fhADIF->home = GetBits(&bsi, 1);
fhADIF->bsType = GetBits(&bsi, 1);
fhADIF->bitRate = GetBits(&bsi, 23);
fhADIF->numPCE = GetBits(&bsi, 4) + 1; /* add 1 (so range = [1, 16]) */
if (fhADIF->bsType == 0)
fhADIF->bufferFull = GetBits(&bsi, 20);
/* parse all program config elements */
for (i = 0; i < fhADIF->numPCE; i++)
DecodeProgramConfigElement(pce + i, &bsi);
/* byte align */
ByteAlignBitstream(&bsi);
/* update codec info */
psi->nChans = GetNumChannelsADIF(pce, fhADIF->numPCE);
psi->sampRateIdx = GetSampleRateIdxADIF(pce, fhADIF->numPCE);
/* check validity of header */
if (psi->nChans < 0 || psi->sampRateIdx < 0 || psi->sampRateIdx >= NUM_SAMPLE_RATES)
return ERR_AAC_INVALID_ADIF_HEADER;
/* syntactic element fields will be read from bitstream for each element */
aacDecInfo->prevBlockID = AAC_ID_INVALID;
aacDecInfo->currBlockID = AAC_ID_INVALID;
aacDecInfo->currInstTag = -1;
/* fill in user-accessible data */
aacDecInfo->bitRate = 0;
aacDecInfo->nChans = psi->nChans;
aacDecInfo->sampRate = sampRateTab[psi->sampRateIdx];
aacDecInfo->profile = pce[0].profile;
aacDecInfo->sbrEnabled = 0;
/* update bitstream reader */
bitsUsed = CalcBitsUsed(&bsi, *buf, *bitOffset);
*buf += (bitsUsed + *bitOffset) >> 3;
*bitOffset = (bitsUsed + *bitOffset) & 0x07;
*bitsAvail -= bitsUsed ;
if (*bitsAvail < 0)
return ERR_AAC_INDATA_UNDERFLOW;
return ERR_AAC_NONE;
}
/**************************************************************************************
* Function: SetRawBlockParams
*
* Description: set internal state variables for decoding a stream of raw data blocks
*
* Inputs: valid AACDecInfo struct
* flag indicating source of parameters (from previous headers or passed
* explicitly by caller)
* number of channels
* sample rate
* profile ID
*
* Outputs: updated state variables in aacDecInfo
*
* Return: 0 if successful, error code (< 0) if error
*
* Notes: if copyLast == 1, then psi->nChans, psi->sampRateIdx, and
* aacDecInfo->profile are not changed (it's assumed that we already
* set them, such as by a previous call to UnpackADTSHeader())
* if copyLast == 0, then the parameters we passed in are used instead
**************************************************************************************/
int SetRawBlockParams(AACDecInfo *aacDecInfo, int copyLast, int nChans, int sampRate, int profile)
{
int idx;
PSInfoBase *psi;
/* validate pointers */
if (!aacDecInfo || !aacDecInfo->psInfoBase)
return ERR_AAC_NULL_POINTER;
psi = (PSInfoBase *)(aacDecInfo->psInfoBase);
if (!copyLast) {
aacDecInfo->profile = profile;
psi->nChans = nChans;
for (idx = 0; idx < NUM_SAMPLE_RATES; idx++) {
if (sampRate == sampRateTab[idx]) {
psi->sampRateIdx = idx;
break;
}
}
if (idx == NUM_SAMPLE_RATES)
return ERR_AAC_INVALID_FRAME;
}
aacDecInfo->nChans = psi->nChans;
aacDecInfo->sampRate = sampRateTab[psi->sampRateIdx];
/* check validity of header */
if (psi->sampRateIdx >= NUM_SAMPLE_RATES || psi->sampRateIdx < 0 || aacDecInfo->profile != AAC_PROFILE_LC)
return ERR_AAC_RAWBLOCK_PARAMS;
return ERR_AAC_NONE;
}
/**************************************************************************************
* Function: PrepareRawBlock
*
* Description: reset per-block state variables for raw blocks (no ADTS/ADIF headers)
*
* Inputs: valid AACDecInfo struct
*
* Outputs: updated state variables in aacDecInfo
*
* Return: 0 if successful, error code (< 0) if error
**************************************************************************************/
int PrepareRawBlock(AACDecInfo *aacDecInfo)
{
// PSInfoBase *psi;
/* validate pointers */
if (!aacDecInfo || !aacDecInfo->psInfoBase)
return ERR_AAC_NULL_POINTER;
// psi = (PSInfoBase *)(aacDecInfo->psInfoBase);
/* syntactic element fields will be read from bitstream for each element */
aacDecInfo->prevBlockID = AAC_ID_INVALID;
aacDecInfo->currBlockID = AAC_ID_INVALID;
aacDecInfo->currInstTag = -1;
/* fill in user-accessible data */
aacDecInfo->bitRate = 0;
aacDecInfo->sbrEnabled = 0;
return ERR_AAC_NONE;
}
/**************************************************************************************
* Function: FlushCodec
*
* Description: flush internal codec state (after seeking, for example)
*
* Inputs: valid AACDecInfo struct
*
* Outputs: updated state variables in aacDecInfo
*
* Return: 0 if successful, error code (< 0) if error
*
* Notes: only need to clear data which is persistent between frames
* (such as overlap buffer)
**************************************************************************************/
int FlushCodec(AACDecInfo *aacDecInfo)
{
PSInfoBase *psi;
/* validate pointers */
if (!aacDecInfo || !aacDecInfo->psInfoBase)
return ERR_AAC_NULL_POINTER;
psi = (PSInfoBase *)(aacDecInfo->psInfoBase);
ClearBuffer(psi->overlap, AAC_MAX_NCHANS * AAC_MAX_NSAMPS * sizeof(int));
ClearBuffer(psi->prevWinShape, AAC_MAX_NCHANS * sizeof(int));
return ERR_AAC_NONE;
}

View File

@@ -0,0 +1,415 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: huffman.c,v 1.2 2005/05/24 16:01:55 albertofloyd Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* huffman.c - Huffman decoding
**************************************************************************************/
#include "coder.h"
/**************************************************************************************
* Function: DecodeHuffmanScalar
*
* Description: decode one Huffman symbol from bitstream
*
* Inputs: pointers to Huffman table and info struct
* left-aligned bit buffer with >= huffTabInfo->maxBits bits
*
* Outputs: decoded symbol in *val
*
* Return: number of bits in symbol
*
* Notes: assumes canonical Huffman codes:
* first CW always 0, we have "count" CW's of length "nBits" bits
* starting CW for codes of length nBits+1 =
* (startCW[nBits] + count[nBits]) << 1
* if there are no codes at nBits, then we just keep << 1 each time
* (since count[nBits] = 0)
**************************************************************************************/
/* __attribute__ ((section (".data"))) */ int DecodeHuffmanScalar(const signed short *huffTab, const HuffInfo *huffTabInfo, unsigned int bitBuf, signed int *val)
{
unsigned int count, start, shift, t;
const unsigned /*char*/ int *countPtr;
const signed short *map;
map = huffTab + huffTabInfo->offset;
countPtr = huffTabInfo->count;
start = 0;
count = 0;
shift = 32;
do {
start += count;
start <<= 1;
map += count;
count = *countPtr++;
shift--;
t = (bitBuf >> shift) - start;
} while (t >= count);
*val = (signed int)pgm_read_word(&map[t]);
return (countPtr - huffTabInfo->count);
}
#define APPLY_SIGN(v, s) {(v) ^= ((signed int)(s) >> 31); (v) -= ((signed int)(s) >> 31);}
#define GET_QUAD_SIGNBITS(v) (((unsigned int)(v) << 17) >> 29) /* bits 14-12, unsigned */
#define GET_QUAD_W(v) (((signed int)(v) << 20) >> 29) /* bits 11-9, sign-extend */
#define GET_QUAD_X(v) (((signed int)(v) << 23) >> 29) /* bits 8-6, sign-extend */
#define GET_QUAD_Y(v) (((signed int)(v) << 26) >> 29) /* bits 5-3, sign-extend */
#define GET_QUAD_Z(v) (((signed int)(v) << 29) >> 29) /* bits 2-0, sign-extend */
#define GET_PAIR_SIGNBITS(v) (((unsigned int)(v) << 20) >> 30) /* bits 11-10, unsigned */
#define GET_PAIR_Y(v) (((signed int)(v) << 22) >> 27) /* bits 9-5, sign-extend */
#define GET_PAIR_Z(v) (((signed int)(v) << 27) >> 27) /* bits 4-0, sign-extend */
#define GET_ESC_SIGNBITS(v) (((unsigned int)(v) << 18) >> 30) /* bits 13-12, unsigned */
#define GET_ESC_Y(v) (((signed int)(v) << 20) >> 26) /* bits 11-6, sign-extend */
#define GET_ESC_Z(v) (((signed int)(v) << 26) >> 26) /* bits 5-0, sign-extend */
/**************************************************************************************
* Function: UnpackZeros
*
* Description: fill a section of coefficients with zeros
*
* Inputs: number of coefficients
*
* Outputs: nVals zeros, starting at coef
*
* Return: none
*
* Notes: assumes nVals is always a multiple of 4 because all scalefactor bands
* are a multiple of 4 coefficients long
**************************************************************************************/
static void UnpackZeros(int nVals, int *coef)
{
while (nVals > 0) {
*coef++ = 0;
*coef++ = 0;
*coef++ = 0;
*coef++ = 0;
nVals -= 4;
}
}
/**************************************************************************************
* Function: UnpackQuads
*
* Description: decode a section of 4-way vector Huffman coded coefficients
*
* Inputs BitStreamInfo struct pointing to start of codewords for this section
* index of Huffman codebook
* number of coefficients
*
* Outputs: nVals coefficients, starting at coef
*
* Return: none
*
* Notes: assumes nVals is always a multiple of 4 because all scalefactor bands
* are a multiple of 4 coefficients long
**************************************************************************************/
/* __attribute__ ((section (".data"))) */ static void UnpackQuads(BitStreamInfo *bsi, int cb, int nVals, int *coef)
{
int w, x, y, z, maxBits, nCodeBits, nSignBits, val;
unsigned int bitBuf;
maxBits = huffTabSpecInfo[cb - HUFFTAB_SPEC_OFFSET].maxBits + 4;
while (nVals > 0) {
/* decode quad */
bitBuf = GetBitsNoAdvance(bsi, maxBits) << (32 - maxBits);
nCodeBits = DecodeHuffmanScalar(huffTabSpec, &huffTabSpecInfo[cb - HUFFTAB_SPEC_OFFSET], bitBuf, &val);
w = GET_QUAD_W(val);
x = GET_QUAD_X(val);
y = GET_QUAD_Y(val);
z = GET_QUAD_Z(val);
bitBuf <<= nCodeBits;
nSignBits = (int)GET_QUAD_SIGNBITS(val);
AdvanceBitstream(bsi, nCodeBits + nSignBits);
if (nSignBits) {
if (w) {APPLY_SIGN(w, bitBuf); bitBuf <<= 1;}
if (x) {APPLY_SIGN(x, bitBuf); bitBuf <<= 1;}
if (y) {APPLY_SIGN(y, bitBuf); bitBuf <<= 1;}
if (z) {APPLY_SIGN(z, bitBuf); bitBuf <<= 1;}
}
*coef++ = w; *coef++ = x; *coef++ = y; *coef++ = z;
nVals -= 4;
}
}
/**************************************************************************************
* Function: UnpackPairsNoEsc
*
* Description: decode a section of 2-way vector Huffman coded coefficients,
* using non-esc tables (5 through 10)
*
* Inputs BitStreamInfo struct pointing to start of codewords for this section
* index of Huffman codebook (must not be the escape codebook)
* number of coefficients
*
* Outputs: nVals coefficients, starting at coef
*
* Return: none
*
* Notes: assumes nVals is always a multiple of 2 because all scalefactor bands
* are a multiple of 4 coefficients long
**************************************************************************************/
/* __attribute__ ((section (".data"))) */ static void UnpackPairsNoEsc(BitStreamInfo *bsi, int cb, int nVals, int *coef)
{
int y, z, maxBits, nCodeBits, nSignBits, val;
unsigned int bitBuf;
maxBits = huffTabSpecInfo[cb - HUFFTAB_SPEC_OFFSET].maxBits + 2;
while (nVals > 0) {
/* decode pair */
bitBuf = GetBitsNoAdvance(bsi, maxBits) << (32 - maxBits);
nCodeBits = DecodeHuffmanScalar(huffTabSpec, &huffTabSpecInfo[cb-HUFFTAB_SPEC_OFFSET], bitBuf, &val);
y = GET_PAIR_Y(val);
z = GET_PAIR_Z(val);
bitBuf <<= nCodeBits;
nSignBits = GET_PAIR_SIGNBITS(val);
AdvanceBitstream(bsi, nCodeBits + nSignBits);
if (nSignBits) {
if (y) {APPLY_SIGN(y, bitBuf); bitBuf <<= 1;}
if (z) {APPLY_SIGN(z, bitBuf); bitBuf <<= 1;}
}
*coef++ = y; *coef++ = z;
nVals -= 2;
}
}
/**************************************************************************************
* Function: UnpackPairsEsc
*
* Description: decode a section of 2-way vector Huffman coded coefficients,
* using esc table (11)
*
* Inputs BitStreamInfo struct pointing to start of codewords for this section
* index of Huffman codebook (must be the escape codebook)
* number of coefficients
*
* Outputs: nVals coefficients, starting at coef
*
* Return: none
*
* Notes: assumes nVals is always a multiple of 2 because all scalefactor bands
* are a multiple of 4 coefficients long
**************************************************************************************/
/* __attribute__ ((section (".data"))) */ static void UnpackPairsEsc(BitStreamInfo *bsi, int cb, int nVals, int *coef)
{
int y, z, maxBits, nCodeBits, nSignBits, n, val;
unsigned int bitBuf;
maxBits = huffTabSpecInfo[cb - HUFFTAB_SPEC_OFFSET].maxBits + 2;
while (nVals > 0) {
/* decode pair with escape value */
bitBuf = GetBitsNoAdvance(bsi, maxBits) << (32 - maxBits);
nCodeBits = DecodeHuffmanScalar(huffTabSpec, &huffTabSpecInfo[cb-HUFFTAB_SPEC_OFFSET], bitBuf, &val);
y = GET_ESC_Y(val);
z = GET_ESC_Z(val);
bitBuf <<= nCodeBits;
nSignBits = GET_ESC_SIGNBITS(val);
AdvanceBitstream(bsi, nCodeBits + nSignBits);
if (y == 16) {
n = 4;
while (GetBits(bsi, 1) == 1)
n++;
y = (1 << n) + GetBits(bsi, n);
}
if (z == 16) {
n = 4;
while (GetBits(bsi, 1) == 1)
n++;
z = (1 << n) + GetBits(bsi, n);
}
if (nSignBits) {
if (y) {APPLY_SIGN(y, bitBuf); bitBuf <<= 1;}
if (z) {APPLY_SIGN(z, bitBuf); bitBuf <<= 1;}
}
*coef++ = y; *coef++ = z;
nVals -= 2;
}
}
/**************************************************************************************
* Function: DecodeSpectrumLong
*
* Description: decode transform coefficients for frame with one long block
*
* Inputs: platform specific info struct
* BitStreamInfo struct pointing to start of spectral data
* (14496-3, table 4.4.29)
* index of current channel
*
* Outputs: decoded, quantized coefficients for this channel
*
* Return: none
*
* Notes: adds in pulse data if present
* fills coefficient buffer with zeros in any region not coded with
* codebook in range [1, 11] (including sfb's above sfbMax)
**************************************************************************************/
/* __attribute__ ((section (".data"))) */ void DecodeSpectrumLong(PSInfoBase *psi, BitStreamInfo *bsi, int ch)
{
int i, sfb, cb, nVals, offset;
const /*short*/ int *sfbTab;
unsigned char *sfbCodeBook;
int *coef;
ICSInfo *icsInfo;
PulseInfo *pi;
coef = psi->coef[ch];
icsInfo = (ch == 1 && psi->commonWin == 1) ? &(psi->icsInfo[0]) : &(psi->icsInfo[ch]);
/* decode long block */
sfbTab = sfBandTabLong + sfBandTabLongOffset[psi->sampRateIdx];
sfbCodeBook = psi->sfbCodeBook[ch];
for (sfb = 0; sfb < icsInfo->maxSFB; sfb++) {
cb = *sfbCodeBook++;
nVals = sfbTab[sfb+1] - sfbTab[sfb];
if (cb == 0)
UnpackZeros(nVals, coef);
else if (cb <= 4)
UnpackQuads(bsi, cb, nVals, coef);
else if (cb <= 10)
UnpackPairsNoEsc(bsi, cb, nVals, coef);
else if (cb == 11)
UnpackPairsEsc(bsi, cb, nVals, coef);
else
UnpackZeros(nVals, coef);
coef += nVals;
}
/* fill with zeros above maxSFB */
nVals = NSAMPS_LONG - sfbTab[sfb];
UnpackZeros(nVals, coef);
/* add pulse data, if present */
pi = &psi->pulseInfo[ch];
if (pi->pulseDataPresent) {
coef = psi->coef[ch];
offset = sfbTab[pi->startSFB];
for (i = 0; i < pi->numPulse; i++) {
offset += pi->offset[i];
if (coef[offset] > 0)
coef[offset] += pi->amp[i];
else
coef[offset] -= pi->amp[i];
}
ASSERT(offset < NSAMPS_LONG);
}
}
/**************************************************************************************
* Function: DecodeSpectrumShort
*
* Description: decode transform coefficients for frame with eight short blocks
*
* Inputs: platform specific info struct
* BitStreamInfo struct pointing to start of spectral data
* (14496-3, table 4.4.29)
* index of current channel
*
* Outputs: decoded, quantized coefficients for this channel
*
* Return: none
*
* Notes: fills coefficient buffer with zeros in any region not coded with
* codebook in range [1, 11] (including sfb's above sfbMax)
* deinterleaves window groups into 8 windows
**************************************************************************************/
/* __attribute__ ((section (".data"))) */ void DecodeSpectrumShort(PSInfoBase *psi, BitStreamInfo *bsi, int ch)
{
int gp, cb, nVals=0, win, offset, sfb;
const /*short*/ int *sfbTab;
unsigned char *sfbCodeBook;
int *coef;
ICSInfo *icsInfo;
coef = psi->coef[ch];
icsInfo = (ch == 1 && psi->commonWin == 1) ? &(psi->icsInfo[0]) : &(psi->icsInfo[ch]);
/* decode short blocks, deinterleaving in-place */
sfbTab = sfBandTabShort + sfBandTabShortOffset[psi->sampRateIdx];
sfbCodeBook = psi->sfbCodeBook[ch];
for (gp = 0; gp < icsInfo->numWinGroup; gp++) {
for (sfb = 0; sfb < icsInfo->maxSFB; sfb++) {
nVals = sfbTab[sfb+1] - sfbTab[sfb];
cb = *sfbCodeBook++;
for (win = 0; win < icsInfo->winGroupLen[gp]; win++) {
offset = win*NSAMPS_SHORT;
if (cb == 0)
UnpackZeros(nVals, coef + offset);
else if (cb <= 4)
UnpackQuads(bsi, cb, nVals, coef + offset);
else if (cb <= 10)
UnpackPairsNoEsc(bsi, cb, nVals, coef + offset);
else if (cb == 11)
UnpackPairsEsc(bsi, cb, nVals, coef + offset);
else
UnpackZeros(nVals, coef + offset);
}
coef += nVals;
}
/* fill with zeros above maxSFB */
for (win = 0; win < icsInfo->winGroupLen[gp]; win++) {
offset = win*NSAMPS_SHORT;
nVals = NSAMPS_SHORT - sfbTab[sfb];
UnpackZeros(nVals, coef + offset);
}
coef += nVals;
coef += (icsInfo->winGroupLen[gp] - 1)*NSAMPS_SHORT;
}
ASSERT(coef == psi->coef[ch] + NSAMPS_LONG);
}

View File

@@ -0,0 +1,177 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: hufftabs.c,v 1.1 2005/02/26 01:47:34 jrecker Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* hufftabs.c - Huffman symbol tables
**************************************************************************************/
#include "coder.h"
const HuffInfo huffTabSpecInfo[11] PROGMEM = {
/* table 0 not used */
{11, { 1, 0, 0, 0, 8, 0, 24, 0, 24, 8, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 0},
{ 9, { 0, 0, 1, 1, 7, 24, 15, 19, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 81},
{16, { 1, 0, 0, 4, 2, 6, 3, 5, 15, 15, 8, 9, 3, 3, 5, 2, 0, 0, 0, 0}, 162},
{12, { 0, 0, 0, 10, 6, 0, 9, 21, 8, 14, 11, 2, 0, 0, 0, 0, 0, 0, 0, 0}, 243},
{13, { 1, 0, 0, 4, 4, 0, 4, 12, 12, 12, 18, 10, 4, 0, 0, 0, 0, 0, 0, 0}, 324},
{11, { 0, 0, 0, 9, 0, 16, 13, 8, 23, 8, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 405},
{12, { 1, 0, 2, 1, 0, 4, 5, 10, 14, 15, 8, 4, 0, 0, 0, 0, 0, 0, 0, 0}, 486},
{10, { 0, 0, 1, 5, 7, 10, 14, 15, 8, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 550},
{15, { 1, 0, 2, 1, 0, 4, 3, 8, 11, 20, 31, 38, 32, 14, 4, 0, 0, 0, 0, 0}, 614},
{12, { 0, 0, 0, 3, 8, 14, 17, 25, 31, 41, 22, 8, 0, 0, 0, 0, 0, 0, 0, 0}, 783},
{12, { 0, 0, 0, 2, 6, 7, 16, 59, 55, 95, 43, 6, 0, 0, 0, 0, 0, 0, 0, 0}, 952},
};
const signed short huffTabSpec[1241] PROGMEM = {
/* spectrum table 1 [81] (signed) */
0x0000, 0x0200, 0x0e00, 0x0007, 0x0040, 0x0001, 0x0038, 0x0008, 0x01c0, 0x03c0, 0x0e40, 0x0039, 0x0078, 0x01c8, 0x000f, 0x0240,
0x003f, 0x0fc0, 0x01f8, 0x0238, 0x0047, 0x0e08, 0x0009, 0x0208, 0x01c1, 0x0048, 0x0041, 0x0e38, 0x0201, 0x0e07, 0x0207, 0x0e01,
0x01c7, 0x0278, 0x0e78, 0x03c8, 0x004f, 0x0079, 0x01c9, 0x01cf, 0x03f8, 0x0239, 0x007f, 0x0e48, 0x0e0f, 0x0fc8, 0x01f9, 0x03c1,
0x03c7, 0x0e47, 0x0ff8, 0x01ff, 0x0049, 0x020f, 0x0241, 0x0e41, 0x0248, 0x0fc1, 0x0e3f, 0x0247, 0x023f, 0x0e39, 0x0fc7, 0x0e09,
0x0209, 0x03cf, 0x0e79, 0x0e4f, 0x03f9, 0x0249, 0x0fc9, 0x027f, 0x0fcf, 0x0fff, 0x0279, 0x03c9, 0x0e49, 0x0e7f, 0x0ff9, 0x03ff,
0x024f,
/* spectrum table 2 [81] (signed) */
0x0000, 0x0200, 0x0e00, 0x0001, 0x0038, 0x0007, 0x01c0, 0x0008, 0x0040, 0x01c8, 0x0e40, 0x0078, 0x000f, 0x0047, 0x0039, 0x0e07,
0x03c0, 0x0238, 0x0fc0, 0x003f, 0x0208, 0x0201, 0x01c1, 0x0e08, 0x0041, 0x01f8, 0x0e01, 0x01c7, 0x0e38, 0x0240, 0x0048, 0x0009,
0x0207, 0x0079, 0x0239, 0x0e78, 0x01cf, 0x03c8, 0x0247, 0x0209, 0x0e48, 0x01f9, 0x0248, 0x0e0f, 0x0ff8, 0x0e39, 0x03f8, 0x0278,
0x03c1, 0x0e47, 0x0fc8, 0x0e09, 0x0fc1, 0x0fc7, 0x01ff, 0x020f, 0x023f, 0x007f, 0x0049, 0x0e41, 0x0e3f, 0x004f, 0x03c7, 0x01c9,
0x0241, 0x03cf, 0x0e79, 0x03f9, 0x0fff, 0x0e4f, 0x0e49, 0x0249, 0x0fcf, 0x03c9, 0x0e7f, 0x0fc9, 0x027f, 0x03ff, 0x0ff9, 0x0279,
0x024f,
/* spectrum table 3 [81] (unsigned) */
0x0000, 0x1200, 0x1001, 0x1040, 0x1008, 0x2240, 0x2009, 0x2048, 0x2041, 0x2208, 0x3049, 0x2201, 0x3248, 0x4249, 0x3209, 0x3241,
0x1400, 0x1002, 0x200a, 0x2440, 0x3288, 0x2011, 0x3051, 0x2280, 0x304a, 0x3448, 0x1010, 0x2088, 0x2050, 0x1080, 0x2042, 0x2408,
0x4289, 0x3089, 0x3250, 0x4251, 0x3281, 0x2210, 0x3211, 0x2081, 0x4449, 0x424a, 0x3441, 0x320a, 0x2012, 0x3052, 0x3488, 0x3290,
0x2202, 0x2401, 0x3091, 0x2480, 0x4291, 0x3242, 0x3409, 0x4252, 0x4489, 0x2090, 0x308a, 0x3212, 0x3481, 0x3450, 0x3490, 0x3092,
0x4491, 0x4451, 0x428a, 0x4292, 0x2082, 0x2410, 0x3282, 0x3411, 0x444a, 0x3442, 0x4492, 0x448a, 0x4452, 0x340a, 0x2402, 0x3482,
0x3412,
/* spectrum table 4 [81] (unsigned) */
0x4249, 0x3049, 0x3241, 0x3248, 0x3209, 0x1200, 0x2240, 0x0000, 0x2009, 0x2208, 0x2201, 0x2048, 0x1001, 0x2041, 0x1008, 0x1040,
0x4449, 0x4251, 0x4289, 0x424a, 0x3448, 0x3441, 0x3288, 0x3409, 0x3051, 0x304a, 0x3250, 0x3089, 0x320a, 0x3281, 0x3242, 0x3211,
0x2440, 0x2408, 0x2280, 0x2401, 0x2042, 0x2088, 0x200a, 0x2050, 0x2081, 0x2202, 0x2011, 0x2210, 0x1400, 0x1002, 0x1080, 0x1010,
0x4291, 0x4489, 0x4451, 0x4252, 0x428a, 0x444a, 0x3290, 0x3488, 0x3450, 0x3091, 0x3052, 0x3481, 0x308a, 0x3411, 0x3212, 0x4491,
0x3282, 0x340a, 0x3442, 0x4292, 0x4452, 0x448a, 0x2090, 0x2480, 0x2012, 0x2410, 0x2082, 0x2402, 0x4492, 0x3092, 0x3490, 0x3482,
0x3412,
/* spectrum table 5 [81] (signed) */
0x0000, 0x03e0, 0x0020, 0x0001, 0x001f, 0x003f, 0x03e1, 0x03ff, 0x0021, 0x03c0, 0x0002, 0x0040, 0x001e, 0x03df, 0x0041, 0x03fe,
0x0022, 0x03c1, 0x005f, 0x03e2, 0x003e, 0x03a0, 0x0060, 0x001d, 0x0003, 0x03bf, 0x0023, 0x0061, 0x03fd, 0x03a1, 0x007f, 0x003d,
0x03e3, 0x03c2, 0x0042, 0x03de, 0x005e, 0x03be, 0x007e, 0x03c3, 0x005d, 0x0062, 0x0043, 0x03a2, 0x03dd, 0x001c, 0x0380, 0x0081,
0x0080, 0x039f, 0x0004, 0x009f, 0x03fc, 0x0024, 0x03e4, 0x0381, 0x003c, 0x007d, 0x03bd, 0x03a3, 0x03c4, 0x039e, 0x0082, 0x005c,
0x0044, 0x0063, 0x0382, 0x03dc, 0x009e, 0x007c, 0x039d, 0x0383, 0x0064, 0x03a4, 0x0083, 0x009d, 0x03bc, 0x009c, 0x0384, 0x0084,
0x039c,
/* spectrum table 6 [81] (signed) */
0x0000, 0x0020, 0x001f, 0x0001, 0x03e0, 0x0021, 0x03e1, 0x003f, 0x03ff, 0x005f, 0x0041, 0x03c1, 0x03df, 0x03c0, 0x03e2, 0x0040,
0x003e, 0x0022, 0x001e, 0x03fe, 0x0002, 0x005e, 0x03c2, 0x03de, 0x0042, 0x03a1, 0x0061, 0x007f, 0x03e3, 0x03bf, 0x0023, 0x003d,
0x03fd, 0x0060, 0x03a0, 0x001d, 0x0003, 0x0062, 0x03be, 0x03c3, 0x0043, 0x007e, 0x005d, 0x03dd, 0x03a2, 0x0063, 0x007d, 0x03bd,
0x03a3, 0x003c, 0x03fc, 0x0081, 0x0381, 0x039f, 0x0024, 0x009f, 0x03e4, 0x001c, 0x0382, 0x039e, 0x0044, 0x03dc, 0x0380, 0x0082,
0x009e, 0x03c4, 0x0080, 0x005c, 0x0004, 0x03bc, 0x03a4, 0x007c, 0x009d, 0x0064, 0x0083, 0x0383, 0x039d, 0x0084, 0x0384, 0x039c,
0x009c,
/* spectrum table 7 [64] (unsigned) */
0x0000, 0x0420, 0x0401, 0x0821, 0x0841, 0x0822, 0x0440, 0x0402, 0x0861, 0x0823, 0x0842, 0x0460, 0x0403, 0x0843, 0x0862, 0x0824,
0x0881, 0x0825, 0x08a1, 0x0863, 0x0844, 0x0404, 0x0480, 0x0882, 0x0845, 0x08a2, 0x0405, 0x08c1, 0x04a0, 0x0826, 0x0883, 0x0865,
0x0864, 0x08a3, 0x0846, 0x08c2, 0x0827, 0x0866, 0x0406, 0x04c0, 0x0884, 0x08e1, 0x0885, 0x08e2, 0x08a4, 0x08c3, 0x0847, 0x08e3,
0x08c4, 0x08a5, 0x0886, 0x0867, 0x04e0, 0x0407, 0x08c5, 0x08a6, 0x08e4, 0x0887, 0x08a7, 0x08e5, 0x08e6, 0x08c6, 0x08c7, 0x08e7,
/* spectrum table 8 [64] (unsigned) */
0x0821, 0x0841, 0x0420, 0x0822, 0x0401, 0x0842, 0x0000, 0x0440, 0x0402, 0x0861, 0x0823, 0x0862, 0x0843, 0x0863, 0x0881, 0x0824,
0x0882, 0x0844, 0x0460, 0x0403, 0x0883, 0x0864, 0x08a2, 0x08a1, 0x0845, 0x0825, 0x08a3, 0x0865, 0x0884, 0x08a4, 0x0404, 0x0885,
0x0480, 0x0846, 0x08c2, 0x08c1, 0x0826, 0x0866, 0x08c3, 0x08a5, 0x04a0, 0x08c4, 0x0405, 0x0886, 0x08e1, 0x08e2, 0x0847, 0x08c5,
0x08e3, 0x0827, 0x08a6, 0x0867, 0x08c6, 0x08e4, 0x04c0, 0x0887, 0x0406, 0x08e5, 0x08e6, 0x08c7, 0x08a7, 0x04e0, 0x0407, 0x08e7,
/* spectrum table 9 [169] (unsigned) */
0x0000, 0x0420, 0x0401, 0x0821, 0x0841, 0x0822, 0x0440, 0x0402, 0x0861, 0x0842, 0x0823, 0x0460, 0x0403, 0x0843, 0x0862, 0x0824,
0x0881, 0x0844, 0x0825, 0x0882, 0x0863, 0x0404, 0x0480, 0x08a1, 0x0845, 0x0826, 0x0864, 0x08a2, 0x08c1, 0x0883, 0x0405, 0x0846,
0x04a0, 0x0827, 0x0865, 0x0828, 0x0901, 0x0884, 0x08a3, 0x08c2, 0x08e1, 0x0406, 0x0902, 0x0848, 0x0866, 0x0847, 0x0885, 0x0921,
0x0829, 0x08e2, 0x04c0, 0x08a4, 0x08c3, 0x0903, 0x0407, 0x0922, 0x0868, 0x0886, 0x0867, 0x0408, 0x0941, 0x08c4, 0x0849, 0x08a5,
0x0500, 0x04e0, 0x08e3, 0x0942, 0x0923, 0x0904, 0x082a, 0x08e4, 0x08c5, 0x08a6, 0x0888, 0x0887, 0x0869, 0x0961, 0x08a8, 0x0520,
0x0905, 0x0943, 0x084a, 0x0409, 0x0962, 0x0924, 0x08c6, 0x0981, 0x0889, 0x0906, 0x082b, 0x0925, 0x0944, 0x08a7, 0x08e5, 0x084b,
0x082c, 0x0982, 0x0963, 0x086a, 0x08a9, 0x08c7, 0x0907, 0x0964, 0x040a, 0x08e6, 0x0983, 0x0540, 0x0945, 0x088a, 0x08c8, 0x084c,
0x0926, 0x0927, 0x088b, 0x0560, 0x08c9, 0x086b, 0x08aa, 0x0908, 0x08e8, 0x0985, 0x086c, 0x0965, 0x08e7, 0x0984, 0x0966, 0x0946,
0x088c, 0x08e9, 0x08ab, 0x040b, 0x0986, 0x08ca, 0x0580, 0x0947, 0x08ac, 0x08ea, 0x0928, 0x040c, 0x0967, 0x0909, 0x0929, 0x0948,
0x08eb, 0x0987, 0x08cb, 0x090b, 0x0968, 0x08ec, 0x08cc, 0x090a, 0x0949, 0x090c, 0x092a, 0x092b, 0x092c, 0x094b, 0x0989, 0x094a,
0x0969, 0x0988, 0x096a, 0x098a, 0x098b, 0x094c, 0x096b, 0x096c, 0x098c,
/* spectrum table 10 [169] (unsigned) */
0x0821, 0x0822, 0x0841, 0x0842, 0x0420, 0x0401, 0x0823, 0x0862, 0x0861, 0x0843, 0x0863, 0x0440, 0x0402, 0x0844, 0x0882, 0x0824,
0x0881, 0x0000, 0x0883, 0x0864, 0x0460, 0x0403, 0x0884, 0x0845, 0x08a2, 0x0825, 0x08a1, 0x08a3, 0x0865, 0x08a4, 0x0885, 0x08c2,
0x0846, 0x08c3, 0x0480, 0x08c1, 0x0404, 0x0826, 0x0866, 0x08a5, 0x08c4, 0x0886, 0x08c5, 0x08e2, 0x0867, 0x0847, 0x08a6, 0x0902,
0x08e3, 0x04a0, 0x08e1, 0x0405, 0x0901, 0x0827, 0x0903, 0x08e4, 0x0887, 0x0848, 0x08c6, 0x08e5, 0x0828, 0x0868, 0x0904, 0x0888,
0x08a7, 0x0905, 0x08a8, 0x08e6, 0x08c7, 0x0922, 0x04c0, 0x08c8, 0x0923, 0x0869, 0x0921, 0x0849, 0x0406, 0x0906, 0x0924, 0x0889,
0x0942, 0x0829, 0x08e7, 0x0907, 0x0925, 0x08e8, 0x0943, 0x08a9, 0x0944, 0x084a, 0x0941, 0x086a, 0x0926, 0x08c9, 0x0500, 0x088a,
0x04e0, 0x0962, 0x08e9, 0x0963, 0x0946, 0x082a, 0x0961, 0x0927, 0x0407, 0x0908, 0x0945, 0x086b, 0x08aa, 0x0909, 0x0965, 0x0408,
0x0964, 0x084b, 0x08ea, 0x08ca, 0x0947, 0x088b, 0x082b, 0x0982, 0x0928, 0x0983, 0x0966, 0x08ab, 0x0984, 0x0967, 0x0985, 0x086c,
0x08cb, 0x0520, 0x0948, 0x0540, 0x0981, 0x0409, 0x088c, 0x0929, 0x0986, 0x084c, 0x090a, 0x092a, 0x082c, 0x0968, 0x0987, 0x08eb,
0x08ac, 0x08cc, 0x0949, 0x090b, 0x0988, 0x040a, 0x08ec, 0x0560, 0x094a, 0x0969, 0x096a, 0x040b, 0x096b, 0x092b, 0x094b, 0x0580,
0x090c, 0x0989, 0x094c, 0x092c, 0x096c, 0x098b, 0x040c, 0x098a, 0x098c,
/* spectrum table 11 [289] (unsigned) */
0x0000, 0x2041, 0x2410, 0x1040, 0x1001, 0x2081, 0x2042, 0x2082, 0x2043, 0x20c1, 0x20c2, 0x1080, 0x2083, 0x1002, 0x20c3, 0x2101,
0x2044, 0x2102, 0x2084, 0x2103, 0x20c4, 0x10c0, 0x1003, 0x2141, 0x2142, 0x2085, 0x2104, 0x2045, 0x2143, 0x20c5, 0x2144, 0x2105,
0x2182, 0x2086, 0x2181, 0x2183, 0x20c6, 0x2046, 0x2110, 0x20d0, 0x2405, 0x2403, 0x2404, 0x2184, 0x2406, 0x1100, 0x2106, 0x1004,
0x2090, 0x2145, 0x2150, 0x2407, 0x2402, 0x2408, 0x2087, 0x21c2, 0x20c7, 0x2185, 0x2146, 0x2190, 0x240a, 0x21c3, 0x21c1, 0x2409,
0x21d0, 0x2050, 0x2047, 0x2107, 0x240b, 0x21c4, 0x240c, 0x2210, 0x2401, 0x2186, 0x2250, 0x2088, 0x2147, 0x2290, 0x240d, 0x2203,
0x2202, 0x20c8, 0x1140, 0x240e, 0x22d0, 0x21c5, 0x2108, 0x2187, 0x21c6, 0x1005, 0x2204, 0x240f, 0x2310, 0x2048, 0x2201, 0x2390,
0x2148, 0x2350, 0x20c9, 0x2205, 0x21c7, 0x2089, 0x2206, 0x2242, 0x2243, 0x23d0, 0x2109, 0x2188, 0x1180, 0x2244, 0x2149, 0x2207,
0x21c8, 0x2049, 0x2283, 0x1006, 0x2282, 0x2241, 0x2245, 0x210a, 0x208a, 0x2246, 0x20ca, 0x2189, 0x2284, 0x2208, 0x2285, 0x2247,
0x22c3, 0x204a, 0x11c0, 0x2286, 0x21c9, 0x20cb, 0x214a, 0x2281, 0x210b, 0x22c2, 0x2342, 0x218a, 0x2343, 0x208b, 0x1400, 0x214b,
0x22c5, 0x22c4, 0x2248, 0x21ca, 0x2209, 0x1010, 0x210d, 0x1007, 0x20cd, 0x22c6, 0x2341, 0x2344, 0x2303, 0x208d, 0x2345, 0x220a,
0x218b, 0x2288, 0x2287, 0x2382, 0x2304, 0x204b, 0x210c, 0x22c1, 0x20cc, 0x204d, 0x2302, 0x21cb, 0x20ce, 0x214c, 0x214d, 0x2384,
0x210e, 0x22c7, 0x2383, 0x2305, 0x2346, 0x2306, 0x1200, 0x22c8, 0x208c, 0x2249, 0x2385, 0x218d, 0x228a, 0x23c2, 0x220b, 0x224a,
0x2386, 0x2289, 0x214e, 0x22c9, 0x2381, 0x208e, 0x218c, 0x204c, 0x2348, 0x1008, 0x2347, 0x21cc, 0x2307, 0x21cd, 0x23c3, 0x2301,
0x218e, 0x208f, 0x23c5, 0x23c4, 0x204e, 0x224b, 0x210f, 0x2387, 0x220d, 0x2349, 0x220c, 0x214f, 0x20cf, 0x228b, 0x22ca, 0x2308,
0x23c6, 0x23c7, 0x220e, 0x23c1, 0x21ce, 0x1240, 0x1009, 0x224d, 0x224c, 0x2309, 0x2388, 0x228d, 0x2389, 0x230a, 0x218f, 0x21cf,
0x224e, 0x23c8, 0x22cb, 0x22ce, 0x204f, 0x228c, 0x228e, 0x234b, 0x234a, 0x22cd, 0x22cc, 0x220f, 0x238b, 0x234c, 0x230d, 0x23c9,
0x238a, 0x1280, 0x230b, 0x224f, 0x100a, 0x230c, 0x12c0, 0x230e, 0x228f, 0x234d, 0x100d, 0x238c, 0x23ca, 0x23cb, 0x22cf, 0x238d,
0x1340, 0x100b, 0x234e, 0x23cc, 0x23cd, 0x230f, 0x1380, 0x238e, 0x234f, 0x1300, 0x238f, 0x100e, 0x100c, 0x23ce, 0x13c0, 0x100f,
0x23cf,
};
const HuffInfo huffTabScaleFactInfo PROGMEM =
{19, { 1, 0, 1, 3, 2, 4, 3, 5, 4, 6, 6, 6, 5, 8, 4, 7, 3, 7, 46, 0}, 0};
/* note - includes offset of -60 (4.6.2.3 in spec) */
const signed short huffTabScaleFact[121] PROGMEM = {
/* scale factor table [121] */
0, -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, 14, -14, 16, 15, 17,
18, -15, -17, -16, 19, -18, -19, 20, -20, 21, -21, 22, -22, 23, -23, -25,
25, -27, -24, -26, 24, -28, 27, 29, -30, -29, 26, -31, -34, -33, -32, -36,
28, -35, -38, -37, 30, -39, -41, -57, -59, -58, -60, 38, 39, 40, 41, 42,
57, 37, 31, 32, 33, 34, 35, 36, 44, 51, 52, 53, 54, 55, 56, 50,
45, 46, 47, 48, 49, 58, -54, -52, -51, -50, -55, 43, 60, 59, -56, -53,
-45, -44, -42, -40, -43, -49, -48, -46, -47,
};

View File

@@ -0,0 +1,589 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: imdct.c,v 1.1 2005/02/26 01:47:35 jrecker Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* imdct.c - inverse MDCT
**************************************************************************************/
#include "coder.h"
#include "assembly.h"
#define RND_VAL (1 << (FBITS_OUT_IMDCT-1))
#ifndef AAC_ENABLE_SBR
/**************************************************************************************
* Function: DecWindowOverlap
*
* Description: apply synthesis window, do overlap-add, clip to 16-bit PCM,
* for winSequence LONG-LONG
*
* Inputs: input buffer (output of type-IV DCT)
* overlap buffer (saved from last time)
* number of channels
* window type (sin or KBD) for input buffer
* window type (sin or KBD) for overlap buffer
*
* Outputs: one channel, one frame of 16-bit PCM, interleaved by nChans
*
* Return: none
*
* Notes: this processes one channel at a time, but skips every other sample in
* the output buffer (pcm) for stereo interleaving
* this should fit in registers on ARM
*
* TODO: ARM5E version with saturating overlap/add (QADD)
* asm code with free pointer updates, better load scheduling
**************************************************************************************/
/*__attribute__ ((section (".data")))*/ static void DecWindowOverlap(int *buf0, int *over0, short *pcm0, int nChans, int winTypeCurr, int winTypePrev)
{
int in, w0, w1, f0, f1;
int *buf1, *over1;
short *pcm1;
const int *wndPrev, *wndCurr;
buf0 += (1024 >> 1);
buf1 = buf0 - 1;
pcm1 = pcm0 + (1024 - 1) * nChans;
over1 = over0 + 1024 - 1;
wndPrev = (winTypePrev == 1 ? kbdWindow + kbdWindowOffset[1] : sinWindow + sinWindowOffset[1]);
if (winTypeCurr == winTypePrev) {
/* cut window loads in half since current and overlap sections use same symmetric window */
do {
w0 = *wndPrev++;
w1 = *wndPrev++;
in = *buf0++;
f0 = MULSHIFT32(w0, in);
f1 = MULSHIFT32(w1, in);
in = *over0;
*pcm0 = CLIPTOSHORT( (in - f0 + RND_VAL) >> FBITS_OUT_IMDCT );
pcm0 += nChans;
in = *over1;
*pcm1 = CLIPTOSHORT( (in + f1 + RND_VAL) >> FBITS_OUT_IMDCT );
pcm1 -= nChans;
in = *buf1--;
*over1-- = MULSHIFT32(w0, in);
*over0++ = MULSHIFT32(w1, in);
} while (over0 < over1);
} else {
/* different windows for current and overlap parts - should still fit in registers on ARM w/o stack spill */
wndCurr = (winTypeCurr == 1 ? kbdWindow + kbdWindowOffset[1] : sinWindow + sinWindowOffset[1]);
do {
w0 = *wndPrev++;
w1 = *wndPrev++;
in = *buf0++;
f0 = MULSHIFT32(w0, in);
f1 = MULSHIFT32(w1, in);
in = *over0;
*pcm0 = CLIPTOSHORT( (in - f0 + RND_VAL) >> FBITS_OUT_IMDCT );
pcm0 += nChans;
in = *over1;
*pcm1 = CLIPTOSHORT( (in + f1 + RND_VAL) >> FBITS_OUT_IMDCT );
pcm1 -= nChans;
w0 = *wndCurr++;
w1 = *wndCurr++;
in = *buf1--;
*over1-- = MULSHIFT32(w0, in);
*over0++ = MULSHIFT32(w1, in);
} while (over0 < over1);
}
}
/**************************************************************************************
* Function: DecWindowOverlapLongStart
*
* Description: apply synthesis window, do overlap-add, clip to 16-bit PCM,
* for winSequence LONG-START
*
* Inputs: input buffer (output of type-IV DCT)
* overlap buffer (saved from last time)
* number of channels
* window type (sin or KBD) for input buffer
* window type (sin or KBD) for overlap buffer
*
* Outputs: one channel, one frame of 16-bit PCM, interleaved by nChans
*
* Return: none
*
* Notes: this processes one channel at a time, but skips every other sample in
* the output buffer (pcm) for stereo interleaving
* this should fit in registers on ARM
*
* TODO: ARM5E version with saturating overlap/add (QADD)
* asm code with free pointer updates, better load scheduling
**************************************************************************************/
/*__attribute__ ((section (".data")))*/ static void DecWindowOverlapLongStart(int *buf0, int *over0, short *pcm0, int nChans, int winTypeCurr, int winTypePrev)
{
int i, in, w0, w1, f0, f1;
int *buf1, *over1;
short *pcm1;
const int *wndPrev, *wndCurr;
buf0 += (1024 >> 1);
buf1 = buf0 - 1;
pcm1 = pcm0 + (1024 - 1) * nChans;
over1 = over0 + 1024 - 1;
wndPrev = (winTypePrev == 1 ? kbdWindow + kbdWindowOffset[1] : sinWindow + sinWindowOffset[1]);
i = 448; /* 2 outputs, 2 overlaps per loop */
do {
w0 = *wndPrev++;
w1 = *wndPrev++;
in = *buf0++;
f0 = MULSHIFT32(w0, in);
f1 = MULSHIFT32(w1, in);
in = *over0;
*pcm0 = CLIPTOSHORT( (in - f0 + RND_VAL) >> FBITS_OUT_IMDCT );
pcm0 += nChans;
in = *over1;
*pcm1 = CLIPTOSHORT( (in + f1 + RND_VAL) >> FBITS_OUT_IMDCT );
pcm1 -= nChans;
in = *buf1--;
*over1-- = 0; /* Wn = 0 for n = (2047, 2046, ... 1600) */
*over0++ = in >> 1; /* Wn = 1 for n = (1024, 1025, ... 1471) */
} while (--i);
wndCurr = (winTypeCurr == 1 ? kbdWindow + kbdWindowOffset[0] : sinWindow + sinWindowOffset[0]);
/* do 64 more loops - 2 outputs, 2 overlaps per loop */
do {
w0 = *wndPrev++;
w1 = *wndPrev++;
in = *buf0++;
f0 = MULSHIFT32(w0, in);
f1 = MULSHIFT32(w1, in);
in = *over0;
*pcm0 = CLIPTOSHORT( (in - f0 + RND_VAL) >> FBITS_OUT_IMDCT );
pcm0 += nChans;
in = *over1;
*pcm1 = CLIPTOSHORT( (in + f1 + RND_VAL) >> FBITS_OUT_IMDCT );
pcm1 -= nChans;
w0 = *wndCurr++; /* W[0], W[1], ... --> W[255], W[254], ... */
w1 = *wndCurr++; /* W[127], W[126], ... --> W[128], W[129], ... */
in = *buf1--;
*over1-- = MULSHIFT32(w0, in); /* Wn = short window for n = (1599, 1598, ... , 1536) */
*over0++ = MULSHIFT32(w1, in); /* Wn = short window for n = (1472, 1473, ... , 1535) */
} while (over0 < over1);
}
/**************************************************************************************
* Function: DecWindowOverlapLongStop
*
* Description: apply synthesis window, do overlap-add, clip to 16-bit PCM,
* for winSequence LONG-STOP
*
* Inputs: input buffer (output of type-IV DCT)
* overlap buffer (saved from last time)
* number of channels
* window type (sin or KBD) for input buffer
* window type (sin or KBD) for overlap buffer
*
* Outputs: one channel, one frame of 16-bit PCM, interleaved by nChans
*
* Return: none
*
* Notes: this processes one channel at a time, but skips every other sample in
* the output buffer (pcm) for stereo interleaving
* this should fit in registers on ARM
*
* TODO: ARM5E version with saturating overlap/add (QADD)
* asm code with free pointer updates, better load scheduling
**************************************************************************************/
/*__attribute__ ((section (".data")))*/ static void DecWindowOverlapLongStop(int *buf0, int *over0, short *pcm0, int nChans, int winTypeCurr, int winTypePrev)
{
int i, in, w0, w1, f0, f1;
int *buf1, *over1;
short *pcm1;
const int *wndPrev, *wndCurr;
buf0 += (1024 >> 1);
buf1 = buf0 - 1;
pcm1 = pcm0 + (1024 - 1) * nChans;
over1 = over0 + 1024 - 1;
wndPrev = (winTypePrev == 1 ? kbdWindow + kbdWindowOffset[0] : sinWindow + sinWindowOffset[0]);
wndCurr = (winTypeCurr == 1 ? kbdWindow + kbdWindowOffset[1] : sinWindow + sinWindowOffset[1]);
i = 448; /* 2 outputs, 2 overlaps per loop */
do {
/* Wn = 0 for n = (0, 1, ... 447) */
/* Wn = 1 for n = (576, 577, ... 1023) */
in = *buf0++;
f1 = in >> 1; /* scale since skipping multiply by Q31 */
in = *over0;
*pcm0 = CLIPTOSHORT( (in + RND_VAL) >> FBITS_OUT_IMDCT );
pcm0 += nChans;
in = *over1;
*pcm1 = CLIPTOSHORT( (in + f1 + RND_VAL) >> FBITS_OUT_IMDCT );
pcm1 -= nChans;
w0 = *wndCurr++;
w1 = *wndCurr++;
in = *buf1--;
*over1-- = MULSHIFT32(w0, in);
*over0++ = MULSHIFT32(w1, in);
} while (--i);
/* do 64 more loops - 2 outputs, 2 overlaps per loop */
do {
w0 = *wndPrev++; /* W[0], W[1], ...W[63] */
w1 = *wndPrev++; /* W[127], W[126], ... W[64] */
in = *buf0++;
f0 = MULSHIFT32(w0, in);
f1 = MULSHIFT32(w1, in);
in = *over0;
*pcm0 = CLIPTOSHORT( (in - f0 + RND_VAL) >> FBITS_OUT_IMDCT );
pcm0 += nChans;
in = *over1;
*pcm1 = CLIPTOSHORT( (in + f1 + RND_VAL) >> FBITS_OUT_IMDCT );
pcm1 -= nChans;
w0 = *wndCurr++;
w1 = *wndCurr++;
in = *buf1--;
*over1-- = MULSHIFT32(w0, in);
*over0++ = MULSHIFT32(w1, in);
} while (over0 < over1);
}
/**************************************************************************************
* Function: DecWindowOverlapShort
*
* Description: apply synthesis window, do overlap-add, clip to 16-bit PCM,
* for winSequence EIGHT-SHORT (does all 8 short blocks)
*
* Inputs: input buffer (output of type-IV DCT)
* overlap buffer (saved from last time)
* number of channels
* window type (sin or KBD) for input buffer
* window type (sin or KBD) for overlap buffer
*
* Outputs: one channel, one frame of 16-bit PCM, interleaved by nChans
*
* Return: none
*
* Notes: this processes one channel at a time, but skips every other sample in
* the output buffer (pcm) for stereo interleaving
* this should fit in registers on ARM
*
* TODO: ARM5E version with saturating overlap/add (QADD)
* asm code with free pointer updates, better load scheduling
**************************************************************************************/
/*__attribute__ ((section (".data"))) */ static void DecWindowOverlapShort(int *buf0, int *over0, short *pcm0, int nChans, int winTypeCurr, int winTypePrev)
{
int i, in, w0, w1, f0, f1;
int *buf1, *over1;
short *pcm1;
const int *wndPrev, *wndCurr;
wndPrev = (winTypePrev == 1 ? kbdWindow + kbdWindowOffset[0] : sinWindow + sinWindowOffset[0]);
wndCurr = (winTypeCurr == 1 ? kbdWindow + kbdWindowOffset[0] : sinWindow + sinWindowOffset[0]);
/* pcm[0-447] = 0 + overlap[0-447] */
i = 448;
do {
f0 = *over0++;
f1 = *over0++;
*pcm0 = CLIPTOSHORT( (f0 + RND_VAL) >> FBITS_OUT_IMDCT ); pcm0 += nChans;
*pcm0 = CLIPTOSHORT( (f1 + RND_VAL) >> FBITS_OUT_IMDCT ); pcm0 += nChans;
i -= 2;
} while (i);
/* pcm[448-575] = Wp[0-127] * block0[0-127] + overlap[448-575] */
pcm1 = pcm0 + (128 - 1) * nChans;
over1 = over0 + 128 - 1;
buf0 += 64;
buf1 = buf0 - 1;
do {
w0 = *wndPrev++; /* W[0], W[1], ...W[63] */
w1 = *wndPrev++; /* W[127], W[126], ... W[64] */
in = *buf0++;
f0 = MULSHIFT32(w0, in);
f1 = MULSHIFT32(w1, in);
in = *over0;
*pcm0 = CLIPTOSHORT( (in - f0 + RND_VAL) >> FBITS_OUT_IMDCT );
pcm0 += nChans;
in = *over1;
*pcm1 = CLIPTOSHORT( (in + f1 + RND_VAL) >> FBITS_OUT_IMDCT );
pcm1 -= nChans;
w0 = *wndCurr++;
w1 = *wndCurr++;
in = *buf1--;
/* save over0/over1 for next short block, in the slots just vacated */
*over1-- = MULSHIFT32(w0, in);
*over0++ = MULSHIFT32(w1, in);
} while (over0 < over1);
/* pcm[576-703] = Wc[128-255] * block0[128-255] + Wc[0-127] * block1[0-127] + overlap[576-703]
* pcm[704-831] = Wc[128-255] * block1[128-255] + Wc[0-127] * block2[0-127] + overlap[704-831]
* pcm[832-959] = Wc[128-255] * block2[128-255] + Wc[0-127] * block3[0-127] + overlap[832-959]
*/
for (i = 0; i < 3; i++) {
pcm0 += 64 * nChans;
pcm1 = pcm0 + (128 - 1) * nChans;
over0 += 64;
over1 = over0 + 128 - 1;
buf0 += 64;
buf1 = buf0 - 1;
wndCurr -= 128;
do {
w0 = *wndCurr++; /* W[0], W[1], ...W[63] */
w1 = *wndCurr++; /* W[127], W[126], ... W[64] */
in = *buf0++;
f0 = MULSHIFT32(w0, in);
f1 = MULSHIFT32(w1, in);
in = *(over0 - 128); /* from last short block */
in += *(over0 + 0); /* from last full frame */
*pcm0 = CLIPTOSHORT( (in - f0 + RND_VAL) >> FBITS_OUT_IMDCT );
pcm0 += nChans;
in = *(over1 - 128); /* from last short block */
in += *(over1 + 0); /* from last full frame */
*pcm1 = CLIPTOSHORT( (in + f1 + RND_VAL) >> FBITS_OUT_IMDCT );
pcm1 -= nChans;
/* save over0/over1 for next short block, in the slots just vacated */
in = *buf1--;
*over1-- = MULSHIFT32(w0, in);
*over0++ = MULSHIFT32(w1, in);
} while (over0 < over1);
}
/* pcm[960-1023] = Wc[128-191] * block3[128-191] + Wc[0-63] * block4[0-63] + overlap[960-1023]
* over[0-63] = Wc[192-255] * block3[192-255] + Wc[64-127] * block4[64-127]
*/
pcm0 += 64 * nChans;
over0 -= 832; /* points at overlap[64] */
over1 = over0 + 128 - 1; /* points at overlap[191] */
buf0 += 64;
buf1 = buf0 - 1;
wndCurr -= 128;
do {
w0 = *wndCurr++; /* W[0], W[1], ...W[63] */
w1 = *wndCurr++; /* W[127], W[126], ... W[64] */
in = *buf0++;
f0 = MULSHIFT32(w0, in);
f1 = MULSHIFT32(w1, in);
in = *(over0 + 768); /* from last short block */
in += *(over0 + 896); /* from last full frame */
*pcm0 = CLIPTOSHORT( (in - f0 + RND_VAL) >> FBITS_OUT_IMDCT );
pcm0 += nChans;
in = *(over1 + 768); /* from last short block */
*(over1 - 128) = in + f1;
in = *buf1--;
*over1-- = MULSHIFT32(w0, in); /* save in overlap[128-191] */
*over0++ = MULSHIFT32(w1, in); /* save in overlap[64-127] */
} while (over0 < over1);
/* over0 now points at overlap[128] */
/* over[64-191] = Wc[128-255] * block4[128-255] + Wc[0-127] * block5[0-127]
* over[192-319] = Wc[128-255] * block5[128-255] + Wc[0-127] * block6[0-127]
* over[320-447] = Wc[128-255] * block6[128-255] + Wc[0-127] * block7[0-127]
* over[448-576] = Wc[128-255] * block7[128-255]
*/
for (i = 0; i < 3; i++) {
over0 += 64;
over1 = over0 + 128 - 1;
buf0 += 64;
buf1 = buf0 - 1;
wndCurr -= 128;
do {
w0 = *wndCurr++; /* W[0], W[1], ...W[63] */
w1 = *wndCurr++; /* W[127], W[126], ... W[64] */
in = *buf0++;
f0 = MULSHIFT32(w0, in);
f1 = MULSHIFT32(w1, in);
/* from last short block */
*(over0 - 128) -= f0;
*(over1 - 128)+= f1;
in = *buf1--;
*over1-- = MULSHIFT32(w0, in);
*over0++ = MULSHIFT32(w1, in);
} while (over0 < over1);
}
/* over[576-1024] = 0 */
i = 448;
over0 += 64;
do {
*over0++ = 0;
*over0++ = 0;
*over0++ = 0;
*over0++ = 0;
i -= 4;
} while (i);
}
#endif /* !AAC_ENABLE_SBR */
/**************************************************************************************
* Function: IMDCT
*
* Description: inverse transform and convert to 16-bit PCM
*
* Inputs: valid AACDecInfo struct
* index of current channel (0 for SCE/LFE, 0 or 1 for CPE)
* output channel (range = [0, nChans-1])
*
* Outputs: complete frame of decoded PCM, after inverse transform
*
* Return: 0 if successful, -1 if error
*
* Notes: If AAC_ENABLE_SBR is defined at compile time then window + overlap
* does NOT clip to 16-bit PCM and does NOT interleave channels
* If AAC_ENABLE_SBR is NOT defined at compile time, then window + overlap
* does clip to 16-bit PCM and interleaves channels
* If SBR is enabled at compile time, but we don't know whether it is
* actually used for this frame (e.g. the first frame of a stream),
* we need to produce both clipped 16-bit PCM in outbuf AND
* unclipped 32-bit PCM in the SBR input buffer. In this case we make
* a separate pass over the 32-bit PCM to produce 16-bit PCM output.
* This inflicts a slight performance hit when decoding non-SBR files.
**************************************************************************************/
int IMDCT(AACDecInfo *aacDecInfo, int ch, int chOut, short *outbuf)
{
int i;
PSInfoBase *psi;
ICSInfo *icsInfo;
/* validate pointers */
if (!aacDecInfo || !aacDecInfo->psInfoBase)
return -1;
psi = (PSInfoBase *)(aacDecInfo->psInfoBase);
icsInfo = (ch == 1 && psi->commonWin == 1) ? &(psi->icsInfo[0]) : &(psi->icsInfo[ch]);
outbuf += chOut;
/* optimized type-IV DCT (operates inplace) */
if (icsInfo->winSequence == 2) {
/* 8 short blocks */
for (i = 0; i < 8; i++)
DCT4(0, psi->coef[ch] + i*128, psi->gbCurrent[ch]);
} else {
/* 1 long block */
DCT4(1, psi->coef[ch], psi->gbCurrent[ch]);
}
#ifdef AAC_ENABLE_SBR
/* window, overlap-add, don't clip to short (send to SBR decoder)
* store the decoded 32-bit samples in top half (second AAC_MAX_NSAMPS samples) of coef buffer
*/
if (icsInfo->winSequence == 0)
DecWindowOverlapNoClip(psi->coef[ch], psi->overlap[chOut], psi->sbrWorkBuf[ch], icsInfo->winShape, psi->prevWinShape[chOut]);
else if (icsInfo->winSequence == 1)
DecWindowOverlapLongStartNoClip(psi->coef[ch], psi->overlap[chOut], psi->sbrWorkBuf[ch], icsInfo->winShape, psi->prevWinShape[chOut]);
else if (icsInfo->winSequence == 2)
DecWindowOverlapShortNoClip(psi->coef[ch], psi->overlap[chOut], psi->sbrWorkBuf[ch], icsInfo->winShape, psi->prevWinShape[chOut]);
else if (icsInfo->winSequence == 3)
DecWindowOverlapLongStopNoClip(psi->coef[ch], psi->overlap[chOut], psi->sbrWorkBuf[ch], icsInfo->winShape, psi->prevWinShape[chOut]);
if (!aacDecInfo->sbrEnabled) {
for (i = 0; i < AAC_MAX_NSAMPS; i++) {
*outbuf = CLIPTOSHORT((psi->sbrWorkBuf[ch][i] + RND_VAL) >> FBITS_OUT_IMDCT);
outbuf += aacDecInfo->nChans;
}
}
aacDecInfo->rawSampleBuf[ch] = psi->sbrWorkBuf[ch];
aacDecInfo->rawSampleBytes = sizeof(int);
aacDecInfo->rawSampleFBits = FBITS_OUT_IMDCT;
#else
/* window, overlap-add, round to PCM - optimized for each window sequence */
if (icsInfo->winSequence == 0)
DecWindowOverlap(psi->coef[ch], psi->overlap[chOut], outbuf, aacDecInfo->nChans, icsInfo->winShape, psi->prevWinShape[chOut]);
else if (icsInfo->winSequence == 1)
DecWindowOverlapLongStart(psi->coef[ch], psi->overlap[chOut], outbuf, aacDecInfo->nChans, icsInfo->winShape, psi->prevWinShape[chOut]);
else if (icsInfo->winSequence == 2)
DecWindowOverlapShort(psi->coef[ch], psi->overlap[chOut], outbuf, aacDecInfo->nChans, icsInfo->winShape, psi->prevWinShape[chOut]);
else if (icsInfo->winSequence == 3)
DecWindowOverlapLongStop(psi->coef[ch], psi->overlap[chOut], outbuf, aacDecInfo->nChans, icsInfo->winShape, psi->prevWinShape[chOut]);
aacDecInfo->rawSampleBuf[ch] = 0;
aacDecInfo->rawSampleBytes = 0;
aacDecInfo->rawSampleFBits = 0;
#endif
psi->prevWinShape[chOut] = icsInfo->winShape;
return 0;
}

View File

@@ -0,0 +1,484 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: noiseless.c,v 1.1 2005/02/26 01:47:35 jrecker Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* noiseless.c - decode channel info, scalefactors, quantized coefficients,
* scalefactor band codebook, and TNS coefficients from bitstream
**************************************************************************************/
#include "coder.h"
//#include "profile.h"
//#define PROFILE_START(x)
//#define PROFILE_END()
/**************************************************************************************
* Function: DecodeICSInfo
*
* Description: decode individual channel stream info
*
* Inputs: BitStreamInfo struct pointing to start of ICS info
* (14496-3, table 4.4.6)
* sample rate index
*
* Outputs: updated icsInfo struct
*
* Return: none
**************************************************************************************/
/* __attribute__ ((section (".data"))) */ void DecodeICSInfo(BitStreamInfo *bsi, ICSInfo *icsInfo, int sampRateIdx)
{
int sfb, g, mask;
icsInfo->icsResBit = GetBits(bsi, 1);
icsInfo->winSequence = GetBits(bsi, 2);
icsInfo->winShape = GetBits(bsi, 1);
if (icsInfo->winSequence == 2) {
/* short block */
icsInfo->maxSFB = GetBits(bsi, 4);
icsInfo->sfGroup = GetBits(bsi, 7);
icsInfo->numWinGroup = 1;
icsInfo->winGroupLen[0] = 1;
mask = 0x40; /* start with bit 6 */
for (g = 0; g < 7; g++) {
if (icsInfo->sfGroup & mask) {
icsInfo->winGroupLen[icsInfo->numWinGroup - 1]++;
} else {
icsInfo->numWinGroup++;
icsInfo->winGroupLen[icsInfo->numWinGroup - 1] = 1;
}
mask >>= 1;
}
} else {
/* long block */
icsInfo->maxSFB = GetBits(bsi, 6);
icsInfo->predictorDataPresent = GetBits(bsi, 1);
if (icsInfo->predictorDataPresent) {
icsInfo->predictorReset = GetBits(bsi, 1);
if (icsInfo->predictorReset)
icsInfo->predictorResetGroupNum = GetBits(bsi, 5);
for (sfb = 0; sfb < MIN(icsInfo->maxSFB, predSFBMax[sampRateIdx]); sfb++)
icsInfo->predictionUsed[sfb] = GetBits(bsi, 1);
}
icsInfo->numWinGroup = 1;
icsInfo->winGroupLen[0] = 1;
}
}
/**************************************************************************************
* Function: DecodeSectionData
*
* Description: decode section data (scale factor band groupings and
* associated Huffman codebooks)
*
* Inputs: BitStreamInfo struct pointing to start of ICS info
* (14496-3, table 4.4.25)
* window sequence (short or long blocks)
* number of window groups (1 for long blocks, 1-8 for short blocks)
* max coded scalefactor band
*
* Outputs: index of Huffman codebook for each scalefactor band in each section
*
* Return: none
*
* Notes: sectCB, sectEnd, sfbCodeBook, ordered by window groups for short blocks
**************************************************************************************/
/* __attribute__ ((section (".data"))) */ static void DecodeSectionData(BitStreamInfo *bsi, int winSequence, int numWinGrp, int maxSFB, unsigned char *sfbCodeBook)
{
int g, cb, sfb;
int sectLen, sectLenBits, sectLenIncr, sectEscapeVal;
sectLenBits = (winSequence == 2 ? 3 : 5);
sectEscapeVal = (1 << sectLenBits) - 1;
for (g = 0; g < numWinGrp; g++) {
sfb = 0;
while (sfb < maxSFB) {
cb = GetBits(bsi, 4); /* next section codebook */
sectLen = 0;
do {
sectLenIncr = GetBits(bsi, sectLenBits);
sectLen += sectLenIncr;
} while (sectLenIncr == sectEscapeVal);
sfb += sectLen;
while (sectLen--)
*sfbCodeBook++ = (unsigned char)cb;
}
ASSERT(sfb == maxSFB);
}
}
/**************************************************************************************
* Function: DecodeOneScaleFactor
*
* Description: decode one scalefactor using scalefactor Huffman codebook
*
* Inputs: BitStreamInfo struct pointing to start of next coded scalefactor
*
* Outputs: updated BitstreamInfo struct
*
* Return: one decoded scalefactor, including index_offset of -60
**************************************************************************************/
static int DecodeOneScaleFactor(BitStreamInfo *bsi)
{
int nBits, val;
unsigned int bitBuf;
/* decode next scalefactor from bitstream */
bitBuf = GetBitsNoAdvance(bsi, huffTabScaleFactInfo.maxBits) << (32 - huffTabScaleFactInfo.maxBits);
//PROFILE_START("DecodeHuffmanScalar");
nBits = DecodeHuffmanScalar(huffTabScaleFact, &huffTabScaleFactInfo, bitBuf, &val);
AdvanceBitstream(bsi, nBits);
//PROFILE_END();
return val;
}
/**************************************************************************************
* Function: DecodeScaleFactors
*
* Description: decode scalefactors, PNS energy, and intensity stereo weights
*
* Inputs: BitStreamInfo struct pointing to start of ICS info
* (14496-3, table 4.4.26)
* number of window groups (1 for long blocks, 1-8 for short blocks)
* max coded scalefactor band
* global gain (starting value for differential scalefactor coding)
* index of Huffman codebook for each scalefactor band in each section
*
* Outputs: decoded scalefactor for each section
*
* Return: none
*
* Notes: sfbCodeBook, scaleFactors ordered by window groups for short blocks
* for section with codebook 13, scaleFactors buffer has decoded PNS
* energy instead of regular scalefactor
* for section with codebook 14 or 15, scaleFactors buffer has intensity
* stereo weight instead of regular scalefactor
**************************************************************************************/
/* __attribute__ ((section (".data"))) */ static void DecodeScaleFactors(BitStreamInfo *bsi, int numWinGrp, int maxSFB, int globalGain,
unsigned char *sfbCodeBook, short *scaleFactors)
{
int g, sfbCB, nrg, npf, val, sf, is;
/* starting values for differential coding */
sf = globalGain;
is = 0;
nrg = globalGain - 90 - 256;
npf = 1;
for (g = 0; g < numWinGrp * maxSFB; g++) {
sfbCB = *sfbCodeBook++;
if (sfbCB == 14 || sfbCB == 15) {
/* intensity stereo - differential coding */
val = DecodeOneScaleFactor(bsi);
is += val;
*scaleFactors++ = (short)is;
} else if (sfbCB == 13) {
/* PNS - first energy is directly coded, rest are Huffman coded (npf = noise_pcm_flag) */
if (npf) {
val = GetBits(bsi, 9);
npf = 0;
} else {
val = DecodeOneScaleFactor(bsi);
}
nrg += val;
*scaleFactors++ = (short)nrg;
} else if (sfbCB >= 1 && sfbCB <= 11) {
/* regular (non-zero) region - differential coding */
val = DecodeOneScaleFactor(bsi);
sf += val;
*scaleFactors++ = (short)sf;
} else {
/* inactive scalefactor band if codebook 0 */
*scaleFactors++ = 0;
}
}
}
/**************************************************************************************
* Function: DecodePulseInfo
*
* Description: decode pulse information
*
* Inputs: BitStreamInfo struct pointing to start of pulse info
* (14496-3, table 4.4.7)
*
* Outputs: updated PulseInfo struct
*
* Return: none
**************************************************************************************/
/* __attribute__ ((section (".data"))) */ static void DecodePulseInfo(BitStreamInfo *bsi, PulseInfo *pi)
{
int i;
pi->numPulse = GetBits(bsi, 2) + 1; /* add 1 here */
pi->startSFB = GetBits(bsi, 6);
for (i = 0; i < pi->numPulse; i++) {
pi->offset[i] = GetBits(bsi, 5);
pi->amp[i] = GetBits(bsi, 4);
}
}
/**************************************************************************************
* Function: DecodeTNSInfo
*
* Description: decode TNS filter information
*
* Inputs: BitStreamInfo struct pointing to start of TNS info
* (14496-3, table 4.4.27)
* window sequence (short or long blocks)
*
* Outputs: updated TNSInfo struct
* buffer of decoded (signed) TNS filter coefficients
*
* Return: none
**************************************************************************************/
static const signed char sgnMask[3] = {0x02, 0x04, 0x08};
static const signed char negMask[3] = {~0x03, ~0x07, ~0x0f};
static void DecodeTNSInfo(BitStreamInfo *bsi, int winSequence, TNSInfo *ti, signed char *tnsCoef)
{
int i, w, f, coefBits, compress;
signed char c, s, n;
unsigned char *filtLength, *filtOrder, *filtDir;
filtLength = ti->length;
filtOrder = ti->order;
filtDir = ti->dir;
if (winSequence == 2) {
/* short blocks */
for (w = 0; w < NWINDOWS_SHORT; w++) {
ti->numFilt[w] = GetBits(bsi, 1);
if (ti->numFilt[w]) {
ti->coefRes[w] = GetBits(bsi, 1) + 3;
*filtLength = GetBits(bsi, 4);
*filtOrder = GetBits(bsi, 3);
if (*filtOrder) {
*filtDir++ = GetBits(bsi, 1);
compress = GetBits(bsi, 1);
coefBits = (int)ti->coefRes[w] - compress; /* 2, 3, or 4 */
s = sgnMask[coefBits - 2];
n = negMask[coefBits - 2];
for (i = 0; i < *filtOrder; i++) {
c = GetBits(bsi, coefBits);
if (c & s) c |= n;
*tnsCoef++ = c;
}
}
filtLength++;
filtOrder++;
}
}
} else {
/* long blocks */
ti->numFilt[0] = GetBits(bsi, 2);
if (ti->numFilt[0])
ti->coefRes[0] = GetBits(bsi, 1) + 3;
for (f = 0; f < ti->numFilt[0]; f++) {
*filtLength = GetBits(bsi, 6);
*filtOrder = GetBits(bsi, 5);
if (*filtOrder) {
*filtDir++ = GetBits(bsi, 1);
compress = GetBits(bsi, 1);
coefBits = (int)ti->coefRes[0] - compress; /* 2, 3, or 4 */
s = sgnMask[coefBits - 2];
n = negMask[coefBits - 2];
for (i = 0; i < *filtOrder; i++) {
c = GetBits(bsi, coefBits);
if (c & s) c |= n;
*tnsCoef++ = c;
}
}
filtLength++;
filtOrder++;
}
}
}
/* bitstream field lengths for gain control data:
* gainBits[winSequence][0] = maxWindow (how many gain windows there are)
* gainBits[winSequence][1] = locBitsZero (bits for alocCode if window == 0)
* gainBits[winSequence][2] = locBits (bits for alocCode if window != 0)
*/
static const unsigned char gainBits[4][3] = {
{1, 5, 5}, /* long */
{2, 4, 2}, /* start */
{8, 2, 2}, /* short */
{2, 4, 5}, /* stop */
};
/**************************************************************************************
* Function: DecodeGainControlInfo
*
* Description: decode gain control information (SSR profile only)
*
* Inputs: BitStreamInfo struct pointing to start of gain control info
* (14496-3, table 4.4.12)
* window sequence (short or long blocks)
*
* Outputs: updated GainControlInfo struct
*
* Return: none
**************************************************************************************/
static void DecodeGainControlInfo(BitStreamInfo *bsi, int winSequence, GainControlInfo *gi)
{
int bd, wd, ad;
int locBits, locBitsZero, maxWin;
gi->maxBand = GetBits(bsi, 2);
maxWin = (int)gainBits[winSequence][0];
locBitsZero = (int)gainBits[winSequence][1];
locBits = (int)gainBits[winSequence][2];
for (bd = 1; bd <= gi->maxBand; bd++) {
for (wd = 0; wd < maxWin; wd++) {
gi->adjNum[bd][wd] = GetBits(bsi, 3);
for (ad = 0; ad < gi->adjNum[bd][wd]; ad++) {
gi->alevCode[bd][wd][ad] = GetBits(bsi, 4);
gi->alocCode[bd][wd][ad] = GetBits(bsi, (wd == 0 ? locBitsZero : locBits));
}
}
}
}
/**************************************************************************************
* Function: DecodeICS
*
* Description: decode individual channel stream
*
* Inputs: platform specific info struct
* BitStreamInfo struct pointing to start of individual channel stream
* (14496-3, table 4.4.24)
* index of current channel
*
* Outputs: updated section data, scale factor data, pulse data, TNS data,
* and gain control data
*
* Return: none
**************************************************************************************/
static void DecodeICS(PSInfoBase *psi, BitStreamInfo *bsi, int ch)
{
int globalGain;
ICSInfo *icsInfo;
PulseInfo *pi;
TNSInfo *ti;
GainControlInfo *gi;
icsInfo = (ch == 1 && psi->commonWin == 1) ? &(psi->icsInfo[0]) : &(psi->icsInfo[ch]);
globalGain = GetBits(bsi, 8);
if (!psi->commonWin)
DecodeICSInfo(bsi, icsInfo, psi->sampRateIdx);
DecodeSectionData(bsi, icsInfo->winSequence, icsInfo->numWinGroup, icsInfo->maxSFB, psi->sfbCodeBook[ch]);
DecodeScaleFactors(bsi, icsInfo->numWinGroup, icsInfo->maxSFB, globalGain, psi->sfbCodeBook[ch], psi->scaleFactors[ch]);
pi = &psi->pulseInfo[ch];
pi->pulseDataPresent = GetBits(bsi, 1);
if (pi->pulseDataPresent)
DecodePulseInfo(bsi, pi);
ti = &psi->tnsInfo[ch];
ti->tnsDataPresent = GetBits(bsi, 1);
if (ti->tnsDataPresent)
DecodeTNSInfo(bsi, icsInfo->winSequence, ti, ti->coef);
gi = &psi->gainControlInfo[ch];
gi->gainControlDataPresent = GetBits(bsi, 1);
if (gi->gainControlDataPresent)
DecodeGainControlInfo(bsi, icsInfo->winSequence, gi);
}
/**************************************************************************************
* Function: DecodeNoiselessData
*
* Description: decode noiseless data (side info and transform coefficients)
*
* Inputs: valid AACDecInfo struct
* double pointer to buffer pointing to start of individual channel stream
* (14496-3, table 4.4.24)
* pointer to bit offset
* pointer to number of valid bits remaining in buf
* index of current channel
*
* Outputs: updated global gain, section data, scale factor data, pulse data,
* TNS data, gain control data, and spectral data
*
* Return: 0 if successful, error code (< 0) if error
**************************************************************************************/
int DecodeNoiselessData(AACDecInfo *aacDecInfo, unsigned char **buf, int *bitOffset, int *bitsAvail, int ch)
{
int bitsUsed;
BitStreamInfo bsi;
PSInfoBase *psi;
ICSInfo *icsInfo;
/* validate pointers */
if (!aacDecInfo || !aacDecInfo->psInfoBase)
return ERR_AAC_NULL_POINTER;
psi = (PSInfoBase *)(aacDecInfo->psInfoBase);
icsInfo = (ch == 1 && psi->commonWin == 1) ? &(psi->icsInfo[0]) : &(psi->icsInfo[ch]);
SetBitstreamPointer(&bsi, (*bitsAvail+7) >> 3, *buf);
GetBits(&bsi, *bitOffset);
DecodeICS(psi, &bsi, ch);
if (icsInfo->winSequence == 2)
DecodeSpectrumShort(psi, &bsi, ch);
else
DecodeSpectrumLong(psi, &bsi, ch);
bitsUsed = CalcBitsUsed(&bsi, *buf, *bitOffset);
*buf += ((bitsUsed + *bitOffset) >> 3);
*bitOffset = ((bitsUsed + *bitOffset) & 0x07);
*bitsAvail -= bitsUsed;
aacDecInfo->sbDeinterleaveReqd[ch] = 0;
aacDecInfo->tnsUsed |= psi->tnsInfo[ch].tnsDataPresent; /* set flag if TNS used for any channel */
return ERR_AAC_NONE;
}

View File

@@ -0,0 +1,357 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: pns.c,v 1.2 2005/03/10 17:01:56 jrecker Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* pns.c - perceptual noise substitution
**************************************************************************************/
#include "coder.h"
#include "assembly.h"
/**************************************************************************************
* Function: Get32BitVal
*
* Description: generate 32-bit unsigned random number
*
* Inputs: last number calculated (seed, first time through)
*
* Outputs: new number, saved in *last
*
* Return: 32-bit number, uniformly distributed between [0, 2^32)
*
* Notes: uses simple linear congruential generator
**************************************************************************************/
static unsigned int Get32BitVal(unsigned int *last)
{
unsigned int r = *last;
/* use same coefs as MPEG reference code (classic LCG)
* use unsigned multiply to force reliable wraparound behavior in C (mod 2^32)
*/
r = (1664525U * r) + 1013904223U;
*last = r;
return r;
}
#define NUM_ITER_INVSQRT 4
#define X0_COEF_2 0xc0000000 /* Q29: -2.0 */
#define X0_OFF_2 0x60000000 /* Q29: 3.0 */
#define Q26_3 0x0c000000 /* Q26: 3.0 */
/**************************************************************************************
* Function: InvRootR
*
* Description: use Newton's method to solve for x = 1/sqrt(r)
*
* Inputs: r in Q30 format, range = [0.25, 1] (normalize inputs to this range)
*
* Outputs: none
*
* Return: x = Q29, range = (1, 2)
*
* Notes: guaranteed to converge and not overflow for any r in this range
*
* xn+1 = xn - f(xn)/f'(xn)
* f(x) = 1/sqrt(r) - x = 0 (find root)
* = 1/x^2 - r
* f'(x) = -2/x^3
*
* so xn+1 = xn/2 * (3 - r*xn^2)
*
* NUM_ITER_INVSQRT = 3, maxDiff = 1.3747e-02
* NUM_ITER_INVSQRT = 4, maxDiff = 3.9832e-04
**************************************************************************************/
static int InvRootR(int r)
{
int i, xn, t;
/* use linear equation for initial guess
* x0 = -2*r + 3 (so x0 always >= correct answer in range [0.25, 1))
* xn = Q29 (at every step)
*/
xn = (MULSHIFT32(r, X0_COEF_2) << 2) + X0_OFF_2;
for (i = 0; i < NUM_ITER_INVSQRT; i++) {
t = MULSHIFT32(xn, xn); /* Q26 = Q29*Q29 */
t = Q26_3 - (MULSHIFT32(r, t) << 2); /* Q26 = Q26 - (Q31*Q26 << 1) */
xn = MULSHIFT32(xn, t) << (6 - 1); /* Q29 = (Q29*Q26 << 6), and -1 for division by 2 */
}
/* clip to range (1.0, 2.0)
* (because of rounding, this can converge to xn slightly > 2.0 when r is near 0.25)
*/
if (xn >> 30)
xn = (1 << 30) - 1;
return xn;
}
/**************************************************************************************
* Function: ScaleNoiseVector
*
* Description: apply scaling to vector of noise coefficients for one scalefactor band
*
* Inputs: unscaled coefficients
* number of coefficients in vector (one scalefactor band of coefs)
* scalefactor for this band (i.e. noise energy)
*
* Outputs: nVals coefficients in Q(FBITS_OUT_DQ_OFF)
*
* Return: guard bit mask (OR of abs value of all noise coefs)
**************************************************************************************/
static int ScaleNoiseVector(int *coef, int nVals, int sf)
{
/* pow(2, i/4.0) for i = [0,1,2,3], format = Q30 */
static const int pow14[4] PROGMEM = {
0x40000000, 0x4c1bf829, 0x5a82799a, 0x6ba27e65
};
int i, c, spec, energy, sq, scalef, scalei, invSqrtEnergy, z, gbMask;
energy = 0;
for (i = 0; i < nVals; i++) {
spec = coef[i];
/* max nVals = max SFB width = 96, so energy can gain < 2^7 bits in accumulation */
sq = (spec * spec) >> 8; /* spec*spec range = (-2^30, 2^30) */
energy += sq;
}
/* unless nVals == 1 (or the number generator is broken...), this should not happen */
if (energy == 0)
return 0; /* coef[i] must = 0 for i = [0, nVals-1], so gbMask = 0 */
/* pow(2, sf/4) * pow(2, FBITS_OUT_DQ_OFF) */
scalef = pow14[sf & 0x3];
scalei = (sf >> 2) + FBITS_OUT_DQ_OFF;
/* energy has implied factor of 2^-8 since we shifted the accumulator
* normalize energy to range [0.25, 1.0), calculate 1/sqrt(1), and denormalize
* i.e. divide input by 2^(30-z) and convert to Q30
* output of 1/sqrt(i) now has extra factor of 2^((30-z)/2)
* for energy > 0, z is an even number between 0 and 28
* final scaling of invSqrtEnergy:
* 2^(15 - z/2) to compensate for implicit 2^(30-z) factor in input
* +4 to compensate for implicit 2^-8 factor in input
*/
z = CLZ(energy) - 2; /* energy has at least 2 leading zeros (see acc loop) */
z &= 0xfffffffe; /* force even */
invSqrtEnergy = InvRootR(energy << z); /* energy << z must be in range [0x10000000, 0x40000000] */
scalei -= (15 - z/2 + 4); /* nInt = 1/sqrt(energy) in Q29 */
/* normalize for final scaling */
z = CLZ(invSqrtEnergy) - 1;
invSqrtEnergy <<= z;
scalei -= (z - 3 - 2); /* -2 for scalef, z-3 for invSqrtEnergy */
scalef = MULSHIFT32(scalef, invSqrtEnergy); /* scalef (input) = Q30, invSqrtEnergy = Q29 * 2^z */
gbMask = 0;
if (scalei < 0) {
scalei = -scalei;
if (scalei > 31)
scalei = 31;
for (i = 0; i < nVals; i++) {
c = MULSHIFT32(coef[i], scalef) >> scalei;
gbMask |= FASTABS(c);
coef[i] = c;
}
} else {
/* for scalei <= 16, no clipping possible (coef[i] is < 2^15 before scaling)
* for scalei > 16, just saturate exponent (rare)
* scalef is close to full-scale (since we normalized invSqrtEnergy)
* remember, we are just producing noise here
*/
if (scalei > 16)
scalei = 16;
for (i = 0; i < nVals; i++) {
c = MULSHIFT32(coef[i] << scalei, scalef);
coef[i] = c;
gbMask |= FASTABS(c);
}
}
return gbMask;
}
/**************************************************************************************
* Function: GenerateNoiseVector
*
* Description: create vector of noise coefficients for one scalefactor band
*
* Inputs: seed for number generator
* number of coefficients to generate
*
* Outputs: buffer of nVals coefficients, range = [-2^15, 2^15)
* updated seed for number generator
*
* Return: none
**************************************************************************************/
static void GenerateNoiseVector(int *coef, int *last, int nVals)
{
int i;
for (i = 0; i < nVals; i++)
coef[i] = ((signed int)Get32BitVal((unsigned int *)last)) >> 16;
}
/**************************************************************************************
* Function: CopyNoiseVector
*
* Description: copy vector of noise coefficients for one scalefactor band from L to R
*
* Inputs: buffer of left coefficients
* number of coefficients to copy
*
* Outputs: buffer of right coefficients
*
* Return: none
**************************************************************************************/
static void CopyNoiseVector(int *coefL, int *coefR, int nVals)
{
int i;
for (i = 0; i < nVals; i++)
coefR[i] = coefL[i];
}
/**************************************************************************************
* Function: PNS
*
* Description: apply perceptual noise substitution, if enabled (MPEG-4 only)
*
* Inputs: valid AACDecInfo struct
* index of current channel
*
* Outputs: shaped noise in scalefactor bands where PNS is active
* updated minimum guard bit count for this channel
*
* Return: 0 if successful, -1 if error
**************************************************************************************/
int PNS(AACDecInfo *aacDecInfo, int ch)
{
int gp, sfb, win, width, nSamps, gb, gbMask;
int *coef;
const /*short*/ int *sfbTab;
unsigned char *sfbCodeBook;
short *scaleFactors;
int msMaskOffset, checkCorr, genNew;
unsigned char msMask;
unsigned char *msMaskPtr;
PSInfoBase *psi;
ICSInfo *icsInfo;
/* validate pointers */
if (!aacDecInfo || !aacDecInfo->psInfoBase)
return -1;
psi = (PSInfoBase *)(aacDecInfo->psInfoBase);
icsInfo = (ch == 1 && psi->commonWin == 1) ? &(psi->icsInfo[0]) : &(psi->icsInfo[ch]);
if (!psi->pnsUsed[ch])
return 0;
if (icsInfo->winSequence == 2) {
sfbTab = sfBandTabShort + sfBandTabShortOffset[psi->sampRateIdx];
nSamps = NSAMPS_SHORT;
} else {
sfbTab = sfBandTabLong + sfBandTabLongOffset[psi->sampRateIdx];
nSamps = NSAMPS_LONG;
}
coef = psi->coef[ch];
sfbCodeBook = psi->sfbCodeBook[ch];
scaleFactors = psi->scaleFactors[ch];
checkCorr = (aacDecInfo->currBlockID == AAC_ID_CPE && psi->commonWin == 1 ? 1 : 0);
gbMask = 0;
for (gp = 0; gp < icsInfo->numWinGroup; gp++) {
for (win = 0; win < icsInfo->winGroupLen[gp]; win++) {
msMaskPtr = psi->msMaskBits + ((gp*icsInfo->maxSFB) >> 3);
msMaskOffset = ((gp*icsInfo->maxSFB) & 0x07);
msMask = (*msMaskPtr++) >> msMaskOffset;
for (sfb = 0; sfb < icsInfo->maxSFB; sfb++) {
width = sfbTab[sfb+1] - sfbTab[sfb];
if (sfbCodeBook[sfb] == 13) {
if (ch == 0) {
/* generate new vector, copy into ch 1 if it's possible that the channels will be correlated
* if ch 1 has PNS enabled for this SFB but it's uncorrelated (i.e. ms_used == 0),
* the copied values will be overwritten when we process ch 1
*/
GenerateNoiseVector(coef, &psi->pnsLastVal, width);
if (checkCorr && psi->sfbCodeBook[1][gp*icsInfo->maxSFB + sfb] == 13)
CopyNoiseVector(coef, psi->coef[1] + (coef - psi->coef[0]), width);
} else {
/* generate new vector if no correlation between channels */
genNew = 1;
if (checkCorr && psi->sfbCodeBook[0][gp*icsInfo->maxSFB + sfb] == 13) {
if ( (psi->msMaskPresent == 1 && (msMask & 0x01)) || psi->msMaskPresent == 2 )
genNew = 0;
}
if (genNew)
GenerateNoiseVector(coef, &psi->pnsLastVal, width);
}
gbMask |= ScaleNoiseVector(coef, width, psi->scaleFactors[ch][gp*icsInfo->maxSFB + sfb]);
}
coef += width;
/* get next mask bit (should be branchless on ARM) */
msMask >>= 1;
if (++msMaskOffset == 8) {
msMask = *msMaskPtr++;
msMaskOffset = 0;
}
}
coef += (nSamps - sfbTab[icsInfo->maxSFB]);
}
sfbCodeBook += icsInfo->maxSFB;
scaleFactors += icsInfo->maxSFB;
}
/* update guard bit count if necessary */
gb = CLZ(gbMask) - 1;
if (psi->gbCurrent[ch] > gb)
psi->gbCurrent[ch] = gb;
return 0;
}

View File

@@ -0,0 +1,127 @@
Fixed-point HE-AAC decoder
Developed by RealNetworks, 2005
===============================
Overview
--------
This module contains a high-performance HE-AAC decoder for 32-bit fixed-point
processors. The following is a summary of what is and is not supported:
Supported:
- MPEG2, MPEG4 low complexity decoding (intensity stereo, M-S, TNS, PNS)
- spectral band replication (SBR), high-quality mode
- mono, stereo, and multichannel modes
- ADTS, ADIF, and raw data block file formats
Not currently supported:
- main or SSR profile, LTP
- coupling channel elements (CCE)
- 960/1920-sample frame size
- low-power mode SBR
- downsampled (single-rate) SBR
- parametric stereo
Highlights
----------
- highly optimized for ARM processors (details in docs/ subdirectory)
- reference x86 implementation
- C and assembly code only (C++ not required for codec library)
- reentrant, statically linkable
- low memory (details in docs/ subdirectory)
- option to use Intel Integrated Performance Primitives (details below)
Supported platforms and toolchains
----------------------------------
This codec should run on any 32-bit fixed-point processor which can perform a full 32x32-bit
multiply (providing a 64-bit result). The following processors and toolchains are supported:
- x86, Microsoft Visual C++
- x86, GNU toolchain (gcc)
- ARM, ARM Developer Suite (ADS)
- ARM, Microsoft Embedded Visual C++
- ARM, GNU toolchain (gcc)
ARM refers to any processor supporting ARM architecture v.4 or above. Thumb is not required.
Generally ADS produces the fastest code. EVC 3 does not support inline assembly code for
ARM targets, so calls to MULSHIFT32 (smull on ARM) are left as function calls. This incurs
a significant performance penalty. For the fastest code on targets which do not normally use
ADS consider compiling with ADS, using the -S option to output assembly code, and
feeding this assembly code to the assembler of your choice. This might require some
syntax changes in the .S file.
Adding support for a new processor is fairly simple. Simply add a new block to the file
real/assembly.h which implements the required inline assembly functions for your processor.
Something like
...
#elif defined NEW_PROCESSOR
/* you implement MULSHIFT32() and so forth */
#else
#error Unsupported platform in assembly.h
#endif
Optionally you can rewrite or add assembly language files optimized for your platform. Note
that many of the algorithms are designed for an ARM-type processor, so performance of the
unmodified C code might be noticeably worse on other architectures.
Adding support for a new toolchain is straightforward. Use the sample projects or the
Helix makefiles as a template for which source files to include.
Multichannel
------------
For multichannel, just set AAC_MAX_NCHANS in pub/aacdec.h to the desired max number
of channels (default = 2) and recompile. This increases RAM usage since more memory
is required to save state for multiple channels. See docs/memory.xls for details.
Directory structure
-------------------
fixpt/ platform-independent code and tables, public API
fixpt/docs memory and CPU usage figures, callgraphs
fixpt/hxwrap Helix wrapper code and makefiles
fixpt/ipp source code which uses IPP for decoding (see the "IPP" section below)
fixpt/pub public header files
fixpt/real source code for RealNetworks' AAC decoder
fixpt/testwrap sample code to build a command-line test application
Code organization
-----------------
fixpt/
aacdec.c main decode functions, exports C-only API
aactabs.c common tables used by all implementations
fixpt/pub/
aaccommon.h low-level codec API which aacdec.c calls
aacdec.h high-level codec API which applications call
statname.h symbols which get name-mangled by C preprocessor to allow static linking
fixpt/ipp source code for wrapper files which link in IPP libraries
fixpt/real full source code for RealNetworks AAC decoder, including SBR
fixpt/real/asm optimized assembly code files for certain platforms
To build an AAC decoder library, you'll need to compile the top-level files and EITHER
real/*.c OR ipp/*.c and the appropriate IPP library.
Decoder using Real code: aacdec.c + aactabs.c + real/*.c + real/asm/[platform]/*.s (if necessary)
Decoder using IPP code: aacdec.c + aactabs.c + ipp/*.c + ippac*.lib
IPP
---
For certain platforms Intel<65> has created highly-optimized object code libraries of DSP
routines. These are called the Intel<65> Integrated Performance Primitives (IPP). If IPP
libraries are available for a platform, this AAC decoder can link them in and use them
instead of the RealNetworks source code. To use IPP, you still need to build the top-level
files (aacdec.c, aactabs.c). You also build the files in ipp/*.c. These are just thin
wrappers which provide the glue logic between the top-level decode functions in
aacdec.c and the optimized DSP primitives in the IPP libraries. IPP libraries are not
included in this module. You must obtain them WITH A LICENSE directly from Intel.
Further info on the latest versions of IPP (as of the date of this readme) is available
from the URL below:
http://www.intel.com/software/products/ipp/
This site explains how to obtain IPP and the terms under which IPP libraries may be used.
The code in this module is merely wrapper code which calls IPP functions. You are fully
responsible for adhering to the license agreement under which you obtain the IPP
libraries from Intel.
readme.txt last updated 02/25/05

View File

@@ -0,0 +1,431 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: sbr.c,v 1.3 2005/05/24 16:01:55 albertofloyd Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* sbr.c - top level functions for SBR
**************************************************************************************/
#if defined(USE_DEFAULT_STDLIB) || defined(ESP_PLATFORM)
#include <stdio.h>
#include <stdlib.h>
#else
#include "hlxclib/stdlib.h"
#endif
#include "sbr.h"
/**************************************************************************************
* Function: InitSBRState
*
* Description: initialize PSInfoSBR struct at start of stream or after flush
*
* Inputs: valid AACDecInfo struct
*
* Outputs: PSInfoSBR struct with proper initial state
*
* Return: none
**************************************************************************************/
static void InitSBRState(PSInfoSBR *psi)
{
int i, ch;
unsigned char *c;
if (!psi)
return;
/* clear SBR state structure */
c = (unsigned char *)psi;
for (i = 0; i < (int)sizeof(PSInfoSBR); i++)
*c++ = 0;
/* initialize non-zero state variables */
for (ch = 0; ch < AAC_MAX_NCHANS; ch++) {
psi->sbrChan[ch].reset = 1;
psi->sbrChan[ch].laPrev = -1;
}
}
/**************************************************************************************
* Function: InitSBR
*
* Description: initialize SBR decoder
*
* Inputs: valid AACDecInfo struct
*
* Outputs: PSInfoSBR struct to hold SBR state information
*
* Return: 0 if successful, error code (< 0) if error
*
* Note: memory allocation for SBR is only done here
**************************************************************************************/
int InitSBR(AACDecInfo *aacDecInfo)
{
PSInfoSBR *psi;
if (!aacDecInfo)
return ERR_AAC_NULL_POINTER;
/* allocate SBR state structure */
psi = (PSInfoSBR *)malloc(sizeof(PSInfoSBR));
if (!psi) {
printf("OOM in SBR, can't allocate %d bytes\n", sizeof(PSInfoSBR));
return ERR_AAC_SBR_INIT;
}
InitSBRState(psi);
aacDecInfo->psInfoSBR = psi;
return ERR_AAC_NONE;
}
int InitSBRPre(AACDecInfo *aacDecInfo, void **ptr, int *sz)
{
PSInfoSBR *psi;
if (!aacDecInfo)
return ERR_AAC_NULL_POINTER;
/* allocate SBR state structure */
psi = (PSInfoSBR *)*ptr;
*sz -= sizeof(PSInfoSBR);
if (*sz < 0) {
printf("OOM in SBR, can't allocate %d bytes\n", sizeof(PSInfoSBR));
return ERR_AAC_SBR_INIT;
}
InitSBRState(psi);
*ptr = (void*)((char*)(*ptr) + sizeof(PSInfoSBR));
aacDecInfo->psInfoSBR = psi;
return ERR_AAC_NONE;
}
/**************************************************************************************
* Function: FreeSBR
*
* Description: free SBR decoder
*
* Inputs: valid AACDecInfo struct
*
* Outputs: none
*
* Return: none
*
* Note: memory deallocation for SBR is only done here
**************************************************************************************/
void FreeSBR(AACDecInfo *aacDecInfo)
{
if (aacDecInfo && aacDecInfo->psInfoSBR)
free(aacDecInfo->psInfoSBR);
return;
}
/**************************************************************************************
* Function: DecodeSBRBitstream
*
* Description: decode sideband information for SBR
*
* Inputs: valid AACDecInfo struct
* fill buffer with SBR extension block
* number of bytes in fill buffer
* base output channel (range = [0, nChans-1])
*
* Outputs: initialized state structs (SBRHdr, SBRGrid, SBRFreq, SBRChan)
*
* Return: 0 if successful, error code (< 0) if error
*
* Notes: SBR payload should be in aacDecInfo->fillBuf
* returns with no error if fill buffer is not an SBR extension block,
* or if current block is not a fill block (e.g. for LFE upsampling)
**************************************************************************************/
int DecodeSBRBitstream(AACDecInfo *aacDecInfo, int chBase)
{
int headerFlag;
BitStreamInfo bsi;
PSInfoSBR *psi;
/* validate pointers */
if (!aacDecInfo || !aacDecInfo->psInfoSBR)
return ERR_AAC_NULL_POINTER;
psi = (PSInfoSBR *)(aacDecInfo->psInfoSBR);
if (aacDecInfo->currBlockID != AAC_ID_FIL || (aacDecInfo->fillExtType != EXT_SBR_DATA && aacDecInfo->fillExtType != EXT_SBR_DATA_CRC))
return ERR_AAC_NONE;
SetBitstreamPointer(&bsi, aacDecInfo->fillCount, aacDecInfo->fillBuf);
if (GetBits(&bsi, 4) != (unsigned int)aacDecInfo->fillExtType)
return ERR_AAC_SBR_BITSTREAM;
if (aacDecInfo->fillExtType == EXT_SBR_DATA_CRC)
psi->crcCheckWord = GetBits(&bsi, 10);
headerFlag = GetBits(&bsi, 1);
if (headerFlag) {
/* get sample rate index for output sample rate (2x base rate) */
psi->sampRateIdx = GetSampRateIdx(2 * aacDecInfo->sampRate);
if (psi->sampRateIdx < 0 || psi->sampRateIdx >= NUM_SAMPLE_RATES)
return ERR_AAC_SBR_BITSTREAM;
else if (psi->sampRateIdx >= NUM_SAMPLE_RATES_SBR)
return ERR_AAC_SBR_SINGLERATE_UNSUPPORTED;
/* reset flag = 1 if header values changed */
if (UnpackSBRHeader(&bsi, &(psi->sbrHdr[chBase])))
psi->sbrChan[chBase].reset = 1;
/* first valid SBR header should always trigger CalcFreqTables(), since psi->reset was set in InitSBR() */
if (psi->sbrChan[chBase].reset)
CalcFreqTables(&(psi->sbrHdr[chBase+0]), &(psi->sbrFreq[chBase]), psi->sampRateIdx);
/* copy and reset state to right channel for CPE */
if (aacDecInfo->prevBlockID == AAC_ID_CPE)
psi->sbrChan[chBase+1].reset = psi->sbrChan[chBase+0].reset;
}
/* if no header has been received, upsample only */
if (psi->sbrHdr[chBase].count == 0)
return ERR_AAC_NONE;
if (aacDecInfo->prevBlockID == AAC_ID_SCE) {
UnpackSBRSingleChannel(&bsi, psi, chBase);
} else if (aacDecInfo->prevBlockID == AAC_ID_CPE) {
UnpackSBRChannelPair(&bsi, psi, chBase);
} else {
return ERR_AAC_SBR_BITSTREAM;
}
ByteAlignBitstream(&bsi);
return ERR_AAC_NONE;
}
/**************************************************************************************
* Function: DecodeSBRData
*
* Description: apply SBR to one frame of PCM data
*
* Inputs: 1024 samples of decoded 32-bit PCM, before SBR
* size of input PCM samples (must be 4 bytes)
* number of fraction bits in input PCM samples
* base output channel (range = [0, nChans-1])
* initialized state structs (SBRHdr, SBRGrid, SBRFreq, SBRChan)
*
* Outputs: 2048 samples of decoded 16-bit PCM, after SBR
*
* Return: 0 if successful, error code (< 0) if error
**************************************************************************************/
int DecodeSBRData(AACDecInfo *aacDecInfo, int chBase, short *outbuf)
{
int k, l, ch, chBlock, qmfaBands, qmfsBands;
int upsampleOnly, gbIdx, gbMask;
int *inbuf;
short *outptr;
PSInfoSBR *psi;
SBRHeader *sbrHdr;
SBRGrid *sbrGrid;
SBRFreq *sbrFreq;
SBRChan *sbrChan;
/* validate pointers */
if (!aacDecInfo || !aacDecInfo->psInfoSBR)
return ERR_AAC_NULL_POINTER;
psi = (PSInfoSBR *)(aacDecInfo->psInfoSBR);
/* same header and freq tables for both channels in CPE */
sbrHdr = &(psi->sbrHdr[chBase]);
sbrFreq = &(psi->sbrFreq[chBase]);
/* upsample only if we haven't received an SBR header yet or if we have an LFE block */
if (aacDecInfo->currBlockID == AAC_ID_LFE) {
chBlock = 1;
upsampleOnly = 1;
} else if (aacDecInfo->currBlockID == AAC_ID_FIL) {
if (aacDecInfo->prevBlockID == AAC_ID_SCE)
chBlock = 1;
else if (aacDecInfo->prevBlockID == AAC_ID_CPE)
chBlock = 2;
else
return ERR_AAC_NONE;
upsampleOnly = (sbrHdr->count == 0 ? 1 : 0);
if (aacDecInfo->fillExtType != EXT_SBR_DATA && aacDecInfo->fillExtType != EXT_SBR_DATA_CRC)
return ERR_AAC_NONE;
} else {
/* ignore non-SBR blocks */
return ERR_AAC_NONE;
}
if (upsampleOnly) {
sbrFreq->kStart = 32;
sbrFreq->numQMFBands = 0;
}
for (ch = 0; ch < chBlock; ch++) {
sbrGrid = &(psi->sbrGrid[chBase + ch]);
sbrChan = &(psi->sbrChan[chBase + ch]);
if (aacDecInfo->rawSampleBuf[ch] == 0 || aacDecInfo->rawSampleBytes != 4)
return ERR_AAC_SBR_PCM_FORMAT;
inbuf = (int *)aacDecInfo->rawSampleBuf[ch];
outptr = outbuf + chBase + ch;
/* restore delay buffers (could use ring buffer or keep in temp buffer for nChans == 1) */
for (l = 0; l < HF_GEN; l++) {
for (k = 0; k < 64; k++) {
psi->XBuf[l][k][0] = psi->XBufDelay[chBase + ch][l][k][0];
psi->XBuf[l][k][1] = psi->XBufDelay[chBase + ch][l][k][1];
}
}
/* step 1 - analysis QMF */
qmfaBands = sbrFreq->kStart;
for (l = 0; l < 32; l++) {
gbMask = QMFAnalysis(inbuf + l*32, psi->delayQMFA[chBase + ch], psi->XBuf[l + HF_GEN][0],
aacDecInfo->rawSampleFBits, &(psi->delayIdxQMFA[chBase + ch]), qmfaBands);
gbIdx = ((l + HF_GEN) >> 5) & 0x01;
sbrChan->gbMask[gbIdx] |= gbMask; /* gbIdx = (0 if i < 32), (1 if i >= 32) */
}
if (upsampleOnly) {
/* no SBR - just run synthesis QMF to upsample by 2x */
qmfsBands = 32;
for (l = 0; l < 32; l++) {
/* step 4 - synthesis QMF */
QMFSynthesis(psi->XBuf[l + HF_ADJ][0], psi->delayQMFS[chBase + ch], &(psi->delayIdxQMFS[chBase + ch]), qmfsBands, outptr, aacDecInfo->nChans);
outptr += 64*aacDecInfo->nChans;
}
} else {
/* if previous frame had lower SBR starting freq than current, zero out the synthesized QMF
* bands so they aren't used as sources for patching
* after patch generation, restore from delay buffer
* can only happen after header reset
*/
for (k = sbrFreq->kStartPrev; k < sbrFreq->kStart; k++) {
for (l = 0; l < sbrGrid->envTimeBorder[0] + HF_ADJ; l++) {
psi->XBuf[l][k][0] = 0;
psi->XBuf[l][k][1] = 0;
}
}
/* step 2 - HF generation */
GenerateHighFreq(psi, sbrGrid, sbrFreq, sbrChan, ch);
/* restore SBR bands that were cleared before patch generation (time slots 0, 1 no longer needed) */
for (k = sbrFreq->kStartPrev; k < sbrFreq->kStart; k++) {
for (l = HF_ADJ; l < sbrGrid->envTimeBorder[0] + HF_ADJ; l++) {
psi->XBuf[l][k][0] = psi->XBufDelay[chBase + ch][l][k][0];
psi->XBuf[l][k][1] = psi->XBufDelay[chBase + ch][l][k][1];
}
}
/* step 3 - HF adjustment */
AdjustHighFreq(psi, sbrHdr, sbrGrid, sbrFreq, sbrChan, ch);
/* step 4 - synthesis QMF */
qmfsBands = sbrFreq->kStartPrev + sbrFreq->numQMFBandsPrev;
for (l = 0; l < sbrGrid->envTimeBorder[0]; l++) {
/* if new envelope starts mid-frame, use old settings until start of first envelope in this frame */
QMFSynthesis(psi->XBuf[l + HF_ADJ][0], psi->delayQMFS[chBase + ch], &(psi->delayIdxQMFS[chBase + ch]), qmfsBands, outptr, aacDecInfo->nChans);
outptr += 64*aacDecInfo->nChans;
}
qmfsBands = sbrFreq->kStart + sbrFreq->numQMFBands;
for ( ; l < 32; l++) {
/* use new settings for rest of frame (usually the entire frame, unless the first envelope starts mid-frame) */
QMFSynthesis(psi->XBuf[l + HF_ADJ][0], psi->delayQMFS[chBase + ch], &(psi->delayIdxQMFS[chBase + ch]), qmfsBands, outptr, aacDecInfo->nChans);
outptr += 64*aacDecInfo->nChans;
}
}
/* save delay */
for (l = 0; l < HF_GEN; l++) {
for (k = 0; k < 64; k++) {
psi->XBufDelay[chBase + ch][l][k][0] = psi->XBuf[l+32][k][0];
psi->XBufDelay[chBase + ch][l][k][1] = psi->XBuf[l+32][k][1];
}
}
sbrChan->gbMask[0] = sbrChan->gbMask[1];
sbrChan->gbMask[1] = 0;
if (sbrHdr->count > 0)
sbrChan->reset = 0;
}
sbrFreq->kStartPrev = sbrFreq->kStart;
sbrFreq->numQMFBandsPrev = sbrFreq->numQMFBands;
if (aacDecInfo->nChans > 0 && (chBase + ch) == aacDecInfo->nChans)
psi->frameCount++;
return ERR_AAC_NONE;
}
/**************************************************************************************
* Function: FlushCodecSBR
*
* Description: flush internal SBR codec state (after seeking, for example)
*
* Inputs: valid AACDecInfo struct
*
* Outputs: updated state variables for SBR
*
* Return: 0 if successful, error code (< 0) if error
*
* Notes: SBR is heavily dependent on state from previous frames
* (e.g. delta coded scalefactors, previous envelope boundaries, etc.)
* On flush, we reset everything as if SBR had just been initialized
* for the first time. This triggers "upsample-only" mode until
* the first valid SBR header is received. Then SBR starts as usual.
**************************************************************************************/
int FlushCodecSBR(AACDecInfo *aacDecInfo)
{
PSInfoSBR *psi;
/* validate pointers */
if (!aacDecInfo || !aacDecInfo->psInfoSBR)
return ERR_AAC_NULL_POINTER;
psi = (PSInfoSBR *)(aacDecInfo->psInfoSBR);
InitSBRState(psi);
return 0;
}

View File

@@ -0,0 +1,383 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: sbr.h,v 1.2 2005/05/20 18:05:41 jrecker Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* sbr.h - definitions of platform-specific SBR data structures, functions, and tables
**************************************************************************************/
#ifndef _SBR_H
#define _SBR_H
#include "aaccommon.h"
#include "bitstream.h"
#ifndef ASSERT
#if defined(_WIN32) && defined(_M_IX86) && (defined (_DEBUG) || defined (REL_ENABLE_ASSERTS))
#define ASSERT(x) if (!(x)) __asm int 3;
#else
#define ASSERT(x) /* do nothing */
#endif
#endif
#ifndef MAX
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#endif
#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
#define NUM_TIME_SLOTS 16
#define SAMPLES_PER_SLOT 2 /* RATE in spec */
#define NUM_SAMPLE_RATES_SBR 9 /* downsampled (single-rate) mode unsupported, so only use Fs_sbr >= 16 kHz */
#define MAX_NUM_ENV 5
#define MAX_NUM_NOISE_FLOORS 2
#define MAX_NUM_NOISE_FLOOR_BANDS 5 /* max Nq, see 4.6.18.3.6 */
#define MAX_NUM_PATCHES 5
#define MAX_NUM_SMOOTH_COEFS 5
#define HF_GEN 8
#define HF_ADJ 2
#define MAX_QMF_BANDS 48 /* max QMF subbands covered by SBR (4.6.18.3.6) */
#define FBITS_IN_QMFA 14
#define FBITS_LOST_QMFA (1 + 2 + 3 + 2 + 1) /* 1 from cTab, 2 in premul, 3 in FFT, 2 in postmul, 1 for implicit scaling by 2.0 */
#define FBITS_OUT_QMFA (FBITS_IN_QMFA - FBITS_LOST_QMFA)
#define MIN_GBITS_IN_QMFS 2
#define FBITS_IN_QMFS FBITS_OUT_QMFA
#define FBITS_LOST_DCT4_64 (2 + 3 + 2) /* 2 in premul, 3 in FFT, 2 in postmul */
#define FBITS_OUT_DQ_ENV 29 /* dequantized env scalefactors are Q(29 - envDataDequantScale) */
#define FBITS_OUT_DQ_NOISE 24 /* range of Q_orig = [2^-24, 2^6] */
#define NOISE_FLOOR_OFFSET 6
/* see comments in ApplyBoost() */
#define FBITS_GLIM_BOOST 24
#define FBITS_QLIM_BOOST 14
#define MAX_HUFF_BITS 20
#define NUM_QMF_DELAY_BUFS 10
#define DELAY_SAMPS_QMFA (NUM_QMF_DELAY_BUFS * 32)
#define DELAY_SAMPS_QMFS (NUM_QMF_DELAY_BUFS * 128)
/* additional external symbols to name-mangle for static linking */
#define FFT32C STATNAME(FFT32C)
#define CalcFreqTables STATNAME(CalcFreqTables)
#define AdjustHighFreq STATNAME(AdjustHighFreq)
#define GenerateHighFreq STATNAME(GenerateHighFreq)
#define DecodeSBREnvelope STATNAME(DecodeSBREnvelope)
#define DecodeSBRNoise STATNAME(DecodeSBRNoise)
#define UncoupleSBREnvelope STATNAME(UncoupleSBREnvelope)
#define UncoupleSBRNoise STATNAME(UncoupleSBRNoise)
#define InvRNormalized STATNAME(InvRNormalized)
#define RatioPowInv STATNAME(RatioPowInv)
#define SqrtFix STATNAME(SqrtFix)
#define QMFAnalysis STATNAME(QMFAnalysis)
#define QMFSynthesis STATNAME(QMFSynthesis)
#define GetSampRateIdx STATNAME(GetSampRateIdx)
#define UnpackSBRHeader STATNAME(UnpackSBRHeader)
#define UnpackSBRSingleChannel STATNAME(UnpackSBRSingleChannel)
#define UnpackSBRChannelPair STATNAME(UnpackSBRChannelPair)
/* asm functions */
#define CVKernel1 STATNAME(CVKernel1)
#define CVKernel2 STATNAME(CVKernel2)
#define QMFAnalysisConv STATNAME(QMFAnalysisConv)
#define QMFSynthesisConv STATNAME(QMFSynthesisConv)
#define k0Tab STATNAME(k0Tab)
#define k2Tab STATNAME(k2Tab)
#define goalSBTab STATNAME(goalSBTab)
#define huffTabSBR STATNAME(huffTabSBR)
#define huffTabSBRInfo STATNAME(huffTabSBRInfo)
#define log2Tab STATNAME(log2Tab)
#define noiseTab STATNAME(noiseTab)
#define cTabA STATNAME(cTabA)
#define cTabS STATNAME(cTabS)
/* do y <<= n, clipping to range [-2^30, 2^30 - 1] (i.e. output has one guard bit) */
#define CLIP_2N_SHIFT30(y, n) { \
int sign = (y) >> 31; \
if (sign != (y) >> (30 - (n))) { \
(y) = sign ^ (0x3fffffff); \
} else { \
(y) = (y) << (n); \
} \
}
/*
#define CLIP_2N(y, n) { \
int sign = (y) >> 31; \
if (sign != ((y) >> (n))) { \
(y) = sign ^ ((1 << (n)) - 1); \
} \
}
*/
enum {
SBR_GRID_FIXFIX = 0,
SBR_GRID_FIXVAR = 1,
SBR_GRID_VARFIX = 2,
SBR_GRID_VARVAR = 3
};
enum {
HuffTabSBR_tEnv15 = 0,
HuffTabSBR_fEnv15 = 1,
HuffTabSBR_tEnv15b = 2,
HuffTabSBR_fEnv15b = 3,
HuffTabSBR_tEnv30 = 4,
HuffTabSBR_fEnv30 = 5,
HuffTabSBR_tEnv30b = 6,
HuffTabSBR_fEnv30b = 7,
HuffTabSBR_tNoise30 = 8,
HuffTabSBR_fNoise30 = 5,
HuffTabSBR_tNoise30b = 9,
HuffTabSBR_fNoise30b = 7
};
typedef struct _HuffInfo {
int maxBits; /* number of bits in longest codeword */
unsigned /*char*/ int count[MAX_HUFF_BITS]; /* count[i] = number of codes with length i+1 bits */
int offset; /* offset into symbol table */
} HuffInfo;
/* need one SBRHeader per element (SCE/CPE), updated only on new header */
typedef struct _SBRHeader {
int count;
unsigned char ampRes;
unsigned char startFreq;
unsigned char stopFreq;
unsigned char crossOverBand;
unsigned char resBitsHdr;
unsigned char hdrExtra1;
unsigned char hdrExtra2;
unsigned char freqScale;
unsigned char alterScale;
unsigned char noiseBands;
unsigned char limiterBands;
unsigned char limiterGains;
unsigned char interpFreq;
unsigned char smoothMode;
} SBRHeader;
/* need one SBRGrid per channel, updated every frame */
typedef struct _SBRGrid {
unsigned char frameClass;
unsigned char ampResFrame;
unsigned char pointer;
unsigned char numEnv; /* L_E */
unsigned char envTimeBorder[MAX_NUM_ENV+1]; /* t_E */
unsigned char freqRes[MAX_NUM_ENV]; /* r */
unsigned char numNoiseFloors; /* L_Q */
unsigned char noiseTimeBorder[MAX_NUM_NOISE_FLOORS+1]; /* t_Q */
unsigned char numEnvPrev;
unsigned char numNoiseFloorsPrev;
unsigned char freqResPrev;
} SBRGrid;
/* need one SBRFreq per element (SCE/CPE/LFE), updated only on header reset */
typedef struct _SBRFreq {
int kStart; /* k_x */
int nMaster;
int nHigh;
int nLow;
int nLimiter; /* N_l */
int numQMFBands; /* M */
int numNoiseFloorBands; /* Nq */
int kStartPrev;
int numQMFBandsPrev;
unsigned char freqMaster[MAX_QMF_BANDS + 1]; /* not necessary to save this after derived tables are generated */
unsigned char freqHigh[MAX_QMF_BANDS + 1];
unsigned char freqLow[MAX_QMF_BANDS / 2 + 1]; /* nLow = nHigh - (nHigh >> 1) */
unsigned char freqNoise[MAX_NUM_NOISE_FLOOR_BANDS+1];
unsigned char freqLimiter[MAX_QMF_BANDS / 2 + MAX_NUM_PATCHES]; /* max (intermediate) size = nLow + numPatches - 1 */
unsigned char numPatches;
unsigned char patchNumSubbands[MAX_NUM_PATCHES + 1];
unsigned char patchStartSubband[MAX_NUM_PATCHES + 1];
} SBRFreq;
typedef struct _SBRChan {
int reset;
unsigned char deltaFlagEnv[MAX_NUM_ENV];
unsigned char deltaFlagNoise[MAX_NUM_NOISE_FLOORS];
signed char envDataQuant[MAX_NUM_ENV][MAX_QMF_BANDS]; /* range = [0, 127] */
signed char noiseDataQuant[MAX_NUM_NOISE_FLOORS][MAX_NUM_NOISE_FLOOR_BANDS];
unsigned char invfMode[2][MAX_NUM_NOISE_FLOOR_BANDS]; /* invfMode[0/1][band] = prev/curr */
int chirpFact[MAX_NUM_NOISE_FLOOR_BANDS]; /* bwArray */
unsigned char addHarmonicFlag[2]; /* addHarmonicFlag[0/1] = prev/curr */
unsigned char addHarmonic[2][64]; /* addHarmonic[0/1][band] = prev/curr */
int gbMask[2]; /* gbMask[0/1] = XBuf[0-31]/XBuf[32-39] */
signed char laPrev;
int noiseTabIndex;
int sinIndex;
int gainNoiseIndex;
int gTemp[MAX_NUM_SMOOTH_COEFS][MAX_QMF_BANDS];
int qTemp[MAX_NUM_SMOOTH_COEFS][MAX_QMF_BANDS];
} SBRChan;
typedef struct _PSInfoSBR {
/* save for entire file */
int frameCount;
int sampRateIdx;
/* state info that must be saved for each channel */
SBRHeader sbrHdr[AAC_MAX_NCHANS];
SBRGrid sbrGrid[AAC_MAX_NCHANS];
SBRFreq sbrFreq[AAC_MAX_NCHANS];
SBRChan sbrChan[AAC_MAX_NCHANS];
/* temp variables, no need to save between blocks */
unsigned char dataExtra;
unsigned char resBitsData;
unsigned char extendedDataPresent;
int extendedDataSize;
signed char envDataDequantScale[MAX_NCHANS_ELEM][MAX_NUM_ENV];
int envDataDequant[MAX_NCHANS_ELEM][MAX_NUM_ENV][MAX_QMF_BANDS];
int noiseDataDequant[MAX_NCHANS_ELEM][MAX_NUM_NOISE_FLOORS][MAX_NUM_NOISE_FLOOR_BANDS];
int eCurr[MAX_QMF_BANDS];
unsigned char eCurrExp[MAX_QMF_BANDS];
unsigned char eCurrExpMax;
signed char la;
int crcCheckWord;
int couplingFlag;
int envBand;
int eOMGainMax;
int gainMax;
int gainMaxFBits;
int noiseFloorBand;
int qp1Inv;
int qqp1Inv;
int sMapped;
int sBand;
int highBand;
int sumEOrigMapped;
int sumECurrGLim;
int sumSM;
int sumQM;
int gLimBoost[MAX_QMF_BANDS];
int qmLimBoost[MAX_QMF_BANDS];
int smBoost[MAX_QMF_BANDS];
int smBuf[MAX_QMF_BANDS];
int qmLimBuf[MAX_QMF_BANDS];
int gLimBuf[MAX_QMF_BANDS];
int gLimFbits[MAX_QMF_BANDS];
int gFiltLast[MAX_QMF_BANDS];
int qFiltLast[MAX_QMF_BANDS];
/* large buffers */
int delayIdxQMFA[AAC_MAX_NCHANS];
int delayQMFA[AAC_MAX_NCHANS][DELAY_SAMPS_QMFA];
int delayIdxQMFS[AAC_MAX_NCHANS];
int delayQMFS[AAC_MAX_NCHANS][DELAY_SAMPS_QMFS];
int XBufDelay[AAC_MAX_NCHANS][HF_GEN][64][2];
int XBuf[32+8][64][2];
} PSInfoSBR;
/* sbrfft.c */
void FFT32C(int *x);
/* sbrfreq.c */
int CalcFreqTables(SBRHeader *sbrHdr, SBRFreq *sbrFreq, int sampRateIdx);
/* sbrhfadj.c */
void AdjustHighFreq(PSInfoSBR *psi, SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int ch);
/* sbrhfgen.c */
void GenerateHighFreq(PSInfoSBR *psi, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int ch);
/* sbrhuff.c */
void DecodeSBREnvelope(BitStreamInfo *bsi, PSInfoSBR *psi, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int ch);
void DecodeSBRNoise(BitStreamInfo *bsi, PSInfoSBR *psi, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int ch);
void UncoupleSBREnvelope(PSInfoSBR *psi, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChanR);
void UncoupleSBRNoise(PSInfoSBR *psi, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChanR);
/* sbrmath.c */
int InvRNormalized(int r);
int RatioPowInv(int a, int b, int c);
int SqrtFix(int x, int fBitsIn, int *fBitsOut);
/* sbrqmf.c */
int QMFAnalysis(int *inbuf, int *delay, int *XBuf, int fBitsIn, int *delayIdx, int qmfaBands);
void QMFSynthesis(int *inbuf, int *delay, int *delayIdx, int qmfsBands, short *outbuf, int nChans);
/* sbrside.c */
int GetSampRateIdx(int sampRate);
int UnpackSBRHeader(BitStreamInfo *bsi, SBRHeader *sbrHdr);
void UnpackSBRSingleChannel(BitStreamInfo *bsi, PSInfoSBR *psi, int chOut);
void UnpackSBRChannelPair(BitStreamInfo *bsi, PSInfoSBR *psi, int chOut);
/* sbrtabs.c */
extern const unsigned char k0Tab[NUM_SAMPLE_RATES_SBR][16];
extern const unsigned char k2Tab[NUM_SAMPLE_RATES_SBR][14];
extern const unsigned char goalSBTab[NUM_SAMPLE_RATES_SBR];
extern const HuffInfo huffTabSBRInfo[10];
extern const signed int /*short*/ huffTabSBR[604];
extern const int log2Tab[65];
extern const int noiseTab[512*2];
extern const int cTabA[165];
extern const int cTabS[640];
#endif /* _SBR_H */

View File

@@ -0,0 +1,368 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: sbrfft.c,v 1.1 2005/02/26 01:47:35 jrecker Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com), Ken Cooke (kenc@real.com)
* February 2005
*
* sbrfft.c - optimized FFT for SBR QMF filters
**************************************************************************************/
#include "sbr.h"
#include "assembly.h"
#define SQRT1_2 0x5a82799a
/* swap RE{p0} with RE{p1} and IM{P0} with IM{P1} */
#define swapcplx(p0,p1) \
t = p0; t1 = *(&(p0)+1); p0 = p1; *(&(p0)+1) = *(&(p1)+1); p1 = t; *(&(p1)+1) = t1
/* nfft = 32, hard coded since small, fixed size FFT
static const unsigned char bitrevtab32[9] = {
0x01, 0x04, 0x03, 0x06, 0x00, 0x02, 0x05, 0x07, 0x00,
};
*/
/* twiddle table for radix 4 pass, format = Q31 */
static const int twidTabOdd32[8*6] = {
0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x40000000, 0x00000000, 0x539eba45, 0xe7821d59,
0x4b418bbe, 0xf383a3e2, 0x58c542c5, 0xdc71898d, 0x5a82799a, 0xd2bec333, 0x539eba45, 0xe7821d59,
0x539eba45, 0xc4df2862, 0x539eba45, 0xc4df2862, 0x58c542c5, 0xdc71898d, 0x3248d382, 0xc13ad060,
0x40000000, 0xc0000000, 0x5a82799a, 0xd2bec333, 0x00000000, 0xd2bec333, 0x22a2f4f8, 0xc4df2862,
0x58c542c5, 0xcac933ae, 0xcdb72c7e, 0xf383a3e2, 0x00000000, 0xd2bec333, 0x539eba45, 0xc4df2862,
0xac6145bb, 0x187de2a7, 0xdd5d0b08, 0xe7821d59, 0x4b418bbe, 0xc13ad060, 0xa73abd3b, 0x3536cc52,
};
/**************************************************************************************
* Function: BitReverse32
*
* Description: Ken's fast in-place bit reverse
*
* Inputs: buffer of 32 complex samples
*
* Outputs: bit-reversed samples in same buffer
*
* Return: none
**************************************************************************************/
static void BitReverse32(int *inout)
{
int t, t1;
swapcplx(inout[2], inout[32]);
swapcplx(inout[4], inout[16]);
swapcplx(inout[6], inout[48]);
swapcplx(inout[10], inout[40]);
swapcplx(inout[12], inout[24]);
swapcplx(inout[14], inout[56]);
swapcplx(inout[18], inout[36]);
swapcplx(inout[22], inout[52]);
swapcplx(inout[26], inout[44]);
swapcplx(inout[30], inout[60]);
swapcplx(inout[38], inout[50]);
swapcplx(inout[46], inout[58]);
}
/**************************************************************************************
* Function: R8FirstPass32
*
* Description: radix-8 trivial pass for decimation-in-time FFT (log2(N) = 5)
*
* Inputs: buffer of (bit-reversed) samples
*
* Outputs: processed samples in same buffer
*
* Return: none
*
* Notes: assumes 3 guard bits, gains 1 integer bit
* guard bits out = guard bits in - 3 (if inputs are full scale)
* or guard bits in - 2 (if inputs bounded to +/- sqrt(2)/2)
* see scaling comments in fft.c for base AAC
* should compile with no stack spills on ARM (verify compiled output)
* current instruction count (per pass): 16 LDR, 16 STR, 4 SMULL, 61 ALU
**************************************************************************************/
static void R8FirstPass32(int *r0)
{
int r1, r2, r3, r4, r5, r6, r7;
int r8, r9, r10, r11, r12, r14;
/* number of passes = fft size / 8 = 32 / 8 = 4 */
r1 = (32 >> 3);
do {
r2 = r0[8];
r3 = r0[9];
r4 = r0[10];
r5 = r0[11];
r6 = r0[12];
r7 = r0[13];
r8 = r0[14];
r9 = r0[15];
r10 = r2 + r4;
r11 = r3 + r5;
r12 = r6 + r8;
r14 = r7 + r9;
r2 -= r4;
r3 -= r5;
r6 -= r8;
r7 -= r9;
r4 = r2 - r7;
r5 = r2 + r7;
r8 = r3 - r6;
r9 = r3 + r6;
r2 = r4 - r9;
r3 = r4 + r9;
r6 = r5 - r8;
r7 = r5 + r8;
r2 = MULSHIFT32(SQRT1_2, r2); /* can use r4, r5, r8, or r9 for constant and lo32 scratch reg */
r3 = MULSHIFT32(SQRT1_2, r3);
r6 = MULSHIFT32(SQRT1_2, r6);
r7 = MULSHIFT32(SQRT1_2, r7);
r4 = r10 + r12;
r5 = r10 - r12;
r8 = r11 + r14;
r9 = r11 - r14;
r10 = r0[0];
r11 = r0[2];
r12 = r0[4];
r14 = r0[6];
r10 += r11;
r12 += r14;
r4 >>= 1;
r10 += r12;
r4 += (r10 >> 1);
r0[ 0] = r4;
r4 -= (r10 >> 1);
r4 = (r10 >> 1) - r4;
r0[ 8] = r4;
r9 >>= 1;
r10 -= 2*r12;
r4 = (r10 >> 1) + r9;
r0[ 4] = r4;
r4 = (r10 >> 1) - r9;
r0[12] = r4;
r10 += r12;
r10 -= 2*r11;
r12 -= 2*r14;
r4 = r0[1];
r9 = r0[3];
r11 = r0[5];
r14 = r0[7];
r4 += r9;
r11 += r14;
r8 >>= 1;
r4 += r11;
r8 += (r4 >> 1);
r0[ 1] = r8;
r8 -= (r4 >> 1);
r8 = (r4 >> 1) - r8;
r0[ 9] = r8;
r5 >>= 1;
r4 -= 2*r11;
r8 = (r4 >> 1) - r5;
r0[ 5] = r8;
r8 = (r4 >> 1) + r5;
r0[13] = r8;
r4 += r11;
r4 -= 2*r9;
r11 -= 2*r14;
r9 = r10 - r11;
r10 += r11;
r14 = r4 + r12;
r4 -= r12;
r5 = (r10 >> 1) + r7;
r8 = (r4 >> 1) - r6;
r0[ 2] = r5;
r0[ 3] = r8;
r5 = (r9 >> 1) - r2;
r8 = (r14 >> 1) - r3;
r0[ 6] = r5;
r0[ 7] = r8;
r5 = (r10 >> 1) - r7;
r8 = (r4 >> 1) + r6;
r0[10] = r5;
r0[11] = r8;
r5 = (r9 >> 1) + r2;
r8 = (r14 >> 1) + r3;
r0[14] = r5;
r0[15] = r8;
r0 += 16;
r1--;
} while (r1 != 0);
}
/**************************************************************************************
* Function: R4Core32
*
* Description: radix-4 pass for 32-point decimation-in-time FFT
*
* Inputs: buffer of samples
*
* Outputs: processed samples in same buffer
*
* Return: none
*
* Notes: gain 2 integer bits
* guard bits out = guard bits in - 1 (if inputs are full scale)
* see scaling comments in fft.c for base AAC
* uses 3-mul, 3-add butterflies instead of 4-mul, 2-add
* should compile with no stack spills on ARM (verify compiled output)
* current instruction count (per pass): 16 LDR, 16 STR, 4 SMULL, 61 ALU
**************************************************************************************/
static void R4Core32(int *r0)
{
int r2, r3, r4, r5, r6, r7;
int r8, r9, r10, r12, r14;
int *r1;
r1 = (int *)twidTabOdd32;
r10 = 8;
do {
/* can use r14 for lo32 scratch register in all MULSHIFT32 */
r2 = r1[0];
r3 = r1[1];
r4 = r0[16];
r5 = r0[17];
r12 = r4 + r5;
r12 = MULSHIFT32(r3, r12);
r5 = MULSHIFT32(r2, r5) + r12;
r2 += 2*r3;
r4 = MULSHIFT32(r2, r4) - r12;
r2 = r1[2];
r3 = r1[3];
r6 = r0[32];
r7 = r0[33];
r12 = r6 + r7;
r12 = MULSHIFT32(r3, r12);
r7 = MULSHIFT32(r2, r7) + r12;
r2 += 2*r3;
r6 = MULSHIFT32(r2, r6) - r12;
r2 = r1[4];
r3 = r1[5];
r8 = r0[48];
r9 = r0[49];
r12 = r8 + r9;
r12 = MULSHIFT32(r3, r12);
r9 = MULSHIFT32(r2, r9) + r12;
r2 += 2*r3;
r8 = MULSHIFT32(r2, r8) - r12;
r2 = r0[0];
r3 = r0[1];
r12 = r6 + r8;
r8 = r6 - r8;
r14 = r9 - r7;
r9 = r9 + r7;
r6 = (r2 >> 2) - r4;
r7 = (r3 >> 2) - r5;
r4 += (r2 >> 2);
r5 += (r3 >> 2);
r2 = r4 + r12;
r3 = r5 + r9;
r0[0] = r2;
r0[1] = r3;
r2 = r6 - r14;
r3 = r7 - r8;
r0[16] = r2;
r0[17] = r3;
r2 = r4 - r12;
r3 = r5 - r9;
r0[32] = r2;
r0[33] = r3;
r2 = r6 + r14;
r3 = r7 + r8;
r0[48] = r2;
r0[49] = r3;
r0 += 2;
r1 += 6;
r10--;
} while (r10 != 0);
}
/**************************************************************************************
* Function: FFT32C
*
* Description: Ken's very fast in-place radix-4 decimation-in-time FFT
*
* Inputs: buffer of 32 complex samples (before bit-reversal)
*
* Outputs: processed samples in same buffer
*
* Return: none
*
* Notes: assumes 3 guard bits in, gains 3 integer bits
* guard bits out = guard bits in - 2
* (guard bit analysis includes assumptions about steps immediately
* before and after, i.e. PreMul and PostMul for DCT)
**************************************************************************************/
void FFT32C(int *x)
{
/* decimation in time */
BitReverse32(x);
/* 32-point complex FFT */
R8FirstPass32(x); /* gain 1 int bit, lose 2 GB (making assumptions about input) */
R4Core32(x); /* gain 2 int bits, lose 0 GB (making assumptions about input) */
}

View File

@@ -0,0 +1,641 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: sbrfreq.c,v 1.2 2005/05/20 18:05:41 jrecker Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* sbrfreq.c - frequency band table calculation for SBR
**************************************************************************************/
#include "sbr.h"
#include "assembly.h"
/**************************************************************************************
* Function: BubbleSort
*
* Description: in-place sort of unsigned chars
*
* Inputs: buffer of elements to sort
* number of elements to sort
*
* Outputs: sorted buffer
*
* Return: none
**************************************************************************************/
static void BubbleSort(unsigned char *v, int nItems)
{
int i;
unsigned char t;
while (nItems >= 2) {
for (i = 0; i < nItems-1; i++) {
if (v[i+1] < v[i]) {
t = v[i+1];
v[i+1] = v[i];
v[i] = t;
}
}
nItems--;
}
}
/**************************************************************************************
* Function: VMin
*
* Description: find smallest element in a buffer of unsigned chars
*
* Inputs: buffer of elements to search
* number of elements to search
*
* Outputs: none
*
* Return: smallest element in buffer
**************************************************************************************/
static unsigned char VMin(unsigned char *v, int nItems)
{
int i;
unsigned char vMin;
vMin = v[0];
for (i = 1; i < nItems; i++) {
if (v[i] < vMin)
vMin = v[i];
}
return vMin;
}
/**************************************************************************************
* Function: VMax
*
* Description: find largest element in a buffer of unsigned chars
*
* Inputs: buffer of elements to search
* number of elements to search
*
* Outputs: none
*
* Return: largest element in buffer
**************************************************************************************/
static unsigned char VMax(unsigned char *v, int nItems)
{
int i;
unsigned char vMax;
vMax = v[0];
for (i = 1; i < nItems; i++) {
if (v[i] > vMax)
vMax = v[i];
}
return vMax;
}
/**************************************************************************************
* Function: CalcFreqMasterScaleZero
*
* Description: calculate master frequency table when freqScale == 0
* (4.6.18.3.2.1, figure 4.39)
*
* Inputs: alterScale flag
* index of first QMF subband in master freq table (k0)
* index of last QMF subband (k2)
*
* Outputs: master frequency table
*
* Return: number of bands in master frequency table
*
* Notes: assumes k2 - k0 <= 48 and k2 >= k0 (4.6.18.3.6)
**************************************************************************************/
static int CalcFreqMasterScaleZero(unsigned char *freqMaster, int alterScale, int k0, int k2)
{
int nMaster, k, nBands, k2Achieved, dk, vDk[64], k2Diff;
if (alterScale) {
dk = 2;
nBands = 2 * ((k2 - k0 + 2) >> 2);
} else {
dk = 1;
nBands = 2 * ((k2 - k0) >> 1);
}
if (nBands <= 0)
return 0;
k2Achieved = k0 + nBands * dk;
k2Diff = k2 - k2Achieved;
for (k = 0; k < nBands; k++)
vDk[k] = dk;
if (k2Diff > 0) {
k = nBands - 1;
while (k2Diff) {
vDk[k]++;
k--;
k2Diff--;
}
} else if (k2Diff < 0) {
k = 0;
while (k2Diff) {
vDk[k]--;
k++;
k2Diff++;
}
}
nMaster = nBands;
freqMaster[0] = k0;
for (k = 1; k <= nBands; k++)
freqMaster[k] = freqMaster[k-1] + vDk[k-1];
return nMaster;
}
/* mBandTab[i] = temp1[i] / 2 */
static const int mBandTab[3] PROGMEM = {6, 5, 4};
/* invWarpTab[i] = 1.0 / temp2[i], Q30 (see 4.6.18.3.2.1) */
static const int invWarpTab[2] PROGMEM = {0x40000000, 0x313b13b1};
/**************************************************************************************
* Function: CalcFreqMasterScale
*
* Description: calculate master frequency table when freqScale > 0
* (4.6.18.3.2.1, figure 4.39)
*
* Inputs: alterScale flag
* freqScale flag
* index of first QMF subband in master freq table (k0)
* index of last QMF subband (k2)
*
* Outputs: master frequency table
*
* Return: number of bands in master frequency table
*
* Notes: assumes k2 - k0 <= 48 and k2 >= k0 (4.6.18.3.6)
**************************************************************************************/
static int CalcFreqMaster(unsigned char *freqMaster, int freqScale, int alterScale, int k0, int k2)
{
int bands, twoRegions, k, k1, t, vLast, vCurr, pCurr;
int invWarp, nBands0, nBands1, change;
unsigned char vDk1Min, vDk0Max;
unsigned char *vDelta;
if (freqScale < 1 || freqScale > 3)
return -1;
bands = mBandTab[freqScale - 1];
invWarp = invWarpTab[alterScale];
/* tested for all k0 = [5, 64], k2 = [k0, 64] */
if (k2*10000 > 22449*k0) {
twoRegions = 1;
k1 = 2*k0;
} else {
twoRegions = 0;
k1 = k2;
}
/* tested for all k0 = [5, 64], k1 = [k0, 64], freqScale = [1,3] */
t = (log2Tab[k1] - log2Tab[k0]) >> 3; /* log2(k1/k0), Q28 to Q25 */
nBands0 = 2 * (((bands * t) + (1 << 24)) >> 25); /* multiply by bands/2, round to nearest int (mBandTab has factor of 1/2 rolled in) */
/* tested for all valid combinations of k0, k1, nBands (from sampRate, freqScale, alterScale)
* roundoff error can be a problem with fixpt (e.g. pCurr = 12.499999 instead of 12.50003)
* because successive multiplication always undershoots a little bit, but this
* doesn't occur in any of the ratios we encounter from the valid k0/k1 bands in the spec
*/
t = RatioPowInv(k1, k0, nBands0);
pCurr = k0 << 24;
vLast = k0;
vDelta = freqMaster + 1; /* operate in-place */
for (k = 0; k < nBands0; k++) {
pCurr = MULSHIFT32(pCurr, t) << 8; /* keep in Q24 */
vCurr = (pCurr + (1 << 23)) >> 24;
vDelta[k] = (vCurr - vLast);
vLast = vCurr;
}
/* sort the deltas and find max delta for first region */
BubbleSort(vDelta, nBands0);
vDk0Max = VMax(vDelta, nBands0);
/* fill master frequency table with bands from first region */
freqMaster[0] = k0;
for (k = 1; k <= nBands0; k++)
freqMaster[k] += freqMaster[k-1];
/* if only one region, then the table is complete */
if (!twoRegions)
return nBands0;
/* tested for all k1 = [10, 64], k2 = [k0, 64], freqScale = [1,3] */
t = (log2Tab[k2] - log2Tab[k1]) >> 3; /* log2(k1/k0), Q28 to Q25 */
t = MULSHIFT32(bands * t, invWarp) << 2; /* multiply by bands/2, divide by warp factor, keep Q25 */
nBands1 = 2 * ((t + (1 << 24)) >> 25); /* round to nearest int */
/* see comments above for calculations in first region */
t = RatioPowInv(k2, k1, nBands1);
pCurr = k1 << 24;
vLast = k1;
vDelta = freqMaster + nBands0 + 1; /* operate in-place */
for (k = 0; k < nBands1; k++) {
pCurr = MULSHIFT32(pCurr, t) << 8; /* keep in Q24 */
vCurr = (pCurr + (1 << 23)) >> 24;
vDelta[k] = (vCurr - vLast);
vLast = vCurr;
}
/* sort the deltas, adjusting first and last if the second region has smaller deltas than the first */
vDk1Min = VMin(vDelta, nBands1);
if (vDk1Min < vDk0Max) {
BubbleSort(vDelta, nBands1);
change = vDk0Max - vDelta[0];
if (change > ((vDelta[nBands1 - 1] - vDelta[0]) >> 1))
change = ((vDelta[nBands1 - 1] - vDelta[0]) >> 1);
vDelta[0] += change;
vDelta[nBands1-1] -= change;
}
BubbleSort(vDelta, nBands1);
/* fill master frequency table with bands from second region
* Note: freqMaster[nBands0] = k1
*/
for (k = 1; k <= nBands1; k++)
freqMaster[k + nBands0] += freqMaster[k + nBands0 - 1];
return (nBands0 + nBands1);
}
/**************************************************************************************
* Function: CalcFreqHigh
*
* Description: calculate high resolution frequency table (4.6.18.3.2.2)
*
* Inputs: master frequency table
* number of bands in master frequency table
* crossover band from header
*
* Outputs: high resolution frequency table
*
* Return: number of bands in high resolution frequency table
**************************************************************************************/
static int CalcFreqHigh(unsigned char *freqHigh, unsigned char *freqMaster, int nMaster, int crossOverBand)
{
int k, nHigh;
nHigh = nMaster - crossOverBand;
for (k = 0; k <= nHigh; k++)
freqHigh[k] = freqMaster[k + crossOverBand];
return nHigh;
}
/**************************************************************************************
* Function: CalcFreqLow
*
* Description: calculate low resolution frequency table (4.6.18.3.2.2)
*
* Inputs: high resolution frequency table
* number of bands in high resolution frequency table
*
* Outputs: low resolution frequency table
*
* Return: number of bands in low resolution frequency table
**************************************************************************************/
static int CalcFreqLow(unsigned char *freqLow, unsigned char *freqHigh, int nHigh)
{
int k, nLow, oddFlag;
nLow = nHigh - (nHigh >> 1);
freqLow[0] = freqHigh[0];
oddFlag = nHigh & 0x01;
for (k = 1; k <= nLow; k++)
freqLow[k] = freqHigh[2*k - oddFlag];
return nLow;
}
/**************************************************************************************
* Function: CalcFreqNoise
*
* Description: calculate noise floor frequency table (4.6.18.3.2.2)
*
* Inputs: low resolution frequency table
* number of bands in low resolution frequency table
* index of starting QMF subband for SBR (kStart)
* index of last QMF subband (k2)
* number of noise bands
*
* Outputs: noise floor frequency table
*
* Return: number of bands in noise floor frequency table
**************************************************************************************/
static int CalcFreqNoise(unsigned char *freqNoise, unsigned char *freqLow, int nLow, int kStart, int k2, int noiseBands)
{
int i, iLast, k, nQ, lTop, lBottom;
lTop = log2Tab[k2];
lBottom = log2Tab[kStart];
nQ = noiseBands*((lTop - lBottom) >> 2); /* Q28 to Q26, noiseBands = [0,3] */
nQ = (nQ + (1 << 25)) >> 26;
if (nQ < 1)
nQ = 1;
ASSERT(nQ <= MAX_NUM_NOISE_FLOOR_BANDS); /* required from 4.6.18.3.6 */
iLast = 0;
freqNoise[0] = freqLow[0];
for (k = 1; k <= nQ; k++) {
i = iLast + (nLow - iLast) / (nQ + 1 - k); /* truncating division */
freqNoise[k] = freqLow[i];
iLast = i;
}
return nQ;
}
/**************************************************************************************
* Function: BuildPatches
*
* Description: build high frequency patches (4.6.18.6.3)
*
* Inputs: master frequency table
* number of bands in low resolution frequency table
* index of first QMF subband in master freq table (k0)
* index of starting QMF subband for SBR (kStart)
* number of QMF bands in high resolution frequency table
* sample rate index
*
* Outputs: starting subband for each patch
* number of subbands in each patch
*
* Return: number of patches
**************************************************************************************/
static int BuildPatches(unsigned char *patchNumSubbands, unsigned char *patchStartSubband, unsigned char *freqMaster,
int nMaster, int k0, int kStart, int numQMFBands, int sampRateIdx)
{
int i, j, k;
int msb, sb, usb, numPatches, goalSB, oddFlag;
msb = k0;
usb = kStart;
numPatches = 0;
goalSB = goalSBTab[sampRateIdx];
if (nMaster == 0) {
patchNumSubbands[0] = 0;
patchStartSubband[0] = 0;
return 0;
}
if (goalSB < kStart + numQMFBands) {
k = 0;
for (i = 0; freqMaster[i] < goalSB; i++)
k = i+1;
} else {
k = nMaster;
}
do {
j = k+1;
do {
j--;
sb = freqMaster[j];
oddFlag = (sb - 2 + k0) & 0x01;
} while (sb > k0 - 1 + msb - oddFlag);
patchNumSubbands[numPatches] = MAX(sb - usb, 0);
patchStartSubband[numPatches] = k0 - oddFlag - patchNumSubbands[numPatches];
/* from MPEG reference code - slightly different from spec */
if ((patchNumSubbands[numPatches] < 3) && (numPatches > 0))
break;
if (patchNumSubbands[numPatches] > 0) {
usb = sb;
msb = sb;
numPatches++;
} else {
msb = kStart;
}
if (freqMaster[k] - sb < 3)
k = nMaster;
} while (sb != (kStart + numQMFBands) && numPatches <= MAX_NUM_PATCHES);
return numPatches;
}
/**************************************************************************************
* Function: FindFreq
*
* Description: search buffer of unsigned chars for a specific value
*
* Inputs: buffer of elements to search
* number of elements to search
* value to search for
*
* Outputs: none
*
* Return: non-zero if the value is found anywhere in the buffer, zero otherwise
**************************************************************************************/
static int FindFreq(unsigned char *freq, int nFreq, unsigned char val)
{
int k;
for (k = 0; k < nFreq; k++) {
if (freq[k] == val)
return 1;
}
return 0;
}
/**************************************************************************************
* Function: RemoveFreq
*
* Description: remove one element from a buffer of unsigned chars
*
* Inputs: buffer of elements
* number of elements
* index of element to remove
*
* Outputs: new buffer of length nFreq-1
*
* Return: none
**************************************************************************************/
static void RemoveFreq(unsigned char *freq, int nFreq, int removeIdx)
{
int k;
if (removeIdx >= nFreq)
return;
for (k = removeIdx; k < nFreq - 1; k++)
freq[k] = freq[k+1];
}
/**************************************************************************************
* Function: CalcFreqLimiter
*
* Description: calculate limiter frequency table (4.6.18.3.2.3)
*
* Inputs: number of subbands in each patch
* low resolution frequency table
* number of bands in low resolution frequency table
* index of starting QMF subband for SBR (kStart)
* number of limiter bands
* number of patches
*
* Outputs: limiter frequency table
*
* Return: number of bands in limiter frequency table
**************************************************************************************/
static int CalcFreqLimiter(unsigned char *freqLimiter, unsigned char *patchNumSubbands, unsigned char *freqLow,
int nLow, int kStart, int limiterBands, int numPatches)
{
int k, bands, nLimiter, nOctaves;
int limBandsPerOctave[3] = {120, 200, 300}; /* [1.2, 2.0, 3.0] * 100 */
unsigned char patchBorders[MAX_NUM_PATCHES + 1];
/* simple case */
if (limiterBands == 0) {
freqLimiter[0] = freqLow[0] - kStart;
freqLimiter[1] = freqLow[nLow] - kStart;
return 1;
}
bands = limBandsPerOctave[limiterBands - 1];
patchBorders[0] = kStart;
/* from MPEG reference code - slightly different from spec (top border) */
for (k = 1; k < numPatches; k++)
patchBorders[k] = patchBorders[k-1] + patchNumSubbands[k-1];
patchBorders[k] = freqLow[nLow];
for (k = 0; k <= nLow; k++)
freqLimiter[k] = freqLow[k];
for (k = 1; k < numPatches; k++)
freqLimiter[k+nLow] = patchBorders[k];
k = 1;
nLimiter = nLow + numPatches - 1;
BubbleSort(freqLimiter, nLimiter + 1);
while (k <= nLimiter) {
nOctaves = log2Tab[freqLimiter[k]] - log2Tab[freqLimiter[k-1]]; /* Q28 */
nOctaves = (nOctaves >> 9) * bands; /* Q19, max bands = 300 < 2^9 */
if (nOctaves < (49 << 19)) { /* compare with 0.49*100, in Q19 */
if (freqLimiter[k] == freqLimiter[k-1] || FindFreq(patchBorders, numPatches + 1, freqLimiter[k]) == 0) {
RemoveFreq(freqLimiter, nLimiter + 1, k);
nLimiter--;
} else if (FindFreq(patchBorders, numPatches + 1, freqLimiter[k-1]) == 0) {
RemoveFreq(freqLimiter, nLimiter + 1, k-1);
nLimiter--;
} else {
k++;
}
} else {
k++;
}
}
/* store limiter boundaries as offsets from kStart */
for (k = 0; k <= nLimiter; k++)
freqLimiter[k] -= kStart;
return nLimiter;
}
/**************************************************************************************
* Function: CalcFreqTables
*
* Description: calulate master and derived frequency tables, and patches
*
* Inputs: initialized SBRHeader struct for this SCE/CPE block
* initialized SBRFreq struct for this SCE/CPE block
* sample rate index of output sample rate (after SBR)
*
* Outputs: master and derived frequency tables, and patches
*
* Return: non-zero if error, zero otherwise
**************************************************************************************/
int CalcFreqTables(SBRHeader *sbrHdr, SBRFreq *sbrFreq, int sampRateIdx)
{
int k0, k2;
k0 = k0Tab[sampRateIdx][sbrHdr->startFreq];
if (sbrHdr->stopFreq == 14)
k2 = 2*k0;
else if (sbrHdr->stopFreq == 15)
k2 = 3*k0;
else
k2 = k2Tab[sampRateIdx][sbrHdr->stopFreq];
if (k2 > 64)
k2 = 64;
/* calculate master frequency table */
if (sbrHdr->freqScale == 0)
sbrFreq->nMaster = CalcFreqMasterScaleZero(sbrFreq->freqMaster, sbrHdr->alterScale, k0, k2);
else
sbrFreq->nMaster = CalcFreqMaster(sbrFreq->freqMaster, sbrHdr->freqScale, sbrHdr->alterScale, k0, k2);
/* calculate high frequency table and related parameters */
sbrFreq->nHigh = CalcFreqHigh(sbrFreq->freqHigh, sbrFreq->freqMaster, sbrFreq->nMaster, sbrHdr->crossOverBand);
sbrFreq->numQMFBands = sbrFreq->freqHigh[sbrFreq->nHigh] - sbrFreq->freqHigh[0];
sbrFreq->kStart = sbrFreq->freqHigh[0];
/* calculate low frequency table */
sbrFreq->nLow = CalcFreqLow(sbrFreq->freqLow, sbrFreq->freqHigh, sbrFreq->nHigh);
/* calculate noise floor frequency table */
sbrFreq->numNoiseFloorBands = CalcFreqNoise(sbrFreq->freqNoise, sbrFreq->freqLow, sbrFreq->nLow, sbrFreq->kStart, k2, sbrHdr->noiseBands);
/* calculate limiter table */
sbrFreq->numPatches = BuildPatches(sbrFreq->patchNumSubbands, sbrFreq->patchStartSubband, sbrFreq->freqMaster,
sbrFreq->nMaster, k0, sbrFreq->kStart, sbrFreq->numQMFBands, sampRateIdx);
sbrFreq->nLimiter = CalcFreqLimiter(sbrFreq->freqLimiter, sbrFreq->patchNumSubbands, sbrFreq->freqLow, sbrFreq->nLow, sbrFreq->kStart,
sbrHdr->limiterBands, sbrFreq->numPatches);
return 0;
}

View File

@@ -0,0 +1,853 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: sbrhfadj.c,v 1.3 2005/05/24 16:01:55 albertofloyd Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* sbrhfadj.c - high frequency adjustment for SBR
**************************************************************************************/
#include "sbr.h"
#include "assembly.h"
/* invBandTab[i] = 1.0 / (i + 1), Q31 */
static const int invBandTab[64] PROGMEM = {
0x7fffffff, 0x40000000, 0x2aaaaaab, 0x20000000, 0x1999999a, 0x15555555, 0x12492492, 0x10000000,
0x0e38e38e, 0x0ccccccd, 0x0ba2e8ba, 0x0aaaaaab, 0x09d89d8a, 0x09249249, 0x08888889, 0x08000000,
0x07878788, 0x071c71c7, 0x06bca1af, 0x06666666, 0x06186186, 0x05d1745d, 0x0590b216, 0x05555555,
0x051eb852, 0x04ec4ec5, 0x04bda12f, 0x04924925, 0x0469ee58, 0x04444444, 0x04210842, 0x04000000,
0x03e0f83e, 0x03c3c3c4, 0x03a83a84, 0x038e38e4, 0x03759f23, 0x035e50d8, 0x03483483, 0x03333333,
0x031f3832, 0x030c30c3, 0x02fa0be8, 0x02e8ba2f, 0x02d82d83, 0x02c8590b, 0x02b93105, 0x02aaaaab,
0x029cbc15, 0x028f5c29, 0x02828283, 0x02762762, 0x026a439f, 0x025ed098, 0x0253c825, 0x02492492,
0x023ee090, 0x0234f72c, 0x022b63cc, 0x02222222, 0x02192e2a, 0x02108421, 0x02082082, 0x02000000,
};
/**************************************************************************************
* Function: EstimateEnvelope
*
* Description: estimate power of generated HF QMF bands in one time-domain envelope
* (4.6.18.7.3)
*
* Inputs: initialized PSInfoSBR struct
* initialized SBRHeader struct for this SCE/CPE block
* initialized SBRGrid struct for this channel
* initialized SBRFreq struct for this SCE/CPE block
* index of current envelope
*
* Outputs: power of each QMF subband, stored as integer (Q0) * 2^N, N >= 0
*
* Return: none
**************************************************************************************/
static void EstimateEnvelope(PSInfoSBR *psi, SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, int env)
{
int i, m, iStart, iEnd, xre, xim, nScale, expMax;
int p, n, mStart, mEnd, invFact, t;
int *XBuf;
U64 eCurr;
unsigned char *freqBandTab;
/* estimate current envelope */
iStart = sbrGrid->envTimeBorder[env] + HF_ADJ;
iEnd = sbrGrid->envTimeBorder[env+1] + HF_ADJ;
if (sbrGrid->freqRes[env]) {
n = sbrFreq->nHigh;
freqBandTab = sbrFreq->freqHigh;
} else {
n = sbrFreq->nLow;
freqBandTab = sbrFreq->freqLow;
}
/* ADS should inline MADD64 (smlal) properly, but check to make sure */
expMax = 0;
if (sbrHdr->interpFreq) {
for (m = 0; m < sbrFreq->numQMFBands; m++) {
eCurr.w64 = 0;
XBuf = psi->XBuf[iStart][sbrFreq->kStart + m];
for (i = iStart; i < iEnd; i++) {
/* scale to int before calculating power (precision not critical, and avoids overflow) */
xre = (*XBuf) >> FBITS_OUT_QMFA; XBuf += 1;
xim = (*XBuf) >> FBITS_OUT_QMFA; XBuf += (2*64 - 1);
eCurr.w64 = MADD64(eCurr.w64, xre, xre);
eCurr.w64 = MADD64(eCurr.w64, xim, xim);
}
/* eCurr.w64 is now Q(64 - 2*FBITS_OUT_QMFA) (64-bit word)
* if energy is too big to fit in 32-bit word (> 2^31) scale down by power of 2
*/
nScale = 0;
if (eCurr.r.hi32) {
nScale = (32 - CLZ(eCurr.r.hi32)) + 1;
t = (int)(eCurr.r.lo32 >> nScale); /* logical (unsigned) >> */
t |= eCurr.r.hi32 << (32 - nScale);
} else if (eCurr.r.lo32 >> 31) {
nScale = 1;
t = (int)(eCurr.r.lo32 >> nScale); /* logical (unsigned) >> */
} else {
t = (int)eCurr.r.lo32;
}
invFact = invBandTab[(iEnd - iStart)-1];
psi->eCurr[m] = MULSHIFT32(t, invFact);
psi->eCurrExp[m] = nScale + 1; /* +1 for invFact = Q31 */
if (psi->eCurrExp[m] > expMax)
expMax = psi->eCurrExp[m];
}
} else {
for (p = 0; p < n; p++) {
mStart = freqBandTab[p];
mEnd = freqBandTab[p+1];
eCurr.w64 = 0;
for (i = iStart; i < iEnd; i++) {
XBuf = psi->XBuf[i][mStart];
for (m = mStart; m < mEnd; m++) {
xre = (*XBuf++) >> FBITS_OUT_QMFA;
xim = (*XBuf++) >> FBITS_OUT_QMFA;
eCurr.w64 = MADD64(eCurr.w64, xre, xre);
eCurr.w64 = MADD64(eCurr.w64, xim, xim);
}
}
nScale = 0;
if (eCurr.r.hi32) {
nScale = (32 - CLZ(eCurr.r.hi32)) + 1;
t = (int)(eCurr.r.lo32 >> nScale); /* logical (unsigned) >> */
t |= eCurr.r.hi32 << (32 - nScale);
} else if (eCurr.r.lo32 >> 31) {
nScale = 1;
t = (int)(eCurr.r.lo32 >> nScale); /* logical (unsigned) >> */
} else {
t = (int)eCurr.r.lo32;
}
invFact = invBandTab[(iEnd - iStart)-1];
invFact = MULSHIFT32(invBandTab[(mEnd - mStart)-1], invFact) << 1;
t = MULSHIFT32(t, invFact);
for (m = mStart; m < mEnd; m++) {
psi->eCurr[m - sbrFreq->kStart] = t;
psi->eCurrExp[m - sbrFreq->kStart] = nScale + 1; /* +1 for invFact = Q31 */
}
if (psi->eCurrExp[mStart - sbrFreq->kStart] > expMax)
expMax = psi->eCurrExp[mStart - sbrFreq->kStart];
}
}
psi->eCurrExpMax = expMax;
}
/**************************************************************************************
* Function: GetSMapped
*
* Description: calculate SMapped (4.6.18.7.2)
*
* Inputs: initialized PSInfoSBR struct
* initialized SBRGrid struct for this channel
* initialized SBRFreq struct for this SCE/CPE block
* initialized SBRChan struct for this channel
* index of current envelope
* index of current QMF band
* la flag for this envelope
*
* Outputs: none
*
* Return: 1 if a sinusoid is present in this band, 0 if not
**************************************************************************************/
static int GetSMapped(SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int env, int band, int la)
{
int bandStart, bandEnd, oddFlag, r;
if (sbrGrid->freqRes[env]) {
/* high resolution */
bandStart = band;
bandEnd = band+1;
} else {
/* low resolution (see CalcFreqLow() for mapping) */
oddFlag = sbrFreq->nHigh & 0x01;
bandStart = (band > 0 ? 2*band - oddFlag : 0); /* starting index for freqLow[band] */
bandEnd = 2*(band+1) - oddFlag; /* ending index for freqLow[band+1] */
}
/* sMapped = 1 if sIndexMapped == 1 for any frequency in this band */
for (band = bandStart; band < bandEnd; band++) {
if (sbrChan->addHarmonic[1][band]) {
r = ((sbrFreq->freqHigh[band+1] + sbrFreq->freqHigh[band]) >> 1);
if (env >= la || sbrChan->addHarmonic[0][r] == 1)
return 1;
}
}
return 0;
}
#define GBOOST_MAX 0x2830afd3 /* Q28, 1.584893192 squared */
#define ACC_SCALE 6
/* squared version of table in 4.6.18.7.5 */
static const int limGainTab[4] PROGMEM = {0x20138ca7, 0x40000000, 0x7fb27dce, 0x80000000}; /* Q30 (0x80000000 = sentinel for GMAX) */
/**************************************************************************************
* Function: CalcMaxGain
*
* Description: calculate max gain in one limiter band (4.6.18.7.5)
*
* Inputs: initialized PSInfoSBR struct
* initialized SBRHeader struct for this SCE/CPE block
* initialized SBRGrid struct for this channel
* initialized SBRFreq struct for this SCE/CPE block
* index of current channel (0 for SCE, 0 or 1 for CPE)
* index of current envelope
* index of current limiter band
* number of fraction bits in dequantized envelope
* (max = Q(FBITS_OUT_DQ_ENV - 6) = Q23, can go negative)
*
* Outputs: updated gainMax, gainMaxFBits, and sumEOrigMapped in PSInfoSBR struct
*
* Return: none
**************************************************************************************/
static void CalcMaxGain(PSInfoSBR *psi, SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, int ch, int env, int lim, int fbitsDQ)
{
int m, mStart, mEnd, q, z, r;
int sumEOrigMapped, sumECurr, gainMax, eOMGainMax, envBand;
unsigned char eCurrExpMax;
unsigned char *freqBandTab;
mStart = sbrFreq->freqLimiter[lim]; /* these are offsets from kStart */
mEnd = sbrFreq->freqLimiter[lim + 1];
freqBandTab = (sbrGrid->freqRes[env] ? sbrFreq->freqHigh : sbrFreq->freqLow);
/* calculate max gain to apply to signal in this limiter band */
sumECurr = 0;
sumEOrigMapped = 0;
eCurrExpMax = psi->eCurrExpMax;
eOMGainMax = psi->eOMGainMax;
envBand = psi->envBand;
for (m = mStart; m < mEnd; m++) {
/* map current QMF band to appropriate envelope band */
if (m == freqBandTab[envBand + 1] - sbrFreq->kStart) {
envBand++;
eOMGainMax = psi->envDataDequant[ch][env][envBand] >> ACC_SCALE; /* summing max 48 bands */
}
sumEOrigMapped += eOMGainMax;
/* easy test for overflow on ARM */
sumECurr += (psi->eCurr[m] >> (eCurrExpMax - psi->eCurrExp[m]));
if (sumECurr >> 30) {
sumECurr >>= 1;
eCurrExpMax++;
}
}
psi->eOMGainMax = eOMGainMax;
psi->envBand = envBand;
psi->gainMaxFBits = 30; /* Q30 tables */
if (sumECurr == 0) {
/* any non-zero numerator * 1/EPS_0 is > G_MAX */
gainMax = (sumEOrigMapped == 0 ? (int)limGainTab[sbrHdr->limiterGains] : (int)0x80000000);
} else if (sumEOrigMapped == 0) {
/* 1/(any non-zero denominator) * EPS_0 * limGainTab[x] is appx. 0 */
gainMax = 0;
} else {
/* sumEOrigMapped = Q(fbitsDQ - ACC_SCALE), sumECurr = Q(-eCurrExpMax) */
gainMax = limGainTab[sbrHdr->limiterGains];
if (sbrHdr->limiterGains != 3) {
q = MULSHIFT32(sumEOrigMapped, gainMax); /* Q(fbitsDQ - ACC_SCALE - 2), gainMax = Q30 */
z = CLZ(sumECurr) - 1;
r = InvRNormalized(sumECurr << z); /* in = Q(z - eCurrExpMax), out = Q(29 + 31 - z + eCurrExpMax) */
gainMax = MULSHIFT32(q, r); /* Q(29 + 31 - z + eCurrExpMax + fbitsDQ - ACC_SCALE - 2 - 32) */
psi->gainMaxFBits = 26 - z + eCurrExpMax + fbitsDQ - ACC_SCALE;
}
}
psi->sumEOrigMapped = sumEOrigMapped;
psi->gainMax = gainMax;
}
/**************************************************************************************
* Function: CalcNoiseDivFactors
*
* Description: calculate 1/(1+Q) and Q/(1+Q) (4.6.18.7.4; 4.6.18.7.5)
*
* Inputs: dequantized noise floor scalefactor
*
* Outputs: 1/(1+Q) and Q/(1+Q), format = Q31
*
* Return: none
**************************************************************************************/
static void CalcNoiseDivFactors(int q, int *qp1Inv, int *qqp1Inv)
{
int z, qp1, t, s;
/* 1 + Q_orig */
qp1 = (q >> 1);
qp1 += (1 << (FBITS_OUT_DQ_NOISE - 1)); /* >> 1 to avoid overflow when adding 1.0 */
z = CLZ(qp1) - 1; /* z <= 31 - FBITS_OUT_DQ_NOISE */
qp1 <<= z; /* Q(FBITS_OUT_DQ_NOISE + z) = Q31 * 2^-(31 - (FBITS_OUT_DQ_NOISE + z)) */
t = InvRNormalized(qp1) << 1; /* Q30 * 2^(31 - (FBITS_OUT_DQ_NOISE + z)), guaranteed not to overflow */
/* normalize to Q31 */
s = (31 - (FBITS_OUT_DQ_NOISE - 1) - z - 1); /* clearly z >= 0, z <= (30 - (FBITS_OUT_DQ_NOISE - 1)) */
*qp1Inv = (t >> s); /* s = [0, 31 - FBITS_OUT_DQ_NOISE] */
*qqp1Inv = MULSHIFT32(t, q) << (32 - FBITS_OUT_DQ_NOISE - s);
}
/**************************************************************************************
* Function: CalcComponentGains
*
* Description: calculate gain of envelope, sinusoids, and noise in one limiter band
* (4.6.18.7.5)
*
* Inputs: initialized PSInfoSBR struct
* initialized SBRHeader struct for this SCE/CPE block
* initialized SBRGrid struct for this channel
* initialized SBRFreq struct for this SCE/CPE block
* initialized SBRChan struct for this channel
* index of current channel (0 for SCE, 0 or 1 for CPE)
* index of current envelope
* index of current limiter band
* number of fraction bits in dequantized envelope
*
* Outputs: gains for envelope, sinusoids and noise
* number of fraction bits for envelope gain
* sum of the total gain for each component in this band
* other updated state variables
*
* Return: none
**************************************************************************************/
static void CalcComponentGains(PSInfoSBR *psi, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int ch, int env, int lim, int fbitsDQ)
{
int d, m, mStart, mEnd, q, qm, noiseFloor, sIndexMapped;
int shift, eCurr, maxFlag, gainMax, gainMaxFBits;
int gain, sm, z, r, fbitsGain, gainScale;
unsigned char *freqBandTab;
mStart = sbrFreq->freqLimiter[lim]; /* these are offsets from kStart */
mEnd = sbrFreq->freqLimiter[lim + 1];
gainMax = psi->gainMax;
gainMaxFBits = psi->gainMaxFBits;
d = (env == psi->la || env == sbrChan->laPrev ? 0 : 1);
freqBandTab = (sbrGrid->freqRes[env] ? sbrFreq->freqHigh : sbrFreq->freqLow);
/* figure out which noise floor this envelope is in (only 1 or 2 noise floors allowed) */
noiseFloor = 0;
if (sbrGrid->numNoiseFloors == 2 && sbrGrid->noiseTimeBorder[1] <= sbrGrid->envTimeBorder[env])
noiseFloor++;
psi->sumECurrGLim = 0;
psi->sumSM = 0;
psi->sumQM = 0;
/* calculate energy of noise to add in this limiter band */
for (m = mStart; m < mEnd; m++) {
if (m == sbrFreq->freqNoise[psi->noiseFloorBand + 1] - sbrFreq->kStart) {
/* map current QMF band to appropriate noise floor band (NOTE: freqLimiter[0] == freqLow[0] = freqHigh[0]) */
psi->noiseFloorBand++;
CalcNoiseDivFactors(psi->noiseDataDequant[ch][noiseFloor][psi->noiseFloorBand], &(psi->qp1Inv), &(psi->qqp1Inv));
}
if (m == sbrFreq->freqHigh[psi->highBand + 1] - sbrFreq->kStart)
psi->highBand++;
if (m == freqBandTab[psi->sBand + 1] - sbrFreq->kStart) {
psi->sBand++;
psi->sMapped = GetSMapped(sbrGrid, sbrFreq, sbrChan, env, psi->sBand, psi->la);
}
/* get sIndexMapped for this QMF subband */
sIndexMapped = 0;
r = ((sbrFreq->freqHigh[psi->highBand+1] + sbrFreq->freqHigh[psi->highBand]) >> 1);
if (m + sbrFreq->kStart == r) {
/* r = center frequency, deltaStep = (env >= la || sIndexMapped'(r, numEnv'-1) == 1) */
if (env >= psi->la || sbrChan->addHarmonic[0][r] == 1)
sIndexMapped = sbrChan->addHarmonic[1][psi->highBand];
}
/* save sine flags from last envelope in this frame:
* addHarmonic[0][0...63] = saved sine present flag from previous frame, for each QMF subband
* addHarmonic[1][0...nHigh-1] = addHarmonic bit from current frame, for each high-res frequency band
* from MPEG reference code - slightly different from spec
* (sIndexMapped'(m,LE'-1) can still be 0 when numEnv == psi->la)
*/
if (env == sbrGrid->numEnv - 1) {
if (m + sbrFreq->kStart == r)
sbrChan->addHarmonic[0][m + sbrFreq->kStart] = sbrChan->addHarmonic[1][psi->highBand];
else
sbrChan->addHarmonic[0][m + sbrFreq->kStart] = 0;
}
gain = psi->envDataDequant[ch][env][psi->sBand];
qm = MULSHIFT32(gain, psi->qqp1Inv) << 1;
sm = (sIndexMapped ? MULSHIFT32(gain, psi->qp1Inv) << 1 : 0);
/* three cases: (sMapped == 0 && delta == 1), (sMapped == 0 && delta == 0), (sMapped == 1) */
if (d == 1 && psi->sMapped == 0)
gain = MULSHIFT32(psi->qp1Inv, gain) << 1;
else if (psi->sMapped != 0)
gain = MULSHIFT32(psi->qqp1Inv, gain) << 1;
/* gain, qm, sm = Q(fbitsDQ), gainMax = Q(fbitsGainMax) */
eCurr = psi->eCurr[m];
if (eCurr) {
z = CLZ(eCurr) - 1;
r = InvRNormalized(eCurr << z); /* in = Q(z - eCurrExp), out = Q(29 + 31 - z + eCurrExp) */
gainScale = MULSHIFT32(gain, r); /* out = Q(29 + 31 - z + eCurrExp + fbitsDQ - 32) */
fbitsGain = 29 + 31 - z + psi->eCurrExp[m] + fbitsDQ - 32;
} else {
/* if eCurr == 0, then gain is unchanged (divide by EPS = 1) */
gainScale = gain;
fbitsGain = fbitsDQ;
}
/* see if gain for this band exceeds max gain */
maxFlag = 0;
if (gainMax != (int)0x80000000) {
if (fbitsGain >= gainMaxFBits) {
shift = MIN(fbitsGain - gainMaxFBits, 31);
maxFlag = ((gainScale >> shift) > gainMax ? 1 : 0);
} else {
shift = MIN(gainMaxFBits - fbitsGain, 31);
maxFlag = (gainScale > (gainMax >> shift) ? 1 : 0);
}
}
if (maxFlag) {
/* gainScale > gainMax, calculate ratio with 32/16 division */
q = 0;
r = gainScale; /* guaranteed > 0, else maxFlag could not have been set */
z = CLZ(r);
if (z < 16) {
q = 16 - z;
r >>= q; /* out = Q(fbitsGain - q) */
}
z = CLZ(gainMax) - 1;
r = (gainMax << z) / r; /* out = Q((fbitsGainMax + z) - (fbitsGain - q)) */
q = (gainMaxFBits + z) - (fbitsGain - q); /* r = Q(q) */
if (q > 30) {
r >>= MIN(q - 30, 31);
} else {
z = MIN(30 - q, 30);
CLIP_2N_SHIFT30(r, z); /* let r = Q30 since range = [0.0, 1.0) (clip to 0x3fffffff = 0.99999) */
}
qm = MULSHIFT32(qm, r) << 2;
gain = MULSHIFT32(gain, r) << 2;
psi->gLimBuf[m] = gainMax;
psi->gLimFbits[m] = gainMaxFBits;
} else {
psi->gLimBuf[m] = gainScale;
psi->gLimFbits[m] = fbitsGain;
}
/* sumSM, sumQM, sumECurrGLim = Q(fbitsDQ - ACC_SCALE) */
psi->smBuf[m] = sm;
psi->sumSM += (sm >> ACC_SCALE);
psi->qmLimBuf[m] = qm;
if (env != psi->la && env != sbrChan->laPrev && sm == 0)
psi->sumQM += (qm >> ACC_SCALE);
/* eCurr * gain^2 same as gain^2, before division by eCurr
* (but note that gain != 0 even if eCurr == 0, since it's divided by eps)
*/
if (eCurr)
psi->sumECurrGLim += (gain >> ACC_SCALE);
}
}
/**************************************************************************************
* Function: ApplyBoost
*
* Description: calculate and apply boost factor for envelope, sinusoids, and noise
* in this limiter band (4.6.18.7.5)
*
* Inputs: initialized PSInfoSBR struct
* initialized SBRFreq struct for this SCE/CPE block
* index of current limiter band
* number of fraction bits in dequantized envelope
*
* Outputs: envelope gain, sinusoids and noise after scaling by gBoost
* format = Q(FBITS_GLIM_BOOST) for envelope gain,
* = Q(FBITS_QLIM_BOOST) for noise
* = Q(FBITS_OUT_QMFA) for sinusoids
*
* Return: none
*
* Notes: after scaling, each component has at least 1 GB
**************************************************************************************/
static void ApplyBoost(PSInfoSBR *psi, SBRFreq *sbrFreq, int lim, int fbitsDQ)
{
int m, mStart, mEnd, q, z, r;
int sumEOrigMapped, gBoost;
mStart = sbrFreq->freqLimiter[lim]; /* these are offsets from kStart */
mEnd = sbrFreq->freqLimiter[lim + 1];
sumEOrigMapped = psi->sumEOrigMapped >> 1;
r = (psi->sumECurrGLim >> 1) + (psi->sumSM >> 1) + (psi->sumQM >> 1); /* 1 GB fine (sm and qm are mutually exclusive in acc) */
if (r < (1 << (31-28))) {
/* any non-zero numerator * 1/EPS_0 is > GBOOST_MAX
* round very small r to zero to avoid scaling problems
*/
gBoost = (sumEOrigMapped == 0 ? (1 << 28) : GBOOST_MAX);
z = 0;
} else if (sumEOrigMapped == 0) {
/* 1/(any non-zero denominator) * EPS_0 is appx. 0 */
gBoost = 0;
z = 0;
} else {
/* numerator (sumEOrigMapped) and denominator (r) have same Q format (before << z) */
z = CLZ(r) - 1; /* z = [0, 27] */
r = InvRNormalized(r << z);
gBoost = MULSHIFT32(sumEOrigMapped, r);
}
/* gBoost = Q(28 - z) */
if (gBoost > (GBOOST_MAX >> z)) {
gBoost = GBOOST_MAX;
z = 0;
}
gBoost <<= z; /* gBoost = Q28, minimum 1 GB */
/* convert gain, noise, sinusoids to fixed Q format, clipping if necessary
* (rare, usually only happens at very low bitrates, introduces slight
* distortion into final HF mapping, but should be inaudible)
*/
for (m = mStart; m < mEnd; m++) {
/* let gLimBoost = Q24, since in practice the max values are usually 16 to 20
* unless limiterGains == 3 (limiter off) and eCurr ~= 0 (i.e. huge gain, but only
* because the envelope has 0 power anyway)
*/
q = MULSHIFT32(psi->gLimBuf[m], gBoost) << 2; /* Q(gLimFbits) * Q(28) --> Q(gLimFbits[m]-2) */
r = SqrtFix(q, psi->gLimFbits[m] - 2, &z);
z -= FBITS_GLIM_BOOST;
if (z >= 0) {
psi->gLimBoost[m] = r >> MIN(z, 31);
} else {
z = MIN(30, -z);
CLIP_2N_SHIFT30(r, z);
psi->gLimBoost[m] = r;
}
q = MULSHIFT32(psi->qmLimBuf[m], gBoost) << 2; /* Q(fbitsDQ) * Q(28) --> Q(fbitsDQ-2) */
r = SqrtFix(q, fbitsDQ - 2, &z);
z -= FBITS_QLIM_BOOST; /* << by 14, since integer sqrt of x < 2^16, and we want to leave 1 GB */
if (z >= 0) {
psi->qmLimBoost[m] = r >> MIN(31, z);
} else {
z = MIN(30, -z);
CLIP_2N_SHIFT30(r, z);
psi->qmLimBoost[m] = r;
}
q = MULSHIFT32(psi->smBuf[m], gBoost) << 2; /* Q(fbitsDQ) * Q(28) --> Q(fbitsDQ-2) */
r = SqrtFix(q, fbitsDQ - 2, &z);
z -= FBITS_OUT_QMFA; /* justify for adding to signal (xBuf) later */
if (z >= 0) {
psi->smBoost[m] = r >> MIN(31, z);
} else {
z = MIN(30, -z);
CLIP_2N_SHIFT30(r, z);
psi->smBoost[m] = r;
}
}
}
/**************************************************************************************
* Function: CalcGain
*
* Description: calculate and apply proper gain to HF components in one envelope
* (4.6.18.7.5)
*
* Inputs: initialized PSInfoSBR struct
* initialized SBRHeader struct for this SCE/CPE block
* initialized SBRGrid struct for this channel
* initialized SBRFreq struct for this SCE/CPE block
* initialized SBRChan struct for this channel
* index of current channel (0 for SCE, 0 or 1 for CPE)
* index of current envelope
*
* Outputs: envelope gain, sinusoids and noise after scaling
*
* Return: none
**************************************************************************************/
static void CalcGain(PSInfoSBR *psi, SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int ch, int env)
{
int lim, fbitsDQ;
/* initialize to -1 so that mapping limiter bands to env/noise bands works right on first pass */
psi->envBand = -1;
psi->noiseFloorBand = -1;
psi->sBand = -1;
psi->highBand = -1;
fbitsDQ = (FBITS_OUT_DQ_ENV - psi->envDataDequantScale[ch][env]); /* Q(29 - optional scalefactor) */
for (lim = 0; lim < sbrFreq->nLimiter; lim++) {
/* the QMF bands are divided into lim regions (consecutive, non-overlapping) */
CalcMaxGain(psi, sbrHdr, sbrGrid, sbrFreq, ch, env, lim, fbitsDQ);
CalcComponentGains(psi, sbrGrid, sbrFreq, sbrChan, ch, env, lim, fbitsDQ);
ApplyBoost(psi, sbrFreq, lim, fbitsDQ);
}
}
/* hSmooth table from 4.7.18.7.6, format = Q31 */
static const int hSmoothCoef[MAX_NUM_SMOOTH_COEFS] PROGMEM = {
0x2aaaaaab, 0x2697a512, 0x1becfa68, 0x0ebdb043, 0x04130598,
};
/**************************************************************************************
* Function: MapHF
*
* Description: map HF components to proper QMF bands, with optional gain smoothing
* filter (4.6.18.7.6)
*
* Inputs: initialized PSInfoSBR struct
* initialized SBRHeader struct for this SCE/CPE block
* initialized SBRGrid struct for this channel
* initialized SBRFreq struct for this SCE/CPE block
* initialized SBRChan struct for this channel
* index of current envelope
* reset flag (can be non-zero for first envelope only)
*
* Outputs: complete reconstructed subband QMF samples for this envelope
*
* Return: none
*
* Notes: ensures that output has >= MIN_GBITS_IN_QMFS guard bits,
* so it's not necessary to check anything in the synth QMF
**************************************************************************************/
static void MapHF(PSInfoSBR *psi, SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int env, int hfReset)
{
int noiseTabIndex, sinIndex, gainNoiseIndex, hSL;
int i, iStart, iEnd, m, idx, j, s, n, smre, smim;
int gFilt, qFilt, xre, xim, gbMask, gbIdx;
int *XBuf;
noiseTabIndex = sbrChan->noiseTabIndex;
sinIndex = sbrChan->sinIndex;
gainNoiseIndex = sbrChan->gainNoiseIndex; /* oldest entries in filter delay buffer */
if (hfReset)
noiseTabIndex = 2; /* starts at 1, double since complex */
hSL = (sbrHdr->smoothMode ? 0 : 4);
if (hfReset) {
for (i = 0; i < hSL; i++) {
for (m = 0; m < sbrFreq->numQMFBands; m++) {
sbrChan->gTemp[gainNoiseIndex][m] = psi->gLimBoost[m];
sbrChan->qTemp[gainNoiseIndex][m] = psi->qmLimBoost[m];
}
gainNoiseIndex++;
if (gainNoiseIndex == MAX_NUM_SMOOTH_COEFS)
gainNoiseIndex = 0;
}
ASSERT(env == 0); /* should only be reset when env == 0 */
}
iStart = sbrGrid->envTimeBorder[env];
iEnd = sbrGrid->envTimeBorder[env+1];
for (i = iStart; i < iEnd; i++) {
/* save new values in temp buffers (delay)
* we only store MAX_NUM_SMOOTH_COEFS most recent values,
* so don't keep storing the same value over and over
*/
if (i - iStart < MAX_NUM_SMOOTH_COEFS) {
for (m = 0; m < sbrFreq->numQMFBands; m++) {
sbrChan->gTemp[gainNoiseIndex][m] = psi->gLimBoost[m];
sbrChan->qTemp[gainNoiseIndex][m] = psi->qmLimBoost[m];
}
}
/* see 4.6.18.7.6 */
XBuf = psi->XBuf[i + HF_ADJ][sbrFreq->kStart];
gbMask = 0;
for (m = 0; m < sbrFreq->numQMFBands; m++) {
if (env == psi->la || env == sbrChan->laPrev) {
/* no smoothing filter for gain, and qFilt = 0 (only need to do once) */
if (i == iStart) {
psi->gFiltLast[m] = sbrChan->gTemp[gainNoiseIndex][m];
psi->qFiltLast[m] = 0;
}
} else if (hSL == 0) {
/* no smoothing filter for gain, (only need to do once) */
if (i == iStart) {
psi->gFiltLast[m] = sbrChan->gTemp[gainNoiseIndex][m];
psi->qFiltLast[m] = sbrChan->qTemp[gainNoiseIndex][m];
}
} else {
/* apply smoothing filter to gain and noise (after MAX_NUM_SMOOTH_COEFS, it's always the same) */
if (i - iStart < MAX_NUM_SMOOTH_COEFS) {
gFilt = 0;
qFilt = 0;
idx = gainNoiseIndex;
for (j = 0; j < MAX_NUM_SMOOTH_COEFS; j++) {
/* sum(abs(hSmoothCoef[j])) for all j < 1.0 */
gFilt += MULSHIFT32(sbrChan->gTemp[idx][m], hSmoothCoef[j]);
qFilt += MULSHIFT32(sbrChan->qTemp[idx][m], hSmoothCoef[j]);
idx--;
if (idx < 0)
idx += MAX_NUM_SMOOTH_COEFS;
}
psi->gFiltLast[m] = gFilt << 1; /* restore to Q(FBITS_GLIM_BOOST) (gain of filter < 1.0, so no overflow) */
psi->qFiltLast[m] = qFilt << 1; /* restore to Q(FBITS_QLIM_BOOST) */
}
}
if (psi->smBoost[m] != 0) {
/* add scaled signal and sinusoid, don't add noise (qFilt = 0) */
smre = psi->smBoost[m];
smim = smre;
/* sinIndex: [0] xre += sm [1] xim += sm*s [2] xre -= sm [3] xim -= sm*s */
s = (sinIndex >> 1); /* if 2 or 3, flip sign to subtract sm */
s <<= 31;
smre ^= (s >> 31);
smre -= (s >> 31);
s ^= ((m + sbrFreq->kStart) << 31);
smim ^= (s >> 31);
smim -= (s >> 31);
/* if sinIndex == 0 or 2, smim = 0; if sinIndex == 1 or 3, smre = 0 */
s = sinIndex << 31;
smim &= (s >> 31);
s ^= 0x80000000;
smre &= (s >> 31);
noiseTabIndex += 2; /* noise filtered by 0, but still need to bump index */
} else {
/* add scaled signal and scaled noise */
qFilt = psi->qFiltLast[m];
n = noiseTab[noiseTabIndex++];
smre = MULSHIFT32(n, qFilt) >> (FBITS_QLIM_BOOST - 1 - FBITS_OUT_QMFA);
n = noiseTab[noiseTabIndex++];
smim = MULSHIFT32(n, qFilt) >> (FBITS_QLIM_BOOST - 1 - FBITS_OUT_QMFA);
}
noiseTabIndex &= 1023; /* 512 complex numbers */
gFilt = psi->gFiltLast[m];
xre = MULSHIFT32(gFilt, XBuf[0]);
xim = MULSHIFT32(gFilt, XBuf[1]);
CLIP_2N_SHIFT30(xre, 32 - FBITS_GLIM_BOOST);
CLIP_2N_SHIFT30(xim, 32 - FBITS_GLIM_BOOST);
xre += smre; *XBuf++ = xre;
xim += smim; *XBuf++ = xim;
gbMask |= FASTABS(xre);
gbMask |= FASTABS(xim);
}
/* update circular buffer index */
gainNoiseIndex++;
if (gainNoiseIndex == MAX_NUM_SMOOTH_COEFS)
gainNoiseIndex = 0;
sinIndex++;
sinIndex &= 3;
/* ensure MIN_GBITS_IN_QMFS guard bits in output
* almost never occurs in practice, but checking here makes synth QMF logic very simple
*/
if (gbMask >> (31 - MIN_GBITS_IN_QMFS)) {
XBuf = psi->XBuf[i + HF_ADJ][sbrFreq->kStart];
for (m = 0; m < sbrFreq->numQMFBands; m++) {
xre = XBuf[0]; xim = XBuf[1];
CLIP_2N(xre, (31 - MIN_GBITS_IN_QMFS));
CLIP_2N(xim, (31 - MIN_GBITS_IN_QMFS));
*XBuf++ = xre; *XBuf++ = xim;
}
CLIP_2N(gbMask, (31 - MIN_GBITS_IN_QMFS));
}
gbIdx = ((i + HF_ADJ) >> 5) & 0x01;
sbrChan->gbMask[gbIdx] |= gbMask;
}
sbrChan->noiseTabIndex = noiseTabIndex;
sbrChan->sinIndex = sinIndex;
sbrChan->gainNoiseIndex = gainNoiseIndex;
}
/**************************************************************************************
* Function: AdjustHighFreq
*
* Description: adjust high frequencies and add noise and sinusoids (4.6.18.7)
*
* Inputs: initialized PSInfoSBR struct
* initialized SBRHeader struct for this SCE/CPE block
* initialized SBRGrid struct for this channel
* initialized SBRFreq struct for this SCE/CPE block
* initialized SBRChan struct for this channel
* index of current channel (0 for SCE, 0 or 1 for CPE)
*
* Outputs: complete reconstructed subband QMF samples for this channel
*
* Return: none
**************************************************************************************/
void AdjustHighFreq(PSInfoSBR *psi, SBRHeader *sbrHdr, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int ch)
{
int i, env, hfReset;
unsigned char frameClass, pointer;
frameClass = sbrGrid->frameClass;
pointer = sbrGrid->pointer;
/* derive la from table 4.159 */
if ((frameClass == SBR_GRID_FIXVAR || frameClass == SBR_GRID_VARVAR) && pointer > 0)
psi->la = sbrGrid->numEnv + 1 - pointer;
else if (frameClass == SBR_GRID_VARFIX && pointer > 1)
psi->la = pointer - 1;
else
psi->la = -1;
/* for each envelope, estimate gain and adjust SBR QMF bands */
hfReset = sbrChan->reset;
for (env = 0; env < sbrGrid->numEnv; env++) {
EstimateEnvelope(psi, sbrHdr, sbrGrid, sbrFreq, env);
CalcGain(psi, sbrHdr, sbrGrid, sbrFreq, sbrChan, ch, env);
MapHF(psi, sbrHdr, sbrGrid, sbrFreq, sbrChan, env, hfReset);
hfReset = 0; /* only set for first envelope after header reset */
}
/* set saved sine flags to 0 for QMF bands outside of current frequency range */
for (i = 0; i < sbrFreq->freqLimiter[0] + sbrFreq->kStart; i++)
sbrChan->addHarmonic[0][i] = 0;
for (i = sbrFreq->freqLimiter[sbrFreq->nLimiter] + sbrFreq->kStart; i < 64; i++)
sbrChan->addHarmonic[0][i] = 0;
sbrChan->addHarmonicFlag[0] = sbrChan->addHarmonicFlag[1];
/* save la for next frame */
if (psi->la == sbrGrid->numEnv)
sbrChan->laPrev = 0;
else
sbrChan->laPrev = -1;
}

View File

@@ -0,0 +1,616 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: sbrhfgen.c,v 1.2 2005/05/19 20:45:20 jrecker Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* sbrhfgen.c - high frequency generation for SBR
**************************************************************************************/
#include "sbr.h"
#include "assembly.h"
#define FBITS_LPCOEFS 29 /* Q29 for range of (-4, 4) */
#define MAG_16 (16 * (1 << (32 - (2*(32-FBITS_LPCOEFS))))) /* i.e. 16 in Q26 format */
#define RELAX_COEF 0x7ffff79c /* 1.0 / (1.0 + 1e-6), Q31 */
/* newBWTab[prev invfMode][curr invfMode], format = Q31 (table 4.158)
* sample file which uses all of these: al_sbr_sr_64_2_fsaac32.aac
*/
static const int newBWTab[4][4] PROGMEM = {
{0x00000000, 0x4ccccccd, 0x73333333, 0x7d70a3d7},
{0x4ccccccd, 0x60000000, 0x73333333, 0x7d70a3d7},
{0x00000000, 0x60000000, 0x73333333, 0x7d70a3d7},
{0x00000000, 0x60000000, 0x73333333, 0x7d70a3d7},
};
/**************************************************************************************
* Function: CVKernel1
*
* Description: kernel of covariance matrix calculation for p01, p11, p12, p22
*
* Inputs: buffer of low-freq samples, starting at time index = 0,
* freq index = patch subband
*
* Outputs: 64-bit accumulators for p01re, p01im, p12re, p12im, p11re, p22re
* stored in accBuf
*
* Return: none
*
* Notes: this is carefully written to be efficient on ARM
* use the assembly code version in sbrcov.s when building for ARM!
**************************************************************************************/
#if (defined (XXXX__arm) && defined (__ARMCC_VERSION)) || (defined (_WIN32) && defined (_WIN32_WCE) && defined (ARM)) || (defined(__GNUC__) && defined(XXXX__arm__))
#ifdef __cplusplus
extern "C"
#endif
void CVKernel1(int *XBuf, int *accBuf);
#else
void CVKernel1(int *XBuf, int *accBuf)
{
U64 p01re, p01im, p12re, p12im, p11re, p22re;
int n, x0re, x0im, x1re, x1im;
x0re = XBuf[0];
x0im = XBuf[1];
XBuf += (2*64);
x1re = XBuf[0];
x1im = XBuf[1];
XBuf += (2*64);
p01re.w64 = p01im.w64 = 0;
p12re.w64 = p12im.w64 = 0;
p11re.w64 = 0;
p22re.w64 = 0;
p12re.w64 = MADD64(p12re.w64, x1re, x0re);
p12re.w64 = MADD64(p12re.w64, x1im, x0im);
p12im.w64 = MADD64(p12im.w64, x0re, x1im);
p12im.w64 = MADD64(p12im.w64, -x0im, x1re);
p22re.w64 = MADD64(p22re.w64, x0re, x0re);
p22re.w64 = MADD64(p22re.w64, x0im, x0im);
for (n = (NUM_TIME_SLOTS*SAMPLES_PER_SLOT + 6); n != 0; n--) {
/* 4 input, 3*2 acc, 1 ptr, 1 loop counter = 12 registers (use same for x0im, -x0im) */
x0re = x1re;
x0im = x1im;
x1re = XBuf[0];
x1im = XBuf[1];
p01re.w64 = MADD64(p01re.w64, x1re, x0re);
p01re.w64 = MADD64(p01re.w64, x1im, x0im);
p01im.w64 = MADD64(p01im.w64, x0re, x1im);
p01im.w64 = MADD64(p01im.w64, -x0im, x1re);
p11re.w64 = MADD64(p11re.w64, x0re, x0re);
p11re.w64 = MADD64(p11re.w64, x0im, x0im);
XBuf += (2*64);
}
/* these can be derived by slight changes to account for boundary conditions */
p12re.w64 += p01re.w64;
p12re.w64 = MADD64(p12re.w64, x1re, -x0re);
p12re.w64 = MADD64(p12re.w64, x1im, -x0im);
p12im.w64 += p01im.w64;
p12im.w64 = MADD64(p12im.w64, x0re, -x1im);
p12im.w64 = MADD64(p12im.w64, x0im, x1re);
p22re.w64 += p11re.w64;
p22re.w64 = MADD64(p22re.w64, x0re, -x0re);
p22re.w64 = MADD64(p22re.w64, x0im, -x0im);
accBuf[0] = p01re.r.lo32; accBuf[1] = p01re.r.hi32;
accBuf[2] = p01im.r.lo32; accBuf[3] = p01im.r.hi32;
accBuf[4] = p11re.r.lo32; accBuf[5] = p11re.r.hi32;
accBuf[6] = p12re.r.lo32; accBuf[7] = p12re.r.hi32;
accBuf[8] = p12im.r.lo32; accBuf[9] = p12im.r.hi32;
accBuf[10] = p22re.r.lo32; accBuf[11] = p22re.r.hi32;
}
#endif
/**************************************************************************************
* Function: CalcCovariance1
*
* Description: calculate covariance matrix for p01, p12, p11, p22 (4.6.18.6.2)
*
* Inputs: buffer of low-freq samples, starting at time index 0,
* freq index = patch subband
*
* Outputs: complex covariance elements p01re, p01im, p12re, p12im, p11re, p22re
* (p11im = p22im = 0)
* format = integer (Q0) * 2^N, with scalefactor N >= 0
*
* Return: scalefactor N
*
* Notes: outputs are normalized to have 1 GB (sign in at least top 2 bits)
**************************************************************************************/
static int CalcCovariance1(int *XBuf, int *p01reN, int *p01imN, int *p12reN, int *p12imN, int *p11reN, int *p22reN)
{
int accBuf[2*6];
int n, z, s, loShift, hiShift, gbMask;
U64 p01re, p01im, p12re, p12im, p11re, p22re;
CVKernel1(XBuf, accBuf);
p01re.r.lo32 = accBuf[0]; p01re.r.hi32 = accBuf[1];
p01im.r.lo32 = accBuf[2]; p01im.r.hi32 = accBuf[3];
p11re.r.lo32 = accBuf[4]; p11re.r.hi32 = accBuf[5];
p12re.r.lo32 = accBuf[6]; p12re.r.hi32 = accBuf[7];
p12im.r.lo32 = accBuf[8]; p12im.r.hi32 = accBuf[9];
p22re.r.lo32 = accBuf[10]; p22re.r.hi32 = accBuf[11];
/* 64-bit accumulators now have 2*FBITS_OUT_QMFA fraction bits
* want to scale them down to integers (32-bit signed, Q0)
* with scale factor of 2^n, n >= 0
* leave 2 GB's for calculating determinant, so take top 30 non-zero bits
*/
gbMask = ((p01re.r.hi32) ^ (p01re.r.hi32 >> 31)) | ((p01im.r.hi32) ^ (p01im.r.hi32 >> 31));
gbMask |= ((p12re.r.hi32) ^ (p12re.r.hi32 >> 31)) | ((p12im.r.hi32) ^ (p12im.r.hi32 >> 31));
gbMask |= ((p11re.r.hi32) ^ (p11re.r.hi32 >> 31)) | ((p22re.r.hi32) ^ (p22re.r.hi32 >> 31));
if (gbMask == 0) {
s = p01re.r.hi32 >> 31; gbMask = (p01re.r.lo32 ^ s) - s;
s = p01im.r.hi32 >> 31; gbMask |= (p01im.r.lo32 ^ s) - s;
s = p12re.r.hi32 >> 31; gbMask |= (p12re.r.lo32 ^ s) - s;
s = p12im.r.hi32 >> 31; gbMask |= (p12im.r.lo32 ^ s) - s;
s = p11re.r.hi32 >> 31; gbMask |= (p11re.r.lo32 ^ s) - s;
s = p22re.r.hi32 >> 31; gbMask |= (p22re.r.lo32 ^ s) - s;
z = 32 + CLZ(gbMask);
} else {
gbMask = FASTABS(p01re.r.hi32) | FASTABS(p01im.r.hi32);
gbMask |= FASTABS(p12re.r.hi32) | FASTABS(p12im.r.hi32);
gbMask |= FASTABS(p11re.r.hi32) | FASTABS(p22re.r.hi32);
z = CLZ(gbMask);
}
n = 64 - z; /* number of non-zero bits in bottom of 64-bit word */
if (n <= 30) {
loShift = (30 - n);
*p01reN = p01re.r.lo32 << loShift; *p01imN = p01im.r.lo32 << loShift;
*p12reN = p12re.r.lo32 << loShift; *p12imN = p12im.r.lo32 << loShift;
*p11reN = p11re.r.lo32 << loShift; *p22reN = p22re.r.lo32 << loShift;
return -(loShift + 2*FBITS_OUT_QMFA);
} else if (n < 32 + 30) {
loShift = (n - 30);
hiShift = 32 - loShift;
*p01reN = (p01re.r.hi32 << hiShift) | (p01re.r.lo32 >> loShift);
*p01imN = (p01im.r.hi32 << hiShift) | (p01im.r.lo32 >> loShift);
*p12reN = (p12re.r.hi32 << hiShift) | (p12re.r.lo32 >> loShift);
*p12imN = (p12im.r.hi32 << hiShift) | (p12im.r.lo32 >> loShift);
*p11reN = (p11re.r.hi32 << hiShift) | (p11re.r.lo32 >> loShift);
*p22reN = (p22re.r.hi32 << hiShift) | (p22re.r.lo32 >> loShift);
return (loShift - 2*FBITS_OUT_QMFA);
} else {
hiShift = n - (32 + 30);
*p01reN = p01re.r.hi32 >> hiShift; *p01imN = p01im.r.hi32 >> hiShift;
*p12reN = p12re.r.hi32 >> hiShift; *p12imN = p12im.r.hi32 >> hiShift;
*p11reN = p11re.r.hi32 >> hiShift; *p22reN = p22re.r.hi32 >> hiShift;
return (32 - 2*FBITS_OUT_QMFA - hiShift);
}
return 0;
}
/**************************************************************************************
* Function: CVKernel2
*
* Description: kernel of covariance matrix calculation for p02
*
* Inputs: buffer of low-freq samples, starting at time index = 0,
* freq index = patch subband
*
* Outputs: 64-bit accumulators for p02re, p02im stored in accBuf
*
* Return: none
*
* Notes: this is carefully written to be efficient on ARM
* use the assembly code version in sbrcov.s when building for ARM!
**************************************************************************************/
#if (defined (XXXX__arm) && defined (__ARMCC_VERSION)) || (defined (_WIN32) && defined (_WIN32_WCE) && defined (ARM)) || (defined(__GNUC__) && defined(XXXX__arm__))
#ifdef __cplusplus
extern "C"
#endif
void CVKernel2(int *XBuf, int *accBuf);
#else
void CVKernel2(int *XBuf, int *accBuf)
{
U64 p02re, p02im;
int n, x0re, x0im, x1re, x1im, x2re, x2im;
p02re.w64 = p02im.w64 = 0;
x0re = XBuf[0];
x0im = XBuf[1];
XBuf += (2*64);
x1re = XBuf[0];
x1im = XBuf[1];
XBuf += (2*64);
for (n = (NUM_TIME_SLOTS*SAMPLES_PER_SLOT + 6); n != 0; n--) {
/* 6 input, 2*2 acc, 1 ptr, 1 loop counter = 12 registers (use same for x0im, -x0im) */
x2re = XBuf[0];
x2im = XBuf[1];
p02re.w64 = MADD64(p02re.w64, x2re, x0re);
p02re.w64 = MADD64(p02re.w64, x2im, x0im);
p02im.w64 = MADD64(p02im.w64, x0re, x2im);
p02im.w64 = MADD64(p02im.w64, -x0im, x2re);
x0re = x1re;
x0im = x1im;
x1re = x2re;
x1im = x2im;
XBuf += (2*64);
}
accBuf[0] = p02re.r.lo32;
accBuf[1] = p02re.r.hi32;
accBuf[2] = p02im.r.lo32;
accBuf[3] = p02im.r.hi32;
}
#endif
/**************************************************************************************
* Function: CalcCovariance2
*
* Description: calculate covariance matrix for p02 (4.6.18.6.2)
*
* Inputs: buffer of low-freq samples, starting at time index = 0,
* freq index = patch subband
*
* Outputs: complex covariance element p02re, p02im
* format = integer (Q0) * 2^N, with scalefactor N >= 0
*
* Return: scalefactor N
*
* Notes: outputs are normalized to have 1 GB (sign in at least top 2 bits)
**************************************************************************************/
static int CalcCovariance2(int *XBuf, int *p02reN, int *p02imN)
{
U64 p02re, p02im;
int n, z, s, loShift, hiShift, gbMask;
int accBuf[2*2];
CVKernel2(XBuf, accBuf);
p02re.r.lo32 = accBuf[0];
p02re.r.hi32 = accBuf[1];
p02im.r.lo32 = accBuf[2];
p02im.r.hi32 = accBuf[3];
/* 64-bit accumulators now have 2*FBITS_OUT_QMFA fraction bits
* want to scale them down to integers (32-bit signed, Q0)
* with scale factor of 2^n, n >= 0
* leave 1 GB for calculating determinant, so take top 30 non-zero bits
*/
gbMask = ((p02re.r.hi32) ^ (p02re.r.hi32 >> 31)) | ((p02im.r.hi32) ^ (p02im.r.hi32 >> 31));
if (gbMask == 0) {
s = p02re.r.hi32 >> 31; gbMask = (p02re.r.lo32 ^ s) - s;
s = p02im.r.hi32 >> 31; gbMask |= (p02im.r.lo32 ^ s) - s;
z = 32 + CLZ(gbMask);
} else {
gbMask = FASTABS(p02re.r.hi32) | FASTABS(p02im.r.hi32);
z = CLZ(gbMask);
}
n = 64 - z; /* number of non-zero bits in bottom of 64-bit word */
if (n <= 30) {
loShift = (30 - n);
*p02reN = p02re.r.lo32 << loShift;
*p02imN = p02im.r.lo32 << loShift;
return -(loShift + 2*FBITS_OUT_QMFA);
} else if (n < 32 + 30) {
loShift = (n - 30);
hiShift = 32 - loShift;
*p02reN = (p02re.r.hi32 << hiShift) | (p02re.r.lo32 >> loShift);
*p02imN = (p02im.r.hi32 << hiShift) | (p02im.r.lo32 >> loShift);
return (loShift - 2*FBITS_OUT_QMFA);
} else {
hiShift = n - (32 + 30);
*p02reN = p02re.r.hi32 >> hiShift;
*p02imN = p02im.r.hi32 >> hiShift;
return (32 - 2*FBITS_OUT_QMFA - hiShift);
}
return 0;
}
/**************************************************************************************
* Function: CalcLPCoefs
*
* Description: calculate linear prediction coefficients for one subband (4.6.18.6.2)
*
* Inputs: buffer of low-freq samples, starting at time index = 0,
* freq index = patch subband
* number of guard bits in input sample buffer
*
* Outputs: complex LP coefficients a0re, a0im, a1re, a1im, format = Q29
*
* Return: none
*
* Notes: output coefficients (a0re, a0im, a1re, a1im) clipped to range (-4, 4)
* if the comples coefficients have magnitude >= 4.0, they are all
* set to 0 (see spec)
**************************************************************************************/
static void CalcLPCoefs(int *XBuf, int *a0re, int *a0im, int *a1re, int *a1im, int gb)
{
int zFlag, n1, n2, nd, d, dInv, tre, tim;
int p01re, p01im, p02re, p02im, p12re, p12im, p11re, p22re;
/* pre-scale to avoid overflow - probably never happens in practice (see QMFA)
* max bit growth per accumulator = 38*2 = 76 mul-adds (X * X)
* using 64-bit MADD, so if X has n guard bits, X*X has 2n+1 guard bits
* gain 1 extra sign bit per multiply, so ensure ceil(log2(76/2) / 2) = 3 guard bits on inputs
*/
if (gb < 3) {
nd = 3 - gb;
for (n1 = (NUM_TIME_SLOTS*SAMPLES_PER_SLOT + 6 + 2); n1 != 0; n1--) {
XBuf[0] >>= nd; XBuf[1] >>= nd;
XBuf += (2*64);
}
XBuf -= (2*64*(NUM_TIME_SLOTS*SAMPLES_PER_SLOT + 6 + 2));
}
/* calculate covariance elements */
n1 = CalcCovariance1(XBuf, &p01re, &p01im, &p12re, &p12im, &p11re, &p22re);
n2 = CalcCovariance2(XBuf, &p02re, &p02im);
/* normalize everything to larger power of 2 scalefactor, call it n1 */
if (n1 < n2) {
nd = MIN(n2 - n1, 31);
p01re >>= nd; p01im >>= nd;
p12re >>= nd; p12im >>= nd;
p11re >>= nd; p22re >>= nd;
n1 = n2;
} else if (n1 > n2) {
nd = MIN(n1 - n2, 31);
p02re >>= nd; p02im >>= nd;
}
/* calculate determinant of covariance matrix (at least 1 GB in pXX) */
d = MULSHIFT32(p12re, p12re) + MULSHIFT32(p12im, p12im);
d = MULSHIFT32(d, RELAX_COEF) << 1;
d = MULSHIFT32(p11re, p22re) - d;
ASSERT(d >= 0); /* should never be < 0 */
zFlag = 0;
*a0re = *a0im = 0;
*a1re = *a1im = 0;
if (d > 0) {
/* input = Q31 d = Q(-2*n1 - 32 + nd) = Q31 * 2^(31 + 2*n1 + 32 - nd)
* inverse = Q29 dInv = Q29 * 2^(-31 - 2*n1 - 32 + nd) = Q(29 + 31 + 2*n1 + 32 - nd)
*
* numerator has same Q format as d, since it's sum of normalized squares
* so num * inverse = Q(-2*n1 - 32) * Q(29 + 31 + 2*n1 + 32 - nd)
* = Q(29 + 31 - nd), drop low 32 in MULSHIFT32
* = Q(29 + 31 - 32 - nd) = Q(28 - nd)
*/
nd = CLZ(d) - 1;
d <<= nd;
dInv = InvRNormalized(d);
/* 1 GB in pXX */
tre = MULSHIFT32(p01re, p12re) - MULSHIFT32(p01im, p12im) - MULSHIFT32(p02re, p11re);
tre = MULSHIFT32(tre, dInv);
tim = MULSHIFT32(p01re, p12im) + MULSHIFT32(p01im, p12re) - MULSHIFT32(p02im, p11re);
tim = MULSHIFT32(tim, dInv);
/* if d is extremely small, just set coefs to 0 (would have poor precision anyway) */
if (nd > 28 || (FASTABS(tre) >> (28 - nd)) >= 4 || (FASTABS(tim) >> (28 - nd)) >= 4) {
zFlag = 1;
} else {
*a1re = tre << (FBITS_LPCOEFS - 28 + nd); /* i.e. convert Q(28 - nd) to Q(29) */
*a1im = tim << (FBITS_LPCOEFS - 28 + nd);
}
}
if (p11re) {
/* input = Q31 p11re = Q(-n1 + nd) = Q31 * 2^(31 + n1 - nd)
* inverse = Q29 dInv = Q29 * 2^(-31 - n1 + nd) = Q(29 + 31 + n1 - nd)
*
* numerator is Q(-n1 - 3)
* so num * inverse = Q(-n1 - 3) * Q(29 + 31 + n1 - nd)
* = Q(29 + 31 - 3 - nd), drop low 32 in MULSHIFT32
* = Q(29 + 31 - 3 - 32 - nd) = Q(25 - nd)
*/
nd = CLZ(p11re) - 1; /* assume positive */
p11re <<= nd;
dInv = InvRNormalized(p11re);
/* a1re, a1im = Q29, so scaled by (n1 + 3) */
tre = (p01re >> 3) + MULSHIFT32(p12re, *a1re) + MULSHIFT32(p12im, *a1im);
tre = -MULSHIFT32(tre, dInv);
tim = (p01im >> 3) - MULSHIFT32(p12im, *a1re) + MULSHIFT32(p12re, *a1im);
tim = -MULSHIFT32(tim, dInv);
if (nd > 25 || (FASTABS(tre) >> (25 - nd)) >= 4 || (FASTABS(tim) >> (25 - nd)) >= 4) {
zFlag = 1;
} else {
*a0re = tre << (FBITS_LPCOEFS - 25 + nd); /* i.e. convert Q(25 - nd) to Q(29) */
*a0im = tim << (FBITS_LPCOEFS - 25 + nd);
}
}
/* see 4.6.18.6.2 - if magnitude of a0 or a1 >= 4 then a0 = a1 = 0
* i.e. a0re < 4, a0im < 4, a1re < 4, a1im < 4
* Q29*Q29 = Q26
*/
if (zFlag || MULSHIFT32(*a0re, *a0re) + MULSHIFT32(*a0im, *a0im) >= MAG_16 || MULSHIFT32(*a1re, *a1re) + MULSHIFT32(*a1im, *a1im) >= MAG_16) {
*a0re = *a0im = 0;
*a1re = *a1im = 0;
}
/* no need to clip - we never changed the XBuf data, just used it to calculate a0 and a1 */
if (gb < 3) {
nd = 3 - gb;
for (n1 = (NUM_TIME_SLOTS*SAMPLES_PER_SLOT + 6 + 2); n1 != 0; n1--) {
XBuf[0] <<= nd; XBuf[1] <<= nd;
XBuf += (2*64);
}
}
}
/**************************************************************************************
* Function: GenerateHighFreq
*
* Description: generate high frequencies with SBR (4.6.18.6)
*
* Inputs: initialized PSInfoSBR struct
* initialized SBRGrid struct for this channel
* initialized SBRFreq struct for this SCE/CPE block
* initialized SBRChan struct for this channel
* index of current channel (0 for SCE, 0 or 1 for CPE)
*
* Outputs: new high frequency samples starting at frequency kStart
*
* Return: none
**************************************************************************************/
void GenerateHighFreq(PSInfoSBR *psi, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int ch)
{
int band, newBW, c, t, gb, gbMask, gbIdx;
int currPatch, p, x, k, g, i, iStart, iEnd, bw, bwsq;
int a0re, a0im, a1re, a1im;
int x1re, x1im, x2re, x2im;
int ACCre, ACCim;
int *XBufLo, *XBufHi;
(void) ch;
/* calculate array of chirp factors */
for (band = 0; band < sbrFreq->numNoiseFloorBands; band++) {
c = sbrChan->chirpFact[band]; /* previous (bwArray') */
newBW = newBWTab[sbrChan->invfMode[0][band]][sbrChan->invfMode[1][band]];
/* weighted average of new and old (can't overflow - total gain = 1.0) */
if (newBW < c)
t = MULSHIFT32(newBW, 0x60000000) + MULSHIFT32(0x20000000, c); /* new is smaller: 0.75*new + 0.25*old */
else
t = MULSHIFT32(newBW, 0x74000000) + MULSHIFT32(0x0c000000, c); /* new is larger: 0.90625*new + 0.09375*old */
t <<= 1;
if (t < 0x02000000) /* below 0.015625, clip to 0 */
t = 0;
if (t > 0x7f800000) /* clip to 0.99609375 */
t = 0x7f800000;
/* save curr as prev for next time */
sbrChan->chirpFact[band] = t;
sbrChan->invfMode[0][band] = sbrChan->invfMode[1][band];
}
iStart = sbrGrid->envTimeBorder[0] + HF_ADJ;
iEnd = sbrGrid->envTimeBorder[sbrGrid->numEnv] + HF_ADJ;
/* generate new high freqs from low freqs, patches, and chirp factors */
k = sbrFreq->kStart;
g = 0;
bw = sbrChan->chirpFact[g];
bwsq = MULSHIFT32(bw, bw) << 1;
gbMask = (sbrChan->gbMask[0] | sbrChan->gbMask[1]); /* older 32 | newer 8 */
gb = CLZ(gbMask) - 1;
for (currPatch = 0; currPatch < sbrFreq->numPatches; currPatch++) {
for (x = 0; x < sbrFreq->patchNumSubbands[currPatch]; x++) {
/* map k to corresponding noise floor band */
if (k >= sbrFreq->freqNoise[g+1]) {
g++;
bw = sbrChan->chirpFact[g]; /* Q31 */
bwsq = MULSHIFT32(bw, bw) << 1; /* Q31 */
}
p = sbrFreq->patchStartSubband[currPatch] + x; /* low QMF band */
XBufHi = psi->XBuf[iStart][k];
if (bw) {
CalcLPCoefs(psi->XBuf[0][p], &a0re, &a0im, &a1re, &a1im, gb);
a0re = MULSHIFT32(bw, a0re); /* Q31 * Q29 = Q28 */
a0im = MULSHIFT32(bw, a0im);
a1re = MULSHIFT32(bwsq, a1re);
a1im = MULSHIFT32(bwsq, a1im);
XBufLo = psi->XBuf[iStart-2][p];
x2re = XBufLo[0]; /* RE{XBuf[n-2]} */
x2im = XBufLo[1]; /* IM{XBuf[n-2]} */
XBufLo += (64*2);
x1re = XBufLo[0]; /* RE{XBuf[n-1]} */
x1im = XBufLo[1]; /* IM{XBuf[n-1]} */
XBufLo += (64*2);
for (i = iStart; i < iEnd; i++) {
/* a0re/im, a1re/im are Q28 with at least 1 GB,
* so the summing for AACre/im is fine (1 GB in, plus 1 from MULSHIFT32)
*/
ACCre = MULSHIFT32(x2re, a1re) - MULSHIFT32(x2im, a1im);
ACCim = MULSHIFT32(x2re, a1im) + MULSHIFT32(x2im, a1re);
x2re = x1re;
x2im = x1im;
ACCre += MULSHIFT32(x1re, a0re) - MULSHIFT32(x1im, a0im);
ACCim += MULSHIFT32(x1re, a0im) + MULSHIFT32(x1im, a0re);
x1re = XBufLo[0]; /* RE{XBuf[n]} */
x1im = XBufLo[1]; /* IM{XBuf[n]} */
XBufLo += (64*2);
/* lost 4 fbits when scaling by a0re/im, a1re/im (Q28) */
CLIP_2N_SHIFT30(ACCre, 4);
ACCre += x1re;
CLIP_2N_SHIFT30(ACCim, 4);
ACCim += x1im;
XBufHi[0] = ACCre;
XBufHi[1] = ACCim;
XBufHi += (64*2);
/* update guard bit masks */
gbMask = FASTABS(ACCre);
gbMask |= FASTABS(ACCim);
gbIdx = (i >> 5) & 0x01; /* 0 if i < 32, 1 if i >= 32 */
sbrChan->gbMask[gbIdx] |= gbMask;
}
} else {
XBufLo = (int *)psi->XBuf[iStart][p];
for (i = iStart; i < iEnd; i++) {
XBufHi[0] = XBufLo[0];
XBufHi[1] = XBufLo[1];
XBufLo += (64*2);
XBufHi += (64*2);
}
}
k++; /* high QMF band */
}
}
}

View File

@@ -0,0 +1,476 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: sbrhuff.c,v 1.1 2005/02/26 01:47:35 jrecker Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* sbrhuff.c - functions for unpacking Huffman-coded envelope and noise data
**************************************************************************************/
#include "sbr.h"
#include "assembly.h"
/**************************************************************************************
* Function: DecodeHuffmanScalar
*
* Description: decode one Huffman symbol from bitstream
*
* Inputs: pointers to Huffman table and info struct
* left-aligned bit buffer with >= huffTabInfo->maxBits bits
*
* Outputs: decoded symbol in *val
*
* Return: number of bits in symbol
*
* Notes: assumes canonical Huffman codes:
* first CW always 0, we have "count" CW's of length "nBits" bits
* starting CW for codes of length nBits+1 =
* (startCW[nBits] + count[nBits]) << 1
* if there are no codes at nBits, then we just keep << 1 each time
* (since count[nBits] = 0)
**************************************************************************************/
static int DecodeHuffmanScalar(const signed /*short*/ int *huffTab, const HuffInfo *huffTabInfo, unsigned int bitBuf, signed int *val)
{
unsigned int count, start, shift, t;
const unsigned int /*char*/ *countPtr;
const signed int /*short*/ *map;
map = huffTab + huffTabInfo->offset;
countPtr = huffTabInfo->count;
start = 0;
count = 0;
shift = 32;
do {
start += count;
start <<= 1;
map += count;
count = *countPtr++;
shift--;
t = (bitBuf >> shift) - start;
} while (t >= count);
*val = (signed int)map[t];
return (countPtr - huffTabInfo->count);
}
/**************************************************************************************
* Function: DecodeOneSymbol
*
* Description: dequantize one Huffman symbol from bitstream,
* using table huffTabSBR[huffTabIndex]
*
* Inputs: BitStreamInfo struct pointing to start of next Huffman codeword
* index of Huffman table
*
* Outputs: bitstream advanced by number of bits in codeword
*
* Return: one decoded symbol
**************************************************************************************/
static int DecodeOneSymbol(BitStreamInfo *bsi, int huffTabIndex)
{
int nBits, val;
unsigned int bitBuf;
const HuffInfo *hi;
hi = &(huffTabSBRInfo[huffTabIndex]);
bitBuf = GetBitsNoAdvance(bsi, hi->maxBits) << (32 - hi->maxBits);
nBits = DecodeHuffmanScalar(huffTabSBR, hi, bitBuf, &val);
AdvanceBitstream(bsi, nBits);
return val;
}
/* [1.0, sqrt(2)], format = Q29 (one guard bit for decoupling) */
static const int envDQTab[2] PROGMEM = {0x20000000, 0x2d413ccc};
/**************************************************************************************
* Function: DequantizeEnvelope
*
* Description: dequantize envelope scalefactors
*
* Inputs: number of scalefactors to process
* amplitude resolution flag for this frame (0 or 1)
* quantized envelope scalefactors
*
* Outputs: dequantized envelope scalefactors
*
* Return: extra int bits in output (6 + expMax)
* in other words, output format = Q(FBITS_OUT_DQ_ENV - (6 + expMax))
*
* Notes: dequantized scalefactors have at least 2 GB
**************************************************************************************/
static int DequantizeEnvelope(int nBands, int ampRes, signed char *envQuant, int *envDequant)
{
int exp, expMax, i, scalei;
if (nBands <= 0)
return 0;
/* scan for largest dequant value (do separately from envelope decoding to keep code cleaner) */
expMax = 0;
for (i = 0; i < nBands; i++) {
if (envQuant[i] > expMax)
expMax = envQuant[i];
}
/* dequantized envelope gains
* envDequant = 64*2^(envQuant / alpha) = 2^(6 + envQuant / alpha)
* if ampRes == 0, alpha = 2 and range of envQuant = [0, 127]
* if ampRes == 1, alpha = 1 and range of envQuant = [0, 63]
* also if coupling is on, envDequant is scaled by something in range [0, 2]
* so range of envDequant = [2^6, 2^69] (no coupling), [2^6, 2^70] (with coupling)
*
* typical range (from observation) of envQuant/alpha = [0, 27] --> largest envQuant ~= 2^33
* output: Q(29 - (6 + expMax))
*
* reference: 14496-3:2001(E)/4.6.18.3.5 and 14496-4:200X/FPDAM8/5.6.5.1.2.1.5
*/
if (ampRes) {
do {
exp = *envQuant++;
scalei = MIN(expMax - exp, 31);
*envDequant++ = envDQTab[0] >> scalei;
} while (--nBands);
return (6 + expMax);
} else {
expMax >>= 1;
do {
exp = *envQuant++;
scalei = MIN(expMax - (exp >> 1), 31);
*envDequant++ = envDQTab[exp & 0x01] >> scalei;
} while (--nBands);
return (6 + expMax);
}
}
/**************************************************************************************
* Function: DequantizeNoise
*
* Description: dequantize noise scalefactors
*
* Inputs: number of scalefactors to process
* quantized noise scalefactors
*
* Outputs: dequantized noise scalefactors, format = Q(FBITS_OUT_DQ_NOISE)
*
* Return: none
*
* Notes: dequantized scalefactors have at least 2 GB
**************************************************************************************/
static void DequantizeNoise(int nBands, signed char *noiseQuant, int *noiseDequant)
{
int exp, scalei;
if (nBands <= 0)
return;
/* dequantize noise floor gains (4.6.18.3.5):
* noiseDequant = 2^(NOISE_FLOOR_OFFSET - noiseQuant)
*
* range of noiseQuant = [0, 30] (see 4.6.18.3.6), NOISE_FLOOR_OFFSET = 6
* so range of noiseDequant = [2^-24, 2^6]
*/
do {
exp = *noiseQuant++;
scalei = NOISE_FLOOR_OFFSET - exp + FBITS_OUT_DQ_NOISE; /* 6 + 24 - exp, exp = [0,30] */
if (scalei < 0)
*noiseDequant++ = 0;
else if (scalei < 30)
*noiseDequant++ = 1 << scalei;
else
*noiseDequant++ = 0x3fffffff; /* leave 2 GB */
} while (--nBands);
}
/**************************************************************************************
* Function: DecodeSBREnvelope
*
* Description: decode delta Huffman coded envelope scalefactors from bitstream
*
* Inputs: BitStreamInfo struct pointing to start of env data
* initialized PSInfoSBR struct
* initialized SBRGrid struct for this channel
* initialized SBRFreq struct for this SCE/CPE block
* initialized SBRChan struct for this channel
* index of current channel (0 for SCE, 0 or 1 for CPE)
*
* Outputs: dequantized env scalefactors for left channel (before decoupling)
* dequantized env scalefactors for right channel (if coupling off)
* or raw decoded env scalefactors for right channel (if coupling on)
*
* Return: none
**************************************************************************************/
void DecodeSBREnvelope(BitStreamInfo *bsi, PSInfoSBR *psi, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int ch)
{
int huffIndexTime, huffIndexFreq, env, envStartBits, band, nBands, sf, lastEnv;
int freqRes, freqResPrev, dShift, i;
if (psi->couplingFlag && ch) {
dShift = 1;
if (sbrGrid->ampResFrame) {
huffIndexTime = HuffTabSBR_tEnv30b;
huffIndexFreq = HuffTabSBR_fEnv30b;
envStartBits = 5;
} else {
huffIndexTime = HuffTabSBR_tEnv15b;
huffIndexFreq = HuffTabSBR_fEnv15b;
envStartBits = 6;
}
} else {
dShift = 0;
if (sbrGrid->ampResFrame) {
huffIndexTime = HuffTabSBR_tEnv30;
huffIndexFreq = HuffTabSBR_fEnv30;
envStartBits = 6;
} else {
huffIndexTime = HuffTabSBR_tEnv15;
huffIndexFreq = HuffTabSBR_fEnv15;
envStartBits = 7;
}
}
/* range of envDataQuant[] = [0, 127] (see comments in DequantizeEnvelope() for reference) */
for (env = 0; env < sbrGrid->numEnv; env++) {
nBands = (sbrGrid->freqRes[env] ? sbrFreq->nHigh : sbrFreq->nLow);
freqRes = (sbrGrid->freqRes[env]);
freqResPrev = (env == 0 ? sbrGrid->freqResPrev : sbrGrid->freqRes[env-1]);
lastEnv = (env == 0 ? sbrGrid->numEnvPrev-1 : env-1);
if (lastEnv < 0)
lastEnv = 0; /* first frame */
ASSERT(nBands <= MAX_QMF_BANDS);
if (sbrChan->deltaFlagEnv[env] == 0) {
/* delta coding in freq */
sf = GetBits(bsi, envStartBits) << dShift;
sbrChan->envDataQuant[env][0] = sf;
for (band = 1; band < nBands; band++) {
sf = DecodeOneSymbol(bsi, huffIndexFreq) << dShift;
sbrChan->envDataQuant[env][band] = sf + sbrChan->envDataQuant[env][band-1];
}
} else if (freqRes == freqResPrev) {
/* delta coding in time - same freq resolution for both frames */
for (band = 0; band < nBands; band++) {
sf = DecodeOneSymbol(bsi, huffIndexTime) << dShift;
sbrChan->envDataQuant[env][band] = sf + sbrChan->envDataQuant[lastEnv][band];
}
} else if (freqRes == 0 && freqResPrev == 1) {
/* delta coding in time - low freq resolution for new frame, high freq resolution for old frame */
for (band = 0; band < nBands; band++) {
sf = DecodeOneSymbol(bsi, huffIndexTime) << dShift;
sbrChan->envDataQuant[env][band] = sf;
for (i = 0; i < sbrFreq->nHigh; i++) {
if (sbrFreq->freqHigh[i] == sbrFreq->freqLow[band]) {
sbrChan->envDataQuant[env][band] += sbrChan->envDataQuant[lastEnv][i];
break;
}
}
}
} else if (freqRes == 1 && freqResPrev == 0) {
/* delta coding in time - high freq resolution for new frame, low freq resolution for old frame */
for (band = 0; band < nBands; band++) {
sf = DecodeOneSymbol(bsi, huffIndexTime) << dShift;
sbrChan->envDataQuant[env][band] = sf;
for (i = 0; i < sbrFreq->nLow; i++) {
if (sbrFreq->freqLow[i] <= sbrFreq->freqHigh[band] && sbrFreq->freqHigh[band] < sbrFreq->freqLow[i+1] ) {
sbrChan->envDataQuant[env][band] += sbrChan->envDataQuant[lastEnv][i];
break;
}
}
}
}
/* skip coupling channel */
if (ch != 1 || psi->couplingFlag != 1)
psi->envDataDequantScale[ch][env] = DequantizeEnvelope(nBands, sbrGrid->ampResFrame, sbrChan->envDataQuant[env], psi->envDataDequant[ch][env]);
}
sbrGrid->numEnvPrev = sbrGrid->numEnv;
sbrGrid->freqResPrev = sbrGrid->freqRes[sbrGrid->numEnv-1];
}
/**************************************************************************************
* Function: DecodeSBRNoise
*
* Description: decode delta Huffman coded noise scalefactors from bitstream
*
* Inputs: BitStreamInfo struct pointing to start of noise data
* initialized PSInfoSBR struct
* initialized SBRGrid struct for this channel
* initialized SBRFreq struct for this SCE/CPE block
* initialized SBRChan struct for this channel
* index of current channel (0 for SCE, 0 or 1 for CPE)
*
* Outputs: dequantized noise scalefactors for left channel (before decoupling)
* dequantized noise scalefactors for right channel (if coupling off)
* or raw decoded noise scalefactors for right channel (if coupling on)
*
* Return: none
**************************************************************************************/
void DecodeSBRNoise(BitStreamInfo *bsi, PSInfoSBR *psi, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChan, int ch)
{
int huffIndexTime, huffIndexFreq, noiseFloor, band, dShift, sf, lastNoiseFloor;
if (psi->couplingFlag && ch) {
dShift = 1;
huffIndexTime = HuffTabSBR_tNoise30b;
huffIndexFreq = HuffTabSBR_fNoise30b;
} else {
dShift = 0;
huffIndexTime = HuffTabSBR_tNoise30;
huffIndexFreq = HuffTabSBR_fNoise30;
}
for (noiseFloor = 0; noiseFloor < sbrGrid->numNoiseFloors; noiseFloor++) {
lastNoiseFloor = (noiseFloor == 0 ? sbrGrid->numNoiseFloorsPrev-1 : noiseFloor-1);
if (lastNoiseFloor < 0)
lastNoiseFloor = 0; /* first frame */
ASSERT(sbrFreq->numNoiseFloorBands <= MAX_QMF_BANDS);
if (sbrChan->deltaFlagNoise[noiseFloor] == 0) {
/* delta coding in freq */
sbrChan->noiseDataQuant[noiseFloor][0] = GetBits(bsi, 5) << dShift;
for (band = 1; band < sbrFreq->numNoiseFloorBands; band++) {
sf = DecodeOneSymbol(bsi, huffIndexFreq) << dShift;
sbrChan->noiseDataQuant[noiseFloor][band] = sf + sbrChan->noiseDataQuant[noiseFloor][band-1];
}
} else {
/* delta coding in time */
for (band = 0; band < sbrFreq->numNoiseFloorBands; band++) {
sf = DecodeOneSymbol(bsi, huffIndexTime) << dShift;
sbrChan->noiseDataQuant[noiseFloor][band] = sf + sbrChan->noiseDataQuant[lastNoiseFloor][band];
}
}
/* skip coupling channel */
if (ch != 1 || psi->couplingFlag != 1)
DequantizeNoise(sbrFreq->numNoiseFloorBands, sbrChan->noiseDataQuant[noiseFloor], psi->noiseDataDequant[ch][noiseFloor]);
}
sbrGrid->numNoiseFloorsPrev = sbrGrid->numNoiseFloors;
}
/* dqTabCouple[i] = 2 / (1 + 2^(12 - i)), format = Q30 */
static const int dqTabCouple[25] PROGMEM = {
0x0007ff80, 0x000ffe00, 0x001ff802, 0x003fe010, 0x007f8080, 0x00fe03f8, 0x01f81f82, 0x03e0f83e,
0x07878788, 0x0e38e38e, 0x1999999a, 0x2aaaaaab, 0x40000000, 0x55555555, 0x66666666, 0x71c71c72,
0x78787878, 0x7c1f07c2, 0x7e07e07e, 0x7f01fc08, 0x7f807f80, 0x7fc01ff0, 0x7fe007fe, 0x7ff00200,
0x7ff80080,
};
/**************************************************************************************
* Function: UncoupleSBREnvelope
*
* Description: scale dequantized envelope scalefactors according to channel
* coupling rules
*
* Inputs: initialized PSInfoSBR struct including
* dequantized envelope data for left channel
* initialized SBRGrid struct for this channel
* initialized SBRFreq struct for this SCE/CPE block
* initialized SBRChan struct for right channel including
* quantized envelope scalefactors
*
* Outputs: dequantized envelope data for left channel (after decoupling)
* dequantized envelope data for right channel (after decoupling)
*
* Return: none
**************************************************************************************/
void UncoupleSBREnvelope(PSInfoSBR *psi, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChanR)
{
int env, band, nBands, scalei, E_1;
scalei = (sbrGrid->ampResFrame ? 0 : 1);
for (env = 0; env < sbrGrid->numEnv; env++) {
nBands = (sbrGrid->freqRes[env] ? sbrFreq->nHigh : sbrFreq->nLow);
psi->envDataDequantScale[1][env] = psi->envDataDequantScale[0][env]; /* same scalefactor for L and R */
for (band = 0; band < nBands; band++) {
/* clip E_1 to [0, 24] (scalefactors approach 0 or 2) */
E_1 = sbrChanR->envDataQuant[env][band] >> scalei;
if (E_1 < 0) E_1 = 0;
if (E_1 > 24) E_1 = 24;
/* envDataDequant[0] has 1 GB, so << by 2 is okay */
psi->envDataDequant[1][env][band] = MULSHIFT32(psi->envDataDequant[0][env][band], dqTabCouple[24 - E_1]) << 2;
psi->envDataDequant[0][env][band] = MULSHIFT32(psi->envDataDequant[0][env][band], dqTabCouple[E_1]) << 2;
}
}
}
/**************************************************************************************
* Function: UncoupleSBRNoise
*
* Description: scale dequantized noise floor scalefactors according to channel
* coupling rules
*
* Inputs: initialized PSInfoSBR struct including
* dequantized noise data for left channel
* initialized SBRGrid struct for this channel
* initialized SBRFreq struct for this SCE/CPE block
* initialized SBRChan struct for this channel including
* quantized noise scalefactors
*
* Outputs: dequantized noise data for left channel (after decoupling)
* dequantized noise data for right channel (after decoupling)
*
* Return: none
**************************************************************************************/
void UncoupleSBRNoise(PSInfoSBR *psi, SBRGrid *sbrGrid, SBRFreq *sbrFreq, SBRChan *sbrChanR)
{
int noiseFloor, band, Q_1;
for (noiseFloor = 0; noiseFloor < sbrGrid->numNoiseFloors; noiseFloor++) {
for (band = 0; band < sbrFreq->numNoiseFloorBands; band++) {
/* Q_1 should be in range [0, 24] according to 4.6.18.3.6, but check to make sure */
Q_1 = sbrChanR->noiseDataQuant[noiseFloor][band];
if (Q_1 < 0) Q_1 = 0;
if (Q_1 > 24) Q_1 = 24;
/* noiseDataDequant[0] has 1 GB, so << by 2 is okay */
psi->noiseDataDequant[1][noiseFloor][band] = MULSHIFT32(psi->noiseDataDequant[0][noiseFloor][band], dqTabCouple[24 - Q_1]) << 2;
psi->noiseDataDequant[0][noiseFloor][band] = MULSHIFT32(psi->noiseDataDequant[0][noiseFloor][band], dqTabCouple[Q_1]) << 2;
}
}
}

View File

@@ -0,0 +1,447 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: sbrimdct.c,v 1.1 2005/02/26 01:47:35 jrecker Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* sbrimdct.c - inverse MDCT without clipping or interleaving, for input to SBR
**************************************************************************************/
#include "coder.h"
#include "assembly.h"
/**************************************************************************************
* Function: DecWindowOverlapNoClip
*
* Description: apply synthesis window, do overlap-add without clipping,
* for winSequence LONG-LONG
*
* Inputs: input buffer (output of type-IV DCT)
* overlap buffer (saved from last time)
* window type (sin or KBD) for input buffer
* window type (sin or KBD) for overlap buffer
*
* Outputs: one channel, one frame of 32-bit PCM, non-interleaved
*
* Return: none
*
* Notes: use this function when the decoded PCM is going to the SBR decoder
**************************************************************************************/
void DecWindowOverlapNoClip(int *buf0, int *over0, int *out0, int winTypeCurr, int winTypePrev)
{
int in, w0, w1, f0, f1;
int *buf1, *over1, *out1;
const int *wndPrev, *wndCurr;
buf0 += (1024 >> 1);
buf1 = buf0 - 1;
out1 = out0 + 1024 - 1;
over1 = over0 + 1024 - 1;
wndPrev = (winTypePrev == 1 ? kbdWindow + kbdWindowOffset[1] : sinWindow + sinWindowOffset[1]);
if (winTypeCurr == winTypePrev) {
/* cut window loads in half since current and overlap sections use same symmetric window */
do {
w0 = *wndPrev++;
w1 = *wndPrev++;
in = *buf0++;
f0 = MULSHIFT32(w0, in);
f1 = MULSHIFT32(w1, in);
in = *over0;
*out0++ = in - f0;
in = *over1;
*out1-- = in + f1;
in = *buf1--;
*over1-- = MULSHIFT32(w0, in);
*over0++ = MULSHIFT32(w1, in);
} while (over0 < over1);
} else {
/* different windows for current and overlap parts - should still fit in registers on ARM w/o stack spill */
wndCurr = (winTypeCurr == 1 ? kbdWindow + kbdWindowOffset[1] : sinWindow + sinWindowOffset[1]);
do {
w0 = *wndPrev++;
w1 = *wndPrev++;
in = *buf0++;
f0 = MULSHIFT32(w0, in);
f1 = MULSHIFT32(w1, in);
in = *over0;
*out0++ = in - f0;
in = *over1;
*out1-- = in + f1;
w0 = *wndCurr++;
w1 = *wndCurr++;
in = *buf1--;
*over1-- = MULSHIFT32(w0, in);
*over0++ = MULSHIFT32(w1, in);
} while (over0 < over1);
}
}
/**************************************************************************************
* Function: DecWindowOverlapLongStart
*
* Description: apply synthesis window, do overlap-add, without clipping
* for winSequence LONG-START
*
* Inputs: input buffer (output of type-IV DCT)
* overlap buffer (saved from last time)
* window type (sin or KBD) for input buffer
* window type (sin or KBD) for overlap buffer
*
* Outputs: one channel, one frame of 32-bit PCM, non-interleaved
*
* Return: none
*
* Notes: use this function when the decoded PCM is going to the SBR decoder
**************************************************************************************/
void DecWindowOverlapLongStartNoClip(int *buf0, int *over0, int *out0, int winTypeCurr, int winTypePrev)
{
int i, in, w0, w1, f0, f1;
int *buf1, *over1, *out1;
const int *wndPrev, *wndCurr;
buf0 += (1024 >> 1);
buf1 = buf0 - 1;
out1 = out0 + 1024 - 1;
over1 = over0 + 1024 - 1;
wndPrev = (winTypePrev == 1 ? kbdWindow + kbdWindowOffset[1] : sinWindow + sinWindowOffset[1]);
i = 448; /* 2 outputs, 2 overlaps per loop */
do {
w0 = *wndPrev++;
w1 = *wndPrev++;
in = *buf0++;
f0 = MULSHIFT32(w0, in);
f1 = MULSHIFT32(w1, in);
in = *over0;
*out0++ = in - f0;
in = *over1;
*out1-- = in + f1;
in = *buf1--;
*over1-- = 0; /* Wn = 0 for n = (2047, 2046, ... 1600) */
*over0++ = in >> 1; /* Wn = 1 for n = (1024, 1025, ... 1471) */
} while (--i);
wndCurr = (winTypeCurr == 1 ? kbdWindow + kbdWindowOffset[0] : sinWindow + sinWindowOffset[0]);
/* do 64 more loops - 2 outputs, 2 overlaps per loop */
do {
w0 = *wndPrev++;
w1 = *wndPrev++;
in = *buf0++;
f0 = MULSHIFT32(w0, in);
f1 = MULSHIFT32(w1, in);
in = *over0;
*out0++ = in - f0;
in = *over1;
*out1-- = in + f1;
w0 = *wndCurr++; /* W[0], W[1], ... --> W[255], W[254], ... */
w1 = *wndCurr++; /* W[127], W[126], ... --> W[128], W[129], ... */
in = *buf1--;
*over1-- = MULSHIFT32(w0, in); /* Wn = short window for n = (1599, 1598, ... , 1536) */
*over0++ = MULSHIFT32(w1, in); /* Wn = short window for n = (1472, 1473, ... , 1535) */
} while (over0 < over1);
}
/**************************************************************************************
* Function: DecWindowOverlapLongStop
*
* Description: apply synthesis window, do overlap-add, without clipping
* for winSequence LONG-STOP
*
* Inputs: input buffer (output of type-IV DCT)
* overlap buffer (saved from last time)
* window type (sin or KBD) for input buffer
* window type (sin or KBD) for overlap buffer
*
* Outputs: one channel, one frame of 32-bit PCM, non-interleaved
*
* Return: none
*
* Notes: use this function when the decoded PCM is going to the SBR decoder
**************************************************************************************/
void DecWindowOverlapLongStopNoClip(int *buf0, int *over0, int *out0, int winTypeCurr, int winTypePrev)
{
int i, in, w0, w1, f0, f1;
int *buf1, *over1, *out1;
const int *wndPrev, *wndCurr;
buf0 += (1024 >> 1);
buf1 = buf0 - 1;
out1 = out0 + 1024 - 1;
over1 = over0 + 1024 - 1;
wndPrev = (winTypePrev == 1 ? kbdWindow + kbdWindowOffset[0] : sinWindow + sinWindowOffset[0]);
wndCurr = (winTypeCurr == 1 ? kbdWindow + kbdWindowOffset[1] : sinWindow + sinWindowOffset[1]);
i = 448; /* 2 outputs, 2 overlaps per loop */
do {
/* Wn = 0 for n = (0, 1, ... 447) */
/* Wn = 1 for n = (576, 577, ... 1023) */
in = *buf0++;
f1 = in >> 1; /* scale since skipping multiply by Q31 */
in = *over0;
*out0++ = in;
in = *over1;
*out1-- = in + f1;
w0 = *wndCurr++;
w1 = *wndCurr++;
in = *buf1--;
*over1-- = MULSHIFT32(w0, in);
*over0++ = MULSHIFT32(w1, in);
} while (--i);
/* do 64 more loops - 2 outputs, 2 overlaps per loop */
do {
w0 = *wndPrev++; /* W[0], W[1], ...W[63] */
w1 = *wndPrev++; /* W[127], W[126], ... W[64] */
in = *buf0++;
f0 = MULSHIFT32(w0, in);
f1 = MULSHIFT32(w1, in);
in = *over0;
*out0++ = in - f0;
in = *over1;
*out1-- = in + f1;
w0 = *wndCurr++;
w1 = *wndCurr++;
in = *buf1--;
*over1-- = MULSHIFT32(w0, in);
*over0++ = MULSHIFT32(w1, in);
} while (over0 < over1);
}
/**************************************************************************************
* Function: DecWindowOverlapShort
*
* Description: apply synthesis window, do overlap-add, without clipping
* for winSequence EIGHT-SHORT (does all 8 short blocks)
*
* Inputs: input buffer (output of type-IV DCT)
* overlap buffer (saved from last time)
* window type (sin or KBD) for input buffer
* window type (sin or KBD) for overlap buffer
*
* Outputs: one channel, one frame of 32-bit PCM, non-interleaved
*
* Return: none
*
* Notes: use this function when the decoded PCM is going to the SBR decoder
**************************************************************************************/
void DecWindowOverlapShortNoClip(int *buf0, int *over0, int *out0, int winTypeCurr, int winTypePrev)
{
int i, in, w0, w1, f0, f1;
int *buf1, *over1, *out1;
const int *wndPrev, *wndCurr;
wndPrev = (winTypePrev == 1 ? kbdWindow + kbdWindowOffset[0] : sinWindow + sinWindowOffset[0]);
wndCurr = (winTypeCurr == 1 ? kbdWindow + kbdWindowOffset[0] : sinWindow + sinWindowOffset[0]);
/* pcm[0-447] = 0 + overlap[0-447] */
i = 448;
do {
f0 = *over0++;
f1 = *over0++;
*out0++ = f0;
*out0++ = f1;
i -= 2;
} while (i);
/* pcm[448-575] = Wp[0-127] * block0[0-127] + overlap[448-575] */
out1 = out0 + (128 - 1);
over1 = over0 + 128 - 1;
buf0 += 64;
buf1 = buf0 - 1;
do {
w0 = *wndPrev++; /* W[0], W[1], ...W[63] */
w1 = *wndPrev++; /* W[127], W[126], ... W[64] */
in = *buf0++;
f0 = MULSHIFT32(w0, in);
f1 = MULSHIFT32(w1, in);
in = *over0;
*out0++ = in - f0;
in = *over1;
*out1-- = in + f1;
w0 = *wndCurr++;
w1 = *wndCurr++;
in = *buf1--;
/* save over0/over1 for next short block, in the slots just vacated */
*over1-- = MULSHIFT32(w0, in);
*over0++ = MULSHIFT32(w1, in);
} while (over0 < over1);
/* pcm[576-703] = Wc[128-255] * block0[128-255] + Wc[0-127] * block1[0-127] + overlap[576-703]
* pcm[704-831] = Wc[128-255] * block1[128-255] + Wc[0-127] * block2[0-127] + overlap[704-831]
* pcm[832-959] = Wc[128-255] * block2[128-255] + Wc[0-127] * block3[0-127] + overlap[832-959]
*/
for (i = 0; i < 3; i++) {
out0 += 64;
out1 = out0 + 128 - 1;
over0 += 64;
over1 = over0 + 128 - 1;
buf0 += 64;
buf1 = buf0 - 1;
wndCurr -= 128;
do {
w0 = *wndCurr++; /* W[0], W[1], ...W[63] */
w1 = *wndCurr++; /* W[127], W[126], ... W[64] */
in = *buf0++;
f0 = MULSHIFT32(w0, in);
f1 = MULSHIFT32(w1, in);
in = *(over0 - 128); /* from last short block */
in += *(over0 + 0); /* from last full frame */
*out0++ = in - f0;
in = *(over1 - 128); /* from last short block */
in += *(over1 + 0); /* from last full frame */
*out1-- = in + f1;
/* save over0/over1 for next short block, in the slots just vacated */
in = *buf1--;
*over1-- = MULSHIFT32(w0, in);
*over0++ = MULSHIFT32(w1, in);
} while (over0 < over1);
}
/* pcm[960-1023] = Wc[128-191] * block3[128-191] + Wc[0-63] * block4[0-63] + overlap[960-1023]
* over[0-63] = Wc[192-255] * block3[192-255] + Wc[64-127] * block4[64-127]
*/
out0 += 64;
over0 -= 832; /* points at overlap[64] */
over1 = over0 + 128 - 1; /* points at overlap[191] */
buf0 += 64;
buf1 = buf0 - 1;
wndCurr -= 128;
do {
w0 = *wndCurr++; /* W[0], W[1], ...W[63] */
w1 = *wndCurr++; /* W[127], W[126], ... W[64] */
in = *buf0++;
f0 = MULSHIFT32(w0, in);
f1 = MULSHIFT32(w1, in);
in = *(over0 + 768); /* from last short block */
in += *(over0 + 896); /* from last full frame */
*out0++ = in - f0;
in = *(over1 + 768); /* from last short block */
*(over1 - 128) = in + f1;
in = *buf1--;
*over1-- = MULSHIFT32(w0, in); /* save in overlap[128-191] */
*over0++ = MULSHIFT32(w1, in); /* save in overlap[64-127] */
} while (over0 < over1);
/* over0 now points at overlap[128] */
/* over[64-191] = Wc[128-255] * block4[128-255] + Wc[0-127] * block5[0-127]
* over[192-319] = Wc[128-255] * block5[128-255] + Wc[0-127] * block6[0-127]
* over[320-447] = Wc[128-255] * block6[128-255] + Wc[0-127] * block7[0-127]
* over[448-576] = Wc[128-255] * block7[128-255]
*/
for (i = 0; i < 3; i++) {
over0 += 64;
over1 = over0 + 128 - 1;
buf0 += 64;
buf1 = buf0 - 1;
wndCurr -= 128;
do {
w0 = *wndCurr++; /* W[0], W[1], ...W[63] */
w1 = *wndCurr++; /* W[127], W[126], ... W[64] */
in = *buf0++;
f0 = MULSHIFT32(w0, in);
f1 = MULSHIFT32(w1, in);
/* from last short block */
*(over0 - 128) -= f0;
*(over1 - 128)+= f1;
in = *buf1--;
*over1-- = MULSHIFT32(w0, in);
*over0++ = MULSHIFT32(w1, in);
} while (over0 < over1);
}
/* over[576-1024] = 0 */
i = 448;
over0 += 64;
do {
*over0++ = 0;
*over0++ = 0;
*over0++ = 0;
*over0++ = 0;
i -= 4;
} while (i);
}

View File

@@ -0,0 +1,195 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: sbrmath.c,v 1.1 2005/02/26 01:47:35 jrecker Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* sbrmath.c - fixed-point math functions for SBR
**************************************************************************************/
#include "sbr.h"
#include "assembly.h"
#define Q28_2 0x20000000 /* Q28: 2.0 */
#define Q28_15 0x30000000 /* Q28: 1.5 */
#define NUM_ITER_IRN 5
/**************************************************************************************
* Function: InvRNormalized
*
* Description: use Newton's method to solve for x = 1/r
*
* Inputs: r = Q31, range = [0.5, 1) (normalize your inputs to this range)
*
* Outputs: none
*
* Return: x = Q29, range ~= [1.0, 2.0]
*
* Notes: guaranteed to converge and not overflow for any r in [0.5, 1)
*
* xn+1 = xn - f(xn)/f'(xn)
* f(x) = 1/r - x = 0 (find root)
* = 1/x - r
* f'(x) = -1/x^2
*
* so xn+1 = xn - (1/xn - r) / (-1/xn^2)
* = xn * (2 - r*xn)
*
* NUM_ITER_IRN = 2, maxDiff = 6.2500e-02 (precision of about 4 bits)
* NUM_ITER_IRN = 3, maxDiff = 3.9063e-03 (precision of about 8 bits)
* NUM_ITER_IRN = 4, maxDiff = 1.5288e-05 (precision of about 16 bits)
* NUM_ITER_IRN = 5, maxDiff = 3.0034e-08 (precision of about 24 bits)
**************************************************************************************/
int InvRNormalized(int r)
{
int i, xn, t;
/* r = [0.5, 1.0)
* 1/r = (1.0, 2.0]
* so use 1.5 as initial guess
*/
xn = Q28_15;
/* xn = xn*(2.0 - r*xn) */
for (i = NUM_ITER_IRN; i != 0; i--) {
t = MULSHIFT32(r, xn); /* Q31*Q29 = Q28 */
t = Q28_2 - t; /* Q28 */
xn = MULSHIFT32(xn, t) << 4; /* Q29*Q28 << 4 = Q29 */
}
return xn;
}
#define NUM_TERMS_RPI 5
#define LOG2_EXP_INV 0x58b90bfc /* 1/log2(e), Q31 */
/* invTab[x] = 1/(x+1), format = Q30 */
static const int invTab[NUM_TERMS_RPI] PROGMEM = {0x40000000, 0x20000000, 0x15555555, 0x10000000, 0x0ccccccd};
/**************************************************************************************
* Function: RatioPowInv
*
* Description: use Taylor (MacLaurin) series expansion to calculate (a/b) ^ (1/c)
*
* Inputs: a = [1, 64], b = [1, 64], c = [1, 64], a >= b
*
* Outputs: none
*
* Return: y = Q24, range ~= [0.015625, 64]
**************************************************************************************/
int RatioPowInv(int a, int b, int c)
{
int lna, lnb, i, p, t, y;
if (a < 1 || b < 1 || c < 1 || a > 64 || b > 64 || c > 64 || a < b)
return 0;
lna = MULSHIFT32(log2Tab[a], LOG2_EXP_INV) << 1; /* ln(a), Q28 */
lnb = MULSHIFT32(log2Tab[b], LOG2_EXP_INV) << 1; /* ln(b), Q28 */
p = (lna - lnb) / c; /* Q28 */
/* sum in Q24 */
y = (1 << 24);
t = p >> 4; /* t = p^1 * 1/1! (Q24)*/
y += t;
for (i = 2; i <= NUM_TERMS_RPI; i++) {
t = MULSHIFT32(invTab[i-1], t) << 2;
t = MULSHIFT32(p, t) << 4; /* t = p^i * 1/i! (Q24) */
y += t;
}
return y;
}
/**************************************************************************************
* Function: SqrtFix
*
* Description: use binary search to calculate sqrt(q)
*
* Inputs: q = Q30
* number of fraction bits in input
*
* Outputs: number of fraction bits in output
*
* Return: lo = Q(fBitsOut)
*
* Notes: absolute precision varies depending on fBitsIn
* normalizes input to range [0x200000000, 0x7fffffff] and takes
* floor(sqrt(input)), and sets fBitsOut appropriately
**************************************************************************************/
int SqrtFix(int q, int fBitsIn, int *fBitsOut)
{
int z, lo, hi, mid;
if (q <= 0) {
*fBitsOut = fBitsIn;
return 0;
}
/* force even fBitsIn */
z = fBitsIn & 0x01;
q >>= z;
fBitsIn -= z;
/* for max precision, normalize to [0x20000000, 0x7fffffff] */
z = (CLZ(q) - 1);
z >>= 1;
q <<= (2*z);
/* choose initial bounds */
lo = 1;
if (q >= 0x10000000)
lo = 16384; /* (int)sqrt(0x10000000) */
hi = 46340; /* (int)sqrt(0x7fffffff) */
/* do binary search with 32x32->32 multiply test */
do {
mid = (lo + hi) >> 1;
if (mid*mid > q)
hi = mid - 1;
else
lo = mid + 1;
} while (hi >= lo);
lo--;
*fBitsOut = ((fBitsIn + 2*z) >> 1);
return lo;
}

View File

@@ -0,0 +1,527 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: sbrqmf.c,v 1.2 2005/05/19 20:45:20 jrecker Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* sbrqmf.c - analysis and synthesis QMF filters for SBR
**************************************************************************************/
#include "sbr.h"
#include "assembly.h"
/* PreMultiply64() table
* format = Q30
* reordered for sequential access
*
* for (i = 0; i < 64/4; i++) {
* angle = (i + 0.25) * M_PI / nmdct;
* x = (cos(angle) + sin(angle));
* x = sin(angle);
*
* angle = (nmdct/2 - 1 - i + 0.25) * M_PI / nmdct;
* x = (cos(angle) + sin(angle));
* x = sin(angle);
* }
*/
static const int cos4sin4tab64[64] PROGMEM = {
0x40c7d2bd, 0x00c90e90, 0x424ff28f, 0x3ff4e5e0, 0x43cdd89a, 0x03ecadcf, 0x454149fc, 0x3fc395f9,
0x46aa0d6d, 0x070de172, 0x4807eb4b, 0x3f6af2e3, 0x495aada2, 0x0a2abb59, 0x4aa22036, 0x3eeb3347,
0x4bde1089, 0x0d415013, 0x4d0e4de2, 0x3e44a5ef, 0x4e32a956, 0x104fb80e, 0x4f4af5d1, 0x3d77b192,
0x50570819, 0x135410c3, 0x5156b6d9, 0x3c84d496, 0x5249daa2, 0x164c7ddd, 0x53304df6, 0x3b6ca4c4,
0x5409ed4b, 0x19372a64, 0x54d69714, 0x3a2fcee8, 0x55962bc0, 0x1c1249d8, 0x56488dc5, 0x38cf1669,
0x56eda1a0, 0x1edc1953, 0x57854ddd, 0x374b54ce, 0x580f7b19, 0x2192e09b, 0x588c1404, 0x35a5793c,
0x58fb0568, 0x2434f332, 0x595c3e2a, 0x33de87de, 0x59afaf4c, 0x26c0b162, 0x59f54bee, 0x31f79948,
0x5a2d0957, 0x29348937, 0x5a56deec, 0x2ff1d9c7, 0x5a72c63b, 0x2b8ef77d, 0x5a80baf6, 0x2dce88aa,
};
/* PostMultiply64() table
* format = Q30
* reordered for sequential access
*
* for (i = 0; i <= (32/2); i++) {
* angle = i * M_PI / 64;
* x = (cos(angle) + sin(angle));
* x = sin(angle);
* }
*/
static const int cos1sin1tab64[34] PROGMEM = {
0x40000000, 0x00000000, 0x43103085, 0x0323ecbe, 0x45f704f7, 0x0645e9af, 0x48b2b335, 0x09640837,
0x4b418bbe, 0x0c7c5c1e, 0x4da1fab5, 0x0f8cfcbe, 0x4fd288dc, 0x1294062f, 0x51d1dc80, 0x158f9a76,
0x539eba45, 0x187de2a7, 0x553805f2, 0x1b5d100a, 0x569cc31b, 0x1e2b5d38, 0x57cc15bc, 0x20e70f32,
0x58c542c5, 0x238e7673, 0x5987b08a, 0x261feffa, 0x5a12e720, 0x2899e64a, 0x5a6690ae, 0x2afad269,
0x5a82799a, 0x2d413ccd,
};
/**************************************************************************************
* Function: PreMultiply64
*
* Description: pre-twiddle stage of 64-point DCT-IV
*
* Inputs: buffer of 64 samples
*
* Outputs: processed samples in same buffer
*
* Return: none
*
* Notes: minimum 1 GB in, 2 GB out, gains 2 int bits
* gbOut = gbIn + 1
* output is limited to sqrt(2)/2 plus GB in full GB
* uses 3-mul, 3-add butterflies instead of 4-mul, 2-add
**************************************************************************************/
static void PreMultiply64(int *zbuf1)
{
int i, ar1, ai1, ar2, ai2, z1, z2;
int t, cms2, cps2a, sin2a, cps2b, sin2b;
int *zbuf2;
const int *csptr;
zbuf2 = zbuf1 + 64 - 1;
csptr = cos4sin4tab64;
/* whole thing should fit in registers - verify that compiler does this */
for (i = 64 >> 2; i != 0; i--) {
/* cps2 = (cos+sin), sin2 = sin, cms2 = (cos-sin) */
cps2a = *csptr++;
sin2a = *csptr++;
cps2b = *csptr++;
sin2b = *csptr++;
ar1 = *(zbuf1 + 0);
ai2 = *(zbuf1 + 1);
ai1 = *(zbuf2 + 0);
ar2 = *(zbuf2 - 1);
/* gain 2 ints bit from MULSHIFT32 by Q30
* max per-sample gain (ignoring implicit scaling) = MAX(sin(angle)+cos(angle)) = 1.414
* i.e. gain 1 GB since worst case is sin(angle) = cos(angle) = 0.707 (Q30), gain 2 from
* extra sign bits, and eat one in adding
*/
t = MULSHIFT32(sin2a, ar1 + ai1);
z2 = MULSHIFT32(cps2a, ai1) - t;
cms2 = cps2a - 2*sin2a;
z1 = MULSHIFT32(cms2, ar1) + t;
*zbuf1++ = z1; /* cos*ar1 + sin*ai1 */
*zbuf1++ = z2; /* cos*ai1 - sin*ar1 */
t = MULSHIFT32(sin2b, ar2 + ai2);
z2 = MULSHIFT32(cps2b, ai2) - t;
cms2 = cps2b - 2*sin2b;
z1 = MULSHIFT32(cms2, ar2) + t;
*zbuf2-- = z2; /* cos*ai2 - sin*ar2 */
*zbuf2-- = z1; /* cos*ar2 + sin*ai2 */
}
}
/**************************************************************************************
* Function: PostMultiply64
*
* Description: post-twiddle stage of 64-point type-IV DCT
*
* Inputs: buffer of 64 samples
* number of output samples to calculate
*
* Outputs: processed samples in same buffer
*
* Return: none
*
* Notes: minimum 1 GB in, 2 GB out, gains 2 int bits
* gbOut = gbIn + 1
* output is limited to sqrt(2)/2 plus GB in full GB
* nSampsOut is rounded up to next multiple of 4, since we calculate
* 4 samples per loop
**************************************************************************************/
static void PostMultiply64(int *fft1, int nSampsOut)
{
int i, ar1, ai1, ar2, ai2;
int t, cms2, cps2, sin2;
int *fft2;
const int *csptr;
csptr = cos1sin1tab64;
fft2 = fft1 + 64 - 1;
/* load coeffs for first pass
* cps2 = (cos+sin)/2, sin2 = sin/2, cms2 = (cos-sin)/2
*/
cps2 = *csptr++;
sin2 = *csptr++;
cms2 = cps2 - 2*sin2;
for (i = (nSampsOut + 3) >> 2; i != 0; i--) {
ar1 = *(fft1 + 0);
ai1 = *(fft1 + 1);
ar2 = *(fft2 - 1);
ai2 = *(fft2 + 0);
/* gain 2 int bits (multiplying by Q30), max gain = sqrt(2) */
t = MULSHIFT32(sin2, ar1 + ai1);
*fft2-- = t - MULSHIFT32(cps2, ai1);
*fft1++ = t + MULSHIFT32(cms2, ar1);
cps2 = *csptr++;
sin2 = *csptr++;
ai2 = -ai2;
t = MULSHIFT32(sin2, ar2 + ai2);
*fft2-- = t - MULSHIFT32(cps2, ai2);
cms2 = cps2 - 2*sin2;
*fft1++ = t + MULSHIFT32(cms2, ar2);
}
}
/**************************************************************************************
* Function: QMFAnalysisConv
*
* Description: convolution kernel for analysis QMF
*
* Inputs: pointer to coefficient table, reordered for sequential access
* delay buffer of size 32*10 = 320 real-valued PCM samples
* index for delay ring buffer (range = [0, 9])
*
* Outputs: 64 consecutive 32-bit samples
*
* Return: none
*
* Notes: this is carefully written to be efficient on ARM
* use the assembly code version in sbrqmfak.s when building for ARM!
**************************************************************************************/
#if (defined (__arm) && defined (__ARMCC_VERSION)) || (defined (_WIN32) && defined (_WIN32_WCE) && defined (ARM)) || (defined(__GNUC__) && defined(__arm__))
#ifdef __cplusplus
extern "C"
#endif
void QMFAnalysisConv(int *cTab, int *delay, int dIdx, int *uBuf);
#else
void QMFAnalysisConv(int *cTab, int *delay, int dIdx, int *uBuf)
{
int k, dOff;
int *cPtr0, *cPtr1;
U64 u64lo, u64hi;
dOff = dIdx*32 + 31;
cPtr0 = cTab;
cPtr1 = cTab + 33*5 - 1;
/* special first pass since we need to flip sign to create cTab[384], cTab[512] */
u64lo.w64 = 0;
u64hi.w64 = 0;
u64lo.w64 = MADD64(u64lo.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;}
u64hi.w64 = MADD64(u64hi.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;}
u64lo.w64 = MADD64(u64lo.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;}
u64hi.w64 = MADD64(u64hi.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;}
u64lo.w64 = MADD64(u64lo.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;}
u64hi.w64 = MADD64(u64hi.w64, *cPtr1--, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;}
u64lo.w64 = MADD64(u64lo.w64, -(*cPtr1--), delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;}
u64hi.w64 = MADD64(u64hi.w64, *cPtr1--, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;}
u64lo.w64 = MADD64(u64lo.w64, -(*cPtr1--), delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;}
u64hi.w64 = MADD64(u64hi.w64, *cPtr1--, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;}
uBuf[0] = u64lo.r.hi32;
uBuf[32] = u64hi.r.hi32;
uBuf++;
dOff--;
/* max gain for any sample in uBuf, after scaling by cTab, ~= 0.99
* so we can just sum the uBuf values with no overflow problems
*/
for (k = 1; k <= 31; k++) {
u64lo.w64 = 0;
u64hi.w64 = 0;
u64lo.w64 = MADD64(u64lo.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;}
u64hi.w64 = MADD64(u64hi.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;}
u64lo.w64 = MADD64(u64lo.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;}
u64hi.w64 = MADD64(u64hi.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;}
u64lo.w64 = MADD64(u64lo.w64, *cPtr0++, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;}
u64hi.w64 = MADD64(u64hi.w64, *cPtr1--, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;}
u64lo.w64 = MADD64(u64lo.w64, *cPtr1--, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;}
u64hi.w64 = MADD64(u64hi.w64, *cPtr1--, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;}
u64lo.w64 = MADD64(u64lo.w64, *cPtr1--, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;}
u64hi.w64 = MADD64(u64hi.w64, *cPtr1--, delay[dOff]); dOff -= 32; if (dOff < 0) {dOff += 320;}
uBuf[0] = u64lo.r.hi32;
uBuf[32] = u64hi.r.hi32;
uBuf++;
dOff--;
}
}
#endif
/**************************************************************************************
* Function: QMFAnalysis
*
* Description: 32-subband analysis QMF (4.6.18.4.1)
*
* Inputs: 32 consecutive samples of decoded 32-bit PCM, format = Q(fBitsIn)
* delay buffer of size 32*10 = 320 PCM samples
* number of fraction bits in input PCM
* index for delay ring buffer (range = [0, 9])
* number of subbands to calculate (range = [0, 32])
*
* Outputs: qmfaBands complex subband samples, format = Q(FBITS_OUT_QMFA)
* updated delay buffer
* updated delay index
*
* Return: guard bit mask
*
* Notes: output stored as RE{X0}, IM{X0}, RE{X1}, IM{X1}, ... RE{X31}, IM{X31}
* output stored in int buffer of size 64*2 = 128
* (zero-filled from XBuf[2*qmfaBands] to XBuf[127])
**************************************************************************************/
int QMFAnalysis(int *inbuf, int *delay, int *XBuf, int fBitsIn, int *delayIdx, int qmfaBands)
{
int n, y, shift, gbMask;
int *delayPtr, *uBuf, *tBuf;
/* use XBuf[128] as temp buffer for reordering */
uBuf = XBuf; /* first 64 samples */
tBuf = XBuf + 64; /* second 64 samples */
/* overwrite oldest PCM with new PCM
* delay[n] has 1 GB after shifting (either << or >>)
*/
delayPtr = delay + (*delayIdx * 32);
if (fBitsIn > FBITS_IN_QMFA) {
shift = MIN(fBitsIn - FBITS_IN_QMFA, 31);
for (n = 32; n != 0; n--) {
y = (*inbuf) >> shift;
inbuf++;
*delayPtr++ = y;
}
} else {
shift = MIN(FBITS_IN_QMFA - fBitsIn, 30);
for (n = 32; n != 0; n--) {
y = *inbuf++;
CLIP_2N_SHIFT30(y, shift);
*delayPtr++ = y;
}
}
QMFAnalysisConv((int *)cTabA, delay, *delayIdx, uBuf);
/* uBuf has at least 2 GB right now (1 from clipping to Q(FBITS_IN_QMFA), one from
* the scaling by cTab (MULSHIFT32(*delayPtr--, *cPtr++), with net gain of < 1.0)
* TODO - fuse with QMFAnalysisConv to avoid separate reordering
*/
tBuf[2*0 + 0] = uBuf[0];
tBuf[2*0 + 1] = uBuf[1];
for (n = 1; n < 31; n++) {
tBuf[2*n + 0] = -uBuf[64-n];
tBuf[2*n + 1] = uBuf[n+1];
}
tBuf[2*31 + 1] = uBuf[32];
tBuf[2*31 + 0] = -uBuf[33];
/* fast in-place DCT-IV - only need 2*qmfaBands output samples */
PreMultiply64(tBuf); /* 2 GB in, 3 GB out */
FFT32C(tBuf); /* 3 GB in, 1 GB out */
PostMultiply64(tBuf, qmfaBands*2); /* 1 GB in, 2 GB out */
/* TODO - roll into PostMultiply (if enough registers) */
gbMask = 0;
for (n = 0; n < qmfaBands; n++) {
XBuf[2*n+0] = tBuf[ n + 0]; /* implicit scaling of 2 in our output Q format */
gbMask |= FASTABS(XBuf[2*n+0]);
XBuf[2*n+1] = -tBuf[63 - n];
gbMask |= FASTABS(XBuf[2*n+1]);
}
/* fill top section with zeros for HF generation */
for ( ; n < 64; n++) {
XBuf[2*n+0] = 0;
XBuf[2*n+1] = 0;
}
*delayIdx = (*delayIdx == NUM_QMF_DELAY_BUFS - 1 ? 0 : *delayIdx + 1);
/* minimum of 2 GB in output */
return gbMask;
}
/* lose FBITS_LOST_DCT4_64 in DCT4, gain 6 for implicit scaling by 1/64, lose 1 for cTab multiply (Q31) */
#define FBITS_OUT_QMFS (FBITS_IN_QMFS - FBITS_LOST_DCT4_64 + 6 - 1)
#define RND_VAL (1 << (FBITS_OUT_QMFS-1))
/**************************************************************************************
* Function: QMFSynthesisConv
*
* Description: final convolution kernel for synthesis QMF
*
* Inputs: pointer to coefficient table, reordered for sequential access
* delay buffer of size 64*10 = 640 complex samples (1280 ints)
* index for delay ring buffer (range = [0, 9])
* number of QMF subbands to process (range = [0, 64])
* number of channels
*
* Outputs: 64 consecutive 16-bit PCM samples, interleaved by factor of nChans
*
* Return: none
*
* Notes: this is carefully written to be efficient on ARM
* use the assembly code version in sbrqmfsk.s when building for ARM!
**************************************************************************************/
#if (defined (__arm) && defined (__ARMCC_VERSION)) || (defined (_WIN32) && defined (_WIN32_WCE) && defined (ARM)) || (defined(__GNUC__) && defined(__arm__))
#ifdef __cplusplus
extern "C"
#endif
void QMFSynthesisConv(int *cPtr, int *delay, int dIdx, short *outbuf, int nChans);
#else
void QMFSynthesisConv(int *cPtr, int *delay, int dIdx, short *outbuf, int nChans)
{
int k, dOff0, dOff1;
U64 sum64;
dOff0 = (dIdx)*128;
dOff1 = dOff0 - 1;
if (dOff1 < 0)
dOff1 += 1280;
/* scaling note: total gain of coefs (cPtr[0]-cPtr[9] for any k) is < 2.0, so 1 GB in delay values is adequate */
for (k = 0; k <= 63; k++) {
sum64.w64 = 0;
sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff0]); dOff0 -= 256; if (dOff0 < 0) {dOff0 += 1280;}
sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff1]); dOff1 -= 256; if (dOff1 < 0) {dOff1 += 1280;}
sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff0]); dOff0 -= 256; if (dOff0 < 0) {dOff0 += 1280;}
sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff1]); dOff1 -= 256; if (dOff1 < 0) {dOff1 += 1280;}
sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff0]); dOff0 -= 256; if (dOff0 < 0) {dOff0 += 1280;}
sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff1]); dOff1 -= 256; if (dOff1 < 0) {dOff1 += 1280;}
sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff0]); dOff0 -= 256; if (dOff0 < 0) {dOff0 += 1280;}
sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff1]); dOff1 -= 256; if (dOff1 < 0) {dOff1 += 1280;}
sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff0]); dOff0 -= 256; if (dOff0 < 0) {dOff0 += 1280;}
sum64.w64 = MADD64(sum64.w64, *cPtr++, delay[dOff1]); dOff1 -= 256; if (dOff1 < 0) {dOff1 += 1280;}
dOff0++;
dOff1--;
*outbuf = CLIPTOSHORT((sum64.r.hi32 + RND_VAL) >> FBITS_OUT_QMFS);
outbuf += nChans;
}
}
#endif
/**************************************************************************************
* Function: QMFSynthesis
*
* Description: 64-subband synthesis QMF (4.6.18.4.2)
*
* Inputs: 64 consecutive complex subband QMF samples, format = Q(FBITS_IN_QMFS)
* delay buffer of size 64*10 = 640 complex samples (1280 ints)
* index for delay ring buffer (range = [0, 9])
* number of QMF subbands to process (range = [0, 64])
* number of channels
*
* Outputs: 64 consecutive 16-bit PCM samples, interleaved by factor of nChans
* updated delay buffer
* updated delay index
*
* Return: none
*
* Notes: assumes MIN_GBITS_IN_QMFS guard bits in input, either from
* QMFAnalysis (if upsampling only) or from MapHF (if SBR on)
**************************************************************************************/
void QMFSynthesis(int *inbuf, int *delay, int *delayIdx, int qmfsBands, short *outbuf, int nChans)
{
int n, a0, a1, b0, b1, dOff0, dOff1, dIdx;
int *tBufLo, *tBufHi;
dIdx = *delayIdx;
tBufLo = delay + dIdx*128 + 0;
tBufHi = delay + dIdx*128 + 127;
/* reorder inputs to DCT-IV, only use first qmfsBands (complex) samples
* TODO - fuse with PreMultiply64 to avoid separate reordering steps
*/
for (n = 0; n < qmfsBands >> 1; n++) {
a0 = *inbuf++;
b0 = *inbuf++;
a1 = *inbuf++;
b1 = *inbuf++;
*tBufLo++ = a0;
*tBufLo++ = a1;
*tBufHi-- = b0;
*tBufHi-- = b1;
}
if (qmfsBands & 0x01) {
a0 = *inbuf++;
b0 = *inbuf++;
*tBufLo++ = a0;
*tBufHi-- = b0;
*tBufLo++ = 0;
*tBufHi-- = 0;
n++;
}
for ( ; n < 32; n++) {
*tBufLo++ = 0;
*tBufHi-- = 0;
*tBufLo++ = 0;
*tBufHi-- = 0;
}
tBufLo = delay + dIdx*128 + 0;
tBufHi = delay + dIdx*128 + 64;
/* 2 GB in, 3 GB out */
PreMultiply64(tBufLo);
PreMultiply64(tBufHi);
/* 3 GB in, 1 GB out */
FFT32C(tBufLo);
FFT32C(tBufHi);
/* 1 GB in, 2 GB out */
PostMultiply64(tBufLo, 64);
PostMultiply64(tBufHi, 64);
/* could fuse with PostMultiply64 to avoid separate pass */
dOff0 = dIdx*128;
dOff1 = dIdx*128 + 64;
for (n = 32; n != 0; n--) {
a0 = (*tBufLo++);
a1 = (*tBufLo++);
b0 = (*tBufHi++);
b1 = -(*tBufHi++);
delay[dOff0++] = (b0 - a0);
delay[dOff0++] = (b1 - a1);
delay[dOff1++] = (b0 + a0);
delay[dOff1++] = (b1 + a1);
}
QMFSynthesisConv((int *)cTabS, delay, dIdx, outbuf, nChans);
*delayIdx = (*delayIdx == NUM_QMF_DELAY_BUFS - 1 ? 0 : *delayIdx + 1);
}

View File

@@ -0,0 +1,575 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: sbrside.c,v 1.2 2005/05/24 16:01:55 albertofloyd Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* sbrside.c - functions for unpacking side info from SBR bitstream
**************************************************************************************/
#include "sbr.h"
/**************************************************************************************
* Function: GetSampRateIdx
*
* Description: get index of given sample rate
*
* Inputs: sample rate (in Hz)
*
* Outputs: none
*
* Return: index of sample rate (table 1.15 in 14496-3:2001(E))
* -1 if sample rate not found in table
**************************************************************************************/
int GetSampRateIdx(int sampRate)
{
int idx;
for (idx = 0; idx < NUM_SAMPLE_RATES; idx++) {
if (sampRate == sampRateTab[idx])
return idx;
}
return -1;
}
/**************************************************************************************
* Function: UnpackSBRHeader
*
* Description: unpack SBR header (table 4.56)
*
* Inputs: BitStreamInfo struct pointing to start of SBR header
*
* Outputs: initialized SBRHeader struct for this SCE/CPE block
*
* Return: non-zero if frame reset is triggered, zero otherwise
**************************************************************************************/
int UnpackSBRHeader(BitStreamInfo *bsi, SBRHeader *sbrHdr)
{
SBRHeader sbrHdrPrev;
/* save previous values so we know whether to reset decoder */
sbrHdrPrev.startFreq = sbrHdr->startFreq;
sbrHdrPrev.stopFreq = sbrHdr->stopFreq;
sbrHdrPrev.freqScale = sbrHdr->freqScale;
sbrHdrPrev.alterScale = sbrHdr->alterScale;
sbrHdrPrev.crossOverBand = sbrHdr->crossOverBand;
sbrHdrPrev.noiseBands = sbrHdr->noiseBands;
sbrHdr->ampRes = GetBits(bsi, 1);
sbrHdr->startFreq = GetBits(bsi, 4);
sbrHdr->stopFreq = GetBits(bsi, 4);
sbrHdr->crossOverBand = GetBits(bsi, 3);
sbrHdr->resBitsHdr = GetBits(bsi, 2);
sbrHdr->hdrExtra1 = GetBits(bsi, 1);
sbrHdr->hdrExtra2 = GetBits(bsi, 1);
if (sbrHdr->hdrExtra1) {
sbrHdr->freqScale = GetBits(bsi, 2);
sbrHdr->alterScale = GetBits(bsi, 1);
sbrHdr->noiseBands = GetBits(bsi, 2);
} else {
/* defaults */
sbrHdr->freqScale = 2;
sbrHdr->alterScale = 1;
sbrHdr->noiseBands = 2;
}
if (sbrHdr->hdrExtra2) {
sbrHdr->limiterBands = GetBits(bsi, 2);
sbrHdr->limiterGains = GetBits(bsi, 2);
sbrHdr->interpFreq = GetBits(bsi, 1);
sbrHdr->smoothMode = GetBits(bsi, 1);
} else {
/* defaults */
sbrHdr->limiterBands = 2;
sbrHdr->limiterGains = 2;
sbrHdr->interpFreq = 1;
sbrHdr->smoothMode = 1;
}
sbrHdr->count++;
/* if any of these have changed from previous frame, reset the SBR module */
if (sbrHdr->startFreq != sbrHdrPrev.startFreq || sbrHdr->stopFreq != sbrHdrPrev.stopFreq ||
sbrHdr->freqScale != sbrHdrPrev.freqScale || sbrHdr->alterScale != sbrHdrPrev.alterScale ||
sbrHdr->crossOverBand != sbrHdrPrev.crossOverBand || sbrHdr->noiseBands != sbrHdrPrev.noiseBands
)
return -1;
else
return 0;
}
/* cLog2[i] = ceil(log2(i)) (disregard i == 0) */
static const unsigned char cLog2[9] = {0, 0, 1, 2, 2, 3, 3, 3, 3};
/**************************************************************************************
* Function: UnpackSBRGrid
*
* Description: unpack SBR grid (table 4.62)
*
* Inputs: BitStreamInfo struct pointing to start of SBR grid
* initialized SBRHeader struct for this SCE/CPE block
*
* Outputs: initialized SBRGrid struct for this channel
*
* Return: none
**************************************************************************************/
static void UnpackSBRGrid(BitStreamInfo *bsi, SBRHeader *sbrHdr, SBRGrid *sbrGrid)
{
int numEnvRaw, env, rel, pBits, border, middleBorder=0;
unsigned char relBordLead[MAX_NUM_ENV], relBordTrail[MAX_NUM_ENV];
unsigned char relBorder0[3], relBorder1[3], relBorder[3];
unsigned char numRelBorder0, numRelBorder1, numRelBorder, numRelLead=0, numRelTrail;
unsigned char absBordLead=0, absBordTrail=0, absBorder;
sbrGrid->ampResFrame = sbrHdr->ampRes;
sbrGrid->frameClass = GetBits(bsi, 2);
switch (sbrGrid->frameClass) {
case SBR_GRID_FIXFIX:
numEnvRaw = GetBits(bsi, 2);
sbrGrid->numEnv = (1 << numEnvRaw);
if (sbrGrid->numEnv == 1)
sbrGrid->ampResFrame = 0;
ASSERT(sbrGrid->numEnv == 1 || sbrGrid->numEnv == 2 || sbrGrid->numEnv == 4);
sbrGrid->freqRes[0] = GetBits(bsi, 1);
for (env = 1; env < sbrGrid->numEnv; env++)
sbrGrid->freqRes[env] = sbrGrid->freqRes[0];
absBordLead = 0;
absBordTrail = NUM_TIME_SLOTS;
numRelLead = sbrGrid->numEnv - 1;
numRelTrail = 0;
/* numEnv = 1, 2, or 4 */
if (sbrGrid->numEnv == 1) border = NUM_TIME_SLOTS / 1;
else if (sbrGrid->numEnv == 2) border = NUM_TIME_SLOTS / 2;
else border = NUM_TIME_SLOTS / 4;
for (rel = 0; rel < numRelLead; rel++)
relBordLead[rel] = border;
middleBorder = (sbrGrid->numEnv >> 1);
break;
case SBR_GRID_FIXVAR:
absBorder = GetBits(bsi, 2) + NUM_TIME_SLOTS;
numRelBorder = GetBits(bsi, 2);
sbrGrid->numEnv = numRelBorder + 1;
for (rel = 0; rel < numRelBorder; rel++)
relBorder[rel] = 2*GetBits(bsi, 2) + 2;
pBits = cLog2[sbrGrid->numEnv + 1];
sbrGrid->pointer = GetBits(bsi, pBits);
for (env = sbrGrid->numEnv - 1; env >= 0; env--)
sbrGrid->freqRes[env] = GetBits(bsi, 1);
absBordLead = 0;
absBordTrail = absBorder;
numRelLead = 0;
numRelTrail = numRelBorder;
for (rel = 0; rel < numRelTrail; rel++)
relBordTrail[rel] = relBorder[rel];
if (sbrGrid->pointer > 1) middleBorder = sbrGrid->numEnv + 1 - sbrGrid->pointer;
else middleBorder = sbrGrid->numEnv - 1;
break;
case SBR_GRID_VARFIX:
absBorder = GetBits(bsi, 2);
numRelBorder = GetBits(bsi, 2);
sbrGrid->numEnv = numRelBorder + 1;
for (rel = 0; rel < numRelBorder; rel++)
relBorder[rel] = 2*GetBits(bsi, 2) + 2;
pBits = cLog2[sbrGrid->numEnv + 1];
sbrGrid->pointer = GetBits(bsi, pBits);
for (env = 0; env < sbrGrid->numEnv; env++)
sbrGrid->freqRes[env] = GetBits(bsi, 1);
absBordLead = absBorder;
absBordTrail = NUM_TIME_SLOTS;
numRelLead = numRelBorder;
numRelTrail = 0;
for (rel = 0; rel < numRelLead; rel++)
relBordLead[rel] = relBorder[rel];
if (sbrGrid->pointer == 0) middleBorder = 1;
else if (sbrGrid->pointer == 1) middleBorder = sbrGrid->numEnv - 1;
else middleBorder = sbrGrid->pointer - 1;
break;
case SBR_GRID_VARVAR:
absBordLead = GetBits(bsi, 2); /* absBorder0 */
absBordTrail = GetBits(bsi, 2) + NUM_TIME_SLOTS; /* absBorder1 */
numRelBorder0 = GetBits(bsi, 2);
numRelBorder1 = GetBits(bsi, 2);
sbrGrid->numEnv = numRelBorder0 + numRelBorder1 + 1;
ASSERT(sbrGrid->numEnv <= 5);
for (rel = 0; rel < numRelBorder0; rel++)
relBorder0[rel] = 2*GetBits(bsi, 2) + 2;
for (rel = 0; rel < numRelBorder1; rel++)
relBorder1[rel] = 2*GetBits(bsi, 2) + 2;
pBits = cLog2[numRelBorder0 + numRelBorder1 + 2];
sbrGrid->pointer = GetBits(bsi, pBits);
for (env = 0; env < sbrGrid->numEnv; env++)
sbrGrid->freqRes[env] = GetBits(bsi, 1);
numRelLead = numRelBorder0;
numRelTrail = numRelBorder1;
for (rel = 0; rel < numRelLead; rel++)
relBordLead[rel] = relBorder0[rel];
for (rel = 0; rel < numRelTrail; rel++)
relBordTrail[rel] = relBorder1[rel];
if (sbrGrid->pointer > 1) middleBorder = sbrGrid->numEnv + 1 - sbrGrid->pointer;
else middleBorder = sbrGrid->numEnv - 1;
break;
}
/* build time border vector */
sbrGrid->envTimeBorder[0] = absBordLead * SAMPLES_PER_SLOT;
rel = 0;
border = absBordLead;
for (env = 1; env <= numRelLead; env++) {
border += relBordLead[rel++];
sbrGrid->envTimeBorder[env] = border * SAMPLES_PER_SLOT;
}
rel = 0;
border = absBordTrail;
for (env = sbrGrid->numEnv - 1; env > numRelLead; env--) {
border -= relBordTrail[rel++];
sbrGrid->envTimeBorder[env] = border * SAMPLES_PER_SLOT;
}
sbrGrid->envTimeBorder[sbrGrid->numEnv] = absBordTrail * SAMPLES_PER_SLOT;
if (sbrGrid->numEnv > 1) {
sbrGrid->numNoiseFloors = 2;
sbrGrid->noiseTimeBorder[0] = sbrGrid->envTimeBorder[0];
sbrGrid->noiseTimeBorder[1] = sbrGrid->envTimeBorder[middleBorder];
sbrGrid->noiseTimeBorder[2] = sbrGrid->envTimeBorder[sbrGrid->numEnv];
} else {
sbrGrid->numNoiseFloors = 1;
sbrGrid->noiseTimeBorder[0] = sbrGrid->envTimeBorder[0];
sbrGrid->noiseTimeBorder[1] = sbrGrid->envTimeBorder[1];
}
}
/**************************************************************************************
* Function: UnpackDeltaTimeFreq
*
* Description: unpack time/freq flags for delta coding of SBR envelopes (table 4.63)
*
* Inputs: BitStreamInfo struct pointing to start of dt/df flags
* number of envelopes
* number of noise floors
*
* Outputs: delta flags for envelope and noise floors
*
* Return: none
**************************************************************************************/
static void UnpackDeltaTimeFreq(BitStreamInfo *bsi, int numEnv, unsigned char *deltaFlagEnv,
int numNoiseFloors, unsigned char *deltaFlagNoise)
{
int env, noiseFloor;
for (env = 0; env < numEnv; env++)
deltaFlagEnv[env] = GetBits(bsi, 1);
for (noiseFloor = 0; noiseFloor < numNoiseFloors; noiseFloor++)
deltaFlagNoise[noiseFloor] = GetBits(bsi, 1);
}
/**************************************************************************************
* Function: UnpackInverseFilterMode
*
* Description: unpack invf flags for chirp factor calculation (table 4.64)
*
* Inputs: BitStreamInfo struct pointing to start of invf flags
* number of noise floor bands
*
* Outputs: invf flags for noise floor bands
*
* Return: none
**************************************************************************************/
static void UnpackInverseFilterMode(BitStreamInfo *bsi, int numNoiseFloorBands, unsigned char *mode)
{
int n;
for (n = 0; n < numNoiseFloorBands; n++)
mode[n] = GetBits(bsi, 2);
}
/**************************************************************************************
* Function: UnpackSinusoids
*
* Description: unpack sinusoid (harmonic) flags for each SBR subband (table 4.67)
*
* Inputs: BitStreamInfo struct pointing to start of sinusoid flags
* number of high resolution SBR subbands (nHigh)
*
* Outputs: sinusoid flags for each SBR subband, zero-filled above nHigh
*
* Return: none
**************************************************************************************/
static void UnpackSinusoids(BitStreamInfo *bsi, int nHigh, int addHarmonicFlag, unsigned char *addHarmonic)
{
int n;
n = 0;
if (addHarmonicFlag) {
for ( ; n < nHigh; n++)
addHarmonic[n] = GetBits(bsi, 1);
}
/* zero out unused bands */
for ( ; n < MAX_QMF_BANDS; n++)
addHarmonic[n] = 0;
}
/**************************************************************************************
* Function: CopyCouplingGrid
*
* Description: copy grid parameters from left to right for channel coupling
*
* Inputs: initialized SBRGrid struct for left channel
*
* Outputs: initialized SBRGrid struct for right channel
*
* Return: none
**************************************************************************************/
static void CopyCouplingGrid(SBRGrid *sbrGridLeft, SBRGrid *sbrGridRight)
{
int env, noiseFloor;
sbrGridRight->frameClass = sbrGridLeft->frameClass;
sbrGridRight->ampResFrame = sbrGridLeft->ampResFrame;
sbrGridRight->pointer = sbrGridLeft->pointer;
sbrGridRight->numEnv = sbrGridLeft->numEnv;
for (env = 0; env < sbrGridLeft->numEnv; env++) {
sbrGridRight->envTimeBorder[env] = sbrGridLeft->envTimeBorder[env];
sbrGridRight->freqRes[env] = sbrGridLeft->freqRes[env];
}
sbrGridRight->envTimeBorder[env] = sbrGridLeft->envTimeBorder[env]; /* borders are [0, numEnv] inclusive */
sbrGridRight->numNoiseFloors = sbrGridLeft->numNoiseFloors;
for (noiseFloor = 0; noiseFloor <= sbrGridLeft->numNoiseFloors; noiseFloor++)
sbrGridRight->noiseTimeBorder[noiseFloor] = sbrGridLeft->noiseTimeBorder[noiseFloor];
/* numEnvPrev, numNoiseFloorsPrev, freqResPrev are updated in DecodeSBREnvelope() and DecodeSBRNoise() */
}
/**************************************************************************************
* Function: CopyCouplingInverseFilterMode
*
* Description: copy invf flags from left to right for channel coupling
*
* Inputs: invf flags for left channel
* number of noise floor bands
*
* Outputs: invf flags for right channel
*
* Return: none
**************************************************************************************/
static void CopyCouplingInverseFilterMode(int numNoiseFloorBands, unsigned char *modeLeft, unsigned char *modeRight)
{
int band;
for (band = 0; band < numNoiseFloorBands; band++)
modeRight[band] = modeLeft[band];
}
/**************************************************************************************
* Function: UnpackSBRSingleChannel
*
* Description: unpack sideband info (grid, delta flags, invf flags, envelope and
* noise floor configuration, sinusoids) for a single channel
*
* Inputs: BitStreamInfo struct pointing to start of sideband info
* initialized PSInfoSBR struct (after parsing SBR header and building
* frequency tables)
* base output channel (range = [0, nChans-1])
*
* Outputs: updated PSInfoSBR struct (SBRGrid and SBRChan)
*
* Return: none
**************************************************************************************/
void UnpackSBRSingleChannel(BitStreamInfo *bsi, PSInfoSBR *psi, int chBase)
{
int bitsLeft;
SBRHeader *sbrHdr = &(psi->sbrHdr[chBase]);
SBRGrid *sbrGridL = &(psi->sbrGrid[chBase+0]);
SBRFreq *sbrFreq = &(psi->sbrFreq[chBase]);
SBRChan *sbrChanL = &(psi->sbrChan[chBase+0]);
psi->dataExtra = GetBits(bsi, 1);
if (psi->dataExtra)
psi->resBitsData = GetBits(bsi, 4);
UnpackSBRGrid(bsi, sbrHdr, sbrGridL);
UnpackDeltaTimeFreq(bsi, sbrGridL->numEnv, sbrChanL->deltaFlagEnv, sbrGridL->numNoiseFloors, sbrChanL->deltaFlagNoise);
UnpackInverseFilterMode(bsi, sbrFreq->numNoiseFloorBands, sbrChanL->invfMode[1]);
DecodeSBREnvelope(bsi, psi, sbrGridL, sbrFreq, sbrChanL, 0);
DecodeSBRNoise(bsi, psi, sbrGridL, sbrFreq, sbrChanL, 0);
sbrChanL->addHarmonicFlag[1] = GetBits(bsi, 1);
UnpackSinusoids(bsi, sbrFreq->nHigh, sbrChanL->addHarmonicFlag[1], sbrChanL->addHarmonic[1]);
psi->extendedDataPresent = GetBits(bsi, 1);
if (psi->extendedDataPresent) {
psi->extendedDataSize = GetBits(bsi, 4);
if (psi->extendedDataSize == 15)
psi->extendedDataSize += GetBits(bsi, 8);
bitsLeft = 8 * psi->extendedDataSize;
/* get ID, unpack extension info, do whatever is necessary with it... */
while (bitsLeft > 0) {
GetBits(bsi, 8);
bitsLeft -= 8;
}
}
}
/**************************************************************************************
* Function: UnpackSBRChannelPair
*
* Description: unpack sideband info (grid, delta flags, invf flags, envelope and
* noise floor configuration, sinusoids) for a channel pair
*
* Inputs: BitStreamInfo struct pointing to start of sideband info
* initialized PSInfoSBR struct (after parsing SBR header and building
* frequency tables)
* base output channel (range = [0, nChans-1])
*
* Outputs: updated PSInfoSBR struct (SBRGrid and SBRChan for both channels)
*
* Return: none
**************************************************************************************/
void UnpackSBRChannelPair(BitStreamInfo *bsi, PSInfoSBR *psi, int chBase)
{
int bitsLeft;
SBRHeader *sbrHdr = &(psi->sbrHdr[chBase]);
SBRGrid *sbrGridL = &(psi->sbrGrid[chBase+0]), *sbrGridR = &(psi->sbrGrid[chBase+1]);
SBRFreq *sbrFreq = &(psi->sbrFreq[chBase]);
SBRChan *sbrChanL = &(psi->sbrChan[chBase+0]), *sbrChanR = &(psi->sbrChan[chBase+1]);
psi->dataExtra = GetBits(bsi, 1);
if (psi->dataExtra) {
psi->resBitsData = GetBits(bsi, 4);
psi->resBitsData = GetBits(bsi, 4);
}
psi->couplingFlag = GetBits(bsi, 1);
if (psi->couplingFlag) {
UnpackSBRGrid(bsi, sbrHdr, sbrGridL);
CopyCouplingGrid(sbrGridL, sbrGridR);
UnpackDeltaTimeFreq(bsi, sbrGridL->numEnv, sbrChanL->deltaFlagEnv, sbrGridL->numNoiseFloors, sbrChanL->deltaFlagNoise);
UnpackDeltaTimeFreq(bsi, sbrGridR->numEnv, sbrChanR->deltaFlagEnv, sbrGridR->numNoiseFloors, sbrChanR->deltaFlagNoise);
UnpackInverseFilterMode(bsi, sbrFreq->numNoiseFloorBands, sbrChanL->invfMode[1]);
CopyCouplingInverseFilterMode(sbrFreq->numNoiseFloorBands, sbrChanL->invfMode[1], sbrChanR->invfMode[1]);
DecodeSBREnvelope(bsi, psi, sbrGridL, sbrFreq, sbrChanL, 0);
DecodeSBRNoise(bsi, psi, sbrGridL, sbrFreq, sbrChanL, 0);
DecodeSBREnvelope(bsi, psi, sbrGridR, sbrFreq, sbrChanR, 1);
DecodeSBRNoise(bsi, psi, sbrGridR, sbrFreq, sbrChanR, 1);
/* pass RIGHT sbrChan struct */
UncoupleSBREnvelope(psi, sbrGridL, sbrFreq, sbrChanR);
UncoupleSBRNoise(psi, sbrGridL, sbrFreq, sbrChanR);
} else {
UnpackSBRGrid(bsi, sbrHdr, sbrGridL);
UnpackSBRGrid(bsi, sbrHdr, sbrGridR);
UnpackDeltaTimeFreq(bsi, sbrGridL->numEnv, sbrChanL->deltaFlagEnv, sbrGridL->numNoiseFloors, sbrChanL->deltaFlagNoise);
UnpackDeltaTimeFreq(bsi, sbrGridR->numEnv, sbrChanR->deltaFlagEnv, sbrGridR->numNoiseFloors, sbrChanR->deltaFlagNoise);
UnpackInverseFilterMode(bsi, sbrFreq->numNoiseFloorBands, sbrChanL->invfMode[1]);
UnpackInverseFilterMode(bsi, sbrFreq->numNoiseFloorBands, sbrChanR->invfMode[1]);
DecodeSBREnvelope(bsi, psi, sbrGridL, sbrFreq, sbrChanL, 0);
DecodeSBREnvelope(bsi, psi, sbrGridR, sbrFreq, sbrChanR, 1);
DecodeSBRNoise(bsi, psi, sbrGridL, sbrFreq, sbrChanL, 0);
DecodeSBRNoise(bsi, psi, sbrGridR, sbrFreq, sbrChanR, 1);
}
sbrChanL->addHarmonicFlag[1] = GetBits(bsi, 1);
UnpackSinusoids(bsi, sbrFreq->nHigh, sbrChanL->addHarmonicFlag[1], sbrChanL->addHarmonic[1]);
sbrChanR->addHarmonicFlag[1] = GetBits(bsi, 1);
UnpackSinusoids(bsi, sbrFreq->nHigh, sbrChanR->addHarmonicFlag[1], sbrChanR->addHarmonic[1]);
psi->extendedDataPresent = GetBits(bsi, 1);
if (psi->extendedDataPresent) {
psi->extendedDataSize = GetBits(bsi, 4);
if (psi->extendedDataSize == 15)
psi->extendedDataSize += GetBits(bsi, 8);
bitsLeft = 8 * psi->extendedDataSize;
/* get ID, unpack extension info, do whatever is necessary with it... */
while (bitsLeft > 0) {
GetBits(bsi, 8);
bitsLeft -= 8;
}
}
}

View File

@@ -0,0 +1,400 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: sbrtabs.c,v 1.1 2005/02/26 01:47:35 jrecker Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* sbrtabs.c - platform-independent tables for SBR (global, read-only)
**************************************************************************************/
#include "sbr.h"
/* k0Tab[sampRateIdx][k] = k0 = startMin + offset(bs_start_freq) for given sample rate (4.6.18.3.2.1)
* downsampled (single-rate) SBR not currently supported
*/
const unsigned char k0Tab[NUM_SAMPLE_RATES_SBR][16] = {
{ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 23, 27, 31 }, /* 96 kHz */
{ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 23, 27, 31 }, /* 88 kHz */
{ 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 19, 21, 23, 26, 30 }, /* 64 kHz */
{ 7, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 22, 24, 27, 31 }, /* 48 kHz */
{ 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 23, 25, 28, 32 }, /* 44 kHz */
{ 10, 12, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 27, 29, 32 }, /* 32 kHz */
{ 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 25, 27, 29, 32 }, /* 24 kHz */
{ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26, 28, 30 }, /* 22 kHz */
{ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }, /* 16 kHz */
};
/* k2Tab[sampRateIdx][k] = stopVector(bs_stop_freq) for given sample rate, bs_stop_freq = [0, 13] (4.6.18.3.2.1)
* generated with Matlab script calc_stopvec.m
* downsampled (single-rate) SBR not currently supported
*/
const unsigned char k2Tab[NUM_SAMPLE_RATES_SBR][14] = {
{ 13, 15, 17, 19, 21, 24, 27, 31, 35, 39, 44, 50, 57, 64 }, /* 96 kHz */
{ 15, 17, 19, 21, 23, 26, 29, 33, 37, 41, 46, 51, 57, 64 }, /* 88 kHz */
{ 20, 22, 24, 26, 28, 31, 34, 37, 41, 45, 49, 54, 59, 64 }, /* 64 kHz */
{ 21, 23, 25, 27, 29, 32, 35, 38, 41, 45, 49, 54, 59, 64 }, /* 48 kHz */
{ 23, 25, 27, 29, 31, 34, 37, 40, 43, 47, 51, 55, 59, 64 }, /* 44 kHz */
{ 32, 34, 36, 38, 40, 42, 44, 46, 49, 52, 55, 58, 61, 64 }, /* 32 kHz */
{ 32, 34, 36, 38, 40, 42, 44, 46, 49, 52, 55, 58, 61, 64 }, /* 24 kHz */
{ 35, 36, 38, 40, 42, 44, 46, 48, 50, 52, 55, 58, 61, 64 }, /* 22 kHz */
{ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 60, 62, 64 }, /* 16 kHz */
};
/* NINT(2.048E6 / Fs) (figure 4.47)
* downsampled (single-rate) SBR not currently supported
*/
const unsigned char goalSBTab[NUM_SAMPLE_RATES_SBR] = {
21, 23, 32, 43, 46, 64, 85, 93, 128
};
const HuffInfo huffTabSBRInfo[10] PROGMEM = {
{19, { 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 2, 7, 4, 8, 72, 0}, 0},
{20, { 0, 2, 2, 2, 2, 2, 1, 3, 3, 2, 4, 4, 4, 3, 2, 5, 6, 13, 15, 46}, 121},
{17, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 0, 0, 1, 25, 10, 0, 0, 0}, 242},
{19, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 3, 1, 0, 1, 1, 2, 1, 29, 2, 0}, 291},
{19, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 1, 2, 5, 1, 4, 2, 3, 34, 0}, 340},
{20, { 1, 1, 1, 1, 1, 1, 0, 2, 2, 2, 2, 2, 1, 2, 3, 4, 4, 7, 10, 16}, 403},
{14, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 13, 2, 0, 0, 0, 0, 0, 0}, 466},
{14, { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 6, 8, 0, 0, 0, 0, 0, 0}, 491},
{14, { 1, 1, 1, 1, 1, 1, 0, 2, 0, 1, 1, 0, 51, 2, 0, 0, 0, 0, 0, 0}, 516},
{ 8, { 1, 1, 1, 0, 1, 1, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 579},
};
/* Huffman tables from appendix 4.A.6.1, includes offset of -LAV[i] for table i */
const signed int /*short*/ huffTabSBR[604] PROGMEM = {
/* SBR table sbr_tenv15 [121] (signed) */
0, -1, 1, -2, 2, -3, 3, -4, 4, -5, 5, -6, 6, -7, 7, -8,
-9, 8, -10, 9, -11, 10, -12, -13, 11, -14, 12, -15, -16, 13, -19, -18,
-17, 14, -24, -20, 16, -26, -21, 15, -23, -25, -22, -60, -59, -58, -57, -56,
-55, -54, -53, -52, -51, -50, -49, -48, -47, -46, -45, -44, -43, -42, -41, -40,
-39, -38, -37, -36, -35, -34, -33, -32, -31, -30, -29, -28, -27, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
52, 53, 54, 55, 56, 57, 58, 59, 60,
/* SBR table sbr_fenv15 [121] (signed) */
0, -1, 1, -2, -3, 2, -4, 3, -5, 4, -6, 5, -7, 6, -8, 7,
-9, 8, -10, 9, -11, 10, 11, -12, 12, -13, 13, 14, -14, -15, 15, 16,
17, -16, -17, -18, -19, 18, 19, -20, -21, 20, 21, -24, -23, -22, -26, -28,
22, 23, 25, -41, -25, 26, 27, -30, -27, 24, 28, 44, -51, -46, -44, -43,
-37, -33, -31, -29, 30, 37, 42, 47, 48, -60, -59, -58, -57, -56, -55, -54,
-53, -52, -50, -49, -48, -47, -45, -42, -40, -39, -38, -36, -35, -34, -32, 29,
31, 32, 33, 34, 35, 36, 38, 39, 40, 41, 43, 45, 46, 49, 50, 51,
52, 53, 54, 55, 56, 57, 58, 59, 60,
/* SBR table sbr_tenv15b [49] (signed) */
0, 1, -1, 2, -2, 3, -3, 4, -4, -5, 5, -6, 6, 7, -7, 8,
-24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9,
-8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24,
/* SBR table sbr_fenv15b [49] (signed) */
0, -1, 1, -2, 2, 3, -3, -4, 4, -5, 5, -6, 6, -7, 7, 8,
-9, -8, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11,
-10, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24,
/* SBR table sbr_tenv30 [63] (signed) */
0, -1, 1, -2, 2, -3, 3, -4, 4, -5, 5, -6, -7, 6, -8, 7,
-9, -10, 8, 9, 10, -13, -11, -12, -14, 11, 12, -31, -30, -29, -28, -27,
-26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
/* SBR table sbr_fenv30 [63] (signed) */
0, -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, 15, -14, 18,
-18, -24, -19, 16, 17, -22, -21, -16, 20, 21, 22, 25, -23, -20, 24, -31,
-30, -29, -28, -27, -26, -25, -17, 19, 23, 26, 27, 28, 29, 30, 31,
/* SBR table sbr_tenv30b [25] (signed) */
0, 1, -1, -2, 2, 3, -3, -4, 4, -5, -12, -11, -10, -9, -8, -7,
-6, 5, 6, 7, 8, 9, 10, 11, 12,
/* SBR table sbr_fenv30b [25] (signed) */
0, -1, 1, -2, 2, 3, -3, -4, 4, -5, 5, 6, -12, -11, -10, -9,
-8, -7, -6, 7, 8, 9, 10, 11, 12,
/* SBR table sbr_tnoise30 [63] (signed) */
0, 1, -1, -2, 2, -3, 3, -4, 4, -5, 5, 11, -31, -30, -29, -28,
-27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12,
-11, -10, -9, -8, -7, -6, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
/* SBR table sbr_tnoise30b [25] (signed) */
0, -1, 1, -2, 2, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, 3,
4, 5, 6, 7, 8, 9, 10, 11, 12,
};
/* log2Tab[x] = floor(log2(x)), format = Q28 */
const int log2Tab[65] PROGMEM = {
0x00000000, 0x00000000, 0x10000000, 0x195c01a3, 0x20000000, 0x25269e12, 0x295c01a3, 0x2ceaecfe,
0x30000000, 0x32b80347, 0x35269e12, 0x3759d4f8, 0x395c01a3, 0x3b350047, 0x3ceaecfe, 0x3e829fb6,
0x40000000, 0x41663f6f, 0x42b80347, 0x43f782d7, 0x45269e12, 0x4646eea2, 0x4759d4f8, 0x48608280,
0x495c01a3, 0x4a4d3c25, 0x4b350047, 0x4c1404ea, 0x4ceaecfe, 0x4dba4a47, 0x4e829fb6, 0x4f446359,
0x50000000, 0x50b5d69b, 0x51663f6f, 0x52118b11, 0x52b80347, 0x5359ebc5, 0x53f782d7, 0x549101ea,
0x55269e12, 0x55b88873, 0x5646eea2, 0x56d1fafd, 0x5759d4f8, 0x57dea15a, 0x58608280, 0x58df988f,
0x595c01a3, 0x59d5d9fd, 0x5a4d3c25, 0x5ac24113, 0x5b350047, 0x5ba58feb, 0x5c1404ea, 0x5c80730b,
0x5ceaecfe, 0x5d53847a, 0x5dba4a47, 0x5e1f4e51, 0x5e829fb6, 0x5ee44cd5, 0x5f446359, 0x5fa2f045,
0x60000000
};
/* coefficient table 4.A.87, format = Q31
* reordered as:
* cTab[0], cTab[64], cTab[128], cTab[192], cTab[256],
* cTab[2], cTab[66], cTab[130], cTab[194], cTab[258],
* ...
* cTab[64], cTab[128], cTab[192], cTab[256], cTab[320]
*
* NOTE: cTab[1, 2, ... , 318, 319] = cTab[639, 638, ... 322, 321]
* except cTab[384] = -cTab[256], cTab[512] = -cTab[128]
*/
const int cTabA[165] PROGMEM = {
0x00000000, 0x0055dba1, 0x01b2e41d, 0x09015651, 0x2e3a7532, 0xffed978a, 0x006090c4, 0x01fd3ba0, 0x08a24899, 0x311af3a4,
0xfff0065d, 0x006b47fa, 0x024bf7a1, 0x082f552e, 0x33ff670e, 0xffef7b8b, 0x0075fded, 0x029e35b4, 0x07a8127d, 0x36e69691,
0xffee1650, 0x00807994, 0x02f3e48d, 0x070bbf58, 0x39ce0477, 0xffecc31b, 0x008a7dd7, 0x034d01f0, 0x06593912, 0x3cb41219,
0xffeb50b2, 0x009424c6, 0x03a966bb, 0x0590a67d, 0x3f962fb8, 0xffe9ca76, 0x009d10bf, 0x04083fec, 0x04b0adcb, 0x4272a385,
0xffe88ba8, 0x00a520bb, 0x04694101, 0x03b8f8dc, 0x4547daea, 0xffe79e16, 0x00abe79e, 0x04cc2fcf, 0x02a99097, 0x4812f848,
0xffe6d466, 0x00b1978d, 0x05303f87, 0x01816e06, 0x4ad237a2, 0xffe65416, 0x00b5c867, 0x05950122, 0x0040c496, 0x4d83976c,
0xffe66dd0, 0x00b8394b, 0x05f9c051, 0xfee723c6, 0x5024d70e, 0xffe69423, 0x00b8c6b0, 0x065dd56a, 0xfd7475d8, 0x52b449de,
0xffe75361, 0x00b73ab0, 0x06c0f0c0, 0xfbe8f5bd, 0x552f8ff7, 0xffe85b4b, 0x00b36acd, 0x0721bf22, 0xfa44a069, 0x579505f5,
0xffea353a, 0x00acbd2f, 0x077fedb3, 0xf887507c, 0x59e2f69e, 0xffec8409, 0x00a3508f, 0x07da2b7f, 0xf6b1f3c3, 0x5c16d0ae,
0xffef2395, 0x0096dcc2, 0x08303897, 0xf4c473c6, 0x5e2f6367, 0xfff294c3, 0x00872c63, 0x0880ffdd, 0xf2bf6ea4, 0x602b0c7f,
0xfff681d6, 0x007400b8, 0x08cb4e23, 0xf0a3959f, 0x6207f220, 0xfffb42b0, 0x005d36df, 0x090ec1fc, 0xee71b2fe, 0x63c45243,
0x00007134, 0x00426f36, 0x0949eaac, 0xec2a3f5f, 0x655f63f2, 0x0006b1cf, 0x0023b989, 0x097c1ee8, 0xe9cea84a, 0x66d76725,
0x000d31b5, 0x0000e790, 0x09a3e163, 0xe75f8bb8, 0x682b39a4, 0x001471f8, 0xffda17f2, 0x09c0e59f, 0xe4de0cb0, 0x6959709d,
0x001c3549, 0xffaea5d6, 0x09d19ca9, 0xe24b8f66, 0x6a619c5e, 0x0024dd50, 0xff7ee3f1, 0x09d5560b, 0xdfa93ab5, 0x6b42a864,
0x002d8e42, 0xff4aabc8, 0x09caeb0f, 0xdcf898fb, 0x6bfbdd98, 0x003745f9, 0xff120d70, 0x09b18a1d, 0xda3b176a, 0x6c8c4c7a,
0x004103f4, 0xfed4bec3, 0x09881dc5, 0xd7722f04, 0x6cf4073e, 0x004b6c46, 0xfe933dc0, 0x094d7ec2, 0xd49fd55f, 0x6d32730f,
0x0055dba1, 0x01b2e41d, 0x09015651, 0x2e3a7532, 0x6d474e1d,
};
/* coefficient table 4.A.87, format = Q31
* reordered as cTab[0], cTab[64], cTab[128], ... cTab[576], cTab[1], cTab[65], cTab[129], ... cTab[639]
* keeping full table (not using symmetry) to allow sequential access in synth filter inner loop
* format = Q31
*/
const int cTabS[640] PROGMEM = {
0x00000000, 0x0055dba1, 0x01b2e41d, 0x09015651, 0x2e3a7532, 0x6d474e1d, 0xd1c58ace, 0x09015651, 0xfe4d1be3, 0x0055dba1,
0xffede50e, 0x005b5371, 0x01d78bfc, 0x08d3e41b, 0x2faa221c, 0x6d41d963, 0xd3337b3d, 0x09299ead, 0xfe70b8d1, 0x0050b177,
0xffed978a, 0x006090c4, 0x01fd3ba0, 0x08a24899, 0x311af3a4, 0x6d32730f, 0xd49fd55f, 0x094d7ec2, 0xfe933dc0, 0x004b6c46,
0xffefc9b9, 0x0065fde5, 0x02244a24, 0x086b1eeb, 0x328cc6f0, 0x6d18520e, 0xd60a46e5, 0x096d0e21, 0xfeb48d0d, 0x00465348,
0xfff0065d, 0x006b47fa, 0x024bf7a1, 0x082f552e, 0x33ff670e, 0x6cf4073e, 0xd7722f04, 0x09881dc5, 0xfed4bec3, 0x004103f4,
0xffeff6ca, 0x0070c8a5, 0x0274ba43, 0x07ee507c, 0x3572ec70, 0x6cc59bab, 0xd8d7f21f, 0x099ec3dc, 0xfef3f6ab, 0x003c1fa4,
0xffef7b8b, 0x0075fded, 0x029e35b4, 0x07a8127d, 0x36e69691, 0x6c8c4c7a, 0xda3b176a, 0x09b18a1d, 0xff120d70, 0x003745f9,
0xffeedfa4, 0x007b3875, 0x02c89901, 0x075ca90c, 0x385a49c4, 0x6c492217, 0xdb9b5b12, 0x09c018ce, 0xff2ef725, 0x00329ab6,
0xffee1650, 0x00807994, 0x02f3e48d, 0x070bbf58, 0x39ce0477, 0x6bfbdd98, 0xdcf898fb, 0x09caeb0f, 0xff4aabc8, 0x002d8e42,
0xffed651d, 0x0085c217, 0x03201116, 0x06b559c3, 0x3b415115, 0x6ba4629f, 0xde529086, 0x09d1fa23, 0xff6542d1, 0x00293718,
0xffecc31b, 0x008a7dd7, 0x034d01f0, 0x06593912, 0x3cb41219, 0x6b42a864, 0xdfa93ab5, 0x09d5560b, 0xff7ee3f1, 0x0024dd50,
0xffebe77b, 0x008f4bfc, 0x037ad438, 0x05f7fb90, 0x3e25b17e, 0x6ad73e8d, 0xe0fc421e, 0x09d52709, 0xff975c01, 0x002064f8,
0xffeb50b2, 0x009424c6, 0x03a966bb, 0x0590a67d, 0x3f962fb8, 0x6a619c5e, 0xe24b8f66, 0x09d19ca9, 0xffaea5d6, 0x001c3549,
0xffea9192, 0x0098b855, 0x03d8afe6, 0x05237f9d, 0x41058bc6, 0x69e29784, 0xe396a45d, 0x09cab9f2, 0xffc4e365, 0x0018703f,
0xffe9ca76, 0x009d10bf, 0x04083fec, 0x04b0adcb, 0x4272a385, 0x6959709d, 0xe4de0cb0, 0x09c0e59f, 0xffda17f2, 0x001471f8,
0xffe940f4, 0x00a1039c, 0x043889c6, 0x0437fb0a, 0x43de620a, 0x68c7269b, 0xe620c476, 0x09b3d77f, 0xffee183b, 0x0010bc63,
0xffe88ba8, 0x00a520bb, 0x04694101, 0x03b8f8dc, 0x4547daea, 0x682b39a4, 0xe75f8bb8, 0x09a3e163, 0x0000e790, 0x000d31b5,
0xffe83a07, 0x00a8739d, 0x049aa82f, 0x03343533, 0x46aea856, 0x6785c24d, 0xe89971b7, 0x099140a7, 0x00131c75, 0x0009aa3f,
0xffe79e16, 0x00abe79e, 0x04cc2fcf, 0x02a99097, 0x4812f848, 0x66d76725, 0xe9cea84a, 0x097c1ee8, 0x0023b989, 0x0006b1cf,
0xffe7746e, 0x00af374c, 0x04fe20be, 0x02186a91, 0x4973fef1, 0x661fd6b8, 0xeafee7f1, 0x0963ed46, 0x0033b927, 0x00039609,
0xffe6d466, 0x00b1978d, 0x05303f87, 0x01816e06, 0x4ad237a2, 0x655f63f2, 0xec2a3f5f, 0x0949eaac, 0x00426f36, 0x00007134,
0xffe6afee, 0x00b3d15c, 0x05626209, 0x00e42fa2, 0x4c2ca3df, 0x64964063, 0xed50a31d, 0x092d7970, 0x00504f41, 0xfffdfa25,
0xffe65416, 0x00b5c867, 0x05950122, 0x0040c496, 0x4d83976c, 0x63c45243, 0xee71b2fe, 0x090ec1fc, 0x005d36df, 0xfffb42b0,
0xffe681c6, 0x00b74c37, 0x05c76fed, 0xff96db90, 0x4ed62be3, 0x62ea6474, 0xef8d4d7b, 0x08edfeaa, 0x006928a0, 0xfff91fca,
0xffe66dd0, 0x00b8394b, 0x05f9c051, 0xfee723c6, 0x5024d70e, 0x6207f220, 0xf0a3959f, 0x08cb4e23, 0x007400b8, 0xfff681d6,
0xffe66fac, 0x00b8fe0d, 0x062bf5ec, 0xfe310657, 0x516eefb9, 0x611d58a3, 0xf1b461ab, 0x08a75da4, 0x007e0393, 0xfff48700,
0xffe69423, 0x00b8c6b0, 0x065dd56a, 0xfd7475d8, 0x52b449de, 0x602b0c7f, 0xf2bf6ea4, 0x0880ffdd, 0x00872c63, 0xfff294c3,
0xffe6fed4, 0x00b85f70, 0x068f8b44, 0xfcb1d740, 0x53f495aa, 0x5f30ff5f, 0xf3c4e887, 0x08594887, 0x008f87aa, 0xfff0e7ef,
0xffe75361, 0x00b73ab0, 0x06c0f0c0, 0xfbe8f5bd, 0x552f8ff7, 0x5e2f6367, 0xf4c473c6, 0x08303897, 0x0096dcc2, 0xffef2395,
0xffe80414, 0x00b58c8c, 0x06f1825d, 0xfb19b7bd, 0x56654bdd, 0x5d26be9b, 0xf5be0fa9, 0x08061671, 0x009da526, 0xffedc418,
0xffe85b4b, 0x00b36acd, 0x0721bf22, 0xfa44a069, 0x579505f5, 0x5c16d0ae, 0xf6b1f3c3, 0x07da2b7f, 0x00a3508f, 0xffec8409,
0xffe954d0, 0x00b06b68, 0x075112a2, 0xf96916f5, 0x58befacd, 0x5b001db8, 0xf79fa13a, 0x07ad8c26, 0x00a85e94, 0xffeb3849,
0xffea353a, 0x00acbd2f, 0x077fedb3, 0xf887507c, 0x59e2f69e, 0x59e2f69e, 0xf887507c, 0x077fedb3, 0x00acbd2f, 0xffea353a,
0xffeb3849, 0x00a85e94, 0x07ad8c26, 0xf79fa13a, 0x5b001db8, 0x58befacd, 0xf96916f5, 0x075112a2, 0x00b06b68, 0xffe954d0,
0xffec8409, 0x00a3508f, 0x07da2b7f, 0xf6b1f3c3, 0x5c16d0ae, 0x579505f5, 0xfa44a069, 0x0721bf22, 0x00b36acd, 0xffe85b4b,
0xffedc418, 0x009da526, 0x08061671, 0xf5be0fa9, 0x5d26be9b, 0x56654bdd, 0xfb19b7bd, 0x06f1825d, 0x00b58c8c, 0xffe80414,
0xffef2395, 0x0096dcc2, 0x08303897, 0xf4c473c6, 0x5e2f6367, 0x552f8ff7, 0xfbe8f5bd, 0x06c0f0c0, 0x00b73ab0, 0xffe75361,
0xfff0e7ef, 0x008f87aa, 0x08594887, 0xf3c4e887, 0x5f30ff5f, 0x53f495aa, 0xfcb1d740, 0x068f8b44, 0x00b85f70, 0xffe6fed4,
0xfff294c3, 0x00872c63, 0x0880ffdd, 0xf2bf6ea4, 0x602b0c7f, 0x52b449de, 0xfd7475d8, 0x065dd56a, 0x00b8c6b0, 0xffe69423,
0xfff48700, 0x007e0393, 0x08a75da4, 0xf1b461ab, 0x611d58a3, 0x516eefb9, 0xfe310657, 0x062bf5ec, 0x00b8fe0d, 0xffe66fac,
0xfff681d6, 0x007400b8, 0x08cb4e23, 0xf0a3959f, 0x6207f220, 0x5024d70e, 0xfee723c6, 0x05f9c051, 0x00b8394b, 0xffe66dd0,
0xfff91fca, 0x006928a0, 0x08edfeaa, 0xef8d4d7b, 0x62ea6474, 0x4ed62be3, 0xff96db90, 0x05c76fed, 0x00b74c37, 0xffe681c6,
0xfffb42b0, 0x005d36df, 0x090ec1fc, 0xee71b2fe, 0x63c45243, 0x4d83976c, 0x0040c496, 0x05950122, 0x00b5c867, 0xffe65416,
0xfffdfa25, 0x00504f41, 0x092d7970, 0xed50a31d, 0x64964063, 0x4c2ca3df, 0x00e42fa2, 0x05626209, 0x00b3d15c, 0xffe6afee,
0x00007134, 0x00426f36, 0x0949eaac, 0xec2a3f5f, 0x655f63f2, 0x4ad237a2, 0x01816e06, 0x05303f87, 0x00b1978d, 0xffe6d466,
0x00039609, 0x0033b927, 0x0963ed46, 0xeafee7f1, 0x661fd6b8, 0x4973fef1, 0x02186a91, 0x04fe20be, 0x00af374c, 0xffe7746e,
0x0006b1cf, 0x0023b989, 0x097c1ee8, 0xe9cea84a, 0x66d76725, 0x4812f848, 0x02a99097, 0x04cc2fcf, 0x00abe79e, 0xffe79e16,
0x0009aa3f, 0x00131c75, 0x099140a7, 0xe89971b7, 0x6785c24d, 0x46aea856, 0x03343533, 0x049aa82f, 0x00a8739d, 0xffe83a07,
0x000d31b5, 0x0000e790, 0x09a3e163, 0xe75f8bb8, 0x682b39a4, 0x4547daea, 0x03b8f8dc, 0x04694101, 0x00a520bb, 0xffe88ba8,
0x0010bc63, 0xffee183b, 0x09b3d77f, 0xe620c476, 0x68c7269b, 0x43de620a, 0x0437fb0a, 0x043889c6, 0x00a1039c, 0xffe940f4,
0x001471f8, 0xffda17f2, 0x09c0e59f, 0xe4de0cb0, 0x6959709d, 0x4272a385, 0x04b0adcb, 0x04083fec, 0x009d10bf, 0xffe9ca76,
0x0018703f, 0xffc4e365, 0x09cab9f2, 0xe396a45d, 0x69e29784, 0x41058bc6, 0x05237f9d, 0x03d8afe6, 0x0098b855, 0xffea9192,
0x001c3549, 0xffaea5d6, 0x09d19ca9, 0xe24b8f66, 0x6a619c5e, 0x3f962fb8, 0x0590a67d, 0x03a966bb, 0x009424c6, 0xffeb50b2,
0x002064f8, 0xff975c01, 0x09d52709, 0xe0fc421e, 0x6ad73e8d, 0x3e25b17e, 0x05f7fb90, 0x037ad438, 0x008f4bfc, 0xffebe77b,
0x0024dd50, 0xff7ee3f1, 0x09d5560b, 0xdfa93ab5, 0x6b42a864, 0x3cb41219, 0x06593912, 0x034d01f0, 0x008a7dd7, 0xffecc31b,
0x00293718, 0xff6542d1, 0x09d1fa23, 0xde529086, 0x6ba4629f, 0x3b415115, 0x06b559c3, 0x03201116, 0x0085c217, 0xffed651d,
0x002d8e42, 0xff4aabc8, 0x09caeb0f, 0xdcf898fb, 0x6bfbdd98, 0x39ce0477, 0x070bbf58, 0x02f3e48d, 0x00807994, 0xffee1650,
0x00329ab6, 0xff2ef725, 0x09c018ce, 0xdb9b5b12, 0x6c492217, 0x385a49c4, 0x075ca90c, 0x02c89901, 0x007b3875, 0xffeedfa4,
0x003745f9, 0xff120d70, 0x09b18a1d, 0xda3b176a, 0x6c8c4c7a, 0x36e69691, 0x07a8127d, 0x029e35b4, 0x0075fded, 0xffef7b8b,
0x003c1fa4, 0xfef3f6ab, 0x099ec3dc, 0xd8d7f21f, 0x6cc59bab, 0x3572ec70, 0x07ee507c, 0x0274ba43, 0x0070c8a5, 0xffeff6ca,
0x004103f4, 0xfed4bec3, 0x09881dc5, 0xd7722f04, 0x6cf4073e, 0x33ff670e, 0x082f552e, 0x024bf7a1, 0x006b47fa, 0xfff0065d,
0x00465348, 0xfeb48d0d, 0x096d0e21, 0xd60a46e5, 0x6d18520e, 0x328cc6f0, 0x086b1eeb, 0x02244a24, 0x0065fde5, 0xffefc9b9,
0x004b6c46, 0xfe933dc0, 0x094d7ec2, 0xd49fd55f, 0x6d32730f, 0x311af3a4, 0x08a24899, 0x01fd3ba0, 0x006090c4, 0xffed978a,
0x0050b177, 0xfe70b8d1, 0x09299ead, 0xd3337b3d, 0x6d41d963, 0x2faa221c, 0x08d3e41b, 0x01d78bfc, 0x005b5371, 0xffede50f,
};
/* noise table 4.A.88, format = Q31 */
const int noiseTab[512*2] PROGMEM = {
0x8010fd38, 0xb3dc7948, 0x7c4e2301, 0xa9904192, 0x121622a7, 0x86489625, 0xc3d53d25, 0xd0343fa9,
0x674d6f70, 0x25f4e9fd, 0xce1a8c8b, 0x72a726c5, 0xfea6efc6, 0xaa4adb1a, 0x8b2dd628, 0xf14029e4,
0x46321c1a, 0x604889a0, 0x33363b63, 0x815ed069, 0x802b4315, 0x8f2bf7f3, 0x85b86073, 0x745cfb46,
0xc57886b3, 0xb76731f0, 0xa2a66772, 0x828ca631, 0x60cc145e, 0x1ad1010f, 0x090c83d4, 0x9bd7ba87,
0x5f5aeea2, 0x8b4dbd99, 0x848e7b1e, 0x86bb9fa2, 0x26f18ae5, 0xc0b81194, 0x553407bf, 0x52c17953,
0x755f468d, 0x166b04f8, 0xa5687981, 0x4343248b, 0xa6558d5e, 0xc5f6fab7, 0x80a4fb8c, 0x8cb53cb7,
0x7da68a54, 0x9cd8df8a, 0xba05376c, 0xfcb58ee2, 0xfdd657a4, 0x005e35ca, 0x91c75c55, 0x367651e6,
0x816abf85, 0x8f831c4f, 0x423f9c9c, 0x55aa919e, 0x80779834, 0xb59f4244, 0x800a095c, 0x7de9e0cc,
0x46bda5cb, 0x4c184464, 0x2c438f71, 0x797216b5, 0x5035cee6, 0xa0c3a26e, 0x9d3f95fa, 0xd4a100c0,
0x8ac30dac, 0x04b87397, 0x9e5ac516, 0x8b0b442e, 0x66210ad6, 0x88ba7598, 0x45b9bd33, 0xf0be5087,
0x9261b85e, 0x364f6a31, 0x891c4b50, 0x23ad08ce, 0xf10366a6, 0x80414276, 0x1b562e06, 0x8be21591,
0x9e798195, 0x7fb4045c, 0x7d9506cf, 0x854e691f, 0x9207f092, 0x7a94c9d5, 0x88911536, 0x3f45cc61,
0x27059279, 0xa5b57109, 0x6d2bb67b, 0x3bdc5379, 0x74e662d8, 0x80348f8c, 0xf875e638, 0x5a8caea1,
0x2459ae75, 0x2c54b939, 0x79ee3203, 0xb9bc8683, 0x9b6f630c, 0x9f45b351, 0x8563b2b9, 0xe5dbba41,
0x697c7d0d, 0x7bb7c90e, 0xac900866, 0x8e6b5177, 0x8822dd37, 0x7fd5a91e, 0x7506da05, 0x82302aca,
0xa5e4be04, 0x4b4288eb, 0x00b8bc9f, 0x4f1033e4, 0x7200d612, 0x43900c8c, 0xa815b900, 0x676ed1d4,
0x5c5f23b2, 0xa758ee11, 0xaf73abfa, 0x11714ec0, 0x265239e0, 0xc50de679, 0x8a84e341, 0xa1438354,
0x7f1a341f, 0x343ec96b, 0x696e71b0, 0xa13bde39, 0x81e75094, 0x80091111, 0x853a73bf, 0x80f9c1ee,
0xe4980086, 0x886a8e28, 0xa7e89426, 0xdd93edd7, 0x7592100d, 0x0bfa8123, 0x850a26d4, 0x2e34f395,
0x421b6c00, 0xa4a462e4, 0x4e3f5090, 0x3c189f4c, 0x3c971a56, 0xdd0376d2, 0x747a5367, 0x7bcbc9d7,
0x3966be6a, 0x7efda616, 0x55445e15, 0x7ba2ab3f, 0x5fe684f2, 0x8cf42af9, 0x808c61c3, 0x4390c27b,
0x7cac62ff, 0xea6cab22, 0x5d0902ad, 0xc27b7208, 0x7a27389d, 0x5820a357, 0xa29bbe59, 0x9df0f1fd,
0x92bd67e5, 0x7195b587, 0x97cac65b, 0x8339807e, 0x8f72d832, 0x5fad8685, 0xa462d9d3, 0x81d46214,
0x6ae93e1d, 0x6b23a5b9, 0xc2732874, 0x81795268, 0x7c568cb6, 0x668513ea, 0x428d024e, 0x66b78b3a,
0xfee9ef03, 0x9ddcbb82, 0xa605f07e, 0x46dc55e0, 0x85415054, 0xc89ec271, 0x7c42edfb, 0x0befe59b,
0x89b8f607, 0x6d732a1a, 0xa7081ebd, 0x7e403258, 0x21feeb7b, 0x5dd7a1e7, 0x23e3a31a, 0x129bc896,
0xa11a6b54, 0x7f1e031c, 0xfdc1a4d1, 0x96402e53, 0xb9700f1a, 0x8168ecd6, 0x7d63d3cc, 0x87a70d65,
0x81075a7a, 0x55c8caa7, 0xa95d00b5, 0x102b1652, 0x0bb30215, 0xe5b63237, 0xa446ca44, 0x82d4c333,
0x67b2e094, 0x44c3d661, 0x33fd6036, 0xde1ea2a1, 0xa95e8e47, 0x78f66eb9, 0x6f2aef1e, 0xe8887247,
0x80a3b70e, 0xfca0d9d3, 0x6bf0fd20, 0x0d5226de, 0xf4341c87, 0x5902df05, 0x7ff1a38d, 0xf02e5a5b,
0x99f129af, 0x8ac63d01, 0x7b53f599, 0x7bb32532, 0x99ac59b0, 0x5255a80f, 0xf1320a41, 0x2497aa5c,
0xcce60bd8, 0x787c634b, 0x7ed58c5b, 0x8a28eb3a, 0x24a5e647, 0x8b79a2c1, 0x955f5ce5, 0xa9d12bc4,
0x7a1e20c6, 0x3eeda7ac, 0xf7be823a, 0x042924ce, 0x808b3f03, 0x364248da, 0xac2895e5, 0x69a8b5fa,
0x97fe8b63, 0xbdeac9aa, 0x8073e0ad, 0x6c25dba7, 0x005e51d2, 0x52e74389, 0x59d3988c, 0xe5d1f39c,
0x7b57dc91, 0x341adbe7, 0xa7d42b8d, 0x74e9f335, 0xd35bf7d8, 0x5b7c0a4b, 0x75bc0874, 0x552129bf,
0x8144b70d, 0x6de93bbb, 0x5825f14b, 0x473ec5ca, 0x80a8f37c, 0xe6552d69, 0x7898360b, 0x806379b0,
0xa9b59339, 0x3f6bf60c, 0xc367d731, 0x920ade99, 0x125592f7, 0x877e5ed1, 0xda895d95, 0x075f2ece,
0x380e5f5e, 0x9b006b62, 0xd17a6dd2, 0x530a0e13, 0xf4cc9a14, 0x7d0a0ed4, 0x847c6e3f, 0xbaee4975,
0x47131163, 0x64fb2cac, 0x5e2100a6, 0x7b756a42, 0xd87609f4, 0x98bfe48c, 0x0493745e, 0x836c5784,
0x7e5ccb40, 0x3df6b476, 0x97700d28, 0x8bbd93fd, 0x56de9cdb, 0x680b4e65, 0xebc3d90e, 0x6d286793,
0x6753712e, 0xe05c98a7, 0x3d2b6b85, 0xc4b18ddb, 0x7b59b869, 0x31435688, 0x811888e9, 0xe011ee7a,
0x6a5844f9, 0x86ae35ea, 0xb4cbc10b, 0x01a6f5d6, 0x7a49ed64, 0x927caa49, 0x847ddaed, 0xae0d9bb6,
0x836bdb04, 0x0fd810a6, 0x74fe126b, 0x4a346b5f, 0x80184d36, 0x5afd153c, 0x90cc8102, 0xe606d0e6,
0xde69aa58, 0xa89f1222, 0xe06df715, 0x8fd16144, 0x0317c3e8, 0x22ce92fc, 0x690c3eca, 0x93166f02,
0x71573414, 0x8d43cffb, 0xe8bd0bb6, 0xde86770f, 0x0bf99a41, 0x4633a661, 0xba064108, 0x7adafae3,
0x2f6cde5d, 0xb350a52c, 0xa5ebfb0b, 0x74c57b46, 0xd3b603b5, 0x80b70892, 0xa7f7fa53, 0xd94b566c,
0xdda3fd86, 0x6a635793, 0x3ed005ca, 0xc5f087d8, 0x31e3a746, 0x7a4278f9, 0x82def1f9, 0x06caa2b2,
0xe9d2c349, 0x8940e7f7, 0x7feef8dd, 0x4a9b01f0, 0xacde69f8, 0x57ddc280, 0xf09e4ba4, 0xb6d9f729,
0xb48c18f2, 0xd3654aa9, 0xca7a03c8, 0x14d57545, 0x7fda87a5, 0x0e411366, 0xb77d0df0, 0x8c2aa467,
0x787f2590, 0x2d292db1, 0x9f12682c, 0x44ac364d, 0x1a4b31a6, 0x871f7ded, 0x7ff99167, 0x6630a1d5,
0x25385eb9, 0x2d4dd549, 0xaf8a7004, 0x319ebe0f, 0x379ab730, 0x81dc56a4, 0x822d8523, 0x1ae8554c,
0x18fa0786, 0x875f7de4, 0x85ca350f, 0x7de818dc, 0x7786a38f, 0xa5456355, 0x92e60f88, 0xf5526122,
0x916039bc, 0xc561e2de, 0x31c42042, 0x7c82e290, 0x75d158b2, 0xb015bda1, 0x7220c750, 0x46565441,
0xd0da1fdd, 0x7b777481, 0x782e73c6, 0x8cd72b7b, 0x7f1006aa, 0xfb30e51e, 0x87994818, 0x34e7c7db,
0x7faae06b, 0xea74fbc0, 0xd20c7af4, 0xc44f396b, 0x06b4234e, 0xdf2e2a93, 0x2efb07c8, 0xce861911,
0x7550ea05, 0xd8d90bbb, 0x58522eec, 0x746b3520, 0xce844ce9, 0x7f5cacc3, 0xda8f17e0, 0x2fedf9cb,
0xb2f77ec4, 0x6f13f4c0, 0x834de085, 0x7b7ace4b, 0x713b16ac, 0x499c5ab0, 0x06a7961d, 0x1b39a48a,
0xbb853e6e, 0x7c781cc1, 0xc0baebf5, 0x7dace394, 0x815ceebc, 0xcc7b27d4, 0x8274b181, 0xa2be40a2,
0xdd01d5dc, 0x7fefeb14, 0x0813ec78, 0xba3077cc, 0xe5cf1e1c, 0xedcfacae, 0x54c43a9b, 0x5cd62a42,
0x93806b55, 0x03095c5b, 0x8e076ae3, 0x71bfcd2a, 0x7ac1989b, 0x623bc71a, 0x5e15d4d2, 0xfb341dd1,
0xd75dfbca, 0xd0da32be, 0xd4569063, 0x337869da, 0x3d30606a, 0xcd89cca2, 0x7dd2ae36, 0x028c03cd,
0xd85e052c, 0xe8dc9ec5, 0x7ffd9241, 0xde5bf4c6, 0x88c4b235, 0x8228be2e, 0x7fe6ec64, 0x996abe6a,
0xdeb0666d, 0x9eb86611, 0xd249b922, 0x18b3e26b, 0x80211168, 0x5f8bb99c, 0x6ecb0dd2, 0x4728ff8d,
0x2ac325b8, 0x6e5169d2, 0x7ebbd68d, 0x05e41d17, 0xaaa19f28, 0x8ab238a6, 0x51f105be, 0x140809cc,
0x7f7345d9, 0x3aae5a9d, 0xaecec6e4, 0x1afb3473, 0xf6229ed1, 0x8d55f467, 0x7e32003a, 0x70f30c14,
0x6686f33f, 0xd0d45ed8, 0x644fab57, 0x3a3fbbd3, 0x0b255fc4, 0x679a1701, 0x90e17b6e, 0x325d537b,
0xcd7b9b87, 0xaa7be2a2, 0x7d47c966, 0xa33dbce5, 0x8659c3bb, 0x72a41367, 0x15c446e0, 0x45fe8b0a,
0x9d8ddf26, 0x84d47643, 0x7fabe0da, 0x36a70122, 0x7a28ebfe, 0x7c29b8b8, 0x7f760406, 0xbabe4672,
0x23ea216e, 0x92bcc50a, 0x6d20dba2, 0xad5a7c7e, 0xbf3897f5, 0xabb793e1, 0x8391fc7e, 0xe270291c,
0x7a248d58, 0x80f8fd15, 0x83ef19f3, 0x5e6ece7d, 0x278430c1, 0x35239f4d, 0xe09c073b, 0x50e78cb5,
0xd4b811bd, 0xce834ee0, 0xf88aaa34, 0xf71da5a9, 0xe2b0a1d5, 0x7c3aef31, 0xe84eabca, 0x3ce25964,
0xf29336d3, 0x8fa78b2c, 0xa3fc3415, 0x63e1313d, 0x7fbc74e0, 0x7340bc93, 0x49ae583b, 0x8b79de4b,
0x25011ce9, 0x7b462279, 0x36007db0, 0x3da1599c, 0x77780772, 0xc845c9bb, 0x83ba68be, 0x6ee507d1,
0x2f0159b8, 0x5392c4ed, 0x98336ff6, 0x0b3c7f11, 0xde697aac, 0x893fc8d0, 0x6b83f8f3, 0x47799a0d,
0x801d9dfc, 0x8516a83e, 0x5f8d22ec, 0x0f8ba384, 0xa049dc4b, 0xdd920b05, 0x7a99bc9f, 0x9ad19344,
0x7a345dba, 0xf501a13f, 0x3e58bf19, 0x7fffaf9a, 0x3b4e1511, 0x0e08b991, 0x9e157620, 0x7230a326,
0x4977f9ff, 0x2d2bbae1, 0x607aa7fc, 0x7bc85d5f, 0xb441bbbe, 0x8d8fa5f2, 0x601cce26, 0xda1884f2,
0x81c82d64, 0x200b709c, 0xcbd36abe, 0x8cbdddd3, 0x55ab61d3, 0x7e3ee993, 0x833f18aa, 0xffc1aaea,
0x7362e16a, 0x7fb85db2, 0x904ee04c, 0x7f04dca6, 0x8ad7a046, 0xebe7d8f7, 0xfbc4c687, 0xd0609458,
0x093ed977, 0x8e546085, 0x7f5b8236, 0x7c47e118, 0xa01f2641, 0x7ffb3e48, 0x05de7cda, 0x7fc281b9,
0x8e0278fc, 0xd74e6d07, 0x94c24450, 0x7cf9e641, 0x2ad27871, 0x919fa815, 0x805fd205, 0x7758397f,
0xe2c7e02c, 0x1828e194, 0x5613d6fe, 0xfb55359f, 0xf9699516, 0x8978ee26, 0x7feebad9, 0x77d71d82,
0x55b28b60, 0x7e997600, 0x80821a6b, 0xc6d78af1, 0x691822ab, 0x7f6982a0, 0x7ef56f99, 0x5c307f40,
0xac6f8b76, 0x42cc8ba4, 0x782c61d9, 0xa0224dd0, 0x7bd234d1, 0x74576e3b, 0xe38cfe9a, 0x491e66ef,
0xc78291c5, 0x895bb87f, 0x924f7889, 0x71b89394, 0x757b779d, 0xc4a9c604, 0x5cdf7829, 0x8020e9df,
0x805e8245, 0x4a82c398, 0x6360bd62, 0x78bb60fc, 0x09e0d014, 0x4b0ea180, 0xb841978b, 0x69a0e864,
0x7df35977, 0x3284b0dd, 0x3cdc2efd, 0x57d31f5e, 0x541069cc, 0x1776e92e, 0x04309ea3, 0xa015eb2d,
0xce7bfabc, 0x41b638f8, 0x8365932e, 0x846ab44c, 0xbbcc80cb, 0x8afa6cac, 0x7fc422ea, 0x4e403fc0,
0xbfac9aee, 0x8e4c6709, 0x028e01fb, 0x6d160a9b, 0x7fe93004, 0x790f9cdc, 0x6a1f37a0, 0xf7e7ef30,
0xb4ea0f04, 0x7bf4c8e6, 0xe981701f, 0xc258a9d3, 0x6acbbfba, 0xef5479c7, 0x079c8bd8, 0x1a410f56,
0x6853b799, 0x86cd4f01, 0xc66e23b6, 0x34585565, 0x8d1fe00d, 0x7fcdba1a, 0x32c9717b, 0xa02f9f48,
0xf64940db, 0x5ed7d8f1, 0x61b823b2, 0x356f8918, 0xa0a7151e, 0x793fc969, 0x530beaeb, 0x34e93270,
0x4fc4ddb5, 0x88d58b6c, 0x36094774, 0xf620ac80, 0x03763a72, 0xf910c9a6, 0x6666fb2d, 0x752c8be8,
0x9a6dfdd8, 0xd1a7117d, 0x51c1b1d4, 0x0a67773d, 0x43b32a79, 0x4cdcd085, 0x5f067d30, 0x05bfe92a,
0x7ed7d203, 0xe71a3c85, 0x99127ce2, 0x8eb3cac4, 0xad4bbcea, 0x5c6a0fd0, 0x0eec04af, 0x94e95cd4,
0x8654f921, 0x83eabb5d, 0xb058d7ca, 0x69f12d3c, 0x03d881b2, 0x80558ef7, 0x82938cb3, 0x2ec0e1d6,
0x80044422, 0xd1e47051, 0x720fc6ff, 0x82b20316, 0x0d527b02, 0x63049a15, 0x7ad5b9ad, 0xd2a4641d,
0x41144f86, 0x7b04917a, 0x15c4a2c0, 0x9da07916, 0x211df54a, 0x7fdd09af, 0xfe924f3f, 0x7e132cfe,
0x9a1d18d6, 0x7c56508b, 0x80f0f0af, 0x8095ced6, 0x8037d0d7, 0x026719d1, 0xa55fec43, 0x2b1c7cb7,
0xa5cd5ac1, 0x77639fad, 0x7fcd8b62, 0x81a18c27, 0xaee4912e, 0xeae9eebe, 0xeb3081de, 0x8532aada,
0xc822362e, 0x86a649a9, 0x8031a71d, 0x7b319dc6, 0xea8022e6, 0x814bc5a9, 0x8f62f7a1, 0xa430ea17,
0x388deafb, 0x883b5185, 0x776fe13c, 0x801c683f, 0x87c11b98, 0xb7cbc644, 0x8e9ad3e8, 0x3cf5a10c,
0x7ff6a634, 0x949ef096, 0x9f84aa7c, 0x010af13f, 0x782d1de8, 0xf18e492a, 0x6cf63b01, 0x4301cd81,
0x32d15c9e, 0x68ad8cef, 0xd09bd2d6, 0x908c5c15, 0xd1e36260, 0x2c5bfdd0, 0x88765a99, 0x93deba1e,
0xac6ae342, 0xe865b84c, 0x0f4f2847, 0x7fdf0499, 0x78b1c9b3, 0x6a73261e, 0x601a96f6, 0xd2847933,
0x489aa888, 0xe12e8093, 0x3bfa5a5f, 0xd96ba5f7, 0x7c8f4c8d, 0x80940c6f, 0xcef9dd1a, 0x7e1a055f,
0x3483558b, 0x02b59cc4, 0x0c56333e, 0x05a5b813, 0x92d66287, 0x7516b679, 0x71bfe03f, 0x8056bf68,
0xc24d0724, 0x8416bcf3, 0x234afbdb, 0x4b0d6f9c, 0xaba97333, 0x4b4f42b6, 0x7e8343ab, 0x7ffe2603,
0xe590f73c, 0x45e10c76, 0xb07a6a78, 0xb35609d3, 0x1a027dfd, 0x90cb6e20, 0x82d3fe38, 0x7b409257,
0x0e395afa, 0x1b802093, 0xcb0c6c59, 0x241e17e7, 0x1ee3ea0a, 0x41a82302, 0xab04350a, 0xf570beb7,
0xbb444b9b, 0x83021459, 0x838d65dc, 0x1c439c84, 0x6fdcc454, 0xef9ef325, 0x18626c1c, 0x020d251f,
0xc4aae786, 0x8614cb48, 0xf6f53ca6, 0x8710dbab, 0x89abec0d, 0xf29d41c1, 0x94b50336, 0xfdd49178,
0x604658d1, 0x800e85be, 0xca1bb079, 0x7fa48eeb, 0xa3b7fafe, 0xd330436b, 0x64eb604c, 0x43a658ae,
0x7caa1337, 0xddd445e6, 0x7efbf955, 0xb706ec71, 0x624a6b53, 0x9e0e231f, 0x97097248, 0xa1e1a17a,
0x68dd2e44, 0x7f9d2e14, 0xddcc7074, 0x58324197, 0xc88fc426, 0x6d3640ae, 0x7ef83600, 0x759a0270,
0x98b6d854, 0xd63c9b84, 0x372474a2, 0xe3f18cfd, 0x56ab0bdb, 0x85c9be7e, 0x47dfcfeb, 0xa5830d41,
0x0ddd6283, 0xf4f480ad, 0x74c60e38, 0xab8943c3, 0xc1508fe7, 0x480cdc39, 0x8e097362, 0xa44793be,
0x538b7e18, 0x545f5b41, 0x56529175, 0x9771a97e, 0xc2da7421, 0xea8265f2, 0x805d1163, 0x883c5d28,
0x8ba94c48, 0x4f676e65, 0xf78735b3, 0xe1853671, 0x7f454f53, 0x18147f85, 0x7d09e15d, 0xdb4f3494,
0x795c8973, 0x83310632, 0x85d8061c, 0x9a1a0ebf, 0xc125583c, 0x2a1b1a95, 0x7fd9103f, 0x71e98c72,
0x40932ed7, 0x91ed227a, 0x3c5e560e, 0xe816dee9, 0xb0891b80, 0x600038ba, 0xc7d9a80d, 0x7fff5e09,
0x7e3f4351, 0xbb6b4424, 0xb14448d4, 0x8d6bb7e1, 0xfb153626, 0xa68ad537, 0xd9782006, 0xf62f6991,
0x359ba8c1, 0x02ccff0b, 0x91bf2256, 0x7ea71c4d, 0x560ce5df, 0xeeba289b, 0xa574c4e7, 0x9e04f6ee,
0x7860a5ec, 0x0b8db4a2, 0x968ba3d7, 0x0b6c77df, 0xd6f3157d, 0x402eff1a, 0x49b820b3, 0x8152aebb,
0xd180b0b6, 0x098604d4, 0x7ff92224, 0xede9c996, 0x89c58061, 0x829624c4, 0xc6e71ea7, 0xba94d915,
0x389c3cf6, 0x5b4c5a06, 0x04b335e6, 0x516a8aab, 0x42c8d7d9, 0x92b12af6, 0x86c8549f, 0xfda98acf,
0x819673b6, 0x69545dac, 0x6feaa230, 0x726e6d3f, 0x886ebdfe, 0x34f5730a, 0x7af63ba2, 0x77307bbf,
0x7cd80630, 0x6e45efe0, 0x7f8ad7eb, 0x59d7df99, 0x86c70946, 0xda233629, 0x753f6cbf, 0x825eeb40,
};

View File

@@ -0,0 +1,115 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: statname.h,v 1.1 2005/02/26 01:47:34 jrecker Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* statname.h - name mangling macros for static linking
**************************************************************************************/
#ifndef _STATNAME_H
#define _STATNAME_H
/* define STAT_PREFIX to a unique name for static linking
* all the C functions and global variables will be mangled by the preprocessor
* e.g. void DCT4(...) becomes void raac_DCT4(...)
*/
#define STAT_PREFIX raac
#define STATCC1(x,y,z) STATCC2(x,y,z)
#define STATCC2(x,y,z) x##y##z
#ifdef STAT_PREFIX
#define STATNAME(func) STATCC1(STAT_PREFIX, _, func)
#else
#define STATNAME(func) func
#endif
/* these symbols are common to all implementations */
#define AllocateBuffers STATNAME(AllocateBuffers)
#define FreeBuffers STATNAME(FreeBuffers)
#define ClearBuffer STATNAME(ClearBuffer)
#define SetRawBlockParams STATNAME(SetRawBlockParams)
#define PrepareRawBlock STATNAME(PrepareRawBlock)
#define FlushCodec STATNAME(FlushCodec)
#define UnpackADTSHeader STATNAME(UnpackADTSHeader)
#define GetADTSChannelMapping STATNAME(GetADTSChannelMapping)
#define UnpackADIFHeader STATNAME(UnpackADIFHeader)
#define DecodeNextElement STATNAME(DecodeNextElement)
#define DecodeNoiselessData STATNAME(DecodeNoiselessData)
#define Dequantize STATNAME(Dequantize)
#define StereoProcess STATNAME(StereoProcess)
#define DeinterleaveShortBlocks STATNAME(DeinterleaveShortBlocks)
#define PNS STATNAME(PNS)
#define TNSFilter STATNAME(TNSFilter)
#define IMDCT STATNAME(IMDCT)
#define InitSBR STATNAME(InitSBR)
#define DecodeSBRBitstream STATNAME(DecodeSBRBitstream)
#define DecodeSBRData STATNAME(DecodeSBRData)
#define FreeSBR STATNAME(FreeSBR)
#define FlushCodecSBR STATNAME(FlushCodecSBR)
/* global ROM tables */
#define sampRateTab STATNAME(sampRateTab)
#define predSFBMax STATNAME(predSFBMax)
#define channelMapTab STATNAME(channelMapTab)
#define elementNumChans STATNAME(elementNumChans)
#define sfBandTotalShort STATNAME(sfBandTotalShort)
#define sfBandTotalLong STATNAME(sfBandTotalLong)
#define sfBandTabShortOffset STATNAME(sfBandTabShortOffset)
#define sfBandTabShort STATNAME(sfBandTabShort)
#define sfBandTabLongOffset STATNAME(sfBandTabLongOffset)
#define sfBandTabLong STATNAME(sfBandTabLong)
#define tnsMaxBandsShortOffset STATNAME(tnsMaxBandsShortOffset)
#define tnsMaxBandsShort STATNAME(tnsMaxBandsShort)
#define tnsMaxOrderShort STATNAME(tnsMaxOrderShort)
#define tnsMaxBandsLongOffset STATNAME(tnsMaxBandsLongOffset)
#define tnsMaxBandsLong STATNAME(tnsMaxBandsLong)
#define tnsMaxOrderLong STATNAME(tnsMaxOrderLong)
/* in your implementation's top-level include file (e.g. real\coder.h) you should
* add new #define sym STATNAME(sym) lines for all the
* additional global functions or variables which your
* implementation uses
*/
#endif /* _STATNAME_H */

View File

@@ -0,0 +1,246 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: stproc.c,v 1.3 2005/05/24 16:01:55 albertofloyd Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* stproc.c - mid-side and intensity stereo processing
**************************************************************************************/
#include "coder.h"
#include "assembly.h"
/* pow14[0][i] = -pow(2, i/4.0)
* pow14[1][i] = +pow(2, i/4.0)
*
* i = [0,1,2,3]
* format = Q30
*/
/**************************************************************************************
* Function: StereoProcessGroup
*
* Description: apply mid-side and intensity stereo to group of transform coefficients
*
* Inputs: dequantized transform coefficients for both channels
* pointer to appropriate scalefactor band table
* mid-side mask enabled flag
* buffer with mid-side mask (one bit for each scalefactor band)
* bit offset into mid-side mask buffer
* max coded scalefactor band
* buffer of codebook indices for right channel
* buffer of scalefactors for right channel, range = [0, 256]
*
* Outputs: updated transform coefficients in Q(FBITS_OUT_DQ_OFF)
* updated minimum guard bit count for both channels
*
* Return: none
*
* Notes: assume no guard bits in input
* gains 0 int bits
**************************************************************************************/
static void StereoProcessGroup(int *coefL, int *coefR, const /*short*/ int *sfbTab,
int msMaskPres, unsigned char *msMaskPtr, int msMaskOffset, int maxSFB,
unsigned char *cbRight, short *sfRight, int *gbCurrent)
{
//fb
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnarrowing"
static const int pow14[2][4] PROGMEM = {
{ 0xc0000000, 0xb3e407d7, 0xa57d8666, 0x945d819b },
{ 0x40000000, 0x4c1bf829, 0x5a82799a, 0x6ba27e65 }
};
#pragma GCC diagnostic pop
int sfb, width, cbIdx, sf, cl, cr, scalef, scalei;
int gbMaskL, gbMaskR;
unsigned char msMask;
msMask = (*msMaskPtr++) >> msMaskOffset;
gbMaskL = 0;
gbMaskR = 0;
for (sfb = 0; sfb < maxSFB; sfb++) {
width = sfbTab[sfb+1] - sfbTab[sfb]; /* assume >= 0 (see sfBandTabLong/sfBandTabShort) */
cbIdx = cbRight[sfb];
if (cbIdx == 14 || cbIdx == 15) {
/* intensity stereo */
if (msMaskPres == 1 && (msMask & 0x01))
cbIdx ^= 0x01; /* invert_intensity(): 14 becomes 15, or 15 becomes 14 */
sf = -sfRight[sfb]; /* negative since we use identity 0.5^(x) = 2^(-x) (see spec) */
cbIdx &= 0x01; /* choose - or + scale factor */
scalef = pow14[cbIdx][sf & 0x03];
scalei = (sf >> 2) + 2; /* +2 to compensate for scalef = Q30 */
if (scalei > 0) {
if (scalei > 30)
scalei = 30;
do {
cr = MULSHIFT32(*coefL++, scalef);
CLIP_2N(cr, 31-scalei);
cr <<= scalei;
gbMaskR |= FASTABS(cr);
*coefR++ = cr;
} while (--width);
} else {
scalei = -scalei;
if (scalei > 31)
scalei = 31;
do {
cr = MULSHIFT32(*coefL++, scalef) >> scalei;
gbMaskR |= FASTABS(cr);
*coefR++ = cr;
} while (--width);
}
} else if ( cbIdx != 13 && ((msMaskPres == 1 && (msMask & 0x01)) || msMaskPres == 2) ) {
/* mid-side stereo (assumes no GB in inputs) */
do {
cl = *coefL;
cr = *coefR;
if ( (FASTABS(cl) | FASTABS(cr)) >> 30 ) {
/* avoid overflow (rare) */
cl >>= 1;
sf = cl + (cr >> 1); CLIP_2N(sf, 30); sf <<= 1;
cl = cl - (cr >> 1); CLIP_2N(cl, 30); cl <<= 1;
} else {
/* usual case */
sf = cl + cr;
cl -= cr;
}
*coefL++ = sf;
gbMaskL |= FASTABS(sf);
*coefR++ = cl;
gbMaskR |= FASTABS(cl);
} while (--width);
} else {
/* nothing to do */
coefL += width;
coefR += width;
}
/* get next mask bit (should be branchless on ARM) */
msMask >>= 1;
if (++msMaskOffset == 8) {
msMask = *msMaskPtr++;
msMaskOffset = 0;
}
}
cl = CLZ(gbMaskL) - 1;
if (gbCurrent[0] > cl)
gbCurrent[0] = cl;
cr = CLZ(gbMaskR) - 1;
if (gbCurrent[1] > cr)
gbCurrent[1] = cr;
return;
}
/**************************************************************************************
* Function: StereoProcess
*
* Description: apply mid-side and intensity stereo, if enabled
*
* Inputs: valid AACDecInfo struct (including dequantized transform coefficients)
*
* Outputs: updated transform coefficients in Q(FBITS_OUT_DQ_OFF)
* updated minimum guard bit count for both channels
*
* Return: 0 if successful, -1 if error
**************************************************************************************/
int StereoProcess(AACDecInfo *aacDecInfo)
{
PSInfoBase *psi;
ICSInfo *icsInfo;
int gp, win, nSamps, msMaskOffset;
int *coefL, *coefR;
unsigned char *msMaskPtr;
const /*short*/ int *sfbTab;
/* validate pointers */
if (!aacDecInfo || !aacDecInfo->psInfoBase)
return -1;
psi = (PSInfoBase *)(aacDecInfo->psInfoBase);
/* mid-side and intensity stereo require common_window == 1 (see MPEG4 spec, Correction 2, 2004) */
if (psi->commonWin != 1 || aacDecInfo->currBlockID != AAC_ID_CPE)
return 0;
/* nothing to do */
if (!psi->msMaskPresent && !psi->intensityUsed[1])
return 0;
icsInfo = &(psi->icsInfo[0]);
if (icsInfo->winSequence == 2) {
sfbTab = sfBandTabShort + sfBandTabShortOffset[psi->sampRateIdx];
nSamps = NSAMPS_SHORT;
} else {
sfbTab = sfBandTabLong + sfBandTabLongOffset[psi->sampRateIdx];
nSamps = NSAMPS_LONG;
}
coefL = psi->coef[0];
coefR = psi->coef[1];
/* do fused mid-side/intensity processing for each block (one long or eight short) */
msMaskOffset = 0;
msMaskPtr = psi->msMaskBits;
for (gp = 0; gp < icsInfo->numWinGroup; gp++) {
for (win = 0; win < icsInfo->winGroupLen[gp]; win++) {
StereoProcessGroup(coefL, coefR, sfbTab, psi->msMaskPresent,
msMaskPtr, msMaskOffset, icsInfo->maxSFB, psi->sfbCodeBook[1] + gp*icsInfo->maxSFB,
psi->scaleFactors[1] + gp*icsInfo->maxSFB, psi->gbCurrent);
coefL += nSamps;
coefR += nSamps;
}
/* we use one bit per sfb, so there are maxSFB bits for each window group */
msMaskPtr += (msMaskOffset + icsInfo->maxSFB) >> 3;
msMaskOffset = (msMaskOffset + icsInfo->maxSFB) & 0x07;
}
ASSERT(coefL == psi->coef[0] + 1024);
ASSERT(coefR == psi->coef[1] + 1024);
return 0;
}

View File

@@ -0,0 +1,300 @@
/* ***** BEGIN LICENSE BLOCK *****
* Source last modified: $Id: tns.c,v 1.2 2005/05/24 16:01:55 albertofloyd Exp $
*
* Portions Copyright (c) 1995-2005 RealNetworks, Inc. All Rights Reserved.
*
* The contents of this file, and the files included with this file,
* are subject to the current version of the RealNetworks Public
* Source License (the "RPSL") available at
* http://www.helixcommunity.org/content/rpsl unless you have licensed
* the file under the current version of the RealNetworks Community
* Source License (the "RCSL") available at
* http://www.helixcommunity.org/content/rcsl, in which case the RCSL
* will apply. You may also obtain the license terms directly from
* RealNetworks. You may not use this file except in compliance with
* the RPSL or, if you have a valid RCSL with RealNetworks applicable
* to this file, the RCSL. Please see the applicable RPSL or RCSL for
* the rights, obligations and limitations governing use of the
* contents of the file.
*
* This file is part of the Helix DNA Technology. RealNetworks is the
* developer of the Original Code and owns the copyrights in the
* portions it created.
*
* This file, and the files included with this file, is distributed
* and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
* KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
* ENJOYMENT OR NON-INFRINGEMENT.
*
* Technology Compatibility Kit Test Suite(s) Location:
* http://www.helixcommunity.org/content/tck
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
/**************************************************************************************
* Fixed-point HE-AAC decoder
* Jon Recker (jrecker@real.com)
* February 2005
*
* tns.c - apply TNS to spectrum
**************************************************************************************/
#include "coder.h"
#include "assembly.h"
#define FBITS_LPC_COEFS 20
//fb
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnarrowing"
/* inverse quantization tables for TNS filter coefficients, format = Q31
* see bottom of file for table generation
* negative (vs. spec) since we use MADD for filter kernel
*/
static const int invQuant3[16] PROGMEM = {
0x00000000, 0xc8767f65, 0x9becf22c, 0x83358feb, 0x83358feb, 0x9becf22c, 0xc8767f65, 0x00000000,
0x2bc750e9, 0x5246dd49, 0x6ed9eba1, 0x7e0e2e32, 0x7e0e2e32, 0x6ed9eba1, 0x5246dd49, 0x2bc750e9,
};
static const int invQuant4[16] PROGMEM = {
0x00000000, 0xe5632654, 0xcbf00dbe, 0xb4c373ee, 0xa0e0a15f, 0x9126145f, 0x8643c7b3, 0x80b381ac,
0x7f7437ad, 0x7b1d1a49, 0x7294b5f2, 0x66256db2, 0x563ba8aa, 0x4362210e, 0x2e3d2abb, 0x17851aad,
};
#pragma GCC diagnostic pop
/**************************************************************************************
* Function: DecodeLPCCoefs
*
* Description: decode LPC coefficients for TNS
*
* Inputs: order of TNS filter
* resolution of coefficients (3 or 4 bits)
* coefficients unpacked from bitstream
* scratch buffer (b) of size >= order
*
* Outputs: LPC coefficients in Q(FBITS_LPC_COEFS), in 'a'
*
* Return: none
*
* Notes: assumes no guard bits in input transform coefficients
* a[i] = Q(FBITS_LPC_COEFS), don't store a0 = 1.0
* (so a[0] = first delay tap, etc.)
* max abs(a[i]) < log2(order), so for max order = 20 a[i] < 4.4
* (up to 3 bits of gain) so a[i] has at least 31 - FBITS_LPC_COEFS - 3
* guard bits
* to ensure no intermediate overflow in all-pole filter, set
* FBITS_LPC_COEFS such that number of guard bits >= log2(max order)
**************************************************************************************/
static void DecodeLPCCoefs(int order, int res, signed char *filtCoef, int *a, int *b)
{
int i, m, t;
const int *invQuantTab;
if (res == 3) invQuantTab = invQuant3;
else if (res == 4) invQuantTab = invQuant4;
else return;
for (m = 0; m < order; m++) {
t = invQuantTab[filtCoef[m] & 0x0f]; /* t = Q31 */
for (i = 0; i < m; i++)
b[i] = a[i] - (MULSHIFT32(t, a[m-i-1]) << 1);
for (i = 0; i < m; i++)
a[i] = b[i];
a[m] = t >> (31 - FBITS_LPC_COEFS);
}
}
/**************************************************************************************
* Function: FilterRegion
*
* Description: apply LPC filter to one region of coefficients
*
* Inputs: number of transform coefficients in this region
* direction flag (forward = 1, backward = -1)
* order of filter
* 'size' transform coefficients
* 'order' LPC coefficients in Q(FBITS_LPC_COEFS)
* scratch buffer for history (must be >= order samples long)
*
* Outputs: filtered transform coefficients
*
* Return: guard bit mask (OR of abs value of all filtered transform coefs)
*
* Notes: assumes no guard bits in input transform coefficients
* gains 0 int bits
* history buffer does not need to be preserved between regions
**************************************************************************************/
static int FilterRegion(int size, int dir, int order, int *audioCoef, int *a, int *hist)
{
int i, j, y, hi32, inc, gbMask;
U64 sum64;
/* init history to 0 every time */
for (i = 0; i < order; i++)
hist[i] = 0;
sum64.w64 = 0; /* avoid warning */
gbMask = 0;
inc = (dir ? -1 : 1);
do {
/* sum64 = a0*y[n] = 1.0*y[n] */
y = *audioCoef;
sum64.r.hi32 = y >> (32 - FBITS_LPC_COEFS);
sum64.r.lo32 = y << FBITS_LPC_COEFS;
/* sum64 += (a1*y[n-1] + a2*y[n-2] + ... + a[order-1]*y[n-(order-1)]) */
for (j = order - 1; j > 0; j--) {
sum64.w64 = MADD64(sum64.w64, hist[j], a[j]);
hist[j] = hist[j-1];
}
sum64.w64 = MADD64(sum64.w64, hist[0], a[0]);
y = (sum64.r.hi32 << (32 - FBITS_LPC_COEFS)) | (sum64.r.lo32 >> FBITS_LPC_COEFS);
/* clip output (rare) */
hi32 = sum64.r.hi32;
if ((hi32 >> 31) != (hi32 >> (FBITS_LPC_COEFS-1)))
y = (hi32 >> 31) ^ 0x7fffffff;
hist[0] = y;
*audioCoef = y;
audioCoef += inc;
gbMask |= FASTABS(y);
} while (--size);
return gbMask;
}
/**************************************************************************************
* Function: TNSFilter
*
* Description: apply temporal noise shaping, if enabled
*
* Inputs: valid AACDecInfo struct
* index of current channel
*
* Outputs: updated transform coefficients
* updated minimum guard bit count for this channel
*
* Return: 0 if successful, -1 if error
**************************************************************************************/
int TNSFilter(AACDecInfo *aacDecInfo, int ch)
{
int win, winLen, nWindows, nSFB, filt, bottom, top, order, maxOrder, dir;
int start, end, size, tnsMaxBand, numFilt, gbMask;
int *audioCoef;
unsigned char *filtLength, *filtOrder, *filtRes, *filtDir;
signed char *filtCoef;
const unsigned /*char*/ int *tnsMaxBandTab;
const /*short*/ int *sfbTab;
ICSInfo *icsInfo;
TNSInfo *ti;
PSInfoBase *psi;
/* validate pointers */
if (!aacDecInfo || !aacDecInfo->psInfoBase)
return -1;
psi = (PSInfoBase *)(aacDecInfo->psInfoBase);
icsInfo = (ch == 1 && psi->commonWin == 1) ? &(psi->icsInfo[0]) : &(psi->icsInfo[ch]);
ti = &psi->tnsInfo[ch];
if (!ti->tnsDataPresent)
return 0;
if (icsInfo->winSequence == 2) {
nWindows = NWINDOWS_SHORT;
winLen = NSAMPS_SHORT;
nSFB = sfBandTotalShort[psi->sampRateIdx];
maxOrder = tnsMaxOrderShort[aacDecInfo->profile];
sfbTab = sfBandTabShort + sfBandTabShortOffset[psi->sampRateIdx];
tnsMaxBandTab = tnsMaxBandsShort + tnsMaxBandsShortOffset[aacDecInfo->profile];
tnsMaxBand = tnsMaxBandTab[psi->sampRateIdx];
} else {
nWindows = NWINDOWS_LONG;
winLen = NSAMPS_LONG;
nSFB = sfBandTotalLong[psi->sampRateIdx];
maxOrder = tnsMaxOrderLong[aacDecInfo->profile];
sfbTab = sfBandTabLong + sfBandTabLongOffset[psi->sampRateIdx];
tnsMaxBandTab = tnsMaxBandsLong + tnsMaxBandsLongOffset[aacDecInfo->profile];
tnsMaxBand = tnsMaxBandTab[psi->sampRateIdx];
}
if (tnsMaxBand > icsInfo->maxSFB)
tnsMaxBand = icsInfo->maxSFB;
filtRes = ti->coefRes;
filtLength = ti->length;
filtOrder = ti->order;
filtDir = ti->dir;
filtCoef = ti->coef;
gbMask = 0;
audioCoef = psi->coef[ch];
for (win = 0; win < nWindows; win++) {
bottom = nSFB;
numFilt = ti->numFilt[win];
for (filt = 0; filt < numFilt; filt++) {
top = bottom;
bottom = top - *filtLength++;
bottom = MAX(bottom, 0);
order = *filtOrder++;
order = MIN(order, maxOrder);
if (order) {
start = sfbTab[MIN(bottom, tnsMaxBand)];
end = sfbTab[MIN(top, tnsMaxBand)];
size = end - start;
if (size > 0) {
dir = *filtDir++;
if (dir)
start = end - 1;
DecodeLPCCoefs(order, filtRes[win], filtCoef, psi->tnsLPCBuf, psi->tnsWorkBuf);
gbMask |= FilterRegion(size, dir, order, audioCoef + start, psi->tnsLPCBuf, psi->tnsWorkBuf);
}
filtCoef += order;
}
}
audioCoef += winLen;
}
/* update guard bit count if necessary */
size = CLZ(gbMask) - 1;
if (psi->gbCurrent[ch] > size)
psi->gbCurrent[ch] = size;
return 0;
}
/* Code to generate invQuantXXX[] tables
* {
* int res, i, t;
* double powScale, iqfac, iqfac_m, d;
*
* powScale = pow(2.0, 31) * -1.0; / ** make coefficients negative for using MADD in kernel ** /
* for (res = 3; res <= 4; res++) {
* iqfac = ( ((1 << (res-1)) - 0.5) * (2.0 / M_PI) );
* iqfac_m = ( ((1 << (res-1)) + 0.5) * (2.0 / M_PI) );
* printf("static const int invQuant%d[16] = {\n", res);
* for (i = 0; i < 16; i++) {
* / ** extend bottom 4 bits into signed, 2's complement number ** /
* t = (i << 28) >> 28;
*
* if (t >= 0) d = sin(t / iqfac);
* else d = sin(t / iqfac_m);
*
* d *= powScale;
* printf("0x%08x, ", (int)(d > 0 ? d + 0.5 : d - 0.5));
* if ((i & 0x07) == 0x07)
* printf("\n");
* }
* printf("};\n\n");
* }
* }
*/

File diff suppressed because it is too large Load Diff