| /* |
| * 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. |
| */ |
| |
| /****************************************************************** |
| |
| iLBC Speech Coder ANSI-C Source Code |
| |
| WebRtcIlbcfix_Decode.c |
| |
| ******************************************************************/ |
| |
| // Defines WEBRTC_ARCH_BIG_ENDIAN, used below. |
| #include "rtc_base/system/arch.h" |
| |
| #include "modules/audio_coding/codecs/ilbc/defines.h" |
| #include "modules/audio_coding/codecs/ilbc/simple_lsf_dequant.h" |
| #include "modules/audio_coding/codecs/ilbc/decoder_interpolate_lsf.h" |
| #include "modules/audio_coding/codecs/ilbc/index_conv_dec.h" |
| #include "modules/audio_coding/codecs/ilbc/do_plc.h" |
| #include "modules/audio_coding/codecs/ilbc/constants.h" |
| #include "modules/audio_coding/codecs/ilbc/enhancer_interface.h" |
| #include "modules/audio_coding/codecs/ilbc/xcorr_coef.h" |
| #include "modules/audio_coding/codecs/ilbc/lsf_check.h" |
| #include "modules/audio_coding/codecs/ilbc/decode_residual.h" |
| #include "modules/audio_coding/codecs/ilbc/unpack_bits.h" |
| #include "modules/audio_coding/codecs/ilbc/hp_output.h" |
| #include "modules/audio_coding/codecs/ilbc/init_decode.h" |
| #ifndef WEBRTC_ARCH_BIG_ENDIAN |
| #include "modules/audio_coding/codecs/ilbc/swap_bytes.h" |
| #endif |
| |
| /*----------------------------------------------------------------* |
| * main decoder function |
| *---------------------------------------------------------------*/ |
| |
| int WebRtcIlbcfix_DecodeImpl( |
| int16_t *decblock, /* (o) decoded signal block */ |
| const uint16_t *bytes, /* (i) encoded signal bits */ |
| IlbcDecoder *iLBCdec_inst, /* (i/o) the decoder state |
| structure */ |
| int16_t mode /* (i) 0: bad packet, PLC, |
| 1: normal */ |
| ) { |
| const int old_mode = iLBCdec_inst->mode; |
| const int old_use_enhancer = iLBCdec_inst->use_enhancer; |
| |
| size_t i; |
| int16_t order_plus_one; |
| |
| int16_t last_bit; |
| int16_t *data; |
| /* Stack based */ |
| int16_t decresidual[BLOCKL_MAX]; |
| int16_t PLCresidual[BLOCKL_MAX + LPC_FILTERORDER]; |
| int16_t syntdenum[NSUB_MAX*(LPC_FILTERORDER+1)]; |
| int16_t PLClpc[LPC_FILTERORDER + 1]; |
| #ifndef WEBRTC_ARCH_BIG_ENDIAN |
| uint16_t swapped[NO_OF_WORDS_30MS]; |
| #endif |
| iLBC_bits *iLBCbits_inst = (iLBC_bits*)PLCresidual; |
| |
| /* Reuse some buffers that are non overlapping in order to save stack memory */ |
| data = &PLCresidual[LPC_FILTERORDER]; |
| |
| if (mode) { /* the data are good */ |
| |
| /* decode data */ |
| |
| /* Unpacketize bits into parameters */ |
| |
| #ifndef WEBRTC_ARCH_BIG_ENDIAN |
| WebRtcIlbcfix_SwapBytes(bytes, iLBCdec_inst->no_of_words, swapped); |
| last_bit = WebRtcIlbcfix_UnpackBits(swapped, iLBCbits_inst, iLBCdec_inst->mode); |
| #else |
| last_bit = WebRtcIlbcfix_UnpackBits(bytes, iLBCbits_inst, iLBCdec_inst->mode); |
| #endif |
| |
| /* Check for bit errors */ |
| if (iLBCbits_inst->startIdx<1) |
| mode = 0; |
| if ((iLBCdec_inst->mode==20) && (iLBCbits_inst->startIdx>3)) |
| mode = 0; |
| if ((iLBCdec_inst->mode==30) && (iLBCbits_inst->startIdx>5)) |
| mode = 0; |
| if (last_bit==1) |
| mode = 0; |
| |
| if (mode) { /* No bit errors was detected, continue decoding */ |
| /* Stack based */ |
| int16_t lsfdeq[LPC_FILTERORDER*LPC_N_MAX]; |
| int16_t weightdenum[(LPC_FILTERORDER + 1)*NSUB_MAX]; |
| |
| /* adjust index */ |
| WebRtcIlbcfix_IndexConvDec(iLBCbits_inst->cb_index); |
| |
| /* decode the lsf */ |
| WebRtcIlbcfix_SimpleLsfDeQ(lsfdeq, (int16_t*)(iLBCbits_inst->lsf), iLBCdec_inst->lpc_n); |
| WebRtcIlbcfix_LsfCheck(lsfdeq, LPC_FILTERORDER, iLBCdec_inst->lpc_n); |
| WebRtcIlbcfix_DecoderInterpolateLsp(syntdenum, weightdenum, |
| lsfdeq, LPC_FILTERORDER, iLBCdec_inst); |
| |
| /* Decode the residual using the cb and gain indexes */ |
| if (!WebRtcIlbcfix_DecodeResidual(iLBCdec_inst, iLBCbits_inst, |
| decresidual, syntdenum)) |
| goto error; |
| |
| /* preparing the plc for a future loss! */ |
| WebRtcIlbcfix_DoThePlc( |
| PLCresidual, PLClpc, 0, decresidual, |
| syntdenum + (LPC_FILTERORDER + 1) * (iLBCdec_inst->nsub - 1), |
| iLBCdec_inst->last_lag, iLBCdec_inst); |
| |
| /* Use the output from doThePLC */ |
| WEBRTC_SPL_MEMCPY_W16(decresidual, PLCresidual, iLBCdec_inst->blockl); |
| } |
| |
| } |
| |
| if (mode == 0) { |
| /* the data is bad (either a PLC call |
| * was made or a bit error was detected) |
| */ |
| |
| /* packet loss conceal */ |
| |
| WebRtcIlbcfix_DoThePlc(PLCresidual, PLClpc, 1, decresidual, syntdenum, |
| iLBCdec_inst->last_lag, iLBCdec_inst); |
| |
| WEBRTC_SPL_MEMCPY_W16(decresidual, PLCresidual, iLBCdec_inst->blockl); |
| |
| order_plus_one = LPC_FILTERORDER + 1; |
| |
| for (i = 0; i < iLBCdec_inst->nsub; i++) { |
| WEBRTC_SPL_MEMCPY_W16(syntdenum+(i*order_plus_one), |
| PLClpc, order_plus_one); |
| } |
| } |
| |
| if ((*iLBCdec_inst).use_enhancer == 1) { /* Enhancer activated */ |
| |
| /* Update the filter and filter coefficients if there was a packet loss */ |
| if (iLBCdec_inst->prev_enh_pl==2) { |
| for (i=0;i<iLBCdec_inst->nsub;i++) { |
| WEBRTC_SPL_MEMCPY_W16(&(iLBCdec_inst->old_syntdenum[i*(LPC_FILTERORDER+1)]), |
| syntdenum, (LPC_FILTERORDER+1)); |
| } |
| } |
| |
| /* post filtering */ |
| (*iLBCdec_inst).last_lag = |
| WebRtcIlbcfix_EnhancerInterface(data, decresidual, iLBCdec_inst); |
| |
| /* synthesis filtering */ |
| |
| /* Set up the filter state */ |
| WEBRTC_SPL_MEMCPY_W16(&data[-LPC_FILTERORDER], iLBCdec_inst->syntMem, LPC_FILTERORDER); |
| |
| if (iLBCdec_inst->mode==20) { |
| /* Enhancer has 40 samples delay */ |
| i=0; |
| WebRtcSpl_FilterARFastQ12( |
| data, data, |
| iLBCdec_inst->old_syntdenum + (i+iLBCdec_inst->nsub-1)*(LPC_FILTERORDER+1), |
| LPC_FILTERORDER+1, SUBL); |
| |
| for (i=1; i < iLBCdec_inst->nsub; i++) { |
| WebRtcSpl_FilterARFastQ12( |
| data+i*SUBL, data+i*SUBL, |
| syntdenum+(i-1)*(LPC_FILTERORDER+1), |
| LPC_FILTERORDER+1, SUBL); |
| } |
| |
| } else if (iLBCdec_inst->mode==30) { |
| /* Enhancer has 80 samples delay */ |
| for (i=0; i < 2; i++) { |
| WebRtcSpl_FilterARFastQ12( |
| data+i*SUBL, data+i*SUBL, |
| iLBCdec_inst->old_syntdenum + (i+4)*(LPC_FILTERORDER+1), |
| LPC_FILTERORDER+1, SUBL); |
| } |
| for (i=2; i < iLBCdec_inst->nsub; i++) { |
| WebRtcSpl_FilterARFastQ12( |
| data+i*SUBL, data+i*SUBL, |
| syntdenum+(i-2)*(LPC_FILTERORDER+1), |
| LPC_FILTERORDER+1, SUBL); |
| } |
| } |
| |
| /* Save the filter state */ |
| WEBRTC_SPL_MEMCPY_W16(iLBCdec_inst->syntMem, &data[iLBCdec_inst->blockl-LPC_FILTERORDER], LPC_FILTERORDER); |
| |
| } else { /* Enhancer not activated */ |
| size_t lag; |
| |
| /* Find last lag (since the enhancer is not called to give this info) */ |
| lag = 20; |
| if (iLBCdec_inst->mode==20) { |
| lag = WebRtcIlbcfix_XcorrCoef( |
| &decresidual[iLBCdec_inst->blockl-60], |
| &decresidual[iLBCdec_inst->blockl-60-lag], |
| 60, |
| 80, lag, -1); |
| } else { |
| lag = WebRtcIlbcfix_XcorrCoef( |
| &decresidual[iLBCdec_inst->blockl-ENH_BLOCKL], |
| &decresidual[iLBCdec_inst->blockl-ENH_BLOCKL-lag], |
| ENH_BLOCKL, |
| 100, lag, -1); |
| } |
| |
| /* Store lag (it is needed if next packet is lost) */ |
| (*iLBCdec_inst).last_lag = lag; |
| |
| /* copy data and run synthesis filter */ |
| WEBRTC_SPL_MEMCPY_W16(data, decresidual, iLBCdec_inst->blockl); |
| |
| /* Set up the filter state */ |
| WEBRTC_SPL_MEMCPY_W16(&data[-LPC_FILTERORDER], iLBCdec_inst->syntMem, LPC_FILTERORDER); |
| |
| for (i=0; i < iLBCdec_inst->nsub; i++) { |
| WebRtcSpl_FilterARFastQ12( |
| data+i*SUBL, data+i*SUBL, |
| syntdenum + i*(LPC_FILTERORDER+1), |
| LPC_FILTERORDER+1, SUBL); |
| } |
| |
| /* Save the filter state */ |
| WEBRTC_SPL_MEMCPY_W16(iLBCdec_inst->syntMem, &data[iLBCdec_inst->blockl-LPC_FILTERORDER], LPC_FILTERORDER); |
| } |
| |
| WEBRTC_SPL_MEMCPY_W16(decblock,data,iLBCdec_inst->blockl); |
| |
| /* High pass filter the signal (with upscaling a factor 2 and saturation) */ |
| WebRtcIlbcfix_HpOutput(decblock, (int16_t*)WebRtcIlbcfix_kHpOutCoefs, |
| iLBCdec_inst->hpimemy, iLBCdec_inst->hpimemx, |
| iLBCdec_inst->blockl); |
| |
| WEBRTC_SPL_MEMCPY_W16(iLBCdec_inst->old_syntdenum, |
| syntdenum, iLBCdec_inst->nsub*(LPC_FILTERORDER+1)); |
| |
| iLBCdec_inst->prev_enh_pl=0; |
| |
| if (mode==0) { /* PLC was used */ |
| iLBCdec_inst->prev_enh_pl=1; |
| } |
| |
| return 0; // Success. |
| |
| error: |
| // The decoder got sick from eating that data. Reset it and return. |
| WebRtcIlbcfix_InitDecode(iLBCdec_inst, old_mode, old_use_enhancer); |
| return -1; // Error |
| } |