| /* | |
| * 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 | |
| ******************************************************************/ | |
| #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 | |
| } |