From 698b536f3b34a7cfc41a80e1034cc359456bdd66 Mon Sep 17 00:00:00 2001 From: Dave Burke Date: Sat, 12 May 2012 13:17:25 -0700 Subject: Update to 2012_05_11 version. Fixes: - Don't throw error for invalid bitrate but limit to functional value - More robust ASC parsing - More robust handling of corrupt bitstreams - Handle multiple raw access units Change-Id: Ib49fe2545ff4185fe924126da702fe84ac5c2d87 --- libAACdec/src/aacdec_drc.cpp | 64 ++- libAACdec/src/aacdec_drc_types.h | 8 +- libAACdec/src/aacdec_hcrs.cpp | 3 + libAACdec/src/aacdec_tns.h | 2 +- libAACdec/src/aacdecoder.cpp | 73 ++- libAACdec/src/aacdecoder_lib.cpp | 4 +- libAACenc/src/aacenc.cpp | 95 ++-- libAACenc/src/aacenc.h | 27 + libAACenc/src/aacenc_lib.cpp | 164 +++++- libAACenc/src/psy_data.h | 2 +- libAACenc/src/qc_main.cpp | 35 +- libFDK/include/FDK_hybrid.h | 211 +++++++ libFDK/include/arm/clz_arm.h | 6 +- libFDK/include/fixpoint_math.h | 12 + libFDK/include/qmf.h | 2 +- libFDK/src/Android.mk | 1 + libFDK/src/FDK_hybrid.cpp | 766 +++++++++++++++++++++++++ libFDK/src/dct.cpp | 2 +- libFDK/src/fft.cpp | 8 +- libFDK/src/qmf.cpp | 2 +- libMpegTPDec/include/tpdec_lib.h | 3 +- libMpegTPDec/src/tpdec_asc.cpp | 101 +--- libMpegTPDec/src/tpdec_latm.cpp | 3 - libMpegTPDec/src/tpdec_lib.cpp | 28 +- libMpegTPEnc/src/tpenc_asc.cpp | 33 +- libSBRdec/src/env_extr.cpp | 6 +- libSBRdec/src/sbr_dec.cpp | 7 +- libSBRdec/src/sbr_ram.cpp | 2 +- libSBRdec/src/sbrdecoder.cpp | 31 +- libSBRenc/include/sbr_encoder.h | 10 + libSBRenc/src/Android.mk | 1 - libSBRenc/src/env_est.cpp | 34 +- libSBRenc/src/env_est.h | 3 +- libSBRenc/src/ps_bitenc.cpp | 3 +- libSBRenc/src/ps_const.h | 24 +- libSBRenc/src/ps_encode.cpp | 228 +++----- libSBRenc/src/ps_encode.h | 44 +- libSBRenc/src/ps_main.cpp | 1143 +++++++++++--------------------------- libSBRenc/src/ps_main.h | 220 +++++--- libSBRenc/src/psenc_hybrid.cpp | 836 ---------------------------- libSBRenc/src/psenc_hybrid.h | 182 ------ libSBRenc/src/sbr.h | 3 +- libSBRenc/src/sbr_encoder.cpp | 189 +++++-- libSBRenc/src/sbr_ram.cpp | 62 +-- libSBRenc/src/sbr_ram.h | 72 +-- libSBRenc/src/sbr_rom.cpp | 14 +- libSBRenc/src/sbr_rom.h | 8 +- libSYS/include/FDK_audio.h | 6 + libSYS/include/genericStds.h | 2 +- 49 files changed, 2179 insertions(+), 2606 deletions(-) create mode 100644 libFDK/include/FDK_hybrid.h create mode 100644 libFDK/src/FDK_hybrid.cpp delete mode 100644 libSBRenc/src/psenc_hybrid.cpp delete mode 100644 libSBRenc/src/psenc_hybrid.h diff --git a/libAACdec/src/aacdec_drc.cpp b/libAACdec/src/aacdec_drc.cpp index 58abea2..9049353 100644 --- a/libAACdec/src/aacdec_drc.cpp +++ b/libAACdec/src/aacdec_drc.cpp @@ -42,7 +42,7 @@ #define DRC_PARAMETER_BITS ( 7 ) #define DRC_MAX_QUANT_STEPS ( 1<bandTop[0] = (1024 >> 2) - 1; pDrcChData->drcValue[0] = 0; pDrcChData->drcInterpolationScheme = 0; + pDrcChData->drcDataType = UNKNOWN_PAYLOAD; } } @@ -130,7 +131,7 @@ AAC_DECODER_ERROR aacDecoder_drcSetParam ( if (self == NULL) { return AAC_DEC_INVALID_HANDLE; } - self->params.cut = (FIXP_DBL)((INT)(DRC_PARAM_QUANT_STEP>>DRC_PARAM_SCALE) * (INT)(value+1)); + self->params.cut = (FIXP_DBL)((INT)(DRC_PARAM_QUANT_STEP>>DRC_PARAM_SCALE) * (INT)value); break; case DRC_BOOST_SCALE: /* set boost factor */ @@ -141,7 +142,7 @@ AAC_DECODER_ERROR aacDecoder_drcSetParam ( if (self == NULL) { return AAC_DEC_INVALID_HANDLE; } - self->params.boost = (FIXP_DBL)((INT)(DRC_PARAM_QUANT_STEP>>DRC_PARAM_SCALE) * (INT)(value+1)); + self->params.boost = (FIXP_DBL)((INT)(DRC_PARAM_QUANT_STEP>>DRC_PARAM_SCALE) * (INT)value); break; case TARGET_REF_LEVEL: if ( value > MAX_REFERENCE_LEVEL @@ -300,14 +301,13 @@ int aacDecoder_drcMarkPayload ( break; case DVB_DRC_ANC_DATA: + bitCnt += 8; /* check sync word */ if (FDKreadBits(bs, 8) == DVB_ANC_DATA_SYNC_BYTE) { int dmxLevelsPresent, compressionPresent; int coarseGrainTcPresent, fineGrainTcPresent; - bitCnt+=8; - /* bs_info field */ FDKreadBits(bs, 8); /* mpeg_audio_type, dolby_surround_mode, presentation_mode */ bitCnt+=8; @@ -432,7 +432,7 @@ static int aacDecoder_drcParse ( } /* Set DRC payload type */ - pDrcBs->type = MPEG_DRC_EXT_DATA; + pDrcBs->channelData.drcDataType = MPEG_DRC_EXT_DATA; return (bitCnt); } @@ -515,23 +515,26 @@ static int aacDecoder_drcReadCompression ( if ( compressionOn ) { /* A compression value is available so store the data just like MPEG DRC data */ - pDrcBs->channelData.drcValue[0] = compressionValue; - pDrcBs->channelData.numBands = 1; /* one value for all bands */ - pDrcBs->pceInstanceTag = -1; /* not present */ - pDrcBs->progRefLevel = -1; /* not present */ + pDrcBs->channelData.numBands = 1; /* One band ... */ + pDrcBs->channelData.drcValue[0] = compressionValue; /* ... with one value ... */ + pDrcBs->channelData.bandTop[0] = (1024 >> 2) - 1; /* ... comprising the whole spectrum. */ + pDrcBs->pceInstanceTag = -1; /* Not present */ + pDrcBs->progRefLevel = -1; /* Not present */ + pDrcBs->channelData.drcDataType = DVB_DRC_ANC_DATA; /* Set DRC payload type to DVB. */ } else { /* No compression value available */ /* CAUTION: It is not clearly defined by standard how to react in this situation. */ - pDrcBs->channelData.drcValue[0] = 0x7F; /* 0dB */ - pDrcBs->channelData.bandTop[0] = 0; + /* Turn down the compression value to aprox. 0dB */ + pDrcBs->channelData.numBands = 1; /* One band ... */ + pDrcBs->channelData.drcValue[0] = 0x80; /* ... with aprox. 0dB ... */ + pDrcBs->channelData.bandTop[0] = (1024 >> 2) - 1; /* ... comprising the whole spectrum. */ + pDrcBs->channelData.drcDataType = DVB_DRC_ANC_DATA; /* Set DRC payload type to DVB. */ /* If compression_on field is set to "0" the compression_value field shall be "0000 0000". */ if (compressionValue != 0) { return 0; } } - /* Set DRC payload type now because the payload seems to be correct. */ - pDrcBs->type = DVB_DRC_ANC_DATA; } /* Read timecodes if available just to get the right amount of bits. */ @@ -617,7 +620,7 @@ static int aacDecoder_drcExtractAndMap ( CDrcPayload *pThreadBs = &threadBs[thread]; int numExclChns = 0; - switch (pThreadBs->type) { + switch ((AACDEC_DRC_PAYLOAD_TYPE)pThreadBs->channelData.drcDataType) { default: continue; case MPEG_DRC_EXT_DATA: @@ -659,7 +662,7 @@ static int aacDecoder_drcExtractAndMap ( /* thread applies to this channel */ - if ( (pThreadBs->type == MPEG_DRC_EXT_DATA) + if ( (pThreadBs->channelData.drcDataType == MPEG_DRC_EXT_DATA) && ( (numExcludedChns[thread] == 0) || (!(pThreadBs->excludedChnsMask & (1<excludedChnsMask; + AACDEC_DRC_PAYLOAD_TYPE drcPayloadType = (AACDEC_DRC_PAYLOAD_TYPE)pThreadBs->channelData.drcDataType; int ch; /* last progRefLevel transmitted is the one that is used @@ -692,9 +696,9 @@ static int aacDecoder_drcExtractAndMap ( int mapedChannel = channelMapping[ch]; if ( ((exclMask & (1<params.applyHeavyCompression && (pThreadBs->type == DVB_DRC_ANC_DATA)) - || (!self->params.applyHeavyCompression && (pThreadBs->type == MPEG_DRC_EXT_DATA)) ) - ) { + && ( (drcPayloadType == MPEG_DRC_EXT_DATA) + || ((drcPayloadType == DVB_DRC_ANC_DATA) && self->params.applyHeavyCompression) + ) ) { /* copy thread to channel */ pAacDecoderStaticChannelInfo[ch]->drcData = pThreadBs->channelData; } @@ -781,10 +785,17 @@ void aacDecoder_drcApply ( UCHAR drcVal = pDrcChData->drcValue[band]; top = fixMin((int)( (pDrcChData->bandTop[band]+1)<<2 ), aacFrameSize); - if ( pParams->applyHeavyCompression ) { + fact_mantissa[band] = FL2FXCONST_DBL(0.5f); + fact_exponent[band] = 1; + + if ( pParams->applyHeavyCompression + && ((AACDEC_DRC_PAYLOAD_TYPE)pDrcChData->drcDataType == DVB_DRC_ANC_DATA) ) + { INT compressionFactorVal_e; - int valX = drcVal >> 4; - int valY = drcVal & 0x0F; + int valX, valY; + + valX = drcVal >> 4; + valY = drcVal & 0x0F; /* calculate the unscaled heavy compression factor. compressionFactor = 48.164 - 6.0206*valX - 0.4014*valY dB @@ -801,11 +812,8 @@ void aacDecoder_drcApply ( fact_exponent[band] = DVB_COMPRESSION_SCALE - valX + compressionFactorVal_e; } - else { - fact_mantissa[band] = FL2FXCONST_DBL(0.5f); - fact_exponent[band] = 1; - } } else + if ((AACDEC_DRC_PAYLOAD_TYPE)pDrcChData->drcDataType == MPEG_DRC_EXT_DATA) { /* apply the scaled dynamic range control words to factor. * if scaling drc_cut (or drc_boost), or control word drc_mantissa is 0 @@ -824,10 +832,6 @@ void aacDecoder_drcApply ( 3+DRC_PARAM_SCALE, &fact_exponent[band] ); } - else { - fact_mantissa[band] = FL2FXCONST_DBL(0.5f); - fact_exponent[band] = 1; - } } fact_mantissa[band] = fMult(fact_mantissa[band], norm_mantissa); diff --git a/libAACdec/src/aacdec_drc_types.h b/libAACdec/src/aacdec_drc_types.h index 20a593b..2306bb9 100644 --- a/libAACdec/src/aacdec_drc_types.h +++ b/libAACdec/src/aacdec_drc_types.h @@ -41,9 +41,9 @@ */ typedef enum { - UNKNOWN_PAYLOAD = 0, - MPEG_DRC_EXT_DATA, - DVB_DRC_ANC_DATA + UNKNOWN_PAYLOAD = 0, + MPEG_DRC_EXT_DATA = 1, + DVB_DRC_ANC_DATA = 2 } AACDEC_DRC_PAYLOAD_TYPE; @@ -54,12 +54,12 @@ typedef struct USHORT bandTop[MAX_DRC_BANDS]; SHORT drcInterpolationScheme; UCHAR drcValue[MAX_DRC_BANDS]; + SCHAR drcDataType; } CDrcChannelData; typedef struct { - AACDEC_DRC_PAYLOAD_TYPE type; UINT excludedChnsMask; SCHAR progRefLevel; SCHAR pceInstanceTag; diff --git a/libAACdec/src/aacdec_hcrs.cpp b/libAACdec/src/aacdec_hcrs.cpp index da8928e..1c2bb46 100644 --- a/libAACdec/src/aacdec_hcrs.cpp +++ b/libAACdec/src/aacdec_hcrs.cpp @@ -736,6 +736,9 @@ UINT Hcr_State_BODY_SIGN__SIGN(HANDLE_FDK_BITSTREAM bs, void *ptr) /* search for a line (which was decoded in previous state) which is not zero. [This value will get a sign] */ while ( pResultBase[iQSC] == (FIXP_DBL)0 ) { iQSC++; /* points to current value different from zero */ + if (iQSC >= 1024) { + return BODY_SIGN__SIGN; + } } /* put sign together with line; if carryBit is zero, the sign is ok already; no write operation necessary in this case */ diff --git a/libAACdec/src/aacdec_tns.h b/libAACdec/src/aacdec_tns.h index cf3f597..55b31ce 100644 --- a/libAACdec/src/aacdec_tns.h +++ b/libAACdec/src/aacdec_tns.h @@ -34,7 +34,7 @@ enum { TNS_MAX_WINDOWS = 8, /* 8 */ - TNS_MAXIMUM_ORDER = 12, /* 12 for AAC-LC and AAC-SSR. Set to 20 for AAC-Main (AOT 1). Some broken encoders also do order 20 for AAC-LC :( */ + TNS_MAXIMUM_ORDER = 20, /* 12 for AAC-LC and AAC-SSR. Set to 20 for AAC-Main (AOT 1). Some broken encoders also do order 20 for AAC-LC :( */ TNS_MAXIMUM_FILTERS = 3 }; diff --git a/libAACdec/src/aacdecoder.cpp b/libAACdec/src/aacdecoder.cpp index 534d48f..77c415b 100644 --- a/libAACdec/src/aacdecoder.cpp +++ b/libAACdec/src/aacdecoder.cpp @@ -345,6 +345,7 @@ static AAC_DECODER_ERROR CProgramConfigElement_Read ( HANDLE_FDK_BITSTREAM bs, HANDLE_TRANSPORTDEC pTp, CProgramConfig *pce, + UINT channelConfig, UINT alignAnchor ) { AAC_DECODER_ERROR error = AAC_DEC_OK; @@ -362,8 +363,15 @@ static AAC_DECODER_ERROR CProgramConfigElement_Read ( transportDec_CrcEndReg(pTp, crcReg); - if (!pce->isValid && tmpPce->NumChannels <= (6) && tmpPce->Profile == 1) { - /* store PCE data */ + if ( CProgramConfig_IsValid(tmpPce) + && ( (channelConfig == 6 && (tmpPce->NumChannels == 6)) + || (channelConfig == 5 && (tmpPce->NumChannels == 5)) + || (channelConfig == 0 && (tmpPce->NumChannels == pce->NumChannels)) ) + && (tmpPce->NumFrontChannelElements == 2) + && (tmpPce->NumSideChannelElements == 0) + && (tmpPce->NumBackChannelElements == 1) + && (tmpPce->Profile == 1) ) + { /* Copy the complete PCE including metadata. */ FDKmemcpy(pce, tmpPce, sizeof(CProgramConfig)); } @@ -411,29 +419,18 @@ AAC_DECODER_ERROR CAacDecoder_ExtPayloadParse (HANDLE_AACDECODER self, INT readBits = aacDecoder_drcMarkPayload( self->hDrcInfo, hBs, MPEG_DRC_EXT_DATA ); if (readBits > *count) - { - FDKpushBack(hBs, readBits - *count); + { /* Read too much. Something went wrong! */ error = AAC_DEC_PARSE_ERROR; - return error; - } - else - { - *count -= (readBits+7) & ~0x7; } + *count -= readBits; } break; - case EXT_LDSAC_DATA: - case EXT_SAC_DATA: - /* Skip MPEG Surround Extension payload */ - FDKpushFor(hBs, *count); - *count = 0; - break; + case EXT_SBR_DATA_CRC: crcFlag = 1; - case EXT_SBR_DATA: - { + if (IS_CHANNEL_ELEMENT(previous_element)) { SBR_ERROR sbrError; CAacDecoder_SyncQmfMode(self); @@ -479,6 +476,8 @@ AAC_DECODER_ERROR CAacDecoder_ExtPayloadParse (HANDLE_AACDECODER self, self->frameOK = 0; } } + } else { + error = AAC_DEC_PARSE_ERROR; } break; @@ -523,14 +522,16 @@ AAC_DECODER_ERROR CAacDecoder_ExtPayloadParse (HANDLE_AACDECODER self, *count -= (dataElementLength<<3); } else { /* align = 0 */ - FDKpushFor(hBs, (*count)<<3); - *count = 0; + error = AAC_DEC_PARSE_ERROR; + goto bail; } } break; case EXT_DATA_LENGTH: - { + if ( !fIsFillElement /* Makes no sens to have an additional length in a fill ... */ + && (self->flags & AC_ER) ) /* ... element because this extension payload type was ... */ + { /* ... created to circumvent the missing length in ER-Syntax. */ int bitCnt, len = FDKreadBits(hBs, 4); *count -= 4; @@ -551,7 +552,9 @@ AAC_DECODER_ERROR CAacDecoder_ExtPayloadParse (HANDLE_AACDECODER self, /* Check NOTE 2: The extension_payload() included here must not have extension_type == EXT_DATA_LENGTH. */ error = AAC_DEC_PARSE_ERROR; - } else { + goto bail; + } + else { /* rewind and call myself again. */ FDKpushBack(hBs, 4); @@ -562,12 +565,13 @@ AAC_DECODER_ERROR CAacDecoder_ExtPayloadParse (HANDLE_AACDECODER self, &bitCnt, previous_element, elIndex, - 0 ); + 1 ); /* Treat same as fill element */ *count -= len - bitCnt; } + /* Note: the fall through in case the if statement above is not taken is intentional. */ + break; } - break; case EXT_FIL: @@ -578,6 +582,16 @@ AAC_DECODER_ERROR CAacDecoder_ExtPayloadParse (HANDLE_AACDECODER self, break; } +bail: + if ( (error != AAC_DEC_OK) + && fIsFillElement ) + { /* Skip the remaining extension bytes */ + FDKpushBiDirectional(hBs, *count); + *count = 0; + /* Patch error code because decoding can go on. */ + error = AAC_DEC_OK; + /* Be sure that parsing errors have been stored. */ + } return error; } @@ -750,7 +764,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_Init(HANDLE_AACDECODER self, const CS /* valid number of channels -> copy program config element (PCE) from ASC */ FDKmemcpy(&self->pce, &asc->m_progrConfigElement, sizeof(CProgramConfig)); /* Built element table */ - el = CProgramConfig_GetElementTable(&asc->m_progrConfigElement, self->elements); + el = CProgramConfig_GetElementTable(&asc->m_progrConfigElement, self->elements, 7); for (; el<7; el++) { self->elements[el] = ID_NONE; } @@ -1286,7 +1300,6 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( } } -#if defined(PCM_POSTPROCESS_ENABLE) && defined(DVB_MIXDOWN_ENABLE) && defined(AACDEC_DVB_SUPPORT_ENABLE) { UCHAR *pDvbAncData = NULL; AAC_DECODER_ERROR ancErr; @@ -1309,7 +1322,6 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( 0 /* not mpeg2 */ ); } } -#endif /* PCM_POSTPROCESS_ENABLE && DVB_MIXDOWN_ENABLE && AACDEC_DVB_SUPPORT_ENABLE */ break; #ifdef TP_PCE_ENABLE @@ -1318,9 +1330,10 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( if ( CProgramConfigElement_Read( bs, self->hInput, pce, + self->streamInfo.channelConfig, auStartAnchor ) ) { /* Built element table */ - int elIdx = CProgramConfig_GetElementTable(pce, self->elements); + int elIdx = CProgramConfig_GetElementTable(pce, self->elements, 7); /* Reset the remaining tabs */ for ( ; elIdx<7; elIdx++) { self->elements[elIdx] = ID_NONE; @@ -1368,7 +1381,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( if ( (bitCnt > 0) && (self->flags & AC_SBR_PRESENT) && (self->flags & (AC_USAC|AC_RSVD50|AC_ELD)) ) { - SBR_ERROR err; + SBR_ERROR err = SBRDEC_OK; int elIdx, numChElements = el_cnt[ID_SCE] + el_cnt[ID_CPE]; for (elIdx = 0; elIdx < numChElements; elIdx += 1) @@ -1494,7 +1507,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( /* Update number of output channels */ self->streamInfo.numChannels = aacChannels; -#if defined(TP_PCE_ENABLE) && defined(PCM_POSTPROCESS_ENABLE) && defined(MPEG_PCE_MIXDOWN_ENABLE) + #ifdef TP_PCE_ENABLE if (pceRead == 1 || CProgramConfig_IsValid(pce)) { /* Set matrix mixdown infos if available from PCE. */ pcmDmx_SetMatrixMixdownFromPce ( self->hPcmUtils, @@ -1502,7 +1515,7 @@ LINKSPEC_CPP AAC_DECODER_ERROR CAacDecoder_DecodeFrame( pce->MatrixMixdownIndex, pce->PseudoSurroundEnable ); } -#endif + #endif /* If there is no valid data to transfrom into time domain, return. */ if ( ! IS_OUTPUT_VALID(ErrorStatus) ) { diff --git a/libAACdec/src/aacdecoder_lib.cpp b/libAACdec/src/aacdecoder_lib.cpp index 379c84c..763981b 100644 --- a/libAACdec/src/aacdecoder_lib.cpp +++ b/libAACdec/src/aacdecoder_lib.cpp @@ -48,7 +48,7 @@ /* Decoder library info */ #define AACDECODER_LIB_VL0 2 #define AACDECODER_LIB_VL1 4 -#define AACDECODER_LIB_VL2 0 +#define AACDECODER_LIB_VL2 1 #define AACDECODER_LIB_TITLE "AAC Decoder Lib" #define AACDECODER_LIB_BUILD_DATE __DATE__ #define AACDECODER_LIB_BUILD_TIME __TIME__ @@ -500,6 +500,8 @@ LINKSPEC_CPP HANDLE_AACDECODER aacDecoder_Open(TRANSPORT_TYPE transportFmt, UINT return NULL; } + transportDec_SetParam(pIn, TPDEC_PARAM_IGNORE_BUFFERFULLNESS, 1); + /* Allocate AAC decoder core struct. */ aacDec = CAacDecoder_Open(transportFmt); diff --git a/libAACenc/src/aacenc.cpp b/libAACenc/src/aacenc.cpp index 5ab7192..c2c744f 100644 --- a/libAACenc/src/aacenc.cpp +++ b/libAACenc/src/aacenc.cpp @@ -43,48 +43,61 @@ +#define MIN_BUFSIZE_PER_EFF_CHAN 6144 + static AAC_ENCODER_ERROR FDKaacEnc_InitCheckAncillary(INT bitRate, INT framelength, INT ancillaryRate, INT *ancillaryBitsPerFrame, INT sampleRate); -/** - * For calculating average bitrate of an access unit 32 bit data width is not sufficient - * in worst case. Therefore use scaling of the samplingrate parameter to keep complete information. - */ -typedef struct { - INT samplingRate; - UCHAR scalingFactor; -} SR_SCALING_TAB; - -static const SR_SCALING_TAB samplingRateScalingTable[] = +INT FDKaacEnc_LimitBitrate( + HANDLE_TRANSPORTENC hTpEnc, + INT coreSamplingRate, + INT frameLength, + INT nChannels, + INT nChannelsEff, + INT bitRate, + INT averageBits, + INT *pAverageBitsPerFrame, + INT bitrateMode, + INT nSubFrames + ) { - { 8000, 5 }, { 11025, 0 }, { 12000, 5 }, { 16000, 5 }, - { 22050, 1 }, { 24000, 5 }, { 32000, 5 }, { 44100, 2 }, - { 48000, 5 }, { 64000, 5 }, { 88200, 3 }, { 96000, 5 } -}; + INT transportBits, prevBitRate, averageBitsPerFrame, shift = 0, iter=0; -/** - * Get maximal scaling factor without losing samplingrate accuracy. - * - * \param samplingRate Samplingrate to be used. - * \return scaling value. - */ -static int GetSrSf(const INT samplingRate) -{ - int i, result = 0; + while ( (frameLength & ~((1<<(shift+1))-1)) == frameLength + && (coreSamplingRate & ~((1<<(shift+1))-1)) == coreSamplingRate ) + { + shift ++; + } - for (i=0; i<(int)(sizeof(samplingRateScalingTable)/sizeof(SR_SCALING_TAB)); i++) { - if ( samplingRateScalingTable[i].samplingRate == samplingRate ) { - result = samplingRateScalingTable[i].scalingFactor; - break; + do { + prevBitRate = bitRate; + averageBitsPerFrame = (bitRate*(frameLength>>shift)) / (coreSamplingRate>>shift) / nSubFrames; + + if (pAverageBitsPerFrame != NULL) { + *pAverageBitsPerFrame = averageBitsPerFrame; } - } - return result; + + if (hTpEnc != NULL) { + transportBits = transportEnc_GetStaticBits(hTpEnc, averageBitsPerFrame); + } else { + /* Assume some worst case */ + transportBits = 208; + } + + bitRate = FDKmax(bitRate, ((((40 * nChannels) + transportBits + frameLength) * (coreSamplingRate)) / frameLength) ); + FDK_ASSERT(bitRate >= 0); + + bitRate = FDKmin(bitRate, ((nChannelsEff * MIN_BUFSIZE_PER_EFF_CHAN)*(coreSamplingRate>>shift)) / (frameLength>>shift)) ; + FDK_ASSERT(bitRate >= 0); + + } while (prevBitRate != bitRate && iter++ < 3) ; + + return bitRate; } -#define MIN_BUFSIZE_PER_EFF_CHAN 6144 typedef struct { @@ -349,16 +362,20 @@ AAC_ENCODER_ERROR FDKaacEnc_Initialize(HANDLE_AAC_ENC hAacEnc, /* check bit rate */ - /* check if bitRate is not too low or high */ - averageBitsPerFrame = (config->bitRate*(config->framelength>>GetSrSf(config->sampleRate))) / (config->sampleRate>>GetSrSf(config->sampleRate)) / config->nSubFrames; - - /* assume minimum static bits of 40 in each channel. */ - if ( (averageBitsPerFrame <= ((40*config->nChannels) + transportEnc_GetStaticBits(hTpEnc, averageBitsPerFrame))) || - ( ((config->bitRate*(config->framelength>>GetSrSf(config->sampleRate)))) > - ((FDKaacEnc_GetChannelModeConfiguration(config->channelMode)->nChannelsEff * MIN_BUFSIZE_PER_EFF_CHAN))*(config->sampleRate>>GetSrSf(config->sampleRate)) ) - ) + if (FDKaacEnc_LimitBitrate( + hTpEnc, + config->sampleRate, + config->framelength, + config->nChannels, + FDKaacEnc_GetChannelModeConfiguration(config->channelMode)->nChannelsEff, + config->bitRate, + config->averageBits, + &averageBitsPerFrame, + config->bitrateMode, + config->nSubFrames + ) != config->bitRate ) { - return AAC_ENC_UNSUPPORTED_BITRATE; + return AAC_ENC_UNSUPPORTED_BITRATE; } if (config->syntaxFlags & AC_ER_VCB11) { diff --git a/libAACenc/src/aacenc.h b/libAACenc/src/aacenc.h index 66ef2b9..22228f6 100644 --- a/libAACenc/src/aacenc.h +++ b/libAACenc/src/aacenc.h @@ -159,6 +159,33 @@ typedef struct { typedef struct AAC_ENC *HANDLE_AAC_ENC; +/** + * \brief Limit given bit rate to a valid value + * \param hTpEnc transport encoder handle + * \param coreSamplingRate the sample rate to be used for the AAC encoder + * \param frameLength the frameLength to be used for the AAC encoder + * \param nChannels number of total channels + * \param nChannelsEff number of effective channels + * \param bitRate the initial bit rate value for which the closest valid bit rate value is searched for + * \param averageBits average bits per frame for fixed framing. Set to -1 if not available. + * \param optional pointer where the current bits per frame are stored into. + * \param bitrateMode the current bit rate mode + * \param nSubFrames number of sub frames for super framing (not transport frames). + * \return a valid bit rate value as close as possible or identical to bitRate + */ +INT FDKaacEnc_LimitBitrate( + HANDLE_TRANSPORTENC hTpEnc, + INT coreSamplingRate, + INT frameLength, + INT nChannels, + INT nChannelsEff, + INT bitRate, + INT averageBits, + INT *pAverageBitsPerFrame, + INT bitrateMode, + INT nSubFrames + ); + /*----------------------------------------------------------------------------- functionname: FDKaacEnc_GetVBRBitrate diff --git a/libAACenc/src/aacenc_lib.cpp b/libAACenc/src/aacenc_lib.cpp index 65a9bfc..7984c13 100644 --- a/libAACenc/src/aacenc_lib.cpp +++ b/libAACenc/src/aacenc_lib.cpp @@ -388,6 +388,138 @@ AAC_ENCODER_ERROR aacEncDefaultConfig(HANDLE_AACENC_CONFIG hAacConfig, return AAC_ENC_OK; } +static +void aacEncDistributeSbrBits(CHANNEL_MAPPING *channelMapping, SBR_ELEMENT_INFO *sbrElInfo, INT bitRate) +{ + INT codebits = bitRate; + int el; + + /* Copy Element info */ + for (el=0; elnElements; el++) { + sbrElInfo[el].ChannelIndex[0] = channelMapping->elInfo[el].ChannelIndex[0]; + sbrElInfo[el].ChannelIndex[1] = channelMapping->elInfo[el].ChannelIndex[1]; + sbrElInfo[el].elType = channelMapping->elInfo[el].elType; + sbrElInfo[el].bitRate = (INT)(fMultNorm(channelMapping->elInfo[el].relativeBits, (FIXP_DBL)bitRate)); + sbrElInfo[el].instanceTag = channelMapping->elInfo[el].instanceTag; + sbrElInfo[el].nChannelsInEl = channelMapping->elInfo[el].nChannelsInEl; + + codebits -= sbrElInfo[el].bitRate; + } + sbrElInfo[0].bitRate += codebits; +} + + +static +INT aacEncoder_LimitBitrate( + const HANDLE_TRANSPORTENC hTpEnc, + const INT samplingRate, + const INT frameLength, + const INT nChannels, + const CHANNEL_MODE channelMode, + INT bitRate, + const INT nSubFrames, + const INT sbrActive, + const AUDIO_OBJECT_TYPE aot + ) +{ + INT coreSamplingRate; + CHANNEL_MAPPING cm; + + FDKaacEnc_InitChannelMapping(channelMode, CH_ORDER_MPEG, &cm); + + if (sbrActive) { + /* Assume SBR rate ratio of 2:1 */ + coreSamplingRate = samplingRate / 2; + } else { + coreSamplingRate = samplingRate; + } + + /* Consider bandwidth channel bit rate limit (see bandwidth.cpp: GetBandwidthEntry()) */ + if (aot == AOT_ER_AAC_LD || aot == AOT_ER_AAC_ELD) { + bitRate = FDKmin(360000*nChannels, bitRate); + bitRate = FDKmax(8000*nChannels, bitRate); + } + + if (aot == AOT_AAC_LC || aot == AOT_SBR || aot == AOT_PS) { + bitRate = FDKmin(576000*nChannels, bitRate); + /*bitRate = FDKmax(0*nChannels, bitRate);*/ + } + + + /* Limit bit rate in respect to the core coder */ + bitRate = FDKaacEnc_LimitBitrate( + hTpEnc, + coreSamplingRate, + frameLength, + nChannels, + cm.nChannelsEff, + bitRate, + -1, + NULL, + -1, + nSubFrames + ); + + /* Limit bit rate in respect to available SBR modes if active */ + if (sbrActive) + { + SBR_ELEMENT_INFO sbrElInfo[6]; + INT sbrBitRate = 0; + int e, tooBig=-1; + + FDK_ASSERT(cm.nElements <= (6)); + + /* Get bit rate for each SBR element */ + aacEncDistributeSbrBits(&cm, sbrElInfo, bitRate); + + for (e=0; e sbrBitRateOut) { + FDK_ASSERT(tooBig != 0); + tooBig = 1; + if (e == 0) { + sbrBitRate = 5000000; + } + } + if (tooBig != -1) + { + INT sbrBitRateLimit = (INT)fDivNorm((FIXP_DBL)sbrBitRateOut, cm.elInfo[e].relativeBits); + if (tooBig) { + sbrBitRate = fMin(sbrBitRate, sbrBitRateLimit-16); + FDK_ASSERT( (INT)fMultNorm(cm.elInfo[e].relativeBits, (FIXP_DBL)sbrBitRate) < sbrBitRateOut); + } else { + sbrBitRate = fMax(sbrBitRate, sbrBitRateLimit+16); + FDK_ASSERT( (INT)fMultNorm(cm.elInfo[e].relativeBits, (FIXP_DBL)sbrBitRate) >= sbrBitRateOut); + } + } + } + if (tooBig != -1) { + bitRate = sbrBitRate; + } + } + + FDK_ASSERT(bitRate > 0); + + return bitRate; +} + /* * \brief Consistency check of given USER_PARAM struct and * copy back configuration from public struct into internal @@ -482,6 +614,19 @@ AACENC_ERROR FDKaacEnc_AdjustEncSettings(HANDLE_AACENCODER hAacEncoder, break; } + /* We need the frame length to call aacEncoder_LimitBitrate() */ + hAacConfig->bitRate = aacEncoder_LimitBitrate( + NULL, + hAacConfig->sampleRate, + hAacConfig->framelength, + hAacConfig->nChannels, + hAacConfig->channelMode, + config->userBitrate, + hAacConfig->nSubFrames, + isSbrActive(hAacConfig), + hAacConfig->audioObjectType + ); + switch ( hAacConfig->audioObjectType ) { case AOT_ER_AAC_LD: case AOT_ER_AAC_ELD: @@ -605,7 +750,6 @@ static AACENC_ERROR aacEncInit(HANDLE_AACENCODER hAacEncoder, INT frameLength = hAacConfig->framelength; - if ( (InitFlags & AACENC_INIT_CONFIG) ) { CHANNEL_MODE prevChMode = hAacConfig->channelMode; @@ -645,9 +789,7 @@ static AACENC_ERROR aacEncInit(HANDLE_AACENCODER hAacEncoder, INT sbrError; SBR_ELEMENT_INFO sbrElInfo[(6)]; CHANNEL_MAPPING channelMapping; - int el; - INT codebits = hAacConfig->bitRate; - INT bitrateSc = CountLeadingBits(codebits); + AUDIO_OBJECT_TYPE aot = hAacConfig->audioObjectType; if ( FDKaacEnc_InitChannelMapping(hAacConfig->channelMode, @@ -662,19 +804,7 @@ static AACENC_ERROR aacEncInit(HANDLE_AACENCODER hAacEncoder, return AACENC_INIT_ERROR; } - /* Copy Element info */ - for (el=0; elbitRate<>(bitrateSc)); - sbrElInfo[el].instanceTag = channelMapping.elInfo[el].instanceTag; - sbrElInfo[el].nChannelsInEl = channelMapping.elInfo[el].nChannelsInEl; - - sbrElInfo[el].bitRate = fMult(channelMapping.elInfo[el].relativeBits, (FIXP_DBL)hAacConfig->bitRate); - codebits -= sbrElInfo[el].bitRate; - } - sbrElInfo[0].bitRate += codebits; + aacEncDistributeSbrBits(&channelMapping, sbrElInfo, hAacConfig->bitRate); UINT initFlag = 0; initFlag += (InitFlags & AACENC_INIT_STATES) ? 1 : 0; diff --git a/libAACenc/src/psy_data.h b/libAACenc/src/psy_data.h index af3cde8..38faac1 100644 --- a/libAACenc/src/psy_data.h +++ b/libAACenc/src/psy_data.h @@ -60,7 +60,7 @@ typedef shouldBeUnion{ typedef struct{ INT_PCM* psyInputBuffer; - FIXP_DBL RESTRICT overlapAddBuffer[1024]; + FIXP_DBL overlapAddBuffer[1024]; BLOCK_SWITCHING_CONTROL blockSwitchingControl; /* block switching */ FIXP_DBL sfbThresholdnm1[MAX_SFB]; /* FDKaacEnc_PreEchoControl */ diff --git a/libAACenc/src/qc_main.cpp b/libAACenc/src/qc_main.cpp index df9c4c4..3414310 100644 --- a/libAACenc/src/qc_main.cpp +++ b/libAACenc/src/qc_main.cpp @@ -1314,23 +1314,30 @@ AAC_ENCODER_ERROR FDKaacEnc_FinalizeBitConsumption(CHANNEL_MAPPING *cm, /* Now we can get the exact transport bit amount, and hopefully it is equal to the estimated value */ exactTpBits = transportEnc_GetStaticBits(hTpEnc, qcOut->totalBits); - while (exactTpBits != qcKernel->globHdrBits && (max_iter-- > 0)) - { - INT diffBits = qcKernel->globHdrBits-exactTpBits; - if (diffBits >= 0) { - /* move bits from header to payload */ - qcOut->totFillBits += diffBits; - qcOut->totalBits += diffBits; - qcOut->grantedDynBits += diffBits; + if (exactTpBits != qcKernel->globHdrBits) { + INT diffFillBits = 0; + + /* Number of bits which can be moved to bitreservoir. */ + INT bitsToBitres = qcKernel->globHdrBits - exactTpBits; + + if (bitsToBitres>0) { + /* if bitreservoir can not take all bits, move ramaining bits to fillbits */ + diffFillBits = FDKmax(0, bitsToBitres - (qcKernel->bitResTotMax-qcKernel->bitResTot)); } - else { - /* get missing bits from bitreservoir */ - qcKernel->bitResTot += diffBits; + else if (bitsToBitres<0) { + /* if bits mus be taken from bitreservoir, reduce fillbits first. */ + diffFillBits = (FDKmax(FDKmax(bitsToBitres, -qcKernel->bitResTot), -qcOut->totFillBits)); } - qcKernel->globHdrBits = exactTpBits; - exactTpBits = transportEnc_GetStaticBits(hTpEnc, qcOut->totalBits); + + diffFillBits = (diffFillBits+7)&~7; /* assure previous alignment */ + + qcOut->totFillBits += diffFillBits; + qcOut->totalBits += diffFillBits; + qcOut->grantedDynBits += diffFillBits; + + /* new header bits */ + qcKernel->globHdrBits = transportEnc_GetStaticBits(hTpEnc, qcOut->totalBits); } - FDK_ASSERT(exactTpBits == qcKernel->globHdrBits); } /* Save total fill bits and distribut to alignment and fill bits */ diff --git a/libFDK/include/FDK_hybrid.h b/libFDK/include/FDK_hybrid.h new file mode 100644 index 0000000..c5d31ae --- /dev/null +++ b/libFDK/include/FDK_hybrid.h @@ -0,0 +1,211 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2011) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Markus Lohwasser + Description: FDK Tools Hybrid Filterbank + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#ifndef __FDK_HYBRID_H +#define __FDK_HYBRID_H + + + +#include "common_fix.h" + +/*--------------- enums -------------------------------*/ + +/** + * Hybrid Filterband modes. + */ +typedef enum { + THREE_TO_TEN, + THREE_TO_TWELVE, + THREE_TO_SIXTEEN + +} FDK_HYBRID_MODE; + + +/*--------------- structure definitions ---------------*/ +typedef struct FDK_HYBRID_SETUP *HANDLE_FDK_HYBRID_SETUP; + +typedef struct +{ + FIXP_DBL *bufferLFReal[3]; /*!< LF real filter states. */ + FIXP_DBL *bufferLFImag[3]; /*!< LF imag filter states. */ + FIXP_DBL *bufferHFReal[13]; /*!< HF real delay lines. */ + FIXP_DBL *bufferHFImag[13]; /*!< HF imag delay lines. */ + + INT bufferLFpos; /*!< Position to write incoming data into ringbuffer. */ + INT bufferHFpos; /*!< Delay line positioning. */ + INT nrBands; /*!< Number of QMF bands. */ + INT cplxBands; /*!< Number of complex QMF bands.*/ + UCHAR hfMode; /*!< Flag signalizes treatment of HF bands. */ + + FIXP_DBL *pLFmemory; /*!< Pointer to LF states buffer. */ + FIXP_DBL *pHFmemory; /*!< Pointer to HF states buffer. */ + + UINT LFmemorySize; /*!< Size of LF states buffer. */ + UINT HFmemorySize; /*!< Size of HF states buffer. */ + + HANDLE_FDK_HYBRID_SETUP pSetup; /*!< Pointer to filter setup. */ + +} FDK_ANA_HYB_FILTER; + + +typedef struct +{ + INT nrBands; /*!< Number of QMF bands. */ + INT cplxBands; /*!< Number of complex QMF bands.*/ + + HANDLE_FDK_HYBRID_SETUP pSetup; /*!< Pointer to filter setup. */ + +} FDK_SYN_HYB_FILTER; + +typedef FDK_ANA_HYB_FILTER *HANDLE_FDK_ANA_HYB_FILTER; +typedef FDK_SYN_HYB_FILTER *HANDLE_FDK_SYN_HYB_FILTER; + + +/** + * \brief Create one instance of Hybrid Analyis Filterbank. + * + * \param hAnalysisHybFilter Pointer to an outlying allocated Hybrid Analysis Filterbank structure. + * \param pLFmemory Pointer to outlying buffer used LF filtering. + * \param LFmemorySize Size of pLFmemory in bytes. + * \param pHFmemory Pointer to outlying buffer used HF delay line. + * \param HFmemorySize Size of pLFmemory in bytes. + * + * \return 0 on success. + */ +INT FDKhybridAnalysisOpen( + HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter, + FIXP_DBL *const pLFmemory, + const UINT LFmemorySize, + FIXP_DBL *const pHFmemory, + const UINT HFmemorySize + ); + + +/** + * \brief Initialize and configure Hybrdid Analysis Filterbank instance. + * + * \param hAnalysisHybFilter A Hybrid Analysis Filterbank handle. + * \param mode Select hybrid filter configuration. + * \param qmfBands Number of qmf bands to be processed. + * \param cplxBands Number of complex qmf bands to be processed. + * \param initStatesFlag Indicates whether the states buffer has to be cleared. + * + * \return 0 on success. + */ +INT FDKhybridAnalysisInit( + HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter, + const FDK_HYBRID_MODE mode, + const INT qmfBands, + const INT cplxBands, + const INT initStatesFlag + ); + + +/** + * \brief Adjust Hybrdid Analysis Filterbank states. + * + * \param hAnalysisHybFilter A Hybrid Analysis Filterbank handle. + * \param scalingValue Scaling value to be applied on filter states. + * + * \return 0 on success. + */ +INT FDKhybridAnalysisScaleStates( + HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter, + const INT scalingValue + ); + + +/** + * \brief Apply Hybrid Analysis Filterbank on Qmf input data. + * + * \param hAnalysisHybFilter A Hybrid Analysis Filterbank handle. + * \param pQmfReal Qmf input data. + * \param pQmfImag Qmf input data. + * \param pHybridReal Hybrid output data. + * \param pHybridImag Hybrid output data. + * + * \return 0 on success. + */ +INT FDKhybridAnalysisApply( + HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter, + const FIXP_DBL *const pQmfReal, + const FIXP_DBL *const pQmfImag, + FIXP_DBL *const pHybridReal, + FIXP_DBL *const pHybridImag + ); + + +/** + * \brief Close a Hybrid Analysis Filterbank instance. + * + * \param hAnalysisHybFilter Pointer to a Hybrid Analysis Filterbank instance. + * + * \return 0 on success. + */ +INT FDKhybridAnalysisClose( + HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter + ); + +/** + * \brief Initialize and configure Hybrdid Synthesis Filterbank instance. + * + * \param hSynthesisHybFilter A Hybrid Synthesis Filterbank handle. + * \param mode Select hybrid filter configuration. + * \param qmfBands Number of qmf bands to be processed. + * \param cplxBands Number of complex qmf bands to be processed. + * + * \return 0 on success. + */ +INT FDKhybridSynthesisInit( + HANDLE_FDK_SYN_HYB_FILTER hSynthesisHybFilter, + const FDK_HYBRID_MODE mode, + const INT qmfBands, + const INT cplxBands + ); + +/** + * \brief Apply Hybrid Analysis Filterbank on Hybrid data. + * + * \param hSynthesisHybFilter A Hybrid Analysis Filterbandk handle. + * \param pHybridReal Hybrid input data. + * \param pHybridImag Hybrid input data. + * \param pQmfReal Qmf output data. + * \param pQmfImag Qmf output data. + * + * \return 0 on success. + */ +INT FDKhybridSynthesisApply( + HANDLE_FDK_SYN_HYB_FILTER hSynthesisHybFilter, + const FIXP_DBL *const pHybridReal, + const FIXP_DBL *const pHybridImag, + FIXP_DBL *const pQmfReal, + FIXP_DBL *const pQmfImag + ); + + +#endif /* __FDK_HYBRID_H */ diff --git a/libFDK/include/arm/clz_arm.h b/libFDK/include/arm/clz_arm.h index d3c3e04..e81d0ae 100644 --- a/libFDK/include/arm/clz_arm.h +++ b/libFDK/include/arm/clz_arm.h @@ -43,12 +43,12 @@ inline INT fixnorm_D(LONG value) { INT result; - if (value < 0) { - value = ~value; - } if (value == 0) { return 0; } + if (value < 0) { + value = ~value; + } result = fixnormz_D(value); return result - 1; } diff --git a/libFDK/include/fixpoint_math.h b/libFDK/include/fixpoint_math.h index 0d0a059..2552be6 100644 --- a/libFDK/include/fixpoint_math.h +++ b/libFDK/include/fixpoint_math.h @@ -206,6 +206,18 @@ FIXP_DBL fMultNorm( INT *result_e ); +inline FIXP_DBL fMultNorm(FIXP_DBL f1, FIXP_DBL f2) +{ + FIXP_DBL m; + INT e; + + m = fMultNorm(f1, f2, &e); + + m = scaleValueSaturate(m, e); + + return m; +} + /** * \brief Divide 2 FIXP_DBL values with normalization of input values. * \param num numerator diff --git a/libFDK/include/qmf.h b/libFDK/include/qmf.h index 89c1061..85b5fb5 100644 --- a/libFDK/include/qmf.h +++ b/libFDK/include/qmf.h @@ -25,7 +25,7 @@ *******************************************************************************/ /*! \file qmf.h - \brief Complex qmf analysis/synthesis $Revision: 36871 $ + \brief Complex qmf analysis/synthesis $Revision: 37444 $ \author Markus Werner */ diff --git a/libFDK/src/Android.mk b/libFDK/src/Android.mk index 64553d8..44309ed 100644 --- a/libFDK/src/Android.mk +++ b/libFDK/src/Android.mk @@ -7,6 +7,7 @@ LOCAL_SRC_FILES := \ FDK_bitbuffer.cpp \ FDK_core.cpp \ FDK_crc.cpp \ + FDK_hybrid.cpp \ FDK_tools_rom.cpp \ FDK_trigFcts.cpp \ fft.cpp \ diff --git a/libFDK/src/FDK_hybrid.cpp b/libFDK/src/FDK_hybrid.cpp new file mode 100644 index 0000000..d66e534 --- /dev/null +++ b/libFDK/src/FDK_hybrid.cpp @@ -0,0 +1,766 @@ +/*************************** Fraunhofer IIS FDK Tools ********************** + + (C) Copyright Fraunhofer IIS (2011) + All Rights Reserved + + Please be advised that this software and/or program delivery is + Confidential Information of Fraunhofer and subject to and covered by the + + Fraunhofer IIS Software Evaluation Agreement + between Google Inc. and Fraunhofer + effective and in full force since March 1, 2012. + + You may use this software and/or program only under the terms and + conditions described in the above mentioned Fraunhofer IIS Software + Evaluation Agreement. Any other and/or further use requires a separate agreement. + + + $Id$ + Author(s): Markus Lohwasser + Description: FDK Tools Hybrid Filterbank + + This software and/or program is protected by copyright law and international + treaties. Any reproduction or distribution of this software and/or program, + or any portion of it, may result in severe civil and criminal penalties, and + will be prosecuted to the maximum extent possible under law. + +******************************************************************************/ + +#include "FDK_hybrid.h" + + +#include "fft.h" + +/*--------------- defines -----------------------------*/ +#define FFT_IDX_R(a) (2*a) +#define FFT_IDX_I(a) (2*a+1) + +#define HYB_COEF8_0 ( 0.00746082949812f ) +#define HYB_COEF8_1 ( 0.02270420949825f ) +#define HYB_COEF8_2 ( 0.04546865930473f ) +#define HYB_COEF8_3 ( 0.07266113929591f ) +#define HYB_COEF8_4 ( 0.09885108575264f ) +#define HYB_COEF8_5 ( 0.11793710567217f ) +#define HYB_COEF8_6 ( 0.12500000000000f ) +#define HYB_COEF8_7 ( HYB_COEF8_5 ) +#define HYB_COEF8_8 ( HYB_COEF8_4 ) +#define HYB_COEF8_9 ( HYB_COEF8_3 ) +#define HYB_COEF8_10 ( HYB_COEF8_2 ) +#define HYB_COEF8_11 ( HYB_COEF8_1 ) +#define HYB_COEF8_12 ( HYB_COEF8_0 ) + + +/*--------------- structure definitions ---------------*/ + +#if defined(ARCH_PREFER_MULT_32x16) + #define FIXP_HTB FIXP_SGL /* SGL data type. */ + #define FIXP_HTP FIXP_SPK /* Packed SGL data type. */ + #define HTC(a) (FX_DBL2FXCONST_SGL(a)) /* Cast to SGL */ + #define FL2FXCONST_HTB FL2FXCONST_SGL +#else + #define FIXP_HTB FIXP_DBL /* SGL data type. */ + #define FIXP_HTP FIXP_DPK /* Packed DBL data type. */ + #define HTC(a) ((FIXP_DBL)(LONG)(a)) /* Cast to DBL */ + #define FL2FXCONST_HTB FL2FXCONST_DBL +#endif + +#define HTCP(real,imag) { { HTC(real), HTC(imag) } } /* How to arrange the packed values. */ + + +struct FDK_HYBRID_SETUP +{ + UCHAR nrQmfBands; /*!< Number of QMF bands to be converted to hybrid. */ + UCHAR nHybBands[3]; /*!< Number of Hybrid bands generated by nrQmfBands. */ + SCHAR kHybrid[3]; /*!< Filter configuration of each QMF band. */ + UCHAR protoLen; /*!< Prototype filter length. */ + UCHAR filterDelay; /*!< Delay caused by hybrid filter. */ + const INT *pReadIdxTable; /*!< Helper table to access input data ringbuffer. */ + +}; + +/*--------------- constants ---------------------------*/ +static const INT ringbuffIdxTab[2*13] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; + +static const FDK_HYBRID_SETUP setup_3_16 = { 3, { 8, 4, 4}, { 8, 4, 4}, 13, (13-1)/2, ringbuffIdxTab}; +static const FDK_HYBRID_SETUP setup_3_12 = { 3, { 8, 2, 2}, { 8, 2, 2}, 13, (13-1)/2, ringbuffIdxTab}; +static const FDK_HYBRID_SETUP setup_3_10 = { 3, { 6, 2, 2}, { -8, -2, 2}, 13, (13-1)/2, ringbuffIdxTab}; + + +static const FIXP_HTP HybFilterCoef8[] = { + HTCP(0x10000000, 0x00000000), HTCP(0x0df26407, 0xfa391882), HTCP(0xff532109, 0x00acdef7), HTCP(0x08f26d36, 0xf70d92ca), + HTCP(0xfee34b5f, 0x02af570f), HTCP(0x038f276e, 0xf7684793), HTCP(0x00000000, 0x05d1eac2), HTCP(0x00000000, 0x05d1eac2), + HTCP(0x038f276e, 0x0897b86d), HTCP(0xfee34b5f, 0xfd50a8f1), HTCP(0x08f26d36, 0x08f26d36), HTCP(0xff532109, 0xff532109), + HTCP(0x0df26407, 0x05c6e77e) +}; + +static const FIXP_HTB HybFilterCoef2[13] = { + FL2FXCONST_HTB( 0.00000000000000f), FL2FXCONST_HTB( 0.01899487526049f), FL2FXCONST_HTB( 0.00000000000000f), FL2FXCONST_HTB(-0.07293139167538f), FL2FXCONST_HTB( 0.00000000000000f), FL2FXCONST_HTB( 0.30596630545168f), + FL2FXCONST_HTB( 0.50000000000000f), FL2FXCONST_HTB( 0.30596630545168f), FL2FXCONST_HTB( 0.00000000000000f), FL2FXCONST_HTB(-0.07293139167538f), FL2FXCONST_HTB( 0.00000000000000f), FL2FXCONST_HTB( 0.01899487526049f), + FL2FXCONST_HTB( 0.00000000000000f) +}; + +static const FIXP_HTB HybFilterCoef4[13] = { + FL2FXCONST_HTB(-0.00305151927305f), FL2FXCONST_HTB(-0.00794862316203f), FL2FXCONST_HTB( 0.0f), FL2FXCONST_HTB( 0.04318924038756f), FL2FXCONST_HTB( 0.12542448210445f), FL2FXCONST_HTB( 0.21227807049160f), + FL2FXCONST_HTB( 0.25f), FL2FXCONST_HTB( 0.21227807049160f), FL2FXCONST_HTB( 0.12542448210445f), FL2FXCONST_HTB( 0.04318924038756f), FL2FXCONST_HTB( 0.0f), FL2FXCONST_HTB(-0.00794862316203f), + FL2FXCONST_HTB(-0.00305151927305f) +}; + +/*--------------- function declarations ---------------*/ +static INT kChannelFiltering( + const FIXP_DBL *const pQmfReal, + const FIXP_DBL *const pQmfImag, + const INT *const pReadIdx, + FIXP_DBL *const mHybridReal, + FIXP_DBL *const mHybridImag, + const SCHAR hybridConfig + ); + + +/*--------------- function definitions ----------------*/ + +INT FDKhybridAnalysisOpen( + HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter, + FIXP_DBL *const pLFmemory, + const UINT LFmemorySize, + FIXP_DBL *const pHFmemory, + const UINT HFmemorySize + ) +{ + INT err = 0; + + /* Save pointer to extern memory. */ + hAnalysisHybFilter->pLFmemory = pLFmemory; + hAnalysisHybFilter->LFmemorySize = LFmemorySize; + + hAnalysisHybFilter->pHFmemory = pHFmemory; + hAnalysisHybFilter->HFmemorySize = HFmemorySize; + + return err; +} + +INT FDKhybridAnalysisInit( + HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter, + const FDK_HYBRID_MODE mode, + const INT qmfBands, + const INT cplxBands, + const INT initStatesFlag + ) +{ + int k; + INT err = 0; + FIXP_DBL *pMem = NULL; + HANDLE_FDK_HYBRID_SETUP setup = NULL; + + switch (mode) { + case THREE_TO_TEN: setup = (HANDLE_FDK_HYBRID_SETUP)&setup_3_10; break; + case THREE_TO_TWELVE: setup = (HANDLE_FDK_HYBRID_SETUP)&setup_3_12; break; + case THREE_TO_SIXTEEN: setup = (HANDLE_FDK_HYBRID_SETUP)&setup_3_16; break; + default: err = -1; goto bail; + } + + /* Initialize handle. */ + hAnalysisHybFilter->pSetup = setup; + hAnalysisHybFilter->bufferLFpos = setup->protoLen-1; + hAnalysisHybFilter->bufferHFpos = 0; + hAnalysisHybFilter->nrBands = qmfBands; + hAnalysisHybFilter->cplxBands = cplxBands; + hAnalysisHybFilter->hfMode = 0; + + /* Check available memory. */ + if ( ((2*setup->nrQmfBands*setup->protoLen*sizeof(FIXP_DBL)) > hAnalysisHybFilter->LFmemorySize) + || ((setup->filterDelay*((qmfBands-setup->nrQmfBands)+(cplxBands-setup->nrQmfBands))*sizeof(FIXP_DBL)) > hAnalysisHybFilter->HFmemorySize) ) + { + err = -2; + goto bail; + } + + /* Distribut LF memory. */ + pMem = hAnalysisHybFilter->pLFmemory; + for (k=0; knrQmfBands; k++) { + hAnalysisHybFilter->bufferLFReal[k] = pMem; pMem += setup->protoLen; + hAnalysisHybFilter->bufferLFImag[k] = pMem; pMem += setup->protoLen; + } + + /* Distribut HF memory. */ + pMem = hAnalysisHybFilter->pHFmemory; + for (k=0; kfilterDelay; k++) { + hAnalysisHybFilter->bufferHFReal[k] = pMem; pMem += (qmfBands-setup->nrQmfBands); + hAnalysisHybFilter->bufferHFImag[k] = pMem; pMem += (cplxBands-setup->nrQmfBands); + } + + if (initStatesFlag) { + /* Clear LF buffer */ + for (k=0; knrQmfBands; k++) { + FDKmemclear(hAnalysisHybFilter->bufferLFReal[k], setup->protoLen*sizeof(FIXP_DBL)); + FDKmemclear(hAnalysisHybFilter->bufferLFImag[k], setup->protoLen*sizeof(FIXP_DBL)); + } + + if (qmfBands > setup->nrQmfBands) { + /* Clear HF buffer */ + for (k=0; kfilterDelay; k++) { + FDKmemclear(hAnalysisHybFilter->bufferHFReal[k], (qmfBands-setup->nrQmfBands)*sizeof(FIXP_DBL)); + FDKmemclear(hAnalysisHybFilter->bufferHFImag[k], (cplxBands-setup->nrQmfBands)*sizeof(FIXP_DBL)); + } + } + } + +bail: + return err; +} + +INT FDKhybridAnalysisScaleStates( + HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter, + const INT scalingValue + ) +{ + INT err = 0; + + if (hAnalysisHybFilter==NULL) { + err = 1; /* invalid handle */ + } + else { + int k; + HANDLE_FDK_HYBRID_SETUP setup = hAnalysisHybFilter->pSetup; + + /* Scale LF buffer */ + for (k=0; knrQmfBands; k++) { + scaleValues(hAnalysisHybFilter->bufferLFReal[k], setup->protoLen, scalingValue); + scaleValues(hAnalysisHybFilter->bufferLFImag[k], setup->protoLen, scalingValue); + } + if (hAnalysisHybFilter->nrBands > setup->nrQmfBands) { + /* Scale HF buffer */ + for (k=0; kfilterDelay; k++) { + scaleValues(hAnalysisHybFilter->bufferHFReal[k], (hAnalysisHybFilter->nrBands-setup->nrQmfBands), scalingValue); + scaleValues(hAnalysisHybFilter->bufferHFImag[k], (hAnalysisHybFilter->cplxBands-setup->nrQmfBands), scalingValue); + } + } + } + return err; +} + +INT FDKhybridAnalysisApply( + HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter, + const FIXP_DBL *const pQmfReal, + const FIXP_DBL *const pQmfImag, + FIXP_DBL *const pHybridReal, + FIXP_DBL *const pHybridImag) +{ + int k, hybOffset = 0; + INT err = 0; + const int nrQmfBandsLF = hAnalysisHybFilter->pSetup->nrQmfBands; /* number of QMF bands to be converted to hybrid */ + + const int writIndex = hAnalysisHybFilter->bufferLFpos; + int readIndex = hAnalysisHybFilter->bufferLFpos; + + if (++readIndex>=hAnalysisHybFilter->pSetup->protoLen) readIndex = 0; + const INT* pBufferLFreadIdx = &hAnalysisHybFilter->pSetup->pReadIdxTable[readIndex]; + + /* + * LF buffer. + */ + for (k=0; kbufferLFReal[k][writIndex] = pQmfReal[k]; + hAnalysisHybFilter->bufferLFImag[k][writIndex] = pQmfImag[k]; + + /* Perform hybrid filtering. */ + kChannelFiltering( + hAnalysisHybFilter->bufferLFReal[k], + hAnalysisHybFilter->bufferLFImag[k], + pBufferLFreadIdx, + pHybridReal+hybOffset, + pHybridImag+hybOffset, + hAnalysisHybFilter->pSetup->kHybrid[k]); + + hybOffset += hAnalysisHybFilter->pSetup->nHybBands[k]; + } + + hAnalysisHybFilter->bufferLFpos = readIndex; /* Index where to write next input sample. */ + + if (hAnalysisHybFilter->nrBands > nrQmfBandsLF) { + /* + * HF buffer. + */ + if (hAnalysisHybFilter->hfMode!=0) { + /* HF delay compensation was applied outside. */ + FDKmemcpy(pHybridReal+hybOffset, &pQmfReal[nrQmfBandsLF], (hAnalysisHybFilter->nrBands-nrQmfBandsLF)*sizeof(FIXP_DBL)); + FDKmemcpy(pHybridImag+hybOffset, &pQmfImag[nrQmfBandsLF], (hAnalysisHybFilter->cplxBands-nrQmfBandsLF)*sizeof(FIXP_DBL)); + } + else { + /* HF delay compensation, filterlength/2. */ + FDKmemcpy(pHybridReal+hybOffset, hAnalysisHybFilter->bufferHFReal[hAnalysisHybFilter->bufferHFpos], (hAnalysisHybFilter->nrBands-nrQmfBandsLF)*sizeof(FIXP_DBL)); + FDKmemcpy(pHybridImag+hybOffset, hAnalysisHybFilter->bufferHFImag[hAnalysisHybFilter->bufferHFpos], (hAnalysisHybFilter->cplxBands-nrQmfBandsLF)*sizeof(FIXP_DBL)); + + FDKmemcpy(hAnalysisHybFilter->bufferHFReal[hAnalysisHybFilter->bufferHFpos], &pQmfReal[nrQmfBandsLF], (hAnalysisHybFilter->nrBands-nrQmfBandsLF)*sizeof(FIXP_DBL)); + FDKmemcpy(hAnalysisHybFilter->bufferHFImag[hAnalysisHybFilter->bufferHFpos], &pQmfImag[nrQmfBandsLF], (hAnalysisHybFilter->cplxBands-nrQmfBandsLF)*sizeof(FIXP_DBL)); + + if (++hAnalysisHybFilter->bufferHFpos>=hAnalysisHybFilter->pSetup->filterDelay) hAnalysisHybFilter->bufferHFpos = 0; + } + } /* process HF part*/ + + return err; +} + +INT FDKhybridAnalysisClose( + HANDLE_FDK_ANA_HYB_FILTER hAnalysisHybFilter + ) +{ + INT err = 0; + + if (hAnalysisHybFilter != NULL) { + hAnalysisHybFilter->pLFmemory = NULL; + hAnalysisHybFilter->pHFmemory = NULL; + hAnalysisHybFilter->LFmemorySize = 0; + hAnalysisHybFilter->HFmemorySize = 0; + } + + return err; +} + +INT FDKhybridSynthesisInit( + HANDLE_FDK_SYN_HYB_FILTER hSynthesisHybFilter, + const FDK_HYBRID_MODE mode, + const INT qmfBands, + const INT cplxBands + ) +{ + INT err = 0; + HANDLE_FDK_HYBRID_SETUP setup = NULL; + + switch (mode) { + case THREE_TO_TEN: setup = (HANDLE_FDK_HYBRID_SETUP)&setup_3_10; break; + case THREE_TO_TWELVE: setup = (HANDLE_FDK_HYBRID_SETUP)&setup_3_12; break; + case THREE_TO_SIXTEEN: setup = (HANDLE_FDK_HYBRID_SETUP)&setup_3_16; break; + default: err = -1; goto bail; + } + + hSynthesisHybFilter->pSetup = setup; + hSynthesisHybFilter->nrBands = qmfBands; + hSynthesisHybFilter->cplxBands = cplxBands; + +bail: + return err; +} + + +INT FDKhybridSynthesisApply( + HANDLE_FDK_SYN_HYB_FILTER hSynthesisHybFilter, + const FIXP_DBL *const pHybridReal, + const FIXP_DBL *const pHybridImag, + FIXP_DBL *const pQmfReal, + FIXP_DBL *const pQmfImag + ) +{ + int k, n, hybOffset=0; + INT err = 0; + const INT nrQmfBandsLF = hSynthesisHybFilter->pSetup->nrQmfBands; + + /* + * LF buffer. + */ + for (k=0; kpSetup->nHybBands[k]; + + FIXP_DBL accu1 = FL2FXCONST_DBL(0.f); + FIXP_DBL accu2 = FL2FXCONST_DBL(0.f); + + /* Perform hybrid filtering. */ + for (n=0; nnrBands > nrQmfBandsLF) { + /* + * HF buffer. + */ + FDKmemcpy(&pQmfReal[nrQmfBandsLF], &pHybridReal[hybOffset], (hSynthesisHybFilter->nrBands-nrQmfBandsLF)*sizeof(FIXP_DBL)); + FDKmemcpy(&pQmfImag[nrQmfBandsLF], &pHybridImag[hybOffset], (hSynthesisHybFilter->cplxBands-nrQmfBandsLF)*sizeof(FIXP_DBL)); + } + + return err; +} + +/*****************************************************************************/ +/* **** FILTERBANK **** */ + +/* + 2 channel filter + Filter Coefs: + 0.0, + 0.01899487526049, + 0.0, + -0.07293139167538, + 0.0, + 0.30596630545168, + 0.5, + 0.30596630545168, + 0.0, + -0.07293139167538, + 0.0, + 0.01899487526049, + 0.0 + + + Filter design: + h[q,n] = g[n] * cos(2pi/2 * q * (n-6) ); n = 0..12, q = 0,1; + + -> h[0,n] = g[n] * 1; + -> h[1,n] = g[n] * pow(-1,n); +*/ +static void dualChannelFiltering( + const FIXP_DBL *const pQmfReal, + const FIXP_DBL *const pQmfImag, + const INT *const pReadIdx, + FIXP_DBL *const mHybridReal, + FIXP_DBL *const mHybridImag, + const INT invert + ) +{ + const FIXP_HTB *p = HybFilterCoef2; + + FIXP_DBL r1, r6; + FIXP_DBL i1, i6; + + /* symmetric filter coefficients */ + r1 = fMultDiv2(p[1], pQmfReal[pReadIdx[1]]) + fMultDiv2(p[1], pQmfReal[pReadIdx[11]]) ; + i1 = fMultDiv2(p[1], pQmfImag[pReadIdx[1]]) + fMultDiv2(p[1], pQmfImag[pReadIdx[11]]) ; + r1 += fMultDiv2(p[3], pQmfReal[pReadIdx[3]]) + fMultDiv2(p[3], pQmfReal[pReadIdx[ 9]]) ; + i1 += fMultDiv2(p[3], pQmfImag[pReadIdx[3]]) + fMultDiv2(p[3], pQmfImag[pReadIdx[ 9]]) ; + r1 += fMultDiv2(p[5], pQmfReal[pReadIdx[5]]) + fMultDiv2(p[5], pQmfReal[pReadIdx[ 7]]) ; + i1 += fMultDiv2(p[5], pQmfImag[pReadIdx[5]]) + fMultDiv2(p[5], pQmfImag[pReadIdx[ 7]]) ; + r6 = fMultDiv2(p[6], pQmfReal[pReadIdx[6]]) ; + i6 = fMultDiv2(p[6], pQmfImag[pReadIdx[6]]) ; + + if (invert) { + mHybridReal[1] = (r1 + r6) << 1; + mHybridImag[1] = (i1 + i6) << 1; + + mHybridReal[0] = (r6 - r1) << 1; + mHybridImag[0] = (i6 - i1) << 1; + } + else { + mHybridReal[0] = (r1 + r6) << 1; + mHybridImag[0] = (i1 + i6) << 1; + + mHybridReal[1] = (r6 - r1) << 1; + mHybridImag[1] = (i6 - i1) << 1; + } +} + +static void fourChannelFiltering( + const FIXP_DBL *const pQmfReal, + const FIXP_DBL *const pQmfImag, + const INT *const pReadIdx, + FIXP_DBL *const mHybridReal, + FIXP_DBL *const mHybridImag, + const INT invert + ) +{ + const FIXP_HTB *p = HybFilterCoef4; + + FIXP_DBL fft[8]; + + static const FIXP_DBL cr[13] = { + FL2FXCONST_DBL( 0.f), FL2FXCONST_DBL(-0.70710678118655f), FL2FXCONST_DBL( -1.f), + FL2FXCONST_DBL(-0.70710678118655f), FL2FXCONST_DBL( 0.f), FL2FXCONST_DBL( 0.70710678118655f), + FL2FXCONST_DBL( 1.f), + FL2FXCONST_DBL( 0.70710678118655f), FL2FXCONST_DBL( 0.f), FL2FXCONST_DBL(-0.70710678118655f), + FL2FXCONST_DBL( -1.f), FL2FXCONST_DBL(-0.70710678118655f), FL2FXCONST_DBL( 0.f) + }; + static const FIXP_DBL ci[13] = { + FL2FXCONST_DBL( -1.f), FL2FXCONST_DBL(-0.70710678118655f), FL2FXCONST_DBL( 0.f), + FL2FXCONST_DBL( 0.70710678118655f), FL2FXCONST_DBL( 1.f), FL2FXCONST_DBL( 0.70710678118655f), + FL2FXCONST_DBL( 0.f), + FL2FXCONST_DBL(-0.70710678118655f), FL2FXCONST_DBL( -1.f), FL2FXCONST_DBL(-0.70710678118655f), + FL2FXCONST_DBL( 0.f), FL2FXCONST_DBL( 0.70710678118655f), FL2FXCONST_DBL( 1.f) + }; + + + /* FIR filter. */ + /* pre twiddeling with pre-twiddling coefficients c[n] */ + /* multiplication with filter coefficients p[n] */ + /* hint: (a + ib)*(c + id) = (a*c - b*d) + i(a*d + b*c) */ + /* write to fft coefficient n' */ + fft[FFT_IDX_R(0)] = ( fMult(p[10], ( fMultSub(fMultDiv2(cr[ 2], pQmfReal[pReadIdx[ 2]]), ci[ 2], pQmfImag[pReadIdx[ 2]]))) + + fMult(p[ 6], ( fMultSub(fMultDiv2(cr[ 6], pQmfReal[pReadIdx[ 6]]), ci[ 6], pQmfImag[pReadIdx[ 6]]))) + + fMult(p[ 2], ( fMultSub(fMultDiv2(cr[10], pQmfReal[pReadIdx[10]]), ci[10], pQmfImag[pReadIdx[10]]))) ); + fft[FFT_IDX_I(0)] = ( fMult(p[10], ( fMultAdd(fMultDiv2(ci[ 2], pQmfReal[pReadIdx[ 2]]), cr[ 2], pQmfImag[pReadIdx[ 2]]))) + + fMult(p[ 6], ( fMultAdd(fMultDiv2(ci[ 6], pQmfReal[pReadIdx[ 6]]), cr[ 6], pQmfImag[pReadIdx[ 6]]))) + + fMult(p[ 2], ( fMultAdd(fMultDiv2(ci[10], pQmfReal[pReadIdx[10]]), cr[10], pQmfImag[pReadIdx[10]]))) ); + + /* twiddle dee dum */ + fft[FFT_IDX_R(1)] = ( fMult(p[ 9], ( fMultSub(fMultDiv2(cr[ 3], pQmfReal[pReadIdx[ 3]]), ci[ 3], pQmfImag[pReadIdx[ 3]]))) + + fMult(p[ 5], ( fMultSub(fMultDiv2(cr[ 7], pQmfReal[pReadIdx[ 7]]), ci[ 7], pQmfImag[pReadIdx[ 7]]))) + + fMult(p[ 1], ( fMultSub(fMultDiv2(cr[11], pQmfReal[pReadIdx[11]]), ci[11], pQmfImag[pReadIdx[11]]))) ); + fft[FFT_IDX_I(1)] = ( fMult(p[ 9], ( fMultAdd(fMultDiv2(ci[ 3], pQmfReal[pReadIdx[ 3]]), cr[ 3], pQmfImag[pReadIdx[ 3]]))) + + fMult(p[ 5], ( fMultAdd(fMultDiv2(ci[ 7], pQmfReal[pReadIdx[ 7]]), cr[ 7], pQmfImag[pReadIdx[ 7]]))) + + fMult(p[ 1], ( fMultAdd(fMultDiv2(ci[11], pQmfReal[pReadIdx[11]]), cr[11], pQmfImag[pReadIdx[11]]))) ); + + /* twiddle dee dee */ + fft[FFT_IDX_R(2)] = ( fMult(p[12], ( fMultSub(fMultDiv2(cr[ 0], pQmfReal[pReadIdx[ 0]]), ci[ 0], pQmfImag[pReadIdx[ 0]]))) + + fMult(p[ 8], ( fMultSub(fMultDiv2(cr[ 4], pQmfReal[pReadIdx[ 4]]), ci[ 4], pQmfImag[pReadIdx[ 4]]))) + + fMult(p[ 4], ( fMultSub(fMultDiv2(cr[ 8], pQmfReal[pReadIdx[ 8]]), ci[ 8], pQmfImag[pReadIdx[ 8]]))) + + fMult(p[ 0], ( fMultSub(fMultDiv2(cr[12], pQmfReal[pReadIdx[12]]), ci[12], pQmfImag[pReadIdx[12]]))) ); + fft[FFT_IDX_I(2)] = ( fMult(p[12], ( fMultAdd(fMultDiv2(ci[ 0], pQmfReal[pReadIdx[ 0]]), cr[ 0], pQmfImag[pReadIdx[ 0]]))) + + fMult(p[ 8], ( fMultAdd(fMultDiv2(ci[ 4], pQmfReal[pReadIdx[ 4]]), cr[ 4], pQmfImag[pReadIdx[ 4]]))) + + fMult(p[ 4], ( fMultAdd(fMultDiv2(ci[ 8], pQmfReal[pReadIdx[ 8]]), cr[ 8], pQmfImag[pReadIdx[ 8]]))) + + fMult(p[ 0], ( fMultAdd(fMultDiv2(ci[12], pQmfReal[pReadIdx[12]]), cr[12], pQmfImag[pReadIdx[12]]))) ); + + fft[FFT_IDX_R(3)] = ( fMult(p[11], ( fMultSub(fMultDiv2(cr[ 1], pQmfReal[pReadIdx[ 1]]), ci[ 1], pQmfImag[pReadIdx[ 1]]))) + + fMult(p[ 7], ( fMultSub(fMultDiv2(cr[ 5], pQmfReal[pReadIdx[ 5]]), ci[ 5], pQmfImag[pReadIdx[ 5]]))) + + fMult(p[ 3], ( fMultSub(fMultDiv2(cr[ 9], pQmfReal[pReadIdx[ 9]]), ci[ 9], pQmfImag[pReadIdx[ 9]]))) ); + fft[FFT_IDX_I(3)] = ( fMult(p[11], ( fMultAdd(fMultDiv2(ci[ 1], pQmfReal[pReadIdx[ 1]]), cr[ 1], pQmfImag[pReadIdx[ 1]]))) + + fMult(p[ 7], ( fMultAdd(fMultDiv2(ci[ 5], pQmfReal[pReadIdx[ 5]]), cr[ 5], pQmfImag[pReadIdx[ 5]]))) + + fMult(p[ 3], ( fMultAdd(fMultDiv2(ci[ 9], pQmfReal[pReadIdx[ 9]]), cr[ 9], pQmfImag[pReadIdx[ 9]]))) ); + + /* fft modulation */ + /* here: fast manual fft modulation for a fft of length M=4 */ + /* fft_4{x[n]} = x[0]*exp(-i*2*pi/4*m*0) + x[1]*exp(-i*2*pi/4*m*1) + + x[2]*exp(-i*2*pi/4*m*2) + x[3]*exp(-i*2*pi/4*m*3) */ + + /* + fft bin m=0: + X[0, n] = x[0] + x[1] + x[2] + x[3] + */ + mHybridReal[0] = fft[FFT_IDX_R(0)] + fft[FFT_IDX_R(1)] + fft[FFT_IDX_R(2)] + fft[FFT_IDX_R(3)]; + mHybridImag[0] = fft[FFT_IDX_I(0)] + fft[FFT_IDX_I(1)] + fft[FFT_IDX_I(2)] + fft[FFT_IDX_I(3)]; + + /* + fft bin m=1: + X[1, n] = x[0] - i*x[1] - x[2] + i*x[3] + */ + mHybridReal[1] = fft[FFT_IDX_R(0)] + fft[FFT_IDX_I(1)] - fft[FFT_IDX_R(2)] - fft[FFT_IDX_I(3)]; + mHybridImag[1] = fft[FFT_IDX_I(0)] - fft[FFT_IDX_R(1)] - fft[FFT_IDX_I(2)] + fft[FFT_IDX_R(3)]; + + /* + fft bin m=2: + X[2, n] = x[0] - x[1] + x[2] - x[3] + */ + mHybridReal[2] = fft[FFT_IDX_R(0)] - fft[FFT_IDX_R(1)] + fft[FFT_IDX_R(2)] - fft[FFT_IDX_R(3)]; + mHybridImag[2] = fft[FFT_IDX_I(0)] - fft[FFT_IDX_I(1)] + fft[FFT_IDX_I(2)] - fft[FFT_IDX_I(3)]; + + /* + fft bin m=3: + X[3, n] = x[0] + j*x[1] - x[2] - j*x[3] + */ + mHybridReal[3] = fft[FFT_IDX_R(0)] - fft[FFT_IDX_I(1)] - fft[FFT_IDX_R(2)] + fft[FFT_IDX_I(3)]; + mHybridImag[3] = fft[FFT_IDX_I(0)] + fft[FFT_IDX_R(1)] - fft[FFT_IDX_I(2)] - fft[FFT_IDX_R(3)]; +} + + + +/* + 8 channel filter + + Implementation using a FFT of length 8 + + prototype filter coefficients: + 0.00746082949812 0.02270420949825 0.04546865930473 0.07266113929591 0.09885108575264 0.11793710567217 + 0.125 + 0.11793710567217 0.09885108575264 0.07266113929591 0.04546865930473 0.02270420949825 0.00746082949812 + + Filter design: + N = 13; Q = 8; + h[q,n] = g[n] * exp(j * 2 * pi / Q * (q + .5) * (n - 6)); n = 0..(N-1), q = 0..(Q-1); + + Time Signal: x[t]; + Filter Bank Output + y[q,t] = conv(x[t],h[q,t]) = conv(h[q,t],x[t]) = sum(x[k] * h[q, t - k] ) = sum(h[q, k] * x[t - k] ); k = 0..(N-1); + + y[q,t] = x[t - 12]*h[q, 12] + x[t - 11]*h[q, 11] + x[t - 10]*h[q, 10] + x[t - 9]*h[q, 9] + + x[t - 8]*h[q, 8] + x[t - 7]*h[q, 7] + + x[t - 6]*h[q, 6] + + x[t - 5]*h[q, 5] + x[t - 4]*h[q, 4] + + x[t - 3]*h[q, 3] + x[t - 2]*h[q, 2] + x[t - 1]*h[q, 1] + x[t - 0]*h[q, 0]; + + h'[q, n] = h[q,(N-1)-n] = g[n] * exp(j * 2 * pi / Q * (q + .5) * (6 - n)); n = 0..(N-1), q = 0..(Q-1); + + y[q,t] = x[t - 12]*h'[q, 0] + x[t - 11]*h'[q, 1] + x[t - 10]*h'[q, 2] + x[t - 9]*h'[q, 3] + + x[t - 8]*h'[q, 4] + x[t - 7]*h'[q, 5] + + x[t - 6]*h'[q, 6] + + x[t - 5]*h'[q, 7] + x[t - 4]*h'[q, 8] + + x[t - 3]*h'[q, 9] + x[t - 2]*h'[q, 10] + x[t - 1]*h'[q, 11] + x[t - 0]*h'[q, 12]; + + Try to split off FFT Modulation Term: + FFT(x[t], q) = sum(x[t+k]*exp(-j*2*pi/N *q * k)) + c m + Step 1: h'[q,n] = g[n] * ( exp(j * 2 * pi / 8 * .5 * (6 - n)) ) * ( exp (j * 2 * pi / 8 * q * (6 - n)) ); + + h'[q,n] = g[n] *c[n] * m[q,n]; (see above) + c[n] = exp( j * 2 * pi / 8 * .5 * (6 - n) ); + m[q,n] = exp( j * 2 * pi / 8 * q * (6 - n) ); + + y[q,t] = x[t - 0]*g[0]*c[0]*m[q,0] + x[t - 1]*g[1]*c[ 1]*m[q, 1] + ... + ... + x[t - 12]*g[2]*c[12]*m[q,12]; + + | + n m *exp(-j*2*pi) | n' fft +------------------------------------------------------------------------------------------------------------------------- + 0 exp( j * 2 * pi / 8 * q * 6) -> exp(-j * 2 * pi / 8 * q * 2) | 2 exp(-j * 2 * pi / 8 * q * 0) + 1 exp( j * 2 * pi / 8 * q * 5) -> exp(-j * 2 * pi / 8 * q * 3) | 3 exp(-j * 2 * pi / 8 * q * 1) + 2 exp( j * 2 * pi / 8 * q * 4) -> exp(-j * 2 * pi / 8 * q * 4) | 4 exp(-j * 2 * pi / 8 * q * 2) + 3 exp( j * 2 * pi / 8 * q * 3) -> exp(-j * 2 * pi / 8 * q * 5) | 5 exp(-j * 2 * pi / 8 * q * 3) + 4 exp( j * 2 * pi / 8 * q * 2) -> exp(-j * 2 * pi / 8 * q * 6) | 6 exp(-j * 2 * pi / 8 * q * 4) + 5 exp( j * 2 * pi / 8 * q * 1) -> exp(-j * 2 * pi / 8 * q * 7) | 7 exp(-j * 2 * pi / 8 * q * 5) + 6 exp( j * 2 * pi / 8 * q * 0) | 0 exp(-j * 2 * pi / 8 * q * 6) + 7 exp(-j * 2 * pi / 8 * q * 1) | 1 exp(-j * 2 * pi / 8 * q * 7) + 8 exp(-j * 2 * pi / 8 * q * 2) | 2 + 9 exp(-j * 2 * pi / 8 * q * 3) | 3 + 10 exp(-j * 2 * pi / 8 * q * 4) | 4 + 11 exp(-j * 2 * pi / 8 * q * 5) | 5 + 12 exp(-j * 2 * pi / 8 * q * 6) | 6 + + + now use fft modulation coefficients + m[6] = = fft[0] + m[7] = = fft[1] + m[8] = m[ 0] = fft[2] + m[9] = m[ 1] = fft[3] + m[10] = m[ 2] = fft[4] + m[11] = m[ 3] = fft[5] + m[12] = m[ 4] = fft[6] + m[ 5] = fft[7] + + y[q,t] = ( x[t- 6]*g[ 6]*c[ 6] ) * fft[q,0] + + ( x[t- 7]*g[ 7]*c[ 7] ) * fft[q,1] + + ( x[t- 0]*g[ 0]*c[ 0] + x[t- 8]*g[ 8]*c[ 8] ) * fft[q,2] + + ( x[t- 1]*g[ 1]*c[ 1] + x[t- 9]*g[ 9]*c[ 9] ) * fft[q,3] + + ( x[t- 2]*g[ 2]*c[ 2] + x[t-10]*g[10]*c[10] ) * fft[q,4] + + ( x[t- 3]*g[ 3]*c[ 3] + x[t-11]*g[11]*c[11] ) * fft[q,5] + + ( x[t- 4]*g[ 4]*c[ 4] + x[t-12]*g[12]*c[12] ) * fft[q,6] + + ( x[t- 5]*g[ 5]*c[ 5] ) * fft[q,7]; + + pre twiddle factors c[n] = exp(j * 2 * pi / 8 * .5 * (6 - n)); + n c] | n c[n] | n c[n] +--------------------------------------------------------------------------------------------------- + 0 exp( j * 6 * pi / 8) | 1 exp( j * 5 * pi / 8) | 2 exp( j * 4 * pi / 8) + 3 exp( j * 3 * pi / 8) | 4 exp( j * 2 * pi / 8) | 5 exp( j * 1 * pi / 8) + 6 exp( j * 0 * pi / 8) | 7 exp(-j * 1 * pi / 8) | 8 exp(-j * 2 * pi / 8) + 9 exp(-j * 3 * pi / 8) | 10 exp(-j * 4 * pi / 8) | 11 exp(-j * 5 * pi / 8) + 12 exp(-j * 6 * pi / 8) | | + +*/ +static void eightChannelFiltering( + const FIXP_DBL *const pQmfReal, + const FIXP_DBL *const pQmfImag, + const INT *const pReadIdx, + FIXP_DBL *const mHybridReal, + FIXP_DBL *const mHybridImag, + const INT invert + ) +{ + const FIXP_HTP *p = HybFilterCoef8; + INT k, sc; + + FIXP_DBL mfft[16+ALIGNMENT_DEFAULT]; + FIXP_DBL *pfft = (FIXP_DBL*)ALIGN_PTR(mfft); + + FIXP_DBL accu1, accu2, accu3, accu4; + + /* pre twiddeling */ + pfft[FFT_IDX_R(0)] = fMultDiv2(p[0].v.re, pQmfReal[pReadIdx[6]]); + pfft[FFT_IDX_I(0)] = fMultDiv2(p[0].v.re, pQmfImag[pReadIdx[6]]); + + cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[7]], pQmfImag[pReadIdx[7]], p[1]); + pfft[FFT_IDX_R(1)] = accu1; + pfft[FFT_IDX_I(1)] = accu2; + + cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[0]], pQmfImag[pReadIdx[0]], p[2]); + cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[8]], pQmfImag[pReadIdx[8]], p[3]); + pfft[FFT_IDX_R(2)] = accu1 + accu3; + pfft[FFT_IDX_I(2)] = accu2 + accu4; + + cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[1]], pQmfImag[pReadIdx[1]], p[4]); + cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[9]], pQmfImag[pReadIdx[9]], p[5]); + pfft[FFT_IDX_R(3)] = accu1 + accu3; + pfft[FFT_IDX_I(3)] = accu2 + accu4; + + pfft[FFT_IDX_R(4)] = fMultDiv2(pQmfImag[pReadIdx[10]], p[7].v.im) - fMultDiv2(pQmfImag[pReadIdx[ 2]], p[6].v.im); + pfft[FFT_IDX_I(4)] = fMultDiv2(pQmfReal[pReadIdx[ 2]], p[6].v.im) - fMultDiv2(pQmfReal[pReadIdx[10]], p[7].v.im); + + cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[ 3]], pQmfImag[pReadIdx[ 3]], p[8]); + cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[11]], pQmfImag[pReadIdx[11]], p[9]); + pfft[FFT_IDX_R(5)] = accu1 + accu3; + pfft[FFT_IDX_I(5)] = accu2 + accu4; + + cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[ 4]], pQmfImag[pReadIdx[ 4]], p[10]); + cplxMultDiv2(&accu3, &accu4, pQmfReal[pReadIdx[12]], pQmfImag[pReadIdx[12]], p[11]); + pfft[FFT_IDX_R(6)] = accu1 + accu3; + pfft[FFT_IDX_I(6)] = accu2 + accu4; + + cplxMultDiv2(&accu1, &accu2, pQmfReal[pReadIdx[ 5]], pQmfImag[pReadIdx[ 5]], p[12]); + pfft[FFT_IDX_R(7)] = accu1; + pfft[FFT_IDX_I(7)] = accu2; + + /* fft modulation */ + fft_8 (pfft); + sc = 1 + 2; + + if (invert) { + mHybridReal[0] = pfft[FFT_IDX_R(7)] << sc; + mHybridImag[0] = pfft[FFT_IDX_I(7)] << sc; + mHybridReal[1] = pfft[FFT_IDX_R(0)] << sc; + mHybridImag[1] = pfft[FFT_IDX_I(0)] << sc; + + mHybridReal[2] = pfft[FFT_IDX_R(6)] << sc; + mHybridImag[2] = pfft[FFT_IDX_I(6)] << sc; + mHybridReal[3] = pfft[FFT_IDX_R(1)] << sc; + mHybridImag[3] = pfft[FFT_IDX_I(1)] << sc; + + mHybridReal[4] = pfft[FFT_IDX_R(2)] << sc; + mHybridReal[4] += pfft[FFT_IDX_R(5)] << sc; + mHybridImag[4] = pfft[FFT_IDX_I(2)] << sc; + mHybridImag[4] += pfft[FFT_IDX_I(5)] << sc; + + mHybridReal[5] = pfft[FFT_IDX_R(3)] << sc; + mHybridReal[5] += pfft[FFT_IDX_R(4)] << sc; + mHybridImag[5] = pfft[FFT_IDX_I(3)] << sc; + mHybridImag[5] += pfft[FFT_IDX_I(4)] << sc; + } + else { + for(k=0; k<8;k++ ) { + mHybridReal[k] = pfft[FFT_IDX_R(k)] << sc; + mHybridImag[k] = pfft[FFT_IDX_I(k)] << sc; + } + } +} + +static INT kChannelFiltering( + const FIXP_DBL *const pQmfReal, + const FIXP_DBL *const pQmfImag, + const INT *const pReadIdx, + FIXP_DBL *const mHybridReal, + FIXP_DBL *const mHybridImag, + const SCHAR hybridConfig + ) +{ + INT err = 0; + + switch (hybridConfig) { + case 2: + case -2: + dualChannelFiltering(pQmfReal, pQmfImag, pReadIdx, mHybridReal, mHybridImag, (hybridConfig<0) ? 1 : 0 ); + break; + case 4: + case -4: + fourChannelFiltering(pQmfReal, pQmfImag, pReadIdx, mHybridReal, mHybridImag, (hybridConfig<0) ? 1 : 0 ); + break; + case 8: + case -8: + eightChannelFiltering(pQmfReal, pQmfImag, pReadIdx, mHybridReal, mHybridImag, (hybridConfig<0) ? 1 : 0 ); + break; + default: + err = -1; + } + + return err; +} + + + diff --git a/libFDK/src/dct.cpp b/libFDK/src/dct.cpp index d05a26f..6a267cf 100644 --- a/libFDK/src/dct.cpp +++ b/libFDK/src/dct.cpp @@ -21,7 +21,7 @@ *******************************************************************************/ /*! \file dct.cpp - \brief DCT Implementations $Revision: 36871 $ + \brief DCT Implementations $Revision: 37444 $ Library functions to calculate standard DCTs. This will most likely be replaced by hand-optimized functions for the specific target processor. diff --git a/libFDK/src/fft.cpp b/libFDK/src/fft.cpp index 9f47807..cd04b98 100644 --- a/libFDK/src/fft.cpp +++ b/libFDK/src/fft.cpp @@ -344,7 +344,7 @@ static inline void fft15(FIXP_DBL *pInput) y[ 3 + iy] = ur - vi; /* Im B'= -Re C + Re D + Im A - Im B */ \ y[ 7 + iy] = vi + ur; /* Im D'= Re C - Re D + Im A - Im B */ -static const FIXP_SPK fft16_w16[2] = { {{STC(0x7641af3d), STC(0x30fbc54d)}}, {{ STC(0x30fbc54d), STC(0x7641af3d)}} }; +static const FIXP_STP fft16_w16[2] = { STCP(0x7641af3d, 0x30fbc54d), STCP(0x30fbc54d, 0x7641af3d) }; LNK_SECTION_CODE_L1 inline void fft_16(FIXP_DBL *RESTRICT x) @@ -527,10 +527,10 @@ inline void fft_16(FIXP_DBL *RESTRICT x) } #ifndef FUNCTION_fft_32 -static const FIXP_SPK fft32_w32[6] = +static const FIXP_STP fft32_w32[6] = { - {{ STC(0x7641af3d), STC(0x30fbc54d)}}, {{ STC(0x30fbc54d), STC(0x7641af3d)}}, {{ STC(0x7d8a5f40), STC(0x18f8b83c)}}, - {{ STC(0x6a6d98a4), STC(0x471cece7)}}, {{ STC(0x471cece7), STC(0x6a6d98a4)}}, {{ STC(0x18f8b83c), STC(0x7d8a5f40)}} + STCP (0x7641af3d, 0x30fbc54d), STCP(0x30fbc54d, 0x7641af3d), STCP(0x7d8a5f40, 0x18f8b83c), + STCP (0x6a6d98a4, 0x471cece7), STCP(0x471cece7, 0x6a6d98a4), STCP(0x18f8b83c, 0x7d8a5f40) }; LNK_SECTION_CODE_L1 diff --git a/libFDK/src/qmf.cpp b/libFDK/src/qmf.cpp index b02a066..361fcfd 100644 --- a/libFDK/src/qmf.cpp +++ b/libFDK/src/qmf.cpp @@ -27,7 +27,7 @@ ******************************************************************************/ /*! \file - \brief Complex qmf analysis/synthesis, $Revision: 36871 $ + \brief Complex qmf analysis/synthesis, $Revision: 37444 $ This module contains the qmf filterbank for analysis [ cplxAnalysisQmfFiltering() ] and synthesis [ cplxSynthesisQmfFiltering() ]. It is a polyphase implementation of a complex exponential modulated filter bank. The analysis part usually runs at half the sample rate diff --git a/libMpegTPDec/include/tpdec_lib.h b/libMpegTPDec/include/tpdec_lib.h index f32f6d8..5597e9d 100644 --- a/libMpegTPDec/include/tpdec_lib.h +++ b/libMpegTPDec/include/tpdec_lib.h @@ -162,7 +162,8 @@ int CProgramConfig_LookupElement( * \return Total element count including all SCE, CPE and LFE. */ int CProgramConfig_GetElementTable( const CProgramConfig *pPce, - MP4_ELEMENT_ID table[] ); + MP4_ELEMENT_ID table[], + const INT elListSize ); /** * \brief Initialize a given AudioSpecificConfig structure. diff --git a/libMpegTPDec/src/tpdec_asc.cpp b/libMpegTPDec/src/tpdec_asc.cpp index ee7c7cf..3553398 100644 --- a/libMpegTPDec/src/tpdec_asc.cpp +++ b/libMpegTPDec/src/tpdec_asc.cpp @@ -382,11 +382,19 @@ int CProgramConfig_LookupElement( #ifdef TP_PCE_ENABLE int CProgramConfig_GetElementTable( const CProgramConfig *pPce, - MP4_ELEMENT_ID elList[] + MP4_ELEMENT_ID elList[], + const INT elListSize ) { int i, el = 0; + if ( elListSize + < pPce->NumFrontChannelElements + pPce->NumSideChannelElements + pPce->NumBackChannelElements + pPce->NumLfeChannelElements + ) + { + return 0; + } + for (i=0; i < pPce->NumFrontChannelElements; i++) { elList[el++] = (pPce->FrontElementIsCpe[i]) ? ID_CPE : ID_SCE; @@ -619,94 +627,6 @@ bail: #endif /* TP_ELD_ENABLE */ -static -TRANSPORTDEC_ERROR AudioSpecificConfig_ExtensionParse(CSAudioSpecificConfig *self, HANDLE_FDK_BITSTREAM bs, CSTpCallBacks *cb) -{ - TP_ASC_EXTENSION_ID lastAscExt, ascExtId = ASCEXT_UNKOWN; - INT bitsAvailable = (INT)FDKgetValidBits(bs); - - while (bitsAvailable >= 11) - { - lastAscExt = ascExtId; - ascExtId = (TP_ASC_EXTENSION_ID)FDKreadBits(bs, 11); - bitsAvailable -= 11; - - switch (ascExtId) { - case ASCEXT_SBR: /* 0x2b7 */ - if ( (self->m_extensionAudioObjectType != AOT_SBR) && (bitsAvailable >= 5) ) { - self->m_extensionAudioObjectType = getAOT(bs); - - if ( (self->m_extensionAudioObjectType == AOT_SBR) - || (self->m_extensionAudioObjectType == AOT_ER_BSAC) ) - { /* Get SBR extension configuration */ - self->m_sbrPresentFlag = FDKreadBits(bs, 1); - bitsAvailable -= 1; - - if ( self->m_sbrPresentFlag == 1 ) { - self->m_extensionSamplingFrequency = getSampleRate(bs, &self->m_extensionSamplingFrequencyIndex, 4); - - if ((INT)self->m_extensionSamplingFrequency <= 0) { - return TRANSPORTDEC_PARSE_ERROR; - } - } - if ( self->m_extensionAudioObjectType == AOT_ER_BSAC ) { - self->m_extensionChannelConfiguration = FDKreadBits(bs, 4); - bitsAvailable -= 4; - } - } - /* Update counter because of variable length fields (AOT and sampling rate) */ - bitsAvailable = (INT)FDKgetValidBits(bs); - } - break; - case ASCEXT_PS: /* 0x548 */ - if ( (lastAscExt == ASCEXT_SBR) - && (self->m_extensionAudioObjectType == AOT_SBR) - && (bitsAvailable > 0) ) - { /* Get PS extension configuration */ - self->m_psPresentFlag = FDKreadBits(bs, 1); - bitsAvailable -= 1; - } - break; - case ASCEXT_MPS: /* 0x76a */ - if ( self->m_extensionAudioObjectType == AOT_MPEGS ) - break; - case ASCEXT_LDMPS: /* 0x7cc */ - if ( (ascExtId == ASCEXT_LDMPS) - && (self->m_extensionAudioObjectType == AOT_LD_MPEGS) ) - break; - if (bitsAvailable >= 1) - { - bitsAvailable -= 1; - if ( FDKreadBits(bs, 1) ) { /* self->m_mpsPresentFlag */ - int sscLen = FDKreadBits(bs, 8); - bitsAvailable -= 8; - if (sscLen == 0xFF) { - sscLen += FDKreadBits(bs, 16); - bitsAvailable -= 16; - } - if (cb->cbSsc != NULL) { - cb->cbSsc( - cb->cbSscData, - bs, - self->m_aot, - self->m_samplingFrequency, - 1, - sscLen - ); - } else - FDKpushFor(bs, sscLen); /* Skip SSC to be able to read the next extension if there is one. */ - - bitsAvailable -= sscLen*8; - } - } - break; - default: - return TRANSPORTDEC_UNSUPPORTED_FORMAT; - } - } - - return TRANSPORTDEC_OK; -} /* * API Functions @@ -857,9 +777,6 @@ TRANSPORTDEC_ERROR AudioSpecificConfig_Parse( break; } - if (fExplicitBackwardCompatible) { - ErrorStatus = AudioSpecificConfig_ExtensionParse(self, bs, cb); - } return (ErrorStatus); } diff --git a/libMpegTPDec/src/tpdec_latm.cpp b/libMpegTPDec/src/tpdec_latm.cpp index 28daebc..71e35a7 100644 --- a/libMpegTPDec/src/tpdec_latm.cpp +++ b/libMpegTPDec/src/tpdec_latm.cpp @@ -315,9 +315,6 @@ TRANSPORTDEC_ERROR CLatmDemux_ReadPayloadLengthInfo(HANDLE_FDK_BITSTREAM bs, CLa else { ErrorStatus = TRANSPORTDEC_PARSE_ERROR; //AAC_DEC_LATM_TIMEFRAMING; } - if ((INT)FDKgetValidBits(bs) < totalPayloadBits) { - return TRANSPORTDEC_NOT_ENOUGH_BITS; - } if (pLatmDemux->m_audioMuxLengthBytes > 0 && totalPayloadBits > pLatmDemux->m_audioMuxLengthBytes*8) { return TRANSPORTDEC_PARSE_ERROR; } diff --git a/libMpegTPDec/src/tpdec_lib.cpp b/libMpegTPDec/src/tpdec_lib.cpp index 4387847..e179678 100644 --- a/libMpegTPDec/src/tpdec_lib.cpp +++ b/libMpegTPDec/src/tpdec_lib.cpp @@ -85,6 +85,7 @@ struct TRANSPORTDEC #define TPDEC_IGNORE_BUFFERFULLNESS 4 #define TPDEC_EARLY_CONFIG 8 #define TPDEC_LOST_FRAMES_PENDING 16 +#define TPDEC_CONFIG_FOUND 32 C_ALLOC_MEM(Ram_TransportDecoder, TRANSPORTDEC, 1) C_ALLOC_MEM(Ram_TransportDecoderBuffer, UCHAR, TRANSPORTDEC_INBUF_SIZE) @@ -177,11 +178,10 @@ TRANSPORTDEC_ERROR transportDec_OutOfBandConfig(HANDLE_TRANSPORTDEC hTp, UCHAR * } } break; + default: case TT_MP4_RAW: err = AudioSpecificConfig_Parse(&hTp->asc[layer], hBs, 1, &hTp->callbacks); break; - default: - return TRANSPORTDEC_UNSUPPORTED_FORMAT; } if (err == TRANSPORTDEC_OK) { int errC; @@ -192,6 +192,10 @@ TRANSPORTDEC_ERROR transportDec_OutOfBandConfig(HANDLE_TRANSPORTDEC hTp, UCHAR * } } + if (err == TRANSPORTDEC_OK) { + hTp->flags |= TPDEC_CONFIG_FOUND; + } + return err; } @@ -439,6 +443,14 @@ TRANSPORTDEC_ERROR synchronization( totalBits = (INT)FDKgetValidBits(hBs); + if (totalBits <= 0) { + /* Return sync error, because this happens only in case of severly damaged bit streams. + Returning TRANSPORTDEC_NOT_ENOUGH_BITS here is very dangerous. */ + /* numberOfRawDataBlocks must be always reset in case of sync errors. */ + hTp->numberOfRawDataBlocks = 0; + goto bail; + } + fTraverseMoreFrames = (hTp->flags & (TPDEC_MINIMIZE_DELAY|TPDEC_EARLY_CONFIG)) && ! (hTp->flags & TPDEC_SYNCOK); /* Set transport specific sync parameters */ @@ -625,13 +637,15 @@ TRANSPORTDEC_ERROR synchronization( if (err == TRANSPORTDEC_SYNC_ERROR) { int bits; - FDK_ASSERT(hTp->numberOfRawDataBlocks == 0); + /* Enforce re-sync of transport headers. */ + hTp->numberOfRawDataBlocks = 0; + /* Ensure that the bit amount lands and a multiple of TPDEC_SYNCSKIP */ bits = (bitsAvail + headerBits) % TPDEC_SYNCSKIP; /* Rewind - TPDEC_SYNCSKIP, in order to look for a synch one bit ahead next time. */ FDKpushBiDirectional(hBs, -(headerBits - TPDEC_SYNCSKIP) + bits); bitsAvail += headerBits - TPDEC_SYNCSKIP - bits; - headerBits = 0; + headerBits = 0; } /* Frame traversal */ @@ -710,6 +724,7 @@ TRANSPORTDEC_ERROR synchronization( err = TRANSPORTDEC_OK; } +bail: hTp->auLength[0] = rawDataBlockLength; if (err == TRANSPORTDEC_OK) { @@ -852,7 +867,7 @@ TRANSPORTDEC_ERROR transportDec_ReadAccessUnit( const HANDLE_TRANSPORTDEC hTp, c case TT_MP4_ADIF: /* Read header if not already done */ - if (!(hTp->flags & TPDEC_SYNCOK)) + if (!(hTp->flags & TPDEC_CONFIG_FOUND)) { CProgramConfig *pce; @@ -876,8 +891,7 @@ TRANSPORTDEC_ERROR transportDec_ReadAccessUnit( const HANDLE_TRANSPORTDEC hTp, c errC = hTp->callbacks.cbUpdateConfig(hTp->callbacks.cbUpdateConfigData, &hTp->asc[0]); if (errC == 0) { - /* Misuse sync flag to parse header only once. */ - hTp->flags |= TPDEC_SYNCOK; + hTp->flags |= TPDEC_CONFIG_FOUND; } else { err = TRANSPORTDEC_PARSE_ERROR; goto bail; diff --git a/libMpegTPEnc/src/tpenc_asc.cpp b/libMpegTPEnc/src/tpenc_asc.cpp index 674ffe2..8b7f804 100644 --- a/libMpegTPEnc/src/tpenc_asc.cpp +++ b/libMpegTPEnc/src/tpenc_asc.cpp @@ -33,15 +33,6 @@ #include "FDK_bitstream.h" #include "genericStds.h" -#define ASC_FLAG_EXT 0x0001 -#define ASC_FLAG_SBR 0x0002 -#define ASC_FLAG_SBRCRC 0x0004 -#define ASC_FLAG_VCB11 0x0010 -#define ASC_FLAG_RVLC 0x0020 -#define ASC_FLAG_HCR 0x0040 -#define ASC_FLAG_HCR 0x0040 - - #define PCE_MAX_ELEMENTS 8 /** @@ -353,7 +344,6 @@ int transportEnc_writeELDSpecificConfig( HANDLE_FDK_BITSTREAM hBs, CODER_CONFIG *config, int epConfig, - int flags, CSTpCallBacks *cb ) { @@ -363,14 +353,14 @@ int transportEnc_writeELDSpecificConfig( } FDKwriteBits(hBs, (config->samplesPerFrame == 480) ? 1 : 0, 1); - FDKwriteBits(hBs, (flags & ASC_FLAG_VCB11) ? 1:0, 1); - FDKwriteBits(hBs, (flags & ASC_FLAG_RVLC ) ? 1:0, 1); - FDKwriteBits(hBs, (flags & ASC_FLAG_HCR ) ? 1:0, 1); + FDKwriteBits(hBs, (config->flags & CC_VCB11 ) ? 1:0, 1); + FDKwriteBits(hBs, (config->flags & CC_RVLC ) ? 1:0, 1); + FDKwriteBits(hBs, (config->flags & CC_HCR ) ? 1:0, 1); - FDKwriteBits(hBs, (flags & ASC_FLAG_SBR) ? 1:0, 1); /* SBR header flag */ - if ( (flags & ASC_FLAG_SBR) ) { + FDKwriteBits(hBs, (config->flags & CC_SBR) ? 1:0, 1); /* SBR header flag */ + if ( (config->flags & CC_SBR) ) { FDKwriteBits(hBs, (config->samplingRate == config->extSamplingRate) ? 0:1, 1); /* Samplerate Flag */ - FDKwriteBits(hBs, (flags &ASC_FLAG_SBRCRC) ? 1:0, 1); /* SBR CRC flag*/ + FDKwriteBits(hBs, (config->flags & CC_SBRCRC) ? 1:0, 1); /* SBR CRC flag*/ if (cb->cbSbr != NULL) { const PCE_CONFIGURATION *pPce; @@ -399,7 +389,7 @@ int transportEnc_writeASC ( CSTpCallBacks *cb ) { - UINT flags = 0; + UINT extFlag = 0; int err; int epConfig = 0; @@ -416,14 +406,11 @@ int transportEnc_writeASC ( case AOT_ER_AAC_LD: case AOT_ER_AAC_ELD: case AOT_USAC: - flags |= ASC_FLAG_EXT; + extFlag = 1; break; default: break; } - if (config->flags & CC_SBR) { - flags |= ASC_FLAG_SBR; - } if (config->extAOT == AOT_SBR || config->extAOT == AOT_PS) writeAot(asc, config->extAOT); @@ -462,14 +449,14 @@ int transportEnc_writeASC ( case AOT_ER_TWIN_VQ: case AOT_ER_BSAC: case AOT_ER_AAC_LD: - err = transportEnc_writeGASpecificConfig(asc, config, (flags & ASC_FLAG_EXT) ? 1:0, alignAnchor); + err = transportEnc_writeGASpecificConfig(asc, config, extFlag, alignAnchor); if (err) return err; break; #endif /* TP_GA_ENABLE */ #ifdef TP_ELD_ENABLE case AOT_ER_AAC_ELD: - err = transportEnc_writeELDSpecificConfig(asc, config, epConfig, flags, cb); + err = transportEnc_writeELDSpecificConfig(asc, config, epConfig, cb); if (err) return err; break; diff --git a/libSBRdec/src/env_extr.cpp b/libSBRdec/src/env_extr.cpp index 040b812..1e02975 100644 --- a/libSBRdec/src/env_extr.cpp +++ b/libSBRdec/src/env_extr.cpp @@ -25,7 +25,7 @@ *******************************************************************************/ /*! \file - \brief Envelope extraction $Revision: 36841 $ + \brief Envelope extraction $Revision: 38006 $ The functions provided by this module are mostly called by applySBR(). After it is determined that there is valid SBR data, sbrGetHeaderData() might be called if the current SBR data contains an \ref SBR_HEADER_ELEMENT as opposed to a \ref SBR_STANDARD_ELEMENT. This function @@ -167,6 +167,10 @@ initHeaderData ( /* One SBR timeslot corresponds to the amount of samples equal to the amount of analysis bands, divided by the timestep. */ hHeaderData->numberTimeSlots = (samplesPerFrame/numAnalysisBands) >> (hHeaderData->timeStep - 1); + if (hHeaderData->numberTimeSlots > (16)) { + sbrError = SBRDEC_UNSUPPORTED_CONFIG; + } + hHeaderData->numberOfAnalysisBands = numAnalysisBands; bail: diff --git a/libSBRdec/src/sbr_dec.cpp b/libSBRdec/src/sbr_dec.cpp index a075ca3..6be3c00 100644 --- a/libSBRdec/src/sbr_dec.cpp +++ b/libSBRdec/src/sbr_dec.cpp @@ -25,7 +25,7 @@ *******************************************************************************/ /*! \file - \brief Sbr decoder $Revision: 36841 $ + \brief Sbr decoder $Revision: 37646 $ This module provides the actual decoder implementation. The SBR data (side information) is already decoded. Only three functions are provided: @@ -537,6 +537,9 @@ sbr_dec ( HANDLE_SBR_DEC hSbrDec, /*!< handle to Decoder channel */ maxShift = hSbrDec->sbrDrcChannel.nextFact_exp; } + /* copy DRC data to right channel (with PS both channels use the same DRC gains) */ + FDKmemcpy(&hSbrDecRight->sbrDrcChannel, &hSbrDec->sbrDrcChannel, sizeof(SBRDEC_DRC_CHANNEL)); + for (i = 0; i < synQmf->no_col; i++) { /* ----- no_col loop ----- */ INT outScalefactorR, outScalefactorL; @@ -565,7 +568,7 @@ sbr_dec ( HANDLE_SBR_DEC hSbrDec, /*!< handle to Decoder channel */ sbrDecoder_drcApplySlot ( /* right channel */ - &hSbrDec->sbrDrcChannel, + &hSbrDecRight->sbrDrcChannel, rQmfReal, rQmfImag, i, diff --git a/libSBRdec/src/sbr_ram.cpp b/libSBRdec/src/sbr_ram.cpp index 6fa34a5..883a261 100644 --- a/libSBRdec/src/sbr_ram.cpp +++ b/libSBRdec/src/sbr_ram.cpp @@ -26,7 +26,7 @@ /*! \file \brief Memory layout - $Revision: 36841 $ + $Revision: 38012 $ This module declares all static and dynamic memory spaces */ diff --git a/libSBRdec/src/sbrdecoder.cpp b/libSBRdec/src/sbrdecoder.cpp index dc824cb..2e5e304 100644 --- a/libSBRdec/src/sbrdecoder.cpp +++ b/libSBRdec/src/sbrdecoder.cpp @@ -25,7 +25,7 @@ *******************************************************************************/ /*! \file - \brief SBR decoder frontend $Revision: 36841 $ + \brief SBR decoder frontend $Revision: 38029 $ This module provides a frontend to the SBR decoder. The function openSBR() is called for initialization. The function sbrDecoder_Apply() is called for each frame. sbr_Apply() will call the required functions to decode the raw SBR data (provided by env_extr.cpp), to decode the envelope data and noise floor levels [decodeSbrData()], @@ -79,7 +79,7 @@ /* Decoder library info */ #define SBRDECODER_LIB_VL0 2 #define SBRDECODER_LIB_VL1 1 -#define SBRDECODER_LIB_VL2 0 +#define SBRDECODER_LIB_VL2 1 #define SBRDECODER_LIB_TITLE "SBR Decoder" #define SBRDECODER_LIB_BUILD_DATE __DATE__ #define SBRDECODER_LIB_BUILD_TIME __TIME__ @@ -367,6 +367,7 @@ SBR_ERROR sbrDecoder_InitElement ( { SBR_ERROR sbrError = SBRDEC_OK; int chCnt=0; + int nSbrElementsStart = self->numSbrElements; /* Check core codec AOT */ if (! sbrDecoder_isCoreCodecValid(coreCodec) || elementIndex >= (4)) { @@ -488,8 +489,13 @@ SBR_ERROR sbrDecoder_InitElement ( bail: if (sbrError != SBRDEC_OK) { - /* Free the memory allocated for this element */ - sbrDecoder_DestroyElement( self, elementIndex ); + if (nSbrElementsStart < self->numSbrElements) { + /* Free the memory allocated for this element */ + sbrDecoder_DestroyElement( self, elementIndex ); + } else if (self->pSbrElement[elementIndex] != NULL) { + /* Set error flag to trigger concealment */ + self->pSbrElement[elementIndex]->frameErrorFlag[self->pSbrElement[elementIndex]->useFrameSlot] = 1;; + } } return sbrError; @@ -933,7 +939,8 @@ SBR_ERROR sbrDecoder_Parse( 1); } - if (headerStatus == HEADER_RESET) { + if (headerStatus == HEADER_RESET) + { errorStatus = sbrDecoder_HeaderUpdate( self, hSbrHeader, @@ -1130,6 +1137,10 @@ sbrDecoder_DecodeElement ( self->flags ); + if (errorStatus != SBRDEC_OK) { + return errorStatus; + } + hSbrHeader->syncState = UPSAMPLING; errorStatus = sbrDecoder_HeaderUpdate( @@ -1139,6 +1150,11 @@ sbrDecoder_DecodeElement ( pSbrChannel, hSbrElement->nChannels ); + + if (errorStatus != SBRDEC_OK) { + hSbrHeader->syncState = SBR_NOT_INITIALIZED; + return errorStatus; + } } /* reset */ @@ -1296,6 +1312,11 @@ SBR_ERROR sbrDecoder_Apply ( HANDLE_SBRDECODER self, psPossible = *psDecoded; + if (self->numSbrElements < 1) { + /* exit immediately to avoid access violations */ + return SBRDEC_CREATE_ERROR; + } + /* Sanity check of allocated SBR elements. */ for (sbrElementNum=0; sbrElementNumnumSbrElements; sbrElementNum++) { if (self->pSbrElement[sbrElementNum] == NULL) { diff --git a/libSBRenc/include/sbr_encoder.h b/libSBRenc/include/sbr_encoder.h index d54582d..88d0569 100644 --- a/libSBRenc/include/sbr_encoder.h +++ b/libSBRenc/include/sbr_encoder.h @@ -212,6 +212,16 @@ INT sbrEncoder_Open( INT supportPS ); +/** + * \brief get closest working bit rate to specified desired bit rate for a single SBR element + * \param bitRate the desired target bit rate + * \param numChannels the amount of audio channels + * \param coreSampleRate the sample rate of the core coder + * \param the current Audio Object Type + * \return closest working bit rate to bitRate value + */ +UINT sbrEncoder_LimitBitRate(UINT bitRate, UINT numChannels, UINT coreSampleRate, AUDIO_OBJECT_TYPE aot); + /** * \brief Initialize SBR Encoder instance. * \param phSbrEncoder Pointer to a SBR Encoder instance. diff --git a/libSBRenc/src/Android.mk b/libSBRenc/src/Android.mk index 55d5d4e..0a3a9d8 100644 --- a/libSBRenc/src/Android.mk +++ b/libSBRenc/src/Android.mk @@ -16,7 +16,6 @@ LOCAL_SRC_FILES := \ env_est.cpp \ invf_est.cpp \ nf_est.cpp \ - psenc_hybrid.cpp \ ps_main.cpp \ sbrenc_freq_sca.cpp \ sbr_misc.cpp \ diff --git a/libSBRenc/src/env_est.cpp b/libSBRenc/src/env_est.cpp index 0b7f7b0..8e8e190 100644 --- a/libSBRenc/src/env_est.cpp +++ b/libSBRenc/src/env_est.cpp @@ -799,27 +799,6 @@ calculateSbrEnvelope (FIXP_DBL **RESTRICT YBufferLeft, /*! energy buffer left * } /* i*/ } -/* - * Update QMF buffers - */ -static void FDKsbrEnc_updateRIBuffers(HANDLE_ENV_CHANNEL h_envChan) -{ - int i; - - /* rBufferWriteOffset ist always 0, do we need this ? */ - for (i = 0; i < h_envChan->sbrExtractEnvelope.rBufferWriteOffset; i++) { - FIXP_DBL *temp; - - temp = h_envChan->sbrExtractEnvelope.rBuffer[i]; - h_envChan->sbrExtractEnvelope.rBuffer[i] = h_envChan->sbrExtractEnvelope.rBuffer[i + h_envChan->sbrExtractEnvelope.no_cols]; - h_envChan->sbrExtractEnvelope.rBuffer[i + h_envChan->sbrExtractEnvelope.no_cols] = temp; - - temp = h_envChan->sbrExtractEnvelope.iBuffer[i]; - h_envChan->sbrExtractEnvelope.iBuffer[i] = h_envChan->sbrExtractEnvelope.iBuffer[i + h_envChan->sbrExtractEnvelope.no_cols]; - h_envChan->sbrExtractEnvelope.iBuffer[i + h_envChan->sbrExtractEnvelope.no_cols] = temp; - } -} - /***************************************************************************/ /*! @@ -873,8 +852,8 @@ FDKsbrEnc_extractSbrEnvelope1 ( Precalculation of Tonality Quotas COEFF Transform OK */ FDKsbrEnc_CalculateTonalityQuotas(&hEnvChan->TonCorr, - sbrExtrEnv->rBuffer+ sbrExtrEnv->rBufferWriteOffset, - sbrExtrEnv->iBuffer+ sbrExtrEnv->rBufferWriteOffset, + sbrExtrEnv->rBuffer, + sbrExtrEnv->iBuffer, h_con->freqBandTable[HI][h_con->nSfb[HI]], hEnvChan->qmfScale); @@ -914,8 +893,6 @@ FDKsbrEnc_extractSbrEnvelope1 ( sbrExtrEnv->no_cols); - - FDKsbrEnc_updateRIBuffers(hEnvChan); } /***************************************************************************/ @@ -1741,12 +1718,11 @@ FDKsbrEnc_InitExtractSbrEnvelope (HANDLE_SBR_EXTRACT_ENVELOPE hSbrCut, { hSbrCut->YBufferWriteOffset = tran_off*time_step; } - hSbrCut->rBufferWriteOffset = 0; hSbrCut->rBufferReadOffset = 0; YBufferLength = hSbrCut->YBufferWriteOffset + no_cols; - rBufferLength = hSbrCut->rBufferWriteOffset + no_cols; + rBufferLength = no_cols; hSbrCut->pre_transient_info[0] = 0; hSbrCut->pre_transient_info[1] = 0; @@ -1824,8 +1800,8 @@ FDKsbrEnc_deleteExtractSbrEnvelope (HANDLE_SBR_EXTRACT_ENVELOPE hSbrCut) INT FDKsbrEnc_GetEnvEstDelay(HANDLE_SBR_EXTRACT_ENVELOPE hSbr) { - return hSbr->no_rows*((hSbr->YBufferWriteOffset)*2 + /* mult 2 because nrg's are grouped half */ - hSbr->rBufferWriteOffset - hSbr->rBufferReadOffset ); /* in reference hold half spec and calc nrg's on overlapped spec */ + return hSbr->no_rows*((hSbr->YBufferWriteOffset)*2 /* mult 2 because nrg's are grouped half */ + - hSbr->rBufferReadOffset ); /* in reference hold half spec and calc nrg's on overlapped spec */ } diff --git a/libSBRenc/src/env_est.h b/libSBRenc/src/env_est.h index 5aa66ee..be74976 100644 --- a/libSBRenc/src/env_est.h +++ b/libSBRenc/src/env_est.h @@ -25,7 +25,7 @@ ****************************************************************************/ /*! \file - \brief Envelope estimation structs and prototypes $Revision: 36847 $ + \brief Envelope estimation structs and prototypes $Revision: 37142 $ */ #ifndef __ENV_EST_H #define __ENV_EST_H @@ -56,7 +56,6 @@ typedef struct int YBufferWriteOffset; int YBufferSzShift; int rBufferReadOffset; - int rBufferWriteOffset; int no_cols; int no_rows; diff --git a/libSBRenc/src/ps_bitenc.cpp b/libSBRenc/src/ps_bitenc.cpp index 960229b..82fec24 100644 --- a/libSBRenc/src/ps_bitenc.cpp +++ b/libSBRenc/src/ps_bitenc.cpp @@ -202,8 +202,7 @@ static const UINT opdDeltaTime_Code[] = static const INT psBands[] = { PS_BANDS_COARSE, - PS_BANDS_MID, - PS_BANDS_FINE + PS_BANDS_MID }; static INT getNoBands(PS_RESOLUTION mode) diff --git a/libSBRenc/src/ps_const.h b/libSBRenc/src/ps_const.h index 20fcc88..376528b 100644 --- a/libSBRenc/src/ps_const.h +++ b/libSBRenc/src/ps_const.h @@ -28,6 +28,17 @@ #ifndef PS_CONST_H #define PS_CONST_H +#define MAX_PS_CHANNELS ( 2 ) +#define HYBRID_MAX_QMF_BANDS ( 3 ) +#define HYBRID_FILTER_LENGTH ( 13 ) +#define HYBRID_FILTER_DELAY ( (HYBRID_FILTER_LENGTH-1)/2 ) + +#define HYBRID_FRAMESIZE ( QMF_MAX_TIME_SLOTS ) +#define HYBRID_READ_OFFSET ( 10 ) + +#define MAX_HYBRID_BANDS ( (QMF_CHANNELS-HYBRID_MAX_QMF_BANDS+10) ) + + typedef enum { PS_RES_COARSE = 0, PS_RES_MID = 1, @@ -37,8 +48,7 @@ typedef enum { typedef enum { PS_BANDS_COARSE = 10, PS_BANDS_MID = 20, - PS_BANDS_FINE = 34, - PS_MAX_BANDS = PS_BANDS_FINE + PS_MAX_BANDS = PS_BANDS_MID } PS_BANDS; typedef enum { @@ -62,4 +72,14 @@ typedef enum { } PS_CONSTS; +typedef enum { + PSENC_OK = 0x0000, /*!< No error happened. All fine. */ + PSENC_INVALID_HANDLE = 0x0020, /*!< Handle passed to function call was invalid. */ + PSENC_MEMORY_ERROR = 0x0021, /*!< Memory allocation failed. */ + PSENC_INIT_ERROR = 0x0040, /*!< General initialization error. */ + PSENC_ENCODE_ERROR = 0x0060 /*!< The encoding process was interrupted by an unexpected error. */ + +} FDK_PSENC_ERROR; + + #endif diff --git a/libSBRenc/src/ps_encode.cpp b/libSBRenc/src/ps_encode.cpp index 1f78d66..6f098aa 100644 --- a/libSBRenc/src/ps_encode.cpp +++ b/libSBRenc/src/ps_encode.cpp @@ -27,7 +27,7 @@ ******************************************************************************/ /*! \file - \brief PS parameter extraction, encoding functions $Revision: 36847 $ + \brief PS parameter extraction, encoding functions $Revision: 37142 $ */ #include "ps_main.h" @@ -43,7 +43,6 @@ #include "genericStds.h" - inline void FDKsbrEnc_addFIXP_DBL(const FIXP_DBL *X, const FIXP_DBL *Y, FIXP_DBL *Z, INT n) { for (INT i=0; iiidTimeCnt = MAX_TIME_DIFF_FRAMES; hPsData->iccTimeCnt = MAX_TIME_DIFF_FRAMES; hPsData->noEnvCnt = MAX_NOENV_CNT; - } else { - error = ERROR(CDI, "Unable to write to hPsData."); } return error; @@ -226,9 +185,6 @@ static INT getICCMode(const INT nBands, case PS_BANDS_MID: mode = PS_RES_MID; break; - case PS_BANDS_FINE: - mode = PS_RES_FINE; - break; default: mode = 0; } @@ -252,9 +208,6 @@ static INT getIIDMode(const INT nBands, case PS_BANDS_MID: mode = PS_RES_MID; break; - case PS_BANDS_FINE: - mode = PS_RES_FINE; - break; default: mode = 0; break; @@ -339,7 +292,6 @@ static void processIidData(PS_DATA *psData, INT loudnDiff = 0; INT iidTransmit = 0; - bitsIidFreq = bitsIidTime = 0; /* Quantize IID coefficients */ @@ -348,7 +300,6 @@ static void processIidData(PS_DATA *psData, errIIDFine += quantizeCoef(iid[env], psBands, iidQuantFine_fx, 15, 31, iidIdxFine[env]); } - /* normalize error to number of envelopes, ps bands errIID /= psBands*nEnvelopes; errIIDFine /= psBands*nEnvelopes; */ @@ -638,8 +589,8 @@ static void calculateIID(FIXP_DBL ldPwrL[PS_MAX_ENVELOPES][PS_MAX_BANDS], */ FIXP_DBL IID = fMultDiv2( FL2FXCONST_DBL(LOG10_2_10/IID_SCALE_FT), (ldPwrL[env][i]-ldPwrR[env][i]) ); - IID = fixMin( IID, (FIXP_DBL)(FL2FXCONST_DBL( 1.f)>>(LD_DATA_SHIFT+1)) ); - IID = fixMax( IID, (FIXP_DBL)(FL2FXCONST_DBL(-1.f)>>(LD_DATA_SHIFT+1)) ); + IID = fixMin( IID, (FIXP_DBL)(MAXVAL_DBL>>(LD_DATA_SHIFT+1)) ); + IID = fixMax( IID, (FIXP_DBL)(MINVAL_DBL>>(LD_DATA_SHIFT+1)) ); iid[env][i] = IID << (LD_DATA_SHIFT+1); } } @@ -664,9 +615,6 @@ static void calculateICC(FIXP_DBL ldPwrL[PS_MAX_ENVELOPES][PS_MAX_BANDS], case PS_BANDS_MID: border = 11; break; - case PS_BANDS_FINE: - border = 16; - break; default: break; } @@ -748,70 +696,74 @@ void FDKsbrEnc_initPsBandNrgScale(HANDLE_PS_ENCODE hPsEncode) } } -HANDLE_ERROR_INFO FDKsbrEnc_CreatePSEncode(HANDLE_PS_ENCODE *phPsEncode){ - - HANDLE_ERROR_INFO error = noError; - - HANDLE_PS_ENCODE hPsEncode = GetRam_PsEncode(); - FDKmemclear(hPsEncode,sizeof(PS_ENCODE)); +FDK_PSENC_ERROR FDKsbrEnc_CreatePSEncode( + HANDLE_PS_ENCODE *phPsEncode + ) +{ + FDK_PSENC_ERROR error = PSENC_OK; - if(error == noError){ - if(noError != (error = CreatePSData(&hPsEncode->hPsData))){ - error = handBack(error); + if (phPsEncode==NULL) { + error = PSENC_INVALID_HANDLE; + } + else { + HANDLE_PS_ENCODE hPsEncode = NULL; + if (NULL==(hPsEncode = GetRam_PsEncode())) { + error = PSENC_MEMORY_ERROR; + goto bail; } + FDKmemclear(hPsEncode,sizeof(PS_ENCODE)); + *phPsEncode = hPsEncode; /* return allocated handle */ } - - *phPsEncode = hPsEncode; - +bail: return error; } -HANDLE_ERROR_INFO FDKsbrEnc_InitPSEncode(HANDLE_PS_ENCODE hPsEncode, const PS_BANDS psEncMode, const FIXP_DBL iidQuantErrorThreshold){ - - HANDLE_ERROR_INFO error = noError; +FDK_PSENC_ERROR FDKsbrEnc_InitPSEncode( + HANDLE_PS_ENCODE hPsEncode, + const PS_BANDS psEncMode, + const FIXP_DBL iidQuantErrorThreshold + ) +{ + FDK_PSENC_ERROR error = PSENC_OK; - if(error == noError){ - if(noError != (InitPSData(hPsEncode->hPsData))){ - error = handBack(error); - } + if (NULL==hPsEncode) { + error = PSENC_INVALID_HANDLE; } + else { + if (PSENC_OK != (InitPSData(&hPsEncode->psData))) { + goto bail; + } - if(error == noError){ switch(psEncMode){ - case PS_BANDS_COARSE: - case PS_BANDS_MID: - hPsEncode->nQmfIidGroups = QMF_GROUPS_LO_RES; - hPsEncode->nSubQmfIidGroups = SUBQMF_GROUPS_LO_RES; - FDKmemcpy(hPsEncode->iidGroupBorders, iidGroupBordersLoRes, (hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups + 1)*sizeof(INT)); - FDKmemcpy(hPsEncode->subband2parameterIndex, subband2parameter20, (hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups) *sizeof(INT)); - FDKmemcpy(hPsEncode->iidGroupWidthLd, iidGroupWidthLdLoRes, (hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups) *sizeof(UCHAR)); - break; - case PS_BANDS_FINE: - FDK_ASSERT(0); /* we don't support this mode! */ - - break; - default: - error = ERROR(CDI, "Invalid stereo band configuration."); - break; + case PS_BANDS_COARSE: + case PS_BANDS_MID: + hPsEncode->nQmfIidGroups = QMF_GROUPS_LO_RES; + hPsEncode->nSubQmfIidGroups = SUBQMF_GROUPS_LO_RES; + FDKmemcpy(hPsEncode->iidGroupBorders, iidGroupBordersLoRes, (hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups + 1)*sizeof(INT)); + FDKmemcpy(hPsEncode->subband2parameterIndex, subband2parameter20, (hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups) *sizeof(INT)); + FDKmemcpy(hPsEncode->iidGroupWidthLd, iidGroupWidthLdLoRes, (hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups) *sizeof(UCHAR)); + break; + default: + error = PSENC_INIT_ERROR; + goto bail; } - } - if(error == noError){ hPsEncode->psEncMode = psEncMode; hPsEncode->iidQuantErrorThreshold = iidQuantErrorThreshold; FDKsbrEnc_initPsBandNrgScale(hPsEncode); } - +bail: return error; } -HANDLE_ERROR_INFO FDKsbrEnc_DestroyPSEncode(HANDLE_PS_ENCODE *phPsEncode){ - - HANDLE_ERROR_INFO error = noError; +FDK_PSENC_ERROR FDKsbrEnc_DestroyPSEncode( + HANDLE_PS_ENCODE *phPsEncode + ) +{ + FDK_PSENC_ERROR error = PSENC_OK; - if(error == noError){ - DestroyPSData(&(*phPsEncode)->hPsData); + if (NULL !=phPsEncode) { FreeRam_PsEncode(phPsEncode); } @@ -825,44 +777,42 @@ typedef struct { FIXP_DBL ldPwrR[PS_MAX_ENVELOPES][PS_MAX_BANDS]; FIXP_DBL pwrCr[PS_MAX_ENVELOPES][PS_MAX_BANDS]; FIXP_DBL pwrCi[PS_MAX_ENVELOPES][PS_MAX_BANDS]; + } PS_PWR_DATA; -HANDLE_ERROR_INFO FDKsbrEnc_PSEncode(HANDLE_PS_ENCODE RESTRICT hPsEncode, - HANDLE_PS_OUT RESTRICT hPsOut, - HANDLE_PS_CHANNEL_DATA RESTRICT hChanDatal, - HANDLE_PS_CHANNEL_DATA RESTRICT hChanDatar, - UCHAR *RESTRICT dynBandScale, - UINT maxEnvelopes, - const int sendHeader) + +FDK_PSENC_ERROR FDKsbrEnc_PSEncode( + HANDLE_PS_ENCODE hPsEncode, + HANDLE_PS_OUT hPsOut, + UCHAR *dynBandScale, + UINT maxEnvelopes, + FIXP_DBL *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2], + const INT frameSize, + const INT sendHeader + ) { - HANDLE_ERROR_INFO error = noError; - HANDLE_PS_DATA hPsData = hPsEncode->hPsData; - HANDLE_PS_HYBRID_DATA hHybDatal = hChanDatal->hHybData; - HANDLE_PS_HYBRID_DATA hHybDatar = hChanDatar->hHybData; - FIXP_QMF **RESTRICT lr = NULL, **RESTRICT li = NULL, **RESTRICT rr = NULL, **RESTRICT ri = NULL; + FDK_PSENC_ERROR error = PSENC_OK; + + HANDLE_PS_DATA hPsData = &hPsEncode->psData; FIXP_DBL iid [PS_MAX_ENVELOPES][PS_MAX_BANDS]; FIXP_DBL icc [PS_MAX_ENVELOPES][PS_MAX_BANDS]; int envBorder[PS_MAX_ENVELOPES+1]; - int group, bin, border, col, subband, band; + int group, bin, col, subband, band; int i = 0; int env = 0; int psBands = (int) hPsEncode->psEncMode; - int frameSize = FDKsbrEnc_GetHybridFrameSize(hHybDatal); /* same as FDKsbrEnc_GetHybridFrameSize(hHybDatar) */ int nIidGroups = hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups; int nEnvelopes = fixMin(maxEnvelopes, (UINT)PS_MAX_ENVELOPES); C_ALLOC_SCRATCH_START(pwrData, PS_PWR_DATA, 1); - for(env=0; envrHybData; li = hHybDatal->iHybData; - rr = hHybDatar->rHybData; ri = hHybDatar->iHybData; - UCHAR switched = 0; - for (group=0; group < nIidGroups; group++) { /* Translate group to bin */ bin = hPsEncode->subband2parameterIndex[group]; @@ -885,30 +831,21 @@ HANDLE_ERROR_INFO FDKsbrEnc_PSEncode(HANDLE_PS_ENCODE RESTRICT hPsEncode, bin >>= 1; } - if (!switched && group == hPsEncode->nSubQmfIidGroups) { - /* switch to qmf data */ - lr = hChanDatal->hPsQmfData->rQmfData; li = hChanDatal->hPsQmfData->iQmfData; - rr = hChanDatar->hPsQmfData->rQmfData; ri = hChanDatar->hPsQmfData->iQmfData; - /* calc offset between hybrid subsubbands and qmf bands */ - nHybridQmfOffset = FDKsbrEnc_GetNumberHybridQmfBands(hHybDatal) - FDKsbrEnc_GetNumberHybridBands(hHybDatal); - switched = 1; - } - /* determine group border */ - int bScale = 2*descale + hPsEncode->psBandNrgScale[bin]; - border = hPsEncode->iidGroupBorders[group+1]; + int bScale = hPsEncode->psBandNrgScale[bin]; FIXP_DBL pwrL_env_bin = pwrData->pwrL[env][bin]; FIXP_DBL pwrR_env_bin = pwrData->pwrR[env][bin]; FIXP_DBL pwrCr_env_bin = pwrData->pwrCr[env][bin]; FIXP_DBL pwrCi_env_bin = pwrData->pwrCi[env][bin]; + int scale = (int)dynBandScale[bin]; for (col=envBorder[env]; coliidGroupBorders[group]; subband < border; subband++) { - FIXP_QMF l_real = (lr[col][subband + nHybridQmfOffset]) << scale; - FIXP_QMF l_imag = (li[col][subband + nHybridQmfOffset]) << scale; - FIXP_QMF r_real = (rr[col][subband + nHybridQmfOffset]) << scale; - FIXP_QMF r_imag = (ri[col][subband + nHybridQmfOffset]) << scale; + for (subband = hPsEncode->iidGroupBorders[group]; subband < hPsEncode->iidGroupBorders[group+1]; subband++) { + FIXP_QMF l_real = (hybridData[col][0][0][subband]) << scale; + FIXP_QMF l_imag = (hybridData[col][0][1][subband]) << scale; + FIXP_QMF r_real = (hybridData[col][1][0][subband]) << scale; + FIXP_QMF r_imag = (hybridData[col][1][1][subband]) << scale; pwrL_env_bin += (fPow2Div2(l_real) + fPow2Div2(l_imag)) >> bScale; pwrR_env_bin += (fPow2Div2(r_real) + fPow2Div2(r_imag)) >> bScale; @@ -931,13 +868,10 @@ HANDLE_ERROR_INFO FDKsbrEnc_PSEncode(HANDLE_PS_ENCODE RESTRICT hPsEncode, } /* nEnvelopes */ - /* calculate iid and icc */ calculateIID(pwrData->ldPwrL, pwrData->ldPwrR, iid, nEnvelopes, psBands); calculateICC(pwrData->ldPwrL, pwrData->ldPwrR, pwrData->pwrCr, pwrData->pwrCi, icc, nEnvelopes, psBands); - - /*** Envelope Reduction ***/ while (envelopeReducible(iid,icc,psBands,nEnvelopes)) { int e=0; @@ -1001,7 +935,6 @@ HANDLE_ERROR_INFO FDKsbrEnc_PSEncode(HANDLE_PS_ENCODE RESTRICT hPsEncode, } - if (nEnvelopes>0) { hPsOut->enableIID = hPsData->iidEnable; @@ -1060,7 +993,6 @@ HANDLE_ERROR_INFO FDKsbrEnc_PSEncode(HANDLE_PS_ENCODE RESTRICT hPsEncode, } } /* Envelope > 0 */ - C_ALLOC_SCRATCH_END(pwrData, PS_PWR_DATA, 1) return error; diff --git a/libSBRenc/src/ps_encode.h b/libSBRenc/src/ps_encode.h index 6ce9d1f..be8ba9a 100644 --- a/libSBRenc/src/ps_encode.h +++ b/libSBRenc/src/ps_encode.h @@ -27,7 +27,7 @@ ******************************************************************************/ /*! \file - \brief PS parameter extraction, encoding functions $Revision: 36847 $ + \brief PS parameter extraction, encoding functions $Revision: 37142 $ */ #ifndef __INCLUDED_PS_ENCODE_H @@ -35,7 +35,7 @@ #include "ps_const.h" #include "ps_bitenc.h" -#include "psenc_hybrid.h" + #define IID_SCALE_FT (64.f) /* maxVal in Quant tab is +/- 50 */ #define IID_SCALE 6 /* maxVal in Quant tab is +/- 50 */ @@ -81,7 +81,7 @@ typedef struct T_PS_DATA { typedef struct T_PS_ENCODE{ - HANDLE_PS_DATA hPsData; + PS_DATA psData; PS_BANDS psEncMode; INT nQmfIidGroups; @@ -97,21 +97,29 @@ typedef struct T_PS_ENCODE{ typedef struct T_PS_ENCODE *HANDLE_PS_ENCODE; -typedef struct T_PS_CHANNEL_DATA *HANDLE_PS_CHANNEL_DATA; - -HANDLE_ERROR_INFO FDKsbrEnc_CreatePSEncode(HANDLE_PS_ENCODE *phPsEncode); - -HANDLE_ERROR_INFO FDKsbrEnc_InitPSEncode(HANDLE_PS_ENCODE hPsEncode, const PS_BANDS psEncMode, const FIXP_DBL iidQuantErrorThreshold); - -HANDLE_ERROR_INFO FDKsbrEnc_DestroyPSEncode(HANDLE_PS_ENCODE *phPsEncode); - -HANDLE_ERROR_INFO FDKsbrEnc_PSEncode(HANDLE_PS_ENCODE hPsEncode, - HANDLE_PS_OUT hPsOut, - HANDLE_PS_CHANNEL_DATA hChanDatal, - HANDLE_PS_CHANNEL_DATA hChanDatar, - UCHAR *dynBandScale, - UINT maxEnvelopes, - const int sendHeader); +FDK_PSENC_ERROR FDKsbrEnc_CreatePSEncode( + HANDLE_PS_ENCODE *phPsEncode + ); + +FDK_PSENC_ERROR FDKsbrEnc_InitPSEncode( + HANDLE_PS_ENCODE hPsEncode, + const PS_BANDS psEncMode, + const FIXP_DBL iidQuantErrorThreshold + ); + +FDK_PSENC_ERROR FDKsbrEnc_DestroyPSEncode( + HANDLE_PS_ENCODE *phPsEncode + ); + +FDK_PSENC_ERROR FDKsbrEnc_PSEncode( + HANDLE_PS_ENCODE hPsEncode, + HANDLE_PS_OUT hPsOut, + UCHAR *dynBandScale, + UINT maxEnvelopes, + FIXP_DBL *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2], + const INT frameSize, + const INT sendHeader + ); #endif diff --git a/libSBRenc/src/ps_main.cpp b/libSBRenc/src/ps_main.cpp index c2b19d8..be954c9 100644 --- a/libSBRenc/src/ps_main.cpp +++ b/libSBRenc/src/ps_main.cpp @@ -36,673 +36,247 @@ #include "sbr_ram.h" - - -/* Function declarations ****************************************************/ -static void psFindBestScaling(HANDLE_PARAMETRIC_STEREO hParametricStereo, - UCHAR *dynBandScale, - FIXP_QMF *maxBandValue, - SCHAR *dmxScale); - -/* - name: static HANDLE_ERROR_INFO CreatePSQmf() - description: Creates struct (buffer) to store qmf data - returns: error code of type HANDLE_ERROR_INFO - input: - INT nCols: number of qmf samples stored in regular qmf buffer - - INT nRows: number qmf channels - - INT hybridFilterDelay: delay in qmf samples of hybrid filter - output: - HANDLE_PS_QMF_DATA *hPsQmfData: according handle -*/ -static HANDLE_ERROR_INFO CreatePSQmf(HANDLE_PS_QMF_DATA *phPsQmfData, INT ch) -{ - HANDLE_ERROR_INFO error = noError; - HANDLE_PS_QMF_DATA hPsQmfData = GetRam_PsQmfData(ch); - if (hPsQmfData==NULL) { - error = 1; - goto bail; - } - FDKmemclear(hPsQmfData, sizeof(PS_QMF_DATA)); - - hPsQmfData->rQmfData[0] = GetRam_PsRqmf(ch); - hPsQmfData->iQmfData[0] = GetRam_PsIqmf(ch); - - if ( (hPsQmfData->rQmfData[0]==NULL) || (hPsQmfData->iQmfData[0]==NULL) ) { - error = 1; - goto bail; - } - - -bail: - *phPsQmfData = hPsQmfData; - return error; -} - -static HANDLE_ERROR_INFO InitPSQmf(HANDLE_PS_QMF_DATA hPsQmfData, INT nCols, INT nRows, INT hybridFilterDelay, INT ch, UCHAR *dynamic_RAM) -{ - INT i, bufferLength = 0; - - hPsQmfData->nCols = nCols; - hPsQmfData->nRows = nRows; - hPsQmfData->bufferReadOffset = QMF_READ_OFFSET; - hPsQmfData->bufferReadOffsetHybrid = HYBRID_READ_OFFSET; /* calc read offset for hybrid analysis in qmf samples */ - hPsQmfData->bufferWriteOffset = hPsQmfData->bufferReadOffsetHybrid + hybridFilterDelay; - hPsQmfData->bufferLength = bufferLength = hPsQmfData->bufferWriteOffset + nCols; - - FDK_ASSERT(PSENC_QMF_BUFFER_LENGTH>=bufferLength); - - for(i=0; irQmfData[i] = FDKsbrEnc_SliceRam_PsRqmf(hPsQmfData->rQmfData[0], dynamic_RAM, ch, i, nCols); - hPsQmfData->iQmfData[i] = FDKsbrEnc_SliceRam_PsIqmf(hPsQmfData->iQmfData[0], dynamic_RAM, ch, i, nCols); - } - - for(i=0; irQmfData[i], (sizeof(FIXP_QMF)*QMF_CHANNELS)); - FDKmemclear(hPsQmfData->iQmfData[i], (sizeof(FIXP_QMF)*QMF_CHANNELS)); - } - - return noError; -} - - -/* - name: static HANDLE_ERROR_INFO CreatePSChannel() - description: Creates PS channel struct - returns: error code of type HANDLE_ERROR_INFO - input: - HANDLE_PS_HYBRID_CONFIG hHybConfig: config structure for hybrid filter bank - output: - HANDLE_PS_CHANNEL_DATA *hPsChannelData -*/ -static HANDLE_ERROR_INFO CreatePSChannel(HANDLE_PS_CHANNEL_DATA *hPsChannelData, - INT ch - ) +/*--------------- function declarations --------------------*/ +static void psFindBestScaling( + HANDLE_PARAMETRIC_STEREO hParametricStereo, + FIXP_DBL *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2], + UCHAR *dynBandScale, + FIXP_QMF *maxBandValue, + SCHAR *dmxScale + ); + +/*------------- function definitions ----------------*/ +FDK_PSENC_ERROR PSEnc_Create( + HANDLE_PARAMETRIC_STEREO *phParametricStereo + ) { - HANDLE_ERROR_INFO error = noError; + FDK_PSENC_ERROR error = PSENC_OK; - (*hPsChannelData) = GetRam_PsChData(ch); - - if (*hPsChannelData==NULL) { - error = 1; - goto bail; + if (phParametricStereo==NULL) { + error = PSENC_INVALID_HANDLE; } - FDKmemclear(*hPsChannelData, sizeof(PS_CHANNEL_DATA)); + else { + int i; + HANDLE_PARAMETRIC_STEREO hParametricStereo = NULL; - - if (error == noError) { - if (noError != (error = FDKsbrEnc_CreateHybridFilterBank(&(*hPsChannelData)->hHybAna, - ch ))) - { + if (NULL==(hParametricStereo = GetRam_ParamStereo())) { + error = PSENC_MEMORY_ERROR; goto bail; } - } - if (error == noError) { - if (noError != (error = FDKsbrEnc_CreateHybridData( &((*hPsChannelData)->hHybData), - ch))) { - goto bail; - } - } - if(error == noError){ - if(noError != (error = CreatePSQmf(&((*hPsChannelData)->hPsQmfData), ch))) - { - goto bail; - } - } -bail: - return error; -} - -static HANDLE_ERROR_INFO InitPSChannel(HANDLE_PS_CHANNEL_DATA hPsChannelData, - HANDLE_PS_HYBRID_CONFIG hHybConfig, - INT noQmfSlots, - INT noQmfBands - ,INT ch, - UCHAR *dynamic_RAM - ) -{ - HANDLE_ERROR_INFO error = noError; - INT hybridFilterDelay = 0; - - if (error == noError) { - if (noError != (error = FDKsbrEnc_InitHybridFilterBank(hPsChannelData->hHybAna, - hHybConfig, - noQmfSlots ))) - { - error = handBack(error); - } - } + FDKmemclear(hParametricStereo, sizeof(PARAMETRIC_STEREO)); - if(error == noError){ - hybridFilterDelay = FDKsbrEnc_GetHybridFilterDelay(hPsChannelData->hHybAna); - hPsChannelData->psChannelDelay = hybridFilterDelay * noQmfBands; - } - - if (error == noError) { - if (noError != (error = FDKsbrEnc_InitHybridData( hPsChannelData->hHybData, - hHybConfig, - noQmfSlots))) - { - error = handBack(error); - } - } - - if(error == noError){ - if(noError != (error = InitPSQmf(hPsChannelData->hPsQmfData, - noQmfSlots, - noQmfBands, - hybridFilterDelay - ,ch, - dynamic_RAM - ))) - { - error = handBack(error); - } - } - - return error; -} - - -/* - name: static HANDLE_ERROR_INFO PSEnc_Create() - description: Creates PS struct - returns: error code of type HANDLE_ERROR_INFO - input: HANDLE_PSENC_CONFIG hPsEncConfig: configuration - output: HANDLE_PARAMETRIC_STEREO *hParametricStereo - -*/ -HANDLE_ERROR_INFO -PSEnc_Create(HANDLE_PARAMETRIC_STEREO *phParametricStereo) -{ - HANDLE_ERROR_INFO error = noError; - INT i; - HANDLE_PARAMETRIC_STEREO hParametricStereo = GetRam_ParamStereo(); - - if (hParametricStereo==NULL) { - error = 1; - goto bail; - } - - FDKmemclear(hParametricStereo,sizeof(PARAMETRIC_STEREO)); - - hParametricStereo->qmfDelayRealRef = GetRam_PsEnvRBuffer(0); - hParametricStereo->qmfDelayImagRef = GetRam_PsEnvIBuffer(0); - - if ( (hParametricStereo->qmfDelayRealRef==NULL) || (hParametricStereo->qmfDelayImagRef==NULL) ) { - error = 1; - goto bail; - } - - for (i = 0; i < (QMF_MAX_TIME_SLOTS>>1); i++) { - hParametricStereo->qmfDelayReal[i] = hParametricStereo->qmfDelayRealRef + (i*QMF_CHANNELS); - hParametricStereo->qmfDelayImag[i] = hParametricStereo->qmfDelayImagRef + (i*QMF_CHANNELS); - } - - for(i=0; ihPsChannelData[i], - i - ))) - { + if (PSENC_OK != (error = FDKsbrEnc_CreatePSEncode(&hParametricStereo->hPsEncode))) { goto bail; } - } - - if(noError != (error = FDKsbrEnc_CreatePSEncode(&hParametricStereo->hPsEncode))) { - error = 1; - goto bail; - } - - hParametricStereo->hHybridConfig = GetRam_PsHybConfig(); /* allocate memory */ + for (i=0; ifdkHybAnaFilter[i], + hParametricStereo->__staticHybAnaStatesLF[i], + sizeof(hParametricStereo->__staticHybAnaStatesLF[i]), + hParametricStereo->__staticHybAnaStatesHF[i], + sizeof(hParametricStereo->__staticHybAnaStatesHF[i]) + ) !=0 ) + { + error = PSENC_MEMORY_ERROR; + goto bail; + } + } - /* calc PS_OUT values and delay one frame ! */ - hParametricStereo->hPsOut[0] = GetRam_PsOut(0); - hParametricStereo->hPsOut[1] = GetRam_PsOut(1); - if ( (hParametricStereo->hHybridConfig==NULL) || (hParametricStereo->hPsOut[0]==NULL) || (hParametricStereo->hPsOut[1]==NULL) ) { - error = 1; - goto bail; + *phParametricStereo = hParametricStereo; /* return allocated handle */ } - bail: - *phParametricStereo = hParametricStereo; return error; } -HANDLE_ERROR_INFO -PSEnc_Init(HANDLE_PARAMETRIC_STEREO hParametricStereo, - HANDLE_PSENC_CONFIG hPsEncConfig, - INT noQmfSlots, - INT noQmfBands - ,UCHAR *dynamic_RAM - ) +FDK_PSENC_ERROR PSEnc_Init( + HANDLE_PARAMETRIC_STEREO hParametricStereo, + const HANDLE_PSENC_CONFIG hPsEncConfig, + INT noQmfSlots, + INT noQmfBands + ,UCHAR *dynamic_RAM + ) { - HANDLE_ERROR_INFO error = noError; - INT i; - INT tmpDelay = 0; + FDK_PSENC_ERROR error = PSENC_OK; - if(error == noError){ - if(hPsEncConfig == NULL){ - error = ERROR(CDI, "Invalid configuration handle."); - } + if ( (NULL==hParametricStereo) || (NULL==hPsEncConfig) ) { + error = PSENC_INVALID_HANDLE; } + else { + int ch, i; - hParametricStereo->initPS = 1; - hParametricStereo->noQmfSlots = noQmfSlots; - hParametricStereo->noQmfBands = noQmfBands; + hParametricStereo->initPS = 1; + hParametricStereo->noQmfSlots = noQmfSlots; + hParametricStereo->noQmfBands = noQmfBands; - for (i = 0; i < hParametricStereo->noQmfSlots>>1; i++) { - FDKmemclear( hParametricStereo->qmfDelayReal[i],QMF_CHANNELS*sizeof(FIXP_DBL)); - FDKmemclear( hParametricStereo->qmfDelayImag[i],QMF_CHANNELS*sizeof(FIXP_DBL)); - } - hParametricStereo->qmfDelayScale = FRACT_BITS-1; - - if(error == noError) { - PS_BANDS nHybridSubbands = (PS_BANDS)0; - - switch(hPsEncConfig->nStereoBands){ - case PSENC_STEREO_BANDS_10: - nHybridSubbands = PS_BANDS_COARSE; - break; - case PSENC_STEREO_BANDS_20: - nHybridSubbands = PS_BANDS_MID; - break; - case PSENC_STEREO_BANDS_34: - /* nHybridSubbands = PS_BANDS_FINE; */ - FDK_ASSERT(0); /* we don't support this mode! */ - break; - default: - nHybridSubbands = (PS_BANDS)0; - break; - } - /* create configuration for hybrid filter bank */ - FDKmemclear(hParametricStereo->hHybridConfig,sizeof(PS_HYBRID_CONFIG)); - if(noError != (error = FDKsbrEnc_CreateHybridConfig(&hParametricStereo->hHybridConfig, nHybridSubbands))) { - error = handBack(error); - } - } + /* clear delay lines */ + FDKmemclear(hParametricStereo->qmfDelayLines, sizeof(hParametricStereo->qmfDelayLines)); + hParametricStereo->qmfDelayScale = FRACT_BITS-1; - tmpDelay = 0; - for(i=0; ihPsChannelData[i], - hParametricStereo->hHybridConfig, - hParametricStereo->noQmfSlots, - hParametricStereo->noQmfBands - ,i, - dynamic_RAM - ))) - { - error = handBack(error); - } - } - - if(error == noError){ - /* sum up delay in samples for all channels (should be the same for all channels) */ - tmpDelay += hParametricStereo->hPsChannelData[i]->psChannelDelay; - } - } + /* create configuration for hybrid filter bank */ + for (ch=0; chfdkHybAnaFilter[ch], + THREE_TO_TEN, + QMF_CHANNELS, + QMF_CHANNELS, + 1 + ); + } /* ch */ + + FDKhybridSynthesisInit( + &hParametricStereo->fdkHybSynFilter, + THREE_TO_TEN, + QMF_CHANNELS, + QMF_CHANNELS + ); - if(error == noError){ /* determine average delay */ - hParametricStereo->psDelay = tmpDelay/MAX_PS_CHANNELS; - } + hParametricStereo->psDelay = (HYBRID_FILTER_DELAY*hParametricStereo->noQmfBands); - if(error == noError){ - if ( (hPsEncConfig->maxEnvelopes < PSENC_NENV_1) - || (hPsEncConfig->maxEnvelopes > PSENC_NENV_MAX) ) { + if ( (hPsEncConfig->maxEnvelopes < PSENC_NENV_1) || (hPsEncConfig->maxEnvelopes > PSENC_NENV_MAX) ) { hPsEncConfig->maxEnvelopes = PSENC_NENV_DEFAULT; } hParametricStereo->maxEnvelopes = hPsEncConfig->maxEnvelopes; - } - if(error == noError){ - if(noError != (error = FDKsbrEnc_InitPSEncode(hParametricStereo->hPsEncode, (PS_BANDS) hPsEncConfig->nStereoBands, hPsEncConfig->iidQuantErrorThreshold))){ - error = handBack(error); + if (PSENC_OK != (error = FDKsbrEnc_InitPSEncode(hParametricStereo->hPsEncode, (PS_BANDS) hPsEncConfig->nStereoBands, hPsEncConfig->iidQuantErrorThreshold))){ + goto bail; } - } - - /* clear buffer */ - FDKmemclear(hParametricStereo->hPsOut[0], sizeof(PS_OUT)); - FDKmemclear(hParametricStereo->hPsOut[1], sizeof(PS_OUT)); - - /* clear scaling buffer */ - FDKmemclear(hParametricStereo->dynBandScale, sizeof(UCHAR)*PS_MAX_BANDS); - FDKmemclear(hParametricStereo->maxBandValue, sizeof(FIXP_QMF)*PS_MAX_BANDS); - - return error; -} - - - -/* - name: static HANDLE_ERROR_INFO DestroyPSQmf - description: destroy PS qmf buffers - returns: error code of type HANDLE_ERROR_INFO - input: - HANDLE_PS_QMF_DATA *hPsQmfData - output: none -*/ - -static HANDLE_ERROR_INFO DestroyPSQmf(HANDLE_PS_QMF_DATA* phPsQmfData) -{ - HANDLE_PS_QMF_DATA hPsQmfData = *phPsQmfData; - - if(hPsQmfData) { - FreeRam_PsRqmf(hPsQmfData->rQmfData); - FreeRam_PsIqmf(hPsQmfData->iQmfData); - FreeRam_PsQmfData(phPsQmfData); - } - - return noError; -} - - - -/* - name: static HANDLE_ERROR_INFO DestroyPSChannel - description: destroy PS channel data - returns: error code of type HANDLE_ERROR_INFO - input: - HANDLE_PS_CHANNEL_DATA *hPsChannelDAta - output: none -*/ - - -static HANDLE_ERROR_INFO DestroyPSChannel(HANDLE_PS_CHANNEL_DATA *phPsChannelData){ - - HANDLE_ERROR_INFO error = noError; - HANDLE_PS_CHANNEL_DATA hPsChannelData = *phPsChannelData; - - if(hPsChannelData != NULL){ - - DestroyPSQmf(&hPsChannelData->hPsQmfData); - FDKsbrEnc_DeleteHybridFilterBank(&hPsChannelData->hHybAna); + for (ch = 0; chhHybData); - - FreeRam_PsChData(phPsChannelData); - } - - return error; -} - - -/* - name: static HANDLE_ERROR_INFO PSEnc_Destroy - description: destroy PS encoder handle - returns: error code of type HANDLE_ERROR_INFO - input: - HANDLE_PARAMETRIC_STEREO *hParametricStereo - output: none -*/ - -HANDLE_ERROR_INFO -PSEnc_Destroy(HANDLE_PARAMETRIC_STEREO *phParametricStereo){ - - HANDLE_ERROR_INFO error = noError; - HANDLE_PARAMETRIC_STEREO hParametricStereo = *phParametricStereo; - INT i; + for (i=0; ipHybridData[i+HYBRID_READ_OFFSET][ch][0] = &pDynReal[i*MAX_HYBRID_BANDS]; + hParametricStereo->pHybridData[i+HYBRID_READ_OFFSET][ch][1] = &pDynImag[i*MAX_HYBRID_BANDS];; + } - if(hParametricStereo != NULL){ - for(i=0; ihPsChannelData[i])); - } - FreeRam_PsEnvRBuffer(&hParametricStereo->qmfDelayRealRef); - FreeRam_PsEnvIBuffer(&hParametricStereo->qmfDelayImagRef); + for (i=0; ipHybridData[i][ch][0] = hParametricStereo->__staticHybridData[i][ch][0]; + hParametricStereo->pHybridData[i][ch][1] = hParametricStereo->__staticHybridData[i][ch][1]; + } + } /* ch */ - FDKsbrEnc_DestroyPSEncode(&hParametricStereo->hPsEncode); + /* clear static hybrid buffer */ + FDKmemclear(hParametricStereo->__staticHybridData, sizeof(hParametricStereo->__staticHybridData)); - FreeRam_PsOut(&hParametricStereo->hPsOut[0]); - FreeRam_PsOut(&hParametricStereo->hPsOut[1]); + /* clear bs buffer */ + FDKmemclear(hParametricStereo->psOut, sizeof(hParametricStereo->psOut)); - FreeRam_PsHybConfig(&hParametricStereo->hHybridConfig); - FreeRam_ParamStereo(phParametricStereo); - } + /* clear scaling buffer */ + FDKmemclear(hParametricStereo->dynBandScale, sizeof(UCHAR)*PS_MAX_BANDS); + FDKmemclear(hParametricStereo->maxBandValue, sizeof(FIXP_QMF)*PS_MAX_BANDS); + } /* valid handle */ +bail: return error; } -/* - name: static HANDLE_ERROR_INFO UpdatePSQmfData - description: updates buffer containing qmf data first/second halve - returns: error code of type HANDLE_ERROR_INFO - input: - HANDLE_PARAMETRIC_STEREO hParametricStereo - output: - HANDLE_PARAMETRIC_STEREO hParametricStereo with updated qmf data -*/ -static HANDLE_ERROR_INFO -UpdatePSQmfData_first(HANDLE_PARAMETRIC_STEREO hParametricStereo) +FDK_PSENC_ERROR PSEnc_Destroy( + HANDLE_PARAMETRIC_STEREO *phParametricStereo + ) { - HANDLE_ERROR_INFO error = noError; - int i, ch; - for (ch=0; chhPsChannelData[ch]->hPsQmfData->rQmfData + QMF_READ_OFFSET; - FIXP_QMF **RESTRICT imagQmfData = hParametricStereo->hPsChannelData[ch]->hPsQmfData->iQmfData + QMF_READ_OFFSET; - - /* get needed parameters */ - INT nCols = hParametricStereo->hPsChannelData[ch]->hPsQmfData->nCols; - INT nRows = hParametricStereo->hPsChannelData[ch]->hPsQmfData->nRows; - - /* move processed buffer data nCols qmf samples forward */ - for(i=0; ihPsChannelData[ch]->hPsQmfData->rQmfData + QMF_READ_OFFSET; - FIXP_QMF **RESTRICT imagQmfData = hParametricStereo->hPsChannelData[ch]->hPsQmfData->iQmfData + QMF_READ_OFFSET; - - /* get needed parameters */ - INT writeOffset = hParametricStereo->hPsChannelData[ch]->hPsQmfData->bufferWriteOffset; - INT nCols = hParametricStereo->hPsChannelData[ch]->hPsQmfData->nCols; - INT nRows = hParametricStereo->hPsChannelData[ch]->hPsQmfData->nRows; - - /* move processed buffer data nCols qmf samples forward */ - for(i=HYBRID_READ_OFFSET; ihPsEncode); + FreeRam_ParamStereo(phParametricStereo); } } return error; } - - -/* - name: static HANDLE_ERROR_INFO UpdatePSHybridData - description: updates buffer containg PS hybrid data - returns: error code of type HANDLE_ERROR_INFO - input: - HANDLE_PARAMETRIC_STEREO hParametricStereo - output: - HANDLE_PARAMETRIC_STEREO hParametricStereo with updated hybrid data -*/ - -static HANDLE_ERROR_INFO UpdatePSHybridData(HANDLE_PARAMETRIC_STEREO hParametricStereo) +static FDK_PSENC_ERROR ExtractPSParameters( + HANDLE_PARAMETRIC_STEREO hParametricStereo, + const int sendHeader, + FIXP_DBL *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2] + ) { - INT i, ch; - - for (ch=0; chhPsChannelData[ch]->hHybData; - FIXP_QMF **realHybridData = hHybData->rHybData + HYBRID_DATA_READ_OFFSET; - FIXP_QMF **imagHybridData = hHybData->iHybData + HYBRID_DATA_READ_OFFSET; - INT writeOffset = hHybData->hybDataWriteOffset; - INT frameSize = hHybData->frameSize; - - for(i=0; iinitPS){ + hParametricStereo->psOut[1] = hParametricStereo->psOut[0]; + } + hParametricStereo->psOut[0] = hParametricStereo->psOut[1]; + + if (PSENC_OK != (error = FDKsbrEnc_PSEncode( + hParametricStereo->hPsEncode, + &hParametricStereo->psOut[1], + hParametricStereo->dynBandScale, + hParametricStereo->maxEnvelopes, + hybridData, + hParametricStereo->noQmfSlots, + sendHeader))) + { + goto bail; } - } - /* call ps encode function */ - if(error == noError){ - if (hParametricStereo->initPS){ - *hParametricStereo->hPsOut[1] = *hParametricStereo->hPsOut[0]; - } - *hParametricStereo->hPsOut[0] = *hParametricStereo->hPsOut[1]; - - if(noError != (error = FDKsbrEnc_PSEncode(hParametricStereo->hPsEncode, - hParametricStereo->hPsOut[1], - hParametricStereo->hPsChannelData[0], - hParametricStereo->hPsChannelData[1], - hParametricStereo->dynBandScale, - hParametricStereo->maxEnvelopes, - sendHeader))){ - error = handBack(error); + if (hParametricStereo->initPS) { + hParametricStereo->psOut[0] = hParametricStereo->psOut[1]; + hParametricStereo->initPS = 0; } - if (hParametricStereo->initPS){ - *hParametricStereo->hPsOut[0] = *hParametricStereo->hPsOut[1]; - hParametricStereo->initPS = 0; - } } - +bail: return error; } -/* - name: static HANDLE_ERROR_INFO DownmixPSQmfData - description: energy weighted downmix and hybrid synthesis - returns: error code of type HANDLE_ERROR_INFO - input: - HANDLE_PARAMETRIC_STEREO hParametricStereo containing left and right channel qmf data - output: - HANDLE_PARAMETRIC_STEREO with updated qmf data buffer, hybrid data buffer - - FIXP_QMF **mixRealQmfData: pointer to buffer containing downmixed (real) qmf data - - FIXP_QMF **mixImagQmfData: pointer to buffer containing downmixed (imag) qmf data -*/ - -static HANDLE_ERROR_INFO -DownmixPSQmfData(HANDLE_PARAMETRIC_STEREO hParametricStereo, FIXP_QMF **RESTRICT mixRealQmfData, - FIXP_QMF **RESTRICT mixImagQmfData, SCHAR *downmixScale) +static FDK_PSENC_ERROR DownmixPSQmfData( + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_QMF_FILTER_BANK sbrSynthQmf, + FIXP_QMF **RESTRICT mixRealQmfData, + FIXP_QMF **RESTRICT mixImagQmfData, + INT_PCM *downsampledOutSignal, + FIXP_DBL *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2], + const INT noQmfSlots, + const INT psQmfScale[MAX_PS_CHANNELS], + SCHAR *qmfScale + ) { - HANDLE_ERROR_INFO error = noError; - int n, k; - int dynQmfScale, adjQmfScale; - int nQmfSamples=0, nQmfBands=0, nHybridQmfBands=0; - FIXP_QMF **RESTRICT leftRealQmfData = NULL; - FIXP_QMF **RESTRICT leftImagQmfData = NULL; - FIXP_QMF **RESTRICT rightRealQmfData = NULL; - FIXP_QMF **RESTRICT rightImagQmfData = NULL; - FIXP_QMF **RESTRICT leftRealHybridQmfData = NULL; - FIXP_QMF **RESTRICT leftImagHybridQmfData = NULL; - FIXP_QMF **RESTRICT rightRealHybridQmfData = NULL; - FIXP_QMF **RESTRICT rightImagHybridQmfData = NULL; + FDK_PSENC_ERROR error = PSENC_OK; if(hParametricStereo == NULL){ - error = ERROR(CDI, "Invalid handle hParametricStereo."); - } - - if(error == noError){ - /* Update first part of qmf buffers... - no whole buffer update possible; downmix is inplace */ - if(noError != (error = UpdatePSQmfData_first(hParametricStereo))){ - error = handBack(error); - } + error = PSENC_INVALID_HANDLE; } - - if(error == noError){ - /* get buffers: synchronize QMF buffers and hybrid buffers to compensate hybrid filter delay */ - /* hybrid filter bank looks nHybridFilterDelay qmf samples forward */ - leftRealQmfData = hParametricStereo->hPsChannelData[0]->hPsQmfData->rQmfData + HYBRID_READ_OFFSET; - leftImagQmfData = hParametricStereo->hPsChannelData[0]->hPsQmfData->iQmfData + HYBRID_READ_OFFSET; - rightRealQmfData = hParametricStereo->hPsChannelData[1]->hPsQmfData->rQmfData + HYBRID_READ_OFFSET; - rightImagQmfData = hParametricStereo->hPsChannelData[1]->hPsQmfData->iQmfData + HYBRID_READ_OFFSET; - - leftRealHybridQmfData = hParametricStereo->hPsChannelData[0]->hHybData->rHybData + HYBRID_WRITE_OFFSET; - leftImagHybridQmfData = hParametricStereo->hPsChannelData[0]->hHybData->iHybData + HYBRID_WRITE_OFFSET; - rightRealHybridQmfData = hParametricStereo->hPsChannelData[1]->hHybData->rHybData + HYBRID_WRITE_OFFSET; - rightImagHybridQmfData = hParametricStereo->hPsChannelData[1]->hHybData->iHybData + HYBRID_WRITE_OFFSET; - - /* get number of needed parameters */ - nQmfSamples = hParametricStereo->hPsChannelData[0]->hPsQmfData->nCols; - nQmfBands = hParametricStereo->hPsChannelData[0]->hPsQmfData->nRows; - nHybridQmfBands = FDKsbrEnc_GetNumberHybridQmfBands(hParametricStereo->hPsChannelData[0]->hHybData); + else { + int n, k; + C_ALLOC_SCRATCH_START(pWorkBuffer, FIXP_QMF, QMF_CHANNELS*2); /* define scalings */ - adjQmfScale = hParametricStereo->hPsChannelData[0]->hHybData->sf_fixpHybrid - - hParametricStereo->hPsChannelData[0]->psQmfScale; - - dynQmfScale = fixMax(0, hParametricStereo->dmxScale-1); /* scale one bit more for addition of left and right */ - - *downmixScale = hParametricStereo->hPsChannelData[0]->hHybData->sf_fixpHybrid - dynQmfScale + 1; - - const FIXP_DBL maxStereoScaleFactor = FL2FXCONST_DBL(2.0f/2.f); + int dynQmfScale = fixMax(0, hParametricStereo->dmxScale-1); /* scale one bit more for addition of left and right */ + int downmixScale = psQmfScale[0] - dynQmfScale; + const FIXP_DBL maxStereoScaleFactor = MAXVAL_DBL; /* 2.f/2.f */ - for(n = 0; nhPsChannelData[0]->hHybData, k); - } else { - /* process qmf data */ - nHybridSubBands = 1; - } - - tmpMixReal = FL2FXCONST_DBL(0.f); - tmpMixImag = FL2FXCONST_DBL(0.f); - - for(l=0; l>dynScale; - tmpMixImag += fMultDiv2(stereoScaleFactor, (FIXP_QMF)(tmpLeftImag + tmpRightImag))>>dynScale; - } + /* write data to hybrid output */ + tmpHybrid[0][k] = fMultDiv2(stereoScaleFactor, (FIXP_QMF)(tmpLeftReal + tmpRightReal))>>dynScale; + tmpHybrid[1][k] = fMultDiv2(stereoScaleFactor, (FIXP_QMF)(tmpLeftImag + tmpRightImag))>>dynScale; - mixRealQmfData[n][k] = tmpMixReal; - mixImagQmfData[n][k] = tmpMixImag; + } /* hybrid bands - k */ - hybridDataOffset += nHybridSubBands; - } - } - } /* if(error == noError) */ + FDKhybridSynthesisApply( + &hParametricStereo->fdkHybSynFilter, + tmpHybrid[0], + tmpHybrid[1], + mixRealQmfData[n], + mixImagQmfData[n]); + qmfSynthesisFilteringSlot( + sbrSynthQmf, + mixRealQmfData[n], + mixImagQmfData[n], + downmixScale-7, + downmixScale-7, + downsampledOutSignal+(n*sbrSynthQmf->no_channels), + 1, + pWorkBuffer); - if(error == noError){ - /* ... and update the hybrid data */ - if(noError != (error = UpdatePSHybridData(hParametricStereo))){ - error = handBack(error); - } - } + } /* slots */ - return error; -} + *qmfScale = -downmixScale + 7; + C_ALLOC_SCRATCH_END(pWorkBuffer, FIXP_QMF, QMF_CHANNELS*2); -/* - name: INT FDKsbrEnc_PSEnc_WritePSData() - description: writes ps_data() element to bitstream (hBitstream), returns number of written bits; - returns number of written bits only, if hBitstream == NULL - returns: number of bits in ps_data() - input: - HANDLE_PARAMETRIC_STEREO hParametricStereo containing extracted ps parameters - output: - HANDLE_FDK_BITSTREAM containing ps_data() element -*/ -INT -FDKsbrEnc_PSEnc_WritePSData(HANDLE_PARAMETRIC_STEREO hParametricStereo, HANDLE_FDK_BITSTREAM hBitstream) -{ - - INT nBitsWritten = 0; + { + const INT noQmfSlots2 = hParametricStereo->noQmfSlots>>1; + const int noQmfBands = hParametricStereo->noQmfBands; - if(hParametricStereo != NULL){ - nBitsWritten = FDKsbrEnc_WritePSBitstream(hParametricStereo->hPsOut[0], hBitstream); - } + INT scale, i, j, slotOffset; - return nBitsWritten; -} + FIXP_QMF tmp[2][QMF_CHANNELS]; + for (i=0; iqmfDelayLines[0][i], noQmfBands*sizeof(FIXP_QMF)); + FDKmemcpy(tmp[1], hParametricStereo->qmfDelayLines[1][i], noQmfBands*sizeof(FIXP_QMF)); -/* - name: static HANDLE_ERROR_INFO PSHybridAnalysis() - description: hybrid analysis filter bank of lowest qmf banks - returns: error code of type HANDLE_ERROR_INFO - input: - HANDLE_PARAMETRIC_STEREO hParametricStereo containing qmf samples - output: - HANDLE_PARAMETRIC STEREO hParametricStereo also containing hybrid data -*/ + FDKmemcpy(hParametricStereo->qmfDelayLines[0][i], mixRealQmfData[i+noQmfSlots2], noQmfBands*sizeof(FIXP_QMF)); + FDKmemcpy(hParametricStereo->qmfDelayLines[1][i], mixImagQmfData[i+noQmfSlots2], noQmfBands*sizeof(FIXP_QMF)); -static HANDLE_ERROR_INFO -PSHybridAnalysis(HANDLE_PARAMETRIC_STEREO hParametricStereo){ + FDKmemcpy(mixRealQmfData[i+noQmfSlots2], mixRealQmfData[i], noQmfBands*sizeof(FIXP_QMF)); + FDKmemcpy(mixImagQmfData[i+noQmfSlots2], mixImagQmfData[i], noQmfBands*sizeof(FIXP_QMF)); - HANDLE_ERROR_INFO error = noError; - int ch; + FDKmemcpy(mixRealQmfData[i], tmp[0], noQmfBands*sizeof(FIXP_QMF)); + FDKmemcpy(mixImagQmfData[i], tmp[1], noQmfBands*sizeof(FIXP_QMF)); + } - if(hParametricStereo == NULL){ - error = ERROR(CDI, "Invalid handle hParametricStereo."); - } + if (hParametricStereo->qmfDelayScale > *qmfScale) { + scale = hParametricStereo->qmfDelayScale - *qmfScale; + slotOffset = 0; + } + else { + scale = *qmfScale - hParametricStereo->qmfDelayScale; + slotOffset = noQmfSlots2; + } - for (ch=0; chhPsChannelData[ch]->hHybAna, - hParametricStereo->hPsChannelData[ch]->hPsQmfData->rQmfData + HYBRID_READ_OFFSET, - hParametricStereo->hPsChannelData[ch]->hPsQmfData->iQmfData + HYBRID_READ_OFFSET, - hParametricStereo->hPsChannelData[ch]->psQmfScale, - hParametricStereo->hPsChannelData[ch]->hHybData->rHybData + HYBRID_WRITE_OFFSET, - hParametricStereo->hPsChannelData[ch]->hHybData->iHybData + HYBRID_WRITE_OFFSET, - &hParametricStereo->hPsChannelData[ch]->hHybData->sf_fixpHybrid))){ - error = handBack(error); + for (i=0; i>= scale; + mixImagQmfData[i+slotOffset][j] >>= scale; } } + + scale = *qmfScale; + *qmfScale = FDKmin(*qmfScale, hParametricStereo->qmfDelayScale); + hParametricStereo->qmfDelayScale = scale; } + } /* valid handle */ + return error; } -/* - name: HANDLE_ERROR_INFO FDKsbrEnc_PSEnc_ParametricStereoProcessing - description: Complete PS Processing: - qmf + hybrid analysis of time domain data (left and right channel), - PS parameter extraction - downmix of qmf data - returns: error code of type HANDLE_ERROR_INFO - input: - HANDLE_PARAMETRIC_STEREO hParametricStereo - output: - HANDLE_PARAMETRIC STEREO hParametricStereo containing extracted PS parameters - - FIXP_DBL **qmfDataReal: Pointer to buffer containing downmixed, real qmf data - - FIXP_DBL **qmfDataImag: Pointer to buffer containing downmixed, imag qmf data - - INT_PCM **downsampledOutSignal: Pointer to buffer containing downmixed time signal - - SCHAR *qmfScale: Updated scale value for the QMF downmix data - -*/ - -HANDLE_ERROR_INFO -FDKsbrEnc_PSEnc_ParametricStereoProcessing(HANDLE_PARAMETRIC_STEREO hParametricStereo, - FIXP_QMF **RESTRICT qmfDataReal, - FIXP_QMF **RESTRICT qmfDataImag, - INT qmfOffset, - INT_PCM *downsampledOutSignal, - HANDLE_QMF_FILTER_BANK sbrSynthQmf, - SCHAR *qmfScale, - const int sendHeader) + +INT FDKsbrEnc_PSEnc_WritePSData( + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_FDK_BITSTREAM hBitstream + ) { - HANDLE_ERROR_INFO error = noError; - FIXP_QMF **downmixedRealQmfData = qmfDataReal+qmfOffset; - FIXP_QMF **downmixedImagQmfData = qmfDataImag+qmfOffset; - SCHAR dmScale = 0; - INT noQmfBands = hParametricStereo->noQmfBands; + return ( (hParametricStereo!=NULL) ? FDKsbrEnc_WritePSBitstream(&hParametricStereo->psOut[0], hBitstream) : 0 ); +} - if (error == noError) { - /* do ps hybrid analysis */ - if(noError != (error = PSHybridAnalysis(hParametricStereo))){ - error = handBack(error); - } - } - - /* find best scaling in new QMF and Hybrid data */ - psFindBestScaling( hParametricStereo, - hParametricStereo->dynBandScale, - hParametricStereo->maxBandValue, - &hParametricStereo->dmxScale ) ; +FDK_PSENC_ERROR FDKsbrEnc_PSEnc_ParametricStereoProcessing( + HANDLE_PARAMETRIC_STEREO hParametricStereo, + INT_PCM *samples[2], + UINT timeInStride, + QMF_FILTER_BANK **hQmfAnalysis, + FIXP_QMF **RESTRICT downmixedRealQmfData, + FIXP_QMF **RESTRICT downmixedImagQmfData, + INT_PCM *downsampledOutSignal, + HANDLE_QMF_FILTER_BANK sbrSynthQmf, + SCHAR *qmfScale, + const int sendHeader + ) +{ + FDK_PSENC_ERROR error = PSENC_OK; + INT noQmfBands = hParametricStereo->noQmfBands; + INT psQmfScale[MAX_PS_CHANNELS] = {0}; + int psCh, i; + C_ALLOC_SCRATCH_START(pWorkBuffer, FIXP_DBL, QMF_CHANNELS*4); + for (psCh = 0; psChno_col; i++) { - if(error == noError){ - /* downmix and hybrid synthesis */ - if(noError != (error = DownmixPSQmfData(hParametricStereo, downmixedRealQmfData, downmixedImagQmfData, &dmScale))){ - error = handBack(error); - } - } + qmfAnalysisFilteringSlot( + hQmfAnalysis[psCh], + &pWorkBuffer[2*QMF_CHANNELS], /* qmfReal[QMF_CHANNELS] */ + &pWorkBuffer[3*QMF_CHANNELS], /* qmfImag[QMF_CHANNELS] */ + samples[psCh]+i*(hQmfAnalysis[psCh]->no_channels*timeInStride), + timeInStride, + &pWorkBuffer[0*QMF_CHANNELS] /* qmf workbuffer 2*QMF_CHANNELS */ + ); + FDKhybridAnalysisApply( + &hParametricStereo->fdkHybAnaFilter[psCh], + &pWorkBuffer[2*QMF_CHANNELS], /* qmfReal[QMF_CHANNELS] */ + &pWorkBuffer[3*QMF_CHANNELS], /* qmfImag[QMF_CHANNELS] */ + hParametricStereo->pHybridData[i+HYBRID_READ_OFFSET][psCh][0], + hParametricStereo->pHybridData[i+HYBRID_READ_OFFSET][psCh][1] + ); - if (error == noError) - { - C_ALLOC_SCRATCH_START(qmfWorkBuffer, FIXP_DBL, QMF_CHANNELS*2); - /* + } /* no_col loop i */ - QMF synthesis including downsampling + psQmfScale[psCh] = hQmfAnalysis[psCh]->outScalefactor; - */ - QMF_SCALE_FACTOR tmpScale; - int scale = -dmScale; - tmpScale.lb_scale = scale; - tmpScale.ov_lb_scale = scale; - tmpScale.hb_scale = scale; - tmpScale.ov_hb_scale = 0; + } /* for psCh */ - qmfSynthesisFiltering( sbrSynthQmf, - downmixedRealQmfData, - downmixedImagQmfData, - &tmpScale, - 0, - downsampledOutSignal, - 1, - qmfWorkBuffer ); + C_ALLOC_SCRATCH_END(pWorkBuffer, FIXP_DBL, QMF_CHANNELS*4); - C_ALLOC_SCRATCH_END(qmfWorkBuffer, FIXP_DBL, QMF_CHANNELS*2); + /* find best scaling in new QMF and Hybrid data */ + psFindBestScaling( hParametricStereo, + &hParametricStereo->pHybridData[HYBRID_READ_OFFSET], + hParametricStereo->dynBandScale, + hParametricStereo->maxBandValue, + &hParametricStereo->dmxScale ) ; + /* extract the ps parameters */ + if(PSENC_OK != (error = ExtractPSParameters(hParametricStereo, sendHeader, &hParametricStereo->pHybridData[0]))){ + goto bail; } - /* scaling in sbr module differs -> scaling update */ - *qmfScale = -dmScale + 7; - - - /* - * Do PS to SBR QMF data transfer/scaling buffer shifting, delay lines etc. - */ - { - INT noQmfSlots2 = hParametricStereo->noQmfSlots>>1; - - FIXP_QMF r_tmp1; - FIXP_QMF i_tmp1; - FIXP_QMF **delayQmfReal = hParametricStereo->qmfDelayReal; - FIXP_QMF **delayQmfImag = hParametricStereo->qmfDelayImag; - INT scale, i, j; - - if (hParametricStereo->qmfDelayScale > *qmfScale) { - scale = hParametricStereo->qmfDelayScale - *qmfScale; + /* save hybrid date for next frame */ + for (i=0; ipHybridData[i][0][0], hParametricStereo->pHybridData[HYBRID_FRAMESIZE+i][0][0], MAX_HYBRID_BANDS*sizeof(FIXP_DBL)); /* left, real */ + FDKmemcpy(hParametricStereo->pHybridData[i][0][1], hParametricStereo->pHybridData[HYBRID_FRAMESIZE+i][0][1], MAX_HYBRID_BANDS*sizeof(FIXP_DBL)); /* left, imag */ + FDKmemcpy(hParametricStereo->pHybridData[i][1][0], hParametricStereo->pHybridData[HYBRID_FRAMESIZE+i][1][0], MAX_HYBRID_BANDS*sizeof(FIXP_DBL)); /* right, real */ + FDKmemcpy(hParametricStereo->pHybridData[i][1][1], hParametricStereo->pHybridData[HYBRID_FRAMESIZE+i][1][1], MAX_HYBRID_BANDS*sizeof(FIXP_DBL)); /* right, imag */ + } - for (i=0; i> scale; - qmfDataImag[i][j] = delayQmfImag[i][j] >> scale; - delayQmfReal[i][j] = qmfDataReal[i+noQmfSlots2][j]; - delayQmfImag[i][j] = qmfDataImag[i+noQmfSlots2][j]; - qmfDataReal[i+noQmfSlots2][j] = r_tmp1; - qmfDataImag[i+noQmfSlots2][j] = i_tmp1; - } - } - hParametricStereo->qmfDelayScale = *qmfScale; - } - else { - scale = *qmfScale - hParametricStereo->qmfDelayScale; - for (i=0; i> scale; - qmfDataImag[i+noQmfSlots2][j] = i_tmp1 >> scale; - } - } - scale = *qmfScale; - *qmfScale = hParametricStereo->qmfDelayScale; - hParametricStereo->qmfDelayScale = scale; - } + /* downmix and hybrid synthesis */ + if (PSENC_OK != (error = DownmixPSQmfData(hParametricStereo, sbrSynthQmf, downmixedRealQmfData, downmixedImagQmfData, downsampledOutSignal, &hParametricStereo->pHybridData[HYBRID_READ_OFFSET], hParametricStereo->noQmfSlots, psQmfScale, qmfScale))) { + goto bail; } +bail: + return error; } -static void psFindBestScaling(HANDLE_PARAMETRIC_STEREO hParametricStereo, - UCHAR *RESTRICT dynBandScale, - FIXP_QMF *RESTRICT maxBandValue, - SCHAR *RESTRICT dmxScale) +static void psFindBestScaling( + HANDLE_PARAMETRIC_STEREO hParametricStereo, + FIXP_DBL *hybridData[HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2], + UCHAR *dynBandScale, + FIXP_QMF *maxBandValue, + SCHAR *dmxScale + ) { HANDLE_PS_ENCODE hPsEncode = hParametricStereo->hPsEncode; - HANDLE_PS_HYBRID_DATA hHybDatal = hParametricStereo->hPsChannelData[0]->hHybData; - - INT group, bin, border, col, band; - INT frameSize = FDKsbrEnc_GetHybridFrameSize(hHybDatal); /* same as FDKsbrEnc_GetHybridFrameSize(hHybDatar) */ - INT psBands = (INT) hPsEncode->psEncMode; - INT nIidGroups = hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups; - - FIXP_QMF **lr = hParametricStereo->hPsChannelData[0]->hHybData->rHybData; - FIXP_QMF **li = hParametricStereo->hPsChannelData[0]->hHybData->iHybData; - FIXP_QMF **rr = hParametricStereo->hPsChannelData[1]->hHybData->rHybData; - FIXP_QMF **ri = hParametricStereo->hPsChannelData[1]->hHybData->iHybData; - FIXP_QMF **lrBuffer = hParametricStereo->hPsChannelData[0]->hPsQmfData->rQmfData; - FIXP_QMF **liBuffer = hParametricStereo->hPsChannelData[0]->hPsQmfData->iQmfData; - FIXP_QMF **rrBuffer = hParametricStereo->hPsChannelData[1]->hPsQmfData->rQmfData; - FIXP_QMF **riBuffer = hParametricStereo->hPsChannelData[1]->hPsQmfData->iQmfData; + + INT group, bin, col, band; + const INT frameSize = hParametricStereo->noQmfSlots; + const INT psBands = (INT) hPsEncode->psEncMode; + const INT nIidGroups = hPsEncode->nQmfIidGroups + hPsEncode->nSubQmfIidGroups; /* group wise scaling */ FIXP_QMF maxVal [2][PS_MAX_BANDS]; FIXP_QMF maxValue = FL2FXCONST_DBL(0.f); - INT nHybridQmfOffset = 0; - - UCHAR switched = 0; - FDKmemclear(maxVal, sizeof(maxVal)); /* start with hybrid data */ @@ -1004,53 +502,32 @@ static void psFindBestScaling(HANDLE_PARAMETRIC_STEREO hParametricStereo, /* Translate group to bin */ bin = hPsEncode->subband2parameterIndex[group]; - if (!switched && group == hPsEncode->nSubQmfIidGroups) { - /* switch to qmf data */ - lr = lrBuffer; li = liBuffer; - rr = rrBuffer; ri = riBuffer; - - /* calc offset between hybrid subsubbands and qmf bands */ - nHybridQmfOffset = FDKsbrEnc_GetNumberHybridQmfBands(hHybDatal) - FDKsbrEnc_GetNumberHybridBands(hHybDatal); - switched = 1; - } - /* Translate from 20 bins to 10 bins */ if (hPsEncode->psEncMode == PS_BANDS_COARSE) { bin >>= 1; } - /* determine group border */ - border = hPsEncode->iidGroupBorders[group+1]; - /* QMF downmix scaling */ { FIXP_QMF tmp = maxVal[0][bin]; int i; - for (col=HYBRID_READ_OFFSET; coliidGroupBorders[group] + nHybridQmfOffset]; - FIXP_QMF *pLI = &li[col][hPsEncode->iidGroupBorders[group] + nHybridQmfOffset]; - FIXP_QMF *pRR = &rr[col][hPsEncode->iidGroupBorders[group] + nHybridQmfOffset]; - FIXP_QMF *pRI = &ri[col][hPsEncode->iidGroupBorders[group] + nHybridQmfOffset]; - for (i = 0; iiidGroupBorders[group]; i++) { - tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(*pLR++)); - tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(*pLI++)); - tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(*pRR++)); - tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(*pRI++)); + for (col=0; coliidGroupBorders[group]; i < hPsEncode->iidGroupBorders[group+1]; i++) { + tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(hybridData[col][0][0][i])); + tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(hybridData[col][0][1][i])); + tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(hybridData[col][1][0][i])); + tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(hybridData[col][1][1][i])); } } maxVal[0][bin] = tmp; tmp = maxVal[1][bin]; - for (col=frameSize; coliidGroupBorders[group] + nHybridQmfOffset]; - FIXP_QMF *pLI = &li[col][hPsEncode->iidGroupBorders[group] + nHybridQmfOffset]; - FIXP_QMF *pRR = &rr[col][hPsEncode->iidGroupBorders[group] + nHybridQmfOffset]; - FIXP_QMF *pRI = &ri[col][hPsEncode->iidGroupBorders[group] + nHybridQmfOffset]; - for (i = 0; iiidGroupBorders[group]; i++) { - tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(*pLR++)); - tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(*pLI++)); - tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(*pRR++)); - tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(*pRI++)); + for (col=frameSize-HYBRID_READ_OFFSET; coliidGroupBorders[group]; i < hPsEncode->iidGroupBorders[group+1]; i++) { + tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(hybridData[col][0][0][i])); + tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(hybridData[col][0][1][i])); + tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(hybridData[col][1][0][i])); + tmp = fixMax(tmp, (FIXP_QMF)fixp_abs(hybridData[col][1][1][i])); } } maxVal[1][bin] = tmp; diff --git a/libSBRenc/src/ps_main.h b/libSBRenc/src/ps_main.h index b2fac92..4833fe0 100644 --- a/libSBRenc/src/ps_main.h +++ b/libSBRenc/src/ps_main.h @@ -30,74 +30,49 @@ /* Includes ******************************************************************/ #include "sbr_def.h" -#include "psenc_hybrid.h" +#include "qmf.h" #include "ps_encode.h" #include "FDK_bitstream.h" +#include "FDK_hybrid.h" + /* Data Types ****************************************************************/ typedef enum { PSENC_STEREO_BANDS_INVALID = 0, - PSENC_STEREO_BANDS_10 = 10, - PSENC_STEREO_BANDS_20 = 20, - PSENC_STEREO_BANDS_34 = 34 + PSENC_STEREO_BANDS_10 = 10, + PSENC_STEREO_BANDS_20 = 20 + } PSENC_STEREO_BANDS_CONFIG; typedef enum { - PSENC_NENV_1 = 1, - PSENC_NENV_2 = 2, - PSENC_NENV_4 = 4, - PSENC_NENV_DEFAULT = PSENC_NENV_2, - PSENC_NENV_MAX = PSENC_NENV_4 -} PSENC_NENV_CONFIG; + PSENC_NENV_1 = 1, + PSENC_NENV_2 = 2, + PSENC_NENV_4 = 4, + PSENC_NENV_DEFAULT = PSENC_NENV_2, + PSENC_NENV_MAX = PSENC_NENV_4 -#define MAX_PS_CHANNELS ( 2 ) -#define PSENC_QMF_BUFFER_LENGTH ( 48 ) +} PSENC_NENV_CONFIG; typedef struct { - - UINT bitrateFrom; /* inclusive */ - UINT bitrateTo; /* exclusive */ - PSENC_STEREO_BANDS_CONFIG nStereoBands; - PSENC_NENV_CONFIG nEnvelopes; - LONG iidQuantErrorThreshold; /* quantization threshold to switch between coarse and fine iid quantization */ + UINT bitrateFrom; /* inclusive */ + UINT bitrateTo; /* exclusive */ + PSENC_STEREO_BANDS_CONFIG nStereoBands; + PSENC_NENV_CONFIG nEnvelopes; + LONG iidQuantErrorThreshold; /* quantization threshold to switch between coarse and fine iid quantization */ } psTuningTable_t; /* Function / Class Declarations *********************************************/ -typedef struct T_PS_QMF_DATA -{ - FIXP_QMF *rQmfData[PSENC_QMF_BUFFER_LENGTH]; - FIXP_QMF *iQmfData[PSENC_QMF_BUFFER_LENGTH]; - INT nCols; - INT nRows; - INT bufferReadOffset; - INT bufferReadOffsetHybrid; - INT bufferWriteOffset; - INT bufferLength; -} PS_QMF_DATA, *HANDLE_PS_QMF_DATA; - -typedef struct T_PS_CHANNEL_DATA { - HANDLE_PS_QMF_DATA hPsQmfData; - - int psQmfScale; - HANDLE_PS_HYBRID_DATA hHybData; - HANDLE_PS_HYBRID hHybAna; - INT psChannelDelay; /* delay in samples */ -} PS_CHANNEL_DATA, *HANDLE_PS_CHANNEL_DATA; - typedef struct T_PARAMETRIC_STEREO { - - HANDLE_PS_HYBRID_CONFIG hHybridConfig; - HANDLE_PS_CHANNEL_DATA hPsChannelData[MAX_PS_CHANNELS]; HANDLE_PS_ENCODE hPsEncode; - HANDLE_PS_OUT hPsOut[2]; + PS_OUT psOut[2]; - FIXP_QMF *qmfDelayReal[QMF_MAX_TIME_SLOTS>>1]; - FIXP_QMF *qmfDelayImag[QMF_MAX_TIME_SLOTS>>1]; - FIXP_QMF *qmfDelayRealRef; - FIXP_QMF *qmfDelayImagRef; - int qmfDelayScale; + FIXP_DBL __staticHybridData[HYBRID_READ_OFFSET][MAX_PS_CHANNELS][2][MAX_HYBRID_BANDS]; + FIXP_DBL *pHybridData[HYBRID_READ_OFFSET+HYBRID_FRAMESIZE][MAX_PS_CHANNELS][2]; + + FIXP_QMF qmfDelayLines[2][QMF_MAX_TIME_SLOTS>>1][QMF_CHANNELS]; + int qmfDelayScale; INT psDelay; UINT maxEnvelopes; @@ -108,53 +83,126 @@ typedef struct T_PARAMETRIC_STEREO { INT noQmfSlots; INT noQmfBands; -} PARAMETRIC_STEREO; + FIXP_DBL __staticHybAnaStatesLF[MAX_PS_CHANNELS][2*HYBRID_FILTER_LENGTH*HYBRID_MAX_QMF_BANDS]; + FIXP_DBL __staticHybAnaStatesHF[MAX_PS_CHANNELS][2*HYBRID_FILTER_DELAY*(QMF_CHANNELS-HYBRID_MAX_QMF_BANDS)]; + FDK_ANA_HYB_FILTER fdkHybAnaFilter[MAX_PS_CHANNELS]; + FDK_SYN_HYB_FILTER fdkHybSynFilter; +} PARAMETRIC_STEREO; typedef struct T_PSENC_CONFIG { - - INT frameSize; - INT qmfFilterMode; - INT sbrPsDelay; - PSENC_STEREO_BANDS_CONFIG nStereoBands; - PSENC_NENV_CONFIG maxEnvelopes; - FIXP_DBL iidQuantErrorThreshold; + INT frameSize; + INT qmfFilterMode; + INT sbrPsDelay; + PSENC_STEREO_BANDS_CONFIG nStereoBands; + PSENC_NENV_CONFIG maxEnvelopes; + FIXP_DBL iidQuantErrorThreshold; } PSENC_CONFIG, *HANDLE_PSENC_CONFIG; typedef struct T_PARAMETRIC_STEREO *HANDLE_PARAMETRIC_STEREO; -HANDLE_ERROR_INFO -PSEnc_Create(HANDLE_PARAMETRIC_STEREO *phParametricStereo); - -HANDLE_ERROR_INFO -PSEnc_Init(HANDLE_PARAMETRIC_STEREO hParametricStereo, - HANDLE_PSENC_CONFIG hPsEncConfig, - INT noQmfSlots, - INT noQmfBands - ,UCHAR *dynamic_RAM - ); - -HANDLE_ERROR_INFO -UpdatePSQmfData_second(HANDLE_PARAMETRIC_STEREO hParametricStereo); - -HANDLE_ERROR_INFO -PSEnc_Destroy(HANDLE_PARAMETRIC_STEREO *hParametricStereo); - - -HANDLE_ERROR_INFO -FDKsbrEnc_PSEnc_ParametricStereoProcessing(HANDLE_PARAMETRIC_STEREO hParametricStereo, - FIXP_QMF **RESTRICT qmfRealData, - FIXP_QMF **RESTRICT qmfImagData, - INT qmfOffset, - INT_PCM *downsampledOutSignal, - HANDLE_QMF_FILTER_BANK sbrSynthQmf, - SCHAR *qmfScale, - const int sendHeader); - -INT -FDKsbrEnc_PSEnc_WritePSData(HANDLE_PARAMETRIC_STEREO hParametricStereo, HANDLE_FDK_BITSTREAM hBitstream); +/** + * \brief Create a parametric stereo encoder instance. + * + * \param phParametricStereo A pointer to a parametric stereo handle to be allocated. Initialized on return. + * + * \return + * - PSENC_OK, on succes. + * - PSENC_INVALID_HANDLE, PSENC_MEMORY_ERROR, on failure. + */ +FDK_PSENC_ERROR PSEnc_Create( + HANDLE_PARAMETRIC_STEREO *phParametricStereo + ); + + +/** + * \brief Initialize a parametric stereo encoder instance. + * + * \param hParametricStereo Meta Data handle. + * \param hPsEncConfig Filled parametric stereo configuration structure. + * \param noQmfSlots Number of slots within one audio frame. + * \param noQmfBands Number of QMF bands. + * \param dynamic_RAM Pointer to preallocated workbuffer. + * + * \return + * - PSENC_OK, on succes. + * - PSENC_INVALID_HANDLE, PSENC_INIT_ERROR, on failure. + */ +FDK_PSENC_ERROR PSEnc_Init( + HANDLE_PARAMETRIC_STEREO hParametricStereo, + const HANDLE_PSENC_CONFIG hPsEncConfig, + INT noQmfSlots, + INT noQmfBands + ,UCHAR *dynamic_RAM + ); + + +/** + * \brief Destroy parametric stereo encoder instance. + * + * Deallocate instance and free whole memory. + * + * \param phParametricStereo Pointer to the parametric stereo handle to be deallocated. + * + * \return + * - PSENC_OK, on succes. + * - PSENC_INVALID_HANDLE, on failure. + */ +FDK_PSENC_ERROR PSEnc_Destroy( + HANDLE_PARAMETRIC_STEREO *phParametricStereo + ); + + +/** + * \brief Apply parametric stereo processing. + * + * \param hParametricStereo Meta Data handle. + * \param samples Pointer to 2 channel audio input signal. + * \param timeInStride, Stride factor of input buffer. + * \param hQmfAnalysis, Pointer to QMF analysis filterbanks. + * \param downmixedRealQmfData Pointer to real QMF buffer to be written to. + * \param downmixedImagQmfData Pointer to imag QMF buffer to be written to. + * \param downsampledOutSignal Pointer to buffer where to write downmixed timesignal. + * \param sbrSynthQmf Pointer to QMF synthesis filterbank. + * \param qmfScale Return scaling factor of the qmf data. + * \param sendHeader Signal whether to write header data. + * + * \return + * - PSENC_OK, on succes. + * - PSENC_INVALID_HANDLE, PSENC_ENCODE_ERROR, on failure. + */ +FDK_PSENC_ERROR FDKsbrEnc_PSEnc_ParametricStereoProcessing( + HANDLE_PARAMETRIC_STEREO hParametricStereo, + INT_PCM *samples[2], + UINT timeInStride, + QMF_FILTER_BANK **hQmfAnalysis, + FIXP_QMF **RESTRICT downmixedRealQmfData, + FIXP_QMF **RESTRICT downmixedImagQmfData, + INT_PCM *downsampledOutSignal, + HANDLE_QMF_FILTER_BANK sbrSynthQmf, + SCHAR *qmfScale, + const int sendHeader + ); + + +/** + * \brief Write parametric stereo bitstream. + * + * Write ps_data() element to bitstream and return number of written bits. + * Returns number of written bits only, if hBitstream == NULL. + * + * \param hParametricStereo Meta Data handle. + * \param hBitstream Bitstream buffer handle. + * + * \return + * - number of written bits. + */ +INT FDKsbrEnc_PSEnc_WritePSData( + HANDLE_PARAMETRIC_STEREO hParametricStereo, + HANDLE_FDK_BITSTREAM hBitstream + ); #endif /* __INCLUDED_PS_MAIN_H */ diff --git a/libSBRenc/src/psenc_hybrid.cpp b/libSBRenc/src/psenc_hybrid.cpp deleted file mode 100644 index a314678..0000000 --- a/libSBRenc/src/psenc_hybrid.cpp +++ /dev/null @@ -1,836 +0,0 @@ -/***************************** MPEG Audio Encoder *************************** - - (C) Copyright Fraunhofer IIS (2004-2005) - All Rights Reserved - - Please be advised that this software and/or program delivery is - Confidential Information of Fraunhofer and subject to and covered by the - - Fraunhofer IIS Software Evaluation Agreement - between Google Inc. and Fraunhofer - effective and in full force since March 1, 2012. - - You may use this software and/or program only under the terms and - conditions described in the above mentioned Fraunhofer IIS Software - Evaluation Agreement. Any other and/or further use requires a separate agreement. - - - $Id$ - Initial author: M. Neuendorf, M. Multrus - contents/description: hybrid analysis filter bank - - This software and/or program is protected by copyright law and international - treaties. Any reproduction or distribution of this software and/or program, - or any portion of it, may result in severe civil and criminal penalties, and - will be prosecuted to the maximum extent possible under law. - -******************************************************************************/ - -#include "psenc_hybrid.h" - - -/* Includes ******************************************************************/ - -#include "psenc_hybrid.h" -#include "sbr_ram.h" - -#include "fft.h" - -#include "genericStds.h" - -/* Defines *******************************************************************/ - -#define HYBRID_SCALE 4 - -/*//#define FAST_FILTER2 -#define FAST_FILTER4 -#define FAST_FILTER8 -#define FAST_FILTER12 -*/ -#define HYBRID_INVERSE_ORDER ( 0x0F000000 ) -#define HYBRID_INVERSE_MASK ( ~HYBRID_INVERSE_ORDER ) - -//#define REAL ( 0 ) -//#define CPLX ( 1 ) - -#define cos0Pi FL2FXCONST_DBL( 1.f) -#define sin0Pi FL2FXCONST_DBL( 0.f) -#define cos1Pi FL2FXCONST_DBL(-1.f) -#define sin1Pi FL2FXCONST_DBL( 0.f) -#define cos1Pi_2 FL2FXCONST_DBL( 0.f) -#define sin1Pi_2 FL2FXCONST_DBL( 1.f) -#define cos1Pi_3 FL2FXCONST_DBL( 0.5f) -#define sin1Pi_3 FL2FXCONST_DBL( 0.86602540378444f) - -#define cos0Pi_4 cos0Pi -#define cos1Pi_4 FL2FXCONST_DBL(0.70710678118655f) -#define cos2Pi_4 cos1Pi_2 -#define cos3Pi_4 (-cos1Pi_4) -#define cos4Pi_4 (-cos0Pi_4) -#define cos5Pi_4 cos3Pi_4 -#define cos6Pi_4 cos2Pi_4 - -#define sin0Pi_4 sin0Pi -#define sin1Pi_4 FL2FXCONST_DBL(0.70710678118655f) -#define sin2Pi_4 sin1Pi_2 -#define sin3Pi_4 sin1Pi_4 -#define sin4Pi_4 sin0Pi_4 -#define sin5Pi_4 (-sin3Pi_4) -#define sin6Pi_4 (-sin2Pi_4) - -#define cos0Pi_8 cos0Pi -#define cos1Pi_8 FL2FXCONST_DBL(0.92387953251129f) -#define cos2Pi_8 cos1Pi_4 -#define cos3Pi_8 FL2FXCONST_DBL(0.38268343236509f) -#define cos4Pi_8 cos2Pi_4 -#define cos5Pi_8 (-cos3Pi_8) -#define cos6Pi_8 (-cos2Pi_8) - -#define sin0Pi_8 sin0Pi -#define sin1Pi_8 cos3Pi_8 -#define sin2Pi_8 sin1Pi_4 -#define sin3Pi_8 cos1Pi_8 -#define sin4Pi_8 sin2Pi_4 -#define sin5Pi_8 sin3Pi_8 -#define sin6Pi_8 sin1Pi_4 - -#define cos0Pi_12 cos0Pi -#define cos1Pi_12 FL2FXCONST_DBL(0.96592582628906f) -#define cos2Pi_12 FL2FXCONST_DBL(0.86602540378444f) -#define cos3Pi_12 cos1Pi_4 -#define cos4Pi_12 cos1Pi_3 -#define cos5Pi_12 FL2FXCONST_DBL(0.25881904510252f) -#define cos6Pi_12 cos1Pi_2 - -#define sin0Pi_12 sin0Pi -#define sin1Pi_12 cos5Pi_12 -#define sin2Pi_12 cos4Pi_12 -#define sin3Pi_12 sin1Pi_4 -#define sin4Pi_12 sin1Pi_3 -#define sin5Pi_12 cos1Pi_12 -#define sin6Pi_12 sin1Pi_2 - -#define FFT_IDX_R(a) (2*a) -#define FFT_IDX_I(a) (2*a+1) - - -/* Constants *****************************************************************/ - -/* static const UINT noQmfBandsInHybrid34 = 5; */ - -static const INT aHybridResolution10[] = { HYBRID_6_CPLX, - HYBRID_2_REAL | HYBRID_INVERSE_ORDER, - HYBRID_2_REAL }; - -static const INT aHybridResolution20[] = { HYBRID_6_CPLX, - HYBRID_2_REAL | HYBRID_INVERSE_ORDER, - HYBRID_2_REAL }; - -/*static const INT aHybridResolution34[] = { HYBRID_12_CPLX, - HYBRID_8_CPLX, - HYBRID_4_CPLX, - HYBRID_4_CPLX, - HYBRID_4_CPLX };*/ - -static const FIXP_DBL p8_13_20[HYBRID_FILTER_LENGTH] = -{ - FL2FXCONST_DBL(0.00746082949812f), FL2FXCONST_DBL(0.02270420949825f), FL2FXCONST_DBL(0.04546865930473f), FL2FXCONST_DBL(0.07266113929591f), - FL2FXCONST_DBL(0.09885108575264f), FL2FXCONST_DBL(0.11793710567217f), FL2FXCONST_DBL(0.125f ), FL2FXCONST_DBL(0.11793710567217f), - FL2FXCONST_DBL(0.09885108575264f), FL2FXCONST_DBL(0.07266113929591f), FL2FXCONST_DBL(0.04546865930473f), FL2FXCONST_DBL(0.02270420949825f), - FL2FXCONST_DBL(0.00746082949812f) -}; - -static const FIXP_DBL p2_13_20[HYBRID_FILTER_LENGTH] = -{ - FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL( 0.01899487526049f), FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(-0.07293139167538f), - FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL( 0.30596630545168f), FL2FXCONST_DBL(0.5f), FL2FXCONST_DBL( 0.30596630545168f), - FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL(-0.07293139167538f), FL2FXCONST_DBL(0.0f), FL2FXCONST_DBL( 0.01899487526049f), - FL2FXCONST_DBL(0.0f) -}; - - -/*static const float p12_13_34[HYBRID_FILTER_LENGTH] = -{ - 0.04081179924692, 0.03812810994926, 0.05144908135699, 0.06399831151592, - 0.07428313801106, 0.08100347892914, 0.08333333333333, 0.08100347892914, - 0.07428313801106, 0.06399831151592, 0.05144908135699, 0.03812810994926, - 0.04081179924692 -}; - -static const float p8_13_34[HYBRID_FILTER_LENGTH] = -{ - 0.01565675600122, 0.03752716391991, 0.05417891378782, 0.08417044116767, - 0.10307344158036, 0.12222452249753, 0.12500000000000, 0.12222452249753, - 0.10307344158036, 0.08417044116767, 0.05417891378782, 0.03752716391991, - 0.01565675600122 -}; - -static const float p4_13_34[HYBRID_FILTER_LENGTH] = -{ - -0.05908211155639, -0.04871498374946, 0.0, 0.07778723915851, - 0.16486303567403, 0.23279856662996, 0.25, 0.23279856662996, - 0.16486303567403, 0.07778723915851, 0.0, -0.04871498374946, - -0.05908211155639 -};*/ - - -/* Function / Class Implementation *******************************************/ - - - -/*****************************************************************************/ -/* **** FILTERBANK CONFIG **** */ - -HANDLE_ERROR_INFO FDKsbrEnc_CreateHybridConfig(HANDLE_PS_HYBRID_CONFIG *phHybConfig, - PS_BANDS mode) -{ - HANDLE_ERROR_INFO error = noError; - HANDLE_PS_HYBRID_CONFIG h = NULL; - UINT k = 0; - - if (error == noError) { - h = *phHybConfig; /* Simplify your life */ - h->mode = mode; - - switch (mode) { - case PS_BANDS_MID: - h->noQmfBandsInHybrid = NO_QMF_BANDS_HYBRID_20; - for (k=0; knoQmfBandsInHybrid; k++) { - h->aHybridResolution[k] = aHybridResolution20[k]; - } - break; - - case PS_BANDS_FINE: - /*h->noQmfBandsInHybrid = noQmfBandsInHybrid34; - for (k=0; knoQmfBandsInHybrid; k++) { - h->aHybridResolution[k] = aHybridResolution34[k]; - }*/ - FDK_ASSERT(0); /* we don't support! */ - break; - - case PS_BANDS_COARSE: - h->noQmfBandsInHybrid = NO_QMF_BANDS_HYBRID_10; - for (k=0; knoQmfBandsInHybrid; k++) { - h->aHybridResolution[k] = aHybridResolution10[k]; - } - break; - - default: - error = ERROR(CDI, "Invalid hybrid filter bank configuration."); - break; - } - } - - return error; -} - -/*****************************************************************************/ -/* **** FILTERBANK DATA **** */ - -HANDLE_ERROR_INFO FDKsbrEnc_CreateHybridData(HANDLE_PS_HYBRID_DATA *phHybData, - INT ch) -{ - HANDLE_ERROR_INFO error = noError; - int k; - - HANDLE_PS_HYBRID_DATA hHybData = GetRam_HybData(ch); - if (hHybData==NULL) { - error = 1; - goto bail; - } - - FDKmemclear(hHybData, sizeof(PS_HYBRID_DATA)); - - hHybData->rHybData[0] = GetRam_PsRhyb(ch); - hHybData->iHybData[0] = GetRam_PsIhyb(ch); - if ( (hHybData->rHybData[0]==NULL) || (hHybData->iHybData[0]==NULL) ) { - error = 1; - goto bail; - } - - - - for (k=1; k<(HYBRID_FRAMESIZE+HYBRID_WRITEOFFSET); k++) { - hHybData->rHybData[k] = hHybData->rHybData[0] + (k*HYBRID_NUM_BANDS); - hHybData->iHybData[k] = hHybData->iHybData[0] + (k*HYBRID_NUM_BANDS); - } - -bail: - *phHybData = hHybData; - return error; -} - - -HANDLE_ERROR_INFO FDKsbrEnc_InitHybridData(HANDLE_PS_HYBRID_DATA hHybData, - HANDLE_PS_HYBRID_CONFIG hHybConfig, - INT frameSize) -{ - HANDLE_ERROR_INFO error = noError; - INT nHybridBands = 0; - INT k = 0; - INT noBands = 0; - const INT *hybridRes = NULL; - - if (hHybConfig != NULL) { - noBands = hHybConfig->noQmfBandsInHybrid; - hybridRes = hHybConfig->aHybridResolution; - } - - for (k=0; k=nHybridBands); - - hHybData->hybDataReadOffset = HYBRID_DATA_READ_OFFSET; - hHybData->hybDataWriteOffset = HYBRID_WRITEOFFSET; - - for (k=0; k<(HYBRID_FRAMESIZE+HYBRID_WRITEOFFSET); k++) { - FDKmemclear(hHybData->rHybData[k], sizeof(FIXP_QMF)*HYBRID_NUM_BANDS); - FDKmemclear(hHybData->iHybData[k], sizeof(FIXP_QMF)*HYBRID_NUM_BANDS); - } - - hHybData->frameSize = frameSize; - hHybData->nHybridBands = nHybridBands; - hHybData->nHybridQmfBands = noBands; - - /* store hybrid resoltion in hybrid data handle */ - FDK_ASSERT (HYBRID_MAX_QMF_BANDS>=hHybData->nHybridQmfBands); - for(k = 0; knHybridQmfBands; k++){ - hHybData->nHybridResolution[k] = (hybridRes[k] & HYBRID_INVERSE_MASK); - } - - return error; -} - -HANDLE_ERROR_INFO FDKsbrEnc_DestroyHybridData(HANDLE_PS_HYBRID_DATA* phHybData) -{ - HANDLE_PS_HYBRID_DATA hHybData = *phHybData; - - if (hHybData!=NULL) { - FreeRam_PsRhyb(&hHybData->rHybData[0]); - FreeRam_PsIhyb(&hHybData->iHybData[0]); - FreeRam_HybData(phHybData); - } - - return noError; -} - -/*** Access functions ***/ - -/* return hybrid band resolution of qmf band 'qmfBand' */ -INT FDKsbrEnc_GetHybridResolution(HANDLE_PS_HYBRID_DATA h, INT qmfBand){ - - INT nHybridResolution = 0; - - if(h->nHybridResolution){ - nHybridResolution = h->nHybridResolution[qmfBand]; - } - - return nHybridResolution; -} - -/*****************************************************************************/ -/* **** FILTERBANK **** */ - -/* - 2 channel filter - Filter Coefs: - 0.0, - 0.01899487526049, - 0.0, - -0.07293139167538, - 0.0, - 0.30596630545168, - 0.5, - 0.30596630545168, - 0.0, - -0.07293139167538, - 0.0, - 0.01899487526049, - 0.0 - - - Filter design: - h[q,n] = g[n] * cos(2pi/2 * q * (n-6) ); n = 0..12, q = 0,1; - - -> h[0,n] = g[n] * 1; - -> h[1,n] = g[n] * pow(-1,n); - -*/ - -static void dualChannelFiltering(const FIXP_QMF *RESTRICT pQmfReal, - const FIXP_QMF *RESTRICT pQmfImag, - FIXP_QMF **RESTRICT mHybridReal, - FIXP_QMF **RESTRICT mHybridImag, - INT nSamples) -{ - INT i; - - for(i = 0; i < nSamples; i++) { - FIXP_DBL r1, r3, r5, r6; - FIXP_DBL i1, i3, i5, i6; - - /* symmetric filter coefficients - scaleValue same as used in eightChannelFiltering (HYBRID_SCALE = 4) - */ - r1 = fMultDiv2(p2_13_20[1], (FIXP_QMF)((pQmfReal[1+i]>>1) + (pQmfReal[11+i]>>1)) ) >> 2; - r3 = fMultDiv2(p2_13_20[3], (FIXP_QMF)((pQmfReal[3+i]>>1) + (pQmfReal[ 9+i]>>1)) ) >> 2; - r5 = fMultDiv2(p2_13_20[5], (FIXP_QMF)((pQmfReal[5+i]>>1) + (pQmfReal[ 7+i]>>1)) ) >> 2; - r6 = fMultDiv2(p2_13_20[6], (FIXP_QMF) (pQmfReal[6+i]>>1) ) >> 2; - - i1 = fMultDiv2(p2_13_20[1], (FIXP_QMF)((pQmfImag[1+i]>>1) + (pQmfImag[11+i]>>1)) ) >> 2; - i3 = fMultDiv2(p2_13_20[3], (FIXP_QMF)((pQmfImag[3+i]>>1) + (pQmfImag[ 9+i]>>1)) ) >> 2; - i5 = fMultDiv2(p2_13_20[5], (FIXP_QMF)((pQmfImag[5+i]>>1) + (pQmfImag[ 7+i]>>1)) ) >> 2; - i6 = fMultDiv2(p2_13_20[6], (FIXP_QMF) (pQmfImag[6+i]>>1) ) >> 2; - - mHybridReal[i][0] = FX_DBL2FX_QMF(r1 + r3 + r5 + r6); - mHybridImag[i][0] = FX_DBL2FX_QMF(i1 + i3 + i5 + i6); - - mHybridReal[i][1] = FX_DBL2FX_QMF(- r1 - r3 - r5 + r6); - mHybridImag[i][1] = FX_DBL2FX_QMF(- i1 - i3 - i5 + i6); - } -} - -/* - 8 channel filter - - Implementation using a FFT of length 8 - - prototype filter coefficients: - 0.00746082949812 0.02270420949825 0.04546865930473 0.07266113929591 0.09885108575264 0.11793710567217 - 0.125 - 0.11793710567217 0.09885108575264 0.07266113929591 0.04546865930473 0.02270420949825 0.00746082949812 - - Filter design: - N = 13; Q = 8; - h[q,n] = g[n] * exp(j * 2 * pi / Q * (q + .5) * (n - 6)); n = 0..(N-1), q = 0..(Q-1); - - Time Signal: x[t]; - Filter Bank Output - y[q,t] = conv(x[t],h[q,t]) = conv(h[q,t],x[t]) = sum(x[k] * h[q, t - k] ) = sum(h[q, k] * x[t - k] ); k = 0..(N-1); - - y[q,t] = x[t - 12]*h[q, 12] + x[t - 11]*h[q, 11] + x[t - 10]*h[q, 10] + x[t - 9]*h[q, 9] - + x[t - 8]*h[q, 8] + x[t - 7]*h[q, 7] - + x[t - 6]*h[q, 6] - + x[t - 5]*h[q, 5] + x[t - 4]*h[q, 4] - + x[t - 3]*h[q, 3] + x[t - 2]*h[q, 2] + x[t - 1]*h[q, 1] + x[t - 0]*h[q, 0]; - - h'[q, n] = h[q,(N-1)-n] = g[n] * exp(j * 2 * pi / Q * (q + .5) * (6 - n)); n = 0..(N-1), q = 0..(Q-1); - - y[q,t] = x[t - 12]*h'[q, 0] + x[t - 11]*h'[q, 1] + x[t - 10]*h'[q, 2] + x[t - 9]*h'[q, 3] - + x[t - 8]*h'[q, 4] + x[t - 7]*h'[q, 5] - + x[t - 6]*h'[q, 6] - + x[t - 5]*h'[q, 7] + x[t - 4]*h'[q, 8] - + x[t - 3]*h'[q, 9] + x[t - 2]*h'[q, 10] + x[t - 1]*h'[q, 11] + x[t - 0]*h'[q, 12]; - - Try to split off FFT Modulation Term: - FFT(x[t], q) = sum(x[t+k]*exp(-j*2*pi/N *q * k)) - c m - Step 1: h'[q,n] = g[n] * ( exp(j * 2 * pi / 8 * .5 * (6 - n)) ) * ( exp (j * 2 * pi / 8 * q * (6 - n)) ); - - h'[q,n] = g[n] *c[n] * m[q,n]; (see above) - c[n] = exp( j * 2 * pi / 8 * .5 * (6 - n) ); - m[q,n] = exp( j * 2 * pi / 8 * q * (6 - n) ); - - y[q,t] = x[t - 0]*g[0]*c[0]*m[q,0] + x[t - 1]*g[1]*c[ 1]*m[q, 1] + ... - ... + x[t - 12]*g[2]*c[12]*m[q,12]; - - | - n m *exp(-j*2*pi) | n' fft -------------------------------------------------------------------------------------------------------------------------- - 0 exp( j * 2 * pi / 8 * q * 6) -> exp(-j * 2 * pi / 8 * q * 2) | 2 exp(-j * 2 * pi / 8 * q * 0) - 1 exp( j * 2 * pi / 8 * q * 5) -> exp(-j * 2 * pi / 8 * q * 3) | 3 exp(-j * 2 * pi / 8 * q * 1) - 2 exp( j * 2 * pi / 8 * q * 4) -> exp(-j * 2 * pi / 8 * q * 4) | 4 exp(-j * 2 * pi / 8 * q * 2) - 3 exp( j * 2 * pi / 8 * q * 3) -> exp(-j * 2 * pi / 8 * q * 5) | 5 exp(-j * 2 * pi / 8 * q * 3) - 4 exp( j * 2 * pi / 8 * q * 2) -> exp(-j * 2 * pi / 8 * q * 6) | 6 exp(-j * 2 * pi / 8 * q * 4) - 5 exp( j * 2 * pi / 8 * q * 1) -> exp(-j * 2 * pi / 8 * q * 7) | 7 exp(-j * 2 * pi / 8 * q * 5) - 6 exp( j * 2 * pi / 8 * q * 0) | 0 exp(-j * 2 * pi / 8 * q * 6) - 7 exp(-j * 2 * pi / 8 * q * 1) | 1 exp(-j * 2 * pi / 8 * q * 7) - 8 exp(-j * 2 * pi / 8 * q * 2) | 2 - 9 exp(-j * 2 * pi / 8 * q * 3) | 3 - 10 exp(-j * 2 * pi / 8 * q * 4) | 4 - 11 exp(-j * 2 * pi / 8 * q * 5) | 5 - 12 exp(-j * 2 * pi / 8 * q * 6) | 6 - - - now use fft modulation coefficients - m[6] = = fft[0] - m[7] = = fft[1] - m[8] = m[ 0] = fft[2] - m[9] = m[ 1] = fft[3] - m[10] = m[ 2] = fft[4] - m[11] = m[ 3] = fft[5] - m[12] = m[ 4] = fft[6] - m[ 5] = fft[7] - - y[q,t] = ( x[t- 6]*g[ 6]*c[ 6] ) * fft[q,0] + - ( x[t- 7]*g[ 7]*c[ 7] ) * fft[q,1] + - ( x[t- 0]*g[ 0]*c[ 0] + x[t- 8]*g[ 8]*c[ 8] ) * fft[q,2] + - ( x[t- 1]*g[ 1]*c[ 1] + x[t- 9]*g[ 9]*c[ 9] ) * fft[q,3] + - ( x[t- 2]*g[ 2]*c[ 2] + x[t-10]*g[10]*c[10] ) * fft[q,4] + - ( x[t- 3]*g[ 3]*c[ 3] + x[t-11]*g[11]*c[11] ) * fft[q,5] + - ( x[t- 4]*g[ 4]*c[ 4] + x[t-12]*g[12]*c[12] ) * fft[q,6] + - ( x[t- 5]*g[ 5]*c[ 5] ) * fft[q,7]; - - pre twiddle factors c[n] = exp(j * 2 * pi / 8 * .5 * (6 - n)); - n c] | n c[n] | n c[n] ---------------------------------------------------------------------------------------------------- - 0 exp( j * 6 * pi / 8) | 1 exp( j * 5 * pi / 8) | 2 exp( j * 4 * pi / 8) - 3 exp( j * 3 * pi / 8) | 4 exp( j * 2 * pi / 8) | 5 exp( j * 1 * pi / 8) - 6 exp( j * 0 * pi / 8) | 7 exp(-j * 1 * pi / 8) | 8 exp(-j * 2 * pi / 8) - 9 exp(-j * 3 * pi / 8) | 10 exp(-j * 4 * pi / 8) | 11 exp(-j * 5 * pi / 8) - 12 exp(-j * 6 * pi / 8) | | - -*/ - -static const FIXP_DBL cr[13] = -{ cos6Pi_8, cos5Pi_8, cos4Pi_8, - cos3Pi_8, cos2Pi_8, cos1Pi_8, - cos0Pi_8, - cos1Pi_8, cos2Pi_8, cos3Pi_8, - cos4Pi_8, cos5Pi_8, cos6Pi_8 -}; - -static const FIXP_DBL ci[13] = -{ - sin6Pi_8, sin5Pi_8, sin4Pi_8, - sin3Pi_8, sin2Pi_8, sin1Pi_8, - sin0Pi_8, - -sin1Pi_8, -sin2Pi_8, -sin3Pi_8, - -sin4Pi_8, -sin5Pi_8, -sin6Pi_8 -}; - - -static void eightChannelFiltering(const FIXP_QMF *pQmfReal, - const FIXP_QMF *pQmfImag, - FIXP_DBL *fft, - FIXP_QMF **mHybridReal, - FIXP_QMF **mHybridImag, - INT nSamples, - const FIXP_DBL *p) -{ - INT i, bin; - for(i = 0; i < nSamples; i++) { - /* pre twiddeling - scaling 4 = 2 (fMultDiv2) + 2 (dit_fft) scaling (HYBRID_SCALE = 4) - */ - fft[FFT_IDX_R(0)] = fMultDiv2(p[6], fMultSubDiv2(fMultDiv2(cr[6], pQmfReal[6+i]), ci[6], pQmfImag[6+i])); - fft[FFT_IDX_I(0)] = fMultDiv2(p[6], fMultAddDiv2(fMultDiv2(ci[6], pQmfReal[6+i]), cr[6], pQmfImag[6+i])); - - fft[FFT_IDX_R(1)] = fMultDiv2(p[7], fMultSubDiv2(fMultDiv2(cr[7], pQmfReal[7+i]), ci[7], pQmfImag[7+i])); - fft[FFT_IDX_I(1)] = fMultDiv2(p[7], fMultAddDiv2(fMultDiv2(ci[7], pQmfReal[7+i]), cr[7], pQmfImag[7+i])); - - fft[FFT_IDX_R(2)] = ( fMultDiv2(p[ 0], fMultSubDiv2(fMultDiv2(cr[0], pQmfReal[ 0+i]), ci[0], pQmfImag[ 0+i]))+ - fMultDiv2(p[ 8], fMultSubDiv2(fMultDiv2(cr[8], pQmfReal[ 8+i]), ci[8], pQmfImag[ 8+i])) ); - fft[FFT_IDX_I(2)] = ( fMultDiv2(p[ 0], fMultAddDiv2(fMultDiv2(ci[0], pQmfReal[ 0+i]), cr[0], pQmfImag[ 0+i]))+ - fMultDiv2(p[ 8], fMultAddDiv2(fMultDiv2(ci[8], pQmfReal[ 8+i]), cr[8], pQmfImag[ 8+i])) ); - - fft[FFT_IDX_R(3)] = ( fMultDiv2(p[ 1], fMultSubDiv2(fMultDiv2(cr[1], pQmfReal[ 1+i]), ci[1], pQmfImag[ 1+i]))+ - fMultDiv2(p[ 9], fMultSubDiv2(fMultDiv2(cr[9], pQmfReal[ 9+i]), ci[9], pQmfImag[ 9+i])) ); - fft[FFT_IDX_I(3)] = ( fMultDiv2(p[ 1], fMultAddDiv2(fMultDiv2(ci[1], pQmfReal[ 1+i]), cr[1], pQmfImag[ 1+i]))+ - fMultDiv2(p[ 9], fMultAddDiv2(fMultDiv2(ci[9], pQmfReal[ 9+i]), cr[9], pQmfImag[ 9+i])) ); - - fft[FFT_IDX_R(4)] = ( fMultDiv2(p[ 2], fMultSubDiv2( fMultDiv2(cr[2], pQmfReal[ 2+i]), ci[2], pQmfImag[ 2+i]))+ - fMultDiv2(p[10], fMultSubDiv2(fMultDiv2(cr[10], pQmfReal[10+i]), ci[10], pQmfImag[10+i])) ); - fft[FFT_IDX_I(4)] = ( fMultDiv2(p[ 2], fMultAddDiv2( fMultDiv2(ci[2], pQmfReal[ 2+i]), cr[2], pQmfImag[ 2+i]))+ - fMultDiv2(p[10], fMultAddDiv2(fMultDiv2(ci[10], pQmfReal[10+i]), cr[10], pQmfImag[10+i])) ); - - fft[FFT_IDX_R(5)] = ( fMultDiv2(p[ 3], fMultSubDiv2( fMultDiv2(cr[3], pQmfReal[ 3+i]), ci[3], pQmfImag[ 3+i]))+ - fMultDiv2(p[11], fMultSubDiv2(fMultDiv2(cr[11], pQmfReal[11+i]), ci[11], pQmfImag[11+i])) ); - fft[FFT_IDX_I(5)] = ( fMultDiv2(p[ 3], fMultAddDiv2( fMultDiv2(ci[3], pQmfReal[ 3+i]), cr[3], pQmfImag[ 3+i]))+ - fMultDiv2(p[11], fMultAddDiv2(fMultDiv2(ci[11], pQmfReal[11+i]), cr[11], pQmfImag[11+i])) ); - - fft[FFT_IDX_R(6)] = ( fMultDiv2(p[ 4], fMultSubDiv2( fMultDiv2(cr[4], pQmfReal[ 4+i]), ci[4], pQmfImag[ 4+i]))+ - fMultDiv2(p[12], fMultSubDiv2(fMultDiv2(cr[12], pQmfReal[12+i]), ci[12], pQmfImag[12+i])) ); - fft[FFT_IDX_I(6)] = ( fMultDiv2(p[ 4], fMultAddDiv2( fMultDiv2(ci[4], pQmfReal[ 4+i]), cr[4], pQmfImag[ 4+i]))+ - fMultDiv2(p[12], fMultAddDiv2(fMultDiv2(ci[12], pQmfReal[12+i]), cr[12], pQmfImag[12+i])) ); - - fft[FFT_IDX_R(7)] = fMultDiv2(p[5], fMultSubDiv2(fMultDiv2(cr[5], pQmfReal[5+i]), ci[5], pQmfImag[5+i])); - fft[FFT_IDX_I(7)] = fMultDiv2(p[5], fMultAddDiv2(fMultDiv2(ci[5], pQmfReal[5+i]), cr[5], pQmfImag[5+i])); - - /* fft modulation */ - fft_8(fft); - - /* resort fft data INTo output array*/ - for(bin=0; bin<8;bin++ ) { - mHybridReal[i][bin] = FX_DBL2FX_QMF(fft[FFT_IDX_R(bin)]); - mHybridImag[i][bin] = FX_DBL2FX_QMF(fft[FFT_IDX_I(bin)]); - } - } -} - -/**************************************************************************//** -HybridAnalysis -******************************************************************************/ - -HANDLE_ERROR_INFO -HybridAnalysis ( HANDLE_PS_HYBRID hHybrid, /*!< Handle to HYBRID struct. */ - FIXP_QMF *const *const mQmfReal, /*!< The real part of the QMF-matrix. */ - FIXP_QMF *const *const mQmfImag, /*!< The imaginary part of the QMF-matrix. */ - SCHAR sf_fixpQmf, /*!< Qmf scale factor */ - FIXP_QMF **mHybridReal, /*!< The real part of the hybrid-matrix. */ - FIXP_QMF **mHybridImag, /*!< The imaginary part of the hybrid-matrix. */ - SCHAR *sf_fixpHybrid) /*!< Hybrid scale factor */ -{ - HANDLE_ERROR_INFO error = noError; - INT n, band; - INT hybridRes; - INT chOffset = 0; - /* INT usedStereoBands = hHybrid->mode; */ /*!< indicates which 8 band filter to use */ - INT frameSize = hHybrid->frameSize; - INT hybridFilterDelay = hHybrid->hybridFilterDelay; - - for(band = 0; band < hHybrid->nQmfBands; band++) { /* loop all qmf bands */ - - if(error == noError){ - hybridRes = hHybrid->pResolution[band]; - - /* Create working buffer. */ - /* Copy stored samples to working buffer. */ - FDKmemcpy(hHybrid->pWorkReal, hHybrid->mQmfBufferReal[band], - hHybrid->qmfBufferMove * sizeof(FIXP_QMF)); - FDKmemcpy(hHybrid->pWorkImag, hHybrid->mQmfBufferImag[band], - hHybrid->qmfBufferMove * sizeof(FIXP_QMF)); - - /* Append new samples to working buffer. */ - for(n = 0; n < frameSize; n++) { - hHybrid->pWorkReal [hHybrid->qmfBufferMove + n] = mQmfReal [n + hybridFilterDelay] [band]; - hHybrid->pWorkImag [hHybrid->qmfBufferMove + n] = mQmfImag [n + hybridFilterDelay] [band]; - } - - /* Store samples for next frame. */ - FDKmemcpy(hHybrid->mQmfBufferReal[band], hHybrid->pWorkReal + frameSize, - hHybrid->qmfBufferMove * sizeof(FIXP_QMF)); - FDKmemcpy(hHybrid->mQmfBufferImag[band], hHybrid->pWorkImag + frameSize, - hHybrid->qmfBufferMove * sizeof(FIXP_QMF)); - - - switch(hybridRes) { - case HYBRID_2_REAL: - dualChannelFiltering( hHybrid->pWorkReal, - hHybrid->pWorkImag, - hHybrid->mTempReal, - hHybrid->mTempImag, - frameSize); - - /* copy data to output buffer */ - for(n = 0; n < frameSize; n++) { - FDKmemcpy(&mHybridReal[n][chOffset], hHybrid->mTempReal[n], - (INT)(hybridRes & HYBRID_INVERSE_MASK)*sizeof(FIXP_QMF)); - FDKmemcpy(&mHybridImag[n][chOffset], hHybrid->mTempImag[n], - (INT)(hybridRes & HYBRID_INVERSE_MASK)*sizeof(FIXP_QMF)); - } - break; - - case HYBRID_2_REAL | HYBRID_INVERSE_ORDER: - dualChannelFiltering( hHybrid->pWorkReal, - hHybrid->pWorkImag, - hHybrid->mTempReal, - hHybrid->mTempImag, - frameSize); - - /* copy and resort data */ - for ( n = 0; n < frameSize; n++ ) - { - mHybridReal[n][chOffset + 0] = hHybrid->mTempReal[n][1] ; - mHybridReal[n][chOffset + 1] = hHybrid->mTempReal[n][0] ; - mHybridImag[n][chOffset + 0] = hHybrid->mTempImag[n][1] ; - mHybridImag[n][chOffset + 1] = hHybrid->mTempImag[n][0] ; - } - break; - - case HYBRID_6_CPLX: - eightChannelFiltering( hHybrid->pWorkReal, - hHybrid->pWorkImag, - hHybrid->fft, - hHybrid->mTempReal, - hHybrid->mTempImag, - frameSize, - /*(usedStereoBands==PS_BANDS_FINE)?p8_13_34:*/p8_13_20); - - /* do the shuffle */ - for ( n = 0; n < frameSize; n++ ) - { - /* add data ... */ - hHybrid->mTempReal[n][2] += hHybrid->mTempReal[n][5]; - hHybrid->mTempImag[n][2] += hHybrid->mTempImag[n][5]; - hHybrid->mTempReal[n][3] += hHybrid->mTempReal[n][4]; - hHybrid->mTempImag[n][3] += hHybrid->mTempImag[n][4]; - - /* shuffle and copy to output buffer */ - mHybridReal[n][chOffset + 0] = hHybrid->mTempReal[n][6] ; - mHybridReal[n][chOffset + 1] = hHybrid->mTempReal[n][7] ; - mHybridReal[n][chOffset + 2] = hHybrid->mTempReal[n][0] ; - mHybridReal[n][chOffset + 3] = hHybrid->mTempReal[n][1] ; - mHybridReal[n][chOffset + 4] = hHybrid->mTempReal[n][2] ; - mHybridReal[n][chOffset + 5] = hHybrid->mTempReal[n][3] ; - - mHybridImag[n][chOffset + 0] = hHybrid->mTempImag[n][6] ; - mHybridImag[n][chOffset + 1] = hHybrid->mTempImag[n][7] ; - mHybridImag[n][chOffset + 2] = hHybrid->mTempImag[n][0] ; - mHybridImag[n][chOffset + 3] = hHybrid->mTempImag[n][1] ; - mHybridImag[n][chOffset + 4] = hHybrid->mTempImag[n][2] ; - mHybridImag[n][chOffset + 5] = hHybrid->mTempImag[n][3] ; - } - break; - - case HYBRID_8_CPLX: - eightChannelFiltering( hHybrid->pWorkReal, - hHybrid->pWorkImag, - hHybrid->fft, - hHybrid->mTempReal, - hHybrid->mTempImag, - frameSize, - /*(usedStereoBands==PS_BANDS_FINE)?p8_13_34:*/p8_13_20); - - /* copy data to output buffer */ - for(n = 0; n < frameSize; n++) { - FDKmemcpy(&mHybridReal[n][chOffset], hHybrid->mTempReal[n], - (INT)(hybridRes & HYBRID_INVERSE_MASK)*sizeof(FIXP_QMF)); - FDKmemcpy(&mHybridImag[n][chOffset], hHybrid->mTempImag[n], - (INT)(hybridRes & HYBRID_INVERSE_MASK)*sizeof(FIXP_QMF)); - } - break; - - default: - error = ERROR(CDI, "Invalid filter bank configuration."); - break; - } - /* prepare next run by incresing chOffset */ - chOffset += hybridRes & HYBRID_INVERSE_MASK; - } - } - - *sf_fixpHybrid = sf_fixpQmf + HYBRID_SCALE; - - return error; -} - -/**************************************************************************//** - FDKsbrEnc_CreateHybridFilterBank -******************************************************************************/ -HANDLE_ERROR_INFO -FDKsbrEnc_CreateHybridFilterBank ( HANDLE_PS_HYBRID *phHybrid, /*!< Pointer to handle to HYBRID struct. */ - INT ch) /*!< Current channel */ -{ - HANDLE_ERROR_INFO error = noError; - INT i; - HANDLE_PS_HYBRID hs = GetRam_PsHybrid(ch); /* allocate memory */ - if (hs==NULL) { - error = 1; - goto bail; - } - - hs->fft = GetRam_PsHybFFT(); - - /* alloc working memory */ - hs->pWorkReal = GetRam_PsHybWkReal(); - hs->pWorkImag = GetRam_PsHybWkImag(); - - if ( (hs->fft==NULL) || (hs->pWorkReal==NULL) || (hs->pWorkImag==NULL) ) { - error = 1; - goto bail; - } - - /* Allocate buffers */ - for (i = 0; i < HYBRID_FRAMESIZE; i++) { - hs->mTempReal[i] = GetRam_PsMtmpReal(i); - hs->mTempImag[i] = GetRam_PsMtmpImag(i); - if ( (hs->mTempReal[i]==NULL) || (hs->mTempImag[i]==NULL) ) { - error = 1; - goto bail; - } - } - -bail: - *phHybrid = hs; - return error; -} - -HANDLE_ERROR_INFO -FDKsbrEnc_InitHybridFilterBank ( HANDLE_PS_HYBRID hs, /*!< Handle to HYBRID struct. */ - HANDLE_PS_HYBRID_CONFIG hHybConfig, /*!< Configuration hanlde for filter bank */ - INT frameSize) /*!< Number of QMF slots */ -{ - HANDLE_ERROR_INFO error = noError; - INT i; - INT maxNoChannels = HYBRID_12_CPLX, noBands; - PS_BANDS mode; - const INT *RESTRICT pResolution; - - /* filter bank configuration */ - mode = hHybConfig->mode; - noBands = hHybConfig->noQmfBandsInHybrid; - pResolution = hHybConfig->aHybridResolution; - - /* assign resolution, check for valid values */ - for (i = 0; i < noBands; i++) { - if(error == noError){ - if( pResolution[i] != HYBRID_12_CPLX && - pResolution[i] != HYBRID_8_CPLX && - pResolution[i] != HYBRID_6_CPLX && - pResolution[i] != HYBRID_2_REAL && - pResolution[i] != (HYBRID_2_REAL | HYBRID_INVERSE_ORDER) && - pResolution[i] != HYBRID_4_CPLX ){ - error = ERROR(CDI, "Invalid filter bank resolution"); - } - } - hs->pResolution[i] = pResolution[i]; - if((pResolution[i] & HYBRID_INVERSE_MASK) > maxNoChannels){ - maxNoChannels = pResolution[i] & HYBRID_INVERSE_MASK; - } - } - FDK_ASSERT (MAX_HYBRID_RES>=maxNoChannels); /* check size of mTempReal/Imag */ - - /* assign parameters */ - hs->mode = mode; - hs->nQmfBands = noBands; - hs->frameSize = frameSize; - hs->frameSizeInit = frameSize; - hs->qmfBufferMove = HYBRID_FILTER_LENGTH - 1; - hs->hybridFilterDelay = HYBRID_FILTER_LENGTH/2; - - FDK_ASSERT (HYBRID_FRAMESIZE>=hs->frameSize); - FDK_ASSERT (QMF_BUFFER_MOVE>=hs->qmfBufferMove); - - return error; -} - - -/**************************************************************************//** - FDKsbrEnc_DeleteHybridFilterBank -******************************************************************************/ - -HANDLE_ERROR_INFO -FDKsbrEnc_DeleteHybridFilterBank ( HANDLE_PS_HYBRID* phHybrid ) /*!< Pointer to handle to HYBRID struct. */ -{ - int i; - HANDLE_PS_HYBRID hHybrid = *phHybrid; - - if (hHybrid!=NULL) { - if (hHybrid->fft) - FreeRam_PsHybFFT(&hHybrid->fft); - if (hHybrid->pWorkReal) - FreeRam_PsHybWkReal(&hHybrid->pWorkReal); - if (hHybrid->pWorkImag) - FreeRam_PsHybWkImag(&hHybrid->pWorkImag); - - for (i = 0; i < HYBRID_FRAMESIZE; i++) { - if (hHybrid->mTempReal[i]) - FreeRam_PsMtmpReal(&hHybrid->mTempReal[i]); - if (hHybrid->mTempImag[i]) - FreeRam_PsMtmpImag(&hHybrid->mTempImag[i]); - } - - FreeRam_PsHybrid(phHybrid); - } - - return noError; -} - -/*** Access functions ***/ -INT FDKsbrEnc_GetHybridFilterDelay(HANDLE_PS_HYBRID hHybrid){ - - return hHybrid->hybridFilterDelay; -} - diff --git a/libSBRenc/src/psenc_hybrid.h b/libSBRenc/src/psenc_hybrid.h deleted file mode 100644 index 79e600d..0000000 --- a/libSBRenc/src/psenc_hybrid.h +++ /dev/null @@ -1,182 +0,0 @@ -/***************************** MPEG Audio Encoder *************************** - - (C) Copyright Fraunhofer IIS (2004-2005) - All Rights Reserved - - Please be advised that this software and/or program delivery is - Confidential Information of Fraunhofer and subject to and covered by the - - Fraunhofer IIS Software Evaluation Agreement - between Google Inc. and Fraunhofer - effective and in full force since March 1, 2012. - - You may use this software and/or program only under the terms and - conditions described in the above mentioned Fraunhofer IIS Software - Evaluation Agreement. Any other and/or further use requires a separate agreement. - - - $Id$ - Initial author: M. Neuendorf, M. Multrus - contents/description: hypbrid filter bank (prototypes) - - This software and/or program is protected by copyright law and international - treaties. Any reproduction or distribution of this software and/or program, - or any portion of it, may result in severe civil and criminal penalties, and - will be prosecuted to the maximum extent possible under law. - -******************************************************************************/ -#ifndef __hybrid_h -#define __hybrid_h - -/* Includes ******************************************************************/ -#include "sbr_def.h" -#include "ps_const.h" - -#include "qmf.h" - -/* Data Types ****************************************************************/ - -typedef enum { - HYBRID_2_REAL = 2, - HYBRID_4_CPLX = 4, - HYBRID_6_CPLX = 6, - HYBRID_8_CPLX = 8, - HYBRID_12_CPLX = 12 -} HYBRID_RES; - -#define MAX_HYBRID_RES (HYBRID_12_CPLX) - -/* Defines *******************************************************************/ -#define MAX_QMF_BANDS_IN_HYBRID (5) -#define MAX_IID_GROUPS (50) /* NO_IID_GROUPS_HI_RES */ - -#define HYBRID_FILTER_LENGTH ( 13 ) - -#define HYBRID_FRAMESIZE ( QMF_MAX_TIME_SLOTS ) -#define HYBRID_WRITEOFFSET ( 10 ) -#define HYBRID_NUM_BANDS ( 10 ) - -#define NO_QMF_BANDS_HYBRID_10 ( 3 ) -#define NO_QMF_BANDS_HYBRID_20 ( 3 ) -#define HYBRID_MAX_QMF_BANDS ( NO_QMF_BANDS_HYBRID_20 ) - -#define QMF_BUFFER_MOVE ( HYBRID_FILTER_LENGTH - 1 ) - - -/* Data Types ****************************************************************/ -typedef struct PS_HYBRID_CONFIG_tag { - PS_BANDS mode; - - UINT noQmfBandsInHybrid; - INT aHybridResolution[MAX_QMF_BANDS_IN_HYBRID]; /* valid entries from 0 to noQmfBandsInHybrid */ - -} PS_HYBRID_CONFIG, *HANDLE_PS_HYBRID_CONFIG; - -typedef struct PS_HYBRID_tag -{ - PS_BANDS mode; - INT nQmfBands; - INT frameSizeInit; - INT frameSize; - INT pResolution[HYBRID_MAX_QMF_BANDS]; - INT qmfBufferMove; - INT hybridFilterDelay; - - FIXP_DBL *fft; - - FIXP_QMF *pWorkReal; /**< Working arrays for Qmf samples. */ - FIXP_QMF *pWorkImag; - - FIXP_QMF mQmfBufferReal[HYBRID_MAX_QMF_BANDS][QMF_BUFFER_MOVE]; /**< Stores old Qmf samples. */ - FIXP_QMF mQmfBufferImag[HYBRID_MAX_QMF_BANDS][QMF_BUFFER_MOVE]; - FIXP_QMF *mTempReal[HYBRID_FRAMESIZE]; /**< Temporary matrices for filter bank output. */ - FIXP_QMF *mTempImag[HYBRID_FRAMESIZE]; - -} PS_HYBRID; - -typedef struct PS_HYBRID_DATA_tag { - INT frameSize; - INT nHybridBands; - INT nHybridQmfBands; - INT nHybridResolution [HYBRID_MAX_QMF_BANDS]; - - FIXP_QMF* rHybData [(HYBRID_FRAMESIZE + HYBRID_WRITEOFFSET)]; - FIXP_QMF* iHybData [(HYBRID_FRAMESIZE + HYBRID_WRITEOFFSET)]; - SCHAR sf_fixpHybrid; - - INT hybDataReadOffset; - INT hybDataWriteOffset; - -} PS_HYBRID_DATA; - - -typedef struct PS_HYBRID_DATA_tag *HANDLE_PS_HYBRID_DATA; -typedef struct PS_HYBRID_tag *HANDLE_PS_HYBRID; - - - -/* Function Declarations *********************************************/ - -/*****************************************************************************/ -/* **** FILTERBANK CONFIG **** */ - -HANDLE_ERROR_INFO FDKsbrEnc_CreateHybridConfig(HANDLE_PS_HYBRID_CONFIG *phHybConfig, - PS_BANDS mode); - -/*****************************************************************************/ -/* **** FILTERBANK DATA **** */ - -HANDLE_ERROR_INFO FDKsbrEnc_CreateHybridData(HANDLE_PS_HYBRID_DATA *phHybData, - INT ch); - -HANDLE_ERROR_INFO FDKsbrEnc_InitHybridData(HANDLE_PS_HYBRID_DATA hHybData, - HANDLE_PS_HYBRID_CONFIG hHybConfig, - INT frameSize); - -HANDLE_ERROR_INFO FDKsbrEnc_DestroyHybridData(HANDLE_PS_HYBRID_DATA* phHybData); - -inline INT FDKsbrEnc_GetHybridFrameSize(HANDLE_PS_HYBRID_DATA h) { - return h->frameSize; -} - -inline INT FDKsbrEnc_GetNumberHybridBands(HANDLE_PS_HYBRID_DATA h) { - return h->nHybridBands; -} - -inline INT FDKsbrEnc_GetNumberHybridQmfBands(HANDLE_PS_HYBRID_DATA h) { - return h->nHybridQmfBands; -} - -INT FDKsbrEnc_GetHybridResolution(HANDLE_PS_HYBRID_DATA h, INT qmfBand); - - - -/*****************************************************************************/ -/* **** FILTERBANK **** */ - -HANDLE_ERROR_INFO -FDKsbrEnc_CreateHybridFilterBank ( HANDLE_PS_HYBRID *phHybrid, - INT ch ); - -HANDLE_ERROR_INFO -FDKsbrEnc_InitHybridFilterBank ( HANDLE_PS_HYBRID hHybrid, - HANDLE_PS_HYBRID_CONFIG hHybConfig, - INT frameSize ); - -HANDLE_ERROR_INFO -FDKsbrEnc_DeleteHybridFilterBank ( HANDLE_PS_HYBRID* phHybrid ); - -HANDLE_ERROR_INFO -HybridAnalysis ( HANDLE_PS_HYBRID hHybrid, - FIXP_QMF *const * const mQmfReal, - FIXP_QMF *const * const mQmfImag, - SCHAR sf_fixpQmf, - FIXP_QMF **mHybridReal, - FIXP_QMF **mHybridImag, - SCHAR *sf_fixpHybrid); - - -INT -FDKsbrEnc_GetHybridFilterDelay(HANDLE_PS_HYBRID hHybrid); - -#endif /*__hybrid_h*/ diff --git a/libSBRenc/src/sbr.h b/libSBRenc/src/sbr.h index 40a3953..c833db5 100644 --- a/libSBRenc/src/sbr.h +++ b/libSBRenc/src/sbr.h @@ -25,7 +25,7 @@ *******************************************************************************/ /*! \file - \brief Main SBR structs definitions $Revision: 36847 $ + \brief Main SBR structs definitions $Revision: 37142 $ */ #ifndef __SBR_H @@ -92,7 +92,6 @@ struct SBR_ENCODER UCHAR* dynamicRam; UCHAR* pSBRdynamic_RAM; - HANDLE_PSENC_CONFIG hPsEncConfig; HANDLE_PARAMETRIC_STEREO hParametricStereo; QMF_FILTER_BANK qmfSynthesisPS; diff --git a/libSBRenc/src/sbr_encoder.cpp b/libSBRenc/src/sbr_encoder.cpp index 9c3cf37..31dea4e 100644 --- a/libSBRenc/src/sbr_encoder.cpp +++ b/libSBRenc/src/sbr_encoder.cpp @@ -37,7 +37,6 @@ #include "qmf.h" #include "ps_main.h" -#include "psenc_hybrid.h" #define SBRENCODER_LIB_VL0 3 #define SBRENCODER_LIB_VL1 2 @@ -101,30 +100,76 @@ \return Index to the appropriate table ****************************************************************************/ +#define DISTANCE_CEIL_VALUE 5000000 static INT getSbrTuningTableIndex(UINT bitrate, /*! the total bitrate in bits/sec */ UINT numChannels,/*! the number of channels for the core coder */ UINT sampleRate, /*! the sampling rate of the core coder */ - AUDIO_OBJECT_TYPE core + AUDIO_OBJECT_TYPE core, + UINT *pBitRateClosest ) { - int i, paramSetTop; + int i, paramSetTop, bitRateClosestLowerIndex=-1, bitRateClosestUpperIndex=-1, found = 0; + UINT bitRateClosestUpper = 0, bitRateClosestLower=DISTANCE_CEIL_VALUE; + + FDK_ASSERT(SBRENC_TUNING_SIZE == sizeof(sbrTuningTable)/sizeof(sbrTuningTable[0])); if (core == AOT_ER_AAC_ELD) { paramSetTop = SBRENC_TUNING_SIZE; - i = 126; + i = SBRENC_AACLC_TUNING_SIZE; } else { - paramSetTop = 126; + paramSetTop = SBRENC_AACLC_TUNING_SIZE; i = 0; } for (; i < paramSetTop ; i++) { - if (numChannels == sbrTuningTable [i].numChannels) { - if ((sampleRate == sbrTuningTable [i].sampleRate) && - (bitrate >= sbrTuningTable [i].bitrateFrom) && + if ( numChannels == sbrTuningTable [i].numChannels + && sampleRate == sbrTuningTable [i].sampleRate ) + { + found = 1; + if ((bitrate >= sbrTuningTable [i].bitrateFrom) && (bitrate < sbrTuningTable [i].bitrateTo)) { + bitRateClosestLower = bitrate; + bitRateClosestUpper = bitrate; + //FDKprintf("entry %d\n", i); return i ; + } else { + if ( sbrTuningTable [i].bitrateFrom > bitrate ) { + if (sbrTuningTable [i].bitrateFrom < bitRateClosestLower) { + bitRateClosestLower = sbrTuningTable [i].bitrateFrom; + bitRateClosestLowerIndex = i; + } + } + if ( sbrTuningTable [i].bitrateTo <= bitrate ) { + if (sbrTuningTable [i].bitrateTo > bitRateClosestUpper) { + bitRateClosestUpper = sbrTuningTable [i].bitrateTo-1; + bitRateClosestUpperIndex = i; + } + } + } + } + } + + if (pBitRateClosest != NULL) + { + /* Is there was at least one matching tuning entry found then pick the least distance bit rate */ + if (found) + { + int distanceUpper=DISTANCE_CEIL_VALUE, distanceLower=DISTANCE_CEIL_VALUE; + if (bitRateClosestLowerIndex >= 0) { + distanceLower = sbrTuningTable [bitRateClosestLowerIndex].bitrateFrom - bitrate; } + if (bitRateClosestUpperIndex >= 0) { + distanceUpper = bitrate - sbrTuningTable [bitRateClosestUpperIndex].bitrateTo; + } + if ( distanceUpper < distanceLower ) + { + *pBitRateClosest = bitRateClosestUpper; + } else { + *pBitRateClosest = bitRateClosestLower; + } + } else { + *pBitRateClosest = 0; } } @@ -141,14 +186,46 @@ getSbrTuningTableIndex(UINT bitrate, /*! the total bitrate in bits/sec */ ****************************************************************************/ static INT -getPsTuningTableIndex(UINT bitrate){ +getPsTuningTableIndex(UINT bitrate, UINT *pBitRateClosest){ INT i, paramSets = sizeof (psTuningTable) / sizeof (psTuningTable [0]); + int bitRateClosestLowerIndex=-1, bitRateClosestUpperIndex=-1; + UINT bitRateClosestUpper = 0, bitRateClosestLower=DISTANCE_CEIL_VALUE; for (i = 0 ; i < paramSets ; i++) { if ((bitrate >= psTuningTable [i].bitrateFrom) && (bitrate < psTuningTable [i].bitrateTo)) { return i ; + } else { + if ( psTuningTable [i].bitrateFrom > bitrate ) { + if (psTuningTable [i].bitrateFrom < bitRateClosestLower) { + bitRateClosestLower = psTuningTable [i].bitrateFrom; + bitRateClosestLowerIndex = i; + } + } + if ( psTuningTable [i].bitrateTo <= bitrate ) { + if (psTuningTable [i].bitrateTo > bitRateClosestUpper) { + bitRateClosestUpper = psTuningTable [i].bitrateTo-1; + bitRateClosestUpperIndex = i; + } + } + } + } + + if (pBitRateClosest != NULL) + { + int distanceUpper=DISTANCE_CEIL_VALUE, distanceLower=DISTANCE_CEIL_VALUE; + if (bitRateClosestLowerIndex >= 0) { + distanceLower = sbrTuningTable [bitRateClosestLowerIndex].bitrateFrom - bitrate; + } + if (bitRateClosestUpperIndex >= 0) { + distanceUpper = bitrate - sbrTuningTable [bitRateClosestUpperIndex].bitrateTo; + } + if ( distanceUpper < distanceLower ) + { + *pBitRateClosest = bitRateClosestUpper; + } else { + *pBitRateClosest = bitRateClosestLower; } } @@ -197,7 +274,7 @@ FDKsbrEnc_IsSbrSettingAvail (UINT bitrate, /*! the total bitrate in bit /* try DOWN_SMPL_FAC of the input sampling rate */ sampleRateCore = sampleRateInput/DOWN_SMPL_FAC; - idx = getSbrTuningTableIndex(bitrate, numOutputChannels, sampleRateCore, core); + idx = getSbrTuningTableIndex(bitrate, numOutputChannels, sampleRateCore, core, NULL); return (idx == INVALID_TABLE_IDX ? 0 : 1); } @@ -257,7 +334,7 @@ FDKsbrEnc_AdjustSbrSettings (const sbrConfigurationPtr config, /*! output, modif } } - idx = getSbrTuningTableIndex(bitRate,numChannels,fsCore, core); + idx = getSbrTuningTableIndex(bitRate,numChannels,fsCore, core, NULL); if (idx != INVALID_TABLE_IDX) { config->startFreq = sbrTuningTable[idx].startFreq ; @@ -492,8 +569,6 @@ void sbrEncoder_Close (HANDLE_SBR_ENCODER *phSbrEncoder) } - if (hSbrEncoder->hPsEncConfig) - FreeRam_PsEncConf(&hSbrEncoder->hPsEncConfig); if (hSbrEncoder->hParametricStereo) PSEnc_Destroy(&hSbrEncoder->hParametricStereo); if (hSbrEncoder->qmfSynthesisPS.FilterStates) @@ -801,8 +876,8 @@ FDKsbrEnc_EnvEncodeFrame(HANDLE_SBR_ENCODER hEnvEncoder, /* Obtain pointers to QMF buffers. */ - pQmfReal = sbrExtrEnv->rBuffer+sbrExtrEnv->rBufferWriteOffset; - pQmfImag = sbrExtrEnv->iBuffer+sbrExtrEnv->rBufferWriteOffset; + pQmfReal = sbrExtrEnv->rBuffer; + pQmfImag = sbrExtrEnv->iBuffer; qmfAnalysisFiltering( hSbrElement->hQmfAnalysis[ch], pQmfReal, @@ -822,33 +897,8 @@ FDKsbrEnc_EnvEncodeFrame(HANDLE_SBR_ENCODER hEnvEncoder, /* Parametric Stereo processing */ - if(hSbrElement->elInfo.fParametricStereo) + if (hSbrElement->elInfo.fParametricStereo) { - int psCh; - - /* Parametric Stereo QMF buffer preprocessing: copy previous qmf data down */ - UpdatePSQmfData_second(hEnvEncoder->hParametricStereo); - - for (psCh = 0; psCh<2; psCh ++) - { - C_ALLOC_SCRATCH_START(qmfWorkBuffer, FIXP_DBL, QMF_CHANNELS*2); - HANDLE_PS_QMF_DATA hPsQmfData = hEnvEncoder->hParametricStereo->hPsChannelData[psCh]->hPsQmfData; - QMF_SCALE_FACTOR tmpScale; - - - qmfAnalysisFiltering( hSbrElement->hQmfAnalysis[psCh], - hPsQmfData->rQmfData + hPsQmfData->bufferWriteOffset, - hPsQmfData->iQmfData + hPsQmfData->bufferWriteOffset, - &tmpScale, - samples + hSbrElement->elInfo.ChannelIndex[psCh], - timeInStride, - qmfWorkBuffer ); - - C_ALLOC_SCRATCH_END(qmfWorkBuffer, FIXP_DBL, QMF_CHANNELS*2); - - hEnvEncoder->hParametricStereo->hPsChannelData[psCh]->psQmfScale = -tmpScale.lb_scale; - } - /* Limit Parametric Stereo to one instance */ FDK_ASSERT(ch == 0); @@ -867,10 +917,13 @@ FDKsbrEnc_EnvEncodeFrame(HANDLE_SBR_ENCODER hEnvEncoder, o downmixed qmf data is written to sbrExtrEnv->rBuffer and sbrExtrEnv->iBuffer */ SCHAR qmfScale; + INT_PCM* pSamples[2] = {samples + hSbrElement->elInfo.ChannelIndex[0],samples + hSbrElement->elInfo.ChannelIndex[1]}; error = FDKsbrEnc_PSEnc_ParametricStereoProcessing( hEnvEncoder->hParametricStereo, + pSamples, + timeInStride, + hSbrElement->hQmfAnalysis, sbrExtrEnv->rBuffer, sbrExtrEnv->iBuffer, - sbrExtrEnv->rBufferWriteOffset, samples + hSbrElement->elInfo.ChannelIndex[ch], &hEnvEncoder->qmfSynthesisPS, &qmfScale, @@ -1266,11 +1319,6 @@ INT sbrEncoder_Open( } if (supportPS) { - hSbrEncoder->hPsEncConfig = GetRam_PsEncConf(); - if (hSbrEncoder->hPsEncConfig==NULL) { - goto bail; - } - if (PSEnc_Create(&hSbrEncoder->hParametricStereo)) { goto bail; @@ -1582,6 +1630,32 @@ INT FDKsbrEnc_DelayCompensation ( return 0; } +UINT sbrEncoder_LimitBitRate(UINT bitRate, UINT numChannels, UINT coreSampleRate, AUDIO_OBJECT_TYPE aot) +{ + UINT newBitRate; + INT index; + + FDK_ASSERT(numChannels > 0 && numChannels <= 2); + if (aot == AOT_PS) { + if (numChannels == 2) { + index = getPsTuningTableIndex(bitRate, &newBitRate); + if (index == INVALID_TABLE_IDX) { + bitRate = newBitRate; + } + /* Set numChannels to 1 because for PS we need a SBR SCE (mono) element. */ + numChannels = 1; + } else { + return 0; + } + } + index = getSbrTuningTableIndex(bitRate, numChannels, coreSampleRate, aot, &newBitRate); + if (index != INVALID_TABLE_IDX) { + newBitRate = bitRate; + } + + return newBitRate; +} + INT sbrEncoder_Init( HANDLE_SBR_ENCODER hSbrEncoder, @@ -1894,22 +1968,23 @@ INT sbrEncoder_Init( /* initialize parametric stereo */ if (usePs) { + PSENC_CONFIG psEncConfig; FDK_ASSERT(hSbrEncoder->noElements == 1); - INT psTuningTableIdx = getPsTuningTableIndex(elInfo[0].bitRate); //sbrConfig.codecSettings.bitRate); + INT psTuningTableIdx = getPsTuningTableIndex(elInfo[0].bitRate, NULL); - hSbrEncoder->hPsEncConfig->frameSize = *frameLength; //sbrConfig.sbrFrameSize; - hSbrEncoder->hPsEncConfig->qmfFilterMode = 0; - hSbrEncoder->hPsEncConfig->sbrPsDelay = 0; + psEncConfig.frameSize = *frameLength; //sbrConfig.sbrFrameSize; + psEncConfig.qmfFilterMode = 0; + psEncConfig.sbrPsDelay = 0; /* tuning parameters */ if (psTuningTableIdx != INVALID_TABLE_IDX) { - hSbrEncoder->hPsEncConfig->nStereoBands = psTuningTable[psTuningTableIdx].nStereoBands; - hSbrEncoder->hPsEncConfig->maxEnvelopes = psTuningTable[psTuningTableIdx].nEnvelopes; - hSbrEncoder->hPsEncConfig->iidQuantErrorThreshold = (FIXP_DBL)psTuningTable[psTuningTableIdx].iidQuantErrorThreshold; + psEncConfig.nStereoBands = psTuningTable[psTuningTableIdx].nStereoBands; + psEncConfig.maxEnvelopes = psTuningTable[psTuningTableIdx].nEnvelopes; + psEncConfig.iidQuantErrorThreshold = (FIXP_DBL)psTuningTable[psTuningTableIdx].iidQuantErrorThreshold; /* calculation is not quite linear, increased number of envelopes causes more bits */ /* assume avg. 50 bits per frame for 10 stereo bands / 1 envelope configuration */ - hSbrEncoder->estimateBitrate += ( (((*sampleRate) * 5 * hSbrEncoder->hPsEncConfig->nStereoBands * hSbrEncoder->hPsEncConfig->maxEnvelopes) / hSbrEncoder->frameSize)); + hSbrEncoder->estimateBitrate += ( (((*sampleRate) * 5 * psEncConfig.nStereoBands * psEncConfig.maxEnvelopes) / hSbrEncoder->frameSize)); } else { error = ERROR(CDI, "Invalid ps tuning table index."); @@ -1926,10 +2001,10 @@ INT sbrEncoder_Init( if(errorInfo == noError){ /* update delay */ - hSbrEncoder->hPsEncConfig->sbrPsDelay = FDKsbrEnc_GetEnvEstDelay(&hSbrEncoder->sbrElement[0]->sbrChannel[0]->hEnvChannel.sbrExtractEnvelope); + psEncConfig.sbrPsDelay = FDKsbrEnc_GetEnvEstDelay(&hSbrEncoder->sbrElement[0]->sbrChannel[0]->hEnvChannel.sbrExtractEnvelope); if(noError != (errorInfo = PSEnc_Init( hSbrEncoder->hParametricStereo, - hSbrEncoder->hPsEncConfig, + &psEncConfig, hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfSlots, hSbrEncoder->sbrElement[0]->sbrConfigData.noQmfBands ,hSbrEncoder->dynamicRam diff --git a/libSBRenc/src/sbr_ram.cpp b/libSBRenc/src/sbr_ram.cpp index 289270c..2413059 100644 --- a/libSBRenc/src/sbr_ram.cpp +++ b/libSBRenc/src/sbr_ram.cpp @@ -26,7 +26,7 @@ /*! \file \brief Memory layout - $Revision: 36847 $ + $Revision: 37142 $ This module declares all static and dynamic memory spaces */ @@ -114,39 +114,10 @@ C_ALLOC_MEM2 (Ram_Sbr_guideVectorOrig, FIXP_DBL, (MAX_NO_OF_ESTIMATES*MAX_FREQ_C */ C_AALLOC_MEM_L(Ram_PsQmfStatesSynthesis, FIXP_DBL, QMF_FILTER_LENGTH/2, SECT_DATA_L1) -C_ALLOC_MEM (Ram_PsEnvRBuffer, FIXP_DBL, QMF_MAX_TIME_SLOTS*QMF_CHANNELS/2) -C_ALLOC_MEM (Ram_PsEnvIBuffer, FIXP_DBL, QMF_MAX_TIME_SLOTS*QMF_CHANNELS/2) -C_ALLOC_MEM2 (Ram_PsChData, PS_CHANNEL_DATA, 1, MAX_PS_CHANNELS) -C_ALLOC_MEM (Ram_PsEncConf, PSENC_CONFIG, 1) C_ALLOC_MEM_L (Ram_PsEncode, PS_ENCODE, 1, SECT_DATA_L1) -C_ALLOC_MEM (Ram_PsData, PS_DATA, 1) C_ALLOC_MEM (Ram_ParamStereo, PARAMETRIC_STEREO, 1) -C_ALLOC_MEM2 (Ram_PsOut, PS_OUT, 1, 2) -/* QMF data - */ -C_ALLOC_MEM (Ram_PsQmfNewSamples, FIXP_DBL, QMF_CHANNELS) - -C_ALLOC_MEM2 (Ram_PsQmfData, PS_QMF_DATA, 1, MAX_PS_CHANNELS) - -/* HYBRID data - */ -C_AALLOC_MEM (Ram_PsHybFFT, FIXP_DBL, 16) - -C_ALLOC_MEM2(Ram_HybData, PS_HYBRID_DATA, 1, MAX_PS_CHANNELS) -C_ALLOC_MEM2(Ram_PsHybrid, PS_HYBRID, 1, MAX_PS_CHANNELS) -C_ALLOC_MEM (Ram_PsHybConfig, PS_HYBRID_CONFIG, 1) - -C_ALLOC_MEM2(Ram_PsRhyb, FIXP_QMF, ((HYBRID_FRAMESIZE+HYBRID_WRITEOFFSET)*HYBRID_NUM_BANDS), MAX_PS_CHANNELS) -C_ALLOC_MEM2(Ram_PsIhyb, FIXP_QMF, ((HYBRID_FRAMESIZE+HYBRID_WRITEOFFSET)*HYBRID_NUM_BANDS), MAX_PS_CHANNELS) - -C_ALLOC_MEM (Ram_PsHybWkReal, FIXP_QMF, (HYBRID_FRAMESIZE + QMF_BUFFER_MOVE)) -C_ALLOC_MEM (Ram_PsHybWkImag, FIXP_QMF, (HYBRID_FRAMESIZE + QMF_BUFFER_MOVE)) - -C_ALLOC_MEM2(Ram_PsMtmpReal, FIXP_QMF, (MAX_HYBRID_RES), HYBRID_FRAMESIZE) -C_ALLOC_MEM2(Ram_PsMtmpImag, FIXP_QMF, (MAX_HYBRID_RES), HYBRID_FRAMESIZE) - /* @} */ @@ -175,38 +146,11 @@ C_ALLOC_MEM2(Ram_PsMtmpImag, FIXP_QMF, (MAX_HYBRID_RES), HYBRID_FRAMESIZE) /* The SBR encoder uses a single channel overlapping buffer set (always n=0), but PS does not. */ FIXP_DBL* GetRam_Sbr_envRBuffer (int n, UCHAR* dynamic_RAM) { FDK_ASSERT(dynamic_RAM!=0); - return ((FIXP_DBL*) (dynamic_RAM + OFFSET_QMF + (n*ENV_R_BUFF_BYTE*2) )); + return ((FIXP_DBL*) (dynamic_RAM + OFFSET_QMF + (n*(ENV_R_BUFF_BYTE+ENV_I_BUFF_BYTE)) )); } FIXP_DBL* GetRam_Sbr_envIBuffer (int n, UCHAR* dynamic_RAM) { FDK_ASSERT(dynamic_RAM!=0); - //return ((FIXP_DBL*) (dynamic_RAM + OFFSET_QMF + (MAX_NUM_CHANNELS*ENV_R_BUFF_BYTE) + n*ENV_I_BUFF_BYTE)); - return ((FIXP_DBL*) (dynamic_RAM + OFFSET_QMF + (ENV_R_BUFF_BYTE) + (n*ENV_I_BUFF_BYTE*2))); - } - - /* reuse QMF buffer in PS module. We Require space to hold 2 channels. */ - C_ALLOC_MEM2(Ram_PsRqmf, FIXP_QMF, ((PSENC_QMF_BUFFER_LENGTH-QMF_MAX_TIME_SLOTS)*(QMF_CHANNELS)), MAX_PS_CHANNELS) - C_ALLOC_MEM2(Ram_PsIqmf, FIXP_QMF, ((PSENC_QMF_BUFFER_LENGTH-QMF_MAX_TIME_SLOTS)*(QMF_CHANNELS)), MAX_PS_CHANNELS) - - FIXP_QMF* FDKsbrEnc_SliceRam_PsRqmf(FIXP_DBL* rQmfData, UCHAR* dynamic_RAM, int ch, int i, int qmfSlots) - { - FDK_ASSERT(dynamic_RAM!=0); - if (i>1)-6 ) -#define HYBRID_DATA_READ_OFFSET ( 0 ) -#define QMF_READ_OFFSET ( 0 ) - - H_ALLOC_MEM(Ram_PsRqmf, FIXP_DBL) - H_ALLOC_MEM(Ram_PsIqmf, FIXP_DBL) FIXP_DBL* FDKsbrEnc_SliceRam_PsRqmf (FIXP_DBL* rQmfData, UCHAR* dynamic_RAM, int n, int i, int qmfSlots); FIXP_DBL* FDKsbrEnc_SliceRam_PsIqmf (FIXP_DBL* iQmfData, UCHAR* dynamic_RAM, int n, int i, int qmfSlots); - H_ALLOC_MEM(Ram_PsQmfData, PS_QMF_DATA) - H_ALLOC_MEM(Ram_PsChData, PS_CHANNEL_DATA) - H_ALLOC_MEM(Ram_ParamStereo, PARAMETRIC_STEREO) - H_ALLOC_MEM(Ram_PsOut, PS_OUT) - - /* HYBRID */ - H_ALLOC_MEM(Ram_PsHybFFT, FIXP_DBL) - - H_ALLOC_MEM(Ram_HybData, PS_HYBRID_DATA) - H_ALLOC_MEM(Ram_PsRhyb, FIXP_DBL) - H_ALLOC_MEM(Ram_PsIhyb, FIXP_DBL) - - H_ALLOC_MEM(Ram_PsHybConfig, PS_HYBRID_CONFIG) - H_ALLOC_MEM(Ram_PsHybrid, PS_HYBRID) - - FIXP_DBL* psMqmfBufferRealInit (INT ch, INT i); - FIXP_DBL* psMqmfBufferImagInit (INT ch, INT i); - - - /* working buffer */ - H_ALLOC_MEM(Ram_PsHybWkReal, FIXP_DBL) - H_ALLOC_MEM(Ram_PsHybWkImag, FIXP_DBL) - - H_ALLOC_MEM(Ram_PsMtmpReal, FIXP_DBL) - H_ALLOC_MEM(Ram_PsMtmpImag, FIXP_DBL) diff --git a/libSBRenc/src/sbr_rom.cpp b/libSBRenc/src/sbr_rom.cpp index e83a519..77cef12 100644 --- a/libSBRenc/src/sbr_rom.cpp +++ b/libSBRenc/src/sbr_rom.cpp @@ -25,7 +25,7 @@ /*! \file \brief Definition of constant tables - $Revision: 36914 $ + $Revision: 37577 $ This module contains most of the constant data that can be stored in ROM. */ @@ -623,8 +623,8 @@ const sbrTuningTable_t sbrTuningTable[SBRENC_TUNING_SIZE] = /* 22.05/44.1 kHz dual rate */ { 8000, 11369, 22050, 1, 1, 1, 1, 1, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 8 kbit/s */ /**changed (not changed !!)*/ { 11369, 16000, 22050, 1, 1, 0, 3, 3, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 12 kbit/s */ - { 16000, 18000, 22050, 1, 1, 0, 4, 3, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 16 kbit/s */ - { 18000, 22000, 22050, 1, 1, 2, 5, 4, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 20 kbit/s */ + { 16000, 18000, 22050, 1, 2, 4, 4, 3, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 16 kbit/s */ + { 18000, 22000, 22050, 1, 4, 4, 5, 5, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 20 kbit/s */ { 22000, 28000, 22050, 1, 4, 4, 6, 5, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 24 kbit/s */ { 28000, 36000, 22050, 1, 7, 8, 8, 8, 2, 0, 3, SBR_MONO, 2 }, /* nominal: 32 kbit/s */ { 36000, 44000, 22050, 1, 9, 9, 9, 9, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 40 kbit/s */ @@ -634,8 +634,8 @@ const sbrTuningTable_t sbrTuningTable[SBRENC_TUNING_SIZE] = /* 24/48 kHz dual rate */ { 8000, 12000, 24000, 1, 1, 1, 1, 1, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 8 kbit/s */ /**changed (not changed !!)*/ { 12000, 16000, 24000, 1, 1, 0, 3, 3, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 12 kbit/s */ - { 16000, 18000, 24000, 1, 1, 0, 4, 3, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 16 kbit/s */ - { 18000, 22000, 24000, 1, 1, 1, 4, 4, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 20 kbit/s */ + { 16000, 18000, 24000, 1, 2, 4, 4, 3, 1, 0, 6, SBR_MONO, 3 }, /* nominal: 16 kbit/s */ + { 18000, 22000, 24000, 1, 4, 4, 5, 5, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 20 kbit/s */ { 22000, 28000, 24000, 1, 4, 4, 6, 5, 2, 0, 6, SBR_MONO, 2 }, /* nominal: 24 kbit/s */ { 28000, 36000, 24000, 1, 6, 8, 8, 8, 2, 0, 3, SBR_MONO, 2 }, /* nominal: 32 kbit/s */ { 36000, 44000, 24000, 1, 8, 9, 9, 9, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 40 kbit/s */ @@ -643,7 +643,6 @@ const sbrTuningTable_t sbrTuningTable[SBRENC_TUNING_SIZE] = { 52000, 64001, 24000, 1, 13,11,11,10, 2, 0, 3, SBR_MONO, 1 }, /* nominal: 48 kbit/s */ /* 22.05/44.1 kHz dual rate */ - { 16000, 24000, 22050, 2, 0, 0, 0, 0, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 20 kbit/s */ { 24000, 28000, 22050, 2, 3, 2, 5, 4, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 24 kbit/s */ { 28000, 32000, 22050, 2, 3, 2, 7, 6, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 28 kbit/s */ { 32000, 36000, 22050, 2, 5, 4, 7, 6, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 32 kbit/s */ @@ -655,7 +654,6 @@ const sbrTuningTable_t sbrTuningTable[SBRENC_TUNING_SIZE] = { 82000,128001, 22050, 2, 13,12,11,11, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 80 kbit/s */ /* 24/48 kHz dual rate */ - { 16000, 24000, 24000, 2, 0, 0, 0, 0, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 20 kbit/s */ { 24000, 28000, 24000, 2, 3, 3, 5, 5, 1, 0, -3, SBR_SWITCH_LRC, 3 }, /* nominal: 24 kbit/s */ { 28000, 36000, 24000, 2, 5, 4, 7, 6, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 32 kbit/s */ { 36000, 44000, 24000, 2, 4, 8, 8, 8, 2, 0, -3, SBR_SWITCH_LRC, 2 }, /* nominal: 40 kbit/s */ @@ -664,6 +662,8 @@ const sbrTuningTable_t sbrTuningTable[SBRENC_TUNING_SIZE] = { 60000, 76000, 24000, 2, 11,12,10,11, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 64 kbit/s */ { 76000, 88000, 24000, 2, 12,13,11,11, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 80 kbit/s */ { 88000,128001, 24000, 2, 13,13,11,11, 3, 0, -3, SBR_LEFT_RIGHT, 1 }, /* nominal: 92 kbit/s */ + + }; const psTuningTable_t psTuningTable[4] = diff --git a/libSBRenc/src/sbr_rom.h b/libSBRenc/src/sbr_rom.h index 696a54c..68135cb 100644 --- a/libSBRenc/src/sbr_rom.h +++ b/libSBRenc/src/sbr_rom.h @@ -26,7 +26,7 @@ /*! \file \brief Declaration of constant tables -$Revision: 36847 $ +$Revision: 37577 $ */ #ifndef __SBR_ROM_H #define __SBR_ROM_H @@ -60,7 +60,11 @@ extern const UCHAR v_Huff_NoiseLevelL11T[63]; extern const INT bookSbrNoiseBalanceC11T[25]; extern const UCHAR bookSbrNoiseBalanceL11T[25]; -#define SBRENC_TUNING_SIZE (126 + 37) +#define SBRENC_AACLC_TUNING_SIZE 124 +#define SBRENC_AACELD_TUNING_SIZE 35 +#define SBRENC_AACELD2_TUNING_SIZE 31 + +#define SBRENC_TUNING_SIZE (SBRENC_AACLC_TUNING_SIZE + SBRENC_AACELD_TUNING_SIZE) extern const sbrTuningTable_t sbrTuningTable[SBRENC_TUNING_SIZE]; diff --git a/libSYS/include/FDK_audio.h b/libSYS/include/FDK_audio.h index 1d28187..6003eb3 100644 --- a/libSYS/include/FDK_audio.h +++ b/libSYS/include/FDK_audio.h @@ -236,6 +236,7 @@ typedef enum { #define CC_IS_BASELAYER 0x00200000 #define CC_PROTECTION 0x00400000 #define CC_SBR 0x00800000 +#define CC_SBRCRC 0x00010000 #define CC_RVLC 0x01000000 #define CC_VCB11 0x02000000 #define CC_HCR 0x04000000 @@ -284,6 +285,11 @@ typedef enum ID_LAST } MP4_ELEMENT_ID; +#define IS_CHANNEL_ELEMENT(elementId) \ + ((elementId) == ID_SCE \ +|| (elementId) == ID_CPE \ +|| (elementId) == ID_LFE) + #define EXT_ID_BITS 4 /**< Size in bits of extension payload type tags. */ /** Extension payload types. */ diff --git a/libSYS/include/genericStds.h b/libSYS/include/genericStds.h index 8009050..d1058b9 100644 --- a/libSYS/include/genericStds.h +++ b/libSYS/include/genericStds.h @@ -40,7 +40,7 @@ /* Always increase verbosity of memory allocation in case of a debug built. DEBUG is defined globally in that case. */ #if defined(DEBUG) || defined(FDK_DEBUG) -#define MEMORY_MEASUREMENT +//#define MEMORY_MEASUREMENT #endif #ifndef M_PI -- cgit v1.2.3