From 6f12fff925188ced26e518cd2252aff3e93bb04e Mon Sep 17 00:00:00 2001 From: Alexander Gutkin Date: Mon, 20 Aug 2012 16:27:22 +0100 Subject: [PATCH] Added iSAC coder. - Imported the floating point implementation of iSAC coder from stable public webRTC release: http://code.google.com/p/webrtc/source/browse/#svn%2Fstable - Added a reminder (in a TODO file) to switch from floating point to fixed point implementation. Please note that this is the minimal amount of functionality we (the speech text-to-speech team) require for delivering our unit selection algorithms for the Glass project. I'd be happy to address any comments you have. Change-Id: I20481680786ec5372258efcea69ea5c9750a321a --- Android.mk | 27 + TODO | 3 + .../codecs/isac/main/interface/isac.h | 729 ++++++ .../codecs/isac/main/source/Android.mk | 66 + .../codecs/isac/main/source/arith_routines.c | 60 + .../codecs/isac/main/source/arith_routines.h | 63 + .../isac/main/source/arith_routines_hist.c | 291 +++ .../isac/main/source/arith_routines_logist.c | 294 +++ .../isac/main/source/bandwidth_estimator.c | 1020 ++++++++ .../isac/main/source/bandwidth_estimator.h | 177 ++ .../codecs/isac/main/source/codec.h | 217 ++ .../codecs/isac/main/source/crc.c | 110 + .../codecs/isac/main/source/crc.h | 46 + .../codecs/isac/main/source/decode.c | 299 +++ .../codecs/isac/main/source/decode_bwe.c | 88 + .../codecs/isac/main/source/encode.c | 1252 +++++++++ .../codecs/isac/main/source/encode_lpc_swb.c | 708 +++++ .../codecs/isac/main/source/encode_lpc_swb.h | 283 ++ .../codecs/isac/main/source/entropy_coding.c | 2066 +++++++++++++++ .../codecs/isac/main/source/entropy_coding.h | 341 +++ .../codecs/isac/main/source/fft.c | 947 +++++++ .../codecs/isac/main/source/fft.h | 45 + .../isac/main/source/filter_functions.c | 271 ++ .../isac/main/source/filterbank_tables.c | 37 + .../isac/main/source/filterbank_tables.h | 46 + .../codecs/isac/main/source/filterbanks.c | 346 +++ .../codecs/isac/main/source/intialize.c | 175 ++ .../codecs/isac/main/source/isac.c | 2313 +++++++++++++++++ .../codecs/isac/main/source/isac.gypi | 91 + .../codecs/isac/main/source/lattice.c | 217 ++ .../codecs/isac/main/source/lpc_analysis.c | 535 ++++ .../codecs/isac/main/source/lpc_analysis.h | 50 + .../isac/main/source/lpc_gain_swb_tables.c | 137 + .../isac/main/source/lpc_gain_swb_tables.h | 49 + .../isac/main/source/lpc_shape_swb12_tables.c | 159 ++ .../isac/main/source/lpc_shape_swb12_tables.h | 65 + .../isac/main/source/lpc_shape_swb16_tables.c | 248 ++ .../isac/main/source/lpc_shape_swb16_tables.h | 79 + .../codecs/isac/main/source/lpc_tables.c | 601 +++++ .../codecs/isac/main/source/lpc_tables.h | 100 + .../isac/main/source/os_specific_inline.h | 42 + .../codecs/isac/main/source/pitch_estimator.c | 622 +++++ .../codecs/isac/main/source/pitch_estimator.h | 71 + .../codecs/isac/main/source/pitch_filter.c | 383 +++ .../isac/main/source/pitch_gain_tables.c | 105 + .../isac/main/source/pitch_gain_tables.h | 45 + .../isac/main/source/pitch_lag_tables.c | 277 ++ .../isac/main/source/pitch_lag_tables.h | 114 + .../codecs/isac/main/source/settings.h | 205 ++ .../main/source/spectrum_ar_model_tables.c | 138 + .../main/source/spectrum_ar_model_tables.h | 76 + .../codecs/isac/main/source/structs.h | 477 ++++ .../codecs/isac/main/source/transform.c | 131 + 53 files changed, 17337 insertions(+) create mode 100644 TODO create mode 100644 src/modules/audio_coding/codecs/isac/main/interface/isac.h create mode 100644 src/modules/audio_coding/codecs/isac/main/source/Android.mk create mode 100644 src/modules/audio_coding/codecs/isac/main/source/arith_routines.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/arith_routines.h create mode 100644 src/modules/audio_coding/codecs/isac/main/source/arith_routines_hist.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/arith_routines_logist.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h create mode 100644 src/modules/audio_coding/codecs/isac/main/source/codec.h create mode 100644 src/modules/audio_coding/codecs/isac/main/source/crc.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/crc.h create mode 100644 src/modules/audio_coding/codecs/isac/main/source/decode.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/decode_bwe.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/encode.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.h create mode 100644 src/modules/audio_coding/codecs/isac/main/source/entropy_coding.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/entropy_coding.h create mode 100644 src/modules/audio_coding/codecs/isac/main/source/fft.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/fft.h create mode 100644 src/modules/audio_coding/codecs/isac/main/source/filter_functions.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/filterbank_tables.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/filterbank_tables.h create mode 100644 src/modules/audio_coding/codecs/isac/main/source/filterbanks.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/intialize.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/isac.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/isac.gypi create mode 100644 src/modules/audio_coding/codecs/isac/main/source/lattice.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/lpc_analysis.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/lpc_analysis.h create mode 100644 src/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h create mode 100644 src/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h create mode 100644 src/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h create mode 100644 src/modules/audio_coding/codecs/isac/main/source/lpc_tables.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/lpc_tables.h create mode 100644 src/modules/audio_coding/codecs/isac/main/source/os_specific_inline.h create mode 100644 src/modules/audio_coding/codecs/isac/main/source/pitch_estimator.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/pitch_estimator.h create mode 100644 src/modules/audio_coding/codecs/isac/main/source/pitch_filter.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.h create mode 100644 src/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.h create mode 100644 src/modules/audio_coding/codecs/isac/main/source/settings.h create mode 100644 src/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.c create mode 100644 src/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.h create mode 100644 src/modules/audio_coding/codecs/isac/main/source/structs.h create mode 100644 src/modules/audio_coding/codecs/isac/main/source/transform.c diff --git a/Android.mk b/Android.mk index dc214e9768..a6e7a49671 100644 --- a/Android.mk +++ b/Android.mk @@ -20,6 +20,7 @@ include $(MY_WEBRTC_ROOT_PATH)/src/modules/audio_processing/ns/Android.mk include $(MY_WEBRTC_ROOT_PATH)/src/modules/audio_processing/utility/Android.mk #include $(MY_WEBRTC_ROOT_PATH)/src/modules/utility/source/Android.mk include $(MY_WEBRTC_ROOT_PATH)/src/system_wrappers/source/Android.mk +include $(MY_WEBRTC_ROOT_PATH)/src/modules/audio_coding/codecs/isac/main/source/Android.mk # build .so LOCAL_PATH := $(call my-dir) @@ -65,3 +66,29 @@ include external/stlport/libstlport.mk endif include $(BUILD_SHARED_LIBRARY) +include $(CLEAR_VARS) +include $(LOCAL_PATH)/../../external/webrtc/android-webrtc.mk + +LOCAL_ARM_MODE := arm +LOCAL_MODULE := libwebrtc_audio_coding +LOCAL_MODULE_TAGS := optional + +LOCAL_WHOLE_STATIC_LIBRARIES := \ + libwebrtc_isac \ + libwebrtc_spl \ + libwebrtc_system_wrappers + +LOCAL_STATIC_LIBRARIES := \ + libprotobuf-cpp-2.3.0-lite + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libdl \ + libstlport + +LOCAL_PRELINK_MODULE := false + +ifndef NDK_ROOT +include external/stlport/libstlport.mk +endif +include $(BUILD_SHARED_LIBRARY) diff --git a/TODO b/TODO new file mode 100644 index 0000000000..a5f997a353 --- /dev/null +++ b/TODO @@ -0,0 +1,3 @@ +Alexander Gutkin : Switch the iSAC codec to be + fixed rather than floating point. The current code uses floating + point implementation for purely experimental reasons. diff --git a/src/modules/audio_coding/codecs/isac/main/interface/isac.h b/src/modules/audio_coding/codecs/isac/main/interface/isac.h new file mode 100644 index 0000000000..03c260bb8a --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/interface/isac.h @@ -0,0 +1,729 @@ +/* + * 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. + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INTERFACE_ISAC_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INTERFACE_ISAC_H_ + +/* + * Define the fixed-point numeric formats + */ +#include "typedefs.h" + +typedef struct WebRtcISACStruct ISACStruct; + +enum IsacSamplingRate {kIsacWideband = 16, kIsacSuperWideband = 32}; + + +#if defined(__cplusplus) +extern "C" { +#endif + + /****************************************************************************** + * WebRtcIsac_AssignSize(...) + * + * This function returns the size of the ISAC instance, so that the instance + * can be created outside iSAC. + * + * Input: + * - samplingRate : sampling rate of the input/output audio. + * + * Output: + * - sizeinbytes : number of bytes needed to allocate for the + * instance. + * + * Return value : 0 - Ok + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsac_AssignSize( + int* sizeinbytes); + + + /****************************************************************************** + * WebRtcIsac_Assign(...) + * + * This function assignes the memory already created to the ISAC instance. + * + * Input: + * - *ISAC_main_inst : a pointer to the coder instance. + * - samplingRate : sampling rate of the input/output audio. + * - ISAC_inst_Addr : the already allocated memory, where we put the + * iSAC structure. + * + * Return value : 0 - Ok + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsac_Assign( + ISACStruct** ISAC_main_inst, + void* ISAC_inst_Addr); + + + /****************************************************************************** + * WebRtcIsac_Create(...) + * + * This function creates an ISAC instance, which will contain the state + * information for one coding/decoding channel. + * + * Input: + * - *ISAC_main_inst : a pointer to the coder instance. + * + * Return value : 0 - Ok + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsac_Create( + ISACStruct** ISAC_main_inst); + + + /****************************************************************************** + * WebRtcIsac_Free(...) + * + * This function frees the ISAC instance created at the beginning. + * + * Input: + * - ISAC_main_inst : an ISAC instance. + * + * Return value : 0 - Ok + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsac_Free( + ISACStruct* ISAC_main_inst); + + + /****************************************************************************** + * WebRtcIsac_EncoderInit(...) + * + * This function initializes an ISAC instance prior to the encoder calls. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - CodingMode : 0 -> Bit rate and frame length are + * automatically adjusted to available bandwidth + * on transmission channel, just valid if codec + * is created to work in wideband mode. + * 1 -> User sets a frame length and a target bit + * rate which is taken as the maximum + * short-term average bit rate. + * + * Return value : 0 - Ok + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsac_EncoderInit( + ISACStruct* ISAC_main_inst, + WebRtc_Word16 CodingMode); + + + /****************************************************************************** + * WebRtcIsac_Encode(...) + * + * This function encodes 10ms audio blocks and inserts it into a package. + * Input speech length has 160 samples if operating at 16 kHz sampling + * rate, or 320 if operating at 32 kHz sampling rate. The encoder buffers the + * input audio until the whole frame is buffered then proceeds with encoding. + * + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - speechIn : input speech vector. + * + * Output: + * - encoded : the encoded data vector + * + * Return value: + * : >0 - Length (in bytes) of coded data + * : 0 - The buffer didn't reach the chosen + * frame-size so it keeps buffering speech + * samples. + * : -1 - Error + */ + + WebRtc_Word16 WebRtcIsac_Encode( + ISACStruct* ISAC_main_inst, + const WebRtc_Word16* speechIn, + WebRtc_Word16* encoded); + + + /****************************************************************************** + * WebRtcIsac_DecoderInit(...) + * + * This function initializes an ISAC instance prior to the decoder calls. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * + * Return value + * : 0 - Ok + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsac_DecoderInit( + ISACStruct* ISAC_main_inst); + + + /****************************************************************************** + * WebRtcIsac_UpdateBwEstimate(...) + * + * This function updates the estimate of the bandwidth. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - encoded : encoded ISAC frame(s). + * - packet_size : size of the packet. + * - rtp_seq_number : the RTP number of the packet. + * - send_ts : the RTP send timestamp, given in samples + * - arr_ts : the arrival time of the packet (from NetEq) + * in samples. + * + * Return value : 0 - Ok + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsac_UpdateBwEstimate( + ISACStruct* ISAC_main_inst, + const WebRtc_UWord16* encoded, + WebRtc_Word32 packet_size, + WebRtc_UWord16 rtp_seq_number, + WebRtc_UWord32 send_ts, + WebRtc_UWord32 arr_ts); + + + /****************************************************************************** + * WebRtcIsac_Decode(...) + * + * This function decodes an ISAC frame. At 16 kHz sampling rate, the length + * of the output audio could be either 480 or 960 samples, equivalent to + * 30 or 60 ms respectively. At 32 kHz sampling rate, the length of the + * output audio is 960 samples, which is 30 ms. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - encoded : encoded ISAC frame(s). + * - len : bytes in encoded vector. + * + * Output: + * - decoded : The decoded vector. + * + * Return value : >0 - number of samples in decoded vector. + * -1 - Error. + */ + + WebRtc_Word16 WebRtcIsac_Decode( + ISACStruct* ISAC_main_inst, + const WebRtc_UWord16* encoded, + WebRtc_Word16 len, + WebRtc_Word16* decoded, + WebRtc_Word16* speechType); + + + /****************************************************************************** + * WebRtcIsac_DecodePlc(...) + * + * This function conducts PLC for ISAC frame(s). Output speech length + * will be a multiple of frames, i.e. multiples of 30 ms audio. Therefore, + * the output is multiple of 480 samples if operating at 16 kHz and multiple + * of 960 if operating at 32 kHz. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - noOfLostFrames : Number of PLC frames to produce. + * + * Output: + * - decoded : The decoded vector. + * + * Return value : >0 - number of samples in decoded PLC vector + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsac_DecodePlc( + ISACStruct* ISAC_main_inst, + WebRtc_Word16* decoded, + WebRtc_Word16 noOfLostFrames); + + + /****************************************************************************** + * WebRtcIsac_Control(...) + * + * This function sets the limit on the short-term average bit-rate and the + * frame length. Should be used only in Instantaneous mode. At 16 kHz sampling + * rate, an average bit-rate between 10000 to 32000 bps is valid and a + * frame-size of 30 or 60 ms is acceptable. At 32 kHz, an average bit-rate + * between 10000 to 56000 is acceptable, and the valid frame-size is 30 ms. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - rate : limit on the short-term average bit rate, + * in bits/second. + * - framesize : frame-size in millisecond. + * + * Return value : 0 - ok + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsac_Control( + ISACStruct* ISAC_main_inst, + WebRtc_Word32 rate, + WebRtc_Word16 framesize); + + + /****************************************************************************** + * WebRtcIsac_ControlBwe(...) + * + * This function sets the initial values of bottleneck and frame-size if + * iSAC is used in channel-adaptive mode. Therefore, this API is not + * applicable if the codec is created to operate in super-wideband mode. + * + * Through this API, users can enforce a frame-size for all values of + * bottleneck. Then iSAC will not automatically change the frame-size. + * + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - rateBPS : initial value of bottleneck in bits/second + * 10000 <= rateBPS <= 56000 is accepted + * For default bottleneck set rateBPS = 0 + * - frameSizeMs : number of milliseconds per frame (30 or 60) + * - enforceFrameSize : 1 to enforce the given frame-size through + * out the adaptation process, 0 to let iSAC + * change the frame-size if required. + * + * Return value : 0 - ok + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsac_ControlBwe( + ISACStruct* ISAC_main_inst, + WebRtc_Word32 rateBPS, + WebRtc_Word16 frameSizeMs, + WebRtc_Word16 enforceFrameSize); + + + /****************************************************************************** + * WebRtcIsac_ReadFrameLen(...) + * + * This function returns the length of the frame represented in the packet. + * + * Input: + * - encoded : Encoded bit-stream + * + * Output: + * - frameLength : Length of frame in packet (in samples) + * + */ + + WebRtc_Word16 WebRtcIsac_ReadFrameLen( + ISACStruct* ISAC_main_inst, + const WebRtc_Word16* encoded, + WebRtc_Word16* frameLength); + + + /****************************************************************************** + * WebRtcIsac_version(...) + * + * This function returns the version number. + * + * Output: + * - version : Pointer to character string + * + */ + + void WebRtcIsac_version( + char *version); + + + /****************************************************************************** + * WebRtcIsac_GetErrorCode(...) + * + * This function can be used to check the error code of an iSAC instance. When + * a function returns -1 a error code will be set for that instance. The + * function below extract the code of the last error that occurred in the + * specified instance. + * + * Input: + * - ISAC_main_inst : ISAC instance + * + * Return value : Error code + */ + + WebRtc_Word16 WebRtcIsac_GetErrorCode( + ISACStruct* ISAC_main_inst); + + + /**************************************************************************** + * WebRtcIsac_GetUplinkBw(...) + * + * This function outputs the target bottleneck of the codec. In + * channel-adaptive mode, the target bottleneck is specified through in-band + * signalling retreived by bandwidth estimator. + * In channel-independent, also called instantaneous mode, the target + * bottleneck is provided to the encoder by calling xxx_control(...). If + * xxx_control is never called the default values is returned. The default + * value for bottleneck at 16 kHz encoder sampling rate is 32000 bits/sec, + * and it is 56000 bits/sec for 32 kHz sampling rate. + * Note that the output is the iSAC internal operating bottleneck which might + * differ slightly from the one provided through xxx_control(). + * + * Input: + * - ISAC_main_inst : iSAC instance + * + * Output: + * - *bottleneck : bottleneck in bits/sec + * + * Return value : -1 if error happens + * 0 bit-rates computed correctly. + */ + + WebRtc_Word16 WebRtcIsac_GetUplinkBw( + ISACStruct* ISAC_main_inst, + WebRtc_Word32* bottleneck); + + + /****************************************************************************** + * WebRtcIsac_SetMaxPayloadSize(...) + * + * This function sets a limit for the maximum payload size of iSAC. The same + * value is used both for 30 and 60 ms packets. If the encoder sampling rate + * is 16 kHz the maximum payload size is between 120 and 400 bytes. If the + * encoder sampling rate is 32 kHz the maximum payload size is between 120 + * and 600 bytes. + * + * If an out of range limit is used, the function returns -1, but the closest + * valid value will be applied. + * + * --------------- + * IMPORTANT NOTES + * --------------- + * The size of a packet is limited to the minimum of 'max-payload-size' and + * 'max-rate.' For instance, let's assume the max-payload-size is set to + * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps + * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms + * frame-size. Then a packet with a frame-size of 30 ms is limited to 150, + * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to + * 170 bytes, i.e. min(170, 300). + * + * Input: + * - ISAC_main_inst : iSAC instance + * - maxPayloadBytes : maximum size of the payload in bytes + * valid values are between 120 and 400 bytes + * if encoder sampling rate is 16 kHz. For + * 32 kHz encoder sampling rate valid values + * are between 120 and 600 bytes. + * + * Return value : 0 if successful + * -1 if error happens + */ + + WebRtc_Word16 WebRtcIsac_SetMaxPayloadSize( + ISACStruct* ISAC_main_inst, + WebRtc_Word16 maxPayloadBytes); + + + /****************************************************************************** + * WebRtcIsac_SetMaxRate(...) + * + * This function sets the maximum rate which the codec may not exceed for + * any signal packet. The maximum rate is defined and payload-size per + * frame-size in bits per second. + * + * The codec has a maximum rate of 53400 bits per second (200 bytes per 30 + * ms) if the encoder sampling rate is 16kHz, and 160 kbps (600 bytes/30 ms) + * if the encoder sampling rate is 32 kHz. + * + * It is possible to set a maximum rate between 32000 and 53400 bits/sec + * in wideband mode, and 32000 to 160000 bits/sec in super-wideband mode. + * + * If an out of range limit is used, the function returns -1, but the closest + * valid value will be applied. + * + * --------------- + * IMPORTANT NOTES + * --------------- + * The size of a packet is limited to the minimum of 'max-payload-size' and + * 'max-rate.' For instance, let's assume the max-payload-size is set to + * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps + * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms + * frame-size. Then a packet with a frame-size of 30 ms is limited to 150, + * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to + * 170 bytes, min(170, 300). + * + * Input: + * - ISAC_main_inst : iSAC instance + * - maxRate : maximum rate in bits per second, + * valid values are 32000 to 53400 bits/sec in + * wideband mode, and 32000 to 160000 bits/sec in + * super-wideband mode. + * + * Return value : 0 if successful + * -1 if error happens + */ + + WebRtc_Word16 WebRtcIsac_SetMaxRate( + ISACStruct* ISAC_main_inst, + WebRtc_Word32 maxRate); + + + /****************************************************************************** + * WebRtcIsac_DecSampRate() + * Return the sampling rate of the decoded audio. + * + * Input: + * - ISAC_main_inst : iSAC instance + * + * Return value : enumerator representing sampling frequency + * associated with the decoder, i.e. the + * sampling rate of the decoded audio. + * + */ + + enum IsacSamplingRate WebRtcIsac_DecSampRate( + ISACStruct* ISAC_main_inst); + + + /****************************************************************************** + * WebRtcIsac_EncSampRate() + * + * Input: + * - ISAC_main_inst : iSAC instance + * + * Return value : enumerator representing sampling frequency + * associated with the encoder, the input audio + * is expected to be sampled at this rate. + * + */ + + enum IsacSamplingRate WebRtcIsac_EncSampRate( + ISACStruct* ISAC_main_inst); + + + /****************************************************************************** + * WebRtcIsac_SetDecSampRate() + * Set the sampling rate of the decoder. Initialization of the decoder WILL + * NOT overwrite the sampling rate of the encoder. The default value is 16 kHz + * which is set when the instance is created. + * + * Input: + * - ISAC_main_inst : iSAC instance + * - sampRate : enumerator specifying the sampling rate. + * + * Return value : 0 if successful + * -1 if failed. + */ + + WebRtc_Word16 WebRtcIsac_SetDecSampRate( + ISACStruct* ISAC_main_inst, + enum IsacSamplingRate sampRate); + + + /****************************************************************************** + * WebRtcIsac_SetEncSampRate() + * Set the sampling rate of the encoder. Initialization of the encoder WILL + * NOT overwrite the sampling rate of the encoder. The default value is 16 kHz + * which is set when the instance is created. The encoding-mode and the + * bottleneck remain unchanged by this call, however, the maximum rate and + * maximum payload-size will reset to their default value. + * + * Input: + * - ISAC_main_inst : iSAC instance + * - sampRate : enumerator specifying the sampling rate. + * + * Return value : 0 if successful + * -1 if failed. + */ + + WebRtc_Word16 WebRtcIsac_SetEncSampRate( + ISACStruct* ISAC_main_inst, + enum IsacSamplingRate sampRate); + + + + /****************************************************************************** + * WebRtcIsac_GetNewBitStream(...) + * + * This function returns encoded data, with the recieved bwe-index in the + * stream. If the rate is set to a value less than bottleneck of codec + * the new bistream will be re-encoded with the given target rate. + * It should always return a complete packet, i.e. only called once + * even for 60 msec frames. + * + * NOTE 1! This function does not write in the ISACStruct, it is not allowed. + * NOTE 2! Currently not implemented for SWB mode. + * NOTE 3! Rates larger than the bottleneck of the codec will be limited + * to the current bottleneck. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - bweIndex : Index of bandwidth estimate to put in new + * bitstream + * - rate : target rate of the transcoder is bits/sec. + * Valid values are the accepted rate in iSAC, + * i.e. 10000 to 56000. + * - isRCU : if the new bit-stream is an RCU stream. + * Note that the rate parameter always indicates + * the target rate of the main paylaod, regardless + * of 'isRCU' value. + * + * Output: + * - encoded : The encoded data vector + * + * Return value : >0 - Length (in bytes) of coded data + * -1 - Error or called in SWB mode + * NOTE! No error code is written to + * the struct since it is only allowed to read + * the struct. + */ + WebRtc_Word16 WebRtcIsac_GetNewBitStream( + ISACStruct* ISAC_main_inst, + WebRtc_Word16 bweIndex, + WebRtc_Word16 jitterInfo, + WebRtc_Word32 rate, + WebRtc_Word16* encoded, + WebRtc_Word16 isRCU); + + + + /**************************************************************************** + * WebRtcIsac_GetDownLinkBwIndex(...) + * + * This function returns index representing the Bandwidth estimate from + * other side to this side. + * + * Input: + * - ISAC_main_inst : iSAC struct + * + * Output: + * - bweIndex : Bandwidth estimate to transmit to other side. + * + */ + + WebRtc_Word16 WebRtcIsac_GetDownLinkBwIndex( + ISACStruct* ISAC_main_inst, + WebRtc_Word16* bweIndex, + WebRtc_Word16* jitterInfo); + + + /**************************************************************************** + * WebRtcIsac_UpdateUplinkBw(...) + * + * This function takes an index representing the Bandwidth estimate from + * this side to other side and updates BWE. + * + * Input: + * - ISAC_main_inst : iSAC struct + * - bweIndex : Bandwidth estimate from other side. + * + */ + + WebRtc_Word16 WebRtcIsac_UpdateUplinkBw( + ISACStruct* ISAC_main_inst, + WebRtc_Word16 bweIndex); + + + /**************************************************************************** + * WebRtcIsac_ReadBwIndex(...) + * + * This function returns the index of the Bandwidth estimate from the bitstream. + * + * Input: + * - encoded : Encoded bitstream + * + * Output: + * - frameLength : Length of frame in packet (in samples) + * - bweIndex : Bandwidth estimate in bitstream + * + */ + + WebRtc_Word16 WebRtcIsac_ReadBwIndex( + const WebRtc_Word16* encoded, + WebRtc_Word16* bweIndex); + + + + /******************************************************************************* + * WebRtcIsac_GetNewFrameLen(...) + * + * returns the frame lenght (in samples) of the next packet. In the case of channel-adaptive + * mode, iSAC decides on its frame lenght based on the estimated bottleneck + * this allows a user to prepare for the next packet (at the encoder) + * + * The primary usage is in CE to make the iSAC works in channel-adaptive mode + * + * Input: + * - ISAC_main_inst : iSAC struct + * + * Return Value : frame lenght in samples + * + */ + + WebRtc_Word16 WebRtcIsac_GetNewFrameLen( + ISACStruct* ISAC_main_inst); + + + /**************************************************************************** + * WebRtcIsac_GetRedPayload(...) + * + * Populates "encoded" with the redundant payload of the recently encoded + * frame. This function has to be called once that WebRtcIsac_Encode(...) + * returns a positive value. Regardless of the frame-size this function will + * be called only once after encoding is completed. + * + * Input: + * - ISAC_main_inst : iSAC struct + * + * Output: + * - encoded : the encoded data vector + * + * + * Return value: + * : >0 - Length (in bytes) of coded data + * : -1 - Error + * + * + */ + WebRtc_Word16 WebRtcIsac_GetRedPayload( + ISACStruct* ISAC_main_inst, + WebRtc_Word16* encoded); + + + /**************************************************************************** + * WebRtcIsac_DecodeRcu(...) + * + * This function decodes a redundant (RCU) iSAC frame. Function is called in + * NetEq with a stored RCU payload i case of packet loss. Output speech length + * will be a multiple of 480 samples: 480 or 960 samples, + * depending on the framesize (30 or 60 ms). + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - encoded : encoded ISAC RCU frame(s) + * - len : bytes in encoded vector + * + * Output: + * - decoded : The decoded vector + * + * Return value : >0 - number of samples in decoded vector + * -1 - Error + */ + WebRtc_Word16 WebRtcIsac_DecodeRcu( + ISACStruct* ISAC_main_inst, + const WebRtc_UWord16* encoded, + WebRtc_Word16 len, + WebRtc_Word16* decoded, + WebRtc_Word16* speechType); + + +#if defined(__cplusplus) +} +#endif + + + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INTERFACE_ISAC_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/main/source/Android.mk b/src/modules/audio_coding/codecs/isac/main/source/Android.mk new file mode 100644 index 0000000000..07b2a314b5 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/Android.mk @@ -0,0 +1,66 @@ +# 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. + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +include $(LOCAL_PATH)/../../../../../../../android-webrtc.mk + +LOCAL_ARM_MODE := arm +LOCAL_MODULE_CLASS := STATIC_LIBRARIES +LOCAL_MODULE := libwebrtc_isac +LOCAL_MODULE_TAGS := optional +LOCAL_SRC_FILES := \ + arith_routines.c \ + arith_routines_hist.c \ + arith_routines_logist.c \ + bandwidth_estimator.c \ + crc.c \ + decode.c \ + decode_bwe.c \ + encode.c \ + encode_lpc_swb.c \ + entropy_coding.c \ + fft.c \ + filter_functions.c \ + filterbank_tables.c \ + intialize.c \ + isac.c \ + filterbanks.c \ + pitch_lag_tables.c \ + lattice.c \ + lpc_gain_swb_tables.c \ + lpc_analysis.c \ + lpc_shape_swb12_tables.c \ + lpc_shape_swb16_tables.c \ + lpc_tables.c \ + pitch_estimator.c \ + pitch_filter.c \ + pitch_gain_tables.c \ + spectrum_ar_model_tables.c \ + transform.c + +# Flags passed to both C and C++ files. +LOCAL_CFLAGS := \ + $(MY_WEBRTC_COMMON_DEFS) + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/../interface \ + $(LOCAL_PATH)/../../../../../.. \ + $(LOCAL_PATH)/../../../../../../common_audio/signal_processing/include + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libdl \ + libstlport + +ifndef NDK_ROOT +include external/stlport/libstlport.mk +endif +include $(BUILD_STATIC_LIBRARY) diff --git a/src/modules/audio_coding/codecs/isac/main/source/arith_routines.c b/src/modules/audio_coding/codecs/isac/main/source/arith_routines.c new file mode 100644 index 0000000000..31c441a7af --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/arith_routines.c @@ -0,0 +1,60 @@ +/* + * 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. + */ + +#include "arith_routines.h" +#include "settings.h" + + +/* + * terminate and return byte stream; + * returns the number of bytes in the stream + */ +int WebRtcIsac_EncTerminate(Bitstr *streamdata) /* in-/output struct containing bitstream */ +{ + WebRtc_UWord8 *stream_ptr; + + + /* point to the right place in the stream buffer */ + stream_ptr = streamdata->stream + streamdata->stream_index; + + /* find minimum length (determined by current interval width) */ + if ( streamdata->W_upper > 0x01FFFFFF ) + { + streamdata->streamval += 0x01000000; + /* add carry to buffer */ + if (streamdata->streamval < 0x01000000) + { + /* propagate carry */ + while ( !(++(*--stream_ptr)) ); + /* put pointer back to the old value */ + stream_ptr = streamdata->stream + streamdata->stream_index; + } + /* write remaining data to bitstream */ + *stream_ptr++ = (WebRtc_UWord8) (streamdata->streamval >> 24); + } + else + { + streamdata->streamval += 0x00010000; + /* add carry to buffer */ + if (streamdata->streamval < 0x00010000) + { + /* propagate carry */ + while ( !(++(*--stream_ptr)) ); + /* put pointer back to the old value */ + stream_ptr = streamdata->stream + streamdata->stream_index; + } + /* write remaining data to bitstream */ + *stream_ptr++ = (WebRtc_UWord8) (streamdata->streamval >> 24); + *stream_ptr++ = (WebRtc_UWord8) ((streamdata->streamval >> 16) & 0x00FF); + } + + /* calculate stream length */ + return (int)(stream_ptr - streamdata->stream); +} diff --git a/src/modules/audio_coding/codecs/isac/main/source/arith_routines.h b/src/modules/audio_coding/codecs/isac/main/source/arith_routines.h new file mode 100644 index 0000000000..8e5f496f98 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/arith_routines.h @@ -0,0 +1,63 @@ +/* + * 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. + */ + +/* + * arith_routines.h + * + * Functions for arithmetic coding. + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ARITH_ROUTINES_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ARITH_ROUTINES_H_ + +#include "structs.h" + + +int WebRtcIsac_EncLogisticMulti2( + Bitstr *streamdata, /* in-/output struct containing bitstream */ + WebRtc_Word16 *dataQ7, /* input: data vector */ + const WebRtc_UWord16 *env, /* input: side info vector defining the width of the pdf */ + const int N, /* input: data vector length */ + const WebRtc_Word16 isSWB12kHz); /* if the codec is working in 12kHz bandwidth */ + +/* returns the number of bytes in the stream */ +int WebRtcIsac_EncTerminate(Bitstr *streamdata); /* in-/output struct containing bitstream */ + +/* returns the number of bytes in the stream so far */ +int WebRtcIsac_DecLogisticMulti2( + WebRtc_Word16 *data, /* output: data vector */ + Bitstr *streamdata, /* in-/output struct containing bitstream */ + const WebRtc_UWord16 *env, /* input: side info vector defining the width of the pdf */ + const WebRtc_Word16 *dither, /* input: dither vector */ + const int N, /* input: data vector length */ + const WebRtc_Word16 isSWB12kHz); /* if the codec is working in 12kHz bandwidth */ + +void WebRtcIsac_EncHistMulti( + Bitstr *streamdata, /* in-/output struct containing bitstream */ + const int *data, /* input: data vector */ + const WebRtc_UWord16 **cdf, /* input: array of cdf arrays */ + const int N); /* input: data vector length */ + +int WebRtcIsac_DecHistBisectMulti( + int *data, /* output: data vector */ + Bitstr *streamdata, /* in-/output struct containing bitstream */ + const WebRtc_UWord16 **cdf, /* input: array of cdf arrays */ + const WebRtc_UWord16 *cdf_size, /* input: array of cdf table sizes+1 (power of two: 2^k) */ + const int N); /* input: data vector length */ + +int WebRtcIsac_DecHistOneStepMulti( + int *data, /* output: data vector */ + Bitstr *streamdata, /* in-/output struct containing bitstream */ + const WebRtc_UWord16 **cdf, /* input: array of cdf arrays */ + const WebRtc_UWord16 *init_index,/* input: vector of initial cdf table search entries */ + const int N); /* input: data vector length */ + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ARITH_ROUTINES_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/main/source/arith_routines_hist.c b/src/modules/audio_coding/codecs/isac/main/source/arith_routines_hist.c new file mode 100644 index 0000000000..f4a13d6078 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/arith_routines_hist.c @@ -0,0 +1,291 @@ +/* + * 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. + */ + +#include "settings.h" +#include "arith_routines.h" + + +/* + * code symbols into arithmetic bytestream + */ +void WebRtcIsac_EncHistMulti(Bitstr *streamdata, /* in-/output struct containing bitstream */ + const int *data, /* input: data vector */ + const WebRtc_UWord16 **cdf, /* input: array of cdf arrays */ + const int N) /* input: data vector length */ +{ + WebRtc_UWord32 W_lower, W_upper; + WebRtc_UWord32 W_upper_LSB, W_upper_MSB; + WebRtc_UWord8 *stream_ptr; + WebRtc_UWord8 *stream_ptr_carry; + WebRtc_UWord32 cdf_lo, cdf_hi; + int k; + + + /* point to beginning of stream buffer */ + stream_ptr = streamdata->stream + streamdata->stream_index; + W_upper = streamdata->W_upper; + + for (k=N; k>0; k--) + { + /* fetch cdf_lower and cdf_upper from cdf tables */ + cdf_lo = (WebRtc_UWord32) *(*cdf + *data); + cdf_hi = (WebRtc_UWord32) *(*cdf++ + *data++ + 1); + + /* update interval */ + W_upper_LSB = W_upper & 0x0000FFFF; + W_upper_MSB = W_upper >> 16; + W_lower = W_upper_MSB * cdf_lo; + W_lower += (W_upper_LSB * cdf_lo) >> 16; + W_upper = W_upper_MSB * cdf_hi; + W_upper += (W_upper_LSB * cdf_hi) >> 16; + + /* shift interval such that it begins at zero */ + W_upper -= ++W_lower; + + /* add integer to bitstream */ + streamdata->streamval += W_lower; + + /* handle carry */ + if (streamdata->streamval < W_lower) + { + /* propagate carry */ + stream_ptr_carry = stream_ptr; + while (!(++(*--stream_ptr_carry))); + } + + /* renormalize interval, store most significant byte of streamval and update streamval */ + while ( !(W_upper & 0xFF000000) ) /* W_upper < 2^24 */ + { + W_upper <<= 8; + *stream_ptr++ = (WebRtc_UWord8) (streamdata->streamval >> 24); + streamdata->streamval <<= 8; + } + } + + /* calculate new stream_index */ + streamdata->stream_index = (int)(stream_ptr - streamdata->stream); + streamdata->W_upper = W_upper; + + return; +} + + + +/* + * function to decode more symbols from the arithmetic bytestream, using method of bisection + * cdf tables should be of size 2^k-1 (which corresponds to an alphabet size of 2^k-2) + */ +int WebRtcIsac_DecHistBisectMulti(int *data, /* output: data vector */ + Bitstr *streamdata, /* in-/output struct containing bitstream */ + const WebRtc_UWord16 **cdf, /* input: array of cdf arrays */ + const WebRtc_UWord16 *cdf_size, /* input: array of cdf table sizes+1 (power of two: 2^k) */ + const int N) /* input: data vector length */ +{ + WebRtc_UWord32 W_lower, W_upper; + WebRtc_UWord32 W_tmp; + WebRtc_UWord32 W_upper_LSB, W_upper_MSB; + WebRtc_UWord32 streamval; + const WebRtc_UWord8 *stream_ptr; + const WebRtc_UWord16 *cdf_ptr; + int size_tmp; + int k; + + W_lower = 0; //to remove warning -DH + stream_ptr = streamdata->stream + streamdata->stream_index; + W_upper = streamdata->W_upper; + if (W_upper == 0) + /* Should not be possible in normal operation */ + return -2; + + if (streamdata->stream_index == 0) /* first time decoder is called for this stream */ + { + /* read first word from bytestream */ + streamval = *stream_ptr << 24; + streamval |= *++stream_ptr << 16; + streamval |= *++stream_ptr << 8; + streamval |= *++stream_ptr; + } else { + streamval = streamdata->streamval; + } + + for (k=N; k>0; k--) + { + /* find the integer *data for which streamval lies in [W_lower+1, W_upper] */ + W_upper_LSB = W_upper & 0x0000FFFF; + W_upper_MSB = W_upper >> 16; + + /* start halfway the cdf range */ + size_tmp = *cdf_size++ >> 1; + cdf_ptr = *cdf + (size_tmp - 1); + + /* method of bisection */ + for ( ;; ) + { + W_tmp = W_upper_MSB * *cdf_ptr; + W_tmp += (W_upper_LSB * *cdf_ptr) >> 16; + size_tmp >>= 1; + if (size_tmp == 0) break; + if (streamval > W_tmp) + { + W_lower = W_tmp; + cdf_ptr += size_tmp; + } else { + W_upper = W_tmp; + cdf_ptr -= size_tmp; + } + } + if (streamval > W_tmp) + { + W_lower = W_tmp; + *data++ = (int)(cdf_ptr - *cdf++); + } else { + W_upper = W_tmp; + *data++ = (int)(cdf_ptr - *cdf++ - 1); + } + + /* shift interval to start at zero */ + W_upper -= ++W_lower; + + /* add integer to bitstream */ + streamval -= W_lower; + + /* renormalize interval and update streamval */ + while ( !(W_upper & 0xFF000000) ) /* W_upper < 2^24 */ + { + /* read next byte from stream */ + streamval = (streamval << 8) | *++stream_ptr; + W_upper <<= 8; + } + + if (W_upper == 0) + /* Should not be possible in normal operation */ + return -2; + + + } + + streamdata->stream_index = (int)(stream_ptr - streamdata->stream); + streamdata->W_upper = W_upper; + streamdata->streamval = streamval; + + + /* find number of bytes in original stream (determined by current interval width) */ + if ( W_upper > 0x01FFFFFF ) + return streamdata->stream_index - 2; + else + return streamdata->stream_index - 1; +} + + + +/* + * function to decode more symbols from the arithmetic bytestream, taking single step up or + * down at a time + * cdf tables can be of arbitrary size, but large tables may take a lot of iterations + */ +int WebRtcIsac_DecHistOneStepMulti(int *data, /* output: data vector */ + Bitstr *streamdata, /* in-/output struct containing bitstream */ + const WebRtc_UWord16 **cdf, /* input: array of cdf arrays */ + const WebRtc_UWord16 *init_index, /* input: vector of initial cdf table search entries */ + const int N) /* input: data vector length */ +{ + WebRtc_UWord32 W_lower, W_upper; + WebRtc_UWord32 W_tmp; + WebRtc_UWord32 W_upper_LSB, W_upper_MSB; + WebRtc_UWord32 streamval; + const WebRtc_UWord8 *stream_ptr; + const WebRtc_UWord16 *cdf_ptr; + int k; + + + stream_ptr = streamdata->stream + streamdata->stream_index; + W_upper = streamdata->W_upper; + if (W_upper == 0) + /* Should not be possible in normal operation */ + return -2; + + if (streamdata->stream_index == 0) /* first time decoder is called for this stream */ + { + /* read first word from bytestream */ + streamval = *stream_ptr << 24; + streamval |= *++stream_ptr << 16; + streamval |= *++stream_ptr << 8; + streamval |= *++stream_ptr; + } else { + streamval = streamdata->streamval; + } + + + for (k=N; k>0; k--) + { + /* find the integer *data for which streamval lies in [W_lower+1, W_upper] */ + W_upper_LSB = W_upper & 0x0000FFFF; + W_upper_MSB = W_upper >> 16; + + /* start at the specified table entry */ + cdf_ptr = *cdf + (*init_index++); + W_tmp = W_upper_MSB * *cdf_ptr; + W_tmp += (W_upper_LSB * *cdf_ptr) >> 16; + if (streamval > W_tmp) + { + for ( ;; ) + { + W_lower = W_tmp; + if (cdf_ptr[0]==65535) + /* range check */ + return -3; + W_tmp = W_upper_MSB * *++cdf_ptr; + W_tmp += (W_upper_LSB * *cdf_ptr) >> 16; + if (streamval <= W_tmp) break; + } + W_upper = W_tmp; + *data++ = (int)(cdf_ptr - *cdf++ - 1); + } else { + for ( ;; ) + { + W_upper = W_tmp; + --cdf_ptr; + if (cdf_ptr<*cdf) { + /* range check */ + return -3; + } + W_tmp = W_upper_MSB * *cdf_ptr; + W_tmp += (W_upper_LSB * *cdf_ptr) >> 16; + if (streamval > W_tmp) break; + } + W_lower = W_tmp; + *data++ = (int)(cdf_ptr - *cdf++); + } + + /* shift interval to start at zero */ + W_upper -= ++W_lower; + /* add integer to bitstream */ + streamval -= W_lower; + + /* renormalize interval and update streamval */ + while ( !(W_upper & 0xFF000000) ) /* W_upper < 2^24 */ + { + /* read next byte from stream */ + streamval = (streamval << 8) | *++stream_ptr; + W_upper <<= 8; + } + } + + streamdata->stream_index = (int)(stream_ptr - streamdata->stream); + streamdata->W_upper = W_upper; + streamdata->streamval = streamval; + + + /* find number of bytes in original stream (determined by current interval width) */ + if ( W_upper > 0x01FFFFFF ) + return streamdata->stream_index - 2; + else + return streamdata->stream_index - 1; +} diff --git a/src/modules/audio_coding/codecs/isac/main/source/arith_routines_logist.c b/src/modules/audio_coding/codecs/isac/main/source/arith_routines_logist.c new file mode 100644 index 0000000000..422855a4ce --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/arith_routines_logist.c @@ -0,0 +1,294 @@ +/* + * 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. + */ + +/* + * arith_routines.h + * + * This file contains functions for arithmatically encoding and + * decoding DFT coefficients. + * + */ + + +#include "arith_routines.h" + + + +static const WebRtc_Word32 kHistEdgesQ15[51] = { + -327680, -314573, -301466, -288359, -275252, -262144, -249037, -235930, -222823, -209716, + -196608, -183501, -170394, -157287, -144180, -131072, -117965, -104858, -91751, -78644, + -65536, -52429, -39322, -26215, -13108, 0, 13107, 26214, 39321, 52428, + 65536, 78643, 91750, 104857, 117964, 131072, 144179, 157286, 170393, 183500, + 196608, 209715, 222822, 235929, 249036, 262144, 275251, 288358, 301465, 314572, + 327680}; + + +static const int kCdfSlopeQ0[51] = { /* Q0 */ + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 13, 23, 47, 87, 154, 315, 700, 1088, + 2471, 6064, 14221, 21463, 36634, 36924, 19750, 13270, 5806, 2312, + 1095, 660, 316, 145, 86, 41, 32, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 0}; + + +static const int kCdfQ16[51] = { /* Q16 */ + 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, + 20, 22, 24, 29, 38, 57, 92, 153, 279, 559, + 994, 1983, 4408, 10097, 18682, 33336, 48105, 56005, 61313, 63636, + 64560, 64998, 65262, 65389, 65447, 65481, 65497, 65510, 65512, 65514, + 65516, 65518, 65520, 65522, 65524, 65526, 65528, 65530, 65532, 65534, + 65535}; + + + +/* function to be converted to fixed point */ +static __inline WebRtc_UWord32 piecewise(WebRtc_Word32 xinQ15) { + + WebRtc_Word32 ind, qtmp1, qtmp2, qtmp3; + WebRtc_UWord32 tmpUW32; + + + qtmp2 = xinQ15; + + if (qtmp2 < kHistEdgesQ15[0]) { + qtmp2 = kHistEdgesQ15[0]; + } + if (qtmp2 > kHistEdgesQ15[50]) { + qtmp2 = kHistEdgesQ15[50]; + } + + qtmp1 = qtmp2 - kHistEdgesQ15[0]; /* Q15 - Q15 = Q15 */ + ind = (qtmp1 * 5) >> 16; /* 2^16 / 5 = 0.4 in Q15 */ + /* Q15 -> Q0 */ + qtmp1 = qtmp2 - kHistEdgesQ15[ind]; /* Q15 - Q15 = Q15 */ + qtmp2 = kCdfSlopeQ0[ind] * qtmp1; /* Q0 * Q15 = Q15 */ + qtmp3 = qtmp2>>15; /* Q15 -> Q0 */ + + tmpUW32 = kCdfQ16[ind] + qtmp3; /* Q0 + Q0 = Q0 */ + return tmpUW32; +} + + + +int WebRtcIsac_EncLogisticMulti2( + Bitstr *streamdata, /* in-/output struct containing bitstream */ + WebRtc_Word16 *dataQ7, /* input: data vector */ + const WebRtc_UWord16 *envQ8, /* input: side info vector defining the width of the pdf */ + const int N, /* input: data vector length / 2 */ + const WebRtc_Word16 isSWB12kHz) +{ + WebRtc_UWord32 W_lower, W_upper; + WebRtc_UWord32 W_upper_LSB, W_upper_MSB; + WebRtc_UWord8 *stream_ptr; + WebRtc_UWord8 *maxStreamPtr; + WebRtc_UWord8 *stream_ptr_carry; + WebRtc_UWord32 cdf_lo, cdf_hi; + int k; + + /* point to beginning of stream buffer */ + stream_ptr = streamdata->stream + streamdata->stream_index; + W_upper = streamdata->W_upper; + + maxStreamPtr = streamdata->stream + STREAM_SIZE_MAX_60 - 1; + for (k = 0; k < N; k++) + { + /* compute cdf_lower and cdf_upper by evaluating the piecewise linear cdf */ + cdf_lo = piecewise((*dataQ7 - 64) * *envQ8); + cdf_hi = piecewise((*dataQ7 + 64) * *envQ8); + + /* test and clip if probability gets too small */ + while (cdf_lo+1 >= cdf_hi) { + /* clip */ + if (*dataQ7 > 0) { + *dataQ7 -= 128; + cdf_hi = cdf_lo; + cdf_lo = piecewise((*dataQ7 - 64) * *envQ8); + } else { + *dataQ7 += 128; + cdf_lo = cdf_hi; + cdf_hi = piecewise((*dataQ7 + 64) * *envQ8); + } + } + + dataQ7++; + // increment only once per 4 iterations for SWB-16kHz or WB + // increment only once per 2 iterations for SWB-12kHz + envQ8 += (isSWB12kHz)? (k & 1):((k & 1) & (k >> 1)); + + + /* update interval */ + W_upper_LSB = W_upper & 0x0000FFFF; + W_upper_MSB = W_upper >> 16; + W_lower = W_upper_MSB * cdf_lo; + W_lower += (W_upper_LSB * cdf_lo) >> 16; + W_upper = W_upper_MSB * cdf_hi; + W_upper += (W_upper_LSB * cdf_hi) >> 16; + + /* shift interval such that it begins at zero */ + W_upper -= ++W_lower; + + /* add integer to bitstream */ + streamdata->streamval += W_lower; + + /* handle carry */ + if (streamdata->streamval < W_lower) + { + /* propagate carry */ + stream_ptr_carry = stream_ptr; + while (!(++(*--stream_ptr_carry))); + } + + /* renormalize interval, store most significant byte of streamval and update streamval */ + while ( !(W_upper & 0xFF000000) ) /* W_upper < 2^24 */ + { + W_upper <<= 8; + *stream_ptr++ = (WebRtc_UWord8) (streamdata->streamval >> 24); + + if(stream_ptr > maxStreamPtr) + { + return -ISAC_DISALLOWED_BITSTREAM_LENGTH; + } + streamdata->streamval <<= 8; + } + } + + /* calculate new stream_index */ + streamdata->stream_index = (int)(stream_ptr - streamdata->stream); + streamdata->W_upper = W_upper; + + return 0; +} + + + +int WebRtcIsac_DecLogisticMulti2( + WebRtc_Word16 *dataQ7, /* output: data vector */ + Bitstr *streamdata, /* in-/output struct containing bitstream */ + const WebRtc_UWord16 *envQ8, /* input: side info vector defining the width of the pdf */ + const WebRtc_Word16 *ditherQ7,/* input: dither vector */ + const int N, /* input: data vector length */ + const WebRtc_Word16 isSWB12kHz) +{ + WebRtc_UWord32 W_lower, W_upper; + WebRtc_UWord32 W_tmp; + WebRtc_UWord32 W_upper_LSB, W_upper_MSB; + WebRtc_UWord32 streamval; + const WebRtc_UWord8 *stream_ptr; + WebRtc_UWord32 cdf_tmp; + WebRtc_Word16 candQ7; + int k; + + stream_ptr = streamdata->stream + streamdata->stream_index; + W_upper = streamdata->W_upper; + if (streamdata->stream_index == 0) /* first time decoder is called for this stream */ + { + /* read first word from bytestream */ + streamval = *stream_ptr << 24; + streamval |= *++stream_ptr << 16; + streamval |= *++stream_ptr << 8; + streamval |= *++stream_ptr; + } else { + streamval = streamdata->streamval; + } + + + for (k = 0; k < N; k++) + { + /* find the integer *data for which streamval lies in [W_lower+1, W_upper] */ + W_upper_LSB = W_upper & 0x0000FFFF; + W_upper_MSB = W_upper >> 16; + + /* find first candidate by inverting the logistic cdf */ + candQ7 = - *ditherQ7 + 64; + cdf_tmp = piecewise(candQ7 * *envQ8); + + W_tmp = W_upper_MSB * cdf_tmp; + W_tmp += (W_upper_LSB * cdf_tmp) >> 16; + if (streamval > W_tmp) + { + W_lower = W_tmp; + candQ7 += 128; + cdf_tmp = piecewise(candQ7 * *envQ8); + + W_tmp = W_upper_MSB * cdf_tmp; + W_tmp += (W_upper_LSB * cdf_tmp) >> 16; + while (streamval > W_tmp) + { + W_lower = W_tmp; + candQ7 += 128; + cdf_tmp = piecewise(candQ7 * *envQ8); + + W_tmp = W_upper_MSB * cdf_tmp; + W_tmp += (W_upper_LSB * cdf_tmp) >> 16; + + /* error check */ + if (W_lower == W_tmp) return -1; + } + W_upper = W_tmp; + + /* another sample decoded */ + *dataQ7 = candQ7 - 64; + } + else + { + W_upper = W_tmp; + candQ7 -= 128; + cdf_tmp = piecewise(candQ7 * *envQ8); + + W_tmp = W_upper_MSB * cdf_tmp; + W_tmp += (W_upper_LSB * cdf_tmp) >> 16; + while ( !(streamval > W_tmp) ) + { + W_upper = W_tmp; + candQ7 -= 128; + cdf_tmp = piecewise(candQ7 * *envQ8); + + W_tmp = W_upper_MSB * cdf_tmp; + W_tmp += (W_upper_LSB * cdf_tmp) >> 16; + + /* error check */ + if (W_upper == W_tmp) return -1; + } + W_lower = W_tmp; + + /* another sample decoded */ + *dataQ7 = candQ7 + 64; + } + ditherQ7++; + dataQ7++; + // increment only once per 4 iterations for SWB-16kHz or WB + // increment only once per 2 iterations for SWB-12kHz + envQ8 += (isSWB12kHz)? (k & 1):((k & 1) & (k >> 1)); + + /* shift interval to start at zero */ + W_upper -= ++W_lower; + + /* add integer to bitstream */ + streamval -= W_lower; + + /* renormalize interval and update streamval */ + while ( !(W_upper & 0xFF000000) ) /* W_upper < 2^24 */ + { + /* read next byte from stream */ + streamval = (streamval << 8) | *++stream_ptr; + W_upper <<= 8; + } + } + + streamdata->stream_index = (int)(stream_ptr - streamdata->stream); + streamdata->W_upper = W_upper; + streamdata->streamval = streamval; + + /* find number of bytes in original stream (determined by current interval width) */ + if ( W_upper > 0x01FFFFFF ) + return streamdata->stream_index - 2; + else + return streamdata->stream_index - 1; +} diff --git a/src/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.c b/src/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.c new file mode 100644 index 0000000000..d0a50c5296 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.c @@ -0,0 +1,1020 @@ +/* + * 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. + */ + +/* + * BwEstimator.c + * + * This file contains the code for the Bandwidth Estimator designed + * for iSAC. + * + */ + +#include "bandwidth_estimator.h" +#include "settings.h" +#include "isac.h" + +#include + +/* array of quantization levels for bottle neck info; Matlab code: */ +/* sprintf('%4.1ff, ', logspace(log10(5000), log10(40000), 12)) */ +static const float kQRateTableWb[12] = +{ + 10000.0f, 11115.3f, 12355.1f, 13733.1f, 15264.8f, 16967.3f, + 18859.8f, 20963.3f, 23301.4f, 25900.3f, 28789.0f, 32000.0f}; + + +static const float kQRateTableSwb[24] = +{ + 10000.0f, 11115.3f, 12355.1f, 13733.1f, 15264.8f, 16967.3f, + 18859.8f, 20963.3f, 23153.1f, 25342.9f, 27532.7f, 29722.5f, + 31912.3f, 34102.1f, 36291.9f, 38481.7f, 40671.4f, 42861.2f, + 45051.0f, 47240.8f, 49430.6f, 51620.4f, 53810.2f, 56000.0f, +}; + + + + +WebRtc_Word32 WebRtcIsac_InitBandwidthEstimator( + BwEstimatorstr* bwest_str, + enum IsacSamplingRate encoderSampRate, + enum IsacSamplingRate decoderSampRate) +{ + switch(encoderSampRate) + { + case kIsacWideband: + { + bwest_str->send_bw_avg = INIT_BN_EST_WB; + break; + } + case kIsacSuperWideband: + { + bwest_str->send_bw_avg = INIT_BN_EST_SWB; + break; + } + } + + switch(decoderSampRate) + { + case kIsacWideband: + { + bwest_str->prev_frame_length = INIT_FRAME_LEN_WB; + bwest_str->rec_bw_inv = 1.0f / + (INIT_BN_EST_WB + INIT_HDR_RATE_WB); + bwest_str->rec_bw = (WebRtc_Word32)INIT_BN_EST_WB; + bwest_str->rec_bw_avg_Q = INIT_BN_EST_WB; + bwest_str->rec_bw_avg = INIT_BN_EST_WB + INIT_HDR_RATE_WB; + bwest_str->rec_header_rate = INIT_HDR_RATE_WB; + break; + } + case kIsacSuperWideband: + { + bwest_str->prev_frame_length = INIT_FRAME_LEN_SWB; + bwest_str->rec_bw_inv = 1.0f / + (INIT_BN_EST_SWB + INIT_HDR_RATE_SWB); + bwest_str->rec_bw = (WebRtc_Word32)INIT_BN_EST_SWB; + bwest_str->rec_bw_avg_Q = INIT_BN_EST_SWB; + bwest_str->rec_bw_avg = INIT_BN_EST_SWB + INIT_HDR_RATE_SWB; + bwest_str->rec_header_rate = INIT_HDR_RATE_SWB; + break; + } + } + + bwest_str->prev_rec_rtp_number = 0; + bwest_str->prev_rec_arr_ts = 0; + bwest_str->prev_rec_send_ts = 0; + bwest_str->prev_rec_rtp_rate = 1.0f; + bwest_str->last_update_ts = 0; + bwest_str->last_reduction_ts = 0; + bwest_str->count_tot_updates_rec = -9; + bwest_str->rec_jitter = 10.0f; + bwest_str->rec_jitter_short_term = 0.0f; + bwest_str->rec_jitter_short_term_abs = 5.0f; + bwest_str->rec_max_delay = 10.0f; + bwest_str->rec_max_delay_avg_Q = 10.0f; + bwest_str->num_pkts_rec = 0; + + bwest_str->send_max_delay_avg = 10.0f; + + bwest_str->hsn_detect_rec = 0; + + bwest_str->num_consec_rec_pkts_over_30k = 0; + + bwest_str->hsn_detect_snd = 0; + + bwest_str->num_consec_snt_pkts_over_30k = 0; + + bwest_str->in_wait_period = 0; + + bwest_str->change_to_WB = 0; + + bwest_str->numConsecLatePkts = 0; + bwest_str->consecLatency = 0; + bwest_str->inWaitLatePkts = 0; + bwest_str->senderTimestamp = 0; + bwest_str->receiverTimestamp = 0; + return 0; +} + +/* This function updates both bottle neck rates */ +/* Parameters: */ +/* rtp_number - value from RTP packet, from NetEq */ +/* frame length - length of signal frame in ms, from iSAC decoder */ +/* send_ts - value in RTP header giving send time in samples */ +/* arr_ts - value given by timeGetTime() time of arrival in samples of packet from NetEq */ +/* pksize - size of packet in bytes, from NetEq */ +/* Index - integer (range 0...23) indicating bottle neck & jitter as estimated by other side */ +/* returns 0 if everything went fine, -1 otherwise */ +WebRtc_Word16 WebRtcIsac_UpdateBandwidthEstimator( + BwEstimatorstr *bwest_str, + const WebRtc_UWord16 rtp_number, + const WebRtc_Word32 frame_length, + const WebRtc_UWord32 send_ts, + const WebRtc_UWord32 arr_ts, + const WebRtc_Word32 pksize + /*, const WebRtc_UWord16 Index*/) +{ + float weight = 0.0f; + float curr_bw_inv = 0.0f; + float rec_rtp_rate; + float t_diff_proj; + float arr_ts_diff; + float send_ts_diff; + float arr_time_noise; + float arr_time_noise_abs; + + float delay_correction_factor = 1; + float late_diff = 0.0f; + int immediate_set = 0; + int num_pkts_expected; + + + // We have to adjust the header-rate if the first packet has a + // frame-size different than the initialized value. + if ( frame_length != bwest_str->prev_frame_length ) + { + bwest_str->rec_header_rate = (float)HEADER_SIZE * 8.0f * + 1000.0f / (float)frame_length; /* bits/s */ + } + + /* UPDATE ESTIMATES ON THIS SIDE */ + /* compute far-side transmission rate */ + rec_rtp_rate = ((float)pksize * 8.0f * 1000.0f / (float)frame_length) + + bwest_str->rec_header_rate; + // rec_rtp_rate packet bits/s + header bits/s + + /* check for timer wrap-around */ + if (arr_ts < bwest_str->prev_rec_arr_ts) + { + bwest_str->prev_rec_arr_ts = arr_ts; + bwest_str->last_update_ts = arr_ts; + bwest_str->last_reduction_ts = arr_ts + 3*FS; + bwest_str->num_pkts_rec = 0; + + /* store frame length */ + bwest_str->prev_frame_length = frame_length; + + /* store far-side transmission rate */ + bwest_str->prev_rec_rtp_rate = rec_rtp_rate; + + /* store far-side RTP time stamp */ + bwest_str->prev_rec_rtp_number = rtp_number; + + return 0; + } + + bwest_str->num_pkts_rec++; + + /* check that it's not one of the first 9 packets */ + if ( bwest_str->count_tot_updates_rec > 0 ) + { + if(bwest_str->in_wait_period > 0 ) + { + bwest_str->in_wait_period--; + } + + bwest_str->inWaitLatePkts -= ((bwest_str->inWaitLatePkts > 0)? 1:0); + send_ts_diff = (float)(send_ts - bwest_str->prev_rec_send_ts); + + if (send_ts_diff <= (16 * frame_length)*2) + //doesn't allow for a dropped packet, not sure necessary to be + // that strict -DH + { + /* if not been updated for a long time, reduce the BN estimate */ + if((WebRtc_UWord32)(arr_ts - bwest_str->last_update_ts) * + 1000.0f / FS > 3000) + { + //how many frames should have been received since the last + // update if too many have been dropped or there have been + // big delays won't allow this reduction may no longer need + // the send_ts_diff here + num_pkts_expected = (int)(((float)(arr_ts - + bwest_str->last_update_ts) * 1000.0f /(float) FS) / + (float)frame_length); + + if(((float)bwest_str->num_pkts_rec/(float)num_pkts_expected) > + 0.9) + { + float inv_bitrate = (float) pow( 0.99995, + (double)((WebRtc_UWord32)(arr_ts - + bwest_str->last_reduction_ts)*1000.0f/FS) ); + + if ( inv_bitrate ) + { + bwest_str->rec_bw_inv /= inv_bitrate; + + //precautionary, likely never necessary + if (bwest_str->hsn_detect_snd && + bwest_str->hsn_detect_rec) + { + if (bwest_str->rec_bw_inv > 0.000066f) + { + bwest_str->rec_bw_inv = 0.000066f; + } + } + } + else + { + bwest_str->rec_bw_inv = 1.0f / + (INIT_BN_EST_WB + INIT_HDR_RATE_WB); + } + /* reset time-since-update counter */ + bwest_str->last_reduction_ts = arr_ts; + } + else + //reset here? + { + bwest_str->last_reduction_ts = arr_ts + 3*FS; + bwest_str->last_update_ts = arr_ts; + bwest_str->num_pkts_rec = 0; + } + } + } + else + { + bwest_str->last_reduction_ts = arr_ts + 3*FS; + bwest_str->last_update_ts = arr_ts; + bwest_str->num_pkts_rec = 0; + } + + + /* temporarily speed up adaptation if frame length has changed */ + if ( frame_length != bwest_str->prev_frame_length ) + { + bwest_str->count_tot_updates_rec = 10; + bwest_str->rec_header_rate = (float)HEADER_SIZE * 8.0f * + 1000.0f / (float)frame_length; /* bits/s */ + + bwest_str->rec_bw_inv = 1.0f /((float)bwest_str->rec_bw + + bwest_str->rec_header_rate); + } + + //////////////////////// + arr_ts_diff = (float)(arr_ts - bwest_str->prev_rec_arr_ts); + + if (send_ts_diff > 0 ) + { + late_diff = arr_ts_diff - send_ts_diff; + } + else + { + late_diff = arr_ts_diff - (float)(16 * frame_length); + } + + if((late_diff > 0) && !bwest_str->inWaitLatePkts) + { + bwest_str->numConsecLatePkts++; + bwest_str->consecLatency += late_diff; + } + else + { + bwest_str->numConsecLatePkts = 0; + bwest_str->consecLatency = 0; + } + if(bwest_str->numConsecLatePkts > 50) + { + float latencyMs = bwest_str->consecLatency/(FS/1000); + float averageLatencyMs = latencyMs / bwest_str->numConsecLatePkts; + delay_correction_factor = frame_length / (frame_length + averageLatencyMs); + immediate_set = 1; + bwest_str->inWaitLatePkts = (WebRtc_Word16)((bwest_str->consecLatency/(FS/1000)) / 30);// + 150; + bwest_str->start_wait_period = arr_ts; + } + /////////////////////////////////////////////// + + + + /* update only if previous packet was not lost */ + if ( rtp_number == bwest_str->prev_rec_rtp_number + 1 ) + { + + + if (!(bwest_str->hsn_detect_snd && bwest_str->hsn_detect_rec)) + { + if ((arr_ts_diff > (float)(16 * frame_length))) + { + //1/2 second + if ((late_diff > 8000.0f) && !bwest_str->in_wait_period) + { + delay_correction_factor = 0.7f; + bwest_str->in_wait_period = 55; + bwest_str->start_wait_period = arr_ts; + immediate_set = 1; + } + //320 ms + else if (late_diff > 5120.0f && !bwest_str->in_wait_period) + { + delay_correction_factor = 0.8f; + immediate_set = 1; + bwest_str->in_wait_period = 44; + bwest_str->start_wait_period = arr_ts; + } + } + } + + + if ((bwest_str->prev_rec_rtp_rate > bwest_str->rec_bw_avg) && + (rec_rtp_rate > bwest_str->rec_bw_avg) && + !bwest_str->in_wait_period) + { + /* test if still in initiation period and increment counter */ + if (bwest_str->count_tot_updates_rec++ > 99) + { + /* constant weight after initiation part */ + weight = 0.01f; + } + else + { + /* weight decreases with number of updates */ + weight = 1.0f / (float) bwest_str->count_tot_updates_rec; + } + /* Bottle Neck Estimation */ + + /* limit outliers */ + /* if more than 25 ms too much */ + if (arr_ts_diff > frame_length * FS/1000 + 400.0f) + { + // in samples, why 25ms?? + arr_ts_diff = frame_length * FS/1000 + 400.0f; + } + if(arr_ts_diff < (frame_length * FS/1000) - 160.0f) + { + /* don't allow it to be less than frame rate - 10 ms */ + arr_ts_diff = (float)frame_length * FS/1000 - 160.0f; + } + + /* compute inverse receiving rate for last packet */ + curr_bw_inv = arr_ts_diff / ((float)(pksize + HEADER_SIZE) * + 8.0f * FS); // (180+35)*8*16000 = 27.5 Mbit.... + + + if(curr_bw_inv < + (1.0f / (MAX_ISAC_BW + bwest_str->rec_header_rate))) + { + // don't allow inv rate to be larger than MAX + curr_bw_inv = (1.0f / + (MAX_ISAC_BW + bwest_str->rec_header_rate)); + } + + /* update bottle neck rate estimate */ + bwest_str->rec_bw_inv = weight * curr_bw_inv + + (1.0f - weight) * bwest_str->rec_bw_inv; + + /* reset time-since-update counter */ + bwest_str->last_update_ts = arr_ts; + bwest_str->last_reduction_ts = arr_ts + 3 * FS; + bwest_str->num_pkts_rec = 0; + + /* Jitter Estimation */ + /* projected difference between arrival times */ + t_diff_proj = ((float)(pksize + HEADER_SIZE) * 8.0f * + 1000.0f) / bwest_str->rec_bw_avg; + + + // difference between projected and actual + // arrival time differences + arr_time_noise = (float)(arr_ts_diff*1000.0f/FS) - + t_diff_proj; + arr_time_noise_abs = (float) fabs( arr_time_noise ); + + /* long term averaged absolute jitter */ + bwest_str->rec_jitter = weight * arr_time_noise_abs + + (1.0f - weight) * bwest_str->rec_jitter; + if (bwest_str->rec_jitter > 10.0f) + { + bwest_str->rec_jitter = 10.0f; + } + /* short term averaged absolute jitter */ + bwest_str->rec_jitter_short_term_abs = 0.05f * + arr_time_noise_abs + 0.95f * + bwest_str->rec_jitter_short_term_abs; + + /* short term averaged jitter */ + bwest_str->rec_jitter_short_term = 0.05f * arr_time_noise + + 0.95f * bwest_str->rec_jitter_short_term; + } + } + } + else + { + // reset time-since-update counter when + // receiving the first 9 packets + bwest_str->last_update_ts = arr_ts; + bwest_str->last_reduction_ts = arr_ts + 3*FS; + bwest_str->num_pkts_rec = 0; + + bwest_str->count_tot_updates_rec++; + } + + /* limit minimum bottle neck rate */ + if (bwest_str->rec_bw_inv > 1.0f / ((float)MIN_ISAC_BW + + bwest_str->rec_header_rate)) + { + bwest_str->rec_bw_inv = 1.0f / ((float)MIN_ISAC_BW + + bwest_str->rec_header_rate); + } + + // limit maximum bitrate + if (bwest_str->rec_bw_inv < 1.0f / ((float)MAX_ISAC_BW + + bwest_str->rec_header_rate)) + { + bwest_str->rec_bw_inv = 1.0f / ((float)MAX_ISAC_BW + + bwest_str->rec_header_rate); + } + + /* store frame length */ + bwest_str->prev_frame_length = frame_length; + + /* store far-side transmission rate */ + bwest_str->prev_rec_rtp_rate = rec_rtp_rate; + + /* store far-side RTP time stamp */ + bwest_str->prev_rec_rtp_number = rtp_number; + + // Replace bwest_str->rec_max_delay by the new + // value (atomic operation) + bwest_str->rec_max_delay = 3.0f * bwest_str->rec_jitter; + + /* store send and arrival time stamp */ + bwest_str->prev_rec_arr_ts = arr_ts ; + bwest_str->prev_rec_send_ts = send_ts; + + /* Replace bwest_str->rec_bw by the new value (atomic operation) */ + bwest_str->rec_bw = (WebRtc_Word32)(1.0f / bwest_str->rec_bw_inv - + bwest_str->rec_header_rate); + + if (immediate_set) + { + bwest_str->rec_bw = (WebRtc_Word32) (delay_correction_factor * + (float) bwest_str->rec_bw); + + if (bwest_str->rec_bw < (WebRtc_Word32) MIN_ISAC_BW) + { + bwest_str->rec_bw = (WebRtc_Word32) MIN_ISAC_BW; + } + + bwest_str->rec_bw_avg = bwest_str->rec_bw + + bwest_str->rec_header_rate; + + bwest_str->rec_bw_avg_Q = (float) bwest_str->rec_bw; + + bwest_str->rec_jitter_short_term = 0.0f; + + bwest_str->rec_bw_inv = 1.0f / (bwest_str->rec_bw + + bwest_str->rec_header_rate); + + bwest_str->count_tot_updates_rec = 1; + + immediate_set = 0; + bwest_str->consecLatency = 0; + bwest_str->numConsecLatePkts = 0; + } + + return 0; +} + + +/* This function updates the send bottle neck rate */ +/* Index - integer (range 0...23) indicating bottle neck & jitter as estimated by other side */ +/* returns 0 if everything went fine, -1 otherwise */ +WebRtc_Word16 WebRtcIsac_UpdateUplinkBwImpl( + BwEstimatorstr* bwest_str, + WebRtc_Word16 index, + enum IsacSamplingRate encoderSamplingFreq) +{ + if((index < 0) || (index > 23)) + { + return -ISAC_RANGE_ERROR_BW_ESTIMATOR; + } + + /* UPDATE ESTIMATES FROM OTHER SIDE */ + if(encoderSamplingFreq == kIsacWideband) + { + if(index > 11) + { + index -= 12; + /* compute the jitter estimate as decoded on the other side */ + bwest_str->send_max_delay_avg = 0.9f * bwest_str->send_max_delay_avg + + 0.1f * (float)MAX_ISAC_MD; + } + else + { + /* compute the jitter estimate as decoded on the other side */ + bwest_str->send_max_delay_avg = 0.9f * bwest_str->send_max_delay_avg + + 0.1f * (float)MIN_ISAC_MD; + } + + /* compute the BN estimate as decoded on the other side */ + bwest_str->send_bw_avg = 0.9f * bwest_str->send_bw_avg + + 0.1f * kQRateTableWb[index]; + } + else + { + /* compute the BN estimate as decoded on the other side */ + bwest_str->send_bw_avg = 0.9f * bwest_str->send_bw_avg + + 0.1f * kQRateTableSwb[index]; + } + + if (bwest_str->send_bw_avg > (float) 28000 && !bwest_str->hsn_detect_snd) + { + bwest_str->num_consec_snt_pkts_over_30k++; + + if (bwest_str->num_consec_snt_pkts_over_30k >= 66) + { + //approx 2 seconds with 30ms frames + bwest_str->hsn_detect_snd = 1; + } + } + else if (!bwest_str->hsn_detect_snd) + { + bwest_str->num_consec_snt_pkts_over_30k = 0; + } + return 0; +} + +// called when there is upper-band bit-stream to update jitter +// statistics. +WebRtc_Word16 WebRtcIsac_UpdateUplinkJitter( + BwEstimatorstr* bwest_str, + WebRtc_Word32 index) +{ + if((index < 0) || (index > 23)) + { + return -ISAC_RANGE_ERROR_BW_ESTIMATOR; + } + + if(index > 0) + { + /* compute the jitter estimate as decoded on the other side */ + bwest_str->send_max_delay_avg = 0.9f * bwest_str->send_max_delay_avg + + 0.1f * (float)MAX_ISAC_MD; + } + else + { + /* compute the jitter estimate as decoded on the other side */ + bwest_str->send_max_delay_avg = 0.9f * bwest_str->send_max_delay_avg + + 0.1f * (float)MIN_ISAC_MD; + } + + return 0; +} + + + +// Returns the bandwidth/jitter estimation code (integer 0...23) +// to put in the sending iSAC payload +WebRtc_UWord16 +WebRtcIsac_GetDownlinkBwJitIndexImpl( + BwEstimatorstr* bwest_str, + WebRtc_Word16* bottleneckIndex, + WebRtc_Word16* jitterInfo, + enum IsacSamplingRate decoderSamplingFreq) +{ + float MaxDelay; + //WebRtc_UWord16 MaxDelayBit; + + float rate; + float r; + float e1, e2; + const float weight = 0.1f; + const float* ptrQuantizationTable; + WebRtc_Word16 addJitterInfo; + WebRtc_Word16 minInd; + WebRtc_Word16 maxInd; + WebRtc_Word16 midInd; + + /* Get Max Delay Bit */ + /* get unquantized max delay */ + MaxDelay = (float)WebRtcIsac_GetDownlinkMaxDelay(bwest_str); + + if ( ((1.f - weight) * bwest_str->rec_max_delay_avg_Q + weight * + MAX_ISAC_MD - MaxDelay) > (MaxDelay - (1.f-weight) * + bwest_str->rec_max_delay_avg_Q - weight * MIN_ISAC_MD) ) + { + jitterInfo[0] = 0; + /* update quantized average */ + bwest_str->rec_max_delay_avg_Q = + (1.f - weight) * bwest_str->rec_max_delay_avg_Q + weight * + (float)MIN_ISAC_MD; + } + else + { + jitterInfo[0] = 1; + /* update quantized average */ + bwest_str->rec_max_delay_avg_Q = + (1.f-weight) * bwest_str->rec_max_delay_avg_Q + weight * + (float)MAX_ISAC_MD; + } + + // Get unquantized rate. + rate = (float)WebRtcIsac_GetDownlinkBandwidth(bwest_str); + + /* Get Rate Index */ + if(decoderSamplingFreq == kIsacWideband) + { + ptrQuantizationTable = kQRateTableWb; + addJitterInfo = 1; + maxInd = 11; + } + else + { + ptrQuantizationTable = kQRateTableSwb; + addJitterInfo = 0; + maxInd = 23; + } + + minInd = 0; + while(maxInd > minInd + 1) + { + midInd = (maxInd + minInd) >> 1; + if(rate > ptrQuantizationTable[midInd]) + { + minInd = midInd; + } + else + { + maxInd = midInd; + } + } + // Chose the index which gives results an average which is closest + // to rate + r = (1 - weight) * bwest_str->rec_bw_avg_Q - rate; + e1 = weight * ptrQuantizationTable[minInd] + r; + e2 = weight * ptrQuantizationTable[maxInd] + r; + e1 = (e1 > 0)? e1:-e1; + e2 = (e2 > 0)? e2:-e2; + if(e1 < e2) + { + bottleneckIndex[0] = minInd; + } + else + { + bottleneckIndex[0] = maxInd; + } + + bwest_str->rec_bw_avg_Q = (1 - weight) * bwest_str->rec_bw_avg_Q + + weight * ptrQuantizationTable[bottleneckIndex[0]]; + bottleneckIndex[0] += jitterInfo[0] * 12 * addJitterInfo; + + bwest_str->rec_bw_avg = (1 - weight) * bwest_str->rec_bw_avg + weight * + (rate + bwest_str->rec_header_rate); + + return 0; +} + + + +/* get the bottle neck rate from far side to here, as estimated on this side */ +WebRtc_Word32 WebRtcIsac_GetDownlinkBandwidth( const BwEstimatorstr *bwest_str) +{ + WebRtc_Word32 rec_bw; + float jitter_sign; + float bw_adjust; + + /* create a value between -1.0 and 1.0 indicating "average sign" of jitter */ + jitter_sign = bwest_str->rec_jitter_short_term / + bwest_str->rec_jitter_short_term_abs; + + /* adjust bw proportionally to negative average jitter sign */ + bw_adjust = 1.0f - jitter_sign * (0.15f + 0.15f * jitter_sign * jitter_sign); + + /* adjust Rate if jitter sign is mostly constant */ + rec_bw = (WebRtc_Word32)(bwest_str->rec_bw * bw_adjust); + + /* limit range of bottle neck rate */ + if (rec_bw < MIN_ISAC_BW) + { + rec_bw = MIN_ISAC_BW; + } + else if (rec_bw > MAX_ISAC_BW) + { + rec_bw = MAX_ISAC_BW; + } + return rec_bw; +} + +/* Returns the max delay (in ms) */ +WebRtc_Word32 +WebRtcIsac_GetDownlinkMaxDelay(const BwEstimatorstr *bwest_str) +{ + WebRtc_Word32 rec_max_delay; + + rec_max_delay = (WebRtc_Word32)(bwest_str->rec_max_delay); + + /* limit range of jitter estimate */ + if (rec_max_delay < MIN_ISAC_MD) + { + rec_max_delay = MIN_ISAC_MD; + } + else if (rec_max_delay > MAX_ISAC_MD) + { + rec_max_delay = MAX_ISAC_MD; + } + return rec_max_delay; +} + +/* get the bottle neck rate from here to far side, as estimated by far side */ +void +WebRtcIsac_GetUplinkBandwidth( + const BwEstimatorstr* bwest_str, + WebRtc_Word32* bitRate) +{ + /* limit range of bottle neck rate */ + if (bwest_str->send_bw_avg < MIN_ISAC_BW) + { + *bitRate = MIN_ISAC_BW; + } + else if (bwest_str->send_bw_avg > MAX_ISAC_BW) + { + *bitRate = MAX_ISAC_BW; + } + else + { + *bitRate = (WebRtc_Word32)(bwest_str->send_bw_avg); + } + return; +} + +/* Returns the max delay value from the other side in ms */ +WebRtc_Word32 +WebRtcIsac_GetUplinkMaxDelay(const BwEstimatorstr *bwest_str) +{ + WebRtc_Word32 send_max_delay; + + send_max_delay = (WebRtc_Word32)(bwest_str->send_max_delay_avg); + + /* limit range of jitter estimate */ + if (send_max_delay < MIN_ISAC_MD) + { + send_max_delay = MIN_ISAC_MD; + } + else if (send_max_delay > MAX_ISAC_MD) + { + send_max_delay = MAX_ISAC_MD; + } + return send_max_delay; +} + + +/* + * update long-term average bitrate and amount of data in buffer + * returns minimum payload size (bytes) + */ +int WebRtcIsac_GetMinBytes( + RateModel* State, + int StreamSize, /* bytes in bitstream */ + const int FrameSamples, /* samples per frame */ + const double BottleNeck, /* bottle neck rate; excl headers (bps) */ + const double DelayBuildUp, /* max delay from bottleneck buffering (ms) */ + enum ISACBandwidth bandwidth + /*,WebRtc_Word16 frequentLargePackets*/) +{ + double MinRate = 0.0; + int MinBytes; + double TransmissionTime; + int burstInterval = BURST_INTERVAL; + + // first 10 packets @ low rate, then INIT_BURST_LEN packets @ + // fixed rate of INIT_RATE bps + if (State->InitCounter > 0) + { + if (State->InitCounter-- <= INIT_BURST_LEN) + { + if(bandwidth == isac8kHz) + { + MinRate = INIT_RATE_WB; + } + else + { + MinRate = INIT_RATE_SWB; + } + } + else + { + MinRate = 0; + } + } + else + { + /* handle burst */ + if (State->BurstCounter) + { + if (State->StillBuffered < (1.0 - 1.0/BURST_LEN) * DelayBuildUp) + { + /* max bps derived from BottleNeck and DelayBuildUp values */ + MinRate = (1.0 + (FS/1000) * DelayBuildUp / + (double)(BURST_LEN * FrameSamples)) * BottleNeck; + } + else + { + // max bps derived from StillBuffered and DelayBuildUp + // values + MinRate = (1.0 + (FS/1000) * (DelayBuildUp - + State->StillBuffered) / (double)FrameSamples) * BottleNeck; + if (MinRate < 1.04 * BottleNeck) + { + MinRate = 1.04 * BottleNeck; + } + } + State->BurstCounter--; + } + } + + + /* convert rate from bits/second to bytes/packet */ + MinBytes = (int) (MinRate * FrameSamples / (8.0 * FS)); + + /* StreamSize will be adjusted if less than MinBytes */ + if (StreamSize < MinBytes) + { + StreamSize = MinBytes; + } + + /* keep track of when bottle neck was last exceeded by at least 1% */ + if (StreamSize * 8.0 * FS / FrameSamples > 1.01 * BottleNeck) { + if (State->PrevExceed) { + /* bottle_neck exceded twice in a row, decrease ExceedAgo */ + State->ExceedAgo -= /*BURST_INTERVAL*/ burstInterval / (BURST_LEN - 1); + if (State->ExceedAgo < 0) + State->ExceedAgo = 0; + } + else + { + State->ExceedAgo += (FrameSamples * 1000) / FS; /* ms */ + State->PrevExceed = 1; + } + } + else + { + State->PrevExceed = 0; + State->ExceedAgo += (FrameSamples * 1000) / FS; /* ms */ + } + + /* set burst flag if bottle neck not exceeded for long time */ + if ((State->ExceedAgo > burstInterval) && + (State->BurstCounter == 0)) + { + if (State->PrevExceed) + { + State->BurstCounter = BURST_LEN - 1; + } + else + { + State->BurstCounter = BURST_LEN; + } + } + + + /* Update buffer delay */ + TransmissionTime = StreamSize * 8.0 * 1000.0 / BottleNeck; /* ms */ + State->StillBuffered += TransmissionTime; + State->StillBuffered -= (FrameSamples * 1000) / FS; /* ms */ + if (State->StillBuffered < 0.0) + { + State->StillBuffered = 0.0; + } + + return MinBytes; +} + + +/* + * update long-term average bitrate and amount of data in buffer + */ +void WebRtcIsac_UpdateRateModel( + RateModel *State, + int StreamSize, /* bytes in bitstream */ + const int FrameSamples, /* samples per frame */ + const double BottleNeck) /* bottle neck rate; excl headers (bps) */ +{ + double TransmissionTime; + + /* avoid the initial "high-rate" burst */ + State->InitCounter = 0; + + /* Update buffer delay */ + TransmissionTime = StreamSize * 8.0 * 1000.0 / BottleNeck; /* ms */ + State->StillBuffered += TransmissionTime; + State->StillBuffered -= (FrameSamples * 1000) / FS; /* ms */ + if (State->StillBuffered < 0.0) + State->StillBuffered = 0.0; + +} + + +void WebRtcIsac_InitRateModel( + RateModel *State) +{ + State->PrevExceed = 0; /* boolean */ + State->ExceedAgo = 0; /* ms */ + State->BurstCounter = 0; /* packets */ + State->InitCounter = INIT_BURST_LEN + 10; /* packets */ + State->StillBuffered = 1.0; /* ms */ +} + +int WebRtcIsac_GetNewFrameLength( + double bottle_neck, + int current_framesamples) +{ + int new_framesamples; + + const int Thld_20_30 = 20000; + + //const int Thld_30_20 = 30000; + const int Thld_30_20 = 1000000; // disable 20 ms frames + + const int Thld_30_60 = 18000; + //const int Thld_30_60 = 0; // disable 60 ms frames + + const int Thld_60_30 = 27000; + + + new_framesamples = current_framesamples; + + /* find new framelength */ + switch(current_framesamples) { + case 320: + if (bottle_neck < Thld_20_30) + new_framesamples = 480; + break; + case 480: + if (bottle_neck < Thld_30_60) + new_framesamples = 960; + else if (bottle_neck > Thld_30_20) + new_framesamples = 320; + break; + case 960: + if (bottle_neck >= Thld_60_30) + new_framesamples = 480; + break; + } + + return new_framesamples; +} + +double WebRtcIsac_GetSnr( + double bottle_neck, + int framesamples) +{ + double s2nr; + + const double a_20 = -30.0; + const double b_20 = 0.8; + const double c_20 = 0.0; + + const double a_30 = -23.0; + const double b_30 = 0.48; + const double c_30 = 0.0; + + const double a_60 = -23.0; + const double b_60 = 0.53; + const double c_60 = 0.0; + + + /* find new SNR value */ + switch(framesamples) { + case 320: + s2nr = a_20 + b_20 * bottle_neck * 0.001 + c_20 * bottle_neck * + bottle_neck * 0.000001; + break; + case 480: + s2nr = a_30 + b_30 * bottle_neck * 0.001 + c_30 * bottle_neck * + bottle_neck * 0.000001; + break; + case 960: + s2nr = a_60 + b_60 * bottle_neck * 0.001 + c_60 * bottle_neck * + bottle_neck * 0.000001; + break; + default: + s2nr = 0; + } + + return s2nr; + +} diff --git a/src/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h b/src/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h new file mode 100644 index 0000000000..5604d7bbbd --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/bandwidth_estimator.h @@ -0,0 +1,177 @@ +/* + * 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. + */ + +/* + * bandwidth_estimator.h + * + * This header file contains the API for the Bandwidth Estimator + * designed for iSAC. + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_ + +#include "structs.h" +#include "settings.h" + + +#define MIN_ISAC_BW 10000 +#define MIN_ISAC_BW_LB 10000 +#define MIN_ISAC_BW_UB 25000 + +#define MAX_ISAC_BW 56000 +#define MAX_ISAC_BW_UB 32000 +#define MAX_ISAC_BW_LB 32000 + +#define MIN_ISAC_MD 5 +#define MAX_ISAC_MD 25 + +// assumed header size, in bytes; we don't know the exact number +// (header compression may be used) +#define HEADER_SIZE 35 + +// Initial Frame-Size, in ms, for Wideband & Super-Wideband Mode +#define INIT_FRAME_LEN_WB 60 +#define INIT_FRAME_LEN_SWB 30 + +// Initial Bottleneck Estimate, in bits/sec, for +// Wideband & Super-wideband mode +#define INIT_BN_EST_WB 20e3f +#define INIT_BN_EST_SWB 56e3f + +// Initial Header rate (header rate depends on frame-size), +// in bits/sec, for Wideband & Super-Wideband mode. +#define INIT_HDR_RATE_WB \ + ((float)HEADER_SIZE * 8.0f * 1000.0f / (float)INIT_FRAME_LEN_WB) +#define INIT_HDR_RATE_SWB \ + ((float)HEADER_SIZE * 8.0f * 1000.0f / (float)INIT_FRAME_LEN_SWB) + +// number of packets in a row for a high rate burst +#define BURST_LEN 3 + +// ms, max time between two full bursts +#define BURST_INTERVAL 500 + +// number of packets in a row for initial high rate burst +#define INIT_BURST_LEN 5 + +// bits/s, rate for the first BURST_LEN packets +#define INIT_RATE_WB INIT_BN_EST_WB +#define INIT_RATE_SWB INIT_BN_EST_SWB + + +#if defined(__cplusplus) +extern "C" { +#endif + + /* This function initializes the struct */ + /* to be called before using the struct for anything else */ + /* returns 0 if everything went fine, -1 otherwise */ + WebRtc_Word32 WebRtcIsac_InitBandwidthEstimator( + BwEstimatorstr* bwest_str, + enum IsacSamplingRate encoderSampRate, + enum IsacSamplingRate decoderSampRate); + + /* This function updates the receiving estimate */ + /* Parameters: */ + /* rtp_number - value from RTP packet, from NetEq */ + /* frame length - length of signal frame in ms, from iSAC decoder */ + /* send_ts - value in RTP header giving send time in samples */ + /* arr_ts - value given by timeGetTime() time of arrival in samples of packet from NetEq */ + /* pksize - size of packet in bytes, from NetEq */ + /* Index - integer (range 0...23) indicating bottle neck & jitter as estimated by other side */ + /* returns 0 if everything went fine, -1 otherwise */ + WebRtc_Word16 WebRtcIsac_UpdateBandwidthEstimator( + BwEstimatorstr* bwest_str, + const WebRtc_UWord16 rtp_number, + const WebRtc_Word32 frame_length, + const WebRtc_UWord32 send_ts, + const WebRtc_UWord32 arr_ts, + const WebRtc_Word32 pksize); + + /* Update receiving estimates. Used when we only receive BWE index, no iSAC data packet. */ + WebRtc_Word16 WebRtcIsac_UpdateUplinkBwImpl( + BwEstimatorstr* bwest_str, + WebRtc_Word16 Index, + enum IsacSamplingRate encoderSamplingFreq); + + /* Returns the bandwidth/jitter estimation code (integer 0...23) to put in the sending iSAC payload */ + WebRtc_UWord16 WebRtcIsac_GetDownlinkBwJitIndexImpl( + BwEstimatorstr* bwest_str, + WebRtc_Word16* bottleneckIndex, + WebRtc_Word16* jitterInfo, + enum IsacSamplingRate decoderSamplingFreq); + + /* Returns the bandwidth estimation (in bps) */ + WebRtc_Word32 WebRtcIsac_GetDownlinkBandwidth( + const BwEstimatorstr *bwest_str); + + /* Returns the max delay (in ms) */ + WebRtc_Word32 WebRtcIsac_GetDownlinkMaxDelay( + const BwEstimatorstr *bwest_str); + + /* Returns the bandwidth that iSAC should send with in bps */ + void WebRtcIsac_GetUplinkBandwidth( + const BwEstimatorstr* bwest_str, + WebRtc_Word32* bitRate); + + /* Returns the max delay value from the other side in ms */ + WebRtc_Word32 WebRtcIsac_GetUplinkMaxDelay( + const BwEstimatorstr *bwest_str); + + + /* + * update amount of data in bottle neck buffer and burst handling + * returns minimum payload size (bytes) + */ + int WebRtcIsac_GetMinBytes( + RateModel* State, + int StreamSize, /* bytes in bitstream */ + const int FrameLen, /* ms per frame */ + const double BottleNeck, /* bottle neck rate; excl headers (bps) */ + const double DelayBuildUp, /* max delay from bottleneck buffering (ms) */ + enum ISACBandwidth bandwidth + /*,WebRtc_Word16 frequentLargePackets*/); + + /* + * update long-term average bitrate and amount of data in buffer + */ + void WebRtcIsac_UpdateRateModel( + RateModel* State, + int StreamSize, /* bytes in bitstream */ + const int FrameSamples, /* samples per frame */ + const double BottleNeck); /* bottle neck rate; excl headers (bps) */ + + + void WebRtcIsac_InitRateModel( + RateModel *State); + + /* Returns the new framelength value (input argument: bottle_neck) */ + int WebRtcIsac_GetNewFrameLength( + double bottle_neck, + int current_framelength); + + /* Returns the new SNR value (input argument: bottle_neck) */ + double WebRtcIsac_GetSnr( + double bottle_neck, + int new_framelength); + + + WebRtc_Word16 WebRtcIsac_UpdateUplinkJitter( + BwEstimatorstr* bwest_str, + WebRtc_Word32 index); + +#if defined(__cplusplus) +} +#endif + + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/main/source/codec.h b/src/modules/audio_coding/codecs/isac/main/source/codec.h new file mode 100644 index 0000000000..0b4d862056 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/codec.h @@ -0,0 +1,217 @@ +/* + * 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. + */ + +/* + * codec.h + * + * This header file contains the calls to the internal encoder + * and decoder functions. + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_ + +#include "structs.h" + + +void WebRtcIsac_ResetBitstream(Bitstr* bit_stream); + +int WebRtcIsac_EstimateBandwidth(BwEstimatorstr* bwest_str, Bitstr* streamdata, + WebRtc_Word32 packet_size, + WebRtc_UWord16 rtp_seq_number, + WebRtc_UWord32 send_ts, WebRtc_UWord32 arr_ts, + enum IsacSamplingRate encoderSampRate, + enum IsacSamplingRate decoderSampRate); + +int WebRtcIsac_DecodeLb(float* signal_out, ISACLBDecStruct* ISACdec_obj, + WebRtc_Word16* current_framesamples, + WebRtc_Word16 isRCUPayload); + +int WebRtcIsac_DecodeRcuLb(float* signal_out, ISACLBDecStruct* ISACdec_obj, + WebRtc_Word16* current_framesamples); + +int WebRtcIsac_EncodeLb(float* in, ISACLBEncStruct* ISACencLB_obj, + WebRtc_Word16 codingMode, WebRtc_Word16 + bottleneckIndex); + +int WebRtcIsac_EncodeStoredDataLb(const ISAC_SaveEncData_t* ISACSavedEnc_obj, + Bitstr* ISACBitStr_obj, int BWnumber, + float scale); + +int WebRtcIsac_EncodeStoredDataUb( + const ISACUBSaveEncDataStruct* ISACSavedEnc_obj, Bitstr* bitStream, + WebRtc_Word32 jitterInfo, float scale, enum ISACBandwidth bandwidth); + +WebRtc_Word16 WebRtcIsac_GetRedPayloadUb( + const ISACUBSaveEncDataStruct* ISACSavedEncObj, Bitstr* bitStreamObj, + enum ISACBandwidth bandwidth); + +/****************************************************************************** + * WebRtcIsac_RateAllocation() + * Internal function to perform a rate-allocation for upper and lower-band, + * given a total rate. + * + * Input: + * - inRateBitPerSec : a total bit-rate in bits/sec. + * + * Output: + * - rateLBBitPerSec : a bit-rate allocated to the lower-band + * in bits/sec. + * - rateUBBitPerSec : a bit-rate 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); + + +/****************************************************************************** + * WebRtcIsac_DecodeUb16() + * + * Decode the upper-band if the codec is in 0-16 kHz mode. + * + * Input/Output: + * -ISACdec_obj : pointer to the upper-band decoder object. The + * bit-stream is stored inside the decoder object. + * + * Output: + * -signal_out : decoded audio, 480 samples 30 ms. + * + * Return value : >0 number of decoded bytes. + * <0 if an error occurred. + */ +int WebRtcIsac_DecodeUb16(float* signal_out, ISACUBDecStruct* ISACdec_obj, + WebRtc_Word16 isRCUPayload); + + +/****************************************************************************** + * WebRtcIsac_DecodeUb12() + * + * Decode the upper-band if the codec is in 0-12 kHz mode. + * + * Input/Output: + * -ISACdec_obj : pointer to the upper-band decoder object. The + * bit-stream is stored inside the decoder object. + * + * Output: + * -signal_out : decoded audio, 480 samples 30 ms. + * + * Return value : >0 number of decoded bytes. + * <0 if an error occurred. + */ +int WebRtcIsac_DecodeUb12(float* signal_out, ISACUBDecStruct* ISACdec_obj, + WebRtc_Word16 isRCUPayload); + + +/****************************************************************************** + * WebRtcIsac_EncodeUb16() + * + * Encode the upper-band if the codec is in 0-16 kHz mode. + * + * Input: + * -in : upper-band audio, 160 samples (10 ms). + * + * Input/Output: + * -ISACdec_obj : pointer to the upper-band encoder object. The + * bit-stream is stored inside the encoder object. + * + * Return value : >0 number of encoded bytes. + * <0 if an error occurred. + */ +int WebRtcIsac_EncodeUb16(float* in, ISACUBEncStruct* ISACenc_obj, + WebRtc_Word32 jitterInfo); + + +/****************************************************************************** + * WebRtcIsac_EncodeUb12() + * + * Encode the upper-band if the codec is in 0-12 kHz mode. + * + * Input: + * -in : upper-band audio, 160 samples (10 ms). + * + * Input/Output: + * -ISACdec_obj : pointer to the upper-band encoder object. The + * bit-stream is stored inside the encoder object. + * + * Return value : >0 number of encoded bytes. + * <0 if an error occurred. + */ +int WebRtcIsac_EncodeUb12(float* in, ISACUBEncStruct* ISACenc_obj, + WebRtc_Word32 jitterInfo); + +/************************** initialization functions *************************/ + +void WebRtcIsac_InitMasking(MaskFiltstr* maskdata); + +void WebRtcIsac_InitPreFilterbank(PreFiltBankstr* prefiltdata); + +void WebRtcIsac_InitPostFilterbank(PostFiltBankstr* postfiltdata); + +void WebRtcIsac_InitPitchFilter(PitchFiltstr* pitchfiltdata); + +void WebRtcIsac_InitPitchAnalysis(PitchAnalysisStruct* State); + + +/**************************** transform functions ****************************/ + +void WebRtcIsac_InitTransform(); + +void WebRtcIsac_Time2Spec(double* inre1, double* inre2, WebRtc_Word16* outre, + WebRtc_Word16* outim, FFTstr* fftstr_obj); + +void WebRtcIsac_Spec2time(double* inre, double* inim, double* outre1, + double* outre2, FFTstr* fftstr_obj); + + +/******************************* filter functions ****************************/ + +void WebRtcIsac_AllPoleFilter(double* InOut, double* Coef, int lengthInOut, + int orderCoef); + +void WebRtcIsac_AllZeroFilter(double* In, double* Coef, int lengthInOut, + int orderCoef, double* Out); + +void WebRtcIsac_ZeroPoleFilter(double* In, double* ZeroCoef, double* PoleCoef, + int lengthInOut, int orderCoef, double* Out); + + +/***************************** filterbank functions **************************/ + +void WebRtcIsac_SplitAndFilterFloat(float* in, float* LP, float* HP, + double* LP_la, double* HP_la, + PreFiltBankstr* prefiltdata); + + +void WebRtcIsac_FilterAndCombineFloat(float* InLP, float* InHP, float* Out, + PostFiltBankstr* postfiltdata); + + +/************************* normalized lattice filters ************************/ + +void WebRtcIsac_NormLatticeFilterMa(int orderCoef, float* stateF, float* stateG, + float* lat_in, double* filtcoeflo, + double* lat_out); + +void WebRtcIsac_NormLatticeFilterAr(int orderCoef, float* stateF, float* stateG, + double* lat_in, double* lo_filt_coef, + float* lat_out); + +void WebRtcIsac_Dir2Lat(double* a, int orderCoef, float* sth, float* cth); + +void WebRtcIsac_AutoCorr(double* r, const double* x, int N, int order); + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/main/source/crc.c b/src/modules/audio_coding/codecs/isac/main/source/crc.c new file mode 100644 index 0000000000..098e4b7a69 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/crc.c @@ -0,0 +1,110 @@ +/* + * 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. + */ + +#include "crc.h" +#include +#include "signal_processing_library.h" + +#define POLYNOMIAL 0x04c11db7L + + +static const WebRtc_UWord32 kCrcTable[256] = { + 0, 0x4c11db7, 0x9823b6e, 0xd4326d9, 0x130476dc, 0x17c56b6b, + 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, + 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, + 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, + 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, + 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, + 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, + 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, + 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x18aeb13, 0x54bf6a4, + 0x808d07d, 0xcc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, + 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, + 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, + 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, + 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, + 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, + 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, + 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, + 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, + 0x3f9b762c, 0x3b5a6b9b, 0x315d626, 0x7d4cb91, 0xa97ed48, 0xe56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, + 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, + 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, + 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, + 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, + 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, + 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, + 0x18197087, 0x1cd86d30, 0x29f3d35, 0x65e2082, 0xb1d065b, 0xfdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, + 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, + 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, + 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, + 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, + 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 +}; + + + + +/**************************************************************************** + * WebRtcIsac_GetCrc(...) + * + * This function returns a 32 bit CRC checksum of a bit stream + * + * Input: + * - bitstream : payload bitstream + * - len_bitstream_in_bytes : number of 8-bit words in the bit stream + * + * Output: + * - crc : checksum + * + * Return value : 0 - Ok + * -1 - Error + */ + +WebRtc_Word16 WebRtcIsac_GetCrc(const WebRtc_Word16* bitstream, + WebRtc_Word16 len_bitstream_in_bytes, + WebRtc_UWord32* crc) +{ + WebRtc_UWord8* bitstream_ptr_uw8; + WebRtc_UWord32 crc_state; + int byte_cntr; + int crc_tbl_indx; + + /* Sanity Check. */ + if (bitstream == NULL) { + return -1; + } + /* cast to UWord8 pointer */ + bitstream_ptr_uw8 = (WebRtc_UWord8 *)bitstream; + + /* initialize */ + crc_state = 0xFFFFFFFF; + + for (byte_cntr = 0; byte_cntr < len_bitstream_in_bytes; byte_cntr++) { + crc_tbl_indx = (WEBRTC_SPL_RSHIFT_U32(crc_state, 24) ^ + bitstream_ptr_uw8[byte_cntr]) & 0xFF; + crc_state = WEBRTC_SPL_LSHIFT_U32(crc_state, 8) ^ kCrcTable[crc_tbl_indx]; + } + + *crc = ~crc_state; + return 0; +} diff --git a/src/modules/audio_coding/codecs/isac/main/source/crc.h b/src/modules/audio_coding/codecs/isac/main/source/crc.h new file mode 100644 index 0000000000..015127894b --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/crc.h @@ -0,0 +1,46 @@ +/* + * 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. + */ + +/* + * crc.h + * + * Checksum functions + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_ + +#include "typedefs.h" + +/**************************************************************************** + * WebRtcIsac_GetCrc(...) + * + * This function returns a 32 bit CRC checksum of a bit stream + * + * Input: + * - encoded : payload bit stream + * - no_of_word8s : number of 8-bit words in the bit stream + * + * Output: + * - crc : checksum + * + * Return value : 0 - Ok + * -1 - Error + */ + +WebRtc_Word16 WebRtcIsac_GetCrc( + const WebRtc_Word16* encoded, + WebRtc_Word16 no_of_word8s, + WebRtc_UWord32* crc); + + + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/main/source/decode.c b/src/modules/audio_coding/codecs/isac/main/source/decode.c new file mode 100644 index 0000000000..2b06cd08d4 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/decode.c @@ -0,0 +1,299 @@ +/* + * 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. + */ + +/* + * decode_B.c + * + * This file contains definition of funtions for decoding. + * Decoding of lower-band, including normal-decoding and RCU decoding. + * 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 "codec.h" +#include "entropy_coding.h" +#include "pitch_estimator.h" +#include "bandwidth_estimator.h" +#include "structs.h" +#include "settings.h" + +#include +#include +#include + + +/* + * function to decode the bitstream + * returns the total number of bytes in the stream + */ +int WebRtcIsac_DecodeLb(float* signal_out, ISACLBDecStruct* ISACdecLB_obj, + WebRtc_Word16* current_framesamples, + WebRtc_Word16 isRCUPayload) { + int k; + int len, err; + WebRtc_Word16 bandwidthInd; + + float LP_dec_float[FRAMESAMPLES_HALF]; + float HP_dec_float[FRAMESAMPLES_HALF]; + + double LPw[FRAMESAMPLES_HALF]; + double HPw[FRAMESAMPLES_HALF]; + double LPw_pf[FRAMESAMPLES_HALF]; + + double lo_filt_coef[(ORDERLO + 1)*SUBFRAMES]; + double hi_filt_coef[(ORDERHI + 1)*SUBFRAMES]; + + double real_f[FRAMESAMPLES_HALF]; + double imag_f[FRAMESAMPLES_HALF]; + + double PitchLags[4]; + double PitchGains[4]; + double AvgPitchGain; + WebRtc_Word16 PitchGains_Q12[4]; + WebRtc_Word16 AvgPitchGain_Q12; + + float gain; + + int frame_nb; /* counter */ + int frame_mode; /* 0 30ms, 1 for 60ms */ + /* Processed_samples: 480 (30, 60 ms). Cannot take other values. */ + + WebRtcIsac_ResetBitstream(&(ISACdecLB_obj->bitstr_obj)); + + len = 0; + + /* Decode framelength and BW estimation - not used, + only for stream pointer*/ + err = WebRtcIsac_DecodeFrameLen(&ISACdecLB_obj->bitstr_obj, + current_framesamples); + if (err < 0) { + return err; + } + + /* Frame_mode: + * 0: indicates 30 ms frame (480 samples) + * 1: indicates 60 ms frame (960 samples) */ + frame_mode = *current_framesamples / MAX_FRAMESAMPLES; + + err = WebRtcIsac_DecodeSendBW(&ISACdecLB_obj->bitstr_obj, &bandwidthInd); + if (err < 0) { + return err; + } + + /* One loop if it's one frame (20 or 30ms), 2 loops if 2 frames + bundled together (60ms). */ + for (frame_nb = 0; frame_nb <= frame_mode; frame_nb++) { + /* Decode & de-quantize pitch parameters */ + err = WebRtcIsac_DecodePitchGain(&ISACdecLB_obj->bitstr_obj, + PitchGains_Q12); + if (err < 0) { + return err; + } + + err = WebRtcIsac_DecodePitchLag(&ISACdecLB_obj->bitstr_obj, PitchGains_Q12, + PitchLags); + if (err < 0) { + return err; + } + + AvgPitchGain_Q12 = (PitchGains_Q12[0] + PitchGains_Q12[1] + + PitchGains_Q12[2] + PitchGains_Q12[3]) >> 2; + + /* Decode & de-quantize filter coefficients. */ + err = WebRtcIsac_DecodeLpc(&ISACdecLB_obj->bitstr_obj, lo_filt_coef, + hi_filt_coef); + if (err < 0) { + return err; + } + /* Decode & de-quantize spectrum. */ + len = WebRtcIsac_DecodeSpec(&ISACdecLB_obj->bitstr_obj, AvgPitchGain_Q12, + kIsacLowerBand, real_f, imag_f); + if (len < 0) { + return len; + } + + /* Inverse transform. */ + WebRtcIsac_Spec2time(real_f, imag_f, LPw, HPw, + &ISACdecLB_obj->fftstr_obj); + + /* Convert PitchGains back to float for pitchfilter_post */ + for (k = 0; k < 4; k++) { + PitchGains[k] = ((float)PitchGains_Q12[k]) / 4096; + } + if (isRCUPayload) { + for (k = 0; k < 240; k++) { + LPw[k] *= RCU_TRANSCODING_SCALE_INVERSE; + HPw[k] *= RCU_TRANSCODING_SCALE_INVERSE; + } + } + + /* Inverse pitch filter. */ + WebRtcIsac_PitchfilterPost(LPw, LPw_pf, &ISACdecLB_obj->pitchfiltstr_obj, + PitchLags, PitchGains); + /* Convert AvgPitchGain back to float for computation of gain. */ + AvgPitchGain = ((float)AvgPitchGain_Q12) / 4096; + gain = 1.0f - 0.45f * (float)AvgPitchGain; + + for (k = 0; k < FRAMESAMPLES_HALF; k++) { + /* Reduce gain to compensate for pitch enhancer. */ + LPw_pf[k] *= gain; + } + + if (isRCUPayload) { + for (k = 0; k < FRAMESAMPLES_HALF; k++) { + /* Compensation for transcoding gain changes. */ + LPw_pf[k] *= RCU_TRANSCODING_SCALE; + HPw[k] *= RCU_TRANSCODING_SCALE; + } + } + /* Perceptual post-filtering (using normalized lattice filter). */ + WebRtcIsac_NormLatticeFilterAr( + ORDERLO, ISACdecLB_obj->maskfiltstr_obj.PostStateLoF, + (ISACdecLB_obj->maskfiltstr_obj).PostStateLoG, LPw_pf, lo_filt_coef, + LP_dec_float); + WebRtcIsac_NormLatticeFilterAr( + ORDERHI, ISACdecLB_obj->maskfiltstr_obj.PostStateHiF, + (ISACdecLB_obj->maskfiltstr_obj).PostStateHiG, HPw, hi_filt_coef, + HP_dec_float); + + /* Recombine the 2 bands. */ + WebRtcIsac_FilterAndCombineFloat(LP_dec_float, HP_dec_float, + signal_out + frame_nb * FRAMESAMPLES, + &ISACdecLB_obj->postfiltbankstr_obj); + } + return len; +} + + +/* + * This decode function is called when the codec is operating in 16 kHz + * bandwidth to decode the upperband, i.e. 8-16 kHz. + * + * Contrary to lower-band, the upper-band (8-16 kHz) is not split in + * frequency, but split to 12 sub-frames, i.e. twice as lower-band. + */ +int WebRtcIsac_DecodeUb16(float* signal_out, ISACUBDecStruct* ISACdecUB_obj, + WebRtc_Word16 isRCUPayload) { + int len, err; + + double halfFrameFirst[FRAMESAMPLES_HALF]; + double halfFrameSecond[FRAMESAMPLES_HALF]; + + double percepFilterParam[(UB_LPC_ORDER + 1) * (SUBFRAMES << 1) + + (UB_LPC_ORDER + 1)]; + + double real_f[FRAMESAMPLES_HALF]; + double imag_f[FRAMESAMPLES_HALF]; + const WebRtc_Word16 kAveragePitchGain = 0; /* No pitch-gain for upper-band. */ + len = 0; + + /* Decode & de-quantize filter coefficients. */ + memset(percepFilterParam, 0, sizeof(percepFilterParam)); + err = WebRtcIsac_DecodeInterpolLpcUb(&ISACdecUB_obj->bitstr_obj, + percepFilterParam, isac16kHz); + if (err < 0) { + return err; + } + + /* Decode & de-quantize spectrum. */ + len = WebRtcIsac_DecodeSpec(&ISACdecUB_obj->bitstr_obj, kAveragePitchGain, + kIsacUpperBand16, real_f, imag_f); + if (len < 0) { + return len; + } + if (isRCUPayload) { + int n; + for (n = 0; n < 240; n++) { + real_f[n] *= RCU_TRANSCODING_SCALE_UB_INVERSE; + imag_f[n] *= RCU_TRANSCODING_SCALE_UB_INVERSE; + } + } + /* Inverse transform. */ + WebRtcIsac_Spec2time(real_f, imag_f, halfFrameFirst, halfFrameSecond, + &ISACdecUB_obj->fftstr_obj); + + /* Perceptual post-filtering (using normalized lattice filter). */ + WebRtcIsac_NormLatticeFilterAr( + UB_LPC_ORDER, ISACdecUB_obj->maskfiltstr_obj.PostStateLoF, + (ISACdecUB_obj->maskfiltstr_obj).PostStateLoG, halfFrameFirst, + &percepFilterParam[(UB_LPC_ORDER + 1)], signal_out); + + WebRtcIsac_NormLatticeFilterAr( + UB_LPC_ORDER, ISACdecUB_obj->maskfiltstr_obj.PostStateLoF, + (ISACdecUB_obj->maskfiltstr_obj).PostStateLoG, halfFrameSecond, + &percepFilterParam[(UB_LPC_ORDER + 1) * SUBFRAMES + (UB_LPC_ORDER + 1)], + &signal_out[FRAMESAMPLES_HALF]); + + return len; +} + +/* + * This decode function is called when the codec operates at 0-12 kHz + * bandwidth to decode the upperband, i.e. 8-12 kHz. + * + * At the encoder the upper-band is split into two band, 8-12 kHz & 12-16 + * kHz, and only 8-12 kHz is encoded. At the decoder, 8-12 kHz band is + * reconstructed and 12-16 kHz replaced with zeros. Then two bands + * are combined, to reconstruct the upperband 8-16 kHz. + */ +int WebRtcIsac_DecodeUb12(float* signal_out, ISACUBDecStruct* ISACdecUB_obj, + WebRtc_Word16 isRCUPayload) { + int len, err; + + float LP_dec_float[FRAMESAMPLES_HALF]; + float HP_dec_float[FRAMESAMPLES_HALF]; + + double LPw[FRAMESAMPLES_HALF]; + double HPw[FRAMESAMPLES_HALF]; + + double percepFilterParam[(UB_LPC_ORDER + 1)*SUBFRAMES]; + + double real_f[FRAMESAMPLES_HALF]; + double imag_f[FRAMESAMPLES_HALF]; + const WebRtc_Word16 kAveragePitchGain = 0; /* No pitch-gain for upper-band. */ + len = 0; + + /* Decode & dequantize filter coefficients. */ + err = WebRtcIsac_DecodeInterpolLpcUb(&ISACdecUB_obj->bitstr_obj, + percepFilterParam, isac12kHz); + if (err < 0) { + return err; + } + + /* Decode & de-quantize spectrum. */ + len = WebRtcIsac_DecodeSpec(&ISACdecUB_obj->bitstr_obj, kAveragePitchGain, + kIsacUpperBand12, real_f, imag_f); + if (len < 0) { + return len; + } + + if (isRCUPayload) { + int n; + for (n = 0; n < 240; n++) { + real_f[n] *= RCU_TRANSCODING_SCALE_UB_INVERSE; + imag_f[n] *= RCU_TRANSCODING_SCALE_UB_INVERSE; + } + } + /* Inverse transform. */ + WebRtcIsac_Spec2time(real_f, imag_f, LPw, HPw, &ISACdecUB_obj->fftstr_obj); + /* perceptual post-filtering (using normalized lattice filter) */ + WebRtcIsac_NormLatticeFilterAr(UB_LPC_ORDER, + ISACdecUB_obj->maskfiltstr_obj.PostStateLoF, + (ISACdecUB_obj->maskfiltstr_obj).PostStateLoG, + LPw, percepFilterParam, LP_dec_float); + /* Zero for 12-16 kHz. */ + memset(HP_dec_float, 0, sizeof(float) * (FRAMESAMPLES_HALF)); + /* Recombine the 2 bands. */ + WebRtcIsac_FilterAndCombineFloat(HP_dec_float, LP_dec_float, signal_out, + &ISACdecUB_obj->postfiltbankstr_obj); + return len; +} diff --git a/src/modules/audio_coding/codecs/isac/main/source/decode_bwe.c b/src/modules/audio_coding/codecs/isac/main/source/decode_bwe.c new file mode 100644 index 0000000000..cdac7fa8bf --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/decode_bwe.c @@ -0,0 +1,88 @@ +/* + * 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. + */ + +#include "structs.h" +#include "bandwidth_estimator.h" +#include "entropy_coding.h" +#include "codec.h" + + +int +WebRtcIsac_EstimateBandwidth( + BwEstimatorstr* bwest_str, + Bitstr* streamdata, + WebRtc_Word32 packet_size, + WebRtc_UWord16 rtp_seq_number, + WebRtc_UWord32 send_ts, + WebRtc_UWord32 arr_ts, + enum IsacSamplingRate encoderSampRate, + enum IsacSamplingRate decoderSampRate) +{ + WebRtc_Word16 index; + WebRtc_Word16 frame_samples; + WebRtc_UWord32 sendTimestampIn16kHz; + WebRtc_UWord32 arrivalTimestampIn16kHz; + WebRtc_UWord32 diffSendTime; + WebRtc_UWord32 diffArrivalTime; + int err; + + /* decode framelength and BW estimation */ + err = WebRtcIsac_DecodeFrameLen(streamdata, &frame_samples); + if(err < 0) // error check + { + return err; + } + err = WebRtcIsac_DecodeSendBW(streamdata, &index); + if(err < 0) // error check + { + return err; + } + + /* UPDATE ESTIMATES FROM OTHER SIDE */ + err = WebRtcIsac_UpdateUplinkBwImpl(bwest_str, index, encoderSampRate); + if(err < 0) + { + return err; + } + + // We like BWE to work at 16 kHz sampling rate, + // therefore, we have to change the timestamps accordingly. + // translate the send timestamp if required + diffSendTime = (WebRtc_UWord32)((WebRtc_UWord32)send_ts - + (WebRtc_UWord32)bwest_str->senderTimestamp); + bwest_str->senderTimestamp = send_ts; + + diffArrivalTime = (WebRtc_UWord32)((WebRtc_UWord32)arr_ts - + (WebRtc_UWord32)bwest_str->receiverTimestamp); + bwest_str->receiverTimestamp = arr_ts; + + if(decoderSampRate == kIsacSuperWideband) + { + diffArrivalTime = (WebRtc_UWord32)diffArrivalTime >> 1; + diffSendTime = (WebRtc_UWord32)diffSendTime >> 1; + } + // arrival timestamp in 16 kHz + arrivalTimestampIn16kHz = (WebRtc_UWord32)((WebRtc_UWord32) + bwest_str->prev_rec_arr_ts + (WebRtc_UWord32)diffArrivalTime); + // send timestamp in 16 kHz + sendTimestampIn16kHz = (WebRtc_UWord32)((WebRtc_UWord32) + bwest_str->prev_rec_send_ts + (WebRtc_UWord32)diffSendTime); + + err = WebRtcIsac_UpdateBandwidthEstimator(bwest_str, rtp_seq_number, + (frame_samples * 1000) / FS, sendTimestampIn16kHz, + arrivalTimestampIn16kHz, packet_size); + // error check + if(err < 0) + { + return err; + } + + return 0; +} diff --git a/src/modules/audio_coding/codecs/isac/main/source/encode.c b/src/modules/audio_coding/codecs/isac/main/source/encode.c new file mode 100644 index 0000000000..f6bdc17d11 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/encode.c @@ -0,0 +1,1252 @@ +/* + * 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. + */ + +/* + * 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 +#include +#include + +#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 + 'kLowerBandBitRate12' and '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 50 kbps and 56 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 'kLowerBandBitRate16' and + 'kUpperBandBitRate16' 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 kLowerBandBitRate12[7] = { + 29000, 30000, 30000, 31000, 31000, 32000, 32000 }; +static const WebRtc_Word16 kUpperBandBitRate12[7] = { + 25000, 25000, 27000, 27000, 29000, 29000, 32000 }; + +/* 50 51.2 52.4 53.6 54.8 56 */ +static const WebRtc_Word16 kLowerBandBitRate16[6] = { + 31000, 31000, 32000, 32000, 32000, 32000 }; +static const WebRtc_Word16 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 = kLowerBandBitRate12[idx]; + *rateUBBitPerSec = kUpperBandBitRate12[idx]; + + if (idx < 6) { + *rateLBBitPerSec += (WebRtc_Word16)( + idxErr * (kLowerBandBitRate12[idx + 1] - kLowerBandBitRate12[idx])); + *rateUBBitPerSec += (WebRtc_Word16)( + idxErr * (kUpperBandBitRate12[idx + 1] - 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 = kLowerBandBitRate16[idx]; + *rateUBBitPerSec = kUpperBandBitRate16[idx]; + + if (idx < 5) { + *rateLBBitPerSec += (WebRtc_Word16)(idxErr * + (kLowerBandBitRate16[idx + 1] - + kLowerBandBitRate16[idx])); + + *rateUBBitPerSec += (WebRtc_Word16)(idxErr * + (kUpperBandBitRate16[idx + 1] - + 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; +} + + +void WebRtcIsac_ResetBitstream(Bitstr* bit_stream) { + bit_stream->W_upper = 0xFFFFFFFF; + bit_stream->stream_index = 0; + bit_stream->streamval = 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 status = 0; + int my_index; + transcode_obj transcodingParam; + double bytesLeftSpecCoding; + WebRtc_UWord16 payloadLimitBytes; + + /* Copy new frame-length and bottleneck 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; + + /* buffer speech samples (by 10ms packet) until the frame-length */ + /* 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 != FRAMESAMPLES) { + 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 */ + WebRtcIsac_ResetBitstream(&(ISACencLB_obj->bitstr_obj)); + + 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, &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, + &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. */ + my_index = ISACencLB_obj->SaveEnc_obj.startIdx * FRAMESAMPLES_HALF; + memcpy(&ISACencLB_obj->SaveEnc_obj.fre[my_index], fre, sizeof(fre)); + memcpy(&ISACencLB_obj->SaveEnc_obj.fim[my_index], fim, sizeof(fim)); + + ISACencLB_obj->SaveEnc_obj.AvgPitchGain[ISACencLB_obj->SaveEnc_obj.startIdx] = + AvgPitchGain_Q12; + + /* Quantization and loss-less coding. */ + err = WebRtcIsac_EncodeSpec(fre, fim, AvgPitchGain_Q12, kIsacLowerBand, + &ISACencLB_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). */ + 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 conservative */ + 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. */ + my_index = ISACencLB_obj->SaveEnc_obj.startIdx * FRAMESAMPLES_HALF; + memcpy(&ISACencLB_obj->SaveEnc_obj.fre[my_index], fre, sizeof(fre)); + memcpy(&ISACencLB_obj->SaveEnc_obj.fim[my_index], fim, sizeof(fim)); + + /* 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, + &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_EncodeSpec(fre, fim, AvgPitchGain_Q12, kIsacLowerBand, + &ISACencLB_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). */ + if (frame_mode == 1 && ISACencLB_obj->frame_nb == 1) { + /* If this is the second 30 ms of a 60 ms frame reset + this such that in the next call encoder starts fresh. */ + ISACencLB_obj->frame_nb = 0; + } + return err; + } + iterCntr++; + } + + /* If 60 ms frame-size and just processed the first 30 ms, */ + /* go back to main function to buffer the other 30 ms 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 frame-length 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; +} + + + +static int LimitPayloadUb(ISACUBEncStruct* ISACencUB_obj, + WebRtc_UWord16 payloadLimitBytes, + double bytesLeftSpecCoding, + transcode_obj* transcodingParam, + WebRtc_Word16* fre, WebRtc_Word16* fim, + double* lpcGains, enum ISACBand band, int status) { + + int iterCntr = 0; + int k; + double bytesSpecCoderUsed; + double transcodeScale; + const WebRtc_Word16 kAveragePitchGain = 0.0; + + do { + if (iterCntr >= MAX_PAYLOAD_LIMIT_ITERATION) { + /* We were not able to limit the payload size. */ + return -ISAC_PAYLOAD_LARGER_THAN_LIMIT; + } + + if (status == -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. */ + if (band == kIsacUpperBand16) { + /* Two sets of coefficients if 16 kHz. */ + for (k = 0; k < SUBFRAMES; k++) { + transcodingParam->loFiltGain[k] *= transcodeScale; + transcodingParam->hiFiltGain[k] *= transcodeScale; + } + } else { + /* One sets of coefficients if 12 kHz. */ + 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 FFT coefficients for multiple encoding. */ + memcpy(ISACencUB_obj->SaveEnc_obj.realFFT, fre, + sizeof(ISACencUB_obj->SaveEnc_obj.realFFT)); + memcpy(ISACencUB_obj->SaveEnc_obj.imagFFT, fim, + sizeof(ISACencUB_obj->SaveEnc_obj.imagFFT)); + + /* 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)); + /* Entropy Code lpc-gains, indices are stored for a later use.*/ + WebRtcIsac_EncodeLpcGainUb(transcodingParam->loFiltGain, + &ISACencUB_obj->bitstr_obj, + ISACencUB_obj->SaveEnc_obj.lpcGainIndex); + + /* If 16kHz should do one more set. */ + if (band == kIsacUpperBand16) { + /* Store the gains for multiple encoding. */ + memcpy(&ISACencUB_obj->SaveEnc_obj.lpcGain[SUBFRAMES], + &lpcGains[SUBFRAMES], SUBFRAMES * sizeof(double)); + /* Entropy Code lpc-gains, indices are stored for a later use.*/ + 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. */ + status = WebRtcIsac_EncodeSpec(fre, fim, kAveragePitchGain, + band, &ISACencUB_obj->bitstr_obj); + if ((status < 0) && (status != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) { + /* There has been an error but it was not too large payload + (we can cure too large payload). */ + return status; + } + iterCntr++; + } while ((ISACencUB_obj->bitstr_obj.stream_index > payloadLimitBytes) || + (status == -ISAC_DISALLOWED_BITSTREAM_LENGTH)); + return 0; +} + +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; + WebRtc_UWord16 payloadLimitBytes; + double s2nr; + const WebRtc_Word16 kAveragePitchGain = 0.0; + int bytesLeftSpecCoding; + + /* Buffer speech samples (by 10ms packet) until the frame-length is */ + /* reached (30 ms). */ + /*********************************************************************/ + + /* fill the buffer with 10ms input data */ + memcpy(&ISACencUB_obj->data_buffer_float[ISACencUB_obj->buffer_index], in, + FRAMESAMPLES_10ms * sizeof(float)); + + /* If buffer size is not equal to current frame-size, 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 bit-stream */ + WebRtcIsac_ResetBitstream(&(ISACencUB_obj->bitstr_obj)); + + /* Encoding of bandwidth information. */ + 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]; + } + + /* LPC filtering (using normalized lattice filter), */ + /* first half-frame. */ + 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, sizeof(fre)); + memcpy(ISACencUB_obj->SaveEnc_obj.imagFFT, fim, sizeof(fim)); + + /* 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)); + + /* Qantization and lossless coding */ + /* Note that there is no pitch-gain for this band so kAveragePitchGain = 0 + * is passed to the function. In fact, the function ignores the 3rd parameter + * for this band. */ + err = WebRtcIsac_EncodeSpec(fre, fim, kAveragePitchGain, kIsacUpperBand16, + &ISACencUB_obj->bitstr_obj); + if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) { + return err; + } + + if ((ISACencUB_obj->bitstr_obj.stream_index > payloadLimitBytes) || + (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH)) { + err = LimitPayloadUb(ISACencUB_obj, payloadLimitBytes, bytesLeftSpecCoding, + &transcodingParam, fre, fim, lpcGains, + kIsacUpperBand16, err); + } + if (err < 0) { + return err; + } + /* 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; + + 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 */ + + int status = 0; + + double varscale[1]; + + double corr[UB_LPC_GAIN_DIM][UB_LPC_ORDER + 1]; + double lpcGains[SUBFRAMES]; + transcode_obj transcodingParam; + WebRtc_UWord16 payloadLimitBytes; + double s2nr; + const WebRtc_Word16 kAveragePitchGain = 0.0; + double bytesLeftSpecCoding; + + /* Buffer speech samples (by 10ms packet) until the framelength is */ + /* reached (30 ms). */ + /********************************************************************/ + + /* Fill the buffer with 10ms input data. */ + memcpy(&ISACencUB_obj->data_buffer_float[ISACencUB_obj->buffer_index], in, + FRAMESAMPLES_10ms * sizeof(float)); + + /* 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 bit-stream. */ + WebRtcIsac_ResetBitstream(&(ISACencUB_obj->bitstr_obj)); + + /* Encoding bandwidth information. */ + 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); + + /* 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(HPw)); + + /* Transform */ + WebRtcIsac_Time2Spec(LPw, HPw, fre, fim, &ISACencUB_obj->fftstr_obj); + + /* Store FFT coefficients for multiple encoding. */ + memcpy(ISACencUB_obj->SaveEnc_obj.realFFT, fre, + sizeof(ISACencUB_obj->SaveEnc_obj.realFFT)); + memcpy(ISACencUB_obj->SaveEnc_obj.imagFFT, fim, + sizeof(ISACencUB_obj->SaveEnc_obj.imagFFT)); + + /* Save the bit-stream object at this point for FEC. */ + memcpy(&ISACencUB_obj->SaveEnc_obj.bitStreamObj, + &ISACencUB_obj->bitstr_obj, sizeof(Bitstr)); + + /* Quantization and loss-less coding */ + /* The 4th parameter to this function is pitch-gain, which is only used + * when encoding 0-8 kHz band, and irrelevant in this function, therefore, + * we insert zero here. */ + err = WebRtcIsac_EncodeSpec(fre, fim, kAveragePitchGain, kIsacUpperBand12, + &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; + } + + if ((ISACencUB_obj->bitstr_obj.stream_index > payloadLimitBytes) || + (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH)) { + err = LimitPayloadUb(ISACencUB_obj, payloadLimitBytes, bytesLeftSpecCoding, + &transcodingParam, fre, fim, lpcGains, + kIsacUpperBand12, err); + } + if (err < 0) { + return err; + } + /* Complete arithmetic coding. */ + return WebRtcIsac_EncTerminate(&ISACencUB_obj->bitstr_obj); +} + + + + + + +/* This function is used to create a new bit-stream with new BWE. + The same data as previously encoded with the function WebRtcIsac_Encoder(). + The data needed is taken from the structure, 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]; + const int kModel = 0; + + /* Sanity Check - possible values for BWnumber is 0 - 23. */ + if ((BWnumber < 0) || (BWnumber > 23)) { + return -ISAC_RANGE_ERROR_BW_ESTIMATOR; + } + + /* Reset bit-stream. */ + WebRtcIsac_ResetBitstream(ISACBitStr_obj); + + /* 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 classification. */ + 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 */ + /* Only one model exists. The entropy coding is done only for backward + * compatibility. */ + WebRtcIsac_EncHistMulti(ISACBitStr_obj, &kModel, + 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, + 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], + &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, KLT_ORDER_GAIN); + + /* Quantization and loss-less coding. */ + status = WebRtcIsac_EncodeSpec(&tmp_fre[ii * FRAMESAMPLES_HALF], + &tmp_fim[ii * FRAMESAMPLES_HALF], + ISACSavedEnc_obj->AvgPitchGain[ii], + kIsacLowerBand, ISACBitStr_obj); + if (status < 0) { + return status; + } + } + /* Complete arithmetic coding. */ + return WebRtcIsac_EncTerminate(ISACBitStr_obj); +} + + +int WebRtcIsac_EncodeStoredDataUb( + const ISACUBSaveEncDataStruct* ISACSavedEnc_obj, + Bitstr* bitStream, + WebRtc_Word32 jitterInfo, + float scale, + enum ISACBandwidth bandwidth) { + int n; + int err; + double lpcGain[SUBFRAMES]; + WebRtc_Word16 realFFT[FRAMESAMPLES_HALF]; + WebRtc_Word16 imagFFT[FRAMESAMPLES_HALF]; + const WebRtc_UWord16** shape_cdf; + int shape_len; + const WebRtc_Word16 kAveragePitchGain = 0.0; + enum ISACBand band; + /* Reset bitstream. */ + WebRtcIsac_ResetBitstream(bitStream); + + /* Encode jitter index. */ + WebRtcIsac_EncodeJitterInfo(jitterInfo, bitStream); + + err = WebRtcIsac_EncodeBandwidth(bandwidth, bitStream); + if (err < 0) { + return err; + } + + /* Encode LPC-shape. */ + if (bandwidth == isac12kHz) { + shape_cdf = WebRtcIsac_kLpcShapeCdfMatUb12; + shape_len = UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME; + band = kIsacUpperBand12; + } else { + shape_cdf = WebRtcIsac_kLpcShapeCdfMatUb16; + shape_len = UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME; + band = kIsacUpperBand16; + } + WebRtcIsac_EncHistMulti(bitStream, ISACSavedEnc_obj->indexLPCShape, + shape_cdf, shape_len); + + if ((scale <= 0.0) || (scale >= 1.0)) { + /* We only consider scales between zero and one. */ + WebRtcIsac_EncHistMulti(bitStream, ISACSavedEnc_obj->lpcGainIndex, + WebRtcIsac_kLpcGainCdfMat, UB_LPC_GAIN_DIM); + if (bandwidth == isac16kHz) { + /* Store gain indices of the second half. */ + WebRtcIsac_EncHistMulti(bitStream, + &ISACSavedEnc_obj->lpcGainIndex[SUBFRAMES], + WebRtcIsac_kLpcGainCdfMat, UB_LPC_GAIN_DIM); + } + /* Store FFT coefficients. */ + err = WebRtcIsac_EncodeSpec(ISACSavedEnc_obj->realFFT, + ISACSavedEnc_obj->imagFFT, kAveragePitchGain, + band, bitStream); + } else { + /* Scale LPC gain and FFT coefficients. */ + for (n = 0; n < SUBFRAMES; n++) { + lpcGain[n] = scale * ISACSavedEnc_obj->lpcGain[n]; + } + /* Store LPC gains. */ + WebRtcIsac_StoreLpcGainUb(lpcGain, bitStream); + + if (bandwidth == isac16kHz) { + /* Scale and code the gains of the second half of the frame, if 16kHz. */ + for (n = 0; n < SUBFRAMES; n++) { + lpcGain[n] = scale * ISACSavedEnc_obj->lpcGain[n + SUBFRAMES]; + } + WebRtcIsac_StoreLpcGainUb(lpcGain, bitStream); + } + + for (n = 0; n < FRAMESAMPLES_HALF; 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_EncodeSpec(realFFT, imagFFT, kAveragePitchGain, + band, 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]; + enum ISACBand band; + const WebRtc_Word16 kAveragePitchGain = 0.0; + /* 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); + } + + band = (bandwidth == isac12kHz) ? kIsacUpperBand12 : kIsacUpperBand16; + status = WebRtcIsac_EncodeSpec(realFFT, imagFFT, kAveragePitchGain, band, + bitStreamObj); + if (status < 0) { + return status; + } else { + /* Terminate entropy coding */ + return WebRtcIsac_EncTerminate(bitStreamObj); + } +} diff --git a/src/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.c b/src/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.c new file mode 100644 index 0000000000..2bf4c36460 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.c @@ -0,0 +1,708 @@ +/* + * 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. + */ + +/* + * code_LPC_UB.c + * + * This file contains definition of functions used to + * encode LPC parameters (Shape & gain) of the upper band. + * + */ + +#include "encode_lpc_swb.h" +#include "typedefs.h" +#include "settings.h" + +#include "lpc_shape_swb12_tables.h" +#include "lpc_shape_swb16_tables.h" +#include "lpc_gain_swb_tables.h" + +#include +#include +#include + +/****************************************************************************** + * WebRtcIsac_RemoveLarMean() + * + * Remove the means from LAR coefficients. + * + * Input: + * -lar : pointer to lar vectors. LAR vectors are + * concatenated. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -lar : pointer to mean-removed LAR:s. + * + * + */ +WebRtc_Word16 +WebRtcIsac_RemoveLarMean( + double* lar, + WebRtc_Word16 bandwidth) +{ + WebRtc_Word16 coeffCntr; + WebRtc_Word16 vecCntr; + WebRtc_Word16 numVec; + const double* meanLAR; + switch(bandwidth) + { + case isac12kHz: + { + numVec = UB_LPC_VEC_PER_FRAME; + meanLAR = WebRtcIsac_kMeanLarUb12; + break; + } + case isac16kHz: + { + numVec = UB16_LPC_VEC_PER_FRAME; + meanLAR = WebRtcIsac_kMeanLarUb16; + break; + } + default: + return -1; + } + + for(vecCntr = 0; vecCntr < numVec; vecCntr++) + { + for(coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++) + { + // REMOVE MEAN + *lar++ -= meanLAR[coeffCntr]; + } + } + return 0; +} + +/****************************************************************************** + * WebRtcIsac_DecorrelateIntraVec() + * + * Remove the correlation amonge the components of LAR vectors. If LAR vectors + * of one frame are put in a matrix where each column is a LAR vector of a + * sub-frame, then this is equivalent to multiplying the LAR matrix with + * a decorrelting mtrix from left. + * + * Input: + * -inLar : pointer to mean-removed LAR vecrtors. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -out : decorrelated LAR vectors. + */ +WebRtc_Word16 +WebRtcIsac_DecorrelateIntraVec( + const double* data, + double* out, + WebRtc_Word16 bandwidth) +{ + const double* ptrData; + const double* ptrRow; + WebRtc_Word16 rowCntr; + WebRtc_Word16 colCntr; + WebRtc_Word16 larVecCntr; + WebRtc_Word16 numVec; + const double* decorrMat; + switch(bandwidth) + { + case isac12kHz: + { + decorrMat = &WebRtcIsac_kIntraVecDecorrMatUb12[0][0]; + numVec = UB_LPC_VEC_PER_FRAME; + break; + } + case isac16kHz: + { + decorrMat = &WebRtcIsac_kIintraVecDecorrMatUb16[0][0]; + numVec = UB16_LPC_VEC_PER_FRAME; + break; + } + default: + return -1; + } + + // + // decorrMat * data + // + // data is assumed to contain 'numVec' of LAR + // vectors (mean removed) each of dimension 'UB_LPC_ORDER' + // concatenated one after the other. + // + + ptrData = data; + for(larVecCntr = 0; larVecCntr < numVec; larVecCntr++) + { + for(rowCntr = 0; rowCntr < UB_LPC_ORDER; rowCntr++) + { + ptrRow = &decorrMat[rowCntr * UB_LPC_ORDER]; + *out = 0; + for(colCntr = 0; colCntr < UB_LPC_ORDER; colCntr++) + { + *out += ptrData[colCntr] * ptrRow[colCntr]; + } + out++; + } + ptrData += UB_LPC_ORDER; + } + return 0; +} + +/****************************************************************************** + * WebRtcIsac_DecorrelateInterVec() + * + * Remover the correlation among mean-removed LAR vectors. If LAR vectors + * of one frame are put in a matrix where each column is a LAR vector of a + * sub-frame, then this is equivalent to multiplying the LAR matrix with + * a decorrelting mtrix from right. + * + * Input: + * -data : pointer to matrix of LAR vectors. The matrix + * is stored column-wise. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -out : decorrelated LAR vectors. + */ +WebRtc_Word16 +WebRtcIsac_DecorrelateInterVec( + const double* data, + double* out, + WebRtc_Word16 bandwidth) +{ + WebRtc_Word16 coeffCntr; + WebRtc_Word16 rowCntr; + WebRtc_Word16 colCntr; + const double* decorrMat; + WebRtc_Word16 interVecDim; + + switch(bandwidth) + { + case isac12kHz: + { + decorrMat = &WebRtcIsac_kInterVecDecorrMatUb12[0][0]; + interVecDim = UB_LPC_VEC_PER_FRAME; + break; + } + case isac16kHz: + { + decorrMat = &WebRtcIsac_kInterVecDecorrMatUb16[0][0]; + interVecDim = UB16_LPC_VEC_PER_FRAME; + break; + } + default: + return -1; + } + + // + // data * decorrMat + // + // data is of size 'interVecDim' * 'UB_LPC_ORDER' + // That is 'interVecDim' of LAR vectors (mean removed) + // in columns each of dimension 'UB_LPC_ORDER'. + // matrix is stored column-wise. + // + + for(coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++) + { + for(colCntr = 0; colCntr < interVecDim; colCntr++) + { + out[coeffCntr + colCntr * UB_LPC_ORDER] = 0; + for(rowCntr = 0; rowCntr < interVecDim; rowCntr++) + { + out[coeffCntr + colCntr * UB_LPC_ORDER] += + data[coeffCntr + rowCntr * UB_LPC_ORDER] * + decorrMat[rowCntr * interVecDim + colCntr]; + } + } + } + return 0; +} + +/****************************************************************************** + * WebRtcIsac_QuantizeUncorrLar() + * + * Quantize the uncorrelated parameters. + * + * Input: + * -data : uncorrelated LAR vectors. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -data : quantized version of the input. + * -idx : pointer to quantization indices. + */ +double +WebRtcIsac_QuantizeUncorrLar( + double* data, + int* recIdx, + WebRtc_Word16 bandwidth) +{ + WebRtc_Word16 cntr; + WebRtc_Word32 idx; + WebRtc_Word16 interVecDim; + const double* leftRecPoint; + double quantizationStepSize; + const WebRtc_Word16* numQuantCell; + switch(bandwidth) + { + case isac12kHz: + { + leftRecPoint = WebRtcIsac_kLpcShapeLeftRecPointUb12; + quantizationStepSize = WebRtcIsac_kLpcShapeQStepSizeUb12; + numQuantCell = WebRtcIsac_kLpcShapeNumRecPointUb12; + interVecDim = UB_LPC_VEC_PER_FRAME; + break; + } + case isac16kHz: + { + leftRecPoint = WebRtcIsac_kLpcShapeLeftRecPointUb16; + quantizationStepSize = WebRtcIsac_kLpcShapeQStepSizeUb16; + numQuantCell = WebRtcIsac_kLpcShapeNumRecPointUb16; + interVecDim = UB16_LPC_VEC_PER_FRAME; + break; + } + default: + return -1; + } + + // + // Quantize the parametrs. + // + for(cntr = 0; cntr < UB_LPC_ORDER * interVecDim; cntr++) + { + idx = (WebRtc_Word32)floor((*data - leftRecPoint[cntr]) / + quantizationStepSize + 0.5); + if(idx < 0) + { + idx = 0; + } + else if(idx >= numQuantCell[cntr]) + { + idx = numQuantCell[cntr] - 1; + } + + *data++ = leftRecPoint[cntr] + idx * quantizationStepSize; + *recIdx++ = idx; + } + return 0; +} + + +/****************************************************************************** + * WebRtcIsac_DequantizeLpcParam() + * + * Get the quantized value of uncorrelated LARs given the quantization indices. + * + * Input: + * -idx : pointer to quantiztion indices. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -out : pointer to quantized values. + */ +WebRtc_Word16 +WebRtcIsac_DequantizeLpcParam( + const int* idx, + double* out, + WebRtc_Word16 bandwidth) +{ + WebRtc_Word16 cntr; + WebRtc_Word16 interVecDim; + const double* leftRecPoint; + double quantizationStepSize; + + switch(bandwidth) + { + case isac12kHz: + { + leftRecPoint = WebRtcIsac_kLpcShapeLeftRecPointUb12; + quantizationStepSize = WebRtcIsac_kLpcShapeQStepSizeUb12; + interVecDim = UB_LPC_VEC_PER_FRAME; + break; + } + case isac16kHz: + { + leftRecPoint = WebRtcIsac_kLpcShapeLeftRecPointUb16; + quantizationStepSize = WebRtcIsac_kLpcShapeQStepSizeUb16; + interVecDim = UB16_LPC_VEC_PER_FRAME; + break; + } + default: + return -1; + } + + // + // Dequantize given the quantization indices + // + + for(cntr = 0; cntr < UB_LPC_ORDER * interVecDim; cntr++) + { + *out++ = leftRecPoint[cntr] + *idx++ * quantizationStepSize; + } + return 0; +} + + +/****************************************************************************** + * WebRtcIsac_CorrelateIntraVec() + * + * This is the inverse of WebRtcIsac_DecorrelateIntraVec(). + * + * Input: + * -data : uncorrelated parameters. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -out : correlated parametrs. + */ +WebRtc_Word16 +WebRtcIsac_CorrelateIntraVec( + const double* data, + double* out, + WebRtc_Word16 bandwidth) +{ + WebRtc_Word16 vecCntr; + WebRtc_Word16 rowCntr; + WebRtc_Word16 colCntr; + WebRtc_Word16 numVec; + const double* ptrData; + const double* intraVecDecorrMat; + + switch(bandwidth) + { + case isac12kHz: + { + numVec = UB_LPC_VEC_PER_FRAME; + intraVecDecorrMat = &WebRtcIsac_kIntraVecDecorrMatUb12[0][0]; + break; + } + case isac16kHz: + { + numVec = UB16_LPC_VEC_PER_FRAME; + intraVecDecorrMat = &WebRtcIsac_kIintraVecDecorrMatUb16[0][0]; + break; + } + default: + return -1; + } + + + ptrData = data; + for(vecCntr = 0; vecCntr < numVec; vecCntr++) + { + for(colCntr = 0; colCntr < UB_LPC_ORDER; colCntr++) + { + *out = 0; + for(rowCntr = 0; rowCntr < UB_LPC_ORDER; rowCntr++) + { + *out += ptrData[rowCntr] * + intraVecDecorrMat[rowCntr * UB_LPC_ORDER + colCntr]; + } + out++; + } + ptrData += UB_LPC_ORDER; + } + return 0; +} + +/****************************************************************************** + * WebRtcIsac_CorrelateInterVec() + * + * This is the inverse of WebRtcIsac_DecorrelateInterVec(). + * + * Input: + * -data + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -out : correlated parametrs. + */ +WebRtc_Word16 +WebRtcIsac_CorrelateInterVec( + const double* data, + double* out, + WebRtc_Word16 bandwidth) +{ + WebRtc_Word16 coeffCntr; + WebRtc_Word16 rowCntr; + WebRtc_Word16 colCntr; + WebRtc_Word16 interVecDim; + double myVec[UB16_LPC_VEC_PER_FRAME]; + const double* interVecDecorrMat; + + switch(bandwidth) + { + case isac12kHz: + { + interVecDim = UB_LPC_VEC_PER_FRAME; + interVecDecorrMat = &WebRtcIsac_kInterVecDecorrMatUb12[0][0]; + break; + } + case isac16kHz: + { + interVecDim = UB16_LPC_VEC_PER_FRAME; + interVecDecorrMat = &WebRtcIsac_kInterVecDecorrMatUb16[0][0]; + break; + } + default: + return -1; + } + + for(coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++) + { + for(rowCntr = 0; rowCntr < interVecDim; rowCntr++) + { + myVec[rowCntr] = 0; + for(colCntr = 0; colCntr < interVecDim; colCntr++) + { + myVec[rowCntr] += data[coeffCntr + colCntr * UB_LPC_ORDER] * //*ptrData * + interVecDecorrMat[rowCntr * interVecDim + colCntr]; + //ptrData += UB_LPC_ORDER; + } + } + + for(rowCntr = 0; rowCntr < interVecDim; rowCntr++) + { + out[coeffCntr + rowCntr * UB_LPC_ORDER] = myVec[rowCntr]; + } + } + return 0; +} + +/****************************************************************************** + * WebRtcIsac_AddLarMean() + * + * This is the inverse of WebRtcIsac_RemoveLarMean() + * + * Input: + * -data : pointer to mean-removed LAR:s. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -data : pointer to LARs. + */ +WebRtc_Word16 +WebRtcIsac_AddLarMean( + double* data, + WebRtc_Word16 bandwidth) +{ + WebRtc_Word16 coeffCntr; + WebRtc_Word16 vecCntr; + WebRtc_Word16 numVec; + const double* meanLAR; + + switch(bandwidth) + { + case isac12kHz: + { + numVec = UB_LPC_VEC_PER_FRAME; + meanLAR = WebRtcIsac_kMeanLarUb12; + break; + } + case isac16kHz: + { + numVec = UB16_LPC_VEC_PER_FRAME; + meanLAR = WebRtcIsac_kMeanLarUb16; + break; + } + default: + return -1; + } + + for(vecCntr = 0; vecCntr < numVec; vecCntr++) + { + for(coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++) + { + *data++ += meanLAR[coeffCntr]; + } + } + return 0; +} + +/****************************************************************************** + * WebRtcIsac_ToLogDomainRemoveMean() + * + * Transform the LPC gain to log domain then remove the mean value. + * + * Input: + * -lpcGain : pointer to LPC Gain, expecting 6 LPC gains + * + * Output: + * -lpcGain : mean-removed in log domain. + */ +WebRtc_Word16 +WebRtcIsac_ToLogDomainRemoveMean( + double* data) +{ + WebRtc_Word16 coeffCntr; + for(coeffCntr = 0; coeffCntr < UB_LPC_GAIN_DIM; coeffCntr++) + { + data[coeffCntr] = log(data[coeffCntr]) - WebRtcIsac_kMeanLpcGain; + } + return 0; +} + + +/****************************************************************************** + * WebRtcIsac_DecorrelateLPGain() + * + * Decorrelate LPC gains. There are 6 LPC Gains per frame. This is like + * multiplying gain vector with decorrelating matrix. + * + * Input: + * -data : LPC gain in log-domain with mean removed. + * + * Output: + * -out : decorrelated parameters. + */ +WebRtc_Word16 WebRtcIsac_DecorrelateLPGain( + const double* data, + double* out) +{ + WebRtc_Word16 rowCntr; + WebRtc_Word16 colCntr; + + for(colCntr = 0; colCntr < UB_LPC_GAIN_DIM; colCntr++) + { + *out = 0; + for(rowCntr = 0; rowCntr < UB_LPC_GAIN_DIM; rowCntr++) + { + *out += data[rowCntr] * WebRtcIsac_kLpcGainDecorrMat[rowCntr][colCntr]; + } + out++; + } + return 0; +} + +/****************************************************************************** + * WebRtcIsac_QuantizeLpcGain() + * + * Quantize the decorrelated log-domain gains. + * + * Input: + * -lpcGain : uncorrelated LPC gains. + * + * Output: + * -idx : quantization indices + * -lpcGain : quantized value of the inpt. + */ +double WebRtcIsac_QuantizeLpcGain( + double* data, + int* idx) +{ + WebRtc_Word16 coeffCntr; + for(coeffCntr = 0; coeffCntr < UB_LPC_GAIN_DIM; coeffCntr++) + { + *idx = (int)floor((*data - WebRtcIsac_kLeftRecPointLpcGain[coeffCntr]) / + WebRtcIsac_kQSizeLpcGain + 0.5); + + if(*idx < 0) + { + *idx = 0; + } + else if(*idx >= WebRtcIsac_kNumQCellLpcGain[coeffCntr]) + { + *idx = WebRtcIsac_kNumQCellLpcGain[coeffCntr] - 1; + } + *data = WebRtcIsac_kLeftRecPointLpcGain[coeffCntr] + *idx * + WebRtcIsac_kQSizeLpcGain; + + data++; + idx++; + } + return 0; +} + +/****************************************************************************** + * WebRtcIsac_DequantizeLpcGain() + * + * Get the quantized values given the quantization indices. + * + * Input: + * -idx : pointer to quantization indices. + * + * Output: + * -lpcGains : quantized values of the given parametes. + */ +WebRtc_Word16 WebRtcIsac_DequantizeLpcGain( + const int* idx, + double* out) +{ + WebRtc_Word16 coeffCntr; + for(coeffCntr = 0; coeffCntr < UB_LPC_GAIN_DIM; coeffCntr++) + { + *out = WebRtcIsac_kLeftRecPointLpcGain[coeffCntr] + *idx * + WebRtcIsac_kQSizeLpcGain; + out++; + idx++; + } + return 0; +} + +/****************************************************************************** + * WebRtcIsac_CorrelateLpcGain() + * + * This is the inverse of WebRtcIsac_DecorrelateLPGain(). + * + * Input: + * -data : decorrelated parameters. + * + * Output: + * -out : correlated parameters. + */ +WebRtc_Word16 WebRtcIsac_CorrelateLpcGain( + const double* data, + double* out) +{ + WebRtc_Word16 rowCntr; + WebRtc_Word16 colCntr; + + for(rowCntr = 0; rowCntr < UB_LPC_GAIN_DIM; rowCntr++) + { + *out = 0; + for(colCntr = 0; colCntr < UB_LPC_GAIN_DIM; colCntr++) + { + *out += WebRtcIsac_kLpcGainDecorrMat[rowCntr][colCntr] * data[colCntr]; + } + out++; + } + + return 0; +} + + +/****************************************************************************** + * WebRtcIsac_AddMeanToLinearDomain() + * + * This is the inverse of WebRtcIsac_ToLogDomainRemoveMean(). + * + * Input: + * -lpcGain : LPC gain in log-domain & mean removed + * + * Output: + * -lpcGain : LPC gain in normal domain. + */ +WebRtc_Word16 WebRtcIsac_AddMeanToLinearDomain( + double* lpcGains) +{ + WebRtc_Word16 coeffCntr; + for(coeffCntr = 0; coeffCntr < UB_LPC_GAIN_DIM; coeffCntr++) + { + lpcGains[coeffCntr] = exp(lpcGains[coeffCntr] + WebRtcIsac_kMeanLpcGain); + } + return 0; +} diff --git a/src/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.h b/src/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.h new file mode 100644 index 0000000000..e7f1a76af2 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/encode_lpc_swb.h @@ -0,0 +1,283 @@ +/* + * 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_lpc_swb.h + * + * This file contains declaration of functions used to + * encode LPC parameters (Shape & gain) of the upper band. + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_ + +#include "typedefs.h" +#include "settings.h" +#include "structs.h" + + +/****************************************************************************** + * WebRtcIsac_RemoveLarMean() + * + * Remove the means from LAR coefficients. + * + * Input: + * -lar : pointer to lar vectors. LAR vectors are + * concatenated. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -lar : pointer to mean-removed LAR:s. + * + * + */ +WebRtc_Word16 WebRtcIsac_RemoveLarMean( + double* lar, + WebRtc_Word16 bandwidth); + +/****************************************************************************** + * WebRtcIsac_DecorrelateIntraVec() + * + * Remove the correlation amonge the components of LAR vectors. If LAR vectors + * of one frame are put in a matrix where each column is a LAR vector of a + * sub-frame, then this is equivalent to multiplying the LAR matrix with + * a decorrelting mtrix from left. + * + * Input: + * -inLar : pointer to mean-removed LAR vecrtors. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -out : decorrelated LAR vectors. + */ +WebRtc_Word16 WebRtcIsac_DecorrelateIntraVec( + const double* inLAR, + double* out, + WebRtc_Word16 bandwidth); + + +/****************************************************************************** + * WebRtcIsac_DecorrelateInterVec() + * + * Remover the correlation among mean-removed LAR vectors. If LAR vectors + * of one frame are put in a matrix where each column is a LAR vector of a + * sub-frame, then this is equivalent to multiplying the LAR matrix with + * a decorrelting mtrix from right. + * + * Input: + * -data : pointer to matrix of LAR vectors. The matrix + * is stored column-wise. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -out : decorrelated LAR vectors. + */ +WebRtc_Word16 WebRtcIsac_DecorrelateInterVec( + const double* data, + double* out, + WebRtc_Word16 bandwidth); + + +/****************************************************************************** + * WebRtcIsac_QuantizeUncorrLar() + * + * Quantize the uncorrelated parameters. + * + * Input: + * -data : uncorrelated LAR vectors. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -data : quantized version of the input. + * -idx : pointer to quantization indices. + */ +double WebRtcIsac_QuantizeUncorrLar( + double* data, + int* idx, + WebRtc_Word16 bandwidth); + + +/****************************************************************************** + * WebRtcIsac_CorrelateIntraVec() + * + * This is the inverse of WebRtcIsac_DecorrelateIntraVec(). + * + * Input: + * -data : uncorrelated parameters. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -out : correlated parametrs. + */ +WebRtc_Word16 WebRtcIsac_CorrelateIntraVec( + const double* data, + double* out, + WebRtc_Word16 bandwidth); + + +/****************************************************************************** + * WebRtcIsac_CorrelateInterVec() + * + * This is the inverse of WebRtcIsac_DecorrelateInterVec(). + * + * Input: + * -data + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -out : correlated parametrs. + */ +WebRtc_Word16 WebRtcIsac_CorrelateInterVec( + const double* data, + double* out, + WebRtc_Word16 bandwidth); + + +/****************************************************************************** + * WebRtcIsac_AddLarMean() + * + * This is the inverse of WebRtcIsac_RemoveLarMean() + * + * Input: + * -data : pointer to mean-removed LAR:s. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -data : pointer to LARs. + */ +WebRtc_Word16 WebRtcIsac_AddLarMean( + double* data, + WebRtc_Word16 bandwidth); + + +/****************************************************************************** + * WebRtcIsac_DequantizeLpcParam() + * + * Get the quantized value of uncorrelated LARs given the quantization indices. + * + * Input: + * -idx : pointer to quantiztion indices. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -out : pointer to quantized values. + */ +WebRtc_Word16 WebRtcIsac_DequantizeLpcParam( + const int* idx, + double* out, + WebRtc_Word16 bandwidth); + + +/****************************************************************************** + * WebRtcIsac_ToLogDomainRemoveMean() + * + * Transform the LPC gain to log domain then remove the mean value. + * + * Input: + * -lpcGain : pointer to LPC Gain, expecting 6 LPC gains + * + * Output: + * -lpcGain : mean-removed in log domain. + */ +WebRtc_Word16 WebRtcIsac_ToLogDomainRemoveMean( + double* lpGains); + + +/****************************************************************************** + * WebRtcIsac_DecorrelateLPGain() + * + * Decorrelate LPC gains. There are 6 LPC Gains per frame. This is like + * multiplying gain vector with decorrelating matrix. + * + * Input: + * -data : LPC gain in log-domain with mean removed. + * + * Output: + * -out : decorrelated parameters. + */ +WebRtc_Word16 WebRtcIsac_DecorrelateLPGain( + const double* data, + double* out); + + +/****************************************************************************** + * WebRtcIsac_QuantizeLpcGain() + * + * Quantize the decorrelated log-domain gains. + * + * Input: + * -lpcGain : uncorrelated LPC gains. + * + * Output: + * -idx : quantization indices + * -lpcGain : quantized value of the inpt. + */ +double WebRtcIsac_QuantizeLpcGain( + double* lpGains, + int* idx); + + +/****************************************************************************** + * WebRtcIsac_DequantizeLpcGain() + * + * Get the quantized values given the quantization indices. + * + * Input: + * -idx : pointer to quantization indices. + * + * Output: + * -lpcGains : quantized values of the given parametes. + */ +WebRtc_Word16 WebRtcIsac_DequantizeLpcGain( + const int* idx, + double* lpGains); + + +/****************************************************************************** + * WebRtcIsac_CorrelateLpcGain() + * + * This is the inverse of WebRtcIsac_DecorrelateLPGain(). + * + * Input: + * -data : decorrelated parameters. + * + * Output: + * -out : correlated parameters. + */ +WebRtc_Word16 WebRtcIsac_CorrelateLpcGain( + const double* data, + double* out); + + +/****************************************************************************** + * WebRtcIsac_AddMeanToLinearDomain() + * + * This is the inverse of WebRtcIsac_ToLogDomainRemoveMean(). + * + * Input: + * -lpcGain : LPC gain in log-domain & mean removed + * + * Output: + * -lpcGain : LPC gain in normal domain. + */ +WebRtc_Word16 WebRtcIsac_AddMeanToLinearDomain( + double* lpcGains); + + +#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_ diff --git a/src/modules/audio_coding/codecs/isac/main/source/entropy_coding.c b/src/modules/audio_coding/codecs/isac/main/source/entropy_coding.c new file mode 100644 index 0000000000..49c695ce2f --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/entropy_coding.c @@ -0,0 +1,2066 @@ +/* + * 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 "entropy_coding.h" +#include "settings.h" +#include "arith_routines.h" +#include "signal_processing_library.h" +#include "spectrum_ar_model_tables.h" +#include "lpc_tables.h" +#include "pitch_gain_tables.h" +#include "pitch_lag_tables.h" +#include "encode_lpc_swb.h" +#include "lpc_shape_swb12_tables.h" +#include "lpc_shape_swb16_tables.h" +#include "lpc_gain_swb_tables.h" +#include "os_specific_inline.h" + +#include +#include + +static const WebRtc_UWord16 kLpcVecPerSegmentUb12 = 5; +static const WebRtc_UWord16 kLpcVecPerSegmentUb16 = 4; + +/* CDF array for encoder bandwidth (12 vs 16 kHz) indicator. */ +static const WebRtc_UWord16 kOneBitEqualProbCdf[3] = { + 0, 32768, 65535 }; + +/* Pointer to cdf array for encoder bandwidth (12 vs 16 kHz) indicator. */ +static const WebRtc_UWord16* kOneBitEqualProbCdf_ptr[1] = { + kOneBitEqualProbCdf }; + +/* + * Initial cdf index for decoder of encoded bandwidth + * (12 vs 16 kHz) indicator. + */ +static const WebRtc_UWord16 kOneBitEqualProbInitIndex[1] = { 1 }; + + +static const int kIsSWB12 = 1; + +/* compute correlation from power spectrum */ +static void FindCorrelation(WebRtc_Word32* PSpecQ12, WebRtc_Word32* CorrQ7) { + WebRtc_Word32 summ[FRAMESAMPLES / 8]; + WebRtc_Word32 diff[FRAMESAMPLES / 8]; + const WebRtc_Word16* CS_ptrQ9; + WebRtc_Word32 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 WebRtc_Word16* ARCoefQ12, + const WebRtc_Word32 gainQ10, + WebRtc_Word32* CurveQ16) { + WebRtc_Word32 CorrQ11[AR_ORDER + 1]; + WebRtc_Word32 sum, tmpGain; + WebRtc_Word32 diffQ16[FRAMESAMPLES / 8]; + const WebRtc_Word16* CS_ptrQ9; + int k, n; + WebRtc_Word16 round, shftVal = 0, sh; + + sum = 0; + for (n = 0; n < AR_ORDER + 1; n++) { + sum += WEBRTC_SPL_MUL(ARCoefQ12[n], ARCoefQ12[n]); /* Q24 */ + } + sum = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(WEBRTC_SPL_RSHIFT_W32(sum, 6), + 65) + 32768, 16); /* Q8 */ + CorrQ11[0] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(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 = WEBRTC_SPL_RSHIFT_W32(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 = WEBRTC_SPL_RSHIFT_W32(sum, 15); + CorrQ11[k] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(sum, tmpGain) + round, + shftVal); + } + sum = WEBRTC_SPL_LSHIFT_W32(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] += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL( + 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] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL( + CS_ptrQ9[n], WEBRTC_SPL_RSHIFT_W32(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] += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL( + CS_ptrQ9[n], WEBRTC_SPL_RSHIFT_W32(CorrQ11[k + 1], shftVal)) + 2, 2); + } + } + + for (k = 0; k < FRAMESAMPLES / 8; k++) { + CurveQ16[FRAMESAMPLES_QUARTER - 1 - k] = CurveQ16[k] - + WEBRTC_SPL_LSHIFT_W32(diffQ16[k], shftVal); + CurveQ16[k] += WEBRTC_SPL_LSHIFT_W32(diffQ16[k], shftVal); + } +} + +/* Generate array of dither samples in Q7. */ +static void GenerateDitherQ7Lb(WebRtc_Word16* bufQ7, WebRtc_UWord32 seed, + int length, WebRtc_Word16 AvgPitchGain_Q12) { + int k, shft; + WebRtc_Word16 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 = (WebRtc_Word16)(((int)seed + 16777216) >> 25); + + /* New random unsigned int. */ + seed = (seed * 196314165) + 907633515; + + /* Fixed-point dither sample between -64 and 64. */ + dither2_Q7 = (WebRtc_Word16)(((int)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 = (WebRtc_Word16)(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 = (WebRtc_Word16)(((int)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( + WebRtc_Word16* bufQ7, + WebRtc_UWord32 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] = (WebRtc_Word16)(((int)seed + 16777216) >> 25); + + /* Scale by 0.35. */ + bufQ7[k] = (WebRtc_Word16)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, WebRtc_Word16 AvgPitchGain_Q12, + enum ISACBand band, double* fr, double* fi) { + WebRtc_Word16 DitherQ7[FRAMESAMPLES]; + WebRtc_Word16 data[FRAMESAMPLES]; + WebRtc_Word32 invARSpec2_Q16[FRAMESAMPLES_QUARTER]; + WebRtc_UWord16 invARSpecQ8[FRAMESAMPLES_QUARTER]; + WebRtc_Word16 ARCoefQ12[AR_ORDER + 1]; + WebRtc_Word16 RCQ15[AR_ORDER]; + WebRtc_Word16 gainQ10; + WebRtc_Word32 gain2_Q10, res; + WebRtc_Word32 in_sqrt; + WebRtc_Word32 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] = (WebRtc_Word16)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. */ + WebRtc_Word32 p1; + WebRtc_Word32 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, (WebRtc_Word16)( + (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 WebRtc_Word16* fr, const WebRtc_Word16* fi, + WebRtc_Word16 AvgPitchGain_Q12, enum ISACBand band, + Bitstr* streamdata) { + WebRtc_Word16 ditherQ7[FRAMESAMPLES]; + WebRtc_Word16 dataQ7[FRAMESAMPLES]; + WebRtc_Word32 PSpec[FRAMESAMPLES_QUARTER]; + WebRtc_Word32 invARSpec2_Q16[FRAMESAMPLES_QUARTER]; + WebRtc_UWord16 invARSpecQ8[FRAMESAMPLES_QUARTER]; + WebRtc_Word32 CorrQ7[AR_ORDER + 1]; + WebRtc_Word32 CorrQ7_norm[AR_ORDER + 1]; + WebRtc_Word16 RCQ15[AR_ORDER]; + WebRtc_Word16 ARCoefQ12[AR_ORDER + 1]; + WebRtc_Word32 gain2_Q10; + WebRtc_Word16 val; + WebRtc_Word32 nrg, res; + WebRtc_UWord32 sum; + WebRtc_Word32 in_sqrt; + WebRtc_Word32 newRes; + WebRtc_Word16 err; + WebRtc_UWord32 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 = (WebRtc_UWord32)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 = (WebRtc_Word32)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] = (WebRtc_Word16)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; + } +} + + +WebRtc_Word16 WebRtcIsac_Poly2LarUB(double* lpcVecs, WebRtc_Word16 bandwidth) { + double poly[MAX_ORDER]; + double rc[MAX_ORDER]; + double* ptrIO; + WebRtc_Word16 vecCntr; + WebRtc_Word16 vecSize; + WebRtc_Word16 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; +} + +WebRtc_Word16 WebRtcIsac_DecodeInterpolLpcUb(Bitstr* streamdata, + double* percepFilterParams, + WebRtc_Word16 bandwidth) { + double lpcCoeff[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME]; + int err; + int interpolCntr; + int subframeCntr; + WebRtc_Word16 numSegments; + WebRtc_Word16 numVecPerSegment; + WebRtc_Word16 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, + ISAC_SaveEncData_t* 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, ISAC_SaveEncData_t* 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]; + } +} + + +WebRtc_Word16 WebRtcIsac_EncodeLpcUB(double* lpcVecs, Bitstr* streamdata, + double* interpolLPCCoeff, + WebRtc_Word16 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, + ISAC_SaveEncData_t* 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); +} + + + +WebRtc_Word16 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, WebRtc_Word16* 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(WebRtc_Word16* 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]; + + if (RCQ15[k] > WebRtcIsac_kQArBoundaryLevels[index[k]]) { + while (RCQ15[k] > WebRtcIsac_kQArBoundaryLevels[index[k] + 1]) { + index[k]++; + } + } else { + while (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, WebRtc_Word32* 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(WebRtc_Word32* 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, + WebRtc_Word16* PitchGains_Q12) { + int index_comb, err; + const WebRtc_UWord16* 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(WebRtc_Word16* PitchGains_Q12, + Bitstr* streamdata, + ISAC_SaveEncData_t* encData) { + int k, j; + double C; + double S[PITCH_SUBFRAMES]; + int index[3]; + int index_comb; + const WebRtc_UWord16* 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, WebRtc_Word16* 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 WebRtc_Word16* lower_limit; + const WebRtc_UWord16* init_index; + const WebRtc_UWord16* cdf_size; + const WebRtc_UWord16** 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, WebRtc_Word16* PitchGain_Q12, + Bitstr* streamdata, + ISAC_SaveEncData_t* encData) { + int k, j; + double StepSize; + double C; + int index[PITCH_SUBFRAMES]; + double mean_gain; + const double* mean_val2, *mean_val3, *mean_val4; + const WebRtc_Word16* lower_limit, *upper_limit; + const WebRtc_UWord16** 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 WebRtc_UWord16 WebRtcIsac_kFrameLengthCdf[4] = { + 0, 21845, 43690, 65535 }; + +/* pointer to cdf array for frame length indicator */ +const WebRtc_UWord16* WebRtcIsac_kFrameLengthCdf_ptr[1] = { + WebRtcIsac_kFrameLengthCdf }; + +/* initial cdf index for decoder of frame length indicator */ +const WebRtc_UWord16 WebRtcIsac_kFrameLengthInitIndex[1] = { 1 }; + + +int WebRtcIsac_DecodeFrameLen(Bitstr* streamdata, WebRtc_Word16* 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(WebRtc_Word16 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 WebRtc_UWord16 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 WebRtc_UWord16* kBwCdfPtr[1] = { kBwCdf }; + +/* initial cdf index for decoder of estimated bandwidth*/ +static const WebRtc_UWord16 kBwInitIndex[1] = { 7 }; + + +int WebRtcIsac_DecodeSendBW(Bitstr* streamdata, WebRtc_Word16* 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 = (WebRtc_Word16)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, + WebRtc_Word16 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; +} + +WebRtc_Word16 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; +} + +WebRtc_Word16 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; +} + +WebRtc_Word16 WebRtcIsac_EncodeJitterInfo(WebRtc_Word32 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; +} + +WebRtc_Word16 WebRtcIsac_DecodeJitterInfo(Bitstr* streamData, + WebRtc_Word32* 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 = (WebRtc_Word16)(intVar); + return 0; +} diff --git a/src/modules/audio_coding/codecs/isac/main/source/entropy_coding.h b/src/modules/audio_coding/codecs/isac/main/source/entropy_coding.h new file mode 100644 index 0000000000..1a469535ad --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/entropy_coding.h @@ -0,0 +1,341 @@ +/* + * 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.h + * + * This header file declares all of the functions used to arithmetically + * encode the iSAC bistream + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_ + +#include "settings.h" +#include "structs.h" + +/****************************************************************************** + * WebRtcIsac_DecodeSpec() + * Decode real and imaginary part of the DFT coefficients, given a bit-stream. + * The decoded DFT coefficient can be transformed to time domain by + * WebRtcIsac_Time2Spec(). + * + * Input: + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * - AvgPitchGain_Q12 : average pitch-gain of the frame. This is only + * relevant for 0-4 kHz band, and the input value is + * not used in other bands. + * - band : specifies which band's DFT should be decoded. + * + * Output: + * - *fr : pointer to a buffer where the real part of DFT + * coefficients are written to. + * - *fi : pointer to a buffer where the imaginary part + * of DFT coefficients are written to. + * + * Return value : < 0 if an error occures + * 0 if succeeded. + */ +int WebRtcIsac_DecodeSpec(Bitstr* streamdata, WebRtc_Word16 AvgPitchGain_Q12, + enum ISACBand band, double* fr, double* fi); + +/****************************************************************************** + * WebRtcIsac_EncodeSpec() + * Encode real and imaginary part of the DFT coefficients into the given + * bit-stream. + * + * Input: + * - *fr : pointer to a buffer where the real part of DFT + * coefficients are written to. + * - *fi : pointer to a buffer where the imaginary part + * of DFT coefficients are written to. + * - AvgPitchGain_Q12 : average pitch-gain of the frame. This is only + * relevant for 0-4 kHz band, and the input value is + * not used in other bands. + * - band : specifies which band's DFT should be decoded. + * + * Output: + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * + * Return value : < 0 if an error occures + * 0 if succeeded. + */ +int WebRtcIsac_EncodeSpec(const WebRtc_Word16* fr, const WebRtc_Word16* fi, + WebRtc_Word16 AvgPitchGain_Q12, enum ISACBand band, + Bitstr* streamdata); + +/* decode & dequantize LPC Coef */ +int WebRtcIsac_DecodeLpcCoef(Bitstr* streamdata, double* LPCCoef); +int WebRtcIsac_DecodeLpcCoefUB(Bitstr* streamdata, double* lpcVecs, + double* percepFilterGains, + WebRtc_Word16 bandwidth); + +int WebRtcIsac_DecodeLpc(Bitstr* streamdata, double* LPCCoef_lo, + double* LPCCoef_hi); + +/* quantize & code LPC Coef */ +void WebRtcIsac_EncodeLpcLb(double* LPCCoef_lo, double* LPCCoef_hi, + Bitstr* streamdata, ISAC_SaveEncData_t* encData); + +void WebRtcIsac_EncodeLpcGainLb(double* LPCCoef_lo, double* LPCCoef_hi, + Bitstr* streamdata, + ISAC_SaveEncData_t* encData); + +/****************************************************************************** + * WebRtcIsac_EncodeLpcUB() + * Encode LPC parameters, given as A-polynomial, of upper-band. The encoding + * is performed in LAR domain. + * For the upper-band, we compute and encode LPC of some sub-frames, LPC of + * other sub-frames are computed by linear interpolation, in LAR domain. This + * function performs the interpolation and returns the LPC of all sub-frames. + * + * Inputs: + * - lpcCoef : a buffer containing A-polynomials of sub-frames + * (excluding first coefficient that is 1). + * - bandwidth : specifies if the codec is operating at 0-12 kHz + * or 0-16 kHz mode. + * + * Input/output: + * - streamdata : pointer to a structure containing the encoded + * data and the parameters needed for entropy + * coding. + * + * Output: + * - interpolLPCCoeff : Decoded and interpolated LPC (A-polynomial) + * of all sub-frames. + * If LP analysis is of order K, and there are N + * sub-frames then this is a buffer of size + * (k + 1) * N, each vector starts with the LPC gain + * of the corresponding sub-frame. The LPC gains + * are encoded and inserted after this function is + * called. The first A-coefficient which is 1 is not + * included. + * + * Return value : 0 if encoding is successful, + * <0 if failed to encode. + */ +WebRtc_Word16 WebRtcIsac_EncodeLpcUB(double* lpcCoeff, Bitstr* streamdata, + double* interpolLPCCoeff, + WebRtc_Word16 bandwidth, + ISACUBSaveEncDataStruct* encData); + +/****************************************************************************** + * WebRtcIsac_DecodeInterpolLpcUb() + * Decode LPC coefficients and interpolate to get the coefficients fo all + * sub-frmaes. + * + * Inputs: + * - bandwidth : spepecifies if the codec is in 0-12 kHz or + * 0-16 kHz mode. + * + * Input/output: + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * + * Output: + * - percepFilterParam : Decoded and interpolated LPC (A-polynomial) of + * all sub-frames. + * If LP analysis is of order K, and there are N + * sub-frames then this is a buffer of size + * (k + 1) * N, each vector starts with the LPC gain + * of the corresponding sub-frame. The LPC gains + * are encoded and inserted after this function is + * called. The first A-coefficient which is 1 is not + * included. + * + * Return value : 0 if encoding is successful, + * <0 if failed to encode. + */ +WebRtc_Word16 WebRtcIsac_DecodeInterpolLpcUb(Bitstr* streamdata, + double* percepFilterParam, + WebRtc_Word16 bandwidth); + +/* Decode & dequantize RC */ +int WebRtcIsac_DecodeRc(Bitstr* streamdata, WebRtc_Word16* RCQ15); + +/* Quantize & code RC */ +void WebRtcIsac_EncodeRc(WebRtc_Word16* RCQ15, Bitstr* streamdata); + +/* Decode & dequantize squared Gain */ +int WebRtcIsac_DecodeGain2(Bitstr* streamdata, WebRtc_Word32* Gain2); + +/* Quantize & code squared Gain (input is squared gain) */ +int WebRtcIsac_EncodeGain2(WebRtc_Word32* gain2, Bitstr* streamdata); + +void WebRtcIsac_EncodePitchGain(WebRtc_Word16* PitchGains_Q12, + Bitstr* streamdata, + ISAC_SaveEncData_t* encData); + +void WebRtcIsac_EncodePitchLag(double* PitchLags, WebRtc_Word16* PitchGain_Q12, + Bitstr* streamdata, ISAC_SaveEncData_t* encData); + +int WebRtcIsac_DecodePitchGain(Bitstr* streamdata, + WebRtc_Word16* PitchGain_Q12); +int WebRtcIsac_DecodePitchLag(Bitstr* streamdata, WebRtc_Word16* PitchGain_Q12, + double* PitchLag); + +int WebRtcIsac_DecodeFrameLen(Bitstr* streamdata, WebRtc_Word16* framelength); +int WebRtcIsac_EncodeFrameLen(WebRtc_Word16 framelength, Bitstr* streamdata); +int WebRtcIsac_DecodeSendBW(Bitstr* streamdata, WebRtc_Word16* BWno); +void WebRtcIsac_EncodeReceiveBw(int* BWno, Bitstr* streamdata); + +/* Step-down */ +void WebRtcIsac_Poly2Rc(double* a, int N, double* RC); + +/* Step-up */ +void WebRtcIsac_Rc2Poly(double* RC, int N, double* a); + +void WebRtcIsac_TranscodeLPCCoef(double* LPCCoef_lo, double* LPCCoef_hi, + int* index_g); + + +/****************************************************************************** + * WebRtcIsac_EncodeLpcGainUb() + * Encode LPC gains of sub-Frames. + * + * Input/outputs: + * - lpGains : a buffer which contains 'SUBFRAME' number of + * LP gains to be encoded. The input values are + * overwritten by the quantized values. + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * + * Output: + * - lpcGainIndex : quantization indices for lpc gains, these will + * be stored to be used for FEC. + */ +void WebRtcIsac_EncodeLpcGainUb(double* lpGains, Bitstr* streamdata, + int* lpcGainIndex); + + +/****************************************************************************** + * WebRtcIsac_EncodeLpcGainUb() + * Store LPC gains of sub-Frames in 'streamdata'. + * + * Input: + * - lpGains : a buffer which contains 'SUBFRAME' number of + * LP gains to be encoded. + * Input/outputs: + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * + */ +void WebRtcIsac_StoreLpcGainUb(double* lpGains, Bitstr* streamdata); + + +/****************************************************************************** + * WebRtcIsac_DecodeLpcGainUb() + * Decode the LPC gain of sub-frames. + * + * Input/output: + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * + * Output: + * - lpGains : a buffer where decoded LPC gians will be stored. + * + * Return value : 0 if succeeded. + * <0 if failed. + */ +WebRtc_Word16 WebRtcIsac_DecodeLpcGainUb(double* lpGains, Bitstr* streamdata); + + +/****************************************************************************** + * WebRtcIsac_EncodeBandwidth() + * Encode if the bandwidth of encoded audio is 0-12 kHz or 0-16 kHz. + * + * Input: + * - bandwidth : an enumerator specifying if the codec in is + * 0-12 kHz or 0-16 kHz mode. + * + * Input/output: + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * + * Return value : 0 if succeeded. + * <0 if failed. + */ +WebRtc_Word16 WebRtcIsac_EncodeBandwidth(enum ISACBandwidth bandwidth, + Bitstr* streamData); + + +/****************************************************************************** + * WebRtcIsac_DecodeBandwidth() + * Decode the bandwidth of the encoded audio, i.e. if the bandwidth is 0-12 kHz + * or 0-16 kHz. + * + * Input/output: + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * + * Output: + * - bandwidth : an enumerator specifying if the codec is in + * 0-12 kHz or 0-16 kHz mode. + * + * Return value : 0 if succeeded. + * <0 if failed. + */ +WebRtc_Word16 WebRtcIsac_DecodeBandwidth(Bitstr* streamData, + enum ISACBandwidth* bandwidth); + + +/****************************************************************************** + * WebRtcIsac_EncodeJitterInfo() + * Decode the jitter information. + * + * Input/output: + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * + * Input: + * - jitterInfo : one bit of info specifying if the channel is + * in high/low jitter. Zero indicates low jitter + * and one indicates high jitter. + * + * Return value : 0 if succeeded. + * <0 if failed. + */ +WebRtc_Word16 WebRtcIsac_EncodeJitterInfo(WebRtc_Word32 jitterIndex, + Bitstr* streamData); + + +/****************************************************************************** + * WebRtcIsac_DecodeJitterInfo() + * Decode the jitter information. + * + * Input/output: + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * + * Output: + * - jitterInfo : one bit of info specifying if the channel is + * in high/low jitter. Zero indicates low jitter + * and one indicates high jitter. + * + * Return value : 0 if succeeded. + * <0 if failed. + */ +WebRtc_Word16 WebRtcIsac_DecodeJitterInfo(Bitstr* streamData, + WebRtc_Word32* jitterInfo); + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/main/source/fft.c b/src/modules/audio_coding/codecs/isac/main/source/fft.c new file mode 100644 index 0000000000..c8247983aa --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/fft.c @@ -0,0 +1,947 @@ +/* + * Copyright(c)1995,97 Mark Olesen + * Queen's Univ at Kingston (Canada) + * + * Permission to use, copy, modify, and distribute this software for + * any purpose without fee is hereby granted, provided that this + * entire notice is included in all copies of any software which is + * or includes a copy or modification of this software and in all + * copies of the supporting documentation for such software. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR QUEEN'S + * UNIVERSITY AT KINGSTON MAKES ANY REPRESENTATION OR WARRANTY OF ANY + * KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS + * FITNESS FOR ANY PARTICULAR PURPOSE. + * + * All of which is to say that you can do what you like with this + * source code provided you don't try to sell it as your own and you + * include an unaltered copy of this message (including the + * copyright). + * + * It is also implicitly understood that bug fixes and improvements + * should make their way back to the general Internet community so + * that everyone benefits. + * + * Changes: + * Trivial type modifications by the WebRTC authors. + */ + + +/* + * File: + * WebRtcIsac_Fftn.c + * + * Public: + * WebRtcIsac_Fftn / fftnf (); + * + * Private: + * WebRtcIsac_Fftradix / fftradixf (); + * + * Descript: + * multivariate complex Fourier transform, computed in place + * using mixed-radix Fast Fourier Transform algorithm. + * + * Fortran code by: + * RC Singleton, Stanford Research Institute, Sept. 1968 + * + * translated by f2c (version 19950721). + * + * int WebRtcIsac_Fftn (int ndim, const int dims[], REAL Re[], REAL Im[], + * int iSign, double scaling); + * + * NDIM = the total number dimensions + * DIMS = a vector of array sizes + * if NDIM is zero then DIMS must be zero-terminated + * + * RE and IM hold the real and imaginary components of the data, and return + * the resulting real and imaginary Fourier coefficients. Multidimensional + * data *must* be allocated contiguously. There is no limit on the number + * of dimensions. + * + * ISIGN = the sign of the complex exponential (ie, forward or inverse FFT) + * the magnitude of ISIGN (normally 1) is used to determine the + * correct indexing increment (see below). + * + * SCALING = normalizing constant by which the final result is *divided* + * if SCALING == -1, normalize by total dimension of the transform + * if SCALING < -1, normalize by the square-root of the total dimension + * + * example: + * tri-variate transform with Re[n1][n2][n3], Im[n1][n2][n3] + * + * int dims[3] = {n1,n2,n3} + * WebRtcIsac_Fftn (3, dims, Re, Im, 1, scaling); + * + *-----------------------------------------------------------------------* + * int WebRtcIsac_Fftradix (REAL Re[], REAL Im[], size_t nTotal, size_t nPass, + * size_t nSpan, int iSign, size_t max_factors, + * size_t max_perm); + * + * RE, IM - see above documentation + * + * Although there is no limit on the number of dimensions, WebRtcIsac_Fftradix() must + * be called once for each dimension, but the calls may be in any order. + * + * NTOTAL = the total number of complex data values + * NPASS = the dimension of the current variable + * NSPAN/NPASS = the spacing of consecutive data values while indexing the + * current variable + * ISIGN - see above documentation + * + * example: + * tri-variate transform with Re[n1][n2][n3], Im[n1][n2][n3] + * + * WebRtcIsac_Fftradix (Re, Im, n1*n2*n3, n1, n1, 1, maxf, maxp); + * WebRtcIsac_Fftradix (Re, Im, n1*n2*n3, n2, n1*n2, 1, maxf, maxp); + * WebRtcIsac_Fftradix (Re, Im, n1*n2*n3, n3, n1*n2*n3, 1, maxf, maxp); + * + * single-variate transform, + * NTOTAL = N = NSPAN = (number of complex data values), + * + * WebRtcIsac_Fftradix (Re, Im, n, n, n, 1, maxf, maxp); + * + * The data can also be stored in a single array with alternating real and + * imaginary parts, the magnitude of ISIGN is changed to 2 to give correct + * indexing increment, and data [0] and data [1] used to pass the initial + * addresses for the sequences of real and imaginary values, + * + * example: + * REAL data [2*NTOTAL]; + * WebRtcIsac_Fftradix ( &data[0], &data[1], NTOTAL, nPass, nSpan, 2, maxf, maxp); + * + * for temporary allocation: + * + * MAX_FACTORS >= the maximum prime factor of NPASS + * MAX_PERM >= the number of prime factors of NPASS. In addition, + * if the square-free portion K of NPASS has two or more prime + * factors, then MAX_PERM >= (K-1) + * + * storage in FACTOR for a maximum of 15 prime factors of NPASS. if NPASS + * has more than one square-free factor, the product of the square-free + * factors must be <= 210 array storage for maximum prime factor of 23 the + * following two constants should agree with the array dimensions. + * + *----------------------------------------------------------------------*/ +#include "fft.h" + +#include +#include + + + +/* double precision routine */ +static int +WebRtcIsac_Fftradix (double Re[], double Im[], + size_t nTotal, size_t nPass, size_t nSpan, int isign, + int max_factors, unsigned int max_perm, + FFTstr *fftstate); + + + +#ifndef M_PI +# define M_PI 3.14159265358979323846264338327950288 +#endif + +#ifndef SIN60 +# define SIN60 0.86602540378443865 /* sin(60 deg) */ +# define COS72 0.30901699437494742 /* cos(72 deg) */ +# define SIN72 0.95105651629515357 /* sin(72 deg) */ +#endif + +# define REAL double +# define FFTN WebRtcIsac_Fftn +# define FFTNS "fftn" +# define FFTRADIX WebRtcIsac_Fftradix +# define FFTRADIXS "fftradix" + + +int WebRtcIsac_Fftns(unsigned int ndim, const int dims[], + double Re[], + double Im[], + int iSign, + double scaling, + FFTstr *fftstate) +{ + + size_t nSpan, nPass, nTotal; + unsigned int i; + int ret, max_factors, max_perm; + + /* + * tally the number of elements in the data array + * and determine the number of dimensions + */ + nTotal = 1; + if (ndim && dims [0]) + { + for (i = 0; i < ndim; i++) + { + if (dims [i] <= 0) + { + return -1; + } + nTotal *= dims [i]; + } + } + else + { + ndim = 0; + for (i = 0; dims [i]; i++) + { + if (dims [i] <= 0) + { + return -1; + } + nTotal *= dims [i]; + ndim++; + } + } + + /* determine maximum number of factors and permuations */ +#if 1 + /* + * follow John Beale's example, just use the largest dimension and don't + * worry about excess allocation. May be someone else will do it? + */ + max_factors = max_perm = 1; + for (i = 0; i < ndim; i++) + { + nSpan = dims [i]; + if ((int)nSpan > max_factors) + { + max_factors = (int)nSpan; + } + if ((int)nSpan > max_perm) + { + max_perm = (int)nSpan; + } + } +#else + /* use the constants used in the original Fortran code */ + max_factors = 23; + max_perm = 209; +#endif + /* loop over the dimensions: */ + nPass = 1; + for (i = 0; i < ndim; i++) + { + nSpan = dims [i]; + nPass *= nSpan; + ret = FFTRADIX (Re, Im, nTotal, nSpan, nPass, iSign, + max_factors, max_perm, fftstate); + /* exit, clean-up already done */ + if (ret) + return ret; + } + + /* Divide through by the normalizing constant: */ + if (scaling && scaling != 1.0) + { + if (iSign < 0) iSign = -iSign; + if (scaling < 0.0) + { + scaling = (double)nTotal; + if (scaling < -1.0) + scaling = sqrt (scaling); + } + scaling = 1.0 / scaling; /* multiply is often faster */ + for (i = 0; i < nTotal; i += iSign) + { + Re [i] *= scaling; + Im [i] *= scaling; + } + } + return 0; +} + +/* + * singleton's mixed radix routine + * + * could move allocation out to WebRtcIsac_Fftn(), but leave it here so that it's + * possible to make this a standalone function + */ + +static int FFTRADIX (REAL Re[], + REAL Im[], + size_t nTotal, + size_t nPass, + size_t nSpan, + int iSign, + int max_factors, + unsigned int max_perm, + FFTstr *fftstate) +{ + int ii, mfactor, kspan, ispan, inc; + int j, jc, jf, jj, k, k1, k2, k3, k4, kk, kt, nn, ns, nt; + + + REAL radf; + REAL c1, c2, c3, cd, aa, aj, ak, ajm, ajp, akm, akp; + REAL s1, s2, s3, sd, bb, bj, bk, bjm, bjp, bkm, bkp; + + REAL *Rtmp = NULL; /* temp space for real part*/ + REAL *Itmp = NULL; /* temp space for imaginary part */ + REAL *Cos = NULL; /* Cosine values */ + REAL *Sin = NULL; /* Sine values */ + + REAL s60 = SIN60; /* sin(60 deg) */ + REAL c72 = COS72; /* cos(72 deg) */ + REAL s72 = SIN72; /* sin(72 deg) */ + REAL pi2 = M_PI; /* use PI first, 2 PI later */ + + + fftstate->SpaceAlloced = 0; + fftstate->MaxPermAlloced = 0; + + + // initialize to avoid warnings + k3 = c2 = c3 = s2 = s3 = 0.0; + + if (nPass < 2) + return 0; + + /* allocate storage */ + if (fftstate->SpaceAlloced < max_factors * sizeof (REAL)) + { +#ifdef SUN_BROKEN_REALLOC + if (!fftstate->SpaceAlloced) /* first time */ + { + fftstate->SpaceAlloced = max_factors * sizeof (REAL); + } + else + { +#endif + fftstate->SpaceAlloced = max_factors * sizeof (REAL); +#ifdef SUN_BROKEN_REALLOC + } +#endif + } + else + { + /* allow full use of alloc'd space */ + max_factors = fftstate->SpaceAlloced / sizeof (REAL); + } + if (fftstate->MaxPermAlloced < max_perm) + { +#ifdef SUN_BROKEN_REALLOC + if (!fftstate->MaxPermAlloced) /* first time */ + else +#endif + fftstate->MaxPermAlloced = max_perm; + } + else + { + /* allow full use of alloc'd space */ + max_perm = fftstate->MaxPermAlloced; + } + if (fftstate->Tmp0 == NULL || fftstate->Tmp1 == NULL || fftstate->Tmp2 == NULL || fftstate->Tmp3 == NULL + || fftstate->Perm == NULL) { + return -1; + } + + /* assign pointers */ + Rtmp = (REAL *) fftstate->Tmp0; + Itmp = (REAL *) fftstate->Tmp1; + Cos = (REAL *) fftstate->Tmp2; + Sin = (REAL *) fftstate->Tmp3; + + /* + * Function Body + */ + inc = iSign; + if (iSign < 0) { + s72 = -s72; + s60 = -s60; + pi2 = -pi2; + inc = -inc; /* absolute value */ + } + + /* adjust for strange increments */ + nt = inc * (int)nTotal; + ns = inc * (int)nSpan; + kspan = ns; + + nn = nt - inc; + jc = ns / (int)nPass; + radf = pi2 * (double) jc; + pi2 *= 2.0; /* use 2 PI from here on */ + + ii = 0; + jf = 0; + /* determine the factors of n */ + mfactor = 0; + k = (int)nPass; + while (k % 16 == 0) { + mfactor++; + fftstate->factor [mfactor - 1] = 4; + k /= 16; + } + j = 3; + jj = 9; + do { + while (k % jj == 0) { + mfactor++; + fftstate->factor [mfactor - 1] = j; + k /= jj; + } + j += 2; + jj = j * j; + } while (jj <= k); + if (k <= 4) { + kt = mfactor; + fftstate->factor [mfactor] = k; + if (k != 1) + mfactor++; + } else { + if (k - (k / 4 << 2) == 0) { + mfactor++; + fftstate->factor [mfactor - 1] = 2; + k /= 4; + } + kt = mfactor; + j = 2; + do { + if (k % j == 0) { + mfactor++; + fftstate->factor [mfactor - 1] = j; + k /= j; + } + j = ((j + 1) / 2 << 1) + 1; + } while (j <= k); + } + if (kt) { + j = kt; + do { + mfactor++; + fftstate->factor [mfactor - 1] = fftstate->factor [j - 1]; + j--; + } while (j); + } + + /* test that mfactors is in range */ + if (mfactor > NFACTOR) + { + return -1; + } + + /* compute fourier transform */ + for (;;) { + sd = radf / (double) kspan; + cd = sin(sd); + cd = 2.0 * cd * cd; + sd = sin(sd + sd); + kk = 0; + ii++; + + switch (fftstate->factor [ii - 1]) { + case 2: + /* transform for factor of 2 (including rotation factor) */ + kspan /= 2; + k1 = kspan + 2; + do { + do { + k2 = kk + kspan; + ak = Re [k2]; + bk = Im [k2]; + Re [k2] = Re [kk] - ak; + Im [k2] = Im [kk] - bk; + Re [kk] += ak; + Im [kk] += bk; + kk = k2 + kspan; + } while (kk < nn); + kk -= nn; + } while (kk < jc); + if (kk >= kspan) + goto Permute_Results_Label; /* exit infinite loop */ + do { + c1 = 1.0 - cd; + s1 = sd; + do { + do { + do { + k2 = kk + kspan; + ak = Re [kk] - Re [k2]; + bk = Im [kk] - Im [k2]; + Re [kk] += Re [k2]; + Im [kk] += Im [k2]; + Re [k2] = c1 * ak - s1 * bk; + Im [k2] = s1 * ak + c1 * bk; + kk = k2 + kspan; + } while (kk < (nt-1)); + k2 = kk - nt; + c1 = -c1; + kk = k1 - k2; + } while (kk > k2); + ak = c1 - (cd * c1 + sd * s1); + s1 = sd * c1 - cd * s1 + s1; + c1 = 2.0 - (ak * ak + s1 * s1); + s1 *= c1; + c1 *= ak; + kk += jc; + } while (kk < k2); + k1 += inc + inc; + kk = (k1 - kspan + 1) / 2 + jc - 1; + } while (kk < (jc + jc)); + break; + + case 4: /* transform for factor of 4 */ + ispan = kspan; + kspan /= 4; + + do { + c1 = 1.0; + s1 = 0.0; + do { + do { + k1 = kk + kspan; + k2 = k1 + kspan; + k3 = k2 + kspan; + akp = Re [kk] + Re [k2]; + akm = Re [kk] - Re [k2]; + ajp = Re [k1] + Re [k3]; + ajm = Re [k1] - Re [k3]; + bkp = Im [kk] + Im [k2]; + bkm = Im [kk] - Im [k2]; + bjp = Im [k1] + Im [k3]; + bjm = Im [k1] - Im [k3]; + Re [kk] = akp + ajp; + Im [kk] = bkp + bjp; + ajp = akp - ajp; + bjp = bkp - bjp; + if (iSign < 0) { + akp = akm + bjm; + bkp = bkm - ajm; + akm -= bjm; + bkm += ajm; + } else { + akp = akm - bjm; + bkp = bkm + ajm; + akm += bjm; + bkm -= ajm; + } + /* avoid useless multiplies */ + if (s1 == 0.0) { + Re [k1] = akp; + Re [k2] = ajp; + Re [k3] = akm; + Im [k1] = bkp; + Im [k2] = bjp; + Im [k3] = bkm; + } else { + Re [k1] = akp * c1 - bkp * s1; + Re [k2] = ajp * c2 - bjp * s2; + Re [k3] = akm * c3 - bkm * s3; + Im [k1] = akp * s1 + bkp * c1; + Im [k2] = ajp * s2 + bjp * c2; + Im [k3] = akm * s3 + bkm * c3; + } + kk = k3 + kspan; + } while (kk < nt); + + c2 = c1 - (cd * c1 + sd * s1); + s1 = sd * c1 - cd * s1 + s1; + c1 = 2.0 - (c2 * c2 + s1 * s1); + s1 *= c1; + c1 *= c2; + /* values of c2, c3, s2, s3 that will get used next time */ + c2 = c1 * c1 - s1 * s1; + s2 = 2.0 * c1 * s1; + c3 = c2 * c1 - s2 * s1; + s3 = c2 * s1 + s2 * c1; + kk = kk - nt + jc; + } while (kk < kspan); + kk = kk - kspan + inc; + } while (kk < jc); + if (kspan == jc) + goto Permute_Results_Label; /* exit infinite loop */ + break; + + default: + /* transform for odd factors */ +#ifdef FFT_RADIX4 + return -1; + break; +#else /* FFT_RADIX4 */ + k = fftstate->factor [ii - 1]; + ispan = kspan; + kspan /= k; + + switch (k) { + case 3: /* transform for factor of 3 (optional code) */ + do { + do { + k1 = kk + kspan; + k2 = k1 + kspan; + ak = Re [kk]; + bk = Im [kk]; + aj = Re [k1] + Re [k2]; + bj = Im [k1] + Im [k2]; + Re [kk] = ak + aj; + Im [kk] = bk + bj; + ak -= 0.5 * aj; + bk -= 0.5 * bj; + aj = (Re [k1] - Re [k2]) * s60; + bj = (Im [k1] - Im [k2]) * s60; + Re [k1] = ak - bj; + Re [k2] = ak + bj; + Im [k1] = bk + aj; + Im [k2] = bk - aj; + kk = k2 + kspan; + } while (kk < (nn - 1)); + kk -= nn; + } while (kk < kspan); + break; + + case 5: /* transform for factor of 5 (optional code) */ + c2 = c72 * c72 - s72 * s72; + s2 = 2.0 * c72 * s72; + do { + do { + k1 = kk + kspan; + k2 = k1 + kspan; + k3 = k2 + kspan; + k4 = k3 + kspan; + akp = Re [k1] + Re [k4]; + akm = Re [k1] - Re [k4]; + bkp = Im [k1] + Im [k4]; + bkm = Im [k1] - Im [k4]; + ajp = Re [k2] + Re [k3]; + ajm = Re [k2] - Re [k3]; + bjp = Im [k2] + Im [k3]; + bjm = Im [k2] - Im [k3]; + aa = Re [kk]; + bb = Im [kk]; + Re [kk] = aa + akp + ajp; + Im [kk] = bb + bkp + bjp; + ak = akp * c72 + ajp * c2 + aa; + bk = bkp * c72 + bjp * c2 + bb; + aj = akm * s72 + ajm * s2; + bj = bkm * s72 + bjm * s2; + Re [k1] = ak - bj; + Re [k4] = ak + bj; + Im [k1] = bk + aj; + Im [k4] = bk - aj; + ak = akp * c2 + ajp * c72 + aa; + bk = bkp * c2 + bjp * c72 + bb; + aj = akm * s2 - ajm * s72; + bj = bkm * s2 - bjm * s72; + Re [k2] = ak - bj; + Re [k3] = ak + bj; + Im [k2] = bk + aj; + Im [k3] = bk - aj; + kk = k4 + kspan; + } while (kk < (nn-1)); + kk -= nn; + } while (kk < kspan); + break; + + default: + if (k != jf) { + jf = k; + s1 = pi2 / (double) k; + c1 = cos(s1); + s1 = sin(s1); + if (jf > max_factors){ + return -1; + } + Cos [jf - 1] = 1.0; + Sin [jf - 1] = 0.0; + j = 1; + do { + Cos [j - 1] = Cos [k - 1] * c1 + Sin [k - 1] * s1; + Sin [j - 1] = Cos [k - 1] * s1 - Sin [k - 1] * c1; + k--; + Cos [k - 1] = Cos [j - 1]; + Sin [k - 1] = -Sin [j - 1]; + j++; + } while (j < k); + } + do { + do { + k1 = kk; + k2 = kk + ispan; + ak = aa = Re [kk]; + bk = bb = Im [kk]; + j = 1; + k1 += kspan; + do { + k2 -= kspan; + j++; + Rtmp [j - 1] = Re [k1] + Re [k2]; + ak += Rtmp [j - 1]; + Itmp [j - 1] = Im [k1] + Im [k2]; + bk += Itmp [j - 1]; + j++; + Rtmp [j - 1] = Re [k1] - Re [k2]; + Itmp [j - 1] = Im [k1] - Im [k2]; + k1 += kspan; + } while (k1 < k2); + Re [kk] = ak; + Im [kk] = bk; + k1 = kk; + k2 = kk + ispan; + j = 1; + do { + k1 += kspan; + k2 -= kspan; + jj = j; + ak = aa; + bk = bb; + aj = 0.0; + bj = 0.0; + k = 1; + do { + k++; + ak += Rtmp [k - 1] * Cos [jj - 1]; + bk += Itmp [k - 1] * Cos [jj - 1]; + k++; + aj += Rtmp [k - 1] * Sin [jj - 1]; + bj += Itmp [k - 1] * Sin [jj - 1]; + jj += j; + if (jj > jf) { + jj -= jf; + } + } while (k < jf); + k = jf - j; + Re [k1] = ak - bj; + Im [k1] = bk + aj; + Re [k2] = ak + bj; + Im [k2] = bk - aj; + j++; + } while (j < k); + kk += ispan; + } while (kk < nn); + kk -= nn; + } while (kk < kspan); + break; + } + + /* multiply by rotation factor (except for factors of 2 and 4) */ + if (ii == mfactor) + goto Permute_Results_Label; /* exit infinite loop */ + kk = jc; + do { + c2 = 1.0 - cd; + s1 = sd; + do { + c1 = c2; + s2 = s1; + kk += kspan; + do { + do { + ak = Re [kk]; + Re [kk] = c2 * ak - s2 * Im [kk]; + Im [kk] = s2 * ak + c2 * Im [kk]; + kk += ispan; + } while (kk < nt); + ak = s1 * s2; + s2 = s1 * c2 + c1 * s2; + c2 = c1 * c2 - ak; + kk = kk - nt + kspan; + } while (kk < ispan); + c2 = c1 - (cd * c1 + sd * s1); + s1 += sd * c1 - cd * s1; + c1 = 2.0 - (c2 * c2 + s1 * s1); + s1 *= c1; + c2 *= c1; + kk = kk - ispan + jc; + } while (kk < kspan); + kk = kk - kspan + jc + inc; + } while (kk < (jc + jc)); + break; +#endif /* FFT_RADIX4 */ + } + } + + /* permute the results to normal order---done in two stages */ + /* permutation for square factors of n */ +Permute_Results_Label: + fftstate->Perm [0] = ns; + if (kt) { + k = kt + kt + 1; + if (mfactor < k) + k--; + j = 1; + fftstate->Perm [k] = jc; + do { + fftstate->Perm [j] = fftstate->Perm [j - 1] / fftstate->factor [j - 1]; + fftstate->Perm [k - 1] = fftstate->Perm [k] * fftstate->factor [j - 1]; + j++; + k--; + } while (j < k); + k3 = fftstate->Perm [k]; + kspan = fftstate->Perm [1]; + kk = jc; + k2 = kspan; + j = 1; + if (nPass != nTotal) { + /* permutation for multivariate transform */ + Permute_Multi_Label: + do { + do { + k = kk + jc; + do { + /* swap Re [kk] <> Re [k2], Im [kk] <> Im [k2] */ + ak = Re [kk]; Re [kk] = Re [k2]; Re [k2] = ak; + bk = Im [kk]; Im [kk] = Im [k2]; Im [k2] = bk; + kk += inc; + k2 += inc; + } while (kk < (k-1)); + kk += ns - jc; + k2 += ns - jc; + } while (kk < (nt-1)); + k2 = k2 - nt + kspan; + kk = kk - nt + jc; + } while (k2 < (ns-1)); + do { + do { + k2 -= fftstate->Perm [j - 1]; + j++; + k2 = fftstate->Perm [j] + k2; + } while (k2 > fftstate->Perm [j - 1]); + j = 1; + do { + if (kk < (k2-1)) + goto Permute_Multi_Label; + kk += jc; + k2 += kspan; + } while (k2 < (ns-1)); + } while (kk < (ns-1)); + } else { + /* permutation for single-variate transform (optional code) */ + Permute_Single_Label: + do { + /* swap Re [kk] <> Re [k2], Im [kk] <> Im [k2] */ + ak = Re [kk]; Re [kk] = Re [k2]; Re [k2] = ak; + bk = Im [kk]; Im [kk] = Im [k2]; Im [k2] = bk; + kk += inc; + k2 += kspan; + } while (k2 < (ns-1)); + do { + do { + k2 -= fftstate->Perm [j - 1]; + j++; + k2 = fftstate->Perm [j] + k2; + } while (k2 >= fftstate->Perm [j - 1]); + j = 1; + do { + if (kk < k2) + goto Permute_Single_Label; + kk += inc; + k2 += kspan; + } while (k2 < (ns-1)); + } while (kk < (ns-1)); + } + jc = k3; + } + + if ((kt << 1) + 1 >= mfactor) + return 0; + ispan = fftstate->Perm [kt]; + /* permutation for square-free factors of n */ + j = mfactor - kt; + fftstate->factor [j] = 1; + do { + fftstate->factor [j - 1] *= fftstate->factor [j]; + j--; + } while (j != kt); + kt++; + nn = fftstate->factor [kt - 1] - 1; + if (nn > (int) max_perm) { + return -1; + } + j = jj = 0; + for (;;) { + k = kt + 1; + k2 = fftstate->factor [kt - 1]; + kk = fftstate->factor [k - 1]; + j++; + if (j > nn) + break; /* exit infinite loop */ + jj += kk; + while (jj >= k2) { + jj -= k2; + k2 = kk; + k++; + kk = fftstate->factor [k - 1]; + jj += kk; + } + fftstate->Perm [j - 1] = jj; + } + /* determine the permutation cycles of length greater than 1 */ + j = 0; + for (;;) { + do { + j++; + kk = fftstate->Perm [j - 1]; + } while (kk < 0); + if (kk != j) { + do { + k = kk; + kk = fftstate->Perm [k - 1]; + fftstate->Perm [k - 1] = -kk; + } while (kk != j); + k3 = kk; + } else { + fftstate->Perm [j - 1] = -j; + if (j == nn) + break; /* exit infinite loop */ + } + } + max_factors *= inc; + /* reorder a and b, following the permutation cycles */ + for (;;) { + j = k3 + 1; + nt -= ispan; + ii = nt - inc + 1; + if (nt < 0) + break; /* exit infinite loop */ + do { + do { + j--; + } while (fftstate->Perm [j - 1] < 0); + jj = jc; + do { + kspan = jj; + if (jj > max_factors) { + kspan = max_factors; + } + jj -= kspan; + k = fftstate->Perm [j - 1]; + kk = jc * k + ii + jj; + k1 = kk + kspan - 1; + k2 = 0; + do { + k2++; + Rtmp [k2 - 1] = Re [k1]; + Itmp [k2 - 1] = Im [k1]; + k1 -= inc; + } while (k1 != (kk-1)); + do { + k1 = kk + kspan - 1; + k2 = k1 - jc * (k + fftstate->Perm [k - 1]); + k = -fftstate->Perm [k - 1]; + do { + Re [k1] = Re [k2]; + Im [k1] = Im [k2]; + k1 -= inc; + k2 -= inc; + } while (k1 != (kk-1)); + kk = k2 + 1; + } while (k != j); + k1 = kk + kspan - 1; + k2 = 0; + do { + k2++; + Re [k1] = Rtmp [k2 - 1]; + Im [k1] = Itmp [k2 - 1]; + k1 -= inc; + } while (k1 != (kk-1)); + } while (jj); + } while (j != 1); + } + return 0; /* exit point here */ +} +/* ---------------------- end-of-file (c source) ---------------------- */ + diff --git a/src/modules/audio_coding/codecs/isac/main/source/fft.h b/src/modules/audio_coding/codecs/isac/main/source/fft.h new file mode 100644 index 0000000000..a42f57bcb5 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/fft.h @@ -0,0 +1,45 @@ +/* + * 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. + */ + +/*--------------------------------*-C-*---------------------------------* + * File: + * fftn.h + * ---------------------------------------------------------------------* + * Re[]: real value array + * Im[]: imaginary value array + * nTotal: total number of complex values + * nPass: number of elements involved in this pass of transform + * nSpan: nspan/nPass = number of bytes to increment pointer + * in Re[] and Im[] + * isign: exponent: +1 = forward -1 = reverse + * scaling: normalizing constant by which the final result is *divided* + * scaling == -1, normalize by total dimension of the transform + * scaling < -1, normalize by the square-root of the total dimension + * + * ---------------------------------------------------------------------- + * See the comments in the code for correct usage! + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FFT_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FFT_H_ + + +#include "structs.h" + + +/* double precision routine */ + + +int WebRtcIsac_Fftns (unsigned int ndim, const int dims[], double Re[], double Im[], + int isign, double scaling, FFTstr *fftstate); + + + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FFT_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/main/source/filter_functions.c b/src/modules/audio_coding/codecs/isac/main/source/filter_functions.c new file mode 100644 index 0000000000..33024a3dee --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/filter_functions.c @@ -0,0 +1,271 @@ +/* + * 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. + */ + +#include +#ifdef WEBRTC_ANDROID +#include +#endif +#include "pitch_estimator.h" +#include "lpc_analysis.h" +#include "codec.h" + + + +void WebRtcIsac_AllPoleFilter(double *InOut, double *Coef, int lengthInOut, int orderCoef){ + + /* the state of filter is assumed to be in InOut[-1] to InOut[-orderCoef] */ + double scal; + double sum; + int n,k; + + //if (fabs(Coef[0]-1.0)<0.001) { + if ( (Coef[0] > 0.9999) && (Coef[0] < 1.0001) ) + { + for(n = 0; n < lengthInOut; n++) + { + sum = Coef[1] * InOut[-1]; + for(k = 2; k <= orderCoef; k++){ + sum += Coef[k] * InOut[-k]; + } + *InOut++ -= sum; + } + } + else + { + scal = 1.0 / Coef[0]; + for(n=0;nbuffer, sizeof(double) * PITCH_WLPCBUFLEN); + memcpy(tmpbuffer+PITCH_WLPCBUFLEN, in, sizeof(double) * PITCH_FRAME_LEN); + memcpy(wfdata->buffer, tmpbuffer+PITCH_FRAME_LEN, sizeof(double) * PITCH_WLPCBUFLEN); + + dp=weoutbuf; + dp2=whoutbuf; + for (k=0;kweostate[k]; + *dp2++ = wfdata->whostate[k]; + opol[k]=0.0; + } + opol[0]=1.0; + opol[PITCH_WLPCORDER]=0.0; + weo=dp; + who=dp2; + + endpos=PITCH_WLPCBUFLEN + PITCH_SUBFRAME_LEN; + inp=tmpbuffer + PITCH_WLPCBUFLEN; + + for (n=0; nwindow[k]*tmpbuffer[start+k]; + } + + /* Get LPC polynomial */ + WebRtcIsac_AutoCorr(corr, ext, PITCH_WLPCWINLEN, PITCH_WLPCORDER); + corr[0]=1.01*corr[0]+1.0; /* White noise correction */ + WebRtcIsac_LevDurb(apol, rc, corr, PITCH_WLPCORDER); + WebRtcIsac_BwExpand(apolr, apol, rho, PITCH_WLPCORDER+1); + + /* Filtering */ + WebRtcIsac_ZeroPoleFilter(inp, apol, apolr, PITCH_SUBFRAME_LEN, PITCH_WLPCORDER, weo); + WebRtcIsac_ZeroPoleFilter(inp, apolr, opol, PITCH_SUBFRAME_LEN, PITCH_WLPCORDER, who); + + inp+=PITCH_SUBFRAME_LEN; + endpos+=PITCH_SUBFRAME_LEN; + weo+=PITCH_SUBFRAME_LEN; + who+=PITCH_SUBFRAME_LEN; + } + + /* Export filter states */ + for (k=0;kweostate[k]=weoutbuf[PITCH_FRAME_LEN+k]; + wfdata->whostate[k]=whoutbuf[PITCH_FRAME_LEN+k]; + } + + /* Export output data */ + memcpy(weiout, weoutbuf+PITCH_WLPCORDER, sizeof(double) * PITCH_FRAME_LEN); + memcpy(whiout, whoutbuf+PITCH_WLPCORDER, sizeof(double) * PITCH_FRAME_LEN); +} + + +static const double APupper[ALLPASSSECTIONS] = {0.0347, 0.3826}; +static const double APlower[ALLPASSSECTIONS] = {0.1544, 0.744}; + + + +void WebRtcIsac_AllpassFilterForDec(double *InOut, + const double *APSectionFactors, + int lengthInOut, + double *FilterState) +{ + //This performs all-pass filtering--a series of first order all-pass sections are used + //to filter the input in a cascade manner. + int n,j; + double temp; + for (j=0; jINLABUFx arrays + each of length QLOOKAHEAD. + The remaining FRAMESAMPLES_HALF-QLOOKAHEAD samples are based + on the first FRAMESAMPLES_HALF-QLOOKAHEAD samples of the input + array in[]. + HP: a FRAMESAMPLES_HALF array of high-pass filtered samples that + have been phase equalized. The first QLOOKAHEAD samples are + based on the samples in the two prefiltdata->INLABUFx arrays + each of length QLOOKAHEAD. + The remaining FRAMESAMPLES_HALF-QLOOKAHEAD samples are based + on the first FRAMESAMPLES_HALF-QLOOKAHEAD samples of the input + array in[]. + + LP_la: a FRAMESAMPLES_HALF array of low-pass filtered samples. + These samples are not phase equalized. They are computed + from the samples in the in[] array. + HP_la: a FRAMESAMPLES_HALF array of high-pass filtered samples + that are not phase equalized. They are computed from + the in[] vector. + prefiltdata: this input data structure's filterbank state and + lookahead sample buffers are updated for the next + encoding iteration. +*/ +void WebRtcIsac_SplitAndFilterFloat(float *pin, float *LP, float *HP, + double *LP_la, double *HP_la, + PreFiltBankstr *prefiltdata) +{ + int k,n; + float CompositeAPFilterState[NUMBEROFCOMPOSITEAPSECTIONS]; + float ForTransform_CompositeAPFilterState[NUMBEROFCOMPOSITEAPSECTIONS]; + float ForTransform_CompositeAPFilterState2[NUMBEROFCOMPOSITEAPSECTIONS]; + float tempinoutvec[FRAMESAMPLES+MAX_AR_MODEL_ORDER]; + float tempin_ch1[FRAMESAMPLES+MAX_AR_MODEL_ORDER]; + float tempin_ch2[FRAMESAMPLES+MAX_AR_MODEL_ORDER]; + float in[FRAMESAMPLES]; + float ftmp; + + + /* High pass filter */ + + for (k=0;kHPstates_float[0] + + kHpStCoefInFloat[3] * prefiltdata->HPstates_float[1]; + ftmp = pin[k] - kHpStCoefInFloat[0] * prefiltdata->HPstates_float[0] - + kHpStCoefInFloat[1] * prefiltdata->HPstates_float[1]; + prefiltdata->HPstates_float[1] = prefiltdata->HPstates_float[0]; + prefiltdata->HPstates_float[0] = ftmp; + } + + /* + % backwards all-pass filtering to obtain zero-phase + [tmp1(N2+LA:-1:LA+1, 1), state1] = filter(Q.coef, Q.coef(end:-1:1), in(N:-2:2)); + tmp1(LA:-1:1) = filter(Q.coef, Q.coef(end:-1:1), Q.LookAheadBuf1, state1); + Q.LookAheadBuf1 = in(N:-2:N-2*LA+2); + */ + /*Backwards all-pass filter the odd samples of the input (upper channel) + to eventually obtain zero phase. The composite all-pass filter (comprised of both + the upper and lower channel all-pass filsters in series) is used for the + filtering. */ + + /* First Channel */ + + /*initial state of composite filter is zero */ + for (k=0;kINLABUF1_float, + WebRtcIsac_kCompositeApFactorsFloat, QLOOKAHEAD, + NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState); + + /* save the output, but write it in forward order */ + /* write the lookahead samples for the next encoding iteration. Every other + sample at the end of the input frame is written in reverse order for the + lookahead length. Exported in the prefiltdata structure. */ + for (k=0;kINLABUF1_float[k]; + prefiltdata->INLABUF1_float[k]=in[FRAMESAMPLES-1-2*k]; + } + + /* Second Channel. This is exactly like the first channel, except that the + even samples are now filtered instead (lower channel). */ + for (k=0;kINLABUF2_float, + WebRtcIsac_kCompositeApFactorsFloat, QLOOKAHEAD,NUMBEROFCOMPOSITEAPSECTIONS, + CompositeAPFilterState); + + for (k=0;kINLABUF2_float[k]; + prefiltdata->INLABUF2_float[k]=in[FRAMESAMPLES-2-2*k]; + } + + /* Transform filter states from backward to forward */ + /*At this point, each of the states of the backwards composite filters for the + two channels are transformed into forward filtering states for the corresponding + forward channel filters. Each channel's forward filtering state from the previous + encoding iteration is added to the transformed state to get a proper forward state */ + + /* So the existing NUMBEROFCOMPOSITEAPSECTIONS x 1 (4x1) state vector is multiplied by a + NUMBEROFCHANNELAPSECTIONSxNUMBEROFCOMPOSITEAPSECTIONS (2x4) transform matrix to get the + new state that is added to the previous 2x1 input state */ + + for (k=0;kINSTAT1_float[k] += ForTransform_CompositeAPFilterState[n]* + WebRtcIsac_kTransform1Float[k*NUMBEROFCHANNELAPSECTIONS+n]; + prefiltdata->INSTAT2_float[k] += ForTransform_CompositeAPFilterState2[n]* + WebRtcIsac_kTransform2Float[k*NUMBEROFCHANNELAPSECTIONS+n]; + } + } + + /*obtain polyphase components by forward all-pass filtering through each channel */ + /* the backward filtered samples are now forward filtered with the corresponding channel filters */ + /* The all pass filtering automatically updates the filter states which are exported in the + prefiltdata structure */ + WebRtcIsac_AllPassFilter2Float(tempin_ch1,WebRtcIsac_kUpperApFactorsFloat, + FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTAT1_float); + WebRtcIsac_AllPassFilter2Float(tempin_ch2,WebRtcIsac_kLowerApFactorsFloat, + FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTAT2_float); + + /* Now Construct low-pass and high-pass signals as combinations of polyphase components */ + for (k=0; kINSTATLA1_float); + WebRtcIsac_AllPassFilter2Float(tempin_ch2,WebRtcIsac_kLowerApFactorsFloat, + FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTATLA2_float); + + for (k=0; kSTATE_0_UPPER_float); + + /* Now, all-pass filter the new lower channel signal. But since all-pass filter factors + at the decoder are swapped from the ones at the encoder, the 'upper' channel + all-pass filter factors (WebRtcIsac_kUpperApFactorsFloat) are used to filter this new + lower channel signal */ + WebRtcIsac_AllPassFilter2Float(tempin_ch2, WebRtcIsac_kUpperApFactorsFloat, + FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS,postfiltdata->STATE_0_LOWER_float); + + + /* Merge outputs to form the full length output signal.*/ + for (k=0;kHPstates1_float[0] + + kHpStCoefOut1Float[3] * postfiltdata->HPstates1_float[1]; + ftmp = Out[k] - kHpStCoefOut1Float[0] * postfiltdata->HPstates1_float[0] - + kHpStCoefOut1Float[1] * postfiltdata->HPstates1_float[1]; + postfiltdata->HPstates1_float[1] = postfiltdata->HPstates1_float[0]; + postfiltdata->HPstates1_float[0] = ftmp; + Out[k] = ftmp2; + } + + for (k=0;kHPstates2_float[0] + + kHpStCoefOut2Float[3] * postfiltdata->HPstates2_float[1]; + ftmp = Out[k] - kHpStCoefOut2Float[0] * postfiltdata->HPstates2_float[0] - + kHpStCoefOut2Float[1] * postfiltdata->HPstates2_float[1]; + postfiltdata->HPstates2_float[1] = postfiltdata->HPstates2_float[0]; + postfiltdata->HPstates2_float[0] = ftmp; + Out[k] = ftmp2; + } +} diff --git a/src/modules/audio_coding/codecs/isac/main/source/intialize.c b/src/modules/audio_coding/codecs/isac/main/source/intialize.c new file mode 100644 index 0000000000..6df034d1c7 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/intialize.c @@ -0,0 +1,175 @@ +/* + * 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 "structs.h" +#include "codec.h" +#include "pitch_estimator.h" + +#include + +void WebRtcIsac_InitMasking(MaskFiltstr *maskdata) { + + int k; + + for (k = 0; k < WINLEN; k++) { + maskdata->DataBufferLo[k] = 0.0; + maskdata->DataBufferHi[k] = 0.0; + } + for (k = 0; k < ORDERLO+1; k++) { + maskdata->CorrBufLo[k] = 0.0; + maskdata->PreStateLoF[k] = 0.0; + maskdata->PreStateLoG[k] = 0.0; + maskdata->PostStateLoF[k] = 0.0; + maskdata->PostStateLoG[k] = 0.0; + } + for (k = 0; k < ORDERHI+1; k++) { + maskdata->CorrBufHi[k] = 0.0; + maskdata->PreStateHiF[k] = 0.0; + maskdata->PreStateHiG[k] = 0.0; + maskdata->PostStateHiF[k] = 0.0; + maskdata->PostStateHiG[k] = 0.0; + } + + maskdata->OldEnergy = 10.0; + + /* fill tables for transforms */ + WebRtcIsac_InitTransform(); + + return; +} + +void WebRtcIsac_InitPreFilterbank(PreFiltBankstr *prefiltdata) +{ + int k; + + for (k = 0; k < QLOOKAHEAD; k++) { + prefiltdata->INLABUF1[k] = 0; + prefiltdata->INLABUF2[k] = 0; + + prefiltdata->INLABUF1_float[k] = 0; + prefiltdata->INLABUF2_float[k] = 0; + } + for (k = 0; k < 2*(QORDER-1); k++) { + prefiltdata->INSTAT1[k] = 0; + prefiltdata->INSTAT2[k] = 0; + prefiltdata->INSTATLA1[k] = 0; + prefiltdata->INSTATLA2[k] = 0; + + prefiltdata->INSTAT1_float[k] = 0; + prefiltdata->INSTAT2_float[k] = 0; + prefiltdata->INSTATLA1_float[k] = 0; + prefiltdata->INSTATLA2_float[k] = 0; + } + + /* High pass filter states */ + prefiltdata->HPstates[0] = 0.0; + prefiltdata->HPstates[1] = 0.0; + + prefiltdata->HPstates_float[0] = 0.0f; + prefiltdata->HPstates_float[1] = 0.0f; + + return; +} + +void WebRtcIsac_InitPostFilterbank(PostFiltBankstr *postfiltdata) +{ + int k; + + for (k = 0; k < 2*POSTQORDER; k++) { + postfiltdata->STATE_0_LOWER[k] = 0; + postfiltdata->STATE_0_UPPER[k] = 0; + + postfiltdata->STATE_0_LOWER_float[k] = 0; + postfiltdata->STATE_0_UPPER_float[k] = 0; + } + + /* High pass filter states */ + postfiltdata->HPstates1[0] = 0.0; + postfiltdata->HPstates1[1] = 0.0; + + postfiltdata->HPstates2[0] = 0.0; + postfiltdata->HPstates2[1] = 0.0; + + postfiltdata->HPstates1_float[0] = 0.0f; + postfiltdata->HPstates1_float[1] = 0.0f; + + postfiltdata->HPstates2_float[0] = 0.0f; + postfiltdata->HPstates2_float[1] = 0.0f; + + return; +} + + +void WebRtcIsac_InitPitchFilter(PitchFiltstr *pitchfiltdata) +{ + int k; + + for (k = 0; k < PITCH_BUFFSIZE; k++) { + pitchfiltdata->ubuf[k] = 0.0; + } + pitchfiltdata->ystate[0] = 0.0; + for (k = 1; k < (PITCH_DAMPORDER); k++) { + pitchfiltdata->ystate[k] = 0.0; + } + pitchfiltdata->oldlagp[0] = 50.0; + pitchfiltdata->oldgainp[0] = 0.0; +} + +void WebRtcIsac_InitWeightingFilter(WeightFiltstr *wfdata) +{ + int k; + double t, dtmp, dtmp2, denum, denum2; + + for (k=0;kbuffer[k]=0.0; + + for (k=0;kistate[k]=0.0; + wfdata->weostate[k]=0.0; + wfdata->whostate[k]=0.0; + } + + /* next part should be in Matlab, writing to a global table */ + t = 0.5; + denum = 1.0 / ((double) PITCH_WLPCWINLEN); + denum2 = denum * denum; + for (k=0;kwindow[k] = dtmp2 * dtmp2; + t++; + } +} + +/* clear all buffers */ +void WebRtcIsac_InitPitchAnalysis(PitchAnalysisStruct *State) +{ + int k; + + for (k = 0; k < PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2; k++) + State->dec_buffer[k] = 0.0; + for (k = 0; k < 2*ALLPASSSECTIONS+1; k++) + State->decimator_state[k] = 0.0; + for (k = 0; k < 2; k++) + State->hp_state[k] = 0.0; + for (k = 0; k < QLOOKAHEAD; k++) + State->whitened_buf[k] = 0.0; + for (k = 0; k < QLOOKAHEAD; k++) + State->inbuf[k] = 0.0; + + WebRtcIsac_InitPitchFilter(&(State->PFstr_wght)); + + WebRtcIsac_InitPitchFilter(&(State->PFstr)); + + WebRtcIsac_InitWeightingFilter(&(State->Wghtstr)); +} diff --git a/src/modules/audio_coding/codecs/isac/main/source/isac.c b/src/modules/audio_coding/codecs/isac/main/source/isac.c new file mode 100644 index 0000000000..7c90334670 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/isac.c @@ -0,0 +1,2313 @@ +/* + * 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. + */ + +/* + * isac.c + * + * This C file contains the functions for the ISAC API + * + */ + +#include "isac.h" +#include "bandwidth_estimator.h" +#include "crc.h" +#include "entropy_coding.h" +#include "codec.h" +#include "structs.h" +#include "signal_processing_library.h" +#include "lpc_shape_swb16_tables.h" +#include "os_specific_inline.h" + +#include +#include +#include +#include + +#define BIT_MASK_DEC_INIT 0x0001 +#define BIT_MASK_ENC_INIT 0x0002 + +#define LEN_CHECK_SUM_WORD8 4 +#define MAX_NUM_LAYERS 10 + + +/**************************************************************************** + * UpdatePayloadSizeLimit(...) + * + * Call this function to update the limit on the payload size. The limit on + * payload size might change i) if a user ''directly changes the limit by + * calling xxx_setMaxPayloadSize() or xxx_setMaxRate(), or ii) indirectly + * when bandwidth is changing. The latter might be the result of bandwidth + * adaptation, or direct change of the bottleneck in instantaneous mode. + * + * This function takes the current overall limit on payload, and translates it + * to the limits on lower and upper-band. If the codec is in wideband mode, + * then the overall limit and the limit on the lower-band is the same. + * Otherwise, a fraction of the limit should be allocated to lower-band + * leaving some room for the upper-band bit-stream. That is why an update + * of limit is required every time that the bandwidth is changing. + * + */ +static void UpdatePayloadSizeLimit(ISACMainStruct* instISAC) { + WebRtc_Word16 lim30MsPayloadBytes = WEBRTC_SPL_MIN( + (instISAC->maxPayloadSizeBytes), + (instISAC->maxRateBytesPer30Ms)); + WebRtc_Word16 lim60MsPayloadBytes = WEBRTC_SPL_MIN( + (instISAC->maxPayloadSizeBytes), + (instISAC->maxRateBytesPer30Ms << 1)); + + /* The only time that iSAC will have 60 ms + * frame-size is when operating in wideband, so + * there is no upper-band bit-stream. */ + + if (instISAC->bandwidthKHz == isac8kHz) { + /* At 8 kHz there is no upper-band bit-stream, + * therefore, the lower-band limit is the overall limit. */ + instISAC->instLB.ISACencLB_obj.payloadLimitBytes60 = + lim60MsPayloadBytes; + instISAC->instLB.ISACencLB_obj.payloadLimitBytes30 = + lim30MsPayloadBytes; + } else { + /* When in super-wideband, we only have 30 ms frames. + * Do a rate allocation for the given limit. */ + if (lim30MsPayloadBytes > 250) { + /* 4/5 to lower-band the rest for upper-band. */ + instISAC->instLB.ISACencLB_obj.payloadLimitBytes30 = + (lim30MsPayloadBytes << 2) / 5; + } else if (lim30MsPayloadBytes > 200) { + /* For the interval of 200 to 250 the share of + * upper-band linearly grows from 20 to 50. */ + instISAC->instLB.ISACencLB_obj.payloadLimitBytes30 = + (lim30MsPayloadBytes << 1) / 5 + 100; + } else { + /* Allocate only 20 for upper-band. */ + instISAC->instLB.ISACencLB_obj.payloadLimitBytes30 = + lim30MsPayloadBytes - 20; + } + instISAC->instUB.ISACencUB_obj.maxPayloadSizeBytes = + lim30MsPayloadBytes; + } +} + + +/**************************************************************************** + * UpdateBottleneck(...) + * + * This function updates the bottleneck only if the codec is operating in + * channel-adaptive mode. Furthermore, as the update of bottleneck might + * result in an update of bandwidth, therefore, the bottlenech should be + * updated just right before the first 10ms of a frame is pushed into encoder. + * + */ +static void UpdateBottleneck(ISACMainStruct* instISAC) { + /* Read the bottleneck from bandwidth estimator for the + * first 10 ms audio. This way, if there is a change + * in bandwidth, upper and lower-band will be in sync. */ + if ((instISAC->codingMode == 0) && + (instISAC->instLB.ISACencLB_obj.buffer_index == 0) && + (instISAC->instLB.ISACencLB_obj.frame_nb == 0)) { + WebRtc_Word32 bottleneck; + WebRtcIsac_GetUplinkBandwidth(&(instISAC->bwestimator_obj), + &bottleneck); + + /* Adding hysteresis when increasing signal bandwidth. */ + if ((instISAC->bandwidthKHz == isac8kHz) + && (bottleneck > 37000) + && (bottleneck < 41000)) { + bottleneck = 37000; + } + + /* Switching from 12 kHz to 16 kHz is not allowed at this revision. + * If we let this happen, we have to take care of buffer_index and + * the last LPC vector. */ + if ((instISAC->bandwidthKHz != isac16kHz) && + (bottleneck > 46000)) { + bottleneck = 46000; + } + + /* We might need a rate allocation. */ + if (instISAC->encoderSamplingRateKHz == kIsacWideband) { + /* Wideband is the only choice we have here. */ + instISAC->instLB.ISACencLB_obj.bottleneck = + (bottleneck > 32000) ? 32000 : bottleneck; + instISAC->bandwidthKHz = isac8kHz; + } else { + /* Do the rate-allocation and get the new bandwidth. */ + enum ISACBandwidth bandwidth; + WebRtcIsac_RateAllocation(bottleneck, + &(instISAC->instLB.ISACencLB_obj.bottleneck), + &(instISAC->instUB.ISACencUB_obj.bottleneck), + &bandwidth); + if (bandwidth != isac8kHz) { + instISAC->instLB.ISACencLB_obj.new_framelength = 480; + } + if (bandwidth != instISAC->bandwidthKHz) { + /* Bandwidth is changing. */ + instISAC->bandwidthKHz = bandwidth; + UpdatePayloadSizeLimit(instISAC); + if (bandwidth == isac12kHz) { + instISAC->instLB.ISACencLB_obj.buffer_index = 0; + } + /* Currently we don't let the bandwidth to switch to 16 kHz + * if in adaptive mode. If we let this happen, we have to take + * care of buffer_index and the last LPC vector. */ + } + } + } +} + + +/**************************************************************************** + * GetSendBandwidthInfo(...) + * + * This is called to get the bandwidth info. This info is the bandwidth and + * the jitter of 'there-to-here' channel, estimated 'here.' These info + * is signaled in an in-band fashion to the other side. + * + * The call to the bandwidth estimator triggers a recursive averaging which + * has to be synchronized between encoder & decoder, therefore, the call to + * BWE should be once per packet. As the BWE info is inserted into bit-stream + * We need a valid info right before the encodeLB function is going to + * generate a bit-stream. That is when lower-band buffer has already 20ms + * of audio, and the 3rd block of 10ms is going to be injected into encoder. + * + * Inputs: + * - instISAC : iSAC instance. + * + * Outputs: + * - bandwidthIndex : an index which has to be encoded in + * lower-band bit-stream, indicating the + * bandwidth of there-to-here channel. + * - jitterInfo : this indicates if the jitter is high + * or low and it is encoded in upper-band + * bit-stream. + * + */ +static void GetSendBandwidthInfo(ISACMainStruct* instISAC, + WebRtc_Word16* bandwidthIndex, + WebRtc_Word16* jitterInfo) { + if ((instISAC->instLB.ISACencLB_obj.buffer_index == + (FRAMESAMPLES_10ms << 1)) && + (instISAC->instLB.ISACencLB_obj.frame_nb == 0)) { + /* Bandwidth estimation and coding. */ + WebRtcIsac_GetDownlinkBwJitIndexImpl(&(instISAC->bwestimator_obj), + bandwidthIndex, jitterInfo, + instISAC->decoderSamplingRateKHz); + } +} + + +/**************************************************************************** + * WebRtcIsac_AssignSize(...) + * + * This function returns the size of the ISAC instance, so that the instance + * can be created out side iSAC. + * + * Output: + * - sizeinbytes : number of bytes needed to allocate for the + * instance. + * + * Return value : 0 - Ok + * -1 - Error + */ +WebRtc_Word16 WebRtcIsac_AssignSize(int* sizeInBytes) { + *sizeInBytes = sizeof(ISACMainStruct) * 2 / sizeof(WebRtc_Word16); + return 0; +} + + +/**************************************************************************** + * WebRtcIsac_Assign(...) + * + * This function assigns the memory already created to the ISAC instance. + * + * Input: + * - ISAC_main_inst : address of the pointer to the coder instance. + * - instISAC_Addr : the already allocated memory, where we put the + * iSAC structure. + * + * Return value : 0 - Ok + * -1 - Error + */ +WebRtc_Word16 WebRtcIsac_Assign(ISACStruct** ISAC_main_inst, + void* instISAC_Addr) { + if (instISAC_Addr != NULL) { + ISACMainStruct* instISAC = (ISACMainStruct*)instISAC_Addr; + instISAC->errorCode = 0; + instISAC->initFlag = 0; + + /* Assign the address. */ + *ISAC_main_inst = (ISACStruct*)instISAC_Addr; + + /* Default is wideband. */ + instISAC->encoderSamplingRateKHz = kIsacWideband; + instISAC->decoderSamplingRateKHz = kIsacWideband; + instISAC->bandwidthKHz = isac8kHz; + return 0; + } else { + return -1; + } +} + + +/**************************************************************************** + * WebRtcIsac_Create(...) + * + * This function creates an ISAC instance, which will contain the state + * information for one coding/decoding channel. + * + * Input: + * - ISAC_main_inst : address of the pointer to the coder instance. + * + * Return value : 0 - Ok + * -1 - Error + */ +WebRtc_Word16 WebRtcIsac_Create(ISACStruct** ISAC_main_inst) { + ISACMainStruct* instISAC; + + instISAC = (ISACMainStruct*)WEBRTC_SPL_VNEW(ISACMainStruct, 1); + *ISAC_main_inst = (ISACStruct*)instISAC; + if (*ISAC_main_inst != NULL) { + instISAC->errorCode = 0; + instISAC->initFlag = 0; + /* Default is wideband. */ + instISAC->bandwidthKHz = isac8kHz; + instISAC->encoderSamplingRateKHz = kIsacWideband; + instISAC->decoderSamplingRateKHz = kIsacWideband; + return 0; + } else { + return -1; + } +} + + +/**************************************************************************** + * WebRtcIsac_Free(...) + * + * This function frees the ISAC instance created at the beginning. + * + * Input: + * - ISAC_main_inst : a ISAC instance. + * + * Return value : 0 - Ok + * -1 - Error + */ +WebRtc_Word16 WebRtcIsac_Free(ISACStruct* ISAC_main_inst) { + ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; + WEBRTC_SPL_FREE(instISAC); + return 0; +} + + +/**************************************************************************** + * EncoderInitLb(...) - internal function for initialization of + * Lower Band + * EncoderInitUb(...) - internal function for initialization of + * Upper Band + * WebRtcIsac_EncoderInit(...) - API function + * + * This function initializes a ISAC instance prior to the encoder calls. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - CodingMode : 0 -> Bit rate and frame length are automatically + * adjusted to available bandwidth on + * transmission channel, applicable just to + * wideband mode. + * 1 -> User sets a frame length and a target bit + * rate which is taken as the maximum + * short-term average bit rate. + * + * Return value : 0 - Ok + * -1 - Error + */ +static WebRtc_Word16 EncoderInitLb(ISACLBStruct* instLB, + WebRtc_Word16 codingMode, + enum IsacSamplingRate sampRate) { + WebRtc_Word16 statusInit = 0; + int k; + + /* Init stream vector to zero */ + for (k = 0; k < STREAM_SIZE_MAX_60; k++) { + instLB->ISACencLB_obj.bitstr_obj.stream[k] = 0; + } + + if ((codingMode == 1) || (sampRate == kIsacSuperWideband)) { + /* 30 ms frame-size if either in super-wideband or + * instantaneous mode (I-mode). */ + instLB->ISACencLB_obj.new_framelength = 480; + } else { + instLB->ISACencLB_obj.new_framelength = INITIAL_FRAMESAMPLES; + } + + WebRtcIsac_InitMasking(&instLB->ISACencLB_obj.maskfiltstr_obj); + WebRtcIsac_InitPreFilterbank(&instLB->ISACencLB_obj.prefiltbankstr_obj); + WebRtcIsac_InitPitchFilter(&instLB->ISACencLB_obj.pitchfiltstr_obj); + WebRtcIsac_InitPitchAnalysis( + &instLB->ISACencLB_obj.pitchanalysisstr_obj); + + instLB->ISACencLB_obj.buffer_index = 0; + instLB->ISACencLB_obj.frame_nb = 0; + /* Default for I-mode. */ + instLB->ISACencLB_obj.bottleneck = 32000; + instLB->ISACencLB_obj.current_framesamples = 0; + instLB->ISACencLB_obj.s2nr = 0; + instLB->ISACencLB_obj.payloadLimitBytes30 = STREAM_SIZE_MAX_30; + instLB->ISACencLB_obj.payloadLimitBytes60 = STREAM_SIZE_MAX_60; + instLB->ISACencLB_obj.maxPayloadBytes = STREAM_SIZE_MAX_60; + instLB->ISACencLB_obj.maxRateInBytes = STREAM_SIZE_MAX_30; + instLB->ISACencLB_obj.enforceFrameSize = 0; + /* Invalid value prevents getRedPayload to + run before encoder is called. */ + instLB->ISACencLB_obj.lastBWIdx = -1; + return statusInit; +} + +static WebRtc_Word16 EncoderInitUb(ISACUBStruct* instUB, + WebRtc_Word16 bandwidth) { + WebRtc_Word16 statusInit = 0; + int k; + + /* Init stream vector to zero. */ + for (k = 0; k < STREAM_SIZE_MAX_60; k++) { + instUB->ISACencUB_obj.bitstr_obj.stream[k] = 0; + } + + WebRtcIsac_InitMasking(&instUB->ISACencUB_obj.maskfiltstr_obj); + WebRtcIsac_InitPreFilterbank(&instUB->ISACencUB_obj.prefiltbankstr_obj); + + if (bandwidth == isac16kHz) { + instUB->ISACencUB_obj.buffer_index = LB_TOTAL_DELAY_SAMPLES; + } else { + instUB->ISACencUB_obj.buffer_index = 0; + } + /* Default for I-mode. */ + instUB->ISACencUB_obj.bottleneck = 32000; + /* These store the limits for the wideband + super-wideband bit-stream. */ + instUB->ISACencUB_obj.maxPayloadSizeBytes = STREAM_SIZE_MAX_30 << 1; + /* This has to be updated after each lower-band encoding to guarantee + * a correct payload-limitation. */ + instUB->ISACencUB_obj.numBytesUsed = 0; + memset(instUB->ISACencUB_obj.data_buffer_float, 0, + (MAX_FRAMESAMPLES + LB_TOTAL_DELAY_SAMPLES) * sizeof(float)); + + memcpy(&(instUB->ISACencUB_obj.lastLPCVec), + WebRtcIsac_kMeanLarUb16, sizeof(double) * UB_LPC_ORDER); + + return statusInit; +} + + +WebRtc_Word16 WebRtcIsac_EncoderInit(ISACStruct* ISAC_main_inst, + WebRtc_Word16 codingMode) { + ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; + WebRtc_Word16 status; + + if ((codingMode != 0) && (codingMode != 1)) { + instISAC->errorCode = ISAC_DISALLOWED_CODING_MODE; + return -1; + } + /* Default bottleneck. */ + instISAC->bottleneck = MAX_ISAC_BW; + + if (instISAC->encoderSamplingRateKHz == kIsacWideband) { + instISAC->bandwidthKHz = isac8kHz; + instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX_60; + instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX_30; + } else { + instISAC->bandwidthKHz = isac16kHz; + instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX; + instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX; + } + + /* Channel-adaptive = 0; Instantaneous (Channel-independent) = 1. */ + instISAC->codingMode = codingMode; + + WebRtcIsac_InitBandwidthEstimator(&instISAC->bwestimator_obj, + instISAC->encoderSamplingRateKHz, + instISAC->decoderSamplingRateKHz); + + WebRtcIsac_InitRateModel(&instISAC->rate_data_obj); + /* Default for I-mode. */ + instISAC->MaxDelay = 10.0; + + status = EncoderInitLb(&instISAC->instLB, codingMode, + instISAC->encoderSamplingRateKHz); + if (status < 0) { + instISAC->errorCode = -status; + return -1; + } + + if (instISAC->encoderSamplingRateKHz == kIsacSuperWideband) { + /* Initialize encoder filter-bank. */ + memset(instISAC->analysisFBState1, 0, + FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32)); + memset(instISAC->analysisFBState2, 0, + FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32)); + + status = EncoderInitUb(&(instISAC->instUB), + instISAC->bandwidthKHz); + if (status < 0) { + instISAC->errorCode = -status; + return -1; + } + } + /* Initialization is successful, set the flag. */ + instISAC->initFlag |= BIT_MASK_ENC_INIT; + return 0; +} + + +/**************************************************************************** + * WebRtcIsac_Encode(...) + * + * This function encodes 10ms frame(s) and inserts it into a package. + * Input speech length has to be 160 samples (10ms). The encoder buffers those + * 10ms frames until it reaches the chosen Framesize (480 or 960 samples + * corresponding to 30 or 60 ms frames), and then proceeds to the encoding. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - speechIn : input speech vector. + * + * Output: + * - encoded : the encoded data vector + * + * Return value: + * : >0 - Length (in bytes) of coded data + * : 0 - The buffer didn't reach the chosen + * frameSize so it keeps buffering speech + * samples. + * : -1 - Error + */ +WebRtc_Word16 WebRtcIsac_Encode(ISACStruct* ISAC_main_inst, + const WebRtc_Word16* speechIn, + WebRtc_Word16* encoded) { + float inFrame[FRAMESAMPLES_10ms]; + WebRtc_Word16 speechInLB[FRAMESAMPLES_10ms]; + WebRtc_Word16 speechInUB[FRAMESAMPLES_10ms]; + WebRtc_Word16 streamLenLB = 0; + WebRtc_Word16 streamLenUB = 0; + WebRtc_Word16 streamLen = 0; + WebRtc_Word16 k = 0; + WebRtc_UWord8* ptrEncodedUW8 = (WebRtc_UWord8*)encoded; + int garbageLen = 0; + WebRtc_Word32 bottleneck = 0; + WebRtc_Word16 bottleneckIdx = 0; + WebRtc_Word16 jitterInfo = 0; + + ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; + ISACLBStruct* instLB = &(instISAC->instLB); + ISACUBStruct* instUB = &(instISAC->instUB); + + /* Check if encoder initiated. */ + if ((instISAC->initFlag & BIT_MASK_ENC_INIT) != + BIT_MASK_ENC_INIT) { + instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; + return -1; + } + + if (instISAC->encoderSamplingRateKHz == kIsacSuperWideband) { + WebRtcSpl_AnalysisQMF(speechIn, speechInLB, speechInUB, + instISAC->analysisFBState1, + instISAC->analysisFBState2); + + /* Convert from fixed to floating point. */ + for (k = 0; k < FRAMESAMPLES_10ms; k++) { + inFrame[k] = (float)speechInLB[k]; + } + } else { + for (k = 0; k < FRAMESAMPLES_10ms; k++) { + inFrame[k] = (float) speechIn[k]; + } + } + + /* Add some noise to avoid denormal numbers. */ + inFrame[0] += (float)1.23455334e-3; + inFrame[1] -= (float)2.04324239e-3; + inFrame[2] += (float)1.90854954e-3; + inFrame[9] += (float)1.84854878e-3; + + /* This function will update the bottleneck if required. */ + UpdateBottleneck(instISAC); + + /* Get the bandwith information which has to be sent to the other side. */ + GetSendBandwidthInfo(instISAC, &bottleneckIdx, &jitterInfo); + + /* Encode lower-band. */ + streamLenLB = WebRtcIsac_EncodeLb(inFrame, &instLB->ISACencLB_obj, + instISAC->codingMode, bottleneckIdx); + if (streamLenLB < 0) { + return -1; + } + + if (instISAC->encoderSamplingRateKHz == kIsacSuperWideband) { + instUB = &(instISAC->instUB); + + /* Convert to float. */ + for (k = 0; k < FRAMESAMPLES_10ms; k++) { + inFrame[k] = (float) speechInUB[k]; + } + + /* Add some noise to avoid denormal numbers. */ + inFrame[0] += (float)1.23455334e-3; + inFrame[1] -= (float)2.04324239e-3; + inFrame[2] += (float)1.90854954e-3; + inFrame[9] += (float)1.84854878e-3; + + /* Tell to upper-band the number of bytes used so far. + * This is for payload limitation. */ + instUB->ISACencUB_obj.numBytesUsed = streamLenLB + 1 + + LEN_CHECK_SUM_WORD8; + /* Encode upper-band. */ + switch (instISAC->bandwidthKHz) { + case isac12kHz: { + streamLenUB = WebRtcIsac_EncodeUb12(inFrame, &instUB->ISACencUB_obj, + jitterInfo); + break; + } + case isac16kHz: { + streamLenUB = WebRtcIsac_EncodeUb16(inFrame, &instUB->ISACencUB_obj, + jitterInfo); + break; + } + case isac8kHz: { + streamLenUB = 0; + break; + } + } + + if ((streamLenUB < 0) && (streamLenUB != -ISAC_PAYLOAD_LARGER_THAN_LIMIT)) { + /* An error has happened but this is not the error due to a + * bit-stream larger than the limit. */ + return -1; + } + + if (streamLenLB == 0) { + return 0; + } + + /* One byte is allocated for the length. According to older decoders + so the length bit-stream plus one byte for size and + LEN_CHECK_SUM_WORD8 for the checksum should be less than or equal + to 255. */ + if ((streamLenUB > (255 - (LEN_CHECK_SUM_WORD8 + 1))) || + (streamLenUB == -ISAC_PAYLOAD_LARGER_THAN_LIMIT)) { + /* We have got a too long bit-stream we skip the upper-band + * bit-stream for this frame. */ + streamLenUB = 0; + } + + memcpy(ptrEncodedUW8, instLB->ISACencLB_obj.bitstr_obj.stream, streamLenLB); + streamLen = streamLenLB; + if (streamLenUB > 0) { + ptrEncodedUW8[streamLenLB] = (WebRtc_UWord8)(streamLenUB + 1 + + LEN_CHECK_SUM_WORD8); + memcpy(&ptrEncodedUW8[streamLenLB + 1], + instUB->ISACencUB_obj.bitstr_obj.stream, streamLenUB); + streamLen += ptrEncodedUW8[streamLenLB]; + } else { + ptrEncodedUW8[streamLenLB] = 0; + } + } else { + if (streamLenLB == 0) { + return 0; + } + memcpy(ptrEncodedUW8, instLB->ISACencLB_obj.bitstr_obj.stream, + streamLenLB); + streamLenUB = 0; + streamLen = streamLenLB; + } + + /* Add Garbage if required. */ + WebRtcIsac_GetUplinkBandwidth(&instISAC->bwestimator_obj, &bottleneck); + if (instISAC->codingMode == 0) { + int minBytes; + int limit; + WebRtc_UWord8* ptrGarbage; + + instISAC->MaxDelay = (double)WebRtcIsac_GetUplinkMaxDelay( + &instISAC->bwestimator_obj); + + /* Update rate model and get minimum number of bytes in this packet. */ + minBytes = WebRtcIsac_GetMinBytes( + &(instISAC->rate_data_obj), streamLen, + instISAC->instLB.ISACencLB_obj.current_framesamples, bottleneck, + instISAC->MaxDelay, instISAC->bandwidthKHz); + + /* Make sure MinBytes does not exceed packet size limit. */ + if (instISAC->bandwidthKHz == isac8kHz) { + if (instLB->ISACencLB_obj.current_framesamples == FRAMESAMPLES) { + limit = instLB->ISACencLB_obj.payloadLimitBytes30; + } else { + limit = instLB->ISACencLB_obj.payloadLimitBytes60; + } + } else { + limit = instUB->ISACencUB_obj.maxPayloadSizeBytes; + } + minBytes = (minBytes > limit) ? limit : minBytes; + + /* 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 length we can signal using 8 bits. */ + if ((instISAC->bandwidthKHz == isac8kHz) || + (streamLenUB == 0)) { + ptrGarbage = &ptrEncodedUW8[streamLenLB]; + limit = streamLen + 255; + } else { + ptrGarbage = &ptrEncodedUW8[streamLenLB + 1 + streamLenUB]; + limit = streamLen + (255 - ptrEncodedUW8[streamLenLB]); + } + minBytes = (minBytes > limit) ? limit : minBytes; + + garbageLen = (minBytes > streamLen) ? (minBytes - streamLen) : 0; + + /* Save data for creation of multiple bit-streams. */ + /* If bit-stream too short then add garbage at the end. */ + if (garbageLen > 0) { + for (k = 0; k < garbageLen; k++) { + ptrGarbage[k] = (WebRtc_UWord8)(rand() & 0xFF); + } + /* For a correct length of the upper-band bit-stream together + * with the garbage. Garbage is embeded in upper-band bit-stream. + * That is the only way to preserve backward compatibility. */ + if ((instISAC->bandwidthKHz == isac8kHz) || + (streamLenUB == 0)) { + ptrEncodedUW8[streamLenLB] = (WebRtc_UWord8)garbageLen; + } else { + ptrEncodedUW8[streamLenLB] += (WebRtc_UWord8)garbageLen; + /* Write the length of the garbage at the end of the upper-band + * bit-stream, if exists. This helps for sanity check. */ + ptrEncodedUW8[streamLenLB + 1 + streamLenUB] = + (WebRtc_UWord8)garbageLen; + + } + streamLen += garbageLen; + } + } else { + /* update rate model */ + WebRtcIsac_UpdateRateModel( + &instISAC->rate_data_obj, streamLen, + instISAC->instLB.ISACencLB_obj.current_framesamples, bottleneck); + garbageLen = 0; + } + + /* Generate CRC if required. */ + if ((instISAC->bandwidthKHz != isac8kHz) && (streamLenUB > 0)) { + WebRtc_UWord32 crc; + + WebRtcIsac_GetCrc((WebRtc_Word16*)(&(ptrEncodedUW8[streamLenLB + 1])), + streamLenUB + garbageLen, &crc); +#ifndef WEBRTC_BIG_ENDIAN + for (k = 0; k < LEN_CHECK_SUM_WORD8; k++) { + ptrEncodedUW8[streamLen - LEN_CHECK_SUM_WORD8 + k] = + (WebRtc_UWord8)((crc >> (24 - k * 8)) & 0xFF); + } +#else + memcpy(&ptrEncodedUW8[streamLenLB + streamLenUB + 1], &crc, + LEN_CHECK_SUM_WORD8); +#endif + } + return streamLen; +} + + +/****************************************************************************** + * WebRtcIsac_GetNewBitStream(...) + * + * This function returns encoded data, with the recieved bwe-index in the + * stream. If the rate is set to a value less than bottleneck of codec + * the new bistream will be re-encoded with the given target rate. + * It should always return a complete packet, i.e. only called once + * even for 60 msec frames. + * + * NOTE 1! This function does not write in the ISACStruct, it is not allowed. + * NOTE 3! Rates larger than the bottleneck of the codec will be limited + * to the current bottleneck. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - bweIndex : Index of bandwidth estimate to put in new + * bitstream + * - rate : target rate of the transcoder is bits/sec. + * Valid values are the accepted rate in iSAC, + * i.e. 10000 to 56000. + * + * Output: + * - encoded : The encoded data vector + * + * Return value : >0 - Length (in bytes) of coded data + * -1 - Error or called in SWB mode + * NOTE! No error code is written to + * the struct since it is only allowed to read + * the struct. + */ +WebRtc_Word16 WebRtcIsac_GetNewBitStream(ISACStruct* ISAC_main_inst, + WebRtc_Word16 bweIndex, + WebRtc_Word16 jitterInfo, + WebRtc_Word32 rate, + WebRtc_Word16* encoded, + WebRtc_Word16 isRCU) { + Bitstr iSACBitStreamInst; /* Local struct for bitstream handling */ + WebRtc_Word16 streamLenLB; + WebRtc_Word16 streamLenUB; + WebRtc_Word16 totalStreamLen; + double gain2; + double gain1; + float scale; + enum ISACBandwidth bandwidthKHz; + double rateLB; + double rateUB; + WebRtc_Word32 currentBN; + WebRtc_UWord8* encodedPtrUW8 = (WebRtc_UWord8*)encoded; + WebRtc_UWord32 crc; +#ifndef WEBRTC_BIG_ENDIAN + WebRtc_Word16 k; +#endif + ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; + + if ((instISAC->initFlag & BIT_MASK_ENC_INIT) != + BIT_MASK_ENC_INIT) { + return -1; + } + + /* Get the bottleneck of this iSAC and limit the + * given rate to the current bottleneck. */ + WebRtcIsac_GetUplinkBw(ISAC_main_inst, ¤tBN); + if (rate > currentBN) { + rate = currentBN; + } + + if (WebRtcIsac_RateAllocation(rate, &rateLB, &rateUB, &bandwidthKHz) < 0) { + return -1; + } + + /* Cannot transcode from 16 kHz to 12 kHz. */ + if ((bandwidthKHz == isac12kHz) && + (instISAC->bandwidthKHz == isac16kHz)) { + return -1; + } + + /* A gain [dB] for the given rate. */ + gain1 = WebRtcIsac_GetSnr( + rateLB, instISAC->instLB.ISACencLB_obj.current_framesamples); + /* The gain [dB] of this iSAC. */ + gain2 = WebRtcIsac_GetSnr( + instISAC->instLB.ISACencLB_obj.bottleneck, + instISAC->instLB.ISACencLB_obj.current_framesamples); + + /* Scale is the ratio of two gains in normal domain. */ + scale = (float)pow(10, (gain1 - gain2) / 20.0); + /* Change the scale if this is a RCU bit-stream. */ + scale = (isRCU) ? (scale * RCU_TRANSCODING_SCALE) : scale; + + streamLenLB = WebRtcIsac_EncodeStoredDataLb( + &instISAC->instLB.ISACencLB_obj.SaveEnc_obj, + &iSACBitStreamInst, bweIndex, scale); + + if (streamLenLB < 0) { + return -1; + } + + /* Convert from bytes to WebRtc_Word16. */ + memcpy(encoded, iSACBitStreamInst.stream, streamLenLB); + + if (bandwidthKHz == isac8kHz) { + return streamLenLB; + } + + totalStreamLen = streamLenLB; + /* super-wideband is always at 30ms. + * These gains are in dB. + * Gain for the given rate. */ + gain1 = WebRtcIsac_GetSnr(rateUB, FRAMESAMPLES); + /* Gain of this iSAC */ + gain2 = WebRtcIsac_GetSnr(instISAC->instUB.ISACencUB_obj.bottleneck, + FRAMESAMPLES); + + /* Scale is the ratio of two gains in normal domain. */ + scale = (float)pow(10, (gain1 - gain2) / 20.0); + + /* Change the scale if this is a RCU bit-stream. */ + scale = (isRCU)? (scale * RCU_TRANSCODING_SCALE_UB) : scale; + + streamLenUB = WebRtcIsac_EncodeStoredDataUb( + &(instISAC->instUB.ISACencUB_obj.SaveEnc_obj), + &iSACBitStreamInst, jitterInfo, scale, + instISAC->bandwidthKHz); + + if (streamLenUB < 0) { + return -1; + } + + if (streamLenUB + 1 + LEN_CHECK_SUM_WORD8 > 255) { + return streamLenLB; + } + + totalStreamLen = streamLenLB + streamLenUB + 1 + LEN_CHECK_SUM_WORD8; + encodedPtrUW8[streamLenLB] = streamLenUB + 1 + LEN_CHECK_SUM_WORD8; + + memcpy(&encodedPtrUW8[streamLenLB + 1], iSACBitStreamInst.stream, + streamLenUB); + + WebRtcIsac_GetCrc((WebRtc_Word16*)(&(encodedPtrUW8[streamLenLB + 1])), + streamLenUB, &crc); +#ifndef WEBRTC_BIG_ENDIAN + for (k = 0; k < LEN_CHECK_SUM_WORD8; k++) { + encodedPtrUW8[totalStreamLen - LEN_CHECK_SUM_WORD8 + k] = + (WebRtc_UWord8)((crc >> (24 - k * 8)) & 0xFF); + } +#else + memcpy(&encodedPtrUW8[streamLenLB + streamLenUB + 1], &crc, + LEN_CHECK_SUM_WORD8); +#endif + return totalStreamLen; +} + + +/**************************************************************************** + * DecoderInitLb(...) - internal function for initialization of + * Lower Band + * DecoderInitUb(...) - internal function for initialization of + * Upper Band + * WebRtcIsac_DecoderInit(...) - API function + * + * This function initializes a ISAC instance prior to the decoder calls. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * + * Return value + * : 0 - Ok + * -1 - Error + */ +static WebRtc_Word16 DecoderInitLb(ISACLBStruct* instISAC) { + int i; + /* Initialize stream vector to zero. */ + for (i = 0; i < STREAM_SIZE_MAX_60; i++) { + instISAC->ISACdecLB_obj.bitstr_obj.stream[i] = 0; + } + + WebRtcIsac_InitMasking(&instISAC->ISACdecLB_obj.maskfiltstr_obj); + WebRtcIsac_InitPostFilterbank( + &instISAC->ISACdecLB_obj.postfiltbankstr_obj); + WebRtcIsac_InitPitchFilter(&instISAC->ISACdecLB_obj.pitchfiltstr_obj); + return 0; +} + +static WebRtc_Word16 DecoderInitUb(ISACUBStruct* instISAC) { + int i; + /* Init stream vector to zero */ + for (i = 0; i < STREAM_SIZE_MAX_60; i++) { + instISAC->ISACdecUB_obj.bitstr_obj.stream[i] = 0; + } + + WebRtcIsac_InitMasking(&instISAC->ISACdecUB_obj.maskfiltstr_obj); + WebRtcIsac_InitPostFilterbank( + &instISAC->ISACdecUB_obj.postfiltbankstr_obj); + return (0); +} + +WebRtc_Word16 WebRtcIsac_DecoderInit(ISACStruct* ISAC_main_inst) { + ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; + + if (DecoderInitLb(&instISAC->instLB) < 0) { + return -1; + } + if (instISAC->decoderSamplingRateKHz == kIsacSuperWideband) { + memset(instISAC->synthesisFBState1, 0, + FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32)); + memset(instISAC->synthesisFBState2, 0, + FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32)); + + if (DecoderInitUb(&(instISAC->instUB)) < 0) { + return -1; + } + } + if ((instISAC->initFlag & BIT_MASK_ENC_INIT) != BIT_MASK_ENC_INIT) { + WebRtcIsac_InitBandwidthEstimator(&instISAC->bwestimator_obj, + instISAC->encoderSamplingRateKHz, + instISAC->decoderSamplingRateKHz); + } + instISAC->initFlag |= BIT_MASK_DEC_INIT; + instISAC->resetFlag_8kHz = 0; + return 0; +} + + +/**************************************************************************** + * WebRtcIsac_UpdateBwEstimate(...) + * + * This function updates the estimate of the bandwidth. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - encoded : encoded ISAC frame(s). + * - packet_size : size of the packet. + * - rtp_seq_number : the RTP number of the packet. + * - arr_ts : the arrival time of the packet (from NetEq) + * in samples. + * + * Return value : 0 - Ok + * -1 - Error + */ +WebRtc_Word16 WebRtcIsac_UpdateBwEstimate(ISACStruct* ISAC_main_inst, + const WebRtc_UWord16* encoded, + WebRtc_Word32 packet_size, + WebRtc_UWord16 rtp_seq_number, + WebRtc_UWord32 send_ts, + WebRtc_UWord32 arr_ts) { + ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; + Bitstr streamdata; +#ifndef WEBRTC_BIG_ENDIAN + int k; +#endif + WebRtc_Word16 err; + + /* Check if decoder initiated. */ + if ((instISAC->initFlag & BIT_MASK_DEC_INIT) != BIT_MASK_DEC_INIT) { + instISAC->errorCode = ISAC_DECODER_NOT_INITIATED; + return -1; + } + + if (packet_size <= 0) { + /* Return error code if the packet length is null. */ + instISAC->errorCode = ISAC_EMPTY_PACKET; + return -1; + } + + WebRtcIsac_ResetBitstream(&(streamdata)); + +#ifndef WEBRTC_BIG_ENDIAN + for (k = 0; k < 10; k++) { + streamdata.stream[k] = (WebRtc_UWord8)((encoded[k >> 1] >> + ((k & 1) << 3)) & 0xFF); + } +#else + memcpy(streamdata.stream, encoded, 10); +#endif + + err = WebRtcIsac_EstimateBandwidth(&instISAC->bwestimator_obj, &streamdata, + packet_size, rtp_seq_number, send_ts, + arr_ts, instISAC->encoderSamplingRateKHz, + instISAC->decoderSamplingRateKHz); + if (err < 0) { + /* Return error code if something went wrong. */ + instISAC->errorCode = -err; + return -1; + } + return 0; +} + +static WebRtc_Word16 Decode(ISACStruct* ISAC_main_inst, + const WebRtc_UWord16* encoded, + WebRtc_Word16 lenEncodedBytes, + WebRtc_Word16* decoded, + WebRtc_Word16* speechType, + WebRtc_Word16 isRCUPayload) { + /* Number of samples (480 or 960), output from decoder + that were actually used in the encoder/decoder + (determined on the fly). */ + WebRtc_Word16 numSamplesLB; + WebRtc_Word16 numSamplesUB; + WebRtc_Word16 speechIdx; + float outFrame[MAX_FRAMESAMPLES]; + WebRtc_Word16 outFrameLB[MAX_FRAMESAMPLES]; + WebRtc_Word16 outFrameUB[MAX_FRAMESAMPLES]; + WebRtc_Word16 numDecodedBytesLB; + WebRtc_Word16 numDecodedBytesUB; + WebRtc_Word16 lenEncodedLBBytes; + WebRtc_Word16 validChecksum = 1; + WebRtc_Word16 k; + WebRtc_UWord8* ptrEncodedUW8 = (WebRtc_UWord8*)encoded; + WebRtc_UWord16 numLayer; + WebRtc_Word16 totSizeBytes; + WebRtc_Word16 err; + + ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; + ISACUBDecStruct* decInstUB = &(instISAC->instUB.ISACdecUB_obj); + ISACLBDecStruct* decInstLB = &(instISAC->instLB.ISACdecLB_obj); + + /* Check if decoder initiated. */ + if ((instISAC->initFlag & BIT_MASK_DEC_INIT) != + BIT_MASK_DEC_INIT) { + instISAC->errorCode = ISAC_DECODER_NOT_INITIATED; + return -1; + } + + if (lenEncodedBytes <= 0) { + /* return error code if the packet length is null. */ + instISAC->errorCode = ISAC_EMPTY_PACKET; + return -1; + } + + /* The size of the encoded lower-band is bounded by + * STREAM_SIZE_MAX. If a payload with the size larger than STREAM_SIZE_MAX + * is received, it is not considered erroneous. */ + lenEncodedLBBytes = (lenEncodedBytes > STREAM_SIZE_MAX) ? + STREAM_SIZE_MAX : lenEncodedBytes; + + /* Copy to lower-band bit-stream structure. */ + memcpy(instISAC->instLB.ISACdecLB_obj.bitstr_obj.stream, ptrEncodedUW8, + lenEncodedLBBytes); + + /* Regardless of that the current codec is setup to work in + * wideband or super-wideband, the decoding of the lower-band + * has to be performed. */ + numDecodedBytesLB = WebRtcIsac_DecodeLb(outFrame, decInstLB, + &numSamplesLB, isRCUPayload); + + if ((numDecodedBytesLB < 0) || (numDecodedBytesLB > lenEncodedLBBytes) || + (numSamplesLB > MAX_FRAMESAMPLES)) { + instISAC->errorCode = ISAC_LENGTH_MISMATCH; + return -1; + } + + /* Error Check, we accept multi-layer bit-stream This will limit number + * of iterations of the while loop. Even without this the number + * of iterations is limited. */ + numLayer = 1; + totSizeBytes = numDecodedBytesLB; + while (totSizeBytes != lenEncodedBytes) { + if ((totSizeBytes > lenEncodedBytes) || + (ptrEncodedUW8[totSizeBytes] == 0) || + (numLayer > MAX_NUM_LAYERS)) { + instISAC->errorCode = ISAC_LENGTH_MISMATCH; + return -1; + } + totSizeBytes += ptrEncodedUW8[totSizeBytes]; + numLayer++; + } + + if (instISAC->decoderSamplingRateKHz == kIsacWideband) { + for (k = 0; k < numSamplesLB; k++) { + if (outFrame[k] > 32767) { + decoded[k] = 32767; + } else if (outFrame[k] < -32768) { + decoded[k] = -32768; + } else { + decoded[k] = (WebRtc_Word16)WebRtcIsac_lrint(outFrame[k]); + } + } + numSamplesUB = 0; + } else { + WebRtc_UWord32 crc; + /* We don't accept larger than 30ms (480 samples at lower-band) + * frame-size. */ + for (k = 0; k < numSamplesLB; k++) { + if (outFrame[k] > 32767) { + outFrameLB[k] = 32767; + } else if (outFrame[k] < -32768) { + outFrameLB[k] = -32768; + } else { + outFrameLB[k] = (WebRtc_Word16)WebRtcIsac_lrint(outFrame[k]); + } + } + + /* Check for possible error, and if upper-band stream exists. */ + if (numDecodedBytesLB == lenEncodedBytes) { + /* Decoding was successful. No super-wideband bit-stream exists. */ + numSamplesUB = numSamplesLB; + memset(outFrameUB, 0, sizeof(WebRtc_Word16) * numSamplesUB); + + /* Prepare for the potential increase of signal bandwidth. */ + instISAC->resetFlag_8kHz = 2; + } else { + /* This includes the checksum and the bytes that stores the length. */ + WebRtc_Word16 lenNextStream = ptrEncodedUW8[numDecodedBytesLB]; + + /* Is this garbage or valid super-wideband bit-stream? + * Check if checksum is valid. */ + if (lenNextStream <= (LEN_CHECK_SUM_WORD8 + 1)) { + /* Such a small second layer cannot be super-wideband layer. + * It must be a short garbage. */ + validChecksum = 0; + } else { + /* Run CRC to see if the checksum match. */ + WebRtcIsac_GetCrc((WebRtc_Word16*)( + &ptrEncodedUW8[numDecodedBytesLB + 1]), + lenNextStream - LEN_CHECK_SUM_WORD8 - 1, &crc); + + validChecksum = 1; + for (k = 0; k < LEN_CHECK_SUM_WORD8; k++) { + validChecksum &= (((crc >> (24 - k * 8)) & 0xFF) == + ptrEncodedUW8[numDecodedBytesLB + lenNextStream - + LEN_CHECK_SUM_WORD8 + k]); + } + } + + if (!validChecksum) { + /* This is a garbage, we have received a wideband + * bit-stream with garbage. */ + numSamplesUB = numSamplesLB; + memset(outFrameUB, 0, sizeof(WebRtc_Word16) * numSamplesUB); + } else { + /* A valid super-wideband biststream exists. */ + enum ISACBandwidth bandwidthKHz; + WebRtc_Word32 maxDelayBit; + + /* If we have super-wideband bit-stream, we cannot + * have 60 ms frame-size. */ + if (numSamplesLB > FRAMESAMPLES) { + instISAC->errorCode = ISAC_LENGTH_MISMATCH; + return -1; + } + + /* The rest of the bit-stream contains the upper-band + * bit-stream curently this is the only thing there, + * however, we might add more layers. */ + + /* Have to exclude one byte where the length is stored + * and last 'LEN_CHECK_SUM_WORD8' bytes where the + * checksum is stored. */ + lenNextStream -= (LEN_CHECK_SUM_WORD8 + 1); + + memcpy(decInstUB->bitstr_obj.stream, + &ptrEncodedUW8[numDecodedBytesLB + 1], lenNextStream); + + /* Reset bit-stream object, this is the first decoding. */ + WebRtcIsac_ResetBitstream(&(decInstUB->bitstr_obj)); + + /* Decode jitter information. */ + err = WebRtcIsac_DecodeJitterInfo(&decInstUB->bitstr_obj, &maxDelayBit); + if (err < 0) { + instISAC->errorCode = -err; + return -1; + } + + /* Update jitter info which is in the upper-band bit-stream + * only if the encoder is in super-wideband. Otherwise, + * the jitter info is already embedded in bandwidth index + * and has been updated. */ + if (instISAC->encoderSamplingRateKHz == kIsacSuperWideband) { + err = WebRtcIsac_UpdateUplinkJitter( + &(instISAC->bwestimator_obj), maxDelayBit); + if (err < 0) { + instISAC->errorCode = -err; + return -1; + } + } + + /* Decode bandwidth information. */ + err = WebRtcIsac_DecodeBandwidth(&decInstUB->bitstr_obj, + &bandwidthKHz); + if (err < 0) { + instISAC->errorCode = -err; + return -1; + } + + switch (bandwidthKHz) { + case isac12kHz: { + numDecodedBytesUB = WebRtcIsac_DecodeUb12(outFrame, decInstUB, + isRCUPayload); + + /* Hang-over for transient alleviation - + * wait two frames to add the upper band going up from 8 kHz. */ + if (instISAC->resetFlag_8kHz > 0) { + if (instISAC->resetFlag_8kHz == 2) { + /* Silence first and a half frame. */ + memset(outFrame, 0, MAX_FRAMESAMPLES * + sizeof(float)); + } else { + const float rampStep = 2.0f / MAX_FRAMESAMPLES; + float rampVal = 0; + memset(outFrame, 0, (MAX_FRAMESAMPLES >> 1) * + sizeof(float)); + + /* Ramp up second half of second frame. */ + for (k = MAX_FRAMESAMPLES / 2; k < MAX_FRAMESAMPLES; k++) { + outFrame[k] *= rampVal; + rampVal += rampStep; + } + } + instISAC->resetFlag_8kHz -= 1; + } + + break; + } + case isac16kHz: { + numDecodedBytesUB = WebRtcIsac_DecodeUb16(outFrame, decInstUB, + isRCUPayload); + break; + } + default: + return -1; + } + + /* It might be less due to garbage. */ + if ((numDecodedBytesUB != lenNextStream) && + (numDecodedBytesUB != (lenNextStream - + ptrEncodedUW8[numDecodedBytesLB + 1 + numDecodedBytesUB]))) { + instISAC->errorCode = ISAC_LENGTH_MISMATCH; + return -1; + } + + /* If there is no error Upper-band always decodes + * 30 ms (480 samples). */ + numSamplesUB = FRAMESAMPLES; + + /* Convert to W16. */ + for (k = 0; k < numSamplesUB; k++) { + if (outFrame[k] > 32767) { + outFrameUB[k] = 32767; + } else if (outFrame[k] < -32768) { + outFrameUB[k] = -32768; + } else { + outFrameUB[k] = (WebRtc_Word16)WebRtcIsac_lrint( + outFrame[k]); + } + } + } + } + + speechIdx = 0; + while (speechIdx < numSamplesLB) { + WebRtcSpl_SynthesisQMF(&outFrameLB[speechIdx], &outFrameUB[speechIdx], + &decoded[(speechIdx << 1)], + instISAC->synthesisFBState1, + instISAC->synthesisFBState2); + + speechIdx += FRAMESAMPLES_10ms; + } + } + *speechType = 0; + return (numSamplesLB + numSamplesUB); +} + + + + + + + +/**************************************************************************** + * WebRtcIsac_Decode(...) + * + * This function decodes a ISAC frame. Output speech length + * will be a multiple of 480 samples: 480 or 960 samples, + * depending on the frameSize (30 or 60 ms). + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - encoded : encoded ISAC frame(s) + * - len : bytes in encoded vector + * + * Output: + * - decoded : The decoded vector + * + * Return value : >0 - number of samples in decoded vector + * -1 - Error + */ + +WebRtc_Word16 WebRtcIsac_Decode(ISACStruct* ISAC_main_inst, + const WebRtc_UWord16* encoded, + WebRtc_Word16 lenEncodedBytes, + WebRtc_Word16* decoded, + WebRtc_Word16* speechType) { + WebRtc_Word16 isRCUPayload = 0; + return Decode(ISAC_main_inst, encoded, lenEncodedBytes, decoded, + speechType, isRCUPayload); +} + +/**************************************************************************** + * WebRtcIsac_DecodeRcu(...) + * + * This function decodes a redundant (RCU) iSAC frame. Function is called in + * NetEq with a stored RCU payload in case of packet loss. Output speech length + * will be a multiple of 480 samples: 480 or 960 samples, + * depending on the framesize (30 or 60 ms). + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - encoded : encoded ISAC RCU frame(s) + * - len : bytes in encoded vector + * + * Output: + * - decoded : The decoded vector + * + * Return value : >0 - number of samples in decoded vector + * -1 - Error + */ + + + +WebRtc_Word16 WebRtcIsac_DecodeRcu(ISACStruct* ISAC_main_inst, + const WebRtc_UWord16* encoded, + WebRtc_Word16 lenEncodedBytes, + WebRtc_Word16* decoded, + WebRtc_Word16* speechType) { + WebRtc_Word16 isRCUPayload = 1; + return Decode(ISAC_main_inst, encoded, lenEncodedBytes, decoded, + speechType, isRCUPayload); +} + + +/**************************************************************************** + * WebRtcIsac_DecodePlc(...) + * + * This function conducts PLC for ISAC frame(s). Output speech length + * will be a multiple of 480 samples: 480 or 960 samples, + * depending on the frameSize (30 or 60 ms). + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - noOfLostFrames : Number of PLC frames to produce + * + * Output: + * - decoded : The decoded vector + * + * Return value : >0 - number of samples in decoded PLC vector + * -1 - Error + */ +WebRtc_Word16 WebRtcIsac_DecodePlc(ISACStruct* ISAC_main_inst, + WebRtc_Word16* decoded, + WebRtc_Word16 noOfLostFrames) { + WebRtc_Word16 numSamples = 0; + ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; + + /* Limit number of frames to two = 60 millisecond. + * Otherwise we exceed data vectors. */ + if (noOfLostFrames > 2) { + noOfLostFrames = 2; + } + + /* Get the number of samples per frame */ + switch (instISAC->decoderSamplingRateKHz) { + case kIsacWideband: { + numSamples = 480 * noOfLostFrames; + break; + } + case kIsacSuperWideband: { + numSamples = 960 * noOfLostFrames; + break; + } + } + + /* Set output samples to zero. */ + memset(decoded, 0, numSamples * sizeof(WebRtc_Word16)); + return numSamples; +} + + +/**************************************************************************** + * ControlLb(...) - Internal function for controlling Lower Band + * ControlUb(...) - Internal function for controlling Upper Band + * WebRtcIsac_Control(...) - API function + * + * This function sets the limit on the short-term average bit rate and the + * frame length. Should be used only in Instantaneous mode. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - rate : limit on the short-term average bit rate, + * in bits/second (between 10000 and 32000) + * - frameSize : number of milliseconds per frame (30 or 60) + * + * Return value : 0 - ok + * -1 - Error + */ +static WebRtc_Word16 ControlLb(ISACLBStruct* instISAC, double rate, + WebRtc_Word16 frameSize) { + if ((rate >= 10000) && (rate <= 32000)) { + instISAC->ISACencLB_obj.bottleneck = rate; + } else { + return -ISAC_DISALLOWED_BOTTLENECK; + } + + if ((frameSize == 30) || (frameSize == 60)) { + instISAC->ISACencLB_obj.new_framelength = (FS / 1000) * frameSize; + } else { + return -ISAC_DISALLOWED_FRAME_LENGTH; + } + + return 0; +} + +static WebRtc_Word16 ControlUb(ISACUBStruct* instISAC, double rate) { + if ((rate >= 10000) && (rate <= 32000)) { + instISAC->ISACencUB_obj.bottleneck = rate; + } else { + return -ISAC_DISALLOWED_BOTTLENECK; + } + return 0; +} + +WebRtc_Word16 WebRtcIsac_Control(ISACStruct* ISAC_main_inst, + WebRtc_Word32 bottleneckBPS, + WebRtc_Word16 frameSize) { + ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; + WebRtc_Word16 status; + double rateLB; + double rateUB; + enum ISACBandwidth bandwidthKHz; + + if (instISAC->codingMode == 0) { + /* In adaptive mode. */ + instISAC->errorCode = ISAC_MODE_MISMATCH; + return -1; + } + + /* Check if encoder initiated */ + if ((instISAC->initFlag & BIT_MASK_ENC_INIT) != + BIT_MASK_ENC_INIT) { + instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; + return -1; + } + + if (instISAC->encoderSamplingRateKHz == kIsacWideband) { + /* If the sampling rate is 16kHz then bandwith should be 8kHz, + * regardless of bottleneck. */ + bandwidthKHz = isac8kHz; + rateLB = (bottleneckBPS > 32000) ? 32000 : bottleneckBPS; + rateUB = 0; + } else { + if (WebRtcIsac_RateAllocation(bottleneckBPS, &rateLB, &rateUB, + &bandwidthKHz) < 0) { + return -1; + } + } + + if ((instISAC->encoderSamplingRateKHz == kIsacSuperWideband) && + (frameSize != 30) && + (bandwidthKHz != isac8kHz)) { + /* Cannot have 60 ms in super-wideband. */ + instISAC->errorCode = ISAC_DISALLOWED_FRAME_LENGTH; + return -1; + } + + status = ControlLb(&instISAC->instLB, rateLB, frameSize); + if (status < 0) { + instISAC->errorCode = -status; + return -1; + } + if (bandwidthKHz != isac8kHz) { + status = ControlUb(&(instISAC->instUB), rateUB); + if (status < 0) { + instISAC->errorCode = -status; + return -1; + } + } + + + /* Check if bandwidth is changing from wideband to super-wideband + * then we have to synch data buffer of lower & upper-band. Also + * clean up the upper-band data buffer. */ + + if ((instISAC->bandwidthKHz == isac8kHz) && (bandwidthKHz != isac8kHz)) { + memset(instISAC->instUB.ISACencUB_obj.data_buffer_float, 0, + sizeof(float) * (MAX_FRAMESAMPLES + LB_TOTAL_DELAY_SAMPLES)); + + if (bandwidthKHz == isac12kHz) { + instISAC->instUB.ISACencUB_obj.buffer_index = + instISAC->instLB.ISACencLB_obj.buffer_index; + } else { + instISAC->instUB.ISACencUB_obj.buffer_index = + LB_TOTAL_DELAY_SAMPLES + instISAC->instLB.ISACencLB_obj.buffer_index; + + memcpy(&(instISAC->instUB.ISACencUB_obj.lastLPCVec), + WebRtcIsac_kMeanLarUb16, sizeof(double) * UB_LPC_ORDER); + } + } + + /* Update the payload limit if the bandwidth is changing. */ + if (instISAC->bandwidthKHz != bandwidthKHz) { + instISAC->bandwidthKHz = bandwidthKHz; + UpdatePayloadSizeLimit(instISAC); + } + instISAC->bottleneck = bottleneckBPS; + return 0; +} + + +/**************************************************************************** + * WebRtcIsac_ControlBwe(...) + * + * This function sets the initial values of bottleneck and frame-size if + * iSAC is used in channel-adaptive mode. Through this API, users can + * enforce a frame-size for all values of bottleneck. Then iSAC will not + * automatically change the frame-size. + * + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - rateBPS : initial value of bottleneck in bits/second + * 10000 <= rateBPS <= 32000 is accepted + * For default bottleneck set rateBPS = 0 + * - frameSizeMs : number of milliseconds per frame (30 or 60) + * - enforceFrameSize : 1 to enforce the given frame-size through out + * the adaptation process, 0 to let iSAC change + * the frame-size if required. + * + * Return value : 0 - ok + * -1 - Error + */ +WebRtc_Word16 WebRtcIsac_ControlBwe(ISACStruct* ISAC_main_inst, + WebRtc_Word32 bottleneckBPS, + WebRtc_Word16 frameSizeMs, + WebRtc_Word16 enforceFrameSize) { + ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; + enum ISACBandwidth bandwidth; + + /* Check if encoder initiated */ + if ((instISAC->initFlag & BIT_MASK_ENC_INIT) != + BIT_MASK_ENC_INIT) { + instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; + return -1; + } + + /* Check that we are in channel-adaptive mode, otherwise, return (-1) */ + if (instISAC->codingMode != 0) { + instISAC->errorCode = ISAC_MODE_MISMATCH; + return -1; + } + if ((frameSizeMs != 30) && + (instISAC->encoderSamplingRateKHz == kIsacSuperWideband)) { + return -1; + } + + /* Set structure variable if enforceFrameSize is set. ISAC will then + * keep the chosen frame size. */ + if (enforceFrameSize != 0) { + instISAC->instLB.ISACencLB_obj.enforceFrameSize = 1; + } else { + instISAC->instLB.ISACencLB_obj.enforceFrameSize = 0; + } + + /* Set the initial rate. If the input value is zero then the default intial + * rate is used. Otehrwise, values between 10 to 32 kbps are accepted. */ + if (bottleneckBPS != 0) { + double rateLB; + double rateUB; + if (WebRtcIsac_RateAllocation(bottleneckBPS, &rateLB, &rateUB, + &bandwidth) < 0) { + return -1; + } + instISAC->bwestimator_obj.send_bw_avg = (float)bottleneckBPS; + instISAC->bandwidthKHz = bandwidth; + } + + /* Set the initial frame-size. If 'enforceFrameSize' is set, the frame-size + * will not change */ + if (frameSizeMs != 0) { + if ((frameSizeMs == 30) || (frameSizeMs == 60)) { + instISAC->instLB.ISACencLB_obj.new_framelength = (FS / 1000) * + frameSizeMs; + } else { + instISAC->errorCode = ISAC_DISALLOWED_FRAME_LENGTH; + return -1; + } + } + return 0; +} + + +/**************************************************************************** + * WebRtcIsac_GetDownLinkBwIndex(...) + * + * This function returns index representing the Bandwidth estimate from + * the other side to this side. + * + * Input: + * - ISAC_main_inst : iSAC structure + * + * Output: + * - bweIndex : Bandwidth estimate to transmit to other side. + * + */ +WebRtc_Word16 WebRtcIsac_GetDownLinkBwIndex(ISACStruct* ISAC_main_inst, + WebRtc_Word16* bweIndex, + WebRtc_Word16* jitterInfo) { + ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; + + /* Check if encoder initialized. */ + if ((instISAC->initFlag & BIT_MASK_DEC_INIT) != + BIT_MASK_DEC_INIT) { + instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; + return -1; + } + + /* Call function to get Bandwidth Estimate. */ + WebRtcIsac_GetDownlinkBwJitIndexImpl(&(instISAC->bwestimator_obj), bweIndex, + jitterInfo, + instISAC->decoderSamplingRateKHz); + return 0; +} + + +/**************************************************************************** + * WebRtcIsac_UpdateUplinkBw(...) + * + * This function takes an index representing the Bandwidth estimate from + * this side to other side and updates BWE. + * + * Input: + * - ISAC_main_inst : iSAC structure + * - rateIndex : Bandwidth estimate from other side. + * + * Return value : 0 - ok + * -1 - index out of range + */ +WebRtc_Word16 WebRtcIsac_UpdateUplinkBw(ISACStruct* ISAC_main_inst, + WebRtc_Word16 bweIndex) { + ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; + WebRtc_Word16 returnVal; + + /* Check if encoder initiated. */ + if ((instISAC->initFlag & BIT_MASK_ENC_INIT) != + BIT_MASK_ENC_INIT) { + instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; + return -1; + } + + /* Call function to get Bandwidth Estimate. */ + returnVal = WebRtcIsac_UpdateUplinkBwImpl( + &(instISAC->bwestimator_obj), bweIndex, + instISAC->encoderSamplingRateKHz); + + if (returnVal < 0) { + instISAC->errorCode = -returnVal; + return -1; + } else { + return 0; + } +} + + +/**************************************************************************** + * WebRtcIsac_ReadBwIndex(...) + * + * This function returns the index of the Bandwidth estimate from the + * bit-stream. + * + * Input: + * - encoded : Encoded bit-stream + * + * Output: + * - frameLength : Length of frame in packet (in samples) + * - bweIndex : Bandwidth estimate in bit-stream + * + */ +WebRtc_Word16 WebRtcIsac_ReadBwIndex(const WebRtc_Word16* encoded, + WebRtc_Word16* bweIndex) { + Bitstr streamdata; +#ifndef WEBRTC_BIG_ENDIAN + int k; +#endif + WebRtc_Word16 err; + + WebRtcIsac_ResetBitstream(&(streamdata)); + +#ifndef WEBRTC_BIG_ENDIAN + for (k = 0; k < 10; k++) { + streamdata.stream[k] = (WebRtc_UWord8)((encoded[k >> 1] >> + ((k & 1) << 3)) & 0xFF); + } +#else + memcpy(streamdata.stream, encoded, 10); +#endif + + /* Decode frame length. */ + err = WebRtcIsac_DecodeFrameLen(&streamdata, bweIndex); + if (err < 0) { + return err; + } + + /* Decode BW estimation. */ + err = WebRtcIsac_DecodeSendBW(&streamdata, bweIndex); + if (err < 0) { + return err; + } + + return 0; +} + + +/**************************************************************************** + * WebRtcIsac_ReadFrameLen(...) + * + * This function returns the length of the frame represented in the packet. + * + * Input: + * - encoded : Encoded bitstream + * + * Output: + * - frameLength : Length of frame in packet (in samples) + * + */ +WebRtc_Word16 WebRtcIsac_ReadFrameLen(ISACStruct* ISAC_main_inst, + const WebRtc_Word16* encoded, + WebRtc_Word16* frameLength) { + Bitstr streamdata; +#ifndef WEBRTC_BIG_ENDIAN + int k; +#endif + WebRtc_Word16 err; + ISACMainStruct* instISAC; + + WebRtcIsac_ResetBitstream(&(streamdata)); + +#ifndef WEBRTC_BIG_ENDIAN + for (k = 0; k < 10; k++) { + streamdata.stream[k] = (WebRtc_UWord8)((encoded[k >> 1] >> + ((k & 1) << 3)) & 0xFF); + } +#else + memcpy(streamdata.stream, encoded, 10); +#endif + + /* Decode frame length. */ + err = WebRtcIsac_DecodeFrameLen(&streamdata, frameLength); + if (err < 0) { + return -1; + } + instISAC = (ISACMainStruct*)ISAC_main_inst; + + if (instISAC->decoderSamplingRateKHz == kIsacSuperWideband) { + /* The decoded frame length indicates the number of samples in + * lower-band in this case, multiply by 2 to get the total number + * of samples. */ + *frameLength <<= 1; + } + return 0; +} + + +/******************************************************************************* + * WebRtcIsac_GetNewFrameLen(...) + * + * This function returns the frame length (in samples) of the next packet. + * In the case of channel-adaptive mode, iSAC decides on its frame length based + * on the estimated bottleneck, this AOI allows a user to prepare for the next + * packet (at the encoder). + * + * The primary usage is in CE to make the iSAC works in channel-adaptive mode + * + * Input: + * - ISAC_main_inst : iSAC struct + * + * Return Value : frame lenght in samples + * + */ +WebRtc_Word16 WebRtcIsac_GetNewFrameLen(ISACStruct* ISAC_main_inst) { + ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; + + /* Return new frame length. */ + if (instISAC->encoderSamplingRateKHz == kIsacWideband) { + return (instISAC->instLB.ISACencLB_obj.new_framelength); + } else { + return ((instISAC->instLB.ISACencLB_obj.new_framelength) << 1); + } +} + + +/**************************************************************************** + * WebRtcIsac_GetErrorCode(...) + * + * This function can be used to check the error code of an iSAC instance. + * When a function returns -1 an error code will be set for that instance. + * The function below extracts the code of the last error that occurred in + * the specified instance. + * + * Input: + * - ISAC_main_inst : ISAC instance + * + * Return value : Error code + */ +WebRtc_Word16 WebRtcIsac_GetErrorCode(ISACStruct* ISAC_main_inst) { + return ((ISACMainStruct*)ISAC_main_inst)->errorCode; +} + + +/**************************************************************************** + * WebRtcIsac_GetUplinkBw(...) + * + * This function outputs the target bottleneck of the codec. In + * channel-adaptive mode, the target bottleneck is specified through an in-band + * signalling retrieved by bandwidth estimator. + * In channel-independent, also called instantaneous mode, the target + * bottleneck is provided to the encoder by calling xxx_control(...) (if + * xxx_control is never called, the default values are used.). + * Note that the output is the iSAC internal operating bottleneck which might + * differ slightly from the one provided through xxx_control(). + * + * Input: + * - ISAC_main_inst : iSAC instance + * + * Output: + * - *bottleneck : bottleneck in bits/sec + * + * Return value : -1 if error happens + * 0 bit-rates computed correctly. + */ +WebRtc_Word16 WebRtcIsac_GetUplinkBw(ISACStruct* ISAC_main_inst, + WebRtc_Word32* bottleneck) { + ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; + + if (instISAC->codingMode == 0) { + /* We are in adaptive mode then get the bottleneck from BWE. */ + *bottleneck = (WebRtc_Word32)instISAC->bwestimator_obj.send_bw_avg; + } else { + *bottleneck = instISAC->bottleneck; + } + + if ((*bottleneck > 32000) && (*bottleneck < 38000)) { + *bottleneck = 32000; + } else if ((*bottleneck > 45000) && (*bottleneck < 50000)) { + *bottleneck = 45000; + } else if (*bottleneck > 56000) { + *bottleneck = 56000; + } + return 0; +} + + +/****************************************************************************** + * WebRtcIsac_SetMaxPayloadSize(...) + * + * This function sets a limit for the maximum payload size of iSAC. The same + * value is used both for 30 and 60 ms packets. If the encoder sampling rate + * is 16 kHz the maximum payload size is between 120 and 400 bytes. If the + * encoder sampling rate is 32 kHz the maximum payload size is between 120 + * and 600 bytes. + * + * --------------- + * IMPORTANT NOTES + * --------------- + * The size of a packet is limited to the minimum of 'max-payload-size' and + * 'max-rate.' For instance, let's assume the max-payload-size is set to + * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps + * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms + * frame-size. Then a packet with a frame-size of 30 ms is limited to 150, + * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to + * 170 bytes, i.e. min(170, 300). + * + * Input: + * - ISAC_main_inst : iSAC instance + * - maxPayloadBytes : maximum size of the payload in bytes + * valid values are between 100 and 400 bytes + * if encoder sampling rate is 16 kHz. For + * 32 kHz encoder sampling rate valid values + * are between 100 and 600 bytes. + * + * Return value : 0 if successful + * -1 if error happens + */ +WebRtc_Word16 WebRtcIsac_SetMaxPayloadSize(ISACStruct* ISAC_main_inst, + WebRtc_Word16 maxPayloadBytes) { + ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; + WebRtc_Word16 status = 0; + + /* Check if encoder initiated */ + if ((instISAC->initFlag & BIT_MASK_ENC_INIT) != + BIT_MASK_ENC_INIT) { + instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; + return -1; + } + + if (instISAC->encoderSamplingRateKHz == kIsacSuperWideband) { + /* Sanity check. */ + if (maxPayloadBytes < 120) { + /* 'maxRate' is out of valid range + * set to the acceptable value and return -1. */ + maxPayloadBytes = 120; + status = -1; + } + + /* sanity check */ + if (maxPayloadBytes > STREAM_SIZE_MAX) { + /* maxRate is out of valid range, + * set to the acceptable value and return -1. */ + maxPayloadBytes = STREAM_SIZE_MAX; + status = -1; + } + } else { + if (maxPayloadBytes < 120) { + /* Max payload-size is out of valid range + * set to the acceptable value and return -1. */ + maxPayloadBytes = 120; + status = -1; + } + if (maxPayloadBytes > STREAM_SIZE_MAX_60) { + /* Max payload-size is out of valid range + * set to the acceptable value and return -1. */ + maxPayloadBytes = STREAM_SIZE_MAX_60; + status = -1; + } + } + instISAC->maxPayloadSizeBytes = maxPayloadBytes; + UpdatePayloadSizeLimit(instISAC); + return status; +} + + +/****************************************************************************** + * WebRtcIsac_SetMaxRate(...) + * + * This function sets the maximum rate which the codec may not exceed for + * any signal packet. The maximum rate is defined and payload-size per + * frame-size in bits per second. + * + * The codec has a maximum rate of 53400 bits per second (200 bytes per 30 + * ms) if the encoder sampling rate is 16kHz, and 160 kbps (600 bytes/30 ms) + * if the encoder sampling rate is 32 kHz. + * + * It is possible to set a maximum rate between 32000 and 53400 bits/sec + * in wideband mode, and 32000 to 160000 bits/sec in super-wideband mode. + * + * --------------- + * IMPORTANT NOTES + * --------------- + * The size of a packet is limited to the minimum of 'max-payload-size' and + * 'max-rate.' For instance, let's assume the max-payload-size is set to + * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps + * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms + * frame-size. Then a packet with a frame-size of 30 ms is limited to 150, + * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to + * 170 bytes, min(170, 300). + * + * Input: + * - ISAC_main_inst : iSAC instance + * - maxRate : maximum rate in bits per second, + * valid values are 32000 to 53400 bits/sec in + * wideband mode, and 32000 to 160000 bits/sec in + * super-wideband mode. + * + * Return value : 0 if successful + * -1 if error happens + */ +WebRtc_Word16 WebRtcIsac_SetMaxRate(ISACStruct* ISAC_main_inst, + WebRtc_Word32 maxRate) { + ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; + WebRtc_Word16 maxRateInBytesPer30Ms; + WebRtc_Word16 status = 0; + + /* check if encoder initiated */ + if ((instISAC->initFlag & BIT_MASK_ENC_INIT) != BIT_MASK_ENC_INIT) { + instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; + return -1; + } + /* Calculate maximum number of bytes per 30 msec packets for the + given maximum rate. Multiply with 30/1000 to get number of + bits per 30 ms, divide by 8 to get number of bytes per 30 ms: + maxRateInBytes = floor((maxRate * 30/1000) / 8); */ + maxRateInBytesPer30Ms = (WebRtc_Word16)(maxRate * 3 / 800); + + if (instISAC->encoderSamplingRateKHz == kIsacWideband) { + if (maxRate < 32000) { + /* 'maxRate' is out of valid range. + * Set to the acceptable value and return -1. */ + maxRateInBytesPer30Ms = 120; + status = -1; + } + + if (maxRate > 53400) { + /* 'maxRate' is out of valid range. + * Set to the acceptable value and return -1. */ + maxRateInBytesPer30Ms = 200; + status = -1; + } + } else { + if (maxRateInBytesPer30Ms < 120) { + /* 'maxRate' is out of valid range + * Sset to the acceptable value and return -1. */ + maxRateInBytesPer30Ms = 120; + status = -1; + } + + if (maxRateInBytesPer30Ms > STREAM_SIZE_MAX) { + /* 'maxRate' is out of valid range. + * Set to the acceptable value and return -1. */ + maxRateInBytesPer30Ms = STREAM_SIZE_MAX; + status = -1; + } + } + instISAC->maxRateBytesPer30Ms = maxRateInBytesPer30Ms; + UpdatePayloadSizeLimit(instISAC); + return status; +} + + +/**************************************************************************** + * WebRtcIsac_GetRedPayload(...) + * + * This function populates "encoded" with the redundant payload of the recently + * encodedframe. This function has to be called once that WebRtcIsac_Encode(...) + * returns a positive value. Regardless of the frame-size this function will + * be called only once after encoding is completed. The bit-stream is + * targeted for 16000 bit/sec. + * + * Input: + * - ISAC_main_inst : iSAC struct + * + * Output: + * - encoded : the encoded data vector + * + * + * Return value : >0 - Length (in bytes) of coded data + * : -1 - Error + */ +WebRtc_Word16 WebRtcIsac_GetRedPayload(ISACStruct* ISAC_main_inst, + WebRtc_Word16* encoded) { + Bitstr iSACBitStreamInst; + WebRtc_Word16 streamLenLB; + WebRtc_Word16 streamLenUB; + WebRtc_Word16 streamLen; + WebRtc_Word16 totalLenUB; + WebRtc_UWord8* ptrEncodedUW8 = (WebRtc_UWord8*)encoded; + ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; +#ifndef WEBRTC_BIG_ENDIAN + int k; +#endif + + if ((instISAC->initFlag & BIT_MASK_ENC_INIT) != + BIT_MASK_ENC_INIT) { + instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; + } + + WebRtcIsac_ResetBitstream(&(iSACBitStreamInst)); + + streamLenLB = WebRtcIsac_EncodeStoredDataLb( + &instISAC->instLB.ISACencLB_obj.SaveEnc_obj, + &iSACBitStreamInst, + instISAC->instLB.ISACencLB_obj.lastBWIdx, + RCU_TRANSCODING_SCALE); + if (streamLenLB < 0) { + return -1; + } + + /* convert from bytes to WebRtc_Word16. */ + memcpy(ptrEncodedUW8, iSACBitStreamInst.stream, streamLenLB); + streamLen = streamLenLB; + if (instISAC->bandwidthKHz == isac8kHz) { + return streamLenLB; + } + + streamLenUB = WebRtcIsac_GetRedPayloadUb( + &instISAC->instUB.ISACencUB_obj.SaveEnc_obj, + &iSACBitStreamInst, instISAC->bandwidthKHz); + if (streamLenUB < 0) { + /* An error has happened but this is not the error due to a + * bit-stream larger than the limit. */ + return -1; + } + + /* We have one byte to write the total length of the upper-band. + * The length includes the bit-stream length, check-sum and the + * single byte where the length is written to. This is according to + * iSAC wideband and how the "garbage" is dealt. */ + totalLenUB = streamLenUB + 1 + LEN_CHECK_SUM_WORD8; + if (totalLenUB > 255) { + streamLenUB = 0; + } + + /* Generate CRC if required. */ + if ((instISAC->bandwidthKHz != isac8kHz) && + (streamLenUB > 0)) { + WebRtc_UWord32 crc; + streamLen += totalLenUB; + ptrEncodedUW8[streamLenLB] = (WebRtc_UWord8)totalLenUB; + memcpy(&ptrEncodedUW8[streamLenLB + 1], iSACBitStreamInst.stream, + streamLenUB); + + WebRtcIsac_GetCrc((WebRtc_Word16*)(&(ptrEncodedUW8[streamLenLB + 1])), + streamLenUB, &crc); +#ifndef WEBRTC_BIG_ENDIAN + for (k = 0; k < LEN_CHECK_SUM_WORD8; k++) { + ptrEncodedUW8[streamLen - LEN_CHECK_SUM_WORD8 + k] = + (WebRtc_UWord8)((crc >> (24 - k * 8)) & 0xFF); + } +#else + memcpy(&ptrEncodedUW8[streamLenLB + streamLenUB + 1], &crc, + LEN_CHECK_SUM_WORD8); +#endif + } + return streamLen; +} + + +/**************************************************************************** + * WebRtcIsac_version(...) + * + * This function returns the version number. + * + * Output: + * - version : Pointer to character string + * + */ +void WebRtcIsac_version(char* version) { + strcpy(version, "4.3.0"); +} + + +/****************************************************************************** + * WebRtcIsac_SetEncSampRate() + * This function sets the sampling rate of the encoder. Initialization of the + * encoder WILL NOT overwrite the sampling rate of the encoder. The default + * value is 16 kHz which is set when the instance is created. The encoding-mode + * and the bottleneck remain unchanged by this call, however, the maximum rate + * and maximum payload-size will be reset to their default values. + * + * Input: + * - ISAC_main_inst : iSAC instance + * - sampRate : enumerator specifying the sampling rate. + * + * Return value : 0 if successful + * -1 if failed. + */ +WebRtc_Word16 WebRtcIsac_SetEncSampRate(ISACStruct* ISAC_main_inst, + enum IsacSamplingRate sampRate) { + ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; + + if ((sampRate != kIsacWideband) && + (sampRate != kIsacSuperWideband)) { + /* Sampling Frequency is not supported. */ + instISAC->errorCode = ISAC_UNSUPPORTED_SAMPLING_FREQUENCY; + return -1; + } else if ((instISAC->initFlag & BIT_MASK_ENC_INIT) != + BIT_MASK_ENC_INIT) { + if (sampRate == kIsacWideband) { + instISAC->bandwidthKHz = isac8kHz; + } else { + instISAC->bandwidthKHz = isac16kHz; + } + instISAC->encoderSamplingRateKHz = sampRate; + return 0; + } else { + ISACUBStruct* instUB = &(instISAC->instUB); + ISACLBStruct* instLB = &(instISAC->instLB); + double bottleneckLB; + double bottleneckUB; + WebRtc_Word32 bottleneck = instISAC->bottleneck; + WebRtc_Word16 codingMode = instISAC->codingMode; + WebRtc_Word16 frameSizeMs = instLB->ISACencLB_obj.new_framelength / + (FS / 1000); + + if ((sampRate == kIsacWideband) && + (instISAC->encoderSamplingRateKHz == kIsacSuperWideband)) { + /* Changing from super-wideband to wideband. + * we don't need to re-initialize the encoder of the lower-band. */ + instISAC->bandwidthKHz = isac8kHz; + if (codingMode == 1) { + ControlLb(instLB, + (bottleneck > 32000) ? 32000 : bottleneck, FRAMESIZE); + } + instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX_60; + instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX_30; + } else if ((sampRate == kIsacSuperWideband) && + (instISAC->encoderSamplingRateKHz == kIsacWideband)) { + if (codingMode == 1) { + WebRtcIsac_RateAllocation(bottleneck, &bottleneckLB, &bottleneckUB, + &(instISAC->bandwidthKHz)); + } + + instISAC->bandwidthKHz = isac16kHz; + instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX; + instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX; + + EncoderInitLb(instLB, codingMode, sampRate); + EncoderInitUb(instUB, instISAC->bandwidthKHz); + + memset(instISAC->analysisFBState1, 0, + FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32)); + memset(instISAC->analysisFBState2, 0, + FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32)); + + if (codingMode == 1) { + instISAC->bottleneck = bottleneck; + ControlLb(instLB, bottleneckLB, + (instISAC->bandwidthKHz == isac8kHz) ? frameSizeMs:FRAMESIZE); + if (instISAC->bandwidthKHz > isac8kHz) { + ControlUb(instUB, bottleneckUB); + } + } else { + instLB->ISACencLB_obj.enforceFrameSize = 0; + instLB->ISACencLB_obj.new_framelength = FRAMESAMPLES; + } + } + instISAC->encoderSamplingRateKHz = sampRate; + return 0; + } +} + + +/****************************************************************************** + * WebRtcIsac_SetDecSampRate() + * This function sets the sampling rate of the decoder. Initialization of the + * decoder WILL NOT overwrite the sampling rate of the encoder. The default + * value is 16 kHz which is set when the instance is created. + * + * Input: + * - ISAC_main_inst : iSAC instance + * - sampRate : enumerator specifying the sampling rate. + * + * Return value : 0 if successful + * -1 if failed. + */ +WebRtc_Word16 WebRtcIsac_SetDecSampRate(ISACStruct* ISAC_main_inst, + enum IsacSamplingRate sampRate) { + ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; + + if ((sampRate != kIsacWideband) && + (sampRate != kIsacSuperWideband)) { + /* Sampling Frequency is not supported. */ + instISAC->errorCode = ISAC_UNSUPPORTED_SAMPLING_FREQUENCY; + return -1; + } else { + if ((instISAC->decoderSamplingRateKHz == kIsacWideband) && + (sampRate == kIsacSuperWideband)) { + /* Switching from wideband to super-wideband at the decoder + * we need to reset the filter-bank and initialize upper-band decoder. */ + memset(instISAC->synthesisFBState1, 0, + FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32)); + memset(instISAC->synthesisFBState2, 0, + FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32)); + + if (DecoderInitUb(&(instISAC->instUB)) < 0) { + return -1; + } + } + instISAC->decoderSamplingRateKHz = sampRate; + return 0; + } +} + + +/****************************************************************************** + * WebRtcIsac_EncSampRate() + * + * Input: + * - ISAC_main_inst : iSAC instance + * + * Return value : enumerator representing sampling frequency + * associated with the encoder, the input audio + * is expected to be sampled at this rate. + * + */ +enum IsacSamplingRate WebRtcIsac_EncSampRate(ISACStruct* ISAC_main_inst) { + ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; + return instISAC->encoderSamplingRateKHz; +} + + +/****************************************************************************** + * WebRtcIsac_DecSampRate() + * Return the sampling rate of the decoded audio. + * + * Input: + * - ISAC_main_inst : iSAC instance + * + * Return value : enumerator representing sampling frequency + * associated with the decoder, i.e. the + * sampling rate of the decoded audio. + * + */ +enum IsacSamplingRate WebRtcIsac_DecSampRate(ISACStruct* ISAC_main_inst) { + ISACMainStruct* instISAC = (ISACMainStruct*)ISAC_main_inst; + return instISAC->decoderSamplingRateKHz; +} diff --git a/src/modules/audio_coding/codecs/isac/main/source/isac.gypi b/src/modules/audio_coding/codecs/isac/main/source/isac.gypi new file mode 100644 index 0000000000..d30be551bd --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/isac.gypi @@ -0,0 +1,91 @@ +# 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. + +{ + 'targets': [ + { + 'target_name': 'iSAC', + 'type': '<(library)', + 'dependencies': [ + '<(webrtc_root)/common_audio/common_audio.gyp:signal_processing', + ], + 'include_dirs': [ + '../interface', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '../interface', + ], + }, + 'sources': [ + '../interface/isac.h', + 'arith_routines.c', + 'arith_routines_hist.c', + 'arith_routines_logist.c', + 'bandwidth_estimator.c', + 'crc.c', + 'decode.c', + 'decode_bwe.c', + 'encode.c', + 'encode_lpc_swb.c', + 'entropy_coding.c', + 'fft.c', + 'filter_functions.c', + 'filterbank_tables.c', + 'intialize.c', + 'isac.c', + 'filterbanks.c', + 'pitch_lag_tables.c', + 'lattice.c', + 'lpc_gain_swb_tables.c', + 'lpc_analysis.c', + 'lpc_shape_swb12_tables.c', + 'lpc_shape_swb16_tables.c', + 'lpc_tables.c', + 'pitch_estimator.c', + 'pitch_filter.c', + 'pitch_gain_tables.c', + 'spectrum_ar_model_tables.c', + 'transform.c', + 'arith_routines.h', + 'bandwidth_estimator.h', + 'codec.h', + 'crc.h', + 'encode_lpc_swb.h', + 'entropy_coding.h', + 'fft.h', + 'filterbank_tables.h', + 'lpc_gain_swb_tables.h', + 'lpc_analysis.h', + 'lpc_shape_swb12_tables.h', + 'lpc_shape_swb16_tables.h', + 'lpc_tables.h', + 'pitch_estimator.h', + 'pitch_gain_tables.h', + 'pitch_lag_tables.h', + 'settings.h', + 'spectrum_ar_model_tables.h', + 'structs.h', + 'os_specific_inline.h', + ], + 'conditions': [ + ['OS!="win"', { + 'defines': [ + 'WEBRTC_LINUX', + ], + }], + ], + }, + ], +} + +# Local Variables: +# tab-width:2 +# indent-tabs-mode:nil +# End: +# vim: set expandtab tabstop=2 shiftwidth=2: diff --git a/src/modules/audio_coding/codecs/isac/main/source/lattice.c b/src/modules/audio_coding/codecs/isac/main/source/lattice.c new file mode 100644 index 0000000000..a46135a3f7 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/lattice.c @@ -0,0 +1,217 @@ +/* + * 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. + */ + +/* + * lattice.c + * + * contains the normalized lattice filter routines (MA and AR) for iSAC codec + * + */ +#include "settings.h" +#include "codec.h" + +#include +#include +#ifdef WEBRTC_ANDROID +#include +#endif + +/* filter the signal using normalized lattice filter */ +/* MA filter */ +void WebRtcIsac_NormLatticeFilterMa(int orderCoef, + float *stateF, + float *stateG, + float *lat_in, + double *filtcoeflo, + double *lat_out) +{ + int n,k,i,u,temp1; + int ord_1 = orderCoef+1; + float sth[MAX_AR_MODEL_ORDER]; + float cth[MAX_AR_MODEL_ORDER]; + float inv_cth[MAX_AR_MODEL_ORDER]; + double a[MAX_AR_MODEL_ORDER+1]; + float f[MAX_AR_MODEL_ORDER+1][HALF_SUBFRAMELEN], g[MAX_AR_MODEL_ORDER+1][HALF_SUBFRAMELEN]; + float gain1; + + for (u=0;u=0;i--) //get the state of f&g for the first input, for all orders + { + ARf[i][0] = cth[i]*ARf[i+1][0] - sth[i]*stateG[i]; + ARg[i+1][0] = sth[i]*ARf[i+1][0] + cth[i]* stateG[i]; + } + ARg[0][0] = ARf[0][0]; + + for(n=0;n<(HALF_SUBFRAMELEN-1);n++) + { + for(k=orderCoef-1;k>=0;k--) + { + ARf[k][n+1] = cth[k]*ARf[k+1][n+1] - sth[k]*ARg[k][n]; + ARg[k+1][n+1] = sth[k]*ARf[k+1][n+1] + cth[k]* ARg[k][n]; + } + ARg[0][n+1] = ARf[0][n+1]; + } + + memcpy(lat_out+u * HALF_SUBFRAMELEN, &(ARf[0][0]), sizeof(float) * HALF_SUBFRAMELEN); + + /* cannot use memcpy in the following */ + for (i=0;i0; m--) + { + tmp_inv = 1.0f / cth2; + for (k=1; k<=m; k++) + { + tmp[k] = ((float)a[k] - sth[m] * (float)a[m-k+1]) * tmp_inv; + } + + for (k=1; k +#include + +#define LEVINSON_EPS 1.0e-10 + + +/* window */ +/* Matlab generation code: + * t = (1:256)/257; r = 1-(1-t).^.45; w = sin(r*pi).^3; w = w/sum(w); plot((1:256)/8, w); grid; + * for k=1:16, fprintf(1, '%.8f, ', w(k*16 + (-15:0))); fprintf(1, '\n'); end + */ +static const double kLpcCorrWindow[WINLEN] = { + 0.00000000, 0.00000001, 0.00000004, 0.00000010, 0.00000020, + 0.00000035, 0.00000055, 0.00000083, 0.00000118, 0.00000163, + 0.00000218, 0.00000283, 0.00000361, 0.00000453, 0.00000558, 0.00000679, + 0.00000817, 0.00000973, 0.00001147, 0.00001342, 0.00001558, + 0.00001796, 0.00002058, 0.00002344, 0.00002657, 0.00002997, + 0.00003365, 0.00003762, 0.00004190, 0.00004651, 0.00005144, 0.00005673, + 0.00006236, 0.00006837, 0.00007476, 0.00008155, 0.00008875, + 0.00009636, 0.00010441, 0.00011290, 0.00012186, 0.00013128, + 0.00014119, 0.00015160, 0.00016252, 0.00017396, 0.00018594, 0.00019846, + 0.00021155, 0.00022521, 0.00023946, 0.00025432, 0.00026978, + 0.00028587, 0.00030260, 0.00031998, 0.00033802, 0.00035674, + 0.00037615, 0.00039626, 0.00041708, 0.00043863, 0.00046092, 0.00048396, + 0.00050775, 0.00053233, 0.00055768, 0.00058384, 0.00061080, + 0.00063858, 0.00066720, 0.00069665, 0.00072696, 0.00075813, + 0.00079017, 0.00082310, 0.00085692, 0.00089164, 0.00092728, 0.00096384, + 0.00100133, 0.00103976, 0.00107914, 0.00111947, 0.00116077, + 0.00120304, 0.00124630, 0.00129053, 0.00133577, 0.00138200, + 0.00142924, 0.00147749, 0.00152676, 0.00157705, 0.00162836, 0.00168070, + 0.00173408, 0.00178850, 0.00184395, 0.00190045, 0.00195799, + 0.00201658, 0.00207621, 0.00213688, 0.00219860, 0.00226137, + 0.00232518, 0.00239003, 0.00245591, 0.00252284, 0.00259079, 0.00265977, + 0.00272977, 0.00280078, 0.00287280, 0.00294582, 0.00301984, + 0.00309484, 0.00317081, 0.00324774, 0.00332563, 0.00340446, + 0.00348421, 0.00356488, 0.00364644, 0.00372889, 0.00381220, 0.00389636, + 0.00398135, 0.00406715, 0.00415374, 0.00424109, 0.00432920, + 0.00441802, 0.00450754, 0.00459773, 0.00468857, 0.00478001, + 0.00487205, 0.00496464, 0.00505775, 0.00515136, 0.00524542, 0.00533990, + 0.00543476, 0.00552997, 0.00562548, 0.00572125, 0.00581725, + 0.00591342, 0.00600973, 0.00610612, 0.00620254, 0.00629895, + 0.00639530, 0.00649153, 0.00658758, 0.00668341, 0.00677894, 0.00687413, + 0.00696891, 0.00706322, 0.00715699, 0.00725016, 0.00734266, + 0.00743441, 0.00752535, 0.00761540, 0.00770449, 0.00779254, + 0.00787947, 0.00796519, 0.00804963, 0.00813270, 0.00821431, 0.00829437, + 0.00837280, 0.00844949, 0.00852436, 0.00859730, 0.00866822, + 0.00873701, 0.00880358, 0.00886781, 0.00892960, 0.00898884, + 0.00904542, 0.00909923, 0.00915014, 0.00919805, 0.00924283, 0.00928436, + 0.00932252, 0.00935718, 0.00938821, 0.00941550, 0.00943890, + 0.00945828, 0.00947351, 0.00948446, 0.00949098, 0.00949294, + 0.00949020, 0.00948262, 0.00947005, 0.00945235, 0.00942938, 0.00940099, + 0.00936704, 0.00932738, 0.00928186, 0.00923034, 0.00917268, + 0.00910872, 0.00903832, 0.00896134, 0.00887763, 0.00878706, + 0.00868949, 0.00858478, 0.00847280, 0.00835343, 0.00822653, 0.00809199, + 0.00794970, 0.00779956, 0.00764145, 0.00747530, 0.00730103, + 0.00711857, 0.00692787, 0.00672888, 0.00652158, 0.00630597, + 0.00608208, 0.00584994, 0.00560962, 0.00536124, 0.00510493, 0.00484089, + 0.00456935, 0.00429062, 0.00400505, 0.00371310, 0.00341532, + 0.00311238, 0.00280511, 0.00249452, 0.00218184, 0.00186864, + 0.00155690, 0.00124918, 0.00094895, 0.00066112, 0.00039320, 0.00015881 +}; + +double WebRtcIsac_LevDurb(double *a, double *k, double *r, int order) +{ + + double sum, alpha; + int m, m_h, i; + alpha = 0; //warning -DH + a[0] = 1.0; + if (r[0] < LEVINSON_EPS) { /* if r[0] <= 0, set LPC coeff. to zero */ + for (i = 0; i < order; i++) { + k[i] = 0; + a[i+1] = 0; + } + } else { + a[1] = k[0] = -r[1]/r[0]; + alpha = r[0] + r[1] * k[0]; + for (m = 1; m < order; m++){ + sum = r[m + 1]; + for (i = 0; i < m; i++){ + sum += a[i+1] * r[m - i]; + } + k[m] = -sum / alpha; + alpha += k[m] * sum; + m_h = (m + 1) >> 1; + for (i = 0; i < m_h; i++){ + sum = a[i+1] + k[m] * a[m - i]; + a[m - i] += k[m] * a[i+1]; + a[i+1] = sum; + } + a[m+1] = k[m]; + } + } + return alpha; +} + + +//was static before, but didn't work with MEX file +void WebRtcIsac_GetVars(const double *input, const WebRtc_Word16 *pitchGains_Q12, + double *oldEnergy, double *varscale) +{ + double nrg[4], chng, pg; + int k; + + double pitchGains[4]={0,0,0,0};; + + /* Calculate energies of first and second frame halfs */ + nrg[0] = 0.0001; + for (k = QLOOKAHEAD/2; k < (FRAMESAMPLES_QUARTER + QLOOKAHEAD) / 2; k++) { + nrg[0] += input[k]*input[k]; + } + nrg[1] = 0.0001; + for ( ; k < (FRAMESAMPLES_HALF + QLOOKAHEAD) / 2; k++) { + nrg[1] += input[k]*input[k]; + } + nrg[2] = 0.0001; + for ( ; k < (FRAMESAMPLES*3/4 + QLOOKAHEAD) / 2; k++) { + nrg[2] += input[k]*input[k]; + } + nrg[3] = 0.0001; + for ( ; k < (FRAMESAMPLES + QLOOKAHEAD) / 2; k++) { + nrg[3] += input[k]*input[k]; + } + + /* Calculate average level change */ + chng = 0.25 * (fabs(10.0 * log10(nrg[3] / nrg[2])) + + fabs(10.0 * log10(nrg[2] / nrg[1])) + + fabs(10.0 * log10(nrg[1] / nrg[0])) + + fabs(10.0 * log10(nrg[0] / *oldEnergy))); + + + /* Find average pitch gain */ + pg = 0.0; + for (k=0; k<4; k++) + { + pitchGains[k] = ((float)pitchGains_Q12[k])/4096; + pg += pitchGains[k]; + } + pg *= 0.25; + + /* If pitch gain is low and energy constant - increase noise level*/ + /* Matlab code: + pg = 0:.01:.45; plot(pg, 0.0 + 1.0 * exp( -1.0 * exp(-200.0 * pg.*pg.*pg) / (1.0 + 0.4 * 0) )) + */ + *varscale = 0.0 + 1.0 * exp( -1.4 * exp(-200.0 * pg*pg*pg) / (1.0 + 0.4 * chng) ); + + *oldEnergy = nrg[3]; +} + +void +WebRtcIsac_GetVarsUB( + const double* input, + double* oldEnergy, + double* varscale) +{ + double nrg[4], chng; + int k; + + /* Calculate energies of first and second frame halfs */ + nrg[0] = 0.0001; + for (k = 0; k < (FRAMESAMPLES_QUARTER) / 2; k++) { + nrg[0] += input[k]*input[k]; + } + nrg[1] = 0.0001; + for ( ; k < (FRAMESAMPLES_HALF) / 2; k++) { + nrg[1] += input[k]*input[k]; + } + nrg[2] = 0.0001; + for ( ; k < (FRAMESAMPLES*3/4) / 2; k++) { + nrg[2] += input[k]*input[k]; + } + nrg[3] = 0.0001; + for ( ; k < (FRAMESAMPLES) / 2; k++) { + nrg[3] += input[k]*input[k]; + } + + /* Calculate average level change */ + chng = 0.25 * (fabs(10.0 * log10(nrg[3] / nrg[2])) + + fabs(10.0 * log10(nrg[2] / nrg[1])) + + fabs(10.0 * log10(nrg[1] / nrg[0])) + + fabs(10.0 * log10(nrg[0] / *oldEnergy))); + + + /* If pitch gain is low and energy constant - increase noise level*/ + /* Matlab code: + pg = 0:.01:.45; plot(pg, 0.0 + 1.0 * exp( -1.0 * exp(-200.0 * pg.*pg.*pg) / (1.0 + 0.4 * 0) )) + */ + *varscale = exp( -1.4 / (1.0 + 0.4 * chng) ); + + *oldEnergy = nrg[3]; +} + +void WebRtcIsac_GetLpcCoefLb(double *inLo, double *inHi, MaskFiltstr *maskdata, + double signal_noise_ratio, const WebRtc_Word16 *pitchGains_Q12, + double *lo_coeff, double *hi_coeff) +{ + int k, n, j, pos1, pos2; + double varscale; + + double DataLo[WINLEN], DataHi[WINLEN]; + double corrlo[ORDERLO+2], corrlo2[ORDERLO+1]; + double corrhi[ORDERHI+1]; + double k_veclo[ORDERLO], k_vechi[ORDERHI]; + + double a_LO[ORDERLO+1], a_HI[ORDERHI+1]; + double tmp, res_nrg; + + double FwdA, FwdB; + + /* hearing threshold level in dB; higher value gives more noise */ + const double HearThresOffset = -28.0; + + /* bandwdith expansion factors for low- and high band */ + const double gammaLo = 0.9; + const double gammaHi = 0.8; + + /* less-noise-at-low-frequencies factor */ + double aa; + + + /* convert from dB to signal level */ + const double H_T_H = pow(10.0, 0.05 * HearThresOffset); + double S_N_R = pow(10.0, 0.05 * signal_noise_ratio) / 3.46; /* divide by sqrt(12) */ + + /* change quallevel depending on pitch gains and level fluctuations */ + WebRtcIsac_GetVars(inLo, pitchGains_Q12, &(maskdata->OldEnergy), &varscale); + + /* less-noise-at-low-frequencies factor */ + aa = 0.35 * (0.5 + 0.5 * varscale); + + /* replace data in buffer by new look-ahead data */ + for (pos1 = 0; pos1 < QLOOKAHEAD; pos1++) + maskdata->DataBufferLo[pos1 + WINLEN - QLOOKAHEAD] = inLo[pos1]; + + for (k = 0; k < SUBFRAMES; k++) { + + /* Update input buffer and multiply signal with window */ + for (pos1 = 0; pos1 < WINLEN - UPDATE/2; pos1++) { + maskdata->DataBufferLo[pos1] = maskdata->DataBufferLo[pos1 + UPDATE/2]; + maskdata->DataBufferHi[pos1] = maskdata->DataBufferHi[pos1 + UPDATE/2]; + DataLo[pos1] = maskdata->DataBufferLo[pos1] * kLpcCorrWindow[pos1]; + DataHi[pos1] = maskdata->DataBufferHi[pos1] * kLpcCorrWindow[pos1]; + } + pos2 = k * UPDATE/2; + for (n = 0; n < UPDATE/2; n++, pos1++) { + maskdata->DataBufferLo[pos1] = inLo[QLOOKAHEAD + pos2]; + maskdata->DataBufferHi[pos1] = inHi[pos2++]; + DataLo[pos1] = maskdata->DataBufferLo[pos1] * kLpcCorrWindow[pos1]; + DataHi[pos1] = maskdata->DataBufferHi[pos1] * kLpcCorrWindow[pos1]; + } + + /* Get correlation coefficients */ + WebRtcIsac_AutoCorr(corrlo, DataLo, WINLEN, ORDERLO+1); /* computing autocorrelation */ + WebRtcIsac_AutoCorr(corrhi, DataHi, WINLEN, ORDERHI); + + + /* less noise for lower frequencies, by filtering/scaling autocorrelation sequences */ + corrlo2[0] = (1.0+aa*aa) * corrlo[0] - 2.0*aa * corrlo[1]; + tmp = (1.0 + aa*aa); + for (n = 1; n <= ORDERLO; n++) { + corrlo2[n] = tmp * corrlo[n] - aa * (corrlo[n-1] + corrlo[n+1]); + } + tmp = (1.0+aa) * (1.0+aa); + for (n = 0; n <= ORDERHI; n++) { + corrhi[n] = tmp * corrhi[n]; + } + + /* add white noise floor */ + corrlo2[0] += 1e-6; + corrhi[0] += 1e-6; + + + FwdA = 0.01; + FwdB = 0.01; + + /* recursive filtering of correlation over subframes */ + for (n = 0; n <= ORDERLO; n++) { + maskdata->CorrBufLo[n] = FwdA * maskdata->CorrBufLo[n] + corrlo2[n]; + corrlo2[n] = ((1.0-FwdA)*FwdB) * maskdata->CorrBufLo[n] + (1.0-FwdB) * corrlo2[n]; + } + for (n = 0; n <= ORDERHI; n++) { + maskdata->CorrBufHi[n] = FwdA * maskdata->CorrBufHi[n] + corrhi[n]; + corrhi[n] = ((1.0-FwdA)*FwdB) * maskdata->CorrBufHi[n] + (1.0-FwdB) * corrhi[n]; + } + + /* compute prediction coefficients */ + WebRtcIsac_LevDurb(a_LO, k_veclo, corrlo2, ORDERLO); + WebRtcIsac_LevDurb(a_HI, k_vechi, corrhi, ORDERHI); + + /* bandwidth expansion */ + tmp = gammaLo; + for (n = 1; n <= ORDERLO; n++) { + a_LO[n] *= tmp; + tmp *= gammaLo; + } + + /* residual energy */ + res_nrg = 0.0; + for (j = 0; j <= ORDERLO; j++) { + for (n = 0; n <= j; n++) { + res_nrg += a_LO[j] * corrlo2[j-n] * a_LO[n]; + } + for (n = j+1; n <= ORDERLO; n++) { + res_nrg += a_LO[j] * corrlo2[n-j] * a_LO[n]; + } + } + + /* add hearing threshold and compute the gain */ + *lo_coeff++ = S_N_R / (sqrt(res_nrg) / varscale + H_T_H); + + /* copy coefficients to output array */ + for (n = 1; n <= ORDERLO; n++) { + *lo_coeff++ = a_LO[n]; + } + + + /* bandwidth expansion */ + tmp = gammaHi; + for (n = 1; n <= ORDERHI; n++) { + a_HI[n] *= tmp; + tmp *= gammaHi; + } + + /* residual energy */ + res_nrg = 0.0; + for (j = 0; j <= ORDERHI; j++) { + for (n = 0; n <= j; n++) { + res_nrg += a_HI[j] * corrhi[j-n] * a_HI[n]; + } + for (n = j+1; n <= ORDERHI; n++) { + res_nrg += a_HI[j] * corrhi[n-j] * a_HI[n]; + } + } + + /* add hearing threshold and compute of the gain */ + *hi_coeff++ = S_N_R / (sqrt(res_nrg) / varscale + H_T_H); + + /* copy coefficients to output array */ + for (n = 1; n <= ORDERHI; n++) { + *hi_coeff++ = a_HI[n]; + } + } +} + + + +/****************************************************************************** + * WebRtcIsac_GetLpcCoefUb() + * + * Compute LP coefficients and correlation coefficients. At 12 kHz LP + * coefficients of the first and the last sub-frame is computed. At 16 kHz + * LP coefficients of 4th, 8th and 12th sub-frames are computed. We always + * compute correlation coefficients of all sub-frames. + * + * Inputs: + * -inSignal : Input signal + * -maskdata : a structure keeping signal from previous frame. + * -bandwidth : specifies if the codec is in 0-16 kHz mode or + * 0-12 kHz mode. + * + * Outputs: + * -lpCoeff : pointer to a buffer where A-polynomials are + * written to (first coeff is 1 and it is not + * written) + * -corrMat : a matrix where correlation coefficients of each + * sub-frame are written to one row. + * -varscale : a scale used to compute LPC gains. + */ +void +WebRtcIsac_GetLpcCoefUb( + double* inSignal, + MaskFiltstr* maskdata, + double* lpCoeff, + double corrMat[][UB_LPC_ORDER + 1], + double* varscale, + WebRtc_Word16 bandwidth) +{ + int frameCntr, activeFrameCntr, n, pos1, pos2; + WebRtc_Word16 criterion1; + WebRtc_Word16 criterion2; + WebRtc_Word16 numSubFrames = SUBFRAMES * (1 + (bandwidth == isac16kHz)); + double data[WINLEN]; + double corrSubFrame[UB_LPC_ORDER+2]; + double reflecCoeff[UB_LPC_ORDER]; + + double aPolynom[UB_LPC_ORDER+1]; + double tmp; + + /* bandwdith expansion factors */ + const double gamma = 0.9; + + /* change quallevel depending on pitch gains and level fluctuations */ + WebRtcIsac_GetVarsUB(inSignal, &(maskdata->OldEnergy), varscale); + + /* replace data in buffer by new look-ahead data */ + for(frameCntr = 0, activeFrameCntr = 0; frameCntr < numSubFrames; + frameCntr++) + { + if(frameCntr == SUBFRAMES) + { + // we are in 16 kHz + varscale++; + WebRtcIsac_GetVarsUB(&inSignal[FRAMESAMPLES_HALF], + &(maskdata->OldEnergy), varscale); + } + /* Update input buffer and multiply signal with window */ + for(pos1 = 0; pos1 < WINLEN - UPDATE/2; pos1++) + { + maskdata->DataBufferLo[pos1] = maskdata->DataBufferLo[pos1 + + UPDATE/2]; + data[pos1] = maskdata->DataBufferLo[pos1] * kLpcCorrWindow[pos1]; + } + pos2 = frameCntr * UPDATE/2; + for(n = 0; n < UPDATE/2; n++, pos1++, pos2++) + { + maskdata->DataBufferLo[pos1] = inSignal[pos2]; + data[pos1] = maskdata->DataBufferLo[pos1] * kLpcCorrWindow[pos1]; + } + + /* Get correlation coefficients */ + /* computing autocorrelation */ + WebRtcIsac_AutoCorr(corrSubFrame, data, WINLEN, UB_LPC_ORDER+1); + memcpy(corrMat[frameCntr], corrSubFrame, + (UB_LPC_ORDER+1)*sizeof(double)); + + criterion1 = ((frameCntr == 0) || (frameCntr == (SUBFRAMES - 1))) && + (bandwidth == isac12kHz); + criterion2 = (((frameCntr+1) % 4) == 0) && + (bandwidth == isac16kHz); + if(criterion1 || criterion2) + { + /* add noise */ + corrSubFrame[0] += 1e-6; + /* compute prediction coefficients */ + WebRtcIsac_LevDurb(aPolynom, reflecCoeff, corrSubFrame, + UB_LPC_ORDER); + + /* bandwidth expansion */ + tmp = gamma; + for (n = 1; n <= UB_LPC_ORDER; n++) + { + *lpCoeff++ = aPolynom[n] * tmp; + tmp *= gamma; + } + activeFrameCntr++; + } + } +} + + + +/****************************************************************************** + * WebRtcIsac_GetLpcGain() + * + * Compute the LPC gains for each sub-frame, given the LPC of each sub-frame + * and the corresponding correlation coefficients. + * + * Inputs: + * -signal_noise_ratio : the desired SNR in dB. + * -numVecs : number of sub-frames + * -corrMat : a matrix of correlation coefficients where + * each row is a set of correlation coefficients of + * one sub-frame. + * -varscale : a scale computed when WebRtcIsac_GetLpcCoefUb() + * is called. + * + * Outputs: + * -gain : pointer to a buffer where LP gains are written. + * + */ +void +WebRtcIsac_GetLpcGain( + double signal_noise_ratio, + const double* filtCoeffVecs, + int numVecs, + double* gain, + double corrMat[][UB_LPC_ORDER + 1], + const double* varscale) +{ + WebRtc_Word16 j, n; + WebRtc_Word16 subFrameCntr; + double aPolynom[ORDERLO + 1]; + double res_nrg; + + const double HearThresOffset = -28.0; + const double H_T_H = pow(10.0, 0.05 * HearThresOffset); + /* divide by sqrt(12) = 3.46 */ + const double S_N_R = pow(10.0, 0.05 * signal_noise_ratio) / 3.46; + + aPolynom[0] = 1; + for(subFrameCntr = 0; subFrameCntr < numVecs; subFrameCntr++) + { + if(subFrameCntr == SUBFRAMES) + { + // we are in second half of a SWB frame. use new varscale + varscale++; + } + memcpy(&aPolynom[1], &filtCoeffVecs[(subFrameCntr * (UB_LPC_ORDER + 1)) + + 1], sizeof(double) * UB_LPC_ORDER); + + /* residual energy */ + res_nrg = 0.0; + for(j = 0; j <= UB_LPC_ORDER; j++) + { + for(n = 0; n <= j; n++) + { + res_nrg += aPolynom[j] * corrMat[subFrameCntr][j-n] * + aPolynom[n]; + } + for(n = j+1; n <= UB_LPC_ORDER; n++) + { + res_nrg += aPolynom[j] * corrMat[subFrameCntr][n-j] * + aPolynom[n]; + } + } + + /* add hearing threshold and compute the gain */ + gain[subFrameCntr] = S_N_R / (sqrt(res_nrg) / *varscale + H_T_H); + } +} diff --git a/src/modules/audio_coding/codecs/isac/main/source/lpc_analysis.h b/src/modules/audio_coding/codecs/isac/main/source/lpc_analysis.h new file mode 100644 index 0000000000..4eafeac7bc --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/lpc_analysis.h @@ -0,0 +1,50 @@ +/* + * 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. + */ + +/* + * lpc_analysis.h + * + * LPC functions + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_ANALYSIS_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_ANALYSIS_H_ + +#include "settings.h" +#include "structs.h" + +double WebRtcIsac_LevDurb(double *a, double *k, double *r, int order); + +void WebRtcIsac_GetVars(const double *input, const WebRtc_Word16 *pitchGains_Q12, + double *oldEnergy, double *varscale); + +void WebRtcIsac_GetLpcCoefLb(double *inLo, double *inHi, MaskFiltstr *maskdata, + double signal_noise_ratio, const WebRtc_Word16 *pitchGains_Q12, + double *lo_coeff, double *hi_coeff); + + +void WebRtcIsac_GetLpcGain( + double signal_noise_ratio, + const double* filtCoeffVecs, + int numVecs, + double* gain, + double corrLo[][UB_LPC_ORDER + 1], + const double* varscale); + +void WebRtcIsac_GetLpcCoefUb( + double* inSignal, + MaskFiltstr* maskdata, + double* lpCoeff, + double corr[][UB_LPC_ORDER + 1], + double* varscale, + WebRtc_Word16 bandwidth); + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_ANALYIS_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.c b/src/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.c new file mode 100644 index 0000000000..25c69cbfef --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.c @@ -0,0 +1,137 @@ +/* + * 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. + */ + +/* + * SWB_KLT_Tables_LPCGain.c + * + * This file defines tables used for entropy coding of LPC Gain + * of upper-band. + * + */ + +#include "lpc_gain_swb_tables.h" +#include "settings.h" +#include "typedefs.h" + +const double WebRtcIsac_kQSizeLpcGain = 0.100000; + +const double WebRtcIsac_kMeanLpcGain = -3.3822; + +/* +* The smallest reconstruction points for quantiztion of +* LPC gains. +*/ +const double WebRtcIsac_kLeftRecPointLpcGain[SUBFRAMES] = +{ + -0.800000, -1.000000, -1.200000, -2.200000, -3.000000, -12.700000 +}; + +/* +* Number of reconstruction points of quantizers for LPC Gains. +*/ +const WebRtc_Word16 WebRtcIsac_kNumQCellLpcGain[SUBFRAMES] = +{ + 17, 20, 25, 45, 77, 170 +}; +/* +* Starting index for entropy decoder to search for the right interval, +* one entry per LAR coefficient +*/ +const WebRtc_UWord16 WebRtcIsac_kLpcGainEntropySearch[SUBFRAMES] = +{ + 8, 10, 12, 22, 38, 85 +}; + +/* +* The following 6 vectors define CDF of 6 decorrelated LPC +* gains. +*/ +const WebRtc_UWord16 WebRtcIsac_kLpcGainCdfVec0[18] = +{ + 0, 10, 27, 83, 234, 568, 1601, 4683, 16830, 57534, 63437, + 64767, 65229, 65408, 65483, 65514, 65527, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcGainCdfVec1[21] = +{ + 0, 15, 33, 84, 185, 385, 807, 1619, 3529, 7850, 19488, + 51365, 62437, 64548, 65088, 65304, 65409, 65484, 65507, 65522, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcGainCdfVec2[26] = +{ + 0, 15, 29, 54, 89, 145, 228, 380, 652, 1493, 4260, + 12359, 34133, 50749, 57224, 60814, 62927, 64078, 64742, 65103, 65311, 65418, + 65473, 65509, 65521, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcGainCdfVec3[46] = +{ + 0, 8, 12, 16, 26, 42, 56, 76, 111, 164, 247, + 366, 508, 693, 1000, 1442, 2155, 3188, 4854, 7387, 11249, 17617, + 30079, 46711, 56291, 60127, 62140, 63258, 63954, 64384, 64690, 64891, 65031, + 65139, 65227, 65293, 65351, 65399, 65438, 65467, 65492, 65504, 65510, 65518, + 65523, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcGainCdfVec4[78] = +{ + 0, 17, 29, 39, 51, 70, 104, 154, 234, 324, 443, + 590, 760, 971, 1202, 1494, 1845, 2274, 2797, 3366, 4088, 4905, + 5899, 7142, 8683, 10625, 12983, 16095, 20637, 28216, 38859, 47237, 51537, + 54150, 56066, 57583, 58756, 59685, 60458, 61103, 61659, 62144, 62550, 62886, + 63186, 63480, 63743, 63954, 64148, 64320, 64467, 64600, 64719, 64837, 64939, + 65014, 65098, 65160, 65211, 65250, 65290, 65325, 65344, 65366, 65391, 65410, + 65430, 65447, 65460, 65474, 65487, 65494, 65501, 65509, 65513, 65518, 65520, + 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcGainCdfVec5[171] = +{ + 0, 10, 12, 14, 16, 18, 23, 29, 35, 42, 51, + 58, 65, 72, 78, 87, 96, 103, 111, 122, 134, 150, + 167, 184, 202, 223, 244, 265, 289, 315, 346, 379, 414, + 450, 491, 532, 572, 613, 656, 700, 751, 802, 853, 905, + 957, 1021, 1098, 1174, 1250, 1331, 1413, 1490, 1565, 1647, 1730, + 1821, 1913, 2004, 2100, 2207, 2314, 2420, 2532, 2652, 2783, 2921, + 3056, 3189, 3327, 3468, 3640, 3817, 3993, 4171, 4362, 4554, 4751, + 4948, 5142, 5346, 5566, 5799, 6044, 6301, 6565, 6852, 7150, 7470, + 7797, 8143, 8492, 8835, 9181, 9547, 9919, 10315, 10718, 11136, 11566, + 12015, 12482, 12967, 13458, 13953, 14432, 14903, 15416, 15936, 16452, 16967, + 17492, 18024, 18600, 19173, 19736, 20311, 20911, 21490, 22041, 22597, 23157, + 23768, 24405, 25034, 25660, 26280, 26899, 27614, 28331, 29015, 29702, 30403, + 31107, 31817, 32566, 33381, 34224, 35099, 36112, 37222, 38375, 39549, 40801, + 42074, 43350, 44626, 45982, 47354, 48860, 50361, 51845, 53312, 54739, 56026, + 57116, 58104, 58996, 59842, 60658, 61488, 62324, 63057, 63769, 64285, 64779, + 65076, 65344, 65430, 65500, 65517, 65535 +}; + +/* +* An array of pointers to CDFs of decorrelated LPC Gains +*/ +const WebRtc_UWord16* WebRtcIsac_kLpcGainCdfMat[SUBFRAMES] = +{ + WebRtcIsac_kLpcGainCdfVec0, WebRtcIsac_kLpcGainCdfVec1, + WebRtcIsac_kLpcGainCdfVec2, WebRtcIsac_kLpcGainCdfVec3, + WebRtcIsac_kLpcGainCdfVec4, WebRtcIsac_kLpcGainCdfVec5 +}; + +/* +* A matrix to decorrellate LPC gains of subframes. +*/ +const double WebRtcIsac_kLpcGainDecorrMat[SUBFRAMES][SUBFRAMES] = +{ + {-0.150860, 0.327872, 0.367220, 0.504613, 0.559270, 0.409234}, + { 0.457128, -0.613591, -0.289283, -0.029734, 0.393760, 0.418240}, + {-0.626043, 0.136489, -0.439118, -0.448323, 0.135987, 0.420869}, + { 0.526617, 0.480187, 0.242552, -0.488754, -0.158713, 0.411331}, + {-0.302587, -0.494953, 0.588112, -0.063035, -0.404290, 0.387510}, + { 0.086378, 0.147714, -0.428875, 0.548300, -0.570121, 0.401391} +}; diff --git a/src/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h b/src/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h new file mode 100644 index 0000000000..1eba97c8ba --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/lpc_gain_swb_tables.h @@ -0,0 +1,49 @@ +/* + * 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. + */ + +/* + * SWB_KLT_Tables_LPCGain.h + * + * This file declares tables used for entropy coding of LPC Gain + * of upper-band. + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_GAIN_SWB_TABLES_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_GAIN_SWB_TABLES_H_ + +#include "settings.h" +#include "typedefs.h" + +extern const double WebRtcIsac_kQSizeLpcGain; + +extern const double WebRtcIsac_kLeftRecPointLpcGain[SUBFRAMES]; + +extern const WebRtc_Word16 WebRtcIsac_kNumQCellLpcGain[SUBFRAMES]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcGainEntropySearch[SUBFRAMES]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcGainCdfVec0[18]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcGainCdfVec1[21]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcGainCdfVec2[26]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcGainCdfVec3[46]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcGainCdfVec4[78]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcGainCdfVec5[171]; + +extern const WebRtc_UWord16* WebRtcIsac_kLpcGainCdfMat[SUBFRAMES]; + +extern const double WebRtcIsac_kLpcGainDecorrMat[SUBFRAMES][SUBFRAMES]; + +#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_GAIN_SWB_TABLES_H_ diff --git a/src/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.c b/src/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.c new file mode 100644 index 0000000000..695d583277 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.c @@ -0,0 +1,159 @@ +/* + * 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. + */ + +/* + * SWB_KLT_Tables.c + * + * This file defines tables used for entropy coding of LPC shape of + * upper-band signal if the bandwidth is 12 kHz. + * + */ + +#include "lpc_shape_swb12_tables.h" +#include "settings.h" +#include "typedefs.h" + +/* +* Mean value of LAR +*/ +const double WebRtcIsac_kMeanLarUb12[UB_LPC_ORDER] = +{ + 0.03748928306641, 0.09453441192543, -0.01112522344398, 0.03800237516842 +}; + +/* +* A rotation matrix to decorrelate intra-vector correlation, +* i.e. correlation among components of LAR vector. +*/ +const double WebRtcIsac_kIntraVecDecorrMatUb12[UB_LPC_ORDER][UB_LPC_ORDER] = +{ + {-0.00075365493856, -0.05809964887743, -0.23397966154116, 0.97050367376411}, + { 0.00625021257734, -0.17299965610679, 0.95977735920651, 0.22104179375008}, + { 0.20543384258374, -0.96202143495696, -0.15301870801552, -0.09432375099565}, + {-0.97865075648479, -0.20300322280841, -0.02581111653779, -0.01913568980258} +}; + +/* +* A rotation matrix to remove correlation among LAR coefficients +* of different LAR vectors. One might guess that decorrelation matrix +* for the first component should differ from the second component +* but we haven't observed a significant benefit of having different +* decorrelation matrices for different components. +*/ +const double WebRtcIsac_kInterVecDecorrMatUb12 +[UB_LPC_VEC_PER_FRAME][UB_LPC_VEC_PER_FRAME] = +{ + { 0.70650597970460, -0.70770707262373}, + {-0.70770707262373, -0.70650597970460} +}; + +/* +* LAR quantization step-size. +*/ +const double WebRtcIsac_kLpcShapeQStepSizeUb12 = 0.150000; + +/* +* The smallest reconstruction points for quantiztion of LAR coefficients. +*/ +const double WebRtcIsac_kLpcShapeLeftRecPointUb12 +[UB_LPC_ORDER*UB_LPC_VEC_PER_FRAME] = +{ + -0.900000, -1.050000, -1.350000, -1.800000, -1.350000, -1.650000, + -2.250000, -3.450000 +}; + +/* +* Number of reconstruction points of quantizers for LAR coefficients. +*/ +const WebRtc_Word16 WebRtcIsac_kLpcShapeNumRecPointUb12 +[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME] = +{ + 13, 15, 19, 27, 19, 24, 32, 48 +}; + +/* +* Starting index for entropy decoder to search for the right interval, +* one entry per LAR coefficient +*/ +const WebRtc_UWord16 WebRtcIsac_kLpcShapeEntropySearchUb12 +[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME] = +{ + 6, 7, 9, 13, 9, 12, 16, 24 +}; + +/* +* The following 8 vectors define CDF of 8 decorrelated LAR +* coefficients. +*/ +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec0Ub12[14] = +{ + 0, 13, 95, 418, 1687, 6498, 21317, 44200, 59029, 63849, 65147, + 65449, 65525, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec1Ub12[16] = +{ + 0, 10, 59, 255, 858, 2667, 8200, 22609, 42988, 57202, 62947, + 64743, 65308, 65476, 65522, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec2Ub12[20] = +{ + 0, 18, 40, 118, 332, 857, 2017, 4822, 11321, 24330, 41279, + 54342, 60637, 63394, 64659, 65184, 65398, 65482, 65518, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec3Ub12[28] = +{ + 0, 21, 38, 90, 196, 398, 770, 1400, 2589, 4650, 8211, + 14933, 26044, 39592, 50814, 57452, 60971, 62884, 63995, 64621, 65019, 65273, + 65410, 65480, 65514, 65522, 65531, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec4Ub12[20] = +{ + 0, 7, 46, 141, 403, 969, 2132, 4649, 10633, 24902, 43254, + 54665, 59928, 62674, 64173, 64938, 65293, 65464, 65523, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec5Ub12[25] = +{ + 0, 7, 22, 72, 174, 411, 854, 1737, 3545, 6774, 13165, + 25221, 40980, 52821, 58714, 61706, 63472, 64437, 64989, 65287, 65430, 65503, + 65525, 65529, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec6Ub12[33] = +{ + 0, 11, 21, 36, 65, 128, 228, 401, 707, 1241, 2126, + 3589, 6060, 10517, 18853, 31114, 42477, 49770, 54271, 57467, 59838, 61569, + 62831, 63772, 64433, 64833, 65123, 65306, 65419, 65466, 65499, 65519, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec7Ub12[49] = +{ + 0, 14, 34, 67, 107, 167, 245, 326, 449, 645, 861, + 1155, 1508, 2003, 2669, 3544, 4592, 5961, 7583, 9887, 13256, 18765, + 26519, 34077, 40034, 44349, 47795, 50663, 53262, 55473, 57458, 59122, 60592, + 61742, 62690, 63391, 63997, 64463, 64794, 65045, 65207, 65309, 65394, 65443, + 65478, 65504, 65514, 65523, 65535 +}; + +/* +* An array of pointers to CDFs of decorrelated LARs +*/ +const WebRtc_UWord16* WebRtcIsac_kLpcShapeCdfMatUb12 +[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME] = +{ + WebRtcIsac_kLpcShapeCdfVec0Ub12, WebRtcIsac_kLpcShapeCdfVec1Ub12, + WebRtcIsac_kLpcShapeCdfVec2Ub12, WebRtcIsac_kLpcShapeCdfVec3Ub12, + WebRtcIsac_kLpcShapeCdfVec4Ub12, WebRtcIsac_kLpcShapeCdfVec5Ub12, + WebRtcIsac_kLpcShapeCdfVec6Ub12, WebRtcIsac_kLpcShapeCdfVec7Ub12 +}; diff --git a/src/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h b/src/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h new file mode 100644 index 0000000000..1e93847fae --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb12_tables.h @@ -0,0 +1,65 @@ +/* + * 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. + */ + +/* + * lpc_shape_swb12_tables.h + * + * This file declares tables used for entropy coding of LPC shape of + * upper-band signal if the bandwidth is 12 kHz. + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB12_TABLES_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB12_TABLES_H_ + +#include "settings.h" +#include "typedefs.h" + +extern const double WebRtcIsac_kMeanLarUb12[UB_LPC_ORDER]; + +extern const double WebRtcIsac_kMeanLpcGain; + +extern const double WebRtcIsac_kIntraVecDecorrMatUb12[UB_LPC_ORDER][UB_LPC_ORDER]; + +extern const double WebRtcIsac_kInterVecDecorrMatUb12 +[UB_LPC_VEC_PER_FRAME][UB_LPC_VEC_PER_FRAME]; + +extern const double WebRtcIsac_kLpcShapeQStepSizeUb12; + +extern const double WebRtcIsac_kLpcShapeLeftRecPointUb12 +[UB_LPC_ORDER*UB_LPC_VEC_PER_FRAME]; + + +extern const WebRtc_Word16 WebRtcIsac_kLpcShapeNumRecPointUb12 +[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeEntropySearchUb12 +[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec0Ub12[14]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec1Ub12[16]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec2Ub12[20]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec3Ub12[28]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec4Ub12[20]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec5Ub12[25]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec6Ub12[33]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec7Ub12[49]; + +extern const WebRtc_UWord16* WebRtcIsac_kLpcShapeCdfMatUb12 +[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME]; + +#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB12_TABLES_H_ diff --git a/src/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.c b/src/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.c new file mode 100644 index 0000000000..89f45233f5 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.c @@ -0,0 +1,248 @@ +/* + * 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. + */ + +/* + * SWB16_KLT_Tables.c + * + * This file defines tables used for entropy coding of LPC shape of + * upper-band signal if the bandwidth is 16 kHz. + * + */ + +#include "lpc_shape_swb16_tables.h" +#include "settings.h" +#include "typedefs.h" + +/* +* Mean value of LAR +*/ +const double WebRtcIsac_kMeanLarUb16[UB_LPC_ORDER] = +{ +0.454978, 0.364747, 0.102999, 0.104523 +}; + +/* +* A rotation matrix to decorrelate intra-vector correlation, +* i.e. correlation among components of LAR vector. +*/ +const double WebRtcIsac_kIintraVecDecorrMatUb16[UB_LPC_ORDER][UB_LPC_ORDER] = +{ + {-0.020528, -0.085858, -0.002431, 0.996093}, + {-0.033155, 0.036102, 0.998786, 0.004866}, + { 0.202627, 0.974853, -0.028940, 0.088132}, + {-0.978479, 0.202454, -0.039785, -0.002811} +}; + +/* +* A rotation matrix to remove correlation among LAR coefficients +* of different LAR vectors. One might guess that decorrelation matrix +* for the first component should differ from the second component +* but we haven't observed a significant benefit of having different +* decorrelation matrices for different components. +*/ +const double WebRtcIsac_kInterVecDecorrMatUb16 +[UB16_LPC_VEC_PER_FRAME][UB16_LPC_VEC_PER_FRAME] = +{ + { 0.291675, -0.515786, 0.644927, 0.482658}, + {-0.647220, 0.479712, 0.289556, 0.516856}, + { 0.643084, 0.485489, -0.289307, 0.516763}, + {-0.287185, -0.517823, -0.645389, 0.482553} +}; + +/* +* The following 16 vectors define CDF of 16 decorrelated LAR +* coefficients. +*/ +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub16[14] = +{ + 0, 2, 20, 159, 1034, 5688, 20892, 44653, + 59849, 64485, 65383, 65518, 65534, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec1Ub16[16] = +{ + 0, 1, 7, 43, 276, 1496, 6681, 21653, + 43891, 58859, 64022, 65248, 65489, 65529, 65534, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec2Ub16[18] = +{ + 0, 1, 9, 54, 238, 933, 3192, 9461, + 23226, 42146, 56138, 62413, 64623, 65300, 65473, 65521, + 65533, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec3Ub16[30] = +{ + 0, 2, 4, 8, 17, 36, 75, 155, + 329, 683, 1376, 2662, 5047, 9508, 17526, 29027, + 40363, 48997, 55096, 59180, 61789, 63407, 64400, 64967, + 65273, 65429, 65497, 65526, 65534, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec4Ub16[16] = +{ + 0, 1, 10, 63, 361, 1785, 7407, 22242, + 43337, 58125, 63729, 65181, 65472, 65527, 65534, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec5Ub16[17] = +{ + 0, 1, 7, 29, 134, 599, 2443, 8590, + 22962, 42635, 56911, 63060, 64940, 65408, 65513, 65531, + 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec6Ub16[21] = +{ + 0, 1, 5, 16, 57, 191, 611, 1808, + 4847, 11755, 24612, 40910, 53789, 60698, 63729, 64924, + 65346, 65486, 65523, 65532, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec7Ub16[36] = +{ + 0, 1, 4, 12, 25, 55, 104, 184, + 314, 539, 926, 1550, 2479, 3861, 5892, 8845, + 13281, 20018, 29019, 38029, 45581, 51557, 56057, 59284, + 61517, 63047, 64030, 64648, 65031, 65261, 65402, 65480, + 65518, 65530, 65534, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec8Ub16[21] = +{ + 0, 1, 2, 7, 26, 103, 351, 1149, + 3583, 10204, 23846, 41711, 55361, 61917, 64382, 65186, + 65433, 65506, 65528, 65534, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub160[21] = +{ + 0, 6, 19, 63, 205, 638, 1799, 4784, + 11721, 24494, 40803, 53805, 60886, 63822, 64931, 65333, + 65472, 65517, 65530, 65533, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub161[28] = +{ + 0, 1, 3, 11, 31, 86, 221, 506, + 1101, 2296, 4486, 8477, 15356, 26079, 38941, 49952, + 57165, 61257, 63426, 64549, 65097, 65351, 65463, 65510, + 65526, 65532, 65534, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub162[55] = +{ + 0, 3, 12, 23, 42, 65, 89, 115, + 150, 195, 248, 327, 430, 580, 784, 1099, + 1586, 2358, 3651, 5899, 9568, 14312, 19158, 23776, + 28267, 32663, 36991, 41153, 45098, 48680, 51870, 54729, + 57141, 59158, 60772, 62029, 63000, 63761, 64322, 64728, + 65000, 65192, 65321, 65411, 65463, 65496, 65514, 65523, + 65527, 65529, 65531, 65532, 65533, 65534, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub163[26] = +{ + 0, 2, 4, 10, 21, 48, 114, 280, + 701, 1765, 4555, 11270, 24267, 41213, 54285, 61003, + 63767, 64840, 65254, 65421, 65489, 65514, 65526, 65532, + 65534, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub164[28] = +{ + 0, 1, 3, 6, 15, 36, 82, 196, + 453, 1087, 2557, 5923, 13016, 25366, 40449, 52582, + 59539, 62896, 64389, 65033, 65316, 65442, 65494, 65519, + 65529, 65533, 65534, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub165[34] = +{ + 0, 2, 4, 8, 18, 35, 73, 146, + 279, 524, 980, 1789, 3235, 5784, 10040, 16998, + 27070, 38543, 48499, 55421, 59712, 62257, 63748, 64591, + 65041, 65278, 65410, 65474, 65508, 65522, 65530, 65533, + 65534, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub166[71] = +{ + 0, 1, 2, 6, 13, 26, 55, 92, + 141, 191, 242, 296, 355, 429, 522, 636, + 777, 947, 1162, 1428, 1753, 2137, 2605, 3140, + 3743, 4409, 5164, 6016, 6982, 8118, 9451, 10993, + 12754, 14810, 17130, 19780, 22864, 26424, 30547, 35222, + 40140, 44716, 48698, 52056, 54850, 57162, 59068, 60643, + 61877, 62827, 63561, 64113, 64519, 64807, 65019, 65167, + 65272, 65343, 65399, 65440, 65471, 65487, 65500, 65509, + 65518, 65524, 65527, 65531, 65533, 65534, 65535 +}; + +/* +* An array of pointers to CDFs of decorrelated LARs +*/ +const WebRtc_UWord16* WebRtcIsac_kLpcShapeCdfMatUb16 +[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME] = { + WebRtcIsac_kLpcShapeCdfVec01Ub16, + WebRtcIsac_kLpcShapeCdfVec1Ub16, + WebRtcIsac_kLpcShapeCdfVec2Ub16, + WebRtcIsac_kLpcShapeCdfVec3Ub16, + WebRtcIsac_kLpcShapeCdfVec4Ub16, + WebRtcIsac_kLpcShapeCdfVec5Ub16, + WebRtcIsac_kLpcShapeCdfVec6Ub16, + WebRtcIsac_kLpcShapeCdfVec7Ub16, + WebRtcIsac_kLpcShapeCdfVec8Ub16, + WebRtcIsac_kLpcShapeCdfVec01Ub160, + WebRtcIsac_kLpcShapeCdfVec01Ub161, + WebRtcIsac_kLpcShapeCdfVec01Ub162, + WebRtcIsac_kLpcShapeCdfVec01Ub163, + WebRtcIsac_kLpcShapeCdfVec01Ub164, + WebRtcIsac_kLpcShapeCdfVec01Ub165, + WebRtcIsac_kLpcShapeCdfVec01Ub166 +}; + +/* +* The smallest reconstruction points for quantiztion of LAR coefficients. +*/ +const double WebRtcIsac_kLpcShapeLeftRecPointUb16 +[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME] = +{ + -0.8250, -0.9750, -1.1250, -2.1750, -0.9750, -1.1250, -1.4250, + -2.6250, -1.4250, -1.2750, -1.8750, -3.6750, -1.7250, -1.8750, + -2.3250, -5.4750 +}; + +/* +* Number of reconstruction points of quantizers for LAR coefficients. +*/ +const WebRtc_Word16 WebRtcIsac_kLpcShapeNumRecPointUb16 +[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME] = +{ + 13, 15, 17, 29, 15, 16, 20, 35, 20, + 20, 27, 54, 25, 27, 33, 70 +}; + +/* +* Starting index for entropy decoder to search for the right interval, +* one entry per LAR coefficient +*/ +const WebRtc_UWord16 WebRtcIsac_kLpcShapeEntropySearchUb16 +[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME] = +{ + 6, 7, 8, 14, 7, 8, 10, 17, 10, + 10, 13, 27, 12, 13, 16, 35 +}; + +/* +* LAR quantization step-size. +*/ +const double WebRtcIsac_kLpcShapeQStepSizeUb16 = 0.150000; diff --git a/src/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h b/src/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h new file mode 100644 index 0000000000..68d08b2047 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/lpc_shape_swb16_tables.h @@ -0,0 +1,79 @@ +/* + * 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. + */ + +/* + * lpc_shape_swb16_tables.h + * + * This file declares tables used for entropy coding of LPC shape of + * upper-band signal if the bandwidth is 16 kHz. + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB16_TABLES_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB16_TABLES_H_ + +#include "settings.h" +#include "typedefs.h" + + +extern const double WebRtcIsac_kMeanLarUb16[UB_LPC_ORDER]; + +extern const double WebRtcIsac_kIintraVecDecorrMatUb16[UB_LPC_ORDER][UB_LPC_ORDER]; + +extern const double WebRtcIsac_kInterVecDecorrMatUb16 +[UB16_LPC_VEC_PER_FRAME][UB16_LPC_VEC_PER_FRAME]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub16[14]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec1Ub16[16]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec2Ub16[18]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec3Ub16[30]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec4Ub16[16]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec5Ub16[17]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec6Ub16[21]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec7Ub16[36]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec8Ub16[21]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub160[21]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub161[28]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub162[55]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub163[26]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub164[28]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub165[34]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub166[71]; + +extern const WebRtc_UWord16* WebRtcIsac_kLpcShapeCdfMatUb16 +[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME]; + +extern const double WebRtcIsac_kLpcShapeLeftRecPointUb16 +[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME]; + +extern const WebRtc_Word16 WebRtcIsac_kLpcShapeNumRecPointUb16 +[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeEntropySearchUb16 +[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME]; + +extern const double WebRtcIsac_kLpcShapeQStepSizeUb16; + +#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB16_TABLES_H_ diff --git a/src/modules/audio_coding/codecs/isac/main/source/lpc_tables.c b/src/modules/audio_coding/codecs/isac/main/source/lpc_tables.c new file mode 100644 index 0000000000..985e43cb6f --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/lpc_tables.c @@ -0,0 +1,601 @@ +/* + * 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. + */ + +/* coding tables for the KLT coefficients */ + +#include "lpc_tables.h" +#include "settings.h" + +/* cdf array for model indicator */ +const WebRtc_UWord16 WebRtcIsac_kQKltModelCdf[4] = { + 0, 15434, 37548, 65535 }; + +/* pointer to cdf array for model indicator */ +const WebRtc_UWord16 *WebRtcIsac_kQKltModelCdfPtr[1] = { + WebRtcIsac_kQKltModelCdf }; + +/* initial cdf index for decoder of model indicator */ +const WebRtc_UWord16 WebRtcIsac_kQKltModelInitIndex[1] = { 1 }; + +/* offset to go from rounded value to quantization index */ +const short WebRtcIsac_kQKltQuantMinGain[12] = { + 3, 6, 4, 6, 6, 9, 5, 16, 11, 34, 32, 47 }; + + +const short WebRtcIsac_kQKltQuantMinShape[108] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 2, 2, 2, 3, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 1, 2, 2, 3, 0, 0, 0, 0, + 1, 0, 1, 1, 1, 1, 1, 1, 1, 2, + 2, 4, 3, 5, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 2, 1, 2, 2, 3, 4, + 4, 7, 0, 0, 1, 1, 1, 1, 1, 1, + 1, 2, 3, 2, 3, 4, 4, 5, 7, 13, + 0, 1, 1, 2, 3, 2, 2, 2, 4, 4, + 5, 6, 7, 11, 9, 13, 12, 26 }; + +/* maximum quantization index */ +const WebRtc_UWord16 WebRtcIsac_kQKltMaxIndGain[12] = { + 6, 12, 8, 14, 10, 19, 12, 31, 22, 56, 52, 138 }; + +const WebRtc_UWord16 WebRtcIsac_kQKltMaxIndShape[108] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 2, 2, 2, 2, 4, 4, 5, 6, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 1, 2, 2, + 2, 2, 3, 4, 5, 7, 0, 0, 0, 0, + 2, 0, 2, 2, 2, 2, 3, 2, 2, 4, + 4, 6, 6, 9, 0, 0, 0, 0, 2, 2, + 2, 2, 2, 2, 3, 2, 4, 4, 7, 7, + 9, 13, 0, 0, 2, 2, 2, 2, 2, 2, + 3, 4, 5, 4, 6, 8, 8, 10, 16, 25, + 0, 2, 2, 4, 5, 4, 4, 4, 7, 8, + 9, 10, 13, 19, 17, 23, 25, 49 }; + +/* index offset */ +const WebRtc_UWord16 WebRtcIsac_kQKltOffsetGain[12] = { + 0, 7, 20, 29, 44, 55, 75, 88, 120, 143, 200, 253 }; + +const WebRtc_UWord16 WebRtcIsac_kQKltOffsetShape[108] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 11, 14, 17, 20, 23, 28, 33, 39, 46, 47, + 48, 49, 50, 52, 53, 54, 55, 56, 58, 61, + 64, 67, 70, 74, 79, 85, 93, 94, 95, 96, + 97, 100, 101, 104, 107, 110, 113, 117, 120, 123, + 128, 133, 140, 147, 157, 158, 159, 160, 161, 164, + 167, 170, 173, 176, 179, 183, 186, 191, 196, 204, + 212, 222, 236, 237, 238, 241, 244, 247, 250, 253, + 256, 260, 265, 271, 276, 283, 292, 301, 312, 329, + 355, 356, 359, 362, 367, 373, 378, 383, 388, 396, + 405, 415, 426, 440, 460, 478, 502, 528 }; + +/* initial cdf index for KLT coefficients */ +const WebRtc_UWord16 WebRtcIsac_kQKltInitIndexGain[12] = { + 3, 6, 4, 7, 5, 10, 6, 16, 11, 28, 26, 69}; + +const WebRtc_UWord16 WebRtcIsac_kQKltInitIndexShape[108] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 2, 2, 3, 3, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 2, 2, 3, 4, 0, 0, 0, 0, + 1, 0, 1, 1, 1, 1, 2, 1, 1, 2, + 2, 3, 3, 5, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 2, 1, 2, 2, 4, 4, + 5, 7, 0, 0, 1, 1, 1, 1, 1, 1, + 2, 2, 3, 2, 3, 4, 4, 5, 8, 13, + 0, 1, 1, 2, 3, 2, 2, 2, 4, 4, + 5, 5, 7, 10, 9, 12, 13, 25 }; + + +/* quantizer representation levels */ +const double WebRtcIsac_kQKltLevelsGain[392] = { + -2.78127126, -1.76745590, -0.77913790, -0.00437329, 0.79961206, + 1.81775776, 2.81389782, -5.78753143, -4.88384084, -3.89320940, + -2.88133610, -1.92859977, -0.86347396, 0.02003888, 0.86140400, + 1.89667156, 2.97134967, 3.98781964, 4.91727277, 5.82865898, + -4.11195874, -2.80898424, -1.87547977, -0.80943825, -0.00679084, + 0.79573851, 1.83953397, 2.67586037, 3.76274082, -6.10933968, + -4.93034581, -3.89281296, -2.91530625, -1.89684163, -0.85319130, + -0.02275767, 0.86862017, 1.91578276, 2.96107339, 3.96543056, + 4.91369908, 5.91058154, 6.83848343, 8.07136925, -5.87470395, + -4.84703049, -3.84284597, -2.86168446, -1.89290192, -0.82798145, + -0.00080013, 0.82594974, 1.85754329, 2.88351798, 3.96172628, + -8.85684885, -7.87387461, -6.97811862, -5.93256270, -4.94301439, + -3.95513701, -2.96041544, -1.94031192, -0.87961478, -0.00456201, + 0.89911505, 1.91723376, 2.94011511, 3.93302540, 4.97990967, + 5.93133404, 7.02181199, 7.92407762, 8.80155440, 10.04665814, + -4.82396678, -3.85612158, -2.89482244, -1.89558408, -0.90036978, + -0.00677823, 0.90607989, 1.90937981, 2.91175777, 3.91637730, + 4.97565723, 5.84771228, 7.11145863, -16.07879840, -15.03776309, + -13.93905670, -12.95671800, -11.89171202, -10.95820934, -9.95923714, + -8.94357334, -7.99068299, -6.97481009, -5.94826231, -4.96673988, + -3.97490466, -2.97846970, -1.95130435, -0.94215262, -0.01444043, + 0.96770704, 1.95848598, 2.94107862, 3.95666119, 4.97253085, + 5.97191122, 6.93277360, 7.96608727, 8.87958779, 10.00264269, + 10.86560820, 12.07449071, 13.04491775, 13.97507061, 14.91845261, + -10.85696295, -9.83365357, -9.01245635, -7.95915145, -6.95625003, + -5.95362618, -4.93468444, -3.98760978, -2.95044407, -1.97041277, + -0.97701799, -0.00840234, 0.97834289, 1.98361415, 2.97802439, + 3.96415871, 4.95369042, 5.94101770, 6.92756798, 7.94063998, + 8.85951828, 9.97077022, 11.00068503, -33.92030406, -32.81426422, + -32.00000000, -31.13243639, -30.11886909, -29.06017570, -28.12598824, + -27.22045482, -25.81215858, -25.07849962, -23.93018013, -23.02097643, + -21.89529725, -20.99091085, -19.98889048, -18.94327044, -17.96562071, + -16.96126218, -15.95054062, -14.98516200, -13.97101012, -13.02106500, + -11.98438006, -11.03216748, -9.95930286, -8.97043946, -7.98085082, + -6.98360995, -5.98998802, -4.98668173, -4.00032906, -3.00420619, + -1.98701132, -0.99324682, -0.00609324, 0.98297834, 1.99483076, + 3.00305044, 3.97142097, 4.97525759, 5.98612258, 6.97448236, + 7.97575900, 9.01086211, 9.98665542, 11.00541438, 11.98078628, + 12.92352471, 14.06849675, 14.99949430, 15.94904834, 16.97440321, + 18.04040916, 18.88987609, 20.05312391, 21.00000000, 21.79443341, + -31.98578825, -31.00000000, -29.89060567, -28.98555686, -27.97114102, + -26.84935410, -26.02402230, -24.94195278, -23.92336849, -22.95552382, + -21.97932836, -20.96055470, -19.99649553, -19.03436122, -17.96706525, + -17.01139515, -16.01363516, -14.99154248, -14.00298333, -12.99630613, + -11.99955519, -10.99000421, -10.00819092, -8.99763648, -7.98431793, + -7.01769025, -5.99604690, -4.99980697, -3.99334671, -3.01748192, + -2.02051217, -1.00848371, -0.01942358, 1.00477757, 1.95477872, + 2.98593031, 3.98779079, 4.96862849, 6.02694771, 6.93983733, + 7.89874717, 8.99615862, 10.02367921, 10.96293452, 11.84351528, + 12.92207187, 13.85122329, 15.05146877, 15.99371264, 17.00000000, + 18.00000000, 19.00000000, 19.82763573, -47.00000000, -46.00000000, + -44.87138498, -44.00000000, -43.00000000, -42.00000000, -41.00000000, + -39.88966612, -38.98913239, -37.80306486, -37.23584325, -35.94200288, + -34.99881301, -34.11361858, -33.06507360, -32.13129135, -30.90891364, + -29.81511907, -28.99250380, -28.04535391, -26.99767800, -26.04418164, + -24.95687851, -24.04865595, -23.03392645, -21.89366707, -20.93517364, + -19.99388660, -18.91620943, -18.03749683, -16.99532379, -15.98683813, + -15.06421479, -13.99359211, -12.99714098, -11.97022520, -10.98500279, + -9.98834422, -8.95729330, -8.01232284, -7.00253661, -5.99681626, + -5.01207817, -3.95914904, -3.01232178, -1.96615919, -0.97687670, + 0.01228030, 0.98412288, 2.01753544, 3.00580570, 3.97783510, + 4.98846894, 6.01321400, 7.00867732, 8.00416375, 9.01771966, + 9.98637729, 10.98255180, 11.99194163, 13.01807333, 14.00999545, + 15.00118556, 16.00089224, 17.00584148, 17.98251763, 18.99942091, + 19.96917690, 20.97839265, 21.98207297, 23.00171271, 23.99930737, + 24.99746061, 26.00936304, 26.98240132, 28.01126868, 29.01395915, + 29.98153507, 31.01376711, 31.99876818, 33.00475317, 33.99753994, + 34.99493913, 35.98933585, 36.95620160, 37.98428461, 38.99317544, + 40.01832073, 40.98048133, 41.95999283, 42.98232091, 43.96523612, + 44.99574268, 45.99524194, 47.05464025, 48.03821548, 48.99354366, + 49.96400411, 50.98017973, 51.95184408, 52.96291806, 54.00194392, + 54.96603783, 55.95623778, 57.03076595, 58.05889901, 58.99081551, + 59.97928121, 61.05071612, 62.03971580, 63.01286038, 64.01290338, + 65.02074503, 65.99454594, 67.00399425, 67.96571257, 68.95305727, + 69.92030664, 70.95594862, 71.98088567, 73.04764124, 74.00285480, + 75.02696330, 75.89837673, 76.93459997, 78.16266309, 78.83317543, + 80.00000000, 80.87251574, 82.09803524, 83.10671664, 84.00000000, + 84.77023523, 86.00000000, 87.00000000, 87.92946897, 88.69159118, + 90.00000000, 90.90535270 }; + +const double WebRtcIsac_kQKltLevelsShape[578] = { + 0.00032397, 0.00008053, -0.00061202, -0.00012620, 0.00030437, + 0.00054764, -0.00027902, 0.00069360, 0.00029449, -0.80219239, + 0.00091089, -0.74514927, -0.00094283, 0.64030631, -0.60509119, + 0.00035575, 0.61851665, -0.62129957, 0.00375219, 0.60054900, + -0.61554359, 0.00054977, 0.63362016, -1.73118727, -0.65422341, + 0.00524568, 0.66165298, 1.76785515, -1.83182018, -0.65997434, + -0.00011887, 0.67524299, 1.79933938, -1.76344480, -0.72547708, + -0.00133017, 0.73104704, 1.75305377, 2.85164534, -2.80423916, + -1.71959639, -0.75419722, -0.00329945, 0.77196760, 1.72211069, + 2.87339653, 0.00031089, -0.00015311, 0.00018201, -0.00035035, + -0.77357251, 0.00154647, -0.00047625, -0.00045299, 0.00086590, + 0.00044762, -0.83383829, 0.00024787, -0.68526258, -0.00122472, + 0.64643255, -0.60904942, -0.00448987, 0.62309184, -0.59626442, + -0.00574132, 0.62296546, -0.63222115, 0.00013441, 0.63609545, + -0.66911055, -0.00369971, 0.66346095, 2.07281301, -1.77184694, + -0.67640425, -0.00010145, 0.64818392, 1.74948973, -1.69420224, + -0.71943894, -0.00004680, 0.75303493, 1.81075983, 2.80610041, + -2.80005755, -1.79866753, -0.77409777, -0.00084220, 0.80141293, + 1.78291081, 2.73954236, 3.82994169, 0.00015140, -0.00012766, + -0.00034241, -0.00119125, -0.76113497, 0.00069246, 0.76722027, + 0.00132862, -0.69107530, 0.00010656, 0.77061578, -0.78012970, + 0.00095947, 0.77828502, -0.64787758, 0.00217168, 0.63050167, + -0.58601125, 0.00306596, 0.59466308, -0.58603410, 0.00059779, + 0.64257970, 1.76512766, -0.61193600, -0.00259517, 0.59767574, + -0.61026273, 0.00315811, 0.61725479, -1.69169719, -0.65816029, + 0.00067575, 0.65576890, 2.00000000, -1.72689193, -0.69780808, + -0.00040990, 0.70668487, 1.74198458, -3.79028154, -3.00000000, + -1.73194459, -0.70179341, -0.00106695, 0.71302629, 1.76849782, + -2.89332364, -1.78585007, -0.78731491, -0.00132610, 0.79692976, + 1.75247009, 2.97828682, -5.26238694, -3.69559829, -2.87286122, + -1.84908818, -0.84434577, -0.01167975, 0.84641753, 1.84087672, + 2.87628156, 3.83556679, -0.00190204, 0.00092642, 0.00354385, + -0.00012982, -0.67742785, 0.00229509, 0.64935672, -0.58444751, + 0.00470733, 0.57299534, -0.58456202, -0.00097715, 0.64593607, + -0.64060330, -0.00638534, 0.59680157, -0.59287537, 0.00490772, + 0.58919707, -0.60306173, -0.00417464, 0.60562100, -1.75218757, + -0.63018569, -0.00225922, 0.63863300, -0.63949939, -0.00126421, + 0.64268914, -1.75851182, -0.68318060, 0.00510418, 0.69049211, + 1.88178506, -1.71136148, -0.72710534, -0.00815559, 0.73412917, + 1.79996711, -2.77111145, -1.73940498, -0.78212945, 0.01074476, + 0.77688916, 1.76873972, 2.87281379, 3.77554698, -3.75832725, + -2.95463235, -1.80451491, -0.80017226, 0.00149902, 0.80729206, + 1.78265046, 2.89391793, -3.78236148, -2.83640598, -1.82532067, + -0.88844327, -0.00620952, 0.88208030, 1.85757631, 2.81712391, + 3.88430176, 5.16179367, -7.00000000, -5.93805408, -4.87172597, + -3.87524433, -2.89399744, -1.92359563, -0.92136341, -0.00172725, + 0.93087018, 1.90528280, 2.89809686, 3.88085708, 4.89147740, + 5.89078692, -0.00239502, 0.00312564, -1.00000000, 0.00178325, + 1.00000000, -0.62198029, 0.00143254, 0.65344051, -0.59851220, + -0.00676987, 0.61510140, -0.58894151, 0.00385055, 0.59794203, + -0.59808568, -0.00038214, 0.57625703, -0.63009713, -0.01107985, + 0.61278758, -0.64206758, -0.00154369, 0.65480598, 1.80604162, + -1.80909286, -0.67810514, 0.00205762, 0.68571097, 1.79453891, + -3.22682422, -1.73808453, -0.71870305, -0.00738594, 0.71486172, + 1.73005326, -1.66891897, -0.73689615, -0.00616203, 0.74262409, + 1.73807899, -2.92417482, -1.73866741, -0.78133871, 0.00764425, + 0.80027264, 1.78668732, 2.74992588, -4.00000000, -2.75578740, + -1.83697516, -0.83117035, -0.00355191, 0.83527172, 1.82814700, + 2.77377675, 3.80718693, -3.81667698, -2.83575471, -1.83372350, + -0.86579471, 0.00547578, 0.87582281, 1.82858793, 2.87265007, + 3.91405377, -4.87521600, -3.78999094, -2.86437014, -1.86964365, + -0.90618018, 0.00128243, 0.91497811, 1.87374952, 2.83199819, + 3.91519130, 4.76632822, -6.68713448, -6.01252467, -4.94587936, + -3.88795368, -2.91299088, -1.92592211, -0.95504570, -0.00089980, + 0.94565200, 1.93239633, 2.91832808, 3.91363475, 4.88920034, + 5.96471415, 6.83905252, 7.86195009, 8.81571018,-12.96141759, + -11.73039516,-10.96459719, -9.97382433, -9.04414433, -7.89460619, + -6.96628608, -5.93236595, -4.93337924, -3.95479990, -2.96451499, + -1.96635876, -0.97271229, -0.00402238, 0.98343930, 1.98348291, + 2.96641164, 3.95456471, 4.95517089, 5.98975714, 6.90322073, + 7.90468849, 8.85639467, 9.97255498, 10.79006309, 11.81988596, + 0.04950500, -1.00000000, -0.01226628, 1.00000000, -0.59479469, + -0.10438305, 0.59822144, -2.00000000, -0.67109149, -0.09256692, + 0.65171621, 2.00000000, -3.00000000, -1.68391999, -0.76681039, + -0.03354151, 0.71509146, 1.77615472, -2.00000000, -0.68661511, + -0.02497881, 0.66478398, 2.00000000, -2.00000000, -0.67032784, + -0.00920582, 0.64892756, 2.00000000, -2.00000000, -0.68561894, + 0.03641869, 0.73021611, 1.68293863, -4.00000000, -2.72024184, + -1.80096059, -0.81696185, 0.03604685, 0.79232033, 1.70070730, + 3.00000000, -4.00000000, -2.71795670, -1.80482986, -0.86001162, + 0.03764903, 0.87723968, 1.79970771, 2.72685932, 3.67589143, + -5.00000000, -4.00000000, -2.85492548, -1.78996365, -0.83250358, + -0.01376828, 0.84195506, 1.78161105, 2.76754458, 4.00000000, + -6.00000000, -5.00000000, -3.82268811, -2.77563624, -1.82608163, + -0.86486114, -0.02671886, 0.86693165, 1.88422879, 2.86248347, + 3.95632216, -7.00000000, -6.00000000, -5.00000000, -3.77533988, + -2.86391432, -1.87052039, -0.90513658, 0.06271236, 0.91083620, + 1.85734756, 2.86031688, 3.82019418, 4.94420394, 6.00000000, + -11.00000000,-10.00000000, -9.00000000, -8.00000000, -6.91952415, + -6.00000000, -4.92044374, -3.87845165, -2.87392362, -1.88413020, + -0.91915740, 0.00318517, 0.91602800, 1.89664838, 2.88925058, + 3.84123856, 4.78988651, 5.94526812, 6.81953917, 8.00000000, + -9.00000000, -8.00000000, -7.03319143, -5.94530963, -4.86669720, + -3.92438007, -2.88620396, -1.92848070, -0.94365985, 0.01671855, + 0.97349410, 1.93419878, 2.89740109, 3.89662823, 4.83235583, + 5.88106535, 6.80328232, 8.00000000,-13.00000000,-12.00000000, + -11.00000000,-10.00000000, -9.00000000, -7.86033489, -6.83344055, + -5.89844215, -4.90811454, -3.94841298, -2.95820490, -1.98627966, + -0.99161468, -0.02286136, 0.96055651, 1.95052433, 2.93969396, + 3.94304346, 4.88522624, 5.87434241, 6.78309433, 7.87244101, + 9.00000000, 10.00000000,-12.09117356,-11.00000000,-10.00000000, + -8.84766108, -7.86934236, -6.98544896, -5.94233429, -4.95583292, + -3.95575986, -2.97085529, -1.98955811, -0.99359873, -0.00485413, + 0.98298870, 1.98093258, 2.96430203, 3.95540216, 4.96915010, + 5.96775124, 6.99236918, 7.96503302, 8.99864542, 9.85857723, + 10.96541926, 11.91647197, 12.71060069,-26.00000000,-25.00000000, + -24.00585596,-23.11642573,-22.14271284,-20.89800711,-19.87815799, + -19.05036354,-17.88555651,-16.86471209,-15.97711073,-14.94012359, + -14.02661226,-12.98243228,-11.97489256,-10.97402777, -9.96425624, + -9.01085220, -7.97372506, -6.98795002, -5.97271328, -5.00191694, + -3.98055849, -2.98458048, -1.99470442, -0.99656768, -0.00825666, + 1.00272004, 1.99922218, 2.99357669, 4.01407905, 5.01003897, + 5.98115528, 7.00018958, 8.00338125, 8.98981046, 9.98990318, + 10.96341479, 11.96866930, 12.99175139, 13.94580443, 14.95745083, + 15.98992869, 16.97484646, 17.99630043, 18.93396897, 19.88347741, + 20.96532482, 21.92191032, 23.22314702 }; + + +/* cdf tables for quantizer indices */ +const WebRtc_UWord16 WebRtcIsac_kQKltCdfGain[404] = { + 0, 13, 301, 3730, 61784, 65167, 65489, 65535, 0, 17, + 142, 314, 929, 2466, 7678, 56450, 63463, 64740, 65204, 65426, + 65527, 65535, 0, 8, 100, 724, 6301, 60105, 65125, 65510, + 65531, 65535, 0, 13, 117, 368, 1068, 3010, 11928, 53603, + 61177, 63404, 64505, 65108, 65422, 65502, 65531, 65535, 0, 4, + 17, 96, 410, 1859, 12125, 54361, 64103, 65305, 65497, 65535, + 0, 4, 88, 230, 469, 950, 1746, 3228, 6092, 16592, + 44756, 56848, 61256, 63308, 64325, 64920, 65309, 65460, 65502, + 65522, 65535, 0, 88, 352, 1675, 6339, 20749, 46686, 59284, 63525, + 64949, 65359, 65502, 65527, 65535, 0, 13, 38, 63, 117, + 234, 381, 641, 929, 1407, 2043, 2809, 4032, 5753, 8792, + 14407, 24308, 38941, 48947, 55403, 59293, 61411, 62688, 63630, + 64329, 64840, 65188, 65376, 65472, 65506, 65527, 65531, 65535, + 0, 8, 29, 75, 222, 615, 1327, 2801, 5623, 9931, 16094, 24966, + 34419, 43458, 50676, 56186, 60055, 62500, 63936, 64765, 65225, + 65435, 65514, 65535, 0, 8, 13, 15, 17, 21, 33, 59, + 71, 92, 151, 243, 360, 456, 674, 934, 1223, 1583, + 1989, 2504, 3031, 3617, 4354, 5154, 6163, 7411, 8780, 10747, + 12874, 15591, 18974, 23027, 27436, 32020, 36948, 41830, 46205, + 49797, 53042, 56094, 58418, 60360, 61763, 62818, 63559, 64103, + 64509, 64798, 65045, 65162, 65288, 65363, 65447, 65506, 65522, + 65531, 65533, 65535, 0, 4, 6, 25, 38, 71, 138, 264, 519, 808, + 1227, 1825, 2516, 3408, 4279, 5560, 7092, 9197, 11420, 14108, + 16947, 20300, 23926, 27459, 31164, 34827, 38575, 42178, 45540, + 48747, 51444, 54090, 56426, 58460, 60080, 61595, 62734, 63668, + 64275, 64673, 64936, 65112, 65217, 65334, 65426, 65464, 65477, + 65489, 65518, 65527, 65529, 65531, 65533, 65535, 0, 2, 4, 8, 10, + 12, 14, 16, 21, 33, 50, 71, 84, 92, 105, 138, 180, 255, 318, + 377, 435, 473, 511, 590, 682, 758, 913, 1097, 1256, 1449, 1671, + 1884, 2169, 2445, 2772, 3157, 3563, 3944, 4375, 4848, 5334, 5820, + 6448, 7101, 7716, 8378, 9102, 9956, 10752, 11648, 12707, 13670, + 14758, 15910, 17187, 18472, 19627, 20649, 21951, 23169, 24283, + 25552, 26862, 28227, 29391, 30764, 31882, 33213, 34432, 35600, + 36910, 38116, 39464, 40729, 41872, 43144, 44371, 45514, 46762, + 47813, 48968, 50069, 51032, 51974, 52908, 53737, 54603, 55445, + 56282, 56990, 57572, 58191, 58840, 59410, 59887, 60264, 60607, + 60946, 61269, 61516, 61771, 61960, 62198, 62408, 62558, 62776, + 62985, 63207, 63408, 63546, 63739, 63906, 64070, 64237, 64371, + 64551, 64677, 64836, 64999, 65095, 65213, 65284, 65338, 65380, + 65426, 65447, 65472, 65485, 65487, 65489, 65502, 65510, 65512, + 65514, 65516, 65518, 65522, 65531, 65533, 65535 }; + + +const WebRtc_UWord16 WebRtcIsac_kQKltCdfShape[686] = { + 0, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 65535, + 0, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 4, + 65535, 0, 8, 65514, 65535, 0, 29, 65481, 65535, 0, + 121, 65439, 65535, 0, 239, 65284, 65535, 0, 8, 779, + 64999, 65527, 65535, 0, 8, 888, 64693, 65522, 65535, 0, + 29, 2604, 62843, 65497, 65531, 65535, 0, 25, 176, 4576, + 61164, 65275, 65527, 65535, 0, 65535, 0, 65535, 0, 65535, + 0, 65535, 0, 4, 65535, 0, 65535, 0, 65535, 0, + 65535, 0, 65535, 0, 4, 65535, 0, 33, 65502, 65535, + 0, 54, 65481, 65535, 0, 251, 65309, 65535, 0, 611, + 65074, 65535, 0, 1273, 64292, 65527, 65535, 0, 4, 1809, + 63940, 65518, 65535, 0, 88, 4392, 60603, 65426, 65531, 65535, + 0, 25, 419, 7046, 57756, 64961, 65514, 65531, 65535, 0, + 65535, 0, 65535, 0, 65535, 0, 65535, 0, 4, 65531, + 65535, 0, 65535, 0, 8, 65531, 65535, 0, 4, 65527, + 65535, 0, 17, 65510, 65535, 0, 42, 65481, 65535, 0, + 197, 65342, 65531, 65535, 0, 385, 65154, 65535, 0, 1005, + 64522, 65535, 0, 8, 1985, 63469, 65533, 65535, 0, 38, + 3119, 61884, 65514, 65535, 0, 4, 6, 67, 4961, 60804, + 65472, 65535, 0, 17, 565, 9182, 56538, 65087, 65514, 65535, + 0, 8, 63, 327, 2118, 14490, 52774, 63839, 65376, 65522, + 65535, 0, 65535, 0, 65535, 0, 65535, 0, 65535, 0, + 17, 65522, 65535, 0, 59, 65489, 65535, 0, 50, 65522, + 65535, 0, 54, 65489, 65535, 0, 310, 65179, 65535, 0, + 615, 64836, 65535, 0, 4, 1503, 63965, 65535, 0, 2780, + 63383, 65535, 0, 21, 3919, 61051, 65527, 65535, 0, 84, + 6674, 59929, 65435, 65535, 0, 4, 255, 7976, 55784, 65150, + 65518, 65531, 65535, 0, 4, 8, 582, 10726, 53465, 64949, + 65518, 65535, 0, 29, 339, 3006, 17555, 49517, 62956, 65200, + 65497, 65531, 65535, 0, 2, 33, 138, 565, 2324, 7670, + 22089, 45966, 58949, 63479, 64966, 65380, 65518, 65535, 0, 65535, + 0, 65535, 0, 2, 65533, 65535, 0, 46, 65514, 65535, + 0, 414, 65091, 65535, 0, 540, 64911, 65535, 0, 419, + 65162, 65535, 0, 976, 64790, 65535, 0, 2977, 62495, 65531, + 65535, 0, 4, 3852, 61034, 65527, 65535, 0, 4, 29, + 6021, 60243, 65468, 65535, 0, 84, 6711, 58066, 65418, 65535, + 0, 13, 281, 9550, 54917, 65125, 65506, 65535, 0, 2, + 63, 984, 12108, 52644, 64342, 65435, 65527, 65535, 0, 29, + 251, 2014, 14871, 47553, 62881, 65229, 65518, 65535, 0, 13, + 142, 749, 4220, 18497, 45200, 60913, 64823, 65426, 65527, 65535, + 0, 13, 71, 264, 1176, 3789, 10500, 24480, 43488, 56324, + 62315, 64493, 65242, 65464, 65514, 65522, 65531, 65535, 0, 4, + 13, 38, 109, 205, 448, 850, 1708, 3429, 6276, 11371, + 19221, 29734, 40955, 49391, 55411, 59460, 62102, 63793, 64656, + 65150, 65401, 65485, 65522, 65531, 65535, 0, 65535, 0, 2, 65533, + 65535, 0, 1160, 65476, 65535, 0, 2, 6640, 64763, 65533, + 65535, 0, 2, 38, 9923, 61009, 65527, 65535, 0, 2, + 4949, 63092, 65533, 65535, 0, 2, 3090, 63398, 65533, 65535, + 0, 2, 2520, 58744, 65510, 65535, 0, 2, 13, 544, + 8784, 51403, 65148, 65533, 65535, 0, 2, 25, 1017, 10412, + 43550, 63651, 65489, 65527, 65535, 0, 2, 4, 29, 783, + 13377, 52462, 64524, 65495, 65533, 65535, 0, 2, 4, 6, + 100, 1817, 18451, 52590, 63559, 65376, 65531, 65535, 0, 2, + 4, 6, 46, 385, 2562, 11225, 37416, 60488, 65026, 65487, + 65529, 65533, 65535, 0, 2, 4, 6, 8, 10, 12, + 42, 222, 971, 5221, 19811, 45048, 60312, 64486, 65294, 65474, + 65525, 65529, 65533, 65535, 0, 2, 4, 8, 71, 167, + 666, 2533, 7875, 19622, 38082, 54359, 62108, 64633, 65290, 65495, + 65529, 65533, 65535, 0, 2, 4, 6, 8, 10, 13, + 109, 586, 1930, 4949, 11600, 22641, 36125, 48312, 56899, 61495, + 63927, 64932, 65389, 65489, 65518, 65531, 65533, 65535, 0, 4, + 6, 8, 67, 209, 712, 1838, 4195, 8432, 14432, 22834, + 31723, 40523, 48139, 53929, 57865, 60657, 62403, 63584, 64363, + 64907, 65167, 65372, 65472, 65514, 65535, 0, 2, 4, 13, 25, + 42, 46, 50, 75, 113, 147, 281, 448, 657, 909, + 1185, 1591, 1976, 2600, 3676, 5317, 7398, 9914, 12941, 16169, + 19477, 22885, 26464, 29851, 33360, 37228, 41139, 44802, 48654, + 52058, 55181, 57676, 59581, 61022, 62190, 63107, 63676, 64199, + 64547, 64924, 65158, 65313, 65430, 65481, 65518, 65535 }; + + +/* pointers to cdf tables for quantizer indices */ +const WebRtc_UWord16 *WebRtcIsac_kQKltCdfPtrGain[12] = { + WebRtcIsac_kQKltCdfGain +0 +0, WebRtcIsac_kQKltCdfGain +0 +8, + WebRtcIsac_kQKltCdfGain +0 +22, WebRtcIsac_kQKltCdfGain +0 +32, + WebRtcIsac_kQKltCdfGain +0 +48, WebRtcIsac_kQKltCdfGain +0 +60, + WebRtcIsac_kQKltCdfGain +0 +81, WebRtcIsac_kQKltCdfGain +0 +95, + WebRtcIsac_kQKltCdfGain +0 +128, WebRtcIsac_kQKltCdfGain +0 +152, + WebRtcIsac_kQKltCdfGain +0 +210, WebRtcIsac_kQKltCdfGain +0 +264 }; + +const WebRtc_UWord16 *WebRtcIsac_kQKltCdfPtrShape[108] = { + WebRtcIsac_kQKltCdfShape +0 +0, WebRtcIsac_kQKltCdfShape +0 +2, + WebRtcIsac_kQKltCdfShape +0 +4, WebRtcIsac_kQKltCdfShape +0 +6, + WebRtcIsac_kQKltCdfShape +0 +8, WebRtcIsac_kQKltCdfShape +0 +10, + WebRtcIsac_kQKltCdfShape +0 +12, WebRtcIsac_kQKltCdfShape +0 +14, + WebRtcIsac_kQKltCdfShape +0 +16, WebRtcIsac_kQKltCdfShape +0 +18, + WebRtcIsac_kQKltCdfShape +0 +21, WebRtcIsac_kQKltCdfShape +0 +25, + WebRtcIsac_kQKltCdfShape +0 +29, WebRtcIsac_kQKltCdfShape +0 +33, + WebRtcIsac_kQKltCdfShape +0 +37, WebRtcIsac_kQKltCdfShape +0 +43, + WebRtcIsac_kQKltCdfShape +0 +49, WebRtcIsac_kQKltCdfShape +0 +56, + WebRtcIsac_kQKltCdfShape +0 +64, WebRtcIsac_kQKltCdfShape +0 +66, + WebRtcIsac_kQKltCdfShape +0 +68, WebRtcIsac_kQKltCdfShape +0 +70, + WebRtcIsac_kQKltCdfShape +0 +72, WebRtcIsac_kQKltCdfShape +0 +75, + WebRtcIsac_kQKltCdfShape +0 +77, WebRtcIsac_kQKltCdfShape +0 +79, + WebRtcIsac_kQKltCdfShape +0 +81, WebRtcIsac_kQKltCdfShape +0 +83, + WebRtcIsac_kQKltCdfShape +0 +86, WebRtcIsac_kQKltCdfShape +0 +90, + WebRtcIsac_kQKltCdfShape +0 +94, WebRtcIsac_kQKltCdfShape +0 +98, + WebRtcIsac_kQKltCdfShape +0 +102, WebRtcIsac_kQKltCdfShape +0 +107, + WebRtcIsac_kQKltCdfShape +0 +113, WebRtcIsac_kQKltCdfShape +0 +120, + WebRtcIsac_kQKltCdfShape +0 +129, WebRtcIsac_kQKltCdfShape +0 +131, + WebRtcIsac_kQKltCdfShape +0 +133, WebRtcIsac_kQKltCdfShape +0 +135, + WebRtcIsac_kQKltCdfShape +0 +137, WebRtcIsac_kQKltCdfShape +0 +141, + WebRtcIsac_kQKltCdfShape +0 +143, WebRtcIsac_kQKltCdfShape +0 +147, + WebRtcIsac_kQKltCdfShape +0 +151, WebRtcIsac_kQKltCdfShape +0 +155, + WebRtcIsac_kQKltCdfShape +0 +159, WebRtcIsac_kQKltCdfShape +0 +164, + WebRtcIsac_kQKltCdfShape +0 +168, WebRtcIsac_kQKltCdfShape +0 +172, + WebRtcIsac_kQKltCdfShape +0 +178, WebRtcIsac_kQKltCdfShape +0 +184, + WebRtcIsac_kQKltCdfShape +0 +192, WebRtcIsac_kQKltCdfShape +0 +200, + WebRtcIsac_kQKltCdfShape +0 +211, WebRtcIsac_kQKltCdfShape +0 +213, + WebRtcIsac_kQKltCdfShape +0 +215, WebRtcIsac_kQKltCdfShape +0 +217, + WebRtcIsac_kQKltCdfShape +0 +219, WebRtcIsac_kQKltCdfShape +0 +223, + WebRtcIsac_kQKltCdfShape +0 +227, WebRtcIsac_kQKltCdfShape +0 +231, + WebRtcIsac_kQKltCdfShape +0 +235, WebRtcIsac_kQKltCdfShape +0 +239, + WebRtcIsac_kQKltCdfShape +0 +243, WebRtcIsac_kQKltCdfShape +0 +248, + WebRtcIsac_kQKltCdfShape +0 +252, WebRtcIsac_kQKltCdfShape +0 +258, + WebRtcIsac_kQKltCdfShape +0 +264, WebRtcIsac_kQKltCdfShape +0 +273, + WebRtcIsac_kQKltCdfShape +0 +282, WebRtcIsac_kQKltCdfShape +0 +293, + WebRtcIsac_kQKltCdfShape +0 +308, WebRtcIsac_kQKltCdfShape +0 +310, + WebRtcIsac_kQKltCdfShape +0 +312, WebRtcIsac_kQKltCdfShape +0 +316, + WebRtcIsac_kQKltCdfShape +0 +320, WebRtcIsac_kQKltCdfShape +0 +324, + WebRtcIsac_kQKltCdfShape +0 +328, WebRtcIsac_kQKltCdfShape +0 +332, + WebRtcIsac_kQKltCdfShape +0 +336, WebRtcIsac_kQKltCdfShape +0 +341, + WebRtcIsac_kQKltCdfShape +0 +347, WebRtcIsac_kQKltCdfShape +0 +354, + WebRtcIsac_kQKltCdfShape +0 +360, WebRtcIsac_kQKltCdfShape +0 +368, + WebRtcIsac_kQKltCdfShape +0 +378, WebRtcIsac_kQKltCdfShape +0 +388, + WebRtcIsac_kQKltCdfShape +0 +400, WebRtcIsac_kQKltCdfShape +0 +418, + WebRtcIsac_kQKltCdfShape +0 +445, WebRtcIsac_kQKltCdfShape +0 +447, + WebRtcIsac_kQKltCdfShape +0 +451, WebRtcIsac_kQKltCdfShape +0 +455, + WebRtcIsac_kQKltCdfShape +0 +461, WebRtcIsac_kQKltCdfShape +0 +468, + WebRtcIsac_kQKltCdfShape +0 +474, WebRtcIsac_kQKltCdfShape +0 +480, + WebRtcIsac_kQKltCdfShape +0 +486, WebRtcIsac_kQKltCdfShape +0 +495, + WebRtcIsac_kQKltCdfShape +0 +505, WebRtcIsac_kQKltCdfShape +0 +516, + WebRtcIsac_kQKltCdfShape +0 +528, WebRtcIsac_kQKltCdfShape +0 +543, + WebRtcIsac_kQKltCdfShape +0 +564, WebRtcIsac_kQKltCdfShape +0 +583, + WebRtcIsac_kQKltCdfShape +0 +608, WebRtcIsac_kQKltCdfShape +0 +635 }; + + +/* left KLT transforms */ +const double WebRtcIsac_kKltT1Gain[4] = { + -0.79742827, 0.60341375, 0.60341375, 0.79742827 }; + +const double WebRtcIsac_kKltT1Shape[324] = { + 0.00159597, 0.00049320, 0.00513821, 0.00021066, 0.01338581, + -0.00422367, -0.00272072, 0.00935107, 0.02047622, 0.02691189, + 0.00478236, 0.03969702, 0.00886698, 0.04877604, -0.10898362, + -0.05930891, -0.03415047, 0.98889721, 0.00293558, -0.00035282, + 0.01156321, -0.00195341, -0.00937631, 0.01052213, -0.02551163, + 0.01644059, 0.03189927, 0.07754773, -0.08742313, -0.03026338, + 0.05136248, -0.14395974, 0.17725040, 0.22664856, 0.93380230, + 0.07076411, 0.00557890, -0.00222834, 0.01377569, 0.01466808, + 0.02847361, -0.00603178, 0.02382480, -0.01210452, 0.03797267, + -0.02371480, 0.11260335, -0.07366682, 0.00453436, -0.04136941, + -0.07912843, -0.95031418, 0.25295337, -0.05302216, -0.00617554, + -0.00044040, -0.00653778, 0.01097838, 0.01529174, 0.01374431, + -0.00748512, -0.00020034, 0.02432713, 0.11101570, -0.08556891, + 0.09282249, -0.01029446, 0.67556443, -0.67454300, 0.06910063, + 0.20866865, -0.10318050, 0.00932175, 0.00524058, 0.00803610, + -0.00594676, -0.01082578, 0.01069906, 0.00546768, 0.01565291, + 0.06816200, 0.10201227, 0.16812734, 0.22984074, 0.58213170, + -0.54138651, -0.51379962, 0.06847390, -0.01920037, -0.04592324, + -0.00467394, 0.00328858, 0.00377424, -0.00987448, 0.08222096, + -0.00377301, 0.04551941, -0.02592517, 0.16317082, 0.13077530, + 0.22702921, -0.31215289, -0.69645962, -0.38047101, -0.39339411, + 0.11124777, 0.02508035, -0.00708074, 0.00400344, 0.00040331, + 0.01142402, 0.01725406, 0.01635170, 0.14285366, 0.03949233, + -0.05905676, 0.05877154, -0.17497577, -0.32479440, 0.80754464, + -0.38085603, -0.17055430, -0.03168622, -0.07531451, 0.02942002, + -0.02148095, -0.00754114, -0.00322372, 0.00567812, -0.01701521, + -0.12358320, 0.11473564, 0.09070136, 0.06533068, -0.22560802, + 0.19209022, 0.81605094, 0.36592275, -0.09919829, 0.16667122, + 0.16300725, 0.04803807, 0.06739263, -0.00156752, -0.01685302, + -0.00905240, -0.02297836, -0.00469939, 0.06310613, -0.16391930, + 0.10919511, 0.12529293, 0.85581322, -0.32145522, 0.24539076, + 0.07181839, 0.07289591, 0.14066759, 0.10406711, 0.05815518, + 0.01072680, -0.00759339, 0.00053486, -0.00044865, 0.03407361, + 0.01645348, 0.08758579, 0.27722240, 0.53665485, -0.74853376, + -0.01118192, -0.19805430, 0.06130619, -0.09675299, 0.08978480, + 0.03405255, -0.00706867, 0.05102045, 0.03250746, 0.01849966, + -0.01216314, -0.01184187, -0.01579288, 0.00114807, 0.11376166, + 0.88342114, -0.36425379, 0.13863190, 0.12524180, -0.13553892, + 0.04715856, -0.12341103, 0.04531568, 0.01899360, -0.00206897, + 0.00567768, -0.01444163, 0.00411946, -0.00855896, 0.00381663, + -0.01664861, -0.05534280, 0.21328278, 0.20161162, 0.72360394, + 0.59130708, -0.08043791, 0.08757349, -0.13893918, -0.05147377, + 0.02680690, -0.01144070, 0.00625162, -0.00634215, -0.01248947, + -0.00329455, -0.00609625, -0.00136305, -0.05097048, -0.01029851, + 0.25065384, -0.16856837, -0.07123372, 0.15992623, -0.39487617, + -0.79972301, 0.18118185, -0.04826639, -0.01805578, -0.02927253, + -0.16400618, 0.07472763, 0.10376449, 0.01705406, 0.01065801, + -0.01500498, 0.02039914, 0.37776349, -0.84484186, 0.10434286, + 0.15616990, 0.13474456, -0.00906238, -0.25238368, -0.03820885, + -0.10650905, -0.03880833, -0.03660028, -0.09640894, 0.00583314, + 0.01922097, 0.01489911, -0.02431117, -0.09372217, 0.39404721, + -0.84786223, -0.31277121, 0.03193850, 0.01974060, 0.01887901, + 0.00337911, -0.11359599, -0.02792521, -0.03220184, -0.01533311, + 0.00015962, -0.04225043, -0.00933965, 0.00675311, 0.00206060, + 0.15926771, 0.40199829, -0.80792558, -0.35591604, -0.17169764, + 0.02830436, 0.02459982, -0.03438589, 0.00718705, -0.01798329, + -0.01594508, -0.00702430, -0.00952419, -0.00962701, -0.01307212, + -0.01749740, 0.01299602, 0.00587270, -0.36103108, -0.82039266, + -0.43092844, -0.08500097, -0.04361674, -0.00333482, 0.01250434, + -0.02538295, -0.00921797, 0.01645071, -0.01400872, 0.00317607, + 0.00003277, -0.01617646, -0.00616863, -0.00882661, 0.00466157, + 0.00353237, 0.91803104, -0.39503305, -0.02048964, 0.00060125, + 0.01980634, 0.00300109, 0.00313880, 0.00657337, 0.00715163, + 0.00000261, 0.00854276, -0.00154825, -0.00516128, 0.00909527, + 0.00095609, 0.00701196, -0.00221867, -0.00156741 }; + +/* right KLT transforms */ +const double WebRtcIsac_kKltT2Gain[36] = { + 0.14572837, -0.45446306, 0.61990621, -0.52197033, 0.32145074, + -0.11026900, -0.20698282, 0.48962182, -0.27127933, -0.33627476, + 0.65094037, -0.32715751, 0.40262573, -0.47844405, -0.33876075, + 0.44130653, 0.37383966, -0.39964662, -0.51730480, 0.06611973, + 0.49030187, 0.47512886, -0.02141226, -0.51129451, -0.58578569, + -0.39132064, -0.13187771, 0.15649421, 0.40735596, 0.54396897, + 0.40381276, 0.40904942, 0.41179766, 0.41167576, 0.40840251, + 0.40468132 }; + +const double WebRtcIsac_kKltT2Shape[36] = { + 0.13427386, -0.35132558, 0.52506528, -0.59419077, 0.45075085, + -0.16312057, 0.29857439, -0.58660147, 0.34265431, 0.20879510, + -0.56063262, 0.30238345, 0.43308283, -0.41186999, -0.35288681, + 0.42768996, 0.36094634, -0.45284910, -0.47116680, 0.02893449, + 0.54326135, 0.45249040, -0.06264420, -0.52283830, 0.57137758, + 0.44298139, 0.12617554, -0.20819946, -0.42324603, -0.48876443, + 0.39597050, 0.40713935, 0.41389880, 0.41512486, 0.41130400, + 0.40575001 }; + +/* means of log gains and LAR coefficients*/ +const double WebRtcIsac_kLpcMeansGain[12] = { + -6.86881911, -5.35075273, -6.86792680, -5.36200897, -6.86401538, + -5.36921533, -6.86802969, -5.36893966, -6.86538097, -5.36315063, + -6.85535304, -5.35155315 }; + +const double WebRtcIsac_kLpcMeansShape[108] = { + -0.91232981, 0.26258634, -0.33716701, 0.08477430, -0.03378426, + 0.14423909, 0.07036185, 0.06155019, 0.01490385, 0.04138740, + 0.01427317, 0.01288970, 0.83872106, 0.25750199, 0.07988929, + -0.01957923, 0.00831390, 0.01770300, -0.90957164, 0.25732216, + -0.33385344, 0.08735740, -0.03715332, 0.14584917, 0.06998990, + 0.06131968, 0.01504379, 0.04067339, 0.01428039, 0.01406460, + 0.83846243, 0.26169862, 0.08109025, -0.01767055, 0.00970539, + 0.01954310, -0.90490803, 0.24656405, -0.33578607, 0.08843286, + -0.03749139, 0.14443959, 0.07214669, 0.06170993, 0.01449947, + 0.04134309, 0.01314762, 0.01413471, 0.83895203, 0.26748062, + 0.08197507, -0.01781298, 0.00885967, 0.01922394, -0.90922472, + 0.24495889, -0.33921540, 0.08877169, -0.03581332, 0.14199172, + 0.07444032, 0.06185940, 0.01502054, 0.04185113, 0.01276579, + 0.01355457, 0.83645358, 0.26631720, 0.08119697, -0.01835449, + 0.00788512, 0.01846446, -0.90482253, 0.24658310, -0.34019734, + 0.08281090, -0.03486038, 0.14359248, 0.07401336, 0.06001471, + 0.01528421, 0.04254560, 0.01321472, 0.01240799, 0.83857127, + 0.26281654, 0.08174380, -0.02099842, 0.00755176, 0.01699448, + -0.90132307, 0.25174308, -0.33838268, 0.07883863, -0.02877906, + 0.14105407, 0.07220290, 0.06000352, 0.01684879, 0.04226844, + 0.01331331, 0.01269244, 0.83832138, 0.25467485, 0.08118028, + -0.02120528, 0.00747832, 0.01567212 }; diff --git a/src/modules/audio_coding/codecs/isac/main/source/lpc_tables.h b/src/modules/audio_coding/codecs/isac/main/source/lpc_tables.h new file mode 100644 index 0000000000..c217804fa6 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/lpc_tables.h @@ -0,0 +1,100 @@ +/* + * 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. + */ + +/* + * lpc_tables.h + * + * header file for coding tables for the LPC coefficients + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_TABLES_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_TABLES_H_ + +#include "structs.h" + +#include "settings.h" + +#define KLT_STEPSIZE 1.00000000 +#define KLT_NUM_AVG_GAIN 0 +#define KLT_NUM_AVG_SHAPE 0 +#define KLT_NUM_MODELS 3 +#define LPC_GAIN_SCALE 4.000f +#define LPC_LOBAND_SCALE 2.100f +#define LPC_LOBAND_ORDER ORDERLO +#define LPC_HIBAND_SCALE 0.450f +#define LPC_HIBAND_ORDER ORDERHI +#define LPC_GAIN_ORDER 2 + +#define LPC_SHAPE_ORDER (LPC_LOBAND_ORDER + LPC_HIBAND_ORDER) + +#define KLT_ORDER_GAIN (LPC_GAIN_ORDER * SUBFRAMES) +#define KLT_ORDER_SHAPE (LPC_SHAPE_ORDER * SUBFRAMES) + +/* cdf array for model indicator */ +extern const WebRtc_UWord16 WebRtcIsac_kQKltModelCdf[KLT_NUM_MODELS+1]; + +/* pointer to cdf array for model indicator */ +extern const WebRtc_UWord16 *WebRtcIsac_kQKltModelCdfPtr[1]; + +/* initial cdf index for decoder of model indicator */ +extern const WebRtc_UWord16 WebRtcIsac_kQKltModelInitIndex[1]; + +/* offset to go from rounded value to quantization index */ +extern const short WebRtcIsac_kQKltQuantMinGain[12]; + +extern const short WebRtcIsac_kQKltQuantMinShape[108]; + +/* maximum quantization index */ +extern const WebRtc_UWord16 WebRtcIsac_kQKltMaxIndGain[12]; + +extern const WebRtc_UWord16 WebRtcIsac_kQKltMaxIndShape[108]; + +/* index offset */ +extern const WebRtc_UWord16 WebRtcIsac_kQKltOffsetGain[12]; + +extern const WebRtc_UWord16 WebRtcIsac_kQKltOffsetShape[108]; + +/* initial cdf index for KLT coefficients */ +extern const WebRtc_UWord16 WebRtcIsac_kQKltInitIndexGain[12]; + +extern const WebRtc_UWord16 WebRtcIsac_kQKltInitIndexShape[108]; + +/* quantizer representation levels */ +extern const double WebRtcIsac_kQKltLevelsGain[392]; + +extern const double WebRtcIsac_kQKltLevelsShape[578]; + +/* cdf tables for quantizer indices */ +extern const WebRtc_UWord16 WebRtcIsac_kQKltCdfGain[404]; + +extern const WebRtc_UWord16 WebRtcIsac_kQKltCdfShape[686]; + +/* pointers to cdf tables for quantizer indices */ +extern const WebRtc_UWord16 *WebRtcIsac_kQKltCdfPtrGain[12]; + +extern const WebRtc_UWord16 *WebRtcIsac_kQKltCdfPtrShape[108]; + +/* left KLT transforms */ +extern const double WebRtcIsac_kKltT1Gain[4]; + +extern const double WebRtcIsac_kKltT1Shape[324]; + +/* right KLT transforms */ +extern const double WebRtcIsac_kKltT2Gain[36]; + +extern const double WebRtcIsac_kKltT2Shape[36]; + +/* means of log gains and LAR coefficients */ +extern const double WebRtcIsac_kLpcMeansGain[12]; + +extern const double WebRtcIsac_kLpcMeansShape[108]; + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_TABLES_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/main/source/os_specific_inline.h b/src/modules/audio_coding/codecs/isac/main/source/os_specific_inline.h new file mode 100644 index 0000000000..c469c2ec9c --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/os_specific_inline.h @@ -0,0 +1,42 @@ +/* + * 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. + */ + + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_OS_SPECIFIC_INLINE_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_OS_SPECIFIC_INLINE_H_ + +#include +#include "typedefs.h" + +// TODO(turaj): switch to WEBRTC_POSIX when available +#if defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) +#define WebRtcIsac_lrint lrint +#elif (defined(WEBRTC_ARCH_X86) && defined(WIN32)) +static __inline long int WebRtcIsac_lrint(double x_dbl) { + long int x_int; + + __asm { + fld x_dbl + fistp x_int + }; + + return x_int; +} +#else // Do a slow but correct implementation of lrint + +static __inline long int WebRtcIsac_lrint(double x_dbl) { + long int x_int; + x_int = (long int)floor(x_dbl + 0.499999999999); + return x_int; +} + +#endif + +#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_OS_SPECIFIC_INLINE_H_ diff --git a/src/modules/audio_coding/codecs/isac/main/source/pitch_estimator.c b/src/modules/audio_coding/codecs/isac/main/source/pitch_estimator.c new file mode 100644 index 0000000000..75525f69d4 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/pitch_estimator.c @@ -0,0 +1,622 @@ +/* + * 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. + */ + +#include "pitch_estimator.h" + +#include +#include +#ifdef WEBRTC_ANDROID +#include +#endif + +static const double kInterpolWin[8] = {-0.00067556028640, 0.02184247643159, -0.12203175715679, 0.60086484101160, + 0.60086484101160, -0.12203175715679, 0.02184247643159, -0.00067556028640}; + +/* interpolation filter */ +__inline static void IntrepolFilter(double *data_ptr, double *intrp) +{ + *intrp = kInterpolWin[0] * data_ptr[-3]; + *intrp += kInterpolWin[1] * data_ptr[-2]; + *intrp += kInterpolWin[2] * data_ptr[-1]; + *intrp += kInterpolWin[3] * data_ptr[0]; + *intrp += kInterpolWin[4] * data_ptr[1]; + *intrp += kInterpolWin[5] * data_ptr[2]; + *intrp += kInterpolWin[6] * data_ptr[3]; + *intrp += kInterpolWin[7] * data_ptr[4]; +} + + +/* 2D parabolic interpolation */ +/* probably some 0.5 factors can be eliminated, and the square-roots can be removed from the Cholesky fact. */ +__inline static void Intrpol2D(double T[3][3], double *x, double *y, double *peak_val) +{ + double c, b[2], A[2][2]; + double t1, t2, d; + double delta1, delta2; + + + // double T[3][3] = {{-1.25, -.25,-.25}, {-.25, .75, .75}, {-.25, .75, .75}}; + // should result in: delta1 = 0.5; delta2 = 0.0; peak_val = 1.0 + + c = T[1][1]; + b[0] = 0.5 * (T[1][2] + T[2][1] - T[0][1] - T[1][0]); + b[1] = 0.5 * (T[1][0] + T[2][1] - T[0][1] - T[1][2]); + A[0][1] = -0.5 * (T[0][1] + T[2][1] - T[1][0] - T[1][2]); + t1 = 0.5 * (T[0][0] + T[2][2]) - c; + t2 = 0.5 * (T[2][0] + T[0][2]) - c; + d = (T[0][1] + T[1][2] + T[1][0] + T[2][1]) - 4.0 * c - t1 - t2; + A[0][0] = -t1 - 0.5 * d; + A[1][1] = -t2 - 0.5 * d; + + /* deal with singularities or ill-conditioned cases */ + if ( (A[0][0] < 1e-7) || ((A[0][0] * A[1][1] - A[0][1] * A[0][1]) < 1e-7) ) { + *peak_val = T[1][1]; + return; + } + + /* Cholesky decomposition: replace A by upper-triangular factor */ + A[0][0] = sqrt(A[0][0]); + A[0][1] = A[0][1] / A[0][0]; + A[1][1] = sqrt(A[1][1] - A[0][1] * A[0][1]); + + /* compute [x; y] = -0.5 * inv(A) * b */ + t1 = b[0] / A[0][0]; + t2 = (b[1] - t1 * A[0][1]) / A[1][1]; + delta2 = t2 / A[1][1]; + delta1 = 0.5 * (t1 - delta2 * A[0][1]) / A[0][0]; + delta2 *= 0.5; + + /* limit norm */ + t1 = delta1 * delta1 + delta2 * delta2; + if (t1 > 1.0) { + delta1 /= t1; + delta2 /= t1; + } + + *peak_val = 0.5 * (b[0] * delta1 + b[1] * delta2) + c; + + *x += delta1; + *y += delta2; +} + + +static void PCorr(const double *in, double *outcorr) +{ + double sum, ysum, prod; + const double *x, *inptr; + int k, n; + + //ysum = 1e-6; /* use this with float (i.s.o. double)! */ + ysum = 1e-13; + sum = 0.0; + x = in + PITCH_MAX_LAG/2 + 2; + for (n = 0; n < PITCH_CORR_LEN2; n++) { + ysum += in[n] * in[n]; + sum += x[n] * in[n]; + } + + outcorr += PITCH_LAG_SPAN2 - 1; /* index of last element in array */ + *outcorr = sum / sqrt(ysum); + + for (k = 1; k < PITCH_LAG_SPAN2; k++) { + ysum -= in[k-1] * in[k-1]; + ysum += in[PITCH_CORR_LEN2 + k - 1] * in[PITCH_CORR_LEN2 + k - 1]; + sum = 0.0; + inptr = &in[k]; + prod = x[0] * inptr[0]; + for (n = 1; n < PITCH_CORR_LEN2; n++) { + sum += prod; + prod = x[n] * inptr[n]; + } + sum += prod; + outcorr--; + *outcorr = sum / sqrt(ysum); + } +} + + +void WebRtcIsac_InitializePitch(const double *in, + const double old_lag, + const double old_gain, + PitchAnalysisStruct *State, + double *lags) +{ + double buf_dec[PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2+2]; + double ratio, log_lag, gain_bias; + double bias; + double corrvec1[PITCH_LAG_SPAN2]; + double corrvec2[PITCH_LAG_SPAN2]; + int m, k; + // Allocating 10 extra entries at the begining of the CorrSurf + double corrSurfBuff[10 + (2*PITCH_BW+3)*(PITCH_LAG_SPAN2+4)]; + double* CorrSurf[2*PITCH_BW+3]; + double *CorrSurfPtr1, *CorrSurfPtr2; + double LagWin[3] = {0.2, 0.5, 0.98}; + int ind1, ind2, peaks_ind, peak, max_ind; + int peaks[PITCH_MAX_NUM_PEAKS]; + double adj, gain_tmp; + double corr, corr_max; + double intrp_a, intrp_b, intrp_c, intrp_d; + double peak_vals[PITCH_MAX_NUM_PEAKS]; + double lags1[PITCH_MAX_NUM_PEAKS]; + double lags2[PITCH_MAX_NUM_PEAKS]; + double T[3][3]; + int row; + + for(k = 0; k < 2*PITCH_BW+3; k++) + { + CorrSurf[k] = &corrSurfBuff[10 + k * (PITCH_LAG_SPAN2+4)]; + } + /* reset CorrSurf matrix */ + memset(corrSurfBuff, 0, sizeof(double) * (10 + (2*PITCH_BW+3) * (PITCH_LAG_SPAN2+4))); + + //warnings -DH + max_ind = 0; + peak = 0; + + /* copy old values from state buffer */ + memcpy(buf_dec, State->dec_buffer, sizeof(double) * (PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2)); + + /* decimation; put result after the old values */ + WebRtcIsac_DecimateAllpass(in, State->decimator_state, PITCH_FRAME_LEN, + &buf_dec[PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2]); + + /* low-pass filtering */ + for (k = PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2; k < PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2+2; k++) + buf_dec[k] += 0.75 * buf_dec[k-1] - 0.25 * buf_dec[k-2]; + + /* copy end part back into state buffer */ + memcpy(State->dec_buffer, buf_dec+PITCH_FRAME_LEN/2, sizeof(double) * (PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2)); + + /* compute correlation for first and second half of the frame */ + PCorr(buf_dec, corrvec1); + PCorr(buf_dec + PITCH_CORR_STEP2, corrvec2); + + /* bias towards pitch lag of previous frame */ + log_lag = log(0.5 * old_lag); + gain_bias = 4.0 * old_gain * old_gain; + if (gain_bias > 0.8) gain_bias = 0.8; + for (k = 0; k < PITCH_LAG_SPAN2; k++) + { + ratio = log((double) (k + (PITCH_MIN_LAG/2-2))) - log_lag; + bias = 1.0 + gain_bias * exp(-5.0 * ratio * ratio); + corrvec1[k] *= bias; + } + + /* taper correlation functions */ + for (k = 0; k < 3; k++) { + gain_tmp = LagWin[k]; + corrvec1[k] *= gain_tmp; + corrvec2[k] *= gain_tmp; + corrvec1[PITCH_LAG_SPAN2-1-k] *= gain_tmp; + corrvec2[PITCH_LAG_SPAN2-1-k] *= gain_tmp; + } + + corr_max = 0.0; + /* fill middle row of correlation surface */ + ind1 = 0; + ind2 = 0; + CorrSurfPtr1 = &CorrSurf[PITCH_BW][2]; + for (k = 0; k < PITCH_LAG_SPAN2; k++) { + corr = corrvec1[ind1++] + corrvec2[ind2++]; + CorrSurfPtr1[k] = corr; + if (corr > corr_max) { + corr_max = corr; /* update maximum */ + max_ind = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]); + } + } + /* fill first and last rows of correlation surface */ + ind1 = 0; + ind2 = PITCH_BW; + CorrSurfPtr1 = &CorrSurf[0][2]; + CorrSurfPtr2 = &CorrSurf[2*PITCH_BW][PITCH_BW+2]; + for (k = 0; k < PITCH_LAG_SPAN2-PITCH_BW; k++) { + ratio = ((double) (ind1 + 12)) / ((double) (ind2 + 12)); + adj = 0.2 * ratio * (2.0 - ratio); /* adjustment factor; inverse parabola as a function of ratio */ + corr = adj * (corrvec1[ind1] + corrvec2[ind2]); + CorrSurfPtr1[k] = corr; + if (corr > corr_max) { + corr_max = corr; /* update maximum */ + max_ind = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]); + } + corr = adj * (corrvec1[ind2++] + corrvec2[ind1++]); + CorrSurfPtr2[k] = corr; + if (corr > corr_max) { + corr_max = corr; /* update maximum */ + max_ind = (int)(&CorrSurfPtr2[k] - &CorrSurf[0][0]); + } + } + /* fill second and next to last rows of correlation surface */ + ind1 = 0; + ind2 = PITCH_BW-1; + CorrSurfPtr1 = &CorrSurf[1][2]; + CorrSurfPtr2 = &CorrSurf[2*PITCH_BW-1][PITCH_BW+1]; + for (k = 0; k < PITCH_LAG_SPAN2-PITCH_BW+1; k++) { + ratio = ((double) (ind1 + 12)) / ((double) (ind2 + 12)); + adj = 0.9 * ratio * (2.0 - ratio); /* adjustment factor; inverse parabola as a function of ratio */ + corr = adj * (corrvec1[ind1] + corrvec2[ind2]); + CorrSurfPtr1[k] = corr; + if (corr > corr_max) { + corr_max = corr; /* update maximum */ + max_ind = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]); + } + corr = adj * (corrvec1[ind2++] + corrvec2[ind1++]); + CorrSurfPtr2[k] = corr; + if (corr > corr_max) { + corr_max = corr; /* update maximum */ + max_ind = (int)(&CorrSurfPtr2[k] - &CorrSurf[0][0]); + } + } + /* fill remainder of correlation surface */ + for (m = 2; m < PITCH_BW; m++) { + ind1 = 0; + ind2 = PITCH_BW - m; /* always larger than ind1 */ + CorrSurfPtr1 = &CorrSurf[m][2]; + CorrSurfPtr2 = &CorrSurf[2*PITCH_BW-m][PITCH_BW+2-m]; + for (k = 0; k < PITCH_LAG_SPAN2-PITCH_BW+m; k++) { + ratio = ((double) (ind1 + 12)) / ((double) (ind2 + 12)); + adj = ratio * (2.0 - ratio); /* adjustment factor; inverse parabola as a function of ratio */ + corr = adj * (corrvec1[ind1] + corrvec2[ind2]); + CorrSurfPtr1[k] = corr; + if (corr > corr_max) { + corr_max = corr; /* update maximum */ + max_ind = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]); + } + corr = adj * (corrvec1[ind2++] + corrvec2[ind1++]); + CorrSurfPtr2[k] = corr; + if (corr > corr_max) { + corr_max = corr; /* update maximum */ + max_ind = (int)(&CorrSurfPtr2[k] - &CorrSurf[0][0]); + } + } + } + + /* threshold value to qualify as a peak */ + corr_max *= 0.6; + + peaks_ind = 0; + /* find peaks */ + for (m = 1; m < PITCH_BW+1; m++) { + if (peaks_ind == PITCH_MAX_NUM_PEAKS) break; + CorrSurfPtr1 = &CorrSurf[m][2]; + for (k = 2; k < PITCH_LAG_SPAN2-PITCH_BW-2+m; k++) { + corr = CorrSurfPtr1[k]; + if (corr > corr_max) { + if ( (corr > CorrSurfPtr1[k - (PITCH_LAG_SPAN2+5)]) && (corr > CorrSurfPtr1[k - (PITCH_LAG_SPAN2+4)]) ) { + if ( (corr > CorrSurfPtr1[k + (PITCH_LAG_SPAN2+4)]) && (corr > CorrSurfPtr1[k + (PITCH_LAG_SPAN2+5)]) ) { + /* found a peak; store index into matrix */ + peaks[peaks_ind++] = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]); + if (peaks_ind == PITCH_MAX_NUM_PEAKS) break; + } + } + } + } + } + for (m = PITCH_BW+1; m < 2*PITCH_BW; m++) { + if (peaks_ind == PITCH_MAX_NUM_PEAKS) break; + CorrSurfPtr1 = &CorrSurf[m][2]; + for (k = 2+m-PITCH_BW; k < PITCH_LAG_SPAN2-2; k++) { + corr = CorrSurfPtr1[k]; + if (corr > corr_max) { + if ( (corr > CorrSurfPtr1[k - (PITCH_LAG_SPAN2+5)]) && (corr > CorrSurfPtr1[k - (PITCH_LAG_SPAN2+4)]) ) { + if ( (corr > CorrSurfPtr1[k + (PITCH_LAG_SPAN2+4)]) && (corr > CorrSurfPtr1[k + (PITCH_LAG_SPAN2+5)]) ) { + /* found a peak; store index into matrix */ + peaks[peaks_ind++] = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]); + if (peaks_ind == PITCH_MAX_NUM_PEAKS) break; + } + } + } + } + } + + if (peaks_ind > 0) { + /* examine each peak */ + CorrSurfPtr1 = &CorrSurf[0][0]; + for (k = 0; k < peaks_ind; k++) { + peak = peaks[k]; + + /* compute four interpolated values around current peak */ + IntrepolFilter(&CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+5)], &intrp_a); + IntrepolFilter(&CorrSurfPtr1[peak - 1 ], &intrp_b); + IntrepolFilter(&CorrSurfPtr1[peak ], &intrp_c); + IntrepolFilter(&CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+4)], &intrp_d); + + /* determine maximum of the interpolated values */ + corr = CorrSurfPtr1[peak]; + corr_max = intrp_a; + if (intrp_b > corr_max) corr_max = intrp_b; + if (intrp_c > corr_max) corr_max = intrp_c; + if (intrp_d > corr_max) corr_max = intrp_d; + + /* determine where the peak sits and fill a 3x3 matrix around it */ + row = peak / (PITCH_LAG_SPAN2+4); + lags1[k] = (double) ((peak - row * (PITCH_LAG_SPAN2+4)) + PITCH_MIN_LAG/2 - 4); + lags2[k] = (double) (lags1[k] + PITCH_BW - row); + if ( corr > corr_max ) { + T[0][0] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+5)]; + T[2][0] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+4)]; + T[1][1] = corr; + T[0][2] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+4)]; + T[2][2] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+5)]; + T[1][0] = intrp_a; + T[0][1] = intrp_b; + T[2][1] = intrp_c; + T[1][2] = intrp_d; + } else { + if (intrp_a == corr_max) { + lags1[k] -= 0.5; + lags2[k] += 0.5; + IntrepolFilter(&CorrSurfPtr1[peak - 2*(PITCH_LAG_SPAN2+5)], &T[0][0]); + IntrepolFilter(&CorrSurfPtr1[peak - (2*PITCH_LAG_SPAN2+9)], &T[2][0]); + T[1][1] = intrp_a; + T[0][2] = intrp_b; + T[2][2] = intrp_c; + T[1][0] = CorrSurfPtr1[peak - (2*PITCH_LAG_SPAN2+9)]; + T[0][1] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+5)]; + T[2][1] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+4)]; + T[1][2] = corr; + } else if (intrp_b == corr_max) { + lags1[k] -= 0.5; + lags2[k] -= 0.5; + IntrepolFilter(&CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+6)], &T[0][0]); + T[2][0] = intrp_a; + T[1][1] = intrp_b; + IntrepolFilter(&CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+3)], &T[0][2]); + T[2][2] = intrp_d; + T[1][0] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+5)]; + T[0][1] = CorrSurfPtr1[peak - 1]; + T[2][1] = corr; + T[1][2] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+4)]; + } else if (intrp_c == corr_max) { + lags1[k] += 0.5; + lags2[k] += 0.5; + T[0][0] = intrp_a; + IntrepolFilter(&CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+4)], &T[2][0]); + T[1][1] = intrp_c; + T[0][2] = intrp_d; + IntrepolFilter(&CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+5)], &T[2][2]); + T[1][0] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+4)]; + T[0][1] = corr; + T[2][1] = CorrSurfPtr1[peak + 1]; + T[1][2] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+5)]; + } else { + lags1[k] += 0.5; + lags2[k] -= 0.5; + T[0][0] = intrp_b; + T[2][0] = intrp_c; + T[1][1] = intrp_d; + IntrepolFilter(&CorrSurfPtr1[peak + 2*(PITCH_LAG_SPAN2+4)], &T[0][2]); + IntrepolFilter(&CorrSurfPtr1[peak + (2*PITCH_LAG_SPAN2+9)], &T[2][2]); + T[1][0] = corr; + T[0][1] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+4)]; + T[2][1] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+5)]; + T[1][2] = CorrSurfPtr1[peak + (2*PITCH_LAG_SPAN2+9)]; + } + } + + /* 2D parabolic interpolation gives more accurate lags and peak value */ + Intrpol2D(T, &lags1[k], &lags2[k], &peak_vals[k]); + } + + /* determine the highest peak, after applying a bias towards short lags */ + corr_max = 0.0; + for (k = 0; k < peaks_ind; k++) { + corr = peak_vals[k] * pow(PITCH_PEAK_DECAY, log(lags1[k] + lags2[k])); + if (corr > corr_max) { + corr_max = corr; + peak = k; + } + } + + lags1[peak] *= 2.0; + lags2[peak] *= 2.0; + + if (lags1[peak] < (double) PITCH_MIN_LAG) lags1[peak] = (double) PITCH_MIN_LAG; + if (lags2[peak] < (double) PITCH_MIN_LAG) lags2[peak] = (double) PITCH_MIN_LAG; + if (lags1[peak] > (double) PITCH_MAX_LAG) lags1[peak] = (double) PITCH_MAX_LAG; + if (lags2[peak] > (double) PITCH_MAX_LAG) lags2[peak] = (double) PITCH_MAX_LAG; + + /* store lags of highest peak in output array */ + lags[0] = lags1[peak]; + lags[1] = lags1[peak]; + lags[2] = lags2[peak]; + lags[3] = lags2[peak]; + } + else + { + row = max_ind / (PITCH_LAG_SPAN2+4); + lags1[0] = (double) ((max_ind - row * (PITCH_LAG_SPAN2+4)) + PITCH_MIN_LAG/2 - 4); + lags2[0] = (double) (lags1[0] + PITCH_BW - row); + + if (lags1[0] < (double) PITCH_MIN_LAG) lags1[0] = (double) PITCH_MIN_LAG; + if (lags2[0] < (double) PITCH_MIN_LAG) lags2[0] = (double) PITCH_MIN_LAG; + if (lags1[0] > (double) PITCH_MAX_LAG) lags1[0] = (double) PITCH_MAX_LAG; + if (lags2[0] > (double) PITCH_MAX_LAG) lags2[0] = (double) PITCH_MAX_LAG; + + /* store lags of highest peak in output array */ + lags[0] = lags1[0]; + lags[1] = lags1[0]; + lags[2] = lags2[0]; + lags[3] = lags2[0]; + } +} + + + +/* create weighting matrix by orthogonalizing a basis of polynomials of increasing order + * t = (0:4)'; + * A = [t.^0, t.^1, t.^2, t.^3, t.^4]; + * [Q, dummy] = qr(A); + * P.Weight = Q * diag([0, .1, .5, 1, 1]) * Q'; */ +static const double kWeight[5][5] = { + { 0.29714285714286, -0.30857142857143, -0.05714285714286, 0.05142857142857, 0.01714285714286}, + {-0.30857142857143, 0.67428571428571, -0.27142857142857, -0.14571428571429, 0.05142857142857}, + {-0.05714285714286, -0.27142857142857, 0.65714285714286, -0.27142857142857, -0.05714285714286}, + { 0.05142857142857, -0.14571428571429, -0.27142857142857, 0.67428571428571, -0.30857142857143}, + { 0.01714285714286, 0.05142857142857, -0.05714285714286, -0.30857142857143, 0.29714285714286} +}; + + +void WebRtcIsac_PitchAnalysis(const double *in, /* PITCH_FRAME_LEN samples */ + double *out, /* PITCH_FRAME_LEN+QLOOKAHEAD samples */ + PitchAnalysisStruct *State, + double *lags, + double *gains) +{ + double HPin[PITCH_FRAME_LEN]; + double Weighted[PITCH_FRAME_LEN]; + double Whitened[PITCH_FRAME_LEN + QLOOKAHEAD]; + double inbuf[PITCH_FRAME_LEN + QLOOKAHEAD]; + double out_G[PITCH_FRAME_LEN + QLOOKAHEAD]; // could be removed by using out instead + double out_dG[4][PITCH_FRAME_LEN + QLOOKAHEAD]; + double old_lag, old_gain; + double nrg_wht, tmp; + double Wnrg, Wfluct, Wgain; + double H[4][4]; + double grad[4]; + double dG[4]; + int k, m, n, iter; + + /* high pass filtering using second order pole-zero filter */ + WebRtcIsac_Highpass(in, HPin, State->hp_state, PITCH_FRAME_LEN); + + /* copy from state into buffer */ + memcpy(Whitened, State->whitened_buf, sizeof(double) * QLOOKAHEAD); + + /* compute weighted and whitened signals */ + WebRtcIsac_WeightingFilter(HPin, &Weighted[0], &Whitened[QLOOKAHEAD], &(State->Wghtstr)); + + /* copy from buffer into state */ + memcpy(State->whitened_buf, Whitened+PITCH_FRAME_LEN, sizeof(double) * QLOOKAHEAD); + + old_lag = State->PFstr_wght.oldlagp[0]; + old_gain = State->PFstr_wght.oldgainp[0]; + + /* inital pitch estimate */ + WebRtcIsac_InitializePitch(Weighted, old_lag, old_gain, State, lags); + + + /* Iterative optimization of lags - to be done */ + + /* compute energy of whitened signal */ + nrg_wht = 0.0; + for (k = 0; k < PITCH_FRAME_LEN + QLOOKAHEAD; k++) + nrg_wht += Whitened[k] * Whitened[k]; + + + /* Iterative optimization of gains */ + + /* set weights for energy, gain fluctiation, and spectral gain penalty functions */ + Wnrg = 1.0 / nrg_wht; + Wgain = 0.005; + Wfluct = 3.0; + + /* set initial gains */ + for (k = 0; k < 4; k++) + gains[k] = PITCH_MAX_GAIN_06; + + /* two iterations should be enough */ + for (iter = 0; iter < 2; iter++) { + /* compute Jacobian of pre-filter output towards gains */ + WebRtcIsac_PitchfilterPre_gains(Whitened, out_G, out_dG, &(State->PFstr_wght), lags, gains); + + /* gradient and approximate Hessian (lower triangle) for minimizing the filter's output power */ + for (k = 0; k < 4; k++) { + tmp = 0.0; + for (n = 0; n < PITCH_FRAME_LEN + QLOOKAHEAD; n++) + tmp += out_G[n] * out_dG[k][n]; + grad[k] = tmp * Wnrg; + } + for (k = 0; k < 4; k++) { + for (m = 0; m <= k; m++) { + tmp = 0.0; + for (n = 0; n < PITCH_FRAME_LEN + QLOOKAHEAD; n++) + tmp += out_dG[m][n] * out_dG[k][n]; + H[k][m] = tmp * Wnrg; + } + } + + /* add gradient and Hessian (lower triangle) for dampening fast gain changes */ + for (k = 0; k < 4; k++) { + tmp = kWeight[k+1][0] * old_gain; + for (m = 0; m < 4; m++) + tmp += kWeight[k+1][m+1] * gains[m]; + grad[k] += tmp * Wfluct; + } + for (k = 0; k < 4; k++) { + for (m = 0; m <= k; m++) { + H[k][m] += kWeight[k+1][m+1] * Wfluct; + } + } + + /* add gradient and Hessian for dampening gain */ + for (k = 0; k < 3; k++) { + tmp = 1.0 / (1 - gains[k]); + grad[k] += tmp * tmp * Wgain; + H[k][k] += 2.0 * tmp * (tmp * tmp * Wgain); + } + tmp = 1.0 / (1 - gains[3]); + grad[3] += 1.33 * (tmp * tmp * Wgain); + H[3][3] += 2.66 * tmp * (tmp * tmp * Wgain); + + + /* compute Cholesky factorization of Hessian + * by overwritting the upper triangle; scale factors on diagonal + * (for non pc-platforms store the inverse of the diagonals seperately to minimize divisions) */ + H[0][1] = H[1][0] / H[0][0]; + H[0][2] = H[2][0] / H[0][0]; + H[0][3] = H[3][0] / H[0][0]; + H[1][1] -= H[0][0] * H[0][1] * H[0][1]; + H[1][2] = (H[2][1] - H[0][1] * H[2][0]) / H[1][1]; + H[1][3] = (H[3][1] - H[0][1] * H[3][0]) / H[1][1]; + H[2][2] -= H[0][0] * H[0][2] * H[0][2] + H[1][1] * H[1][2] * H[1][2]; + H[2][3] = (H[3][2] - H[0][2] * H[3][0] - H[1][2] * H[1][1] * H[1][3]) / H[2][2]; + H[3][3] -= H[0][0] * H[0][3] * H[0][3] + H[1][1] * H[1][3] * H[1][3] + H[2][2] * H[2][3] * H[2][3]; + + /* Compute update as delta_gains = -inv(H) * grad */ + /* copy and negate */ + for (k = 0; k < 4; k++) + dG[k] = -grad[k]; + /* back substitution */ + dG[1] -= dG[0] * H[0][1]; + dG[2] -= dG[0] * H[0][2] + dG[1] * H[1][2]; + dG[3] -= dG[0] * H[0][3] + dG[1] * H[1][3] + dG[2] * H[2][3]; + /* scale */ + for (k = 0; k < 4; k++) + dG[k] /= H[k][k]; + /* back substitution */ + dG[2] -= dG[3] * H[2][3]; + dG[1] -= dG[3] * H[1][3] + dG[2] * H[1][2]; + dG[0] -= dG[3] * H[0][3] + dG[2] * H[0][2] + dG[1] * H[0][1]; + + /* update gains and check range */ + for (k = 0; k < 4; k++) { + gains[k] += dG[k]; + if (gains[k] > PITCH_MAX_GAIN) + gains[k] = PITCH_MAX_GAIN; + else if (gains[k] < 0.0) + gains[k] = 0.0; + } + } + + /* update state for next frame */ + WebRtcIsac_PitchfilterPre(Whitened, out, &(State->PFstr_wght), lags, gains); + + /* concatenate previous input's end and current input */ + memcpy(inbuf, State->inbuf, sizeof(double) * QLOOKAHEAD); + memcpy(inbuf+QLOOKAHEAD, in, sizeof(double) * PITCH_FRAME_LEN); + + /* lookahead pitch filtering for masking analysis */ + WebRtcIsac_PitchfilterPre_la(inbuf, out, &(State->PFstr), lags, gains); + + /* store last part of input */ + for (k = 0; k < QLOOKAHEAD; k++) + State->inbuf[k] = inbuf[k + PITCH_FRAME_LEN]; +} diff --git a/src/modules/audio_coding/codecs/isac/main/source/pitch_estimator.h b/src/modules/audio_coding/codecs/isac/main/source/pitch_estimator.h new file mode 100644 index 0000000000..f5d93564be --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/pitch_estimator.h @@ -0,0 +1,71 @@ +/* + * 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. + */ + +/* + * pitch_estimator.h + * + * Pitch functions + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_ + +#include "structs.h" + + + +void WebRtcIsac_PitchAnalysis(const double *in, /* PITCH_FRAME_LEN samples */ + double *out, /* PITCH_FRAME_LEN+QLOOKAHEAD samples */ + PitchAnalysisStruct *State, + double *lags, + double *gains); + +void WebRtcIsac_InitializePitch(const double *in, + const double old_lag, + const double old_gain, + PitchAnalysisStruct *State, + double *lags); + +void WebRtcIsac_PitchfilterPre(double *indat, + double *outdat, + PitchFiltstr *pfp, + double *lags, + double *gains); + +void WebRtcIsac_PitchfilterPost(double *indat, + double *outdat, + PitchFiltstr *pfp, + double *lags, + double *gains); + +void WebRtcIsac_PitchfilterPre_la(double *indat, + double *outdat, + PitchFiltstr *pfp, + double *lags, + double *gains); + +void WebRtcIsac_PitchfilterPre_gains(double *indat, + double *outdat, + double out_dG[][PITCH_FRAME_LEN + QLOOKAHEAD], + PitchFiltstr *pfp, + double *lags, + double *gains); + +void WebRtcIsac_WeightingFilter(const double *in, double *weiout, double *whiout, WeightFiltstr *wfdata); + +void WebRtcIsac_Highpass(const double *in, double *out, double *state, int N); + +void WebRtcIsac_DecimateAllpass(const double *in, + double *state_in, /* array of size: 2*ALLPASSSECTIONS+1 */ + int N, /* number of input samples */ + double *out); /* array of size N/2 */ + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/main/source/pitch_filter.c b/src/modules/audio_coding/codecs/isac/main/source/pitch_filter.c new file mode 100644 index 0000000000..f03d230e65 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/pitch_filter.c @@ -0,0 +1,383 @@ +/* + * 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. + */ + +#include "pitch_estimator.h" + +#include +#include +#include + +#include "os_specific_inline.h" + +/* + * We are implementing the following filters; + * + * Pre-filtering: + * y(z) = x(z) + damper(z) * gain * (x(z) + y(z)) * z ^ (-lag); + * + * Post-filtering: + * y(z) = x(z) - damper(z) * gain * (x(z) + y(z)) * z ^ (-lag); + * + * Note that |lag| is a floating number so we perform an interpolation to + * obtain the correct |lag|. + * + */ + +static const double kDampFilter[PITCH_DAMPORDER] = {-0.07, 0.25, 0.64, 0.25, + -0.07}; + +/* interpolation coefficients; generated by design_pitch_filter.m */ +static const double kIntrpCoef[PITCH_FRACS][PITCH_FRACORDER] = { + {-0.02239172458614, 0.06653315052934, -0.16515880017569, 0.60701333734125, + 0.64671399919202, -0.20249000396417, 0.09926548334755, -0.04765933793109, + 0.01754159521746}, + {-0.01985640750434, 0.05816126837866, -0.13991265473714, 0.44560418147643, + 0.79117042386876, -0.20266133815188, 0.09585268418555, -0.04533310458084, + 0.01654127246314}, + {-0.01463300534216, 0.04229888475060, -0.09897034715253, 0.28284326017787, + 0.90385267956632, -0.16976950138649, 0.07704272393639, -0.03584218578311, + 0.01295781500709}, + {-0.00764851320885, 0.02184035544377, -0.04985561057281, 0.13083306574393, + 0.97545011664662, -0.10177807997561, 0.04400901776474, -0.02010737175166, + 0.00719783432422}, + {-0.00000000000000, 0.00000000000000, -0.00000000000001, 0.00000000000001, + 0.99999999999999, 0.00000000000001, -0.00000000000001, 0.00000000000000, + -0.00000000000000}, + {0.00719783432422, -0.02010737175166, 0.04400901776474, -0.10177807997562, + 0.97545011664663, 0.13083306574393, -0.04985561057280, 0.02184035544377, + -0.00764851320885}, + {0.01295781500710, -0.03584218578312, 0.07704272393640, -0.16976950138650, + 0.90385267956634, 0.28284326017785, -0.09897034715252, 0.04229888475059, + -0.01463300534216}, + {0.01654127246315, -0.04533310458085, 0.09585268418557, -0.20266133815190, + 0.79117042386878, 0.44560418147640, -0.13991265473712, 0.05816126837865, + -0.01985640750433} +}; + +/* + * Enumerating the operation of the filter. + * iSAC has 4 different pitch-filter which are very similar in their structure. + * + * kPitchFilterPre : In this mode the filter is operating as pitch + * pre-filter. This is used at the encoder. + * kPitchFilterPost : In this mode the filter is operating as pitch + * post-filter. This is the inverse of pre-filter and used + * in the decoder. + * kPitchFilterPreLa : This is, in structure, similar to pre-filtering but + * utilizing 3 millisecond lookahead. It is used to + * obtain the signal for LPC analysis. + * kPitchFilterPreGain : This is, in structure, similar to pre-filtering but + * differential changes in gain is considered. This is + * used to find the optimal gain. + */ +typedef enum { + kPitchFilterPre, kPitchFilterPost, kPitchFilterPreLa, kPitchFilterPreGain +} PitchFilterOperation; + +/* + * Structure with parameters used for pitch-filtering. + * buffer : a buffer where the sum of previous inputs and outputs + * are stored. + * damper_state : the state of the damping filter. The filter is defined by + * |kDampFilter|. + * interpol_coeff : pointer to a set of coefficient which are used to utilize + * fractional pitch by interpolation. + * gain : pitch-gain to be applied to the current segment of input. + * lag : pitch-lag for the current segment of input. + * lag_offset : the offset of lag w.r.t. current sample. + * sub_frame : sub-frame index, there are 4 pitch sub-frames in an iSAC + * frame. + * This specifies the usage of the filter. See + * 'PitchFilterOperation' for operational modes. + * num_samples : number of samples to be processed in each segment. + * index : index of the input and output sample. + * damper_state_dg : state of damping filter for different trial gains. + * gain_mult : differential changes to gain. + */ +typedef struct { + double buffer[PITCH_INTBUFFSIZE + QLOOKAHEAD]; + double damper_state[PITCH_DAMPORDER]; + const double *interpol_coeff; + double gain; + double lag; + int lag_offset; + + int sub_frame; + PitchFilterOperation mode; + int num_samples; + int index; + + double damper_state_dg[4][PITCH_DAMPORDER]; + double gain_mult[4]; +} PitchFilterParam; + +/********************************************************************** + * FilterSegment() + * Filter one segment, a quarter of a frame. + * + * Inputs + * in_data : pointer to the input signal of 30 ms at 8 kHz sample-rate. + * filter_param : pitch filter parameters. + * + * Outputs + * out_data : pointer to a buffer where the filtered signal is written to. + * out_dg : [only used in kPitchFilterPreGain] pointer to a buffer + * where the output of different gain values (differential + * change to gain) is written. + */ +static void FilterSegment(const double* in_data, PitchFilterParam* parameters, + double* out_data, + double out_dg[][PITCH_FRAME_LEN + QLOOKAHEAD]) { + int n; + int m; + int j; + double sum; + double sum2; + /* Index of |parameters->buffer| where the output is written to. */ + int pos = parameters->index + PITCH_BUFFSIZE; + /* Index of |parameters->buffer| where samples are read for fractional-lag + * computation. */ + int pos_lag = pos - parameters->lag_offset; + + for (n = 0; n < parameters->num_samples; ++n) { + /* Shift low pass filter states. */ + for (m = PITCH_DAMPORDER - 1; m > 0; --m) { + parameters->damper_state[m] = parameters->damper_state[m - 1]; + } + /* Filter to get fractional pitch. */ + sum = 0.0; + for (m = 0; m < PITCH_FRACORDER; ++m) { + sum += parameters->buffer[pos_lag + m] * parameters->interpol_coeff[m]; + } + /* Multiply with gain. */ + parameters->damper_state[0] = parameters->gain * sum; + + if (parameters->mode == kPitchFilterPreGain) { + int lag_index = parameters->index - parameters->lag_offset; + int m_tmp = (lag_index < 0) ? -lag_index : 0; + /* Update the damper state for the new sample. */ + for (m = PITCH_DAMPORDER - 1; m > 0; --m) { + for (j = 0; j < 4; ++j) { + parameters->damper_state_dg[j][m] = + parameters->damper_state_dg[j][m - 1]; + } + } + + for (j = 0; j < parameters->sub_frame + 1; ++j) { + /* Filter for fractional pitch. */ + sum2 = 0.0; + for (m = PITCH_FRACORDER-1; m >= m_tmp; --m) { + /* |lag_index + m| is always larger than or equal to zero, see how + * m_tmp is computed. This is equivalent to assume samples outside + * |out_dg[j]| are zero. */ + sum2 += out_dg[j][lag_index + m] * parameters->interpol_coeff[m]; + } + /* Add the contribution of differential gain change. */ + parameters->damper_state_dg[j][0] = parameters->gain_mult[j] * sum + + parameters->gain * sum2; + } + + /* Filter with damping filter, and store the results. */ + for (j = 0; j < parameters->sub_frame + 1; ++j) { + sum = 0.0; + for (m = 0; m < PITCH_DAMPORDER; ++m) { + sum -= parameters->damper_state_dg[j][m] * kDampFilter[m]; + } + out_dg[j][parameters->index] = sum; + } + } + /* Filter with damping filter. */ + sum = 0.0; + for (m = 0; m < PITCH_DAMPORDER; ++m) { + sum += parameters->damper_state[m] * kDampFilter[m]; + } + + /* Subtract from input and update buffer. */ + out_data[parameters->index] = in_data[parameters->index] - sum; + parameters->buffer[pos] = in_data[parameters->index] + + out_data[parameters->index]; + + ++parameters->index; + ++pos; + ++pos_lag; + } + return; +} + +/* Update filter parameters based on the pitch-gains and pitch-lags. */ +static void Update(PitchFilterParam* parameters) { + double fraction; + int fraction_index; + /* Compute integer lag-offset. */ + parameters->lag_offset = WebRtcIsac_lrint(parameters->lag + PITCH_FILTDELAY + + 0.5); + /* Find correct set of coefficients for computing fractional pitch. */ + fraction = parameters->lag_offset - (parameters->lag + PITCH_FILTDELAY); + fraction_index = WebRtcIsac_lrint(PITCH_FRACS * fraction - 0.5); + parameters->interpol_coeff = kIntrpCoef[fraction_index]; + + if (parameters->mode == kPitchFilterPreGain) { + /* If in this mode make a differential change to pitch gain. */ + parameters->gain_mult[parameters->sub_frame] += 0.2; + if (parameters->gain_mult[parameters->sub_frame] > 1.0) { + parameters->gain_mult[parameters->sub_frame] = 1.0; + } + if (parameters->sub_frame > 0) { + parameters->gain_mult[parameters->sub_frame - 1] -= 0.2; + } + } +} + +/****************************************************************************** + * FilterFrame() + * Filter a frame of 30 millisecond, given pitch-lags and pitch-gains. + * + * Inputs + * in_data : pointer to the input signal of 30 ms at 8 kHz sample-rate. + * lags : pointer to pitch-lags, 4 lags per frame. + * gains : pointer to pitch-gians, 4 gains per frame. + * mode : defining the functionality of the filter. It takes the + * following values. + * kPitchFilterPre: Pitch pre-filter, used at encoder. + * kPitchFilterPost: Pitch post-filter, used at decoder. + * kPitchFilterPreLa: Pitch pre-filter with lookahead. + * kPitchFilterPreGain: Pitch pre-filter used to otain optimal + * pitch-gains. + * + * Outputs + * out_data : pointer to a buffer where the filtered signal is written to. + * out_dg : [only used in kPitchFilterPreGain] pointer to a buffer + * where the output of different gain values (differential + * change to gain) is written. + */ +static void FilterFrame(const double* in_data, PitchFiltstr* filter_state, + double* lags, double* gains, PitchFilterOperation mode, + double* out_data, + double out_dg[][PITCH_FRAME_LEN + QLOOKAHEAD]) { + PitchFilterParam filter_parameters; + double gain_delta, lag_delta; + double old_lag, old_gain; + int n; + int m; + const double kEnhancer = 1.3; + + /* Set up buffer and states. */ + filter_parameters.index = 0; + filter_parameters.lag_offset = 0; + filter_parameters.mode = mode; + /* Copy states to local variables. */ + memcpy(filter_parameters.buffer, filter_state->ubuf, + sizeof(filter_state->ubuf)); + memcpy(filter_parameters.damper_state, filter_state->ystate, + sizeof(filter_state->ystate)); + + if (mode == kPitchFilterPreGain) { + /* Clear buffers. */ + memset(filter_parameters.gain_mult, 0, sizeof(filter_parameters.gain_mult)); + memset(filter_parameters.damper_state_dg, 0, + sizeof(filter_parameters.damper_state_dg)); + for (n = 0; n < PITCH_SUBFRAMES; ++n) { + //memset(out_dg[n], 0, sizeof(double) * (PITCH_FRAME_LEN + QLOOKAHEAD)); + memset(out_dg[n], 0, sizeof(out_dg[n])); + } + } else if (mode == kPitchFilterPost) { + /* Make output more periodic. Negative sign is to change the structure + * of the filter. */ + for (n = 0; n < PITCH_SUBFRAMES; ++n) { + gains[n] *= -kEnhancer; + } + } + + old_lag = *filter_state->oldlagp; + old_gain = *filter_state->oldgainp; + + /* No interpolation if pitch lag step is big. */ + if ((lags[0] > (PITCH_UPSTEP * old_lag)) || + (lags[0] < (PITCH_DOWNSTEP * old_lag))) { + old_lag = lags[0]; + old_gain = gains[0]; + + if (mode == kPitchFilterPreGain) { + filter_parameters.gain_mult[0] = 1.0; + } + } + + filter_parameters.num_samples = PITCH_UPDATE; + for (m = 0; m < PITCH_SUBFRAMES; ++m) { + /* Set the sub-frame value. */ + filter_parameters.sub_frame = m; + /* Calculate interpolation steps for pitch-lag and pitch-gain. */ + lag_delta = (lags[m] - old_lag) / PITCH_GRAN_PER_SUBFRAME; + filter_parameters.lag = old_lag; + gain_delta = (gains[m] - old_gain) / PITCH_GRAN_PER_SUBFRAME; + filter_parameters.gain = old_gain; + /* Store for the next sub-frame. */ + old_lag = lags[m]; + old_gain = gains[m]; + + for (n = 0; n < PITCH_GRAN_PER_SUBFRAME; ++n) { + /* Step-wise interpolation of pitch gains and lags. As pitch-lag changes, + * some parameters of filter need to be update. */ + filter_parameters.gain += gain_delta; + filter_parameters.lag += lag_delta; + /* Update parameters according to new lag value. */ + Update(&filter_parameters); + /* Filter a segment of input. */ + FilterSegment(in_data, &filter_parameters, out_data, out_dg); + } + } + + if (mode != kPitchFilterPreGain) { + /* Export buffer and states. */ + memcpy(filter_state->ubuf, &filter_parameters.buffer[PITCH_FRAME_LEN], + sizeof(filter_state->ubuf)); + memcpy(filter_state->ystate, filter_parameters.damper_state, + sizeof(filter_state->ystate)); + + /* Store for the next frame. */ + *filter_state->oldlagp = old_lag; + *filter_state->oldgainp = old_gain; + } + + if ((mode == kPitchFilterPreGain) || (mode == kPitchFilterPreLa)) { + /* Filter the lookahead segment, this is treated as the last sub-frame. So + * set |pf_param| to last sub-frame. */ + filter_parameters.sub_frame = PITCH_SUBFRAMES - 1; + filter_parameters.num_samples = QLOOKAHEAD; + FilterSegment(in_data, &filter_parameters, out_data, out_dg); + } +} + +void WebRtcIsac_PitchfilterPre(double* in_data, double* out_data, + PitchFiltstr* pf_state, double* lags, + double* gains) { + FilterFrame(in_data, pf_state, lags, gains, kPitchFilterPre, out_data, NULL); +} + +void WebRtcIsac_PitchfilterPre_la(double* in_data, double* out_data, + PitchFiltstr* pf_state, double* lags, + double* gains) { + FilterFrame(in_data, pf_state, lags, gains, kPitchFilterPreLa, out_data, + NULL); +} + +void WebRtcIsac_PitchfilterPre_gains( + double* in_data, double* out_data, + double out_dg[][PITCH_FRAME_LEN + QLOOKAHEAD], PitchFiltstr *pf_state, + double* lags, double* gains) { + FilterFrame(in_data, pf_state, lags, gains, kPitchFilterPreGain, out_data, + out_dg); +} + +void WebRtcIsac_PitchfilterPost(double* in_data, double* out_data, + PitchFiltstr* pf_state, double* lags, + double* gains) { + FilterFrame(in_data, pf_state, lags, gains, kPitchFilterPost, out_data, NULL); +} diff --git a/src/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.c b/src/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.c new file mode 100644 index 0000000000..5d998a2928 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.c @@ -0,0 +1,105 @@ +/* + * 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. + */ + +#include "pitch_gain_tables.h" + +#include "settings.h" + +/* header file for coding tables for the pitch filter side-info in the entropy coder */ +/********************* Pitch Filter Gain Coefficient Tables ************************/ +/* cdf for quantized pitch filter gains */ +const WebRtc_UWord16 WebRtcIsac_kQPitchGainCdf[255] = { + 0, 2, 4, 6, 64, 901, 903, 905, 16954, 16956, + 16961, 17360, 17362, 17364, 17366, 17368, 17370, 17372, 17374, 17411, + 17514, 17516, 17583, 18790, 18796, 18802, 20760, 20777, 20782, 21722, + 21724, 21728, 21738, 21740, 21742, 21744, 21746, 21748, 22224, 22227, + 22230, 23214, 23229, 23239, 25086, 25108, 25120, 26088, 26094, 26098, + 26175, 26177, 26179, 26181, 26183, 26185, 26484, 26507, 26522, 27705, + 27731, 27750, 29767, 29799, 29817, 30866, 30883, 30885, 31025, 31029, + 31031, 31033, 31035, 31037, 31114, 31126, 31134, 32687, 32722, 32767, + 35718, 35742, 35757, 36943, 36952, 36954, 37115, 37128, 37130, 37132, + 37134, 37136, 37143, 37145, 37152, 38843, 38863, 38897, 47458, 47467, + 47474, 49040, 49061, 49063, 49145, 49157, 49159, 49161, 49163, 49165, + 49167, 49169, 49171, 49757, 49770, 49782, 61333, 61344, 61346, 62860, + 62883, 62885, 62887, 62889, 62891, 62893, 62895, 62897, 62899, 62901, + 62903, 62905, 62907, 62909, 65496, 65498, 65500, 65521, 65523, 65525, + 65527, 65529, 65531, 65533, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535}; + +/* index limits and ranges */ +const WebRtc_Word16 WebRtcIsac_kIndexLowerLimitGain[3] = { + -7, -2, -1}; + +const WebRtc_Word16 WebRtcIsac_kIndexUpperLimitGain[3] = { + 0, 3, 1}; + +const WebRtc_UWord16 WebRtcIsac_kIndexMultsGain[2] = { + 18, 3}; + +/* size of cdf table */ +const WebRtc_UWord16 WebRtcIsac_kQCdfTableSizeGain[1] = { + 256}; + +///////////////////////////FIXED POINT +/* mean values of pitch filter gains in FIXED point */ +const WebRtc_Word16 WebRtcIsac_kQMeanGain1Q12[144] = { + 843, 1092, 1336, 1222, 1405, 1656, 1500, 1815, 1843, 1838, 1839, 1843, 1843, 1843, 1843, 1843, + 1843, 1843, 814, 846, 1092, 1013, 1174, 1383, 1391, 1511, 1584, 1734, 1753, 1843, 1843, 1843, + 1843, 1843, 1843, 1843, 524, 689, 777, 845, 947, 1069, 1090, 1263, 1380, 1447, 1559, 1676, + 1645, 1749, 1843, 1843, 1843, 1843, 81, 477, 563, 611, 706, 806, 849, 1012, 1192, 1128, + 1330, 1489, 1425, 1576, 1826, 1741, 1843, 1843, 0, 290, 305, 356, 488, 575, 602, 741, + 890, 835, 1079, 1196, 1182, 1376, 1519, 1506, 1680, 1843, 0, 47, 97, 69, 289, 381, + 385, 474, 617, 664, 803, 1079, 935, 1160, 1269, 1265, 1506, 1741, 0, 0, 0, 0, + 112, 120, 190, 283, 442, 343, 526, 809, 684, 935, 1134, 1020, 1265, 1506, 0, 0, + 0, 0, 0, 0, 0, 111, 256, 87, 373, 597, 430, 684, 935, 770, 1020, 1265}; + +const WebRtc_Word16 WebRtcIsac_kQMeanGain2Q12[144] = { + 1760, 1525, 1285, 1747, 1671, 1393, 1843, 1826, 1555, 1843, 1784, 1606, 1843, 1843, 1711, 1843, + 1843, 1814, 1389, 1275, 1040, 1564, 1414, 1252, 1610, 1495, 1343, 1753, 1592, 1405, 1804, 1720, + 1475, 1843, 1814, 1581, 1208, 1061, 856, 1349, 1148, 994, 1390, 1253, 1111, 1495, 1343, 1178, + 1770, 1465, 1234, 1814, 1581, 1342, 1040, 793, 713, 1053, 895, 737, 1128, 1003, 861, 1277, + 1094, 981, 1475, 1192, 1019, 1581, 1342, 1098, 855, 570, 483, 833, 648, 540, 948, 744, + 572, 1009, 844, 636, 1234, 934, 685, 1342, 1217, 984, 537, 318, 124, 603, 423, 350, + 687, 479, 322, 791, 581, 430, 987, 671, 488, 1098, 849, 597, 283, 27, 0, 397, + 222, 38, 513, 271, 124, 624, 325, 157, 737, 484, 233, 849, 597, 343, 27, 0, + 0, 141, 0, 0, 256, 69, 0, 370, 87, 0, 484, 229, 0, 597, 343, 87}; + +const WebRtc_Word16 WebRtcIsac_kQMeanGain3Q12[144] = { + 1843, 1843, 1711, 1843, 1818, 1606, 1843, 1827, 1511, 1814, 1639, 1393, 1760, 1525, 1285, 1656, + 1419, 1176, 1835, 1718, 1475, 1841, 1650, 1387, 1648, 1498, 1287, 1600, 1411, 1176, 1522, 1299, + 1040, 1419, 1176, 928, 1773, 1461, 1128, 1532, 1355, 1202, 1429, 1260, 1115, 1398, 1151, 1025, + 1172, 1080, 790, 1176, 928, 677, 1475, 1147, 1019, 1276, 1096, 922, 1214, 1010, 901, 1057, + 893, 800, 1040, 796, 734, 928, 677, 424, 1137, 897, 753, 1120, 830, 710, 875, 751, + 601, 795, 642, 583, 790, 544, 475, 677, 474, 140, 987, 750, 482, 697, 573, 450, + 691, 487, 303, 661, 394, 332, 537, 303, 220, 424, 168, 0, 737, 484, 229, 624, + 348, 153, 441, 261, 136, 397, 166, 51, 283, 27, 0, 168, 0, 0, 484, 229, + 0, 370, 57, 0, 256, 43, 0, 141, 0, 0, 27, 0, 0, 0, 0, 0}; + + +const WebRtc_Word16 WebRtcIsac_kQMeanGain4Q12[144] = { + 1843, 1843, 1843, 1843, 1841, 1843, 1500, 1821, 1843, 1222, 1434, 1656, 843, 1092, 1336, 504, + 757, 1007, 1843, 1843, 1843, 1838, 1791, 1843, 1265, 1505, 1599, 965, 1219, 1425, 730, 821, + 1092, 249, 504, 757, 1783, 1819, 1843, 1351, 1567, 1727, 1096, 1268, 1409, 805, 961, 1131, + 444, 670, 843, 0, 249, 504, 1425, 1655, 1743, 1096, 1324, 1448, 822, 1019, 1199, 490, + 704, 867, 81, 450, 555, 0, 0, 249, 1247, 1428, 1530, 881, 1073, 1283, 610, 759, + 939, 278, 464, 645, 0, 200, 270, 0, 0, 0, 935, 1163, 1410, 528, 790, 1068, + 377, 499, 717, 173, 240, 274, 0, 43, 62, 0, 0, 0, 684, 935, 1182, 343, + 551, 735, 161, 262, 423, 0, 55, 27, 0, 0, 0, 0, 0, 0, 430, 684, + 935, 87, 377, 597, 0, 46, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0}; diff --git a/src/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.h b/src/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.h new file mode 100644 index 0000000000..f958f5df45 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/pitch_gain_tables.h @@ -0,0 +1,45 @@ +/* + * 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. + */ + +/* + * pitch_gain_tables.h + * + * This file contains tables for the pitch filter side-info in the entropy coder. + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_GAIN_TABLES_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_GAIN_TABLES_H_ + +#include "typedefs.h" + +/* header file for coding tables for the pitch filter side-info in the entropy coder */ +/********************* Pitch Filter Gain Coefficient Tables ************************/ +/* cdf for quantized pitch filter gains */ +extern const WebRtc_UWord16 WebRtcIsac_kQPitchGainCdf[255]; + +/* index limits and ranges */ +extern const WebRtc_Word16 WebRtcIsac_kIndexLowerLimitGain[3]; + +extern const WebRtc_Word16 WebRtcIsac_kIndexUpperLimitGain[3]; +extern const WebRtc_UWord16 WebRtcIsac_kIndexMultsGain[2]; + +/* mean values of pitch filter gains */ +//(Y) +extern const WebRtc_Word16 WebRtcIsac_kQMeanGain1Q12[144]; +extern const WebRtc_Word16 WebRtcIsac_kQMeanGain2Q12[144]; +extern const WebRtc_Word16 WebRtcIsac_kQMeanGain3Q12[144]; +extern const WebRtc_Word16 WebRtcIsac_kQMeanGain4Q12[144]; +//(Y) + +/* size of cdf table */ +extern const WebRtc_UWord16 WebRtcIsac_kQCdfTableSizeGain[1]; + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_GAIN_TABLES_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.c b/src/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.c new file mode 100644 index 0000000000..72a031e227 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.c @@ -0,0 +1,277 @@ +/* + * 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. + */ + +#include "pitch_lag_tables.h" +#include "settings.h" + +/* header file for coding tables for the pitch filter side-info in the entropy coder */ +/********************* Pitch Filter Gain Coefficient Tables ************************/ + +/* tables for use with small pitch gain */ + +/* cdf for quantized pitch filter lags */ +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf1Lo[127] = { + 0, 134, 336, 549, 778, 998, 1264, 1512, 1777, 2070, + 2423, 2794, 3051, 3361, 3708, 3979, 4315, 4610, 4933, 5269, + 5575, 5896, 6155, 6480, 6816, 7129, 7477, 7764, 8061, 8358, + 8718, 9020, 9390, 9783, 10177, 10543, 10885, 11342, 11795, 12213, + 12680, 13096, 13524, 13919, 14436, 14903, 15349, 15795, 16267, 16734, + 17266, 17697, 18130, 18632, 19080, 19447, 19884, 20315, 20735, 21288, + 21764, 22264, 22723, 23193, 23680, 24111, 24557, 25022, 25537, 26082, + 26543, 27090, 27620, 28139, 28652, 29149, 29634, 30175, 30692, 31273, + 31866, 32506, 33059, 33650, 34296, 34955, 35629, 36295, 36967, 37726, + 38559, 39458, 40364, 41293, 42256, 43215, 44231, 45253, 46274, 47359, + 48482, 49678, 50810, 51853, 53016, 54148, 55235, 56263, 57282, 58363, + 59288, 60179, 61076, 61806, 62474, 63129, 63656, 64160, 64533, 64856, + 65152, 65535, 65535, 65535, 65535, 65535, 65535}; + +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf2Lo[20] = { + 0, 429, 3558, 5861, 8558, 11639, 15210, 19502, 24773, 31983, + 42602, 48567, 52601, 55676, 58160, 60172, 61889, 63235, 65383, 65535}; + +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf3Lo[2] = { + 0, 65535}; + +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf4Lo[10] = { + 0, 2966, 6368, 11182, 19431, 37793, 48532, 55353, 60626, 65535}; + +const WebRtc_UWord16 *WebRtcIsac_kQPitchLagCdfPtrLo[4] = {WebRtcIsac_kQPitchLagCdf1Lo, WebRtcIsac_kQPitchLagCdf2Lo, WebRtcIsac_kQPitchLagCdf3Lo, WebRtcIsac_kQPitchLagCdf4Lo}; + +/* size of first cdf table */ +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdfSizeLo[1] = {128}; + +/* index limits and ranges */ +const WebRtc_Word16 WebRtcIsac_kQIndexLowerLimitLagLo[4] = { +-140, -9, 0, -4}; + +const WebRtc_Word16 WebRtcIsac_kQIndexUpperLimitLagLo[4] = { +-20, 9, 0, 4}; + +/* initial index for arithmetic decoder */ +const WebRtc_UWord16 WebRtcIsac_kQInitIndexLagLo[3] = { + 10, 1, 5}; + +/* mean values of pitch filter lags */ +const double WebRtcIsac_kQMeanLag2Lo[19] = { +-17.21385070, -15.82678944, -14.07123081, -12.03003877, -10.01311864, -8.00794627, -5.91162987, -3.89231876, -1.90220980, -0.01879275, + 1.89144232, 3.88123171, 5.92146992, 7.96435361, 9.98923648, 11.98266347, 13.96101002, 15.74855713, 17.10976611}; + +const double WebRtcIsac_kQMeanLag3Lo[1] = { + 0.00000000}; + +const double WebRtcIsac_kQMeanLag4Lo[9] = { +-7.76246496, -5.92083980, -3.94095226, -1.89502305, 0.03724681, 1.93054221, 3.96443467, 5.91726366, 7.78434291}; + +const double WebRtcIsac_kQPitchLagStepsizeLo = 2.000000; + + +/* tables for use with medium pitch gain */ + +/* cdf for quantized pitch filter lags */ +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf1Mid[255] = { + 0, 28, 61, 88, 121, 149, 233, 331, 475, 559, + 624, 661, 689, 712, 745, 791, 815, 843, 866, 922, + 959, 1024, 1061, 1117, 1178, 1238, 1280, 1350, 1453, 1513, + 1564, 1625, 1671, 1741, 1788, 1904, 2072, 2421, 2626, 2770, + 2840, 2900, 2942, 3012, 3068, 3115, 3147, 3194, 3254, 3319, + 3366, 3520, 3678, 3780, 3850, 3911, 3957, 4032, 4106, 4185, + 4292, 4474, 4683, 4842, 5019, 5191, 5321, 5428, 5540, 5675, + 5763, 5847, 5959, 6127, 6304, 6564, 6839, 7090, 7263, 7421, + 7556, 7728, 7872, 7984, 8142, 8361, 8580, 8743, 8938, 9227, + 9409, 9539, 9674, 9795, 9930, 10060, 10177, 10382, 10614, 10861, + 11038, 11271, 11415, 11629, 11792, 12044, 12193, 12416, 12574, 12821, + 13007, 13235, 13445, 13654, 13901, 14134, 14488, 15000, 15703, 16285, + 16504, 16797, 17086, 17328, 17579, 17807, 17998, 18268, 18538, 18836, + 19087, 19274, 19474, 19716, 19935, 20270, 20833, 21303, 21532, 21741, + 21978, 22207, 22523, 22770, 23054, 23613, 23943, 24204, 24399, 24651, + 24832, 25074, 25270, 25549, 25759, 26015, 26150, 26424, 26713, 27048, + 27342, 27504, 27681, 27854, 28021, 28207, 28412, 28664, 28859, 29064, + 29278, 29548, 29748, 30107, 30377, 30656, 30856, 31164, 31452, 31755, + 32011, 32328, 32626, 32919, 33319, 33789, 34329, 34925, 35396, 35973, + 36443, 36964, 37551, 38156, 38724, 39357, 40023, 40908, 41587, 42602, + 43924, 45037, 45810, 46597, 47421, 48291, 49092, 50051, 51448, 52719, + 53440, 54241, 54944, 55977, 56676, 57299, 57872, 58389, 59059, 59688, + 60237, 60782, 61094, 61573, 61890, 62290, 62658, 63030, 63217, 63454, + 63622, 63882, 64003, 64273, 64427, 64529, 64581, 64697, 64758, 64902, + 65414, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535}; + +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf2Mid[36] = { + 0, 71, 335, 581, 836, 1039, 1323, 1795, 2258, 2608, + 3005, 3591, 4243, 5344, 7163, 10583, 16848, 28078, 49448, 57007, + 60357, 61850, 62837, 63437, 63872, 64188, 64377, 64614, 64774, 64949, + 65039, 65115, 65223, 65360, 65474, 65535}; + +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf3Mid[2] = { + 0, 65535}; + +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf4Mid[20] = { + 0, 28, 246, 459, 667, 1045, 1523, 2337, 4337, 11347, + 44231, 56709, 60781, 62243, 63161, 63969, 64608, 65062, 65502, 65535}; + +const WebRtc_UWord16 *WebRtcIsac_kQPitchLagCdfPtrMid[4] = {WebRtcIsac_kQPitchLagCdf1Mid, WebRtcIsac_kQPitchLagCdf2Mid, WebRtcIsac_kQPitchLagCdf3Mid, WebRtcIsac_kQPitchLagCdf4Mid}; + +/* size of first cdf table */ +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdfSizeMid[1] = {256}; + +/* index limits and ranges */ +const WebRtc_Word16 WebRtcIsac_kQIndexLowerLimitLagMid[4] = { +-280, -17, 0, -9}; + +const WebRtc_Word16 WebRtcIsac_kQIndexUpperLimitLagMid[4] = { +-40, 17, 0, 9}; + +/* initial index for arithmetic decoder */ +const WebRtc_UWord16 WebRtcIsac_kQInitIndexLagMid[3] = { + 18, 1, 10}; + +/* mean values of pitch filter lags */ +const double WebRtcIsac_kQMeanLag2Mid[35] = { +-16.89183900, -15.86949778, -15.05476653, -14.00664348, -13.02793036, -12.07324237, -11.00542532, -10.11250602, -8.90792971, -8.02474753, +-7.00426767, -5.94055287, -4.98251338, -3.91053158, -2.98820425, -1.93524245, -0.92978085, -0.01722509, 0.91317387, 1.92973955, + 2.96908851, 3.93728974, 4.96308471, 5.92244151, 7.08673497, 8.00993708, 9.04656316, 9.98538742, 10.97851694, 11.94772884, + 13.02426166, 14.00039951, 15.01347042, 15.80758023, 16.94086895}; + +const double WebRtcIsac_kQMeanLag3Mid[1] = { + 0.00000000}; + +const double WebRtcIsac_kQMeanLag4Mid[19] = { +-8.60409403, -7.89198395, -7.03450280, -5.86260421, -4.93822322, -3.93078706, -2.91302322, -1.91824007, -0.87003282, 0.02822649, + 0.89951758, 1.87495484, 2.91802604, 3.96874074, 5.06571703, 5.93618227, 7.00520185, 7.88497726, 8.64160364}; + +const double WebRtcIsac_kQPitchLagStepsizeMid = 1.000000; + + +/* tables for use with large pitch gain */ + +/* cdf for quantized pitch filter lags */ +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf1Hi[511] = { + 0, 7, 18, 33, 69, 105, 156, 228, 315, 612, + 680, 691, 709, 724, 735, 738, 742, 746, 749, 753, + 756, 760, 764, 774, 782, 785, 789, 796, 800, 803, + 807, 814, 818, 822, 829, 832, 847, 854, 858, 869, + 876, 883, 898, 908, 934, 977, 1010, 1050, 1060, 1064, + 1075, 1078, 1086, 1089, 1093, 1104, 1111, 1122, 1133, 1136, + 1151, 1162, 1183, 1209, 1252, 1281, 1339, 1364, 1386, 1401, + 1411, 1415, 1426, 1430, 1433, 1440, 1448, 1455, 1462, 1477, + 1487, 1495, 1502, 1506, 1509, 1516, 1524, 1531, 1535, 1542, + 1553, 1556, 1578, 1589, 1611, 1625, 1639, 1643, 1654, 1665, + 1672, 1687, 1694, 1705, 1708, 1719, 1730, 1744, 1752, 1759, + 1791, 1795, 1820, 1867, 1886, 1915, 1936, 1943, 1965, 1987, + 2041, 2099, 2161, 2175, 2200, 2211, 2226, 2233, 2244, 2251, + 2266, 2280, 2287, 2298, 2309, 2316, 2331, 2342, 2356, 2378, + 2403, 2418, 2447, 2497, 2544, 2602, 2863, 2895, 2903, 2935, + 2950, 2971, 3004, 3011, 3018, 3029, 3040, 3062, 3087, 3127, + 3152, 3170, 3199, 3243, 3293, 3322, 3340, 3377, 3402, 3427, + 3474, 3518, 3543, 3579, 3601, 3637, 3659, 3706, 3731, 3760, + 3818, 3847, 3869, 3901, 3920, 3952, 4068, 4169, 4220, 4271, + 4524, 4571, 4604, 4632, 4672, 4730, 4777, 4806, 4857, 4904, + 4951, 5002, 5031, 5060, 5107, 5150, 5212, 5266, 5331, 5382, + 5432, 5490, 5544, 5610, 5700, 5762, 5812, 5874, 5972, 6022, + 6091, 6163, 6232, 6305, 6402, 6540, 6685, 6880, 7090, 7271, + 7379, 7452, 7542, 7625, 7687, 7770, 7843, 7911, 7966, 8024, + 8096, 8190, 8252, 8320, 8411, 8501, 8585, 8639, 8751, 8842, + 8918, 8986, 9066, 9127, 9203, 9269, 9345, 9406, 9464, 9536, + 9612, 9667, 9735, 9844, 9931, 10036, 10119, 10199, 10260, 10358, + 10441, 10514, 10666, 10734, 10872, 10951, 11053, 11125, 11223, 11324, + 11516, 11664, 11737, 11816, 11892, 12008, 12120, 12200, 12280, 12392, + 12490, 12576, 12685, 12812, 12917, 13003, 13108, 13210, 13300, 13384, + 13470, 13579, 13673, 13771, 13879, 13999, 14136, 14201, 14368, 14614, + 14759, 14867, 14958, 15030, 15121, 15189, 15280, 15385, 15461, 15555, + 15653, 15768, 15884, 15971, 16069, 16145, 16210, 16279, 16380, 16463, + 16539, 16615, 16688, 16818, 16919, 17017, 18041, 18338, 18523, 18649, + 18790, 18917, 19047, 19167, 19315, 19460, 19601, 19731, 19858, 20068, + 20173, 20318, 20466, 20625, 20741, 20911, 21045, 21201, 21396, 21588, + 21816, 22022, 22305, 22547, 22786, 23072, 23322, 23600, 23879, 24168, + 24433, 24769, 25120, 25511, 25895, 26289, 26792, 27219, 27683, 28077, + 28566, 29094, 29546, 29977, 30491, 30991, 31573, 32105, 32594, 33173, + 33788, 34497, 35181, 35833, 36488, 37255, 37921, 38645, 39275, 39894, + 40505, 41167, 41790, 42431, 43096, 43723, 44385, 45134, 45858, 46607, + 47349, 48091, 48768, 49405, 49955, 50555, 51167, 51985, 52611, 53078, + 53494, 53965, 54435, 54996, 55601, 56125, 56563, 56838, 57244, 57566, + 57967, 58297, 58771, 59093, 59419, 59647, 59886, 60143, 60461, 60693, + 60917, 61170, 61416, 61634, 61891, 62122, 62310, 62455, 62632, 62839, + 63103, 63436, 63639, 63805, 63906, 64015, 64192, 64355, 64475, 64558, + 64663, 64742, 64811, 64865, 64916, 64956, 64981, 65025, 65068, 65115, + 65195, 65314, 65419, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535}; + +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf2Hi[68] = { + 0, 7, 11, 22, 37, 52, 56, 59, 81, 85, + 89, 96, 115, 130, 137, 152, 170, 181, 193, 200, + 207, 233, 237, 259, 289, 318, 363, 433, 592, 992, + 1607, 3062, 6149, 12206, 25522, 48368, 58223, 61918, 63640, 64584, + 64943, 65098, 65206, 65268, 65294, 65335, 65350, 65372, 65387, 65402, + 65413, 65420, 65428, 65435, 65439, 65450, 65454, 65468, 65472, 65476, + 65483, 65491, 65498, 65505, 65516, 65520, 65528, 65535}; + +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf3Hi[2] = { + 0, 65535}; + +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf4Hi[35] = { + 0, 7, 19, 30, 41, 48, 63, 74, 82, 96, + 122, 152, 215, 330, 701, 2611, 10931, 48106, 61177, 64341, + 65112, 65238, 65309, 65338, 65364, 65379, 65401, 65427, 65453, 65465, + 65476, 65490, 65509, 65528, 65535}; + +const WebRtc_UWord16 *WebRtcIsac_kQPitchLagCdfPtrHi[4] = {WebRtcIsac_kQPitchLagCdf1Hi, WebRtcIsac_kQPitchLagCdf2Hi, WebRtcIsac_kQPitchLagCdf3Hi, WebRtcIsac_kQPitchLagCdf4Hi}; + +/* size of first cdf table */ +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdfSizeHi[1] = {512}; + +/* index limits and ranges */ +const WebRtc_Word16 WebRtcIsac_kQindexLowerLimitLagHi[4] = { +-552, -34, 0, -16}; + +const WebRtc_Word16 WebRtcIsac_kQindexUpperLimitLagHi[4] = { +-80, 32, 0, 17}; + +/* initial index for arithmetic decoder */ +const WebRtc_UWord16 WebRtcIsac_kQInitIndexLagHi[3] = { + 34, 1, 18}; + +/* mean values of pitch filter lags */ +const double WebRtcIsac_kQMeanLag2Hi[67] = { +-17.07263295, -16.50000000, -15.83966081, -15.55613708, -14.96948007, -14.50000000, -14.00000000, -13.48377986, -13.00000000, -12.50000000, +-11.93199636, -11.44530414, -11.04197641, -10.39910301, -10.15202337, -9.51322461, -8.93357741, -8.46456632, -8.10270672, -7.53751847, +-6.98686404, -6.50000000, -6.08463150, -5.46872991, -5.00864717, -4.50163760, -4.01382410, -3.43856708, -2.96898001, -2.46554810, +-1.96861004, -1.47106701, -0.97197237, -0.46561654, -0.00531409, 0.45767857, 0.96777907, 1.47507903, 1.97740425, 2.46695420, + 3.00695774, 3.47167185, 4.02712538, 4.49280007, 5.01087640, 5.48191963, 6.04916550, 6.51511058, 6.97297819, 7.46565499, + 8.01489405, 8.39912001, 8.91819757, 9.50000000, 10.11654065, 10.50000000, 11.03712583, 11.50000000, 12.00000000, 12.38964346, + 12.89466127, 13.43657881, 13.96013840, 14.46279912, 15.00000000, 15.39412269, 15.96662441}; + +const double WebRtcIsac_kQMeanLag3Hi[1] = { + 0.00000000}; + +const double WebRtcIsac_kQMeanLag4Hi[34] = { +-7.98331221, -7.47988769, -7.03626557, -6.52708003, -6.06982173, -5.51856292, -5.05827033, -4.45909878, -3.99125864, -3.45308135, +-3.02328139, -2.47297273, -1.94341995, -1.44699056, -0.93612243, -0.43012406, 0.01120357, 0.44054812, 0.93199883, 1.45669587, + 1.97218322, 2.50187419, 2.98748690, 3.49343202, 4.01660147, 4.50984306, 5.01402683, 5.58936797, 5.91787793, 6.59998900, + 6.85034315, 7.53503316, 7.87711194, 8.53631648}; + +const double WebRtcIsac_kQPitchLagStepsizeHi = 0.500000; + +/* transform matrix */ +const double WebRtcIsac_kTransform[4][4] = { +{-0.50000000, -0.50000000, -0.50000000, -0.50000000}, +{ 0.67082039, 0.22360680, -0.22360680, -0.67082039}, +{ 0.50000000, -0.50000000, -0.50000000, 0.50000000}, +{ 0.22360680, -0.67082039, 0.67082039, -0.22360680}}; + +/* transpose transform matrix */ +const double WebRtcIsac_kTransformTranspose[4][4] = { +{-0.50000000, 0.67082039, 0.50000000, 0.22360680}, +{-0.50000000, 0.22360680, -0.50000000, -0.67082039}, +{-0.50000000, -0.22360680, -0.50000000, 0.67082039}, +{-0.50000000, -0.67082039, 0.50000000, -0.22360680}}; + diff --git a/src/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.h b/src/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.h new file mode 100644 index 0000000000..67b02e5e4d --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/pitch_lag_tables.h @@ -0,0 +1,114 @@ +/* + * 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. + */ + +/* + * pitch_lag_tables.h + * + * This file contains tables for the pitch filter side-info in the entropy coder. + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_LAG_TABLES_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_LAG_TABLES_H_ + +#include "typedefs.h" +/* header file for coding tables for the pitch filter side-info in the entropy coder */ +/********************* Pitch Filter Lag Coefficient Tables ************************/ + +/* tables for use with small pitch gain */ + +/* cdfs for quantized pitch lags */ +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf1Lo[127]; +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf2Lo[20]; +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf3Lo[2]; +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf4Lo[10]; + +extern const WebRtc_UWord16 *WebRtcIsac_kQPitchLagCdfPtrLo[4]; + +/* size of first cdf table */ +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdfSizeLo[1]; + +/* index limits and ranges */ +extern const WebRtc_Word16 WebRtcIsac_kQIndexLowerLimitLagLo[4]; +extern const WebRtc_Word16 WebRtcIsac_kQIndexUpperLimitLagLo[4]; + +/* initial index for arithmetic decoder */ +extern const WebRtc_UWord16 WebRtcIsac_kQInitIndexLagLo[3]; + +/* mean values of pitch filter lags */ +extern const double WebRtcIsac_kQMeanLag2Lo[19]; +extern const double WebRtcIsac_kQMeanLag3Lo[1]; +extern const double WebRtcIsac_kQMeanLag4Lo[9]; + +extern const double WebRtcIsac_kQPitchLagStepsizeLo; + + +/* tables for use with medium pitch gain */ + +/* cdfs for quantized pitch lags */ +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf1Mid[255]; +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf2Mid[36]; +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf3Mid[2]; +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf4Mid[20]; + +extern const WebRtc_UWord16 *WebRtcIsac_kQPitchLagCdfPtrMid[4]; + +/* size of first cdf table */ +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdfSizeMid[1]; + +/* index limits and ranges */ +extern const WebRtc_Word16 WebRtcIsac_kQIndexLowerLimitLagMid[4]; +extern const WebRtc_Word16 WebRtcIsac_kQIndexUpperLimitLagMid[4]; + +/* initial index for arithmetic decoder */ +extern const WebRtc_UWord16 WebRtcIsac_kQInitIndexLagMid[3]; + +/* mean values of pitch filter lags */ +extern const double WebRtcIsac_kQMeanLag2Mid[35]; +extern const double WebRtcIsac_kQMeanLag3Mid[1]; +extern const double WebRtcIsac_kQMeanLag4Mid[19]; + +extern const double WebRtcIsac_kQPitchLagStepsizeMid; + + +/* tables for use with large pitch gain */ + +/* cdfs for quantized pitch lags */ +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf1Hi[511]; +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf2Hi[68]; +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf3Hi[2]; +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf4Hi[35]; + +extern const WebRtc_UWord16 *WebRtcIsac_kQPitchLagCdfPtrHi[4]; + +/* size of first cdf table */ +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdfSizeHi[1]; + +/* index limits and ranges */ +extern const WebRtc_Word16 WebRtcIsac_kQindexLowerLimitLagHi[4]; +extern const WebRtc_Word16 WebRtcIsac_kQindexUpperLimitLagHi[4]; + +/* initial index for arithmetic decoder */ +extern const WebRtc_UWord16 WebRtcIsac_kQInitIndexLagHi[3]; + +/* mean values of pitch filter lags */ +extern const double WebRtcIsac_kQMeanLag2Hi[67]; +extern const double WebRtcIsac_kQMeanLag3Hi[1]; +extern const double WebRtcIsac_kQMeanLag4Hi[34]; + +extern const double WebRtcIsac_kQPitchLagStepsizeHi; + +/* transform matrix */ +extern const double WebRtcIsac_kTransform[4][4]; + +/* transpose transform matrix */ +extern const double WebRtcIsac_kTransformTranspose[4][4]; + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_LAG_TABLES_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/main/source/settings.h b/src/modules/audio_coding/codecs/isac/main/source/settings.h new file mode 100644 index 0000000000..9c1ec1e6a0 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/settings.h @@ -0,0 +1,205 @@ +/* + * 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. + */ + +/* + * settings.h + * + * Declaration of #defines used in the iSAC codec + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SETTINGS_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SETTINGS_H_ + +/* sampling frequency (Hz) */ +#define FS 16000 + +/* number of samples per frame (either 320 (20ms), 480 (30ms) or 960 (60ms)) */ +#define INITIAL_FRAMESAMPLES 960 + + +#define MAXFFTSIZE 2048 +#define NFACTOR 11 + + + +/* do not modify the following; this will have to be modified if we + * have a 20ms framesize option */ +/**********************************************************************/ +/* miliseconds */ +#define FRAMESIZE 30 +/* number of samples per frame processed in the encoder, 480 */ +#define FRAMESAMPLES 480 /* ((FRAMESIZE*FS)/1000) */ +#define FRAMESAMPLES_HALF 240 +#define FRAMESAMPLES_QUARTER 120 +/**********************************************************************/ + + + +/* max number of samples per frame (= 60 ms frame) */ +#define MAX_FRAMESAMPLES 960 +#define MAX_SWBFRAMESAMPLES (MAX_FRAMESAMPLES * 2) +/* number of samples per 10ms frame */ +#define FRAMESAMPLES_10ms ((10*FS)/1000) +#define SWBFRAMESAMPLES_10ms (FRAMESAMPLES_10ms * 2) +/* number of samples in 30 ms frame */ +#define FRAMESAMPLES_30ms 480 +/* number of subframes */ +#define SUBFRAMES 6 +/* length of a subframe */ +#define UPDATE 80 +/* length of half a subframe (low/high band) */ +#define HALF_SUBFRAMELEN (UPDATE/2) +/* samples of look ahead (in a half-band, so actually + * half the samples of look ahead @ FS) */ +#define QLOOKAHEAD 24 /* 3 ms */ +/* order of AR model in spectral entropy coder */ +#define AR_ORDER 6 +/* order of LP model in spectral entropy coder */ +#define LP_ORDER 0 + +/* window length (masking analysis) */ +#define WINLEN 256 +/* order of low-band pole filter used to approximate masking curve */ +#define ORDERLO 12 +/* order of hi-band pole filter used to approximate masking curve */ +#define ORDERHI 6 + +#define UB_LPC_ORDER 4 +#define UB_LPC_VEC_PER_FRAME 2 +#define UB16_LPC_VEC_PER_FRAME 4 +#define UB_ACTIVE_SUBFRAMES 2 +#define UB_MAX_LPC_ORDER 6 +#define UB_INTERPOL_SEGMENTS 1 +#define UB16_INTERPOL_SEGMENTS 3 +#define LB_TOTAL_DELAY_SAMPLES 48 +enum ISACBandwidth {isac8kHz = 8, isac12kHz = 12, isac16kHz = 16}; +enum ISACBand {kIsacLowerBand = 0, kIsacUpperBand12 = 1, kIsacUpperBand16 = 2}; +#define UB_LPC_GAIN_DIM SUBFRAMES +#define FB_STATE_SIZE_WORD32 6 + + +/* order for post_filter_bank */ +#define POSTQORDER 3 +/* order for pre-filterbank */ +#define QORDER 3 +/* another order */ +#define QORDER_ALL (POSTQORDER+QORDER-1) +/* for decimator */ +#define ALLPASSSECTIONS 2 + + +/* array size for byte stream in number of bytes. */ +/* The old maximum size still needed for the decoding */ +#define STREAM_SIZE_MAX 600 +#define STREAM_SIZE_MAX_30 200 /* 200 bytes=53.4 kbps @ 30 ms.framelength */ +#define STREAM_SIZE_MAX_60 400 /* 400 bytes=53.4 kbps @ 60 ms.framelength */ + +/* storage size for bit counts */ +#define BIT_COUNTER_SIZE 30 +/* maximum order of any AR model or filter */ +#define MAX_AR_MODEL_ORDER 12//50 + + +/* For pitch analysis */ +#define PITCH_FRAME_LEN (FRAMESAMPLES_HALF) /* 30 ms */ +#define PITCH_MAX_LAG 140 /* 57 Hz */ +#define PITCH_MIN_LAG 20 /* 400 Hz */ +#define PITCH_MAX_GAIN 0.45 +#define PITCH_MAX_GAIN_06 0.27 /* PITCH_MAX_GAIN*0.6 */ +#define PITCH_MAX_GAIN_Q12 1843 +#define PITCH_LAG_SPAN2 (PITCH_MAX_LAG/2-PITCH_MIN_LAG/2+5) +#define PITCH_CORR_LEN2 60 /* 15 ms */ +#define PITCH_CORR_STEP2 (PITCH_FRAME_LEN/4) +#define PITCH_BW 11 /* half the band width of correlation surface */ +#define PITCH_SUBFRAMES 4 +#define PITCH_GRAN_PER_SUBFRAME 5 +#define PITCH_SUBFRAME_LEN (PITCH_FRAME_LEN/PITCH_SUBFRAMES) +#define PITCH_UPDATE (PITCH_SUBFRAME_LEN/PITCH_GRAN_PER_SUBFRAME) +/* maximum number of peaks to be examined in correlation surface */ +#define PITCH_MAX_NUM_PEAKS 10 +#define PITCH_PEAK_DECAY 0.85 +/* For weighting filter */ +#define PITCH_WLPCORDER 6 +#define PITCH_WLPCWINLEN PITCH_FRAME_LEN +#define PITCH_WLPCASYM 0.3 /* asymmetry parameter */ +#define PITCH_WLPCBUFLEN PITCH_WLPCWINLEN +/* For pitch filter */ +/* Extra 50 for fraction and LP filters */ +#define PITCH_BUFFSIZE (PITCH_MAX_LAG + 50) +#define PITCH_INTBUFFSIZE (PITCH_FRAME_LEN+PITCH_BUFFSIZE) +/* Max rel. step for interpolation */ +#define PITCH_UPSTEP 1.5 +/* Max rel. step for interpolation */ +#define PITCH_DOWNSTEP 0.67 +#define PITCH_FRACS 8 +#define PITCH_FRACORDER 9 +#define PITCH_DAMPORDER 5 +#define PITCH_FILTDELAY 1.5f +/* stepsize for quantization of the pitch Gain */ +#define PITCH_GAIN_STEPSIZE 0.125 + + + +/* Order of high pass filter */ +#define HPORDER 2 + +/* some mathematical constants */ +/* log2(exp) */ +#define LOG2EXP 1.44269504088896 +#define PI 3.14159265358979 + +/* Maximum number of iterations allowed to limit payload size */ +#define MAX_PAYLOAD_LIMIT_ITERATION 5 + +/* Redundant Coding */ +#define RCU_BOTTLENECK_BPS 16000 +#define RCU_TRANSCODING_SCALE 0.40f +#define RCU_TRANSCODING_SCALE_INVERSE 2.5f + +#define RCU_TRANSCODING_SCALE_UB 0.50f +#define RCU_TRANSCODING_SCALE_UB_INVERSE 2.0f + + +/* Define Error codes */ +/* 6000 General */ +#define ISAC_MEMORY_ALLOCATION_FAILED 6010 +#define ISAC_MODE_MISMATCH 6020 +#define ISAC_DISALLOWED_BOTTLENECK 6030 +#define ISAC_DISALLOWED_FRAME_LENGTH 6040 +#define ISAC_UNSUPPORTED_SAMPLING_FREQUENCY 6050 + +/* 6200 Bandwidth estimator */ +#define ISAC_RANGE_ERROR_BW_ESTIMATOR 6240 +/* 6400 Encoder */ +#define ISAC_ENCODER_NOT_INITIATED 6410 +#define ISAC_DISALLOWED_CODING_MODE 6420 +#define ISAC_DISALLOWED_FRAME_MODE_ENCODER 6430 +#define ISAC_DISALLOWED_BITSTREAM_LENGTH 6440 +#define ISAC_PAYLOAD_LARGER_THAN_LIMIT 6450 +#define ISAC_DISALLOWED_ENCODER_BANDWIDTH 6460 +/* 6600 Decoder */ +#define ISAC_DECODER_NOT_INITIATED 6610 +#define ISAC_EMPTY_PACKET 6620 +#define ISAC_DISALLOWED_FRAME_MODE_DECODER 6630 +#define ISAC_RANGE_ERROR_DECODE_FRAME_LENGTH 6640 +#define ISAC_RANGE_ERROR_DECODE_BANDWIDTH 6650 +#define ISAC_RANGE_ERROR_DECODE_PITCH_GAIN 6660 +#define ISAC_RANGE_ERROR_DECODE_PITCH_LAG 6670 +#define ISAC_RANGE_ERROR_DECODE_LPC 6680 +#define ISAC_RANGE_ERROR_DECODE_SPECTRUM 6690 +#define ISAC_LENGTH_MISMATCH 6730 +#define ISAC_RANGE_ERROR_DECODE_BANDWITH 6740 +#define ISAC_DISALLOWED_BANDWIDTH_MODE_DECODER 6750 +#define ISAC_DISALLOWED_LPC_MODEL 6760 +/* 6800 Call setup formats */ +#define ISAC_INCOMPATIBLE_FORMATS 6810 + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SETTINGS_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.c b/src/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.c new file mode 100644 index 0000000000..92b9c4d626 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.c @@ -0,0 +1,138 @@ +/* + * 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. + */ + +#include "spectrum_ar_model_tables.h" +#include "settings.h" + +/********************* AR Coefficient Tables ************************/ +/* cdf for quantized reflection coefficient 1 */ +const WebRtc_UWord16 WebRtcIsac_kQArRc1Cdf[12] = { + 0, 2, 4, 129, 7707, 57485, 65495, 65527, 65529, 65531, + 65533, 65535}; + +/* cdf for quantized reflection coefficient 2 */ +const WebRtc_UWord16 WebRtcIsac_kQArRc2Cdf[12] = { + 0, 2, 4, 7, 531, 25298, 64525, 65526, 65529, 65531, + 65533, 65535}; + +/* cdf for quantized reflection coefficient 3 */ +const WebRtc_UWord16 WebRtcIsac_kQArRc3Cdf[12] = { + 0, 2, 4, 6, 620, 22898, 64843, 65527, 65529, 65531, + 65533, 65535}; + +/* cdf for quantized reflection coefficient 4 */ +const WebRtc_UWord16 WebRtcIsac_kQArRc4Cdf[12] = { + 0, 2, 4, 6, 35, 10034, 60733, 65506, 65529, 65531, + 65533, 65535}; + +/* cdf for quantized reflection coefficient 5 */ +const WebRtc_UWord16 WebRtcIsac_kQArRc5Cdf[12] = { + 0, 2, 4, 6, 36, 7567, 56727, 65385, 65529, 65531, + 65533, 65535}; + +/* cdf for quantized reflection coefficient 6 */ +const WebRtc_UWord16 WebRtcIsac_kQArRc6Cdf[12] = { + 0, 2, 4, 6, 14, 6579, 57360, 65409, 65529, 65531, + 65533, 65535}; + +/* representation levels for quantized reflection coefficient 1 */ +const WebRtc_Word16 WebRtcIsac_kQArRc1Levels[11] = { + -32104, -29007, -23202, -15496, -9279, -2577, 5934, 17535, 24512, 29503, 32104 +}; + +/* representation levels for quantized reflection coefficient 2 */ +const WebRtc_Word16 WebRtcIsac_kQArRc2Levels[11] = { + -32104, -29503, -23494, -15261, -7309, -1399, 6158, 16381, 24512, 29503, 32104 +}; + +/* representation levels for quantized reflection coefficient 3 */ +const WebRtc_Word16 WebRtcIsac_kQArRc3Levels[11] = { +-32104, -29503, -23157, -15186, -7347, -1359, 5829, 17535, 24512, 29503, 32104 +}; + +/* representation levels for quantized reflection coefficient 4 */ +const WebRtc_Word16 WebRtcIsac_kQArRc4Levels[11] = { +-32104, -29503, -24512, -15362, -6665, -342, 6596, 14585, 24512, 29503, 32104 +}; + +/* representation levels for quantized reflection coefficient 5 */ +const WebRtc_Word16 WebRtcIsac_kQArRc5Levels[11] = { +-32104, -29503, -24512, -15005, -6564, -106, 7123, 14920, 24512, 29503, 32104 +}; + +/* representation levels for quantized reflection coefficient 6 */ +const WebRtc_Word16 WebRtcIsac_kQArRc6Levels[11] = { +-32104, -29503, -24512, -15096, -6656, -37, 7036, 14847, 24512, 29503, 32104 +}; + +/* quantization boundary levels for reflection coefficients */ +const WebRtc_Word16 WebRtcIsac_kQArBoundaryLevels[12] = { +-32768, -31441, -27566, -21458, -13612, -4663, 4663, 13612, 21458, 27566, 31441, 32767 +}; + +/* initial index for AR reflection coefficient quantizer and cdf table search */ +const WebRtc_UWord16 WebRtcIsac_kQArRcInitIndex[6] = { + 5, 5, 5, 5, 5, 5}; + +/* pointers to AR cdf tables */ +const WebRtc_UWord16 *WebRtcIsac_kQArRcCdfPtr[AR_ORDER] = { + WebRtcIsac_kQArRc1Cdf, WebRtcIsac_kQArRc2Cdf, WebRtcIsac_kQArRc3Cdf, + WebRtcIsac_kQArRc4Cdf, WebRtcIsac_kQArRc5Cdf, WebRtcIsac_kQArRc6Cdf +}; + +/* pointers to AR representation levels tables */ +const WebRtc_Word16 *WebRtcIsac_kQArRcLevelsPtr[AR_ORDER] = { + WebRtcIsac_kQArRc1Levels, WebRtcIsac_kQArRc2Levels, WebRtcIsac_kQArRc3Levels, + WebRtcIsac_kQArRc4Levels, WebRtcIsac_kQArRc5Levels, WebRtcIsac_kQArRc6Levels +}; + + +/******************** GAIN Coefficient Tables ***********************/ +/* cdf for Gain coefficient */ +const WebRtc_UWord16 WebRtcIsac_kQGainCdf[19] = { + 0, 2, 4, 6, 8, 10, 12, 14, 16, 1172, + 11119, 29411, 51699, 64445, 65527, 65529, 65531, 65533, 65535}; + +/* representation levels for quantized squared Gain coefficient */ +const WebRtc_Word32 WebRtcIsac_kQGain2Levels[18] = { +// 17, 28, 46, 76, 128, 215, 364, 709, 1268, 1960, 3405, 6078, 11286, 17827, 51918, 134498, 487432, 2048000}; + 128, 128, 128, 128, 128, 215, 364, 709, 1268, 1960, 3405, 6078, 11286, 17827, 51918, 134498, 487432, 2048000}; +/* quantization boundary levels for squared Gain coefficient */ +const WebRtc_Word32 WebRtcIsac_kQGain2BoundaryLevels[19] = { +0, 21, 35, 59, 99, 166, 280, 475, 815, 1414, 2495, 4505, 8397, 16405, 34431, 81359, 240497, 921600, 0x7FFFFFFF}; + +/* pointers to Gain cdf table */ +const WebRtc_UWord16 *WebRtcIsac_kQGainCdf_ptr[1] = {WebRtcIsac_kQGainCdf}; + +/* Gain initial index for gain quantizer and cdf table search */ +const WebRtc_UWord16 WebRtcIsac_kQGainInitIndex[1] = {11}; + +/************************* Cosine Tables ****************************/ +/* Cosine table */ +const WebRtc_Word16 WebRtcIsac_kCos[6][60] = { +{512, 512, 511, 510, 508, 507, 505, 502, 499, 496, 493, 489, 485, 480, 476, 470, 465, 459, 453, 447, +440, 433, 426, 418, 410, 402, 394, 385, 376, 367, 357, 348, 338, 327, 317, 306, 295, 284, 273, 262, +250, 238, 226, 214, 202, 190, 177, 165, 152, 139, 126, 113, 100, 87, 73, 60, 47, 33, 20, 7}, +{512, 510, 508, 503, 498, 491, 483, 473, 462, 450, 437, 422, 406, 389, 371, 352, 333, 312, 290, 268, +244, 220, 196, 171, 145, 120, 93, 67, 40, 13, -13, -40, -67, -93, -120, -145, -171, -196, -220, -244, +-268, -290, -312, -333, -352, -371, -389, -406, -422, -437, -450, -462, -473, -483, -491, -498, -503, -508, -510, -512}, +{512, 508, 502, 493, 480, 465, 447, 426, 402, 376, 348, 317, 284, 250, 214, 177, 139, 100, 60, 20, +-20, -60, -100, -139, -177, -214, -250, -284, -317, -348, -376, -402, -426, -447, -465, -480, -493, -502, -508, -512, +-512, -508, -502, -493, -480, -465, -447, -426, -402, -376, -348, -317, -284, -250, -214, -177, -139, -100, -60, -20}, +{511, 506, 495, 478, 456, 429, 398, 362, 322, 279, 232, 183, 133, 80, 27, -27, -80, -133, -183, -232, +-279, -322, -362, -398, -429, -456, -478, -495, -506, -511, -511, -506, -495, -478, -456, -429, -398, -362, -322, -279, +-232, -183, -133, -80, -27, 27, 80, 133, 183, 232, 279, 322, 362, 398, 429, 456, 478, 495, 506, 511}, +{511, 502, 485, 459, 426, 385, 338, 284, 226, 165, 100, 33, -33, -100, -165, -226, -284, -338, -385, -426, +-459, -485, -502, -511, -511, -502, -485, -459, -426, -385, -338, -284, -226, -165, -100, -33, 33, 100, 165, 226, +284, 338, 385, 426, 459, 485, 502, 511, 511, 502, 485, 459, 426, 385, 338, 284, 226, 165, 100, 33}, +{510, 498, 473, 437, 389, 333, 268, 196, 120, 40, -40, -120, -196, -268, -333, -389, -437, -473, -498, -510, +-510, -498, -473, -437, -389, -333, -268, -196, -120, -40, 40, 120, 196, 268, 333, 389, 437, 473, 498, 510, +510, 498, 473, 437, 389, 333, 268, 196, 120, 40, -40, -120, -196, -268, -333, -389, -437, -473, -498, -510} +}; diff --git a/src/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.h b/src/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.h new file mode 100644 index 0000000000..159245bd98 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/spectrum_ar_model_tables.h @@ -0,0 +1,76 @@ +/* + * 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. + */ + +/* + * spectrum_ar_model_tables.h + * + * This file contains definitions of tables with AR coefficients, + * Gain coefficients and cosine tables. + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_ + +#include "structs.h" + +/********************* AR Coefficient Tables ************************/ +/* cdf for quantized reflection coefficient 1 */ +extern const WebRtc_UWord16 WebRtcIsac_kQArRc1Cdf[12]; + +/* cdf for quantized reflection coefficient 2 */ +extern const WebRtc_UWord16 WebRtcIsac_kQArRc2Cdf[12]; + +/* cdf for quantized reflection coefficient 3 */ +extern const WebRtc_UWord16 WebRtcIsac_kQArRc3Cdf[12]; + +/* cdf for quantized reflection coefficient 4 */ +extern const WebRtc_UWord16 WebRtcIsac_kQArRc4Cdf[12]; + +/* cdf for quantized reflection coefficient 5 */ +extern const WebRtc_UWord16 WebRtcIsac_kQArRc5Cdf[12]; + +/* cdf for quantized reflection coefficient 6 */ +extern const WebRtc_UWord16 WebRtcIsac_kQArRc6Cdf[12]; + +/* quantization boundary levels for reflection coefficients */ +extern const WebRtc_Word16 WebRtcIsac_kQArBoundaryLevels[12]; + +/* initial indices for AR reflection coefficient quantizer and cdf table search */ +extern const WebRtc_UWord16 WebRtcIsac_kQArRcInitIndex[AR_ORDER]; + +/* pointers to AR cdf tables */ +extern const WebRtc_UWord16 *WebRtcIsac_kQArRcCdfPtr[AR_ORDER]; + +/* pointers to AR representation levels tables */ +extern const WebRtc_Word16 *WebRtcIsac_kQArRcLevelsPtr[AR_ORDER]; + + +/******************** GAIN Coefficient Tables ***********************/ +/* cdf for Gain coefficient */ +extern const WebRtc_UWord16 WebRtcIsac_kQGainCdf[19]; + +/* representation levels for quantized Gain coefficient */ +extern const WebRtc_Word32 WebRtcIsac_kQGain2Levels[18]; + +/* squared quantization boundary levels for Gain coefficient */ +extern const WebRtc_Word32 WebRtcIsac_kQGain2BoundaryLevels[19]; + +/* pointer to Gain cdf table */ +extern const WebRtc_UWord16 *WebRtcIsac_kQGainCdf_ptr[1]; + +/* Gain initial index for gain quantizer and cdf table search */ +extern const WebRtc_UWord16 WebRtcIsac_kQGainInitIndex[1]; + +/************************* Cosine Tables ****************************/ +/* Cosine table */ +extern const WebRtc_Word16 WebRtcIsac_kCos[6][60]; + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/main/source/structs.h b/src/modules/audio_coding/codecs/isac/main/source/structs.h new file mode 100644 index 0000000000..96cef30bc5 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/structs.h @@ -0,0 +1,477 @@ +/* + * 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. + */ + +/* + * structs.h + * + * This header file contains all the structs used in the ISAC codec + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_STRUCTS_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_STRUCTS_H_ + + +#include "typedefs.h" +#include "settings.h" +#include "isac.h" + +typedef struct Bitstreamstruct { + + WebRtc_UWord8 stream[STREAM_SIZE_MAX]; + WebRtc_UWord32 W_upper; + WebRtc_UWord32 streamval; + WebRtc_UWord32 stream_index; + +} Bitstr; + +typedef struct { + + double DataBufferLo[WINLEN]; + double DataBufferHi[WINLEN]; + + double CorrBufLo[ORDERLO+1]; + double CorrBufHi[ORDERHI+1]; + + float PreStateLoF[ORDERLO+1]; + float PreStateLoG[ORDERLO+1]; + float PreStateHiF[ORDERHI+1]; + float PreStateHiG[ORDERHI+1]; + float PostStateLoF[ORDERLO+1]; + float PostStateLoG[ORDERLO+1]; + float PostStateHiF[ORDERHI+1]; + float PostStateHiG[ORDERHI+1]; + + double OldEnergy; + +} MaskFiltstr; + + +typedef struct { + + //state vectors for each of the two analysis filters + double INSTAT1[2*(QORDER-1)]; + double INSTAT2[2*(QORDER-1)]; + double INSTATLA1[2*(QORDER-1)]; + double INSTATLA2[2*(QORDER-1)]; + double INLABUF1[QLOOKAHEAD]; + double INLABUF2[QLOOKAHEAD]; + + float INSTAT1_float[2*(QORDER-1)]; + float INSTAT2_float[2*(QORDER-1)]; + float INSTATLA1_float[2*(QORDER-1)]; + float INSTATLA2_float[2*(QORDER-1)]; + float INLABUF1_float[QLOOKAHEAD]; + float INLABUF2_float[QLOOKAHEAD]; + + /* High pass filter */ + double HPstates[HPORDER]; + float HPstates_float[HPORDER]; + +} PreFiltBankstr; + + +typedef struct { + + //state vectors for each of the two analysis filters + double STATE_0_LOWER[2*POSTQORDER]; + double STATE_0_UPPER[2*POSTQORDER]; + + /* High pass filter */ + double HPstates1[HPORDER]; + double HPstates2[HPORDER]; + + float STATE_0_LOWER_float[2*POSTQORDER]; + float STATE_0_UPPER_float[2*POSTQORDER]; + + float HPstates1_float[HPORDER]; + float HPstates2_float[HPORDER]; + +} PostFiltBankstr; + +typedef struct { + + //data buffer for pitch filter + double ubuf[PITCH_BUFFSIZE]; + + //low pass state vector + double ystate[PITCH_DAMPORDER]; + + //old lag and gain + double oldlagp[1]; + double oldgainp[1]; + +} PitchFiltstr; + +typedef struct { + + //data buffer + double buffer[PITCH_WLPCBUFLEN]; + + //state vectors + double istate[PITCH_WLPCORDER]; + double weostate[PITCH_WLPCORDER]; + double whostate[PITCH_WLPCORDER]; + + //LPC window -> should be a global array because constant + double window[PITCH_WLPCWINLEN]; + +} WeightFiltstr; + +typedef struct { + + //for inital estimator + double dec_buffer[PITCH_CORR_LEN2 + PITCH_CORR_STEP2 + + PITCH_MAX_LAG/2 - PITCH_FRAME_LEN/2+2]; + double decimator_state[2*ALLPASSSECTIONS+1]; + double hp_state[2]; + + double whitened_buf[QLOOKAHEAD]; + + double inbuf[QLOOKAHEAD]; + + PitchFiltstr PFstr_wght; + PitchFiltstr PFstr; + WeightFiltstr Wghtstr; + +} PitchAnalysisStruct; + + + +/* Have instance of struct together with other iSAC structs */ +typedef struct { + + /* Previous frame length (in ms) */ + WebRtc_Word32 prev_frame_length; + + /* Previous RTP timestamp from received + packet (in samples relative beginning) */ + WebRtc_Word32 prev_rec_rtp_number; + + /* Send timestamp for previous packet (in ms using timeGetTime()) */ + WebRtc_UWord32 prev_rec_send_ts; + + /* Arrival time for previous packet (in ms using timeGetTime()) */ + WebRtc_UWord32 prev_rec_arr_ts; + + /* rate of previous packet, derived from RTP timestamps (in bits/s) */ + float prev_rec_rtp_rate; + + /* Time sinse the last update of the BN estimate (in ms) */ + WebRtc_UWord32 last_update_ts; + + /* Time sinse the last reduction (in ms) */ + WebRtc_UWord32 last_reduction_ts; + + /* How many times the estimate was update in the beginning */ + WebRtc_Word32 count_tot_updates_rec; + + /* The estimated bottle neck rate from there to here (in bits/s) */ + WebRtc_Word32 rec_bw; + float rec_bw_inv; + float rec_bw_avg; + float rec_bw_avg_Q; + + /* The estimated mean absolute jitter value, + as seen on this side (in ms) */ + float rec_jitter; + float rec_jitter_short_term; + float rec_jitter_short_term_abs; + float rec_max_delay; + float rec_max_delay_avg_Q; + + /* (assumed) bitrate for headers (bps) */ + float rec_header_rate; + + /* The estimated bottle neck rate from here to there (in bits/s) */ + float send_bw_avg; + + /* The estimated mean absolute jitter value, as seen on + the other siee (in ms) */ + float send_max_delay_avg; + + // number of packets received since last update + int num_pkts_rec; + + int num_consec_rec_pkts_over_30k; + + // flag for marking that a high speed network has been + // detected downstream + int hsn_detect_rec; + + int num_consec_snt_pkts_over_30k; + + // flag for marking that a high speed network has + // been detected upstream + int hsn_detect_snd; + + WebRtc_UWord32 start_wait_period; + + int in_wait_period; + + int change_to_WB; + + WebRtc_UWord32 senderTimestamp; + WebRtc_UWord32 receiverTimestamp; + //enum IsacSamplingRate incomingStreamSampFreq; + WebRtc_UWord16 numConsecLatePkts; + float consecLatency; + WebRtc_Word16 inWaitLatePkts; +} BwEstimatorstr; + + +typedef struct { + + /* boolean, flags if previous packet exceeded B.N. */ + int PrevExceed; + /* ms */ + int ExceedAgo; + /* packets left to send in current burst */ + int BurstCounter; + /* packets */ + int InitCounter; + /* ms remaining in buffer when next packet will be sent */ + double StillBuffered; + +} RateModel; + + +typedef struct { + + unsigned int SpaceAlloced; + unsigned int MaxPermAlloced; + double Tmp0[MAXFFTSIZE]; + double Tmp1[MAXFFTSIZE]; + double Tmp2[MAXFFTSIZE]; + double Tmp3[MAXFFTSIZE]; + int Perm[MAXFFTSIZE]; + int factor [NFACTOR]; + +} FFTstr; + + +/* The following strutc is used to store data from encoding, to make it + fast and easy to construct a new bitstream with a different Bandwidth + estimate. All values (except framelength and minBytes) is double size to + handle 60 ms of data. +*/ +typedef struct { + + /* Used to keep track of if it is first or second part of 60 msec packet */ + int startIdx; + + /* Frame length in samples */ + WebRtc_Word16 framelength; + + /* Pitch Gain */ + int pitchGain_index[2]; + + /* Pitch Lag */ + double meanGain[2]; + int pitchIndex[PITCH_SUBFRAMES*2]; + + /* LPC */ + int LPCindex_s[108*2]; /* KLT_ORDER_SHAPE = 108 */ + int LPCindex_g[12*2]; /* KLT_ORDER_GAIN = 12 */ + double LPCcoeffs_lo[(ORDERLO+1)*SUBFRAMES*2]; + double LPCcoeffs_hi[(ORDERHI+1)*SUBFRAMES*2]; + + /* Encode Spec */ + WebRtc_Word16 fre[FRAMESAMPLES]; + WebRtc_Word16 fim[FRAMESAMPLES]; + WebRtc_Word16 AvgPitchGain[2]; + + /* Used in adaptive mode only */ + int minBytes; + +} ISAC_SaveEncData_t; + + +typedef struct { + + int indexLPCShape[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME]; + double lpcGain[SUBFRAMES<<1]; + int lpcGainIndex[SUBFRAMES<<1]; + + Bitstr bitStreamObj; + + WebRtc_Word16 realFFT[FRAMESAMPLES_HALF]; + WebRtc_Word16 imagFFT[FRAMESAMPLES_HALF]; +} ISACUBSaveEncDataStruct; + + + +typedef struct { + + Bitstr bitstr_obj; + MaskFiltstr maskfiltstr_obj; + PreFiltBankstr prefiltbankstr_obj; + PitchFiltstr pitchfiltstr_obj; + PitchAnalysisStruct pitchanalysisstr_obj; + FFTstr fftstr_obj; + ISAC_SaveEncData_t SaveEnc_obj; + + int buffer_index; + WebRtc_Word16 current_framesamples; + + float data_buffer_float[FRAMESAMPLES_30ms]; + + int frame_nb; + double bottleneck; + WebRtc_Word16 new_framelength; + double s2nr; + + /* Maximum allowed number of bits for a 30 msec packet */ + WebRtc_Word16 payloadLimitBytes30; + /* Maximum allowed number of bits for a 30 msec packet */ + WebRtc_Word16 payloadLimitBytes60; + /* Maximum allowed number of bits for both 30 and 60 msec packet */ + WebRtc_Word16 maxPayloadBytes; + /* Maximum allowed rate in bytes per 30 msec packet */ + WebRtc_Word16 maxRateInBytes; + + /*--- + If set to 1 iSAC will not addapt the frame-size, if used in + channel-adaptive mode. The initial value will be used for all rates. + ---*/ + WebRtc_Word16 enforceFrameSize; + + /*----- + This records the BWE index the encoder injected into the bit-stream. + It will be used in RCU. The same BWE index of main paylaod will be in + the redundant payload. We can not retrive it from BWE because it is + a recursive procedure (WebRtcIsac_GetDownlinkBwJitIndexImpl) and has to be + called only once per each encode. + -----*/ + WebRtc_Word16 lastBWIdx; +} ISACLBEncStruct; + +typedef struct { + + Bitstr bitstr_obj; + MaskFiltstr maskfiltstr_obj; + PreFiltBankstr prefiltbankstr_obj; + FFTstr fftstr_obj; + ISACUBSaveEncDataStruct SaveEnc_obj; + + int buffer_index; + float data_buffer_float[MAX_FRAMESAMPLES + + LB_TOTAL_DELAY_SAMPLES]; + double bottleneck; + /* Maximum allowed number of bits for a 30 msec packet */ + //WebRtc_Word16 payloadLimitBytes30; + /* Maximum allowed number of bits for both 30 and 60 msec packet */ + //WebRtc_Word16 maxPayloadBytes; + WebRtc_Word16 maxPayloadSizeBytes; + + double lastLPCVec[UB_LPC_ORDER]; + WebRtc_Word16 numBytesUsed; + WebRtc_Word16 lastJitterInfo; +} ISACUBEncStruct; + + + +typedef struct { + + Bitstr bitstr_obj; + MaskFiltstr maskfiltstr_obj; + PostFiltBankstr postfiltbankstr_obj; + PitchFiltstr pitchfiltstr_obj; + FFTstr fftstr_obj; + +} ISACLBDecStruct; + +typedef struct { + + Bitstr bitstr_obj; + MaskFiltstr maskfiltstr_obj; + PostFiltBankstr postfiltbankstr_obj; + FFTstr fftstr_obj; + +} ISACUBDecStruct; + + + +typedef struct { + + ISACLBEncStruct ISACencLB_obj; + ISACLBDecStruct ISACdecLB_obj; +} ISACLBStruct; + + +typedef struct { + + ISACUBEncStruct ISACencUB_obj; + ISACUBDecStruct ISACdecUB_obj; +} ISACUBStruct; + +/* + This struct is used to take a snapshot of the entropy coder and LPC gains + right before encoding LPC gains. This allows us to go back to that state + if we like to limit the payload size. +*/ +typedef struct { + /* 6 lower-band & 6 upper-band */ + double loFiltGain[SUBFRAMES]; + double hiFiltGain[SUBFRAMES]; + /* Upper boundary of interval W */ + WebRtc_UWord32 W_upper; + WebRtc_UWord32 streamval; + /* Index to the current position in bytestream */ + WebRtc_UWord32 stream_index; + WebRtc_UWord8 stream[3]; +} transcode_obj; + + +typedef struct { + // lower-band codec instance + ISACLBStruct instLB; + // upper-band codec instance + ISACUBStruct instUB; + + // Bandwidth Estimator and model for the rate. + BwEstimatorstr bwestimator_obj; + RateModel rate_data_obj; + double MaxDelay; + + /* 0 = adaptive; 1 = instantaneous */ + WebRtc_Word16 codingMode; + + // overall bottleneck of the codec + WebRtc_Word32 bottleneck; + + // QMF Filter state + WebRtc_Word32 analysisFBState1[FB_STATE_SIZE_WORD32]; + WebRtc_Word32 analysisFBState2[FB_STATE_SIZE_WORD32]; + WebRtc_Word32 synthesisFBState1[FB_STATE_SIZE_WORD32]; + WebRtc_Word32 synthesisFBState2[FB_STATE_SIZE_WORD32]; + + // Error Code + WebRtc_Word16 errorCode; + + // bandwidth of the encoded audio 8, 12 or 16 kHz + enum ISACBandwidth bandwidthKHz; + // Sampling rate of audio, encoder and decode, 8 or 16 kHz + enum IsacSamplingRate encoderSamplingRateKHz; + enum IsacSamplingRate decoderSamplingRateKHz; + // Flag to keep track of initializations, lower & upper-band + // encoder and decoder. + WebRtc_Word16 initFlag; + + // Flag to to indicate signal bandwidth switch + WebRtc_Word16 resetFlag_8kHz; + + // Maximum allowed rate, measured in Bytes per 30 ms. + WebRtc_Word16 maxRateBytesPer30Ms; + // Maximum allowed payload-size, measured in Bytes. + WebRtc_Word16 maxPayloadSizeBytes; +} ISACMainStruct; + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_STRUCTS_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/main/source/transform.c b/src/modules/audio_coding/codecs/isac/main/source/transform.c new file mode 100644 index 0000000000..97b801ac49 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/main/source/transform.c @@ -0,0 +1,131 @@ +/* + * 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. + */ + +#include "settings.h" +#include "fft.h" +#include "codec.h" +#include "os_specific_inline.h" +#include + +static double costab1[FRAMESAMPLES_HALF]; +static double sintab1[FRAMESAMPLES_HALF]; +static double costab2[FRAMESAMPLES_QUARTER]; +static double sintab2[FRAMESAMPLES_QUARTER]; + +void WebRtcIsac_InitTransform() +{ + int k; + double fact, phase; + + fact = PI / (FRAMESAMPLES_HALF); + phase = 0.0; + for (k = 0; k < FRAMESAMPLES_HALF; k++) { + costab1[k] = cos(phase); + sintab1[k] = sin(phase); + phase += fact; + } + + fact = PI * ((double) (FRAMESAMPLES_HALF - 1)) / ((double) FRAMESAMPLES_HALF); + phase = 0.5 * fact; + for (k = 0; k < FRAMESAMPLES_QUARTER; k++) { + costab2[k] = cos(phase); + sintab2[k] = sin(phase); + phase += fact; + } +} + + +void WebRtcIsac_Time2Spec(double *inre1, + double *inre2, + WebRtc_Word16 *outreQ7, + WebRtc_Word16 *outimQ7, + FFTstr *fftstr_obj) +{ + + int k; + int dims[1]; + double tmp1r, tmp1i, xr, xi, yr, yi, fact; + double tmpre[FRAMESAMPLES_HALF], tmpim[FRAMESAMPLES_HALF]; + + + dims[0] = FRAMESAMPLES_HALF; + + + /* Multiply with complex exponentials and combine into one complex vector */ + fact = 0.5 / sqrt(FRAMESAMPLES_HALF); + for (k = 0; k < FRAMESAMPLES_HALF; k++) { + tmp1r = costab1[k]; + tmp1i = sintab1[k]; + tmpre[k] = (inre1[k] * tmp1r + inre2[k] * tmp1i) * fact; + tmpim[k] = (inre2[k] * tmp1r - inre1[k] * tmp1i) * fact; + } + + + /* Get DFT */ + WebRtcIsac_Fftns(1, dims, tmpre, tmpim, -1, 1.0, fftstr_obj); + + /* Use symmetry to separate into two complex vectors and center frames in time around zero */ + for (k = 0; k < FRAMESAMPLES_QUARTER; k++) { + xr = tmpre[k] + tmpre[FRAMESAMPLES_HALF - 1 - k]; + yi = -tmpre[k] + tmpre[FRAMESAMPLES_HALF - 1 - k]; + xi = tmpim[k] - tmpim[FRAMESAMPLES_HALF - 1 - k]; + yr = tmpim[k] + tmpim[FRAMESAMPLES_HALF - 1 - k]; + + tmp1r = costab2[k]; + tmp1i = sintab2[k]; + outreQ7[k] = (WebRtc_Word16)WebRtcIsac_lrint((xr * tmp1r - xi * tmp1i) * 128.0); + outimQ7[k] = (WebRtc_Word16)WebRtcIsac_lrint((xr * tmp1i + xi * tmp1r) * 128.0); + outreQ7[FRAMESAMPLES_HALF - 1 - k] = (WebRtc_Word16)WebRtcIsac_lrint((-yr * tmp1i - yi * tmp1r) * 128.0); + outimQ7[FRAMESAMPLES_HALF - 1 - k] = (WebRtc_Word16)WebRtcIsac_lrint((-yr * tmp1r + yi * tmp1i) * 128.0); + } +} + + +void WebRtcIsac_Spec2time(double *inre, double *inim, double *outre1, double *outre2, FFTstr *fftstr_obj) +{ + + int k; + double tmp1r, tmp1i, xr, xi, yr, yi, fact; + + int dims; + + dims = FRAMESAMPLES_HALF; + + for (k = 0; k < FRAMESAMPLES_QUARTER; k++) { + /* Move zero in time to beginning of frames */ + tmp1r = costab2[k]; + tmp1i = sintab2[k]; + xr = inre[k] * tmp1r + inim[k] * tmp1i; + xi = inim[k] * tmp1r - inre[k] * tmp1i; + yr = -inim[FRAMESAMPLES_HALF - 1 - k] * tmp1r - inre[FRAMESAMPLES_HALF - 1 - k] * tmp1i; + yi = -inre[FRAMESAMPLES_HALF - 1 - k] * tmp1r + inim[FRAMESAMPLES_HALF - 1 - k] * tmp1i; + + /* Combine into one vector, z = x + j * y */ + outre1[k] = xr - yi; + outre1[FRAMESAMPLES_HALF - 1 - k] = xr + yi; + outre2[k] = xi + yr; + outre2[FRAMESAMPLES_HALF - 1 - k] = -xi + yr; + } + + + /* Get IDFT */ + WebRtcIsac_Fftns(1, &dims, outre1, outre2, 1, FRAMESAMPLES_HALF, fftstr_obj); + + + /* Demodulate and separate */ + fact = sqrt(FRAMESAMPLES_HALF); + for (k = 0; k < FRAMESAMPLES_HALF; k++) { + tmp1r = costab1[k]; + tmp1i = sintab1[k]; + xr = (outre1[k] * tmp1r - outre2[k] * tmp1i) * fact; + outre2[k] = (outre2[k] * tmp1r + outre1[k] * tmp1i) * fact; + outre1[k] = xr; + } +}