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