iSAC: Move global trig tables into the codec instance

These tables are constant, so it makes sense for all encoders to share
one copy---but it was initialized in a racy way, and there's no
appealing way to fix that without adding dependencies on locking
functions. So we simply give each codec instance its own copy, which
costs 8 * (240 + 240 + 120 + 120) = 5760 bytes apiece.

As noted in the TODO comment, the size of the tables could be reduced,
and they could be filled in at compile-time, but that would make the
encoder output slightly different, which would mess with our tests.

R=henrik.lundin@webrtc.org, solenberg@webrtc.org

Review URL: https://codereview.webrtc.org/1177993003.

Cr-Commit-Position: refs/heads/master@{#9442}
This commit is contained in:
Karl Wiberg 2015-06-16 00:02:34 +02:00
parent 030249dd24
commit ac81163011
7 changed files with 111 additions and 73 deletions

View File

@ -31,16 +31,20 @@ int WebRtcIsac_EstimateBandwidth(BwEstimatorstr* bwest_str, Bitstr* streamdata,
enum IsacSamplingRate encoderSampRate,
enum IsacSamplingRate decoderSampRate);
int WebRtcIsac_DecodeLb(float* signal_out, ISACLBDecStruct* ISACdec_obj,
int WebRtcIsac_DecodeLb(const TransformTables* transform_tables,
float* signal_out,
ISACLBDecStruct* ISACdec_obj,
int16_t* current_framesamples,
int16_t isRCUPayload);
int WebRtcIsac_DecodeRcuLb(float* signal_out, ISACLBDecStruct* ISACdec_obj,
int16_t* current_framesamples);
int WebRtcIsac_EncodeLb(float* in, ISACLBEncStruct* ISACencLB_obj,
int16_t codingMode, int16_t
bottleneckIndex);
int WebRtcIsac_EncodeLb(const TransformTables* transform_tables,
float* in,
ISACLBEncStruct* ISACencLB_obj,
int16_t codingMode,
int16_t bottleneckIndex);
int WebRtcIsac_EncodeStoredDataLb(const IsacSaveEncoderData* ISACSavedEnc_obj,
Bitstr* ISACBitStr_obj, int BWnumber,
@ -93,10 +97,11 @@ int16_t WebRtcIsac_RateAllocation(int32_t inRateBitPerSec,
* Return value : >0 number of decoded bytes.
* <0 if an error occurred.
*/
int WebRtcIsac_DecodeUb16(float* signal_out, ISACUBDecStruct* ISACdec_obj,
int WebRtcIsac_DecodeUb16(const TransformTables* transform_tables,
float* signal_out,
ISACUBDecStruct* ISACdec_obj,
int16_t isRCUPayload);
/******************************************************************************
* WebRtcIsac_DecodeUb12()
*
@ -112,10 +117,11 @@ int WebRtcIsac_DecodeUb16(float* signal_out, ISACUBDecStruct* ISACdec_obj,
* Return value : >0 number of decoded bytes.
* <0 if an error occurred.
*/
int WebRtcIsac_DecodeUb12(float* signal_out, ISACUBDecStruct* ISACdec_obj,
int WebRtcIsac_DecodeUb12(const TransformTables* transform_tables,
float* signal_out,
ISACUBDecStruct* ISACdec_obj,
int16_t isRCUPayload);
/******************************************************************************
* WebRtcIsac_EncodeUb16()
*
@ -131,10 +137,11 @@ int WebRtcIsac_DecodeUb12(float* signal_out, ISACUBDecStruct* ISACdec_obj,
* Return value : >0 number of encoded bytes.
* <0 if an error occurred.
*/
int WebRtcIsac_EncodeUb16(float* in, ISACUBEncStruct* ISACenc_obj,
int WebRtcIsac_EncodeUb16(const TransformTables* transform_tables,
float* in,
ISACUBEncStruct* ISACenc_obj,
int32_t jitterInfo);
/******************************************************************************
* WebRtcIsac_EncodeUb12()
*
@ -150,7 +157,9 @@ int WebRtcIsac_EncodeUb16(float* in, ISACUBEncStruct* ISACenc_obj,
* Return value : >0 number of encoded bytes.
* <0 if an error occurred.
*/
int WebRtcIsac_EncodeUb12(float* in, ISACUBEncStruct* ISACenc_obj,
int WebRtcIsac_EncodeUb12(const TransformTables* transform_tables,
float* in,
ISACUBEncStruct* ISACenc_obj,
int32_t jitterInfo);
/************************** initialization functions *************************/
@ -168,14 +177,21 @@ void WebRtcIsac_InitPitchAnalysis(PitchAnalysisStruct* State);
/**************************** transform functions ****************************/
void WebRtcIsac_InitTransform();
void WebRtcIsac_InitTransform(TransformTables* tables);
void WebRtcIsac_Time2Spec(double* inre1, double* inre2, int16_t* outre,
int16_t* outim, FFTstr* fftstr_obj);
void WebRtcIsac_Spec2time(double* inre, double* inim, double* outre1,
double* outre2, FFTstr* fftstr_obj);
void WebRtcIsac_Time2Spec(const TransformTables* tables,
double* inre1,
double* inre2,
int16_t* outre,
int16_t* outim,
FFTstr* fftstr_obj);
void WebRtcIsac_Spec2time(const TransformTables* tables,
double* inre,
double* inim,
double* outre1,
double* outre2,
FFTstr* fftstr_obj);
/******************************* filter functions ****************************/

View File

@ -35,7 +35,8 @@
* function to decode the bitstream
* returns the total number of bytes in the stream
*/
int WebRtcIsac_DecodeLb(float* signal_out, ISACLBDecStruct* ISACdecLB_obj,
int WebRtcIsac_DecodeLb(const TransformTables* transform_tables,
float* signal_out, ISACLBDecStruct* ISACdecLB_obj,
int16_t* current_framesamples,
int16_t isRCUPayload) {
int k;
@ -122,7 +123,7 @@ int WebRtcIsac_DecodeLb(float* signal_out, ISACLBDecStruct* ISACdecLB_obj,
}
/* Inverse transform. */
WebRtcIsac_Spec2time(real_f, imag_f, LPw, HPw,
WebRtcIsac_Spec2time(transform_tables, real_f, imag_f, LPw, HPw,
&ISACdecLB_obj->fftstr_obj);
/* Convert PitchGains back to float for pitchfilter_post */
@ -181,7 +182,8 @@ int WebRtcIsac_DecodeLb(float* signal_out, ISACLBDecStruct* ISACdecLB_obj,
* Contrary to lower-band, the upper-band (8-16 kHz) is not split in
* frequency, but split to 12 sub-frames, i.e. twice as lower-band.
*/
int WebRtcIsac_DecodeUb16(float* signal_out, ISACUBDecStruct* ISACdecUB_obj,
int WebRtcIsac_DecodeUb16(const TransformTables* transform_tables,
float* signal_out, ISACUBDecStruct* ISACdecUB_obj,
int16_t isRCUPayload) {
int len, err;
@ -218,7 +220,8 @@ int WebRtcIsac_DecodeUb16(float* signal_out, ISACUBDecStruct* ISACdecUB_obj,
}
}
/* Inverse transform. */
WebRtcIsac_Spec2time(real_f, imag_f, halfFrameFirst, halfFrameSecond,
WebRtcIsac_Spec2time(transform_tables,
real_f, imag_f, halfFrameFirst, halfFrameSecond,
&ISACdecUB_obj->fftstr_obj);
/* Perceptual post-filtering (using normalized lattice filter). */
@ -245,8 +248,9 @@ int WebRtcIsac_DecodeUb16(float* signal_out, ISACUBDecStruct* ISACdecUB_obj,
* reconstructed and 12-16 kHz replaced with zeros. Then two bands
* are combined, to reconstruct the upperband 8-16 kHz.
*/
int WebRtcIsac_DecodeUb12(float* signal_out, ISACUBDecStruct* ISACdecUB_obj,
int16_t isRCUPayload) {
int WebRtcIsac_DecodeUb12(const TransformTables* transform_tables,
float* signal_out, ISACUBDecStruct* ISACdecUB_obj,
int16_t isRCUPayload) {
int len, err;
float LP_dec_float[FRAMESAMPLES_HALF];
@ -284,7 +288,8 @@ int WebRtcIsac_DecodeUb12(float* signal_out, ISACUBDecStruct* ISACdecUB_obj,
}
}
/* Inverse transform. */
WebRtcIsac_Spec2time(real_f, imag_f, LPw, HPw, &ISACdecUB_obj->fftstr_obj);
WebRtcIsac_Spec2time(transform_tables,
real_f, imag_f, LPw, HPw, &ISACdecUB_obj->fftstr_obj);
/* perceptual post-filtering (using normalized lattice filter) */
WebRtcIsac_NormLatticeFilterAr(UB_LPC_ORDER,
ISACdecUB_obj->maskfiltstr_obj.PostStateLoF,

View File

@ -177,7 +177,8 @@ void WebRtcIsac_ResetBitstream(Bitstr* bit_stream) {
bit_stream->streamval = 0;
}
int WebRtcIsac_EncodeLb(float* in, ISACLBEncStruct* ISACencLB_obj,
int WebRtcIsac_EncodeLb(const TransformTables* transform_tables,
float* in, ISACLBEncStruct* ISACencLB_obj,
int16_t codingMode,
int16_t bottleneckIndex) {
int stream_length = 0;
@ -382,7 +383,8 @@ int WebRtcIsac_EncodeLb(float* in, ISACLBEncStruct* ISACencLB_obj,
WebRtcIsac_PitchfilterPre(LPw, LPw_pf, &ISACencLB_obj->pitchfiltstr_obj,
PitchLags, PitchGains);
/* Transform */
WebRtcIsac_Time2Spec(LPw_pf, HPw, fre, fim, &ISACencLB_obj->fftstr_obj);
WebRtcIsac_Time2Spec(transform_tables,
LPw_pf, HPw, fre, fim, &ISACencLB_obj->fftstr_obj);
/* Save data for multiple packets memory. */
my_index = ISACencLB_obj->SaveEnc_obj.startIdx * FRAMESAMPLES_HALF;
@ -641,7 +643,8 @@ static int LimitPayloadUb(ISACUBEncStruct* ISACencUB_obj,
return 0;
}
int WebRtcIsac_EncodeUb16(float* in, ISACUBEncStruct* ISACencUB_obj,
int WebRtcIsac_EncodeUb16(const TransformTables* transform_tables,
float* in, ISACUBEncStruct* ISACencUB_obj,
int32_t jitterInfo) {
int err;
int k;
@ -782,7 +785,8 @@ int WebRtcIsac_EncodeUb16(float* in, ISACUBEncStruct* ISACencUB_obj,
&percepFilterParams[(UB_LPC_ORDER + 1) + SUBFRAMES * (UB_LPC_ORDER + 1)],
&LP_lookahead[FRAMESAMPLES_HALF]);
WebRtcIsac_Time2Spec(&LP_lookahead[0], &LP_lookahead[FRAMESAMPLES_HALF],
WebRtcIsac_Time2Spec(transform_tables,
&LP_lookahead[0], &LP_lookahead[FRAMESAMPLES_HALF],
fre, fim, &ISACencUB_obj->fftstr_obj);
/* Store FFT coefficients for multiple encoding. */
@ -826,7 +830,8 @@ int WebRtcIsac_EncodeUb16(float* in, ISACUBEncStruct* ISACencUB_obj,
}
int WebRtcIsac_EncodeUb12(float* in, ISACUBEncStruct* ISACencUB_obj,
int WebRtcIsac_EncodeUb12(const TransformTables* transform_tables,
float* in, ISACUBEncStruct* ISACencUB_obj,
int32_t jitterInfo) {
int err;
int k;
@ -957,7 +962,8 @@ int WebRtcIsac_EncodeUb12(float* in, ISACUBEncStruct* ISACencUB_obj,
memset(HPw, 0, sizeof(HPw));
/* Transform */
WebRtcIsac_Time2Spec(LPw, HPw, fre, fim, &ISACencUB_obj->fftstr_obj);
WebRtcIsac_Time2Spec(transform_tables,
LPw, HPw, fre, fim, &ISACencUB_obj->fftstr_obj);
/* Store FFT coefficients for multiple encoding. */
memcpy(ISACencUB_obj->SaveEnc_obj.realFFT, fre,

View File

@ -40,10 +40,6 @@ void WebRtcIsac_InitMasking(MaskFiltstr *maskdata) {
}
maskdata->OldEnergy = 10.0;
/* fill tables for transforms */
WebRtcIsac_InitTransform();
return;
}

View File

@ -251,6 +251,8 @@ int16_t WebRtcIsac_Assign(ISACStruct** ISAC_main_inst,
instISAC->decoderSamplingRateKHz = kIsacWideband;
instISAC->bandwidthKHz = isac8kHz;
instISAC->in_sample_rate_hz = 16000;
WebRtcIsac_InitTransform(&instISAC->transform_tables);
return 0;
} else {
return -1;
@ -284,6 +286,8 @@ int16_t WebRtcIsac_Create(ISACStruct** ISAC_main_inst) {
instISAC->encoderSamplingRateKHz = kIsacWideband;
instISAC->decoderSamplingRateKHz = kIsacWideband;
instISAC->in_sample_rate_hz = 16000;
WebRtcIsac_InitTransform(&instISAC->transform_tables);
return 0;
} else {
return -1;
@ -579,7 +583,8 @@ int WebRtcIsac_Encode(ISACStruct* ISAC_main_inst,
GetSendBandwidthInfo(instISAC, &bottleneckIdx, &jitterInfo);
/* Encode lower-band. */
streamLenLB = WebRtcIsac_EncodeLb(inFrame, &instLB->ISACencLB_obj,
streamLenLB = WebRtcIsac_EncodeLb(&instISAC->transform_tables,
inFrame, &instLB->ISACencLB_obj,
instISAC->codingMode, bottleneckIdx);
if (streamLenLB < 0) {
return -1;
@ -606,12 +611,14 @@ int WebRtcIsac_Encode(ISACStruct* ISAC_main_inst,
/* Encode upper-band. */
switch (instISAC->bandwidthKHz) {
case isac12kHz: {
streamLenUB = WebRtcIsac_EncodeUb12(inFrame, &instUB->ISACencUB_obj,
streamLenUB = WebRtcIsac_EncodeUb12(&instISAC->transform_tables,
inFrame, &instUB->ISACencUB_obj,
jitterInfo);
break;
}
case isac16kHz: {
streamLenUB = WebRtcIsac_EncodeUb16(inFrame, &instUB->ISACencUB_obj,
streamLenUB = WebRtcIsac_EncodeUb16(&instISAC->transform_tables,
inFrame, &instUB->ISACencUB_obj,
jitterInfo);
break;
}
@ -1106,7 +1113,8 @@ static int Decode(ISACStruct* ISAC_main_inst,
/* Regardless of that the current codec is setup to work in
* wideband or super-wideband, the decoding of the lower-band
* has to be performed. */
numDecodedBytesLB = WebRtcIsac_DecodeLb(outFrame, decInstLB,
numDecodedBytesLB = WebRtcIsac_DecodeLb(&instISAC->transform_tables,
outFrame, decInstLB,
&numSamplesLB, isRCUPayload);
if ((numDecodedBytesLB < 0) || (numDecodedBytesLB > lenEncodedLBBytes) ||
@ -1249,8 +1257,8 @@ static int Decode(ISACStruct* ISAC_main_inst,
switch (bandwidthKHz) {
case isac12kHz: {
numDecodedBytesUB = WebRtcIsac_DecodeUb12(outFrame, decInstUB,
isRCUPayload);
numDecodedBytesUB = WebRtcIsac_DecodeUb12(
&instISAC->transform_tables, outFrame, decInstUB, isRCUPayload);
/* Hang-over for transient alleviation -
* wait two frames to add the upper band going up from 8 kHz. */
@ -1277,8 +1285,8 @@ static int Decode(ISACStruct* ISAC_main_inst,
break;
}
case isac16kHz: {
numDecodedBytesUB = WebRtcIsac_DecodeUb16(outFrame, decInstUB,
isRCUPayload);
numDecodedBytesUB = WebRtcIsac_DecodeUb16(
&instISAC->transform_tables, outFrame, decInstUB, isRCUPayload);
break;
}
default:

View File

@ -428,6 +428,16 @@ typedef struct {
uint8_t stream[3];
} transcode_obj;
typedef struct {
// TODO(kwiberg): The size of these tables could be reduced by storing floats
// instead of doubles, and by making use of the identity cos(x) =
// sin(x+pi/2). They could also be made global constants that we fill in at
// compile time.
double costab1[FRAMESAMPLES_HALF];
double sintab1[FRAMESAMPLES_HALF];
double costab2[FRAMESAMPLES_QUARTER];
double sintab2[FRAMESAMPLES_QUARTER];
} TransformTables;
typedef struct {
// lower-band codec instance
@ -477,6 +487,9 @@ typedef struct {
uint16_t in_sample_rate_hz;
/* State for the input-resampler. It is only used for 48 kHz input signals. */
int16_t state_in_resampler[SIZE_RESAMPLER_STATE];
// Trig tables for WebRtcIsac_Time2Spec and WebRtcIsac_Spec2time.
TransformTables transform_tables;
} ISACMainStruct;
#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_STRUCTS_H_ */

View File

@ -14,41 +14,33 @@
#include "os_specific_inline.h"
#include <math.h>
static double costab1[FRAMESAMPLES_HALF];
static double sintab1[FRAMESAMPLES_HALF];
static double costab2[FRAMESAMPLES_QUARTER];
static double sintab2[FRAMESAMPLES_QUARTER];
void WebRtcIsac_InitTransform()
{
void WebRtcIsac_InitTransform(TransformTables* tables) {
int k;
double fact, phase;
fact = PI / (FRAMESAMPLES_HALF);
phase = 0.0;
for (k = 0; k < FRAMESAMPLES_HALF; k++) {
costab1[k] = cos(phase);
sintab1[k] = sin(phase);
tables->costab1[k] = cos(phase);
tables->sintab1[k] = sin(phase);
phase += fact;
}
fact = PI * ((double) (FRAMESAMPLES_HALF - 1)) / ((double) FRAMESAMPLES_HALF);
phase = 0.5 * fact;
for (k = 0; k < FRAMESAMPLES_QUARTER; k++) {
costab2[k] = cos(phase);
sintab2[k] = sin(phase);
tables->costab2[k] = cos(phase);
tables->sintab2[k] = sin(phase);
phase += fact;
}
}
void WebRtcIsac_Time2Spec(double *inre1,
double *inre2,
int16_t *outreQ7,
int16_t *outimQ7,
FFTstr *fftstr_obj)
{
void WebRtcIsac_Time2Spec(const TransformTables* tables,
double* inre1,
double* inre2,
int16_t* outreQ7,
int16_t* outimQ7,
FFTstr* fftstr_obj) {
int k;
int dims[1];
double tmp1r, tmp1i, xr, xi, yr, yi, fact;
@ -61,8 +53,8 @@ void WebRtcIsac_Time2Spec(double *inre1,
/* Multiply with complex exponentials and combine into one complex vector */
fact = 0.5 / sqrt(FRAMESAMPLES_HALF);
for (k = 0; k < FRAMESAMPLES_HALF; k++) {
tmp1r = costab1[k];
tmp1i = sintab1[k];
tmp1r = tables->costab1[k];
tmp1i = tables->sintab1[k];
tmpre[k] = (inre1[k] * tmp1r + inre2[k] * tmp1i) * fact;
tmpim[k] = (inre2[k] * tmp1r - inre1[k] * tmp1i) * fact;
}
@ -78,8 +70,8 @@ void WebRtcIsac_Time2Spec(double *inre1,
xi = tmpim[k] - tmpim[FRAMESAMPLES_HALF - 1 - k];
yr = tmpim[k] + tmpim[FRAMESAMPLES_HALF - 1 - k];
tmp1r = costab2[k];
tmp1i = sintab2[k];
tmp1r = tables->costab2[k];
tmp1i = tables->sintab2[k];
outreQ7[k] = (int16_t)WebRtcIsac_lrint((xr * tmp1r - xi * tmp1i) * 128.0);
outimQ7[k] = (int16_t)WebRtcIsac_lrint((xr * tmp1i + xi * tmp1r) * 128.0);
outreQ7[FRAMESAMPLES_HALF - 1 - k] = (int16_t)WebRtcIsac_lrint((-yr * tmp1i - yi * tmp1r) * 128.0);
@ -87,10 +79,12 @@ void WebRtcIsac_Time2Spec(double *inre1,
}
}
void WebRtcIsac_Spec2time(double *inre, double *inim, double *outre1, double *outre2, FFTstr *fftstr_obj)
{
void WebRtcIsac_Spec2time(const TransformTables* tables,
double* inre,
double* inim,
double* outre1,
double* outre2,
FFTstr* fftstr_obj) {
int k;
double tmp1r, tmp1i, xr, xi, yr, yi, fact;
@ -100,8 +94,8 @@ void WebRtcIsac_Spec2time(double *inre, double *inim, double *outre1, double *ou
for (k = 0; k < FRAMESAMPLES_QUARTER; k++) {
/* Move zero in time to beginning of frames */
tmp1r = costab2[k];
tmp1i = sintab2[k];
tmp1r = tables->costab2[k];
tmp1i = tables->sintab2[k];
xr = inre[k] * tmp1r + inim[k] * tmp1i;
xi = inim[k] * tmp1r - inre[k] * tmp1i;
yr = -inim[FRAMESAMPLES_HALF - 1 - k] * tmp1r - inre[FRAMESAMPLES_HALF - 1 - k] * tmp1i;
@ -122,8 +116,8 @@ void WebRtcIsac_Spec2time(double *inre, double *inim, double *outre1, double *ou
/* Demodulate and separate */
fact = sqrt(FRAMESAMPLES_HALF);
for (k = 0; k < FRAMESAMPLES_HALF; k++) {
tmp1r = costab1[k];
tmp1i = sintab1[k];
tmp1r = tables->costab1[k];
tmp1i = tables->sintab1[k];
xr = (outre1[k] * tmp1r - outre2[k] * tmp1i) * fact;
outre2[k] = (outre2[k] * tmp1r + outre1[k] * tmp1i) * fact;
outre1[k] = xr;