diff options
Diffstat (limited to 'src/modules/audio_coding/codecs/isac/fix/source/encode.c')
-rw-r--r-- | src/modules/audio_coding/codecs/isac/fix/source/encode.c | 626 |
1 files changed, 626 insertions, 0 deletions
diff --git a/src/modules/audio_coding/codecs/isac/fix/source/encode.c b/src/modules/audio_coding/codecs/isac/fix/source/encode.c new file mode 100644 index 0000000000..cb531e5ac9 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/encode.c @@ -0,0 +1,626 @@ +/* + * 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 + * + * Encoding function for the iSAC coder. + * + */ + +#include "arith_routins.h" +#include "bandwidth_estimator.h" +#include "codec.h" +#include "pitch_gain_tables.h" +#include "pitch_lag_tables.h" +#include "entropy_coding.h" +#include "lpc_tables.h" +#include "lpc_masking_model.h" +#include "pitch_estimator.h" +#include "structs.h" +#include <stdio.h> + + +int WebRtcIsacfix_EncodeImpl(WebRtc_Word16 *in, + ISACFIX_EncInst_t *ISACenc_obj, + BwEstimatorstr *bw_estimatordata, + WebRtc_Word16 CodingMode) +{ + WebRtc_Word16 stream_length = 0; + WebRtc_Word16 usefulstr_len = 0; + int k; + WebRtc_Word16 BWno; + + WebRtc_Word16 lofilt_coefQ15[(ORDERLO)*SUBFRAMES]; + WebRtc_Word16 hifilt_coefQ15[(ORDERHI)*SUBFRAMES]; + WebRtc_Word32 gain_lo_hiQ17[2*SUBFRAMES]; + + WebRtc_Word16 LPandHP[FRAMESAMPLES/2 + QLOOKAHEAD]; + WebRtc_Word16 LP16a[FRAMESAMPLES/2 + QLOOKAHEAD]; + WebRtc_Word16 HP16a[FRAMESAMPLES/2 + QLOOKAHEAD]; + + WebRtc_Word16 PitchLags_Q7[PITCH_SUBFRAMES]; + WebRtc_Word16 PitchGains_Q12[PITCH_SUBFRAMES]; + WebRtc_Word16 AvgPitchGain_Q12; + + WebRtc_Word16 frame_mode; /* 0 for 30ms, 1 for 60ms */ + WebRtc_Word16 processed_samples; + int status; + + WebRtc_Word32 bits_gainsQ11; + WebRtc_Word16 MinBytes; + WebRtc_Word16 bmodel; + + transcode_obj transcodingParam; + WebRtc_Word16 payloadLimitBytes; + WebRtc_Word16 arithLenBeforeEncodingDFT; + WebRtc_Word16 iterCntr; + + /* copy new frame length and bottle neck rate only for the first 10 ms data */ + if (ISACenc_obj->buffer_index == 0) { + /* set the framelength for the next packet */ + ISACenc_obj->current_framesamples = ISACenc_obj->new_framelength; + } + + frame_mode = ISACenc_obj->current_framesamples/MAX_FRAMESAMPLES; /* 0 (30 ms) or 1 (60 ms) */ + processed_samples = ISACenc_obj->current_framesamples/(frame_mode+1); /* 480 (30, 60 ms) */ + + /* 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++) { + ISACenc_obj->data_buffer_fix[k + ISACenc_obj->buffer_index] = in[k]; + } + /* if buffersize is not equal to current framesize, and end of file is not reached yet, */ + /* increase index and go back to main to get more speech samples */ + if (ISACenc_obj->buffer_index + FRAMESAMPLES_10ms != processed_samples) { + ISACenc_obj->buffer_index = ISACenc_obj->buffer_index + FRAMESAMPLES_10ms; + return 0; + } + /* if buffer reached the right size, reset index and continue with encoding the frame */ + ISACenc_obj->buffer_index = 0; + + /* end of buffer function */ + /**************************/ + + /* encoding */ + /************/ + + if (frame_mode == 0 || ISACenc_obj->frame_nb == 0 ) + { + /* reset bitstream */ + ISACenc_obj->bitstr_obj.W_upper = 0xFFFFFFFF; + ISACenc_obj->bitstr_obj.streamval = 0; + ISACenc_obj->bitstr_obj.stream_index = 0; + ISACenc_obj->bitstr_obj.full = 1; + + if (CodingMode == 0) { + ISACenc_obj->BottleNeck = WebRtcIsacfix_GetUplinkBandwidth(bw_estimatordata); + ISACenc_obj->MaxDelay = WebRtcIsacfix_GetUplinkMaxDelay(bw_estimatordata); + } + if (CodingMode == 0 && frame_mode == 0 && (ISACenc_obj->enforceFrameSize == 0)) { + ISACenc_obj->new_framelength = WebRtcIsacfix_GetNewFrameLength(ISACenc_obj->BottleNeck, + ISACenc_obj->current_framesamples); + } + + // multiply the bottleneck by 0.88 before computing SNR, 0.88 is tuned by experimenting on TIMIT + // 901/1024 is 0.87988281250000 + ISACenc_obj->s2nr = WebRtcIsacfix_GetSnr((WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(ISACenc_obj->BottleNeck, 901, 10), + ISACenc_obj->current_framesamples); + + /* encode frame length */ + status = WebRtcIsacfix_EncodeFrameLen(ISACenc_obj->current_framesamples, &ISACenc_obj->bitstr_obj); + if (status < 0) + { + /* Wrong frame size */ + if (frame_mode == 1 && ISACenc_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. + ISACenc_obj->frame_nb = 0; + } + return status; + } + + /* Save framelength for multiple packets memory */ + if (ISACenc_obj->SaveEnc_ptr != NULL) { + (ISACenc_obj->SaveEnc_ptr)->framelength=ISACenc_obj->current_framesamples; + } + + /* bandwidth estimation and coding */ + BWno = WebRtcIsacfix_GetDownlinkBwIndexImpl(bw_estimatordata); + status = WebRtcIsacfix_EncodeReceiveBandwidth(&BWno, &ISACenc_obj->bitstr_obj); + if (status < 0) + { + if (frame_mode == 1 && ISACenc_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. + ISACenc_obj->frame_nb = 0; + } + return status; + } + } + + /* split signal in two bands */ + WebRtcIsacfix_SplitAndFilter1(ISACenc_obj->data_buffer_fix, LP16a, HP16a, &ISACenc_obj->prefiltbankstr_obj ); + + /* estimate pitch parameters and pitch-filter lookahead signal */ + WebRtcIsacfix_PitchAnalysis(LP16a+QLOOKAHEAD, LPandHP, + &ISACenc_obj->pitchanalysisstr_obj, PitchLags_Q7, PitchGains_Q12); /* LPandHP = LP_lookahead_pfQ0, */ + + /* Set where to store data in multiple packets memory */ + if (ISACenc_obj->SaveEnc_ptr != NULL) { + if (frame_mode == 0 || ISACenc_obj->frame_nb == 0) + { + (ISACenc_obj->SaveEnc_ptr)->startIdx = 0; + } + else + { + (ISACenc_obj->SaveEnc_ptr)->startIdx = 1; + } + } + + /* quantize & encode pitch parameters */ + status = WebRtcIsacfix_EncodePitchGain(PitchGains_Q12, &ISACenc_obj->bitstr_obj, ISACenc_obj->SaveEnc_ptr); + if (status < 0) + { + if (frame_mode == 1 && ISACenc_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. + ISACenc_obj->frame_nb = 0; + } + return status; + } + status = WebRtcIsacfix_EncodePitchLag(PitchLags_Q7 , PitchGains_Q12, &ISACenc_obj->bitstr_obj, ISACenc_obj->SaveEnc_ptr); + if (status < 0) + { + if (frame_mode == 1 && ISACenc_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. + ISACenc_obj->frame_nb = 0; + } + return status; + } + AvgPitchGain_Q12 = WEBRTC_SPL_RSHIFT_W32(PitchGains_Q12[0] + PitchGains_Q12[1] + PitchGains_Q12[2] + PitchGains_Q12[3], 2); + + /* find coefficients for perceptual pre-filters */ + WebRtcIsacfix_GetLpcCoef(LPandHP, HP16a+QLOOKAHEAD, &ISACenc_obj->maskfiltstr_obj, + ISACenc_obj->s2nr, PitchGains_Q12, + gain_lo_hiQ17, lofilt_coefQ15, hifilt_coefQ15); /*LPandHP = LP_lookahead_pfQ0*/ + + // record LPC Gains for possible bit-rate reduction + for(k = 0; k < KLT_ORDER_GAIN; k++) + { + transcodingParam.lpcGains[k] = gain_lo_hiQ17[k]; + } + + /* code LPC model and shape - gains not quantized yet */ + status = WebRtcIsacfix_EncodeLpc(gain_lo_hiQ17, lofilt_coefQ15, hifilt_coefQ15, + &bmodel, &bits_gainsQ11, &ISACenc_obj->bitstr_obj, ISACenc_obj->SaveEnc_ptr, &transcodingParam); + if (status < 0) + { + if (frame_mode == 1 && ISACenc_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. + ISACenc_obj->frame_nb = 0; + } + return status; + } + arithLenBeforeEncodingDFT = (ISACenc_obj->bitstr_obj.stream_index << 1) + (1-ISACenc_obj->bitstr_obj.full); + + /* low-band filtering */ + WebRtcIsacfix_NormLatticeFilterMa(ORDERLO, ISACenc_obj->maskfiltstr_obj.PreStateLoGQ15, + LP16a, lofilt_coefQ15, gain_lo_hiQ17, 0, LPandHP);/* LPandHP = LP16b */ + + /* pitch filter */ + WebRtcIsacfix_PitchFilter(LPandHP, LP16a, &ISACenc_obj->pitchfiltstr_obj, PitchLags_Q7, PitchGains_Q12, 1);/* LPandHP = LP16b */ + + /* high-band filtering */ + WebRtcIsacfix_NormLatticeFilterMa(ORDERHI, ISACenc_obj->maskfiltstr_obj.PreStateHiGQ15, + HP16a, hifilt_coefQ15, gain_lo_hiQ17, 1, LPandHP);/*LPandHP = HP16b*/ + + /* transform */ + WebRtcIsacfix_Time2Spec(LP16a, LPandHP, LP16a, LPandHP); /*LPandHP = HP16b*/ + + /* Save data for multiple packets memory */ + if (ISACenc_obj->SaveEnc_ptr != NULL) { + for (k = 0; k < FRAMESAMPLES_HALF; k++) { + (ISACenc_obj->SaveEnc_ptr)->fre[k + (ISACenc_obj->SaveEnc_ptr)->startIdx*FRAMESAMPLES_HALF] = LP16a[k]; + (ISACenc_obj->SaveEnc_ptr)->fim[k + (ISACenc_obj->SaveEnc_ptr)->startIdx*FRAMESAMPLES_HALF] = LPandHP[k]; + } + (ISACenc_obj->SaveEnc_ptr)->AvgPitchGain[(ISACenc_obj->SaveEnc_ptr)->startIdx] = AvgPitchGain_Q12; + } + + /* quantization and lossless coding */ + status = WebRtcIsacfix_EncodeSpec(LP16a, LPandHP, &ISACenc_obj->bitstr_obj, AvgPitchGain_Q12); + if((status <= -1) && (status != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) /*LPandHP = HP16b*/ + { + if (frame_mode == 1 && ISACenc_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. + ISACenc_obj->frame_nb = 0; + } + return status; + } + + if((frame_mode == 1) && (ISACenc_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 = ISACenc_obj->payloadLimitBytes60 >> 1; + } + else if (frame_mode == 0) + { + // it is a 30ms frame + payloadLimitBytes = (ISACenc_obj->payloadLimitBytes30) - 3; + } + else + { + // this is the second half of a 60ms frame. + payloadLimitBytes = ISACenc_obj->payloadLimitBytes60 - 3; // subract 3 because termination process may add 3 bytes + } + + iterCntr = 0; + while((((ISACenc_obj->bitstr_obj.stream_index) << 1) > payloadLimitBytes) || + (status == -ISAC_DISALLOWED_BITSTREAM_LENGTH)) + { + WebRtc_Word16 arithLenDFTByte; + WebRtc_Word16 bytesLeftQ5; + WebRtc_Word16 ratioQ5[8] = {0, 6, 9, 12, 16, 19, 22, 25}; + + // According to experiments on TIMIT the following is proper for audio, but it is not agressive enough for tonal inputs + // such as DTMF, sweep-sine, ... + // + // (0.55 - (0.8 - ratio[i]/32) * 5 / 6) * 2^14 + // WebRtc_Word16 scaleQ14[8] = {0, 648, 1928, 3208, 4915, 6195, 7475, 8755}; + + + // This is a supper-agressive scaling passed the tests (tonal inputs) tone with one iteration for payload limit + // of 120 (32kbps bottleneck), number of frames needed a rate-reduction was 58403 + // + WebRtc_Word16 scaleQ14[8] = {0, 348, 828, 1408, 2015, 3195, 3500, 3500}; + WebRtc_Word16 idx; + + if(iterCntr >= MAX_PAYLOAD_LIMIT_ITERATION) + { + // We were not able to limit the payload size + + if((frame_mode == 1) && (ISACenc_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 togetehr we won't exceed + // the limit. + ISACenc_obj->frame_nb = 1; + return 0; + } + else if((frame_mode == 1) && (ISACenc_obj->frame_nb == 1)) + { + ISACenc_obj->frame_nb = 0; + } + + if(status != -ISAC_DISALLOWED_BITSTREAM_LENGTH) + { + return -ISAC_PAYLOAD_LARGER_THAN_LIMIT; + } + else + { + return status; + } + } + if(status != -ISAC_DISALLOWED_BITSTREAM_LENGTH) + { + arithLenDFTByte = (ISACenc_obj->bitstr_obj.stream_index << 1) + (1-ISACenc_obj->bitstr_obj.full) - arithLenBeforeEncodingDFT; + bytesLeftQ5 = (payloadLimitBytes - arithLenBeforeEncodingDFT) << 5; + + // bytesLeft / arithLenDFTBytes indicates how much scaling is required a rough estimate (agressive) + // scale = 0.55 - (0.8 - bytesLeft / arithLenDFTBytes) * 5 / 6 + // bytesLeft / arithLenDFTBytes below 0.2 will have a scale of zero and above 0.8 are treated as 0.8 + // to avoid division we do more simplification. + // + // values of (bytesLeft / arithLenDFTBytes)*32 between ratioQ5[i] and ratioQ5[i+1] are rounded to ratioQ5[i] + // and the corresponding scale is chosen + + // we compare bytesLeftQ5 with ratioQ5[]*arithLenDFTByte; + idx = 4; + idx += (bytesLeftQ5 >= WEBRTC_SPL_MUL_16_16(ratioQ5[idx], arithLenDFTByte))? 2:-2; + idx += (bytesLeftQ5 >= WEBRTC_SPL_MUL_16_16(ratioQ5[idx], arithLenDFTByte))? 1:-1; + idx += (bytesLeftQ5 >= WEBRTC_SPL_MUL_16_16(ratioQ5[idx], arithLenDFTByte))? 0:-1; + } + else + { + // we are here because the bit-stream did not fit into the buffer, in this case, the stream_index is not + // trustable, especially if the is the first 30ms of a packet. Thereforem, we will go for the most agressive + // case. + idx = 0; + } + // scale FFT coefficients to reduce the bit-rate + for(k = 0; k < FRAMESAMPLES_HALF; k++) + { + LP16a[k] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(LP16a[k], scaleQ14[idx], 14); + LPandHP[k] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(LPandHP[k], scaleQ14[idx], 14); + } + + // Save data for multiple packets memory + if (ISACenc_obj->SaveEnc_ptr != NULL) + { + for(k = 0; k < FRAMESAMPLES_HALF; k++) + { + (ISACenc_obj->SaveEnc_ptr)->fre[k + (ISACenc_obj->SaveEnc_ptr)->startIdx*FRAMESAMPLES_HALF] = LP16a[k]; + (ISACenc_obj->SaveEnc_ptr)->fim[k + (ISACenc_obj->SaveEnc_ptr)->startIdx*FRAMESAMPLES_HALF] = LPandHP[k]; + } + } + + // scale the unquantized LPC gains and save the scaled version for the future use + for(k = 0; k < KLT_ORDER_GAIN; k++) + { + gain_lo_hiQ17[k] = WEBRTC_SPL_MUL_16_32_RSFT14(scaleQ14[idx], transcodingParam.lpcGains[k]);//transcodingParam.lpcGains[k]; // + transcodingParam.lpcGains[k] = gain_lo_hiQ17[k]; + } + + // reset the bit-stream object to the state which it had before encoding LPC Gains + ISACenc_obj->bitstr_obj.full = transcodingParam.full; + ISACenc_obj->bitstr_obj.stream_index = transcodingParam.stream_index; + ISACenc_obj->bitstr_obj.streamval = transcodingParam.streamval; + ISACenc_obj->bitstr_obj.W_upper = transcodingParam.W_upper; + ISACenc_obj->bitstr_obj.stream[transcodingParam.stream_index-1] = transcodingParam.beforeLastWord; + ISACenc_obj->bitstr_obj.stream[transcodingParam.stream_index] = transcodingParam.lastWord; + + + // quantize and encode LPC gain + WebRtcIsacfix_EstCodeLpcGain(gain_lo_hiQ17, &ISACenc_obj->bitstr_obj, ISACenc_obj->SaveEnc_ptr); + arithLenBeforeEncodingDFT = (ISACenc_obj->bitstr_obj.stream_index << 1) + (1-ISACenc_obj->bitstr_obj.full); + status = WebRtcIsacfix_EncodeSpec(LP16a, LPandHP, &ISACenc_obj->bitstr_obj, AvgPitchGain_Q12); + if((status <= -1) && (status != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) /*LPandHP = HP16b*/ + { + if (frame_mode == 1 && ISACenc_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. + ISACenc_obj->frame_nb = 0; + } + return status; + } + iterCntr++; + } + + if (frame_mode == 1 && ISACenc_obj->frame_nb == 0) + /* i.e. 60 ms framesize and just processed the first 30ms, */ + /* go back to main function to buffer the other 30ms speech frame */ + { + ISACenc_obj->frame_nb = 1; + return 0; + } + else if (frame_mode == 1 && ISACenc_obj->frame_nb == 1) + { + ISACenc_obj->frame_nb = 0; + /* also update the framelength for next packet, in Adaptive mode only */ + if (CodingMode == 0 && (ISACenc_obj->enforceFrameSize == 0)) { + ISACenc_obj->new_framelength = WebRtcIsacfix_GetNewFrameLength(ISACenc_obj->BottleNeck, + ISACenc_obj->current_framesamples); + } + } + + + /* complete arithmetic coding */ + stream_length = WebRtcIsacfix_EncTerminate(&ISACenc_obj->bitstr_obj); + /* can this be negative? */ + + if(CodingMode == 0) + { + + /* update rate model and get minimum number of bytes in this packet */ + MinBytes = WebRtcIsacfix_GetMinBytes(&ISACenc_obj->rate_data_obj, (WebRtc_Word16) stream_length, + ISACenc_obj->current_framesamples, ISACenc_obj->BottleNeck, ISACenc_obj->MaxDelay); + + /* if bitstream is too short, add garbage at the end */ + + /* Store length of coded data */ + usefulstr_len = stream_length; + + /* Make sure MinBytes does not exceed packet size limit */ + if ((ISACenc_obj->frame_nb == 0) && (MinBytes > ISACenc_obj->payloadLimitBytes30)) { + MinBytes = ISACenc_obj->payloadLimitBytes30; + } else if ((ISACenc_obj->frame_nb == 1) && (MinBytes > ISACenc_obj->payloadLimitBytes60)) { + MinBytes = ISACenc_obj->payloadLimitBytes60; + } + + /* Make sure we don't allow more than 255 bytes of garbage data. + We store the length of the garbage data in 8 bits in the bitstream, + 255 is the max garbage lenght we can signal using 8 bits. */ + if( MinBytes > usefulstr_len + 255 ) { + MinBytes = usefulstr_len + 255; + } + + /* Save data for creation of multiple bitstreams */ + if (ISACenc_obj->SaveEnc_ptr != NULL) { + (ISACenc_obj->SaveEnc_ptr)->minBytes = MinBytes; + } + + while (stream_length < MinBytes) + { + if (stream_length & 0x0001){ + ISACenc_obj->bitstr_seed = WEBRTC_SPL_RAND( ISACenc_obj->bitstr_seed ); + ISACenc_obj->bitstr_obj.stream[ WEBRTC_SPL_RSHIFT_W16(stream_length, 1) ] |= (WebRtc_UWord16)(ISACenc_obj->bitstr_seed & 0xFF); + } else { + ISACenc_obj->bitstr_seed = WEBRTC_SPL_RAND( ISACenc_obj->bitstr_seed ); + ISACenc_obj->bitstr_obj.stream[ WEBRTC_SPL_RSHIFT_W16(stream_length, 1) ] = WEBRTC_SPL_LSHIFT_U16(ISACenc_obj->bitstr_seed, 8); + } + stream_length++; + } + + /* to get the real stream_length, without garbage */ + if (usefulstr_len & 0x0001) { + ISACenc_obj->bitstr_obj.stream[usefulstr_len>>1] &= 0xFF00; + ISACenc_obj->bitstr_obj.stream[usefulstr_len>>1] += (MinBytes - usefulstr_len) & 0x00FF; + } + else { + ISACenc_obj->bitstr_obj.stream[usefulstr_len>>1] &= 0x00FF; + ISACenc_obj->bitstr_obj.stream[usefulstr_len>>1] += WEBRTC_SPL_LSHIFT_U16((MinBytes - usefulstr_len) & 0x00FF, 8); + } + } + else + { + /* update rate model */ + WebRtcIsacfix_UpdateRateModel(&ISACenc_obj->rate_data_obj, (WebRtc_Word16) stream_length, + ISACenc_obj->current_framesamples, ISACenc_obj->BottleNeck); + } + return stream_length; +} + +/* This function is used to create a new bitstream with new BWE. + The same data as previously encoded with the fucntion WebRtcIsacfix_EncodeImpl() + is used. The data needed is taken from the struct, where it was stored + when calling the encoder. */ +int WebRtcIsacfix_EncodeStoredData(ISACFIX_EncInst_t *ISACenc_obj, + int BWnumber, + float scale) +{ + int ii; + int status; + WebRtc_Word16 BWno = BWnumber; + int stream_length = 0; + + WebRtc_Word16 model; + const WebRtc_UWord16 *Q_PitchGain_cdf_ptr[1]; + const WebRtc_UWord16 **cdf; + const ISAC_SaveEncData_t *SaveEnc_str; + WebRtc_Word32 tmpLPCcoeffs_g[KLT_ORDER_GAIN<<1]; + WebRtc_Word16 tmpLPCindex_g[KLT_ORDER_GAIN<<1]; + WebRtc_Word16 tmp_fre[FRAMESAMPLES]; + WebRtc_Word16 tmp_fim[FRAMESAMPLES]; + + SaveEnc_str = ISACenc_obj->SaveEnc_ptr; + + /* Check if SaveEnc memory exists */ + if (SaveEnc_str == NULL) { + return (-1); + } + + /* Sanity Check - possible values for BWnumber is 0 - 23 */ + if ((BWnumber < 0) || (BWnumber > 23)) { + return -ISAC_RANGE_ERROR_BW_ESTIMATOR; + } + + /* reset bitstream */ + ISACenc_obj->bitstr_obj.W_upper = 0xFFFFFFFF; + ISACenc_obj->bitstr_obj.streamval = 0; + ISACenc_obj->bitstr_obj.stream_index = 0; + ISACenc_obj->bitstr_obj.full = 1; + + /* encode frame length */ + status = WebRtcIsacfix_EncodeFrameLen(SaveEnc_str->framelength, &ISACenc_obj->bitstr_obj); + if (status < 0) { + /* Wrong frame size */ + return status; + } + + /* encode bandwidth estimate */ + status = WebRtcIsacfix_EncodeReceiveBandwidth(&BWno, &ISACenc_obj->bitstr_obj); + if (status < 0) { + return status; + } + + /* Transcoding */ + /* If scale < 1, rescale data to produce lower bitrate signal */ + if ((0.0 < scale) && (scale < 1.0)) { + /* Compensate LPC gain */ + for (ii = 0; ii < (KLT_ORDER_GAIN*(1+SaveEnc_str->startIdx)); ii++) { + tmpLPCcoeffs_g[ii] = (WebRtc_Word32) ((scale) * (float) SaveEnc_str->LPCcoeffs_g[ii]); + } + + /* Scale DFT */ + for (ii = 0; ii < (FRAMESAMPLES_HALF*(1+SaveEnc_str->startIdx)); ii++) { + tmp_fre[ii] = (WebRtc_Word16) ((scale) * (float) SaveEnc_str->fre[ii]) ; + tmp_fim[ii] = (WebRtc_Word16) ((scale) * (float) SaveEnc_str->fim[ii]) ; + } + } else { + for (ii = 0; ii < (KLT_ORDER_GAIN*(1+SaveEnc_str->startIdx)); ii++) { + tmpLPCindex_g[ii] = SaveEnc_str->LPCindex_g[ii]; + } + + for (ii = 0; ii < (FRAMESAMPLES_HALF*(1+SaveEnc_str->startIdx)); ii++) { + tmp_fre[ii] = SaveEnc_str->fre[ii]; + tmp_fim[ii] = SaveEnc_str->fim[ii]; + } + } + + /* Loop over number of 30 msec */ + for (ii = 0; ii <= SaveEnc_str->startIdx; ii++) + { + + /* encode pitch gains */ + *Q_PitchGain_cdf_ptr = WebRtcIsacfix_kPitchGainCdf; + status = WebRtcIsacfix_EncHistMulti(&ISACenc_obj->bitstr_obj, &SaveEnc_str->pitchGain_index[ii], + Q_PitchGain_cdf_ptr, 1); + if (status < 0) { + return status; + } + + /* entropy coding of quantization pitch lags */ + /* voicing classificiation */ + if (SaveEnc_str->meanGain[ii] <= 819) { + cdf = WebRtcIsacfix_kPitchLagPtrLo; + } else if (SaveEnc_str->meanGain[ii] <= 1638) { + cdf = WebRtcIsacfix_kPitchLagPtrMid; + } else { + cdf = WebRtcIsacfix_kPitchLagPtrHi; + } + status = WebRtcIsacfix_EncHistMulti(&ISACenc_obj->bitstr_obj, + &SaveEnc_str->pitchIndex[PITCH_SUBFRAMES*ii], cdf, PITCH_SUBFRAMES); + if (status < 0) { + return status; + } + + /* LPC */ + /* entropy coding of model number */ + model = 0; + status = WebRtcIsacfix_EncHistMulti(&ISACenc_obj->bitstr_obj, &model, + WebRtcIsacfix_kModelCdfPtr, 1); + if (status < 0) { + return status; + } + + /* entropy coding of quantization indices - LPC shape only */ + status = WebRtcIsacfix_EncHistMulti(&ISACenc_obj->bitstr_obj, &SaveEnc_str->LPCindex_s[KLT_ORDER_SHAPE*ii], + WebRtcIsacfix_kCdfShapePtr[0], KLT_ORDER_SHAPE); + if (status < 0) { + return status; + } + + /* If transcoding, get new LPC gain indices */ + if (scale < 1.0) { + WebRtcIsacfix_TranscodeLpcCoef(&tmpLPCcoeffs_g[KLT_ORDER_GAIN*ii], &tmpLPCindex_g[KLT_ORDER_GAIN*ii]); + } + + /* entropy coding of quantization indices - LPC gain */ + status = WebRtcIsacfix_EncHistMulti(&ISACenc_obj->bitstr_obj, &tmpLPCindex_g[KLT_ORDER_GAIN*ii], + WebRtcIsacfix_kCdfGainPtr[0], KLT_ORDER_GAIN); + if (status < 0) { + return status; + } + + /* quantization and lossless coding */ + status = WebRtcIsacfix_EncodeSpec(&tmp_fre[ii*FRAMESAMPLES_HALF], &tmp_fim[ii*FRAMESAMPLES_HALF], + &ISACenc_obj->bitstr_obj, SaveEnc_str->AvgPitchGain[ii]); + if (status < 0) { + return status; + } + } + + /* complete arithmetic coding */ + stream_length = WebRtcIsacfix_EncTerminate(&ISACenc_obj->bitstr_obj); + + return stream_length; +} |