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

WebRTC internal code should always used include paths that starts from the root of the project and that clearly identify the header file. This allows 'gn check' to actually keep dependencies under control because 'gn check' cannot enforce anything if the include path is not fully qualified (starting from the root of the project). Bug: webrtc:8815 Change-Id: I23fb4fed0c27a4d98bea360315b959af843587bc Reviewed-on: https://webrtc-review.googlesource.com/46101 Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org> Reviewed-by: Karl Wiberg <kwiberg@webrtc.org> Cr-Commit-Position: refs/heads/master@{#21847}
2066 lines
62 KiB
C
2066 lines
62 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 "common_audio/signal_processing/include/signal_processing_library.h"
|
|
#include "modules/audio_coding/codecs/isac/main/source/entropy_coding.h"
|
|
#include "modules/audio_coding/codecs/isac/main/source/settings.h"
|
|
#include "modules/audio_coding/codecs/isac/main/source/arith_routines.h"
|
|
#include "modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.h"
|
|
#include "modules/audio_coding/codecs/isac/main/source/lpc_tables.h"
|
|
#include "modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.h"
|
|
#include "modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.h"
|
|
#include "modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.h"
|
|
#include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h"
|
|
#include "modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h"
|
|
#include "modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h"
|
|
#include "modules/audio_coding/codecs/isac/main/source/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;
|
|
}
|