mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-14 06:10:40 +01:00

In order to eliminate the WebRTC Subtree mirror in Chromium, WebRTC is moving the content of the src/webrtc directory up to the src/ directory. NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true TBR=tommi@webrtc.org Bug: chromium:611808 Change-Id: Iac59c5b51b950f174119565bac87955a7994bc38 Reviewed-on: https://webrtc-review.googlesource.com/1560 Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org> Reviewed-by: Henrik Kjellander <kjellander@webrtc.org> Cr-Commit-Position: refs/heads/master@{#19845}
2066 lines
61 KiB
C
2066 lines
61 KiB
C
/*
|
|
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
/*
|
|
* entropy_coding.c
|
|
*
|
|
* This header file defines all of the functions used to arithmetically
|
|
* encode the iSAC bistream
|
|
*
|
|
*/
|
|
|
|
|
|
#include "entropy_coding.h"
|
|
#include "settings.h"
|
|
#include "arith_routines.h"
|
|
#include "signal_processing_library.h"
|
|
#include "spectrum_ar_model_tables.h"
|
|
#include "lpc_tables.h"
|
|
#include "pitch_gain_tables.h"
|
|
#include "pitch_lag_tables.h"
|
|
#include "encode_lpc_swb.h"
|
|
#include "lpc_shape_swb12_tables.h"
|
|
#include "lpc_shape_swb16_tables.h"
|
|
#include "lpc_gain_swb_tables.h"
|
|
#include "os_specific_inline.h"
|
|
|
|
#include <math.h>
|
|
#include <string.h>
|
|
|
|
static const uint16_t kLpcVecPerSegmentUb12 = 5;
|
|
static const uint16_t kLpcVecPerSegmentUb16 = 4;
|
|
|
|
/* CDF array for encoder bandwidth (12 vs 16 kHz) indicator. */
|
|
static const uint16_t kOneBitEqualProbCdf[3] = {
|
|
0, 32768, 65535 };
|
|
|
|
/* Pointer to cdf array for encoder bandwidth (12 vs 16 kHz) indicator. */
|
|
static const uint16_t* const kOneBitEqualProbCdf_ptr[1] = {
|
|
kOneBitEqualProbCdf };
|
|
|
|
/*
|
|
* Initial cdf index for decoder of encoded bandwidth
|
|
* (12 vs 16 kHz) indicator.
|
|
*/
|
|
static const uint16_t kOneBitEqualProbInitIndex[1] = { 1 };
|
|
|
|
|
|
static const int kIsSWB12 = 1;
|
|
|
|
/* compute correlation from power spectrum */
|
|
static void FindCorrelation(int32_t* PSpecQ12, int32_t* CorrQ7) {
|
|
int32_t summ[FRAMESAMPLES / 8];
|
|
int32_t diff[FRAMESAMPLES / 8];
|
|
const int16_t* CS_ptrQ9;
|
|
int32_t sum;
|
|
int k, n;
|
|
|
|
for (k = 0; k < FRAMESAMPLES / 8; k++) {
|
|
summ[k] = (PSpecQ12[k] + PSpecQ12[FRAMESAMPLES_QUARTER - 1 - k] + 16) >> 5;
|
|
diff[k] = (PSpecQ12[k] - PSpecQ12[FRAMESAMPLES_QUARTER - 1 - k] + 16) >> 5;
|
|
}
|
|
|
|
sum = 2;
|
|
for (n = 0; n < FRAMESAMPLES / 8; n++) {
|
|
sum += summ[n];
|
|
}
|
|
CorrQ7[0] = sum;
|
|
|
|
for (k = 0; k < AR_ORDER; k += 2) {
|
|
sum = 0;
|
|
CS_ptrQ9 = WebRtcIsac_kCos[k];
|
|
for (n = 0; n < FRAMESAMPLES / 8; n++)
|
|
sum += (CS_ptrQ9[n] * diff[n] + 256) >> 9;
|
|
CorrQ7[k + 1] = sum;
|
|
}
|
|
|
|
for (k = 1; k < AR_ORDER; k += 2) {
|
|
sum = 0;
|
|
CS_ptrQ9 = WebRtcIsac_kCos[k];
|
|
for (n = 0; n < FRAMESAMPLES / 8; n++)
|
|
sum += (CS_ptrQ9[n] * summ[n] + 256) >> 9;
|
|
CorrQ7[k + 1] = sum;
|
|
}
|
|
}
|
|
|
|
/* compute inverse AR power spectrum */
|
|
/* Changed to the function used in iSAC FIX for compatibility reasons */
|
|
static void FindInvArSpec(const int16_t* ARCoefQ12,
|
|
const int32_t gainQ10,
|
|
int32_t* CurveQ16) {
|
|
int32_t CorrQ11[AR_ORDER + 1];
|
|
int32_t sum, tmpGain;
|
|
int32_t diffQ16[FRAMESAMPLES / 8];
|
|
const int16_t* CS_ptrQ9;
|
|
int k, n;
|
|
int16_t round, shftVal = 0, sh;
|
|
|
|
sum = 0;
|
|
for (n = 0; n < AR_ORDER + 1; n++) {
|
|
sum += WEBRTC_SPL_MUL(ARCoefQ12[n], ARCoefQ12[n]); /* Q24 */
|
|
}
|
|
sum = ((sum >> 6) * 65 + 32768) >> 16; /* Q8 */
|
|
CorrQ11[0] = (sum * gainQ10 + 256) >> 9;
|
|
|
|
/* To avoid overflow, we shift down gainQ10 if it is large.
|
|
* We will not lose any precision */
|
|
if (gainQ10 > 400000) {
|
|
tmpGain = gainQ10 >> 3;
|
|
round = 32;
|
|
shftVal = 6;
|
|
} else {
|
|
tmpGain = gainQ10;
|
|
round = 256;
|
|
shftVal = 9;
|
|
}
|
|
|
|
for (k = 1; k < AR_ORDER + 1; k++) {
|
|
sum = 16384;
|
|
for (n = k; n < AR_ORDER + 1; n++)
|
|
sum += WEBRTC_SPL_MUL(ARCoefQ12[n - k], ARCoefQ12[n]); /* Q24 */
|
|
sum >>= 15;
|
|
CorrQ11[k] = (sum * tmpGain + round) >> shftVal;
|
|
}
|
|
sum = CorrQ11[0] << 7;
|
|
for (n = 0; n < FRAMESAMPLES / 8; n++) {
|
|
CurveQ16[n] = sum;
|
|
}
|
|
for (k = 1; k < AR_ORDER; k += 2) {
|
|
for (n = 0; n < FRAMESAMPLES / 8; n++) {
|
|
CurveQ16[n] += (WebRtcIsac_kCos[k][n] * CorrQ11[k + 1] + 2) >> 2;
|
|
}
|
|
}
|
|
|
|
CS_ptrQ9 = WebRtcIsac_kCos[0];
|
|
|
|
/* If CorrQ11[1] too large we avoid getting overflow in the
|
|
* calculation by shifting */
|
|
sh = WebRtcSpl_NormW32(CorrQ11[1]);
|
|
if (CorrQ11[1] == 0) { /* Use next correlation */
|
|
sh = WebRtcSpl_NormW32(CorrQ11[2]);
|
|
}
|
|
if (sh < 9) {
|
|
shftVal = 9 - sh;
|
|
} else {
|
|
shftVal = 0;
|
|
}
|
|
for (n = 0; n < FRAMESAMPLES / 8; n++) {
|
|
diffQ16[n] = (CS_ptrQ9[n] * (CorrQ11[1] >> shftVal) + 2) >> 2;
|
|
}
|
|
for (k = 2; k < AR_ORDER; k += 2) {
|
|
CS_ptrQ9 = WebRtcIsac_kCos[k];
|
|
for (n = 0; n < FRAMESAMPLES / 8; n++) {
|
|
diffQ16[n] += (CS_ptrQ9[n] * (CorrQ11[k + 1] >> shftVal) + 2) >> 2;
|
|
}
|
|
}
|
|
|
|
for (k = 0; k < FRAMESAMPLES / 8; k++) {
|
|
int32_t diff_q16_shifted = (int32_t)((uint32_t)(diffQ16[k]) << shftVal);
|
|
CurveQ16[FRAMESAMPLES_QUARTER - 1 - k] = CurveQ16[k] - diff_q16_shifted;
|
|
CurveQ16[k] += diff_q16_shifted;
|
|
}
|
|
}
|
|
|
|
/* Generate array of dither samples in Q7. */
|
|
static void GenerateDitherQ7Lb(int16_t* bufQ7, uint32_t seed,
|
|
int length, int16_t AvgPitchGain_Q12) {
|
|
int k, shft;
|
|
int16_t dither1_Q7, dither2_Q7, dither_gain_Q14;
|
|
|
|
/* This threshold should be equal to that in decode_spec(). */
|
|
if (AvgPitchGain_Q12 < 614) {
|
|
for (k = 0; k < length - 2; k += 3) {
|
|
/* New random unsigned int. */
|
|
seed = (seed * 196314165) + 907633515;
|
|
|
|
/* Fixed-point dither sample between -64 and 64 (Q7). */
|
|
/* dither = seed * 128 / 4294967295 */
|
|
dither1_Q7 = (int16_t)(((int32_t)(seed + 16777216)) >> 25);
|
|
|
|
/* New random unsigned int. */
|
|
seed = (seed * 196314165) + 907633515;
|
|
|
|
/* Fixed-point dither sample between -64 and 64. */
|
|
dither2_Q7 = (int16_t)(((int32_t)(seed + 16777216)) >> 25);
|
|
|
|
shft = (seed >> 25) & 15;
|
|
if (shft < 5) {
|
|
bufQ7[k] = dither1_Q7;
|
|
bufQ7[k + 1] = dither2_Q7;
|
|
bufQ7[k + 2] = 0;
|
|
} else if (shft < 10) {
|
|
bufQ7[k] = dither1_Q7;
|
|
bufQ7[k + 1] = 0;
|
|
bufQ7[k + 2] = dither2_Q7;
|
|
} else {
|
|
bufQ7[k] = 0;
|
|
bufQ7[k + 1] = dither1_Q7;
|
|
bufQ7[k + 2] = dither2_Q7;
|
|
}
|
|
}
|
|
} else {
|
|
dither_gain_Q14 = (int16_t)(22528 - 10 * AvgPitchGain_Q12);
|
|
|
|
/* Dither on half of the coefficients. */
|
|
for (k = 0; k < length - 1; k += 2) {
|
|
/* New random unsigned int */
|
|
seed = (seed * 196314165) + 907633515;
|
|
|
|
/* Fixed-point dither sample between -64 and 64. */
|
|
dither1_Q7 = (int16_t)(((int32_t)(seed + 16777216)) >> 25);
|
|
|
|
/* Dither sample is placed in either even or odd index. */
|
|
shft = (seed >> 25) & 1; /* Either 0 or 1 */
|
|
|
|
bufQ7[k + shft] = (((dither_gain_Q14 * dither1_Q7) + 8192) >> 14);
|
|
bufQ7[k + 1 - shft] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
* GenerateDitherQ7LbUB()
|
|
*
|
|
* generate array of dither samples in Q7 There are less zeros in dither
|
|
* vector compared to GenerateDitherQ7Lb.
|
|
*
|
|
* A uniform random number generator with the range of [-64 64] is employed
|
|
* but the generated dithers are scaled by 0.35, a heuristic scaling.
|
|
*
|
|
* Input:
|
|
* -seed : the initial seed for the random number generator.
|
|
* -length : the number of dither values to be generated.
|
|
*
|
|
* Output:
|
|
* -bufQ7 : pointer to a buffer where dithers are written to.
|
|
*/
|
|
static void GenerateDitherQ7LbUB(
|
|
int16_t* bufQ7,
|
|
uint32_t seed,
|
|
int length) {
|
|
int k;
|
|
for (k = 0; k < length; k++) {
|
|
/* new random unsigned int */
|
|
seed = (seed * 196314165) + 907633515;
|
|
|
|
/* Fixed-point dither sample between -64 and 64 (Q7). */
|
|
/* bufQ7 = seed * 128 / 4294967295 */
|
|
bufQ7[k] = (int16_t)(((int32_t)(seed + 16777216)) >> 25);
|
|
|
|
/* Scale by 0.35. */
|
|
bufQ7[k] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(bufQ7[k], 2048, 13);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Function to decode the complex spectrum from the bit stream
|
|
* returns the total number of bytes in the stream.
|
|
*/
|
|
int WebRtcIsac_DecodeSpec(Bitstr* streamdata, int16_t AvgPitchGain_Q12,
|
|
enum ISACBand band, double* fr, double* fi) {
|
|
int16_t DitherQ7[FRAMESAMPLES];
|
|
int16_t data[FRAMESAMPLES];
|
|
int32_t invARSpec2_Q16[FRAMESAMPLES_QUARTER];
|
|
uint16_t invARSpecQ8[FRAMESAMPLES_QUARTER];
|
|
int16_t ARCoefQ12[AR_ORDER + 1];
|
|
int16_t RCQ15[AR_ORDER];
|
|
int16_t gainQ10;
|
|
int32_t gain2_Q10, res;
|
|
int32_t in_sqrt;
|
|
int32_t newRes;
|
|
int k, len, i;
|
|
int is_12khz = !kIsSWB12;
|
|
int num_dft_coeff = FRAMESAMPLES;
|
|
/* Create dither signal. */
|
|
if (band == kIsacLowerBand) {
|
|
GenerateDitherQ7Lb(DitherQ7, streamdata->W_upper, FRAMESAMPLES,
|
|
AvgPitchGain_Q12);
|
|
} else {
|
|
GenerateDitherQ7LbUB(DitherQ7, streamdata->W_upper, FRAMESAMPLES);
|
|
if (band == kIsacUpperBand12) {
|
|
is_12khz = kIsSWB12;
|
|
num_dft_coeff = FRAMESAMPLES_HALF;
|
|
}
|
|
}
|
|
|
|
/* Decode model parameters. */
|
|
if (WebRtcIsac_DecodeRc(streamdata, RCQ15) < 0)
|
|
return -ISAC_RANGE_ERROR_DECODE_SPECTRUM;
|
|
|
|
WebRtcSpl_ReflCoefToLpc(RCQ15, AR_ORDER, ARCoefQ12);
|
|
|
|
if (WebRtcIsac_DecodeGain2(streamdata, &gain2_Q10) < 0)
|
|
return -ISAC_RANGE_ERROR_DECODE_SPECTRUM;
|
|
|
|
/* Compute inverse AR power spectrum. */
|
|
FindInvArSpec(ARCoefQ12, gain2_Q10, invARSpec2_Q16);
|
|
|
|
/* Convert to magnitude spectrum,
|
|
* by doing square-roots (modified from SPLIB). */
|
|
res = 1 << (WebRtcSpl_GetSizeInBits(invARSpec2_Q16[0]) >> 1);
|
|
for (k = 0; k < FRAMESAMPLES_QUARTER; k++) {
|
|
in_sqrt = invARSpec2_Q16[k];
|
|
i = 10;
|
|
|
|
/* Negative values make no sense for a real sqrt-function. */
|
|
if (in_sqrt < 0)
|
|
in_sqrt = -in_sqrt;
|
|
|
|
newRes = (in_sqrt / res + res) >> 1;
|
|
do {
|
|
res = newRes;
|
|
newRes = (in_sqrt / res + res) >> 1;
|
|
} while (newRes != res && i-- > 0);
|
|
|
|
invARSpecQ8[k] = (int16_t)newRes;
|
|
}
|
|
|
|
len = WebRtcIsac_DecLogisticMulti2(data, streamdata, invARSpecQ8, DitherQ7,
|
|
num_dft_coeff, is_12khz);
|
|
/* Arithmetic decoding of spectrum. */
|
|
if (len < 1) {
|
|
return -ISAC_RANGE_ERROR_DECODE_SPECTRUM;
|
|
}
|
|
|
|
switch (band) {
|
|
case kIsacLowerBand: {
|
|
/* Scale down spectral samples with low SNR. */
|
|
int32_t p1;
|
|
int32_t p2;
|
|
if (AvgPitchGain_Q12 <= 614) {
|
|
p1 = 30 << 10;
|
|
p2 = 32768 + (33 << 16);
|
|
} else {
|
|
p1 = 36 << 10;
|
|
p2 = 32768 + (40 << 16);
|
|
}
|
|
for (k = 0; k < FRAMESAMPLES; k += 4) {
|
|
gainQ10 = WebRtcSpl_DivW32W16ResW16(p1, (int16_t)(
|
|
(invARSpec2_Q16[k >> 2] + p2) >> 16));
|
|
*fr++ = (double)((data[ k ] * gainQ10 + 512) >> 10) / 128.0;
|
|
*fi++ = (double)((data[k + 1] * gainQ10 + 512) >> 10) / 128.0;
|
|
*fr++ = (double)((data[k + 2] * gainQ10 + 512) >> 10) / 128.0;
|
|
*fi++ = (double)((data[k + 3] * gainQ10 + 512) >> 10) / 128.0;
|
|
}
|
|
break;
|
|
}
|
|
case kIsacUpperBand12: {
|
|
for (k = 0, i = 0; k < FRAMESAMPLES_HALF; k += 4) {
|
|
fr[i] = (double)data[ k ] / 128.0;
|
|
fi[i] = (double)data[k + 1] / 128.0;
|
|
i++;
|
|
fr[i] = (double)data[k + 2] / 128.0;
|
|
fi[i] = (double)data[k + 3] / 128.0;
|
|
i++;
|
|
}
|
|
/* The second half of real and imaginary coefficients is zero. This is
|
|
* due to using the old FFT module which requires two signals as input
|
|
* while in 0-12 kHz mode we only have 8-12 kHz band, and the second
|
|
* signal is set to zero. */
|
|
memset(&fr[FRAMESAMPLES_QUARTER], 0, FRAMESAMPLES_QUARTER *
|
|
sizeof(double));
|
|
memset(&fi[FRAMESAMPLES_QUARTER], 0, FRAMESAMPLES_QUARTER *
|
|
sizeof(double));
|
|
break;
|
|
}
|
|
case kIsacUpperBand16: {
|
|
for (i = 0, k = 0; k < FRAMESAMPLES; k += 4, i++) {
|
|
fr[i] = (double)data[ k ] / 128.0;
|
|
fi[i] = (double)data[k + 1] / 128.0;
|
|
fr[(FRAMESAMPLES_HALF) - 1 - i] = (double)data[k + 2] / 128.0;
|
|
fi[(FRAMESAMPLES_HALF) - 1 - i] = (double)data[k + 3] / 128.0;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return len;
|
|
}
|
|
|
|
|
|
int WebRtcIsac_EncodeSpec(const int16_t* fr, const int16_t* fi,
|
|
int16_t AvgPitchGain_Q12, enum ISACBand band,
|
|
Bitstr* streamdata) {
|
|
int16_t ditherQ7[FRAMESAMPLES];
|
|
int16_t dataQ7[FRAMESAMPLES];
|
|
int32_t PSpec[FRAMESAMPLES_QUARTER];
|
|
int32_t invARSpec2_Q16[FRAMESAMPLES_QUARTER];
|
|
uint16_t invARSpecQ8[FRAMESAMPLES_QUARTER];
|
|
int32_t CorrQ7[AR_ORDER + 1];
|
|
int32_t CorrQ7_norm[AR_ORDER + 1];
|
|
int16_t RCQ15[AR_ORDER];
|
|
int16_t ARCoefQ12[AR_ORDER + 1];
|
|
int32_t gain2_Q10;
|
|
int16_t val;
|
|
int32_t nrg, res;
|
|
uint32_t sum;
|
|
int32_t in_sqrt;
|
|
int32_t newRes;
|
|
int16_t err;
|
|
uint32_t nrg_u32;
|
|
int shift_var;
|
|
int k, n, j, i;
|
|
int is_12khz = !kIsSWB12;
|
|
int num_dft_coeff = FRAMESAMPLES;
|
|
|
|
/* Create dither signal. */
|
|
if (band == kIsacLowerBand) {
|
|
GenerateDitherQ7Lb(ditherQ7, streamdata->W_upper, FRAMESAMPLES,
|
|
AvgPitchGain_Q12);
|
|
} else {
|
|
GenerateDitherQ7LbUB(ditherQ7, streamdata->W_upper, FRAMESAMPLES);
|
|
if (band == kIsacUpperBand12) {
|
|
is_12khz = kIsSWB12;
|
|
num_dft_coeff = FRAMESAMPLES_HALF;
|
|
}
|
|
}
|
|
|
|
/* add dither and quantize, and compute power spectrum */
|
|
switch (band) {
|
|
case kIsacLowerBand: {
|
|
for (k = 0; k < FRAMESAMPLES; k += 4) {
|
|
val = ((*fr++ + ditherQ7[k] + 64) & 0xFF80) - ditherQ7[k];
|
|
dataQ7[k] = val;
|
|
sum = val * val;
|
|
|
|
val = ((*fi++ + ditherQ7[k + 1] + 64) & 0xFF80) - ditherQ7[k + 1];
|
|
dataQ7[k + 1] = val;
|
|
sum += val * val;
|
|
|
|
val = ((*fr++ + ditherQ7[k + 2] + 64) & 0xFF80) - ditherQ7[k + 2];
|
|
dataQ7[k + 2] = val;
|
|
sum += val * val;
|
|
|
|
val = ((*fi++ + ditherQ7[k + 3] + 64) & 0xFF80) - ditherQ7[k + 3];
|
|
dataQ7[k + 3] = val;
|
|
sum += val * val;
|
|
|
|
PSpec[k >> 2] = sum >> 2;
|
|
}
|
|
break;
|
|
}
|
|
case kIsacUpperBand12: {
|
|
for (k = 0, j = 0; k < FRAMESAMPLES_HALF; k += 4) {
|
|
val = ((*fr++ + ditherQ7[k] + 64) & 0xFF80) - ditherQ7[k];
|
|
dataQ7[k] = val;
|
|
sum = val * val;
|
|
|
|
val = ((*fi++ + ditherQ7[k + 1] + 64) & 0xFF80) - ditherQ7[k + 1];
|
|
dataQ7[k + 1] = val;
|
|
sum += val * val;
|
|
|
|
PSpec[j++] = sum >> 1;
|
|
|
|
val = ((*fr++ + ditherQ7[k + 2] + 64) & 0xFF80) - ditherQ7[k + 2];
|
|
dataQ7[k + 2] = val;
|
|
sum = val * val;
|
|
|
|
val = ((*fi++ + ditherQ7[k + 3] + 64) & 0xFF80) - ditherQ7[k + 3];
|
|
dataQ7[k + 3] = val;
|
|
sum += val * val;
|
|
|
|
PSpec[j++] = sum >> 1;
|
|
}
|
|
break;
|
|
}
|
|
case kIsacUpperBand16: {
|
|
for (j = 0, k = 0; k < FRAMESAMPLES; k += 4, j++) {
|
|
val = ((fr[j] + ditherQ7[k] + 64) & 0xFF80) - ditherQ7[k];
|
|
dataQ7[k] = val;
|
|
sum = val * val;
|
|
|
|
val = ((fi[j] + ditherQ7[k + 1] + 64) & 0xFF80) - ditherQ7[k + 1];
|
|
dataQ7[k + 1] = val;
|
|
sum += val * val;
|
|
|
|
val = ((fr[(FRAMESAMPLES_HALF) - 1 - j] + ditherQ7[k + 2] + 64) &
|
|
0xFF80) - ditherQ7[k + 2];
|
|
dataQ7[k + 2] = val;
|
|
sum += val * val;
|
|
|
|
val = ((fi[(FRAMESAMPLES_HALF) - 1 - j] + ditherQ7[k + 3] + 64) &
|
|
0xFF80) - ditherQ7[k + 3];
|
|
dataQ7[k + 3] = val;
|
|
sum += val * val;
|
|
|
|
PSpec[k >> 2] = sum >> 2;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* compute correlation from power spectrum */
|
|
FindCorrelation(PSpec, CorrQ7);
|
|
|
|
/* Find AR coefficients */
|
|
/* Aumber of bit shifts to 14-bit normalize CorrQ7[0]
|
|
* (leaving room for sign) */
|
|
shift_var = WebRtcSpl_NormW32(CorrQ7[0]) - 18;
|
|
|
|
if (shift_var > 0) {
|
|
for (k = 0; k < AR_ORDER + 1; k++) {
|
|
CorrQ7_norm[k] = CorrQ7[k] << shift_var;
|
|
}
|
|
} else {
|
|
for (k = 0; k < AR_ORDER + 1; k++) {
|
|
CorrQ7_norm[k] = CorrQ7[k] >> (-shift_var);
|
|
}
|
|
}
|
|
|
|
/* Find RC coefficients. */
|
|
WebRtcSpl_AutoCorrToReflCoef(CorrQ7_norm, AR_ORDER, RCQ15);
|
|
|
|
/* Quantize & code RC Coefficient. */
|
|
WebRtcIsac_EncodeRc(RCQ15, streamdata);
|
|
|
|
/* RC -> AR coefficients */
|
|
WebRtcSpl_ReflCoefToLpc(RCQ15, AR_ORDER, ARCoefQ12);
|
|
|
|
/* Compute ARCoef' * Corr * ARCoef in Q19. */
|
|
nrg = 0;
|
|
for (j = 0; j <= AR_ORDER; j++) {
|
|
for (n = 0; n <= j; n++) {
|
|
nrg += (ARCoefQ12[j] * ((CorrQ7_norm[j - n] * ARCoefQ12[n] + 256) >> 9) +
|
|
4) >> 3;
|
|
}
|
|
for (n = j + 1; n <= AR_ORDER; n++) {
|
|
nrg += (ARCoefQ12[j] * ((CorrQ7_norm[n - j] * ARCoefQ12[n] + 256) >> 9) +
|
|
4) >> 3;
|
|
}
|
|
}
|
|
|
|
nrg_u32 = (uint32_t)nrg;
|
|
if (shift_var > 0) {
|
|
nrg_u32 = nrg_u32 >> shift_var;
|
|
} else {
|
|
nrg_u32 = nrg_u32 << (-shift_var);
|
|
}
|
|
if (nrg_u32 > 0x7FFFFFFF) {
|
|
nrg = 0x7FFFFFFF;
|
|
} else {
|
|
nrg = (int32_t)nrg_u32;
|
|
}
|
|
/* Also shifts 31 bits to the left! */
|
|
gain2_Q10 = WebRtcSpl_DivResultInQ31(FRAMESAMPLES_QUARTER, nrg);
|
|
|
|
/* Quantize & code gain2_Q10. */
|
|
if (WebRtcIsac_EncodeGain2(&gain2_Q10, streamdata)) {
|
|
return -1;
|
|
}
|
|
|
|
/* Compute inverse AR power spectrum. */
|
|
FindInvArSpec(ARCoefQ12, gain2_Q10, invARSpec2_Q16);
|
|
/* Convert to magnitude spectrum, by doing square-roots
|
|
* (modified from SPLIB). */
|
|
res = 1 << (WebRtcSpl_GetSizeInBits(invARSpec2_Q16[0]) >> 1);
|
|
for (k = 0; k < FRAMESAMPLES_QUARTER; k++) {
|
|
in_sqrt = invARSpec2_Q16[k];
|
|
i = 10;
|
|
/* Negative values make no sense for a real sqrt-function. */
|
|
if (in_sqrt < 0) {
|
|
in_sqrt = -in_sqrt;
|
|
}
|
|
newRes = (in_sqrt / res + res) >> 1;
|
|
do {
|
|
res = newRes;
|
|
newRes = (in_sqrt / res + res) >> 1;
|
|
} while (newRes != res && i-- > 0);
|
|
|
|
invARSpecQ8[k] = (int16_t)newRes;
|
|
}
|
|
/* arithmetic coding of spectrum */
|
|
err = WebRtcIsac_EncLogisticMulti2(streamdata, dataQ7, invARSpecQ8,
|
|
num_dft_coeff, is_12khz);
|
|
if (err < 0) {
|
|
return (err);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* step-up */
|
|
void WebRtcIsac_Rc2Poly(double* RC, int N, double* a) {
|
|
int m, k;
|
|
double tmp[MAX_AR_MODEL_ORDER];
|
|
|
|
a[0] = 1.0;
|
|
tmp[0] = 1.0;
|
|
for (m = 1; m <= N; m++) {
|
|
/* copy */
|
|
memcpy(&tmp[1], &a[1], (m - 1) * sizeof(double));
|
|
a[m] = RC[m - 1];
|
|
for (k = 1; k < m; k++) {
|
|
a[k] += RC[m - 1] * tmp[m - k];
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* step-down */
|
|
void WebRtcIsac_Poly2Rc(double* a, int N, double* RC) {
|
|
int m, k;
|
|
double tmp[MAX_AR_MODEL_ORDER];
|
|
double tmp_inv;
|
|
|
|
RC[N - 1] = a[N];
|
|
for (m = N - 1; m > 0; m--) {
|
|
tmp_inv = 1.0 / (1.0 - RC[m] * RC[m]);
|
|
for (k = 1; k <= m; k++) {
|
|
tmp[k] = (a[k] - RC[m] * a[m - k + 1]) * tmp_inv;
|
|
}
|
|
|
|
memcpy(&a[1], &tmp[1], (m - 1) * sizeof(double));
|
|
RC[m - 1] = tmp[m];
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
#define MAX_ORDER 100
|
|
|
|
/* Matlab's LAR definition */
|
|
void WebRtcIsac_Rc2Lar(const double* refc, double* lar, int order) {
|
|
int k;
|
|
for (k = 0; k < order; k++) {
|
|
lar[k] = log((1 + refc[k]) / (1 - refc[k]));
|
|
}
|
|
}
|
|
|
|
|
|
void WebRtcIsac_Lar2Rc(const double* lar, double* refc, int order) {
|
|
int k;
|
|
double tmp;
|
|
|
|
for (k = 0; k < order; k++) {
|
|
tmp = exp(lar[k]);
|
|
refc[k] = (tmp - 1) / (tmp + 1);
|
|
}
|
|
}
|
|
|
|
void WebRtcIsac_Poly2Lar(double* lowband, int orderLo, double* hiband,
|
|
int orderHi, int Nsub, double* lars) {
|
|
int k;
|
|
double rc[MAX_ORDER], *inpl, *inph, *outp;
|
|
|
|
inpl = lowband;
|
|
inph = hiband;
|
|
outp = lars;
|
|
for (k = 0; k < Nsub; k++) {
|
|
/* gains */
|
|
outp[0] = inpl[0];
|
|
outp[1] = inph[0];
|
|
outp += 2;
|
|
|
|
/* Low band */
|
|
inpl[0] = 1.0;
|
|
WebRtcIsac_Poly2Rc(inpl, orderLo, rc);
|
|
WebRtcIsac_Rc2Lar(rc, outp, orderLo);
|
|
outp += orderLo;
|
|
|
|
/* High band */
|
|
inph[0] = 1.0;
|
|
WebRtcIsac_Poly2Rc(inph, orderHi, rc);
|
|
WebRtcIsac_Rc2Lar(rc, outp, orderHi);
|
|
outp += orderHi;
|
|
|
|
inpl += orderLo + 1;
|
|
inph += orderHi + 1;
|
|
}
|
|
}
|
|
|
|
|
|
int16_t WebRtcIsac_Poly2LarUB(double* lpcVecs, int16_t bandwidth) {
|
|
double poly[MAX_ORDER];
|
|
double rc[MAX_ORDER];
|
|
double* ptrIO;
|
|
int16_t vecCntr;
|
|
int16_t vecSize;
|
|
int16_t numVec;
|
|
|
|
vecSize = UB_LPC_ORDER;
|
|
switch (bandwidth) {
|
|
case isac12kHz: {
|
|
numVec = UB_LPC_VEC_PER_FRAME;
|
|
break;
|
|
}
|
|
case isac16kHz: {
|
|
numVec = UB16_LPC_VEC_PER_FRAME;
|
|
break;
|
|
}
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
ptrIO = lpcVecs;
|
|
poly[0] = 1.0;
|
|
for (vecCntr = 0; vecCntr < numVec; vecCntr++) {
|
|
memcpy(&poly[1], ptrIO, sizeof(double) * vecSize);
|
|
WebRtcIsac_Poly2Rc(poly, vecSize, rc);
|
|
WebRtcIsac_Rc2Lar(rc, ptrIO, vecSize);
|
|
ptrIO += vecSize;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
void WebRtcIsac_Lar2Poly(double* lars, double* lowband, int orderLo,
|
|
double* hiband, int orderHi, int Nsub) {
|
|
int k, orderTot;
|
|
double rc[MAX_ORDER], *outpl, *outph, *inp;
|
|
|
|
orderTot = (orderLo + orderHi + 2);
|
|
outpl = lowband;
|
|
outph = hiband;
|
|
/* First two elements of 'inp' store gains*/
|
|
inp = lars;
|
|
for (k = 0; k < Nsub; k++) {
|
|
/* Low band */
|
|
WebRtcIsac_Lar2Rc(&inp[2], rc, orderLo);
|
|
WebRtcIsac_Rc2Poly(rc, orderLo, outpl);
|
|
|
|
/* High band */
|
|
WebRtcIsac_Lar2Rc(&inp[orderLo + 2], rc, orderHi);
|
|
WebRtcIsac_Rc2Poly(rc, orderHi, outph);
|
|
|
|
/* gains */
|
|
outpl[0] = inp[0];
|
|
outph[0] = inp[1];
|
|
|
|
outpl += orderLo + 1;
|
|
outph += orderHi + 1;
|
|
inp += orderTot;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* assumes 2 LAR vectors interpolates to 'numPolyVec' A-polynomials
|
|
* Note: 'numPolyVecs' includes the first and the last point of the interval
|
|
*/
|
|
void WebRtcIsac_Lar2PolyInterpolUB(double* larVecs, double* percepFilterParams,
|
|
int numPolyVecs) {
|
|
int polyCntr, coeffCntr;
|
|
double larInterpol[UB_LPC_ORDER];
|
|
double rc[UB_LPC_ORDER];
|
|
double delta[UB_LPC_ORDER];
|
|
|
|
/* calculate the step-size for linear interpolation coefficients */
|
|
for (coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++) {
|
|
delta[coeffCntr] = (larVecs[UB_LPC_ORDER + coeffCntr] -
|
|
larVecs[coeffCntr]) / (numPolyVecs - 1);
|
|
}
|
|
|
|
for (polyCntr = 0; polyCntr < numPolyVecs; polyCntr++) {
|
|
for (coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++) {
|
|
larInterpol[coeffCntr] = larVecs[coeffCntr] +
|
|
delta[coeffCntr] * polyCntr;
|
|
}
|
|
WebRtcIsac_Lar2Rc(larInterpol, rc, UB_LPC_ORDER);
|
|
|
|
/* convert to A-polynomial, the following function returns A[0] = 1;
|
|
* which is written where gains had to be written. Then we write the
|
|
* gain (outside this function). This way we say a memcpy. */
|
|
WebRtcIsac_Rc2Poly(rc, UB_LPC_ORDER, percepFilterParams);
|
|
percepFilterParams += (UB_LPC_ORDER + 1);
|
|
}
|
|
}
|
|
|
|
int WebRtcIsac_DecodeLpc(Bitstr* streamdata, double* LPCCoef_lo,
|
|
double* LPCCoef_hi) {
|
|
double lars[KLT_ORDER_GAIN + KLT_ORDER_SHAPE];
|
|
int err;
|
|
|
|
err = WebRtcIsac_DecodeLpcCoef(streamdata, lars);
|
|
if (err < 0) {
|
|
return -ISAC_RANGE_ERROR_DECODE_LPC;
|
|
}
|
|
WebRtcIsac_Lar2Poly(lars, LPCCoef_lo, ORDERLO, LPCCoef_hi, ORDERHI,
|
|
SUBFRAMES);
|
|
return 0;
|
|
}
|
|
|
|
int16_t WebRtcIsac_DecodeInterpolLpcUb(Bitstr* streamdata,
|
|
double* percepFilterParams,
|
|
int16_t bandwidth) {
|
|
double lpcCoeff[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
|
|
int err;
|
|
int interpolCntr;
|
|
int subframeCntr;
|
|
int16_t numSegments;
|
|
int16_t numVecPerSegment;
|
|
int16_t numGains;
|
|
|
|
double percepFilterGains[SUBFRAMES << 1];
|
|
double* ptrOutParam = percepFilterParams;
|
|
|
|
err = WebRtcIsac_DecodeLpcCoefUB(streamdata, lpcCoeff, percepFilterGains,
|
|
bandwidth);
|
|
if (err < 0) {
|
|
return -ISAC_RANGE_ERROR_DECODE_LPC;
|
|
}
|
|
|
|
switch (bandwidth) {
|
|
case isac12kHz: {
|
|
numGains = SUBFRAMES;
|
|
numSegments = UB_LPC_VEC_PER_FRAME - 1;
|
|
numVecPerSegment = kLpcVecPerSegmentUb12;
|
|
break;
|
|
}
|
|
case isac16kHz: {
|
|
numGains = SUBFRAMES << 1;
|
|
numSegments = UB16_LPC_VEC_PER_FRAME - 1;
|
|
numVecPerSegment = kLpcVecPerSegmentUb16;
|
|
break;
|
|
}
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
for (interpolCntr = 0; interpolCntr < numSegments; interpolCntr++) {
|
|
WebRtcIsac_Lar2PolyInterpolUB(&lpcCoeff[interpolCntr * UB_LPC_ORDER],
|
|
ptrOutParam, numVecPerSegment + 1);
|
|
ptrOutParam += (numVecPerSegment * (UB_LPC_ORDER + 1));
|
|
}
|
|
|
|
ptrOutParam = percepFilterParams;
|
|
|
|
if (bandwidth == isac16kHz) {
|
|
ptrOutParam += (1 + UB_LPC_ORDER);
|
|
}
|
|
|
|
for (subframeCntr = 0; subframeCntr < numGains; subframeCntr++) {
|
|
*ptrOutParam = percepFilterGains[subframeCntr];
|
|
ptrOutParam += (1 + UB_LPC_ORDER);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* decode & dequantize LPC Coef */
|
|
int WebRtcIsac_DecodeLpcCoef(Bitstr* streamdata, double* LPCCoef) {
|
|
int j, k, n, pos, pos2, posg, poss, offsg, offss, offs2;
|
|
int index_g[KLT_ORDER_GAIN], index_s[KLT_ORDER_SHAPE];
|
|
double tmpcoeffs_g[KLT_ORDER_GAIN], tmpcoeffs_s[KLT_ORDER_SHAPE];
|
|
double tmpcoeffs2_g[KLT_ORDER_GAIN], tmpcoeffs2_s[KLT_ORDER_SHAPE];
|
|
double sum;
|
|
int err;
|
|
int model = 1;
|
|
|
|
/* entropy decoding of model number */
|
|
/* We are keeping this for backward compatibility of bit-streams. */
|
|
err = WebRtcIsac_DecHistOneStepMulti(&model, streamdata,
|
|
WebRtcIsac_kQKltModelCdfPtr,
|
|
WebRtcIsac_kQKltModelInitIndex, 1);
|
|
if (err < 0) {
|
|
return err;
|
|
}
|
|
/* Only accepted value of model is 0. It is kept in bit-stream for backward
|
|
* compatibility. */
|
|
if (model != 0) {
|
|
return -ISAC_DISALLOWED_LPC_MODEL;
|
|
}
|
|
|
|
/* entropy decoding of quantization indices */
|
|
err = WebRtcIsac_DecHistOneStepMulti(
|
|
index_s, streamdata, WebRtcIsac_kQKltCdfPtrShape,
|
|
WebRtcIsac_kQKltInitIndexShape, KLT_ORDER_SHAPE);
|
|
if (err < 0) {
|
|
return err;
|
|
}
|
|
err = WebRtcIsac_DecHistOneStepMulti(
|
|
index_g, streamdata, WebRtcIsac_kQKltCdfPtrGain,
|
|
WebRtcIsac_kQKltInitIndexGain, KLT_ORDER_GAIN);
|
|
if (err < 0) {
|
|
return err;
|
|
}
|
|
|
|
/* find quantization levels for coefficients */
|
|
for (k = 0; k < KLT_ORDER_SHAPE; k++) {
|
|
tmpcoeffs_s[k] =
|
|
WebRtcIsac_kQKltLevelsShape[WebRtcIsac_kQKltOffsetShape[k] +
|
|
index_s[k]];
|
|
}
|
|
for (k = 0; k < KLT_ORDER_GAIN; k++) {
|
|
tmpcoeffs_g[k] = WebRtcIsac_kQKltLevelsGain[WebRtcIsac_kQKltOffsetGain[k] +
|
|
index_g[k]];
|
|
}
|
|
|
|
/* Inverse KLT */
|
|
|
|
/* Left transform, transpose matrix! */
|
|
offsg = 0;
|
|
offss = 0;
|
|
posg = 0;
|
|
poss = 0;
|
|
for (j = 0; j < SUBFRAMES; j++) {
|
|
offs2 = 0;
|
|
for (k = 0; k < LPC_GAIN_ORDER; k++) {
|
|
sum = 0;
|
|
pos = offsg;
|
|
pos2 = offs2;
|
|
for (n = 0; n < LPC_GAIN_ORDER; n++) {
|
|
sum += tmpcoeffs_g[pos++] * WebRtcIsac_kKltT1Gain[pos2++];
|
|
}
|
|
tmpcoeffs2_g[posg++] = sum;
|
|
offs2 += LPC_GAIN_ORDER;
|
|
}
|
|
offs2 = 0;
|
|
for (k = 0; k < LPC_SHAPE_ORDER; k++) {
|
|
sum = 0;
|
|
pos = offss;
|
|
pos2 = offs2;
|
|
for (n = 0; n < LPC_SHAPE_ORDER; n++) {
|
|
sum += tmpcoeffs_s[pos++] * WebRtcIsac_kKltT1Shape[pos2++];
|
|
}
|
|
tmpcoeffs2_s[poss++] = sum;
|
|
offs2 += LPC_SHAPE_ORDER;
|
|
}
|
|
offsg += LPC_GAIN_ORDER;
|
|
offss += LPC_SHAPE_ORDER;
|
|
}
|
|
|
|
/* Right transform, transpose matrix */
|
|
offsg = 0;
|
|
offss = 0;
|
|
posg = 0;
|
|
poss = 0;
|
|
for (j = 0; j < SUBFRAMES; j++) {
|
|
posg = offsg;
|
|
for (k = 0; k < LPC_GAIN_ORDER; k++) {
|
|
sum = 0;
|
|
pos = k;
|
|
pos2 = j;
|
|
for (n = 0; n < SUBFRAMES; n++) {
|
|
sum += tmpcoeffs2_g[pos] * WebRtcIsac_kKltT2Gain[pos2];
|
|
pos += LPC_GAIN_ORDER;
|
|
pos2 += SUBFRAMES;
|
|
|
|
}
|
|
tmpcoeffs_g[posg++] = sum;
|
|
}
|
|
poss = offss;
|
|
for (k = 0; k < LPC_SHAPE_ORDER; k++) {
|
|
sum = 0;
|
|
pos = k;
|
|
pos2 = j;
|
|
for (n = 0; n < SUBFRAMES; n++) {
|
|
sum += tmpcoeffs2_s[pos] * WebRtcIsac_kKltT2Shape[pos2];
|
|
pos += LPC_SHAPE_ORDER;
|
|
pos2 += SUBFRAMES;
|
|
}
|
|
tmpcoeffs_s[poss++] = sum;
|
|
}
|
|
offsg += LPC_GAIN_ORDER;
|
|
offss += LPC_SHAPE_ORDER;
|
|
}
|
|
|
|
/* scaling, mean addition, and gain restoration */
|
|
posg = 0;
|
|
poss = 0;
|
|
pos = 0;
|
|
for (k = 0; k < SUBFRAMES; k++) {
|
|
/* log gains */
|
|
LPCCoef[pos] = tmpcoeffs_g[posg] / LPC_GAIN_SCALE;
|
|
LPCCoef[pos] += WebRtcIsac_kLpcMeansGain[posg];
|
|
LPCCoef[pos] = exp(LPCCoef[pos]);
|
|
pos++;
|
|
posg++;
|
|
LPCCoef[pos] = tmpcoeffs_g[posg] / LPC_GAIN_SCALE;
|
|
LPCCoef[pos] += WebRtcIsac_kLpcMeansGain[posg];
|
|
LPCCoef[pos] = exp(LPCCoef[pos]);
|
|
pos++;
|
|
posg++;
|
|
|
|
/* Low-band LAR coefficients. */
|
|
for (n = 0; n < LPC_LOBAND_ORDER; n++, pos++, poss++) {
|
|
LPCCoef[pos] = tmpcoeffs_s[poss] / LPC_LOBAND_SCALE;
|
|
LPCCoef[pos] += WebRtcIsac_kLpcMeansShape[poss];
|
|
}
|
|
|
|
/* High-band LAR coefficients. */
|
|
for (n = 0; n < LPC_HIBAND_ORDER; n++, pos++, poss++) {
|
|
LPCCoef[pos] = tmpcoeffs_s[poss] / LPC_HIBAND_SCALE;
|
|
LPCCoef[pos] += WebRtcIsac_kLpcMeansShape[poss];
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* Encode LPC in LAR domain. */
|
|
void WebRtcIsac_EncodeLar(double* LPCCoef, Bitstr* streamdata,
|
|
IsacSaveEncoderData* encData) {
|
|
int j, k, n, pos, pos2, poss, offss, offs2;
|
|
int index_s[KLT_ORDER_SHAPE];
|
|
int index_ovr_s[KLT_ORDER_SHAPE];
|
|
double tmpcoeffs_s[KLT_ORDER_SHAPE];
|
|
double tmpcoeffs2_s[KLT_ORDER_SHAPE];
|
|
double sum;
|
|
const int kModel = 0;
|
|
|
|
/* Mean removal and scaling. */
|
|
poss = 0;
|
|
pos = 0;
|
|
for (k = 0; k < SUBFRAMES; k++) {
|
|
/* First two element are gains, move over them. */
|
|
pos += 2;
|
|
|
|
/* Low-band LAR coefficients. */
|
|
for (n = 0; n < LPC_LOBAND_ORDER; n++, poss++, pos++) {
|
|
tmpcoeffs_s[poss] = LPCCoef[pos] - WebRtcIsac_kLpcMeansShape[poss];
|
|
tmpcoeffs_s[poss] *= LPC_LOBAND_SCALE;
|
|
}
|
|
|
|
/* High-band LAR coefficients. */
|
|
for (n = 0; n < LPC_HIBAND_ORDER; n++, poss++, pos++) {
|
|
tmpcoeffs_s[poss] = LPCCoef[pos] - WebRtcIsac_kLpcMeansShape[poss];
|
|
tmpcoeffs_s[poss] *= LPC_HIBAND_SCALE;
|
|
}
|
|
}
|
|
|
|
/* KLT */
|
|
|
|
/* Left transform. */
|
|
offss = 0;
|
|
for (j = 0; j < SUBFRAMES; j++) {
|
|
poss = offss;
|
|
for (k = 0; k < LPC_SHAPE_ORDER; k++) {
|
|
sum = 0;
|
|
pos = offss;
|
|
pos2 = k;
|
|
for (n = 0; n < LPC_SHAPE_ORDER; n++) {
|
|
sum += tmpcoeffs_s[pos++] * WebRtcIsac_kKltT1Shape[pos2];
|
|
pos2 += LPC_SHAPE_ORDER;
|
|
}
|
|
tmpcoeffs2_s[poss++] = sum;
|
|
}
|
|
offss += LPC_SHAPE_ORDER;
|
|
}
|
|
|
|
/* Right transform. */
|
|
offss = 0;
|
|
offs2 = 0;
|
|
for (j = 0; j < SUBFRAMES; j++) {
|
|
poss = offss;
|
|
for (k = 0; k < LPC_SHAPE_ORDER; k++) {
|
|
sum = 0;
|
|
pos = k;
|
|
pos2 = offs2;
|
|
for (n = 0; n < SUBFRAMES; n++) {
|
|
sum += tmpcoeffs2_s[pos] * WebRtcIsac_kKltT2Shape[pos2++];
|
|
pos += LPC_SHAPE_ORDER;
|
|
}
|
|
tmpcoeffs_s[poss++] = sum;
|
|
}
|
|
offs2 += SUBFRAMES;
|
|
offss += LPC_SHAPE_ORDER;
|
|
}
|
|
|
|
/* Quantize coefficients. */
|
|
for (k = 0; k < KLT_ORDER_SHAPE; k++) {
|
|
index_s[k] = (WebRtcIsac_lrint(tmpcoeffs_s[k] / KLT_STEPSIZE)) +
|
|
WebRtcIsac_kQKltQuantMinShape[k];
|
|
if (index_s[k] < 0) {
|
|
index_s[k] = 0;
|
|
} else if (index_s[k] > WebRtcIsac_kQKltMaxIndShape[k]) {
|
|
index_s[k] = WebRtcIsac_kQKltMaxIndShape[k];
|
|
}
|
|
index_ovr_s[k] = WebRtcIsac_kQKltOffsetShape[k] + index_s[k];
|
|
}
|
|
|
|
|
|
/* Only one model remains in this version of the code, kModel = 0. We
|
|
* are keeping for bit-streams to be backward compatible. */
|
|
/* entropy coding of model number */
|
|
WebRtcIsac_EncHistMulti(streamdata, &kModel, WebRtcIsac_kQKltModelCdfPtr, 1);
|
|
|
|
/* Save data for creation of multiple bit streams */
|
|
/* Entropy coding of quantization indices - shape only. */
|
|
WebRtcIsac_EncHistMulti(streamdata, index_s, WebRtcIsac_kQKltCdfPtrShape,
|
|
KLT_ORDER_SHAPE);
|
|
|
|
/* Save data for creation of multiple bit streams. */
|
|
for (k = 0; k < KLT_ORDER_SHAPE; k++) {
|
|
encData->LPCindex_s[KLT_ORDER_SHAPE * encData->startIdx + k] = index_s[k];
|
|
}
|
|
|
|
/* Find quantization levels for shape coefficients. */
|
|
for (k = 0; k < KLT_ORDER_SHAPE; k++) {
|
|
tmpcoeffs_s[k] = WebRtcIsac_kQKltLevelsShape[index_ovr_s[k]];
|
|
}
|
|
/* Inverse KLT. */
|
|
/* Left transform, transpose matrix.! */
|
|
offss = 0;
|
|
poss = 0;
|
|
for (j = 0; j < SUBFRAMES; j++) {
|
|
offs2 = 0;
|
|
for (k = 0; k < LPC_SHAPE_ORDER; k++) {
|
|
sum = 0;
|
|
pos = offss;
|
|
pos2 = offs2;
|
|
for (n = 0; n < LPC_SHAPE_ORDER; n++) {
|
|
sum += tmpcoeffs_s[pos++] * WebRtcIsac_kKltT1Shape[pos2++];
|
|
}
|
|
tmpcoeffs2_s[poss++] = sum;
|
|
offs2 += LPC_SHAPE_ORDER;
|
|
}
|
|
offss += LPC_SHAPE_ORDER;
|
|
}
|
|
|
|
/* Right transform, Transpose matrix */
|
|
offss = 0;
|
|
poss = 0;
|
|
for (j = 0; j < SUBFRAMES; j++) {
|
|
poss = offss;
|
|
for (k = 0; k < LPC_SHAPE_ORDER; k++) {
|
|
sum = 0;
|
|
pos = k;
|
|
pos2 = j;
|
|
for (n = 0; n < SUBFRAMES; n++) {
|
|
sum += tmpcoeffs2_s[pos] * WebRtcIsac_kKltT2Shape[pos2];
|
|
pos += LPC_SHAPE_ORDER;
|
|
pos2 += SUBFRAMES;
|
|
}
|
|
tmpcoeffs_s[poss++] = sum;
|
|
}
|
|
offss += LPC_SHAPE_ORDER;
|
|
}
|
|
|
|
/* Scaling, mean addition, and gain restoration. */
|
|
poss = 0;
|
|
pos = 0;
|
|
for (k = 0; k < SUBFRAMES; k++) {
|
|
/* Ignore gains. */
|
|
pos += 2;
|
|
|
|
/* Low band LAR coefficients. */
|
|
for (n = 0; n < LPC_LOBAND_ORDER; n++, pos++, poss++) {
|
|
LPCCoef[pos] = tmpcoeffs_s[poss] / LPC_LOBAND_SCALE;
|
|
LPCCoef[pos] += WebRtcIsac_kLpcMeansShape[poss];
|
|
}
|
|
|
|
/* High band LAR coefficients. */
|
|
for (n = 0; n < LPC_HIBAND_ORDER; n++, pos++, poss++) {
|
|
LPCCoef[pos] = tmpcoeffs_s[poss] / LPC_HIBAND_SCALE;
|
|
LPCCoef[pos] += WebRtcIsac_kLpcMeansShape[poss];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void WebRtcIsac_EncodeLpcLb(double* LPCCoef_lo, double* LPCCoef_hi,
|
|
Bitstr* streamdata, IsacSaveEncoderData* encData) {
|
|
double lars[KLT_ORDER_GAIN + KLT_ORDER_SHAPE];
|
|
int k;
|
|
|
|
WebRtcIsac_Poly2Lar(LPCCoef_lo, ORDERLO, LPCCoef_hi, ORDERHI, SUBFRAMES,
|
|
lars);
|
|
WebRtcIsac_EncodeLar(lars, streamdata, encData);
|
|
WebRtcIsac_Lar2Poly(lars, LPCCoef_lo, ORDERLO, LPCCoef_hi, ORDERHI,
|
|
SUBFRAMES);
|
|
/* Save data for creation of multiple bit streams (and transcoding). */
|
|
for (k = 0; k < (ORDERLO + 1)*SUBFRAMES; k++) {
|
|
encData->LPCcoeffs_lo[(ORDERLO + 1)*SUBFRAMES * encData->startIdx + k] =
|
|
LPCCoef_lo[k];
|
|
}
|
|
for (k = 0; k < (ORDERHI + 1)*SUBFRAMES; k++) {
|
|
encData->LPCcoeffs_hi[(ORDERHI + 1)*SUBFRAMES * encData->startIdx + k] =
|
|
LPCCoef_hi[k];
|
|
}
|
|
}
|
|
|
|
|
|
int16_t WebRtcIsac_EncodeLpcUB(double* lpcVecs, Bitstr* streamdata,
|
|
double* interpolLPCCoeff,
|
|
int16_t bandwidth,
|
|
ISACUBSaveEncDataStruct* encData) {
|
|
double U[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
|
|
int idx[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
|
|
int interpolCntr;
|
|
|
|
WebRtcIsac_Poly2LarUB(lpcVecs, bandwidth);
|
|
WebRtcIsac_RemoveLarMean(lpcVecs, bandwidth);
|
|
WebRtcIsac_DecorrelateIntraVec(lpcVecs, U, bandwidth);
|
|
WebRtcIsac_DecorrelateInterVec(U, lpcVecs, bandwidth);
|
|
WebRtcIsac_QuantizeUncorrLar(lpcVecs, idx, bandwidth);
|
|
|
|
WebRtcIsac_CorrelateInterVec(lpcVecs, U, bandwidth);
|
|
WebRtcIsac_CorrelateIntraVec(U, lpcVecs, bandwidth);
|
|
WebRtcIsac_AddLarMean(lpcVecs, bandwidth);
|
|
|
|
switch (bandwidth) {
|
|
case isac12kHz: {
|
|
/* Store the indices to be used for multiple encoding. */
|
|
memcpy(encData->indexLPCShape, idx, UB_LPC_ORDER *
|
|
UB_LPC_VEC_PER_FRAME * sizeof(int));
|
|
WebRtcIsac_EncHistMulti(streamdata, idx, WebRtcIsac_kLpcShapeCdfMatUb12,
|
|
UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME);
|
|
for (interpolCntr = 0; interpolCntr < UB_INTERPOL_SEGMENTS;
|
|
interpolCntr++) {
|
|
WebRtcIsac_Lar2PolyInterpolUB(lpcVecs, interpolLPCCoeff,
|
|
kLpcVecPerSegmentUb12 + 1);
|
|
lpcVecs += UB_LPC_ORDER;
|
|
interpolLPCCoeff += (kLpcVecPerSegmentUb12 * (UB_LPC_ORDER + 1));
|
|
}
|
|
break;
|
|
}
|
|
case isac16kHz: {
|
|
/* Store the indices to be used for multiple encoding. */
|
|
memcpy(encData->indexLPCShape, idx, UB_LPC_ORDER *
|
|
UB16_LPC_VEC_PER_FRAME * sizeof(int));
|
|
WebRtcIsac_EncHistMulti(streamdata, idx, WebRtcIsac_kLpcShapeCdfMatUb16,
|
|
UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME);
|
|
for (interpolCntr = 0; interpolCntr < UB16_INTERPOL_SEGMENTS;
|
|
interpolCntr++) {
|
|
WebRtcIsac_Lar2PolyInterpolUB(lpcVecs, interpolLPCCoeff,
|
|
kLpcVecPerSegmentUb16 + 1);
|
|
lpcVecs += UB_LPC_ORDER;
|
|
interpolLPCCoeff += (kLpcVecPerSegmentUb16 * (UB_LPC_ORDER + 1));
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void WebRtcIsac_EncodeLpcGainLb(double* LPCCoef_lo, double* LPCCoef_hi,
|
|
Bitstr* streamdata,
|
|
IsacSaveEncoderData* encData) {
|
|
int j, k, n, pos, pos2, posg, offsg, offs2;
|
|
int index_g[KLT_ORDER_GAIN];
|
|
int index_ovr_g[KLT_ORDER_GAIN];
|
|
double tmpcoeffs_g[KLT_ORDER_GAIN];
|
|
double tmpcoeffs2_g[KLT_ORDER_GAIN];
|
|
double sum;
|
|
/* log gains, mean removal and scaling */
|
|
posg = 0;
|
|
for (k = 0; k < SUBFRAMES; k++) {
|
|
tmpcoeffs_g[posg] = log(LPCCoef_lo[(LPC_LOBAND_ORDER + 1) * k]);
|
|
tmpcoeffs_g[posg] -= WebRtcIsac_kLpcMeansGain[posg];
|
|
tmpcoeffs_g[posg] *= LPC_GAIN_SCALE;
|
|
posg++;
|
|
tmpcoeffs_g[posg] = log(LPCCoef_hi[(LPC_HIBAND_ORDER + 1) * k]);
|
|
tmpcoeffs_g[posg] -= WebRtcIsac_kLpcMeansGain[posg];
|
|
tmpcoeffs_g[posg] *= LPC_GAIN_SCALE;
|
|
posg++;
|
|
}
|
|
|
|
/* KLT */
|
|
|
|
/* Left transform. */
|
|
offsg = 0;
|
|
for (j = 0; j < SUBFRAMES; j++) {
|
|
posg = offsg;
|
|
for (k = 0; k < LPC_GAIN_ORDER; k++) {
|
|
sum = 0;
|
|
pos = offsg;
|
|
pos2 = k;
|
|
for (n = 0; n < LPC_GAIN_ORDER; n++) {
|
|
sum += tmpcoeffs_g[pos++] * WebRtcIsac_kKltT1Gain[pos2];
|
|
pos2 += LPC_GAIN_ORDER;
|
|
}
|
|
tmpcoeffs2_g[posg++] = sum;
|
|
}
|
|
offsg += LPC_GAIN_ORDER;
|
|
}
|
|
|
|
/* Right transform. */
|
|
offsg = 0;
|
|
offs2 = 0;
|
|
for (j = 0; j < SUBFRAMES; j++) {
|
|
posg = offsg;
|
|
for (k = 0; k < LPC_GAIN_ORDER; k++) {
|
|
sum = 0;
|
|
pos = k;
|
|
pos2 = offs2;
|
|
for (n = 0; n < SUBFRAMES; n++) {
|
|
sum += tmpcoeffs2_g[pos] * WebRtcIsac_kKltT2Gain[pos2++];
|
|
pos += LPC_GAIN_ORDER;
|
|
}
|
|
tmpcoeffs_g[posg++] = sum;
|
|
}
|
|
offs2 += SUBFRAMES;
|
|
offsg += LPC_GAIN_ORDER;
|
|
}
|
|
|
|
/* Quantize coefficients. */
|
|
for (k = 0; k < KLT_ORDER_GAIN; k++) {
|
|
/* Get index. */
|
|
pos2 = WebRtcIsac_lrint(tmpcoeffs_g[k] / KLT_STEPSIZE);
|
|
index_g[k] = (pos2) + WebRtcIsac_kQKltQuantMinGain[k];
|
|
if (index_g[k] < 0) {
|
|
index_g[k] = 0;
|
|
} else if (index_g[k] > WebRtcIsac_kQKltMaxIndGain[k]) {
|
|
index_g[k] = WebRtcIsac_kQKltMaxIndGain[k];
|
|
}
|
|
index_ovr_g[k] = WebRtcIsac_kQKltOffsetGain[k] + index_g[k];
|
|
|
|
/* Find quantization levels for coefficients. */
|
|
tmpcoeffs_g[k] = WebRtcIsac_kQKltLevelsGain[index_ovr_g[k]];
|
|
|
|
/* Save data for creation of multiple bit streams. */
|
|
encData->LPCindex_g[KLT_ORDER_GAIN * encData->startIdx + k] = index_g[k];
|
|
}
|
|
|
|
/* Entropy coding of quantization indices - gain. */
|
|
WebRtcIsac_EncHistMulti(streamdata, index_g, WebRtcIsac_kQKltCdfPtrGain,
|
|
KLT_ORDER_GAIN);
|
|
|
|
/* Find quantization levels for coefficients. */
|
|
/* Left transform. */
|
|
offsg = 0;
|
|
posg = 0;
|
|
for (j = 0; j < SUBFRAMES; j++) {
|
|
offs2 = 0;
|
|
for (k = 0; k < LPC_GAIN_ORDER; k++) {
|
|
sum = 0;
|
|
pos = offsg;
|
|
pos2 = offs2;
|
|
for (n = 0; n < LPC_GAIN_ORDER; n++)
|
|
sum += tmpcoeffs_g[pos++] * WebRtcIsac_kKltT1Gain[pos2++];
|
|
tmpcoeffs2_g[posg++] = sum;
|
|
offs2 += LPC_GAIN_ORDER;
|
|
}
|
|
offsg += LPC_GAIN_ORDER;
|
|
}
|
|
|
|
/* Right transform, transpose matrix. */
|
|
offsg = 0;
|
|
posg = 0;
|
|
for (j = 0; j < SUBFRAMES; j++) {
|
|
posg = offsg;
|
|
for (k = 0; k < LPC_GAIN_ORDER; k++) {
|
|
sum = 0;
|
|
pos = k;
|
|
pos2 = j;
|
|
for (n = 0; n < SUBFRAMES; n++) {
|
|
sum += tmpcoeffs2_g[pos] * WebRtcIsac_kKltT2Gain[pos2];
|
|
pos += LPC_GAIN_ORDER;
|
|
pos2 += SUBFRAMES;
|
|
}
|
|
tmpcoeffs_g[posg++] = sum;
|
|
}
|
|
offsg += LPC_GAIN_ORDER;
|
|
}
|
|
|
|
|
|
/* Scaling, mean addition, and gain restoration. */
|
|
posg = 0;
|
|
for (k = 0; k < SUBFRAMES; k++) {
|
|
sum = tmpcoeffs_g[posg] / LPC_GAIN_SCALE;
|
|
sum += WebRtcIsac_kLpcMeansGain[posg];
|
|
LPCCoef_lo[k * (LPC_LOBAND_ORDER + 1)] = exp(sum);
|
|
pos++;
|
|
posg++;
|
|
sum = tmpcoeffs_g[posg] / LPC_GAIN_SCALE;
|
|
sum += WebRtcIsac_kLpcMeansGain[posg];
|
|
LPCCoef_hi[k * (LPC_HIBAND_ORDER + 1)] = exp(sum);
|
|
pos++;
|
|
posg++;
|
|
}
|
|
|
|
}
|
|
|
|
void WebRtcIsac_EncodeLpcGainUb(double* lpGains, Bitstr* streamdata,
|
|
int* lpcGainIndex) {
|
|
double U[UB_LPC_GAIN_DIM];
|
|
int idx[UB_LPC_GAIN_DIM];
|
|
WebRtcIsac_ToLogDomainRemoveMean(lpGains);
|
|
WebRtcIsac_DecorrelateLPGain(lpGains, U);
|
|
WebRtcIsac_QuantizeLpcGain(U, idx);
|
|
/* Store the index for re-encoding for FEC. */
|
|
memcpy(lpcGainIndex, idx, UB_LPC_GAIN_DIM * sizeof(int));
|
|
WebRtcIsac_CorrelateLpcGain(U, lpGains);
|
|
WebRtcIsac_AddMeanToLinearDomain(lpGains);
|
|
WebRtcIsac_EncHistMulti(streamdata, idx, WebRtcIsac_kLpcGainCdfMat,
|
|
UB_LPC_GAIN_DIM);
|
|
}
|
|
|
|
|
|
void WebRtcIsac_StoreLpcGainUb(double* lpGains, Bitstr* streamdata) {
|
|
double U[UB_LPC_GAIN_DIM];
|
|
int idx[UB_LPC_GAIN_DIM];
|
|
WebRtcIsac_ToLogDomainRemoveMean(lpGains);
|
|
WebRtcIsac_DecorrelateLPGain(lpGains, U);
|
|
WebRtcIsac_QuantizeLpcGain(U, idx);
|
|
WebRtcIsac_EncHistMulti(streamdata, idx, WebRtcIsac_kLpcGainCdfMat,
|
|
UB_LPC_GAIN_DIM);
|
|
}
|
|
|
|
|
|
|
|
int16_t WebRtcIsac_DecodeLpcGainUb(double* lpGains, Bitstr* streamdata) {
|
|
double U[UB_LPC_GAIN_DIM];
|
|
int idx[UB_LPC_GAIN_DIM];
|
|
int err;
|
|
err = WebRtcIsac_DecHistOneStepMulti(idx, streamdata,
|
|
WebRtcIsac_kLpcGainCdfMat,
|
|
WebRtcIsac_kLpcGainEntropySearch,
|
|
UB_LPC_GAIN_DIM);
|
|
if (err < 0) {
|
|
return -1;
|
|
}
|
|
WebRtcIsac_DequantizeLpcGain(idx, U);
|
|
WebRtcIsac_CorrelateLpcGain(U, lpGains);
|
|
WebRtcIsac_AddMeanToLinearDomain(lpGains);
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/* decode & dequantize RC */
|
|
int WebRtcIsac_DecodeRc(Bitstr* streamdata, int16_t* RCQ15) {
|
|
int k, err;
|
|
int index[AR_ORDER];
|
|
|
|
/* entropy decoding of quantization indices */
|
|
err = WebRtcIsac_DecHistOneStepMulti(index, streamdata,
|
|
WebRtcIsac_kQArRcCdfPtr,
|
|
WebRtcIsac_kQArRcInitIndex, AR_ORDER);
|
|
if (err < 0)
|
|
return err;
|
|
|
|
/* find quantization levels for reflection coefficients */
|
|
for (k = 0; k < AR_ORDER; k++) {
|
|
RCQ15[k] = *(WebRtcIsac_kQArRcLevelsPtr[k] + index[k]);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* quantize & code RC */
|
|
void WebRtcIsac_EncodeRc(int16_t* RCQ15, Bitstr* streamdata) {
|
|
int k;
|
|
int index[AR_ORDER];
|
|
|
|
/* quantize reflection coefficients (add noise feedback?) */
|
|
for (k = 0; k < AR_ORDER; k++) {
|
|
index[k] = WebRtcIsac_kQArRcInitIndex[k];
|
|
// The safe-guards in following while conditions are to suppress gcc 4.8.3
|
|
// warnings, Issue 2888. Otherwise, first and last elements of
|
|
// |WebRtcIsac_kQArBoundaryLevels| are such that the following search
|
|
// *never* cause an out-of-boundary read.
|
|
if (RCQ15[k] > WebRtcIsac_kQArBoundaryLevels[index[k]]) {
|
|
while (index[k] + 1 < NUM_AR_RC_QUANT_BAUNDARY &&
|
|
RCQ15[k] > WebRtcIsac_kQArBoundaryLevels[index[k] + 1]) {
|
|
index[k]++;
|
|
}
|
|
} else {
|
|
while (index[k] > 0 &&
|
|
RCQ15[k] < WebRtcIsac_kQArBoundaryLevels[--index[k]]) ;
|
|
}
|
|
RCQ15[k] = *(WebRtcIsac_kQArRcLevelsPtr[k] + index[k]);
|
|
}
|
|
|
|
/* entropy coding of quantization indices */
|
|
WebRtcIsac_EncHistMulti(streamdata, index, WebRtcIsac_kQArRcCdfPtr, AR_ORDER);
|
|
}
|
|
|
|
|
|
/* decode & dequantize squared Gain */
|
|
int WebRtcIsac_DecodeGain2(Bitstr* streamdata, int32_t* gainQ10) {
|
|
int index, err;
|
|
|
|
/* entropy decoding of quantization index */
|
|
err = WebRtcIsac_DecHistOneStepMulti(&index, streamdata,
|
|
WebRtcIsac_kQGainCdf_ptr,
|
|
WebRtcIsac_kQGainInitIndex, 1);
|
|
if (err < 0) {
|
|
return err;
|
|
}
|
|
/* find quantization level */
|
|
*gainQ10 = WebRtcIsac_kQGain2Levels[index];
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* quantize & code squared Gain */
|
|
int WebRtcIsac_EncodeGain2(int32_t* gainQ10, Bitstr* streamdata) {
|
|
int index;
|
|
|
|
/* find quantization index */
|
|
index = WebRtcIsac_kQGainInitIndex[0];
|
|
if (*gainQ10 > WebRtcIsac_kQGain2BoundaryLevels[index]) {
|
|
while (*gainQ10 > WebRtcIsac_kQGain2BoundaryLevels[index + 1]) {
|
|
index++;
|
|
}
|
|
} else {
|
|
while (*gainQ10 < WebRtcIsac_kQGain2BoundaryLevels[--index]) ;
|
|
}
|
|
/* De-quantize */
|
|
*gainQ10 = WebRtcIsac_kQGain2Levels[index];
|
|
|
|
/* entropy coding of quantization index */
|
|
WebRtcIsac_EncHistMulti(streamdata, &index, WebRtcIsac_kQGainCdf_ptr, 1);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* code and decode Pitch Gains and Lags functions */
|
|
|
|
/* decode & dequantize Pitch Gains */
|
|
int WebRtcIsac_DecodePitchGain(Bitstr* streamdata,
|
|
int16_t* PitchGains_Q12) {
|
|
int index_comb, err;
|
|
const uint16_t* WebRtcIsac_kQPitchGainCdf_ptr[1];
|
|
|
|
/* Entropy decoding of quantization indices */
|
|
*WebRtcIsac_kQPitchGainCdf_ptr = WebRtcIsac_kQPitchGainCdf;
|
|
err = WebRtcIsac_DecHistBisectMulti(&index_comb, streamdata,
|
|
WebRtcIsac_kQPitchGainCdf_ptr,
|
|
WebRtcIsac_kQCdfTableSizeGain, 1);
|
|
/* Error check, Q_mean_Gain.. tables are of size 144 */
|
|
if ((err < 0) || (index_comb < 0) || (index_comb >= 144)) {
|
|
return -ISAC_RANGE_ERROR_DECODE_PITCH_GAIN;
|
|
}
|
|
/* De-quantize back to pitch gains by table look-up. */
|
|
PitchGains_Q12[0] = WebRtcIsac_kQMeanGain1Q12[index_comb];
|
|
PitchGains_Q12[1] = WebRtcIsac_kQMeanGain2Q12[index_comb];
|
|
PitchGains_Q12[2] = WebRtcIsac_kQMeanGain3Q12[index_comb];
|
|
PitchGains_Q12[3] = WebRtcIsac_kQMeanGain4Q12[index_comb];
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* Quantize & code Pitch Gains. */
|
|
void WebRtcIsac_EncodePitchGain(int16_t* PitchGains_Q12,
|
|
Bitstr* streamdata,
|
|
IsacSaveEncoderData* encData) {
|
|
int k, j;
|
|
double C;
|
|
double S[PITCH_SUBFRAMES];
|
|
int index[3];
|
|
int index_comb;
|
|
const uint16_t* WebRtcIsac_kQPitchGainCdf_ptr[1];
|
|
double PitchGains[PITCH_SUBFRAMES] = {0, 0, 0, 0};
|
|
|
|
/* Take the asin. */
|
|
for (k = 0; k < PITCH_SUBFRAMES; k++) {
|
|
PitchGains[k] = ((float)PitchGains_Q12[k]) / 4096;
|
|
S[k] = asin(PitchGains[k]);
|
|
}
|
|
|
|
/* Find quantization index; only for the first three
|
|
* transform coefficients. */
|
|
for (k = 0; k < 3; k++) {
|
|
/* transform */
|
|
C = 0.0;
|
|
for (j = 0; j < PITCH_SUBFRAMES; j++) {
|
|
C += WebRtcIsac_kTransform[k][j] * S[j];
|
|
}
|
|
/* Quantize */
|
|
index[k] = WebRtcIsac_lrint(C / PITCH_GAIN_STEPSIZE);
|
|
|
|
/* Check that the index is not outside the boundaries of the table. */
|
|
if (index[k] < WebRtcIsac_kIndexLowerLimitGain[k]) {
|
|
index[k] = WebRtcIsac_kIndexLowerLimitGain[k];
|
|
} else if (index[k] > WebRtcIsac_kIndexUpperLimitGain[k]) {
|
|
index[k] = WebRtcIsac_kIndexUpperLimitGain[k];
|
|
}
|
|
index[k] -= WebRtcIsac_kIndexLowerLimitGain[k];
|
|
}
|
|
|
|
/* Calculate unique overall index. */
|
|
index_comb = WebRtcIsac_kIndexMultsGain[0] * index[0] +
|
|
WebRtcIsac_kIndexMultsGain[1] * index[1] + index[2];
|
|
|
|
/* unquantize back to pitch gains by table look-up */
|
|
PitchGains_Q12[0] = WebRtcIsac_kQMeanGain1Q12[index_comb];
|
|
PitchGains_Q12[1] = WebRtcIsac_kQMeanGain2Q12[index_comb];
|
|
PitchGains_Q12[2] = WebRtcIsac_kQMeanGain3Q12[index_comb];
|
|
PitchGains_Q12[3] = WebRtcIsac_kQMeanGain4Q12[index_comb];
|
|
|
|
/* entropy coding of quantization pitch gains */
|
|
*WebRtcIsac_kQPitchGainCdf_ptr = WebRtcIsac_kQPitchGainCdf;
|
|
WebRtcIsac_EncHistMulti(streamdata, &index_comb,
|
|
WebRtcIsac_kQPitchGainCdf_ptr, 1);
|
|
encData->pitchGain_index[encData->startIdx] = index_comb;
|
|
}
|
|
|
|
|
|
|
|
/* Pitch LAG */
|
|
/* Decode & de-quantize Pitch Lags. */
|
|
int WebRtcIsac_DecodePitchLag(Bitstr* streamdata, int16_t* PitchGain_Q12,
|
|
double* PitchLags) {
|
|
int k, err;
|
|
double StepSize;
|
|
double C;
|
|
int index[PITCH_SUBFRAMES];
|
|
double mean_gain;
|
|
const double* mean_val2, *mean_val3, *mean_val4;
|
|
const int16_t* lower_limit;
|
|
const uint16_t* init_index;
|
|
const uint16_t* cdf_size;
|
|
const uint16_t** cdf;
|
|
double PitchGain[4] = {0, 0, 0, 0};
|
|
|
|
/* compute mean pitch gain */
|
|
mean_gain = 0.0;
|
|
for (k = 0; k < 4; k++) {
|
|
PitchGain[k] = ((float)PitchGain_Q12[k]) / 4096;
|
|
mean_gain += PitchGain[k];
|
|
}
|
|
mean_gain /= 4.0;
|
|
|
|
/* voicing classification. */
|
|
if (mean_gain < 0.2) {
|
|
StepSize = WebRtcIsac_kQPitchLagStepsizeLo;
|
|
cdf = WebRtcIsac_kQPitchLagCdfPtrLo;
|
|
cdf_size = WebRtcIsac_kQPitchLagCdfSizeLo;
|
|
mean_val2 = WebRtcIsac_kQMeanLag2Lo;
|
|
mean_val3 = WebRtcIsac_kQMeanLag3Lo;
|
|
mean_val4 = WebRtcIsac_kQMeanLag4Lo;
|
|
lower_limit = WebRtcIsac_kQIndexLowerLimitLagLo;
|
|
init_index = WebRtcIsac_kQInitIndexLagLo;
|
|
} else if (mean_gain < 0.4) {
|
|
StepSize = WebRtcIsac_kQPitchLagStepsizeMid;
|
|
cdf = WebRtcIsac_kQPitchLagCdfPtrMid;
|
|
cdf_size = WebRtcIsac_kQPitchLagCdfSizeMid;
|
|
mean_val2 = WebRtcIsac_kQMeanLag2Mid;
|
|
mean_val3 = WebRtcIsac_kQMeanLag3Mid;
|
|
mean_val4 = WebRtcIsac_kQMeanLag4Mid;
|
|
lower_limit = WebRtcIsac_kQIndexLowerLimitLagMid;
|
|
init_index = WebRtcIsac_kQInitIndexLagMid;
|
|
} else {
|
|
StepSize = WebRtcIsac_kQPitchLagStepsizeHi;
|
|
cdf = WebRtcIsac_kQPitchLagCdfPtrHi;
|
|
cdf_size = WebRtcIsac_kQPitchLagCdfSizeHi;
|
|
mean_val2 = WebRtcIsac_kQMeanLag2Hi;
|
|
mean_val3 = WebRtcIsac_kQMeanLag3Hi;
|
|
mean_val4 = WebRtcIsac_kQMeanLag4Hi;
|
|
lower_limit = WebRtcIsac_kQindexLowerLimitLagHi;
|
|
init_index = WebRtcIsac_kQInitIndexLagHi;
|
|
}
|
|
|
|
/* Entropy decoding of quantization indices. */
|
|
err = WebRtcIsac_DecHistBisectMulti(index, streamdata, cdf, cdf_size, 1);
|
|
if ((err < 0) || (index[0] < 0)) {
|
|
return -ISAC_RANGE_ERROR_DECODE_PITCH_LAG;
|
|
}
|
|
err = WebRtcIsac_DecHistOneStepMulti(index + 1, streamdata, cdf + 1,
|
|
init_index, 3);
|
|
if (err < 0) {
|
|
return -ISAC_RANGE_ERROR_DECODE_PITCH_LAG;
|
|
}
|
|
|
|
/* Unquantize back to transform coefficients and do the inverse transform:
|
|
* S = T'*C. */
|
|
C = (index[0] + lower_limit[0]) * StepSize;
|
|
for (k = 0; k < PITCH_SUBFRAMES; k++) {
|
|
PitchLags[k] = WebRtcIsac_kTransformTranspose[k][0] * C;
|
|
}
|
|
C = mean_val2[index[1]];
|
|
for (k = 0; k < PITCH_SUBFRAMES; k++) {
|
|
PitchLags[k] += WebRtcIsac_kTransformTranspose[k][1] * C;
|
|
}
|
|
C = mean_val3[index[2]];
|
|
for (k = 0; k < PITCH_SUBFRAMES; k++) {
|
|
PitchLags[k] += WebRtcIsac_kTransformTranspose[k][2] * C;
|
|
}
|
|
C = mean_val4[index[3]];
|
|
for (k = 0; k < PITCH_SUBFRAMES; k++) {
|
|
PitchLags[k] += WebRtcIsac_kTransformTranspose[k][3] * C;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/* Quantize & code pitch lags. */
|
|
void WebRtcIsac_EncodePitchLag(double* PitchLags, int16_t* PitchGain_Q12,
|
|
Bitstr* streamdata,
|
|
IsacSaveEncoderData* encData) {
|
|
int k, j;
|
|
double StepSize;
|
|
double C;
|
|
int index[PITCH_SUBFRAMES];
|
|
double mean_gain;
|
|
const double* mean_val2, *mean_val3, *mean_val4;
|
|
const int16_t* lower_limit, *upper_limit;
|
|
const uint16_t** cdf;
|
|
double PitchGain[4] = {0, 0, 0, 0};
|
|
|
|
/* compute mean pitch gain */
|
|
mean_gain = 0.0;
|
|
for (k = 0; k < 4; k++) {
|
|
PitchGain[k] = ((float)PitchGain_Q12[k]) / 4096;
|
|
mean_gain += PitchGain[k];
|
|
}
|
|
mean_gain /= 4.0;
|
|
|
|
/* Save data for creation of multiple bit streams */
|
|
encData->meanGain[encData->startIdx] = mean_gain;
|
|
|
|
/* Voicing classification. */
|
|
if (mean_gain < 0.2) {
|
|
StepSize = WebRtcIsac_kQPitchLagStepsizeLo;
|
|
cdf = WebRtcIsac_kQPitchLagCdfPtrLo;
|
|
mean_val2 = WebRtcIsac_kQMeanLag2Lo;
|
|
mean_val3 = WebRtcIsac_kQMeanLag3Lo;
|
|
mean_val4 = WebRtcIsac_kQMeanLag4Lo;
|
|
lower_limit = WebRtcIsac_kQIndexLowerLimitLagLo;
|
|
upper_limit = WebRtcIsac_kQIndexUpperLimitLagLo;
|
|
} else if (mean_gain < 0.4) {
|
|
StepSize = WebRtcIsac_kQPitchLagStepsizeMid;
|
|
cdf = WebRtcIsac_kQPitchLagCdfPtrMid;
|
|
mean_val2 = WebRtcIsac_kQMeanLag2Mid;
|
|
mean_val3 = WebRtcIsac_kQMeanLag3Mid;
|
|
mean_val4 = WebRtcIsac_kQMeanLag4Mid;
|
|
lower_limit = WebRtcIsac_kQIndexLowerLimitLagMid;
|
|
upper_limit = WebRtcIsac_kQIndexUpperLimitLagMid;
|
|
} else {
|
|
StepSize = WebRtcIsac_kQPitchLagStepsizeHi;
|
|
cdf = WebRtcIsac_kQPitchLagCdfPtrHi;
|
|
mean_val2 = WebRtcIsac_kQMeanLag2Hi;
|
|
mean_val3 = WebRtcIsac_kQMeanLag3Hi;
|
|
mean_val4 = WebRtcIsac_kQMeanLag4Hi;
|
|
lower_limit = WebRtcIsac_kQindexLowerLimitLagHi;
|
|
upper_limit = WebRtcIsac_kQindexUpperLimitLagHi;
|
|
}
|
|
|
|
/* find quantization index */
|
|
for (k = 0; k < 4; k++) {
|
|
/* transform */
|
|
C = 0.0;
|
|
for (j = 0; j < PITCH_SUBFRAMES; j++) {
|
|
C += WebRtcIsac_kTransform[k][j] * PitchLags[j];
|
|
}
|
|
/* quantize */
|
|
index[k] = WebRtcIsac_lrint(C / StepSize);
|
|
|
|
/* check that the index is not outside the boundaries of the table */
|
|
if (index[k] < lower_limit[k]) {
|
|
index[k] = lower_limit[k];
|
|
} else if (index[k] > upper_limit[k]) index[k] = upper_limit[k]; {
|
|
index[k] -= lower_limit[k];
|
|
}
|
|
/* Save data for creation of multiple bit streams */
|
|
encData->pitchIndex[PITCH_SUBFRAMES * encData->startIdx + k] = index[k];
|
|
}
|
|
|
|
/* Un-quantize back to transform coefficients and do the inverse transform:
|
|
* S = T'*C */
|
|
C = (index[0] + lower_limit[0]) * StepSize;
|
|
for (k = 0; k < PITCH_SUBFRAMES; k++) {
|
|
PitchLags[k] = WebRtcIsac_kTransformTranspose[k][0] * C;
|
|
}
|
|
C = mean_val2[index[1]];
|
|
for (k = 0; k < PITCH_SUBFRAMES; k++) {
|
|
PitchLags[k] += WebRtcIsac_kTransformTranspose[k][1] * C;
|
|
}
|
|
C = mean_val3[index[2]];
|
|
for (k = 0; k < PITCH_SUBFRAMES; k++) {
|
|
PitchLags[k] += WebRtcIsac_kTransformTranspose[k][2] * C;
|
|
}
|
|
C = mean_val4[index[3]];
|
|
for (k = 0; k < PITCH_SUBFRAMES; k++) {
|
|
PitchLags[k] += WebRtcIsac_kTransformTranspose[k][3] * C;
|
|
}
|
|
/* entropy coding of quantization pitch lags */
|
|
WebRtcIsac_EncHistMulti(streamdata, index, cdf, PITCH_SUBFRAMES);
|
|
}
|
|
|
|
|
|
|
|
/* Routines for in-band signaling of bandwidth estimation */
|
|
/* Histograms based on uniform distribution of indices */
|
|
/* Move global variables later! */
|
|
|
|
|
|
/* cdf array for frame length indicator */
|
|
const uint16_t WebRtcIsac_kFrameLengthCdf[4] = {
|
|
0, 21845, 43690, 65535 };
|
|
|
|
/* pointer to cdf array for frame length indicator */
|
|
const uint16_t* WebRtcIsac_kFrameLengthCdf_ptr[1] = {
|
|
WebRtcIsac_kFrameLengthCdf };
|
|
|
|
/* initial cdf index for decoder of frame length indicator */
|
|
const uint16_t WebRtcIsac_kFrameLengthInitIndex[1] = { 1 };
|
|
|
|
|
|
int WebRtcIsac_DecodeFrameLen(Bitstr* streamdata, int16_t* framesamples) {
|
|
int frame_mode, err;
|
|
err = 0;
|
|
/* entropy decoding of frame length [1:30ms,2:60ms] */
|
|
err = WebRtcIsac_DecHistOneStepMulti(&frame_mode, streamdata,
|
|
WebRtcIsac_kFrameLengthCdf_ptr,
|
|
WebRtcIsac_kFrameLengthInitIndex, 1);
|
|
if (err < 0)
|
|
return -ISAC_RANGE_ERROR_DECODE_FRAME_LENGTH;
|
|
|
|
switch (frame_mode) {
|
|
case 1:
|
|
*framesamples = 480; /* 30ms */
|
|
break;
|
|
case 2:
|
|
*framesamples = 960; /* 60ms */
|
|
break;
|
|
default:
|
|
err = -ISAC_DISALLOWED_FRAME_MODE_DECODER;
|
|
}
|
|
return err;
|
|
}
|
|
|
|
int WebRtcIsac_EncodeFrameLen(int16_t framesamples, Bitstr* streamdata) {
|
|
int frame_mode, status;
|
|
|
|
status = 0;
|
|
frame_mode = 0;
|
|
/* entropy coding of frame length [1:480 samples,2:960 samples] */
|
|
switch (framesamples) {
|
|
case 480:
|
|
frame_mode = 1;
|
|
break;
|
|
case 960:
|
|
frame_mode = 2;
|
|
break;
|
|
default:
|
|
status = - ISAC_DISALLOWED_FRAME_MODE_ENCODER;
|
|
}
|
|
|
|
if (status < 0)
|
|
return status;
|
|
|
|
WebRtcIsac_EncHistMulti(streamdata, &frame_mode,
|
|
WebRtcIsac_kFrameLengthCdf_ptr, 1);
|
|
return status;
|
|
}
|
|
|
|
/* cdf array for estimated bandwidth */
|
|
static const uint16_t kBwCdf[25] = {
|
|
0, 2731, 5461, 8192, 10923, 13653, 16384, 19114, 21845, 24576, 27306, 30037,
|
|
32768, 35498, 38229, 40959, 43690, 46421, 49151, 51882, 54613, 57343, 60074,
|
|
62804, 65535 };
|
|
|
|
/* pointer to cdf array for estimated bandwidth */
|
|
static const uint16_t* const kBwCdfPtr[1] = { kBwCdf };
|
|
|
|
/* initial cdf index for decoder of estimated bandwidth*/
|
|
static const uint16_t kBwInitIndex[1] = { 7 };
|
|
|
|
|
|
int WebRtcIsac_DecodeSendBW(Bitstr* streamdata, int16_t* BWno) {
|
|
int BWno32, err;
|
|
|
|
/* entropy decoding of sender's BW estimation [0..23] */
|
|
err = WebRtcIsac_DecHistOneStepMulti(&BWno32, streamdata, kBwCdfPtr,
|
|
kBwInitIndex, 1);
|
|
if (err < 0) {
|
|
return -ISAC_RANGE_ERROR_DECODE_BANDWIDTH;
|
|
}
|
|
*BWno = (int16_t)BWno32;
|
|
return err;
|
|
}
|
|
|
|
void WebRtcIsac_EncodeReceiveBw(int* BWno, Bitstr* streamdata) {
|
|
/* entropy encoding of receiver's BW estimation [0..23] */
|
|
WebRtcIsac_EncHistMulti(streamdata, BWno, kBwCdfPtr, 1);
|
|
}
|
|
|
|
|
|
/* estimate code length of LPC Coef */
|
|
void WebRtcIsac_TranscodeLPCCoef(double* LPCCoef_lo, double* LPCCoef_hi,
|
|
int* index_g) {
|
|
int j, k, n, pos, pos2, posg, offsg, offs2;
|
|
int index_ovr_g[KLT_ORDER_GAIN];
|
|
double tmpcoeffs_g[KLT_ORDER_GAIN];
|
|
double tmpcoeffs2_g[KLT_ORDER_GAIN];
|
|
double sum;
|
|
|
|
/* log gains, mean removal and scaling */
|
|
posg = 0;
|
|
for (k = 0; k < SUBFRAMES; k++) {
|
|
tmpcoeffs_g[posg] = log(LPCCoef_lo[(LPC_LOBAND_ORDER + 1) * k]);
|
|
tmpcoeffs_g[posg] -= WebRtcIsac_kLpcMeansGain[posg];
|
|
tmpcoeffs_g[posg] *= LPC_GAIN_SCALE;
|
|
posg++;
|
|
tmpcoeffs_g[posg] = log(LPCCoef_hi[(LPC_HIBAND_ORDER + 1) * k]);
|
|
tmpcoeffs_g[posg] -= WebRtcIsac_kLpcMeansGain[posg];
|
|
tmpcoeffs_g[posg] *= LPC_GAIN_SCALE;
|
|
posg++;
|
|
}
|
|
|
|
/* KLT */
|
|
|
|
/* Left transform. */
|
|
offsg = 0;
|
|
for (j = 0; j < SUBFRAMES; j++) {
|
|
posg = offsg;
|
|
for (k = 0; k < LPC_GAIN_ORDER; k++) {
|
|
sum = 0;
|
|
pos = offsg;
|
|
pos2 = k;
|
|
for (n = 0; n < LPC_GAIN_ORDER; n++) {
|
|
sum += tmpcoeffs_g[pos++] * WebRtcIsac_kKltT1Gain[pos2];
|
|
pos2 += LPC_GAIN_ORDER;
|
|
}
|
|
tmpcoeffs2_g[posg++] = sum;
|
|
}
|
|
offsg += LPC_GAIN_ORDER;
|
|
}
|
|
|
|
/* Right transform. */
|
|
offsg = 0;
|
|
offs2 = 0;
|
|
for (j = 0; j < SUBFRAMES; j++) {
|
|
posg = offsg;
|
|
for (k = 0; k < LPC_GAIN_ORDER; k++) {
|
|
sum = 0;
|
|
pos = k;
|
|
pos2 = offs2;
|
|
for (n = 0; n < SUBFRAMES; n++) {
|
|
sum += tmpcoeffs2_g[pos] * WebRtcIsac_kKltT2Gain[pos2++];
|
|
pos += LPC_GAIN_ORDER;
|
|
}
|
|
tmpcoeffs_g[posg++] = sum;
|
|
}
|
|
offs2 += SUBFRAMES;
|
|
offsg += LPC_GAIN_ORDER;
|
|
}
|
|
|
|
|
|
/* quantize coefficients */
|
|
for (k = 0; k < KLT_ORDER_GAIN; k++) {
|
|
/* Get index. */
|
|
pos2 = WebRtcIsac_lrint(tmpcoeffs_g[k] / KLT_STEPSIZE);
|
|
index_g[k] = (pos2) + WebRtcIsac_kQKltQuantMinGain[k];
|
|
if (index_g[k] < 0) {
|
|
index_g[k] = 0;
|
|
} else if (index_g[k] > WebRtcIsac_kQKltMaxIndGain[k]) {
|
|
index_g[k] = WebRtcIsac_kQKltMaxIndGain[k];
|
|
}
|
|
index_ovr_g[k] = WebRtcIsac_kQKltOffsetGain[k] + index_g[k];
|
|
|
|
/* find quantization levels for coefficients */
|
|
tmpcoeffs_g[k] = WebRtcIsac_kQKltLevelsGain[index_ovr_g[k]];
|
|
}
|
|
}
|
|
|
|
|
|
/* Decode & de-quantize LPC Coefficients. */
|
|
int WebRtcIsac_DecodeLpcCoefUB(Bitstr* streamdata, double* lpcVecs,
|
|
double* percepFilterGains,
|
|
int16_t bandwidth) {
|
|
int index_s[KLT_ORDER_SHAPE];
|
|
|
|
double U[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
|
|
int err;
|
|
|
|
/* Entropy decoding of quantization indices. */
|
|
switch (bandwidth) {
|
|
case isac12kHz: {
|
|
err = WebRtcIsac_DecHistOneStepMulti(
|
|
index_s, streamdata, WebRtcIsac_kLpcShapeCdfMatUb12,
|
|
WebRtcIsac_kLpcShapeEntropySearchUb12, UB_LPC_ORDER *
|
|
UB_LPC_VEC_PER_FRAME);
|
|
break;
|
|
}
|
|
case isac16kHz: {
|
|
err = WebRtcIsac_DecHistOneStepMulti(
|
|
index_s, streamdata, WebRtcIsac_kLpcShapeCdfMatUb16,
|
|
WebRtcIsac_kLpcShapeEntropySearchUb16, UB_LPC_ORDER *
|
|
UB16_LPC_VEC_PER_FRAME);
|
|
break;
|
|
}
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
if (err < 0) {
|
|
return err;
|
|
}
|
|
|
|
WebRtcIsac_DequantizeLpcParam(index_s, lpcVecs, bandwidth);
|
|
WebRtcIsac_CorrelateInterVec(lpcVecs, U, bandwidth);
|
|
WebRtcIsac_CorrelateIntraVec(U, lpcVecs, bandwidth);
|
|
WebRtcIsac_AddLarMean(lpcVecs, bandwidth);
|
|
WebRtcIsac_DecodeLpcGainUb(percepFilterGains, streamdata);
|
|
|
|
if (bandwidth == isac16kHz) {
|
|
/* Decode another set of Gains. */
|
|
WebRtcIsac_DecodeLpcGainUb(&percepFilterGains[SUBFRAMES], streamdata);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int16_t WebRtcIsac_EncodeBandwidth(enum ISACBandwidth bandwidth,
|
|
Bitstr* streamData) {
|
|
int bandwidthMode;
|
|
switch (bandwidth) {
|
|
case isac12kHz: {
|
|
bandwidthMode = 0;
|
|
break;
|
|
}
|
|
case isac16kHz: {
|
|
bandwidthMode = 1;
|
|
break;
|
|
}
|
|
default:
|
|
return -ISAC_DISALLOWED_ENCODER_BANDWIDTH;
|
|
}
|
|
WebRtcIsac_EncHistMulti(streamData, &bandwidthMode, kOneBitEqualProbCdf_ptr,
|
|
1);
|
|
return 0;
|
|
}
|
|
|
|
int16_t WebRtcIsac_DecodeBandwidth(Bitstr* streamData,
|
|
enum ISACBandwidth* bandwidth) {
|
|
int bandwidthMode;
|
|
if (WebRtcIsac_DecHistOneStepMulti(&bandwidthMode, streamData,
|
|
kOneBitEqualProbCdf_ptr,
|
|
kOneBitEqualProbInitIndex, 1) < 0) {
|
|
return -ISAC_RANGE_ERROR_DECODE_BANDWITH;
|
|
}
|
|
switch (bandwidthMode) {
|
|
case 0: {
|
|
*bandwidth = isac12kHz;
|
|
break;
|
|
}
|
|
case 1: {
|
|
*bandwidth = isac16kHz;
|
|
break;
|
|
}
|
|
default:
|
|
return -ISAC_DISALLOWED_BANDWIDTH_MODE_DECODER;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int16_t WebRtcIsac_EncodeJitterInfo(int32_t jitterIndex,
|
|
Bitstr* streamData) {
|
|
/* This is to avoid LINUX warning until we change 'int' to 'Word32'. */
|
|
int intVar;
|
|
|
|
if ((jitterIndex < 0) || (jitterIndex > 1)) {
|
|
return -1;
|
|
}
|
|
intVar = (int)(jitterIndex);
|
|
/* Use the same CDF table as for bandwidth
|
|
* both take two values with equal probability.*/
|
|
WebRtcIsac_EncHistMulti(streamData, &intVar, kOneBitEqualProbCdf_ptr, 1);
|
|
return 0;
|
|
}
|
|
|
|
int16_t WebRtcIsac_DecodeJitterInfo(Bitstr* streamData,
|
|
int32_t* jitterInfo) {
|
|
int intVar;
|
|
/* Use the same CDF table as for bandwidth
|
|
* both take two values with equal probability. */
|
|
if (WebRtcIsac_DecHistOneStepMulti(&intVar, streamData,
|
|
kOneBitEqualProbCdf_ptr,
|
|
kOneBitEqualProbInitIndex, 1) < 0) {
|
|
return -ISAC_RANGE_ERROR_DECODE_BANDWITH;
|
|
}
|
|
*jitterInfo = (int16_t)(intVar);
|
|
return 0;
|
|
}
|