1458 lines
51 KiB
C
1458 lines
51 KiB
C
/*
|
|
* Copyright (c) 2011 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.
|
|
*/
|
|
|
|
/*
|
|
* encode.c
|
|
*
|
|
* This file contains definition of funtions for encoding.
|
|
* Decoding of upper-band, including 8-12 kHz, when the bandwidth is
|
|
* 0-12 kHz, and 8-16 kHz, when the bandwidth is 0-16 kHz.
|
|
*
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "structs.h"
|
|
#include "codec.h"
|
|
#include "pitch_estimator.h"
|
|
#include "entropy_coding.h"
|
|
#include "arith_routines.h"
|
|
#include "pitch_gain_tables.h"
|
|
#include "pitch_lag_tables.h"
|
|
#include "spectrum_ar_model_tables.h"
|
|
#include "lpc_tables.h"
|
|
#include "lpc_analysis.h"
|
|
#include "bandwidth_estimator.h"
|
|
#include "lpc_shape_swb12_tables.h"
|
|
#include "lpc_shape_swb16_tables.h"
|
|
#include "lpc_gain_swb_tables.h"
|
|
|
|
|
|
#define UB_LOOKAHEAD 24
|
|
|
|
/*
|
|
Rate allocation tables of lower and upper-band bottleneck for
|
|
12kHz & 16kHz bandwidth.
|
|
|
|
12 kHz bandwidth
|
|
-----------------
|
|
The overall bottleneck of the coder is between 38 kbps and 45 kbps. We have
|
|
considered 7 enteries, uniformly distributed in this interval, i.e. 38,
|
|
39.17, 40.33, 41.5, 42.67, 43.83 and 45. For every entery, the lower-band
|
|
and the upper-band bottlenecks are specified in
|
|
'WebRtcIsac_kLowerBandBitRate12' and 'WebRtcIsac_kUpperBandBitRate12'
|
|
tables, respectively. E.g. the overall rate of 41.5 kbps corresponts to a
|
|
bottleneck of 31 kbps for lower-band and 27 kbps for upper-band. Given an
|
|
overall bottleneck of the codec, we use linear interpolation to get
|
|
lower-band and upper-band bottlenecks.
|
|
|
|
16 kHz bandwidth
|
|
-----------------
|
|
The overall bottleneck of the coder is between 38 kbps and 45 kbps. We have
|
|
considered 7 enteries, uniformly distributed in this interval, i.e. 50, 51.2,
|
|
52.4, 53.6, 54.8 and 56. For every entery, the lower-band and the upper-band
|
|
bottlenecks are specified in 'WebRtcIsac_kLowerBandBitRate12' and
|
|
'WebRtcIsac_kUpperBandBitRate12' tables, respectively. E.g. the overall rate
|
|
of 53.6 kbps corresponts to a bottleneck of 32 kbps for lower-band and 30
|
|
kbps for upper-band. Given an overall bottleneck of the codec, we use linear
|
|
interpolation to get lower-band and upper-band bottlenecks.
|
|
|
|
*/
|
|
|
|
// 38 39.17 40.33 41.5 42.67 43.83 45
|
|
static const WebRtc_Word16 WebRtcIsac_kLowerBandBitRate12[7] = {
|
|
29000, 30000, 30000, 31000, 31000, 32000, 32000};
|
|
static const WebRtc_Word16 WebRtcIsac_kUpperBandBitRate12[7] = {
|
|
25000, 25000, 27000, 27000, 29000, 29000, 32000};
|
|
|
|
// 50 51.2 52.4 53.6 54.8 56
|
|
static const WebRtc_Word16 WebRtcIsac_kLowerBandBitRate16[6] = {
|
|
31000, 31000, 32000, 32000, 32000, 32000};
|
|
static const WebRtc_Word16 WebRtcIsac_kUpperBandBitRate16[6] = {
|
|
28000, 29000, 29000, 30000, 31000, 32000};
|
|
|
|
/******************************************************************************
|
|
* WebRtcIsac_RateAllocation()
|
|
* Internal function to perform a rate-allocation for upper and lower-band,
|
|
* given a total rate.
|
|
*
|
|
* Input:
|
|
* - inRateBitPerSec : a total bottleneck in bits/sec.
|
|
*
|
|
* Output:
|
|
* - rateLBBitPerSec : a bottleneck allocated to the lower-band
|
|
* in bits/sec.
|
|
* - rateUBBitPerSec : a bottleneck allocated to the upper-band
|
|
* in bits/sec.
|
|
*
|
|
* Return value : 0 if rate allocation has been successful.
|
|
* -1 if failed to allocate rates.
|
|
*/
|
|
|
|
WebRtc_Word16
|
|
WebRtcIsac_RateAllocation(
|
|
WebRtc_Word32 inRateBitPerSec,
|
|
double* rateLBBitPerSec,
|
|
double* rateUBBitPerSec,
|
|
enum ISACBandwidth* bandwidthKHz)
|
|
{
|
|
WebRtc_Word16 idx;
|
|
double idxD;
|
|
double idxErr;
|
|
if(inRateBitPerSec < 38000)
|
|
{
|
|
// If the given overall bottleneck is less than 38000 then
|
|
// then codec has to operate in wideband mode, i.e. 8 kHz
|
|
// bandwidth.
|
|
*rateLBBitPerSec = (WebRtc_Word16)((inRateBitPerSec > 32000)?
|
|
32000:inRateBitPerSec);
|
|
*rateUBBitPerSec = 0;
|
|
*bandwidthKHz = isac8kHz;
|
|
}
|
|
else if((inRateBitPerSec >= 38000) && (inRateBitPerSec < 50000))
|
|
{
|
|
// At a bottleneck between 38 and 50 kbps the codec is operating
|
|
// at 12 kHz bandwidth. Using xxxBandBitRate12[] to calculates
|
|
// upper/lower bottleneck
|
|
|
|
// find the bottlenecks by linear interpolation
|
|
// step is (45000 - 38000)/6.0 we use the inverse of it.
|
|
const double stepSizeInv = 8.5714286e-4;
|
|
idxD = (inRateBitPerSec - 38000) * stepSizeInv;
|
|
idx = (idxD >= 6)? 6:((WebRtc_Word16)idxD);
|
|
idxErr = idxD - idx;
|
|
*rateLBBitPerSec = WebRtcIsac_kLowerBandBitRate12[idx];
|
|
*rateUBBitPerSec = WebRtcIsac_kUpperBandBitRate12[idx];
|
|
|
|
if(idx < 6)
|
|
{
|
|
*rateLBBitPerSec += (WebRtc_Word16)(idxErr *
|
|
(WebRtcIsac_kLowerBandBitRate12[idx + 1] -
|
|
WebRtcIsac_kLowerBandBitRate12[idx]));
|
|
*rateUBBitPerSec += (WebRtc_Word16)(idxErr *
|
|
(WebRtcIsac_kUpperBandBitRate12[idx + 1] -
|
|
WebRtcIsac_kUpperBandBitRate12[idx]));
|
|
}
|
|
|
|
*bandwidthKHz = isac12kHz;
|
|
}
|
|
else if((inRateBitPerSec >= 50000) && (inRateBitPerSec <= 56000))
|
|
{
|
|
// A bottleneck between 50 and 56 kbps corresponds to bandwidth
|
|
// of 16 kHz. Using xxxBandBitRate16[] to calculates
|
|
// upper/lower bottleneck
|
|
|
|
// find the bottlenecks by linear interpolation
|
|
// step is (56000 - 50000)/5 we use the inverse of it
|
|
const double stepSizeInv = 8.3333333e-4;
|
|
idxD = (inRateBitPerSec - 50000) * stepSizeInv;
|
|
idx = (idxD >= 5)? 5:((WebRtc_Word16)idxD);
|
|
idxErr = idxD - idx;
|
|
*rateLBBitPerSec = WebRtcIsac_kLowerBandBitRate16[idx];
|
|
*rateUBBitPerSec = WebRtcIsac_kUpperBandBitRate16[idx];
|
|
|
|
if(idx < 5)
|
|
{
|
|
*rateLBBitPerSec += (WebRtc_Word16)(idxErr *
|
|
(WebRtcIsac_kLowerBandBitRate16[idx + 1] -
|
|
WebRtcIsac_kLowerBandBitRate16[idx]));
|
|
|
|
*rateUBBitPerSec += (WebRtc_Word16)(idxErr *
|
|
(WebRtcIsac_kUpperBandBitRate16[idx + 1] -
|
|
WebRtcIsac_kUpperBandBitRate16[idx]));
|
|
}
|
|
|
|
*bandwidthKHz = isac16kHz;
|
|
}
|
|
else
|
|
{
|
|
// Out-of-range botlteneck value.
|
|
return -1;
|
|
}
|
|
|
|
// limit the values.
|
|
*rateLBBitPerSec = (*rateLBBitPerSec > 32000)? 32000:*rateLBBitPerSec;
|
|
*rateUBBitPerSec = (*rateUBBitPerSec > 32000)? 32000:*rateUBBitPerSec;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int
|
|
WebRtcIsac_EncodeLb(
|
|
float* in,
|
|
ISACLBEncStruct* ISACencLB_obj,
|
|
WebRtc_Word16 codingMode,
|
|
WebRtc_Word16 bottleneckIndex)
|
|
{
|
|
int stream_length = 0;
|
|
int err;
|
|
int k;
|
|
int iterCntr;
|
|
|
|
double lofilt_coef[(ORDERLO+1)*SUBFRAMES];
|
|
double hifilt_coef[(ORDERHI+1)*SUBFRAMES];
|
|
float LP[FRAMESAMPLES_HALF];
|
|
float HP[FRAMESAMPLES_HALF];
|
|
|
|
double LP_lookahead[FRAMESAMPLES_HALF];
|
|
double HP_lookahead[FRAMESAMPLES_HALF];
|
|
double LP_lookahead_pf[FRAMESAMPLES_HALF + QLOOKAHEAD];
|
|
double LPw[FRAMESAMPLES_HALF];
|
|
|
|
double HPw[FRAMESAMPLES_HALF];
|
|
double LPw_pf[FRAMESAMPLES_HALF];
|
|
WebRtc_Word16 fre[FRAMESAMPLES_HALF]; /* Q7 */
|
|
WebRtc_Word16 fim[FRAMESAMPLES_HALF]; /* Q7 */
|
|
|
|
double PitchLags[4];
|
|
double PitchGains[4];
|
|
WebRtc_Word16 PitchGains_Q12[4];
|
|
WebRtc_Word16 AvgPitchGain_Q12;
|
|
|
|
int frame_mode; /* 0 for 30ms, 1 for 60ms */
|
|
int processed_samples, status = 0;
|
|
|
|
double bits_gains;
|
|
int bmodel;
|
|
|
|
transcode_obj transcodingParam;
|
|
double bytesLeftSpecCoding;
|
|
WebRtc_UWord16 payloadLimitBytes;
|
|
|
|
/* copy new frame length and bottle neck rate only for the first
|
|
10 ms data */
|
|
if (ISACencLB_obj->buffer_index == 0) {
|
|
/* set the framelength for the next packet */
|
|
ISACencLB_obj->current_framesamples = ISACencLB_obj->new_framelength;
|
|
}
|
|
/* frame_mode is 0 (30 ms) or 1 (60 ms) */
|
|
frame_mode = ISACencLB_obj->current_framesamples/MAX_FRAMESAMPLES;
|
|
/* processed_samples: 480 (30, 60 ms) */
|
|
processed_samples = ISACencLB_obj->current_framesamples/(frame_mode+1);
|
|
|
|
/* buffer speech samples (by 10ms packet) until the framelength */
|
|
/* is reached (30 or 60 ms) */
|
|
/****************************************************************/
|
|
|
|
/* fill the buffer with 10ms input data */
|
|
for (k = 0; k < FRAMESAMPLES_10ms; k++) {
|
|
ISACencLB_obj->data_buffer_float[k + ISACencLB_obj->buffer_index] =
|
|
in[k];
|
|
}
|
|
|
|
/* if buffersize is not equal to current framesize then increase index
|
|
and return. We do no encoding untill we have enough audio. */
|
|
if (ISACencLB_obj->buffer_index + FRAMESAMPLES_10ms != processed_samples) {
|
|
ISACencLB_obj->buffer_index += FRAMESAMPLES_10ms;
|
|
return 0;
|
|
}
|
|
/* if buffer reached the right size, reset index and continue with
|
|
encoding the frame */
|
|
ISACencLB_obj->buffer_index = 0;
|
|
|
|
/* end of buffer function */
|
|
/**************************/
|
|
|
|
/* encoding */
|
|
/************/
|
|
|
|
if (frame_mode == 0 || ISACencLB_obj->frame_nb == 0 ) {
|
|
// This is to avoid Linux warnings until we change 'int' to 'Word32'
|
|
// at all places.
|
|
int intVar;
|
|
/* reset bitstream */
|
|
ISACencLB_obj->bitstr_obj.W_upper = 0xFFFFFFFF;
|
|
ISACencLB_obj->bitstr_obj.streamval = 0;
|
|
ISACencLB_obj->bitstr_obj.stream_index = 0;
|
|
|
|
if((codingMode == 0) && (frame_mode == 0) &&
|
|
(ISACencLB_obj->enforceFrameSize == 0)) {
|
|
ISACencLB_obj->new_framelength =
|
|
WebRtcIsac_GetNewFrameLength(ISACencLB_obj->bottleneck,
|
|
ISACencLB_obj->current_framesamples);
|
|
}
|
|
|
|
ISACencLB_obj->s2nr = WebRtcIsac_GetSnr(
|
|
ISACencLB_obj->bottleneck, ISACencLB_obj->current_framesamples);
|
|
|
|
/* encode frame length */
|
|
status = WebRtcIsac_EncodeFrameLen(
|
|
ISACencLB_obj->current_framesamples, &ISACencLB_obj->bitstr_obj);
|
|
if (status < 0) {
|
|
/* Wrong frame size */
|
|
return status;
|
|
}
|
|
/* Save framelength for multiple packets memory */
|
|
ISACencLB_obj->SaveEnc_obj.framelength =
|
|
ISACencLB_obj->current_framesamples;
|
|
|
|
/* To be used for Redundant Coding */
|
|
ISACencLB_obj->lastBWIdx = bottleneckIndex;
|
|
intVar = (int)bottleneckIndex;
|
|
WebRtcIsac_EncodeReceiveBw(&intVar, &ISACencLB_obj->bitstr_obj);
|
|
}
|
|
|
|
/* split signal in two bands */
|
|
WebRtcIsac_SplitAndFilterFloat(ISACencLB_obj->data_buffer_float, LP, HP,
|
|
LP_lookahead, HP_lookahead, &ISACencLB_obj->prefiltbankstr_obj );
|
|
|
|
/* estimate pitch parameters and pitch-filter lookahead signal */
|
|
WebRtcIsac_PitchAnalysis(LP_lookahead, LP_lookahead_pf,
|
|
&ISACencLB_obj->pitchanalysisstr_obj, PitchLags, PitchGains);
|
|
|
|
/* encode in FIX Q12 */
|
|
|
|
/* convert PitchGain to Fixed point */
|
|
for (k=0;k<PITCH_SUBFRAMES;k++) {
|
|
PitchGains_Q12[k] = (WebRtc_Word16)(PitchGains[k] * 4096.0);
|
|
}
|
|
|
|
/* Set where to store data in multiple packets memory */
|
|
if (frame_mode == 0 || ISACencLB_obj->frame_nb == 0)
|
|
{
|
|
ISACencLB_obj->SaveEnc_obj.startIdx = 0;
|
|
} else {
|
|
ISACencLB_obj->SaveEnc_obj.startIdx = 1;
|
|
}
|
|
|
|
/* quantize & encode pitch parameters */
|
|
WebRtcIsac_EncodePitchGain(PitchGains_Q12, &ISACencLB_obj->bitstr_obj,
|
|
&ISACencLB_obj->SaveEnc_obj);
|
|
WebRtcIsac_EncodePitchLag(PitchLags, PitchGains_Q12,
|
|
&ISACencLB_obj->bitstr_obj, &ISACencLB_obj->SaveEnc_obj);
|
|
|
|
AvgPitchGain_Q12 = (PitchGains_Q12[0] + PitchGains_Q12[1] +
|
|
PitchGains_Q12[2] + PitchGains_Q12[3])>>2;
|
|
|
|
/* find coefficients for perceptual pre-filters */
|
|
WebRtcIsac_GetLpcCoefLb(LP_lookahead_pf, HP_lookahead,
|
|
&ISACencLB_obj->maskfiltstr_obj, ISACencLB_obj->s2nr,
|
|
PitchGains_Q12, lofilt_coef, hifilt_coef);
|
|
|
|
/* code LPC model and shape - gains not quantized yet */
|
|
WebRtcIsac_EncodeLpcLb(lofilt_coef, hifilt_coef, &bmodel, &bits_gains,
|
|
&ISACencLB_obj->bitstr_obj, &ISACencLB_obj->SaveEnc_obj);
|
|
|
|
/* convert PitchGains back to FLOAT for pitchfilter_pre */
|
|
for (k = 0; k < 4; k++) {
|
|
PitchGains[k] = ((float)PitchGains_Q12[k])/4096;
|
|
}
|
|
|
|
/* Store the state of arithmetic coder before coding LPC gains */
|
|
transcodingParam.W_upper = ISACencLB_obj->bitstr_obj.W_upper;
|
|
transcodingParam.stream_index = ISACencLB_obj->bitstr_obj.stream_index;
|
|
transcodingParam.streamval = ISACencLB_obj->bitstr_obj.streamval;
|
|
transcodingParam.stream[0] = ISACencLB_obj->bitstr_obj.stream[
|
|
ISACencLB_obj->bitstr_obj.stream_index - 2];
|
|
transcodingParam.stream[1] = ISACencLB_obj->bitstr_obj.stream[
|
|
ISACencLB_obj->bitstr_obj.stream_index - 1];
|
|
transcodingParam.stream[2] = ISACencLB_obj->bitstr_obj.stream[
|
|
ISACencLB_obj->bitstr_obj.stream_index];
|
|
|
|
/* Store LPC Gains before encoding them */
|
|
for(k = 0; k < SUBFRAMES; k++) {
|
|
transcodingParam.loFiltGain[k] = lofilt_coef[(LPC_LOBAND_ORDER+1)*k];
|
|
transcodingParam.hiFiltGain[k] = hifilt_coef[(LPC_HIBAND_ORDER+1)*k];
|
|
}
|
|
|
|
/* Code gains */
|
|
WebRtcIsac_EncodeLpcGainLb(lofilt_coef, hifilt_coef, bmodel,
|
|
&ISACencLB_obj->bitstr_obj, &ISACencLB_obj->SaveEnc_obj);
|
|
|
|
/* Get the correct value for the payload limit and calculate the
|
|
number of bytes left for coding the spectrum.*/
|
|
if((frame_mode == 1) && (ISACencLB_obj->frame_nb == 0)) {
|
|
/* It is a 60ms and we are in the first 30ms then the limit at
|
|
this point should be half of the assigned value */
|
|
payloadLimitBytes = ISACencLB_obj->payloadLimitBytes60 >> 1;
|
|
}
|
|
else if (frame_mode == 0) {
|
|
/* It is a 30ms frame */
|
|
/* Subract 3 because termination process may add 3 bytes */
|
|
payloadLimitBytes = ISACencLB_obj->payloadLimitBytes30 - 3;
|
|
} else {
|
|
/* This is the second half of a 60ms frame. */
|
|
/* Subract 3 because termination process may add 3 bytes */
|
|
payloadLimitBytes = ISACencLB_obj->payloadLimitBytes60 - 3;
|
|
}
|
|
bytesLeftSpecCoding = payloadLimitBytes - transcodingParam.stream_index;
|
|
|
|
/* perceptual pre-filtering (using normalized lattice filter) */
|
|
/* low-band filtering */
|
|
WebRtcIsac_NormLatticeFilterMa(ORDERLO,
|
|
ISACencLB_obj->maskfiltstr_obj.PreStateLoF,
|
|
ISACencLB_obj->maskfiltstr_obj.PreStateLoG, LP, lofilt_coef, LPw);
|
|
/* high-band filtering */
|
|
WebRtcIsac_NormLatticeFilterMa(ORDERHI,
|
|
ISACencLB_obj->maskfiltstr_obj.PreStateHiF,
|
|
ISACencLB_obj->maskfiltstr_obj.PreStateHiG, HP, hifilt_coef, HPw);
|
|
|
|
|
|
/* pitch filter */
|
|
WebRtcIsac_PitchfilterPre(LPw, LPw_pf, &ISACencLB_obj->pitchfiltstr_obj,
|
|
PitchLags, PitchGains);
|
|
|
|
/* transform */
|
|
WebRtcIsac_Time2Spec(LPw_pf, HPw, fre, fim, &ISACencLB_obj->fftstr_obj);
|
|
|
|
|
|
/* Save data for multiple packets memory */
|
|
for (k = 0; k < FRAMESAMPLES_HALF; k++) {
|
|
ISACencLB_obj->SaveEnc_obj.fre[k +
|
|
ISACencLB_obj->SaveEnc_obj.startIdx*FRAMESAMPLES_HALF] = fre[k];
|
|
ISACencLB_obj->SaveEnc_obj.fim[k +
|
|
ISACencLB_obj->SaveEnc_obj.startIdx*FRAMESAMPLES_HALF] = fim[k];
|
|
}
|
|
ISACencLB_obj->SaveEnc_obj.AvgPitchGain[
|
|
ISACencLB_obj->SaveEnc_obj.startIdx] = AvgPitchGain_Q12;
|
|
|
|
/* quantization and lossless coding */
|
|
err = WebRtcIsac_EncodeSpecLb(fre, fim, &ISACencLB_obj->bitstr_obj,
|
|
AvgPitchGain_Q12);
|
|
if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
|
|
/* There has been an error but it was not too large payload
|
|
(we can cure too large payload) */
|
|
if (frame_mode == 1 && ISACencLB_obj->frame_nb == 1) {
|
|
/* If this is the second 30ms of a 60ms frame reset
|
|
this such that in the next call encoder starts fresh. */
|
|
ISACencLB_obj->frame_nb = 0;
|
|
}
|
|
return err;
|
|
}
|
|
iterCntr = 0;
|
|
while((ISACencLB_obj->bitstr_obj.stream_index > payloadLimitBytes) ||
|
|
(err == -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
|
|
double bytesSpecCoderUsed;
|
|
double transcodeScale;
|
|
|
|
if(iterCntr >= MAX_PAYLOAD_LIMIT_ITERATION) {
|
|
/* We were not able to limit the payload size */
|
|
if((frame_mode == 1) && (ISACencLB_obj->frame_nb == 0)) {
|
|
/* This was the first 30ms of a 60ms frame. Although
|
|
the payload is larger than it should be but we let
|
|
the second 30ms be encoded. Maybe together we
|
|
won't exceed the limit. */
|
|
ISACencLB_obj->frame_nb = 1;
|
|
return 0;
|
|
} else if((frame_mode == 1) && (ISACencLB_obj->frame_nb == 1)) {
|
|
ISACencLB_obj->frame_nb = 0;
|
|
}
|
|
|
|
if(err != -ISAC_DISALLOWED_BITSTREAM_LENGTH) {
|
|
return -ISAC_PAYLOAD_LARGER_THAN_LIMIT;
|
|
} else {
|
|
return status;
|
|
}
|
|
}
|
|
|
|
if(err == -ISAC_DISALLOWED_BITSTREAM_LENGTH) {
|
|
bytesSpecCoderUsed = STREAM_SIZE_MAX;
|
|
// being coservative
|
|
transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed * 0.5;
|
|
} else {
|
|
bytesSpecCoderUsed = ISACencLB_obj->bitstr_obj.stream_index -
|
|
transcodingParam.stream_index;
|
|
transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed;
|
|
}
|
|
|
|
/* To be safe, we reduce the scale depending on
|
|
the number of iterations. */
|
|
transcodeScale *= (1.0 - (0.9 * (double)iterCntr /
|
|
(double)MAX_PAYLOAD_LIMIT_ITERATION));
|
|
|
|
/* Scale the LPC Gains */
|
|
for (k = 0; k < SUBFRAMES; k++) {
|
|
lofilt_coef[(LPC_LOBAND_ORDER+1) * k] =
|
|
transcodingParam.loFiltGain[k] * transcodeScale;
|
|
hifilt_coef[(LPC_HIBAND_ORDER+1) * k] =
|
|
transcodingParam.hiFiltGain[k] * transcodeScale;
|
|
transcodingParam.loFiltGain[k] =
|
|
lofilt_coef[(LPC_LOBAND_ORDER+1) * k];
|
|
transcodingParam.hiFiltGain[k] =
|
|
hifilt_coef[(LPC_HIBAND_ORDER+1) * k];
|
|
}
|
|
|
|
/* Scale DFT coefficients */
|
|
for (k = 0; k < FRAMESAMPLES_HALF; k++) {
|
|
fre[k] = (WebRtc_Word16)(fre[k] * transcodeScale);
|
|
fim[k] = (WebRtc_Word16)(fim[k] * transcodeScale);
|
|
}
|
|
|
|
/* Save data for multiple packets memory */
|
|
for (k = 0; k < FRAMESAMPLES_HALF; k++) {
|
|
ISACencLB_obj->SaveEnc_obj.fre[k +
|
|
ISACencLB_obj->SaveEnc_obj.startIdx * FRAMESAMPLES_HALF] =
|
|
fre[k];
|
|
ISACencLB_obj->SaveEnc_obj.fim[k +
|
|
ISACencLB_obj->SaveEnc_obj.startIdx * FRAMESAMPLES_HALF] =
|
|
fim[k];
|
|
}
|
|
|
|
/* Re-store the state of arithmetic coder before coding LPC gains */
|
|
ISACencLB_obj->bitstr_obj.W_upper = transcodingParam.W_upper;
|
|
ISACencLB_obj->bitstr_obj.stream_index = transcodingParam.stream_index;
|
|
ISACencLB_obj->bitstr_obj.streamval = transcodingParam.streamval;
|
|
ISACencLB_obj->bitstr_obj.stream[transcodingParam.stream_index - 2] =
|
|
transcodingParam.stream[0];
|
|
ISACencLB_obj->bitstr_obj.stream[transcodingParam.stream_index - 1] =
|
|
transcodingParam.stream[1];
|
|
ISACencLB_obj->bitstr_obj.stream[transcodingParam.stream_index] =
|
|
transcodingParam.stream[2];
|
|
|
|
/* Code gains */
|
|
WebRtcIsac_EncodeLpcGainLb(lofilt_coef, hifilt_coef, bmodel,
|
|
&ISACencLB_obj->bitstr_obj, &ISACencLB_obj->SaveEnc_obj);
|
|
|
|
/* Update the number of bytes left for encoding the spectrum */
|
|
bytesLeftSpecCoding = payloadLimitBytes -
|
|
transcodingParam.stream_index;
|
|
|
|
/* Encode the spectrum */
|
|
err = WebRtcIsac_EncodeSpecLb(fre, fim, &ISACencLB_obj->bitstr_obj,
|
|
AvgPitchGain_Q12);
|
|
if((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
|
|
/* There has been an error but it was not too large
|
|
payload (we can cure too large payload) */
|
|
if (frame_mode == 1 && ISACencLB_obj->frame_nb == 1) {
|
|
/* If this is the second 30ms of a 60ms frame reset
|
|
this such that in the next call encoder starts fresh. */
|
|
ISACencLB_obj->frame_nb = 0;
|
|
}
|
|
return err;
|
|
}
|
|
iterCntr++;
|
|
}
|
|
|
|
/* i.e. 60 ms framesize and just processed the first 30ms, */
|
|
/* go back to main function to buffer the other 30ms speech frame */
|
|
if (frame_mode == 1)
|
|
{
|
|
if(ISACencLB_obj->frame_nb == 0)
|
|
{
|
|
ISACencLB_obj->frame_nb = 1;
|
|
return 0;
|
|
}
|
|
else if(ISACencLB_obj->frame_nb == 1)
|
|
{
|
|
ISACencLB_obj->frame_nb = 0;
|
|
/* also update the framelength for next packet,
|
|
in Adaptive mode only */
|
|
if (codingMode == 0 && (ISACencLB_obj->enforceFrameSize == 0))
|
|
{
|
|
ISACencLB_obj->new_framelength =
|
|
WebRtcIsac_GetNewFrameLength(ISACencLB_obj->bottleneck,
|
|
ISACencLB_obj->current_framesamples);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ISACencLB_obj->frame_nb = 0;
|
|
}
|
|
|
|
/* complete arithmetic coding */
|
|
stream_length = WebRtcIsac_EncTerminate(&ISACencLB_obj->bitstr_obj);
|
|
|
|
return stream_length;
|
|
}
|
|
|
|
|
|
int
|
|
WebRtcIsac_EncodeUb16(
|
|
float* in,
|
|
ISACUBEncStruct* ISACencUB_obj,
|
|
WebRtc_Word32 jitterInfo)
|
|
{
|
|
int err;
|
|
int k;
|
|
|
|
double lpcVecs[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME];
|
|
double percepFilterParams[(1 + UB_LPC_ORDER) * (SUBFRAMES<<1) +
|
|
(1 + UB_LPC_ORDER)];
|
|
|
|
double LP_lookahead[FRAMESAMPLES];
|
|
WebRtc_Word16 fre[FRAMESAMPLES_HALF]; /* Q7 */
|
|
WebRtc_Word16 fim[FRAMESAMPLES_HALF]; /* Q7 */
|
|
|
|
int status = 0;
|
|
|
|
double varscale[2];
|
|
double corr[SUBFRAMES<<1][UB_LPC_ORDER + 1];
|
|
double lpcGains[SUBFRAMES<<1];
|
|
transcode_obj transcodingParam;
|
|
double bytesLeftSpecCoding;
|
|
WebRtc_UWord16 payloadLimitBytes;
|
|
WebRtc_UWord16 iterCntr;
|
|
double s2nr;
|
|
|
|
|
|
/* buffer speech samples (by 10ms packet) until the framelength is */
|
|
/* reached (30 or 60 ms) */
|
|
/*********************************************************************/
|
|
|
|
/* fill the buffer with 10ms input data */
|
|
for (k = 0; k < FRAMESAMPLES_10ms; k++) {
|
|
ISACencUB_obj->data_buffer_float[k + ISACencUB_obj->buffer_index] =
|
|
in[k];
|
|
}
|
|
|
|
/* if buffersize is not equal to current framesize, and end of file is
|
|
not reached yet, we don't do encoding unless we have the whole frame */
|
|
if (ISACencUB_obj->buffer_index + FRAMESAMPLES_10ms < FRAMESAMPLES) {
|
|
ISACencUB_obj->buffer_index += FRAMESAMPLES_10ms;
|
|
return 0;
|
|
}
|
|
|
|
/* end of buffer function */
|
|
/**************************/
|
|
|
|
/* encoding */
|
|
/************/
|
|
|
|
/* reset bitstream */
|
|
ISACencUB_obj->bitstr_obj.W_upper = 0xFFFFFFFF;
|
|
ISACencUB_obj->bitstr_obj.streamval = 0;
|
|
ISACencUB_obj->bitstr_obj.stream_index = 0;
|
|
|
|
/* bandwidth estimation and coding */
|
|
/* To be used for Redundant Coding */
|
|
WebRtcIsac_EncodeJitterInfo(jitterInfo, &ISACencUB_obj->bitstr_obj);
|
|
|
|
status = WebRtcIsac_EncodeBandwidth(isac16kHz,
|
|
&ISACencUB_obj->bitstr_obj);
|
|
if (status < 0) {
|
|
return status;
|
|
}
|
|
|
|
s2nr = WebRtcIsac_GetSnr(ISACencUB_obj->bottleneck,
|
|
FRAMESAMPLES);
|
|
|
|
memcpy(lpcVecs, ISACencUB_obj->lastLPCVec, UB_LPC_ORDER * sizeof(double));
|
|
|
|
for (k = 0; k < FRAMESAMPLES; k++) {
|
|
LP_lookahead[k] = ISACencUB_obj->data_buffer_float[UB_LOOKAHEAD + k];
|
|
}
|
|
|
|
/* find coefficients for perceptual pre-filters */
|
|
WebRtcIsac_GetLpcCoefUb(LP_lookahead, &ISACencUB_obj->maskfiltstr_obj,
|
|
&lpcVecs[UB_LPC_ORDER], corr, varscale, isac16kHz);
|
|
|
|
memcpy(ISACencUB_obj->lastLPCVec,
|
|
&lpcVecs[(UB16_LPC_VEC_PER_FRAME - 1) * (UB_LPC_ORDER)],
|
|
sizeof(double) * UB_LPC_ORDER);
|
|
|
|
/* code LPC model and shape - gains not quantized yet */
|
|
WebRtcIsac_EncodeLpcUB(lpcVecs, &ISACencUB_obj->bitstr_obj,
|
|
percepFilterParams, isac16kHz, &ISACencUB_obj->SaveEnc_obj);
|
|
|
|
|
|
// the first set of lpc parameters are from the last sub-frame of
|
|
// the previous frame. so we don't care about them
|
|
WebRtcIsac_GetLpcGain(s2nr, &percepFilterParams[UB_LPC_ORDER + 1],
|
|
(SUBFRAMES<<1), lpcGains, corr, varscale);
|
|
|
|
/* Store the state of arithmetic coder before coding LPC gains */
|
|
transcodingParam.stream_index = ISACencUB_obj->bitstr_obj.stream_index;
|
|
transcodingParam.W_upper = ISACencUB_obj->bitstr_obj.W_upper;
|
|
transcodingParam.streamval = ISACencUB_obj->bitstr_obj.streamval;
|
|
transcodingParam.stream[0] = ISACencUB_obj->bitstr_obj.stream[
|
|
ISACencUB_obj->bitstr_obj.stream_index - 2];
|
|
transcodingParam.stream[1] = ISACencUB_obj->bitstr_obj.stream[
|
|
ISACencUB_obj->bitstr_obj.stream_index - 1];
|
|
transcodingParam.stream[2] = ISACencUB_obj->bitstr_obj.stream[
|
|
ISACencUB_obj->bitstr_obj.stream_index];
|
|
|
|
/* Store LPC Gains before encoding them */
|
|
for(k = 0; k < SUBFRAMES; k++) {
|
|
transcodingParam.loFiltGain[k] = lpcGains[k];
|
|
transcodingParam.hiFiltGain[k] = lpcGains[SUBFRAMES + k];
|
|
}
|
|
|
|
// Store the gains for multiple encoding
|
|
memcpy(ISACencUB_obj->SaveEnc_obj.lpcGain, lpcGains, (SUBFRAMES << 1) * sizeof(double));
|
|
|
|
WebRtcIsac_EncodeLpcGainUb(lpcGains, &ISACencUB_obj->bitstr_obj,
|
|
ISACencUB_obj->SaveEnc_obj.lpcGainIndex);
|
|
WebRtcIsac_EncodeLpcGainUb(&lpcGains[SUBFRAMES], &ISACencUB_obj->bitstr_obj,
|
|
&ISACencUB_obj->SaveEnc_obj.lpcGainIndex[SUBFRAMES]);
|
|
|
|
/* Get the correct value for the payload limit and calculate the number of
|
|
bytes left for coding the spectrum. It is a 30ms frame
|
|
Subract 3 because termination process may add 3 bytes */
|
|
payloadLimitBytes = ISACencUB_obj->maxPayloadSizeBytes -
|
|
ISACencUB_obj->numBytesUsed - 3;
|
|
bytesLeftSpecCoding = payloadLimitBytes -
|
|
ISACencUB_obj->bitstr_obj.stream_index;
|
|
|
|
for (k = 0; k < (SUBFRAMES<<1); k++) {
|
|
percepFilterParams[k*(UB_LPC_ORDER + 1) + (UB_LPC_ORDER + 1)] =
|
|
lpcGains[k];
|
|
}
|
|
|
|
/* perceptual pre-filtering (using normalized lattice filter) */
|
|
/* first half-frame filtering */
|
|
WebRtcIsac_NormLatticeFilterMa(UB_LPC_ORDER,
|
|
ISACencUB_obj->maskfiltstr_obj.PreStateLoF,
|
|
ISACencUB_obj->maskfiltstr_obj.PreStateLoG,
|
|
&ISACencUB_obj->data_buffer_float[0],
|
|
&percepFilterParams[UB_LPC_ORDER + 1],
|
|
&LP_lookahead[0]);
|
|
|
|
/* Second half-frame filtering */
|
|
WebRtcIsac_NormLatticeFilterMa(UB_LPC_ORDER,
|
|
ISACencUB_obj->maskfiltstr_obj.PreStateLoF,
|
|
ISACencUB_obj->maskfiltstr_obj.PreStateLoG,
|
|
&ISACencUB_obj->data_buffer_float[FRAMESAMPLES_HALF],
|
|
&percepFilterParams[(UB_LPC_ORDER + 1) + SUBFRAMES *
|
|
(UB_LPC_ORDER + 1)], &LP_lookahead[FRAMESAMPLES_HALF]);
|
|
|
|
WebRtcIsac_Time2Spec(&LP_lookahead[0], &LP_lookahead[FRAMESAMPLES_HALF],
|
|
fre, fim, &ISACencUB_obj->fftstr_obj);
|
|
|
|
//Store FFT coefficients for multiple encoding
|
|
memcpy(&ISACencUB_obj->SaveEnc_obj.realFFT, fre,
|
|
FRAMESAMPLES_HALF * sizeof(WebRtc_Word16));
|
|
|
|
memcpy(&ISACencUB_obj->SaveEnc_obj.imagFFT, fim,
|
|
FRAMESAMPLES_HALF * sizeof(WebRtc_Word16));
|
|
|
|
// Prepare the audio buffer for the next packet
|
|
// move the last 3 ms to the beginning of the buffer
|
|
memcpy(ISACencUB_obj->data_buffer_float,
|
|
&ISACencUB_obj->data_buffer_float[FRAMESAMPLES],
|
|
LB_TOTAL_DELAY_SAMPLES * sizeof(float));
|
|
// start writing with 3 ms delay to compensate for the delay
|
|
// of the lower-band.
|
|
ISACencUB_obj->buffer_index = LB_TOTAL_DELAY_SAMPLES;
|
|
|
|
// Save the bit-stream object at this point for FEC.
|
|
memcpy(&ISACencUB_obj->SaveEnc_obj.bitStreamObj,
|
|
&ISACencUB_obj->bitstr_obj, sizeof(Bitstr));
|
|
|
|
/* quantization and lossless coding */
|
|
err = WebRtcIsac_EncodeSpecUB16(fre, fim, &ISACencUB_obj->bitstr_obj);
|
|
if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
|
|
return err;
|
|
}
|
|
|
|
iterCntr = 0;
|
|
while((ISACencUB_obj->bitstr_obj.stream_index > payloadLimitBytes) ||
|
|
(err == -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
|
|
double bytesSpecCoderUsed;
|
|
double transcodeScale;
|
|
|
|
if (iterCntr >= MAX_PAYLOAD_LIMIT_ITERATION) {
|
|
/* We were not able to limit the payload size */
|
|
return -ISAC_PAYLOAD_LARGER_THAN_LIMIT;
|
|
}
|
|
|
|
if (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH) {
|
|
bytesSpecCoderUsed = STREAM_SIZE_MAX;
|
|
// being conservative
|
|
transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed * 0.5;
|
|
} else {
|
|
bytesSpecCoderUsed = ISACencUB_obj->bitstr_obj.stream_index -
|
|
transcodingParam.stream_index;
|
|
transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed;
|
|
}
|
|
|
|
/* To be safe, we reduce the scale depending on the
|
|
number of iterations. */
|
|
transcodeScale *= (1.0 - (0.9 * (double)iterCntr/
|
|
(double)MAX_PAYLOAD_LIMIT_ITERATION));
|
|
|
|
/* Scale the LPC Gains */
|
|
for (k = 0; k < SUBFRAMES; k++) {
|
|
transcodingParam.loFiltGain[k] *= transcodeScale;
|
|
transcodingParam.hiFiltGain[k] *= transcodeScale;
|
|
}
|
|
|
|
/* Scale DFT coefficients */
|
|
for (k = 0; k < FRAMESAMPLES_HALF; k++) {
|
|
fre[k] = (WebRtc_Word16)(fre[k] * transcodeScale + 0.5);
|
|
fim[k] = (WebRtc_Word16)(fim[k] * transcodeScale + 0.5);
|
|
}
|
|
|
|
//Store FFT coefficients for multiple encoding
|
|
memcpy(&ISACencUB_obj->SaveEnc_obj.realFFT, fre,
|
|
FRAMESAMPLES_HALF * sizeof(WebRtc_Word16));
|
|
|
|
memcpy(&ISACencUB_obj->SaveEnc_obj.imagFFT, fim,
|
|
FRAMESAMPLES_HALF * sizeof(WebRtc_Word16));
|
|
|
|
|
|
/* Store the state of arithmetic coder before coding LPC gains */
|
|
ISACencUB_obj->bitstr_obj.W_upper = transcodingParam.W_upper;
|
|
|
|
ISACencUB_obj->bitstr_obj.stream_index = transcodingParam.stream_index;
|
|
|
|
ISACencUB_obj->bitstr_obj.streamval = transcodingParam.streamval;
|
|
|
|
ISACencUB_obj->bitstr_obj.stream[transcodingParam.stream_index - 2] =
|
|
transcodingParam.stream[0];
|
|
|
|
ISACencUB_obj->bitstr_obj.stream[transcodingParam.stream_index - 1] =
|
|
transcodingParam.stream[1];
|
|
|
|
ISACencUB_obj->bitstr_obj.stream[transcodingParam.stream_index] =
|
|
transcodingParam.stream[2];
|
|
|
|
// Store the gains for multiple encoding
|
|
memcpy(ISACencUB_obj->SaveEnc_obj.lpcGain, lpcGains,
|
|
(SUBFRAMES << 1) * sizeof(double));
|
|
|
|
WebRtcIsac_EncodeLpcGainUb(transcodingParam.loFiltGain,
|
|
&ISACencUB_obj->bitstr_obj,
|
|
ISACencUB_obj->SaveEnc_obj.lpcGainIndex);
|
|
WebRtcIsac_EncodeLpcGainUb(transcodingParam.hiFiltGain,
|
|
&ISACencUB_obj->bitstr_obj,
|
|
&ISACencUB_obj->SaveEnc_obj.lpcGainIndex[SUBFRAMES]);
|
|
|
|
/* Update the number of bytes left for encoding the spectrum */
|
|
bytesLeftSpecCoding = payloadLimitBytes -
|
|
ISACencUB_obj->bitstr_obj.stream_index;
|
|
|
|
// Save the bit-stream object at this point for FEC.
|
|
memcpy(&ISACencUB_obj->SaveEnc_obj.bitStreamObj,
|
|
&ISACencUB_obj->bitstr_obj, sizeof(Bitstr));
|
|
|
|
/* Encode the spectrum */
|
|
err = WebRtcIsac_EncodeSpecUB16(fre, fim, &ISACencUB_obj->bitstr_obj);
|
|
if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
|
|
/* There has been an error but it was not too large payload
|
|
(we can cure too large payload) */
|
|
return err;
|
|
}
|
|
iterCntr++;
|
|
}
|
|
|
|
/* complete arithmetic coding */
|
|
return WebRtcIsac_EncTerminate(&ISACencUB_obj->bitstr_obj);
|
|
}
|
|
|
|
|
|
int
|
|
WebRtcIsac_EncodeUb12(
|
|
float* in,
|
|
ISACUBEncStruct* ISACencUB_obj,
|
|
WebRtc_Word32 jitterInfo)
|
|
{
|
|
int err;
|
|
int k;
|
|
int iterCntr;
|
|
|
|
double lpcVecs[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME];
|
|
|
|
double percepFilterParams[(1 + UB_LPC_ORDER) * SUBFRAMES];
|
|
float LP[FRAMESAMPLES_HALF];
|
|
float HP[FRAMESAMPLES_HALF];
|
|
|
|
double LP_lookahead[FRAMESAMPLES_HALF];
|
|
double HP_lookahead[FRAMESAMPLES_HALF];
|
|
double LPw[FRAMESAMPLES_HALF];
|
|
|
|
double HPw[FRAMESAMPLES_HALF];
|
|
WebRtc_Word16 fre[FRAMESAMPLES_HALF]; /* Q7 */
|
|
WebRtc_Word16 fim[FRAMESAMPLES_HALF]; /* Q7 */
|
|
|
|
WebRtc_Word16 AvgPitchGain_Q12;
|
|
|
|
int status = 0;
|
|
|
|
double varscale[1];
|
|
|
|
double corr[UB_LPC_GAIN_DIM][UB_LPC_ORDER + 1];
|
|
double lpcGains[SUBFRAMES];
|
|
transcode_obj transcodingParam;
|
|
double bytesLeftSpecCoding;
|
|
WebRtc_UWord16 payloadLimitBytes;
|
|
double s2nr;
|
|
|
|
/* buffer speech samples (by 10ms packet) until the framelength is */
|
|
/* reached (30 or 60 ms) */
|
|
/********************************************************************/
|
|
|
|
/* fill the buffer with 10ms input data */
|
|
for (k=0; k<FRAMESAMPLES_10ms; k++) {
|
|
ISACencUB_obj->data_buffer_float[k + ISACencUB_obj->buffer_index] =
|
|
in[k];
|
|
}
|
|
|
|
/* if buffer-size is not equal to current frame-size then increase the
|
|
index and return. We do the encoding when we have enough audio. */
|
|
if (ISACencUB_obj->buffer_index + FRAMESAMPLES_10ms < FRAMESAMPLES) {
|
|
ISACencUB_obj->buffer_index += FRAMESAMPLES_10ms;
|
|
return 0;
|
|
}
|
|
/* if buffer reached the right size, reset index and continue
|
|
with encoding the frame */
|
|
ISACencUB_obj->buffer_index = 0;
|
|
|
|
/* end of buffer function */
|
|
/**************************/
|
|
|
|
/* encoding */
|
|
/************/
|
|
|
|
/* reset bitstream */
|
|
ISACencUB_obj->bitstr_obj.W_upper = 0xFFFFFFFF;
|
|
ISACencUB_obj->bitstr_obj.streamval = 0;
|
|
ISACencUB_obj->bitstr_obj.stream_index = 0;
|
|
|
|
/* bandwidth estimation and coding */
|
|
/* To be used for Redundant Coding */
|
|
WebRtcIsac_EncodeJitterInfo(jitterInfo, &ISACencUB_obj->bitstr_obj);
|
|
|
|
status = WebRtcIsac_EncodeBandwidth(isac12kHz,
|
|
&ISACencUB_obj->bitstr_obj);
|
|
if (status < 0) {
|
|
return status;
|
|
}
|
|
|
|
|
|
s2nr = WebRtcIsac_GetSnr(ISACencUB_obj->bottleneck,
|
|
FRAMESAMPLES);
|
|
|
|
/* split signal in two bands */
|
|
WebRtcIsac_SplitAndFilterFloat(ISACencUB_obj->data_buffer_float, HP, LP,
|
|
HP_lookahead, LP_lookahead, &ISACencUB_obj->prefiltbankstr_obj);
|
|
|
|
AvgPitchGain_Q12 = 0;
|
|
|
|
/* find coefficients for perceptual pre-filters */
|
|
WebRtcIsac_GetLpcCoefUb(LP_lookahead, &ISACencUB_obj->maskfiltstr_obj,
|
|
lpcVecs, corr, varscale, isac12kHz);
|
|
|
|
/* code LPC model and shape - gains not quantized yet */
|
|
WebRtcIsac_EncodeLpcUB(lpcVecs, &ISACencUB_obj->bitstr_obj,
|
|
percepFilterParams, isac12kHz, &ISACencUB_obj->SaveEnc_obj);
|
|
|
|
WebRtcIsac_GetLpcGain(s2nr, percepFilterParams, SUBFRAMES, lpcGains,
|
|
corr, varscale);
|
|
|
|
/* Store the state of arithmetic coder before coding LPC gains */
|
|
transcodingParam.W_upper = ISACencUB_obj->bitstr_obj.W_upper;
|
|
|
|
transcodingParam.stream_index = ISACencUB_obj->bitstr_obj.stream_index;
|
|
|
|
transcodingParam.streamval = ISACencUB_obj->bitstr_obj.streamval;
|
|
|
|
transcodingParam.stream[0] = ISACencUB_obj->bitstr_obj.stream[
|
|
ISACencUB_obj->bitstr_obj.stream_index - 2];
|
|
|
|
transcodingParam.stream[1] = ISACencUB_obj->bitstr_obj.stream[
|
|
ISACencUB_obj->bitstr_obj.stream_index - 1];
|
|
|
|
transcodingParam.stream[2] = ISACencUB_obj->bitstr_obj.stream[
|
|
ISACencUB_obj->bitstr_obj.stream_index];
|
|
|
|
/* Store LPC Gains before encoding them */
|
|
for(k = 0; k < SUBFRAMES; k++) {
|
|
transcodingParam.loFiltGain[k] = lpcGains[k];
|
|
}
|
|
|
|
// Store the gains for multiple encoding
|
|
memcpy(ISACencUB_obj->SaveEnc_obj.lpcGain, lpcGains, SUBFRAMES *
|
|
sizeof(double));
|
|
|
|
WebRtcIsac_EncodeLpcGainUb(lpcGains, &ISACencUB_obj->bitstr_obj,
|
|
ISACencUB_obj->SaveEnc_obj.lpcGainIndex);
|
|
|
|
for(k = 0; k < SUBFRAMES; k++) {
|
|
percepFilterParams[k*(UB_LPC_ORDER + 1)] = lpcGains[k];
|
|
}
|
|
|
|
/* perceptual pre-filtering (using normalized lattice filter) */
|
|
/* low-band filtering */
|
|
WebRtcIsac_NormLatticeFilterMa(UB_LPC_ORDER,
|
|
ISACencUB_obj->maskfiltstr_obj.PreStateLoF,
|
|
ISACencUB_obj->maskfiltstr_obj.PreStateLoG, LP, percepFilterParams,
|
|
LPw);
|
|
|
|
/* Get the correct value for the payload limit and calculate the number
|
|
of bytes left for coding the spectrum. It is a 30ms frame Subract 3
|
|
because termination process may add 3 bytes */
|
|
payloadLimitBytes = ISACencUB_obj->maxPayloadSizeBytes -
|
|
ISACencUB_obj->numBytesUsed - 3;
|
|
bytesLeftSpecCoding = payloadLimitBytes -
|
|
ISACencUB_obj->bitstr_obj.stream_index;
|
|
|
|
memset(HPw, 0, sizeof(double) * FRAMESAMPLES_HALF);
|
|
|
|
/* transform */
|
|
WebRtcIsac_Time2Spec(LPw, HPw, fre, fim, &ISACencUB_obj->fftstr_obj);
|
|
|
|
//Store real FFT coefficients for multiple encoding
|
|
memcpy(&ISACencUB_obj->SaveEnc_obj.realFFT, fre,
|
|
FRAMESAMPLES_HALF * sizeof(WebRtc_Word16));
|
|
|
|
//Store imaginary FFT coefficients for multiple encoding
|
|
memcpy(&ISACencUB_obj->SaveEnc_obj.imagFFT, fim,
|
|
FRAMESAMPLES_HALF * sizeof(WebRtc_Word16));
|
|
|
|
// Save the bit-stream object at this point for FEC.
|
|
memcpy(&ISACencUB_obj->SaveEnc_obj.bitStreamObj,
|
|
&ISACencUB_obj->bitstr_obj, sizeof(Bitstr));
|
|
|
|
/* quantization and lossless coding */
|
|
err = WebRtcIsac_EncodeSpecUB12(fre, fim, &ISACencUB_obj->bitstr_obj);
|
|
if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
|
|
/* There has been an error but it was not too large
|
|
payload (we can cure too large payload) */
|
|
return err;
|
|
}
|
|
iterCntr = 0;
|
|
while((ISACencUB_obj->bitstr_obj.stream_index > payloadLimitBytes) ||
|
|
(err == -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
|
|
double bytesSpecCoderUsed;
|
|
double transcodeScale;
|
|
|
|
if (iterCntr >= MAX_PAYLOAD_LIMIT_ITERATION) {
|
|
/* We were not able to limit the payload size */
|
|
return -ISAC_PAYLOAD_LARGER_THAN_LIMIT;
|
|
}
|
|
|
|
if (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH) {
|
|
bytesSpecCoderUsed = STREAM_SIZE_MAX;
|
|
// being coservative
|
|
transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed * 0.5;
|
|
} else {
|
|
bytesSpecCoderUsed = ISACencUB_obj->bitstr_obj.stream_index -
|
|
transcodingParam.stream_index;
|
|
transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed;
|
|
}
|
|
|
|
/* To be safe, we reduce the scale depending on the
|
|
number of iterations. */
|
|
transcodeScale *= (1.0 - (0.9 * (double)iterCntr/
|
|
(double)MAX_PAYLOAD_LIMIT_ITERATION));
|
|
|
|
/* Scale the LPC Gains */
|
|
for (k = 0; k < SUBFRAMES; k++) {
|
|
transcodingParam.loFiltGain[k] *= transcodeScale;
|
|
}
|
|
|
|
/* Scale DFT coefficients */
|
|
for (k = 0; k < FRAMESAMPLES_HALF; k++) {
|
|
fre[k] = (WebRtc_Word16)(fre[k] * transcodeScale + 0.5);
|
|
fim[k] = (WebRtc_Word16)(fim[k] * transcodeScale + 0.5);
|
|
}
|
|
|
|
//Store real FFT coefficients for multiple encoding
|
|
memcpy(&ISACencUB_obj->SaveEnc_obj.realFFT, fre,
|
|
FRAMESAMPLES_HALF * sizeof(WebRtc_Word16));
|
|
|
|
//Store imaginary FFT coefficients for multiple encoding
|
|
memcpy(&ISACencUB_obj->SaveEnc_obj.imagFFT, fim,
|
|
FRAMESAMPLES_HALF * sizeof(WebRtc_Word16));
|
|
|
|
|
|
/* Re-store the state of arithmetic coder before coding LPC gains */
|
|
ISACencUB_obj->bitstr_obj.W_upper = transcodingParam.W_upper;
|
|
|
|
ISACencUB_obj->bitstr_obj.stream_index = transcodingParam.stream_index;
|
|
|
|
ISACencUB_obj->bitstr_obj.streamval = transcodingParam.streamval;
|
|
|
|
ISACencUB_obj->bitstr_obj.stream[transcodingParam.stream_index - 2] =
|
|
transcodingParam.stream[0];
|
|
|
|
ISACencUB_obj->bitstr_obj.stream[transcodingParam.stream_index - 1] =
|
|
transcodingParam.stream[1];
|
|
|
|
ISACencUB_obj->bitstr_obj.stream[transcodingParam.stream_index] =
|
|
transcodingParam.stream[2];
|
|
|
|
// Store the gains for multiple encoding
|
|
memcpy(&ISACencUB_obj->SaveEnc_obj.lpcGain, lpcGains, SUBFRAMES *
|
|
sizeof(double));
|
|
|
|
// encode LPC gain and store quantization indices. HAving quantization
|
|
// indices reduces transcoding complexity if 'scale factor' is 1.
|
|
WebRtcIsac_EncodeLpcGainUb(transcodingParam.loFiltGain,
|
|
&ISACencUB_obj->bitstr_obj,
|
|
ISACencUB_obj->SaveEnc_obj.lpcGainIndex);
|
|
|
|
// Save the bit-stream object at this point for FEC.
|
|
memcpy(&ISACencUB_obj->SaveEnc_obj.bitStreamObj,
|
|
&ISACencUB_obj->bitstr_obj, sizeof(Bitstr));
|
|
|
|
/* Update the number of bytes left for encoding the spectrum */
|
|
bytesLeftSpecCoding = payloadLimitBytes -
|
|
ISACencUB_obj->bitstr_obj.stream_index;
|
|
|
|
/* Encode the spectrum */
|
|
err = WebRtcIsac_EncodeSpecUB12(fre, fim,
|
|
&ISACencUB_obj->bitstr_obj);
|
|
if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) {
|
|
/* There has been an error but it was not too large payload
|
|
(we can cure too large payload) */
|
|
return err;
|
|
}
|
|
iterCntr++;
|
|
}
|
|
|
|
/* complete arithmetic coding */
|
|
return WebRtcIsac_EncTerminate(&ISACencUB_obj->bitstr_obj);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This function is used to create a new bitstream with new BWE.
|
|
The same data as previously encoded with the function WebRtcIsac_Encoder().
|
|
The data needed is taken from the struct, where it was stored
|
|
when calling the encoder. */
|
|
|
|
int WebRtcIsac_EncodeStoredDataLb(
|
|
const ISAC_SaveEncData_t* ISACSavedEnc_obj,
|
|
Bitstr* ISACBitStr_obj,
|
|
int BWnumber,
|
|
float scale)
|
|
{
|
|
int ii;
|
|
int status;
|
|
int BWno = BWnumber;
|
|
|
|
const WebRtc_UWord16 *WebRtcIsac_kQPitchGainCdf_ptr[1];
|
|
const WebRtc_UWord16 **cdf;
|
|
|
|
double tmpLPCcoeffs_lo[(ORDERLO+1)*SUBFRAMES*2];
|
|
double tmpLPCcoeffs_hi[(ORDERHI+1)*SUBFRAMES*2];
|
|
int tmpLPCindex_g[12*2];
|
|
WebRtc_Word16 tmp_fre[FRAMESAMPLES], tmp_fim[FRAMESAMPLES];
|
|
|
|
/* Sanity Check - possible values for BWnumber is 0 - 23 */
|
|
if ((BWnumber < 0) || (BWnumber > 23)) {
|
|
return -ISAC_RANGE_ERROR_BW_ESTIMATOR;
|
|
}
|
|
|
|
/* reset bitstream */
|
|
ISACBitStr_obj->W_upper = 0xFFFFFFFF;
|
|
ISACBitStr_obj->streamval = 0;
|
|
ISACBitStr_obj->stream_index = 0;
|
|
|
|
/* encode frame length */
|
|
status = WebRtcIsac_EncodeFrameLen(ISACSavedEnc_obj->framelength,
|
|
ISACBitStr_obj);
|
|
if (status < 0) {
|
|
/* Wrong frame size */
|
|
return status;
|
|
}
|
|
|
|
/* Transcoding */
|
|
if ((scale > 0.0) && (scale < 1.0)) {
|
|
/* Compensate LPC gain */
|
|
for (ii = 0;
|
|
ii < ((ORDERLO + 1)* SUBFRAMES * (1 + ISACSavedEnc_obj->startIdx));
|
|
ii++) {
|
|
tmpLPCcoeffs_lo[ii] = scale * ISACSavedEnc_obj->LPCcoeffs_lo[ii];
|
|
}
|
|
for (ii = 0;
|
|
ii < ((ORDERHI + 1) * SUBFRAMES *(1 + ISACSavedEnc_obj->startIdx));
|
|
ii++) {
|
|
tmpLPCcoeffs_hi[ii] = scale * ISACSavedEnc_obj->LPCcoeffs_hi[ii];
|
|
}
|
|
/* Scale DFT */
|
|
for (ii = 0;
|
|
ii < (FRAMESAMPLES_HALF * (1 + ISACSavedEnc_obj->startIdx));
|
|
ii++) {
|
|
tmp_fre[ii] = (WebRtc_Word16)((scale) *
|
|
(float)ISACSavedEnc_obj->fre[ii]) ;
|
|
tmp_fim[ii] = (WebRtc_Word16)((scale) *
|
|
(float)ISACSavedEnc_obj->fim[ii]) ;
|
|
}
|
|
} else {
|
|
for (ii = 0;
|
|
ii < (KLT_ORDER_GAIN * (1 + ISACSavedEnc_obj->startIdx));
|
|
ii++) {
|
|
tmpLPCindex_g[ii] = ISACSavedEnc_obj->LPCindex_g[ii];
|
|
}
|
|
for (ii = 0;
|
|
ii < (FRAMESAMPLES_HALF * (1 + ISACSavedEnc_obj->startIdx));
|
|
ii++) {
|
|
tmp_fre[ii] = ISACSavedEnc_obj->fre[ii];
|
|
tmp_fim[ii] = ISACSavedEnc_obj->fim[ii];
|
|
}
|
|
}
|
|
|
|
/* encode bandwidth estimate */
|
|
WebRtcIsac_EncodeReceiveBw(&BWno, ISACBitStr_obj);
|
|
|
|
/* Loop over number of 30 msec */
|
|
for (ii = 0; ii <= ISACSavedEnc_obj->startIdx; ii++) {
|
|
/* encode pitch gains */
|
|
*WebRtcIsac_kQPitchGainCdf_ptr = WebRtcIsac_kQPitchGainCdf;
|
|
WebRtcIsac_EncHistMulti(ISACBitStr_obj,
|
|
&ISACSavedEnc_obj->pitchGain_index[ii], WebRtcIsac_kQPitchGainCdf_ptr, 1);
|
|
|
|
/* entropy coding of quantization pitch lags */
|
|
/* voicing classificiation */
|
|
if (ISACSavedEnc_obj->meanGain[ii] < 0.2) {
|
|
cdf = WebRtcIsac_kQPitchLagCdfPtrLo;
|
|
} else if (ISACSavedEnc_obj->meanGain[ii] < 0.4) {
|
|
cdf = WebRtcIsac_kQPitchLagCdfPtrMid;
|
|
} else {
|
|
cdf = WebRtcIsac_kQPitchLagCdfPtrHi;
|
|
}
|
|
WebRtcIsac_EncHistMulti(ISACBitStr_obj,
|
|
&ISACSavedEnc_obj->pitchIndex[PITCH_SUBFRAMES*ii], cdf,
|
|
PITCH_SUBFRAMES);
|
|
|
|
/* LPC */
|
|
/* entropy coding of model number */
|
|
WebRtcIsac_EncHistMulti(ISACBitStr_obj,
|
|
&ISACSavedEnc_obj->LPCmodel[ii], WebRtcIsac_kQKltModelCdfPtr, 1);
|
|
|
|
/* entropy coding of quantization indices - LPC shape only */
|
|
WebRtcIsac_EncHistMulti(ISACBitStr_obj,
|
|
&ISACSavedEnc_obj->LPCindex_s[KLT_ORDER_SHAPE*ii],
|
|
WebRtcIsac_kQKltCdfPtrShape[ISACSavedEnc_obj->LPCmodel[ii]],
|
|
KLT_ORDER_SHAPE);
|
|
|
|
/* If transcoding, get new LPC gain indices */
|
|
if (scale < 1.0) {
|
|
WebRtcIsac_TranscodeLPCCoef(&tmpLPCcoeffs_lo[(ORDERLO+1) *
|
|
SUBFRAMES*ii], &tmpLPCcoeffs_hi[(ORDERHI+1)*SUBFRAMES*ii],
|
|
ISACSavedEnc_obj->LPCmodel[ii],
|
|
&tmpLPCindex_g[KLT_ORDER_GAIN * ii]);
|
|
}
|
|
|
|
/* entropy coding of quantization indices - LPC gain */
|
|
WebRtcIsac_EncHistMulti(ISACBitStr_obj,
|
|
&tmpLPCindex_g[KLT_ORDER_GAIN*ii], WebRtcIsac_kQKltCdfPtrGain[
|
|
ISACSavedEnc_obj->LPCmodel[ii]], KLT_ORDER_GAIN);
|
|
|
|
/* quantization and lossless coding */
|
|
status = WebRtcIsac_EncodeSpecLb(&tmp_fre[ii*FRAMESAMPLES_HALF],
|
|
&tmp_fim[ii*FRAMESAMPLES_HALF], ISACBitStr_obj,
|
|
ISACSavedEnc_obj->AvgPitchGain[ii]);
|
|
if (status < 0) {
|
|
return status;
|
|
}
|
|
}
|
|
|
|
/* complete arithmetic coding */
|
|
return WebRtcIsac_EncTerminate(ISACBitStr_obj);
|
|
}
|
|
|
|
|
|
|
|
|
|
int WebRtcIsac_EncodeStoredDataUb12(
|
|
const ISACUBSaveEncDataStruct* ISACSavedEnc_obj,
|
|
Bitstr* bitStream,
|
|
WebRtc_Word32 jitterInfo,
|
|
float scale)
|
|
{
|
|
int n;
|
|
int err;
|
|
double lpcGain[SUBFRAMES];
|
|
WebRtc_Word16 realFFT[FRAMESAMPLES];
|
|
WebRtc_Word16 imagFFT[FRAMESAMPLES];
|
|
|
|
/* reset bitstream */
|
|
bitStream->W_upper = 0xFFFFFFFF;
|
|
bitStream->streamval = 0;
|
|
bitStream->stream_index = 0;
|
|
|
|
// Encode jitter index
|
|
WebRtcIsac_EncodeJitterInfo(jitterInfo, bitStream);
|
|
|
|
err = WebRtcIsac_EncodeBandwidth(isac12kHz, bitStream);
|
|
if(err < 0)
|
|
{
|
|
return err;
|
|
}
|
|
|
|
// Encode LPC-shape
|
|
WebRtcIsac_EncHistMulti(bitStream, ISACSavedEnc_obj->indexLPCShape,
|
|
WebRtcIsac_kLpcShapeCdfMatUb12, UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME);
|
|
|
|
|
|
// we only consider scales between zero and one.
|
|
if((scale <= 0.0) || (scale > 1.0))
|
|
{
|
|
scale = 1.0f;
|
|
}
|
|
|
|
if(scale == 1.0f)
|
|
{
|
|
//memcpy(lpcGain, ISACSavedEnc_obj->lpcGain, SUBFRAMES * sizeof(double));
|
|
WebRtcIsac_EncHistMulti(bitStream, ISACSavedEnc_obj->lpcGainIndex,
|
|
WebRtcIsac_kLpcGainCdfMat, UB_LPC_GAIN_DIM);
|
|
// store FFT coefficients
|
|
err = WebRtcIsac_EncodeSpecUB12(ISACSavedEnc_obj->realFFT,
|
|
ISACSavedEnc_obj->imagFFT, bitStream);
|
|
}
|
|
else
|
|
{
|
|
/* scale lpc gain and FFT coefficients */
|
|
for(n = 0; n < SUBFRAMES; n++)
|
|
{
|
|
lpcGain[n] = scale * ISACSavedEnc_obj->lpcGain[n];
|
|
}
|
|
// store lpc gain
|
|
WebRtcIsac_StoreLpcGainUb(lpcGain, bitStream);
|
|
for(n = 0; n < FRAMESAMPLES; n++)
|
|
{
|
|
realFFT[n] = (WebRtc_Word16)(scale * (float)ISACSavedEnc_obj->realFFT[n] + 0.5f);
|
|
imagFFT[n] = (WebRtc_Word16)(scale * (float)ISACSavedEnc_obj->imagFFT[n] + 0.5f);
|
|
}
|
|
// store FFT coefficients
|
|
err = WebRtcIsac_EncodeSpecUB12(realFFT, imagFFT, bitStream);
|
|
}
|
|
if(err < 0)
|
|
{
|
|
// error happened while encoding FFT coefficients.
|
|
return err;
|
|
}
|
|
|
|
/* complete arithmetic coding */
|
|
return WebRtcIsac_EncTerminate(bitStream);
|
|
}
|
|
|
|
|
|
int
|
|
WebRtcIsac_EncodeStoredDataUb16(
|
|
const ISACUBSaveEncDataStruct* ISACSavedEnc_obj,
|
|
Bitstr* bitStream,
|
|
WebRtc_Word32 jitterInfo,
|
|
float scale)
|
|
{
|
|
int n;
|
|
int err;
|
|
double lpcGain[SUBFRAMES << 1];
|
|
WebRtc_Word16 realFFT[FRAMESAMPLES];
|
|
WebRtc_Word16 imagFFT[FRAMESAMPLES];
|
|
|
|
/* reset bitstream */
|
|
bitStream->W_upper = 0xFFFFFFFF;
|
|
bitStream->streamval = 0;
|
|
bitStream->stream_index = 0;
|
|
|
|
// Encode jitter index
|
|
WebRtcIsac_EncodeJitterInfo(jitterInfo, bitStream);
|
|
|
|
err = WebRtcIsac_EncodeBandwidth(isac16kHz, bitStream);
|
|
if(err < 0)
|
|
{
|
|
return err;
|
|
}
|
|
|
|
WebRtcIsac_EncHistMulti(bitStream, ISACSavedEnc_obj->indexLPCShape,
|
|
WebRtcIsac_kLpcShapeCdfMatUb16, UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME);
|
|
|
|
// we only consider scales between zero and one.
|
|
if((scale <= 0.0) || (scale > 1.0))
|
|
{
|
|
scale = 1.0f;
|
|
}
|
|
|
|
if(scale == 1.0f)
|
|
{
|
|
// store gains
|
|
WebRtcIsac_EncHistMulti(bitStream, ISACSavedEnc_obj->lpcGainIndex,
|
|
WebRtcIsac_kLpcGainCdfMat, UB_LPC_GAIN_DIM);
|
|
WebRtcIsac_EncHistMulti(bitStream, &ISACSavedEnc_obj->lpcGainIndex[SUBFRAMES],
|
|
WebRtcIsac_kLpcGainCdfMat, UB_LPC_GAIN_DIM);
|
|
// store FFT coefficients
|
|
err = WebRtcIsac_EncodeSpecUB16(ISACSavedEnc_obj->realFFT,
|
|
ISACSavedEnc_obj->imagFFT, bitStream);
|
|
|
|
}
|
|
else
|
|
{
|
|
/* Scale Gain */
|
|
for(n = 0; n < SUBFRAMES; n++)
|
|
{
|
|
lpcGain[n] = scale * ISACSavedEnc_obj->lpcGain[n];
|
|
lpcGain[n + SUBFRAMES] = scale * ISACSavedEnc_obj->lpcGain[n + SUBFRAMES];
|
|
}
|
|
// store lpc gain
|
|
WebRtcIsac_StoreLpcGainUb(lpcGain, bitStream);
|
|
WebRtcIsac_StoreLpcGainUb(&lpcGain[SUBFRAMES], bitStream);
|
|
/* scale FFT coefficients */
|
|
for(n = 0; n < FRAMESAMPLES; n++)
|
|
{
|
|
realFFT[n] = (WebRtc_Word16)(scale * (float)ISACSavedEnc_obj->realFFT[n] + 0.5f);
|
|
imagFFT[n] = (WebRtc_Word16)(scale * (float)ISACSavedEnc_obj->imagFFT[n] + 0.5f);
|
|
}
|
|
// store FFT coefficients
|
|
err = WebRtcIsac_EncodeSpecUB16(realFFT, imagFFT, bitStream);
|
|
}
|
|
|
|
if(err < 0)
|
|
{
|
|
// error happened while encoding FFT coefficients.
|
|
return err;
|
|
}
|
|
|
|
/* complete arithmetic coding */
|
|
return WebRtcIsac_EncTerminate(bitStream);
|
|
}
|
|
|
|
|
|
WebRtc_Word16
|
|
WebRtcIsac_GetRedPayloadUb(
|
|
const ISACUBSaveEncDataStruct* ISACSavedEncObj,
|
|
Bitstr* bitStreamObj,
|
|
enum ISACBandwidth bandwidth)
|
|
{
|
|
int n;
|
|
WebRtc_Word16 status;
|
|
WebRtc_Word16 realFFT[FRAMESAMPLES_HALF];
|
|
WebRtc_Word16 imagFFT[FRAMESAMPLES_HALF];
|
|
|
|
// store bit-stream object.
|
|
memcpy(bitStreamObj, &ISACSavedEncObj->bitStreamObj, sizeof(Bitstr));
|
|
|
|
// Scale FFT coefficients.
|
|
for(n = 0; n < FRAMESAMPLES_HALF; n++)
|
|
{
|
|
realFFT[n] = (WebRtc_Word16)((float)ISACSavedEncObj->realFFT[n] *
|
|
RCU_TRANSCODING_SCALE_UB + 0.5);
|
|
imagFFT[n] = (WebRtc_Word16)((float)ISACSavedEncObj->imagFFT[n] *
|
|
RCU_TRANSCODING_SCALE_UB + 0.5);
|
|
}
|
|
|
|
switch(bandwidth)
|
|
{
|
|
case isac12kHz:
|
|
{
|
|
status = WebRtcIsac_EncodeSpecUB12(realFFT, imagFFT, bitStreamObj);
|
|
break;
|
|
}
|
|
case isac16kHz:
|
|
{
|
|
status = WebRtcIsac_EncodeSpecUB16(realFFT, imagFFT, bitStreamObj);
|
|
break;
|
|
}
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
if(status < 0)
|
|
{
|
|
// error happened
|
|
return status;
|
|
}
|
|
else
|
|
{
|
|
// terminate entropy coding
|
|
return WebRtcIsac_EncTerminate(bitStreamObj);
|
|
}
|
|
}
|