Restructure QMF implementation and provide 16/32 bit implementation in parallel.

Bug: 149514474
Test: atest DecoderTestXheAac DecoderTestAacDrc
Change-Id: I2c6b332a0b5c4966a3f680d7a4d562d9bf18752c
This commit is contained in:
Fraunhofer IIS FDK 2019-12-19 17:27:25 +01:00 committed by Jean-Michel Trivi
parent 443d38963e
commit 5482443193
5 changed files with 334 additions and 389 deletions

View File

@ -1,7 +1,7 @@
/* -----------------------------------------------------------------------------
Software License for The Fraunhofer FDK AAC Codec Library for Android
© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
Forschung e.V. All rights reserved.
1. INTRODUCTION
@ -145,15 +145,15 @@ H_ALLOC_MEM_OVERLAY(QmfWorkBufferCore6, FIXP_DBL)
#define QMF_DOMAIN_OV_TIMESLOTS_16 (3)
#define QMF_DOMAIN_OV_TIMESLOTS_32 (6)
H_ALLOC_MEM(AnaQmfStates, FIXP_QAS)
H_ALLOC_MEM(AnaQmfStates, FIXP_DBL)
H_ALLOC_MEM(SynQmfStates, FIXP_QSS)
H_ALLOC_MEM(QmfSlotsReal, FIXP_DBL *)
H_ALLOC_MEM(QmfSlotsImag, FIXP_DBL *)
H_ALLOC_MEM(QmfOverlapBuffer, FIXP_DBL)
H_ALLOC_MEM(AnaQmfStates16, FIXP_QAS)
H_ALLOC_MEM(AnaQmfStates24, FIXP_QAS)
H_ALLOC_MEM(AnaQmfStates32, FIXP_QAS)
H_ALLOC_MEM(AnaQmfStates16, FIXP_DBL)
H_ALLOC_MEM(AnaQmfStates24, FIXP_DBL)
H_ALLOC_MEM(AnaQmfStates32, FIXP_DBL)
H_ALLOC_MEM(QmfSlotsReal16, FIXP_DBL *)
H_ALLOC_MEM(QmfSlotsReal32, FIXP_DBL *)
H_ALLOC_MEM(QmfSlotsImag16, FIXP_DBL *)
@ -244,7 +244,7 @@ typedef struct {
(workBuf_nTimeSlots * workBuf_nBands * CMPLX_MOD). */
USHORT workBufferOffset; /*!< Offset within work buffer. */
USHORT workBufferSectSize; /*!< Size of work buffer section. */
FIXP_QAS *
FIXP_DBL *
pAnaQmfStates; /*!< Pointer to QMF analysis states (persistent memory). */
FIXP_DBL
*pOverlapBuffer; /*!< Pointer to QMF overlap/delay memory (persistent

View File

@ -1,7 +1,7 @@
/* -----------------------------------------------------------------------------
Software License for The Fraunhofer FDK AAC Codec Library for Android
© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
Forschung e.V. All rights reserved.
1. INTRODUCTION
@ -116,6 +116,7 @@ amm-info@iis.fraunhofer.de
#define FIXP_QAS FIXP_PCM
#define QAS_BITS SAMPLE_BITS
#define INT_PCM_QMFIN INT_PCM
#define FIXP_QSS FIXP_DBL
#define QSS_BITS DFRACT_BITS
@ -201,16 +202,25 @@ struct QMF_FILTER_BANK {
typedef struct QMF_FILTER_BANK *HANDLE_QMF_FILTER_BANK;
void qmfAnalysisFiltering(
HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank */
FIXP_DBL **qmfReal, /*!< Pointer to real subband slots */
FIXP_DBL **qmfImag, /*!< Pointer to imag subband slots */
QMF_SCALE_FACTOR *scaleFactor, /*!< Scale factors of QMF data */
const LONG *timeIn, /*!< Time signal */
const int timeIn_e, /*!< Exponent of audio data */
const int stride, /*!< Stride factor of audio data */
FIXP_DBL *pWorkBuffer /*!< pointer to temporary working buffer */
);
int qmfInitAnalysisFilterBank(
HANDLE_QMF_FILTER_BANK h_Qmf, /*!< QMF Handle */
FIXP_QAS *pFilterStates, /*!< Pointer to filter state buffer */
int noCols, /*!< Number of time slots */
int lsb, /*!< Number of lower bands */
int usb, /*!< Number of upper bands */
int no_channels, /*!< Number of critically sampled bands */
int flags); /*!< Flags */
#if SAMPLE_BITS == 16
int qmfInitAnalysisFilterBank(
HANDLE_QMF_FILTER_BANK h_Qmf, /*!< QMF Handle */
FIXP_DBL *pFilterStates, /*!< Pointer to filter state buffer */
int noCols, /*!< Number of time slots */
int lsb, /*!< Number of lower bands */
int usb, /*!< Number of upper bands */
int no_channels, /*!< Number of critically sampled bands */
int flags); /*!< Flags */
#endif
void qmfAnalysisFiltering(
HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank */
@ -222,6 +232,48 @@ void qmfAnalysisFiltering(
const int stride, /*!< Stride factor of audio data */
FIXP_DBL *pWorkBuffer /*!< pointer to temporal working buffer */
);
#if SAMPLE_BITS == 16
void qmfAnalysisFiltering(
HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank */
FIXP_DBL **qmfReal, /*!< Pointer to real subband slots */
FIXP_DBL **qmfImag, /*!< Pointer to imag subband slots */
QMF_SCALE_FACTOR *scaleFactor, /*!< Scale factors of QMF data */
const LONG *timeIn, /*!< Time signal */
const int timeIn_e, /*!< Exponent of audio data */
const int stride, /*!< Stride factor of audio data */
FIXP_DBL *pWorkBuffer /*!< pointer to temporary working buffer */
);
#endif
void qmfAnalysisFilteringSlot(
HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Synthesis Bank */
FIXP_DBL *qmfReal, /*!< Low and High band, real */
FIXP_DBL *qmfImag, /*!< Low and High band, imag */
const INT_PCM *timeIn, /*!< Pointer to input */
const int stride, /*!< stride factor of input */
FIXP_DBL *pWorkBuffer /*!< pointer to temporal working buffer */
);
#if SAMPLE_BITS == 16
void qmfAnalysisFilteringSlot(
HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Synthesis Bank */
FIXP_DBL *qmfReal, /*!< Low and High band, real */
FIXP_DBL *qmfImag, /*!< Low and High band, imag */
const LONG *timeIn, /*!< Pointer to input */
const int stride, /*!< stride factor of input */
FIXP_DBL *pWorkBuffer /*!< pointer to temporary working buffer */
);
#endif
int qmfInitSynthesisFilterBank(
HANDLE_QMF_FILTER_BANK h_Qmf, /*!< QMF Handle */
FIXP_QSS *pFilterStates, /*!< Pointer to filter state buffer */
int noCols, /*!< Number of time slots */
int lsb, /*!< Number of lower bands */
int usb, /*!< Number of upper bands */
int no_channels, /*!< Number of critically sampled bands */
int flags); /*!< Flags */
void qmfSynthesisFiltering(
HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */
@ -234,41 +286,19 @@ void qmfSynthesisFiltering(
FIXP_DBL *pWorkBuffer /*!< pointer to temporary working buffer. It must be
aligned */
);
#if SAMPLE_BITS == 16
int qmfInitAnalysisFilterBank(
HANDLE_QMF_FILTER_BANK h_Qmf, /*!< QMF Handle */
FIXP_QAS *pFilterStates, /*!< Pointer to filter state buffer */
int noCols, /*!< Number of time slots */
int lsb, /*!< Number of lower bands */
int usb, /*!< Number of upper bands */
int no_channels, /*!< Number of critically sampled bands */
int flags); /*!< Flags */
void qmfAnalysisFilteringSlot(
HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Synthesis Bank */
FIXP_DBL *qmfReal, /*!< Low and High band, real */
FIXP_DBL *qmfImag, /*!< Low and High band, imag */
const LONG *timeIn, /*!< Pointer to input */
const int stride, /*!< stride factor of input */
FIXP_DBL *pWorkBuffer /*!< pointer to temporary working buffer */
void qmfSynthesisFiltering(
HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */
FIXP_DBL **QmfBufferReal, /*!< Pointer to real subband slots */
FIXP_DBL **QmfBufferImag, /*!< Pointer to imag subband slots */
const QMF_SCALE_FACTOR *scaleFactor, /*!< Scale factors of QMF data */
const int ov_len, /*!< Length of band overlap */
LONG *timeOut, /*!< Time signal */
const int timeOut_e, /*!< Target exponent for timeOut */
FIXP_DBL *pWorkBuffer /*!< pointer to temporary working buffer */
);
void qmfAnalysisFilteringSlot(
HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Synthesis Bank */
FIXP_DBL *qmfReal, /*!< Low and High band, real */
FIXP_DBL *qmfImag, /*!< Low and High band, imag */
const INT_PCM *timeIn, /*!< Pointer to input */
const int stride, /*!< stride factor of input */
FIXP_DBL *pWorkBuffer /*!< pointer to temporal working buffer */
);
int qmfInitSynthesisFilterBank(
HANDLE_QMF_FILTER_BANK h_Qmf, /*!< QMF Handle */
FIXP_QSS *pFilterStates, /*!< Pointer to filter state buffer */
int noCols, /*!< Number of time slots */
int lsb, /*!< Number of lower bands */
int usb, /*!< Number of upper bands */
int no_channels, /*!< Number of critically sampled bands */
int flags); /*!< Flags */
#endif
void qmfSynthesisFilteringSlot(HANDLE_QMF_FILTER_BANK synQmf,
const FIXP_DBL *realSlot,
@ -276,6 +306,15 @@ void qmfSynthesisFilteringSlot(HANDLE_QMF_FILTER_BANK synQmf,
const int scaleFactorLowBand,
const int scaleFactorHighBand, INT_PCM *timeOut,
const int timeOut_e, FIXP_DBL *pWorkBuffer);
#if SAMPLE_BITS == 16
void qmfSynthesisFilteringSlot(HANDLE_QMF_FILTER_BANK synQmf,
const FIXP_DBL *realSlot,
const FIXP_DBL *imagSlot,
const int scaleFactorLowBand,
const int scaleFactorHighBand, LONG *timeOut,
const int timeOut_e, FIXP_DBL *pWorkBuffer);
#endif
void qmfChangeOutScalefactor(
HANDLE_QMF_FILTER_BANK synQmf, /*!< Handle of Qmf Synthesis Bank */
@ -291,11 +330,5 @@ void qmfChangeOutGain(
FIXP_DBL outputGain, /*!< New gain for output data (mantissa) */
int outputGainScale /*!< New gain for output data (exponent) */
);
void qmfSynPrototypeFirSlot(
HANDLE_QMF_FILTER_BANK qmf,
FIXP_DBL *RESTRICT realSlot, /*!< Input: Pointer to real Slot */
FIXP_DBL *RESTRICT imagSlot, /*!< Input: Pointer to imag Slot */
INT_PCM *RESTRICT timeOut, /*!< Time domain data */
const int timeOut_e);
#endif /*ifndef QMF_H */

View File

@ -1,7 +1,7 @@
/* -----------------------------------------------------------------------------
Software License for The Fraunhofer FDK AAC Codec Library for Android
© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
Forschung e.V. All rights reserved.
1. INTRODUCTION
@ -402,4 +402,220 @@ void qmfSynthesisFiltering(
timeOut + (i * L * stride), stride, pWorkBuffer);
} /* no_col loop i */
}
/*!
*
* \brief Create QMF filter bank instance
*
*
* \return 0 if successful
*
*/
int qmfInitAnalysisFilterBank(
HANDLE_QMF_FILTER_BANK h_Qmf, /*!< Returns handle */
FIXP_QAS *pFilterStates, /*!< Handle to filter states */
int noCols, /*!< Number of timeslots per frame */
int lsb, /*!< lower end of QMF */
int usb, /*!< upper end of QMF */
int no_channels, /*!< Number of channels (bands) */
int flags) /*!< Low Power flag */
{
int err = qmfInitFilterBank(h_Qmf, pFilterStates, noCols, lsb, usb,
no_channels, flags, 0);
if (!(flags & QMF_FLAG_KEEP_STATES) && (h_Qmf->FilterStates != NULL)) {
FDKmemclear(h_Qmf->FilterStates,
(2 * QMF_NO_POLY - 1) * h_Qmf->no_channels * sizeof(FIXP_QAS));
}
FDK_ASSERT(h_Qmf->no_channels >= h_Qmf->lsb);
return err;
}
#ifndef FUNCTION_qmfAnaPrototypeFirSlot
/*!
\brief Perform Analysis Prototype Filtering on a single slot of input data.
*/
static void qmfAnaPrototypeFirSlot(
FIXP_DBL *analysisBuffer,
INT no_channels, /*!< Number channels of analysis filter */
const FIXP_PFT *p_filter, INT p_stride, /*!< Stride of analysis filter */
FIXP_QAS *RESTRICT pFilterStates) {
INT k;
FIXP_DBL accu;
const FIXP_PFT *RESTRICT p_flt = p_filter;
FIXP_DBL *RESTRICT pData_0 = analysisBuffer + 2 * no_channels - 1;
FIXP_DBL *RESTRICT pData_1 = analysisBuffer;
FIXP_QAS *RESTRICT sta_0 = (FIXP_QAS *)pFilterStates;
FIXP_QAS *RESTRICT sta_1 =
(FIXP_QAS *)pFilterStates + (2 * QMF_NO_POLY * no_channels) - 1;
INT pfltStep = QMF_NO_POLY * (p_stride);
INT staStep1 = no_channels << 1;
INT staStep2 = (no_channels << 3) - 1; /* Rewind one less */
/* FIR filters 127..64 0..63 */
for (k = 0; k < no_channels; k++) {
accu = fMultDiv2(p_flt[0], *sta_1);
sta_1 -= staStep1;
accu += fMultDiv2(p_flt[1], *sta_1);
sta_1 -= staStep1;
accu += fMultDiv2(p_flt[2], *sta_1);
sta_1 -= staStep1;
accu += fMultDiv2(p_flt[3], *sta_1);
sta_1 -= staStep1;
accu += fMultDiv2(p_flt[4], *sta_1);
*pData_1++ = (accu << 1);
sta_1 += staStep2;
p_flt += pfltStep;
accu = fMultDiv2(p_flt[0], *sta_0);
sta_0 += staStep1;
accu += fMultDiv2(p_flt[1], *sta_0);
sta_0 += staStep1;
accu += fMultDiv2(p_flt[2], *sta_0);
sta_0 += staStep1;
accu += fMultDiv2(p_flt[3], *sta_0);
sta_0 += staStep1;
accu += fMultDiv2(p_flt[4], *sta_0);
*pData_0-- = (accu << 1);
sta_0 -= staStep2;
}
}
#endif /* !defined(FUNCTION_qmfAnaPrototypeFirSlot) */
#ifndef FUNCTION_qmfAnaPrototypeFirSlot_NonSymmetric
/*!
\brief Perform Analysis Prototype Filtering on a single slot of input data.
*/
static void qmfAnaPrototypeFirSlot_NonSymmetric(
FIXP_DBL *analysisBuffer,
int no_channels, /*!< Number channels of analysis filter */
const FIXP_PFT *p_filter, int p_stride, /*!< Stride of analysis filter */
FIXP_QAS *RESTRICT pFilterStates) {
const FIXP_PFT *RESTRICT p_flt = p_filter;
int p, k;
for (k = 0; k < 2 * no_channels; k++) {
FIXP_DBL accu = (FIXP_DBL)0;
p_flt += QMF_NO_POLY * (p_stride - 1);
/*
Perform FIR-Filter
*/
for (p = 0; p < QMF_NO_POLY; p++) {
accu += fMultDiv2(*p_flt++, pFilterStates[2 * no_channels * p]);
}
analysisBuffer[2 * no_channels - 1 - k] = (accu << 1);
pFilterStates++;
}
}
#endif /* FUNCTION_qmfAnaPrototypeFirSlot_NonSymmetric */
/*
* \brief Perform one QMF slot analysis of the time domain data of timeIn
* with specified stride and stores the real part of the subband
* samples in rSubband, and the imaginary part in iSubband
*
* Note: anaQmf->lsb can be greater than anaQmf->no_channels in case
* of implicit resampling (USAC with reduced 3/4 core frame length).
*/
void qmfAnalysisFilteringSlot(
HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Synthesis Bank */
FIXP_DBL *qmfReal, /*!< Low and High band, real */
FIXP_DBL *qmfImag, /*!< Low and High band, imag */
const INT_PCM_QMFIN *RESTRICT timeIn, /*!< Pointer to input */
const int stride, /*!< stride factor of input */
FIXP_DBL *pWorkBuffer /*!< pointer to temporal working buffer */
) {
int offset = anaQmf->no_channels * (QMF_NO_POLY * 2 - 1);
/*
Feed time signal into oldest anaQmf->no_channels states
*/
{
FIXP_QAS *FilterStatesAnaTmp = ((FIXP_QAS *)anaQmf->FilterStates) + offset;
/* Feed and scale actual time in slot */
for (int i = anaQmf->no_channels >> 1; i != 0; i--) {
/* Place INT_PCM value left aligned in scaledTimeIn */
*FilterStatesAnaTmp++ = (FIXP_QAS)*timeIn;
timeIn += stride;
*FilterStatesAnaTmp++ = (FIXP_QAS)*timeIn;
timeIn += stride;
}
}
if (anaQmf->flags & QMF_FLAG_NONSYMMETRIC) {
qmfAnaPrototypeFirSlot_NonSymmetric(pWorkBuffer, anaQmf->no_channels,
anaQmf->p_filter, anaQmf->p_stride,
(FIXP_QAS *)anaQmf->FilterStates);
} else {
qmfAnaPrototypeFirSlot(pWorkBuffer, anaQmf->no_channels, anaQmf->p_filter,
anaQmf->p_stride, (FIXP_QAS *)anaQmf->FilterStates);
}
if (anaQmf->flags & QMF_FLAG_LP) {
if (anaQmf->flags & QMF_FLAG_CLDFB)
qmfForwardModulationLP_odd(anaQmf, pWorkBuffer, qmfReal);
else
qmfForwardModulationLP_even(anaQmf, pWorkBuffer, qmfReal);
} else {
qmfForwardModulationHQ(anaQmf, pWorkBuffer, qmfReal, qmfImag);
}
/*
Shift filter states
Should be realized with modulo addressing on a DSP instead of a true buffer
shift
*/
FDKmemmove(anaQmf->FilterStates,
(FIXP_QAS *)anaQmf->FilterStates + anaQmf->no_channels,
offset * sizeof(FIXP_QAS));
}
/*!
*
* \brief Perform complex-valued subband filtering of the time domain
* data of timeIn and stores the real part of the subband
* samples in rAnalysis, and the imaginary part in iAnalysis
* The qmf coefficient table is symmetric. The symmetry is expoited by
* shrinking the coefficient table to half the size. The addressing mode
* takes care of the symmetries.
*
*
* \sa PolyphaseFiltering
*/
void qmfAnalysisFiltering(
HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank */
FIXP_DBL **qmfReal, /*!< Pointer to real subband slots */
FIXP_DBL **qmfImag, /*!< Pointer to imag subband slots */
QMF_SCALE_FACTOR *scaleFactor,
const INT_PCM_QMFIN *timeIn, /*!< Time signal */
const int timeIn_e, const int stride,
FIXP_DBL *pWorkBuffer /*!< pointer to temporal working buffer */
) {
int i;
int no_channels = anaQmf->no_channels;
scaleFactor->lb_scale =
-ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK - timeIn_e;
scaleFactor->lb_scale -= anaQmf->filterScale;
for (i = 0; i < anaQmf->no_col; i++) {
FIXP_DBL *qmfImagSlot = NULL;
if (!(anaQmf->flags & QMF_FLAG_LP)) {
qmfImagSlot = qmfImag[i];
}
qmfAnalysisFilteringSlot(anaQmf, qmfReal[i], qmfImagSlot, timeIn, stride,
pWorkBuffer);
timeIn += no_channels * stride;
} /* no_col loop i */
}
#endif /* QMF_PCM_H */

View File

@ -1,7 +1,7 @@
/* -----------------------------------------------------------------------------
Software License for The Fraunhofer FDK AAC Codec Library for Android
© Copyright 1995 - 2018 Fraunhofer-Gesellschaft zur Förderung der angewandten
© Copyright 1995 - 2019 Fraunhofer-Gesellschaft zur Förderung der angewandten
Forschung e.V. All rights reserved.
1. INTRODUCTION
@ -128,13 +128,13 @@ C_ALLOC_MEM_OVERLAY(QmfWorkBufferCore6, FIXP_DBL, QMF_WB_SECTION_SIZE,
/*! Analysis states buffer. <br>
Dimension: #((8) + (1)) */
C_ALLOC_MEM2(AnaQmfStates, FIXP_QAS, 10 * QMF_DOMAIN_MAX_ANALYSIS_QMF_BANDS,
((8) + (1)))
C_AALLOC_MEM2(AnaQmfStates, FIXP_DBL, 10 * QMF_DOMAIN_MAX_ANALYSIS_QMF_BANDS,
((8) + (1)))
/*! Synthesis states buffer. <br>
Dimension: #((8) + (1)) */
C_ALLOC_MEM2(SynQmfStates, FIXP_QSS, 9 * QMF_DOMAIN_MAX_SYNTHESIS_QMF_BANDS,
((8) + (1)))
C_AALLOC_MEM2(SynQmfStates, FIXP_QSS, 9 * QMF_DOMAIN_MAX_SYNTHESIS_QMF_BANDS,
((8) + (1)))
/*! Pointer to real qmf data for each time slot. <br>
Dimension: #((8) + (1)) */
@ -156,18 +156,17 @@ C_AALLOC_MEM2(QmfOverlapBuffer, FIXP_DBL,
/*! Analysis states buffer. <br>
Dimension: #((8) + (1)) */
C_ALLOC_MEM2(AnaQmfStates16, FIXP_QAS, 10 * QMF_DOMAIN_ANALYSIS_QMF_BANDS_16,
((8) + (1)))
C_AALLOC_MEM2(AnaQmfStates16, FIXP_DBL, 10 * QMF_DOMAIN_ANALYSIS_QMF_BANDS_16,
((8) + (1)))
/*! Analysis states buffer. <br>
Dimension: #((8) + (1)) */
C_AALLOC_MEM2(AnaQmfStates24, FIXP_DBL, 10 * QMF_DOMAIN_ANALYSIS_QMF_BANDS_24,
((8) + (1)))
/*! Analysis states buffer. <br>
Dimension: #((8) + (1)) */
C_ALLOC_MEM2(AnaQmfStates24, FIXP_QAS, 10 * QMF_DOMAIN_ANALYSIS_QMF_BANDS_24,
((8) + (1)))
/*! Analysis states buffer. <br>
Dimension: #((8) + (1)) */
C_ALLOC_MEM2(AnaQmfStates32, FIXP_QAS, 10 * QMF_DOMAIN_ANALYSIS_QMF_BANDS_32,
((8) + (1)))
C_AALLOC_MEM2(AnaQmfStates32, FIXP_DBL, 10 * QMF_DOMAIN_ANALYSIS_QMF_BANDS_32,
((8) + (1)))
/*! Pointer to real qmf data for each time slot. <br>
Dimension: #((8) + (1)) */

View File

@ -147,88 +147,6 @@ amm-info@iis.fraunhofer.de
/* moved to qmf_pcm.h: -> qmfSynPrototypeFirSlot_NonSymmetric */
/* moved to qmf_pcm.h: -> qmfSynthesisFilteringSlot */
#ifndef FUNCTION_qmfAnaPrototypeFirSlot
/*!
\brief Perform Analysis Prototype Filtering on a single slot of input data.
*/
static void qmfAnaPrototypeFirSlot(
FIXP_DBL *analysisBuffer,
INT no_channels, /*!< Number channels of analysis filter */
const FIXP_PFT *p_filter, INT p_stride, /*!< Stride of analysis filter */
FIXP_QAS *RESTRICT pFilterStates) {
INT k;
FIXP_DBL accu;
const FIXP_PFT *RESTRICT p_flt = p_filter;
FIXP_DBL *RESTRICT pData_0 = analysisBuffer + 2 * no_channels - 1;
FIXP_DBL *RESTRICT pData_1 = analysisBuffer;
FIXP_QAS *RESTRICT sta_0 = (FIXP_QAS *)pFilterStates;
FIXP_QAS *RESTRICT sta_1 =
(FIXP_QAS *)pFilterStates + (2 * QMF_NO_POLY * no_channels) - 1;
INT pfltStep = QMF_NO_POLY * (p_stride);
INT staStep1 = no_channels << 1;
INT staStep2 = (no_channels << 3) - 1; /* Rewind one less */
/* FIR filters 127..64 0..63 */
for (k = 0; k < no_channels; k++) {
accu = fMultDiv2(p_flt[0], *sta_1);
sta_1 -= staStep1;
accu += fMultDiv2(p_flt[1], *sta_1);
sta_1 -= staStep1;
accu += fMultDiv2(p_flt[2], *sta_1);
sta_1 -= staStep1;
accu += fMultDiv2(p_flt[3], *sta_1);
sta_1 -= staStep1;
accu += fMultDiv2(p_flt[4], *sta_1);
*pData_1++ = (accu << 1);
sta_1 += staStep2;
p_flt += pfltStep;
accu = fMultDiv2(p_flt[0], *sta_0);
sta_0 += staStep1;
accu += fMultDiv2(p_flt[1], *sta_0);
sta_0 += staStep1;
accu += fMultDiv2(p_flt[2], *sta_0);
sta_0 += staStep1;
accu += fMultDiv2(p_flt[3], *sta_0);
sta_0 += staStep1;
accu += fMultDiv2(p_flt[4], *sta_0);
*pData_0-- = (accu << 1);
sta_0 -= staStep2;
}
}
#endif /* !defined(FUNCTION_qmfAnaPrototypeFirSlot) */
#ifndef FUNCTION_qmfAnaPrototypeFirSlot_NonSymmetric
/*!
\brief Perform Analysis Prototype Filtering on a single slot of input data.
*/
static void qmfAnaPrototypeFirSlot_NonSymmetric(
FIXP_DBL *analysisBuffer,
int no_channels, /*!< Number channels of analysis filter */
const FIXP_PFT *p_filter, int p_stride, /*!< Stride of analysis filter */
FIXP_QAS *RESTRICT pFilterStates) {
const FIXP_PFT *RESTRICT p_flt = p_filter;
int p, k;
for (k = 0; k < 2 * no_channels; k++) {
FIXP_DBL accu = (FIXP_DBL)0;
p_flt += QMF_NO_POLY * (p_stride - 1);
/*
Perform FIR-Filter
*/
for (p = 0; p < QMF_NO_POLY; p++) {
accu += fMultDiv2(*p_flt++, pFilterStates[2 * no_channels * p]);
}
analysisBuffer[2 * no_channels - 1 - k] = (accu << 1);
pFilterStates++;
}
}
#endif /* FUNCTION_qmfAnaPrototypeFirSlot_NonSymmetric */
/*!
*
* \brief Perform real-valued forward modulation of the time domain
@ -381,211 +299,6 @@ static void qmfForwardModulationHQ(
}
#endif /* FUNCTION_qmfForwardModulationHQ */
/*
* \brief Perform one QMF slot analysis of the time domain data of timeIn
* with specified stride and stores the real part of the subband
* samples in rSubband, and the imaginary part in iSubband
*
* Note: anaQmf->lsb can be greater than anaQmf->no_channels in case
* of implicit resampling (USAC with reduced 3/4 core frame length).
*/
#if (SAMPLE_BITS != DFRACT_BITS) && (QAS_BITS == DFRACT_BITS)
void qmfAnalysisFilteringSlot(
HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Synthesis Bank */
FIXP_DBL *qmfReal, /*!< Low and High band, real */
FIXP_DBL *qmfImag, /*!< Low and High band, imag */
const LONG *RESTRICT timeIn, /*!< Pointer to input */
const int stride, /*!< stride factor of input */
FIXP_DBL *pWorkBuffer /*!< pointer to temporal working buffer */
) {
int offset = anaQmf->no_channels * (QMF_NO_POLY * 2 - 1);
/*
Feed time signal into oldest anaQmf->no_channels states
*/
{
FIXP_DBL *FilterStatesAnaTmp = ((FIXP_DBL *)anaQmf->FilterStates) + offset;
/* Feed and scale actual time in slot */
for (int i = anaQmf->no_channels >> 1; i != 0; i--) {
/* Place INT_PCM value left aligned in scaledTimeIn */
*FilterStatesAnaTmp++ = (FIXP_QAS)*timeIn;
timeIn += stride;
*FilterStatesAnaTmp++ = (FIXP_QAS)*timeIn;
timeIn += stride;
}
}
if (anaQmf->flags & QMF_FLAG_NONSYMMETRIC) {
qmfAnaPrototypeFirSlot_NonSymmetric(pWorkBuffer, anaQmf->no_channels,
anaQmf->p_filter, anaQmf->p_stride,
(FIXP_QAS *)anaQmf->FilterStates);
} else {
qmfAnaPrototypeFirSlot(pWorkBuffer, anaQmf->no_channels, anaQmf->p_filter,
anaQmf->p_stride, (FIXP_QAS *)anaQmf->FilterStates);
}
if (anaQmf->flags & QMF_FLAG_LP) {
if (anaQmf->flags & QMF_FLAG_CLDFB)
qmfForwardModulationLP_odd(anaQmf, pWorkBuffer, qmfReal);
else
qmfForwardModulationLP_even(anaQmf, pWorkBuffer, qmfReal);
} else {
qmfForwardModulationHQ(anaQmf, pWorkBuffer, qmfReal, qmfImag);
}
/*
Shift filter states
Should be realized with modulo adressing on a DSP instead of a true buffer
shift
*/
FDKmemmove(anaQmf->FilterStates,
(FIXP_QAS *)anaQmf->FilterStates + anaQmf->no_channels,
offset * sizeof(FIXP_QAS));
}
#endif
void qmfAnalysisFilteringSlot(
HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Synthesis Bank */
FIXP_DBL *qmfReal, /*!< Low and High band, real */
FIXP_DBL *qmfImag, /*!< Low and High band, imag */
const INT_PCM *RESTRICT timeIn, /*!< Pointer to input */
const int stride, /*!< stride factor of input */
FIXP_DBL *pWorkBuffer /*!< pointer to temporal working buffer */
) {
int offset = anaQmf->no_channels * (QMF_NO_POLY * 2 - 1);
/*
Feed time signal into oldest anaQmf->no_channels states
*/
{
FIXP_QAS *FilterStatesAnaTmp = ((FIXP_QAS *)anaQmf->FilterStates) + offset;
/* Feed and scale actual time in slot */
for (int i = anaQmf->no_channels >> 1; i != 0; i--) {
/* Place INT_PCM value left aligned in scaledTimeIn */
#if (QAS_BITS == SAMPLE_BITS)
*FilterStatesAnaTmp++ = (FIXP_QAS)*timeIn;
timeIn += stride;
*FilterStatesAnaTmp++ = (FIXP_QAS)*timeIn;
timeIn += stride;
#elif (QAS_BITS > SAMPLE_BITS)
*FilterStatesAnaTmp++ = ((FIXP_QAS)*timeIn) << (QAS_BITS - SAMPLE_BITS);
timeIn += stride;
*FilterStatesAnaTmp++ = ((FIXP_QAS)*timeIn) << (QAS_BITS - SAMPLE_BITS);
timeIn += stride;
#else
*FilterStatesAnaTmp++ = (FIXP_QAS)((*timeIn) >> (SAMPLE_BITS - QAS_BITS));
timeIn += stride;
*FilterStatesAnaTmp++ = (FIXP_QAS)((*timeIn) >> (SAMPLE_BITS - QAS_BITS));
timeIn += stride;
#endif
}
}
if (anaQmf->flags & QMF_FLAG_NONSYMMETRIC) {
qmfAnaPrototypeFirSlot_NonSymmetric(pWorkBuffer, anaQmf->no_channels,
anaQmf->p_filter, anaQmf->p_stride,
(FIXP_QAS *)anaQmf->FilterStates);
} else {
qmfAnaPrototypeFirSlot(pWorkBuffer, anaQmf->no_channels, anaQmf->p_filter,
anaQmf->p_stride, (FIXP_QAS *)anaQmf->FilterStates);
}
if (anaQmf->flags & QMF_FLAG_LP) {
if (anaQmf->flags & QMF_FLAG_CLDFB)
qmfForwardModulationLP_odd(anaQmf, pWorkBuffer, qmfReal);
else
qmfForwardModulationLP_even(anaQmf, pWorkBuffer, qmfReal);
} else {
qmfForwardModulationHQ(anaQmf, pWorkBuffer, qmfReal, qmfImag);
}
/*
Shift filter states
Should be realized with modulo adressing on a DSP instead of a true buffer
shift
*/
FDKmemmove(anaQmf->FilterStates,
(FIXP_QAS *)anaQmf->FilterStates + anaQmf->no_channels,
offset * sizeof(FIXP_QAS));
}
/*!
*
* \brief Perform complex-valued subband filtering of the time domain
* data of timeIn and stores the real part of the subband
* samples in rAnalysis, and the imaginary part in iAnalysis
* The qmf coefficient table is symmetric. The symmetry is expoited by
* shrinking the coefficient table to half the size. The addressing mode
* takes care of the symmetries.
*
*
* \sa PolyphaseFiltering
*/
#if (SAMPLE_BITS != DFRACT_BITS) && (QAS_BITS == DFRACT_BITS)
void qmfAnalysisFiltering(
HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank */
FIXP_DBL **qmfReal, /*!< Pointer to real subband slots */
FIXP_DBL **qmfImag, /*!< Pointer to imag subband slots */
QMF_SCALE_FACTOR *scaleFactor, const LONG *timeIn, /*!< Time signal */
const int timeIn_e, const int stride,
FIXP_DBL *pWorkBuffer /*!< pointer to temporal working buffer */
) {
int i;
int no_channels = anaQmf->no_channels;
scaleFactor->lb_scale =
-ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK - timeIn_e;
scaleFactor->lb_scale -= anaQmf->filterScale;
for (i = 0; i < anaQmf->no_col; i++) {
FIXP_DBL *qmfImagSlot = NULL;
if (!(anaQmf->flags & QMF_FLAG_LP)) {
qmfImagSlot = qmfImag[i];
}
qmfAnalysisFilteringSlot(anaQmf, qmfReal[i], qmfImagSlot, timeIn, stride,
pWorkBuffer);
timeIn += no_channels * stride;
} /* no_col loop i */
}
#endif
void qmfAnalysisFiltering(
HANDLE_QMF_FILTER_BANK anaQmf, /*!< Handle of Qmf Analysis Bank */
FIXP_DBL **qmfReal, /*!< Pointer to real subband slots */
FIXP_DBL **qmfImag, /*!< Pointer to imag subband slots */
QMF_SCALE_FACTOR *scaleFactor, const INT_PCM *timeIn, /*!< Time signal */
const int timeIn_e, const int stride,
FIXP_DBL *pWorkBuffer /*!< pointer to temporal working buffer */
) {
int i;
int no_channels = anaQmf->no_channels;
scaleFactor->lb_scale =
-ALGORITHMIC_SCALING_IN_ANALYSIS_FILTERBANK - timeIn_e;
scaleFactor->lb_scale -= anaQmf->filterScale;
for (i = 0; i < anaQmf->no_col; i++) {
FIXP_DBL *qmfImagSlot = NULL;
if (!(anaQmf->flags & QMF_FLAG_LP)) {
qmfImagSlot = qmfImag[i];
}
qmfAnalysisFilteringSlot(anaQmf, qmfReal[i], qmfImagSlot, timeIn, stride,
pWorkBuffer);
timeIn += no_channels * stride;
} /* no_col loop i */
}
/*!
*
* \brief Perform low power inverse modulation of the subband
@ -997,35 +710,6 @@ static inline void qmfAdaptFilterStates(
}
}
/*!
*
* \brief Create QMF filter bank instance
*
*
* \return 0 if succesful
*
*/
int qmfInitAnalysisFilterBank(
HANDLE_QMF_FILTER_BANK h_Qmf, /*!< Returns handle */
FIXP_QAS *pFilterStates, /*!< Handle to filter states */
int noCols, /*!< Number of timeslots per frame */
int lsb, /*!< lower end of QMF */
int usb, /*!< upper end of QMF */
int no_channels, /*!< Number of channels (bands) */
int flags) /*!< Low Power flag */
{
int err = qmfInitFilterBank(h_Qmf, pFilterStates, noCols, lsb, usb,
no_channels, flags, 0);
if (!(flags & QMF_FLAG_KEEP_STATES) && (h_Qmf->FilterStates != NULL)) {
FDKmemclear(h_Qmf->FilterStates,
(2 * QMF_NO_POLY - 1) * h_Qmf->no_channels * sizeof(FIXP_QAS));
}
FDK_ASSERT(h_Qmf->no_channels >= h_Qmf->lsb);
return err;
}
/*!
*
* \brief Create QMF filter bank instance
@ -1129,8 +813,21 @@ void qmfChangeOutGain(
synQmf->outGain_e = outputGainScale;
}
/* When QMF_16IN_32OUT is set, synthesis functions for 16 and 32 bit parallel
* output is compiled */
#define INT_PCM_QMFOUT INT_PCM
#define SAMPLE_BITS_QMFOUT SAMPLE_BITS
#include "qmf_pcm.h"
#if SAMPLE_BITS == 16
/* also create a 32 bit output version */
#undef INT_PCM_QMFOUT
#undef SAMPLE_BITS_QMFOUT
#undef QMF_PCM_H
#undef FIXP_QAS
#undef QAS_BITS
#undef INT_PCM_QMFIN
#define INT_PCM_QMFOUT LONG
#define SAMPLE_BITS_QMFOUT 32
#define FIXP_QAS FIXP_DBL
#define QAS_BITS 32
#define INT_PCM_QMFIN LONG
#include "qmf_pcm.h"
#endif