diff options
author | Alexander Gutkin <agutkin@google.com> | 2012-09-17 08:53:18 +0100 |
---|---|---|
committer | Alexander Gutkin <agutkin@google.com> | 2012-09-18 10:56:58 +0100 |
commit | a6451827d543eb00824bc95097e47d0aac51ae93 (patch) | |
tree | 4a8cf6cf1ff19717bdbf501c94a899d83518bf93 | |
parent | 6f12fff925188ced26e518cd2252aff3e93bb04e (diff) | |
download | webrtc-a6451827d543eb00824bc95097e47d0aac51ae93.tar.gz |
Added fixed point iSAC codec implementation.
- Added fixed-point iSAC audio codec implementation (from stable r2699).
- Updated system wrappers (from stable r2699).
- Some cosmetic makefile changes.
Change-Id: If75d503698c11a4e4ceb851529127aadfe52f255
126 files changed, 23058 insertions, 952 deletions
diff --git a/Android.mk b/Android.mk index a6e7a49671..7b046d67af 100644 --- a/Android.mk +++ b/Android.mk @@ -12,6 +12,8 @@ MY_WEBRTC_ROOT_PATH := $(call my-dir) include $(MY_WEBRTC_ROOT_PATH)/src/common_audio/resampler/Android.mk include $(MY_WEBRTC_ROOT_PATH)/src/common_audio/signal_processing/Android.mk include $(MY_WEBRTC_ROOT_PATH)/src/common_audio/vad/Android.mk +include $(MY_WEBRTC_ROOT_PATH)/src/modules/audio_coding/codecs/isac/fix/source/Android.mk +include $(MY_WEBRTC_ROOT_PATH)/src/modules/audio_coding/codecs/isac/main/source/Android.mk include $(MY_WEBRTC_ROOT_PATH)/src/modules/audio_processing/aec/Android.mk include $(MY_WEBRTC_ROOT_PATH)/src/modules/audio_processing/aecm/Android.mk include $(MY_WEBRTC_ROOT_PATH)/src/modules/audio_processing/agc/Android.mk @@ -20,7 +22,6 @@ 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) @@ -75,9 +76,15 @@ LOCAL_MODULE_TAGS := optional LOCAL_WHOLE_STATIC_LIBRARIES := \ libwebrtc_isac \ + libwebrtc_isacfix \ libwebrtc_spl \ libwebrtc_system_wrappers +ifeq ($(WEBRTC_BUILD_NEON_LIBS),true) +LOCAL_WHOLE_STATIC_LIBRARIES += \ + libwebrtc_isacfix_neon +endif + LOCAL_STATIC_LIBRARIES := \ libprotobuf-cpp-2.3.0-lite diff --git a/src/modules/audio_coding/codecs/isac/fix/interface/isacfix.h b/src/modules/audio_coding/codecs/isac/fix/interface/isacfix.h new file mode 100644 index 0000000000..28e942940f --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/interface/isacfix.h @@ -0,0 +1,633 @@ +/* + * 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_FIX_INTERFACE_ISACFIX_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_INTERFACE_ISACFIX_H_ + +/* + * Define the fixpoint numeric formats + */ +#include "typedefs.h" + + +typedef struct { + void *dummy; +} ISACFIX_MainStruct; + + +#if defined(__cplusplus) +extern "C" { +#endif + + + /************************************************************************** + * WebRtcIsacfix_AssignSize(...) + * + * Functions used when malloc is not allowed + * Output the number of bytes needed to allocate for iSAC struct. + * + */ + + WebRtc_Word16 WebRtcIsacfix_AssignSize(int *sizeinbytes); + + /************************************************************************** + * WebRtcIsacfix_Assign(...) + * + * Functions used when malloc is not allowed, it + * places a struct at the given address. + * + * Input: + * - *ISAC_main_inst : a pointer to the coder instance. + * - ISACFIX_inst_Addr : address of the memory where a space is + * for iSAC structure. + * + * Return value : 0 - Ok + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsacfix_Assign(ISACFIX_MainStruct **inst, + void *ISACFIX_inst_Addr); + + /**************************************************************************** + * WebRtcIsacfix_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 WebRtcIsacfix_Create(ISACFIX_MainStruct **ISAC_main_inst); + + + /**************************************************************************** + * WebRtcIsacfix_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 WebRtcIsacfix_Free(ISACFIX_MainStruct *ISAC_main_inst); + + + /**************************************************************************** + * WebRtcIsacfix_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. + * 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 WebRtcIsacfix_EncoderInit(ISACFIX_MainStruct *ISAC_main_inst, + WebRtc_Word16 CodingMode); + + + /**************************************************************************** + * WebRtcIsacfix_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 WebRtcIsacfix_Encode(ISACFIX_MainStruct *ISAC_main_inst, + const WebRtc_Word16 *speechIn, + WebRtc_Word16 *encoded); + + + + /**************************************************************************** + * WebRtcIsacfix_EncodeNb(...) + * + * This function encodes 10ms narrow band (8 kHz sampling) frame(s) and inserts + * it into a package. Input speech length has to be 80 samples (10ms). The encoder + * interpolates into wide-band (16 kHz sampling) buffers those + * 10ms frames until it reaches the chosen Framesize (480 or 960 wide-band samples + * corresponding to 30 or 60 ms frames), and then proceeds to the encoding. + * + * The function is enabled if WEBRTC_ISAC_FIX_NB_CALLS_ENABLED is defined + * + * 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 + */ + + +#ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED + WebRtc_Word16 WebRtcIsacfix_EncodeNb(ISACFIX_MainStruct *ISAC_main_inst, + const WebRtc_Word16 *speechIn, + WebRtc_Word16 *encoded); +#endif // WEBRTC_ISAC_FIX_NB_CALLS_ENABLED + + + + /**************************************************************************** + * WebRtcIsacfix_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 WebRtcIsacfix_DecoderInit(ISACFIX_MainStruct *ISAC_main_inst); + + + /**************************************************************************** + * WebRtcIsacfix_UpdateBwEstimate1(...) + * + * 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 WebRtcIsacfix_UpdateBwEstimate1(ISACFIX_MainStruct *ISAC_main_inst, + const WebRtc_UWord16 *encoded, + WebRtc_Word32 packet_size, + WebRtc_UWord16 rtp_seq_number, + WebRtc_UWord32 arr_ts); + + /**************************************************************************** + * WebRtcIsacfix_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 send time of the packet from RTP header, + * in samples. + * - arr_ts : the arrival time of the packet (from NetEq) + * in samples. + * + * Return value : 0 - Ok + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsacfix_UpdateBwEstimate(ISACFIX_MainStruct *ISAC_main_inst, + const WebRtc_UWord16 *encoded, + WebRtc_Word32 packet_size, + WebRtc_UWord16 rtp_seq_number, + WebRtc_UWord32 send_ts, + WebRtc_UWord32 arr_ts); + + /**************************************************************************** + * WebRtcIsacfix_Decode(...) + * + * This function decodes an 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 WebRtcIsacfix_Decode(ISACFIX_MainStruct *ISAC_main_inst, + const WebRtc_UWord16 *encoded, + WebRtc_Word16 len, + WebRtc_Word16 *decoded, + WebRtc_Word16 *speechType); + + + /**************************************************************************** + * WebRtcIsacfix_DecodeNb(...) + * + * This function decodes a ISAC frame in narrow-band (8 kHz sampling). + * Output speech length will be a multiple of 240 samples: 240 or 480 samples, + * depending on the framesize (30 or 60 ms). + * + * The function is enabled if WEBRTC_ISAC_FIX_NB_CALLS_ENABLED is defined + * + * 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 + */ + +#ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED + WebRtc_Word16 WebRtcIsacfix_DecodeNb(ISACFIX_MainStruct *ISAC_main_inst, + const WebRtc_UWord16 *encoded, + WebRtc_Word16 len, + WebRtc_Word16 *decoded, + WebRtc_Word16 *speechType); +#endif // WEBRTC_ISAC_FIX_NB_CALLS_ENABLED + + + /**************************************************************************** + * WebRtcIsacfix_DecodePlcNb(...) + * + * This function conducts PLC for ISAC frame(s) in narrow-band (8kHz sampling). + * Output speech length will be "240*noOfLostFrames" samples + * that equevalent of "30*noOfLostFrames" millisecond. + * + * The function is enabled if WEBRTC_ISAC_FIX_NB_CALLS_ENABLED is defined + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - noOfLostFrames : Number of PLC frames (240 sample=30ms) to produce + * NOTE! Maximum number is 2 (480 samples = 60ms) + * + * Output: + * - decoded : The decoded vector + * + * Return value : >0 - number of samples in decoded PLC vector + * -1 - Error + */ + +#ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED + WebRtc_Word16 WebRtcIsacfix_DecodePlcNb(ISACFIX_MainStruct *ISAC_main_inst, + WebRtc_Word16 *decoded, + WebRtc_Word16 noOfLostFrames ); +#endif // WEBRTC_ISAC_FIX_NB_CALLS_ENABLED + + + + + /**************************************************************************** + * WebRtcIsacfix_DecodePlc(...) + * + * This function conducts PLC for ISAC frame(s) in wide-band (16kHz sampling). + * Output speech length will be "480*noOfLostFrames" samples + * that is equevalent of "30*noOfLostFrames" millisecond. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - noOfLostFrames : Number of PLC frames (480sample = 30ms) + * to produce + * NOTE! Maximum number is 2 (960 samples = 60ms) + * + * Output: + * - decoded : The decoded vector + * + * Return value : >0 - number of samples in decoded PLC vector + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsacfix_DecodePlc(ISACFIX_MainStruct *ISAC_main_inst, + WebRtc_Word16 *decoded, + WebRtc_Word16 noOfLostFrames ); + + + /**************************************************************************** + * WebRtcIsacfix_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 WebRtcIsacfix_ReadFrameLen(const WebRtc_Word16* encoded, + WebRtc_Word16* frameLength); + + /**************************************************************************** + * WebRtcIsacfix_Control(...) + * + * 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 + */ + + WebRtc_Word16 WebRtcIsacfix_Control(ISACFIX_MainStruct *ISAC_main_inst, + WebRtc_Word16 rate, + WebRtc_Word16 framesize); + + + + /**************************************************************************** + * WebRtcIsacfix_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 + * - 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 WebRtcIsacfix_ControlBwe(ISACFIX_MainStruct *ISAC_main_inst, + WebRtc_Word16 rateBPS, + WebRtc_Word16 frameSizeMs, + WebRtc_Word16 enforceFrameSize); + + + + /**************************************************************************** + * WebRtcIsacfix_version(...) + * + * This function returns the version number. + * + * Output: + * - version : Pointer to character string + * + */ + + void WebRtcIsacfix_version(char *version); + + + /**************************************************************************** + * WebRtcIsacfix_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 occured in the + * specified instance. + * + * Input: + * - ISAC_main_inst : ISAC instance + * + * Return value : Error code + */ + + WebRtc_Word16 WebRtcIsacfix_GetErrorCode(ISACFIX_MainStruct *ISAC_main_inst); + + + /**************************************************************************** + * WebRtcIsacfix_GetUplinkBw(...) + * + * This function return iSAC send bitrate + * + * Input: + * - ISAC_main_inst : iSAC instance + * + * Return value : <0 Error code + * else bitrate + */ + + WebRtc_Word32 WebRtcIsacfix_GetUplinkBw(ISACFIX_MainStruct *ISAC_main_inst); + + + /**************************************************************************** + * WebRtcIsacfix_SetMaxPayloadSize(...) + * + * This function sets a limit for the maximum payload size of iSAC. The same + * value is used both for 30 and 60 msec packets. + * The absolute max will be valid until next time the function is called. + * NOTE! This function may override the function WebRtcIsacfix_SetMaxRate() + * + * Input: + * - ISAC_main_inst : iSAC instance + * - maxPayloadBytes : maximum size of the payload in bytes + * valid values are between 100 and 400 bytes + * + * + * Return value : 0 if sucessful + * -1 if error happens + */ + + WebRtc_Word16 WebRtcIsacfix_SetMaxPayloadSize(ISACFIX_MainStruct *ISAC_main_inst, + WebRtc_Word16 maxPayloadBytes); + + + /**************************************************************************** + * WebRtcIsacfix_SetMaxRate(...) + * + * This function sets the maximum rate which the codec may not exceed for a + * singel packet. The maximum rate is set in bits per second. + * The codec has an absolute maximum rate of 53400 bits per second (200 bytes + * per 30 msec). + * It is possible to set a maximum rate between 32000 and 53400 bits per second. + * + * The rate limit is valid until next time the function is called. + * + * NOTE! Packet size will never go above the value set if calling + * WebRtcIsacfix_SetMaxPayloadSize() (default max packet size is 400 bytes). + * + * Input: + * - ISAC_main_inst : iSAC instance + * - maxRateInBytes : maximum rate in bits per second, + * valid values are 32000 to 53400 bits + * + * Return value : 0 if sucessful + * -1 if error happens + */ + + WebRtc_Word16 WebRtcIsacfix_SetMaxRate(ISACFIX_MainStruct *ISAC_main_inst, + WebRtc_Word32 maxRate); + + /**************************************************************************** + * WebRtcIsacfix_CreateInternal(...) + * + * This function creates the memory that is used to store data in the encoder + * + * Input: + * - *ISAC_main_inst : a pointer to the coder instance. + * + * Return value : 0 - Ok + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsacfix_CreateInternal(ISACFIX_MainStruct *ISAC_main_inst); + + + /**************************************************************************** + * WebRtcIsacfix_FreeInternal(...) + * + * This function frees the internal memory for storing encoder data. + * + * Input: + * - ISAC_main_inst : an ISAC instance. + * + * Return value : 0 - Ok + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsacfix_FreeInternal(ISACFIX_MainStruct *ISAC_main_inst); + + + /**************************************************************************** + * WebRtcIsacfix_GetNewBitStream(...) + * + * This function returns encoded data, with the recieved bwe-index in the + * stream. It should always return a complete packet, i.e. only called once + * even for 60 msec frames + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - bweIndex : index of bandwidth estimate to put in new bitstream + * - scale : factor for rate change (0.4 ~=> half the rate, 1 no change). + * + * Output: + * - encoded : the encoded data vector + * + * Return value : >0 - Length (in bytes) of coded data + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsacfix_GetNewBitStream(ISACFIX_MainStruct *ISAC_main_inst, + WebRtc_Word16 bweIndex, + float scale, + WebRtc_Word16 *encoded); + + + /**************************************************************************** + * WebRtcIsacfix_GetDownLinkBwIndex(...) + * + * This function returns index representing the Bandwidth estimate from + * other side to this side. + * + * Input: + * - ISAC_main_inst : iSAC struct + * + * Output: + * - rateIndex : Bandwidth estimate to transmit to other side. + * + */ + + WebRtc_Word16 WebRtcIsacfix_GetDownLinkBwIndex(ISACFIX_MainStruct* ISAC_main_inst, + WebRtc_Word16* rateIndex); + + + /**************************************************************************** + * WebRtcIsacfix_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 + * - rateIndex : Bandwidth estimate from other side. + * + */ + + WebRtc_Word16 WebRtcIsacfix_UpdateUplinkBw(ISACFIX_MainStruct* ISAC_main_inst, + WebRtc_Word16 rateIndex); + + + /**************************************************************************** + * WebRtcIsacfix_ReadBwIndex(...) + * + * This function returns the index of the Bandwidth estimate from the bitstream. + * + * Input: + * - encoded : Encoded bitstream + * + * Output: + * - rateIndex : Bandwidth estimate in bitstream + * + */ + + WebRtc_Word16 WebRtcIsacfix_ReadBwIndex(const WebRtc_Word16* encoded, + WebRtc_Word16* rateIndex); + + + /**************************************************************************** + * WebRtcIsacfix_GetNewFrameLen(...) + * + * This function return the next frame length (in samples) of iSAC. + * + * Input: + * -ISAC_main_inst : iSAC instance + * + * Return value : frame lenght in samples + */ + + WebRtc_Word16 WebRtcIsacfix_GetNewFrameLen(ISACFIX_MainStruct *ISAC_main_inst); + + +#if defined(__cplusplus) +} +#endif + + + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_INTERFACE_ISACFIX_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/fix/source/Android.mk b/src/modules/audio_coding/codecs/isac/fix/source/Android.mk new file mode 100644 index 0000000000..bd2a91df00 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/Android.mk @@ -0,0 +1,149 @@ +# 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. + +############################# +# Build the non-neon library. + +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_isacfix +LOCAL_MODULE_TAGS := optional +LOCAL_SRC_FILES := \ + arith_routines.c \ + arith_routines_hist.c \ + arith_routines_logist.c \ + bandwidth_estimator.c \ + decode.c \ + decode_bwe.c \ + decode_plc.c \ + encode.c \ + entropy_coding.c \ + fft.c \ + filterbank_tables.c \ + filterbanks.c \ + filters.c \ + initialize.c \ + isacfix.c \ + lattice.c \ + lpc_masking_model.c \ + lpc_tables.c \ + pitch_estimator.c \ + pitch_filter.c \ + pitch_gain_tables.c \ + pitch_lag_tables.c \ + spectrum_ar_model_tables.c \ + transform.c + +ifeq ($(ARCH_ARM_HAVE_ARMV7A),true) +# Using .S (instead of .s) extention is to include a C header file in assembly. +LOCAL_SRC_FILES += \ + lattice_armv7.S \ + pitch_filter_armv6.S +else +LOCAL_SRC_FILES += \ + lattice_c.c +endif + +# 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_STATIC_LIBRARIES += libwebrtc_system_wrappers + +LOCAL_SHARED_LIBRARIES := \ + libcutils \ + libdl \ + libstlport + +ifndef NDK_ROOT +include external/stlport/libstlport.mk +endif +include $(BUILD_STATIC_LIBRARY) + +######################### +# Build the neon library. +ifeq ($(WEBRTC_BUILD_NEON_LIBS),true) + +include $(CLEAR_VARS) + +LOCAL_ARM_MODE := arm +LOCAL_MODULE_CLASS := STATIC_LIBRARIES +LOCAL_MODULE := libwebrtc_isacfix_neon +LOCAL_MODULE_TAGS := optional +LOCAL_SRC_FILES := \ + filters_neon.c \ + lattice_neon.S \ + lpc_masking_model_neon.S + +# Flags passed to both C and C++ files. +LOCAL_CFLAGS := \ + $(MY_WEBRTC_COMMON_DEFS) \ + -mfpu=neon \ + -mfloat-abi=softfp \ + -flax-vector-conversions + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/../interface \ + $(LOCAL_PATH)/../../../../../.. \ + $(LOCAL_PATH)/../../../../../../common_audio/signal_processing/include + + +ifndef NDK_ROOT +include external/stlport/libstlport.mk +endif +include $(BUILD_STATIC_LIBRARY) + +endif # ifeq ($(WEBRTC_BUILD_NEON_LIBS),true) + +########################### +# isac test app + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests +LOCAL_CPP_EXTENSION := .cc +LOCAL_SRC_FILES:= ../test/kenny.c + +# Flags passed to both C and C++ files. +LOCAL_CFLAGS := $(MY_WEBRTC_COMMON_DEFS) + +LOCAL_C_INCLUDES := \ + $(LOCAL_PATH)/../interface \ + $(LOCAL_PATH)/../../../../../.. + +LOCAL_STATIC_LIBRARIES := \ + libwebrtc_isacfix \ + libwebrtc_spl \ + libwebrtc_system_wrappers + +ifeq ($(WEBRTC_BUILD_NEON_LIBS),true) +LOCAL_STATIC_LIBRARIES += \ + libwebrtc_isacfix_neon +endif + +LOCAL_SHARED_LIBRARIES := \ + libutils + +LOCAL_MODULE:= webrtc_isac_test + +ifdef NDK_ROOT +include $(BUILD_EXECUTABLE) +else +include $(BUILD_NATIVE_TEST) +endif diff --git a/src/modules/audio_coding/codecs/isac/fix/source/arith_routines.c b/src/modules/audio_coding/codecs/isac/fix/source/arith_routines.c new file mode 100644 index 0000000000..ee62bad5fa --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/arith_routines.c @@ -0,0 +1,124 @@ +/* + * 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_routins.c + * + * This C file contains a function for finalizing the bitstream + * after arithmetic coding. + * + */ + +#include "arith_routins.h" + + +/**************************************************************************** + * WebRtcIsacfix_EncTerminate(...) + * + * Final call to the arithmetic coder for an encoder call. This function + * terminates and return byte stream. + * + * Input: + * - streamData : in-/output struct containing bitstream + * + * Return value : number of bytes in the stream + */ +WebRtc_Word16 WebRtcIsacfix_EncTerminate(Bitstr_enc *streamData) +{ + WebRtc_UWord16 *streamPtr; + WebRtc_UWord16 negCarry; + + /* point to the right place in the stream buffer */ + streamPtr = streamData->stream + streamData->stream_index; + + /* find minimum length (determined by current interval width) */ + if ( streamData->W_upper > 0x01FFFFFF ) + { + streamData->streamval += 0x01000000; + + /* if result is less than the added value we must take care of the carry */ + if (streamData->streamval < 0x01000000) + { + /* propagate carry */ + if (streamData->full == 0) { + /* Add value to current value */ + negCarry = *streamPtr; + negCarry += 0x0100; + *streamPtr = negCarry; + + /* if value is too big, propagate carry to next byte, and so on */ + while (!(negCarry)) + { + negCarry = *--streamPtr; + negCarry++; + *streamPtr = negCarry; + } + } else { + /* propagate carry by adding one to the previous byte in the + * stream if that byte is 0xFFFF we need to propagate the carry + * furhter back in the stream */ + while ( !(++(*--streamPtr)) ); + } + + /* put pointer back to the old value */ + streamPtr = streamData->stream + streamData->stream_index; + } + /* write remaining data to bitstream, if "full == 0" first byte has data */ + if (streamData->full == 0) { + *streamPtr++ += (WebRtc_UWord16) WEBRTC_SPL_RSHIFT_W32(streamData->streamval, 24); + streamData->full = 1; + } else { + *streamPtr = (WebRtc_UWord16) WEBRTC_SPL_LSHIFT_W32( + WEBRTC_SPL_RSHIFT_W32(streamData->streamval, 24), 8); + streamData->full = 0; + } + } + else + { + streamData->streamval += 0x00010000; + + /* if result is less than the added value we must take care of the carry */ + if (streamData->streamval < 0x00010000) + { + /* propagate carry */ + if (streamData->full == 0) { + /* Add value to current value */ + negCarry = *streamPtr; + negCarry += 0x0100; + *streamPtr = negCarry; + + /* if value to big, propagate carry to next byte, and so on */ + while (!(negCarry)) + { + negCarry = *--streamPtr; + negCarry++; + *streamPtr = negCarry; + } + } else { + /* Add carry to previous byte */ + while ( !(++(*--streamPtr)) ); + } + + /* put pointer back to the old value */ + streamPtr = streamData->stream + streamData->stream_index; + } + /* write remaining data (2 bytes) to bitstream */ + if (streamData->full) { + *streamPtr++ = (WebRtc_UWord16) WEBRTC_SPL_RSHIFT_W32(streamData->streamval, 16); + } else { + *streamPtr++ |= (WebRtc_UWord16) WEBRTC_SPL_RSHIFT_W32(streamData->streamval, 24); + *streamPtr = (WebRtc_UWord16) WEBRTC_SPL_RSHIFT_W32(streamData->streamval, 8) + & 0xFF00; + } + } + + /* calculate stream length in bytes */ + return (((streamPtr - streamData->stream)<<1) + !(streamData->full)); +} diff --git a/src/modules/audio_coding/codecs/isac/fix/source/arith_routines_hist.c b/src/modules/audio_coding/codecs/isac/fix/source/arith_routines_hist.c new file mode 100644 index 0000000000..14f1addabb --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/arith_routines_hist.c @@ -0,0 +1,404 @@ +/* + * 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_routinshist.c + * + * This C file contains arithmetic encoding and decoding. + * + */ + +#include "arith_routins.h" + + +/**************************************************************************** + * WebRtcIsacfix_EncHistMulti(...) + * + * Encode the histogram interval + * + * Input: + * - streamData : in-/output struct containing bitstream + * - data : data vector + * - cdf : array of cdf arrays + * - lenData : data vector length + * + * Return value : 0 if ok + * <0 if error detected + */ +int WebRtcIsacfix_EncHistMulti(Bitstr_enc *streamData, + const WebRtc_Word16 *data, + const WebRtc_UWord16 **cdf, + const WebRtc_Word16 lenData) +{ + WebRtc_UWord32 W_lower; + WebRtc_UWord32 W_upper; + WebRtc_UWord32 W_upper_LSB; + WebRtc_UWord32 W_upper_MSB; + WebRtc_UWord16 *streamPtr; + WebRtc_UWord16 negCarry; + WebRtc_UWord16 *maxStreamPtr; + WebRtc_UWord16 *streamPtrCarry; + WebRtc_UWord32 cdfLo; + WebRtc_UWord32 cdfHi; + int k; + + + /* point to beginning of stream buffer + * and set maximum streamPtr value */ + streamPtr = streamData->stream + streamData->stream_index; + maxStreamPtr = streamData->stream + STREAM_MAXW16_60MS - 1; + + W_upper = streamData->W_upper; + + for (k = lenData; k > 0; k--) + { + /* fetch cdf_lower and cdf_upper from cdf tables */ + cdfLo = (WebRtc_UWord32) *(*cdf + (WebRtc_UWord32)*data); + cdfHi = (WebRtc_UWord32) *(*cdf++ + (WebRtc_UWord32)*data++ + 1); + + /* update interval */ + W_upper_LSB = W_upper & 0x0000FFFF; + W_upper_MSB = WEBRTC_SPL_RSHIFT_W32(W_upper, 16); + W_lower = WEBRTC_SPL_UMUL(W_upper_MSB, cdfLo); + W_lower += WEBRTC_SPL_UMUL_RSFT16(W_upper_LSB, cdfLo); + W_upper = WEBRTC_SPL_UMUL(W_upper_MSB, cdfHi); + W_upper += WEBRTC_SPL_UMUL_RSFT16(W_upper_LSB, cdfHi); + + /* 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 */ + streamPtrCarry = streamPtr; + if (streamData->full == 0) { + negCarry = *streamPtrCarry; + negCarry += 0x0100; + *streamPtrCarry = negCarry; + while (!(negCarry)) + { + negCarry = *--streamPtrCarry; + negCarry++; + *streamPtrCarry = negCarry; + } + } else { + while ( !(++(*--streamPtrCarry)) ); + } + } + + /* renormalize interval, store most significant byte of streamval and update streamval + * W_upper < 2^24 */ + while ( !(W_upper & 0xFF000000) ) + { + W_upper = WEBRTC_SPL_LSHIFT_W32(W_upper, 8); + if (streamData->full == 0) { + *streamPtr++ += (WebRtc_UWord16) WEBRTC_SPL_RSHIFT_W32(streamData->streamval, 24); + streamData->full = 1; + } else { + *streamPtr = (WebRtc_UWord16) WEBRTC_SPL_LSHIFT_W32( + WEBRTC_SPL_RSHIFT_W32(streamData->streamval, 24), 8); + streamData->full = 0; + } + + if( streamPtr > maxStreamPtr ) { + return -ISAC_DISALLOWED_BITSTREAM_LENGTH; + } + streamData->streamval = WEBRTC_SPL_LSHIFT_W32(streamData->streamval, 8); + } + } + + /* calculate new stream_index */ + streamData->stream_index = streamPtr - streamData->stream; + streamData->W_upper = W_upper; + + return 0; +} + + +/**************************************************************************** + * WebRtcIsacfix_DecHistBisectMulti(...) + * + * 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) + * + * Input: + * - streamData : in-/output struct containing bitstream + * - cdf : array of cdf arrays + * - cdfSize : array of cdf table sizes+1 (power of two: 2^k) + * - lenData : data vector length + * + * Output: + * - data : data vector + * + * Return value : number of bytes in the stream + * <0 if error detected + */ +WebRtc_Word16 WebRtcIsacfix_DecHistBisectMulti(WebRtc_Word16 *data, + Bitstr_dec *streamData, + const WebRtc_UWord16 **cdf, + const WebRtc_UWord16 *cdfSize, + const WebRtc_Word16 lenData) +{ + WebRtc_UWord32 W_lower = 0; + WebRtc_UWord32 W_upper; + WebRtc_UWord32 W_tmp; + WebRtc_UWord32 W_upper_LSB; + WebRtc_UWord32 W_upper_MSB; + WebRtc_UWord32 streamval; + const WebRtc_UWord16 *streamPtr; + const WebRtc_UWord16 *cdfPtr; + WebRtc_Word16 sizeTmp; + int k; + + + streamPtr = streamData->stream + streamData->stream_index; + W_upper = streamData->W_upper; + + /* Error check: should not be possible in normal operation */ + if (W_upper == 0) { + return -2; + } + + /* first time decoder is called for this stream */ + if (streamData->stream_index == 0) + { + /* read first word from bytestream */ + streamval = WEBRTC_SPL_LSHIFT_W32((WebRtc_UWord32)*streamPtr++, 16); + streamval |= *streamPtr++; + } else { + streamval = streamData->streamval; + } + + for (k = lenData; 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 = WEBRTC_SPL_RSHIFT_W32(W_upper, 16); + + /* start halfway the cdf range */ + sizeTmp = WEBRTC_SPL_RSHIFT_W16(*cdfSize++, 1); + cdfPtr = *cdf + (sizeTmp - 1); + + /* method of bisection */ + for ( ;; ) + { + W_tmp = WEBRTC_SPL_UMUL_32_16(W_upper_MSB, *cdfPtr); + W_tmp += WEBRTC_SPL_UMUL_32_16_RSFT16(W_upper_LSB, *cdfPtr); + sizeTmp = WEBRTC_SPL_RSHIFT_W16(sizeTmp, 1); + if (sizeTmp == 0) { + break; + } + + if (streamval > W_tmp) + { + W_lower = W_tmp; + cdfPtr += sizeTmp; + } else { + W_upper = W_tmp; + cdfPtr -= sizeTmp; + } + } + if (streamval > W_tmp) + { + W_lower = W_tmp; + *data++ = cdfPtr - *cdf++; + } else { + W_upper = W_tmp; + *data++ = cdfPtr - *cdf++ - 1; + } + + /* shift interval to start at zero */ + W_upper -= ++W_lower; + + /* add integer to bitstream */ + streamval -= W_lower; + + /* renormalize interval and update streamval */ + /* W_upper < 2^24 */ + while ( !(W_upper & 0xFF000000) ) + { + /* read next byte from stream */ + if (streamData->full == 0) { + streamval = WEBRTC_SPL_LSHIFT_W32(streamval, 8) | + (*streamPtr++ & 0x00FF); + streamData->full = 1; + } else { + streamval = WEBRTC_SPL_LSHIFT_W32(streamval, 8) | + WEBRTC_SPL_RSHIFT_W16(*streamPtr, 8); + streamData->full = 0; + } + W_upper = WEBRTC_SPL_LSHIFT_W32(W_upper, 8); + } + + + /* Error check: should not be possible in normal operation */ + if (W_upper == 0) { + return -2; + } + + } + + streamData->stream_index = streamPtr - streamData->stream; + streamData->W_upper = W_upper; + streamData->streamval = streamval; + + if ( W_upper > 0x01FFFFFF ) { + return (streamData->stream_index*2 - 3 + !streamData->full); + } else { + return (streamData->stream_index*2 - 2 + !streamData->full); + } +} + + +/**************************************************************************** + * WebRtcIsacfix_DecHistOneStepMulti(...) + * + * 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. + * + * Input: + * - streamData : in-/output struct containing bitstream + * - cdf : array of cdf arrays + * - initIndex : vector of initial cdf table search entries + * - lenData : data vector length + * + * Output: + * - data : data vector + * + * Return value : number of bytes in original stream + * <0 if error detected + */ +WebRtc_Word16 WebRtcIsacfix_DecHistOneStepMulti(WebRtc_Word16 *data, + Bitstr_dec *streamData, + const WebRtc_UWord16 **cdf, + const WebRtc_UWord16 *initIndex, + const WebRtc_Word16 lenData) +{ + WebRtc_UWord32 W_lower; + WebRtc_UWord32 W_upper; + WebRtc_UWord32 W_tmp; + WebRtc_UWord32 W_upper_LSB; + WebRtc_UWord32 W_upper_MSB; + WebRtc_UWord32 streamval; + const WebRtc_UWord16 *streamPtr; + const WebRtc_UWord16 *cdfPtr; + int k; + + + streamPtr = streamData->stream + streamData->stream_index; + W_upper = streamData->W_upper; + /* Error check: Should not be possible in normal operation */ + if (W_upper == 0) { + return -2; + } + + /* Check if it is the first time decoder is called for this stream */ + if (streamData->stream_index == 0) + { + /* read first word from bytestream */ + streamval = WEBRTC_SPL_LSHIFT_U32(*streamPtr++, 16); + streamval |= *streamPtr++; + } else { + streamval = streamData->streamval; + } + + for (k = lenData; 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 = WEBRTC_SPL_RSHIFT_U32(W_upper, 16); + + /* start at the specified table entry */ + cdfPtr = *cdf + (*initIndex++); + W_tmp = WEBRTC_SPL_UMUL_32_16(W_upper_MSB, *cdfPtr); + W_tmp += WEBRTC_SPL_UMUL_32_16_RSFT16(W_upper_LSB, *cdfPtr); + + if (streamval > W_tmp) + { + for ( ;; ) + { + W_lower = W_tmp; + + /* range check */ + if (cdfPtr[0] == 65535) { + return -3; + } + + W_tmp = WEBRTC_SPL_UMUL_32_16(W_upper_MSB, *++cdfPtr); + W_tmp += WEBRTC_SPL_UMUL_32_16_RSFT16(W_upper_LSB, *cdfPtr); + + if (streamval <= W_tmp) { + break; + } + } + W_upper = W_tmp; + *data++ = cdfPtr - *cdf++ - 1; + } else { + for ( ;; ) + { + W_upper = W_tmp; + --cdfPtr; + + /* range check */ + if (cdfPtr < *cdf) { + return -3; + } + + W_tmp = WEBRTC_SPL_UMUL_32_16(W_upper_MSB, *cdfPtr); + W_tmp += WEBRTC_SPL_UMUL_32_16_RSFT16(W_upper_LSB, *cdfPtr); + + if (streamval > W_tmp) { + break; + } + } + W_lower = W_tmp; + *data++ = cdfPtr - *cdf++; + } + + /* shift interval to start at zero */ + W_upper -= ++W_lower; + + /* add integer to bitstream */ + streamval -= W_lower; + + /* renormalize interval and update streamval */ + /* W_upper < 2^24 */ + while ( !(W_upper & 0xFF000000) ) + { + /* read next byte from stream */ + if (streamData->full == 0) { + streamval = WEBRTC_SPL_LSHIFT_W32(streamval, 8) | (*streamPtr++ & 0x00FF); + streamData->full = 1; + } else { + streamval = WEBRTC_SPL_LSHIFT_W32(streamval, 8) | (*streamPtr >> 8); + streamData->full = 0; + } + W_upper = WEBRTC_SPL_LSHIFT_W32(W_upper, 8); + } + } + + streamData->stream_index = streamPtr - 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 - 3 + !streamData->full); + } else { + return (streamData->stream_index*2 - 2 + !streamData->full); + } +} diff --git a/src/modules/audio_coding/codecs/isac/fix/source/arith_routines_logist.c b/src/modules/audio_coding/codecs/isac/fix/source/arith_routines_logist.c new file mode 100644 index 0000000000..39c437e518 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/arith_routines_logist.c @@ -0,0 +1,404 @@ +/* + * 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_routinslogist.c + * + * This C file contains arithmetic encode and decode logistic + * + */ + +#include "arith_routins.h" + + +/* Tables for piecewise linear cdf functions: y = k*x */ + +/* x Points for function piecewise() in Q15 */ +static const WebRtc_Word32 kHistEdges[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 +}; + + +/* k Points for function piecewise() in Q0 */ +static const WebRtc_UWord16 kCdfSlope[51] = { + 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 +}; + +/* y Points for function piecewise() in Q0 */ +static const WebRtc_UWord16 kCdfLogistic[51] = { + 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 +}; + + +/**************************************************************************** + * WebRtcIsacfix_Piecewise(...) + * + * Piecewise linear function + * + * Input: + * - xinQ15 : input value x in Q15 + * + * Return value : korresponding y-value in Q0 + */ + + +static __inline WebRtc_UWord16 WebRtcIsacfix_Piecewise(WebRtc_Word32 xinQ15) { + WebRtc_Word32 ind; + WebRtc_Word32 qtmp1; + WebRtc_UWord16 qtmp2; + + /* Find index for x-value */ + qtmp1 = WEBRTC_SPL_SAT(kHistEdges[50],xinQ15,kHistEdges[0]); + ind = WEBRTC_SPL_MUL(5, qtmp1 - kHistEdges[0]); + ind = WEBRTC_SPL_RSHIFT_W32(ind, 16); + + /* Calculate corresponding y-value ans return*/ + qtmp1 = qtmp1 - kHistEdges[ind]; + qtmp2 = (WebRtc_UWord16)WEBRTC_SPL_RSHIFT_U32( + WEBRTC_SPL_UMUL_32_16(qtmp1,kCdfSlope[ind]), 15); + return (kCdfLogistic[ind] + qtmp2); +} + +/**************************************************************************** + * WebRtcIsacfix_EncLogisticMulti2(...) + * + * Arithmetic coding of spectrum. + * + * Input: + * - streamData : in-/output struct containing bitstream + * - dataQ7 : data vector in Q7 + * - envQ8 : side info vector defining the width of the pdf + * in Q8 + * - lenData : data vector length + * + * Return value : 0 if ok, + * <0 otherwise. + */ +int WebRtcIsacfix_EncLogisticMulti2(Bitstr_enc *streamData, + WebRtc_Word16 *dataQ7, + const WebRtc_UWord16 *envQ8, + const WebRtc_Word16 lenData) +{ + WebRtc_UWord32 W_lower; + WebRtc_UWord32 W_upper; + WebRtc_UWord16 W_upper_LSB; + WebRtc_UWord16 W_upper_MSB; + WebRtc_UWord16 *streamPtr; + WebRtc_UWord16 *maxStreamPtr; + WebRtc_UWord16 *streamPtrCarry; + WebRtc_UWord16 negcarry; + WebRtc_UWord32 cdfLo; + WebRtc_UWord32 cdfHi; + int k; + + /* point to beginning of stream buffer + * and set maximum streamPtr value */ + streamPtr = streamData->stream + streamData->stream_index; + maxStreamPtr = streamData->stream + STREAM_MAXW16_60MS - 1; + W_upper = streamData->W_upper; + + for (k = 0; k < lenData; k++) + { + /* compute cdf_lower and cdf_upper by evaluating the + * WebRtcIsacfix_Piecewise linear cdf */ + cdfLo = WebRtcIsacfix_Piecewise(WEBRTC_SPL_MUL_16_U16(*dataQ7 - 64, *envQ8)); + cdfHi = WebRtcIsacfix_Piecewise(WEBRTC_SPL_MUL_16_U16(*dataQ7 + 64, *envQ8)); + + /* test and clip if probability gets too small */ + while ((cdfLo + 1) >= cdfHi) { + /* clip */ + if (*dataQ7 > 0) { + *dataQ7 -= 128; + cdfHi = cdfLo; + cdfLo = WebRtcIsacfix_Piecewise( + WEBRTC_SPL_MUL_16_U16(*dataQ7 - 64, *envQ8)); + } else { + *dataQ7 += 128; + cdfLo = cdfHi; + cdfHi = WebRtcIsacfix_Piecewise( + WEBRTC_SPL_MUL_16_U16(*dataQ7 + 64, *envQ8)); + } + } + + dataQ7++; + /* increment only once per 4 iterations */ + envQ8 += (k & 1) & (k >> 1); + + + /* update interval */ + W_upper_LSB = (WebRtc_UWord16)W_upper; + W_upper_MSB = (WebRtc_UWord16)WEBRTC_SPL_RSHIFT_U32(W_upper, 16); + W_lower = WEBRTC_SPL_UMUL_32_16(cdfLo, W_upper_MSB); + W_lower += WEBRTC_SPL_UMUL_32_16_RSFT16(cdfLo, W_upper_LSB); + W_upper = WEBRTC_SPL_UMUL_32_16(cdfHi, W_upper_MSB); + W_upper += WEBRTC_SPL_UMUL_32_16_RSFT16(cdfHi, W_upper_LSB); + + /* 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 */ + streamPtrCarry = streamPtr; + if (streamData->full == 0) { + negcarry = *streamPtrCarry; + negcarry += 0x0100; + *streamPtrCarry = negcarry; + while (!(negcarry)) + { + negcarry = *--streamPtrCarry; + negcarry++; + *streamPtrCarry = negcarry; + } + } else { + while (!(++(*--streamPtrCarry))); + } + } + + /* renormalize interval, store most significant byte of streamval and update streamval + * W_upper < 2^24 */ + while ( !(W_upper & 0xFF000000) ) + { + W_upper = WEBRTC_SPL_LSHIFT_U32(W_upper, 8); + if (streamData->full == 0) { + *streamPtr++ += (WebRtc_UWord16) WEBRTC_SPL_RSHIFT_U32( + streamData->streamval, 24); + streamData->full = 1; + } else { + *streamPtr = (WebRtc_UWord16) WEBRTC_SPL_LSHIFT_U32( + WEBRTC_SPL_RSHIFT_U32(streamData->streamval, 24), 8); + streamData->full = 0; + } + + if( streamPtr > maxStreamPtr ) + return -ISAC_DISALLOWED_BITSTREAM_LENGTH; + + streamData->streamval = WEBRTC_SPL_LSHIFT_U32(streamData->streamval, 8); + } + } + + /* calculate new stream_index */ + streamData->stream_index = streamPtr - streamData->stream; + streamData->W_upper = W_upper; + + return 0; +} + + +/**************************************************************************** + * WebRtcIsacfix_DecLogisticMulti2(...) + * + * Arithmetic decoding of spectrum. + * + * Input: + * - streamData : in-/output struct containing bitstream + * - envQ8 : side info vector defining the width of the pdf + * in Q8 + * - lenData : data vector length + * + * Input/Output: + * - dataQ7 : input: dither vector, output: data vector + * + * Return value : number of bytes in the stream so far + * -1 if error detected + */ +WebRtc_Word16 WebRtcIsacfix_DecLogisticMulti2(WebRtc_Word16 *dataQ7, + Bitstr_dec *streamData, + const WebRtc_Word32 *envQ8, + const WebRtc_Word16 lenData) +{ + WebRtc_UWord32 W_lower; + WebRtc_UWord32 W_upper; + WebRtc_UWord32 W_tmp; + WebRtc_UWord16 W_upper_LSB; + WebRtc_UWord16 W_upper_MSB; + WebRtc_UWord32 streamVal; + WebRtc_UWord16 cdfTmp; + WebRtc_Word32 res; + WebRtc_Word32 inSqrt; + WebRtc_Word32 newRes; + const WebRtc_UWord16 *streamPtr; + WebRtc_Word16 candQ7; + WebRtc_Word16 envCount; + WebRtc_UWord16 tmpARSpecQ8 = 0; + int k, i; + + + /* point to beginning of stream buffer */ + streamPtr = streamData->stream + streamData->stream_index; + W_upper = streamData->W_upper; + + /* Check if it is first time decoder is called for this stream */ + if (streamData->stream_index == 0) + { + /* read first word from bytestream */ + streamVal = WEBRTC_SPL_LSHIFT_U32(*streamPtr++, 16); + streamVal |= *streamPtr++; + + } else { + streamVal = streamData->streamval; + } + + + res = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)1, + WEBRTC_SPL_RSHIFT_W16(WebRtcSpl_GetSizeInBits(envQ8[0]), 1)); + envCount = 0; + + /* code assumes lenData%4 == 0 */ + for (k = 0; k < lenData; k += 4) + { + int k4; + + /* convert to magnitude spectrum, by doing square-roots (modified from SPLIB) */ + inSqrt = envQ8[envCount]; + i = 10; + + /* For safty reasons */ + if (inSqrt < 0) + inSqrt=-inSqrt; + + newRes = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_DIV(inSqrt, res) + res, 1); + do + { + res = newRes; + newRes = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_DIV(inSqrt, res) + res, 1); + } while (newRes != res && i-- > 0); + + tmpARSpecQ8 = (WebRtc_UWord16)newRes; + + for(k4 = 0; k4 < 4; k4++) + { + /* find the integer *data for which streamVal lies in [W_lower+1, W_upper] */ + W_upper_LSB = (WebRtc_UWord16) (W_upper & 0x0000FFFF); + W_upper_MSB = (WebRtc_UWord16) WEBRTC_SPL_RSHIFT_U32(W_upper, 16); + + /* find first candidate by inverting the logistic cdf + * Input dither value collected from io-stream */ + candQ7 = - *dataQ7 + 64; + cdfTmp = WebRtcIsacfix_Piecewise(WEBRTC_SPL_MUL_16_U16(candQ7, tmpARSpecQ8)); + + W_tmp = WEBRTC_SPL_UMUL_16_16(cdfTmp, W_upper_MSB); + W_tmp += WEBRTC_SPL_UMUL_16_16_RSFT16(cdfTmp, W_upper_LSB); + + if (streamVal > W_tmp) + { + W_lower = W_tmp; + candQ7 += 128; + cdfTmp = WebRtcIsacfix_Piecewise(WEBRTC_SPL_MUL_16_U16(candQ7, tmpARSpecQ8)); + + W_tmp = WEBRTC_SPL_UMUL_16_16(cdfTmp, W_upper_MSB); + W_tmp += WEBRTC_SPL_UMUL_16_16_RSFT16(cdfTmp, W_upper_LSB); + + while (streamVal > W_tmp) + { + W_lower = W_tmp; + candQ7 += 128; + cdfTmp = WebRtcIsacfix_Piecewise( + WEBRTC_SPL_MUL_16_U16(candQ7, tmpARSpecQ8)); + + W_tmp = WEBRTC_SPL_UMUL_16_16(cdfTmp, W_upper_MSB); + W_tmp += WEBRTC_SPL_UMUL_16_16_RSFT16(cdfTmp, W_upper_LSB); + + /* error check */ + if (W_lower == W_tmp) { + return -1; + } + } + W_upper = W_tmp; + + /* Output value put in dataQ7: another sample decoded */ + *dataQ7 = candQ7 - 64; + } + else + { + W_upper = W_tmp; + candQ7 -= 128; + cdfTmp = WebRtcIsacfix_Piecewise(WEBRTC_SPL_MUL_16_U16(candQ7, tmpARSpecQ8)); + + W_tmp = WEBRTC_SPL_UMUL_16_16(cdfTmp, W_upper_MSB); + W_tmp += WEBRTC_SPL_UMUL_16_16_RSFT16(cdfTmp, W_upper_LSB); + + while ( !(streamVal > W_tmp) ) + { + W_upper = W_tmp; + candQ7 -= 128; + cdfTmp = WebRtcIsacfix_Piecewise( + WEBRTC_SPL_MUL_16_U16(candQ7, tmpARSpecQ8)); + + W_tmp = WEBRTC_SPL_UMUL_16_16(cdfTmp, W_upper_MSB); + W_tmp += WEBRTC_SPL_UMUL_16_16_RSFT16(cdfTmp, W_upper_LSB); + + /* error check */ + if (W_upper == W_tmp){ + return -1; + } + } + W_lower = W_tmp; + + /* Output value put in dataQ7: another sample decoded */ + *dataQ7 = candQ7 + 64; + } + + dataQ7++; + + /* shift interval to start at zero */ + W_upper -= ++W_lower; + + /* add integer to bitstream */ + streamVal -= W_lower; + + /* renormalize interval and update streamVal + * W_upper < 2^24 */ + while ( !(W_upper & 0xFF000000) ) + { + /* read next byte from stream */ + if (streamData->full == 0) { + streamVal = WEBRTC_SPL_LSHIFT_W32(streamVal, 8) | (*streamPtr++ & 0x00FF); + streamData->full = 1; + } else { + streamVal = WEBRTC_SPL_LSHIFT_W32(streamVal, 8) | + WEBRTC_SPL_RSHIFT_U16(*streamPtr, 8); + streamData->full = 0; + } + W_upper = WEBRTC_SPL_LSHIFT_W32(W_upper, 8); + } + } + envCount++; + } + + streamData->stream_index = streamPtr - 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 - 3 + !streamData->full); + else + return (streamData->stream_index*2 - 2 + !streamData->full); +} diff --git a/src/modules/audio_coding/codecs/isac/fix/source/arith_routins.h b/src/modules/audio_coding/codecs/isac/fix/source/arith_routins.h new file mode 100644 index 0000000000..9aa49dac7f --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/arith_routins.h @@ -0,0 +1,160 @@ +/* + * 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_routins.h + * + * Functions for arithmetic coding. + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_ARITH_ROUTINS_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_ARITH_ROUTINS_H_ + +#include "structs.h" + + +/**************************************************************************** + * WebRtcIsacfix_EncLogisticMulti2(...) + * + * Arithmetic coding of spectrum. + * + * Input: + * - streamData : in-/output struct containing bitstream + * - dataQ7 : data vector in Q7 + * - envQ8 : side info vector defining the width of the pdf + * in Q8 + * - lenData : data vector length + * + * Return value : 0 if ok, + * <0 otherwise. + */ +int WebRtcIsacfix_EncLogisticMulti2( + Bitstr_enc *streamData, + WebRtc_Word16 *dataQ7, + const WebRtc_UWord16 *env, + const WebRtc_Word16 lenData); + + +/**************************************************************************** + * WebRtcIsacfix_EncTerminate(...) + * + * Final call to the arithmetic coder for an encoder call. This function + * terminates and return byte stream. + * + * Input: + * - streamData : in-/output struct containing bitstream + * + * Return value : number of bytes in the stream + */ +WebRtc_Word16 WebRtcIsacfix_EncTerminate(Bitstr_enc *streamData); + + +/**************************************************************************** + * WebRtcIsacfix_DecLogisticMulti2(...) + * + * Arithmetic decoding of spectrum. + * + * Input: + * - streamData : in-/output struct containing bitstream + * - envQ8 : side info vector defining the width of the pdf + * in Q8 + * - lenData : data vector length + * + * Input/Output: + * - dataQ7 : input: dither vector, output: data vector, in Q7 + * + * Return value : number of bytes in the stream so far + * <0 if error detected + */ +WebRtc_Word16 WebRtcIsacfix_DecLogisticMulti2( + WebRtc_Word16 *data, + Bitstr_dec *streamData, + const WebRtc_Word32 *env, + const WebRtc_Word16 lenData); + + +/**************************************************************************** + * WebRtcIsacfix_EncHistMulti(...) + * + * Encode the histogram interval + * + * Input: + * - streamData : in-/output struct containing bitstream + * - data : data vector + * - cdf : array of cdf arrays + * - lenData : data vector length + * + * Return value : 0 if ok + * <0 if error detected + */ +int WebRtcIsacfix_EncHistMulti( + Bitstr_enc *streamData, + const WebRtc_Word16 *data, + const WebRtc_UWord16 **cdf, + const WebRtc_Word16 lenData); + + +/**************************************************************************** + * WebRtcIsacfix_DecHistBisectMulti(...) + * + * Function to decode more symbols from the arithmetic bytestream, using + * method of bisection. + * C df tables should be of size 2^k-1 (which corresponds to an + * alphabet size of 2^k-2) + * + * Input: + * - streamData : in-/output struct containing bitstream + * - cdf : array of cdf arrays + * - cdfSize : array of cdf table sizes+1 (power of two: 2^k) + * - lenData : data vector length + * + * Output: + * - data : data vector + * + * Return value : number of bytes in the stream + * <0 if error detected + */ +WebRtc_Word16 WebRtcIsacfix_DecHistBisectMulti( + WebRtc_Word16 *data, + Bitstr_dec *streamData, + const WebRtc_UWord16 **cdf, + const WebRtc_UWord16 *cdfSize, + const WebRtc_Word16 lenData); + + +/**************************************************************************** + * WebRtcIsacfix_DecHistOneStepMulti(...) + * + * 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. + * + * Input: + * - streamData : in-/output struct containing bitstream + * - cdf : array of cdf arrays + * - initIndex : vector of initial cdf table search entries + * - lenData : data vector length + * + * Output: + * - data : data vector + * + * Return value : number of bytes in original stream + * <0 if error detected + */ +WebRtc_Word16 WebRtcIsacfix_DecHistOneStepMulti( + WebRtc_Word16 *data, + Bitstr_dec *streamData, + const WebRtc_UWord16 **cdf, + const WebRtc_UWord16 *initIndex, + const WebRtc_Word16 lenData); + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_ARITH_ROUTINS_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/fix/source/bandwidth_estimator.c b/src/modules/audio_coding/codecs/isac/fix/source/bandwidth_estimator.c new file mode 100644 index 0000000000..a274b6671e --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/bandwidth_estimator.c @@ -0,0 +1,1022 @@ +/* + * 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.c + * + * This file contains the code for the Bandwidth Estimator designed + * for iSAC. + * + * NOTE! Castings needed for C55, do not remove! + * + */ + +#include "bandwidth_estimator.h" +#include "settings.h" + + +/* array of quantization levels for bottle neck info; Matlab code: */ +/* sprintf('%4.1ff, ', logspace(log10(5000), log10(40000), 12)) */ +static const WebRtc_Word16 kQRateTable[12] = { + 10000, 11115, 12355, 13733, 15265, 16967, + 18860, 20963, 23301, 25900, 28789, 32000 +}; + +/* 0.1 times the values in the table kQRateTable */ +/* values are in Q16 */ +static const WebRtc_Word32 KQRate01[12] = { + 65536000, 72843264, 80969728, 90000589, 100040704, 111194931, + 123600896, 137383117, 152705434, 169738240, 188671590, 209715200 +}; + +/* Bits per Bytes Seconds + * 8 bits/byte * 1000 msec/sec * 1/framelength (in msec)->bits/byte*sec + * frame length will either be 30 or 60 msec. 8738 is 1/60 in Q19 and 1/30 in Q18 + * The following number is either in Q15 or Q14 depending on the current frame length */ +static const WebRtc_Word32 kBitsByteSec = 4369000; + +/* Received header rate. First value is for 30 ms packets and second for 60 ms */ +static const WebRtc_Word16 kRecHeaderRate[2] = { + 9333, 4666 +}; + +/* Inverted minimum and maximum bandwidth in Q30. + minBwInv 30 ms, maxBwInv 30 ms, + minBwInv 60 ms, maxBwInv 69 ms +*/ +static const WebRtc_Word32 kInvBandwidth[4] = { + 55539, 25978, + 73213, 29284 +}; + +/* Number of samples in 25 msec */ +static const WebRtc_Word32 kSamplesIn25msec = 400; + + +/**************************************************************************** + * WebRtcIsacfix_InitBandwidthEstimator(...) + * + * This function initializes the struct for the bandwidth estimator + * + * Input/Output: + * - bweStr : Struct containing bandwidth information. + * + * Return value : 0 + */ +WebRtc_Word32 WebRtcIsacfix_InitBandwidthEstimator(BwEstimatorstr *bweStr) +{ + bweStr->prevFrameSizeMs = INIT_FRAME_LEN; + bweStr->prevRtpNumber = 0; + bweStr->prevSendTime = 0; + bweStr->prevArrivalTime = 0; + bweStr->prevRtpRate = 1; + bweStr->lastUpdate = 0; + bweStr->lastReduction = 0; + bweStr->countUpdates = -9; + + /* INIT_BN_EST = 20000 + * INIT_BN_EST_Q7 = 2560000 + * INIT_HDR_RATE = 4666 + * INIT_REC_BN_EST_Q5 = 789312 + * + * recBwInv = 1/(INIT_BN_EST + INIT_HDR_RATE) in Q30 + * recBwAvg = INIT_BN_EST + INIT_HDR_RATE in Q5 + */ + bweStr->recBwInv = 43531; + bweStr->recBw = INIT_BN_EST; + bweStr->recBwAvgQ = INIT_BN_EST_Q7; + bweStr->recBwAvg = INIT_REC_BN_EST_Q5; + bweStr->recJitter = (WebRtc_Word32) 327680; /* 10 in Q15 */ + bweStr->recJitterShortTerm = 0; + bweStr->recJitterShortTermAbs = (WebRtc_Word32) 40960; /* 5 in Q13 */ + bweStr->recMaxDelay = (WebRtc_Word32) 10; + bweStr->recMaxDelayAvgQ = (WebRtc_Word32) 5120; /* 10 in Q9 */ + bweStr->recHeaderRate = INIT_HDR_RATE; + bweStr->countRecPkts = 0; + bweStr->sendBwAvg = INIT_BN_EST_Q7; + bweStr->sendMaxDelayAvg = (WebRtc_Word32) 5120; /* 10 in Q9 */ + + bweStr->countHighSpeedRec = 0; + bweStr->highSpeedRec = 0; + bweStr->countHighSpeedSent = 0; + bweStr->highSpeedSend = 0; + bweStr->inWaitPeriod = 0; + + /* Find the inverse of the max bw and min bw in Q30 + * (1 / (MAX_ISAC_BW + INIT_HDR_RATE) in Q30 + * (1 / (MIN_ISAC_BW + INIT_HDR_RATE) in Q30 + */ + bweStr->maxBwInv = kInvBandwidth[3]; + bweStr->minBwInv = kInvBandwidth[2]; + + return 0; +} + +/**************************************************************************** + * WebRtcIsacfix_UpdateUplinkBwImpl(...) + * + * This function updates bottle neck rate received from other side in payload + * and calculates a new bottle neck to send to the other side. + * + * Input/Output: + * - bweStr : struct containing bandwidth information. + * - rtpNumber : value from RTP packet, from NetEq + * - frameSize : length of signal frame in ms, from iSAC decoder + * - sendTime : value in RTP header giving send time in samples + * - arrivalTime : 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 + * + * Return value : 0 if everything went fine, + * -1 otherwise + */ +WebRtc_Word32 WebRtcIsacfix_UpdateUplinkBwImpl(BwEstimatorstr *bweStr, + const WebRtc_UWord16 rtpNumber, + const WebRtc_Word16 frameSize, + const WebRtc_UWord32 sendTime, + const WebRtc_UWord32 arrivalTime, + const WebRtc_Word16 pksize, + const WebRtc_UWord16 Index) +{ + WebRtc_UWord16 weight = 0; + WebRtc_UWord32 currBwInv = 0; + WebRtc_UWord16 recRtpRate; + WebRtc_UWord32 arrTimeProj; + WebRtc_Word32 arrTimeDiff; + WebRtc_Word32 arrTimeNoise; + WebRtc_Word32 arrTimeNoiseAbs; + WebRtc_Word32 sendTimeDiff; + + WebRtc_Word32 delayCorrFactor = DELAY_CORRECTION_MED; + WebRtc_Word32 lateDiff = 0; + WebRtc_Word16 immediateSet = 0; + WebRtc_Word32 frameSizeSampl; + + WebRtc_Word32 temp; + WebRtc_Word32 msec; + WebRtc_UWord32 exponent; + WebRtc_UWord32 reductionFactor; + WebRtc_UWord32 numBytesInv; + WebRtc_Word32 sign; + + WebRtc_UWord32 byteSecondsPerBit; + WebRtc_UWord32 tempLower; + WebRtc_UWord32 tempUpper; + WebRtc_Word32 recBwAvgInv; + WebRtc_Word32 numPktsExpected; + + WebRtc_Word16 errCode; + + /* UPDATE ESTIMATES FROM OTHER SIDE */ + + /* The function also checks if Index has a valid value */ + errCode = WebRtcIsacfix_UpdateUplinkBwRec(bweStr, Index); + if (errCode <0) { + return(errCode); + } + + + /* UPDATE ESTIMATES ON THIS SIDE */ + + /* Bits per second per byte * 1/30 or 1/60 */ + if (frameSize == 60) { + /* If frameSize changed since last call, from 30 to 60, recalculate some values */ + if ( (frameSize != bweStr->prevFrameSizeMs) && (bweStr->countUpdates > 0)) { + bweStr->countUpdates = 10; + bweStr->recHeaderRate = kRecHeaderRate[1]; + + bweStr->maxBwInv = kInvBandwidth[3]; + bweStr->minBwInv = kInvBandwidth[2]; + bweStr->recBwInv = WEBRTC_SPL_UDIV(1073741824, (bweStr->recBw + bweStr->recHeaderRate)); + } + + /* kBitsByteSec is in Q15 */ + recRtpRate = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(kBitsByteSec, + (WebRtc_Word32)pksize), 15) + bweStr->recHeaderRate; + + } else { + /* If frameSize changed since last call, from 60 to 30, recalculate some values */ + if ( (frameSize != bweStr->prevFrameSizeMs) && (bweStr->countUpdates > 0)) { + bweStr->countUpdates = 10; + bweStr->recHeaderRate = kRecHeaderRate[0]; + + bweStr->maxBwInv = kInvBandwidth[1]; + bweStr->minBwInv = kInvBandwidth[0]; + bweStr->recBwInv = WEBRTC_SPL_UDIV(1073741824, (bweStr->recBw + bweStr->recHeaderRate)); + } + + /* kBitsByteSec is in Q14 */ + recRtpRate = (WebRtc_UWord16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(kBitsByteSec, + (WebRtc_Word32)pksize), 14) + bweStr->recHeaderRate; + } + + + /* Check for timer wrap-around */ + if (arrivalTime < bweStr->prevArrivalTime) { + bweStr->prevArrivalTime = arrivalTime; + bweStr->lastUpdate = arrivalTime; + bweStr->lastReduction = arrivalTime + FS3; + + bweStr->countRecPkts = 0; + + /* store frame size */ + bweStr->prevFrameSizeMs = frameSize; + + /* store far-side transmission rate */ + bweStr->prevRtpRate = recRtpRate; + + /* store far-side RTP time stamp */ + bweStr->prevRtpNumber = rtpNumber; + + return 0; + } + + bweStr->countRecPkts++; + + /* Calculate framesize in msec */ + frameSizeSampl = WEBRTC_SPL_MUL_16_16((WebRtc_Word16)SAMPLES_PER_MSEC, frameSize); + + /* Check that it's not one of the first 9 packets */ + if ( bweStr->countUpdates > 0 ) { + + /* Stay in Wait Period for 1.5 seconds (no updates in wait period) */ + if(bweStr->inWaitPeriod) { + if ((arrivalTime - bweStr->startWaitPeriod)> FS_1_HALF) { + bweStr->inWaitPeriod = 0; + } + } + + /* If not been updated for a long time, reduce the BN estimate */ + + /* Check send time difference between this packet and previous received */ + sendTimeDiff = sendTime - bweStr->prevSendTime; + if (sendTimeDiff <= WEBRTC_SPL_LSHIFT_W32(frameSizeSampl, 1)) { + + /* Only update if 3 seconds has past since last update */ + if ((arrivalTime - bweStr->lastUpdate) > FS3) { + + /* Calculate expected number of received packets since last update */ + numPktsExpected = WEBRTC_SPL_UDIV(arrivalTime - bweStr->lastUpdate, frameSizeSampl); + + /* If received number of packets is more than 90% of expected (922 = 0.9 in Q10): */ + /* do the update, else not */ + if(WEBRTC_SPL_LSHIFT_W32(bweStr->countRecPkts, 10) > WEBRTC_SPL_MUL_16_16(922, numPktsExpected)) { + /* Q4 chosen to approx dividing by 16 */ + msec = (arrivalTime - bweStr->lastReduction); + + /* the number below represents 13 seconds, highly unlikely + but to insure no overflow when reduction factor is multiplied by recBw inverse */ + if (msec > 208000) { + msec = 208000; + } + + /* Q20 2^(negative number: - 76/1048576) = .99995 + product is Q24 */ + exponent = WEBRTC_SPL_UMUL(0x0000004C, msec); + + /* do the approx with positive exponent so that value is actually rf^-1 + and multiply by bw inverse */ + reductionFactor = WEBRTC_SPL_RSHIFT_U32(0x01000000 | (exponent & 0x00FFFFFF), + WEBRTC_SPL_RSHIFT_U32(exponent, 24)); + + /* reductionFactor in Q13 */ + reductionFactor = WEBRTC_SPL_RSHIFT_U32(reductionFactor, 11); + + if ( reductionFactor != 0 ) { + bweStr->recBwInv = WEBRTC_SPL_MUL((WebRtc_Word32)bweStr->recBwInv, (WebRtc_Word32)reductionFactor); + bweStr->recBwInv = WEBRTC_SPL_RSHIFT_W32((WebRtc_Word32)bweStr->recBwInv, 13); + + } else { + /* recBwInv = 1 / (INIT_BN_EST + INIT_HDR_RATE) in Q26 (Q30??)*/ + bweStr->recBwInv = WEBRTC_SPL_DIV((1073741824 + + WEBRTC_SPL_LSHIFT_W32(((WebRtc_Word32)INIT_BN_EST + INIT_HDR_RATE), 1)), INIT_BN_EST + INIT_HDR_RATE); + } + + /* reset time-since-update counter */ + bweStr->lastReduction = arrivalTime; + } else { + /* Delay last reduction with 3 seconds */ + bweStr->lastReduction = arrivalTime + FS3; + bweStr->lastUpdate = arrivalTime; + bweStr->countRecPkts = 0; + } + } + } else { + bweStr->lastReduction = arrivalTime + FS3; + bweStr->lastUpdate = arrivalTime; + bweStr->countRecPkts = 0; + } + + + /* update only if previous packet was not lost */ + if ( rtpNumber == bweStr->prevRtpNumber + 1 ) { + arrTimeDiff = arrivalTime - bweStr->prevArrivalTime; + + if (!(bweStr->highSpeedSend && bweStr->highSpeedRec)) { + if (arrTimeDiff > frameSizeSampl) { + if (sendTimeDiff > 0) { + lateDiff = arrTimeDiff - sendTimeDiff - + WEBRTC_SPL_LSHIFT_W32(frameSizeSampl, 1); + } else { + lateDiff = arrTimeDiff - frameSizeSampl; + } + + /* 8000 is 1/2 second (in samples at FS) */ + if (lateDiff > 8000) { + delayCorrFactor = (WebRtc_Word32) DELAY_CORRECTION_MAX; + bweStr->inWaitPeriod = 1; + bweStr->startWaitPeriod = arrivalTime; + immediateSet = 1; + } else if (lateDiff > 5120) { + delayCorrFactor = (WebRtc_Word32) DELAY_CORRECTION_MED; + immediateSet = 1; + bweStr->inWaitPeriod = 1; + bweStr->startWaitPeriod = arrivalTime; + } + } + } + + if ((bweStr->prevRtpRate > WEBRTC_SPL_RSHIFT_W32((WebRtc_Word32) bweStr->recBwAvg, 5)) && + (recRtpRate > WEBRTC_SPL_RSHIFT_W32((WebRtc_Word32)bweStr->recBwAvg, 5)) && + !bweStr->inWaitPeriod) { + + /* test if still in initiation period and increment counter */ + if (bweStr->countUpdates++ > 99) { + /* constant weight after initiation part, 0.01 in Q13 */ + weight = (WebRtc_UWord16) 82; + } else { + /* weight decreases with number of updates, 1/countUpdates in Q13 */ + weight = (WebRtc_UWord16) WebRtcSpl_DivW32W16( + (WebRtc_Word32)(8192 + WEBRTC_SPL_RSHIFT_W32((WebRtc_Word32) bweStr->countUpdates, 1)), + (WebRtc_Word16)bweStr->countUpdates); + } + + /* Bottle Neck Estimation */ + + /* limit outliers, if more than 25 ms too much */ + if (arrTimeDiff > frameSizeSampl + kSamplesIn25msec) { + arrTimeDiff = frameSizeSampl + kSamplesIn25msec; + } + + /* don't allow it to be less than frame rate - 10 ms */ + if (arrTimeDiff < frameSizeSampl - FRAMESAMPLES_10ms) { + arrTimeDiff = frameSizeSampl - FRAMESAMPLES_10ms; + } + + /* compute inverse receiving rate for last packet, in Q19 */ + numBytesInv = (WebRtc_UWord16) WebRtcSpl_DivW32W16( + (WebRtc_Word32)(524288 + WEBRTC_SPL_RSHIFT_W32(((WebRtc_Word32)pksize + HEADER_SIZE), 1)), + (WebRtc_Word16)(pksize + HEADER_SIZE)); + + /* 8389 is ~ 1/128000 in Q30 */ + byteSecondsPerBit = WEBRTC_SPL_MUL_16_16(arrTimeDiff, 8389); + + /* get upper N bits */ + tempUpper = WEBRTC_SPL_RSHIFT_U32(byteSecondsPerBit, 15); + + /* get lower 15 bits */ + tempLower = byteSecondsPerBit & 0x00007FFF; + + tempUpper = WEBRTC_SPL_MUL(tempUpper, numBytesInv); + tempLower = WEBRTC_SPL_MUL(tempLower, numBytesInv); + tempLower = WEBRTC_SPL_RSHIFT_U32(tempLower, 15); + + currBwInv = tempUpper + tempLower; + currBwInv = WEBRTC_SPL_RSHIFT_U32(currBwInv, 4); + + /* Limit inv rate. Note that minBwInv > maxBwInv! */ + if(currBwInv < bweStr->maxBwInv) { + currBwInv = bweStr->maxBwInv; + } else if(currBwInv > bweStr->minBwInv) { + currBwInv = bweStr->minBwInv; + } + + /* update bottle neck rate estimate */ + bweStr->recBwInv = WEBRTC_SPL_UMUL(weight, currBwInv) + + WEBRTC_SPL_UMUL((WebRtc_UWord32) 8192 - weight, bweStr->recBwInv); + + /* Shift back to Q30 from Q40 (actual used bits shouldn't be more than 27 based on minBwInv) + up to 30 bits used with Q13 weight */ + bweStr->recBwInv = WEBRTC_SPL_RSHIFT_U32(bweStr->recBwInv, 13); + + /* reset time-since-update counter */ + bweStr->lastUpdate = arrivalTime; + bweStr->lastReduction = arrivalTime + FS3; + bweStr->countRecPkts = 0; + + /* to save resolution compute the inverse of recBwAvg in Q26 by left shifting numerator to 2^31 + and NOT right shifting recBwAvg 5 bits to an integer + At max 13 bits are used + shift to Q5 */ + recBwAvgInv = WEBRTC_SPL_UDIV((WebRtc_UWord32)(0x80000000 + WEBRTC_SPL_RSHIFT_U32(bweStr->recBwAvg, 1)), + bweStr->recBwAvg); + + /* Calculate Projected arrival time difference */ + + /* The numerator of the quotient can be 22 bits so right shift inv by 4 to avoid overflow + result in Q22 */ + arrTimeProj = WEBRTC_SPL_MUL((WebRtc_Word32)8000, recBwAvgInv); + /* shift to Q22 */ + arrTimeProj = WEBRTC_SPL_RSHIFT_U32(arrTimeProj, 4); + /* complete calulation */ + arrTimeProj = WEBRTC_SPL_MUL(((WebRtc_Word32)pksize + HEADER_SIZE), arrTimeProj); + /* shift to Q10 */ + arrTimeProj = WEBRTC_SPL_RSHIFT_U32(arrTimeProj, 12); + + /* difference between projected and actual arrival time differences */ + /* Q9 (only shift arrTimeDiff by 5 to simulate divide by 16 (need to revisit if change sampling rate) DH */ + if (WEBRTC_SPL_LSHIFT_W32(arrTimeDiff, 6) > (WebRtc_Word32)arrTimeProj) { + arrTimeNoise = WEBRTC_SPL_LSHIFT_W32(arrTimeDiff, 6) - arrTimeProj; + sign = 1; + } else { + arrTimeNoise = arrTimeProj - WEBRTC_SPL_LSHIFT_W32(arrTimeDiff, 6); + sign = -1; + } + + /* Q9 */ + arrTimeNoiseAbs = arrTimeNoise; + + /* long term averaged absolute jitter, Q15 */ + weight = WEBRTC_SPL_RSHIFT_W32(weight, 3); + bweStr->recJitter = WEBRTC_SPL_MUL(weight, WEBRTC_SPL_LSHIFT_W32(arrTimeNoiseAbs, 5)) + + WEBRTC_SPL_MUL(1024 - weight, bweStr->recJitter); + + /* remove the fractional portion */ + bweStr->recJitter = WEBRTC_SPL_RSHIFT_W32(bweStr->recJitter, 10); + + /* Maximum jitter is 10 msec in Q15 */ + if (bweStr->recJitter > (WebRtc_Word32)327680) { + bweStr->recJitter = (WebRtc_Word32)327680; + } + + /* short term averaged absolute jitter */ + /* Calculation in Q13 products in Q23 */ + bweStr->recJitterShortTermAbs = WEBRTC_SPL_MUL(51, WEBRTC_SPL_LSHIFT_W32(arrTimeNoiseAbs, 3)) + + WEBRTC_SPL_MUL(973, bweStr->recJitterShortTermAbs); + bweStr->recJitterShortTermAbs = WEBRTC_SPL_RSHIFT_W32(bweStr->recJitterShortTermAbs , 10); + + /* short term averaged jitter */ + /* Calculation in Q13 products in Q23 */ + bweStr->recJitterShortTerm = WEBRTC_SPL_MUL(205, WEBRTC_SPL_LSHIFT_W32(arrTimeNoise, 3)) * sign + + WEBRTC_SPL_MUL(3891, bweStr->recJitterShortTerm); + + if (bweStr->recJitterShortTerm < 0) { + temp = -bweStr->recJitterShortTerm; + temp = WEBRTC_SPL_RSHIFT_W32(temp, 12); + bweStr->recJitterShortTerm = -temp; + } else { + bweStr->recJitterShortTerm = WEBRTC_SPL_RSHIFT_W32(bweStr->recJitterShortTerm, 12); + } + } + } + } else { + /* reset time-since-update counter when receiving the first 9 packets */ + bweStr->lastUpdate = arrivalTime; + bweStr->lastReduction = arrivalTime + FS3; + bweStr->countRecPkts = 0; + bweStr->countUpdates++; + } + + /* Limit to minimum or maximum bottle neck rate (in Q30) */ + if (bweStr->recBwInv > bweStr->minBwInv) { + bweStr->recBwInv = bweStr->minBwInv; + } else if (bweStr->recBwInv < bweStr->maxBwInv) { + bweStr->recBwInv = bweStr->maxBwInv; + } + + + /* store frame length */ + bweStr->prevFrameSizeMs = frameSize; + + /* store far-side transmission rate */ + bweStr->prevRtpRate = recRtpRate; + + /* store far-side RTP time stamp */ + bweStr->prevRtpNumber = rtpNumber; + + /* Replace bweStr->recMaxDelay by the new value (atomic operation) */ + if (bweStr->prevArrivalTime != 0xffffffff) { + bweStr->recMaxDelay = WEBRTC_SPL_MUL(3, bweStr->recJitter); + } + + /* store arrival time stamp */ + bweStr->prevArrivalTime = arrivalTime; + bweStr->prevSendTime = sendTime; + + /* Replace bweStr->recBw by the new value */ + bweStr->recBw = WEBRTC_SPL_UDIV(1073741824, bweStr->recBwInv) - bweStr->recHeaderRate; + + if (immediateSet) { + /* delay correction factor is in Q10 */ + bweStr->recBw = WEBRTC_SPL_UMUL(delayCorrFactor, bweStr->recBw); + bweStr->recBw = WEBRTC_SPL_RSHIFT_U32(bweStr->recBw, 10); + + if (bweStr->recBw < (WebRtc_Word32) MIN_ISAC_BW) { + bweStr->recBw = (WebRtc_Word32) MIN_ISAC_BW; + } + + bweStr->recBwAvg = WEBRTC_SPL_LSHIFT_U32(bweStr->recBw + bweStr->recHeaderRate, 5); + + bweStr->recBwAvgQ = WEBRTC_SPL_LSHIFT_U32(bweStr->recBw, 7); + + bweStr->recJitterShortTerm = 0; + + bweStr->recBwInv = WEBRTC_SPL_UDIV(1073741824, bweStr->recBw + bweStr->recHeaderRate); + + immediateSet = 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 WebRtcIsacfix_UpdateUplinkBwRec(BwEstimatorstr *bweStr, + const WebRtc_Word16 Index) +{ + WebRtc_UWord16 RateInd; + + if ( (Index < 0) || (Index > 23) ) { + return -ISAC_RANGE_ERROR_BW_ESTIMATOR; + } + + /* UPDATE ESTIMATES FROM OTHER SIDE */ + + if ( Index > 11 ) { + RateInd = Index - 12; + /* compute the jitter estimate as decoded on the other side in Q9 */ + /* sendMaxDelayAvg = 0.9 * sendMaxDelayAvg + 0.1 * MAX_ISAC_MD */ + bweStr->sendMaxDelayAvg = WEBRTC_SPL_MUL(461, bweStr->sendMaxDelayAvg) + + WEBRTC_SPL_MUL(51, WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)MAX_ISAC_MD, 9)); + bweStr->sendMaxDelayAvg = WEBRTC_SPL_RSHIFT_W32(bweStr->sendMaxDelayAvg, 9); + + } else { + RateInd = Index; + /* compute the jitter estimate as decoded on the other side in Q9 */ + /* sendMaxDelayAvg = 0.9 * sendMaxDelayAvg + 0.1 * MIN_ISAC_MD */ + bweStr->sendMaxDelayAvg = WEBRTC_SPL_MUL(461, bweStr->sendMaxDelayAvg) + + WEBRTC_SPL_MUL(51, WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)MIN_ISAC_MD,9)); + bweStr->sendMaxDelayAvg = WEBRTC_SPL_RSHIFT_W32(bweStr->sendMaxDelayAvg, 9); + + } + + + /* compute the BN estimate as decoded on the other side */ + /* sendBwAvg = 0.9 * sendBwAvg + 0.1 * kQRateTable[RateInd]; */ + bweStr->sendBwAvg = WEBRTC_SPL_UMUL(461, bweStr->sendBwAvg) + + WEBRTC_SPL_UMUL(51, WEBRTC_SPL_LSHIFT_U32(kQRateTable[RateInd], 7)); + bweStr->sendBwAvg = WEBRTC_SPL_RSHIFT_U32(bweStr->sendBwAvg, 9); + + + if (WEBRTC_SPL_RSHIFT_U32(bweStr->sendBwAvg, 7) > 28000 && !bweStr->highSpeedSend) { + bweStr->countHighSpeedSent++; + + /* approx 2 seconds with 30ms frames */ + if (bweStr->countHighSpeedSent >= 66) { + bweStr->highSpeedSend = 1; + } + } else if (!bweStr->highSpeedSend) { + bweStr->countHighSpeedSent = 0; + } + + return 0; +} + +/**************************************************************************** + * WebRtcIsacfix_GetDownlinkBwIndexImpl(...) + * + * This function calculates and returns the bandwidth/jitter estimation code + * (integer 0...23) to put in the sending iSAC payload. + * + * Input: + * - bweStr : BWE struct + * + * Return: + * bandwith and jitter index (0..23) + */ +WebRtc_UWord16 WebRtcIsacfix_GetDownlinkBwIndexImpl(BwEstimatorstr *bweStr) +{ + WebRtc_Word32 rate; + WebRtc_Word32 maxDelay; + WebRtc_UWord16 rateInd; + WebRtc_UWord16 maxDelayBit; + WebRtc_Word32 tempTerm1; + WebRtc_Word32 tempTerm2; + WebRtc_Word32 tempTermX; + WebRtc_Word32 tempTermY; + WebRtc_Word32 tempMin; + WebRtc_Word32 tempMax; + + /* Get Rate Index */ + + /* Get unquantized rate. Always returns 10000 <= rate <= 32000 */ + rate = WebRtcIsacfix_GetDownlinkBandwidth(bweStr); + + /* Compute the averaged BN estimate on this side */ + + /* recBwAvg = 0.9 * recBwAvg + 0.1 * (rate + bweStr->recHeaderRate), 0.9 and 0.1 in Q9 */ + bweStr->recBwAvg = WEBRTC_SPL_UMUL(922, bweStr->recBwAvg) + + WEBRTC_SPL_UMUL(102, WEBRTC_SPL_LSHIFT_U32((WebRtc_UWord32)rate + bweStr->recHeaderRate, 5)); + bweStr->recBwAvg = WEBRTC_SPL_RSHIFT_U32(bweStr->recBwAvg, 10); + + /* find quantization index that gives the closest rate after averaging */ + for (rateInd = 1; rateInd < 12; rateInd++) { + if (rate <= kQRateTable[rateInd]){ + break; + } + } + + /* find closest quantization index, and update quantized average by taking: */ + /* 0.9*recBwAvgQ + 0.1*kQRateTable[rateInd] */ + + /* 0.9 times recBwAvgQ in Q16 */ + /* 461/512 - 25/65536 =0.900009 */ + tempTerm1 = WEBRTC_SPL_MUL(bweStr->recBwAvgQ, 25); + tempTerm1 = WEBRTC_SPL_RSHIFT_W32(tempTerm1, 7); + tempTermX = WEBRTC_SPL_UMUL(461, bweStr->recBwAvgQ) - tempTerm1; + + /* rate in Q16 */ + tempTermY = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)rate, 16); + + /* 0.1 * kQRateTable[rateInd] = KQRate01[rateInd] */ + tempTerm1 = tempTermX + KQRate01[rateInd] - tempTermY; + tempTerm2 = tempTermY - tempTermX - KQRate01[rateInd-1]; + + /* Compare (0.9 * recBwAvgQ + 0.1 * kQRateTable[rateInd] - rate) > + (rate - 0.9 * recBwAvgQ - 0.1 * kQRateTable[rateInd-1]) */ + if (tempTerm1 > tempTerm2) { + rateInd--; + } + + /* Update quantized average by taking: */ + /* 0.9*recBwAvgQ + 0.1*kQRateTable[rateInd] */ + + /* Add 0.1 times kQRateTable[rateInd], in Q16 */ + tempTermX += KQRate01[rateInd]; + + /* Shift back to Q7 */ + bweStr->recBwAvgQ = WEBRTC_SPL_RSHIFT_W32(tempTermX, 9); + + /* Count consecutive received bandwidth above 28000 kbps (28000 in Q7 = 3584000) */ + /* If 66 high estimates in a row, set highSpeedRec to one */ + /* 66 corresponds to ~2 seconds in 30 msec mode */ + if ((bweStr->recBwAvgQ > 3584000) && !bweStr->highSpeedRec) { + bweStr->countHighSpeedRec++; + if (bweStr->countHighSpeedRec >= 66) { + bweStr->highSpeedRec = 1; + } + } else if (!bweStr->highSpeedRec) { + bweStr->countHighSpeedRec = 0; + } + + /* Get Max Delay Bit */ + + /* get unquantized max delay */ + maxDelay = WebRtcIsacfix_GetDownlinkMaxDelay(bweStr); + + /* Update quantized max delay average */ + tempMax = 652800; /* MAX_ISAC_MD * 0.1 in Q18 */ + tempMin = 130560; /* MIN_ISAC_MD * 0.1 in Q18 */ + tempTermX = WEBRTC_SPL_MUL((WebRtc_Word32)bweStr->recMaxDelayAvgQ, (WebRtc_Word32)461); + tempTermY = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)maxDelay, 18); + + tempTerm1 = tempTermX + tempMax - tempTermY; + tempTerm2 = tempTermY - tempTermX - tempMin; + + if ( tempTerm1 > tempTerm2) { + maxDelayBit = 0; + tempTerm1 = tempTermX + tempMin; + + /* update quantized average, shift back to Q9 */ + bweStr->recMaxDelayAvgQ = WEBRTC_SPL_RSHIFT_W32(tempTerm1, 9); + } else { + maxDelayBit = 12; + tempTerm1 = tempTermX + tempMax; + + /* update quantized average, shift back to Q9 */ + bweStr->recMaxDelayAvgQ = WEBRTC_SPL_RSHIFT_W32(tempTerm1, 9); + } + + /* Return bandwitdh and jitter index (0..23) */ + return (WebRtc_UWord16)(rateInd + maxDelayBit); +} + +/* get the bottle neck rate from far side to here, as estimated on this side */ +WebRtc_UWord16 WebRtcIsacfix_GetDownlinkBandwidth(const BwEstimatorstr *bweStr) +{ + WebRtc_UWord32 recBw; + WebRtc_Word32 jitter_sign; /* Q8 */ + WebRtc_Word32 bw_adjust; /* Q16 */ + WebRtc_Word32 rec_jitter_short_term_abs_inv; /* Q18 */ + WebRtc_Word32 temp; + + /* Q18 rec jitter short term abs is in Q13, multiply it by 2^13 to save precision + 2^18 then needs to be shifted 13 bits to 2^31 */ + rec_jitter_short_term_abs_inv = WEBRTC_SPL_UDIV(0x80000000, bweStr->recJitterShortTermAbs); + + /* Q27 = 9 + 18 */ + jitter_sign = WEBRTC_SPL_MUL(WEBRTC_SPL_RSHIFT_W32(bweStr->recJitterShortTerm, 4), (WebRtc_Word32)rec_jitter_short_term_abs_inv); + + if (jitter_sign < 0) { + temp = -jitter_sign; + temp = WEBRTC_SPL_RSHIFT_W32(temp, 19); + jitter_sign = -temp; + } else { + jitter_sign = WEBRTC_SPL_RSHIFT_W32(jitter_sign, 19); + } + + /* adjust bw proportionally to negative average jitter sign */ + //bw_adjust = 1.0f - jitter_sign * (0.15f + 0.15f * jitter_sign * jitter_sign); + //Q8 -> Q16 .15 +.15 * jitter^2 first term is .15 in Q16 latter term is Q8*Q8*Q8 + //38 in Q8 ~.15 9830 in Q16 ~.15 + temp = 9830 + WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL(38, WEBRTC_SPL_MUL(jitter_sign, jitter_sign))), 8); + + if (jitter_sign < 0) { + temp = WEBRTC_SPL_MUL(jitter_sign, temp); + temp = -temp; + temp = WEBRTC_SPL_RSHIFT_W32(temp, 8); + bw_adjust = (WebRtc_UWord32)65536 + temp; /* (1 << 16) + temp; */ + } else { + bw_adjust = (WebRtc_UWord32)65536 - WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(jitter_sign, temp), 8);/* (1 << 16) - ((jitter_sign * temp) >> 8); */ + } + + //make sure following multiplication won't overflow + //bw adjust now Q14 + bw_adjust = WEBRTC_SPL_RSHIFT_W32(bw_adjust, 2);//see if good resolution is maintained + + /* adjust Rate if jitter sign is mostly constant */ + recBw = WEBRTC_SPL_UMUL(bweStr->recBw, bw_adjust); + + recBw = WEBRTC_SPL_RSHIFT_W32(recBw, 14); + + /* limit range of bottle neck rate */ + if (recBw < MIN_ISAC_BW) { + recBw = MIN_ISAC_BW; + } else if (recBw > MAX_ISAC_BW) { + recBw = MAX_ISAC_BW; + } + + return (WebRtc_UWord16) recBw; +} + +/* Returns the mmax delay (in ms) */ +WebRtc_Word16 WebRtcIsacfix_GetDownlinkMaxDelay(const BwEstimatorstr *bweStr) +{ + WebRtc_Word16 recMaxDelay; + + recMaxDelay = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(bweStr->recMaxDelay, 15); + + /* limit range of jitter estimate */ + if (recMaxDelay < MIN_ISAC_MD) { + recMaxDelay = MIN_ISAC_MD; + } else if (recMaxDelay > MAX_ISAC_MD) { + recMaxDelay = MAX_ISAC_MD; + } + + return recMaxDelay; +} + +/* get the bottle neck rate from here to far side, as estimated by far side */ +WebRtc_Word16 WebRtcIsacfix_GetUplinkBandwidth(const BwEstimatorstr *bweStr) +{ + WebRtc_Word16 send_bw; + + send_bw = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_U32(bweStr->sendBwAvg, 7); + + /* limit range of bottle neck rate */ + if (send_bw < MIN_ISAC_BW) { + send_bw = MIN_ISAC_BW; + } else if (send_bw > MAX_ISAC_BW) { + send_bw = MAX_ISAC_BW; + } + + return send_bw; +} + + + +/* Returns the max delay value from the other side in ms */ +WebRtc_Word16 WebRtcIsacfix_GetUplinkMaxDelay(const BwEstimatorstr *bweStr) +{ + WebRtc_Word16 send_max_delay; + + send_max_delay = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(bweStr->sendMaxDelayAvg, 9); + + /* 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) + */ +WebRtc_UWord16 WebRtcIsacfix_GetMinBytes(RateModel *State, + WebRtc_Word16 StreamSize, /* bytes in bitstream */ + const WebRtc_Word16 FrameSamples, /* samples per frame */ + const WebRtc_Word16 BottleNeck, /* bottle neck rate; excl headers (bps) */ + const WebRtc_Word16 DelayBuildUp) /* max delay from bottle neck buffering (ms) */ +{ + WebRtc_Word32 MinRate = 0; + WebRtc_UWord16 MinBytes; + WebRtc_Word16 TransmissionTime; + WebRtc_Word32 inv_Q12; + WebRtc_Word32 den; + + + /* 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) { + MinRate = INIT_RATE; + } else { + MinRate = 0; + } + } else { + /* handle burst */ + if (State->BurstCounter) { + if (State->StillBuffered < WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL((512 - WEBRTC_SPL_DIV(512, BURST_LEN)), DelayBuildUp), 9)) { + /* max bps derived from BottleNeck and DelayBuildUp values */ + inv_Q12 = WEBRTC_SPL_DIV(4096, WEBRTC_SPL_MUL(BURST_LEN, FrameSamples)); + MinRate = WEBRTC_SPL_MUL(512 + WEBRTC_SPL_MUL(SAMPLES_PER_MSEC, WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(DelayBuildUp, inv_Q12), 3)), BottleNeck); + } else { + /* max bps derived from StillBuffered and DelayBuildUp values */ + inv_Q12 = WEBRTC_SPL_DIV(4096, FrameSamples); + if (DelayBuildUp > State->StillBuffered) { + MinRate = WEBRTC_SPL_MUL(512 + WEBRTC_SPL_MUL(SAMPLES_PER_MSEC, WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(DelayBuildUp - State->StillBuffered, inv_Q12), 3)), BottleNeck); + } else if ((den = WEBRTC_SPL_MUL(SAMPLES_PER_MSEC, (State->StillBuffered - DelayBuildUp))) >= FrameSamples) { + /* MinRate will be negative here */ + MinRate = 0; + } else { + MinRate = WEBRTC_SPL_MUL((512 - WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(den, inv_Q12), 3)), BottleNeck); + } + //if (MinRate < 1.04 * BottleNeck) + // MinRate = 1.04 * BottleNeck; + //Q9 + if (MinRate < WEBRTC_SPL_MUL(532, BottleNeck)) { + MinRate += WEBRTC_SPL_MUL(22, BottleNeck); + } + } + + State->BurstCounter--; + } + } + + + /* convert rate from bits/second to bytes/packet */ + //round and shift before conversion + MinRate += 256; + MinRate = WEBRTC_SPL_RSHIFT_W32(MinRate, 9); + MinBytes = (WebRtc_UWord16)WEBRTC_SPL_UDIV(WEBRTC_SPL_MUL(MinRate, FrameSamples), FS8); + + /* 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% */ + //517/512 ~ 1.01 + if (WEBRTC_SPL_DIV(WEBRTC_SPL_MUL(StreamSize, FS8), FrameSamples) > (WEBRTC_SPL_MUL(517, BottleNeck) >> 9)) { + if (State->PrevExceed) { + /* bottle_neck exceded twice in a row, decrease ExceedAgo */ + State->ExceedAgo -= WEBRTC_SPL_DIV(BURST_INTERVAL, BURST_LEN - 1); + if (State->ExceedAgo < 0) { + State->ExceedAgo = 0; + } + } else { + State->ExceedAgo += (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W16(FrameSamples, 4); /* ms */ + State->PrevExceed = 1; + } + } else { + State->PrevExceed = 0; + State->ExceedAgo += (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W16(FrameSamples, 4); /* ms */ + } + + /* set burst flag if bottle neck not exceeded for long time */ + if ((State->ExceedAgo > BURST_INTERVAL) && (State->BurstCounter == 0)) { + if (State->PrevExceed) { + State->BurstCounter = BURST_LEN - 1; + } else { + State->BurstCounter = BURST_LEN; + } + } + + + /* Update buffer delay */ + TransmissionTime = (WebRtc_Word16)WEBRTC_SPL_DIV(WEBRTC_SPL_MUL(StreamSize, 8000), BottleNeck); /* ms */ + State->StillBuffered += TransmissionTime; + State->StillBuffered -= (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W16(FrameSamples, 4); //>>4 = SAMPLES_PER_MSEC /* ms */ + if (State->StillBuffered < 0) { + State->StillBuffered = 0; + } + + if (State->StillBuffered > 2000) { + State->StillBuffered = 2000; + } + + return MinBytes; +} + + +/* + * update long-term average bitrate and amount of data in buffer + */ +void WebRtcIsacfix_UpdateRateModel(RateModel *State, + WebRtc_Word16 StreamSize, /* bytes in bitstream */ + const WebRtc_Word16 FrameSamples, /* samples per frame */ + const WebRtc_Word16 BottleNeck) /* bottle neck rate; excl headers (bps) */ +{ + WebRtc_Word16 TransmissionTime; + + /* avoid the initial "high-rate" burst */ + State->InitCounter = 0; + + /* Update buffer delay */ + TransmissionTime = (WebRtc_Word16)WEBRTC_SPL_DIV(WEBRTC_SPL_MUL(WEBRTC_SPL_MUL(StreamSize, 8), 1000), BottleNeck); /* ms */ + State->StillBuffered += TransmissionTime; + State->StillBuffered -= (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W16(FrameSamples, 4); /* ms */ + if (State->StillBuffered < 0) { + State->StillBuffered = 0; + } + +} + + +void WebRtcIsacfix_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; /* ms */ +} + + + + + +WebRtc_Word16 WebRtcIsacfix_GetNewFrameLength(WebRtc_Word16 bottle_neck, WebRtc_Word16 current_framesamples) +{ + WebRtc_Word16 new_framesamples; + + new_framesamples = current_framesamples; + + /* find new framelength */ + switch(current_framesamples) { + case 480: + if (bottle_neck < Thld_30_60) { + new_framesamples = 960; + } + break; + case 960: + if (bottle_neck >= Thld_60_30) { + new_framesamples = 480; + } + break; + default: + new_framesamples = -1; /* Error */ + } + + return new_framesamples; +} + +WebRtc_Word16 WebRtcIsacfix_GetSnr(WebRtc_Word16 bottle_neck, WebRtc_Word16 framesamples) +{ + WebRtc_Word16 s2nr = 0; + + /* find new SNR value */ + //consider BottleNeck to be in Q10 ( * 1 in Q10) + switch(framesamples) { + case 480: + /*s2nr = -1*(a_30 << 10) + ((b_30 * bottle_neck) >> 10);*/ + s2nr = -22500 + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(500, bottle_neck, 10); //* 0.001; //+ c_30 * bottle_neck * bottle_neck * 0.000001; + break; + case 960: + /*s2nr = -1*(a_60 << 10) + ((b_60 * bottle_neck) >> 10);*/ + s2nr = -22500 + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(500, bottle_neck, 10); //* 0.001; //+ c_30 * bottle_neck * bottle_neck * 0.000001; + break; + default: + s2nr = -1; /* Error */ + } + + return s2nr; //return in Q10 + +} diff --git a/src/modules/audio_coding/codecs/isac/fix/source/bandwidth_estimator.h b/src/modules/audio_coding/codecs/isac/fix/source/bandwidth_estimator.h new file mode 100644 index 0000000000..76a50f8238 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/bandwidth_estimator.h @@ -0,0 +1,127 @@ +/* + * 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_FIX_SOURCE_BANDWIDTH_ESTIMATOR_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_BANDWIDTH_ESTIMATOR_H_ + +#include "structs.h" + + +/**************************************************************************** + * WebRtcIsacfix_InitBandwidthEstimator(...) + * + * This function initializes the struct for the bandwidth estimator + * + * Input/Output: + * - bwest_str : Struct containing bandwidth information. + * + * Return value : 0 + */ + +WebRtc_Word32 WebRtcIsacfix_InitBandwidthEstimator(BwEstimatorstr *bwest_str); + + +/**************************************************************************** + * WebRtcIsacfix_UpdateUplinkBwImpl(...) + * + * This function updates bottle neck rate received from other side in payload + * and calculates a new bottle neck to send to the other side. + * + * Input/Output: + * - bweStr : struct containing bandwidth information. + * - rtpNumber : value from RTP packet, from NetEq + * - frameSize : length of signal frame in ms, from iSAC decoder + * - sendTime : value in RTP header giving send time in samples + * - arrivalTime : 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 + * + * Return value : 0 if everything went fine, + * -1 otherwise + */ + +WebRtc_Word32 WebRtcIsacfix_UpdateUplinkBwImpl(BwEstimatorstr *bwest_str, + const WebRtc_UWord16 rtp_number, + const WebRtc_Word16 frameSize, + const WebRtc_UWord32 send_ts, + const WebRtc_UWord32 arr_ts, + const WebRtc_Word16 pksize, + const WebRtc_UWord16 Index); + +/* Update receiving estimates. Used when we only receive BWE index, no iSAC data packet. */ +WebRtc_Word16 WebRtcIsacfix_UpdateUplinkBwRec(BwEstimatorstr *bwest_str, + const WebRtc_Word16 Index); + +/**************************************************************************** + * WebRtcIsacfix_GetDownlinkBwIndexImpl(...) + * + * This function calculates and returns the bandwidth/jitter estimation code + * (integer 0...23) to put in the sending iSAC payload. + * + * Input: + * - bweStr : BWE struct + * + * Return: + * bandwith and jitter index (0..23) + */ +WebRtc_UWord16 WebRtcIsacfix_GetDownlinkBwIndexImpl(BwEstimatorstr *bwest_str); + +/* Returns the bandwidth estimation (in bps) */ +WebRtc_UWord16 WebRtcIsacfix_GetDownlinkBandwidth(const BwEstimatorstr *bwest_str); + +/* Returns the bandwidth that iSAC should send with in bps */ +WebRtc_Word16 WebRtcIsacfix_GetUplinkBandwidth(const BwEstimatorstr *bwest_str); + +/* Returns the max delay (in ms) */ +WebRtc_Word16 WebRtcIsacfix_GetDownlinkMaxDelay(const BwEstimatorstr *bwest_str); + +/* Returns the max delay value from the other side in ms */ +WebRtc_Word16 WebRtcIsacfix_GetUplinkMaxDelay(const BwEstimatorstr *bwest_str); + +/* + * update amount of data in bottle neck buffer and burst handling + * returns minimum payload size (bytes) + */ +WebRtc_UWord16 WebRtcIsacfix_GetMinBytes(RateModel *State, + WebRtc_Word16 StreamSize, /* bytes in bitstream */ + const WebRtc_Word16 FrameLen, /* ms per frame */ + const WebRtc_Word16 BottleNeck, /* bottle neck rate; excl headers (bps) */ + const WebRtc_Word16 DelayBuildUp); /* max delay from bottle neck buffering (ms) */ + +/* + * update long-term average bitrate and amount of data in buffer + */ +void WebRtcIsacfix_UpdateRateModel(RateModel *State, + WebRtc_Word16 StreamSize, /* bytes in bitstream */ + const WebRtc_Word16 FrameSamples, /* samples per frame */ + const WebRtc_Word16 BottleNeck); /* bottle neck rate; excl headers (bps) */ + + +void WebRtcIsacfix_InitRateModel(RateModel *State); + +/* Returns the new framelength value (input argument: bottle_neck) */ +WebRtc_Word16 WebRtcIsacfix_GetNewFrameLength(WebRtc_Word16 bottle_neck, WebRtc_Word16 current_framelength); + +/* Returns the new SNR value (input argument: bottle_neck) */ +//returns snr in Q10 +WebRtc_Word16 WebRtcIsacfix_GetSnr(WebRtc_Word16 bottle_neck, WebRtc_Word16 framesamples); + + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_BANDWIDTH_ESTIMATOR_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/fix/source/codec.h b/src/modules/audio_coding/codecs/isac/fix/source/codec.h new file mode 100644 index 0000000000..1b4f987230 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/codec.h @@ -0,0 +1,179 @@ +/* + * 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_FIX_SOURCE_CODEC_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_CODEC_H_ + +#include "structs.h" + + +int WebRtcIsacfix_EstimateBandwidth(BwEstimatorstr *bwest_str, + Bitstr_dec *streamdata, + WebRtc_Word32 packet_size, + WebRtc_UWord16 rtp_seq_number, + WebRtc_UWord32 send_ts, + WebRtc_UWord32 arr_ts); + +WebRtc_Word16 WebRtcIsacfix_DecodeImpl(WebRtc_Word16 *signal_out16, + ISACFIX_DecInst_t *ISACdec_obj, + WebRtc_Word16 *current_framesamples); + +WebRtc_Word16 WebRtcIsacfix_DecodePlcImpl(WebRtc_Word16 *decoded, + ISACFIX_DecInst_t *ISACdec_obj, + WebRtc_Word16 *current_framesample ); + +int WebRtcIsacfix_EncodeImpl(WebRtc_Word16 *in, + ISACFIX_EncInst_t *ISACenc_obj, + BwEstimatorstr *bw_estimatordata, + WebRtc_Word16 CodingMode); + +int WebRtcIsacfix_EncodeStoredData(ISACFIX_EncInst_t *ISACenc_obj, + int BWnumber, + float scale); + +/* initialization functions */ + +void WebRtcIsacfix_InitMaskingEnc(MaskFiltstr_enc *maskdata); +void WebRtcIsacfix_InitMaskingDec(MaskFiltstr_dec *maskdata); + +void WebRtcIsacfix_InitPreFilterbank(PreFiltBankstr *prefiltdata); + +void WebRtcIsacfix_InitPostFilterbank(PostFiltBankstr *postfiltdata); + +void WebRtcIsacfix_InitPitchFilter(PitchFiltstr *pitchfiltdata); + +void WebRtcIsacfix_InitPitchAnalysis(PitchAnalysisStruct *State); + +void WebRtcIsacfix_InitPlc( PLCstr *State ); + + +/* transform functions */ + +void WebRtcIsacfix_InitTransform(); + + +void WebRtcIsacfix_Time2Spec(WebRtc_Word16 *inre1Q9, + WebRtc_Word16 *inre2Q9, + WebRtc_Word16 *outre, + WebRtc_Word16 *outim); + + + +void WebRtcIsacfix_Spec2Time(WebRtc_Word16 *inreQ7, + WebRtc_Word16 *inimQ7, + WebRtc_Word32 *outre1Q16, + WebRtc_Word32 *outre2Q16); + + + + +/* filterbank functions */ + +void WebRtcIsacfix_SplitAndFilter1(WebRtc_Word16 *in, + WebRtc_Word16 *LP16, + WebRtc_Word16 *HP16, + PreFiltBankstr *prefiltdata); + +void WebRtcIsacfix_FilterAndCombine1(WebRtc_Word16 *tempin_ch1, + WebRtc_Word16 *tempin_ch2, + WebRtc_Word16 *out16, + PostFiltBankstr *postfiltdata); + +#ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED + +void WebRtcIsacfix_SplitAndFilter2(WebRtc_Word16 *in, + WebRtc_Word16 *LP16, + WebRtc_Word16 *HP16, + PreFiltBankstr *prefiltdata); + +void WebRtcIsacfix_FilterAndCombine2(WebRtc_Word16 *tempin_ch1, + WebRtc_Word16 *tempin_ch2, + WebRtc_Word16 *out16, + PostFiltBankstr *postfiltdata, + WebRtc_Word16 len); + +#endif + +/* normalized lattice filters */ + +void WebRtcIsacfix_NormLatticeFilterMa(WebRtc_Word16 orderCoef, + WebRtc_Word32 *stateGQ15, + WebRtc_Word16 *lat_inQ0, + WebRtc_Word16 *filt_coefQ15, + WebRtc_Word32 *gain_lo_hiQ17, + WebRtc_Word16 lo_hi, + WebRtc_Word16 *lat_outQ9); + +void WebRtcIsacfix_NormLatticeFilterAr(WebRtc_Word16 orderCoef, + WebRtc_Word16 *stateGQ0, + WebRtc_Word32 *lat_inQ25, + WebRtc_Word16 *filt_coefQ15, + WebRtc_Word32 *gain_lo_hiQ17, + WebRtc_Word16 lo_hi, + WebRtc_Word16 *lat_outQ0); + +/* TODO(kma): Remove the following functions into individual header files. */ + +/* Internal functions in both C and ARM Neon versions */ + +int WebRtcIsacfix_AutocorrC(WebRtc_Word32* __restrict r, + const WebRtc_Word16* __restrict x, + WebRtc_Word16 N, + WebRtc_Word16 order, + WebRtc_Word16* __restrict scale); + +void WebRtcIsacfix_FilterMaLoopC(int16_t input0, + int16_t input1, + int32_t input2, + int32_t* ptr0, + int32_t* ptr1, + int32_t* ptr2); + +#if (defined WEBRTC_DETECT_ARM_NEON) || (defined WEBRTC_ARCH_ARM_NEON) +int WebRtcIsacfix_AutocorrNeon(WebRtc_Word32* __restrict r, + const WebRtc_Word16* __restrict x, + WebRtc_Word16 N, + WebRtc_Word16 order, + WebRtc_Word16* __restrict scale); + +void WebRtcIsacfix_FilterMaLoopNeon(int16_t input0, + int16_t input1, + int32_t input2, + int32_t* ptr0, + int32_t* ptr1, + int32_t* ptr2); +#endif + +/* Function pointers associated with the above functions. */ + +typedef int (*AutocorrFix)(WebRtc_Word32* __restrict r, + const WebRtc_Word16* __restrict x, + WebRtc_Word16 N, + WebRtc_Word16 order, + WebRtc_Word16* __restrict scale); +extern AutocorrFix WebRtcIsacfix_AutocorrFix; + +typedef void (*FilterMaLoopFix)(int16_t input0, + int16_t input1, + int32_t input2, + int32_t* ptr0, + int32_t* ptr1, + int32_t* ptr2); +extern FilterMaLoopFix WebRtcIsacfix_FilterMaLoopFix; + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_CODEC_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/fix/source/decode.c b/src/modules/audio_coding/codecs/isac/fix/source/decode.c new file mode 100644 index 0000000000..2e15e7a974 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/decode.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. + */ + +/* + * decode.c + * + * This C file contains the internal decoding function. + * + */ + +#include <string.h> + +#include "bandwidth_estimator.h" +#include "codec.h" +#include "entropy_coding.h" +#include "pitch_estimator.h" +#include "settings.h" +#include "structs.h" + + + + +WebRtc_Word16 WebRtcIsacfix_DecodeImpl(WebRtc_Word16 *signal_out16, + ISACFIX_DecInst_t *ISACdec_obj, + WebRtc_Word16 *current_framesamples) +{ + int k; + int err; + WebRtc_Word16 BWno; + WebRtc_Word16 len = 0; + + WebRtc_Word16 model; + + + WebRtc_Word16 Vector_Word16_1[FRAMESAMPLES/2]; + WebRtc_Word16 Vector_Word16_2[FRAMESAMPLES/2]; + + WebRtc_Word32 Vector_Word32_1[FRAMESAMPLES/2]; + WebRtc_Word32 Vector_Word32_2[FRAMESAMPLES/2]; + + WebRtc_Word16 lofilt_coefQ15[ORDERLO*SUBFRAMES]; //refl. coeffs + WebRtc_Word16 hifilt_coefQ15[ORDERHI*SUBFRAMES]; //refl. coeffs + WebRtc_Word32 gain_lo_hiQ17[2*SUBFRAMES]; + + WebRtc_Word16 PitchLags_Q7[PITCH_SUBFRAMES]; + WebRtc_Word16 PitchGains_Q12[PITCH_SUBFRAMES]; + WebRtc_Word16 AvgPitchGain_Q12; + + WebRtc_Word16 tmp_1, tmp_2; + WebRtc_Word32 tmp32a, tmp32b; + WebRtc_Word16 gainQ13; + + + WebRtc_Word16 frame_nb; /* counter */ + WebRtc_Word16 frame_mode; /* 0 for 20ms and 30ms, 1 for 60ms */ + WebRtc_Word16 processed_samples; + + /* PLC */ + WebRtc_Word16 overlapWin[ 240 ]; + + (ISACdec_obj->bitstr_obj).W_upper = 0xFFFFFFFF; + (ISACdec_obj->bitstr_obj).streamval = 0; + (ISACdec_obj->bitstr_obj).stream_index = 0; + (ISACdec_obj->bitstr_obj).full = 1; + + + /* decode framelength and BW estimation - not used, only for stream pointer*/ + err = WebRtcIsacfix_DecodeFrameLen(&ISACdec_obj->bitstr_obj, current_framesamples); + if (err<0) // error check + return err; + + frame_mode = (WebRtc_Word16)WEBRTC_SPL_DIV(*current_framesamples, MAX_FRAMESAMPLES); /* 0, or 1 */ + processed_samples = (WebRtc_Word16)WEBRTC_SPL_DIV(*current_framesamples, frame_mode+1); /* either 320 (20ms) or 480 (30, 60 ms) */ + + err = WebRtcIsacfix_DecodeSendBandwidth(&ISACdec_obj->bitstr_obj, &BWno); + if (err<0) // error check + 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 & dequantize pitch parameters */ + err = WebRtcIsacfix_DecodePitchGain(&(ISACdec_obj->bitstr_obj), PitchGains_Q12); + if (err<0) // error check + return err; + + err = WebRtcIsacfix_DecodePitchLag(&ISACdec_obj->bitstr_obj, PitchGains_Q12, PitchLags_Q7); + if (err<0) // error check + return err; + + AvgPitchGain_Q12 = (WebRtc_Word16)(((WebRtc_Word32)PitchGains_Q12[0] + PitchGains_Q12[1] + PitchGains_Q12[2] + PitchGains_Q12[3])>>2); + + /* decode & dequantize FiltCoef */ + err = WebRtcIsacfix_DecodeLpc(gain_lo_hiQ17, lofilt_coefQ15, hifilt_coefQ15, + &ISACdec_obj->bitstr_obj, &model); + + if (err<0) // error check + return err; + + /* decode & dequantize spectrum */ + len = WebRtcIsacfix_DecodeSpec(&ISACdec_obj->bitstr_obj, Vector_Word16_1, Vector_Word16_2, AvgPitchGain_Q12); + if (len < 0) // error check + return len; + + // Why does this need Q16 in and out? /JS + WebRtcIsacfix_Spec2Time(Vector_Word16_1, Vector_Word16_2, Vector_Word32_1, Vector_Word32_2); + + for (k=0; k<FRAMESAMPLES/2; k++) { + Vector_Word16_1[k] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(Vector_Word32_1[k]+64, 7); //Q16 -> Q9 + } + + /* ---- If this is recovery frame ---- */ + if( (ISACdec_obj->plcstr_obj).used == PLC_WAS_USED ) + { + (ISACdec_obj->plcstr_obj).used = PLC_NOT_USED; + if( (ISACdec_obj->plcstr_obj).B < 1000 ) + { + (ISACdec_obj->plcstr_obj).decayCoeffPriodic = 4000; + } + + ISACdec_obj->plcstr_obj.decayCoeffPriodic = WEBRTC_SPL_WORD16_MAX; /* DECAY_RATE is in Q15 */ + ISACdec_obj->plcstr_obj.decayCoeffNoise = WEBRTC_SPL_WORD16_MAX; /* DECAY_RATE is in Q15 */ + ISACdec_obj->plcstr_obj.pitchCycles = 0; + + PitchGains_Q12[0] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(PitchGains_Q12[0], 700, 10 ); + + /* ---- Add-overlap ---- */ + WebRtcSpl_GetHanningWindow( overlapWin, RECOVERY_OVERLAP ); + for( k = 0; k < RECOVERY_OVERLAP; k++ ) + Vector_Word16_1[k] = WEBRTC_SPL_ADD_SAT_W16( + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT( (ISACdec_obj->plcstr_obj).overlapLP[k], overlapWin[RECOVERY_OVERLAP - k - 1], 14), + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT( Vector_Word16_1[k], overlapWin[k], 14) ); + + + + } + + /* --- Store side info --- */ + if( frame_nb == frame_mode ) + { + /* --- LPC info */ + WEBRTC_SPL_MEMCPY_W16( (ISACdec_obj->plcstr_obj).lofilt_coefQ15, &lofilt_coefQ15[(SUBFRAMES-1)*ORDERLO], ORDERLO ); + WEBRTC_SPL_MEMCPY_W16( (ISACdec_obj->plcstr_obj).hifilt_coefQ15, &hifilt_coefQ15[(SUBFRAMES-1)*ORDERHI], ORDERHI ); + (ISACdec_obj->plcstr_obj).gain_lo_hiQ17[0] = gain_lo_hiQ17[(SUBFRAMES-1) * 2]; + (ISACdec_obj->plcstr_obj).gain_lo_hiQ17[1] = gain_lo_hiQ17[(SUBFRAMES-1) * 2 + 1]; + + /* --- LTP info */ + (ISACdec_obj->plcstr_obj).AvgPitchGain_Q12 = PitchGains_Q12[3]; + (ISACdec_obj->plcstr_obj).lastPitchGain_Q12 = PitchGains_Q12[3]; + (ISACdec_obj->plcstr_obj).lastPitchLag_Q7 = PitchLags_Q7[3]; + + if( PitchLags_Q7[3] < 3000 ) + (ISACdec_obj->plcstr_obj).lastPitchLag_Q7 += PitchLags_Q7[3]; + + WEBRTC_SPL_MEMCPY_W16( (ISACdec_obj->plcstr_obj).prevPitchInvIn, Vector_Word16_1, FRAMESAMPLES/2 ); + + } + /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ + + /* inverse pitch filter */ + WebRtcIsacfix_PitchFilter(Vector_Word16_1, Vector_Word16_2, &ISACdec_obj->pitchfiltstr_obj, PitchLags_Q7, PitchGains_Q12, 4); + + if( frame_nb == frame_mode ) + { + WEBRTC_SPL_MEMCPY_W16( (ISACdec_obj->plcstr_obj).prevPitchInvOut, &(Vector_Word16_2[FRAMESAMPLES/2 - (PITCH_MAX_LAG + 10)]), PITCH_MAX_LAG ); + } + + + /* reduce gain to compensate for pitch enhancer */ + /* gain = 1.0f - 0.45f * AvgPitchGain; */ + tmp32a = WEBRTC_SPL_MUL_16_16_RSFT(AvgPitchGain_Q12, 29, 0); // Q18 + tmp32b = 262144 - tmp32a; // Q18 + gainQ13 = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp32b, 5); // Q13 + + for (k = 0; k < FRAMESAMPLES/2; k++) + { + Vector_Word32_1[k] = (WebRtc_Word32) WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_16(Vector_Word16_2[k], gainQ13), 3); // Q25 + } + + + /* perceptual post-filtering (using normalized lattice filter) */ + WebRtcIsacfix_NormLatticeFilterAr(ORDERLO, (ISACdec_obj->maskfiltstr_obj).PostStateLoGQ0, + Vector_Word32_1, lofilt_coefQ15, gain_lo_hiQ17, 0, Vector_Word16_1); + + /* --- Store Highpass Residual --- */ + for (k = 0; k < FRAMESAMPLES/2; k++) + Vector_Word32_1[k] = WEBRTC_SPL_LSHIFT_W32(Vector_Word32_2[k], 9); // Q16 -> Q25 + + for( k = 0; k < PITCH_MAX_LAG + 10; k++ ) + (ISACdec_obj->plcstr_obj).prevHP[k] = Vector_Word32_1[FRAMESAMPLES/2 - (PITCH_MAX_LAG + 10) + k]; + + + WebRtcIsacfix_NormLatticeFilterAr(ORDERHI, (ISACdec_obj->maskfiltstr_obj).PostStateHiGQ0, + Vector_Word32_1, hifilt_coefQ15, gain_lo_hiQ17, 1, Vector_Word16_2); + + /* recombine the 2 bands */ + + /* Form the polyphase signals, and compensate for DC offset */ + for (k=0;k<FRAMESAMPLES/2;k++) { + tmp_1 = (WebRtc_Word16)WebRtcSpl_SatW32ToW16(((WebRtc_Word32)Vector_Word16_1[k]+Vector_Word16_2[k] + 1)); /* Construct a new upper channel signal*/ + tmp_2 = (WebRtc_Word16)WebRtcSpl_SatW32ToW16(((WebRtc_Word32)Vector_Word16_1[k]-Vector_Word16_2[k])); /* Construct a new lower channel signal*/ + Vector_Word16_1[k] = tmp_1; + Vector_Word16_2[k] = tmp_2; + } + + WebRtcIsacfix_FilterAndCombine1(Vector_Word16_1, Vector_Word16_2, signal_out16 + frame_nb * processed_samples, &ISACdec_obj->postfiltbankstr_obj); + + } + return len; +} diff --git a/src/modules/audio_coding/codecs/isac/fix/source/decode_bwe.c b/src/modules/audio_coding/codecs/isac/fix/source/decode_bwe.c new file mode 100644 index 0000000000..68c600306a --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/decode_bwe.c @@ -0,0 +1,69 @@ +/* + * 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. + */ + +/* + * decode_bwe.c + * + * This C file contains the internal decode bandwidth estimate function. + * + */ + + +#include "bandwidth_estimator.h" +#include "codec.h" +#include "entropy_coding.h" +#include "structs.h" + + + + +int WebRtcIsacfix_EstimateBandwidth(BwEstimatorstr *bwest_str, + Bitstr_dec *streamdata, + WebRtc_Word32 packet_size, + WebRtc_UWord16 rtp_seq_number, + WebRtc_UWord32 send_ts, + WebRtc_UWord32 arr_ts) +{ + WebRtc_Word16 index; + WebRtc_Word16 frame_samples; + int err; + + /* decode framelength */ + err = WebRtcIsacfix_DecodeFrameLen(streamdata, &frame_samples); + /* error check */ + if (err<0) { + return err; + } + + /* decode BW estimation */ + err = WebRtcIsacfix_DecodeSendBandwidth(streamdata, &index); + /* error check */ + if (err<0) { + return err; + } + + /* Update BWE with received data */ + err = WebRtcIsacfix_UpdateUplinkBwImpl( + bwest_str, + rtp_seq_number, + (WebRtc_UWord16)WEBRTC_SPL_UDIV(WEBRTC_SPL_UMUL(frame_samples,1000), FS), + send_ts, + arr_ts, + (WebRtc_Word16) packet_size, /* in bytes */ + index); + + /* error check */ + if (err<0) { + return err; + } + + /* Succesful */ + return 0; +} diff --git a/src/modules/audio_coding/codecs/isac/fix/source/decode_plc.c b/src/modules/audio_coding/codecs/isac/fix/source/decode_plc.c new file mode 100644 index 0000000000..de5165872d --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/decode_plc.c @@ -0,0 +1,830 @@ +/* + * 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. + */ + +/* + * decode_plc.c + * + * Packet Loss Concealment. + * + */ + +#include <string.h> + +#include "settings.h" +#include "entropy_coding.h" +#include "pitch_estimator.h" +#include "bandwidth_estimator.h" +#include "structs.h" +#include "codec.h" + + +#define NO_OF_PRIMES 8 +#define NOISE_FILTER_LEN 30 + +/* + * function to decode the bitstream + * returns the total number of bytes in the stream + */ + +static WebRtc_Word16 plc_filterma_Fast( + WebRtc_Word16 *In, /* (i) Vector to be filtered. InOut[-orderCoef+1] + to InOut[-1] contains state */ + WebRtc_Word16 *Out, /* (o) Filtered vector */ + WebRtc_Word16 *B, /* (i) The filter coefficients (in Q0) */ + WebRtc_Word16 Blen, /* (i) Number of B coefficients */ + WebRtc_Word16 len, /* (i) Number of samples to be filtered */ + WebRtc_Word16 reduceDecay, + WebRtc_Word16 decay, + WebRtc_Word16 rshift ) +{ + int i, j; + WebRtc_Word32 o; + WebRtc_Word32 lim; + + lim = WEBRTC_SPL_LSHIFT_W32( (WebRtc_Word32)1, 15 + rshift )-1; + + for (i = 0; i < len; i++) + { + G_CONST WebRtc_Word16 *b_ptr = &B[0]; + G_CONST WebRtc_Word16 *x_ptr = &In[i]; + + o = (WebRtc_Word32)0; + + for (j = 0;j < Blen; j++) + { + o = WEBRTC_SPL_ADD_SAT_W32( o, WEBRTC_SPL_MUL_16_16( *b_ptr, *x_ptr) ); + b_ptr++; + x_ptr--; + } + + /* to round off correctly */ + o = WEBRTC_SPL_ADD_SAT_W32( o, WEBRTC_SPL_LSHIFT_W32( 1, (rshift-1) ) ); + + /* saturate according to the domain of the filter coefficients */ + o = WEBRTC_SPL_SAT((WebRtc_Word32)lim, o, (WebRtc_Word32)-lim); + + /* o should be in the range of WebRtc_Word16 */ + o = WEBRTC_SPL_RSHIFT_W32( o, rshift ); + + /* decay the output signal; this is specific to plc */ + *Out++ = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT( (WebRtc_Word16)o, decay, 15); // ((o + (WebRtc_Word32)2048) >> 12); + + /* change the decay */ + decay -= reduceDecay; + if( decay < 0 ) + decay = 0; + } + return( decay ); +} + + + + + + + + +static __inline WebRtc_Word32 log2_Q8_T( WebRtc_UWord32 x ) { + + WebRtc_Word32 zeros, lg2; + WebRtc_Word16 frac; + + zeros=WebRtcSpl_NormU32(x); + frac=(WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(((WebRtc_UWord32)WEBRTC_SPL_LSHIFT_W32(x, zeros)&0x7FFFFFFF), 23); + /* log2(magn(i)) */ + + lg2= (WEBRTC_SPL_LSHIFT_W16((31-zeros), 8)+frac); + return lg2; + +} + +static __inline WebRtc_Word16 exp2_Q10_T(WebRtc_Word16 x) { // Both in and out in Q10 + + WebRtc_Word16 tmp16_1, tmp16_2; + + tmp16_2=(WebRtc_Word16)(0x0400|(x&0x03FF)); + tmp16_1=-(WebRtc_Word16)WEBRTC_SPL_RSHIFT_W16(x,10); + if(tmp16_1>0) + return (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W16(tmp16_2, tmp16_1); + else + return (WebRtc_Word16) WEBRTC_SPL_LSHIFT_W16(tmp16_2, -tmp16_1); + +} + + +/* + This is a fixed-point version of the above code with limLow = 700 and limHigh = 5000, + hard-coded. The values 700 and 5000 were experimentally obtained. + + The function implements membership values for two sets. The mebership functions are + of second orders corresponding to half-bell-shapped pulses. +*/ +static void MemshipValQ15( WebRtc_Word16 in, WebRtc_Word16 *A, WebRtc_Word16 *B ) +{ + WebRtc_Word16 x; + + in -= 700; /* translate the lowLim to 0, limHigh = 5000 - 700, M = 2150 */ + + if( in <= 2150 ) + { + if( in > 0 ) + { + /* b = in^2 / (2 * M^2), a = 1 - b in Q0. + We have to compute in Q15 */ + + /* x = in / 2150 {in Q15} = x * 15.2409 {in Q15} = + x*15 + (x*983)/(2^12); note that 983/2^12 = 0.23999 */ + + /* we are sure that x is in the range of WebRtc_Word16 */ + x = (WebRtc_Word16)( WEBRTC_SPL_MUL_16_16( in, 15 ) + + WEBRTC_SPL_MUL_16_16_RSFT( in, 983, 12) ); + /* b = x^2 / 2 {in Q15} so a shift of 16 is required to + be in correct domain and one more for the division by 2 */ + *B = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32( WEBRTC_SPL_MUL_16_16( x, x ) + 0x00010000, 17 ); + *A = WEBRTC_SPL_WORD16_MAX - *B; + } + else + { + *B = 0; + *A = WEBRTC_SPL_WORD16_MAX; + } + } + else + { + if( in < 4300 ) + { + /* This is a mirror case of the above */ + in = 4300 - in; + x = (WebRtc_Word16)( WEBRTC_SPL_MUL_16_16( in, 15 ) + + WEBRTC_SPL_MUL_16_16_RSFT( in, 983, 12) ); + /* b = x^2 / 2 {in Q15} so a shift of 16 is required to + be in correct domain and one more for the division by 2 */ + *A = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32( WEBRTC_SPL_MUL_16_16( x, x ) + 0x00010000, 17 ); + *B = WEBRTC_SPL_WORD16_MAX - *A; + + } + else + { + *A = 0; + *B = WEBRTC_SPL_WORD16_MAX; + } + } +} + + + + +static void LinearResampler( WebRtc_Word16 *in, WebRtc_Word16 *out, WebRtc_Word16 lenIn, WebRtc_Word16 lenOut ) +{ + WebRtc_Word32 n; + WebRtc_Word16 resOut, i, j, relativePos, diff; /* */ + WebRtc_UWord16 udiff; + + if( lenIn == lenOut ) + { + WEBRTC_SPL_MEMCPY_W16( out, in, lenIn ); + return; + } + + n = WEBRTC_SPL_MUL_16_16( (WebRtc_Word16)(lenIn-1), RESAMP_RES ); + resOut = WebRtcSpl_DivW32W16ResW16( n, (WebRtc_Word16)(lenOut-1) ); + + out[0] = in[0]; + for( i = 1, j = 0, relativePos = 0; i < lenOut; i++ ) + { + + relativePos += resOut; + while( relativePos > RESAMP_RES ) + { + j++; + relativePos -= RESAMP_RES; + } + + + /* an overflow may happen and the differce in sample values may + * require more than 16 bits. We like to avoid 32 bit arithmatic + * as much as possible */ + + if( (in[ j ] > 0) && (in[j + 1] < 0) ) + { + udiff = (WebRtc_UWord16)(in[ j ] - in[j + 1]); + out[ i ] = in[ j ] - (WebRtc_UWord16)( ((WebRtc_Word32)( udiff * relativePos )) >> RESAMP_RES_BIT); + } + else + { + if( (in[j] < 0) && (in[j+1] > 0) ) + { + udiff = (WebRtc_UWord16)( in[j + 1] - in[ j ] ); + out[ i ] = in[ j ] + (WebRtc_UWord16)( ((WebRtc_Word32)( udiff * relativePos )) >> RESAMP_RES_BIT); + } + else + { + diff = in[ j + 1 ] - in[ j ]; + out[ i ] = in[ j ] + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT( diff, relativePos, RESAMP_RES_BIT ); + } + } + } +} + + + + + +WebRtc_Word16 WebRtcIsacfix_DecodePlcImpl(WebRtc_Word16 *signal_out16, + ISACFIX_DecInst_t *ISACdec_obj, + WebRtc_Word16 *current_framesamples ) +{ + int subframecnt; + WebRtc_Word16 len = 0; + + WebRtc_Word16* Vector_Word16_1; + WebRtc_Word16 Vector_Word16_Extended_1[FRAMESAMPLES_HALF + NOISE_FILTER_LEN]; + WebRtc_Word16* Vector_Word16_2; + WebRtc_Word16 Vector_Word16_Extended_2[FRAMESAMPLES_HALF + NOISE_FILTER_LEN]; + + WebRtc_Word32 Vector_Word32_1[FRAMESAMPLES_HALF]; + WebRtc_Word32 Vector_Word32_2[FRAMESAMPLES_HALF]; + + WebRtc_Word16 lofilt_coefQ15[ORDERLO*SUBFRAMES]; //refl. coeffs + WebRtc_Word16 hifilt_coefQ15[ORDERHI*SUBFRAMES]; //refl. coeffs + + WebRtc_Word16 pitchLags_Q7[PITCH_SUBFRAMES]; + WebRtc_Word16 pitchGains_Q12[PITCH_SUBFRAMES]; + + WebRtc_Word16 tmp_1, tmp_2; + WebRtc_Word32 tmp32a, tmp32b; + WebRtc_Word16 gainQ13; + + WebRtc_Word16 myDecayRate; + + /* ---------- PLC variables ------------ */ + WebRtc_Word16 lag0, i, k, noiseIndex; + WebRtc_Word16 stretchPitchLP[PITCH_MAX_LAG + 10], stretchPitchLP1[PITCH_MAX_LAG + 10]; + + WebRtc_Word32 gain_lo_hiQ17[2*SUBFRAMES]; + + WebRtc_Word16 nLP, pLP, wNoisyLP, wPriodicLP, tmp16, minIdx; + WebRtc_Word32 nHP, pHP, wNoisyHP, wPriodicHP, corr, minCorr, maxCoeff; + WebRtc_Word16 noise1, rshift; + + + WebRtc_Word16 ltpGain, pitchGain, myVoiceIndicator, myAbs, maxAbs; + WebRtc_Word32 varIn, varOut, logVarIn, logVarOut, Q, logMaxAbs; + int rightShiftIn, rightShiftOut; + + + /* ------------------------------------- */ + + + myDecayRate = (DECAY_RATE); + Vector_Word16_1 = &Vector_Word16_Extended_1[NOISE_FILTER_LEN]; + Vector_Word16_2 = &Vector_Word16_Extended_2[NOISE_FILTER_LEN]; + + + /* ----- Simply Copy Previous LPC parameters ------ */ + for( subframecnt = 0; subframecnt < SUBFRAMES; subframecnt++ ) + { + /* lower Band */ + WEBRTC_SPL_MEMCPY_W16(&lofilt_coefQ15[ subframecnt * ORDERLO ], + (ISACdec_obj->plcstr_obj).lofilt_coefQ15, ORDERLO); + gain_lo_hiQ17[2*subframecnt] = (ISACdec_obj->plcstr_obj).gain_lo_hiQ17[0]; + + /* Upper Band */ + WEBRTC_SPL_MEMCPY_W16(&hifilt_coefQ15[ subframecnt * ORDERHI ], + (ISACdec_obj->plcstr_obj).hifilt_coefQ15, ORDERHI); + gain_lo_hiQ17[2*subframecnt + 1] = (ISACdec_obj->plcstr_obj).gain_lo_hiQ17[1]; + } + + + + + lag0 = WEBRTC_SPL_RSHIFT_W16( + (ISACdec_obj->plcstr_obj).lastPitchLag_Q7 + 64, 7 ) + 1; + + + if( (ISACdec_obj->plcstr_obj).used != PLC_WAS_USED ) + { + (ISACdec_obj->plcstr_obj).pitchCycles = 0; + + (ISACdec_obj->plcstr_obj).lastPitchLP = + &((ISACdec_obj->plcstr_obj).prevPitchInvIn[FRAMESAMPLES_HALF - lag0]); + minCorr = WEBRTC_SPL_WORD32_MAX; + + if ( (FRAMESAMPLES_HALF - 2*lag0 - 10) > 0 ) + { + minIdx = 11; + for( i = 0; i < 21; i++ ) + { + corr = 0; + for( k = 0; k < lag0; k++ ) + { + corr = WEBRTC_SPL_ADD_SAT_W32( corr, WEBRTC_SPL_ABS_W32( + WEBRTC_SPL_SUB_SAT_W16( + (ISACdec_obj->plcstr_obj).lastPitchLP[k], + (ISACdec_obj->plcstr_obj).prevPitchInvIn[ + FRAMESAMPLES_HALF - 2*lag0 - 10 + i + k ] ) ) ); + } + if( corr < minCorr ) + { + minCorr = corr; + minIdx = i; + } + } + (ISACdec_obj->plcstr_obj).prevPitchLP = + &( (ISACdec_obj->plcstr_obj).prevPitchInvIn[ + FRAMESAMPLES_HALF - lag0*2 - 10 + minIdx] ); + } + else + { + (ISACdec_obj->plcstr_obj).prevPitchLP = + (ISACdec_obj->plcstr_obj).lastPitchLP; + } + pitchGain = (ISACdec_obj->plcstr_obj).lastPitchGain_Q12; + + WebRtcSpl_AutoCorrelation( + &(ISACdec_obj->plcstr_obj).prevPitchInvIn[FRAMESAMPLES_HALF - lag0], + lag0, 0, &varIn, &rightShiftIn); + WebRtcSpl_AutoCorrelation( + &(ISACdec_obj->plcstr_obj).prevPitchInvOut[PITCH_MAX_LAG + 10 - lag0], + lag0, 0, &varOut, &rightShiftOut); + + maxAbs = 0; + for( i = 0; i< lag0; i++) + { + myAbs = WEBRTC_SPL_ABS_W16( + (ISACdec_obj->plcstr_obj).prevPitchInvOut[ + PITCH_MAX_LAG + 10 - lag0 + i] ); + maxAbs = (myAbs > maxAbs)? myAbs:maxAbs; + } + logVarIn = log2_Q8_T( (WebRtc_UWord32)( varIn ) ) + + (WebRtc_Word32)(rightShiftIn << 8); + logVarOut = log2_Q8_T( (WebRtc_UWord32)( varOut ) ) + + (WebRtc_Word32)(rightShiftOut << 8); + logMaxAbs = log2_Q8_T( (WebRtc_UWord32)( maxAbs ) ); + + ltpGain = (WebRtc_Word16)(logVarOut - logVarIn); + Q = 2 * logMaxAbs - ( logVarOut - 1512 ); + + /* + * --- + * We are computing sqrt( (VarIn/lag0) / var( noise ) ) + * var( noise ) is almost 256. we have already computed log2( VarIn ) in Q8 + * so we actually compute 2^( 0.5*(log2( VarIn ) - log2( lag0 ) - log2( var(noise ) ) ). + * Note that put log function is in Q8 but the exponential function is in Q10. + * -- + */ + + logVarIn -= log2_Q8_T( (WebRtc_UWord32)( lag0 ) ); + tmp16 = (WebRtc_Word16)((logVarIn<<1) - (4<<10) ); + rightShiftIn = 0; + if( tmp16 > 4096 ) + { + tmp16 -= 4096; + tmp16 = exp2_Q10_T( tmp16 ); + tmp16 >>= 6; + } + else + tmp16 = exp2_Q10_T( tmp16 )>>10; + + (ISACdec_obj->plcstr_obj).std = tmp16 - 4; + + if( (ltpGain < 110) || (ltpGain > 230) ) + { + if( ltpGain < 100 && (pitchGain < 1800) ) + { + (ISACdec_obj->plcstr_obj).A = WEBRTC_SPL_WORD16_MAX; + } + else + { + (ISACdec_obj->plcstr_obj).A = ((ltpGain < 110) && (Q < 800) + )? WEBRTC_SPL_WORD16_MAX:0; + } + (ISACdec_obj->plcstr_obj).B = WEBRTC_SPL_WORD16_MAX - + (ISACdec_obj->plcstr_obj).A; + } + else + { + if( (pitchGain < 450) || (pitchGain > 1600) ) + { + (ISACdec_obj->plcstr_obj).A = ((pitchGain < 450) + )? WEBRTC_SPL_WORD16_MAX:0; + (ISACdec_obj->plcstr_obj).B = WEBRTC_SPL_WORD16_MAX - + (ISACdec_obj->plcstr_obj).A; + } + else + { + myVoiceIndicator = ltpGain * 2 + pitchGain; + MemshipValQ15( myVoiceIndicator, + &(ISACdec_obj->plcstr_obj).A, &(ISACdec_obj->plcstr_obj).B ); + } + } + + + + myVoiceIndicator = ltpGain * 16 + pitchGain * 2 + (pitchGain >> 8); + MemshipValQ15( myVoiceIndicator, + &(ISACdec_obj->plcstr_obj).A, &(ISACdec_obj->plcstr_obj).B ); + + + + (ISACdec_obj->plcstr_obj).stretchLag = lag0; + (ISACdec_obj->plcstr_obj).pitchIndex = 0; + + } + else + { + myDecayRate = (DECAY_RATE<<2); + } + + if( (ISACdec_obj->plcstr_obj).B < 1000 ) + { + myDecayRate += (DECAY_RATE<<3); + } + + /* ------------ reconstructing the residual signal ------------------ */ + + LinearResampler( (ISACdec_obj->plcstr_obj).lastPitchLP, + stretchPitchLP, lag0, (ISACdec_obj->plcstr_obj).stretchLag ); + /* inverse pitch filter */ + + pitchLags_Q7[0] = pitchLags_Q7[1] = pitchLags_Q7[2] = pitchLags_Q7[3] = + ((ISACdec_obj->plcstr_obj).stretchLag<<7); + pitchGains_Q12[3] = ( (ISACdec_obj->plcstr_obj).lastPitchGain_Q12); + pitchGains_Q12[2] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT( + pitchGains_Q12[3], 1010, 10 ); + pitchGains_Q12[1] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT( + pitchGains_Q12[2], 1010, 10 ); + pitchGains_Q12[0] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT( + pitchGains_Q12[1], 1010, 10 ); + + + /* most of the time either B or A are zero so seperating */ + if( (ISACdec_obj->plcstr_obj).B == 0 ) + { + for( i = 0; i < FRAMESAMPLES_HALF; i++ ) + { + /* --- Low Pass */ + (ISACdec_obj->plcstr_obj).seed = WEBRTC_SPL_RAND( + (ISACdec_obj->plcstr_obj).seed ); + Vector_Word16_1[i] = WEBRTC_SPL_RSHIFT_W16( + (ISACdec_obj->plcstr_obj).seed, 10 ) - 16; + + /* --- Highpass */ + (ISACdec_obj->plcstr_obj).seed = WEBRTC_SPL_RAND( + (ISACdec_obj->plcstr_obj).seed ); + Vector_Word16_2[i] = WEBRTC_SPL_RSHIFT_W16( + (ISACdec_obj->plcstr_obj).seed, 10 ) - 16; + + } + for( i = 1; i < NOISE_FILTER_LEN; i++ ) + { + (ISACdec_obj->plcstr_obj).seed = WEBRTC_SPL_RAND( + (ISACdec_obj->plcstr_obj).seed ); + Vector_Word16_Extended_1[ i ] = WEBRTC_SPL_RSHIFT_W16( + (ISACdec_obj->plcstr_obj).seed, 10 ) - 16; + + (ISACdec_obj->plcstr_obj).seed = WEBRTC_SPL_RAND( + (ISACdec_obj->plcstr_obj).seed ); + Vector_Word16_Extended_2[ i ] = WEBRTC_SPL_RSHIFT_W16( + (ISACdec_obj->plcstr_obj).seed, 10 ) - 16; + } + plc_filterma_Fast(Vector_Word16_1, Vector_Word16_Extended_1, + &(ISACdec_obj->plcstr_obj).prevPitchInvIn[FRAMESAMPLES_HALF - + NOISE_FILTER_LEN], (WebRtc_Word16) NOISE_FILTER_LEN, + (WebRtc_Word16) FRAMESAMPLES_HALF, (WebRtc_Word16)(5), + (ISACdec_obj->plcstr_obj).decayCoeffNoise, (WebRtc_Word16)(6)); + + maxCoeff = WebRtcSpl_MaxAbsValueW32( + &(ISACdec_obj->plcstr_obj).prevHP[ + PITCH_MAX_LAG + 10 - NOISE_FILTER_LEN], NOISE_FILTER_LEN ); + + rshift = 0; + while( maxCoeff > WEBRTC_SPL_WORD16_MAX ) + { + maxCoeff = WEBRTC_SPL_RSHIFT_W32(maxCoeff, 1); + rshift++; + } + for( i = 0; i < NOISE_FILTER_LEN; i++ ) { + Vector_Word16_1[ FRAMESAMPLES_HALF - NOISE_FILTER_LEN + i] = + (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32( + (ISACdec_obj->plcstr_obj).prevHP[ + PITCH_MAX_LAG + 10 - NOISE_FILTER_LEN + i], rshift); + } + (ISACdec_obj->plcstr_obj).decayCoeffNoise = plc_filterma_Fast( + Vector_Word16_2, + Vector_Word16_Extended_2, + &Vector_Word16_1[FRAMESAMPLES_HALF - NOISE_FILTER_LEN], + (WebRtc_Word16) NOISE_FILTER_LEN, + (WebRtc_Word16) FRAMESAMPLES_HALF, + (WebRtc_Word16) (5), + (ISACdec_obj->plcstr_obj).decayCoeffNoise, + (WebRtc_Word16) (7) ); + + for( i = 0; i < FRAMESAMPLES_HALF; i++ ) + Vector_Word32_2[i] = WEBRTC_SPL_LSHIFT_W32( + (WebRtc_Word32)Vector_Word16_Extended_2[i], rshift ); + + Vector_Word16_1 = Vector_Word16_Extended_1; + } + else + { + if( (ISACdec_obj->plcstr_obj).A == 0 ) + { + /* ------ Periodic Vector --- */ + for( i = 0, noiseIndex = 0; i < FRAMESAMPLES_HALF; i++, noiseIndex++ ) + { + /* --- Lowpass */ + pLP = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT( + stretchPitchLP[(ISACdec_obj->plcstr_obj).pitchIndex], + (ISACdec_obj->plcstr_obj).decayCoeffPriodic, 15 ); + + /* --- Highpass */ + pHP = (WebRtc_Word32)WEBRTC_SPL_MUL_16_32_RSFT15( + (ISACdec_obj->plcstr_obj).decayCoeffPriodic, + (ISACdec_obj->plcstr_obj).prevHP[PITCH_MAX_LAG + 10 - + (ISACdec_obj->plcstr_obj).stretchLag + + (ISACdec_obj->plcstr_obj).pitchIndex] ); + + /* --- lower the muliplier (more decay at next sample) --- */ + (ISACdec_obj->plcstr_obj).decayCoeffPriodic -= (myDecayRate); + if( (ISACdec_obj->plcstr_obj).decayCoeffPriodic < 0 ) + (ISACdec_obj->plcstr_obj).decayCoeffPriodic = 0; + + (ISACdec_obj->plcstr_obj).pitchIndex++; + + if( (ISACdec_obj->plcstr_obj).pitchIndex == + (ISACdec_obj->plcstr_obj).stretchLag ) + { + (ISACdec_obj->plcstr_obj).pitchIndex = 0; + (ISACdec_obj->plcstr_obj).pitchCycles++; + + if( (ISACdec_obj->plcstr_obj).stretchLag != (lag0 + 1) ) + { + (ISACdec_obj->plcstr_obj).stretchLag = lag0 + 1; + } + else + { + (ISACdec_obj->plcstr_obj).stretchLag = lag0; + } + + (ISACdec_obj->plcstr_obj).stretchLag = ( + (ISACdec_obj->plcstr_obj).stretchLag > PITCH_MAX_LAG + )? (PITCH_MAX_LAG):(ISACdec_obj->plcstr_obj).stretchLag; + + LinearResampler( (ISACdec_obj->plcstr_obj).lastPitchLP, + stretchPitchLP, lag0, (ISACdec_obj->plcstr_obj).stretchLag ); + + LinearResampler( (ISACdec_obj->plcstr_obj).prevPitchLP, + stretchPitchLP1, lag0, (ISACdec_obj->plcstr_obj).stretchLag ); + + switch( (ISACdec_obj->plcstr_obj).pitchCycles ) + { + case 1: + { + for( k=0; k<(ISACdec_obj->plcstr_obj).stretchLag; k++ ) + { + stretchPitchLP[k] = (WebRtc_Word16)(( + (WebRtc_Word32)stretchPitchLP[k]* 3 + + (WebRtc_Word32)stretchPitchLP1[k])>>2); + } + break; + } + case 2: + { + for( k=0; k<(ISACdec_obj->plcstr_obj).stretchLag; k++ ) + { + stretchPitchLP[k] = (WebRtc_Word16)(( + (WebRtc_Word32)stretchPitchLP[k] + + (WebRtc_Word32)stretchPitchLP1[k] )>>1); + } + break; + } + case 3: + { + for( k=0; k<(ISACdec_obj->plcstr_obj).stretchLag; k++ ) + { + stretchPitchLP[k] = (WebRtc_Word16)((stretchPitchLP[k] + + (WebRtc_Word32)stretchPitchLP1[k]*3 )>>2); + } + break; + } + } + + if( (ISACdec_obj->plcstr_obj).pitchCycles == 3 ) + { + myDecayRate += 35; //(myDecayRate>>1); + (ISACdec_obj->plcstr_obj).pitchCycles = 0; + } + + } + + /* ------ Sum the noisy and periodic signals ------ */ + Vector_Word16_1[i] = pLP; + Vector_Word32_2[i] = pHP; + } + } + else + { + for( i = 0, noiseIndex = 0; i < FRAMESAMPLES_HALF; i++, noiseIndex++ ) + { + + (ISACdec_obj->plcstr_obj).seed = WEBRTC_SPL_RAND( + (ISACdec_obj->plcstr_obj).seed ); + + noise1 = WEBRTC_SPL_RSHIFT_W16( + (ISACdec_obj->plcstr_obj).seed, 10 ) - 16; + + nLP = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT( + (WebRtc_Word16)((noise1)*(ISACdec_obj->plcstr_obj).std), + (ISACdec_obj->plcstr_obj).decayCoeffNoise, 15 ); + + /* --- Highpass */ + (ISACdec_obj->plcstr_obj).seed = WEBRTC_SPL_RAND( + (ISACdec_obj->plcstr_obj).seed ); + noise1 = WEBRTC_SPL_RSHIFT_W16( + (ISACdec_obj->plcstr_obj).seed, 11 ) - 8; + + nHP = (WebRtc_Word32)WEBRTC_SPL_MUL_16_32_RSFT15( + (ISACdec_obj->plcstr_obj).decayCoeffNoise, + (WebRtc_Word32)(noise1*(ISACdec_obj->plcstr_obj).std) ); + + /* --- lower the muliplier (more decay at next sample) --- */ + (ISACdec_obj->plcstr_obj).decayCoeffNoise -= (myDecayRate); + if( (ISACdec_obj->plcstr_obj).decayCoeffNoise < 0 ) + (ISACdec_obj->plcstr_obj).decayCoeffNoise = 0; + + /* ------ Periodic Vector --- */ + /* --- Lowpass */ + pLP = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT( + stretchPitchLP[(ISACdec_obj->plcstr_obj).pitchIndex], + (ISACdec_obj->plcstr_obj).decayCoeffPriodic, 15 ); + + /* --- Highpass */ + pHP = (WebRtc_Word32)WEBRTC_SPL_MUL_16_32_RSFT15( + (ISACdec_obj->plcstr_obj).decayCoeffPriodic, + (ISACdec_obj->plcstr_obj).prevHP[PITCH_MAX_LAG + 10 - + (ISACdec_obj->plcstr_obj).stretchLag + + (ISACdec_obj->plcstr_obj).pitchIndex] ); + + /* --- lower the muliplier (more decay at next sample) --- */ + (ISACdec_obj->plcstr_obj).decayCoeffPriodic -= (myDecayRate); + if( (ISACdec_obj->plcstr_obj).decayCoeffPriodic < 0 ) + { + (ISACdec_obj->plcstr_obj).decayCoeffPriodic = 0; + } + + /* ------ Weighting the noisy and periodic vectors ------- */ + wNoisyLP = (WebRtc_Word16)(WEBRTC_SPL_MUL_16_16_RSFT( + (ISACdec_obj->plcstr_obj).A, nLP, 15 ) ); + wNoisyHP = (WebRtc_Word32)(WEBRTC_SPL_MUL_16_32_RSFT15( + (ISACdec_obj->plcstr_obj).A, (nHP) ) ); + + wPriodicLP = (WebRtc_Word16)(WEBRTC_SPL_MUL_16_16_RSFT( + (ISACdec_obj->plcstr_obj).B, pLP, 15)); + wPriodicHP = (WebRtc_Word32)(WEBRTC_SPL_MUL_16_32_RSFT15( + (ISACdec_obj->plcstr_obj).B, pHP)); + + (ISACdec_obj->plcstr_obj).pitchIndex++; + + if((ISACdec_obj->plcstr_obj).pitchIndex == + (ISACdec_obj->plcstr_obj).stretchLag) + { + (ISACdec_obj->plcstr_obj).pitchIndex = 0; + (ISACdec_obj->plcstr_obj).pitchCycles++; + + if( (ISACdec_obj->plcstr_obj).stretchLag != (lag0 + 1) ) + (ISACdec_obj->plcstr_obj).stretchLag = lag0 + 1; + else + (ISACdec_obj->plcstr_obj).stretchLag = lag0; + + (ISACdec_obj->plcstr_obj).stretchLag = ( + (ISACdec_obj->plcstr_obj).stretchLag > PITCH_MAX_LAG + )? (PITCH_MAX_LAG):(ISACdec_obj->plcstr_obj).stretchLag; + LinearResampler( + (ISACdec_obj->plcstr_obj).lastPitchLP, + stretchPitchLP, lag0, (ISACdec_obj->plcstr_obj).stretchLag ); + + LinearResampler((ISACdec_obj->plcstr_obj).prevPitchLP, + stretchPitchLP1, lag0, (ISACdec_obj->plcstr_obj).stretchLag ); + + switch((ISACdec_obj->plcstr_obj).pitchCycles) + { + case 1: + { + for( k=0; k<(ISACdec_obj->plcstr_obj).stretchLag; k++ ) + { + stretchPitchLP[k] = (WebRtc_Word16)(( + (WebRtc_Word32)stretchPitchLP[k]* 3 + + (WebRtc_Word32)stretchPitchLP1[k] )>>2); + } + break; + } + case 2: + { + for( k=0; k<(ISACdec_obj->plcstr_obj).stretchLag; k++ ) + { + stretchPitchLP[k] = (WebRtc_Word16)(( + (WebRtc_Word32)stretchPitchLP[k] + + (WebRtc_Word32)stretchPitchLP1[k])>>1); + } + break; + } + case 3: + { + for( k=0; k<(ISACdec_obj->plcstr_obj).stretchLag; k++ ) + { + stretchPitchLP[k] = (WebRtc_Word16)( + (stretchPitchLP[k] + + (WebRtc_Word32)stretchPitchLP1[k]*3 )>>2); + } + break; + } + } + + if( (ISACdec_obj->plcstr_obj).pitchCycles == 3 ) + { + myDecayRate += 55; //(myDecayRate>>1); + (ISACdec_obj->plcstr_obj).pitchCycles = 0; + } + } + + /* ------ Sum the noisy and periodic signals ------ */ + Vector_Word16_1[i] = (WebRtc_Word16)WEBRTC_SPL_ADD_SAT_W16( + wNoisyLP, wPriodicLP ); + Vector_Word32_2[i] = (WebRtc_Word32)WEBRTC_SPL_ADD_SAT_W32( + wNoisyHP, wPriodicHP ); + } + } + } + /* ----------------- residual signal is reconstructed ------------------ */ + + k = (ISACdec_obj->plcstr_obj).pitchIndex; + /* --- Write one pitch cycle for recovery block --- */ + + for( i = 0; i < RECOVERY_OVERLAP; i++ ) + { + (ISACdec_obj->plcstr_obj).overlapLP[i] = (WebRtc_Word16)( + WEBRTC_SPL_MUL_16_16_RSFT(stretchPitchLP[k], + (ISACdec_obj->plcstr_obj).decayCoeffPriodic, 15) ); + k = ( k < ((ISACdec_obj->plcstr_obj).stretchLag - 1) )? (k+1):0; + } + + (ISACdec_obj->plcstr_obj).lastPitchLag_Q7 = (ISACdec_obj->plcstr_obj).stretchLag << 7; + + + /* --- Inverse Pitch Filter --- */ + WebRtcIsacfix_PitchFilter(Vector_Word16_1, Vector_Word16_2, + &ISACdec_obj->pitchfiltstr_obj, pitchLags_Q7, pitchGains_Q12, 4); + + /* reduce gain to compensate for pitch enhancer */ + /* gain = 1.0f - 0.45f * AvgPitchGain; */ + tmp32a = WEBRTC_SPL_MUL_16_16_RSFT((ISACdec_obj->plcstr_obj).AvgPitchGain_Q12, + 29, 0); // Q18 + tmp32b = 262144 - tmp32a; // Q18 + gainQ13 = (WebRtc_Word16) (tmp32b >> 5); // Q13 + + /* perceptual post-filtering (using normalized lattice filter) */ + for (k = 0; k < FRAMESAMPLES_HALF; k++) + Vector_Word32_1[k] = (WebRtc_Word32) WEBRTC_SPL_MUL_16_16( + Vector_Word16_2[k], gainQ13) << 3; // Q25 + + + WebRtcIsacfix_NormLatticeFilterAr(ORDERLO, + (ISACdec_obj->maskfiltstr_obj).PostStateLoGQ0, + Vector_Word32_1, lofilt_coefQ15, gain_lo_hiQ17, 0, Vector_Word16_1); + + WebRtcIsacfix_NormLatticeFilterAr(ORDERHI, + (ISACdec_obj->maskfiltstr_obj).PostStateHiGQ0, + Vector_Word32_2, hifilt_coefQ15, gain_lo_hiQ17, 1, Vector_Word16_2); + + /* recombine the 2 bands */ + + /* Form the polyphase signals, and compensate for DC offset */ + for (k=0;k<FRAMESAMPLES_HALF;k++) + { + /* Construct a new upper channel signal*/ + tmp_1 = (WebRtc_Word16)WebRtcSpl_SatW32ToW16( + ((WebRtc_Word32)Vector_Word16_1[k]+Vector_Word16_2[k] + 1)); + /* Construct a new lower channel signal*/ + tmp_2 = (WebRtc_Word16)WebRtcSpl_SatW32ToW16( + ((WebRtc_Word32)Vector_Word16_1[k]-Vector_Word16_2[k])); + Vector_Word16_1[k] = tmp_1; + Vector_Word16_2[k] = tmp_2; + } + + + WebRtcIsacfix_FilterAndCombine1(Vector_Word16_1, + Vector_Word16_2, signal_out16, &ISACdec_obj->postfiltbankstr_obj); + + (ISACdec_obj->plcstr_obj).used = PLC_WAS_USED; + *current_framesamples = 480; + + return len; +} diff --git a/src/modules/audio_coding/codecs/isac/fix/source/encode.c b/src/modules/audio_coding/codecs/isac/fix/source/encode.c new file mode 100644 index 0000000000..cb531e5ac9 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/encode.c @@ -0,0 +1,626 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * encode.c + * + * Encoding function for the iSAC coder. + * + */ + +#include "arith_routins.h" +#include "bandwidth_estimator.h" +#include "codec.h" +#include "pitch_gain_tables.h" +#include "pitch_lag_tables.h" +#include "entropy_coding.h" +#include "lpc_tables.h" +#include "lpc_masking_model.h" +#include "pitch_estimator.h" +#include "structs.h" +#include <stdio.h> + + +int WebRtcIsacfix_EncodeImpl(WebRtc_Word16 *in, + ISACFIX_EncInst_t *ISACenc_obj, + BwEstimatorstr *bw_estimatordata, + WebRtc_Word16 CodingMode) +{ + WebRtc_Word16 stream_length = 0; + WebRtc_Word16 usefulstr_len = 0; + int k; + WebRtc_Word16 BWno; + + WebRtc_Word16 lofilt_coefQ15[(ORDERLO)*SUBFRAMES]; + WebRtc_Word16 hifilt_coefQ15[(ORDERHI)*SUBFRAMES]; + WebRtc_Word32 gain_lo_hiQ17[2*SUBFRAMES]; + + WebRtc_Word16 LPandHP[FRAMESAMPLES/2 + QLOOKAHEAD]; + WebRtc_Word16 LP16a[FRAMESAMPLES/2 + QLOOKAHEAD]; + WebRtc_Word16 HP16a[FRAMESAMPLES/2 + QLOOKAHEAD]; + + WebRtc_Word16 PitchLags_Q7[PITCH_SUBFRAMES]; + WebRtc_Word16 PitchGains_Q12[PITCH_SUBFRAMES]; + WebRtc_Word16 AvgPitchGain_Q12; + + WebRtc_Word16 frame_mode; /* 0 for 30ms, 1 for 60ms */ + WebRtc_Word16 processed_samples; + int status; + + WebRtc_Word32 bits_gainsQ11; + WebRtc_Word16 MinBytes; + WebRtc_Word16 bmodel; + + transcode_obj transcodingParam; + WebRtc_Word16 payloadLimitBytes; + WebRtc_Word16 arithLenBeforeEncodingDFT; + WebRtc_Word16 iterCntr; + + /* copy new frame length and bottle neck rate only for the first 10 ms data */ + if (ISACenc_obj->buffer_index == 0) { + /* set the framelength for the next packet */ + ISACenc_obj->current_framesamples = ISACenc_obj->new_framelength; + } + + frame_mode = ISACenc_obj->current_framesamples/MAX_FRAMESAMPLES; /* 0 (30 ms) or 1 (60 ms) */ + processed_samples = ISACenc_obj->current_framesamples/(frame_mode+1); /* 480 (30, 60 ms) */ + + /* buffer speech samples (by 10ms packet) until the framelength is reached (30 or 60 ms) */ + /**************************************************************************************/ + /* fill the buffer with 10ms input data */ + for(k=0; k<FRAMESAMPLES_10ms; k++) { + ISACenc_obj->data_buffer_fix[k + ISACenc_obj->buffer_index] = in[k]; + } + /* if buffersize is not equal to current framesize, and end of file is not reached yet, */ + /* increase index and go back to main to get more speech samples */ + if (ISACenc_obj->buffer_index + FRAMESAMPLES_10ms != processed_samples) { + ISACenc_obj->buffer_index = ISACenc_obj->buffer_index + FRAMESAMPLES_10ms; + return 0; + } + /* if buffer reached the right size, reset index and continue with encoding the frame */ + ISACenc_obj->buffer_index = 0; + + /* end of buffer function */ + /**************************/ + + /* encoding */ + /************/ + + if (frame_mode == 0 || ISACenc_obj->frame_nb == 0 ) + { + /* reset bitstream */ + ISACenc_obj->bitstr_obj.W_upper = 0xFFFFFFFF; + ISACenc_obj->bitstr_obj.streamval = 0; + ISACenc_obj->bitstr_obj.stream_index = 0; + ISACenc_obj->bitstr_obj.full = 1; + + if (CodingMode == 0) { + ISACenc_obj->BottleNeck = WebRtcIsacfix_GetUplinkBandwidth(bw_estimatordata); + ISACenc_obj->MaxDelay = WebRtcIsacfix_GetUplinkMaxDelay(bw_estimatordata); + } + if (CodingMode == 0 && frame_mode == 0 && (ISACenc_obj->enforceFrameSize == 0)) { + ISACenc_obj->new_framelength = WebRtcIsacfix_GetNewFrameLength(ISACenc_obj->BottleNeck, + ISACenc_obj->current_framesamples); + } + + // multiply the bottleneck by 0.88 before computing SNR, 0.88 is tuned by experimenting on TIMIT + // 901/1024 is 0.87988281250000 + ISACenc_obj->s2nr = WebRtcIsacfix_GetSnr((WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(ISACenc_obj->BottleNeck, 901, 10), + ISACenc_obj->current_framesamples); + + /* encode frame length */ + status = WebRtcIsacfix_EncodeFrameLen(ISACenc_obj->current_framesamples, &ISACenc_obj->bitstr_obj); + if (status < 0) + { + /* Wrong frame size */ + if (frame_mode == 1 && ISACenc_obj->frame_nb == 1) + { + // If this is the second 30ms of a 60ms frame reset this such that in the next call + // encoder starts fresh. + ISACenc_obj->frame_nb = 0; + } + return status; + } + + /* Save framelength for multiple packets memory */ + if (ISACenc_obj->SaveEnc_ptr != NULL) { + (ISACenc_obj->SaveEnc_ptr)->framelength=ISACenc_obj->current_framesamples; + } + + /* bandwidth estimation and coding */ + BWno = WebRtcIsacfix_GetDownlinkBwIndexImpl(bw_estimatordata); + status = WebRtcIsacfix_EncodeReceiveBandwidth(&BWno, &ISACenc_obj->bitstr_obj); + if (status < 0) + { + if (frame_mode == 1 && ISACenc_obj->frame_nb == 1) + { + // If this is the second 30ms of a 60ms frame reset this such that in the next call + // encoder starts fresh. + ISACenc_obj->frame_nb = 0; + } + return status; + } + } + + /* split signal in two bands */ + WebRtcIsacfix_SplitAndFilter1(ISACenc_obj->data_buffer_fix, LP16a, HP16a, &ISACenc_obj->prefiltbankstr_obj ); + + /* estimate pitch parameters and pitch-filter lookahead signal */ + WebRtcIsacfix_PitchAnalysis(LP16a+QLOOKAHEAD, LPandHP, + &ISACenc_obj->pitchanalysisstr_obj, PitchLags_Q7, PitchGains_Q12); /* LPandHP = LP_lookahead_pfQ0, */ + + /* Set where to store data in multiple packets memory */ + if (ISACenc_obj->SaveEnc_ptr != NULL) { + if (frame_mode == 0 || ISACenc_obj->frame_nb == 0) + { + (ISACenc_obj->SaveEnc_ptr)->startIdx = 0; + } + else + { + (ISACenc_obj->SaveEnc_ptr)->startIdx = 1; + } + } + + /* quantize & encode pitch parameters */ + status = WebRtcIsacfix_EncodePitchGain(PitchGains_Q12, &ISACenc_obj->bitstr_obj, ISACenc_obj->SaveEnc_ptr); + if (status < 0) + { + if (frame_mode == 1 && ISACenc_obj->frame_nb == 1) + { + // If this is the second 30ms of a 60ms frame reset this such that in the next call + // encoder starts fresh. + ISACenc_obj->frame_nb = 0; + } + return status; + } + status = WebRtcIsacfix_EncodePitchLag(PitchLags_Q7 , PitchGains_Q12, &ISACenc_obj->bitstr_obj, ISACenc_obj->SaveEnc_ptr); + if (status < 0) + { + if (frame_mode == 1 && ISACenc_obj->frame_nb == 1) + { + // If this is the second 30ms of a 60ms frame reset this such that in the next call + // encoder starts fresh. + ISACenc_obj->frame_nb = 0; + } + return status; + } + AvgPitchGain_Q12 = WEBRTC_SPL_RSHIFT_W32(PitchGains_Q12[0] + PitchGains_Q12[1] + PitchGains_Q12[2] + PitchGains_Q12[3], 2); + + /* find coefficients for perceptual pre-filters */ + WebRtcIsacfix_GetLpcCoef(LPandHP, HP16a+QLOOKAHEAD, &ISACenc_obj->maskfiltstr_obj, + ISACenc_obj->s2nr, PitchGains_Q12, + gain_lo_hiQ17, lofilt_coefQ15, hifilt_coefQ15); /*LPandHP = LP_lookahead_pfQ0*/ + + // record LPC Gains for possible bit-rate reduction + for(k = 0; k < KLT_ORDER_GAIN; k++) + { + transcodingParam.lpcGains[k] = gain_lo_hiQ17[k]; + } + + /* code LPC model and shape - gains not quantized yet */ + status = WebRtcIsacfix_EncodeLpc(gain_lo_hiQ17, lofilt_coefQ15, hifilt_coefQ15, + &bmodel, &bits_gainsQ11, &ISACenc_obj->bitstr_obj, ISACenc_obj->SaveEnc_ptr, &transcodingParam); + if (status < 0) + { + if (frame_mode == 1 && ISACenc_obj->frame_nb == 1) + { + // If this is the second 30ms of a 60ms frame reset this such that in the next call + // encoder starts fresh. + ISACenc_obj->frame_nb = 0; + } + return status; + } + arithLenBeforeEncodingDFT = (ISACenc_obj->bitstr_obj.stream_index << 1) + (1-ISACenc_obj->bitstr_obj.full); + + /* low-band filtering */ + WebRtcIsacfix_NormLatticeFilterMa(ORDERLO, ISACenc_obj->maskfiltstr_obj.PreStateLoGQ15, + LP16a, lofilt_coefQ15, gain_lo_hiQ17, 0, LPandHP);/* LPandHP = LP16b */ + + /* pitch filter */ + WebRtcIsacfix_PitchFilter(LPandHP, LP16a, &ISACenc_obj->pitchfiltstr_obj, PitchLags_Q7, PitchGains_Q12, 1);/* LPandHP = LP16b */ + + /* high-band filtering */ + WebRtcIsacfix_NormLatticeFilterMa(ORDERHI, ISACenc_obj->maskfiltstr_obj.PreStateHiGQ15, + HP16a, hifilt_coefQ15, gain_lo_hiQ17, 1, LPandHP);/*LPandHP = HP16b*/ + + /* transform */ + WebRtcIsacfix_Time2Spec(LP16a, LPandHP, LP16a, LPandHP); /*LPandHP = HP16b*/ + + /* Save data for multiple packets memory */ + if (ISACenc_obj->SaveEnc_ptr != NULL) { + for (k = 0; k < FRAMESAMPLES_HALF; k++) { + (ISACenc_obj->SaveEnc_ptr)->fre[k + (ISACenc_obj->SaveEnc_ptr)->startIdx*FRAMESAMPLES_HALF] = LP16a[k]; + (ISACenc_obj->SaveEnc_ptr)->fim[k + (ISACenc_obj->SaveEnc_ptr)->startIdx*FRAMESAMPLES_HALF] = LPandHP[k]; + } + (ISACenc_obj->SaveEnc_ptr)->AvgPitchGain[(ISACenc_obj->SaveEnc_ptr)->startIdx] = AvgPitchGain_Q12; + } + + /* quantization and lossless coding */ + status = WebRtcIsacfix_EncodeSpec(LP16a, LPandHP, &ISACenc_obj->bitstr_obj, AvgPitchGain_Q12); + if((status <= -1) && (status != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) /*LPandHP = HP16b*/ + { + if (frame_mode == 1 && ISACenc_obj->frame_nb == 1) + { + // If this is the second 30ms of a 60ms frame reset this such that in the next call + // encoder starts fresh. + ISACenc_obj->frame_nb = 0; + } + return status; + } + + if((frame_mode == 1) && (ISACenc_obj->frame_nb == 0)) + { + // it is a 60ms and we are in the first 30ms + // then the limit at this point should be half of the assigned value + payloadLimitBytes = ISACenc_obj->payloadLimitBytes60 >> 1; + } + else if (frame_mode == 0) + { + // it is a 30ms frame + payloadLimitBytes = (ISACenc_obj->payloadLimitBytes30) - 3; + } + else + { + // this is the second half of a 60ms frame. + payloadLimitBytes = ISACenc_obj->payloadLimitBytes60 - 3; // subract 3 because termination process may add 3 bytes + } + + iterCntr = 0; + while((((ISACenc_obj->bitstr_obj.stream_index) << 1) > payloadLimitBytes) || + (status == -ISAC_DISALLOWED_BITSTREAM_LENGTH)) + { + WebRtc_Word16 arithLenDFTByte; + WebRtc_Word16 bytesLeftQ5; + WebRtc_Word16 ratioQ5[8] = {0, 6, 9, 12, 16, 19, 22, 25}; + + // According to experiments on TIMIT the following is proper for audio, but it is not agressive enough for tonal inputs + // such as DTMF, sweep-sine, ... + // + // (0.55 - (0.8 - ratio[i]/32) * 5 / 6) * 2^14 + // WebRtc_Word16 scaleQ14[8] = {0, 648, 1928, 3208, 4915, 6195, 7475, 8755}; + + + // This is a supper-agressive scaling passed the tests (tonal inputs) tone with one iteration for payload limit + // of 120 (32kbps bottleneck), number of frames needed a rate-reduction was 58403 + // + WebRtc_Word16 scaleQ14[8] = {0, 348, 828, 1408, 2015, 3195, 3500, 3500}; + WebRtc_Word16 idx; + + if(iterCntr >= MAX_PAYLOAD_LIMIT_ITERATION) + { + // We were not able to limit the payload size + + if((frame_mode == 1) && (ISACenc_obj->frame_nb == 0)) + { + // This was the first 30ms of a 60ms frame. Although the payload is larger than it + // should be but we let the second 30ms be encoded. Maybe togetehr we won't exceed + // the limit. + ISACenc_obj->frame_nb = 1; + return 0; + } + else if((frame_mode == 1) && (ISACenc_obj->frame_nb == 1)) + { + ISACenc_obj->frame_nb = 0; + } + + if(status != -ISAC_DISALLOWED_BITSTREAM_LENGTH) + { + return -ISAC_PAYLOAD_LARGER_THAN_LIMIT; + } + else + { + return status; + } + } + if(status != -ISAC_DISALLOWED_BITSTREAM_LENGTH) + { + arithLenDFTByte = (ISACenc_obj->bitstr_obj.stream_index << 1) + (1-ISACenc_obj->bitstr_obj.full) - arithLenBeforeEncodingDFT; + bytesLeftQ5 = (payloadLimitBytes - arithLenBeforeEncodingDFT) << 5; + + // bytesLeft / arithLenDFTBytes indicates how much scaling is required a rough estimate (agressive) + // scale = 0.55 - (0.8 - bytesLeft / arithLenDFTBytes) * 5 / 6 + // bytesLeft / arithLenDFTBytes below 0.2 will have a scale of zero and above 0.8 are treated as 0.8 + // to avoid division we do more simplification. + // + // values of (bytesLeft / arithLenDFTBytes)*32 between ratioQ5[i] and ratioQ5[i+1] are rounded to ratioQ5[i] + // and the corresponding scale is chosen + + // we compare bytesLeftQ5 with ratioQ5[]*arithLenDFTByte; + idx = 4; + idx += (bytesLeftQ5 >= WEBRTC_SPL_MUL_16_16(ratioQ5[idx], arithLenDFTByte))? 2:-2; + idx += (bytesLeftQ5 >= WEBRTC_SPL_MUL_16_16(ratioQ5[idx], arithLenDFTByte))? 1:-1; + idx += (bytesLeftQ5 >= WEBRTC_SPL_MUL_16_16(ratioQ5[idx], arithLenDFTByte))? 0:-1; + } + else + { + // we are here because the bit-stream did not fit into the buffer, in this case, the stream_index is not + // trustable, especially if the is the first 30ms of a packet. Thereforem, we will go for the most agressive + // case. + idx = 0; + } + // scale FFT coefficients to reduce the bit-rate + for(k = 0; k < FRAMESAMPLES_HALF; k++) + { + LP16a[k] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(LP16a[k], scaleQ14[idx], 14); + LPandHP[k] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(LPandHP[k], scaleQ14[idx], 14); + } + + // Save data for multiple packets memory + if (ISACenc_obj->SaveEnc_ptr != NULL) + { + for(k = 0; k < FRAMESAMPLES_HALF; k++) + { + (ISACenc_obj->SaveEnc_ptr)->fre[k + (ISACenc_obj->SaveEnc_ptr)->startIdx*FRAMESAMPLES_HALF] = LP16a[k]; + (ISACenc_obj->SaveEnc_ptr)->fim[k + (ISACenc_obj->SaveEnc_ptr)->startIdx*FRAMESAMPLES_HALF] = LPandHP[k]; + } + } + + // scale the unquantized LPC gains and save the scaled version for the future use + for(k = 0; k < KLT_ORDER_GAIN; k++) + { + gain_lo_hiQ17[k] = WEBRTC_SPL_MUL_16_32_RSFT14(scaleQ14[idx], transcodingParam.lpcGains[k]);//transcodingParam.lpcGains[k]; // + transcodingParam.lpcGains[k] = gain_lo_hiQ17[k]; + } + + // reset the bit-stream object to the state which it had before encoding LPC Gains + ISACenc_obj->bitstr_obj.full = transcodingParam.full; + ISACenc_obj->bitstr_obj.stream_index = transcodingParam.stream_index; + ISACenc_obj->bitstr_obj.streamval = transcodingParam.streamval; + ISACenc_obj->bitstr_obj.W_upper = transcodingParam.W_upper; + ISACenc_obj->bitstr_obj.stream[transcodingParam.stream_index-1] = transcodingParam.beforeLastWord; + ISACenc_obj->bitstr_obj.stream[transcodingParam.stream_index] = transcodingParam.lastWord; + + + // quantize and encode LPC gain + WebRtcIsacfix_EstCodeLpcGain(gain_lo_hiQ17, &ISACenc_obj->bitstr_obj, ISACenc_obj->SaveEnc_ptr); + arithLenBeforeEncodingDFT = (ISACenc_obj->bitstr_obj.stream_index << 1) + (1-ISACenc_obj->bitstr_obj.full); + status = WebRtcIsacfix_EncodeSpec(LP16a, LPandHP, &ISACenc_obj->bitstr_obj, AvgPitchGain_Q12); + if((status <= -1) && (status != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) /*LPandHP = HP16b*/ + { + if (frame_mode == 1 && ISACenc_obj->frame_nb == 1) + { + // If this is the second 30ms of a 60ms frame reset this such that in the next call + // encoder starts fresh. + ISACenc_obj->frame_nb = 0; + } + return status; + } + iterCntr++; + } + + if (frame_mode == 1 && ISACenc_obj->frame_nb == 0) + /* i.e. 60 ms framesize and just processed the first 30ms, */ + /* go back to main function to buffer the other 30ms speech frame */ + { + ISACenc_obj->frame_nb = 1; + return 0; + } + else if (frame_mode == 1 && ISACenc_obj->frame_nb == 1) + { + ISACenc_obj->frame_nb = 0; + /* also update the framelength for next packet, in Adaptive mode only */ + if (CodingMode == 0 && (ISACenc_obj->enforceFrameSize == 0)) { + ISACenc_obj->new_framelength = WebRtcIsacfix_GetNewFrameLength(ISACenc_obj->BottleNeck, + ISACenc_obj->current_framesamples); + } + } + + + /* complete arithmetic coding */ + stream_length = WebRtcIsacfix_EncTerminate(&ISACenc_obj->bitstr_obj); + /* can this be negative? */ + + if(CodingMode == 0) + { + + /* update rate model and get minimum number of bytes in this packet */ + MinBytes = WebRtcIsacfix_GetMinBytes(&ISACenc_obj->rate_data_obj, (WebRtc_Word16) stream_length, + ISACenc_obj->current_framesamples, ISACenc_obj->BottleNeck, ISACenc_obj->MaxDelay); + + /* if bitstream is too short, add garbage at the end */ + + /* Store length of coded data */ + usefulstr_len = stream_length; + + /* Make sure MinBytes does not exceed packet size limit */ + if ((ISACenc_obj->frame_nb == 0) && (MinBytes > ISACenc_obj->payloadLimitBytes30)) { + MinBytes = ISACenc_obj->payloadLimitBytes30; + } else if ((ISACenc_obj->frame_nb == 1) && (MinBytes > ISACenc_obj->payloadLimitBytes60)) { + MinBytes = ISACenc_obj->payloadLimitBytes60; + } + + /* Make sure we don't allow more than 255 bytes of garbage data. + We store the length of the garbage data in 8 bits in the bitstream, + 255 is the max garbage lenght we can signal using 8 bits. */ + if( MinBytes > usefulstr_len + 255 ) { + MinBytes = usefulstr_len + 255; + } + + /* Save data for creation of multiple bitstreams */ + if (ISACenc_obj->SaveEnc_ptr != NULL) { + (ISACenc_obj->SaveEnc_ptr)->minBytes = MinBytes; + } + + while (stream_length < MinBytes) + { + if (stream_length & 0x0001){ + ISACenc_obj->bitstr_seed = WEBRTC_SPL_RAND( ISACenc_obj->bitstr_seed ); + ISACenc_obj->bitstr_obj.stream[ WEBRTC_SPL_RSHIFT_W16(stream_length, 1) ] |= (WebRtc_UWord16)(ISACenc_obj->bitstr_seed & 0xFF); + } else { + ISACenc_obj->bitstr_seed = WEBRTC_SPL_RAND( ISACenc_obj->bitstr_seed ); + ISACenc_obj->bitstr_obj.stream[ WEBRTC_SPL_RSHIFT_W16(stream_length, 1) ] = WEBRTC_SPL_LSHIFT_U16(ISACenc_obj->bitstr_seed, 8); + } + stream_length++; + } + + /* to get the real stream_length, without garbage */ + if (usefulstr_len & 0x0001) { + ISACenc_obj->bitstr_obj.stream[usefulstr_len>>1] &= 0xFF00; + ISACenc_obj->bitstr_obj.stream[usefulstr_len>>1] += (MinBytes - usefulstr_len) & 0x00FF; + } + else { + ISACenc_obj->bitstr_obj.stream[usefulstr_len>>1] &= 0x00FF; + ISACenc_obj->bitstr_obj.stream[usefulstr_len>>1] += WEBRTC_SPL_LSHIFT_U16((MinBytes - usefulstr_len) & 0x00FF, 8); + } + } + else + { + /* update rate model */ + WebRtcIsacfix_UpdateRateModel(&ISACenc_obj->rate_data_obj, (WebRtc_Word16) stream_length, + ISACenc_obj->current_framesamples, ISACenc_obj->BottleNeck); + } + return stream_length; +} + +/* This function is used to create a new bitstream with new BWE. + The same data as previously encoded with the fucntion WebRtcIsacfix_EncodeImpl() + is used. The data needed is taken from the struct, where it was stored + when calling the encoder. */ +int WebRtcIsacfix_EncodeStoredData(ISACFIX_EncInst_t *ISACenc_obj, + int BWnumber, + float scale) +{ + int ii; + int status; + WebRtc_Word16 BWno = BWnumber; + int stream_length = 0; + + WebRtc_Word16 model; + const WebRtc_UWord16 *Q_PitchGain_cdf_ptr[1]; + const WebRtc_UWord16 **cdf; + const ISAC_SaveEncData_t *SaveEnc_str; + WebRtc_Word32 tmpLPCcoeffs_g[KLT_ORDER_GAIN<<1]; + WebRtc_Word16 tmpLPCindex_g[KLT_ORDER_GAIN<<1]; + WebRtc_Word16 tmp_fre[FRAMESAMPLES]; + WebRtc_Word16 tmp_fim[FRAMESAMPLES]; + + SaveEnc_str = ISACenc_obj->SaveEnc_ptr; + + /* Check if SaveEnc memory exists */ + if (SaveEnc_str == NULL) { + return (-1); + } + + /* Sanity Check - possible values for BWnumber is 0 - 23 */ + if ((BWnumber < 0) || (BWnumber > 23)) { + return -ISAC_RANGE_ERROR_BW_ESTIMATOR; + } + + /* reset bitstream */ + ISACenc_obj->bitstr_obj.W_upper = 0xFFFFFFFF; + ISACenc_obj->bitstr_obj.streamval = 0; + ISACenc_obj->bitstr_obj.stream_index = 0; + ISACenc_obj->bitstr_obj.full = 1; + + /* encode frame length */ + status = WebRtcIsacfix_EncodeFrameLen(SaveEnc_str->framelength, &ISACenc_obj->bitstr_obj); + if (status < 0) { + /* Wrong frame size */ + return status; + } + + /* encode bandwidth estimate */ + status = WebRtcIsacfix_EncodeReceiveBandwidth(&BWno, &ISACenc_obj->bitstr_obj); + if (status < 0) { + return status; + } + + /* Transcoding */ + /* If scale < 1, rescale data to produce lower bitrate signal */ + if ((0.0 < scale) && (scale < 1.0)) { + /* Compensate LPC gain */ + for (ii = 0; ii < (KLT_ORDER_GAIN*(1+SaveEnc_str->startIdx)); ii++) { + tmpLPCcoeffs_g[ii] = (WebRtc_Word32) ((scale) * (float) SaveEnc_str->LPCcoeffs_g[ii]); + } + + /* Scale DFT */ + for (ii = 0; ii < (FRAMESAMPLES_HALF*(1+SaveEnc_str->startIdx)); ii++) { + tmp_fre[ii] = (WebRtc_Word16) ((scale) * (float) SaveEnc_str->fre[ii]) ; + tmp_fim[ii] = (WebRtc_Word16) ((scale) * (float) SaveEnc_str->fim[ii]) ; + } + } else { + for (ii = 0; ii < (KLT_ORDER_GAIN*(1+SaveEnc_str->startIdx)); ii++) { + tmpLPCindex_g[ii] = SaveEnc_str->LPCindex_g[ii]; + } + + for (ii = 0; ii < (FRAMESAMPLES_HALF*(1+SaveEnc_str->startIdx)); ii++) { + tmp_fre[ii] = SaveEnc_str->fre[ii]; + tmp_fim[ii] = SaveEnc_str->fim[ii]; + } + } + + /* Loop over number of 30 msec */ + for (ii = 0; ii <= SaveEnc_str->startIdx; ii++) + { + + /* encode pitch gains */ + *Q_PitchGain_cdf_ptr = WebRtcIsacfix_kPitchGainCdf; + status = WebRtcIsacfix_EncHistMulti(&ISACenc_obj->bitstr_obj, &SaveEnc_str->pitchGain_index[ii], + Q_PitchGain_cdf_ptr, 1); + if (status < 0) { + return status; + } + + /* entropy coding of quantization pitch lags */ + /* voicing classificiation */ + if (SaveEnc_str->meanGain[ii] <= 819) { + cdf = WebRtcIsacfix_kPitchLagPtrLo; + } else if (SaveEnc_str->meanGain[ii] <= 1638) { + cdf = WebRtcIsacfix_kPitchLagPtrMid; + } else { + cdf = WebRtcIsacfix_kPitchLagPtrHi; + } + status = WebRtcIsacfix_EncHistMulti(&ISACenc_obj->bitstr_obj, + &SaveEnc_str->pitchIndex[PITCH_SUBFRAMES*ii], cdf, PITCH_SUBFRAMES); + if (status < 0) { + return status; + } + + /* LPC */ + /* entropy coding of model number */ + model = 0; + status = WebRtcIsacfix_EncHistMulti(&ISACenc_obj->bitstr_obj, &model, + WebRtcIsacfix_kModelCdfPtr, 1); + if (status < 0) { + return status; + } + + /* entropy coding of quantization indices - LPC shape only */ + status = WebRtcIsacfix_EncHistMulti(&ISACenc_obj->bitstr_obj, &SaveEnc_str->LPCindex_s[KLT_ORDER_SHAPE*ii], + WebRtcIsacfix_kCdfShapePtr[0], KLT_ORDER_SHAPE); + if (status < 0) { + return status; + } + + /* If transcoding, get new LPC gain indices */ + if (scale < 1.0) { + WebRtcIsacfix_TranscodeLpcCoef(&tmpLPCcoeffs_g[KLT_ORDER_GAIN*ii], &tmpLPCindex_g[KLT_ORDER_GAIN*ii]); + } + + /* entropy coding of quantization indices - LPC gain */ + status = WebRtcIsacfix_EncHistMulti(&ISACenc_obj->bitstr_obj, &tmpLPCindex_g[KLT_ORDER_GAIN*ii], + WebRtcIsacfix_kCdfGainPtr[0], KLT_ORDER_GAIN); + if (status < 0) { + return status; + } + + /* quantization and lossless coding */ + status = WebRtcIsacfix_EncodeSpec(&tmp_fre[ii*FRAMESAMPLES_HALF], &tmp_fim[ii*FRAMESAMPLES_HALF], + &ISACenc_obj->bitstr_obj, SaveEnc_str->AvgPitchGain[ii]); + if (status < 0) { + return status; + } + } + + /* complete arithmetic coding */ + stream_length = WebRtcIsacfix_EncTerminate(&ISACenc_obj->bitstr_obj); + + return stream_length; +} diff --git a/src/modules/audio_coding/codecs/isac/fix/source/entropy_coding.c b/src/modules/audio_coding/codecs/isac/fix/source/entropy_coding.c new file mode 100644 index 0000000000..0b64d8358b --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/entropy_coding.c @@ -0,0 +1,2072 @@ +/* + * 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. + */ + +/* + * entropy_coding.c + * + * This file contains all functions used to arithmetically + * encode the iSAC bistream. + * + */ + +#include <stddef.h> + +#include "arith_routins.h" +#include "spectrum_ar_model_tables.h" +#include "pitch_gain_tables.h" +#include "pitch_lag_tables.h" +#include "entropy_coding.h" +#include "lpc_tables.h" +#include "settings.h" +#include "signal_processing_library.h" + + +/* + This function implements the fix-point correspondant function to lrint. + + FLP: (WebRtc_Word32)floor(flt+.499999999999) + FIP: (fixVal+roundVal)>>qDomain + + where roundVal = 2^(qDomain-1) = 1<<(qDomain-1) + +*/ +static __inline WebRtc_Word32 CalcLrIntQ(WebRtc_Word32 fixVal, WebRtc_Word16 qDomain) { + WebRtc_Word32 intgr; + WebRtc_Word32 roundVal; + + roundVal = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)1, qDomain-1); + intgr = WEBRTC_SPL_RSHIFT_W32(fixVal+roundVal, qDomain); + + return intgr; +} + +/* + __inline WebRtc_UWord32 stepwise(WebRtc_Word32 dinQ10) { + + WebRtc_Word32 ind, diQ10, dtQ10; + + diQ10 = dinQ10; + if (diQ10 < DPMIN_Q10) + diQ10 = DPMIN_Q10; + if (diQ10 >= DPMAX_Q10) + diQ10 = DPMAX_Q10 - 1; + + dtQ10 = diQ10 - DPMIN_Q10;*/ /* Q10 + Q10 = Q10 */ +/* ind = (dtQ10 * 5) >> 10; */ /* 2^10 / 5 = 0.2 in Q10 */ +/* Q10 -> Q0 */ + +/* return rpointsFIX_Q10[ind]; + + } +*/ + +/* logN(x) = logN(2)*log2(x) = 0.6931*log2(x). Output in Q8. */ +/* The input argument X to logN(X) is 2^17 times higher than the + input floating point argument Y to log(Y), since the X value + is a Q17 value. This can be compensated for after the call, by + subraction a value Z for each Q-step. One Q-step means that + X gets 2 thimes higher, i.e. Z = logN(2)*256 = 0.693147180559*256 = + 177.445678 should be subtracted (since logN() returns a Q8 value). + For a X value in Q17, the value 177.445678*17 = 3017 should be + subtracted */ +static WebRtc_Word16 CalcLogN(WebRtc_Word32 arg) { + WebRtc_Word16 zeros, log2, frac, logN; + + zeros=WebRtcSpl_NormU32(arg); + frac=(WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32(WEBRTC_SPL_LSHIFT_W32(arg, zeros)&0x7FFFFFFF, 23); + log2=(WebRtc_Word16)(WEBRTC_SPL_LSHIFT_W32(31-zeros, 8)+frac); // log2(x) in Q8 + logN=(WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(log2,22713,15); //Q8*Q15 log(2) = 0.693147 = 22713 in Q15 + logN=logN+11; //Scalar compensation which minimizes the (log(x)-logN(x))^2 error over all x. + + return logN; +} + + +/* + expN(x) = 2^(a*x), where a = log2(e) ~= 1.442695 + + Input: Q8 (WebRtc_Word16) + Output: Q17 (WebRtc_Word32) + + a = log2(e) = log2(exp(1)) ~= 1.442695 ==> a = 23637 in Q14 (1.442688) + To this value, 700 is added or subtracted in order to get an average error + nearer zero, instead of always same-sign. +*/ + +static WebRtc_Word32 CalcExpN(WebRtc_Word16 x) { + WebRtc_Word16 ax, axINT, axFRAC; + WebRtc_Word16 exp16; + WebRtc_Word32 exp; + + if (x>=0) { + // ax=(WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(x, 23637-700, 14); //Q8 + ax=(WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(x, 23637, 14); //Q8 + axINT = WEBRTC_SPL_RSHIFT_W16(ax, 8); //Q0 + axFRAC = ax&0x00FF; + exp16 = WEBRTC_SPL_LSHIFT_W32(1, axINT); //Q0 + axFRAC = axFRAC+256; //Q8 + exp = WEBRTC_SPL_MUL_16_16(exp16, axFRAC); // Q0*Q8 = Q8 + exp = WEBRTC_SPL_LSHIFT_W32(exp, 9); //Q17 + } else { + // ax=(WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(x, 23637+700, 14); //Q8 + ax=(WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(x, 23637, 14); //Q8 + ax = -ax; + axINT = 1 + WEBRTC_SPL_RSHIFT_W16(ax, 8); //Q0 + axFRAC = 0x00FF - (ax&0x00FF); + exp16 = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(32768, axINT); //Q15 + axFRAC = axFRAC+256; //Q8 + exp = WEBRTC_SPL_MUL_16_16(exp16, axFRAC); // Q15*Q8 = Q23 + exp = WEBRTC_SPL_RSHIFT_W32(exp, 6); //Q17 + } + + return exp; +} + + +/* compute correlation from power spectrum */ +static void CalcCorrelation(WebRtc_Word32 *PSpecQ12, WebRtc_Word32 *CorrQ7) +{ + WebRtc_Word32 summ[FRAMESAMPLES/8]; + WebRtc_Word32 diff[FRAMESAMPLES/8]; + WebRtc_Word32 sum; + int k, n; + + for (k = 0; k < FRAMESAMPLES/8; k++) { + summ[k] = WEBRTC_SPL_RSHIFT_W32(PSpecQ12[k] + PSpecQ12[FRAMESAMPLES/4-1 - k] + 16, 5); + diff[k] = WEBRTC_SPL_RSHIFT_W32(PSpecQ12[k] - PSpecQ12[FRAMESAMPLES/4-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; + for (n = 0; n < FRAMESAMPLES/8; n++) + sum += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(WebRtcIsacfix_kCos[k][n], diff[n]) + 256, 9); + CorrQ7[k+1] = sum; + } + + for (k=1; k<AR_ORDER; k+=2) { + sum = 0; + for (n = 0; n < FRAMESAMPLES/8; n++) + sum += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(WebRtcIsacfix_kCos[k][n], summ[n]) + 256, 9); + CorrQ7[k+1] = sum; + } +} + + +/* compute inverse AR power spectrum */ +static void CalcInvArSpec(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); /* result in 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(WebRtcIsacfix_kCos[k][n], CorrQ11[k+1]) + 2, 2); + } + + CS_ptrQ9 = WebRtcIsacfix_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 = WebRtcIsacfix_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/4-1 - k] = CurveQ16[k] - WEBRTC_SPL_LSHIFT_W32(diffQ16[k], shftVal); + CurveQ16[k] += WEBRTC_SPL_LSHIFT_W32(diffQ16[k], shftVal); + } +} + +static void CalcRootInvArSpec(const WebRtc_Word16 *ARCoefQ12, + const WebRtc_Word32 gainQ10, + WebRtc_UWord16 *CurveQ8) +{ + WebRtc_Word32 CorrQ11[AR_ORDER+1]; + WebRtc_Word32 sum, tmpGain; + WebRtc_Word32 summQ16[FRAMESAMPLES/8]; + WebRtc_Word32 diffQ16[FRAMESAMPLES/8]; + + const WebRtc_Word16 *CS_ptrQ9; + int k, n, i; + WebRtc_Word16 round, shftVal = 0, sh; + WebRtc_Word32 res, in_sqrt, newRes; + + 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); /* result in 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++) + summQ16[n] = sum; + + for (k = 1; k < (AR_ORDER); k += 2) { + for (n = 0; n < FRAMESAMPLES/8; n++) + summQ16[n] += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_32_16(CorrQ11[k+1],WebRtcIsacfix_kCos[k][n]) + 2, 2); + } + + CS_ptrQ9 = WebRtcIsacfix_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 = WebRtcIsacfix_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); + } + + in_sqrt = summQ16[0] + WEBRTC_SPL_LSHIFT_W32(diffQ16[0], shftVal); + + /* convert to magnitude spectrum, by doing square-roots (modified from SPLIB) */ + res = WEBRTC_SPL_LSHIFT_W32(1, WEBRTC_SPL_RSHIFT_W16(WebRtcSpl_GetSizeInBits(in_sqrt), 1)); + + for (k = 0; k < FRAMESAMPLES/8; k++) + { + in_sqrt = summQ16[k] + WEBRTC_SPL_LSHIFT_W32(diffQ16[k], shftVal); + i = 10; + + /* make in_sqrt positive to prohibit sqrt of negative values */ + if(in_sqrt<0) + in_sqrt=-in_sqrt; + + newRes = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_DIV(in_sqrt, res) + res, 1); + do + { + res = newRes; + newRes = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_DIV(in_sqrt, res) + res, 1); + } while (newRes != res && i-- > 0); + + CurveQ8[k] = (WebRtc_Word16)newRes; + } + for (k = FRAMESAMPLES/8; k < FRAMESAMPLES/4; k++) { + + in_sqrt = summQ16[FRAMESAMPLES/4-1 - k] - WEBRTC_SPL_LSHIFT_W32(diffQ16[FRAMESAMPLES/4-1 - k], shftVal); + i = 10; + + /* make in_sqrt positive to prohibit sqrt of negative values */ + if(in_sqrt<0) + in_sqrt=-in_sqrt; + + newRes = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_DIV(in_sqrt, res) + res, 1); + do + { + res = newRes; + newRes = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_DIV(in_sqrt, res) + res, 1); + } while (newRes != res && i-- > 0); + + CurveQ8[k] = (WebRtc_Word16)newRes; + } + +} + + + +/* generate array of dither samples in Q7 */ +static void GenerateDitherQ7(WebRtc_Word16 *bufQ7, + WebRtc_UWord32 seed, + WebRtc_Word16 length, + WebRtc_Word16 AvgPitchGain_Q12) +{ + int k; + WebRtc_Word16 dither1_Q7, dither2_Q7, dither_gain_Q14, shft; + + if (AvgPitchGain_Q12 < 614) /* this threshold should be equal to that in decode_spec() */ + { + for (k = 0; k < length-2; k += 3) + { + /* new random unsigned WebRtc_Word32 */ + seed = WEBRTC_SPL_UMUL(seed, 196314165) + 907633515; + + /* fixed-point dither sample between -64 and 64 (Q7) */ + dither1_Q7 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((WebRtc_Word32)seed + 16777216, 25); // * 128/4294967295 + + /* new random unsigned WebRtc_Word32 */ + seed = WEBRTC_SPL_UMUL(seed, 196314165) + 907633515; + + /* fixed-point dither sample between -64 and 64 */ + dither2_Q7 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(seed + 16777216, 25); + + shft = (WebRtc_Word16)(WEBRTC_SPL_RSHIFT_U32(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 - WEBRTC_SPL_MUL(10, AvgPitchGain_Q12)); + + /* dither on half of the coefficients */ + for (k = 0; k < length-1; k += 2) + { + /* new random unsigned WebRtc_Word32 */ + seed = WEBRTC_SPL_UMUL(seed, 196314165) + 907633515; + + /* fixed-point dither sample between -64 and 64 */ + dither1_Q7 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((WebRtc_Word32)seed + 16777216, 25); + + /* dither sample is placed in either even or odd index */ + shft = (WebRtc_Word16)(WEBRTC_SPL_RSHIFT_U32(seed, 25) & 1); /* either 0 or 1 */ + + bufQ7[k + shft] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(dither_gain_Q14, dither1_Q7) + 8192, 14); + bufQ7[k + 1 - shft] = 0; + } + } +} + + + + +/* + * function to decode the complex spectrum from the bitstream + * returns the total number of bytes in the stream + */ +WebRtc_Word16 WebRtcIsacfix_DecodeSpec(Bitstr_dec *streamdata, + WebRtc_Word16 *frQ7, + WebRtc_Word16 *fiQ7, + WebRtc_Word16 AvgPitchGain_Q12) +{ + WebRtc_Word16 data[FRAMESAMPLES]; + WebRtc_Word32 invARSpec2_Q16[FRAMESAMPLES/4]; + WebRtc_Word16 ARCoefQ12[AR_ORDER+1]; + WebRtc_Word16 RCQ15[AR_ORDER]; + WebRtc_Word16 gainQ10; + WebRtc_Word32 gain2_Q10; + WebRtc_Word16 len; + int k; + + /* create dither signal */ + GenerateDitherQ7(data, streamdata->W_upper, FRAMESAMPLES, AvgPitchGain_Q12); /* Dither is output in vector 'Data' */ + + /* decode model parameters */ + if (WebRtcIsacfix_DecodeRcCoef(streamdata, RCQ15) < 0) + return -ISAC_RANGE_ERROR_DECODE_SPECTRUM; + + + WebRtcSpl_ReflCoefToLpc(RCQ15, AR_ORDER, ARCoefQ12); + + if (WebRtcIsacfix_DecodeGain2(streamdata, &gain2_Q10) < 0) + return -ISAC_RANGE_ERROR_DECODE_SPECTRUM; + + /* compute inverse AR power spectrum */ + CalcInvArSpec(ARCoefQ12, gain2_Q10, invARSpec2_Q16); + + /* arithmetic decoding of spectrum */ + /* 'data' input and output. Input = Dither */ + len = WebRtcIsacfix_DecLogisticMulti2(data, streamdata, invARSpec2_Q16, (WebRtc_Word16)FRAMESAMPLES); + + if (len<1) + return -ISAC_RANGE_ERROR_DECODE_SPECTRUM; + + /* subtract dither and scale down spectral samples with low SNR */ + if (AvgPitchGain_Q12 <= 614) + { + for (k = 0; k < FRAMESAMPLES; k += 4) + { + gainQ10 = WebRtcSpl_DivW32W16ResW16(WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)30, 10), + (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32(invARSpec2_Q16[k>>2] + (WebRtc_UWord32)2195456, 16)); + *frQ7++ = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[ k ], gainQ10) + 512, 10); + *fiQ7++ = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[k+1], gainQ10) + 512, 10); + *frQ7++ = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[k+2], gainQ10) + 512, 10); + *fiQ7++ = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[k+3], gainQ10) + 512, 10); + } + } + else + { + for (k = 0; k < FRAMESAMPLES; k += 4) + { + gainQ10 = WebRtcSpl_DivW32W16ResW16(WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)36, 10), + (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32(invARSpec2_Q16[k>>2] + (WebRtc_UWord32)2654208, 16)); + *frQ7++ = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[ k ], gainQ10) + 512, 10); + *fiQ7++ = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[k+1], gainQ10) + 512, 10); + *frQ7++ = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[k+2], gainQ10) + 512, 10); + *fiQ7++ = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(data[k+3], gainQ10) + 512, 10); + } + } + + return len; +} + + +int WebRtcIsacfix_EncodeSpec(const WebRtc_Word16 *fr, + const WebRtc_Word16 *fi, + Bitstr_enc *streamdata, + WebRtc_Word16 AvgPitchGain_Q12) +{ + WebRtc_Word16 dataQ7[FRAMESAMPLES]; + WebRtc_Word32 PSpec[FRAMESAMPLES/4]; + WebRtc_UWord16 invARSpecQ8[FRAMESAMPLES/4]; + 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; + WebRtc_UWord32 sum; + WebRtc_Word16 lft_shft; + WebRtc_Word16 status; + int k, n, j; + + + /* create dither_float signal */ + GenerateDitherQ7(dataQ7, streamdata->W_upper, FRAMESAMPLES, AvgPitchGain_Q12); + + /* add dither and quantize, and compute power spectrum */ + /* Vector dataQ7 contains Dither in Q7 */ + for (k = 0; k < FRAMESAMPLES; k += 4) + { + val = ((*fr++ + dataQ7[k] + 64) & 0xFF80) - dataQ7[k]; /* Data = Dither */ + dataQ7[k] = val; /* New value in Data */ + sum = WEBRTC_SPL_UMUL(val, val); + + val = ((*fi++ + dataQ7[k+1] + 64) & 0xFF80) - dataQ7[k+1]; /* Data = Dither */ + dataQ7[k+1] = val; /* New value in Data */ + sum += WEBRTC_SPL_UMUL(val, val); + + val = ((*fr++ + dataQ7[k+2] + 64) & 0xFF80) - dataQ7[k+2]; /* Data = Dither */ + dataQ7[k+2] = val; /* New value in Data */ + sum += WEBRTC_SPL_UMUL(val, val); + + val = ((*fi++ + dataQ7[k+3] + 64) & 0xFF80) - dataQ7[k+3]; /* Data = Dither */ + dataQ7[k+3] = val; /* New value in Data */ + sum += WEBRTC_SPL_UMUL(val, val); + + PSpec[k>>2] = WEBRTC_SPL_RSHIFT_U32(sum, 2); + } + + /* compute correlation from power spectrum */ + CalcCorrelation(PSpec, CorrQ7); + + + /* find AR coefficients */ + /* number of bit shifts to 14-bit normalize CorrQ7[0] (leaving room for sign) */ + lft_shft = WebRtcSpl_NormW32(CorrQ7[0]) - 18; + + if (lft_shft > 0) { + for (k=0; k<AR_ORDER+1; k++) + CorrQ7_norm[k] = WEBRTC_SPL_LSHIFT_W32(CorrQ7[k], lft_shft); + } else { + for (k=0; k<AR_ORDER+1; k++) + CorrQ7_norm[k] = WEBRTC_SPL_RSHIFT_W32(CorrQ7[k], -lft_shft); + } + + /* find RC coefficients */ + WebRtcSpl_AutoCorrToReflCoef(CorrQ7_norm, AR_ORDER, RCQ15); + + /* quantize & code RC Coef */ + status = WebRtcIsacfix_EncodeRcCoef(RCQ15, streamdata); + if (status < 0) { + return status; + } + + /* 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 += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(ARCoefQ12[j], WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(CorrQ7_norm[j-n], ARCoefQ12[n]) + 256, 9)) + 4, 3); + for (n = j+1; n <= AR_ORDER; n++) + nrg += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(ARCoefQ12[j], WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(CorrQ7_norm[n-j], ARCoefQ12[n]) + 256, 9)) + 4, 3); + } + + if (lft_shft > 0) + nrg = WEBRTC_SPL_RSHIFT_W32(nrg, lft_shft); + else + nrg = WEBRTC_SPL_LSHIFT_W32(nrg, -lft_shft); + + if(nrg>131072) + gain2_Q10 = WebRtcSpl_DivResultInQ31(FRAMESAMPLES >> 2, nrg); /* also shifts 31 bits to the left! */ + else + gain2_Q10 = WEBRTC_SPL_RSHIFT_W32(FRAMESAMPLES, 2); + + /* quantize & code gain2_Q10 */ + if (WebRtcIsacfix_EncodeGain2(&gain2_Q10, streamdata)) + return -1; + + /* compute inverse AR magnitude spectrum */ + CalcRootInvArSpec(ARCoefQ12, gain2_Q10, invARSpecQ8); + + + /* arithmetic coding of spectrum */ + status = WebRtcIsacfix_EncLogisticMulti2(streamdata, dataQ7, invARSpecQ8, (WebRtc_Word16)FRAMESAMPLES); + if ( status ) + return( status ); + + return 0; +} + + +/* Matlab's LAR definition */ +static void Rc2LarFix(const WebRtc_Word16 *rcQ15, WebRtc_Word32 *larQ17, WebRtc_Word16 order) { + + /* + + This is a piece-wise implemenetation of a rc2lar-function (all values in the comment + are Q15 values and are based on [0 24956/32768 30000/32768 32500/32768], i.e. + [0.76159667968750 0.91552734375000 0.99182128906250] + + x0 x1 a k x0(again) b + ================================================================================== + 0.00 0.76: 0 2.625997508581 0 0 + 0.76 0.91: 2.000012018559 7.284502668663 0.761596679688 -3.547841027073 + 0.91 0.99: 3.121320351712 31.115835041229 0.915527343750 -25.366077452148 + 0.99 1.00: 5.495270168700 686.663805654056 0.991821289063 -675.552510708011 + + The implementation is y(x)= a + (x-x0)*k, but this can be simplified to + + y(x) = a-x0*k + x*k = b + x*k, where b = a-x0*k + + akx=[0 2.625997508581 0 + 2.000012018559 7.284502668663 0.761596679688 + 3.121320351712 31.115835041229 0.915527343750 + 5.495270168700 686.663805654056 0.991821289063]; + + b = akx(:,1) - akx(:,3).*akx(:,2) + + [ 0.0 + -3.547841027073 + -25.366077452148 + -675.552510708011] + + */ + + int k; + WebRtc_Word16 rc; + WebRtc_Word32 larAbsQ17; + + for (k = 0; k < order; k++) { + + rc = WEBRTC_SPL_ABS_W16(rcQ15[k]); //Q15 + + /* Calculate larAbsQ17 in Q17 from rc in Q15 */ + + if (rc<24956) { //0.7615966 in Q15 + // (Q15*Q13)>>11 = Q17 + larAbsQ17 = WEBRTC_SPL_MUL_16_16_RSFT(rc, 21512, 11); + } else if (rc<30000) { //0.91552734375 in Q15 + // Q17 + (Q15*Q12)>>10 = Q17 + larAbsQ17 = -465024 + WEBRTC_SPL_MUL_16_16_RSFT(rc, 29837, 10); + } else if (rc<32500) { //0.99182128906250 in Q15 + // Q17 + (Q15*Q10)>>8 = Q17 + larAbsQ17 = -3324784 + WEBRTC_SPL_MUL_16_16_RSFT(rc, 31863, 8); + } else { + // Q17 + (Q15*Q5)>>3 = Q17 + larAbsQ17 = -88546020 + WEBRTC_SPL_MUL_16_16_RSFT(rc, 21973, 3); + } + + if (rcQ15[k]>0) { + larQ17[k] = larAbsQ17; + } else { + larQ17[k] = -larAbsQ17; + } + } +} + + +static void Lar2RcFix(const WebRtc_Word32 *larQ17, WebRtc_Word16 *rcQ15, WebRtc_Word16 order) { + + /* + This is a piece-wise implemenetation of a lar2rc-function + See comment in Rc2LarFix() about details. + */ + + int k; + WebRtc_Word16 larAbsQ11; + WebRtc_Word32 rc; + + for (k = 0; k < order; k++) { + + larAbsQ11 = (WebRtc_Word16) WEBRTC_SPL_ABS_W32(WEBRTC_SPL_RSHIFT_W32(larQ17[k]+32,6)); //Q11 + + if (larAbsQ11<4097) { //2.000012018559 in Q11 + // Q11*Q16>>12 = Q15 + rc = WEBRTC_SPL_MUL_16_16_RSFT(larAbsQ11, 24957, 12); + } else if (larAbsQ11<6393) { //3.121320351712 in Q11 + // (Q11*Q17 + Q13)>>13 = Q15 + rc = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16(larAbsQ11, 17993) + 130738688), 13); + } else if (larAbsQ11<11255) { //5.495270168700 in Q11 + // (Q11*Q19 + Q30)>>15 = Q15 + rc = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16(larAbsQ11, 16850) + 875329820), 15); + } else { + // (Q11*Q24>>16 + Q19)>>4 = Q15 + rc = WEBRTC_SPL_RSHIFT_W32(((WEBRTC_SPL_MUL_16_16_RSFT(larAbsQ11, 24433, 16)) + 515804), 4); + } + + if (larQ17[k]<=0) { + rc = -rc; + } + + rcQ15[k] = (WebRtc_Word16) rc; // Q15 + } +} + +static void Poly2LarFix(WebRtc_Word16 *lowbandQ15, + WebRtc_Word16 orderLo, + WebRtc_Word16 *hibandQ15, + WebRtc_Word16 orderHi, + WebRtc_Word16 Nsub, + WebRtc_Word32 *larsQ17) { + + int k, n; + WebRtc_Word32 *outpQ17; + WebRtc_Word16 orderTot; + WebRtc_Word32 larQ17[MAX_ORDER]; // Size 7+6 is enough + + orderTot = (orderLo + orderHi); + outpQ17 = larsQ17; + for (k = 0; k < Nsub; k++) { + + Rc2LarFix(lowbandQ15, larQ17, orderLo); + + for (n = 0; n < orderLo; n++) + outpQ17[n] = larQ17[n]; //Q17 + + Rc2LarFix(hibandQ15, larQ17, orderHi); + + for (n = 0; n < orderHi; n++) + outpQ17[n + orderLo] = larQ17[n]; //Q17; + + outpQ17 += orderTot; + lowbandQ15 += orderLo; + hibandQ15 += orderHi; + } +} + + +static void Lar2polyFix(WebRtc_Word32 *larsQ17, + WebRtc_Word16 *lowbandQ15, + WebRtc_Word16 orderLo, + WebRtc_Word16 *hibandQ15, + WebRtc_Word16 orderHi, + WebRtc_Word16 Nsub) { + + int k, n; + WebRtc_Word16 orderTot; + WebRtc_Word16 *outplQ15, *outphQ15; + WebRtc_Word32 *inpQ17; + WebRtc_Word16 rcQ15[7+6]; + + orderTot = (orderLo + orderHi); + outplQ15 = lowbandQ15; + outphQ15 = hibandQ15; + inpQ17 = larsQ17; + for (k = 0; k < Nsub; k++) { + + /* gains not handled here as in the FLP version */ + + /* Low band */ + Lar2RcFix(&inpQ17[0], rcQ15, orderLo); + for (n = 0; n < orderLo; n++) + outplQ15[n] = rcQ15[n]; // Refl. coeffs + + /* High band */ + Lar2RcFix(&inpQ17[orderLo], rcQ15, orderHi); + for (n = 0; n < orderHi; n++) + outphQ15[n] = rcQ15[n]; // Refl. coeffs + + inpQ17 += orderTot; + outplQ15 += orderLo; + outphQ15 += orderHi; + } +} + +int WebRtcIsacfix_DecodeLpc(WebRtc_Word32 *gain_lo_hiQ17, + WebRtc_Word16 *LPCCoef_loQ15, + WebRtc_Word16 *LPCCoef_hiQ15, + Bitstr_dec *streamdata, + WebRtc_Word16 *outmodel) { + + WebRtc_Word32 larsQ17[KLT_ORDER_SHAPE]; // KLT_ORDER_GAIN+KLT_ORDER_SHAPE == (ORDERLO+ORDERHI)*SUBFRAMES + int err; + + err = WebRtcIsacfix_DecodeLpcCoef(streamdata, larsQ17, gain_lo_hiQ17, outmodel); + if (err<0) // error check + return -ISAC_RANGE_ERROR_DECODE_LPC; + + Lar2polyFix(larsQ17, LPCCoef_loQ15, ORDERLO, LPCCoef_hiQ15, ORDERHI, SUBFRAMES); + + return 0; +} + +/* decode & dequantize LPC Coef */ +int WebRtcIsacfix_DecodeLpcCoef(Bitstr_dec *streamdata, + WebRtc_Word32 *LPCCoefQ17, + WebRtc_Word32 *gain_lo_hiQ17, + WebRtc_Word16 *outmodel) +{ + int j, k, n; + int err; + WebRtc_Word16 pos, pos2, posg, poss, offsg, offss, offs2; + WebRtc_Word16 gainpos; + WebRtc_Word16 model; + WebRtc_Word16 index_QQ[KLT_ORDER_SHAPE]; + WebRtc_Word32 tmpcoeffs_gQ17[KLT_ORDER_GAIN]; + WebRtc_Word32 tmpcoeffs2_gQ21[KLT_ORDER_GAIN]; + WebRtc_Word16 tmpcoeffs_sQ10[KLT_ORDER_SHAPE]; + WebRtc_Word32 tmpcoeffs_sQ17[KLT_ORDER_SHAPE]; + WebRtc_Word32 tmpcoeffs2_sQ18[KLT_ORDER_SHAPE]; + WebRtc_Word32 sumQQ; + WebRtc_Word16 sumQQ16; + WebRtc_Word32 tmp32; + + + + /* entropy decoding of model number */ + err = WebRtcIsacfix_DecHistOneStepMulti(&model, streamdata, WebRtcIsacfix_kModelCdfPtr, WebRtcIsacfix_kModelInitIndex, 1); + if (err<0) // error check + return err; + + /* entropy decoding of quantization indices */ + err = WebRtcIsacfix_DecHistOneStepMulti(index_QQ, streamdata, WebRtcIsacfix_kCdfShapePtr[model], WebRtcIsacfix_kInitIndexShape[model], KLT_ORDER_SHAPE); + if (err<0) // error check + return err; + /* find quantization levels for coefficients */ + for (k=0; k<KLT_ORDER_SHAPE; k++) { + tmpcoeffs_sQ10[WebRtcIsacfix_kSelIndShape[k]] = WebRtcIsacfix_kLevelsShapeQ10[WebRtcIsacfix_kOfLevelsShape[model]+WebRtcIsacfix_kOffsetShape[model][k] + index_QQ[k]]; + } + + err = WebRtcIsacfix_DecHistOneStepMulti(index_QQ, streamdata, WebRtcIsacfix_kCdfGainPtr[model], WebRtcIsacfix_kInitIndexGain[model], KLT_ORDER_GAIN); + if (err<0) // error check + return err; + /* find quantization levels for coefficients */ + for (k=0; k<KLT_ORDER_GAIN; k++) { + tmpcoeffs_gQ17[WebRtcIsacfix_kSelIndGain[k]] = WebRtcIsacfix_kLevelsGainQ17[WebRtcIsacfix_kOfLevelsGain[model]+ WebRtcIsacfix_kOffsetGain[model][k] + index_QQ[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<2; k++) { + sumQQ = 0; + pos = offsg; + pos2 = offs2; + for (n=0; n<2; n++) { + sumQQ += (WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT1GainQ15[model][pos2], tmpcoeffs_gQ17[pos]<<5)); // (Q15*Q17)>>(16-5) = Q21 + pos++; + pos2++; + } + tmpcoeffs2_gQ21[posg] = sumQQ; //Q21 + posg++; + offs2 += 2; + } + offs2 = 0; + + for (k=0; k<LPC_SHAPE_ORDER; k++) { + sumQQ = 0; + pos = offss; + pos2 = offs2; + for (n=0; n<LPC_SHAPE_ORDER; n++) { + sumQQ += WEBRTC_SPL_MUL_16_16_RSFT(tmpcoeffs_sQ10[pos], WebRtcIsacfix_kT1ShapeQ15[model][pos2], 7); // (Q10*Q15)>>7 = Q18 + pos++; + pos2++; + } + tmpcoeffs2_sQ18[poss] = sumQQ; //Q18 + poss++; + offs2 += LPC_SHAPE_ORDER; + } + offsg += 2; + 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<2; k++) { + sumQQ = 0; + pos = k; + pos2 = j; + for (n=0; n<SUBFRAMES; n++) { + sumQQ += WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT2GainQ15[model][pos2], tmpcoeffs2_gQ21[pos]), 1); // (Q15*Q21)>>(16-1) = Q21 + pos += 2; + pos2 += SUBFRAMES; + + } + tmpcoeffs_gQ17[posg] = WEBRTC_SPL_RSHIFT_W32(sumQQ, 4); + posg++; + } + poss = offss; + for (k=0; k<LPC_SHAPE_ORDER; k++) { + sumQQ = 0; + pos = k; + pos2 = j; + for (n=0; n<SUBFRAMES; n++) { + sumQQ += (WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT2ShapeQ15[model][pos2], tmpcoeffs2_sQ18[pos])); // (Q15*Q18)>>16 = Q17 + pos += LPC_SHAPE_ORDER; + pos2 += SUBFRAMES; + } + tmpcoeffs_sQ17[poss] = sumQQ; + poss++; + } + offsg += 2; + offss += LPC_SHAPE_ORDER; + } + + /* scaling, mean addition, and gain restoration */ + gainpos = 0; + posg = 0;poss = 0;pos=0; + for (k=0; k<SUBFRAMES; k++) { + + /* log gains */ + sumQQ16 = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmpcoeffs_gQ17[posg], 2+9); //Divide by 4 and get Q17 to Q8, i.e. shift 2+9 + sumQQ16 += WebRtcIsacfix_kMeansGainQ8[model][posg]; + sumQQ = CalcExpN(sumQQ16); // Q8 in and Q17 out + gain_lo_hiQ17[gainpos] = sumQQ; //Q17 + gainpos++; + posg++; + + sumQQ16 = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmpcoeffs_gQ17[posg], 2+9); //Divide by 4 and get Q17 to Q8, i.e. shift 2+9 + sumQQ16 += WebRtcIsacfix_kMeansGainQ8[model][posg]; + sumQQ = CalcExpN(sumQQ16); // Q8 in and Q17 out + gain_lo_hiQ17[gainpos] = sumQQ; //Q17 + gainpos++; + posg++; + + /* lo band LAR coeffs */ + for (n=0; n<ORDERLO; n++, pos++, poss++) { + tmp32 = WEBRTC_SPL_MUL_16_32_RSFT16(31208, tmpcoeffs_sQ17[poss]); // (Q16*Q17)>>16 = Q17, with 1/2.1 = 0.47619047619 ~= 31208 in Q16 + tmp32 = tmp32 + WebRtcIsacfix_kMeansShapeQ17[model][poss]; // Q17+Q17 = Q17 + LPCCoefQ17[pos] = tmp32; + } + + /* hi band LAR coeffs */ + for (n=0; n<ORDERHI; n++, pos++, poss++) { + tmp32 = WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(18204, tmpcoeffs_sQ17[poss]), 3); // ((Q13*Q17)>>16)<<3 = Q17, with 1/0.45 = 2.222222222222 ~= 18204 in Q13 + tmp32 = tmp32 + WebRtcIsacfix_kMeansShapeQ17[model][poss]; // Q17+Q17 = Q17 + LPCCoefQ17[pos] = tmp32; + } + } + + + *outmodel=model; + + return 0; +} + +/* estimate codel length of LPC Coef */ +static int EstCodeLpcCoef(WebRtc_Word32 *LPCCoefQ17, + WebRtc_Word32 *gain_lo_hiQ17, + WebRtc_Word16 *model, + WebRtc_Word32 *sizeQ11, + Bitstr_enc *streamdata, + ISAC_SaveEncData_t* encData, + transcode_obj *transcodingParam) { + int j, k, n; + WebRtc_Word16 posQQ, pos2QQ, gainpos; + WebRtc_Word16 pos, pos2, poss, posg, offsg, offss, offs2; + WebRtc_Word16 index_gQQ[KLT_ORDER_GAIN], index_sQQ[KLT_ORDER_SHAPE]; + WebRtc_Word16 index_ovr_gQQ[KLT_ORDER_GAIN], index_ovr_sQQ[KLT_ORDER_SHAPE]; + WebRtc_Word32 BitsQQ; + + WebRtc_Word16 tmpcoeffs_gQ6[KLT_ORDER_GAIN]; + WebRtc_Word32 tmpcoeffs_gQ17[KLT_ORDER_GAIN]; + WebRtc_Word32 tmpcoeffs_sQ17[KLT_ORDER_SHAPE]; + WebRtc_Word32 tmpcoeffs2_gQ21[KLT_ORDER_GAIN]; + WebRtc_Word32 tmpcoeffs2_sQ17[KLT_ORDER_SHAPE]; + WebRtc_Word32 sumQQ; + WebRtc_Word32 tmp32; + WebRtc_Word16 sumQQ16; + int status = 0; + + /* write LAR coefficients to statistics file */ + /* Save data for creation of multiple bitstreams (and transcoding) */ + if (encData != NULL) { + for (k=0; k<KLT_ORDER_GAIN; k++) { + encData->LPCcoeffs_g[KLT_ORDER_GAIN*encData->startIdx + k] = gain_lo_hiQ17[k]; + } + } + + /* log gains, mean removal and scaling */ + posg = 0;poss = 0;pos=0; gainpos=0; + + for (k=0; k<SUBFRAMES; k++) { + /* log gains */ + + /* The input argument X to logN(X) is 2^17 times higher than the + input floating point argument Y to log(Y), since the X value + is a Q17 value. This can be compensated for after the call, by + subraction a value Z for each Q-step. One Q-step means that + X gets 2 times higher, i.e. Z = logN(2)*256 = 0.693147180559*256 = + 177.445678 should be subtracted (since logN() returns a Q8 value). + For a X value in Q17, the value 177.445678*17 = 3017 should be + subtracted */ + tmpcoeffs_gQ6[posg] = CalcLogN(gain_lo_hiQ17[gainpos])-3017; //Q8 + tmpcoeffs_gQ6[posg] -= WebRtcIsacfix_kMeansGainQ8[0][posg]; //Q8, but Q6 after not-needed mult. by 4 + posg++; gainpos++; + + tmpcoeffs_gQ6[posg] = CalcLogN(gain_lo_hiQ17[gainpos])-3017; //Q8 + tmpcoeffs_gQ6[posg] -= WebRtcIsacfix_kMeansGainQ8[0][posg]; //Q8, but Q6 after not-needed mult. by 4 + posg++; gainpos++; + + /* lo band LAR coeffs */ + for (n=0; n<ORDERLO; n++, poss++, pos++) { + tmp32 = LPCCoefQ17[pos] - WebRtcIsacfix_kMeansShapeQ17[0][poss]; //Q17 + tmp32 = WEBRTC_SPL_MUL_16_32_RSFT16(17203, tmp32<<3); // tmp32 = 2.1*tmp32 + tmpcoeffs_sQ17[poss] = tmp32; //Q17 + } + + /* hi band LAR coeffs */ + for (n=0; n<ORDERHI; n++, poss++, pos++) { + tmp32 = LPCCoefQ17[pos] - WebRtcIsacfix_kMeansShapeQ17[0][poss]; //Q17 + tmp32 = WEBRTC_SPL_MUL_16_32_RSFT16(14746, tmp32<<1); // tmp32 = 0.45*tmp32 + tmpcoeffs_sQ17[poss] = tmp32; //Q17 + } + + } + + + /* KLT */ + + /* left transform */ + offsg = 0; + offss = 0; + for (j=0; j<SUBFRAMES; j++) { + posg = offsg; + for (k=0; k<2; k++) { + sumQQ = 0; + pos = offsg; + pos2 = k; + for (n=0; n<2; n++) { + sumQQ += WEBRTC_SPL_MUL_16_16(tmpcoeffs_gQ6[pos], WebRtcIsacfix_kT1GainQ15[0][pos2]); //Q21 = Q6*Q15 + pos++; + pos2 += 2; + } + tmpcoeffs2_gQ21[posg] = sumQQ; + posg++; + } + poss = offss; + for (k=0; k<LPC_SHAPE_ORDER; k++) { + sumQQ = 0; + pos = offss; + pos2 = k; + for (n=0; n<LPC_SHAPE_ORDER; n++) { + sumQQ += (WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT1ShapeQ15[0][pos2], tmpcoeffs_sQ17[pos]<<1)); // (Q15*Q17)>>(16-1) = Q17 + pos++; + pos2 += LPC_SHAPE_ORDER; + } + tmpcoeffs2_sQ17[poss] = sumQQ; //Q17 + poss++; + } + offsg += 2; + offss += LPC_SHAPE_ORDER; + } + + /* right transform */ + offsg = 0; + offss = 0; + offs2 = 0; + for (j=0; j<SUBFRAMES; j++) { + posg = offsg; + for (k=0; k<2; k++) { + sumQQ = 0; + pos = k; + pos2 = offs2; + for (n=0; n<SUBFRAMES; n++) { + sumQQ += WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT2GainQ15[0][pos2], tmpcoeffs2_gQ21[pos]), 1); // (Q15*Q21)>>(16-1) = Q21 + pos += 2; + pos2++; + } + tmpcoeffs_gQ17[posg] = WEBRTC_SPL_RSHIFT_W32(sumQQ, 4); + posg++; + } + poss = offss; + for (k=0; k<LPC_SHAPE_ORDER; k++) { + sumQQ = 0; + pos = k; + pos2 = offs2; + for (n=0; n<SUBFRAMES; n++) { + sumQQ += (WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT2ShapeQ15[0][pos2], tmpcoeffs2_sQ17[pos]<<1)); // (Q15*Q17)>>(16-1) = Q17 + pos += LPC_SHAPE_ORDER; + pos2++; + } + tmpcoeffs_sQ17[poss] = sumQQ; + poss++; + } + offs2 += SUBFRAMES; + offsg += 2; + offss += LPC_SHAPE_ORDER; + } + + /* quantize coefficients */ + + BitsQQ = 0; + for (k=0; k<KLT_ORDER_GAIN; k++) //ATTN: ok? + { + posQQ = WebRtcIsacfix_kSelIndGain[k]; + pos2QQ= (WebRtc_Word16)CalcLrIntQ(tmpcoeffs_gQ17[posQQ], 17); + + index_gQQ[k] = pos2QQ + WebRtcIsacfix_kQuantMinGain[k]; //ATTN: ok? + if (index_gQQ[k] < 0) { + index_gQQ[k] = 0; + } + else if (index_gQQ[k] > WebRtcIsacfix_kMaxIndGain[k]) { + index_gQQ[k] = WebRtcIsacfix_kMaxIndGain[k]; + } + index_ovr_gQQ[k] = WebRtcIsacfix_kOffsetGain[0][k]+index_gQQ[k]; + posQQ = WebRtcIsacfix_kOfLevelsGain[0] + index_ovr_gQQ[k]; + + /* Save data for creation of multiple bitstreams */ + if (encData != NULL) { + encData->LPCindex_g[KLT_ORDER_GAIN*encData->startIdx + k] = index_gQQ[k]; + } + + /* determine number of bits */ + sumQQ = WebRtcIsacfix_kCodeLenGainQ11[posQQ]; //Q11 + BitsQQ += sumQQ; + } + + for (k=0; k<KLT_ORDER_SHAPE; k++) //ATTN: ok? + { + index_sQQ[k] = (WebRtc_Word16)(CalcLrIntQ(tmpcoeffs_sQ17[WebRtcIsacfix_kSelIndShape[k]], 17) + WebRtcIsacfix_kQuantMinShape[k]); //ATTN: ok? + + if (index_sQQ[k] < 0) + index_sQQ[k] = 0; + else if (index_sQQ[k] > WebRtcIsacfix_kMaxIndShape[k]) + index_sQQ[k] = WebRtcIsacfix_kMaxIndShape[k]; + index_ovr_sQQ[k] = WebRtcIsacfix_kOffsetShape[0][k]+index_sQQ[k]; + + posQQ = WebRtcIsacfix_kOfLevelsShape[0] + index_ovr_sQQ[k]; + sumQQ = WebRtcIsacfix_kCodeLenShapeQ11[posQQ]; //Q11 + BitsQQ += sumQQ; + } + + + + *model = 0; + *sizeQ11=BitsQQ; + + /* entropy coding of model number */ + status = WebRtcIsacfix_EncHistMulti(streamdata, model, WebRtcIsacfix_kModelCdfPtr, 1); + if (status < 0) { + return status; + } + + /* entropy coding of quantization indices - shape only */ + status = WebRtcIsacfix_EncHistMulti(streamdata, index_sQQ, WebRtcIsacfix_kCdfShapePtr[0], KLT_ORDER_SHAPE); + if (status < 0) { + return status; + } + + /* Save data for creation of multiple bitstreams */ + if (encData != NULL) { + for (k=0; k<KLT_ORDER_SHAPE; k++) + { + encData->LPCindex_s[KLT_ORDER_SHAPE*encData->startIdx + k] = index_sQQ[k]; + } + } + /* save the state of the bitstream object 'streamdata' for the possible bit-rate reduction */ + transcodingParam->full = streamdata->full; + transcodingParam->stream_index = streamdata->stream_index; + transcodingParam->streamval = streamdata->streamval; + transcodingParam->W_upper = streamdata->W_upper; + transcodingParam->beforeLastWord = streamdata->stream[streamdata->stream_index-1]; + transcodingParam->lastWord = streamdata->stream[streamdata->stream_index]; + + /* entropy coding of index */ + status = WebRtcIsacfix_EncHistMulti(streamdata, index_gQQ, WebRtcIsacfix_kCdfGainPtr[0], KLT_ORDER_GAIN); + if (status < 0) { + return status; + } + + /* find quantization levels for shape coefficients */ + for (k=0; k<KLT_ORDER_SHAPE; k++) { + tmpcoeffs_sQ17[WebRtcIsacfix_kSelIndShape[k]] = WEBRTC_SPL_MUL(128, WebRtcIsacfix_kLevelsShapeQ10[WebRtcIsacfix_kOfLevelsShape[0]+index_ovr_sQQ[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++) { + sumQQ = 0; + pos = offss; + pos2 = offs2; + for (n=0; n<LPC_SHAPE_ORDER; n++) { + sumQQ += (WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT1ShapeQ15[0][pos2], tmpcoeffs_sQ17[pos]<<1)); // (Q15*Q17)>>(16-1) = Q17 + pos++; + pos2++; + } + tmpcoeffs2_sQ17[poss] = sumQQ; + + poss++; + 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++) { + sumQQ = 0; + pos = k; + pos2 = j; + for (n=0; n<SUBFRAMES; n++) { + sumQQ += (WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT2ShapeQ15[0][pos2], tmpcoeffs2_sQ17[pos]<<1)); // (Q15*Q17)>>(16-1) = Q17 + pos += LPC_SHAPE_ORDER; + pos2 += SUBFRAMES; + } + tmpcoeffs_sQ17[poss] = sumQQ; + poss++; + } + offss += LPC_SHAPE_ORDER; + } + + /* scaling, mean addition, and gain restoration */ + poss = 0;pos=0; + for (k=0; k<SUBFRAMES; k++) { + + /* lo band LAR coeffs */ + for (n=0; n<ORDERLO; n++, pos++, poss++) { + tmp32 = WEBRTC_SPL_MUL_16_32_RSFT16(31208, tmpcoeffs_sQ17[poss]); // (Q16*Q17)>>16 = Q17, with 1/2.1 = 0.47619047619 ~= 31208 in Q16 + tmp32 = tmp32 + WebRtcIsacfix_kMeansShapeQ17[0][poss]; // Q17+Q17 = Q17 + LPCCoefQ17[pos] = tmp32; + } + + /* hi band LAR coeffs */ + for (n=0; n<ORDERHI; n++, pos++, poss++) { + tmp32 = WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(18204, tmpcoeffs_sQ17[poss]), 3); // ((Q13*Q17)>>16)<<3 = Q17, with 1/0.45 = 2.222222222222 ~= 18204 in Q13 + tmp32 = tmp32 + WebRtcIsacfix_kMeansShapeQ17[0][poss]; // Q17+Q17 = Q17 + LPCCoefQ17[pos] = tmp32; + } + + } + + //to update tmpcoeffs_gQ17 to the proper state + for (k=0; k<KLT_ORDER_GAIN; k++) { + tmpcoeffs_gQ17[WebRtcIsacfix_kSelIndGain[k]] = WebRtcIsacfix_kLevelsGainQ17[WebRtcIsacfix_kOfLevelsGain[0]+index_ovr_gQQ[k]]; + } + + + + /* find quantization levels for coefficients */ + + /* left transform */ + offsg = 0; + posg = 0; + for (j=0; j<SUBFRAMES; j++) { + offs2 = 0; + for (k=0; k<2; k++) { + sumQQ = 0; + pos = offsg; + pos2 = offs2; + for (n=0; n<2; n++) { + sumQQ += (WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT1GainQ15[0][pos2], tmpcoeffs_gQ17[pos])<<1); // (Q15*Q17)>>(16-1) = Q17 + pos++; + pos2++; + } + tmpcoeffs2_gQ21[posg] = WEBRTC_SPL_LSHIFT_W32(sumQQ, 4); //Q17<<4 = Q21 + posg++; + offs2 += 2; + } + offsg += 2; + } + + /* right transform */ // Transpose matrix + offsg = 0; + posg = 0; + for (j=0; j<SUBFRAMES; j++) { + posg = offsg; + for (k=0; k<2; k++) { + sumQQ = 0; + pos = k; + pos2 = j; + for (n=0; n<SUBFRAMES; n++) { + sumQQ += WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT2GainQ15[0][pos2], tmpcoeffs2_gQ21[pos]), 1); // (Q15*Q21)>>(16-1) = Q21 + pos += 2; + pos2 += SUBFRAMES; + } + tmpcoeffs_gQ17[posg] = WEBRTC_SPL_RSHIFT_W32(sumQQ, 4); + posg++; + } + offsg += 2; + } + + /* scaling, mean addition, and gain restoration */ + posg = 0; + gainpos = 0; + for (k=0; k<2*SUBFRAMES; k++) { + + sumQQ16 = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmpcoeffs_gQ17[posg], 2+9); //Divide by 4 and get Q17 to Q8, i.e. shift 2+9 + sumQQ16 += WebRtcIsacfix_kMeansGainQ8[0][posg]; + sumQQ = CalcExpN(sumQQ16); // Q8 in and Q17 out + gain_lo_hiQ17[gainpos] = sumQQ; //Q17 + + gainpos++; + pos++;posg++; + } + + return 0; +} + +int WebRtcIsacfix_EstCodeLpcGain(WebRtc_Word32 *gain_lo_hiQ17, + Bitstr_enc *streamdata, + ISAC_SaveEncData_t* encData) { + int j, k, n; + WebRtc_Word16 posQQ, pos2QQ, gainpos; + WebRtc_Word16 pos, pos2, posg, offsg, offs2; + WebRtc_Word16 index_gQQ[KLT_ORDER_GAIN]; + + WebRtc_Word16 tmpcoeffs_gQ6[KLT_ORDER_GAIN]; + WebRtc_Word32 tmpcoeffs_gQ17[KLT_ORDER_GAIN]; + WebRtc_Word32 tmpcoeffs2_gQ21[KLT_ORDER_GAIN]; + WebRtc_Word32 sumQQ; + int status = 0; + + /* write LAR coefficients to statistics file */ + /* Save data for creation of multiple bitstreams (and transcoding) */ + if (encData != NULL) { + for (k=0; k<KLT_ORDER_GAIN; k++) { + encData->LPCcoeffs_g[KLT_ORDER_GAIN*encData->startIdx + k] = gain_lo_hiQ17[k]; + } + } + + /* log gains, mean removal and scaling */ + posg = 0; pos = 0; gainpos = 0; + + for (k=0; k<SUBFRAMES; k++) { + /* log gains */ + + /* The input argument X to logN(X) is 2^17 times higher than the + input floating point argument Y to log(Y), since the X value + is a Q17 value. This can be compensated for after the call, by + subraction a value Z for each Q-step. One Q-step means that + X gets 2 times higher, i.e. Z = logN(2)*256 = 0.693147180559*256 = + 177.445678 should be subtracted (since logN() returns a Q8 value). + For a X value in Q17, the value 177.445678*17 = 3017 should be + subtracted */ + tmpcoeffs_gQ6[posg] = CalcLogN(gain_lo_hiQ17[gainpos])-3017; //Q8 + tmpcoeffs_gQ6[posg] -= WebRtcIsacfix_kMeansGainQ8[0][posg]; //Q8, but Q6 after not-needed mult. by 4 + posg++; gainpos++; + + tmpcoeffs_gQ6[posg] = CalcLogN(gain_lo_hiQ17[gainpos])-3017; //Q8 + tmpcoeffs_gQ6[posg] -= WebRtcIsacfix_kMeansGainQ8[0][posg]; //Q8, but Q6 after not-needed mult. by 4 + posg++; gainpos++; + } + + + /* KLT */ + + /* left transform */ + offsg = 0; + for (j=0; j<SUBFRAMES; j++) { + posg = offsg; + for (k=0; k<2; k++) { + sumQQ = 0; + pos = offsg; + pos2 = k; + for (n=0; n<2; n++) { + sumQQ += WEBRTC_SPL_MUL_16_16(tmpcoeffs_gQ6[pos], WebRtcIsacfix_kT1GainQ15[0][pos2]); //Q21 = Q6*Q15 + pos++; + pos2 += 2; + } + tmpcoeffs2_gQ21[posg] = sumQQ; + posg++; + } + offsg += 2; + } + + /* right transform */ + offsg = 0; + offs2 = 0; + for (j=0; j<SUBFRAMES; j++) { + posg = offsg; + for (k=0; k<2; k++) { + sumQQ = 0; + pos = k; + pos2 = offs2; + for (n=0; n<SUBFRAMES; n++) { + sumQQ += WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT2GainQ15[0][pos2], tmpcoeffs2_gQ21[pos]), 1); // (Q15*Q21)>>(16-1) = Q21 + pos += 2; + pos2++; + } + tmpcoeffs_gQ17[posg] = WEBRTC_SPL_RSHIFT_W32(sumQQ, 4); + posg++; + } + offsg += 2; + offs2 += SUBFRAMES; + } + + /* quantize coefficients */ + + for (k=0; k<KLT_ORDER_GAIN; k++) //ATTN: ok? + { + posQQ = WebRtcIsacfix_kSelIndGain[k]; + pos2QQ= (WebRtc_Word16)CalcLrIntQ(tmpcoeffs_gQ17[posQQ], 17); + + index_gQQ[k] = pos2QQ + WebRtcIsacfix_kQuantMinGain[k]; //ATTN: ok? + if (index_gQQ[k] < 0) { + index_gQQ[k] = 0; + } + else if (index_gQQ[k] > WebRtcIsacfix_kMaxIndGain[k]) { + index_gQQ[k] = WebRtcIsacfix_kMaxIndGain[k]; + } + + /* Save data for creation of multiple bitstreams */ + if (encData != NULL) { + encData->LPCindex_g[KLT_ORDER_GAIN*encData->startIdx + k] = index_gQQ[k]; + } + } + + /* entropy coding of index */ + status = WebRtcIsacfix_EncHistMulti(streamdata, index_gQQ, WebRtcIsacfix_kCdfGainPtr[0], KLT_ORDER_GAIN); + if (status < 0) { + return status; + } + + return 0; +} + + +int WebRtcIsacfix_EncodeLpc(WebRtc_Word32 *gain_lo_hiQ17, + WebRtc_Word16 *LPCCoef_loQ15, + WebRtc_Word16 *LPCCoef_hiQ15, + WebRtc_Word16 *model, + WebRtc_Word32 *sizeQ11, + Bitstr_enc *streamdata, + ISAC_SaveEncData_t* encData, + transcode_obj *transcodeParam) +{ + int status = 0; + WebRtc_Word32 larsQ17[KLT_ORDER_SHAPE]; // KLT_ORDER_SHAPE == (ORDERLO+ORDERHI)*SUBFRAMES + // = (6+12)*6 == 108 + + Poly2LarFix(LPCCoef_loQ15, ORDERLO, LPCCoef_hiQ15, ORDERHI, SUBFRAMES, larsQ17); + + status = EstCodeLpcCoef(larsQ17, gain_lo_hiQ17, model, sizeQ11, streamdata, encData, transcodeParam); + if (status < 0) { + return (status); + } + + Lar2polyFix(larsQ17, LPCCoef_loQ15, ORDERLO, LPCCoef_hiQ15, ORDERHI, SUBFRAMES); + + return 0; +} + + +/* decode & dequantize RC */ +int WebRtcIsacfix_DecodeRcCoef(Bitstr_dec *streamdata, WebRtc_Word16 *RCQ15) +{ + int k, err; + WebRtc_Word16 index[AR_ORDER]; + + /* entropy decoding of quantization indices */ + err = WebRtcIsacfix_DecHistOneStepMulti(index, streamdata, WebRtcIsacfix_kRcCdfPtr, WebRtcIsacfix_kRcInitInd, AR_ORDER); + if (err<0) // error check + return err; + + /* find quantization levels for reflection coefficients */ + for (k=0; k<AR_ORDER; k++) + { + RCQ15[k] = *(WebRtcIsacfix_kRcLevPtr[k] + index[k]); + } + + return 0; +} + + + +/* quantize & code RC */ +int WebRtcIsacfix_EncodeRcCoef(WebRtc_Word16 *RCQ15, Bitstr_enc *streamdata) +{ + int k; + WebRtc_Word16 index[AR_ORDER]; + int status; + + /* quantize reflection coefficients (add noise feedback?) */ + for (k=0; k<AR_ORDER; k++) + { + index[k] = WebRtcIsacfix_kRcInitInd[k]; + + if (RCQ15[k] > WebRtcIsacfix_kRcBound[index[k]]) + { + while (RCQ15[k] > WebRtcIsacfix_kRcBound[index[k] + 1]) + index[k]++; + } + else + { + while (RCQ15[k] < WebRtcIsacfix_kRcBound[--index[k]]) ; + } + + RCQ15[k] = *(WebRtcIsacfix_kRcLevPtr[k] + index[k]); + } + + + /* entropy coding of quantization indices */ + status = WebRtcIsacfix_EncHistMulti(streamdata, index, WebRtcIsacfix_kRcCdfPtr, AR_ORDER); + + /* If error in WebRtcIsacfix_EncHistMulti(), status will be negative, otherwise 0 */ + return status; +} + + +/* decode & dequantize squared Gain */ +int WebRtcIsacfix_DecodeGain2(Bitstr_dec *streamdata, WebRtc_Word32 *gainQ10) +{ + int err; + WebRtc_Word16 index; + + /* entropy decoding of quantization index */ + err = WebRtcIsacfix_DecHistOneStepMulti( + &index, + streamdata, + WebRtcIsacfix_kGainPtr, + WebRtcIsacfix_kGainInitInd, + 1); + /* error check */ + if (err<0) { + return err; + } + + /* find quantization level */ + *gainQ10 = WebRtcIsacfix_kGain2Lev[index]; + + return 0; +} + + + +/* quantize & code squared Gain */ +int WebRtcIsacfix_EncodeGain2(WebRtc_Word32 *gainQ10, Bitstr_enc *streamdata) +{ + WebRtc_Word16 index; + int status = 0; + + /* find quantization index */ + index = WebRtcIsacfix_kGainInitInd[0]; + if (*gainQ10 > WebRtcIsacfix_kGain2Bound[index]) + { + while (*gainQ10 > WebRtcIsacfix_kGain2Bound[index + 1]) + index++; + } + else + { + while (*gainQ10 < WebRtcIsacfix_kGain2Bound[--index]) ; + } + + /* dequantize */ + *gainQ10 = WebRtcIsacfix_kGain2Lev[index]; + + /* entropy coding of quantization index */ + status = WebRtcIsacfix_EncHistMulti(streamdata, &index, WebRtcIsacfix_kGainPtr, 1); + + /* If error in WebRtcIsacfix_EncHistMulti(), status will be negative, otherwise 0 */ + return status; +} + + +/* code and decode Pitch Gains and Lags functions */ + +/* decode & dequantize Pitch Gains */ +int WebRtcIsacfix_DecodePitchGain(Bitstr_dec *streamdata, WebRtc_Word16 *PitchGains_Q12) +{ + int err; + WebRtc_Word16 index_comb; + const WebRtc_UWord16 *pitch_gain_cdf_ptr[1]; + + /* entropy decoding of quantization indices */ + *pitch_gain_cdf_ptr = WebRtcIsacfix_kPitchGainCdf; + err = WebRtcIsacfix_DecHistBisectMulti(&index_comb, streamdata, pitch_gain_cdf_ptr, WebRtcIsacfix_kCdfTableSizeGain, 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; + + /* unquantize back to pitch gains by table look-up */ + PitchGains_Q12[0] = WebRtcIsacfix_kPitchGain1[index_comb]; + PitchGains_Q12[1] = WebRtcIsacfix_kPitchGain2[index_comb]; + PitchGains_Q12[2] = WebRtcIsacfix_kPitchGain3[index_comb]; + PitchGains_Q12[3] = WebRtcIsacfix_kPitchGain4[index_comb]; + + return 0; +} + + +/* quantize & code Pitch Gains */ +int WebRtcIsacfix_EncodePitchGain(WebRtc_Word16 *PitchGains_Q12, Bitstr_enc *streamdata, ISAC_SaveEncData_t* encData) +{ + int k,j; + WebRtc_Word16 SQ15[PITCH_SUBFRAMES]; + WebRtc_Word16 index[3]; + WebRtc_Word16 index_comb; + const WebRtc_UWord16 *pitch_gain_cdf_ptr[1]; + WebRtc_Word32 CQ17; + int status = 0; + + + /* get the approximate arcsine (almost linear)*/ + for (k=0; k<PITCH_SUBFRAMES; k++) + SQ15[k] = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16_RSFT(PitchGains_Q12[k],33,2); //Q15 + + + /* find quantization index; only for the first three transform coefficients */ + for (k=0; k<3; k++) + { + /* transform */ + CQ17=0; + for (j=0; j<PITCH_SUBFRAMES; j++) { + CQ17 += WEBRTC_SPL_MUL_16_16_RSFT(WebRtcIsacfix_kTransform[k][j], SQ15[j],10); // Q17 + } + + index[k] = (WebRtc_Word16)((CQ17 + 8192)>>14); // Rounding and scaling with stepsize (=1/0.125=8) + + /* check that the index is not outside the boundaries of the table */ + if (index[k] < WebRtcIsacfix_kLowerlimiGain[k]) index[k] = WebRtcIsacfix_kLowerlimiGain[k]; + else if (index[k] > WebRtcIsacfix_kUpperlimitGain[k]) index[k] = WebRtcIsacfix_kUpperlimitGain[k]; + index[k] -= WebRtcIsacfix_kLowerlimiGain[k]; + } + + /* calculate unique overall index */ + index_comb = (WebRtc_Word16)(WEBRTC_SPL_MUL(WebRtcIsacfix_kMultsGain[0], index[0]) + + WEBRTC_SPL_MUL(WebRtcIsacfix_kMultsGain[1], index[1]) + index[2]); + + /* unquantize back to pitch gains by table look-up */ + // (Y) + PitchGains_Q12[0] = WebRtcIsacfix_kPitchGain1[index_comb]; + PitchGains_Q12[1] = WebRtcIsacfix_kPitchGain2[index_comb]; + PitchGains_Q12[2] = WebRtcIsacfix_kPitchGain3[index_comb]; + PitchGains_Q12[3] = WebRtcIsacfix_kPitchGain4[index_comb]; + + + /* entropy coding of quantization pitch gains */ + *pitch_gain_cdf_ptr = WebRtcIsacfix_kPitchGainCdf; + status = WebRtcIsacfix_EncHistMulti(streamdata, &index_comb, pitch_gain_cdf_ptr, 1); + if (status < 0) { + return status; + } + + /* Save data for creation of multiple bitstreams */ + if (encData != NULL) { + encData->pitchGain_index[encData->startIdx] = index_comb; + } + + return 0; +} + + + +/* Pitch LAG */ + + +/* decode & dequantize Pitch Lags */ +int WebRtcIsacfix_DecodePitchLag(Bitstr_dec *streamdata, + WebRtc_Word16 *PitchGain_Q12, + WebRtc_Word16 *PitchLags_Q7) +{ + int k, err; + WebRtc_Word16 index[PITCH_SUBFRAMES]; + const WebRtc_Word16 *mean_val2Q10, *mean_val4Q10; + + const WebRtc_Word16 *lower_limit; + const WebRtc_UWord16 *init_index; + const WebRtc_UWord16 *cdf_size; + const WebRtc_UWord16 **cdf; + + WebRtc_Word32 meangainQ12; + WebRtc_Word32 CQ11, CQ10,tmp32a,tmp32b; + WebRtc_Word16 shft,tmp16a,tmp16c; + + meangainQ12=0; + for (k = 0; k < 4; k++) + meangainQ12 += PitchGain_Q12[k]; + + meangainQ12 = WEBRTC_SPL_RSHIFT_W32(meangainQ12, 2); // Get average + + /* voicing classificiation */ + if (meangainQ12 <= 819) { // mean_gain < 0.2 + shft = -1; // StepSize=2.0; + cdf = WebRtcIsacfix_kPitchLagPtrLo; + cdf_size = WebRtcIsacfix_kPitchLagSizeLo; + mean_val2Q10 = WebRtcIsacfix_kMeanLag2Lo; + mean_val4Q10 = WebRtcIsacfix_kMeanLag4Lo; + lower_limit = WebRtcIsacfix_kLowerLimitLo; + init_index = WebRtcIsacfix_kInitIndLo; + } else if (meangainQ12 <= 1638) { // mean_gain < 0.4 + shft = 0; // StepSize=1.0; + cdf = WebRtcIsacfix_kPitchLagPtrMid; + cdf_size = WebRtcIsacfix_kPitchLagSizeMid; + mean_val2Q10 = WebRtcIsacfix_kMeanLag2Mid; + mean_val4Q10 = WebRtcIsacfix_kMeanLag4Mid; + lower_limit = WebRtcIsacfix_kLowerLimitMid; + init_index = WebRtcIsacfix_kInitIndMid; + } else { + shft = 1; // StepSize=0.5; + cdf = WebRtcIsacfix_kPitchLagPtrHi; + cdf_size = WebRtcIsacfix_kPitchLagSizeHi; + mean_val2Q10 = WebRtcIsacfix_kMeanLag2Hi; + mean_val4Q10 = WebRtcIsacfix_kMeanLag4Hi; + lower_limit = WebRtcIsacfix_kLowerLimitHi; + init_index = WebRtcIsacfix_kInitIndHi; + } + + /* entropy decoding of quantization indices */ + err = WebRtcIsacfix_DecHistBisectMulti(index, streamdata, cdf, cdf_size, 1); + if ((err<0) || (index[0]<0)) // error check + return -ISAC_RANGE_ERROR_DECODE_PITCH_LAG; + + err = WebRtcIsacfix_DecHistOneStepMulti(index+1, streamdata, cdf+1, init_index, 3); + if (err<0) // error check + return -ISAC_RANGE_ERROR_DECODE_PITCH_LAG; + + + /* unquantize back to transform coefficients and do the inverse transform: S = T'*C */ + CQ11 = ((WebRtc_Word32)index[0] + lower_limit[0]); // Q0 + CQ11 = WEBRTC_SPL_SHIFT_W32(CQ11,11-shft); // Scale with StepSize, Q11 + for (k=0; k<PITCH_SUBFRAMES; k++) { + tmp32a = WEBRTC_SPL_MUL_16_32_RSFT11(WebRtcIsacfix_kTransform[0][k], CQ11); + tmp16a = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp32a, 5); + PitchLags_Q7[k] = tmp16a; + } + + CQ10 = mean_val2Q10[index[1]]; + for (k=0; k<PITCH_SUBFRAMES; k++) { + tmp32b = (WebRtc_Word32) WEBRTC_SPL_MUL_16_16_RSFT((WebRtc_Word16) WebRtcIsacfix_kTransform[1][k], (WebRtc_Word16) CQ10,10); + tmp16c = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp32b, 5); + PitchLags_Q7[k] += tmp16c; + } + + CQ10 = mean_val4Q10[index[3]]; + for (k=0; k<PITCH_SUBFRAMES; k++) { + tmp32b = (WebRtc_Word32) WEBRTC_SPL_MUL_16_16_RSFT((WebRtc_Word16) WebRtcIsacfix_kTransform[3][k], (WebRtc_Word16) CQ10,10); + tmp16c = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp32b, 5); + PitchLags_Q7[k] += tmp16c; + } + + return 0; +} + + + +/* quantize & code Pitch Lags */ +int WebRtcIsacfix_EncodePitchLag(WebRtc_Word16 *PitchLagsQ7,WebRtc_Word16 *PitchGain_Q12, + Bitstr_enc *streamdata, ISAC_SaveEncData_t* encData) +{ + int k, j; + WebRtc_Word16 index[PITCH_SUBFRAMES]; + WebRtc_Word32 meangainQ12, CQ17; + WebRtc_Word32 CQ11, CQ10,tmp32a; + + const WebRtc_Word16 *mean_val2Q10,*mean_val4Q10; + const WebRtc_Word16 *lower_limit, *upper_limit; + const WebRtc_UWord16 **cdf; + WebRtc_Word16 shft, tmp16a, tmp16b, tmp16c; + WebRtc_Word32 tmp32b; + int status = 0; + + /* compute mean pitch gain */ + meangainQ12=0; + for (k = 0; k < 4; k++) + meangainQ12 += PitchGain_Q12[k]; + + meangainQ12 = WEBRTC_SPL_RSHIFT_W32(meangainQ12, 2); + + /* Save data for creation of multiple bitstreams */ + if (encData != NULL) { + encData->meanGain[encData->startIdx] = meangainQ12; + } + + /* voicing classificiation */ + if (meangainQ12 <= 819) { // mean_gain < 0.2 + shft = -1; // StepSize=2.0; + cdf = WebRtcIsacfix_kPitchLagPtrLo; + mean_val2Q10 = WebRtcIsacfix_kMeanLag2Lo; + mean_val4Q10 = WebRtcIsacfix_kMeanLag4Lo; + lower_limit = WebRtcIsacfix_kLowerLimitLo; + upper_limit = WebRtcIsacfix_kUpperLimitLo; + } else if (meangainQ12 <= 1638) { // mean_gain < 0.4 + shft = 0; // StepSize=1.0; + cdf = WebRtcIsacfix_kPitchLagPtrMid; + mean_val2Q10 = WebRtcIsacfix_kMeanLag2Mid; + mean_val4Q10 = WebRtcIsacfix_kMeanLag4Mid; + lower_limit = WebRtcIsacfix_kLowerLimitMid; + upper_limit = WebRtcIsacfix_kUpperLimitMid; + } else { + shft = 1; // StepSize=0.5; + cdf = WebRtcIsacfix_kPitchLagPtrHi; + mean_val2Q10 = WebRtcIsacfix_kMeanLag2Hi; + mean_val4Q10 = WebRtcIsacfix_kMeanLag4Hi; + lower_limit = WebRtcIsacfix_kLowerLimitHi; + upper_limit = WebRtcIsacfix_kUpperLimitHi; + } + + /* find quantization index */ + for (k=0; k<4; k++) + { + /* transform */ + CQ17=0; + for (j=0; j<PITCH_SUBFRAMES; j++) + CQ17 += WEBRTC_SPL_MUL_16_16_RSFT(WebRtcIsacfix_kTransform[k][j], PitchLagsQ7[j],2); // Q17 + + CQ17 = WEBRTC_SPL_SHIFT_W32(CQ17,shft); // Scale with StepSize + + /* quantize */ + tmp16b = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(CQ17 + 65536, 17 ); + index[k] = tmp16b; + + /* 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 bitstreams */ + if(encData != NULL) { + encData->pitchIndex[PITCH_SUBFRAMES*encData->startIdx + k] = index[k]; + } + } + + /* unquantize back to transform coefficients and do the inverse transform: S = T'*C */ + CQ11 = (index[0] + lower_limit[0]); // Q0 + CQ11 = WEBRTC_SPL_SHIFT_W32(CQ11,11-shft); // Scale with StepSize, Q11 + + for (k=0; k<PITCH_SUBFRAMES; k++) { + tmp32a = WEBRTC_SPL_MUL_16_32_RSFT11(WebRtcIsacfix_kTransform[0][k], CQ11); // Q12 + tmp16a = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp32a, 5);// Q7 + PitchLagsQ7[k] = tmp16a; + } + + CQ10 = mean_val2Q10[index[1]]; + for (k=0; k<PITCH_SUBFRAMES; k++) { + tmp32b = (WebRtc_Word32) WEBRTC_SPL_MUL_16_16_RSFT((WebRtc_Word16) WebRtcIsacfix_kTransform[1][k], (WebRtc_Word16) CQ10,10); + tmp16c = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp32b, 5); // Q7 + PitchLagsQ7[k] += tmp16c; + } + + CQ10 = mean_val4Q10[index[3]]; + for (k=0; k<PITCH_SUBFRAMES; k++) { + tmp32b = (WebRtc_Word32) WEBRTC_SPL_MUL_16_16_RSFT((WebRtc_Word16) WebRtcIsacfix_kTransform[3][k], (WebRtc_Word16) CQ10,10); + tmp16c = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp32b, 5); // Q7 + PitchLagsQ7[k] += tmp16c; + } + + /* entropy coding of quantization pitch lags */ + status = WebRtcIsacfix_EncHistMulti(streamdata, index, cdf, PITCH_SUBFRAMES); + + /* If error in WebRtcIsacfix_EncHistMulti(), status will be negative, otherwise 0 */ + return status; +} + + + +/* Routines for inband signaling of bandwitdh estimation */ +/* Histograms based on uniform distribution of indices */ +/* Move global variables later! */ + + +/* cdf array for frame length indicator */ +const WebRtc_UWord16 kFrameLenCdf[4] = { + 0, 21845, 43690, 65535}; + +/* pointer to cdf array for frame length indicator */ +const WebRtc_UWord16 *kFrameLenCdfPtr[1] = {kFrameLenCdf}; + +/* initial cdf index for decoder of frame length indicator */ +const WebRtc_UWord16 kFrameLenInitIndex[1] = {1}; + + +int WebRtcIsacfix_DecodeFrameLen(Bitstr_dec *streamdata, + WebRtc_Word16 *framesamples) +{ + + int err; + WebRtc_Word16 frame_mode; + + err = 0; + /* entropy decoding of frame length [1:30ms,2:60ms] */ + err = WebRtcIsacfix_DecHistOneStepMulti(&frame_mode, streamdata, kFrameLenCdfPtr, kFrameLenInitIndex, 1); + if (err<0) // error check + 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 WebRtcIsacfix_EncodeFrameLen(WebRtc_Word16 framesamples, Bitstr_enc *streamdata) { + + int status; + WebRtc_Word16 frame_mode; + + 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; + + status = WebRtcIsacfix_EncHistMulti(streamdata, &frame_mode, kFrameLenCdfPtr, 1); + + return status; +} + +/* cdf array for estimated bandwidth */ +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 */ +const WebRtc_UWord16 *kBwCdfPtr[1] = {kBwCdf}; + +/* initial cdf index for decoder of estimated bandwidth*/ +const WebRtc_UWord16 kBwInitIndex[1] = {7}; + + +int WebRtcIsacfix_DecodeSendBandwidth(Bitstr_dec *streamdata, WebRtc_Word16 *BWno) { + + int err; + WebRtc_Word16 BWno32; + + /* entropy decoding of sender's BW estimation [0..23] */ + err = WebRtcIsacfix_DecHistOneStepMulti(&BWno32, streamdata, kBwCdfPtr, kBwInitIndex, 1); + if (err<0) // error check + return -ISAC_RANGE_ERROR_DECODE_BANDWIDTH; + *BWno = (WebRtc_Word16)BWno32; + return err; + +} + + +int WebRtcIsacfix_EncodeReceiveBandwidth(WebRtc_Word16 *BWno, Bitstr_enc *streamdata) +{ + int status = 0; + /* entropy encoding of receiver's BW estimation [0..23] */ + status = WebRtcIsacfix_EncHistMulti(streamdata, BWno, kBwCdfPtr, 1); + + return status; +} + +/* estimate codel length of LPC Coef */ +void WebRtcIsacfix_TranscodeLpcCoef(WebRtc_Word32 *gain_lo_hiQ17, + WebRtc_Word16 *index_gQQ) { + int j, k, n; + WebRtc_Word16 posQQ, pos2QQ; + WebRtc_Word16 pos, pos2, posg, offsg, offs2, gainpos; + WebRtc_Word32 tmpcoeffs_gQ6[KLT_ORDER_GAIN]; + WebRtc_Word32 tmpcoeffs_gQ17[KLT_ORDER_GAIN]; + WebRtc_Word32 tmpcoeffs2_gQ21[KLT_ORDER_GAIN]; + WebRtc_Word32 sumQQ; + + + /* log gains, mean removal and scaling */ + posg = 0;pos=0; gainpos=0; + + for (k=0; k<SUBFRAMES; k++) { + /* log gains */ + + /* The input argument X to logN(X) is 2^17 times higher than the + input floating point argument Y to log(Y), since the X value + is a Q17 value. This can be compensated for after the call, by + subraction a value Z for each Q-step. One Q-step means that + X gets 2 times higher, i.e. Z = logN(2)*256 = 0.693147180559*256 = + 177.445678 should be subtracted (since logN() returns a Q8 value). + For a X value in Q17, the value 177.445678*17 = 3017 should be + subtracted */ + tmpcoeffs_gQ6[posg] = CalcLogN(gain_lo_hiQ17[gainpos])-3017; //Q8 + tmpcoeffs_gQ6[posg] -= WebRtcIsacfix_kMeansGainQ8[0][posg]; //Q8, but Q6 after not-needed mult. by 4 + posg++; gainpos++; + + tmpcoeffs_gQ6[posg] = CalcLogN(gain_lo_hiQ17[gainpos])-3017; //Q8 + tmpcoeffs_gQ6[posg] -= WebRtcIsacfix_kMeansGainQ8[0][posg]; //Q8, but Q6 after not-needed mult. by 4 + posg++; gainpos++; + + } + + + /* KLT */ + + /* left transform */ + offsg = 0; + for (j=0; j<SUBFRAMES; j++) { + posg = offsg; + for (k=0; k<2; k++) { + sumQQ = 0; + pos = offsg; + pos2 = k; + for (n=0; n<2; n++) { + sumQQ += WEBRTC_SPL_MUL_16_16(tmpcoeffs_gQ6[pos], WebRtcIsacfix_kT1GainQ15[0][pos2]); //Q21 = Q6*Q15 + pos++; + pos2 += 2; + } + tmpcoeffs2_gQ21[posg] = sumQQ; + posg++; + } + + offsg += 2; + } + + /* right transform */ + offsg = 0; + offs2 = 0; + for (j=0; j<SUBFRAMES; j++) { + posg = offsg; + for (k=0; k<2; k++) { + sumQQ = 0; + pos = k; + pos2 = offs2; + for (n=0; n<SUBFRAMES; n++) { + sumQQ += WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(WebRtcIsacfix_kT2GainQ15[0][pos2], tmpcoeffs2_gQ21[pos]), 1); // (Q15*Q21)>>(16-1) = Q21 + pos += 2; + pos2++; + } + tmpcoeffs_gQ17[posg] = WEBRTC_SPL_RSHIFT_W32(sumQQ, 4); + posg++; + } + offsg += 2; + offs2 += SUBFRAMES; + } + + /* quantize coefficients */ + for (k=0; k<KLT_ORDER_GAIN; k++) //ATTN: ok? + { + posQQ = WebRtcIsacfix_kSelIndGain[k]; + pos2QQ= (WebRtc_Word16)CalcLrIntQ(tmpcoeffs_gQ17[posQQ], 17); + + index_gQQ[k] = pos2QQ + WebRtcIsacfix_kQuantMinGain[k]; //ATTN: ok? + if (index_gQQ[k] < 0) { + index_gQQ[k] = 0; + } + else if (index_gQQ[k] > WebRtcIsacfix_kMaxIndGain[k]) { + index_gQQ[k] = WebRtcIsacfix_kMaxIndGain[k]; + } + } +} diff --git a/src/modules/audio_coding/codecs/isac/fix/source/entropy_coding.h b/src/modules/audio_coding/codecs/isac/fix/source/entropy_coding.h new file mode 100644 index 0000000000..298ea223ac --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/entropy_coding.h @@ -0,0 +1,111 @@ +/* + * 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. + */ + +/* + * entropy_coding.h + * + * This header file contains all of the functions used to arithmetically + * encode the iSAC bistream + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_ENTROPY_CODING_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_ENTROPY_CODING_H_ + +#include "structs.h" + +/* decode complex spectrum (return number of bytes in stream) */ +WebRtc_Word16 WebRtcIsacfix_DecodeSpec(Bitstr_dec *streamdata, + WebRtc_Word16 *frQ7, + WebRtc_Word16 *fiQ7, + WebRtc_Word16 AvgPitchGain_Q12); + +/* encode complex spectrum */ +int WebRtcIsacfix_EncodeSpec(const WebRtc_Word16 *fr, + const WebRtc_Word16 *fi, + Bitstr_enc *streamdata, + WebRtc_Word16 AvgPitchGain_Q12); + + +/* decode & dequantize LPC Coef */ +int WebRtcIsacfix_DecodeLpcCoef(Bitstr_dec *streamdata, + WebRtc_Word32 *LPCCoefQ17, + WebRtc_Word32 *gain_lo_hiQ17, + WebRtc_Word16 *outmodel); + +int WebRtcIsacfix_DecodeLpc(WebRtc_Word32 *gain_lo_hiQ17, + WebRtc_Word16 *LPCCoef_loQ15, + WebRtc_Word16 *LPCCoef_hiQ15, + Bitstr_dec *streamdata, + WebRtc_Word16 *outmodel); + +/* quantize & code LPC Coef */ +int WebRtcIsacfix_EncodeLpc(WebRtc_Word32 *gain_lo_hiQ17, + WebRtc_Word16 *LPCCoef_loQ15, + WebRtc_Word16 *LPCCoef_hiQ15, + WebRtc_Word16 *model, + WebRtc_Word32 *sizeQ11, + Bitstr_enc *streamdata, + ISAC_SaveEncData_t* encData, + transcode_obj *transcodeParam); + +int WebRtcIsacfix_EstCodeLpcGain(WebRtc_Word32 *gain_lo_hiQ17, + Bitstr_enc *streamdata, + ISAC_SaveEncData_t* encData); +/* decode & dequantize RC */ +int WebRtcIsacfix_DecodeRcCoef(Bitstr_dec *streamdata, + WebRtc_Word16 *RCQ15); + +/* quantize & code RC */ +int WebRtcIsacfix_EncodeRcCoef(WebRtc_Word16 *RCQ15, + Bitstr_enc *streamdata); + +/* decode & dequantize squared Gain */ +int WebRtcIsacfix_DecodeGain2(Bitstr_dec *streamdata, + WebRtc_Word32 *Gain2); + +/* quantize & code squared Gain (input is squared gain) */ +int WebRtcIsacfix_EncodeGain2(WebRtc_Word32 *gain2, + Bitstr_enc *streamdata); + +int WebRtcIsacfix_EncodePitchGain(WebRtc_Word16 *PitchGains_Q12, + Bitstr_enc *streamdata, + ISAC_SaveEncData_t* encData); + +int WebRtcIsacfix_EncodePitchLag(WebRtc_Word16 *PitchLagQ7, + WebRtc_Word16 *PitchGain_Q12, + Bitstr_enc *streamdata, + ISAC_SaveEncData_t* encData); + +int WebRtcIsacfix_DecodePitchGain(Bitstr_dec *streamdata, + WebRtc_Word16 *PitchGain_Q12); + +int WebRtcIsacfix_DecodePitchLag(Bitstr_dec *streamdata, + WebRtc_Word16 *PitchGain_Q12, + WebRtc_Word16 *PitchLagQ7); + +int WebRtcIsacfix_DecodeFrameLen(Bitstr_dec *streamdata, + WebRtc_Word16 *framelength); + + +int WebRtcIsacfix_EncodeFrameLen(WebRtc_Word16 framelength, + Bitstr_enc *streamdata); + +int WebRtcIsacfix_DecodeSendBandwidth(Bitstr_dec *streamdata, + WebRtc_Word16 *BWno); + + +int WebRtcIsacfix_EncodeReceiveBandwidth(WebRtc_Word16 *BWno, + Bitstr_enc *streamdata); + +void WebRtcIsacfix_TranscodeLpcCoef(WebRtc_Word32 *tmpcoeffs_gQ6, + WebRtc_Word16 *index_gQQ); + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_ENTROPY_CODING_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/fix/source/fft.c b/src/modules/audio_coding/codecs/isac/fix/source/fft.c new file mode 100644 index 0000000000..fff35c4ffa --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/fft.c @@ -0,0 +1,415 @@ +/* + * 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. + */ + +/* + * fft.c + * + * Fast Fourier Transform + * + */ + + +#include "fft.h" + +const WebRtc_Word16 kSortTabFft[240] = { + 0, 60, 120, 180, 20, 80, 140, 200, 40, 100, 160, 220, + 4, 64, 124, 184, 24, 84, 144, 204, 44, 104, 164, 224, + 8, 68, 128, 188, 28, 88, 148, 208, 48, 108, 168, 228, + 12, 72, 132, 192, 32, 92, 152, 212, 52, 112, 172, 232, + 16, 76, 136, 196, 36, 96, 156, 216, 56, 116, 176, 236, + 1, 61, 121, 181, 21, 81, 141, 201, 41, 101, 161, 221, + 5, 65, 125, 185, 25, 85, 145, 205, 45, 105, 165, 225, + 9, 69, 129, 189, 29, 89, 149, 209, 49, 109, 169, 229, + 13, 73, 133, 193, 33, 93, 153, 213, 53, 113, 173, 233, + 17, 77, 137, 197, 37, 97, 157, 217, 57, 117, 177, 237, + 2, 62, 122, 182, 22, 82, 142, 202, 42, 102, 162, 222, + 6, 66, 126, 186, 26, 86, 146, 206, 46, 106, 166, 226, + 10, 70, 130, 190, 30, 90, 150, 210, 50, 110, 170, 230, + 14, 74, 134, 194, 34, 94, 154, 214, 54, 114, 174, 234, + 18, 78, 138, 198, 38, 98, 158, 218, 58, 118, 178, 238, + 3, 63, 123, 183, 23, 83, 143, 203, 43, 103, 163, 223, + 7, 67, 127, 187, 27, 87, 147, 207, 47, 107, 167, 227, + 11, 71, 131, 191, 31, 91, 151, 211, 51, 111, 171, 231, + 15, 75, 135, 195, 35, 95, 155, 215, 55, 115, 175, 235, + 19, 79, 139, 199, 39, 99, 159, 219, 59, 119, 179, 239 +}; + +/* Cosine table in Q14 */ +const WebRtc_Word16 kCosTabFfftQ14[240] = { + 16384, 16378, 16362, 16333, 16294, 16244, 16182, 16110, 16026, 15931, 15826, 15709, + 15582, 15444, 15296, 15137, 14968, 14788, 14598, 14399, 14189, 13970, 13741, 13502, + 13255, 12998, 12733, 12458, 12176, 11885, 11585, 11278, 10963, 10641, 10311, 9974, + 9630, 9280, 8923, 8561, 8192, 7818, 7438, 7053, 6664, 6270, 5872, 5469, + 5063, 4653, 4240, 3825, 3406, 2986, 2563, 2139, 1713, 1285, 857, 429, + 0, -429, -857, -1285, -1713, -2139, -2563, -2986, -3406, -3825, -4240, -4653, + -5063, -5469, -5872, -6270, -6664, -7053, -7438, -7818, -8192, -8561, -8923, -9280, + -9630, -9974, -10311, -10641, -10963, -11278, -11585, -11885, -12176, -12458, -12733, -12998, + -13255, -13502, -13741, -13970, -14189, -14399, -14598, -14788, -14968, -15137, -15296, -15444, + -15582, -15709, -15826, -15931, -16026, -16110, -16182, -16244, -16294, -16333, -16362, -16378, + -16384, -16378, -16362, -16333, -16294, -16244, -16182, -16110, -16026, -15931, -15826, -15709, + -15582, -15444, -15296, -15137, -14968, -14788, -14598, -14399, -14189, -13970, -13741, -13502, + -13255, -12998, -12733, -12458, -12176, -11885, -11585, -11278, -10963, -10641, -10311, -9974, + -9630, -9280, -8923, -8561, -8192, -7818, -7438, -7053, -6664, -6270, -5872, -5469, + -5063, -4653, -4240, -3825, -3406, -2986, -2563, -2139, -1713, -1285, -857, -429, + 0, 429, 857, 1285, 1713, 2139, 2563, 2986, 3406, 3825, 4240, 4653, + 5063, 5469, 5872, 6270, 6664, 7053, 7438, 7818, 8192, 8561, 8923, 9280, + 9630, 9974, 10311, 10641, 10963, 11278, 11585, 11885, 12176, 12458, 12733, 12998, + 13255, 13502, 13741, 13970, 14189, 14399, 14598, 14788, 14968, 15137, 15296, 15444, + 15582, 15709, 15826, 15931, 16026, 16110, 16182, 16244, 16294, 16333, 16362, 16378 +}; + + + +/* Uses 16x16 mul, without rounding, which is faster. Uses WEBRTC_SPL_MUL_16_16_RSFT */ +WebRtc_Word16 WebRtcIsacfix_FftRadix16Fastest(WebRtc_Word16 RexQx[], WebRtc_Word16 ImxQx[], WebRtc_Word16 iSign) { + + WebRtc_Word16 dd, ee, ff, gg, hh, ii; + WebRtc_Word16 k0, k1, k2, k3, k4, kk; + WebRtc_Word16 tmp116, tmp216; + + WebRtc_Word16 ccc1Q14, ccc2Q14, ccc3Q14, sss1Q14, sss2Q14, sss3Q14; + WebRtc_Word16 sss60Q14, ccc72Q14, sss72Q14; + WebRtc_Word16 aaQx, ajQx, akQx, ajmQx, ajpQx, akmQx, akpQx; + WebRtc_Word16 bbQx, bjQx, bkQx, bjmQx, bjpQx, bkmQx, bkpQx; + + WebRtc_Word16 ReDATAQx[240], ImDATAQx[240]; + + sss60Q14 = kCosTabFfftQ14[20]; + ccc72Q14 = kCosTabFfftQ14[48]; + sss72Q14 = kCosTabFfftQ14[12]; + + if (iSign < 0) { + sss72Q14 = -sss72Q14; + sss60Q14 = -sss60Q14; + } + /* Complexity is: 10 cycles */ + + /* compute fourier transform */ + + // transform for factor of 4 + for (kk=0; kk<60; kk++) { + k0 = kk; + k1 = k0 + 60; + k2 = k1 + 60; + k3 = k2 + 60; + + akpQx = RexQx[k0] + RexQx[k2]; + akmQx = RexQx[k0] - RexQx[k2]; + ajpQx = RexQx[k1] + RexQx[k3]; + ajmQx = RexQx[k1] - RexQx[k3]; + bkpQx = ImxQx[k0] + ImxQx[k2]; + bkmQx = ImxQx[k0] - ImxQx[k2]; + bjpQx = ImxQx[k1] + ImxQx[k3]; + bjmQx = ImxQx[k1] - ImxQx[k3]; + + RexQx[k0] = akpQx + ajpQx; + ImxQx[k0] = bkpQx + bjpQx; + ajpQx = akpQx - ajpQx; + bjpQx = bkpQx - bjpQx; + if (iSign < 0) { + akpQx = akmQx + bjmQx; + bkpQx = bkmQx - ajmQx; + akmQx -= bjmQx; + bkmQx += ajmQx; + } else { + akpQx = akmQx - bjmQx; + bkpQx = bkmQx + ajmQx; + akmQx += bjmQx; + bkmQx -= ajmQx; + } + + ccc1Q14 = kCosTabFfftQ14[kk]; + ccc2Q14 = kCosTabFfftQ14[WEBRTC_SPL_MUL_16_16(2, kk)]; + ccc3Q14 = kCosTabFfftQ14[WEBRTC_SPL_MUL_16_16(3, kk)]; + sss1Q14 = kCosTabFfftQ14[kk+60]; + sss2Q14 = kCosTabFfftQ14[WEBRTC_SPL_MUL_16_16(2, kk)+60]; + sss3Q14 = kCosTabFfftQ14[WEBRTC_SPL_MUL_16_16(3, kk)+60]; + if (iSign==1) { + sss1Q14 = -sss1Q14; + sss2Q14 = -sss2Q14; + sss3Q14 = -sss3Q14; + } + + //Do several multiplications like Q14*Q16>>14 = Q16 + // RexQ16[k1] = akpQ16 * ccc1Q14 - bkpQ16 * sss1Q14; + // RexQ16[k2] = ajpQ16 * ccc2Q14 - bjpQ16 * sss2Q14; + // RexQ16[k3] = akmQ16 * ccc3Q14 - bkmQ16 * sss3Q14; + // ImxQ16[k1] = akpQ16 * sss1Q14 + bkpQ16 * ccc1Q14; + // ImxQ16[k2] = ajpQ16 * sss2Q14 + bjpQ16 * ccc2Q14; + // ImxQ16[k3] = akmQ16 * sss3Q14 + bkmQ16 * ccc3Q14; + + RexQx[k1] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(ccc1Q14, akpQx, 14) - + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(sss1Q14, bkpQx, 14); // 6 non-mul + 2 mul cycles, i.e. 8 cycles (6+2*7=20 cycles if 16x32mul) + RexQx[k2] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(ccc2Q14, ajpQx, 14) - + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(sss2Q14, bjpQx, 14); + RexQx[k3] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(ccc3Q14, akmQx, 14) - + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(sss3Q14, bkmQx, 14); + ImxQx[k1] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(sss1Q14, akpQx, 14) + + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(ccc1Q14, bkpQx, 14); + ImxQx[k2] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(sss2Q14, ajpQx, 14) + + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(ccc2Q14, bjpQx, 14); + ImxQx[k3] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(sss3Q14, akmQx, 14) + + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(ccc3Q14, bkmQx, 14); + //This mul segment needs 6*8 = 48 cycles for 16x16 muls, but 6*20 = 120 cycles for 16x32 muls + + + } + /* Complexity is: 51+48 = 99 cycles for 16x16 muls, but 51+120 = 171 cycles for 16x32 muls*/ + + // transform for factor of 3 + kk=0; + k1=20; + k2=40; + + for (hh=0; hh<4; hh++) { + for (ii=0; ii<20; ii++) { + akQx = RexQx[kk]; + bkQx = ImxQx[kk]; + ajQx = RexQx[k1] + RexQx[k2]; + bjQx = ImxQx[k1] + ImxQx[k2]; + RexQx[kk] = akQx + ajQx; + ImxQx[kk] = bkQx + bjQx; + tmp116 = WEBRTC_SPL_RSHIFT_W16(ajQx, 1); + tmp216 = WEBRTC_SPL_RSHIFT_W16(bjQx, 1); + akQx = akQx - tmp116; + bkQx = bkQx - tmp216; + tmp116 = RexQx[k1] - RexQx[k2]; + tmp216 = ImxQx[k1] - ImxQx[k2]; + + ajQx = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(sss60Q14, tmp116, 14); // Q14*Qx>>14 = Qx + bjQx = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(sss60Q14, tmp216, 14); // Q14*Qx>>14 = Qx + RexQx[k1] = akQx - bjQx; + RexQx[k2] = akQx + bjQx; + ImxQx[k1] = bkQx + ajQx; + ImxQx[k2] = bkQx - ajQx; + + kk++; + k1++; + k2++; + } + /* Complexity : (31+6)*20 = 740 cycles for 16x16 muls, but (31+18)*20 = 980 cycles for 16x32 muls*/ + kk=kk+40; + k1=k1+40; + k2=k2+40; + } + /* Complexity : 4*(740+3) = 2972 cycles for 16x16 muls, but 4*(980+3) = 3932 cycles for 16x32 muls*/ + + /* multiply by rotation factor for odd factor 3 or 5 (not for 4) + Same code (duplicated) for both ii=2 and ii=3 */ + kk = 1; + ee = 0; + ff = 0; + + for (gg=0; gg<19; gg++) { + kk += 20; + ff = ff+4; + for (hh=0; hh<2; hh++) { + ee = ff + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16(hh, ff); + dd = ee + 60; + ccc2Q14 = kCosTabFfftQ14[ee]; + sss2Q14 = kCosTabFfftQ14[dd]; + if (iSign==1) { + sss2Q14 = -sss2Q14; + } + for (ii=0; ii<4; ii++) { + akQx = RexQx[kk]; + bkQx = ImxQx[kk]; + RexQx[kk] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(ccc2Q14, akQx, 14) - // Q14*Qx>>14 = Qx + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(sss2Q14, bkQx, 14); + ImxQx[kk] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(sss2Q14, akQx, 14) + // Q14*Qx>>14 = Qx + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(ccc2Q14, bkQx, 14); + + + kk += 60; + } + kk = kk - 220; + } + // Complexity: 2*(13+5+4*13+2) = 144 for 16x16 muls, but 2*(13+5+4*33+2) = 304 cycles for 16x32 muls + kk = kk - 59; + } + // Complexity: 19*144 = 2736 for 16x16 muls, but 19*304 = 5776 cycles for 16x32 muls + + // transform for factor of 5 + kk = 0; + ccc2Q14 = kCosTabFfftQ14[96]; + sss2Q14 = kCosTabFfftQ14[84]; + if (iSign==1) { + sss2Q14 = -sss2Q14; + } + + for (hh=0; hh<4; hh++) { + for (ii=0; ii<12; ii++) { + k1 = kk + 4; + k2 = k1 + 4; + k3 = k2 + 4; + k4 = k3 + 4; + + akpQx = RexQx[k1] + RexQx[k4]; + akmQx = RexQx[k1] - RexQx[k4]; + bkpQx = ImxQx[k1] + ImxQx[k4]; + bkmQx = ImxQx[k1] - ImxQx[k4]; + ajpQx = RexQx[k2] + RexQx[k3]; + ajmQx = RexQx[k2] - RexQx[k3]; + bjpQx = ImxQx[k2] + ImxQx[k3]; + bjmQx = ImxQx[k2] - ImxQx[k3]; + aaQx = RexQx[kk]; + bbQx = ImxQx[kk]; + RexQx[kk] = aaQx + akpQx + ajpQx; + ImxQx[kk] = bbQx + bkpQx + bjpQx; + + akQx = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(ccc72Q14, akpQx, 14) + + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(ccc2Q14, ajpQx, 14) + aaQx; + bkQx = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(ccc72Q14, bkpQx, 14) + + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(ccc2Q14, bjpQx, 14) + bbQx; + ajQx = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(sss72Q14, akmQx, 14) + + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(sss2Q14, ajmQx, 14); + bjQx = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(sss72Q14, bkmQx, 14) + + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(sss2Q14, bjmQx, 14); + // 32+4*8=64 or 32+4*20=112 + + RexQx[k1] = akQx - bjQx; + RexQx[k4] = akQx + bjQx; + ImxQx[k1] = bkQx + ajQx; + ImxQx[k4] = bkQx - ajQx; + + akQx = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(ccc2Q14, akpQx, 14) + + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(ccc72Q14, ajpQx, 14) + aaQx; + bkQx = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(ccc2Q14, bkpQx, 14) + + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(ccc72Q14, bjpQx, 14) + bbQx; + ajQx = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(sss2Q14, akmQx, 14) - + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(sss72Q14, ajmQx, 14); + bjQx = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(sss2Q14, bkmQx, 14) - + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(sss72Q14, bjmQx, 14); + // 8+4*8=40 or 8+4*20=88 + + RexQx[k2] = akQx - bjQx; + RexQx[k3] = akQx + bjQx; + ImxQx[k2] = bkQx + ajQx; + ImxQx[k3] = bkQx - ajQx; + + kk = k4 + 4; + } + // Complexity: 12*(64+40+10) = 1368 for 16x16 muls, but 12*(112+88+10) = 2520 cycles for 16x32 muls + kk -= 239; + } + // Complexity: 4*1368 = 5472 for 16x16 muls, but 4*2520 = 10080 cycles for 16x32 muls + + /* multiply by rotation factor for odd factor 3 or 5 (not for 4) + Same code (duplicated) for both ii=2 and ii=3 */ + kk = 1; + ee=0; + + for (gg=0; gg<3; gg++) { + kk += 4; + dd = 12 + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16(12, gg); + ff = 0; + for (hh=0; hh<4; hh++) { + ff = ff+dd; + ee = ff+60; + for (ii=0; ii<12; ii++) { + akQx = RexQx[kk]; + bkQx = ImxQx[kk]; + + ccc2Q14 = kCosTabFfftQ14[ff]; + sss2Q14 = kCosTabFfftQ14[ee]; + + if (iSign==1) { + sss2Q14 = -sss2Q14; + } + + RexQx[kk] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(ccc2Q14, akQx, 14) - + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(sss2Q14, bkQx, 14); + ImxQx[kk] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(sss2Q14, akQx, 14) + + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(ccc2Q14, bkQx, 14); + + kk += 20; + } + kk = kk - 236; + // Complexity: 12*(12+12) = 288 for 16x16 muls, but 12*(12+32) = 528 cycles for 16x32 muls + } + kk = kk - 19; + // Complexity: 4*288+6 for 16x16 muls, but 4*528+6 cycles for 16x32 muls + } + // Complexity: 3*4*288+6 = 3462 for 16x16 muls, but 3*4*528+6 = 6342 cycles for 16x32 muls + + + // last transform for factor of 4 */ + for (kk=0; kk<240; kk=kk+4) { + k1 = kk + 1; + k2 = k1 + 1; + k3 = k2 + 1; + + akpQx = RexQx[kk] + RexQx[k2]; + akmQx = RexQx[kk] - RexQx[k2]; + ajpQx = RexQx[k1] + RexQx[k3]; + ajmQx = RexQx[k1] - RexQx[k3]; + bkpQx = ImxQx[kk] + ImxQx[k2]; + bkmQx = ImxQx[kk] - ImxQx[k2]; + bjpQx = ImxQx[k1] + ImxQx[k3]; + bjmQx = ImxQx[k1] - ImxQx[k3]; + RexQx[kk] = akpQx + ajpQx; + ImxQx[kk] = bkpQx + bjpQx; + ajpQx = akpQx - ajpQx; + bjpQx = bkpQx - bjpQx; + if (iSign < 0) { + akpQx = akmQx + bjmQx; + bkpQx = bkmQx - ajmQx; + akmQx -= bjmQx; + bkmQx += ajmQx; + } else { + akpQx = akmQx - bjmQx; + bkpQx = bkmQx + ajmQx; + akmQx += bjmQx; + bkmQx -= ajmQx; + } + RexQx[k1] = akpQx; + RexQx[k2] = ajpQx; + RexQx[k3] = akmQx; + ImxQx[k1] = bkpQx; + ImxQx[k2] = bjpQx; + ImxQx[k3] = bkmQx; + } + // Complexity: 60*45 = 2700 for 16x16 muls, but 60*45 = 2700 cycles for 16x32 muls + + /* permute the results to normal order */ + for (ii=0; ii<240; ii++) { + ReDATAQx[ii]=RexQx[ii]; + ImDATAQx[ii]=ImxQx[ii]; + } + // Complexity: 240*2=480 cycles + + for (ii=0; ii<240; ii++) { + RexQx[ii]=ReDATAQx[kSortTabFft[ii]]; + ImxQx[ii]=ImDATAQx[kSortTabFft[ii]]; + } + // Complexity: 240*2*2=960 cycles + + // Total complexity: + // 16x16 16x32 + // Complexity: 10 10 + // Complexity: 99 171 + // Complexity: 2972 3932 + // Complexity: 2736 5776 + // Complexity: 5472 10080 + // Complexity: 3462 6342 + // Complexity: 2700 2700 + // Complexity: 480 480 + // Complexity: 960 960 + // ======================= + // 18891 30451 + // + // If this FFT is called 2 time each frame, i.e. 67 times per second, it will correspond to + // a C54 complexity of 67*18891/1000000 = 1.27 MIPS with 16x16-muls, and 67*30451/1000000 = + // = 2.04 MIPS with 16x32-muls. Note that this routine somtimes is called 6 times during the + // encoding of a frame, i.e. the max complexity would be 7/2*1.27 = 4.4 MIPS for the 16x16 mul case. + + + return 0; +} diff --git a/src/modules/audio_coding/codecs/isac/fix/source/fft.h b/src/modules/audio_coding/codecs/isac/fix/source/fft.h new file mode 100644 index 0000000000..efa116e705 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/fft.h @@ -0,0 +1,41 @@ +/* + * 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: + * fft.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_FIX_SOURCE_FFT_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_FFT_H_ + + +#include "structs.h" + + +WebRtc_Word16 WebRtcIsacfix_FftRadix16Fastest(WebRtc_Word16 RexQx[], WebRtc_Word16 ImxQx[], WebRtc_Word16 iSign); + + + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_FFT_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/fix/source/filterbank_internal.h b/src/modules/audio_coding/codecs/isac/fix/source/filterbank_internal.h new file mode 100644 index 0000000000..d5d9efbe16 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/filterbank_internal.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_FILTERBANK_INTERNAL_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_FILTERBANK_INTERNAL_H_ + +#include "typedefs.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/* Arguments: + * io: Input/output, in Q0. + * len: Input, sample length. + * coefficient: Input. + * state: Input/output, filter state, in Q4. + */ +void WebRtcIsacfix_HighpassFilterFixDec32(int16_t *io, + int16_t len, + const int16_t *coefficient, + int32_t *state); + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif +/* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_FILTERBANK_INTERNAL_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/fix/source/filterbank_tables.c b/src/modules/audio_coding/codecs/isac/fix/source/filterbank_tables.c new file mode 100644 index 0000000000..732611b643 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/filterbank_tables.c @@ -0,0 +1,62 @@ +/* + * 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. + */ + +/* + * filterbank_tables.c + * + * This file contains variables that are used in + * filterbanks.c + * + */ + +#include "filterbank_tables.h" + +/* HPstcoeff_in_Q14 = {a1, a2, b1 - b0 * a1, b2 - b0 * a2}; + * In float, they are: {-1.94895953203325f, 0.94984516000000f, + * -0.05101826139794f, 0.05015484000000f}; + */ +const int16_t WebRtcIsacfix_kHpStCoeffInQ30[8] = { + 16189, -31932, /* Q30 lo/hi pair */ + 17243, 15562, /* Q30 lo/hi pair */ + -17186, -26748, /* Q35 lo/hi pair */ + -27476, 26296 /* Q35 lo/hi pair */ +}; + +/* HPstcoeff_out_1_Q14 = {a1, a2, b1 - b0 * a1, b2 - b0 * a2}; + * In float, they are: {-1.99701049409000f, 0.99714204490000f, + * 0.01701049409000f, -0.01704204490000f}; + */ +const int16_t WebRtcIsacfix_kHPStCoeffOut1Q30[8] = { + -1306, -32719, /* Q30 lo/hi pair */ + 11486, 16337, /* Q30 lo/hi pair */ + 26078, 8918, /* Q35 lo/hi pair */ + 3956, -8935 /* Q35 lo/hi pair */ +}; + +/* HPstcoeff_out_2_Q14 = {a1, a2, b1 - b0 * a1, b2 - b0 * a2}; + * In float, they are: {-1.98645294509837f, 0.98672435560000f, + * 0.00645294509837f, -0.00662435560000f}; + */ +const int16_t WebRtcIsacfix_kHPStCoeffOut2Q30[8] = { + -2953, -32546, /* Q30 lo/hi pair */ + 32233, 16166, /* Q30 lo/hi pair */ + 13217, 3383, /* Q35 lo/hi pair */ + -4597, -3473 /* Q35 lo/hi pair */ +}; + +/* The upper channel all-pass filter factors */ +const int16_t WebRtcIsacfix_kUpperApFactorsQ15[2] = { + 1137, 12537 +}; + +/* The lower channel all-pass filter factors */ +const int16_t WebRtcIsacfix_kLowerApFactorsQ15[2] = { + 5059, 24379 +}; diff --git a/src/modules/audio_coding/codecs/isac/fix/source/filterbank_tables.h b/src/modules/audio_coding/codecs/isac/fix/source/filterbank_tables.h new file mode 100644 index 0000000000..9a888e4fc6 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/filterbank_tables.h @@ -0,0 +1,52 @@ +/* + * 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. + */ + +/* + * filterbank_tables.h + * + * Header file for variables that are defined in + * filterbank_tables.c. + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_FILTERBANK_TABLES_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_FILTERBANK_TABLES_H_ + +#include "typedefs.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/********************* Coefficient Tables ************************/ + +/* HPstcoeff_in_Q14 = {a1, a2, b1 - b0 * a1, b2 - b0 * a2}; */ +/* [Q30lo Q30hi Q30lo Q30hi Q35lo Q35hi Q35lo Q35hi] */ +extern const int16_t WebRtcIsacfix_kHpStCoeffInQ30[8]; + +/* HPstcoeff_out_1_Q14 = {a1, a2, b1 - b0 * a1, b2 - b0 * a2}; */ +/* [Q30lo Q30hi Q30lo Q30hi Q35lo Q35hi Q35lo Q35hi] */ +extern const int16_t WebRtcIsacfix_kHPStCoeffOut1Q30[8]; + +/* HPstcoeff_out_2_Q14 = {a1, a2, b1 - b0 * a1, b2 - b0 * a2}; */ +/* [Q30lo Q30hi Q30lo Q30hi Q35lo Q35hi Q35lo Q35hi] */ +extern const int16_t WebRtcIsacfix_kHPStCoeffOut2Q30[8]; + +/* The upper channel all-pass filter factors */ +extern const int16_t WebRtcIsacfix_kUpperApFactorsQ15[2]; + +/* The lower channel all-pass filter factors */ +extern const int16_t WebRtcIsacfix_kLowerApFactorsQ15[2]; + +#if defined(__cplusplus) || defined(c_plusplus) +} +#endif + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_FILTERBANK_TABLES_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/fix/source/filterbanks.c b/src/modules/audio_coding/codecs/isac/fix/source/filterbanks.c new file mode 100644 index 0000000000..949e7cf6e4 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/filterbanks.c @@ -0,0 +1,354 @@ +/* + * 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. + */ + +/* + * filterbanks.c + * + * This file contains function + * WebRtcIsacfix_SplitAndFilter, and WebRtcIsacfix_FilterAndCombine + * which implement filterbanks that produce decimated lowpass and + * highpass versions of a signal, and performs reconstruction. + * + */ + +#include "codec.h" +#include "filterbank_internal.h" +#include "filterbank_tables.h" +#include "settings.h" + + +static void AllpassFilter2FixDec16(WebRtc_Word16 *InOut16, //Q0 + const WebRtc_Word16 *APSectionFactors, //Q15 + WebRtc_Word16 lengthInOut, + WebRtc_Word16 NumberOfSections, + WebRtc_Word32 *FilterState) //Q16 +{ + int n, j; + WebRtc_Word32 a, b; + + for (j=0; j<NumberOfSections; j++) { + for (n=0;n<lengthInOut;n++) { + + + a = WEBRTC_SPL_MUL_16_16(APSectionFactors[j], InOut16[n]); //Q15*Q0=Q15 + a = WEBRTC_SPL_LSHIFT_W32(a, 1); // Q15 -> Q16 + b = WEBRTC_SPL_ADD_SAT_W32(a, FilterState[j]); //Q16+Q16=Q16 + a = WEBRTC_SPL_MUL_16_16_RSFT(-APSectionFactors[j], (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(b, 16), 0); //Q15*Q0=Q15 + FilterState[j] = WEBRTC_SPL_ADD_SAT_W32(WEBRTC_SPL_LSHIFT_W32(a,1), WEBRTC_SPL_LSHIFT_W32((WebRtc_UWord32)InOut16[n],16)); // Q15<<1 + Q0<<16 = Q16 + Q16 = Q16 + InOut16[n] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(b, 16); //Save as Q0 + + } + } + +} + + +void WebRtcIsacfix_HighpassFilterFixDec32(int16_t *io, + int16_t len, + const int16_t *coefficient, + int32_t *state) +{ + int k; + WebRtc_Word32 a1 = 0, b1 = 0, c = 0, in = 0; + WebRtc_Word32 a2 = 0, b2 = 0; + WebRtc_Word32 state0 = state[0]; + WebRtc_Word32 state1 = state[1]; + + for (k=0; k<len; k++) { + in = (WebRtc_Word32)io[k]; + +#ifdef WEBRTC_ARCH_ARM_V7 + { + int tmp_coeff0 = 0; + int tmp_coeff1 = 0; + __asm __volatile( + "ldr %[tmp_coeff0], [%[coeff]]\n\t" + "ldr %[tmp_coeff1], [%[coeff], #4]\n\t" + "smmulr %[a2], %[tmp_coeff0], %[state0]\n\t" + "smmulr %[b2], %[tmp_coeff1], %[state1]\n\t" + "ldr %[tmp_coeff0], [%[coeff], #8]\n\t" + "ldr %[tmp_coeff1], [%[coeff], #12]\n\t" + "smmulr %[a1], %[tmp_coeff0], %[state0]\n\t" + "smmulr %[b1], %[tmp_coeff1], %[state1]\n\t" + :[a2]"+r"(a2), + [b2]"+r"(b2), + [a1]"+r"(a1), + [b1]"+r"(b1), + [tmp_coeff0]"+r"(tmp_coeff0), + [tmp_coeff1]"+r"(tmp_coeff1) + :[coeff]"r"(coefficient), + [state0]"r"(state0), + [state1]"r"(state1) + ); + } +#else + /* Q35 * Q4 = Q39 ; shift 32 bit => Q7 */ + a1 = WEBRTC_SPL_MUL_32_32_RSFT32(coefficient[5], coefficient[4], state0); + b1 = WEBRTC_SPL_MUL_32_32_RSFT32(coefficient[7], coefficient[6], state1); + + /* Q30 * Q4 = Q34 ; shift 32 bit => Q2 */ + a2 = WEBRTC_SPL_MUL_32_32_RSFT32(coefficient[1], coefficient[0], state0); + b2 = WEBRTC_SPL_MUL_32_32_RSFT32(coefficient[3], coefficient[2], state1); +#endif + + c = ((WebRtc_Word32)in) + WEBRTC_SPL_RSHIFT_W32(a1+b1, 7); // Q0 + io[k] = (WebRtc_Word16)WebRtcSpl_SatW32ToW16(c); // Write output as Q0. + + c = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)in, 2) - a2 - b2; // In Q2. + c = (WebRtc_Word32)WEBRTC_SPL_SAT(536870911, c, -536870912); + + state1 = state0; + state0 = WEBRTC_SPL_LSHIFT_W32(c, 2); // Write state as Q4 + } + state[0] = state0; + state[1] = state1; +} + + +void WebRtcIsacfix_SplitAndFilter1(WebRtc_Word16 *pin, + WebRtc_Word16 *LP16, + WebRtc_Word16 *HP16, + PreFiltBankstr *prefiltdata) +{ + /* Function WebRtcIsacfix_SplitAndFilter */ + /* This function creates low-pass and high-pass decimated versions of part of + the input signal, and part of the signal in the input 'lookahead buffer'. */ + + int k; + + WebRtc_Word16 tempin_ch1[FRAMESAMPLES/2 + QLOOKAHEAD]; + WebRtc_Word16 tempin_ch2[FRAMESAMPLES/2 + QLOOKAHEAD]; + WebRtc_Word32 tmpState[WEBRTC_SPL_MUL_16_16(2,(QORDER-1))]; /* 4 */ + + + /* High pass filter */ + WebRtcIsacfix_HighpassFilterFixDec32(pin, FRAMESAMPLES, WebRtcIsacfix_kHpStCoeffInQ30, prefiltdata->HPstates_fix); + + + /* First Channel */ + for (k=0;k<FRAMESAMPLES/2;k++) { + tempin_ch1[QLOOKAHEAD + k] = pin[1+WEBRTC_SPL_MUL_16_16(2, k)]; + } + for (k=0;k<QLOOKAHEAD;k++) { + tempin_ch1[k]=prefiltdata->INLABUF1_fix[k]; + prefiltdata->INLABUF1_fix[k]=pin[FRAMESAMPLES+1-WEBRTC_SPL_MUL_16_16(2, QLOOKAHEAD)+WEBRTC_SPL_MUL_16_16(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;k<FRAMESAMPLES/2;k++) { + tempin_ch2[QLOOKAHEAD+k] = pin[WEBRTC_SPL_MUL_16_16(2, k)]; + } + for (k=0;k<QLOOKAHEAD;k++) { + tempin_ch2[k]=prefiltdata->INLABUF2_fix[k]; + prefiltdata->INLABUF2_fix[k]=pin[FRAMESAMPLES-WEBRTC_SPL_MUL_16_16(2, QLOOKAHEAD)+WEBRTC_SPL_MUL_16_16(2, k)]; + } + + + /*obtain polyphase components by forward all-pass filtering through each channel */ + /* The all pass filtering automatically updates the filter states which are exported in the + prefiltdata structure */ + AllpassFilter2FixDec16(tempin_ch1,WebRtcIsacfix_kUpperApFactorsQ15, FRAMESAMPLES/2 , NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTAT1_fix); + AllpassFilter2FixDec16(tempin_ch2,WebRtcIsacfix_kLowerApFactorsQ15, FRAMESAMPLES/2 , NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTAT2_fix); + + for (k=0;k<WEBRTC_SPL_MUL_16_16(2, (QORDER-1));k++) + tmpState[k] = prefiltdata->INSTAT1_fix[k]; + AllpassFilter2FixDec16(tempin_ch1 + FRAMESAMPLES/2,WebRtcIsacfix_kUpperApFactorsQ15, QLOOKAHEAD , NUMBEROFCHANNELAPSECTIONS, tmpState); + for (k=0;k<WEBRTC_SPL_MUL_16_16(2, (QORDER-1));k++) + tmpState[k] = prefiltdata->INSTAT2_fix[k]; + AllpassFilter2FixDec16(tempin_ch2 + FRAMESAMPLES/2,WebRtcIsacfix_kLowerApFactorsQ15, QLOOKAHEAD , NUMBEROFCHANNELAPSECTIONS, tmpState); + + + /* Now Construct low-pass and high-pass signals as combinations of polyphase components */ + for (k=0; k<FRAMESAMPLES/2 + QLOOKAHEAD; k++) { + WebRtc_Word32 tmp1, tmp2, tmp3; + tmp1 = (WebRtc_Word32)tempin_ch1[k]; // Q0 -> Q0 + tmp2 = (WebRtc_Word32)tempin_ch2[k]; // Q0 -> Q0 + tmp3 = (WebRtc_Word32)WEBRTC_SPL_RSHIFT_W32((tmp1 + tmp2), 1);/* low pass signal*/ + LP16[k] = (WebRtc_Word16)WebRtcSpl_SatW32ToW16(tmp3); /*low pass */ + tmp3 = (WebRtc_Word32)WEBRTC_SPL_RSHIFT_W32((tmp1 - tmp2), 1);/* high pass signal*/ + HP16[k] = (WebRtc_Word16)WebRtcSpl_SatW32ToW16(tmp3); /*high pass */ + } + +}/*end of WebRtcIsacfix_SplitAndFilter */ + + +#ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED + +/* Without lookahead */ +void WebRtcIsacfix_SplitAndFilter2(WebRtc_Word16 *pin, + WebRtc_Word16 *LP16, + WebRtc_Word16 *HP16, + PreFiltBankstr *prefiltdata) +{ + /* Function WebRtcIsacfix_SplitAndFilter2 */ + /* This function creates low-pass and high-pass decimated versions of part of + the input signal. */ + + int k; + + WebRtc_Word16 tempin_ch1[FRAMESAMPLES/2]; + WebRtc_Word16 tempin_ch2[FRAMESAMPLES/2]; + + + /* High pass filter */ + WebRtcIsacfix_HighpassFilterFixDec32(pin, FRAMESAMPLES, WebRtcIsacfix_kHpStCoeffInQ30, prefiltdata->HPstates_fix); + + + /* First Channel */ + for (k=0;k<FRAMESAMPLES/2;k++) { + tempin_ch1[k] = pin[1+WEBRTC_SPL_MUL_16_16(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;k<FRAMESAMPLES/2;k++) { + tempin_ch2[k] = pin[WEBRTC_SPL_MUL_16_16(2, k)]; + } + + + /*obtain polyphase components by forward all-pass filtering through each channel */ + /* The all pass filtering automatically updates the filter states which are exported in the + prefiltdata structure */ + AllpassFilter2FixDec16(tempin_ch1,WebRtcIsacfix_kUpperApFactorsQ15, FRAMESAMPLES/2 , NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTAT1_fix); + AllpassFilter2FixDec16(tempin_ch2,WebRtcIsacfix_kLowerApFactorsQ15, FRAMESAMPLES/2 , NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTAT2_fix); + + + /* Now Construct low-pass and high-pass signals as combinations of polyphase components */ + for (k=0; k<FRAMESAMPLES/2; k++) { + WebRtc_Word32 tmp1, tmp2, tmp3; + tmp1 = (WebRtc_Word32)tempin_ch1[k]; // Q0 -> Q0 + tmp2 = (WebRtc_Word32)tempin_ch2[k]; // Q0 -> Q0 + tmp3 = (WebRtc_Word32)WEBRTC_SPL_RSHIFT_W32((tmp1 + tmp2), 1);/* low pass signal*/ + LP16[k] = (WebRtc_Word16)WebRtcSpl_SatW32ToW16(tmp3); /*low pass */ + tmp3 = (WebRtc_Word32)WEBRTC_SPL_RSHIFT_W32((tmp1 - tmp2), 1);/* high pass signal*/ + HP16[k] = (WebRtc_Word16)WebRtcSpl_SatW32ToW16(tmp3); /*high pass */ + } + +}/*end of WebRtcIsacfix_SplitAndFilter */ + +#endif + + + +////////////////////////////////////////////////////////// +////////// Combining +/* Function WebRtcIsacfix_FilterAndCombine */ +/* This is a decoder function that takes the decimated + length FRAMESAMPLES/2 input low-pass and + high-pass signals and creates a reconstructed fullband + output signal of length FRAMESAMPLES. WebRtcIsacfix_FilterAndCombine + is the sibling function of WebRtcIsacfix_SplitAndFilter */ +/* INPUTS: + inLP: a length FRAMESAMPLES/2 array of input low-pass + samples. + inHP: a length FRAMESAMPLES/2 array of input high-pass + samples. + postfiltdata: input data structure containing the filterbank + states from the previous decoding iteration. + OUTPUTS: + Out: a length FRAMESAMPLES array of output reconstructed + samples (fullband) based on the input low-pass and + high-pass signals. + postfiltdata: the input data structure containing the filterbank + states is updated for the next decoding iteration */ +void WebRtcIsacfix_FilterAndCombine1(WebRtc_Word16 *tempin_ch1, + WebRtc_Word16 *tempin_ch2, + WebRtc_Word16 *out16, + PostFiltBankstr *postfiltdata) +{ + int k; + WebRtc_Word16 in[FRAMESAMPLES]; + + /* all-pass filter the new upper channel signal. HOWEVER, use the all-pass filter factors + that were used as a lower channel at the encoding side. So at the decoder, the + corresponding all-pass filter factors for each channel are swapped.*/ + + AllpassFilter2FixDec16(tempin_ch1, WebRtcIsacfix_kLowerApFactorsQ15, FRAMESAMPLES/2, NUMBEROFCHANNELAPSECTIONS,postfiltdata->STATE_0_UPPER_fix); + + /* 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 (kUpperApFactors) are used to filter this new lower channel signal */ + + AllpassFilter2FixDec16(tempin_ch2, WebRtcIsacfix_kUpperApFactorsQ15, FRAMESAMPLES/2, NUMBEROFCHANNELAPSECTIONS,postfiltdata->STATE_0_LOWER_fix); + + /* Merge outputs to form the full length output signal.*/ + for (k=0;k<FRAMESAMPLES/2;k++) { + in[WEBRTC_SPL_MUL_16_16(2, k)]=tempin_ch2[k]; + in[WEBRTC_SPL_MUL_16_16(2, k)+1]=tempin_ch1[k]; + } + + /* High pass filter */ + WebRtcIsacfix_HighpassFilterFixDec32(in, FRAMESAMPLES, WebRtcIsacfix_kHPStCoeffOut1Q30, postfiltdata->HPstates1_fix); + WebRtcIsacfix_HighpassFilterFixDec32(in, FRAMESAMPLES, WebRtcIsacfix_kHPStCoeffOut2Q30, postfiltdata->HPstates2_fix); + + for (k=0;k<FRAMESAMPLES;k++) { + out16[k] = in[k]; + } +} + + +#ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED +/* Function WebRtcIsacfix_FilterAndCombine */ +/* This is a decoder function that takes the decimated + length len/2 input low-pass and + high-pass signals and creates a reconstructed fullband + output signal of length len. WebRtcIsacfix_FilterAndCombine + is the sibling function of WebRtcIsacfix_SplitAndFilter */ +/* INPUTS: + inLP: a length len/2 array of input low-pass + samples. + inHP: a length len/2 array of input high-pass + samples. + postfiltdata: input data structure containing the filterbank + states from the previous decoding iteration. + OUTPUTS: + Out: a length len array of output reconstructed + samples (fullband) based on the input low-pass and + high-pass signals. + postfiltdata: the input data structure containing the filterbank + states is updated for the next decoding iteration */ +void WebRtcIsacfix_FilterAndCombine2(WebRtc_Word16 *tempin_ch1, + WebRtc_Word16 *tempin_ch2, + WebRtc_Word16 *out16, + PostFiltBankstr *postfiltdata, + WebRtc_Word16 len) +{ + int k; + WebRtc_Word16 in[FRAMESAMPLES]; + + /* all-pass filter the new upper channel signal. HOWEVER, use the all-pass filter factors + that were used as a lower channel at the encoding side. So at the decoder, the + corresponding all-pass filter factors for each channel are swapped.*/ + + AllpassFilter2FixDec16(tempin_ch1, WebRtcIsacfix_kLowerApFactorsQ15,(WebRtc_Word16) (len/2), NUMBEROFCHANNELAPSECTIONS,postfiltdata->STATE_0_UPPER_fix); + + /* 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 (kUpperApFactors) are used to filter this new lower channel signal */ + + AllpassFilter2FixDec16(tempin_ch2, WebRtcIsacfix_kUpperApFactorsQ15, (WebRtc_Word16) (len/2), NUMBEROFCHANNELAPSECTIONS,postfiltdata->STATE_0_LOWER_fix); + + /* Merge outputs to form the full length output signal.*/ + for (k=0;k<len/2;k++) { + in[WEBRTC_SPL_MUL_16_16(2, k)]=tempin_ch2[k]; + in[WEBRTC_SPL_MUL_16_16(2, k)+1]=tempin_ch1[k]; + } + + /* High pass filter */ + WebRtcIsacfix_HighpassFilterFixDec32(in, len, WebRtcIsacfix_kHPStCoeffOut1Q30, postfiltdata->HPstates1_fix); + WebRtcIsacfix_HighpassFilterFixDec32(in, len, WebRtcIsacfix_kHPStCoeffOut2Q30, postfiltdata->HPstates2_fix); + + for (k=0;k<len;k++) { + out16[k] = in[k]; + } +} + +#endif diff --git a/src/modules/audio_coding/codecs/isac/fix/source/filters.c b/src/modules/audio_coding/codecs/isac/fix/source/filters.c new file mode 100644 index 0000000000..6ee047753c --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/filters.c @@ -0,0 +1,122 @@ +/* + * 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. + */ + +/* + * filters.c + * + * This file contains function WebRtcIsacfix_AutocorrC, + * AllpassFilterForDec32, and WebRtcIsacfix_DecimateAllpass32 + * + */ + +#include <string.h> + +#include "pitch_estimator.h" +#include "lpc_masking_model.h" +#include "codec.h" + +// Autocorrelation function in fixed point. +// NOTE! Different from SPLIB-version in how it scales the signal. +int WebRtcIsacfix_AutocorrC(WebRtc_Word32* __restrict r, + const WebRtc_Word16* __restrict x, + WebRtc_Word16 N, + WebRtc_Word16 order, + WebRtc_Word16* __restrict scale) { + int i = 0; + int j = 0; + int16_t scaling = 0; + int32_t sum = 0; + uint32_t temp = 0; + int64_t prod = 0; + + // Calculate r[0]. + for (i = 0; i < N; i++) { + prod += WEBRTC_SPL_MUL_16_16(x[i], x[i]); + } + + // Calculate scaling (the value of shifting). + temp = (uint32_t)(prod >> 31); + if(temp == 0) { + scaling = 0; + } else { + scaling = 32 - WebRtcSpl_NormU32(temp); + } + r[0] = (int32_t)(prod >> scaling); + + // Perform the actual correlation calculation. + for (i = 1; i < order + 1; i++) { + prod = 0; + for (j = 0; j < N - i; j++) { + prod += WEBRTC_SPL_MUL_16_16(x[j], x[i + j]); + } + sum = (int32_t)(prod >> scaling); + r[i] = sum; + } + + *scale = scaling; + + return(order + 1); +} + +static const WebRtc_Word32 kApUpperQ15[ALLPASSSECTIONS] = { 1137, 12537 }; +static const WebRtc_Word32 kApLowerQ15[ALLPASSSECTIONS] = { 5059, 24379 }; + + +static void AllpassFilterForDec32(WebRtc_Word16 *InOut16, //Q0 + const WebRtc_Word32 *APSectionFactors, //Q15 + WebRtc_Word16 lengthInOut, + WebRtc_Word32 *FilterState) //Q16 +{ + int n, j; + WebRtc_Word32 a, b; + + for (j=0; j<ALLPASSSECTIONS; j++) { + for (n=0;n<lengthInOut;n+=2){ + a = WEBRTC_SPL_MUL_16_32_RSFT16(InOut16[n], APSectionFactors[j]); //Q0*Q31=Q31 shifted 16 gives Q15 + a = WEBRTC_SPL_LSHIFT_W32(a, 1); // Q15 -> Q16 + b = WEBRTC_SPL_ADD_SAT_W32(a, FilterState[j]); //Q16+Q16=Q16 + a = WEBRTC_SPL_MUL_16_32_RSFT16( + (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(b, 16), + -APSectionFactors[j]); //Q0*Q31=Q31 shifted 16 gives Q15 + FilterState[j] = WEBRTC_SPL_ADD_SAT_W32( + WEBRTC_SPL_LSHIFT_W32(a,1), + WEBRTC_SPL_LSHIFT_W32((WebRtc_UWord32)InOut16[n], 16)); // Q15<<1 + Q0<<16 = Q16 + Q16 = Q16 + InOut16[n] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(b, 16); //Save as Q0 + } + } +} + + + + +void WebRtcIsacfix_DecimateAllpass32(const WebRtc_Word16 *in, + WebRtc_Word32 *state_in, /* array of size: 2*ALLPASSSECTIONS+1 */ + WebRtc_Word16 N, /* number of input samples */ + WebRtc_Word16 *out) /* array of size N/2 */ +{ + int n; + WebRtc_Word16 data_vec[PITCH_FRAME_LEN]; + + /* copy input */ + memcpy(data_vec+1, in, WEBRTC_SPL_MUL_16_16(sizeof(WebRtc_Word16), (N-1))); + + + data_vec[0] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(state_in[WEBRTC_SPL_MUL_16_16(2, ALLPASSSECTIONS)],16); //the z^(-1) state + state_in[WEBRTC_SPL_MUL_16_16(2, ALLPASSSECTIONS)] = WEBRTC_SPL_LSHIFT_W32((WebRtc_UWord32)in[N-1],16); + + + + AllpassFilterForDec32(data_vec+1, kApUpperQ15, N, state_in); + AllpassFilterForDec32(data_vec, kApLowerQ15, N, state_in+ALLPASSSECTIONS); + + for (n=0;n<N/2;n++) { + out[n]=WEBRTC_SPL_ADD_SAT_W16(data_vec[WEBRTC_SPL_MUL_16_16(2, n)], data_vec[WEBRTC_SPL_MUL_16_16(2, n)+1]); + } +} diff --git a/src/modules/audio_coding/codecs/isac/fix/source/filters_neon.c b/src/modules/audio_coding/codecs/isac/fix/source/filters_neon.c new file mode 100644 index 0000000000..93143fe432 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/filters_neon.c @@ -0,0 +1,167 @@ +/* + * 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. + */ + +/* + * filters_neon.c + * + * This file contains function WebRtcIsacfix_AutocorrNeon, optimized for + * ARM Neon platform. + * + */ + +#include <arm_neon.h> +#include <assert.h> + +#include "codec.h" + +// Autocorrelation function in fixed point. +// NOTE! Different from SPLIB-version in how it scales the signal. +int WebRtcIsacfix_AutocorrNeon( + WebRtc_Word32* __restrict r, + const WebRtc_Word16* __restrict x, + WebRtc_Word16 N, + WebRtc_Word16 order, + WebRtc_Word16* __restrict scale) { + + // The 1st for loop assumed N % 4 == 0. + assert(N % 4 == 0); + + int i = 0; + int zeros_low = 0; + int zeros_high = 0; + int16_t scaling = 0; + int32_t sum = 0; + + // Step 1, calculate r[0] and how much scaling is needed. + + int16x4_t reg16x4; + int64x1_t reg64x1a; + int64x1_t reg64x1b; + int32x4_t reg32x4; + int64x2_t reg64x2 = vdupq_n_s64(0); // zeros + + // Loop over the samples and do: + // sum += WEBRTC_SPL_MUL_16_16(x[i], x[i]); + for (i = 0; i < N; i += 4) { + reg16x4 = vld1_s16(&x[i]); + reg32x4 = vmull_s16(reg16x4, reg16x4); + reg64x2 = vpadalq_s32(reg64x2, reg32x4); + } + reg64x1a = vget_low_s64(reg64x2); + reg64x1b = vget_high_s64(reg64x2); + reg64x1a = vadd_s64(reg64x1a, reg64x1b); + + // Calculate the value of shifting (scaling). + __asm__ __volatile__( + "vmov %[z_l], %[z_h], %P[reg]\n\t" + "clz %[z_l], %[z_l]\n\t" + "clz %[z_h], %[z_h]\n\t" + :[z_l]"+r"(zeros_low), + [z_h]"+r"(zeros_high) + :[reg]"w"(reg64x1a) + ); + if (zeros_high != 32) { + scaling = (32 - zeros_high + 1); + } else if (zeros_low == 0) { + scaling = 1; + } + reg64x1b = -scaling; + reg64x1a = vshl_s64(reg64x1a, reg64x1b); + + // Record the result. + r[0] = (int32_t)vget_lane_s64(reg64x1a, 0); + + + // Step 2, perform the actual correlation calculation. + + /* Original C code (for the rest of the function): + for (i = 1; i < order + 1; i++) { + prod = 0; + for (j = 0; j < N - i; j++) { + prod += WEBRTC_SPL_MUL_16_16(x[j], x[i + j]); + } + sum = (int32_t)(prod >> scaling); + r[i] = sum; + } + */ + + for (i = 1; i < order + 1; i++) { + int32_t prod_lower = 0; + int32_t prod_upper = 0; + const int16_t* ptr0 = &x[0]; + const int16_t* ptr1 = &x[i]; + int32_t tmp = 0; + + // Initialize the sum (q9) to zero. + __asm__ __volatile__("vmov.i32 q9, #0\n\t":::"q9"); + + // Calculate the major block of the samples (a multiple of 8). + for (; ptr0 < &x[N - i - 7];) { + __asm__ __volatile__( + "vld1.16 {d20, d21}, [%[ptr0]]!\n\t" + "vld1.16 {d22, d23}, [%[ptr1]]!\n\t" + "vmull.s16 q12, d20, d22\n\t" + "vmull.s16 q13, d21, d23\n\t" + "vpadal.s32 q9, q12\n\t" + "vpadal.s32 q9, q13\n\t" + + // Specify constraints. + :[ptr0]"+r"(ptr0), + [ptr1]"+r"(ptr1) + : + :"d18", "d19", "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27" + ); + } + + // Calculate the rest of the samples. + for (; ptr0 < &x[N - i]; ptr0++, ptr1++) { + __asm__ __volatile__( + "smulbb %[tmp], %[ptr0], %[ptr1]\n\t" + "adds %[prod_lower], %[prod_lower], %[tmp]\n\t" + "adc %[prod_upper], %[prod_upper], %[tmp], asr #31\n\t" + + // Specify constraints. + :[prod_lower]"+r"(prod_lower), + [prod_upper]"+r"(prod_upper), + [tmp]"+r"(tmp) + :[ptr0]"r"(*ptr0), + [ptr1]"r"(*ptr1) + ); + } + + // Sum the results up, and do shift. + __asm__ __volatile__( + "vadd.i64 d18, d19\n\t" + "vmov.32 d17[0], %[prod_lower]\n\t" + "vmov.32 d17[1], %[prod_upper]\n\t" + "vadd.i64 d17, d18\n\t" + "mov %[tmp], %[scaling], asr #31\n\t" + "vmov.32 d16, %[scaling], %[tmp]\n\t" + "vshl.s64 d17, d16\n\t" + "vmov.32 %[sum], d17[0]\n\t" + + // Specify constraints. + :[sum]"=r"(sum), + [tmp]"+r"(tmp) + :[prod_upper]"r"(prod_upper), + [prod_lower]"r"(prod_lower), + [scaling]"r"(-scaling) + :"d16", "d17", "d18", "d19" + ); + + // Record the result. + r[i] = sum; + } + + // Record the result. + *scale = scaling; + + return(order + 1); +} diff --git a/src/modules/audio_coding/codecs/isac/fix/source/initialize.c b/src/modules/audio_coding/codecs/isac/fix/source/initialize.c new file mode 100644 index 0000000000..4d11af53a7 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/initialize.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. + */ + +/* + * initialize.c + * + * Internal initfunctions + * + */ + +#include "codec.h" +#include "structs.h" +#include "pitch_estimator.h" + + +void WebRtcIsacfix_InitMaskingEnc(MaskFiltstr_enc *maskdata) { + + int k; + + for (k = 0; k < WINLEN; k++) { + maskdata->DataBufferLoQ0[k] = (WebRtc_Word16) 0; + maskdata->DataBufferHiQ0[k] = (WebRtc_Word16) 0; + } + for (k = 0; k < ORDERLO+1; k++) { + maskdata->CorrBufLoQQ[k] = (WebRtc_Word32) 0; + maskdata->CorrBufLoQdom[k] = 0; + + maskdata->PreStateLoGQ15[k] = 0; + + } + for (k = 0; k < ORDERHI+1; k++) { + maskdata->CorrBufHiQQ[k] = (WebRtc_Word32) 0; + maskdata->CorrBufHiQdom[k] = 0; + maskdata->PreStateHiGQ15[k] = 0; + } + + maskdata->OldEnergy = 10; + + return; +} + +void WebRtcIsacfix_InitMaskingDec(MaskFiltstr_dec *maskdata) { + + int k; + + for (k = 0; k < ORDERLO+1; k++) + { + maskdata->PostStateLoGQ0[k] = 0; + } + for (k = 0; k < ORDERHI+1; k++) + { + maskdata->PostStateHiGQ0[k] = 0; + } + + maskdata->OldEnergy = 10; + + return; +} + + + + + + + +void WebRtcIsacfix_InitPreFilterbank(PreFiltBankstr *prefiltdata) +{ + int k; + + for (k = 0; k < QLOOKAHEAD; k++) { + prefiltdata->INLABUF1_fix[k] = 0; + prefiltdata->INLABUF2_fix[k] = 0; + } + for (k = 0; k < WEBRTC_SPL_MUL_16_16(2,(QORDER-1)); k++) { + + prefiltdata->INSTAT1_fix[k] = 0; + prefiltdata->INSTAT2_fix[k] = 0; + } + + /* High pass filter states */ + prefiltdata->HPstates_fix[0] = 0; + prefiltdata->HPstates_fix[1] = 0; + + return; +} + +void WebRtcIsacfix_InitPostFilterbank(PostFiltBankstr *postfiltdata) +{ + int k; + + for (k = 0; k < WEBRTC_SPL_MUL_16_16(2, POSTQORDER); k++) { + + postfiltdata->STATE_0_LOWER_fix[k] = 0; + postfiltdata->STATE_0_UPPER_fix[k] = 0; + } + + /* High pass filter states */ + + postfiltdata->HPstates1_fix[0] = 0; + postfiltdata->HPstates1_fix[1] = 0; + + postfiltdata->HPstates2_fix[0] = 0; + postfiltdata->HPstates2_fix[1] = 0; + + return; +} + + +void WebRtcIsacfix_InitPitchFilter(PitchFiltstr *pitchfiltdata) +{ + int k; + + for (k = 0; k < PITCH_BUFFSIZE; k++) + pitchfiltdata->ubufQQ[k] = 0; + for (k = 0; k < (PITCH_DAMPORDER); k++) + pitchfiltdata->ystateQQ[k] = 0; + + pitchfiltdata->oldlagQ7 = 6400; /* 50.0 in Q7 */ + pitchfiltdata->oldgainQ12 = 0; +} + +void WebRtcIsacfix_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_buffer16[k] = 0; + } + for (k = 0; k < WEBRTC_SPL_MUL_16_16(2, ALLPASSSECTIONS)+1; k++) { + State->decimator_state32[k] = 0; + } + + for (k = 0; k < QLOOKAHEAD; k++) + State->inbuf[k] = 0; + + WebRtcIsacfix_InitPitchFilter(&(State->PFstr_wght)); + + WebRtcIsacfix_InitPitchFilter(&(State->PFstr)); +} + + +void WebRtcIsacfix_InitPlc( PLCstr *State ) +{ + State->decayCoeffPriodic = WEBRTC_SPL_WORD16_MAX; + State->decayCoeffNoise = WEBRTC_SPL_WORD16_MAX; + + State->used = PLC_WAS_USED; + + WebRtcSpl_ZerosArrayW16(State->overlapLP, RECOVERY_OVERLAP); + WebRtcSpl_ZerosArrayW16(State->lofilt_coefQ15, ORDERLO); + WebRtcSpl_ZerosArrayW16(State->hifilt_coefQ15, ORDERHI ); + + State->AvgPitchGain_Q12 = 0; + State->lastPitchGain_Q12 = 0; + State->lastPitchLag_Q7 = 0; + State->gain_lo_hiQ17[0]=State->gain_lo_hiQ17[1] = 0; + WebRtcSpl_ZerosArrayW16(State->prevPitchInvIn, FRAMESAMPLES/2); + WebRtcSpl_ZerosArrayW16(State->prevPitchInvOut, PITCH_MAX_LAG + 10 ); + WebRtcSpl_ZerosArrayW32(State->prevHP, PITCH_MAX_LAG + 10 ); + State->pitchCycles = 0; + State->A = 0; + State->B = 0; + State->pitchIndex = 0; + State->stretchLag = 240; + State->seed = 4447; + + +} diff --git a/src/modules/audio_coding/codecs/isac/fix/source/isacfix.c b/src/modules/audio_coding/codecs/isac/fix/source/isacfix.c new file mode 100644 index 0000000000..8786b121b0 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/isacfix.c @@ -0,0 +1,1551 @@ +/* + * 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. + */ + +/* + * isacfix.c + * + * This C file contains the functions for the ISAC API + * + */ + +#include "modules/audio_coding/codecs/isac/fix/interface/isacfix.h" + +#include <stdlib.h> + +#include "modules/audio_coding/codecs/isac/fix/source/bandwidth_estimator.h" +#include "modules/audio_coding/codecs/isac/fix/source/codec.h" +#include "modules/audio_coding/codecs/isac/fix/source/entropy_coding.h" +#include "modules/audio_coding/codecs/isac/fix/source/lpc_masking_model.h" +#include "modules/audio_coding/codecs/isac/fix/source/structs.h" +#include "system_wrappers/interface/cpu_features_wrapper.h" + + +/************************************************************************** + * WebRtcIsacfix_AssignSize(...) + * + * Functions used when malloc is not allowed + * Returns number of bytes needed to allocate for iSAC struct. + * + */ + +WebRtc_Word16 WebRtcIsacfix_AssignSize(int *sizeinbytes) { + *sizeinbytes=sizeof(ISACFIX_SubStruct)*2/sizeof(WebRtc_Word16); + return(0); +} + +/*************************************************************************** + * WebRtcIsacfix_Assign(...) + * + * Functions used when malloc is not allowed + * Place struct at given address + * + * If successful, Return 0, else Return -1 + */ + +WebRtc_Word16 WebRtcIsacfix_Assign(ISACFIX_MainStruct **inst, void *ISACFIX_inst_Addr) { + if (ISACFIX_inst_Addr!=NULL) { + *inst = (ISACFIX_MainStruct*)ISACFIX_inst_Addr; + (*(ISACFIX_SubStruct**)inst)->errorcode = 0; + (*(ISACFIX_SubStruct**)inst)->initflag = 0; + (*(ISACFIX_SubStruct**)inst)->ISACenc_obj.SaveEnc_ptr = NULL; + return(0); + } else { + return(-1); + } +} + + +#ifndef ISACFIX_NO_DYNAMIC_MEM + +/**************************************************************************** + * WebRtcIsacfix_Create(...) + * + * This function creates a 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 WebRtcIsacfix_Create(ISACFIX_MainStruct **ISAC_main_inst) +{ + ISACFIX_SubStruct *tempo; + tempo = malloc(1 * sizeof(ISACFIX_SubStruct)); + *ISAC_main_inst = (ISACFIX_MainStruct *)tempo; + if (*ISAC_main_inst!=NULL) { + (*(ISACFIX_SubStruct**)ISAC_main_inst)->errorcode = 0; + (*(ISACFIX_SubStruct**)ISAC_main_inst)->initflag = 0; + (*(ISACFIX_SubStruct**)ISAC_main_inst)->ISACenc_obj.SaveEnc_ptr = NULL; + return(0); + } else { + return(-1); + } +} + + +/**************************************************************************** + * WebRtcIsacfix_CreateInternal(...) + * + * This function creates the memory that is used to store data in the encoder + * + * Input: + * - *ISAC_main_inst : a pointer to the coder instance. + * + * Return value : 0 - Ok + * -1 - Error + */ + +WebRtc_Word16 WebRtcIsacfix_CreateInternal(ISACFIX_MainStruct *ISAC_main_inst) +{ + ISACFIX_SubStruct *ISAC_inst; + + /* typecast pointer to real structure */ + ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst; + + /* Allocate memory for storing encoder data */ + ISAC_inst->ISACenc_obj.SaveEnc_ptr = malloc(1 * sizeof(ISAC_SaveEncData_t)); + + if (ISAC_inst->ISACenc_obj.SaveEnc_ptr!=NULL) { + return(0); + } else { + return(-1); + } +} + + +#endif + + + +/**************************************************************************** + * WebRtcIsacfix_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 WebRtcIsacfix_Free(ISACFIX_MainStruct *ISAC_main_inst) +{ + free(ISAC_main_inst); + return(0); +} + +/**************************************************************************** + * WebRtcIsacfix_FreeInternal(...) + * + * This function frees the internal memory for storing encoder data. + * + * Input: + * - ISAC_main_inst : a ISAC instance. + * + * Return value : 0 - Ok + * -1 - Error + */ + +WebRtc_Word16 WebRtcIsacfix_FreeInternal(ISACFIX_MainStruct *ISAC_main_inst) +{ + ISACFIX_SubStruct *ISAC_inst; + + /* typecast pointer to real structure */ + ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst; + + /* Release memory */ + free(ISAC_inst->ISACenc_obj.SaveEnc_ptr); + + return(0); +} + +/**************************************************************************** + * WebRtcAecm_InitNeon(...) + * + * This function initializes function pointers for ARM Neon platform. + */ + +#if (defined WEBRTC_DETECT_ARM_NEON || defined WEBRTC_ARCH_ARM_NEON) +static void WebRtcIsacfix_InitNeon(void) { + WebRtcIsacfix_AutocorrFix = WebRtcIsacfix_AutocorrNeon; + WebRtcIsacfix_FilterMaLoopFix = WebRtcIsacfix_FilterMaLoopNeon; + WebRtcIsacfix_CalculateResidualEnergy = + WebRtcIsacfix_CalculateResidualEnergyNeon; +} +#endif + +/**************************************************************************** + * WebRtcIsacfix_EncoderInit(...) + * + * 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. + * 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 WebRtcIsacfix_EncoderInit(ISACFIX_MainStruct *ISAC_main_inst, + WebRtc_Word16 CodingMode) +{ + int k; + WebRtc_Word16 statusInit; + ISACFIX_SubStruct *ISAC_inst; + + statusInit = 0; + /* typecast pointer to rela structure */ + ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst; + + /* flag encoder init */ + ISAC_inst->initflag |= 2; + + if (CodingMode == 0) + /* Adaptive mode */ + ISAC_inst->ISACenc_obj.new_framelength = INITIAL_FRAMESAMPLES; + else if (CodingMode == 1) + /* Instantaneous mode */ + ISAC_inst->ISACenc_obj.new_framelength = 480; /* default for I-mode */ + else { + ISAC_inst->errorcode = ISAC_DISALLOWED_CODING_MODE; + statusInit = -1; + } + + ISAC_inst->CodingMode = CodingMode; + + WebRtcIsacfix_InitMaskingEnc(&ISAC_inst->ISACenc_obj.maskfiltstr_obj); + WebRtcIsacfix_InitPreFilterbank(&ISAC_inst->ISACenc_obj.prefiltbankstr_obj); + WebRtcIsacfix_InitPitchFilter(&ISAC_inst->ISACenc_obj.pitchfiltstr_obj); + WebRtcIsacfix_InitPitchAnalysis(&ISAC_inst->ISACenc_obj.pitchanalysisstr_obj); + + + WebRtcIsacfix_InitBandwidthEstimator(&ISAC_inst->bwestimator_obj); + WebRtcIsacfix_InitRateModel(&ISAC_inst->ISACenc_obj.rate_data_obj); + + + ISAC_inst->ISACenc_obj.buffer_index = 0; + ISAC_inst->ISACenc_obj.frame_nb = 0; + ISAC_inst->ISACenc_obj.BottleNeck = 32000; /* default for I-mode */ + ISAC_inst->ISACenc_obj.MaxDelay = 10; /* default for I-mode */ + ISAC_inst->ISACenc_obj.current_framesamples = 0; + ISAC_inst->ISACenc_obj.s2nr = 0; + ISAC_inst->ISACenc_obj.MaxBits = 0; + ISAC_inst->ISACenc_obj.bitstr_seed = 4447; + ISAC_inst->ISACenc_obj.payloadLimitBytes30 = STREAM_MAXW16_30MS << 1; + ISAC_inst->ISACenc_obj.payloadLimitBytes60 = STREAM_MAXW16_60MS << 1; + ISAC_inst->ISACenc_obj.maxPayloadBytes = STREAM_MAXW16_60MS << 1; + ISAC_inst->ISACenc_obj.maxRateInBytes = STREAM_MAXW16_30MS << 1; + ISAC_inst->ISACenc_obj.enforceFrameSize = 0; + + /* Init the bistream data area to zero */ + for (k=0; k<STREAM_MAXW16_60MS; k++){ + ISAC_inst->ISACenc_obj.bitstr_obj.stream[k] = 0; + } + +#ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED + WebRtcIsacfix_InitPostFilterbank(&ISAC_inst->ISACenc_obj.interpolatorstr_obj); +#endif + + // Initiaze function pointers. + WebRtcIsacfix_AutocorrFix = WebRtcIsacfix_AutocorrC; + WebRtcIsacfix_FilterMaLoopFix = WebRtcIsacfix_FilterMaLoopC; + WebRtcIsacfix_CalculateResidualEnergy = + WebRtcIsacfix_CalculateResidualEnergyC; + +#ifdef WEBRTC_DETECT_ARM_NEON + if ((WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON) != 0) { + WebRtcIsacfix_InitNeon(); + } +#elif defined(WEBRTC_ARCH_ARM_NEON) + WebRtcIsacfix_InitNeon(); +#endif + + return statusInit; +} + +/**************************************************************************** + * WebRtcIsacfix_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 WebRtcIsacfix_Encode(ISACFIX_MainStruct *ISAC_main_inst, + const WebRtc_Word16 *speechIn, + WebRtc_Word16 *encoded) +{ + ISACFIX_SubStruct *ISAC_inst; + WebRtc_Word16 stream_len; +#ifndef WEBRTC_BIG_ENDIAN + int k; +#endif + + /* typecast pointer to rela structure */ + ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst; + + + /* check if encoder initiated */ + if ((ISAC_inst->initflag & 2) != 2) { + ISAC_inst->errorcode = ISAC_ENCODER_NOT_INITIATED; + return (-1); + } + + stream_len = WebRtcIsacfix_EncodeImpl((WebRtc_Word16*)speechIn, + &ISAC_inst->ISACenc_obj, + &ISAC_inst->bwestimator_obj, + ISAC_inst->CodingMode); + if (stream_len<0) { + ISAC_inst->errorcode = - stream_len; + return -1; + } + + + /* convert from bytes to WebRtc_Word16 */ +#ifndef WEBRTC_BIG_ENDIAN + for (k=0;k<(stream_len+1)>>1;k++) { + encoded[k] = (WebRtc_Word16)( ( (WebRtc_UWord16)(ISAC_inst->ISACenc_obj.bitstr_obj).stream[k] >> 8 ) + | (((ISAC_inst->ISACenc_obj.bitstr_obj).stream[k] & 0x00FF) << 8)); + } + +#else + WEBRTC_SPL_MEMCPY_W16(encoded, (ISAC_inst->ISACenc_obj.bitstr_obj).stream, (stream_len + 1)>>1); +#endif + + + + return stream_len; + +} + + + + +/**************************************************************************** + * WebRtcIsacfix_EncodeNb(...) + * + * This function encodes 10ms narrow band (8 kHz sampling) frame(s) and inserts + * it into a package. Input speech length has to be 80 samples (10ms). The encoder + * interpolates into wide-band (16 kHz sampling) buffers those + * 10ms frames until it reaches the chosen Framesize (480 or 960 wide-band samples + * corresponding to 30 or 60 ms frames), and then proceeds to the encoding. + * + * The function is enabled if WEBRTC_ISAC_FIX_NB_CALLS_ENABLED is defined + * + * 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 + */ +#ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED +WebRtc_Word16 WebRtcIsacfix_EncodeNb(ISACFIX_MainStruct *ISAC_main_inst, + const WebRtc_Word16 *speechIn, + WebRtc_Word16 *encoded) +{ + ISACFIX_SubStruct *ISAC_inst; + WebRtc_Word16 stream_len; + WebRtc_Word16 speechInWB[FRAMESAMPLES_10ms]; + WebRtc_Word16 Vector_Word16_1[FRAMESAMPLES_10ms/2]; + WebRtc_Word16 Vector_Word16_2[FRAMESAMPLES_10ms/2]; + + int k; + + + /* typecast pointer to rela structure */ + ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst; + + + /* check if encoder initiated */ + if ((ISAC_inst->initflag & 2) != 2) { + ISAC_inst->errorcode = ISAC_ENCODER_NOT_INITIATED; + return (-1); + } + + + /* Oversample to WB */ + + /* Form polyphase signals, and compensate for DC offset */ + for (k=0;k<FRAMESAMPLES_10ms/2;k++) { + Vector_Word16_1[k] = speechIn[k] + 1; + Vector_Word16_2[k] = speechIn[k]; + } + WebRtcIsacfix_FilterAndCombine2(Vector_Word16_1, Vector_Word16_2, speechInWB, &ISAC_inst->ISACenc_obj.interpolatorstr_obj, FRAMESAMPLES_10ms); + + + /* Encode WB signal */ + stream_len = WebRtcIsacfix_EncodeImpl((WebRtc_Word16*)speechInWB, + &ISAC_inst->ISACenc_obj, + &ISAC_inst->bwestimator_obj, + ISAC_inst->CodingMode); + if (stream_len<0) { + ISAC_inst->errorcode = - stream_len; + return -1; + } + + + /* convert from bytes to WebRtc_Word16 */ +#ifndef WEBRTC_BIG_ENDIAN + for (k=0;k<(stream_len+1)>>1;k++) { + encoded[k] = (WebRtc_Word16)(((WebRtc_UWord16)(ISAC_inst->ISACenc_obj.bitstr_obj).stream[k] >> 8) + | (((ISAC_inst->ISACenc_obj.bitstr_obj).stream[k] & 0x00FF) << 8)); + } + +#else + WEBRTC_SPL_MEMCPY_W16(encoded, (ISAC_inst->ISACenc_obj.bitstr_obj).stream, (stream_len + 1)>>1); +#endif + + + + return stream_len; +} +#endif /* WEBRTC_ISAC_FIX_NB_CALLS_ENABLED */ + + +/**************************************************************************** + * WebRtcIsacfix_GetNewBitStream(...) + * + * This function returns encoded data, with the recieved bwe-index in the + * stream. It should always return a complete packet, i.e. only called once + * even for 60 msec frames + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - bweIndex : index of bandwidth estimate to put in new bitstream + * + * Output: + * - encoded : the encoded data vector + * + * Return value: + * : >0 - Length (in bytes) of coded data + * : -1 - Error + */ + +WebRtc_Word16 WebRtcIsacfix_GetNewBitStream(ISACFIX_MainStruct *ISAC_main_inst, + WebRtc_Word16 bweIndex, + float scale, + WebRtc_Word16 *encoded) +{ + ISACFIX_SubStruct *ISAC_inst; + WebRtc_Word16 stream_len; +#ifndef WEBRTC_BIG_ENDIAN + int k; +#endif + + /* typecast pointer to rela structure */ + ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst; + + + /* check if encoder initiated */ + if ((ISAC_inst->initflag & 2) != 2) { + ISAC_inst->errorcode = ISAC_ENCODER_NOT_INITIATED; + return (-1); + } + + stream_len = WebRtcIsacfix_EncodeStoredData(&ISAC_inst->ISACenc_obj, + bweIndex, + scale); + if (stream_len<0) { + ISAC_inst->errorcode = - stream_len; + return -1; + } + +#ifndef WEBRTC_BIG_ENDIAN + for (k=0;k<(stream_len+1)>>1;k++) { + encoded[k] = (WebRtc_Word16)( ( (WebRtc_UWord16)(ISAC_inst->ISACenc_obj.bitstr_obj).stream[k] >> 8 ) + | (((ISAC_inst->ISACenc_obj.bitstr_obj).stream[k] & 0x00FF) << 8)); + } + +#else + WEBRTC_SPL_MEMCPY_W16(encoded, (ISAC_inst->ISACenc_obj.bitstr_obj).stream, (stream_len + 1)>>1); +#endif + + return stream_len; + +} + + + +/**************************************************************************** + * WebRtcIsacfix_DecoderInit(...) + * + * This function initializes a ISAC instance prior to the decoder calls. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * + * Return value + * : 0 - Ok + * -1 - Error + */ + +WebRtc_Word16 WebRtcIsacfix_DecoderInit(ISACFIX_MainStruct *ISAC_main_inst) +{ + ISACFIX_SubStruct *ISAC_inst; + + /* typecast pointer to real structure */ + ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst; + + /* flag decoder init */ + ISAC_inst->initflag |= 1; + + + WebRtcIsacfix_InitMaskingDec(&ISAC_inst->ISACdec_obj.maskfiltstr_obj); + WebRtcIsacfix_InitPostFilterbank(&ISAC_inst->ISACdec_obj.postfiltbankstr_obj); + WebRtcIsacfix_InitPitchFilter(&ISAC_inst->ISACdec_obj.pitchfiltstr_obj); + + /* TS */ + WebRtcIsacfix_InitPlc( &ISAC_inst->ISACdec_obj.plcstr_obj ); + + +#ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED + WebRtcIsacfix_InitPreFilterbank(&ISAC_inst->ISACdec_obj.decimatorstr_obj); +#endif + + return 0; +} + + +/**************************************************************************** + * WebRtcIsacfix_UpdateBwEstimate1(...) + * + * 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 WebRtcIsacfix_UpdateBwEstimate1(ISACFIX_MainStruct *ISAC_main_inst, + const WebRtc_UWord16 *encoded, + WebRtc_Word32 packet_size, + WebRtc_UWord16 rtp_seq_number, + WebRtc_UWord32 arr_ts) +{ + ISACFIX_SubStruct *ISAC_inst; + Bitstr_dec streamdata; + WebRtc_UWord16 partOfStream[5]; +#ifndef WEBRTC_BIG_ENDIAN + int k; +#endif + WebRtc_Word16 err; + + /* Set stream pointer to point at partOfStream */ + streamdata.stream = (WebRtc_UWord16 *)partOfStream; + + /* typecast pointer to real structure */ + ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst; + + /* Sanity check of packet length */ + if (packet_size <= 0) { + /* return error code if the packet length is null or less */ + ISAC_inst->errorcode = ISAC_EMPTY_PACKET; + return -1; + } else if (packet_size > (STREAM_MAXW16<<1)) { + /* return error code if length of stream is too long */ + ISAC_inst->errorcode = ISAC_LENGTH_MISMATCH; + return -1; + } + + /* check if decoder initiated */ + if ((ISAC_inst->initflag & 1) != 1) { + ISAC_inst->errorcode = ISAC_DECODER_NOT_INITIATED; + return (-1); + } + + streamdata.W_upper = 0xFFFFFFFF; + streamdata.streamval = 0; + streamdata.stream_index = 0; + streamdata.full = 1; + +#ifndef WEBRTC_BIG_ENDIAN + for (k=0; k<5; k++) { + streamdata.stream[k] = (WebRtc_UWord16) (((WebRtc_UWord16)encoded[k] >> 8)|((encoded[k] & 0xFF)<<8)); + } +#else + memcpy(streamdata.stream, encoded, 5); +#endif + + if (packet_size == 0) + { + /* return error code if the packet length is null */ + ISAC_inst->errorcode = ISAC_EMPTY_PACKET; + return -1; + } + + err = WebRtcIsacfix_EstimateBandwidth(&ISAC_inst->bwestimator_obj, + &streamdata, + packet_size, + rtp_seq_number, + 0, + arr_ts); + + + if (err < 0) + { + /* return error code if something went wrong */ + ISAC_inst->errorcode = -err; + return -1; + } + + + return 0; +} + +/**************************************************************************** + * WebRtcIsacfix_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 : Send Time Stamp from RTP header + * - arr_ts : the arrival time of the packet (from NetEq) + * in samples. + * + * Return value : 0 - Ok + * -1 - Error + */ + +WebRtc_Word16 WebRtcIsacfix_UpdateBwEstimate(ISACFIX_MainStruct *ISAC_main_inst, + const WebRtc_UWord16 *encoded, + WebRtc_Word32 packet_size, + WebRtc_UWord16 rtp_seq_number, + WebRtc_UWord32 send_ts, + WebRtc_UWord32 arr_ts) +{ + ISACFIX_SubStruct *ISAC_inst; + Bitstr_dec streamdata; + WebRtc_UWord16 partOfStream[5]; +#ifndef WEBRTC_BIG_ENDIAN + int k; +#endif + WebRtc_Word16 err; + + /* Set stream pointer to point at partOfStream */ + streamdata.stream = (WebRtc_UWord16 *)partOfStream; + + /* typecast pointer to real structure */ + ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst; + + /* Sanity check of packet length */ + if (packet_size <= 0) { + /* return error code if the packet length is null or less */ + ISAC_inst->errorcode = ISAC_EMPTY_PACKET; + return -1; + } else if (packet_size > (STREAM_MAXW16<<1)) { + /* return error code if length of stream is too long */ + ISAC_inst->errorcode = ISAC_LENGTH_MISMATCH; + return -1; + } + + /* check if decoder initiated */ + if ((ISAC_inst->initflag & 1) != 1) { + ISAC_inst->errorcode = ISAC_DECODER_NOT_INITIATED; + return (-1); + } + + streamdata.W_upper = 0xFFFFFFFF; + streamdata.streamval = 0; + streamdata.stream_index = 0; + streamdata.full = 1; + +#ifndef WEBRTC_BIG_ENDIAN + for (k=0; k<5; k++) { + streamdata.stream[k] = (WebRtc_UWord16) ((encoded[k] >> 8)|((encoded[k] & 0xFF)<<8)); + } +#else + memcpy(streamdata.stream, encoded, 5); +#endif + + if (packet_size == 0) + { + /* return error code if the packet length is null */ + ISAC_inst->errorcode = ISAC_EMPTY_PACKET; + return -1; + } + + err = WebRtcIsacfix_EstimateBandwidth(&ISAC_inst->bwestimator_obj, + &streamdata, + packet_size, + rtp_seq_number, + send_ts, + arr_ts); + + if (err < 0) + { + /* return error code if something went wrong */ + ISAC_inst->errorcode = -err; + return -1; + } + + + return 0; +} + +/**************************************************************************** + * WebRtcIsacfix_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 WebRtcIsacfix_Decode(ISACFIX_MainStruct *ISAC_main_inst, + const WebRtc_UWord16 *encoded, + WebRtc_Word16 len, + WebRtc_Word16 *decoded, + WebRtc_Word16 *speechType) +{ + ISACFIX_SubStruct *ISAC_inst; + /* number of samples (480 or 960), output from decoder */ + /* that were actually used in the encoder/decoder (determined on the fly) */ + WebRtc_Word16 number_of_samples; +#ifndef WEBRTC_BIG_ENDIAN + int k; +#endif + WebRtc_Word16 declen = 0; + + /* typecast pointer to real structure */ + ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst; + + /* check if decoder initiated */ + if ((ISAC_inst->initflag & 1) != 1) { + ISAC_inst->errorcode = ISAC_DECODER_NOT_INITIATED; + return (-1); + } + + /* Sanity check of packet length */ + if (len <= 0) { + /* return error code if the packet length is null or less */ + ISAC_inst->errorcode = ISAC_EMPTY_PACKET; + return -1; + } else if (len > (STREAM_MAXW16<<1)) { + /* return error code if length of stream is too long */ + ISAC_inst->errorcode = ISAC_LENGTH_MISMATCH; + return -1; + } + + (ISAC_inst->ISACdec_obj.bitstr_obj).stream = (WebRtc_UWord16 *)encoded; + + /* convert bitstream from WebRtc_Word16 to bytes */ +#ifndef WEBRTC_BIG_ENDIAN + for (k=0; k<(len>>1); k++) { + (ISAC_inst->ISACdec_obj.bitstr_obj).stream[k] = (WebRtc_UWord16) ((encoded[k] >> 8)|((encoded[k] & 0xFF)<<8)); + } + if (len & 0x0001) + (ISAC_inst->ISACdec_obj.bitstr_obj).stream[k] = (WebRtc_UWord16) ((encoded[k] & 0xFF)<<8); +#endif + + /* added for NetEq purposes (VAD/DTX related) */ + *speechType=1; + + declen = WebRtcIsacfix_DecodeImpl(decoded,&ISAC_inst->ISACdec_obj, &number_of_samples); + + if (declen < 0) { + /* Some error inside the decoder */ + ISAC_inst->errorcode = -declen; + memset(decoded, 0, sizeof(WebRtc_Word16) * MAX_FRAMESAMPLES); + return -1; + } + + /* error check */ + + if (declen & 0x0001) { + if (len != declen && len != declen + (((ISAC_inst->ISACdec_obj.bitstr_obj).stream[declen>>1]) & 0x00FF) ) { + ISAC_inst->errorcode = ISAC_LENGTH_MISMATCH; + memset(decoded, 0, sizeof(WebRtc_Word16) * number_of_samples); + return -1; + } + } else { + if (len != declen && len != declen + (((ISAC_inst->ISACdec_obj.bitstr_obj).stream[declen>>1]) >> 8) ) { + ISAC_inst->errorcode = ISAC_LENGTH_MISMATCH; + memset(decoded, 0, sizeof(WebRtc_Word16) * number_of_samples); + return -1; + } + } + + return number_of_samples; +} + + + + + +/**************************************************************************** + * WebRtcIsacfix_DecodeNb(...) + * + * This function decodes a ISAC frame in narrow-band (8 kHz sampling). + * Output speech length will be a multiple of 240 samples: 240 or 480 samples, + * depending on the framesize (30 or 60 ms). + * + * The function is enabled if WEBRTC_ISAC_FIX_NB_CALLS_ENABLED is defined + * + * 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 + */ + +#ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED +WebRtc_Word16 WebRtcIsacfix_DecodeNb(ISACFIX_MainStruct *ISAC_main_inst, + const WebRtc_UWord16 *encoded, + WebRtc_Word16 len, + WebRtc_Word16 *decoded, + WebRtc_Word16 *speechType) +{ + ISACFIX_SubStruct *ISAC_inst; + /* twice the number of samples (480 or 960), output from decoder */ + /* that were actually used in the encoder/decoder (determined on the fly) */ + WebRtc_Word16 number_of_samples; +#ifndef WEBRTC_BIG_ENDIAN + int k; +#endif + WebRtc_Word16 declen = 0; + WebRtc_Word16 dummy[FRAMESAMPLES/2]; + + + /* typecast pointer to real structure */ + ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst; + + /* check if decoder initiated */ + if ((ISAC_inst->initflag & 1) != 1) { + ISAC_inst->errorcode = ISAC_DECODER_NOT_INITIATED; + return (-1); + } + + if (len == 0) + { /* return error code if the packet length is null */ + + ISAC_inst->errorcode = ISAC_EMPTY_PACKET; + return -1; + } + + (ISAC_inst->ISACdec_obj.bitstr_obj).stream = (WebRtc_UWord16 *)encoded; + + /* convert bitstream from WebRtc_Word16 to bytes */ +#ifndef WEBRTC_BIG_ENDIAN + for (k=0; k<(len>>1); k++) { + (ISAC_inst->ISACdec_obj.bitstr_obj).stream[k] = (WebRtc_UWord16) ((encoded[k] >> 8)|((encoded[k] & 0xFF)<<8)); + } + if (len & 0x0001) + (ISAC_inst->ISACdec_obj.bitstr_obj).stream[k] = (WebRtc_UWord16) ((encoded[k] & 0xFF)<<8); +#endif + + /* added for NetEq purposes (VAD/DTX related) */ + *speechType=1; + + declen = WebRtcIsacfix_DecodeImpl(decoded,&ISAC_inst->ISACdec_obj, &number_of_samples); + + if (declen < 0) { + /* Some error inside the decoder */ + ISAC_inst->errorcode = -declen; + memset(decoded, 0, sizeof(WebRtc_Word16) * FRAMESAMPLES); + return -1; + } + + /* error check */ + + if (declen & 0x0001) { + if (len != declen && len != declen + (((ISAC_inst->ISACdec_obj.bitstr_obj).stream[declen>>1]) & 0x00FF) ) { + ISAC_inst->errorcode = ISAC_LENGTH_MISMATCH; + memset(decoded, 0, sizeof(WebRtc_Word16) * number_of_samples); + return -1; + } + } else { + if (len != declen && len != declen + (((ISAC_inst->ISACdec_obj.bitstr_obj).stream[declen>>1]) >> 8) ) { + ISAC_inst->errorcode = ISAC_LENGTH_MISMATCH; + memset(decoded, 0, sizeof(WebRtc_Word16) * number_of_samples); + return -1; + } + } + + WebRtcIsacfix_SplitAndFilter2(decoded, decoded, dummy, &ISAC_inst->ISACdec_obj.decimatorstr_obj); + + if (number_of_samples>FRAMESAMPLES) { + WebRtcIsacfix_SplitAndFilter2(decoded + FRAMESAMPLES, decoded + FRAMESAMPLES/2, + dummy, &ISAC_inst->ISACdec_obj.decimatorstr_obj); + } + + return number_of_samples/2; +} +#endif /* WEBRTC_ISAC_FIX_NB_CALLS_ENABLED */ + + +/**************************************************************************** + * WebRtcIsacfix_DecodePlcNb(...) + * + * This function conducts PLC for ISAC frame(s) in narrow-band (8kHz sampling). + * Output speech length will be "240*noOfLostFrames" samples + * that is equevalent of "30*noOfLostFrames" millisecond. + * + * The function is enabled if WEBRTC_ISAC_FIX_NB_CALLS_ENABLED is defined + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - noOfLostFrames : Number of PLC frames (240 sample=30ms) to produce + * + * Output: + * - decoded : The decoded vector + * + * Return value : >0 - number of samples in decoded PLC vector + * -1 - Error + */ + +#ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED +WebRtc_Word16 WebRtcIsacfix_DecodePlcNb(ISACFIX_MainStruct *ISAC_main_inst, + WebRtc_Word16 *decoded, + WebRtc_Word16 noOfLostFrames ) +{ + WebRtc_Word16 no_of_samples, declen, k, ok; + WebRtc_Word16 outframeNB[FRAMESAMPLES]; + WebRtc_Word16 outframeWB[FRAMESAMPLES]; + WebRtc_Word16 dummy[FRAMESAMPLES/2]; + + + ISACFIX_SubStruct *ISAC_inst; + /* typecast pointer to real structure */ + ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst; + + /* Limit number of frames to two = 60 msec. Otherwise we exceed data vectors */ + if (noOfLostFrames > 2){ + noOfLostFrames = 2; + } + + k = 0; + declen = 0; + while( noOfLostFrames > 0 ) + { + ok = WebRtcIsacfix_DecodePlcImpl( outframeWB, &ISAC_inst->ISACdec_obj, &no_of_samples ); + if(ok) + return -1; + + WebRtcIsacfix_SplitAndFilter2(outframeWB, &(outframeNB[k*240]), dummy, &ISAC_inst->ISACdec_obj.decimatorstr_obj); + + declen += no_of_samples; + noOfLostFrames--; + k++; + } + + declen>>=1; + + for (k=0;k<declen;k++) { + decoded[k] = outframeNB[k]; + } + + return declen; +} +#endif /* WEBRTC_ISAC_FIX_NB_CALLS_ENABLED */ + + + + +/**************************************************************************** + * WebRtcIsacfix_DecodePlc(...) + * + * This function conducts PLC for ISAC frame(s) in wide-band (16kHz sampling). + * Output speech length will be "480*noOfLostFrames" samples + * that is equevalent of "30*noOfLostFrames" millisecond. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - noOfLostFrames : Number of PLC frames (480sample = 30ms) + * to produce + * + * Output: + * - decoded : The decoded vector + * + * Return value : >0 - number of samples in decoded PLC vector + * -1 - Error + */ + +WebRtc_Word16 WebRtcIsacfix_DecodePlc(ISACFIX_MainStruct *ISAC_main_inst, + WebRtc_Word16 *decoded, + WebRtc_Word16 noOfLostFrames) +{ + + WebRtc_Word16 no_of_samples, declen, k, ok; + WebRtc_Word16 outframe16[MAX_FRAMESAMPLES]; + + ISACFIX_SubStruct *ISAC_inst; + /* typecast pointer to real structure */ + ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst; + + /* Limit number of frames to two = 60 msec. Otherwise we exceed data vectors */ + if (noOfLostFrames > 2) { + noOfLostFrames = 2; + } + k = 0; + declen = 0; + while( noOfLostFrames > 0 ) + { + ok = WebRtcIsacfix_DecodePlcImpl( &(outframe16[k*480]), &ISAC_inst->ISACdec_obj, &no_of_samples ); + if(ok) + return -1; + declen += no_of_samples; + noOfLostFrames--; + k++; + } + + for (k=0;k<declen;k++) { + decoded[k] = outframe16[k]; + } + + return declen; +} + + +/**************************************************************************** + * WebRtcIsacfix_Control(...) + * + * 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 + */ + +WebRtc_Word16 WebRtcIsacfix_Control(ISACFIX_MainStruct *ISAC_main_inst, + WebRtc_Word16 rate, + WebRtc_Word16 framesize) +{ + ISACFIX_SubStruct *ISAC_inst; + /* typecast pointer to real structure */ + ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst; + + if (ISAC_inst->CodingMode == 0) + { + /* in adaptive mode */ + ISAC_inst->errorcode = ISAC_MODE_MISMATCH; + return -1; + } + + + if (rate >= 10000 && rate <= 32000) + ISAC_inst->ISACenc_obj.BottleNeck = rate; + else { + ISAC_inst->errorcode = ISAC_DISALLOWED_BOTTLENECK; + return -1; + } + + + + if (framesize == 30 || framesize == 60) + ISAC_inst->ISACenc_obj.new_framelength = (FS/1000) * framesize; + else { + ISAC_inst->errorcode = ISAC_DISALLOWED_FRAME_LENGTH; + return -1; + } + + return 0; +} + + +/**************************************************************************** + * WebRtcIsacfix_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 WebRtcIsacfix_ControlBwe(ISACFIX_MainStruct *ISAC_main_inst, + WebRtc_Word16 rateBPS, + WebRtc_Word16 frameSizeMs, + WebRtc_Word16 enforceFrameSize) +{ + ISACFIX_SubStruct *ISAC_inst; + /* Typecast pointer to real structure */ + ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst; + + /* check if encoder initiated */ + if ((ISAC_inst->initflag & 2) != 2) { + ISAC_inst->errorcode = ISAC_ENCODER_NOT_INITIATED; + return (-1); + } + + /* Check that we are in channel-adaptive mode, otherwise, return -1 */ + if (ISAC_inst->CodingMode != 0) { + ISAC_inst->errorcode = ISAC_MODE_MISMATCH; + return (-1); + } + + /* Set struct variable if enforceFrameSize is set. ISAC will then keep the */ + /* chosen frame size. */ + ISAC_inst->ISACenc_obj.enforceFrameSize = (enforceFrameSize != 0)? 1:0; + + /* Set initial rate, if value between 10000 and 32000, */ + /* if rateBPS is 0, keep the default initial bottleneck value (15000) */ + if ((rateBPS >= 10000) && (rateBPS <= 32000)) { + ISAC_inst->bwestimator_obj.sendBwAvg = (((WebRtc_UWord32)rateBPS) << 7); + } else if (rateBPS != 0) { + ISAC_inst->errorcode = ISAC_DISALLOWED_BOTTLENECK; + return -1; + } + + /* Set initial framesize. If enforceFrameSize is set the frame size will not change */ + if ((frameSizeMs == 30) || (frameSizeMs == 60)) { + ISAC_inst->ISACenc_obj.new_framelength = (FS/1000) * frameSizeMs; + } else { + ISAC_inst->errorcode = ISAC_DISALLOWED_FRAME_LENGTH; + return -1; + } + + return 0; +} + + + + + +/**************************************************************************** + * WebRtcIsacfix_GetDownLinkBwIndex(...) + * + * This function returns index representing the Bandwidth estimate from + * other side to this side. + * + * Input: + * - ISAC_main_inst: iSAC struct + * + * Output: + * - rateIndex : Bandwidth estimate to transmit to other side. + * + */ + +WebRtc_Word16 WebRtcIsacfix_GetDownLinkBwIndex(ISACFIX_MainStruct* ISAC_main_inst, + WebRtc_Word16* rateIndex) +{ + ISACFIX_SubStruct *ISAC_inst; + + /* typecast pointer to real structure */ + ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst; + + /* Call function to get Bandwidth Estimate */ + *rateIndex = WebRtcIsacfix_GetDownlinkBwIndexImpl(&ISAC_inst->bwestimator_obj); + + return 0; +} + + +/**************************************************************************** + * WebRtcIsacfix_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 + * - rateIndex : Bandwidth estimate from other side. + * + */ + +WebRtc_Word16 WebRtcIsacfix_UpdateUplinkBw(ISACFIX_MainStruct* ISAC_main_inst, + WebRtc_Word16 rateIndex) +{ + WebRtc_Word16 err = 0; + ISACFIX_SubStruct *ISAC_inst; + + /* typecast pointer to real structure */ + ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst; + + /* Call function to update BWE with received Bandwidth Estimate */ + err = WebRtcIsacfix_UpdateUplinkBwRec(&ISAC_inst->bwestimator_obj, rateIndex); + if (err < 0) { + ISAC_inst->errorcode = -err; + return (-1); + } + + return 0; +} + +/**************************************************************************** + * WebRtcIsacfix_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 WebRtcIsacfix_ReadFrameLen(const WebRtc_Word16* encoded, + WebRtc_Word16* frameLength) +{ + Bitstr_dec streamdata; + WebRtc_UWord16 partOfStream[5]; +#ifndef WEBRTC_BIG_ENDIAN + int k; +#endif + WebRtc_Word16 err; + + /* Set stream pointer to point at partOfStream */ + streamdata.stream = (WebRtc_UWord16 *)partOfStream; + + streamdata.W_upper = 0xFFFFFFFF; + streamdata.streamval = 0; + streamdata.stream_index = 0; + streamdata.full = 1; + +#ifndef WEBRTC_BIG_ENDIAN + for (k=0; k<5; k++) { + streamdata.stream[k] = (WebRtc_UWord16) (((WebRtc_UWord16)encoded[k] >> 8)|((encoded[k] & 0xFF)<<8)); + } +#else + memcpy(streamdata.stream, encoded, 5); +#endif + + /* decode frame length */ + err = WebRtcIsacfix_DecodeFrameLen(&streamdata, frameLength); + if (err<0) // error check + return err; + + return 0; +} + + +/**************************************************************************** + * WebRtcIsacfix_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) + * - rateIndex : Bandwidth estimate in bitstream + * + */ + +WebRtc_Word16 WebRtcIsacfix_ReadBwIndex(const WebRtc_Word16* encoded, + WebRtc_Word16* rateIndex) +{ + Bitstr_dec streamdata; + WebRtc_UWord16 partOfStream[5]; +#ifndef WEBRTC_BIG_ENDIAN + int k; +#endif + WebRtc_Word16 err; + + /* Set stream pointer to point at partOfStream */ + streamdata.stream = (WebRtc_UWord16 *)partOfStream; + + streamdata.W_upper = 0xFFFFFFFF; + streamdata.streamval = 0; + streamdata.stream_index = 0; + streamdata.full = 1; + +#ifndef WEBRTC_BIG_ENDIAN + for (k=0; k<5; k++) { + streamdata.stream[k] = (WebRtc_UWord16) (((WebRtc_UWord16)encoded[k] >> 8)|((encoded[k] & 0xFF)<<8)); + } +#else + memcpy(streamdata.stream, encoded, 5); +#endif + + /* decode frame length, needed to get to the rateIndex in the bitstream */ + err = WebRtcIsacfix_DecodeFrameLen(&streamdata, rateIndex); + if (err<0) // error check + return err; + + /* decode BW estimation */ + err = WebRtcIsacfix_DecodeSendBandwidth(&streamdata, rateIndex); + if (err<0) // error check + return err; + + return 0; +} + + + + +/**************************************************************************** + * WebRtcIsacfix_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 occured in the + * specified instance. + * + * Input: + * - ISAC_main_inst : ISAC instance + * + * Return value : Error code + */ + +WebRtc_Word16 WebRtcIsacfix_GetErrorCode(ISACFIX_MainStruct *ISAC_main_inst) +{ + ISACFIX_SubStruct *ISAC_inst; + /* typecast pointer to real structure */ + ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst; + + return ISAC_inst->errorcode; +} + + + +/**************************************************************************** + * WebRtcIsacfix_GetUplinkBw(...) + * + * This function returns the inst quantized iSAC send bitrate + * + * Input: + * - ISAC_main_inst : iSAC instance + * + * Return value : bitrate + */ + +WebRtc_Word32 WebRtcIsacfix_GetUplinkBw(ISACFIX_MainStruct *ISAC_main_inst) +{ + ISACFIX_SubStruct *ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst; + BwEstimatorstr * bw = (BwEstimatorstr*)&(ISAC_inst->bwestimator_obj); + + return (WebRtc_Word32) WebRtcIsacfix_GetUplinkBandwidth(bw); +} + +/**************************************************************************** + * WebRtcIsacfix_GetNewFrameLen(...) + * + * This function return the next frame length (in samples) of iSAC. + * + * Input: + * - ISAC_main_inst : iSAC instance + * + * Return value : frame lenght in samples + */ + +WebRtc_Word16 WebRtcIsacfix_GetNewFrameLen(ISACFIX_MainStruct *ISAC_main_inst) +{ + ISACFIX_SubStruct *ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst; + return ISAC_inst->ISACenc_obj.new_framelength; +} + + +/**************************************************************************** + * WebRtcIsacfix_SetMaxPayloadSize(...) + * + * This function sets a limit for the maximum payload size of iSAC. The same + * value is used both for 30 and 60 msec packets. + * The absolute max will be valid until next time the function is called. + * NOTE! This function may override the function WebRtcIsacfix_SetMaxRate() + * + * Input: + * - ISAC_main_inst : iSAC instance + * - maxPayloadBytes : maximum size of the payload in bytes + * valid values are between 100 and 400 bytes + * + * + * Return value : 0 if sucessful + * -1 if error happens + */ + +WebRtc_Word16 WebRtcIsacfix_SetMaxPayloadSize(ISACFIX_MainStruct *ISAC_main_inst, + WebRtc_Word16 maxPayloadBytes) +{ + ISACFIX_SubStruct *ISAC_inst; + + /* typecast pointer to real structure */ + ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst; + + if((maxPayloadBytes < 100) || (maxPayloadBytes > 400)) + { + /* maxPayloadBytes is out of valid range */ + return -1; + } + else + { + /* Set new absolute max, which will not change unless this function + is called again with a new value */ + ISAC_inst->ISACenc_obj.maxPayloadBytes = maxPayloadBytes; + + /* Set new maximum values for 30 and 60 msec packets */ + if (maxPayloadBytes < ISAC_inst->ISACenc_obj.maxRateInBytes) { + ISAC_inst->ISACenc_obj.payloadLimitBytes30 = maxPayloadBytes; + } else { + ISAC_inst->ISACenc_obj.payloadLimitBytes30 = ISAC_inst->ISACenc_obj.maxRateInBytes; + } + + if ( maxPayloadBytes < (ISAC_inst->ISACenc_obj.maxRateInBytes << 1)) { + ISAC_inst->ISACenc_obj.payloadLimitBytes60 = maxPayloadBytes; + } else { + ISAC_inst->ISACenc_obj.payloadLimitBytes60 = (ISAC_inst->ISACenc_obj.maxRateInBytes << 1); + } + } + return 0; +} + + +/**************************************************************************** + * WebRtcIsacfix_SetMaxRate(...) + * + * This function sets the maximum rate which the codec may not exceed for a + * singel packet. The maximum rate is set in bits per second. + * The codec has an absolute maximum rate of 53400 bits per second (200 bytes + * per 30 msec). + * It is possible to set a maximum rate between 32000 and 53400 bits per second. + * + * The rate limit is valid until next time the function is called. + * + * NOTE! Packet size will never go above the value set if calling + * WebRtcIsacfix_SetMaxPayloadSize() (default max packet size is 400 bytes). + * + * Input: + * - ISAC_main_inst : iSAC instance + * - maxRateInBytes : maximum rate in bits per second, + * valid values are 32000 to 53400 bits + * + * Return value : 0 if sucessful + * -1 if error happens + */ + +WebRtc_Word16 WebRtcIsacfix_SetMaxRate(ISACFIX_MainStruct *ISAC_main_inst, + WebRtc_Word32 maxRate) +{ + ISACFIX_SubStruct *ISAC_inst; + WebRtc_Word16 maxRateInBytes; + + /* typecast pointer to real structure */ + ISAC_inst = (ISACFIX_SubStruct *)ISAC_main_inst; + + if((maxRate < 32000) || (maxRate > 53400)) + { + /* maxRate is out of valid range */ + return -1; + } + else + { + /* 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 msec, + divide by 8 to get number of bytes per 30 msec: + maxRateInBytes = floor((maxRate * 30/1000) / 8); */ + maxRateInBytes = (WebRtc_Word16)( WebRtcSpl_DivW32W16ResW16(WEBRTC_SPL_MUL(maxRate, 3), 800) ); + + /* Store the value for usage in the WebRtcIsacfix_SetMaxPayloadSize-function */ + ISAC_inst->ISACenc_obj.maxRateInBytes = maxRateInBytes; + + /* For 30 msec packets: if the new limit is below the maximum + payload size, set a new limit */ + if (maxRateInBytes < ISAC_inst->ISACenc_obj.maxPayloadBytes) { + ISAC_inst->ISACenc_obj.payloadLimitBytes30 = maxRateInBytes; + } else { + ISAC_inst->ISACenc_obj.payloadLimitBytes30 = ISAC_inst->ISACenc_obj.maxPayloadBytes; + } + + /* For 60 msec packets: if the new limit (times 2) is below the + maximum payload size, set a new limit */ + if ( (maxRateInBytes << 1) < ISAC_inst->ISACenc_obj.maxPayloadBytes) { + ISAC_inst->ISACenc_obj.payloadLimitBytes60 = (maxRateInBytes << 1); + } else { + ISAC_inst->ISACenc_obj.payloadLimitBytes60 = ISAC_inst->ISACenc_obj.maxPayloadBytes; + } + } + + return 0; +} + + + +/**************************************************************************** + * WebRtcIsacfix_version(...) + * + * This function returns the version number. + * + * Output: + * - version : Pointer to character string + * + */ + +void WebRtcIsacfix_version(char *version) +{ + strcpy(version, "3.6.0"); +} diff --git a/src/modules/audio_coding/codecs/isac/fix/source/isacfix.gypi b/src/modules/audio_coding/codecs/isac/fix/source/isacfix.gypi new file mode 100644 index 0000000000..739b2e1f32 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/isacfix.gypi @@ -0,0 +1,108 @@ +# 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. + +{ + 'targets': [ + { + 'target_name': 'iSACFix', + 'type': '<(library)', + 'dependencies': [ + '<(webrtc_root)/common_audio/common_audio.gyp:signal_processing', + '<(webrtc_root)/system_wrappers/source/system_wrappers.gyp:system_wrappers', + ], + 'include_dirs': [ + '../interface', + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '../interface', + ], + }, + 'sources': [ + '../interface/isacfix.h', + 'arith_routines.c', + 'arith_routines_hist.c', + 'arith_routines_logist.c', + 'bandwidth_estimator.c', + 'decode.c', + 'decode_bwe.c', + 'decode_plc.c', + 'encode.c', + 'entropy_coding.c', + 'fft.c', + 'filterbank_tables.c', + 'filterbanks.c', + 'filters.c', + 'initialize.c', + 'isacfix.c', + 'lattice.c', + 'lattice_c.c', + 'lpc_masking_model.c', + 'lpc_tables.c', + 'pitch_estimator.c', + 'pitch_filter.c', + 'pitch_filter_c.c', + 'pitch_gain_tables.c', + 'pitch_lag_tables.c', + 'spectrum_ar_model_tables.c', + 'transform.c', + 'arith_routins.h', + 'bandwidth_estimator.h', + 'codec.h', + 'entropy_coding.h', + 'fft.h', + 'filterbank_tables.h', + 'lpc_masking_model.h', + 'lpc_tables.h', + 'pitch_estimator.h', + 'pitch_gain_tables.h', + 'pitch_lag_tables.h', + 'settings.h', + 'spectrum_ar_model_tables.h', + 'structs.h', + ], + 'conditions': [ + ['OS!="win"', { + 'defines': [ + 'WEBRTC_LINUX', + ], + }], + ['target_arch=="arm" and armv7==1', { + 'dependencies': [ 'isac_neon', ], + 'sources': [ + 'lattice_armv7.S', + 'pitch_filter_armv6.S', + ], + 'sources!': [ + 'lattice_c.c', + 'pitch_filter_c.c', + ], + }], + ], + }, + ], + 'conditions': [ + ['target_arch=="arm" and armv7==1', { + 'targets': [ + { + 'target_name': 'isac_neon', + 'type': '<(library)', + 'includes': ['../../../../../../build/arm_neon.gypi',], + 'dependencies': [ + '<(webrtc_root)/common_audio/common_audio.gyp:signal_processing', + ], + 'sources': [ + 'filters_neon.c', + 'lattice_neon.S', + 'lpc_masking_model_neon.S', + ], + }, + ], + }], + ], +} diff --git a/src/modules/audio_coding/codecs/isac/fix/source/lattice.c b/src/modules/audio_coding/codecs/isac/fix/source/lattice.c new file mode 100644 index 0000000000..14588d0f0d --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/lattice.c @@ -0,0 +1,314 @@ +/* + * 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 "codec.h" +#include "settings.h" + +#define LATTICE_MUL_32_32_RSFT16(a32a, a32b, b32) \ + ((WebRtc_Word32)(WEBRTC_SPL_MUL(a32a, b32) + (WEBRTC_SPL_MUL_16_32_RSFT16(a32b, b32)))) +/* This macro is FORBIDDEN to use elsewhere than in a function in this file and + its corresponding neon version. It might give unpredictable results, since a + general WebRtc_Word32*WebRtc_Word32 multiplication results in a 64 bit value. + The result is then shifted just 16 steps to the right, giving need for 48 + bits, i.e. in the generel case, it will NOT fit in a WebRtc_Word32. In the + cases used in here, the WebRtc_Word32 will be enough, since (for a good + reason) the involved multiplicands aren't big enough to overflow a + WebRtc_Word32 after shifting right 16 bits. I have compared the result of a + multiplication between t32 and tmp32, done in two ways: + 1) Using (WebRtc_Word32) (((float)(tmp32))*((float)(tmp32b))/65536.0); + 2) Using LATTICE_MUL_32_32_RSFT16(t16a, t16b, tmp32b); + By running 25 files, I haven't found any bigger diff than 64 - this was in the + case when method 1) gave 650235648 and 2) gave 650235712. +*/ + +/* Function prototype: filtering ar_g_Q0[] and ar_f_Q0[] through an AR filter + with coefficients cth_Q15[] and sth_Q15[]. + Implemented for both generic and ARMv7 platforms. + */ +void WebRtcIsacfix_FilterArLoop(int16_t* ar_g_Q0, + int16_t* ar_f_Q0, + int16_t* cth_Q15, + int16_t* sth_Q15, + int16_t order_coef); + +/* Inner loop used for function WebRtcIsacfix_NormLatticeFilterMa(). It does: + for 0 <= n < HALF_SUBFRAMELEN - 1: + *ptr2 = input2 * (*ptr2) + input0 * (*ptr0)); + *ptr1 = input1 * (*ptr0) + input0 * (*ptr2); + Note, function WebRtcIsacfix_FilterMaLoopNeon and WebRtcIsacfix_FilterMaLoopC + are not bit-exact. The accuracy by the ARM Neon function is same or better. +*/ +void WebRtcIsacfix_FilterMaLoopC(int16_t input0, // Filter coefficient + int16_t input1, // Filter coefficient + int32_t input2, // Inverse coeff. (1/input1) + int32_t* ptr0, // Sample buffer + int32_t* ptr1, // Sample buffer + int32_t* ptr2) { // Sample buffer + int n = 0; + + // Separate the 32-bit variable input2 into two 16-bit integers (high 16 and + // low 16 bits), for using LATTICE_MUL_32_32_RSFT16 in the loop. + int16_t t16a = (int16_t)(input2 >> 16); + int16_t t16b = (int16_t)input2; + if (t16b < 0) t16a++; + + // The loop filtering the samples *ptr0, *ptr1, *ptr2 with filter coefficients + // input0, input1, and input2. + for(n = 0; n < HALF_SUBFRAMELEN - 1; n++, ptr0++, ptr1++, ptr2++) { + int32_t tmp32a = 0; + int32_t tmp32b = 0; + + // Calculate *ptr2 = input2 * (*ptr2 + input0 * (*ptr0)); + tmp32a = WEBRTC_SPL_MUL_16_32_RSFT15(input0, *ptr0); // Q15 * Q15 >> 15 = Q15 + tmp32b = *ptr2 + tmp32a; // Q15 + Q15 = Q15 + *ptr2 = LATTICE_MUL_32_32_RSFT16(t16a, t16b, tmp32b); + + // Calculate *ptr1 = input1 * (*ptr0) + input0 * (*ptr2); + tmp32a = WEBRTC_SPL_MUL_16_32_RSFT15(input1, *ptr0); // Q15*Q15>>15 = Q15 + tmp32b = WEBRTC_SPL_MUL_16_32_RSFT15(input0, *ptr2); // Q15*Q15>>15 = Q15 + *ptr1 = tmp32a + tmp32b; // Q15 + Q15 = Q15 + } +} + +// Declare a function pointer. +FilterMaLoopFix WebRtcIsacfix_FilterMaLoopFix; + +/* filter the signal using normalized lattice filter */ +/* MA filter */ +void WebRtcIsacfix_NormLatticeFilterMa(WebRtc_Word16 orderCoef, + WebRtc_Word32 *stateGQ15, + WebRtc_Word16 *lat_inQ0, + WebRtc_Word16 *filt_coefQ15, + WebRtc_Word32 *gain_lo_hiQ17, + WebRtc_Word16 lo_hi, + WebRtc_Word16 *lat_outQ9) +{ + WebRtc_Word16 sthQ15[MAX_AR_MODEL_ORDER]; + WebRtc_Word16 cthQ15[MAX_AR_MODEL_ORDER]; + + int u, i, k, n; + WebRtc_Word16 temp2,temp3; + WebRtc_Word16 ord_1 = orderCoef+1; + WebRtc_Word32 inv_cthQ16[MAX_AR_MODEL_ORDER]; + + WebRtc_Word32 gain32, fQtmp; + WebRtc_Word16 gain16; + WebRtc_Word16 gain_sh; + + WebRtc_Word32 tmp32, tmp32b; + WebRtc_Word32 fQ15vec[HALF_SUBFRAMELEN]; + WebRtc_Word32 gQ15[MAX_AR_MODEL_ORDER+1][HALF_SUBFRAMELEN]; + WebRtc_Word16 sh; + WebRtc_Word16 t16a; + WebRtc_Word16 t16b; + + for (u=0;u<SUBFRAMES;u++) + { + int32_t temp1 = WEBRTC_SPL_MUL_16_16(u, HALF_SUBFRAMELEN); + + /* set the Direct Form coefficients */ + temp2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16(u, orderCoef); + temp3 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16(2, u)+lo_hi; + + /* compute lattice filter coefficients */ + memcpy(sthQ15, &filt_coefQ15[temp2], orderCoef * sizeof(WebRtc_Word16)); + + WebRtcSpl_SqrtOfOneMinusXSquared(sthQ15, orderCoef, cthQ15); + + /* compute the gain */ + gain32 = gain_lo_hiQ17[temp3]; + gain_sh = WebRtcSpl_NormW32(gain32); + gain32 = WEBRTC_SPL_LSHIFT_W32(gain32, gain_sh); //Q(17+gain_sh) + + for (k=0;k<orderCoef;k++) + { + gain32 = WEBRTC_SPL_MUL_16_32_RSFT15(cthQ15[k], gain32); //Q15*Q(17+gain_sh)>>15 = Q(17+gain_sh) + inv_cthQ16[k] = WebRtcSpl_DivW32W16((WebRtc_Word32)2147483647, cthQ15[k]); // 1/cth[k] in Q31/Q15 = Q16 + } + gain16 = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(gain32, 16); //Q(1+gain_sh) + + /* normalized lattice filter */ + /*****************************/ + + /* initial conditions */ + for (i=0;i<HALF_SUBFRAMELEN;i++) + { + fQ15vec[i] = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)lat_inQ0[i + temp1], 15); //Q15 + gQ15[0][i] = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)lat_inQ0[i + temp1], 15); //Q15 + } + + + fQtmp = fQ15vec[0]; + + /* get the state of f&g for the first input, for all orders */ + for (i=1;i<ord_1;i++) + { + // Calculate f[i][0] = inv_cth[i-1]*(f[i-1][0] + sth[i-1]*stateG[i-1]); + tmp32 = WEBRTC_SPL_MUL_16_32_RSFT15(sthQ15[i-1], stateGQ15[i-1]);//Q15*Q15>>15 = Q15 + tmp32b= fQtmp + tmp32; //Q15+Q15=Q15 + tmp32 = inv_cthQ16[i-1]; //Q16 + t16a = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp32, 16); + t16b = (WebRtc_Word16) (tmp32-WEBRTC_SPL_LSHIFT_W32(((WebRtc_Word32)t16a), 16)); + if (t16b<0) t16a++; + tmp32 = LATTICE_MUL_32_32_RSFT16(t16a, t16b, tmp32b); + fQtmp = tmp32; // Q15 + + // Calculate g[i][0] = cth[i-1]*stateG[i-1] + sth[i-1]* f[i][0]; + tmp32 = WEBRTC_SPL_MUL_16_32_RSFT15(cthQ15[i-1], stateGQ15[i-1]); //Q15*Q15>>15 = Q15 + tmp32b = WEBRTC_SPL_MUL_16_32_RSFT15(sthQ15[i-1], fQtmp); //Q15*Q15>>15 = Q15 + tmp32 = tmp32 + tmp32b;//Q15+Q15 = Q15 + gQ15[i][0] = tmp32; // Q15 + } + + /* filtering */ + /* save the states */ + for(k=0;k<orderCoef;k++) + { + // for 0 <= n < HALF_SUBFRAMELEN - 1: + // f[k+1][n+1] = inv_cth[k]*(f[k][n+1] + sth[k]*g[k][n]); + // g[k+1][n+1] = cth[k]*g[k][n] + sth[k]* f[k+1][n+1]; + WebRtcIsacfix_FilterMaLoopFix(sthQ15[k], cthQ15[k], inv_cthQ16[k], + &gQ15[k][0], &gQ15[k+1][1], &fQ15vec[1]); + } + + fQ15vec[0] = fQtmp; + + for(n=0;n<HALF_SUBFRAMELEN;n++) + { + //gain32 = WEBRTC_SPL_RSHIFT_W32(gain32, gain_sh); // Q(17+gain_sh) -> Q17 + tmp32 = WEBRTC_SPL_MUL_16_32_RSFT16(gain16, fQ15vec[n]); //Q(1+gain_sh)*Q15>>16 = Q(gain_sh) + sh = 9-gain_sh; //number of needed shifts to reach Q9 + t16a = (WebRtc_Word16) WEBRTC_SPL_SHIFT_W32(tmp32, sh); + lat_outQ9[n + temp1] = t16a; + } + + /* save the states */ + for (i=0;i<ord_1;i++) + { + stateGQ15[i] = gQ15[i][HALF_SUBFRAMELEN-1]; + } + //process next frame + } + + return; +} + + + + + +/* ----------------AR filter-------------------------*/ +/* filter the signal using normalized lattice filter */ +void WebRtcIsacfix_NormLatticeFilterAr(WebRtc_Word16 orderCoef, + WebRtc_Word16 *stateGQ0, + WebRtc_Word32 *lat_inQ25, + WebRtc_Word16 *filt_coefQ15, + WebRtc_Word32 *gain_lo_hiQ17, + WebRtc_Word16 lo_hi, + WebRtc_Word16 *lat_outQ0) +{ + int ii,n,k,i,u; + WebRtc_Word16 sthQ15[MAX_AR_MODEL_ORDER]; + WebRtc_Word16 cthQ15[MAX_AR_MODEL_ORDER]; + WebRtc_Word32 tmp32; + + + WebRtc_Word16 tmpAR; + WebRtc_Word16 ARfQ0vec[HALF_SUBFRAMELEN]; + WebRtc_Word16 ARgQ0vec[MAX_AR_MODEL_ORDER+1]; + + WebRtc_Word32 inv_gain32; + WebRtc_Word16 inv_gain16; + WebRtc_Word16 den16; + WebRtc_Word16 sh; + + WebRtc_Word16 temp2,temp3; + WebRtc_Word16 ord_1 = orderCoef+1; + + for (u=0;u<SUBFRAMES;u++) + { + int32_t temp1 = WEBRTC_SPL_MUL_16_16(u, HALF_SUBFRAMELEN); + + //set the denominator and numerator of the Direct Form + temp2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16(u, orderCoef); + temp3 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16(2, u) + lo_hi; + + for (ii=0; ii<orderCoef; ii++) { + sthQ15[ii] = filt_coefQ15[temp2+ii]; + } + + WebRtcSpl_SqrtOfOneMinusXSquared(sthQ15, orderCoef, cthQ15); + + /* Simulation of the 25 files shows that maximum value in + the vector gain_lo_hiQ17[] is 441344, which means that + it is log2((2^31)/441344) = 12.2 shifting bits from + saturation. Therefore, it should be safe to use Q27 instead + of Q17. */ + + tmp32 = WEBRTC_SPL_LSHIFT_W32(gain_lo_hiQ17[temp3], 10); // Q27 + + for (k=0;k<orderCoef;k++) { + tmp32 = WEBRTC_SPL_MUL_16_32_RSFT15(cthQ15[k], tmp32); // Q15*Q27>>15 = Q27 + } + + sh = WebRtcSpl_NormW32(tmp32); // tmp32 is the gain + den16 = (WebRtc_Word16) WEBRTC_SPL_SHIFT_W32(tmp32, sh-16); //Q(27+sh-16) = Q(sh+11) (all 16 bits are value bits) + inv_gain32 = WebRtcSpl_DivW32W16((WebRtc_Word32)2147483647, den16); // 1/gain in Q31/Q(sh+11) = Q(20-sh) + + //initial conditions + inv_gain16 = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(inv_gain32, 2); // 1/gain in Q(20-sh-2) = Q(18-sh) + + for (i=0;i<HALF_SUBFRAMELEN;i++) + { + + tmp32 = WEBRTC_SPL_LSHIFT_W32(lat_inQ25[i + temp1], 1); //Q25->Q26 + tmp32 = WEBRTC_SPL_MUL_16_32_RSFT16(inv_gain16, tmp32); //lat_in[]*inv_gain in (Q(18-sh)*Q26)>>16 = Q(28-sh) + tmp32 = WEBRTC_SPL_SHIFT_W32(tmp32, -(28-sh)); // lat_in[]*inv_gain in Q0 + + ARfQ0vec[i] = (WebRtc_Word16)WebRtcSpl_SatW32ToW16(tmp32); // Q0 + } + + for (i=orderCoef-1;i>=0;i--) //get the state of f&g for the first input, for all orders + { + tmp32 = WEBRTC_SPL_RSHIFT_W32(((WEBRTC_SPL_MUL_16_16(cthQ15[i],ARfQ0vec[0])) - (WEBRTC_SPL_MUL_16_16(sthQ15[i],stateGQ0[i])) + 16384), 15); + tmpAR = (WebRtc_Word16)WebRtcSpl_SatW32ToW16(tmp32); // Q0 + + tmp32 = WEBRTC_SPL_RSHIFT_W32(((WEBRTC_SPL_MUL_16_16(sthQ15[i],ARfQ0vec[0])) + (WEBRTC_SPL_MUL_16_16(cthQ15[i], stateGQ0[i])) + 16384), 15); + ARgQ0vec[i+1] = (WebRtc_Word16)WebRtcSpl_SatW32ToW16(tmp32); // Q0 + ARfQ0vec[0] = tmpAR; + } + ARgQ0vec[0] = ARfQ0vec[0]; + + // Filter ARgQ0vec[] and ARfQ0vec[] through coefficients cthQ15[] and sthQ15[]. + WebRtcIsacfix_FilterArLoop(ARgQ0vec, ARfQ0vec, cthQ15, sthQ15, orderCoef); + + for(n=0;n<HALF_SUBFRAMELEN;n++) + { + lat_outQ0[n + temp1] = ARfQ0vec[n]; + } + + + /* cannot use memcpy in the following */ + + for (i=0;i<ord_1;i++) + { + stateGQ0[i] = ARgQ0vec[i]; + } + } + + return; +} diff --git a/src/modules/audio_coding/codecs/isac/fix/source/lattice_armv7.S b/src/modules/audio_coding/codecs/isac/fix/source/lattice_armv7.S new file mode 100644 index 0000000000..1cd3a764fd --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/lattice_armv7.S @@ -0,0 +1,82 @@ +@ +@ 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. +@ + +@ Contains a function for the core loop in the normalized lattice AR +@ filter routine for iSAC codec, optimized for ARMv7 platforms. +@ +@ Output is bit-exact with the reference C code in lattic_c.c +@ +@ Register usage: +@ +@ r0: &ar_g_Q0 +@ r1: &ar_f_Q0 +@ r2: &cth_Q15 +@ r3: &sth_Q15 +@ r4: out loop counter +@ r5: tmpAR +@ r9: inner loop counter +@ r12: constant #16384 +@ r6, r7, r8, r10, r11: scratch + +#include "settings.h" + +.arch armv7-a +.global WebRtcIsacfix_FilterArLoop +.align 2 + +WebRtcIsacfix_FilterArLoop: +.fnstart + +.save {r4-r11} + push {r4-r11} + + add r1, #2 @ &ar_f_Q0[1] + mov r12, #16384 + mov r4, #HALF_SUBFRAMELEN + sub r4, #1 @ Outer loop counter = HALF_SUBFRAMELEN - 1 + +HALF_SUBFRAME_LOOP: @ for(n = 0; n < HALF_SUBFRAMELEN - 1; n++) + + ldr r9, [sp, #32] @ Restore the inner loop counter to order_coef + ldrh r5, [r1] @ tmpAR = ar_f_Q0[n+1] + add r0, r9, asl #1 @ Restore r0 to &ar_g_Q0[order_coef] + add r2, r9, asl #1 @ Restore r2 to &cth_Q15[order_coef] + add r3, r9, asl #1 @ Restore r3 to &sth_Q15[order_coef] + +ORDER_COEF_LOOP: @ for(k = order_coef - 1 ; k >= 0; k--) + + ldrh r7, [r3, #-2]! @ sth_Q15[k] + ldrh r6, [r2, #-2]! @ cth_Q15[k] + + ldrh r8, [r0, #-2] @ ar_g_Q0[k] + smlabb r11, r7, r5, r12 @ sth_Q15[k] * tmpAR + 16384 + smlabb r10, r6, r5, r12 @ cth_Q15[k] * tmpAR + 16384 + smulbb r7, r7, r8 @ sth_Q15[k] * ar_g_Q0[k] + smlabb r11, r6, r8, r11 @ cth_Q15[k]*ar_g_Q0[k]+(sth_Q15[k]*tmpAR+16384) + + sub r10, r10, r7 @ cth_Q15[k]*tmpAR+16384-(sth_Q15[k]*ar_g_Q0[k]) + ssat r11, #16, r11, asr #15 + ssat r5, #16, r10, asr #15 + strh r11, [r0], #-2 @ Output: ar_g_Q0[k+1] + + subs r9, #1 + bgt ORDER_COEF_LOOP + + strh r5, [r0] @ Output: ar_g_Q0[0] = tmpAR; + strh r5, [r1], #2 @ Output: ar_f_Q0[n+1] = tmpAR; + + subs r4, #1 + bne HALF_SUBFRAME_LOOP + + pop {r4-r11} + bx lr + +.fnend + diff --git a/src/modules/audio_coding/codecs/isac/fix/source/lattice_c.c b/src/modules/audio_coding/codecs/isac/fix/source/lattice_c.c new file mode 100644 index 0000000000..80ccf39e19 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/lattice_c.c @@ -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. + */ + +/* + * Contains the core loop function for the lattice filter AR routine + * for iSAC codec. + * + */ + +#include "settings.h" +#include "signal_processing_library.h" +#include "typedefs.h" + +/* Filter ar_g_Q0[] and ar_f_Q0[] through an AR filter with coefficients + * cth_Q15[] and sth_Q15[]. + */ +void WebRtcIsacfix_FilterArLoop(int16_t* ar_g_Q0, // Input samples + int16_t* ar_f_Q0, // Input samples + int16_t* cth_Q15, // Filter coefficients + int16_t* sth_Q15, // Filter coefficients + int16_t order_coef) { // order of the filter + int n = 0; + + for (n = 0; n < HALF_SUBFRAMELEN - 1; n++) { + int k = 0; + int16_t tmpAR = 0; + int32_t tmp32 = 0; + int32_t tmp32_2 = 0; + + tmpAR = ar_f_Q0[n + 1]; + for (k = order_coef - 1; k >= 0; k--) { + tmp32 = WEBRTC_SPL_RSHIFT_W32(((WEBRTC_SPL_MUL_16_16(cth_Q15[k], tmpAR)) + - (WEBRTC_SPL_MUL_16_16(sth_Q15[k], ar_g_Q0[k])) + 16384), 15); + tmp32_2 = WEBRTC_SPL_RSHIFT_W32(((WEBRTC_SPL_MUL_16_16(sth_Q15[k], tmpAR)) + + (WEBRTC_SPL_MUL_16_16(cth_Q15[k], ar_g_Q0[k])) + 16384), 15); + tmpAR = (WebRtc_Word16)WebRtcSpl_SatW32ToW16(tmp32); + ar_g_Q0[k + 1] = (WebRtc_Word16)WebRtcSpl_SatW32ToW16(tmp32_2); + } + ar_f_Q0[n + 1] = tmpAR; + ar_g_Q0[0] = tmpAR; + } +} diff --git a/src/modules/audio_coding/codecs/isac/fix/source/lattice_neon.S b/src/modules/audio_coding/codecs/isac/fix/source/lattice_neon.S new file mode 100644 index 0000000000..a59b6e37f2 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/lattice_neon.S @@ -0,0 +1,155 @@ +@ +@ 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_neon.s +@ +@ Contains a function for the core loop in the normalized lattice MA +@ filter routine for iSAC codec, optimized for ARM Neon platform. +@ void WebRtcIsacfix_FilterMaLoopNeon(int16_t input0, +@ int16_t input1, +@ int32_t input2, +@ int32_t* ptr0, +@ int32_t* ptr1, +@ int32_t* __restrict ptr2); +@ It calculates +@ *ptr2 = input2 * (*ptr2) + input0 * (*ptr0)); +@ *ptr1 = input1 * (*ptr0) + input0 * (*ptr2); +@ in Q15 domain. +@ +@ Reference code in lattice.c. +@ Output is not bit-exact with the reference C code, due to the replacement +@ of WEBRTC_SPL_MUL_16_32_RSFT15 and LATTICE_MUL_32_32_RSFT16 with Neon +@ instructions, smulwb, and smull. Speech quality was not degraded by +@ testing speech and tone vectors. + +.arch armv7-a +.fpu neon + +#include "settings.h" + +.global WebRtcIsacfix_FilterMaLoopNeon + +.align 2 + +WebRtcIsacfix_FilterMaLoopNeon: +.fnstart + +.save {r4-r8} + push {r4-r8} + + vdup.32 d28, r0 @ Initialize Neon register with input0 + vdup.32 d29, r1 @ Initialize Neon register with input1 + vdup.32 d30, r2 @ Initialize Neon register with input2 + ldr r4, [sp, #20] @ ptr1 + ldr r12, [sp, #24] @ ptr2 + + @ Number of loop iterations after unrolling: r5 = (HALF_SUBFRAMELEN - 1) >> 2 + @ Leftover samples after the loop, in r6: + @ r6 = (HALF_SUBFRAMELEN - 1) - (HALF_SUBFRAMELEN - 1) >> 2 << 2 + mov r6, #HALF_SUBFRAMELEN + sub r6, #1 + lsr r5, r6, #2 + sub r6, r5, lsl #2 + + @ First r5 iterations in a loop. + +LOOP: + vld1.32 {d0, d1}, [r3]! @ *ptr0 + + vmull.s32 q10, d0, d28 @ tmp32a = input0 * (*ptr0) + vmull.s32 q11, d1, d28 @ tmp32a = input0 * (*ptr0) + vmull.s32 q12, d0, d29 @ input1 * (*ptr0) + vmull.s32 q13, d1, d29 @ input1 * (*ptr0) + + vrshrn.i64 d4, q10, #15 + vrshrn.i64 d5, q11, #15 + + vld1.32 {d2, d3}, [r12] @ *ptr2 + vadd.i32 q3, q2, q1 @ tmp32b = *ptr2 + tmp32a + + vrshrn.i64 d0, q12, #15 + + vmull.s32 q10, d6, d30 @ input2 * (*ptr2 + tmp32b) + vmull.s32 q11, d7, d30 @ input2 * (*ptr2 + tmp32b) + + vrshrn.i64 d16, q10, #16 + vrshrn.i64 d17, q11, #16 + + vmull.s32 q10, d16, d28 @ input0 * (*ptr2) + vmull.s32 q11, d17, d28 @ input0 * (*ptr2) + + vrshrn.i64 d1, q13, #15 + vrshrn.i64 d18, q10, #15 + vrshrn.i64 d19, q11, #15 + + vst1.32 {d16, d17}, [r12]! @ *ptr2 + + vadd.i32 q9, q0, q9 + subs r5, #1 + vst1.32 {d18, d19}, [r4]! @ *ptr1 + + bgt LOOP + + @ Check how many samples still need to be processed. + subs r6, #2 + blt LAST_SAMPLE + + @ Process two more samples: + vld1.32 d0, [r3]! @ *ptr0 + + vmull.s32 q11, d0, d28 @ tmp32a = input0 * (*ptr0) + vmull.s32 q13, d0, d29 @ input1 * (*ptr0) + + vld1.32 d18, [r12] @ *ptr2 + vrshrn.i64 d4, q11, #15 + + vadd.i32 d7, d4, d18 @ tmp32b = *ptr2 + tmp32a + vmull.s32 q11, d7, d30 @ input2 * (*ptr2 + tmp32b) + vrshrn.i64 d16, q11, #16 + + vmull.s32 q11, d16, d28 @ input0 * (*ptr2) + vst1.32 d16, [r12]! @ *ptr2 + + vrshrn.i64 d0, q13, #15 + vrshrn.i64 d19, q11, #15 + vadd.i32 d19, d0, d19 + + vst1.32 d19, [r4]! @ *ptr1 + + @ If there's still one more sample, process it here. +LAST_SAMPLE: + cmp r6, #1 + bne END + + @ *ptr2 = input2 * (*ptr2 + input0 * (*ptr0)); + + ldr r7, [r3] @ *ptr0 + ldr r8, [r12] @ *ptr2 + + smulwb r5, r7, r0 @ tmp32a = *ptr0 * input0 >> 16 + add r8, r8, r5, lsl #1 @ tmp32b = *ptr2 + (tmp32a << 1) + smull r5, r6, r8, r2 @ tmp32b * input2, in 64 bits + lsl r6, #16 + add r6, r5, lsr #16 @ Only take the middle 32 bits + str r6, [r12] @ Output (*ptr2, as 32 bits) + + @ *ptr1 = input1 * (*ptr0) + input0 * (*ptr2); + + smulwb r5, r7, r1 @ tmp32a = *ptr0 * input1 >> 16 + smulwb r6, r6, r0 @ tmp32b = *ptr2 * input0 >> 16 + lsl r5, r5, #1 + add r5, r6, lsl #1 + str r5, [r4] @ Output (*ptr1) + +END: + pop {r4-r8} + bx lr + +.fnend diff --git a/src/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model.c b/src/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model.c new file mode 100644 index 0000000000..4be438eb52 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model.c @@ -0,0 +1,957 @@ +/* + * 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_masking_model.c + * + * LPC analysis and filtering functions + * + */ + +#include "lpc_masking_model.h" + +#include <limits.h> /* For LLONG_MAX and LLONG_MIN. */ +#include "codec.h" +#include "entropy_coding.h" +#include "settings.h" + +/* The conversion is implemented by the step-down algorithm */ +void WebRtcSpl_AToK_JSK( + WebRtc_Word16 *a16, /* Q11 */ + WebRtc_Word16 useOrder, + WebRtc_Word16 *k16 /* Q15 */ + ) +{ + int m, k; + WebRtc_Word32 tmp32[MAX_AR_MODEL_ORDER]; + WebRtc_Word32 tmp32b; + WebRtc_Word32 tmp_inv_denum32; + WebRtc_Word16 tmp_inv_denum16; + + k16[useOrder-1]= WEBRTC_SPL_LSHIFT_W16(a16[useOrder], 4); //Q11<<4 => Q15 + + for (m=useOrder-1; m>0; m--) { + tmp_inv_denum32 = ((WebRtc_Word32) 1073741823) - WEBRTC_SPL_MUL_16_16(k16[m], k16[m]); // (1 - k^2) in Q30 + tmp_inv_denum16 = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp_inv_denum32, 15); // (1 - k^2) in Q15 + + for (k=1; k<=m; k++) { + tmp32b = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)a16[k], 16) - + WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_16(k16[m], a16[m-k+1]), 1); + + tmp32[k] = WebRtcSpl_DivW32W16(tmp32b, tmp_inv_denum16); //Q27/Q15 = Q12 + } + + for (k=1; k<m; k++) { + a16[k] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp32[k], 1); //Q12>>1 => Q11 + } + + tmp32[m] = WEBRTC_SPL_SAT(4092, tmp32[m], -4092); + k16[m-1] = (WebRtc_Word16) WEBRTC_SPL_LSHIFT_W32(tmp32[m], 3); //Q12<<3 => Q15 + } + + return; +} + + + + + +WebRtc_Word16 WebRtcSpl_LevinsonW32_JSK( + WebRtc_Word32 *R, /* (i) Autocorrelation of length >= order+1 */ + WebRtc_Word16 *A, /* (o) A[0..order] LPC coefficients (Q11) */ + WebRtc_Word16 *K, /* (o) K[0...order-1] Reflection coefficients (Q15) */ + WebRtc_Word16 order /* (i) filter order */ + ) { + WebRtc_Word16 i, j; + WebRtc_Word16 R_hi[LEVINSON_MAX_ORDER+1], R_low[LEVINSON_MAX_ORDER+1]; + /* Aurocorr coefficients in high precision */ + WebRtc_Word16 A_hi[LEVINSON_MAX_ORDER+1], A_low[LEVINSON_MAX_ORDER+1]; + /* LPC coefficients in high precicion */ + WebRtc_Word16 A_upd_hi[LEVINSON_MAX_ORDER+1], A_upd_low[LEVINSON_MAX_ORDER+1]; + /* LPC coefficients for next iteration */ + WebRtc_Word16 K_hi, K_low; /* reflection coefficient in high precision */ + WebRtc_Word16 Alpha_hi, Alpha_low, Alpha_exp; /* Prediction gain Alpha in high precision + and with scale factor */ + WebRtc_Word16 tmp_hi, tmp_low; + WebRtc_Word32 temp1W32, temp2W32, temp3W32; + WebRtc_Word16 norm; + + /* Normalize the autocorrelation R[0]...R[order+1] */ + + norm = WebRtcSpl_NormW32(R[0]); + + for (i=order;i>=0;i--) { + temp1W32 = WEBRTC_SPL_LSHIFT_W32(R[i], norm); + /* Put R in hi and low format */ + R_hi[i] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(temp1W32, 16); + R_low[i] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((temp1W32 - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)R_hi[i], 16)), 1); + } + + /* K = A[1] = -R[1] / R[0] */ + + temp2W32 = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)R_hi[1],16) + + WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)R_low[1],1); /* R[1] in Q31 */ + temp3W32 = WEBRTC_SPL_ABS_W32(temp2W32); /* abs R[1] */ + temp1W32 = WebRtcSpl_DivW32HiLow(temp3W32, R_hi[0], R_low[0]); /* abs(R[1])/R[0] in Q31 */ + /* Put back the sign on R[1] */ + if (temp2W32 > 0) { + temp1W32 = -temp1W32; + } + + /* Put K in hi and low format */ + K_hi = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(temp1W32, 16); + K_low = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((temp1W32 - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)K_hi, 16)), 1); + + /* Store first reflection coefficient */ + K[0] = K_hi; + + temp1W32 = WEBRTC_SPL_RSHIFT_W32(temp1W32, 4); /* A[1] in Q27 */ + + /* Put A[1] in hi and low format */ + A_hi[1] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(temp1W32, 16); + A_low[1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((temp1W32 - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)A_hi[1], 16)), 1); + + /* Alpha = R[0] * (1-K^2) */ + + temp1W32 = WEBRTC_SPL_LSHIFT_W32((WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(K_hi, K_low), 14) + + WEBRTC_SPL_MUL_16_16(K_hi, K_hi)), 1); /* temp1W32 = k^2 in Q31 */ + + temp1W32 = WEBRTC_SPL_ABS_W32(temp1W32); /* Guard against <0 */ + temp1W32 = (WebRtc_Word32)0x7fffffffL - temp1W32; /* temp1W32 = (1 - K[0]*K[0]) in Q31 */ + + /* Store temp1W32 = 1 - K[0]*K[0] on hi and low format */ + tmp_hi = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(temp1W32, 16); + tmp_low = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((temp1W32 - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)tmp_hi, 16)), 1); + + /* Calculate Alpha in Q31 */ + temp1W32 = WEBRTC_SPL_LSHIFT_W32((WEBRTC_SPL_MUL_16_16(R_hi[0], tmp_hi) + + WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(R_hi[0], tmp_low), 15) + + WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(R_low[0], tmp_hi), 15) ), 1); + + /* Normalize Alpha and put it in hi and low format */ + + Alpha_exp = WebRtcSpl_NormW32(temp1W32); + temp1W32 = WEBRTC_SPL_LSHIFT_W32(temp1W32, Alpha_exp); + Alpha_hi = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(temp1W32, 16); + Alpha_low = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((temp1W32 - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)Alpha_hi, 16)), 1); + + /* Perform the iterative calculations in the + Levinson Durbin algorithm */ + + for (i=2; i<=order; i++) + { + + /* ---- + \ + temp1W32 = R[i] + > R[j]*A[i-j] + / + ---- + j=1..i-1 + */ + + temp1W32 = 0; + + for(j=1; j<i; j++) { + /* temp1W32 is in Q31 */ + temp1W32 += (WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_16(R_hi[j], A_hi[i-j]), 1) + + WEBRTC_SPL_LSHIFT_W32(( WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(R_hi[j], A_low[i-j]), 15) + + WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(R_low[j], A_hi[i-j]), 15) ), 1)); + } + + temp1W32 = WEBRTC_SPL_LSHIFT_W32(temp1W32, 4); + temp1W32 += (WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)R_hi[i], 16) + + WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)R_low[i], 1)); + + /* K = -temp1W32 / Alpha */ + temp2W32 = WEBRTC_SPL_ABS_W32(temp1W32); /* abs(temp1W32) */ + temp3W32 = WebRtcSpl_DivW32HiLow(temp2W32, Alpha_hi, Alpha_low); /* abs(temp1W32)/Alpha */ + + /* Put the sign of temp1W32 back again */ + if (temp1W32 > 0) { + temp3W32 = -temp3W32; + } + + /* Use the Alpha shifts from earlier to denormalize */ + norm = WebRtcSpl_NormW32(temp3W32); + if ((Alpha_exp <= norm)||(temp3W32==0)) { + temp3W32 = WEBRTC_SPL_LSHIFT_W32(temp3W32, Alpha_exp); + } else { + if (temp3W32 > 0) + { + temp3W32 = (WebRtc_Word32)0x7fffffffL; + } else + { + temp3W32 = (WebRtc_Word32)0x80000000L; + } + } + + /* Put K on hi and low format */ + K_hi = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(temp3W32, 16); + K_low = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((temp3W32 - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)K_hi, 16)), 1); + + /* Store Reflection coefficient in Q15 */ + K[i-1] = K_hi; + + /* Test for unstable filter. If unstable return 0 and let the + user decide what to do in that case + */ + + if ((WebRtc_Word32)WEBRTC_SPL_ABS_W16(K_hi) > (WebRtc_Word32)32740) { + return(-i); /* Unstable filter */ + } + + /* + Compute updated LPC coefficient: Anew[i] + Anew[j]= A[j] + K*A[i-j] for j=1..i-1 + Anew[i]= K + */ + + for(j=1; j<i; j++) + { + temp1W32 = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)A_hi[j],16) + + WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)A_low[j],1); /* temp1W32 = A[j] in Q27 */ + + temp1W32 += WEBRTC_SPL_LSHIFT_W32(( WEBRTC_SPL_MUL_16_16(K_hi, A_hi[i-j]) + + WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(K_hi, A_low[i-j]), 15) + + WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(K_low, A_hi[i-j]), 15) ), 1); /* temp1W32 += K*A[i-j] in Q27 */ + + /* Put Anew in hi and low format */ + A_upd_hi[j] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(temp1W32, 16); + A_upd_low[j] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((temp1W32 - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)A_upd_hi[j], 16)), 1); + } + + temp3W32 = WEBRTC_SPL_RSHIFT_W32(temp3W32, 4); /* temp3W32 = K in Q27 (Convert from Q31 to Q27) */ + + /* Store Anew in hi and low format */ + A_upd_hi[i] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(temp3W32, 16); + A_upd_low[i] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((temp3W32 - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)A_upd_hi[i], 16)), 1); + + /* Alpha = Alpha * (1-K^2) */ + + temp1W32 = WEBRTC_SPL_LSHIFT_W32((WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(K_hi, K_low), 14) + + WEBRTC_SPL_MUL_16_16(K_hi, K_hi)), 1); /* K*K in Q31 */ + + temp1W32 = WEBRTC_SPL_ABS_W32(temp1W32); /* Guard against <0 */ + temp1W32 = (WebRtc_Word32)0x7fffffffL - temp1W32; /* 1 - K*K in Q31 */ + + /* Convert 1- K^2 in hi and low format */ + tmp_hi = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(temp1W32, 16); + tmp_low = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((temp1W32 - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)tmp_hi, 16)), 1); + + /* Calculate Alpha = Alpha * (1-K^2) in Q31 */ + temp1W32 = WEBRTC_SPL_LSHIFT_W32(( WEBRTC_SPL_MUL_16_16(Alpha_hi, tmp_hi) + + WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(Alpha_hi, tmp_low), 15) + + WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(Alpha_low, tmp_hi), 15)), 1); + + /* Normalize Alpha and store it on hi and low format */ + + norm = WebRtcSpl_NormW32(temp1W32); + temp1W32 = WEBRTC_SPL_LSHIFT_W32(temp1W32, norm); + + Alpha_hi = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(temp1W32, 16); + Alpha_low = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((temp1W32 - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)Alpha_hi, 16)), 1); + + /* Update the total nomalization of Alpha */ + Alpha_exp = Alpha_exp + norm; + + /* Update A[] */ + + for(j=1; j<=i; j++) + { + A_hi[j] =A_upd_hi[j]; + A_low[j] =A_upd_low[j]; + } + } + + /* + Set A[0] to 1.0 and store the A[i] i=1...order in Q12 + (Convert from Q27 and use rounding) + */ + + A[0] = 2048; + + for(i=1; i<=order; i++) { + /* temp1W32 in Q27 */ + temp1W32 = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)A_hi[i], 16) + + WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)A_low[i], 1); + /* Round and store upper word */ + A[i] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(temp1W32+(WebRtc_Word32)32768, 16); + } + return(1); /* Stable filters */ +} + + + + + +/* window */ +/* Matlab generation of floating point 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 + * All values are multiplyed with 2^21 in fixed point code. + */ +static const WebRtc_Word16 kWindowAutocorr[WINLEN] = { + 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 5, 6, + 8, 10, 12, 14, 17, 20, 24, 28, 33, 38, 43, 49, + 56, 63, 71, 79, 88, 98, 108, 119, 131, 143, 157, 171, + 186, 202, 219, 237, 256, 275, 296, 318, 341, 365, 390, 416, + 444, 472, 502, 533, 566, 600, 635, 671, 709, 748, 789, 831, + 875, 920, 967, 1015, 1065, 1116, 1170, 1224, 1281, 1339, 1399, 1461, + 1525, 1590, 1657, 1726, 1797, 1870, 1945, 2021, 2100, 2181, 2263, 2348, + 2434, 2523, 2614, 2706, 2801, 2898, 2997, 3099, 3202, 3307, 3415, 3525, + 3637, 3751, 3867, 3986, 4106, 4229, 4354, 4481, 4611, 4742, 4876, 5012, + 5150, 5291, 5433, 5578, 5725, 5874, 6025, 6178, 6333, 6490, 6650, 6811, + 6974, 7140, 7307, 7476, 7647, 7820, 7995, 8171, 8349, 8529, 8711, 8894, + 9079, 9265, 9453, 9642, 9833, 10024, 10217, 10412, 10607, 10803, 11000, 11199, + 11398, 11597, 11797, 11998, 12200, 12401, 12603, 12805, 13008, 13210, 13412, 13614, + 13815, 14016, 14216, 14416, 14615, 14813, 15009, 15205, 15399, 15591, 15782, 15971, + 16157, 16342, 16524, 16704, 16881, 17056, 17227, 17395, 17559, 17720, 17877, 18030, + 18179, 18323, 18462, 18597, 18727, 18851, 18970, 19082, 19189, 19290, 19384, 19471, + 19551, 19623, 19689, 19746, 19795, 19835, 19867, 19890, 19904, 19908, 19902, 19886, + 19860, 19823, 19775, 19715, 19644, 19561, 19465, 19357, 19237, 19102, 18955, 18793, + 18618, 18428, 18223, 18004, 17769, 17518, 17252, 16970, 16672, 16357, 16025, 15677, + 15311, 14929, 14529, 14111, 13677, 13225, 12755, 12268, 11764, 11243, 10706, 10152, + 9583, 8998, 8399, 7787, 7162, 6527, 5883, 5231, 4576, 3919, 3265, 2620, + 1990, 1386, 825, 333 +}; + + +/* By using a hearing threshold level in dB of -28 dB (higher value gives more noise), + the H_T_H (in float) can be calculated as: + H_T_H = pow(10.0, 0.05 * (-28.0)) = 0.039810717055350 + In Q19, H_T_H becomes round(0.039810717055350*2^19) ~= 20872, i.e. + H_T_H = 20872/524288.0, and H_T_HQ19 = 20872; +*/ + + +/* The bandwidth expansion vectors are created from: + kPolyVecLo=[0.900000,0.810000,0.729000,0.656100,0.590490,0.531441,0.478297,0.430467,0.387420,0.348678,0.313811,0.282430]; + kPolyVecHi=[0.800000,0.640000,0.512000,0.409600,0.327680,0.262144]; + round(kPolyVecLo*32768) + round(kPolyVecHi*32768) +*/ +static const WebRtc_Word16 kPolyVecLo[12] = { + 29491, 26542, 23888, 21499, 19349, 17414, 15673, 14106, 12695, 11425, 10283, 9255 +}; +static const WebRtc_Word16 kPolyVecHi[6] = { + 26214, 20972, 16777, 13422, 10737, 8590 +}; + +static __inline WebRtc_Word32 log2_Q8_LPC( WebRtc_UWord32 x ) { + + WebRtc_Word32 zeros, lg2; + WebRtc_Word16 frac; + + zeros=WebRtcSpl_NormU32(x); + frac=(WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(((WebRtc_UWord32)WEBRTC_SPL_LSHIFT_W32(x, zeros)&0x7FFFFFFF), 23); + + /* log2(x) */ + + lg2= (WEBRTC_SPL_LSHIFT_W16((31-zeros), 8)+frac); + return lg2; + +} + +static const WebRtc_Word16 kMulPitchGain = -25; /* 200/256 in Q5 */ +static const WebRtc_Word16 kChngFactor = 3523; /* log10(2)*10/4*0.4/1.4=log10(2)/1.4= 0.2150 in Q14 */ +static const WebRtc_Word16 kExp2 = 11819; /* 1/log(2) */ +const int kShiftLowerBand = 11; /* Shift value for lower band in Q domain. */ +const int kShiftHigherBand = 12; /* Shift value for higher band in Q domain. */ + +void WebRtcIsacfix_GetVars(const WebRtc_Word16 *input, const WebRtc_Word16 *pitchGains_Q12, + WebRtc_UWord32 *oldEnergy, WebRtc_Word16 *varscale) +{ + int k; + WebRtc_UWord32 nrgQ[4]; + WebRtc_Word16 nrgQlog[4]; + WebRtc_Word16 tmp16, chng1, chng2, chng3, chng4, tmp, chngQ, oldNrgQlog, pgQ, pg3; + WebRtc_Word32 expPg32; + WebRtc_Word16 expPg, divVal; + WebRtc_Word16 tmp16_1, tmp16_2; + + /* Calculate energies of first and second frame halfs */ + nrgQ[0]=0; + for (k = QLOOKAHEAD/2; k < (FRAMESAMPLES/4 + QLOOKAHEAD) / 2; k++) { + nrgQ[0] +=WEBRTC_SPL_MUL_16_16(input[k],input[k]); + } + nrgQ[1]=0; + for ( ; k < (FRAMESAMPLES/2 + QLOOKAHEAD) / 2; k++) { + nrgQ[1] +=WEBRTC_SPL_MUL_16_16(input[k],input[k]); + } + nrgQ[2]=0; + for ( ; k < (WEBRTC_SPL_MUL_16_16(FRAMESAMPLES, 3)/4 + QLOOKAHEAD) / 2; k++) { + nrgQ[2] +=WEBRTC_SPL_MUL_16_16(input[k],input[k]); + } + nrgQ[3]=0; + for ( ; k < (FRAMESAMPLES + QLOOKAHEAD) / 2; k++) { + nrgQ[3] +=WEBRTC_SPL_MUL_16_16(input[k],input[k]); + } + + for ( k=0; k<4; k++) { + nrgQlog[k] = (WebRtc_Word16)log2_Q8_LPC(nrgQ[k]); /* log2(nrgQ) */ + } + oldNrgQlog = (WebRtc_Word16)log2_Q8_LPC(*oldEnergy); + + /* Calculate average level change */ + chng1 = WEBRTC_SPL_ABS_W16(nrgQlog[3]-nrgQlog[2]); + chng2 = WEBRTC_SPL_ABS_W16(nrgQlog[2]-nrgQlog[1]); + chng3 = WEBRTC_SPL_ABS_W16(nrgQlog[1]-nrgQlog[0]); + chng4 = WEBRTC_SPL_ABS_W16(nrgQlog[0]-oldNrgQlog); + tmp = chng1+chng2+chng3+chng4; + chngQ = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp, kChngFactor, 10); /* Q12 */ + chngQ += 2926; /* + 1.0/1.4 in Q12 */ + + /* Find average pitch gain */ + pgQ = 0; + for (k=0; k<4; k++) + { + pgQ += pitchGains_Q12[k]; + } + + pg3 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(pgQ, pgQ,11); /* pgQ in Q(12+2)=Q14. Q14*Q14>>11 => Q17 */ + pg3 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(pgQ, pg3,13); /* Q17*Q14>>13 =>Q18 */ + pg3 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(pg3, kMulPitchGain ,5); /* Q10 kMulPitchGain = -25 = -200 in Q-3. */ + + tmp16=(WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(kExp2,pg3,13);/* Q13*Q10>>13 => Q10*/ + if (tmp16<0) { + tmp16_2 = (0x0400 | (tmp16 & 0x03FF)); + tmp16_1 = (WEBRTC_SPL_RSHIFT_W16((WebRtc_UWord16)(tmp16 ^ 0xFFFF), 10)-3); /* Gives result in Q14 */ + if (tmp16_1<0) + expPg=(WebRtc_Word16) -WEBRTC_SPL_LSHIFT_W16(tmp16_2, -tmp16_1); + else + expPg=(WebRtc_Word16) -WEBRTC_SPL_RSHIFT_W16(tmp16_2, tmp16_1); + } else + expPg = (WebRtc_Word16) -16384; /* 1 in Q14, since 2^0=1 */ + + expPg32 = (WebRtc_Word32)WEBRTC_SPL_LSHIFT_W16((WebRtc_Word32)expPg, 8); /* Q22 */ + divVal = WebRtcSpl_DivW32W16ResW16(expPg32, chngQ); /* Q22/Q12=Q10 */ + + tmp16=(WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(kExp2,divVal,13);/* Q13*Q10>>13 => Q10*/ + if (tmp16<0) { + tmp16_2 = (0x0400 | (tmp16 & 0x03FF)); + tmp16_1 = (WEBRTC_SPL_RSHIFT_W16((WebRtc_UWord16)(tmp16 ^ 0xFFFF), 10)-3); /* Gives result in Q14 */ + if (tmp16_1<0) + expPg=(WebRtc_Word16) WEBRTC_SPL_LSHIFT_W16(tmp16_2, -tmp16_1); + else + expPg=(WebRtc_Word16) WEBRTC_SPL_RSHIFT_W16(tmp16_2, tmp16_1); + } else + expPg = (WebRtc_Word16) 16384; /* 1 in Q14, since 2^0=1 */ + + *varscale = expPg-1; + *oldEnergy = nrgQ[3]; +} + + + +static __inline WebRtc_Word16 exp2_Q10_T(WebRtc_Word16 x) { // Both in and out in Q10 + + WebRtc_Word16 tmp16_1, tmp16_2; + + tmp16_2=(WebRtc_Word16)(0x0400|(x&0x03FF)); + tmp16_1=-(WebRtc_Word16)WEBRTC_SPL_RSHIFT_W16(x,10); + if(tmp16_1>0) + return (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W16(tmp16_2, tmp16_1); + else + return (WebRtc_Word16) WEBRTC_SPL_LSHIFT_W16(tmp16_2, -tmp16_1); + +} + + +// Declare function pointers. +AutocorrFix WebRtcIsacfix_AutocorrFix; +CalculateResidualEnergy WebRtcIsacfix_CalculateResidualEnergy; + +/* This routine calculates the residual energy for LPC. + * Formula as shown in comments inside. + */ +int32_t WebRtcIsacfix_CalculateResidualEnergyC(int lpc_order, + int32_t q_val_corr, + int q_val_polynomial, + int16_t* a_polynomial, + int32_t* corr_coeffs, + int* q_val_residual_energy) { + int i = 0, j = 0; + int shift_internal = 0, shift_norm = 0; + int32_t tmp32 = 0, word32_high = 0, word32_low = 0, residual_energy = 0; + int64_t sum64 = 0, sum64_tmp = 0; + + for (i = 0; i <= lpc_order; i++) { + for (j = i; j <= lpc_order; j++) { + /* For the case of i == 0: residual_energy += + * a_polynomial[j] * corr_coeffs[i] * a_polynomial[j - i]; + * For the case of i != 0: residual_energy += + * a_polynomial[j] * corr_coeffs[i] * a_polynomial[j - i] * 2; + */ + + tmp32 = WEBRTC_SPL_MUL_16_16(a_polynomial[j], a_polynomial[j - i]); + /* tmp32 in Q(q_val_polynomial * 2). */ + if (i != 0) { + tmp32 <<= 1; + } + sum64_tmp = (int64_t)tmp32 * (int64_t)corr_coeffs[i]; + sum64_tmp >>= shift_internal; + + /* Test overflow and sum the result. */ + if(((sum64_tmp > 0 && sum64 > 0) && (LLONG_MAX - sum64 < sum64_tmp)) || + ((sum64_tmp < 0 && sum64 < 0) && (LLONG_MIN - sum64 > sum64_tmp))) { + /* Shift right for overflow. */ + shift_internal += 1; + sum64 >>= 1; + sum64 += sum64_tmp >> 1; + } else { + sum64 += sum64_tmp; + } + } + } + + word32_high = (int32_t)(sum64 >> 32); + word32_low = (int32_t)sum64; + + // Calculate the value of shifting (shift_norm) for the 64-bit sum. + if(word32_high != 0) { + shift_norm = 32 - WebRtcSpl_NormW32(word32_high); + residual_energy = (int32_t)(sum64 >> shift_norm); + } else { + if((word32_low & 0x80000000) != 0) { + shift_norm = 1; + residual_energy = (uint32_t)word32_low >> 1; + } else { + shift_norm = WebRtcSpl_NormW32(word32_low); + residual_energy = word32_low << shift_norm; + shift_norm = -shift_norm; + } + } + + /* Q(q_val_polynomial * 2) * Q(q_val_corr) >> shift_internal >> shift_norm + * = Q(q_val_corr - shift_internal - shift_norm + q_val_polynomial * 2) + */ + *q_val_residual_energy = q_val_corr - shift_internal - shift_norm + + q_val_polynomial * 2; + + return residual_energy; +} + +void WebRtcIsacfix_GetLpcCoef(WebRtc_Word16 *inLoQ0, + WebRtc_Word16 *inHiQ0, + MaskFiltstr_enc *maskdata, + WebRtc_Word16 snrQ10, + const WebRtc_Word16 *pitchGains_Q12, + WebRtc_Word32 *gain_lo_hiQ17, + WebRtc_Word16 *lo_coeffQ15, + WebRtc_Word16 *hi_coeffQ15) +{ + int k, n, ii; + int pos1, pos2; + int sh_lo, sh_hi, sh, ssh, shMem; + WebRtc_Word16 varscaleQ14; + + WebRtc_Word16 tmpQQlo, tmpQQhi; + WebRtc_Word32 tmp32; + WebRtc_Word16 tmp16,tmp16b; + + WebRtc_Word16 polyHI[ORDERHI+1]; + WebRtc_Word16 rcQ15_lo[ORDERLO], rcQ15_hi[ORDERHI]; + + + WebRtc_Word16 DataLoQ6[WINLEN], DataHiQ6[WINLEN]; + WebRtc_Word32 corrloQQ[ORDERLO+2]; + WebRtc_Word32 corrhiQQ[ORDERHI+1]; + WebRtc_Word32 corrlo2QQ[ORDERLO+1]; + WebRtc_Word16 scale; + WebRtc_Word16 QdomLO, QdomHI, newQdomHI, newQdomLO; + + WebRtc_Word32 res_nrgQQ; + WebRtc_Word32 sqrt_nrg; + + /* less-noise-at-low-frequencies factor */ + WebRtc_Word16 aaQ14; + + /* Multiplication with 1/sqrt(12) ~= 0.28901734104046 can be done by convertion to + Q15, i.e. round(0.28901734104046*32768) = 9471, and use 9471/32768.0 ~= 0.289032 + */ + WebRtc_Word16 snrq; + int shft; + + WebRtc_Word16 tmp16a; + WebRtc_Word32 tmp32a, tmp32b, tmp32c; + + WebRtc_Word16 a_LOQ11[ORDERLO+1]; + WebRtc_Word16 k_vecloQ15[ORDERLO]; + WebRtc_Word16 a_HIQ12[ORDERHI+1]; + WebRtc_Word16 k_vechiQ15[ORDERHI]; + + WebRtc_Word16 stab; + + snrq=snrQ10; + + /* SNR= C * 2 ^ (D * snrq) ; C=0.289, D=0.05*log2(10)=0.166 (~=172 in Q10)*/ + tmp16 = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16_RSFT(snrq, 172, 10); // Q10 + tmp16b = exp2_Q10_T(tmp16); // Q10 + snrq = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16_RSFT(tmp16b, 285, 10); // Q10 + + /* change quallevel depending on pitch gains and level fluctuations */ + WebRtcIsacfix_GetVars(inLoQ0, pitchGains_Q12, &(maskdata->OldEnergy), &varscaleQ14); + + /* less-noise-at-low-frequencies factor */ + /* Calculation of 0.35 * (0.5 + 0.5 * varscale) in fixpoint: + With 0.35 in Q16 (0.35 ~= 22938/65536.0 = 0.3500061) and varscaleQ14 in Q14, + we get Q16*Q14>>16 = Q14 + */ + aaQ14 = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32( + (WEBRTC_SPL_MUL_16_16(22938, (8192 + WEBRTC_SPL_RSHIFT_W32(varscaleQ14, 1))) + + ((WebRtc_Word32)32768)), 16); + + /* Calculate tmp = (1.0 + aa*aa); in Q12 */ + tmp16 = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16_RSFT(aaQ14, aaQ14, 15); //Q14*Q14>>15 = Q13 + tmpQQlo = 4096 + WEBRTC_SPL_RSHIFT_W16(tmp16, 1); // Q12 + Q13>>1 = Q12 + + /* Calculate tmp = (1.0+aa) * (1.0+aa); */ + tmp16 = 8192 + WEBRTC_SPL_RSHIFT_W16(aaQ14, 1); // 1+a in Q13 + tmpQQhi = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16_RSFT(tmp16, tmp16, 14); //Q13*Q13>>14 = Q12 + + /* replace data in buffer by new look-ahead data */ + for (pos1 = 0; pos1 < QLOOKAHEAD; pos1++) { + maskdata->DataBufferLoQ0[pos1 + WINLEN - QLOOKAHEAD] = inLoQ0[pos1]; + } + + for (k = 0; k < SUBFRAMES; k++) { + + /* Update input buffer and multiply signal with window */ + for (pos1 = 0; pos1 < WINLEN - UPDATE/2; pos1++) { + maskdata->DataBufferLoQ0[pos1] = maskdata->DataBufferLoQ0[pos1 + UPDATE/2]; + maskdata->DataBufferHiQ0[pos1] = maskdata->DataBufferHiQ0[pos1 + UPDATE/2]; + DataLoQ6[pos1] = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16_RSFT( + maskdata->DataBufferLoQ0[pos1], kWindowAutocorr[pos1], 15); // Q0*Q21>>15 = Q6 + DataHiQ6[pos1] = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16_RSFT( + maskdata->DataBufferHiQ0[pos1], kWindowAutocorr[pos1], 15); // Q0*Q21>>15 = Q6 + } + pos2 = (WebRtc_Word16)(WEBRTC_SPL_MUL_16_16(k, UPDATE)/2); + for (n = 0; n < UPDATE/2; n++, pos1++) { + maskdata->DataBufferLoQ0[pos1] = inLoQ0[QLOOKAHEAD + pos2]; + maskdata->DataBufferHiQ0[pos1] = inHiQ0[pos2++]; + DataLoQ6[pos1] = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16_RSFT( + maskdata->DataBufferLoQ0[pos1], kWindowAutocorr[pos1], 15); // Q0*Q21>>15 = Q6 + DataHiQ6[pos1] = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16_RSFT( + maskdata->DataBufferHiQ0[pos1], kWindowAutocorr[pos1], 15); // Q0*Q21>>15 = Q6 + } + + /* Get correlation coefficients */ + /* The highest absolute value measured inside DataLo in the test set + For DataHi, corresponding value was 160. + + This means that it should be possible to represent the input values + to WebRtcSpl_AutoCorrelation() as Q6 values (since 307*2^6 = + 19648). Of course, Q0 will also work, but due to the low energy in + DataLo and DataHi, the outputted autocorrelation will be more accurate + and mimic the floating point code better, by being in an high as possible + Q-domain. + */ + + WebRtcIsacfix_AutocorrFix(corrloQQ,DataLoQ6,WINLEN, ORDERLO+1, &scale); + QdomLO = 12-scale; // QdomLO is the Q-domain of corrloQQ + sh_lo = WebRtcSpl_NormW32(corrloQQ[0]); + QdomLO += sh_lo; + for (ii=0; ii<ORDERLO+2; ii++) { + corrloQQ[ii] = WEBRTC_SPL_LSHIFT_W32(corrloQQ[ii], sh_lo); + } + /* It is investigated whether it was possible to use 16 bits for the + 32-bit vector corrloQQ, but it didn't work. */ + + WebRtcIsacfix_AutocorrFix(corrhiQQ,DataHiQ6,WINLEN, ORDERHI, &scale); + + QdomHI = 12-scale; // QdomHI is the Q-domain of corrhiQQ + sh_hi = WebRtcSpl_NormW32(corrhiQQ[0]); + QdomHI += sh_hi; + for (ii=0; ii<ORDERHI+1; ii++) { + corrhiQQ[ii] = WEBRTC_SPL_LSHIFT_W32(corrhiQQ[ii], sh_hi); + } + + /* less noise for lower frequencies, by filtering/scaling autocorrelation sequences */ + + /* Calculate corrlo2[0] = tmpQQlo * corrlo[0] - 2.0*tmpQQlo * corrlo[1];*/ + corrlo2QQ[0] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(tmpQQlo, corrloQQ[0]), 1)- // Q(12+QdomLO-16)>>1 = Q(QdomLO-5) + WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(aaQ14, corrloQQ[1]), 2); // 2*Q(14+QdomLO-16)>>3 = Q(QdomLO-2)>>2 = Q(QdomLO-5) + + /* Calculate corrlo2[n] = tmpQQlo * corrlo[n] - tmpQQlo * (corrlo[n-1] + corrlo[n+1]);*/ + for (n = 1; n <= ORDERLO; n++) { + + tmp32 = WEBRTC_SPL_RSHIFT_W32(corrloQQ[n-1], 1) + WEBRTC_SPL_RSHIFT_W32(corrloQQ[n+1], 1); // Q(QdomLO-1) + corrlo2QQ[n] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(tmpQQlo, corrloQQ[n]), 1)- // Q(12+QdomLO-16)>>1 = Q(QdomLO-5) + WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(aaQ14, tmp32), 2); // Q(14+QdomLO-1-16)>>2 = Q(QdomLO-3)>>2 = Q(QdomLO-5) + + } + QdomLO -= 5; + + /* Calculate corrhi[n] = tmpQQhi * corrhi[n]; */ + for (n = 0; n <= ORDERHI; n++) { + corrhiQQ[n] = WEBRTC_SPL_MUL_16_32_RSFT16(tmpQQhi, corrhiQQ[n]); // Q(12+QdomHI-16) = Q(QdomHI-4) + } + QdomHI -= 4; + + /* add white noise floor */ + /* corrlo2QQ is in Q(QdomLO) and corrhiQQ is in Q(QdomHI) */ + /* Calculate corrlo2[0] += 9.5367431640625e-7; and + corrhi[0] += 9.5367431640625e-7, where the constant is 1/2^20 */ + + tmp32 = WEBRTC_SPL_SHIFT_W32((WebRtc_Word32) 1, QdomLO-20); + corrlo2QQ[0] += tmp32; + tmp32 = WEBRTC_SPL_SHIFT_W32((WebRtc_Word32) 1, QdomHI-20); + corrhiQQ[0] += tmp32; + + /* corrlo2QQ is in Q(QdomLO) and corrhiQQ is in Q(QdomHI) before the following + code segment, where we want to make sure we get a 1-bit margin */ + for (n = 0; n <= ORDERLO; n++) { + corrlo2QQ[n] = WEBRTC_SPL_RSHIFT_W32(corrlo2QQ[n], 1); // Make sure we have a 1-bit margin + } + QdomLO -= 1; // Now, corrlo2QQ is in Q(QdomLO), with a 1-bit margin + + for (n = 0; n <= ORDERHI; n++) { + corrhiQQ[n] = WEBRTC_SPL_RSHIFT_W32(corrhiQQ[n], 1); // Make sure we have a 1-bit margin + } + QdomHI -= 1; // Now, corrhiQQ is in Q(QdomHI), with a 1-bit margin + + + newQdomLO = QdomLO; + + for (n = 0; n <= ORDERLO; n++) { + WebRtc_Word32 tmp, tmpB, tmpCorr; + WebRtc_Word16 alpha=328; //0.01 in Q15 + WebRtc_Word16 beta=324; //(1-0.01)*0.01=0.0099 in Q15 + WebRtc_Word16 gamma=32440; //(1-0.01)=0.99 in Q15 + + if (maskdata->CorrBufLoQQ[n] != 0) { + shMem=WebRtcSpl_NormW32(maskdata->CorrBufLoQQ[n]); + sh = QdomLO - maskdata->CorrBufLoQdom[n]; + if (sh<=shMem) { + tmp = WEBRTC_SPL_SHIFT_W32(maskdata->CorrBufLoQQ[n], sh); // Get CorrBufLoQQ to same domain as corrlo2 + tmp = WEBRTC_SPL_MUL_16_32_RSFT15(alpha, tmp); + } else if ((sh-shMem)<7){ + tmp = WEBRTC_SPL_SHIFT_W32(maskdata->CorrBufLoQQ[n], shMem); // Shift up CorrBufLoQQ as much as possible + tmp = WEBRTC_SPL_MUL_16_32_RSFT15(WEBRTC_SPL_LSHIFT_W16(alpha, (sh-shMem)), tmp); // Shift alpha the number of times required to get tmp in QdomLO + } else { + tmp = WEBRTC_SPL_SHIFT_W32(maskdata->CorrBufLoQQ[n], shMem); // Shift up CorrBufHiQQ as much as possible + tmp = WEBRTC_SPL_MUL_16_32_RSFT15(WEBRTC_SPL_LSHIFT_W16(alpha, 6), tmp); // Shift alpha as much as possible without overflow the number of times required to get tmp in QdomHI + tmpCorr = WEBRTC_SPL_RSHIFT_W32(corrloQQ[n], sh-shMem-6); + tmp = tmp + tmpCorr; + maskdata->CorrBufLoQQ[n] = tmp; + newQdomLO = QdomLO-(sh-shMem-6); + maskdata->CorrBufLoQdom[n] = newQdomLO; + } + } else + tmp = 0; + + tmp = tmp + corrlo2QQ[n]; + + maskdata->CorrBufLoQQ[n] = tmp; + maskdata->CorrBufLoQdom[n] = QdomLO; + + tmp=WEBRTC_SPL_MUL_16_32_RSFT15(beta, tmp); + tmpB=WEBRTC_SPL_MUL_16_32_RSFT15(gamma, corrlo2QQ[n]); + corrlo2QQ[n] = tmp + tmpB; + } + if( newQdomLO!=QdomLO) { + for (n = 0; n <= ORDERLO; n++) { + if (maskdata->CorrBufLoQdom[n] != newQdomLO) + corrloQQ[n] = WEBRTC_SPL_RSHIFT_W32(corrloQQ[n], maskdata->CorrBufLoQdom[n]-newQdomLO); + } + QdomLO = newQdomLO; + } + + + newQdomHI = QdomHI; + + for (n = 0; n <= ORDERHI; n++) { + WebRtc_Word32 tmp, tmpB, tmpCorr; + WebRtc_Word16 alpha=328; //0.01 in Q15 + WebRtc_Word16 beta=324; //(1-0.01)*0.01=0.0099 in Q15 + WebRtc_Word16 gamma=32440; //(1-0.01)=0.99 in Q1 + if (maskdata->CorrBufHiQQ[n] != 0) { + shMem=WebRtcSpl_NormW32(maskdata->CorrBufHiQQ[n]); + sh = QdomHI - maskdata->CorrBufHiQdom[n]; + if (sh<=shMem) { + tmp = WEBRTC_SPL_SHIFT_W32(maskdata->CorrBufHiQQ[n], sh); // Get CorrBufHiQQ to same domain as corrhi + tmp = WEBRTC_SPL_MUL_16_32_RSFT15(alpha, tmp); + tmpCorr = corrhiQQ[n]; + tmp = tmp + tmpCorr; + maskdata->CorrBufHiQQ[n] = tmp; + maskdata->CorrBufHiQdom[n] = QdomHI; + } else if ((sh-shMem)<7) { + tmp = WEBRTC_SPL_SHIFT_W32(maskdata->CorrBufHiQQ[n], shMem); // Shift up CorrBufHiQQ as much as possible + tmp = WEBRTC_SPL_MUL_16_32_RSFT15(WEBRTC_SPL_LSHIFT_W16(alpha, (sh-shMem)), tmp); // Shift alpha the number of times required to get tmp in QdomHI + tmpCorr = corrhiQQ[n]; + tmp = tmp + tmpCorr; + maskdata->CorrBufHiQQ[n] = tmp; + maskdata->CorrBufHiQdom[n] = QdomHI; + } else { + tmp = WEBRTC_SPL_SHIFT_W32(maskdata->CorrBufHiQQ[n], shMem); // Shift up CorrBufHiQQ as much as possible + tmp = WEBRTC_SPL_MUL_16_32_RSFT15(WEBRTC_SPL_LSHIFT_W16(alpha, 6), tmp); // Shift alpha as much as possible without overflow the number of times required to get tmp in QdomHI + tmpCorr = WEBRTC_SPL_RSHIFT_W32(corrhiQQ[n], sh-shMem-6); + tmp = tmp + tmpCorr; + maskdata->CorrBufHiQQ[n] = tmp; + newQdomHI = QdomHI-(sh-shMem-6); + maskdata->CorrBufHiQdom[n] = newQdomHI; + } + } else { + tmp = corrhiQQ[n]; + tmpCorr = tmp; + maskdata->CorrBufHiQQ[n] = tmp; + maskdata->CorrBufHiQdom[n] = QdomHI; + } + + tmp=WEBRTC_SPL_MUL_16_32_RSFT15(beta, tmp); + tmpB=WEBRTC_SPL_MUL_16_32_RSFT15(gamma, tmpCorr); + corrhiQQ[n] = tmp + tmpB; + } + + if( newQdomHI!=QdomHI) { + for (n = 0; n <= ORDERHI; n++) { + if (maskdata->CorrBufHiQdom[n] != newQdomHI) + corrhiQQ[n] = WEBRTC_SPL_RSHIFT_W32(corrhiQQ[n], maskdata->CorrBufHiQdom[n]-newQdomHI); + } + QdomHI = newQdomHI; + } + + stab=WebRtcSpl_LevinsonW32_JSK(corrlo2QQ, a_LOQ11, k_vecloQ15, ORDERLO); + + if (stab<0) { // If unstable use lower order + a_LOQ11[0]=2048; + for (n = 1; n <= ORDERLO; n++) { + a_LOQ11[n]=0; + } + + stab=WebRtcSpl_LevinsonW32_JSK(corrlo2QQ, a_LOQ11, k_vecloQ15, 8); + } + + + WebRtcSpl_LevinsonDurbin(corrhiQQ, a_HIQ12, k_vechiQ15, ORDERHI); + + /* bandwidth expansion */ + for (n = 1; n <= ORDERLO; n++) { + a_LOQ11[n] = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16_RSFT_WITH_FIXROUND(kPolyVecLo[n-1], a_LOQ11[n]); + } + + + polyHI[0] = a_HIQ12[0]; + for (n = 1; n <= ORDERHI; n++) { + a_HIQ12[n] = (WebRtc_Word16) WEBRTC_SPL_MUL_16_16_RSFT_WITH_FIXROUND(kPolyVecHi[n-1], a_HIQ12[n]); + polyHI[n] = a_HIQ12[n]; + } + + /* Normalize the corrlo2 vector */ + sh = WebRtcSpl_NormW32(corrlo2QQ[0]); + for (n = 0; n <= ORDERLO; n++) { + corrlo2QQ[n] = WEBRTC_SPL_LSHIFT_W32(corrlo2QQ[n], sh); + } + QdomLO += sh; /* Now, corrlo2QQ is still in Q(QdomLO) */ + + + /* residual energy */ + + sh_lo = 31; + res_nrgQQ = WebRtcIsacfix_CalculateResidualEnergy(ORDERLO, QdomLO, + kShiftLowerBand, a_LOQ11, corrlo2QQ, &sh_lo); + + /* Convert to reflection coefficients */ + WebRtcSpl_AToK_JSK(a_LOQ11, ORDERLO, rcQ15_lo); + + if (sh_lo & 0x0001) { + res_nrgQQ=WEBRTC_SPL_RSHIFT_W32(res_nrgQQ, 1); + sh_lo-=1; + } + + + if( res_nrgQQ > 0 ) + { + sqrt_nrg=WebRtcSpl_Sqrt(res_nrgQQ); + + /* add hearing threshold and compute the gain */ + /* lo_coeff = varscale * S_N_R / (sqrt_nrg + varscale * H_T_H); */ + + + //tmp32a=WEBRTC_SPL_MUL_16_16_RSFT(varscaleQ14, H_T_HQ19, 17); // Q14 + tmp32a=WEBRTC_SPL_RSHIFT_W32((WebRtc_Word32) varscaleQ14,1); // H_T_HQ19=65536 (16-17=-1) ssh= WEBRTC_SPL_RSHIFT_W16(sh_lo, 1); // sqrt_nrg is in Qssh + ssh= WEBRTC_SPL_RSHIFT_W16(sh_lo, 1); // sqrt_nrg is in Qssh + sh = ssh - 14; + tmp32b = WEBRTC_SPL_SHIFT_W32(tmp32a, sh); // Q14->Qssh + tmp32c = sqrt_nrg + tmp32b; // Qssh (denominator) + tmp32a = WEBRTC_SPL_MUL_16_16_RSFT(varscaleQ14, snrq, 0); //Q24 (numerator) + + sh = WebRtcSpl_NormW32(tmp32c); + shft = 16 - sh; + tmp16a = (WebRtc_Word16) WEBRTC_SPL_SHIFT_W32(tmp32c, -shft); // Q(ssh-shft) (denominator) + + tmp32b = WebRtcSpl_DivW32W16(tmp32a, tmp16a); // Q(24-ssh+shft) + sh = ssh-shft-7; + *gain_lo_hiQ17 = WEBRTC_SPL_SHIFT_W32(tmp32b, sh); // Gains in Q17 + } + else + { + *gain_lo_hiQ17 = 100; //(WebRtc_Word32)WEBRTC_SPL_LSHIFT_W32( (WebRtc_Word32)1, 17); // Gains in Q17 + } + gain_lo_hiQ17++; + + /* copy coefficients to output array */ + for (n = 0; n < ORDERLO; n++) { + *lo_coeffQ15 = (WebRtc_Word16) (rcQ15_lo[n]); + lo_coeffQ15++; + } + /* residual energy */ + sh_hi = 31; + res_nrgQQ = WebRtcIsacfix_CalculateResidualEnergy(ORDERHI, QdomHI, + kShiftHigherBand, a_HIQ12, corrhiQQ, &sh_hi); + + /* Convert to reflection coefficients */ + WebRtcSpl_LpcToReflCoef(polyHI, ORDERHI, rcQ15_hi); + + if (sh_hi & 0x0001) { + res_nrgQQ=WEBRTC_SPL_RSHIFT_W32(res_nrgQQ, 1); + sh_hi-=1; + } + + + if( res_nrgQQ > 0 ) + { + sqrt_nrg=WebRtcSpl_Sqrt(res_nrgQQ); + + + /* add hearing threshold and compute the gain */ + /* hi_coeff = varscale * S_N_R / (sqrt_nrg + varscale * H_T_H); */ + + //tmp32a=WEBRTC_SPL_MUL_16_16_RSFT(varscaleQ14, H_T_HQ19, 17); // Q14 + tmp32a=WEBRTC_SPL_RSHIFT_W32((WebRtc_Word32) varscaleQ14,1); // H_T_HQ19=65536 (16-17=-1) + + ssh= WEBRTC_SPL_RSHIFT_W32(sh_hi, 1); // sqrt_nrg is in Qssh + sh = ssh - 14; + tmp32b = WEBRTC_SPL_SHIFT_W32(tmp32a, sh); // Q14->Qssh + tmp32c = sqrt_nrg + tmp32b; // Qssh (denominator) + tmp32a = WEBRTC_SPL_MUL_16_16_RSFT(varscaleQ14, snrq, 0); //Q24 (numerator) + + sh = WebRtcSpl_NormW32(tmp32c); + shft = 16 - sh; + tmp16a = (WebRtc_Word16) WEBRTC_SPL_SHIFT_W32(tmp32c, -shft); // Q(ssh-shft) (denominator) + + tmp32b = WebRtcSpl_DivW32W16(tmp32a, tmp16a); // Q(24-ssh+shft) + sh = ssh-shft-7; + *gain_lo_hiQ17 = WEBRTC_SPL_SHIFT_W32(tmp32b, sh); // Gains in Q17 + } + else + { + *gain_lo_hiQ17 = 100; //(WebRtc_Word32)WEBRTC_SPL_LSHIFT_W32( (WebRtc_Word32)1, 17); // Gains in Q17 + } + gain_lo_hiQ17++; + + + /* copy coefficients to output array */ + for (n = 0; n < ORDERHI; n++) { + *hi_coeffQ15 = rcQ15_hi[n]; + hi_coeffQ15++; + } + } +} diff --git a/src/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model.h b/src/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model.h new file mode 100644 index 0000000000..e06a207795 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model.h @@ -0,0 +1,69 @@ +/* + * 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_masking_model.h + * + * LPC functions + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_LPC_MASKING_MODEL_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_LPC_MASKING_MODEL_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "structs.h" + +void WebRtcIsacfix_GetVars(const WebRtc_Word16 *input, + const WebRtc_Word16 *pitchGains_Q12, + WebRtc_UWord32 *oldEnergy, + WebRtc_Word16 *varscale); + +void WebRtcIsacfix_GetLpcCoef(WebRtc_Word16 *inLoQ0, + WebRtc_Word16 *inHiQ0, + MaskFiltstr_enc *maskdata, + WebRtc_Word16 snrQ10, + const WebRtc_Word16 *pitchGains_Q12, + WebRtc_Word32 *gain_lo_hiQ17, + WebRtc_Word16 *lo_coeffQ15, + WebRtc_Word16 *hi_coeffQ15); + +typedef int32_t (*CalculateResidualEnergy)(int lpc_order, + int32_t q_val_corr, + int q_val_polynomial, + int16_t* a_polynomial, + int32_t* corr_coeffs, + int* q_val_residual_energy); +extern CalculateResidualEnergy WebRtcIsacfix_CalculateResidualEnergy; + +int32_t WebRtcIsacfix_CalculateResidualEnergyC(int lpc_order, + int32_t q_val_corr, + int q_val_polynomial, + int16_t* a_polynomial, + int32_t* corr_coeffs, + int* q_val_residual_energy); + +#if (defined WEBRTC_DETECT_ARM_NEON) || (defined WEBRTC_ARCH_ARM_NEON) +int32_t WebRtcIsacfix_CalculateResidualEnergyNeon(int lpc_order, + int32_t q_val_corr, + int q_val_polynomial, + int16_t* a_polynomial, + int32_t* corr_coeffs, + int* q_val_residual_energy); +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_LPC_MASKING_MODEL_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model_neon.S b/src/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model_neon.S new file mode 100644 index 0000000000..20b60d0f4e --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/lpc_masking_model_neon.S @@ -0,0 +1,177 @@ +@ +@ 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. +@ + +@ Contains a function for WebRtcIsacfix_CalculateResidualEnergyNeon() in +@ iSAC codec, optimized for ARM Neon platform. Reference code in +@ lpc_masking_model.c. + +.arch armv7-a +.fpu neon +.global WebRtcIsacfix_CalculateResidualEnergyNeon +.align 2 + +@ int32_t WebRtcIsacfix_CalculateResidualEnergyNeon(int lpc_order, +@ int32_t q_val_corr, +@ int q_val_polynomial, +@ int16_t* a_polynomial, +@ int32_t* corr_coeffs, +@ int* q_val_residual_energy); + +WebRtcIsacfix_CalculateResidualEnergyNeon: +.fnstart +.save {r4-r11} + push {r4-r11} + + sub r13, r13, #16 + str r1, [r13, #8] + str r2, [r13, #12] + + mov r4, #1 + vmov.s64 q11, #0 @ Initialize shift_internal. + vmov.s64 q13, #0 @ Initialize sum64. + vmov.s64 q10, #0 + vmov.u8 d20[0], r4 @ Set q10 to 1. + + cmp r0, #0 + blt POST_LOOP_I + + add r9, r3, r0, asl #1 @ &a_polynomial[lpc_order] + mov r6, #0 @ Loop counter i. + ldr r11, [r13, #48] + sub r10, r0, #1 + mov r7, r3 @ &a_polynomial[0] + str r9, [r13, #4] + +LOOP_I: + ldr r2, [r11], #4 @ corr_coeffs[i] + vmov.s64 q15, #0 @ Initialize the sum64_tmp. + vdup.s32 d25, r2 + + cmp r0, r6 @ Compare lpc_order to i. + movle r2, r6 + ble POST_LOOP_J + + mov r1, r6 @ j = i; + mov r12, r7 @ &a_polynomial[i] + mov r4, r3 @ &a_polynomial[j - i] + +LOOP_J: + ldr r8, [r12], #4 + ldr r5, [r4], #4 + vmov.u32 d0[0], r8 + vmov.u32 d1[0], r5 + vmull.s16 q0, d0, d1 + vmull.s32 q0, d0, d25 + cmp r6, #0 @ i == 0? + vshl.s64 q0, q11 + beq SUM1 + vshl.s64 q0, #1 + +SUM1: + vqadd.s64 q14, q0, q15 @ Sum and test overflow. + add r1, r1, #2 + bvc MOV1 @ Skip the shift if there's no overflow. + vshr.s64 q0, #1 + vshr.s64 q15, #1 + vadd.s64 q14, q0, q15 + vsub.s64 q11, q10 + +MOV1: + cmp r0, r1 @ Compare lpc_order to j. + vmov.s64 q15, q14 + bgt LOOP_J + + bic r1, r10, #1 + add r2, r6, #2 + add r2, r1, r2 + +POST_LOOP_J: + vqadd.s64 q0, q13, q15 @ Sum and test overflow. + bvc MOV2 @ Skip the shift if there's no overflow. + vshr.s64 q13, #1 + vshr.s64 q15, #1 + vadd.s64 q0, q13, q15 + vsub.s64 q11, q10 + +MOV2: + vmov.s64 q13, q0 @ update sum64. + cmp r2, r0 + bne CHECK_LOOP_CONDITION + + @ Last sample in the inner loop. + ldr r4, [r13, #4] + ldrsh r8, [r4] + ldrsh r12, [r9] + mul r8, r8, r12 + vmov.s32 d0[0], r8 + vmull.s32 q0, d0, d25 + cmp r6, #0 @ i == 0? + vshl.s64 q0, q11 + beq SUM2 + vshl.s64 q0, #1 + +SUM2: + vqadd.s64 d1, d0, d26 @ Sum and test overflow. + bvc MOV3 @ Skip the shift if there's no overflow. + vshr.s64 q13, #1 + vshr.s64 d0, #1 + vadd.s64 d1, d0, d26 + vsub.s64 q11, q10 + +MOV3: + vmov.s64 d26, d1 @ update sum64. + +CHECK_LOOP_CONDITION: + add r6, r6, #1 + sub r9, r9, #2 + cmp r0, r6 @ Compare i to lpc_order. + sub r10, r10, #1 + add r7, r7, #2 + bge LOOP_I + +POST_LOOP_I: + mov r3, #0 + vqadd.s64 d0, d26, d27 @ Sum and test overflow. + bvc GET_SHIFT_NORM @ Skip the shift if there's no overflow. + vshr.s64 q13, #1 + vadd.s64 d0, d26, d27 + vsub.s64 q11, q10 + +GET_SHIFT_NORM: + vcls.s32 d1, d0 @ Count leading extra sign bits. + vmov.32 r2, d1[1] @ Store # of sign bits of only the 32 MSBs. + vmovl.s32 q1, d1 + vshl.s64 d0, d3 @ d3 contains # of sign bits of the 32 MSBs. + + vcls.s32 d1, d0 @ Count again the leading extra sign bits. + vmov.s32 r1, d1[1] @ Store # of sign bits of only the 32 MSBs. + vmovl.s32 q1, d1 + vshl.s64 d0, d3 @ d3 contains # of sign bits of the 32 MSBs. + + vmov.s32 r0, d0[1] @ residual_energy + vmov.s32 r3, d22[0] @ shift_internal + + @ Calculate the value for q_val_residual_energy. + ldr r4, [r13, #8] @ q_val_corr + ldr r5, [r13, #12] @ q_val_polynomial + sub r12, r4, #32 + add r12, r12, r5, asl #1 + add r1, r12, r1 @ add 1st part of shift_internal. + add r12, r1, r2 @ add 2nd part of shift_internal. + ldr r2, [r13, #52] + add r3, r12, r3 @ value for q_val_residual_energy. + str r3, [r2, #0] + + add r13, r13, #16 + pop {r4-r11} + bx r14 + +.fnend + diff --git a/src/modules/audio_coding/codecs/isac/fix/source/lpc_tables.c b/src/modules/audio_coding/codecs/isac/fix/source/lpc_tables.c new file mode 100644 index 0000000000..90cc9af47a --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/lpc_tables.c @@ -0,0 +1,1280 @@ +/* + * 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_tables.c + * + * Coding tables for the KLT coefficients + * + */ + + +#include "settings.h" +#include "lpc_tables.h" + +/* indices of KLT coefficients used */ +const WebRtc_UWord16 WebRtcIsacfix_kSelIndGain[12] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11}; + +const WebRtc_UWord16 WebRtcIsacfix_kSelIndShape[108] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, + 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 101, 102, 103, 104, 105, 106, 107 +}; + +/* cdf array for model indicator */ +const WebRtc_UWord16 WebRtcIsacfix_kModelCdf[4] = { + 0, 15434, 37548, 65535 +}; + +/* pointer to cdf array for model indicator */ +const WebRtc_UWord16 *WebRtcIsacfix_kModelCdfPtr[1] = { + WebRtcIsacfix_kModelCdf +}; + +/* initial cdf index for decoder of model indicator */ +const WebRtc_UWord16 WebRtcIsacfix_kModelInitIndex[1] = { + 1 +}; + +/* offset to go from rounded value to quantization index */ +const WebRtc_Word16 WebRtcIsacfix_kQuantMinGain[12] ={ + 3, 6, 4, 6, 6, 9, 5, 16, 11, 34, 32, 47 +}; + +const WebRtc_Word16 WebRtcIsacfix_kQuantMinShape[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 WebRtcIsacfix_kMaxIndGain[12] = { + 6, 12, 8, 14, 10, 19, 12, 31, 22, 56, 52, 138 +}; + +const WebRtc_UWord16 WebRtcIsacfix_kMaxIndShape[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 WebRtcIsacfix_kOffsetGain[3][12] = { + { 0, 7, 20, 29, 44, 55, 75, 88, 120, 143, 200, 253}, + { 0, 7, 19, 27, 42, 53, 73, 86, 117, 140, 197, 249}, + { 0, 7, 20, 28, 44, 55, 75, 89, 121, 145, 202, 257} +}; + +const WebRtc_UWord16 WebRtcIsacfix_kOffsetShape[3][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 + }, + { + 0, 1, 2, 3, 4, 6, 7, 8, 9, 11, + 13, 16, 19, 22, 26, 29, 34, 39, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 55, 57, 60, + 63, 66, 70, 73, 78, 84, 91, 92, 93, 94, + 95, 96, 97, 99, 102, 105, 108, 111, 114, 118, + 123, 128, 134, 141, 151, 152, 153, 154, 156, 159, + 162, 165, 168, 171, 174, 177, 181, 186, 194, 200, + 208, 218, 233, 234, 235, 236, 239, 242, 245, 248, + 251, 254, 258, 263, 270, 277, 288, 297, 308, 324, + 349, 351, 354, 357, 361, 366, 372, 378, 383, 390, + 398, 407, 420, 431, 450, 472, 496, 524 + }, + { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 11, + 14, 17, 20, 23, 26, 29, 34, 40, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 58, 61, 64, + 67, 70, 73, 77, 82, 88, 96, 97, 98, 99, + 101, 102, 104, 107, 110, 113, 116, 119, 122, 125, + 129, 134, 141, 150, 160, 161, 162, 163, 166, 168, + 171, 174, 177, 180, 183, 186, 190, 195, 201, 208, + 216, 226, 243, 244, 245, 248, 251, 254, 257, 260, + 263, 268, 273, 278, 284, 291, 299, 310, 323, 340, + 366, 368, 371, 374, 379, 383, 389, 394, 399, 406, + 414, 422, 433, 445, 461, 480, 505, 533 + } +}; + +/* initial cdf index for KLT coefficients */ +const WebRtc_UWord16 WebRtcIsacfix_kInitIndexGain[3][12] = { + { 3, 6, 4, 7, 5, 10, 6, 16, 11, 28, 26, 69}, + { 3, 6, 4, 7, 5, 10, 6, 15, 11, 28, 26, 69}, + { 3, 6, 4, 8, 5, 10, 7, 16, 12, 28, 27, 70} +}; + +const WebRtc_UWord16 WebRtcIsacfix_kInitIndexShape[3][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 + }, + { + 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, + 1, 1, 1, 2, 1, 2, 2, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, + 1, 2, 1, 2, 3, 3, 0, 0, 0, 0, + 0, 0, 1, 1, 1, 1, 1, 1, 2, 2, + 2, 3, 3, 5, 0, 0, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 2, 4, 3, 4, + 5, 7, 0, 0, 0, 1, 1, 1, 1, 1, + 1, 2, 2, 3, 3, 5, 4, 5, 8, 12, + 1, 1, 1, 2, 2, 3, 3, 2, 3, 4, + 4, 6, 5, 9, 11, 12, 14, 25 + }, + { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 2, 3, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 2, 2, 3, 4, 0, 0, 0, 1, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, + 2, 3, 4, 5, 0, 0, 0, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 2, 3, 3, 4, + 5, 8, 0, 0, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 3, 3, 4, 5, 6, 8, 13, + 1, 1, 1, 2, 2, 3, 2, 2, 3, 4, + 4, 5, 6, 8, 9, 12, 14, 25 + } +}; + +/* offsets for quantizer representation levels*/ +const WebRtc_UWord16 WebRtcIsacfix_kOfLevelsGain[3] = { + 0, 392, 779 +}; + +const WebRtc_UWord16 WebRtcIsacfix_kOfLevelsShape[3] = { + 0, 578, 1152 +}; + +/* quantizer representation levels */ + + + +const WebRtc_Word32 WebRtcIsacfix_kLevelsGainQ17[1176] = { + -364547,-231664,-102123,-573,104807,238257,368823,-758583,-640135,-510291 + ,-377662,-252785,-113177,2627,112906,248601,389461,522691,644517,763974 + ,-538963,-368179,-245823,-106095,-890,104299,241111,350730,493190,-800763 + ,-646230,-510239,-382115,-248623,-111829,-2983,113852,251105,388114,519757 + ,644048,774712,896334,1057931,-770009,-635310,-503690,-375087,-248106,-108525 + ,-105,108259,243472,377948,519271,-1160885,-1032044,-914636,-777593,-647891 + ,-518408,-388028,-254321,-115293,-598,117849,251296,385367,515510,652727 + ,777432,920363,1038625,1153637,1316836,-632287,-505430,-379430,-248458,-118013 + ,-888,118762,250266,381650,513327,652169,766471,932113,-2107480,-1971030 + ,-1827020,-1698263,-1558670,-1436314,-1305377,-1172252,-1047355,-914202,-779651,-651001 + ,-520999,-390394,-255761,-123490,-1893,126839,256703,385493,518607,651760 + ,782750,908693,1044131,1163865,1311066,1424177,1582628,1709823,1831740,1955391 + ,-1423044,-1288917,-1181281,-1043222,-911770,-780354,-646799,-522664,-386721,-258266 + ,-128060,-1101,128233,259996,390336,519590,649290,778701,908010,1040796 + ,1161235,1306889,1441882,-4446002,-4301031,-4194304,-4080591,-3947740,-3808975,-3686530 + ,-3567839,-3383251,-3287089,-3136577,-3017405,-2869860,-2751321,-2619984,-2482932,-2354790 + ,-2223147,-2090669,-1964135,-1831208,-1706697,-1570817,-1446008,-1305386,-1175773,-1046066 + ,-915356,-785120,-653614,-524331,-393767,-260442,-130187,-799,128841,261466 + ,393616,520542,652117,784613,914159,1045399,1181072,1308971,1442502,1570346 + ,1693912,1843986,1966014,2090474,2224869,2364593,2475934,2628403,2752512,2856640 + ,-4192441,-4063232,-3917821,-3799195,-3666233,-3519199,-3411021,-3269192,-3135684,-3008826 + ,-2880875,-2747342,-2620981,-2494872,-2354979,-2229718,-2098939,-1964971,-1835399,-1703452 + ,-1572806,-1440482,-1311794,-1179338,-1046521,-919823,-785914,-655335,-523416,-395507 + ,-264833,-132184,-2546,131698,256217,391372,522688,651248,789964,909618 + ,1035305,1179145,1313824,1436934,1552353,1693722,1815508,1972826,2096328,2228224 + ,2359296,2490368,2598848,-6160384,-6029312,-5881382,-5767168,-5636096,-5505024,-5373952 + ,-5228418,-5110384,-4954923,-4880576,-4710990,-4587364,-4471340,-4333905,-4211513,-4051293 + ,-3907927,-3800105,-3675961,-3538640,-3413663,-3271148,-3152105,-3019103,-2869647,-2744015 + ,-2620639,-2479385,-2364211,-2227611,-2095427,-1974497,-1834168,-1703561,-1568961,-1439826 + ,-1309192,-1174050,-1050191,-917836,-786015,-656943,-518934,-394831,-257708,-128041 + ,1610,128991,264442,393977,521383,653849,788164,918641,1049122,1181971 + ,1308934,1439505,1571808,1706305,1836318,1966235,2097269,2228990,2357005,2490292 + ,2617400,2749680,2881234,3014880,3145637,3276467,3409099,3536637,3671493,3802918 + ,3929740,4065036,4194143,4325999,4456126,4586857,4717194,4843923,4978676,5110913 + ,5245281,5371394,5499780,5633779,5762611,5897682,6028688,6167546,6296465,6421682 + ,6548882,6682074,6809432,6941956,7078143,7204509,7334296,7475137,7609896,7732044 + ,7861604,8002039,8131670,8259222,8390299,8522399,8650037,8782348,8908402,9037815 + ,9164594,9300338,9434679,9574500,9699702,9833934,9948152,10083972,10244937,10332822 + ,10485760,10600122,10760754,10892964,11010048,11111004,11272192,11403264,11525091,11624984 + ,11796480,11915146,-393216,-262144,-101702,-740,100568,262144,393216,-786432 + ,-655360,-524288,-383907,-243301,-94956,-156,95547,269629,416691,524288 + ,655360,-393216,-262144,-88448,-37,87318,262144,393216,524288,-917504 + ,-786432,-655360,-495894,-373308,-267503,-93211,4119,91308,250895,393216 + ,526138,655360,786432,917504,-786432,-655360,-524288,-393216,-262144,-83497 + ,222,86893,240922,393216,524288,-1048576,-917504,-790472,-655360,-508639 + ,-383609,-262016,-95550,-3775,96692,256797,364847,534906,655360,786432 + ,889679,1048576,1179648,1310720,1441792,-655360,-524288,-377684,-248408,-93690 + ,1261,95441,227519,393216,524288,655360,786432,917504,-2097152,-1966080 + ,-1809470,-1703936,-1572864,-1441792,-1314289,-1195149,-1056205,-917504,-809951,-657769 + ,-521072,-383788,-248747,-106350,-2944,105550,243408,388548,521064,628732 + ,786432,885456,1064548,1179648,1310720,1441792,1572864,1703936,1835008,-1441792 + ,-1310720,-1179648,-1037570,-888492,-767774,-646634,-519935,-373458,-248029,-111915 + ,760,111232,247735,379432,507672,672699,786432,917504,1048576,1179648 + ,1310720,1441792,-4456448,-4325376,-4194304,-4063232,-3932160,-3801088,-3670016,-3538944 + ,-3407872,-3276800,-3145728,-3014656,-2883584,-2752512,-2647002,-2490368,-2359296,-2228224 + ,-2097152,-1951753,-1835008,-1703936,-1594177,-1462001,-1289150,-1160774,-1025917,-924928 + ,-782509,-641294,-516191,-386630,-251910,-118886,5210,121226,253949,386008 + ,517973,649374,780064,917783,1052462,1183856,1290593,1419389,1556641,1699884 + ,1835008,1988314,2090470,2228224,2359296,2490368,2621440,2752512,2883584,-3801088 + ,-3643514,-3539937,-3409931,-3263294,-3145658,-3012952,-2879230,-2752359,-2622556,-2483471 + ,-2357556,-2226500,-2093112,-1965892,-1833664,-1701035,-1567767,-1440320,-1310556,-1178339 + ,-1049625,-916812,-786477,-655277,-525050,-393773,-264828,-130696,-480,132126 + ,260116,394197,527846,652294,785563,917183,1049511,1175958,1308161,1438759 + ,1572253,1698835,1828535,1967072,2089391,2212798,2348901,2461547,2621440,2752512 + ,2883584,-7309870,-7203780,-7062699,-6939106,-6790819,-6672036,-6553600,-6422317,-6288422 + ,-6164694,-6026456,-5901410,-5754168,-5621459,-5502710,-5369686,-5240454,-5120712,-4976140 + ,-4847970,-4723070,-4589083,-4450923,-4324680,-4189892,-4065551,-3931803,-3800209,-3668539 + ,-3539395,-3404801,-3277470,-3141389,-3016710,-2885724,-2752612,-2618541,-2486762,-2354153 + ,-2225059,-2094984,-1968194,-1830895,-1699508,-1575743,-1444516,-1308683,-1179714,-1053088 + ,-917981,-783707,-653900,-524980,-395409,-260309,-131948,-3452,132113,263241 + ,392185,522597,654134,788288,919810,1045795,1179210,1314201,1444235,1574447 + ,1705193,1834009,1967332,2098102,2229019,2359147,2489859,2619878,2754966,2879671 + ,3014438,3146143,3276733,3405958,3542196,3667493,3798815,3932961,4062458,4187125 + ,4322346,4454875,4587752,4716809,4848274,4975027,5111957,5242215,5373085,5501158 + ,5640140,5762918,5895358,6024008,6157906,6290628,6422713,6546339,6675888,6815606 + ,6955288,7077501,7211630,7337893,7473635,7607175,7728310,7866475,7999658,8127888 + ,8241758,8386483,8522550,8641582,8771915,8922139,9038632,9179385,9313426,9437184 + ,9568256,9699328,9830400,9952933,10120004,10223616,10354688,10474645,10616832,-393216 + ,-262144,-85425,-121,82533,262144,393216,-786432,-655360,-524288,-379928 + ,-222821,-95200,287,95541,227093,393216,493567,655360,786432,-393216 + ,-262144,-86805,510,86722,262144,393216,524288,-1048576,-917504,-786432 + ,-624456,-529951,-395071,-241627,-101168,81,99975,241605,393216,524288 + ,655360,786432,917504,-786432,-655360,-524288,-393216,-230359,-95619,-137 + ,94425,226222,393216,524288,-1179648,-1048576,-917504,-773841,-655360,-492258 + ,-379715,-244707,-103621,-434,104523,242680,381575,523659,650565,786432 + ,917504,1048576,1179648,1310720,-786432,-629344,-524288,-376757,-242858,-101932 + ,-2715,107155,239212,366480,514943,655360,786432,917504,-2228224,-2097152 + ,-1966080,-1835008,-1703936,-1572864,-1441792,-1284584,-1179648,-1048819,-934658,-777181 + ,-626371,-515660,-377493,-248975,-113036,436,113584,248354,379718,512475 + ,653932,796494,917504,1048576,1179648,1310720,1441792,1572864,1703936,1835008 + ,-1572864,-1441792,-1297608,-1161159,-1032316,-917092,-779770,-647384,-515529,-384269 + ,-250003,-119252,1053,118111,249512,380545,512039,648101,770656,907003 + ,1021725,1178082,1310720,1441792,-4587520,-4456448,-4325376,-4194304,-4063232,-3932160 + ,-3801088,-3670016,-3538944,-3407872,-3276800,-3145728,-2999335,-2883584,-2752512,-2621440 + ,-2490368,-2359296,-2228224,-2112691,-1966080,-1848781,-1709830,-1566109,-1438427,-1303530 + ,-1176124,-1040936,-913876,-784585,-652025,-518361,-385267,-256342,-127297,-2733 + ,125422,257792,389363,519911,651106,783805,909407,1044143,1174156,1309267 + ,1436173,1553771,1708958,1814083,1967036,2095386,2255169,2359296,2478303,2621440 + ,2752512,-4456448,-4325376,-4194304,-4063232,-3932160,-3797524,-3670016,-3560250,-3413217 + ,-3257719,-3166416,-2986626,-2878000,-2781144,-2625383,-2495465,-2346792,-2230930,-2077063 + ,-1949225,-1819274,-1697261,-1568664,-1443074,-1304302,-1175289,-1043794,-913423,-785561 + ,-652104,-522835,-392667,-260517,-130088,-2,129509,260990,391931,522470 + ,655770,784902,917093,1046445,1176951,1303121,1441362,1565401,1702022,1822856 + ,1952852,2090384,2214607,2338436,2457483,2621440,-8781824,-8650752,-8519680,-8388608 + ,-8260828,-8126464,-8003337,-7859030,-7750057,-7602176,-7471104,-7340032,-7193045,-7090588 + ,-6946816,-6843344,-6676635,-6557575,-6447804,-6277614,-6159736,-6035729,-5884723,-5739567 + ,-5634818,-5489867,-5372864,-5243300,-5098939,-4988639,-4856258,-4728494,-4591717,-4447428 + ,-4322409,-4192918,-4062638,-3934141,-3797545,-3673373,-3531587,-3407391,-3277404,-3147797 + ,-3013578,-2886548,-2749811,-2616428,-2490949,-2361301,-2228482,-2096883,-1964343,-1831754 + ,-1702201,-1572495,-1442012,-1309242,-1182451,-1048996,-916905,-786510,-657079,-524730 + ,-393672,-261313,-128743,166,130678,261334,393287,524155,655570,786839 + ,917353,1052167,1179013,1309360,1442634,1571153,1703961,1832027,1965014,2097912 + ,2224861,2355341,2490455,2623051,2753484,2877015,3015783,3144157,3273705,3405255 + ,3542006,3669580,3802417,3935413,4065088,4190896,4333521,4456355,4579781,4713832 + ,4845707,4978625,5113278,5243817,5382318,5500592,5638135,5761179,5900822,6029270 + ,6186398,6297816,6436435,6559163,6666389,6806548,6950461,7086078,7195777,7350973 + ,7480132,7614852,7743514,7847288,8014762,8126464,8257536,8388608,8519680,8650752 + ,8781824,8912896,9043968,9175040,9306112,9437184 +}; + + + +const WebRtc_Word16 WebRtcIsacfix_kLevelsShapeQ10[1735] = { + 0, 0, -1, 0, 0, 1, 0, 1, 0, -821 + , 1, -763, -1, 656, -620, 0, 633, -636, 4, 615 + , -630, 1, 649, -1773, -670, 5, 678, 1810, -1876, -676 + , 0, 691, 1843, -1806, -743, -1, 749, 1795, 2920, -2872 + , -1761, -772, -3, 790, 1763, 2942, 0, 0, 0, 0 + , -792, 2, 0, 0, 1, 0, -854, 0, -702, -1 + , 662, -624, -5, 638, -611, -6, 638, -647, 0, 651 + , -685, -4, 679, 2123, -1814, -693, 0, 664, 1791, -1735 + , -737, 0, 771, 1854, 2873, -2867, -1842, -793, -1, 821 + , 1826, 2805, 3922, 0, 0, 0, -1, -779, 1, 786 + , 1, -708, 0, 789, -799, 1, 797, -663, 2, 646 + , -600, 3, 609, -600, 1, 658, 1807, -627, -3, 612 + , -625, 3, 632, -1732, -674, 1, 672, 2048, -1768, -715 + , 0, 724, 1784, -3881, -3072, -1774, -719, -1, 730, 1811 + , -2963, -1829, -806, -1, 816, 1795, 3050, -5389, -3784, -2942 + , -1893, -865, -12, 867, 1885, 2945, 3928, -2, 1, 4 + , 0, -694, 2, 665, -598, 5, 587, -599, -1, 661 + , -656, -7, 611, -607, 5, 603, -618, -4, 620, -1794 + , -645, -2, 654, -655, -1, 658, -1801, -700, 5, 707 + , 1927, -1752, -745, -8, 752, 1843, -2838, -1781, -801, 11 + , 796, 1811, 2942, 3866, -3849, -3026, -1848, -819, 2, 827 + , 1825, 2963, -3873, -2904, -1869, -910, -6, 903, 1902, 2885 + , 3978, 5286, -7168, -6081, -4989, -3968, -2963, -1970, -943, -2 + , 953, 1951, 2968, 3974, 5009, 6032, -2, 3, -1024, 2 + , 1024, -637, 1, 669, -613, -7, 630, -603, 4, 612 + , -612, 0, 590, -645, -11, 627, -657, -2, 671, 1849 + , -1853, -694, 2, 702, 1838, -3304, -1780, -736, -8, 732 + , 1772, -1709, -755, -6, 760, 1780, -2994, -1780, -800, 8 + , 819, 1830, 2816, -4096, -2822, -1881, -851, -4, 855, 1872 + , 2840, 3899, -3908, -2904, -1878, -887, 6, 897, 1872, 2942 + , 4008, -4992, -3881, -2933, -1915, -928, 1, 937, 1919, 2900 + , 4009, 4881, -6848, -6157, -5065, -3981, -2983, -1972, -978, -1 + , 968, 1979, 2988, 4008, 5007, 6108, 7003, 8051, 9027,-13272 + ,-12012,-11228,-10213, -9261, -8084, -7133, -6075, -5052, -4050, -3036 + , -2014, -996, -4, 1007, 2031, 3038, 4049, 5074, 6134, 7069 + , 8094, 9069, 10212, 11049, 12104, 51, -1024, -13, 1024, -609 + , -107, 613, -2048, -687, -95, 667, 2048, -3072, -1724, -785 + , -34, 732, 1819, -2048, -703, -26, 681, 2048, -2048, -686 + , -9, 665, 2048, -2048, -702, 37, 748, 1723, -4096, -2786 + , -1844, -837, 37, 811, 1742, 3072, -4096, -2783, -1848, -881 + , 39, 898, 1843, 2792, 3764, -5120, -4096, -2923, -1833, -852 + , -14, 862, 1824, 2834, 4096, -6144, -5120, -3914, -2842, -1870 + , -886, -27, 888, 1929, 2931, 4051, -7168, -6144, -5120, -3866 + , -2933, -1915, -927, 64, 933, 1902, 2929, 3912, 5063, 6144 + ,-11264,-10240, -9216, -8192, -7086, -6144, -5039, -3972, -2943, -1929 + , -941, 3, 938, 1942, 2959, 3933, 4905, 6088, 6983, 8192 + , -9216, -8192, -7202, -6088, -4983, -4019, -2955, -1975, -966, 17 + , 997, 1981, 2967, 3990, 4948, 6022, 6967, 8192,-13312,-12288 + ,-11264,-10240, -9216, -8049, -6997, -6040, -5026, -4043, -3029, -2034 + , -1015, -23, 984, 1997, 3010, 4038, 5002, 6015, 6946, 8061 + , 9216, 10240,-12381,-11264,-10240, -9060, -8058, -7153, -6085, -5075 + , -4051, -3042, -2037, -1017, -5, 1007, 2028, 3035, 4050, 5088 + , 6111, 7160, 8156, 9215, 10095, 11229, 12202, 13016,-26624,-25600 + ,-24582,-23671,-22674,-21400,-20355,-19508,-18315,-17269,-16361,-15299 + ,-14363,-13294,-12262,-11237,-10203, -9227, -8165, -7156, -6116, -5122 + , -4076, -3056, -2043, -1020, -8, 1027, 2047, 3065, 4110, 5130 + , 6125, 7168, 8195, 9206, 10230, 11227, 12256, 13304, 14281, 15316 + , 16374, 17382, 18428, 19388, 20361, 21468, 22448, 23781, 0, 0 + , -1, 0, -2, 1024, 0, 0, 0, -1, 1024, -1024 + , 1, -1024, 4, 1024, -1024, 2, 1024, -1024, 2, 1024 + , -2048, -1024, -4, 1024, -1024, 2, 1024, -2048, -1024, -3 + , 1024, 2048, -2048, -1024, 4, 1024, 2048, -3072, -2048, -1024 + , -1, 662, 2048, 0, 1, 0, 0, 1, -2, -2 + , 0, 2, 1024, -1, 1024, -1024, 4, 1024, -1024, 1 + , 1024, -1024, 1, 1024, -2048, -781, -4, 844, -807, -5 + , 866, -2048, -726, -13, 777, 2048, -2048, -643, -4, 617 + , 2048, 3072, -3072, -2048, -629, 1, 630, 2048, 3072, 0 + , -1, 1, -2, 2, 1, -1024, 5, -1024, 6, 1024 + , -1024, 4, 1024, -1024, 1, 1024, -1024, -9, 1024, -673 + , -7, 655, -2048, -665, -15, 716, -2048, -647, 4, 640 + , 2048, -2048, -615, -1, 635, 2048, -2048, -613, 10, 637 + , 2048, 3072, -3072, -2048, -647, -3, 641, 2048, 3072, -5120 + , -4096, -3072, -2048, -681, 6, 685, 2048, 3072, 4096, 1 + , 1, 0, -1, 1024, -1024, -3, 1024, -1024, 6, 1024 + , -1024, -1, 769, -733, 0, 1024, -876, -2, 653, -1024 + , -4, 786, -596, -13, 595, -634, -2, 638, 2048, -2048 + , -620, -5, 620, 2048, -4096, -3072, -2048, -639, 11, 655 + , 2048, 3072, -3072, -2048, -659, 5, 663, 2048, -3072, -1823 + , -687, 22, 695, 2048, 3072, 4096, -4096, -3072, -1848, -715 + , -3, 727, 1816, 3072, 4096, 5120, -8192, -7168, -6144, -5120 + , -4096, -2884, -1771, -756, -14, 775, 1844, 3072, 4096, 5120 + , 6144, -1, 1, 0, -1024, 2, 815, -768, 2, 708 + , -1024, -3, 693, -661, -7, 607, -643, -5, 609, -624 + , 3, 631, -682, -3, 691, 2048, -2048, -640, 5, 650 + , 2048, -3072, -2048, -701, 9, 704, 2048, 3072, -3072, -2048 + , -670, 10, 674, 2048, 3072, -5120, -4096, -3072, -1749, -738 + , 0, 733, 1811, 3072, 4096, 5120, -4096, -3072, -1873, -753 + , 0, 756, 1874, 3072, 4096, -5120, -4096, -2900, -1838, -793 + , -6, 793, 1868, 2837, 4096, 5120, -7168, -6144, -5120, -4096 + , -2832, -1891, -828, 1, 828, 1901, 2823, 3912, 5120, 6144 + , 7168, 8192,-13312,-12288,-11264,-10240, -9216, -8192, -7168, -6144 + , -5120, -3976, -3004, -1911, -869, 7, 869, 1932, 3024, 3992 + , 5009, 6144, 7168, 8192, 9216, 10240, 11264, -4, 1024, -629 + , -22, 609, -623, 9, 640, -2048, -768, 1, 682, -2048 + , -741, 49, 722, 2048, -3072, -1706, -808, -20, 768, 1750 + , -1684, -727, -29, 788, 1840, 3033, -1758, -784, 0, 801 + , 1702, -3072, -1813, -814, 38, 820, 1884, 2927, -4096, -3241 + , -1839, -922, 25, 882, 1886, 2812, -4096, -2982, -1923, -894 + , 84, 912, 1869, 2778, 4096, -4928, -3965, -2902, -1920, -883 + , 3, 917, 1953, 2921, 3957, 4922, 6144, 7168, -5120, -3916 + , -2897, -1949, -930, 31, 959, 1934, 2901, 3851, 5120, -9216 + , -8192, -7046, -6029, -5030, -4034, -2980, -1969, -1013, -76, 963 + , 1963, 2901, 3929, 4893, 6270, 7168, 8192, 9216,-12288,-11264 + ,-10240, -9216, -8192, -6846, -6123, -5108, -4008, -3000, -1963, -954 + , -6, 958, 1992, 3009, 4020, 5085, 6097, 7168, 8192, 9216 + ,-11264,-10139, -9194, -8127, -7156, -6102, -5053, -4049, -3036, -2025 + , -1009, -34, 974, 1984, 3034, 4028, 5138, 6000, 7057, 8166 + , 9070, 10033, 11360, 12288,-13312,-12288,-10932,-10190, -9120, -8123 + , -7128, -6103, -5074, -4081, -3053, -2029, -989, -4, 1010, 2028 + , 3051, 4073, 5071, 6099, 7132, 8147, 9295, 10159, 11023, 12263 + , 13312, 14336,-25600,-24576,-23552,-22529,-21504,-20480,-19456,-18637 + ,-17425,-16165,-15316,-14327,-13606,-12135,-11182,-10107, -9153, -8144 + , -7146, -6160, -5129, -4095, -3064, -2038, -1025, 1, 1031, 2072 + , 3074, 4088, 5123, 6149, 7157, 8173, 9198, 10244, 11250, 12268 + , 13263, 14289, 15351, 16370, 17402, 18413, 19474, 20337, 21386, 22521 + , 23367, 24350, 0, 0, 0, 0, 0, 0, 0, 0 + , -1024, 0, 1024, -1024, 0, 1024, -1024, 0, 1024, -1024 + , 0, 1024, -1024, 0, 1024, -773, 0, 1024, -674, 0 + , 645, -2048, -745, 0, 628, 2048, -2048, -712, 0, 681 + , 2048, 3072, -3072, -2048, -673, 0, 682, 1964, 3257, 0 + , 0, 0, 0, 0, 0, 0, 0, -1024, 0, 1024 + , -1024, 0, 1024, -1024, 0, 1024, -705, 0, 623, -771 + , 0, 1024, -786, 0, 688, -631, 0, 652, 2048, -2048 + , -627, -1, 666, 2048, -3072, -1756, -694, 0, 674, 2048 + , -3098, -1879, -720, 5, 694, 1886, 2958, 4096, 0, 0 + , 0, 0, 1024, 0, 0, 1024, -769, 0, 1024, -1024 + , 0, 1024, -1024, 0, 1024, -817, 0, 734, -786, 0 + , 651, -638, 0, 637, -623, 0, 671, -652, 0, 619 + , 2048, -2048, -670, -1, 663, 2048, -1908, -680, 1, 686 + , 2048, 3072, 4096, -4096, -3072, -1833, -711, 0, 727, 1747 + , 3072, 4096, -4096, -2971, -1826, -762, 2, 766, 1832, 2852 + , 3928, 5079, 0, 0, 0, -1024, 0, 1024, -1024, 0 + , -656, 0, 1024, -599, 0, 620, -1024, 0, 1024, -603 + , 0, 622, -643, 0, 660, -599, 0, 611, -641, -1 + , 651, 2048, -2048, -648, -2, 647, 1798, -3072, -2048, -672 + , 2, 670, 2048, -3072, -1780, -694, -1, 706, 1751, 3072 + , -3072, -1862, -757, 7, 739, 1798, 3072, 4096, -5120, -4096 + , -3253, -1811, -787, 3, 782, 1887, 3123, 4096, -7252, -6144 + , -5354, -4060, -2864, -1863, -820, -11, 847, 1903, 2970, 3851 + , 4921, 5957, 7168, 8192, 9306, 0, 0, -1024, 0, 1024 + , -726, 0, 706, -692, 0, 593, -598, 0, 616, -624 + , 0, 616, -605, 0, 613, -2048, -652, 1, 635, 2048 + , -2048, -647, -1, 660, 2048, -1811, -668, -2, 685, 2048 + , -1796, -731, -2, 730, 1702, 3072, -3072, -1766, -747, -4 + , 756, 1770, 3072, -4096, -3024, -1762, -783, 4, 771, 1781 + , 3072, -5120, -4057, -2807, -1832, -822, 0, 816, 1804, 2851 + , 3949, 5120, -6144, -4899, -3927, -2920, -1893, -874, -2, 868 + , 1881, 2905, 3960, 4912, 6144, -9216, -8192, -7168, -6225, -4963 + , -3943, -2956, -1890, -902, 0, 897, 1914, 2916, 3984, 4990 + , 6050, 7168,-11264,-10217, -9114, -8132, -7035, -5988, -4984, -4000 + , -2980, -1962, -927, 7, 931, 1956, 2981, 4031, 4972, 6213 + , 7227, 8192, 9216, 10240, 11170, 12288, 13312, 14336, 0, 1024 + , -557, 1, 571, -606, -4, 612, -1676, -707, 10, 673 + , 2048, -2048, -727, 5, 686, -3072, -1772, -755, 12, 716 + , 1877, -1856, -786, 2, 786, 1712, -1685, -818, -16, 863 + , 1729, -3072, -1762, -857, 3, 866, 1838, 2841, -3862, -2816 + , -1864, -925, -2, 923, 1897, 2779, -2782, -1838, -920, -28 + , 931, 1951, 2835, 3804, -4815, -4001, -2940, -1934, -959, -22 + , 975, 1957, 2904, 3971, 4835, -5148, -3892, -2944, -1953, -986 + , -11, 989, 1968, 2939, 3949, 4947, 5902, -9216, -8192, -6915 + , -6004, -4965, -4013, -3009, -1977, -987, -1, 982, 1972, 3000 + , 3960, 4939, 5814, -8976, -7888, -7084, -5955, -5043, -4009, -2991 + , -2002, -1000, -8, 993, 2011, 3023, 4026, 5028, 6023, 7052 + , 8014, 9216,-11240,-10036, -9125, -8118, -7105, -6062, -5048, -4047 + , -3044, -2025, -1009, -1, 1011, 2023, 3042, 4074, 5085, 6108 + , 7119, 8142, 9152, 10114, 11141, 12250, 13307,-15360,-14099,-13284 + ,-12291,-11223,-10221, -9152, -8147, -7128, -6104, -5077, -4072, -3062 + , -2033, -1020, 7, 1018, 2038, 3059, 4081, 5084, 6109, 7102 + , 8128, 9134, 10125, 11239, 12080,-23552,-22528,-21504,-20480,-19456 + ,-18159,-17240,-16291,-15364,-14285,-13305,-12271,-11233,-10217, -9198 + , -8175, -7157, -6134, -5122, -4089, -3071, -2047, -1018, 3, 1026 + , 2041, 3077, 4090, 5108, 6131, 7150, 8172, 9175, 10196, 11272 + , 12303, 13273, 14328, 15332, 16334, 17381, 18409, 19423, 20423, 21451 + , 22679, 23391, 24568, 25600, 26589 +}; + +/* cdf tables for quantizer indices */ +const WebRtc_UWord16 WebRtcIsacfix_kCdfGain[1212] = { + 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, 0, 2, 4, 6, 65528, 65531, + 65533, 65535, 0, 2, 4, 6, 8, 10, 222, 65321, + 65513, 65528, 65531, 65533, 65535, 0, 2, 4, 50, 65476, + 65529, 65531, 65533, 65535, 0, 2, 4, 6, 8, 12, + 38, 544, 64936, 65509, 65523, 65525, 65529, 65531, 65533, 65535, + 0, 2, 4, 6, 8, 10, 1055, 64508, 65528, 65531, + 65533, 65535, 0, 2, 4, 6, 8, 10, 12, 123, + 3956, 62999, 65372, 65495, 65515, 65521, 65523, 65525, 65527, 65529, + 65531, 65533, 65535, 0, 2, 4, 12, 53, 4707, 59445, + 65467, 65525, 65527, 65529, 65531, 65533, 65535, 0, 2, 4, + 6, 8, 10, 12, 14, 16, 38, 40, 50, 67, + 96, 234, 929, 14345, 55750, 64866, 65389, 65462, 65514, 65517, + 65519, 65521, 65523, 65525, 65527, 65529, 65531, 65533, 65535, 0, + 2, 4, 6, 8, 10, 15, 35, 91, 377, 1946, + 13618, 52565, 63714, 65184, 65465, 65520, 65523, 65525, 65527, 65529, + 65531, 65533, 65535, 0, 2, 4, 6, 8, 10, 12, + 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, + 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, + 54, 82, 149, 362, 751, 1701, 4239, 12893, 38627, 55072, + 60875, 63071, 64158, 64702, 65096, 65283, 65412, 65473, 65494, 65505, + 65508, 65517, 65519, 65521, 65523, 65525, 65527, 65529, 65531, 65533, + 65535, 0, 2, 15, 23, 53, 143, 260, 418, 698, + 988, 1353, 1812, 2411, 3144, 4015, 5143, 6401, 7611, 8999, + 10653, 12512, 14636, 16865, 19404, 22154, 24798, 27521, 30326, 33102, + 35790, 38603, 41415, 43968, 46771, 49435, 52152, 54715, 57143, 59481, + 61178, 62507, 63603, 64489, 64997, 65257, 65427, 65473, 65503, 65520, + 65529, 65531, 65533, 65535, 0, 3, 6, 9, 26, 32, + 44, 46, 64, 94, 111, 164, 205, 254, 327, 409, + 506, 608, 733, 885, 1093, 1292, 1482, 1742, 1993, 2329, + 2615, 3029, 3374, 3798, 4257, 4870, 5405, 5992, 6618, 7225, + 7816, 8418, 9051, 9761, 10532, 11380, 12113, 13010, 13788, 14594, + 15455, 16361, 17182, 18088, 18997, 20046, 20951, 21968, 22947, 24124, + 25296, 26547, 27712, 28775, 29807, 30835, 31709, 32469, 33201, 34014, + 34876, 35773, 36696, 37620, 38558, 39547, 40406, 41277, 42367, 43290, + 44445, 45443, 46510, 47684, 48973, 50157, 51187, 52242, 53209, 54083, + 55006, 55871, 56618, 57293, 57965, 58556, 59222, 59722, 60180, 60554, + 60902, 61250, 61554, 61837, 62100, 62372, 62631, 62856, 63078, 63324, + 63557, 63768, 63961, 64089, 64235, 64352, 64501, 64633, 64770, 64887, + 65001, 65059, 65121, 65188, 65246, 65302, 65346, 65390, 65428, 65463, + 65477, 65506, 65515, 65517, 65519, 65521, 65523, 65525, 65527, 65529, + 65531, 65533, 65535, 0, 2, 4, 109, 65332, 65531, 65533, + 65535, 0, 2, 4, 6, 8, 25, 1817, 63874, 65511, + 65527, 65529, 65531, 65533, 65535, 0, 2, 4, 907, 65014, + 65529, 65531, 65533, 65535, 0, 2, 4, 6, 8, 10, + 12, 132, 2743, 62708, 65430, 65525, 65527, 65529, 65531, 65533, + 65535, 0, 2, 4, 6, 8, 35, 3743, 61666, 65485, + 65531, 65533, 65535, 0, 2, 4, 6, 8, 10, 23, + 109, 683, 6905, 58417, 64911, 65398, 65497, 65518, 65525, 65527, + 65529, 65531, 65533, 65535, 0, 2, 4, 6, 53, 510, + 10209, 55212, 64573, 65441, 65522, 65529, 65531, 65533, 65535, 0, + 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, + 22, 32, 90, 266, 1037, 3349, 14468, 50488, 62394, 64685, + 65341, 65480, 65514, 65519, 65521, 65523, 65525, 65527, 65529, 65531, + 65533, 65535, 0, 2, 4, 6, 9, 16, 37, 106, + 296, 748, 1868, 5733, 18897, 45553, 60165, 63949, 64926, 65314, + 65441, 65508, 65524, 65529, 65531, 65533, 65535, 0, 2, 4, + 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, + 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, + 46, 48, 50, 83, 175, 344, 667, 1293, 2337, 4357, + 8033, 14988, 28600, 43244, 52011, 57042, 59980, 61779, 63065, 63869, + 64390, 64753, 64988, 65164, 65326, 65422, 65462, 65492, 65506, 65522, + 65524, 65526, 65531, 65533, 65535, 0, 2, 4, 6, 8, + 10, 12, 14, 16, 25, 39, 48, 55, 62, 65, + 85, 106, 139, 169, 194, 252, 323, 485, 688, 1074, + 1600, 2544, 3863, 5733, 8303, 11397, 15529, 20273, 25734, 31455, + 36853, 41891, 46410, 50306, 53702, 56503, 58673, 60479, 61880, 62989, + 63748, 64404, 64852, 65124, 65309, 65424, 65480, 65524, 65528, 65533, + 65535, 0, 2, 4, 6, 8, 10, 12, 14, 21, + 23, 25, 27, 29, 31, 39, 41, 43, 48, 60, + 72, 79, 106, 136, 166, 187, 224, 252, 323, 381, + 427, 478, 568, 660, 783, 912, 1046, 1175, 1365, 1567, + 1768, 2024, 2347, 2659, 3049, 3529, 4033, 4623, 5281, 5925, + 6726, 7526, 8417, 9468, 10783, 12141, 13571, 15222, 16916, 18659, + 20350, 22020, 23725, 25497, 27201, 29026, 30867, 32632, 34323, 36062, + 37829, 39466, 41144, 42654, 43981, 45343, 46579, 47759, 49013, 50171, + 51249, 52283, 53245, 54148, 54938, 55669, 56421, 57109, 57791, 58464, + 59092, 59674, 60105, 60653, 61083, 61407, 61757, 62095, 62388, 62649, + 62873, 63157, 63358, 63540, 63725, 63884, 64046, 64155, 64278, 64426, + 64548, 64654, 64806, 64906, 64994, 65077, 65137, 65215, 65277, 65324, + 65354, 65409, 65437, 65455, 65462, 65490, 65495, 65499, 65508, 65511, + 65513, 65515, 65517, 65519, 65521, 65523, 65525, 65527, 65529, 65531, + 65533, 65535 +}; + +const WebRtc_UWord16 WebRtcIsacfix_kCdfShape[2059] = { + 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, 0, 65535, 0, 65535, + 0, 65535, 0, 65535, 0, 65533, 65535, 0, 65535, 0, + 65535, 0, 65535, 0, 65533, 65535, 0, 2, 65535, 0, + 2, 65533, 65535, 0, 2, 65533, 65535, 0, 2, 65533, + 65535, 0, 2, 4, 65533, 65535, 0, 2, 65533, 65535, + 0, 2, 4, 65531, 65533, 65535, 0, 2, 4, 65531, + 65533, 65535, 0, 2, 4, 6, 65524, 65533, 65535, 0, + 65535, 0, 65535, 0, 65535, 0, 65535, 0, 65535, 0, + 65535, 0, 65535, 0, 65535, 0, 65533, 65535, 0, 65533, + 65535, 0, 2, 65533, 65535, 0, 2, 65533, 65535, 0, + 2, 65533, 65535, 0, 2, 4, 65532, 65535, 0, 6, + 65523, 65535, 0, 2, 15, 65530, 65533, 65535, 0, 2, + 35, 65493, 65531, 65533, 65535, 0, 2, 4, 158, 65382, + 65531, 65533, 65535, 0, 65535, 0, 65535, 0, 65535, 0, + 65535, 0, 65535, 0, 65535, 0, 2, 65535, 0, 2, + 65533, 65535, 0, 2, 65533, 65535, 0, 2, 65533, 65535, + 0, 2, 65533, 65535, 0, 9, 65512, 65535, 0, 2, + 12, 65529, 65535, 0, 2, 73, 65434, 65533, 65535, 0, + 2, 240, 65343, 65533, 65535, 0, 2, 476, 65017, 65531, + 65533, 65535, 0, 2, 4, 1046, 64686, 65531, 65533, 65535, + 0, 2, 4, 6, 8, 1870, 63898, 65529, 65531, 65533, + 65535, 0, 65535, 0, 65535, 0, 65535, 0, 65533, 65535, + 0, 2, 65533, 65535, 0, 2, 65533, 65535, 0, 2, + 65532, 65535, 0, 6, 65533, 65535, 0, 6, 65523, 65535, + 0, 2, 65532, 65535, 0, 137, 65439, 65535, 0, 576, + 64899, 65533, 65535, 0, 2, 289, 65299, 65533, 65535, 0, + 2, 4, 6, 880, 64134, 65531, 65533, 65535, 0, 2, + 4, 1853, 63347, 65533, 65535, 0, 2, 6, 2516, 61762, + 65529, 65531, 65533, 65535, 0, 2, 4, 9, 3980, 61380, + 65503, 65529, 65531, 65533, 65535, 0, 2, 4, 6, 8, + 10, 12, 61, 6393, 59859, 65466, 65527, 65529, 65531, 65533, + 65535, 0, 65535, 0, 65535, 0, 65535, 0, 2, 65532, + 65535, 0, 3, 65529, 65535, 0, 2, 65529, 65535, 0, + 61, 65453, 65535, 0, 234, 65313, 65535, 0, 503, 65138, + 65535, 0, 155, 65402, 65533, 65535, 0, 2, 1058, 64554, + 65533, 65535, 0, 2, 4, 3138, 62109, 65531, 65533, 65535, + 0, 2, 4, 2031, 63339, 65531, 65533, 65535, 0, 2, + 4, 6, 9, 4155, 60778, 65523, 65529, 65531, 65533, 65535, + 0, 2, 4, 41, 6189, 59269, 65490, 65531, 65533, 65535, + 0, 2, 4, 6, 210, 8789, 57043, 65400, 65528, 65531, + 65533, 65535, 0, 2, 4, 6, 8, 26, 453, 10086, + 55499, 64948, 65483, 65524, 65527, 65529, 65531, 65533, 65535, 0, + 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, + 114, 1014, 11202, 52670, 64226, 65356, 65503, 65514, 65523, 65525, + 65527, 65529, 65531, 65533, 65535, 0, 65533, 65535, 0, 15, + 65301, 65535, 0, 152, 64807, 65535, 0, 2, 3328, 63308, + 65535, 0, 2, 4050, 59730, 65533, 65535, 0, 2, 164, + 10564, 61894, 65529, 65535, 0, 15, 6712, 59831, 65076, 65532, + 65535, 0, 32, 7712, 57449, 65459, 65535, 0, 2, 210, + 7849, 53110, 65021, 65523, 65535, 0, 2, 12, 1081, 13883, + 48262, 62870, 65477, 65535, 0, 2, 88, 847, 6145, 37852, + 62012, 65454, 65533, 65535, 0, 9, 47, 207, 1823, 14522, + 45521, 61069, 64891, 65481, 65528, 65531, 65533, 65535, 0, 2, + 9, 488, 2881, 12758, 38703, 58412, 64420, 65410, 65533, 65535, + 0, 2, 4, 6, 61, 333, 1891, 6486, 19720, 43188, + 57547, 62472, 64796, 65421, 65497, 65523, 65529, 65531, 65533, 65535, + 0, 2, 4, 6, 8, 10, 12, 29, 117, 447, + 1528, 6138, 21242, 43133, 56495, 62432, 64746, 65362, 65500, 65529, + 65531, 65533, 65535, 0, 2, 18, 105, 301, 760, 1490, + 3472, 7568, 15002, 26424, 40330, 53029, 60048, 62964, 64274, 64890, + 65337, 65445, 65489, 65513, 65527, 65530, 65533, 65535, 0, 2, + 4, 6, 41, 102, 409, 853, 2031, 4316, 7302, 11328, + 16869, 24825, 34926, 43481, 50877, 56126, 59874, 62103, 63281, 63857, + 64166, 64675, 65382, 65522, 65531, 65533, 65535, 0, 2, 4, + 6, 8, 10, 12, 14, 16, 18, 29, 38, 53, + 58, 96, 181, 503, 1183, 2849, 5590, 8600, 11379, 13942, + 16478, 19453, 22638, 26039, 29411, 32921, 37596, 41433, 44998, 48560, + 51979, 55106, 57666, 59892, 61485, 62616, 63484, 64018, 64375, 64685, + 64924, 65076, 65278, 65395, 65471, 65509, 65529, 65535, 0, 65535, + 0, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 65535, + 0, 65535, 0, 65535, 0, 2, 65533, 65535, 0, 2, + 65533, 65535, 0, 2, 65533, 65535, 0, 2, 65533, 65535, + 0, 2, 65533, 65535, 0, 2, 65533, 65535, 0, 7, + 65519, 65535, 0, 2, 14, 65491, 65533, 65535, 0, 2, + 81, 65427, 65531, 65533, 65535, 0, 2, 4, 312, 65293, + 65528, 65533, 65535, 0, 65535, 0, 65535, 0, 65535, 0, + 65535, 0, 65535, 0, 65535, 0, 65535, 0, 65535, 0, + 2, 65533, 65535, 0, 2, 65533, 65535, 0, 2, 65533, + 65535, 0, 5, 65523, 65535, 0, 2, 65533, 65535, 0, + 7, 65526, 65535, 0, 46, 65464, 65533, 65535, 0, 2, + 120, 65309, 65533, 65535, 0, 2, 5, 362, 65097, 65533, + 65535, 0, 2, 18, 1164, 64785, 65528, 65531, 65533, 65535, + 0, 65535, 0, 65535, 0, 65535, 0, 65533, 65535, 0, + 65535, 0, 65533, 65535, 0, 2, 65533, 65535, 0, 2, + 65533, 65535, 0, 2, 65533, 65535, 0, 2, 65530, 65535, + 0, 2, 65523, 65535, 0, 69, 65477, 65535, 0, 141, + 65459, 65535, 0, 194, 65325, 65533, 65535, 0, 2, 543, + 64912, 65533, 65535, 0, 5, 1270, 64301, 65529, 65531, 65533, + 65535, 0, 2, 4, 12, 2055, 63538, 65508, 65531, 65533, + 65535, 0, 2, 7, 102, 3775, 61970, 65429, 65526, 65528, + 65533, 65535, 0, 65535, 0, 65535, 0, 65535, 0, 2, + 65533, 65535, 0, 2, 65535, 0, 9, 65533, 65535, 0, + 25, 65512, 65535, 0, 2, 65533, 65535, 0, 44, 65480, + 65535, 0, 48, 65475, 65535, 0, 162, 65373, 65535, 0, + 637, 64806, 65533, 65535, 0, 2, 935, 64445, 65533, 65535, + 0, 2, 4, 1662, 64083, 65533, 65535, 0, 2, 12, + 3036, 62469, 65521, 65533, 65535, 0, 2, 120, 5405, 60468, + 65469, 65531, 65533, 65535, 0, 2, 4, 18, 254, 6663, + 58999, 65272, 65528, 65533, 65535, 0, 2, 4, 9, 12, + 67, 591, 8981, 56781, 64564, 65365, 65508, 65524, 65526, 65529, + 65531, 65533, 65535, 0, 65535, 0, 65535, 0, 2, 65533, + 65535, 0, 9, 65526, 65535, 0, 14, 65503, 65535, 0, + 127, 65390, 65535, 0, 517, 64990, 65535, 0, 178, 65330, + 65535, 0, 2, 1055, 64533, 65533, 65535, 0, 2, 1558, + 63942, 65533, 65535, 0, 2, 2205, 63173, 65533, 65535, 0, + 25, 4493, 60862, 65505, 65533, 65535, 0, 2, 48, 5890, + 59442, 65482, 65533, 65535, 0, 2, 4, 127, 7532, 58191, + 65394, 65533, 65535, 0, 2, 5, 32, 550, 10388, 54924, + 65046, 65510, 65531, 65533, 65535, 0, 2, 4, 30, 150, + 1685, 14340, 51375, 63619, 65288, 65503, 65528, 65533, 65535, 0, + 2, 4, 6, 8, 28, 97, 473, 2692, 15407, 50020, + 62880, 65064, 65445, 65508, 65531, 65533, 65535, 0, 2, 4, + 12, 32, 79, 150, 372, 907, 2184, 5868, 18207, 45431, + 59856, 64031, 65096, 65401, 65481, 65507, 65521, 65523, 65525, 65527, + 65529, 65531, 65533, 65535, 0, 65533, 65535, 0, 182, 65491, + 65535, 0, 877, 64286, 65535, 0, 9, 2708, 63612, 65533, + 65535, 0, 2, 6038, 59532, 65535, 0, 2, 92, 5500, + 60539, 65533, 65535, 0, 268, 8908, 56512, 65385, 65535, 0, + 129, 13110, 52742, 65036, 65535, 0, 2, 806, 14003, 51929, + 64732, 65523, 65535, 0, 7, 92, 2667, 18159, 47678, 62610, + 65355, 65535, 0, 32, 1836, 19676, 48237, 61677, 64960, 65526, + 65535, 0, 21, 159, 967, 5668, 22782, 44709, 58317, 64020, + 65406, 65528, 65535, 0, 7, 162, 1838, 8328, 23929, 43014, + 56394, 63374, 65216, 65484, 65521, 65535, 0, 2, 4, 6, + 28, 268, 1120, 3613, 10688, 24185, 40989, 54917, 61684, 64510, + 65403, 65530, 65535, 0, 2, 16, 44, 139, 492, 1739, + 5313, 13558, 26766, 41566, 52446, 58937, 62815, 64480, 65201, 65454, + 65524, 65533, 65535, 0, 7, 25, 76, 263, 612, 1466, + 3325, 6832, 12366, 20152, 29466, 39255, 47360, 53506, 57740, 60726, + 62845, 64131, 64882, 65260, 65459, 65521, 65528, 65530, 65535, 0, + 2, 4, 14, 48, 136, 312, 653, 1240, 2369, 4327, + 7028, 10759, 15449, 21235, 28027, 35386, 42938, 49562, 54990, 59119, + 62086, 63916, 64863, 65249, 65445, 65493, 65523, 65535, 0, 2, + 4, 6, 8, 10, 12, 21, 83, 208, 409, 723, + 1152, 1868, 2951, 4463, 6460, 8979, 11831, 15195, 18863, 22657, + 26762, 30881, 34963, 39098, 43054, 47069, 50620, 53871, 56821, 59386, + 61340, 62670, 63512, 64023, 64429, 64750, 64944, 65126, 65279, 65366, + 65413, 65445, 65473, 65505, 65510, 65521, 65528, 65530, 65535 +}; + +/* pointers to cdf tables for quantizer indices */ +const WebRtc_UWord16 *WebRtcIsacfix_kCdfGainPtr[3][12] = { + { WebRtcIsacfix_kCdfGain +0 +0, WebRtcIsacfix_kCdfGain +0 +8, WebRtcIsacfix_kCdfGain +0 +22, + WebRtcIsacfix_kCdfGain +0 +32, WebRtcIsacfix_kCdfGain +0 +48, WebRtcIsacfix_kCdfGain +0 +60, + WebRtcIsacfix_kCdfGain +0 +81, WebRtcIsacfix_kCdfGain +0 +95, WebRtcIsacfix_kCdfGain +0 +128, + WebRtcIsacfix_kCdfGain +0 +152, WebRtcIsacfix_kCdfGain +0 +210, WebRtcIsacfix_kCdfGain +0 +264 + }, + { WebRtcIsacfix_kCdfGain +404 +0, WebRtcIsacfix_kCdfGain +404 +8, WebRtcIsacfix_kCdfGain +404 +21, + WebRtcIsacfix_kCdfGain +404 +30, WebRtcIsacfix_kCdfGain +404 +46, WebRtcIsacfix_kCdfGain +404 +58, + WebRtcIsacfix_kCdfGain +404 +79, WebRtcIsacfix_kCdfGain +404 +93, WebRtcIsacfix_kCdfGain +404 +125, + WebRtcIsacfix_kCdfGain +404 +149, WebRtcIsacfix_kCdfGain +404 +207, WebRtcIsacfix_kCdfGain +404 +260 + }, + { WebRtcIsacfix_kCdfGain +803 +0, WebRtcIsacfix_kCdfGain +803 +8, WebRtcIsacfix_kCdfGain +803 +22, + WebRtcIsacfix_kCdfGain +803 +31, WebRtcIsacfix_kCdfGain +803 +48, WebRtcIsacfix_kCdfGain +803 +60, + WebRtcIsacfix_kCdfGain +803 +81, WebRtcIsacfix_kCdfGain +803 +96, WebRtcIsacfix_kCdfGain +803 +129, + WebRtcIsacfix_kCdfGain +803 +154, WebRtcIsacfix_kCdfGain +803 +212, WebRtcIsacfix_kCdfGain +803 +268 + } +}; + +const WebRtc_UWord16 *WebRtcIsacfix_kCdfShapePtr[3][108] = { + { WebRtcIsacfix_kCdfShape +0 +0, WebRtcIsacfix_kCdfShape +0 +2, WebRtcIsacfix_kCdfShape +0 +4, + WebRtcIsacfix_kCdfShape +0 +6, WebRtcIsacfix_kCdfShape +0 +8, WebRtcIsacfix_kCdfShape +0 +10, + WebRtcIsacfix_kCdfShape +0 +12, WebRtcIsacfix_kCdfShape +0 +14, WebRtcIsacfix_kCdfShape +0 +16, + WebRtcIsacfix_kCdfShape +0 +18, WebRtcIsacfix_kCdfShape +0 +21, WebRtcIsacfix_kCdfShape +0 +25, + WebRtcIsacfix_kCdfShape +0 +29, WebRtcIsacfix_kCdfShape +0 +33, WebRtcIsacfix_kCdfShape +0 +37, + WebRtcIsacfix_kCdfShape +0 +43, WebRtcIsacfix_kCdfShape +0 +49, WebRtcIsacfix_kCdfShape +0 +56, + WebRtcIsacfix_kCdfShape +0 +64, WebRtcIsacfix_kCdfShape +0 +66, WebRtcIsacfix_kCdfShape +0 +68, + WebRtcIsacfix_kCdfShape +0 +70, WebRtcIsacfix_kCdfShape +0 +72, WebRtcIsacfix_kCdfShape +0 +75, + WebRtcIsacfix_kCdfShape +0 +77, WebRtcIsacfix_kCdfShape +0 +79, WebRtcIsacfix_kCdfShape +0 +81, + WebRtcIsacfix_kCdfShape +0 +83, WebRtcIsacfix_kCdfShape +0 +86, WebRtcIsacfix_kCdfShape +0 +90, + WebRtcIsacfix_kCdfShape +0 +94, WebRtcIsacfix_kCdfShape +0 +98, WebRtcIsacfix_kCdfShape +0 +102, + WebRtcIsacfix_kCdfShape +0 +107, WebRtcIsacfix_kCdfShape +0 +113, WebRtcIsacfix_kCdfShape +0 +120, + WebRtcIsacfix_kCdfShape +0 +129, WebRtcIsacfix_kCdfShape +0 +131, WebRtcIsacfix_kCdfShape +0 +133, + WebRtcIsacfix_kCdfShape +0 +135, WebRtcIsacfix_kCdfShape +0 +137, WebRtcIsacfix_kCdfShape +0 +141, + WebRtcIsacfix_kCdfShape +0 +143, WebRtcIsacfix_kCdfShape +0 +147, WebRtcIsacfix_kCdfShape +0 +151, + WebRtcIsacfix_kCdfShape +0 +155, WebRtcIsacfix_kCdfShape +0 +159, WebRtcIsacfix_kCdfShape +0 +164, + WebRtcIsacfix_kCdfShape +0 +168, WebRtcIsacfix_kCdfShape +0 +172, WebRtcIsacfix_kCdfShape +0 +178, + WebRtcIsacfix_kCdfShape +0 +184, WebRtcIsacfix_kCdfShape +0 +192, WebRtcIsacfix_kCdfShape +0 +200, + WebRtcIsacfix_kCdfShape +0 +211, WebRtcIsacfix_kCdfShape +0 +213, WebRtcIsacfix_kCdfShape +0 +215, + WebRtcIsacfix_kCdfShape +0 +217, WebRtcIsacfix_kCdfShape +0 +219, WebRtcIsacfix_kCdfShape +0 +223, + WebRtcIsacfix_kCdfShape +0 +227, WebRtcIsacfix_kCdfShape +0 +231, WebRtcIsacfix_kCdfShape +0 +235, + WebRtcIsacfix_kCdfShape +0 +239, WebRtcIsacfix_kCdfShape +0 +243, WebRtcIsacfix_kCdfShape +0 +248, + WebRtcIsacfix_kCdfShape +0 +252, WebRtcIsacfix_kCdfShape +0 +258, WebRtcIsacfix_kCdfShape +0 +264, + WebRtcIsacfix_kCdfShape +0 +273, WebRtcIsacfix_kCdfShape +0 +282, WebRtcIsacfix_kCdfShape +0 +293, + WebRtcIsacfix_kCdfShape +0 +308, WebRtcIsacfix_kCdfShape +0 +310, WebRtcIsacfix_kCdfShape +0 +312, + WebRtcIsacfix_kCdfShape +0 +316, WebRtcIsacfix_kCdfShape +0 +320, WebRtcIsacfix_kCdfShape +0 +324, + WebRtcIsacfix_kCdfShape +0 +328, WebRtcIsacfix_kCdfShape +0 +332, WebRtcIsacfix_kCdfShape +0 +336, + WebRtcIsacfix_kCdfShape +0 +341, WebRtcIsacfix_kCdfShape +0 +347, WebRtcIsacfix_kCdfShape +0 +354, + WebRtcIsacfix_kCdfShape +0 +360, WebRtcIsacfix_kCdfShape +0 +368, WebRtcIsacfix_kCdfShape +0 +378, + WebRtcIsacfix_kCdfShape +0 +388, WebRtcIsacfix_kCdfShape +0 +400, WebRtcIsacfix_kCdfShape +0 +418, + WebRtcIsacfix_kCdfShape +0 +445, WebRtcIsacfix_kCdfShape +0 +447, WebRtcIsacfix_kCdfShape +0 +451, + WebRtcIsacfix_kCdfShape +0 +455, WebRtcIsacfix_kCdfShape +0 +461, WebRtcIsacfix_kCdfShape +0 +468, + WebRtcIsacfix_kCdfShape +0 +474, WebRtcIsacfix_kCdfShape +0 +480, WebRtcIsacfix_kCdfShape +0 +486, + WebRtcIsacfix_kCdfShape +0 +495, WebRtcIsacfix_kCdfShape +0 +505, WebRtcIsacfix_kCdfShape +0 +516, + WebRtcIsacfix_kCdfShape +0 +528, WebRtcIsacfix_kCdfShape +0 +543, WebRtcIsacfix_kCdfShape +0 +564, + WebRtcIsacfix_kCdfShape +0 +583, WebRtcIsacfix_kCdfShape +0 +608, WebRtcIsacfix_kCdfShape +0 +635 + }, + { WebRtcIsacfix_kCdfShape +686 +0, WebRtcIsacfix_kCdfShape +686 +2, WebRtcIsacfix_kCdfShape +686 +4, + WebRtcIsacfix_kCdfShape +686 +6, WebRtcIsacfix_kCdfShape +686 +8, WebRtcIsacfix_kCdfShape +686 +11, + WebRtcIsacfix_kCdfShape +686 +13, WebRtcIsacfix_kCdfShape +686 +15, WebRtcIsacfix_kCdfShape +686 +17, + WebRtcIsacfix_kCdfShape +686 +20, WebRtcIsacfix_kCdfShape +686 +23, WebRtcIsacfix_kCdfShape +686 +27, + WebRtcIsacfix_kCdfShape +686 +31, WebRtcIsacfix_kCdfShape +686 +35, WebRtcIsacfix_kCdfShape +686 +40, + WebRtcIsacfix_kCdfShape +686 +44, WebRtcIsacfix_kCdfShape +686 +50, WebRtcIsacfix_kCdfShape +686 +56, + WebRtcIsacfix_kCdfShape +686 +63, WebRtcIsacfix_kCdfShape +686 +65, WebRtcIsacfix_kCdfShape +686 +67, + WebRtcIsacfix_kCdfShape +686 +69, WebRtcIsacfix_kCdfShape +686 +71, WebRtcIsacfix_kCdfShape +686 +73, + WebRtcIsacfix_kCdfShape +686 +75, WebRtcIsacfix_kCdfShape +686 +77, WebRtcIsacfix_kCdfShape +686 +79, + WebRtcIsacfix_kCdfShape +686 +82, WebRtcIsacfix_kCdfShape +686 +85, WebRtcIsacfix_kCdfShape +686 +89, + WebRtcIsacfix_kCdfShape +686 +93, WebRtcIsacfix_kCdfShape +686 +97, WebRtcIsacfix_kCdfShape +686 +102, + WebRtcIsacfix_kCdfShape +686 +106, WebRtcIsacfix_kCdfShape +686 +112, WebRtcIsacfix_kCdfShape +686 +119, + WebRtcIsacfix_kCdfShape +686 +127, WebRtcIsacfix_kCdfShape +686 +129, WebRtcIsacfix_kCdfShape +686 +131, + WebRtcIsacfix_kCdfShape +686 +133, WebRtcIsacfix_kCdfShape +686 +135, WebRtcIsacfix_kCdfShape +686 +137, + WebRtcIsacfix_kCdfShape +686 +139, WebRtcIsacfix_kCdfShape +686 +142, WebRtcIsacfix_kCdfShape +686 +146, + WebRtcIsacfix_kCdfShape +686 +150, WebRtcIsacfix_kCdfShape +686 +154, WebRtcIsacfix_kCdfShape +686 +158, + WebRtcIsacfix_kCdfShape +686 +162, WebRtcIsacfix_kCdfShape +686 +167, WebRtcIsacfix_kCdfShape +686 +173, + WebRtcIsacfix_kCdfShape +686 +179, WebRtcIsacfix_kCdfShape +686 +186, WebRtcIsacfix_kCdfShape +686 +194, + WebRtcIsacfix_kCdfShape +686 +205, WebRtcIsacfix_kCdfShape +686 +207, WebRtcIsacfix_kCdfShape +686 +209, + WebRtcIsacfix_kCdfShape +686 +211, WebRtcIsacfix_kCdfShape +686 +214, WebRtcIsacfix_kCdfShape +686 +218, + WebRtcIsacfix_kCdfShape +686 +222, WebRtcIsacfix_kCdfShape +686 +226, WebRtcIsacfix_kCdfShape +686 +230, + WebRtcIsacfix_kCdfShape +686 +234, WebRtcIsacfix_kCdfShape +686 +238, WebRtcIsacfix_kCdfShape +686 +242, + WebRtcIsacfix_kCdfShape +686 +247, WebRtcIsacfix_kCdfShape +686 +253, WebRtcIsacfix_kCdfShape +686 +262, + WebRtcIsacfix_kCdfShape +686 +269, WebRtcIsacfix_kCdfShape +686 +278, WebRtcIsacfix_kCdfShape +686 +289, + WebRtcIsacfix_kCdfShape +686 +305, WebRtcIsacfix_kCdfShape +686 +307, WebRtcIsacfix_kCdfShape +686 +309, + WebRtcIsacfix_kCdfShape +686 +311, WebRtcIsacfix_kCdfShape +686 +315, WebRtcIsacfix_kCdfShape +686 +319, + WebRtcIsacfix_kCdfShape +686 +323, WebRtcIsacfix_kCdfShape +686 +327, WebRtcIsacfix_kCdfShape +686 +331, + WebRtcIsacfix_kCdfShape +686 +335, WebRtcIsacfix_kCdfShape +686 +340, WebRtcIsacfix_kCdfShape +686 +346, + WebRtcIsacfix_kCdfShape +686 +354, WebRtcIsacfix_kCdfShape +686 +362, WebRtcIsacfix_kCdfShape +686 +374, + WebRtcIsacfix_kCdfShape +686 +384, WebRtcIsacfix_kCdfShape +686 +396, WebRtcIsacfix_kCdfShape +686 +413, + WebRtcIsacfix_kCdfShape +686 +439, WebRtcIsacfix_kCdfShape +686 +442, WebRtcIsacfix_kCdfShape +686 +446, + WebRtcIsacfix_kCdfShape +686 +450, WebRtcIsacfix_kCdfShape +686 +455, WebRtcIsacfix_kCdfShape +686 +461, + WebRtcIsacfix_kCdfShape +686 +468, WebRtcIsacfix_kCdfShape +686 +475, WebRtcIsacfix_kCdfShape +686 +481, + WebRtcIsacfix_kCdfShape +686 +489, WebRtcIsacfix_kCdfShape +686 +498, WebRtcIsacfix_kCdfShape +686 +508, + WebRtcIsacfix_kCdfShape +686 +522, WebRtcIsacfix_kCdfShape +686 +534, WebRtcIsacfix_kCdfShape +686 +554, + WebRtcIsacfix_kCdfShape +686 +577, WebRtcIsacfix_kCdfShape +686 +602, WebRtcIsacfix_kCdfShape +686 +631 + }, + { WebRtcIsacfix_kCdfShape +1368 +0, WebRtcIsacfix_kCdfShape +1368 +2, WebRtcIsacfix_kCdfShape +1368 +4, + WebRtcIsacfix_kCdfShape +1368 +6, WebRtcIsacfix_kCdfShape +1368 +8, WebRtcIsacfix_kCdfShape +1368 +10, + WebRtcIsacfix_kCdfShape +1368 +12, WebRtcIsacfix_kCdfShape +1368 +14, WebRtcIsacfix_kCdfShape +1368 +16, + WebRtcIsacfix_kCdfShape +1368 +20, WebRtcIsacfix_kCdfShape +1368 +24, WebRtcIsacfix_kCdfShape +1368 +28, + WebRtcIsacfix_kCdfShape +1368 +32, WebRtcIsacfix_kCdfShape +1368 +36, WebRtcIsacfix_kCdfShape +1368 +40, + WebRtcIsacfix_kCdfShape +1368 +44, WebRtcIsacfix_kCdfShape +1368 +50, WebRtcIsacfix_kCdfShape +1368 +57, + WebRtcIsacfix_kCdfShape +1368 +65, WebRtcIsacfix_kCdfShape +1368 +67, WebRtcIsacfix_kCdfShape +1368 +69, + WebRtcIsacfix_kCdfShape +1368 +71, WebRtcIsacfix_kCdfShape +1368 +73, WebRtcIsacfix_kCdfShape +1368 +75, + WebRtcIsacfix_kCdfShape +1368 +77, WebRtcIsacfix_kCdfShape +1368 +79, WebRtcIsacfix_kCdfShape +1368 +81, + WebRtcIsacfix_kCdfShape +1368 +85, WebRtcIsacfix_kCdfShape +1368 +89, WebRtcIsacfix_kCdfShape +1368 +93, + WebRtcIsacfix_kCdfShape +1368 +97, WebRtcIsacfix_kCdfShape +1368 +101, WebRtcIsacfix_kCdfShape +1368 +105, + WebRtcIsacfix_kCdfShape +1368 +110, WebRtcIsacfix_kCdfShape +1368 +116, WebRtcIsacfix_kCdfShape +1368 +123, + WebRtcIsacfix_kCdfShape +1368 +132, WebRtcIsacfix_kCdfShape +1368 +134, WebRtcIsacfix_kCdfShape +1368 +136, + WebRtcIsacfix_kCdfShape +1368 +138, WebRtcIsacfix_kCdfShape +1368 +141, WebRtcIsacfix_kCdfShape +1368 +143, + WebRtcIsacfix_kCdfShape +1368 +146, WebRtcIsacfix_kCdfShape +1368 +150, WebRtcIsacfix_kCdfShape +1368 +154, + WebRtcIsacfix_kCdfShape +1368 +158, WebRtcIsacfix_kCdfShape +1368 +162, WebRtcIsacfix_kCdfShape +1368 +166, + WebRtcIsacfix_kCdfShape +1368 +170, WebRtcIsacfix_kCdfShape +1368 +174, WebRtcIsacfix_kCdfShape +1368 +179, + WebRtcIsacfix_kCdfShape +1368 +185, WebRtcIsacfix_kCdfShape +1368 +193, WebRtcIsacfix_kCdfShape +1368 +203, + WebRtcIsacfix_kCdfShape +1368 +214, WebRtcIsacfix_kCdfShape +1368 +216, WebRtcIsacfix_kCdfShape +1368 +218, + WebRtcIsacfix_kCdfShape +1368 +220, WebRtcIsacfix_kCdfShape +1368 +224, WebRtcIsacfix_kCdfShape +1368 +227, + WebRtcIsacfix_kCdfShape +1368 +231, WebRtcIsacfix_kCdfShape +1368 +235, WebRtcIsacfix_kCdfShape +1368 +239, + WebRtcIsacfix_kCdfShape +1368 +243, WebRtcIsacfix_kCdfShape +1368 +247, WebRtcIsacfix_kCdfShape +1368 +251, + WebRtcIsacfix_kCdfShape +1368 +256, WebRtcIsacfix_kCdfShape +1368 +262, WebRtcIsacfix_kCdfShape +1368 +269, + WebRtcIsacfix_kCdfShape +1368 +277, WebRtcIsacfix_kCdfShape +1368 +286, WebRtcIsacfix_kCdfShape +1368 +297, + WebRtcIsacfix_kCdfShape +1368 +315, WebRtcIsacfix_kCdfShape +1368 +317, WebRtcIsacfix_kCdfShape +1368 +319, + WebRtcIsacfix_kCdfShape +1368 +323, WebRtcIsacfix_kCdfShape +1368 +327, WebRtcIsacfix_kCdfShape +1368 +331, + WebRtcIsacfix_kCdfShape +1368 +335, WebRtcIsacfix_kCdfShape +1368 +339, WebRtcIsacfix_kCdfShape +1368 +343, + WebRtcIsacfix_kCdfShape +1368 +349, WebRtcIsacfix_kCdfShape +1368 +355, WebRtcIsacfix_kCdfShape +1368 +361, + WebRtcIsacfix_kCdfShape +1368 +368, WebRtcIsacfix_kCdfShape +1368 +376, WebRtcIsacfix_kCdfShape +1368 +385, + WebRtcIsacfix_kCdfShape +1368 +397, WebRtcIsacfix_kCdfShape +1368 +411, WebRtcIsacfix_kCdfShape +1368 +429, + WebRtcIsacfix_kCdfShape +1368 +456, WebRtcIsacfix_kCdfShape +1368 +459, WebRtcIsacfix_kCdfShape +1368 +463, + WebRtcIsacfix_kCdfShape +1368 +467, WebRtcIsacfix_kCdfShape +1368 +473, WebRtcIsacfix_kCdfShape +1368 +478, + WebRtcIsacfix_kCdfShape +1368 +485, WebRtcIsacfix_kCdfShape +1368 +491, WebRtcIsacfix_kCdfShape +1368 +497, + WebRtcIsacfix_kCdfShape +1368 +505, WebRtcIsacfix_kCdfShape +1368 +514, WebRtcIsacfix_kCdfShape +1368 +523, + WebRtcIsacfix_kCdfShape +1368 +535, WebRtcIsacfix_kCdfShape +1368 +548, WebRtcIsacfix_kCdfShape +1368 +565, + WebRtcIsacfix_kCdfShape +1368 +585, WebRtcIsacfix_kCdfShape +1368 +611, WebRtcIsacfix_kCdfShape +1368 +640 + } +}; + +/* code length for all coefficients using different models */ + +const WebRtc_Word16 WebRtcIsacfix_kCodeLenGainQ11[392] = { + 25189, 16036, 8717, 358, 8757, 15706, 21456, 24397, 18502, 17559 + , 13794, 11088, 7480, 873, 6603, 11636, 14627, 16805, 19132, 26624 + , 26624, 19408, 13751, 7280, 583, 7591, 15178, 23773, 28672, 25189 + , 19045, 16442, 13412, 10397, 5893, 1338, 6376, 9992, 12074, 13853 + , 15781, 19821, 22819, 28672, 28672, 25189, 19858, 15781, 11262, 5477 + , 1298, 5632, 11814, 17234, 22020, 28672, 19677, 18125, 16587, 14521 + , 13032, 11196, 9249, 5411, 2495, 4994, 7975, 10234, 12308, 13892 + , 15148, 17944, 21725, 23917, 25189, 19539, 16293, 11531, 7808, 4475 + , 2739, 4872, 8089, 11314, 14992, 18105, 23257, 26624, 25189, 23257 + , 23257, 20982, 18697, 18023, 16338, 16036, 14539, 13695, 13146, 11763 + , 10754, 9074, 7260, 5584, 4430, 5553, 6848, 8344, 10141, 11636 + , 12535, 13416, 14342, 15477, 17296, 19282, 22349, 23773, 28672, 28672 + , 26624, 23773, 21456, 18023, 15118, 13362, 11212, 9293, 8043, 6985 + , 5908, 5721, 5853, 6518, 7316, 8360, 9716, 11289, 12912, 14652 + , 16969, 19858, 23773, 26624, 28013, 30720, 30720, 28672, 25426, 23141 + , 25426, 23773, 20720, 19408, 18697, 19282, 16859, 16338, 16026, 15377 + , 15021, 14319, 14251, 13937, 13260, 13017, 12332, 11703, 11430, 10359 + , 10128, 9405, 8757, 8223, 7974, 7859, 7646, 7673, 7997, 8580 + , 8880, 9061, 9866, 10397, 11358, 12200, 13244, 14157, 15021, 16026 + , 16490, 18697, 18479, 20011, 19677, 20720, 24576, 26276, 30720, 30720 + , 28672, 30720, 24068, 25189, 22437, 20345, 18479, 16396, 16026, 14928 + , 13877, 13450, 12696, 12766, 11626, 11098, 10159, 9998, 9437, 9275 + , 8783, 8552, 8629, 8488, 8522, 8454, 8571, 8775, 8915, 9427 + , 9483, 9851, 10260, 10933, 11131, 11974, 12560, 13833, 15080, 16304 + , 17491, 19017, 18697, 19408, 22020, 25189, 25426, 22819, 26276, 30720 + , 30720, 30720, 30720, 30720, 30720, 28672, 30720, 30720, 30720, 30720 + , 28013, 25426, 24397, 23773, 25189, 26624, 25189, 22437, 21725, 20011 + , 20527, 20720, 20771, 22020, 22020, 19858, 19408, 19972, 17866, 17360 + , 17791, 17219, 16805, 16927, 16067, 16162, 15661, 15178, 15021, 15209 + , 14845, 14570, 14490, 14490, 13733, 13617, 13794, 13577, 13312, 12824 + , 13032, 12683, 12189, 12469, 12109, 11940, 11636, 11617, 11932, 12294 + , 11578, 11775, 12039, 11654, 11560, 11439, 11909, 11421, 12029, 11513 + , 11773, 11899, 11560, 11805, 11476, 11664, 11963, 11647, 11754, 11963 + , 11703, 12211, 11932, 12074, 12469, 12535, 12560, 12912, 12783, 12866 + , 12884, 13378, 13957, 13775, 13635, 14019, 14545, 15240, 15520, 15554 + , 15697, 16490, 16396, 17281, 16599, 16969, 17963, 16859, 16983, 16805 + , 17099, 18210, 17219, 17646, 17700, 17646, 18297, 17425, 18479, 17791 + , 17718, 19282, 18672, 20173, 20982, 21725, 21456, 23773, 23257, 25189 + , 30720, 30720, 25189, 26624, 30720, 30720, 30720, 30720, 28672, 26276 + , 30720, 30720 +}; + +const WebRtc_Word16 WebRtcIsacfix_kCodeLenShapeQ11[577] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 28672 + , 0, 26624, 1, 23773, 22819, 4, 20982, 18598, 10, 19282 + , 16587, 22, 16442, 26624, 13126, 60, 14245, 26624, 26624, 12736 + , 79, 12912, 25189, 22819, 9563, 249, 9474, 22349, 28672, 23257 + , 17944, 7980, 434, 8181, 16431, 26624, 0, 0, 0, 0 + , 28672, 0, 0, 0, 0, 0, 28672, 0, 22437, 3 + , 22437, 20982, 5, 20982, 16442, 22, 16752, 13814, 49, 14646 + , 11645, 116, 11734, 26624, 28672, 10613, 158, 11010, 24397, 19539 + , 8046, 453, 7709, 19017, 28672, 23257, 15110, 6770, 758, 6523 + , 14108, 24397, 28672, 0, 0, 0, 0, 28672, 0, 28672 + , 0, 26624, 1, 28672, 28672, 1, 26624, 24397, 2, 23257 + , 21725, 4, 20982, 17158, 18, 17281, 28672, 15178, 35, 15209 + , 12343, 92, 12320, 26624, 10344, 189, 10217, 30720, 22020, 9033 + , 322, 8549, 23773, 28672, 30720, 20622, 7666, 473, 7806, 20527 + , 24397, 14135, 5995, 960, 6018, 14872, 23773, 26624, 20928, 16293 + , 10636, 4926, 1588, 5256, 11088, 18043, 25189, 0, 0, 0 + , 0, 24397, 1, 25189, 20720, 5, 21456, 21209, 3, 25189 + , 20982, 5, 21456, 15818, 30, 15410, 13794, 60, 13416, 28672 + , 11162, 142, 11025, 9337, 231, 10094, 23773, 8338, 405, 7930 + , 26624, 19677, 6787, 613, 7318, 19161, 28672, 16442, 6319, 932 + , 5748, 15312, 25189, 28672, 28672, 28672, 13998, 5513, 1263, 5146 + , 14024, 24397, 22819, 15818, 9460, 4447, 2122, 4681, 9970, 15945 + , 22349, 28672, 30720, 22622, 19017, 14872, 10689, 7405, 4473, 2983 + , 4783, 7894, 11186, 14964, 18210, 24397, 0, 0, 30720, 0 + , 30720, 21456, 3, 23773, 14964, 39, 14757, 14179, 53, 13751 + , 14928, 36, 15272, 12430, 79, 13228, 9135, 285, 9077, 28672 + , 28672, 8377, 403, 7919, 26624, 28672, 23257, 7068, 560, 7473 + , 20345, 19677, 6770, 720, 6464, 18697, 25189, 16249, 5779, 1087 + , 5494, 15209, 22819, 30720, 20622, 12601, 5240, 1419, 5091, 12095 + , 19408, 26624, 22819, 16805, 10683, 4812, 2056, 4293, 9836, 16026 + , 24397, 25189, 18409, 13833, 8681, 4503, 2653, 4220, 8329, 13853 + , 19132, 26624, 25189, 20771, 17219, 12630, 9520, 6733, 4565, 3657 + , 4817, 7069, 10058, 13212, 16805, 21209, 26624, 26276, 28672, 28672 + , 26276, 23257, 20173, 19282, 16538, 15051, 12811, 10754, 9267, 7547 + , 6270, 5407, 5214, 6057, 7054, 8226, 9488, 10806, 12793, 14442 + , 16442, 19677, 22099, 26276, 28672, 0, 30720, 0, 30720, 11920 + , 56, 20720, 30720, 6766, 355, 13130, 30720, 30720, 22180, 5589 + , 736, 7902, 26624, 30720, 7634, 354, 9721, 30720, 30720, 9027 + , 246, 10117, 30720, 30720, 9630, 453, 6709, 23257, 30720, 25683 + , 14228, 6127, 1271, 4615, 15178, 30720, 30720, 23504, 12382, 5739 + , 2015, 3492, 10560, 22020, 26624, 30720, 30720, 23257, 13192, 4873 + , 1527, 5001, 12445, 22020, 30720, 30720, 30720, 30720, 19344, 10761 + , 4051, 1927, 5281, 10594, 17866, 28672, 30720, 30720, 30720, 21869 + , 15554, 10060, 5979, 2710, 3085, 7889, 14646, 21725, 28672, 30720 + , 30720, 30720, 30720, 30720, 30720, 30720, 22719, 17425, 13212, 8083 + , 4439, 2820, 4305, 8136, 12988, 17425, 21151, 28672, 28672, 30720 + , 30720, 30720, 28672, 20527, 19282, 14412, 10513, 7407, 5079, 3744 + , 4115, 6308, 9621, 13599, 17040, 22349, 28672, 30720, 30720, 30720 + , 30720, 30720, 30720, 29522, 19282, 14545, 11485, 9093, 6760, 5262 + , 4672, 4970, 6005, 7852, 9732, 12343, 14672, 19161, 22819, 25189 + , 30720, 30720, 28672, 30720, 30720, 20720, 18125, 14388, 12007, 9825 + , 8092, 7064, 6069, 5903, 5932, 6359, 7169, 8310, 9324, 10711 + , 11867, 13096, 14157, 16338, 17040, 19161, 21725, 23773, 30720, 30720 + , 26276, 25426, 24397, 28672, 28672, 23257, 22020, 22349, 18297, 17646 + , 16983, 16431, 16162, 15021, 15178, 13751, 12142, 10895, 10193, 9632 + , 9086, 8896, 8823, 8735, 8591, 8754, 8649, 8361, 8329, 8522 + , 8373, 8739, 8993, 9657, 10454, 11279, 11899, 12614, 14024, 14273 + , 15477, 15240, 16649, 17866, 18697, 21151, 22099 +}; + +/* left KLT transforms */ +const WebRtc_Word16 WebRtcIsacfix_kT1GainQ15[3][4] = { + { -26130, 19773, 19773, 26130 }, + { -26664, 19046, 19046, 26664 }, + { -23538, 22797, 22797, 23538 } +}; + + + +const WebRtc_Word16 WebRtcIsacfix_kT1ShapeQ15[3][324] = { + { 52,16,168,7,439,-138,-89,306,671,882, + 157,1301,291,1598,-3571,-1943,-1119,32404,96,-12, + 379,-64,-307,345,-836,539,1045,2541,-2865,-992, + 1683,-4717,5808,7427,30599,2319,183,-73,451,481, + 933,-198,781,-397,1244,-777,3690,-2414,149,-1356, + -2593,-31140,8289,-1737,-202,-14,-214,360,501,450, + -245,-7,797,3638,-2804,3042,-337,22137,-22103,2264, + 6838,-3381,305,172,263,-195,-355,351,179,513, + 2234,3343,5509,7531,19075,-17740,-16836,2244,-629,-1505, + -153,108,124,-324,2694,-124,1492,-850,5347,4285, + 7439,-10229,-22822,-12467,-12891,3645,822,-232,131,13, + 374,565,536,4681,1294,-1935,1926,-5734,-10643,26462, + -12480,-5589,-1038,-2468,964,-704,-247,-106,186,-558, + -4050,3760,2972,2141,-7393,6294,26740,11991,-3251,5461, + 5341,1574,2208,-51,-552,-297,-753,-154,2068,-5371, + 3578,4106,28043,-10533,8041,2353,2389,4609,3410,1906, + 351,-249,18,-15,1117,539,2870,9084,17585,-24528, + -366,-6490,2009,-3170,2942,1116,-232,1672,1065,606, + -399,-388,-518,38,3728,28948,-11936,4543,4104,-4441, + 1545,-4044,1485,622,-68,186,-473,135,-280,125, + -546,-1813,6989,6606,23711,19376,-2636,2870,-4553,-1687, + 878,-375,205,-208,-409,-108,-200,-45,-1670,-337, + 8213,-5524,-2334,5240,-12939,-26205,5937,-1582,-592,-959, + -5374,2449,3400,559,349,-492,668,12379,-27684,3419, + 5117,4415,-297,-8270,-1252,-3490,-1272,-1199,-3159,191, + 630,488,-797,-3071,12912,-27783,-10249,1047,647,619, + 111,-3722,-915,-1055,-502,5,-1384,-306,221,68, + 5219,13173,-26474,-11663,-5626,927,806,-1127,236,-589, + -522,-230,-312,-315,-428,-573,426,192,-11830,-26883, + -14121,-2785,-1429,-109,410,-832,-302,539,-459,104, + 1,-530,-202,-289,153,116,30082,-12944,-671,20, + 649,98,103,215,234,0,280,-51,-169,298, + 31,230,-73,-51 + }, + { -154,-7,-192,61,-739,-389,-947,-162,-60,94, + 511,-716,1520,-1428,4168,-2214,1816,32270,-123,-77, + -199,-99,-42,-588,203,-240,-930,-35,1580,234, + 3206,-5507,-1495,-10946,30000,-2667,-136,-176,-240,-175, + -204,-661,-1796,-1039,-1271,498,3143,734,2663,2699, + -8127,29333,10495,2356,-72,113,-91,118,-2840,-723, + -1733,-1158,-389,-2116,-3054,-3,-5179,8071,29546,6308, + 5657,-3178,-186,-294,-473,-635,1213,-983,-1437,-1715, + -1094,1280,-92,-9573,948,29576,-7060,-5921,2954,1349, + -337,-108,-1099,962,418,-413,-1149,-334,1241,3975, + -6825,26725,-14377,7051,-4772,-1707,2335,2008,-150,570, + 1371,42,-1649,-619,2039,3369,-1225,1583,-2755,-15207, + -27504,-4855,-4304,1495,2733,1324,15,-448,403,353, + 3016,-1242,2338,2673,2064,-7496,-30447,-3686,5833,-1301, + -2455,2122,1519,608,43,-653,773,-3072,912,-1537, + 4505,10284,30237,1549,3200,-691,205,1702,658,1014, + 1499,148,79,-322,-1162,-4639,-813,7536,3204,29109, + -10747,-26,1611,2286,2114,2561,1022,372,348,207, + 1062,-1088,-443,-9849,2381,5671,29097,-7612,-2927,3853, + 194,1155,275,1438,1438,1312,581,888,-784,906, + 112,-11103,25104,14438,-9311,-3068,1210,368,370,-940, + -2434,-1148,1925,392,657,258,-526,1475,-2281,-4265, + -1880,1534,2185,-1472,959,-30934,6306,3114,-4109,1768, + -2612,-703,45,644,2185,2033,5670,7211,19114,-22427, + 6432,5150,-4090,-2694,3860,1245,-596,293,1829,369, + -319,229,-3256,2170,-6374,-26216,-4570,-16053,-5766,-262, + -2006,2873,-1477,147,378,-1544,-344,-544,-985,-481, + 4210,4542,30757,-7291,-4863,1529,-2079,-628,-603,-783, + -408,1646,697,808,-620,-292,181,158,-13313,-29173, + 5984,-1262,859,-1776,-558,-24,-883,-1421,739,210, + -531,-285,131,-160,-246,-56,29345,-13706,-2859,-2966, + -300,-970,-2382,-268,-103,-636,-12,-62,-691,-253, + -147,-127,27,66 + }, + { 55,-212,-198,489,-274,81,682,399,328,-934, + -389,-37,1357,-3632,5276,6581,-9493,-29921,29,-45, + 2,190,172,-15,311,-130,-1085,-25,324,-684, + 3223,-6580,4485,-5280,-29521,9933,82,-320,-530,229, + -705,-533,-414,848,-1842,-4473,1390,-857,6717,-6692, + 4648,29397,576,8339,-68,-85,238,-330,264,-1012, + -381,-203,-3384,-3329,3906,6810,3790,-6250,28312,-8078, + 8089,1565,160,-569,-612,-613,-1063,-1928,-1125,3421, + -7481,-7484,4942,-6984,4330,-25591,-10574,-6982,5682,-1781, + -308,89,178,-1715,-420,-3530,-5776,1219,-8617,-7137, + 7015,4981,24875,12657,-5408,-3356,-785,-1972,326,-858, + -506,-3382,-986,-6258,-2259,4015,-8374,-10482,3127,23826, + -14126,-514,-5417,2178,-2912,-17,-587,80,67,-5881, + -1702,-5351,-4481,398,-10156,-225,20727,-15460,-11603,7752, + 3660,1714,-2001,-359,499,-527,-1225,-7820,-1297,-6326, + -8526,7900,-18328,13311,-17488,-2926,-196,-17,2281,873, + 480,-160,-624,471,780,-8729,1707,-14262,-20647,1721, + 18590,-2206,-1214,-1066,312,-2602,783,-412,-113,49, + -119,1305,-2371,-15132,-1833,-18252,20295,-8316,2227,341, + -2074,-702,3082,-262,-465,-198,430,30,-70,-788, + 2342,-25132,-4863,19783,-484,2137,2811,-1906,799,1586, + 962,-734,-191,-30,-129,-93,-1126,1729,5860,-2030, + 8953,603,-3338,-10869,-1144,22070,12130,10513,3191,-6881, + -3514,2090,711,-666,1843,-5997,-5681,2921,-17641,-2801, + 4969,18590,7169,12214,8587,4405,3008,-1074,-371,-77, + 253,331,-5611,5014,13152,-1985,18483,-1696,8043,20463, + 2381,-393,1688,-1205,618,1220,457,248,-83,176, + 7920,-13676,-22139,-3038,17402,2036,844,3258,994,719, + 2087,-44,426,494,12,-91,46,5,-14204,22912, + -18156,-361,442,2298,-829,2229,386,1433,1335,1323, + 55,-592,-139,49,-12,-57,27783,17134,350,-282, + 552,158,142,2488,465,329,1087,118,143,10, + 56,65,-15,-31 + } +}; + +/* right KLT transforms */ +const WebRtc_Word16 WebRtcIsacfix_kT2GainQ15[3][36] = { + { 4775, -14892, 20313, -17104, 10533, -3613, -6782, 16044, -8889, + -11019, 21330, -10720, 13193, -15678, -11101, 14461, 12250, -13096, + -16951, 2167, 16066, 15569, -702, -16754, -19195, -12823, -4321, + 5128, 13348, 17825, 13232, 13404, 13494, 13490, 13383, 13261 + }, + { -3725, 11408, -18493, 20031, -13097, 3865, 9344, -19294, 10740, + 8856, -18432, 8982, 13975, -14444, -11930, 11774, 14285, -13594, + -16323, -4, 16340, 15609, 359, -17220, -18401, -13471, -4643, + 5225, 13375, 18053, 13124, 13463, 13621, 13583, 13393, 13072 + }, + { -3513, 11402, -17883, 19504, -14399, 4885, 8702, -19513, 12046, + 8533, -18110, 8447, 12778, -14838, -12444, 13177, 14107, -12759, + -17268, 914, 15822, 15661, 838, -16686, -18907, -12936, -4820, + 4175, 12398, 18830, 12913, 13215, 13433, 13572, 13601, 13518 + } +}; + +const WebRtc_Word16 WebRtcIsacfix_kT2ShapeQ15[3][36] = { + { 4400, -11512, 17205, -19470, 14770, -5345, 9784, -19222, 11228, + 6842, -18371, 9909, 14191, -13496, -11563, 14015, 11827, -14839, + -15439, 948, 17802, 14827, -2053, -17132, 18723, 14516, 4135, + -6822, -13869, -16016, 12975, 13341, 13563, 13603, 13478, 13296 + }, + { 5420, -14215, 19060, -18073, 11709, -3911, 9645, -18335, 7717, + 10842, -19283, 9777, 14898, -12555, -13661, 11668, 13520, -13733, + -15936, -1358, 15671, 16728, 328, -17100, 17527, 13973, 5587, + -5194, -14165, -17677, 12970, 13446, 13693, 13660, 13462, 13015 + }, + { 4386, -12426, 18019, -18895, 13894, -5034, 9713, -19270, 10283, + 8692, -18439, 9317, 13992, -13454, -13241, 12850, 13366, -13336, + -16334, -498, 15976, 16213, -114, -16987, 18191, 13659, 4958, + -5116, -13444, -18021, 12911, 13424, 13718, 13674, 13464, 13054 + } +}; + +/* means of log gains and LAR coefficients*/ +const WebRtc_Word16 WebRtcIsacfix_kMeansGainQ8[3][12] = { + { -1758, -1370, -1758, -1373, -1757, -1375, + -1758, -1374, -1758, -1373, -1755, -1370 + }, + { -1569, -1224, -1569, -1225, -1569, -1227, + -1569, -1226, -1567, -1225, -1565, -1224 + }, + { -1452, -957, -1447, -951, -1438, -944, + -1431, -938, -1419, -931, -1406, -926 + } +}; + + +const WebRtc_Word32 WebRtcIsacfix_kMeansShapeQ17[3][108] = { + { -119581, 34418, -44193, 11112, -4428, 18906, 9222, 8068, 1953, 5425, + 1871, 1689, 109933, 33751, 10471, -2566, 1090, 2320, -119219, 33728, + -43759, 11450, -4870, 19117, 9174, 8037, 1972, 5331, 1872, 1843, + 109899, 34301, 10629, -2316, 1272, 2562, -118608, 32318, -44012, 11591, + -4914, 18932, 9456, 8088, 1900, 5419, 1723, 1853, 109963, 35059, + 10745, -2335, 1161, 2520, -119174, 32107, -44462, 11635, -4694, 18611, + 9757, 8108, 1969, 5486, 1673, 1777, 109636, 34907, 10643, -2406, + 1034, 2420, -118597, 32320, -44590, 10854, -4569, 18821, 9701, 7866, + 2003, 5577, 1732, 1626, 109913, 34448, 10714, -2752, 990, 2228, + -118138, 32996, -44352, 10334, -3772, 18488, 9464, 7865, 2208, 5540, + 1745, 1664, 109880, 33381, 10640, -2779, 980, 2054 + }, + { -146328, 46370, 1047, 26431, 10035, 13933, 6415, 14359, -2368, 6661, + 2269, 1764, 96623, 7802, 4163, 10742, 1643, 2954, -146871, 46561, 1127, + 26225, 10113, 14096, 6771, 14323, -2037, 6788, 2297, 1761, 96324, 8382, + 4309, 10450, 1695, 3016, -146502, 46475, 1580, 26118, 10487, 14179, 6622, + 14439, -2034, 6757, 2342, 1761, 95869, 8966, 4347, 10358, 1999, 2855, + -146958, 47717, 826, 25952, 10263, 14061, 5266, 13681, -2417, 6582, 2047, + 1608, 96257, 9107, 4452, 10301, 1792, 2676, -146992, 47123, 446, 25822, + 10405, 14292, 5140, 13804, -2403, 6496, 1834, 1735, 97489, 9253, 4414, + 10684, 1549, 2721, -145811, 46182, 901, 26482, 10241, 14524, 6075, 14514, + -2147, 6691, 2196, 1899, 97011, 8178, 4102, 10758, 1638, 2869 + }, + { -166617, 46969, -43908, 17726, 6330, 25615, 6913, 5450, -2301, 1984, + 507, 2883, 149998, 28709, 19333, 16703, 11093, 8965, -168254, 46604, + -44315, 17862, 6474, 25746, 7018, 5373, -2343, 1930, 513, 2819, 150391, + 28627, 19194, 16678, 10998, 8929, -169093, 46084, -44767, 17427, 6401, + 25674, 7147, 5472, -2336, 1820, 491, 2802, 149860, 28430, 19064, 16524, + 10898, 8875, -170205, 46189, -44877, 17403, 6190, 25209, 7035, 5673, -2173, + 1894, 574, 2756, 148830, 28230, 18819, 16418, 10789, 8811, -171263, 45045, + -44834, 16858, 6103, 24726, 7014, 5713, -2103, 1877, 518, 2729, 147073, + 27744, 18629, 16277, 10690, 8703, -171720, 44153, -45062, 15951, 5872, + 24429, 7044, 5585, -2082, 1807, 519, 2769, 144791, 27402, 18490, 16126, + 10548, 8635 + } +}; diff --git a/src/modules/audio_coding/codecs/isac/fix/source/lpc_tables.h b/src/modules/audio_coding/codecs/isac/fix/source/lpc_tables.h new file mode 100644 index 0000000000..4f2e0e7f17 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/lpc_tables.h @@ -0,0 +1,98 @@ +/* + * 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_tables.h + * + * header file for coding tables for the LPC coefficients + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_LPC_TABLES_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_LPC_TABLES_H_ + +#include "typedefs.h" + + +/* indices of KLT coefficients used */ +extern const WebRtc_UWord16 WebRtcIsacfix_kSelIndGain[12]; + +extern const WebRtc_UWord16 WebRtcIsacfix_kSelIndShape[108]; + +/* cdf array for model indicator */ +extern const WebRtc_UWord16 WebRtcIsacfix_kModelCdf[KLT_NUM_MODELS+1]; + +/* pointer to cdf array for model indicator */ +extern const WebRtc_UWord16 *WebRtcIsacfix_kModelCdfPtr[1]; + +/* initial cdf index for decoder of model indicator */ +extern const WebRtc_UWord16 WebRtcIsacfix_kModelInitIndex[1]; + +/* offset to go from rounded value to quantization index */ +extern const WebRtc_Word16 WebRtcIsacfix_kQuantMinGain[12]; + +extern const WebRtc_Word16 WebRtcIsacfix_kQuantMinShape[108]; + +/* maximum quantization index */ +extern const WebRtc_UWord16 WebRtcIsacfix_kMaxIndGain[12]; + +extern const WebRtc_UWord16 WebRtcIsacfix_kMaxIndShape[108]; + +/* index offset */ +extern const WebRtc_UWord16 WebRtcIsacfix_kOffsetGain[KLT_NUM_MODELS][12]; + +extern const WebRtc_UWord16 WebRtcIsacfix_kOffsetShape[KLT_NUM_MODELS][108]; + +/* initial cdf index for KLT coefficients */ +extern const WebRtc_UWord16 WebRtcIsacfix_kInitIndexGain[KLT_NUM_MODELS][12]; + +extern const WebRtc_UWord16 WebRtcIsacfix_kInitIndexShape[KLT_NUM_MODELS][108]; + +/* offsets for quantizer representation levels */ +extern const WebRtc_UWord16 WebRtcIsacfix_kOfLevelsGain[3]; + +extern const WebRtc_UWord16 WebRtcIsacfix_kOfLevelsShape[3]; + +/* quantizer representation levels */ +extern const WebRtc_Word32 WebRtcIsacfix_kLevelsGainQ17[1176]; + +extern const WebRtc_Word16 WebRtcIsacfix_kLevelsShapeQ10[1735]; + +/* cdf tables for quantizer indices */ +extern const WebRtc_UWord16 WebRtcIsacfix_kCdfGain[1212]; + +extern const WebRtc_UWord16 WebRtcIsacfix_kCdfShape[2059]; + +/* pointers to cdf tables for quantizer indices */ +extern const WebRtc_UWord16 *WebRtcIsacfix_kCdfGainPtr[KLT_NUM_MODELS][12]; + +extern const WebRtc_UWord16 *WebRtcIsacfix_kCdfShapePtr[KLT_NUM_MODELS][108]; + +/* code length for all coefficients using different models */ +extern const WebRtc_Word16 WebRtcIsacfix_kCodeLenGainQ11[392]; + +extern const WebRtc_Word16 WebRtcIsacfix_kCodeLenShapeQ11[577]; + +/* left KLT transforms */ +extern const WebRtc_Word16 WebRtcIsacfix_kT1GainQ15[KLT_NUM_MODELS][4]; + +extern const WebRtc_Word16 WebRtcIsacfix_kT1ShapeQ15[KLT_NUM_MODELS][324]; + +/* right KLT transforms */ +extern const WebRtc_Word16 WebRtcIsacfix_kT2GainQ15[KLT_NUM_MODELS][36]; + +extern const WebRtc_Word16 WebRtcIsacfix_kT2ShapeQ15[KLT_NUM_MODELS][36]; + +/* means of log gains and LAR coefficients */ +extern const WebRtc_Word16 WebRtcIsacfix_kMeansGainQ8[KLT_NUM_MODELS][12]; + +extern const WebRtc_Word32 WebRtcIsacfix_kMeansShapeQ17[3][108]; + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_LPC_TABLES_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/fix/source/pitch_estimator.c b/src/modules/audio_coding/codecs/isac/fix/source/pitch_estimator.c new file mode 100644 index 0000000000..6af02d8962 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/pitch_estimator.c @@ -0,0 +1,551 @@ +/* + * 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.c + * + * Pitch filter functions + * + */ + +#ifdef WEBRTC_ARCH_ARM_NEON +#include <arm_neon.h> +#endif + +#include "pitch_estimator.h" +#include "signal_processing_library.h" +#include "system_wrappers/interface/compile_assert.h" + +/* log2[0.2, 0.5, 0.98] in Q8 */ +static const WebRtc_Word16 kLogLagWinQ8[3] = { + -594, -256, -7 +}; + +/* [1 -0.75 0.25] in Q12 */ +static const WebRtc_Word16 kACoefQ12[3] = { + 4096, -3072, 1024 +}; + + + +static __inline WebRtc_Word32 Log2Q8( WebRtc_UWord32 x ) { + + WebRtc_Word32 zeros, lg2; + WebRtc_Word16 frac; + + zeros=WebRtcSpl_NormU32(x); + frac=(WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(((WebRtc_UWord32)(WEBRTC_SPL_LSHIFT_W32(x, zeros))&0x7FFFFFFF), 23); + /* log2(magn(i)) */ + + lg2= (WEBRTC_SPL_LSHIFT_W32((31-zeros), 8)+frac); + return lg2; + +} + +static __inline WebRtc_Word16 Exp2Q10(WebRtc_Word16 x) { // Both in and out in Q10 + + WebRtc_Word16 tmp16_1, tmp16_2; + + tmp16_2=(WebRtc_Word16)(0x0400|(x&0x03FF)); + tmp16_1=-(WebRtc_Word16)WEBRTC_SPL_RSHIFT_W16(x,10); + if(tmp16_1>0) + return (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W16(tmp16_2, tmp16_1); + else + return (WebRtc_Word16) WEBRTC_SPL_LSHIFT_W16(tmp16_2, -tmp16_1); + +} + + + +/* 1D parabolic interpolation . All input and output values are in Q8 */ +static __inline void Intrp1DQ8(WebRtc_Word32 *x, WebRtc_Word32 *fx, WebRtc_Word32 *y, WebRtc_Word32 *fy) { + + WebRtc_Word16 sign1=1, sign2=1; + WebRtc_Word32 r32, q32, t32, nom32, den32; + WebRtc_Word16 t16, tmp16, tmp16_1; + + if ((fx[0]>0) && (fx[2]>0)) { + r32=fx[1]-fx[2]; + q32=fx[0]-fx[1]; + nom32=q32+r32; + den32=WEBRTC_SPL_MUL_32_16((q32-r32), 2); + if (nom32<0) + sign1=-1; + if (den32<0) + sign2=-1; + + /* t = (q32+r32)/(2*(q32-r32)) = (fx[0]-fx[1] + fx[1]-fx[2])/(2 * fx[0]-fx[1] - (fx[1]-fx[2]))*/ + /* (Signs are removed because WebRtcSpl_DivResultInQ31 can't handle negative numbers) */ + t32=WebRtcSpl_DivResultInQ31(WEBRTC_SPL_MUL_32_16(nom32, sign1),WEBRTC_SPL_MUL_32_16(den32, sign2)); /* t in Q31, without signs */ + + t16=(WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(t32, 23); /* Q8 */ + t16=t16*sign1*sign2; /* t in Q8 with signs */ + + *y = x[0]+t16; /* Q8 */ + // *y = x[1]+t16; /* Q8 */ + + /* The following code calculates fy in three steps */ + /* fy = 0.5 * t * (t-1) * fx[0] + (1-t*t) * fx[1] + 0.5 * t * (t+1) * fx[2]; */ + + /* Part I: 0.5 * t * (t-1) * fx[0] */ + tmp16_1=(WebRtc_Word16)WEBRTC_SPL_MUL_16_16(t16,t16); /* Q8*Q8=Q16 */ + tmp16_1 = WEBRTC_SPL_RSHIFT_W16(tmp16_1,2); /* Q16>>2 = Q14 */ + t16 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16(t16, 64); /* Q8<<6 = Q14 */ + tmp16 = tmp16_1-t16; + *fy = WEBRTC_SPL_MUL_16_32_RSFT15(tmp16, fx[0]); /* (Q14 * Q8 >>15)/2 = Q8 */ + + /* Part II: (1-t*t) * fx[1] */ + tmp16 = 16384-tmp16_1; /* 1 in Q14 - Q14 */ + *fy += WEBRTC_SPL_MUL_16_32_RSFT14(tmp16, fx[1]);/* Q14 * Q8 >> 14 = Q8 */ + + /* Part III: 0.5 * t * (t+1) * fx[2] */ + tmp16 = tmp16_1+t16; + *fy += WEBRTC_SPL_MUL_16_32_RSFT15(tmp16, fx[2]);/* (Q14 * Q8 >>15)/2 = Q8 */ + } else { + *y = x[0]; + *fy= fx[1]; + } +} + + +static void FindFour32(WebRtc_Word32 *in, WebRtc_Word16 length, WebRtc_Word16 *bestind) +{ + WebRtc_Word32 best[4]= {-100, -100, -100, -100}; + WebRtc_Word16 k; + + for (k=0; k<length; k++) { + if (in[k] > best[3]) { + if (in[k] > best[2]) { + if (in[k] > best[1]) { + if (in[k] > best[0]) { // The Best + best[3] = best[2]; + bestind[3] = bestind[2]; + best[2] = best[1]; + bestind[2] = bestind[1]; + best[1] = best[0]; + bestind[1] = bestind[0]; + best[0] = in[k]; + bestind[0] = k; + } else { // 2nd best + best[3] = best[2]; + bestind[3] = bestind[2]; + best[2] = best[1]; + bestind[2] = bestind[1]; + best[1] = in[k]; + bestind[1] = k; + } + } else { // 3rd best + best[3] = best[2]; + bestind[3] = bestind[2]; + best[2] = in[k]; + bestind[2] = k; + } + } else { // 4th best + best[3] = in[k]; + bestind[3] = k; + } + } + } +} + + + + + +static void PCorr2Q32(const WebRtc_Word16 *in, WebRtc_Word32 *logcorQ8) +{ + WebRtc_Word16 scaling,n,k; + WebRtc_Word32 ysum32,csum32, lys, lcs; + WebRtc_Word32 oneQ8; + + + const WebRtc_Word16 *x, *inptr; + + oneQ8 = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)1, 8); // 1.00 in Q8 + + x = in + PITCH_MAX_LAG/2 + 2; + scaling = WebRtcSpl_GetScalingSquare ((WebRtc_Word16 *) in, PITCH_CORR_LEN2, PITCH_CORR_LEN2); + ysum32 = 1; + csum32 = 0; + x = in + PITCH_MAX_LAG/2 + 2; + for (n = 0; n < PITCH_CORR_LEN2; n++) { + ysum32 += WEBRTC_SPL_MUL_16_16_RSFT( (WebRtc_Word16) in[n],(WebRtc_Word16) in[n], scaling); // Q0 + csum32 += WEBRTC_SPL_MUL_16_16_RSFT((WebRtc_Word16) x[n],(WebRtc_Word16) in[n], scaling); // Q0 + } + + logcorQ8 += PITCH_LAG_SPAN2 - 1; + + lys=Log2Q8((WebRtc_UWord32) ysum32); // Q8 + lys=WEBRTC_SPL_RSHIFT_W32(lys, 1); //sqrt(ysum); + + if (csum32>0) { + + lcs=Log2Q8((WebRtc_UWord32) csum32); // 2log(csum) in Q8 + + if (lcs>(lys + oneQ8) ){ // csum/sqrt(ysum) > 2 in Q8 + *logcorQ8 = lcs - lys; // log2(csum/sqrt(ysum)) + } else { + *logcorQ8 = oneQ8; // 1.00 + } + + } else { + *logcorQ8 = 0; + } + + + for (k = 1; k < PITCH_LAG_SPAN2; k++) { + inptr = &in[k]; + ysum32 -= WEBRTC_SPL_MUL_16_16_RSFT( (WebRtc_Word16) in[k-1],(WebRtc_Word16) in[k-1], scaling); + ysum32 += WEBRTC_SPL_MUL_16_16_RSFT( (WebRtc_Word16) in[PITCH_CORR_LEN2 + k - 1],(WebRtc_Word16) in[PITCH_CORR_LEN2 + k - 1], scaling); + +#ifdef WEBRTC_ARCH_ARM_NEON + { + int32_t vbuff[4]; + int32x4_t int_32x4_sum = vmovq_n_s32(0); + // Can't shift a Neon register to right with a non-constant shift value. + int32x4_t int_32x4_scale = vdupq_n_s32(-scaling); + // Assert a codition used in loop unrolling at compile-time. + COMPILE_ASSERT(PITCH_CORR_LEN2 %4 == 0); + + for (n = 0; n < PITCH_CORR_LEN2; n += 4) { + int16x4_t int_16x4_x = vld1_s16(&x[n]); + int16x4_t int_16x4_in = vld1_s16(&inptr[n]); + int32x4_t int_32x4 = vmull_s16(int_16x4_x, int_16x4_in); + int_32x4 = vshlq_s32(int_32x4, int_32x4_scale); + int_32x4_sum = vaddq_s32(int_32x4_sum, int_32x4); + } + + // Use vector store to avoid long stall from data trasferring + // from vector to general register. + vst1q_s32(vbuff, int_32x4_sum); + csum32 = vbuff[0] + vbuff[1]; + csum32 += vbuff[2]; + csum32 += vbuff[3]; + } +#else + csum32 = 0; + if(scaling == 0) { + for (n = 0; n < PITCH_CORR_LEN2; n++) { + csum32 += x[n] * inptr[n]; + } + } else { + for (n = 0; n < PITCH_CORR_LEN2; n++) { + csum32 += (x[n] * inptr[n]) >> scaling; + } + } +#endif + + logcorQ8--; + + lys=Log2Q8((WebRtc_UWord32)ysum32); // Q8 + lys=WEBRTC_SPL_RSHIFT_W32(lys, 1); //sqrt(ysum); + + if (csum32>0) { + + lcs=Log2Q8((WebRtc_UWord32) csum32); // 2log(csum) in Q8 + + if (lcs>(lys + oneQ8) ){ // csum/sqrt(ysum) > 2 + *logcorQ8 = lcs - lys; // log2(csum/sqrt(ysum)) + } else { + *logcorQ8 = oneQ8; // 1.00 + } + + } else { + *logcorQ8 = 0; + } + } +} + + + +void WebRtcIsacfix_InitialPitch(const WebRtc_Word16 *in, /* Q0 */ + PitchAnalysisStruct *State, + WebRtc_Word16 *lagsQ7 /* Q7 */ + ) +{ + WebRtc_Word16 buf_dec16[PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2+2]; + WebRtc_Word32 *crrvecQ8_1,*crrvecQ8_2; + WebRtc_Word32 cv1q[PITCH_LAG_SPAN2+2],cv2q[PITCH_LAG_SPAN2+2], peakvq[PITCH_LAG_SPAN2+2]; + int k; + WebRtc_Word16 peaks_indq; + WebRtc_Word16 peakiq[PITCH_LAG_SPAN2]; + WebRtc_Word32 corr; + WebRtc_Word32 corr32, corr_max32, corr_max_o32; + WebRtc_Word16 npkq; + WebRtc_Word16 best4q[4]={0,0,0,0}; + WebRtc_Word32 xq[3],yq[1],fyq[1]; + WebRtc_Word32 *fxq; + WebRtc_Word32 best_lag1q, best_lag2q; + WebRtc_Word32 tmp32a,tmp32b,lag32,ratq; + WebRtc_Word16 start; + WebRtc_Word16 oldgQ12, tmp16a, tmp16b, gain_bias16,tmp16c, tmp16d, bias16; + WebRtc_Word32 tmp32c,tmp32d, tmp32e; + WebRtc_Word16 old_lagQ; + WebRtc_Word32 old_lagQ8; + WebRtc_Word32 lagsQ8[4]; + + old_lagQ = State->PFstr_wght.oldlagQ7; // Q7 + old_lagQ8= WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)old_lagQ,1); //Q8 + + oldgQ12= State->PFstr_wght.oldgainQ12; + + crrvecQ8_1=&cv1q[1]; + crrvecQ8_2=&cv2q[1]; + + + /* copy old values from state buffer */ + memcpy(buf_dec16, State->dec_buffer16, WEBRTC_SPL_MUL_16_16(sizeof(WebRtc_Word16), (PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2))); + + /* decimation; put result after the old values */ + WebRtcIsacfix_DecimateAllpass32(in, State->decimator_state32, PITCH_FRAME_LEN, + &buf_dec16[PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2]); + + /* low-pass filtering */ + start= PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2; + WebRtcSpl_FilterARFastQ12(&buf_dec16[start],&buf_dec16[start],(WebRtc_Word16*)kACoefQ12,3, PITCH_FRAME_LEN/2); + + /* copy end part back into state buffer */ + for (k = 0; k < (PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2); k++) + State->dec_buffer16[k] = buf_dec16[k+PITCH_FRAME_LEN/2]; + + + /* compute correlation for first and second half of the frame */ + PCorr2Q32(buf_dec16, crrvecQ8_1); + PCorr2Q32(buf_dec16 + PITCH_CORR_STEP2, crrvecQ8_2); + + + /* bias towards pitch lag of previous frame */ + tmp32a = Log2Q8((WebRtc_UWord32) old_lagQ8) - 2304; // log2(0.5*oldlag) in Q8 + tmp32b = WEBRTC_SPL_MUL_16_16_RSFT(oldgQ12,oldgQ12, 10); //Q12 & * 4.0; + gain_bias16 = (WebRtc_Word16) tmp32b; //Q12 + if (gain_bias16 > 3276) gain_bias16 = 3276; // 0.8 in Q12 + + + for (k = 0; k < PITCH_LAG_SPAN2; k++) + { + if (crrvecQ8_1[k]>0) { + tmp32b = Log2Q8((WebRtc_UWord32) (k + (PITCH_MIN_LAG/2-2))); + tmp16a = (WebRtc_Word16) (tmp32b - tmp32a); // Q8 & fabs(ratio)<4 + tmp32c = WEBRTC_SPL_MUL_16_16_RSFT(tmp16a,tmp16a, 6); //Q10 + tmp16b = (WebRtc_Word16) tmp32c; // Q10 & <8 + tmp32d = WEBRTC_SPL_MUL_16_16_RSFT(tmp16b, 177 , 8); // mult with ln2 in Q8 + tmp16c = (WebRtc_Word16) tmp32d; // Q10 & <4 + tmp16d = Exp2Q10((WebRtc_Word16) -tmp16c); //Q10 + tmp32c = WEBRTC_SPL_MUL_16_16_RSFT(gain_bias16,tmp16d,13); // Q10 & * 0.5 + bias16 = (WebRtc_Word16) (1024 + tmp32c); // Q10 + tmp32b = Log2Q8((WebRtc_UWord32) bias16) - 2560; // Q10 in -> Q8 out with 10*2^8 offset + crrvecQ8_1[k] += tmp32b ; // -10*2^8 offset + } + } + + /* taper correlation functions */ + for (k = 0; k < 3; k++) { + crrvecQ8_1[k] += kLogLagWinQ8[k]; + crrvecQ8_2[k] += kLogLagWinQ8[k]; + + crrvecQ8_1[PITCH_LAG_SPAN2-1-k] += kLogLagWinQ8[k]; + crrvecQ8_2[PITCH_LAG_SPAN2-1-k] += kLogLagWinQ8[k]; + } + + + /* Make zeropadded corr vectors */ + cv1q[0]=0; + cv2q[0]=0; + cv1q[PITCH_LAG_SPAN2+1]=0; + cv2q[PITCH_LAG_SPAN2+1]=0; + corr_max32 = 0; + + for (k = 1; k <= PITCH_LAG_SPAN2; k++) + { + + + corr32=crrvecQ8_1[k-1]; + if (corr32 > corr_max32) + corr_max32 = corr32; + + corr32=crrvecQ8_2[k-1]; + corr32 += -4; // Compensate for later (log2(0.99)) + + if (corr32 > corr_max32) + corr_max32 = corr32; + + } + + /* threshold value to qualify as a peak */ + // corr_max32 += -726; // log(0.14)/log(2.0) in Q8 + corr_max32 += -1000; // log(0.14)/log(2.0) in Q8 + corr_max_o32 = corr_max32; + + + /* find peaks in corr1 */ + peaks_indq = 0; + for (k = 1; k <= PITCH_LAG_SPAN2; k++) + { + corr32=cv1q[k]; + if (corr32>corr_max32) { // Disregard small peaks + if ((corr32>=cv1q[k-1]) && (corr32>cv1q[k+1])) { // Peak? + peakvq[peaks_indq] = corr32; + peakiq[peaks_indq++] = k; + } + } + } + + + /* find highest interpolated peak */ + corr_max32=0; + best_lag1q =0; + if (peaks_indq > 0) { + FindFour32(peakvq, (WebRtc_Word16) peaks_indq, best4q); + npkq = WEBRTC_SPL_MIN(peaks_indq, 4); + + for (k=0;k<npkq;k++) { + + lag32 = peakiq[best4q[k]]; + fxq = &cv1q[peakiq[best4q[k]]-1]; + xq[0]= lag32; + xq[0] = WEBRTC_SPL_LSHIFT_W32(xq[0], 8); + Intrp1DQ8(xq, fxq, yq, fyq); + + tmp32a= Log2Q8((WebRtc_UWord32) *yq) - 2048; // offset 8*2^8 + /* Bias towards short lags */ + /* log(pow(0.8, log(2.0 * *y )))/log(2.0) */ + tmp32b= WEBRTC_SPL_MUL_16_16_RSFT((WebRtc_Word16) tmp32a, -42, 8); + tmp32c= tmp32b + 256; + *fyq += tmp32c; + if (*fyq > corr_max32) { + corr_max32 = *fyq; + best_lag1q = *yq; + } + } + tmp32a = best_lag1q - OFFSET_Q8; + tmp32b = WEBRTC_SPL_LSHIFT_W32(tmp32a, 1); + lagsQ8[0] = tmp32b + PITCH_MIN_LAG_Q8; + lagsQ8[1] = lagsQ8[0]; + } else { + lagsQ8[0] = old_lagQ8; + lagsQ8[1] = lagsQ8[0]; + } + + /* Bias towards constant pitch */ + tmp32a = lagsQ8[0] - PITCH_MIN_LAG_Q8; + ratq = WEBRTC_SPL_RSHIFT_W32(tmp32a, 1) + OFFSET_Q8; + + for (k = 1; k <= PITCH_LAG_SPAN2; k++) + { + tmp32a = WEBRTC_SPL_LSHIFT_W32(k, 7); // 0.5*k Q8 + tmp32b = (WebRtc_Word32) (WEBRTC_SPL_LSHIFT_W32(tmp32a, 1)) - ratq; // Q8 + tmp32c = WEBRTC_SPL_MUL_16_16_RSFT((WebRtc_Word16) tmp32b, (WebRtc_Word16) tmp32b, 8); // Q8 + + tmp32b = (WebRtc_Word32) tmp32c + (WebRtc_Word32) WEBRTC_SPL_RSHIFT_W32(ratq, 1); // (k-r)^2 + 0.5 * r Q8 + tmp32c = Log2Q8((WebRtc_UWord32) tmp32a) - 2048; // offset 8*2^8 , log2(0.5*k) Q8 + tmp32d = Log2Q8((WebRtc_UWord32) tmp32b) - 2048; // offset 8*2^8 , log2(0.5*k) Q8 + tmp32e = tmp32c -tmp32d; + + cv2q[k] += WEBRTC_SPL_RSHIFT_W32(tmp32e, 1); + + } + + /* find peaks in corr2 */ + corr_max32 = corr_max_o32; + peaks_indq = 0; + + for (k = 1; k <= PITCH_LAG_SPAN2; k++) + { + corr=cv2q[k]; + if (corr>corr_max32) { // Disregard small peaks + if ((corr>=cv2q[k-1]) && (corr>cv2q[k+1])) { // Peak? + peakvq[peaks_indq] = corr; + peakiq[peaks_indq++] = k; + } + } + } + + + + /* find highest interpolated peak */ + corr_max32 = 0; + best_lag2q =0; + if (peaks_indq > 0) { + + FindFour32(peakvq, (WebRtc_Word16) peaks_indq, best4q); + npkq = WEBRTC_SPL_MIN(peaks_indq, 4); + for (k=0;k<npkq;k++) { + + lag32 = peakiq[best4q[k]]; + fxq = &cv2q[peakiq[best4q[k]]-1]; + + xq[0]= lag32; + xq[0] = WEBRTC_SPL_LSHIFT_W32(xq[0], 8); + Intrp1DQ8(xq, fxq, yq, fyq); + + /* Bias towards short lags */ + /* log(pow(0.8, log(2.0f * *y )))/log(2.0f) */ + tmp32a= Log2Q8((WebRtc_UWord32) *yq) - 2048; // offset 8*2^8 + tmp32b= WEBRTC_SPL_MUL_16_16_RSFT((WebRtc_Word16) tmp32a, -82, 8); + tmp32c= tmp32b + 256; + *fyq += tmp32c; + if (*fyq > corr_max32) { + corr_max32 = *fyq; + best_lag2q = *yq; + } + } + + tmp32a = best_lag2q - OFFSET_Q8; + tmp32b = WEBRTC_SPL_LSHIFT_W32(tmp32a, 1); + lagsQ8[2] = tmp32b + PITCH_MIN_LAG_Q8; + lagsQ8[3] = lagsQ8[2]; + } else { + lagsQ8[2] = lagsQ8[0]; + lagsQ8[3] = lagsQ8[0]; + } + + lagsQ7[0]=(WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(lagsQ8[0], 1); + lagsQ7[1]=(WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(lagsQ8[1], 1); + lagsQ7[2]=(WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(lagsQ8[2], 1); + lagsQ7[3]=(WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(lagsQ8[3], 1); + + +} + + + +void WebRtcIsacfix_PitchAnalysis(const WebRtc_Word16 *inn, /* PITCH_FRAME_LEN samples */ + WebRtc_Word16 *outQ0, /* PITCH_FRAME_LEN+QLOOKAHEAD samples */ + PitchAnalysisStruct *State, + WebRtc_Word16 *PitchLags_Q7, + WebRtc_Word16 *PitchGains_Q12) +{ + WebRtc_Word16 inbufQ0[PITCH_FRAME_LEN + QLOOKAHEAD]; + WebRtc_Word16 k; + + /* inital pitch estimate */ + WebRtcIsacfix_InitialPitch(inn, State, PitchLags_Q7); + + + /* Calculate gain */ + WebRtcIsacfix_PitchFilterGains(inn, &(State->PFstr_wght), PitchLags_Q7, PitchGains_Q12); + + /* concatenate previous input's end and current input */ + for (k = 0; k < QLOOKAHEAD; k++) { + inbufQ0[k] = State->inbuf[k]; + } + for (k = 0; k < PITCH_FRAME_LEN; k++) { + inbufQ0[k+QLOOKAHEAD] = (WebRtc_Word16) inn[k]; + } + + /* lookahead pitch filtering for masking analysis */ + WebRtcIsacfix_PitchFilter(inbufQ0, outQ0, &(State->PFstr), PitchLags_Q7,PitchGains_Q12, 2); + + + /* store last part of input */ + for (k = 0; k < QLOOKAHEAD; k++) { + State->inbuf[k] = inbufQ0[k + PITCH_FRAME_LEN]; + } +} diff --git a/src/modules/audio_coding/codecs/isac/fix/source/pitch_estimator.h b/src/modules/audio_coding/codecs/isac/fix/source/pitch_estimator.h new file mode 100644 index 0000000000..6225256cca --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/pitch_estimator.h @@ -0,0 +1,61 @@ +/* + * 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. + */ + +/* + * pitch_estimator.h + * + * Pitch functions + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_PITCH_ESTIMATOR_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_PITCH_ESTIMATOR_H_ + +#include "structs.h" + +void WebRtcIsacfix_PitchAnalysis(const WebRtc_Word16 *in, /* PITCH_FRAME_LEN samples */ + WebRtc_Word16 *outQ0, /* PITCH_FRAME_LEN+QLOOKAHEAD samples */ + PitchAnalysisStruct *State, + WebRtc_Word16 *lagsQ7, + WebRtc_Word16 *PitchGains_Q12); + +void WebRtcIsacfix_InitialPitch(const WebRtc_Word16 *in, + PitchAnalysisStruct *State, + WebRtc_Word16 *qlags); + +void WebRtcIsacfix_PitchFilter(WebRtc_Word16 *indatFix, + WebRtc_Word16 *outdatQQ, + PitchFiltstr *pfp, + WebRtc_Word16 *lagsQ7, + WebRtc_Word16 *gainsQ12, + WebRtc_Word16 type); + +void WebRtcIsacfix_PitchFilterCore(int loopNumber, + WebRtc_Word16 gain, + int index, + WebRtc_Word16 sign, + WebRtc_Word16* inputState, + WebRtc_Word16* outputBuff2, + const WebRtc_Word16* coefficient, + WebRtc_Word16* inputBuf, + WebRtc_Word16* outputBuf, + int* index2); + +void WebRtcIsacfix_PitchFilterGains(const WebRtc_Word16 *indatQ0, + PitchFiltstr *pfp, + WebRtc_Word16 *lagsQ7, + WebRtc_Word16 *gainsQ12); + +void WebRtcIsacfix_DecimateAllpass32(const WebRtc_Word16 *in, + WebRtc_Word32 *state_in, /* array of size: 2*ALLPASSSECTIONS+1 */ + WebRtc_Word16 N, /* number of input samples */ + WebRtc_Word16 *out); /* array of size N/2 */ + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_PITCH_ESTIMATOR_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/fix/source/pitch_filter.c b/src/modules/audio_coding/codecs/isac/fix/source/pitch_filter.c new file mode 100644 index 0000000000..f30293e947 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/pitch_filter.c @@ -0,0 +1,280 @@ +/* + * 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. + */ + +/* + * pitch_filter.c + * + * Pitch filter functions + * + */ + +#include "common_audio/signal_processing/include/signal_processing_library.h" +#include "modules/audio_coding/codecs/isac/fix/source/pitch_estimator.h" +#include "modules/audio_coding/codecs/isac/fix/source/settings.h" +#include "modules/audio_coding/codecs/isac/fix/source/structs.h" +#include "system_wrappers/interface/compile_assert.h" + +// Number of segments in a pitch subframe. +static const int kSegments = 5; + +// A division factor of 1/5 in Q15. +static const WebRtc_Word16 kDivFactor = 6553; + +// Filter coefficicients in Q15. +static const WebRtc_Word16 kDampFilter[PITCH_DAMPORDER] = { + -2294, 8192, 20972, 8192, -2294 +}; + +// Interpolation coefficients; generated by design_pitch_filter.m. +// Coefficients are stored in Q14. +static const WebRtc_Word16 kIntrpCoef[PITCH_FRACS][PITCH_FRACORDER] = { + {-367, 1090, -2706, 9945, 10596, -3318, 1626, -781, 287}, + {-325, 953, -2292, 7301, 12963, -3320, 1570, -743, 271}, + {-240, 693, -1622, 4634, 14809, -2782, 1262, -587, 212}, + {-125, 358, -817, 2144, 15982, -1668, 721, -329, 118}, + { 0, 0, -1, 1, 16380, 1, -1, 0, 0}, + { 118, -329, 721, -1668, 15982, 2144, -817, 358, -125}, + { 212, -587, 1262, -2782, 14809, 4634, -1622, 693, -240}, + { 271, -743, 1570, -3320, 12963, 7301, -2292, 953, -325} +}; + +// Function prototype for pitch filtering. +// TODO(Turaj): Add descriptions of input and output parameters. +void WebRtcIsacfix_PitchFilterCore(int loopNumber, + WebRtc_Word16 gain, + int index, + WebRtc_Word16 sign, + WebRtc_Word16* inputState, + WebRtc_Word16* outputBuf2, + const WebRtc_Word16* coefficient, + WebRtc_Word16* inputBuf, + WebRtc_Word16* outputBuf, + int* index2); + +static __inline WebRtc_Word32 CalcLrIntQ(WebRtc_Word32 fixVal, + WebRtc_Word16 qDomain) { + WebRtc_Word32 intgr; + WebRtc_Word32 roundVal; + + roundVal = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)1, qDomain - 1); + intgr = WEBRTC_SPL_RSHIFT_W32(fixVal + roundVal, qDomain); + + return intgr; +} + +void WebRtcIsacfix_PitchFilter(WebRtc_Word16* indatQQ, // Q10 if type is 1 or 4, + // Q0 if type is 2. + WebRtc_Word16* outdatQQ, + PitchFiltstr* pfp, + WebRtc_Word16* lagsQ7, + WebRtc_Word16* gainsQ12, + WebRtc_Word16 type) { + int k, ind, cnt; + WebRtc_Word16 sign = 1; + WebRtc_Word16 inystateQQ[PITCH_DAMPORDER]; + WebRtc_Word16 ubufQQ[PITCH_INTBUFFSIZE + QLOOKAHEAD]; + const WebRtc_Word16 Gain = 21299; // 1.3 in Q14 + WebRtc_Word16 oldLagQ7; + WebRtc_Word16 oldGainQ12, lagdeltaQ7, curLagQ7, gaindeltaQ12, curGainQ12; + int indW32 = 0, frcQQ = 0; + WebRtc_Word32 tmpW32; + const WebRtc_Word16* fracoeffQQ = NULL; + + // Assumptions in ARM assembly for WebRtcIsacfix_PitchFilterCoreARM(). + COMPILE_ASSERT(PITCH_FRACORDER == 9); + COMPILE_ASSERT(PITCH_DAMPORDER == 5); + + // Set up buffer and states. + memcpy(ubufQQ, pfp->ubufQQ, sizeof(pfp->ubufQQ)); + memcpy(inystateQQ, pfp->ystateQQ, sizeof(inystateQQ)); + + // Get old lag and gain value from memory. + oldLagQ7 = pfp->oldlagQ7; + oldGainQ12 = pfp->oldgainQ12; + + if (type == 4) { + sign = -1; + + // Make output more periodic. + for (k = 0; k < PITCH_SUBFRAMES; k++) { + gainsQ12[k] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT( + gainsQ12[k], Gain, 14); + } + } + + // No interpolation if pitch lag step is big. + if ((WEBRTC_SPL_MUL_16_16_RSFT(lagsQ7[0], 3, 1) < oldLagQ7) || + (lagsQ7[0] > WEBRTC_SPL_MUL_16_16_RSFT(oldLagQ7, 3, 1))) { + oldLagQ7 = lagsQ7[0]; + oldGainQ12 = gainsQ12[0]; + } + + ind = 0; + + for (k = 0; k < PITCH_SUBFRAMES; k++) { + // Calculate interpolation steps. + lagdeltaQ7 = lagsQ7[k] - oldLagQ7; + lagdeltaQ7 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( + lagdeltaQ7, kDivFactor, 15); + curLagQ7 = oldLagQ7; + gaindeltaQ12 = gainsQ12[k] - oldGainQ12; + gaindeltaQ12 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT( + gaindeltaQ12, kDivFactor, 15); + + curGainQ12 = oldGainQ12; + oldLagQ7 = lagsQ7[k]; + oldGainQ12 = gainsQ12[k]; + + // Each frame has 4 60-sample pitch subframes, and each subframe has 5 + // 12-sample segments. Each segment need to be processed with + // newly-updated parameters, so we break the pitch filtering into + // two for-loops (5 x 12) below. It's also why kDivFactor = 0.2 (in Q15). + for (cnt = 0; cnt < kSegments; cnt++) { + // Update parameters for each segment. + curGainQ12 += gaindeltaQ12; + curLagQ7 += lagdeltaQ7; + indW32 = CalcLrIntQ(curLagQ7, 7); + tmpW32 = WEBRTC_SPL_LSHIFT_W32(indW32, 7); + tmpW32 -= curLagQ7; + frcQQ = WEBRTC_SPL_RSHIFT_W32(tmpW32, 4); + frcQQ += 4; + + if (frcQQ == PITCH_FRACS) { + frcQQ = 0; + } + fracoeffQQ = kIntrpCoef[frcQQ]; + + // Pitch filtering. + WebRtcIsacfix_PitchFilterCore(PITCH_SUBFRAME_LEN / kSegments, curGainQ12, + indW32, sign, inystateQQ, ubufQQ, fracoeffQQ, indatQQ, outdatQQ, &ind); + } + } + + // Export buffer and states. + memcpy(pfp->ubufQQ, ubufQQ + PITCH_FRAME_LEN, sizeof(pfp->ubufQQ)); + memcpy(pfp->ystateQQ, inystateQQ, sizeof(pfp->ystateQQ)); + + pfp->oldlagQ7 = oldLagQ7; + pfp->oldgainQ12 = oldGainQ12; + + if (type == 2) { + // Filter look-ahead segment. + WebRtcIsacfix_PitchFilterCore(QLOOKAHEAD, curGainQ12, indW32, 1, inystateQQ, + ubufQQ, fracoeffQQ, indatQQ, outdatQQ, &ind); + } +} + + +void WebRtcIsacfix_PitchFilterGains(const WebRtc_Word16* indatQ0, + PitchFiltstr* pfp, + WebRtc_Word16* lagsQ7, + WebRtc_Word16* gainsQ12) { + int k, n, m, ind, pos, pos3QQ; + + WebRtc_Word16 ubufQQ[PITCH_INTBUFFSIZE]; + WebRtc_Word16 oldLagQ7, lagdeltaQ7, curLagQ7; + const WebRtc_Word16* fracoeffQQ = NULL; + WebRtc_Word16 scale; + WebRtc_Word16 cnt = 0, frcQQ, indW16 = 0, tmpW16; + WebRtc_Word32 tmpW32, tmp2W32, csum1QQ, esumxQQ; + + // Set up buffer and states. + memcpy(ubufQQ, pfp->ubufQQ, sizeof(pfp->ubufQQ)); + oldLagQ7 = pfp->oldlagQ7; + + // No interpolation if pitch lag step is big. + if ((WEBRTC_SPL_MUL_16_16_RSFT(lagsQ7[0], 3, 1) < oldLagQ7) || + (lagsQ7[0] > WEBRTC_SPL_MUL_16_16_RSFT(oldLagQ7, 3, 1))) { + oldLagQ7 = lagsQ7[0]; + } + + ind = 0; + pos = ind + PITCH_BUFFSIZE; + scale = 0; + for (k = 0; k < PITCH_SUBFRAMES; k++) { + + // Calculate interpolation steps. + lagdeltaQ7 = lagsQ7[k] - oldLagQ7; + lagdeltaQ7 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( + lagdeltaQ7, kDivFactor, 15); + curLagQ7 = oldLagQ7; + oldLagQ7 = lagsQ7[k]; + + csum1QQ = 1; + esumxQQ = 1; + + // Same as function WebRtcIsacfix_PitchFilter(), we break the pitch + // filtering into two for-loops (5 x 12) below. + for (cnt = 0; cnt < kSegments; cnt++) { + // Update parameters for each segment. + curLagQ7 += lagdeltaQ7; + indW16 = (WebRtc_Word16)CalcLrIntQ(curLagQ7, 7); + tmpW16 = WEBRTC_SPL_LSHIFT_W16(indW16, 7); + tmpW16 -= curLagQ7; + frcQQ = WEBRTC_SPL_RSHIFT_W16(tmpW16, 4); + frcQQ += 4; + + if (frcQQ == PITCH_FRACS) { + frcQQ = 0; + } + fracoeffQQ = kIntrpCoef[frcQQ]; + + pos3QQ = pos - (indW16 + 4); + + for (n = 0; n < PITCH_SUBFRAME_LEN / kSegments; n++) { + // Filter to get fractional pitch. + + tmpW32 = 0; + for (m = 0; m < PITCH_FRACORDER; m++) { + tmpW32 += WEBRTC_SPL_MUL_16_16(ubufQQ[pos3QQ + m], fracoeffQQ[m]); + } + + // Subtract from input and update buffer. + ubufQQ[pos] = indatQ0[ind]; + + tmp2W32 = WEBRTC_SPL_MUL_16_32_RSFT14(indatQ0[ind], tmpW32); + tmpW32 += 8192; + tmpW16 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmpW32, 14); + tmpW32 = WEBRTC_SPL_MUL_16_16(tmpW16, tmpW16); + + if ((tmp2W32 > 1073700000) || (csum1QQ > 1073700000) || + (tmpW32 > 1073700000) || (esumxQQ > 1073700000)) { // 2^30 + scale++; + csum1QQ = WEBRTC_SPL_RSHIFT_W32(csum1QQ, 1); + esumxQQ = WEBRTC_SPL_RSHIFT_W32(esumxQQ, 1); + } + tmp2W32 = WEBRTC_SPL_RSHIFT_W32(tmp2W32, scale); + csum1QQ += tmp2W32; + tmpW32 = WEBRTC_SPL_RSHIFT_W32(tmpW32, scale); + esumxQQ += tmpW32; + + ind++; + pos++; + pos3QQ++; + } + } + + if (csum1QQ < esumxQQ) { + tmp2W32 = WebRtcSpl_DivResultInQ31(csum1QQ, esumxQQ); + + // Gain should be half the correlation. + tmpW32 = WEBRTC_SPL_RSHIFT_W32(tmp2W32, 20); + } else { + tmpW32 = 4096; + } + gainsQ12[k] = (WebRtc_Word16)WEBRTC_SPL_SAT(PITCH_MAX_GAIN_Q12, tmpW32, 0); + } + + // Export buffer and states. + memcpy(pfp->ubufQQ, ubufQQ + PITCH_FRAME_LEN, sizeof(pfp->ubufQQ)); + pfp->oldlagQ7 = lagsQ7[PITCH_SUBFRAMES - 1]; + pfp->oldgainQ12 = gainsQ12[PITCH_SUBFRAMES - 1]; + +} diff --git a/src/modules/audio_coding/codecs/isac/fix/source/pitch_filter_armv6.S b/src/modules/audio_coding/codecs/isac/fix/source/pitch_filter_armv6.S new file mode 100644 index 0000000000..7ce3b6f26d --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/pitch_filter_armv6.S @@ -0,0 +1,147 @@ +@ +@ 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. +@ + +@ Contains the core loop routine for the pitch filter function in iSAC, +@ optimized for ARMv7 platforms. +@ +@ Output is bit-exact with the reference C code in pitch_filter.c. + +#include "settings.h" + +.arch armv6 +.align 2 +.global WebRtcIsacfix_PitchFilterCore + + +@ void WebRtcIsacfix_PitchFilterCore(int loopNumber, +@ WebRtc_Word16 gain, +@ int index, +@ WebRtc_Word16 sign, +@ WebRtc_Word16* inputState, +@ WebRtc_Word16* outputBuf2, +@ const WebRtc_Word16* coefficient, +@ WebRtc_Word16* inputBuf, +@ WebRtc_Word16* outputBuf, +@ int* index2) { + +WebRtcIsacfix_PitchFilterCore: +.fnstart + push {r4-r11} + sub sp, #8 + + str r0, [sp] @ loopNumber + str r3, [sp, #4] @ sign + ldr r3, [sp, #44] @ outputBuf2 + ldr r6, [sp, #60] @ index2 + ldr r7, [r6] @ *index2 + ldr r8, [sp, #52] @ inputBuf + ldr r12, [sp, #56] @ outputBuf + + add r4, r7, r0 + str r4, [r6] @ Store return value to index2. + + mov r10, r7, asl #1 + add r12, r10 @ &outputBuf[*index2] + add r8, r10 @ &inputBuf[*index2] + + add r4, r7, #PITCH_BUFFSIZE @ *index2 + PITCH_BUFFSIZE + add r6, r3, r4, lsl #1 @ &outputBuf2[*index2 + PITCH_BUFFSIZE] + sub r4, r2 @ r2: index + sub r4, #2 @ *index2 + PITCH_BUFFSIZE - index - 2 + add r3, r4, lsl #1 @ &ubufQQpos2[*index2] + ldr r9, [sp, #48] @ coefficient + +LOOP: +@ Usage of registers in the loop: +@ r0: loop counter +@ r1: gain +@ r2: tmpW32 +@ r3: &ubufQQpos2[] +@ r6: &outputBuf2[] +@ r8: &inputBuf[] +@ r9: &coefficient[] +@ r12: &outputBuf[] +@ r4, r5, r7, r10, r11: scratch + + @ Filter to get fractional pitch. + @ The pitch filter loop here is unrolled with 9 multipications. + pld [r3] + ldr r10, [r3], #4 @ ubufQQpos2[*index2 + 0, *index2 + 1] + ldr r4, [r9], #4 @ coefficient[0, 1] + ldr r11, [r3], #4 + ldr r5, [r9], #4 + smuad r2, r10, r4 + smlad r2, r11, r5, r2 + + ldr r10, [r3], #4 + ldr r4, [r9], #4 + ldr r11, [r3], #4 + ldr r5, [r9], #4 + smlad r2, r10, r4, r2 + ldrh r10, [r3], #-14 @ r3 back to &ubufQQpos2[*index2]. + ldrh r4, [r9], #-16 @ r9 back to &coefficient[0]. + smlad r2, r11, r5, r2 + smlabb r2, r10, r4, r2 + + @ Saturate to avoid overflow in tmpW16. + asr r2, #1 + add r4, r2, #0x1000 + ssat r7, #16, r4, asr #13 + + @ Shift low pass filter state, and excute the low pass filter. + @ The memmove() and the low pass filter loop are unrolled and mixed. + smulbb r5, r1, r7 + add r7, r5, #0x800 + asr r7, #12 @ Get the value for inputState[0]. + ldr r11, [sp, #40] @ inputState + pld [r11] + adr r10, kDampFilter + ldrsh r4, [r10], #2 @ kDampFilter[0] + mul r2, r7, r4 + ldr r4, [r11] @ inputState[0, 1], before shift. + strh r7, [r11] @ inputState[0], after shift. + ldr r5, [r11, #4] @ inputState[2, 3], before shift. + ldr r7, [r10], #4 @ kDampFilter[1, 2] + ldr r10, [r10] @ kDampFilter[3, 4] + str r4, [r11, #2] @ inputState[1, 2], after shift. + str r5, [r11, #6] @ inputState[3, 4], after shift. + smlad r2, r4, r7, r2 + smlad r2, r5, r10, r2 + + @ Saturate to avoid overflow. + @ First shift the sample to the range of [0xC0000000, 0x3FFFFFFF], + @ to avoid overflow in the next saturation step. + asr r2, #1 + add r10, r2, #0x2000 + ssat r10, #16, r10, asr #14 + + @ Subtract from input and update buffer. + ldr r11, [sp, #4] @ sign + ldrsh r4, [r8] + ldrsh r7, [r8], #2 @ inputBuf[*index2] + smulbb r5, r11, r10 + subs r0, #1 + sub r4, r5 + ssat r2, #16, r4 + strh r2, [r12], #2 @ outputBuf[*index2] + + add r2, r7 + ssat r2, #16, r2 + strh r2, [r6], #2 @ outputBuff2[*index2 + PITCH_BUFFSIZE] + bgt LOOP + + add sp, #8 + pop {r4-r11} + bx lr +.fnend + +.align 2 +kDampFilter: + .short -2294, 8192, 20972, 8192, -2294 diff --git a/src/modules/audio_coding/codecs/isac/fix/source/pitch_filter_c.c b/src/modules/audio_coding/codecs/isac/fix/source/pitch_filter_c.c new file mode 100644 index 0000000000..29b4b6af6e --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/pitch_filter_c.c @@ -0,0 +1,74 @@ +/* + * 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 "common_audio/signal_processing/include/signal_processing_library.h" +#include "modules/audio_coding/codecs/isac/fix/source/pitch_estimator.h" + +/* Filter coefficicients in Q15. */ +static const WebRtc_Word16 kDampFilter[PITCH_DAMPORDER] = { + -2294, 8192, 20972, 8192, -2294 +}; + +void WebRtcIsacfix_PitchFilterCore(int loopNumber, + WebRtc_Word16 gain, + int index, + WebRtc_Word16 sign, + WebRtc_Word16* inputState, + WebRtc_Word16* outputBuf2, + const WebRtc_Word16* coefficient, + WebRtc_Word16* inputBuf, + WebRtc_Word16* outputBuf, + int* index2) { + int i = 0, j = 0; /* Loop counters. */ + WebRtc_Word16* ubufQQpos2 = &outputBuf2[PITCH_BUFFSIZE - (index + 2)]; + WebRtc_Word16 tmpW16 = 0; + + for (i = 0; i < loopNumber; i++) { + WebRtc_Word32 tmpW32 = 0; + + /* Filter to get fractional pitch. */ + for (j = 0; j < PITCH_FRACORDER; j++) { + tmpW32 += WEBRTC_SPL_MUL_16_16(ubufQQpos2[*index2 + j], coefficient[j]); + } + + /* Saturate to avoid overflow in tmpW16. */ + tmpW32 = WEBRTC_SPL_SAT(536862719, tmpW32, -536879104); + tmpW32 += 8192; + tmpW16 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmpW32, 14); + + /* Shift low pass filter state. */ + memmove(&inputState[1], &inputState[0], + (PITCH_DAMPORDER - 1) * sizeof(WebRtc_Word16)); + inputState[0] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( + gain, tmpW16, 12); + + /* Low pass filter. */ + tmpW32 = 0; + /* TODO(kma): Define a static inline function WebRtcSpl_DotProduct() + in spl_inl.h to replace this and other similar loops. */ + for (j = 0; j < PITCH_DAMPORDER; j++) { + tmpW32 += WEBRTC_SPL_MUL_16_16(inputState[j], kDampFilter[j]); + } + + /* Saturate to avoid overflow in tmpW16. */ + tmpW32 = WEBRTC_SPL_SAT(1073725439, tmpW32, -1073758208); + tmpW32 += 16384; + tmpW16 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmpW32, 15); + + /* Subtract from input and update buffer. */ + tmpW32 = inputBuf[*index2] - WEBRTC_SPL_MUL_16_16(sign, tmpW16); + outputBuf[*index2] = WebRtcSpl_SatW32ToW16(tmpW32); + tmpW32 = inputBuf[*index2] + outputBuf[*index2]; + outputBuf2[*index2 + PITCH_BUFFSIZE] = WebRtcSpl_SatW32ToW16(tmpW32); + + (*index2)++; + } +} + diff --git a/src/modules/audio_coding/codecs/isac/fix/source/pitch_gain_tables.c b/src/modules/audio_coding/codecs/isac/fix/source/pitch_gain_tables.c new file mode 100644 index 0000000000..50ea658360 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/pitch_gain_tables.c @@ -0,0 +1,149 @@ +/* + * 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.c + * + * This file contains tables for the pitch filter side-info in the entropy coder. + * + */ + +#include "pitch_gain_tables.h" + + +/********************* Pitch Filter Gain Coefficient Tables ************************/ + +/* cdf for quantized pitch filter gains */ +const WebRtc_UWord16 WebRtcIsacfix_kPitchGainCdf[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 WebRtcIsacfix_kLowerlimiGain[3] = { + -7, -2, -1 +}; + +const WebRtc_Word16 WebRtcIsacfix_kUpperlimitGain[3] = { + 0, 3, 1 +}; + +const WebRtc_UWord16 WebRtcIsacfix_kMultsGain[2] = { + 18, 3 +}; + +/* size of cdf table */ +const WebRtc_UWord16 WebRtcIsacfix_kCdfTableSizeGain[1] = { + 256 +}; + +/* mean values of pitch filter gains in FIXED point Q12 */ +const WebRtc_Word16 WebRtcIsacfix_kPitchGain1[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 WebRtcIsacfix_kPitchGain2[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 WebRtcIsacfix_kPitchGain3[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 WebRtcIsacfix_kPitchGain4[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 +}; + + + +/* transform matrix in Q12*/ +const WebRtc_Word16 WebRtcIsacfix_kTransform[4][4] = { + { -2048, -2048, -2048, -2048 }, + { 2748, 916, -916, -2748 }, + { 2048, -2048, -2048, 2048 }, + { 916, -2748, 2748, -916 } +}; diff --git a/src/modules/audio_coding/codecs/isac/fix/source/pitch_gain_tables.h b/src/modules/audio_coding/codecs/isac/fix/source/pitch_gain_tables.h new file mode 100644 index 0000000000..788e5536b7 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/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_FIX_SOURCE_PITCH_GAIN_TABLES_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_PITCH_GAIN_TABLES_H_ + +#include "typedefs.h" + + +/********************* Pitch Filter Gain Coefficient Tables ************************/ +/* cdf for quantized pitch filter gains */ +extern const WebRtc_UWord16 WebRtcIsacfix_kPitchGainCdf[255]; + +/* index limits and ranges */ +extern const WebRtc_Word16 WebRtcIsacfix_kLowerlimiGain[3]; +extern const WebRtc_Word16 WebRtcIsacfix_kUpperlimitGain[3]; +extern const WebRtc_UWord16 WebRtcIsacfix_kMultsGain[2]; + +/* mean values of pitch filter gains in Q12*/ +extern const WebRtc_Word16 WebRtcIsacfix_kPitchGain1[144]; +extern const WebRtc_Word16 WebRtcIsacfix_kPitchGain2[144]; +extern const WebRtc_Word16 WebRtcIsacfix_kPitchGain3[144]; +extern const WebRtc_Word16 WebRtcIsacfix_kPitchGain4[144]; + +/* size of cdf table */ +extern const WebRtc_UWord16 WebRtcIsacfix_kCdfTableSizeGain[1]; + +/* transform matrix */ +extern const WebRtc_Word16 WebRtcIsacfix_kTransform[4][4]; + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_PITCH_GAIN_TABLES_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/fix/source/pitch_lag_tables.c b/src/modules/audio_coding/codecs/isac/fix/source/pitch_lag_tables.c new file mode 100644 index 0000000000..81700e4745 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/pitch_lag_tables.c @@ -0,0 +1,306 @@ +/* + * 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.c + * + * This file contains tables for the pitch filter side-info in the entropy coder. + * + */ + +#include "settings.h" +#include "pitch_lag_tables.h" + + +/********************* Pitch Filter Gain Coefficient Tables ************************/ + +/* tables for use with small pitch gain */ + +/* cdf for quantized pitch filter lags */ +const WebRtc_UWord16 WebRtcIsacfix_kPitchLagCdf1Lo[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 WebRtcIsacfix_kPitchLagCdf2Lo[20] = { + 0, 429, 3558, 5861, 8558, 11639, 15210, 19502, 24773, 31983, + 42602, 48567, 52601, 55676, 58160, 60172, 61889, 63235, 65383, 65535 +}; + +const WebRtc_UWord16 WebRtcIsacfix_kPitchLagCdf3Lo[2] = { + 0, 65535 +}; + +const WebRtc_UWord16 WebRtcIsacfix_kPitchLagCdf4Lo[10] = { + 0, 2966, 6368, 11182, 19431, 37793, 48532, 55353, 60626, 65535 +}; + +const WebRtc_UWord16 *WebRtcIsacfix_kPitchLagPtrLo[4] = { + WebRtcIsacfix_kPitchLagCdf1Lo, + WebRtcIsacfix_kPitchLagCdf2Lo, + WebRtcIsacfix_kPitchLagCdf3Lo, + WebRtcIsacfix_kPitchLagCdf4Lo +}; + +/* size of first cdf table */ +const WebRtc_UWord16 WebRtcIsacfix_kPitchLagSizeLo[1] = { + 128 +}; + +/* index limits and ranges */ +const WebRtc_Word16 WebRtcIsacfix_kLowerLimitLo[4] = { + -140, -9, 0, -4 +}; + +const WebRtc_Word16 WebRtcIsacfix_kUpperLimitLo[4] = { + -20, 9, 0, 4 +}; + +/* initial index for arithmetic decoder */ +const WebRtc_UWord16 WebRtcIsacfix_kInitIndLo[3] = { + 10, 1, 5 +}; + +/* mean values of pitch filter lags in Q10 */ + +const WebRtc_Word16 WebRtcIsacfix_kMeanLag2Lo[19] = { + -17627, -16207, -14409, -12319, -10253, -8200, -6054, -3986, -1948, -19, + 1937, 3974, 6064, 8155, 10229, 12270, 14296, 16127, 17520 +}; + +const WebRtc_Word16 WebRtcIsacfix_kMeanLag4Lo[9] = { + -7949, -6063, -4036, -1941, 38, 1977, 4060, 6059 +}; + + + +/* tables for use with medium pitch gain */ + +/* cdf for quantized pitch filter lags */ +const WebRtc_UWord16 WebRtcIsacfix_kPitchLagCdf1Mid[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 WebRtcIsacfix_kPitchLagCdf2Mid[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 WebRtcIsacfix_kPitchLagCdf3Mid[2] = { + 0, 65535 +}; + +const WebRtc_UWord16 WebRtcIsacfix_kPitchLagCdf4Mid[20] = { + 0, 28, 246, 459, 667, 1045, 1523, 2337, 4337, 11347, + 44231, 56709, 60781, 62243, 63161, 63969, 64608, 65062, 65502, 65535 +}; + +const WebRtc_UWord16 *WebRtcIsacfix_kPitchLagPtrMid[4] = { + WebRtcIsacfix_kPitchLagCdf1Mid, + WebRtcIsacfix_kPitchLagCdf2Mid, + WebRtcIsacfix_kPitchLagCdf3Mid, + WebRtcIsacfix_kPitchLagCdf4Mid +}; + +/* size of first cdf table */ +const WebRtc_UWord16 WebRtcIsacfix_kPitchLagSizeMid[1] = { + 256 +}; + +/* index limits and ranges */ +const WebRtc_Word16 WebRtcIsacfix_kLowerLimitMid[4] = { + -280, -17, 0, -9 +}; + +const WebRtc_Word16 WebRtcIsacfix_kUpperLimitMid[4] = { + -40, 17, 0, 9 +}; + +/* initial index for arithmetic decoder */ +const WebRtc_UWord16 WebRtcIsacfix_kInitIndMid[3] = { + 18, 1, 10 +}; + +/* mean values of pitch filter lags in Q10 */ + +const WebRtc_Word16 WebRtcIsacfix_kMeanLag2Mid[35] = { + -17297, -16250, -15416, -14343, -13341, -12363, -11270, + -10355, -9122, -8217, -7172, -6083, -5102, -4004, -3060, + -1982, -952, -18, 935, 1976, 3040, 4032, + 5082, 6065, 7257, 8202, 9264, 10225, 11242, + 12234, 13337, 14336, 15374, 16187, 17347 +}; + + +const WebRtc_Word16 WebRtcIsacfix_kMeanLag4Mid[19] = { + -8811, -8081, -7203, -6003, -5057, -4025, -2983, -1964, + -891, 29, 921, 1920, 2988, 4064, 5187, 6079, 7173, 8074, 8849 +}; + + +/* tables for use with large pitch gain */ + +/* cdf for quantized pitch filter lags */ +const WebRtc_UWord16 WebRtcIsacfix_kPitchLagCdf1Hi[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 WebRtcIsacfix_kPitchLagCdf2Hi[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 WebRtcIsacfix_kPitchLagCdf3Hi[2] = { + 0, 65535 +}; + +const WebRtc_UWord16 WebRtcIsacfix_kPitchLagCdf4Hi[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 *WebRtcIsacfix_kPitchLagPtrHi[4] = { + WebRtcIsacfix_kPitchLagCdf1Hi, + WebRtcIsacfix_kPitchLagCdf2Hi, + WebRtcIsacfix_kPitchLagCdf3Hi, + WebRtcIsacfix_kPitchLagCdf4Hi +}; + +/* size of first cdf table */ +const WebRtc_UWord16 WebRtcIsacfix_kPitchLagSizeHi[1] = { + 512 +}; + +/* index limits and ranges */ +const WebRtc_Word16 WebRtcIsacfix_kLowerLimitHi[4] = { + -552, -34, 0, -16 +}; + +const WebRtc_Word16 WebRtcIsacfix_kUpperLimitHi[4] = { + -80, 32, 0, 17 +}; + +/* initial index for arithmetic decoder */ +const WebRtc_UWord16 WebRtcIsacfix_kInitIndHi[3] = { + 34, 1, 18 +}; + +/* mean values of pitch filter lags */ + +const WebRtc_Word16 WebRtcIsacfix_kMeanLag2Hi[67] = { + -17482, -16896, -16220, -15929, -15329, -14848, -14336, -13807, -13312, -12800, -12218, -11720, + -11307, -10649, -10396, -9742, -9148, -8668, -8297, -7718, -7155, -6656, -6231, -5600, -5129, + -4610, -4110, -3521, -3040, -2525, -2016, -1506, -995, -477, -5, 469, 991, 1510, 2025, 2526, 3079, + 3555, 4124, 4601, 5131, 5613, 6194, 6671, 7140, 7645, 8207, 8601, 9132, 9728, 10359, 10752, 11302, + 11776, 12288, 12687, 13204, 13759, 14295, 14810, 15360, 15764, 16350 +}; + + +const WebRtc_Word16 WebRtcIsacfix_kMeanLag4Hi[34] = { + -8175, -7659, -7205, -6684, -6215, -5651, -5180, -4566, -4087, -3536, -3096, + -2532, -1990, -1482, -959, -440, 11, 451, 954, 1492, 2020, 2562, 3059, + 3577, 4113, 4618, 5134, 5724, 6060, 6758, 7015, 7716, 8066, 8741 +}; diff --git a/src/modules/audio_coding/codecs/isac/fix/source/pitch_lag_tables.h b/src/modules/audio_coding/codecs/isac/fix/source/pitch_lag_tables.h new file mode 100644 index 0000000000..9517c29b3d --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/pitch_lag_tables.h @@ -0,0 +1,103 @@ +/* + * 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_FIX_SOURCE_PITCH_LAG_TABLES_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_PITCH_LAG_TABLES_H_ + + +#include "typedefs.h" + + +/********************* Pitch Filter Lag Coefficient Tables ************************/ + +/* tables for use with small pitch gain */ + +/* cdfs for quantized pitch lags */ +extern const WebRtc_UWord16 WebRtcIsacfix_kPitchLagCdf1Lo[127]; +extern const WebRtc_UWord16 WebRtcIsacfix_kPitchLagCdf2Lo[20]; +extern const WebRtc_UWord16 WebRtcIsacfix_kPitchLagCdf3Lo[2]; +extern const WebRtc_UWord16 WebRtcIsacfix_kPitchLagCdf4Lo[10]; + +extern const WebRtc_UWord16 *WebRtcIsacfix_kPitchLagPtrLo[4]; + +/* size of first cdf table */ +extern const WebRtc_UWord16 WebRtcIsacfix_kPitchLagSizeLo[1]; + +/* index limits and ranges */ +extern const WebRtc_Word16 WebRtcIsacfix_kLowerLimitLo[4]; +extern const WebRtc_Word16 WebRtcIsacfix_kUpperLimitLo[4]; + +/* initial index for arithmetic decoder */ +extern const WebRtc_UWord16 WebRtcIsacfix_kInitIndLo[3]; + +/* mean values of pitch filter lags */ +extern const WebRtc_Word16 WebRtcIsacfix_kMeanLag2Lo[19]; +extern const WebRtc_Word16 WebRtcIsacfix_kMeanLag4Lo[9]; + + + +/* tables for use with medium pitch gain */ + +/* cdfs for quantized pitch lags */ +extern const WebRtc_UWord16 WebRtcIsacfix_kPitchLagCdf1Mid[255]; +extern const WebRtc_UWord16 WebRtcIsacfix_kPitchLagCdf2Mid[36]; +extern const WebRtc_UWord16 WebRtcIsacfix_kPitchLagCdf3Mid[2]; +extern const WebRtc_UWord16 WebRtcIsacfix_kPitchLagCdf4Mid[20]; + +extern const WebRtc_UWord16 *WebRtcIsacfix_kPitchLagPtrMid[4]; + +/* size of first cdf table */ +extern const WebRtc_UWord16 WebRtcIsacfix_kPitchLagSizeMid[1]; + +/* index limits and ranges */ +extern const WebRtc_Word16 WebRtcIsacfix_kLowerLimitMid[4]; +extern const WebRtc_Word16 WebRtcIsacfix_kUpperLimitMid[4]; + +/* initial index for arithmetic decoder */ +extern const WebRtc_UWord16 WebRtcIsacfix_kInitIndMid[3]; + +/* mean values of pitch filter lags */ +extern const WebRtc_Word16 WebRtcIsacfix_kMeanLag2Mid[35]; +extern const WebRtc_Word16 WebRtcIsacfix_kMeanLag4Mid[19]; + + +/* tables for use with large pitch gain */ + +/* cdfs for quantized pitch lags */ +extern const WebRtc_UWord16 WebRtcIsacfix_kPitchLagCdf1Hi[511]; +extern const WebRtc_UWord16 WebRtcIsacfix_kPitchLagCdf2Hi[68]; +extern const WebRtc_UWord16 WebRtcIsacfix_kPitchLagCdf3Hi[2]; +extern const WebRtc_UWord16 WebRtcIsacfix_kPitchLagCdf4Hi[35]; + +extern const WebRtc_UWord16 *WebRtcIsacfix_kPitchLagPtrHi[4]; + +/* size of first cdf table */ +extern const WebRtc_UWord16 WebRtcIsacfix_kPitchLagSizeHi[1]; + +/* index limits and ranges */ +extern const WebRtc_Word16 WebRtcIsacfix_kLowerLimitHi[4]; +extern const WebRtc_Word16 WebRtcIsacfix_kUpperLimitHi[4]; + +/* initial index for arithmetic decoder */ +extern const WebRtc_UWord16 WebRtcIsacfix_kInitIndHi[3]; + +/* mean values of pitch filter lags */ +extern const WebRtc_Word16 WebRtcIsacfix_kMeanLag2Hi[67]; +extern const WebRtc_Word16 WebRtcIsacfix_kMeanLag4Hi[34]; + + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_PITCH_LAG_TABLES_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/fix/source/settings.h b/src/modules/audio_coding/codecs/isac/fix/source/settings.h new file mode 100644 index 0000000000..da88ba25ff --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/settings.h @@ -0,0 +1,205 @@ +/* + * 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. + */ + +/* + * settings.h + * + * Declaration of #defines used in the iSAC codec + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_SETTINGS_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_SETTINGS_H_ + + +/* sampling frequency (Hz) */ +#define FS 16000 +/* 1.5 times Sampling frequency */ +#define FS_1_HALF (WebRtc_UWord32) 24000 +/* Three times Sampling frequency */ +#define FS3 (WebRtc_UWord32) 48000 +/* Eight times Sampling frequency */ +#define FS8 (WebRtc_UWord32) 128000 + +/* number of samples per frame (either 480 (30ms) or 960 (60ms)) */ +#define INITIAL_FRAMESAMPLES 960 + +/* miliseconds */ +#define FRAMESIZE 30 +/* number of samples per frame processed in the encoder (30ms) */ +#define FRAMESAMPLES 480 /* ((FRAMESIZE*FS)/1000) */ +#define FRAMESAMPLES_HALF 240 +/* max number of samples per frame (= 60 ms frame) */ +#define MAX_FRAMESAMPLES 960 +/* number of samples per 10ms frame */ +#define FRAMESAMPLES_10ms 160 /* ((10*FS)/1000) */ +/* Number of samples per 1 ms */ +#define SAMPLES_PER_MSEC 16 +/* number of subframes */ +#define SUBFRAMES 6 +/* length of a subframe */ +#define UPDATE 80 +/* length of half a subframe (low/high band) */ +#define HALF_SUBFRAMELEN 40 /* (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 +#define MAX_ORDER 13 +#define LEVINSON_MAX_ORDER 12 + +/* 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 KLT_NUM_AVG_GAIN 0 +#define KLT_NUM_AVG_SHAPE 0 +#define KLT_NUM_MODELS 3 +#define LPC_SHAPE_ORDER 18 /* (ORDERLO + ORDERHI) */ + +#define KLT_ORDER_GAIN 12 /* (2 * SUBFRAMES) */ +#define KLT_ORDER_SHAPE 108 /* (LPC_SHAPE_ORDER * SUBFRAMES) */ + + + +/* order for post_filter_bank */ +#define POSTQORDER 3 +/* order for pre-filterbank */ +#define QORDER 3 +/* for decimator */ +#define ALLPASSSECTIONS 2 +/* The number of composite all-pass filter factors */ +#define NUMBEROFCOMPOSITEAPSECTIONS 4 + +/* The number of all-pass filter factors in an upper or lower channel*/ +#define NUMBEROFCHANNELAPSECTIONS 2 + + + +#define DPMIN_Q10 -10240 /* -10.00 in Q10 */ +#define DPMAX_Q10 10240 /* 10.00 in Q10 */ +#define MINBITS_Q10 10240 /* 10.0 in Q10 */ + + +/* array size for byte stream in number of Word16. */ +#define STREAM_MAXW16 300 /* The old maximum size still needed for the decoding */ +#define STREAM_MAXW16_30MS 100 /* 100 Word16 = 200 bytes = 53.4 kbit/s @ 30 ms.framelength */ +#define STREAM_MAXW16_60MS 200 /* 200 Word16 = 400 bytes = 53.4 kbit/s @ 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 + +/* Maximum number of iterations allowed to limit payload size */ +#define MAX_PAYLOAD_LIMIT_ITERATION 1 + +/* Bandwidth estimator */ + +#define MIN_ISAC_BW 10000 /* Minimum bandwidth in bits per sec */ +#define MAX_ISAC_BW 32000 /* Maxmum bandwidth in bits per sec */ +#define MIN_ISAC_MD 5 /* Minimum Max Delay in ?? */ +#define MAX_ISAC_MD 25 /* Maxmum Max Delay in ?? */ +#define DELAY_CORRECTION_MAX 717 +#define DELAY_CORRECTION_MED 819 +#define Thld_30_60 18000 +#define Thld_60_30 27000 + +/* assumed header size; we don't know the exact number (header compression may be used) */ +#define HEADER_SIZE 35 /* bytes */ +#define INIT_FRAME_LEN 60 +#define INIT_BN_EST 20000 +#define INIT_BN_EST_Q7 2560000 /* 20 kbps in Q7 */ +#define INIT_REC_BN_EST_Q5 789312 /* INIT_BN_EST + INIT_HDR_RATE in Q5 */ + +/* 8738 in Q18 is ~ 1/30 */ +/* #define INIT_HDR_RATE (((HEADER_SIZE * 8 * 1000) * 8738) >> NUM_BITS_TO_SHIFT (INIT_FRAME_LEN)) */ +#define INIT_HDR_RATE 4666 +/* 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 800 +/* 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 10240000 /* INIT_BN_EST in Q9 */ + + +/* For pitch analysis */ +#define PITCH_FRAME_LEN 240 /* (FRAMESAMPLES/2) 30 ms */ +#define PITCH_MAX_LAG 140 /* 57 Hz */ +#define PITCH_MIN_LAG 20 /* 400 Hz */ +#define PITCH_MIN_LAG_Q8 5120 /* 256 * PITCH_MIN_LAG */ +#define OFFSET_Q8 768 /* 256 * 3 */ + +#define PITCH_MAX_GAIN_Q12 1843 /* 0.45 */ +#define PITCH_LAG_SPAN2 65 /* (PITCH_MAX_LAG/2-PITCH_MIN_LAG/2+5) */ +#define PITCH_CORR_LEN2 60 /* 15 ms */ +#define PITCH_CORR_STEP2 60 /* (PITCH_FRAME_LEN/4) */ +#define PITCH_SUBFRAMES 4 +#define PITCH_SUBFRAME_LEN 60 /* (PITCH_FRAME_LEN/PITCH_SUBFRAMES) */ + +/* For pitch filter */ +#define PITCH_BUFFSIZE 190 /* (PITCH_MAX_LAG + 50) Extra 50 for fraction and LP filters */ +#define PITCH_INTBUFFSIZE 430 /* (PITCH_FRAME_LEN+PITCH_BUFFSIZE) */ +#define PITCH_FRACS 8 +#define PITCH_FRACORDER 9 +#define PITCH_DAMPORDER 5 + + +/* Order of high pass filter */ +#define HPORDER 2 + + +/* PLC */ +#define DECAY_RATE 10 /* Q15, 20% of decay every lost frame apllied linearly sample by sample*/ +#define PLC_WAS_USED 1 +#define PLC_NOT_USED 3 +#define RECOVERY_OVERLAP 80 +#define RESAMP_RES 256 +#define RESAMP_RES_BIT 8 + + + +/* 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 +/* 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 +/* 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 +/* 6800 Call setup formats */ +#define ISAC_INCOMPATIBLE_FORMATS 6810 + + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_SETTINGS_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/fix/source/spectrum_ar_model_tables.c b/src/modules/audio_coding/codecs/isac/fix/source/spectrum_ar_model_tables.c new file mode 100644 index 0000000000..81b932fd80 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/spectrum_ar_model_tables.c @@ -0,0 +1,193 @@ +/* + * 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.c + * + * This file contains tables with AR coefficients, Gain coefficients + * and cosine tables. + * + */ + +#include "spectrum_ar_model_tables.h" +#include "settings.h" + +/********************* AR Coefficient Tables ************************/ + +/* cdf for quantized reflection coefficient 1 */ +const WebRtc_UWord16 WebRtcIsacfix_kRc1Cdf[12] = { + 0, 2, 4, 129, 7707, 57485, 65495, 65527, 65529, 65531, + 65533, 65535 +}; + +/* cdf for quantized reflection coefficient 2 */ +const WebRtc_UWord16 WebRtcIsacfix_kRc2Cdf[12] = { + 0, 2, 4, 7, 531, 25298, 64525, 65526, 65529, 65531, + 65533, 65535 +}; + +/* cdf for quantized reflection coefficient 3 */ +const WebRtc_UWord16 WebRtcIsacfix_kRc3Cdf[12] = { + 0, 2, 4, 6, 620, 22898, 64843, 65527, 65529, 65531, + 65533, 65535 +}; + +/* cdf for quantized reflection coefficient 4 */ +const WebRtc_UWord16 WebRtcIsacfix_kRc4Cdf[12] = { + 0, 2, 4, 6, 35, 10034, 60733, 65506, 65529, 65531, + 65533, 65535 +}; + +/* cdf for quantized reflection coefficient 5 */ +const WebRtc_UWord16 WebRtcIsacfix_kRc5Cdf[12] = { + 0, 2, 4, 6, 36, 7567, 56727, 65385, 65529, 65531, + 65533, 65535 +}; + +/* cdf for quantized reflection coefficient 6 */ +const WebRtc_UWord16 WebRtcIsacfix_kRc6Cdf[12] = { + 0, 2, 4, 6, 14, 6579, 57360, 65409, 65529, 65531, + 65533, 65535 +}; + +/* representation levels for quantized reflection coefficient 1 */ +const WebRtc_Word16 WebRtcIsacfix_kRc1Levels[11] = { + -32104, -29007, -23202, -15496, -9279, -2577, 5934, 17535, 24512, 29503, 32104 +}; + +/* representation levels for quantized reflection coefficient 2 */ +const WebRtc_Word16 WebRtcIsacfix_kRc2Levels[11] = { + -32104, -29503, -23494, -15261, -7309, -1399, 6158, 16381, 24512, 29503, 32104 +}; + +/* representation levels for quantized reflection coefficient 3 */ +const WebRtc_Word16 WebRtcIsacfix_kRc3Levels[11] = { + -32104, -29503, -23157, -15186, -7347, -1359, 5829, 17535, 24512, 29503, 32104 +}; + +/* representation levels for quantized reflection coefficient 4 */ +const WebRtc_Word16 WebRtcIsacfix_kRc4Levels[11] = { + -32104, -29503, -24512, -15362, -6665, -342, 6596, 14585, 24512, 29503, 32104 +}; + +/* representation levels for quantized reflection coefficient 5 */ +const WebRtc_Word16 WebRtcIsacfix_kRc5Levels[11] = { + -32104, -29503, -24512, -15005, -6564, -106, 7123, 14920, 24512, 29503, 32104 +}; + +/* representation levels for quantized reflection coefficient 6 */ +const WebRtc_Word16 WebRtcIsacfix_kRc6Levels[11] = { + -32104, -29503, -24512, -15096, -6656, -37, 7036, 14847, 24512, 29503, 32104 +}; + +/* quantization boundary levels for reflection coefficients */ +const WebRtc_Word16 WebRtcIsacfix_kRcBound[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 WebRtcIsacfix_kRcInitInd[6] = { + 5, 5, 5, 5, 5, 5 +}; + +/* pointers to AR cdf tables */ +const WebRtc_UWord16 *WebRtcIsacfix_kRcCdfPtr[AR_ORDER] = { + WebRtcIsacfix_kRc1Cdf, + WebRtcIsacfix_kRc2Cdf, + WebRtcIsacfix_kRc3Cdf, + WebRtcIsacfix_kRc4Cdf, + WebRtcIsacfix_kRc5Cdf, + WebRtcIsacfix_kRc6Cdf +}; + +/* pointers to AR representation levels tables */ +const WebRtc_Word16 *WebRtcIsacfix_kRcLevPtr[AR_ORDER] = { + WebRtcIsacfix_kRc1Levels, + WebRtcIsacfix_kRc2Levels, + WebRtcIsacfix_kRc3Levels, + WebRtcIsacfix_kRc4Levels, + WebRtcIsacfix_kRc5Levels, + WebRtcIsacfix_kRc6Levels +}; + + +/******************** GAIN Coefficient Tables ***********************/ + +/* cdf for Gain coefficient */ +const WebRtc_UWord16 WebRtcIsacfix_kGainCdf[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 WebRtcIsacfix_kGain2Lev[18] = { + 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 WebRtcIsacfix_kGain2Bound[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 *WebRtcIsacfix_kGainPtr[1] = { + WebRtcIsacfix_kGainCdf +}; + +/* gain initial index for gain quantizer and cdf table search */ +const WebRtc_UWord16 WebRtcIsacfix_kGainInitInd[1] = { + 11 +}; + + +/************************* Cosine Tables ****************************/ + +/* cosine table */ +const WebRtc_Word16 WebRtcIsacfix_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/fix/source/spectrum_ar_model_tables.h b/src/modules/audio_coding/codecs/isac/fix/source/spectrum_ar_model_tables.h new file mode 100644 index 0000000000..b506d0e43d --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/spectrum_ar_model_tables.h @@ -0,0 +1,96 @@ +/* + * 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_FIX_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_ + +#include "typedefs.h" +#include "settings.h" + + +/********************* AR Coefficient Tables ************************/ +/* cdf for quantized reflection coefficient 1 */ +extern const WebRtc_UWord16 WebRtcIsacfix_kRc1Cdf[12]; + +/* cdf for quantized reflection coefficient 2 */ +extern const WebRtc_UWord16 WebRtcIsacfix_kRc2Cdf[12]; + +/* cdf for quantized reflection coefficient 3 */ +extern const WebRtc_UWord16 WebRtcIsacfix_kRc3Cdf[12]; + +/* cdf for quantized reflection coefficient 4 */ +extern const WebRtc_UWord16 WebRtcIsacfix_kRc4Cdf[12]; + +/* cdf for quantized reflection coefficient 5 */ +extern const WebRtc_UWord16 WebRtcIsacfix_kRc5Cdf[12]; + +/* cdf for quantized reflection coefficient 6 */ +extern const WebRtc_UWord16 WebRtcIsacfix_kRc6Cdf[12]; + +/* representation levels for quantized reflection coefficient 1 */ +extern const WebRtc_Word16 WebRtcIsacfix_kRc1Levels[11]; + +/* representation levels for quantized reflection coefficient 2 */ +extern const WebRtc_Word16 WebRtcIsacfix_kRc2Levels[11]; + +/* representation levels for quantized reflection coefficient 3 */ +extern const WebRtc_Word16 WebRtcIsacfix_kRc3Levels[11]; + +/* representation levels for quantized reflection coefficient 4 */ +extern const WebRtc_Word16 WebRtcIsacfix_kRc4Levels[11]; + +/* representation levels for quantized reflection coefficient 5 */ +extern const WebRtc_Word16 WebRtcIsacfix_kRc5Levels[11]; + +/* representation levels for quantized reflection coefficient 6 */ +extern const WebRtc_Word16 WebRtcIsacfix_kRc6Levels[11]; + +/* quantization boundary levels for reflection coefficients */ +extern const WebRtc_Word16 WebRtcIsacfix_kRcBound[12]; + +/* initial indices for AR reflection coefficient quantizer and cdf table search */ +extern const WebRtc_UWord16 WebRtcIsacfix_kRcInitInd[AR_ORDER]; + +/* pointers to AR cdf tables */ +extern const WebRtc_UWord16 *WebRtcIsacfix_kRcCdfPtr[AR_ORDER]; + +/* pointers to AR representation levels tables */ +extern const WebRtc_Word16 *WebRtcIsacfix_kRcLevPtr[AR_ORDER]; + + +/******************** GAIN Coefficient Tables ***********************/ +/* cdf for Gain coefficient */ +extern const WebRtc_UWord16 WebRtcIsacfix_kGainCdf[19]; + +/* representation levels for quantized Gain coefficient */ +extern const WebRtc_Word32 WebRtcIsacfix_kGain2Lev[18]; + +/* squared quantization boundary levels for Gain coefficient */ +extern const WebRtc_Word32 WebRtcIsacfix_kGain2Bound[19]; + +/* pointer to Gain cdf table */ +extern const WebRtc_UWord16 *WebRtcIsacfix_kGainPtr[1]; + +/* Gain initial index for gain quantizer and cdf table search */ +extern const WebRtc_UWord16 WebRtcIsacfix_kGainInitInd[1]; + +/************************* Cosine Tables ****************************/ +/* Cosine table */ +extern const WebRtc_Word16 WebRtcIsacfix_kCos[6][60]; + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/fix/source/structs.h b/src/modules/audio_coding/codecs/isac/fix/source/structs.h new file mode 100644 index 0000000000..c038a433f0 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/structs.h @@ -0,0 +1,382 @@ +/* + * 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. + */ + +/* + * structs.h + * + * This header file contains all the structs used in the ISAC codec + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_STRUCTS_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_STRUCTS_H_ + + +#include "common_audio/signal_processing/include/signal_processing_library.h" +#include "modules/audio_coding/codecs/isac/fix/source/settings.h" +#include "typedefs.h" + +/* Bitstream struct for decoder */ +typedef struct Bitstreamstruct_dec { + + WebRtc_UWord16 *stream; /* Pointer to bytestream to decode */ + WebRtc_UWord32 W_upper; /* Upper boundary of interval W */ + WebRtc_UWord32 streamval; + WebRtc_UWord16 stream_index; /* Index to the current position in bytestream */ + WebRtc_Word16 full; /* 0 - first byte in memory filled, second empty*/ + /* 1 - both bytes are empty (we just filled the previous memory */ + +} Bitstr_dec; + +/* Bitstream struct for encoder */ +typedef struct Bitstreamstruct_enc { + + WebRtc_UWord16 stream[STREAM_MAXW16_60MS]; /* Vector for adding encoded bytestream */ + WebRtc_UWord32 W_upper; /* Upper boundary of interval W */ + WebRtc_UWord32 streamval; + WebRtc_UWord16 stream_index; /* Index to the current position in bytestream */ + WebRtc_Word16 full; /* 0 - first byte in memory filled, second empty*/ + /* 1 - both bytes are empty (we just filled the previous memory */ + +} Bitstr_enc; + + +typedef struct { + + WebRtc_Word16 DataBufferLoQ0[WINLEN]; + WebRtc_Word16 DataBufferHiQ0[WINLEN]; + + WebRtc_Word32 CorrBufLoQQ[ORDERLO+1]; + WebRtc_Word32 CorrBufHiQQ[ORDERHI+1]; + + WebRtc_Word16 CorrBufLoQdom[ORDERLO+1]; + WebRtc_Word16 CorrBufHiQdom[ORDERHI+1]; + + WebRtc_Word32 PreStateLoGQ15[ORDERLO+1]; + WebRtc_Word32 PreStateHiGQ15[ORDERHI+1]; + + WebRtc_UWord32 OldEnergy; + +} MaskFiltstr_enc; + + + +typedef struct { + + WebRtc_Word16 PostStateLoGQ0[ORDERLO+1]; + WebRtc_Word16 PostStateHiGQ0[ORDERHI+1]; + + WebRtc_UWord32 OldEnergy; + +} MaskFiltstr_dec; + + + + + + + + +typedef struct { + + //state vectors for each of the two analysis filters + + WebRtc_Word32 INSTAT1_fix[2*(QORDER-1)]; + WebRtc_Word32 INSTAT2_fix[2*(QORDER-1)]; + WebRtc_Word16 INLABUF1_fix[QLOOKAHEAD]; + WebRtc_Word16 INLABUF2_fix[QLOOKAHEAD]; + + /* High pass filter */ + WebRtc_Word32 HPstates_fix[HPORDER]; + +} PreFiltBankstr; + + +typedef struct { + + //state vectors for each of the two analysis filters + WebRtc_Word32 STATE_0_LOWER_fix[2*POSTQORDER]; + WebRtc_Word32 STATE_0_UPPER_fix[2*POSTQORDER]; + + /* High pass filter */ + + WebRtc_Word32 HPstates1_fix[HPORDER]; + WebRtc_Word32 HPstates2_fix[HPORDER]; + +} PostFiltBankstr; + +typedef struct { + + + /* data buffer for pitch filter */ + WebRtc_Word16 ubufQQ[PITCH_BUFFSIZE]; + + /* low pass state vector */ + WebRtc_Word16 ystateQQ[PITCH_DAMPORDER]; + + /* old lag and gain */ + WebRtc_Word16 oldlagQ7; + WebRtc_Word16 oldgainQ12; + +} PitchFiltstr; + + + +typedef struct { + + //for inital estimator + WebRtc_Word16 dec_buffer16[PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2]; + WebRtc_Word32 decimator_state32[2*ALLPASSSECTIONS+1]; + WebRtc_Word16 inbuf[QLOOKAHEAD]; + + PitchFiltstr PFstr_wght; + PitchFiltstr PFstr; + + +} PitchAnalysisStruct; + + +typedef struct { + /* Parameters used in PLC to avoid re-computation */ + + /* --- residual signals --- */ + WebRtc_Word16 prevPitchInvIn[FRAMESAMPLES/2]; + WebRtc_Word16 prevPitchInvOut[PITCH_MAX_LAG + 10]; // [FRAMESAMPLES/2]; save 90 + WebRtc_Word32 prevHP[PITCH_MAX_LAG + 10]; // [FRAMESAMPLES/2]; save 90 + + + WebRtc_Word16 decayCoeffPriodic; /* how much to supress a sample */ + WebRtc_Word16 decayCoeffNoise; + WebRtc_Word16 used; /* if PLC is used */ + + + WebRtc_Word16 *lastPitchLP; // [FRAMESAMPLES/2]; saved 240; + + + /* --- LPC side info --- */ + WebRtc_Word16 lofilt_coefQ15[ ORDERLO ]; + WebRtc_Word16 hifilt_coefQ15[ ORDERHI ]; + WebRtc_Word32 gain_lo_hiQ17[2]; + + /* --- LTP side info --- */ + WebRtc_Word16 AvgPitchGain_Q12; + WebRtc_Word16 lastPitchGain_Q12; + WebRtc_Word16 lastPitchLag_Q7; + + /* --- Add-overlap in recovery packet --- */ + WebRtc_Word16 overlapLP[ RECOVERY_OVERLAP ]; // [FRAMESAMPLES/2]; saved 160 + + WebRtc_Word16 pitchCycles; + WebRtc_Word16 A; + WebRtc_Word16 B; + WebRtc_Word16 pitchIndex; + WebRtc_Word16 stretchLag; + WebRtc_Word16 *prevPitchLP; // [ FRAMESAMPLES/2 ]; saved 240 + WebRtc_Word16 seed; + + WebRtc_Word16 std; +} PLCstr; + + + +/* Have instance of struct together with other iSAC structs */ +typedef struct { + + WebRtc_Word16 prevFrameSizeMs; /* Previous frame size (in ms) */ + WebRtc_UWord16 prevRtpNumber; /* Previous RTP timestamp from received packet */ + /* (in samples relative beginning) */ + WebRtc_UWord32 prevSendTime; /* Send time for previous packet, from RTP header */ + WebRtc_UWord32 prevArrivalTime; /* Arrival time for previous packet (in ms using timeGetTime()) */ + WebRtc_UWord16 prevRtpRate; /* rate of previous packet, derived from RTP timestamps (in bits/s) */ + WebRtc_UWord32 lastUpdate; /* Time since the last update of the Bottle Neck estimate (in samples) */ + WebRtc_UWord32 lastReduction; /* Time sinse the last reduction (in samples) */ + WebRtc_Word32 countUpdates; /* How many times the estimate was update in the beginning */ + + /* The estimated bottle neck rate from there to here (in bits/s) */ + WebRtc_UWord32 recBw; + WebRtc_UWord32 recBwInv; + WebRtc_UWord32 recBwAvg; + WebRtc_UWord32 recBwAvgQ; + + WebRtc_UWord32 minBwInv; + WebRtc_UWord32 maxBwInv; + + /* The estimated mean absolute jitter value, as seen on this side (in ms) */ + WebRtc_Word32 recJitter; + WebRtc_Word32 recJitterShortTerm; + WebRtc_Word32 recJitterShortTermAbs; + WebRtc_Word32 recMaxDelay; + WebRtc_Word32 recMaxDelayAvgQ; + + + WebRtc_Word16 recHeaderRate; /* (assumed) bitrate for headers (bps) */ + + WebRtc_UWord32 sendBwAvg; /* The estimated bottle neck rate from here to there (in bits/s) */ + WebRtc_Word32 sendMaxDelayAvg; /* The estimated mean absolute jitter value, as seen on the other siee (in ms) */ + + + WebRtc_Word16 countRecPkts; /* number of packets received since last update */ + WebRtc_Word16 highSpeedRec; /* flag for marking that a high speed network has been detected downstream */ + + /* number of consecutive pkts sent during which the bwe estimate has + remained at a value greater than the downstream threshold for determining highspeed network */ + WebRtc_Word16 countHighSpeedRec; + + /* flag indicating bwe should not adjust down immediately for very late pckts */ + WebRtc_Word16 inWaitPeriod; + + /* variable holding the time of the start of a window of time when + bwe should not adjust down immediately for very late pckts */ + WebRtc_UWord32 startWaitPeriod; + + /* number of consecutive pkts sent during which the bwe estimate has + remained at a value greater than the upstream threshold for determining highspeed network */ + WebRtc_Word16 countHighSpeedSent; + + /* flag indicated the desired number of packets over threshold rate have been sent and + bwe will assume the connection is over broadband network */ + WebRtc_Word16 highSpeedSend; + + + + +} BwEstimatorstr; + + +typedef struct { + + /* boolean, flags if previous packet exceeded B.N. */ + WebRtc_Word16 PrevExceed; + /* ms */ + WebRtc_Word16 ExceedAgo; + /* packets left to send in current burst */ + WebRtc_Word16 BurstCounter; + /* packets */ + WebRtc_Word16 InitCounter; + /* ms remaining in buffer when next packet will be sent */ + WebRtc_Word16 StillBuffered; + +} RateModel; + +/* 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 */ + WebRtc_Word16 pitchGain_index[2]; + + /* Pitch Lag */ + WebRtc_Word32 meanGain[2]; + WebRtc_Word16 pitchIndex[PITCH_SUBFRAMES*2]; + + /* LPC */ + WebRtc_Word32 LPCcoeffs_g[12*2]; /* KLT_ORDER_GAIN = 12 */ + WebRtc_Word16 LPCindex_s[108*2]; /* KLT_ORDER_SHAPE = 108 */ + WebRtc_Word16 LPCindex_g[12*2]; /* KLT_ORDER_GAIN = 12 */ + + /* 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 { + + Bitstr_enc bitstr_obj; + MaskFiltstr_enc maskfiltstr_obj; + PreFiltBankstr prefiltbankstr_obj; + PitchFiltstr pitchfiltstr_obj; + PitchAnalysisStruct pitchanalysisstr_obj; + RateModel rate_data_obj; + + WebRtc_Word16 buffer_index; + WebRtc_Word16 current_framesamples; + + WebRtc_Word16 data_buffer_fix[FRAMESAMPLES]; // the size was MAX_FRAMESAMPLES + + WebRtc_Word16 frame_nb; + WebRtc_Word16 BottleNeck; + WebRtc_Word16 MaxDelay; + WebRtc_Word16 new_framelength; + WebRtc_Word16 s2nr; + WebRtc_UWord16 MaxBits; + + WebRtc_Word16 bitstr_seed; +#ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED + PostFiltBankstr interpolatorstr_obj; +#endif + + ISAC_SaveEncData_t *SaveEnc_ptr; + WebRtc_Word16 payloadLimitBytes30; /* Maximum allowed number of bits for a 30 msec packet */ + WebRtc_Word16 payloadLimitBytes60; /* Maximum allowed number of bits for a 30 msec packet */ + WebRtc_Word16 maxPayloadBytes; /* Maximum allowed number of bits for both 30 and 60 msec packet */ + WebRtc_Word16 maxRateInBytes; /* Maximum allowed rate in bytes per 30 msec packet */ + WebRtc_Word16 enforceFrameSize; /* If set iSAC will never change packet size */ + +} ISACFIX_EncInst_t; + + +typedef struct { + + Bitstr_dec bitstr_obj; + MaskFiltstr_dec maskfiltstr_obj; + PostFiltBankstr postfiltbankstr_obj; + PitchFiltstr pitchfiltstr_obj; + PLCstr plcstr_obj; /* TS; for packet loss concealment */ + +#ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED + PreFiltBankstr decimatorstr_obj; +#endif + +} ISACFIX_DecInst_t; + + + +typedef struct { + + ISACFIX_EncInst_t ISACenc_obj; + ISACFIX_DecInst_t ISACdec_obj; + BwEstimatorstr bwestimator_obj; + WebRtc_Word16 CodingMode; /* 0 = adaptive; 1 = instantaneous */ + WebRtc_Word16 errorcode; + WebRtc_Word16 initflag; /* 0 = nothing initiated; 1 = encoder or decoder */ + /* not initiated; 2 = all initiated */ +} ISACFIX_SubStruct; + + +typedef struct { + WebRtc_Word32 lpcGains[12]; /* 6 lower-band & 6 upper-band we may need to double it for 60*/ + /* */ + WebRtc_UWord32 W_upper; /* Upper boundary of interval W */ + WebRtc_UWord32 streamval; + WebRtc_UWord16 stream_index; /* Index to the current position in bytestream */ + WebRtc_Word16 full; /* 0 - first byte in memory filled, second empty*/ + /* 1 - both bytes are empty (we just filled the previous memory */ + WebRtc_UWord16 beforeLastWord; + WebRtc_UWord16 lastWord; +} transcode_obj; + + +//Bitstr_enc myBitStr; + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_STRUCTS_H_ */ diff --git a/src/modules/audio_coding/codecs/isac/fix/source/transform.c b/src/modules/audio_coding/codecs/isac/fix/source/transform.c new file mode 100644 index 0000000000..56ef9f2feb --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/source/transform.c @@ -0,0 +1,296 @@ +/* + * 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. + */ + +/* + * WebRtcIsacfix_kTransform.c + * + * Transform functions + * + */ + +#include "fft.h" +#include "codec.h" +#include "settings.h" + + +/* Cosine table 1 in Q14 */ +static const WebRtc_Word16 kCosTab1[FRAMESAMPLES/2] = { + 16384, 16383, 16378, 16371, 16362, 16349, 16333, 16315, 16294, 16270, + 16244, 16214, 16182, 16147, 16110, 16069, 16026, 15980, 15931, 15880, + 15826, 15769, 15709, 15647, 15582, 15515, 15444, 15371, 15296, 15218, + 15137, 15053, 14968, 14879, 14788, 14694, 14598, 14500, 14399, 14295, + 14189, 14081, 13970, 13856, 13741, 13623, 13502, 13380, 13255, 13128, + 12998, 12867, 12733, 12597, 12458, 12318, 12176, 12031, 11885, 11736, + 11585, 11433, 11278, 11121, 10963, 10803, 10641, 10477, 10311, 10143, + 9974, 9803, 9630, 9456, 9280, 9102, 8923, 8743, 8561, 8377, + 8192, 8006, 7818, 7629, 7438, 7246, 7053, 6859, 6664, 6467, + 6270, 6071, 5872, 5671, 5469, 5266, 5063, 4859, 4653, 4447, + 4240, 4033, 3825, 3616, 3406, 3196, 2986, 2775, 2563, 2351, + 2139, 1926, 1713, 1499, 1285, 1072, 857, 643, 429, 214, + 0, -214, -429, -643, -857, -1072, -1285, -1499, -1713, -1926, + -2139, -2351, -2563, -2775, -2986, -3196, -3406, -3616, -3825, -4033, + -4240, -4447, -4653, -4859, -5063, -5266, -5469, -5671, -5872, -6071, + -6270, -6467, -6664, -6859, -7053, -7246, -7438, -7629, -7818, -8006, + -8192, -8377, -8561, -8743, -8923, -9102, -9280, -9456, -9630, -9803, + -9974, -10143, -10311, -10477, -10641, -10803, -10963, -11121, -11278, -11433, + -11585, -11736, -11885, -12031, -12176, -12318, -12458, -12597, -12733, -12867, + -12998, -13128, -13255, -13380, -13502, -13623, -13741, -13856, -13970, -14081, + -14189, -14295, -14399, -14500, -14598, -14694, -14788, -14879, -14968, -15053, + -15137, -15218, -15296, -15371, -15444, -15515, -15582, -15647, -15709, -15769, + -15826, -15880, -15931, -15980, -16026, -16069, -16110, -16147, -16182, -16214, + -16244, -16270, -16294, -16315, -16333, -16349, -16362, -16371, -16378, -16383 +}; + + +/* Sine table 1 in Q14 */ +static const WebRtc_Word16 kSinTab1[FRAMESAMPLES/2] = { + 0, 214, 429, 643, 857, 1072, 1285, 1499, 1713, 1926, + 2139, 2351, 2563, 2775, 2986, 3196, 3406, 3616, 3825, 4033, + 4240, 4447, 4653, 4859, 5063, 5266, 5469, 5671, 5872, 6071, + 6270, 6467, 6664, 6859, 7053, 7246, 7438, 7629, 7818, 8006, + 8192, 8377, 8561, 8743, 8923, 9102, 9280, 9456, 9630, 9803, + 9974, 10143, 10311, 10477, 10641, 10803, 10963, 11121, 11278, 11433, + 11585, 11736, 11885, 12031, 12176, 12318, 12458, 12597, 12733, 12867, + 12998, 13128, 13255, 13380, 13502, 13623, 13741, 13856, 13970, 14081, + 14189, 14295, 14399, 14500, 14598, 14694, 14788, 14879, 14968, 15053, + 15137, 15218, 15296, 15371, 15444, 15515, 15582, 15647, 15709, 15769, + 15826, 15880, 15931, 15980, 16026, 16069, 16110, 16147, 16182, 16214, + 16244, 16270, 16294, 16315, 16333, 16349, 16362, 16371, 16378, 16383, + 16384, 16383, 16378, 16371, 16362, 16349, 16333, 16315, 16294, 16270, + 16244, 16214, 16182, 16147, 16110, 16069, 16026, 15980, 15931, 15880, + 15826, 15769, 15709, 15647, 15582, 15515, 15444, 15371, 15296, 15218, + 15137, 15053, 14968, 14879, 14788, 14694, 14598, 14500, 14399, 14295, + 14189, 14081, 13970, 13856, 13741, 13623, 13502, 13380, 13255, 13128, + 12998, 12867, 12733, 12597, 12458, 12318, 12176, 12031, 11885, 11736, + 11585, 11433, 11278, 11121, 10963, 10803, 10641, 10477, 10311, 10143, + 9974, 9803, 9630, 9456, 9280, 9102, 8923, 8743, 8561, 8377, + 8192, 8006, 7818, 7629, 7438, 7246, 7053, 6859, 6664, 6467, + 6270, 6071, 5872, 5671, 5469, 5266, 5063, 4859, 4653, 4447, + 4240, 4033, 3825, 3616, 3406, 3196, 2986, 2775, 2563, 2351, + 2139, 1926, 1713, 1499, 1285, 1072, 857, 643, 429, 214 +}; + + +/* Cosine table 2 in Q14 */ +static const WebRtc_Word16 kCosTab2[FRAMESAMPLES/4] = { + 107, -322, 536, -750, 965, -1179, 1392, -1606, 1819, -2032, + 2245, -2457, 2669, -2880, 3091, -3301, 3511, -3720, 3929, -4137, + 4344, -4550, 4756, -4961, 5165, -5368, 5570, -5771, 5971, -6171, + 6369, -6566, 6762, -6957, 7150, -7342, 7534, -7723, 7912, -8099, + 8285, -8469, 8652, -8833, 9013, -9191, 9368, -9543, 9717, -9889, + 10059, -10227, 10394, -10559, 10722, -10883, 11042, -11200, 11356, -11509, + 11661, -11810, 11958, -12104, 12247, -12389, 12528, -12665, 12800, -12933, + 13063, -13192, 13318, -13441, 13563, -13682, 13799, -13913, 14025, -14135, + 14242, -14347, 14449, -14549, 14647, -14741, 14834, -14924, 15011, -15095, + 15178, -15257, 15334, -15408, 15480, -15549, 15615, -15679, 15739, -15798, + 15853, -15906, 15956, -16003, 16048, -16090, 16129, -16165, 16199, -16229, + 16257, -16283, 16305, -16325, 16342, -16356, 16367, -16375, 16381, -16384 +}; + + +/* Sine table 2 in Q14 */ +static const WebRtc_Word16 kSinTab2[FRAMESAMPLES/4] = { + 16384, -16381, 16375, -16367, 16356, -16342, 16325, -16305, 16283, -16257, + 16229, -16199, 16165, -16129, 16090, -16048, 16003, -15956, 15906, -15853, + 15798, -15739, 15679, -15615, 15549, -15480, 15408, -15334, 15257, -15178, + 15095, -15011, 14924, -14834, 14741, -14647, 14549, -14449, 14347, -14242, + 14135, -14025, 13913, -13799, 13682, -13563, 13441, -13318, 13192, -13063, + 12933, -12800, 12665, -12528, 12389, -12247, 12104, -11958, 11810, -11661, + 11509, -11356, 11200, -11042, 10883, -10722, 10559, -10394, 10227, -10059, + 9889, -9717, 9543, -9368, 9191, -9013, 8833, -8652, 8469, -8285, + 8099, -7912, 7723, -7534, 7342, -7150, 6957, -6762, 6566, -6369, + 6171, -5971, 5771, -5570, 5368, -5165, 4961, -4756, 4550, -4344, + 4137, -3929, 3720, -3511, 3301, -3091, 2880, -2669, 2457, -2245, + 2032, -1819, 1606, -1392, 1179, -965, 750, -536, 322, -107 +}; + + + +void WebRtcIsacfix_Time2Spec(WebRtc_Word16 *inre1Q9, + WebRtc_Word16 *inre2Q9, + WebRtc_Word16 *outreQ7, + WebRtc_Word16 *outimQ7) +{ + + int k; + WebRtc_Word32 tmpreQ16[FRAMESAMPLES/2], tmpimQ16[FRAMESAMPLES/2]; + WebRtc_Word16 tmp1rQ14, tmp1iQ14; + WebRtc_Word32 xrQ16, xiQ16, yrQ16, yiQ16; + WebRtc_Word32 v1Q16, v2Q16; + WebRtc_Word16 factQ19, sh; + + /* Multiply with complex exponentials and combine into one complex vector */ + factQ19 = 16921; // 0.5/sqrt(240) in Q19 is round(.5/sqrt(240)*(2^19)) = 16921 + for (k = 0; k < FRAMESAMPLES/2; k++) { + tmp1rQ14 = kCosTab1[k]; + tmp1iQ14 = kSinTab1[k]; + xrQ16 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(tmp1rQ14, inre1Q9[k]) + WEBRTC_SPL_MUL_16_16(tmp1iQ14, inre2Q9[k]), 7); + xiQ16 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(tmp1rQ14, inre2Q9[k]) - WEBRTC_SPL_MUL_16_16(tmp1iQ14, inre1Q9[k]), 7); + tmpreQ16[k] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(factQ19, xrQ16)+4, 3); // (Q16*Q19>>16)>>3 = Q16 + tmpimQ16[k] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_32_RSFT16(factQ19, xiQ16)+4, 3); // (Q16*Q19>>16)>>3 = Q16 + } + + + xrQ16 = WebRtcSpl_MaxAbsValueW32(tmpreQ16, FRAMESAMPLES/2); + yrQ16 = WebRtcSpl_MaxAbsValueW32(tmpimQ16, FRAMESAMPLES/2); + if (yrQ16>xrQ16) { + xrQ16 = yrQ16; + } + + sh = WebRtcSpl_NormW32(xrQ16); + sh = sh-24; //if sh becomes >=0, then we should shift sh steps to the left, and the domain will become Q(16+sh) + //if sh becomes <0, then we should shift -sh steps to the right, and the domain will become Q(16+sh) + + //"Fastest" vectors + if (sh>=0) { + for (k=0; k<FRAMESAMPLES/2; k++) { + inre1Q9[k] = (WebRtc_Word16) WEBRTC_SPL_LSHIFT_W32(tmpreQ16[k], sh); //Q(16+sh) + inre2Q9[k] = (WebRtc_Word16) WEBRTC_SPL_LSHIFT_W32(tmpimQ16[k], sh); //Q(16+sh) + } + } else { + WebRtc_Word32 round = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)1, -sh-1); + for (k=0; k<FRAMESAMPLES/2; k++) { + inre1Q9[k] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmpreQ16[k]+round, -sh); //Q(16+sh) + inre2Q9[k] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmpimQ16[k]+round, -sh); //Q(16+sh) + } + } + + /* Get DFT */ + WebRtcIsacfix_FftRadix16Fastest(inre1Q9, inre2Q9, -1); // real call + + //"Fastest" vectors + if (sh>=0) { + for (k=0; k<FRAMESAMPLES/2; k++) { + tmpreQ16[k] = WEBRTC_SPL_RSHIFT_W32((WebRtc_Word32)inre1Q9[k], sh); //Q(16+sh) -> Q16 + tmpimQ16[k] = WEBRTC_SPL_RSHIFT_W32((WebRtc_Word32)inre2Q9[k], sh); //Q(16+sh) -> Q16 + } + } else { + for (k=0; k<FRAMESAMPLES/2; k++) { + tmpreQ16[k] = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)inre1Q9[k], -sh); //Q(16+sh) -> Q16 + tmpimQ16[k] = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)inre2Q9[k], -sh); //Q(16+sh) -> Q16 + } + } + + + /* Use symmetry to separate into two complex vectors and center frames in time around zero */ + for (k = 0; k < FRAMESAMPLES/4; k++) { + xrQ16 = tmpreQ16[k] + tmpreQ16[FRAMESAMPLES/2 - 1 - k]; + yiQ16 = -tmpreQ16[k] + tmpreQ16[FRAMESAMPLES/2 - 1 - k]; + xiQ16 = tmpimQ16[k] - tmpimQ16[FRAMESAMPLES/2 - 1 - k]; + yrQ16 = tmpimQ16[k] + tmpimQ16[FRAMESAMPLES/2 - 1 - k]; + tmp1rQ14 = kCosTab2[k]; + tmp1iQ14 = kSinTab2[k]; + v1Q16 = WEBRTC_SPL_MUL_16_32_RSFT14(tmp1rQ14, xrQ16) - WEBRTC_SPL_MUL_16_32_RSFT14(tmp1iQ14, xiQ16); + v2Q16 = WEBRTC_SPL_MUL_16_32_RSFT14(tmp1iQ14, xrQ16) + WEBRTC_SPL_MUL_16_32_RSFT14(tmp1rQ14, xiQ16); + outreQ7[k] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(v1Q16, 9); + outimQ7[k] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(v2Q16, 9); + v1Q16 = -WEBRTC_SPL_MUL_16_32_RSFT14(tmp1iQ14, yrQ16) - WEBRTC_SPL_MUL_16_32_RSFT14(tmp1rQ14, yiQ16); + v2Q16 = -WEBRTC_SPL_MUL_16_32_RSFT14(tmp1rQ14, yrQ16) + WEBRTC_SPL_MUL_16_32_RSFT14(tmp1iQ14, yiQ16); + outreQ7[FRAMESAMPLES/2 - 1 - k] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(v1Q16, 9); //CalcLrIntQ(v1Q16, 9); + outimQ7[FRAMESAMPLES/2 - 1 - k] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(v2Q16, 9); //CalcLrIntQ(v2Q16, 9); + + } +} + + +void WebRtcIsacfix_Spec2Time(WebRtc_Word16 *inreQ7, WebRtc_Word16 *inimQ7, WebRtc_Word32 *outre1Q16, WebRtc_Word32 *outre2Q16) +{ + + int k; + WebRtc_Word16 tmp1rQ14, tmp1iQ14; + WebRtc_Word32 xrQ16, xiQ16, yrQ16, yiQ16; + WebRtc_Word32 tmpInRe, tmpInIm, tmpInRe2, tmpInIm2; + WebRtc_Word16 factQ11; + WebRtc_Word16 sh; + + for (k = 0; k < FRAMESAMPLES/4; k++) { + /* Move zero in time to beginning of frames */ + tmp1rQ14 = kCosTab2[k]; + tmp1iQ14 = kSinTab2[k]; + + tmpInRe = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32) inreQ7[k], 9); // Q7 -> Q16 + tmpInIm = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32) inimQ7[k], 9); // Q7 -> Q16 + tmpInRe2 = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32) inreQ7[FRAMESAMPLES/2 - 1 - k], 9); // Q7 -> Q16 + tmpInIm2 = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32) inimQ7[FRAMESAMPLES/2 - 1 - k], 9); // Q7 -> Q16 + + xrQ16 = WEBRTC_SPL_MUL_16_32_RSFT14(tmp1rQ14, tmpInRe) + WEBRTC_SPL_MUL_16_32_RSFT14(tmp1iQ14, tmpInIm); + xiQ16 = WEBRTC_SPL_MUL_16_32_RSFT14(tmp1rQ14, tmpInIm) - WEBRTC_SPL_MUL_16_32_RSFT14(tmp1iQ14, tmpInRe); + yrQ16 = -WEBRTC_SPL_MUL_16_32_RSFT14(tmp1rQ14, tmpInIm2) - WEBRTC_SPL_MUL_16_32_RSFT14(tmp1iQ14, tmpInRe2); + yiQ16 = -WEBRTC_SPL_MUL_16_32_RSFT14(tmp1rQ14, tmpInRe2) + WEBRTC_SPL_MUL_16_32_RSFT14(tmp1iQ14, tmpInIm2); + + /* Combine into one vector, z = x + j * y */ + outre1Q16[k] = xrQ16 - yiQ16; + outre1Q16[FRAMESAMPLES/2 - 1 - k] = xrQ16 + yiQ16; + outre2Q16[k] = xiQ16 + yrQ16; + outre2Q16[FRAMESAMPLES/2 - 1 - k] = -xiQ16 + yrQ16; + } + + /* Get IDFT */ + tmpInRe = WebRtcSpl_MaxAbsValueW32(outre1Q16, 240); + tmpInIm = WebRtcSpl_MaxAbsValueW32(outre2Q16, 240); + if (tmpInIm>tmpInRe) { + tmpInRe = tmpInIm; + } + + sh = WebRtcSpl_NormW32(tmpInRe); + sh = sh-24; //if sh becomes >=0, then we should shift sh steps to the left, and the domain will become Q(16+sh) + //if sh becomes <0, then we should shift -sh steps to the right, and the domain will become Q(16+sh) + + //"Fastest" vectors + if (sh>=0) { + for (k=0; k<240; k++) { + inreQ7[k] = (WebRtc_Word16) WEBRTC_SPL_LSHIFT_W32(outre1Q16[k], sh); //Q(16+sh) + inimQ7[k] = (WebRtc_Word16) WEBRTC_SPL_LSHIFT_W32(outre2Q16[k], sh); //Q(16+sh) + } + } else { + WebRtc_Word32 round = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)1, -sh-1); + for (k=0; k<240; k++) { + inreQ7[k] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(outre1Q16[k]+round, -sh); //Q(16+sh) + inimQ7[k] = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(outre2Q16[k]+round, -sh); //Q(16+sh) + } + } + + WebRtcIsacfix_FftRadix16Fastest(inreQ7, inimQ7, 1); // real call + + //"Fastest" vectors + if (sh>=0) { + for (k=0; k<240; k++) { + outre1Q16[k] = WEBRTC_SPL_RSHIFT_W32((WebRtc_Word32)inreQ7[k], sh); //Q(16+sh) -> Q16 + outre2Q16[k] = WEBRTC_SPL_RSHIFT_W32((WebRtc_Word32)inimQ7[k], sh); //Q(16+sh) -> Q16 + } + } else { + for (k=0; k<240; k++) { + outre1Q16[k] = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)inreQ7[k], -sh); //Q(16+sh) -> Q16 + outre2Q16[k] = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)inimQ7[k], -sh); //Q(16+sh) -> Q16 + } + } + + /* Divide through by the normalizing constant: */ + /* scale all values with 1/240, i.e. with 273 in Q16 */ + /* 273/65536 ~= 0.0041656 */ + /* 1/240 ~= 0.0041666 */ + for (k=0; k<240; k++) { + outre1Q16[k] = WEBRTC_SPL_MUL_16_32_RSFT16(273, outre1Q16[k]); + outre2Q16[k] = WEBRTC_SPL_MUL_16_32_RSFT16(273, outre2Q16[k]); + } + + /* Demodulate and separate */ + factQ11 = 31727; // sqrt(240) in Q11 is round(15.49193338482967*2048) = 31727 + for (k = 0; k < FRAMESAMPLES/2; k++) { + tmp1rQ14 = kCosTab1[k]; + tmp1iQ14 = kSinTab1[k]; + xrQ16 = WEBRTC_SPL_MUL_16_32_RSFT14(tmp1rQ14, outre1Q16[k]) - WEBRTC_SPL_MUL_16_32_RSFT14(tmp1iQ14, outre2Q16[k]); + xiQ16 = WEBRTC_SPL_MUL_16_32_RSFT14(tmp1rQ14, outre2Q16[k]) + WEBRTC_SPL_MUL_16_32_RSFT14(tmp1iQ14, outre1Q16[k]); + xrQ16 = WEBRTC_SPL_MUL_16_32_RSFT11(factQ11, xrQ16); + xiQ16 = WEBRTC_SPL_MUL_16_32_RSFT11(factQ11, xiQ16); + outre2Q16[k] = xiQ16; + outre1Q16[k] = xrQ16; + } +} diff --git a/src/modules/audio_coding/codecs/isac/fix/test/ISACHist.cc b/src/modules/audio_coding/codecs/isac/fix/test/ISACHist.cc new file mode 100644 index 0000000000..753acd7e65 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/test/ISACHist.cc @@ -0,0 +1,173 @@ +/* + * 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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +//#include "isac_codec.h" +//#include "isac_structs.h" +#include "isacfix.h" + + +#define NUM_CODECS 1 + +int main(int argc, char* argv[]) +{ + FILE *inFileList; + FILE *audioFile; + FILE *outFile; + char audioFileName[501]; + short audioBuff[960]; + short encoded[600]; + short startAudio; + short encodedLen; + ISACFIX_MainStruct *isac_struct; + unsigned long int hist[601]; + + // reset the histogram + for(short n=0; n < 601; n++) + { + hist[n] = 0; + } + + + inFileList = fopen(argv[1], "r"); + if(inFileList == NULL) + { + printf("Could not open the input file.\n"); + getchar(); + exit(-1); + } + outFile = fopen(argv[2], "w"); + if(outFile == NULL) + { + printf("Could not open the histogram file.\n"); + getchar(); + exit(-1); + } + + short frameSizeMsec = 30; + if(argc > 3) + { + frameSizeMsec = atoi(argv[3]); + } + + short audioOffset = 0; + if(argc > 4) + { + audioOffset = atoi(argv[4]); + } + int ok; + ok = WebRtcIsacfix_Create(&isac_struct); + // instantaneous mode + ok |= WebRtcIsacfix_EncoderInit(isac_struct, 1); + // is not used but initialize + ok |= WebRtcIsacfix_DecoderInit(isac_struct); + ok |= WebRtcIsacfix_Control(isac_struct, 32000, frameSizeMsec); + + if(ok != 0) + { + printf("\nProblem in seting up iSAC\n"); + exit(-1); + } + + while( fgets(audioFileName, 500, inFileList) != NULL ) + { + // remove trailing white-spaces and any Cntrl character + if(strlen(audioFileName) == 0) + { + continue; + } + short n = strlen(audioFileName) - 1; + while(isspace(audioFileName[n]) || iscntrl(audioFileName[n])) + { + audioFileName[n] = '\0'; + n--; + if(n < 0) + { + break; + } + } + + // remove leading spaces + if(strlen(audioFileName) == 0) + { + continue; + } + n = 0; + while((isspace(audioFileName[n]) || iscntrl(audioFileName[n])) && + (audioFileName[n] != '\0')) + { + n++; + } + memmove(audioFileName, &audioFileName[n], 500 - n); + if(strlen(audioFileName) == 0) + { + continue; + } + audioFile = fopen(audioFileName, "rb"); + if(audioFile == NULL) + { + printf("\nCannot open %s!!!!!\n", audioFileName); + exit(0); + } + + if(audioOffset > 0) + { + fseek(audioFile, (audioOffset<<1), SEEK_SET); + } + + while(fread(audioBuff, sizeof(short), (480*frameSizeMsec/30), audioFile) >= (480*frameSizeMsec/30)) + { + startAudio = 0; + do + { + encodedLen = WebRtcIsacfix_Encode(isac_struct, + &audioBuff[startAudio], encoded); + startAudio += 160; + } while(encodedLen == 0); + + if(encodedLen < 0) + { + printf("\nEncoding Error!!!\n"); + exit(0); + } + hist[encodedLen]++; + } + fclose(audioFile); + } + fclose(inFileList); + unsigned long totalFrames = 0; + for(short n=0; n < 601; n++) + { + totalFrames += hist[n]; + fprintf(outFile, "%10lu\n", hist[n]); + } + fclose(outFile); + + short topTenCntr = 0; + printf("\nTotal number of Frames %lu\n\n", totalFrames); + printf("Payload Len # occurences\n"); + printf("=========== ============\n"); + + for(short n = 600; (n >= 0) && (topTenCntr < 10); n--) + { + if(hist[n] > 0) + { + topTenCntr++; + printf(" %3d %3d\n", n, hist[n]); + } + } + WebRtcIsacfix_Free(isac_struct); + return 0; +} + diff --git a/src/modules/audio_coding/codecs/isac/fix/test/Isac_test.cc b/src/modules/audio_coding/codecs/isac/fix/test/Isac_test.cc new file mode 100644 index 0000000000..2791db4512 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/test/Isac_test.cc @@ -0,0 +1,260 @@ +/* + * 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. + */ + +/****************************************************************** + Stand Alone test application for ISACFIX and ISAC LC + +******************************************************************/ + +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include "typedefs.h" + +#include "isacfix.h" +ISACFIX_MainStruct *ISACfix_inst; + +#define FS 16000 + + +typedef struct { + WebRtc_UWord32 arrival_time; /* samples */ + WebRtc_UWord32 sample_count; /* samples */ + WebRtc_UWord16 rtp_number; +} BottleNeckModel; + +void get_arrival_time(int current_framesamples, /* samples */ + int packet_size, /* bytes */ + int bottleneck, /* excluding headers; bits/s */ + BottleNeckModel *BN_data) +{ + const int HeaderSize = 35; + int HeaderRate; + + HeaderRate = HeaderSize * 8 * FS / current_framesamples; /* bits/s */ + + /* everything in samples */ + BN_data->sample_count = BN_data->sample_count + current_framesamples; + + BN_data->arrival_time += ((packet_size + HeaderSize) * 8 * FS) / (bottleneck + HeaderRate); + + if (BN_data->arrival_time < BN_data->sample_count) + BN_data->arrival_time = BN_data->sample_count; + + BN_data->rtp_number++; +} + +/* +#ifdef __cplusplus +extern "C" { +#endif +*/ +int main(int argc, char* argv[]){ + + /* Parameters */ + FILE *pInFile, *pOutFile, *pChcFile; + WebRtc_Word8 inFile[40]; + WebRtc_Word8 outFile[40]; + WebRtc_Word8 chcFile[40]; + WebRtc_Word8 codec[10]; + WebRtc_Word16 bitrt, spType, size; + WebRtc_UWord16 frameLen; + WebRtc_Word16 sigOut[1000], sigIn[1000]; + WebRtc_UWord16 bitStream[500]; /* double to 32 kbps for 60 ms */ + + WebRtc_Word16 chc, ok; + int noOfCalls, cdlen; + WebRtc_Word16 noOfLostFrames; + int err, errtype; + + BottleNeckModel BN_data; + + int totalbits =0; + int totalsmpls =0; + + /*End Parameters*/ + + + if ((argc==6)||(argc==7) ){ + + strcpy(codec,argv[5]); + + if(argc==7){ + if (!_stricmp("isac",codec)){ + bitrt = atoi(argv[6]); + if ( (bitrt<10000)&&(bitrt>32000)){ + printf("Error: Supported bit rate in the range 10000-32000 bps!\n"); + exit(-1); + } + + }else{ + printf("Error: Codec not recognized. Check spelling!\n"); + exit(-1); + } + + } else { + printf("Error: Codec not recognized. Check spelling!\n"); + exit(-1); + } + } else { + printf("Error: Wrong number of input parameter!\n\n"); + exit(-1); + } + + frameLen = atoi(argv[4]); + strcpy(chcFile,argv[3]); + strcpy(outFile,argv[2]); + strcpy(inFile,argv[1]); + + /* Open file streams */ + if( (pInFile = fopen(inFile,"rb")) == NULL ) { + printf( "Error: Did not find input file!\n" ); + exit(-1); + } + strcat(outFile,"_"); + strcat(outFile, argv[4]); + strcat(outFile,"_"); + strcat(outFile, codec); + + if (argc==7){ + strcat(outFile,"_"); + strcat(outFile, argv[6]); + } + if (_stricmp("none", chcFile)){ + strcat(outFile,"_"); + strcat(outFile, "plc"); + } + + strcat(outFile, ".otp"); + + if (_stricmp("none", chcFile)){ + if( (pChcFile = fopen(chcFile,"rb")) == NULL ) { + printf( "Error: Did not find channel file!\n" ); + exit(-1); + } + } + /******************************************************************/ + if (!_stricmp("isac", codec)){ /* ISAC */ + if ((frameLen!=480)&&(frameLen!=960)) { + printf("Error: ISAC only supports 480 and 960 samples per frame (not %d)\n", frameLen); + exit(-1); + } + if( (pOutFile = fopen(outFile,"wb")) == NULL ) { + printf( "Could not open output file!\n" ); + exit(-1); + } + ok=WebRtcIsacfix_Create(&ISACfix_inst); + if (ok!=0) { + printf("Couldn't allocate memory for iSAC fix instance\n"); + exit(-1); + } + + BN_data.arrival_time = 0; + BN_data.sample_count = 0; + BN_data.rtp_number = 0; + + WebRtcIsacfix_EncoderInit(ISACfix_inst,1); + WebRtcIsacfix_DecoderInit(ISACfix_inst); + err = WebRtcIsacfix_Control(ISACfix_inst, bitrt, (frameLen>>4)); + if (err < 0) { + /* exit if returned with error */ + errtype=WebRtcIsacfix_GetErrorCode(ISACfix_inst); + printf("\n\n Error in initialization: %d.\n\n", errtype); + exit(EXIT_FAILURE); + } + /* loop over frame */ + while (fread(sigIn,sizeof(WebRtc_Word16),frameLen,pInFile) == frameLen) { + + noOfCalls=0; + cdlen=0; + while (cdlen<=0) { + cdlen=WebRtcIsacfix_Encode(ISACfix_inst,&sigIn[noOfCalls*160],(WebRtc_Word16*)bitStream); + if(cdlen==-1){ + errtype=WebRtcIsacfix_GetErrorCode(ISACfix_inst); + printf("\n\nError in encoder: %d.\n\n", errtype); + exit(-1); + } + noOfCalls++; + } + + + if(_stricmp("none", chcFile)){ + if (fread(&chc,sizeof(WebRtc_Word16),1,pChcFile)!=1) /* packet may be lost */ + break; + } else { + chc = 1; /* packets never lost */ + } + + /* simulate packet handling through NetEq and the modem */ + get_arrival_time(frameLen, cdlen, bitrt, &BN_data); + + if (chc){ /* decode */ + + err = WebRtcIsacfix_UpdateBwEstimate1(ISACfix_inst, + bitStream, + cdlen, + BN_data.rtp_number, + BN_data.arrival_time); + + if (err < 0) { + /* exit if returned with error */ + errtype=WebRtcIsacfix_GetErrorCode(ISACfix_inst); + printf("\n\nError in decoder: %d.\n\n", errtype); + exit(EXIT_FAILURE); + } + size = WebRtcIsacfix_Decode(ISACfix_inst, bitStream, cdlen, sigOut, &spType); + if(size<=0){ + /* exit if returned with error */ + errtype=WebRtcIsacfix_GetErrorCode(ISACfix_inst); + printf("\n\nError in decoder: %d.\n\n", errtype); + exit(-1); + } + } else { /* PLC */ + if (frameLen == 480){ + noOfLostFrames = 1; + } else{ + noOfLostFrames = 2; + } + size = WebRtcIsacfix_DecodePlc(ISACfix_inst, sigOut, noOfLostFrames ); + if(size<=0){ + errtype=WebRtcIsacfix_GetErrorCode(ISACfix_inst); + printf("\n\nError in decoder: %d.\n\n", errtype); + exit(-1); + } + } + + /* Write decoded speech to file */ + fwrite(sigOut,sizeof(short),size,pOutFile); + + totalbits += 8 * cdlen; + totalsmpls += size; + + } + /******************************************************************/ + } + +// printf("\n\ntotal bits = %d bits", totalbits); + printf("\nmeasured average bitrate = %0.3f kbits/s", (double)totalbits * 16 / totalsmpls); + printf("\n"); + + + fclose(pInFile); + fclose(pOutFile); + if (_stricmp("none", chcFile)){ + fclose(pChcFile); + } + + if (!_stricmp("isac", codec)){ + WebRtcIsacfix_Free(ISACfix_inst); + } + + return 0; + +} diff --git a/src/modules/audio_coding/codecs/isac/fix/test/QA/ChannelFiles.txt b/src/modules/audio_coding/codecs/isac/fix/test/QA/ChannelFiles.txt new file mode 100644 index 0000000000..05f7410141 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/test/QA/ChannelFiles.txt @@ -0,0 +1,3 @@ +bottlenecks.txt +lowrates.txt +tworates.txt diff --git a/src/modules/audio_coding/codecs/isac/fix/test/QA/InputFiles.txt b/src/modules/audio_coding/codecs/isac/fix/test/QA/InputFiles.txt new file mode 100644 index 0000000000..f26b7afb6c --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/test/QA/InputFiles.txt @@ -0,0 +1,31 @@ +DTMF_16kHz_long.pcm +DTMF_16kHz_short.pcm +F00.INP +F01.INP +F02.INP +F03.INP +F04.INP +F05.INP +F06.INP +longtest.pcm +ltest_speech_clean.pcm +ltest_music.pcm +ltest_speech_noisy.pcm +misc2.pcm +purenb.pcm +sawsweep_380_60.pcm +sinesweep.pcm +sinesweep_half.pcm +speechmusic.pcm +speechmusic_nb.pcm +speechoffice0dB.pcm +speech_and_misc_NB.pcm +speech_and_misc_WB.pcm +testM4.pcm +testM4D_rev.pcm +testM4D.pcm +testfile.pcm +tone_cisco.pcm +tone_cisco_long.pcm +wb_contspeech.pcm +wb_speech_office25db.pcm
\ No newline at end of file diff --git a/src/modules/audio_coding/codecs/isac/fix/test/QA/InputFilesFew.txt b/src/modules/audio_coding/codecs/isac/fix/test/QA/InputFilesFew.txt new file mode 100644 index 0000000000..08bbde30d7 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/test/QA/InputFilesFew.txt @@ -0,0 +1,6 @@ +DTMF_16kHz_short.pcm +ltest_speech_noisy.pcm +misc2.pcm +sinesweep.pcm +speechmusic.pcm +tone_cisco.pcm diff --git a/src/modules/audio_coding/codecs/isac/fix/test/QA/ListOfTestCases.xls b/src/modules/audio_coding/codecs/isac/fix/test/QA/ListOfTestCases.xls Binary files differnew file mode 100644 index 0000000000..f0889ef4ed --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/test/QA/ListOfTestCases.xls diff --git a/src/modules/audio_coding/codecs/isac/fix/test/QA/diffiSAC.txt b/src/modules/audio_coding/codecs/isac/fix/test/QA/diffiSAC.txt new file mode 100644 index 0000000000..96b87c066b --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/test/QA/diffiSAC.txt @@ -0,0 +1,481 @@ +#!/bin/bash +(set -o igncr) 2>/dev/null && set -o igncr; # force bash to ignore \r character + +diff ../dataqa350/i30_1DTMF_16kHz_long.pcm ../dataqa351/i30_1DTMF_16kHz_long.pcm +diff ../dataqa350/i60_1DTMF_16kHz_long.pcm ../dataqa351/i60_1DTMF_16kHz_long.pcm +diff ../dataqa350/i30_2DTMF_16kHz_long.pcm ../dataqa351/i30_2DTMF_16kHz_long.pcm +diff ../dataqa350/i60_2DTMF_16kHz_long.pcm ../dataqa351/i60_2DTMF_16kHz_long.pcm +diff ../dataqa350/i30_3DTMF_16kHz_long.pcm ../dataqa351/i30_3DTMF_16kHz_long.pcm +diff ../dataqa350/i60_3DTMF_16kHz_long.pcm ../dataqa351/i60_3DTMF_16kHz_long.pcm +diff ../dataqa350/i30_4DTMF_16kHz_long.pcm ../dataqa351/i30_4DTMF_16kHz_long.pcm +diff ../dataqa350/i60_4DTMF_16kHz_long.pcm ../dataqa351/i60_4DTMF_16kHz_long.pcm +diff ../dataqa350/i30_5DTMF_16kHz_long.pcm ../dataqa351/i30_5DTMF_16kHz_long.pcm +diff ../dataqa350/i60_5DTMF_16kHz_long.pcm ../dataqa351/i60_5DTMF_16kHz_long.pcm +diff ../dataqa350/i30_6DTMF_16kHz_long.pcm ../dataqa351/i30_6DTMF_16kHz_long.pcm +diff ../dataqa350/i60_6DTMF_16kHz_long.pcm ../dataqa351/i60_6DTMF_16kHz_long.pcm +diff ../dataqa350/a1DTMF_16kHz_long.pcm ../dataqa351/a1DTMF_16kHz_long.pcm +diff ../dataqa350/a2DTMF_16kHz_long.pcm ../dataqa351/a2DTMF_16kHz_long.pcm +diff ../dataqa350/a3DTMF_16kHz_long.pcm ../dataqa351/a3DTMF_16kHz_long.pcm +diff ../dataqa350/i30_7DTMF_16kHz_short.pcm ../dataqa351/i30_7DTMF_16kHz_short.pcm +diff ../dataqa350/i60_7DTMF_16kHz_short.pcm ../dataqa351/i60_7DTMF_16kHz_short.pcm +diff ../dataqa350/i30_8DTMF_16kHz_short.pcm ../dataqa351/i30_8DTMF_16kHz_short.pcm +diff ../dataqa350/i60_8DTMF_16kHz_short.pcm ../dataqa351/i60_8DTMF_16kHz_short.pcm +diff ../dataqa350/i30_9DTMF_16kHz_short.pcm ../dataqa351/i30_9DTMF_16kHz_short.pcm +diff ../dataqa350/i60_9DTMF_16kHz_short.pcm ../dataqa351/i60_9DTMF_16kHz_short.pcm +diff ../dataqa350/i30_10DTMF_16kHz_short.pcm ../dataqa351/i30_10DTMF_16kHz_short.pcm +diff ../dataqa350/i60_10DTMF_16kHz_short.pcm ../dataqa351/i60_10DTMF_16kHz_short.pcm +diff ../dataqa350/i30_11DTMF_16kHz_short.pcm ../dataqa351/i30_11DTMF_16kHz_short.pcm +diff ../dataqa350/i60_11DTMF_16kHz_short.pcm ../dataqa351/i60_11DTMF_16kHz_short.pcm +diff ../dataqa350/i30_12DTMF_16kHz_short.pcm ../dataqa351/i30_12DTMF_16kHz_short.pcm +diff ../dataqa350/i60_12DTMF_16kHz_short.pcm ../dataqa351/i60_12DTMF_16kHz_short.pcm +diff ../dataqa350/a4DTMF_16kHz_short.pcm ../dataqa351/a4DTMF_16kHz_short.pcm +diff ../dataqa350/a5DTMF_16kHz_short.pcm ../dataqa351/a5DTMF_16kHz_short.pcm +diff ../dataqa350/a6DTMF_16kHz_short.pcm ../dataqa351/a6DTMF_16kHz_short.pcm +diff ../dataqa350/i30_13F00.INP ../dataqa350/i30_13F00.INP +diff ../dataqa350/i60_13F00.INP ../dataqa350/i60_13F00.INP +diff ../dataqa350/i30_14F00.INP ../dataqa350/i30_14F00.INP +diff ../dataqa350/i60_14F00.INP ../dataqa350/i60_14F00.INP +diff ../dataqa350/i30_15F00.INP ../dataqa350/i30_15F00.INP +diff ../dataqa350/i60_15F00.INP ../dataqa350/i60_15F00.INP +diff ../dataqa350/i30_16F00.INP ../dataqa350/i30_16F00.INP +diff ../dataqa350/i60_16F00.INP ../dataqa350/i60_16F00.INP +diff ../dataqa350/i30_17F00.INP ../dataqa350/i30_17F00.INP +diff ../dataqa350/i60_17F00.INP ../dataqa350/i60_17F00.INP +diff ../dataqa350/i30_18F00.INP ../dataqa350/i30_18F00.INP +diff ../dataqa350/i60_18F00.INP ../dataqa350/i60_18F00.INP +diff ../dataqa350/a7F00.INP ../dataqa350/a7F00.INP +diff ../dataqa350/a8F00.INP ../dataqa350/a8F00.INP +diff ../dataqa350/a9F00.INP ../dataqa350/a9F00.INP +diff ../dataqa350/i30_19F01.INP ../dataqa350/i30_19F01.INP +diff ../dataqa350/i60_19F01.INP ../dataqa350/i60_19F01.INP +diff ../dataqa350/i30_20F01.INP ../dataqa350/i30_20F01.INP +diff ../dataqa350/i60_20F01.INP ../dataqa350/i60_20F01.INP +diff ../dataqa350/i30_21F01.INP ../dataqa350/i30_21F01.INP +diff ../dataqa350/i60_21F01.INP ../dataqa350/i60_21F01.INP +diff ../dataqa350/i30_22F01.INP ../dataqa350/i30_22F01.INP +diff ../dataqa350/i60_22F01.INP ../dataqa350/i60_22F01.INP +diff ../dataqa350/i30_23F01.INP ../dataqa350/i30_23F01.INP +diff ../dataqa350/i60_23F01.INP ../dataqa350/i60_23F01.INP +diff ../dataqa350/i30_24F01.INP ../dataqa350/i30_24F01.INP +diff ../dataqa350/i60_24F01.INP ../dataqa350/i60_24F01.INP +diff ../dataqa350/a10F01.INP ../dataqa350/a10F01.INP +diff ../dataqa350/a11F01.INP ../dataqa350/a11F01.INP +diff ../dataqa350/a12F01.INP ../dataqa350/a12F01.INP +diff ../dataqa350/i30_25F02.INP ../dataqa350/i30_25F02.INP +diff ../dataqa350/i60_25F02.INP ../dataqa350/i60_25F02.INP +diff ../dataqa350/i30_26F02.INP ../dataqa350/i30_26F02.INP +diff ../dataqa350/i60_26F02.INP ../dataqa350/i60_26F02.INP +diff ../dataqa350/i30_27F02.INP ../dataqa350/i30_27F02.INP +diff ../dataqa350/i60_27F02.INP ../dataqa350/i60_27F02.INP +diff ../dataqa350/i30_28F02.INP ../dataqa350/i30_28F02.INP +diff ../dataqa350/i60_28F02.INP ../dataqa350/i60_28F02.INP +diff ../dataqa350/i30_29F02.INP ../dataqa350/i30_29F02.INP +diff ../dataqa350/i60_29F02.INP ../dataqa350/i60_29F02.INP +diff ../dataqa350/i30_30F02.INP ../dataqa350/i30_30F02.INP +diff ../dataqa350/i60_30F02.INP ../dataqa350/i60_30F02.INP +diff ../dataqa350/a13F02.INP ../dataqa350/a13F02.INP +diff ../dataqa350/a14F02.INP ../dataqa350/a14F02.INP +diff ../dataqa350/a15F02.INP ../dataqa350/a15F02.INP +diff ../dataqa350/i30_31F03.INP ../dataqa350/i30_31F03.INP +diff ../dataqa350/i60_31F03.INP ../dataqa350/i60_31F03.INP +diff ../dataqa350/i30_32F03.INP ../dataqa350/i30_32F03.INP +diff ../dataqa350/i60_32F03.INP ../dataqa350/i60_32F03.INP +diff ../dataqa350/i30_33F03.INP ../dataqa350/i30_33F03.INP +diff ../dataqa350/i60_33F03.INP ../dataqa350/i60_33F03.INP +diff ../dataqa350/i30_34F03.INP ../dataqa350/i30_34F03.INP +diff ../dataqa350/i60_34F03.INP ../dataqa350/i60_34F03.INP +diff ../dataqa350/i30_35F03.INP ../dataqa350/i30_35F03.INP +diff ../dataqa350/i60_35F03.INP ../dataqa350/i60_35F03.INP +diff ../dataqa350/i30_36F03.INP ../dataqa350/i30_36F03.INP +diff ../dataqa350/i60_36F03.INP ../dataqa350/i60_36F03.INP +diff ../dataqa350/a16F03.INP ../dataqa350/a16F03.INP +diff ../dataqa350/a17F03.INP ../dataqa350/a17F03.INP +diff ../dataqa350/a18F03.INP ../dataqa350/a18F03.INP +diff ../dataqa350/i30_37F04.INP ../dataqa350/i30_37F04.INP +diff ../dataqa350/i60_37F04.INP ../dataqa350/i60_37F04.INP +diff ../dataqa350/i30_38F04.INP ../dataqa350/i30_38F04.INP +diff ../dataqa350/i60_38F04.INP ../dataqa350/i60_38F04.INP +diff ../dataqa350/i30_39F04.INP ../dataqa350/i30_39F04.INP +diff ../dataqa350/i60_39F04.INP ../dataqa350/i60_39F04.INP +diff ../dataqa350/i30_40F04.INP ../dataqa350/i30_40F04.INP +diff ../dataqa350/i60_40F04.INP ../dataqa350/i60_40F04.INP +diff ../dataqa350/i30_41F04.INP ../dataqa350/i30_41F04.INP +diff ../dataqa350/i60_41F04.INP ../dataqa350/i60_41F04.INP +diff ../dataqa350/i30_42F04.INP ../dataqa350/i30_42F04.INP +diff ../dataqa350/i60_42F04.INP ../dataqa350/i60_42F04.INP +diff ../dataqa350/a19F04.INP ../dataqa350/a19F04.INP +diff ../dataqa350/a20F04.INP ../dataqa350/a20F04.INP +diff ../dataqa350/a21F04.INP ../dataqa350/a21F04.INP +diff ../dataqa350/i30_43F05.INP ../dataqa350/i30_43F05.INP +diff ../dataqa350/i60_43F05.INP ../dataqa350/i60_43F05.INP +diff ../dataqa350/i30_44F05.INP ../dataqa350/i30_44F05.INP +diff ../dataqa350/i60_44F05.INP ../dataqa350/i60_44F05.INP +diff ../dataqa350/i30_45F05.INP ../dataqa350/i30_45F05.INP +diff ../dataqa350/i60_45F05.INP ../dataqa350/i60_45F05.INP +diff ../dataqa350/i30_46F05.INP ../dataqa350/i30_46F05.INP +diff ../dataqa350/i60_46F05.INP ../dataqa350/i60_46F05.INP +diff ../dataqa350/i30_47F05.INP ../dataqa350/i30_47F05.INP +diff ../dataqa350/i60_47F05.INP ../dataqa350/i60_47F05.INP +diff ../dataqa350/i30_48F05.INP ../dataqa350/i30_48F05.INP +diff ../dataqa350/i60_48F05.INP ../dataqa350/i60_48F05.INP +diff ../dataqa350/a22F05.INP ../dataqa350/a22F05.INP +diff ../dataqa350/a23F05.INP ../dataqa350/a23F05.INP +diff ../dataqa350/a24F05.INP ../dataqa350/a24F05.INP +diff ../dataqa350/i30_49F06.INP ../dataqa350/i30_49F06.INP +diff ../dataqa350/i60_49F06.INP ../dataqa350/i60_49F06.INP +diff ../dataqa350/i30_50F06.INP ../dataqa350/i30_50F06.INP +diff ../dataqa350/i60_50F06.INP ../dataqa350/i60_50F06.INP +diff ../dataqa350/i30_51F06.INP ../dataqa350/i30_51F06.INP +diff ../dataqa350/i60_51F06.INP ../dataqa350/i60_51F06.INP +diff ../dataqa350/i30_52F06.INP ../dataqa350/i30_52F06.INP +diff ../dataqa350/i60_52F06.INP ../dataqa350/i60_52F06.INP +diff ../dataqa350/i30_53F06.INP ../dataqa350/i30_53F06.INP +diff ../dataqa350/i60_53F06.INP ../dataqa350/i60_53F06.INP +diff ../dataqa350/i30_54F06.INP ../dataqa350/i30_54F06.INP +diff ../dataqa350/i60_54F06.INP ../dataqa350/i60_54F06.INP +diff ../dataqa350/a25F06.INP ../dataqa350/a25F06.INP +diff ../dataqa350/a26F06.INP ../dataqa350/a26F06.INP +diff ../dataqa350/a27F06.INP ../dataqa350/a27F06.INP +diff ../dataqa350/i30_55longtest.pcm ../dataqa351/i30_55longtest.pcm +diff ../dataqa350/i60_55longtest.pcm ../dataqa351/i60_55longtest.pcm +diff ../dataqa350/i30_56longtest.pcm ../dataqa351/i30_56longtest.pcm +diff ../dataqa350/i60_56longtest.pcm ../dataqa351/i60_56longtest.pcm +diff ../dataqa350/i30_57longtest.pcm ../dataqa351/i30_57longtest.pcm +diff ../dataqa350/i60_57longtest.pcm ../dataqa351/i60_57longtest.pcm +diff ../dataqa350/i30_58longtest.pcm ../dataqa351/i30_58longtest.pcm +diff ../dataqa350/i60_58longtest.pcm ../dataqa351/i60_58longtest.pcm +diff ../dataqa350/i30_59longtest.pcm ../dataqa351/i30_59longtest.pcm +diff ../dataqa350/i60_59longtest.pcm ../dataqa351/i60_59longtest.pcm +diff ../dataqa350/i30_60longtest.pcm ../dataqa351/i30_60longtest.pcm +diff ../dataqa350/i60_60longtest.pcm ../dataqa351/i60_60longtest.pcm +diff ../dataqa350/a28longtest.pcm ../dataqa351/a28longtest.pcm +diff ../dataqa350/a29longtest.pcm ../dataqa351/a29longtest.pcm +diff ../dataqa350/a30longtest.pcm ../dataqa351/a30longtest.pcm +diff ../dataqa350/i30_61ltest_speech_clean.pcm ../dataqa351/i30_61ltest_speech_clean.pcm +diff ../dataqa350/i60_61ltest_speech_clean.pcm ../dataqa351/i60_61ltest_speech_clean.pcm +diff ../dataqa350/i30_62ltest_speech_clean.pcm ../dataqa351/i30_62ltest_speech_clean.pcm +diff ../dataqa350/i60_62ltest_speech_clean.pcm ../dataqa351/i60_62ltest_speech_clean.pcm +diff ../dataqa350/i30_63ltest_speech_clean.pcm ../dataqa351/i30_63ltest_speech_clean.pcm +diff ../dataqa350/i60_63ltest_speech_clean.pcm ../dataqa351/i60_63ltest_speech_clean.pcm +diff ../dataqa350/i30_64ltest_speech_clean.pcm ../dataqa351/i30_64ltest_speech_clean.pcm +diff ../dataqa350/i60_64ltest_speech_clean.pcm ../dataqa351/i60_64ltest_speech_clean.pcm +diff ../dataqa350/i30_65ltest_speech_clean.pcm ../dataqa351/i30_65ltest_speech_clean.pcm +diff ../dataqa350/i60_65ltest_speech_clean.pcm ../dataqa351/i60_65ltest_speech_clean.pcm +diff ../dataqa350/i30_66ltest_speech_clean.pcm ../dataqa351/i30_66ltest_speech_clean.pcm +diff ../dataqa350/i60_66ltest_speech_clean.pcm ../dataqa351/i60_66ltest_speech_clean.pcm +diff ../dataqa350/a31ltest_speech_clean.pcm ../dataqa351/a31ltest_speech_clean.pcm +diff ../dataqa350/a32ltest_speech_clean.pcm ../dataqa351/a32ltest_speech_clean.pcm +diff ../dataqa350/a33ltest_speech_clean.pcm ../dataqa351/a33ltest_speech_clean.pcm +diff ../dataqa350/i30_67ltest_music.pcm ../dataqa351/i30_67ltest_music.pcm +diff ../dataqa350/i60_67ltest_music.pcm ../dataqa351/i60_67ltest_music.pcm +diff ../dataqa350/i30_68ltest_music.pcm ../dataqa351/i30_68ltest_music.pcm +diff ../dataqa350/i60_68ltest_music.pcm ../dataqa351/i60_68ltest_music.pcm +diff ../dataqa350/i30_69ltest_music.pcm ../dataqa351/i30_69ltest_music.pcm +diff ../dataqa350/i60_69ltest_music.pcm ../dataqa351/i60_69ltest_music.pcm +diff ../dataqa350/i30_70ltest_music.pcm ../dataqa351/i30_70ltest_music.pcm +diff ../dataqa350/i60_70ltest_music.pcm ../dataqa351/i60_70ltest_music.pcm +diff ../dataqa350/i30_71ltest_music.pcm ../dataqa351/i30_71ltest_music.pcm +diff ../dataqa350/i60_71ltest_music.pcm ../dataqa351/i60_71ltest_music.pcm +diff ../dataqa350/i30_72ltest_music.pcm ../dataqa351/i30_72ltest_music.pcm +diff ../dataqa350/i60_72ltest_music.pcm ../dataqa351/i60_72ltest_music.pcm +diff ../dataqa350/a34ltest_music.pcm ../dataqa351/a34ltest_music.pcm +diff ../dataqa350/a35ltest_music.pcm ../dataqa351/a35ltest_music.pcm +diff ../dataqa350/a36ltest_music.pcm ../dataqa351/a36ltest_music.pcm +diff ../dataqa350/i30_73ltest_speech_noisy.pcm ../dataqa351/i30_73ltest_speech_noisy.pcm +diff ../dataqa350/i60_73ltest_speech_noisy.pcm ../dataqa351/i60_73ltest_speech_noisy.pcm +diff ../dataqa350/i30_74ltest_speech_noisy.pcm ../dataqa351/i30_74ltest_speech_noisy.pcm +diff ../dataqa350/i60_74ltest_speech_noisy.pcm ../dataqa351/i60_74ltest_speech_noisy.pcm +diff ../dataqa350/i30_75ltest_speech_noisy.pcm ../dataqa351/i30_75ltest_speech_noisy.pcm +diff ../dataqa350/i60_75ltest_speech_noisy.pcm ../dataqa351/i60_75ltest_speech_noisy.pcm +diff ../dataqa350/i30_76ltest_speech_noisy.pcm ../dataqa351/i30_76ltest_speech_noisy.pcm +diff ../dataqa350/i60_76ltest_speech_noisy.pcm ../dataqa351/i60_76ltest_speech_noisy.pcm +diff ../dataqa350/i30_77ltest_speech_noisy.pcm ../dataqa351/i30_77ltest_speech_noisy.pcm +diff ../dataqa350/i60_77ltest_speech_noisy.pcm ../dataqa351/i60_77ltest_speech_noisy.pcm +diff ../dataqa350/i30_78ltest_speech_noisy.pcm ../dataqa351/i30_78ltest_speech_noisy.pcm +diff ../dataqa350/i60_78ltest_speech_noisy.pcm ../dataqa351/i60_78ltest_speech_noisy.pcm +diff ../dataqa350/a37ltest_speech_noisy.pcm ../dataqa351/a37ltest_speech_noisy.pcm +diff ../dataqa350/a38ltest_speech_noisy.pcm ../dataqa351/a38ltest_speech_noisy.pcm +diff ../dataqa350/a39ltest_speech_noisy.pcm ../dataqa351/a39ltest_speech_noisy.pcm +diff ../dataqa350/i30_79misc2.pcm ../dataqa351/i30_79misc2.pcm +diff ../dataqa350/i60_79misc2.pcm ../dataqa351/i60_79misc2.pcm +diff ../dataqa350/i30_80misc2.pcm ../dataqa351/i30_80misc2.pcm +diff ../dataqa350/i60_80misc2.pcm ../dataqa351/i60_80misc2.pcm +diff ../dataqa350/i30_81misc2.pcm ../dataqa351/i30_81misc2.pcm +diff ../dataqa350/i60_81misc2.pcm ../dataqa351/i60_81misc2.pcm +diff ../dataqa350/i30_82misc2.pcm ../dataqa351/i30_82misc2.pcm +diff ../dataqa350/i60_82misc2.pcm ../dataqa351/i60_82misc2.pcm +diff ../dataqa350/i30_83misc2.pcm ../dataqa351/i30_83misc2.pcm +diff ../dataqa350/i60_83misc2.pcm ../dataqa351/i60_83misc2.pcm +diff ../dataqa350/i30_84misc2.pcm ../dataqa351/i30_84misc2.pcm +diff ../dataqa350/i60_84misc2.pcm ../dataqa351/i60_84misc2.pcm +diff ../dataqa350/a40misc2.pcm ../dataqa351/a40misc2.pcm +diff ../dataqa350/a41misc2.pcm ../dataqa351/a41misc2.pcm +diff ../dataqa350/a42misc2.pcm ../dataqa351/a42misc2.pcm +diff ../dataqa350/i30_85purenb.pcm ../dataqa351/i30_85purenb.pcm +diff ../dataqa350/i60_85purenb.pcm ../dataqa351/i60_85purenb.pcm +diff ../dataqa350/i30_86purenb.pcm ../dataqa351/i30_86purenb.pcm +diff ../dataqa350/i60_86purenb.pcm ../dataqa351/i60_86purenb.pcm +diff ../dataqa350/i30_87purenb.pcm ../dataqa351/i30_87purenb.pcm +diff ../dataqa350/i60_87purenb.pcm ../dataqa351/i60_87purenb.pcm +diff ../dataqa350/i30_88purenb.pcm ../dataqa351/i30_88purenb.pcm +diff ../dataqa350/i60_88purenb.pcm ../dataqa351/i60_88purenb.pcm +diff ../dataqa350/i30_89purenb.pcm ../dataqa351/i30_89purenb.pcm +diff ../dataqa350/i60_89purenb.pcm ../dataqa351/i60_89purenb.pcm +diff ../dataqa350/i30_90purenb.pcm ../dataqa351/i30_90purenb.pcm +diff ../dataqa350/i60_90purenb.pcm ../dataqa351/i60_90purenb.pcm +diff ../dataqa350/a43purenb.pcm ../dataqa351/a43purenb.pcm +diff ../dataqa350/a44purenb.pcm ../dataqa351/a44purenb.pcm +diff ../dataqa350/a45purenb.pcm ../dataqa351/a45purenb.pcm +diff ../dataqa350/i30_91sawsweep_380_60.pcm ../dataqa351/i30_91sawsweep_380_60.pcm +diff ../dataqa350/i60_91sawsweep_380_60.pcm ../dataqa351/i60_91sawsweep_380_60.pcm +diff ../dataqa350/i30_92sawsweep_380_60.pcm ../dataqa351/i30_92sawsweep_380_60.pcm +diff ../dataqa350/i60_92sawsweep_380_60.pcm ../dataqa351/i60_92sawsweep_380_60.pcm +diff ../dataqa350/i30_93sawsweep_380_60.pcm ../dataqa351/i30_93sawsweep_380_60.pcm +diff ../dataqa350/i60_93sawsweep_380_60.pcm ../dataqa351/i60_93sawsweep_380_60.pcm +diff ../dataqa350/i30_94sawsweep_380_60.pcm ../dataqa351/i30_94sawsweep_380_60.pcm +diff ../dataqa350/i60_94sawsweep_380_60.pcm ../dataqa351/i60_94sawsweep_380_60.pcm +diff ../dataqa350/i30_95sawsweep_380_60.pcm ../dataqa351/i30_95sawsweep_380_60.pcm +diff ../dataqa350/i60_95sawsweep_380_60.pcm ../dataqa351/i60_95sawsweep_380_60.pcm +diff ../dataqa350/i30_96sawsweep_380_60.pcm ../dataqa351/i30_96sawsweep_380_60.pcm +diff ../dataqa350/i60_96sawsweep_380_60.pcm ../dataqa351/i60_96sawsweep_380_60.pcm +diff ../dataqa350/a46sawsweep_380_60.pcm ../dataqa351/a46sawsweep_380_60.pcm +diff ../dataqa350/a47sawsweep_380_60.pcm ../dataqa351/a47sawsweep_380_60.pcm +diff ../dataqa350/a48sawsweep_380_60.pcm ../dataqa351/a48sawsweep_380_60.pcm +diff ../dataqa350/i30_97sinesweep.pcm ../dataqa351/i30_97sinesweep.pcm +diff ../dataqa350/i60_97sinesweep.pcm ../dataqa351/i60_97sinesweep.pcm +diff ../dataqa350/i30_98sinesweep.pcm ../dataqa351/i30_98sinesweep.pcm +diff ../dataqa350/i60_98sinesweep.pcm ../dataqa351/i60_98sinesweep.pcm +diff ../dataqa350/i30_99sinesweep.pcm ../dataqa351/i30_99sinesweep.pcm +diff ../dataqa350/i60_99sinesweep.pcm ../dataqa351/i60_99sinesweep.pcm +diff ../dataqa350/i30_100sinesweep.pcm ../dataqa351/i30_100sinesweep.pcm +diff ../dataqa350/i60_100sinesweep.pcm ../dataqa351/i60_100sinesweep.pcm +diff ../dataqa350/i30_101sinesweep.pcm ../dataqa351/i30_101sinesweep.pcm +diff ../dataqa350/i60_101sinesweep.pcm ../dataqa351/i60_101sinesweep.pcm +diff ../dataqa350/i30_102sinesweep.pcm ../dataqa351/i30_102sinesweep.pcm +diff ../dataqa350/i60_102sinesweep.pcm ../dataqa351/i60_102sinesweep.pcm +diff ../dataqa350/a49sinesweep.pcm ../dataqa351/a49sinesweep.pcm +diff ../dataqa350/a50sinesweep.pcm ../dataqa351/a50sinesweep.pcm +diff ../dataqa350/a51sinesweep.pcm ../dataqa351/a51sinesweep.pcm +diff ../dataqa350/i30_103sinesweep_half.pcm ../dataqa351/i30_103sinesweep_half.pcm +diff ../dataqa350/i60_103sinesweep_half.pcm ../dataqa351/i60_103sinesweep_half.pcm +diff ../dataqa350/i30_104sinesweep_half.pcm ../dataqa351/i30_104sinesweep_half.pcm +diff ../dataqa350/i60_104sinesweep_half.pcm ../dataqa351/i60_104sinesweep_half.pcm +diff ../dataqa350/i30_105sinesweep_half.pcm ../dataqa351/i30_105sinesweep_half.pcm +diff ../dataqa350/i60_105sinesweep_half.pcm ../dataqa351/i60_105sinesweep_half.pcm +diff ../dataqa350/i30_106sinesweep_half.pcm ../dataqa351/i30_106sinesweep_half.pcm +diff ../dataqa350/i60_106sinesweep_half.pcm ../dataqa351/i60_106sinesweep_half.pcm +diff ../dataqa350/i30_107sinesweep_half.pcm ../dataqa351/i30_107sinesweep_half.pcm +diff ../dataqa350/i60_107sinesweep_half.pcm ../dataqa351/i60_107sinesweep_half.pcm +diff ../dataqa350/i30_108sinesweep_half.pcm ../dataqa351/i30_108sinesweep_half.pcm +diff ../dataqa350/i60_108sinesweep_half.pcm ../dataqa351/i60_108sinesweep_half.pcm +diff ../dataqa350/a52sinesweep_half.pcm ../dataqa351/a52sinesweep_half.pcm +diff ../dataqa350/a53sinesweep_half.pcm ../dataqa351/a53sinesweep_half.pcm +diff ../dataqa350/a54sinesweep_half.pcm ../dataqa351/a54sinesweep_half.pcm +diff ../dataqa350/i30_109speechmusic.pcm ../dataqa351/i30_109speechmusic.pcm +diff ../dataqa350/i60_109speechmusic.pcm ../dataqa351/i60_109speechmusic.pcm +diff ../dataqa350/i30_110speechmusic.pcm ../dataqa351/i30_110speechmusic.pcm +diff ../dataqa350/i60_110speechmusic.pcm ../dataqa351/i60_110speechmusic.pcm +diff ../dataqa350/i30_111speechmusic.pcm ../dataqa351/i30_111speechmusic.pcm +diff ../dataqa350/i60_111speechmusic.pcm ../dataqa351/i60_111speechmusic.pcm +diff ../dataqa350/i30_112speechmusic.pcm ../dataqa351/i30_112speechmusic.pcm +diff ../dataqa350/i60_112speechmusic.pcm ../dataqa351/i60_112speechmusic.pcm +diff ../dataqa350/i30_113speechmusic.pcm ../dataqa351/i30_113speechmusic.pcm +diff ../dataqa350/i60_113speechmusic.pcm ../dataqa351/i60_113speechmusic.pcm +diff ../dataqa350/i30_114speechmusic.pcm ../dataqa351/i30_114speechmusic.pcm +diff ../dataqa350/i60_114speechmusic.pcm ../dataqa351/i60_114speechmusic.pcm +diff ../dataqa350/a55speechmusic.pcm ../dataqa351/a55speechmusic.pcm +diff ../dataqa350/a56speechmusic.pcm ../dataqa351/a56speechmusic.pcm +diff ../dataqa350/a57speechmusic.pcm ../dataqa351/a57speechmusic.pcm +diff ../dataqa350/i30_115speechmusic_nb.pcm ../dataqa351/i30_115speechmusic_nb.pcm +diff ../dataqa350/i60_115speechmusic_nb.pcm ../dataqa351/i60_115speechmusic_nb.pcm +diff ../dataqa350/i30_116speechmusic_nb.pcm ../dataqa351/i30_116speechmusic_nb.pcm +diff ../dataqa350/i60_116speechmusic_nb.pcm ../dataqa351/i60_116speechmusic_nb.pcm +diff ../dataqa350/i30_117speechmusic_nb.pcm ../dataqa351/i30_117speechmusic_nb.pcm +diff ../dataqa350/i60_117speechmusic_nb.pcm ../dataqa351/i60_117speechmusic_nb.pcm +diff ../dataqa350/i30_118speechmusic_nb.pcm ../dataqa351/i30_118speechmusic_nb.pcm +diff ../dataqa350/i60_118speechmusic_nb.pcm ../dataqa351/i60_118speechmusic_nb.pcm +diff ../dataqa350/i30_119speechmusic_nb.pcm ../dataqa351/i30_119speechmusic_nb.pcm +diff ../dataqa350/i60_119speechmusic_nb.pcm ../dataqa351/i60_119speechmusic_nb.pcm +diff ../dataqa350/i30_120speechmusic_nb.pcm ../dataqa351/i30_120speechmusic_nb.pcm +diff ../dataqa350/i60_120speechmusic_nb.pcm ../dataqa351/i60_120speechmusic_nb.pcm +diff ../dataqa350/a58speechmusic_nb.pcm ../dataqa351/a58speechmusic_nb.pcm +diff ../dataqa350/a59speechmusic_nb.pcm ../dataqa351/a59speechmusic_nb.pcm +diff ../dataqa350/a60speechmusic_nb.pcm ../dataqa351/a60speechmusic_nb.pcm +diff ../dataqa350/i30_121speechoffice0dB.pcm ../dataqa351/i30_121speechoffice0dB.pcm +diff ../dataqa350/i60_121speechoffice0dB.pcm ../dataqa351/i60_121speechoffice0dB.pcm +diff ../dataqa350/i30_122speechoffice0dB.pcm ../dataqa351/i30_122speechoffice0dB.pcm +diff ../dataqa350/i60_122speechoffice0dB.pcm ../dataqa351/i60_122speechoffice0dB.pcm +diff ../dataqa350/i30_123speechoffice0dB.pcm ../dataqa351/i30_123speechoffice0dB.pcm +diff ../dataqa350/i60_123speechoffice0dB.pcm ../dataqa351/i60_123speechoffice0dB.pcm +diff ../dataqa350/i30_124speechoffice0dB.pcm ../dataqa351/i30_124speechoffice0dB.pcm +diff ../dataqa350/i60_124speechoffice0dB.pcm ../dataqa351/i60_124speechoffice0dB.pcm +diff ../dataqa350/i30_125speechoffice0dB.pcm ../dataqa351/i30_125speechoffice0dB.pcm +diff ../dataqa350/i60_125speechoffice0dB.pcm ../dataqa351/i60_125speechoffice0dB.pcm +diff ../dataqa350/i30_126speechoffice0dB.pcm ../dataqa351/i30_126speechoffice0dB.pcm +diff ../dataqa350/i60_126speechoffice0dB.pcm ../dataqa351/i60_126speechoffice0dB.pcm +diff ../dataqa350/a61speechoffice0dB.pcm ../dataqa351/a61speechoffice0dB.pcm +diff ../dataqa350/a62speechoffice0dB.pcm ../dataqa351/a62speechoffice0dB.pcm +diff ../dataqa350/a63speechoffice0dB.pcm ../dataqa351/a63speechoffice0dB.pcm +diff ../dataqa350/i30_127speech_and_misc_NB.pcm ../dataqa351/i30_127speech_and_misc_NB.pcm +diff ../dataqa350/i60_127speech_and_misc_NB.pcm ../dataqa351/i60_127speech_and_misc_NB.pcm +diff ../dataqa350/i30_128speech_and_misc_NB.pcm ../dataqa351/i30_128speech_and_misc_NB.pcm +diff ../dataqa350/i60_128speech_and_misc_NB.pcm ../dataqa351/i60_128speech_and_misc_NB.pcm +diff ../dataqa350/i30_129speech_and_misc_NB.pcm ../dataqa351/i30_129speech_and_misc_NB.pcm +diff ../dataqa350/i60_129speech_and_misc_NB.pcm ../dataqa351/i60_129speech_and_misc_NB.pcm +diff ../dataqa350/i30_130speech_and_misc_NB.pcm ../dataqa351/i30_130speech_and_misc_NB.pcm +diff ../dataqa350/i60_130speech_and_misc_NB.pcm ../dataqa351/i60_130speech_and_misc_NB.pcm +diff ../dataqa350/i30_131speech_and_misc_NB.pcm ../dataqa351/i30_131speech_and_misc_NB.pcm +diff ../dataqa350/i60_131speech_and_misc_NB.pcm ../dataqa351/i60_131speech_and_misc_NB.pcm +diff ../dataqa350/i30_132speech_and_misc_NB.pcm ../dataqa351/i30_132speech_and_misc_NB.pcm +diff ../dataqa350/i60_132speech_and_misc_NB.pcm ../dataqa351/i60_132speech_and_misc_NB.pcm +diff ../dataqa350/a64speech_and_misc_NB.pcm ../dataqa351/a64speech_and_misc_NB.pcm +diff ../dataqa350/a65speech_and_misc_NB.pcm ../dataqa351/a65speech_and_misc_NB.pcm +diff ../dataqa350/a66speech_and_misc_NB.pcm ../dataqa351/a66speech_and_misc_NB.pcm +diff ../dataqa350/i30_133speech_and_misc_WB.pcm ../dataqa351/i30_133speech_and_misc_WB.pcm +diff ../dataqa350/i60_133speech_and_misc_WB.pcm ../dataqa351/i60_133speech_and_misc_WB.pcm +diff ../dataqa350/i30_134speech_and_misc_WB.pcm ../dataqa351/i30_134speech_and_misc_WB.pcm +diff ../dataqa350/i60_134speech_and_misc_WB.pcm ../dataqa351/i60_134speech_and_misc_WB.pcm +diff ../dataqa350/i30_135speech_and_misc_WB.pcm ../dataqa351/i30_135speech_and_misc_WB.pcm +diff ../dataqa350/i60_135speech_and_misc_WB.pcm ../dataqa351/i60_135speech_and_misc_WB.pcm +diff ../dataqa350/i30_136speech_and_misc_WB.pcm ../dataqa351/i30_136speech_and_misc_WB.pcm +diff ../dataqa350/i60_136speech_and_misc_WB.pcm ../dataqa351/i60_136speech_and_misc_WB.pcm +diff ../dataqa350/i30_137speech_and_misc_WB.pcm ../dataqa351/i30_137speech_and_misc_WB.pcm +diff ../dataqa350/i60_137speech_and_misc_WB.pcm ../dataqa351/i60_137speech_and_misc_WB.pcm +diff ../dataqa350/i30_138speech_and_misc_WB.pcm ../dataqa351/i30_138speech_and_misc_WB.pcm +diff ../dataqa350/i60_138speech_and_misc_WB.pcm ../dataqa351/i60_138speech_and_misc_WB.pcm +diff ../dataqa350/a67speech_and_misc_WB.pcm ../dataqa351/a67speech_and_misc_WB.pcm +diff ../dataqa350/a68speech_and_misc_WB.pcm ../dataqa351/a68speech_and_misc_WB.pcm +diff ../dataqa350/a69speech_and_misc_WB.pcm ../dataqa351/a69speech_and_misc_WB.pcm +diff ../dataqa350/i30_139testM4.pcm ../dataqa351/i30_139testM4.pcm +diff ../dataqa350/i60_139testM4.pcm ../dataqa351/i60_139testM4.pcm +diff ../dataqa350/i30_140testM4.pcm ../dataqa351/i30_140testM4.pcm +diff ../dataqa350/i60_140testM4.pcm ../dataqa351/i60_140testM4.pcm +diff ../dataqa350/i30_141testM4.pcm ../dataqa351/i30_141testM4.pcm +diff ../dataqa350/i60_141testM4.pcm ../dataqa351/i60_141testM4.pcm +diff ../dataqa350/i30_142testM4.pcm ../dataqa351/i30_142testM4.pcm +diff ../dataqa350/i60_142testM4.pcm ../dataqa351/i60_142testM4.pcm +diff ../dataqa350/i30_143testM4.pcm ../dataqa351/i30_143testM4.pcm +diff ../dataqa350/i60_143testM4.pcm ../dataqa351/i60_143testM4.pcm +diff ../dataqa350/i30_144testM4.pcm ../dataqa351/i30_144testM4.pcm +diff ../dataqa350/i60_144testM4.pcm ../dataqa351/i60_144testM4.pcm +diff ../dataqa350/a70testM4.pcm ../dataqa351/a70testM4.pcm +diff ../dataqa350/a71testM4.pcm ../dataqa351/a71testM4.pcm +diff ../dataqa350/a72testM4.pcm ../dataqa351/a72testM4.pcm +diff ../dataqa350/i30_145testM4D_rev.pcm ../dataqa351/i30_145testM4D_rev.pcm +diff ../dataqa350/i60_145testM4D_rev.pcm ../dataqa351/i60_145testM4D_rev.pcm +diff ../dataqa350/i30_146testM4D_rev.pcm ../dataqa351/i30_146testM4D_rev.pcm +diff ../dataqa350/i60_146testM4D_rev.pcm ../dataqa351/i60_146testM4D_rev.pcm +diff ../dataqa350/i30_147testM4D_rev.pcm ../dataqa351/i30_147testM4D_rev.pcm +diff ../dataqa350/i60_147testM4D_rev.pcm ../dataqa351/i60_147testM4D_rev.pcm +diff ../dataqa350/i30_148testM4D_rev.pcm ../dataqa351/i30_148testM4D_rev.pcm +diff ../dataqa350/i60_148testM4D_rev.pcm ../dataqa351/i60_148testM4D_rev.pcm +diff ../dataqa350/i30_149testM4D_rev.pcm ../dataqa351/i30_149testM4D_rev.pcm +diff ../dataqa350/i60_149testM4D_rev.pcm ../dataqa351/i60_149testM4D_rev.pcm +diff ../dataqa350/i30_150testM4D_rev.pcm ../dataqa351/i30_150testM4D_rev.pcm +diff ../dataqa350/i60_150testM4D_rev.pcm ../dataqa351/i60_150testM4D_rev.pcm +diff ../dataqa350/a73testM4D_rev.pcm ../dataqa351/a73testM4D_rev.pcm +diff ../dataqa350/a74testM4D_rev.pcm ../dataqa351/a74testM4D_rev.pcm +diff ../dataqa350/a75testM4D_rev.pcm ../dataqa351/a75testM4D_rev.pcm +diff ../dataqa350/i30_151testM4D.pcm ../dataqa351/i30_151testM4D.pcm +diff ../dataqa350/i60_151testM4D.pcm ../dataqa351/i60_151testM4D.pcm +diff ../dataqa350/i30_152testM4D.pcm ../dataqa351/i30_152testM4D.pcm +diff ../dataqa350/i60_152testM4D.pcm ../dataqa351/i60_152testM4D.pcm +diff ../dataqa350/i30_153testM4D.pcm ../dataqa351/i30_153testM4D.pcm +diff ../dataqa350/i60_153testM4D.pcm ../dataqa351/i60_153testM4D.pcm +diff ../dataqa350/i30_154testM4D.pcm ../dataqa351/i30_154testM4D.pcm +diff ../dataqa350/i60_154testM4D.pcm ../dataqa351/i60_154testM4D.pcm +diff ../dataqa350/i30_155testM4D.pcm ../dataqa351/i30_155testM4D.pcm +diff ../dataqa350/i60_155testM4D.pcm ../dataqa351/i60_155testM4D.pcm +diff ../dataqa350/i30_156testM4D.pcm ../dataqa351/i30_156testM4D.pcm +diff ../dataqa350/i60_156testM4D.pcm ../dataqa351/i60_156testM4D.pcm +diff ../dataqa350/a76testM4D.pcm ../dataqa351/a76testM4D.pcm +diff ../dataqa350/a77testM4D.pcm ../dataqa351/a77testM4D.pcm +diff ../dataqa350/a78testM4D.pcm ../dataqa351/a78testM4D.pcm +diff ../dataqa350/i30_157testfile.pcm ../dataqa351/i30_157testfile.pcm +diff ../dataqa350/i60_157testfile.pcm ../dataqa351/i60_157testfile.pcm +diff ../dataqa350/i30_158testfile.pcm ../dataqa351/i30_158testfile.pcm +diff ../dataqa350/i60_158testfile.pcm ../dataqa351/i60_158testfile.pcm +diff ../dataqa350/i30_159testfile.pcm ../dataqa351/i30_159testfile.pcm +diff ../dataqa350/i60_159testfile.pcm ../dataqa351/i60_159testfile.pcm +diff ../dataqa350/i30_160testfile.pcm ../dataqa351/i30_160testfile.pcm +diff ../dataqa350/i60_160testfile.pcm ../dataqa351/i60_160testfile.pcm +diff ../dataqa350/i30_161testfile.pcm ../dataqa351/i30_161testfile.pcm +diff ../dataqa350/i60_161testfile.pcm ../dataqa351/i60_161testfile.pcm +diff ../dataqa350/i30_162testfile.pcm ../dataqa351/i30_162testfile.pcm +diff ../dataqa350/i60_162testfile.pcm ../dataqa351/i60_162testfile.pcm +diff ../dataqa350/a79testfile.pcm ../dataqa351/a79testfile.pcm +diff ../dataqa350/a80testfile.pcm ../dataqa351/a80testfile.pcm +diff ../dataqa350/a81testfile.pcm ../dataqa351/a81testfile.pcm +diff ../dataqa350/i30_163tone_cisco.pcm ../dataqa351/i30_163tone_cisco.pcm +diff ../dataqa350/i60_163tone_cisco.pcm ../dataqa351/i60_163tone_cisco.pcm +diff ../dataqa350/i30_164tone_cisco.pcm ../dataqa351/i30_164tone_cisco.pcm +diff ../dataqa350/i60_164tone_cisco.pcm ../dataqa351/i60_164tone_cisco.pcm +diff ../dataqa350/i30_165tone_cisco.pcm ../dataqa351/i30_165tone_cisco.pcm +diff ../dataqa350/i60_165tone_cisco.pcm ../dataqa351/i60_165tone_cisco.pcm +diff ../dataqa350/i30_166tone_cisco.pcm ../dataqa351/i30_166tone_cisco.pcm +diff ../dataqa350/i60_166tone_cisco.pcm ../dataqa351/i60_166tone_cisco.pcm +diff ../dataqa350/i30_167tone_cisco.pcm ../dataqa351/i30_167tone_cisco.pcm +diff ../dataqa350/i60_167tone_cisco.pcm ../dataqa351/i60_167tone_cisco.pcm +diff ../dataqa350/i30_168tone_cisco.pcm ../dataqa351/i30_168tone_cisco.pcm +diff ../dataqa350/i60_168tone_cisco.pcm ../dataqa351/i60_168tone_cisco.pcm +diff ../dataqa350/a82tone_cisco.pcm ../dataqa351/a82tone_cisco.pcm +diff ../dataqa350/a83tone_cisco.pcm ../dataqa351/a83tone_cisco.pcm +diff ../dataqa350/a84tone_cisco.pcm ../dataqa351/a84tone_cisco.pcm +diff ../dataqa350/i30_169tone_cisco_long.pcm ../dataqa351/i30_169tone_cisco_long.pcm +diff ../dataqa350/i60_169tone_cisco_long.pcm ../dataqa351/i60_169tone_cisco_long.pcm +diff ../dataqa350/i30_170tone_cisco_long.pcm ../dataqa351/i30_170tone_cisco_long.pcm +diff ../dataqa350/i60_170tone_cisco_long.pcm ../dataqa351/i60_170tone_cisco_long.pcm +diff ../dataqa350/i30_171tone_cisco_long.pcm ../dataqa351/i30_171tone_cisco_long.pcm +diff ../dataqa350/i60_171tone_cisco_long.pcm ../dataqa351/i60_171tone_cisco_long.pcm +diff ../dataqa350/i30_172tone_cisco_long.pcm ../dataqa351/i30_172tone_cisco_long.pcm +diff ../dataqa350/i60_172tone_cisco_long.pcm ../dataqa351/i60_172tone_cisco_long.pcm +diff ../dataqa350/i30_173tone_cisco_long.pcm ../dataqa351/i30_173tone_cisco_long.pcm +diff ../dataqa350/i60_173tone_cisco_long.pcm ../dataqa351/i60_173tone_cisco_long.pcm +diff ../dataqa350/i30_174tone_cisco_long.pcm ../dataqa351/i30_174tone_cisco_long.pcm +diff ../dataqa350/i60_174tone_cisco_long.pcm ../dataqa351/i60_174tone_cisco_long.pcm +diff ../dataqa350/a85tone_cisco_long.pcm ../dataqa351/a85tone_cisco_long.pcm +diff ../dataqa350/a86tone_cisco_long.pcm ../dataqa351/a86tone_cisco_long.pcm +diff ../dataqa350/a87tone_cisco_long.pcm ../dataqa351/a87tone_cisco_long.pcm +diff ../dataqa350/i30_175wb_contspeech.pcm ../dataqa351/i30_175wb_contspeech.pcm +diff ../dataqa350/i60_175wb_contspeech.pcm ../dataqa351/i60_175wb_contspeech.pcm +diff ../dataqa350/i30_176wb_contspeech.pcm ../dataqa351/i30_176wb_contspeech.pcm +diff ../dataqa350/i60_176wb_contspeech.pcm ../dataqa351/i60_176wb_contspeech.pcm +diff ../dataqa350/i30_177wb_contspeech.pcm ../dataqa351/i30_177wb_contspeech.pcm +diff ../dataqa350/i60_177wb_contspeech.pcm ../dataqa351/i60_177wb_contspeech.pcm +diff ../dataqa350/i30_178wb_contspeech.pcm ../dataqa351/i30_178wb_contspeech.pcm +diff ../dataqa350/i60_178wb_contspeech.pcm ../dataqa351/i60_178wb_contspeech.pcm +diff ../dataqa350/i30_179wb_contspeech.pcm ../dataqa351/i30_179wb_contspeech.pcm +diff ../dataqa350/i60_179wb_contspeech.pcm ../dataqa351/i60_179wb_contspeech.pcm +diff ../dataqa350/i30_180wb_contspeech.pcm ../dataqa351/i30_180wb_contspeech.pcm +diff ../dataqa350/i60_180wb_contspeech.pcm ../dataqa351/i60_180wb_contspeech.pcm +diff ../dataqa350/a88wb_contspeech.pcm ../dataqa351/a88wb_contspeech.pcm +diff ../dataqa350/a89wb_contspeech.pcm ../dataqa351/a89wb_contspeech.pcm +diff ../dataqa350/a90wb_contspeech.pcm ../dataqa351/a90wb_contspeech.pcm +diff ../dataqa350/i30_181wb_speech_office25db.pcm ../dataqa351/i30_181wb_speech_office25db.pcm +diff ../dataqa350/i60_181wb_speech_office25db.pcm ../dataqa351/i60_181wb_speech_office25db.pcm +diff ../dataqa350/i30_182wb_speech_office25db.pcm ../dataqa351/i30_182wb_speech_office25db.pcm +diff ../dataqa350/i60_182wb_speech_office25db.pcm ../dataqa351/i60_182wb_speech_office25db.pcm +diff ../dataqa350/i30_183wb_speech_office25db.pcm ../dataqa351/i30_183wb_speech_office25db.pcm +diff ../dataqa350/i60_183wb_speech_office25db.pcm ../dataqa351/i60_183wb_speech_office25db.pcm +diff ../dataqa350/i30_184wb_speech_office25db.pcm ../dataqa351/i30_184wb_speech_office25db.pcm +diff ../dataqa350/i60_184wb_speech_office25db.pcm ../dataqa351/i60_184wb_speech_office25db.pcm +diff ../dataqa350/i30_185wb_speech_office25db.pcm ../dataqa351/i30_185wb_speech_office25db.pcm +diff ../dataqa350/i60_185wb_speech_office25db.pcm ../dataqa351/i60_185wb_speech_office25db.pcm +diff ../dataqa350/i30_186wb_speech_office25db.pcm ../dataqa351/i30_186wb_speech_office25db.pcm +diff ../dataqa350/i60_186wb_speech_office25db.pcm ../dataqa351/i60_186wb_speech_office25db.pcm +diff ../dataqa350/a91wb_speech_office25db.pcm ../dataqa351/a91wb_speech_office25db.pcm +diff ../dataqa350/a92wb_speech_office25db.pcm ../dataqa351/a92wb_speech_office25db.pcm +diff ../dataqa350/a93wb_speech_office25db.pcm ../dataqa351/a93wb_speech_office25db.pcm +diff ../dataqa350/a30_1DTMF_16kHz_short.pcm ../dataqa351/a30_1DTMF_16kHz_short.pcm +diff ../dataqa350/a60_1DTMF_16kHz_short.pcm ../dataqa351/a60_1DTMF_16kHz_short.pcm +diff ../dataqa350/a30_2ltest_speech_noisy.pcm ../dataqa351/a30_2ltest_speech_noisy.pcm +diff ../dataqa350/a60_2ltest_speech_noisy.pcm ../dataqa351/a60_2ltest_speech_noisy.pcm +diff ../dataqa350/a30_3misc2.pcm ../dataqa351/a30_3misc2.pcm +diff ../dataqa350/a60_3misc2.pcm ../dataqa351/a60_3misc2.pcm +diff ../dataqa350/a30_4sinesweep.pcm ../dataqa351/a30_4sinesweep.pcm +diff ../dataqa350/a60_4sinesweep.pcm ../dataqa351/a60_4sinesweep.pcm +diff ../dataqa350/a30_5speechmusic.pcm ../dataqa351/a30_5speechmusic.pcm +diff ../dataqa350/a60_5speechmusic.pcm ../dataqa351/a60_5speechmusic.pcm +diff ../dataqa350/a30_6tone_cisco.pcm ../dataqa351/a30_6tone_cisco.pcm +diff ../dataqa350/a60_6tone_cisco.pcm ../dataqa351/a60_6tone_cisco.pcm +diff ../dataqa350/a60_7tone_cisco.pcm ../dataqa351/a60_7tone_cisco.pcm diff --git a/src/modules/audio_coding/codecs/isac/fix/test/QA/diffiSACPLC.txt b/src/modules/audio_coding/codecs/isac/fix/test/QA/diffiSACPLC.txt new file mode 100644 index 0000000000..9e3629b2ca --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/test/QA/diffiSACPLC.txt @@ -0,0 +1,20 @@ +#!/bin/bash +(set -o igncr) 2>/dev/null && set -o igncr; # force bash to ignore \r character + +LOGFILE=logplc.txt +echo "START PLC TEST" > $LOGFILE + +OUTDIR1=../dataqaplc_0 +OUTDIR2=../dataqaplc_1 + +diff $OUTDIR1/outplc1.pcm $OUTDIR2/outplc1.pcm +diff $OUTDIR1/outplc2.pcm $OUTDIR2/outplc2.pcm +diff $OUTDIR1/outplc3.pcm $OUTDIR2/outplc3.pcm +diff $OUTDIR1/outplc4.pcm $OUTDIR2/outplc4.pcm +diff $OUTDIR1/outplc5.pcm $OUTDIR2/outplc5.pcm +diff $OUTDIR1/outplc6.pcm $OUTDIR2/outplc6.pcm + +echo DONE! + + + diff --git a/src/modules/audio_coding/codecs/isac/fix/test/QA/runiSACLongtest.txt b/src/modules/audio_coding/codecs/isac/fix/test/QA/runiSACLongtest.txt new file mode 100644 index 0000000000..eeffc0c955 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/test/QA/runiSACLongtest.txt @@ -0,0 +1,61 @@ +#!/bin/bash +(set -o igncr) 2>/dev/null && set -o igncr; # force bash to ignore \r character + +LOGFILE=logNormal.txt +echo "START ISAC TEST" > $LOGFILE +echo >> $LOGFILE + +ISAC=../Release/kenny.exe +ISACFIXFLOAT=../Release/testFixFloat.exe + +INFILES=$(cat InputFiles.txt) +SUBSET=$(cat InputFilesFew.txt) +CHANNELFILES=$(cat ChannelFiles.txt) +CHANNELLIST=($(cat ChannelFiles.txt)) +INDIR=../data/orig +OUTDIR=../dataqa +mkdir -p $OUTDIR + +TARGETRATE=(10000 15000 20000 25000 30000 32000) +#echo ${CHANNELFILES[1]} + +index1=0 +index2=0 + +for file in $INFILES # loop over all input files + do + + for rate in ${TARGETRATE[*]} + do + let "index1=index1+1" + $ISAC -I $rate -FL 30 $INDIR/"$file" $OUTDIR/i30_$index1"$file" >> $LOGFILE + $ISAC -I $rate -FL 60 $INDIR/"$file" $OUTDIR/i60_$index1"$file" >> $LOGFILE + done + for channel in $CHANNELFILES + do + let "index2=index2+1" + $ISAC $INDIR/$channel $INDIR/"$file" $OUTDIR/a$index2"$file" >> $LOGFILE + done + +done + +index1=0 + +for file in $SUBSET # loop over the subset of input files + do + let "index1=index1+1" + $ISAC $INDIR/${CHANNELLIST[0]} -FL 30 -FIXED_FL $INDIR/"$file" $OUTDIR/a30_$index1"$file" >> $LOGFILE + $ISAC $INDIR/${CHANNELLIST[0]} -FL 60 -FIXED_FL $INDIR/"$file" $OUTDIR/a60_$index1"$file" >> $LOGFILE +done + +let "index1=index1+1" + $ISAC $INDIR/${CHANNELLIST[0]} -INITRATE 25000 -FL 30 $INDIR/"$file" $OUTDIR/a60_$index1"$file" >> $LOGFILE + +# Run fault test + +#./runiSACfault.txt + +echo DONE! + + + diff --git a/src/modules/audio_coding/codecs/isac/fix/test/QA/runiSACNB.txt b/src/modules/audio_coding/codecs/isac/fix/test/QA/runiSACNB.txt new file mode 100644 index 0000000000..605595cc04 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/test/QA/runiSACNB.txt @@ -0,0 +1,45 @@ +#!/bin/bash +(set -o igncr) 2>/dev/null && set -o igncr; # force bash to ignore \r character + +LOGFILE=logNB.txt +echo "START NARROWBAND TEST" > $LOGFILE +echo >> $LOGFILE + +ISAC=../Release/kenny.exe +ISACFIXFLOAT=../Release/testFixFloat.exe + +INFILES=$(cat InputFiles.txt) +SUBSET=$(cat InputFilesFew.txt) +CHANNELFILES=$(cat ChannelFiles.txt) +CHANNELLIST=($(cat ChannelFiles.txt)) +INDIR=../data/orig +OUTDIR=../dataqaNB +mkdir -p $OUTDIR + +TARGETRATE=(10000 15000 20000 25000 30000 32000) +#echo ${CHANNELFILES[1]} + +index1=0 +index2=0 + +# Narrowband Interfaces + +for file in $SUBSET # loop over all input files + do + for rate in ${TARGETRATE[*]} + do + let "index1=index1+1" + $ISAC $rate -FL 30 -NB 1 $INDIR/"$file" $OUTDIR/nb130_$index1"$file" >> $LOGFILE + $ISAC $rate -FL 60 -NB 1 $INDIR/"$file" $OUTDIR/nb160_$index1"$file" >> $LOGFILE + $ISAC $rate -FL 30 -NB 2 $INDIR/"$file" $OUTDIR/nb230_$index1"$file" >> $LOGFILE + $ISAC $rate -FL 60 -NB 2 $INDIR/"$file" $OUTDIR/nb260_$index1"$file" >> $LOGFILE + $ISAC $rate -FL 30 -NB 2 -PL 10 $INDIR/"$file" $OUTDIR/nb2plc30_$index1"$file" >> $LOGFILE + $ISAC $rate -FL 60 -NB 2 -PL 10 $INDIR/"$file" $OUTDIR/nb2plc60_$index1"$file" >> $LOGFILE + done + +done + +echo DONE! + + + diff --git a/src/modules/audio_coding/codecs/isac/fix/test/QA/runiSACPLC.txt b/src/modules/audio_coding/codecs/isac/fix/test/QA/runiSACPLC.txt new file mode 100644 index 0000000000..6bee6f7c3f --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/test/QA/runiSACPLC.txt @@ -0,0 +1,23 @@ +#!/bin/bash +(set -o igncr) 2>/dev/null && set -o igncr; # force bash to ignore \r character + +LOGFILE=logplc.txt +echo "START PLC TEST" > $LOGFILE + +ISAC=../Release/kenny.exe + +INDIR=../data/orig +OUTDIR=../dataqaplc_0 +mkdir -p $OUTDIR + +$ISAC 12000 -PL 15 $INDIR/speechmusic.pcm $OUTDIR/outplc1.pcm +$ISAC 20000 -PL 15 $INDIR/speechmusic.pcm $OUTDIR/outplc2.pcm +$ISAC 32000 -PL 15 $INDIR/speechmusic.pcm $OUTDIR/outplc3.pcm +$ISAC 12000 -PL 15 $INDIR/tone_cisco.pcm $OUTDIR/outplc4.pcm +$ISAC 20000 -PL 15 $INDIR/tone_cisco.pcm $OUTDIR/outplc5.pcm +$ISAC 32000 -PL 15 $INDIR/tone_cisco.pcm $OUTDIR/outplc6.pcm + +echo DONE! + + + diff --git a/src/modules/audio_coding/codecs/isac/fix/test/QA/runiSACRate.txt b/src/modules/audio_coding/codecs/isac/fix/test/QA/runiSACRate.txt new file mode 100644 index 0000000000..d8403e099d --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/test/QA/runiSACRate.txt @@ -0,0 +1,23 @@ +#!/bin/bash +(set -o igncr) 2>/dev/null && set -o igncr; # force bash to ignore \r character + +LOGG=loggRate.txt +OUTDIR=../dataqaRate +mkdir -p $OUTDIR + +../Release/kenny.exe 13000 -FIXED_FL -FL 30 -MAX 100 ../data/orig/sawsweep_380_60.pcm $OUTDIR/out_napi_1.pcm > $LOGG +../Release/kenny.exe ../data/orig/bottlenecks.txt -FIXED_FL -FL 30 -MAXRATE 32000 ../data/orig/sawsweep_380_60.pcm $OUTDIR/out_napi_2.pcm >> $LOGG +../Release/kenny.exe 13000 -FIXED_FL -FL 30 -MAX 100 ../data/orig/sawsweep_380_60.pcm $OUTDIR/out_napi_3.pcm >> $LOGG +../Release/kenny.exe ../data/orig/bottlenecks.txt -FIXED_FL -FL 30 -MAXRATE 32000 ../data/orig/sawsweep_380_60.pcm $OUTDIR/out_napi_4.pcm >> $LOGG +../Release/kenny.exe 13000 -FIXED_FL -FL 60 -MAX 100 ../data/orig/sawsweep_380_60.pcm $OUTDIR/out_napi_5.pcm >> $LOGG +../Release/kenny.exe ../data/orig/bottlenecks.txt -FIXED_FL -FL 60 -MAXRATE 32000 ../data/orig/sawsweep_380_60.pcm $OUTDIR/out_napi_6.pcm >> $LOGG +../Release/kenny.exe 13000 -INIT_RATE 32000 -FIXED_FL -FL 60 -MAX 100 ../data/orig/sawsweep_380_60.pcm $OUTDIR/out_napi_7.pcm >> $LOGG + +../Release/kenny.exe 13000 -FIXED_FL -FL 30 -MAX 100 ../data/orig/longspeech.pcm $OUTDIR/out_napi_11.pcm >> $LOGG +../Release/kenny.exe ../data/orig/bottlenecks.txt -FIXED_FL -FL 30 -MAXRATE 32000 ../data/orig/longspeech.pcm $OUTDIR/out_napi_12.pcm >> $LOGG +../Release/kenny.exe 13000 -FIXED_FL -FL 30 -MAX 100 ../data/orig/longspeech.pcm $OUTDIR/out_napi_13.pcm >> $LOGG +../Release/kenny.exe ../data/orig/bottlenecks.txt -FIXED_FL -FL 30 -MAXRATE 32000 ../data/orig/longspeech.pcm $OUTDIR/out_napi_14.pcm >> $LOGG +../Release/kenny.exe 13000 -FIXED_FL -FL 60 -MAX 100 ../data/orig/longspeech.pcm $OUTDIR/out_napi_15.pcm >> $LOGG +../Release/kenny.exe ../data/orig/bottlenecks.txt -FIXED_FL -FL 60 -MAXRATE 32000 ../data/orig/longspeech.pcm $OUTDIR/out_napi_16.pcm >> $LOGG +../Release/kenny.exe 13000 -INIT_RATE 32000 -FIXED_FL -FL 60 -MAX 100 ../data/orig/longspeech.pcm $OUTDIR/out_napi_17.pcm >> $LOGG + diff --git a/src/modules/audio_coding/codecs/isac/fix/test/QA/runiSACfault.txt b/src/modules/audio_coding/codecs/isac/fix/test/QA/runiSACfault.txt new file mode 100644 index 0000000000..f4d9478fd4 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/test/QA/runiSACfault.txt @@ -0,0 +1,40 @@ +#!/bin/bash +(set -o igncr) 2>/dev/null && set -o igncr; # force bash to ignore \r character + +LOGFILE=logfault.txt +echo "START FAULT TEST" > $LOGFILE + +ISAC=../Release/kenny.exe +ISACFIXFLOAT=../Release/testFixFloat.exe + +INFILES=$(cat InputFiles.txt) +SUBSET=$(cat InputFilesFew.txt) +CHANNELFILES=$(cat ChannelFiles.txt) +CHANNELLIST=($(cat ChannelFiles.txt)) +INDIR=../data/orig +OUTDIR=../dataqaft +mkdir -p $OUTDIR + +TARGETRATE=(10000 15000 20000 25000 30000 32000) +FAULTTEST=(1 2 3 4 5 6 7 9) + +index1=0 + +file=wb_contspeech.pcm + +# Fault test +for testnr in ${FAULTTEST[*]} + do + $ISAC 32000 -F $testnr $INDIR/"$file" $OUTDIR/ft$testnr"$file" >> $LOGFILE +done + +# Fault test number 10, error in bitstream + $ISAC 32000 -F 10 $INDIR/"$file" $OUTDIR/ft10_"$file" >> $LOGFILE + $ISAC 32000 -F 10 -PL 10 $INDIR/"$file" $OUTDIR/ft10plc_"$file" >> $LOGFILE + $ISAC 32000 -F 10 -NB 1 $INDIR/"$file" $OUTDIR/ft10nb1_"$file" >> $LOGFILE + $ISAC 32000 -F 10 -NB 2 -PL 10 $INDIR/"$file" $OUTDIR/ft10nb2_"$file" >> $LOGFILE + +echo DONE! + + + diff --git a/src/modules/audio_coding/codecs/isac/fix/test/QA/runiSACfixfloat.txt b/src/modules/audio_coding/codecs/isac/fix/test/QA/runiSACfixfloat.txt new file mode 100644 index 0000000000..c9e02df2e9 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/test/QA/runiSACfixfloat.txt @@ -0,0 +1,47 @@ +#!/bin/bash +(set -o igncr) 2>/dev/null && set -o igncr; # force bash to ignore \r character + +LOGFILE=logfxfl.txt +echo "START FIX-FLOAT TEST" > $LOGFILE + + +ISACFIXFLOAT=../testFixFloat.exe + +INFILES=$(cat InputFiles.txt) +SUBSET=$(cat InputFilesFew.txt) +CHANNELFILES=$(cat ChannelFiles.txt) +CHANNELLIST=($(cat ChannelFiles.txt)) +INDIR=../data/orig +OUTDIR=../dataqafxfl +mkdir -p $OUTDIR + +index1=0 + +for file in $INFILES # loop over all input files + do + + for channel in $CHANNELFILES + do + let "index1=index1+1" + + $ISACFIXFLOAT $INDIR/$channel -m 1 -PLC $INDIR/"$file" $OUTDIR/flfx$index1"$file" >> $LOGFILE + $ISACFIXFLOAT $INDIR/$channel -m 2 -PLC $INDIR/"$file" $OUTDIR/fxfl$index1"$file" >> $LOGFILE + done + +done + +index1=0 + +for file in $SUBSET # loop over the subset of input files + do + let "index1=index1+1" + $ISACFIXFLOAT $INDIR/$channel -m 1 -NB 1 $INDIR/"$file" $OUTDIR/flfxnb1_$index1"$file" >> $LOGFILE + $ISACFIXFLOAT $INDIR/$channel -m 2 -NB 1 $INDIR/"$file" $OUTDIR/fxflnb1_$index1"$file" >> $LOGFILE + $ISACFIXFLOAT $INDIR/$channel -m 1 -NB 2 -PLC $INDIR/"$file" $OUTDIR/flfxnb2_$index1"$file" >> $LOGFILE + $ISACFIXFLOAT $INDIR/$channel -m 2 -NB 2 -PLC $INDIR/"$file" $OUTDIR/fxflnb2_$index1"$file" >> $LOGFILE +done + +echo DONE! + + + diff --git a/src/modules/audio_coding/codecs/isac/fix/test/isacfix_unittest.cc b/src/modules/audio_coding/codecs/isac/fix/test/isacfix_unittest.cc new file mode 100644 index 0000000000..bef71e96f4 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/test/isacfix_unittest.cc @@ -0,0 +1,96 @@ +/* + * 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 <typedefs.h> + +#include "gtest/gtest.h" +#include "modules/audio_coding/codecs/isac/fix/source/filterbank_internal.h" +#include "modules/audio_coding/codecs/isac/fix/source/filterbank_tables.h" +#include "modules/audio_coding/codecs/isac/fix/source/lpc_masking_model.h" +#include "system_wrappers/interface/cpu_features_wrapper.h" + +class IsacUnitTest : public testing::Test { + protected: + // Pass a function pointer to the Tester function. + void CalculateResidualEnergyTester(CalculateResidualEnergy + CalculateResidualEnergyFunction) { + const int kIntOrder = 10; + const int32_t kInt32QDomain = 5; + const int kIntShift = 11; + int16_t a[kIntOrder + 1] = {32760, 122, 7, 0, -32760, -3958, + -48, 18745, 498, 9, 23456}; + int32_t corr[kIntOrder + 1] = {11443647, -27495, 0, + 98745, -11443600, 1, 1, 498, 9, 888, 23456}; + int q_shift_residual = 0; + int32_t residual_energy = 0; + + // Test the code path where (residual_energy >= 0x10000). + residual_energy = CalculateResidualEnergyFunction(kIntOrder, + kInt32QDomain, kIntShift, a, corr, &q_shift_residual); + EXPECT_EQ(1789023310, residual_energy); + EXPECT_EQ(2, q_shift_residual); + + // Test the code path where (residual_energy < 0x10000) + // and ((energy & 0x8000) != 0). + for(int i = 0; i < kIntOrder + 1; i++) { + a[i] = 24575 >> i; + corr[i] = i; + } + residual_energy = CalculateResidualEnergyFunction(kIntOrder, + kInt32QDomain, kIntShift, a, corr, &q_shift_residual); + EXPECT_EQ(1595279092, residual_energy); + EXPECT_EQ(26, q_shift_residual); + + // Test the code path where (residual_energy <= 0x7fff). + for(int i = 0; i < kIntOrder + 1; i++) { + a[i] = 2457 >> i; + } + residual_energy = CalculateResidualEnergyFunction(kIntOrder, + kInt32QDomain, kIntShift, a, corr, &q_shift_residual); + EXPECT_EQ(2029266944, residual_energy); + EXPECT_EQ(33, q_shift_residual); + } +}; + +TEST_F(IsacUnitTest, CalculateResidualEnergyTest) { + CalculateResidualEnergyTester(WebRtcIsacfix_CalculateResidualEnergyC); +#ifdef WEBRTC_DETECT_ARM_NEON + if ((WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON) != 0) { + CalculateResidualEnergyTester(WebRtcIsacfix_CalculateResidualEnergyNeon); + } +#elif defined(WEBRTC_ARCH_ARM_NEON) + CalculateResidualEnergyTester(WebRtcIsacfix_CalculateResidualEnergyNeon); +#endif +} + +TEST_F(IsacUnitTest, HighpassFilterFixDec32Test) { + const int kSamples = 20; + int16_t in[kSamples]; + int32_t state[2] = {12345, 987654}; +#ifdef WEBRTC_ARCH_ARM_V7 + int32_t out[kSamples] = {-1040, -1035, -22875, -1397, -27604, 20018, 7917, + -1279, -8552, -14494, -7558, -23537, -27258, -30554, -32768, -3432, -32768, + 25215, -27536, 22436}; +#else + int32_t out[kSamples] = {-1040, -1035, -22875, -1397, -27604, 20017, 7915, + -1280, -8554, -14496, -7561, -23541, -27263, -30560, -32768, -3441, -32768, + 25203, -27550, 22419}; +#endif + + for(int i = 0; i < kSamples; i++) { + in[i] = WEBRTC_SPL_WORD32_MAX / (i + 1); + } + + WebRtcIsacfix_HighpassFilterFixDec32(in, kSamples, + WebRtcIsacfix_kHPStCoeffOut1Q30, state); + + for(int i = 0; i < kSamples; i++) { + EXPECT_EQ(out[i], in[i]); + } +} diff --git a/src/modules/audio_coding/codecs/isac/fix/test/kenny.c b/src/modules/audio_coding/codecs/isac/fix/test/kenny.c new file mode 100644 index 0000000000..8b04c98ec5 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/test/kenny.c @@ -0,0 +1,853 @@ +/* + * 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. + */ + +/* kenny.c - Main function for the iSAC coder */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <ctype.h> + +#include "isacfix.h" + + +/* Defines */ +#define SEED_FILE "randseed.txt" /* Used when running decoder on garbage data */ +#define MAX_FRAMESAMPLES 960 /* max number of samples per frame (= 60 ms frame) */ +#define FRAMESAMPLES_10ms 160 /* number of samples per 10ms frame */ +#define FS 16000 /* sampling frequency (Hz) */ + +/* Function for reading audio data from PCM file */ +int readframe(WebRtc_Word16 *data, FILE *inp, int length) { + + short k, rlen, status = 0; + + rlen = fread(data, sizeof(WebRtc_Word16), length, inp); + if (rlen < length) { + for (k = rlen; k < length; k++) + data[k] = 0; + status = 1; + } + + return status; +} + +/* Struct for bottleneck model */ +typedef struct { + WebRtc_UWord32 send_time; /* samples */ + WebRtc_UWord32 arrival_time; /* samples */ + WebRtc_UWord32 sample_count; /* samples */ + WebRtc_UWord16 rtp_number; +} BottleNeckModel; + +void get_arrival_time(int current_framesamples, /* samples */ + int packet_size, /* bytes */ + int bottleneck, /* excluding headers; bits/s */ + BottleNeckModel *BN_data) +{ + const int HeaderSize = 35; + int HeaderRate; + + HeaderRate = HeaderSize * 8 * FS / current_framesamples; /* bits/s */ + + /* everything in samples */ + BN_data->sample_count = BN_data->sample_count + current_framesamples; + + BN_data->arrival_time += ((packet_size + HeaderSize) * 8 * FS) / (bottleneck + HeaderRate); + BN_data->send_time += current_framesamples; + + if (BN_data->arrival_time < BN_data->sample_count) + BN_data->arrival_time = BN_data->sample_count; + + BN_data->rtp_number++; +} + +void get_arrival_time2(int current_framesamples, + int current_delay, + BottleNeckModel *BN_data) +{ + if (current_delay == -1) + //dropped packet + { + BN_data->arrival_time += current_framesamples; + } + else if (current_delay != -2) + { + // + BN_data->arrival_time += (current_framesamples + ((FS/1000) * current_delay)); + } + //else + //current packet has same timestamp as previous packet + + BN_data->rtp_number++; +} + +int main(int argc, char* argv[]) +{ + + char inname[100], outname[100], outbitsname[100], bottleneck_file[100]; + FILE *inp, *outp, *f_bn, *outbits; + int endfile; + + int i, errtype, h = 0, k, packetLossPercent = 0; + WebRtc_Word16 CodingMode; + WebRtc_Word16 bottleneck; + WebRtc_Word16 framesize = 30; /* ms */ + int cur_framesmpls, err = 0, lostPackets = 0; + + /* Runtime statistics */ + double starttime, runtime, length_file; + + WebRtc_Word16 stream_len = 0; + WebRtc_Word16 framecnt, declen = 0; + WebRtc_Word16 shortdata[FRAMESAMPLES_10ms]; + WebRtc_Word16 decoded[MAX_FRAMESAMPLES]; + WebRtc_UWord16 streamdata[500]; + WebRtc_Word16 speechType[1]; + WebRtc_Word16 prevFrameSize = 1; + WebRtc_Word16 rateBPS = 0; + WebRtc_Word16 fixedFL = 0; + WebRtc_Word16 payloadSize = 0; + WebRtc_Word32 payloadRate = 0; + int setControlBWE = 0; + int readLoss; + FILE *plFile = NULL; + + char version_number[20]; + char tmpBit[5] = ".bit"; + + double kbps; + int totalbits =0; + int totalsmpls =0; +#ifdef _DEBUG + FILE *fy; +#endif + WebRtc_Word16 testNum, testCE; + + FILE *fp_gns = NULL; + int gns = 0; + int cur_delay = 0; + char gns_file[100]; + + int nbTest = 0; + WebRtc_Word16 lostFrame; + float scale = (float)0.7; + /* only one structure used for ISAC encoder */ + ISACFIX_MainStruct *ISAC_main_inst; + + /* For fault test 10, garbage data */ + FILE *seedfile; + unsigned int random_seed = (unsigned int) time(NULL);//1196764538 + + BottleNeckModel BN_data; + f_bn = NULL; + +#ifdef _DEBUG + fy = fopen("bit_rate.dat", "w"); + fclose(fy); + fy = fopen("bytes_frames.dat", "w"); + fclose(fy); +#endif + + readLoss = 0; + packetLossPercent = 0; + + /* Handling wrong input arguments in the command line */ + if ((argc<3) || (argc>21)) { + printf("\n\nWrong number of arguments or flag values.\n\n"); + + printf("\n"); + WebRtcIsacfix_version(version_number); + printf("iSAC version %s \n\n", version_number); + + printf("Usage:\n\n"); + printf("./kenny.exe [-F num][-I] bottleneck_value infile outfile \n\n"); + printf("with:\n"); + printf("[-I] :if -I option is specified, the coder will use\n"); + printf(" an instantaneous Bottleneck value. If not, it\n"); + printf(" will be an adaptive Bottleneck value.\n\n"); + printf("bottleneck_value :the value of the bottleneck provided either\n"); + printf(" as a fixed value (e.g. 25000) or\n"); + printf(" read from a file (e.g. bottleneck.txt)\n\n"); + printf("[-INITRATE num] :Set a new value for initial rate. Note! Only used" + " in adaptive mode.\n\n"); + printf("[-FL num] :Set (initial) frame length in msec. Valid length" + " are 30 and 60 msec.\n\n"); + printf("[-FIXED_FL] :Frame length will be fixed to initial value.\n\n"); + printf("[-MAX num] :Set the limit for the payload size of iSAC" + " in bytes. \n"); + printf(" Minimum 100, maximum 400.\n\n"); + printf("[-MAXRATE num] :Set the maxrate for iSAC in bits per second. \n"); + printf(" Minimum 32000, maximum 53400.\n\n"); + printf("[-F num] :if -F option is specified, the test function\n"); + printf(" will run the iSAC API fault scenario specified" + " by the\n"); + printf(" supplied number.\n"); + printf(" F 1 - Call encoder prior to init encoder call\n"); + printf(" F 2 - Call decoder prior to init decoder call\n"); + printf(" F 3 - Call decoder prior to encoder call\n"); + printf(" F 4 - Call decoder with a too short coded" + " sequence\n"); + printf(" F 5 - Call decoder with a too long coded" + " sequence\n"); + printf(" F 6 - Call decoder with random bit stream\n"); + printf(" F 7 - Call init encoder/decoder at random" + " during a call\n"); + printf(" F 8 - Call encoder/decoder without having" + " allocated memory for \n"); + printf(" encoder/decoder instance\n"); + printf(" F 9 - Call decodeB without calling decodeA\n"); + printf(" F 10 - Call decodeB with garbage data\n"); + printf("[-PL num] : if -PL option is specified 0<num<100 will " + "specify the\n"); + printf(" percentage of packet loss\n\n"); + printf("[-G file] : if -G option is specified the file given is" + " a .gns file\n"); + printf(" that represents a network profile\n\n"); + printf("[-NB num] : if -NB option, use the narrowband interfaces\n"); + printf(" num=1 => encode with narrowband encoder" + " (infile is narrowband)\n"); + printf(" num=2 => decode with narrowband decoder" + " (outfile is narrowband)\n\n"); + printf("[-CE num] : Test of APIs used by Conference Engine.\n"); + printf(" CE 1 - createInternal, freeInternal," + " getNewBitstream \n"); + printf(" CE 2 - transcode, getBWE \n"); + printf(" CE 3 - getSendBWE, setSendBWE. \n\n"); + printf("[-RTP_INIT num] : if -RTP_INIT option is specified num will be" + " the initial\n"); + printf(" value of the rtp sequence number.\n\n"); + printf("infile : Normal speech input file\n\n"); + printf("outfile : Speech output file\n\n"); + printf("Example usage : \n\n"); + printf("./kenny.exe -I bottleneck.txt speechIn.pcm speechOut.pcm\n\n"); + exit(0); + + } + + /* Print version number */ + WebRtcIsacfix_version(version_number); + printf("iSAC version %s \n\n", version_number); + + /* Loop over all command line arguments */ + CodingMode = 0; + testNum = 0; + testCE = 0; + for (i = 1; i < argc-2;i++) { + /* Instantaneous mode */ + if (!strcmp ("-I", argv[i])) { + printf("\nInstantaneous BottleNeck\n"); + CodingMode = 1; + i++; + } + + /* Set (initial) bottleneck value */ + if (!strcmp ("-INITRATE", argv[i])) { + rateBPS = atoi(argv[i + 1]); + setControlBWE = 1; + if ((rateBPS < 10000) || (rateBPS > 32000)) { + printf("\n%d is not a initial rate. " + "Valid values are in the range 10000 to 32000.\n", rateBPS); + exit(0); + } + printf("\nNew initial rate: %d\n", rateBPS); + i++; + } + + /* Set (initial) framelength */ + if (!strcmp ("-FL", argv[i])) { + framesize = atoi(argv[i + 1]); + if ((framesize != 30) && (framesize != 60)) { + printf("\n%d is not a valid frame length. " + "Valid length are 30 and 60 msec.\n", framesize); + exit(0); + } + printf("\nFrame Length: %d\n", framesize); + i++; + } + + /* Fixed frame length */ + if (!strcmp ("-FIXED_FL", argv[i])) { + fixedFL = 1; + setControlBWE = 1; + } + + /* Set maximum allowed payload size in bytes */ + if (!strcmp ("-MAX", argv[i])) { + payloadSize = atoi(argv[i + 1]); + printf("Maximum Payload Size: %d\n", payloadSize); + i++; + } + + /* Set maximum rate in bytes */ + if (!strcmp ("-MAXRATE", argv[i])) { + payloadRate = atoi(argv[i + 1]); + printf("Maximum Rate in kbps: %d\n", payloadRate); + i++; + } + + /* Test of fault scenarious */ + if (!strcmp ("-F", argv[i])) { + testNum = atoi(argv[i + 1]); + printf("\nFault test: %d\n", testNum); + if (testNum < 1 || testNum > 10) { + printf("\n%d is not a valid Fault Scenario number." + " Valid Fault Scenarios are numbered 1-10.\n", testNum); + exit(0); + } + i++; + } + + /* Packet loss test */ + if (!strcmp ("-PL", argv[i])) { + if( isdigit( *argv[i+1] ) ) { + packetLossPercent = atoi( argv[i+1] ); + if( (packetLossPercent < 0) | (packetLossPercent > 100) ) { + printf( "\nInvalid packet loss perentage \n" ); + exit( 0 ); + } + if( packetLossPercent > 0 ) { + printf( "\nSimulating %d %% of independent packet loss\n", + packetLossPercent ); + } else { + printf( "\nNo Packet Loss Is Simulated \n" ); + } + readLoss = 0; + } else { + readLoss = 1; + plFile = fopen( argv[i+1], "rb" ); + if( plFile == NULL ) { + printf( "\n couldn't open the frameloss file: %s\n", argv[i+1] ); + exit( 0 ); + } + printf( "\nSimulating packet loss through the given " + "channel file: %s\n", argv[i+1] ); + } + i++; + } + + /* Random packetlosses */ + if (!strcmp ("-rnd", argv[i])) { + srand(time(NULL) ); + printf( "\n Random pattern in lossed packets \n" ); + } + + /* Use gns file */ + if (!strcmp ("-G", argv[i])) { + sscanf(argv[i + 1], "%s", gns_file); + fp_gns = fopen(gns_file, "rb"); + if (fp_gns == NULL) { + printf("Cannot read file %s.\n", gns_file); + exit(0); + } + gns = 1; + i++; + } + + /* Run Narrowband interfaces (either encoder or decoder) */ + if (!strcmp ("-NB", argv[i])) { + nbTest = atoi(argv[i + 1]); + i++; + } + + /* Run Conference Engine APIs */ + if (!strcmp ("-CE", argv[i])) { + testCE = atoi(argv[i + 1]); + if (testCE==1 || testCE==2) { + i++; + scale = (float)atof( argv[i+1] ); + } else if (testCE < 1 || testCE > 3) { + printf("\n%d is not a valid CE-test number, valid Fault " + "Scenarios are numbered 1-3\n", testCE); + exit(0); + } + i++; + } + + /* Set initial RTP number */ + if (!strcmp ("-RTP_INIT", argv[i])) { + i++; + } + } + + /* Get Bottleneck value */ + /* Gns files and bottleneck should not and can not be used simultaneously */ + bottleneck = atoi(argv[CodingMode+1]); + if (bottleneck == 0 && gns == 0) { + sscanf(argv[CodingMode+1], "%s", bottleneck_file); + f_bn = fopen(bottleneck_file, "rb"); + if (f_bn == NULL) { + printf("No value provided for BottleNeck and cannot read file %s\n", bottleneck_file); + exit(0); + } else { + int aux_var; + printf("reading bottleneck rates from file %s\n\n",bottleneck_file); + if (fscanf(f_bn, "%d", &aux_var) == EOF) { + /* Set pointer to beginning of file */ + fseek(f_bn, 0L, SEEK_SET); + if (fscanf(f_bn, "%d", &aux_var) == EOF) { + exit(0); + } + } + bottleneck = (WebRtc_Word16)aux_var; + /* Bottleneck is a cosine function + * Matlab code for writing the bottleneck file: + * BottleNeck_10ms = 20e3 + 10e3 * cos((0:5999)/5999*2*pi); + * fid = fopen('bottleneck.txt', 'wb'); + * fprintf(fid, '%d\n', BottleNeck_10ms); fclose(fid); + */ + } + } else { + f_bn = NULL; + printf("\nfixed bottleneck rate of %d bits/s\n\n", bottleneck); + } + + if (CodingMode == 0) { + printf("\nAdaptive BottleNeck\n"); + } + + /* Get Input and Output files */ + sscanf(argv[argc-2], "%s", inname); + sscanf(argv[argc-1], "%s", outname); + + /* Add '.bit' to output bitstream file */ + while ((int)outname[h] != 0) { + outbitsname[h] = outname[h]; + h++; + } + for (k=0; k<5; k++) { + outbitsname[h] = tmpBit[k]; + h++; + } + if ((inp = fopen(inname,"rb")) == NULL) { + printf(" iSAC: Cannot read file %s\n", inname); + exit(1); + } + if ((outp = fopen(outname,"wb")) == NULL) { + printf(" iSAC: Cannot write file %s\n", outname); + exit(1); + } + + if ((outbits = fopen(outbitsname,"wb")) == NULL) { + printf(" iSAC: Cannot write file %s\n", outbitsname); + exit(1); + } + printf("\nInput:%s\nOutput:%s\n\n", inname, outname); + + /* Error test number 10, garbage data */ + if (testNum == 10) { + /* Test to run decoder with garbage data */ + srand(random_seed); + + if ( (seedfile = fopen(SEED_FILE, "a+t") ) == NULL ) { + printf("Error: Could not open file %s\n", SEED_FILE); + } + else { + fprintf(seedfile, "%u\n", random_seed); + fclose(seedfile); + } + } + + /* Runtime statistics */ + starttime = clock()/(double)CLOCKS_PER_SEC; + + /* Initialize the ISAC and BN structs */ + if (testNum != 8) + { + if(1){ + err =WebRtcIsacfix_Create(&ISAC_main_inst); + }else{ + /* Test the Assign functions */ + int sss; + void *ppp; + err =WebRtcIsacfix_AssignSize(&sss); + ppp=malloc(sss); + err =WebRtcIsacfix_Assign(&ISAC_main_inst,ppp); + } + /* Error check */ + if (err < 0) { + printf("\n\n Error in create.\n\n"); + } + if (testCE == 1) { + err = WebRtcIsacfix_CreateInternal(ISAC_main_inst); + /* Error check */ + if (err < 0) { + printf("\n\n Error in createInternal.\n\n"); + } + } + } + + /* Init of bandwidth data */ + BN_data.send_time = 0; + BN_data.arrival_time = 0; + BN_data.sample_count = 0; + BN_data.rtp_number = 0; + + /* Initialize encoder and decoder */ + framecnt= 0; + endfile = 0; + if (testNum != 1) { + WebRtcIsacfix_EncoderInit(ISAC_main_inst, CodingMode); + } + if (testNum != 2) { + WebRtcIsacfix_DecoderInit(ISAC_main_inst); + } + + if (CodingMode == 1) { + err = WebRtcIsacfix_Control(ISAC_main_inst, bottleneck, framesize); + if (err < 0) { + /* exit if returned with error */ + errtype=WebRtcIsacfix_GetErrorCode(ISAC_main_inst); + printf("\n\n Error in control: %d.\n\n", errtype); + } + } else if(setControlBWE == 1) { + err = WebRtcIsacfix_ControlBwe(ISAC_main_inst, rateBPS, framesize, fixedFL); + } + + if (payloadSize != 0) { + err = WebRtcIsacfix_SetMaxPayloadSize(ISAC_main_inst, payloadSize); + if (err < 0) { + /* exit if returned with error */ + errtype=WebRtcIsacfix_GetErrorCode(ISAC_main_inst); + printf("\n\n Error in SetMaxPayloadSize: %d.\n\n", errtype); + exit(EXIT_FAILURE); + } + } + if (payloadRate != 0) { + err = WebRtcIsacfix_SetMaxRate(ISAC_main_inst, payloadRate); + if (err < 0) { + /* exit if returned with error */ + errtype=WebRtcIsacfix_GetErrorCode(ISAC_main_inst); + printf("\n\n Error in SetMaxRateInBytes: %d.\n\n", errtype); + exit(EXIT_FAILURE); + } + } + + *speechType = 1; + + + while (endfile == 0) { + + if(testNum == 7 && (rand()%2 == 0)) { + err = WebRtcIsacfix_EncoderInit(ISAC_main_inst, CodingMode); + /* Error check */ + if (err < 0) { + errtype=WebRtcIsacfix_GetErrorCode(ISAC_main_inst); + printf("\n\n Error in encoderinit: %d.\n\n", errtype); + } + + err = WebRtcIsacfix_DecoderInit(ISAC_main_inst); + /* Error check */ + if (err < 0) { + errtype=WebRtcIsacfix_GetErrorCode(ISAC_main_inst); + printf("\n\n Error in decoderinit: %d.\n\n", errtype); + } + } + + + cur_framesmpls = 0; + while (1) { + /* Read 10 ms speech block */ + if (nbTest != 1) { + endfile = readframe(shortdata, inp, FRAMESAMPLES_10ms); + } else { + endfile = readframe(shortdata, inp, (FRAMESAMPLES_10ms/2)); + } + + if (testNum == 7) { + srand(time(NULL)); + } + + /* iSAC encoding */ + if (!(testNum == 3 && framecnt == 0)) { + if (nbTest != 1) { + short bwe; + + /* Encode */ + stream_len = WebRtcIsacfix_Encode(ISAC_main_inst, + shortdata, + (WebRtc_Word16*)streamdata); + + /* If packet is ready, and CE testing, call the different API functions + from the internal API. */ + if (stream_len>0) { + if (testCE == 1) { + err = WebRtcIsacfix_ReadBwIndex((WebRtc_Word16*)streamdata, &bwe); + stream_len = WebRtcIsacfix_GetNewBitStream( + ISAC_main_inst, + bwe, + scale, + (WebRtc_Word16*)streamdata); + } else if (testCE == 2) { + /* transcode function not supported */ + } else if (testCE == 3) { + /* Only for Function testing. The functions should normally + not be used in this way */ + + err = WebRtcIsacfix_GetDownLinkBwIndex(ISAC_main_inst, &bwe); + /* Error Check */ + if (err < 0) { + errtype=WebRtcIsacfix_GetErrorCode(ISAC_main_inst); + printf("\nError in getSendBWE: %d.\n", errtype); + } + + err = WebRtcIsacfix_UpdateUplinkBw(ISAC_main_inst, bwe); + /* Error Check */ + if (err < 0) { + errtype=WebRtcIsacfix_GetErrorCode(ISAC_main_inst); + printf("\nError in setBWE: %d.\n", errtype); + } + + } + } + } else { +#ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED + stream_len = WebRtcIsacfix_EncodeNb(ISAC_main_inst, + shortdata, + streamdata); +#else + stream_len = -1; +#endif + } + } + else + { + break; + } + + if (stream_len < 0 || err < 0) { + /* exit if returned with error */ + errtype=WebRtcIsacfix_GetErrorCode(ISAC_main_inst); + printf("\nError in encoder: %d.\n", errtype); + } else { + if (fwrite(streamdata, sizeof(char), + stream_len, outbits) != (size_t)stream_len) { + return -1; + } + } + + cur_framesmpls += FRAMESAMPLES_10ms; + + /* read next bottleneck rate */ + if (f_bn != NULL) { + int aux_var; + if (fscanf(f_bn, "%d", &aux_var) == EOF) { + /* Set pointer to beginning of file */ + fseek(f_bn, 0L, SEEK_SET); + if (fscanf(f_bn, "%d", &aux_var) == EOF) { + exit(0); + } + } + bottleneck = (WebRtc_Word16)aux_var; + if (CodingMode == 1) { + WebRtcIsacfix_Control(ISAC_main_inst, bottleneck, framesize); + } + } + + /* exit encoder loop if the encoder returned a bitstream */ + if (stream_len != 0) break; + } + + /* make coded sequence to short be inreasing */ + /* the length the decoder expects */ + if (testNum == 4) { + stream_len += 10; + } + + /* make coded sequence to long be decreasing */ + /* the length the decoder expects */ + if (testNum == 5) { + stream_len -= 10; + } + + if (testNum == 6) { + srand(time(NULL)); + for (i = 0; i < stream_len; i++ ) { + streamdata[i] = rand(); + } + } + + /* set pointer to beginning of file */ + if (fp_gns != NULL) { + if (fscanf(fp_gns, "%d", &cur_delay) == EOF) { + fseek(fp_gns, 0L, SEEK_SET); + if (fscanf(fp_gns, "%d", &cur_delay) == EOF) { + exit(0); + } + } + } + + /* simulate packet handling through NetEq and the modem */ + if (!(testNum == 3 && framecnt == 0)) { + if (gns == 0) { + get_arrival_time(cur_framesmpls, stream_len, bottleneck, + &BN_data); + } else { + get_arrival_time2(cur_framesmpls, cur_delay, &BN_data); + } + } + + /* packet not dropped */ + if (cur_delay != -1) { + + /* Error test number 10, garbage data */ + if (testNum == 10) { + for ( i = 0; i < stream_len; i++) { + streamdata[i] = (short) (streamdata[i] + (short) rand()); + } + } + + if (testNum != 9) { + err = WebRtcIsacfix_UpdateBwEstimate(ISAC_main_inst, + streamdata, + stream_len, + BN_data.rtp_number, + BN_data.send_time, + BN_data.arrival_time); + + if (err < 0) { + /* exit if returned with error */ + errtype=WebRtcIsacfix_GetErrorCode(ISAC_main_inst); + printf("\nError in decoder: %d.\n", errtype); + } + } +#ifdef _DEBUG + fprintf(stderr," \rframe = %7d", framecnt); +#endif + + if( readLoss == 1 ) { + if( fread( &lostFrame, sizeof(WebRtc_Word16), 1, plFile ) != 1 ) { + rewind( plFile ); + } + lostFrame = !lostFrame; + } else { + lostFrame = (rand()%100 < packetLossPercent); + } + + + + /* iSAC decoding */ + if( lostFrame && framecnt > 0) { + if (nbTest !=2) { + declen = WebRtcIsacfix_DecodePlc(ISAC_main_inst, + decoded, prevFrameSize ); + } else { +#ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED + declen = WebRtcIsacfix_DecodePlcNb(ISAC_main_inst, decoded, + prevFrameSize ); +#else + declen = -1; +#endif + } + lostPackets++; + } else { + if (nbTest !=2 ) { + short FL; + /* Call getFramelen, only used here for function test */ + err = WebRtcIsacfix_ReadFrameLen((WebRtc_Word16*)streamdata, &FL); + declen = WebRtcIsacfix_Decode( ISAC_main_inst, streamdata, stream_len, + decoded, speechType ); + /* Error check */ + if (err<0 || declen<0 || FL!=declen) { + errtype=WebRtcIsacfix_GetErrorCode(ISAC_main_inst); + printf("\nError in decode_B/or getFrameLen: %d.\n", errtype); + } + prevFrameSize = declen/480; + + } else { +#ifdef WEBRTC_ISAC_FIX_NB_CALLS_ENABLED + declen = WebRtcIsacfix_DecodeNb( ISAC_main_inst, streamdata, + stream_len, decoded, speechType ); +#else + declen = -1; +#endif + prevFrameSize = declen/240; + } + } + + if (declen <= 0) { + /* exit if returned with error */ + errtype=WebRtcIsacfix_GetErrorCode(ISAC_main_inst); + printf("\nError in decoder: %d.\n", errtype); + } + + /* Write decoded speech frame to file */ + if (fwrite(decoded, sizeof(WebRtc_Word16), + declen, outp) != (size_t)declen) { + return -1; + } + // fprintf( ratefile, "%f \n", stream_len / ( ((double)declen)/ + // ((double)FS) ) * 8 ); + } else { + lostPackets++; + } + framecnt++; + + totalsmpls += declen; + totalbits += 8 * stream_len; + kbps = ((double) FS) / ((double) cur_framesmpls) * 8.0 * + stream_len / 1000.0;// kbits/s + + /* Error test number 10, garbage data */ + if (testNum == 10) { + if ( (seedfile = fopen(SEED_FILE, "a+t") ) == NULL ) { + printf( "Error: Could not open file %s\n", SEED_FILE); + } + else { + fprintf(seedfile, "ok\n\n"); + fclose(seedfile); + } + } + +#ifdef _DEBUG + + fy = fopen("bit_rate.dat", "a"); + fprintf(fy, "Frame %i = %0.14f\n", framecnt, kbps); + fclose(fy); + +#endif /* _DEBUG */ + + } + printf("\nLost Frames %d ~ %4.1f%%\n", lostPackets, + (double)lostPackets/(double)framecnt*100.0 ); + printf("\n\ntotal bits = %d bits", totalbits); + printf("\nmeasured average bitrate = %0.3f kbits/s", + (double)totalbits *(FS/1000) / totalsmpls); + printf("\n"); + +#ifdef _DEBUG + /* fprintf(stderr,"\n\ntotal bits = %d bits", totalbits); + fprintf(stderr,"\nmeasured average bitrate = %0.3f kbits/s", + (double)totalbits *(FS/1000) / totalsmpls); + fprintf(stderr,"\n"); + */ +#endif /* _DEBUG */ + + /* Runtime statistics */ + + + runtime = (double)(((double)clock()/(double)CLOCKS_PER_SEC)-starttime); + length_file = ((double)framecnt*(double)declen/FS); + printf("\n\nLength of speech file: %.1f s\n", length_file); + printf("Time to run iSAC: %.2f s (%.2f %% of realtime)\n\n", + runtime, (100*runtime/length_file)); + printf("\n\n_______________________________________________\n"); + + fclose(inp); + fclose(outp); + fclose(outbits); + + if ( testCE == 1) { + WebRtcIsacfix_FreeInternal(ISAC_main_inst); + } + WebRtcIsacfix_Free(ISAC_main_inst); + return 0; +} diff --git a/src/modules/audio_coding/codecs/isac/fix/test/test_iSACfixfloat.c b/src/modules/audio_coding/codecs/isac/fix/test/test_iSACfixfloat.c new file mode 100644 index 0000000000..57c30cad96 --- /dev/null +++ b/src/modules/audio_coding/codecs/isac/fix/test/test_iSACfixfloat.c @@ -0,0 +1,693 @@ +/* + * 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. + */ + +/* + * test_iSACfixfloat.c + * + * Test compatibility and quality between floating- and fixed-point code + * */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* include API */ +#include "isac.h" +#include "isacfix.h" + + +/* max number of samples per frame (= 60 ms frame) */ +#define MAX_FRAMESAMPLES 960 +/* number of samples per 10ms frame */ +#define FRAMESAMPLES_10ms 160 +/* sampling frequency (Hz) */ +#define FS 16000 + + + +/* Runtime statistics */ +#include <time.h> +#define CLOCKS_PER_SEC 1000 + + + +// FILE *histfile, *ratefile; + + +/* function for reading audio data from PCM file */ +int readframe(WebRtc_Word16 *data, FILE *inp, int length) { + + short k, rlen, status = 0; + + rlen = fread(data, sizeof(WebRtc_Word16), length, inp); + if (rlen < length) { + for (k = rlen; k < length; k++) + data[k] = 0; + status = 1; + } + + return status; +} + +typedef struct { + WebRtc_UWord32 send_time; /* samples */ + WebRtc_UWord32 arrival_time; /* samples */ + WebRtc_UWord32 sample_count; /* samples */ + WebRtc_UWord16 rtp_number; +} BottleNeckModel; + +void get_arrival_time(int current_framesamples, /* samples */ + int packet_size, /* bytes */ + int bottleneck, /* excluding headers; bits/s */ + BottleNeckModel *BN_data) +{ + const int HeaderSize = 35; + int HeaderRate; + + HeaderRate = HeaderSize * 8 * FS / current_framesamples; /* bits/s */ + + /* everything in samples */ + BN_data->sample_count = BN_data->sample_count + current_framesamples; + + BN_data->arrival_time += ((packet_size + HeaderSize) * 8 * FS) / (bottleneck + HeaderRate); + BN_data->send_time += current_framesamples; + + if (BN_data->arrival_time < BN_data->sample_count) + BN_data->arrival_time = BN_data->sample_count; + + BN_data->rtp_number++; +} + + + +int main(int argc, char* argv[]) +{ + + char inname[50], outname[50], bottleneck_file[50], bitfilename[60], bitending[10]="_bits.pcm"; + FILE *inp, *outp, *f_bn, *bitsp; + int framecnt, endfile; + + + int i,j,errtype, plc=0; + WebRtc_Word16 CodingMode; + WebRtc_Word16 bottleneck; + + WebRtc_Word16 framesize = 30; /* ms */ + //WebRtc_Word16 framesize = 60; /* To invoke cisco complexity case at frame 2252 */ + + int cur_framesmpls, err; + + /* Runtime statistics */ + double starttime; + double runtime; + double length_file; + + WebRtc_Word16 stream_len = 0; + WebRtc_Word16 declen; + + WebRtc_Word16 shortdata[FRAMESAMPLES_10ms]; + WebRtc_Word16 decoded[MAX_FRAMESAMPLES]; + WebRtc_UWord16 streamdata[600]; + WebRtc_Word16 speechType[1]; + +// WebRtc_Word16 *iSACstruct; + + char version_number[20]; + int mode=-1, tmp, nbTest=0; /*,sss;*/ + +#ifdef _DEBUG + FILE *fy; + double kbps; + int totalbits =0; + int totalsmpls =0; +#endif /* _DEBUG */ + + + + + /* only one structure used for ISAC encoder */ + ISAC_MainStruct *ISAC_main_inst; + ISACFIX_MainStruct *ISACFIX_main_inst; + + BottleNeckModel BN_data; + f_bn = NULL; + +#ifdef _DEBUG + fy = fopen("bit_rate.dat", "w"); + fclose(fy); + fy = fopen("bytes_frames.dat", "w"); + fclose(fy); +#endif /* _DEBUG */ + + +//histfile = fopen("histo.dat", "ab"); +//ratefile = fopen("rates.dat", "ab"); + + /* handling wrong input arguments in the command line */ + if ((argc<6) || (argc>10)) { + printf("\n\nWrong number of arguments or flag values.\n\n"); + + printf("\n"); + WebRtcIsacfix_version(version_number); + printf("iSAC version %s \n\n", version_number); + + printf("Usage:\n\n"); + printf("./kenny.exe [-I] bottleneck_value infile outfile \n\n"); + printf("with:\n"); + + printf("[-I] : if -I option is specified, the coder will use\n"); + printf(" an instantaneous Bottleneck value. If not, it\n"); + printf(" will be an adaptive Bottleneck value.\n\n"); + printf("bottleneck_value : the value of the bottleneck provided either\n"); + printf(" as a fixed value (e.g. 25000) or\n"); + printf(" read from a file (e.g. bottleneck.txt)\n\n"); + printf("[-m] mode : Mode (encoder - decoder):\n"); + printf(" : 0 - float - float \n"); + printf(" : 1 - float - fix \n"); + printf(" : 2 - fix - float \n"); + printf(" : 3 - fix - fix \n"); + printf("[-PLC] : Test PLC packetlosses\n"); + printf("[-NB] num : Test NB interfaces, num=1 encNB, num=2 decNB\n"); + printf("infile : Normal speech input file\n\n"); + printf("outfile : Speech output file\n\n"); + printf("Example usage:\n\n"); + printf("./kenny.exe -I bottleneck.txt -m 1 speechIn.pcm speechOut.pcm\n\n"); + exit(0); + + } + + + printf("--------------------START---------------------\n\n"); + WebRtcIsac_version(version_number); + printf("iSAC FLOAT version %s \n", version_number); + WebRtcIsacfix_version(version_number); + printf("iSAC FIX version %s \n\n", version_number); + + CodingMode = 0; + tmp=1; + for (i = 1; i < argc;i++) + { + if (!strcmp ("-I", argv[i])) + { + printf("\nInstantaneous BottleNeck\n"); + CodingMode = 1; + i++; + tmp=0; + } + + if (!strcmp ("-m", argv[i])) { + mode=atoi(argv[i+1]); + i++; + } + + if (!strcmp ("-PLC", argv[i])) + { + plc=1; + } + + if (!strcmp ("-NB", argv[i])) + { + nbTest = atoi(argv[i + 1]); + i++; + } + + } + + if(mode<0) { + printf("\nError! Mode must be set: -m 0 \n"); + exit(0); + } + + if (CodingMode == 0) + { + printf("\nAdaptive BottleNeck\n"); + } + + + + /* Get Bottleneck value */ + bottleneck = atoi(argv[2-tmp]); + if (bottleneck == 0) + { + sscanf(argv[2-tmp], "%s", bottleneck_file); + f_bn = fopen(bottleneck_file, "rb"); + if (f_bn == NULL) + { + printf("No value provided for BottleNeck and cannot read file %s.\n", bottleneck_file); + exit(0); + } + else { + printf("reading bottleneck rates from file %s\n\n",bottleneck_file); + if (fscanf(f_bn, "%d", &bottleneck) == EOF) { + /* Set pointer to beginning of file */ + fseek(f_bn, 0L, SEEK_SET); + fscanf(f_bn, "%d", &bottleneck); + } + + /* Bottleneck is a cosine function + * Matlab code for writing the bottleneck file: + * BottleNeck_10ms = 20e3 + 10e3 * cos((0:5999)/5999*2*pi); + * fid = fopen('bottleneck.txt', 'wb'); + * fprintf(fid, '%d\n', BottleNeck_10ms); fclose(fid); + */ + } + } + else + { + printf("\nfixed bottleneck rate of %d bits/s\n\n", bottleneck); + } + + + + /* Get Input and Output files */ + sscanf(argv[argc-2], "%s", inname); + sscanf(argv[argc-1], "%s", outname); + + if ((inp = fopen(inname,"rb")) == NULL) { + printf(" iSAC: Cannot read file %s.\n", inname); + exit(1); + } + if ((outp = fopen(outname,"wb")) == NULL) { + printf(" iSAC: Cannot write file %s.\n", outname); + exit(1); + } + printf("\nInput:%s\nOutput:%s\n", inname, outname); + + i=0; + while (outname[i]!='\0') { + bitfilename[i]=outname[i]; + i++; + } + i-=4; + for (j=0;j<9;j++, i++) + bitfilename[i]=bitending[j]; + bitfilename[i]='\0'; + if ((bitsp = fopen(bitfilename,"wb")) == NULL) { + printf(" iSAC: Cannot read file %s.\n", bitfilename); + exit(1); + } + printf("Bitstream:%s\n\n", bitfilename); + + + + starttime = clock()/(double)CLOCKS_PER_SEC; /* Runtime statistics */ + + + /* Initialize the ISAC and BN structs */ + WebRtcIsac_create(&ISAC_main_inst); +/* WebRtcIsacfix_AssignSize(&sss); + iSACstruct=malloc(sss); + WebRtcIsacfix_Assign(&ISACFIX_main_inst,iSACstruct);*/ + WebRtcIsacfix_Create(&ISACFIX_main_inst); + + BN_data.send_time = 0; + BN_data.arrival_time = 0; + BN_data.sample_count = 0; + BN_data.rtp_number = 0; + + /* Initialize encoder and decoder */ + framecnt= 0; + endfile = 0; + + if (mode==0) { /* Encode using FLOAT, decode using FLOAT */ + + printf("Coding mode: Encode using FLOAT, decode using FLOAT \n\n"); + + /* Init iSAC FLOAT */ + WebRtcIsac_EncoderInit(ISAC_main_inst, CodingMode); + WebRtcIsac_DecoderInit(ISAC_main_inst); + if (CodingMode == 1) { + err = WebRtcIsac_Control(ISAC_main_inst, bottleneck, framesize); + if (err < 0) { + /* exit if returned with error */ + errtype=WebRtcIsac_GetErrorCode(ISAC_main_inst); + printf("\n\n Error in initialization: %d.\n\n", errtype); + // exit(EXIT_FAILURE); + } + } + + } else if (mode==1) { /* Encode using FLOAT, decode using FIX */ + + printf("Coding mode: Encode using FLOAT, decode using FIX \n\n"); + + /* Init iSAC FLOAT */ + WebRtcIsac_EncoderInit(ISAC_main_inst, CodingMode); + WebRtcIsac_DecoderInit(ISAC_main_inst); + if (CodingMode == 1) { + err = WebRtcIsac_Control(ISAC_main_inst, bottleneck, framesize); + if (err < 0) { + /* exit if returned with error */ + errtype=WebRtcIsac_GetErrorCode(ISAC_main_inst); + printf("\n\n Error in initialization: %d.\n\n", errtype); + // exit(EXIT_FAILURE); + } + } + + /* Init iSAC FIX */ + WebRtcIsacfix_EncoderInit(ISACFIX_main_inst, CodingMode); + WebRtcIsacfix_DecoderInit(ISACFIX_main_inst); + if (CodingMode == 1) { + err = WebRtcIsacfix_Control(ISACFIX_main_inst, bottleneck, framesize); + if (err < 0) { + /* exit if returned with error */ + errtype=WebRtcIsacfix_GetErrorCode(ISACFIX_main_inst); + printf("\n\n Error in initialization: %d.\n\n", errtype); + //exit(EXIT_FAILURE); + } + } + } else if (mode==2) { /* Encode using FIX, decode using FLOAT */ + + printf("Coding mode: Encode using FIX, decode using FLOAT \n\n"); + + /* Init iSAC FLOAT */ + WebRtcIsac_EncoderInit(ISAC_main_inst, CodingMode); + WebRtcIsac_DecoderInit(ISAC_main_inst); + if (CodingMode == 1) { + err = WebRtcIsac_Control(ISAC_main_inst, bottleneck, framesize); + if (err < 0) { + /* exit if returned with error */ + errtype=WebRtcIsac_GetErrorCode(ISAC_main_inst); + printf("\n\n Error in initialization: %d.\n\n", errtype); + //exit(EXIT_FAILURE); + } + } + + /* Init iSAC FIX */ + WebRtcIsacfix_EncoderInit(ISACFIX_main_inst, CodingMode); + WebRtcIsacfix_DecoderInit(ISACFIX_main_inst); + if (CodingMode == 1) { + err = WebRtcIsacfix_Control(ISACFIX_main_inst, bottleneck, framesize); + if (err < 0) { + /* exit if returned with error */ + errtype=WebRtcIsacfix_GetErrorCode(ISACFIX_main_inst); + printf("\n\n Error in initialization: %d.\n\n", errtype); + //exit(EXIT_FAILURE); + } + } + } else if (mode==3) { + + printf("Coding mode: Encode using FIX, decode using FIX \n\n"); + + WebRtcIsacfix_EncoderInit(ISACFIX_main_inst, CodingMode); + WebRtcIsacfix_DecoderInit(ISACFIX_main_inst); + if (CodingMode == 1) { + err = WebRtcIsacfix_Control(ISACFIX_main_inst, bottleneck, framesize); + if (err < 0) { + /* exit if returned with error */ + errtype=WebRtcIsacfix_GetErrorCode(ISACFIX_main_inst); + printf("\n\n Error in initialization: %d.\n\n", errtype); + //exit(EXIT_FAILURE); + } + } + + } else + printf("Mode must be value between 0 and 3\n"); + *speechType = 1; + +//#define BI_TEST 1 +#ifdef BI_TEST + err = WebRtcIsacfix_SetMaxPayloadSize(ISACFIX_main_inst, 300); + if (err < 0) { + /* exit if returned with error */ + errtype=WebRtcIsacfix_GetErrorCode(ISACFIX_main_inst); + printf("\n\n Error in setMaxPayloadSize: %d.\n\n", errtype); + fclose(inp); + fclose(outp); + fclose(bitsp); + return(EXIT_FAILURE); + } +#endif + + + while (endfile == 0) { + + cur_framesmpls = 0; + while (1) { + /* Read 10 ms speech block */ + if (nbTest != 1) + endfile = readframe(shortdata, inp, FRAMESAMPLES_10ms); + else + endfile = readframe(shortdata, inp, (FRAMESAMPLES_10ms/2)); + + /* iSAC encoding */ + + if (mode==0 || mode ==1) { + stream_len = WebRtcIsac_Encode(ISAC_main_inst, shortdata, streamdata); + if (stream_len < 0) { + /* exit if returned with error */ + errtype=WebRtcIsac_GetErrorCode(ISAC_main_inst); + printf("\n\nError in encoder: %d.\n\n", errtype); + // exit(EXIT_FAILURE); + } + } else if (mode==2 || mode==3) { + /* iSAC encoding */ + if (nbTest != 1) + stream_len = WebRtcIsacfix_Encode(ISACFIX_main_inst, shortdata, streamdata); + else + stream_len = WebRtcIsacfix_EncodeNb(ISACFIX_main_inst, shortdata, streamdata); + + if (stream_len < 0) { + /* exit if returned with error */ + errtype=WebRtcIsacfix_GetErrorCode(ISACFIX_main_inst); + printf("\n\nError in encoder: %d.\n\n", errtype); + // exit(EXIT_FAILURE); + } + } + + cur_framesmpls += FRAMESAMPLES_10ms; + + /* read next bottleneck rate */ + if (f_bn != NULL) { + if (fscanf(f_bn, "%d", &bottleneck) == EOF) { + /* Set pointer to beginning of file */ + fseek(f_bn, 0L, SEEK_SET); + fscanf(f_bn, "%d", &bottleneck); + } + if (CodingMode == 1) { + if (mode==0 || mode==1) + WebRtcIsac_Control(ISAC_main_inst, bottleneck, framesize); + else if (mode==2 || mode==3) + WebRtcIsacfix_Control(ISACFIX_main_inst, bottleneck, framesize); + } + } + + /* exit encoder loop if the encoder returned a bitstream */ + if (stream_len != 0) break; + } + + fwrite(streamdata, 1, stream_len, bitsp); /* NOTE! Writes bytes to file */ + + /* simulate packet handling through NetEq and the modem */ + get_arrival_time(cur_framesmpls, stream_len, bottleneck, + &BN_data); +//***************************** + if (1){ + if (mode==0) { + err = WebRtcIsac_UpdateBwEstimate(ISAC_main_inst, + streamdata, + stream_len, + BN_data.rtp_number, + BN_data.arrival_time); + + if (err < 0) { + /* exit if returned with error */ + errtype=WebRtcIsac_GetErrorCode(ISAC_main_inst); + printf("\n\nError in decoder: %d.\n\n", errtype); + //exit(EXIT_FAILURE); + } + /* iSAC decoding */ + declen = WebRtcIsac_Decode(ISAC_main_inst, + streamdata, + stream_len, + decoded, + speechType); + if (declen <= 0) { + /* exit if returned with error */ + errtype=WebRtcIsac_GetErrorCode(ISAC_main_inst); + printf("\n\nError in decoder: %d.\n\n", errtype); + //exit(EXIT_FAILURE); + } + } else if (mode==1) { + + err = WebRtcIsac_UpdateBwEstimate(ISAC_main_inst, + streamdata, + stream_len, + BN_data.rtp_number, + BN_data.arrival_time); + err = WebRtcIsacfix_UpdateBwEstimate1(ISACFIX_main_inst, + streamdata, + stream_len, + BN_data.rtp_number, + BN_data.arrival_time); + if (err < 0) { + /* exit if returned with error */ + errtype=WebRtcIsacfix_GetErrorCode(ISACFIX_main_inst); + printf("\n\nError in decoder: %d.\n\n", errtype); + //exit(EXIT_FAILURE); + } + + declen = WebRtcIsac_Decode(ISAC_main_inst, + streamdata, + stream_len, + decoded, + speechType); + + /* iSAC decoding */ + if (plc && (framecnt+1)%10 == 0) { + if (nbTest !=2 ) + declen = WebRtcIsacfix_DecodePlc( ISACFIX_main_inst, decoded, 1 ); + else + declen = WebRtcIsacfix_DecodePlcNb( ISACFIX_main_inst, decoded, 1 ); + } else { + if (nbTest !=2 ) + declen = WebRtcIsacfix_Decode(ISACFIX_main_inst, + streamdata, + stream_len, + decoded, + speechType); + else + declen = WebRtcIsacfix_DecodeNb(ISACFIX_main_inst, + streamdata, + stream_len, + decoded, + speechType); + } + + if (declen <= 0) { + /* exit if returned with error */ + errtype=WebRtcIsacfix_GetErrorCode(ISACFIX_main_inst); + printf("\n\nError in decoder: %d.\n\n", errtype); + //exit(EXIT_FAILURE); + } + } else if (mode==2) { + err = WebRtcIsacfix_UpdateBwEstimate1(ISACFIX_main_inst, + streamdata, + stream_len, + BN_data.rtp_number, + BN_data.arrival_time); + + err = WebRtcIsac_UpdateBwEstimate(ISAC_main_inst, + streamdata, + stream_len, + BN_data.rtp_number, + BN_data.arrival_time); + + if (err < 0) { + /* exit if returned with error */ + errtype=WebRtcIsac_GetErrorCode(ISAC_main_inst); + printf("\n\nError in decoder: %d.\n\n", errtype); + //exit(EXIT_FAILURE); + } + /* iSAC decoding */ + declen = WebRtcIsac_Decode(ISAC_main_inst, + streamdata, + stream_len, + decoded, + speechType); + if (declen <= 0) { + /* exit if returned with error */ + errtype=WebRtcIsac_GetErrorCode(ISAC_main_inst); + printf("\n\nError in decoder: %d.\n\n", errtype); + //exit(EXIT_FAILURE); + } + } else if (mode==3) { + err = WebRtcIsacfix_UpdateBwEstimate(ISACFIX_main_inst, + streamdata, + stream_len, + BN_data.rtp_number, + BN_data.send_time, + BN_data.arrival_time); + + if (err < 0) { + /* exit if returned with error */ + errtype=WebRtcIsacfix_GetErrorCode(ISACFIX_main_inst); + printf("\n\nError in decoder: %d.\n\n", errtype); + //exit(EXIT_FAILURE); + } + /* iSAC decoding */ + + if (plc && (framecnt+1)%10 == 0) { + if (nbTest !=2 ) + declen = WebRtcIsacfix_DecodePlc( ISACFIX_main_inst, decoded, 1 ); + else + declen = WebRtcIsacfix_DecodePlcNb( ISACFIX_main_inst, decoded, 1 ); + } else { + if (nbTest !=2 ) + declen = WebRtcIsacfix_Decode(ISACFIX_main_inst, + streamdata, + stream_len, + decoded, + speechType); + else + declen = WebRtcIsacfix_DecodeNb(ISACFIX_main_inst, + streamdata, + stream_len, + decoded, + speechType); + } + if (declen <= 0) { + /* exit if returned with error */ + errtype=WebRtcIsacfix_GetErrorCode(ISACFIX_main_inst); + printf("\n\nError in decoder: %d.\n\n", errtype); + //exit(EXIT_FAILURE); + } + } + + /* Write decoded speech frame to file */ + fwrite(decoded, sizeof(WebRtc_Word16), declen, outp); + } + + fprintf(stderr," \rframe = %d", framecnt); + framecnt++; + + + +#ifdef _DEBUG + + totalsmpls += declen; + totalbits += 8 * stream_len; + kbps = ((double) FS) / ((double) cur_framesmpls) * 8.0 * stream_len / 1000.0;// kbits/s + fy = fopen("bit_rate.dat", "a"); + fprintf(fy, "Frame %i = %0.14f\n", framecnt, kbps); + fclose(fy); + +#endif /* _DEBUG */ + + } + +#ifdef _DEBUG + printf("\n\ntotal bits = %d bits", totalbits); + printf("\nmeasured average bitrate = %0.3f kbits/s", (double)totalbits *(FS/1000) / totalsmpls); + printf("\n"); +#endif /* _DEBUG */ + + /* Runtime statistics */ + runtime = (double)(clock()/(double)CLOCKS_PER_SEC-starttime); + length_file = ((double)framecnt*(double)declen/FS); + printf("\n\nLength of speech file: %.1f s\n", length_file); + printf("Time to run iSAC: %.2f s (%.2f %% of realtime)\n\n", runtime, (100*runtime/length_file)); + printf("---------------------END----------------------\n"); + + fclose(inp); + fclose(outp); + + WebRtcIsac_Free(ISAC_main_inst); + WebRtcIsacfix_Free(ISACFIX_main_inst); + + + +// fclose(histfile); +// fclose(ratefile); + + return 0; + +} + + diff --git a/src/system_wrappers/interface/atomic32.h b/src/system_wrappers/interface/atomic32.h new file mode 100644 index 0000000000..e2b12589d7 --- /dev/null +++ b/src/system_wrappers/interface/atomic32.h @@ -0,0 +1,65 @@ +/* + * 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. + */ + +// Atomic, system independent 32-bit integer. Unless you know what you're +// doing, use locks instead! :-) +// +// Note: uses full memory barriers. +// Note: assumes 32-bit (or higher) system +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ATOMIC32_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ATOMIC32_H_ + +#include <cstddef> + +#include "common_types.h" +#include "constructor_magic.h" + +namespace webrtc { + +// 32 bit atomic variable. Note that this class relies on the compiler to +// align the 32 bit value correctly (on a 32 bit boundary), so as long as you're +// not doing things like reinterpret_cast over some custom allocated memory +// without being careful with alignment, you should be fine. +class Atomic32 +{ +public: + Atomic32(WebRtc_Word32 initialValue = 0); + ~Atomic32(); + + // Prefix operator! + WebRtc_Word32 operator++(); + WebRtc_Word32 operator--(); + + WebRtc_Word32 operator+=(WebRtc_Word32 value); + WebRtc_Word32 operator-=(WebRtc_Word32 value); + + // Sets the value atomically to newValue if the value equals compare value. + // The function returns true if the exchange happened. + bool CompareExchange(WebRtc_Word32 newValue, WebRtc_Word32 compareValue); + WebRtc_Word32 Value() const; + +private: + // Disable the + and - operator since it's unclear what these operations + // should do. + Atomic32 operator+(const Atomic32& other); + Atomic32 operator-(const Atomic32& other); + + // Checks if |_value| is 32bit aligned. + inline bool Is32bitAligned() const { + return (reinterpret_cast<ptrdiff_t>(&_value) & 3) == 0; + } + + DISALLOW_COPY_AND_ASSIGN(Atomic32); + + WebRtc_Word32 _value; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ATOMIC32_H_ diff --git a/src/system_wrappers/interface/atomic32_wrapper.h b/src/system_wrappers/interface/atomic32_wrapper.h deleted file mode 100644 index 40862fb492..0000000000 --- a/src/system_wrappers/interface/atomic32_wrapper.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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. - */ - -// Atomic system independant 32-bit integer. -// Note: uses full memory barriers. -// Note: assumes 32-bit (or higher) system -#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ATOMIC32_WRAPPER_H_ -#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ATOMIC32_WRAPPER_H_ - -#include "common_types.h" - -namespace webrtc { -class Atomic32Impl; -class Atomic32Wrapper -{ -public: - Atomic32Wrapper(WebRtc_Word32 initialValue = 0); - ~Atomic32Wrapper(); - - // Prefix operator! - WebRtc_Word32 operator++(); - WebRtc_Word32 operator--(); - - Atomic32Wrapper& operator=(const Atomic32Wrapper& rhs); - Atomic32Wrapper& operator=(WebRtc_Word32 rhs); - - WebRtc_Word32 operator+=(WebRtc_Word32 rhs); - WebRtc_Word32 operator-=(WebRtc_Word32 rhs); - - // Sets the value atomically to newValue if the value equals compare value. - // The function returns true if the exchange happened. - bool CompareExchange(WebRtc_Word32 newValue, WebRtc_Word32 compareValue); - WebRtc_Word32 Value() const; -private: - // Disable the + and - operator since it's unclear what these operations - // should do. - Atomic32Wrapper operator+(const Atomic32Wrapper& rhs); - Atomic32Wrapper operator-(const Atomic32Wrapper& rhs); - - WebRtc_Word32& operator++(int); - WebRtc_Word32& operator--(int); - - // Cheshire cat to hide the implementation (faster than - // using virtual functions) - Atomic32Impl& _impl; -}; -} // namespace webrtc -#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_ATOMIC32_WRAPPER_H_ diff --git a/src/system_wrappers/interface/compile_assert.h b/src/system_wrappers/interface/compile_assert.h new file mode 100644 index 0000000000..4feda86c3a --- /dev/null +++ b/src/system_wrappers/interface/compile_assert.h @@ -0,0 +1,21 @@ +/* + * 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. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_COMPILE_ASSERT_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_COMPILE_ASSERT_H_ + +/* Use this macro to verify at compile time that certain restrictions are met. + * The argument is the boolean expression to evaluate. + * Example: + * COMPILE_ASSERT(sizeof(foo) < 128); +*/ +#define COMPILE_ASSERT(expression) switch(0){case 0: case expression:;} + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_COMPILE_ASSERT_H_ diff --git a/src/system_wrappers/interface/fix_interlocked_exchange_pointer_win.h b/src/system_wrappers/interface/fix_interlocked_exchange_pointer_win.h new file mode 100644 index 0000000000..d85c724729 --- /dev/null +++ b/src/system_wrappers/interface/fix_interlocked_exchange_pointer_win.h @@ -0,0 +1,35 @@ +// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file under third_party_mods/chromium directory of +// source tree or at +// http://src.chromium.org/viewvc/chrome/trunk/src/LICENSE + +// Various inline functions and macros to fix compilation of 32 bit target +// on MSVC with /Wp64 flag enabled. + +// The original code can be found here: +// http://src.chromium.org/svn/trunk/src/base/fix_wp64.h + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_FIX_INTERLOCKED_EXCHANGE_POINTER_WINDOWS_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_FIX_INTERLOCKED_EXCHANGE_POINTER_WINDOWS_H_ + +#include <windows.h> + +// Platform SDK fixes when building with /Wp64 for a 32 bits target. +#if !defined(_WIN64) && defined(_Wp64) + +#ifdef InterlockedExchangePointer +#undef InterlockedExchangePointer +// The problem is that the macro provided for InterlockedExchangePointer() is +// doing a (LONG) C-style cast that triggers invariably the warning C4312 when +// building on 32 bits. +inline void* InterlockedExchangePointer(void* volatile* target, void* value) { + return reinterpret_cast<void*>(static_cast<LONG_PTR>(InterlockedExchange( + reinterpret_cast<volatile LONG*>(target), + static_cast<LONG>(reinterpret_cast<LONG_PTR>(value))))); +} +#endif // #ifdef InterlockedExchangePointer + +#endif // #if !defined(_WIN64) && defined(_Wp64) + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_FIX_INTERLOCKED_EXCHANGE_POINTER_WINDOWS_H_ diff --git a/src/system_wrappers/interface/ref_count.h b/src/system_wrappers/interface/ref_count.h index f90b0b3609..5112bd9037 100644 --- a/src/system_wrappers/interface/ref_count.h +++ b/src/system_wrappers/interface/ref_count.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -11,7 +11,7 @@ #ifndef SYSTEM_WRAPPERS_INTERFACE_REF_COUNT_H_ #define SYSTEM_WRAPPERS_INTERFACE_REF_COUNT_H_ -#include "system_wrappers/interface/atomic32_wrapper.h" +#include "system_wrappers/interface/atomic32.h" namespace webrtc { @@ -74,7 +74,7 @@ class RefCountImpl : public T { } protected: - Atomic32Wrapper ref_count_; + Atomic32 ref_count_; }; } // namespace webrtc diff --git a/src/system_wrappers/interface/sleep.h b/src/system_wrappers/interface/sleep.h new file mode 100644 index 0000000000..c0205bf085 --- /dev/null +++ b/src/system_wrappers/interface/sleep.h @@ -0,0 +1,24 @@ +/* + * 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. + */ +// An OS-independent sleep function. + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SLEEP_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SLEEP_H_ + +namespace webrtc { + +// This function sleeps for the specified number of milliseconds. +// It may return early if the thread is woken by some other event, +// such as the delivery of a signal on Unix. +void SleepMs(int msecs); + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SLEEP_H_ diff --git a/src/system_wrappers/interface/static_instance.h b/src/system_wrappers/interface/static_instance.h index 8fe91cc3e4..b670f969c9 100644 --- a/src/system_wrappers/interface/static_instance.h +++ b/src/system_wrappers/interface/static_instance.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -128,10 +128,8 @@ static T* GetStaticInstance(CountOperation count_operation) { // local copy. T* new_instance = T::CreateInstance(); if (1 == InterlockedIncrement(&instance_count)) { - T* old_value = static_cast<T*> (InterlockedExchangePointer( - reinterpret_cast<void* volatile*>(&instance), new_instance)); - assert(old_value == NULL); - assert(instance); + InterlockedExchangePointer(reinterpret_cast<void* volatile*>(&instance), + new_instance); } else { InterlockedDecrement(&instance_count); if (new_instance) { diff --git a/src/system_wrappers/interface/thread_wrapper.h b/src/system_wrappers/interface/thread_wrapper.h index 72a06e8bdd..030ac8a6f7 100644 --- a/src/system_wrappers/interface/thread_wrapper.h +++ b/src/system_wrappers/interface/thread_wrapper.h @@ -16,6 +16,9 @@ #ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_THREAD_WRAPPER_H_ #define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_THREAD_WRAPPER_H_ +#include "common_types.h" +#include "typedefs.h" + namespace webrtc { // Object that will be passed by the spawned thread when it enters the callback // function. @@ -51,9 +54,12 @@ public: // threadName NULL terminated thread name, will be visable in the Windows // debugger. static ThreadWrapper* CreateThread(ThreadRunFunction func = 0, - ThreadObj obj= 0, - ThreadPriority prio = kNormalPriority, - const char* threadName = 0); + ThreadObj obj= 0, + ThreadPriority prio = kNormalPriority, + const char* threadName = 0); + + // Get the current thread's kernel thread ID. + static uint32_t GetThreadId(); // Non blocking termination of the spawned thread. Note that it is not safe // to delete this class until the spawned thread has been reclaimed. @@ -69,8 +75,9 @@ public: // should be lower than (number of CPUs - 1). amountOfProcessors should be // equal to the number of processors listed in processorNumbers virtual bool SetAffinity(const int* /*processorNumbers*/, - const unsigned int /*amountOfProcessors*/) - {return false;} + const unsigned int /*amountOfProcessors*/) { + return false; + } // Stops the spawned thread and waits for it to be reclaimed with a timeout // of two seconds. Will return false if the thread was not reclaimed. diff --git a/src/system_wrappers/interface/tick_util.h b/src/system_wrappers/interface/tick_util.h index e78e53d2e1..0cd85d0050 100644 --- a/src/system_wrappers/interface/tick_util.h +++ b/src/system_wrappers/interface/tick_util.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -19,6 +19,9 @@ #include <mmsystem.h> #elif WEBRTC_LINUX #include <ctime> +#elif WEBRTC_MAC +#include <mach/mach_time.h> +#include <string.h> #else #include <sys/time.h> #include <time.h> @@ -133,6 +136,7 @@ inline TickTime TickTime::Now() { TickTime result; #if _WIN32 + // TODO(wu): Remove QueryPerformanceCounter implementation. #ifdef USE_QUERY_PERFORMANCE_COUNTER // QueryPerformanceCounter returns the value from the TSC which is // incremented at the CPU frequency. The algorithm used requires @@ -164,12 +168,27 @@ inline TickTime TickTime::Now() #endif #elif defined(WEBRTC_LINUX) struct timespec ts; + // TODO(wu): Remove CLOCK_REALTIME implementation. #ifdef WEBRTC_CLOCK_TYPE_REALTIME clock_gettime(CLOCK_REALTIME, &ts); #else clock_gettime(CLOCK_MONOTONIC, &ts); #endif result._ticks = 1000000000LL * static_cast<WebRtc_Word64>(ts.tv_sec) + static_cast<WebRtc_Word64>(ts.tv_nsec); +#elif defined(WEBRTC_MAC) + static mach_timebase_info_data_t timebase; + if (timebase.denom == 0) { + // Get the timebase if this is the first time we run. + // Recommended by Apple's QA1398. + kern_return_t retval = mach_timebase_info(&timebase); + if (retval != KERN_SUCCESS) { + // TODO(wu): Implement CHECK similar to chrome for all the platforms. + // Then replace this with a CHECK(retval == KERN_SUCCESS); + asm("int3"); + } + } + // Use timebase to convert absolute time tick units into nanoseconds. + result._ticks = mach_absolute_time() * timebase.numer / timebase.denom; #else struct timeval tv; gettimeofday(&tv, NULL); @@ -189,7 +208,7 @@ inline WebRtc_Word64 TickTime::MillisecondTimestamp() #else return now._ticks; #endif -#elif WEBRTC_LINUX +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) return now._ticks / 1000000LL; #else return now._ticks / 1000LL; @@ -208,7 +227,7 @@ inline WebRtc_Word64 TickTime::MicrosecondTimestamp() #else return now._ticks *1000LL; #endif -#elif WEBRTC_LINUX +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) return now._ticks / 1000LL; #else return now._ticks; @@ -230,7 +249,7 @@ inline WebRtc_Word64 TickTime::MillisecondsToTicks(const WebRtc_Word64 ms) #else return ms; #endif -#elif WEBRTC_LINUX +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) return ms * 1000000LL; #else return ms * 1000LL; @@ -247,7 +266,7 @@ inline WebRtc_Word64 TickTime::TicksToMilliseconds(const WebRtc_Word64 ticks) #else return ticks; #endif -#elif WEBRTC_LINUX +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) return ticks / 1000000LL; #else return ticks / 1000LL; @@ -280,7 +299,7 @@ inline WebRtc_Word64 TickInterval::Milliseconds() const // _interval is in ms return _interval; #endif -#elif WEBRTC_LINUX +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) // _interval is in ns return _interval / 1000000; #else @@ -300,7 +319,7 @@ inline WebRtc_Word64 TickInterval::Microseconds() const // _interval is in ms return _interval *1000LL; #endif -#elif WEBRTC_LINUX +#elif defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) // _interval is in ns return _interval / 1000; #else diff --git a/src/system_wrappers/interface/trace.h b/src/system_wrappers/interface/trace.h index 8330f7c4e1..f88d23f8a7 100644 --- a/src/system_wrappers/interface/trace.h +++ b/src/system_wrappers/interface/trace.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -45,11 +45,11 @@ public: // Sets the file name. If addFileCounter is false the same file will be // reused when it fills up. If it's true a new file with incremented name // will be used. - static WebRtc_Word32 SetTraceFile(const WebRtc_Word8* fileName, + static WebRtc_Word32 SetTraceFile(const char* fileName, const bool addFileCounter = false); // Returns the name of the file that the trace is currently writing to. - static WebRtc_Word32 TraceFile(WebRtc_Word8 fileName[1024]); + static WebRtc_Word32 TraceFile(char fileName[1024]); // Registers callback to receive trace messages. TODO (hellner) // why not use OutStream instead? Why is TraceCallback not defined in this @@ -70,7 +70,6 @@ public: const TraceModule module, const WebRtc_Word32 id, const char* msg, ...); - }; } // namespace webrtc #endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_TRACE_H_ diff --git a/src/system_wrappers/source/Android.mk b/src/system_wrappers/source/Android.mk index 575580a497..dee84ca294 100644 --- a/src/system_wrappers/source/Android.mk +++ b/src/system_wrappers/source/Android.mk @@ -1,4 +1,4 @@ -# Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. +# 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 @@ -17,15 +17,15 @@ LOCAL_MODULE := libwebrtc_system_wrappers LOCAL_MODULE_TAGS := optional LOCAL_CPP_EXTENSION := .cc LOCAL_SRC_FILES := \ + android/cpu-features.c \ + cpu_features_android.c \ map.cc \ - rw_lock_generic.cc \ sort.cc \ aligned_malloc.cc \ - atomic32.cc \ + atomic32_posix.cc \ condition_variable.cc \ cpu_no_op.cc \ cpu_features.cc \ - cpu_features_arm.c \ cpu_info.cc \ critical_section.cc \ event.cc \ @@ -38,6 +38,7 @@ LOCAL_SRC_FILES := \ cpu_linux.cc \ critical_section_posix.cc \ event_posix.cc \ + sleep.cc \ thread_posix.cc \ trace_posix.cc \ rw_lock_posix.cc diff --git a/src/system_wrappers/source/android/cpu-features.c b/src/system_wrappers/source/android/cpu-features.c new file mode 100644 index 0000000000..6a5cd8f1aa --- /dev/null +++ b/src/system_wrappers/source/android/cpu-features.c @@ -0,0 +1,396 @@ +/* + * 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 <sys/system_properties.h> +#ifdef __arm__ +#include <machine/cpu-features.h> +#endif +#include <pthread.h> +#include "cpu-features.h" +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <errno.h> + +static pthread_once_t g_once; +static AndroidCpuFamily g_cpuFamily; +static uint64_t g_cpuFeatures; +static int g_cpuCount; + +static const int android_cpufeatures_debug = 0; + +#ifdef __arm__ +# define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_ARM +#elif defined __i386__ +# define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_X86 +#else +# define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_UNKNOWN +#endif + +#define D(...) \ + do { \ + if (android_cpufeatures_debug) { \ + printf(__VA_ARGS__); fflush(stdout); \ + } \ + } while (0) + +#ifdef __i386__ +static __inline__ void x86_cpuid(int func, int values[4]) +{ + int a, b, c, d; + /* We need to preserve ebx since we're compiling PIC code */ + /* this means we can't use "=b" for the second output register */ + __asm__ __volatile__ ( \ + "push %%ebx\n" + "cpuid\n" \ + "mov %1, %%ebx\n" + "pop %%ebx\n" + : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \ + : "a" (func) \ + ); + values[0] = a; + values[1] = b; + values[2] = c; + values[3] = d; +} +#endif + +/* Read the content of /proc/cpuinfo into a user-provided buffer. + * Return the length of the data, or -1 on error. Does *not* + * zero-terminate the content. Will not read more + * than 'buffsize' bytes. + */ +static int +read_file(const char* pathname, char* buffer, size_t buffsize) +{ + int fd, len; + + fd = open(pathname, O_RDONLY); + if (fd < 0) + return -1; + + do { + len = read(fd, buffer, buffsize); + } while (len < 0 && errno == EINTR); + + close(fd); + + return len; +} + +/* Extract the content of a the first occurence of a given field in + * the content of /proc/cpuinfo and return it as a heap-allocated + * string that must be freed by the caller. + * + * Return NULL if not found + */ +static char* +extract_cpuinfo_field(char* buffer, int buflen, const char* field) +{ + int fieldlen = strlen(field); + char* bufend = buffer + buflen; + char* result = NULL; + int len, ignore; + const char *p, *q; + + /* Look for first field occurence, and ensures it starts the line. + */ + p = buffer; + bufend = buffer + buflen; + for (;;) { + p = memmem(p, bufend-p, field, fieldlen); + if (p == NULL) + goto EXIT; + + if (p == buffer || p[-1] == '\n') + break; + + p += fieldlen; + } + + /* Skip to the first column followed by a space */ + p += fieldlen; + p = memchr(p, ':', bufend-p); + if (p == NULL || p[1] != ' ') + goto EXIT; + + /* Find the end of the line */ + p += 2; + q = memchr(p, '\n', bufend-p); + if (q == NULL) + q = bufend; + + /* Copy the line into a heap-allocated buffer */ + len = q-p; + result = malloc(len+1); + if (result == NULL) + goto EXIT; + + memcpy(result, p, len); + result[len] = '\0'; + +EXIT: + return result; +} + +/* Count the number of occurences of a given field prefix in /proc/cpuinfo. + */ +static int +count_cpuinfo_field(char* buffer, int buflen, const char* field) +{ + int fieldlen = strlen(field); + const char* p = buffer; + const char* bufend = buffer + buflen; + const char* q; + int count = 0; + + for (;;) { + const char* q; + + p = memmem(p, bufend-p, field, fieldlen); + if (p == NULL) + break; + + /* Ensure that the field is at the start of a line */ + if (p > buffer && p[-1] != '\n') { + p += fieldlen; + continue; + } + + + /* skip any whitespace */ + q = p + fieldlen; + while (q < bufend && (*q == ' ' || *q == '\t')) + q++; + + /* we must have a colon now */ + if (q < bufend && *q == ':') { + count += 1; + q ++; + } + p = q; + } + + return count; +} + +/* Like strlen(), but for constant string literals */ +#define STRLEN_CONST(x) ((sizeof(x)-1) + + +/* Checks that a space-separated list of items contains one given 'item'. + * Returns 1 if found, 0 otherwise. + */ +static int +has_list_item(const char* list, const char* item) +{ + const char* p = list; + int itemlen = strlen(item); + + if (list == NULL) + return 0; + + while (*p) { + const char* q; + + /* skip spaces */ + while (*p == ' ' || *p == '\t') + p++; + + /* find end of current list item */ + q = p; + while (*q && *q != ' ' && *q != '\t') + q++; + + if (itemlen == q-p && !memcmp(p, item, itemlen)) + return 1; + + /* skip to next item */ + p = q; + } + return 0; +} + + +static void +android_cpuInit(void) +{ + char cpuinfo[4096]; + int cpuinfo_len; + + g_cpuFamily = DEFAULT_CPU_FAMILY; + g_cpuFeatures = 0; + g_cpuCount = 1; + + cpuinfo_len = read_file("/proc/cpuinfo", cpuinfo, sizeof cpuinfo); + D("cpuinfo_len is (%d):\n%.*s\n", cpuinfo_len, + cpuinfo_len >= 0 ? cpuinfo_len : 0, cpuinfo); + + if (cpuinfo_len < 0) /* should not happen */ { + return; + } + + /* Count the CPU cores, the value may be 0 for single-core CPUs */ + g_cpuCount = count_cpuinfo_field(cpuinfo, cpuinfo_len, "processor"); + if (g_cpuCount == 0) { + g_cpuCount = count_cpuinfo_field(cpuinfo, cpuinfo_len, "Processor"); + if (g_cpuCount == 0) { + g_cpuCount = 1; + } + } + + D("found cpuCount = %d\n", g_cpuCount); + +#ifdef __ARM_ARCH__ + { + char* features = NULL; + char* architecture = NULL; + + /* Extract architecture from the "CPU Architecture" field. + * The list is well-known, unlike the the output of + * the 'Processor' field which can vary greatly. + * + * See the definition of the 'proc_arch' array in + * $KERNEL/arch/arm/kernel/setup.c and the 'c_show' function in + * same file. + */ + char* cpuArch = extract_cpuinfo_field(cpuinfo, cpuinfo_len, "CPU architecture"); + + if (cpuArch != NULL) { + char* end; + long archNumber; + int hasARMv7 = 0; + + D("found cpuArch = '%s'\n", cpuArch); + + /* read the initial decimal number, ignore the rest */ + archNumber = strtol(cpuArch, &end, 10); + + /* Here we assume that ARMv8 will be upwards compatible with v7 + * in the future. Unfortunately, there is no 'Features' field to + * indicate that Thumb-2 is supported. + */ + if (end > cpuArch && archNumber >= 7) { + hasARMv7 = 1; + } + + /* Unfortunately, it seems that certain ARMv6-based CPUs + * report an incorrect architecture number of 7! + * + * See http://code.google.com/p/android/issues/detail?id=10812 + * + * We try to correct this by looking at the 'elf_format' + * field reported by the 'Processor' field, which is of the + * form of "(v7l)" for an ARMv7-based CPU, and "(v6l)" for + * an ARMv6-one. + */ + if (hasARMv7) { + char* cpuProc = extract_cpuinfo_field(cpuinfo, cpuinfo_len, + "Processor"); + if (cpuProc != NULL) { + D("found cpuProc = '%s'\n", cpuProc); + if (has_list_item(cpuProc, "(v6l)")) { + D("CPU processor and architecture mismatch!!\n"); + hasARMv7 = 0; + } + free(cpuProc); + } + } + + if (hasARMv7) { + g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_ARMv7; + } + + /* The LDREX / STREX instructions are available from ARMv6 */ + if (archNumber >= 6) { + g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_LDREX_STREX; + } + + free(cpuArch); + } + + /* Extract the list of CPU features from 'Features' field */ + char* cpuFeatures = extract_cpuinfo_field(cpuinfo, cpuinfo_len, "Features"); + + if (cpuFeatures != NULL) { + + D("found cpuFeatures = '%s'\n", cpuFeatures); + + if (has_list_item(cpuFeatures, "vfpv3")) + g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3; + + else if (has_list_item(cpuFeatures, "vfpv3d16")) + g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3; + + if (has_list_item(cpuFeatures, "neon")) { + /* Note: Certain kernels only report neon but not vfpv3 + * in their features list. However, ARM mandates + * that if Neon is implemented, so must be VFPv3 + * so always set the flag. + */ + g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON | + ANDROID_CPU_ARM_FEATURE_VFPv3; + } + free(cpuFeatures); + } + } +#endif /* __ARM_ARCH__ */ + +#ifdef __i386__ + g_cpuFamily = ANDROID_CPU_FAMILY_X86; + + int regs[4]; + +/* According to http://en.wikipedia.org/wiki/CPUID */ +#define VENDOR_INTEL_b 0x756e6547 +#define VENDOR_INTEL_c 0x6c65746e +#define VENDOR_INTEL_d 0x49656e69 + + x86_cpuid(0, regs); + int vendorIsIntel = (regs[1] == VENDOR_INTEL_b && + regs[2] == VENDOR_INTEL_c && + regs[3] == VENDOR_INTEL_d); + + x86_cpuid(1, regs); + if ((regs[2] & (1 << 9)) != 0) { + g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSSE3; + } + if ((regs[2] & (1 << 23)) != 0) { + g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_POPCNT; + } + if (vendorIsIntel && (regs[2] & (1 << 22)) != 0) { + g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_MOVBE; + } +#endif +} + + +AndroidCpuFamily +android_getCpuFamily(void) +{ + pthread_once(&g_once, android_cpuInit); + return g_cpuFamily; +} + + +uint64_t +android_getCpuFeatures(void) +{ + pthread_once(&g_once, android_cpuInit); + return g_cpuFeatures; +} + + +int +android_getCpuCount(void) +{ + pthread_once(&g_once, android_cpuInit); + return g_cpuCount; +} diff --git a/src/system_wrappers/source/android/cpu-features.h b/src/system_wrappers/source/android/cpu-features.h new file mode 100644 index 0000000000..f20c0bc4d9 --- /dev/null +++ b/src/system_wrappers/source/android/cpu-features.h @@ -0,0 +1,56 @@ +/* + * 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. + */ + +// You can download Android source at +// http://source.android.com/source/downloading.html +// Original files are in ndk/sources/android/cpufeatures +// Revision is Change-Id: I9a0629efba36a6023f05e5f092e7addcc1b7d2a9 + +#ifndef CPU_FEATURES_H +#define CPU_FEATURES_H + +#include <sys/cdefs.h> +#include <stdint.h> + +__BEGIN_DECLS + +typedef enum { + ANDROID_CPU_FAMILY_UNKNOWN = 0, + ANDROID_CPU_FAMILY_ARM, + ANDROID_CPU_FAMILY_X86, + + ANDROID_CPU_FAMILY_MAX /* do not remove */ + +} AndroidCpuFamily; + +/* Return family of the device's CPU */ +extern AndroidCpuFamily android_getCpuFamily(void); + +enum { + ANDROID_CPU_ARM_FEATURE_ARMv7 = (1 << 0), + ANDROID_CPU_ARM_FEATURE_VFPv3 = (1 << 1), + ANDROID_CPU_ARM_FEATURE_NEON = (1 << 2), + ANDROID_CPU_ARM_FEATURE_LDREX_STREX = (1 << 3), +}; + +enum { + ANDROID_CPU_X86_FEATURE_SSSE3 = (1 << 0), + ANDROID_CPU_X86_FEATURE_POPCNT = (1 << 1), + ANDROID_CPU_X86_FEATURE_MOVBE = (1 << 2), +}; + +extern uint64_t android_getCpuFeatures(void); + +/* Return the number of CPU cores detected on this device. */ +extern int android_getCpuCount(void); + +__END_DECLS + +#endif /* CPU_FEATURES_H */ diff --git a/src/system_wrappers/source/atomic32.cc b/src/system_wrappers/source/atomic32.cc deleted file mode 100644 index 588dd3e07d..0000000000 --- a/src/system_wrappers/source/atomic32.cc +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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 "atomic32_wrapper.h" - -#if defined(_WIN32) - #include "atomic32_win.h" -#elif defined(WEBRTC_LINUX) - #include "atomic32_linux.h" -#elif defined(WEBRTC_MAC) - #include "atomic32_mac.h" -#else - #error unsupported os! -#endif - -namespace webrtc { -Atomic32Wrapper::Atomic32Wrapper(WebRtc_Word32 initialValue) - : _impl(*new Atomic32Impl(initialValue)) -{ -} - -Atomic32Wrapper::~Atomic32Wrapper() -{ - delete &_impl; -} - -WebRtc_Word32 Atomic32Wrapper::operator++() -{ - return ++_impl; -} - -WebRtc_Word32 Atomic32Wrapper::operator--() -{ - return --_impl; -} - -// Read and write to properly aligned variables are atomic operations. -// Ex reference (for Windows): http://msdn.microsoft.com/en-us/library/ms684122(v=VS.85).aspx -// TODO (hellner) operator= and Atomic32Wrapper::Value() can be fully -// implemented here. -Atomic32Wrapper& Atomic32Wrapper::operator=(const Atomic32Wrapper& rhs) -{ - if(this == &rhs) - { - return *this; - } - _impl = rhs._impl; - return *this; -} - -Atomic32Wrapper& Atomic32Wrapper::operator=(WebRtc_Word32 rhs) -{ - _impl = rhs; - return *this; -} - -WebRtc_Word32 Atomic32Wrapper::operator+=(WebRtc_Word32 rhs) -{ - return _impl += rhs; -} - -WebRtc_Word32 Atomic32Wrapper::operator-=(WebRtc_Word32 rhs) -{ - return _impl -= rhs; -} - -bool Atomic32Wrapper::CompareExchange(WebRtc_Word32 newValue, - WebRtc_Word32 compareValue) -{ - return _impl.CompareExchange(newValue,compareValue); -} - -WebRtc_Word32 Atomic32Wrapper::Value() const -{ - return _impl.Value(); -} -} // namespace webrtc diff --git a/src/system_wrappers/source/atomic32_linux.h b/src/system_wrappers/source/atomic32_linux.h deleted file mode 100644 index f9f5650f2a..0000000000 --- a/src/system_wrappers/source/atomic32_linux.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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. - */ - -// Atomic system independant 32-bit signed integer. -// Linux implementation. -// Note: Requires gcc 4.1.2 or later. -#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_ATOMIC32_LINUX_H_ -#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_ATOMIC32_LINUX_H_ - -#include <inttypes.h> -#include <malloc.h> - -#include "common_types.h" - -namespace webrtc { -class Atomic32Impl -{ -public: - inline Atomic32Impl(WebRtc_Word32 initialValue); - inline ~Atomic32Impl(); - - inline WebRtc_Word32 operator++(); - inline WebRtc_Word32 operator--(); - - inline Atomic32Impl& operator=(const Atomic32Impl& rhs); - inline Atomic32Impl& operator=(WebRtc_Word32 rhs); - inline WebRtc_Word32 operator+=(WebRtc_Word32 rhs); - inline WebRtc_Word32 operator-=(WebRtc_Word32 rhs); - - inline bool CompareExchange(WebRtc_Word32 newValue, - WebRtc_Word32 compareValue); - - inline WebRtc_Word32 Value() const; -private: - void* _ptrMemory; - // Volatile ensures full memory barriers. - volatile WebRtc_Word32* _value; -}; - -// TODO (hellner) use aligned_malloc instead of doing it manually. -inline Atomic32Impl::Atomic32Impl(WebRtc_Word32 initialValue) - : _ptrMemory(NULL), - _value(NULL) -{ // Align the memory associated with _value on a 32-bit boundary. This is a - // requirement for the used Linux APIs to be atomic. - // Keep _ptrMemory to be able to reclaim memory. - _ptrMemory = malloc(sizeof(WebRtc_Word32)*2); - _value = (WebRtc_Word32*) (((uintptr_t)_ptrMemory+3)&(~0x3)); - *_value = initialValue; -} - -inline Atomic32Impl::~Atomic32Impl() -{ - if(_ptrMemory != NULL) - { - free(_ptrMemory); - } -} - -inline WebRtc_Word32 Atomic32Impl::operator++() -{ - WebRtc_Word32 returnValue = __sync_fetch_and_add(_value,1); - returnValue++; - return returnValue; -} - -inline WebRtc_Word32 Atomic32Impl::operator--() -{ - WebRtc_Word32 returnValue = __sync_fetch_and_sub(_value,1); - returnValue--; - return returnValue; -} - -inline Atomic32Impl& Atomic32Impl::operator=(const Atomic32Impl& rhs) -{ - *_value = *rhs._value; - return *this; -} - -inline Atomic32Impl& Atomic32Impl::operator=(WebRtc_Word32 rhs) -{ - *_value = rhs; - return *this; -} - -inline WebRtc_Word32 Atomic32Impl::operator+=(WebRtc_Word32 rhs) -{ - WebRtc_Word32 returnValue = __sync_fetch_and_add(_value,rhs); - returnValue += rhs; - return returnValue; -} - -inline WebRtc_Word32 Atomic32Impl::operator-=(WebRtc_Word32 rhs) -{ - WebRtc_Word32 returnValue = __sync_fetch_and_sub(_value,rhs); - returnValue -= rhs; - return returnValue; -} - -inline bool Atomic32Impl::CompareExchange(WebRtc_Word32 newValue, - WebRtc_Word32 compareValue) -{ - return __sync_bool_compare_and_swap(_value,compareValue,newValue); -} - -inline WebRtc_Word32 Atomic32Impl::Value() const -{ - return *_value; -} -} // namespace webrtc - -#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_ATOMIC32_LINUX_H_ diff --git a/src/system_wrappers/source/atomic32_mac.cc b/src/system_wrappers/source/atomic32_mac.cc new file mode 100644 index 0000000000..9a493b580c --- /dev/null +++ b/src/system_wrappers/source/atomic32_mac.cc @@ -0,0 +1,60 @@ +/* + * 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 "atomic32.h" + +#include <assert.h> +#include <libkern/OSAtomic.h> +#include <stdlib.h> + +#include "common_types.h" + +namespace webrtc { + +Atomic32::Atomic32(WebRtc_Word32 initialValue) : _value(initialValue) +{ + assert(Is32bitAligned()); +} + +Atomic32::~Atomic32() +{ +} + +WebRtc_Word32 Atomic32::operator++() +{ + return OSAtomicIncrement32Barrier(&_value); +} + +WebRtc_Word32 Atomic32::operator--() +{ + return OSAtomicDecrement32Barrier(&_value); +} + +WebRtc_Word32 Atomic32::operator+=(WebRtc_Word32 value) +{ + return OSAtomicAdd32Barrier(value, &_value); +} + +WebRtc_Word32 Atomic32::operator-=(WebRtc_Word32 value) +{ + return OSAtomicAdd32Barrier(-value, &_value); +} + +bool Atomic32::CompareExchange(WebRtc_Word32 newValue, + WebRtc_Word32 compareValue) +{ + return OSAtomicCompareAndSwap32Barrier(compareValue, newValue, &_value); +} + +WebRtc_Word32 Atomic32::Value() const +{ + return _value; +} +} // namespace webrtc diff --git a/src/system_wrappers/source/atomic32_mac.h b/src/system_wrappers/source/atomic32_mac.h deleted file mode 100644 index bf8febcdb5..0000000000 --- a/src/system_wrappers/source/atomic32_mac.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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. - */ - -// Atomic system independant 32-bit signed integer. -// Mac implementation. -#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_ATOMIC32_MAC_H_ -#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_ATOMIC32_MAC_H_ - -#include <stdlib.h> -#include <libkern/OSAtomic.h> - -#include "common_types.h" - -namespace webrtc { -class Atomic32Impl -{ -public: - inline Atomic32Impl(WebRtc_Word32 initialValue); - inline ~Atomic32Impl(); - - inline WebRtc_Word32 operator++(); - inline WebRtc_Word32 operator--(); - - inline Atomic32Impl& operator=(const Atomic32Impl& rhs); - inline Atomic32Impl& operator=(WebRtc_Word32 rhs); - inline WebRtc_Word32 operator+=(WebRtc_Word32 rhs); - inline WebRtc_Word32 operator-=(WebRtc_Word32 rhs); - - inline bool CompareExchange(WebRtc_Word32 newValue, - WebRtc_Word32 compareValue); - - inline WebRtc_Word32 Value() const; -private: - void* _ptrMemory; - // Volatile ensures full memory barriers. - volatile WebRtc_Word32* _value; -}; - -// TODO (hellner) use aligned_malloc instead of doing it manually. -inline Atomic32Impl::Atomic32Impl(WebRtc_Word32 initialValue) - : - _ptrMemory(NULL), - _value(NULL) -{ // Align the memory associated with _value on a 32-bit boundary. This is a - // requirement for the used Mac APIs to be atomic. - // Keep _ptrMemory to be able to reclaim memory. - _ptrMemory = malloc(sizeof(WebRtc_Word32)*2); - _value = (WebRtc_Word32*) (((uintptr_t)_ptrMemory+3)&(~0x3)); - *_value = initialValue; -} - -inline Atomic32Impl::~Atomic32Impl() -{ - if(_ptrMemory != NULL) - { - free(_ptrMemory); - } -} - -inline WebRtc_Word32 Atomic32Impl::operator++() -{ - return OSAtomicIncrement32Barrier( - reinterpret_cast<volatile int32_t*>(_value)); -} - -inline WebRtc_Word32 Atomic32Impl::operator--() -{ - return OSAtomicDecrement32Barrier( - reinterpret_cast<volatile int32_t*>(_value)); -} - -inline Atomic32Impl& Atomic32Impl::operator=(const Atomic32Impl& rhs) -{ - *_value = *rhs._value; - return *this; -} - -inline Atomic32Impl& Atomic32Impl::operator=(WebRtc_Word32 rhs) -{ - *_value = rhs; - return *this; -} - -inline WebRtc_Word32 Atomic32Impl::operator+=(WebRtc_Word32 rhs) -{ - return OSAtomicAdd32Barrier(rhs, - reinterpret_cast<volatile int32_t*>(_value)); -} - -inline WebRtc_Word32 Atomic32Impl::operator-=(WebRtc_Word32 rhs) -{ - return OSAtomicAdd32Barrier(-rhs, - reinterpret_cast<volatile int32_t*>(_value)); -} - -inline bool Atomic32Impl::CompareExchange(WebRtc_Word32 newValue, - WebRtc_Word32 compareValue) -{ - return OSAtomicCompareAndSwap32Barrier( - compareValue, - newValue, - reinterpret_cast<volatile int32_t*>(_value)); -} - -inline WebRtc_Word32 Atomic32Impl::Value() const -{ - return *_value; -} -} // namespace webrtc -#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_ATOMIC32_MAC_H_ diff --git a/src/system_wrappers/source/atomic32_posix.cc b/src/system_wrappers/source/atomic32_posix.cc new file mode 100644 index 0000000000..05b0e57456 --- /dev/null +++ b/src/system_wrappers/source/atomic32_posix.cc @@ -0,0 +1,64 @@ +/* + * 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 "atomic32.h" + +#include <assert.h> +#include <inttypes.h> +#include <malloc.h> + +#include "common_types.h" + +namespace webrtc { + +Atomic32::Atomic32(WebRtc_Word32 initialValue) : _value(initialValue) +{ + assert(Is32bitAligned()); +} + +Atomic32::~Atomic32() +{ +} + +WebRtc_Word32 Atomic32::operator++() +{ + return __sync_fetch_and_add(&_value, 1) + 1; +} + +WebRtc_Word32 Atomic32::operator--() +{ + return __sync_fetch_and_sub(&_value, 1) - 1; +} + +WebRtc_Word32 Atomic32::operator+=(WebRtc_Word32 value) +{ + WebRtc_Word32 returnValue = __sync_fetch_and_add(&_value, value); + returnValue += value; + return returnValue; +} + +WebRtc_Word32 Atomic32::operator-=(WebRtc_Word32 value) +{ + WebRtc_Word32 returnValue = __sync_fetch_and_sub(&_value, value); + returnValue -= value; + return returnValue; +} + +bool Atomic32::CompareExchange(WebRtc_Word32 newValue, + WebRtc_Word32 compareValue) +{ + return __sync_bool_compare_and_swap(&_value, compareValue, newValue); +} + +WebRtc_Word32 Atomic32::Value() const +{ + return _value; +} +} // namespace webrtc diff --git a/src/system_wrappers/source/atomic32_win.cc b/src/system_wrappers/source/atomic32_win.cc new file mode 100644 index 0000000000..2fa9d3dd59 --- /dev/null +++ b/src/system_wrappers/source/atomic32_win.cc @@ -0,0 +1,72 @@ +/* + * 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 "atomic32.h" + +#include <assert.h> +#include <windows.h> + +#include "common_types.h" +#include "compile_assert.h" + +namespace webrtc { + +Atomic32::Atomic32(WebRtc_Word32 initialValue) : _value(initialValue) +{ + // Make sure that the counter variable we're using is of the same size + // as what the API expects. + COMPILE_ASSERT(sizeof(_value) == sizeof(LONG)); + assert(Is32bitAligned()); +} + +Atomic32::~Atomic32() +{ +} + +WebRtc_Word32 Atomic32::operator++() +{ + return static_cast<WebRtc_Word32>(InterlockedIncrement( + reinterpret_cast<volatile LONG*>(&_value))); +} + +WebRtc_Word32 Atomic32::operator--() +{ + return static_cast<WebRtc_Word32>(InterlockedDecrement( + reinterpret_cast<volatile LONG*>(&_value))); +} + +WebRtc_Word32 Atomic32::operator+=(WebRtc_Word32 value) +{ + return InterlockedExchangeAdd(reinterpret_cast<volatile LONG*>(&_value), + value); +} + +WebRtc_Word32 Atomic32::operator-=(WebRtc_Word32 value) +{ + return InterlockedExchangeAdd(reinterpret_cast<volatile LONG*>(&_value), + -value); +} + +bool Atomic32::CompareExchange(WebRtc_Word32 newValue, + WebRtc_Word32 compareValue) +{ + const LONG oldValue = InterlockedCompareExchange( + reinterpret_cast<volatile LONG*>(&_value), + newValue, + compareValue); + // If the old value and the compare value is the same an exchange happened. + return (oldValue == compareValue); +} + +WebRtc_Word32 Atomic32::Value() const +{ + return _value; +} +} // namespace webrtc diff --git a/src/system_wrappers/source/condition_variable_unittest.cc b/src/system_wrappers/source/condition_variable_unittest.cc new file mode 100644 index 0000000000..a9fdd0d24e --- /dev/null +++ b/src/system_wrappers/source/condition_variable_unittest.cc @@ -0,0 +1,208 @@ +/* + * 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 "system_wrappers/interface/condition_variable_wrapper.h" + +#include "gtest/gtest.h" +#include "system_wrappers/interface/critical_section_wrapper.h" +#include "system_wrappers/interface/thread_wrapper.h" +#include "system_wrappers/interface/trace.h" +#include "system_wrappers/source/unittest_utilities.h" + +namespace webrtc { + +namespace { + +const int kLogTrace = false; // Set to true to enable debug logging to stdout. +const int kLongWaitMs = 100*1000; // A long time in testing terms +const int kShortWaitMs = 2*1000; // Long enough for process switches to happen + +#define LOG(...) WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, __VA_ARGS__); + +// A Baton is one possible control structure one can build using +// conditional variables. +// A Baton is always held by one and only one active thread - unlike +// a lock, it can never be free. +// One can pass it or grab it - both calls have timeouts. +// Note - a production tool would guard against passing it without +// grabbing it first. This one is for testing, so it doesn't. +class Baton { + public: + Baton() + : giver_sect_(CriticalSectionWrapper::CreateCriticalSection()), + crit_sect_(CriticalSectionWrapper::CreateCriticalSection()), + cond_var_(ConditionVariableWrapper::CreateConditionVariable()), + being_passed_(false), + pass_count_(0) { + } + + ~Baton() { + delete giver_sect_; + delete crit_sect_; + delete cond_var_; + } + + // Pass the baton. Returns false if baton is not picked up in |max_msecs|. + // Only one process can pass at the same time; this property is + // ensured by the |giver_sect_| lock. + bool Pass(WebRtc_UWord32 max_msecs) { + LOG("Locking giver_sect"); + CriticalSectionScoped cs_giver(giver_sect_); + LOG("Locked giver_sect, locking crit_sect"); + CriticalSectionScoped cs(crit_sect_); + SignalBatonAvailable(); + const bool result = TakeBatonIfStillFree(max_msecs); + if (result) { + ++pass_count_; + LOG("Pass count is %d", pass_count_); + } + return result; + } + + // Grab the baton. Returns false if baton is not passed. + bool Grab(WebRtc_UWord32 max_msecs) { + CriticalSectionScoped cs(crit_sect_); + return WaitUntilBatonOffered(max_msecs); + } + + int PassCount() { + // We don't allow polling PassCount() during a Pass()-call since there is + // no guarantee that |pass_count_| is incremented until the Pass()-call + // finishes. I.e. the Grab()-call may finish before |pass_count_| has been + // incremented. + // Thus, this function waits on giver_sect_. + CriticalSectionScoped cs(giver_sect_); + return pass_count_; + } + + private: + // Wait/Signal forms a classical semaphore on |being_passed_|. + // These functions must be called with crit_sect_ held. + bool WaitUntilBatonOffered(int timeout_ms) { + while (!being_passed_) { + LOG("Wait waiting"); + if (!cond_var_->SleepCS(*crit_sect_, timeout_ms)) { + LOG("Wait timeout"); + return false; + } + } + being_passed_ = false; + cond_var_->Wake(); + return true; + } + + void SignalBatonAvailable() { + assert(!being_passed_); + being_passed_ = true; + LOG("Signal waking"); + cond_var_->Wake(); + } + + // Timeout extension: Wait for a limited time for someone else to + // take it, and take it if it's not taken. + // Returns true if resource is taken by someone else, false + // if it is taken back by the caller. + // This function must be called with both |giver_sect_| and + // |crit_sect_| held. + bool TakeBatonIfStillFree(int timeout_ms) { + bool not_timeout = true; + while (being_passed_ && not_timeout) { + LOG("Takeback waiting"); + not_timeout = cond_var_->SleepCS(*crit_sect_, timeout_ms); + // If we're woken up while variable is still held, we may have + // gotten a wakeup destined for a grabber thread. + // This situation is not treated specially here. + } + if (!being_passed_) { + return true; + } else { + LOG("Takeback grab"); + assert(!not_timeout); + being_passed_ = false; + return false; + } + } + + // Lock that ensures that there is only one thread in the active + // part of Pass() at a time. + // |giver_sect_| must always be acquired before |cond_var_|. + CriticalSectionWrapper* giver_sect_; + // Lock that protects |being_passed_|. + CriticalSectionWrapper* crit_sect_; + ConditionVariableWrapper* cond_var_; + bool being_passed_; + // Statistics information: Number of successfull passes. + int pass_count_; +}; + +// Function that waits on a Baton, and passes it right back. +// We expect these calls never to time out. +bool WaitingRunFunction(void* obj) { + Baton* the_baton = static_cast<Baton*> (obj); + LOG("Thread waiting"); + EXPECT_TRUE(the_baton->Grab(kLongWaitMs)); + LOG("Thread waking parent"); + EXPECT_TRUE(the_baton->Pass(kLongWaitMs)); + return true; +} + +class CondVarTest : public ::testing::Test { + public: + CondVarTest() + : trace_(kLogTrace) { + } + + virtual void SetUp() { + thread_ = ThreadWrapper::CreateThread(&WaitingRunFunction, + &baton_); + unsigned int id = 42; + ASSERT_TRUE(thread_->Start(id)); + } + + virtual void TearDown() { + // We have to wake the thread in order to make it obey the stop order. + // But we don't know if the thread has completed the run function, so + // we don't know if it will exit before or after the Pass. + // Thus, we need to pin it down inside its Run function (between Grab + // and Pass). + ASSERT_TRUE(baton_.Pass(kShortWaitMs)); + thread_->SetNotAlive(); + ASSERT_TRUE(baton_.Grab(kShortWaitMs)); + ASSERT_TRUE(thread_->Stop()); + delete thread_; + } + + protected: + Baton baton_; + + private: + ScopedTracing trace_; + ThreadWrapper* thread_; +}; + +// The SetUp and TearDown functions use condition variables. +// This test verifies those pieces in isolation. +TEST_F(CondVarTest, InitFunctionsWork) { + // All relevant asserts are in the SetUp and TearDown functions. +} + +// This test verifies that one can use the baton multiple times. +TEST_F(CondVarTest, PassBatonMultipleTimes) { + const int kNumberOfRounds = 2; + for (int i = 0; i < kNumberOfRounds; ++i) { + ASSERT_TRUE(baton_.Pass(kShortWaitMs)); + ASSERT_TRUE(baton_.Grab(kShortWaitMs)); + } + EXPECT_EQ(2*kNumberOfRounds, baton_.PassCount()); +} + +} // anonymous namespace + +} // namespace webrtc diff --git a/src/system_wrappers/source/condition_variable_win.cc b/src/system_wrappers/source/condition_variable_win.cc new file mode 100644 index 0000000000..f4fae0b75f --- /dev/null +++ b/src/system_wrappers/source/condition_variable_win.cc @@ -0,0 +1,224 @@ +/* + * Use of this source code is governed by the ACE copyright license which + * can be found in the LICENSE file in the third_party_mods/ace directory of + * the source tree or at http://www1.cse.wustl.edu/~schmidt/ACE-copying.html. + */ +/* + * This source code contain modifications to the original source code + * which can be found here: + * http://www.cs.wustl.edu/~schmidt/win32-cv-1.html (section 3.2). + * Modifications: + * 1) Dynamic detection of native support for condition variables. + * 2) Use of WebRTC defined types and classes. Renaming of some functions. + * 3) Introduction of a second event for wake all functionality. This prevents + * a thread from spinning on the same condition variable, preventing other + * threads from waking up. + */ + +// TODO (hellner): probably nicer to split up native and generic +// implementation into two different files + +#include "condition_variable_win.h" + +#include "critical_section_win.h" +#include "trace.h" + +namespace webrtc { +bool ConditionVariableWindows::_winSupportConditionVariablesPrimitive = false; +static HMODULE library = NULL; + +PInitializeConditionVariable _PInitializeConditionVariable; +PSleepConditionVariableCS _PSleepConditionVariableCS; +PWakeConditionVariable _PWakeConditionVariable; +PWakeAllConditionVariable _PWakeAllConditionVariable; + +typedef void (WINAPI *PInitializeConditionVariable)(PCONDITION_VARIABLE); +typedef BOOL (WINAPI *PSleepConditionVariableCS)(PCONDITION_VARIABLE, + PCRITICAL_SECTION, DWORD); +typedef void (WINAPI *PWakeConditionVariable)(PCONDITION_VARIABLE); +typedef void (WINAPI *PWakeAllConditionVariable)(PCONDITION_VARIABLE); + +ConditionVariableWindows::ConditionVariableWindows() + : _eventID(WAKEALL_0) +{ + if (!library) + { + // Use native implementation if supported (i.e Vista+) + library = LoadLibrary(TEXT("Kernel32.dll")); + if (library) + { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, + "Loaded Kernel.dll"); + + _PInitializeConditionVariable = + (PInitializeConditionVariable) GetProcAddress( + library, + "InitializeConditionVariable"); + _PSleepConditionVariableCS = + (PSleepConditionVariableCS)GetProcAddress( + library, + "SleepConditionVariableCS"); + _PWakeConditionVariable = + (PWakeConditionVariable)GetProcAddress( + library, + "WakeConditionVariable"); + _PWakeAllConditionVariable = + (PWakeAllConditionVariable)GetProcAddress( + library, + "WakeAllConditionVariable"); + + if(_PInitializeConditionVariable && + _PSleepConditionVariableCS && + _PWakeConditionVariable && + _PWakeAllConditionVariable) + { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, + "Loaded native condition variables"); + _winSupportConditionVariablesPrimitive = true; + } + } + } + + if (_winSupportConditionVariablesPrimitive) + { + _PInitializeConditionVariable(&_conditionVariable); + + _events[WAKEALL_0] = NULL; + _events[WAKEALL_1] = NULL; + _events[WAKE] = NULL; + + } else { + memset(&_numWaiters[0],0,sizeof(_numWaiters)); + + InitializeCriticalSection(&_numWaitersCritSect); + + _events[WAKEALL_0] = CreateEvent(NULL, // no security attributes + TRUE, // manual-reset, sticky event + FALSE, // initial state non-signaled + NULL); // no name for event + + _events[WAKEALL_1] = CreateEvent(NULL, // no security attributes + TRUE, // manual-reset, sticky event + FALSE, // initial state non-signaled + NULL); // no name for event + + _events[WAKE] = CreateEvent(NULL, // no security attributes + FALSE, // auto-reset, sticky event + FALSE, // initial state non-signaled + NULL); // no name for event + } +} + +ConditionVariableWindows::~ConditionVariableWindows() +{ + if(!_winSupportConditionVariablesPrimitive) + { + CloseHandle(_events[WAKE]); + CloseHandle(_events[WAKEALL_1]); + CloseHandle(_events[WAKEALL_0]); + + DeleteCriticalSection(&_numWaitersCritSect); + } +} + +void ConditionVariableWindows::SleepCS(CriticalSectionWrapper& critSect) +{ + SleepCS(critSect, INFINITE); +} + +bool ConditionVariableWindows::SleepCS(CriticalSectionWrapper& critSect, + unsigned long maxTimeInMS) +{ + CriticalSectionWindows* cs = reinterpret_cast<CriticalSectionWindows*>( + &critSect); + + if(_winSupportConditionVariablesPrimitive) + { + BOOL retVal = _PSleepConditionVariableCS(&_conditionVariable, + &(cs->crit),maxTimeInMS); + return (retVal == 0) ? false : true; + + }else + { + EnterCriticalSection(&_numWaitersCritSect); + // Get the eventID for the event that will be triggered by next + // WakeAll() call and start waiting for it. + const EventWakeUpType eventID = (WAKEALL_0 == _eventID) ? + WAKEALL_1 : WAKEALL_0; + ++(_numWaiters[eventID]); + LeaveCriticalSection(&_numWaitersCritSect); + + LeaveCriticalSection(&cs->crit); + HANDLE events[2]; + events[0] = _events[WAKE]; + events[1] = _events[eventID]; + const DWORD result = WaitForMultipleObjects(2, // Wait on 2 events. + events, + FALSE, // Wait for either. + maxTimeInMS); + + const bool retVal = (result != WAIT_TIMEOUT); + + EnterCriticalSection(&_numWaitersCritSect); + --(_numWaiters[eventID]); + // Last waiter should only be true for WakeAll(). WakeAll() correspond + // to position 1 in events[] -> (result == WAIT_OBJECT_0 + 1) + const bool lastWaiter = (result == WAIT_OBJECT_0 + 1) && + (_numWaiters[eventID] == 0); + LeaveCriticalSection(&_numWaitersCritSect); + + if (lastWaiter) + { + // Reset/unset the WakeAll() event since all threads have been + // released. + ResetEvent(_events[eventID]); + } + + EnterCriticalSection(&cs->crit); + return retVal; + } +} + +void +ConditionVariableWindows::Wake() +{ + if(_winSupportConditionVariablesPrimitive) + { + _PWakeConditionVariable(&_conditionVariable); + }else + { + EnterCriticalSection(&_numWaitersCritSect); + const bool haveWaiters = (_numWaiters[WAKEALL_0] > 0) || + (_numWaiters[WAKEALL_1] > 0); + LeaveCriticalSection(&_numWaitersCritSect); + + if (haveWaiters) + { + SetEvent(_events[WAKE]); + } + } +} + +void +ConditionVariableWindows::WakeAll() +{ + if(_winSupportConditionVariablesPrimitive) + { + _PWakeAllConditionVariable(&_conditionVariable); + }else + { + EnterCriticalSection(&_numWaitersCritSect); + // Update current WakeAll() event + _eventID = (WAKEALL_0 == _eventID) ? WAKEALL_1 : WAKEALL_0; + // Trigger current event + const EventWakeUpType eventID = _eventID; + const bool haveWaiters = _numWaiters[eventID] > 0; + LeaveCriticalSection(&_numWaitersCritSect); + + if (haveWaiters) + { + SetEvent(_events[eventID]); + } + } +} +} // namespace webrtc diff --git a/src/system_wrappers/source/condition_variable_win.h b/src/system_wrappers/source/condition_variable_win.h new file mode 100644 index 0000000000..aab2564dd1 --- /dev/null +++ b/src/system_wrappers/source/condition_variable_win.h @@ -0,0 +1,67 @@ +/* + * 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_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_WINDOWS_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_WINDOWS_H_ + +#include "condition_variable_wrapper.h" + +#include <windows.h> + +namespace webrtc { +#if !defined CONDITION_VARIABLE_INIT + typedef struct _RTL_CONDITION_VARIABLE + { + void* Ptr; + } RTL_CONDITION_VARIABLE, *PRTL_CONDITION_VARIABLE; + + typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE; +#endif + +typedef void (WINAPI *PInitializeConditionVariable)(PCONDITION_VARIABLE); +typedef BOOL (WINAPI *PSleepConditionVariableCS)(PCONDITION_VARIABLE, + PCRITICAL_SECTION, DWORD); +typedef void (WINAPI *PWakeConditionVariable)(PCONDITION_VARIABLE); +typedef void (WINAPI *PWakeAllConditionVariable)(PCONDITION_VARIABLE); + + +class ConditionVariableWindows : public ConditionVariableWrapper +{ +public: + ConditionVariableWindows(); + ~ConditionVariableWindows(); + + void SleepCS(CriticalSectionWrapper& critSect); + bool SleepCS(CriticalSectionWrapper& critSect, unsigned long maxTimeInMS); + void Wake(); + void WakeAll(); + +private: + enum EventWakeUpType + { + WAKEALL_0 = 0, + WAKEALL_1 = 1, + WAKE = 2, + EVENT_COUNT = 3 + }; + +private: + // Native support for Windows Vista+ + static bool _winSupportConditionVariablesPrimitive; + CONDITION_VARIABLE _conditionVariable; + + unsigned int _numWaiters[2]; + EventWakeUpType _eventID; + CRITICAL_SECTION _numWaitersCritSect; + HANDLE _events[EVENT_COUNT]; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CONDITION_VARIABLE_WINDOWS_H_ diff --git a/src/system_wrappers/source/cpu_features_android.c b/src/system_wrappers/source/cpu_features_android.c new file mode 100644 index 0000000000..7a4fa6ef20 --- /dev/null +++ b/src/system_wrappers/source/cpu_features_android.c @@ -0,0 +1,15 @@ +/* + * 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 "android/cpu-features.h" + +uint64_t WebRtc_GetCPUFeaturesARM(void) { + return android_getCpuFeatures(); +} diff --git a/src/system_wrappers/source/cpu_features_arm.c b/src/system_wrappers/source/cpu_features_arm.c deleted file mode 100644 index 106511852c..0000000000 --- a/src/system_wrappers/source/cpu_features_arm.c +++ /dev/null @@ -1,333 +0,0 @@ -/* - * 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. - */ - -// This file is derived from Android's NDK package r7, located at -// <ndk>/sources/android/cpufeatures/ (downloadable from -// http://developer.android.com/sdk/ndk/index.html). - -#include "cpu_features_wrapper.h" - -#include <fcntl.h> -#include <errno.h> -#include <pthread.h> -#include <stdio.h> -#include <stdlib.h> - -// Define CPU family. -typedef enum { - CPU_FAMILY_UNKNOWN = 0, - CPU_FAMILY_ARM, - CPU_FAMILY_X86, - CPU_FAMILY_MAX // Do not remove. -} CpuFamily; - -static pthread_once_t g_once; -static CpuFamily g_cpuFamily; -static uint64_t g_cpuFeatures; -static int g_cpuCount; - -static const int cpufeatures_debug = 0; - -#ifdef __arm__ -# define DEFAULT_CPU_FAMILY CPU_FAMILY_ARM -#elif defined __i386__ -# define DEFAULT_CPU_FAMILY CPU_FAMILY_X86 -#else -# define DEFAULT_CPU_FAMILY CPU_FAMILY_UNKNOWN -#endif - -#define D(...) \ - do { \ - if (cpufeatures_debug) { \ - printf(__VA_ARGS__); fflush(stdout); \ - } \ - } while (0) - -/* Read the content of /proc/cpuinfo into a user-provided buffer. - * Return the length of the data, or -1 on error. Does *not* - * zero-terminate the content. Will not read more - * than 'buffsize' bytes. - */ -static int read_file(const char* pathname, char* buffer, size_t buffsize) { - int fd, len; - - fd = open(pathname, O_RDONLY); - if (fd < 0) - return -1; - - do { - len = read(fd, buffer, buffsize); - } while (len < 0 && errno == EINTR); - - close(fd); - - return len; -} - -/* Extract the content of a the first occurence of a given field in - * the content of /proc/cpuinfo and return it as a heap-allocated - * string that must be freed by the caller. - * - * Return NULL if not found - */ -static char* extract_cpuinfo_field(char* buffer, int buflen, const char* field) { - int fieldlen = strlen(field); - char* bufend = buffer + buflen; - char* result = NULL; - int len, ignore; - const char* p, *q; - - /* Look for first field occurence, and ensures it starts the line. - */ - p = buffer; - bufend = buffer + buflen; - for (;;) { - p = memmem(p, bufend - p, field, fieldlen); - if (p == NULL) - goto EXIT; - - if (p == buffer || p[-1] == '\n') - break; - - p += fieldlen; - } - - /* Skip to the first column followed by a space */ - p += fieldlen; - p = memchr(p, ':', bufend - p); - if (p == NULL || p[1] != ' ') - goto EXIT; - - /* Find the end of the line */ - p += 2; - q = memchr(p, '\n', bufend - p); - if (q == NULL) - q = bufend; - - /* Copy the line into a heap-allocated buffer */ - len = q - p; - result = malloc(len + 1); - if (result == NULL) - goto EXIT; - - memcpy(result, p, len); - result[len] = '\0'; - -EXIT: - return result; -} - -/* Count the number of occurences of a given field prefix in /proc/cpuinfo. - */ -static int count_cpuinfo_field(char* buffer, int buflen, const char* field) { - int fieldlen = strlen(field); - const char* p = buffer; - const char* bufend = buffer + buflen; - const char* q; - int count = 0; - - for (;;) { - const char* q; - - p = memmem(p, bufend - p, field, fieldlen); - if (p == NULL) - break; - - /* Ensure that the field is at the start of a line */ - if (p > buffer && p[-1] != '\n') { - p += fieldlen; - continue; - } - - - /* skip any whitespace */ - q = p + fieldlen; - while (q < bufend && (*q == ' ' || *q == '\t')) - q++; - - /* we must have a colon now */ - if (q < bufend && *q == ':') { - count += 1; - q ++; - } - p = q; - } - - return count; -} - -/* Like strlen(), but for constant string literals */ -#define STRLEN_CONST(x) ((sizeof(x)-1) - - -/* Checks that a space-separated list of items contains one given 'item'. - * Returns 1 if found, 0 otherwise. - */ -static int has_list_item(const char* list, const char* item) { - const char* p = list; - int itemlen = strlen(item); - - if (list == NULL) - return 0; - - while (*p) { - const char* q; - - /* skip spaces */ - while (*p == ' ' || *p == '\t') - p++; - - /* find end of current list item */ - q = p; - while (*q && *q != ' ' && *q != '\t') - q++; - - if (itemlen == q - p && !memcmp(p, item, itemlen)) - return 1; - - /* skip to next item */ - p = q; - } - return 0; -} - - -static void cpuInit(void) { - char cpuinfo[4096]; - int cpuinfo_len; - - g_cpuFamily = DEFAULT_CPU_FAMILY; - g_cpuFeatures = 0; - g_cpuCount = 1; - - cpuinfo_len = read_file("/proc/cpuinfo", cpuinfo, sizeof cpuinfo); - D("cpuinfo_len is (%d):\n%.*s\n", cpuinfo_len, - cpuinfo_len >= 0 ? cpuinfo_len : 0, cpuinfo); - - if (cpuinfo_len < 0) { /* should not happen */ - return; - } - - /* Count the CPU cores, the value may be 0 for single-core CPUs */ - g_cpuCount = count_cpuinfo_field(cpuinfo, cpuinfo_len, "processor"); - if (g_cpuCount == 0) { - g_cpuCount = count_cpuinfo_field(cpuinfo, cpuinfo_len, "Processor"); - if (g_cpuCount == 0) { - g_cpuCount = 1; - } - } - - D("found cpuCount = %d\n", g_cpuCount); - -#ifdef __arm__ - { - char* features = NULL; - char* architecture = NULL; - - /* Extract architecture from the "CPU Architecture" field. - * The list is well-known, unlike the the output of - * the 'Processor' field which can vary greatly. - * - * See the definition of the 'proc_arch' array in - * $KERNEL/arch/arm/kernel/setup.c and the 'c_show' function in - * same file. - */ - char* cpuArch = extract_cpuinfo_field(cpuinfo, cpuinfo_len, - "CPU architecture"); - - if (cpuArch != NULL) { - char* end; - long archNumber; - int hasARMv7 = 0; - - D("found cpuArch = '%s'\n", cpuArch); - - /* read the initial decimal number, ignore the rest */ - archNumber = strtol(cpuArch, &end, 10); - - /* Here we assume that ARMv8 will be upwards compatible with v7 - * in the future. Unfortunately, there is no 'Features' field to - * indicate that Thumb-2 is supported. - */ - if (end > cpuArch && archNumber >= 7) { - hasARMv7 = 1; - } - - /* Unfortunately, it seems that certain ARMv6-based CPUs - * report an incorrect architecture number of 7! - * - * We try to correct this by looking at the 'elf_format' - * field reported by the 'Processor' field, which is of the - * form of "(v7l)" for an ARMv7-based CPU, and "(v6l)" for - * an ARMv6-one. - */ - if (hasARMv7) { - char* cpuProc = extract_cpuinfo_field(cpuinfo, cpuinfo_len, - "Processor"); - if (cpuProc != NULL) { - D("found cpuProc = '%s'\n", cpuProc); - if (has_list_item(cpuProc, "(v6l)")) { - D("CPU processor and architecture mismatch!!\n"); - hasARMv7 = 0; - } - free(cpuProc); - } - } - - if (hasARMv7) { - g_cpuFeatures |= kCPUFeatureARMv7; - } - - /* The LDREX / STREX instructions are available from ARMv6 */ - if (archNumber >= 6) { - g_cpuFeatures |= kCPUFeatureLDREXSTREX; - } - - free(cpuArch); - } - - /* Extract the list of CPU features from 'Features' field */ - char* cpuFeatures = extract_cpuinfo_field(cpuinfo, cpuinfo_len, - "Features"); - - if (cpuFeatures != NULL) { - - D("found cpuFeatures = '%s'\n", cpuFeatures); - - if (has_list_item(cpuFeatures, "vfpv3")) - g_cpuFeatures |= kCPUFeatureVFPv3; - - else if (has_list_item(cpuFeatures, "vfpv3d16")) - g_cpuFeatures |= kCPUFeatureVFPv3; - - if (has_list_item(cpuFeatures, "neon")) { - /* Note: Certain kernels only report neon but not vfpv3 - * in their features list. However, ARM mandates - * that if Neon is implemented, so must be VFPv3 - * so always set the flag. - */ - g_cpuFeatures |= kCPUFeatureNEON | - kCPUFeatureVFPv3; - } - free(cpuFeatures); - } - } -#endif // __arm__ - -#ifdef __i386__ - g_cpuFamily = CPU_FAMILY_X86; -#endif -} - - -uint64_t WebRtc_GetCPUFeaturesARM(void) { - pthread_once(&g_once, cpuInit); - return g_cpuFeatures; -} diff --git a/src/system_wrappers/source/cpu_linux.cc b/src/system_wrappers/source/cpu_linux.cc index 9d7d89de64..8e8ecda6ca 100644 --- a/src/system_wrappers/source/cpu_linux.cc +++ b/src/system_wrappers/source/cpu_linux.cc @@ -179,6 +179,7 @@ int CpuLinux::GetNumCores() char line[100]; if (!fgets(line, 100, fp)) { + fclose(fp); return -1; } int numCores = -1; diff --git a/src/system_wrappers/source/cpu_measurement_harness.cc b/src/system_wrappers/source/cpu_measurement_harness.cc new file mode 100644 index 0000000000..237e776506 --- /dev/null +++ b/src/system_wrappers/source/cpu_measurement_harness.cc @@ -0,0 +1,127 @@ +/* + * 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 "system_wrappers/interface/cpu_wrapper.h" +#include "system_wrappers/interface/event_wrapper.h" +#include "system_wrappers/interface/scoped_ptr.h" +#include "system_wrappers/source/cpu_measurement_harness.h" + +const int kCpuCheckPeriodMs = 100; + +namespace webrtc { + +CpuMeasurementHarness* CpuMeasurementHarness::Create( + CpuTarget* target, + int work_period_ms, + int work_iterations_per_period, + int duration_ms) { + if (target == NULL) { + return NULL; + } + if (work_period_ms > duration_ms) { + return NULL; + } + if (work_period_ms < 0) { + return NULL; + } + if (duration_ms < 0) { + return NULL; + } + if (work_iterations_per_period < 1) { + return NULL; + } + return new CpuMeasurementHarness(target, work_period_ms, + work_iterations_per_period, duration_ms); +} + +CpuMeasurementHarness::CpuMeasurementHarness(CpuTarget* target, + int work_period_ms, + int work_iterations_per_period, + int duration_ms) + : cpu_target_(target), + work_period_ms_(work_period_ms), + work_iterations_per_period_(work_iterations_per_period), + duration_ms_(duration_ms), + cpu_sum_(0), + cpu_iterations_(0), + cpu_(CpuWrapper::CreateCpu()), + event_(EventWrapper::Create()) { +} + +CpuMeasurementHarness::~CpuMeasurementHarness() { +} + +bool CpuMeasurementHarness::Run() { + if (!WaitForCpuInit()) { + return false; + } + // No need for precision. Run for approximately the asked for duration. + // TODO(hellner): very low prio if at all, the actual duration of the test + // will be longer if calling DoWork() is not negligable and/or called many + // times. It may make sense to compensate for drift here. This will, + // however, only add complexity with minimal gains. Perhaps renaming the + // duration_ms_ to something more fuzzy is a better idea. However, the name + // would be very convoluted if it is to be self documenting. + int elapsed_time_ms = 0; + int last_measured_time = 0; + while (elapsed_time_ms < duration_ms_) { + if (((elapsed_time_ms - last_measured_time) / kCpuCheckPeriodMs) >= 1) { + last_measured_time = elapsed_time_ms; + Measure(); + } + if (!DoWork()) { + return false; + } + event_->Wait(work_period_ms_); + elapsed_time_ms += work_period_ms_; + } + return true; +} + +int CpuMeasurementHarness::AverageCpu() { + if (cpu_iterations_ == 0) { + return 0; + } + assert(cpu_sum_ >= 0); + assert(cpu_iterations_ >= 0); + return cpu_sum_ / cpu_iterations_; +} + +bool CpuMeasurementHarness::WaitForCpuInit() { + bool cpu_usage_available = false; + int num_iterations = 0; + // Initializing the CPU measurements may take a couple of seconds on Windows. + // Since the initialization is lazy we need to wait until it is completed. + // Should not take more than 10000 ms. + while (!cpu_usage_available && (++num_iterations < 10000)) { + event_->Wait(1); + cpu_usage_available = cpu_->CpuUsage() != -1; + } + return cpu_usage_available; +} + +void CpuMeasurementHarness::Measure() { + WebRtc_UWord32 num_cores = 0; + WebRtc_UWord32* cores = NULL; + // Return the average CPU for now. + cpu_sum_ = cpu_->CpuUsageMultiCore(num_cores, cores); + ++cpu_iterations_; +} + +bool CpuMeasurementHarness::DoWork() { + for (int i = 0; i < work_iterations_per_period_; ++i) { + if (!cpu_target_->DoWork()) { + return false; + } + } + return true; +} + +} // namespace webrtc diff --git a/src/system_wrappers/source/cpu_measurement_harness.h b/src/system_wrappers/source/cpu_measurement_harness.h new file mode 100644 index 0000000000..3b87f2775b --- /dev/null +++ b/src/system_wrappers/source/cpu_measurement_harness.h @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#ifndef SRC_SYSTEM_WRAPPERS_SOURCE_CPU_MEASUREMENT_HARNESS_H_ +#define SRC_SYSTEM_WRAPPERS_SOURCE_CPU_MEASUREMENT_HARNESS_H_ + +#include "system_wrappers/interface/scoped_ptr.h" + +namespace webrtc { + +class CpuWrapper; +class EventWrapper; +class ThreadWrapper; + +// This abstract class provides an interface that should be passed to +// CpuMeasurementHarness. CpuMeasurementHarness will call it with the +// frequency requested and measure the CPU usage for all calls. +class CpuTarget { + public: + // Callback function for which the CPU usage should be calculated. + virtual bool DoWork() = 0; + + protected: + CpuTarget() {} + virtual ~CpuTarget() {} +}; + +class CpuMeasurementHarness { + public: + static CpuMeasurementHarness* Create(CpuTarget* target, + int work_period_ms, + int work_iterations_per_period, + int duration_ms); + ~CpuMeasurementHarness(); + bool Run(); + int AverageCpu(); + + protected: + CpuMeasurementHarness(CpuTarget* target, int work_period_ms, + int work_iterations_per_period, int duration_ms); + + private: + bool WaitForCpuInit(); + void Measure(); + bool DoWork(); + + CpuTarget* cpu_target_; + const int work_period_ms_; + const int work_iterations_per_period_; + const int duration_ms_; + int cpu_sum_; + int cpu_iterations_; + scoped_ptr<CpuWrapper> cpu_; + scoped_ptr<EventWrapper> event_; +}; + +} // namespace webrtc + +#endif // SRC_SYSTEM_WRAPPERS_SOURCE_CPU_MEASUREMENT_HARNESS_H_ diff --git a/src/system_wrappers/source/cpu_win.cc b/src/system_wrappers/source/cpu_win.cc new file mode 100644 index 0000000000..86a6a6ad38 --- /dev/null +++ b/src/system_wrappers/source/cpu_win.cc @@ -0,0 +1,530 @@ +/* + * 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 "cpu_win.h" + +#define _WIN32_DCOM + +#include <assert.h> +#include <iostream> +#include <Wbemidl.h> + +#pragma comment(lib, "wbemuuid.lib") + +#include "condition_variable_wrapper.h" +#include "critical_section_wrapper.h" +#include "event_wrapper.h" +#include "thread_wrapper.h" + +namespace webrtc { +WebRtc_Word32 CpuWindows::CpuUsage() +{ + if (!has_initialized_) + { + return -1; + } + // Last element is the average + return cpu_usage_[number_of_objects_ - 1]; +} + +WebRtc_Word32 CpuWindows::CpuUsageMultiCore(WebRtc_UWord32& num_cores, + WebRtc_UWord32*& cpu_usage) +{ + if (has_terminated_) { + num_cores = 0; + cpu_usage = NULL; + return -1; + } + if (!has_initialized_) + { + num_cores = 0; + cpu_usage = NULL; + return -1; + } + num_cores = number_of_objects_ - 1; + cpu_usage = cpu_usage_; + return cpu_usage_[number_of_objects_-1]; +} + +CpuWindows::CpuWindows() + : cpu_polling_thread(NULL), + initialize_(true), + has_initialized_(false), + terminate_(false), + has_terminated_(false), + cpu_usage_(NULL), + wbem_enum_access_(NULL), + number_of_objects_(0), + cpu_usage_handle_(0), + previous_processor_timestamp_(NULL), + timestamp_sys_100_ns_handle_(0), + previous_100ns_timestamp_(NULL), + wbem_service_(NULL), + wbem_service_proxy_(NULL), + wbem_refresher_(NULL), + wbem_enum_(NULL) +{ + // All resources are allocated in PollingCpu(). + if (AllocateComplexDataTypes()) + { + StartPollingCpu(); + } + else + { + assert(false); + } +} + +CpuWindows::~CpuWindows() +{ + // All resources are reclaimed in StopPollingCpu(). + StopPollingCpu(); + DeAllocateComplexDataTypes(); +} + +bool CpuWindows::AllocateComplexDataTypes() +{ + cpu_polling_thread = ThreadWrapper::CreateThread( + CpuWindows::Process, + reinterpret_cast<void*>(this), + kNormalPriority, + "CpuWindows"); + init_crit_ = CriticalSectionWrapper::CreateCriticalSection(); + init_cond_ = ConditionVariableWrapper::CreateConditionVariable(); + terminate_crit_ = CriticalSectionWrapper::CreateCriticalSection(); + terminate_cond_ = ConditionVariableWrapper::CreateConditionVariable(); + sleep_event = EventWrapper::Create(); + return (cpu_polling_thread != NULL) && (init_crit_ != NULL) && + (init_cond_ != NULL) && (terminate_crit_ != NULL) && + (terminate_cond_ != NULL) && (sleep_event != NULL); +} + +void CpuWindows::DeAllocateComplexDataTypes() +{ + if (sleep_event != NULL) + { + delete sleep_event; + sleep_event = NULL; + } + if (terminate_cond_ != NULL) + { + delete terminate_cond_; + terminate_cond_ = NULL; + } + if (terminate_crit_ != NULL) + { + delete terminate_crit_; + terminate_crit_ = NULL; + } + if (init_cond_ != NULL) + { + delete init_cond_; + init_cond_ = NULL; + } + if (init_crit_ != NULL) + { + delete init_crit_; + init_crit_ = NULL; + } + if (cpu_polling_thread != NULL) + { + delete cpu_polling_thread; + cpu_polling_thread = NULL; + } +} + +void CpuWindows::StartPollingCpu() +{ + unsigned int dummy_id = 0; + if (!cpu_polling_thread->Start(dummy_id)) + { + initialize_ = false; + has_terminated_ = true; + assert(false); + } +} + +bool CpuWindows::StopPollingCpu() +{ + { + // If StopPollingCpu is called immediately after StartPollingCpu() it is + // possible that cpu_polling_thread is in the process of initializing. + // Let initialization finish to avoid getting into a bad state. + CriticalSectionScoped cs(init_crit_); + while(initialize_) + { + init_cond_->SleepCS(*init_crit_); + } + } + + CriticalSectionScoped cs(terminate_crit_); + terminate_ = true; + sleep_event->Set(); + while (!has_terminated_) + { + terminate_cond_->SleepCS(*terminate_crit_); + } + cpu_polling_thread->Stop(); + delete cpu_polling_thread; + cpu_polling_thread = NULL; + return true; +} + +bool CpuWindows::Process(void* thread_object) +{ + return reinterpret_cast<CpuWindows*>(thread_object)->ProcessImpl(); +} + +bool CpuWindows::ProcessImpl() +{ + { + CriticalSectionScoped cs(terminate_crit_); + if (terminate_) + { + Terminate(); + terminate_cond_->WakeAll(); + return false; + } + } + // Initialize on first iteration + if (initialize_) + { + CriticalSectionScoped cs(init_crit_); + initialize_ = false; + const bool success = Initialize(); + init_cond_->WakeAll(); + if (!success || !has_initialized_) + { + has_initialized_ = false; + terminate_ = true; + return true; + } + } + // Approximately one seconds sleep for each CPU measurement. Precision is + // not important. 1 second refresh rate is also used by Performance Monitor + // (perfmon). + if(kEventTimeout != sleep_event->Wait(1000)) + { + // Terminating. No need to update CPU usage. + assert(terminate_); + return true; + } + + // UpdateCpuUsage() returns false if a single (or more) CPU read(s) failed. + // Not a major problem if it happens. + UpdateCpuUsage(); + return true; +} + +bool CpuWindows::CreateWmiConnection() +{ + IWbemLocator* service_locator = NULL; + HRESULT hr = CoCreateInstance(CLSID_WbemLocator, NULL, + CLSCTX_INPROC_SERVER, IID_IWbemLocator, + reinterpret_cast<void**> (&service_locator)); + if (FAILED(hr)) + { + return false; + } + // To get the WMI service specify the WMI namespace. + BSTR wmi_namespace = SysAllocString(L"\\\\.\\root\\cimv2"); + if (wmi_namespace == NULL) + { + // This type of failure signifies running out of memory. + service_locator->Release(); + return false; + } + hr = service_locator->ConnectServer(wmi_namespace, NULL, NULL, NULL, 0L, + NULL, NULL, &wbem_service_); + SysFreeString(wmi_namespace); + service_locator->Release(); + return !FAILED(hr); +} + +// Sets up WMI refresher and enum +bool CpuWindows::CreatePerfOsRefresher() +{ + // Create refresher. + HRESULT hr = CoCreateInstance(CLSID_WbemRefresher, NULL, + CLSCTX_INPROC_SERVER, IID_IWbemRefresher, + reinterpret_cast<void**> (&wbem_refresher_)); + if (FAILED(hr)) + { + return false; + } + // Create PerfOS_Processor enum. + IWbemConfigureRefresher* wbem_refresher_config = NULL; + hr = wbem_refresher_->QueryInterface( + IID_IWbemConfigureRefresher, + reinterpret_cast<void**> (&wbem_refresher_config)); + if (FAILED(hr)) + { + return false; + } + + // Create a proxy to the IWbemServices so that a local authentication + // can be set up (this is needed to be able to successfully call + // IWbemConfigureRefresher::AddEnum). Setting authentication with + // CoInitializeSecurity is process-wide (which is too intrusive). + hr = CoCopyProxy(static_cast<IUnknown*> (wbem_service_), + reinterpret_cast<IUnknown**> (&wbem_service_proxy_)); + if(FAILED(hr)) + { + return false; + } + // Set local authentication. + // RPC_C_AUTHN_WINNT means using NTLM instead of Kerberos which is default. + hr = CoSetProxyBlanket(static_cast<IUnknown*> (wbem_service_proxy_), + RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, + RPC_C_AUTHN_LEVEL_DEFAULT, + RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE); + if(FAILED(hr)) + { + return false; + } + + // Don't care about the particular id for the enum. + long enum_id = 0; + hr = wbem_refresher_config->AddEnum(wbem_service_proxy_, + L"Win32_PerfRawData_PerfOS_Processor", + 0, NULL, &wbem_enum_, &enum_id); + wbem_refresher_config->Release(); + wbem_refresher_config = NULL; + return !FAILED(hr); +} + +// Have to pull the first round of data to be able set the handles. +bool CpuWindows::CreatePerfOsCpuHandles() +{ + // Update the refresher so that there is data available in wbem_enum_. + wbem_refresher_->Refresh(0L); + + // The number of enumerators is the number of processor + 1 (the total). + // This is unknown at this point. + DWORD number_returned = 0; + HRESULT hr = wbem_enum_->GetObjects(0L, number_of_objects_, + wbem_enum_access_, &number_returned); + // number_returned indicates the number of enumerators that are needed. + if (hr == WBEM_E_BUFFER_TOO_SMALL && + number_returned > number_of_objects_) + { + // Allocate the number IWbemObjectAccess asked for by the + // GetObjects(..) function. + wbem_enum_access_ = new IWbemObjectAccess*[number_returned]; + cpu_usage_ = new WebRtc_UWord32[number_returned]; + previous_processor_timestamp_ = new unsigned __int64[number_returned]; + previous_100ns_timestamp_ = new unsigned __int64[number_returned]; + if ((wbem_enum_access_ == NULL) || (cpu_usage_ == NULL) || + (previous_processor_timestamp_ == NULL) || + (previous_100ns_timestamp_ == NULL)) + { + // Out of memory. + return false; + } + + SecureZeroMemory(wbem_enum_access_, number_returned * + sizeof(IWbemObjectAccess*)); + memset(cpu_usage_, 0, sizeof(int) * number_returned); + memset(previous_processor_timestamp_, 0, sizeof(unsigned __int64) * + number_returned); + memset(previous_100ns_timestamp_, 0, sizeof(unsigned __int64) * + number_returned); + + number_of_objects_ = number_returned; + // Read should be successfull now that memory has been allocated. + hr = wbem_enum_->GetObjects(0L, number_of_objects_, wbem_enum_access_, + &number_returned); + if (FAILED(hr)) + { + return false; + } + } + else + { + // 0 enumerators should not be enough. Something has gone wrong here. + return false; + } + + // Get the enumerator handles that are needed for calculating CPU usage. + CIMTYPE cpu_usage_type; + hr = wbem_enum_access_[0]->GetPropertyHandle(L"PercentProcessorTime", + &cpu_usage_type, + &cpu_usage_handle_); + if (FAILED(hr)) + { + return false; + } + CIMTYPE timestamp_sys_100_ns_type; + hr = wbem_enum_access_[0]->GetPropertyHandle(L"TimeStamp_Sys100NS", + ×tamp_sys_100_ns_type, + ×tamp_sys_100_ns_handle_); + return !FAILED(hr); +} + +bool CpuWindows::Initialize() +{ + if (terminate_) + { + return false; + } + // Initialize COM library. + HRESULT hr = CoInitializeEx(NULL,COINIT_MULTITHREADED); + if (FAILED(hr)) + { + return false; + } + if (FAILED(hr)) + { + return false; + } + + if (!CreateWmiConnection()) + { + return false; + } + if (!CreatePerfOsRefresher()) + { + return false; + } + if (!CreatePerfOsCpuHandles()) + { + return false; + } + has_initialized_ = true; + return true; +} + +bool CpuWindows::Terminate() +{ + if (has_terminated_) + { + return false; + } + // Reverse order of Initialize(). + // Some compilers complain about deleting NULL though it's well defined + if (previous_100ns_timestamp_ != NULL) + { + delete[] previous_100ns_timestamp_; + previous_100ns_timestamp_ = NULL; + } + if (previous_processor_timestamp_ != NULL) + { + delete[] previous_processor_timestamp_; + previous_processor_timestamp_ = NULL; + } + if (cpu_usage_ != NULL) + { + delete[] cpu_usage_; + cpu_usage_ = NULL; + } + if (wbem_enum_access_ != NULL) + { + for (DWORD i = 0; i < number_of_objects_; i++) + { + if(wbem_enum_access_[i] != NULL) + { + wbem_enum_access_[i]->Release(); + } + } + delete[] wbem_enum_access_; + wbem_enum_access_ = NULL; + } + if (wbem_enum_ != NULL) + { + wbem_enum_->Release(); + wbem_enum_ = NULL; + } + if (wbem_refresher_ != NULL) + { + wbem_refresher_->Release(); + wbem_refresher_ = NULL; + } + if (wbem_service_proxy_ != NULL) + { + wbem_service_proxy_->Release(); + wbem_service_proxy_ = NULL; + } + if (wbem_service_ != NULL) + { + wbem_service_->Release(); + wbem_service_ = NULL; + } + // CoUninitialized should be called once for every CoInitializeEx. + // Regardless if it failed or not. + CoUninitialize(); + has_terminated_ = true; + return true; +} + +bool CpuWindows::UpdateCpuUsage() +{ + wbem_refresher_->Refresh(0L); + DWORD number_returned = 0; + HRESULT hr = wbem_enum_->GetObjects(0L, number_of_objects_, + wbem_enum_access_,&number_returned); + if (FAILED(hr)) + { + // wbem_enum_access_ has already been allocated. Unless the number of + // CPUs change runtime this should not happen. + return false; + } + unsigned __int64 cpu_usage = 0; + unsigned __int64 timestamp_100ns = 0; + bool returnValue = true; + for (DWORD i = 0; i < number_returned; i++) + { + hr = wbem_enum_access_[i]->ReadQWORD(cpu_usage_handle_,&cpu_usage); + if (FAILED(hr)) + { + returnValue = false; + } + hr = wbem_enum_access_[i]->ReadQWORD(timestamp_sys_100_ns_handle_, + ×tamp_100ns); + if (FAILED(hr)) + { + returnValue = false; + } + wbem_enum_access_[i]->Release(); + wbem_enum_access_[i] = NULL; + + const bool wrapparound = + (previous_processor_timestamp_[i] > cpu_usage) || + (previous_100ns_timestamp_[i] > timestamp_100ns); + const bool first_time = (previous_processor_timestamp_[i] == 0) || + (previous_100ns_timestamp_[i] == 0); + if (wrapparound || first_time) + { + previous_processor_timestamp_[i] = cpu_usage; + previous_100ns_timestamp_[i] = timestamp_100ns; + continue; + } + const unsigned __int64 processor_timestamp_delta = + cpu_usage - previous_processor_timestamp_[i]; + const unsigned __int64 timestamp_100ns_delta = + timestamp_100ns - previous_100ns_timestamp_[i]; + + if (processor_timestamp_delta >= timestamp_100ns_delta) + { + cpu_usage_[i] = 0; + } else { + // Quotient must be float since the division is guaranteed to yield + // a value between 0 and 1 which is 0 in integer division. + const float delta_quotient = + static_cast<float>(processor_timestamp_delta) / + static_cast<float>(timestamp_100ns_delta); + cpu_usage_[i] = 100 - static_cast<WebRtc_UWord32>(delta_quotient * + 100); + } + previous_processor_timestamp_[i] = cpu_usage; + previous_100ns_timestamp_[i] = timestamp_100ns; + } + return returnValue; +} +} // namespace webrtc diff --git a/src/system_wrappers/source/cpu_win.h b/src/system_wrappers/source/cpu_win.h new file mode 100644 index 0000000000..d15073c0ba --- /dev/null +++ b/src/system_wrappers/source/cpu_win.h @@ -0,0 +1,103 @@ +// This file contains a Windows implementation of CpuWrapper. +// Note: Windows XP, Windows Server 2003 are the minimum requirements. +// The requirements are due to the implementation being based on +// WMI. +/* + * 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_SYSTEM_WRAPPERS_SOURCE_CPU_WINDOWS_NO_CPOL_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_WINDOWS_NO_CPOL_H_ + +#include "cpu_wrapper.h" + +#include <Wbemidl.h> + +namespace webrtc { +class ConditionVariableWrapper; +class CriticalSectionWrapper; +class EventWrapper; +class ThreadWrapper; + +class CpuWindows : public CpuWrapper +{ +public: + virtual WebRtc_Word32 CpuUsage(); + virtual WebRtc_Word32 CpuUsage(WebRtc_Word8* /*pProcessName*/, + WebRtc_UWord32 /*length*/) {return -1;} + virtual WebRtc_Word32 CpuUsage(WebRtc_UWord32 /*dwProcessID*/) {return -1;} + + virtual WebRtc_Word32 CpuUsageMultiCore(WebRtc_UWord32& num_cores, + WebRtc_UWord32*& cpu_usage); + + virtual void Reset() {} + virtual void Stop() {} + + CpuWindows(); + virtual ~CpuWindows(); +private: + bool AllocateComplexDataTypes(); + void DeAllocateComplexDataTypes(); + + void StartPollingCpu(); + bool StopPollingCpu(); + + static bool Process(void* thread_object); + bool ProcessImpl(); + + bool CreateWmiConnection(); + bool CreatePerfOsRefresher(); + bool CreatePerfOsCpuHandles(); + bool Initialize(); + bool Terminate(); + + bool UpdateCpuUsage(); + + ThreadWrapper* cpu_polling_thread; + + bool initialize_; + bool has_initialized_; + CriticalSectionWrapper* init_crit_; + ConditionVariableWrapper* init_cond_; + + bool terminate_; + bool has_terminated_; + CriticalSectionWrapper* terminate_crit_; + ConditionVariableWrapper* terminate_cond_; + + // For sleep with wake-up functionality. + EventWrapper* sleep_event; + + // Will be an array. Just care about CPU 0 for now. + WebRtc_UWord32* cpu_usage_; + + // One IWbemObjectAccess for each processor and one for the total. + // 0-n-1 is the individual processors. + // n is the total. + IWbemObjectAccess** wbem_enum_access_; + DWORD number_of_objects_; + + // Cpu timestamp + long cpu_usage_handle_; + unsigned __int64* previous_processor_timestamp_; + + // Timestamp + long timestamp_sys_100_ns_handle_; + unsigned __int64* previous_100ns_timestamp_; + + IWbemServices* wbem_service_; + IWbemServices* wbem_service_proxy_; + + IWbemRefresher* wbem_refresher_; + + IWbemHiPerfEnum* wbem_enum_; + +}; +} // namespace webrtc +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_WINDOWS_NO_CPOL_H_ diff --git a/src/system_wrappers/source/cpu_wrapper_unittest.cc b/src/system_wrappers/source/cpu_wrapper_unittest.cc index dd49c3ac94..cd149dc30f 100644 --- a/src/system_wrappers/source/cpu_wrapper_unittest.cc +++ b/src/system_wrappers/source/cpu_wrapper_unittest.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -23,7 +23,14 @@ using webrtc::EventWrapper; using webrtc::scoped_ptr; using webrtc::Trace; -TEST(CpuWrapperTest, Usage) { +// This test is flaky on Windows/Release. +// http://code.google.com/p/webrtc/issues/detail?id=290 +#ifdef _WIN32 +#define MAYBE_Usage DISABLED_Usage +#else +#define MAYBE_Usage Usage +#endif +TEST(CpuWrapperTest, MAYBE_Usage) { Trace::CreateTrace(); std::string trace_file = webrtc::test::OutputPath() + "cpu_wrapper_unittest.txt"; @@ -42,7 +49,7 @@ TEST(CpuWrapperTest, Usage) { // Initializing the CPU measurements may take a couple of seconds on Windows. // Since the initialization is lazy we need to wait until it is completed. // Should not take more than 10000 ms. - while (cpu_usage_available && (++num_iterations < 10000)) { + while (!cpu_usage_available && (++num_iterations < 10000)) { if (cores != NULL) { ASSERT_GT(num_cores, 0u); break; diff --git a/src/system_wrappers/source/critical_section_posix.cc b/src/system_wrappers/source/critical_section_posix.cc index b499b9ffe2..70f85f9a68 100644 --- a/src/system_wrappers/source/critical_section_posix.cc +++ b/src/system_wrappers/source/critical_section_posix.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -8,31 +8,39 @@ * be found in the AUTHORS file in the root of the source tree. */ +// General note: return values for the various pthread synchronization APIs +// are explicitly ignored here. In Chromium, the same thing is done for release. +// However, in debugging, failure in these APIs are logged. There is currently +// no equivalent to DCHECK_EQ in WebRTC code so this is the best we can do here. +// TODO(henrike): add logging when pthread synchronization APIs are failing. + #include "critical_section_posix.h" namespace webrtc { + CriticalSectionPosix::CriticalSectionPosix() { pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&_mutex, &attr); + (void) pthread_mutexattr_init(&attr); + (void) pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + (void) pthread_mutex_init(&_mutex, &attr); } CriticalSectionPosix::~CriticalSectionPosix() { - pthread_mutex_destroy(&_mutex); + (void) pthread_mutex_destroy(&_mutex); } void CriticalSectionPosix::Enter() { - pthread_mutex_lock(&_mutex); + (void) pthread_mutex_lock(&_mutex); } void CriticalSectionPosix::Leave() { - pthread_mutex_unlock(&_mutex); + (void) pthread_mutex_unlock(&_mutex); } + } // namespace webrtc diff --git a/src/system_wrappers/source/critical_section_unittest.cc b/src/system_wrappers/source/critical_section_unittest.cc new file mode 100644 index 0000000000..c48b9f7515 --- /dev/null +++ b/src/system_wrappers/source/critical_section_unittest.cc @@ -0,0 +1,167 @@ +/* + * 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. + */ + +#ifdef _WIN32 +// For Sleep() +#include <windows.h> +#else +// For nanosleep() +#include <time.h> +#endif + +#include "system_wrappers/interface/critical_section_wrapper.h" + +#include "gtest/gtest.h" +#include "system_wrappers/interface/sleep.h" +#include "system_wrappers/interface/thread_wrapper.h" +#include "system_wrappers/interface/trace.h" +#include "system_wrappers/source/unittest_utilities.h" + +namespace webrtc { + +namespace { + +const bool kLogTrace = false; // Set to true to enable debug logging to stdout. + +#define LOG(...) WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, __VA_ARGS__); + +// Cause a process switch. Needed to avoid depending on +// busy-wait in tests. +static void SwitchProcess() { + // Note - sched_yield has been tried as process switch. This does + // not cause a process switch enough of the time for reliability. + SleepMs(1); +} + +class ProtectedCount { + public: + explicit ProtectedCount(CriticalSectionWrapper* crit_sect) + : crit_sect_(crit_sect), + count_(0) { + } + + void Increment() { + CriticalSectionScoped cs(crit_sect_); + ++count_; + LOG("Inc to %d", count_); + } + + int Count() const { + CriticalSectionScoped cs(crit_sect_); + return count_; + } + + private: + CriticalSectionWrapper* crit_sect_; + int count_; +}; + +class CritSectTest : public ::testing::Test { + public: + CritSectTest() : trace_(kLogTrace) { + } + + // Waits a number of cycles for the count to reach a given value. + // Returns true if the target is reached or passed. + bool WaitForCount(int target, ProtectedCount* count) { + int loop_counter = 0; + // On Posix, this SwitchProcess() needs to be in a loop to make the + // test both fast and non-flaky. + // With 1 us wait as the switch, up to 7 rounds have been observed. + while (count->Count() < target && loop_counter < 100*target) { + ++loop_counter; + SwitchProcess(); + } + LOG("Test looped %d times\n", loop_counter); + return (count->Count() >= target); + } + + private: + ScopedTracing trace_; +}; + +bool LockUnlockThenStopRunFunction(void* obj) { + LOG("Wait starting"); + ProtectedCount* the_count = static_cast<ProtectedCount*> (obj); + LOG("Wait incrementing"); + the_count->Increment(); + LOG("Wait returning"); + return false; +} + +TEST_F(CritSectTest, ThreadWakesOnce) { + CriticalSectionWrapper* crit_sect + = CriticalSectionWrapper::CreateCriticalSection(); + ProtectedCount count(crit_sect); + ThreadWrapper* thread = ThreadWrapper::CreateThread( + &LockUnlockThenStopRunFunction, &count); + unsigned int id = 42; + crit_sect->Enter(); + ASSERT_TRUE(thread->Start(id)); + SwitchProcess(); + // The critical section is of reentrant mode, so this should not release + // the lock, even though count.Count() locks and unlocks the critical section + // again. + // Thus, the thread should not be able to increment the count + ASSERT_EQ(0, count.Count()); + crit_sect->Leave(); // This frees the thread to act. + EXPECT_TRUE(WaitForCount(1, &count)); + EXPECT_TRUE(thread->Stop()); + delete thread; + delete crit_sect; +} + +bool LockUnlockRunFunction(void* obj) { + LOG("Wait starting"); + ProtectedCount* the_count = static_cast<ProtectedCount*> (obj); + LOG("Wait incrementing"); + the_count->Increment(); + SwitchProcess(); + LOG("Wait returning"); + return true; +} + +TEST_F(CritSectTest, ThreadWakesTwice) { + CriticalSectionWrapper* crit_sect + = CriticalSectionWrapper::CreateCriticalSection(); + ProtectedCount count(crit_sect); + ThreadWrapper* thread = ThreadWrapper::CreateThread(&LockUnlockRunFunction, + &count); + unsigned int id = 42; + crit_sect->Enter(); // Make sure counter stays 0 until we wait for it. + ASSERT_TRUE(thread->Start(id)); + crit_sect->Leave(); + + // The thread is capable of grabbing the lock multiple times, + // incrementing counter once each time. + // It's possible for the count to be incremented by more than 2. + EXPECT_TRUE(WaitForCount(2, &count)); + EXPECT_LE(2, count.Count()); + + // The thread does not increment while lock is held. + crit_sect->Enter(); + int count_before = count.Count(); + for (int i = 0; i < 10; i++) { + SwitchProcess(); + } + EXPECT_EQ(count_before, count.Count()); + crit_sect->Leave(); + + thread->SetNotAlive(); // Tell thread to exit once run function finishes. + SwitchProcess(); + EXPECT_LT(count_before, count.Count()); + EXPECT_TRUE(thread->Stop()); + delete thread; + delete crit_sect; +} + +} // anonymous namespace + +} // namespace webrtc diff --git a/src/system_wrappers/source/critical_section_win.cc b/src/system_wrappers/source/critical_section_win.cc new file mode 100644 index 0000000000..bbc66e5c7d --- /dev/null +++ b/src/system_wrappers/source/critical_section_win.cc @@ -0,0 +1,35 @@ +/* + * 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 "critical_section_win.h" + +namespace webrtc { +CriticalSectionWindows::CriticalSectionWindows() +{ + InitializeCriticalSection(&crit); +} + +CriticalSectionWindows::~CriticalSectionWindows() +{ + DeleteCriticalSection(&crit); +} + +void +CriticalSectionWindows::Enter() +{ + EnterCriticalSection(&crit); +} + +void +CriticalSectionWindows::Leave() +{ + LeaveCriticalSection(&crit); +} +} // namespace webrtc diff --git a/src/system_wrappers/source/critical_section_win.h b/src/system_wrappers/source/critical_section_win.h new file mode 100644 index 0000000000..9556fa9556 --- /dev/null +++ b/src/system_wrappers/source/critical_section_win.h @@ -0,0 +1,36 @@ +/* + * 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_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WINDOWS_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WINDOWS_H_ + +#include "typedefs.h" +#include "critical_section_wrapper.h" +#include <windows.h> + +namespace webrtc { +class CriticalSectionWindows : public CriticalSectionWrapper +{ +public: + CriticalSectionWindows(); + + virtual ~CriticalSectionWindows(); + + virtual void Enter(); + virtual void Leave(); + +private: + CRITICAL_SECTION crit; + + friend class ConditionVariableWindows; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_WINDOWS_H_ diff --git a/src/system_wrappers/source/event_win.cc b/src/system_wrappers/source/event_win.cc new file mode 100644 index 0000000000..efcb5af870 --- /dev/null +++ b/src/system_wrappers/source/event_win.cc @@ -0,0 +1,84 @@ +/* + * 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 "event_win.h" + +#include "Mmsystem.h" + +namespace webrtc { +EventWindows::EventWindows() + : _event(::CreateEvent(NULL /* security attributes */, + FALSE /* manual reset */, + FALSE /* initial state */, + NULL /* name of event */)), + _timerID(NULL) +{ +} + +EventWindows::~EventWindows() +{ + CloseHandle(_event); +} + +bool EventWindows::Set() +{ + // Note: setting an event that is already set has no effect. + return SetEvent(_event) == 1 ? true : false; +} + +bool EventWindows::Reset() +{ + return ResetEvent(_event) == 1 ? true : false; +} + +EventTypeWrapper EventWindows::Wait(unsigned long maxTime) +{ + unsigned long res = WaitForSingleObject(_event, maxTime); + switch(res) + { + case WAIT_OBJECT_0: + return kEventSignaled; + case WAIT_TIMEOUT: + return kEventTimeout; + default: + return kEventError; + } +} + +bool EventWindows::StartTimer(bool periodic, unsigned long time) +{ + if (_timerID != NULL) + { + timeKillEvent(_timerID); + _timerID=NULL; + } + if (periodic) + { + _timerID=timeSetEvent(time, 0,(LPTIMECALLBACK)HANDLE(_event),0, + TIME_PERIODIC|TIME_CALLBACK_EVENT_PULSE); + } else { + _timerID=timeSetEvent(time, 0,(LPTIMECALLBACK)HANDLE(_event),0, + TIME_ONESHOT|TIME_CALLBACK_EVENT_SET); + } + + if (_timerID == NULL) + { + return false; + } + return true; +} + +bool EventWindows::StopTimer() +{ + timeKillEvent(_timerID); + _timerID = NULL; + return true; +} +} // namespace webrtc diff --git a/src/system_wrappers/source/event_win.h b/src/system_wrappers/source/event_win.h new file mode 100644 index 0000000000..8ca1360c35 --- /dev/null +++ b/src/system_wrappers/source/event_win.h @@ -0,0 +1,40 @@ +/* + * 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_SYSTEM_WRAPPERS_SOURCE_EVENT_WINDOWS_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_WINDOWS_H_ + +#include <windows.h> + +#include "event_wrapper.h" + +#include "typedefs.h" + +namespace webrtc { +class EventWindows : public EventWrapper +{ +public: + EventWindows(); + virtual ~EventWindows(); + + virtual EventTypeWrapper Wait(unsigned long maxTime); + virtual bool Set(); + virtual bool Reset(); + + virtual bool StartTimer(bool periodic, unsigned long time); + virtual bool StopTimer(); + +private: + HANDLE _event; + WebRtc_UWord32 _timerID; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_EVENT_WINDOWS_H_ diff --git a/src/system_wrappers/source/file_impl.cc b/src/system_wrappers/source/file_impl.cc index d163bf6c26..4d06c54707 100644 --- a/src/system_wrappers/source/file_impl.cc +++ b/src/system_wrappers/source/file_impl.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -118,7 +118,7 @@ int FileWrapperImpl::OpenFile(const char *fileNameUTF8, bool readOnly, bool loop, bool text) { size_t length = strlen(fileNameUTF8); - if (length > kMaxFileNameSize) + if (length > kMaxFileNameSize - 1) { return -1; } diff --git a/src/system_wrappers/source/rw_lock.cc b/src/system_wrappers/source/rw_lock.cc index b308358d8a..16da0e321d 100644 --- a/src/system_wrappers/source/rw_lock.cc +++ b/src/system_wrappers/source/rw_lock.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -14,9 +14,6 @@ #if defined(_WIN32) #include "rw_lock_win.h" -#elif defined(WEBRTC_ANDROID) - #include <stdlib.h> - #include "rw_lock_generic.h" #else #include "rw_lock_posix.h" #endif @@ -26,8 +23,6 @@ RWLockWrapper* RWLockWrapper::CreateRWLock() { #ifdef _WIN32 RWLockWrapper* lock = new RWLockWindows(); -#elif defined(WEBRTC_ANDROID) - RWLockWrapper* lock = new RWLockWrapperGeneric(); #else RWLockWrapper* lock = new RWLockPosix(); #endif diff --git a/src/system_wrappers/source/rw_lock_win.cc b/src/system_wrappers/source/rw_lock_win.cc new file mode 100644 index 0000000000..82cd0ac04f --- /dev/null +++ b/src/system_wrappers/source/rw_lock_win.cc @@ -0,0 +1,186 @@ +/* + * 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 "rw_lock_win.h" + +#include "critical_section_wrapper.h" +#include "condition_variable_wrapper.h" +#include "trace.h" + +// TODO (hellner) why not just use the rw_lock_generic.cc solution if +// native is not supported? Unnecessary redundancy! + +namespace webrtc { +bool RWLockWindows::_winSupportRWLockPrimitive = false; +static HMODULE library = NULL; + +PInitializeSRWLock _PInitializeSRWLock; +PAcquireSRWLockExclusive _PAcquireSRWLockExclusive; +PAcquireSRWLockShared _PAcquireSRWLockShared; +PReleaseSRWLockShared _PReleaseSRWLockShared; +PReleaseSRWLockExclusive _PReleaseSRWLockExclusive; + +RWLockWindows::RWLockWindows() + : _critSectPtr(NULL), + _readCondPtr(NULL), + _writeCondPtr(NULL), + _readersActive(0), + _writerActive(false), + _readersWaiting(0), + _writersWaiting(0) +{ +} + +RWLockWindows::~RWLockWindows() +{ + delete _writeCondPtr; + delete _readCondPtr; + delete _critSectPtr; +} + +int RWLockWindows::Init() +{ + if(!library) + { + // Use native implementation if supported (i.e Vista+) + library = LoadLibrary(TEXT("Kernel32.dll")); + if(library) + { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, + "Loaded Kernel.dll"); + + _PInitializeSRWLock = + (PInitializeSRWLock)GetProcAddress( + library, + "InitializeSRWLock"); + + _PAcquireSRWLockExclusive = + (PAcquireSRWLockExclusive)GetProcAddress( + library, + "AcquireSRWLockExclusive"); + _PReleaseSRWLockExclusive = + (PReleaseSRWLockExclusive)GetProcAddress( + library, + "ReleaseSRWLockExclusive"); + _PAcquireSRWLockShared = + (PAcquireSRWLockShared)GetProcAddress( + library, + "AcquireSRWLockShared"); + _PReleaseSRWLockShared = + (PReleaseSRWLockShared)GetProcAddress( + library, + "ReleaseSRWLockShared"); + + if( _PInitializeSRWLock && + _PAcquireSRWLockExclusive && + _PReleaseSRWLockExclusive && + _PAcquireSRWLockShared && + _PReleaseSRWLockShared ) + { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, + "Loaded Simple RW Lock"); + _winSupportRWLockPrimitive = true; + } + } + } + if(_winSupportRWLockPrimitive) + { + _PInitializeSRWLock(&_lock); + } else { + _critSectPtr = CriticalSectionWrapper::CreateCriticalSection(); + _readCondPtr = ConditionVariableWrapper::CreateConditionVariable(); + _writeCondPtr = ConditionVariableWrapper::CreateConditionVariable(); + } + return 0; +} + +void RWLockWindows::AcquireLockExclusive() +{ + if (_winSupportRWLockPrimitive) + { + _PAcquireSRWLockExclusive(&_lock); + } else { + _critSectPtr->Enter(); + + if (_writerActive || _readersActive > 0) + { + ++_writersWaiting; + while (_writerActive || _readersActive > 0) + { + _writeCondPtr->SleepCS(*_critSectPtr); + } + --_writersWaiting; + } + _writerActive = true; + _critSectPtr->Leave(); + } +} + +void RWLockWindows::ReleaseLockExclusive() +{ + if(_winSupportRWLockPrimitive) + { + _PReleaseSRWLockExclusive(&_lock); + } else { + _critSectPtr->Enter(); + _writerActive = false; + if (_writersWaiting > 0) + { + _writeCondPtr->Wake(); + + }else if (_readersWaiting > 0) { + _readCondPtr->WakeAll(); + } + _critSectPtr->Leave(); + } +} + +void RWLockWindows::AcquireLockShared() +{ + if(_winSupportRWLockPrimitive) + { + _PAcquireSRWLockShared(&_lock); + } else + { + _critSectPtr->Enter(); + if (_writerActive || _writersWaiting > 0) + { + ++_readersWaiting; + + while (_writerActive || _writersWaiting > 0) + { + _readCondPtr->SleepCS(*_critSectPtr); + } + --_readersWaiting; + } + ++_readersActive; + _critSectPtr->Leave(); + } +} + +void RWLockWindows::ReleaseLockShared() +{ + if(_winSupportRWLockPrimitive) + { + _PReleaseSRWLockShared(&_lock); + } else + { + _critSectPtr->Enter(); + + --_readersActive; + + if (_readersActive == 0 && _writersWaiting > 0) + { + _writeCondPtr->Wake(); + } + _critSectPtr->Leave(); + } +} +} // namespace webrtc diff --git a/src/system_wrappers/source/rw_lock_win.h b/src/system_wrappers/source/rw_lock_win.h new file mode 100644 index 0000000000..dc5355e4d6 --- /dev/null +++ b/src/system_wrappers/source/rw_lock_win.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. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_WINDOWS_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_WINDOWS_H_ + +#include "rw_lock_wrapper.h" + +#include <Windows.h> + +#if !defined(RTL_SRWLOCK_INIT) + typedef struct _RTL_SRWLOCK + { + void* Ptr; + } RTL_SRWLOCK, *PRTL_SRWLOCK; + typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK; +#endif + +namespace webrtc { +class CriticalSectionWrapper; +class ConditionVariableWrapper; + +typedef void (WINAPI *PInitializeSRWLock)(PSRWLOCK); + +typedef void (WINAPI *PAcquireSRWLockExclusive)(PSRWLOCK); +typedef void (WINAPI *PReleaseSRWLockExclusive)(PSRWLOCK); + +typedef void (WINAPI *PAcquireSRWLockShared)(PSRWLOCK); +typedef void (WINAPI *PReleaseSRWLockShared)(PSRWLOCK); + + +class RWLockWindows :public RWLockWrapper +{ +public: + RWLockWindows(); + virtual ~RWLockWindows(); + + virtual void AcquireLockExclusive(); + virtual void ReleaseLockExclusive(); + + virtual void AcquireLockShared(); + virtual void ReleaseLockShared(); + +protected: + virtual int Init(); + +private: + // For native implementation. + static bool _winSupportRWLockPrimitive; + SRWLOCK _lock; + + // Genric implementation, fallback if native is not supported. + CriticalSectionWrapper* _critSectPtr; + ConditionVariableWrapper* _readCondPtr; + ConditionVariableWrapper* _writeCondPtr; + + int _readersActive; + bool _writerActive; + int _readersWaiting; + int _writersWaiting; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_RW_LOCK_WINDOWS_H_ diff --git a/src/system_wrappers/source/set_thread_name_win.h b/src/system_wrappers/source/set_thread_name_win.h new file mode 100644 index 0000000000..a46f4d6305 --- /dev/null +++ b/src/system_wrappers/source/set_thread_name_win.h @@ -0,0 +1,43 @@ +/* + * Use of this source code is governed by the MICROSOFT LIMITED PUBLIC LICENSE + * copyright license which can be found in the LICENSE file in the + * third_party_mods/mslpl directory of the source tree or at + * http://msdn.microsoft.com/en-us/cc300389.aspx#P. + */ +/* + * The original code can be found here: + * http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.71).aspx + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_SET_NAME_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_SET_NAME_H_ + +namespace webrtc { + +struct THREADNAME_INFO +{ + DWORD dwType; // must be 0x1000 + LPCSTR szName; // pointer to name (in user addr space) + DWORD dwThreadID; // thread ID (-1 = caller thread) + DWORD dwFlags; // reserved for future use, must be zero +}; + +void SetThreadName(DWORD dwThreadID, LPCSTR szThreadName) +{ + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = szThreadName; + info.dwThreadID = dwThreadID; + info.dwFlags = 0; + + __try + { + RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), + (ULONG_PTR*)&info); + } + __except (EXCEPTION_CONTINUE_EXECUTION) + { + } +} +} // namespace webrtc +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_SET_NAME_H_ diff --git a/src/system_wrappers/source/sleep.cc b/src/system_wrappers/source/sleep.cc new file mode 100644 index 0000000000..be8523857c --- /dev/null +++ b/src/system_wrappers/source/sleep.cc @@ -0,0 +1,36 @@ +/* + * 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. + */ +// An OS-independent sleep function. + +#include "system_wrappers/interface/sleep.h" + +#ifdef _WIN32 +// For Sleep() +#include <windows.h> +#else +// For nanosleep() +#include <time.h> +#endif + +namespace webrtc { + +void SleepMs(int msecs) { +#ifdef _WIN32 + Sleep(msecs); +#else + struct timespec short_wait; + struct timespec remainder; + short_wait.tv_sec = msecs / 1000; + short_wait.tv_nsec = (msecs % 1000) * 1000 * 1000; + nanosleep(&short_wait, &remainder); +#endif +} + +} // namespace webrtc diff --git a/src/system_wrappers/source/sort.cc b/src/system_wrappers/source/sort.cc index f44b644978..34aa4373ee 100644 --- a/src/system_wrappers/source/sort.cc +++ b/src/system_wrappers/source/sort.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -412,8 +412,6 @@ namespace webrtc case TYPE_Float64: StdSort<double>(data, numOfElements); break; - default: - return -1; } #endif return 0; @@ -543,9 +541,9 @@ namespace webrtc return StdKeySort<float>(data, key, numOfElements, sizeOfElement); case TYPE_Float64: return StdKeySort<double>(data, key, numOfElements, sizeOfElement); - default: - return -1; } + assert(false); + return -1; #endif } } // namespace webrtc diff --git a/src/system_wrappers/source/system_wrappers.gyp b/src/system_wrappers/source/system_wrappers.gyp index ce2438ffe9..b530d6f483 100644 --- a/src/system_wrappers/source/system_wrappers.gyp +++ b/src/system_wrappers/source/system_wrappers.gyp @@ -1,4 +1,4 @@ -# Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. +# 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 @@ -23,7 +23,8 @@ }, 'sources': [ '../interface/aligned_malloc.h', - '../interface/atomic32_wrapper.h', + '../interface/atomic32.h', + '../interface/compile_assert.h', '../interface/condition_variable_wrapper.h', '../interface/cpu_info.h', '../interface/cpu_wrapper.h', @@ -41,16 +42,16 @@ '../interface/rw_lock_wrapper.h', '../interface/scoped_ptr.h', '../interface/scoped_refptr.h', + '../interface/sleep.h', '../interface/sort.h', '../interface/static_instance.h', '../interface/thread_wrapper.h', '../interface/tick_util.h', '../interface/trace.h', 'aligned_malloc.cc', - 'atomic32.cc', - 'atomic32_linux.h', - 'atomic32_mac.h', - 'atomic32_win.h', + 'atomic32_mac.cc', + 'atomic32_posix.cc', + 'atomic32_win.cc', 'condition_variable.cc', 'condition_variable_posix.cc', 'condition_variable_posix.h', @@ -88,6 +89,7 @@ 'rw_lock_posix.h', 'rw_lock_win.cc', 'rw_lock_win.h', + 'sleep.cc', 'sort.cc', 'thread.cc', 'thread_posix.cc', @@ -109,6 +111,9 @@ },{ 'sources!': [ 'data_log.cc', ], },], + ['OS=="android"', { + 'dependencies': [ 'cpu_features_android', ], + }], ['OS=="linux"', { 'link_settings': { 'libraries': [ '-lrt', ], @@ -118,6 +123,9 @@ 'link_settings': { 'libraries': [ '$(SDKROOT)/System/Library/Frameworks/ApplicationServices.framework', ], }, + 'sources!': [ + 'atomic32_posix.cc', + ], }], ['OS=="win"', { 'link_settings': { @@ -147,18 +155,41 @@ }, ], # targets 'conditions': [ - ['build_with_chromium==0', { + ['OS=="android"', { + 'targets': [ + { + 'variables': { + # Treat this as third-party code. + 'chromium_code': 0, + }, + 'target_name': 'cpu_features_android', + 'type': '<(library)', + 'sources': [ + 'android/cpu-features.c', + 'android/cpu-features.h', + # TODO(leozwang): Ideally we want to audomatically exclude .c files + # as with .cc files, gyp currently only excludes .cc files. + 'cpu_features_android.c', + ], + }, + ], + }], + ['include_tests==1', { 'targets': [ { 'target_name': 'system_wrappers_unittests', 'type': 'executable', 'dependencies': [ 'system_wrappers', - '<(webrtc_root)/../testing/gtest.gyp:gtest', - '<(webrtc_root)/../test/test.gyp:test_support_main', + '<(DEPTH)/testing/gtest.gyp:gtest', + '<(webrtc_root)/test/test.gyp:test_support_main', ], 'sources': [ + 'condition_variable_unittest.cc', 'cpu_wrapper_unittest.cc', + 'cpu_measurement_harness.h', + 'cpu_measurement_harness.cc', + 'critical_section_unittest.cc', 'list_unittest.cc', 'map_unittest.cc', 'data_log_unittest.cc', @@ -166,6 +197,9 @@ 'data_log_helpers_unittest.cc', 'data_log_c_helpers_unittest.c', 'data_log_c_helpers_unittest.h', + 'thread_unittest.cc', + 'trace_unittest.cc', + 'unittest_utilities_unittest.cc', ], 'conditions': [ ['enable_data_logging==1', { @@ -176,7 +210,7 @@ ], }, ], # targets - }], # build_with_chromium + }], # include_tests ], # conditions } diff --git a/src/system_wrappers/source/thread_posix.cc b/src/system_wrappers/source/thread_posix.cc index eb0e8f46a0..6334490f78 100644 --- a/src/system_wrappers/source/thread_posix.cc +++ b/src/system_wrappers/source/thread_posix.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -8,6 +8,40 @@ * be found in the AUTHORS file in the root of the source tree. */ +// The state of a thread is controlled by the two member variables +// _alive and _dead. +// _alive represents the state the thread has been ordered to achieve. +// It is set to true by the thread at startup, and is set to false by +// other threads, using SetNotAlive() and Stop(). +// _dead represents the state the thread has achieved. +// It is written by the thread encapsulated by this class only +// (except at init). It is read only by the Stop() method. +// The Run() method fires _event when it's started; this ensures that the +// Start() method does not continue until after _dead is false. +// This protects against premature Stop() calls from the creator thread, but +// not from other threads. + +// Their transitions and states: +// _alive _dead Set by +// false true Constructor +// true false Run() method entry +// false any Run() method runFunction failure +// any false Run() method exit (happens only with _alive false) +// false any SetNotAlive +// false any Stop Stop waits for _dead to become true. +// +// Summarized a different way: +// Variable Writer Reader +// _alive Constructor(false) Run.loop +// Run.start(true) +// Run.fail(false) +// SetNotAlive(false) +// Stop(false) +// +// _dead Constructor(true) Stop.loop +// Run.start(false) +// Run.exit(true) + #include "thread_posix.h" #include <errno.h> @@ -22,8 +56,13 @@ #include <sys/prctl.h> #endif -#include "event_wrapper.h" -#include "trace.h" +#if defined(WEBRTC_MAC) +#include <mach/mach.h> +#endif + +#include "system_wrappers/interface/critical_section_wrapper.h" +#include "system_wrappers/interface/event_wrapper.h" +#include "system_wrappers/interface/trace.h" namespace webrtc { extern "C" @@ -35,17 +74,6 @@ extern "C" } } -#if (defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID)) -static pid_t gettid() -{ -#if defined(__NR_gettid) - return syscall(__NR_gettid); -#else - return -1; -#endif -} -#endif - ThreadWrapper* ThreadPosix::Create(ThreadRunFunction func, ThreadObj obj, ThreadPriority prio, const char* threadName) { @@ -67,22 +95,37 @@ ThreadPosix::ThreadPosix(ThreadRunFunction func, ThreadObj obj, ThreadPriority prio, const char* threadName) : _runFunction(func), _obj(obj), + _crit_state(CriticalSectionWrapper::CreateCriticalSection()), _alive(false), _dead(true), _prio(prio), _event(EventWrapper::Create()), - _setThreadName(false) -{ -#ifdef WEBRTC_LINUX - _linuxPid = -1; + _name(), + _setThreadName(false), +#if (defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)) + _pid(-1), #endif + _attr(), + _thread(0) +{ if (threadName != NULL) { _setThreadName = true; strncpy(_name, threadName, kThreadMaxNameLength); + _name[kThreadMaxNameLength - 1] = '\0'; } } +uint32_t ThreadWrapper::GetThreadId() { +#if defined(WEBRTC_ANDROID) || defined(WEBRTC_LINUX) + return static_cast<uint32_t>(syscall(__NR_gettid)); +#elif defined(WEBRTC_MAC) + return static_cast<uint32_t>(mach_thread_self()); +#else + return reinterpret_cast<uint32_t>(pthread_self()); +#endif +} + int ThreadPosix::Construct() { int result = 0; @@ -104,7 +147,6 @@ int ThreadPosix::Construct() { return -1; } - return 0; } @@ -112,6 +154,7 @@ ThreadPosix::~ThreadPosix() { pthread_attr_destroy(&_attr); delete _event; + delete _crit_state; } #define HAS_THREAD_ID !defined(MAC_IPHONE) && !defined(MAC_IPHONE_SIM) && \ @@ -180,8 +223,6 @@ bool ThreadPosix::Start(unsigned int& /*threadID*/) case kRealtimePriority: param.sched_priority = maxPrio - 1; break; - default: - return false; } result = pthread_setschedparam(_thread, policy, ¶m); if (result == EINVAL) @@ -191,33 +232,40 @@ bool ThreadPosix::Start(unsigned int& /*threadID*/) return true; } -#if (defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID)) +// CPU_ZERO and CPU_SET are not available in NDK r7, so disable +// SetAffinity on Android for now. +#if (defined(WEBRTC_LINUX) && (!defined(WEBRTC_ANDROID))) bool ThreadPosix::SetAffinity(const int* processorNumbers, - const unsigned int amountOfProcessors) -{ - if (!processorNumbers || (amountOfProcessors == 0)) - { - return false; - } - - cpu_set_t mask; - CPU_ZERO(&mask); - - for(unsigned int processor = 0; - processor < amountOfProcessors; - processor++) - { - CPU_SET(processorNumbers[processor], &mask); - } - const int result = sched_setaffinity(_linuxPid, (unsigned int)sizeof(mask), - &mask); - if (result != 0) - { - return false; + const unsigned int amountOfProcessors) { + if (!processorNumbers || (amountOfProcessors == 0)) { + return false; + } + cpu_set_t mask; + CPU_ZERO(&mask); - } - return true; + for (unsigned int processor = 0; + processor < amountOfProcessors; + processor++) { + CPU_SET(processorNumbers[processor], &mask); + } +#if defined(WEBRTC_ANDROID) + // Android. + const int result = syscall(__NR_sched_setaffinity, + _pid, + sizeof(mask), + &mask); +#else + // "Normal" Linux. + const int result = sched_setaffinity(_pid, + sizeof(mask), + &mask); +#endif + if (result != 0) { + return false; + } + return true; } + #else // NOTE: On Mac OS X, use the Thread affinity API in // /usr/include/mach/thread_policy.h: thread_policy_set and mach_thread_self() @@ -230,6 +278,7 @@ bool ThreadPosix::SetAffinity(const int* , const unsigned int) void ThreadPosix::SetNotAlive() { + CriticalSectionScoped cs(_crit_state); _alive = false; } @@ -249,18 +298,27 @@ bool ThreadPosix::Shutdown() bool ThreadPosix::Stop() { - _alive = false; + bool dead = false; + { + CriticalSectionScoped cs(_crit_state); + _alive = false; + dead = _dead; + } // TODO (hellner) why not use an event here? // Wait up to 10 seconds for the thread to terminate - for (int i = 0; i < 1000 && !_dead; i++) + for (int i = 0; i < 1000 && !dead; i++) { timespec t; t.tv_sec = 0; t.tv_nsec = 10*1000*1000; nanosleep(&t, NULL); + { + CriticalSectionScoped cs(_crit_state); + dead = _dead; + } } - if (_dead) + if (dead) { return true; } @@ -272,13 +330,13 @@ bool ThreadPosix::Stop() void ThreadPosix::Run() { - _alive = true; - _dead = false; -#ifdef WEBRTC_LINUX - if(_linuxPid == -1) { - _linuxPid = gettid(); + CriticalSectionScoped cs(_crit_state); + _alive = true; + _dead = false; } +#if (defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)) + _pid = GetThreadId(); #endif // The event the Start() is waiting for. _event->Set(); @@ -286,38 +344,38 @@ void ThreadPosix::Run() if (_setThreadName) { #ifdef WEBRTC_LINUX - WEBRTC_TRACE(kTraceStateInfo, kTraceUtility,-1, - "Thread with id:%d name:%s started ", _linuxPid, _name); prctl(PR_SET_NAME, (unsigned long)_name, 0, 0, 0); -#else +#endif WEBRTC_TRACE(kTraceStateInfo, kTraceUtility,-1, "Thread with name:%s started ", _name); -#endif - }else + } else { -#ifdef WEBRTC_LINUX - WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, - "Thread with id:%d without name started", _linuxPid); -#else WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, "Thread without name started"); -#endif } + bool alive = true; do { if (_runFunction) { if (!_runFunction(_obj)) { - _alive = false; + alive = false; } } else { - _alive = false; + alive = false; + } + { + CriticalSectionScoped cs(_crit_state); + if (!alive) { + _alive = false; + } + alive = _alive; } } - while (_alive); + while (alive); if (_setThreadName) { @@ -335,6 +393,9 @@ void ThreadPosix::Run() WEBRTC_TRACE(kTraceStateInfo, kTraceUtility,-1, "Thread without name stopped"); } - _dead = true; + { + CriticalSectionScoped cs(_crit_state); + _dead = true; + } } } // namespace webrtc diff --git a/src/system_wrappers/source/thread_posix.h b/src/system_wrappers/source/thread_posix.h index f664a52e70..45489a8622 100644 --- a/src/system_wrappers/source/thread_posix.h +++ b/src/system_wrappers/source/thread_posix.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -15,6 +15,8 @@ #include <pthread.h> namespace webrtc { + +class CriticalSectionWrapper; class EventWrapper; class ThreadPosix : public ThreadWrapper @@ -47,6 +49,7 @@ private: ThreadObj _obj; // internal state + CriticalSectionWrapper* _crit_state; // Protects _alive and _dead bool _alive; bool _dead; ThreadPriority _prio; @@ -57,12 +60,11 @@ private: bool _setThreadName; // handle to thread +#if (defined(WEBRTC_LINUX) || defined(WEBRTC_ANDROID)) + pid_t _pid; +#endif pthread_attr_t _attr; pthread_t _thread; -#ifdef WEBRTC_LINUX - pid_t _linuxPid; -#endif - }; } // namespace webrtc diff --git a/src/system_wrappers/source/thread_unittest.cc b/src/system_wrappers/source/thread_unittest.cc new file mode 100644 index 0000000000..361424a7fb --- /dev/null +++ b/src/system_wrappers/source/thread_unittest.cc @@ -0,0 +1,96 @@ +/* + * 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 "system_wrappers/interface/thread_wrapper.h" + +#include "gtest/gtest.h" +#include "system_wrappers/interface/trace.h" + +namespace webrtc { + +const int kLogTrace = 0; + +class TestTraceCallback : public TraceCallback { + public: + virtual void Print(const TraceLevel level, + const char* traceString, + const int length) { + if (traceString) { + char* cmd_print = new char[length+1]; + memcpy(cmd_print, traceString, length); + cmd_print[length] = '\0'; + printf("%s\n", cmd_print); + fflush(stdout); + delete[] cmd_print; + } + } +}; + +class ThreadTest : public ::testing::Test { + public: + ThreadTest() { + StartTrace(); + } + ~ThreadTest() { + StopTrace(); + } + + private: + void StartTrace() { + if (kLogTrace) { + Trace::CreateTrace(); + Trace::SetLevelFilter(webrtc::kTraceAll); + Trace::SetTraceCallback(&trace_); + } + } + + void StopTrace() { + if (kLogTrace) { + Trace::ReturnTrace(); + } + } + + TestTraceCallback trace_; +}; + +// Function that does nothing, and reports success. +bool NullRunFunction(void* /* obj */) { + return true; +} + +TEST_F(ThreadTest, StartStop) { + ThreadWrapper* thread = ThreadWrapper::CreateThread(&NullRunFunction); + unsigned int id = 42; + ASSERT_TRUE(thread->Start(id)); + EXPECT_TRUE(thread->Stop()); + delete thread; +} + +// Function that sets a boolean. +bool SetFlagRunFunction(void* obj) { + bool* obj_as_bool = static_cast<bool*> (obj); + *obj_as_bool = true; + return true; +} + +TEST_F(ThreadTest, RunFunctionIsCalled) { + bool flag = false; + ThreadWrapper* thread = ThreadWrapper::CreateThread(&SetFlagRunFunction, + &flag); + unsigned int id = 42; + ASSERT_TRUE(thread->Start(id)); + // At this point, the flag may be either true or false. + EXPECT_TRUE(thread->Stop()); + // We expect the thread to have run at least once. + EXPECT_TRUE(flag); + delete thread; +} + +} // namespace webrtc diff --git a/src/system_wrappers/source/thread_win.cc b/src/system_wrappers/source/thread_win.cc new file mode 100644 index 0000000000..07c586a87c --- /dev/null +++ b/src/system_wrappers/source/thread_win.cc @@ -0,0 +1,233 @@ +/* + * 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 "thread_win.h" + +#include <assert.h> +#include <process.h> +#include <stdio.h> +#include <windows.h> + +#include "set_thread_name_win.h" +#include "trace.h" + +namespace webrtc { +ThreadWindows::ThreadWindows(ThreadRunFunction func, ThreadObj obj, + ThreadPriority prio, const char* threadName) + : ThreadWrapper(), + _runFunction(func), + _obj(obj), + _alive(false), + _dead(true), + _doNotCloseHandle(false), + _prio(prio), + _event(NULL), + _thread(NULL), + _id(0), + _name(), + _setThreadName(false) +{ + _event = EventWrapper::Create(); + _critsectStop = CriticalSectionWrapper::CreateCriticalSection(); + if (threadName != NULL) + { + // Set the thread name to appear in the VS debugger. + _setThreadName = true; + strncpy(_name, threadName, kThreadMaxNameLength); + } +} + +ThreadWindows::~ThreadWindows() +{ +#ifdef _DEBUG + assert(!_alive); +#endif + if (_thread) + { + CloseHandle(_thread); + } + if(_event) + { + delete _event; + } + if(_critsectStop) + { + delete _critsectStop; + } +} + +uint32_t ThreadWrapper::GetThreadId() { + return GetCurrentThreadId(); +} + +unsigned int WINAPI ThreadWindows::StartThread(LPVOID lpParameter) +{ + static_cast<ThreadWindows*>(lpParameter)->Run(); + return 0; +} + +bool ThreadWindows::Start(unsigned int& threadID) +{ + _doNotCloseHandle = false; + + // Set stack size to 1M + _thread=(HANDLE)_beginthreadex(NULL, 1024*1024, StartThread, (void*)this, 0, + &threadID); + if(_thread == NULL) + { + return false; + } + _id = threadID; + _event->Wait(INFINITE); + + switch(_prio) + { + case kLowPriority: + SetThreadPriority(_thread, THREAD_PRIORITY_BELOW_NORMAL); + break; + case kNormalPriority: + SetThreadPriority(_thread, THREAD_PRIORITY_NORMAL); + break; + case kHighPriority: + SetThreadPriority(_thread, THREAD_PRIORITY_ABOVE_NORMAL); + break; + case kHighestPriority: + SetThreadPriority(_thread, THREAD_PRIORITY_HIGHEST); + break; + case kRealtimePriority: + SetThreadPriority(_thread, THREAD_PRIORITY_TIME_CRITICAL); + break; + }; + return true; +} + +bool ThreadWindows::SetAffinity(const int* processorNumbers, + const unsigned int amountOfProcessors) +{ + DWORD_PTR processorBitMask = 0; + for(unsigned int processorIndex = 0; + processorIndex < amountOfProcessors; + processorIndex++) + { + // Convert from an array with processor numbers to a bitmask + // Processor numbers start at zero. + // TODO (hellner): this looks like a bug. Shouldn't the '=' be a '+='? + // Or even better |= + processorBitMask = 1 << processorNumbers[processorIndex]; + } + return SetThreadAffinityMask(_thread,processorBitMask) != 0; +} + +void ThreadWindows::SetNotAlive() +{ + _alive = false; +} + +bool ThreadWindows::Shutdown() +{ + DWORD exitCode = 0; + BOOL ret = TRUE; + if (_thread) + { + ret = TerminateThread(_thread, exitCode); + _alive = false; + _dead = true; + _thread = NULL; + } + return ret == TRUE; +} + +bool ThreadWindows::Stop() +{ + _critsectStop->Enter(); + // Prevents the handle from being closed in ThreadWindows::Run() + _doNotCloseHandle = true; + _alive = false; + bool signaled = false; + if (_thread && !_dead) + { + _critsectStop->Leave(); + // Wait up to 2 seconds for the thread to complete. + if( WAIT_OBJECT_0 == WaitForSingleObject(_thread, 2000)) + { + signaled = true; + } + _critsectStop->Enter(); + } + if (_thread) + { + CloseHandle(_thread); + _thread = NULL; + } + _critsectStop->Leave(); + + if (_dead || signaled) + { + return true; + } + else + { + return false; + } +} + +void ThreadWindows::Run() +{ + _alive = true; + _dead = false; + _event->Set(); + + // All tracing must be after _event->Set to avoid deadlock in Trace. + if (_setThreadName) + { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, _id, + "Thread with name:%s started ", _name); + SetThreadName(-1, _name); // -1, set thread name for the calling thread. + }else + { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, _id, + "Thread without name started"); + } + + do + { + if (_runFunction) + { + if (!_runFunction(_obj)) + { + _alive = false; + } + } else { + _alive = false; + } + } while(_alive); + + if (_setThreadName) + { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, _id, + "Thread with name:%s stopped", _name); + } else { + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility,_id, + "Thread without name stopped"); + } + + _critsectStop->Enter(); + + if (_thread && !_doNotCloseHandle) + { + HANDLE thread = _thread; + _thread = NULL; + CloseHandle(thread); + } + _dead = true; + + _critsectStop->Leave(); +}; +} // namespace webrtc diff --git a/src/system_wrappers/source/thread_win.h b/src/system_wrappers/source/thread_win.h new file mode 100644 index 0000000000..4fd7523ec9 --- /dev/null +++ b/src/system_wrappers/source/thread_win.h @@ -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. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_H_ + +#include "thread_wrapper.h" +#include "event_wrapper.h" +#include "critical_section_wrapper.h" + +#include <windows.h> + +namespace webrtc { + +class ThreadWindows : public ThreadWrapper +{ +public: + ThreadWindows(ThreadRunFunction func, ThreadObj obj, ThreadPriority prio, + const char* threadName); + virtual ~ThreadWindows(); + + virtual bool Start(unsigned int& id); + bool SetAffinity(const int* processorNumbers, + const unsigned int amountOfProcessors); + virtual bool Stop(); + virtual void SetNotAlive(); + + static unsigned int WINAPI StartThread(LPVOID lpParameter); + + virtual bool Shutdown(); + +protected: + virtual void Run(); + +private: + ThreadRunFunction _runFunction; + ThreadObj _obj; + + bool _alive; + bool _dead; + + // TODO (hellner) + // _doNotCloseHandle member seem pretty redundant. Should be able to remove + // it. Basically it should be fine to reclaim the handle when calling stop + // and in the destructor. + bool _doNotCloseHandle; + ThreadPriority _prio; + EventWrapper* _event; + CriticalSectionWrapper* _critsectStop; + + HANDLE _thread; + unsigned int _id; + char _name[kThreadMaxNameLength]; + bool _setThreadName; + +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_THREAD_WINDOWS_H_ diff --git a/src/system_wrappers/source/trace_impl.cc b/src/system_wrappers/source/trace_impl.cc index 1156519eb9..c6d9296651 100644 --- a/src/system_wrappers/source/trace_impl.cc +++ b/src/system_wrappers/source/trace_impl.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -17,17 +17,16 @@ #include "trace_win.h" #else #include <stdio.h> -#include <time.h> #include <stdarg.h> #include "trace_posix.h" #endif // _WIN32 +#include "system_wrappers/interface/sleep.h" + #define KEY_LEN_CHARS 31 #ifdef _WIN32 - #pragma warning(disable:4355) -// VS 2005: Disable warnings for default initialized arrays. - #pragma warning(disable:4351) +#pragma warning(disable:4355) #endif // _WIN32 namespace webrtc { @@ -94,7 +93,7 @@ TraceImpl::TraceImpl() for(int n = 0; n < WEBRTC_TRACE_MAX_QUEUE; n++) { _messageQueue[m][n] = new - WebRtc_Word8[WEBRTC_TRACE_MAX_MESSAGE_SIZE]; + char[WEBRTC_TRACE_MAX_MESSAGE_SIZE]; } } } @@ -108,14 +107,7 @@ bool TraceImpl::StopThread() // TODO (hellner): why not use condition variables to do this? Or let the // worker thread die and let this thread flush remaining // messages? -#ifdef _WIN32 - Sleep(10); -#else - timespec t; - t.tv_sec = 0; - t.tv_nsec = 10*1000000; - nanosleep(&t,NULL); -#endif + SleepMs(10); _thread.SetNotAlive(); // Make sure the thread finishes as quickly as possible (instead of having @@ -147,6 +139,12 @@ TraceImpl::~TraceImpl() } } +WebRtc_Word32 TraceImpl::AddThreadId(char* traceMessage) const { + WebRtc_UWord32 threadId = ThreadWrapper::GetThreadId(); + // Messages is 12 characters. + return sprintf(traceMessage, "%10u; ", threadId); +} + WebRtc_Word32 TraceImpl::AddLevel(char* szMessage, const TraceLevel level) const { switch (level) @@ -277,9 +275,6 @@ WebRtc_Word32 TraceImpl::AddModuleAndId(char* traceMessage, sprintf(traceMessage, " VIDEO PROC:%5ld %5ld;", idEngine, idChannel); break; - default: - assert(false); - return 0; } } else { switch (module) @@ -335,16 +330,13 @@ WebRtc_Word32 TraceImpl::AddModuleAndId(char* traceMessage, case kTraceVideoPreocessing: sprintf (traceMessage, " VIDEO PROC:%11ld;", idl); break; - default: - assert(false); - return 0; } } // All messages are 25 characters. return 25; } -WebRtc_Word32 TraceImpl::SetTraceFileImpl(const WebRtc_Word8* fileNameUTF8, +WebRtc_Word32 TraceImpl::SetTraceFileImpl(const char* fileNameUTF8, const bool addFileCounter) { CriticalSectionScoped lock(_critsectInterface); @@ -358,7 +350,7 @@ WebRtc_Word32 TraceImpl::SetTraceFileImpl(const WebRtc_Word8* fileNameUTF8, { _fileCountText = 1; - WebRtc_Word8 fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize]; + char fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize]; CreateFileName(fileNameUTF8, fileNameWithCounterUTF8, _fileCountText); if(_traceFile.OpenFile(fileNameWithCounterUTF8, false, false, @@ -379,7 +371,7 @@ WebRtc_Word32 TraceImpl::SetTraceFileImpl(const WebRtc_Word8* fileNameUTF8, } WebRtc_Word32 TraceImpl::TraceFileImpl( - WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize]) + char fileNameUTF8[FileWrapper::kMaxFileNameSize]) { CriticalSectionScoped lock(_critsectInterface); return _traceFile.FileName(fileNameUTF8, FileWrapper::kMaxFileNameSize); @@ -429,8 +421,14 @@ WebRtc_Word32 TraceImpl::AddMessage( void TraceImpl::AddMessageToList( const char traceMessage[WEBRTC_TRACE_MAX_MESSAGE_SIZE], const WebRtc_UWord16 length, - const TraceLevel level) -{ + const TraceLevel level) { +#ifdef WEBRTC_DIRECT_TRACE + if (_callback) { + _callback->Print(level, traceMessage, length); + } + return; +#endif + CriticalSectionScoped lock(_critsectArray); if(_nextFreeIdx[_activeQueue] >= WEBRTC_TRACE_MAX_QUEUE) @@ -550,8 +548,8 @@ void TraceImpl::WriteToFile() _traceFile.Rewind(); } else { - WebRtc_Word8 oldFileName[FileWrapper::kMaxFileNameSize]; - WebRtc_Word8 newFileName[FileWrapper::kMaxFileNameSize]; + char oldFileName[FileWrapper::kMaxFileNameSize]; + char newFileName[FileWrapper::kMaxFileNameSize]; // get current name _traceFile.FileName(oldFileName, @@ -571,7 +569,7 @@ void TraceImpl::WriteToFile() } if(_rowCountText == 0) { - WebRtc_Word8 message[WEBRTC_TRACE_MAX_MESSAGE_SIZE + 1]; + char message[WEBRTC_TRACE_MAX_MESSAGE_SIZE + 1]; WebRtc_Word32 length = AddDateTimeInfo(message); if(length != -1) { @@ -637,7 +635,7 @@ void TraceImpl::AddImpl(const TraceLevel level, const TraceModule module, ackLen += len; len = AddThreadId(meassagePtr); - if(len == -1) + if(len < 0) { return; } @@ -663,8 +661,8 @@ bool TraceImpl::TraceCheck(const TraceLevel level) const } bool TraceImpl::UpdateFileName( - const WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize], - WebRtc_Word8 fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize], + const char fileNameUTF8[FileWrapper::kMaxFileNameSize], + char fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize], const WebRtc_UWord32 newCount) const { WebRtc_Word32 length = (WebRtc_Word32)strlen(fileNameUTF8); @@ -706,8 +704,8 @@ bool TraceImpl::UpdateFileName( } bool TraceImpl::CreateFileName( - const WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize], - WebRtc_Word8 fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize], + const char fileNameUTF8[FileWrapper::kMaxFileNameSize], + char fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize], const WebRtc_UWord32 newCount) const { WebRtc_Word32 length = (WebRtc_Word32)strlen(fileNameUTF8); @@ -760,7 +758,7 @@ WebRtc_Word32 Trace::LevelFilter(WebRtc_UWord32& filter) return 0; } -WebRtc_Word32 Trace::TraceFile(WebRtc_Word8 fileName[FileWrapper::kMaxFileNameSize]) +WebRtc_Word32 Trace::TraceFile(char fileName[FileWrapper::kMaxFileNameSize]) { TraceImpl* trace = TraceImpl::GetTrace(); if(trace) @@ -772,7 +770,7 @@ WebRtc_Word32 Trace::TraceFile(WebRtc_Word8 fileName[FileWrapper::kMaxFileNameSi return -1; } -WebRtc_Word32 Trace::SetTraceFile(const WebRtc_Word8* fileName, +WebRtc_Word32 Trace::SetTraceFile(const char* fileName, const bool addFileCounter) { TraceImpl* trace = TraceImpl::GetTrace(); diff --git a/src/system_wrappers/source/trace_impl.h b/src/system_wrappers/source/trace_impl.h index 455a3d5523..2b85813a88 100644 --- a/src/system_wrappers/source/trace_impl.h +++ b/src/system_wrappers/source/trace_impl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -49,10 +49,10 @@ public: static TraceImpl* CreateInstance(); static TraceImpl* GetTrace(const TraceLevel level = kTraceAll); - WebRtc_Word32 SetTraceFileImpl(const WebRtc_Word8* fileName, + WebRtc_Word32 SetTraceFileImpl(const char* fileName, const bool addFileCounter); WebRtc_Word32 TraceFileImpl( - WebRtc_Word8 fileName[FileWrapper::kMaxFileNameSize]); + char fileName[FileWrapper::kMaxFileNameSize]); WebRtc_Word32 SetTraceCallbackImpl(TraceCallback* callback); @@ -69,8 +69,9 @@ protected: static TraceImpl* StaticInstance(CountOperation count_operation, const TraceLevel level = kTraceAll); + WebRtc_Word32 AddThreadId(char* traceMessage) const; + // OS specific implementations - virtual WebRtc_Word32 AddThreadId(char* traceMessage) const = 0; virtual WebRtc_Word32 AddTime(char* traceMessage, const TraceLevel level) const = 0; @@ -98,13 +99,13 @@ private: const TraceLevel level); bool UpdateFileName( - const WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize], - WebRtc_Word8 fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize], + const char fileNameUTF8[FileWrapper::kMaxFileNameSize], + char fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize], const WebRtc_UWord32 newCount) const; bool CreateFileName( - const WebRtc_Word8 fileNameUTF8[FileWrapper::kMaxFileNameSize], - WebRtc_Word8 fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize], + const char fileNameUTF8[FileWrapper::kMaxFileNameSize], + char fileNameWithCounterUTF8[FileWrapper::kMaxFileNameSize], const WebRtc_UWord32 newCount) const; void WriteToFile(); @@ -123,7 +124,7 @@ private: WebRtc_UWord16 _nextFreeIdx[WEBRTC_TRACE_NUM_ARRAY]; TraceLevel _level[WEBRTC_TRACE_NUM_ARRAY][WEBRTC_TRACE_MAX_QUEUE]; WebRtc_UWord16 _length[WEBRTC_TRACE_NUM_ARRAY][WEBRTC_TRACE_MAX_QUEUE]; - WebRtc_Word8* _messageQueue[WEBRTC_TRACE_NUM_ARRAY][WEBRTC_TRACE_MAX_QUEUE]; + char* _messageQueue[WEBRTC_TRACE_NUM_ARRAY][WEBRTC_TRACE_MAX_QUEUE]; WebRtc_UWord8 _activeQueue; }; } // namespace webrtc diff --git a/src/system_wrappers/source/trace_impl_no_op.cc b/src/system_wrappers/source/trace_impl_no_op.cc index 17528711bc..e74d901a54 100644 --- a/src/system_wrappers/source/trace_impl_no_op.cc +++ b/src/system_wrappers/source/trace_impl_no_op.cc @@ -31,12 +31,12 @@ WebRtc_Word32 Trace::LevelFilter(WebRtc_UWord32& /*filter*/) } WebRtc_Word32 Trace::TraceFile( - WebRtc_Word8 /*fileName*/[1024]) + char/*fileName*/[1024]) { return -1; } -WebRtc_Word32 Trace::SetTraceFile(const WebRtc_Word8* /*fileName*/, +WebRtc_Word32 Trace::SetTraceFile(const char* /*fileName*/, const bool /*addFileCounter*/) { return -1; diff --git a/src/system_wrappers/source/trace_posix.cc b/src/system_wrappers/source/trace_posix.cc index 198c4349b0..1b8dd934d2 100644 --- a/src/system_wrappers/source/trace_posix.cc +++ b/src/system_wrappers/source/trace_posix.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * 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 @@ -14,10 +14,8 @@ #include <stdarg.h> #include <stdio.h> #include <string.h> +#include <sys/time.h> #include <time.h> -#ifdef __linux__ - #include <sys/syscall.h> -#endif #ifdef WEBRTC_ANDROID #include <pthread.h> #else @@ -41,8 +39,9 @@ namespace webrtc { TracePosix::TracePosix() { - _prevAPITickCount = time(NULL); - _prevTickCount = _prevAPITickCount; + struct timeval systemTimeHighRes; + gettimeofday(&systemTimeHighRes, 0); + _prevAPITickCount = _prevTickCount = systemTimeHighRes.tv_sec; } TracePosix::~TracePosix() @@ -50,69 +49,47 @@ TracePosix::~TracePosix() StopThread(); } -WebRtc_Word32 TracePosix::AddThreadId(char* traceMessage) const { -#ifdef __linux__ - pid_t threadId = (pid_t) syscall(__NR_gettid); - sprintf(traceMessage, "%10d; ", threadId); -#else - WebRtc_UWord64 threadId = (WebRtc_UWord64)pthread_self(); - sprintf(traceMessage, "%10llu; ", - static_cast<long long unsigned int>(threadId)); -#endif - // 12 bytes are written. - return 12; -} - WebRtc_Word32 TracePosix::AddTime(char* traceMessage, const TraceLevel level) const { - time_t dwCurrentTimeInSeconds = time(NULL); - struct tm systemTime; - gmtime_r(&dwCurrentTimeInSeconds, &systemTime); - - if(level == kTraceApiCall) + struct timeval systemTimeHighRes; + if (gettimeofday(&systemTimeHighRes, 0) == -1) { - WebRtc_UWord32 dwDeltaTime = dwCurrentTimeInSeconds - _prevTickCount; - _prevTickCount = dwCurrentTimeInSeconds; - - if(_prevTickCount == 0) - { - dwDeltaTime = 0; - } - if(dwDeltaTime > 0x0fffffff) - { - // Either wraparound or data race. - dwDeltaTime = 0; - } - if(dwDeltaTime > 99999) - { - dwDeltaTime = 99999; - } + return -1; + } + struct tm buffer; + const struct tm* systemTime = + localtime_r(&systemTimeHighRes.tv_sec, &buffer); - sprintf(traceMessage, "(%2u:%2u:%2u:%3u |%5lu) ", systemTime.tm_hour, - systemTime.tm_min, systemTime.tm_sec, 0, - static_cast<unsigned long>(dwDeltaTime)); + const WebRtc_UWord32 ms_time = systemTimeHighRes.tv_usec / 1000; + WebRtc_UWord32 prevTickCount = 0; + if (level == kTraceApiCall) + { + prevTickCount = _prevTickCount; + _prevTickCount = ms_time; } else { - WebRtc_UWord32 dwDeltaTime = dwCurrentTimeInSeconds - _prevAPITickCount; - _prevAPITickCount = dwCurrentTimeInSeconds; - if(_prevAPITickCount == 0) - { - dwDeltaTime = 0; - } - if(dwDeltaTime > 0x0fffffff) - { - // Either wraparound or data race. - dwDeltaTime = 0; - } - if(dwDeltaTime > 99999) - { - dwDeltaTime = 99999; - } - sprintf(traceMessage, "(%2u:%2u:%2u:%3u |%5lu) ", systemTime.tm_hour, - systemTime.tm_min, systemTime.tm_sec, 0, - static_cast<unsigned long>(dwDeltaTime)); + prevTickCount = _prevAPITickCount; + _prevAPITickCount = ms_time; + } + WebRtc_UWord32 dwDeltaTime = ms_time - prevTickCount; + if (prevTickCount == 0) + { + dwDeltaTime = 0; + } + if (dwDeltaTime > 0x0fffffff) + { + // Either wraparound or data race. + dwDeltaTime = 0; + } + if(dwDeltaTime > 99999) + { + dwDeltaTime = 99999; } - // Messages is 22 characters. + + sprintf(traceMessage, "(%2u:%2u:%2u:%3u |%5lu) ", systemTime->tm_hour, + systemTime->tm_min, systemTime->tm_sec, ms_time, + static_cast<unsigned long>(dwDeltaTime)); + // Messages are 22 characters. return 22; } @@ -127,7 +104,8 @@ WebRtc_Word32 TracePosix::AddDateTimeInfo(char* traceMessage) const { time_t t; time(&t); - sprintf(traceMessage, "Local Date: %s", ctime(&t)); + char buffer[26]; // man ctime says buffer should have room for >=26 bytes. + sprintf(traceMessage, "Local Date: %s", ctime_r(&t, buffer)); WebRtc_Word32 len = static_cast<WebRtc_Word32>(strlen(traceMessage)); if ('\n' == traceMessage[len - 1]) diff --git a/src/system_wrappers/source/trace_posix.h b/src/system_wrappers/source/trace_posix.h index 099bcc874e..8c37cd2b4e 100644 --- a/src/system_wrappers/source/trace_posix.h +++ b/src/system_wrappers/source/trace_posix.h @@ -21,7 +21,6 @@ public: TracePosix(); virtual ~TracePosix(); - virtual WebRtc_Word32 AddThreadId(char *traceMessage) const; virtual WebRtc_Word32 AddTime(char* traceMessage, const TraceLevel level) const; diff --git a/src/system_wrappers/source/trace_unittest.cc b/src/system_wrappers/source/trace_unittest.cc new file mode 100644 index 0000000000..982e715726 --- /dev/null +++ b/src/system_wrappers/source/trace_unittest.cc @@ -0,0 +1,57 @@ +/* + * 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 "system_wrappers/interface/trace.h" + +#include "gtest/gtest.h" +#include "system_wrappers/source/cpu_measurement_harness.h" +#include "testsupport/fileutils.h" + +using webrtc::CpuMeasurementHarness; +using webrtc::Trace; +using webrtc::kTraceWarning; +using webrtc::kTraceUtility; + +class Logger : public webrtc::CpuTarget { + public: + Logger() { + Trace::CreateTrace(); + std::string trace_file = webrtc::test::OutputPath() + + "trace_unittest.txt"; + Trace::SetTraceFile(trace_file.c_str()); + Trace::SetLevelFilter(webrtc::kTraceAll); + } + virtual ~Logger() { + Trace::ReturnTrace(); + } + + virtual bool DoWork() { + // Use input paremeters to WEBRTC_TRACE that are not likely to be removed + // in future code. E.g. warnings will likely be kept and this file is in + // utility so it should use kTraceUtility. + WEBRTC_TRACE(kTraceWarning, kTraceUtility, 0, "Log line"); + return true; + } +}; + +// This test is disabled because it measures CPU usage. This is flaky because +// the CPU usage for a machine may spike due to OS or other application. +TEST(TraceTest, DISABLED_CpuUsage) { + Logger logger; + const int periodicity_ms = 1; + const int iterations_per_period = 10; + const int duration_ms = 1000; + CpuMeasurementHarness* cpu_harness = + CpuMeasurementHarness::Create(&logger, periodicity_ms, + iterations_per_period, duration_ms); + cpu_harness->Run(); + const int average_cpu = cpu_harness->AverageCpu(); + EXPECT_GE(5, average_cpu); +} diff --git a/src/system_wrappers/source/trace_win.cc b/src/system_wrappers/source/trace_win.cc new file mode 100644 index 0000000000..f81ed8b044 --- /dev/null +++ b/src/system_wrappers/source/trace_win.cc @@ -0,0 +1,131 @@ +/* + * 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 "trace_win.h" + +#include <cassert> +#include <stdarg.h> + +#include "Mmsystem.h" + +#if defined(_DEBUG) + #define BUILDMODE "d" +#elif defined(DEBUG) + #define BUILDMODE "d" +#elif defined(NDEBUG) + #define BUILDMODE "r" +#else + #define BUILDMODE "?" +#endif +#define BUILDTIME __TIME__ +#define BUILDDATE __DATE__ +// Example: "Oct 10 2002 12:05:30 r" +#define BUILDINFO BUILDDATE " " BUILDTIME " " BUILDMODE + +namespace webrtc { +TraceWindows::TraceWindows() + : _prevAPITickCount(0), + _prevTickCount(0) +{ +} + +TraceWindows::~TraceWindows() +{ + StopThread(); +} + +WebRtc_Word32 TraceWindows::AddTime(char* traceMessage, + const TraceLevel level) const +{ + WebRtc_UWord32 dwCurrentTime = timeGetTime(); + SYSTEMTIME systemTime; + GetSystemTime(&systemTime); + + if(level == kTraceApiCall) + { + WebRtc_UWord32 dwDeltaTime = dwCurrentTime- _prevTickCount; + _prevTickCount = dwCurrentTime; + + if(_prevTickCount == 0) + { + dwDeltaTime = 0; + } + if(dwDeltaTime > 0x0fffffff) + { + // Either wraparound or data race. + dwDeltaTime = 0; + } + if(dwDeltaTime > 99999) + { + dwDeltaTime = 99999; + } + + sprintf (traceMessage, "(%2u:%2u:%2u:%3u |%5lu) ", systemTime.wHour, + systemTime.wMinute, systemTime.wSecond, + systemTime.wMilliseconds, dwDeltaTime); + } else { + WebRtc_UWord32 dwDeltaTime = dwCurrentTime - _prevAPITickCount; + _prevAPITickCount = dwCurrentTime; + + if(_prevAPITickCount == 0) + { + dwDeltaTime = 0; + } + if(dwDeltaTime > 0x0fffffff) + { + // Either wraparound or data race. + dwDeltaTime = 0; + } + if(dwDeltaTime > 99999) + { + dwDeltaTime = 99999; + } + sprintf (traceMessage, "(%2u:%2u:%2u:%3u |%5lu) ", systemTime.wHour, + systemTime.wMinute, systemTime.wSecond, + systemTime.wMilliseconds, dwDeltaTime); + } + // Messages is 12 characters. + return 22; +} + +WebRtc_Word32 TraceWindows::AddBuildInfo(char* traceMessage) const +{ + // write data and time to text file + sprintf(traceMessage, "Build info: %s", BUILDINFO); + // Include NULL termination (hence + 1). + return static_cast<WebRtc_Word32>(strlen(traceMessage)+1); +} + +WebRtc_Word32 TraceWindows::AddDateTimeInfo(char* traceMessage) const +{ + _prevAPITickCount = timeGetTime(); + _prevTickCount = _prevAPITickCount; + + SYSTEMTIME sysTime; + GetLocalTime (&sysTime); + + TCHAR szDateStr[20]; + TCHAR szTimeStr[20]; + + // Create date string (e.g. Apr 04 2002) + GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, TEXT("MMM dd yyyy"), + szDateStr, 20); + + // Create time string (e.g. 15:32:08) + GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, &sysTime, TEXT("HH':'mm':'ss"), + szTimeStr, 20); + + sprintf(traceMessage, "Local Date: %s Local Time: %s", szDateStr, + szTimeStr); + + // Include NULL termination (hence + 1). + return static_cast<WebRtc_Word32>(strlen(traceMessage)+ 1); +} +} // namespace webrtc diff --git a/src/system_wrappers/source/trace_win.h b/src/system_wrappers/source/trace_win.h new file mode 100644 index 0000000000..803198e0fb --- /dev/null +++ b/src/system_wrappers/source/trace_win.h @@ -0,0 +1,36 @@ +/* + * 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_SYSTEM_WRAPPERS_SOURCE_TRACE_WINDOWS_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_WINDOWS_H_ + +#include "trace_impl.h" +#include <stdio.h> +#include <windows.h> + +namespace webrtc { +class TraceWindows : public TraceImpl +{ +public: + TraceWindows(); + virtual ~TraceWindows(); + + virtual WebRtc_Word32 AddTime(char* traceMessage, + const TraceLevel level) const; + + virtual WebRtc_Word32 AddBuildInfo(char* traceMessage) const; + virtual WebRtc_Word32 AddDateTimeInfo(char* traceMessage) const; +private: + volatile mutable WebRtc_UWord32 _prevAPITickCount; + volatile mutable WebRtc_UWord32 _prevTickCount; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_TRACE_WINDOWS_H_ diff --git a/src/system_wrappers/source/unittest_utilities.h b/src/system_wrappers/source/unittest_utilities.h new file mode 100644 index 0000000000..771d798f5d --- /dev/null +++ b/src/system_wrappers/source/unittest_utilities.h @@ -0,0 +1,83 @@ +/* + * 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. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_UNITTEST_UTILITIES_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_UNITTEST_UTILITIES_H_ + +// This file contains utilities that make it simpler to write unittests +// that are appropriate for the system_wrappers classes. + +#include <stdio.h> +#include <string.h> + +#include "system_wrappers/interface/trace.h" + +namespace webrtc { + +class TestTraceCallback : public TraceCallback { + public: + virtual void Print(const TraceLevel level, + const char* traceString, + const int length) { + if (traceString) { + char* cmd_print = new char[length+1]; + memcpy(cmd_print, traceString, length); + cmd_print[length] = '\0'; + printf("%s\n", cmd_print); + fflush(stdout); + delete[] cmd_print; + } + } +}; + +// A class that turns on tracing to stdout at the beginning of the test, +// and turns it off once the test is finished. +// Intended usage: +// class SomeTest : public ::testing::Test { +// protected: +// SomeTest() +// : trace_(false) {} // Change to true to turn on tracing. +// private: +// ScopedTracing trace_; +// } +class ScopedTracing { + public: + explicit ScopedTracing(bool logOn) { + logging_ = logOn; + StartTrace(); + } + + ~ScopedTracing() { + StopTrace(); + } + + private: + void StartTrace() { + if (logging_) { + Trace::CreateTrace(); + Trace::SetLevelFilter(webrtc::kTraceAll); + Trace::SetTraceCallback(&trace_); + } + } + + void StopTrace() { + if (logging_) { + Trace::ReturnTrace(); + } + } + + private: + bool logging_; + TestTraceCallback trace_; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_UNITTEST_UTILITIES_H_ diff --git a/src/system_wrappers/source/unittest_utilities_unittest.cc b/src/system_wrappers/source/unittest_utilities_unittest.cc new file mode 100644 index 0000000000..6e9a0c6186 --- /dev/null +++ b/src/system_wrappers/source/unittest_utilities_unittest.cc @@ -0,0 +1,34 @@ +/* + * 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 "system_wrappers/source/unittest_utilities.h" + +#include "gtest/gtest.h" +#include "system_wrappers/interface/trace.h" + +namespace webrtc { + +// These tests merely check that the code compiles and that no +// fatal accidents happen when logging. +TEST(UnittestUtilities, TraceOn) { + ScopedTracing trace(true); + WEBRTC_TRACE(kTraceInfo, kTraceUtility, 0, "Log line that should appear"); + // TODO(hta): Verify that output appears. + // Note - output is written on another thread, so can take time to appear. +} + +TEST(UnittestUtilities, TraceOff) { + ScopedTracing trace(false); + WEBRTC_TRACE(kTraceInfo, kTraceUtility, 0, + "Log line that should not appear"); + // TODO(hta): Verify that no output appears. +} + +} // namespace webrtc |