diff --git a/configure.in b/configure.in index 288d8829..4ced575d 100644 --- a/configure.in +++ b/configure.in @@ -314,6 +314,35 @@ AC_MSG_RESULT([$want_atomics]) fi AC_SUBST(ATOMIC_OPS) + +# Check for sse2 operations +SSE2_OPS=no +AC_ARG_ENABLE(sse2,AC_HELP_STRING([--enable-sse2],[Enable sse2 operations (default: no)]),want_sse2=$enableval,want_sse2=no) +AC_MSG_CHECKING([whether to use sse2 operations]) +if [[ "x$want_sse2" != "xno" ]]; then +AC_LANG_SAVE +AC_LANG_C +SAVE_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -Wall -Werror -msse2" +AC_TRY_LINK([#include +#include +#include +],[ +float ef[2][2]; +const __m128 k1e_10f = _mm_set1_ps(1e-10f); +_mm_storeu_ps(&ef[0][0], k1e_10f); +return (int) ef[0][0]; +], +SSE2_OPS="yes", +want_sse2="no (missing -march ?)" +) +CFLAGS="$SAVE_CFLAGS" +AC_LANG_RESTORE +fi +AC_MSG_RESULT([$want_sse2]) +AC_SUBST(SSE2_OPS) + + FDSIZE_HACK="" AC_ARG_WITH(fdsize,AC_HELP_STRING([--with-fdsize=NNNN],[set FD_SIZE to NNNN (default 8192)]),[ac_cv_use_fdsize=$withval],[ac_cv_use_fdsize=8192]) if [[ "x$ac_cv_use_fdsize" != "xno" ]]; then @@ -788,6 +817,39 @@ fi AC_SUBST(HAVE_ILBC) AC_SUBST(ILBC_INC) +HAVE_ISAC=no +ISAC_INC="" +AC_ARG_ENABLE(isac-float,AC_HELP_STRING([--enable-isac-float],[Enable iSAC float codec (default: yes)]),want_isac=$enableval,want_isac=yes) +if [[ "x$want_isac" = "xyes" ]]; then +AC_MSG_CHECKING([for iSAC in libs]) + basedir=`cd "$srcdir" && pwd` + incisac="libs/miniwebrtc/audio/coding_isac/main" + if [[ -f "$basedir/$incisac/isac.h" ]]; then + HAVE_ISAC=yes + basedir=`echo "$basedir" | sed 's/\([[^\]]\)\([[[:space:]\$\"'\'']]\)/\1\\\2/g'` + ISAC_INC="-I$basedir/$incisac" + fi +AC_MSG_RESULT([$HAVE_ISAC]) +fi + +AC_ARG_ENABLE(isac-fixed,AC_HELP_STRING([--enable-isac-fixed],[Enable iSAC fixed codec (default: no)]),want_isac_fixed=$enableval,want_isac_fixed=no) +if [[ "x$want_isac_fixed" = "xyes" ]]; then + if [[ x$HAVE_ISAC = "xyes" ]]; then + AC_ERROR([iSAC Fixed and iSAC Float can not be enabled both at the same time]) + else +AC_MSG_CHECKING([for iSAC fixed in libs]) + basedir=`cd "$srcdir" && pwd` + incisac="libs/miniwebrtc/audio/coding_isac/fix" + if [[ -f "$basedir/$incisac/isacfix.h" ]]; then + HAVE_ISAC=yes + basedir=`echo "$basedir" | sed 's/\([[^\]]\)\([[[:space:]\$\"'\'']]\)/\1\\\2/g'` + ISAC_INC="-I$basedir/$incisac -DISAC_FIXED" + fi + fi +AC_MSG_RESULT([$HAVE_ISAC]) +fi +AC_SUBST(HAVE_ISAC) +AC_SUBST(ISAC_INC) HAVE_SPEEX=no SPEEX_INC="" @@ -1424,6 +1486,7 @@ AC_CONFIG_FILES([packing/rpm/yate.spec libs/ymodem/Makefile libs/yasn/Makefile libs/ysnmp/Makefile + libs/miniwebrtc/Makefile share/Makefile share/scripts/Makefile share/skins/Makefile diff --git a/libs/miniwebrtc/Makefile.in b/libs/miniwebrtc/Makefile.in new file mode 100644 index 00000000..ea647e60 --- /dev/null +++ b/libs/miniwebrtc/Makefile.in @@ -0,0 +1,198 @@ +# Makefile +# This file holds the make rules for the libyatexml + +DEBUG := + +CXX := @CXX@ -Wall +CC := @CC@ -Wall +AR := ar +DEFS := +INCLUDES := -I@srcdir@ -I@srcdir@/audio/common/processing \ + -I@srcdir@/audio/common/vad -I@srcdir@/audio/processing/aec \ + -I@srcdir@/audio/processing/aecm -I@srcdir@/audio/processing/agc \ + -I@srcdir@/audio/processing/ns -I@srcdir@/audio/processing/utility \ + -I@srcdir@/system_wrappers + +CFLAGS := @CFLAGS@ @MODULE_CFLAGS@ @INLINE_FLAGS@ -DWEBRTC_NS_FLOAT=true +CPPFLAGS := @CFLAGS@ @MODULE_CPPFLAGS@ @INLINE_FLAGS@ -DWEBRTC_NS_FLOAT=true +LDFLAGS:= @LDFLAGS@ + +LIBS = libminiwebrtc.a +OBJS := audio/common/resampler/resampler.o \ + audio/common/processing/auto_correlation.o \ + audio/common/processing/auto_corr_to_refl_coef.o \ + audio/common/processing/complex_bit_reverse.o \ + audio/common/processing/complex_fft.o \ + audio/common/processing/copy_set_operations.o \ + audio/common/processing/cross_correlation.o \ + audio/common/processing/division_operations.o \ + audio/common/processing/dot_product_with_scale.o \ + audio/common/processing/downsample_fast.o \ + audio/common/processing/energy.o \ + audio/common/processing/filter_ar.o \ + audio/common/processing/filter_ar_fast_q12.o \ + audio/common/processing/filter_ma_fast_q12.o \ + audio/common/processing/get_hanning_window.o \ + audio/common/processing/get_scaling_square.o \ + audio/common/processing/ilbc_specific_functions.o \ + audio/common/processing/levinson_durbin.o \ + audio/common/processing/lpc_to_refl_coef.o \ + audio/common/processing/min_max_operations.o \ + audio/common/processing/randomization_functions.o \ + audio/common/processing/refl_coef_to_lpc.o \ + audio/common/processing/resample.o \ + audio/common/processing/resample_48khz.o \ + audio/common/processing/resample_by_2.o \ + audio/common/processing/resample_by_2_internal.o \ + audio/common/processing/resample_fractional.o \ + audio/common/processing/splitting_filter.o \ + audio/common/processing/spl_sqrt.o \ + audio/common/processing/spl_sqrt_floor.o \ + audio/common/processing/spl_version.o \ + audio/common/processing/sqrt_of_one_minus_x_squared.o \ + audio/common/processing/vector_scaling_operations.o \ + audio/common/processing/webrtc_fft_t_1024_8.o \ + audio/common/processing/webrtc_fft_t_rad.o \ + audio/common/vad/vad_core.o \ + audio/common/vad/vad_filterbank.o \ + audio/common/vad/vad_gmm.o \ + audio/common/vad/vad_sp.o \ + audio/common/vad/webrtc_vad.o \ + audio/coding_isac/fix/arith_routines.o \ + audio/coding_isac/fix/arith_routines_hist.o \ + audio/coding_isac/fix/arith_routines_logist.o \ + audio/coding_isac/fix/bandwidth_estimator.o \ + audio/coding_isac/fix/decode.o \ + audio/coding_isac/fix/decode_bwe.o \ + audio/coding_isac/fix/decode_plc.o \ + audio/coding_isac/fix/encode.o \ + audio/coding_isac/fix/entropy_coding.o \ + audio/coding_isac/fix/fft.o \ + audio/coding_isac/fix/filterbanks.o \ + audio/coding_isac/fix/filterbank_tables.o \ + audio/coding_isac/fix/filters.o \ + audio/coding_isac/fix/initialize.o \ + audio/coding_isac/fix/isacfix.o \ + audio/coding_isac/fix/lattice.o \ + audio/coding_isac/fix/lattice_c.o \ + audio/coding_isac/fix/lpc_masking_model.o \ + audio/coding_isac/fix/lpc_tables.o \ + audio/coding_isac/fix/pitch_estimator.o \ + audio/coding_isac/fix/pitch_filter.o \ + audio/coding_isac/fix/pitch_gain_tables.o \ + audio/coding_isac/fix/pitch_lag_tables.o \ + audio/coding_isac/fix/spectrum_ar_model_tables.o \ + audio/coding_isac/fix/transform.o \ + audio/coding_isac/main/arith_routines.o \ + audio/coding_isac/main/arith_routines_hist.o \ + audio/coding_isac/main/arith_routines_logist.o \ + audio/coding_isac/main/bandwidth_estimator.o \ + audio/coding_isac/main/crc.o \ + audio/coding_isac/main/decode.o \ + audio/coding_isac/main/decode_bwe.o \ + audio/coding_isac/main/encode.o \ + audio/coding_isac/main/encode_lpc_swb.o \ + audio/coding_isac/main/entropy_coding.o \ + audio/coding_isac/main/fft.o \ + audio/coding_isac/main/filterbanks.o \ + audio/coding_isac/main/filterbank_tables.o \ + audio/coding_isac/main/filter_functions.o \ + audio/coding_isac/main/intialize.o \ + audio/coding_isac/main/isac.o \ + audio/coding_isac/main/lattice.o \ + audio/coding_isac/main/lpc_analysis.o \ + audio/coding_isac/main/lpc_gain_swb_tables.o \ + audio/coding_isac/main/lpc_shape_swb12_tables.o \ + audio/coding_isac/main/lpc_shape_swb16_tables.o \ + audio/coding_isac/main/lpc_tables.o \ + audio/coding_isac/main/pitch_estimator.o \ + audio/coding_isac/main/pitch_filter.o \ + audio/coding_isac/main/pitch_gain_tables.o \ + audio/coding_isac/main/pitch_lag_tables.o \ + audio/coding_isac/main/spectrum_ar_model_tables.o \ + audio/coding_isac/main/transform.o \ + audio/processing/audio_buffer.o \ + audio/processing/audio_processing_impl.o \ + audio/processing/echo_cancellation_impl.o \ + audio/processing/echo_control_mobile_impl.o \ + audio/processing/gain_control_impl.o \ + audio/processing/high_pass_filter_impl.o \ + audio/processing/level_estimator_impl.o \ + audio/processing/noise_suppression_impl.o \ + audio/processing/processing_component.o \ + audio/processing/splitting_filter.o \ + audio/processing/voice_detection_impl.o \ + audio/processing/aec/aec_core.o \ + audio/processing/aec/aec_rdft.o \ + audio/processing/aec/aec_resampler.o \ + audio/processing/aec/echo_cancellation.o \ + audio/processing/aecm/aecm_core.o \ + audio/processing/aecm/echo_control_mobile.o \ + audio/processing/agc/analog_agc.o \ + audio/processing/agc/digital_agc.o \ + audio/processing/ns/noise_suppression.o \ + audio/processing/ns/ns_core.o \ + audio/processing/utility/delay_estimator.o \ + audio/processing/utility/delay_estimator_wrapper.o \ + audio/processing/utility/fft4g.o \ + audio/processing/utility/ring_buffer.o \ + system_wrappers/cpu_features.o \ + system_wrappers/critical_section.o \ + system_wrappers/critical_section_posix.o \ + system_wrappers/file_impl.o + +ifneq (@SSE2_OPS@,no) +OBJS := $(OBJS) audio/processing/aec/aec_rdft_sse2.o \ + audio/processing/aec/aec_core_sse2.o +CC := $(CC) -msse2 +CFLAGS := $(CFLAGS) -DSSE2_OPS=true +endif + + +LOCALFLAGS = +MKDEPS := ../../config.status +LOCALLIBS = +COMPILE = $(CXX) $(DEFS) $(DEBUG) $(INCLUDES) $(CPPFLAGS) +CCOMPILE = $(CC) $(DEFS) $(INCLUDES) $(CFLAGS) +LINK = $(CXX) $(LDFLAGS) +MODCOMP = $(COMPILE) $(LDFLAGS) +MODCCOMP = $(COMPILE) $(LDFLAGS) + +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +# include optional local make rules +-include YateLocal.mak + +.PHONY: all debug ddebug xdebug +all: $(LIBS) + +debug: + $(MAKE) all DEBUG=-g3 MODSTRIP= + +ddebug: + $(MAKE) all DEBUG='-g3 -DDEBUG' MODSTRIP= + +xdebug: + $(MAKE) all DEBUG='-g3 -DXDEBUG' MODSTRIP= + +.PHONY: strip +strip: all + strip --strip-debug --discard-locals $(PROGS) + +.PHONY: clean +clean: + @-$(RM) $(PROGS) $(LIBS) $(OBJS) $(AEC) core 2>/dev/null + +%.o: @srcdir@/%.c $(MKDEPS) $(INCFILES) + $(CCOMPILE) -c -o $@ $< + +%.o: @srcdir@/%.cc $(MKDEPS) $(INCFILES) + $(COMPILE) -c -o $@ $< + +Makefile: @srcdir@/Makefile.in ../../config.status + cd ../.. && ./config.status + +libminiwebrtc.a: $(OBJS) + $(AR) rcs $@ $^ + diff --git a/libs/miniwebrtc/README.txt b/libs/miniwebrtc/README.txt new file mode 100644 index 00000000..b5052608 --- /dev/null +++ b/libs/miniwebrtc/README.txt @@ -0,0 +1 @@ +WebRTC SVN version : 1768 \ No newline at end of file diff --git a/libs/miniwebrtc/audio/coding_isac/fix/arith_routines.c b/libs/miniwebrtc/audio/coding_isac/fix/arith_routines.c new file mode 100644 index 00000000..ee62bad5 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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/libs/miniwebrtc/audio/coding_isac/fix/arith_routines_hist.c b/libs/miniwebrtc/audio/coding_isac/fix/arith_routines_hist.c new file mode 100644 index 00000000..14f1adda --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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/libs/miniwebrtc/audio/coding_isac/fix/arith_routines_logist.c b/libs/miniwebrtc/audio/coding_isac/fix/arith_routines_logist.c new file mode 100644 index 00000000..39c437e5 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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/libs/miniwebrtc/audio/coding_isac/fix/arith_routins.h b/libs/miniwebrtc/audio/coding_isac/fix/arith_routins.h new file mode 100644 index 00000000..9aa49dac --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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/libs/miniwebrtc/audio/coding_isac/fix/bandwidth_estimator.c b/libs/miniwebrtc/audio/coding_isac/fix/bandwidth_estimator.c new file mode 100644 index 00000000..a274b667 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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/libs/miniwebrtc/audio/coding_isac/fix/bandwidth_estimator.h b/libs/miniwebrtc/audio/coding_isac/fix/bandwidth_estimator.h new file mode 100644 index 00000000..76a50f82 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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/libs/miniwebrtc/audio/coding_isac/fix/codec.h b/libs/miniwebrtc/audio/coding_isac/fix/codec.h new file mode 100644 index 00000000..154f2e9c --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/codec.h @@ -0,0 +1,183 @@ +/* + * 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. + */ + +/* + * 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); + +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); + +// Functions for ARM-Neon platforms, in place of the above two generic C ones. +#if (defined(WEBRTC_ANDROID) && 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 + **** WebRtcIsacfix_AutocorrC() / WebRtcIsacfix_AutocorrNeon() + **** and WebRtcIsacfix_FilterMaLoopC() / WebRtcIsacfix_FilterMaLoopNeon(). + ****/ + +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/libs/miniwebrtc/audio/coding_isac/fix/decode.c b/libs/miniwebrtc/audio/coding_isac/fix/decode.c new file mode 100644 index 00000000..2e15e7a9 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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 + +#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 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;kpostfiltbankstr_obj); + + } + return len; +} diff --git a/libs/miniwebrtc/audio/coding_isac/fix/decode_bwe.c b/libs/miniwebrtc/audio/coding_isac/fix/decode_bwe.c new file mode 100644 index 00000000..68c60030 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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/libs/miniwebrtc/audio/coding_isac/fix/decode_plc.c b/libs/miniwebrtc/audio/coding_isac/fix/decode_plc.c new file mode 100644 index 00000000..de516587 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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 + +#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;kpostfiltbankstr_obj); + + (ISACdec_obj->plcstr_obj).used = PLC_WAS_USED; + *current_framesamples = 480; + + return len; +} diff --git a/libs/miniwebrtc/audio/coding_isac/fix/encode.c b/libs/miniwebrtc/audio/coding_isac/fix/encode.c new file mode 100644 index 00000000..cb531e5a --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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 + + +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; kdata_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/libs/miniwebrtc/audio/coding_isac/fix/entropy_coding.c b/libs/miniwebrtc/audio/coding_isac/fix/entropy_coding.c new file mode 100644 index 00000000..0b64d835 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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 + +#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; k400000){ + 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; k400000){ + 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 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>(16-5) = Q21 + pos++; + pos2++; + } + tmpcoeffs2_gQ21[posg] = sumQQ; //Q21 + posg++; + offs2 += 2; + } + offs2 = 0; + + for (k=0; k>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>(16-1) = Q21 + pos += 2; + pos2 += SUBFRAMES; + + } + tmpcoeffs_gQ17[posg] = WEBRTC_SPL_RSHIFT_W32(sumQQ, 4); + posg++; + } + poss = offss; + for (k=0; k>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>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>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; kLPCcoeffs_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>(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>(16-1) = Q21 + pos += 2; + pos2++; + } + tmpcoeffs_gQ17[posg] = WEBRTC_SPL_RSHIFT_W32(sumQQ, 4); + posg++; + } + poss = offss; + for (k=0; k>(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 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 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; kLPCindex_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>(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>(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>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>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>(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>(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; kLPCcoeffs_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>(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 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 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>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; kmeanGain[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 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>(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 WebRtcIsacfix_kMaxIndGain[k]) { + index_gQQ[k] = WebRtcIsacfix_kMaxIndGain[k]; + } + } +} diff --git a/libs/miniwebrtc/audio/coding_isac/fix/entropy_coding.h b/libs/miniwebrtc/audio/coding_isac/fix/entropy_coding.h new file mode 100644 index 00000000..298ea223 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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/libs/miniwebrtc/audio/coding_isac/fix/fft.c b/libs/miniwebrtc/audio/coding_isac/fix/fft.c new file mode 100644 index 00000000..fff35c4f --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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/libs/miniwebrtc/audio/coding_isac/fix/fft.h b/libs/miniwebrtc/audio/coding_isac/fix/fft.h new file mode 100644 index 00000000..efa116e7 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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/libs/miniwebrtc/audio/coding_isac/fix/filterbank_tables.c b/libs/miniwebrtc/audio/coding_isac/fix/filterbank_tables.c new file mode 100644 index 00000000..87c62aab --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/filterbank_tables.c @@ -0,0 +1,64 @@ +/* + * 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. + */ + +/* + * filterbank_tables.c + * + * This file contains variables that are used in + * filterbanks.c + * + */ + +#include "filterbank_tables.h" +#include "settings.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 WebRtc_Word16 WebRtcIsacfix_kHpStCoeffInQ30[8] = { + -31932, 16189, /* Q30 hi/lo pair */ + 15562, 17243, /* Q30 hi/lo pair */ + -26748, -17186, /* Q35 hi/lo pair */ + 26296, -27476 /* Q35 hi/lo 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 WebRtc_Word16 WebRtcIsacfix_kHPStCoeffOut1Q30[8] = { + -32719, -1306, /* Q30 hi/lo pair */ + 16337, 11486, /* Q30 hi/lo pair */ + 8918, 26078, /* Q35 hi/lo pair */ + -8935, 3956 /* Q35 hi/lo 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 WebRtc_Word16 WebRtcIsacfix_kHPStCoeffOut2Q30[8] = { + -32546, -2953, /* Q30 hi/lo pair */ + 16166, 32233, /* Q30 hi/lo pair */ + 3383, 13217, /* Q35 hi/lo pair */ + -3473, -4597 /* Q35 hi/lo pair */ +}; + +/* The upper channel all-pass filter factors */ +const WebRtc_Word16 WebRtcIsacfix_kUpperApFactorsQ15[2] = { + 1137, 12537 +}; + +/* The lower channel all-pass filter factors */ +const WebRtc_Word16 WebRtcIsacfix_kLowerApFactorsQ15[2] = { + 5059, 24379 +}; diff --git a/libs/miniwebrtc/audio/coding_isac/fix/filterbank_tables.h b/libs/miniwebrtc/audio/coding_isac/fix/filterbank_tables.h new file mode 100644 index 00000000..b6be4f09 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/filterbank_tables.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. + */ + +/* + * 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" + +/********************* Coefficient Tables ************************/ + +/* HPstcoeff_in_Q14 = {a1, a2, b1 - b0 * a1, b2 - b0 * a2}; */ +extern const WebRtc_Word16 WebRtcIsacfix_kHpStCoeffInQ30[8]; /* [Q30hi Q30lo Q30hi Q30lo Q35hi Q35lo Q35hi Q35lo] */ + +/* HPstcoeff_out_1_Q14 = {a1, a2, b1 - b0 * a1, b2 - b0 * a2}; */ +extern const WebRtc_Word16 WebRtcIsacfix_kHPStCoeffOut1Q30[8]; /* [Q30hi Q30lo Q30hi Q30lo Q35hi Q35lo Q35hi Q35lo] */ + +/* HPstcoeff_out_2_Q14 = {a1, a2, b1 - b0 * a1, b2 - b0 * a2}; */ +extern const WebRtc_Word16 WebRtcIsacfix_kHPStCoeffOut2Q30[8]; /* [Q30hi Q30lo Q30hi Q30lo Q35hi Q35lo Q35hi Q35lo] */ + +/* The upper channel all-pass filter factors */ +extern const WebRtc_Word16 WebRtcIsacfix_kUpperApFactorsQ15[2]; + +/* The lower channel all-pass filter factors */ +extern const WebRtc_Word16 WebRtcIsacfix_kLowerApFactorsQ15[2]; + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_FILTERBANK_TABLES_H_ */ diff --git a/libs/miniwebrtc/audio/coding_isac/fix/filterbanks.c b/libs/miniwebrtc/audio/coding_isac/fix/filterbanks.c new file mode 100644 index 00000000..a53aa663 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/filterbanks.c @@ -0,0 +1,326 @@ +/* + * 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. + */ + +/* + * 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_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 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 + + } + } + +} + + +static void HighpassFilterFixDec32( + WebRtc_Word16 *io, /* Q0:input Q0: Output */ + WebRtc_Word16 len, /* length of input, Input */ + const WebRtc_Word16 *coeff, /* Coeff: [Q30hi Q30lo Q30hi Q30lo Q35hi Q35lo Q35hi Q35lo] */ + WebRtc_Word32 *state) /* Q4:filter state Input/Output */ +{ + int k; + WebRtc_Word32 a, b, c, in; + + + + for (k=0; k Q7 */ + a = WEBRTC_SPL_MUL_32_32_RSFT32(coeff[2*2], coeff[2*2+1], state[0]); + b = WEBRTC_SPL_MUL_32_32_RSFT32(coeff[2*3], coeff[2*3+1], state[1]); + + c = ((WebRtc_Word32)in) + WEBRTC_SPL_RSHIFT_W32(a+b, 7); // Q0 + //c = WEBRTC_SPL_RSHIFT_W32(c, 1); // Q-1 + io[k] = (WebRtc_Word16)WebRtcSpl_SatW32ToW16(c); // Write output as Q0 + + /* Q30 * Q4 = Q34 ; shift 32 bit => Q2 */ + a = WEBRTC_SPL_MUL_32_32_RSFT32(coeff[2*0], coeff[2*0+1], state[0]); + b = WEBRTC_SPL_MUL_32_32_RSFT32(coeff[2*1], coeff[2*1+1], state[1]); + + c = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)in, 2) - a - b; // New state in Q2 + c= (WebRtc_Word32)WEBRTC_SPL_SAT((WebRtc_Word32)536870911, c, (WebRtc_Word32)-536870912); // Check for wrap-around + + state[1] = state[0]; + state[0] = WEBRTC_SPL_LSHIFT_W32(c, 2); // Write state as Q4 + + } +} + + +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 */ + HighpassFilterFixDec32(pin, FRAMESAMPLES, WebRtcIsacfix_kHpStCoeffInQ30, prefiltdata->HPstates_fix); + + + /* First Channel */ + for (k=0;kINLABUF1_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;kINLABUF2_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;kINSTAT1_fix[k]; + AllpassFilter2FixDec16(tempin_ch1 + FRAMESAMPLES/2,WebRtcIsacfix_kUpperApFactorsQ15, QLOOKAHEAD , NUMBEROFCHANNELAPSECTIONS, tmpState); + for (k=0;kINSTAT2_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 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 */ + HighpassFilterFixDec32(pin, FRAMESAMPLES, WebRtcIsacfix_kHpStCoeffInQ30, prefiltdata->HPstates_fix); + + + /* First Channel */ + for (k=0;kINSTAT1_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 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;kHPstates1_fix); + HighpassFilterFixDec32(in, FRAMESAMPLES, WebRtcIsacfix_kHPStCoeffOut2Q30, postfiltdata->HPstates2_fix); + + for (k=0;kSTATE_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;kHPstates1_fix); + HighpassFilterFixDec32(in, len, WebRtcIsacfix_kHPStCoeffOut2Q30, postfiltdata->HPstates2_fix); + + for (k=0;k + +#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 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 +#include + +#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; + int16_t* ptr0 = &x[0]; + 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/libs/miniwebrtc/audio/coding_isac/fix/initialize.c b/libs/miniwebrtc/audio/coding_isac/fix/initialize.c new file mode 100644 index 00000000..4d11af53 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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/libs/miniwebrtc/audio/coding_isac/fix/isacfix.c b/libs/miniwebrtc/audio/coding_isac/fix/isacfix.c new file mode 100644 index 00000000..3a377857 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/isacfix.c @@ -0,0 +1,1529 @@ +/* + * 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. + */ + +/* + * isacfix.c + * + * This C file contains the functions for the ISAC API + * + */ + +#include +#include + +#include "isacfix.h" +#include "bandwidth_estimator.h" +#include "codec.h" +#include "entropy_coding.h" +#include "structs.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); +} + +/**************************************************************************** + * 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; kISACenc_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; + +#ifdef WEBRTC_ARCH_ARM_NEON + WebRtcIsacfix_AutocorrFix = WebRtcIsacfix_AutocorrNeon; + WebRtcIsacfix_FilterMaLoopFix = WebRtcIsacfix_FilterMaLoopNeon; +#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;kISACenc_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;k0 - 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;kCodingMode == 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/libs/miniwebrtc/audio/coding_isac/fix/isacfix.h b/libs/miniwebrtc/audio/coding_isac/fix/isacfix.h new file mode 100644 index 00000000..28e94294 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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/libs/miniwebrtc/audio/coding_isac/fix/lattice.c b/libs/miniwebrtc/audio/coding_isac/fix/lattice.c new file mode 100644 index 00000000..8822c6e9 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/lattice.c @@ -0,0 +1,313 @@ +/* + * 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); +*/ +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>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>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 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>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;iQ26 + 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= 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/libs/miniwebrtc/audio/coding_isac/fix/lpc_masking_model.c b/libs/miniwebrtc/audio/coding_isac/fix/lpc_masking_model.c new file mode 100644 index 00000000..4fa8ebb7 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/lpc_masking_model.c @@ -0,0 +1,1035 @@ +/* + * 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_masking_model.c + * + * LPC analysis and filtering functions + * + */ + +#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>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 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>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 a function pointer. +AutocorrFix WebRtcIsacfix_AutocorrFix; + +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, j, ii; + WebRtc_Word16 pos1, pos2; + WebRtc_Word16 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 round; + WebRtc_Word32 res_nrgQQ; + WebRtc_Word32 sqrt_nrg; + + WebRtc_Word32 aSQR32; + + /* 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, 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>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 = 0; + for (j = 0; j <= ORDERLO; j++) + { + for (n = 0; n < j; n++) + { + WebRtc_Word16 index, diff, sh_corr; + + index = j - n; //WEBRTC_SPL_ABS_W16(j-n); + + /* Calculation of res_nrg += a_LO[j] * corrlo2[j-n] * a_LO[n]; */ + /* corrlo2QQ is in Q(QdomLO) */ + tmp32 = ((WebRtc_Word32) WEBRTC_SPL_MUL_16_16(a_LOQ11[j], a_LOQ11[n])); // Q11*Q11 = Q22 + // multiply by 2 as loop only on half of the matrix. a_LOQ11 gone through bandwidth + // expation so the following shift is safe. + tmp32 = WEBRTC_SPL_LSHIFT_W32(tmp32, 1); + sh = WebRtcSpl_NormW32(tmp32); + aSQR32 = WEBRTC_SPL_LSHIFT_W32(tmp32, sh); // Q(22+sh) + sh_corr = WebRtcSpl_NormW32(corrlo2QQ[index]); + tmp32 = WEBRTC_SPL_LSHIFT_W32(corrlo2QQ[index], sh_corr); + tmp32 = (WebRtc_Word32) WEBRTC_SPL_MUL_32_32_RSFT32BI(aSQR32, tmp32); // Q(22+sh)*Q(QdomLO+sh_corr)>>32 = Q(22+sh+QdomLO+sh_corr-32) = Q(sh+QdomLO+sh_corr-10) + sh = sh+QdomLO+sh_corr-10; + + diff = sh_lo-sh; + + round = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)1, (WEBRTC_SPL_ABS_W32(diff)-1)); + if (diff==0) + round = 0; + if (diff>=31) { + res_nrgQQ = tmp32; + sh_lo = sh; + } else if (diff>0) { + res_nrgQQ = WEBRTC_SPL_RSHIFT_W32((res_nrgQQ+round), (diff+1)) + WEBRTC_SPL_RSHIFT_W32(tmp32, 1); + sh_lo = sh-1; + } else if (diff>-31){ + res_nrgQQ = WEBRTC_SPL_RSHIFT_W32(res_nrgQQ, 1) + WEBRTC_SPL_SHIFT_W32((tmp32+round), -(-diff+1)); + sh_lo = sh_lo-1; + } + sh = WebRtcSpl_NormW32(res_nrgQQ); + res_nrgQQ = WEBRTC_SPL_LSHIFT_W32(res_nrgQQ, sh); + sh_lo += sh; + } + n = j; + { + WebRtc_Word16 index, diff, sh_corr; + + index = 0; //WEBRTC_SPL_ABS_W16(j-n); + + /* Calculation of res_nrg += a_LO[j] * corrlo2[j-n] * a_LO[n]; */ + /* corrlo2QQ is in Q(QdomLO) */ + tmp32 = (WebRtc_Word32) WEBRTC_SPL_MUL_16_16(a_LOQ11[j], a_LOQ11[n]); // Q11*Q11 = Q22 + sh = WebRtcSpl_NormW32(tmp32); + aSQR32 = WEBRTC_SPL_LSHIFT_W32(tmp32, sh); // Q(22+sh) + sh_corr = WebRtcSpl_NormW32(corrlo2QQ[index]); + tmp32 = WEBRTC_SPL_LSHIFT_W32(corrlo2QQ[index], sh_corr); + tmp32 = (WebRtc_Word32) WEBRTC_SPL_MUL_32_32_RSFT32BI(aSQR32, tmp32); // Q(22+sh)*Q(QdomLO+sh_corr)>>32 = Q(22+sh+QdomLO+sh_corr-32) = Q(sh+QdomLO+sh_corr-10) + sh = sh+QdomLO+sh_corr-10; + diff = sh_lo-sh; + + round = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)1, (WEBRTC_SPL_ABS_W32(diff)-1)); + if (diff==0) + round = 0; + if (diff>=31) { + res_nrgQQ = tmp32; + sh_lo = sh; + } else if (diff>0) { + res_nrgQQ = WEBRTC_SPL_RSHIFT_W32((res_nrgQQ+round), (diff+1)) + WEBRTC_SPL_RSHIFT_W32(tmp32, 1); + sh_lo = sh-1; + } else if (diff>-31){ + res_nrgQQ = WEBRTC_SPL_RSHIFT_W32(res_nrgQQ, 1) + WEBRTC_SPL_SHIFT_W32((tmp32+round), -(-diff+1)); + sh_lo = sh_lo-1; + } + sh = WebRtcSpl_NormW32(res_nrgQQ); + res_nrgQQ = WEBRTC_SPL_LSHIFT_W32(res_nrgQQ, sh); + sh_lo += sh; + } + } + /* 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 */ + res_nrgQQ = 0; + sh_hi = 31; + + + for (j = 0; j <= ORDERHI; j++) + { + for (n = 0; n < j; n++) + { + WebRtc_Word16 index, diff, sh_corr; + + index = j-n; //WEBRTC_SPL_ABS_W16(j-n); + + /* Calculation of res_nrg += a_HI[j] * corrhi[j-n] * a_HI[n] * 2; for j != n */ + /* corrhiQQ is in Q(QdomHI) */ + tmp32 = ((WebRtc_Word32) WEBRTC_SPL_MUL_16_16(a_HIQ12[j], a_HIQ12[n])); // Q12*Q12 = Q24 + tmp32 = WEBRTC_SPL_LSHIFT_W32(tmp32, 1); + sh = WebRtcSpl_NormW32(tmp32); + aSQR32 = WEBRTC_SPL_LSHIFT_W32(tmp32, sh); // Q(24+sh) + sh_corr = WebRtcSpl_NormW32(corrhiQQ[index]); + tmp32 = WEBRTC_SPL_LSHIFT_W32(corrhiQQ[index],sh_corr); + tmp32 = (WebRtc_Word32) WEBRTC_SPL_MUL_32_32_RSFT32BI(aSQR32, tmp32); // Q(24+sh)*Q(QdomHI+sh_corr)>>32 = Q(24+sh+QdomHI+sh_corr-32) = Q(sh+QdomHI+sh_corr-8) + sh = sh+QdomHI+sh_corr-8; + diff = sh_hi-sh; + + round = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)1, (WEBRTC_SPL_ABS_W32(diff)-1)); + if (diff==0) + round = 0; + if (diff>=31) { + res_nrgQQ = tmp32; + sh_hi = sh; + } else if (diff>0) { + res_nrgQQ = WEBRTC_SPL_RSHIFT_W32((res_nrgQQ+round), (diff+1)) + WEBRTC_SPL_RSHIFT_W32(tmp32, 1); + sh_hi = sh-1; + } else if (diff>-31){ + res_nrgQQ = WEBRTC_SPL_RSHIFT_W32(res_nrgQQ, 1) + WEBRTC_SPL_SHIFT_W32((tmp32+round), -(-diff+1)); + sh_hi = sh_hi-1; + } + + sh = WebRtcSpl_NormW32(res_nrgQQ); + res_nrgQQ = WEBRTC_SPL_LSHIFT_W32(res_nrgQQ, sh); + sh_hi += sh; + } + + n = j; + { + WebRtc_Word16 index, diff, sh_corr; + + index = 0; //n-j; //WEBRTC_SPL_ABS_W16(j-n); + + /* Calculation of res_nrg += a_HI[j] * corrhi[j-n] * a_HI[n];*/ + /* corrhiQQ is in Q(QdomHI) */ + tmp32 = ((WebRtc_Word32) WEBRTC_SPL_MUL_16_16(a_HIQ12[j], a_HIQ12[n])); // Q12*Q12 = Q24 + sh = WebRtcSpl_NormW32(tmp32); + aSQR32 = WEBRTC_SPL_LSHIFT_W32(tmp32, sh); // Q(24+sh) + sh_corr = WebRtcSpl_NormW32(corrhiQQ[index]); + tmp32 = WEBRTC_SPL_LSHIFT_W32(corrhiQQ[index],sh_corr); + tmp32 = (WebRtc_Word32) WEBRTC_SPL_MUL_32_32_RSFT32BI(aSQR32, tmp32); // Q(24+sh)*Q(QdomHI+sh_corr)>>32 = Q(24+sh+QdomHI+sh_corr-32) = Q(sh+QdomHI+sh_corr-8) + sh = sh+QdomHI+sh_corr-8; + diff = sh_hi-sh; + + round = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)1, (WEBRTC_SPL_ABS_W32(diff)-1)); + if (diff==0) + round = 0; + if (diff>=31) { + res_nrgQQ = tmp32; + sh_hi = sh; + } else if (diff>0) { + res_nrgQQ = WEBRTC_SPL_RSHIFT_W32((res_nrgQQ+round), (diff+1)) + WEBRTC_SPL_RSHIFT_W32(tmp32, 1); + sh_hi = sh-1; + } else if (diff>-31){ + res_nrgQQ = WEBRTC_SPL_RSHIFT_W32(res_nrgQQ, 1) + WEBRTC_SPL_SHIFT_W32((tmp32+round), -(-diff+1)); + sh_hi = sh_hi-1; + } + + sh = WebRtcSpl_NormW32(res_nrgQQ); + res_nrgQQ = WEBRTC_SPL_LSHIFT_W32(res_nrgQQ, sh); + sh_hi += sh; + } + } + + /* 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/libs/miniwebrtc/audio/coding_isac/fix/lpc_masking_model.h b/libs/miniwebrtc/audio/coding_isac/fix/lpc_masking_model.h new file mode 100644 index 00000000..9a64844b --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/lpc_masking_model.h @@ -0,0 +1,37 @@ +/* + * 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_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_ + +#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); + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_FIX_SOURCE_LPC_MASKING_MODEL_H_ */ diff --git a/libs/miniwebrtc/audio/coding_isac/fix/lpc_tables.c b/libs/miniwebrtc/audio/coding_isac/fix/lpc_tables.c new file mode 100644 index 00000000..90cc9af4 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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/libs/miniwebrtc/audio/coding_isac/fix/lpc_tables.h b/libs/miniwebrtc/audio/coding_isac/fix/lpc_tables.h new file mode 100644 index 00000000..4f2e0e7f --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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/libs/miniwebrtc/audio/coding_isac/fix/pitch_estimator.c b/libs/miniwebrtc/audio/coding_isac/fix/pitch_estimator.c new file mode 100644 index 00000000..1702098e --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/pitch_estimator.c @@ -0,0 +1,519 @@ +/* + * 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 + * + */ + +#include + +#include "signal_processing_library.h" +#include "pitch_estimator.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 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 prod32, 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); + csum32 = 0; + prod32 = WEBRTC_SPL_MUL_16_16_RSFT( (WebRtc_Word16) x[0],(WebRtc_Word16) inptr[0], scaling); + + for (n = 1; n < PITCH_CORR_LEN2; n++) { + csum32 += prod32; + prod32 = WEBRTC_SPL_MUL_16_16_RSFT( (WebRtc_Word16) x[n],(WebRtc_Word16) inptr[n], scaling); + } + + csum32 += prod32; + 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 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 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/libs/miniwebrtc/audio/coding_isac/fix/pitch_estimator.h b/libs/miniwebrtc/audio/coding_isac/fix/pitch_estimator.h new file mode 100644 index 00000000..afdc9785 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/pitch_estimator.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * pitch_estimator.h + * + * Pitch functions + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_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_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/libs/miniwebrtc/audio/coding_isac/fix/pitch_filter.c b/libs/miniwebrtc/audio/coding_isac/fix/pitch_filter.c new file mode 100644 index 00000000..87af1533 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/pitch_filter.c @@ -0,0 +1,331 @@ +/* + * 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_estimatorfilter.c + * + * Pitch filter functions + * + */ + +#include + +#include "pitch_estimator.h" + + +/* 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} +}; + + + + +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, n, m, ind; + WebRtc_Word16 sign = 1; + WebRtc_Word16 inystateQQ[PITCH_DAMPORDER]; + WebRtc_Word16 ubufQQ[PITCH_INTBUFFSIZE+QLOOKAHEAD]; + WebRtc_Word16 Gain = 21299; /* 1.3 in Q14 */ + WebRtc_Word16 DivFactor = 6553; /* 0.2 in Q15 */ + WebRtc_Word16 oldLagQ7, oldGainQ12, + lagdeltaQ7, curLagQ7, + gaindeltaQ12, curGainQ12; + WebRtc_Word16 tmpW16, indW16=0, frcQQ, cnt=0, pos, pos2; + const WebRtc_Word16 *fracoeffQQ=NULL; + WebRtc_Word32 tmpW32; + + if (type==4) + sign = -1; + + /* Set up buffer and states */ + memcpy(ubufQQ, pfp->ubufQQ, WEBRTC_SPL_MUL_16_16(sizeof(WebRtc_Word16), PITCH_BUFFSIZE)); + memcpy(inystateQQ, pfp->ystateQQ, WEBRTC_SPL_MUL_16_16(sizeof(WebRtc_Word16), PITCH_DAMPORDER)); + + /* Get old lag and gain value from memory */ + oldLagQ7 = pfp->oldlagQ7; + oldGainQ12 = pfp->oldgainQ12; + + if (type==4) { + /* make output more periodic */ + /* Fixed 1.3 = 21299 in Q14 */ + for (k=0;k WEBRTC_SPL_RSHIFT_W16(WEBRTC_SPL_MUL_16_16(oldLagQ7, 3), 1))) { + oldLagQ7 = lagsQ7[0]; + oldGainQ12 = gainsQ12[0]; + } + + ind=0; + for (k=0;k0;m--) + inystateQQ[m] = inystateQQ[m-1]; + + /* Filter to get fractional pitch */ + pos = ind + PITCH_BUFFSIZE; + pos2 = pos - (indW16 + 2); + + tmpW32=0; + for (m=0;mubufQQ, ubufQQ+PITCH_FRAME_LEN, WEBRTC_SPL_MUL_16_16(sizeof(WebRtc_Word16), PITCH_BUFFSIZE)); + memcpy(pfp->ystateQQ, inystateQQ, WEBRTC_SPL_MUL_16_16(sizeof(WebRtc_Word16), PITCH_DAMPORDER)); + + pfp->oldlagQ7 = oldLagQ7; + pfp->oldgainQ12 = oldGainQ12; + + if (type==2) { + /* Filter look-ahead segment */ + for (n=0;n0;m--) + inystateQQ[m] = inystateQQ[m-1]; + + /* Filter to get fractional pitch */ + pos = ind + PITCH_BUFFSIZE; + pos2= pos - (indW16 + 2); + + tmpW32=0; + for (m=0;mubufQQ, WEBRTC_SPL_MUL_16_16(sizeof(WebRtc_Word16), PITCH_BUFFSIZE)); + oldLagQ7 = pfp->oldlagQ7; + + /* No interpolation if pitch lag step is big */ + if ((WEBRTC_SPL_RSHIFT_W16(WEBRTC_SPL_MUL_16_16(lagsQ7[0], 3), 1) < oldLagQ7) || + (lagsQ7[0] > WEBRTC_SPL_RSHIFT_W16(WEBRTC_SPL_MUL_16_16(oldLagQ7, 3), 1))) { + oldLagQ7 = lagsQ7[0]; + } + + ind=0; + scale=0; + for (k=0;k1073700000) || (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++; + cnt--; + } + + if (csum1QQubufQQ, ubufQQ+PITCH_FRAME_LEN, WEBRTC_SPL_MUL_16_16(sizeof(WebRtc_Word16), PITCH_BUFFSIZE)); + pfp->oldlagQ7 = lagsQ7[PITCH_SUBFRAMES-1]; + pfp->oldgainQ12 = gainsQ12[PITCH_SUBFRAMES-1]; + +} diff --git a/libs/miniwebrtc/audio/coding_isac/fix/pitch_gain_tables.c b/libs/miniwebrtc/audio/coding_isac/fix/pitch_gain_tables.c new file mode 100644 index 00000000..50ea6583 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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/libs/miniwebrtc/audio/coding_isac/fix/pitch_gain_tables.h b/libs/miniwebrtc/audio/coding_isac/fix/pitch_gain_tables.h new file mode 100644 index 00000000..788e5536 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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/libs/miniwebrtc/audio/coding_isac/fix/pitch_lag_tables.c b/libs/miniwebrtc/audio/coding_isac/fix/pitch_lag_tables.c new file mode 100644 index 00000000..81700e47 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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/libs/miniwebrtc/audio/coding_isac/fix/pitch_lag_tables.h b/libs/miniwebrtc/audio/coding_isac/fix/pitch_lag_tables.h new file mode 100644 index 00000000..9517c29b --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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/libs/miniwebrtc/audio/coding_isac/fix/settings.h b/libs/miniwebrtc/audio/coding_isac/fix/settings.h new file mode 100644 index 00000000..da88ba25 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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/libs/miniwebrtc/audio/coding_isac/fix/spectrum_ar_model_tables.c b/libs/miniwebrtc/audio/coding_isac/fix/spectrum_ar_model_tables.c new file mode 100644 index 00000000..81b932fd --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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/libs/miniwebrtc/audio/coding_isac/fix/spectrum_ar_model_tables.h b/libs/miniwebrtc/audio/coding_isac/fix/spectrum_ar_model_tables.h new file mode 100644 index 00000000..b506d0e4 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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/libs/miniwebrtc/audio/coding_isac/fix/structs.h b/libs/miniwebrtc/audio/coding_isac/fix/structs.h new file mode 100644 index 00000000..54dffa92 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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 "typedefs.h" +#include "signal_processing_library.h" +#include "settings.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/libs/miniwebrtc/audio/coding_isac/fix/transform.c b/libs/miniwebrtc/audio/coding_isac/fix/transform.c new file mode 100644 index 00000000..56ef9f2f --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/fix/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=0) { + for (k=0; k Q16 + tmpimQ16[k] = WEBRTC_SPL_RSHIFT_W32((WebRtc_Word32)inre2Q9[k], sh); //Q(16+sh) -> Q16 + } + } else { + for (k=0; k 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/libs/miniwebrtc/audio/coding_isac/main/arith_routines.c b/libs/miniwebrtc/audio/coding_isac/main/arith_routines.c new file mode 100644 index 00000000..31c441a7 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/arith_routines.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "arith_routines.h" +#include "settings.h" + + +/* + * terminate and return byte stream; + * returns the number of bytes in the stream + */ +int WebRtcIsac_EncTerminate(Bitstr *streamdata) /* in-/output struct containing bitstream */ +{ + WebRtc_UWord8 *stream_ptr; + + + /* point to the right place in the stream buffer */ + stream_ptr = streamdata->stream + streamdata->stream_index; + + /* find minimum length (determined by current interval width) */ + if ( streamdata->W_upper > 0x01FFFFFF ) + { + streamdata->streamval += 0x01000000; + /* add carry to buffer */ + if (streamdata->streamval < 0x01000000) + { + /* propagate carry */ + while ( !(++(*--stream_ptr)) ); + /* put pointer back to the old value */ + stream_ptr = streamdata->stream + streamdata->stream_index; + } + /* write remaining data to bitstream */ + *stream_ptr++ = (WebRtc_UWord8) (streamdata->streamval >> 24); + } + else + { + streamdata->streamval += 0x00010000; + /* add carry to buffer */ + if (streamdata->streamval < 0x00010000) + { + /* propagate carry */ + while ( !(++(*--stream_ptr)) ); + /* put pointer back to the old value */ + stream_ptr = streamdata->stream + streamdata->stream_index; + } + /* write remaining data to bitstream */ + *stream_ptr++ = (WebRtc_UWord8) (streamdata->streamval >> 24); + *stream_ptr++ = (WebRtc_UWord8) ((streamdata->streamval >> 16) & 0x00FF); + } + + /* calculate stream length */ + return (int)(stream_ptr - streamdata->stream); +} diff --git a/libs/miniwebrtc/audio/coding_isac/main/arith_routines.h b/libs/miniwebrtc/audio/coding_isac/main/arith_routines.h new file mode 100644 index 00000000..8e5f496f --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/arith_routines.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * arith_routines.h + * + * Functions for arithmetic coding. + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ARITH_ROUTINES_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ARITH_ROUTINES_H_ + +#include "structs.h" + + +int WebRtcIsac_EncLogisticMulti2( + Bitstr *streamdata, /* in-/output struct containing bitstream */ + WebRtc_Word16 *dataQ7, /* input: data vector */ + const WebRtc_UWord16 *env, /* input: side info vector defining the width of the pdf */ + const int N, /* input: data vector length */ + const WebRtc_Word16 isSWB12kHz); /* if the codec is working in 12kHz bandwidth */ + +/* returns the number of bytes in the stream */ +int WebRtcIsac_EncTerminate(Bitstr *streamdata); /* in-/output struct containing bitstream */ + +/* returns the number of bytes in the stream so far */ +int WebRtcIsac_DecLogisticMulti2( + WebRtc_Word16 *data, /* output: data vector */ + Bitstr *streamdata, /* in-/output struct containing bitstream */ + const WebRtc_UWord16 *env, /* input: side info vector defining the width of the pdf */ + const WebRtc_Word16 *dither, /* input: dither vector */ + const int N, /* input: data vector length */ + const WebRtc_Word16 isSWB12kHz); /* if the codec is working in 12kHz bandwidth */ + +void WebRtcIsac_EncHistMulti( + Bitstr *streamdata, /* in-/output struct containing bitstream */ + const int *data, /* input: data vector */ + const WebRtc_UWord16 **cdf, /* input: array of cdf arrays */ + const int N); /* input: data vector length */ + +int WebRtcIsac_DecHistBisectMulti( + int *data, /* output: data vector */ + Bitstr *streamdata, /* in-/output struct containing bitstream */ + const WebRtc_UWord16 **cdf, /* input: array of cdf arrays */ + const WebRtc_UWord16 *cdf_size, /* input: array of cdf table sizes+1 (power of two: 2^k) */ + const int N); /* input: data vector length */ + +int WebRtcIsac_DecHistOneStepMulti( + int *data, /* output: data vector */ + Bitstr *streamdata, /* in-/output struct containing bitstream */ + const WebRtc_UWord16 **cdf, /* input: array of cdf arrays */ + const WebRtc_UWord16 *init_index,/* input: vector of initial cdf table search entries */ + const int N); /* input: data vector length */ + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ARITH_ROUTINES_H_ */ diff --git a/libs/miniwebrtc/audio/coding_isac/main/arith_routines_hist.c b/libs/miniwebrtc/audio/coding_isac/main/arith_routines_hist.c new file mode 100644 index 00000000..f4a13d60 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/arith_routines_hist.c @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "settings.h" +#include "arith_routines.h" + + +/* + * code symbols into arithmetic bytestream + */ +void WebRtcIsac_EncHistMulti(Bitstr *streamdata, /* in-/output struct containing bitstream */ + const int *data, /* input: data vector */ + const WebRtc_UWord16 **cdf, /* input: array of cdf arrays */ + const int N) /* input: data vector length */ +{ + WebRtc_UWord32 W_lower, W_upper; + WebRtc_UWord32 W_upper_LSB, W_upper_MSB; + WebRtc_UWord8 *stream_ptr; + WebRtc_UWord8 *stream_ptr_carry; + WebRtc_UWord32 cdf_lo, cdf_hi; + int k; + + + /* point to beginning of stream buffer */ + stream_ptr = streamdata->stream + streamdata->stream_index; + W_upper = streamdata->W_upper; + + for (k=N; k>0; k--) + { + /* fetch cdf_lower and cdf_upper from cdf tables */ + cdf_lo = (WebRtc_UWord32) *(*cdf + *data); + cdf_hi = (WebRtc_UWord32) *(*cdf++ + *data++ + 1); + + /* update interval */ + W_upper_LSB = W_upper & 0x0000FFFF; + W_upper_MSB = W_upper >> 16; + W_lower = W_upper_MSB * cdf_lo; + W_lower += (W_upper_LSB * cdf_lo) >> 16; + W_upper = W_upper_MSB * cdf_hi; + W_upper += (W_upper_LSB * cdf_hi) >> 16; + + /* shift interval such that it begins at zero */ + W_upper -= ++W_lower; + + /* add integer to bitstream */ + streamdata->streamval += W_lower; + + /* handle carry */ + if (streamdata->streamval < W_lower) + { + /* propagate carry */ + stream_ptr_carry = stream_ptr; + while (!(++(*--stream_ptr_carry))); + } + + /* renormalize interval, store most significant byte of streamval and update streamval */ + while ( !(W_upper & 0xFF000000) ) /* W_upper < 2^24 */ + { + W_upper <<= 8; + *stream_ptr++ = (WebRtc_UWord8) (streamdata->streamval >> 24); + streamdata->streamval <<= 8; + } + } + + /* calculate new stream_index */ + streamdata->stream_index = (int)(stream_ptr - streamdata->stream); + streamdata->W_upper = W_upper; + + return; +} + + + +/* + * function to decode more symbols from the arithmetic bytestream, using method of bisection + * cdf tables should be of size 2^k-1 (which corresponds to an alphabet size of 2^k-2) + */ +int WebRtcIsac_DecHistBisectMulti(int *data, /* output: data vector */ + Bitstr *streamdata, /* in-/output struct containing bitstream */ + const WebRtc_UWord16 **cdf, /* input: array of cdf arrays */ + const WebRtc_UWord16 *cdf_size, /* input: array of cdf table sizes+1 (power of two: 2^k) */ + const int N) /* input: data vector length */ +{ + WebRtc_UWord32 W_lower, W_upper; + WebRtc_UWord32 W_tmp; + WebRtc_UWord32 W_upper_LSB, W_upper_MSB; + WebRtc_UWord32 streamval; + const WebRtc_UWord8 *stream_ptr; + const WebRtc_UWord16 *cdf_ptr; + int size_tmp; + int k; + + W_lower = 0; //to remove warning -DH + stream_ptr = streamdata->stream + streamdata->stream_index; + W_upper = streamdata->W_upper; + if (W_upper == 0) + /* Should not be possible in normal operation */ + return -2; + + if (streamdata->stream_index == 0) /* first time decoder is called for this stream */ + { + /* read first word from bytestream */ + streamval = *stream_ptr << 24; + streamval |= *++stream_ptr << 16; + streamval |= *++stream_ptr << 8; + streamval |= *++stream_ptr; + } else { + streamval = streamdata->streamval; + } + + for (k=N; k>0; k--) + { + /* find the integer *data for which streamval lies in [W_lower+1, W_upper] */ + W_upper_LSB = W_upper & 0x0000FFFF; + W_upper_MSB = W_upper >> 16; + + /* start halfway the cdf range */ + size_tmp = *cdf_size++ >> 1; + cdf_ptr = *cdf + (size_tmp - 1); + + /* method of bisection */ + for ( ;; ) + { + W_tmp = W_upper_MSB * *cdf_ptr; + W_tmp += (W_upper_LSB * *cdf_ptr) >> 16; + size_tmp >>= 1; + if (size_tmp == 0) break; + if (streamval > W_tmp) + { + W_lower = W_tmp; + cdf_ptr += size_tmp; + } else { + W_upper = W_tmp; + cdf_ptr -= size_tmp; + } + } + if (streamval > W_tmp) + { + W_lower = W_tmp; + *data++ = (int)(cdf_ptr - *cdf++); + } else { + W_upper = W_tmp; + *data++ = (int)(cdf_ptr - *cdf++ - 1); + } + + /* shift interval to start at zero */ + W_upper -= ++W_lower; + + /* add integer to bitstream */ + streamval -= W_lower; + + /* renormalize interval and update streamval */ + while ( !(W_upper & 0xFF000000) ) /* W_upper < 2^24 */ + { + /* read next byte from stream */ + streamval = (streamval << 8) | *++stream_ptr; + W_upper <<= 8; + } + + if (W_upper == 0) + /* Should not be possible in normal operation */ + return -2; + + + } + + streamdata->stream_index = (int)(stream_ptr - streamdata->stream); + streamdata->W_upper = W_upper; + streamdata->streamval = streamval; + + + /* find number of bytes in original stream (determined by current interval width) */ + if ( W_upper > 0x01FFFFFF ) + return streamdata->stream_index - 2; + else + return streamdata->stream_index - 1; +} + + + +/* + * function to decode more symbols from the arithmetic bytestream, taking single step up or + * down at a time + * cdf tables can be of arbitrary size, but large tables may take a lot of iterations + */ +int WebRtcIsac_DecHistOneStepMulti(int *data, /* output: data vector */ + Bitstr *streamdata, /* in-/output struct containing bitstream */ + const WebRtc_UWord16 **cdf, /* input: array of cdf arrays */ + const WebRtc_UWord16 *init_index, /* input: vector of initial cdf table search entries */ + const int N) /* input: data vector length */ +{ + WebRtc_UWord32 W_lower, W_upper; + WebRtc_UWord32 W_tmp; + WebRtc_UWord32 W_upper_LSB, W_upper_MSB; + WebRtc_UWord32 streamval; + const WebRtc_UWord8 *stream_ptr; + const WebRtc_UWord16 *cdf_ptr; + int k; + + + stream_ptr = streamdata->stream + streamdata->stream_index; + W_upper = streamdata->W_upper; + if (W_upper == 0) + /* Should not be possible in normal operation */ + return -2; + + if (streamdata->stream_index == 0) /* first time decoder is called for this stream */ + { + /* read first word from bytestream */ + streamval = *stream_ptr << 24; + streamval |= *++stream_ptr << 16; + streamval |= *++stream_ptr << 8; + streamval |= *++stream_ptr; + } else { + streamval = streamdata->streamval; + } + + + for (k=N; k>0; k--) + { + /* find the integer *data for which streamval lies in [W_lower+1, W_upper] */ + W_upper_LSB = W_upper & 0x0000FFFF; + W_upper_MSB = W_upper >> 16; + + /* start at the specified table entry */ + cdf_ptr = *cdf + (*init_index++); + W_tmp = W_upper_MSB * *cdf_ptr; + W_tmp += (W_upper_LSB * *cdf_ptr) >> 16; + if (streamval > W_tmp) + { + for ( ;; ) + { + W_lower = W_tmp; + if (cdf_ptr[0]==65535) + /* range check */ + return -3; + W_tmp = W_upper_MSB * *++cdf_ptr; + W_tmp += (W_upper_LSB * *cdf_ptr) >> 16; + if (streamval <= W_tmp) break; + } + W_upper = W_tmp; + *data++ = (int)(cdf_ptr - *cdf++ - 1); + } else { + for ( ;; ) + { + W_upper = W_tmp; + --cdf_ptr; + if (cdf_ptr<*cdf) { + /* range check */ + return -3; + } + W_tmp = W_upper_MSB * *cdf_ptr; + W_tmp += (W_upper_LSB * *cdf_ptr) >> 16; + if (streamval > W_tmp) break; + } + W_lower = W_tmp; + *data++ = (int)(cdf_ptr - *cdf++); + } + + /* shift interval to start at zero */ + W_upper -= ++W_lower; + /* add integer to bitstream */ + streamval -= W_lower; + + /* renormalize interval and update streamval */ + while ( !(W_upper & 0xFF000000) ) /* W_upper < 2^24 */ + { + /* read next byte from stream */ + streamval = (streamval << 8) | *++stream_ptr; + W_upper <<= 8; + } + } + + streamdata->stream_index = (int)(stream_ptr - streamdata->stream); + streamdata->W_upper = W_upper; + streamdata->streamval = streamval; + + + /* find number of bytes in original stream (determined by current interval width) */ + if ( W_upper > 0x01FFFFFF ) + return streamdata->stream_index - 2; + else + return streamdata->stream_index - 1; +} diff --git a/libs/miniwebrtc/audio/coding_isac/main/arith_routines_logist.c b/libs/miniwebrtc/audio/coding_isac/main/arith_routines_logist.c new file mode 100644 index 00000000..422855a4 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/arith_routines_logist.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * arith_routines.h + * + * This file contains functions for arithmatically encoding and + * decoding DFT coefficients. + * + */ + + +#include "arith_routines.h" + + + +static const WebRtc_Word32 kHistEdgesQ15[51] = { + -327680, -314573, -301466, -288359, -275252, -262144, -249037, -235930, -222823, -209716, + -196608, -183501, -170394, -157287, -144180, -131072, -117965, -104858, -91751, -78644, + -65536, -52429, -39322, -26215, -13108, 0, 13107, 26214, 39321, 52428, + 65536, 78643, 91750, 104857, 117964, 131072, 144179, 157286, 170393, 183500, + 196608, 209715, 222822, 235929, 249036, 262144, 275251, 288358, 301465, 314572, + 327680}; + + +static const int kCdfSlopeQ0[51] = { /* Q0 */ + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 13, 23, 47, 87, 154, 315, 700, 1088, + 2471, 6064, 14221, 21463, 36634, 36924, 19750, 13270, 5806, 2312, + 1095, 660, 316, 145, 86, 41, 32, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 0}; + + +static const int kCdfQ16[51] = { /* Q16 */ + 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, + 20, 22, 24, 29, 38, 57, 92, 153, 279, 559, + 994, 1983, 4408, 10097, 18682, 33336, 48105, 56005, 61313, 63636, + 64560, 64998, 65262, 65389, 65447, 65481, 65497, 65510, 65512, 65514, + 65516, 65518, 65520, 65522, 65524, 65526, 65528, 65530, 65532, 65534, + 65535}; + + + +/* function to be converted to fixed point */ +static __inline WebRtc_UWord32 piecewise(WebRtc_Word32 xinQ15) { + + WebRtc_Word32 ind, qtmp1, qtmp2, qtmp3; + WebRtc_UWord32 tmpUW32; + + + qtmp2 = xinQ15; + + if (qtmp2 < kHistEdgesQ15[0]) { + qtmp2 = kHistEdgesQ15[0]; + } + if (qtmp2 > kHistEdgesQ15[50]) { + qtmp2 = kHistEdgesQ15[50]; + } + + qtmp1 = qtmp2 - kHistEdgesQ15[0]; /* Q15 - Q15 = Q15 */ + ind = (qtmp1 * 5) >> 16; /* 2^16 / 5 = 0.4 in Q15 */ + /* Q15 -> Q0 */ + qtmp1 = qtmp2 - kHistEdgesQ15[ind]; /* Q15 - Q15 = Q15 */ + qtmp2 = kCdfSlopeQ0[ind] * qtmp1; /* Q0 * Q15 = Q15 */ + qtmp3 = qtmp2>>15; /* Q15 -> Q0 */ + + tmpUW32 = kCdfQ16[ind] + qtmp3; /* Q0 + Q0 = Q0 */ + return tmpUW32; +} + + + +int WebRtcIsac_EncLogisticMulti2( + Bitstr *streamdata, /* in-/output struct containing bitstream */ + WebRtc_Word16 *dataQ7, /* input: data vector */ + const WebRtc_UWord16 *envQ8, /* input: side info vector defining the width of the pdf */ + const int N, /* input: data vector length / 2 */ + const WebRtc_Word16 isSWB12kHz) +{ + WebRtc_UWord32 W_lower, W_upper; + WebRtc_UWord32 W_upper_LSB, W_upper_MSB; + WebRtc_UWord8 *stream_ptr; + WebRtc_UWord8 *maxStreamPtr; + WebRtc_UWord8 *stream_ptr_carry; + WebRtc_UWord32 cdf_lo, cdf_hi; + int k; + + /* point to beginning of stream buffer */ + stream_ptr = streamdata->stream + streamdata->stream_index; + W_upper = streamdata->W_upper; + + maxStreamPtr = streamdata->stream + STREAM_SIZE_MAX_60 - 1; + for (k = 0; k < N; k++) + { + /* compute cdf_lower and cdf_upper by evaluating the piecewise linear cdf */ + cdf_lo = piecewise((*dataQ7 - 64) * *envQ8); + cdf_hi = piecewise((*dataQ7 + 64) * *envQ8); + + /* test and clip if probability gets too small */ + while (cdf_lo+1 >= cdf_hi) { + /* clip */ + if (*dataQ7 > 0) { + *dataQ7 -= 128; + cdf_hi = cdf_lo; + cdf_lo = piecewise((*dataQ7 - 64) * *envQ8); + } else { + *dataQ7 += 128; + cdf_lo = cdf_hi; + cdf_hi = piecewise((*dataQ7 + 64) * *envQ8); + } + } + + dataQ7++; + // increment only once per 4 iterations for SWB-16kHz or WB + // increment only once per 2 iterations for SWB-12kHz + envQ8 += (isSWB12kHz)? (k & 1):((k & 1) & (k >> 1)); + + + /* update interval */ + W_upper_LSB = W_upper & 0x0000FFFF; + W_upper_MSB = W_upper >> 16; + W_lower = W_upper_MSB * cdf_lo; + W_lower += (W_upper_LSB * cdf_lo) >> 16; + W_upper = W_upper_MSB * cdf_hi; + W_upper += (W_upper_LSB * cdf_hi) >> 16; + + /* shift interval such that it begins at zero */ + W_upper -= ++W_lower; + + /* add integer to bitstream */ + streamdata->streamval += W_lower; + + /* handle carry */ + if (streamdata->streamval < W_lower) + { + /* propagate carry */ + stream_ptr_carry = stream_ptr; + while (!(++(*--stream_ptr_carry))); + } + + /* renormalize interval, store most significant byte of streamval and update streamval */ + while ( !(W_upper & 0xFF000000) ) /* W_upper < 2^24 */ + { + W_upper <<= 8; + *stream_ptr++ = (WebRtc_UWord8) (streamdata->streamval >> 24); + + if(stream_ptr > maxStreamPtr) + { + return -ISAC_DISALLOWED_BITSTREAM_LENGTH; + } + streamdata->streamval <<= 8; + } + } + + /* calculate new stream_index */ + streamdata->stream_index = (int)(stream_ptr - streamdata->stream); + streamdata->W_upper = W_upper; + + return 0; +} + + + +int WebRtcIsac_DecLogisticMulti2( + WebRtc_Word16 *dataQ7, /* output: data vector */ + Bitstr *streamdata, /* in-/output struct containing bitstream */ + const WebRtc_UWord16 *envQ8, /* input: side info vector defining the width of the pdf */ + const WebRtc_Word16 *ditherQ7,/* input: dither vector */ + const int N, /* input: data vector length */ + const WebRtc_Word16 isSWB12kHz) +{ + WebRtc_UWord32 W_lower, W_upper; + WebRtc_UWord32 W_tmp; + WebRtc_UWord32 W_upper_LSB, W_upper_MSB; + WebRtc_UWord32 streamval; + const WebRtc_UWord8 *stream_ptr; + WebRtc_UWord32 cdf_tmp; + WebRtc_Word16 candQ7; + int k; + + stream_ptr = streamdata->stream + streamdata->stream_index; + W_upper = streamdata->W_upper; + if (streamdata->stream_index == 0) /* first time decoder is called for this stream */ + { + /* read first word from bytestream */ + streamval = *stream_ptr << 24; + streamval |= *++stream_ptr << 16; + streamval |= *++stream_ptr << 8; + streamval |= *++stream_ptr; + } else { + streamval = streamdata->streamval; + } + + + for (k = 0; k < N; k++) + { + /* find the integer *data for which streamval lies in [W_lower+1, W_upper] */ + W_upper_LSB = W_upper & 0x0000FFFF; + W_upper_MSB = W_upper >> 16; + + /* find first candidate by inverting the logistic cdf */ + candQ7 = - *ditherQ7 + 64; + cdf_tmp = piecewise(candQ7 * *envQ8); + + W_tmp = W_upper_MSB * cdf_tmp; + W_tmp += (W_upper_LSB * cdf_tmp) >> 16; + if (streamval > W_tmp) + { + W_lower = W_tmp; + candQ7 += 128; + cdf_tmp = piecewise(candQ7 * *envQ8); + + W_tmp = W_upper_MSB * cdf_tmp; + W_tmp += (W_upper_LSB * cdf_tmp) >> 16; + while (streamval > W_tmp) + { + W_lower = W_tmp; + candQ7 += 128; + cdf_tmp = piecewise(candQ7 * *envQ8); + + W_tmp = W_upper_MSB * cdf_tmp; + W_tmp += (W_upper_LSB * cdf_tmp) >> 16; + + /* error check */ + if (W_lower == W_tmp) return -1; + } + W_upper = W_tmp; + + /* another sample decoded */ + *dataQ7 = candQ7 - 64; + } + else + { + W_upper = W_tmp; + candQ7 -= 128; + cdf_tmp = piecewise(candQ7 * *envQ8); + + W_tmp = W_upper_MSB * cdf_tmp; + W_tmp += (W_upper_LSB * cdf_tmp) >> 16; + while ( !(streamval > W_tmp) ) + { + W_upper = W_tmp; + candQ7 -= 128; + cdf_tmp = piecewise(candQ7 * *envQ8); + + W_tmp = W_upper_MSB * cdf_tmp; + W_tmp += (W_upper_LSB * cdf_tmp) >> 16; + + /* error check */ + if (W_upper == W_tmp) return -1; + } + W_lower = W_tmp; + + /* another sample decoded */ + *dataQ7 = candQ7 + 64; + } + ditherQ7++; + dataQ7++; + // increment only once per 4 iterations for SWB-16kHz or WB + // increment only once per 2 iterations for SWB-12kHz + envQ8 += (isSWB12kHz)? (k & 1):((k & 1) & (k >> 1)); + + /* shift interval to start at zero */ + W_upper -= ++W_lower; + + /* add integer to bitstream */ + streamval -= W_lower; + + /* renormalize interval and update streamval */ + while ( !(W_upper & 0xFF000000) ) /* W_upper < 2^24 */ + { + /* read next byte from stream */ + streamval = (streamval << 8) | *++stream_ptr; + W_upper <<= 8; + } + } + + streamdata->stream_index = (int)(stream_ptr - streamdata->stream); + streamdata->W_upper = W_upper; + streamdata->streamval = streamval; + + /* find number of bytes in original stream (determined by current interval width) */ + if ( W_upper > 0x01FFFFFF ) + return streamdata->stream_index - 2; + else + return streamdata->stream_index - 1; +} diff --git a/libs/miniwebrtc/audio/coding_isac/main/bandwidth_estimator.c b/libs/miniwebrtc/audio/coding_isac/main/bandwidth_estimator.c new file mode 100644 index 00000000..d0a50c52 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/bandwidth_estimator.c @@ -0,0 +1,1020 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * BwEstimator.c + * + * This file contains the code for the Bandwidth Estimator designed + * for iSAC. + * + */ + +#include "bandwidth_estimator.h" +#include "settings.h" +#include "isac.h" + +#include + +/* array of quantization levels for bottle neck info; Matlab code: */ +/* sprintf('%4.1ff, ', logspace(log10(5000), log10(40000), 12)) */ +static const float kQRateTableWb[12] = +{ + 10000.0f, 11115.3f, 12355.1f, 13733.1f, 15264.8f, 16967.3f, + 18859.8f, 20963.3f, 23301.4f, 25900.3f, 28789.0f, 32000.0f}; + + +static const float kQRateTableSwb[24] = +{ + 10000.0f, 11115.3f, 12355.1f, 13733.1f, 15264.8f, 16967.3f, + 18859.8f, 20963.3f, 23153.1f, 25342.9f, 27532.7f, 29722.5f, + 31912.3f, 34102.1f, 36291.9f, 38481.7f, 40671.4f, 42861.2f, + 45051.0f, 47240.8f, 49430.6f, 51620.4f, 53810.2f, 56000.0f, +}; + + + + +WebRtc_Word32 WebRtcIsac_InitBandwidthEstimator( + BwEstimatorstr* bwest_str, + enum IsacSamplingRate encoderSampRate, + enum IsacSamplingRate decoderSampRate) +{ + switch(encoderSampRate) + { + case kIsacWideband: + { + bwest_str->send_bw_avg = INIT_BN_EST_WB; + break; + } + case kIsacSuperWideband: + { + bwest_str->send_bw_avg = INIT_BN_EST_SWB; + break; + } + } + + switch(decoderSampRate) + { + case kIsacWideband: + { + bwest_str->prev_frame_length = INIT_FRAME_LEN_WB; + bwest_str->rec_bw_inv = 1.0f / + (INIT_BN_EST_WB + INIT_HDR_RATE_WB); + bwest_str->rec_bw = (WebRtc_Word32)INIT_BN_EST_WB; + bwest_str->rec_bw_avg_Q = INIT_BN_EST_WB; + bwest_str->rec_bw_avg = INIT_BN_EST_WB + INIT_HDR_RATE_WB; + bwest_str->rec_header_rate = INIT_HDR_RATE_WB; + break; + } + case kIsacSuperWideband: + { + bwest_str->prev_frame_length = INIT_FRAME_LEN_SWB; + bwest_str->rec_bw_inv = 1.0f / + (INIT_BN_EST_SWB + INIT_HDR_RATE_SWB); + bwest_str->rec_bw = (WebRtc_Word32)INIT_BN_EST_SWB; + bwest_str->rec_bw_avg_Q = INIT_BN_EST_SWB; + bwest_str->rec_bw_avg = INIT_BN_EST_SWB + INIT_HDR_RATE_SWB; + bwest_str->rec_header_rate = INIT_HDR_RATE_SWB; + break; + } + } + + bwest_str->prev_rec_rtp_number = 0; + bwest_str->prev_rec_arr_ts = 0; + bwest_str->prev_rec_send_ts = 0; + bwest_str->prev_rec_rtp_rate = 1.0f; + bwest_str->last_update_ts = 0; + bwest_str->last_reduction_ts = 0; + bwest_str->count_tot_updates_rec = -9; + bwest_str->rec_jitter = 10.0f; + bwest_str->rec_jitter_short_term = 0.0f; + bwest_str->rec_jitter_short_term_abs = 5.0f; + bwest_str->rec_max_delay = 10.0f; + bwest_str->rec_max_delay_avg_Q = 10.0f; + bwest_str->num_pkts_rec = 0; + + bwest_str->send_max_delay_avg = 10.0f; + + bwest_str->hsn_detect_rec = 0; + + bwest_str->num_consec_rec_pkts_over_30k = 0; + + bwest_str->hsn_detect_snd = 0; + + bwest_str->num_consec_snt_pkts_over_30k = 0; + + bwest_str->in_wait_period = 0; + + bwest_str->change_to_WB = 0; + + bwest_str->numConsecLatePkts = 0; + bwest_str->consecLatency = 0; + bwest_str->inWaitLatePkts = 0; + bwest_str->senderTimestamp = 0; + bwest_str->receiverTimestamp = 0; + return 0; +} + +/* This function updates both bottle neck rates */ +/* Parameters: */ +/* rtp_number - value from RTP packet, from NetEq */ +/* frame length - length of signal frame in ms, from iSAC decoder */ +/* send_ts - value in RTP header giving send time in samples */ +/* arr_ts - value given by timeGetTime() time of arrival in samples of packet from NetEq */ +/* pksize - size of packet in bytes, from NetEq */ +/* Index - integer (range 0...23) indicating bottle neck & jitter as estimated by other side */ +/* returns 0 if everything went fine, -1 otherwise */ +WebRtc_Word16 WebRtcIsac_UpdateBandwidthEstimator( + BwEstimatorstr *bwest_str, + const WebRtc_UWord16 rtp_number, + const WebRtc_Word32 frame_length, + const WebRtc_UWord32 send_ts, + const WebRtc_UWord32 arr_ts, + const WebRtc_Word32 pksize + /*, const WebRtc_UWord16 Index*/) +{ + float weight = 0.0f; + float curr_bw_inv = 0.0f; + float rec_rtp_rate; + float t_diff_proj; + float arr_ts_diff; + float send_ts_diff; + float arr_time_noise; + float arr_time_noise_abs; + + float delay_correction_factor = 1; + float late_diff = 0.0f; + int immediate_set = 0; + int num_pkts_expected; + + + // We have to adjust the header-rate if the first packet has a + // frame-size different than the initialized value. + if ( frame_length != bwest_str->prev_frame_length ) + { + bwest_str->rec_header_rate = (float)HEADER_SIZE * 8.0f * + 1000.0f / (float)frame_length; /* bits/s */ + } + + /* UPDATE ESTIMATES ON THIS SIDE */ + /* compute far-side transmission rate */ + rec_rtp_rate = ((float)pksize * 8.0f * 1000.0f / (float)frame_length) + + bwest_str->rec_header_rate; + // rec_rtp_rate packet bits/s + header bits/s + + /* check for timer wrap-around */ + if (arr_ts < bwest_str->prev_rec_arr_ts) + { + bwest_str->prev_rec_arr_ts = arr_ts; + bwest_str->last_update_ts = arr_ts; + bwest_str->last_reduction_ts = arr_ts + 3*FS; + bwest_str->num_pkts_rec = 0; + + /* store frame length */ + bwest_str->prev_frame_length = frame_length; + + /* store far-side transmission rate */ + bwest_str->prev_rec_rtp_rate = rec_rtp_rate; + + /* store far-side RTP time stamp */ + bwest_str->prev_rec_rtp_number = rtp_number; + + return 0; + } + + bwest_str->num_pkts_rec++; + + /* check that it's not one of the first 9 packets */ + if ( bwest_str->count_tot_updates_rec > 0 ) + { + if(bwest_str->in_wait_period > 0 ) + { + bwest_str->in_wait_period--; + } + + bwest_str->inWaitLatePkts -= ((bwest_str->inWaitLatePkts > 0)? 1:0); + send_ts_diff = (float)(send_ts - bwest_str->prev_rec_send_ts); + + if (send_ts_diff <= (16 * frame_length)*2) + //doesn't allow for a dropped packet, not sure necessary to be + // that strict -DH + { + /* if not been updated for a long time, reduce the BN estimate */ + if((WebRtc_UWord32)(arr_ts - bwest_str->last_update_ts) * + 1000.0f / FS > 3000) + { + //how many frames should have been received since the last + // update if too many have been dropped or there have been + // big delays won't allow this reduction may no longer need + // the send_ts_diff here + num_pkts_expected = (int)(((float)(arr_ts - + bwest_str->last_update_ts) * 1000.0f /(float) FS) / + (float)frame_length); + + if(((float)bwest_str->num_pkts_rec/(float)num_pkts_expected) > + 0.9) + { + float inv_bitrate = (float) pow( 0.99995, + (double)((WebRtc_UWord32)(arr_ts - + bwest_str->last_reduction_ts)*1000.0f/FS) ); + + if ( inv_bitrate ) + { + bwest_str->rec_bw_inv /= inv_bitrate; + + //precautionary, likely never necessary + if (bwest_str->hsn_detect_snd && + bwest_str->hsn_detect_rec) + { + if (bwest_str->rec_bw_inv > 0.000066f) + { + bwest_str->rec_bw_inv = 0.000066f; + } + } + } + else + { + bwest_str->rec_bw_inv = 1.0f / + (INIT_BN_EST_WB + INIT_HDR_RATE_WB); + } + /* reset time-since-update counter */ + bwest_str->last_reduction_ts = arr_ts; + } + else + //reset here? + { + bwest_str->last_reduction_ts = arr_ts + 3*FS; + bwest_str->last_update_ts = arr_ts; + bwest_str->num_pkts_rec = 0; + } + } + } + else + { + bwest_str->last_reduction_ts = arr_ts + 3*FS; + bwest_str->last_update_ts = arr_ts; + bwest_str->num_pkts_rec = 0; + } + + + /* temporarily speed up adaptation if frame length has changed */ + if ( frame_length != bwest_str->prev_frame_length ) + { + bwest_str->count_tot_updates_rec = 10; + bwest_str->rec_header_rate = (float)HEADER_SIZE * 8.0f * + 1000.0f / (float)frame_length; /* bits/s */ + + bwest_str->rec_bw_inv = 1.0f /((float)bwest_str->rec_bw + + bwest_str->rec_header_rate); + } + + //////////////////////// + arr_ts_diff = (float)(arr_ts - bwest_str->prev_rec_arr_ts); + + if (send_ts_diff > 0 ) + { + late_diff = arr_ts_diff - send_ts_diff; + } + else + { + late_diff = arr_ts_diff - (float)(16 * frame_length); + } + + if((late_diff > 0) && !bwest_str->inWaitLatePkts) + { + bwest_str->numConsecLatePkts++; + bwest_str->consecLatency += late_diff; + } + else + { + bwest_str->numConsecLatePkts = 0; + bwest_str->consecLatency = 0; + } + if(bwest_str->numConsecLatePkts > 50) + { + float latencyMs = bwest_str->consecLatency/(FS/1000); + float averageLatencyMs = latencyMs / bwest_str->numConsecLatePkts; + delay_correction_factor = frame_length / (frame_length + averageLatencyMs); + immediate_set = 1; + bwest_str->inWaitLatePkts = (WebRtc_Word16)((bwest_str->consecLatency/(FS/1000)) / 30);// + 150; + bwest_str->start_wait_period = arr_ts; + } + /////////////////////////////////////////////// + + + + /* update only if previous packet was not lost */ + if ( rtp_number == bwest_str->prev_rec_rtp_number + 1 ) + { + + + if (!(bwest_str->hsn_detect_snd && bwest_str->hsn_detect_rec)) + { + if ((arr_ts_diff > (float)(16 * frame_length))) + { + //1/2 second + if ((late_diff > 8000.0f) && !bwest_str->in_wait_period) + { + delay_correction_factor = 0.7f; + bwest_str->in_wait_period = 55; + bwest_str->start_wait_period = arr_ts; + immediate_set = 1; + } + //320 ms + else if (late_diff > 5120.0f && !bwest_str->in_wait_period) + { + delay_correction_factor = 0.8f; + immediate_set = 1; + bwest_str->in_wait_period = 44; + bwest_str->start_wait_period = arr_ts; + } + } + } + + + if ((bwest_str->prev_rec_rtp_rate > bwest_str->rec_bw_avg) && + (rec_rtp_rate > bwest_str->rec_bw_avg) && + !bwest_str->in_wait_period) + { + /* test if still in initiation period and increment counter */ + if (bwest_str->count_tot_updates_rec++ > 99) + { + /* constant weight after initiation part */ + weight = 0.01f; + } + else + { + /* weight decreases with number of updates */ + weight = 1.0f / (float) bwest_str->count_tot_updates_rec; + } + /* Bottle Neck Estimation */ + + /* limit outliers */ + /* if more than 25 ms too much */ + if (arr_ts_diff > frame_length * FS/1000 + 400.0f) + { + // in samples, why 25ms?? + arr_ts_diff = frame_length * FS/1000 + 400.0f; + } + if(arr_ts_diff < (frame_length * FS/1000) - 160.0f) + { + /* don't allow it to be less than frame rate - 10 ms */ + arr_ts_diff = (float)frame_length * FS/1000 - 160.0f; + } + + /* compute inverse receiving rate for last packet */ + curr_bw_inv = arr_ts_diff / ((float)(pksize + HEADER_SIZE) * + 8.0f * FS); // (180+35)*8*16000 = 27.5 Mbit.... + + + if(curr_bw_inv < + (1.0f / (MAX_ISAC_BW + bwest_str->rec_header_rate))) + { + // don't allow inv rate to be larger than MAX + curr_bw_inv = (1.0f / + (MAX_ISAC_BW + bwest_str->rec_header_rate)); + } + + /* update bottle neck rate estimate */ + bwest_str->rec_bw_inv = weight * curr_bw_inv + + (1.0f - weight) * bwest_str->rec_bw_inv; + + /* reset time-since-update counter */ + bwest_str->last_update_ts = arr_ts; + bwest_str->last_reduction_ts = arr_ts + 3 * FS; + bwest_str->num_pkts_rec = 0; + + /* Jitter Estimation */ + /* projected difference between arrival times */ + t_diff_proj = ((float)(pksize + HEADER_SIZE) * 8.0f * + 1000.0f) / bwest_str->rec_bw_avg; + + + // difference between projected and actual + // arrival time differences + arr_time_noise = (float)(arr_ts_diff*1000.0f/FS) - + t_diff_proj; + arr_time_noise_abs = (float) fabs( arr_time_noise ); + + /* long term averaged absolute jitter */ + bwest_str->rec_jitter = weight * arr_time_noise_abs + + (1.0f - weight) * bwest_str->rec_jitter; + if (bwest_str->rec_jitter > 10.0f) + { + bwest_str->rec_jitter = 10.0f; + } + /* short term averaged absolute jitter */ + bwest_str->rec_jitter_short_term_abs = 0.05f * + arr_time_noise_abs + 0.95f * + bwest_str->rec_jitter_short_term_abs; + + /* short term averaged jitter */ + bwest_str->rec_jitter_short_term = 0.05f * arr_time_noise + + 0.95f * bwest_str->rec_jitter_short_term; + } + } + } + else + { + // reset time-since-update counter when + // receiving the first 9 packets + bwest_str->last_update_ts = arr_ts; + bwest_str->last_reduction_ts = arr_ts + 3*FS; + bwest_str->num_pkts_rec = 0; + + bwest_str->count_tot_updates_rec++; + } + + /* limit minimum bottle neck rate */ + if (bwest_str->rec_bw_inv > 1.0f / ((float)MIN_ISAC_BW + + bwest_str->rec_header_rate)) + { + bwest_str->rec_bw_inv = 1.0f / ((float)MIN_ISAC_BW + + bwest_str->rec_header_rate); + } + + // limit maximum bitrate + if (bwest_str->rec_bw_inv < 1.0f / ((float)MAX_ISAC_BW + + bwest_str->rec_header_rate)) + { + bwest_str->rec_bw_inv = 1.0f / ((float)MAX_ISAC_BW + + bwest_str->rec_header_rate); + } + + /* store frame length */ + bwest_str->prev_frame_length = frame_length; + + /* store far-side transmission rate */ + bwest_str->prev_rec_rtp_rate = rec_rtp_rate; + + /* store far-side RTP time stamp */ + bwest_str->prev_rec_rtp_number = rtp_number; + + // Replace bwest_str->rec_max_delay by the new + // value (atomic operation) + bwest_str->rec_max_delay = 3.0f * bwest_str->rec_jitter; + + /* store send and arrival time stamp */ + bwest_str->prev_rec_arr_ts = arr_ts ; + bwest_str->prev_rec_send_ts = send_ts; + + /* Replace bwest_str->rec_bw by the new value (atomic operation) */ + bwest_str->rec_bw = (WebRtc_Word32)(1.0f / bwest_str->rec_bw_inv - + bwest_str->rec_header_rate); + + if (immediate_set) + { + bwest_str->rec_bw = (WebRtc_Word32) (delay_correction_factor * + (float) bwest_str->rec_bw); + + if (bwest_str->rec_bw < (WebRtc_Word32) MIN_ISAC_BW) + { + bwest_str->rec_bw = (WebRtc_Word32) MIN_ISAC_BW; + } + + bwest_str->rec_bw_avg = bwest_str->rec_bw + + bwest_str->rec_header_rate; + + bwest_str->rec_bw_avg_Q = (float) bwest_str->rec_bw; + + bwest_str->rec_jitter_short_term = 0.0f; + + bwest_str->rec_bw_inv = 1.0f / (bwest_str->rec_bw + + bwest_str->rec_header_rate); + + bwest_str->count_tot_updates_rec = 1; + + immediate_set = 0; + bwest_str->consecLatency = 0; + bwest_str->numConsecLatePkts = 0; + } + + return 0; +} + + +/* This function updates the send bottle neck rate */ +/* Index - integer (range 0...23) indicating bottle neck & jitter as estimated by other side */ +/* returns 0 if everything went fine, -1 otherwise */ +WebRtc_Word16 WebRtcIsac_UpdateUplinkBwImpl( + BwEstimatorstr* bwest_str, + WebRtc_Word16 index, + enum IsacSamplingRate encoderSamplingFreq) +{ + if((index < 0) || (index > 23)) + { + return -ISAC_RANGE_ERROR_BW_ESTIMATOR; + } + + /* UPDATE ESTIMATES FROM OTHER SIDE */ + if(encoderSamplingFreq == kIsacWideband) + { + if(index > 11) + { + index -= 12; + /* compute the jitter estimate as decoded on the other side */ + bwest_str->send_max_delay_avg = 0.9f * bwest_str->send_max_delay_avg + + 0.1f * (float)MAX_ISAC_MD; + } + else + { + /* compute the jitter estimate as decoded on the other side */ + bwest_str->send_max_delay_avg = 0.9f * bwest_str->send_max_delay_avg + + 0.1f * (float)MIN_ISAC_MD; + } + + /* compute the BN estimate as decoded on the other side */ + bwest_str->send_bw_avg = 0.9f * bwest_str->send_bw_avg + + 0.1f * kQRateTableWb[index]; + } + else + { + /* compute the BN estimate as decoded on the other side */ + bwest_str->send_bw_avg = 0.9f * bwest_str->send_bw_avg + + 0.1f * kQRateTableSwb[index]; + } + + if (bwest_str->send_bw_avg > (float) 28000 && !bwest_str->hsn_detect_snd) + { + bwest_str->num_consec_snt_pkts_over_30k++; + + if (bwest_str->num_consec_snt_pkts_over_30k >= 66) + { + //approx 2 seconds with 30ms frames + bwest_str->hsn_detect_snd = 1; + } + } + else if (!bwest_str->hsn_detect_snd) + { + bwest_str->num_consec_snt_pkts_over_30k = 0; + } + return 0; +} + +// called when there is upper-band bit-stream to update jitter +// statistics. +WebRtc_Word16 WebRtcIsac_UpdateUplinkJitter( + BwEstimatorstr* bwest_str, + WebRtc_Word32 index) +{ + if((index < 0) || (index > 23)) + { + return -ISAC_RANGE_ERROR_BW_ESTIMATOR; + } + + if(index > 0) + { + /* compute the jitter estimate as decoded on the other side */ + bwest_str->send_max_delay_avg = 0.9f * bwest_str->send_max_delay_avg + + 0.1f * (float)MAX_ISAC_MD; + } + else + { + /* compute the jitter estimate as decoded on the other side */ + bwest_str->send_max_delay_avg = 0.9f * bwest_str->send_max_delay_avg + + 0.1f * (float)MIN_ISAC_MD; + } + + return 0; +} + + + +// Returns the bandwidth/jitter estimation code (integer 0...23) +// to put in the sending iSAC payload +WebRtc_UWord16 +WebRtcIsac_GetDownlinkBwJitIndexImpl( + BwEstimatorstr* bwest_str, + WebRtc_Word16* bottleneckIndex, + WebRtc_Word16* jitterInfo, + enum IsacSamplingRate decoderSamplingFreq) +{ + float MaxDelay; + //WebRtc_UWord16 MaxDelayBit; + + float rate; + float r; + float e1, e2; + const float weight = 0.1f; + const float* ptrQuantizationTable; + WebRtc_Word16 addJitterInfo; + WebRtc_Word16 minInd; + WebRtc_Word16 maxInd; + WebRtc_Word16 midInd; + + /* Get Max Delay Bit */ + /* get unquantized max delay */ + MaxDelay = (float)WebRtcIsac_GetDownlinkMaxDelay(bwest_str); + + if ( ((1.f - weight) * bwest_str->rec_max_delay_avg_Q + weight * + MAX_ISAC_MD - MaxDelay) > (MaxDelay - (1.f-weight) * + bwest_str->rec_max_delay_avg_Q - weight * MIN_ISAC_MD) ) + { + jitterInfo[0] = 0; + /* update quantized average */ + bwest_str->rec_max_delay_avg_Q = + (1.f - weight) * bwest_str->rec_max_delay_avg_Q + weight * + (float)MIN_ISAC_MD; + } + else + { + jitterInfo[0] = 1; + /* update quantized average */ + bwest_str->rec_max_delay_avg_Q = + (1.f-weight) * bwest_str->rec_max_delay_avg_Q + weight * + (float)MAX_ISAC_MD; + } + + // Get unquantized rate. + rate = (float)WebRtcIsac_GetDownlinkBandwidth(bwest_str); + + /* Get Rate Index */ + if(decoderSamplingFreq == kIsacWideband) + { + ptrQuantizationTable = kQRateTableWb; + addJitterInfo = 1; + maxInd = 11; + } + else + { + ptrQuantizationTable = kQRateTableSwb; + addJitterInfo = 0; + maxInd = 23; + } + + minInd = 0; + while(maxInd > minInd + 1) + { + midInd = (maxInd + minInd) >> 1; + if(rate > ptrQuantizationTable[midInd]) + { + minInd = midInd; + } + else + { + maxInd = midInd; + } + } + // Chose the index which gives results an average which is closest + // to rate + r = (1 - weight) * bwest_str->rec_bw_avg_Q - rate; + e1 = weight * ptrQuantizationTable[minInd] + r; + e2 = weight * ptrQuantizationTable[maxInd] + r; + e1 = (e1 > 0)? e1:-e1; + e2 = (e2 > 0)? e2:-e2; + if(e1 < e2) + { + bottleneckIndex[0] = minInd; + } + else + { + bottleneckIndex[0] = maxInd; + } + + bwest_str->rec_bw_avg_Q = (1 - weight) * bwest_str->rec_bw_avg_Q + + weight * ptrQuantizationTable[bottleneckIndex[0]]; + bottleneckIndex[0] += jitterInfo[0] * 12 * addJitterInfo; + + bwest_str->rec_bw_avg = (1 - weight) * bwest_str->rec_bw_avg + weight * + (rate + bwest_str->rec_header_rate); + + return 0; +} + + + +/* get the bottle neck rate from far side to here, as estimated on this side */ +WebRtc_Word32 WebRtcIsac_GetDownlinkBandwidth( const BwEstimatorstr *bwest_str) +{ + WebRtc_Word32 rec_bw; + float jitter_sign; + float bw_adjust; + + /* create a value between -1.0 and 1.0 indicating "average sign" of jitter */ + jitter_sign = bwest_str->rec_jitter_short_term / + bwest_str->rec_jitter_short_term_abs; + + /* adjust bw proportionally to negative average jitter sign */ + bw_adjust = 1.0f - jitter_sign * (0.15f + 0.15f * jitter_sign * jitter_sign); + + /* adjust Rate if jitter sign is mostly constant */ + rec_bw = (WebRtc_Word32)(bwest_str->rec_bw * bw_adjust); + + /* limit range of bottle neck rate */ + if (rec_bw < MIN_ISAC_BW) + { + rec_bw = MIN_ISAC_BW; + } + else if (rec_bw > MAX_ISAC_BW) + { + rec_bw = MAX_ISAC_BW; + } + return rec_bw; +} + +/* Returns the max delay (in ms) */ +WebRtc_Word32 +WebRtcIsac_GetDownlinkMaxDelay(const BwEstimatorstr *bwest_str) +{ + WebRtc_Word32 rec_max_delay; + + rec_max_delay = (WebRtc_Word32)(bwest_str->rec_max_delay); + + /* limit range of jitter estimate */ + if (rec_max_delay < MIN_ISAC_MD) + { + rec_max_delay = MIN_ISAC_MD; + } + else if (rec_max_delay > MAX_ISAC_MD) + { + rec_max_delay = MAX_ISAC_MD; + } + return rec_max_delay; +} + +/* get the bottle neck rate from here to far side, as estimated by far side */ +void +WebRtcIsac_GetUplinkBandwidth( + const BwEstimatorstr* bwest_str, + WebRtc_Word32* bitRate) +{ + /* limit range of bottle neck rate */ + if (bwest_str->send_bw_avg < MIN_ISAC_BW) + { + *bitRate = MIN_ISAC_BW; + } + else if (bwest_str->send_bw_avg > MAX_ISAC_BW) + { + *bitRate = MAX_ISAC_BW; + } + else + { + *bitRate = (WebRtc_Word32)(bwest_str->send_bw_avg); + } + return; +} + +/* Returns the max delay value from the other side in ms */ +WebRtc_Word32 +WebRtcIsac_GetUplinkMaxDelay(const BwEstimatorstr *bwest_str) +{ + WebRtc_Word32 send_max_delay; + + send_max_delay = (WebRtc_Word32)(bwest_str->send_max_delay_avg); + + /* limit range of jitter estimate */ + if (send_max_delay < MIN_ISAC_MD) + { + send_max_delay = MIN_ISAC_MD; + } + else if (send_max_delay > MAX_ISAC_MD) + { + send_max_delay = MAX_ISAC_MD; + } + return send_max_delay; +} + + +/* + * update long-term average bitrate and amount of data in buffer + * returns minimum payload size (bytes) + */ +int WebRtcIsac_GetMinBytes( + RateModel* State, + int StreamSize, /* bytes in bitstream */ + const int FrameSamples, /* samples per frame */ + const double BottleNeck, /* bottle neck rate; excl headers (bps) */ + const double DelayBuildUp, /* max delay from bottleneck buffering (ms) */ + enum ISACBandwidth bandwidth + /*,WebRtc_Word16 frequentLargePackets*/) +{ + double MinRate = 0.0; + int MinBytes; + double TransmissionTime; + int burstInterval = BURST_INTERVAL; + + // first 10 packets @ low rate, then INIT_BURST_LEN packets @ + // fixed rate of INIT_RATE bps + if (State->InitCounter > 0) + { + if (State->InitCounter-- <= INIT_BURST_LEN) + { + if(bandwidth == isac8kHz) + { + MinRate = INIT_RATE_WB; + } + else + { + MinRate = INIT_RATE_SWB; + } + } + else + { + MinRate = 0; + } + } + else + { + /* handle burst */ + if (State->BurstCounter) + { + if (State->StillBuffered < (1.0 - 1.0/BURST_LEN) * DelayBuildUp) + { + /* max bps derived from BottleNeck and DelayBuildUp values */ + MinRate = (1.0 + (FS/1000) * DelayBuildUp / + (double)(BURST_LEN * FrameSamples)) * BottleNeck; + } + else + { + // max bps derived from StillBuffered and DelayBuildUp + // values + MinRate = (1.0 + (FS/1000) * (DelayBuildUp - + State->StillBuffered) / (double)FrameSamples) * BottleNeck; + if (MinRate < 1.04 * BottleNeck) + { + MinRate = 1.04 * BottleNeck; + } + } + State->BurstCounter--; + } + } + + + /* convert rate from bits/second to bytes/packet */ + MinBytes = (int) (MinRate * FrameSamples / (8.0 * FS)); + + /* StreamSize will be adjusted if less than MinBytes */ + if (StreamSize < MinBytes) + { + StreamSize = MinBytes; + } + + /* keep track of when bottle neck was last exceeded by at least 1% */ + if (StreamSize * 8.0 * FS / FrameSamples > 1.01 * BottleNeck) { + if (State->PrevExceed) { + /* bottle_neck exceded twice in a row, decrease ExceedAgo */ + State->ExceedAgo -= /*BURST_INTERVAL*/ burstInterval / (BURST_LEN - 1); + if (State->ExceedAgo < 0) + State->ExceedAgo = 0; + } + else + { + State->ExceedAgo += (FrameSamples * 1000) / FS; /* ms */ + State->PrevExceed = 1; + } + } + else + { + State->PrevExceed = 0; + State->ExceedAgo += (FrameSamples * 1000) / FS; /* ms */ + } + + /* set burst flag if bottle neck not exceeded for long time */ + if ((State->ExceedAgo > burstInterval) && + (State->BurstCounter == 0)) + { + if (State->PrevExceed) + { + State->BurstCounter = BURST_LEN - 1; + } + else + { + State->BurstCounter = BURST_LEN; + } + } + + + /* Update buffer delay */ + TransmissionTime = StreamSize * 8.0 * 1000.0 / BottleNeck; /* ms */ + State->StillBuffered += TransmissionTime; + State->StillBuffered -= (FrameSamples * 1000) / FS; /* ms */ + if (State->StillBuffered < 0.0) + { + State->StillBuffered = 0.0; + } + + return MinBytes; +} + + +/* + * update long-term average bitrate and amount of data in buffer + */ +void WebRtcIsac_UpdateRateModel( + RateModel *State, + int StreamSize, /* bytes in bitstream */ + const int FrameSamples, /* samples per frame */ + const double BottleNeck) /* bottle neck rate; excl headers (bps) */ +{ + double TransmissionTime; + + /* avoid the initial "high-rate" burst */ + State->InitCounter = 0; + + /* Update buffer delay */ + TransmissionTime = StreamSize * 8.0 * 1000.0 / BottleNeck; /* ms */ + State->StillBuffered += TransmissionTime; + State->StillBuffered -= (FrameSamples * 1000) / FS; /* ms */ + if (State->StillBuffered < 0.0) + State->StillBuffered = 0.0; + +} + + +void WebRtcIsac_InitRateModel( + RateModel *State) +{ + State->PrevExceed = 0; /* boolean */ + State->ExceedAgo = 0; /* ms */ + State->BurstCounter = 0; /* packets */ + State->InitCounter = INIT_BURST_LEN + 10; /* packets */ + State->StillBuffered = 1.0; /* ms */ +} + +int WebRtcIsac_GetNewFrameLength( + double bottle_neck, + int current_framesamples) +{ + int new_framesamples; + + const int Thld_20_30 = 20000; + + //const int Thld_30_20 = 30000; + const int Thld_30_20 = 1000000; // disable 20 ms frames + + const int Thld_30_60 = 18000; + //const int Thld_30_60 = 0; // disable 60 ms frames + + const int Thld_60_30 = 27000; + + + new_framesamples = current_framesamples; + + /* find new framelength */ + switch(current_framesamples) { + case 320: + if (bottle_neck < Thld_20_30) + new_framesamples = 480; + break; + case 480: + if (bottle_neck < Thld_30_60) + new_framesamples = 960; + else if (bottle_neck > Thld_30_20) + new_framesamples = 320; + break; + case 960: + if (bottle_neck >= Thld_60_30) + new_framesamples = 480; + break; + } + + return new_framesamples; +} + +double WebRtcIsac_GetSnr( + double bottle_neck, + int framesamples) +{ + double s2nr; + + const double a_20 = -30.0; + const double b_20 = 0.8; + const double c_20 = 0.0; + + const double a_30 = -23.0; + const double b_30 = 0.48; + const double c_30 = 0.0; + + const double a_60 = -23.0; + const double b_60 = 0.53; + const double c_60 = 0.0; + + + /* find new SNR value */ + switch(framesamples) { + case 320: + s2nr = a_20 + b_20 * bottle_neck * 0.001 + c_20 * bottle_neck * + bottle_neck * 0.000001; + break; + case 480: + s2nr = a_30 + b_30 * bottle_neck * 0.001 + c_30 * bottle_neck * + bottle_neck * 0.000001; + break; + case 960: + s2nr = a_60 + b_60 * bottle_neck * 0.001 + c_60 * bottle_neck * + bottle_neck * 0.000001; + break; + default: + s2nr = 0; + } + + return s2nr; + +} diff --git a/libs/miniwebrtc/audio/coding_isac/main/bandwidth_estimator.h b/libs/miniwebrtc/audio/coding_isac/main/bandwidth_estimator.h new file mode 100644 index 00000000..5604d7bb --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/bandwidth_estimator.h @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * bandwidth_estimator.h + * + * This header file contains the API for the Bandwidth Estimator + * designed for iSAC. + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_ + +#include "structs.h" +#include "settings.h" + + +#define MIN_ISAC_BW 10000 +#define MIN_ISAC_BW_LB 10000 +#define MIN_ISAC_BW_UB 25000 + +#define MAX_ISAC_BW 56000 +#define MAX_ISAC_BW_UB 32000 +#define MAX_ISAC_BW_LB 32000 + +#define MIN_ISAC_MD 5 +#define MAX_ISAC_MD 25 + +// assumed header size, in bytes; we don't know the exact number +// (header compression may be used) +#define HEADER_SIZE 35 + +// Initial Frame-Size, in ms, for Wideband & Super-Wideband Mode +#define INIT_FRAME_LEN_WB 60 +#define INIT_FRAME_LEN_SWB 30 + +// Initial Bottleneck Estimate, in bits/sec, for +// Wideband & Super-wideband mode +#define INIT_BN_EST_WB 20e3f +#define INIT_BN_EST_SWB 56e3f + +// Initial Header rate (header rate depends on frame-size), +// in bits/sec, for Wideband & Super-Wideband mode. +#define INIT_HDR_RATE_WB \ + ((float)HEADER_SIZE * 8.0f * 1000.0f / (float)INIT_FRAME_LEN_WB) +#define INIT_HDR_RATE_SWB \ + ((float)HEADER_SIZE * 8.0f * 1000.0f / (float)INIT_FRAME_LEN_SWB) + +// number of packets in a row for a high rate burst +#define BURST_LEN 3 + +// ms, max time between two full bursts +#define BURST_INTERVAL 500 + +// number of packets in a row for initial high rate burst +#define INIT_BURST_LEN 5 + +// bits/s, rate for the first BURST_LEN packets +#define INIT_RATE_WB INIT_BN_EST_WB +#define INIT_RATE_SWB INIT_BN_EST_SWB + + +#if defined(__cplusplus) +extern "C" { +#endif + + /* This function initializes the struct */ + /* to be called before using the struct for anything else */ + /* returns 0 if everything went fine, -1 otherwise */ + WebRtc_Word32 WebRtcIsac_InitBandwidthEstimator( + BwEstimatorstr* bwest_str, + enum IsacSamplingRate encoderSampRate, + enum IsacSamplingRate decoderSampRate); + + /* This function updates the receiving estimate */ + /* Parameters: */ + /* rtp_number - value from RTP packet, from NetEq */ + /* frame length - length of signal frame in ms, from iSAC decoder */ + /* send_ts - value in RTP header giving send time in samples */ + /* arr_ts - value given by timeGetTime() time of arrival in samples of packet from NetEq */ + /* pksize - size of packet in bytes, from NetEq */ + /* Index - integer (range 0...23) indicating bottle neck & jitter as estimated by other side */ + /* returns 0 if everything went fine, -1 otherwise */ + WebRtc_Word16 WebRtcIsac_UpdateBandwidthEstimator( + BwEstimatorstr* bwest_str, + const WebRtc_UWord16 rtp_number, + const WebRtc_Word32 frame_length, + const WebRtc_UWord32 send_ts, + const WebRtc_UWord32 arr_ts, + const WebRtc_Word32 pksize); + + /* Update receiving estimates. Used when we only receive BWE index, no iSAC data packet. */ + WebRtc_Word16 WebRtcIsac_UpdateUplinkBwImpl( + BwEstimatorstr* bwest_str, + WebRtc_Word16 Index, + enum IsacSamplingRate encoderSamplingFreq); + + /* Returns the bandwidth/jitter estimation code (integer 0...23) to put in the sending iSAC payload */ + WebRtc_UWord16 WebRtcIsac_GetDownlinkBwJitIndexImpl( + BwEstimatorstr* bwest_str, + WebRtc_Word16* bottleneckIndex, + WebRtc_Word16* jitterInfo, + enum IsacSamplingRate decoderSamplingFreq); + + /* Returns the bandwidth estimation (in bps) */ + WebRtc_Word32 WebRtcIsac_GetDownlinkBandwidth( + const BwEstimatorstr *bwest_str); + + /* Returns the max delay (in ms) */ + WebRtc_Word32 WebRtcIsac_GetDownlinkMaxDelay( + const BwEstimatorstr *bwest_str); + + /* Returns the bandwidth that iSAC should send with in bps */ + void WebRtcIsac_GetUplinkBandwidth( + const BwEstimatorstr* bwest_str, + WebRtc_Word32* bitRate); + + /* Returns the max delay value from the other side in ms */ + WebRtc_Word32 WebRtcIsac_GetUplinkMaxDelay( + const BwEstimatorstr *bwest_str); + + + /* + * update amount of data in bottle neck buffer and burst handling + * returns minimum payload size (bytes) + */ + int WebRtcIsac_GetMinBytes( + RateModel* State, + int StreamSize, /* bytes in bitstream */ + const int FrameLen, /* ms per frame */ + const double BottleNeck, /* bottle neck rate; excl headers (bps) */ + const double DelayBuildUp, /* max delay from bottleneck buffering (ms) */ + enum ISACBandwidth bandwidth + /*,WebRtc_Word16 frequentLargePackets*/); + + /* + * update long-term average bitrate and amount of data in buffer + */ + void WebRtcIsac_UpdateRateModel( + RateModel* State, + int StreamSize, /* bytes in bitstream */ + const int FrameSamples, /* samples per frame */ + const double BottleNeck); /* bottle neck rate; excl headers (bps) */ + + + void WebRtcIsac_InitRateModel( + RateModel *State); + + /* Returns the new framelength value (input argument: bottle_neck) */ + int WebRtcIsac_GetNewFrameLength( + double bottle_neck, + int current_framelength); + + /* Returns the new SNR value (input argument: bottle_neck) */ + double WebRtcIsac_GetSnr( + double bottle_neck, + int new_framelength); + + + WebRtc_Word16 WebRtcIsac_UpdateUplinkJitter( + BwEstimatorstr* bwest_str, + WebRtc_Word32 index); + +#if defined(__cplusplus) +} +#endif + + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_BANDWIDTH_ESTIMATOR_H_ */ diff --git a/libs/miniwebrtc/audio/coding_isac/main/codec.h b/libs/miniwebrtc/audio/coding_isac/main/codec.h new file mode 100644 index 00000000..6af27ea9 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/codec.h @@ -0,0 +1,292 @@ +/* + * 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. + */ + +/* + * codec.h + * + * This header file contains the calls to the internal encoder + * and decoder functions. + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_ + +#include "structs.h" + +int WebRtcIsac_EstimateBandwidth( + BwEstimatorstr* bwest_str, + Bitstr* streamdata, + WebRtc_Word32 packet_size, + WebRtc_UWord16 rtp_seq_number, + WebRtc_UWord32 send_ts, + WebRtc_UWord32 arr_ts, + enum IsacSamplingRate encoderSampRate, + enum IsacSamplingRate decoderSampRate); + +int WebRtcIsac_DecodeLb( + float* signal_out, + ISACLBDecStruct* ISACdec_obj, + WebRtc_Word16* current_framesamples, + WebRtc_Word16 isRCUPayload); + +int WebRtcIsac_DecodeRcuLb( + float* signal_out, + ISACLBDecStruct* ISACdec_obj, + WebRtc_Word16* current_framesamples); + +int WebRtcIsac_EncodeLb( + float* in, + ISACLBEncStruct* ISACencLB_obj, + WebRtc_Word16 codingMode, + WebRtc_Word16 bottleneckIndex); + +int WebRtcIsac_EncodeStoredDataLb( + const ISAC_SaveEncData_t* ISACSavedEnc_obj, + Bitstr* ISACBitStr_obj, + int BWnumber, + float scale); + + +int WebRtcIsac_EncodeStoredDataUb12( + const ISACUBSaveEncDataStruct* ISACSavedEnc_obj, + Bitstr* bitStream, + WebRtc_Word32 jitterInfo, + float scale); + +int WebRtcIsac_EncodeStoredDataUb16( + const ISACUBSaveEncDataStruct* ISACSavedEnc_obj, + Bitstr* bitStream, + WebRtc_Word32 jitterInfo, + float scale); + + +WebRtc_Word16 WebRtcIsac_GetRedPayloadUb( + const ISACUBSaveEncDataStruct* ISACSavedEncObj, + Bitstr* bitStreamObj, + enum ISACBandwidth bandwidth); +/****************************************************************************** + * WebRtcIsac_RateAllocation() + * Internal function to perform a rate-allocation for upper and lower-band, + * given a total rate. + * + * Input: + * - inRateBitPerSec : a total bit-rate in bits/sec. + * + * Output: + * - rateLBBitPerSec : a bit-rate allocated to the lower-band + * in bits/sec. + * - rateUBBitPerSec : a bit-rate allocated to the upper-band + * in bits/sec. + * + * Return value : 0 if rate allocation has been successful. + * -1 if failed to allocate rates. + */ + +WebRtc_Word16 +WebRtcIsac_RateAllocation( + WebRtc_Word32 inRateBitPerSec, + double* rateLBBitPerSec, + double* rateUBBitPerSec, + enum ISACBandwidth* bandwidthKHz); + + +/****************************************************************************** + * WebRtcIsac_DecodeUb16() + * + * Decode the upper-band if the codec is in 0-16 kHz mode. + * + * Input/Output: + * -ISACdec_obj : pointer to the upper-band decoder object. The + * bit-stream is stored inside the decoder object. + * + * Output: + * -signal_out : decoded audio, 480 samples 30 ms. + * + * Return value : >0 number of decoded bytes. + * <0 if an error occurred. + */ +int WebRtcIsac_DecodeUb16( + float* signal_out, + ISACUBDecStruct* ISACdec_obj, + WebRtc_Word16 isRCUPayload); + + +/****************************************************************************** + * WebRtcIsac_DecodeUb12() + * + * Decode the upper-band if the codec is in 0-12 kHz mode. + * + * Input/Output: + * -ISACdec_obj : pointer to the upper-band decoder object. The + * bit-stream is stored inside the decoder object. + * + * Output: + * -signal_out : decoded audio, 480 samples 30 ms. + * + * Return value : >0 number of decoded bytes. + * <0 if an error occurred. + */ +int WebRtcIsac_DecodeUb12( + float* signal_out, + ISACUBDecStruct* ISACdec_obj, + WebRtc_Word16 isRCUPayload); + + +/****************************************************************************** + * WebRtcIsac_EncodeUb16() + * + * Encode the upper-band if the codec is in 0-16 kHz mode. + * + * Input: + * -in : upper-band audio, 160 samples (10 ms). + * + * Input/Output: + * -ISACdec_obj : pointer to the upper-band encoder object. The + * bit-stream is stored inside the encoder object. + * + * Return value : >0 number of encoded bytes. + * <0 if an error occurred. + */ +int WebRtcIsac_EncodeUb16( + float* in, + ISACUBEncStruct* ISACenc_obj, + WebRtc_Word32 jitterInfo); + + +/****************************************************************************** + * WebRtcIsac_EncodeUb12() + * + * Encode the upper-band if the codec is in 0-12 kHz mode. + * + * Input: + * -in : upper-band audio, 160 samples (10 ms). + * + * Input/Output: + * -ISACdec_obj : pointer to the upper-band encoder object. The + * bit-stream is stored inside the encoder object. + * + * Return value : >0 number of encoded bytes. + * <0 if an error occurred. + */ +int WebRtcIsac_EncodeUb12( + float* in, + ISACUBEncStruct* ISACenc_obj, + WebRtc_Word32 jitterInfo); + +/************************** initialization functions *************************/ + +void WebRtcIsac_InitMasking(MaskFiltstr *maskdata); + +void WebRtcIsac_InitPreFilterbank(PreFiltBankstr *prefiltdata); + +void WebRtcIsac_InitPostFilterbank(PostFiltBankstr *postfiltdata); + +void WebRtcIsac_InitPitchFilter(PitchFiltstr *pitchfiltdata); + +void WebRtcIsac_InitPitchAnalysis(PitchAnalysisStruct *State); + + +/**************************** transform functions ****************************/ + +void WebRtcIsac_InitTransform(); + +void WebRtcIsac_Time2Spec(double *inre1, + double *inre2, + WebRtc_Word16 *outre, + WebRtc_Word16 *outim, + FFTstr *fftstr_obj); + +void WebRtcIsac_Spec2time(double *inre, + double *inim, + double *outre1, + double *outre2, + FFTstr *fftstr_obj); + + +/******************************* filter functions ****************************/ + +void WebRtcIsac_AllPoleFilter(double *InOut, + double *Coef, + int lengthInOut, + int orderCoef); + +void WebRtcIsac_AllZeroFilter(double *In, + double *Coef, + int lengthInOut, + int orderCoef, + double *Out); + +void WebRtcIsac_ZeroPoleFilter(double *In, + double *ZeroCoef, + double *PoleCoef, + int lengthInOut, + int orderCoef, + double *Out); + + +/***************************** filterbank functions **************************/ + +void WebRtcIsac_SplitAndFilter(double *in, + double *LP, + double *HP, + double *LP_la, + double *HP_la, + PreFiltBankstr *prefiltdata); + + +void WebRtcIsac_FilterAndCombine(double *InLP, + double *InHP, + double *Out, + PostFiltBankstr *postfiltdata); + + + +void WebRtcIsac_SplitAndFilterFloat(float *in, + float *LP, + float *HP, + double *LP_la, + double *HP_la, + PreFiltBankstr *prefiltdata); + + +void WebRtcIsac_FilterAndCombineFloat(float *InLP, + float *InHP, + float *Out, + PostFiltBankstr *postfiltdata); + + +/************************* normalized lattice filters ************************/ + +void WebRtcIsac_NormLatticeFilterMa(int orderCoef, + float *stateF, + float *stateG, + float *lat_in, + double *filtcoeflo, + double *lat_out); + +void WebRtcIsac_NormLatticeFilterAr(int orderCoef, + float *stateF, + float *stateG, + double *lat_in, + double *lo_filt_coef, + float *lat_out); + +void WebRtcIsac_Dir2Lat(double *a, + int orderCoef, + float *sth, + float *cth); + +void WebRtcIsac_AutoCorr(double *r, + const double *x, + int N, + int order); + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CODEC_H_ */ diff --git a/libs/miniwebrtc/audio/coding_isac/main/crc.c b/libs/miniwebrtc/audio/coding_isac/main/crc.c new file mode 100644 index 00000000..098e4b7a --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/crc.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "crc.h" +#include +#include "signal_processing_library.h" + +#define POLYNOMIAL 0x04c11db7L + + +static const WebRtc_UWord32 kCrcTable[256] = { + 0, 0x4c11db7, 0x9823b6e, 0xd4326d9, 0x130476dc, 0x17c56b6b, + 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, + 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, + 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, + 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, + 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, + 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, + 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, + 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x18aeb13, 0x54bf6a4, + 0x808d07d, 0xcc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, + 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, + 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, + 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, + 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, + 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, + 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, + 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, + 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, + 0x3f9b762c, 0x3b5a6b9b, 0x315d626, 0x7d4cb91, 0xa97ed48, 0xe56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, + 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, + 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, + 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, + 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, + 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, + 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, + 0x18197087, 0x1cd86d30, 0x29f3d35, 0x65e2082, 0xb1d065b, 0xfdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, + 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, + 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, + 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, + 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, + 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 +}; + + + + +/**************************************************************************** + * WebRtcIsac_GetCrc(...) + * + * This function returns a 32 bit CRC checksum of a bit stream + * + * Input: + * - bitstream : payload bitstream + * - len_bitstream_in_bytes : number of 8-bit words in the bit stream + * + * Output: + * - crc : checksum + * + * Return value : 0 - Ok + * -1 - Error + */ + +WebRtc_Word16 WebRtcIsac_GetCrc(const WebRtc_Word16* bitstream, + WebRtc_Word16 len_bitstream_in_bytes, + WebRtc_UWord32* crc) +{ + WebRtc_UWord8* bitstream_ptr_uw8; + WebRtc_UWord32 crc_state; + int byte_cntr; + int crc_tbl_indx; + + /* Sanity Check. */ + if (bitstream == NULL) { + return -1; + } + /* cast to UWord8 pointer */ + bitstream_ptr_uw8 = (WebRtc_UWord8 *)bitstream; + + /* initialize */ + crc_state = 0xFFFFFFFF; + + for (byte_cntr = 0; byte_cntr < len_bitstream_in_bytes; byte_cntr++) { + crc_tbl_indx = (WEBRTC_SPL_RSHIFT_U32(crc_state, 24) ^ + bitstream_ptr_uw8[byte_cntr]) & 0xFF; + crc_state = WEBRTC_SPL_LSHIFT_U32(crc_state, 8) ^ kCrcTable[crc_tbl_indx]; + } + + *crc = ~crc_state; + return 0; +} diff --git a/libs/miniwebrtc/audio/coding_isac/main/crc.h b/libs/miniwebrtc/audio/coding_isac/main/crc.h new file mode 100644 index 00000000..01512789 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/crc.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * crc.h + * + * Checksum functions + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_ + +#include "typedefs.h" + +/**************************************************************************** + * WebRtcIsac_GetCrc(...) + * + * This function returns a 32 bit CRC checksum of a bit stream + * + * Input: + * - encoded : payload bit stream + * - no_of_word8s : number of 8-bit words in the bit stream + * + * Output: + * - crc : checksum + * + * Return value : 0 - Ok + * -1 - Error + */ + +WebRtc_Word16 WebRtcIsac_GetCrc( + const WebRtc_Word16* encoded, + WebRtc_Word16 no_of_word8s, + WebRtc_UWord32* crc); + + + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_CRC_H_ */ diff --git a/libs/miniwebrtc/audio/coding_isac/main/decode.c b/libs/miniwebrtc/audio/coding_isac/main/decode.c new file mode 100644 index 00000000..25634b0a --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/decode.c @@ -0,0 +1,330 @@ +/* + * 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_B.c + * + * This file contains definition of funtions for decoding. + * Decoding of lower-band, including normal-decoding and RCU decoding. + * Decoding of upper-band, including 8-12 kHz, when the bandwidth is + * 0-12 kHz, and 8-16 kHz, when the bandwidth is 0-16 kHz. + * + */ + + +#include "codec.h" +#include "entropy_coding.h" +#include "pitch_estimator.h" +#include "bandwidth_estimator.h" +#include "structs.h" +#include "settings.h" + +#include +#include +#include + + +/* + * function to decode the bitstream + * returns the total number of bytes in the stream + */ +int +WebRtcIsac_DecodeLb( + float* signal_out, + ISACLBDecStruct* ISACdecLB_obj, + WebRtc_Word16* current_framesamples, + WebRtc_Word16 isRCUPayload) +{ + int k, model; + int len, err; + WebRtc_Word16 bandwidthInd; + + float LP_dec_float[FRAMESAMPLES_HALF]; + float HP_dec_float[FRAMESAMPLES_HALF]; + + double LPw[FRAMESAMPLES_HALF]; + double HPw[FRAMESAMPLES_HALF]; + double LPw_pf[FRAMESAMPLES_HALF]; + + double lo_filt_coef[(ORDERLO+1)*SUBFRAMES]; + double hi_filt_coef[(ORDERHI+1)*SUBFRAMES]; + + double real_f[FRAMESAMPLES_HALF]; + double imag_f[FRAMESAMPLES_HALF]; + + double PitchLags[4]; + double PitchGains[4]; + double AvgPitchGain; + WebRtc_Word16 PitchGains_Q12[4]; + WebRtc_Word16 AvgPitchGain_Q12; + + float gain; + + int frame_nb; /* counter */ + int frame_mode; /* 0 for 20ms and 30ms, 1 for 60ms */ + int processed_samples; + + (ISACdecLB_obj->bitstr_obj).W_upper = 0xFFFFFFFF; + (ISACdecLB_obj->bitstr_obj).streamval = 0; + (ISACdecLB_obj->bitstr_obj).stream_index = 0; + + len = 0; + + /* decode framelength and BW estimation - not used, + only for stream pointer*/ + err = WebRtcIsac_DecodeFrameLen(&ISACdecLB_obj->bitstr_obj, + current_framesamples); + if (err < 0) { // error check + return err; + } + + /* frame_mode: 0, or 1 */ + frame_mode = *current_framesamples/MAX_FRAMESAMPLES; + /* processed_samples: either 320 (20ms) or 480 (30, 60 ms) */ + processed_samples = *current_framesamples/(frame_mode+1); + + err = WebRtcIsac_DecodeSendBW(&ISACdecLB_obj->bitstr_obj, &bandwidthInd); + 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 = WebRtcIsac_DecodePitchGain(&(ISACdecLB_obj->bitstr_obj), + PitchGains_Q12); + if (err < 0) { // error check + return err; + } + + err = WebRtcIsac_DecodePitchLag(&ISACdecLB_obj->bitstr_obj, + PitchGains_Q12, PitchLags); + if (err < 0) { // error check + return err; + } + + AvgPitchGain_Q12 = (PitchGains_Q12[0] + PitchGains_Q12[1] + + PitchGains_Q12[2] + PitchGains_Q12[3])>>2; + + /* decode & dequantize FiltCoef */ + err = WebRtcIsac_DecodeLpc(&ISACdecLB_obj->bitstr_obj, + lo_filt_coef,hi_filt_coef, &model); + if (err < 0) { // error check + return err; + } + /* decode & dequantize spectrum */ + len = WebRtcIsac_DecodeSpecLb(&ISACdecLB_obj->bitstr_obj, + real_f, imag_f, AvgPitchGain_Q12); + if (len < 0) { // error check + return len; + } + + /* inverse transform */ + WebRtcIsac_Spec2time(real_f, imag_f, LPw, HPw, + &ISACdecLB_obj->fftstr_obj); + + /* convert PitchGains back to FLOAT for pitchfilter_post */ + for (k = 0; k < 4; k++) { + PitchGains[k] = ((float)PitchGains_Q12[k])/4096; + } + + if(isRCUPayload) + { + for (k = 0; k < 240; k++) { + LPw[k] *= RCU_TRANSCODING_SCALE_INVERSE; + HPw[k] *= RCU_TRANSCODING_SCALE_INVERSE; + } + } + + /* inverse pitch filter */ + WebRtcIsac_PitchfilterPost(LPw, LPw_pf, + &ISACdecLB_obj->pitchfiltstr_obj, PitchLags, PitchGains); + /* convert AvgPitchGain back to FLOAT for computation of gain */ + AvgPitchGain = ((float)AvgPitchGain_Q12)/4096; + gain = 1.0f - 0.45f * (float)AvgPitchGain; + + for (k = 0; k < FRAMESAMPLES_HALF; k++) { + /* reduce gain to compensate for pitch enhancer */ + LPw_pf[ k ] *= gain; + } + + if(isRCUPayload) + { + for (k = 0; k < FRAMESAMPLES_HALF; k++) { + /* compensation for transcoding gain changes*/ + LPw_pf[k] *= RCU_TRANSCODING_SCALE; + HPw[k] *= RCU_TRANSCODING_SCALE; + } + } + + /* perceptual post-filtering (using normalized lattice filter) */ + WebRtcIsac_NormLatticeFilterAr(ORDERLO, + ISACdecLB_obj->maskfiltstr_obj.PostStateLoF, + (ISACdecLB_obj->maskfiltstr_obj).PostStateLoG, + LPw_pf, lo_filt_coef, LP_dec_float); + WebRtcIsac_NormLatticeFilterAr(ORDERHI, + ISACdecLB_obj->maskfiltstr_obj.PostStateHiF, + (ISACdecLB_obj->maskfiltstr_obj).PostStateHiG, + HPw, hi_filt_coef, HP_dec_float); + + /* recombine the 2 bands */ + WebRtcIsac_FilterAndCombineFloat( LP_dec_float, HP_dec_float, + signal_out + frame_nb * processed_samples, + &ISACdecLB_obj->postfiltbankstr_obj); + } + + return len; +} + + +/* + * This decode function is called when the codec is operating in 16 kHz + * bandwidth to decode the upperband, i.e. 8-16 kHz. + * + * Contrary to lower-band, the upper-band (8-16 kHz) is not split in + * frequency, but split to 12 sub-frames, i.e. twice as lower-band. + */ +int +WebRtcIsac_DecodeUb16( + float* signal_out, + ISACUBDecStruct* ISACdecUB_obj, + WebRtc_Word16 isRCUPayload) +{ + int len, err; + + double halfFrameFirst[FRAMESAMPLES_HALF]; + double halfFrameSecond[FRAMESAMPLES_HALF]; + + double percepFilterParam[(UB_LPC_ORDER+1) * (SUBFRAMES<<1) + + (UB_LPC_ORDER+1)]; + + double real_f[FRAMESAMPLES_HALF]; + double imag_f[FRAMESAMPLES_HALF]; + + len = 0; + + /* decode & dequantize FiltCoef */ + memset(percepFilterParam, 0, sizeof(percepFilterParam)); + err = WebRtcIsac_DecodeInterpolLpcUb(&ISACdecUB_obj->bitstr_obj, + percepFilterParam, isac16kHz); + if (err < 0) { // error check + return err; + } + + /* decode & dequantize spectrum */ + len = WebRtcIsac_DecodeSpecUB16(&ISACdecUB_obj->bitstr_obj, real_f, + imag_f); + if (len < 0) { // error check + return len; + } + if(isRCUPayload) + { + int n; + for(n = 0; n < 240; n++) + { + real_f[n] *= RCU_TRANSCODING_SCALE_UB_INVERSE; + imag_f[n] *= RCU_TRANSCODING_SCALE_UB_INVERSE; + } + } + + /* inverse transform */ + WebRtcIsac_Spec2time(real_f, imag_f, halfFrameFirst, halfFrameSecond, + &ISACdecUB_obj->fftstr_obj); + + /* perceptual post-filtering (using normalized lattice filter) */ + WebRtcIsac_NormLatticeFilterAr(UB_LPC_ORDER, + ISACdecUB_obj->maskfiltstr_obj.PostStateLoF, + (ISACdecUB_obj->maskfiltstr_obj).PostStateLoG, halfFrameFirst, + &percepFilterParam[(UB_LPC_ORDER+1)], signal_out); + + WebRtcIsac_NormLatticeFilterAr(UB_LPC_ORDER, + ISACdecUB_obj->maskfiltstr_obj.PostStateLoF, + (ISACdecUB_obj->maskfiltstr_obj).PostStateLoG, halfFrameSecond, + &percepFilterParam[(UB_LPC_ORDER + 1) * SUBFRAMES + (UB_LPC_ORDER+1)], + &signal_out[FRAMESAMPLES_HALF]); + + return len; +} + +/* + * This decode function is called when the codec operates at 0-12 kHz + * bandwidth to decode the upperband, i.e. 8-12 kHz. + * + * At the encoder the upper-band is split into two band, 8-12 kHz & 12-16 + * kHz, and only 8-12 kHz is encoded. At the decoder, 8-12 kHz band is + * reconstructed and 12-16 kHz replaced with zeros. Then two bands + * are combined, to reconstruct the upperband 8-16 kHz. + */ +int +WebRtcIsac_DecodeUb12( + float* signal_out, + ISACUBDecStruct* ISACdecUB_obj, + WebRtc_Word16 isRCUPayload) +{ + int len, err; + + float LP_dec_float[FRAMESAMPLES_HALF]; + float HP_dec_float[FRAMESAMPLES_HALF]; + + double LPw[FRAMESAMPLES_HALF]; + double HPw[FRAMESAMPLES_HALF]; + + double percepFilterParam[(UB_LPC_ORDER+1)*SUBFRAMES]; + + double real_f[FRAMESAMPLES_HALF]; + double imag_f[FRAMESAMPLES_HALF]; + + len = 0; + + /* decode & dequantize FiltCoef */ + err = WebRtcIsac_DecodeInterpolLpcUb(&ISACdecUB_obj->bitstr_obj, + percepFilterParam, isac12kHz); + if(err < 0) { // error check + return err; + } + + /* decode & dequantize spectrum */ + len = WebRtcIsac_DecodeSpecUB12(&ISACdecUB_obj->bitstr_obj, + real_f, imag_f); + if(len < 0) { // error check + return len; + } + + if(isRCUPayload) + { + int n; + for(n = 0; n < 240; n++) + { + real_f[n] *= RCU_TRANSCODING_SCALE_UB_INVERSE; + imag_f[n] *= RCU_TRANSCODING_SCALE_UB_INVERSE; + } + } + + /* inverse transform */ + WebRtcIsac_Spec2time(real_f, imag_f, LPw, HPw, &ISACdecUB_obj->fftstr_obj); + + /* perceptual post-filtering (using normalized lattice filter) */ + WebRtcIsac_NormLatticeFilterAr(UB_LPC_ORDER, + ISACdecUB_obj->maskfiltstr_obj.PostStateLoF, + (ISACdecUB_obj->maskfiltstr_obj).PostStateLoG, LPw, + percepFilterParam, LP_dec_float); + + /* Zerro for upper-band */ + memset(HP_dec_float, 0, sizeof(float) * (FRAMESAMPLES_HALF)); + + /* recombine the 2 bands */ + WebRtcIsac_FilterAndCombineFloat(HP_dec_float, LP_dec_float, signal_out, + &ISACdecUB_obj->postfiltbankstr_obj); + + + + return len; +} diff --git a/libs/miniwebrtc/audio/coding_isac/main/decode_bwe.c b/libs/miniwebrtc/audio/coding_isac/main/decode_bwe.c new file mode 100644 index 00000000..cdac7fa8 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/decode_bwe.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "structs.h" +#include "bandwidth_estimator.h" +#include "entropy_coding.h" +#include "codec.h" + + +int +WebRtcIsac_EstimateBandwidth( + BwEstimatorstr* bwest_str, + Bitstr* streamdata, + WebRtc_Word32 packet_size, + WebRtc_UWord16 rtp_seq_number, + WebRtc_UWord32 send_ts, + WebRtc_UWord32 arr_ts, + enum IsacSamplingRate encoderSampRate, + enum IsacSamplingRate decoderSampRate) +{ + WebRtc_Word16 index; + WebRtc_Word16 frame_samples; + WebRtc_UWord32 sendTimestampIn16kHz; + WebRtc_UWord32 arrivalTimestampIn16kHz; + WebRtc_UWord32 diffSendTime; + WebRtc_UWord32 diffArrivalTime; + int err; + + /* decode framelength and BW estimation */ + err = WebRtcIsac_DecodeFrameLen(streamdata, &frame_samples); + if(err < 0) // error check + { + return err; + } + err = WebRtcIsac_DecodeSendBW(streamdata, &index); + if(err < 0) // error check + { + return err; + } + + /* UPDATE ESTIMATES FROM OTHER SIDE */ + err = WebRtcIsac_UpdateUplinkBwImpl(bwest_str, index, encoderSampRate); + if(err < 0) + { + return err; + } + + // We like BWE to work at 16 kHz sampling rate, + // therefore, we have to change the timestamps accordingly. + // translate the send timestamp if required + diffSendTime = (WebRtc_UWord32)((WebRtc_UWord32)send_ts - + (WebRtc_UWord32)bwest_str->senderTimestamp); + bwest_str->senderTimestamp = send_ts; + + diffArrivalTime = (WebRtc_UWord32)((WebRtc_UWord32)arr_ts - + (WebRtc_UWord32)bwest_str->receiverTimestamp); + bwest_str->receiverTimestamp = arr_ts; + + if(decoderSampRate == kIsacSuperWideband) + { + diffArrivalTime = (WebRtc_UWord32)diffArrivalTime >> 1; + diffSendTime = (WebRtc_UWord32)diffSendTime >> 1; + } + // arrival timestamp in 16 kHz + arrivalTimestampIn16kHz = (WebRtc_UWord32)((WebRtc_UWord32) + bwest_str->prev_rec_arr_ts + (WebRtc_UWord32)diffArrivalTime); + // send timestamp in 16 kHz + sendTimestampIn16kHz = (WebRtc_UWord32)((WebRtc_UWord32) + bwest_str->prev_rec_send_ts + (WebRtc_UWord32)diffSendTime); + + err = WebRtcIsac_UpdateBandwidthEstimator(bwest_str, rtp_seq_number, + (frame_samples * 1000) / FS, sendTimestampIn16kHz, + arrivalTimestampIn16kHz, packet_size); + // error check + if(err < 0) + { + return err; + } + + return 0; +} diff --git a/libs/miniwebrtc/audio/coding_isac/main/encode.c b/libs/miniwebrtc/audio/coding_isac/main/encode.c new file mode 100644 index 00000000..75cd7265 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/encode.c @@ -0,0 +1,1451 @@ +/* + * 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 + * + * This file contains definition of funtions for encoding. + * Decoding of upper-band, including 8-12 kHz, when the bandwidth is + * 0-12 kHz, and 8-16 kHz, when the bandwidth is 0-16 kHz. + * + */ + +#include +#include + +#include "structs.h" +#include "codec.h" +#include "pitch_estimator.h" +#include "entropy_coding.h" +#include "arith_routines.h" +#include "pitch_gain_tables.h" +#include "pitch_lag_tables.h" +#include "spectrum_ar_model_tables.h" +#include "lpc_tables.h" +#include "lpc_analysis.h" +#include "bandwidth_estimator.h" +#include "lpc_shape_swb12_tables.h" +#include "lpc_shape_swb16_tables.h" +#include "lpc_gain_swb_tables.h" + + +#define UB_LOOKAHEAD 24 + +/* + Rate allocation tables of lower and upper-band bottleneck for + 12kHz & 16kHz bandwidth. + + 12 kHz bandwidth + ----------------- + The overall bottleneck of the coder is between 38 kbps and 45 kbps. We have + considered 7 enteries, uniformly distributed in this interval, i.e. 38, + 39.17, 40.33, 41.5, 42.67, 43.83 and 45. For every entery, the lower-band + and the upper-band bottlenecks are specified in + 'kLowerBandBitRate12' and 'kUpperBandBitRate12' + tables, respectively. E.g. the overall rate of 41.5 kbps corresponts to a + bottleneck of 31 kbps for lower-band and 27 kbps for upper-band. Given an + overall bottleneck of the codec, we use linear interpolation to get + lower-band and upper-band bottlenecks. + + 16 kHz bandwidth + ----------------- + The overall bottleneck of the coder is between 50 kbps and 56 kbps. We have + considered 7 enteries, uniformly distributed in this interval, i.e. 50, 51.2, + 52.4, 53.6, 54.8 and 56. For every entery, the lower-band and the upper-band + bottlenecks are specified in 'kLowerBandBitRate16' and + 'kUpperBandBitRate16' tables, respectively. E.g. the overall rate + of 53.6 kbps corresponts to a bottleneck of 32 kbps for lower-band and 30 + kbps for upper-band. Given an overall bottleneck of the codec, we use linear + interpolation to get lower-band and upper-band bottlenecks. + +*/ + +// 38 39.17 40.33 41.5 42.67 43.83 45 +static const WebRtc_Word16 kLowerBandBitRate12[7] = { + 29000, 30000, 30000, 31000, 31000, 32000, 32000}; +static const WebRtc_Word16 kUpperBandBitRate12[7] = { + 25000, 25000, 27000, 27000, 29000, 29000, 32000}; + +// 50 51.2 52.4 53.6 54.8 56 +static const WebRtc_Word16 kLowerBandBitRate16[6] = { + 31000, 31000, 32000, 32000, 32000, 32000}; +static const WebRtc_Word16 kUpperBandBitRate16[6] = { + 28000, 29000, 29000, 30000, 31000, 32000}; + +/****************************************************************************** + * WebRtcIsac_RateAllocation() + * Internal function to perform a rate-allocation for upper and lower-band, + * given a total rate. + * + * Input: + * - inRateBitPerSec : a total bottleneck in bits/sec. + * + * Output: + * - rateLBBitPerSec : a bottleneck allocated to the lower-band + * in bits/sec. + * - rateUBBitPerSec : a bottleneck allocated to the upper-band + * in bits/sec. + * + * Return value : 0 if rate allocation has been successful. + * -1 if failed to allocate rates. + */ + +WebRtc_Word16 +WebRtcIsac_RateAllocation( + WebRtc_Word32 inRateBitPerSec, + double* rateLBBitPerSec, + double* rateUBBitPerSec, + enum ISACBandwidth* bandwidthKHz) +{ + WebRtc_Word16 idx; + double idxD; + double idxErr; + if(inRateBitPerSec < 38000) + { + // If the given overall bottleneck is less than 38000 then + // then codec has to operate in wideband mode, i.e. 8 kHz + // bandwidth. + *rateLBBitPerSec = (WebRtc_Word16)((inRateBitPerSec > 32000)? + 32000:inRateBitPerSec); + *rateUBBitPerSec = 0; + *bandwidthKHz = isac8kHz; + } + else if((inRateBitPerSec >= 38000) && (inRateBitPerSec < 50000)) + { + // At a bottleneck between 38 and 50 kbps the codec is operating + // at 12 kHz bandwidth. Using xxxBandBitRate12[] to calculates + // upper/lower bottleneck + + // find the bottlenecks by linear interpolation + // step is (45000 - 38000)/6.0 we use the inverse of it. + const double stepSizeInv = 8.5714286e-4; + idxD = (inRateBitPerSec - 38000) * stepSizeInv; + idx = (idxD >= 6)? 6:((WebRtc_Word16)idxD); + idxErr = idxD - idx; + *rateLBBitPerSec = kLowerBandBitRate12[idx]; + *rateUBBitPerSec = kUpperBandBitRate12[idx]; + + if(idx < 6) + { + *rateLBBitPerSec += (WebRtc_Word16)(idxErr * + (kLowerBandBitRate12[idx + 1] - + kLowerBandBitRate12[idx])); + *rateUBBitPerSec += (WebRtc_Word16)(idxErr * + (kUpperBandBitRate12[idx + 1] - + kUpperBandBitRate12[idx])); + } + + *bandwidthKHz = isac12kHz; + } + else if((inRateBitPerSec >= 50000) && (inRateBitPerSec <= 56000)) + { + // A bottleneck between 50 and 56 kbps corresponds to bandwidth + // of 16 kHz. Using xxxBandBitRate16[] to calculates + // upper/lower bottleneck + + // find the bottlenecks by linear interpolation + // step is (56000 - 50000)/5 we use the inverse of it + const double stepSizeInv = 8.3333333e-4; + idxD = (inRateBitPerSec - 50000) * stepSizeInv; + idx = (idxD >= 5)? 5:((WebRtc_Word16)idxD); + idxErr = idxD - idx; + *rateLBBitPerSec = kLowerBandBitRate16[idx]; + *rateUBBitPerSec = kUpperBandBitRate16[idx]; + + if(idx < 5) + { + *rateLBBitPerSec += (WebRtc_Word16)(idxErr * + (kLowerBandBitRate16[idx + 1] - + kLowerBandBitRate16[idx])); + + *rateUBBitPerSec += (WebRtc_Word16)(idxErr * + (kUpperBandBitRate16[idx + 1] - + kUpperBandBitRate16[idx])); + } + + *bandwidthKHz = isac16kHz; + } + else + { + // Out-of-range botlteneck value. + return -1; + } + + // limit the values. + *rateLBBitPerSec = (*rateLBBitPerSec > 32000)? 32000:*rateLBBitPerSec; + *rateUBBitPerSec = (*rateUBBitPerSec > 32000)? 32000:*rateUBBitPerSec; + + return 0; +} + + + +int +WebRtcIsac_EncodeLb( + float* in, + ISACLBEncStruct* ISACencLB_obj, + WebRtc_Word16 codingMode, + WebRtc_Word16 bottleneckIndex) +{ + int stream_length = 0; + int err; + int k; + int iterCntr; + + double lofilt_coef[(ORDERLO+1)*SUBFRAMES]; + double hifilt_coef[(ORDERHI+1)*SUBFRAMES]; + float LP[FRAMESAMPLES_HALF]; + float HP[FRAMESAMPLES_HALF]; + + double LP_lookahead[FRAMESAMPLES_HALF]; + double HP_lookahead[FRAMESAMPLES_HALF]; + double LP_lookahead_pf[FRAMESAMPLES_HALF + QLOOKAHEAD]; + double LPw[FRAMESAMPLES_HALF]; + + double HPw[FRAMESAMPLES_HALF]; + double LPw_pf[FRAMESAMPLES_HALF]; + WebRtc_Word16 fre[FRAMESAMPLES_HALF]; /* Q7 */ + WebRtc_Word16 fim[FRAMESAMPLES_HALF]; /* Q7 */ + + double PitchLags[4]; + double PitchGains[4]; + WebRtc_Word16 PitchGains_Q12[4]; + WebRtc_Word16 AvgPitchGain_Q12; + + int frame_mode; /* 0 for 30ms, 1 for 60ms */ + int processed_samples, status = 0; + + double bits_gains; + int bmodel; + + transcode_obj transcodingParam; + double bytesLeftSpecCoding; + WebRtc_UWord16 payloadLimitBytes; + + /* copy new frame length and bottle neck rate only for the first + 10 ms data */ + if (ISACencLB_obj->buffer_index == 0) { + /* set the framelength for the next packet */ + ISACencLB_obj->current_framesamples = ISACencLB_obj->new_framelength; + } + /* frame_mode is 0 (30 ms) or 1 (60 ms) */ + frame_mode = ISACencLB_obj->current_framesamples/MAX_FRAMESAMPLES; + /* processed_samples: 480 (30, 60 ms) */ + processed_samples = ISACencLB_obj->current_framesamples/(frame_mode+1); + + /* 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++) { + ISACencLB_obj->data_buffer_float[k + ISACencLB_obj->buffer_index] = + in[k]; + } + + /* if buffersize is not equal to current framesize then increase index + and return. We do no encoding untill we have enough audio. */ + if (ISACencLB_obj->buffer_index + FRAMESAMPLES_10ms != processed_samples) { + ISACencLB_obj->buffer_index += FRAMESAMPLES_10ms; + return 0; + } + /* if buffer reached the right size, reset index and continue with + encoding the frame */ + ISACencLB_obj->buffer_index = 0; + + /* end of buffer function */ + /**************************/ + + /* encoding */ + /************/ + + if (frame_mode == 0 || ISACencLB_obj->frame_nb == 0 ) { + // This is to avoid Linux warnings until we change 'int' to 'Word32' + // at all places. + int intVar; + /* reset bitstream */ + ISACencLB_obj->bitstr_obj.W_upper = 0xFFFFFFFF; + ISACencLB_obj->bitstr_obj.streamval = 0; + ISACencLB_obj->bitstr_obj.stream_index = 0; + + if((codingMode == 0) && (frame_mode == 0) && + (ISACencLB_obj->enforceFrameSize == 0)) { + ISACencLB_obj->new_framelength = + WebRtcIsac_GetNewFrameLength(ISACencLB_obj->bottleneck, + ISACencLB_obj->current_framesamples); + } + + ISACencLB_obj->s2nr = WebRtcIsac_GetSnr( + ISACencLB_obj->bottleneck, ISACencLB_obj->current_framesamples); + + /* encode frame length */ + status = WebRtcIsac_EncodeFrameLen( + ISACencLB_obj->current_framesamples, &ISACencLB_obj->bitstr_obj); + if (status < 0) { + /* Wrong frame size */ + return status; + } + /* Save framelength for multiple packets memory */ + ISACencLB_obj->SaveEnc_obj.framelength = + ISACencLB_obj->current_framesamples; + + /* To be used for Redundant Coding */ + ISACencLB_obj->lastBWIdx = bottleneckIndex; + intVar = (int)bottleneckIndex; + WebRtcIsac_EncodeReceiveBw(&intVar, &ISACencLB_obj->bitstr_obj); + } + + /* split signal in two bands */ + WebRtcIsac_SplitAndFilterFloat(ISACencLB_obj->data_buffer_float, LP, HP, + LP_lookahead, HP_lookahead, &ISACencLB_obj->prefiltbankstr_obj ); + + /* estimate pitch parameters and pitch-filter lookahead signal */ + WebRtcIsac_PitchAnalysis(LP_lookahead, LP_lookahead_pf, + &ISACencLB_obj->pitchanalysisstr_obj, PitchLags, PitchGains); + + /* encode in FIX Q12 */ + + /* convert PitchGain to Fixed point */ + for (k=0;kframe_nb == 0) + { + ISACencLB_obj->SaveEnc_obj.startIdx = 0; + } else { + ISACencLB_obj->SaveEnc_obj.startIdx = 1; + } + + /* quantize & encode pitch parameters */ + WebRtcIsac_EncodePitchGain(PitchGains_Q12, &ISACencLB_obj->bitstr_obj, + &ISACencLB_obj->SaveEnc_obj); + WebRtcIsac_EncodePitchLag(PitchLags, PitchGains_Q12, + &ISACencLB_obj->bitstr_obj, &ISACencLB_obj->SaveEnc_obj); + + AvgPitchGain_Q12 = (PitchGains_Q12[0] + PitchGains_Q12[1] + + PitchGains_Q12[2] + PitchGains_Q12[3])>>2; + + /* find coefficients for perceptual pre-filters */ + WebRtcIsac_GetLpcCoefLb(LP_lookahead_pf, HP_lookahead, + &ISACencLB_obj->maskfiltstr_obj, ISACencLB_obj->s2nr, + PitchGains_Q12, lofilt_coef, hifilt_coef); + + /* code LPC model and shape - gains not quantized yet */ + WebRtcIsac_EncodeLpcLb(lofilt_coef, hifilt_coef, &bmodel, &bits_gains, + &ISACencLB_obj->bitstr_obj, &ISACencLB_obj->SaveEnc_obj); + + /* convert PitchGains back to FLOAT for pitchfilter_pre */ + for (k = 0; k < 4; k++) { + PitchGains[k] = ((float)PitchGains_Q12[k])/4096; + } + + /* Store the state of arithmetic coder before coding LPC gains */ + transcodingParam.W_upper = ISACencLB_obj->bitstr_obj.W_upper; + transcodingParam.stream_index = ISACencLB_obj->bitstr_obj.stream_index; + transcodingParam.streamval = ISACencLB_obj->bitstr_obj.streamval; + transcodingParam.stream[0] = ISACencLB_obj->bitstr_obj.stream[ + ISACencLB_obj->bitstr_obj.stream_index - 2]; + transcodingParam.stream[1] = ISACencLB_obj->bitstr_obj.stream[ + ISACencLB_obj->bitstr_obj.stream_index - 1]; + transcodingParam.stream[2] = ISACencLB_obj->bitstr_obj.stream[ + ISACencLB_obj->bitstr_obj.stream_index]; + + /* Store LPC Gains before encoding them */ + for(k = 0; k < SUBFRAMES; k++) { + transcodingParam.loFiltGain[k] = lofilt_coef[(LPC_LOBAND_ORDER+1)*k]; + transcodingParam.hiFiltGain[k] = hifilt_coef[(LPC_HIBAND_ORDER+1)*k]; + } + + /* Code gains */ + WebRtcIsac_EncodeLpcGainLb(lofilt_coef, hifilt_coef, bmodel, + &ISACencLB_obj->bitstr_obj, &ISACencLB_obj->SaveEnc_obj); + + /* Get the correct value for the payload limit and calculate the + number of bytes left for coding the spectrum.*/ + if((frame_mode == 1) && (ISACencLB_obj->frame_nb == 0)) { + /* It is a 60ms and we are in the first 30ms then the limit at + this point should be half of the assigned value */ + payloadLimitBytes = ISACencLB_obj->payloadLimitBytes60 >> 1; + } + else if (frame_mode == 0) { + /* It is a 30ms frame */ + /* Subract 3 because termination process may add 3 bytes */ + payloadLimitBytes = ISACencLB_obj->payloadLimitBytes30 - 3; + } else { + /* This is the second half of a 60ms frame. */ + /* Subract 3 because termination process may add 3 bytes */ + payloadLimitBytes = ISACencLB_obj->payloadLimitBytes60 - 3; + } + bytesLeftSpecCoding = payloadLimitBytes - transcodingParam.stream_index; + + /* perceptual pre-filtering (using normalized lattice filter) */ + /* low-band filtering */ + WebRtcIsac_NormLatticeFilterMa(ORDERLO, + ISACencLB_obj->maskfiltstr_obj.PreStateLoF, + ISACencLB_obj->maskfiltstr_obj.PreStateLoG, LP, lofilt_coef, LPw); + /* high-band filtering */ + WebRtcIsac_NormLatticeFilterMa(ORDERHI, + ISACencLB_obj->maskfiltstr_obj.PreStateHiF, + ISACencLB_obj->maskfiltstr_obj.PreStateHiG, HP, hifilt_coef, HPw); + + + /* pitch filter */ + WebRtcIsac_PitchfilterPre(LPw, LPw_pf, &ISACencLB_obj->pitchfiltstr_obj, + PitchLags, PitchGains); + + /* transform */ + WebRtcIsac_Time2Spec(LPw_pf, HPw, fre, fim, &ISACencLB_obj->fftstr_obj); + + + /* Save data for multiple packets memory */ + for (k = 0; k < FRAMESAMPLES_HALF; k++) { + ISACencLB_obj->SaveEnc_obj.fre[k + + ISACencLB_obj->SaveEnc_obj.startIdx*FRAMESAMPLES_HALF] = fre[k]; + ISACencLB_obj->SaveEnc_obj.fim[k + + ISACencLB_obj->SaveEnc_obj.startIdx*FRAMESAMPLES_HALF] = fim[k]; + } + ISACencLB_obj->SaveEnc_obj.AvgPitchGain[ + ISACencLB_obj->SaveEnc_obj.startIdx] = AvgPitchGain_Q12; + + /* quantization and lossless coding */ + err = WebRtcIsac_EncodeSpecLb(fre, fim, &ISACencLB_obj->bitstr_obj, + AvgPitchGain_Q12); + if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) { + /* There has been an error but it was not too large payload + (we can cure too large payload) */ + if (frame_mode == 1 && ISACencLB_obj->frame_nb == 1) { + /* If this is the second 30ms of a 60ms frame reset + this such that in the next call encoder starts fresh. */ + ISACencLB_obj->frame_nb = 0; + } + return err; + } + iterCntr = 0; + while((ISACencLB_obj->bitstr_obj.stream_index > payloadLimitBytes) || + (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH)) { + double bytesSpecCoderUsed; + double transcodeScale; + + if(iterCntr >= MAX_PAYLOAD_LIMIT_ITERATION) { + /* We were not able to limit the payload size */ + if((frame_mode == 1) && (ISACencLB_obj->frame_nb == 0)) { + /* This was the first 30ms of a 60ms frame. Although + the payload is larger than it should be but we let + the second 30ms be encoded. Maybe together we + won't exceed the limit. */ + ISACencLB_obj->frame_nb = 1; + return 0; + } else if((frame_mode == 1) && (ISACencLB_obj->frame_nb == 1)) { + ISACencLB_obj->frame_nb = 0; + } + + if(err != -ISAC_DISALLOWED_BITSTREAM_LENGTH) { + return -ISAC_PAYLOAD_LARGER_THAN_LIMIT; + } else { + return status; + } + } + + if(err == -ISAC_DISALLOWED_BITSTREAM_LENGTH) { + bytesSpecCoderUsed = STREAM_SIZE_MAX; + // being coservative + transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed * 0.5; + } else { + bytesSpecCoderUsed = ISACencLB_obj->bitstr_obj.stream_index - + transcodingParam.stream_index; + transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed; + } + + /* To be safe, we reduce the scale depending on + the number of iterations. */ + transcodeScale *= (1.0 - (0.9 * (double)iterCntr / + (double)MAX_PAYLOAD_LIMIT_ITERATION)); + + /* Scale the LPC Gains */ + for (k = 0; k < SUBFRAMES; k++) { + lofilt_coef[(LPC_LOBAND_ORDER+1) * k] = + transcodingParam.loFiltGain[k] * transcodeScale; + hifilt_coef[(LPC_HIBAND_ORDER+1) * k] = + transcodingParam.hiFiltGain[k] * transcodeScale; + transcodingParam.loFiltGain[k] = + lofilt_coef[(LPC_LOBAND_ORDER+1) * k]; + transcodingParam.hiFiltGain[k] = + hifilt_coef[(LPC_HIBAND_ORDER+1) * k]; + } + + /* Scale DFT coefficients */ + for (k = 0; k < FRAMESAMPLES_HALF; k++) { + fre[k] = (WebRtc_Word16)(fre[k] * transcodeScale); + fim[k] = (WebRtc_Word16)(fim[k] * transcodeScale); + } + + /* Save data for multiple packets memory */ + for (k = 0; k < FRAMESAMPLES_HALF; k++) { + ISACencLB_obj->SaveEnc_obj.fre[k + + ISACencLB_obj->SaveEnc_obj.startIdx * FRAMESAMPLES_HALF] = + fre[k]; + ISACencLB_obj->SaveEnc_obj.fim[k + + ISACencLB_obj->SaveEnc_obj.startIdx * FRAMESAMPLES_HALF] = + fim[k]; + } + + /* Re-store the state of arithmetic coder before coding LPC gains */ + ISACencLB_obj->bitstr_obj.W_upper = transcodingParam.W_upper; + ISACencLB_obj->bitstr_obj.stream_index = transcodingParam.stream_index; + ISACencLB_obj->bitstr_obj.streamval = transcodingParam.streamval; + ISACencLB_obj->bitstr_obj.stream[transcodingParam.stream_index - 2] = + transcodingParam.stream[0]; + ISACencLB_obj->bitstr_obj.stream[transcodingParam.stream_index - 1] = + transcodingParam.stream[1]; + ISACencLB_obj->bitstr_obj.stream[transcodingParam.stream_index] = + transcodingParam.stream[2]; + + /* Code gains */ + WebRtcIsac_EncodeLpcGainLb(lofilt_coef, hifilt_coef, bmodel, + &ISACencLB_obj->bitstr_obj, &ISACencLB_obj->SaveEnc_obj); + + /* Update the number of bytes left for encoding the spectrum */ + bytesLeftSpecCoding = payloadLimitBytes - + transcodingParam.stream_index; + + /* Encode the spectrum */ + err = WebRtcIsac_EncodeSpecLb(fre, fim, &ISACencLB_obj->bitstr_obj, + AvgPitchGain_Q12); + if((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) { + /* There has been an error but it was not too large + payload (we can cure too large payload) */ + if (frame_mode == 1 && ISACencLB_obj->frame_nb == 1) { + /* If this is the second 30ms of a 60ms frame reset + this such that in the next call encoder starts fresh. */ + ISACencLB_obj->frame_nb = 0; + } + return err; + } + iterCntr++; + } + + /* i.e. 60 ms framesize and just processed the first 30ms, */ + /* go back to main function to buffer the other 30ms speech frame */ + if (frame_mode == 1) + { + if(ISACencLB_obj->frame_nb == 0) + { + ISACencLB_obj->frame_nb = 1; + return 0; + } + else if(ISACencLB_obj->frame_nb == 1) + { + ISACencLB_obj->frame_nb = 0; + /* also update the framelength for next packet, + in Adaptive mode only */ + if (codingMode == 0 && (ISACencLB_obj->enforceFrameSize == 0)) + { + ISACencLB_obj->new_framelength = + WebRtcIsac_GetNewFrameLength(ISACencLB_obj->bottleneck, + ISACencLB_obj->current_framesamples); + } + } + } + else + { + ISACencLB_obj->frame_nb = 0; + } + + /* complete arithmetic coding */ + stream_length = WebRtcIsac_EncTerminate(&ISACencLB_obj->bitstr_obj); + + return stream_length; +} + +int +WebRtcIsac_EncodeUb16( + float* in, + ISACUBEncStruct* ISACencUB_obj, + WebRtc_Word32 jitterInfo) +{ + int err; + int k; + + double lpcVecs[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME]; + double percepFilterParams[(1 + UB_LPC_ORDER) * (SUBFRAMES<<1) + + (1 + UB_LPC_ORDER)]; + + double LP_lookahead[FRAMESAMPLES]; + WebRtc_Word16 fre[FRAMESAMPLES_HALF]; /* Q7 */ + WebRtc_Word16 fim[FRAMESAMPLES_HALF]; /* Q7 */ + + int status = 0; + + double varscale[2]; + double corr[SUBFRAMES<<1][UB_LPC_ORDER + 1]; + double lpcGains[SUBFRAMES<<1]; + transcode_obj transcodingParam; + double bytesLeftSpecCoding; + WebRtc_UWord16 payloadLimitBytes; + WebRtc_UWord16 iterCntr; + double s2nr; + + /* 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++) { + ISACencUB_obj->data_buffer_float[k + ISACencUB_obj->buffer_index] = + in[k]; + } + + /* if buffersize is not equal to current framesize, and end of file is + not reached yet, we don't do encoding unless we have the whole frame */ + if (ISACencUB_obj->buffer_index + FRAMESAMPLES_10ms < FRAMESAMPLES) { + ISACencUB_obj->buffer_index += FRAMESAMPLES_10ms; + return 0; + } + + /* end of buffer function */ + /**************************/ + + /* encoding */ + /************/ + + /* reset bitstream */ + ISACencUB_obj->bitstr_obj.W_upper = 0xFFFFFFFF; + ISACencUB_obj->bitstr_obj.streamval = 0; + ISACencUB_obj->bitstr_obj.stream_index = 0; + + /* bandwidth estimation and coding */ + /* To be used for Redundant Coding */ + WebRtcIsac_EncodeJitterInfo(jitterInfo, &ISACencUB_obj->bitstr_obj); + + status = WebRtcIsac_EncodeBandwidth(isac16kHz, + &ISACencUB_obj->bitstr_obj); + if (status < 0) { + return status; + } + + s2nr = WebRtcIsac_GetSnr(ISACencUB_obj->bottleneck, + FRAMESAMPLES); + + memcpy(lpcVecs, ISACencUB_obj->lastLPCVec, UB_LPC_ORDER * sizeof(double)); + + for (k = 0; k < FRAMESAMPLES; k++) { + LP_lookahead[k] = ISACencUB_obj->data_buffer_float[UB_LOOKAHEAD + k]; + } + + /* find coefficients for perceptual pre-filters */ + WebRtcIsac_GetLpcCoefUb(LP_lookahead, &ISACencUB_obj->maskfiltstr_obj, + &lpcVecs[UB_LPC_ORDER], corr, varscale, isac16kHz); + + memcpy(ISACencUB_obj->lastLPCVec, + &lpcVecs[(UB16_LPC_VEC_PER_FRAME - 1) * (UB_LPC_ORDER)], + sizeof(double) * UB_LPC_ORDER); + + /* code LPC model and shape - gains not quantized yet */ + WebRtcIsac_EncodeLpcUB(lpcVecs, &ISACencUB_obj->bitstr_obj, + percepFilterParams, isac16kHz, &ISACencUB_obj->SaveEnc_obj); + + + // the first set of lpc parameters are from the last sub-frame of + // the previous frame. so we don't care about them + WebRtcIsac_GetLpcGain(s2nr, &percepFilterParams[UB_LPC_ORDER + 1], + (SUBFRAMES<<1), lpcGains, corr, varscale); + + /* Store the state of arithmetic coder before coding LPC gains */ + transcodingParam.stream_index = ISACencUB_obj->bitstr_obj.stream_index; + transcodingParam.W_upper = ISACencUB_obj->bitstr_obj.W_upper; + transcodingParam.streamval = ISACencUB_obj->bitstr_obj.streamval; + transcodingParam.stream[0] = ISACencUB_obj->bitstr_obj.stream[ + ISACencUB_obj->bitstr_obj.stream_index - 2]; + transcodingParam.stream[1] = ISACencUB_obj->bitstr_obj.stream[ + ISACencUB_obj->bitstr_obj.stream_index - 1]; + transcodingParam.stream[2] = ISACencUB_obj->bitstr_obj.stream[ + ISACencUB_obj->bitstr_obj.stream_index]; + + /* Store LPC Gains before encoding them */ + for(k = 0; k < SUBFRAMES; k++) { + transcodingParam.loFiltGain[k] = lpcGains[k]; + transcodingParam.hiFiltGain[k] = lpcGains[SUBFRAMES + k]; + } + + // Store the gains for multiple encoding + memcpy(ISACencUB_obj->SaveEnc_obj.lpcGain, lpcGains, (SUBFRAMES << 1) * sizeof(double)); + + WebRtcIsac_EncodeLpcGainUb(lpcGains, &ISACencUB_obj->bitstr_obj, + ISACencUB_obj->SaveEnc_obj.lpcGainIndex); + WebRtcIsac_EncodeLpcGainUb(&lpcGains[SUBFRAMES], &ISACencUB_obj->bitstr_obj, + &ISACencUB_obj->SaveEnc_obj.lpcGainIndex[SUBFRAMES]); + + /* Get the correct value for the payload limit and calculate the number of + bytes left for coding the spectrum. It is a 30ms frame + Subract 3 because termination process may add 3 bytes */ + payloadLimitBytes = ISACencUB_obj->maxPayloadSizeBytes - + ISACencUB_obj->numBytesUsed - 3; + bytesLeftSpecCoding = payloadLimitBytes - + ISACencUB_obj->bitstr_obj.stream_index; + + for (k = 0; k < (SUBFRAMES<<1); k++) { + percepFilterParams[k*(UB_LPC_ORDER + 1) + (UB_LPC_ORDER + 1)] = + lpcGains[k]; + } + + /* perceptual pre-filtering (using normalized lattice filter) */ + /* first half-frame filtering */ + WebRtcIsac_NormLatticeFilterMa(UB_LPC_ORDER, + ISACencUB_obj->maskfiltstr_obj.PreStateLoF, + ISACencUB_obj->maskfiltstr_obj.PreStateLoG, + &ISACencUB_obj->data_buffer_float[0], + &percepFilterParams[UB_LPC_ORDER + 1], + &LP_lookahead[0]); + + /* Second half-frame filtering */ + WebRtcIsac_NormLatticeFilterMa(UB_LPC_ORDER, + ISACencUB_obj->maskfiltstr_obj.PreStateLoF, + ISACencUB_obj->maskfiltstr_obj.PreStateLoG, + &ISACencUB_obj->data_buffer_float[FRAMESAMPLES_HALF], + &percepFilterParams[(UB_LPC_ORDER + 1) + SUBFRAMES * + (UB_LPC_ORDER + 1)], &LP_lookahead[FRAMESAMPLES_HALF]); + + WebRtcIsac_Time2Spec(&LP_lookahead[0], &LP_lookahead[FRAMESAMPLES_HALF], + fre, fim, &ISACencUB_obj->fftstr_obj); + + //Store FFT coefficients for multiple encoding + memcpy(&ISACencUB_obj->SaveEnc_obj.realFFT, fre, + FRAMESAMPLES_HALF * sizeof(WebRtc_Word16)); + + memcpy(&ISACencUB_obj->SaveEnc_obj.imagFFT, fim, + FRAMESAMPLES_HALF * sizeof(WebRtc_Word16)); + + // Prepare the audio buffer for the next packet + // move the last 3 ms to the beginning of the buffer + memcpy(ISACencUB_obj->data_buffer_float, + &ISACencUB_obj->data_buffer_float[FRAMESAMPLES], + LB_TOTAL_DELAY_SAMPLES * sizeof(float)); + // start writing with 3 ms delay to compensate for the delay + // of the lower-band. + ISACencUB_obj->buffer_index = LB_TOTAL_DELAY_SAMPLES; + + // Save the bit-stream object at this point for FEC. + memcpy(&ISACencUB_obj->SaveEnc_obj.bitStreamObj, + &ISACencUB_obj->bitstr_obj, sizeof(Bitstr)); + + /* quantization and lossless coding */ + err = WebRtcIsac_EncodeSpecUB16(fre, fim, &ISACencUB_obj->bitstr_obj); + if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) { + return err; + } + + iterCntr = 0; + while((ISACencUB_obj->bitstr_obj.stream_index > payloadLimitBytes) || + (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH)) { + double bytesSpecCoderUsed; + double transcodeScale; + + if (iterCntr >= MAX_PAYLOAD_LIMIT_ITERATION) { + /* We were not able to limit the payload size */ + return -ISAC_PAYLOAD_LARGER_THAN_LIMIT; + } + + if (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH) { + bytesSpecCoderUsed = STREAM_SIZE_MAX; + // being conservative + transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed * 0.5; + } else { + bytesSpecCoderUsed = ISACencUB_obj->bitstr_obj.stream_index - + transcodingParam.stream_index; + transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed; + } + + /* To be safe, we reduce the scale depending on the + number of iterations. */ + transcodeScale *= (1.0 - (0.9 * (double)iterCntr/ + (double)MAX_PAYLOAD_LIMIT_ITERATION)); + + /* Scale the LPC Gains */ + for (k = 0; k < SUBFRAMES; k++) { + transcodingParam.loFiltGain[k] *= transcodeScale; + transcodingParam.hiFiltGain[k] *= transcodeScale; + } + + /* Scale DFT coefficients */ + for (k = 0; k < FRAMESAMPLES_HALF; k++) { + fre[k] = (WebRtc_Word16)(fre[k] * transcodeScale + 0.5); + fim[k] = (WebRtc_Word16)(fim[k] * transcodeScale + 0.5); + } + + //Store FFT coefficients for multiple encoding + memcpy(&ISACencUB_obj->SaveEnc_obj.realFFT, fre, + FRAMESAMPLES_HALF * sizeof(WebRtc_Word16)); + + memcpy(&ISACencUB_obj->SaveEnc_obj.imagFFT, fim, + FRAMESAMPLES_HALF * sizeof(WebRtc_Word16)); + + + /* Store the state of arithmetic coder before coding LPC gains */ + ISACencUB_obj->bitstr_obj.W_upper = transcodingParam.W_upper; + + ISACencUB_obj->bitstr_obj.stream_index = transcodingParam.stream_index; + + ISACencUB_obj->bitstr_obj.streamval = transcodingParam.streamval; + + ISACencUB_obj->bitstr_obj.stream[transcodingParam.stream_index - 2] = + transcodingParam.stream[0]; + + ISACencUB_obj->bitstr_obj.stream[transcodingParam.stream_index - 1] = + transcodingParam.stream[1]; + + ISACencUB_obj->bitstr_obj.stream[transcodingParam.stream_index] = + transcodingParam.stream[2]; + + // Store the gains for multiple encoding + memcpy(ISACencUB_obj->SaveEnc_obj.lpcGain, lpcGains, + (SUBFRAMES << 1) * sizeof(double)); + + WebRtcIsac_EncodeLpcGainUb(transcodingParam.loFiltGain, + &ISACencUB_obj->bitstr_obj, + ISACencUB_obj->SaveEnc_obj.lpcGainIndex); + WebRtcIsac_EncodeLpcGainUb(transcodingParam.hiFiltGain, + &ISACencUB_obj->bitstr_obj, + &ISACencUB_obj->SaveEnc_obj.lpcGainIndex[SUBFRAMES]); + + /* Update the number of bytes left for encoding the spectrum */ + bytesLeftSpecCoding = payloadLimitBytes - + ISACencUB_obj->bitstr_obj.stream_index; + + // Save the bit-stream object at this point for FEC. + memcpy(&ISACencUB_obj->SaveEnc_obj.bitStreamObj, + &ISACencUB_obj->bitstr_obj, sizeof(Bitstr)); + + /* Encode the spectrum */ + err = WebRtcIsac_EncodeSpecUB16(fre, fim, &ISACencUB_obj->bitstr_obj); + if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) { + /* There has been an error but it was not too large payload + (we can cure too large payload) */ + return err; + } + iterCntr++; + } + + /* complete arithmetic coding */ + return WebRtcIsac_EncTerminate(&ISACencUB_obj->bitstr_obj); +} + + +int +WebRtcIsac_EncodeUb12( + float* in, + ISACUBEncStruct* ISACencUB_obj, + WebRtc_Word32 jitterInfo) +{ + int err; + int k; + int iterCntr; + + double lpcVecs[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME]; + + double percepFilterParams[(1 + UB_LPC_ORDER) * SUBFRAMES]; + float LP[FRAMESAMPLES_HALF]; + float HP[FRAMESAMPLES_HALF]; + + double LP_lookahead[FRAMESAMPLES_HALF]; + double HP_lookahead[FRAMESAMPLES_HALF]; + double LPw[FRAMESAMPLES_HALF]; + + double HPw[FRAMESAMPLES_HALF]; + WebRtc_Word16 fre[FRAMESAMPLES_HALF]; /* Q7 */ + WebRtc_Word16 fim[FRAMESAMPLES_HALF]; /* Q7 */ + + int status = 0; + + double varscale[1]; + + double corr[UB_LPC_GAIN_DIM][UB_LPC_ORDER + 1]; + double lpcGains[SUBFRAMES]; + transcode_obj transcodingParam; + double bytesLeftSpecCoding; + WebRtc_UWord16 payloadLimitBytes; + double s2nr; + + /* 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; kdata_buffer_float[k + ISACencUB_obj->buffer_index] = + in[k]; + } + + /* if buffer-size is not equal to current frame-size then increase the + index and return. We do the encoding when we have enough audio. */ + if (ISACencUB_obj->buffer_index + FRAMESAMPLES_10ms < FRAMESAMPLES) { + ISACencUB_obj->buffer_index += FRAMESAMPLES_10ms; + return 0; + } + /* if buffer reached the right size, reset index and continue + with encoding the frame */ + ISACencUB_obj->buffer_index = 0; + + /* end of buffer function */ + /**************************/ + + /* encoding */ + /************/ + + /* reset bitstream */ + ISACencUB_obj->bitstr_obj.W_upper = 0xFFFFFFFF; + ISACencUB_obj->bitstr_obj.streamval = 0; + ISACencUB_obj->bitstr_obj.stream_index = 0; + + /* bandwidth estimation and coding */ + /* To be used for Redundant Coding */ + WebRtcIsac_EncodeJitterInfo(jitterInfo, &ISACencUB_obj->bitstr_obj); + + status = WebRtcIsac_EncodeBandwidth(isac12kHz, + &ISACencUB_obj->bitstr_obj); + if (status < 0) { + return status; + } + + + s2nr = WebRtcIsac_GetSnr(ISACencUB_obj->bottleneck, + FRAMESAMPLES); + + /* split signal in two bands */ + WebRtcIsac_SplitAndFilterFloat(ISACencUB_obj->data_buffer_float, HP, LP, + HP_lookahead, LP_lookahead, &ISACencUB_obj->prefiltbankstr_obj); + + /* find coefficients for perceptual pre-filters */ + WebRtcIsac_GetLpcCoefUb(LP_lookahead, &ISACencUB_obj->maskfiltstr_obj, + lpcVecs, corr, varscale, isac12kHz); + + /* code LPC model and shape - gains not quantized yet */ + WebRtcIsac_EncodeLpcUB(lpcVecs, &ISACencUB_obj->bitstr_obj, + percepFilterParams, isac12kHz, &ISACencUB_obj->SaveEnc_obj); + + WebRtcIsac_GetLpcGain(s2nr, percepFilterParams, SUBFRAMES, lpcGains, + corr, varscale); + + /* Store the state of arithmetic coder before coding LPC gains */ + transcodingParam.W_upper = ISACencUB_obj->bitstr_obj.W_upper; + + transcodingParam.stream_index = ISACencUB_obj->bitstr_obj.stream_index; + + transcodingParam.streamval = ISACencUB_obj->bitstr_obj.streamval; + + transcodingParam.stream[0] = ISACencUB_obj->bitstr_obj.stream[ + ISACencUB_obj->bitstr_obj.stream_index - 2]; + + transcodingParam.stream[1] = ISACencUB_obj->bitstr_obj.stream[ + ISACencUB_obj->bitstr_obj.stream_index - 1]; + + transcodingParam.stream[2] = ISACencUB_obj->bitstr_obj.stream[ + ISACencUB_obj->bitstr_obj.stream_index]; + + /* Store LPC Gains before encoding them */ + for(k = 0; k < SUBFRAMES; k++) { + transcodingParam.loFiltGain[k] = lpcGains[k]; + } + + // Store the gains for multiple encoding + memcpy(ISACencUB_obj->SaveEnc_obj.lpcGain, lpcGains, SUBFRAMES * + sizeof(double)); + + WebRtcIsac_EncodeLpcGainUb(lpcGains, &ISACencUB_obj->bitstr_obj, + ISACencUB_obj->SaveEnc_obj.lpcGainIndex); + + for(k = 0; k < SUBFRAMES; k++) { + percepFilterParams[k*(UB_LPC_ORDER + 1)] = lpcGains[k]; + } + + /* perceptual pre-filtering (using normalized lattice filter) */ + /* low-band filtering */ + WebRtcIsac_NormLatticeFilterMa(UB_LPC_ORDER, + ISACencUB_obj->maskfiltstr_obj.PreStateLoF, + ISACencUB_obj->maskfiltstr_obj.PreStateLoG, LP, percepFilterParams, + LPw); + + /* Get the correct value for the payload limit and calculate the number + of bytes left for coding the spectrum. It is a 30ms frame Subract 3 + because termination process may add 3 bytes */ + payloadLimitBytes = ISACencUB_obj->maxPayloadSizeBytes - + ISACencUB_obj->numBytesUsed - 3; + bytesLeftSpecCoding = payloadLimitBytes - + ISACencUB_obj->bitstr_obj.stream_index; + + memset(HPw, 0, sizeof(double) * FRAMESAMPLES_HALF); + + /* transform */ + WebRtcIsac_Time2Spec(LPw, HPw, fre, fim, &ISACencUB_obj->fftstr_obj); + + //Store real FFT coefficients for multiple encoding + memcpy(&ISACencUB_obj->SaveEnc_obj.realFFT, fre, + FRAMESAMPLES_HALF * sizeof(WebRtc_Word16)); + + //Store imaginary FFT coefficients for multiple encoding + memcpy(&ISACencUB_obj->SaveEnc_obj.imagFFT, fim, + FRAMESAMPLES_HALF * sizeof(WebRtc_Word16)); + + // Save the bit-stream object at this point for FEC. + memcpy(&ISACencUB_obj->SaveEnc_obj.bitStreamObj, + &ISACencUB_obj->bitstr_obj, sizeof(Bitstr)); + + /* quantization and lossless coding */ + err = WebRtcIsac_EncodeSpecUB12(fre, fim, &ISACencUB_obj->bitstr_obj); + if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) { + /* There has been an error but it was not too large + payload (we can cure too large payload) */ + return err; + } + iterCntr = 0; + while((ISACencUB_obj->bitstr_obj.stream_index > payloadLimitBytes) || + (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH)) { + double bytesSpecCoderUsed; + double transcodeScale; + + if (iterCntr >= MAX_PAYLOAD_LIMIT_ITERATION) { + /* We were not able to limit the payload size */ + return -ISAC_PAYLOAD_LARGER_THAN_LIMIT; + } + + if (err == -ISAC_DISALLOWED_BITSTREAM_LENGTH) { + bytesSpecCoderUsed = STREAM_SIZE_MAX; + // being coservative + transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed * 0.5; + } else { + bytesSpecCoderUsed = ISACencUB_obj->bitstr_obj.stream_index - + transcodingParam.stream_index; + transcodeScale = bytesLeftSpecCoding / bytesSpecCoderUsed; + } + + /* To be safe, we reduce the scale depending on the + number of iterations. */ + transcodeScale *= (1.0 - (0.9 * (double)iterCntr/ + (double)MAX_PAYLOAD_LIMIT_ITERATION)); + + /* Scale the LPC Gains */ + for (k = 0; k < SUBFRAMES; k++) { + transcodingParam.loFiltGain[k] *= transcodeScale; + } + + /* Scale DFT coefficients */ + for (k = 0; k < FRAMESAMPLES_HALF; k++) { + fre[k] = (WebRtc_Word16)(fre[k] * transcodeScale + 0.5); + fim[k] = (WebRtc_Word16)(fim[k] * transcodeScale + 0.5); + } + + //Store real FFT coefficients for multiple encoding + memcpy(&ISACencUB_obj->SaveEnc_obj.realFFT, fre, + FRAMESAMPLES_HALF * sizeof(WebRtc_Word16)); + + //Store imaginary FFT coefficients for multiple encoding + memcpy(&ISACencUB_obj->SaveEnc_obj.imagFFT, fim, + FRAMESAMPLES_HALF * sizeof(WebRtc_Word16)); + + + /* Re-store the state of arithmetic coder before coding LPC gains */ + ISACencUB_obj->bitstr_obj.W_upper = transcodingParam.W_upper; + + ISACencUB_obj->bitstr_obj.stream_index = transcodingParam.stream_index; + + ISACencUB_obj->bitstr_obj.streamval = transcodingParam.streamval; + + ISACencUB_obj->bitstr_obj.stream[transcodingParam.stream_index - 2] = + transcodingParam.stream[0]; + + ISACencUB_obj->bitstr_obj.stream[transcodingParam.stream_index - 1] = + transcodingParam.stream[1]; + + ISACencUB_obj->bitstr_obj.stream[transcodingParam.stream_index] = + transcodingParam.stream[2]; + + // Store the gains for multiple encoding + memcpy(&ISACencUB_obj->SaveEnc_obj.lpcGain, lpcGains, SUBFRAMES * + sizeof(double)); + + // encode LPC gain and store quantization indices. HAving quantization + // indices reduces transcoding complexity if 'scale factor' is 1. + WebRtcIsac_EncodeLpcGainUb(transcodingParam.loFiltGain, + &ISACencUB_obj->bitstr_obj, + ISACencUB_obj->SaveEnc_obj.lpcGainIndex); + + // Save the bit-stream object at this point for FEC. + memcpy(&ISACencUB_obj->SaveEnc_obj.bitStreamObj, + &ISACencUB_obj->bitstr_obj, sizeof(Bitstr)); + + /* Update the number of bytes left for encoding the spectrum */ + bytesLeftSpecCoding = payloadLimitBytes - + ISACencUB_obj->bitstr_obj.stream_index; + + /* Encode the spectrum */ + err = WebRtcIsac_EncodeSpecUB12(fre, fim, + &ISACencUB_obj->bitstr_obj); + if ((err < 0) && (err != -ISAC_DISALLOWED_BITSTREAM_LENGTH)) { + /* There has been an error but it was not too large payload + (we can cure too large payload) */ + return err; + } + iterCntr++; + } + + /* complete arithmetic coding */ + return WebRtcIsac_EncTerminate(&ISACencUB_obj->bitstr_obj); +} + + + + + + +/* This function is used to create a new bitstream with new BWE. + The same data as previously encoded with the function WebRtcIsac_Encoder(). + The data needed is taken from the struct, where it was stored + when calling the encoder. */ + +int WebRtcIsac_EncodeStoredDataLb( + const ISAC_SaveEncData_t* ISACSavedEnc_obj, + Bitstr* ISACBitStr_obj, + int BWnumber, + float scale) +{ + int ii; + int status; + int BWno = BWnumber; + + const WebRtc_UWord16 *WebRtcIsac_kQPitchGainCdf_ptr[1]; + const WebRtc_UWord16 **cdf; + + double tmpLPCcoeffs_lo[(ORDERLO+1)*SUBFRAMES*2]; + double tmpLPCcoeffs_hi[(ORDERHI+1)*SUBFRAMES*2]; + int tmpLPCindex_g[12*2]; + WebRtc_Word16 tmp_fre[FRAMESAMPLES], tmp_fim[FRAMESAMPLES]; + + /* Sanity Check - possible values for BWnumber is 0 - 23 */ + if ((BWnumber < 0) || (BWnumber > 23)) { + return -ISAC_RANGE_ERROR_BW_ESTIMATOR; + } + + /* reset bitstream */ + ISACBitStr_obj->W_upper = 0xFFFFFFFF; + ISACBitStr_obj->streamval = 0; + ISACBitStr_obj->stream_index = 0; + + /* encode frame length */ + status = WebRtcIsac_EncodeFrameLen(ISACSavedEnc_obj->framelength, + ISACBitStr_obj); + if (status < 0) { + /* Wrong frame size */ + return status; + } + + /* Transcoding */ + if ((scale > 0.0) && (scale < 1.0)) { + /* Compensate LPC gain */ + for (ii = 0; + ii < ((ORDERLO + 1)* SUBFRAMES * (1 + ISACSavedEnc_obj->startIdx)); + ii++) { + tmpLPCcoeffs_lo[ii] = scale * ISACSavedEnc_obj->LPCcoeffs_lo[ii]; + } + for (ii = 0; + ii < ((ORDERHI + 1) * SUBFRAMES *(1 + ISACSavedEnc_obj->startIdx)); + ii++) { + tmpLPCcoeffs_hi[ii] = scale * ISACSavedEnc_obj->LPCcoeffs_hi[ii]; + } + /* Scale DFT */ + for (ii = 0; + ii < (FRAMESAMPLES_HALF * (1 + ISACSavedEnc_obj->startIdx)); + ii++) { + tmp_fre[ii] = (WebRtc_Word16)((scale) * + (float)ISACSavedEnc_obj->fre[ii]) ; + tmp_fim[ii] = (WebRtc_Word16)((scale) * + (float)ISACSavedEnc_obj->fim[ii]) ; + } + } else { + for (ii = 0; + ii < (KLT_ORDER_GAIN * (1 + ISACSavedEnc_obj->startIdx)); + ii++) { + tmpLPCindex_g[ii] = ISACSavedEnc_obj->LPCindex_g[ii]; + } + for (ii = 0; + ii < (FRAMESAMPLES_HALF * (1 + ISACSavedEnc_obj->startIdx)); + ii++) { + tmp_fre[ii] = ISACSavedEnc_obj->fre[ii]; + tmp_fim[ii] = ISACSavedEnc_obj->fim[ii]; + } + } + + /* encode bandwidth estimate */ + WebRtcIsac_EncodeReceiveBw(&BWno, ISACBitStr_obj); + + /* Loop over number of 30 msec */ + for (ii = 0; ii <= ISACSavedEnc_obj->startIdx; ii++) { + /* encode pitch gains */ + *WebRtcIsac_kQPitchGainCdf_ptr = WebRtcIsac_kQPitchGainCdf; + WebRtcIsac_EncHistMulti(ISACBitStr_obj, + &ISACSavedEnc_obj->pitchGain_index[ii], WebRtcIsac_kQPitchGainCdf_ptr, 1); + + /* entropy coding of quantization pitch lags */ + /* voicing classificiation */ + if (ISACSavedEnc_obj->meanGain[ii] < 0.2) { + cdf = WebRtcIsac_kQPitchLagCdfPtrLo; + } else if (ISACSavedEnc_obj->meanGain[ii] < 0.4) { + cdf = WebRtcIsac_kQPitchLagCdfPtrMid; + } else { + cdf = WebRtcIsac_kQPitchLagCdfPtrHi; + } + WebRtcIsac_EncHistMulti(ISACBitStr_obj, + &ISACSavedEnc_obj->pitchIndex[PITCH_SUBFRAMES*ii], cdf, + PITCH_SUBFRAMES); + + /* LPC */ + /* entropy coding of model number */ + WebRtcIsac_EncHistMulti(ISACBitStr_obj, + &ISACSavedEnc_obj->LPCmodel[ii], WebRtcIsac_kQKltModelCdfPtr, 1); + + /* entropy coding of quantization indices - LPC shape only */ + WebRtcIsac_EncHistMulti(ISACBitStr_obj, + &ISACSavedEnc_obj->LPCindex_s[KLT_ORDER_SHAPE*ii], + WebRtcIsac_kQKltCdfPtrShape[ISACSavedEnc_obj->LPCmodel[ii]], + KLT_ORDER_SHAPE); + + /* If transcoding, get new LPC gain indices */ + if (scale < 1.0) { + WebRtcIsac_TranscodeLPCCoef(&tmpLPCcoeffs_lo[(ORDERLO+1) * + SUBFRAMES*ii], &tmpLPCcoeffs_hi[(ORDERHI+1)*SUBFRAMES*ii], + ISACSavedEnc_obj->LPCmodel[ii], + &tmpLPCindex_g[KLT_ORDER_GAIN * ii]); + } + + /* entropy coding of quantization indices - LPC gain */ + WebRtcIsac_EncHistMulti(ISACBitStr_obj, + &tmpLPCindex_g[KLT_ORDER_GAIN*ii], WebRtcIsac_kQKltCdfPtrGain[ + ISACSavedEnc_obj->LPCmodel[ii]], KLT_ORDER_GAIN); + + /* quantization and lossless coding */ + status = WebRtcIsac_EncodeSpecLb(&tmp_fre[ii*FRAMESAMPLES_HALF], + &tmp_fim[ii*FRAMESAMPLES_HALF], ISACBitStr_obj, + ISACSavedEnc_obj->AvgPitchGain[ii]); + if (status < 0) { + return status; + } + } + + /* complete arithmetic coding */ + return WebRtcIsac_EncTerminate(ISACBitStr_obj); +} + + + + +int WebRtcIsac_EncodeStoredDataUb12( + const ISACUBSaveEncDataStruct* ISACSavedEnc_obj, + Bitstr* bitStream, + WebRtc_Word32 jitterInfo, + float scale) +{ + int n; + int err; + double lpcGain[SUBFRAMES]; + WebRtc_Word16 realFFT[FRAMESAMPLES_HALF]; + WebRtc_Word16 imagFFT[FRAMESAMPLES_HALF]; + + /* reset bitstream */ + bitStream->W_upper = 0xFFFFFFFF; + bitStream->streamval = 0; + bitStream->stream_index = 0; + + // Encode jitter index + WebRtcIsac_EncodeJitterInfo(jitterInfo, bitStream); + + err = WebRtcIsac_EncodeBandwidth(isac12kHz, bitStream); + if(err < 0) + { + return err; + } + + // Encode LPC-shape + WebRtcIsac_EncHistMulti(bitStream, ISACSavedEnc_obj->indexLPCShape, + WebRtcIsac_kLpcShapeCdfMatUb12, UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME); + + + // we only consider scales between zero and one. + if((scale <= 0.0) || (scale > 1.0)) + { + scale = 1.0f; + } + + if(scale == 1.0f) + { + //memcpy(lpcGain, ISACSavedEnc_obj->lpcGain, SUBFRAMES * sizeof(double)); + WebRtcIsac_EncHistMulti(bitStream, ISACSavedEnc_obj->lpcGainIndex, + WebRtcIsac_kLpcGainCdfMat, UB_LPC_GAIN_DIM); + // store FFT coefficients + err = WebRtcIsac_EncodeSpecUB12(ISACSavedEnc_obj->realFFT, + ISACSavedEnc_obj->imagFFT, bitStream); + } + else + { + /* scale lpc gain and FFT coefficients */ + for(n = 0; n < SUBFRAMES; n++) + { + lpcGain[n] = scale * ISACSavedEnc_obj->lpcGain[n]; + } + // store lpc gain + WebRtcIsac_StoreLpcGainUb(lpcGain, bitStream); + for(n = 0; n < FRAMESAMPLES_HALF; n++) + { + realFFT[n] = (WebRtc_Word16)(scale * (float)ISACSavedEnc_obj->realFFT[n] + 0.5f); + imagFFT[n] = (WebRtc_Word16)(scale * (float)ISACSavedEnc_obj->imagFFT[n] + 0.5f); + } + // store FFT coefficients + err = WebRtcIsac_EncodeSpecUB12(realFFT, imagFFT, bitStream); + } + if(err < 0) + { + // error happened while encoding FFT coefficients. + return err; + } + + /* complete arithmetic coding */ + return WebRtcIsac_EncTerminate(bitStream); +} + + +int +WebRtcIsac_EncodeStoredDataUb16( + const ISACUBSaveEncDataStruct* ISACSavedEnc_obj, + Bitstr* bitStream, + WebRtc_Word32 jitterInfo, + float scale) +{ + int n; + int err; + double lpcGain[SUBFRAMES << 1]; + WebRtc_Word16 realFFT[FRAMESAMPLES_HALF]; + WebRtc_Word16 imagFFT[FRAMESAMPLES_HALF]; + + /* reset bitstream */ + bitStream->W_upper = 0xFFFFFFFF; + bitStream->streamval = 0; + bitStream->stream_index = 0; + + // Encode jitter index + WebRtcIsac_EncodeJitterInfo(jitterInfo, bitStream); + + err = WebRtcIsac_EncodeBandwidth(isac16kHz, bitStream); + if(err < 0) + { + return err; + } + + WebRtcIsac_EncHistMulti(bitStream, ISACSavedEnc_obj->indexLPCShape, + WebRtcIsac_kLpcShapeCdfMatUb16, UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME); + + // we only consider scales between zero and one. + if((scale <= 0.0) || (scale > 1.0)) + { + scale = 1.0f; + } + + if(scale == 1.0f) + { + // store gains + WebRtcIsac_EncHistMulti(bitStream, ISACSavedEnc_obj->lpcGainIndex, + WebRtcIsac_kLpcGainCdfMat, UB_LPC_GAIN_DIM); + WebRtcIsac_EncHistMulti(bitStream, &ISACSavedEnc_obj->lpcGainIndex[SUBFRAMES], + WebRtcIsac_kLpcGainCdfMat, UB_LPC_GAIN_DIM); + // store FFT coefficients + err = WebRtcIsac_EncodeSpecUB16(ISACSavedEnc_obj->realFFT, + ISACSavedEnc_obj->imagFFT, bitStream); + + } + else + { + /* Scale Gain */ + for(n = 0; n < SUBFRAMES; n++) + { + lpcGain[n] = scale * ISACSavedEnc_obj->lpcGain[n]; + lpcGain[n + SUBFRAMES] = scale * ISACSavedEnc_obj->lpcGain[n + SUBFRAMES]; + } + // store lpc gain + WebRtcIsac_StoreLpcGainUb(lpcGain, bitStream); + WebRtcIsac_StoreLpcGainUb(&lpcGain[SUBFRAMES], bitStream); + /* scale FFT coefficients */ + for(n = 0; n < FRAMESAMPLES_HALF; n++) + { + realFFT[n] = (WebRtc_Word16)(scale * (float)ISACSavedEnc_obj->realFFT[n] + 0.5f); + imagFFT[n] = (WebRtc_Word16)(scale * (float)ISACSavedEnc_obj->imagFFT[n] + 0.5f); + } + // store FFT coefficients + err = WebRtcIsac_EncodeSpecUB16(realFFT, imagFFT, bitStream); + } + + if(err < 0) + { + // error happened while encoding FFT coefficients. + return err; + } + + /* complete arithmetic coding */ + return WebRtcIsac_EncTerminate(bitStream); +} + + +WebRtc_Word16 +WebRtcIsac_GetRedPayloadUb( + const ISACUBSaveEncDataStruct* ISACSavedEncObj, + Bitstr* bitStreamObj, + enum ISACBandwidth bandwidth) +{ + int n; + WebRtc_Word16 status; + WebRtc_Word16 realFFT[FRAMESAMPLES_HALF]; + WebRtc_Word16 imagFFT[FRAMESAMPLES_HALF]; + + // store bit-stream object. + memcpy(bitStreamObj, &ISACSavedEncObj->bitStreamObj, sizeof(Bitstr)); + + // Scale FFT coefficients. + for(n = 0; n < FRAMESAMPLES_HALF; n++) + { + realFFT[n] = (WebRtc_Word16)((float)ISACSavedEncObj->realFFT[n] * + RCU_TRANSCODING_SCALE_UB + 0.5); + imagFFT[n] = (WebRtc_Word16)((float)ISACSavedEncObj->imagFFT[n] * + RCU_TRANSCODING_SCALE_UB + 0.5); + } + + switch(bandwidth) + { + case isac12kHz: + { + status = WebRtcIsac_EncodeSpecUB12(realFFT, imagFFT, bitStreamObj); + break; + } + case isac16kHz: + { + status = WebRtcIsac_EncodeSpecUB16(realFFT, imagFFT, bitStreamObj); + break; + } + default: + return -1; + } + + if(status < 0) + { + // error happened + return status; + } + else + { + // terminate entropy coding + return WebRtcIsac_EncTerminate(bitStreamObj); + } +} diff --git a/libs/miniwebrtc/audio/coding_isac/main/encode_lpc_swb.c b/libs/miniwebrtc/audio/coding_isac/main/encode_lpc_swb.c new file mode 100644 index 00000000..2bf4c364 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/encode_lpc_swb.c @@ -0,0 +1,708 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * code_LPC_UB.c + * + * This file contains definition of functions used to + * encode LPC parameters (Shape & gain) of the upper band. + * + */ + +#include "encode_lpc_swb.h" +#include "typedefs.h" +#include "settings.h" + +#include "lpc_shape_swb12_tables.h" +#include "lpc_shape_swb16_tables.h" +#include "lpc_gain_swb_tables.h" + +#include +#include +#include + +/****************************************************************************** + * WebRtcIsac_RemoveLarMean() + * + * Remove the means from LAR coefficients. + * + * Input: + * -lar : pointer to lar vectors. LAR vectors are + * concatenated. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -lar : pointer to mean-removed LAR:s. + * + * + */ +WebRtc_Word16 +WebRtcIsac_RemoveLarMean( + double* lar, + WebRtc_Word16 bandwidth) +{ + WebRtc_Word16 coeffCntr; + WebRtc_Word16 vecCntr; + WebRtc_Word16 numVec; + const double* meanLAR; + switch(bandwidth) + { + case isac12kHz: + { + numVec = UB_LPC_VEC_PER_FRAME; + meanLAR = WebRtcIsac_kMeanLarUb12; + break; + } + case isac16kHz: + { + numVec = UB16_LPC_VEC_PER_FRAME; + meanLAR = WebRtcIsac_kMeanLarUb16; + break; + } + default: + return -1; + } + + for(vecCntr = 0; vecCntr < numVec; vecCntr++) + { + for(coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++) + { + // REMOVE MEAN + *lar++ -= meanLAR[coeffCntr]; + } + } + return 0; +} + +/****************************************************************************** + * WebRtcIsac_DecorrelateIntraVec() + * + * Remove the correlation amonge the components of LAR vectors. If LAR vectors + * of one frame are put in a matrix where each column is a LAR vector of a + * sub-frame, then this is equivalent to multiplying the LAR matrix with + * a decorrelting mtrix from left. + * + * Input: + * -inLar : pointer to mean-removed LAR vecrtors. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -out : decorrelated LAR vectors. + */ +WebRtc_Word16 +WebRtcIsac_DecorrelateIntraVec( + const double* data, + double* out, + WebRtc_Word16 bandwidth) +{ + const double* ptrData; + const double* ptrRow; + WebRtc_Word16 rowCntr; + WebRtc_Word16 colCntr; + WebRtc_Word16 larVecCntr; + WebRtc_Word16 numVec; + const double* decorrMat; + switch(bandwidth) + { + case isac12kHz: + { + decorrMat = &WebRtcIsac_kIntraVecDecorrMatUb12[0][0]; + numVec = UB_LPC_VEC_PER_FRAME; + break; + } + case isac16kHz: + { + decorrMat = &WebRtcIsac_kIintraVecDecorrMatUb16[0][0]; + numVec = UB16_LPC_VEC_PER_FRAME; + break; + } + default: + return -1; + } + + // + // decorrMat * data + // + // data is assumed to contain 'numVec' of LAR + // vectors (mean removed) each of dimension 'UB_LPC_ORDER' + // concatenated one after the other. + // + + ptrData = data; + for(larVecCntr = 0; larVecCntr < numVec; larVecCntr++) + { + for(rowCntr = 0; rowCntr < UB_LPC_ORDER; rowCntr++) + { + ptrRow = &decorrMat[rowCntr * UB_LPC_ORDER]; + *out = 0; + for(colCntr = 0; colCntr < UB_LPC_ORDER; colCntr++) + { + *out += ptrData[colCntr] * ptrRow[colCntr]; + } + out++; + } + ptrData += UB_LPC_ORDER; + } + return 0; +} + +/****************************************************************************** + * WebRtcIsac_DecorrelateInterVec() + * + * Remover the correlation among mean-removed LAR vectors. If LAR vectors + * of one frame are put in a matrix where each column is a LAR vector of a + * sub-frame, then this is equivalent to multiplying the LAR matrix with + * a decorrelting mtrix from right. + * + * Input: + * -data : pointer to matrix of LAR vectors. The matrix + * is stored column-wise. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -out : decorrelated LAR vectors. + */ +WebRtc_Word16 +WebRtcIsac_DecorrelateInterVec( + const double* data, + double* out, + WebRtc_Word16 bandwidth) +{ + WebRtc_Word16 coeffCntr; + WebRtc_Word16 rowCntr; + WebRtc_Word16 colCntr; + const double* decorrMat; + WebRtc_Word16 interVecDim; + + switch(bandwidth) + { + case isac12kHz: + { + decorrMat = &WebRtcIsac_kInterVecDecorrMatUb12[0][0]; + interVecDim = UB_LPC_VEC_PER_FRAME; + break; + } + case isac16kHz: + { + decorrMat = &WebRtcIsac_kInterVecDecorrMatUb16[0][0]; + interVecDim = UB16_LPC_VEC_PER_FRAME; + break; + } + default: + return -1; + } + + // + // data * decorrMat + // + // data is of size 'interVecDim' * 'UB_LPC_ORDER' + // That is 'interVecDim' of LAR vectors (mean removed) + // in columns each of dimension 'UB_LPC_ORDER'. + // matrix is stored column-wise. + // + + for(coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++) + { + for(colCntr = 0; colCntr < interVecDim; colCntr++) + { + out[coeffCntr + colCntr * UB_LPC_ORDER] = 0; + for(rowCntr = 0; rowCntr < interVecDim; rowCntr++) + { + out[coeffCntr + colCntr * UB_LPC_ORDER] += + data[coeffCntr + rowCntr * UB_LPC_ORDER] * + decorrMat[rowCntr * interVecDim + colCntr]; + } + } + } + return 0; +} + +/****************************************************************************** + * WebRtcIsac_QuantizeUncorrLar() + * + * Quantize the uncorrelated parameters. + * + * Input: + * -data : uncorrelated LAR vectors. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -data : quantized version of the input. + * -idx : pointer to quantization indices. + */ +double +WebRtcIsac_QuantizeUncorrLar( + double* data, + int* recIdx, + WebRtc_Word16 bandwidth) +{ + WebRtc_Word16 cntr; + WebRtc_Word32 idx; + WebRtc_Word16 interVecDim; + const double* leftRecPoint; + double quantizationStepSize; + const WebRtc_Word16* numQuantCell; + switch(bandwidth) + { + case isac12kHz: + { + leftRecPoint = WebRtcIsac_kLpcShapeLeftRecPointUb12; + quantizationStepSize = WebRtcIsac_kLpcShapeQStepSizeUb12; + numQuantCell = WebRtcIsac_kLpcShapeNumRecPointUb12; + interVecDim = UB_LPC_VEC_PER_FRAME; + break; + } + case isac16kHz: + { + leftRecPoint = WebRtcIsac_kLpcShapeLeftRecPointUb16; + quantizationStepSize = WebRtcIsac_kLpcShapeQStepSizeUb16; + numQuantCell = WebRtcIsac_kLpcShapeNumRecPointUb16; + interVecDim = UB16_LPC_VEC_PER_FRAME; + break; + } + default: + return -1; + } + + // + // Quantize the parametrs. + // + for(cntr = 0; cntr < UB_LPC_ORDER * interVecDim; cntr++) + { + idx = (WebRtc_Word32)floor((*data - leftRecPoint[cntr]) / + quantizationStepSize + 0.5); + if(idx < 0) + { + idx = 0; + } + else if(idx >= numQuantCell[cntr]) + { + idx = numQuantCell[cntr] - 1; + } + + *data++ = leftRecPoint[cntr] + idx * quantizationStepSize; + *recIdx++ = idx; + } + return 0; +} + + +/****************************************************************************** + * WebRtcIsac_DequantizeLpcParam() + * + * Get the quantized value of uncorrelated LARs given the quantization indices. + * + * Input: + * -idx : pointer to quantiztion indices. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -out : pointer to quantized values. + */ +WebRtc_Word16 +WebRtcIsac_DequantizeLpcParam( + const int* idx, + double* out, + WebRtc_Word16 bandwidth) +{ + WebRtc_Word16 cntr; + WebRtc_Word16 interVecDim; + const double* leftRecPoint; + double quantizationStepSize; + + switch(bandwidth) + { + case isac12kHz: + { + leftRecPoint = WebRtcIsac_kLpcShapeLeftRecPointUb12; + quantizationStepSize = WebRtcIsac_kLpcShapeQStepSizeUb12; + interVecDim = UB_LPC_VEC_PER_FRAME; + break; + } + case isac16kHz: + { + leftRecPoint = WebRtcIsac_kLpcShapeLeftRecPointUb16; + quantizationStepSize = WebRtcIsac_kLpcShapeQStepSizeUb16; + interVecDim = UB16_LPC_VEC_PER_FRAME; + break; + } + default: + return -1; + } + + // + // Dequantize given the quantization indices + // + + for(cntr = 0; cntr < UB_LPC_ORDER * interVecDim; cntr++) + { + *out++ = leftRecPoint[cntr] + *idx++ * quantizationStepSize; + } + return 0; +} + + +/****************************************************************************** + * WebRtcIsac_CorrelateIntraVec() + * + * This is the inverse of WebRtcIsac_DecorrelateIntraVec(). + * + * Input: + * -data : uncorrelated parameters. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -out : correlated parametrs. + */ +WebRtc_Word16 +WebRtcIsac_CorrelateIntraVec( + const double* data, + double* out, + WebRtc_Word16 bandwidth) +{ + WebRtc_Word16 vecCntr; + WebRtc_Word16 rowCntr; + WebRtc_Word16 colCntr; + WebRtc_Word16 numVec; + const double* ptrData; + const double* intraVecDecorrMat; + + switch(bandwidth) + { + case isac12kHz: + { + numVec = UB_LPC_VEC_PER_FRAME; + intraVecDecorrMat = &WebRtcIsac_kIntraVecDecorrMatUb12[0][0]; + break; + } + case isac16kHz: + { + numVec = UB16_LPC_VEC_PER_FRAME; + intraVecDecorrMat = &WebRtcIsac_kIintraVecDecorrMatUb16[0][0]; + break; + } + default: + return -1; + } + + + ptrData = data; + for(vecCntr = 0; vecCntr < numVec; vecCntr++) + { + for(colCntr = 0; colCntr < UB_LPC_ORDER; colCntr++) + { + *out = 0; + for(rowCntr = 0; rowCntr < UB_LPC_ORDER; rowCntr++) + { + *out += ptrData[rowCntr] * + intraVecDecorrMat[rowCntr * UB_LPC_ORDER + colCntr]; + } + out++; + } + ptrData += UB_LPC_ORDER; + } + return 0; +} + +/****************************************************************************** + * WebRtcIsac_CorrelateInterVec() + * + * This is the inverse of WebRtcIsac_DecorrelateInterVec(). + * + * Input: + * -data + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -out : correlated parametrs. + */ +WebRtc_Word16 +WebRtcIsac_CorrelateInterVec( + const double* data, + double* out, + WebRtc_Word16 bandwidth) +{ + WebRtc_Word16 coeffCntr; + WebRtc_Word16 rowCntr; + WebRtc_Word16 colCntr; + WebRtc_Word16 interVecDim; + double myVec[UB16_LPC_VEC_PER_FRAME]; + const double* interVecDecorrMat; + + switch(bandwidth) + { + case isac12kHz: + { + interVecDim = UB_LPC_VEC_PER_FRAME; + interVecDecorrMat = &WebRtcIsac_kInterVecDecorrMatUb12[0][0]; + break; + } + case isac16kHz: + { + interVecDim = UB16_LPC_VEC_PER_FRAME; + interVecDecorrMat = &WebRtcIsac_kInterVecDecorrMatUb16[0][0]; + break; + } + default: + return -1; + } + + for(coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++) + { + for(rowCntr = 0; rowCntr < interVecDim; rowCntr++) + { + myVec[rowCntr] = 0; + for(colCntr = 0; colCntr < interVecDim; colCntr++) + { + myVec[rowCntr] += data[coeffCntr + colCntr * UB_LPC_ORDER] * //*ptrData * + interVecDecorrMat[rowCntr * interVecDim + colCntr]; + //ptrData += UB_LPC_ORDER; + } + } + + for(rowCntr = 0; rowCntr < interVecDim; rowCntr++) + { + out[coeffCntr + rowCntr * UB_LPC_ORDER] = myVec[rowCntr]; + } + } + return 0; +} + +/****************************************************************************** + * WebRtcIsac_AddLarMean() + * + * This is the inverse of WebRtcIsac_RemoveLarMean() + * + * Input: + * -data : pointer to mean-removed LAR:s. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -data : pointer to LARs. + */ +WebRtc_Word16 +WebRtcIsac_AddLarMean( + double* data, + WebRtc_Word16 bandwidth) +{ + WebRtc_Word16 coeffCntr; + WebRtc_Word16 vecCntr; + WebRtc_Word16 numVec; + const double* meanLAR; + + switch(bandwidth) + { + case isac12kHz: + { + numVec = UB_LPC_VEC_PER_FRAME; + meanLAR = WebRtcIsac_kMeanLarUb12; + break; + } + case isac16kHz: + { + numVec = UB16_LPC_VEC_PER_FRAME; + meanLAR = WebRtcIsac_kMeanLarUb16; + break; + } + default: + return -1; + } + + for(vecCntr = 0; vecCntr < numVec; vecCntr++) + { + for(coeffCntr = 0; coeffCntr < UB_LPC_ORDER; coeffCntr++) + { + *data++ += meanLAR[coeffCntr]; + } + } + return 0; +} + +/****************************************************************************** + * WebRtcIsac_ToLogDomainRemoveMean() + * + * Transform the LPC gain to log domain then remove the mean value. + * + * Input: + * -lpcGain : pointer to LPC Gain, expecting 6 LPC gains + * + * Output: + * -lpcGain : mean-removed in log domain. + */ +WebRtc_Word16 +WebRtcIsac_ToLogDomainRemoveMean( + double* data) +{ + WebRtc_Word16 coeffCntr; + for(coeffCntr = 0; coeffCntr < UB_LPC_GAIN_DIM; coeffCntr++) + { + data[coeffCntr] = log(data[coeffCntr]) - WebRtcIsac_kMeanLpcGain; + } + return 0; +} + + +/****************************************************************************** + * WebRtcIsac_DecorrelateLPGain() + * + * Decorrelate LPC gains. There are 6 LPC Gains per frame. This is like + * multiplying gain vector with decorrelating matrix. + * + * Input: + * -data : LPC gain in log-domain with mean removed. + * + * Output: + * -out : decorrelated parameters. + */ +WebRtc_Word16 WebRtcIsac_DecorrelateLPGain( + const double* data, + double* out) +{ + WebRtc_Word16 rowCntr; + WebRtc_Word16 colCntr; + + for(colCntr = 0; colCntr < UB_LPC_GAIN_DIM; colCntr++) + { + *out = 0; + for(rowCntr = 0; rowCntr < UB_LPC_GAIN_DIM; rowCntr++) + { + *out += data[rowCntr] * WebRtcIsac_kLpcGainDecorrMat[rowCntr][colCntr]; + } + out++; + } + return 0; +} + +/****************************************************************************** + * WebRtcIsac_QuantizeLpcGain() + * + * Quantize the decorrelated log-domain gains. + * + * Input: + * -lpcGain : uncorrelated LPC gains. + * + * Output: + * -idx : quantization indices + * -lpcGain : quantized value of the inpt. + */ +double WebRtcIsac_QuantizeLpcGain( + double* data, + int* idx) +{ + WebRtc_Word16 coeffCntr; + for(coeffCntr = 0; coeffCntr < UB_LPC_GAIN_DIM; coeffCntr++) + { + *idx = (int)floor((*data - WebRtcIsac_kLeftRecPointLpcGain[coeffCntr]) / + WebRtcIsac_kQSizeLpcGain + 0.5); + + if(*idx < 0) + { + *idx = 0; + } + else if(*idx >= WebRtcIsac_kNumQCellLpcGain[coeffCntr]) + { + *idx = WebRtcIsac_kNumQCellLpcGain[coeffCntr] - 1; + } + *data = WebRtcIsac_kLeftRecPointLpcGain[coeffCntr] + *idx * + WebRtcIsac_kQSizeLpcGain; + + data++; + idx++; + } + return 0; +} + +/****************************************************************************** + * WebRtcIsac_DequantizeLpcGain() + * + * Get the quantized values given the quantization indices. + * + * Input: + * -idx : pointer to quantization indices. + * + * Output: + * -lpcGains : quantized values of the given parametes. + */ +WebRtc_Word16 WebRtcIsac_DequantizeLpcGain( + const int* idx, + double* out) +{ + WebRtc_Word16 coeffCntr; + for(coeffCntr = 0; coeffCntr < UB_LPC_GAIN_DIM; coeffCntr++) + { + *out = WebRtcIsac_kLeftRecPointLpcGain[coeffCntr] + *idx * + WebRtcIsac_kQSizeLpcGain; + out++; + idx++; + } + return 0; +} + +/****************************************************************************** + * WebRtcIsac_CorrelateLpcGain() + * + * This is the inverse of WebRtcIsac_DecorrelateLPGain(). + * + * Input: + * -data : decorrelated parameters. + * + * Output: + * -out : correlated parameters. + */ +WebRtc_Word16 WebRtcIsac_CorrelateLpcGain( + const double* data, + double* out) +{ + WebRtc_Word16 rowCntr; + WebRtc_Word16 colCntr; + + for(rowCntr = 0; rowCntr < UB_LPC_GAIN_DIM; rowCntr++) + { + *out = 0; + for(colCntr = 0; colCntr < UB_LPC_GAIN_DIM; colCntr++) + { + *out += WebRtcIsac_kLpcGainDecorrMat[rowCntr][colCntr] * data[colCntr]; + } + out++; + } + + return 0; +} + + +/****************************************************************************** + * WebRtcIsac_AddMeanToLinearDomain() + * + * This is the inverse of WebRtcIsac_ToLogDomainRemoveMean(). + * + * Input: + * -lpcGain : LPC gain in log-domain & mean removed + * + * Output: + * -lpcGain : LPC gain in normal domain. + */ +WebRtc_Word16 WebRtcIsac_AddMeanToLinearDomain( + double* lpcGains) +{ + WebRtc_Word16 coeffCntr; + for(coeffCntr = 0; coeffCntr < UB_LPC_GAIN_DIM; coeffCntr++) + { + lpcGains[coeffCntr] = exp(lpcGains[coeffCntr] + WebRtcIsac_kMeanLpcGain); + } + return 0; +} diff --git a/libs/miniwebrtc/audio/coding_isac/main/encode_lpc_swb.h b/libs/miniwebrtc/audio/coding_isac/main/encode_lpc_swb.h new file mode 100644 index 00000000..e7f1a76a --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/encode_lpc_swb.h @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * encode_lpc_swb.h + * + * This file contains declaration of functions used to + * encode LPC parameters (Shape & gain) of the upper band. + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_ + +#include "typedefs.h" +#include "settings.h" +#include "structs.h" + + +/****************************************************************************** + * WebRtcIsac_RemoveLarMean() + * + * Remove the means from LAR coefficients. + * + * Input: + * -lar : pointer to lar vectors. LAR vectors are + * concatenated. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -lar : pointer to mean-removed LAR:s. + * + * + */ +WebRtc_Word16 WebRtcIsac_RemoveLarMean( + double* lar, + WebRtc_Word16 bandwidth); + +/****************************************************************************** + * WebRtcIsac_DecorrelateIntraVec() + * + * Remove the correlation amonge the components of LAR vectors. If LAR vectors + * of one frame are put in a matrix where each column is a LAR vector of a + * sub-frame, then this is equivalent to multiplying the LAR matrix with + * a decorrelting mtrix from left. + * + * Input: + * -inLar : pointer to mean-removed LAR vecrtors. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -out : decorrelated LAR vectors. + */ +WebRtc_Word16 WebRtcIsac_DecorrelateIntraVec( + const double* inLAR, + double* out, + WebRtc_Word16 bandwidth); + + +/****************************************************************************** + * WebRtcIsac_DecorrelateInterVec() + * + * Remover the correlation among mean-removed LAR vectors. If LAR vectors + * of one frame are put in a matrix where each column is a LAR vector of a + * sub-frame, then this is equivalent to multiplying the LAR matrix with + * a decorrelting mtrix from right. + * + * Input: + * -data : pointer to matrix of LAR vectors. The matrix + * is stored column-wise. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -out : decorrelated LAR vectors. + */ +WebRtc_Word16 WebRtcIsac_DecorrelateInterVec( + const double* data, + double* out, + WebRtc_Word16 bandwidth); + + +/****************************************************************************** + * WebRtcIsac_QuantizeUncorrLar() + * + * Quantize the uncorrelated parameters. + * + * Input: + * -data : uncorrelated LAR vectors. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -data : quantized version of the input. + * -idx : pointer to quantization indices. + */ +double WebRtcIsac_QuantizeUncorrLar( + double* data, + int* idx, + WebRtc_Word16 bandwidth); + + +/****************************************************************************** + * WebRtcIsac_CorrelateIntraVec() + * + * This is the inverse of WebRtcIsac_DecorrelateIntraVec(). + * + * Input: + * -data : uncorrelated parameters. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -out : correlated parametrs. + */ +WebRtc_Word16 WebRtcIsac_CorrelateIntraVec( + const double* data, + double* out, + WebRtc_Word16 bandwidth); + + +/****************************************************************************** + * WebRtcIsac_CorrelateInterVec() + * + * This is the inverse of WebRtcIsac_DecorrelateInterVec(). + * + * Input: + * -data + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -out : correlated parametrs. + */ +WebRtc_Word16 WebRtcIsac_CorrelateInterVec( + const double* data, + double* out, + WebRtc_Word16 bandwidth); + + +/****************************************************************************** + * WebRtcIsac_AddLarMean() + * + * This is the inverse of WebRtcIsac_RemoveLarMean() + * + * Input: + * -data : pointer to mean-removed LAR:s. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -data : pointer to LARs. + */ +WebRtc_Word16 WebRtcIsac_AddLarMean( + double* data, + WebRtc_Word16 bandwidth); + + +/****************************************************************************** + * WebRtcIsac_DequantizeLpcParam() + * + * Get the quantized value of uncorrelated LARs given the quantization indices. + * + * Input: + * -idx : pointer to quantiztion indices. + * -bandwidth : indicates if the given LAR vectors belong + * to SWB-12kHz or SWB-16kHz. + * + * Output: + * -out : pointer to quantized values. + */ +WebRtc_Word16 WebRtcIsac_DequantizeLpcParam( + const int* idx, + double* out, + WebRtc_Word16 bandwidth); + + +/****************************************************************************** + * WebRtcIsac_ToLogDomainRemoveMean() + * + * Transform the LPC gain to log domain then remove the mean value. + * + * Input: + * -lpcGain : pointer to LPC Gain, expecting 6 LPC gains + * + * Output: + * -lpcGain : mean-removed in log domain. + */ +WebRtc_Word16 WebRtcIsac_ToLogDomainRemoveMean( + double* lpGains); + + +/****************************************************************************** + * WebRtcIsac_DecorrelateLPGain() + * + * Decorrelate LPC gains. There are 6 LPC Gains per frame. This is like + * multiplying gain vector with decorrelating matrix. + * + * Input: + * -data : LPC gain in log-domain with mean removed. + * + * Output: + * -out : decorrelated parameters. + */ +WebRtc_Word16 WebRtcIsac_DecorrelateLPGain( + const double* data, + double* out); + + +/****************************************************************************** + * WebRtcIsac_QuantizeLpcGain() + * + * Quantize the decorrelated log-domain gains. + * + * Input: + * -lpcGain : uncorrelated LPC gains. + * + * Output: + * -idx : quantization indices + * -lpcGain : quantized value of the inpt. + */ +double WebRtcIsac_QuantizeLpcGain( + double* lpGains, + int* idx); + + +/****************************************************************************** + * WebRtcIsac_DequantizeLpcGain() + * + * Get the quantized values given the quantization indices. + * + * Input: + * -idx : pointer to quantization indices. + * + * Output: + * -lpcGains : quantized values of the given parametes. + */ +WebRtc_Word16 WebRtcIsac_DequantizeLpcGain( + const int* idx, + double* lpGains); + + +/****************************************************************************** + * WebRtcIsac_CorrelateLpcGain() + * + * This is the inverse of WebRtcIsac_DecorrelateLPGain(). + * + * Input: + * -data : decorrelated parameters. + * + * Output: + * -out : correlated parameters. + */ +WebRtc_Word16 WebRtcIsac_CorrelateLpcGain( + const double* data, + double* out); + + +/****************************************************************************** + * WebRtcIsac_AddMeanToLinearDomain() + * + * This is the inverse of WebRtcIsac_ToLogDomainRemoveMean(). + * + * Input: + * -lpcGain : LPC gain in log-domain & mean removed + * + * Output: + * -lpcGain : LPC gain in normal domain. + */ +WebRtc_Word16 WebRtcIsac_AddMeanToLinearDomain( + double* lpcGains); + + +#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENCODE_LPC_SWB_H_ diff --git a/libs/miniwebrtc/audio/coding_isac/main/entropy_coding.c b/libs/miniwebrtc/audio/coding_isac/main/entropy_coding.c new file mode 100644 index 00000000..a7299447 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/entropy_coding.c @@ -0,0 +1,2748 @@ +/* + * 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 header file defines all of the functions used to arithmetically + * encode the iSAC bistream + * + */ + + +#include "entropy_coding.h" +#include "settings.h" +#include "arith_routines.h" +#include "signal_processing_library.h" +#include "spectrum_ar_model_tables.h" +#include "lpc_tables.h" +#include "pitch_gain_tables.h" +#include "pitch_lag_tables.h" +#include "encode_lpc_swb.h" +#include "lpc_shape_swb12_tables.h" +#include "lpc_shape_swb16_tables.h" +#include "lpc_gain_swb_tables.h" +#include "os_specific_inline.h" + +#include +#include + +static const WebRtc_UWord16 kLpcVecPerSegmentUb12 = 5; +static const WebRtc_UWord16 kLpcVecPerSegmentUb16 = 4; + +/* coefficients for the stepwise rate estimation */ +static const WebRtc_Word32 kRPointsQ10[100] = { + 14495, 14295, 14112, 13944, 13788, 13643, 13459, 13276, 13195, 13239, + 13243, 13191, 13133, 13216, 13263, 13330, 13316, 13242, 13191, 13106, + 12942, 12669, 12291, 11840, 11361, 10795, 10192, 9561, 8934, 8335, + 7750, 7161, 6589, 6062, 5570, 5048, 4548, 4069, 3587, 3143, + 2717, 2305, 1915, 1557, 1235, 963, 720, 541, 423, 366, + 369, 435, 561, 750, 1001, 1304, 1626, 1989, 2381, 2793, + 3219, 3656, 4134, 4612, 5106, 5629, 6122, 6644, 7216, 7801, + 8386, 8987, 9630, 10255, 10897, 11490, 11950, 12397, 12752, 12999, + 13175, 13258, 13323, 13290, 13296, 13335, 13113, 13255, 13347, 13355, + 13298, 13247, 13313, 13155, 13267, 13313, 13374, 13446, 13525, 13609}; + + +/* cdf array for encoder bandwidth (12 vs 16 kHz) indicator */ +static const WebRtc_UWord16 kOneBitEqualProbCdf[3] = { + 0, 32768, 65535 }; + +/* pointer to cdf array for encoder bandwidth (12 vs 16 kHz) indicator */ +static const WebRtc_UWord16 *kOneBitEqualProbCdf_ptr[1] = { + kOneBitEqualProbCdf }; + +/* initial cdf index for decoder of encoded bandwidth (12 vs 16 kHz) indicator */ +static const WebRtc_UWord16 kOneBitEqualProbInitIndex[1] = {1}; + + +/* coefficients for the stepwise rate estimation */ + + +static const WebRtc_Word32 acnQ10 = 426; +static const WebRtc_Word32 bcnQ10 = -581224; +static const WebRtc_Word32 ccnQ10 = 722631; +static const WebRtc_Word32 lbcnQ10 = -402874; +#define DPMIN_Q10 -10240 // -10.00 in Q10 +#define DPMAX_Q10 10240 // 10.00 in Q10 +#define MINBITS_Q10 10240 /* 10.0 in Q10 */ +#define IS_SWB_12KHZ 1 + +__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 kRPointsQ10[ind]; +} + + +__inline short log2_Q10_B( int x ) +{ + int zeros; + short frac; + + zeros = WebRtcSpl_NormU32( x ); + frac = ((unsigned int)(x << zeros) & 0x7FFFFFFF) >> 21; + return (short) (((31 - zeros) << 10) + frac); +} + + + +/* compute correlation from power spectrum */ +static void WebRtcIsac_FindCorrelation(WebRtc_Word32 *PSpecQ12, WebRtc_Word32 *CorrQ7) +{ + WebRtc_Word32 summ[FRAMESAMPLES/8]; + WebRtc_Word32 diff[FRAMESAMPLES/8]; + const WebRtc_Word16 *CS_ptrQ9; + WebRtc_Word32 sum; + int k, n; + + for (k = 0; k < FRAMESAMPLES/8; k++) { + summ[k] = (PSpecQ12[k] + PSpecQ12[FRAMESAMPLES_QUARTER-1 - k] + 16) >> 5; + diff[k] = (PSpecQ12[k] - PSpecQ12[FRAMESAMPLES_QUARTER-1 - k] + 16) >> 5; + } + + sum = 2; + for (n = 0; n < FRAMESAMPLES/8; n++) + sum += summ[n]; + CorrQ7[0] = sum; + + for (k = 0; k < AR_ORDER; k += 2) { + sum = 0; + CS_ptrQ9 = WebRtcIsac_kCos[k]; + for (n = 0; n < FRAMESAMPLES/8; n++) + sum += (CS_ptrQ9[n] * diff[n] + 256) >> 9; + CorrQ7[k+1] = sum; + } + + for (k=1; k> 9; + CorrQ7[k+1] = sum; + } +} + +/* compute inverse AR power spectrum */ +/* Changed to the function used in iSAC FIX for compatibility reasons */ +static void WebRtcIsac_FindInvArSpec(const WebRtc_Word16 *ARCoefQ12, + const WebRtc_Word32 gainQ10, + WebRtc_Word32 *CurveQ16) +{ + WebRtc_Word32 CorrQ11[AR_ORDER+1]; + WebRtc_Word32 sum, tmpGain; + WebRtc_Word32 diffQ16[FRAMESAMPLES/8]; + const WebRtc_Word16 *CS_ptrQ9; + int k, n; + WebRtc_Word16 round, shftVal = 0, sh; + + sum = 0; + for (n = 0; n < AR_ORDER+1; n++) + sum += WEBRTC_SPL_MUL(ARCoefQ12[n], ARCoefQ12[n]); /* Q24 */ + sum = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(WEBRTC_SPL_RSHIFT_W32(sum, 6), 65) + 32768, 16); /* 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) { + //CS_ptrQ9 = WebRtcIsac_kCos[k]; + for (n = 0; n < FRAMESAMPLES/8; n++) + CurveQ16[n] += WEBRTC_SPL_RSHIFT_W32( + WEBRTC_SPL_MUL(WebRtcIsac_kCos[k][n], CorrQ11[k+1]) + 2, 2); + } + + CS_ptrQ9 = WebRtcIsac_kCos[0]; + + /* If CorrQ11[1] too large we avoid getting overflow in the calculation by shifting */ + sh=WebRtcSpl_NormW32(CorrQ11[1]); + if (CorrQ11[1]==0) /* Use next correlation */ + sh=WebRtcSpl_NormW32(CorrQ11[2]); + + if (sh<9) + shftVal = 9 - sh; + else + shftVal = 0; + + for (n = 0; n < FRAMESAMPLES/8; n++) + diffQ16[n] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(CS_ptrQ9[n], WEBRTC_SPL_RSHIFT_W32(CorrQ11[1], shftVal)) + 2, 2); + for (k = 2; k < AR_ORDER; k += 2) { + CS_ptrQ9 = WebRtcIsac_kCos[k]; + for (n = 0; n < FRAMESAMPLES/8; n++) + diffQ16[n] += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(CS_ptrQ9[n], WEBRTC_SPL_RSHIFT_W32(CorrQ11[k+1], shftVal)) + 2, 2); + } + + for (k=0; k>25); // * 128/4294967295 + + /* new random unsigned int */ + seed = (seed * 196314165) + 907633515; + + /* fixed-point dither sample between -64 and 64 */ + dither2_Q7 = (WebRtc_Word16)(((int)seed + 16777216)>>25); + + shft = (seed >> 25) & 15; + if (shft < 5) + { + bufQ7[k] = dither1_Q7; + bufQ7[k+1] = dither2_Q7; + bufQ7[k+2] = 0; + } + else if (shft < 10) + { + bufQ7[k] = dither1_Q7; + bufQ7[k+1] = 0; + bufQ7[k+2] = dither2_Q7; + } + else + { + bufQ7[k] = 0; + bufQ7[k+1] = dither1_Q7; + bufQ7[k+2] = dither2_Q7; + } + } + } + else + { + dither_gain_Q14 = (WebRtc_Word16)(22528 - 10 * AvgPitchGain_Q12); + + /* dither on half of the coefficients */ + for (k = 0; k < length-1; k += 2) + { + /* new random unsigned int */ + seed = (seed * 196314165) + 907633515; + + /* fixed-point dither sample between -64 and 64 */ + dither1_Q7 = (WebRtc_Word16)(((int)seed + 16777216)>>25); + + /* dither sample is placed in either even or odd index */ + shft = (seed >> 25) & 1; /* either 0 or 1 */ + + bufQ7[k + shft] = (((dither_gain_Q14 * dither1_Q7) + 8192)>>14); + bufQ7[k + 1 - shft] = 0; + } + } +} + + + +/****************************************************************************** + * GenerateDitherQ7LbUB() + * + * generate array of dither samples in Q7 There are less zeros in dither + * vector compared to GenerateDitherQ7Lb. + * + * A uniform random number generator with the range of [-64 64] is employed + * but the generated dithers are scaled by 0.35, a heuristic scaling. + * + * Input: + * -seed : the initial seed for the random number generator. + * -length : the number of dither values to be generated. + * + * Output: + * -bufQ7 : pointer to a buffer where dithers are written to. + */ +static void GenerateDitherQ7LbUB( + WebRtc_Word16 *bufQ7, + WebRtc_UWord32 seed, + int length) +{ + int k; + for (k = 0; k < length; k++) { + /* new random unsigned int */ + seed = (seed * 196314165) + 907633515; + + /* fixed-point dither sample between -64 and 64 (Q7) */ + // * 128/4294967295 + bufQ7[k] = (WebRtc_Word16)(((int)seed + 16777216)>>25); + + // scale by 0.35 + bufQ7[k] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(bufQ7[k], + 2048, 13); + } +} + + + +/* + * function to decode the complex spectrum from the bit stream + * returns the total number of bytes in the stream + */ +int WebRtcIsac_DecodeSpecLb(Bitstr *streamdata, + double *fr, + double *fi, + WebRtc_Word16 AvgPitchGain_Q12) +{ + WebRtc_Word16 DitherQ7[FRAMESAMPLES]; + WebRtc_Word16 data[FRAMESAMPLES]; + WebRtc_Word32 invARSpec2_Q16[FRAMESAMPLES_QUARTER]; + WebRtc_UWord16 invARSpecQ8[FRAMESAMPLES_QUARTER]; + WebRtc_Word16 ARCoefQ12[AR_ORDER+1]; + WebRtc_Word16 RCQ15[AR_ORDER]; + WebRtc_Word16 gainQ10; + WebRtc_Word32 gain2_Q10, res; + WebRtc_Word32 in_sqrt; + WebRtc_Word32 newRes; + int k, len, i; + + /* create dither signal */ + GenerateDitherQ7Lb(DitherQ7, streamdata->W_upper, FRAMESAMPLES, AvgPitchGain_Q12); + + /* decode model parameters */ + if (WebRtcIsac_DecodeRc(streamdata, RCQ15) < 0) + return -ISAC_RANGE_ERROR_DECODE_SPECTRUM; + + WebRtcSpl_ReflCoefToLpc(RCQ15, AR_ORDER, ARCoefQ12); + + if (WebRtcIsac_DecodeGain2(streamdata, &gain2_Q10) < 0) + return -ISAC_RANGE_ERROR_DECODE_SPECTRUM; + + /* compute inverse AR power spectrum */ + WebRtcIsac_FindInvArSpec(ARCoefQ12, gain2_Q10, invARSpec2_Q16); + + /* convert to magnitude spectrum, by doing square-roots (modified from SPLIB) */ + res = 1 << (WebRtcSpl_GetSizeInBits(invARSpec2_Q16[0]) >> 1); + for (k = 0; k < FRAMESAMPLES_QUARTER; k++) + { + in_sqrt = invARSpec2_Q16[k]; + i = 10; + + /* Negative values make no sense for a real sqrt-function. */ + if (in_sqrt<0) + in_sqrt=-in_sqrt; + + newRes = (in_sqrt / res + res) >> 1; + do + { + res = newRes; + newRes = (in_sqrt / res + res) >> 1; + } while (newRes != res && i-- > 0); + + invARSpecQ8[k] = (WebRtc_Word16)newRes; + } + + /* arithmetic decoding of spectrum */ + if ((len = WebRtcIsac_DecLogisticMulti2(data, streamdata, invARSpecQ8, DitherQ7, + FRAMESAMPLES, !IS_SWB_12KHZ)) <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(30 << 10, + (WebRtc_Word16)((invARSpec2_Q16[k>>2] + (32768 + (33 << 16))) >> 16)); + *fr++ = (double)((data[ k ] * gainQ10 + 512) >> 10) / 128.0; + *fi++ = (double)((data[k+1] * gainQ10 + 512) >> 10) / 128.0; + *fr++ = (double)((data[k+2] * gainQ10 + 512) >> 10) / 128.0; + *fi++ = (double)((data[k+3] * gainQ10 + 512) >> 10) / 128.0; + } + } + else + { + for (k = 0; k < FRAMESAMPLES; k += 4) + { + gainQ10 = WebRtcSpl_DivW32W16ResW16(36 << 10, + (WebRtc_Word16)((invARSpec2_Q16[k>>2] + (32768 + (40 << 16))) >> 16)); + *fr++ = (double)((data[ k ] * gainQ10 + 512) >> 10) / 128.0; + *fi++ = (double)((data[k+1] * gainQ10 + 512) >> 10) / 128.0; + *fr++ = (double)((data[k+2] * gainQ10 + 512) >> 10) / 128.0; + *fi++ = (double)((data[k+3] * gainQ10 + 512) >> 10) / 128.0; + } + } + + return len; +} + +/****************************************************************************** + * WebRtcIsac_DecodeSpecUB16() + * Decode real and imaginary part of the DFT coefficients, given a bit-stream. + * This function is called when the codec is in 0-16 kHz bandwidth. + * The decoded DFT coefficient can be transformed to time domain by + * WebRtcIsac_Time2Spec(). + * + * Input: + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * + * Output: + * -*fr : pointer to a buffer where the real part of DFT + * coefficients are written to. + * -*fi : pointer to a buffer where the imaginary part + * of DFT coefficients are written to. + * + * Return value : < 0 if an error occures + * 0 if succeeded. + */ +int WebRtcIsac_DecodeSpecUB16( + Bitstr* streamdata, + double* fr, + double* fi) +{ + WebRtc_Word16 DitherQ7[FRAMESAMPLES]; + WebRtc_Word16 data[FRAMESAMPLES]; + WebRtc_Word32 invARSpec2_Q16[FRAMESAMPLES_QUARTER]; + WebRtc_UWord16 invARSpecQ8[FRAMESAMPLES_QUARTER]; + WebRtc_Word16 ARCoefQ12[AR_ORDER+1]; + WebRtc_Word16 RCQ15[AR_ORDER]; + WebRtc_Word32 gain2_Q10, res; + WebRtc_Word32 in_sqrt; + WebRtc_Word32 newRes; + int k, len, i, j; + + /* create dither signal */ + GenerateDitherQ7LbUB(DitherQ7, streamdata->W_upper, FRAMESAMPLES); + + /* decode model parameters */ + if (WebRtcIsac_DecodeRc(streamdata, RCQ15) < 0) + return -ISAC_RANGE_ERROR_DECODE_SPECTRUM; + + WebRtcSpl_ReflCoefToLpc(RCQ15, AR_ORDER, ARCoefQ12); + + if (WebRtcIsac_DecodeGain2(streamdata, &gain2_Q10) < 0) + return -ISAC_RANGE_ERROR_DECODE_SPECTRUM; + + /* compute inverse AR power spectrum */ + WebRtcIsac_FindInvArSpec(ARCoefQ12, gain2_Q10, invARSpec2_Q16); + + /* convert to magnitude spectrum, by doing square-roots (modified from SPLIB) */ + res = 1 << (WebRtcSpl_GetSizeInBits(invARSpec2_Q16[0]) >> 1); + for (k = 0; k < FRAMESAMPLES_QUARTER; k++) + { + in_sqrt = invARSpec2_Q16[k]; + i = 10; + + /* Negative values make no sense for a real sqrt-function. */ + if (in_sqrt<0) + in_sqrt=-in_sqrt; + + newRes = (in_sqrt / res + res) >> 1; + do + { + res = newRes; + newRes = (in_sqrt / res + res) >> 1; + } while (newRes != res && i-- > 0); + + invARSpecQ8[k] = (WebRtc_Word16)newRes; + } + + /* arithmetic decoding of spectrum */ + if ((len = WebRtcIsac_DecLogisticMulti2(data, streamdata, invARSpecQ8, + DitherQ7, FRAMESAMPLES, !IS_SWB_12KHZ)) <1) + return -ISAC_RANGE_ERROR_DECODE_SPECTRUM; + + /* re-arrange DFT coefficients and scale down */ + for (j = 0, k = 0; k < FRAMESAMPLES; k += 4, j++) + { + fr[j] = (double)data[ k ] / 128.0; + fi[j] = (double)data[k+1] / 128.0; + fr[(FRAMESAMPLES_HALF) - 1 - j] = (double)data[k+2] / 128.0; + fi[(FRAMESAMPLES_HALF) - 1 - j] = (double)data[k+3] / 128.0; + + } + return len; +} + + + + +/****************************************************************************** + * WebRtcIsac_DecodeSpecUB12() + * Decode real and imaginary part of the DFT coefficients, given a bit-stream. + * This function is called when the codec is in 0-12 kHz bandwidth. + * The decoded DFT coefficient can be transformed to time domain by + * WebRtcIsac_Time2Spec(). + * + * Input: + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * + * Output: + * -*fr : pointer to a buffer where the real part of DFT + * coefficients are written to. + * -*fi : pointer to a buffer where the imaginary part + * of DFT coefficients are written to. + * + * Return value : < 0 if an error occures + * 0 if succeeded. + */ +int WebRtcIsac_DecodeSpecUB12( + Bitstr *streamdata, + double *fr, + double *fi) +{ + WebRtc_Word16 DitherQ7[FRAMESAMPLES]; + WebRtc_Word16 data[FRAMESAMPLES]; + WebRtc_Word32 invARSpec2_Q16[FRAMESAMPLES_QUARTER]; + WebRtc_UWord16 invARSpecQ8[FRAMESAMPLES_QUARTER]; + WebRtc_Word16 ARCoefQ12[AR_ORDER+1]; + WebRtc_Word16 RCQ15[AR_ORDER]; + WebRtc_Word32 gain2_Q10; + WebRtc_Word32 res; + WebRtc_Word32 in_sqrt; + WebRtc_Word32 newRes; + int k, len, i; + + /* create dither signal */ + GenerateDitherQ7LbUB(DitherQ7, streamdata->W_upper, FRAMESAMPLES); + + /* decode model parameters */ + if (WebRtcIsac_DecodeRc(streamdata, RCQ15) < 0) + return -ISAC_RANGE_ERROR_DECODE_SPECTRUM; + + WebRtcSpl_ReflCoefToLpc(RCQ15, AR_ORDER, ARCoefQ12); + + if (WebRtcIsac_DecodeGain2(streamdata, &gain2_Q10) < 0) + return -ISAC_RANGE_ERROR_DECODE_SPECTRUM; + + + /* compute inverse AR power spectrum */ + WebRtcIsac_FindInvArSpec(ARCoefQ12, gain2_Q10, invARSpec2_Q16); + + /* convert to magnitude spectrum, by doing square-roots (modified from SPLIB) */ + res = 1 << (WebRtcSpl_GetSizeInBits(invARSpec2_Q16[0]) >> 1); + for (k = 0; k < FRAMESAMPLES_QUARTER; k++) + { + in_sqrt = invARSpec2_Q16[k]; + i = 10; + + /* Negative values make no sense for a real sqrt-function. */ + if (in_sqrt<0) + in_sqrt=-in_sqrt; + + newRes = (in_sqrt / res + res) >> 1; + do + { + res = newRes; + newRes = (in_sqrt / res + res) >> 1; + } while (newRes != res && i-- > 0); + + invARSpecQ8[k] = (WebRtc_Word16)newRes; + } + + /* arithmetic decoding of spectrum */ + if ((len = WebRtcIsac_DecLogisticMulti2(data, streamdata, + invARSpecQ8, DitherQ7, (FRAMESAMPLES_HALF), IS_SWB_12KHZ)) < 1) + { + return -ISAC_RANGE_ERROR_DECODE_SPECTRUM; + } + + for (k = 0, i = 0; k < FRAMESAMPLES_HALF; k += 4) + { + fr[i] = (double)data[ k ] / 128.0; + fi[i] = (double)data[k+1] / 128.0; + i++; + fr[i] = (double)data[k+2] / 128.0; + fi[i] = (double)data[k+3] / 128.0; + i++; + } + + // The second half of real and imaginary coefficients is zero. This is + // due to using the old FFT module which requires two signals as input + // while in 0-12 kHz mode we only have 8-12 kHz band, and the second signal + // is set to zero + memset(&fr[FRAMESAMPLES_QUARTER], 0, FRAMESAMPLES_QUARTER * sizeof(double)); + memset(&fi[FRAMESAMPLES_QUARTER], 0, FRAMESAMPLES_QUARTER * sizeof(double)); + + return len; +} + + + + + +int WebRtcIsac_EncodeSpecLb(const WebRtc_Word16 *fr, + const WebRtc_Word16 *fi, + Bitstr *streamdata, + WebRtc_Word16 AvgPitchGain_Q12) +{ + WebRtc_Word16 ditherQ7[FRAMESAMPLES]; + WebRtc_Word16 dataQ7[FRAMESAMPLES]; + WebRtc_Word32 PSpec[FRAMESAMPLES_QUARTER]; + WebRtc_Word32 invARSpec2_Q16[FRAMESAMPLES_QUARTER]; + WebRtc_UWord16 invARSpecQ8[FRAMESAMPLES_QUARTER]; + WebRtc_Word32 CorrQ7[AR_ORDER+1]; + WebRtc_Word32 CorrQ7_norm[AR_ORDER+1]; + WebRtc_Word16 RCQ15[AR_ORDER]; + WebRtc_Word16 ARCoefQ12[AR_ORDER+1]; + WebRtc_Word32 gain2_Q10; + WebRtc_Word16 val; + WebRtc_Word32 nrg, res; + WebRtc_UWord32 sum; + WebRtc_Word32 in_sqrt; + WebRtc_Word32 newRes; + WebRtc_Word16 err; + WebRtc_UWord32 nrg_u32; + int shift_var; + int k, n, j, i; + + + /* create dither_float signal */ + GenerateDitherQ7Lb(ditherQ7, streamdata->W_upper, FRAMESAMPLES, AvgPitchGain_Q12); + + /* add dither and quantize, and compute power spectrum */ + for (k = 0; k < FRAMESAMPLES; k += 4) + { + val = ((*fr++ + ditherQ7[k] + 64) & 0xFF80) - ditherQ7[k]; + dataQ7[k] = val; + sum = val * val; + + val = ((*fi++ + ditherQ7[k+1] + 64) & 0xFF80) - ditherQ7[k+1]; + dataQ7[k+1] = val; + sum += val * val; + + val = ((*fr++ + ditherQ7[k+2] + 64) & 0xFF80) - ditherQ7[k+2]; + dataQ7[k+2] = val; + sum += val * val; + + val = ((*fi++ + ditherQ7[k+3] + 64) & 0xFF80) - ditherQ7[k+3]; + dataQ7[k+3] = val; + sum += val * val; + + PSpec[k>>2] = sum >> 2; + } + + /* compute correlation from power spectrum */ + WebRtcIsac_FindCorrelation(PSpec, CorrQ7); + + + /* find AR coefficients */ + /* number of bit shifts to 14-bit normalize CorrQ7[0] (leaving room for sign) */ + shift_var = WebRtcSpl_NormW32(CorrQ7[0]) - 18; + + if (shift_var > 0) { + for (k=0; k> (-shift_var); + } + } + + /* find RC coefficients */ + WebRtcSpl_AutoCorrToReflCoef(CorrQ7_norm, AR_ORDER, RCQ15); + + /* quantize & code RC Coefficient */ + WebRtcIsac_EncodeRc(RCQ15, streamdata); + + /* RC -> AR coefficients */ + WebRtcSpl_ReflCoefToLpc(RCQ15, AR_ORDER, ARCoefQ12); + + /* compute ARCoef' * Corr * ARCoef in Q19 */ + nrg = 0; + for (j = 0; j <= AR_ORDER; j++) { + for (n = 0; n <= j; n++) { + nrg += ( ARCoefQ12[j] * ((CorrQ7_norm[j-n] * ARCoefQ12[n] + 256) >> 9) + 4 ) >> 3; + } + for (n = j+1; n <= AR_ORDER; n++) { + nrg += ( ARCoefQ12[j] * ((CorrQ7_norm[n-j] * ARCoefQ12[n] + 256) >> 9) + 4 ) >> 3; + } + } + + nrg_u32 = (WebRtc_UWord32)nrg; + if (shift_var > 0) { + nrg_u32 = nrg_u32 >> shift_var; + } else { + nrg_u32 = nrg_u32 << (-shift_var); + } + + if (nrg_u32 > 0x7FFFFFFF) + nrg = 0x7FFFFFFF; + else + nrg = (WebRtc_Word32)nrg_u32; + + gain2_Q10 = WebRtcSpl_DivResultInQ31(FRAMESAMPLES_QUARTER, nrg); /* also shifts 31 bits to the left! */ + + /* quantize & code gain2_Q10 */ + if (WebRtcIsac_EncodeGain2(&gain2_Q10, streamdata)) { + return -1; + } + + /* compute inverse AR power spectrum */ + WebRtcIsac_FindInvArSpec(ARCoefQ12, gain2_Q10, invARSpec2_Q16); + + /* convert to magnitude spectrum, by doing square-roots (modified from SPLIB) */ + res = 1 << (WebRtcSpl_GetSizeInBits(invARSpec2_Q16[0]) >> 1); + for (k = 0; k < FRAMESAMPLES_QUARTER; k++) + { + in_sqrt = invARSpec2_Q16[k]; + i = 10; + + /* Negative values make no sense for a real sqrt-function. */ + if (in_sqrt<0) + in_sqrt=-in_sqrt; + + newRes = (in_sqrt / res + res) >> 1; + do + { + res = newRes; + newRes = (in_sqrt / res + res) >> 1; + } while (newRes != res && i-- > 0); + + invARSpecQ8[k] = (WebRtc_Word16)newRes; + } + + /* arithmetic coding of spectrum */ + err = WebRtcIsac_EncLogisticMulti2(streamdata, dataQ7, invARSpecQ8, + FRAMESAMPLES, !IS_SWB_12KHZ); + if (err < 0) + { + return (err); + } + + return 0; +} + + +/****************************************************************************** + * WebRtcIsac_EncodeSpecUB16() + * Quantize and encode real and imaginary part of the DFT coefficients. + * This function is called when the codec is in 0-16 kHz bandwidth. + * The real and imaginary part are computed by calling WebRtcIsac_Time2Spec(). + * + * + * Input: + * -*fr : pointer to a buffer where the real part of DFT + * coefficients are stored. + * -*fi : pointer to a buffer where the imaginary part + * of DFT coefficients are stored. + * + * Output: + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * + * Return value : < 0 if an error occures + * 0 if succeeded. + */ +int WebRtcIsac_EncodeSpecUB16( + const WebRtc_Word16* fr, + const WebRtc_Word16* fi, + Bitstr* streamdata) +{ + WebRtc_Word16 ditherQ7[FRAMESAMPLES]; + WebRtc_Word16 dataQ7[FRAMESAMPLES]; + WebRtc_Word32 PSpec[FRAMESAMPLES_QUARTER]; + WebRtc_Word32 invARSpec2_Q16[FRAMESAMPLES_QUARTER]; + WebRtc_UWord16 invARSpecQ8[FRAMESAMPLES_QUARTER]; + WebRtc_Word32 CorrQ7[AR_ORDER+1]; + WebRtc_Word32 CorrQ7_norm[AR_ORDER+1]; + WebRtc_Word16 RCQ15[AR_ORDER]; + WebRtc_Word16 ARCoefQ12[AR_ORDER+1]; + WebRtc_Word32 gain2_Q10; + WebRtc_Word16 val; + WebRtc_Word32 nrg, res; + WebRtc_UWord32 sum; + WebRtc_Word32 in_sqrt; + WebRtc_Word32 newRes; + WebRtc_Word16 err; + WebRtc_UWord32 nrg_u32; + int shift_var; + int k, n, j, i; + + /* create dither_float signal */ + GenerateDitherQ7LbUB(ditherQ7, streamdata->W_upper, FRAMESAMPLES); + + /* add dither and quantize, and compute power spectrum */ + for (j = 0, k = 0; k < FRAMESAMPLES; k += 4, j++) + { + val = ((fr[j] + ditherQ7[k] + 64) & 0xFF80) - ditherQ7[k]; + dataQ7[k] = val; + sum = val * val; + + val = ((fi[j] + ditherQ7[k+1] + 64) & 0xFF80) - ditherQ7[k+1]; + dataQ7[k+1] = val; + sum += val * val; + + val = ((fr[(FRAMESAMPLES_HALF) - 1 - j] + ditherQ7[k+2] + 64) & + 0xFF80) - ditherQ7[k+2]; + dataQ7[k+2] = val; + sum += val * val; + + val = ((fi[(FRAMESAMPLES_HALF) - 1 - j] + ditherQ7[k+3] + 64) & + 0xFF80) - ditherQ7[k+3]; + dataQ7[k+3] = val; + sum += val * val; + + PSpec[k>>2] = sum >> 2; + } + + /* compute correlation from power spectrum */ + WebRtcIsac_FindCorrelation(PSpec, CorrQ7); + + + /* find AR coefficients + number of bit shifts to 14-bit normalize CorrQ7[0] + (leaving room for sign) */ + shift_var = WebRtcSpl_NormW32(CorrQ7[0]) - 18; + + if (shift_var > 0) { + for (k=0; k> (-shift_var); + } + } + + /* find RC coefficients */ + WebRtcSpl_AutoCorrToReflCoef(CorrQ7_norm, AR_ORDER, RCQ15); + + /* quantize & code RC Coef */ + WebRtcIsac_EncodeRc(RCQ15, streamdata); + + /* RC -> AR coefficients */ + WebRtcSpl_ReflCoefToLpc(RCQ15, AR_ORDER, ARCoefQ12); + + /* compute ARCoef' * Corr * ARCoef in Q19 */ + nrg = 0; + for (j = 0; j <= AR_ORDER; j++) { + for (n = 0; n <= j; n++) { + nrg += ( ARCoefQ12[j] * ((CorrQ7_norm[j-n] * ARCoefQ12[n] + + 256) >> 9) + 4 ) >> 3; + } + for (n = j+1; n <= AR_ORDER; n++) { + nrg += ( ARCoefQ12[j] * ((CorrQ7_norm[n-j] * ARCoefQ12[n] + + 256) >> 9) + 4 ) >> 3; + } + } + nrg_u32 = (WebRtc_UWord32)nrg; + if (shift_var > 0) { + nrg_u32 = nrg_u32 >> shift_var; + } else { + nrg_u32 = nrg_u32 << (-shift_var); + } + + if (nrg_u32 > 0x7FFFFFFF) + nrg = 0x7FFFFFFF; + else + nrg = (WebRtc_Word32)nrg_u32; + + gain2_Q10 = WebRtcSpl_DivResultInQ31(FRAMESAMPLES_QUARTER, nrg); /* also shifts 31 bits to the left! */ + + /* quantize & code gain2_Q10 */ + if (WebRtcIsac_EncodeGain2(&gain2_Q10, streamdata)) { + return -1; + } + + /* compute inverse AR power spectrum */ + WebRtcIsac_FindInvArSpec(ARCoefQ12, gain2_Q10, invARSpec2_Q16); + + /* convert to magnitude spectrum, by doing square-roots (modified from SPLIB) */ + res = 1 << (WebRtcSpl_GetSizeInBits(invARSpec2_Q16[0]) >> 1); + for (k = 0; k < FRAMESAMPLES_QUARTER; k++) + { + in_sqrt = invARSpec2_Q16[k]; + i = 10; + + /* Negative values make no sense for a real sqrt-function. */ + if (in_sqrt<0) + in_sqrt=-in_sqrt; + + newRes = (in_sqrt / res + res) >> 1; + do + { + res = newRes; + newRes = (in_sqrt / res + res) >> 1; + } while (newRes != res && i-- > 0); + + invARSpecQ8[k] = (WebRtc_Word16)newRes; + } + + /* arithmetic coding of spectrum */ + err = WebRtcIsac_EncLogisticMulti2(streamdata, dataQ7, invARSpecQ8, + FRAMESAMPLES, !IS_SWB_12KHZ); + if (err < 0) + { + return (err); + } + + return 0; +} + + + + +int WebRtcIsac_EncodeSpecUB12(const WebRtc_Word16 *fr, + const WebRtc_Word16 *fi, + Bitstr *streamdata) +{ + WebRtc_Word16 ditherQ7[FRAMESAMPLES]; + WebRtc_Word16 dataQ7[FRAMESAMPLES]; + WebRtc_Word32 PSpec[FRAMESAMPLES_QUARTER]; + WebRtc_Word32 invARSpec2_Q16[FRAMESAMPLES_QUARTER]; + WebRtc_UWord16 invARSpecQ8[FRAMESAMPLES_QUARTER]; + WebRtc_Word32 CorrQ7[AR_ORDER+1]; + WebRtc_Word32 CorrQ7_norm[AR_ORDER+1]; + WebRtc_Word16 RCQ15[AR_ORDER]; + WebRtc_Word16 ARCoefQ12[AR_ORDER+1]; + WebRtc_Word32 gain2_Q10; + WebRtc_Word16 val; + WebRtc_Word32 nrg, res; + WebRtc_UWord32 sum; + WebRtc_Word32 in_sqrt; + WebRtc_Word32 newRes; + WebRtc_Word16 err; + int shift_var; + int k, n, j, i; + WebRtc_UWord32 nrg_u32; + + /* create dither_float signal */ + GenerateDitherQ7LbUB(ditherQ7, streamdata->W_upper, FRAMESAMPLES); + + /* add dither and quantize, and compute power spectrum */ + for (k = 0, j = 0; k < (FRAMESAMPLES_HALF); k += 4) + { + val = ((*fr++ + ditherQ7[k] + 64) & 0xFF80) - ditherQ7[k]; + dataQ7[k] = val; + sum = (val) * (val); + + val = ((*fi++ + ditherQ7[k+1] + 64) & 0xFF80) - ditherQ7[k+1]; + dataQ7[k+1] = val; + sum += (val) * (val); + + if(j < FRAMESAMPLES_QUARTER) + { + PSpec[j] = sum >> 1; + j++; + } + + val = ((*fr++ + ditherQ7[k+2] + 64) & 0xFF80) - ditherQ7[k+2]; + dataQ7[k+2] = val; + sum = (val) * (val); + + val = ((*fi++ + ditherQ7[k+3] + 64) & 0xFF80) - ditherQ7[k+3]; + dataQ7[k+3] = val; + sum += (val) * (val); + + if(j < FRAMESAMPLES_QUARTER) + { + PSpec[j] = sum >> 1; + j++; + } + } + /* compute correlation from power spectrum */ + WebRtcIsac_FindCorrelation(PSpec, CorrQ7); + + + /* find AR coefficients */ + /* number of bit shifts to 14-bit normalize CorrQ7[0] (leaving room for sign) */ + shift_var = WebRtcSpl_NormW32(CorrQ7[0]) - 18; + + if (shift_var > 0) { + for (k=0; k> (-shift_var); + } + } + + /* find RC coefficients */ + WebRtcSpl_AutoCorrToReflCoef(CorrQ7_norm, AR_ORDER, RCQ15); + + /* quantize & code RC Coef */ + WebRtcIsac_EncodeRc(RCQ15, streamdata); + + + /* RC -> AR coefficients */ + WebRtcSpl_ReflCoefToLpc(RCQ15, AR_ORDER, ARCoefQ12); + + + /* compute ARCoef' * Corr * ARCoef in Q19 */ + nrg = 0; + for (j = 0; j <= AR_ORDER; j++) { + for (n = 0; n <= j; n++) { + nrg += ( ARCoefQ12[j] * ((CorrQ7_norm[j-n] * ARCoefQ12[n] + 256) >> 9) + 4 ) >> 3; + } + for (n = j+1; n <= AR_ORDER; n++) { + nrg += ( ARCoefQ12[j] * ((CorrQ7_norm[n-j] * ARCoefQ12[n] + 256) >> 9) + 4 ) >> 3; + } + } + + nrg_u32 = (WebRtc_UWord32)nrg; + if (shift_var > 0) { + nrg_u32 = nrg_u32 >> shift_var; + } else { + nrg_u32 = nrg_u32 << (-shift_var); + } + + if (nrg_u32 > 0x7FFFFFFF) { + nrg = 0x7FFFFFFF; + } else { + nrg = (WebRtc_Word32)nrg_u32; + } + + gain2_Q10 = WebRtcSpl_DivResultInQ31(FRAMESAMPLES_QUARTER, nrg); /* also shifts 31 bits to the left! */ + + /* quantize & code gain2_Q10 */ + if (WebRtcIsac_EncodeGain2(&gain2_Q10, streamdata)) { + return -1; + } + + /* compute inverse AR power spectrum */ + WebRtcIsac_FindInvArSpec(ARCoefQ12, gain2_Q10, invARSpec2_Q16); + + /* convert to magnitude spectrum, by doing square-roots (modified from SPLIB) */ + res = 1 << (WebRtcSpl_GetSizeInBits(invARSpec2_Q16[0]) >> 1); + for (k = 0; k < FRAMESAMPLES_QUARTER; k++) + { + in_sqrt = invARSpec2_Q16[k]; + i = 10; + + /* Negative values make no sense for a real sqrt-function. */ + if (in_sqrt<0) + in_sqrt=-in_sqrt; + + newRes = (in_sqrt / res + res) >> 1; + do + { + res = newRes; + newRes = (in_sqrt / res + res) >> 1; + } while (newRes != res && i-- > 0); + + invARSpecQ8[k] = (WebRtc_Word16)newRes; + } + + /* arithmetic coding of spectrum */ + err = WebRtcIsac_EncLogisticMulti2(streamdata, dataQ7, invARSpecQ8, + (FRAMESAMPLES_HALF), IS_SWB_12KHZ); + if (err < 0) + { + return (err); + } + + return 0; +} + + + +/* step-up */ +void WebRtcIsac_Rc2Poly(double *RC, int N, double *a) +{ + int m, k; + double tmp[MAX_AR_MODEL_ORDER]; + + a[0] = 1.0; + tmp[0] = 1.0; + for (m=1; m<=N; m++) { + /* copy */ + for (k=1; k0; m--) { + tmp_inv = 1.0 / (1.0 - RC[m]*RC[m]); + for (k=1; k<=m; k++) + tmp[k] = (a[k] - RC[m] * a[m-k+1]) * tmp_inv; + + for (k=1; k WebRtcIsac_kQKltMaxIndGain[k]) + index_g[k] = WebRtcIsac_kQKltMaxIndGain[k]; + index_ovr_g[k] = WebRtcIsac_kQKltOffsetGain[bmodel][k]+index_g[k]; + pos = WebRtcIsac_kQKltOfLevelsGain[bmodel] + index_ovr_g[k]; + + /* determine number of bits */ + sum = WebRtcIsac_kQKltCodeLenGain[pos]; + Bits += sum; + } + + for (k=0; k WebRtcIsac_kQKltMaxIndShape[k]) + index_s[k] = WebRtcIsac_kQKltMaxIndShape[k]; + index_ovr_s[k] = WebRtcIsac_kQKltOffsetShape[bmodel][k]+index_s[k]; + pos = WebRtcIsac_kQKltOfLevelsShape[bmodel] + index_ovr_s[k]; + sum = WebRtcIsac_kQKltCodeLenShape[pos]; + Bits += sum; + } + + + /* Only one model remains in this version of the code, model = 0 */ + *model=bmodel; + *size=Bits; + + /* entropy coding of model number */ + WebRtcIsac_EncHistMulti(streamdata, model, WebRtcIsac_kQKltModelCdfPtr, 1); + + /* entropy coding of quantization indices - shape only */ + WebRtcIsac_EncHistMulti(streamdata, index_s, WebRtcIsac_kQKltCdfPtrShape[bmodel], KLT_ORDER_SHAPE); + + /* Save data for creation of multiple bit streams */ + encData->LPCmodel[encData->startIdx] = 0; + for (k=0; kLPCindex_s[KLT_ORDER_SHAPE*encData->startIdx + k] = index_s[k]; + } + + /* find quantization levels for shape coefficients */ + for (k=0; kLPCcoeffs_lo[(ORDERLO+1)*SUBFRAMES*encData->startIdx + k] = LPCCoef_lo[k]; + } + for (k=0; k<(ORDERHI+1)*SUBFRAMES; k++) { + encData->LPCcoeffs_hi[(ORDERHI+1)*SUBFRAMES*encData->startIdx + k] = LPCCoef_hi[k]; + } +} + + +WebRtc_Word16 +WebRtcIsac_EncodeLpcUB( + double* lpcVecs, + Bitstr* streamdata, + double* interpolLPCCoeff, + WebRtc_Word16 bandwidth, + ISACUBSaveEncDataStruct* encData) +{ + + double U[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME]; + int idx[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME]; + int interpolCntr; + + WebRtcIsac_Poly2LarUB(lpcVecs, bandwidth); + WebRtcIsac_RemoveLarMean(lpcVecs, bandwidth); + WebRtcIsac_DecorrelateIntraVec(lpcVecs, U, bandwidth); + WebRtcIsac_DecorrelateInterVec(U, lpcVecs, bandwidth); + WebRtcIsac_QuantizeUncorrLar(lpcVecs, idx, bandwidth); + + WebRtcIsac_CorrelateInterVec(lpcVecs, U, bandwidth); + WebRtcIsac_CorrelateIntraVec(U, lpcVecs, bandwidth); + WebRtcIsac_AddLarMean(lpcVecs, bandwidth); + + switch(bandwidth) + { + case isac12kHz: + { + // Stor the indices to be used for multiple encoding. + memcpy(encData->indexLPCShape, idx, UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME * + sizeof(int)); + WebRtcIsac_EncHistMulti(streamdata, idx, WebRtcIsac_kLpcShapeCdfMatUb12, + UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME); + for(interpolCntr = 0; interpolCntr < UB_INTERPOL_SEGMENTS; interpolCntr++) + { + WebRtcIsac_Lar2PolyInterpolUB(lpcVecs, + interpolLPCCoeff, kLpcVecPerSegmentUb12 + 1); + lpcVecs += UB_LPC_ORDER; + interpolLPCCoeff += (kLpcVecPerSegmentUb12 * (UB_LPC_ORDER + 1)); + } + break; + } + case isac16kHz: + { + // Stor the indices to be used for multiple encoding. + memcpy(encData->indexLPCShape, idx, UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME * + sizeof(int)); + WebRtcIsac_EncHistMulti(streamdata, idx, WebRtcIsac_kLpcShapeCdfMatUb16, + UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME); + for(interpolCntr = 0; interpolCntr < UB16_INTERPOL_SEGMENTS; interpolCntr++) + { + WebRtcIsac_Lar2PolyInterpolUB(lpcVecs, + interpolLPCCoeff, kLpcVecPerSegmentUb16 + 1); + lpcVecs += UB_LPC_ORDER; + interpolLPCCoeff += (kLpcVecPerSegmentUb16 * (UB_LPC_ORDER + 1)); + } + break; + } + default: + return -1; + } + return 0; +} + +void WebRtcIsac_EncodeLpcGainLb(double *LPCCoef_lo, double *LPCCoef_hi, int model, Bitstr *streamdata, ISAC_SaveEncData_t* encData) { + + int j, k, n, pos, pos2, posg, offsg, offs2; + int index_g[KLT_ORDER_GAIN]; + int index_ovr_g[KLT_ORDER_GAIN]; + double tmpcoeffs_g[KLT_ORDER_GAIN]; + double tmpcoeffs2_g[KLT_ORDER_GAIN]; + double sum; + + /* log gains, mean removal and scaling */ + posg = 0; + for (k=0; k WebRtcIsac_kQKltMaxIndGain[k]) { + index_g[k] = WebRtcIsac_kQKltMaxIndGain[k]; + } + index_ovr_g[k] = WebRtcIsac_kQKltOffsetGain[model][k]+index_g[k]; + + /* find quantization levels for coefficients */ + tmpcoeffs_g[WebRtcIsac_kQKltSelIndGain[k]] = WebRtcIsac_kQKltLevelsGain[WebRtcIsac_kQKltOfLevelsGain[model]+index_ovr_g[k]]; + + /* Save data for creation of multiple bit streams */ + encData->LPCindex_g[KLT_ORDER_GAIN*encData->startIdx + k] = index_g[k]; + } + + + /* entropy coding of quantization indices - gain */ + WebRtcIsac_EncHistMulti(streamdata, index_g, WebRtcIsac_kQKltCdfPtrGain[model], KLT_ORDER_GAIN); + + /* find quantization levels for coefficients */ + + /* left transform */ + offsg = 0; + posg = 0; + for (j=0; j WebRtcIsac_kQArBoundaryLevels[index[k]]) + { + while (RCQ15[k] > WebRtcIsac_kQArBoundaryLevels[index[k] + 1]) + index[k]++; + } + else + { + while (RCQ15[k] < WebRtcIsac_kQArBoundaryLevels[--index[k]]) ; + } + + RCQ15[k] = *(WebRtcIsac_kQArRcLevelsPtr[k] + index[k]); + } + + + /* entropy coding of quantization indices */ + WebRtcIsac_EncHistMulti(streamdata, index, WebRtcIsac_kQArRcCdfPtr, AR_ORDER); +} + + +/* decode & dequantize squared Gain */ +int WebRtcIsac_DecodeGain2(Bitstr *streamdata, WebRtc_Word32 *gainQ10) +{ + int index, err; + + /* entropy decoding of quantization index */ + err = WebRtcIsac_DecHistOneStepMulti(&index, streamdata, WebRtcIsac_kQGainCdf_ptr, + WebRtcIsac_kQGainInitIndex, 1); + if (err<0) // error check + return err; + + /* find quantization level */ + *gainQ10 = WebRtcIsac_kQGain2Levels[index]; + + return 0; +} + + + +/* quantize & code squared Gain */ +int WebRtcIsac_EncodeGain2(WebRtc_Word32 *gainQ10, Bitstr *streamdata) +{ + int index; + + + /* find quantization index */ + index = WebRtcIsac_kQGainInitIndex[0]; + if (*gainQ10 > WebRtcIsac_kQGain2BoundaryLevels[index]) + { + while (*gainQ10 > WebRtcIsac_kQGain2BoundaryLevels[index + 1]) + index++; + } + else + { + while (*gainQ10 < WebRtcIsac_kQGain2BoundaryLevels[--index]) ; + } + + /* dequantize */ + *gainQ10 = WebRtcIsac_kQGain2Levels[index]; + + + /* entropy coding of quantization index */ + WebRtcIsac_EncHistMulti(streamdata, &index, WebRtcIsac_kQGainCdf_ptr, 1); + + return 0; +} + + +/* code and decode Pitch Gains and Lags functions */ + +/* decode & dequantize Pitch Gains */ +int WebRtcIsac_DecodePitchGain(Bitstr *streamdata, WebRtc_Word16 *PitchGains_Q12) +{ + int index_comb, err; + const WebRtc_UWord16 *WebRtcIsac_kQPitchGainCdf_ptr[1]; + + /* entropy decoding of quantization indices */ + *WebRtcIsac_kQPitchGainCdf_ptr = WebRtcIsac_kQPitchGainCdf; + err = WebRtcIsac_DecHistBisectMulti(&index_comb, streamdata, WebRtcIsac_kQPitchGainCdf_ptr, WebRtcIsac_kQCdfTableSizeGain, 1); + /* error check, Q_mean_Gain.. tables are of size 144 */ + if ((err<0) || (index_comb<0) || (index_comb>144)) + return -ISAC_RANGE_ERROR_DECODE_PITCH_GAIN; + + /* unquantize back to pitch gains by table look-up */ + PitchGains_Q12[0] = WebRtcIsac_kQMeanGain1Q12[index_comb]; + PitchGains_Q12[1] = WebRtcIsac_kQMeanGain2Q12[index_comb]; + PitchGains_Q12[2] = WebRtcIsac_kQMeanGain3Q12[index_comb]; + PitchGains_Q12[3] = WebRtcIsac_kQMeanGain4Q12[index_comb]; + + return 0; +} + + +/* quantize & code Pitch Gains */ +void WebRtcIsac_EncodePitchGain(WebRtc_Word16 *PitchGains_Q12, Bitstr *streamdata, ISAC_SaveEncData_t* encData) +{ + int k,j; + double C; + double S[PITCH_SUBFRAMES]; + int index[3]; + int index_comb; + const WebRtc_UWord16 *WebRtcIsac_kQPitchGainCdf_ptr[1]; + double PitchGains[PITCH_SUBFRAMES] = {0,0,0,0}; + + /* take the asin */ + for (k=0; k WebRtcIsac_kIndexUpperLimitGain[k]) index[k] = WebRtcIsac_kIndexUpperLimitGain[k]; + index[k] -= WebRtcIsac_kIndexLowerLimitGain[k]; + } + + /* calculate unique overall index */ + index_comb = WebRtcIsac_kIndexMultsGain[0] * index[0] + WebRtcIsac_kIndexMultsGain[1] * index[1] + index[2]; + + /* unquantize back to pitch gains by table look-up */ + PitchGains_Q12[0] = WebRtcIsac_kQMeanGain1Q12[index_comb]; + PitchGains_Q12[1] = WebRtcIsac_kQMeanGain2Q12[index_comb]; + PitchGains_Q12[2] = WebRtcIsac_kQMeanGain3Q12[index_comb]; + PitchGains_Q12[3] = WebRtcIsac_kQMeanGain4Q12[index_comb]; + + /* entropy coding of quantization pitch gains */ + *WebRtcIsac_kQPitchGainCdf_ptr = WebRtcIsac_kQPitchGainCdf; + WebRtcIsac_EncHistMulti(streamdata, &index_comb, WebRtcIsac_kQPitchGainCdf_ptr, 1); + encData->pitchGain_index[encData->startIdx] = index_comb; + +} + + + +/* Pitch LAG */ + + +/* decode & dequantize Pitch Lags */ +int WebRtcIsac_DecodePitchLag(Bitstr *streamdata, WebRtc_Word16 *PitchGain_Q12, double *PitchLags) +{ + int k, err; + double StepSize; + double C; + int index[PITCH_SUBFRAMES]; + double mean_gain; + const double *mean_val2, *mean_val3, *mean_val4; + const WebRtc_Word16 *lower_limit; + const WebRtc_UWord16 *init_index; + const WebRtc_UWord16 *cdf_size; + const WebRtc_UWord16 **cdf; + + //(Y) + double PitchGain[4]={0,0,0,0}; + // + + /* compute mean pitch gain */ + mean_gain = 0.0; + for (k = 0; k < 4; k++) + { + //(Y) + PitchGain[k] = ((float)PitchGain_Q12[k])/4096; + //(Y) + mean_gain += PitchGain[k]; + } + mean_gain /= 4.0; + + /* voicing classificiation */ + if (mean_gain < 0.2) { + StepSize = WebRtcIsac_kQPitchLagStepsizeLo; + cdf = WebRtcIsac_kQPitchLagCdfPtrLo; + cdf_size = WebRtcIsac_kQPitchLagCdfSizeLo; + mean_val2 = WebRtcIsac_kQMeanLag2Lo; + mean_val3 = WebRtcIsac_kQMeanLag3Lo; + mean_val4 = WebRtcIsac_kQMeanLag4Lo; + lower_limit = WebRtcIsac_kQIndexLowerLimitLagLo; + init_index = WebRtcIsac_kQInitIndexLagLo; + } else if (mean_gain < 0.4) { + StepSize = WebRtcIsac_kQPitchLagStepsizeMid; + cdf = WebRtcIsac_kQPitchLagCdfPtrMid; + cdf_size = WebRtcIsac_kQPitchLagCdfSizeMid; + mean_val2 = WebRtcIsac_kQMeanLag2Mid; + mean_val3 = WebRtcIsac_kQMeanLag3Mid; + mean_val4 = WebRtcIsac_kQMeanLag4Mid; + lower_limit = WebRtcIsac_kQIndexLowerLimitLagMid; + init_index = WebRtcIsac_kQInitIndexLagMid; + } else { + StepSize = WebRtcIsac_kQPitchLagStepsizeHi; + cdf = WebRtcIsac_kQPitchLagCdfPtrHi; + cdf_size = WebRtcIsac_kQPitchLagCdfSizeHi; + mean_val2 = WebRtcIsac_kQMeanLag2Hi; + mean_val3 = WebRtcIsac_kQMeanLag3Hi; + mean_val4 = WebRtcIsac_kQMeanLag4Hi; + lower_limit = WebRtcIsac_kQindexLowerLimitLagHi; + init_index = WebRtcIsac_kQInitIndexLagHi; + } + + /* entropy decoding of quantization indices */ + err = WebRtcIsac_DecHistBisectMulti(index, streamdata, cdf, cdf_size, 1); + if ((err<0) || (index[0]<0)) // error check + return -ISAC_RANGE_ERROR_DECODE_PITCH_LAG; + + err = WebRtcIsac_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 */ + C = (index[0] + lower_limit[0]) * StepSize; + for (k=0; kmeanGain[encData->startIdx] = mean_gain; + + /* voicing classification */ + if (mean_gain < 0.2) { + StepSize = WebRtcIsac_kQPitchLagStepsizeLo; + cdf = WebRtcIsac_kQPitchLagCdfPtrLo; + mean_val2 = WebRtcIsac_kQMeanLag2Lo; + mean_val3 = WebRtcIsac_kQMeanLag3Lo; + mean_val4 = WebRtcIsac_kQMeanLag4Lo; + lower_limit = WebRtcIsac_kQIndexLowerLimitLagLo; + upper_limit = WebRtcIsac_kQIndexUpperLimitLagLo; + } else if (mean_gain < 0.4) { + StepSize = WebRtcIsac_kQPitchLagStepsizeMid; + cdf = WebRtcIsac_kQPitchLagCdfPtrMid; + mean_val2 = WebRtcIsac_kQMeanLag2Mid; + mean_val3 = WebRtcIsac_kQMeanLag3Mid; + mean_val4 = WebRtcIsac_kQMeanLag4Mid; + lower_limit = WebRtcIsac_kQIndexLowerLimitLagMid; + upper_limit = WebRtcIsac_kQIndexUpperLimitLagMid; + } else { + StepSize = WebRtcIsac_kQPitchLagStepsizeHi; + cdf = WebRtcIsac_kQPitchLagCdfPtrHi; + mean_val2 = WebRtcIsac_kQMeanLag2Hi; + mean_val3 = WebRtcIsac_kQMeanLag3Hi; + mean_val4 = WebRtcIsac_kQMeanLag4Hi; + lower_limit = WebRtcIsac_kQindexLowerLimitLagHi; + upper_limit = WebRtcIsac_kQindexUpperLimitLagHi; + } + + + /* find quantization index */ + for (k=0; k<4; k++) + { + /* transform */ + C = 0.0; + for (j=0; j upper_limit[k]) index[k] = upper_limit[k]; + index[k] -= lower_limit[k]; + + /* Save data for creation of multiple bit streams */ + encData->pitchIndex[PITCH_SUBFRAMES*encData->startIdx + k] = index[k]; + } + + /* unquantize back to transform coefficients and do the inverse transform: S = T'*C */ + C = (index[0] + lower_limit[0]) * StepSize; + for (k=0; k WebRtcIsac_kQKltMaxIndGain[k]) { + index_g[k] = WebRtcIsac_kQKltMaxIndGain[k]; + } + index_ovr_g[k] = WebRtcIsac_kQKltOffsetGain[model][k]+index_g[k]; + + /* find quantization levels for coefficients */ + tmpcoeffs_g[WebRtcIsac_kQKltSelIndGain[k]] = WebRtcIsac_kQKltLevelsGain[WebRtcIsac_kQKltOfLevelsGain[model]+index_ovr_g[k]]; + } +} + + +/* decode & dequantize LPC Coef */ +int +WebRtcIsac_DecodeLpcCoefUB( + Bitstr* streamdata, + double* lpcVecs, + double* percepFilterGains, + WebRtc_Word16 bandwidth) +{ + int index_s[KLT_ORDER_SHAPE]; + + double U[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME]; + int err; + + /* entropy decoding of quantization indices */ + switch(bandwidth) + { + case isac12kHz: + { + err = WebRtcIsac_DecHistOneStepMulti(index_s, streamdata, + WebRtcIsac_kLpcShapeCdfMatUb12, WebRtcIsac_kLpcShapeEntropySearchUb12, + UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME); + break; + } + case isac16kHz: + { + err = WebRtcIsac_DecHistOneStepMulti(index_s, streamdata, + WebRtcIsac_kLpcShapeCdfMatUb16, WebRtcIsac_kLpcShapeEntropySearchUb16, + UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME); + break; + } + default: + return -1; + } + + if (err<0) // error check + { + return err; + } + + WebRtcIsac_DequantizeLpcParam(index_s, lpcVecs, bandwidth); + WebRtcIsac_CorrelateInterVec(lpcVecs, U, bandwidth); + WebRtcIsac_CorrelateIntraVec(U, lpcVecs, bandwidth); + WebRtcIsac_AddLarMean(lpcVecs, bandwidth); + + + WebRtcIsac_DecodeLpcGainUb(percepFilterGains, streamdata); + + if(bandwidth == isac16kHz) + { + // decode another set of Gains + WebRtcIsac_DecodeLpcGainUb(&percepFilterGains[SUBFRAMES], streamdata); + } + + return 0; +} + +WebRtc_Word16 +WebRtcIsac_EncodeBandwidth( + enum ISACBandwidth bandwidth, + Bitstr* streamData) +{ + int bandwidthMode; + switch(bandwidth) + { + case isac12kHz: + { + bandwidthMode = 0; + break; + } + case isac16kHz: + { + bandwidthMode = 1; + break; + } + default: + return -ISAC_DISALLOWED_ENCODER_BANDWIDTH; + } + + WebRtcIsac_EncHistMulti(streamData, &bandwidthMode, + kOneBitEqualProbCdf_ptr, 1); + return 0; +} + +WebRtc_Word16 +WebRtcIsac_DecodeBandwidth( + Bitstr* streamData, + enum ISACBandwidth* bandwidth) +{ + int bandwidthMode; + + if(WebRtcIsac_DecHistOneStepMulti(&bandwidthMode, streamData, + kOneBitEqualProbCdf_ptr, + kOneBitEqualProbInitIndex, 1) < 0) + { + // error check + return -ISAC_RANGE_ERROR_DECODE_BANDWITH; + } + + switch(bandwidthMode) + { + case 0: + { + *bandwidth = isac12kHz; + break; + } + case 1: + { + *bandwidth = isac16kHz; + break; + } + default: + return -ISAC_DISALLOWED_BANDWIDTH_MODE_DECODER; + } + return 0; +} + +WebRtc_Word16 +WebRtcIsac_EncodeJitterInfo( + WebRtc_Word32 jitterIndex, + Bitstr* streamData) +{ + // This is to avoid LINUX warning until we change 'int' to + // 'Word32' + int intVar; + + if((jitterIndex < 0) || (jitterIndex > 1)) + { + return -1; + } + intVar = (int)(jitterIndex); + // Use the same CDF table as for bandwidth + // both take two values with equal probability + WebRtcIsac_EncHistMulti(streamData, &intVar, + kOneBitEqualProbCdf_ptr, 1); + return 0; + +} + +WebRtc_Word16 +WebRtcIsac_DecodeJitterInfo( + Bitstr* streamData, + WebRtc_Word32* jitterInfo) +{ + int intVar; + + // Use the same CDF table as for bandwidth + // both take two values with equal probability + if(WebRtcIsac_DecHistOneStepMulti(&intVar, streamData, + kOneBitEqualProbCdf_ptr, + kOneBitEqualProbInitIndex, 1) < 0) + { + // error check + return -ISAC_RANGE_ERROR_DECODE_BANDWITH; + } + *jitterInfo = (WebRtc_Word16)(intVar); + return 0; +} diff --git a/libs/miniwebrtc/audio/coding_isac/main/entropy_coding.h b/libs/miniwebrtc/audio/coding_isac/main/entropy_coding.h new file mode 100644 index 00000000..8446bcf3 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/entropy_coding.h @@ -0,0 +1,412 @@ +/* + * 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 declares all of the functions used to arithmetically + * encode the iSAC bistream + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_ + +#include "structs.h" + +/* decode complex spectrum (return number of bytes in stream) */ +int WebRtcIsac_DecodeSpecLb(Bitstr *streamdata, + double *fr, + double *fi, + WebRtc_Word16 AvgPitchGain_Q12); + +/****************************************************************************** + * WebRtcIsac_DecodeSpecUB16() + * Decode real and imaginary part of the DFT coefficients, given a bit-stream. + * This function is called when the codec is in 0-16 kHz bandwidth. + * The decoded DFT coefficient can be transformed to time domain by + * WebRtcIsac_Time2Spec(). + * + * Input: + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * + * Output: + * -*fr : pointer to a buffer where the real part of DFT + * coefficients are written to. + * -*fi : pointer to a buffer where the imaginary part + * of DFT coefficients are written to. + * + * Return value : < 0 if an error occures + * 0 if succeeded. + */ +int WebRtcIsac_DecodeSpecUB16( + Bitstr* streamdata, + double* fr, + double* fi); + + +/****************************************************************************** + * WebRtcIsac_DecodeSpecUB12() + * Decode real and imaginary part of the DFT coefficients, given a bit-stream. + * This function is called when the codec is in 0-12 kHz bandwidth. + * The decoded DFT coefficient can be transformed to time domain by + * WebRtcIsac_Time2Spec(). + * + * Input: + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * + * Output: + * -*fr : pointer to a buffer where the real part of DFT + * coefficients are written to. + * -*fi : pointer to a buffer where the imaginary part + * of DFT coefficients are written to. + * + * Return value : < 0 if an error occures + * 0 if succeeded. + */ +int WebRtcIsac_DecodeSpecUB12( + Bitstr* streamdata, + double* fr, + double* fi); + + +/* encode complex spectrum */ +int WebRtcIsac_EncodeSpecLb(const WebRtc_Word16* fr, + const WebRtc_Word16* fi, + Bitstr* streamdata, + WebRtc_Word16 AvgPitchGain_Q12); + + +/****************************************************************************** + * WebRtcIsac_EncodeSpecUB16() + * Quantize and encode real and imaginary part of the DFT coefficients. + * This function is called when the codec is in 0-16 kHz bandwidth. + * The real and imaginary part are computed by calling WebRtcIsac_Time2Spec(). + * + * + * Input: + * -*fr : pointer to a buffer where the real part of DFT + * coefficients are stored. + * -*fi : pointer to a buffer where the imaginary part + * of DFT coefficients are stored. + * + * Output: + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * + * Return value : < 0 if an error occures + * 0 if succeeded. + */ +int WebRtcIsac_EncodeSpecUB16( + const WebRtc_Word16* fr, + const WebRtc_Word16* fi, + Bitstr* streamdata); + + +/****************************************************************************** + * WebRtcIsac_EncodeSpecUB12() + * Quantize and encode real and imaginary part of the DFT coefficients. + * This function is called when the codec is in 0-12 kHz bandwidth. + * The real and imaginary part are computed by calling WebRtcIsac_Time2Spec(). + * + * + * Input: + * -*fr : pointer to a buffer where the real part of DFT + * coefficients are stored. + * -*fi : pointer to a buffer where the imaginary part + * of DFT coefficients are stored. + * + * Output: + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * + * Return value : < 0 if an error occures + * 0 if succeeded. + */ +int WebRtcIsac_EncodeSpecUB12( + const WebRtc_Word16* fr, + const WebRtc_Word16* fi, + Bitstr* streamdata); + + +/* decode & dequantize LPC Coef */ +int WebRtcIsac_DecodeLpcCoef(Bitstr *streamdata, double *LPCCoef, int *outmodel); +int WebRtcIsac_DecodeLpcCoefUB( + Bitstr* streamdata, + double* lpcVecs, + double* percepFilterGains, + WebRtc_Word16 bandwidth); + +int WebRtcIsac_DecodeLpc(Bitstr *streamdata, double *LPCCoef_lo, double *LPCCoef_hi, int *outmodel); + +/* quantize & code LPC Coef */ +void WebRtcIsac_EncodeLpcLb(double *LPCCoef_lo, double *LPCCoef_hi, int *model, double *size, Bitstr *streamdata, ISAC_SaveEncData_t* encData); +void WebRtcIsac_EncodeLpcGainLb(double *LPCCoef_lo, double *LPCCoef_hi, int model, Bitstr *streamdata, ISAC_SaveEncData_t* encData); + +/****************************************************************************** + * WebRtcIsac_EncodeLpcUB() + * Encode LPC parameters, given as A-polynomial, of upper-band. The encoding + * is performed in LAR domain. + * For the upper-band, we compute and encode LPC of some sub-frames, LPC of + * other sub-frames are computed by linear interpolation, in LAR domain. This + * function performs the interpolation and returns the LPC of all sub-frames. + * + * Inputs: + * - lpcCoef : a buffer containing A-polynomials of sub-frames + * (excluding first coefficient that is 1). + * - bandwidth : specifies if the codec is operating at 0-12 kHz + * or 0-16 kHz mode. + * + * Input/output: + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * + * Output: + * - interpolLPCCoeff : Decoded and interpolated LPC (A-polynomial) + * of all sub-frames. + * If LP analysis is of order K, and there are N + * sub-frames then this is a buffer of size + * (k + 1) * N, each vector starts with the LPC gain + * of the corresponding sub-frame. The LPC gains + * are encoded and inserted after this function is + * called. The first A-coefficient which is 1 is not + * included. + * + * Return value : 0 if encoding is successful, + * <0 if failed to encode. + */ +WebRtc_Word16 WebRtcIsac_EncodeLpcUB( + double* lpcCoeff, + Bitstr* streamdata, + double* interpolLPCCoeff, + WebRtc_Word16 bandwidth, + ISACUBSaveEncDataStruct* encData); + +/****************************************************************************** + * WebRtcIsac_DecodeInterpolLpcUb() + * Decode LPC coefficients and interpolate to get the coefficients fo all + * sub-frmaes. + * + * Inputs: + * - bandwidth : spepecifies if the codec is in 0-12 kHz or + * 0-16 kHz mode. + * + * Input/output: + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * + * Output: + * - percepFilterParam : Decoded and interpolated LPC (A-polynomial) of + * all sub-frames. + * If LP analysis is of order K, and there are N + * sub-frames then this is a buffer of size + * (k + 1) * N, each vector starts with the LPC gain + * of the corresponding sub-frame. The LPC gains + * are encoded and inserted after this function is + * called. The first A-coefficient which is 1 is not + * included. + * + * Return value : 0 if encoding is successful, + * <0 if failed to encode. + */ +WebRtc_Word16 WebRtcIsac_DecodeInterpolLpcUb( + Bitstr* streamdata, + double* percepFilterParam, + WebRtc_Word16 bandwidth); + +/* decode & dequantize RC */ +int WebRtcIsac_DecodeRc(Bitstr *streamdata, WebRtc_Word16 *RCQ15); + +/* quantize & code RC */ +void WebRtcIsac_EncodeRc(WebRtc_Word16 *RCQ15, Bitstr *streamdata); + +/* decode & dequantize squared Gain */ +int WebRtcIsac_DecodeGain2(Bitstr *streamdata, WebRtc_Word32 *Gain2); + +/* quantize & code squared Gain (input is squared gain) */ +int WebRtcIsac_EncodeGain2(WebRtc_Word32 *gain2, Bitstr *streamdata); + +void WebRtcIsac_EncodePitchGain(WebRtc_Word16* PitchGains_Q12, Bitstr* streamdata, ISAC_SaveEncData_t* encData); + +void WebRtcIsac_EncodePitchLag(double* PitchLags, WebRtc_Word16* PitchGain_Q12, Bitstr* streamdata, ISAC_SaveEncData_t* encData); + +int WebRtcIsac_DecodePitchGain(Bitstr *streamdata, WebRtc_Word16 *PitchGain_Q12); +int WebRtcIsac_DecodePitchLag(Bitstr *streamdata, WebRtc_Word16 *PitchGain_Q12, double *PitchLag); + +int WebRtcIsac_DecodeFrameLen(Bitstr *streamdata, WebRtc_Word16 *framelength); +int WebRtcIsac_EncodeFrameLen(WebRtc_Word16 framelength, Bitstr *streamdata); +int WebRtcIsac_DecodeSendBW(Bitstr *streamdata, WebRtc_Word16 *BWno); +void WebRtcIsac_EncodeReceiveBw(int *BWno, Bitstr *streamdata); + +/* step-down */ +void WebRtcIsac_Poly2Rc(double *a, int N, double *RC); + +/* step-up */ +void WebRtcIsac_Rc2Poly(double *RC, int N, double *a); + +void WebRtcIsac_TranscodeLPCCoef(double *LPCCoef_lo, double *LPCCoef_hi, int model, + int *index_g); + + +/****************************************************************************** + * WebRtcIsac_EncodeLpcGainUb() + * Encode LPC gains of sub-Frames. + * + * Input/outputs: + * - lpGains : a buffer which contains 'SUBFRAME' number of + * LP gains to be encoded. The input values are + * overwritten by the quantized values. + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * + * Output: + * - lpcGainIndex : quantization indices for lpc gains, these will + * be stored to be used for FEC. + */ +void WebRtcIsac_EncodeLpcGainUb( + double* lpGains, + Bitstr* streamdata, + int* lpcGainIndex); + + +/****************************************************************************** + * WebRtcIsac_EncodeLpcGainUb() + * Store LPC gains of sub-Frames in 'streamdata'. + * + * Input: + * - lpGains : a buffer which contains 'SUBFRAME' number of + * LP gains to be encoded. + * Input/outputs: + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * + */ +void WebRtcIsac_StoreLpcGainUb( + double* lpGains, + Bitstr* streamdata); + + +/****************************************************************************** + * WebRtcIsac_DecodeLpcGainUb() + * Decode the LPC gain of sub-frames. + * + * Input/output: + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * + * Output: + * - lpGains : a buffer where decoded LPC gians will be stored. + * + * Return value : 0 if succeeded. + * <0 if failed. + */ +WebRtc_Word16 WebRtcIsac_DecodeLpcGainUb( + double* lpGains, + Bitstr* streamdata); + + +/****************************************************************************** + * WebRtcIsac_EncodeBandwidth() + * Encode if the bandwidth of encoded audio is 0-12 kHz or 0-16 kHz. + * + * Input: + * - bandwidth : an enumerator specifying if the codec in is + * 0-12 kHz or 0-16 kHz mode. + * + * Input/output: + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * + * Return value : 0 if succeeded. + * <0 if failed. + */ +WebRtc_Word16 WebRtcIsac_EncodeBandwidth( + enum ISACBandwidth bandwidth, + Bitstr* streamData); + + +/****************************************************************************** + * WebRtcIsac_DecodeBandwidth() + * Decode the bandwidth of the encoded audio, i.e. if the bandwidth is 0-12 kHz + * or 0-16 kHz. + * + * Input/output: + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * + * Output: + * - bandwidth : an enumerator specifying if the codec is in + * 0-12 kHz or 0-16 kHz mode. + * + * Return value : 0 if succeeded. + * <0 if failed. + */ +WebRtc_Word16 WebRtcIsac_DecodeBandwidth( + Bitstr* streamData, + enum ISACBandwidth* bandwidth); + + +/****************************************************************************** + * WebRtcIsac_EncodeJitterInfo() + * Decode the jitter information. + * + * Input/output: + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * + * Input: + * - jitterInfo : one bit of info specifying if the channel is + * in high/low jitter. Zero indicates low jitter + * and one indicates high jitter. + * + * Return value : 0 if succeeded. + * <0 if failed. + */ +WebRtc_Word16 WebRtcIsac_EncodeJitterInfo( + WebRtc_Word32 jitterIndex, + Bitstr* streamData); + + +/****************************************************************************** + * WebRtcIsac_DecodeJitterInfo() + * Decode the jitter information. + * + * Input/output: + * - streamdata : pointer to a stucture containg the encoded + * data and theparameters needed for entropy + * coding. + * + * Output: + * - jitterInfo : one bit of info specifying if the channel is + * in high/low jitter. Zero indicates low jitter + * and one indicates high jitter. + * + * Return value : 0 if succeeded. + * <0 if failed. + */ +WebRtc_Word16 WebRtcIsac_DecodeJitterInfo( + Bitstr* streamData, + WebRtc_Word32* jitterInfo); + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_ENTROPY_CODING_H_ */ diff --git a/libs/miniwebrtc/audio/coding_isac/main/fft.c b/libs/miniwebrtc/audio/coding_isac/main/fft.c new file mode 100644 index 00000000..c8247983 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/fft.c @@ -0,0 +1,947 @@ +/* + * Copyright(c)1995,97 Mark Olesen + * Queen's Univ at Kingston (Canada) + * + * Permission to use, copy, modify, and distribute this software for + * any purpose without fee is hereby granted, provided that this + * entire notice is included in all copies of any software which is + * or includes a copy or modification of this software and in all + * copies of the supporting documentation for such software. + * + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR QUEEN'S + * UNIVERSITY AT KINGSTON MAKES ANY REPRESENTATION OR WARRANTY OF ANY + * KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS + * FITNESS FOR ANY PARTICULAR PURPOSE. + * + * All of which is to say that you can do what you like with this + * source code provided you don't try to sell it as your own and you + * include an unaltered copy of this message (including the + * copyright). + * + * It is also implicitly understood that bug fixes and improvements + * should make their way back to the general Internet community so + * that everyone benefits. + * + * Changes: + * Trivial type modifications by the WebRTC authors. + */ + + +/* + * File: + * WebRtcIsac_Fftn.c + * + * Public: + * WebRtcIsac_Fftn / fftnf (); + * + * Private: + * WebRtcIsac_Fftradix / fftradixf (); + * + * Descript: + * multivariate complex Fourier transform, computed in place + * using mixed-radix Fast Fourier Transform algorithm. + * + * Fortran code by: + * RC Singleton, Stanford Research Institute, Sept. 1968 + * + * translated by f2c (version 19950721). + * + * int WebRtcIsac_Fftn (int ndim, const int dims[], REAL Re[], REAL Im[], + * int iSign, double scaling); + * + * NDIM = the total number dimensions + * DIMS = a vector of array sizes + * if NDIM is zero then DIMS must be zero-terminated + * + * RE and IM hold the real and imaginary components of the data, and return + * the resulting real and imaginary Fourier coefficients. Multidimensional + * data *must* be allocated contiguously. There is no limit on the number + * of dimensions. + * + * ISIGN = the sign of the complex exponential (ie, forward or inverse FFT) + * the magnitude of ISIGN (normally 1) is used to determine the + * correct indexing increment (see below). + * + * SCALING = normalizing constant by which the final result is *divided* + * if SCALING == -1, normalize by total dimension of the transform + * if SCALING < -1, normalize by the square-root of the total dimension + * + * example: + * tri-variate transform with Re[n1][n2][n3], Im[n1][n2][n3] + * + * int dims[3] = {n1,n2,n3} + * WebRtcIsac_Fftn (3, dims, Re, Im, 1, scaling); + * + *-----------------------------------------------------------------------* + * int WebRtcIsac_Fftradix (REAL Re[], REAL Im[], size_t nTotal, size_t nPass, + * size_t nSpan, int iSign, size_t max_factors, + * size_t max_perm); + * + * RE, IM - see above documentation + * + * Although there is no limit on the number of dimensions, WebRtcIsac_Fftradix() must + * be called once for each dimension, but the calls may be in any order. + * + * NTOTAL = the total number of complex data values + * NPASS = the dimension of the current variable + * NSPAN/NPASS = the spacing of consecutive data values while indexing the + * current variable + * ISIGN - see above documentation + * + * example: + * tri-variate transform with Re[n1][n2][n3], Im[n1][n2][n3] + * + * WebRtcIsac_Fftradix (Re, Im, n1*n2*n3, n1, n1, 1, maxf, maxp); + * WebRtcIsac_Fftradix (Re, Im, n1*n2*n3, n2, n1*n2, 1, maxf, maxp); + * WebRtcIsac_Fftradix (Re, Im, n1*n2*n3, n3, n1*n2*n3, 1, maxf, maxp); + * + * single-variate transform, + * NTOTAL = N = NSPAN = (number of complex data values), + * + * WebRtcIsac_Fftradix (Re, Im, n, n, n, 1, maxf, maxp); + * + * The data can also be stored in a single array with alternating real and + * imaginary parts, the magnitude of ISIGN is changed to 2 to give correct + * indexing increment, and data [0] and data [1] used to pass the initial + * addresses for the sequences of real and imaginary values, + * + * example: + * REAL data [2*NTOTAL]; + * WebRtcIsac_Fftradix ( &data[0], &data[1], NTOTAL, nPass, nSpan, 2, maxf, maxp); + * + * for temporary allocation: + * + * MAX_FACTORS >= the maximum prime factor of NPASS + * MAX_PERM >= the number of prime factors of NPASS. In addition, + * if the square-free portion K of NPASS has two or more prime + * factors, then MAX_PERM >= (K-1) + * + * storage in FACTOR for a maximum of 15 prime factors of NPASS. if NPASS + * has more than one square-free factor, the product of the square-free + * factors must be <= 210 array storage for maximum prime factor of 23 the + * following two constants should agree with the array dimensions. + * + *----------------------------------------------------------------------*/ +#include "fft.h" + +#include +#include + + + +/* double precision routine */ +static int +WebRtcIsac_Fftradix (double Re[], double Im[], + size_t nTotal, size_t nPass, size_t nSpan, int isign, + int max_factors, unsigned int max_perm, + FFTstr *fftstate); + + + +#ifndef M_PI +# define M_PI 3.14159265358979323846264338327950288 +#endif + +#ifndef SIN60 +# define SIN60 0.86602540378443865 /* sin(60 deg) */ +# define COS72 0.30901699437494742 /* cos(72 deg) */ +# define SIN72 0.95105651629515357 /* sin(72 deg) */ +#endif + +# define REAL double +# define FFTN WebRtcIsac_Fftn +# define FFTNS "fftn" +# define FFTRADIX WebRtcIsac_Fftradix +# define FFTRADIXS "fftradix" + + +int WebRtcIsac_Fftns(unsigned int ndim, const int dims[], + double Re[], + double Im[], + int iSign, + double scaling, + FFTstr *fftstate) +{ + + size_t nSpan, nPass, nTotal; + unsigned int i; + int ret, max_factors, max_perm; + + /* + * tally the number of elements in the data array + * and determine the number of dimensions + */ + nTotal = 1; + if (ndim && dims [0]) + { + for (i = 0; i < ndim; i++) + { + if (dims [i] <= 0) + { + return -1; + } + nTotal *= dims [i]; + } + } + else + { + ndim = 0; + for (i = 0; dims [i]; i++) + { + if (dims [i] <= 0) + { + return -1; + } + nTotal *= dims [i]; + ndim++; + } + } + + /* determine maximum number of factors and permuations */ +#if 1 + /* + * follow John Beale's example, just use the largest dimension and don't + * worry about excess allocation. May be someone else will do it? + */ + max_factors = max_perm = 1; + for (i = 0; i < ndim; i++) + { + nSpan = dims [i]; + if ((int)nSpan > max_factors) + { + max_factors = (int)nSpan; + } + if ((int)nSpan > max_perm) + { + max_perm = (int)nSpan; + } + } +#else + /* use the constants used in the original Fortran code */ + max_factors = 23; + max_perm = 209; +#endif + /* loop over the dimensions: */ + nPass = 1; + for (i = 0; i < ndim; i++) + { + nSpan = dims [i]; + nPass *= nSpan; + ret = FFTRADIX (Re, Im, nTotal, nSpan, nPass, iSign, + max_factors, max_perm, fftstate); + /* exit, clean-up already done */ + if (ret) + return ret; + } + + /* Divide through by the normalizing constant: */ + if (scaling && scaling != 1.0) + { + if (iSign < 0) iSign = -iSign; + if (scaling < 0.0) + { + scaling = (double)nTotal; + if (scaling < -1.0) + scaling = sqrt (scaling); + } + scaling = 1.0 / scaling; /* multiply is often faster */ + for (i = 0; i < nTotal; i += iSign) + { + Re [i] *= scaling; + Im [i] *= scaling; + } + } + return 0; +} + +/* + * singleton's mixed radix routine + * + * could move allocation out to WebRtcIsac_Fftn(), but leave it here so that it's + * possible to make this a standalone function + */ + +static int FFTRADIX (REAL Re[], + REAL Im[], + size_t nTotal, + size_t nPass, + size_t nSpan, + int iSign, + int max_factors, + unsigned int max_perm, + FFTstr *fftstate) +{ + int ii, mfactor, kspan, ispan, inc; + int j, jc, jf, jj, k, k1, k2, k3, k4, kk, kt, nn, ns, nt; + + + REAL radf; + REAL c1, c2, c3, cd, aa, aj, ak, ajm, ajp, akm, akp; + REAL s1, s2, s3, sd, bb, bj, bk, bjm, bjp, bkm, bkp; + + REAL *Rtmp = NULL; /* temp space for real part*/ + REAL *Itmp = NULL; /* temp space for imaginary part */ + REAL *Cos = NULL; /* Cosine values */ + REAL *Sin = NULL; /* Sine values */ + + REAL s60 = SIN60; /* sin(60 deg) */ + REAL c72 = COS72; /* cos(72 deg) */ + REAL s72 = SIN72; /* sin(72 deg) */ + REAL pi2 = M_PI; /* use PI first, 2 PI later */ + + + fftstate->SpaceAlloced = 0; + fftstate->MaxPermAlloced = 0; + + + // initialize to avoid warnings + k3 = c2 = c3 = s2 = s3 = 0.0; + + if (nPass < 2) + return 0; + + /* allocate storage */ + if (fftstate->SpaceAlloced < max_factors * sizeof (REAL)) + { +#ifdef SUN_BROKEN_REALLOC + if (!fftstate->SpaceAlloced) /* first time */ + { + fftstate->SpaceAlloced = max_factors * sizeof (REAL); + } + else + { +#endif + fftstate->SpaceAlloced = max_factors * sizeof (REAL); +#ifdef SUN_BROKEN_REALLOC + } +#endif + } + else + { + /* allow full use of alloc'd space */ + max_factors = fftstate->SpaceAlloced / sizeof (REAL); + } + if (fftstate->MaxPermAlloced < max_perm) + { +#ifdef SUN_BROKEN_REALLOC + if (!fftstate->MaxPermAlloced) /* first time */ + else +#endif + fftstate->MaxPermAlloced = max_perm; + } + else + { + /* allow full use of alloc'd space */ + max_perm = fftstate->MaxPermAlloced; + } + if (fftstate->Tmp0 == NULL || fftstate->Tmp1 == NULL || fftstate->Tmp2 == NULL || fftstate->Tmp3 == NULL + || fftstate->Perm == NULL) { + return -1; + } + + /* assign pointers */ + Rtmp = (REAL *) fftstate->Tmp0; + Itmp = (REAL *) fftstate->Tmp1; + Cos = (REAL *) fftstate->Tmp2; + Sin = (REAL *) fftstate->Tmp3; + + /* + * Function Body + */ + inc = iSign; + if (iSign < 0) { + s72 = -s72; + s60 = -s60; + pi2 = -pi2; + inc = -inc; /* absolute value */ + } + + /* adjust for strange increments */ + nt = inc * (int)nTotal; + ns = inc * (int)nSpan; + kspan = ns; + + nn = nt - inc; + jc = ns / (int)nPass; + radf = pi2 * (double) jc; + pi2 *= 2.0; /* use 2 PI from here on */ + + ii = 0; + jf = 0; + /* determine the factors of n */ + mfactor = 0; + k = (int)nPass; + while (k % 16 == 0) { + mfactor++; + fftstate->factor [mfactor - 1] = 4; + k /= 16; + } + j = 3; + jj = 9; + do { + while (k % jj == 0) { + mfactor++; + fftstate->factor [mfactor - 1] = j; + k /= jj; + } + j += 2; + jj = j * j; + } while (jj <= k); + if (k <= 4) { + kt = mfactor; + fftstate->factor [mfactor] = k; + if (k != 1) + mfactor++; + } else { + if (k - (k / 4 << 2) == 0) { + mfactor++; + fftstate->factor [mfactor - 1] = 2; + k /= 4; + } + kt = mfactor; + j = 2; + do { + if (k % j == 0) { + mfactor++; + fftstate->factor [mfactor - 1] = j; + k /= j; + } + j = ((j + 1) / 2 << 1) + 1; + } while (j <= k); + } + if (kt) { + j = kt; + do { + mfactor++; + fftstate->factor [mfactor - 1] = fftstate->factor [j - 1]; + j--; + } while (j); + } + + /* test that mfactors is in range */ + if (mfactor > NFACTOR) + { + return -1; + } + + /* compute fourier transform */ + for (;;) { + sd = radf / (double) kspan; + cd = sin(sd); + cd = 2.0 * cd * cd; + sd = sin(sd + sd); + kk = 0; + ii++; + + switch (fftstate->factor [ii - 1]) { + case 2: + /* transform for factor of 2 (including rotation factor) */ + kspan /= 2; + k1 = kspan + 2; + do { + do { + k2 = kk + kspan; + ak = Re [k2]; + bk = Im [k2]; + Re [k2] = Re [kk] - ak; + Im [k2] = Im [kk] - bk; + Re [kk] += ak; + Im [kk] += bk; + kk = k2 + kspan; + } while (kk < nn); + kk -= nn; + } while (kk < jc); + if (kk >= kspan) + goto Permute_Results_Label; /* exit infinite loop */ + do { + c1 = 1.0 - cd; + s1 = sd; + do { + do { + do { + k2 = kk + kspan; + ak = Re [kk] - Re [k2]; + bk = Im [kk] - Im [k2]; + Re [kk] += Re [k2]; + Im [kk] += Im [k2]; + Re [k2] = c1 * ak - s1 * bk; + Im [k2] = s1 * ak + c1 * bk; + kk = k2 + kspan; + } while (kk < (nt-1)); + k2 = kk - nt; + c1 = -c1; + kk = k1 - k2; + } while (kk > k2); + ak = c1 - (cd * c1 + sd * s1); + s1 = sd * c1 - cd * s1 + s1; + c1 = 2.0 - (ak * ak + s1 * s1); + s1 *= c1; + c1 *= ak; + kk += jc; + } while (kk < k2); + k1 += inc + inc; + kk = (k1 - kspan + 1) / 2 + jc - 1; + } while (kk < (jc + jc)); + break; + + case 4: /* transform for factor of 4 */ + ispan = kspan; + kspan /= 4; + + do { + c1 = 1.0; + s1 = 0.0; + do { + do { + k1 = kk + kspan; + k2 = k1 + kspan; + k3 = k2 + kspan; + akp = Re [kk] + Re [k2]; + akm = Re [kk] - Re [k2]; + ajp = Re [k1] + Re [k3]; + ajm = Re [k1] - Re [k3]; + bkp = Im [kk] + Im [k2]; + bkm = Im [kk] - Im [k2]; + bjp = Im [k1] + Im [k3]; + bjm = Im [k1] - Im [k3]; + Re [kk] = akp + ajp; + Im [kk] = bkp + bjp; + ajp = akp - ajp; + bjp = bkp - bjp; + if (iSign < 0) { + akp = akm + bjm; + bkp = bkm - ajm; + akm -= bjm; + bkm += ajm; + } else { + akp = akm - bjm; + bkp = bkm + ajm; + akm += bjm; + bkm -= ajm; + } + /* avoid useless multiplies */ + if (s1 == 0.0) { + Re [k1] = akp; + Re [k2] = ajp; + Re [k3] = akm; + Im [k1] = bkp; + Im [k2] = bjp; + Im [k3] = bkm; + } else { + Re [k1] = akp * c1 - bkp * s1; + Re [k2] = ajp * c2 - bjp * s2; + Re [k3] = akm * c3 - bkm * s3; + Im [k1] = akp * s1 + bkp * c1; + Im [k2] = ajp * s2 + bjp * c2; + Im [k3] = akm * s3 + bkm * c3; + } + kk = k3 + kspan; + } while (kk < nt); + + c2 = c1 - (cd * c1 + sd * s1); + s1 = sd * c1 - cd * s1 + s1; + c1 = 2.0 - (c2 * c2 + s1 * s1); + s1 *= c1; + c1 *= c2; + /* values of c2, c3, s2, s3 that will get used next time */ + c2 = c1 * c1 - s1 * s1; + s2 = 2.0 * c1 * s1; + c3 = c2 * c1 - s2 * s1; + s3 = c2 * s1 + s2 * c1; + kk = kk - nt + jc; + } while (kk < kspan); + kk = kk - kspan + inc; + } while (kk < jc); + if (kspan == jc) + goto Permute_Results_Label; /* exit infinite loop */ + break; + + default: + /* transform for odd factors */ +#ifdef FFT_RADIX4 + return -1; + break; +#else /* FFT_RADIX4 */ + k = fftstate->factor [ii - 1]; + ispan = kspan; + kspan /= k; + + switch (k) { + case 3: /* transform for factor of 3 (optional code) */ + do { + do { + k1 = kk + kspan; + k2 = k1 + kspan; + ak = Re [kk]; + bk = Im [kk]; + aj = Re [k1] + Re [k2]; + bj = Im [k1] + Im [k2]; + Re [kk] = ak + aj; + Im [kk] = bk + bj; + ak -= 0.5 * aj; + bk -= 0.5 * bj; + aj = (Re [k1] - Re [k2]) * s60; + bj = (Im [k1] - Im [k2]) * s60; + Re [k1] = ak - bj; + Re [k2] = ak + bj; + Im [k1] = bk + aj; + Im [k2] = bk - aj; + kk = k2 + kspan; + } while (kk < (nn - 1)); + kk -= nn; + } while (kk < kspan); + break; + + case 5: /* transform for factor of 5 (optional code) */ + c2 = c72 * c72 - s72 * s72; + s2 = 2.0 * c72 * s72; + do { + do { + k1 = kk + kspan; + k2 = k1 + kspan; + k3 = k2 + kspan; + k4 = k3 + kspan; + akp = Re [k1] + Re [k4]; + akm = Re [k1] - Re [k4]; + bkp = Im [k1] + Im [k4]; + bkm = Im [k1] - Im [k4]; + ajp = Re [k2] + Re [k3]; + ajm = Re [k2] - Re [k3]; + bjp = Im [k2] + Im [k3]; + bjm = Im [k2] - Im [k3]; + aa = Re [kk]; + bb = Im [kk]; + Re [kk] = aa + akp + ajp; + Im [kk] = bb + bkp + bjp; + ak = akp * c72 + ajp * c2 + aa; + bk = bkp * c72 + bjp * c2 + bb; + aj = akm * s72 + ajm * s2; + bj = bkm * s72 + bjm * s2; + Re [k1] = ak - bj; + Re [k4] = ak + bj; + Im [k1] = bk + aj; + Im [k4] = bk - aj; + ak = akp * c2 + ajp * c72 + aa; + bk = bkp * c2 + bjp * c72 + bb; + aj = akm * s2 - ajm * s72; + bj = bkm * s2 - bjm * s72; + Re [k2] = ak - bj; + Re [k3] = ak + bj; + Im [k2] = bk + aj; + Im [k3] = bk - aj; + kk = k4 + kspan; + } while (kk < (nn-1)); + kk -= nn; + } while (kk < kspan); + break; + + default: + if (k != jf) { + jf = k; + s1 = pi2 / (double) k; + c1 = cos(s1); + s1 = sin(s1); + if (jf > max_factors){ + return -1; + } + Cos [jf - 1] = 1.0; + Sin [jf - 1] = 0.0; + j = 1; + do { + Cos [j - 1] = Cos [k - 1] * c1 + Sin [k - 1] * s1; + Sin [j - 1] = Cos [k - 1] * s1 - Sin [k - 1] * c1; + k--; + Cos [k - 1] = Cos [j - 1]; + Sin [k - 1] = -Sin [j - 1]; + j++; + } while (j < k); + } + do { + do { + k1 = kk; + k2 = kk + ispan; + ak = aa = Re [kk]; + bk = bb = Im [kk]; + j = 1; + k1 += kspan; + do { + k2 -= kspan; + j++; + Rtmp [j - 1] = Re [k1] + Re [k2]; + ak += Rtmp [j - 1]; + Itmp [j - 1] = Im [k1] + Im [k2]; + bk += Itmp [j - 1]; + j++; + Rtmp [j - 1] = Re [k1] - Re [k2]; + Itmp [j - 1] = Im [k1] - Im [k2]; + k1 += kspan; + } while (k1 < k2); + Re [kk] = ak; + Im [kk] = bk; + k1 = kk; + k2 = kk + ispan; + j = 1; + do { + k1 += kspan; + k2 -= kspan; + jj = j; + ak = aa; + bk = bb; + aj = 0.0; + bj = 0.0; + k = 1; + do { + k++; + ak += Rtmp [k - 1] * Cos [jj - 1]; + bk += Itmp [k - 1] * Cos [jj - 1]; + k++; + aj += Rtmp [k - 1] * Sin [jj - 1]; + bj += Itmp [k - 1] * Sin [jj - 1]; + jj += j; + if (jj > jf) { + jj -= jf; + } + } while (k < jf); + k = jf - j; + Re [k1] = ak - bj; + Im [k1] = bk + aj; + Re [k2] = ak + bj; + Im [k2] = bk - aj; + j++; + } while (j < k); + kk += ispan; + } while (kk < nn); + kk -= nn; + } while (kk < kspan); + break; + } + + /* multiply by rotation factor (except for factors of 2 and 4) */ + if (ii == mfactor) + goto Permute_Results_Label; /* exit infinite loop */ + kk = jc; + do { + c2 = 1.0 - cd; + s1 = sd; + do { + c1 = c2; + s2 = s1; + kk += kspan; + do { + do { + ak = Re [kk]; + Re [kk] = c2 * ak - s2 * Im [kk]; + Im [kk] = s2 * ak + c2 * Im [kk]; + kk += ispan; + } while (kk < nt); + ak = s1 * s2; + s2 = s1 * c2 + c1 * s2; + c2 = c1 * c2 - ak; + kk = kk - nt + kspan; + } while (kk < ispan); + c2 = c1 - (cd * c1 + sd * s1); + s1 += sd * c1 - cd * s1; + c1 = 2.0 - (c2 * c2 + s1 * s1); + s1 *= c1; + c2 *= c1; + kk = kk - ispan + jc; + } while (kk < kspan); + kk = kk - kspan + jc + inc; + } while (kk < (jc + jc)); + break; +#endif /* FFT_RADIX4 */ + } + } + + /* permute the results to normal order---done in two stages */ + /* permutation for square factors of n */ +Permute_Results_Label: + fftstate->Perm [0] = ns; + if (kt) { + k = kt + kt + 1; + if (mfactor < k) + k--; + j = 1; + fftstate->Perm [k] = jc; + do { + fftstate->Perm [j] = fftstate->Perm [j - 1] / fftstate->factor [j - 1]; + fftstate->Perm [k - 1] = fftstate->Perm [k] * fftstate->factor [j - 1]; + j++; + k--; + } while (j < k); + k3 = fftstate->Perm [k]; + kspan = fftstate->Perm [1]; + kk = jc; + k2 = kspan; + j = 1; + if (nPass != nTotal) { + /* permutation for multivariate transform */ + Permute_Multi_Label: + do { + do { + k = kk + jc; + do { + /* swap Re [kk] <> Re [k2], Im [kk] <> Im [k2] */ + ak = Re [kk]; Re [kk] = Re [k2]; Re [k2] = ak; + bk = Im [kk]; Im [kk] = Im [k2]; Im [k2] = bk; + kk += inc; + k2 += inc; + } while (kk < (k-1)); + kk += ns - jc; + k2 += ns - jc; + } while (kk < (nt-1)); + k2 = k2 - nt + kspan; + kk = kk - nt + jc; + } while (k2 < (ns-1)); + do { + do { + k2 -= fftstate->Perm [j - 1]; + j++; + k2 = fftstate->Perm [j] + k2; + } while (k2 > fftstate->Perm [j - 1]); + j = 1; + do { + if (kk < (k2-1)) + goto Permute_Multi_Label; + kk += jc; + k2 += kspan; + } while (k2 < (ns-1)); + } while (kk < (ns-1)); + } else { + /* permutation for single-variate transform (optional code) */ + Permute_Single_Label: + do { + /* swap Re [kk] <> Re [k2], Im [kk] <> Im [k2] */ + ak = Re [kk]; Re [kk] = Re [k2]; Re [k2] = ak; + bk = Im [kk]; Im [kk] = Im [k2]; Im [k2] = bk; + kk += inc; + k2 += kspan; + } while (k2 < (ns-1)); + do { + do { + k2 -= fftstate->Perm [j - 1]; + j++; + k2 = fftstate->Perm [j] + k2; + } while (k2 >= fftstate->Perm [j - 1]); + j = 1; + do { + if (kk < k2) + goto Permute_Single_Label; + kk += inc; + k2 += kspan; + } while (k2 < (ns-1)); + } while (kk < (ns-1)); + } + jc = k3; + } + + if ((kt << 1) + 1 >= mfactor) + return 0; + ispan = fftstate->Perm [kt]; + /* permutation for square-free factors of n */ + j = mfactor - kt; + fftstate->factor [j] = 1; + do { + fftstate->factor [j - 1] *= fftstate->factor [j]; + j--; + } while (j != kt); + kt++; + nn = fftstate->factor [kt - 1] - 1; + if (nn > (int) max_perm) { + return -1; + } + j = jj = 0; + for (;;) { + k = kt + 1; + k2 = fftstate->factor [kt - 1]; + kk = fftstate->factor [k - 1]; + j++; + if (j > nn) + break; /* exit infinite loop */ + jj += kk; + while (jj >= k2) { + jj -= k2; + k2 = kk; + k++; + kk = fftstate->factor [k - 1]; + jj += kk; + } + fftstate->Perm [j - 1] = jj; + } + /* determine the permutation cycles of length greater than 1 */ + j = 0; + for (;;) { + do { + j++; + kk = fftstate->Perm [j - 1]; + } while (kk < 0); + if (kk != j) { + do { + k = kk; + kk = fftstate->Perm [k - 1]; + fftstate->Perm [k - 1] = -kk; + } while (kk != j); + k3 = kk; + } else { + fftstate->Perm [j - 1] = -j; + if (j == nn) + break; /* exit infinite loop */ + } + } + max_factors *= inc; + /* reorder a and b, following the permutation cycles */ + for (;;) { + j = k3 + 1; + nt -= ispan; + ii = nt - inc + 1; + if (nt < 0) + break; /* exit infinite loop */ + do { + do { + j--; + } while (fftstate->Perm [j - 1] < 0); + jj = jc; + do { + kspan = jj; + if (jj > max_factors) { + kspan = max_factors; + } + jj -= kspan; + k = fftstate->Perm [j - 1]; + kk = jc * k + ii + jj; + k1 = kk + kspan - 1; + k2 = 0; + do { + k2++; + Rtmp [k2 - 1] = Re [k1]; + Itmp [k2 - 1] = Im [k1]; + k1 -= inc; + } while (k1 != (kk-1)); + do { + k1 = kk + kspan - 1; + k2 = k1 - jc * (k + fftstate->Perm [k - 1]); + k = -fftstate->Perm [k - 1]; + do { + Re [k1] = Re [k2]; + Im [k1] = Im [k2]; + k1 -= inc; + k2 -= inc; + } while (k1 != (kk-1)); + kk = k2 + 1; + } while (k != j); + k1 = kk + kspan - 1; + k2 = 0; + do { + k2++; + Re [k1] = Rtmp [k2 - 1]; + Im [k1] = Itmp [k2 - 1]; + k1 -= inc; + } while (k1 != (kk-1)); + } while (jj); + } while (j != 1); + } + return 0; /* exit point here */ +} +/* ---------------------- end-of-file (c source) ---------------------- */ + diff --git a/libs/miniwebrtc/audio/coding_isac/main/fft.h b/libs/miniwebrtc/audio/coding_isac/main/fft.h new file mode 100644 index 00000000..a42f57bc --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/fft.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/*--------------------------------*-C-*---------------------------------* + * File: + * fftn.h + * ---------------------------------------------------------------------* + * Re[]: real value array + * Im[]: imaginary value array + * nTotal: total number of complex values + * nPass: number of elements involved in this pass of transform + * nSpan: nspan/nPass = number of bytes to increment pointer + * in Re[] and Im[] + * isign: exponent: +1 = forward -1 = reverse + * scaling: normalizing constant by which the final result is *divided* + * scaling == -1, normalize by total dimension of the transform + * scaling < -1, normalize by the square-root of the total dimension + * + * ---------------------------------------------------------------------- + * See the comments in the code for correct usage! + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FFT_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FFT_H_ + + +#include "structs.h" + + +/* double precision routine */ + + +int WebRtcIsac_Fftns (unsigned int ndim, const int dims[], double Re[], double Im[], + int isign, double scaling, FFTstr *fftstate); + + + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_FFT_H_ */ diff --git a/libs/miniwebrtc/audio/coding_isac/main/filter_functions.c b/libs/miniwebrtc/audio/coding_isac/main/filter_functions.c new file mode 100644 index 00000000..33024a3d --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/filter_functions.c @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include +#ifdef WEBRTC_ANDROID +#include +#endif +#include "pitch_estimator.h" +#include "lpc_analysis.h" +#include "codec.h" + + + +void WebRtcIsac_AllPoleFilter(double *InOut, double *Coef, int lengthInOut, int orderCoef){ + + /* the state of filter is assumed to be in InOut[-1] to InOut[-orderCoef] */ + double scal; + double sum; + int n,k; + + //if (fabs(Coef[0]-1.0)<0.001) { + if ( (Coef[0] > 0.9999) && (Coef[0] < 1.0001) ) + { + for(n = 0; n < lengthInOut; n++) + { + sum = Coef[1] * InOut[-1]; + for(k = 2; k <= orderCoef; k++){ + sum += Coef[k] * InOut[-k]; + } + *InOut++ -= sum; + } + } + else + { + scal = 1.0 / Coef[0]; + for(n=0;nbuffer, sizeof(double) * PITCH_WLPCBUFLEN); + memcpy(tmpbuffer+PITCH_WLPCBUFLEN, in, sizeof(double) * PITCH_FRAME_LEN); + memcpy(wfdata->buffer, tmpbuffer+PITCH_FRAME_LEN, sizeof(double) * PITCH_WLPCBUFLEN); + + dp=weoutbuf; + dp2=whoutbuf; + for (k=0;kweostate[k]; + *dp2++ = wfdata->whostate[k]; + opol[k]=0.0; + } + opol[0]=1.0; + opol[PITCH_WLPCORDER]=0.0; + weo=dp; + who=dp2; + + endpos=PITCH_WLPCBUFLEN + PITCH_SUBFRAME_LEN; + inp=tmpbuffer + PITCH_WLPCBUFLEN; + + for (n=0; nwindow[k]*tmpbuffer[start+k]; + } + + /* Get LPC polynomial */ + WebRtcIsac_AutoCorr(corr, ext, PITCH_WLPCWINLEN, PITCH_WLPCORDER); + corr[0]=1.01*corr[0]+1.0; /* White noise correction */ + WebRtcIsac_LevDurb(apol, rc, corr, PITCH_WLPCORDER); + WebRtcIsac_BwExpand(apolr, apol, rho, PITCH_WLPCORDER+1); + + /* Filtering */ + WebRtcIsac_ZeroPoleFilter(inp, apol, apolr, PITCH_SUBFRAME_LEN, PITCH_WLPCORDER, weo); + WebRtcIsac_ZeroPoleFilter(inp, apolr, opol, PITCH_SUBFRAME_LEN, PITCH_WLPCORDER, who); + + inp+=PITCH_SUBFRAME_LEN; + endpos+=PITCH_SUBFRAME_LEN; + weo+=PITCH_SUBFRAME_LEN; + who+=PITCH_SUBFRAME_LEN; + } + + /* Export filter states */ + for (k=0;kweostate[k]=weoutbuf[PITCH_FRAME_LEN+k]; + wfdata->whostate[k]=whoutbuf[PITCH_FRAME_LEN+k]; + } + + /* Export output data */ + memcpy(weiout, weoutbuf+PITCH_WLPCORDER, sizeof(double) * PITCH_FRAME_LEN); + memcpy(whiout, whoutbuf+PITCH_WLPCORDER, sizeof(double) * PITCH_FRAME_LEN); +} + + +static const double APupper[ALLPASSSECTIONS] = {0.0347, 0.3826}; +static const double APlower[ALLPASSSECTIONS] = {0.1544, 0.744}; + + + +void WebRtcIsac_AllpassFilterForDec(double *InOut, + const double *APSectionFactors, + int lengthInOut, + double *FilterState) +{ + //This performs all-pass filtering--a series of first order all-pass sections are used + //to filter the input in a cascade manner. + int n,j; + double temp; + for (j=0; jINLABUFx arrays + each of length QLOOKAHEAD. + The remaining FRAMESAMPLES_HALF-QLOOKAHEAD samples are based + on the first FRAMESAMPLES_HALF-QLOOKAHEAD samples of the input + array in[]. + HP: a FRAMESAMPLES_HALF array of high-pass filtered samples that + have been phase equalized. The first QLOOKAHEAD samples are + based on the samples in the two prefiltdata->INLABUFx arrays + each of length QLOOKAHEAD. + The remaining FRAMESAMPLES_HALF-QLOOKAHEAD samples are based + on the first FRAMESAMPLES_HALF-QLOOKAHEAD samples of the input + array in[]. + + LP_la: a FRAMESAMPLES_HALF array of low-pass filtered samples. + These samples are not phase equalized. They are computed + from the samples in the in[] array. + HP_la: a FRAMESAMPLES_HALF array of high-pass filtered samples + that are not phase equalized. They are computed from + the in[] vector. + prefiltdata: this input data structure's filterbank state and + lookahead sample buffers are updated for the next + encoding iteration. +*/ +void WebRtcIsac_SplitAndFilterFloat(float *pin, float *LP, float *HP, + double *LP_la, double *HP_la, + PreFiltBankstr *prefiltdata) +{ + int k,n; + float CompositeAPFilterState[NUMBEROFCOMPOSITEAPSECTIONS]; + float ForTransform_CompositeAPFilterState[NUMBEROFCOMPOSITEAPSECTIONS]; + float ForTransform_CompositeAPFilterState2[NUMBEROFCOMPOSITEAPSECTIONS]; + float tempinoutvec[FRAMESAMPLES+MAX_AR_MODEL_ORDER]; + float tempin_ch1[FRAMESAMPLES+MAX_AR_MODEL_ORDER]; + float tempin_ch2[FRAMESAMPLES+MAX_AR_MODEL_ORDER]; + float in[FRAMESAMPLES]; + float ftmp; + + + /* High pass filter */ + + for (k=0;kHPstates_float[0] + + kHpStCoefInFloat[3] * prefiltdata->HPstates_float[1]; + ftmp = pin[k] - kHpStCoefInFloat[0] * prefiltdata->HPstates_float[0] - + kHpStCoefInFloat[1] * prefiltdata->HPstates_float[1]; + prefiltdata->HPstates_float[1] = prefiltdata->HPstates_float[0]; + prefiltdata->HPstates_float[0] = ftmp; + } + + /* + % backwards all-pass filtering to obtain zero-phase + [tmp1(N2+LA:-1:LA+1, 1), state1] = filter(Q.coef, Q.coef(end:-1:1), in(N:-2:2)); + tmp1(LA:-1:1) = filter(Q.coef, Q.coef(end:-1:1), Q.LookAheadBuf1, state1); + Q.LookAheadBuf1 = in(N:-2:N-2*LA+2); + */ + /*Backwards all-pass filter the odd samples of the input (upper channel) + to eventually obtain zero phase. The composite all-pass filter (comprised of both + the upper and lower channel all-pass filsters in series) is used for the + filtering. */ + + /* First Channel */ + + /*initial state of composite filter is zero */ + for (k=0;kINLABUF1_float, + WebRtcIsac_kCompositeApFactorsFloat, QLOOKAHEAD, + NUMBEROFCOMPOSITEAPSECTIONS, CompositeAPFilterState); + + /* save the output, but write it in forward order */ + /* write the lookahead samples for the next encoding iteration. Every other + sample at the end of the input frame is written in reverse order for the + lookahead length. Exported in the prefiltdata structure. */ + for (k=0;kINLABUF1_float[k]; + prefiltdata->INLABUF1_float[k]=in[FRAMESAMPLES-1-2*k]; + } + + /* Second Channel. This is exactly like the first channel, except that the + even samples are now filtered instead (lower channel). */ + for (k=0;kINLABUF2_float, + WebRtcIsac_kCompositeApFactorsFloat, QLOOKAHEAD,NUMBEROFCOMPOSITEAPSECTIONS, + CompositeAPFilterState); + + for (k=0;kINLABUF2_float[k]; + prefiltdata->INLABUF2_float[k]=in[FRAMESAMPLES-2-2*k]; + } + + /* Transform filter states from backward to forward */ + /*At this point, each of the states of the backwards composite filters for the + two channels are transformed into forward filtering states for the corresponding + forward channel filters. Each channel's forward filtering state from the previous + encoding iteration is added to the transformed state to get a proper forward state */ + + /* So the existing NUMBEROFCOMPOSITEAPSECTIONS x 1 (4x1) state vector is multiplied by a + NUMBEROFCHANNELAPSECTIONSxNUMBEROFCOMPOSITEAPSECTIONS (2x4) transform matrix to get the + new state that is added to the previous 2x1 input state */ + + for (k=0;kINSTAT1_float[k] += ForTransform_CompositeAPFilterState[n]* + WebRtcIsac_kTransform1Float[k*NUMBEROFCHANNELAPSECTIONS+n]; + prefiltdata->INSTAT2_float[k] += ForTransform_CompositeAPFilterState2[n]* + WebRtcIsac_kTransform2Float[k*NUMBEROFCHANNELAPSECTIONS+n]; + } + } + + /*obtain polyphase components by forward all-pass filtering through each channel */ + /* the backward filtered samples are now forward filtered with the corresponding channel filters */ + /* The all pass filtering automatically updates the filter states which are exported in the + prefiltdata structure */ + WebRtcIsac_AllPassFilter2Float(tempin_ch1,WebRtcIsac_kUpperApFactorsFloat, + FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTAT1_float); + WebRtcIsac_AllPassFilter2Float(tempin_ch2,WebRtcIsac_kLowerApFactorsFloat, + FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTAT2_float); + + /* Now Construct low-pass and high-pass signals as combinations of polyphase components */ + for (k=0; kINSTATLA1_float); + WebRtcIsac_AllPassFilter2Float(tempin_ch2,WebRtcIsac_kLowerApFactorsFloat, + FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS, prefiltdata->INSTATLA2_float); + + for (k=0; kSTATE_0_UPPER_float); + + /* Now, all-pass filter the new lower channel signal. But since all-pass filter factors + at the decoder are swapped from the ones at the encoder, the 'upper' channel + all-pass filter factors (WebRtcIsac_kUpperApFactorsFloat) are used to filter this new + lower channel signal */ + WebRtcIsac_AllPassFilter2Float(tempin_ch2, WebRtcIsac_kUpperApFactorsFloat, + FRAMESAMPLES_HALF, NUMBEROFCHANNELAPSECTIONS,postfiltdata->STATE_0_LOWER_float); + + + /* Merge outputs to form the full length output signal.*/ + for (k=0;kHPstates1_float[0] + + kHpStCoefOut1Float[3] * postfiltdata->HPstates1_float[1]; + ftmp = Out[k] - kHpStCoefOut1Float[0] * postfiltdata->HPstates1_float[0] - + kHpStCoefOut1Float[1] * postfiltdata->HPstates1_float[1]; + postfiltdata->HPstates1_float[1] = postfiltdata->HPstates1_float[0]; + postfiltdata->HPstates1_float[0] = ftmp; + Out[k] = ftmp2; + } + + for (k=0;kHPstates2_float[0] + + kHpStCoefOut2Float[3] * postfiltdata->HPstates2_float[1]; + ftmp = Out[k] - kHpStCoefOut2Float[0] * postfiltdata->HPstates2_float[0] - + kHpStCoefOut2Float[1] * postfiltdata->HPstates2_float[1]; + postfiltdata->HPstates2_float[1] = postfiltdata->HPstates2_float[0]; + postfiltdata->HPstates2_float[0] = ftmp; + Out[k] = ftmp2; + } +} diff --git a/libs/miniwebrtc/audio/coding_isac/main/intialize.c b/libs/miniwebrtc/audio/coding_isac/main/intialize.c new file mode 100644 index 00000000..6df034d1 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/intialize.c @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* encode.c - Encoding function for the iSAC coder */ + +#include "structs.h" +#include "codec.h" +#include "pitch_estimator.h" + +#include + +void WebRtcIsac_InitMasking(MaskFiltstr *maskdata) { + + int k; + + for (k = 0; k < WINLEN; k++) { + maskdata->DataBufferLo[k] = 0.0; + maskdata->DataBufferHi[k] = 0.0; + } + for (k = 0; k < ORDERLO+1; k++) { + maskdata->CorrBufLo[k] = 0.0; + maskdata->PreStateLoF[k] = 0.0; + maskdata->PreStateLoG[k] = 0.0; + maskdata->PostStateLoF[k] = 0.0; + maskdata->PostStateLoG[k] = 0.0; + } + for (k = 0; k < ORDERHI+1; k++) { + maskdata->CorrBufHi[k] = 0.0; + maskdata->PreStateHiF[k] = 0.0; + maskdata->PreStateHiG[k] = 0.0; + maskdata->PostStateHiF[k] = 0.0; + maskdata->PostStateHiG[k] = 0.0; + } + + maskdata->OldEnergy = 10.0; + + /* fill tables for transforms */ + WebRtcIsac_InitTransform(); + + return; +} + +void WebRtcIsac_InitPreFilterbank(PreFiltBankstr *prefiltdata) +{ + int k; + + for (k = 0; k < QLOOKAHEAD; k++) { + prefiltdata->INLABUF1[k] = 0; + prefiltdata->INLABUF2[k] = 0; + + prefiltdata->INLABUF1_float[k] = 0; + prefiltdata->INLABUF2_float[k] = 0; + } + for (k = 0; k < 2*(QORDER-1); k++) { + prefiltdata->INSTAT1[k] = 0; + prefiltdata->INSTAT2[k] = 0; + prefiltdata->INSTATLA1[k] = 0; + prefiltdata->INSTATLA2[k] = 0; + + prefiltdata->INSTAT1_float[k] = 0; + prefiltdata->INSTAT2_float[k] = 0; + prefiltdata->INSTATLA1_float[k] = 0; + prefiltdata->INSTATLA2_float[k] = 0; + } + + /* High pass filter states */ + prefiltdata->HPstates[0] = 0.0; + prefiltdata->HPstates[1] = 0.0; + + prefiltdata->HPstates_float[0] = 0.0f; + prefiltdata->HPstates_float[1] = 0.0f; + + return; +} + +void WebRtcIsac_InitPostFilterbank(PostFiltBankstr *postfiltdata) +{ + int k; + + for (k = 0; k < 2*POSTQORDER; k++) { + postfiltdata->STATE_0_LOWER[k] = 0; + postfiltdata->STATE_0_UPPER[k] = 0; + + postfiltdata->STATE_0_LOWER_float[k] = 0; + postfiltdata->STATE_0_UPPER_float[k] = 0; + } + + /* High pass filter states */ + postfiltdata->HPstates1[0] = 0.0; + postfiltdata->HPstates1[1] = 0.0; + + postfiltdata->HPstates2[0] = 0.0; + postfiltdata->HPstates2[1] = 0.0; + + postfiltdata->HPstates1_float[0] = 0.0f; + postfiltdata->HPstates1_float[1] = 0.0f; + + postfiltdata->HPstates2_float[0] = 0.0f; + postfiltdata->HPstates2_float[1] = 0.0f; + + return; +} + + +void WebRtcIsac_InitPitchFilter(PitchFiltstr *pitchfiltdata) +{ + int k; + + for (k = 0; k < PITCH_BUFFSIZE; k++) { + pitchfiltdata->ubuf[k] = 0.0; + } + pitchfiltdata->ystate[0] = 0.0; + for (k = 1; k < (PITCH_DAMPORDER); k++) { + pitchfiltdata->ystate[k] = 0.0; + } + pitchfiltdata->oldlagp[0] = 50.0; + pitchfiltdata->oldgainp[0] = 0.0; +} + +void WebRtcIsac_InitWeightingFilter(WeightFiltstr *wfdata) +{ + int k; + double t, dtmp, dtmp2, denum, denum2; + + for (k=0;kbuffer[k]=0.0; + + for (k=0;kistate[k]=0.0; + wfdata->weostate[k]=0.0; + wfdata->whostate[k]=0.0; + } + + /* next part should be in Matlab, writing to a global table */ + t = 0.5; + denum = 1.0 / ((double) PITCH_WLPCWINLEN); + denum2 = denum * denum; + for (k=0;kwindow[k] = dtmp2 * dtmp2; + t++; + } +} + +/* clear all buffers */ +void WebRtcIsac_InitPitchAnalysis(PitchAnalysisStruct *State) +{ + int k; + + for (k = 0; k < PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2; k++) + State->dec_buffer[k] = 0.0; + for (k = 0; k < 2*ALLPASSSECTIONS+1; k++) + State->decimator_state[k] = 0.0; + for (k = 0; k < 2; k++) + State->hp_state[k] = 0.0; + for (k = 0; k < QLOOKAHEAD; k++) + State->whitened_buf[k] = 0.0; + for (k = 0; k < QLOOKAHEAD; k++) + State->inbuf[k] = 0.0; + + WebRtcIsac_InitPitchFilter(&(State->PFstr_wght)); + + WebRtcIsac_InitPitchFilter(&(State->PFstr)); + + WebRtcIsac_InitWeightingFilter(&(State->Wghtstr)); +} diff --git a/libs/miniwebrtc/audio/coding_isac/main/isac.c b/libs/miniwebrtc/audio/coding_isac/main/isac.c new file mode 100644 index 00000000..67db1e4c --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/isac.c @@ -0,0 +1,2793 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * isac.c + * + * This C file contains the functions for the ISAC API + * + */ + +#include "isac.h" +#include "bandwidth_estimator.h" +#include "crc.h" +#include "entropy_coding.h" +#include "codec.h" +#include "structs.h" +#include "signal_processing_library.h" +#include "lpc_shape_swb16_tables.h" +#include "os_specific_inline.h" + +#include +#include +#include +#include + +#define BIT_MASK_DEC_INIT 0x0001 +#define BIT_MASK_ENC_INIT 0x0002 + +#define LEN_CHECK_SUM_WORD8 4 +#define MAX_NUM_LAYERS 10 + + +/**************************************************************************** + * UpdatePayloadSizeLimit() + * + * Call this function to update the limit on the payload size. The limit on + * payload size might change i) if a user ''directly changes the limit by + * calling xxx_setMaxPayloadSize() or xxx_setMaxRate(), or ii) indirectly + * when bandwidth is changing. The latter might be the result of bandwidth + * adaptation, or direct change of the bottleneck in instantaneous mode. + * + * This function takes the current overall limit on payload, and translate it + * to the limits on lower and upper-band. If the codec is in wideband mode + * then the overall limit and the limit on the lower-band is the same. + * Otherwise, a fraction of the limit should be allocated to lower-band + * leaving some room for the upper-band bit-stream. That is why an update + * of limit is required every time that the bandwidth is changing. + * + */ +static void UpdatePayloadSizeLimit( + ISACMainStruct *instISAC) +{ + WebRtc_Word16 lim30MsPayloadBytes; + WebRtc_Word16 lim60MsPayloadBytes; + + lim30MsPayloadBytes = WEBRTC_SPL_MIN( + (instISAC->maxPayloadSizeBytes), + (instISAC->maxRateBytesPer30Ms)); + + lim60MsPayloadBytes = WEBRTC_SPL_MIN( + (instISAC->maxPayloadSizeBytes), + (instISAC->maxRateBytesPer30Ms << 1)); + + // The only time that iSAC will have 60 ms + // frame-size is when operating in wideband so + // there is no upper-band bit-stream + + if(instISAC->bandwidthKHz == isac8kHz) + { + // at 8 kHz there is no upper-band bit-stream + // therefore the lower-band limit is as the overall + // limit. + instISAC->instLB.ISACencLB_obj.payloadLimitBytes60 = + lim60MsPayloadBytes; + instISAC->instLB.ISACencLB_obj.payloadLimitBytes30 = + lim30MsPayloadBytes; + } + else + { + // when in super-wideband, we only have 30 ms frames + // Do a rate allocation for the given limit. + if(lim30MsPayloadBytes > 250) + { + // 4/5 to lower-band the rest for upper-band + instISAC->instLB.ISACencLB_obj.payloadLimitBytes30 = + (lim30MsPayloadBytes << 2) / 5; + } + else if(lim30MsPayloadBytes > 200) + { + // for the interval of 200 to 250 the share of + // upper-band linearly grows from 20 to 50; + instISAC->instLB.ISACencLB_obj.payloadLimitBytes30 = + (lim30MsPayloadBytes << 1) / 5 + 100; + } + else + { + // allocate only 20 for upper-band + instISAC->instLB.ISACencLB_obj.payloadLimitBytes30 = + lim30MsPayloadBytes - 20; + } + instISAC->instUB.ISACencUB_obj.maxPayloadSizeBytes = + lim30MsPayloadBytes; + } +} + + +/**************************************************************************** + * UpdateBottleneck() + * + * This function updates the bottleneck only if the codec is operating in + * channel-adaptive mode. Furthermore, as the update of bottleneck might + * result in an update of bandwidth, therefore, the bottlenech should be + * updated just right before the first 10ms of a frame is pushed into encoder. + * + */ +static void UpdateBottleneck( + ISACMainStruct *instISAC) +{ + // read the bottleneck from bandwidth estimator for the + // first 10 ms audio. This way, if there is a change + // in bandwidth upper and lower-band will be in sync. + if((instISAC->codingMode == 0) && + (instISAC->instLB.ISACencLB_obj.buffer_index == 0) && + (instISAC->instLB.ISACencLB_obj.frame_nb == 0)) + { + WebRtc_Word32 bottleneck; + WebRtcIsac_GetUplinkBandwidth(&(instISAC->bwestimator_obj), + &bottleneck); + + // Adding hysteresis when increasing signal bandwidth + if((instISAC->bandwidthKHz == isac8kHz) + && (bottleneck > 37000) + && (bottleneck < 41000)) + { + bottleneck = 37000; + } + + // switching from 12 kHz to 16 kHz is not allowed at this revision + // If we let this happen, we have to take care of buffer_index and + // the last LPC vector. + if((instISAC->bandwidthKHz != isac16kHz) && + (bottleneck > 46000)) + { + bottleneck = 46000; + } + + // we might need a rate allocation. + if(instISAC->encoderSamplingRateKHz == kIsacWideband) + { + // wideband is the only choise we have here. + instISAC->instLB.ISACencLB_obj.bottleneck = + (bottleneck > 32000)? 32000:bottleneck; + instISAC->bandwidthKHz = isac8kHz; + } + else + { + // do the rate-allosation and get the new bandwidth. + enum ISACBandwidth bandwidth; + WebRtcIsac_RateAllocation(bottleneck, + &(instISAC->instLB.ISACencLB_obj.bottleneck), + &(instISAC->instUB.ISACencUB_obj.bottleneck), + &bandwidth); + if(bandwidth != isac8kHz) + { + instISAC->instLB.ISACencLB_obj.new_framelength = 480; + } + if(bandwidth != instISAC->bandwidthKHz) + { + // bandwidth is changing. + instISAC->bandwidthKHz = bandwidth; + UpdatePayloadSizeLimit(instISAC); + if(bandwidth == isac12kHz) + { + instISAC->instLB.ISACencLB_obj.buffer_index = 0; + } + // currently we don't let the bandwidth to switch to 16 kHz + // if in adaptive mode. If we let this happen, we have to take + // car of buffer_index and the last LPC vector. + } + } + } +} + + +/**************************************************************************** + * GetSendBandwidthInfo() + * + * This is called to get the bandwidth info. This info is the bandwidth and + * and the jitter of 'there-to-here' channel, estimated 'here.' These info + * is signaled in an in-band fashion to the otherside. + * + * The call to the bandwidth estimator trigers a recursive averaging which + * has to be synchronized between encoder & decoder, therefore. The call to + * BWE should be once per packet. As the BWE info is inserted into bit-stream + * we need a valid info right before the encodeLB function is going to + * generating a bit-stream. That is when lower-band buffer has already 20ms + * of audio, and the 3rd block of 10ms is going to be injected into encoder. + * + * Inputs: + * - instISAC : iSAC instance. + * + * Outputs: + * - bandwidthIndex : an index which has to be encoded in + * lower-band bit-stream, indicating the + * bandwidth of there-to-here channel. + * - jitterInfo : this indicates if the jitter is high + * or low and it is encoded in upper-band + * bit-stream. + * + */ +static void GetSendBandwidthInfo( + ISACMainStruct* instISAC, + WebRtc_Word16* bandwidthIndex, + WebRtc_Word16* jitterInfo) +{ + if((instISAC->instLB.ISACencLB_obj.buffer_index == + (FRAMESAMPLES_10ms << 1)) && + (instISAC->instLB.ISACencLB_obj.frame_nb == 0)) + { + /* bandwidth estimation and coding */ + WebRtcIsac_GetDownlinkBwJitIndexImpl(&(instISAC->bwestimator_obj), + bandwidthIndex, jitterInfo, instISAC->decoderSamplingRateKHz); + } +} + + +/**************************************************************************** + * WebRtcIsac_AssignSize(...) + * + * This function returns the size of the ISAC instance, so that the instance + * can be created out side iSAC. + * + * Output: + * - sizeinbytes : number of bytes needed to allocate for the + * instance. + * + * Return value : 0 - Ok + * -1 - Error + */ +WebRtc_Word16 WebRtcIsac_AssignSize( + int *sizeInBytes) +{ + *sizeInBytes = sizeof(ISACMainStruct) * 2 / sizeof(WebRtc_Word16); + return 0; +} + + +/**************************************************************************** + * WebRtcIsac_Assign(...) + * + * This function assignes the memory already created to the ISAC instance. + * + * Input: + * - ISAC_main_inst : address of the pointer to the coder instance. + * - instISAC_Addr : the already allocaded memeory, where we put the + * iSAC struct + * + * Return value : 0 - Ok + * -1 - Error + */ +WebRtc_Word16 WebRtcIsac_Assign( + ISACStruct** ISAC_main_inst, + void* instISAC_Addr) +{ + if(instISAC_Addr != NULL) + { + ISACMainStruct* instISAC = (ISACMainStruct*)instISAC_Addr; + instISAC->errorCode = 0; + instISAC->initFlag = 0; + + // Assign the address + *ISAC_main_inst = (ISACStruct*)instISAC_Addr; + + // Default is wideband. + instISAC->encoderSamplingRateKHz = kIsacWideband; + instISAC->decoderSamplingRateKHz = kIsacWideband; + instISAC->bandwidthKHz = isac8kHz; + return 0; + } + else + { + return -1; + } +} + + +/**************************************************************************** + * WebRtcIsac_Create(...) + * + * This function creates an ISAC instance, which will contain the state + * information for one coding/decoding channel. + * + * Input: + * - ISAC_main_inst : address of the pointer to the coder instance. + * + * Return value : 0 - Ok + * -1 - Error + */ +WebRtc_Word16 WebRtcIsac_Create( + ISACStruct** ISAC_main_inst) +{ + ISACMainStruct* instISAC; + + instISAC = (ISACMainStruct*)WEBRTC_SPL_VNEW(ISACMainStruct, 1); + *ISAC_main_inst = (ISACStruct*)instISAC; + if(*ISAC_main_inst != NULL) + { + instISAC->errorCode = 0; + instISAC->initFlag = 0; + // Default is wideband + instISAC->bandwidthKHz = isac8kHz; + instISAC->encoderSamplingRateKHz = kIsacWideband; + instISAC->decoderSamplingRateKHz = kIsacWideband; + return 0; + } + else + { + return -1; + } +} + + +/**************************************************************************** + * WebRtcIsac_Free(...) + * + * This function frees the ISAC instance created at the beginning. + * + * Input: + * - ISAC_main_inst : a ISAC instance. + * + * Return value : 0 - Ok + * -1 - Error + */ +WebRtc_Word16 WebRtcIsac_Free( + ISACStruct* ISAC_main_inst) +{ + ISACMainStruct* instISAC; + + instISAC = (ISACMainStruct*)ISAC_main_inst; + WEBRTC_SPL_FREE(instISAC); + return 0; +} + + +/**************************************************************************** + * EncoderInitLb(...) - internal function for initialization of + * Lower Band + * EncoderInitUb(...) - internal function for initialization of + * Upper Band + * WebRtcIsac_EncoderInit(...) - API function + * + * This function initializes a ISAC instance prior to the encoder calls. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - CodingMode : 0 -> Bit rate and frame length are automatically + * adjusted to available bandwidth on + * transmission channel, applicable just to + * wideband mode. + * 1 -> User sets a frame length and a target bit + * rate which is taken as the maximum + * short-term average bit rate. + * + * Return value : 0 - Ok + * -1 - Error + */ +static WebRtc_Word16 EncoderInitLb( + ISACLBStruct* instLB, + WebRtc_Word16 codingMode, + enum IsacSamplingRate sampRate) +{ + WebRtc_Word16 statusInit = 0; + int k; + + /* Init stream vector to zero */ + for(k=0; k < STREAM_SIZE_MAX_60; k++) + { + instLB->ISACencLB_obj.bitstr_obj.stream[k] = 0; + } + + if((codingMode == 1) || (sampRate == kIsacSuperWideband)) + { + // 30 ms frame-size if either in super-wideband or + // instanteneous mode (I-mode) + instLB->ISACencLB_obj.new_framelength = 480; + } + else + { + instLB->ISACencLB_obj.new_framelength = INITIAL_FRAMESAMPLES; + } + + WebRtcIsac_InitMasking(&instLB->ISACencLB_obj.maskfiltstr_obj); + WebRtcIsac_InitPreFilterbank(&instLB->ISACencLB_obj.prefiltbankstr_obj); + WebRtcIsac_InitPitchFilter(&instLB->ISACencLB_obj.pitchfiltstr_obj); + WebRtcIsac_InitPitchAnalysis( + &instLB->ISACencLB_obj.pitchanalysisstr_obj); + + + instLB->ISACencLB_obj.buffer_index = 0; + instLB->ISACencLB_obj.frame_nb = 0; + /* default for I-mode */ + instLB->ISACencLB_obj.bottleneck = 32000; + instLB->ISACencLB_obj.current_framesamples = 0; + instLB->ISACencLB_obj.s2nr = 0; + instLB->ISACencLB_obj.payloadLimitBytes30 = STREAM_SIZE_MAX_30; + instLB->ISACencLB_obj.payloadLimitBytes60 = STREAM_SIZE_MAX_60; + instLB->ISACencLB_obj.maxPayloadBytes = STREAM_SIZE_MAX_60; + instLB->ISACencLB_obj.maxRateInBytes = STREAM_SIZE_MAX_30; + instLB->ISACencLB_obj.enforceFrameSize = 0; + /* invalid value prevents getRedPayload to + run before encoder is called */ + instLB->ISACencLB_obj.lastBWIdx = -1; + return statusInit; +} + +static WebRtc_Word16 EncoderInitUb( + ISACUBStruct* instUB, + WebRtc_Word16 bandwidth) +{ + WebRtc_Word16 statusInit = 0; + int k; + + /* Init stream vector to zero */ + for(k = 0; k < STREAM_SIZE_MAX_60; k++) + { + instUB->ISACencUB_obj.bitstr_obj.stream[k] = 0; + } + + WebRtcIsac_InitMasking(&instUB->ISACencUB_obj.maskfiltstr_obj); + WebRtcIsac_InitPreFilterbank(&instUB->ISACencUB_obj.prefiltbankstr_obj); + + if(bandwidth == isac16kHz) + { + instUB->ISACencUB_obj.buffer_index = LB_TOTAL_DELAY_SAMPLES; + } + else + { + instUB->ISACencUB_obj.buffer_index = 0; + } + /* default for I-mode */ + instUB->ISACencUB_obj.bottleneck = 32000; + // These store the limits for the wideband + super-wideband bit-stream. + instUB->ISACencUB_obj.maxPayloadSizeBytes = STREAM_SIZE_MAX_30 << 1; + // This has to be updated after each lower-band encoding to guarantee + // a correct payload-limitation. + instUB->ISACencUB_obj.numBytesUsed = 0; + memset(instUB->ISACencUB_obj.data_buffer_float, 0, + (MAX_FRAMESAMPLES + LB_TOTAL_DELAY_SAMPLES) * sizeof(float)); + + memcpy(&(instUB->ISACencUB_obj.lastLPCVec), + WebRtcIsac_kMeanLarUb16, sizeof(double) * UB_LPC_ORDER); + + return statusInit; +} + + +WebRtc_Word16 WebRtcIsac_EncoderInit( + ISACStruct* ISAC_main_inst, + WebRtc_Word16 codingMode) +{ + ISACMainStruct *instISAC; + WebRtc_Word16 status; + + instISAC = (ISACMainStruct*)ISAC_main_inst; + + if((codingMode != 0) && (codingMode != 1)) + { + instISAC->errorCode = ISAC_DISALLOWED_CODING_MODE; + return -1; + } + // default bottleneck + instISAC->bottleneck = MAX_ISAC_BW; + + if(instISAC->encoderSamplingRateKHz == kIsacWideband) + { + instISAC->bandwidthKHz = isac8kHz; + instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX_60; + instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX_30; + } + else + { + instISAC->bandwidthKHz = isac16kHz; + instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX; + instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX; + } + + // Channel-adaptive = 0; Instantaneous (Channel-independent) = 1; + instISAC->codingMode = codingMode; + + WebRtcIsac_InitBandwidthEstimator(&instISAC->bwestimator_obj, + instISAC->encoderSamplingRateKHz, + instISAC->decoderSamplingRateKHz); + + WebRtcIsac_InitRateModel(&instISAC->rate_data_obj); + /* default for I-mode */ + instISAC->MaxDelay = 10.0; + + status = EncoderInitLb(&instISAC->instLB, codingMode, + instISAC->encoderSamplingRateKHz); + if(status < 0) + { + instISAC->errorCode = -status; + return -1; + } + + if(instISAC->encoderSamplingRateKHz == kIsacSuperWideband) + { + // Initialize encoder filter-bank. + memset(instISAC->analysisFBState1, 0, + FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32)); + memset(instISAC->analysisFBState2, 0, + FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32)); + + status = EncoderInitUb(&(instISAC->instUB), + instISAC->bandwidthKHz); + if(status < 0) + { + instISAC->errorCode = -status; + return -1; + } + } + // Initializtion is successful, set the flag + instISAC->initFlag |= BIT_MASK_ENC_INIT; + return 0; +} + + +/**************************************************************************** + * WebRtcIsac_Encode(...) + * + * This function encodes 10ms frame(s) and inserts it into a package. + * Input speech length has to be 160 samples (10ms). The encoder buffers those + * 10ms frames until it reaches the chosen Framesize (480 or 960 samples + * corresponding to 30 or 60 ms frames), and then proceeds to the encoding. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - speechIn : input speech vector. + * + * Output: + * - encoded : the encoded data vector + * + * Return value: + * : >0 - Length (in bytes) of coded data + * : 0 - The buffer didn't reach the chosen + * frameSize so it keeps buffering speech + * samples. + * : -1 - Error + */ +WebRtc_Word16 WebRtcIsac_Encode( + ISACStruct* ISAC_main_inst, + const WebRtc_Word16* speechIn, + WebRtc_Word16* encoded) +{ + ISACMainStruct* instISAC; + ISACLBStruct* instLB; + ISACUBStruct* instUB; + + float inFrame[FRAMESAMPLES_10ms]; + WebRtc_Word16 speechInLB[FRAMESAMPLES_10ms]; + WebRtc_Word16 speechInUB[FRAMESAMPLES_10ms]; + WebRtc_Word16 streamLenLB = 0; + WebRtc_Word16 streamLenUB = 0; + WebRtc_Word16 streamLen = 0; + WebRtc_Word16 k = 0; + WebRtc_UWord8* ptrEncodedUW8 = (WebRtc_UWord8*)encoded; + int garbageLen = 0; + WebRtc_Word32 bottleneck = 0; + WebRtc_Word16 bottleneckIdx = 0; + WebRtc_Word16 jitterInfo = 0; + + instISAC = (ISACMainStruct*)ISAC_main_inst; + instLB = &(instISAC->instLB); + instUB = &(instISAC->instUB); + + /* check if encoder initiated */ + if((instISAC->initFlag & BIT_MASK_ENC_INIT) != + BIT_MASK_ENC_INIT) + { + instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; + return -1; + } + + if(instISAC->encoderSamplingRateKHz == kIsacSuperWideband) + { + WebRtcSpl_AnalysisQMF(speechIn, speechInLB, speechInUB, + instISAC->analysisFBState1, instISAC->analysisFBState2); + + /* convert from fixed to floating point */ + for(k = 0; k < FRAMESAMPLES_10ms; k++) + { + inFrame[k] = (float)speechInLB[k]; + } + } + else + { + for(k = 0; k < FRAMESAMPLES_10ms; k++) + { + inFrame[k] = (float) speechIn[k]; + } + } + + /* add some noise to avoid denormal numbers */ + inFrame[0] += (float)1.23455334e-3; + inFrame[1] -= (float)2.04324239e-3; + inFrame[2] += (float)1.90854954e-3; + inFrame[9] += (float)1.84854878e-3; + + + // This function will update the bottleneck if required + UpdateBottleneck(instISAC); + + // Get the bandwith information which has to be sent to the other side + GetSendBandwidthInfo(instISAC, &bottleneckIdx, &jitterInfo); + + // + // ENCODE LOWER-BAND + // + streamLenLB = WebRtcIsac_EncodeLb(inFrame, &instLB->ISACencLB_obj, + instISAC->codingMode, bottleneckIdx); + + if(streamLenLB < 0) + { + return -1; + } + + if(instISAC->encoderSamplingRateKHz == kIsacSuperWideband) + { + instUB = &(instISAC->instUB); + + // convert to float + for(k = 0; k < FRAMESAMPLES_10ms; k++) + { + inFrame[k] = (float) speechInUB[k]; + } + + /* add some noise to avoid denormal numbers */ + inFrame[0] += (float)1.23455334e-3; + inFrame[1] -= (float)2.04324239e-3; + inFrame[2] += (float)1.90854954e-3; + inFrame[9] += (float)1.84854878e-3; + + // Tell to upper-band the number of bytes used so far. + // This is for payload limitation. + instUB->ISACencUB_obj.numBytesUsed = streamLenLB + 1 + + LEN_CHECK_SUM_WORD8; + + // + // ENCODE UPPER-BAND + // + switch(instISAC->bandwidthKHz) + { + case isac12kHz: + { + streamLenUB = WebRtcIsac_EncodeUb12(inFrame, + &instUB->ISACencUB_obj, + jitterInfo); + break; + } + case isac16kHz: + { + streamLenUB = WebRtcIsac_EncodeUb16(inFrame, + &instUB->ISACencUB_obj, + jitterInfo); + break; + } + case isac8kHz: + { + streamLenUB = 0; + break; + } + } + + if((streamLenUB < 0) && + (streamLenUB != -ISAC_PAYLOAD_LARGER_THAN_LIMIT)) + { + // an error has happened but this is not the error due to a + // bit-stream larger than the limit + return -1; + } + + if(streamLenLB == 0) + { + return 0; + } + + // One bite is allocated for the length. According to older decoders + // so the length bit-stream plus one byte for size and + // LEN_CHECK_SUM_WORD8 for the checksum should be less than or equal + // to 255. + if((streamLenUB > (255 - (LEN_CHECK_SUM_WORD8 + 1))) || + (streamLenUB == -ISAC_PAYLOAD_LARGER_THAN_LIMIT)) + { + // we have got a too long bit-stream we skip the upper-band + // bit-stream for this frame. + streamLenUB = 0; + } + + memcpy(ptrEncodedUW8, instLB->ISACencLB_obj.bitstr_obj.stream, + streamLenLB); + streamLen = streamLenLB; + if(streamLenUB > 0) + { + ptrEncodedUW8[streamLenLB] = (WebRtc_UWord8)(streamLenUB + 1 + + LEN_CHECK_SUM_WORD8); + memcpy(&ptrEncodedUW8[streamLenLB + 1], + instUB->ISACencUB_obj.bitstr_obj.stream, streamLenUB); + streamLen += ptrEncodedUW8[streamLenLB]; + } + else + { + ptrEncodedUW8[streamLenLB] = 0; + } + } + else + { + if(streamLenLB == 0) + { + return 0; + } + memcpy(ptrEncodedUW8, instLB->ISACencLB_obj.bitstr_obj.stream, + streamLenLB); + streamLenUB = 0; + streamLen = streamLenLB; + } + + // Add Garbage if required. + WebRtcIsac_GetUplinkBandwidth(&instISAC->bwestimator_obj, &bottleneck); + if(instISAC->codingMode == 0) + { + int minBytes; + int limit; + WebRtc_UWord8* ptrGarbage; + + instISAC->MaxDelay = (double)WebRtcIsac_GetUplinkMaxDelay( + &instISAC->bwestimator_obj); + + /* update rate model and get minimum number of bytes in this packet */ + minBytes = WebRtcIsac_GetMinBytes(&(instISAC->rate_data_obj), + streamLen, instISAC->instLB.ISACencLB_obj.current_framesamples, + bottleneck, instISAC->MaxDelay, instISAC->bandwidthKHz); + + /* Make sure MinBytes does not exceed packet size limit */ + if(instISAC->bandwidthKHz == isac8kHz) + { + if(instLB->ISACencLB_obj.current_framesamples == FRAMESAMPLES) + { + limit = instLB->ISACencLB_obj.payloadLimitBytes30; + } + else + { + limit = instLB->ISACencLB_obj.payloadLimitBytes60; + } + } + else + { + limit = instUB->ISACencUB_obj.maxPayloadSizeBytes; + } + minBytes = (minBytes > limit)? limit:minBytes; + + /* Make sure we don't allow more than 255 bytes of garbage data. + We store the length of the garbage data in 8 bits in the bitstream, + 255 is the max garbage length we can signal using 8 bits. */ + if((instISAC->bandwidthKHz == isac8kHz) || + (streamLenUB == 0)) + { + ptrGarbage = &ptrEncodedUW8[streamLenLB]; + limit = streamLen + 255; + } + else + { + ptrGarbage = &ptrEncodedUW8[streamLenLB + 1 + streamLenUB]; + limit = streamLen + (255 - ptrEncodedUW8[streamLenLB]); + } + minBytes = (minBytes > limit)? limit:minBytes; + + garbageLen = (minBytes > streamLen)? (minBytes - streamLen):0; + + /* Save data for creation of multiple bitstreams */ + //ISACencLB_obj->SaveEnc_obj.minBytes = MinBytes; + + /* if bitstream is too short, add garbage at the end */ + if(garbageLen > 0) + { + for(k = 0; k < garbageLen; k++) + { + ptrGarbage[k] = (WebRtc_UWord8)(rand() & 0xFF); + } + + // for a correct length of the upper-band bit-stream together + // with the garbage. Garbage is embeded in upper-band bit-stream. + // That is the only way to preserve backward compatibility. + if((instISAC->bandwidthKHz == isac8kHz) || + (streamLenUB == 0)) + { + ptrEncodedUW8[streamLenLB] = (WebRtc_UWord8)garbageLen; + } + else + { + ptrEncodedUW8[streamLenLB] += (WebRtc_UWord8)garbageLen; + // write the length of the garbage at the end of the upper-band + // bit-stream, if exists. This helps for sanity check. + ptrEncodedUW8[streamLenLB + 1 + streamLenUB] = (WebRtc_UWord8)garbageLen; + + } + + streamLen += garbageLen; + } + } + else + { + /* update rate model */ + WebRtcIsac_UpdateRateModel(&instISAC->rate_data_obj, streamLen, + instISAC->instLB.ISACencLB_obj.current_framesamples, bottleneck); + garbageLen = 0; + } + + // Generate CRC if required. + if((instISAC->bandwidthKHz != isac8kHz) && + (streamLenUB > 0)) + { + WebRtc_UWord32 crc; + + WebRtcIsac_GetCrc((WebRtc_Word16*)(&(ptrEncodedUW8[streamLenLB + 1])), + streamLenUB + garbageLen, &crc); +#ifndef WEBRTC_BIG_ENDIAN + for(k = 0; k < LEN_CHECK_SUM_WORD8; k++) + { + ptrEncodedUW8[streamLen - LEN_CHECK_SUM_WORD8 + k] = + (WebRtc_UWord8)((crc >> (24 - k * 8)) & 0xFF); + } +#else + memcpy(&ptrEncodedUW8[streamLenLB + streamLenUB + 1], &crc, + LEN_CHECK_SUM_WORD8); +#endif + } + + return streamLen; +} + + +/****************************************************************************** + * WebRtcIsac_GetNewBitStream(...) + * + * This function returns encoded data, with the recieved bwe-index in the + * stream. If the rate is set to a value less than bottleneck of codec + * the new bistream will be re-encoded with the given target rate. + * It should always return a complete packet, i.e. only called once + * even for 60 msec frames. + * + * NOTE 1! This function does not write in the ISACStruct, it is not allowed. + * NOTE 3! Rates larger than the bottleneck of the codec will be limited + * to the current bottleneck. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - bweIndex : Index of bandwidth estimate to put in new + * bitstream + * - rate : target rate of the transcoder is bits/sec. + * Valid values are the accepted rate in iSAC, + * i.e. 10000 to 56000. + * + * Output: + * - encoded : The encoded data vector + * + * Return value : >0 - Length (in bytes) of coded data + * -1 - Error or called in SWB mode + * NOTE! No error code is written to + * the struct since it is only allowed to read + * the struct. + */ +WebRtc_Word16 WebRtcIsac_GetNewBitStream( + ISACStruct* ISAC_main_inst, + WebRtc_Word16 bweIndex, + WebRtc_Word16 jitterInfo, + WebRtc_Word32 rate, + WebRtc_Word16* encoded, + WebRtc_Word16 isRCU) +{ + Bitstr iSACBitStreamInst; /* Local struct for bitstream handling */ + WebRtc_Word16 streamLenLB; + WebRtc_Word16 streamLenUB; + WebRtc_Word16 totalStreamLen; + double gain2; + double gain1; + float scale; + enum ISACBandwidth bandwidthKHz; + double rateLB; + double rateUB; + WebRtc_Word32 currentBN; + ISACMainStruct* instISAC; + WebRtc_UWord8* encodedPtrUW8 = (WebRtc_UWord8*)encoded; + WebRtc_UWord32 crc; +#ifndef WEBRTC_BIG_ENDIAN + WebRtc_Word16 k; +#endif + + instISAC = (ISACMainStruct*)ISAC_main_inst; + + if((instISAC->initFlag & BIT_MASK_ENC_INIT) != + BIT_MASK_ENC_INIT) + { + return -1; + } + + // Get the bottleneck of this iSAC and limit the + // given rate to the current bottleneck. + WebRtcIsac_GetUplinkBw(ISAC_main_inst, ¤tBN); + if(rate > currentBN) + { + rate = currentBN; + } + + if(WebRtcIsac_RateAllocation(rate, &rateLB, &rateUB, &bandwidthKHz) < 0) + { + return -1; + } + + // Cannot transcode from 16 kHz to 12 kHz + if((bandwidthKHz == isac12kHz) && + (instISAC->bandwidthKHz == isac16kHz)) + { + return -1; + } + + // These gains are in dB + // gain for the given rate. + gain1 = WebRtcIsac_GetSnr(rateLB, + instISAC->instLB.ISACencLB_obj.current_framesamples); + // gain of this iSAC + gain2 = WebRtcIsac_GetSnr( + instISAC->instLB.ISACencLB_obj.bottleneck, + instISAC->instLB.ISACencLB_obj.current_framesamples); + + // scale is the ratio of two gains in normal domain. + scale = (float)pow(10, (gain1 - gain2) / 20.0); + // change the scale if this is a RCU bit-stream. + scale = (isRCU)? (scale * RCU_TRANSCODING_SCALE):scale; + + streamLenLB = WebRtcIsac_EncodeStoredDataLb( + &instISAC->instLB.ISACencLB_obj.SaveEnc_obj, &iSACBitStreamInst, + bweIndex, scale); + + if(streamLenLB < 0) + { + return -1; + } + + /* convert from bytes to WebRtc_Word16 */ + memcpy(encoded, iSACBitStreamInst.stream, streamLenLB); + + if(bandwidthKHz == isac8kHz) + { + return streamLenLB; + } + + totalStreamLen = streamLenLB; + // super-wideband is always at 30ms. + // These gains are in dB + // gain for the given rate. + gain1 = WebRtcIsac_GetSnr(rateUB, FRAMESAMPLES); + // gain of this iSAC + gain2 = WebRtcIsac_GetSnr( + instISAC->instUB.ISACencUB_obj.bottleneck, FRAMESAMPLES); + + // scale is the ratio of two gains in normal domain. + scale = (float)pow(10, (gain1 - gain2) / 20.0); + + // change the scale if this is a RCU bit-stream. + scale = (isRCU)? (scale * RCU_TRANSCODING_SCALE_UB):scale; + + switch(instISAC->bandwidthKHz) + { + case isac12kHz: + { + streamLenUB = WebRtcIsac_EncodeStoredDataUb12( + &(instISAC->instUB.ISACencUB_obj.SaveEnc_obj), + &iSACBitStreamInst, jitterInfo, scale); + break; + } + case isac16kHz: + { + streamLenUB = WebRtcIsac_EncodeStoredDataUb16( + &(instISAC->instUB.ISACencUB_obj.SaveEnc_obj), + &iSACBitStreamInst, jitterInfo, scale); + break; + } + default: + return -1; + } + + if(streamLenUB < 0) + { + return -1; + } + + if(streamLenUB + 1 + LEN_CHECK_SUM_WORD8 > 255) + { + return streamLenLB; + } + + totalStreamLen = streamLenLB + streamLenUB + 1 + LEN_CHECK_SUM_WORD8; + encodedPtrUW8[streamLenLB] = streamLenUB + 1 + LEN_CHECK_SUM_WORD8; + + memcpy(&encodedPtrUW8[streamLenLB+1], iSACBitStreamInst.stream, + streamLenUB); + + WebRtcIsac_GetCrc((WebRtc_Word16*)(&(encodedPtrUW8[streamLenLB + 1])), + streamLenUB, &crc); +#ifndef WEBRTC_BIG_ENDIAN + for(k = 0; k < LEN_CHECK_SUM_WORD8; k++) + { + encodedPtrUW8[totalStreamLen - LEN_CHECK_SUM_WORD8 + k] = + (WebRtc_UWord8)((crc >> (24 - k * 8)) & 0xFF); + } +#else + memcpy(&encodedPtrUW8[streamLenLB + streamLenUB + 1], &crc, + LEN_CHECK_SUM_WORD8); +#endif + + + return totalStreamLen; +} + + +/**************************************************************************** + * DecoderInitLb(...) - internal function for initialization of + * Lower Band + * DecoderInitUb(...) - internal function for initialization of + * Upper Band + * WebRtcIsac_DecoderInit(...) - API function + * + * This function initializes a ISAC instance prior to the decoder calls. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * + * Return value + * : 0 - Ok + * -1 - Error + */ +static WebRtc_Word16 DecoderInitLb( + ISACLBStruct* instISAC) +{ + int i; + /* Init stream vector to zero */ + for (i=0; iISACdecLB_obj.bitstr_obj.stream[i] = 0; + } + + WebRtcIsac_InitMasking(&instISAC->ISACdecLB_obj.maskfiltstr_obj); + WebRtcIsac_InitPostFilterbank( + &instISAC->ISACdecLB_obj.postfiltbankstr_obj); + WebRtcIsac_InitPitchFilter(&instISAC->ISACdecLB_obj.pitchfiltstr_obj); + + return (0); +} + +static WebRtc_Word16 DecoderInitUb( + ISACUBStruct* instISAC) +{ + int i; + /* Init stream vector to zero */ + for (i = 0; i < STREAM_SIZE_MAX_60; i++) + { + instISAC->ISACdecUB_obj.bitstr_obj.stream[i] = 0; + } + + WebRtcIsac_InitMasking(&instISAC->ISACdecUB_obj.maskfiltstr_obj); + WebRtcIsac_InitPostFilterbank( + &instISAC->ISACdecUB_obj.postfiltbankstr_obj); + return (0); +} + +WebRtc_Word16 WebRtcIsac_DecoderInit( + ISACStruct *ISAC_main_inst) +{ + ISACMainStruct* instISAC; + + instISAC = (ISACMainStruct*)ISAC_main_inst; + + if(DecoderInitLb(&instISAC->instLB) < 0) + { + return -1; + } + + if(instISAC->decoderSamplingRateKHz == kIsacSuperWideband) + { + memset(instISAC->synthesisFBState1, 0, + FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32)); + memset(instISAC->synthesisFBState2, 0, + FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32)); + + if(DecoderInitUb(&(instISAC->instUB)) < 0) + { + return -1; + } + } + + if((instISAC->initFlag & BIT_MASK_ENC_INIT) != + BIT_MASK_ENC_INIT) + { + WebRtcIsac_InitBandwidthEstimator(&instISAC->bwestimator_obj, + instISAC->encoderSamplingRateKHz, + instISAC->decoderSamplingRateKHz); + } + + instISAC->initFlag |= BIT_MASK_DEC_INIT; + + instISAC->resetFlag_8kHz = 0; + + return 0; +} + + +/**************************************************************************** + * WebRtcIsac_UpdateBwEstimate(...) + * + * This function updates the estimate of the bandwidth. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - encoded : encoded ISAC frame(s). + * - packet_size : size of the packet. + * - rtp_seq_number : the RTP number of the packet. + * - arr_ts : the arrival time of the packet (from NetEq) + * in samples. + * + * Return value : 0 - Ok + * -1 - Error + */ +WebRtc_Word16 WebRtcIsac_UpdateBwEstimate( + ISACStruct* ISAC_main_inst, + const WebRtc_UWord16* encoded, + WebRtc_Word32 packet_size, + WebRtc_UWord16 rtp_seq_number, + WebRtc_UWord32 send_ts, + WebRtc_UWord32 arr_ts) +{ + ISACMainStruct *instISAC; + Bitstr streamdata; +#ifndef WEBRTC_BIG_ENDIAN + int k; +#endif + WebRtc_Word16 err; + + /* typecast pointer to real structure */ + instISAC = (ISACMainStruct *)ISAC_main_inst; + + /* check if decoder initiated */ + if((instISAC->initFlag & BIT_MASK_DEC_INIT) != + BIT_MASK_DEC_INIT) + { + instISAC->errorCode = ISAC_DECODER_NOT_INITIATED; + return -1; + } + + if(packet_size <= 0) + { + /* return error code if the packet length is null */ + instISAC->errorCode = ISAC_EMPTY_PACKET; + return -1; + } + + streamdata.W_upper = 0xFFFFFFFF; + streamdata.streamval = 0; + streamdata.stream_index = 0; + +#ifndef WEBRTC_BIG_ENDIAN + for(k = 0; k < 10; k++) + { + streamdata.stream[k] = (WebRtc_UWord8) ((encoded[k>>1] >> + ((k&1) << 3)) & 0xFF); + } +#else + memcpy(streamdata.stream, encoded, 10); +#endif + + err = WebRtcIsac_EstimateBandwidth(&instISAC->bwestimator_obj, &streamdata, + packet_size, rtp_seq_number, send_ts, arr_ts, + instISAC->encoderSamplingRateKHz, + instISAC->decoderSamplingRateKHz); + + if(err < 0) + { + /* return error code if something went wrong */ + instISAC->errorCode = -err; + return -1; + } + + return 0; +} + +static WebRtc_Word16 Decode( + ISACStruct* ISAC_main_inst, + const WebRtc_UWord16* encoded, + WebRtc_Word16 lenEncodedBytes, + WebRtc_Word16* decoded, + WebRtc_Word16* speechType, + WebRtc_Word16 isRCUPayload) +{ + /* number of samples (480 or 960), output from decoder + that were actually used in the encoder/decoder + (determined on the fly) */ + ISACMainStruct* instISAC; + ISACUBDecStruct* decInstUB; + ISACLBDecStruct* decInstLB; + + WebRtc_Word16 numSamplesLB; + WebRtc_Word16 numSamplesUB; + WebRtc_Word16 speechIdx; + float outFrame[MAX_FRAMESAMPLES]; + WebRtc_Word16 outFrameLB[MAX_FRAMESAMPLES]; + WebRtc_Word16 outFrameUB[MAX_FRAMESAMPLES]; + WebRtc_Word16 numDecodedBytesLB; + WebRtc_Word16 numDecodedBytesUB; + WebRtc_Word16 lenEncodedLBBytes; + WebRtc_Word16 validChecksum = 1; + WebRtc_Word16 k; + WebRtc_UWord8* ptrEncodedUW8 = (WebRtc_UWord8*)encoded; + WebRtc_UWord16 numLayer; + WebRtc_Word16 totSizeBytes; + WebRtc_Word16 err; + + instISAC = (ISACMainStruct*)ISAC_main_inst; + decInstUB = &(instISAC->instUB.ISACdecUB_obj); + decInstLB = &(instISAC->instLB.ISACdecLB_obj); + + /* check if decoder initiated */ + if((instISAC->initFlag & BIT_MASK_DEC_INIT) != + BIT_MASK_DEC_INIT) + { + instISAC->errorCode = ISAC_DECODER_NOT_INITIATED; + return -1; + } + + if(lenEncodedBytes <= 0) + { + /* return error code if the packet length is null */ + instISAC->errorCode = ISAC_EMPTY_PACKET; + return -1; + } + + // the size of the rncoded lower-band is bounded by + // STREAM_SIZE_MAX, + // If a payload with the size larger than STREAM_SIZE_MAX + // is received, it is not considered erroneous. + lenEncodedLBBytes = (lenEncodedBytes > STREAM_SIZE_MAX) + ? STREAM_SIZE_MAX:lenEncodedBytes; + + // Copy to lower-band bit-stream structure + memcpy(instISAC->instLB.ISACdecLB_obj.bitstr_obj.stream, ptrEncodedUW8, + lenEncodedLBBytes); + + // Regardless of that the current codec is setup to work in + // wideband or super-wideband, the decoding of the lower-band + // has to be performed. + numDecodedBytesLB = WebRtcIsac_DecodeLb(outFrame, decInstLB, + &numSamplesLB, isRCUPayload); + + // Check for error + if((numDecodedBytesLB < 0) || + (numDecodedBytesLB > lenEncodedLBBytes) || + (numSamplesLB > MAX_FRAMESAMPLES)) + { + instISAC->errorCode = ISAC_LENGTH_MISMATCH; + return -1; + } + + // Error Check, we accept multi-layer bit-stream + // This will limit number of iterations of the + // while loop. Even withouut this the number of iterations + // is limited. + numLayer = 1; + totSizeBytes = numDecodedBytesLB; + while(totSizeBytes != lenEncodedBytes) + { + if((totSizeBytes > lenEncodedBytes) || + (ptrEncodedUW8[totSizeBytes] == 0) || + (numLayer > MAX_NUM_LAYERS)) + { + instISAC->errorCode = ISAC_LENGTH_MISMATCH; + return -1; + } + totSizeBytes += ptrEncodedUW8[totSizeBytes]; + numLayer++; + } + + if(instISAC->decoderSamplingRateKHz == kIsacWideband) + { + for(k = 0; k < numSamplesLB; k++) + { + if(outFrame[k] > 32767) + { + decoded[k] = 32767; + } + else if(outFrame[k] < -32768) + { + decoded[k] = -32768; + } + else + { + decoded[k] = (WebRtc_Word16)WebRtcIsac_lrint(outFrame[k]); + } + } + numSamplesUB = 0; + } + else + { + WebRtc_UWord32 crc; + // We don't accept larger than 30ms (480 samples at lower-band) + // frame-size. + for(k = 0; k < numSamplesLB; k++) + { + if(outFrame[k] > 32767) + { + outFrameLB[k] = 32767; + } + else if(outFrame[k] < -32768) + { + outFrameLB[k] = -32768; + } + else + { + outFrameLB[k] = (WebRtc_Word16)WebRtcIsac_lrint(outFrame[k]); + } + } + + //numSamplesUB = numSamplesLB; + + // Check for possible error, and if upper-band stream exist. + if(numDecodedBytesLB == lenEncodedBytes) + { + // Decoding was successful. No super-wideband bitstream + // exists. + numSamplesUB = numSamplesLB; + memset(outFrameUB, 0, sizeof(WebRtc_Word16) * numSamplesUB); + + // Prepare for the potential increase of signal bandwidth + instISAC->resetFlag_8kHz = 2; + } + else + { + // this includes the check sum and the bytes that stores the + // length + WebRtc_Word16 lenNextStream = ptrEncodedUW8[numDecodedBytesLB]; + + // Is this garbage or valid super-wideband bit-stream? + // Check if checksum is valid + if(lenNextStream <= (LEN_CHECK_SUM_WORD8 + 1)) + { + // such a small second layer cannot be super-wideband layer. + // It must be a short garbage. + validChecksum = 0; + } + else + { + // Run CRC to see if the checksum match. + WebRtcIsac_GetCrc((WebRtc_Word16*)( + &ptrEncodedUW8[numDecodedBytesLB + 1]), + lenNextStream - LEN_CHECK_SUM_WORD8 - 1, &crc); + + validChecksum = 1; + for(k = 0; k < LEN_CHECK_SUM_WORD8; k++) + { + validChecksum &= (((crc >> (24 - k * 8)) & 0xFF) == + ptrEncodedUW8[numDecodedBytesLB + lenNextStream - + LEN_CHECK_SUM_WORD8 + k]); + } + } + + if(!validChecksum) + { + // this is a garbage, we have received a wideband + // bit-stream with garbage + numSamplesUB = numSamplesLB; + memset(outFrameUB, 0, sizeof(WebRtc_Word16) * numSamplesUB); + } + else + { + // A valid super-wideband biststream exists. + enum ISACBandwidth bandwidthKHz; + WebRtc_Word32 maxDelayBit; + + //instISAC->bwestimator_obj.incomingStreamSampFreq = + // kIsacSuperWideband; + // If we have super-wideband bit-stream, we cannot + // have 60 ms frame-size. + if(numSamplesLB > FRAMESAMPLES) + { + instISAC->errorCode = ISAC_LENGTH_MISMATCH; + return -1; + } + + // the rest of the bit-stream contains the upper-band + // bit-stream curently this is the only thing there, + // however, we might add more layers. + + // Have to exclude one byte where the length is stored + // and last 'LEN_CHECK_SUM_WORD8' bytes where the + // checksum is stored. + lenNextStream -= (LEN_CHECK_SUM_WORD8 + 1); + + memcpy(decInstUB->bitstr_obj.stream, + &ptrEncodedUW8[numDecodedBytesLB + 1], lenNextStream); + + // THIS IS THE FIRST DECODING + decInstUB->bitstr_obj.W_upper = 0xFFFFFFFF; + decInstUB->bitstr_obj.streamval = 0; + decInstUB->bitstr_obj.stream_index = 0; + + // Decode jitter infotmation + err = WebRtcIsac_DecodeJitterInfo(&decInstUB->bitstr_obj, + &maxDelayBit); + // error check + if(err < 0) + { + instISAC->errorCode = -err; + return -1; + } + + // Update jitter info which is in the upper-band bit-stream + // only if the encoder is in super-wideband. Otherwise, + // the jitter info is already embeded in bandwidth index + // and has been updated. + if(instISAC->encoderSamplingRateKHz == kIsacSuperWideband) + { + err = WebRtcIsac_UpdateUplinkJitter( + &(instISAC->bwestimator_obj), maxDelayBit); + if(err < 0) + { + instISAC->errorCode = -err; + return -1; + } + } + + // decode bandwidth information + err = WebRtcIsac_DecodeBandwidth(&decInstUB->bitstr_obj, + &bandwidthKHz); + if(err < 0) + { + instISAC->errorCode = -err; + return -1; + } + + switch(bandwidthKHz) + { + case isac12kHz: + { + numDecodedBytesUB = WebRtcIsac_DecodeUb12(outFrame, + decInstUB, isRCUPayload); + + // Hang-over for transient alleviation - + // wait two frames to add the upper band going up from 8 kHz + if (instISAC->resetFlag_8kHz > 0) + { + if (instISAC->resetFlag_8kHz == 2) + { + // Silence first and a half frame + memset(outFrame, 0, MAX_FRAMESAMPLES * + sizeof(float)); + } + else + { + const float rampStep = 2.0f / MAX_FRAMESAMPLES; + float rampVal = 0; + memset(outFrame, 0, (MAX_FRAMESAMPLES>>1) * + sizeof(float)); + + // Ramp up second half of second frame + for(k = MAX_FRAMESAMPLES/2; k < MAX_FRAMESAMPLES; k++) + { + outFrame[k] *= rampVal; + rampVal += rampStep; + } + } + instISAC->resetFlag_8kHz -= 1; + } + + break; + } + case isac16kHz: + { + numDecodedBytesUB = WebRtcIsac_DecodeUb16(outFrame, + decInstUB, isRCUPayload); + break; + } + default: + return -1; + } + + // it might be less due to garbage. + if((numDecodedBytesUB != lenNextStream) && + (numDecodedBytesUB != (lenNextStream - ptrEncodedUW8[ + numDecodedBytesLB + 1 + numDecodedBytesUB]))) + { + instISAC->errorCode = ISAC_LENGTH_MISMATCH; + return -1; + } + + // If there is no error Upper-band always decodes + // 30 ms (480 samples) + numSamplesUB = FRAMESAMPLES; + + // Convert to W16 + for(k = 0; k < numSamplesUB; k++) + { + if(outFrame[k] > 32767) + { + outFrameUB[k] = 32767; + } + else if(outFrame[k] < -32768) + { + outFrameUB[k] = -32768; + } + else + { + outFrameUB[k] = (WebRtc_Word16)WebRtcIsac_lrint( + outFrame[k]); + } + } + } + } + + speechIdx = 0; + while(speechIdx < numSamplesLB) + { + WebRtcSpl_SynthesisQMF(&outFrameLB[speechIdx], + &outFrameUB[speechIdx], &decoded[(speechIdx<<1)], + instISAC->synthesisFBState1, instISAC->synthesisFBState2); + + speechIdx += FRAMESAMPLES_10ms; + } + } + *speechType = 0; + return (numSamplesLB + numSamplesUB); +} + + + + + + + +/**************************************************************************** + * WebRtcIsac_Decode(...) + * + * This function decodes a ISAC frame. Output speech length + * will be a multiple of 480 samples: 480 or 960 samples, + * depending on the frameSize (30 or 60 ms). + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - encoded : encoded ISAC frame(s) + * - len : bytes in encoded vector + * + * Output: + * - decoded : The decoded vector + * + * Return value : >0 - number of samples in decoded vector + * -1 - Error + */ + +WebRtc_Word16 WebRtcIsac_Decode( + ISACStruct* ISAC_main_inst, + const WebRtc_UWord16* encoded, + WebRtc_Word16 lenEncodedBytes, + WebRtc_Word16* decoded, + WebRtc_Word16* speechType) +{ + WebRtc_Word16 isRCUPayload = 0; + return Decode(ISAC_main_inst, encoded, lenEncodedBytes, decoded, + speechType, isRCUPayload); +} + +/**************************************************************************** + * WebRtcIsac_DecodeRcu(...) + * + * This function decodes a redundant (RCU) iSAC frame. Function is called in + * NetEq with a stored RCU payload i case of packet loss. Output speech length + * will be a multiple of 480 samples: 480 or 960 samples, + * depending on the framesize (30 or 60 ms). + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - encoded : encoded ISAC RCU frame(s) + * - len : bytes in encoded vector + * + * Output: + * - decoded : The decoded vector + * + * Return value : >0 - number of samples in decoded vector + * -1 - Error + */ + + + +WebRtc_Word16 WebRtcIsac_DecodeRcu( + ISACStruct* ISAC_main_inst, + const WebRtc_UWord16* encoded, + WebRtc_Word16 lenEncodedBytes, + WebRtc_Word16* decoded, + WebRtc_Word16* speechType) +{ + WebRtc_Word16 isRCUPayload = 1; + return Decode(ISAC_main_inst, encoded, lenEncodedBytes, decoded, + speechType, isRCUPayload); +} + + +/**************************************************************************** + * WebRtcIsac_DecodePlc(...) + * + * This function conducts PLC for ISAC frame(s). Output speech length + * will be a multiple of 480 samples: 480 or 960 samples, + * depending on the frameSize (30 or 60 ms). + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - noOfLostFrames : Number of PLC frames to produce + * + * Output: + * - decoded : The decoded vector + * + * Return value : >0 - number of samples in decoded PLC vector + * -1 - Error + */ +WebRtc_Word16 WebRtcIsac_DecodePlc( + ISACStruct* ISAC_main_inst, + WebRtc_Word16* decoded, + WebRtc_Word16 noOfLostFrames) +{ + WebRtc_Word16 numSamples = 0; + ISACMainStruct* instISAC; + + + /* typecast pointer to real structure */ + instISAC = (ISACMainStruct*)ISAC_main_inst; + + /* Limit number of frames to two = 60 msec. Otherwise we exceed data vectors */ + if(noOfLostFrames > 2) + { + noOfLostFrames = 2; + } + + /* Get the number of samples per frame */ + switch(instISAC->decoderSamplingRateKHz) + { + case kIsacWideband: + { + numSamples = 480 * noOfLostFrames; + break; + } + case kIsacSuperWideband: + { + numSamples = 960 * noOfLostFrames; + break; + } + } + + /* Set output samples to zero */ + memset(decoded, 0, numSamples * sizeof(WebRtc_Word16)); + return numSamples; +} + + +/**************************************************************************** + * ControlLb(...) - Internal function for controling Lower Band + * ControlUb(...) - Internal function for controling Upper Band + * WebRtcIsac_Control(...) - API function + * + * This function sets the limit on the short-term average bit rate and the + * frame length. Should be used only in Instantaneous mode. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - rate : limit on the short-term average bit rate, + * in bits/second (between 10000 and 32000) + * - frameSize : number of milliseconds per frame (30 or 60) + * + * Return value : 0 - ok + * -1 - Error + */ +static WebRtc_Word16 ControlLb( + ISACLBStruct* instISAC, + double rate, + WebRtc_Word16 frameSize) +{ + if((rate >= 10000) && (rate <= 32000)) + { + instISAC->ISACencLB_obj.bottleneck = rate; + } + else + { + return -ISAC_DISALLOWED_BOTTLENECK; + } + + if((frameSize == 30) || (frameSize == 60)) + { + instISAC->ISACencLB_obj.new_framelength = (FS/1000) * frameSize; + } + else + { + return -ISAC_DISALLOWED_FRAME_LENGTH; + } + + return 0; +} + +static WebRtc_Word16 ControlUb( + ISACUBStruct* instISAC, + double rate) +{ + if((rate >= 10000) && (rate <= 32000)) + { + instISAC->ISACencUB_obj.bottleneck = rate; + } + else + { + return -ISAC_DISALLOWED_BOTTLENECK; + } + return 0; +} + +WebRtc_Word16 WebRtcIsac_Control( + ISACStruct* ISAC_main_inst, + WebRtc_Word32 bottleneckBPS, + WebRtc_Word16 frameSize) +{ + ISACMainStruct *instISAC; + WebRtc_Word16 status; + double rateLB; + double rateUB; + enum ISACBandwidth bandwidthKHz; + + + /* Typecast pointer to real structure */ + instISAC = (ISACMainStruct*)ISAC_main_inst; + + if(instISAC->codingMode == 0) + { + /* in adaptive mode */ + instISAC->errorCode = ISAC_MODE_MISMATCH; + return -1; + } + + /* check if encoder initiated */ + if((instISAC->initFlag & BIT_MASK_ENC_INIT) != + BIT_MASK_ENC_INIT) + { + instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; + return -1; + } + + if(instISAC->encoderSamplingRateKHz == kIsacWideband) + { + // if the sampling rate is 16kHz then bandwith should be 8kHz, + // regardless of bottleneck. + bandwidthKHz = isac8kHz; + rateLB = (bottleneckBPS > 32000)? 32000:bottleneckBPS; + rateUB = 0; + } + else + { + if(WebRtcIsac_RateAllocation(bottleneckBPS, &rateLB, &rateUB, + &bandwidthKHz) < 0) + { + return -1; + } + } + + if((instISAC->encoderSamplingRateKHz == kIsacSuperWideband) && + (frameSize != 30) && + (bandwidthKHz != isac8kHz)) + { + // Cannot have 60 ms in super-wideband + instISAC->errorCode = ISAC_DISALLOWED_FRAME_LENGTH; + return -1; + } + + status = ControlLb(&instISAC->instLB, rateLB, frameSize); + if(status < 0) + { + instISAC->errorCode = -status; + return -1; + } + if(bandwidthKHz != isac8kHz) + { + status = ControlUb(&(instISAC->instUB), rateUB); + if(status < 0) + { + instISAC->errorCode = -status; + return -1; + } + } + + // + // Check if bandwidth is changing from wideband to super-wideband + // then we have to synch data buffer of lower & upper-band. also + // clean up the upper-band data buffer. + // + if((instISAC->bandwidthKHz == isac8kHz) && + (bandwidthKHz != isac8kHz)) + { + memset(instISAC->instUB.ISACencUB_obj.data_buffer_float, 0, + sizeof(float) * (MAX_FRAMESAMPLES + LB_TOTAL_DELAY_SAMPLES)); + + if(bandwidthKHz == isac12kHz) + { + instISAC->instUB.ISACencUB_obj.buffer_index = + instISAC->instLB.ISACencLB_obj.buffer_index; + } + else + { + instISAC->instUB.ISACencUB_obj.buffer_index = LB_TOTAL_DELAY_SAMPLES + + instISAC->instLB.ISACencLB_obj.buffer_index; + + memcpy(&(instISAC->instUB.ISACencUB_obj.lastLPCVec), + WebRtcIsac_kMeanLarUb16, sizeof(double) * UB_LPC_ORDER); + } + } + + // update the payload limit it the bandwidth is changing. + if(instISAC->bandwidthKHz != bandwidthKHz) + { + instISAC->bandwidthKHz = bandwidthKHz; + UpdatePayloadSizeLimit(instISAC); + } + instISAC->bottleneck = bottleneckBPS; + return 0; +} + + +/**************************************************************************** + * WebRtcIsac_ControlBwe(...) + * + * This function sets the initial values of bottleneck and frame-size if + * iSAC is used in channel-adaptive mode. Through this API, users can + * enforce a frame-size for all values of bottleneck. Then iSAC will not + * automatically change the frame-size. + * + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - rateBPS : initial value of bottleneck in bits/second + * 10000 <= rateBPS <= 32000 is accepted + * For default bottleneck set rateBPS = 0 + * - frameSizeMs : number of milliseconds per frame (30 or 60) + * - enforceFrameSize : 1 to enforce the given frame-size through out + * the adaptation process, 0 to let iSAC change + * the frame-size if required. + * + * Return value : 0 - ok + * -1 - Error + */ +WebRtc_Word16 WebRtcIsac_ControlBwe( + ISACStruct* ISAC_main_inst, + WebRtc_Word32 bottleneckBPS, + WebRtc_Word16 frameSizeMs, + WebRtc_Word16 enforceFrameSize) +{ + ISACMainStruct *instISAC; + enum ISACBandwidth bandwidth; + + /* Typecast pointer to real structure */ + instISAC = (ISACMainStruct *)ISAC_main_inst; + + /* check if encoder initiated */ + if((instISAC->initFlag & BIT_MASK_ENC_INIT) != + BIT_MASK_ENC_INIT) + { + instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; + return -1; + } + + /* Check that we are in channel-adaptive mode, otherwise, return (-1) */ + if(instISAC->codingMode != 0) + { + instISAC->errorCode = ISAC_MODE_MISMATCH; + return -1; + } + if((frameSizeMs != 30) && + (instISAC->encoderSamplingRateKHz == kIsacSuperWideband)) + { + return -1; + } + + /* Set struct variable if enforceFrameSize is set. ISAC will then */ + /* keep the chosen frame size. */ + if((enforceFrameSize != 0) /*|| + (instISAC->samplingRateKHz == kIsacSuperWideband)*/) + { + instISAC->instLB.ISACencLB_obj.enforceFrameSize = 1; + } + else + { + instISAC->instLB.ISACencLB_obj.enforceFrameSize = 0; + } + + /* Set initial rate, if value between 10000 and 32000, */ + /* if rateBPS is 0, keep the default initial bottleneck value (15000) */ + if(bottleneckBPS != 0) + { + double rateLB; + double rateUB; + if(WebRtcIsac_RateAllocation(bottleneckBPS, &rateLB, &rateUB, &bandwidth) < 0) + { + return -1; + } + instISAC->bwestimator_obj.send_bw_avg = (float)bottleneckBPS; + instISAC->bandwidthKHz = bandwidth; + } + + /* Set initial frameSize. If enforceFrameSize is set the frame size will + not change */ + if(frameSizeMs != 0) + { + if((frameSizeMs == 30) || (frameSizeMs == 60)) + { + instISAC->instLB.ISACencLB_obj.new_framelength = (FS/1000) * + frameSizeMs; + //instISAC->bwestimator_obj.rec_header_rate = ((float)HEADER_SIZE * + // 8.0f * 1000.0f / (float)frameSizeMs); + } + else + { + instISAC->errorCode = ISAC_DISALLOWED_FRAME_LENGTH; + return -1; + } + } + return 0; +} + + +/**************************************************************************** + * WebRtcIsac_GetDownLinkBwIndex(...) + * + * This function returns index representing the Bandwidth estimate from + * other side to this side. + * + * Input: + * - ISAC_main_inst : iSAC struct + * + * Output: + * - bweIndex : Bandwidth estimate to transmit to other side. + * + */ +WebRtc_Word16 WebRtcIsac_GetDownLinkBwIndex( + ISACStruct* ISAC_main_inst, + WebRtc_Word16* bweIndex, + WebRtc_Word16* jitterInfo) +{ + ISACMainStruct *instISAC; + + /* typecast pointer to real structure */ + instISAC = (ISACMainStruct*)ISAC_main_inst; + + /* check if encoder initiated */ + if((instISAC->initFlag & BIT_MASK_DEC_INIT) != + BIT_MASK_DEC_INIT) + { + instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; + return -1; + } + + /* Call function to get Bandwidth Estimate */ + WebRtcIsac_GetDownlinkBwJitIndexImpl(&(instISAC->bwestimator_obj), + bweIndex, jitterInfo, instISAC->decoderSamplingRateKHz); + return 0; +} + + +/**************************************************************************** + * WebRtcIsac_UpdateUplinkBw(...) + * + * This function takes an index representing the Bandwidth estimate from + * this side to other side and updates BWE. + * + * Input: + * - ISAC_main_inst : iSAC struct + * - rateIndex : Bandwidth estimate from other side. + * + * Return value : 0 - ok + * -1 - index out of range + */ +WebRtc_Word16 WebRtcIsac_UpdateUplinkBw( + ISACStruct* ISAC_main_inst, + WebRtc_Word16 bweIndex) +{ + ISACMainStruct *instISAC; + WebRtc_Word16 returnVal; + + /* typecast pointer to real structure */ + instISAC = (ISACMainStruct *)ISAC_main_inst; + + /* check if encoder initiated */ + if((instISAC->initFlag & BIT_MASK_ENC_INIT) != + BIT_MASK_ENC_INIT) + { + instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; + return -1; + } + + /* Call function to get Bandwidth Estimate */ + returnVal = WebRtcIsac_UpdateUplinkBwImpl( + &(instISAC->bwestimator_obj), bweIndex, + instISAC->encoderSamplingRateKHz); + + if(returnVal < 0) + { + instISAC->errorCode = -returnVal; + return -1; + } + else + { + return 0; + } +} + + +/**************************************************************************** + * WebRtcIsac_ReadBwIndex(...) + * + * This function returns the index of the Bandwidth estimate from the + * bitstream. + * + * Input: + * - encoded : Encoded bitstream + * + * Output: + * - frameLength : Length of frame in packet (in samples) + * - bweIndex : Bandwidth estimate in bitstream + * + */ +WebRtc_Word16 WebRtcIsac_ReadBwIndex( + const WebRtc_Word16* encoded, + WebRtc_Word16* bweIndex) +{ + Bitstr streamdata; +#ifndef WEBRTC_BIG_ENDIAN + int k; +#endif + WebRtc_Word16 err; + + streamdata.W_upper = 0xFFFFFFFF; + streamdata.streamval = 0; + streamdata.stream_index = 0; + +#ifndef WEBRTC_BIG_ENDIAN + for(k = 0; k < 10; k++) + { + streamdata.stream[k] = (WebRtc_UWord8) ((encoded[k>>1] >> + ((k&1) << 3)) & 0xFF); + } +#else + memcpy(streamdata.stream, encoded, 10); +#endif + + /* decode frame length */ + err = WebRtcIsac_DecodeFrameLen(&streamdata, bweIndex); + if(err < 0) + { + return err; + } + + /* decode BW estimation */ + err = WebRtcIsac_DecodeSendBW(&streamdata, bweIndex); + if(err < 0) + { + return err; + } + + return 0; +} + + +/**************************************************************************** + * WebRtcIsac_ReadFrameLen(...) + * + * This function returns the length of the frame represented in the packet. + * + * Input: + * - encoded : Encoded bitstream + * + * Output: + * - frameLength : Length of frame in packet (in samples) + * + */ +WebRtc_Word16 WebRtcIsac_ReadFrameLen( + ISACStruct* ISAC_main_inst, + const WebRtc_Word16* encoded, + WebRtc_Word16* frameLength) +{ + Bitstr streamdata; +#ifndef WEBRTC_BIG_ENDIAN + int k; +#endif + WebRtc_Word16 err; + ISACMainStruct* instISAC; + + streamdata.W_upper = 0xFFFFFFFF; + streamdata.streamval = 0; + streamdata.stream_index = 0; + +#ifndef WEBRTC_BIG_ENDIAN + for (k=0; k<10; k++) { + streamdata.stream[k] = (WebRtc_UWord8) ((encoded[k>>1] >> + ((k&1) << 3)) & 0xFF); + } +#else + memcpy(streamdata.stream, encoded, 10); +#endif + + /* decode frame length */ + err = WebRtcIsac_DecodeFrameLen(&streamdata, frameLength); + if(err < 0) { + return -1; + } + instISAC = (ISACMainStruct*)ISAC_main_inst; + + if(instISAC->decoderSamplingRateKHz == kIsacSuperWideband) + { + // the decoded frame length indicates the number of samples in + // lower-band in this case, multiply by 2 to get the total number + // of samples. + *frameLength <<= 1; + } + + return 0; +} + + +/******************************************************************************* + * WebRtcIsac_GetNewFrameLen(...) + * + * returns the frame lenght (in samples) of the next packet. In the case of + * channel-adaptive mode, iSAC decides on its frame lenght based on the + * estimated bottleneck this allows a user to prepare for the next packet + * (at the encoder). + * + * The primary usage is in CE to make the iSAC works in channel-adaptive mode + * + * Input: + * - ISAC_main_inst : iSAC struct + * + * Return Value : frame lenght in samples + * + */ +WebRtc_Word16 WebRtcIsac_GetNewFrameLen( + ISACStruct *ISAC_main_inst) +{ + ISACMainStruct *instISAC; + + /* typecast pointer to real structure */ + instISAC = (ISACMainStruct *)ISAC_main_inst; + + /* Return new frame length */ + if(instISAC->encoderSamplingRateKHz == kIsacWideband) + { + return (instISAC->instLB.ISACencLB_obj.new_framelength); + } + else + { + return ((instISAC->instLB.ISACencLB_obj.new_framelength) << 1); + } +} + + +/**************************************************************************** + * WebRtcIsac_GetErrorCode(...) + * + * This function can be used to check the error code of an iSAC instance. + * When a function returns -1 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 WebRtcIsac_GetErrorCode( + ISACStruct *ISAC_main_inst) +{ + ISACMainStruct *instISAC; + /* typecast pointer to real structure */ + instISAC = (ISACMainStruct *)ISAC_main_inst; + + return (instISAC->errorCode); +} + + +/**************************************************************************** + * WebRtcIsac_GetUplinkBw(...) + * + * This function outputs the target bottleneck of the codec. In + * channel-adaptive mode, the target bottleneck is specified through in-band + * signalling retreived by bandwidth estimator. + * In channel-independent, also called instantaneous mode, the target + * bottleneck is provided to the encoder by calling xxx_control(...) (if + * xxx_control is never called the default values is). + * Note that the output is the iSAC internal operating bottleneck whch might + * differ slightly from the one provided through xxx_control(). + * + * Input: + * - ISAC_main_inst : iSAC instance + * + * Output: + * - *bottleneck : bottleneck in bits/sec + * + * Return value : -1 if error happens + * 0 bit-rates computed correctly. + */ +WebRtc_Word16 WebRtcIsac_GetUplinkBw( + ISACStruct* ISAC_main_inst, + WebRtc_Word32* bottleneck) +{ + ISACMainStruct* instISAC = (ISACMainStruct *)ISAC_main_inst; + + if(instISAC->codingMode == 0) + { + // we are in adaptive mode then get the bottleneck from BWE + *bottleneck = (WebRtc_Word32)instISAC->bwestimator_obj.send_bw_avg; + } + else + { + *bottleneck = instISAC->bottleneck; + } + + if((*bottleneck > 32000) && (*bottleneck < 38000)) + { + *bottleneck = 32000; + } + else if((*bottleneck > 45000) && (*bottleneck < 50000)) + { + *bottleneck = 45000; + } + else if(*bottleneck > 56000) + { + *bottleneck = 56000; + } + + return 0; +} + + +/****************************************************************************** + * WebRtcIsac_SetMaxPayloadSize(...) + * + * This function sets a limit for the maximum payload size of iSAC. The same + * value is used both for 30 and 60 ms packets. If the encoder sampling rate + * is 16 kHz the maximum payload size is between 120 and 400 bytes. If the + * encoder sampling rate is 32 kHz the maximum payload size is between 120 + * and 600 bytes. + * + * --------------- + * IMPORTANT NOTES + * --------------- + * The size of a packet is limited to the minimum of 'max-payload-size' and + * 'max-rate.' For instance, let's assume the max-payload-size is set to + * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps + * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms + * frame-size. Then a packet with a frame-size of 30 ms is limited to 150, + * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to + * 170 bytes, i.e. min(170, 300). + * + * Input: + * - ISAC_main_inst : iSAC instance + * - maxPayloadBytes : maximum size of the payload in bytes + * valid values are between 100 and 400 bytes + * if encoder sampling rate is 16 kHz. For + * 32 kHz encoder sampling rate valid values + * are between 100 and 600 bytes. + * + * Return value : 0 if successful + * -1 if error happens + */ +WebRtc_Word16 WebRtcIsac_SetMaxPayloadSize( + ISACStruct* ISAC_main_inst, + WebRtc_Word16 maxPayloadBytes) +{ + ISACMainStruct *instISAC; + WebRtc_Word16 status = 0; + + /* typecast pointer to real structure */ + instISAC = (ISACMainStruct *)ISAC_main_inst; + + /* check if encoder initiated */ + if((instISAC->initFlag & BIT_MASK_ENC_INIT) != + BIT_MASK_ENC_INIT) + { + instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; + return -1; + } + + if(instISAC->encoderSamplingRateKHz == kIsacSuperWideband) + { + // sanity check + if(maxPayloadBytes < 120) + { + // maxRate is out of valid range + // set to the acceptable value and return -1. + maxPayloadBytes = 120; + status = -1; + } + + /* sanity check */ + if(maxPayloadBytes > STREAM_SIZE_MAX) + { + // maxRate is out of valid range + // set to the acceptable value and return -1. + maxPayloadBytes = STREAM_SIZE_MAX; + status = -1; + } + } + else + { + if(maxPayloadBytes < 120) + { + // max payload-size is out of valid range + // set to the acceptable value and return -1. + maxPayloadBytes = 120; + status = -1; + } + if(maxPayloadBytes > STREAM_SIZE_MAX_60) + { + // max payload-size is out of valid range + // set to the acceptable value and return -1. + maxPayloadBytes = STREAM_SIZE_MAX_60; + status = -1; + } + } + instISAC->maxPayloadSizeBytes = maxPayloadBytes; + UpdatePayloadSizeLimit(instISAC); + return status; +} + + +/****************************************************************************** + * WebRtcIsac_SetMaxRate(...) + * + * This function sets the maximum rate which the codec may not exceed for + * any signal packet. The maximum rate is defined and payload-size per + * frame-size in bits per second. + * + * The codec has a maximum rate of 53400 bits per second (200 bytes per 30 + * ms) if the encoder sampling rate is 16kHz, and 160 kbps (600 bytes/30 ms) + * if the encoder sampling rate is 32 kHz. + * + * It is possible to set a maximum rate between 32000 and 53400 bits/sec + * in wideband mode, and 32000 to 160000 bits/sec in super-wideband mode. + * + * --------------- + * IMPORTANT NOTES + * --------------- + * The size of a packet is limited to the minimum of 'max-payload-size' and + * 'max-rate.' For instance, let's assume the max-payload-size is set to + * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps + * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms + * frame-size. Then a packet with a frame-size of 30 ms is limited to 150, + * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to + * 170 bytes, min(170, 300). + * + * Input: + * - ISAC_main_inst : iSAC instance + * - maxRate : maximum rate in bits per second, + * valid values are 32000 to 53400 bits/sec in + * wideband mode, and 32000 to 160000 bits/sec in + * super-wideband mode. + * + * Return value : 0 if successful + * -1 if error happens + */ +WebRtc_Word16 WebRtcIsac_SetMaxRate( + ISACStruct* ISAC_main_inst, + WebRtc_Word32 maxRate) +{ + ISACMainStruct *instISAC; + WebRtc_Word16 maxRateInBytesPer30Ms; + WebRtc_Word16 status = 0; + + /* typecast pointer to real structure */ + instISAC = (ISACMainStruct *)ISAC_main_inst; + + /* check if encoder initiated */ + if((instISAC->initFlag & BIT_MASK_ENC_INIT) != + BIT_MASK_ENC_INIT) + { + instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; + return -1; + } + /* + Calculate maximum number of bytes per 30 msec packets for the + given maximum rate. Multiply with 30/1000 to get number of + bits per 30 ms, divide by 8 to get number of bytes per 30 ms: + maxRateInBytes = floor((maxRate * 30/1000) / 8); + */ + maxRateInBytesPer30Ms = (WebRtc_Word16)(maxRate*3/800); + + if(instISAC->encoderSamplingRateKHz == kIsacWideband) + { + if(maxRate < 32000) + { + // max rate is out of valid range + // set to the acceptable value and return -1. + maxRateInBytesPer30Ms = 120; + status = -1; + } + + if(maxRate > 53400) + { + // max rate is out of valid range + // set to the acceptable value and return -1. + maxRateInBytesPer30Ms = 200; + status = -1; + } + } + else + { + if(maxRateInBytesPer30Ms < 120) + { + // maxRate is out of valid range + // set to the acceptable value and return -1. + maxRateInBytesPer30Ms = 120; + status = -1; + } + + if(maxRateInBytesPer30Ms > STREAM_SIZE_MAX) + { + // maxRate is out of valid range + // set to the acceptable value and return -1. + maxRateInBytesPer30Ms = STREAM_SIZE_MAX; + status = -1; + } + } + instISAC->maxRateBytesPer30Ms = maxRateInBytesPer30Ms; + UpdatePayloadSizeLimit(instISAC); + return status; +} + + +/**************************************************************************** + * WebRtcIsac_GetRedPayload(...) + * + * Populates "encoded" with the redundant payload of the recently encoded + * frame. This function has to be called once that WebRtcIsac_Encode(...) + * returns a positive value. Regardless of the frame-size this function will + * be called only once after encoding is completed. The bit-stream is + * targeted for 16000 bit/sec. + * + * Input: + * - ISAC_main_inst : iSAC struct + * + * Output: + * - encoded : the encoded data vector + * + * + * Return value : >0 - Length (in bytes) of coded data + * : -1 - Error + * + * + */ +WebRtc_Word16 WebRtcIsac_GetRedPayload( + ISACStruct* ISAC_main_inst, + WebRtc_Word16* encoded) +{ + ISACMainStruct* instISAC; + Bitstr iSACBitStreamInst; + WebRtc_Word16 streamLenLB; + WebRtc_Word16 streamLenUB; + WebRtc_Word16 streamLen; + WebRtc_Word16 totalLenUB; + WebRtc_UWord8* ptrEncodedUW8 = (WebRtc_UWord8*)encoded; +#ifndef WEBRTC_BIG_ENDIAN + int k; +#endif + + /* typecast pointer to real structure */ + instISAC = (ISACMainStruct*)ISAC_main_inst; + + + if((instISAC->initFlag & BIT_MASK_ENC_INIT) != + BIT_MASK_ENC_INIT) + { + instISAC->errorCode = ISAC_ENCODER_NOT_INITIATED; + } + + + iSACBitStreamInst.W_upper = 0xFFFFFFFF; + iSACBitStreamInst.streamval = 0; + iSACBitStreamInst.stream_index = 0; + + + streamLenLB = WebRtcIsac_EncodeStoredDataLb( + &instISAC->instLB.ISACencLB_obj.SaveEnc_obj, + &iSACBitStreamInst, + instISAC->instLB.ISACencLB_obj.lastBWIdx, + RCU_TRANSCODING_SCALE); + + if(streamLenLB < 0) + { + return -1; + } + + /* convert from bytes to WebRtc_Word16 */ + memcpy(ptrEncodedUW8, iSACBitStreamInst.stream, streamLenLB); + + streamLen = streamLenLB; + + if(instISAC->bandwidthKHz == isac8kHz) + { + return streamLenLB; + } + + streamLenUB = WebRtcIsac_GetRedPayloadUb( + &instISAC->instUB.ISACencUB_obj.SaveEnc_obj, + &iSACBitStreamInst, instISAC->bandwidthKHz); + + if(streamLenUB < 0) + { + // an error has happened but this is not the error due to a + // bit-stream larger than the limit + return -1; + } + + // We have one byte to write the total length of the upper band + // the length include the bitstream length, check-sum and the + // single byte where the length is written to. This is according to + // iSAC wideband and how the "garbage" is dealt. + totalLenUB = streamLenUB + 1 + LEN_CHECK_SUM_WORD8; + if(totalLenUB > 255) + { + streamLenUB = 0; + } + + // Generate CRC if required. + if((instISAC->bandwidthKHz != isac8kHz) && + (streamLenUB > 0)) + { + WebRtc_UWord32 crc; + streamLen += totalLenUB; + ptrEncodedUW8[streamLenLB] = (WebRtc_UWord8)totalLenUB; + memcpy(&ptrEncodedUW8[streamLenLB+1], iSACBitStreamInst.stream, streamLenUB); + + WebRtcIsac_GetCrc((WebRtc_Word16*)(&(ptrEncodedUW8[streamLenLB + 1])), + streamLenUB, &crc); +#ifndef WEBRTC_BIG_ENDIAN + for(k = 0; k < LEN_CHECK_SUM_WORD8; k++) + { + ptrEncodedUW8[streamLen - LEN_CHECK_SUM_WORD8 + k] = + (WebRtc_UWord8)((crc >> (24 - k * 8)) & 0xFF); + } +#else + memcpy(&ptrEncodedUW8[streamLenLB + streamLenUB + 1], &crc, + LEN_CHECK_SUM_WORD8); +#endif + } + + + return streamLen; +} + + +/**************************************************************************** + * WebRtcIsac_version(...) + * + * This function returns the version number. + * + * Output: + * - version : Pointer to character string + * + */ +void WebRtcIsac_version(char *version) +{ + strcpy(version, "4.3.0"); +} + + +/****************************************************************************** + * WebRtcIsac_SetEncSampRate() + * Set the sampling rate of the encoder. Initialization of the encoder WILL + * NOT overwrite the sampling rate of the encoder. The default value is 16 kHz + * which is set when the instance is created. The encoding-mode and the + * bottleneck remain unchanged by this call, however, the maximum rate and + * maximum payload-size will reset to their default value. + * + * Input: + * - ISAC_main_inst : iSAC instance + * - sampRate : enumerator specifying the sampling rate. + * + * Return value : 0 if successful + * -1 if failed. + */ +WebRtc_Word16 WebRtcIsac_SetEncSampRate( + ISACStruct* ISAC_main_inst, + enum IsacSamplingRate sampRate) +{ + ISACMainStruct* instISAC; + + instISAC = (ISACMainStruct*)ISAC_main_inst; + + if((sampRate != kIsacWideband) && + (sampRate != kIsacSuperWideband)) + { + // Sampling Frequency is not supported + instISAC->errorCode = ISAC_UNSUPPORTED_SAMPLING_FREQUENCY; + return -1; + } + else if((instISAC->initFlag & BIT_MASK_ENC_INIT) != + BIT_MASK_ENC_INIT) + { + if(sampRate == kIsacWideband) + { + instISAC->bandwidthKHz = isac8kHz; + } + else + { + instISAC->bandwidthKHz = isac16kHz; + } + instISAC->encoderSamplingRateKHz = sampRate; + return 0; + } + else + { + ISACUBStruct* instUB = &(instISAC->instUB); + ISACLBStruct* instLB = &(instISAC->instLB); + double bottleneckLB; + double bottleneckUB; + WebRtc_Word32 bottleneck = instISAC->bottleneck; + WebRtc_Word16 codingMode = instISAC->codingMode; + WebRtc_Word16 frameSizeMs = instLB->ISACencLB_obj.new_framelength / (FS / 1000); + + if((sampRate == kIsacWideband) && + (instISAC->encoderSamplingRateKHz == kIsacSuperWideband)) + { + // changing from super-wideband to wideband. + // we don't need to re-initialize the encoder of the + // lower-band. + instISAC->bandwidthKHz = isac8kHz; + if(codingMode == 1) + { + ControlLb(instLB, + (bottleneck > 32000)? 32000:bottleneck, FRAMESIZE); + } + instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX_60; + instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX_30; + } + else if((sampRate == kIsacSuperWideband) && + (instISAC->encoderSamplingRateKHz == kIsacWideband)) + { + if(codingMode == 1) + { + WebRtcIsac_RateAllocation(bottleneck, &bottleneckLB, &bottleneckUB, + &(instISAC->bandwidthKHz)); + } + + instISAC->bandwidthKHz = isac16kHz; + instISAC->maxPayloadSizeBytes = STREAM_SIZE_MAX; + instISAC->maxRateBytesPer30Ms = STREAM_SIZE_MAX; + + EncoderInitLb(instLB, codingMode, sampRate); + EncoderInitUb(instUB, instISAC->bandwidthKHz); + + memset(instISAC->analysisFBState1, 0, + FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32)); + memset(instISAC->analysisFBState2, 0, + FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32)); + + if(codingMode == 1) + { + instISAC->bottleneck = bottleneck; + ControlLb(instLB, bottleneckLB, + (instISAC->bandwidthKHz == isac8kHz)? frameSizeMs:FRAMESIZE); + if(instISAC->bandwidthKHz > isac8kHz) + { + ControlUb(instUB, bottleneckUB); + } + } + else + { + instLB->ISACencLB_obj.enforceFrameSize = 0; + instLB->ISACencLB_obj.new_framelength = FRAMESAMPLES; + } + } + instISAC->encoderSamplingRateKHz = sampRate; + return 0; + } +} + + +/****************************************************************************** + * WebRtcIsac_SetDecSampRate() + * Set the sampling rate of the decoder. Initialization of the decoder WILL + * NOT overwrite the sampling rate of the encoder. The default value is 16 kHz + * which is set when the instance is created. + * + * Input: + * - ISAC_main_inst : iSAC instance + * - sampRate : enumerator specifying the sampling rate. + * + * Return value : 0 if successful + * -1 if failed. + */ +WebRtc_Word16 WebRtcIsac_SetDecSampRate( + ISACStruct* ISAC_main_inst, + enum IsacSamplingRate sampRate) +{ + ISACMainStruct* instISAC; + + instISAC = (ISACMainStruct*)ISAC_main_inst; + + if((sampRate != kIsacWideband) && + (sampRate != kIsacSuperWideband)) + { + // Sampling Frequency is not supported + instISAC->errorCode = ISAC_UNSUPPORTED_SAMPLING_FREQUENCY; + return -1; + } + else + { + if((instISAC->decoderSamplingRateKHz == kIsacWideband) && + (sampRate == kIsacSuperWideband)) + { + // switching from wideband to super-wideband at the decoder + // we need to reset the filter-bank and initialize + // upper-band decoder. + memset(instISAC->synthesisFBState1, 0, + FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32)); + memset(instISAC->synthesisFBState2, 0, + FB_STATE_SIZE_WORD32 * sizeof(WebRtc_Word32)); + + if(DecoderInitUb(&(instISAC->instUB)) < 0) + { + return -1; + } + } + instISAC->decoderSamplingRateKHz = sampRate; + return 0; + } +} + + +/****************************************************************************** + * WebRtcIsac_EncSampRate() + * + * Input: + * - ISAC_main_inst : iSAC instance + * + * Return value : enumerator representing sampling frequency + * associated with the encoder, the input audio + * is expected to be sampled at this rate. + * + */ +enum IsacSamplingRate WebRtcIsac_EncSampRate( + ISACStruct* ISAC_main_inst) +{ + ISACMainStruct* instISAC; + + instISAC = (ISACMainStruct*)ISAC_main_inst; + + return instISAC->encoderSamplingRateKHz; +} + + +/****************************************************************************** + * WebRtcIsac_DecSampRate() + * Return the sampling rate of the decoded audio. + * + * Input: + * - ISAC_main_inst : iSAC instance + * + * Return value : enumerator representing sampling frequency + * associated with the decoder, i.e. the + * sampling rate of the decoded audio. + * + */ +enum IsacSamplingRate WebRtcIsac_DecSampRate( + ISACStruct* ISAC_main_inst) +{ + ISACMainStruct* instISAC; + + instISAC = (ISACMainStruct*)ISAC_main_inst; + + return instISAC->decoderSamplingRateKHz; +} diff --git a/libs/miniwebrtc/audio/coding_isac/main/isac.h b/libs/miniwebrtc/audio/coding_isac/main/isac.h new file mode 100644 index 00000000..03c260bb --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/isac.h @@ -0,0 +1,729 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INTERFACE_ISAC_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INTERFACE_ISAC_H_ + +/* + * Define the fixed-point numeric formats + */ +#include "typedefs.h" + +typedef struct WebRtcISACStruct ISACStruct; + +enum IsacSamplingRate {kIsacWideband = 16, kIsacSuperWideband = 32}; + + +#if defined(__cplusplus) +extern "C" { +#endif + + /****************************************************************************** + * WebRtcIsac_AssignSize(...) + * + * This function returns the size of the ISAC instance, so that the instance + * can be created outside iSAC. + * + * Input: + * - samplingRate : sampling rate of the input/output audio. + * + * Output: + * - sizeinbytes : number of bytes needed to allocate for the + * instance. + * + * Return value : 0 - Ok + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsac_AssignSize( + int* sizeinbytes); + + + /****************************************************************************** + * WebRtcIsac_Assign(...) + * + * This function assignes the memory already created to the ISAC instance. + * + * Input: + * - *ISAC_main_inst : a pointer to the coder instance. + * - samplingRate : sampling rate of the input/output audio. + * - ISAC_inst_Addr : the already allocated memory, where we put the + * iSAC structure. + * + * Return value : 0 - Ok + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsac_Assign( + ISACStruct** ISAC_main_inst, + void* ISAC_inst_Addr); + + + /****************************************************************************** + * WebRtcIsac_Create(...) + * + * This function creates an ISAC instance, which will contain the state + * information for one coding/decoding channel. + * + * Input: + * - *ISAC_main_inst : a pointer to the coder instance. + * + * Return value : 0 - Ok + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsac_Create( + ISACStruct** ISAC_main_inst); + + + /****************************************************************************** + * WebRtcIsac_Free(...) + * + * This function frees the ISAC instance created at the beginning. + * + * Input: + * - ISAC_main_inst : an ISAC instance. + * + * Return value : 0 - Ok + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsac_Free( + ISACStruct* ISAC_main_inst); + + + /****************************************************************************** + * WebRtcIsac_EncoderInit(...) + * + * This function initializes an ISAC instance prior to the encoder calls. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - CodingMode : 0 -> Bit rate and frame length are + * automatically adjusted to available bandwidth + * on transmission channel, just valid if codec + * is created to work in wideband mode. + * 1 -> User sets a frame length and a target bit + * rate which is taken as the maximum + * short-term average bit rate. + * + * Return value : 0 - Ok + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsac_EncoderInit( + ISACStruct* ISAC_main_inst, + WebRtc_Word16 CodingMode); + + + /****************************************************************************** + * WebRtcIsac_Encode(...) + * + * This function encodes 10ms audio blocks and inserts it into a package. + * Input speech length has 160 samples if operating at 16 kHz sampling + * rate, or 320 if operating at 32 kHz sampling rate. The encoder buffers the + * input audio until the whole frame is buffered then proceeds with encoding. + * + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - speechIn : input speech vector. + * + * Output: + * - encoded : the encoded data vector + * + * Return value: + * : >0 - Length (in bytes) of coded data + * : 0 - The buffer didn't reach the chosen + * frame-size so it keeps buffering speech + * samples. + * : -1 - Error + */ + + WebRtc_Word16 WebRtcIsac_Encode( + ISACStruct* ISAC_main_inst, + const WebRtc_Word16* speechIn, + WebRtc_Word16* encoded); + + + /****************************************************************************** + * WebRtcIsac_DecoderInit(...) + * + * This function initializes an ISAC instance prior to the decoder calls. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * + * Return value + * : 0 - Ok + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsac_DecoderInit( + ISACStruct* ISAC_main_inst); + + + /****************************************************************************** + * WebRtcIsac_UpdateBwEstimate(...) + * + * This function updates the estimate of the bandwidth. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - encoded : encoded ISAC frame(s). + * - packet_size : size of the packet. + * - rtp_seq_number : the RTP number of the packet. + * - send_ts : the RTP send timestamp, given in samples + * - arr_ts : the arrival time of the packet (from NetEq) + * in samples. + * + * Return value : 0 - Ok + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsac_UpdateBwEstimate( + ISACStruct* ISAC_main_inst, + const WebRtc_UWord16* encoded, + WebRtc_Word32 packet_size, + WebRtc_UWord16 rtp_seq_number, + WebRtc_UWord32 send_ts, + WebRtc_UWord32 arr_ts); + + + /****************************************************************************** + * WebRtcIsac_Decode(...) + * + * This function decodes an ISAC frame. At 16 kHz sampling rate, the length + * of the output audio could be either 480 or 960 samples, equivalent to + * 30 or 60 ms respectively. At 32 kHz sampling rate, the length of the + * output audio is 960 samples, which is 30 ms. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - encoded : encoded ISAC frame(s). + * - len : bytes in encoded vector. + * + * Output: + * - decoded : The decoded vector. + * + * Return value : >0 - number of samples in decoded vector. + * -1 - Error. + */ + + WebRtc_Word16 WebRtcIsac_Decode( + ISACStruct* ISAC_main_inst, + const WebRtc_UWord16* encoded, + WebRtc_Word16 len, + WebRtc_Word16* decoded, + WebRtc_Word16* speechType); + + + /****************************************************************************** + * WebRtcIsac_DecodePlc(...) + * + * This function conducts PLC for ISAC frame(s). Output speech length + * will be a multiple of frames, i.e. multiples of 30 ms audio. Therefore, + * the output is multiple of 480 samples if operating at 16 kHz and multiple + * of 960 if operating at 32 kHz. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - noOfLostFrames : Number of PLC frames to produce. + * + * Output: + * - decoded : The decoded vector. + * + * Return value : >0 - number of samples in decoded PLC vector + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsac_DecodePlc( + ISACStruct* ISAC_main_inst, + WebRtc_Word16* decoded, + WebRtc_Word16 noOfLostFrames); + + + /****************************************************************************** + * WebRtcIsac_Control(...) + * + * This function sets the limit on the short-term average bit-rate and the + * frame length. Should be used only in Instantaneous mode. At 16 kHz sampling + * rate, an average bit-rate between 10000 to 32000 bps is valid and a + * frame-size of 30 or 60 ms is acceptable. At 32 kHz, an average bit-rate + * between 10000 to 56000 is acceptable, and the valid frame-size is 30 ms. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - rate : limit on the short-term average bit rate, + * in bits/second. + * - framesize : frame-size in millisecond. + * + * Return value : 0 - ok + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsac_Control( + ISACStruct* ISAC_main_inst, + WebRtc_Word32 rate, + WebRtc_Word16 framesize); + + + /****************************************************************************** + * WebRtcIsac_ControlBwe(...) + * + * This function sets the initial values of bottleneck and frame-size if + * iSAC is used in channel-adaptive mode. Therefore, this API is not + * applicable if the codec is created to operate in super-wideband mode. + * + * Through this API, users can enforce a frame-size for all values of + * bottleneck. Then iSAC will not automatically change the frame-size. + * + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - rateBPS : initial value of bottleneck in bits/second + * 10000 <= rateBPS <= 56000 is accepted + * For default bottleneck set rateBPS = 0 + * - frameSizeMs : number of milliseconds per frame (30 or 60) + * - enforceFrameSize : 1 to enforce the given frame-size through + * out the adaptation process, 0 to let iSAC + * change the frame-size if required. + * + * Return value : 0 - ok + * -1 - Error + */ + + WebRtc_Word16 WebRtcIsac_ControlBwe( + ISACStruct* ISAC_main_inst, + WebRtc_Word32 rateBPS, + WebRtc_Word16 frameSizeMs, + WebRtc_Word16 enforceFrameSize); + + + /****************************************************************************** + * WebRtcIsac_ReadFrameLen(...) + * + * This function returns the length of the frame represented in the packet. + * + * Input: + * - encoded : Encoded bit-stream + * + * Output: + * - frameLength : Length of frame in packet (in samples) + * + */ + + WebRtc_Word16 WebRtcIsac_ReadFrameLen( + ISACStruct* ISAC_main_inst, + const WebRtc_Word16* encoded, + WebRtc_Word16* frameLength); + + + /****************************************************************************** + * WebRtcIsac_version(...) + * + * This function returns the version number. + * + * Output: + * - version : Pointer to character string + * + */ + + void WebRtcIsac_version( + char *version); + + + /****************************************************************************** + * WebRtcIsac_GetErrorCode(...) + * + * This function can be used to check the error code of an iSAC instance. When + * a function returns -1 a error code will be set for that instance. The + * function below extract the code of the last error that occurred in the + * specified instance. + * + * Input: + * - ISAC_main_inst : ISAC instance + * + * Return value : Error code + */ + + WebRtc_Word16 WebRtcIsac_GetErrorCode( + ISACStruct* ISAC_main_inst); + + + /**************************************************************************** + * WebRtcIsac_GetUplinkBw(...) + * + * This function outputs the target bottleneck of the codec. In + * channel-adaptive mode, the target bottleneck is specified through in-band + * signalling retreived by bandwidth estimator. + * In channel-independent, also called instantaneous mode, the target + * bottleneck is provided to the encoder by calling xxx_control(...). If + * xxx_control is never called the default values is returned. The default + * value for bottleneck at 16 kHz encoder sampling rate is 32000 bits/sec, + * and it is 56000 bits/sec for 32 kHz sampling rate. + * Note that the output is the iSAC internal operating bottleneck which might + * differ slightly from the one provided through xxx_control(). + * + * Input: + * - ISAC_main_inst : iSAC instance + * + * Output: + * - *bottleneck : bottleneck in bits/sec + * + * Return value : -1 if error happens + * 0 bit-rates computed correctly. + */ + + WebRtc_Word16 WebRtcIsac_GetUplinkBw( + ISACStruct* ISAC_main_inst, + WebRtc_Word32* bottleneck); + + + /****************************************************************************** + * WebRtcIsac_SetMaxPayloadSize(...) + * + * This function sets a limit for the maximum payload size of iSAC. The same + * value is used both for 30 and 60 ms packets. If the encoder sampling rate + * is 16 kHz the maximum payload size is between 120 and 400 bytes. If the + * encoder sampling rate is 32 kHz the maximum payload size is between 120 + * and 600 bytes. + * + * If an out of range limit is used, the function returns -1, but the closest + * valid value will be applied. + * + * --------------- + * IMPORTANT NOTES + * --------------- + * The size of a packet is limited to the minimum of 'max-payload-size' and + * 'max-rate.' For instance, let's assume the max-payload-size is set to + * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps + * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms + * frame-size. Then a packet with a frame-size of 30 ms is limited to 150, + * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to + * 170 bytes, i.e. min(170, 300). + * + * Input: + * - ISAC_main_inst : iSAC instance + * - maxPayloadBytes : maximum size of the payload in bytes + * valid values are between 120 and 400 bytes + * if encoder sampling rate is 16 kHz. For + * 32 kHz encoder sampling rate valid values + * are between 120 and 600 bytes. + * + * Return value : 0 if successful + * -1 if error happens + */ + + WebRtc_Word16 WebRtcIsac_SetMaxPayloadSize( + ISACStruct* ISAC_main_inst, + WebRtc_Word16 maxPayloadBytes); + + + /****************************************************************************** + * WebRtcIsac_SetMaxRate(...) + * + * This function sets the maximum rate which the codec may not exceed for + * any signal packet. The maximum rate is defined and payload-size per + * frame-size in bits per second. + * + * The codec has a maximum rate of 53400 bits per second (200 bytes per 30 + * ms) if the encoder sampling rate is 16kHz, and 160 kbps (600 bytes/30 ms) + * if the encoder sampling rate is 32 kHz. + * + * It is possible to set a maximum rate between 32000 and 53400 bits/sec + * in wideband mode, and 32000 to 160000 bits/sec in super-wideband mode. + * + * If an out of range limit is used, the function returns -1, but the closest + * valid value will be applied. + * + * --------------- + * IMPORTANT NOTES + * --------------- + * The size of a packet is limited to the minimum of 'max-payload-size' and + * 'max-rate.' For instance, let's assume the max-payload-size is set to + * 170 bytes, and max-rate is set to 40 kbps. Note that a limit of 40 kbps + * translates to 150 bytes for 30ms frame-size & 300 bytes for 60ms + * frame-size. Then a packet with a frame-size of 30 ms is limited to 150, + * i.e. min(170, 150), and a packet with 60 ms frame-size is limited to + * 170 bytes, min(170, 300). + * + * Input: + * - ISAC_main_inst : iSAC instance + * - maxRate : maximum rate in bits per second, + * valid values are 32000 to 53400 bits/sec in + * wideband mode, and 32000 to 160000 bits/sec in + * super-wideband mode. + * + * Return value : 0 if successful + * -1 if error happens + */ + + WebRtc_Word16 WebRtcIsac_SetMaxRate( + ISACStruct* ISAC_main_inst, + WebRtc_Word32 maxRate); + + + /****************************************************************************** + * WebRtcIsac_DecSampRate() + * Return the sampling rate of the decoded audio. + * + * Input: + * - ISAC_main_inst : iSAC instance + * + * Return value : enumerator representing sampling frequency + * associated with the decoder, i.e. the + * sampling rate of the decoded audio. + * + */ + + enum IsacSamplingRate WebRtcIsac_DecSampRate( + ISACStruct* ISAC_main_inst); + + + /****************************************************************************** + * WebRtcIsac_EncSampRate() + * + * Input: + * - ISAC_main_inst : iSAC instance + * + * Return value : enumerator representing sampling frequency + * associated with the encoder, the input audio + * is expected to be sampled at this rate. + * + */ + + enum IsacSamplingRate WebRtcIsac_EncSampRate( + ISACStruct* ISAC_main_inst); + + + /****************************************************************************** + * WebRtcIsac_SetDecSampRate() + * Set the sampling rate of the decoder. Initialization of the decoder WILL + * NOT overwrite the sampling rate of the encoder. The default value is 16 kHz + * which is set when the instance is created. + * + * Input: + * - ISAC_main_inst : iSAC instance + * - sampRate : enumerator specifying the sampling rate. + * + * Return value : 0 if successful + * -1 if failed. + */ + + WebRtc_Word16 WebRtcIsac_SetDecSampRate( + ISACStruct* ISAC_main_inst, + enum IsacSamplingRate sampRate); + + + /****************************************************************************** + * WebRtcIsac_SetEncSampRate() + * Set the sampling rate of the encoder. Initialization of the encoder WILL + * NOT overwrite the sampling rate of the encoder. The default value is 16 kHz + * which is set when the instance is created. The encoding-mode and the + * bottleneck remain unchanged by this call, however, the maximum rate and + * maximum payload-size will reset to their default value. + * + * Input: + * - ISAC_main_inst : iSAC instance + * - sampRate : enumerator specifying the sampling rate. + * + * Return value : 0 if successful + * -1 if failed. + */ + + WebRtc_Word16 WebRtcIsac_SetEncSampRate( + ISACStruct* ISAC_main_inst, + enum IsacSamplingRate sampRate); + + + + /****************************************************************************** + * WebRtcIsac_GetNewBitStream(...) + * + * This function returns encoded data, with the recieved bwe-index in the + * stream. If the rate is set to a value less than bottleneck of codec + * the new bistream will be re-encoded with the given target rate. + * It should always return a complete packet, i.e. only called once + * even for 60 msec frames. + * + * NOTE 1! This function does not write in the ISACStruct, it is not allowed. + * NOTE 2! Currently not implemented for SWB mode. + * NOTE 3! Rates larger than the bottleneck of the codec will be limited + * to the current bottleneck. + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - bweIndex : Index of bandwidth estimate to put in new + * bitstream + * - rate : target rate of the transcoder is bits/sec. + * Valid values are the accepted rate in iSAC, + * i.e. 10000 to 56000. + * - isRCU : if the new bit-stream is an RCU stream. + * Note that the rate parameter always indicates + * the target rate of the main paylaod, regardless + * of 'isRCU' value. + * + * Output: + * - encoded : The encoded data vector + * + * Return value : >0 - Length (in bytes) of coded data + * -1 - Error or called in SWB mode + * NOTE! No error code is written to + * the struct since it is only allowed to read + * the struct. + */ + WebRtc_Word16 WebRtcIsac_GetNewBitStream( + ISACStruct* ISAC_main_inst, + WebRtc_Word16 bweIndex, + WebRtc_Word16 jitterInfo, + WebRtc_Word32 rate, + WebRtc_Word16* encoded, + WebRtc_Word16 isRCU); + + + + /**************************************************************************** + * WebRtcIsac_GetDownLinkBwIndex(...) + * + * This function returns index representing the Bandwidth estimate from + * other side to this side. + * + * Input: + * - ISAC_main_inst : iSAC struct + * + * Output: + * - bweIndex : Bandwidth estimate to transmit to other side. + * + */ + + WebRtc_Word16 WebRtcIsac_GetDownLinkBwIndex( + ISACStruct* ISAC_main_inst, + WebRtc_Word16* bweIndex, + WebRtc_Word16* jitterInfo); + + + /**************************************************************************** + * WebRtcIsac_UpdateUplinkBw(...) + * + * This function takes an index representing the Bandwidth estimate from + * this side to other side and updates BWE. + * + * Input: + * - ISAC_main_inst : iSAC struct + * - bweIndex : Bandwidth estimate from other side. + * + */ + + WebRtc_Word16 WebRtcIsac_UpdateUplinkBw( + ISACStruct* ISAC_main_inst, + WebRtc_Word16 bweIndex); + + + /**************************************************************************** + * WebRtcIsac_ReadBwIndex(...) + * + * This function returns the index of the Bandwidth estimate from the bitstream. + * + * Input: + * - encoded : Encoded bitstream + * + * Output: + * - frameLength : Length of frame in packet (in samples) + * - bweIndex : Bandwidth estimate in bitstream + * + */ + + WebRtc_Word16 WebRtcIsac_ReadBwIndex( + const WebRtc_Word16* encoded, + WebRtc_Word16* bweIndex); + + + + /******************************************************************************* + * WebRtcIsac_GetNewFrameLen(...) + * + * returns the frame lenght (in samples) of the next packet. In the case of channel-adaptive + * mode, iSAC decides on its frame lenght based on the estimated bottleneck + * this allows a user to prepare for the next packet (at the encoder) + * + * The primary usage is in CE to make the iSAC works in channel-adaptive mode + * + * Input: + * - ISAC_main_inst : iSAC struct + * + * Return Value : frame lenght in samples + * + */ + + WebRtc_Word16 WebRtcIsac_GetNewFrameLen( + ISACStruct* ISAC_main_inst); + + + /**************************************************************************** + * WebRtcIsac_GetRedPayload(...) + * + * Populates "encoded" with the redundant payload of the recently encoded + * frame. This function has to be called once that WebRtcIsac_Encode(...) + * returns a positive value. Regardless of the frame-size this function will + * be called only once after encoding is completed. + * + * Input: + * - ISAC_main_inst : iSAC struct + * + * Output: + * - encoded : the encoded data vector + * + * + * Return value: + * : >0 - Length (in bytes) of coded data + * : -1 - Error + * + * + */ + WebRtc_Word16 WebRtcIsac_GetRedPayload( + ISACStruct* ISAC_main_inst, + WebRtc_Word16* encoded); + + + /**************************************************************************** + * WebRtcIsac_DecodeRcu(...) + * + * This function decodes a redundant (RCU) iSAC frame. Function is called in + * NetEq with a stored RCU payload i case of packet loss. Output speech length + * will be a multiple of 480 samples: 480 or 960 samples, + * depending on the framesize (30 or 60 ms). + * + * Input: + * - ISAC_main_inst : ISAC instance. + * - encoded : encoded ISAC RCU frame(s) + * - len : bytes in encoded vector + * + * Output: + * - decoded : The decoded vector + * + * Return value : >0 - number of samples in decoded vector + * -1 - Error + */ + WebRtc_Word16 WebRtcIsac_DecodeRcu( + ISACStruct* ISAC_main_inst, + const WebRtc_UWord16* encoded, + WebRtc_Word16 len, + WebRtc_Word16* decoded, + WebRtc_Word16* speechType); + + +#if defined(__cplusplus) +} +#endif + + + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_INTERFACE_ISAC_H_ */ diff --git a/libs/miniwebrtc/audio/coding_isac/main/lattice.c b/libs/miniwebrtc/audio/coding_isac/main/lattice.c new file mode 100644 index 00000000..a46135a3 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/lattice.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * lattice.c + * + * contains the normalized lattice filter routines (MA and AR) for iSAC codec + * + */ +#include "settings.h" +#include "codec.h" + +#include +#include +#ifdef WEBRTC_ANDROID +#include +#endif + +/* filter the signal using normalized lattice filter */ +/* MA filter */ +void WebRtcIsac_NormLatticeFilterMa(int orderCoef, + float *stateF, + float *stateG, + float *lat_in, + double *filtcoeflo, + double *lat_out) +{ + int n,k,i,u,temp1; + int ord_1 = orderCoef+1; + float sth[MAX_AR_MODEL_ORDER]; + float cth[MAX_AR_MODEL_ORDER]; + float inv_cth[MAX_AR_MODEL_ORDER]; + double a[MAX_AR_MODEL_ORDER+1]; + float f[MAX_AR_MODEL_ORDER+1][HALF_SUBFRAMELEN], g[MAX_AR_MODEL_ORDER+1][HALF_SUBFRAMELEN]; + float gain1; + + for (u=0;u=0;i--) //get the state of f&g for the first input, for all orders + { + ARf[i][0] = cth[i]*ARf[i+1][0] - sth[i]*stateG[i]; + ARg[i+1][0] = sth[i]*ARf[i+1][0] + cth[i]* stateG[i]; + } + ARg[0][0] = ARf[0][0]; + + for(n=0;n<(HALF_SUBFRAMELEN-1);n++) + { + for(k=orderCoef-1;k>=0;k--) + { + ARf[k][n+1] = cth[k]*ARf[k+1][n+1] - sth[k]*ARg[k][n]; + ARg[k+1][n+1] = sth[k]*ARf[k+1][n+1] + cth[k]* ARg[k][n]; + } + ARg[0][n+1] = ARf[0][n+1]; + } + + memcpy(lat_out+u * HALF_SUBFRAMELEN, &(ARf[0][0]), sizeof(float) * HALF_SUBFRAMELEN); + + /* cannot use memcpy in the following */ + for (i=0;i0; m--) + { + tmp_inv = 1.0f / cth2; + for (k=1; k<=m; k++) + { + tmp[k] = ((float)a[k] - sth[m] * (float)a[m-k+1]) * tmp_inv; + } + + for (k=1; k +#include + +#define LEVINSON_EPS 1.0e-10 + + +/* window */ +/* Matlab generation code: + * t = (1:256)/257; r = 1-(1-t).^.45; w = sin(r*pi).^3; w = w/sum(w); plot((1:256)/8, w); grid; + * for k=1:16, fprintf(1, '%.8f, ', w(k*16 + (-15:0))); fprintf(1, '\n'); end + */ +static const double kLpcCorrWindow[WINLEN] = { + 0.00000000, 0.00000001, 0.00000004, 0.00000010, 0.00000020, + 0.00000035, 0.00000055, 0.00000083, 0.00000118, 0.00000163, + 0.00000218, 0.00000283, 0.00000361, 0.00000453, 0.00000558, 0.00000679, + 0.00000817, 0.00000973, 0.00001147, 0.00001342, 0.00001558, + 0.00001796, 0.00002058, 0.00002344, 0.00002657, 0.00002997, + 0.00003365, 0.00003762, 0.00004190, 0.00004651, 0.00005144, 0.00005673, + 0.00006236, 0.00006837, 0.00007476, 0.00008155, 0.00008875, + 0.00009636, 0.00010441, 0.00011290, 0.00012186, 0.00013128, + 0.00014119, 0.00015160, 0.00016252, 0.00017396, 0.00018594, 0.00019846, + 0.00021155, 0.00022521, 0.00023946, 0.00025432, 0.00026978, + 0.00028587, 0.00030260, 0.00031998, 0.00033802, 0.00035674, + 0.00037615, 0.00039626, 0.00041708, 0.00043863, 0.00046092, 0.00048396, + 0.00050775, 0.00053233, 0.00055768, 0.00058384, 0.00061080, + 0.00063858, 0.00066720, 0.00069665, 0.00072696, 0.00075813, + 0.00079017, 0.00082310, 0.00085692, 0.00089164, 0.00092728, 0.00096384, + 0.00100133, 0.00103976, 0.00107914, 0.00111947, 0.00116077, + 0.00120304, 0.00124630, 0.00129053, 0.00133577, 0.00138200, + 0.00142924, 0.00147749, 0.00152676, 0.00157705, 0.00162836, 0.00168070, + 0.00173408, 0.00178850, 0.00184395, 0.00190045, 0.00195799, + 0.00201658, 0.00207621, 0.00213688, 0.00219860, 0.00226137, + 0.00232518, 0.00239003, 0.00245591, 0.00252284, 0.00259079, 0.00265977, + 0.00272977, 0.00280078, 0.00287280, 0.00294582, 0.00301984, + 0.00309484, 0.00317081, 0.00324774, 0.00332563, 0.00340446, + 0.00348421, 0.00356488, 0.00364644, 0.00372889, 0.00381220, 0.00389636, + 0.00398135, 0.00406715, 0.00415374, 0.00424109, 0.00432920, + 0.00441802, 0.00450754, 0.00459773, 0.00468857, 0.00478001, + 0.00487205, 0.00496464, 0.00505775, 0.00515136, 0.00524542, 0.00533990, + 0.00543476, 0.00552997, 0.00562548, 0.00572125, 0.00581725, + 0.00591342, 0.00600973, 0.00610612, 0.00620254, 0.00629895, + 0.00639530, 0.00649153, 0.00658758, 0.00668341, 0.00677894, 0.00687413, + 0.00696891, 0.00706322, 0.00715699, 0.00725016, 0.00734266, + 0.00743441, 0.00752535, 0.00761540, 0.00770449, 0.00779254, + 0.00787947, 0.00796519, 0.00804963, 0.00813270, 0.00821431, 0.00829437, + 0.00837280, 0.00844949, 0.00852436, 0.00859730, 0.00866822, + 0.00873701, 0.00880358, 0.00886781, 0.00892960, 0.00898884, + 0.00904542, 0.00909923, 0.00915014, 0.00919805, 0.00924283, 0.00928436, + 0.00932252, 0.00935718, 0.00938821, 0.00941550, 0.00943890, + 0.00945828, 0.00947351, 0.00948446, 0.00949098, 0.00949294, + 0.00949020, 0.00948262, 0.00947005, 0.00945235, 0.00942938, 0.00940099, + 0.00936704, 0.00932738, 0.00928186, 0.00923034, 0.00917268, + 0.00910872, 0.00903832, 0.00896134, 0.00887763, 0.00878706, + 0.00868949, 0.00858478, 0.00847280, 0.00835343, 0.00822653, 0.00809199, + 0.00794970, 0.00779956, 0.00764145, 0.00747530, 0.00730103, + 0.00711857, 0.00692787, 0.00672888, 0.00652158, 0.00630597, + 0.00608208, 0.00584994, 0.00560962, 0.00536124, 0.00510493, 0.00484089, + 0.00456935, 0.00429062, 0.00400505, 0.00371310, 0.00341532, + 0.00311238, 0.00280511, 0.00249452, 0.00218184, 0.00186864, + 0.00155690, 0.00124918, 0.00094895, 0.00066112, 0.00039320, 0.00015881 +}; + +double WebRtcIsac_LevDurb(double *a, double *k, double *r, int order) +{ + + double sum, alpha; + int m, m_h, i; + alpha = 0; //warning -DH + a[0] = 1.0; + if (r[0] < LEVINSON_EPS) { /* if r[0] <= 0, set LPC coeff. to zero */ + for (i = 0; i < order; i++) { + k[i] = 0; + a[i+1] = 0; + } + } else { + a[1] = k[0] = -r[1]/r[0]; + alpha = r[0] + r[1] * k[0]; + for (m = 1; m < order; m++){ + sum = r[m + 1]; + for (i = 0; i < m; i++){ + sum += a[i+1] * r[m - i]; + } + k[m] = -sum / alpha; + alpha += k[m] * sum; + m_h = (m + 1) >> 1; + for (i = 0; i < m_h; i++){ + sum = a[i+1] + k[m] * a[m - i]; + a[m - i] += k[m] * a[i+1]; + a[i+1] = sum; + } + a[m+1] = k[m]; + } + } + return alpha; +} + + +//was static before, but didn't work with MEX file +void WebRtcIsac_GetVars(const double *input, const WebRtc_Word16 *pitchGains_Q12, + double *oldEnergy, double *varscale) +{ + double nrg[4], chng, pg; + int k; + + double pitchGains[4]={0,0,0,0};; + + /* Calculate energies of first and second frame halfs */ + nrg[0] = 0.0001; + for (k = QLOOKAHEAD/2; k < (FRAMESAMPLES_QUARTER + QLOOKAHEAD) / 2; k++) { + nrg[0] += input[k]*input[k]; + } + nrg[1] = 0.0001; + for ( ; k < (FRAMESAMPLES_HALF + QLOOKAHEAD) / 2; k++) { + nrg[1] += input[k]*input[k]; + } + nrg[2] = 0.0001; + for ( ; k < (FRAMESAMPLES*3/4 + QLOOKAHEAD) / 2; k++) { + nrg[2] += input[k]*input[k]; + } + nrg[3] = 0.0001; + for ( ; k < (FRAMESAMPLES + QLOOKAHEAD) / 2; k++) { + nrg[3] += input[k]*input[k]; + } + + /* Calculate average level change */ + chng = 0.25 * (fabs(10.0 * log10(nrg[3] / nrg[2])) + + fabs(10.0 * log10(nrg[2] / nrg[1])) + + fabs(10.0 * log10(nrg[1] / nrg[0])) + + fabs(10.0 * log10(nrg[0] / *oldEnergy))); + + + /* Find average pitch gain */ + pg = 0.0; + for (k=0; k<4; k++) + { + pitchGains[k] = ((float)pitchGains_Q12[k])/4096; + pg += pitchGains[k]; + } + pg *= 0.25; + + /* If pitch gain is low and energy constant - increase noise level*/ + /* Matlab code: + pg = 0:.01:.45; plot(pg, 0.0 + 1.0 * exp( -1.0 * exp(-200.0 * pg.*pg.*pg) / (1.0 + 0.4 * 0) )) + */ + *varscale = 0.0 + 1.0 * exp( -1.4 * exp(-200.0 * pg*pg*pg) / (1.0 + 0.4 * chng) ); + + *oldEnergy = nrg[3]; +} + +void +WebRtcIsac_GetVarsUB( + const double* input, + double* oldEnergy, + double* varscale) +{ + double nrg[4], chng; + int k; + + /* Calculate energies of first and second frame halfs */ + nrg[0] = 0.0001; + for (k = 0; k < (FRAMESAMPLES_QUARTER) / 2; k++) { + nrg[0] += input[k]*input[k]; + } + nrg[1] = 0.0001; + for ( ; k < (FRAMESAMPLES_HALF) / 2; k++) { + nrg[1] += input[k]*input[k]; + } + nrg[2] = 0.0001; + for ( ; k < (FRAMESAMPLES*3/4) / 2; k++) { + nrg[2] += input[k]*input[k]; + } + nrg[3] = 0.0001; + for ( ; k < (FRAMESAMPLES) / 2; k++) { + nrg[3] += input[k]*input[k]; + } + + /* Calculate average level change */ + chng = 0.25 * (fabs(10.0 * log10(nrg[3] / nrg[2])) + + fabs(10.0 * log10(nrg[2] / nrg[1])) + + fabs(10.0 * log10(nrg[1] / nrg[0])) + + fabs(10.0 * log10(nrg[0] / *oldEnergy))); + + + /* If pitch gain is low and energy constant - increase noise level*/ + /* Matlab code: + pg = 0:.01:.45; plot(pg, 0.0 + 1.0 * exp( -1.0 * exp(-200.0 * pg.*pg.*pg) / (1.0 + 0.4 * 0) )) + */ + *varscale = exp( -1.4 / (1.0 + 0.4 * chng) ); + + *oldEnergy = nrg[3]; +} + +void WebRtcIsac_GetLpcCoefLb(double *inLo, double *inHi, MaskFiltstr *maskdata, + double signal_noise_ratio, const WebRtc_Word16 *pitchGains_Q12, + double *lo_coeff, double *hi_coeff) +{ + int k, n, j, pos1, pos2; + double varscale; + + double DataLo[WINLEN], DataHi[WINLEN]; + double corrlo[ORDERLO+2], corrlo2[ORDERLO+1]; + double corrhi[ORDERHI+1]; + double k_veclo[ORDERLO], k_vechi[ORDERHI]; + + double a_LO[ORDERLO+1], a_HI[ORDERHI+1]; + double tmp, res_nrg; + + double FwdA, FwdB; + + /* hearing threshold level in dB; higher value gives more noise */ + const double HearThresOffset = -28.0; + + /* bandwdith expansion factors for low- and high band */ + const double gammaLo = 0.9; + const double gammaHi = 0.8; + + /* less-noise-at-low-frequencies factor */ + double aa; + + + /* convert from dB to signal level */ + const double H_T_H = pow(10.0, 0.05 * HearThresOffset); + double S_N_R = pow(10.0, 0.05 * signal_noise_ratio) / 3.46; /* divide by sqrt(12) */ + + /* change quallevel depending on pitch gains and level fluctuations */ + WebRtcIsac_GetVars(inLo, pitchGains_Q12, &(maskdata->OldEnergy), &varscale); + + /* less-noise-at-low-frequencies factor */ + aa = 0.35 * (0.5 + 0.5 * varscale); + + /* replace data in buffer by new look-ahead data */ + for (pos1 = 0; pos1 < QLOOKAHEAD; pos1++) + maskdata->DataBufferLo[pos1 + WINLEN - QLOOKAHEAD] = inLo[pos1]; + + for (k = 0; k < SUBFRAMES; k++) { + + /* Update input buffer and multiply signal with window */ + for (pos1 = 0; pos1 < WINLEN - UPDATE/2; pos1++) { + maskdata->DataBufferLo[pos1] = maskdata->DataBufferLo[pos1 + UPDATE/2]; + maskdata->DataBufferHi[pos1] = maskdata->DataBufferHi[pos1 + UPDATE/2]; + DataLo[pos1] = maskdata->DataBufferLo[pos1] * kLpcCorrWindow[pos1]; + DataHi[pos1] = maskdata->DataBufferHi[pos1] * kLpcCorrWindow[pos1]; + } + pos2 = k * UPDATE/2; + for (n = 0; n < UPDATE/2; n++, pos1++) { + maskdata->DataBufferLo[pos1] = inLo[QLOOKAHEAD + pos2]; + maskdata->DataBufferHi[pos1] = inHi[pos2++]; + DataLo[pos1] = maskdata->DataBufferLo[pos1] * kLpcCorrWindow[pos1]; + DataHi[pos1] = maskdata->DataBufferHi[pos1] * kLpcCorrWindow[pos1]; + } + + /* Get correlation coefficients */ + WebRtcIsac_AutoCorr(corrlo, DataLo, WINLEN, ORDERLO+1); /* computing autocorrelation */ + WebRtcIsac_AutoCorr(corrhi, DataHi, WINLEN, ORDERHI); + + + /* less noise for lower frequencies, by filtering/scaling autocorrelation sequences */ + corrlo2[0] = (1.0+aa*aa) * corrlo[0] - 2.0*aa * corrlo[1]; + tmp = (1.0 + aa*aa); + for (n = 1; n <= ORDERLO; n++) { + corrlo2[n] = tmp * corrlo[n] - aa * (corrlo[n-1] + corrlo[n+1]); + } + tmp = (1.0+aa) * (1.0+aa); + for (n = 0; n <= ORDERHI; n++) { + corrhi[n] = tmp * corrhi[n]; + } + + /* add white noise floor */ + corrlo2[0] += 1e-6; + corrhi[0] += 1e-6; + + + FwdA = 0.01; + FwdB = 0.01; + + /* recursive filtering of correlation over subframes */ + for (n = 0; n <= ORDERLO; n++) { + maskdata->CorrBufLo[n] = FwdA * maskdata->CorrBufLo[n] + corrlo2[n]; + corrlo2[n] = ((1.0-FwdA)*FwdB) * maskdata->CorrBufLo[n] + (1.0-FwdB) * corrlo2[n]; + } + for (n = 0; n <= ORDERHI; n++) { + maskdata->CorrBufHi[n] = FwdA * maskdata->CorrBufHi[n] + corrhi[n]; + corrhi[n] = ((1.0-FwdA)*FwdB) * maskdata->CorrBufHi[n] + (1.0-FwdB) * corrhi[n]; + } + + /* compute prediction coefficients */ + WebRtcIsac_LevDurb(a_LO, k_veclo, corrlo2, ORDERLO); + WebRtcIsac_LevDurb(a_HI, k_vechi, corrhi, ORDERHI); + + /* bandwidth expansion */ + tmp = gammaLo; + for (n = 1; n <= ORDERLO; n++) { + a_LO[n] *= tmp; + tmp *= gammaLo; + } + + /* residual energy */ + res_nrg = 0.0; + for (j = 0; j <= ORDERLO; j++) { + for (n = 0; n <= j; n++) { + res_nrg += a_LO[j] * corrlo2[j-n] * a_LO[n]; + } + for (n = j+1; n <= ORDERLO; n++) { + res_nrg += a_LO[j] * corrlo2[n-j] * a_LO[n]; + } + } + + /* add hearing threshold and compute the gain */ + *lo_coeff++ = S_N_R / (sqrt(res_nrg) / varscale + H_T_H); + + /* copy coefficients to output array */ + for (n = 1; n <= ORDERLO; n++) { + *lo_coeff++ = a_LO[n]; + } + + + /* bandwidth expansion */ + tmp = gammaHi; + for (n = 1; n <= ORDERHI; n++) { + a_HI[n] *= tmp; + tmp *= gammaHi; + } + + /* residual energy */ + res_nrg = 0.0; + for (j = 0; j <= ORDERHI; j++) { + for (n = 0; n <= j; n++) { + res_nrg += a_HI[j] * corrhi[j-n] * a_HI[n]; + } + for (n = j+1; n <= ORDERHI; n++) { + res_nrg += a_HI[j] * corrhi[n-j] * a_HI[n]; + } + } + + /* add hearing threshold and compute of the gain */ + *hi_coeff++ = S_N_R / (sqrt(res_nrg) / varscale + H_T_H); + + /* copy coefficients to output array */ + for (n = 1; n <= ORDERHI; n++) { + *hi_coeff++ = a_HI[n]; + } + } +} + + + +/****************************************************************************** + * WebRtcIsac_GetLpcCoefUb() + * + * Compute LP coefficients and correlation coefficients. At 12 kHz LP + * coefficients of the first and the last sub-frame is computed. At 16 kHz + * LP coefficients of 4th, 8th and 12th sub-frames are computed. We always + * compute correlation coefficients of all sub-frames. + * + * Inputs: + * -inSignal : Input signal + * -maskdata : a structure keeping signal from previous frame. + * -bandwidth : specifies if the codec is in 0-16 kHz mode or + * 0-12 kHz mode. + * + * Outputs: + * -lpCoeff : pointer to a buffer where A-polynomials are + * written to (first coeff is 1 and it is not + * written) + * -corrMat : a matrix where correlation coefficients of each + * sub-frame are written to one row. + * -varscale : a scale used to compute LPC gains. + */ +void +WebRtcIsac_GetLpcCoefUb( + double* inSignal, + MaskFiltstr* maskdata, + double* lpCoeff, + double corrMat[][UB_LPC_ORDER + 1], + double* varscale, + WebRtc_Word16 bandwidth) +{ + int frameCntr, activeFrameCntr, n, pos1, pos2; + WebRtc_Word16 criterion1; + WebRtc_Word16 criterion2; + WebRtc_Word16 numSubFrames = SUBFRAMES * (1 + (bandwidth == isac16kHz)); + double data[WINLEN]; + double corrSubFrame[UB_LPC_ORDER+2]; + double reflecCoeff[UB_LPC_ORDER]; + + double aPolynom[UB_LPC_ORDER+1]; + double tmp; + + /* bandwdith expansion factors */ + const double gamma = 0.9; + + /* change quallevel depending on pitch gains and level fluctuations */ + WebRtcIsac_GetVarsUB(inSignal, &(maskdata->OldEnergy), varscale); + + /* replace data in buffer by new look-ahead data */ + for(frameCntr = 0, activeFrameCntr = 0; frameCntr < numSubFrames; + frameCntr++) + { + if(frameCntr == SUBFRAMES) + { + // we are in 16 kHz + varscale++; + WebRtcIsac_GetVarsUB(&inSignal[FRAMESAMPLES_HALF], + &(maskdata->OldEnergy), varscale); + } + /* Update input buffer and multiply signal with window */ + for(pos1 = 0; pos1 < WINLEN - UPDATE/2; pos1++) + { + maskdata->DataBufferLo[pos1] = maskdata->DataBufferLo[pos1 + + UPDATE/2]; + data[pos1] = maskdata->DataBufferLo[pos1] * kLpcCorrWindow[pos1]; + } + pos2 = frameCntr * UPDATE/2; + for(n = 0; n < UPDATE/2; n++, pos1++, pos2++) + { + maskdata->DataBufferLo[pos1] = inSignal[pos2]; + data[pos1] = maskdata->DataBufferLo[pos1] * kLpcCorrWindow[pos1]; + } + + /* Get correlation coefficients */ + /* computing autocorrelation */ + WebRtcIsac_AutoCorr(corrSubFrame, data, WINLEN, UB_LPC_ORDER+1); + memcpy(corrMat[frameCntr], corrSubFrame, + (UB_LPC_ORDER+1)*sizeof(double)); + + criterion1 = ((frameCntr == 0) || (frameCntr == (SUBFRAMES - 1))) && + (bandwidth == isac12kHz); + criterion2 = (((frameCntr+1) % 4) == 0) && + (bandwidth == isac16kHz); + if(criterion1 || criterion2) + { + /* add noise */ + corrSubFrame[0] += 1e-6; + /* compute prediction coefficients */ + WebRtcIsac_LevDurb(aPolynom, reflecCoeff, corrSubFrame, + UB_LPC_ORDER); + + /* bandwidth expansion */ + tmp = gamma; + for (n = 1; n <= UB_LPC_ORDER; n++) + { + *lpCoeff++ = aPolynom[n] * tmp; + tmp *= gamma; + } + activeFrameCntr++; + } + } +} + + + +/****************************************************************************** + * WebRtcIsac_GetLpcGain() + * + * Compute the LPC gains for each sub-frame, given the LPC of each sub-frame + * and the corresponding correlation coefficients. + * + * Inputs: + * -signal_noise_ratio : the desired SNR in dB. + * -numVecs : number of sub-frames + * -corrMat : a matrix of correlation coefficients where + * each row is a set of correlation coefficients of + * one sub-frame. + * -varscale : a scale computed when WebRtcIsac_GetLpcCoefUb() + * is called. + * + * Outputs: + * -gain : pointer to a buffer where LP gains are written. + * + */ +void +WebRtcIsac_GetLpcGain( + double signal_noise_ratio, + const double* filtCoeffVecs, + int numVecs, + double* gain, + double corrMat[][UB_LPC_ORDER + 1], + const double* varscale) +{ + WebRtc_Word16 j, n; + WebRtc_Word16 subFrameCntr; + double aPolynom[ORDERLO + 1]; + double res_nrg; + + const double HearThresOffset = -28.0; + const double H_T_H = pow(10.0, 0.05 * HearThresOffset); + /* divide by sqrt(12) = 3.46 */ + const double S_N_R = pow(10.0, 0.05 * signal_noise_ratio) / 3.46; + + aPolynom[0] = 1; + for(subFrameCntr = 0; subFrameCntr < numVecs; subFrameCntr++) + { + if(subFrameCntr == SUBFRAMES) + { + // we are in second half of a SWB frame. use new varscale + varscale++; + } + memcpy(&aPolynom[1], &filtCoeffVecs[(subFrameCntr * (UB_LPC_ORDER + 1)) + + 1], sizeof(double) * UB_LPC_ORDER); + + /* residual energy */ + res_nrg = 0.0; + for(j = 0; j <= UB_LPC_ORDER; j++) + { + for(n = 0; n <= j; n++) + { + res_nrg += aPolynom[j] * corrMat[subFrameCntr][j-n] * + aPolynom[n]; + } + for(n = j+1; n <= UB_LPC_ORDER; n++) + { + res_nrg += aPolynom[j] * corrMat[subFrameCntr][n-j] * + aPolynom[n]; + } + } + + /* add hearing threshold and compute the gain */ + gain[subFrameCntr] = S_N_R / (sqrt(res_nrg) / *varscale + H_T_H); + } +} diff --git a/libs/miniwebrtc/audio/coding_isac/main/lpc_analysis.h b/libs/miniwebrtc/audio/coding_isac/main/lpc_analysis.h new file mode 100644 index 00000000..4eafeac7 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/lpc_analysis.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * lpc_analysis.h + * + * LPC functions + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_ANALYSIS_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_ANALYSIS_H_ + +#include "settings.h" +#include "structs.h" + +double WebRtcIsac_LevDurb(double *a, double *k, double *r, int order); + +void WebRtcIsac_GetVars(const double *input, const WebRtc_Word16 *pitchGains_Q12, + double *oldEnergy, double *varscale); + +void WebRtcIsac_GetLpcCoefLb(double *inLo, double *inHi, MaskFiltstr *maskdata, + double signal_noise_ratio, const WebRtc_Word16 *pitchGains_Q12, + double *lo_coeff, double *hi_coeff); + + +void WebRtcIsac_GetLpcGain( + double signal_noise_ratio, + const double* filtCoeffVecs, + int numVecs, + double* gain, + double corrLo[][UB_LPC_ORDER + 1], + const double* varscale); + +void WebRtcIsac_GetLpcCoefUb( + double* inSignal, + MaskFiltstr* maskdata, + double* lpCoeff, + double corr[][UB_LPC_ORDER + 1], + double* varscale, + WebRtc_Word16 bandwidth); + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_ANALYIS_H_ */ diff --git a/libs/miniwebrtc/audio/coding_isac/main/lpc_gain_swb_tables.c b/libs/miniwebrtc/audio/coding_isac/main/lpc_gain_swb_tables.c new file mode 100644 index 00000000..25c69cbf --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/lpc_gain_swb_tables.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * SWB_KLT_Tables_LPCGain.c + * + * This file defines tables used for entropy coding of LPC Gain + * of upper-band. + * + */ + +#include "lpc_gain_swb_tables.h" +#include "settings.h" +#include "typedefs.h" + +const double WebRtcIsac_kQSizeLpcGain = 0.100000; + +const double WebRtcIsac_kMeanLpcGain = -3.3822; + +/* +* The smallest reconstruction points for quantiztion of +* LPC gains. +*/ +const double WebRtcIsac_kLeftRecPointLpcGain[SUBFRAMES] = +{ + -0.800000, -1.000000, -1.200000, -2.200000, -3.000000, -12.700000 +}; + +/* +* Number of reconstruction points of quantizers for LPC Gains. +*/ +const WebRtc_Word16 WebRtcIsac_kNumQCellLpcGain[SUBFRAMES] = +{ + 17, 20, 25, 45, 77, 170 +}; +/* +* Starting index for entropy decoder to search for the right interval, +* one entry per LAR coefficient +*/ +const WebRtc_UWord16 WebRtcIsac_kLpcGainEntropySearch[SUBFRAMES] = +{ + 8, 10, 12, 22, 38, 85 +}; + +/* +* The following 6 vectors define CDF of 6 decorrelated LPC +* gains. +*/ +const WebRtc_UWord16 WebRtcIsac_kLpcGainCdfVec0[18] = +{ + 0, 10, 27, 83, 234, 568, 1601, 4683, 16830, 57534, 63437, + 64767, 65229, 65408, 65483, 65514, 65527, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcGainCdfVec1[21] = +{ + 0, 15, 33, 84, 185, 385, 807, 1619, 3529, 7850, 19488, + 51365, 62437, 64548, 65088, 65304, 65409, 65484, 65507, 65522, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcGainCdfVec2[26] = +{ + 0, 15, 29, 54, 89, 145, 228, 380, 652, 1493, 4260, + 12359, 34133, 50749, 57224, 60814, 62927, 64078, 64742, 65103, 65311, 65418, + 65473, 65509, 65521, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcGainCdfVec3[46] = +{ + 0, 8, 12, 16, 26, 42, 56, 76, 111, 164, 247, + 366, 508, 693, 1000, 1442, 2155, 3188, 4854, 7387, 11249, 17617, + 30079, 46711, 56291, 60127, 62140, 63258, 63954, 64384, 64690, 64891, 65031, + 65139, 65227, 65293, 65351, 65399, 65438, 65467, 65492, 65504, 65510, 65518, + 65523, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcGainCdfVec4[78] = +{ + 0, 17, 29, 39, 51, 70, 104, 154, 234, 324, 443, + 590, 760, 971, 1202, 1494, 1845, 2274, 2797, 3366, 4088, 4905, + 5899, 7142, 8683, 10625, 12983, 16095, 20637, 28216, 38859, 47237, 51537, + 54150, 56066, 57583, 58756, 59685, 60458, 61103, 61659, 62144, 62550, 62886, + 63186, 63480, 63743, 63954, 64148, 64320, 64467, 64600, 64719, 64837, 64939, + 65014, 65098, 65160, 65211, 65250, 65290, 65325, 65344, 65366, 65391, 65410, + 65430, 65447, 65460, 65474, 65487, 65494, 65501, 65509, 65513, 65518, 65520, + 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcGainCdfVec5[171] = +{ + 0, 10, 12, 14, 16, 18, 23, 29, 35, 42, 51, + 58, 65, 72, 78, 87, 96, 103, 111, 122, 134, 150, + 167, 184, 202, 223, 244, 265, 289, 315, 346, 379, 414, + 450, 491, 532, 572, 613, 656, 700, 751, 802, 853, 905, + 957, 1021, 1098, 1174, 1250, 1331, 1413, 1490, 1565, 1647, 1730, + 1821, 1913, 2004, 2100, 2207, 2314, 2420, 2532, 2652, 2783, 2921, + 3056, 3189, 3327, 3468, 3640, 3817, 3993, 4171, 4362, 4554, 4751, + 4948, 5142, 5346, 5566, 5799, 6044, 6301, 6565, 6852, 7150, 7470, + 7797, 8143, 8492, 8835, 9181, 9547, 9919, 10315, 10718, 11136, 11566, + 12015, 12482, 12967, 13458, 13953, 14432, 14903, 15416, 15936, 16452, 16967, + 17492, 18024, 18600, 19173, 19736, 20311, 20911, 21490, 22041, 22597, 23157, + 23768, 24405, 25034, 25660, 26280, 26899, 27614, 28331, 29015, 29702, 30403, + 31107, 31817, 32566, 33381, 34224, 35099, 36112, 37222, 38375, 39549, 40801, + 42074, 43350, 44626, 45982, 47354, 48860, 50361, 51845, 53312, 54739, 56026, + 57116, 58104, 58996, 59842, 60658, 61488, 62324, 63057, 63769, 64285, 64779, + 65076, 65344, 65430, 65500, 65517, 65535 +}; + +/* +* An array of pointers to CDFs of decorrelated LPC Gains +*/ +const WebRtc_UWord16* WebRtcIsac_kLpcGainCdfMat[SUBFRAMES] = +{ + WebRtcIsac_kLpcGainCdfVec0, WebRtcIsac_kLpcGainCdfVec1, + WebRtcIsac_kLpcGainCdfVec2, WebRtcIsac_kLpcGainCdfVec3, + WebRtcIsac_kLpcGainCdfVec4, WebRtcIsac_kLpcGainCdfVec5 +}; + +/* +* A matrix to decorrellate LPC gains of subframes. +*/ +const double WebRtcIsac_kLpcGainDecorrMat[SUBFRAMES][SUBFRAMES] = +{ + {-0.150860, 0.327872, 0.367220, 0.504613, 0.559270, 0.409234}, + { 0.457128, -0.613591, -0.289283, -0.029734, 0.393760, 0.418240}, + {-0.626043, 0.136489, -0.439118, -0.448323, 0.135987, 0.420869}, + { 0.526617, 0.480187, 0.242552, -0.488754, -0.158713, 0.411331}, + {-0.302587, -0.494953, 0.588112, -0.063035, -0.404290, 0.387510}, + { 0.086378, 0.147714, -0.428875, 0.548300, -0.570121, 0.401391} +}; diff --git a/libs/miniwebrtc/audio/coding_isac/main/lpc_gain_swb_tables.h b/libs/miniwebrtc/audio/coding_isac/main/lpc_gain_swb_tables.h new file mode 100644 index 00000000..1eba97c8 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/lpc_gain_swb_tables.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * SWB_KLT_Tables_LPCGain.h + * + * This file declares tables used for entropy coding of LPC Gain + * of upper-band. + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_GAIN_SWB_TABLES_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_GAIN_SWB_TABLES_H_ + +#include "settings.h" +#include "typedefs.h" + +extern const double WebRtcIsac_kQSizeLpcGain; + +extern const double WebRtcIsac_kLeftRecPointLpcGain[SUBFRAMES]; + +extern const WebRtc_Word16 WebRtcIsac_kNumQCellLpcGain[SUBFRAMES]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcGainEntropySearch[SUBFRAMES]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcGainCdfVec0[18]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcGainCdfVec1[21]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcGainCdfVec2[26]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcGainCdfVec3[46]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcGainCdfVec4[78]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcGainCdfVec5[171]; + +extern const WebRtc_UWord16* WebRtcIsac_kLpcGainCdfMat[SUBFRAMES]; + +extern const double WebRtcIsac_kLpcGainDecorrMat[SUBFRAMES][SUBFRAMES]; + +#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_GAIN_SWB_TABLES_H_ diff --git a/libs/miniwebrtc/audio/coding_isac/main/lpc_shape_swb12_tables.c b/libs/miniwebrtc/audio/coding_isac/main/lpc_shape_swb12_tables.c new file mode 100644 index 00000000..695d5832 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/lpc_shape_swb12_tables.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * SWB_KLT_Tables.c + * + * This file defines tables used for entropy coding of LPC shape of + * upper-band signal if the bandwidth is 12 kHz. + * + */ + +#include "lpc_shape_swb12_tables.h" +#include "settings.h" +#include "typedefs.h" + +/* +* Mean value of LAR +*/ +const double WebRtcIsac_kMeanLarUb12[UB_LPC_ORDER] = +{ + 0.03748928306641, 0.09453441192543, -0.01112522344398, 0.03800237516842 +}; + +/* +* A rotation matrix to decorrelate intra-vector correlation, +* i.e. correlation among components of LAR vector. +*/ +const double WebRtcIsac_kIntraVecDecorrMatUb12[UB_LPC_ORDER][UB_LPC_ORDER] = +{ + {-0.00075365493856, -0.05809964887743, -0.23397966154116, 0.97050367376411}, + { 0.00625021257734, -0.17299965610679, 0.95977735920651, 0.22104179375008}, + { 0.20543384258374, -0.96202143495696, -0.15301870801552, -0.09432375099565}, + {-0.97865075648479, -0.20300322280841, -0.02581111653779, -0.01913568980258} +}; + +/* +* A rotation matrix to remove correlation among LAR coefficients +* of different LAR vectors. One might guess that decorrelation matrix +* for the first component should differ from the second component +* but we haven't observed a significant benefit of having different +* decorrelation matrices for different components. +*/ +const double WebRtcIsac_kInterVecDecorrMatUb12 +[UB_LPC_VEC_PER_FRAME][UB_LPC_VEC_PER_FRAME] = +{ + { 0.70650597970460, -0.70770707262373}, + {-0.70770707262373, -0.70650597970460} +}; + +/* +* LAR quantization step-size. +*/ +const double WebRtcIsac_kLpcShapeQStepSizeUb12 = 0.150000; + +/* +* The smallest reconstruction points for quantiztion of LAR coefficients. +*/ +const double WebRtcIsac_kLpcShapeLeftRecPointUb12 +[UB_LPC_ORDER*UB_LPC_VEC_PER_FRAME] = +{ + -0.900000, -1.050000, -1.350000, -1.800000, -1.350000, -1.650000, + -2.250000, -3.450000 +}; + +/* +* Number of reconstruction points of quantizers for LAR coefficients. +*/ +const WebRtc_Word16 WebRtcIsac_kLpcShapeNumRecPointUb12 +[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME] = +{ + 13, 15, 19, 27, 19, 24, 32, 48 +}; + +/* +* Starting index for entropy decoder to search for the right interval, +* one entry per LAR coefficient +*/ +const WebRtc_UWord16 WebRtcIsac_kLpcShapeEntropySearchUb12 +[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME] = +{ + 6, 7, 9, 13, 9, 12, 16, 24 +}; + +/* +* The following 8 vectors define CDF of 8 decorrelated LAR +* coefficients. +*/ +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec0Ub12[14] = +{ + 0, 13, 95, 418, 1687, 6498, 21317, 44200, 59029, 63849, 65147, + 65449, 65525, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec1Ub12[16] = +{ + 0, 10, 59, 255, 858, 2667, 8200, 22609, 42988, 57202, 62947, + 64743, 65308, 65476, 65522, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec2Ub12[20] = +{ + 0, 18, 40, 118, 332, 857, 2017, 4822, 11321, 24330, 41279, + 54342, 60637, 63394, 64659, 65184, 65398, 65482, 65518, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec3Ub12[28] = +{ + 0, 21, 38, 90, 196, 398, 770, 1400, 2589, 4650, 8211, + 14933, 26044, 39592, 50814, 57452, 60971, 62884, 63995, 64621, 65019, 65273, + 65410, 65480, 65514, 65522, 65531, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec4Ub12[20] = +{ + 0, 7, 46, 141, 403, 969, 2132, 4649, 10633, 24902, 43254, + 54665, 59928, 62674, 64173, 64938, 65293, 65464, 65523, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec5Ub12[25] = +{ + 0, 7, 22, 72, 174, 411, 854, 1737, 3545, 6774, 13165, + 25221, 40980, 52821, 58714, 61706, 63472, 64437, 64989, 65287, 65430, 65503, + 65525, 65529, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec6Ub12[33] = +{ + 0, 11, 21, 36, 65, 128, 228, 401, 707, 1241, 2126, + 3589, 6060, 10517, 18853, 31114, 42477, 49770, 54271, 57467, 59838, 61569, + 62831, 63772, 64433, 64833, 65123, 65306, 65419, 65466, 65499, 65519, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec7Ub12[49] = +{ + 0, 14, 34, 67, 107, 167, 245, 326, 449, 645, 861, + 1155, 1508, 2003, 2669, 3544, 4592, 5961, 7583, 9887, 13256, 18765, + 26519, 34077, 40034, 44349, 47795, 50663, 53262, 55473, 57458, 59122, 60592, + 61742, 62690, 63391, 63997, 64463, 64794, 65045, 65207, 65309, 65394, 65443, + 65478, 65504, 65514, 65523, 65535 +}; + +/* +* An array of pointers to CDFs of decorrelated LARs +*/ +const WebRtc_UWord16* WebRtcIsac_kLpcShapeCdfMatUb12 +[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME] = +{ + WebRtcIsac_kLpcShapeCdfVec0Ub12, WebRtcIsac_kLpcShapeCdfVec1Ub12, + WebRtcIsac_kLpcShapeCdfVec2Ub12, WebRtcIsac_kLpcShapeCdfVec3Ub12, + WebRtcIsac_kLpcShapeCdfVec4Ub12, WebRtcIsac_kLpcShapeCdfVec5Ub12, + WebRtcIsac_kLpcShapeCdfVec6Ub12, WebRtcIsac_kLpcShapeCdfVec7Ub12 +}; diff --git a/libs/miniwebrtc/audio/coding_isac/main/lpc_shape_swb12_tables.h b/libs/miniwebrtc/audio/coding_isac/main/lpc_shape_swb12_tables.h new file mode 100644 index 00000000..1e93847f --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/lpc_shape_swb12_tables.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * lpc_shape_swb12_tables.h + * + * This file declares tables used for entropy coding of LPC shape of + * upper-band signal if the bandwidth is 12 kHz. + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB12_TABLES_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB12_TABLES_H_ + +#include "settings.h" +#include "typedefs.h" + +extern const double WebRtcIsac_kMeanLarUb12[UB_LPC_ORDER]; + +extern const double WebRtcIsac_kMeanLpcGain; + +extern const double WebRtcIsac_kIntraVecDecorrMatUb12[UB_LPC_ORDER][UB_LPC_ORDER]; + +extern const double WebRtcIsac_kInterVecDecorrMatUb12 +[UB_LPC_VEC_PER_FRAME][UB_LPC_VEC_PER_FRAME]; + +extern const double WebRtcIsac_kLpcShapeQStepSizeUb12; + +extern const double WebRtcIsac_kLpcShapeLeftRecPointUb12 +[UB_LPC_ORDER*UB_LPC_VEC_PER_FRAME]; + + +extern const WebRtc_Word16 WebRtcIsac_kLpcShapeNumRecPointUb12 +[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeEntropySearchUb12 +[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec0Ub12[14]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec1Ub12[16]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec2Ub12[20]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec3Ub12[28]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec4Ub12[20]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec5Ub12[25]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec6Ub12[33]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec7Ub12[49]; + +extern const WebRtc_UWord16* WebRtcIsac_kLpcShapeCdfMatUb12 +[UB_LPC_ORDER * UB_LPC_VEC_PER_FRAME]; + +#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB12_TABLES_H_ diff --git a/libs/miniwebrtc/audio/coding_isac/main/lpc_shape_swb16_tables.c b/libs/miniwebrtc/audio/coding_isac/main/lpc_shape_swb16_tables.c new file mode 100644 index 00000000..89f45233 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/lpc_shape_swb16_tables.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * SWB16_KLT_Tables.c + * + * This file defines tables used for entropy coding of LPC shape of + * upper-band signal if the bandwidth is 16 kHz. + * + */ + +#include "lpc_shape_swb16_tables.h" +#include "settings.h" +#include "typedefs.h" + +/* +* Mean value of LAR +*/ +const double WebRtcIsac_kMeanLarUb16[UB_LPC_ORDER] = +{ +0.454978, 0.364747, 0.102999, 0.104523 +}; + +/* +* A rotation matrix to decorrelate intra-vector correlation, +* i.e. correlation among components of LAR vector. +*/ +const double WebRtcIsac_kIintraVecDecorrMatUb16[UB_LPC_ORDER][UB_LPC_ORDER] = +{ + {-0.020528, -0.085858, -0.002431, 0.996093}, + {-0.033155, 0.036102, 0.998786, 0.004866}, + { 0.202627, 0.974853, -0.028940, 0.088132}, + {-0.978479, 0.202454, -0.039785, -0.002811} +}; + +/* +* A rotation matrix to remove correlation among LAR coefficients +* of different LAR vectors. One might guess that decorrelation matrix +* for the first component should differ from the second component +* but we haven't observed a significant benefit of having different +* decorrelation matrices for different components. +*/ +const double WebRtcIsac_kInterVecDecorrMatUb16 +[UB16_LPC_VEC_PER_FRAME][UB16_LPC_VEC_PER_FRAME] = +{ + { 0.291675, -0.515786, 0.644927, 0.482658}, + {-0.647220, 0.479712, 0.289556, 0.516856}, + { 0.643084, 0.485489, -0.289307, 0.516763}, + {-0.287185, -0.517823, -0.645389, 0.482553} +}; + +/* +* The following 16 vectors define CDF of 16 decorrelated LAR +* coefficients. +*/ +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub16[14] = +{ + 0, 2, 20, 159, 1034, 5688, 20892, 44653, + 59849, 64485, 65383, 65518, 65534, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec1Ub16[16] = +{ + 0, 1, 7, 43, 276, 1496, 6681, 21653, + 43891, 58859, 64022, 65248, 65489, 65529, 65534, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec2Ub16[18] = +{ + 0, 1, 9, 54, 238, 933, 3192, 9461, + 23226, 42146, 56138, 62413, 64623, 65300, 65473, 65521, + 65533, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec3Ub16[30] = +{ + 0, 2, 4, 8, 17, 36, 75, 155, + 329, 683, 1376, 2662, 5047, 9508, 17526, 29027, + 40363, 48997, 55096, 59180, 61789, 63407, 64400, 64967, + 65273, 65429, 65497, 65526, 65534, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec4Ub16[16] = +{ + 0, 1, 10, 63, 361, 1785, 7407, 22242, + 43337, 58125, 63729, 65181, 65472, 65527, 65534, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec5Ub16[17] = +{ + 0, 1, 7, 29, 134, 599, 2443, 8590, + 22962, 42635, 56911, 63060, 64940, 65408, 65513, 65531, + 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec6Ub16[21] = +{ + 0, 1, 5, 16, 57, 191, 611, 1808, + 4847, 11755, 24612, 40910, 53789, 60698, 63729, 64924, + 65346, 65486, 65523, 65532, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec7Ub16[36] = +{ + 0, 1, 4, 12, 25, 55, 104, 184, + 314, 539, 926, 1550, 2479, 3861, 5892, 8845, + 13281, 20018, 29019, 38029, 45581, 51557, 56057, 59284, + 61517, 63047, 64030, 64648, 65031, 65261, 65402, 65480, + 65518, 65530, 65534, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec8Ub16[21] = +{ + 0, 1, 2, 7, 26, 103, 351, 1149, + 3583, 10204, 23846, 41711, 55361, 61917, 64382, 65186, + 65433, 65506, 65528, 65534, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub160[21] = +{ + 0, 6, 19, 63, 205, 638, 1799, 4784, + 11721, 24494, 40803, 53805, 60886, 63822, 64931, 65333, + 65472, 65517, 65530, 65533, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub161[28] = +{ + 0, 1, 3, 11, 31, 86, 221, 506, + 1101, 2296, 4486, 8477, 15356, 26079, 38941, 49952, + 57165, 61257, 63426, 64549, 65097, 65351, 65463, 65510, + 65526, 65532, 65534, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub162[55] = +{ + 0, 3, 12, 23, 42, 65, 89, 115, + 150, 195, 248, 327, 430, 580, 784, 1099, + 1586, 2358, 3651, 5899, 9568, 14312, 19158, 23776, + 28267, 32663, 36991, 41153, 45098, 48680, 51870, 54729, + 57141, 59158, 60772, 62029, 63000, 63761, 64322, 64728, + 65000, 65192, 65321, 65411, 65463, 65496, 65514, 65523, + 65527, 65529, 65531, 65532, 65533, 65534, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub163[26] = +{ + 0, 2, 4, 10, 21, 48, 114, 280, + 701, 1765, 4555, 11270, 24267, 41213, 54285, 61003, + 63767, 64840, 65254, 65421, 65489, 65514, 65526, 65532, + 65534, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub164[28] = +{ + 0, 1, 3, 6, 15, 36, 82, 196, + 453, 1087, 2557, 5923, 13016, 25366, 40449, 52582, + 59539, 62896, 64389, 65033, 65316, 65442, 65494, 65519, + 65529, 65533, 65534, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub165[34] = +{ + 0, 2, 4, 8, 18, 35, 73, 146, + 279, 524, 980, 1789, 3235, 5784, 10040, 16998, + 27070, 38543, 48499, 55421, 59712, 62257, 63748, 64591, + 65041, 65278, 65410, 65474, 65508, 65522, 65530, 65533, + 65534, 65535 +}; + +const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub166[71] = +{ + 0, 1, 2, 6, 13, 26, 55, 92, + 141, 191, 242, 296, 355, 429, 522, 636, + 777, 947, 1162, 1428, 1753, 2137, 2605, 3140, + 3743, 4409, 5164, 6016, 6982, 8118, 9451, 10993, + 12754, 14810, 17130, 19780, 22864, 26424, 30547, 35222, + 40140, 44716, 48698, 52056, 54850, 57162, 59068, 60643, + 61877, 62827, 63561, 64113, 64519, 64807, 65019, 65167, + 65272, 65343, 65399, 65440, 65471, 65487, 65500, 65509, + 65518, 65524, 65527, 65531, 65533, 65534, 65535 +}; + +/* +* An array of pointers to CDFs of decorrelated LARs +*/ +const WebRtc_UWord16* WebRtcIsac_kLpcShapeCdfMatUb16 +[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME] = { + WebRtcIsac_kLpcShapeCdfVec01Ub16, + WebRtcIsac_kLpcShapeCdfVec1Ub16, + WebRtcIsac_kLpcShapeCdfVec2Ub16, + WebRtcIsac_kLpcShapeCdfVec3Ub16, + WebRtcIsac_kLpcShapeCdfVec4Ub16, + WebRtcIsac_kLpcShapeCdfVec5Ub16, + WebRtcIsac_kLpcShapeCdfVec6Ub16, + WebRtcIsac_kLpcShapeCdfVec7Ub16, + WebRtcIsac_kLpcShapeCdfVec8Ub16, + WebRtcIsac_kLpcShapeCdfVec01Ub160, + WebRtcIsac_kLpcShapeCdfVec01Ub161, + WebRtcIsac_kLpcShapeCdfVec01Ub162, + WebRtcIsac_kLpcShapeCdfVec01Ub163, + WebRtcIsac_kLpcShapeCdfVec01Ub164, + WebRtcIsac_kLpcShapeCdfVec01Ub165, + WebRtcIsac_kLpcShapeCdfVec01Ub166 +}; + +/* +* The smallest reconstruction points for quantiztion of LAR coefficients. +*/ +const double WebRtcIsac_kLpcShapeLeftRecPointUb16 +[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME] = +{ + -0.8250, -0.9750, -1.1250, -2.1750, -0.9750, -1.1250, -1.4250, + -2.6250, -1.4250, -1.2750, -1.8750, -3.6750, -1.7250, -1.8750, + -2.3250, -5.4750 +}; + +/* +* Number of reconstruction points of quantizers for LAR coefficients. +*/ +const WebRtc_Word16 WebRtcIsac_kLpcShapeNumRecPointUb16 +[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME] = +{ + 13, 15, 17, 29, 15, 16, 20, 35, 20, + 20, 27, 54, 25, 27, 33, 70 +}; + +/* +* Starting index for entropy decoder to search for the right interval, +* one entry per LAR coefficient +*/ +const WebRtc_UWord16 WebRtcIsac_kLpcShapeEntropySearchUb16 +[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME] = +{ + 6, 7, 8, 14, 7, 8, 10, 17, 10, + 10, 13, 27, 12, 13, 16, 35 +}; + +/* +* LAR quantization step-size. +*/ +const double WebRtcIsac_kLpcShapeQStepSizeUb16 = 0.150000; diff --git a/libs/miniwebrtc/audio/coding_isac/main/lpc_shape_swb16_tables.h b/libs/miniwebrtc/audio/coding_isac/main/lpc_shape_swb16_tables.h new file mode 100644 index 00000000..68d08b20 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/lpc_shape_swb16_tables.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * lpc_shape_swb16_tables.h + * + * This file declares tables used for entropy coding of LPC shape of + * upper-band signal if the bandwidth is 16 kHz. + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB16_TABLES_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB16_TABLES_H_ + +#include "settings.h" +#include "typedefs.h" + + +extern const double WebRtcIsac_kMeanLarUb16[UB_LPC_ORDER]; + +extern const double WebRtcIsac_kIintraVecDecorrMatUb16[UB_LPC_ORDER][UB_LPC_ORDER]; + +extern const double WebRtcIsac_kInterVecDecorrMatUb16 +[UB16_LPC_VEC_PER_FRAME][UB16_LPC_VEC_PER_FRAME]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub16[14]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec1Ub16[16]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec2Ub16[18]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec3Ub16[30]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec4Ub16[16]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec5Ub16[17]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec6Ub16[21]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec7Ub16[36]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec8Ub16[21]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub160[21]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub161[28]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub162[55]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub163[26]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub164[28]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub165[34]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeCdfVec01Ub166[71]; + +extern const WebRtc_UWord16* WebRtcIsac_kLpcShapeCdfMatUb16 +[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME]; + +extern const double WebRtcIsac_kLpcShapeLeftRecPointUb16 +[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME]; + +extern const WebRtc_Word16 WebRtcIsac_kLpcShapeNumRecPointUb16 +[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME]; + +extern const WebRtc_UWord16 WebRtcIsac_kLpcShapeEntropySearchUb16 +[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME]; + +extern const double WebRtcIsac_kLpcShapeQStepSizeUb16; + +#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_SHAPE_SWB16_TABLES_H_ diff --git a/libs/miniwebrtc/audio/coding_isac/main/lpc_tables.c b/libs/miniwebrtc/audio/coding_isac/main/lpc_tables.c new file mode 100644 index 00000000..7df61214 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/lpc_tables.c @@ -0,0 +1,1129 @@ +/* + * 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. + */ + +/* coding tables for the KLT coefficients */ + +#include "lpc_tables.h" +#include "settings.h" + +/* indices of KLT coefficients used */ +const WebRtc_UWord16 WebRtcIsac_kQKltSelIndGain[12] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11}; + +const WebRtc_UWord16 WebRtcIsac_kQKltSelIndShape[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 WebRtcIsac_kQKltModelCdf[4] = { + 0, 15434, 37548, 65535}; + +/* pointer to cdf array for model indicator */ +const WebRtc_UWord16 *WebRtcIsac_kQKltModelCdfPtr[1] = {WebRtcIsac_kQKltModelCdf}; + +/* initial cdf index for decoder of model indicator */ +const WebRtc_UWord16 WebRtcIsac_kQKltModelInitIndex[1] = {1}; + +/* offset to go from rounded value to quantization index */ +const short WebRtcIsac_kQKltQuantMinGain[12] = { + 3, 6, 4, 6, 6, 9, 5, 16, 11, 34, 32, 47}; + + +const short WebRtcIsac_kQKltQuantMinShape[108] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 1, 1, 1, 2, 2, 2, 3, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, + 1, 1, 1, 2, 2, 3, 0, 0, 0, 0, + 1, 0, 1, 1, 1, 1, 1, 1, 1, 2, + 2, 4, 3, 5, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 2, 1, 2, 2, 3, 4, + 4, 7, 0, 0, 1, 1, 1, 1, 1, 1, + 1, 2, 3, 2, 3, 4, 4, 5, 7, 13, + 0, 1, 1, 2, 3, 2, 2, 2, 4, 4, + 5, 6, 7, 11, 9, 13, 12, 26}; + +/* maximum quantization index */ +const WebRtc_UWord16 WebRtcIsac_kQKltMaxIndGain[12] = { + 6, 12, 8, 14, 10, 19, 12, 31, 22, 56, 52, 138}; + +const WebRtc_UWord16 WebRtcIsac_kQKltMaxIndShape[108] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 2, 2, 2, 2, 4, 4, 5, 6, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 1, 2, 2, + 2, 2, 3, 4, 5, 7, 0, 0, 0, 0, + 2, 0, 2, 2, 2, 2, 3, 2, 2, 4, + 4, 6, 6, 9, 0, 0, 0, 0, 2, 2, + 2, 2, 2, 2, 3, 2, 4, 4, 7, 7, + 9, 13, 0, 0, 2, 2, 2, 2, 2, 2, + 3, 4, 5, 4, 6, 8, 8, 10, 16, 25, + 0, 2, 2, 4, 5, 4, 4, 4, 7, 8, + 9, 10, 13, 19, 17, 23, 25, 49}; + +/* index offset */ +const WebRtc_UWord16 WebRtcIsac_kQKltOffsetGain[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 WebRtcIsac_kQKltOffsetShape[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 WebRtcIsac_kQKltInitIndexGain[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 WebRtcIsac_kQKltInitIndexShape[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 WebRtcIsac_kQKltOfLevelsGain[3] = { + 0, 392, 779}; + +const WebRtc_UWord16 WebRtcIsac_kQKltOfLevelsShape[3] = { + 0, 578, 1152}; + +/* quantizer representation levels */ +const double WebRtcIsac_kQKltLevelsGain[1176] = { +-2.78127126, -1.76745590, -0.77913790, -0.00437329, 0.79961206, 1.81775776, 2.81389782, -5.78753143, -4.88384084, -3.89320940, +-2.88133610, -1.92859977, -0.86347396, 0.02003888, 0.86140400, 1.89667156, 2.97134967, 3.98781964, 4.91727277, 5.82865898, +-4.11195874, -2.80898424, -1.87547977, -0.80943825, -0.00679084, 0.79573851, 1.83953397, 2.67586037, 3.76274082, -6.10933968, +-4.93034581, -3.89281296, -2.91530625, -1.89684163, -0.85319130, -0.02275767, 0.86862017, 1.91578276, 2.96107339, 3.96543056, + 4.91369908, 5.91058154, 6.83848343, 8.07136925, -5.87470395, -4.84703049, -3.84284597, -2.86168446, -1.89290192, -0.82798145, +-0.00080013, 0.82594974, 1.85754329, 2.88351798, 3.96172628, -8.85684885, -7.87387461, -6.97811862, -5.93256270, -4.94301439, +-3.95513701, -2.96041544, -1.94031192, -0.87961478, -0.00456201, 0.89911505, 1.91723376, 2.94011511, 3.93302540, 4.97990967, + 5.93133404, 7.02181199, 7.92407762, 8.80155440, 10.04665814, -4.82396678, -3.85612158, -2.89482244, -1.89558408, -0.90036978, +-0.00677823, 0.90607989, 1.90937981, 2.91175777, 3.91637730, 4.97565723, 5.84771228, 7.11145863, -16.07879840, -15.03776309, +-13.93905670, -12.95671800, -11.89171202, -10.95820934, -9.95923714, -8.94357334, -7.99068299, -6.97481009, -5.94826231, -4.96673988, +-3.97490466, -2.97846970, -1.95130435, -0.94215262, -0.01444043, 0.96770704, 1.95848598, 2.94107862, 3.95666119, 4.97253085, + 5.97191122, 6.93277360, 7.96608727, 8.87958779, 10.00264269, 10.86560820, 12.07449071, 13.04491775, 13.97507061, 14.91845261, +-10.85696295, -9.83365357, -9.01245635, -7.95915145, -6.95625003, -5.95362618, -4.93468444, -3.98760978, -2.95044407, -1.97041277, +-0.97701799, -0.00840234, 0.97834289, 1.98361415, 2.97802439, 3.96415871, 4.95369042, 5.94101770, 6.92756798, 7.94063998, + 8.85951828, 9.97077022, 11.00068503, -33.92030406, -32.81426422, -32.00000000, -31.13243639, -30.11886909, -29.06017570, -28.12598824, +-27.22045482, -25.81215858, -25.07849962, -23.93018013, -23.02097643, -21.89529725, -20.99091085, -19.98889048, -18.94327044, -17.96562071, +-16.96126218, -15.95054062, -14.98516200, -13.97101012, -13.02106500, -11.98438006, -11.03216748, -9.95930286, -8.97043946, -7.98085082, +-6.98360995, -5.98998802, -4.98668173, -4.00032906, -3.00420619, -1.98701132, -0.99324682, -0.00609324, 0.98297834, 1.99483076, + 3.00305044, 3.97142097, 4.97525759, 5.98612258, 6.97448236, 7.97575900, 9.01086211, 9.98665542, 11.00541438, 11.98078628, + 12.92352471, 14.06849675, 14.99949430, 15.94904834, 16.97440321, 18.04040916, 18.88987609, 20.05312391, 21.00000000, 21.79443341, +-31.98578825, -31.00000000, -29.89060567, -28.98555686, -27.97114102, -26.84935410, -26.02402230, -24.94195278, -23.92336849, -22.95552382, +-21.97932836, -20.96055470, -19.99649553, -19.03436122, -17.96706525, -17.01139515, -16.01363516, -14.99154248, -14.00298333, -12.99630613, +-11.99955519, -10.99000421, -10.00819092, -8.99763648, -7.98431793, -7.01769025, -5.99604690, -4.99980697, -3.99334671, -3.01748192, +-2.02051217, -1.00848371, -0.01942358, 1.00477757, 1.95477872, 2.98593031, 3.98779079, 4.96862849, 6.02694771, 6.93983733, + 7.89874717, 8.99615862, 10.02367921, 10.96293452, 11.84351528, 12.92207187, 13.85122329, 15.05146877, 15.99371264, 17.00000000, + 18.00000000, 19.00000000, 19.82763573, -47.00000000, -46.00000000, -44.87138498, -44.00000000, -43.00000000, -42.00000000, -41.00000000, +-39.88966612, -38.98913239, -37.80306486, -37.23584325, -35.94200288, -34.99881301, -34.11361858, -33.06507360, -32.13129135, -30.90891364, +-29.81511907, -28.99250380, -28.04535391, -26.99767800, -26.04418164, -24.95687851, -24.04865595, -23.03392645, -21.89366707, -20.93517364, +-19.99388660, -18.91620943, -18.03749683, -16.99532379, -15.98683813, -15.06421479, -13.99359211, -12.99714098, -11.97022520, -10.98500279, +-9.98834422, -8.95729330, -8.01232284, -7.00253661, -5.99681626, -5.01207817, -3.95914904, -3.01232178, -1.96615919, -0.97687670, + 0.01228030, 0.98412288, 2.01753544, 3.00580570, 3.97783510, 4.98846894, 6.01321400, 7.00867732, 8.00416375, 9.01771966, + 9.98637729, 10.98255180, 11.99194163, 13.01807333, 14.00999545, 15.00118556, 16.00089224, 17.00584148, 17.98251763, 18.99942091, + 19.96917690, 20.97839265, 21.98207297, 23.00171271, 23.99930737, 24.99746061, 26.00936304, 26.98240132, 28.01126868, 29.01395915, + 29.98153507, 31.01376711, 31.99876818, 33.00475317, 33.99753994, 34.99493913, 35.98933585, 36.95620160, 37.98428461, 38.99317544, + 40.01832073, 40.98048133, 41.95999283, 42.98232091, 43.96523612, 44.99574268, 45.99524194, 47.05464025, 48.03821548, 48.99354366, + 49.96400411, 50.98017973, 51.95184408, 52.96291806, 54.00194392, 54.96603783, 55.95623778, 57.03076595, 58.05889901, 58.99081551, + 59.97928121, 61.05071612, 62.03971580, 63.01286038, 64.01290338, 65.02074503, 65.99454594, 67.00399425, 67.96571257, 68.95305727, + 69.92030664, 70.95594862, 71.98088567, 73.04764124, 74.00285480, 75.02696330, 75.89837673, 76.93459997, 78.16266309, 78.83317543, + 80.00000000, 80.87251574, 82.09803524, 83.10671664, 84.00000000, 84.77023523, 86.00000000, 87.00000000, 87.92946897, 88.69159118, + 90.00000000, 90.90535270, -3.00000000, -2.00000000, -0.77592424, -0.00564307, 0.76727305, 2.00000000, 3.00000000, -6.00000000, +-5.00000000, -4.00000000, -2.92897924, -1.85623684, -0.72445303, -0.00119184, 0.72896652, 2.05710416, 3.17909894, 4.00000000, + 5.00000000, -3.00000000, -2.00000000, -0.67480586, -0.00028016, 0.66618169, 2.00000000, 3.00000000, 4.00000000, -7.00000000, +-6.00000000, -5.00000000, -3.78336783, -2.84811556, -2.04088844, -0.71114371, 0.03142493, 0.69662772, 1.91417930, 3.00000000, + 4.01411062, 5.00000000, 6.00000000, 7.00000000, -6.00000000, -5.00000000, -4.00000000, -3.00000000, -2.00000000, -0.63703469, + 0.00169604, 0.66294191, 1.83808563, 3.00000000, 4.00000000, -8.00000000, -7.00000000, -6.03082300, -5.00000000, -3.88061019, +-2.92670084, -1.99902336, -0.72898996, -0.02880170, 0.73769927, 1.95920233, 2.78356263, 4.08100921, 5.00000000, 6.00000000, + 6.78771437, 8.00000000, 9.00000000, 10.00000000, 11.00000000, -5.00000000, -4.00000000, -2.88150384, -1.89520024, -0.71479482, + 0.00962397, 0.72816030, 1.73583550, 3.00000000, 4.00000000, 5.00000000, 6.00000000, 7.00000000, -16.00000000, -15.00000000, +-13.80516401, -13.00000000, -12.00000000, -11.00000000, -10.02723144, -9.11825995, -8.05820112, -7.00000000, -6.17943541, -5.01837980, +-3.97546169, -2.92806857, -1.89778775, -0.81138893, -0.02246016, 0.80528415, 1.85705214, 2.96438524, 3.97540151, 4.79684246, + 6.00000000, 6.75549513, 8.12185828, 9.00000000, 10.00000000, 11.00000000, 12.00000000, 13.00000000, 14.00000000, -11.00000000, +-10.00000000, -9.00000000, -7.91603344, -6.77865892, -5.85765006, -4.93342332, -3.96679157, -2.84925552, -1.89230732, -0.85384229, + 0.00579591, 0.84863246, 1.89006713, 2.89483818, 3.87322971, 5.13228411, 6.00000000, 7.00000000, 8.00000000, 9.00000000, + 10.00000000, 11.00000000, -34.00000000, -33.00000000, -32.00000000, -31.00000000, -30.00000000, -29.00000000, -28.00000000, -27.00000000, +-26.00000000, -25.00000000, -24.00000000, -23.00000000, -22.00000000, -21.00000000, -20.19501953, -19.00000000, -18.00000000, -17.00000000, +-16.00000000, -14.89069633, -14.00000000, -13.00000000, -12.16260304, -11.15418282, -9.83543570, -8.85600407, -7.82712677, -7.05664308, +-5.97007352, -4.89268438, -3.93822771, -2.94975269, -1.92192127, -0.90702480, 0.03974847, 0.92488359, 1.93747579, 2.94500522, + 3.95181797, 4.95433087, 5.95141808, 7.00212920, 8.02964757, 9.03210585, 9.84644504, 10.82907720, 11.87622530, 12.96908371, + 14.00000000, 15.16963413, 15.94902025, 17.00000000, 18.00000000, 19.00000000, 20.00000000, 21.00000000, 22.00000000, -29.00000000, +-27.79780781, -27.00757888, -26.01571026, -24.89695568, -23.99946491, -22.98699614, -21.96678139, -20.99883532, -20.00851529, -18.94738054, +-17.98672566, -16.98684787, -15.96917397, -14.99856852, -13.98974852, -12.97786927, -11.96110939, -10.98877093, -9.99875257, -8.99001359, +-8.00799989, -6.99471760, -6.00034670, -4.99936372, -4.00581479, -3.00424577, -2.02047620, -0.99713266, -0.00366397, 1.00803955, + 1.98452687, 3.00748501, 4.02714611, 4.97661026, 5.99337271, 6.99754716, 8.00713602, 8.97184974, 9.98047901, 10.97685939, + 11.99533975, 12.96107876, 13.95061478, 15.00756776, 15.94078690, 16.88231059, 17.92069248, 18.78011047, 20.00000000, 21.00000000, + 22.00000000, -55.76988333, -54.96048193, -53.88411581, -52.94117980, -51.80983449, -50.90359699, -50.00000000, -48.99838741, -47.97685542, +-47.03288597, -45.97820919, -45.02418374, -43.90081897, -42.88832512, -41.98234549, -40.96745512, -39.98148729, -39.06792854, -37.96493755, +-36.98707870, -36.03416079, -35.01192444, -33.95785029, -32.99469087, -31.96633807, -31.01769053, -29.99727691, -28.99329690, -27.98873019, +-27.00344273, -25.97657141, -25.00511074, -23.96689479, -23.01566842, -22.01632643, -21.00076343, -19.97788007, -18.97248680, -17.96076284, +-16.97585453, -15.98345587, -15.01612745, -13.96862118, -12.96622055, -12.02196641, -11.02078103, -9.98445656, -9.00050060, -8.03442387, +-7.00363761, -5.97921358, -4.98886269, -4.00528221, -3.01672947, -1.98599795, -1.00668518, -0.02633490, 1.00794139, 2.00837138, + 2.99213287, 3.98710216, 4.99064334, 6.01416391, 7.01759708, 7.97878151, 8.99665730, 10.02656114, 11.01863887, 12.01207901, + 13.00958725, 13.99237829, 15.00954971, 16.00724653, 17.00606559, 17.99886292, 18.99611967, 19.98808171, 21.01871930, 21.97014763, + 22.99833843, 24.00316842, 24.99949142, 25.98539601, 27.02480733, 27.98075377, 28.98266019, 30.00611445, 30.99409128, 31.94523141, + 32.97688339, 33.98800206, 35.00177074, 35.98639997, 36.98939428, 37.95644255, 39.00114054, 39.99492439, 40.99338254, 41.97050844, + 43.03085663, 43.96757668, 44.97800970, 45.95953358, 46.98109551, 47.99368477, 49.00141209, 49.94459923, 50.93298108, 51.99894661, + 53.06463883, 53.99704669, 55.02037199, 55.98368047, 57.01930954, 58.03813852, 58.96232502, 60.01644186, 61.03254711, 62.01086576, + 62.87962247, 63.98378413, 65.02189831, 65.93003954, 66.92439900, 68.07051633, 68.95928756, 70.03315022, 71.05579859, 72.00000000, + 73.00000000, 74.00000000, 75.00000000, 75.93485291, 77.20950456, 78.00000000, 79.00000000, 79.91519960, 81.00000000, -3.00000000, +-2.00000000, -0.65174074, -0.00092112, 0.62967387, 2.00000000, 3.00000000, -6.00000000, -5.00000000, -4.00000000, -2.89861729, +-1.69999061, -0.72632201, 0.00219241, 0.72891750, 1.73257865, 3.00000000, 3.76561508, 5.00000000, 6.00000000, -3.00000000, +-2.00000000, -0.66227013, 0.00389373, 0.66163500, 2.00000000, 3.00000000, 4.00000000, -8.00000000, -7.00000000, -6.00000000, +-4.76421796, -4.04320264, -3.01415201, -1.84346485, -0.77185048, 0.00061977, 0.76274524, 1.84330156, 3.00000000, 4.00000000, + 5.00000000, 6.00000000, 7.00000000, -6.00000000, -5.00000000, -4.00000000, -3.00000000, -1.75749611, -0.72951347, -0.00104394, + 0.72040315, 1.72594036, 3.00000000, 4.00000000, -9.00000000, -8.00000000, -7.00000000, -5.90394062, -5.00000000, -3.75562807, +-2.89699407, -1.86696610, -0.79056636, -0.00330943, 0.79744554, 1.85149941, 2.91118681, 3.99520311, 4.96341987, 6.00000000, + 7.00000000, 8.00000000, 9.00000000, 10.00000000, -6.00000000, -4.80151529, -4.00000000, -2.87442856, -1.85285815, -0.77767592, +-0.02071301, 0.81752572, 1.82503940, 2.79602150, 3.92870203, 5.00000000, 6.00000000, 7.00000000, -17.00000000, -16.00000000, +-15.00000000, -14.00000000, -13.00000000, -12.00000000, -11.00000000, -9.80059874, -9.00000000, -8.00185204, -7.13087808, -5.92942149, +-4.77883243, -3.93417708, -2.88004618, -1.89952522, -0.86239337, 0.00332274, 0.86657548, 1.89479279, 2.89701813, 3.90987417, + 4.98910145, 6.07676766, 7.00000000, 8.00000000, 9.00000000, 10.00000000, 11.00000000, 12.00000000, 13.00000000, 14.00000000, +-12.00000000, -11.00000000, -9.89996262, -8.85894205, -7.87594823, -6.99685317, -5.94917589, -4.93914916, -3.93317670, -2.93174244, +-1.90737478, -0.90982242, 0.00803316, 0.90111563, 1.90362879, 2.90332432, 3.90654662, 4.94461954, 5.87963665, 6.91988113, + 7.79514004, 8.98805413, 10.00000000, 11.00000000, -35.00000000, -34.00000000, -33.00000000, -32.00000000, -31.00000000, -30.00000000, +-29.00000000, -28.00000000, -27.00000000, -26.00000000, -25.00000000, -24.00000000, -22.88310970, -22.00000000, -21.00000000, -20.00000000, +-19.00000000, -18.00000000, -17.00000000, -16.11854974, -15.00000000, -14.10507667, -13.04497040, -11.94846700, -10.97432494, -9.94514368, +-8.97311414, -7.94171496, -6.97232122, -5.98590548, -4.97455572, -3.95477903, -2.93935454, -1.95573532, -0.97120273, -0.02084826, + 0.95689153, 1.96679781, 2.97060165, 3.96660892, 4.96754331, 5.97996089, 6.93822411, 7.96618014, 8.95809791, 9.98891474, + 10.95713402, 11.85433084, 13.03831696, 13.84035295, 15.00729606, 15.98652872, 17.20557599, 18.00000000, 18.90794805, 20.00000000, + 21.00000000, -34.00000000, -33.00000000, -32.00000000, -31.00000000, -30.00000000, -28.97280602, -28.00000000, -27.16255057, -26.04078092, +-24.85442050, -24.15783484, -22.78614956, -21.95739865, -21.21844626, -20.03008104, -19.03888543, -17.90460490, -17.02064693, -15.84673652, +-14.87140709, -13.87996048, -12.94907251, -11.96795995, -11.00977925, -9.95103238, -8.96674655, -7.96351667, -6.96886200, -5.99335494, +-4.97515534, -3.98891694, -2.99581150, -1.98758360, -0.99249128, -0.00001403, 0.98807868, 1.99119869, 2.99019366, 3.98612953, + 5.00312941, 5.98833080, 6.99686651, 7.98373889, 8.97942222, 9.94202752, 10.99671622, 11.94306164, 12.98539825, 13.90728690, + 14.89907642, 15.94836675, 16.89611342, 17.84084949, 18.74910958, 20.00000000, -67.00000000, -66.00000000, -65.00000000, -64.00000000, +-63.02511977, -62.00000000, -61.06061493, -59.95964043, -59.12824439, -58.00000000, -57.00000000, -56.00000000, -54.87857996, -54.09689334, +-53.00000000, -52.21057366, -50.93867921, -50.03032952, -49.19283867, -47.89439051, -46.99505692, -46.04895543, -44.89687413, -43.78942208, +-42.99025156, -41.88436155, -40.99169704, -40.00320429, -38.90181498, -38.06029271, -37.05030818, -36.07554573, -35.03202233, -33.93117946, +-32.97736655, -31.98942819, -30.99546798, -30.01511004, -28.97296525, -28.02561164, -26.94386985, -25.99632704, -25.00461143, -24.01578192, +-22.99177609, -22.02261094, -20.97939001, -19.96176066, -19.00442980, -18.01529434, -17.00196902, -15.99794828, -14.98675055, -13.97517657, +-12.98676283, -11.99718760, -11.00167809, -9.98872268, -9.02138474, -8.00320338, -6.99542797, -6.00059136, -5.01311763, -4.00336943, +-3.00348281, -1.99365875, -0.98223019, 0.00126343, 0.99699237, 1.99381968, 3.00054436, 3.99898305, 5.00160508, 6.00310399, + 6.99885096, 8.02740039, 8.99515550, 9.98962151, 11.00642302, 11.98694516, 13.00018933, 13.97726018, 14.99186645, 16.00580131, + 16.97434224, 17.96982658, 19.00066438, 20.01228749, 21.00741822, 21.94988312, 23.00860212, 23.98801542, 24.97638417, 25.98003521, + 27.02336188, 27.99667029, 29.01014125, 30.02481912, 31.01415797, 31.97399854, 33.06214485, 33.99929330, 34.94095386, 35.96368372, + 36.96980925, 37.98389244, 39.01121235, 40.00715026, 41.06382894, 41.96618280, 43.01555590, 43.95430436, 45.01970038, 45.99967821, + 47.19847394, 48.04852502, 49.10609965, 50.04244122, 50.86051406, 51.92983796, 53.02781107, 54.06248545, 54.89942009, 56.08347165, + 57.06887956, 58.09671115, 59.07832400, 59.87005277, 61.14778499, 62.00000000, 63.00000000, 64.00000000, 65.00000000, 66.00000000, + 67.00000000, 68.00000000, 69.00000000, 70.00000000, 71.00000000, 72.00000000}; + +const double WebRtcIsac_kQKltLevelsShape[1735] = { + 0.00032397, 0.00008053, -0.00061202, -0.00012620, 0.00030437, 0.00054764, -0.00027902, 0.00069360, 0.00029449, -0.80219239, + 0.00091089, -0.74514927, -0.00094283, 0.64030631, -0.60509119, 0.00035575, 0.61851665, -0.62129957, 0.00375219, 0.60054900, +-0.61554359, 0.00054977, 0.63362016, -1.73118727, -0.65422341, 0.00524568, 0.66165298, 1.76785515, -1.83182018, -0.65997434, +-0.00011887, 0.67524299, 1.79933938, -1.76344480, -0.72547708, -0.00133017, 0.73104704, 1.75305377, 2.85164534, -2.80423916, +-1.71959639, -0.75419722, -0.00329945, 0.77196760, 1.72211069, 2.87339653, 0.00031089, -0.00015311, 0.00018201, -0.00035035, +-0.77357251, 0.00154647, -0.00047625, -0.00045299, 0.00086590, 0.00044762, -0.83383829, 0.00024787, -0.68526258, -0.00122472, + 0.64643255, -0.60904942, -0.00448987, 0.62309184, -0.59626442, -0.00574132, 0.62296546, -0.63222115, 0.00013441, 0.63609545, +-0.66911055, -0.00369971, 0.66346095, 2.07281301, -1.77184694, -0.67640425, -0.00010145, 0.64818392, 1.74948973, -1.69420224, +-0.71943894, -0.00004680, 0.75303493, 1.81075983, 2.80610041, -2.80005755, -1.79866753, -0.77409777, -0.00084220, 0.80141293, + 1.78291081, 2.73954236, 3.82994169, 0.00015140, -0.00012766, -0.00034241, -0.00119125, -0.76113497, 0.00069246, 0.76722027, + 0.00132862, -0.69107530, 0.00010656, 0.77061578, -0.78012970, 0.00095947, 0.77828502, -0.64787758, 0.00217168, 0.63050167, +-0.58601125, 0.00306596, 0.59466308, -0.58603410, 0.00059779, 0.64257970, 1.76512766, -0.61193600, -0.00259517, 0.59767574, +-0.61026273, 0.00315811, 0.61725479, -1.69169719, -0.65816029, 0.00067575, 0.65576890, 2.00000000, -1.72689193, -0.69780808, +-0.00040990, 0.70668487, 1.74198458, -3.79028154, -3.00000000, -1.73194459, -0.70179341, -0.00106695, 0.71302629, 1.76849782, +-2.89332364, -1.78585007, -0.78731491, -0.00132610, 0.79692976, 1.75247009, 2.97828682, -5.26238694, -3.69559829, -2.87286122, +-1.84908818, -0.84434577, -0.01167975, 0.84641753, 1.84087672, 2.87628156, 3.83556679, -0.00190204, 0.00092642, 0.00354385, +-0.00012982, -0.67742785, 0.00229509, 0.64935672, -0.58444751, 0.00470733, 0.57299534, -0.58456202, -0.00097715, 0.64593607, +-0.64060330, -0.00638534, 0.59680157, -0.59287537, 0.00490772, 0.58919707, -0.60306173, -0.00417464, 0.60562100, -1.75218757, +-0.63018569, -0.00225922, 0.63863300, -0.63949939, -0.00126421, 0.64268914, -1.75851182, -0.68318060, 0.00510418, 0.69049211, + 1.88178506, -1.71136148, -0.72710534, -0.00815559, 0.73412917, 1.79996711, -2.77111145, -1.73940498, -0.78212945, 0.01074476, + 0.77688916, 1.76873972, 2.87281379, 3.77554698, -3.75832725, -2.95463235, -1.80451491, -0.80017226, 0.00149902, 0.80729206, + 1.78265046, 2.89391793, -3.78236148, -2.83640598, -1.82532067, -0.88844327, -0.00620952, 0.88208030, 1.85757631, 2.81712391, + 3.88430176, 5.16179367, -7.00000000, -5.93805408, -4.87172597, -3.87524433, -2.89399744, -1.92359563, -0.92136341, -0.00172725, + 0.93087018, 1.90528280, 2.89809686, 3.88085708, 4.89147740, 5.89078692, -0.00239502, 0.00312564, -1.00000000, 0.00178325, + 1.00000000, -0.62198029, 0.00143254, 0.65344051, -0.59851220, -0.00676987, 0.61510140, -0.58894151, 0.00385055, 0.59794203, +-0.59808568, -0.00038214, 0.57625703, -0.63009713, -0.01107985, 0.61278758, -0.64206758, -0.00154369, 0.65480598, 1.80604162, +-1.80909286, -0.67810514, 0.00205762, 0.68571097, 1.79453891, -3.22682422, -1.73808453, -0.71870305, -0.00738594, 0.71486172, + 1.73005326, -1.66891897, -0.73689615, -0.00616203, 0.74262409, 1.73807899, -2.92417482, -1.73866741, -0.78133871, 0.00764425, + 0.80027264, 1.78668732, 2.74992588, -4.00000000, -2.75578740, -1.83697516, -0.83117035, -0.00355191, 0.83527172, 1.82814700, + 2.77377675, 3.80718693, -3.81667698, -2.83575471, -1.83372350, -0.86579471, 0.00547578, 0.87582281, 1.82858793, 2.87265007, + 3.91405377, -4.87521600, -3.78999094, -2.86437014, -1.86964365, -0.90618018, 0.00128243, 0.91497811, 1.87374952, 2.83199819, + 3.91519130, 4.76632822, -6.68713448, -6.01252467, -4.94587936, -3.88795368, -2.91299088, -1.92592211, -0.95504570, -0.00089980, + 0.94565200, 1.93239633, 2.91832808, 3.91363475, 4.88920034, 5.96471415, 6.83905252, 7.86195009, 8.81571018, -12.96141759, +-11.73039516, -10.96459719, -9.97382433, -9.04414433, -7.89460619, -6.96628608, -5.93236595, -4.93337924, -3.95479990, -2.96451499, +-1.96635876, -0.97271229, -0.00402238, 0.98343930, 1.98348291, 2.96641164, 3.95456471, 4.95517089, 5.98975714, 6.90322073, + 7.90468849, 8.85639467, 9.97255498, 10.79006309, 11.81988596, 0.04950500, -1.00000000, -0.01226628, 1.00000000, -0.59479469, +-0.10438305, 0.59822144, -2.00000000, -0.67109149, -0.09256692, 0.65171621, 2.00000000, -3.00000000, -1.68391999, -0.76681039, +-0.03354151, 0.71509146, 1.77615472, -2.00000000, -0.68661511, -0.02497881, 0.66478398, 2.00000000, -2.00000000, -0.67032784, +-0.00920582, 0.64892756, 2.00000000, -2.00000000, -0.68561894, 0.03641869, 0.73021611, 1.68293863, -4.00000000, -2.72024184, +-1.80096059, -0.81696185, 0.03604685, 0.79232033, 1.70070730, 3.00000000, -4.00000000, -2.71795670, -1.80482986, -0.86001162, + 0.03764903, 0.87723968, 1.79970771, 2.72685932, 3.67589143, -5.00000000, -4.00000000, -2.85492548, -1.78996365, -0.83250358, +-0.01376828, 0.84195506, 1.78161105, 2.76754458, 4.00000000, -6.00000000, -5.00000000, -3.82268811, -2.77563624, -1.82608163, +-0.86486114, -0.02671886, 0.86693165, 1.88422879, 2.86248347, 3.95632216, -7.00000000, -6.00000000, -5.00000000, -3.77533988, +-2.86391432, -1.87052039, -0.90513658, 0.06271236, 0.91083620, 1.85734756, 2.86031688, 3.82019418, 4.94420394, 6.00000000, +-11.00000000, -10.00000000, -9.00000000, -8.00000000, -6.91952415, -6.00000000, -4.92044374, -3.87845165, -2.87392362, -1.88413020, +-0.91915740, 0.00318517, 0.91602800, 1.89664838, 2.88925058, 3.84123856, 4.78988651, 5.94526812, 6.81953917, 8.00000000, +-9.00000000, -8.00000000, -7.03319143, -5.94530963, -4.86669720, -3.92438007, -2.88620396, -1.92848070, -0.94365985, 0.01671855, + 0.97349410, 1.93419878, 2.89740109, 3.89662823, 4.83235583, 5.88106535, 6.80328232, 8.00000000, -13.00000000, -12.00000000, +-11.00000000, -10.00000000, -9.00000000, -7.86033489, -6.83344055, -5.89844215, -4.90811454, -3.94841298, -2.95820490, -1.98627966, +-0.99161468, -0.02286136, 0.96055651, 1.95052433, 2.93969396, 3.94304346, 4.88522624, 5.87434241, 6.78309433, 7.87244101, + 9.00000000, 10.00000000, -12.09117356, -11.00000000, -10.00000000, -8.84766108, -7.86934236, -6.98544896, -5.94233429, -4.95583292, +-3.95575986, -2.97085529, -1.98955811, -0.99359873, -0.00485413, 0.98298870, 1.98093258, 2.96430203, 3.95540216, 4.96915010, + 5.96775124, 6.99236918, 7.96503302, 8.99864542, 9.85857723, 10.96541926, 11.91647197, 12.71060069, -26.00000000, -25.00000000, +-24.00585596, -23.11642573, -22.14271284, -20.89800711, -19.87815799, -19.05036354, -17.88555651, -16.86471209, -15.97711073, -14.94012359, +-14.02661226, -12.98243228, -11.97489256, -10.97402777, -9.96425624, -9.01085220, -7.97372506, -6.98795002, -5.97271328, -5.00191694, +-3.98055849, -2.98458048, -1.99470442, -0.99656768, -0.00825666, 1.00272004, 1.99922218, 2.99357669, 4.01407905, 5.01003897, + 5.98115528, 7.00018958, 8.00338125, 8.98981046, 9.98990318, 10.96341479, 11.96866930, 12.99175139, 13.94580443, 14.95745083, + 15.98992869, 16.97484646, 17.99630043, 18.93396897, 19.88347741, 20.96532482, 21.92191032, 23.22314702, 0.00006846, 0.00014352, +-0.00056203, 0.00027588, -0.00147678, 1.00000000, 0.00003823, 0.00001975, -0.00033710, -0.00096712, 1.00000000, -1.00000000, + 0.00067511, -1.00000000, 0.00342065, 1.00000000, -1.00000000, 0.00196254, 1.00000000, -1.00000000, 0.00201173, 1.00000000, +-2.00000000, -1.00000000, -0.00381686, 1.00000000, -1.00000000, 0.00178037, 1.00000000, -2.00000000, -1.00000000, -0.00320274, + 1.00000000, 2.00000000, -2.00000000, -1.00000000, 0.00426519, 1.00000000, 2.00000000, -3.00000000, -2.00000000, -1.00000000, +-0.00074072, 0.64654602, 2.00000000, 0.00031217, 0.00063348, 0.00020247, 0.00047891, 0.00122893, -0.00150669, -0.00148276, + 0.00016848, 0.00147085, 1.00000000, -0.00088160, 1.00000000, -1.00000000, 0.00381641, 1.00000000, -1.00000000, 0.00129816, + 1.00000000, -1.00000000, 0.00074903, 1.00000000, -2.00000000, -0.76230566, -0.00370764, 0.82467977, -0.78769346, -0.00492670, + 0.84532630, -2.00000000, -0.70943195, -0.01257613, 0.75905385, 2.00000000, -2.00000000, -0.62780445, -0.00408633, 0.60272506, + 2.00000000, 3.00000000, -3.00000000, -2.00000000, -0.61412985, 0.00102833, 0.61527589, 2.00000000, 3.00000000, 0.00012115, +-0.00080909, 0.00071061, -0.00227957, 0.00179794, 0.00103827, -1.00000000, 0.00444757, -1.00000000, 0.00604068, 1.00000000, +-1.00000000, 0.00427327, 1.00000000, -1.00000000, 0.00086662, 1.00000000, -1.00000000, -0.00837492, 1.00000000, -0.65715934, +-0.00645342, 0.64004630, -2.00000000, -0.64987682, -0.01449567, 0.69893373, -2.00000000, -0.63221961, 0.00421765, 0.62452105, + 2.00000000, -2.00000000, -0.60027006, -0.00110630, 0.62033821, 2.00000000, -2.00000000, -0.59823932, 0.00928313, 0.62188520, + 2.00000000, 3.00000000, -3.00000000, -2.00000000, -0.63230286, -0.00248555, 0.62632575, 2.00000000, 3.00000000, -5.00000000, +-4.00000000, -3.00000000, -2.00000000, -0.66521143, 0.00544305, 0.66930486, 2.00000000, 3.00000000, 4.00000000, 0.00077008, + 0.00061140, -0.00009317, -0.00049643, 1.00000000, -1.00000000, -0.00285084, 1.00000000, -1.00000000, 0.00601784, 1.00000000, +-1.00000000, -0.00091887, 0.75122772, -0.71579859, -0.00043545, 1.00000000, -0.85571363, -0.00227654, 0.63816873, -1.00000000, +-0.00393484, 0.76748004, -0.58223659, -0.01229777, 0.58080322, -0.61945902, -0.00232238, 0.62277938, 2.00000000, -2.00000000, +-0.60595489, -0.00535702, 0.60547736, 2.00000000, -4.00000000, -3.00000000, -2.00000000, -0.62368122, 0.01112097, 0.63997294, + 2.00000000, 3.00000000, -3.00000000, -2.00000000, -0.64318217, 0.00515139, 0.64781184, 2.00000000, -3.00000000, -1.78031579, +-0.67122588, 0.02153711, 0.67899877, 2.00000000, 3.00000000, 4.00000000, -4.00000000, -3.00000000, -1.80503233, -0.69835727, +-0.00270770, 0.70999554, 1.77332849, 3.00000000, 4.00000000, 5.00000000, -8.00000000, -7.00000000, -6.00000000, -5.00000000, +-4.00000000, -2.81600693, -1.72970368, -0.73779413, -0.01384841, 0.75694606, 1.80042618, 3.00000000, 4.00000000, 5.00000000, + 6.00000000, -0.00051787, 0.00059593, -0.00023319, -1.00000000, 0.00191861, 0.79547197, -0.75020995, 0.00217840, 0.69165833, +-1.00000000, -0.00304964, 0.67698951, -0.64516943, -0.00657667, 0.59260129, -0.62819301, -0.00456626, 0.59426260, -0.60909519, + 0.00256476, 0.61660408, -0.66560131, -0.00293463, 0.67477566, 2.00000000, -2.00000000, -0.62484067, 0.00505116, 0.63491494, + 2.00000000, -3.00000000, -2.00000000, -0.68427246, 0.00924353, 0.68755774, 2.00000000, 3.00000000, -3.00000000, -2.00000000, +-0.65390928, 0.01008025, 0.65849449, 2.00000000, 3.00000000, -5.00000000, -4.00000000, -3.00000000, -1.70848232, -0.72079538, +-0.00007674, 0.71556176, 1.76815351, 3.00000000, 4.00000000, 5.00000000, -4.00000000, -3.00000000, -1.82887466, -0.73529886, + 0.00033458, 0.73847588, 1.83009515, 3.00000000, 4.00000000, -5.00000000, -4.00000000, -2.83203553, -1.79500085, -0.77452749, +-0.00614320, 0.77416943, 1.82469471, 2.77034612, 4.00000000, 5.00000000, -7.00000000, -6.00000000, -5.00000000, -4.00000000, +-2.76574798, -1.84700836, -0.80822297, 0.00054165, 0.80901445, 1.85687331, 2.75680191, 3.81986695, 5.00000000, 6.00000000, + 7.00000000, 8.00000000, -13.00000000, -12.00000000, -11.00000000, -10.00000000, -9.00000000, -8.00000000, -7.00000000, -6.00000000, +-5.00000000, -3.88304817, -2.93396067, -1.86645989, -0.84825410, 0.00666207, 0.84853252, 1.88634684, 2.95282618, 3.89813287, + 4.89189079, 6.00000000, 7.00000000, 8.00000000, 9.00000000, 10.00000000, 11.00000000, -0.00344877, 1.00000000, -0.61413659, +-0.02115630, 0.59438887, -0.60873054, 0.00844993, 0.62510557, -2.00000000, -0.75002947, 0.00120913, 0.66616051, -2.00000000, +-0.72324691, 0.04760499, 0.70532533, 2.00000000, -3.00000000, -1.66577589, -0.78941380, -0.01909714, 0.74993685, 1.70945570, +-1.64422308, -0.70992006, -0.02795108, 0.76990363, 1.79682243, 2.96233315, -1.71686461, -0.76572785, -0.00041846, 0.78174132, + 1.66217596, -3.00000000, -1.77033369, -0.79475091, 0.03709740, 0.80097076, 1.83947400, 2.85879773, -4.00000000, -3.16528651, +-1.79564411, -0.90078981, 0.02403102, 0.86138856, 1.84207433, 2.74584048, -4.00000000, -2.91249347, -1.87804769, -0.87323549, + 0.08164382, 0.89037056, 1.82505263, 2.71336163, 4.00000000, -4.81262228, -3.87173565, -2.83424209, -1.87517938, -0.86199960, + 0.00268598, 0.89547657, 1.90713511, 2.85219071, 3.86417171, 4.80711781, 6.00000000, 7.00000000, -5.00000000, -3.82388480, +-2.82875808, -1.90350457, -0.90795818, 0.03047007, 0.93676836, 1.88844957, 2.83269711, 3.76109686, 5.00000000, -9.00000000, +-8.00000000, -6.88037957, -5.88776398, -4.91209139, -3.93902541, -2.90989221, -1.92281230, -0.98960535, -0.07440511, 0.94023957, + 1.91666262, 2.83340828, 3.83651295, 4.77839424, 6.12284019, 7.00000000, 8.00000000, 9.00000000, -12.00000000, -11.00000000, +-10.00000000, -9.00000000, -8.00000000, -6.68554513, -5.97994708, -4.98789075, -3.91383581, -2.92952795, -1.91727195, -0.93148075, +-0.00568870, 0.93515148, 1.94580068, 2.93838956, 3.92567644, 4.96573603, 5.95402763, 7.00000000, 8.00000000, 9.00000000, +-11.00000000, -9.90096030, -8.97868124, -7.93663988, -6.98806055, -5.95937864, -4.93473664, -3.95454756, -2.96518446, -1.97711766, +-0.98552111, -0.03317271, 0.95115775, 1.93785086, 2.96310779, 3.93322450, 5.01716212, 5.85909823, 6.89163669, 7.97492693, + 8.85698897, 9.79802946, 11.09373957, 12.00000000, -13.00000000, -12.00000000, -10.67579109, -9.95079100, -8.90576592, -7.93254656, +-6.96112672, -5.96015798, -4.95493809, -3.98556269, -2.98182856, -1.98150255, -0.96551153, -0.00399791, 0.98644875, 1.98043830, + 2.97969033, 3.97728257, 4.95173541, 5.95649050, 6.96447378, 7.95591513, 9.07680954, 9.92093070, 10.76496555, 11.97525735, + 13.00000000, 14.00000000, -25.00000000, -24.00000000, -23.00000000, -22.00072357, -21.00000000, -20.00000000, -19.00000000, -18.20003462, +-17.01648407, -15.78651996, -14.95660266, -13.99167850, -13.28722978, -11.85013840, -10.92025302, -9.87055810, -8.93841040, -7.95329867, +-6.97819441, -6.01593394, -5.00905213, -3.99905285, -2.99171810, -1.99062796, -1.00112466, 0.00140492, 1.00701091, 2.02327185, + 3.00194633, 3.99188294, 5.00313145, 6.00448038, 6.98904951, 7.98158293, 8.98212774, 10.00363404, 10.98641678, 11.98034311, + 12.95176779, 13.95383703, 14.99084578, 15.98600642, 16.99406826, 17.98134623, 19.01793961, 19.86072639, 20.88465474, 21.99287082, + 22.81916620, 23.77946383, 0.00000234, 0.00000298, 0.00000048, 0.00002408, -0.00000165, -0.00001831, -0.00005703, -0.00000184, +-1.00000000, 0.00001977, 1.00000000, -1.00000000, 0.00000010, 1.00000000, -1.00000000, -0.00001152, 1.00000000, -1.00000000, + 0.00000840, 1.00000000, -1.00000000, 0.00002353, 1.00000000, -0.75455603, -0.00001433, 1.00000000, -0.65859705, -0.00000703, + 0.62995860, -2.00000000, -0.72724652, -0.00033969, 0.61359174, 2.00000000, -2.00000000, -0.69510998, -0.00031410, 0.66467605, + 2.00000000, 3.00000000, -3.00000000, -2.00000000, -0.65738683, 0.00039019, 0.66554720, 1.91774106, 3.18089124, 0.00000070, + 0.00001152, -0.00000795, -0.00000058, -0.00003502, -0.00001508, -0.00004225, -0.00002165, -1.00000000, 0.00004391, 1.00000000, +-1.00000000, 0.00001784, 1.00000000, -1.00000000, -0.00003678, 1.00000000, -0.68878314, -0.00013166, 0.60880149, -0.75291978, + 0.00006493, 1.00000000, -0.76757316, 0.00003057, 0.67140524, -0.61602267, -0.00014495, 0.63625803, 2.00000000, -2.00000000, +-0.61253314, -0.00116483, 0.65071851, 2.00000000, -3.00000000, -1.71451667, -0.67799909, -0.00048294, 0.65846019, 2.00000000, +-3.02497593, -1.83515395, -0.70317981, 0.00519701, 0.67780009, 1.84218153, 2.88846262, 4.00000000, 0.00001124, 0.00000588, +-0.00000172, 0.00002835, 1.00000000, 0.00001012, -0.00008644, 1.00000000, -0.75115901, 0.00004347, 1.00000000, -1.00000000, + 0.00002800, 1.00000000, -1.00000000, -0.00006039, 1.00000000, -0.79763258, -0.00011907, 0.71713616, -0.76791870, -0.00007113, + 0.63583609, -0.62337806, 0.00012891, 0.62242094, -0.60837055, 0.00043216, 0.65515705, -0.63637782, -0.00019749, 0.60423967, + 2.00000000, -2.00000000, -0.65404827, -0.00089304, 0.64706660, 2.00000000, -1.86334076, -0.66410366, 0.00063219, 0.66968004, + 2.00000000, 3.00000000, 4.00000000, -4.00000000, -3.00000000, -1.79048834, -0.69451890, 0.00030677, 0.71009333, 1.70591343, + 3.00000000, 4.00000000, -4.00000000, -2.90176499, -1.78368781, -0.74425178, 0.00234068, 0.74847325, 1.78886822, 2.78478854, + 3.83608985, 4.95996151, 0.00002170, 0.00001281, 0.00002162, -1.00000000, -0.00007266, 1.00000000, -1.00000000, -0.00003250, +-0.64088804, 0.00015239, 1.00000000, -0.58450370, -0.00008410, 0.60567186, -1.00000000, -0.00010752, 1.00000000, -0.58922508, +-0.00017378, 0.60755779, -0.62797206, -0.00001016, 0.64432847, -0.58497934, -0.00001851, 0.59716791, -0.62642499, -0.00097386, + 0.63568558, 2.00000000, -2.00000000, -0.63236390, -0.00173361, 0.63142762, 1.75629192, -3.00000000, -2.00000000, -0.65596684, + 0.00209364, 0.65419742, 2.00000000, -3.00000000, -1.73856625, -0.67767521, -0.00119512, 0.68973603, 1.70985573, 3.00000000, +-3.00000000, -1.81820220, -0.73974134, 0.00695869, 0.72216179, 1.75624461, 3.00000000, 4.00000000, -5.00000000, -4.00000000, +-3.17718593, -1.76857567, -0.76822322, 0.00267400, 0.76414602, 1.84309221, 3.04940652, 4.00000000, -7.08189123, -6.00000000, +-5.22882249, -3.96477958, -2.79653492, -1.81923435, -0.80050253, -0.01086663, 0.82708565, 1.85804900, 2.89996354, 3.76028554, + 4.80518081, 5.81738096, 7.00000000, 8.00000000, 9.08816091, -0.00002979, -0.00000333, -1.00000000, -0.00011532, 1.00000000, +-0.70921122, -0.00005325, 0.68933188, -0.67581263, -0.00023107, 0.57868212, -0.58388312, -0.00020850, 0.60149012, -0.60912457, + 0.00001567, 0.60180554, -0.59130091, -0.00038863, 0.59908653, -2.00000000, -0.63697707, 0.00083913, 0.62040514, 2.00000000, +-2.00000000, -0.63216238, -0.00081100, 0.64411071, 2.00000000, -1.76856259, -0.65266989, -0.00243486, 0.66888899, 2.00000000, +-1.75427214, -0.71415385, -0.00226376, 0.71296778, 1.66182947, 3.00000000, -3.00000000, -1.72505821, -0.72920134, -0.00360424, + 0.73800767, 1.72848281, 3.00000000, -4.00000000, -2.95284408, -1.72025758, -0.76503859, 0.00418761, 0.75297139, 1.73959808, + 3.00000000, -5.00000000, -3.96232791, -2.74080544, -1.78897123, -0.80233505, -0.00002050, 0.79693417, 1.76182598, 2.78434458, + 3.85693287, 5.00000000, -6.00000000, -4.78439284, -3.83501790, -2.85203629, -1.84909573, -0.85382658, -0.00181019, 0.84735145, + 1.83676575, 2.83656843, 3.86722376, 4.79702431, 6.00000000, -9.00000000, -8.00000000, -7.00000000, -6.07957292, -4.84677515, +-3.85093972, -2.88683139, -1.84596391, -0.88058034, -0.00008692, 0.87554746, 1.86933183, 2.84729990, 3.89029797, 4.87311773, + 5.90844023, 7.00000000, -11.00000000, -9.97745420, -8.90015761, -7.94187517, -6.86987726, -5.84795335, -4.86693435, -3.90601819, +-2.91031804, -1.91620096, -0.90497055, 0.00659199, 0.90926869, 1.90980821, 2.91070850, 3.93685967, 4.85581177, 6.06727337, + 7.05801043, 8.00000000, 9.00000000, 10.00000000, 10.90825787, 12.00000000, 13.00000000, 14.00000000, -0.00008918, 1.00000000, +-0.54405938, 0.00120348, 0.55781920, -0.59227786, -0.00349602, 0.59777231, -1.63717598, -0.69048065, 0.00999281, 0.65770558, + 2.00000000, -2.00000000, -0.71013571, 0.00454518, 0.66991065, -3.00000000, -1.73004867, -0.73743921, 0.01162454, 0.69964842, + 1.83319587, -1.81225491, -0.76806000, 0.00164742, 0.76780397, 1.67168896, -1.64564794, -0.79903361, -0.01522880, 0.84277926, + 1.68873752, -3.00000000, -1.72063244, -0.83687428, 0.00246724, 0.84618697, 1.79464483, 2.77447025, -3.77118426, -2.75025539, +-1.82050448, -0.90373722, -0.00187780, 0.90102245, 1.85249394, 2.71364180, -2.71720889, -1.79466125, -0.89860801, -0.02725825, + 0.90877329, 1.90542096, 2.76847902, 3.71496428, -4.70257302, -3.90746659, -2.87078421, -1.88858709, -0.93608993, -0.02157425, + 0.95181182, 1.91155682, 2.83614575, 3.87820801, 4.72172277, -5.02764544, -3.80066801, -2.87484378, -1.90707477, -0.96326017, +-0.01060091, 0.96558851, 1.92191548, 2.86970759, 3.85655474, 4.83135970, 5.76387469, -9.00000000, -8.00000000, -6.75261776, +-5.86333393, -4.84846871, -3.91871758, -2.93827286, -1.93050320, -0.96359634, -0.00141931, 0.95926312, 1.92541870, 2.93009411, + 3.86699087, 4.82315929, 5.67815206, -8.76594345, -7.70350451, -6.91784020, -5.81539490, -4.92526872, -3.91513203, -2.92134949, +-1.95465646, -0.97638102, -0.00742564, 0.96948714, 1.96401112, 2.95256722, 3.93146353, 4.90991357, 5.88139022, 6.88640588, + 7.82610489, 9.00000000, -10.97611369, -9.80036760, -8.91109518, -7.92809404, -6.93865353, -5.91965899, -4.92957669, -3.95206224, +-2.97308718, -1.97778214, -0.98552568, -0.00063212, 0.98686014, 1.97511867, 2.97114218, 3.97854244, 4.96578513, 5.96457765, + 6.95180187, 7.95163483, 8.93760897, 9.87666900, 10.88024562, 11.96270158, 12.99519291, -15.00000000, -13.76826291, -12.97229116, +-12.00334834, -10.95980884, -9.98190891, -8.93798503, -7.95621309, -6.96109479, -5.96056649, -4.95843419, -3.97688640, -2.98989576, +-1.98533395, -0.99580972, 0.00694370, 0.99421120, 1.99033132, 2.98751217, 3.98549580, 4.96482394, 5.96623233, 6.93564626, + 7.93772467, 8.92015276, 9.88785129, 10.97606096, 11.79686057, -23.00000000, -22.00000000, -21.00000000, -20.00000000, -19.00000000, +-17.73310977, -16.83574096, -15.90889480, -15.00437366, -13.95007272, -12.99296117, -11.98334751, -10.96970820, -9.97775151, -8.98193840, +-7.98378966, -6.98887770, -5.99059477, -5.00228769, -3.99355850, -2.99947486, -1.99897483, -0.99375857, 0.00324880, 1.00215912, + 1.99277083, 3.00503747, 3.99390482, 4.98854283, 5.98753219, 6.98245347, 7.98089893, 8.95960522, 9.95663648, 11.00810285, + 12.01421617, 12.96208687, 13.99227766, 14.97230040, 15.95114804, 16.97347393, 17.97794884, 18.96777118, 19.94446034, 20.94799029, + 22.14740083, 22.84288347, 23.99212109, 25.00000000, 25.96562658}; + +/* cdf tables for quantizer indices */ +const WebRtc_UWord16 WebRtcIsac_kQKltCdfGain[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 WebRtcIsac_kQKltCdfShape[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 *WebRtcIsac_kQKltCdfPtrGain[3][12] = { +{WebRtcIsac_kQKltCdfGain +0 +0, WebRtcIsac_kQKltCdfGain +0 +8, WebRtcIsac_kQKltCdfGain +0 +22, WebRtcIsac_kQKltCdfGain +0 +32, WebRtcIsac_kQKltCdfGain +0 +48, WebRtcIsac_kQKltCdfGain +0 +60, WebRtcIsac_kQKltCdfGain +0 +81, WebRtcIsac_kQKltCdfGain +0 +95, WebRtcIsac_kQKltCdfGain +0 +128, WebRtcIsac_kQKltCdfGain +0 +152, +WebRtcIsac_kQKltCdfGain +0 +210, WebRtcIsac_kQKltCdfGain +0 +264}, +{WebRtcIsac_kQKltCdfGain +404 +0, WebRtcIsac_kQKltCdfGain +404 +8, WebRtcIsac_kQKltCdfGain +404 +21, WebRtcIsac_kQKltCdfGain +404 +30, WebRtcIsac_kQKltCdfGain +404 +46, WebRtcIsac_kQKltCdfGain +404 +58, WebRtcIsac_kQKltCdfGain +404 +79, WebRtcIsac_kQKltCdfGain +404 +93, WebRtcIsac_kQKltCdfGain +404 +125, WebRtcIsac_kQKltCdfGain +404 +149, +WebRtcIsac_kQKltCdfGain +404 +207, WebRtcIsac_kQKltCdfGain +404 +260}, +{WebRtcIsac_kQKltCdfGain +803 +0, WebRtcIsac_kQKltCdfGain +803 +8, WebRtcIsac_kQKltCdfGain +803 +22, WebRtcIsac_kQKltCdfGain +803 +31, WebRtcIsac_kQKltCdfGain +803 +48, WebRtcIsac_kQKltCdfGain +803 +60, WebRtcIsac_kQKltCdfGain +803 +81, WebRtcIsac_kQKltCdfGain +803 +96, WebRtcIsac_kQKltCdfGain +803 +129, WebRtcIsac_kQKltCdfGain +803 +154, +WebRtcIsac_kQKltCdfGain +803 +212, WebRtcIsac_kQKltCdfGain +803 +268}}; + +const WebRtc_UWord16 *WebRtcIsac_kQKltCdfPtrShape[3][108] = { +{WebRtcIsac_kQKltCdfShape +0 +0, WebRtcIsac_kQKltCdfShape +0 +2, WebRtcIsac_kQKltCdfShape +0 +4, WebRtcIsac_kQKltCdfShape +0 +6, WebRtcIsac_kQKltCdfShape +0 +8, WebRtcIsac_kQKltCdfShape +0 +10, WebRtcIsac_kQKltCdfShape +0 +12, WebRtcIsac_kQKltCdfShape +0 +14, WebRtcIsac_kQKltCdfShape +0 +16, WebRtcIsac_kQKltCdfShape +0 +18, +WebRtcIsac_kQKltCdfShape +0 +21, WebRtcIsac_kQKltCdfShape +0 +25, WebRtcIsac_kQKltCdfShape +0 +29, WebRtcIsac_kQKltCdfShape +0 +33, WebRtcIsac_kQKltCdfShape +0 +37, WebRtcIsac_kQKltCdfShape +0 +43, WebRtcIsac_kQKltCdfShape +0 +49, WebRtcIsac_kQKltCdfShape +0 +56, WebRtcIsac_kQKltCdfShape +0 +64, WebRtcIsac_kQKltCdfShape +0 +66, +WebRtcIsac_kQKltCdfShape +0 +68, WebRtcIsac_kQKltCdfShape +0 +70, WebRtcIsac_kQKltCdfShape +0 +72, WebRtcIsac_kQKltCdfShape +0 +75, WebRtcIsac_kQKltCdfShape +0 +77, WebRtcIsac_kQKltCdfShape +0 +79, WebRtcIsac_kQKltCdfShape +0 +81, WebRtcIsac_kQKltCdfShape +0 +83, WebRtcIsac_kQKltCdfShape +0 +86, WebRtcIsac_kQKltCdfShape +0 +90, +WebRtcIsac_kQKltCdfShape +0 +94, WebRtcIsac_kQKltCdfShape +0 +98, WebRtcIsac_kQKltCdfShape +0 +102, WebRtcIsac_kQKltCdfShape +0 +107, WebRtcIsac_kQKltCdfShape +0 +113, WebRtcIsac_kQKltCdfShape +0 +120, WebRtcIsac_kQKltCdfShape +0 +129, WebRtcIsac_kQKltCdfShape +0 +131, WebRtcIsac_kQKltCdfShape +0 +133, WebRtcIsac_kQKltCdfShape +0 +135, +WebRtcIsac_kQKltCdfShape +0 +137, WebRtcIsac_kQKltCdfShape +0 +141, WebRtcIsac_kQKltCdfShape +0 +143, WebRtcIsac_kQKltCdfShape +0 +147, WebRtcIsac_kQKltCdfShape +0 +151, WebRtcIsac_kQKltCdfShape +0 +155, WebRtcIsac_kQKltCdfShape +0 +159, WebRtcIsac_kQKltCdfShape +0 +164, WebRtcIsac_kQKltCdfShape +0 +168, WebRtcIsac_kQKltCdfShape +0 +172, +WebRtcIsac_kQKltCdfShape +0 +178, WebRtcIsac_kQKltCdfShape +0 +184, WebRtcIsac_kQKltCdfShape +0 +192, WebRtcIsac_kQKltCdfShape +0 +200, WebRtcIsac_kQKltCdfShape +0 +211, WebRtcIsac_kQKltCdfShape +0 +213, WebRtcIsac_kQKltCdfShape +0 +215, WebRtcIsac_kQKltCdfShape +0 +217, WebRtcIsac_kQKltCdfShape +0 +219, WebRtcIsac_kQKltCdfShape +0 +223, +WebRtcIsac_kQKltCdfShape +0 +227, WebRtcIsac_kQKltCdfShape +0 +231, WebRtcIsac_kQKltCdfShape +0 +235, WebRtcIsac_kQKltCdfShape +0 +239, WebRtcIsac_kQKltCdfShape +0 +243, WebRtcIsac_kQKltCdfShape +0 +248, WebRtcIsac_kQKltCdfShape +0 +252, WebRtcIsac_kQKltCdfShape +0 +258, WebRtcIsac_kQKltCdfShape +0 +264, WebRtcIsac_kQKltCdfShape +0 +273, +WebRtcIsac_kQKltCdfShape +0 +282, WebRtcIsac_kQKltCdfShape +0 +293, WebRtcIsac_kQKltCdfShape +0 +308, WebRtcIsac_kQKltCdfShape +0 +310, WebRtcIsac_kQKltCdfShape +0 +312, WebRtcIsac_kQKltCdfShape +0 +316, WebRtcIsac_kQKltCdfShape +0 +320, WebRtcIsac_kQKltCdfShape +0 +324, WebRtcIsac_kQKltCdfShape +0 +328, WebRtcIsac_kQKltCdfShape +0 +332, +WebRtcIsac_kQKltCdfShape +0 +336, WebRtcIsac_kQKltCdfShape +0 +341, WebRtcIsac_kQKltCdfShape +0 +347, WebRtcIsac_kQKltCdfShape +0 +354, WebRtcIsac_kQKltCdfShape +0 +360, WebRtcIsac_kQKltCdfShape +0 +368, WebRtcIsac_kQKltCdfShape +0 +378, WebRtcIsac_kQKltCdfShape +0 +388, WebRtcIsac_kQKltCdfShape +0 +400, WebRtcIsac_kQKltCdfShape +0 +418, +WebRtcIsac_kQKltCdfShape +0 +445, WebRtcIsac_kQKltCdfShape +0 +447, WebRtcIsac_kQKltCdfShape +0 +451, WebRtcIsac_kQKltCdfShape +0 +455, WebRtcIsac_kQKltCdfShape +0 +461, WebRtcIsac_kQKltCdfShape +0 +468, WebRtcIsac_kQKltCdfShape +0 +474, WebRtcIsac_kQKltCdfShape +0 +480, WebRtcIsac_kQKltCdfShape +0 +486, WebRtcIsac_kQKltCdfShape +0 +495, +WebRtcIsac_kQKltCdfShape +0 +505, WebRtcIsac_kQKltCdfShape +0 +516, WebRtcIsac_kQKltCdfShape +0 +528, WebRtcIsac_kQKltCdfShape +0 +543, WebRtcIsac_kQKltCdfShape +0 +564, WebRtcIsac_kQKltCdfShape +0 +583, WebRtcIsac_kQKltCdfShape +0 +608, WebRtcIsac_kQKltCdfShape +0 +635}, +{WebRtcIsac_kQKltCdfShape +686 +0, WebRtcIsac_kQKltCdfShape +686 +2, WebRtcIsac_kQKltCdfShape +686 +4, WebRtcIsac_kQKltCdfShape +686 +6, WebRtcIsac_kQKltCdfShape +686 +8, WebRtcIsac_kQKltCdfShape +686 +11, WebRtcIsac_kQKltCdfShape +686 +13, WebRtcIsac_kQKltCdfShape +686 +15, WebRtcIsac_kQKltCdfShape +686 +17, WebRtcIsac_kQKltCdfShape +686 +20, +WebRtcIsac_kQKltCdfShape +686 +23, WebRtcIsac_kQKltCdfShape +686 +27, WebRtcIsac_kQKltCdfShape +686 +31, WebRtcIsac_kQKltCdfShape +686 +35, WebRtcIsac_kQKltCdfShape +686 +40, WebRtcIsac_kQKltCdfShape +686 +44, WebRtcIsac_kQKltCdfShape +686 +50, WebRtcIsac_kQKltCdfShape +686 +56, WebRtcIsac_kQKltCdfShape +686 +63, WebRtcIsac_kQKltCdfShape +686 +65, +WebRtcIsac_kQKltCdfShape +686 +67, WebRtcIsac_kQKltCdfShape +686 +69, WebRtcIsac_kQKltCdfShape +686 +71, WebRtcIsac_kQKltCdfShape +686 +73, WebRtcIsac_kQKltCdfShape +686 +75, WebRtcIsac_kQKltCdfShape +686 +77, WebRtcIsac_kQKltCdfShape +686 +79, WebRtcIsac_kQKltCdfShape +686 +82, WebRtcIsac_kQKltCdfShape +686 +85, WebRtcIsac_kQKltCdfShape +686 +89, +WebRtcIsac_kQKltCdfShape +686 +93, WebRtcIsac_kQKltCdfShape +686 +97, WebRtcIsac_kQKltCdfShape +686 +102, WebRtcIsac_kQKltCdfShape +686 +106, WebRtcIsac_kQKltCdfShape +686 +112, WebRtcIsac_kQKltCdfShape +686 +119, WebRtcIsac_kQKltCdfShape +686 +127, WebRtcIsac_kQKltCdfShape +686 +129, WebRtcIsac_kQKltCdfShape +686 +131, WebRtcIsac_kQKltCdfShape +686 +133, +WebRtcIsac_kQKltCdfShape +686 +135, WebRtcIsac_kQKltCdfShape +686 +137, WebRtcIsac_kQKltCdfShape +686 +139, WebRtcIsac_kQKltCdfShape +686 +142, WebRtcIsac_kQKltCdfShape +686 +146, WebRtcIsac_kQKltCdfShape +686 +150, WebRtcIsac_kQKltCdfShape +686 +154, WebRtcIsac_kQKltCdfShape +686 +158, WebRtcIsac_kQKltCdfShape +686 +162, WebRtcIsac_kQKltCdfShape +686 +167, +WebRtcIsac_kQKltCdfShape +686 +173, WebRtcIsac_kQKltCdfShape +686 +179, WebRtcIsac_kQKltCdfShape +686 +186, WebRtcIsac_kQKltCdfShape +686 +194, WebRtcIsac_kQKltCdfShape +686 +205, WebRtcIsac_kQKltCdfShape +686 +207, WebRtcIsac_kQKltCdfShape +686 +209, WebRtcIsac_kQKltCdfShape +686 +211, WebRtcIsac_kQKltCdfShape +686 +214, WebRtcIsac_kQKltCdfShape +686 +218, +WebRtcIsac_kQKltCdfShape +686 +222, WebRtcIsac_kQKltCdfShape +686 +226, WebRtcIsac_kQKltCdfShape +686 +230, WebRtcIsac_kQKltCdfShape +686 +234, WebRtcIsac_kQKltCdfShape +686 +238, WebRtcIsac_kQKltCdfShape +686 +242, WebRtcIsac_kQKltCdfShape +686 +247, WebRtcIsac_kQKltCdfShape +686 +253, WebRtcIsac_kQKltCdfShape +686 +262, WebRtcIsac_kQKltCdfShape +686 +269, +WebRtcIsac_kQKltCdfShape +686 +278, WebRtcIsac_kQKltCdfShape +686 +289, WebRtcIsac_kQKltCdfShape +686 +305, WebRtcIsac_kQKltCdfShape +686 +307, WebRtcIsac_kQKltCdfShape +686 +309, WebRtcIsac_kQKltCdfShape +686 +311, WebRtcIsac_kQKltCdfShape +686 +315, WebRtcIsac_kQKltCdfShape +686 +319, WebRtcIsac_kQKltCdfShape +686 +323, WebRtcIsac_kQKltCdfShape +686 +327, +WebRtcIsac_kQKltCdfShape +686 +331, WebRtcIsac_kQKltCdfShape +686 +335, WebRtcIsac_kQKltCdfShape +686 +340, WebRtcIsac_kQKltCdfShape +686 +346, WebRtcIsac_kQKltCdfShape +686 +354, WebRtcIsac_kQKltCdfShape +686 +362, WebRtcIsac_kQKltCdfShape +686 +374, WebRtcIsac_kQKltCdfShape +686 +384, WebRtcIsac_kQKltCdfShape +686 +396, WebRtcIsac_kQKltCdfShape +686 +413, +WebRtcIsac_kQKltCdfShape +686 +439, WebRtcIsac_kQKltCdfShape +686 +442, WebRtcIsac_kQKltCdfShape +686 +446, WebRtcIsac_kQKltCdfShape +686 +450, WebRtcIsac_kQKltCdfShape +686 +455, WebRtcIsac_kQKltCdfShape +686 +461, WebRtcIsac_kQKltCdfShape +686 +468, WebRtcIsac_kQKltCdfShape +686 +475, WebRtcIsac_kQKltCdfShape +686 +481, WebRtcIsac_kQKltCdfShape +686 +489, +WebRtcIsac_kQKltCdfShape +686 +498, WebRtcIsac_kQKltCdfShape +686 +508, WebRtcIsac_kQKltCdfShape +686 +522, WebRtcIsac_kQKltCdfShape +686 +534, WebRtcIsac_kQKltCdfShape +686 +554, WebRtcIsac_kQKltCdfShape +686 +577, WebRtcIsac_kQKltCdfShape +686 +602, WebRtcIsac_kQKltCdfShape +686 +631}, +{WebRtcIsac_kQKltCdfShape +1368 +0, WebRtcIsac_kQKltCdfShape +1368 +2, WebRtcIsac_kQKltCdfShape +1368 +4, WebRtcIsac_kQKltCdfShape +1368 +6, WebRtcIsac_kQKltCdfShape +1368 +8, WebRtcIsac_kQKltCdfShape +1368 +10, WebRtcIsac_kQKltCdfShape +1368 +12, WebRtcIsac_kQKltCdfShape +1368 +14, WebRtcIsac_kQKltCdfShape +1368 +16, WebRtcIsac_kQKltCdfShape +1368 +20, +WebRtcIsac_kQKltCdfShape +1368 +24, WebRtcIsac_kQKltCdfShape +1368 +28, WebRtcIsac_kQKltCdfShape +1368 +32, WebRtcIsac_kQKltCdfShape +1368 +36, WebRtcIsac_kQKltCdfShape +1368 +40, WebRtcIsac_kQKltCdfShape +1368 +44, WebRtcIsac_kQKltCdfShape +1368 +50, WebRtcIsac_kQKltCdfShape +1368 +57, WebRtcIsac_kQKltCdfShape +1368 +65, WebRtcIsac_kQKltCdfShape +1368 +67, +WebRtcIsac_kQKltCdfShape +1368 +69, WebRtcIsac_kQKltCdfShape +1368 +71, WebRtcIsac_kQKltCdfShape +1368 +73, WebRtcIsac_kQKltCdfShape +1368 +75, WebRtcIsac_kQKltCdfShape +1368 +77, WebRtcIsac_kQKltCdfShape +1368 +79, WebRtcIsac_kQKltCdfShape +1368 +81, WebRtcIsac_kQKltCdfShape +1368 +85, WebRtcIsac_kQKltCdfShape +1368 +89, WebRtcIsac_kQKltCdfShape +1368 +93, +WebRtcIsac_kQKltCdfShape +1368 +97, WebRtcIsac_kQKltCdfShape +1368 +101, WebRtcIsac_kQKltCdfShape +1368 +105, WebRtcIsac_kQKltCdfShape +1368 +110, WebRtcIsac_kQKltCdfShape +1368 +116, WebRtcIsac_kQKltCdfShape +1368 +123, WebRtcIsac_kQKltCdfShape +1368 +132, WebRtcIsac_kQKltCdfShape +1368 +134, WebRtcIsac_kQKltCdfShape +1368 +136, WebRtcIsac_kQKltCdfShape +1368 +138, +WebRtcIsac_kQKltCdfShape +1368 +141, WebRtcIsac_kQKltCdfShape +1368 +143, WebRtcIsac_kQKltCdfShape +1368 +146, WebRtcIsac_kQKltCdfShape +1368 +150, WebRtcIsac_kQKltCdfShape +1368 +154, WebRtcIsac_kQKltCdfShape +1368 +158, WebRtcIsac_kQKltCdfShape +1368 +162, WebRtcIsac_kQKltCdfShape +1368 +166, WebRtcIsac_kQKltCdfShape +1368 +170, WebRtcIsac_kQKltCdfShape +1368 +174, +WebRtcIsac_kQKltCdfShape +1368 +179, WebRtcIsac_kQKltCdfShape +1368 +185, WebRtcIsac_kQKltCdfShape +1368 +193, WebRtcIsac_kQKltCdfShape +1368 +203, WebRtcIsac_kQKltCdfShape +1368 +214, WebRtcIsac_kQKltCdfShape +1368 +216, WebRtcIsac_kQKltCdfShape +1368 +218, WebRtcIsac_kQKltCdfShape +1368 +220, WebRtcIsac_kQKltCdfShape +1368 +224, WebRtcIsac_kQKltCdfShape +1368 +227, +WebRtcIsac_kQKltCdfShape +1368 +231, WebRtcIsac_kQKltCdfShape +1368 +235, WebRtcIsac_kQKltCdfShape +1368 +239, WebRtcIsac_kQKltCdfShape +1368 +243, WebRtcIsac_kQKltCdfShape +1368 +247, WebRtcIsac_kQKltCdfShape +1368 +251, WebRtcIsac_kQKltCdfShape +1368 +256, WebRtcIsac_kQKltCdfShape +1368 +262, WebRtcIsac_kQKltCdfShape +1368 +269, WebRtcIsac_kQKltCdfShape +1368 +277, +WebRtcIsac_kQKltCdfShape +1368 +286, WebRtcIsac_kQKltCdfShape +1368 +297, WebRtcIsac_kQKltCdfShape +1368 +315, WebRtcIsac_kQKltCdfShape +1368 +317, WebRtcIsac_kQKltCdfShape +1368 +319, WebRtcIsac_kQKltCdfShape +1368 +323, WebRtcIsac_kQKltCdfShape +1368 +327, WebRtcIsac_kQKltCdfShape +1368 +331, WebRtcIsac_kQKltCdfShape +1368 +335, WebRtcIsac_kQKltCdfShape +1368 +339, +WebRtcIsac_kQKltCdfShape +1368 +343, WebRtcIsac_kQKltCdfShape +1368 +349, WebRtcIsac_kQKltCdfShape +1368 +355, WebRtcIsac_kQKltCdfShape +1368 +361, WebRtcIsac_kQKltCdfShape +1368 +368, WebRtcIsac_kQKltCdfShape +1368 +376, WebRtcIsac_kQKltCdfShape +1368 +385, WebRtcIsac_kQKltCdfShape +1368 +397, WebRtcIsac_kQKltCdfShape +1368 +411, WebRtcIsac_kQKltCdfShape +1368 +429, +WebRtcIsac_kQKltCdfShape +1368 +456, WebRtcIsac_kQKltCdfShape +1368 +459, WebRtcIsac_kQKltCdfShape +1368 +463, WebRtcIsac_kQKltCdfShape +1368 +467, WebRtcIsac_kQKltCdfShape +1368 +473, WebRtcIsac_kQKltCdfShape +1368 +478, WebRtcIsac_kQKltCdfShape +1368 +485, WebRtcIsac_kQKltCdfShape +1368 +491, WebRtcIsac_kQKltCdfShape +1368 +497, WebRtcIsac_kQKltCdfShape +1368 +505, +WebRtcIsac_kQKltCdfShape +1368 +514, WebRtcIsac_kQKltCdfShape +1368 +523, WebRtcIsac_kQKltCdfShape +1368 +535, WebRtcIsac_kQKltCdfShape +1368 +548, WebRtcIsac_kQKltCdfShape +1368 +565, WebRtcIsac_kQKltCdfShape +1368 +585, WebRtcIsac_kQKltCdfShape +1368 +611, WebRtcIsac_kQKltCdfShape +1368 +640}}; + +/* code length for all coefficients using different models */ +const double WebRtcIsac_kQKltCodeLenGain[392] = { + 12.29956028, 7.83007500, 4.25642781, 0.17489215, 4.27591254, 7.66908312, 10.47643804, 11.91253716, 9.03421572, 8.57373525, + 6.73555740, 5.41409855, 3.65237863, 0.42623449, 3.22418399, 5.68145719, 7.14201900, 8.20558413, 9.34178852, 13.00000000, + 13.00000000, 9.47643804, 6.71459778, 3.55472644, 0.28457419, 3.70652835, 7.41128536, 11.60768258, 14.00000000, 12.29956028, + 9.29956028, 8.02845645, 6.54878889, 5.07667251, 2.87749552, 0.65310542, 3.11316029, 4.87911416, 5.89540125, 6.76398581, + 7.70537925, 9.67807191, 11.14201900, 14.00000000, 14.00000000, 12.29956028, 9.69621925, 7.70537925, 5.49915812, 2.67441345, + 0.63381441, 2.74999773, 5.76877882, 8.41503750, 10.75207249, 14.00000000, 9.60768258, 8.85025288, 8.09913319, 7.09010692, + 6.36337538, 5.46667027, 4.51618422, 2.64189829, 1.21843537, 2.43823474, 3.89409149, 4.99718498, 6.00989604, 6.78325414, + 7.39637366, 8.76159526, 10.60768258, 11.67807191, 12.29956028, 9.54056838, 7.95560588, 5.63040265, 3.81264793, 2.18521728, + 1.33727600, 2.37909290, 3.94981123, 5.52426657, 7.32051990, 8.84012866, 11.35614381, 13.00000000, 12.29956028, 11.35614381, + 11.35614381, 10.24511250, 9.12963528, 8.80032766, 7.97763219, 7.83007500, 7.09913319, 6.68711704, 6.41879942, 5.74379131, + 5.25096862, 4.43061904, 3.54492969, 2.72664147, 2.16306204, 2.71142226, 3.34357514, 4.07444556, 4.95151313, 5.68145719, + 6.12041675, 6.55085135, 7.00282052, 7.55705650, 8.44541115, 9.41503750, 10.91253716, 11.60768258, 14.00000000, 14.00000000, + 13.00000000, 11.60768258, 10.47643804, 8.80032766, 7.38161450, 6.52426657, 5.47447919, 4.53749773, 3.92719747, 3.41058292, + 2.88495635, 2.79344346, 2.85805254, 3.18261657, 3.57216340, 4.08225499, 4.74438125, 5.51215997, 6.30477171, 7.15450995, + 8.28575448, 9.69621925, 11.60768258, 13.00000000, 13.67807191, 15.00000000, 15.00000000, 14.00000000, 12.41503750, 11.29956028, + 12.41503750, 11.60768258, 10.11735695, 9.47643804, 9.12963528, 9.41503750, 8.23181568, 7.97763219, 7.82507432, 7.50814690, + 7.33466408, 6.99157138, 6.95834085, 6.80524315, 6.47447919, 6.35614381, 6.02128954, 5.71459778, 5.58109327, 5.05821876, + 4.94539568, 4.59220115, 4.27591254, 4.01522554, 3.89376424, 3.83760867, 3.73321346, 3.74674342, 3.90493270, 4.18942837, + 4.33599724, 4.42446075, 4.81760565, 5.07667251, 5.54570071, 5.95697272, 6.46667027, 6.91253716, 7.33466408, 7.82507432, + 8.05163277, 9.12963528, 9.02272008, 9.77118131, 9.60768258, 10.11735695, 12.00000000, 12.83007500, 15.00000000, 15.00000000, + 14.00000000, 15.00000000, 11.75207249, 12.29956028, 10.95560588, 9.93391081, 9.02272008, 8.00564656, 7.82507432, 7.28919357, + 6.77599833, 6.56745810, 6.19910010, 6.23347109, 5.67694524, 5.41879942, 4.96039548, 4.88170777, 4.60768258, 4.52883287, + 4.28876323, 4.17583679, 4.21332197, 4.14474217, 4.16119001, 4.12809476, 4.18501706, 4.28489599, 4.35299136, 4.60286019, + 4.63040265, 4.81017544, 5.00989604, 5.33822190, 5.43489792, 5.84644797, 6.13272126, 6.75444729, 7.36337538, 7.96108101, + 8.54056838, 9.28575448, 9.12963528, 9.47643804, 10.75207249, 12.29956028, 12.41503750, 11.14201900, 12.83007500, 15.00000000, + 15.00000000, 15.00000000, 15.00000000, 15.00000000, 15.00000000, 14.00000000, 15.00000000, 15.00000000, 15.00000000, 15.00000000, + 13.67807191, 12.41503750, 11.91253716, 11.60768258, 12.29956028, 13.00000000, 12.29956028, 10.95560588, 10.60768258, 9.77118131, + 10.02272008, 10.11735695, 10.14201900, 10.75207249, 10.75207249, 9.69621925, 9.47643804, 9.75207249, 8.72387559, 8.47643804, + 8.68711704, 8.40754296, 8.20558413, 8.26529038, 7.84518189, 7.89147554, 7.64685317, 7.41128536, 7.33466408, 7.42635281, + 7.24845594, 7.11430363, 7.07518750, 7.07518750, 6.70537925, 6.64906082, 6.73555740, 6.62931259, 6.50015411, 6.26190774, + 6.36337538, 6.19264508, 5.95151313, 6.08860801, 5.91253716, 5.83007500, 5.68145719, 5.67244736, 5.82632286, 6.00282052, + 5.65348627, 5.74970158, 5.87846648, 5.69052365, 5.64464890, 5.58531476, 5.81512466, 5.57688409, 5.87329553, 5.62170514, + 5.74851759, 5.81017544, 5.64464890, 5.76398581, 5.60339522, 5.69507833, 5.84139031, 5.68711704, 5.73908047, 5.84139031, + 5.71459778, 5.96245305, 5.82632286, 5.89540125, 6.08860801, 6.12041675, 6.13272126, 6.30477171, 6.24177679, 6.28232358, + 6.29091619, 6.53239445, 6.81512466, 6.72620440, 6.65792533, 6.84518189, 7.10215454, 7.44157929, 7.57793523, 7.59485854, + 7.66460965, 8.05163277, 8.00564656, 8.43775758, 8.10518224, 8.28575448, 8.77118131, 8.23181568, 8.29264087, 8.20558413, + 8.34894831, 8.89147554, 8.40754296, 8.61629571, 8.64244800, 8.61629571, 8.93391081, 8.50814690, 9.02272008, 8.68711704, + 8.65127185, 9.41503750, 9.11735695, 9.85025288, 10.24511250, 10.60768258, 10.47643804, 11.60768258, 11.35614381, 12.29956028, + 15.00000000, 15.00000000, 12.29956028, 13.00000000, 15.00000000, 15.00000000, 15.00000000, 15.00000000, 14.00000000, 12.83007500, + 15.00000000, 15.00000000}; + +const double WebRtcIsac_kQKltCodeLenShape[578] = { + 0.00002201, 0.00002201, 0.00002201, 0.00002201, 0.00002201, 0.00002201, 0.00002201, 0.00002201, 0.00002201, 14.00000000, + 0.00011007, 13.00000000, 0.00066056, 11.60768258, 11.14201900, 0.00185034, 10.24511250, 9.08113676, 0.00480700, 9.41503750, + 8.09913319, 0.01084946, 8.02845645, 13.00000000, 6.40941295, 0.02926496, 6.95560588, 13.00000000, 13.00000000, 6.21864029, + 0.03861814, 6.30477171, 12.29956028, 11.14201900, 4.66964328, 0.12158980, 4.62604734, 10.91253716, 14.00000000, 11.35614381, + 8.76159526, 3.89671219, 0.21179147, 3.99472634, 8.02272008, 13.00000000, 0.00002201, 0.00002201, 0.00002201, 0.00002201, + 14.00000000, 0.00011007, 0.00002201, 0.00002201, 0.00002201, 0.00002201, 14.00000000, 0.00011007, 10.95560588, 0.00147568, + 10.95560588, 10.24511250, 0.00240150, 10.24511250, 8.02845645, 0.01056115, 8.17982104, 6.74497143, 0.02381629, 7.15137706, + 5.68598330, 0.05650076, 5.72970467, 13.00000000, 14.00000000, 5.18221688, 0.07697435, 5.37611851, 11.91253716, 9.54056838, + 3.92853764, 0.22143514, 3.76428491, 9.28575448, 14.00000000, 11.35614381, 7.37794818, 3.30585980, 0.37001735, 3.18521728, + 6.88886433, 11.91253716, 14.00000000, 0.00002201, 0.00002201, 0.00002201, 0.00002201, 14.00000000, 0.00019814, 14.00000000, + 0.00002201, 13.00000000, 0.00028621, 14.00000000, 14.00000000, 0.00028621, 13.00000000, 11.91253716, 0.00094690, 11.35614381, + 10.60768258, 0.00213692, 10.24511250, 8.37794818, 0.00863317, 8.43775758, 14.00000000, 7.41128536, 0.01698415, 7.42635281, + 6.02702021, 0.04514485, 6.01558154, 13.00000000, 5.05090284, 0.09207659, 4.98877274, 15.00000000, 10.75207249, 4.41081703, + 0.15733047, 4.17424617, 11.60768258, 14.00000000, 15.00000000, 10.06926266, 3.74320161, 0.23091117, 3.81141115, 10.02272008, + 11.91253716, 6.90196792, 2.92703003, 0.46874039, 2.93846004, 7.26190774, 11.60768258, 13.00000000, 10.21864029, 7.95560588, + 5.19345038, 2.40520888, 0.77554605, 2.56628417, 5.41409855, 8.81017544, 12.29956028, 0.00002201, 0.00002201, 0.00002201, + 0.00002201, 11.91253716, 0.00068259, 12.29956028, 10.11735695, 0.00233535, 10.47643804, 10.35614381, 0.00140957, 12.29956028, + 10.24511250, 0.00222511, 10.47643804, 7.72387559, 0.01475842, 7.52426657, 6.73555740, 0.02924249, 6.55085135, 14.00000000, + 5.45021533, 0.06930886, 5.38345116, 4.55913083, 0.11289841, 4.92853764, 11.60768258, 4.07148162, 0.19798859, 3.87200568, + 13.00000000, 9.60768258, 3.31393725, 0.29937064, 3.57321111, 9.35614381, 14.00000000, 8.02845645, 3.08542800, 0.45503557, + 2.80678268, 7.47643804, 12.29956028, 14.00000000, 14.00000000, 14.00000000, 6.83509307, 2.69166097, 0.61673447, 2.51266238, + 6.84771516, 11.91253716, 11.14201900, 7.72387559, 4.61899789, 2.17136763, 1.03592993, 2.28586183, 4.86814304, 7.78568088, + 10.91253716, 14.00000000, 15.00000000, 11.04580369, 9.28575448, 7.26190774, 5.21946023, 3.61575588, 2.18431651, 1.45666604, + 2.33566383, 3.85470467, 5.46181107, 7.30651304, 8.89147554, 11.91253716, 0.00002201, 0.00002201, 15.00000000, 0.00011007, + 15.00000000, 10.47643804, 0.00149771, 11.60768258, 7.30651304, 0.01903486, 7.20558413, 6.92318440, 0.02587674, 6.71459778, + 7.28919357, 0.01756340, 7.45696818, 6.06926266, 0.03841465, 6.45890338, 4.46035649, 0.13896157, 4.43204392, 14.00000000, + 14.00000000, 4.09010692, 0.19672654, 3.86653665, 13.00000000, 14.00000000, 11.35614381, 3.45117809, 0.27340929, 3.64878468, + 9.93391081, 9.60768258, 3.30585980, 0.35178287, 3.15607895, 9.12963528, 12.29956028, 7.93391081, 2.82180202, 0.53064436, + 2.68258739, 7.42635281, 11.14201900, 15.00000000, 10.06926266, 6.15294265, 2.55861197, 0.69308389, 2.48602573, 5.90592231, + 9.47643804, 13.00000000, 11.14201900, 8.20558413, 5.21618324, 2.34973357, 1.00379135, 2.09611815, 4.80278331, 7.82507432, + 11.91253716, 12.29956028, 8.98877274, 6.75444729, 4.23886435, 2.19859476, 1.29528579, 2.06032897, 4.06704711, 6.76398581, + 9.34178852, 13.00000000, 12.29956028, 10.14201900, 8.40754296, 6.16710999, 4.64850859, 3.28768796, 2.22892326, 1.78568088, + 2.35209193, 3.45141888, 4.91121176, 6.45117809, 8.20558413, 10.35614381, 13.00000000, 12.83007500, 14.00000000, 14.00000000, + 12.83007500, 11.35614381, 9.85025288, 9.41503750, 8.07518750, 7.34894831, 6.25516616, 5.25096862, 4.52477322, 3.68513357, + 3.06152306, 2.64011320, 2.54608637, 2.95765662, 3.44445223, 4.01665007, 4.63258525, 5.27633906, 6.24678325, 7.05163277, + 8.02845645, 9.60768258, 10.79054663, 12.83007500, 14.00000000, 0.00002201, 15.00000000, 0.00011007, 15.00000000, 5.82009091, + 0.02710994, 10.11735695, 15.00000000, 3.30346709, 0.17317845, 6.41128536, 15.00000000, 15.00000000, 10.83007500, 2.72897475, + 0.35935964, 3.85853144, 13.00000000, 15.00000000, 3.72766182, 0.17268211, 4.74674342, 15.00000000, 15.00000000, 4.40754296, + 0.11993823, 4.93997965, 15.00000000, 15.00000000, 4.70193743, 0.22110152, 3.27591254, 11.35614381, 15.00000000, 12.54056838, + 6.94743195, 2.99157138, 0.62079088, 2.25338071, 7.41128536, 15.00000000, 15.00000000, 11.47643804, 6.04580369, 2.80232255, + 0.98380109, 1.70502034, 5.15607895, 10.75207249, 13.00000000, 15.00000000, 15.00000000, 11.35614381, 6.44157929, 2.37955105, + 0.74567258, 2.44181848, 6.07667251, 10.75207249, 15.00000000, 15.00000000, 15.00000000, 15.00000000, 9.44541115, 5.25432568, + 1.97815248, 0.94086682, 2.57885561, 5.17265730, 8.72387559, 14.00000000, 15.00000000, 15.00000000, 15.00000000, 10.67807191, + 7.59485854, 4.91187431, 2.91934900, 1.32321648, 1.50614455, 3.85215911, 7.15137706, 10.60768258, 14.00000000, 15.00000000, + 15.00000000, 15.00000000, 15.00000000, 15.00000000, 15.00000000, 15.00000000, 11.09310940, 8.50814690, 6.45117809, 3.94675287, + 2.16730774, 1.37674720, 2.10215454, 3.97278511, 6.34178852, 8.50814690, 10.32757466, 14.00000000, 14.00000000, 15.00000000, + 15.00000000, 15.00000000, 14.00000000, 10.02272008, 9.41503750, 7.03710399, 5.13349379, 3.61683574, 2.47999526, 1.82788507, + 2.00945280, 3.08020557, 4.69793233, 6.64025044, 8.32051990, 10.91253716, 14.00000000, 15.00000000, 15.00000000, 15.00000000, + 15.00000000, 15.00000000, 15.00000000, 14.41503750, 9.41503750, 7.10215454, 5.60768258, 4.44014496, 3.30064444, 2.56941678, + 2.28103909, 2.42694459, 2.93206152, 3.83383692, 4.75207249, 6.02702021, 7.16394964, 9.35614381, 11.14201900, 12.29956028, + 15.00000000, 15.00000000, 14.00000000, 15.00000000, 15.00000000, 10.11735695, 8.85025288, 7.02558541, 5.86300889, 4.79726396, + 3.95117259, 3.44925321, 2.96348293, 2.88219459, 2.89671219, 3.10518224, 3.50065237, 4.05748549, 4.55291677, 5.23016216, + 5.79420675, 6.39452048, 6.91253716, 7.97763219, 8.32051990, 9.35614381, 10.60768258, 11.60768258, 15.00000000, 15.00000000, + 12.83007500, 12.41503750, 11.91253716, 14.00000000, 14.00000000, 11.35614381, 10.75207249, 10.91253716, 8.93391081, 8.61629571, + 8.29264087, 8.02272008, 7.89147554, 7.33466408, 7.41128536, 6.71459778, 5.92853764, 5.31964048, 4.97693875, 4.70308379, + 4.43632704, 4.34357514, 4.30825648, 4.26529038, 4.19465917, 4.27420773, 4.22315577, 4.08262792, 4.06667818, 4.16119001, + 4.08860801, 4.26698468, 4.39128315, 4.71517590, 5.10442472, 5.50714538, 5.81017544, 6.15922208}; + +/* left KLT transforms */ +const double WebRtcIsac_kKltT1Gain[3][4] = { +{-0.79742827, 0.60341375, 0.60341375, 0.79742827}, +{-0.81372390, 0.58125159, 0.58125159, 0.81372390}, +{-0.71832547, 0.69570721, 0.69570721, 0.71832547}}; + +const double WebRtcIsac_kKltT1Shape[3][324] = { +{ 0.00159597, 0.00049320, 0.00513821, 0.00021066, 0.01338581, -0.00422367, -0.00272072, 0.00935107, 0.02047622, 0.02691189, + 0.00478236, 0.03969702, 0.00886698, 0.04877604, -0.10898362, -0.05930891, -0.03415047, 0.98889721, 0.00293558, -0.00035282, + 0.01156321, -0.00195341, -0.00937631, 0.01052213, -0.02551163, 0.01644059, 0.03189927, 0.07754773, -0.08742313, -0.03026338, + 0.05136248, -0.14395974, 0.17725040, 0.22664856, 0.93380230, 0.07076411, 0.00557890, -0.00222834, 0.01377569, 0.01466808, + 0.02847361, -0.00603178, 0.02382480, -0.01210452, 0.03797267, -0.02371480, 0.11260335, -0.07366682, 0.00453436, -0.04136941, +-0.07912843, -0.95031418, 0.25295337, -0.05302216, -0.00617554, -0.00044040, -0.00653778, 0.01097838, 0.01529174, 0.01374431, +-0.00748512, -0.00020034, 0.02432713, 0.11101570, -0.08556891, 0.09282249, -0.01029446, 0.67556443, -0.67454300, 0.06910063, + 0.20866865, -0.10318050, 0.00932175, 0.00524058, 0.00803610, -0.00594676, -0.01082578, 0.01069906, 0.00546768, 0.01565291, + 0.06816200, 0.10201227, 0.16812734, 0.22984074, 0.58213170, -0.54138651, -0.51379962, 0.06847390, -0.01920037, -0.04592324, +-0.00467394, 0.00328858, 0.00377424, -0.00987448, 0.08222096, -0.00377301, 0.04551941, -0.02592517, 0.16317082, 0.13077530, + 0.22702921, -0.31215289, -0.69645962, -0.38047101, -0.39339411, 0.11124777, 0.02508035, -0.00708074, 0.00400344, 0.00040331, + 0.01142402, 0.01725406, 0.01635170, 0.14285366, 0.03949233, -0.05905676, 0.05877154, -0.17497577, -0.32479440, 0.80754464, +-0.38085603, -0.17055430, -0.03168622, -0.07531451, 0.02942002, -0.02148095, -0.00754114, -0.00322372, 0.00567812, -0.01701521, +-0.12358320, 0.11473564, 0.09070136, 0.06533068, -0.22560802, 0.19209022, 0.81605094, 0.36592275, -0.09919829, 0.16667122, + 0.16300725, 0.04803807, 0.06739263, -0.00156752, -0.01685302, -0.00905240, -0.02297836, -0.00469939, 0.06310613, -0.16391930, + 0.10919511, 0.12529293, 0.85581322, -0.32145522, 0.24539076, 0.07181839, 0.07289591, 0.14066759, 0.10406711, 0.05815518, + 0.01072680, -0.00759339, 0.00053486, -0.00044865, 0.03407361, 0.01645348, 0.08758579, 0.27722240, 0.53665485, -0.74853376, +-0.01118192, -0.19805430, 0.06130619, -0.09675299, 0.08978480, 0.03405255, -0.00706867, 0.05102045, 0.03250746, 0.01849966, +-0.01216314, -0.01184187, -0.01579288, 0.00114807, 0.11376166, 0.88342114, -0.36425379, 0.13863190, 0.12524180, -0.13553892, + 0.04715856, -0.12341103, 0.04531568, 0.01899360, -0.00206897, 0.00567768, -0.01444163, 0.00411946, -0.00855896, 0.00381663, +-0.01664861, -0.05534280, 0.21328278, 0.20161162, 0.72360394, 0.59130708, -0.08043791, 0.08757349, -0.13893918, -0.05147377, + 0.02680690, -0.01144070, 0.00625162, -0.00634215, -0.01248947, -0.00329455, -0.00609625, -0.00136305, -0.05097048, -0.01029851, + 0.25065384, -0.16856837, -0.07123372, 0.15992623, -0.39487617, -0.79972301, 0.18118185, -0.04826639, -0.01805578, -0.02927253, +-0.16400618, 0.07472763, 0.10376449, 0.01705406, 0.01065801, -0.01500498, 0.02039914, 0.37776349, -0.84484186, 0.10434286, + 0.15616990, 0.13474456, -0.00906238, -0.25238368, -0.03820885, -0.10650905, -0.03880833, -0.03660028, -0.09640894, 0.00583314, + 0.01922097, 0.01489911, -0.02431117, -0.09372217, 0.39404721, -0.84786223, -0.31277121, 0.03193850, 0.01974060, 0.01887901, + 0.00337911, -0.11359599, -0.02792521, -0.03220184, -0.01533311, 0.00015962, -0.04225043, -0.00933965, 0.00675311, 0.00206060, + 0.15926771, 0.40199829, -0.80792558, -0.35591604, -0.17169764, 0.02830436, 0.02459982, -0.03438589, 0.00718705, -0.01798329, +-0.01594508, -0.00702430, -0.00952419, -0.00962701, -0.01307212, -0.01749740, 0.01299602, 0.00587270, -0.36103108, -0.82039266, +-0.43092844, -0.08500097, -0.04361674, -0.00333482, 0.01250434, -0.02538295, -0.00921797, 0.01645071, -0.01400872, 0.00317607, + 0.00003277, -0.01617646, -0.00616863, -0.00882661, 0.00466157, 0.00353237, 0.91803104, -0.39503305, -0.02048964, 0.00060125, + 0.01980634, 0.00300109, 0.00313880, 0.00657337, 0.00715163, 0.00000261, 0.00854276, -0.00154825, -0.00516128, 0.00909527, + 0.00095609, 0.00701196, -0.00221867, -0.00156741}, +{-0.00469582, -0.00020403, -0.00587134, 0.00185153, -0.02256479, -0.01185761, -0.02891481, -0.00493792, -0.00182344, 0.00285962, + 0.01558059, -0.02185140, 0.04639438, -0.04357142, 0.12718613, -0.06756136, 0.05542227, 0.98480184, -0.00374376, -0.00236433, +-0.00607169, -0.00303290, -0.00127243, -0.01794845, 0.00620033, -0.00732704, -0.02837749, -0.00107164, 0.04820548, 0.00713300, + 0.09784244, -0.16806261, -0.04563341, -0.33406041, 0.91554083, -0.08139655, -0.00415851, -0.00538193, -0.00731198, -0.00534534, +-0.00623075, -0.02016943, -0.05480133, -0.03172290, -0.03879603, 0.01518441, 0.09591688, 0.02238470, 0.08126640, 0.08236821, +-0.24802119, 0.89516402, 0.32029647, 0.07188887, -0.00220366, 0.00344025, -0.00277284, 0.00358963, -0.08668007, -0.02205910, +-0.05289669, -0.03535201, -0.01188017, -0.06456872, -0.09321006, -0.00009617, -0.15804070, 0.24632041, 0.90166119, 0.19250690, + 0.17264619, -0.09699155, -0.00567329, -0.00897700, -0.01442565, -0.01939390, 0.03702127, -0.02999862, -0.04385696, -0.05232394, +-0.03339177, 0.03905964, -0.00281424, -0.29213275, 0.02892968, 0.90257613, -0.21546058, -0.18070946, 0.09014567, 0.04117230, +-0.01029696, -0.00329116, -0.03354346, 0.02937079, 0.01274208, -0.01260649, -0.03505571, -0.01020645, 0.03787209, 0.12132165, +-0.20826840, 0.81556933, -0.43874351, 0.21518682, -0.14564290, -0.05210031, 0.07124563, 0.06127983, -0.00457321, 0.01740496, + 0.04185176, 0.00128036, -0.05033693, -0.01890046, 0.06221734, 0.10280078, -0.03738531, 0.04830209, -0.08408293, -0.46409009, +-0.83936263, -0.14817619, -0.13135927, 0.04563506, 0.08340661, 0.04040200, 0.00044396, -0.01365972, 0.01228951, 0.01078273, + 0.09205406, -0.03791500, 0.07135889, 0.08158339, 0.06298278, -0.22875755, -0.92917558, -0.11248260, 0.17801883, -0.03971674, +-0.07491915, 0.06477287, 0.04635713, 0.01856159, 0.00130895, -0.01991604, 0.02358176, -0.09376056, 0.02782280, -0.04691559, + 0.13749249, 0.31383132, 0.92274602, 0.04727419, 0.09765196, -0.02108945, 0.00626005, 0.05193322, 0.02009133, 0.03094066, + 0.04573470, 0.00451733, 0.00240169, -0.00982355, -0.03546208, -0.14156875, -0.02480689, 0.22997442, 0.09778317, 0.88834235, +-0.32797611, -0.00079977, 0.04917079, 0.06977359, 0.06451185, 0.07816204, 0.03119314, 0.01136506, 0.01062006, 0.00632783, + 0.03241828, -0.03318847, -0.01350502, -0.30055361, 0.07265375, 0.17308022, 0.88795796, -0.23231020, -0.08932700, 0.11759604, + 0.00590705, 0.03525351, 0.00840466, 0.04389942, 0.04387629, 0.04003275, 0.01772966, 0.02709780, -0.02393282, 0.02766178, + 0.00342983, -0.33882220, 0.76612668, 0.44061716, -0.28414784, -0.09364014, 0.03694060, 0.01124120, 0.01130268, -0.02869682, +-0.07428963, -0.03504754, 0.05874942, 0.01196795, 0.02003875, 0.00787152, -0.01605561, 0.04501257, -0.06959958, -0.13015784, +-0.05738065, 0.04681625, 0.06668700, -0.04492094, 0.02927765, -0.94404277, 0.19243952, 0.09504337, -0.12540826, 0.05394317, +-0.07972638, -0.02145188, 0.00136427, 0.01964678, 0.06667373, 0.06204535, 0.17302394, 0.22005905, 0.58329964, -0.68440447, + 0.19628796, 0.15718011, -0.12481840, -0.08222507, 0.11780870, 0.03798206, -0.01818866, 0.00892766, 0.05582263, 0.01126832, +-0.00973589, 0.00697442, -0.09937902, 0.06621185, -0.19452202, -0.80004569, -0.13946094, -0.48990700, -0.17595191, -0.00798873, +-0.06121856, 0.08768040, -0.04507631, 0.00448896, 0.01153941, -0.04711652, -0.01050749, -0.01660047, -0.03007159, -0.01468906, + 0.12848053, 0.13859838, 0.93863771, -0.22250065, -0.14841278, 0.04666032, -0.06344813, -0.01915105, -0.01840150, -0.02389410, +-0.01245496, 0.05023402, 0.02125840, 0.02467318, -0.01893022, -0.00889647, 0.00551817, 0.00481915, -0.40626968, -0.89028236, + 0.18261687, -0.03852330, 0.02621926, -0.05420122, -0.01704117, -0.00072893, -0.02694170, -0.04335124, 0.02256467, 0.00642301, +-0.01619484, -0.00871160, 0.00400065, -0.00488820, -0.00752173, -0.00170603, 0.89554989, -0.41825934, -0.08725803, -0.09051404, +-0.00916236, -0.02959065, -0.07268075, -0.00816626, -0.00314215, -0.01941078, -0.00036782, -0.00188655, -0.02107724, -0.00771657, +-0.00448194, -0.00387517, 0.00082998, 0.00202471}, +{ 0.00167296, -0.00647772, -0.00604394, 0.01490810, -0.00837664, 0.00246438, 0.02082153, 0.01216715, 0.01001396, -0.02850860, +-0.01187868, -0.00113289, 0.04140237, -0.11084998, 0.16102260, 0.20084170, -0.28969446, -0.91312256, 0.00087788, -0.00136895, + 0.00004622, 0.00578894, 0.00524119, -0.00044550, 0.00948906, -0.00396910, -0.03312197, -0.00075487, 0.00987494, -0.02088734, + 0.09835550, -0.20080342, 0.13687782, -0.16111863, -0.90089988, 0.30312999, 0.00248784, -0.00975419, -0.01617200, 0.00699371, +-0.02151635, -0.01625774, -0.01262800, 0.02588781, -0.05620764, -0.13651454, 0.04242442, -0.02615307, 0.20497288, -0.20422909, + 0.14184406, 0.89712919, 0.01758042, 0.25447787, -0.00207668, -0.00260329, 0.00724812, -0.01007749, 0.00806242, -0.03089729, +-0.01161934, -0.00618676, -0.10327342, -0.10160272, 0.11919283, 0.20781533, 0.11564869, -0.19072476, 0.86402008, -0.24650846, + 0.24684161, 0.04775750, 0.00486888, -0.01735569, -0.01868000, -0.01870386, -0.03243262, -0.05883701, -0.03433371, 0.10441236, +-0.22831067, -0.22837988, 0.15082544, -0.21313767, 0.13215611, -0.78096079, -0.32270595, -0.21307018, 0.17339271, -0.05435742, +-0.00940813, 0.00272520, 0.00542917, -0.05232991, -0.01280809, -0.10773627, -0.17626479, 0.03719285, -0.26297104, -0.21780618, + 0.21406665, 0.15202177, 0.75911044, 0.38627481, -0.16504189, -0.10242997, -0.02394939, -0.06018959, 0.00994733, -0.02617197, +-0.01543723, -0.10320051, -0.03010481, -0.19098072, -0.06893233, 0.12253174, -0.25556092, -0.31989059, 0.09542655, 0.72712041, +-0.43108921, -0.01568072, -0.16532685, 0.06646835, -0.08885408, -0.00050364, -0.01791050, 0.00245405, 0.00204794, -0.17948691, +-0.05193881, -0.16329387, -0.13676259, 0.01214133, -0.30994612, -0.00687734, 0.63254090, -0.47180795, -0.35409214, 0.23658315, + 0.11170294, 0.05229887, -0.06107035, -0.01094212, 0.01523854, -0.01608284, -0.03739206, -0.23864328, -0.03958494, -0.19305719, +-0.26019058, 0.24108257, -0.55933566, 0.40623396, -0.53367968, -0.08930957, -0.00599383, -0.00050845, 0.06960811, 0.02664961, + 0.01464197, -0.00486781, -0.01905736, 0.01437578, 0.02379930, -0.26639588, 0.05208876, -0.43525002, -0.63009424, 0.05251889, + 0.56732782, -0.06731164, -0.03705909, -0.03253946, 0.00950673, -0.07941760, 0.02388267, -0.01258409, -0.00343524, 0.00148711, +-0.00362107, 0.03981813, -0.07235214, -0.46180041, -0.05595288, -0.55699317, 0.61935853, -0.25379716, 0.06796783, 0.01039267, +-0.06329171, -0.02143024, 0.09406929, -0.00799203, -0.01419805, -0.00603024, 0.01313145, 0.00091161, -0.00212107, -0.02405340, + 0.07146405, -0.76695326, -0.14841817, 0.60372663, -0.01478424, 0.06522462, 0.08580016, -0.05817981, 0.02438942, 0.04840904, + 0.02934363, -0.02239678, -0.00582247, -0.00091312, -0.00394148, -0.00285276, -0.03435745, 0.05277435, 0.17882781, -0.06194164, + 0.27321118, 0.01840179, -0.10188148, -0.33168524, -0.03491221, 0.67351789, 0.37017376, 0.32083717, 0.09737800, -0.20998084, +-0.10725041, 0.06379186, 0.02169903, -0.02031584, 0.05623799, -0.18300962, -0.17337803, 0.08915172, -0.53835537, -0.08547263, + 0.15163321, 0.56732906, 0.21878115, 0.37274266, 0.26206918, 0.13443927, 0.09178695, -0.03276324, -0.01131664, -0.00236369, + 0.00772568, 0.01008805, -0.17122615, 0.15301569, 0.40135484, -0.06058913, 0.56405128, -0.05176853, 0.24544337, 0.62448073, + 0.07265009, -0.01198695, 0.05151774, -0.03678498, 0.01886154, 0.03724094, 0.01393667, 0.00758055, -0.00254297, 0.00537118, + 0.24169707, -0.41735970, -0.67564355, -0.09270478, 0.53106033, 0.06214579, 0.02574404, 0.09943837, 0.03032542, 0.02194476, + 0.06369772, -0.00133741, 0.01301113, 0.01508494, 0.00036111, -0.00278870, 0.00139205, 0.00015792, -0.43347887, 0.69923146, +-0.55406563, -0.01102231, 0.01347767, 0.07012139, -0.02530164, 0.06803192, 0.01177196, 0.04374491, 0.04073027, 0.04037438, + 0.00167330, -0.01807065, -0.00425562, 0.00149653, -0.00035119, -0.00172888, 0.84785495, 0.52289580, 0.01067734, -0.00859194, + 0.01685964, 0.00481442, 0.00434738, 0.07592695, 0.01419942, 0.01005336, 0.03316937, 0.00360465, 0.00435039, 0.00029122, + 0.00171268, 0.00198919, -0.00046889, -0.00094176}}; + +/* right KLT transforms */ +const double WebRtcIsac_kKltT2Gain[3][36] = { +{ 0.14572837, -0.45446306, 0.61990621, -0.52197033, 0.32145074, -0.11026900, -0.20698282, 0.48962182, -0.27127933, -0.33627476, + 0.65094037, -0.32715751, 0.40262573, -0.47844405, -0.33876075, 0.44130653, 0.37383966, -0.39964662, -0.51730480, 0.06611973, + 0.49030187, 0.47512886, -0.02141226, -0.51129451, -0.58578569, -0.39132064, -0.13187771, 0.15649421, 0.40735596, 0.54396897, + 0.40381276, 0.40904942, 0.41179766, 0.41167576, 0.40840251, 0.40468132}, +{-0.11368135, 0.34815515, -0.56434996, 0.61130763, -0.39970336, 0.11795708, 0.28514257, -0.58879243, 0.32775812, 0.27024886, +-0.56251299, 0.27411037, 0.42649186, -0.44080232, -0.36408215, 0.35932457, 0.43592895, -0.41484213, -0.49813030, -0.00012592, + 0.49865688, 0.47634953, 0.01094246, -0.52552726, -0.56154082, -0.41110686, -0.14170764, 0.15946614, 0.40818082, 0.55094554, + 0.40051601, 0.41084781, 0.41567800, 0.41450700, 0.40871872, 0.39891823}, +{-0.10719481, 0.34796287, -0.54573957, 0.59521001, -0.43943367, 0.14907223, 0.26554957, -0.59549939, 0.36760692, 0.26040652, +-0.55268701, 0.25778784, 0.38994096, -0.45282773, -0.37975656, 0.40213055, 0.43052647, -0.38937904, -0.52698359, 0.02788094, + 0.48284286, 0.47792474, 0.02557759, -0.50922240, -0.57699826, -0.39476779, -0.14708238, 0.12742149, 0.37835245, 0.57464021, + 0.39408127, 0.40327462, 0.40993655, 0.41419345, 0.41506301, 0.41253853}}; + +const double WebRtcIsac_kKltT2Shape[3][36] = { +{ 0.13427386, -0.35132558, 0.52506528, -0.59419077, 0.45075085, -0.16312057, 0.29857439, -0.58660147, 0.34265431, 0.20879510, +-0.56063262, 0.30238345, 0.43308283, -0.41186999, -0.35288681, 0.42768996, 0.36094634, -0.45284910, -0.47116680, 0.02893449, + 0.54326135, 0.45249040, -0.06264420, -0.52283830, 0.57137758, 0.44298139, 0.12617554, -0.20819946, -0.42324603, -0.48876443, + 0.39597050, 0.40713935, 0.41389880, 0.41512486, 0.41130400, 0.40575001}, +{ 0.16540737, -0.43379435, 0.58165221, -0.55154773, 0.35734028, -0.11935912, 0.29434254, -0.55954817, 0.23549804, 0.33087258, +-0.58848503, 0.29835834, 0.45464789, -0.38316155, -0.41689708, 0.35607296, 0.41260747, -0.41910198, -0.48633899, -0.04144955, + 0.47824583, 0.51050942, 0.01000345, -0.52184032, 0.53488229, 0.42641051, 0.17049774, -0.15849613, -0.43229355, -0.53945045, + 0.39582002, 0.41033103, 0.41788713, 0.41688080, 0.41081697, 0.39719658}, +{ 0.13386268, -0.37919915, 0.54989123, -0.57663572, 0.42402636, -0.15362720, 0.29641577, -0.58806770, 0.31381040, 0.26524954, +-0.56271012, 0.28431868, 0.42699898, -0.41058922, -0.40408270, 0.39215865, 0.40788513, -0.40699735, -0.49846482, -0.01521208, + 0.48756040, 0.49479418, -0.00347672, -0.51841384, 0.55513106, 0.41683793, 0.15131217, -0.15613621, -0.41029341, -0.54996461, + 0.39402116, 0.40965305, 0.41862791, 0.41730770, 0.41089648, 0.39837262}}; + +/* means of log gains and LAR coefficients*/ +const double WebRtcIsac_kLpcMeansGain[3][12] = { +{-6.86881911, -5.35075273, -6.86792680, -5.36200897, -6.86401538, -5.36921533, -6.86802969, -5.36893966, -6.86538097, -5.36315063, +-6.85535304, -5.35155315}, +{-6.12914600, -4.78070092, -6.12971780, -4.78382183, -6.12858525, -4.79362198, -6.12926491, -4.79017481, -6.12102401, -4.78346122, +-6.11441152, -4.78019228}, +{-5.67273484, -3.73876311, -5.65246094, -3.71407895, -5.61716443, -3.68814580, -5.58804560, -3.66334094, -5.54189577, -3.63845640, +-5.49293185, -3.61760203}}; + +const double WebRtcIsac_kLpcMeansShape[3][108] = { +{-0.91232981, 0.26258634, -0.33716701, 0.08477430, -0.03378426, 0.14423909, 0.07036185, 0.06155019, 0.01490385, 0.04138740, + 0.01427317, 0.01288970, 0.83872106, 0.25750199, 0.07988929, -0.01957923, 0.00831390, 0.01770300, -0.90957164, 0.25732216, +-0.33385344, 0.08735740, -0.03715332, 0.14584917, 0.06998990, 0.06131968, 0.01504379, 0.04067339, 0.01428039, 0.01406460, + 0.83846243, 0.26169862, 0.08109025, -0.01767055, 0.00970539, 0.01954310, -0.90490803, 0.24656405, -0.33578607, 0.08843286, +-0.03749139, 0.14443959, 0.07214669, 0.06170993, 0.01449947, 0.04134309, 0.01314762, 0.01413471, 0.83895203, 0.26748062, + 0.08197507, -0.01781298, 0.00885967, 0.01922394, -0.90922472, 0.24495889, -0.33921540, 0.08877169, -0.03581332, 0.14199172, + 0.07444032, 0.06185940, 0.01502054, 0.04185113, 0.01276579, 0.01355457, 0.83645358, 0.26631720, 0.08119697, -0.01835449, + 0.00788512, 0.01846446, -0.90482253, 0.24658310, -0.34019734, 0.08281090, -0.03486038, 0.14359248, 0.07401336, 0.06001471, + 0.01528421, 0.04254560, 0.01321472, 0.01240799, 0.83857127, 0.26281654, 0.08174380, -0.02099842, 0.00755176, 0.01699448, +-0.90132307, 0.25174308, -0.33838268, 0.07883863, -0.02877906, 0.14105407, 0.07220290, 0.06000352, 0.01684879, 0.04226844, + 0.01331331, 0.01269244, 0.83832138, 0.25467485, 0.08118028, -0.02120528, 0.00747832, 0.01567212}, +{-1.11639718, 0.35377266, 0.00798929, 0.20165280, 0.07656104, 0.10629964, 0.04894160, 0.10955305, -0.01806405, 0.05082282, + 0.01730794, 0.01345957, 0.73717782, 0.05952284, 0.03176204, 0.08195122, 0.01253148, 0.02253385, -1.12053537, 0.35523538, + 0.00859646, 0.20007706, 0.07715852, 0.10754596, 0.05165976, 0.10927703, -0.01554395, 0.05178866, 0.01752534, 0.01343468, + 0.73489046, 0.06395167, 0.03287798, 0.07972374, 0.01293550, 0.02300929, -1.11772179, 0.35457623, 0.01205524, 0.19926481, + 0.08000866, 0.10817921, 0.05052481, 0.11016167, -0.01552091, 0.05155510, 0.01787163, 0.01343778, 0.73142568, 0.06840830, + 0.03316828, 0.07902608, 0.01525042, 0.02178127, -1.12120164, 0.36405233, 0.00630305, 0.19799738, 0.07829690, 0.10727588, + 0.04017317, 0.10437949, -0.01844109, 0.05021700, 0.01561726, 0.01226571, 0.73438044, 0.06947982, 0.03396317, 0.07858683, + 0.01367105, 0.02041955, -1.12146187, 0.35952226, 0.00340090, 0.19700813, 0.07938222, 0.10904137, 0.03921216, 0.10531403, +-0.01833415, 0.04956231, 0.01399539, 0.01323582, 0.74378099, 0.07059589, 0.03367692, 0.08151462, 0.01182040, 0.02075577, +-1.11245254, 0.35234230, 0.00687490, 0.20204252, 0.07813186, 0.11081259, 0.04634665, 0.11073238, -0.01637954, 0.05104577, + 0.01675122, 0.01448696, 0.74013627, 0.06239059, 0.03129412, 0.08207461, 0.01249475, 0.02189238}, +{-1.27118948, 0.35834331, -0.33499347, 0.13524073, 0.04829079, 0.19542773, 0.05273835, 0.04157974, -0.01755227, 0.01513442, + 0.00386630, 0.02199463, 1.14439142, 0.21903073, 0.14750213, 0.12743356, 0.08463334, 0.06839691, -1.28367777, 0.35556287, +-0.33809405, 0.13627881, 0.04939309, 0.19642571, 0.05354373, 0.04099247, -0.01787481, 0.01472425, 0.00391474, 0.02150716, + 1.14739079, 0.21840872, 0.14643624, 0.12724347, 0.08390642, 0.06811938, -1.29007667, 0.35159558, -0.34154267, 0.13295849, + 0.04883602, 0.19587595, 0.05452759, 0.04174703, -0.01782110, 0.01388270, 0.00374754, 0.02138105, 1.14333767, 0.21690116, + 0.14544599, 0.12606728, 0.08314168, 0.06771389, -1.29856471, 0.35239315, -0.34238732, 0.13277553, 0.04722712, 0.19233156, + 0.05366901, 0.04328110, -0.01657749, 0.01444736, 0.00438108, 0.02102563, 1.13548397, 0.21537812, 0.14357377, 0.12525845, + 0.08230994, 0.06722511, -1.30663540, 0.34366563, -0.34205544, 0.12861679, 0.04655851, 0.18864359, 0.05351285, 0.04358693, +-0.01604498, 0.01431907, 0.00395326, 0.02082299, 1.12207794, 0.21167325, 0.14212491, 0.12418671, 0.08155467, 0.06639789, +-1.31011673, 0.33686271, -0.34379843, 0.12169569, 0.04480323, 0.18637557, 0.05374078, 0.04260827, -0.01588226, 0.01378294, + 0.00396009, 0.02112406, 1.10466984, 0.20905894, 0.14107033, 0.12303074, 0.08047136, 0.06588031}}; + diff --git a/libs/miniwebrtc/audio/coding_isac/main/lpc_tables.h b/libs/miniwebrtc/audio/coding_isac/main/lpc_tables.h new file mode 100644 index 00000000..604d963c --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/lpc_tables.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * lpc_tables.h + * + * header file for coding tables for the LPC coefficients + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_TABLES_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_TABLES_H_ + +#include "structs.h" + +#include "settings.h" + +#define KLT_STEPSIZE 1.00000000 +#define KLT_NUM_AVG_GAIN 0 +#define KLT_NUM_AVG_SHAPE 0 +#define KLT_NUM_MODELS 3 +#define LPC_GAIN_SCALE 4.000f +#define LPC_LOBAND_SCALE 2.100f +#define LPC_LOBAND_ORDER ORDERLO +#define LPC_HIBAND_SCALE 0.450f +#define LPC_HIBAND_ORDER ORDERHI +#define LPC_GAIN_ORDER 2 + +#define LPC_SHAPE_ORDER (LPC_LOBAND_ORDER + LPC_HIBAND_ORDER) + +#define KLT_ORDER_GAIN (LPC_GAIN_ORDER * SUBFRAMES) +#define KLT_ORDER_SHAPE (LPC_SHAPE_ORDER * SUBFRAMES) +/* indices of KLT coefficients used */ +extern const WebRtc_UWord16 WebRtcIsac_kQKltSelIndGain[12]; + +extern const WebRtc_UWord16 WebRtcIsac_kQKltSelIndShape[108]; + +/* cdf array for model indicator */ +extern const WebRtc_UWord16 WebRtcIsac_kQKltModelCdf[KLT_NUM_MODELS+1]; + +/* pointer to cdf array for model indicator */ +extern const WebRtc_UWord16 *WebRtcIsac_kQKltModelCdfPtr[1]; + +/* initial cdf index for decoder of model indicator */ +extern const WebRtc_UWord16 WebRtcIsac_kQKltModelInitIndex[1]; + +/* offset to go from rounded value to quantization index */ +extern const short WebRtcIsac_kQKltQuantMinGain[12]; + +extern const short WebRtcIsac_kQKltQuantMinShape[108]; + +/* maximum quantization index */ +extern const WebRtc_UWord16 WebRtcIsac_kQKltMaxIndGain[12]; + +extern const WebRtc_UWord16 WebRtcIsac_kQKltMaxIndShape[108]; + +/* index offset */ +extern const WebRtc_UWord16 WebRtcIsac_kQKltOffsetGain[KLT_NUM_MODELS][12]; + +extern const WebRtc_UWord16 WebRtcIsac_kQKltOffsetShape[KLT_NUM_MODELS][108]; + +/* initial cdf index for KLT coefficients */ +extern const WebRtc_UWord16 WebRtcIsac_kQKltInitIndexGain[KLT_NUM_MODELS][12]; + +extern const WebRtc_UWord16 WebRtcIsac_kQKltInitIndexShape[KLT_NUM_MODELS][108]; + +/* offsets for quantizer representation levels */ +extern const WebRtc_UWord16 WebRtcIsac_kQKltOfLevelsGain[3]; + +extern const WebRtc_UWord16 WebRtcIsac_kQKltOfLevelsShape[3]; + +/* quantizer representation levels */ +extern const double WebRtcIsac_kQKltLevelsGain[1176]; + +extern const double WebRtcIsac_kQKltLevelsShape[1735]; + +/* cdf tables for quantizer indices */ +extern const WebRtc_UWord16 WebRtcIsac_kQKltCdfGain[1212]; + +extern const WebRtc_UWord16 WebRtcIsac_kQKltCdfShape[2059]; + +/* pointers to cdf tables for quantizer indices */ +extern const WebRtc_UWord16 *WebRtcIsac_kQKltCdfPtrGain[KLT_NUM_MODELS][12]; + +extern const WebRtc_UWord16 *WebRtcIsac_kQKltCdfPtrShape[KLT_NUM_MODELS][108]; + +/* code length for all coefficients using different models */ +extern const double WebRtcIsac_kQKltCodeLenGain[392]; + +extern const double WebRtcIsac_kQKltCodeLenShape[578]; + +/* left KLT transforms */ +extern const double WebRtcIsac_kKltT1Gain[KLT_NUM_MODELS][4]; + +extern const double WebRtcIsac_kKltT1Shape[KLT_NUM_MODELS][324]; + +/* right KLT transforms */ +extern const double WebRtcIsac_kKltT2Gain[KLT_NUM_MODELS][36]; + +extern const double WebRtcIsac_kKltT2Shape[KLT_NUM_MODELS][36]; + +/* means of log gains and LAR coefficients */ +extern const double WebRtcIsac_kLpcMeansGain[KLT_NUM_MODELS][12]; + +extern const double WebRtcIsac_kLpcMeansShape[KLT_NUM_MODELS][108]; + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_LPC_TABLES_H_ */ diff --git a/libs/miniwebrtc/audio/coding_isac/main/os_specific_inline.h b/libs/miniwebrtc/audio/coding_isac/main/os_specific_inline.h new file mode 100644 index 00000000..c469c2ec --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/os_specific_inline.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_OS_SPECIFIC_INLINE_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_OS_SPECIFIC_INLINE_H_ + +#include +#include "typedefs.h" + +// TODO(turaj): switch to WEBRTC_POSIX when available +#if defined(WEBRTC_LINUX) || defined(WEBRTC_MAC) +#define WebRtcIsac_lrint lrint +#elif (defined(WEBRTC_ARCH_X86) && defined(WIN32)) +static __inline long int WebRtcIsac_lrint(double x_dbl) { + long int x_int; + + __asm { + fld x_dbl + fistp x_int + }; + + return x_int; +} +#else // Do a slow but correct implementation of lrint + +static __inline long int WebRtcIsac_lrint(double x_dbl) { + long int x_int; + x_int = (long int)floor(x_dbl + 0.499999999999); + return x_int; +} + +#endif + +#endif // WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_OS_SPECIFIC_INLINE_H_ diff --git a/libs/miniwebrtc/audio/coding_isac/main/pitch_estimator.c b/libs/miniwebrtc/audio/coding_isac/main/pitch_estimator.c new file mode 100644 index 00000000..75525f69 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/pitch_estimator.c @@ -0,0 +1,622 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "pitch_estimator.h" + +#include +#include +#ifdef WEBRTC_ANDROID +#include +#endif + +static const double kInterpolWin[8] = {-0.00067556028640, 0.02184247643159, -0.12203175715679, 0.60086484101160, + 0.60086484101160, -0.12203175715679, 0.02184247643159, -0.00067556028640}; + +/* interpolation filter */ +__inline static void IntrepolFilter(double *data_ptr, double *intrp) +{ + *intrp = kInterpolWin[0] * data_ptr[-3]; + *intrp += kInterpolWin[1] * data_ptr[-2]; + *intrp += kInterpolWin[2] * data_ptr[-1]; + *intrp += kInterpolWin[3] * data_ptr[0]; + *intrp += kInterpolWin[4] * data_ptr[1]; + *intrp += kInterpolWin[5] * data_ptr[2]; + *intrp += kInterpolWin[6] * data_ptr[3]; + *intrp += kInterpolWin[7] * data_ptr[4]; +} + + +/* 2D parabolic interpolation */ +/* probably some 0.5 factors can be eliminated, and the square-roots can be removed from the Cholesky fact. */ +__inline static void Intrpol2D(double T[3][3], double *x, double *y, double *peak_val) +{ + double c, b[2], A[2][2]; + double t1, t2, d; + double delta1, delta2; + + + // double T[3][3] = {{-1.25, -.25,-.25}, {-.25, .75, .75}, {-.25, .75, .75}}; + // should result in: delta1 = 0.5; delta2 = 0.0; peak_val = 1.0 + + c = T[1][1]; + b[0] = 0.5 * (T[1][2] + T[2][1] - T[0][1] - T[1][0]); + b[1] = 0.5 * (T[1][0] + T[2][1] - T[0][1] - T[1][2]); + A[0][1] = -0.5 * (T[0][1] + T[2][1] - T[1][0] - T[1][2]); + t1 = 0.5 * (T[0][0] + T[2][2]) - c; + t2 = 0.5 * (T[2][0] + T[0][2]) - c; + d = (T[0][1] + T[1][2] + T[1][0] + T[2][1]) - 4.0 * c - t1 - t2; + A[0][0] = -t1 - 0.5 * d; + A[1][1] = -t2 - 0.5 * d; + + /* deal with singularities or ill-conditioned cases */ + if ( (A[0][0] < 1e-7) || ((A[0][0] * A[1][1] - A[0][1] * A[0][1]) < 1e-7) ) { + *peak_val = T[1][1]; + return; + } + + /* Cholesky decomposition: replace A by upper-triangular factor */ + A[0][0] = sqrt(A[0][0]); + A[0][1] = A[0][1] / A[0][0]; + A[1][1] = sqrt(A[1][1] - A[0][1] * A[0][1]); + + /* compute [x; y] = -0.5 * inv(A) * b */ + t1 = b[0] / A[0][0]; + t2 = (b[1] - t1 * A[0][1]) / A[1][1]; + delta2 = t2 / A[1][1]; + delta1 = 0.5 * (t1 - delta2 * A[0][1]) / A[0][0]; + delta2 *= 0.5; + + /* limit norm */ + t1 = delta1 * delta1 + delta2 * delta2; + if (t1 > 1.0) { + delta1 /= t1; + delta2 /= t1; + } + + *peak_val = 0.5 * (b[0] * delta1 + b[1] * delta2) + c; + + *x += delta1; + *y += delta2; +} + + +static void PCorr(const double *in, double *outcorr) +{ + double sum, ysum, prod; + const double *x, *inptr; + int k, n; + + //ysum = 1e-6; /* use this with float (i.s.o. double)! */ + ysum = 1e-13; + sum = 0.0; + x = in + PITCH_MAX_LAG/2 + 2; + for (n = 0; n < PITCH_CORR_LEN2; n++) { + ysum += in[n] * in[n]; + sum += x[n] * in[n]; + } + + outcorr += PITCH_LAG_SPAN2 - 1; /* index of last element in array */ + *outcorr = sum / sqrt(ysum); + + for (k = 1; k < PITCH_LAG_SPAN2; k++) { + ysum -= in[k-1] * in[k-1]; + ysum += in[PITCH_CORR_LEN2 + k - 1] * in[PITCH_CORR_LEN2 + k - 1]; + sum = 0.0; + inptr = &in[k]; + prod = x[0] * inptr[0]; + for (n = 1; n < PITCH_CORR_LEN2; n++) { + sum += prod; + prod = x[n] * inptr[n]; + } + sum += prod; + outcorr--; + *outcorr = sum / sqrt(ysum); + } +} + + +void WebRtcIsac_InitializePitch(const double *in, + const double old_lag, + const double old_gain, + PitchAnalysisStruct *State, + double *lags) +{ + double buf_dec[PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2+2]; + double ratio, log_lag, gain_bias; + double bias; + double corrvec1[PITCH_LAG_SPAN2]; + double corrvec2[PITCH_LAG_SPAN2]; + int m, k; + // Allocating 10 extra entries at the begining of the CorrSurf + double corrSurfBuff[10 + (2*PITCH_BW+3)*(PITCH_LAG_SPAN2+4)]; + double* CorrSurf[2*PITCH_BW+3]; + double *CorrSurfPtr1, *CorrSurfPtr2; + double LagWin[3] = {0.2, 0.5, 0.98}; + int ind1, ind2, peaks_ind, peak, max_ind; + int peaks[PITCH_MAX_NUM_PEAKS]; + double adj, gain_tmp; + double corr, corr_max; + double intrp_a, intrp_b, intrp_c, intrp_d; + double peak_vals[PITCH_MAX_NUM_PEAKS]; + double lags1[PITCH_MAX_NUM_PEAKS]; + double lags2[PITCH_MAX_NUM_PEAKS]; + double T[3][3]; + int row; + + for(k = 0; k < 2*PITCH_BW+3; k++) + { + CorrSurf[k] = &corrSurfBuff[10 + k * (PITCH_LAG_SPAN2+4)]; + } + /* reset CorrSurf matrix */ + memset(corrSurfBuff, 0, sizeof(double) * (10 + (2*PITCH_BW+3) * (PITCH_LAG_SPAN2+4))); + + //warnings -DH + max_ind = 0; + peak = 0; + + /* copy old values from state buffer */ + memcpy(buf_dec, State->dec_buffer, sizeof(double) * (PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2)); + + /* decimation; put result after the old values */ + WebRtcIsac_DecimateAllpass(in, State->decimator_state, PITCH_FRAME_LEN, + &buf_dec[PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2]); + + /* low-pass filtering */ + for (k = PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2; k < PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2+2; k++) + buf_dec[k] += 0.75 * buf_dec[k-1] - 0.25 * buf_dec[k-2]; + + /* copy end part back into state buffer */ + memcpy(State->dec_buffer, buf_dec+PITCH_FRAME_LEN/2, sizeof(double) * (PITCH_CORR_LEN2+PITCH_CORR_STEP2+PITCH_MAX_LAG/2-PITCH_FRAME_LEN/2+2)); + + /* compute correlation for first and second half of the frame */ + PCorr(buf_dec, corrvec1); + PCorr(buf_dec + PITCH_CORR_STEP2, corrvec2); + + /* bias towards pitch lag of previous frame */ + log_lag = log(0.5 * old_lag); + gain_bias = 4.0 * old_gain * old_gain; + if (gain_bias > 0.8) gain_bias = 0.8; + for (k = 0; k < PITCH_LAG_SPAN2; k++) + { + ratio = log((double) (k + (PITCH_MIN_LAG/2-2))) - log_lag; + bias = 1.0 + gain_bias * exp(-5.0 * ratio * ratio); + corrvec1[k] *= bias; + } + + /* taper correlation functions */ + for (k = 0; k < 3; k++) { + gain_tmp = LagWin[k]; + corrvec1[k] *= gain_tmp; + corrvec2[k] *= gain_tmp; + corrvec1[PITCH_LAG_SPAN2-1-k] *= gain_tmp; + corrvec2[PITCH_LAG_SPAN2-1-k] *= gain_tmp; + } + + corr_max = 0.0; + /* fill middle row of correlation surface */ + ind1 = 0; + ind2 = 0; + CorrSurfPtr1 = &CorrSurf[PITCH_BW][2]; + for (k = 0; k < PITCH_LAG_SPAN2; k++) { + corr = corrvec1[ind1++] + corrvec2[ind2++]; + CorrSurfPtr1[k] = corr; + if (corr > corr_max) { + corr_max = corr; /* update maximum */ + max_ind = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]); + } + } + /* fill first and last rows of correlation surface */ + ind1 = 0; + ind2 = PITCH_BW; + CorrSurfPtr1 = &CorrSurf[0][2]; + CorrSurfPtr2 = &CorrSurf[2*PITCH_BW][PITCH_BW+2]; + for (k = 0; k < PITCH_LAG_SPAN2-PITCH_BW; k++) { + ratio = ((double) (ind1 + 12)) / ((double) (ind2 + 12)); + adj = 0.2 * ratio * (2.0 - ratio); /* adjustment factor; inverse parabola as a function of ratio */ + corr = adj * (corrvec1[ind1] + corrvec2[ind2]); + CorrSurfPtr1[k] = corr; + if (corr > corr_max) { + corr_max = corr; /* update maximum */ + max_ind = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]); + } + corr = adj * (corrvec1[ind2++] + corrvec2[ind1++]); + CorrSurfPtr2[k] = corr; + if (corr > corr_max) { + corr_max = corr; /* update maximum */ + max_ind = (int)(&CorrSurfPtr2[k] - &CorrSurf[0][0]); + } + } + /* fill second and next to last rows of correlation surface */ + ind1 = 0; + ind2 = PITCH_BW-1; + CorrSurfPtr1 = &CorrSurf[1][2]; + CorrSurfPtr2 = &CorrSurf[2*PITCH_BW-1][PITCH_BW+1]; + for (k = 0; k < PITCH_LAG_SPAN2-PITCH_BW+1; k++) { + ratio = ((double) (ind1 + 12)) / ((double) (ind2 + 12)); + adj = 0.9 * ratio * (2.0 - ratio); /* adjustment factor; inverse parabola as a function of ratio */ + corr = adj * (corrvec1[ind1] + corrvec2[ind2]); + CorrSurfPtr1[k] = corr; + if (corr > corr_max) { + corr_max = corr; /* update maximum */ + max_ind = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]); + } + corr = adj * (corrvec1[ind2++] + corrvec2[ind1++]); + CorrSurfPtr2[k] = corr; + if (corr > corr_max) { + corr_max = corr; /* update maximum */ + max_ind = (int)(&CorrSurfPtr2[k] - &CorrSurf[0][0]); + } + } + /* fill remainder of correlation surface */ + for (m = 2; m < PITCH_BW; m++) { + ind1 = 0; + ind2 = PITCH_BW - m; /* always larger than ind1 */ + CorrSurfPtr1 = &CorrSurf[m][2]; + CorrSurfPtr2 = &CorrSurf[2*PITCH_BW-m][PITCH_BW+2-m]; + for (k = 0; k < PITCH_LAG_SPAN2-PITCH_BW+m; k++) { + ratio = ((double) (ind1 + 12)) / ((double) (ind2 + 12)); + adj = ratio * (2.0 - ratio); /* adjustment factor; inverse parabola as a function of ratio */ + corr = adj * (corrvec1[ind1] + corrvec2[ind2]); + CorrSurfPtr1[k] = corr; + if (corr > corr_max) { + corr_max = corr; /* update maximum */ + max_ind = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]); + } + corr = adj * (corrvec1[ind2++] + corrvec2[ind1++]); + CorrSurfPtr2[k] = corr; + if (corr > corr_max) { + corr_max = corr; /* update maximum */ + max_ind = (int)(&CorrSurfPtr2[k] - &CorrSurf[0][0]); + } + } + } + + /* threshold value to qualify as a peak */ + corr_max *= 0.6; + + peaks_ind = 0; + /* find peaks */ + for (m = 1; m < PITCH_BW+1; m++) { + if (peaks_ind == PITCH_MAX_NUM_PEAKS) break; + CorrSurfPtr1 = &CorrSurf[m][2]; + for (k = 2; k < PITCH_LAG_SPAN2-PITCH_BW-2+m; k++) { + corr = CorrSurfPtr1[k]; + if (corr > corr_max) { + if ( (corr > CorrSurfPtr1[k - (PITCH_LAG_SPAN2+5)]) && (corr > CorrSurfPtr1[k - (PITCH_LAG_SPAN2+4)]) ) { + if ( (corr > CorrSurfPtr1[k + (PITCH_LAG_SPAN2+4)]) && (corr > CorrSurfPtr1[k + (PITCH_LAG_SPAN2+5)]) ) { + /* found a peak; store index into matrix */ + peaks[peaks_ind++] = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]); + if (peaks_ind == PITCH_MAX_NUM_PEAKS) break; + } + } + } + } + } + for (m = PITCH_BW+1; m < 2*PITCH_BW; m++) { + if (peaks_ind == PITCH_MAX_NUM_PEAKS) break; + CorrSurfPtr1 = &CorrSurf[m][2]; + for (k = 2+m-PITCH_BW; k < PITCH_LAG_SPAN2-2; k++) { + corr = CorrSurfPtr1[k]; + if (corr > corr_max) { + if ( (corr > CorrSurfPtr1[k - (PITCH_LAG_SPAN2+5)]) && (corr > CorrSurfPtr1[k - (PITCH_LAG_SPAN2+4)]) ) { + if ( (corr > CorrSurfPtr1[k + (PITCH_LAG_SPAN2+4)]) && (corr > CorrSurfPtr1[k + (PITCH_LAG_SPAN2+5)]) ) { + /* found a peak; store index into matrix */ + peaks[peaks_ind++] = (int)(&CorrSurfPtr1[k] - &CorrSurf[0][0]); + if (peaks_ind == PITCH_MAX_NUM_PEAKS) break; + } + } + } + } + } + + if (peaks_ind > 0) { + /* examine each peak */ + CorrSurfPtr1 = &CorrSurf[0][0]; + for (k = 0; k < peaks_ind; k++) { + peak = peaks[k]; + + /* compute four interpolated values around current peak */ + IntrepolFilter(&CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+5)], &intrp_a); + IntrepolFilter(&CorrSurfPtr1[peak - 1 ], &intrp_b); + IntrepolFilter(&CorrSurfPtr1[peak ], &intrp_c); + IntrepolFilter(&CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+4)], &intrp_d); + + /* determine maximum of the interpolated values */ + corr = CorrSurfPtr1[peak]; + corr_max = intrp_a; + if (intrp_b > corr_max) corr_max = intrp_b; + if (intrp_c > corr_max) corr_max = intrp_c; + if (intrp_d > corr_max) corr_max = intrp_d; + + /* determine where the peak sits and fill a 3x3 matrix around it */ + row = peak / (PITCH_LAG_SPAN2+4); + lags1[k] = (double) ((peak - row * (PITCH_LAG_SPAN2+4)) + PITCH_MIN_LAG/2 - 4); + lags2[k] = (double) (lags1[k] + PITCH_BW - row); + if ( corr > corr_max ) { + T[0][0] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+5)]; + T[2][0] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+4)]; + T[1][1] = corr; + T[0][2] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+4)]; + T[2][2] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+5)]; + T[1][0] = intrp_a; + T[0][1] = intrp_b; + T[2][1] = intrp_c; + T[1][2] = intrp_d; + } else { + if (intrp_a == corr_max) { + lags1[k] -= 0.5; + lags2[k] += 0.5; + IntrepolFilter(&CorrSurfPtr1[peak - 2*(PITCH_LAG_SPAN2+5)], &T[0][0]); + IntrepolFilter(&CorrSurfPtr1[peak - (2*PITCH_LAG_SPAN2+9)], &T[2][0]); + T[1][1] = intrp_a; + T[0][2] = intrp_b; + T[2][2] = intrp_c; + T[1][0] = CorrSurfPtr1[peak - (2*PITCH_LAG_SPAN2+9)]; + T[0][1] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+5)]; + T[2][1] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+4)]; + T[1][2] = corr; + } else if (intrp_b == corr_max) { + lags1[k] -= 0.5; + lags2[k] -= 0.5; + IntrepolFilter(&CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+6)], &T[0][0]); + T[2][0] = intrp_a; + T[1][1] = intrp_b; + IntrepolFilter(&CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+3)], &T[0][2]); + T[2][2] = intrp_d; + T[1][0] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+5)]; + T[0][1] = CorrSurfPtr1[peak - 1]; + T[2][1] = corr; + T[1][2] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+4)]; + } else if (intrp_c == corr_max) { + lags1[k] += 0.5; + lags2[k] += 0.5; + T[0][0] = intrp_a; + IntrepolFilter(&CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+4)], &T[2][0]); + T[1][1] = intrp_c; + T[0][2] = intrp_d; + IntrepolFilter(&CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+5)], &T[2][2]); + T[1][0] = CorrSurfPtr1[peak - (PITCH_LAG_SPAN2+4)]; + T[0][1] = corr; + T[2][1] = CorrSurfPtr1[peak + 1]; + T[1][2] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+5)]; + } else { + lags1[k] += 0.5; + lags2[k] -= 0.5; + T[0][0] = intrp_b; + T[2][0] = intrp_c; + T[1][1] = intrp_d; + IntrepolFilter(&CorrSurfPtr1[peak + 2*(PITCH_LAG_SPAN2+4)], &T[0][2]); + IntrepolFilter(&CorrSurfPtr1[peak + (2*PITCH_LAG_SPAN2+9)], &T[2][2]); + T[1][0] = corr; + T[0][1] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+4)]; + T[2][1] = CorrSurfPtr1[peak + (PITCH_LAG_SPAN2+5)]; + T[1][2] = CorrSurfPtr1[peak + (2*PITCH_LAG_SPAN2+9)]; + } + } + + /* 2D parabolic interpolation gives more accurate lags and peak value */ + Intrpol2D(T, &lags1[k], &lags2[k], &peak_vals[k]); + } + + /* determine the highest peak, after applying a bias towards short lags */ + corr_max = 0.0; + for (k = 0; k < peaks_ind; k++) { + corr = peak_vals[k] * pow(PITCH_PEAK_DECAY, log(lags1[k] + lags2[k])); + if (corr > corr_max) { + corr_max = corr; + peak = k; + } + } + + lags1[peak] *= 2.0; + lags2[peak] *= 2.0; + + if (lags1[peak] < (double) PITCH_MIN_LAG) lags1[peak] = (double) PITCH_MIN_LAG; + if (lags2[peak] < (double) PITCH_MIN_LAG) lags2[peak] = (double) PITCH_MIN_LAG; + if (lags1[peak] > (double) PITCH_MAX_LAG) lags1[peak] = (double) PITCH_MAX_LAG; + if (lags2[peak] > (double) PITCH_MAX_LAG) lags2[peak] = (double) PITCH_MAX_LAG; + + /* store lags of highest peak in output array */ + lags[0] = lags1[peak]; + lags[1] = lags1[peak]; + lags[2] = lags2[peak]; + lags[3] = lags2[peak]; + } + else + { + row = max_ind / (PITCH_LAG_SPAN2+4); + lags1[0] = (double) ((max_ind - row * (PITCH_LAG_SPAN2+4)) + PITCH_MIN_LAG/2 - 4); + lags2[0] = (double) (lags1[0] + PITCH_BW - row); + + if (lags1[0] < (double) PITCH_MIN_LAG) lags1[0] = (double) PITCH_MIN_LAG; + if (lags2[0] < (double) PITCH_MIN_LAG) lags2[0] = (double) PITCH_MIN_LAG; + if (lags1[0] > (double) PITCH_MAX_LAG) lags1[0] = (double) PITCH_MAX_LAG; + if (lags2[0] > (double) PITCH_MAX_LAG) lags2[0] = (double) PITCH_MAX_LAG; + + /* store lags of highest peak in output array */ + lags[0] = lags1[0]; + lags[1] = lags1[0]; + lags[2] = lags2[0]; + lags[3] = lags2[0]; + } +} + + + +/* create weighting matrix by orthogonalizing a basis of polynomials of increasing order + * t = (0:4)'; + * A = [t.^0, t.^1, t.^2, t.^3, t.^4]; + * [Q, dummy] = qr(A); + * P.Weight = Q * diag([0, .1, .5, 1, 1]) * Q'; */ +static const double kWeight[5][5] = { + { 0.29714285714286, -0.30857142857143, -0.05714285714286, 0.05142857142857, 0.01714285714286}, + {-0.30857142857143, 0.67428571428571, -0.27142857142857, -0.14571428571429, 0.05142857142857}, + {-0.05714285714286, -0.27142857142857, 0.65714285714286, -0.27142857142857, -0.05714285714286}, + { 0.05142857142857, -0.14571428571429, -0.27142857142857, 0.67428571428571, -0.30857142857143}, + { 0.01714285714286, 0.05142857142857, -0.05714285714286, -0.30857142857143, 0.29714285714286} +}; + + +void WebRtcIsac_PitchAnalysis(const double *in, /* PITCH_FRAME_LEN samples */ + double *out, /* PITCH_FRAME_LEN+QLOOKAHEAD samples */ + PitchAnalysisStruct *State, + double *lags, + double *gains) +{ + double HPin[PITCH_FRAME_LEN]; + double Weighted[PITCH_FRAME_LEN]; + double Whitened[PITCH_FRAME_LEN + QLOOKAHEAD]; + double inbuf[PITCH_FRAME_LEN + QLOOKAHEAD]; + double out_G[PITCH_FRAME_LEN + QLOOKAHEAD]; // could be removed by using out instead + double out_dG[4][PITCH_FRAME_LEN + QLOOKAHEAD]; + double old_lag, old_gain; + double nrg_wht, tmp; + double Wnrg, Wfluct, Wgain; + double H[4][4]; + double grad[4]; + double dG[4]; + int k, m, n, iter; + + /* high pass filtering using second order pole-zero filter */ + WebRtcIsac_Highpass(in, HPin, State->hp_state, PITCH_FRAME_LEN); + + /* copy from state into buffer */ + memcpy(Whitened, State->whitened_buf, sizeof(double) * QLOOKAHEAD); + + /* compute weighted and whitened signals */ + WebRtcIsac_WeightingFilter(HPin, &Weighted[0], &Whitened[QLOOKAHEAD], &(State->Wghtstr)); + + /* copy from buffer into state */ + memcpy(State->whitened_buf, Whitened+PITCH_FRAME_LEN, sizeof(double) * QLOOKAHEAD); + + old_lag = State->PFstr_wght.oldlagp[0]; + old_gain = State->PFstr_wght.oldgainp[0]; + + /* inital pitch estimate */ + WebRtcIsac_InitializePitch(Weighted, old_lag, old_gain, State, lags); + + + /* Iterative optimization of lags - to be done */ + + /* compute energy of whitened signal */ + nrg_wht = 0.0; + for (k = 0; k < PITCH_FRAME_LEN + QLOOKAHEAD; k++) + nrg_wht += Whitened[k] * Whitened[k]; + + + /* Iterative optimization of gains */ + + /* set weights for energy, gain fluctiation, and spectral gain penalty functions */ + Wnrg = 1.0 / nrg_wht; + Wgain = 0.005; + Wfluct = 3.0; + + /* set initial gains */ + for (k = 0; k < 4; k++) + gains[k] = PITCH_MAX_GAIN_06; + + /* two iterations should be enough */ + for (iter = 0; iter < 2; iter++) { + /* compute Jacobian of pre-filter output towards gains */ + WebRtcIsac_PitchfilterPre_gains(Whitened, out_G, out_dG, &(State->PFstr_wght), lags, gains); + + /* gradient and approximate Hessian (lower triangle) for minimizing the filter's output power */ + for (k = 0; k < 4; k++) { + tmp = 0.0; + for (n = 0; n < PITCH_FRAME_LEN + QLOOKAHEAD; n++) + tmp += out_G[n] * out_dG[k][n]; + grad[k] = tmp * Wnrg; + } + for (k = 0; k < 4; k++) { + for (m = 0; m <= k; m++) { + tmp = 0.0; + for (n = 0; n < PITCH_FRAME_LEN + QLOOKAHEAD; n++) + tmp += out_dG[m][n] * out_dG[k][n]; + H[k][m] = tmp * Wnrg; + } + } + + /* add gradient and Hessian (lower triangle) for dampening fast gain changes */ + for (k = 0; k < 4; k++) { + tmp = kWeight[k+1][0] * old_gain; + for (m = 0; m < 4; m++) + tmp += kWeight[k+1][m+1] * gains[m]; + grad[k] += tmp * Wfluct; + } + for (k = 0; k < 4; k++) { + for (m = 0; m <= k; m++) { + H[k][m] += kWeight[k+1][m+1] * Wfluct; + } + } + + /* add gradient and Hessian for dampening gain */ + for (k = 0; k < 3; k++) { + tmp = 1.0 / (1 - gains[k]); + grad[k] += tmp * tmp * Wgain; + H[k][k] += 2.0 * tmp * (tmp * tmp * Wgain); + } + tmp = 1.0 / (1 - gains[3]); + grad[3] += 1.33 * (tmp * tmp * Wgain); + H[3][3] += 2.66 * tmp * (tmp * tmp * Wgain); + + + /* compute Cholesky factorization of Hessian + * by overwritting the upper triangle; scale factors on diagonal + * (for non pc-platforms store the inverse of the diagonals seperately to minimize divisions) */ + H[0][1] = H[1][0] / H[0][0]; + H[0][2] = H[2][0] / H[0][0]; + H[0][3] = H[3][0] / H[0][0]; + H[1][1] -= H[0][0] * H[0][1] * H[0][1]; + H[1][2] = (H[2][1] - H[0][1] * H[2][0]) / H[1][1]; + H[1][3] = (H[3][1] - H[0][1] * H[3][0]) / H[1][1]; + H[2][2] -= H[0][0] * H[0][2] * H[0][2] + H[1][1] * H[1][2] * H[1][2]; + H[2][3] = (H[3][2] - H[0][2] * H[3][0] - H[1][2] * H[1][1] * H[1][3]) / H[2][2]; + H[3][3] -= H[0][0] * H[0][3] * H[0][3] + H[1][1] * H[1][3] * H[1][3] + H[2][2] * H[2][3] * H[2][3]; + + /* Compute update as delta_gains = -inv(H) * grad */ + /* copy and negate */ + for (k = 0; k < 4; k++) + dG[k] = -grad[k]; + /* back substitution */ + dG[1] -= dG[0] * H[0][1]; + dG[2] -= dG[0] * H[0][2] + dG[1] * H[1][2]; + dG[3] -= dG[0] * H[0][3] + dG[1] * H[1][3] + dG[2] * H[2][3]; + /* scale */ + for (k = 0; k < 4; k++) + dG[k] /= H[k][k]; + /* back substitution */ + dG[2] -= dG[3] * H[2][3]; + dG[1] -= dG[3] * H[1][3] + dG[2] * H[1][2]; + dG[0] -= dG[3] * H[0][3] + dG[2] * H[0][2] + dG[1] * H[0][1]; + + /* update gains and check range */ + for (k = 0; k < 4; k++) { + gains[k] += dG[k]; + if (gains[k] > PITCH_MAX_GAIN) + gains[k] = PITCH_MAX_GAIN; + else if (gains[k] < 0.0) + gains[k] = 0.0; + } + } + + /* update state for next frame */ + WebRtcIsac_PitchfilterPre(Whitened, out, &(State->PFstr_wght), lags, gains); + + /* concatenate previous input's end and current input */ + memcpy(inbuf, State->inbuf, sizeof(double) * QLOOKAHEAD); + memcpy(inbuf+QLOOKAHEAD, in, sizeof(double) * PITCH_FRAME_LEN); + + /* lookahead pitch filtering for masking analysis */ + WebRtcIsac_PitchfilterPre_la(inbuf, out, &(State->PFstr), lags, gains); + + /* store last part of input */ + for (k = 0; k < QLOOKAHEAD; k++) + State->inbuf[k] = inbuf[k + PITCH_FRAME_LEN]; +} diff --git a/libs/miniwebrtc/audio/coding_isac/main/pitch_estimator.h b/libs/miniwebrtc/audio/coding_isac/main/pitch_estimator.h new file mode 100644 index 00000000..f5d93564 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/pitch_estimator.h @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * pitch_estimator.h + * + * Pitch functions + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_ + +#include "structs.h" + + + +void WebRtcIsac_PitchAnalysis(const double *in, /* PITCH_FRAME_LEN samples */ + double *out, /* PITCH_FRAME_LEN+QLOOKAHEAD samples */ + PitchAnalysisStruct *State, + double *lags, + double *gains); + +void WebRtcIsac_InitializePitch(const double *in, + const double old_lag, + const double old_gain, + PitchAnalysisStruct *State, + double *lags); + +void WebRtcIsac_PitchfilterPre(double *indat, + double *outdat, + PitchFiltstr *pfp, + double *lags, + double *gains); + +void WebRtcIsac_PitchfilterPost(double *indat, + double *outdat, + PitchFiltstr *pfp, + double *lags, + double *gains); + +void WebRtcIsac_PitchfilterPre_la(double *indat, + double *outdat, + PitchFiltstr *pfp, + double *lags, + double *gains); + +void WebRtcIsac_PitchfilterPre_gains(double *indat, + double *outdat, + double out_dG[][PITCH_FRAME_LEN + QLOOKAHEAD], + PitchFiltstr *pfp, + double *lags, + double *gains); + +void WebRtcIsac_WeightingFilter(const double *in, double *weiout, double *whiout, WeightFiltstr *wfdata); + +void WebRtcIsac_Highpass(const double *in, double *out, double *state, int N); + +void WebRtcIsac_DecimateAllpass(const double *in, + double *state_in, /* array of size: 2*ALLPASSSECTIONS+1 */ + int N, /* number of input samples */ + double *out); /* array of size N/2 */ + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_ESTIMATOR_H_ */ diff --git a/libs/miniwebrtc/audio/coding_isac/main/pitch_filter.c b/libs/miniwebrtc/audio/coding_isac/main/pitch_filter.c new file mode 100644 index 00000000..ccc8d214 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/pitch_filter.c @@ -0,0 +1,469 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "pitch_estimator.h" +#include "os_specific_inline.h" + +#include +#include +#include + +static const double kDampFilter[PITCH_DAMPORDER] = {-0.07, 0.25, 0.64, 0.25, -0.07}; + +/* interpolation coefficients; generated by design_pitch_filter.m */ +static const double kIntrpCoef[PITCH_FRACS][PITCH_FRACORDER] = { + {-0.02239172458614, 0.06653315052934, -0.16515880017569, 0.60701333734125, 0.64671399919202, -0.20249000396417, 0.09926548334755, -0.04765933793109, 0.01754159521746}, + {-0.01985640750434, 0.05816126837866, -0.13991265473714, 0.44560418147643, 0.79117042386876, -0.20266133815188, 0.09585268418555, -0.04533310458084, 0.01654127246314}, + {-0.01463300534216, 0.04229888475060, -0.09897034715253, 0.28284326017787, 0.90385267956632, -0.16976950138649, 0.07704272393639, -0.03584218578311, 0.01295781500709}, + {-0.00764851320885, 0.02184035544377, -0.04985561057281, 0.13083306574393, 0.97545011664662, -0.10177807997561, 0.04400901776474, -0.02010737175166, 0.00719783432422}, + {-0.00000000000000, 0.00000000000000, -0.00000000000001, 0.00000000000001, 0.99999999999999, 0.00000000000001, -0.00000000000001, 0.00000000000000, -0.00000000000000}, + { 0.00719783432422, -0.02010737175166, 0.04400901776474, -0.10177807997562, 0.97545011664663, 0.13083306574393, -0.04985561057280, 0.02184035544377, -0.00764851320885}, + { 0.01295781500710, -0.03584218578312, 0.07704272393640, -0.16976950138650, 0.90385267956634, 0.28284326017785, -0.09897034715252, 0.04229888475059, -0.01463300534216}, + { 0.01654127246315, -0.04533310458085, 0.09585268418557, -0.20266133815190, 0.79117042386878, 0.44560418147640, -0.13991265473712, 0.05816126837865, -0.01985640750433} +}; + + +void WebRtcIsac_PitchfilterPre(double *indat, + double *outdat, + PitchFiltstr *pfp, + double *lags, + double *gains) +{ + + double ubuf[PITCH_INTBUFFSIZE]; + const double *fracoeff = NULL; + double curgain, curlag, gaindelta, lagdelta; + double sum, inystate[PITCH_DAMPORDER]; + double ftmp, oldlag, oldgain; + int k, n, m, pos, ind, pos2, Li, frc; + + Li = 0; + /* Set up buffer and states */ + memcpy(ubuf, pfp->ubuf, sizeof(double) * PITCH_BUFFSIZE); + memcpy(inystate, pfp->ystate, sizeof(double) * PITCH_DAMPORDER); + + oldlag = *pfp->oldlagp; + oldgain = *pfp->oldgainp; + + /* No interpolation if pitch lag step is big */ + if ((lags[0] > (PITCH_UPSTEP * oldlag)) || (lags[0] < (PITCH_DOWNSTEP * oldlag))) { + oldlag = lags[0]; + oldgain = gains[0]; + } + + ind=0; + for (k=0;k0;m--) + inystate[m] = inystate[m-1]; + + /* Filter to get fractional pitch */ + pos = ind + PITCH_BUFFSIZE; + pos2 = pos - Li; + sum=0; + for (m=0;mubuf, ubuf+PITCH_FRAME_LEN, sizeof(double) * PITCH_BUFFSIZE); + memcpy(pfp->ystate, inystate, sizeof(double) * PITCH_DAMPORDER); + + *pfp->oldlagp = oldlag; + *pfp->oldgainp = oldgain; + +} + + +void WebRtcIsac_PitchfilterPre_la(double *indat, + double *outdat, + PitchFiltstr *pfp, + double *lags, + double *gains) +{ + double ubuf[PITCH_INTBUFFSIZE+QLOOKAHEAD]; + const double *fracoeff = NULL; + double curgain, curlag, gaindelta, lagdelta; + double sum, inystate[PITCH_DAMPORDER]; + double ftmp; + double oldlag, oldgain; + int k, n, m, pos, ind, pos2, Li, frc; + + Li = 0; + /* Set up buffer and states */ + memcpy(ubuf, pfp->ubuf, sizeof(double) * PITCH_BUFFSIZE); + memcpy(inystate, pfp->ystate, sizeof(double) * PITCH_DAMPORDER); + + oldlag = *pfp->oldlagp; + oldgain = *pfp->oldgainp; + + /* No interpolation if pitch lag step is big */ + if ((lags[0] > (PITCH_UPSTEP * oldlag)) || (lags[0] < (PITCH_DOWNSTEP * oldlag))) { + oldlag = lags[0]; + oldgain = gains[0]; + } + + + ind=0; + for (k=0;k0;m--) + inystate[m] = inystate[m-1]; + + /* Filter to get fractional pitch */ + pos = ind + PITCH_BUFFSIZE; + pos2 = pos - Li; + sum=0.0; + for (m=0;mubuf, ubuf+PITCH_FRAME_LEN, sizeof(double) * PITCH_BUFFSIZE); + memcpy(pfp->ystate, inystate, sizeof(double) * PITCH_DAMPORDER); + + *pfp->oldlagp = oldlag; + *pfp->oldgainp = oldgain; + + + /* Filter look-ahead segment */ + for (n=0;n0;m--) + inystate[m] = inystate[m-1]; + + /* Filter to get fractional pitch */ + pos = ind + PITCH_BUFFSIZE; + pos2 = pos - Li; + sum=0.0; + for (m=0;mubuf, sizeof(double) * PITCH_BUFFSIZE); + memcpy(inystate, pfp->ystate, sizeof(double) * PITCH_DAMPORDER); + + /* clear some buffers */ + for (k = 0; k < 4; k++) { + gain_mult[k] = 0.0; + for (n = 0; n < PITCH_DAMPORDER; n++) + inystate_dG[k][n] = 0.0; + } + + oldlag = *pfp->oldlagp; + oldgain = *pfp->oldgainp; + + /* No interpolation if pitch lag step is big */ + if ((lags[0] > (PITCH_UPSTEP * oldlag)) || (lags[0] < (PITCH_DOWNSTEP * oldlag))) { + oldlag = lags[0]; + oldgain = gains[0]; + gain_mult[0] = 1.0; + } + + + ind=0; + for (k=0;k 1.0) gain_mult[k] = 1.0; + if (k > 0) gain_mult[k-1] -= 0.2; + } + + /* shift low pass filter states */ + for (m=PITCH_DAMPORDER-1;m>0;m--) { + inystate[m] = inystate[m-1]; + for (j = 0; j < 4; j++) + inystate_dG[j][m] = inystate_dG[j][m-1]; + } + + pos = ind + PITCH_BUFFSIZE; + pos2 = pos - Li; + + /* Filter to get fractional pitch */ + sum=0.0; + for (m=0;m 0) ? Li-ind : 0; + for (j = 0; j < k+1; j++) { + /* filter */ + sum2 = 0.0; + for (m = PITCH_FRACORDER-1; m >= m_tmp; m--) + sum2 += out_dG[j][ind-Li + m] * fracoeff[m]; + inystate_dG[j][0] = gain_mult[j] * sum + curgain * sum2; + } + + /* Low pass filter */ + sum=0.0; + for (m=0;m0;m--) { + inystate[m] = inystate[m-1]; + for (j = 0; j < 4; j++) + inystate_dG[j][m] = inystate_dG[j][m-1]; + } + + pos = ind + PITCH_BUFFSIZE; + pos2 = pos - Li; + + /* Filter to get fractional pitch */ + sum=0.0; + for (m=0;m 0) ? Li-ind : 0; + for (j = 0; (j= m_tmp; m--) + sum2 += out_dG[j][ind-Li + m] * fracoeff[m]; + inystate_dG[j][0] = gain_mult[j] * sum + curgain * sum2; + } + + /* Low pass filter */ + sum=0.0; + for (m=0;mubuf, sizeof(double) * PITCH_BUFFSIZE); + memcpy(inystate, pfp->ystate, sizeof(double) * PITCH_DAMPORDER); + + oldlag = *pfp->oldlagp; + oldgain = *pfp->oldgainp; + + /* make output more periodic */ + for (k=0;k (PITCH_UPSTEP * oldlag)) || (lags[0] < (PITCH_DOWNSTEP * oldlag))) { + oldlag = lags[0]; + oldgain = gains[0]; + } + + + ind=0; + for (k=0;k0;m--) + inystate[m] = inystate[m-1]; + + /* Filter to get fractional pitch */ + pos = ind + PITCH_BUFFSIZE; + pos2 = pos - Li; + sum=0.0; + for (m=0;mubuf, ubuf+PITCH_FRAME_LEN, sizeof(double) * PITCH_BUFFSIZE); + memcpy(pfp->ystate, inystate, sizeof(double) * PITCH_DAMPORDER); + + *pfp->oldlagp = oldlag; + *pfp->oldgainp = oldgain; + +} diff --git a/libs/miniwebrtc/audio/coding_isac/main/pitch_gain_tables.c b/libs/miniwebrtc/audio/coding_isac/main/pitch_gain_tables.c new file mode 100644 index 00000000..5d998a29 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/pitch_gain_tables.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "pitch_gain_tables.h" + +#include "settings.h" + +/* header file for coding tables for the pitch filter side-info in the entropy coder */ +/********************* Pitch Filter Gain Coefficient Tables ************************/ +/* cdf for quantized pitch filter gains */ +const WebRtc_UWord16 WebRtcIsac_kQPitchGainCdf[255] = { + 0, 2, 4, 6, 64, 901, 903, 905, 16954, 16956, + 16961, 17360, 17362, 17364, 17366, 17368, 17370, 17372, 17374, 17411, + 17514, 17516, 17583, 18790, 18796, 18802, 20760, 20777, 20782, 21722, + 21724, 21728, 21738, 21740, 21742, 21744, 21746, 21748, 22224, 22227, + 22230, 23214, 23229, 23239, 25086, 25108, 25120, 26088, 26094, 26098, + 26175, 26177, 26179, 26181, 26183, 26185, 26484, 26507, 26522, 27705, + 27731, 27750, 29767, 29799, 29817, 30866, 30883, 30885, 31025, 31029, + 31031, 31033, 31035, 31037, 31114, 31126, 31134, 32687, 32722, 32767, + 35718, 35742, 35757, 36943, 36952, 36954, 37115, 37128, 37130, 37132, + 37134, 37136, 37143, 37145, 37152, 38843, 38863, 38897, 47458, 47467, + 47474, 49040, 49061, 49063, 49145, 49157, 49159, 49161, 49163, 49165, + 49167, 49169, 49171, 49757, 49770, 49782, 61333, 61344, 61346, 62860, + 62883, 62885, 62887, 62889, 62891, 62893, 62895, 62897, 62899, 62901, + 62903, 62905, 62907, 62909, 65496, 65498, 65500, 65521, 65523, 65525, + 65527, 65529, 65531, 65533, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535}; + +/* index limits and ranges */ +const WebRtc_Word16 WebRtcIsac_kIndexLowerLimitGain[3] = { + -7, -2, -1}; + +const WebRtc_Word16 WebRtcIsac_kIndexUpperLimitGain[3] = { + 0, 3, 1}; + +const WebRtc_UWord16 WebRtcIsac_kIndexMultsGain[2] = { + 18, 3}; + +/* size of cdf table */ +const WebRtc_UWord16 WebRtcIsac_kQCdfTableSizeGain[1] = { + 256}; + +///////////////////////////FIXED POINT +/* mean values of pitch filter gains in FIXED point */ +const WebRtc_Word16 WebRtcIsac_kQMeanGain1Q12[144] = { + 843, 1092, 1336, 1222, 1405, 1656, 1500, 1815, 1843, 1838, 1839, 1843, 1843, 1843, 1843, 1843, + 1843, 1843, 814, 846, 1092, 1013, 1174, 1383, 1391, 1511, 1584, 1734, 1753, 1843, 1843, 1843, + 1843, 1843, 1843, 1843, 524, 689, 777, 845, 947, 1069, 1090, 1263, 1380, 1447, 1559, 1676, + 1645, 1749, 1843, 1843, 1843, 1843, 81, 477, 563, 611, 706, 806, 849, 1012, 1192, 1128, + 1330, 1489, 1425, 1576, 1826, 1741, 1843, 1843, 0, 290, 305, 356, 488, 575, 602, 741, + 890, 835, 1079, 1196, 1182, 1376, 1519, 1506, 1680, 1843, 0, 47, 97, 69, 289, 381, + 385, 474, 617, 664, 803, 1079, 935, 1160, 1269, 1265, 1506, 1741, 0, 0, 0, 0, + 112, 120, 190, 283, 442, 343, 526, 809, 684, 935, 1134, 1020, 1265, 1506, 0, 0, + 0, 0, 0, 0, 0, 111, 256, 87, 373, 597, 430, 684, 935, 770, 1020, 1265}; + +const WebRtc_Word16 WebRtcIsac_kQMeanGain2Q12[144] = { + 1760, 1525, 1285, 1747, 1671, 1393, 1843, 1826, 1555, 1843, 1784, 1606, 1843, 1843, 1711, 1843, + 1843, 1814, 1389, 1275, 1040, 1564, 1414, 1252, 1610, 1495, 1343, 1753, 1592, 1405, 1804, 1720, + 1475, 1843, 1814, 1581, 1208, 1061, 856, 1349, 1148, 994, 1390, 1253, 1111, 1495, 1343, 1178, + 1770, 1465, 1234, 1814, 1581, 1342, 1040, 793, 713, 1053, 895, 737, 1128, 1003, 861, 1277, + 1094, 981, 1475, 1192, 1019, 1581, 1342, 1098, 855, 570, 483, 833, 648, 540, 948, 744, + 572, 1009, 844, 636, 1234, 934, 685, 1342, 1217, 984, 537, 318, 124, 603, 423, 350, + 687, 479, 322, 791, 581, 430, 987, 671, 488, 1098, 849, 597, 283, 27, 0, 397, + 222, 38, 513, 271, 124, 624, 325, 157, 737, 484, 233, 849, 597, 343, 27, 0, + 0, 141, 0, 0, 256, 69, 0, 370, 87, 0, 484, 229, 0, 597, 343, 87}; + +const WebRtc_Word16 WebRtcIsac_kQMeanGain3Q12[144] = { + 1843, 1843, 1711, 1843, 1818, 1606, 1843, 1827, 1511, 1814, 1639, 1393, 1760, 1525, 1285, 1656, + 1419, 1176, 1835, 1718, 1475, 1841, 1650, 1387, 1648, 1498, 1287, 1600, 1411, 1176, 1522, 1299, + 1040, 1419, 1176, 928, 1773, 1461, 1128, 1532, 1355, 1202, 1429, 1260, 1115, 1398, 1151, 1025, + 1172, 1080, 790, 1176, 928, 677, 1475, 1147, 1019, 1276, 1096, 922, 1214, 1010, 901, 1057, + 893, 800, 1040, 796, 734, 928, 677, 424, 1137, 897, 753, 1120, 830, 710, 875, 751, + 601, 795, 642, 583, 790, 544, 475, 677, 474, 140, 987, 750, 482, 697, 573, 450, + 691, 487, 303, 661, 394, 332, 537, 303, 220, 424, 168, 0, 737, 484, 229, 624, + 348, 153, 441, 261, 136, 397, 166, 51, 283, 27, 0, 168, 0, 0, 484, 229, + 0, 370, 57, 0, 256, 43, 0, 141, 0, 0, 27, 0, 0, 0, 0, 0}; + + +const WebRtc_Word16 WebRtcIsac_kQMeanGain4Q12[144] = { + 1843, 1843, 1843, 1843, 1841, 1843, 1500, 1821, 1843, 1222, 1434, 1656, 843, 1092, 1336, 504, + 757, 1007, 1843, 1843, 1843, 1838, 1791, 1843, 1265, 1505, 1599, 965, 1219, 1425, 730, 821, + 1092, 249, 504, 757, 1783, 1819, 1843, 1351, 1567, 1727, 1096, 1268, 1409, 805, 961, 1131, + 444, 670, 843, 0, 249, 504, 1425, 1655, 1743, 1096, 1324, 1448, 822, 1019, 1199, 490, + 704, 867, 81, 450, 555, 0, 0, 249, 1247, 1428, 1530, 881, 1073, 1283, 610, 759, + 939, 278, 464, 645, 0, 200, 270, 0, 0, 0, 935, 1163, 1410, 528, 790, 1068, + 377, 499, 717, 173, 240, 274, 0, 43, 62, 0, 0, 0, 684, 935, 1182, 343, + 551, 735, 161, 262, 423, 0, 55, 27, 0, 0, 0, 0, 0, 0, 430, 684, + 935, 87, 377, 597, 0, 46, 256, 0, 0, 0, 0, 0, 0, 0, 0, 0}; diff --git a/libs/miniwebrtc/audio/coding_isac/main/pitch_gain_tables.h b/libs/miniwebrtc/audio/coding_isac/main/pitch_gain_tables.h new file mode 100644 index 00000000..f958f5df --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/pitch_gain_tables.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * pitch_gain_tables.h + * + * This file contains tables for the pitch filter side-info in the entropy coder. + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_GAIN_TABLES_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_GAIN_TABLES_H_ + +#include "typedefs.h" + +/* header file for coding tables for the pitch filter side-info in the entropy coder */ +/********************* Pitch Filter Gain Coefficient Tables ************************/ +/* cdf for quantized pitch filter gains */ +extern const WebRtc_UWord16 WebRtcIsac_kQPitchGainCdf[255]; + +/* index limits and ranges */ +extern const WebRtc_Word16 WebRtcIsac_kIndexLowerLimitGain[3]; + +extern const WebRtc_Word16 WebRtcIsac_kIndexUpperLimitGain[3]; +extern const WebRtc_UWord16 WebRtcIsac_kIndexMultsGain[2]; + +/* mean values of pitch filter gains */ +//(Y) +extern const WebRtc_Word16 WebRtcIsac_kQMeanGain1Q12[144]; +extern const WebRtc_Word16 WebRtcIsac_kQMeanGain2Q12[144]; +extern const WebRtc_Word16 WebRtcIsac_kQMeanGain3Q12[144]; +extern const WebRtc_Word16 WebRtcIsac_kQMeanGain4Q12[144]; +//(Y) + +/* size of cdf table */ +extern const WebRtc_UWord16 WebRtcIsac_kQCdfTableSizeGain[1]; + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_GAIN_TABLES_H_ */ diff --git a/libs/miniwebrtc/audio/coding_isac/main/pitch_lag_tables.c b/libs/miniwebrtc/audio/coding_isac/main/pitch_lag_tables.c new file mode 100644 index 00000000..72a031e2 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/pitch_lag_tables.c @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "pitch_lag_tables.h" +#include "settings.h" + +/* header file for coding tables for the pitch filter side-info in the entropy coder */ +/********************* Pitch Filter Gain Coefficient Tables ************************/ + +/* tables for use with small pitch gain */ + +/* cdf for quantized pitch filter lags */ +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf1Lo[127] = { + 0, 134, 336, 549, 778, 998, 1264, 1512, 1777, 2070, + 2423, 2794, 3051, 3361, 3708, 3979, 4315, 4610, 4933, 5269, + 5575, 5896, 6155, 6480, 6816, 7129, 7477, 7764, 8061, 8358, + 8718, 9020, 9390, 9783, 10177, 10543, 10885, 11342, 11795, 12213, + 12680, 13096, 13524, 13919, 14436, 14903, 15349, 15795, 16267, 16734, + 17266, 17697, 18130, 18632, 19080, 19447, 19884, 20315, 20735, 21288, + 21764, 22264, 22723, 23193, 23680, 24111, 24557, 25022, 25537, 26082, + 26543, 27090, 27620, 28139, 28652, 29149, 29634, 30175, 30692, 31273, + 31866, 32506, 33059, 33650, 34296, 34955, 35629, 36295, 36967, 37726, + 38559, 39458, 40364, 41293, 42256, 43215, 44231, 45253, 46274, 47359, + 48482, 49678, 50810, 51853, 53016, 54148, 55235, 56263, 57282, 58363, + 59288, 60179, 61076, 61806, 62474, 63129, 63656, 64160, 64533, 64856, + 65152, 65535, 65535, 65535, 65535, 65535, 65535}; + +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf2Lo[20] = { + 0, 429, 3558, 5861, 8558, 11639, 15210, 19502, 24773, 31983, + 42602, 48567, 52601, 55676, 58160, 60172, 61889, 63235, 65383, 65535}; + +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf3Lo[2] = { + 0, 65535}; + +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf4Lo[10] = { + 0, 2966, 6368, 11182, 19431, 37793, 48532, 55353, 60626, 65535}; + +const WebRtc_UWord16 *WebRtcIsac_kQPitchLagCdfPtrLo[4] = {WebRtcIsac_kQPitchLagCdf1Lo, WebRtcIsac_kQPitchLagCdf2Lo, WebRtcIsac_kQPitchLagCdf3Lo, WebRtcIsac_kQPitchLagCdf4Lo}; + +/* size of first cdf table */ +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdfSizeLo[1] = {128}; + +/* index limits and ranges */ +const WebRtc_Word16 WebRtcIsac_kQIndexLowerLimitLagLo[4] = { +-140, -9, 0, -4}; + +const WebRtc_Word16 WebRtcIsac_kQIndexUpperLimitLagLo[4] = { +-20, 9, 0, 4}; + +/* initial index for arithmetic decoder */ +const WebRtc_UWord16 WebRtcIsac_kQInitIndexLagLo[3] = { + 10, 1, 5}; + +/* mean values of pitch filter lags */ +const double WebRtcIsac_kQMeanLag2Lo[19] = { +-17.21385070, -15.82678944, -14.07123081, -12.03003877, -10.01311864, -8.00794627, -5.91162987, -3.89231876, -1.90220980, -0.01879275, + 1.89144232, 3.88123171, 5.92146992, 7.96435361, 9.98923648, 11.98266347, 13.96101002, 15.74855713, 17.10976611}; + +const double WebRtcIsac_kQMeanLag3Lo[1] = { + 0.00000000}; + +const double WebRtcIsac_kQMeanLag4Lo[9] = { +-7.76246496, -5.92083980, -3.94095226, -1.89502305, 0.03724681, 1.93054221, 3.96443467, 5.91726366, 7.78434291}; + +const double WebRtcIsac_kQPitchLagStepsizeLo = 2.000000; + + +/* tables for use with medium pitch gain */ + +/* cdf for quantized pitch filter lags */ +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf1Mid[255] = { + 0, 28, 61, 88, 121, 149, 233, 331, 475, 559, + 624, 661, 689, 712, 745, 791, 815, 843, 866, 922, + 959, 1024, 1061, 1117, 1178, 1238, 1280, 1350, 1453, 1513, + 1564, 1625, 1671, 1741, 1788, 1904, 2072, 2421, 2626, 2770, + 2840, 2900, 2942, 3012, 3068, 3115, 3147, 3194, 3254, 3319, + 3366, 3520, 3678, 3780, 3850, 3911, 3957, 4032, 4106, 4185, + 4292, 4474, 4683, 4842, 5019, 5191, 5321, 5428, 5540, 5675, + 5763, 5847, 5959, 6127, 6304, 6564, 6839, 7090, 7263, 7421, + 7556, 7728, 7872, 7984, 8142, 8361, 8580, 8743, 8938, 9227, + 9409, 9539, 9674, 9795, 9930, 10060, 10177, 10382, 10614, 10861, + 11038, 11271, 11415, 11629, 11792, 12044, 12193, 12416, 12574, 12821, + 13007, 13235, 13445, 13654, 13901, 14134, 14488, 15000, 15703, 16285, + 16504, 16797, 17086, 17328, 17579, 17807, 17998, 18268, 18538, 18836, + 19087, 19274, 19474, 19716, 19935, 20270, 20833, 21303, 21532, 21741, + 21978, 22207, 22523, 22770, 23054, 23613, 23943, 24204, 24399, 24651, + 24832, 25074, 25270, 25549, 25759, 26015, 26150, 26424, 26713, 27048, + 27342, 27504, 27681, 27854, 28021, 28207, 28412, 28664, 28859, 29064, + 29278, 29548, 29748, 30107, 30377, 30656, 30856, 31164, 31452, 31755, + 32011, 32328, 32626, 32919, 33319, 33789, 34329, 34925, 35396, 35973, + 36443, 36964, 37551, 38156, 38724, 39357, 40023, 40908, 41587, 42602, + 43924, 45037, 45810, 46597, 47421, 48291, 49092, 50051, 51448, 52719, + 53440, 54241, 54944, 55977, 56676, 57299, 57872, 58389, 59059, 59688, + 60237, 60782, 61094, 61573, 61890, 62290, 62658, 63030, 63217, 63454, + 63622, 63882, 64003, 64273, 64427, 64529, 64581, 64697, 64758, 64902, + 65414, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535}; + +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf2Mid[36] = { + 0, 71, 335, 581, 836, 1039, 1323, 1795, 2258, 2608, + 3005, 3591, 4243, 5344, 7163, 10583, 16848, 28078, 49448, 57007, + 60357, 61850, 62837, 63437, 63872, 64188, 64377, 64614, 64774, 64949, + 65039, 65115, 65223, 65360, 65474, 65535}; + +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf3Mid[2] = { + 0, 65535}; + +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf4Mid[20] = { + 0, 28, 246, 459, 667, 1045, 1523, 2337, 4337, 11347, + 44231, 56709, 60781, 62243, 63161, 63969, 64608, 65062, 65502, 65535}; + +const WebRtc_UWord16 *WebRtcIsac_kQPitchLagCdfPtrMid[4] = {WebRtcIsac_kQPitchLagCdf1Mid, WebRtcIsac_kQPitchLagCdf2Mid, WebRtcIsac_kQPitchLagCdf3Mid, WebRtcIsac_kQPitchLagCdf4Mid}; + +/* size of first cdf table */ +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdfSizeMid[1] = {256}; + +/* index limits and ranges */ +const WebRtc_Word16 WebRtcIsac_kQIndexLowerLimitLagMid[4] = { +-280, -17, 0, -9}; + +const WebRtc_Word16 WebRtcIsac_kQIndexUpperLimitLagMid[4] = { +-40, 17, 0, 9}; + +/* initial index for arithmetic decoder */ +const WebRtc_UWord16 WebRtcIsac_kQInitIndexLagMid[3] = { + 18, 1, 10}; + +/* mean values of pitch filter lags */ +const double WebRtcIsac_kQMeanLag2Mid[35] = { +-16.89183900, -15.86949778, -15.05476653, -14.00664348, -13.02793036, -12.07324237, -11.00542532, -10.11250602, -8.90792971, -8.02474753, +-7.00426767, -5.94055287, -4.98251338, -3.91053158, -2.98820425, -1.93524245, -0.92978085, -0.01722509, 0.91317387, 1.92973955, + 2.96908851, 3.93728974, 4.96308471, 5.92244151, 7.08673497, 8.00993708, 9.04656316, 9.98538742, 10.97851694, 11.94772884, + 13.02426166, 14.00039951, 15.01347042, 15.80758023, 16.94086895}; + +const double WebRtcIsac_kQMeanLag3Mid[1] = { + 0.00000000}; + +const double WebRtcIsac_kQMeanLag4Mid[19] = { +-8.60409403, -7.89198395, -7.03450280, -5.86260421, -4.93822322, -3.93078706, -2.91302322, -1.91824007, -0.87003282, 0.02822649, + 0.89951758, 1.87495484, 2.91802604, 3.96874074, 5.06571703, 5.93618227, 7.00520185, 7.88497726, 8.64160364}; + +const double WebRtcIsac_kQPitchLagStepsizeMid = 1.000000; + + +/* tables for use with large pitch gain */ + +/* cdf for quantized pitch filter lags */ +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf1Hi[511] = { + 0, 7, 18, 33, 69, 105, 156, 228, 315, 612, + 680, 691, 709, 724, 735, 738, 742, 746, 749, 753, + 756, 760, 764, 774, 782, 785, 789, 796, 800, 803, + 807, 814, 818, 822, 829, 832, 847, 854, 858, 869, + 876, 883, 898, 908, 934, 977, 1010, 1050, 1060, 1064, + 1075, 1078, 1086, 1089, 1093, 1104, 1111, 1122, 1133, 1136, + 1151, 1162, 1183, 1209, 1252, 1281, 1339, 1364, 1386, 1401, + 1411, 1415, 1426, 1430, 1433, 1440, 1448, 1455, 1462, 1477, + 1487, 1495, 1502, 1506, 1509, 1516, 1524, 1531, 1535, 1542, + 1553, 1556, 1578, 1589, 1611, 1625, 1639, 1643, 1654, 1665, + 1672, 1687, 1694, 1705, 1708, 1719, 1730, 1744, 1752, 1759, + 1791, 1795, 1820, 1867, 1886, 1915, 1936, 1943, 1965, 1987, + 2041, 2099, 2161, 2175, 2200, 2211, 2226, 2233, 2244, 2251, + 2266, 2280, 2287, 2298, 2309, 2316, 2331, 2342, 2356, 2378, + 2403, 2418, 2447, 2497, 2544, 2602, 2863, 2895, 2903, 2935, + 2950, 2971, 3004, 3011, 3018, 3029, 3040, 3062, 3087, 3127, + 3152, 3170, 3199, 3243, 3293, 3322, 3340, 3377, 3402, 3427, + 3474, 3518, 3543, 3579, 3601, 3637, 3659, 3706, 3731, 3760, + 3818, 3847, 3869, 3901, 3920, 3952, 4068, 4169, 4220, 4271, + 4524, 4571, 4604, 4632, 4672, 4730, 4777, 4806, 4857, 4904, + 4951, 5002, 5031, 5060, 5107, 5150, 5212, 5266, 5331, 5382, + 5432, 5490, 5544, 5610, 5700, 5762, 5812, 5874, 5972, 6022, + 6091, 6163, 6232, 6305, 6402, 6540, 6685, 6880, 7090, 7271, + 7379, 7452, 7542, 7625, 7687, 7770, 7843, 7911, 7966, 8024, + 8096, 8190, 8252, 8320, 8411, 8501, 8585, 8639, 8751, 8842, + 8918, 8986, 9066, 9127, 9203, 9269, 9345, 9406, 9464, 9536, + 9612, 9667, 9735, 9844, 9931, 10036, 10119, 10199, 10260, 10358, + 10441, 10514, 10666, 10734, 10872, 10951, 11053, 11125, 11223, 11324, + 11516, 11664, 11737, 11816, 11892, 12008, 12120, 12200, 12280, 12392, + 12490, 12576, 12685, 12812, 12917, 13003, 13108, 13210, 13300, 13384, + 13470, 13579, 13673, 13771, 13879, 13999, 14136, 14201, 14368, 14614, + 14759, 14867, 14958, 15030, 15121, 15189, 15280, 15385, 15461, 15555, + 15653, 15768, 15884, 15971, 16069, 16145, 16210, 16279, 16380, 16463, + 16539, 16615, 16688, 16818, 16919, 17017, 18041, 18338, 18523, 18649, + 18790, 18917, 19047, 19167, 19315, 19460, 19601, 19731, 19858, 20068, + 20173, 20318, 20466, 20625, 20741, 20911, 21045, 21201, 21396, 21588, + 21816, 22022, 22305, 22547, 22786, 23072, 23322, 23600, 23879, 24168, + 24433, 24769, 25120, 25511, 25895, 26289, 26792, 27219, 27683, 28077, + 28566, 29094, 29546, 29977, 30491, 30991, 31573, 32105, 32594, 33173, + 33788, 34497, 35181, 35833, 36488, 37255, 37921, 38645, 39275, 39894, + 40505, 41167, 41790, 42431, 43096, 43723, 44385, 45134, 45858, 46607, + 47349, 48091, 48768, 49405, 49955, 50555, 51167, 51985, 52611, 53078, + 53494, 53965, 54435, 54996, 55601, 56125, 56563, 56838, 57244, 57566, + 57967, 58297, 58771, 59093, 59419, 59647, 59886, 60143, 60461, 60693, + 60917, 61170, 61416, 61634, 61891, 62122, 62310, 62455, 62632, 62839, + 63103, 63436, 63639, 63805, 63906, 64015, 64192, 64355, 64475, 64558, + 64663, 64742, 64811, 64865, 64916, 64956, 64981, 65025, 65068, 65115, + 65195, 65314, 65419, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, 65535, + 65535}; + +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf2Hi[68] = { + 0, 7, 11, 22, 37, 52, 56, 59, 81, 85, + 89, 96, 115, 130, 137, 152, 170, 181, 193, 200, + 207, 233, 237, 259, 289, 318, 363, 433, 592, 992, + 1607, 3062, 6149, 12206, 25522, 48368, 58223, 61918, 63640, 64584, + 64943, 65098, 65206, 65268, 65294, 65335, 65350, 65372, 65387, 65402, + 65413, 65420, 65428, 65435, 65439, 65450, 65454, 65468, 65472, 65476, + 65483, 65491, 65498, 65505, 65516, 65520, 65528, 65535}; + +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf3Hi[2] = { + 0, 65535}; + +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf4Hi[35] = { + 0, 7, 19, 30, 41, 48, 63, 74, 82, 96, + 122, 152, 215, 330, 701, 2611, 10931, 48106, 61177, 64341, + 65112, 65238, 65309, 65338, 65364, 65379, 65401, 65427, 65453, 65465, + 65476, 65490, 65509, 65528, 65535}; + +const WebRtc_UWord16 *WebRtcIsac_kQPitchLagCdfPtrHi[4] = {WebRtcIsac_kQPitchLagCdf1Hi, WebRtcIsac_kQPitchLagCdf2Hi, WebRtcIsac_kQPitchLagCdf3Hi, WebRtcIsac_kQPitchLagCdf4Hi}; + +/* size of first cdf table */ +const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdfSizeHi[1] = {512}; + +/* index limits and ranges */ +const WebRtc_Word16 WebRtcIsac_kQindexLowerLimitLagHi[4] = { +-552, -34, 0, -16}; + +const WebRtc_Word16 WebRtcIsac_kQindexUpperLimitLagHi[4] = { +-80, 32, 0, 17}; + +/* initial index for arithmetic decoder */ +const WebRtc_UWord16 WebRtcIsac_kQInitIndexLagHi[3] = { + 34, 1, 18}; + +/* mean values of pitch filter lags */ +const double WebRtcIsac_kQMeanLag2Hi[67] = { +-17.07263295, -16.50000000, -15.83966081, -15.55613708, -14.96948007, -14.50000000, -14.00000000, -13.48377986, -13.00000000, -12.50000000, +-11.93199636, -11.44530414, -11.04197641, -10.39910301, -10.15202337, -9.51322461, -8.93357741, -8.46456632, -8.10270672, -7.53751847, +-6.98686404, -6.50000000, -6.08463150, -5.46872991, -5.00864717, -4.50163760, -4.01382410, -3.43856708, -2.96898001, -2.46554810, +-1.96861004, -1.47106701, -0.97197237, -0.46561654, -0.00531409, 0.45767857, 0.96777907, 1.47507903, 1.97740425, 2.46695420, + 3.00695774, 3.47167185, 4.02712538, 4.49280007, 5.01087640, 5.48191963, 6.04916550, 6.51511058, 6.97297819, 7.46565499, + 8.01489405, 8.39912001, 8.91819757, 9.50000000, 10.11654065, 10.50000000, 11.03712583, 11.50000000, 12.00000000, 12.38964346, + 12.89466127, 13.43657881, 13.96013840, 14.46279912, 15.00000000, 15.39412269, 15.96662441}; + +const double WebRtcIsac_kQMeanLag3Hi[1] = { + 0.00000000}; + +const double WebRtcIsac_kQMeanLag4Hi[34] = { +-7.98331221, -7.47988769, -7.03626557, -6.52708003, -6.06982173, -5.51856292, -5.05827033, -4.45909878, -3.99125864, -3.45308135, +-3.02328139, -2.47297273, -1.94341995, -1.44699056, -0.93612243, -0.43012406, 0.01120357, 0.44054812, 0.93199883, 1.45669587, + 1.97218322, 2.50187419, 2.98748690, 3.49343202, 4.01660147, 4.50984306, 5.01402683, 5.58936797, 5.91787793, 6.59998900, + 6.85034315, 7.53503316, 7.87711194, 8.53631648}; + +const double WebRtcIsac_kQPitchLagStepsizeHi = 0.500000; + +/* transform matrix */ +const double WebRtcIsac_kTransform[4][4] = { +{-0.50000000, -0.50000000, -0.50000000, -0.50000000}, +{ 0.67082039, 0.22360680, -0.22360680, -0.67082039}, +{ 0.50000000, -0.50000000, -0.50000000, 0.50000000}, +{ 0.22360680, -0.67082039, 0.67082039, -0.22360680}}; + +/* transpose transform matrix */ +const double WebRtcIsac_kTransformTranspose[4][4] = { +{-0.50000000, 0.67082039, 0.50000000, 0.22360680}, +{-0.50000000, 0.22360680, -0.50000000, -0.67082039}, +{-0.50000000, -0.22360680, -0.50000000, 0.67082039}, +{-0.50000000, -0.67082039, 0.50000000, -0.22360680}}; + diff --git a/libs/miniwebrtc/audio/coding_isac/main/pitch_lag_tables.h b/libs/miniwebrtc/audio/coding_isac/main/pitch_lag_tables.h new file mode 100644 index 00000000..67b02e5e --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/pitch_lag_tables.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * pitch_lag_tables.h + * + * This file contains tables for the pitch filter side-info in the entropy coder. + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_LAG_TABLES_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_LAG_TABLES_H_ + +#include "typedefs.h" +/* header file for coding tables for the pitch filter side-info in the entropy coder */ +/********************* Pitch Filter Lag Coefficient Tables ************************/ + +/* tables for use with small pitch gain */ + +/* cdfs for quantized pitch lags */ +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf1Lo[127]; +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf2Lo[20]; +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf3Lo[2]; +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf4Lo[10]; + +extern const WebRtc_UWord16 *WebRtcIsac_kQPitchLagCdfPtrLo[4]; + +/* size of first cdf table */ +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdfSizeLo[1]; + +/* index limits and ranges */ +extern const WebRtc_Word16 WebRtcIsac_kQIndexLowerLimitLagLo[4]; +extern const WebRtc_Word16 WebRtcIsac_kQIndexUpperLimitLagLo[4]; + +/* initial index for arithmetic decoder */ +extern const WebRtc_UWord16 WebRtcIsac_kQInitIndexLagLo[3]; + +/* mean values of pitch filter lags */ +extern const double WebRtcIsac_kQMeanLag2Lo[19]; +extern const double WebRtcIsac_kQMeanLag3Lo[1]; +extern const double WebRtcIsac_kQMeanLag4Lo[9]; + +extern const double WebRtcIsac_kQPitchLagStepsizeLo; + + +/* tables for use with medium pitch gain */ + +/* cdfs for quantized pitch lags */ +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf1Mid[255]; +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf2Mid[36]; +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf3Mid[2]; +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf4Mid[20]; + +extern const WebRtc_UWord16 *WebRtcIsac_kQPitchLagCdfPtrMid[4]; + +/* size of first cdf table */ +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdfSizeMid[1]; + +/* index limits and ranges */ +extern const WebRtc_Word16 WebRtcIsac_kQIndexLowerLimitLagMid[4]; +extern const WebRtc_Word16 WebRtcIsac_kQIndexUpperLimitLagMid[4]; + +/* initial index for arithmetic decoder */ +extern const WebRtc_UWord16 WebRtcIsac_kQInitIndexLagMid[3]; + +/* mean values of pitch filter lags */ +extern const double WebRtcIsac_kQMeanLag2Mid[35]; +extern const double WebRtcIsac_kQMeanLag3Mid[1]; +extern const double WebRtcIsac_kQMeanLag4Mid[19]; + +extern const double WebRtcIsac_kQPitchLagStepsizeMid; + + +/* tables for use with large pitch gain */ + +/* cdfs for quantized pitch lags */ +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf1Hi[511]; +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf2Hi[68]; +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf3Hi[2]; +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdf4Hi[35]; + +extern const WebRtc_UWord16 *WebRtcIsac_kQPitchLagCdfPtrHi[4]; + +/* size of first cdf table */ +extern const WebRtc_UWord16 WebRtcIsac_kQPitchLagCdfSizeHi[1]; + +/* index limits and ranges */ +extern const WebRtc_Word16 WebRtcIsac_kQindexLowerLimitLagHi[4]; +extern const WebRtc_Word16 WebRtcIsac_kQindexUpperLimitLagHi[4]; + +/* initial index for arithmetic decoder */ +extern const WebRtc_UWord16 WebRtcIsac_kQInitIndexLagHi[3]; + +/* mean values of pitch filter lags */ +extern const double WebRtcIsac_kQMeanLag2Hi[67]; +extern const double WebRtcIsac_kQMeanLag3Hi[1]; +extern const double WebRtcIsac_kQMeanLag4Hi[34]; + +extern const double WebRtcIsac_kQPitchLagStepsizeHi; + +/* transform matrix */ +extern const double WebRtcIsac_kTransform[4][4]; + +/* transpose transform matrix */ +extern const double WebRtcIsac_kTransformTranspose[4][4]; + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_PITCH_LAG_TABLES_H_ */ diff --git a/libs/miniwebrtc/audio/coding_isac/main/settings.h b/libs/miniwebrtc/audio/coding_isac/main/settings.h new file mode 100644 index 00000000..b7aed770 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/settings.h @@ -0,0 +1,199 @@ +/* + * 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_MAIN_SOURCE_SETTINGS_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SETTINGS_H_ + +/* sampling frequency (Hz) */ +#define FS 16000 + +/* number of samples per frame (either 320 (20ms), 480 (30ms) or 960 (60ms)) */ +#define INITIAL_FRAMESAMPLES 960 + + +#define MAXFFTSIZE 2048 +#define NFACTOR 11 + + + +/* do not modify the following; this will have to be modified if we have a 20ms framesize option */ +/*************************************************************************************************/ +/* miliseconds */ +#define FRAMESIZE 30 +/* number of samples per frame processed in the encoder, 480 */ +#define FRAMESAMPLES 480 /* ((FRAMESIZE*FS)/1000) */ +#define FRAMESAMPLES_HALF 240 +#define FRAMESAMPLES_QUARTER 120 +/*************************************************************************************************/ + + + +/* max number of samples per frame (= 60 ms frame) */ +#define MAX_FRAMESAMPLES 960 +#define MAX_SWBFRAMESAMPLES (MAX_FRAMESAMPLES * 2) +/* number of samples per 10ms frame */ +#define FRAMESAMPLES_10ms ((10*FS)/1000) +#define SWBFRAMESAMPLES_10ms (FRAMESAMPLES_10ms * 2) +/* number of samples in 30 ms frame */ +#define FRAMESAMPLES_30ms 480 +/* number of subframes */ +#define SUBFRAMES 6 +/* length of a subframe */ +#define UPDATE 80 +/* length of half a subframe (low/high band) */ +#define HALF_SUBFRAMELEN (UPDATE/2) +/* samples of look ahead (in a half-band, so actually half the samples of look ahead @ FS) */ +#define QLOOKAHEAD 24 /* 3 ms */ +/* order of AR model in spectral entropy coder */ +#define AR_ORDER 6 +/* order of LP model in spectral entropy coder */ +#define LP_ORDER 0 + +/* window length (masking analysis) */ +#define WINLEN 256 +/* order of low-band pole filter used to approximate masking curve */ +#define ORDERLO 12 +/* order of hi-band pole filter used to approximate masking curve */ +#define ORDERHI 6 + +#define UB_LPC_ORDER 4 +#define UB_LPC_VEC_PER_FRAME 2 +#define UB16_LPC_VEC_PER_FRAME 4 +#define UB_ACTIVE_SUBFRAMES 2 +#define UB_MAX_LPC_ORDER 6 +#define UB_INTERPOL_SEGMENTS 1 +#define UB16_INTERPOL_SEGMENTS 3 +#define LB_TOTAL_DELAY_SAMPLES 48 +enum ISACBandwidth {isac8kHz = 8, isac12kHz = 12, isac16kHz = 16}; +enum ISACBand{isacLowerBand = 0, isacUpperBand = 1}; +#define UB_LPC_GAIN_DIM SUBFRAMES +#define FB_STATE_SIZE_WORD32 6 + + +/* order for post_filter_bank */ +#define POSTQORDER 3 +/* order for pre-filterbank */ +#define QORDER 3 +/* another order */ +#define QORDER_ALL (POSTQORDER+QORDER-1) +/* for decimator */ +#define ALLPASSSECTIONS 2 + + +/* array size for byte stream in number of bytes. */ +#define STREAM_SIZE_MAX 600 /* The old maximum size still needed for the decoding */ +#define STREAM_SIZE_MAX_30 200 /* 200 bytes = 53.4 kbit/s @ 30 ms.framelength */ +#define STREAM_SIZE_MAX_60 400 /* 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//50 + + +/* For pitch analysis */ +#define PITCH_FRAME_LEN (FRAMESAMPLES_HALF) /* 30 ms */ +#define PITCH_MAX_LAG 140 /* 57 Hz */ +#define PITCH_MIN_LAG 20 /* 400 Hz */ +#define PITCH_MAX_GAIN 0.45 +#define PITCH_MAX_GAIN_06 0.27 /* PITCH_MAX_GAIN*0.6 */ +#define PITCH_MAX_GAIN_Q12 1843 +#define PITCH_LAG_SPAN2 (PITCH_MAX_LAG/2-PITCH_MIN_LAG/2+5) +#define PITCH_CORR_LEN2 60 /* 15 ms */ +#define PITCH_CORR_STEP2 (PITCH_FRAME_LEN/4) +#define PITCH_BW 11 /* half the band width of correlation surface */ +#define PITCH_SUBFRAMES 4 +#define PITCH_GRAN_PER_SUBFRAME 5 +#define PITCH_SUBFRAME_LEN (PITCH_FRAME_LEN/PITCH_SUBFRAMES) +#define PITCH_UPDATE (PITCH_SUBFRAME_LEN/PITCH_GRAN_PER_SUBFRAME) +/* maximum number of peaks to be examined in correlation surface */ +#define PITCH_MAX_NUM_PEAKS 10 +#define PITCH_PEAK_DECAY 0.85 +/* For weighting filter */ +#define PITCH_WLPCORDER 6 +#define PITCH_WLPCWINLEN PITCH_FRAME_LEN +#define PITCH_WLPCASYM 0.3 /* asymmetry parameter */ +#define PITCH_WLPCBUFLEN PITCH_WLPCWINLEN +/* For pitch filter */ +#define PITCH_BUFFSIZE (PITCH_MAX_LAG + 50) /* Extra 50 for fraction and LP filters */ +#define PITCH_INTBUFFSIZE (PITCH_FRAME_LEN+PITCH_BUFFSIZE) +/* Max rel. step for interpolation */ +#define PITCH_UPSTEP 1.5 +/* Max rel. step for interpolation */ +#define PITCH_DOWNSTEP 0.67 +#define PITCH_FRACS 8 +#define PITCH_FRACORDER 9 +#define PITCH_DAMPORDER 5 +#define PITCH_FILTDELAY 1.5f +/* stepsize for quantization of the pitch Gain */ +#define PITCH_GAIN_STEPSIZE 0.125 + + + +/* Order of high pass filter */ +#define HPORDER 2 + +/* some mathematical constants */ +#define LOG2EXP 1.44269504088896 /* log2(exp) */ +#define PI 3.14159265358979 + +/* Maximum number of iterations allowed to limit payload size */ +#define MAX_PAYLOAD_LIMIT_ITERATION 5 + +/* Redundant Coding */ +#define RCU_BOTTLENECK_BPS 16000 +#define RCU_TRANSCODING_SCALE 0.40f +#define RCU_TRANSCODING_SCALE_INVERSE 2.5f + +#define RCU_TRANSCODING_SCALE_UB 0.50f +#define RCU_TRANSCODING_SCALE_UB_INVERSE 2.0f + + +/* Define Error codes */ +/* 6000 General */ +#define ISAC_MEMORY_ALLOCATION_FAILED 6010 +#define ISAC_MODE_MISMATCH 6020 +#define ISAC_DISALLOWED_BOTTLENECK 6030 +#define ISAC_DISALLOWED_FRAME_LENGTH 6040 +#define ISAC_UNSUPPORTED_SAMPLING_FREQUENCY 6050 + +/* 6200 Bandwidth estimator */ +#define ISAC_RANGE_ERROR_BW_ESTIMATOR 6240 +/* 6400 Encoder */ +#define ISAC_ENCODER_NOT_INITIATED 6410 +#define ISAC_DISALLOWED_CODING_MODE 6420 +#define ISAC_DISALLOWED_FRAME_MODE_ENCODER 6430 +#define ISAC_DISALLOWED_BITSTREAM_LENGTH 6440 +#define ISAC_PAYLOAD_LARGER_THAN_LIMIT 6450 +#define ISAC_DISALLOWED_ENCODER_BANDWIDTH 6460 +/* 6600 Decoder */ +#define ISAC_DECODER_NOT_INITIATED 6610 +#define ISAC_EMPTY_PACKET 6620 +#define ISAC_DISALLOWED_FRAME_MODE_DECODER 6630 +#define ISAC_RANGE_ERROR_DECODE_FRAME_LENGTH 6640 +#define ISAC_RANGE_ERROR_DECODE_BANDWIDTH 6650 +#define ISAC_RANGE_ERROR_DECODE_PITCH_GAIN 6660 +#define ISAC_RANGE_ERROR_DECODE_PITCH_LAG 6670 +#define ISAC_RANGE_ERROR_DECODE_LPC 6680 +#define ISAC_RANGE_ERROR_DECODE_SPECTRUM 6690 +#define ISAC_LENGTH_MISMATCH 6730 +#define ISAC_RANGE_ERROR_DECODE_BANDWITH 6740 +#define ISAC_DISALLOWED_BANDWIDTH_MODE_DECODER 6750 +/* 6800 Call setup formats */ +#define ISAC_INCOMPATIBLE_FORMATS 6810 + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SETTINGS_H_ */ diff --git a/libs/miniwebrtc/audio/coding_isac/main/spectrum_ar_model_tables.c b/libs/miniwebrtc/audio/coding_isac/main/spectrum_ar_model_tables.c new file mode 100644 index 00000000..92b9c4d6 --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/spectrum_ar_model_tables.c @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "spectrum_ar_model_tables.h" +#include "settings.h" + +/********************* AR Coefficient Tables ************************/ +/* cdf for quantized reflection coefficient 1 */ +const WebRtc_UWord16 WebRtcIsac_kQArRc1Cdf[12] = { + 0, 2, 4, 129, 7707, 57485, 65495, 65527, 65529, 65531, + 65533, 65535}; + +/* cdf for quantized reflection coefficient 2 */ +const WebRtc_UWord16 WebRtcIsac_kQArRc2Cdf[12] = { + 0, 2, 4, 7, 531, 25298, 64525, 65526, 65529, 65531, + 65533, 65535}; + +/* cdf for quantized reflection coefficient 3 */ +const WebRtc_UWord16 WebRtcIsac_kQArRc3Cdf[12] = { + 0, 2, 4, 6, 620, 22898, 64843, 65527, 65529, 65531, + 65533, 65535}; + +/* cdf for quantized reflection coefficient 4 */ +const WebRtc_UWord16 WebRtcIsac_kQArRc4Cdf[12] = { + 0, 2, 4, 6, 35, 10034, 60733, 65506, 65529, 65531, + 65533, 65535}; + +/* cdf for quantized reflection coefficient 5 */ +const WebRtc_UWord16 WebRtcIsac_kQArRc5Cdf[12] = { + 0, 2, 4, 6, 36, 7567, 56727, 65385, 65529, 65531, + 65533, 65535}; + +/* cdf for quantized reflection coefficient 6 */ +const WebRtc_UWord16 WebRtcIsac_kQArRc6Cdf[12] = { + 0, 2, 4, 6, 14, 6579, 57360, 65409, 65529, 65531, + 65533, 65535}; + +/* representation levels for quantized reflection coefficient 1 */ +const WebRtc_Word16 WebRtcIsac_kQArRc1Levels[11] = { + -32104, -29007, -23202, -15496, -9279, -2577, 5934, 17535, 24512, 29503, 32104 +}; + +/* representation levels for quantized reflection coefficient 2 */ +const WebRtc_Word16 WebRtcIsac_kQArRc2Levels[11] = { + -32104, -29503, -23494, -15261, -7309, -1399, 6158, 16381, 24512, 29503, 32104 +}; + +/* representation levels for quantized reflection coefficient 3 */ +const WebRtc_Word16 WebRtcIsac_kQArRc3Levels[11] = { +-32104, -29503, -23157, -15186, -7347, -1359, 5829, 17535, 24512, 29503, 32104 +}; + +/* representation levels for quantized reflection coefficient 4 */ +const WebRtc_Word16 WebRtcIsac_kQArRc4Levels[11] = { +-32104, -29503, -24512, -15362, -6665, -342, 6596, 14585, 24512, 29503, 32104 +}; + +/* representation levels for quantized reflection coefficient 5 */ +const WebRtc_Word16 WebRtcIsac_kQArRc5Levels[11] = { +-32104, -29503, -24512, -15005, -6564, -106, 7123, 14920, 24512, 29503, 32104 +}; + +/* representation levels for quantized reflection coefficient 6 */ +const WebRtc_Word16 WebRtcIsac_kQArRc6Levels[11] = { +-32104, -29503, -24512, -15096, -6656, -37, 7036, 14847, 24512, 29503, 32104 +}; + +/* quantization boundary levels for reflection coefficients */ +const WebRtc_Word16 WebRtcIsac_kQArBoundaryLevels[12] = { +-32768, -31441, -27566, -21458, -13612, -4663, 4663, 13612, 21458, 27566, 31441, 32767 +}; + +/* initial index for AR reflection coefficient quantizer and cdf table search */ +const WebRtc_UWord16 WebRtcIsac_kQArRcInitIndex[6] = { + 5, 5, 5, 5, 5, 5}; + +/* pointers to AR cdf tables */ +const WebRtc_UWord16 *WebRtcIsac_kQArRcCdfPtr[AR_ORDER] = { + WebRtcIsac_kQArRc1Cdf, WebRtcIsac_kQArRc2Cdf, WebRtcIsac_kQArRc3Cdf, + WebRtcIsac_kQArRc4Cdf, WebRtcIsac_kQArRc5Cdf, WebRtcIsac_kQArRc6Cdf +}; + +/* pointers to AR representation levels tables */ +const WebRtc_Word16 *WebRtcIsac_kQArRcLevelsPtr[AR_ORDER] = { + WebRtcIsac_kQArRc1Levels, WebRtcIsac_kQArRc2Levels, WebRtcIsac_kQArRc3Levels, + WebRtcIsac_kQArRc4Levels, WebRtcIsac_kQArRc5Levels, WebRtcIsac_kQArRc6Levels +}; + + +/******************** GAIN Coefficient Tables ***********************/ +/* cdf for Gain coefficient */ +const WebRtc_UWord16 WebRtcIsac_kQGainCdf[19] = { + 0, 2, 4, 6, 8, 10, 12, 14, 16, 1172, + 11119, 29411, 51699, 64445, 65527, 65529, 65531, 65533, 65535}; + +/* representation levels for quantized squared Gain coefficient */ +const WebRtc_Word32 WebRtcIsac_kQGain2Levels[18] = { +// 17, 28, 46, 76, 128, 215, 364, 709, 1268, 1960, 3405, 6078, 11286, 17827, 51918, 134498, 487432, 2048000}; + 128, 128, 128, 128, 128, 215, 364, 709, 1268, 1960, 3405, 6078, 11286, 17827, 51918, 134498, 487432, 2048000}; +/* quantization boundary levels for squared Gain coefficient */ +const WebRtc_Word32 WebRtcIsac_kQGain2BoundaryLevels[19] = { +0, 21, 35, 59, 99, 166, 280, 475, 815, 1414, 2495, 4505, 8397, 16405, 34431, 81359, 240497, 921600, 0x7FFFFFFF}; + +/* pointers to Gain cdf table */ +const WebRtc_UWord16 *WebRtcIsac_kQGainCdf_ptr[1] = {WebRtcIsac_kQGainCdf}; + +/* Gain initial index for gain quantizer and cdf table search */ +const WebRtc_UWord16 WebRtcIsac_kQGainInitIndex[1] = {11}; + +/************************* Cosine Tables ****************************/ +/* Cosine table */ +const WebRtc_Word16 WebRtcIsac_kCos[6][60] = { +{512, 512, 511, 510, 508, 507, 505, 502, 499, 496, 493, 489, 485, 480, 476, 470, 465, 459, 453, 447, +440, 433, 426, 418, 410, 402, 394, 385, 376, 367, 357, 348, 338, 327, 317, 306, 295, 284, 273, 262, +250, 238, 226, 214, 202, 190, 177, 165, 152, 139, 126, 113, 100, 87, 73, 60, 47, 33, 20, 7}, +{512, 510, 508, 503, 498, 491, 483, 473, 462, 450, 437, 422, 406, 389, 371, 352, 333, 312, 290, 268, +244, 220, 196, 171, 145, 120, 93, 67, 40, 13, -13, -40, -67, -93, -120, -145, -171, -196, -220, -244, +-268, -290, -312, -333, -352, -371, -389, -406, -422, -437, -450, -462, -473, -483, -491, -498, -503, -508, -510, -512}, +{512, 508, 502, 493, 480, 465, 447, 426, 402, 376, 348, 317, 284, 250, 214, 177, 139, 100, 60, 20, +-20, -60, -100, -139, -177, -214, -250, -284, -317, -348, -376, -402, -426, -447, -465, -480, -493, -502, -508, -512, +-512, -508, -502, -493, -480, -465, -447, -426, -402, -376, -348, -317, -284, -250, -214, -177, -139, -100, -60, -20}, +{511, 506, 495, 478, 456, 429, 398, 362, 322, 279, 232, 183, 133, 80, 27, -27, -80, -133, -183, -232, +-279, -322, -362, -398, -429, -456, -478, -495, -506, -511, -511, -506, -495, -478, -456, -429, -398, -362, -322, -279, +-232, -183, -133, -80, -27, 27, 80, 133, 183, 232, 279, 322, 362, 398, 429, 456, 478, 495, 506, 511}, +{511, 502, 485, 459, 426, 385, 338, 284, 226, 165, 100, 33, -33, -100, -165, -226, -284, -338, -385, -426, +-459, -485, -502, -511, -511, -502, -485, -459, -426, -385, -338, -284, -226, -165, -100, -33, 33, 100, 165, 226, +284, 338, 385, 426, 459, 485, 502, 511, 511, 502, 485, 459, 426, 385, 338, 284, 226, 165, 100, 33}, +{510, 498, 473, 437, 389, 333, 268, 196, 120, 40, -40, -120, -196, -268, -333, -389, -437, -473, -498, -510, +-510, -498, -473, -437, -389, -333, -268, -196, -120, -40, 40, 120, 196, 268, 333, 389, 437, 473, 498, 510, +510, 498, 473, 437, 389, 333, 268, 196, 120, 40, -40, -120, -196, -268, -333, -389, -437, -473, -498, -510} +}; diff --git a/libs/miniwebrtc/audio/coding_isac/main/spectrum_ar_model_tables.h b/libs/miniwebrtc/audio/coding_isac/main/spectrum_ar_model_tables.h new file mode 100644 index 00000000..159245bd --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/spectrum_ar_model_tables.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * spectrum_ar_model_tables.h + * + * This file contains definitions of tables with AR coefficients, + * Gain coefficients and cosine tables. + * + */ + +#ifndef WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_ + +#include "structs.h" + +/********************* AR Coefficient Tables ************************/ +/* cdf for quantized reflection coefficient 1 */ +extern const WebRtc_UWord16 WebRtcIsac_kQArRc1Cdf[12]; + +/* cdf for quantized reflection coefficient 2 */ +extern const WebRtc_UWord16 WebRtcIsac_kQArRc2Cdf[12]; + +/* cdf for quantized reflection coefficient 3 */ +extern const WebRtc_UWord16 WebRtcIsac_kQArRc3Cdf[12]; + +/* cdf for quantized reflection coefficient 4 */ +extern const WebRtc_UWord16 WebRtcIsac_kQArRc4Cdf[12]; + +/* cdf for quantized reflection coefficient 5 */ +extern const WebRtc_UWord16 WebRtcIsac_kQArRc5Cdf[12]; + +/* cdf for quantized reflection coefficient 6 */ +extern const WebRtc_UWord16 WebRtcIsac_kQArRc6Cdf[12]; + +/* quantization boundary levels for reflection coefficients */ +extern const WebRtc_Word16 WebRtcIsac_kQArBoundaryLevels[12]; + +/* initial indices for AR reflection coefficient quantizer and cdf table search */ +extern const WebRtc_UWord16 WebRtcIsac_kQArRcInitIndex[AR_ORDER]; + +/* pointers to AR cdf tables */ +extern const WebRtc_UWord16 *WebRtcIsac_kQArRcCdfPtr[AR_ORDER]; + +/* pointers to AR representation levels tables */ +extern const WebRtc_Word16 *WebRtcIsac_kQArRcLevelsPtr[AR_ORDER]; + + +/******************** GAIN Coefficient Tables ***********************/ +/* cdf for Gain coefficient */ +extern const WebRtc_UWord16 WebRtcIsac_kQGainCdf[19]; + +/* representation levels for quantized Gain coefficient */ +extern const WebRtc_Word32 WebRtcIsac_kQGain2Levels[18]; + +/* squared quantization boundary levels for Gain coefficient */ +extern const WebRtc_Word32 WebRtcIsac_kQGain2BoundaryLevels[19]; + +/* pointer to Gain cdf table */ +extern const WebRtc_UWord16 *WebRtcIsac_kQGainCdf_ptr[1]; + +/* Gain initial index for gain quantizer and cdf table search */ +extern const WebRtc_UWord16 WebRtcIsac_kQGainInitIndex[1]; + +/************************* Cosine Tables ****************************/ +/* Cosine table */ +extern const WebRtc_Word16 WebRtcIsac_kCos[6][60]; + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_SPECTRUM_AR_MODEL_TABLES_H_ */ diff --git a/libs/miniwebrtc/audio/coding_isac/main/structs.h b/libs/miniwebrtc/audio/coding_isac/main/structs.h new file mode 100644 index 00000000..7523ad6e --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/structs.h @@ -0,0 +1,478 @@ +/* + * 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_MAIN_SOURCE_STRUCTS_H_ +#define WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_STRUCTS_H_ + + +#include "typedefs.h" +#include "settings.h" +#include "isac.h" + +typedef struct Bitstreamstruct { + + WebRtc_UWord8 stream[STREAM_SIZE_MAX]; + WebRtc_UWord32 W_upper; + WebRtc_UWord32 streamval; + WebRtc_UWord32 stream_index; + +} Bitstr; + +typedef struct { + + double DataBufferLo[WINLEN]; + double DataBufferHi[WINLEN]; + + double CorrBufLo[ORDERLO+1]; + double CorrBufHi[ORDERHI+1]; + + float PreStateLoF[ORDERLO+1]; + float PreStateLoG[ORDERLO+1]; + float PreStateHiF[ORDERHI+1]; + float PreStateHiG[ORDERHI+1]; + float PostStateLoF[ORDERLO+1]; + float PostStateLoG[ORDERLO+1]; + float PostStateHiF[ORDERHI+1]; + float PostStateHiG[ORDERHI+1]; + + double OldEnergy; + +} MaskFiltstr; + + +typedef struct { + + //state vectors for each of the two analysis filters + double INSTAT1[2*(QORDER-1)]; + double INSTAT2[2*(QORDER-1)]; + double INSTATLA1[2*(QORDER-1)]; + double INSTATLA2[2*(QORDER-1)]; + double INLABUF1[QLOOKAHEAD]; + double INLABUF2[QLOOKAHEAD]; + + float INSTAT1_float[2*(QORDER-1)]; + float INSTAT2_float[2*(QORDER-1)]; + float INSTATLA1_float[2*(QORDER-1)]; + float INSTATLA2_float[2*(QORDER-1)]; + float INLABUF1_float[QLOOKAHEAD]; + float INLABUF2_float[QLOOKAHEAD]; + + /* High pass filter */ + double HPstates[HPORDER]; + float HPstates_float[HPORDER]; + +} PreFiltBankstr; + + +typedef struct { + + //state vectors for each of the two analysis filters + double STATE_0_LOWER[2*POSTQORDER]; + double STATE_0_UPPER[2*POSTQORDER]; + + /* High pass filter */ + double HPstates1[HPORDER]; + double HPstates2[HPORDER]; + + float STATE_0_LOWER_float[2*POSTQORDER]; + float STATE_0_UPPER_float[2*POSTQORDER]; + + float HPstates1_float[HPORDER]; + float HPstates2_float[HPORDER]; + +} PostFiltBankstr; + +typedef struct { + + //data buffer for pitch filter + double ubuf[PITCH_BUFFSIZE]; + + //low pass state vector + double ystate[PITCH_DAMPORDER]; + + //old lag and gain + double oldlagp[1]; + double oldgainp[1]; + +} PitchFiltstr; + +typedef struct { + + //data buffer + double buffer[PITCH_WLPCBUFLEN]; + + //state vectors + double istate[PITCH_WLPCORDER]; + double weostate[PITCH_WLPCORDER]; + double whostate[PITCH_WLPCORDER]; + + //LPC window -> should be a global array because constant + double window[PITCH_WLPCWINLEN]; + +} WeightFiltstr; + +typedef struct { + + //for inital estimator + double dec_buffer[PITCH_CORR_LEN2 + PITCH_CORR_STEP2 + + PITCH_MAX_LAG/2 - PITCH_FRAME_LEN/2+2]; + double decimator_state[2*ALLPASSSECTIONS+1]; + double hp_state[2]; + + double whitened_buf[QLOOKAHEAD]; + + double inbuf[QLOOKAHEAD]; + + PitchFiltstr PFstr_wght; + PitchFiltstr PFstr; + WeightFiltstr Wghtstr; + +} PitchAnalysisStruct; + + + +/* Have instance of struct together with other iSAC structs */ +typedef struct { + + /* Previous frame length (in ms) */ + WebRtc_Word32 prev_frame_length; + + /* Previous RTP timestamp from received + packet (in samples relative beginning) */ + WebRtc_Word32 prev_rec_rtp_number; + + /* Send timestamp for previous packet (in ms using timeGetTime()) */ + WebRtc_UWord32 prev_rec_send_ts; + + /* Arrival time for previous packet (in ms using timeGetTime()) */ + WebRtc_UWord32 prev_rec_arr_ts; + + /* rate of previous packet, derived from RTP timestamps (in bits/s) */ + float prev_rec_rtp_rate; + + /* Time sinse the last update of the BN estimate (in ms) */ + WebRtc_UWord32 last_update_ts; + + /* Time sinse the last reduction (in ms) */ + WebRtc_UWord32 last_reduction_ts; + + /* How many times the estimate was update in the beginning */ + WebRtc_Word32 count_tot_updates_rec; + + /* The estimated bottle neck rate from there to here (in bits/s) */ + WebRtc_Word32 rec_bw; + float rec_bw_inv; + float rec_bw_avg; + float rec_bw_avg_Q; + + /* The estimated mean absolute jitter value, + as seen on this side (in ms) */ + float rec_jitter; + float rec_jitter_short_term; + float rec_jitter_short_term_abs; + float rec_max_delay; + float rec_max_delay_avg_Q; + + /* (assumed) bitrate for headers (bps) */ + float rec_header_rate; + + /* The estimated bottle neck rate from here to there (in bits/s) */ + float send_bw_avg; + + /* The estimated mean absolute jitter value, as seen on + the other siee (in ms) */ + float send_max_delay_avg; + + // number of packets received since last update + int num_pkts_rec; + + int num_consec_rec_pkts_over_30k; + + // flag for marking that a high speed network has been + // detected downstream + int hsn_detect_rec; + + int num_consec_snt_pkts_over_30k; + + // flag for marking that a high speed network has + // been detected upstream + int hsn_detect_snd; + + WebRtc_UWord32 start_wait_period; + + int in_wait_period; + + int change_to_WB; + + WebRtc_UWord32 senderTimestamp; + WebRtc_UWord32 receiverTimestamp; + //enum IsacSamplingRate incomingStreamSampFreq; + WebRtc_UWord16 numConsecLatePkts; + float consecLatency; + WebRtc_Word16 inWaitLatePkts; +} BwEstimatorstr; + + +typedef struct { + + /* boolean, flags if previous packet exceeded B.N. */ + int PrevExceed; + /* ms */ + int ExceedAgo; + /* packets left to send in current burst */ + int BurstCounter; + /* packets */ + int InitCounter; + /* ms remaining in buffer when next packet will be sent */ + double StillBuffered; + +} RateModel; + + +typedef struct { + + unsigned int SpaceAlloced; + unsigned int MaxPermAlloced; + double Tmp0[MAXFFTSIZE]; + double Tmp1[MAXFFTSIZE]; + double Tmp2[MAXFFTSIZE]; + double Tmp3[MAXFFTSIZE]; + int Perm[MAXFFTSIZE]; + int factor [NFACTOR]; + +} FFTstr; + + +/* The following strutc is used to store data from encoding, to make it + fast and easy to construct a new bitstream with a different Bandwidth + estimate. All values (except framelength and minBytes) is double size to + handle 60 ms of data. +*/ +typedef struct { + + /* Used to keep track of if it is first or second part of 60 msec packet */ + int startIdx; + + /* Frame length in samples */ + WebRtc_Word16 framelength; + + /* Pitch Gain */ + int pitchGain_index[2]; + + /* Pitch Lag */ + double meanGain[2]; + int pitchIndex[PITCH_SUBFRAMES*2]; + + /* LPC */ + int LPCmodel[2]; + int LPCindex_s[108*2]; /* KLT_ORDER_SHAPE = 108 */ + int LPCindex_g[12*2]; /* KLT_ORDER_GAIN = 12 */ + double LPCcoeffs_lo[(ORDERLO+1)*SUBFRAMES*2]; + double LPCcoeffs_hi[(ORDERHI+1)*SUBFRAMES*2]; + + /* Encode Spec */ + WebRtc_Word16 fre[FRAMESAMPLES]; + WebRtc_Word16 fim[FRAMESAMPLES]; + WebRtc_Word16 AvgPitchGain[2]; + + /* Used in adaptive mode only */ + int minBytes; + +} ISAC_SaveEncData_t; + + +typedef struct { + + int indexLPCShape[UB_LPC_ORDER * UB16_LPC_VEC_PER_FRAME]; + double lpcGain[SUBFRAMES<<1]; + int lpcGainIndex[SUBFRAMES<<1]; + + Bitstr bitStreamObj; + + WebRtc_Word16 realFFT[FRAMESAMPLES_HALF]; + WebRtc_Word16 imagFFT[FRAMESAMPLES_HALF]; +} ISACUBSaveEncDataStruct; + + + +typedef struct { + + Bitstr bitstr_obj; + MaskFiltstr maskfiltstr_obj; + PreFiltBankstr prefiltbankstr_obj; + PitchFiltstr pitchfiltstr_obj; + PitchAnalysisStruct pitchanalysisstr_obj; + FFTstr fftstr_obj; + ISAC_SaveEncData_t SaveEnc_obj; + + int buffer_index; + WebRtc_Word16 current_framesamples; + + float data_buffer_float[FRAMESAMPLES_30ms]; + + int frame_nb; + double bottleneck; + WebRtc_Word16 new_framelength; + double s2nr; + + /* Maximum allowed number of bits for a 30 msec packet */ + WebRtc_Word16 payloadLimitBytes30; + /* Maximum allowed number of bits for a 30 msec packet */ + WebRtc_Word16 payloadLimitBytes60; + /* Maximum allowed number of bits for both 30 and 60 msec packet */ + WebRtc_Word16 maxPayloadBytes; + /* Maximum allowed rate in bytes per 30 msec packet */ + WebRtc_Word16 maxRateInBytes; + + /*--- + If set to 1 iSAC will not addapt the frame-size, if used in + channel-adaptive mode. The initial value will be used for all rates. + ---*/ + WebRtc_Word16 enforceFrameSize; + + /*----- + This records the BWE index the encoder injected into the bit-stream. + It will be used in RCU. The same BWE index of main paylaod will be in + the redundant payload. We can not retrive it from BWE because it is + a recursive procedure (WebRtcIsac_GetDownlinkBwJitIndexImpl) and has to be + called only once per each encode. + -----*/ + WebRtc_Word16 lastBWIdx; +} ISACLBEncStruct; + +typedef struct { + + Bitstr bitstr_obj; + MaskFiltstr maskfiltstr_obj; + PreFiltBankstr prefiltbankstr_obj; + FFTstr fftstr_obj; + ISACUBSaveEncDataStruct SaveEnc_obj; + + int buffer_index; + float data_buffer_float[MAX_FRAMESAMPLES + + LB_TOTAL_DELAY_SAMPLES]; + double bottleneck; + /* Maximum allowed number of bits for a 30 msec packet */ + //WebRtc_Word16 payloadLimitBytes30; + /* Maximum allowed number of bits for both 30 and 60 msec packet */ + //WebRtc_Word16 maxPayloadBytes; + WebRtc_Word16 maxPayloadSizeBytes; + + double lastLPCVec[UB_LPC_ORDER]; + WebRtc_Word16 numBytesUsed; + WebRtc_Word16 lastJitterInfo; +} ISACUBEncStruct; + + + +typedef struct { + + Bitstr bitstr_obj; + MaskFiltstr maskfiltstr_obj; + PostFiltBankstr postfiltbankstr_obj; + PitchFiltstr pitchfiltstr_obj; + FFTstr fftstr_obj; + +} ISACLBDecStruct; + +typedef struct { + + Bitstr bitstr_obj; + MaskFiltstr maskfiltstr_obj; + PostFiltBankstr postfiltbankstr_obj; + FFTstr fftstr_obj; + +} ISACUBDecStruct; + + + +typedef struct { + + ISACLBEncStruct ISACencLB_obj; + ISACLBDecStruct ISACdecLB_obj; +} ISACLBStruct; + + +typedef struct { + + ISACUBEncStruct ISACencUB_obj; + ISACUBDecStruct ISACdecUB_obj; +} ISACUBStruct; + +/* + This struct is used to take a snapshot of the entropy coder and LPC gains + right before encoding LPC gains. This allows us to go back to that state + if we like to limit the payload size. +*/ +typedef struct { + /* 6 lower-band & 6 upper-band */ + double loFiltGain[SUBFRAMES]; + double hiFiltGain[SUBFRAMES]; + /* Upper boundary of interval W */ + WebRtc_UWord32 W_upper; + WebRtc_UWord32 streamval; + /* Index to the current position in bytestream */ + WebRtc_UWord32 stream_index; + WebRtc_UWord8 stream[3]; +} transcode_obj; + + +typedef struct { + // lower-band codec instance + ISACLBStruct instLB; + // upper-band codec instance + ISACUBStruct instUB; + + // Bandwidth Estimator and model for the rate. + BwEstimatorstr bwestimator_obj; + RateModel rate_data_obj; + double MaxDelay; + + /* 0 = adaptive; 1 = instantaneous */ + WebRtc_Word16 codingMode; + + // overall bottleneck of the codec + WebRtc_Word32 bottleneck; + + // QMF Filter state + WebRtc_Word32 analysisFBState1[FB_STATE_SIZE_WORD32]; + WebRtc_Word32 analysisFBState2[FB_STATE_SIZE_WORD32]; + WebRtc_Word32 synthesisFBState1[FB_STATE_SIZE_WORD32]; + WebRtc_Word32 synthesisFBState2[FB_STATE_SIZE_WORD32]; + + // Error Code + WebRtc_Word16 errorCode; + + // bandwidth of the encoded audio 8, 12 or 16 kHz + enum ISACBandwidth bandwidthKHz; + // Sampling rate of audio, encoder and decode, 8 or 16 kHz + enum IsacSamplingRate encoderSamplingRateKHz; + enum IsacSamplingRate decoderSamplingRateKHz; + // Flag to keep track of initializations, lower & upper-band + // encoder and decoder. + WebRtc_Word16 initFlag; + + // Flag to to indicate signal bandwidth switch + WebRtc_Word16 resetFlag_8kHz; + + // Maximum allowed rate, measured in Bytes per 30 ms. + WebRtc_Word16 maxRateBytesPer30Ms; + // Maximum allowed payload-size, measured in Bytes. + WebRtc_Word16 maxPayloadSizeBytes; +} ISACMainStruct; + +#endif /* WEBRTC_MODULES_AUDIO_CODING_CODECS_ISAC_MAIN_SOURCE_STRUCTS_H_ */ diff --git a/libs/miniwebrtc/audio/coding_isac/main/transform.c b/libs/miniwebrtc/audio/coding_isac/main/transform.c new file mode 100644 index 00000000..97b801ac --- /dev/null +++ b/libs/miniwebrtc/audio/coding_isac/main/transform.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "settings.h" +#include "fft.h" +#include "codec.h" +#include "os_specific_inline.h" +#include + +static double costab1[FRAMESAMPLES_HALF]; +static double sintab1[FRAMESAMPLES_HALF]; +static double costab2[FRAMESAMPLES_QUARTER]; +static double sintab2[FRAMESAMPLES_QUARTER]; + +void WebRtcIsac_InitTransform() +{ + int k; + double fact, phase; + + fact = PI / (FRAMESAMPLES_HALF); + phase = 0.0; + for (k = 0; k < FRAMESAMPLES_HALF; k++) { + costab1[k] = cos(phase); + sintab1[k] = sin(phase); + phase += fact; + } + + fact = PI * ((double) (FRAMESAMPLES_HALF - 1)) / ((double) FRAMESAMPLES_HALF); + phase = 0.5 * fact; + for (k = 0; k < FRAMESAMPLES_QUARTER; k++) { + costab2[k] = cos(phase); + sintab2[k] = sin(phase); + phase += fact; + } +} + + +void WebRtcIsac_Time2Spec(double *inre1, + double *inre2, + WebRtc_Word16 *outreQ7, + WebRtc_Word16 *outimQ7, + FFTstr *fftstr_obj) +{ + + int k; + int dims[1]; + double tmp1r, tmp1i, xr, xi, yr, yi, fact; + double tmpre[FRAMESAMPLES_HALF], tmpim[FRAMESAMPLES_HALF]; + + + dims[0] = FRAMESAMPLES_HALF; + + + /* Multiply with complex exponentials and combine into one complex vector */ + fact = 0.5 / sqrt(FRAMESAMPLES_HALF); + for (k = 0; k < FRAMESAMPLES_HALF; k++) { + tmp1r = costab1[k]; + tmp1i = sintab1[k]; + tmpre[k] = (inre1[k] * tmp1r + inre2[k] * tmp1i) * fact; + tmpim[k] = (inre2[k] * tmp1r - inre1[k] * tmp1i) * fact; + } + + + /* Get DFT */ + WebRtcIsac_Fftns(1, dims, tmpre, tmpim, -1, 1.0, fftstr_obj); + + /* Use symmetry to separate into two complex vectors and center frames in time around zero */ + for (k = 0; k < FRAMESAMPLES_QUARTER; k++) { + xr = tmpre[k] + tmpre[FRAMESAMPLES_HALF - 1 - k]; + yi = -tmpre[k] + tmpre[FRAMESAMPLES_HALF - 1 - k]; + xi = tmpim[k] - tmpim[FRAMESAMPLES_HALF - 1 - k]; + yr = tmpim[k] + tmpim[FRAMESAMPLES_HALF - 1 - k]; + + tmp1r = costab2[k]; + tmp1i = sintab2[k]; + outreQ7[k] = (WebRtc_Word16)WebRtcIsac_lrint((xr * tmp1r - xi * tmp1i) * 128.0); + outimQ7[k] = (WebRtc_Word16)WebRtcIsac_lrint((xr * tmp1i + xi * tmp1r) * 128.0); + outreQ7[FRAMESAMPLES_HALF - 1 - k] = (WebRtc_Word16)WebRtcIsac_lrint((-yr * tmp1i - yi * tmp1r) * 128.0); + outimQ7[FRAMESAMPLES_HALF - 1 - k] = (WebRtc_Word16)WebRtcIsac_lrint((-yr * tmp1r + yi * tmp1i) * 128.0); + } +} + + +void WebRtcIsac_Spec2time(double *inre, double *inim, double *outre1, double *outre2, FFTstr *fftstr_obj) +{ + + int k; + double tmp1r, tmp1i, xr, xi, yr, yi, fact; + + int dims; + + dims = FRAMESAMPLES_HALF; + + for (k = 0; k < FRAMESAMPLES_QUARTER; k++) { + /* Move zero in time to beginning of frames */ + tmp1r = costab2[k]; + tmp1i = sintab2[k]; + xr = inre[k] * tmp1r + inim[k] * tmp1i; + xi = inim[k] * tmp1r - inre[k] * tmp1i; + yr = -inim[FRAMESAMPLES_HALF - 1 - k] * tmp1r - inre[FRAMESAMPLES_HALF - 1 - k] * tmp1i; + yi = -inre[FRAMESAMPLES_HALF - 1 - k] * tmp1r + inim[FRAMESAMPLES_HALF - 1 - k] * tmp1i; + + /* Combine into one vector, z = x + j * y */ + outre1[k] = xr - yi; + outre1[FRAMESAMPLES_HALF - 1 - k] = xr + yi; + outre2[k] = xi + yr; + outre2[FRAMESAMPLES_HALF - 1 - k] = -xi + yr; + } + + + /* Get IDFT */ + WebRtcIsac_Fftns(1, &dims, outre1, outre2, 1, FRAMESAMPLES_HALF, fftstr_obj); + + + /* Demodulate and separate */ + fact = sqrt(FRAMESAMPLES_HALF); + for (k = 0; k < FRAMESAMPLES_HALF; k++) { + tmp1r = costab1[k]; + tmp1i = sintab1[k]; + xr = (outre1[k] * tmp1r - outre2[k] * tmp1i) * fact; + outre2[k] = (outre2[k] * tmp1r + outre1[k] * tmp1i) * fact; + outre1[k] = xr; + } +} diff --git a/libs/miniwebrtc/audio/common/processing/auto_corr_to_refl_coef.c b/libs/miniwebrtc/audio/common/processing/auto_corr_to_refl_coef.c new file mode 100644 index 00000000..b7e88589 --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/auto_corr_to_refl_coef.c @@ -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. + */ + + +/* + * This file contains the function WebRtcSpl_AutoCorrToReflCoef(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "signal_processing_library.h" + +void WebRtcSpl_AutoCorrToReflCoef(G_CONST WebRtc_Word32 *R, int use_order, WebRtc_Word16 *K) +{ + int i, n; + WebRtc_Word16 tmp; + G_CONST WebRtc_Word32 *rptr; + WebRtc_Word32 L_num, L_den; + WebRtc_Word16 *acfptr, *pptr, *wptr, *p1ptr, *w1ptr, ACF[WEBRTC_SPL_MAX_LPC_ORDER], + P[WEBRTC_SPL_MAX_LPC_ORDER], W[WEBRTC_SPL_MAX_LPC_ORDER]; + + // Initialize loop and pointers. + acfptr = ACF; + rptr = R; + pptr = P; + p1ptr = &P[1]; + w1ptr = &W[1]; + wptr = w1ptr; + + // First loop; n=0. Determine shifting. + tmp = WebRtcSpl_NormW32(*R); + *acfptr = (WebRtc_Word16)((*rptr++ << tmp) >> 16); + *pptr++ = *acfptr++; + + // Initialize ACF, P and W. + for (i = 1; i <= use_order; i++) + { + *acfptr = (WebRtc_Word16)((*rptr++ << tmp) >> 16); + *wptr++ = *acfptr; + *pptr++ = *acfptr++; + } + + // Compute reflection coefficients. + for (n = 1; n <= use_order; n++, K++) + { + tmp = WEBRTC_SPL_ABS_W16(*p1ptr); + if (*P < tmp) + { + for (i = n; i <= use_order; i++) + *K++ = 0; + + return; + } + + // Division: WebRtcSpl_div(tmp, *P) + *K = 0; + if (tmp != 0) + { + L_num = tmp; + L_den = *P; + i = 15; + while (i--) + { + (*K) <<= 1; + L_num <<= 1; + if (L_num >= L_den) + { + L_num -= L_den; + (*K)++; + } + } + if (*p1ptr > 0) + *K = -*K; + } + + // Last iteration; don't do Schur recursion. + if (n == use_order) + return; + + // Schur recursion. + pptr = P; + wptr = w1ptr; + tmp = (WebRtc_Word16)(((WebRtc_Word32)*p1ptr * (WebRtc_Word32)*K + 16384) >> 15); + *pptr = WEBRTC_SPL_ADD_SAT_W16( *pptr, tmp ); + pptr++; + for (i = 1; i <= use_order - n; i++) + { + tmp = (WebRtc_Word16)(((WebRtc_Word32)*wptr * (WebRtc_Word32)*K + 16384) >> 15); + *pptr = WEBRTC_SPL_ADD_SAT_W16( *(pptr+1), tmp ); + pptr++; + tmp = (WebRtc_Word16)(((WebRtc_Word32)*pptr * (WebRtc_Word32)*K + 16384) >> 15); + *wptr = WEBRTC_SPL_ADD_SAT_W16( *wptr, tmp ); + wptr++; + } + } +} diff --git a/libs/miniwebrtc/audio/common/processing/auto_correlation.c b/libs/miniwebrtc/audio/common/processing/auto_correlation.c new file mode 100644 index 00000000..a00fde4b --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/auto_correlation.c @@ -0,0 +1,141 @@ +/* + * 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 contains the function WebRtcSpl_AutoCorrelation(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "signal_processing_library.h" + +int WebRtcSpl_AutoCorrelation(G_CONST WebRtc_Word16* in_vector, + int in_vector_length, + int order, + WebRtc_Word32* result, + int* scale) +{ + WebRtc_Word32 sum; + int i, j; + WebRtc_Word16 smax; // Sample max + G_CONST WebRtc_Word16* xptr1; + G_CONST WebRtc_Word16* xptr2; + WebRtc_Word32* resultptr; + int scaling = 0; + +#ifdef _ARM_OPT_ +#pragma message("NOTE: _ARM_OPT_ optimizations are used") + WebRtc_Word16 loops4; +#endif + + if (order < 0) + order = in_vector_length; + + // Find the max. sample + smax = WebRtcSpl_MaxAbsValueW16(in_vector, in_vector_length); + + // In order to avoid overflow when computing the sum we should scale the samples so that + // (in_vector_length * smax * smax) will not overflow. + + if (smax == 0) + { + scaling = 0; + } else + { + int nbits = WebRtcSpl_GetSizeInBits(in_vector_length); // # of bits in the sum loop + int t = WebRtcSpl_NormW32(WEBRTC_SPL_MUL(smax, smax)); // # of bits to normalize smax + + if (t > nbits) + { + scaling = 0; + } else + { + scaling = nbits - t; + } + + } + + resultptr = result; + + // Perform the actual correlation calculation + for (i = 0; i < order + 1; i++) + { + int loops = (in_vector_length - i); + sum = 0; + xptr1 = in_vector; + xptr2 = &in_vector[i]; +#ifndef _ARM_OPT_ + for (j = loops; j > 0; j--) + { + sum += WEBRTC_SPL_MUL_16_16_RSFT(*xptr1++, *xptr2++, scaling); + } +#else + loops4 = (loops >> 2) << 2; + + if (scaling == 0) + { + for (j = 0; j < loops4; j = j + 4) + { + sum += WEBRTC_SPL_MUL_16_16(*xptr1, *xptr2); + xptr1++; + xptr2++; + sum += WEBRTC_SPL_MUL_16_16(*xptr1, *xptr2); + xptr1++; + xptr2++; + sum += WEBRTC_SPL_MUL_16_16(*xptr1, *xptr2); + xptr1++; + xptr2++; + sum += WEBRTC_SPL_MUL_16_16(*xptr1, *xptr2); + xptr1++; + xptr2++; + } + + for (j = loops4; j < loops; j++) + { + sum += WEBRTC_SPL_MUL_16_16(*xptr1, *xptr2); + xptr1++; + xptr2++; + } + } + else + { + for (j = 0; j < loops4; j = j + 4) + { + sum += WEBRTC_SPL_MUL_16_16_RSFT(*xptr1, *xptr2, scaling); + xptr1++; + xptr2++; + sum += WEBRTC_SPL_MUL_16_16_RSFT(*xptr1, *xptr2, scaling); + xptr1++; + xptr2++; + sum += WEBRTC_SPL_MUL_16_16_RSFT(*xptr1, *xptr2, scaling); + xptr1++; + xptr2++; + sum += WEBRTC_SPL_MUL_16_16_RSFT(*xptr1, *xptr2, scaling); + xptr1++; + xptr2++; + } + + for (j = loops4; j < loops; j++) + { + sum += WEBRTC_SPL_MUL_16_16_RSFT(*xptr1, *xptr2, scaling); + xptr1++; + xptr2++; + } + } + +#endif + *resultptr++ = sum; + } + + *scale = scaling; + + return order + 1; +} diff --git a/libs/miniwebrtc/audio/common/processing/complex_bit_reverse.c b/libs/miniwebrtc/audio/common/processing/complex_bit_reverse.c new file mode 100644 index 00000000..02fde1e9 --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/complex_bit_reverse.c @@ -0,0 +1,109 @@ +/* + * 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 "signal_processing_library.h" + +/* Tables for data buffer indexes that are bit reversed and thus need to be + * swapped. Note that, index_7[{0, 2, 4, ...}] are for the left side of the swap + * operations, while index_7[{1, 3, 5, ...}] are for the right side of the + * operation. Same for index_8. + */ + +/* Indexes for the case of stages == 7. */ +static const int16_t index_7[112] = { + 1, 64, 2, 32, 3, 96, 4, 16, 5, 80, 6, 48, 7, 112, 9, 72, 10, 40, 11, 104, + 12, 24, 13, 88, 14, 56, 15, 120, 17, 68, 18, 36, 19, 100, 21, 84, 22, 52, + 23, 116, 25, 76, 26, 44, 27, 108, 29, 92, 30, 60, 31, 124, 33, 66, 35, 98, + 37, 82, 38, 50, 39, 114, 41, 74, 43, 106, 45, 90, 46, 58, 47, 122, 49, 70, + 51, 102, 53, 86, 55, 118, 57, 78, 59, 110, 61, 94, 63, 126, 67, 97, 69, + 81, 71, 113, 75, 105, 77, 89, 79, 121, 83, 101, 87, 117, 91, 109, 95, 125, + 103, 115, 111, 123 +}; + +/* Indexes for the case of stages == 8. */ +static const int16_t index_8[240] = { + 1, 128, 2, 64, 3, 192, 4, 32, 5, 160, 6, 96, 7, 224, 8, 16, 9, 144, 10, 80, + 11, 208, 12, 48, 13, 176, 14, 112, 15, 240, 17, 136, 18, 72, 19, 200, 20, + 40, 21, 168, 22, 104, 23, 232, 25, 152, 26, 88, 27, 216, 28, 56, 29, 184, + 30, 120, 31, 248, 33, 132, 34, 68, 35, 196, 37, 164, 38, 100, 39, 228, 41, + 148, 42, 84, 43, 212, 44, 52, 45, 180, 46, 116, 47, 244, 49, 140, 50, 76, + 51, 204, 53, 172, 54, 108, 55, 236, 57, 156, 58, 92, 59, 220, 61, 188, 62, + 124, 63, 252, 65, 130, 67, 194, 69, 162, 70, 98, 71, 226, 73, 146, 74, 82, + 75, 210, 77, 178, 78, 114, 79, 242, 81, 138, 83, 202, 85, 170, 86, 106, 87, + 234, 89, 154, 91, 218, 93, 186, 94, 122, 95, 250, 97, 134, 99, 198, 101, + 166, 103, 230, 105, 150, 107, 214, 109, 182, 110, 118, 111, 246, 113, 142, + 115, 206, 117, 174, 119, 238, 121, 158, 123, 222, 125, 190, 127, 254, 131, + 193, 133, 161, 135, 225, 137, 145, 139, 209, 141, 177, 143, 241, 147, 201, + 149, 169, 151, 233, 155, 217, 157, 185, 159, 249, 163, 197, 167, 229, 171, + 213, 173, 181, 175, 245, 179, 205, 183, 237, 187, 221, 191, 253, 199, 227, + 203, 211, 207, 243, 215, 235, 223, 251, 239, 247 +}; + +void WebRtcSpl_ComplexBitReverse(int16_t* __restrict complex_data, int stages) { + /* For any specific value of stages, we know exactly the indexes that are + * bit reversed. Currently (Feb. 2012) in WebRTC the only possible values of + * stages are 7 and 8, so we use tables to save unnecessary iterations and + * calculations for these two cases. + */ + if (stages == 7 || stages == 8) { + int m = 0; + int length = 112; + const int16_t* index = index_7; + + if (stages == 8) { + length = 240; + index = index_8; + } + + /* Decimation in time. Swap the elements with bit-reversed indexes. */ + for (m = 0; m < length; m += 2) { + /* We declare a int32_t* type pointer, to load both the 16-bit real + * and imaginary elements from complex_data in one instruction, reducing + * complexity. + */ + int32_t* complex_data_ptr = (int32_t*)complex_data; + int32_t temp = 0; + + temp = complex_data_ptr[index[m]]; /* Real and imaginary */ + complex_data_ptr[index[m]] = complex_data_ptr[index[m + 1]]; + complex_data_ptr[index[m + 1]] = temp; + } + } + else { + int m = 0, mr = 0, l = 0; + int n = 1 << stages; + int nn = n - 1; + + /* Decimation in time - re-order data */ + for (m = 1; m <= nn; ++m) { + int32_t* complex_data_ptr = (int32_t*)complex_data; + int32_t temp = 0; + + /* Find out indexes that are bit-reversed. */ + l = n; + do { + l >>= 1; + } while (l > nn - mr); + mr = (mr & (l - 1)) + l; + + if (mr <= m) { + continue; + } + + /* Swap the elements with bit-reversed indexes. + * This is similar to the loop in the stages == 7 or 8 cases. + */ + temp = complex_data_ptr[m]; /* Real and imaginary */ + complex_data_ptr[m] = complex_data_ptr[mr]; + complex_data_ptr[mr] = temp; + } + } +} + diff --git a/libs/miniwebrtc/audio/common/processing/complex_fft.c b/libs/miniwebrtc/audio/common/processing/complex_fft.c new file mode 100644 index 00000000..1e8503c2 --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/complex_fft.c @@ -0,0 +1,425 @@ +/* + * 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 contains the function WebRtcSpl_ComplexFFT(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "signal_processing_library.h" + +#define CFFTSFT 14 +#define CFFTRND 1 +#define CFFTRND2 16384 + +#define CIFFTSFT 14 +#define CIFFTRND 1 + +static const WebRtc_Word16 kSinTable1024[] = { + 0, 201, 402, 603, 804, 1005, 1206, 1406, + 1607, 1808, 2009, 2209, 2410, 2610, 2811, 3011, + 3211, 3411, 3611, 3811, 4011, 4210, 4409, 4608, + 4807, 5006, 5205, 5403, 5601, 5799, 5997, 6195, + 6392, 6589, 6786, 6982, 7179, 7375, 7571, 7766, + 7961, 8156, 8351, 8545, 8739, 8932, 9126, 9319, + 9511, 9703, 9895, 10087, 10278, 10469, 10659, 10849, + 11038, 11227, 11416, 11604, 11792, 11980, 12166, 12353, + 12539, 12724, 12909, 13094, 13278, 13462, 13645, 13827, + 14009, 14191, 14372, 14552, 14732, 14911, 15090, 15268, + 15446, 15623, 15799, 15975, 16150, 16325, 16499, 16672, + 16845, 17017, 17189, 17360, 17530, 17699, 17868, 18036, + 18204, 18371, 18537, 18702, 18867, 19031, 19194, 19357, + 19519, 19680, 19840, 20000, 20159, 20317, 20474, 20631, + 20787, 20942, 21096, 21249, 21402, 21554, 21705, 21855, + 22004, 22153, 22301, 22448, 22594, 22739, 22883, 23027, + 23169, 23311, 23452, 23592, 23731, 23869, 24006, 24143, + 24278, 24413, 24546, 24679, 24811, 24942, 25072, 25201, + 25329, 25456, 25582, 25707, 25831, 25954, 26077, 26198, + 26318, 26437, 26556, 26673, 26789, 26905, 27019, 27132, + 27244, 27355, 27466, 27575, 27683, 27790, 27896, 28001, + 28105, 28208, 28309, 28410, 28510, 28608, 28706, 28802, + 28897, 28992, 29085, 29177, 29268, 29358, 29446, 29534, + 29621, 29706, 29790, 29873, 29955, 30036, 30116, 30195, + 30272, 30349, 30424, 30498, 30571, 30643, 30713, 30783, + 30851, 30918, 30984, 31049, + 31113, 31175, 31236, 31297, + 31356, 31413, 31470, 31525, 31580, 31633, 31684, 31735, + 31785, 31833, 31880, 31926, 31970, 32014, 32056, 32097, + 32137, 32176, 32213, 32249, 32284, 32318, 32350, 32382, + 32412, 32441, 32468, 32495, 32520, 32544, 32567, 32588, + 32609, 32628, 32646, 32662, 32678, 32692, 32705, 32717, + 32727, 32736, 32744, 32751, 32757, 32761, 32764, 32766, + 32767, 32766, 32764, 32761, 32757, 32751, 32744, 32736, + 32727, 32717, 32705, 32692, 32678, 32662, 32646, 32628, + 32609, 32588, 32567, 32544, 32520, 32495, 32468, 32441, + 32412, 32382, 32350, 32318, 32284, 32249, 32213, 32176, + 32137, 32097, 32056, 32014, 31970, 31926, 31880, 31833, + 31785, 31735, 31684, 31633, 31580, 31525, 31470, 31413, + 31356, 31297, 31236, 31175, 31113, 31049, 30984, 30918, + 30851, 30783, 30713, 30643, 30571, 30498, 30424, 30349, + 30272, 30195, 30116, 30036, 29955, 29873, 29790, 29706, + 29621, 29534, 29446, 29358, 29268, 29177, 29085, 28992, + 28897, 28802, 28706, 28608, 28510, 28410, 28309, 28208, + 28105, 28001, 27896, 27790, 27683, 27575, 27466, 27355, + 27244, 27132, 27019, 26905, 26789, 26673, 26556, 26437, + 26318, 26198, 26077, 25954, 25831, 25707, 25582, 25456, + 25329, 25201, 25072, 24942, 24811, 24679, 24546, 24413, + 24278, 24143, 24006, 23869, 23731, 23592, 23452, 23311, + 23169, 23027, 22883, 22739, 22594, 22448, 22301, 22153, + 22004, 21855, 21705, 21554, 21402, 21249, 21096, 20942, + 20787, 20631, 20474, 20317, 20159, 20000, 19840, 19680, + 19519, 19357, 19194, 19031, 18867, 18702, 18537, 18371, + 18204, 18036, 17868, 17699, 17530, 17360, 17189, 17017, + 16845, 16672, 16499, 16325, 16150, 15975, 15799, 15623, + 15446, 15268, 15090, 14911, 14732, 14552, 14372, 14191, + 14009, 13827, 13645, 13462, 13278, 13094, 12909, 12724, + 12539, 12353, 12166, 11980, 11792, 11604, 11416, 11227, + 11038, 10849, 10659, 10469, 10278, 10087, 9895, 9703, + 9511, 9319, 9126, 8932, 8739, 8545, 8351, 8156, + 7961, 7766, 7571, 7375, 7179, 6982, 6786, 6589, + 6392, 6195, 5997, 5799, 5601, 5403, 5205, 5006, + 4807, 4608, 4409, 4210, 4011, 3811, 3611, 3411, + 3211, 3011, 2811, 2610, 2410, 2209, 2009, 1808, + 1607, 1406, 1206, 1005, 804, 603, 402, 201, + 0, -201, -402, -603, -804, -1005, -1206, -1406, + -1607, -1808, -2009, -2209, -2410, -2610, -2811, -3011, + -3211, -3411, -3611, -3811, -4011, -4210, -4409, -4608, + -4807, -5006, -5205, -5403, -5601, -5799, -5997, -6195, + -6392, -6589, -6786, -6982, -7179, -7375, -7571, -7766, + -7961, -8156, -8351, -8545, -8739, -8932, -9126, -9319, + -9511, -9703, -9895, -10087, -10278, -10469, -10659, -10849, + -11038, -11227, -11416, -11604, -11792, -11980, -12166, -12353, + -12539, -12724, -12909, -13094, -13278, -13462, -13645, -13827, + -14009, -14191, -14372, -14552, -14732, -14911, -15090, -15268, + -15446, -15623, -15799, -15975, -16150, -16325, -16499, -16672, + -16845, -17017, -17189, -17360, -17530, -17699, -17868, -18036, + -18204, -18371, -18537, -18702, -18867, -19031, -19194, -19357, + -19519, -19680, -19840, -20000, -20159, -20317, -20474, -20631, + -20787, -20942, -21096, -21249, -21402, -21554, -21705, -21855, + -22004, -22153, -22301, -22448, -22594, -22739, -22883, -23027, + -23169, -23311, -23452, -23592, -23731, -23869, -24006, -24143, + -24278, -24413, -24546, -24679, -24811, -24942, -25072, -25201, + -25329, -25456, -25582, -25707, -25831, -25954, -26077, -26198, + -26318, -26437, -26556, -26673, -26789, -26905, -27019, -27132, + -27244, -27355, -27466, -27575, -27683, -27790, -27896, -28001, + -28105, -28208, -28309, -28410, -28510, -28608, -28706, -28802, + -28897, -28992, -29085, -29177, -29268, -29358, -29446, -29534, + -29621, -29706, -29790, -29873, -29955, -30036, -30116, -30195, + -30272, -30349, -30424, -30498, -30571, -30643, -30713, -30783, + -30851, -30918, -30984, -31049, -31113, -31175, -31236, -31297, + -31356, -31413, -31470, -31525, -31580, -31633, -31684, -31735, + -31785, -31833, -31880, -31926, -31970, -32014, -32056, -32097, + -32137, -32176, -32213, -32249, -32284, -32318, -32350, -32382, + -32412, -32441, -32468, -32495, -32520, -32544, -32567, -32588, + -32609, -32628, -32646, -32662, -32678, -32692, -32705, -32717, + -32727, -32736, -32744, -32751, -32757, -32761, -32764, -32766, + -32767, -32766, -32764, -32761, -32757, -32751, -32744, -32736, + -32727, -32717, -32705, -32692, -32678, -32662, -32646, -32628, + -32609, -32588, -32567, -32544, -32520, -32495, -32468, -32441, + -32412, -32382, -32350, -32318, -32284, -32249, -32213, -32176, + -32137, -32097, -32056, -32014, -31970, -31926, -31880, -31833, + -31785, -31735, -31684, -31633, -31580, -31525, -31470, -31413, + -31356, -31297, -31236, -31175, -31113, -31049, -30984, -30918, + -30851, -30783, -30713, -30643, -30571, -30498, -30424, -30349, + -30272, -30195, -30116, -30036, -29955, -29873, -29790, -29706, + -29621, -29534, -29446, -29358, -29268, -29177, -29085, -28992, + -28897, -28802, -28706, -28608, -28510, -28410, -28309, -28208, + -28105, -28001, -27896, -27790, -27683, -27575, -27466, -27355, + -27244, -27132, -27019, -26905, -26789, -26673, -26556, -26437, + -26318, -26198, -26077, -25954, -25831, -25707, -25582, -25456, + -25329, -25201, -25072, -24942, -24811, -24679, -24546, -24413, + -24278, -24143, -24006, -23869, -23731, -23592, -23452, -23311, + -23169, -23027, -22883, -22739, -22594, -22448, -22301, -22153, + -22004, -21855, -21705, -21554, -21402, -21249, -21096, -20942, + -20787, -20631, -20474, -20317, -20159, -20000, -19840, -19680, + -19519, -19357, -19194, -19031, -18867, -18702, -18537, -18371, + -18204, -18036, -17868, -17699, -17530, -17360, -17189, -17017, + -16845, -16672, -16499, -16325, -16150, -15975, -15799, -15623, + -15446, -15268, -15090, -14911, -14732, -14552, -14372, -14191, + -14009, -13827, -13645, -13462, -13278, -13094, -12909, -12724, + -12539, -12353, -12166, -11980, -11792, -11604, -11416, -11227, + -11038, -10849, -10659, -10469, -10278, -10087, -9895, -9703, + -9511, -9319, -9126, -8932, -8739, -8545, -8351, -8156, + -7961, -7766, -7571, -7375, -7179, -6982, -6786, -6589, + -6392, -6195, -5997, -5799, -5601, -5403, -5205, -5006, + -4807, -4608, -4409, -4210, -4011, -3811, -3611, -3411, + -3211, -3011, -2811, -2610, -2410, -2209, -2009, -1808, + -1607, -1406, -1206, -1005, -804, -603, -402, -201 +}; + +int WebRtcSpl_ComplexFFT(WebRtc_Word16 frfi[], int stages, int mode) +{ + int i, j, l, k, istep, n, m; + WebRtc_Word16 wr, wi; + WebRtc_Word32 tr32, ti32, qr32, qi32; + + /* The 1024-value is a constant given from the size of kSinTable1024[], + * and should not be changed depending on the input parameter 'stages' + */ + n = 1 << stages; + if (n > 1024) + return -1; + + l = 1; + k = 10 - 1; /* Constant for given kSinTable1024[]. Do not change + depending on the input parameter 'stages' */ + + if (mode == 0) + { + // mode==0: Low-complexity and Low-accuracy mode + while (l < n) + { + istep = l << 1; + + for (m = 0; m < l; ++m) + { + j = m << k; + + /* The 256-value is a constant given as 1/4 of the size of + * kSinTable1024[], and should not be changed depending on the input + * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2 + */ + wr = kSinTable1024[j + 256]; + wi = -kSinTable1024[j]; + + for (i = m; i < n; i += istep) + { + j = i + l; + + tr32 = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j]) + - WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j + 1])), 15); + + ti32 = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j + 1]) + + WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j])), 15); + + qr32 = (WebRtc_Word32)frfi[2 * i]; + qi32 = (WebRtc_Word32)frfi[2 * i + 1]; + frfi[2 * j] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(qr32 - tr32, 1); + frfi[2 * j + 1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(qi32 - ti32, 1); + frfi[2 * i] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(qr32 + tr32, 1); + frfi[2 * i + 1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(qi32 + ti32, 1); + } + } + + --k; + l = istep; + + } + + } else + { + // mode==1: High-complexity and High-accuracy mode + while (l < n) + { + istep = l << 1; + + for (m = 0; m < l; ++m) + { + j = m << k; + + /* The 256-value is a constant given as 1/4 of the size of + * kSinTable1024[], and should not be changed depending on the input + * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2 + */ + wr = kSinTable1024[j + 256]; + wi = -kSinTable1024[j]; + +#ifdef WEBRTC_ARCH_ARM_V7A + WebRtc_Word32 wri; + WebRtc_Word32 frfi_r; + __asm__("pkhbt %0, %1, %2, lsl #16" : "=r"(wri) : + "r"((WebRtc_Word32)wr), "r"((WebRtc_Word32)wi)); +#endif + + for (i = m; i < n; i += istep) + { + j = i + l; + +#ifdef WEBRTC_ARCH_ARM_V7A + __asm__("pkhbt %0, %1, %2, lsl #16" : "=r"(frfi_r) : + "r"((WebRtc_Word32)frfi[2*j]), "r"((WebRtc_Word32)frfi[2*j +1])); + __asm__("smlsd %0, %1, %2, %3" : "=r"(tr32) : + "r"(wri), "r"(frfi_r), "r"(CFFTRND)); + __asm__("smladx %0, %1, %2, %3" : "=r"(ti32) : + "r"(wri), "r"(frfi_r), "r"(CFFTRND)); + +#else + tr32 = WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j]) + - WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j + 1]) + CFFTRND; + + ti32 = WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j + 1]) + + WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j]) + CFFTRND; +#endif + + tr32 = WEBRTC_SPL_RSHIFT_W32(tr32, 15 - CFFTSFT); + ti32 = WEBRTC_SPL_RSHIFT_W32(ti32, 15 - CFFTSFT); + + qr32 = ((WebRtc_Word32)frfi[2 * i]) << CFFTSFT; + qi32 = ((WebRtc_Word32)frfi[2 * i + 1]) << CFFTSFT; + + frfi[2 * j] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32( + (qr32 - tr32 + CFFTRND2), 1 + CFFTSFT); + frfi[2 * j + 1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32( + (qi32 - ti32 + CFFTRND2), 1 + CFFTSFT); + frfi[2 * i] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32( + (qr32 + tr32 + CFFTRND2), 1 + CFFTSFT); + frfi[2 * i + 1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32( + (qi32 + ti32 + CFFTRND2), 1 + CFFTSFT); + } + } + + --k; + l = istep; + } + } + return 0; +} + +int WebRtcSpl_ComplexIFFT(WebRtc_Word16 frfi[], int stages, int mode) +{ + int i, j, l, k, istep, n, m, scale, shift; + WebRtc_Word16 wr, wi; + WebRtc_Word32 tr32, ti32, qr32, qi32; + WebRtc_Word32 tmp32, round2; + + /* The 1024-value is a constant given from the size of kSinTable1024[], + * and should not be changed depending on the input parameter 'stages' + */ + n = 1 << stages; + if (n > 1024) + return -1; + + scale = 0; + + l = 1; + k = 10 - 1; /* Constant for given kSinTable1024[]. Do not change + depending on the input parameter 'stages' */ + + while (l < n) + { + // variable scaling, depending upon data + shift = 0; + round2 = 8192; + + tmp32 = (WebRtc_Word32)WebRtcSpl_MaxAbsValueW16(frfi, 2 * n); + if (tmp32 > 13573) + { + shift++; + scale++; + round2 <<= 1; + } + if (tmp32 > 27146) + { + shift++; + scale++; + round2 <<= 1; + } + + istep = l << 1; + + if (mode == 0) + { + // mode==0: Low-complexity and Low-accuracy mode + for (m = 0; m < l; ++m) + { + j = m << k; + + /* The 256-value is a constant given as 1/4 of the size of + * kSinTable1024[], and should not be changed depending on the input + * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2 + */ + wr = kSinTable1024[j + 256]; + wi = kSinTable1024[j]; + + for (i = m; i < n; i += istep) + { + j = i + l; + + tr32 = WEBRTC_SPL_RSHIFT_W32((WEBRTC_SPL_MUL_16_16_RSFT(wr, frfi[2 * j], 0) + - WEBRTC_SPL_MUL_16_16_RSFT(wi, frfi[2 * j + 1], 0)), 15); + + ti32 = WEBRTC_SPL_RSHIFT_W32( + (WEBRTC_SPL_MUL_16_16_RSFT(wr, frfi[2 * j + 1], 0) + + WEBRTC_SPL_MUL_16_16_RSFT(wi,frfi[2*j],0)), 15); + + qr32 = (WebRtc_Word32)frfi[2 * i]; + qi32 = (WebRtc_Word32)frfi[2 * i + 1]; + frfi[2 * j] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(qr32 - tr32, shift); + frfi[2 * j + 1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(qi32 - ti32, shift); + frfi[2 * i] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(qr32 + tr32, shift); + frfi[2 * i + 1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(qi32 + ti32, shift); + } + } + } else + { + // mode==1: High-complexity and High-accuracy mode + + for (m = 0; m < l; ++m) + { + j = m << k; + + /* The 256-value is a constant given as 1/4 of the size of + * kSinTable1024[], and should not be changed depending on the input + * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2 + */ + wr = kSinTable1024[j + 256]; + wi = kSinTable1024[j]; + +#ifdef WEBRTC_ARCH_ARM_V7A + WebRtc_Word32 wri; + WebRtc_Word32 frfi_r; + __asm__("pkhbt %0, %1, %2, lsl #16" : "=r"(wri) : + "r"((WebRtc_Word32)wr), "r"((WebRtc_Word32)wi)); +#endif + + for (i = m; i < n; i += istep) + { + j = i + l; + +#ifdef WEBRTC_ARCH_ARM_V7A + __asm__("pkhbt %0, %1, %2, lsl #16" : "=r"(frfi_r) : + "r"((WebRtc_Word32)frfi[2*j]), "r"((WebRtc_Word32)frfi[2*j +1])); + __asm__("smlsd %0, %1, %2, %3" : "=r"(tr32) : + "r"(wri), "r"(frfi_r), "r"(CIFFTRND)); + __asm__("smladx %0, %1, %2, %3" : "=r"(ti32) : + "r"(wri), "r"(frfi_r), "r"(CIFFTRND)); +#else + + tr32 = WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j]) + - WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j + 1]) + CIFFTRND; + + ti32 = WEBRTC_SPL_MUL_16_16(wr, frfi[2 * j + 1]) + + WEBRTC_SPL_MUL_16_16(wi, frfi[2 * j]) + CIFFTRND; +#endif + tr32 = WEBRTC_SPL_RSHIFT_W32(tr32, 15 - CIFFTSFT); + ti32 = WEBRTC_SPL_RSHIFT_W32(ti32, 15 - CIFFTSFT); + + qr32 = ((WebRtc_Word32)frfi[2 * i]) << CIFFTSFT; + qi32 = ((WebRtc_Word32)frfi[2 * i + 1]) << CIFFTSFT; + + frfi[2 * j] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((qr32 - tr32+round2), + shift+CIFFTSFT); + frfi[2 * j + 1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32( + (qi32 - ti32 + round2), shift + CIFFTSFT); + frfi[2 * i] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((qr32 + tr32 + round2), + shift + CIFFTSFT); + frfi[2 * i + 1] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32( + (qi32 + ti32 + round2), shift + CIFFTSFT); + } + } + + } + --k; + l = istep; + } + return scale; +} diff --git a/libs/miniwebrtc/audio/common/processing/copy_set_operations.c b/libs/miniwebrtc/audio/common/processing/copy_set_operations.c new file mode 100644 index 00000000..82473377 --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/copy_set_operations.c @@ -0,0 +1,108 @@ +/* + * 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 contains the implementation of functions + * WebRtcSpl_MemSetW16() + * WebRtcSpl_MemSetW32() + * WebRtcSpl_MemCpyReversedOrder() + * WebRtcSpl_CopyFromEndW16() + * WebRtcSpl_ZerosArrayW16() + * WebRtcSpl_ZerosArrayW32() + * WebRtcSpl_OnesArrayW16() + * WebRtcSpl_OnesArrayW32() + * + * The description header can be found in signal_processing_library.h + * + */ + +#include +#include "signal_processing_library.h" + + +void WebRtcSpl_MemSetW16(WebRtc_Word16 *ptr, WebRtc_Word16 set_value, int length) +{ + int j; + WebRtc_Word16 *arrptr = ptr; + + for (j = length; j > 0; j--) + { + *arrptr++ = set_value; + } +} + +void WebRtcSpl_MemSetW32(WebRtc_Word32 *ptr, WebRtc_Word32 set_value, int length) +{ + int j; + WebRtc_Word32 *arrptr = ptr; + + for (j = length; j > 0; j--) + { + *arrptr++ = set_value; + } +} + +void WebRtcSpl_MemCpyReversedOrder(WebRtc_Word16* dest, WebRtc_Word16* source, int length) +{ + int j; + WebRtc_Word16* destPtr = dest; + WebRtc_Word16* sourcePtr = source; + + for (j = 0; j < length; j++) + { + *destPtr-- = *sourcePtr++; + } +} + +WebRtc_Word16 WebRtcSpl_CopyFromEndW16(G_CONST WebRtc_Word16 *vector_in, + WebRtc_Word16 length, + WebRtc_Word16 samples, + WebRtc_Word16 *vector_out) +{ + // Copy the last of the input vector to vector_out + WEBRTC_SPL_MEMCPY_W16(vector_out, &vector_in[length - samples], samples); + + return samples; +} + +WebRtc_Word16 WebRtcSpl_ZerosArrayW16(WebRtc_Word16 *vector, WebRtc_Word16 length) +{ + WebRtcSpl_MemSetW16(vector, 0, length); + return length; +} + +WebRtc_Word16 WebRtcSpl_ZerosArrayW32(WebRtc_Word32 *vector, WebRtc_Word16 length) +{ + WebRtcSpl_MemSetW32(vector, 0, length); + return length; +} + +WebRtc_Word16 WebRtcSpl_OnesArrayW16(WebRtc_Word16 *vector, WebRtc_Word16 length) +{ + WebRtc_Word16 i; + WebRtc_Word16 *tmpvec = vector; + for (i = 0; i < length; i++) + { + *tmpvec++ = 1; + } + return length; +} + +WebRtc_Word16 WebRtcSpl_OnesArrayW32(WebRtc_Word32 *vector, WebRtc_Word16 length) +{ + WebRtc_Word16 i; + WebRtc_Word32 *tmpvec = vector; + for (i = 0; i < length; i++) + { + *tmpvec++ = 1; + } + return length; +} diff --git a/libs/miniwebrtc/audio/common/processing/cross_correlation.c b/libs/miniwebrtc/audio/common/processing/cross_correlation.c new file mode 100644 index 00000000..726a7496 --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/cross_correlation.c @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* + * This file contains the function WebRtcSpl_CrossCorrelation(). + * The description header can be found in signal_processing_library.h + * + */ + +/* TODO(kma): Clean up the code in this file, and break it up for + * various platforms (Xscale, ARM/Neon etc.). + */ + +#include "signal_processing_library.h" + +void WebRtcSpl_CrossCorrelation(WebRtc_Word32* cross_correlation, WebRtc_Word16* seq1, + WebRtc_Word16* seq2, WebRtc_Word16 dim_seq, + WebRtc_Word16 dim_cross_correlation, + WebRtc_Word16 right_shifts, + WebRtc_Word16 step_seq2) +{ + int i, j; + WebRtc_Word16* seq1Ptr; + WebRtc_Word16* seq2Ptr; + WebRtc_Word32* CrossCorrPtr; + +#ifdef _XSCALE_OPT_ + +#ifdef _WIN32 +#pragma message("NOTE: _XSCALE_OPT_ optimizations are used (overrides _ARM_OPT_ and requires /QRxscale compiler flag)") +#endif + + __int64 macc40; + + int iseq1[250]; + int iseq2[250]; + int iseq3[250]; + int * iseq1Ptr; + int * iseq2Ptr; + int * iseq3Ptr; + int len, i_len; + + seq1Ptr = seq1; + iseq1Ptr = iseq1; + for(i = 0; i < ((dim_seq + 1) >> 1); i++) + { + *iseq1Ptr = (unsigned short)*seq1Ptr++; + *iseq1Ptr++ |= (WebRtc_Word32)*seq1Ptr++ << 16; + + } + + if(dim_seq%2) + { + *(iseq1Ptr-1) &= 0x0000ffff; + } + *iseq1Ptr = 0; + iseq1Ptr++; + *iseq1Ptr = 0; + iseq1Ptr++; + *iseq1Ptr = 0; + + if(step_seq2 < 0) + { + seq2Ptr = seq2 - dim_cross_correlation + 1; + CrossCorrPtr = &cross_correlation[dim_cross_correlation - 1]; + } + else + { + seq2Ptr = seq2; + CrossCorrPtr = cross_correlation; + } + + len = dim_seq + dim_cross_correlation - 1; + i_len = (len + 1) >> 1; + iseq2Ptr = iseq2; + + iseq3Ptr = iseq3; + for(i = 0; i < i_len; i++) + { + *iseq2Ptr = (unsigned short)*seq2Ptr++; + *iseq3Ptr = (unsigned short)*seq2Ptr; + *iseq2Ptr++ |= (WebRtc_Word32)*seq2Ptr++ << 16; + *iseq3Ptr++ |= (WebRtc_Word32)*seq2Ptr << 16; + } + + if(len % 2) + { + iseq2[i_len - 1] &= 0x0000ffff; + iseq3[i_len - 1] = 0; + } + else + iseq3[i_len - 1] &= 0x0000ffff; + + iseq2[i_len] = 0; + iseq3[i_len] = 0; + iseq2[i_len + 1] = 0; + iseq3[i_len + 1] = 0; + iseq2[i_len + 2] = 0; + iseq3[i_len + 2] = 0; + + // Set pointer to start value + iseq2Ptr = iseq2; + iseq3Ptr = iseq3; + + i_len = (dim_seq + 7) >> 3; + for (i = 0; i < dim_cross_correlation; i++) + { + + iseq1Ptr = iseq1; + + macc40 = 0; + + _WriteCoProcessor(macc40, 0); + + if((i & 1)) + { + iseq3Ptr = iseq3 + (i >> 1); + for (j = i_len; j > 0; j--) + { + _SmulAddPack_2SW_ACC(*iseq1Ptr++, *iseq3Ptr++); + _SmulAddPack_2SW_ACC(*iseq1Ptr++, *iseq3Ptr++); + _SmulAddPack_2SW_ACC(*iseq1Ptr++, *iseq3Ptr++); + _SmulAddPack_2SW_ACC(*iseq1Ptr++, *iseq3Ptr++); + } + } + else + { + iseq2Ptr = iseq2 + (i >> 1); + for (j = i_len; j > 0; j--) + { + _SmulAddPack_2SW_ACC(*iseq1Ptr++, *iseq2Ptr++); + _SmulAddPack_2SW_ACC(*iseq1Ptr++, *iseq2Ptr++); + _SmulAddPack_2SW_ACC(*iseq1Ptr++, *iseq2Ptr++); + _SmulAddPack_2SW_ACC(*iseq1Ptr++, *iseq2Ptr++); + } + + } + + macc40 = _ReadCoProcessor(0); + *CrossCorrPtr = (WebRtc_Word32)(macc40 >> right_shifts); + CrossCorrPtr += step_seq2; + } +#else // #ifdef _XSCALE_OPT_ +#ifdef _ARM_OPT_ + WebRtc_Word16 dim_seq8 = (dim_seq >> 3) << 3; +#endif + + CrossCorrPtr = cross_correlation; + + for (i = 0; i < dim_cross_correlation; i++) + { + // Set the pointer to the static vector, set the pointer to the sliding vector + // and initialize cross_correlation + seq1Ptr = seq1; + seq2Ptr = seq2 + (step_seq2 * i); + (*CrossCorrPtr) = 0; + +#ifndef _ARM_OPT_ +#ifdef _WIN32 +#pragma message("NOTE: default implementation is used") +#endif + // Perform the cross correlation + for (j = 0; j < dim_seq; j++) + { + (*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16_RSFT((*seq1Ptr), (*seq2Ptr), right_shifts); + seq1Ptr++; + seq2Ptr++; + } +#else +#ifdef _WIN32 +#pragma message("NOTE: _ARM_OPT_ optimizations are used") +#endif + if (right_shifts == 0) + { + // Perform the optimized cross correlation + for (j = 0; j < dim_seq8; j = j + 8) + { + (*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16((*seq1Ptr), (*seq2Ptr)); + seq1Ptr++; + seq2Ptr++; + (*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16((*seq1Ptr), (*seq2Ptr)); + seq1Ptr++; + seq2Ptr++; + (*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16((*seq1Ptr), (*seq2Ptr)); + seq1Ptr++; + seq2Ptr++; + (*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16((*seq1Ptr), (*seq2Ptr)); + seq1Ptr++; + seq2Ptr++; + (*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16((*seq1Ptr), (*seq2Ptr)); + seq1Ptr++; + seq2Ptr++; + (*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16((*seq1Ptr), (*seq2Ptr)); + seq1Ptr++; + seq2Ptr++; + (*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16((*seq1Ptr), (*seq2Ptr)); + seq1Ptr++; + seq2Ptr++; + (*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16((*seq1Ptr), (*seq2Ptr)); + seq1Ptr++; + seq2Ptr++; + } + + for (j = dim_seq8; j < dim_seq; j++) + { + (*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16((*seq1Ptr), (*seq2Ptr)); + seq1Ptr++; + seq2Ptr++; + } + } + else // right_shifts != 0 + + { + // Perform the optimized cross correlation + for (j = 0; j < dim_seq8; j = j + 8) + { + (*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16_RSFT((*seq1Ptr), (*seq2Ptr), + right_shifts); + seq1Ptr++; + seq2Ptr++; + (*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16_RSFT((*seq1Ptr), (*seq2Ptr), + right_shifts); + seq1Ptr++; + seq2Ptr++; + (*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16_RSFT((*seq1Ptr), (*seq2Ptr), + right_shifts); + seq1Ptr++; + seq2Ptr++; + (*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16_RSFT((*seq1Ptr), (*seq2Ptr), + right_shifts); + seq1Ptr++; + seq2Ptr++; + (*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16_RSFT((*seq1Ptr), (*seq2Ptr), + right_shifts); + seq1Ptr++; + seq2Ptr++; + (*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16_RSFT((*seq1Ptr), (*seq2Ptr), + right_shifts); + seq1Ptr++; + seq2Ptr++; + (*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16_RSFT((*seq1Ptr), (*seq2Ptr), + right_shifts); + seq1Ptr++; + seq2Ptr++; + (*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16_RSFT((*seq1Ptr), (*seq2Ptr), + right_shifts); + seq1Ptr++; + seq2Ptr++; + } + + for (j = dim_seq8; j < dim_seq; j++) + { + (*CrossCorrPtr) += WEBRTC_SPL_MUL_16_16_RSFT((*seq1Ptr), (*seq2Ptr), + right_shifts); + seq1Ptr++; + seq2Ptr++; + } + } +#endif + CrossCorrPtr++; + } +#endif +} diff --git a/libs/miniwebrtc/audio/common/processing/division_operations.c b/libs/miniwebrtc/audio/common/processing/division_operations.c new file mode 100644 index 00000000..b143373a --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/division_operations.c @@ -0,0 +1,144 @@ +/* + * 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 contains implementations of the divisions + * WebRtcSpl_DivU32U16() + * WebRtcSpl_DivW32W16() + * WebRtcSpl_DivW32W16ResW16() + * WebRtcSpl_DivResultInQ31() + * WebRtcSpl_DivW32HiLow() + * + * The description header can be found in signal_processing_library.h + * + */ + +#include "signal_processing_library.h" + +WebRtc_UWord32 WebRtcSpl_DivU32U16(WebRtc_UWord32 num, WebRtc_UWord16 den) +{ + // Guard against division with 0 + if (den != 0) + { + return (WebRtc_UWord32)(num / den); + } else + { + return (WebRtc_UWord32)0xFFFFFFFF; + } +} + +WebRtc_Word32 WebRtcSpl_DivW32W16(WebRtc_Word32 num, WebRtc_Word16 den) +{ + // Guard against division with 0 + if (den != 0) + { + return (WebRtc_Word32)(num / den); + } else + { + return (WebRtc_Word32)0x7FFFFFFF; + } +} + +WebRtc_Word16 WebRtcSpl_DivW32W16ResW16(WebRtc_Word32 num, WebRtc_Word16 den) +{ + // Guard against division with 0 + if (den != 0) + { + return (WebRtc_Word16)(num / den); + } else + { + return (WebRtc_Word16)0x7FFF; + } +} + +WebRtc_Word32 WebRtcSpl_DivResultInQ31(WebRtc_Word32 num, WebRtc_Word32 den) +{ + WebRtc_Word32 L_num = num; + WebRtc_Word32 L_den = den; + WebRtc_Word32 div = 0; + int k = 31; + int change_sign = 0; + + if (num == 0) + return 0; + + if (num < 0) + { + change_sign++; + L_num = -num; + } + if (den < 0) + { + change_sign++; + L_den = -den; + } + while (k--) + { + div <<= 1; + L_num <<= 1; + if (L_num >= L_den) + { + L_num -= L_den; + div++; + } + } + if (change_sign == 1) + { + div = -div; + } + return div; +} + +WebRtc_Word32 WebRtcSpl_DivW32HiLow(WebRtc_Word32 num, WebRtc_Word16 den_hi, + WebRtc_Word16 den_low) +{ + WebRtc_Word16 approx, tmp_hi, tmp_low, num_hi, num_low; + WebRtc_Word32 tmpW32; + + approx = (WebRtc_Word16)WebRtcSpl_DivW32W16((WebRtc_Word32)0x1FFFFFFF, den_hi); + // result in Q14 (Note: 3FFFFFFF = 0.5 in Q30) + + // tmpW32 = 1/den = approx * (2.0 - den * approx) (in Q30) + tmpW32 = (WEBRTC_SPL_MUL_16_16(den_hi, approx) << 1) + + ((WEBRTC_SPL_MUL_16_16(den_low, approx) >> 15) << 1); + // tmpW32 = den * approx + + tmpW32 = (WebRtc_Word32)0x7fffffffL - tmpW32; // result in Q30 (tmpW32 = 2.0-(den*approx)) + + // Store tmpW32 in hi and low format + tmp_hi = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmpW32, 16); + tmp_low = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((tmpW32 + - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)tmp_hi, 16)), 1); + + // tmpW32 = 1/den in Q29 + tmpW32 = ((WEBRTC_SPL_MUL_16_16(tmp_hi, approx) + (WEBRTC_SPL_MUL_16_16(tmp_low, approx) + >> 15)) << 1); + + // 1/den in hi and low format + tmp_hi = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmpW32, 16); + tmp_low = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((tmpW32 + - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)tmp_hi, 16)), 1); + + // Store num in hi and low format + num_hi = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(num, 16); + num_low = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((num + - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)num_hi, 16)), 1); + + // num * (1/den) by 32 bit multiplication (result in Q28) + + tmpW32 = (WEBRTC_SPL_MUL_16_16(num_hi, tmp_hi) + (WEBRTC_SPL_MUL_16_16(num_hi, tmp_low) + >> 15) + (WEBRTC_SPL_MUL_16_16(num_low, tmp_hi) >> 15)); + + // Put result in Q31 (convert from Q28) + tmpW32 = WEBRTC_SPL_LSHIFT_W32(tmpW32, 3); + + return tmpW32; +} diff --git a/libs/miniwebrtc/audio/common/processing/dot_product_with_scale.c b/libs/miniwebrtc/audio/common/processing/dot_product_with_scale.c new file mode 100644 index 00000000..6e085fdb --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/dot_product_with_scale.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* + * This file contains the function WebRtcSpl_DotProductWithScale(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "signal_processing_library.h" + +WebRtc_Word32 WebRtcSpl_DotProductWithScale(WebRtc_Word16 *vector1, WebRtc_Word16 *vector2, + int length, int scaling) +{ + WebRtc_Word32 sum; + int i; +#ifdef _ARM_OPT_ +#pragma message("NOTE: _ARM_OPT_ optimizations are used") + WebRtc_Word16 len4 = (length >> 2) << 2; +#endif + + sum = 0; + +#ifndef _ARM_OPT_ + for (i = 0; i < length; i++) + { + sum += WEBRTC_SPL_MUL_16_16_RSFT(*vector1++, *vector2++, scaling); + } +#else + if (scaling == 0) + { + for (i = 0; i < len4; i = i + 4) + { + sum += WEBRTC_SPL_MUL_16_16(*vector1, *vector2); + vector1++; + vector2++; + sum += WEBRTC_SPL_MUL_16_16(*vector1, *vector2); + vector1++; + vector2++; + sum += WEBRTC_SPL_MUL_16_16(*vector1, *vector2); + vector1++; + vector2++; + sum += WEBRTC_SPL_MUL_16_16(*vector1, *vector2); + vector1++; + vector2++; + } + + for (i = len4; i < length; i++) + { + sum += WEBRTC_SPL_MUL_16_16(*vector1, *vector2); + vector1++; + vector2++; + } + } + else + { + for (i = 0; i < len4; i = i + 4) + { + sum += WEBRTC_SPL_MUL_16_16_RSFT(*vector1, *vector2, scaling); + vector1++; + vector2++; + sum += WEBRTC_SPL_MUL_16_16_RSFT(*vector1, *vector2, scaling); + vector1++; + vector2++; + sum += WEBRTC_SPL_MUL_16_16_RSFT(*vector1, *vector2, scaling); + vector1++; + vector2++; + sum += WEBRTC_SPL_MUL_16_16_RSFT(*vector1, *vector2, scaling); + vector1++; + vector2++; + } + + for (i = len4; i < length; i++) + { + sum += WEBRTC_SPL_MUL_16_16_RSFT(*vector1, *vector2, scaling); + vector1++; + vector2++; + } + } +#endif + + return sum; +} diff --git a/libs/miniwebrtc/audio/common/processing/downsample_fast.c b/libs/miniwebrtc/audio/common/processing/downsample_fast.c new file mode 100644 index 00000000..526cdca8 --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/downsample_fast.c @@ -0,0 +1,47 @@ +/* + * 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 "signal_processing_library.h" + +// TODO(Bjornv): Change the function parameter order to WebRTC code style. +int WebRtcSpl_DownsampleFast(const int16_t* data_in, + int data_in_length, + int16_t* data_out, + int data_out_length, + const int16_t* __restrict coefficients, + int coefficients_length, + int factor, + int delay) { + int i = 0; + int j = 0; + int32_t out_s32 = 0; + int endpos = delay + factor * (data_out_length - 1) + 1; + + // Return error if any of the running conditions doesn't meet. + if (data_out_length <= 0 || coefficients_length <= 0 + || data_in_length < endpos) { + return -1; + } + + for (i = delay; i < endpos; i += factor) { + out_s32 = 2048; // Round value, 0.5 in Q12. + + for (j = 0; j < coefficients_length; j++) { + out_s32 += coefficients[j] * data_in[i - j]; // Q12. + } + + out_s32 >>= 12; // Q0. + + // Saturate and store the output. + *data_out++ = WebRtcSpl_SatW32ToW16(out_s32); + } + + return 0; +} diff --git a/libs/miniwebrtc/audio/common/processing/energy.c b/libs/miniwebrtc/audio/common/processing/energy.c new file mode 100644 index 00000000..e8fdf94e --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/energy.c @@ -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. + */ + + +/* + * This file contains the function WebRtcSpl_Energy(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "signal_processing_library.h" + +WebRtc_Word32 WebRtcSpl_Energy(WebRtc_Word16* vector, int vector_length, int* scale_factor) +{ + WebRtc_Word32 en = 0; + int i; + int scaling = WebRtcSpl_GetScalingSquare(vector, vector_length, vector_length); + int looptimes = vector_length; + WebRtc_Word16 *vectorptr = vector; + + for (i = 0; i < looptimes; i++) + { + en += WEBRTC_SPL_MUL_16_16_RSFT(*vectorptr, *vectorptr, scaling); + vectorptr++; + } + *scale_factor = scaling; + + return en; +} diff --git a/libs/miniwebrtc/audio/common/processing/filter_ar.c b/libs/miniwebrtc/audio/common/processing/filter_ar.c new file mode 100644 index 00000000..24e83a6b --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/filter_ar.c @@ -0,0 +1,89 @@ +/* + * 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 contains the function WebRtcSpl_FilterAR(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "signal_processing_library.h" + +int WebRtcSpl_FilterAR(G_CONST WebRtc_Word16* a, + int a_length, + G_CONST WebRtc_Word16* x, + int x_length, + WebRtc_Word16* state, + int state_length, + WebRtc_Word16* state_low, + int state_low_length, + WebRtc_Word16* filtered, + WebRtc_Word16* filtered_low, + int filtered_low_length) +{ + WebRtc_Word32 o; + WebRtc_Word32 oLOW; + int i, j, stop; + G_CONST WebRtc_Word16* x_ptr = &x[0]; + WebRtc_Word16* filteredFINAL_ptr = filtered; + WebRtc_Word16* filteredFINAL_LOW_ptr = filtered_low; + + for (i = 0; i < x_length; i++) + { + // Calculate filtered[i] and filtered_low[i] + G_CONST WebRtc_Word16* a_ptr = &a[1]; + WebRtc_Word16* filtered_ptr = &filtered[i - 1]; + WebRtc_Word16* filtered_low_ptr = &filtered_low[i - 1]; + WebRtc_Word16* state_ptr = &state[state_length - 1]; + WebRtc_Word16* state_low_ptr = &state_low[state_length - 1]; + + o = (WebRtc_Word32)(*x_ptr++) << 12; + oLOW = (WebRtc_Word32)0; + + stop = (i < a_length) ? i + 1 : a_length; + for (j = 1; j < stop; j++) + { + o -= WEBRTC_SPL_MUL_16_16(*a_ptr, *filtered_ptr--); + oLOW -= WEBRTC_SPL_MUL_16_16(*a_ptr++, *filtered_low_ptr--); + } + for (j = i + 1; j < a_length; j++) + { + o -= WEBRTC_SPL_MUL_16_16(*a_ptr, *state_ptr--); + oLOW -= WEBRTC_SPL_MUL_16_16(*a_ptr++, *state_low_ptr--); + } + + o += (oLOW >> 12); + *filteredFINAL_ptr = (WebRtc_Word16)((o + (WebRtc_Word32)2048) >> 12); + *filteredFINAL_LOW_ptr++ = (WebRtc_Word16)(o - ((WebRtc_Word32)(*filteredFINAL_ptr++) + << 12)); + } + + // Save the filter state + if (x_length >= state_length) + { + WebRtcSpl_CopyFromEndW16(filtered, x_length, a_length - 1, state); + WebRtcSpl_CopyFromEndW16(filtered_low, x_length, a_length - 1, state_low); + } else + { + for (i = 0; i < state_length - x_length; i++) + { + state[i] = state[i + x_length]; + state_low[i] = state_low[i + x_length]; + } + for (i = 0; i < x_length; i++) + { + state[state_length - x_length + i] = filtered[i]; + state[state_length - x_length + i] = filtered_low[i]; + } + } + + return x_length; +} diff --git a/libs/miniwebrtc/audio/common/processing/filter_ar_fast_q12.c b/libs/miniwebrtc/audio/common/processing/filter_ar_fast_q12.c new file mode 100644 index 00000000..04023027 --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/filter_ar_fast_q12.c @@ -0,0 +1,43 @@ +/* + * 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 + +#include "signal_processing_library.h" + +// TODO(bjornv): Change the return type to report errors. + +void WebRtcSpl_FilterARFastQ12(const int16_t* data_in, + int16_t* data_out, + const int16_t* __restrict coefficients, + int coefficients_length, + int data_length) { + int i = 0; + int j = 0; + + assert(data_length > 0); + assert(coefficients_length > 1); + + for (i = 0; i < data_length; i++) { + int32_t output = 0; + int32_t sum = 0; + + for (j = coefficients_length - 1; j > 0; j--) { + sum += coefficients[j] * data_out[i - j]; + } + + output = coefficients[0] * data_in[i]; + output -= sum; + + // Saturate and store the output. + output = WEBRTC_SPL_SAT(134215679, output, -134217728); + data_out[i] = (int16_t)((output + 2048) >> 12); + } +} + diff --git a/libs/miniwebrtc/audio/common/processing/filter_ma_fast_q12.c b/libs/miniwebrtc/audio/common/processing/filter_ma_fast_q12.c new file mode 100644 index 00000000..19ad9b16 --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/filter_ma_fast_q12.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. + */ + + +/* + * This file contains the function WebRtcSpl_FilterMAFastQ12(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "signal_processing_library.h" + +void WebRtcSpl_FilterMAFastQ12(WebRtc_Word16* in_ptr, + WebRtc_Word16* out_ptr, + WebRtc_Word16* B, + WebRtc_Word16 B_length, + WebRtc_Word16 length) +{ + WebRtc_Word32 o; + int i, j; + for (i = 0; i < length; i++) + { + G_CONST WebRtc_Word16* b_ptr = &B[0]; + G_CONST WebRtc_Word16* x_ptr = &in_ptr[i]; + + o = (WebRtc_Word32)0; + + for (j = 0; j < B_length; j++) + { + o += WEBRTC_SPL_MUL_16_16(*b_ptr++, *x_ptr--); + } + + // If output is higher than 32768, saturate it. Same with negative side + // 2^27 = 134217728, which corresponds to 32768 in Q12 + + // Saturate the output + o = WEBRTC_SPL_SAT((WebRtc_Word32)134215679, o, (WebRtc_Word32)-134217728); + + *out_ptr++ = (WebRtc_Word16)((o + (WebRtc_Word32)2048) >> 12); + } + return; +} diff --git a/libs/miniwebrtc/audio/common/processing/get_hanning_window.c b/libs/miniwebrtc/audio/common/processing/get_hanning_window.c new file mode 100644 index 00000000..6d67e60f --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/get_hanning_window.c @@ -0,0 +1,77 @@ +/* + * 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 contains the function WebRtcSpl_GetHanningWindow(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "signal_processing_library.h" + +// Hanning table with 256 entries +static const WebRtc_Word16 kHanningTable[] = { + 1, 2, 6, 10, 15, 22, 30, 39, + 50, 62, 75, 89, 104, 121, 138, 157, + 178, 199, 222, 246, 271, 297, 324, 353, + 383, 413, 446, 479, 513, 549, 586, 624, + 663, 703, 744, 787, 830, 875, 920, 967, + 1015, 1064, 1114, 1165, 1218, 1271, 1325, 1381, + 1437, 1494, 1553, 1612, 1673, 1734, 1796, 1859, + 1924, 1989, 2055, 2122, 2190, 2259, 2329, 2399, + 2471, 2543, 2617, 2691, 2765, 2841, 2918, 2995, + 3073, 3152, 3232, 3312, 3393, 3475, 3558, 3641, + 3725, 3809, 3895, 3980, 4067, 4154, 4242, 4330, + 4419, 4509, 4599, 4689, 4781, 4872, 4964, 5057, + 5150, 5244, 5338, 5432, 5527, 5622, 5718, 5814, + 5910, 6007, 6104, 6202, 6299, 6397, 6495, 6594, + 6693, 6791, 6891, 6990, 7090, 7189, 7289, 7389, + 7489, 7589, 7690, 7790, 7890, 7991, 8091, 8192, + 8293, 8393, 8494, 8594, 8694, 8795, 8895, 8995, + 9095, 9195, 9294, 9394, 9493, 9593, 9691, 9790, + 9889, 9987, 10085, 10182, 10280, 10377, 10474, 10570, +10666, 10762, 10857, 10952, 11046, 11140, 11234, 11327, +11420, 11512, 11603, 11695, 11785, 11875, 11965, 12054, +12142, 12230, 12317, 12404, 12489, 12575, 12659, 12743, +12826, 12909, 12991, 13072, 13152, 13232, 13311, 13389, +13466, 13543, 13619, 13693, 13767, 13841, 13913, 13985, +14055, 14125, 14194, 14262, 14329, 14395, 14460, 14525, +14588, 14650, 14711, 14772, 14831, 14890, 14947, 15003, +15059, 15113, 15166, 15219, 15270, 15320, 15369, 15417, +15464, 15509, 15554, 15597, 15640, 15681, 15721, 15760, +15798, 15835, 15871, 15905, 15938, 15971, 16001, 16031, +16060, 16087, 16113, 16138, 16162, 16185, 16206, 16227, +16246, 16263, 16280, 16295, 16309, 16322, 16334, 16345, +16354, 16362, 16369, 16374, 16378, 16382, 16383, 16384 +}; + +void WebRtcSpl_GetHanningWindow(WebRtc_Word16 *v, WebRtc_Word16 size) +{ + int jj; + WebRtc_Word16 *vptr1; + + WebRtc_Word32 index; + WebRtc_Word32 factor = ((WebRtc_Word32)0x40000000); + + factor = WebRtcSpl_DivW32W16(factor, size); + if (size < 513) + index = (WebRtc_Word32)-0x200000; + else + index = (WebRtc_Word32)-0x100000; + vptr1 = v; + + for (jj = 0; jj < size; jj++) + { + index += factor; + (*vptr1++) = kHanningTable[index >> 22]; + } + +} diff --git a/libs/miniwebrtc/audio/common/processing/get_scaling_square.c b/libs/miniwebrtc/audio/common/processing/get_scaling_square.c new file mode 100644 index 00000000..dccbf334 --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/get_scaling_square.c @@ -0,0 +1,44 @@ +/* + * 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 contains the function WebRtcSpl_GetScalingSquare(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "signal_processing_library.h" + +int WebRtcSpl_GetScalingSquare(WebRtc_Word16 *in_vector, int in_vector_length, int times) +{ + int nbits = WebRtcSpl_GetSizeInBits(times); + int i; + WebRtc_Word16 smax = -1; + WebRtc_Word16 sabs; + WebRtc_Word16 *sptr = in_vector; + int t; + int looptimes = in_vector_length; + + for (i = looptimes; i > 0; i--) + { + sabs = (*sptr > 0 ? *sptr++ : -*sptr++); + smax = (sabs > smax ? sabs : smax); + } + t = WebRtcSpl_NormW32(WEBRTC_SPL_MUL(smax, smax)); + + if (smax == 0) + { + return 0; // Since norm(0) returns 0 + } else + { + return (t > nbits) ? 0 : nbits - t; + } +} diff --git a/libs/miniwebrtc/audio/common/processing/ilbc_specific_functions.c b/libs/miniwebrtc/audio/common/processing/ilbc_specific_functions.c new file mode 100644 index 00000000..5a9e5773 --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/ilbc_specific_functions.c @@ -0,0 +1,120 @@ +/* + * 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 contains implementations of the iLBC specific functions + * WebRtcSpl_ScaleAndAddVectorsWithRound() + * WebRtcSpl_ReverseOrderMultArrayElements() + * WebRtcSpl_ElementwiseVectorMult() + * WebRtcSpl_AddVectorsAndShift() + * WebRtcSpl_AddAffineVectorToVector() + * WebRtcSpl_AffineTransformVector() + * + * The description header can be found in signal_processing_library.h + * + */ + +#include "signal_processing_library.h" + +void WebRtcSpl_ScaleAndAddVectorsWithRound(WebRtc_Word16 *vector1, WebRtc_Word16 scale1, + WebRtc_Word16 *vector2, WebRtc_Word16 scale2, + WebRtc_Word16 right_shifts, WebRtc_Word16 *out, + WebRtc_Word16 vector_length) +{ + int i; + WebRtc_Word16 roundVal; + roundVal = 1 << right_shifts; + roundVal = roundVal >> 1; + for (i = 0; i < vector_length; i++) + { + out[i] = (WebRtc_Word16)((WEBRTC_SPL_MUL_16_16(vector1[i], scale1) + + WEBRTC_SPL_MUL_16_16(vector2[i], scale2) + roundVal) >> right_shifts); + } +} + +void WebRtcSpl_ReverseOrderMultArrayElements(WebRtc_Word16 *out, G_CONST WebRtc_Word16 *in, + G_CONST WebRtc_Word16 *win, + WebRtc_Word16 vector_length, + WebRtc_Word16 right_shifts) +{ + int i; + WebRtc_Word16 *outptr = out; + G_CONST WebRtc_Word16 *inptr = in; + G_CONST WebRtc_Word16 *winptr = win; + for (i = 0; i < vector_length; i++) + { + (*outptr++) = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(*inptr++, + *winptr--, right_shifts); + } +} + +void WebRtcSpl_ElementwiseVectorMult(WebRtc_Word16 *out, G_CONST WebRtc_Word16 *in, + G_CONST WebRtc_Word16 *win, WebRtc_Word16 vector_length, + WebRtc_Word16 right_shifts) +{ + int i; + WebRtc_Word16 *outptr = out; + G_CONST WebRtc_Word16 *inptr = in; + G_CONST WebRtc_Word16 *winptr = win; + for (i = 0; i < vector_length; i++) + { + (*outptr++) = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(*inptr++, + *winptr++, right_shifts); + } +} + +void WebRtcSpl_AddVectorsAndShift(WebRtc_Word16 *out, G_CONST WebRtc_Word16 *in1, + G_CONST WebRtc_Word16 *in2, WebRtc_Word16 vector_length, + WebRtc_Word16 right_shifts) +{ + int i; + WebRtc_Word16 *outptr = out; + G_CONST WebRtc_Word16 *in1ptr = in1; + G_CONST WebRtc_Word16 *in2ptr = in2; + for (i = vector_length; i > 0; i--) + { + (*outptr++) = (WebRtc_Word16)(((*in1ptr++) + (*in2ptr++)) >> right_shifts); + } +} + +void WebRtcSpl_AddAffineVectorToVector(WebRtc_Word16 *out, WebRtc_Word16 *in, + WebRtc_Word16 gain, WebRtc_Word32 add_constant, + WebRtc_Word16 right_shifts, int vector_length) +{ + WebRtc_Word16 *inPtr; + WebRtc_Word16 *outPtr; + int i; + + inPtr = in; + outPtr = out; + for (i = 0; i < vector_length; i++) + { + (*outPtr++) += (WebRtc_Word16)((WEBRTC_SPL_MUL_16_16((*inPtr++), gain) + + (WebRtc_Word32)add_constant) >> right_shifts); + } +} + +void WebRtcSpl_AffineTransformVector(WebRtc_Word16 *out, WebRtc_Word16 *in, + WebRtc_Word16 gain, WebRtc_Word32 add_constant, + WebRtc_Word16 right_shifts, int vector_length) +{ + WebRtc_Word16 *inPtr; + WebRtc_Word16 *outPtr; + int i; + + inPtr = in; + outPtr = out; + for (i = 0; i < vector_length; i++) + { + (*outPtr++) = (WebRtc_Word16)((WEBRTC_SPL_MUL_16_16((*inPtr++), gain) + + (WebRtc_Word32)add_constant) >> right_shifts); + } +} diff --git a/libs/miniwebrtc/audio/common/processing/levinson_durbin.c b/libs/miniwebrtc/audio/common/processing/levinson_durbin.c new file mode 100644 index 00000000..4e11cdb1 --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/levinson_durbin.c @@ -0,0 +1,259 @@ +/* + * 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 contains the function WebRtcSpl_LevinsonDurbin(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "signal_processing_library.h" + +#define SPL_LEVINSON_MAXORDER 20 + +WebRtc_Word16 WebRtcSpl_LevinsonDurbin(WebRtc_Word32 *R, WebRtc_Word16 *A, WebRtc_Word16 *K, + WebRtc_Word16 order) +{ + WebRtc_Word16 i, j; + // Auto-correlation coefficients in high precision + WebRtc_Word16 R_hi[SPL_LEVINSON_MAXORDER + 1], R_low[SPL_LEVINSON_MAXORDER + 1]; + // LPC coefficients in high precision + WebRtc_Word16 A_hi[SPL_LEVINSON_MAXORDER + 1], A_low[SPL_LEVINSON_MAXORDER + 1]; + // LPC coefficients for next iteration + WebRtc_Word16 A_upd_hi[SPL_LEVINSON_MAXORDER + 1], A_upd_low[SPL_LEVINSON_MAXORDER + 1]; + // Reflection coefficient in high precision + WebRtc_Word16 K_hi, K_low; + // Prediction gain Alpha in high precision and with scale factor + WebRtc_Word16 Alpha_hi, Alpha_low, Alpha_exp; + 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_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_MUL_16_16(R_hi[0], tmp_hi) + + (WEBRTC_SPL_MUL_16_16(R_hi[0], tmp_low) >> 15) + + (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_MUL_16_16(R_hi[j], A_hi[i-j]) << 1) + + (((WEBRTC_SPL_MUL_16_16(R_hi[j], A_low[i-j]) >> 15) + + (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 de-normalize + 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)32750) + { + return 0; // 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 = A[j] in Q27 + temp1W32 = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)A_hi[j],16) + + WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)A_low[j],1); + + // temp1W32 += K*A[i-j] in Q27 + temp1W32 += ((WEBRTC_SPL_MUL_16_16(K_hi, A_hi[i-j]) + + (WEBRTC_SPL_MUL_16_16(K_hi, A_low[i-j]) >> 15) + + (WEBRTC_SPL_MUL_16_16(K_low, A_hi[i-j]) >> 15)) << 1); + + // 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 = K in Q27 (Convert from Q31 to Q27) + temp3W32 = WEBRTC_SPL_RSHIFT_W32(temp3W32, 4); + + // 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_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_MUL_16_16(Alpha_hi, tmp_hi) + + (WEBRTC_SPL_MUL_16_16(Alpha_hi, tmp_low) >> 15) + + (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 normalization 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] = 4096; + + 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<<1)+(WebRtc_Word32)32768, 16); + } + return 1; // Stable filters +} diff --git a/libs/miniwebrtc/audio/common/processing/lpc_to_refl_coef.c b/libs/miniwebrtc/audio/common/processing/lpc_to_refl_coef.c new file mode 100644 index 00000000..2cb83c2e --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/lpc_to_refl_coef.c @@ -0,0 +1,57 @@ +/* + * 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 contains the function WebRtcSpl_LpcToReflCoef(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "signal_processing_library.h" + +#define SPL_LPC_TO_REFL_COEF_MAX_AR_MODEL_ORDER 50 + +void WebRtcSpl_LpcToReflCoef(WebRtc_Word16* a16, int use_order, WebRtc_Word16* k16) +{ + int m, k; + WebRtc_Word32 tmp32[SPL_LPC_TO_REFL_COEF_MAX_AR_MODEL_ORDER]; + WebRtc_Word32 tmp_inv_denom32; + WebRtc_Word16 tmp_inv_denom16; + + k16[use_order - 1] = WEBRTC_SPL_LSHIFT_W16(a16[use_order], 3); //Q12<<3 => Q15 + for (m = use_order - 1; m > 0; m--) + { + // (1 - k^2) in Q30 + tmp_inv_denom32 = ((WebRtc_Word32)1073741823) - WEBRTC_SPL_MUL_16_16(k16[m], k16[m]); + // (1 - k^2) in Q15 + tmp_inv_denom16 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp_inv_denom32, 15); + + for (k = 1; k <= m; k++) + { + // tmp[k] = (a[k] - RC[m] * a[m-k+1]) / (1.0 - RC[m]*RC[m]); + + // [Q12<<16 - (Q15*Q12)<<1] = [Q28 - Q28] = Q28 + tmp32[k] = 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(tmp32[k], tmp_inv_denom16); //Q28/Q15 = Q13 + } + + for (k = 1; k < m; k++) + { + a16[k] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32[k], 1); //Q13>>1 => Q12 + } + + tmp32[m] = WEBRTC_SPL_SAT(8191, tmp32[m], -8191); + k16[m - 1] = (WebRtc_Word16)WEBRTC_SPL_LSHIFT_W32(tmp32[m], 2); //Q13<<2 => Q15 + } + return; +} diff --git a/libs/miniwebrtc/audio/common/processing/min_max_operations.c b/libs/miniwebrtc/audio/common/processing/min_max_operations.c new file mode 100644 index 00000000..57eaff7b --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/min_max_operations.c @@ -0,0 +1,265 @@ +/* + * 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 contains the implementation of functions + * WebRtcSpl_MaxAbsValueW16() + * WebRtcSpl_MaxAbsIndexW16() + * WebRtcSpl_MaxAbsValueW32() + * WebRtcSpl_MaxValueW16() + * WebRtcSpl_MaxIndexW16() + * WebRtcSpl_MaxValueW32() + * WebRtcSpl_MaxIndexW32() + * WebRtcSpl_MinValueW16() + * WebRtcSpl_MinIndexW16() + * WebRtcSpl_MinValueW32() + * WebRtcSpl_MinIndexW32() + * + * The description header can be found in signal_processing_library.h. + * + */ + +#include "signal_processing_library.h" + +#if !(defined(WEBRTC_ANDROID) && defined(WEBRTC_ARCH_ARM_NEON)) + +// Maximum absolute value of word16 vector. +WebRtc_Word16 WebRtcSpl_MaxAbsValueW16(const WebRtc_Word16 *vector, WebRtc_Word16 length) +{ + WebRtc_Word32 tempMax = 0; + WebRtc_Word32 absVal; + WebRtc_Word16 totMax; + int i; + G_CONST WebRtc_Word16 *tmpvector = vector; + + for (i = 0; i < length; i++) + { + absVal = WEBRTC_SPL_ABS_W32((*tmpvector)); + if (absVal > tempMax) + { + tempMax = absVal; + } + tmpvector++; + } + totMax = (WebRtc_Word16)WEBRTC_SPL_MIN(tempMax, WEBRTC_SPL_WORD16_MAX); + return totMax; +} + +#endif + +// Index of maximum absolute value in a word16 vector. +WebRtc_Word16 WebRtcSpl_MaxAbsIndexW16(G_CONST WebRtc_Word16* vector, WebRtc_Word16 length) +{ + WebRtc_Word16 tempMax; + WebRtc_Word16 absTemp; + WebRtc_Word16 tempMaxIndex = 0; + WebRtc_Word16 i = 0; + G_CONST WebRtc_Word16 *tmpvector = vector; + + tempMax = WEBRTC_SPL_ABS_W16(*tmpvector); + tmpvector++; + for (i = 1; i < length; i++) + { + absTemp = WEBRTC_SPL_ABS_W16(*tmpvector); + tmpvector++; + if (absTemp > tempMax) + { + tempMax = absTemp; + tempMaxIndex = i; + } + } + return tempMaxIndex; +} + +// Maximum absolute value of word32 vector. +WebRtc_Word32 WebRtcSpl_MaxAbsValueW32(G_CONST WebRtc_Word32 *vector, WebRtc_Word16 length) +{ + WebRtc_UWord32 tempMax = 0; + WebRtc_UWord32 absVal; + WebRtc_Word32 retval; + int i; + G_CONST WebRtc_Word32 *tmpvector = vector; + + for (i = 0; i < length; i++) + { + absVal = WEBRTC_SPL_ABS_W32((*tmpvector)); + if (absVal > tempMax) + { + tempMax = absVal; + } + tmpvector++; + } + retval = (WebRtc_Word32)(WEBRTC_SPL_MIN(tempMax, WEBRTC_SPL_WORD32_MAX)); + return retval; +} + +// Maximum value of word16 vector. +#ifndef XSCALE_OPT +WebRtc_Word16 WebRtcSpl_MaxValueW16(G_CONST WebRtc_Word16* vector, WebRtc_Word16 length) +{ + WebRtc_Word16 tempMax; + WebRtc_Word16 i; + G_CONST WebRtc_Word16 *tmpvector = vector; + + tempMax = *tmpvector++; + for (i = 1; i < length; i++) + { + if (*tmpvector++ > tempMax) + tempMax = vector[i]; + } + return tempMax; +} +#else +#pragma message(">> WebRtcSpl_MaxValueW16 is excluded from this build") +#endif + +// Index of maximum value in a word16 vector. +WebRtc_Word16 WebRtcSpl_MaxIndexW16(G_CONST WebRtc_Word16 *vector, WebRtc_Word16 length) +{ + WebRtc_Word16 tempMax; + WebRtc_Word16 tempMaxIndex = 0; + WebRtc_Word16 i = 0; + G_CONST WebRtc_Word16 *tmpvector = vector; + + tempMax = *tmpvector++; + for (i = 1; i < length; i++) + { + if (*tmpvector++ > tempMax) + { + tempMax = vector[i]; + tempMaxIndex = i; + } + } + return tempMaxIndex; +} + +// Maximum value of word32 vector. +#ifndef XSCALE_OPT +WebRtc_Word32 WebRtcSpl_MaxValueW32(G_CONST WebRtc_Word32* vector, WebRtc_Word16 length) +{ + WebRtc_Word32 tempMax; + WebRtc_Word16 i; + G_CONST WebRtc_Word32 *tmpvector = vector; + + tempMax = *tmpvector++; + for (i = 1; i < length; i++) + { + if (*tmpvector++ > tempMax) + tempMax = vector[i]; + } + return tempMax; +} +#else +#pragma message(">> WebRtcSpl_MaxValueW32 is excluded from this build") +#endif + +// Index of maximum value in a word32 vector. +WebRtc_Word16 WebRtcSpl_MaxIndexW32(G_CONST WebRtc_Word32* vector, WebRtc_Word16 length) +{ + WebRtc_Word32 tempMax; + WebRtc_Word16 tempMaxIndex = 0; + WebRtc_Word16 i = 0; + G_CONST WebRtc_Word32 *tmpvector = vector; + + tempMax = *tmpvector++; + for (i = 1; i < length; i++) + { + if (*tmpvector++ > tempMax) + { + tempMax = vector[i]; + tempMaxIndex = i; + } + } + return tempMaxIndex; +} + +// Minimum value of word16 vector. +WebRtc_Word16 WebRtcSpl_MinValueW16(G_CONST WebRtc_Word16 *vector, WebRtc_Word16 length) +{ + WebRtc_Word16 tempMin; + WebRtc_Word16 i; + G_CONST WebRtc_Word16 *tmpvector = vector; + + // Find the minimum value + tempMin = *tmpvector++; + for (i = 1; i < length; i++) + { + if (*tmpvector++ < tempMin) + tempMin = (vector[i]); + } + return tempMin; +} + +// Index of minimum value in a word16 vector. +#ifndef XSCALE_OPT +WebRtc_Word16 WebRtcSpl_MinIndexW16(G_CONST WebRtc_Word16* vector, WebRtc_Word16 length) +{ + WebRtc_Word16 tempMin; + WebRtc_Word16 tempMinIndex = 0; + WebRtc_Word16 i = 0; + G_CONST WebRtc_Word16* tmpvector = vector; + + // Find index of smallest value + tempMin = *tmpvector++; + for (i = 1; i < length; i++) + { + if (*tmpvector++ < tempMin) + { + tempMin = vector[i]; + tempMinIndex = i; + } + } + return tempMinIndex; +} +#else +#pragma message(">> WebRtcSpl_MinIndexW16 is excluded from this build") +#endif + +// Minimum value of word32 vector. +WebRtc_Word32 WebRtcSpl_MinValueW32(G_CONST WebRtc_Word32 *vector, WebRtc_Word16 length) +{ + WebRtc_Word32 tempMin; + WebRtc_Word16 i; + G_CONST WebRtc_Word32 *tmpvector = vector; + + // Find the minimum value + tempMin = *tmpvector++; + for (i = 1; i < length; i++) + { + if (*tmpvector++ < tempMin) + tempMin = (vector[i]); + } + return tempMin; +} + +// Index of minimum value in a word32 vector. +#ifndef XSCALE_OPT +WebRtc_Word16 WebRtcSpl_MinIndexW32(G_CONST WebRtc_Word32* vector, WebRtc_Word16 length) +{ + WebRtc_Word32 tempMin; + WebRtc_Word16 tempMinIndex = 0; + WebRtc_Word16 i = 0; + G_CONST WebRtc_Word32 *tmpvector = vector; + + // Find index of smallest value + tempMin = *tmpvector++; + for (i = 1; i < length; i++) + { + if (*tmpvector++ < tempMin) + { + tempMin = vector[i]; + tempMinIndex = i; + } + } + return tempMinIndex; +} +#else +#pragma message(">> WebRtcSpl_MinIndexW32 is excluded from this build") +#endif diff --git a/libs/miniwebrtc/audio/common/processing/min_max_operations_neon.c b/libs/miniwebrtc/audio/common/processing/min_max_operations_neon.c new file mode 100644 index 00000000..158bcc18 --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/min_max_operations_neon.c @@ -0,0 +1,47 @@ +/* + * 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. + */ + +#if (defined(WEBRTC_ANDROID) && defined(WEBRTC_ARCH_ARM_NEON)) + +#include + +#include "signal_processing_library.h" + +// Maximum absolute value of word16 vector. +WebRtc_Word16 WebRtcSpl_MaxAbsValueW16(const WebRtc_Word16* vector, + WebRtc_Word16 length) { + WebRtc_Word32 temp_max = 0; + WebRtc_Word32 abs_val; + WebRtc_Word16 tot_max; + int i; + + __asm__("vmov.i16 d25, #0" : : : "d25"); + + for (i = 0; i < length - 7; i += 8) { + __asm__("vld1.16 {d26, d27}, [%0]" : : "r"(&vector[i]) : "q13"); + __asm__("vabs.s16 q13, q13" : : : "q13"); + __asm__("vpmax.s16 d26, d27" : : : "q13"); + __asm__("vpmax.s16 d25, d26" : : : "d25", "d26"); + } + __asm__("vpmax.s16 d25, d25" : : : "d25"); + __asm__("vpmax.s16 d25, d25" : : : "d25"); + __asm__("vmov.s16 %0, d25[0]" : "=r"(temp_max): : "d25"); + + for (; i < length; i++) { + abs_val = WEBRTC_SPL_ABS_W32((vector[i])); + if (abs_val > temp_max) { + temp_max = abs_val; + } + } + tot_max = (WebRtc_Word16)WEBRTC_SPL_MIN(temp_max, WEBRTC_SPL_WORD16_MAX); + return tot_max; +} + +#endif diff --git a/libs/miniwebrtc/audio/common/processing/randomization_functions.c b/libs/miniwebrtc/audio/common/processing/randomization_functions.c new file mode 100644 index 00000000..04271ada --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/randomization_functions.c @@ -0,0 +1,119 @@ +/* + * 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 contains implementations of the randomization functions + * WebRtcSpl_IncreaseSeed() + * WebRtcSpl_RandU() + * WebRtcSpl_RandN() + * WebRtcSpl_RandUArray() + * + * The description header can be found in signal_processing_library.h + * + */ + +#include "signal_processing_library.h" + +static const WebRtc_Word16 kRandNTable[] = { + 9178, -7260, 40, 10189, 4894, -3531, -13779, 14764, + -4008, -8884, -8990, 1008, 7368, 5184, 3251, -5817, + -9786, 5963, 1770, 8066, -7135, 10772, -2298, 1361, + 6484, 2241, -8633, 792, 199, -3344, 6553, -10079, + -15040, 95, 11608, -12469, 14161, -4176, 2476, 6403, + 13685, -16005, 6646, 2239, 10916, -3004, -602, -3141, + 2142, 14144, -5829, 5305, 8209, 4713, 2697, -5112, + 16092, -1210, -2891, -6631, -5360, -11878, -6781, -2739, + -6392, 536, 10923, 10872, 5059, -4748, -7770, 5477, + 38, -1025, -2892, 1638, 6304, 14375, -11028, 1553, + -1565, 10762, -393, 4040, 5257, 12310, 6554, -4799, + 4899, -6354, 1603, -1048, -2220, 8247, -186, -8944, + -12004, 2332, 4801, -4933, 6371, 131, 8614, -5927, + -8287, -22760, 4033, -15162, 3385, 3246, 3153, -5250, + 3766, 784, 6494, -62, 3531, -1582, 15572, 662, + -3952, -330, -3196, 669, 7236, -2678, -6569, 23319, + -8645, -741, 14830, -15976, 4903, 315, -11342, 10311, + 1858, -7777, 2145, 5436, 5677, -113, -10033, 826, + -1353, 17210, 7768, 986, -1471, 8291, -4982, 8207, + -14911, -6255, -2449, -11881, -7059, -11703, -4338, 8025, + 7538, -2823, -12490, 9470, -1613, -2529, -10092, -7807, + 9480, 6970, -12844, 5123, 3532, 4816, 4803, -8455, + -5045, 14032, -4378, -1643, 5756, -11041, -2732, -16618, + -6430, -18375, -3320, 6098, 5131, -4269, -8840, 2482, + -7048, 1547, -21890, -6505, -7414, -424, -11722, 7955, + 1653, -17299, 1823, 473, -9232, 3337, 1111, 873, + 4018, -8982, 9889, 3531, -11763, -3799, 7373, -4539, + 3231, 7054, -8537, 7616, 6244, 16635, 447, -2915, + 13967, 705, -2669, -1520, -1771, -16188, 5956, 5117, + 6371, -9936, -1448, 2480, 5128, 7550, -8130, 5236, + 8213, -6443, 7707, -1950, -13811, 7218, 7031, -3883, + 67, 5731, -2874, 13480, -3743, 9298, -3280, 3552, + -4425, -18, -3785, -9988, -5357, 5477, -11794, 2117, + 1416, -9935, 3376, 802, -5079, -8243, 12652, 66, + 3653, -2368, 6781, -21895, -7227, 2487, 7839, -385, + 6646, -7016, -4658, 5531, -1705, 834, 129, 3694, + -1343, 2238, -22640, -6417, -11139, 11301, -2945, -3494, + -5626, 185, -3615, -2041, -7972, -3106, -60, -23497, + -1566, 17064, 3519, 2518, 304, -6805, -10269, 2105, + 1936, -426, -736, -8122, -1467, 4238, -6939, -13309, + 360, 7402, -7970, 12576, 3287, 12194, -6289, -16006, + 9171, 4042, -9193, 9123, -2512, 6388, -4734, -8739, + 1028, -5406, -1696, 5889, -666, -4736, 4971, 3565, + 9362, -6292, 3876, -3652, -19666, 7523, -4061, 391, + -11773, 7502, -3763, 4929, -9478, 13278, 2805, 4496, + 7814, 16419, 12455, -14773, 2127, -2746, 3763, 4847, + 3698, 6978, 4751, -6957, -3581, -45, 6252, 1513, + -4797, -7925, 11270, 16188, -2359, -5269, 9376, -10777, + 7262, 20031, -6515, -2208, -5353, 8085, -1341, -1303, + 7333, 5576, 3625, 5763, -7931, 9833, -3371, -10305, + 6534, -13539, -9971, 997, 8464, -4064, -1495, 1857, + 13624, 5458, 9490, -11086, -4524, 12022, -550, -198, + 408, -8455, -7068, 10289, 9712, -3366, 9028, -7621, + -5243, 2362, 6909, 4672, -4933, -1799, 4709, -4563, + -62, -566, 1624, -7010, 14730, -17791, -3697, -2344, + -1741, 7099, -9509, -6855, -1989, 3495, -2289, 2031, + 12784, 891, 14189, -3963, -5683, 421, -12575, 1724, + -12682, -5970, -8169, 3143, -1824, -5488, -5130, 8536, + 12799, 794, 5738, 3459, -11689, -258, -3738, -3775, + -8742, 2333, 8312, -9383, 10331, 13119, 8398, 10644, + -19433, -6446, -16277, -11793, 16284, 9345, 15222, 15834, + 2009, -7349, 130, -14547, 338, -5998, 3337, 21492, + 2406, 7703, -951, 11196, -564, 3406, 2217, 4806, + 2374, -5797, 11839, 8940, -11874, 18213, 2855, 10492 +}; + +WebRtc_UWord32 WebRtcSpl_IncreaseSeed(WebRtc_UWord32 *seed) +{ + seed[0] = (seed[0] * ((WebRtc_Word32)69069) + 1) & (WEBRTC_SPL_MAX_SEED_USED - 1); + return seed[0]; +} + +WebRtc_Word16 WebRtcSpl_RandU(WebRtc_UWord32 *seed) +{ + return (WebRtc_Word16)(WebRtcSpl_IncreaseSeed(seed) >> 16); +} + +WebRtc_Word16 WebRtcSpl_RandN(WebRtc_UWord32 *seed) +{ + return kRandNTable[WebRtcSpl_IncreaseSeed(seed) >> 23]; +} + +// Creates an array of uniformly distributed variables +WebRtc_Word16 WebRtcSpl_RandUArray(WebRtc_Word16* vector, + WebRtc_Word16 vector_length, + WebRtc_UWord32* seed) +{ + int i; + for (i = 0; i < vector_length; i++) + { + vector[i] = WebRtcSpl_RandU(seed); + } + return vector_length; +} diff --git a/libs/miniwebrtc/audio/common/processing/refl_coef_to_lpc.c b/libs/miniwebrtc/audio/common/processing/refl_coef_to_lpc.c new file mode 100644 index 00000000..d07804de --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/refl_coef_to_lpc.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* + * This file contains the function WebRtcSpl_ReflCoefToLpc(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "signal_processing_library.h" + +void WebRtcSpl_ReflCoefToLpc(G_CONST WebRtc_Word16 *k, int use_order, WebRtc_Word16 *a) +{ + WebRtc_Word16 any[WEBRTC_SPL_MAX_LPC_ORDER + 1]; + WebRtc_Word16 *aptr, *aptr2, *anyptr; + G_CONST WebRtc_Word16 *kptr; + int m, i; + + kptr = k; + *a = 4096; // i.e., (Word16_MAX >> 3)+1. + *any = *a; + a[1] = WEBRTC_SPL_RSHIFT_W16((*k), 3); + + for (m = 1; m < use_order; m++) + { + kptr++; + aptr = a; + aptr++; + aptr2 = &a[m]; + anyptr = any; + anyptr++; + + any[m + 1] = WEBRTC_SPL_RSHIFT_W16((*kptr), 3); + for (i = 0; i < m; i++) + { + *anyptr = (*aptr) + + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT((*aptr2), (*kptr), 15); + anyptr++; + aptr++; + aptr2--; + } + + aptr = a; + anyptr = any; + for (i = 0; i < (m + 2); i++) + { + *aptr = *anyptr; + aptr++; + anyptr++; + } + } +} diff --git a/libs/miniwebrtc/audio/common/processing/resample.c b/libs/miniwebrtc/audio/common/processing/resample.c new file mode 100644 index 00000000..19d17785 --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/resample.c @@ -0,0 +1,505 @@ +/* + * 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 contains the resampling functions for 22 kHz. + * The description header can be found in signal_processing_library.h + * + */ + +#include "signal_processing_library.h" +#include "resample_by_2_internal.h" + +// Declaration of internally used functions +static void WebRtcSpl_32khzTo22khzIntToShort(const WebRtc_Word32 *In, WebRtc_Word16 *Out, + const WebRtc_Word32 K); + +void WebRtcSpl_32khzTo22khzIntToInt(const WebRtc_Word32 *In, WebRtc_Word32 *Out, + const WebRtc_Word32 K); + +// interpolation coefficients +static const WebRtc_Word16 kCoefficients32To22[5][9] = { + {127, -712, 2359, -6333, 23456, 16775, -3695, 945, -154}, + {-39, 230, -830, 2785, 32366, -2324, 760, -218, 38}, + {117, -663, 2222, -6133, 26634, 13070, -3174, 831, -137}, + {-77, 457, -1677, 5958, 31175, -4136, 1405, -408, 71}, + { 98, -560, 1900, -5406, 29240, 9423, -2480, 663, -110} +}; + +////////////////////// +// 22 kHz -> 16 kHz // +////////////////////// + +// number of subblocks; options: 1, 2, 4, 5, 10 +#define SUB_BLOCKS_22_16 5 + +// 22 -> 16 resampler +void WebRtcSpl_Resample22khzTo16khz(const WebRtc_Word16* in, WebRtc_Word16* out, + WebRtcSpl_State22khzTo16khz* state, WebRtc_Word32* tmpmem) +{ + int k; + + // process two blocks of 10/SUB_BLOCKS_22_16 ms (to reduce temp buffer size) + for (k = 0; k < SUB_BLOCKS_22_16; k++) + { + ///// 22 --> 44 ///// + // WebRtc_Word16 in[220/SUB_BLOCKS_22_16] + // WebRtc_Word32 out[440/SUB_BLOCKS_22_16] + ///// + WebRtcSpl_UpBy2ShortToInt(in, 220 / SUB_BLOCKS_22_16, tmpmem + 16, state->S_22_44); + + ///// 44 --> 32 ///// + // WebRtc_Word32 in[440/SUB_BLOCKS_22_16] + // WebRtc_Word32 out[320/SUB_BLOCKS_22_16] + ///// + // copy state to and from input array + tmpmem[8] = state->S_44_32[0]; + tmpmem[9] = state->S_44_32[1]; + tmpmem[10] = state->S_44_32[2]; + tmpmem[11] = state->S_44_32[3]; + tmpmem[12] = state->S_44_32[4]; + tmpmem[13] = state->S_44_32[5]; + tmpmem[14] = state->S_44_32[6]; + tmpmem[15] = state->S_44_32[7]; + state->S_44_32[0] = tmpmem[440 / SUB_BLOCKS_22_16 + 8]; + state->S_44_32[1] = tmpmem[440 / SUB_BLOCKS_22_16 + 9]; + state->S_44_32[2] = tmpmem[440 / SUB_BLOCKS_22_16 + 10]; + state->S_44_32[3] = tmpmem[440 / SUB_BLOCKS_22_16 + 11]; + state->S_44_32[4] = tmpmem[440 / SUB_BLOCKS_22_16 + 12]; + state->S_44_32[5] = tmpmem[440 / SUB_BLOCKS_22_16 + 13]; + state->S_44_32[6] = tmpmem[440 / SUB_BLOCKS_22_16 + 14]; + state->S_44_32[7] = tmpmem[440 / SUB_BLOCKS_22_16 + 15]; + + WebRtcSpl_Resample44khzTo32khz(tmpmem + 8, tmpmem, 40 / SUB_BLOCKS_22_16); + + ///// 32 --> 16 ///// + // WebRtc_Word32 in[320/SUB_BLOCKS_22_16] + // WebRtc_Word32 out[160/SUB_BLOCKS_22_16] + ///// + WebRtcSpl_DownBy2IntToShort(tmpmem, 320 / SUB_BLOCKS_22_16, out, state->S_32_16); + + // move input/output pointers 10/SUB_BLOCKS_22_16 ms seconds ahead + in += 220 / SUB_BLOCKS_22_16; + out += 160 / SUB_BLOCKS_22_16; + } +} + +// initialize state of 22 -> 16 resampler +void WebRtcSpl_ResetResample22khzTo16khz(WebRtcSpl_State22khzTo16khz* state) +{ + int k; + for (k = 0; k < 8; k++) + { + state->S_22_44[k] = 0; + state->S_44_32[k] = 0; + state->S_32_16[k] = 0; + } +} + +////////////////////// +// 16 kHz -> 22 kHz // +////////////////////// + +// number of subblocks; options: 1, 2, 4, 5, 10 +#define SUB_BLOCKS_16_22 4 + +// 16 -> 22 resampler +void WebRtcSpl_Resample16khzTo22khz(const WebRtc_Word16* in, WebRtc_Word16* out, + WebRtcSpl_State16khzTo22khz* state, WebRtc_Word32* tmpmem) +{ + int k; + + // process two blocks of 10/SUB_BLOCKS_16_22 ms (to reduce temp buffer size) + for (k = 0; k < SUB_BLOCKS_16_22; k++) + { + ///// 16 --> 32 ///// + // WebRtc_Word16 in[160/SUB_BLOCKS_16_22] + // WebRtc_Word32 out[320/SUB_BLOCKS_16_22] + ///// + WebRtcSpl_UpBy2ShortToInt(in, 160 / SUB_BLOCKS_16_22, tmpmem + 8, state->S_16_32); + + ///// 32 --> 22 ///// + // WebRtc_Word32 in[320/SUB_BLOCKS_16_22] + // WebRtc_Word32 out[220/SUB_BLOCKS_16_22] + ///// + // copy state to and from input array + tmpmem[0] = state->S_32_22[0]; + tmpmem[1] = state->S_32_22[1]; + tmpmem[2] = state->S_32_22[2]; + tmpmem[3] = state->S_32_22[3]; + tmpmem[4] = state->S_32_22[4]; + tmpmem[5] = state->S_32_22[5]; + tmpmem[6] = state->S_32_22[6]; + tmpmem[7] = state->S_32_22[7]; + state->S_32_22[0] = tmpmem[320 / SUB_BLOCKS_16_22]; + state->S_32_22[1] = tmpmem[320 / SUB_BLOCKS_16_22 + 1]; + state->S_32_22[2] = tmpmem[320 / SUB_BLOCKS_16_22 + 2]; + state->S_32_22[3] = tmpmem[320 / SUB_BLOCKS_16_22 + 3]; + state->S_32_22[4] = tmpmem[320 / SUB_BLOCKS_16_22 + 4]; + state->S_32_22[5] = tmpmem[320 / SUB_BLOCKS_16_22 + 5]; + state->S_32_22[6] = tmpmem[320 / SUB_BLOCKS_16_22 + 6]; + state->S_32_22[7] = tmpmem[320 / SUB_BLOCKS_16_22 + 7]; + + WebRtcSpl_32khzTo22khzIntToShort(tmpmem, out, 20 / SUB_BLOCKS_16_22); + + // move input/output pointers 10/SUB_BLOCKS_16_22 ms seconds ahead + in += 160 / SUB_BLOCKS_16_22; + out += 220 / SUB_BLOCKS_16_22; + } +} + +// initialize state of 16 -> 22 resampler +void WebRtcSpl_ResetResample16khzTo22khz(WebRtcSpl_State16khzTo22khz* state) +{ + int k; + for (k = 0; k < 8; k++) + { + state->S_16_32[k] = 0; + state->S_32_22[k] = 0; + } +} + +////////////////////// +// 22 kHz -> 8 kHz // +////////////////////// + +// number of subblocks; options: 1, 2, 5, 10 +#define SUB_BLOCKS_22_8 2 + +// 22 -> 8 resampler +void WebRtcSpl_Resample22khzTo8khz(const WebRtc_Word16* in, WebRtc_Word16* out, + WebRtcSpl_State22khzTo8khz* state, WebRtc_Word32* tmpmem) +{ + int k; + + // process two blocks of 10/SUB_BLOCKS_22_8 ms (to reduce temp buffer size) + for (k = 0; k < SUB_BLOCKS_22_8; k++) + { + ///// 22 --> 22 lowpass ///// + // WebRtc_Word16 in[220/SUB_BLOCKS_22_8] + // WebRtc_Word32 out[220/SUB_BLOCKS_22_8] + ///// + WebRtcSpl_LPBy2ShortToInt(in, 220 / SUB_BLOCKS_22_8, tmpmem + 16, state->S_22_22); + + ///// 22 --> 16 ///// + // WebRtc_Word32 in[220/SUB_BLOCKS_22_8] + // WebRtc_Word32 out[160/SUB_BLOCKS_22_8] + ///// + // copy state to and from input array + tmpmem[8] = state->S_22_16[0]; + tmpmem[9] = state->S_22_16[1]; + tmpmem[10] = state->S_22_16[2]; + tmpmem[11] = state->S_22_16[3]; + tmpmem[12] = state->S_22_16[4]; + tmpmem[13] = state->S_22_16[5]; + tmpmem[14] = state->S_22_16[6]; + tmpmem[15] = state->S_22_16[7]; + state->S_22_16[0] = tmpmem[220 / SUB_BLOCKS_22_8 + 8]; + state->S_22_16[1] = tmpmem[220 / SUB_BLOCKS_22_8 + 9]; + state->S_22_16[2] = tmpmem[220 / SUB_BLOCKS_22_8 + 10]; + state->S_22_16[3] = tmpmem[220 / SUB_BLOCKS_22_8 + 11]; + state->S_22_16[4] = tmpmem[220 / SUB_BLOCKS_22_8 + 12]; + state->S_22_16[5] = tmpmem[220 / SUB_BLOCKS_22_8 + 13]; + state->S_22_16[6] = tmpmem[220 / SUB_BLOCKS_22_8 + 14]; + state->S_22_16[7] = tmpmem[220 / SUB_BLOCKS_22_8 + 15]; + + WebRtcSpl_Resample44khzTo32khz(tmpmem + 8, tmpmem, 20 / SUB_BLOCKS_22_8); + + ///// 16 --> 8 ///// + // WebRtc_Word32 in[160/SUB_BLOCKS_22_8] + // WebRtc_Word32 out[80/SUB_BLOCKS_22_8] + ///// + WebRtcSpl_DownBy2IntToShort(tmpmem, 160 / SUB_BLOCKS_22_8, out, state->S_16_8); + + // move input/output pointers 10/SUB_BLOCKS_22_8 ms seconds ahead + in += 220 / SUB_BLOCKS_22_8; + out += 80 / SUB_BLOCKS_22_8; + } +} + +// initialize state of 22 -> 8 resampler +void WebRtcSpl_ResetResample22khzTo8khz(WebRtcSpl_State22khzTo8khz* state) +{ + int k; + for (k = 0; k < 8; k++) + { + state->S_22_22[k] = 0; + state->S_22_22[k + 8] = 0; + state->S_22_16[k] = 0; + state->S_16_8[k] = 0; + } +} + +////////////////////// +// 8 kHz -> 22 kHz // +////////////////////// + +// number of subblocks; options: 1, 2, 5, 10 +#define SUB_BLOCKS_8_22 2 + +// 8 -> 22 resampler +void WebRtcSpl_Resample8khzTo22khz(const WebRtc_Word16* in, WebRtc_Word16* out, + WebRtcSpl_State8khzTo22khz* state, WebRtc_Word32* tmpmem) +{ + int k; + + // process two blocks of 10/SUB_BLOCKS_8_22 ms (to reduce temp buffer size) + for (k = 0; k < SUB_BLOCKS_8_22; k++) + { + ///// 8 --> 16 ///// + // WebRtc_Word16 in[80/SUB_BLOCKS_8_22] + // WebRtc_Word32 out[160/SUB_BLOCKS_8_22] + ///// + WebRtcSpl_UpBy2ShortToInt(in, 80 / SUB_BLOCKS_8_22, tmpmem + 18, state->S_8_16); + + ///// 16 --> 11 ///// + // WebRtc_Word32 in[160/SUB_BLOCKS_8_22] + // WebRtc_Word32 out[110/SUB_BLOCKS_8_22] + ///// + // copy state to and from input array + tmpmem[10] = state->S_16_11[0]; + tmpmem[11] = state->S_16_11[1]; + tmpmem[12] = state->S_16_11[2]; + tmpmem[13] = state->S_16_11[3]; + tmpmem[14] = state->S_16_11[4]; + tmpmem[15] = state->S_16_11[5]; + tmpmem[16] = state->S_16_11[6]; + tmpmem[17] = state->S_16_11[7]; + state->S_16_11[0] = tmpmem[160 / SUB_BLOCKS_8_22 + 10]; + state->S_16_11[1] = tmpmem[160 / SUB_BLOCKS_8_22 + 11]; + state->S_16_11[2] = tmpmem[160 / SUB_BLOCKS_8_22 + 12]; + state->S_16_11[3] = tmpmem[160 / SUB_BLOCKS_8_22 + 13]; + state->S_16_11[4] = tmpmem[160 / SUB_BLOCKS_8_22 + 14]; + state->S_16_11[5] = tmpmem[160 / SUB_BLOCKS_8_22 + 15]; + state->S_16_11[6] = tmpmem[160 / SUB_BLOCKS_8_22 + 16]; + state->S_16_11[7] = tmpmem[160 / SUB_BLOCKS_8_22 + 17]; + + WebRtcSpl_32khzTo22khzIntToInt(tmpmem + 10, tmpmem, 10 / SUB_BLOCKS_8_22); + + ///// 11 --> 22 ///// + // WebRtc_Word32 in[110/SUB_BLOCKS_8_22] + // WebRtc_Word16 out[220/SUB_BLOCKS_8_22] + ///// + WebRtcSpl_UpBy2IntToShort(tmpmem, 110 / SUB_BLOCKS_8_22, out, state->S_11_22); + + // move input/output pointers 10/SUB_BLOCKS_8_22 ms seconds ahead + in += 80 / SUB_BLOCKS_8_22; + out += 220 / SUB_BLOCKS_8_22; + } +} + +// initialize state of 8 -> 22 resampler +void WebRtcSpl_ResetResample8khzTo22khz(WebRtcSpl_State8khzTo22khz* state) +{ + int k; + for (k = 0; k < 8; k++) + { + state->S_8_16[k] = 0; + state->S_16_11[k] = 0; + state->S_11_22[k] = 0; + } +} + +// compute two inner-products and store them to output array +static void WebRtcSpl_DotProdIntToInt(const WebRtc_Word32* in1, const WebRtc_Word32* in2, + const WebRtc_Word16* coef_ptr, WebRtc_Word32* out1, + WebRtc_Word32* out2) +{ + WebRtc_Word32 tmp1 = 16384; + WebRtc_Word32 tmp2 = 16384; + WebRtc_Word16 coef; + + coef = coef_ptr[0]; + tmp1 += coef * in1[0]; + tmp2 += coef * in2[-0]; + + coef = coef_ptr[1]; + tmp1 += coef * in1[1]; + tmp2 += coef * in2[-1]; + + coef = coef_ptr[2]; + tmp1 += coef * in1[2]; + tmp2 += coef * in2[-2]; + + coef = coef_ptr[3]; + tmp1 += coef * in1[3]; + tmp2 += coef * in2[-3]; + + coef = coef_ptr[4]; + tmp1 += coef * in1[4]; + tmp2 += coef * in2[-4]; + + coef = coef_ptr[5]; + tmp1 += coef * in1[5]; + tmp2 += coef * in2[-5]; + + coef = coef_ptr[6]; + tmp1 += coef * in1[6]; + tmp2 += coef * in2[-6]; + + coef = coef_ptr[7]; + tmp1 += coef * in1[7]; + tmp2 += coef * in2[-7]; + + coef = coef_ptr[8]; + *out1 = tmp1 + coef * in1[8]; + *out2 = tmp2 + coef * in2[-8]; +} + +// compute two inner-products and store them to output array +static void WebRtcSpl_DotProdIntToShort(const WebRtc_Word32* in1, const WebRtc_Word32* in2, + const WebRtc_Word16* coef_ptr, WebRtc_Word16* out1, + WebRtc_Word16* out2) +{ + WebRtc_Word32 tmp1 = 16384; + WebRtc_Word32 tmp2 = 16384; + WebRtc_Word16 coef; + + coef = coef_ptr[0]; + tmp1 += coef * in1[0]; + tmp2 += coef * in2[-0]; + + coef = coef_ptr[1]; + tmp1 += coef * in1[1]; + tmp2 += coef * in2[-1]; + + coef = coef_ptr[2]; + tmp1 += coef * in1[2]; + tmp2 += coef * in2[-2]; + + coef = coef_ptr[3]; + tmp1 += coef * in1[3]; + tmp2 += coef * in2[-3]; + + coef = coef_ptr[4]; + tmp1 += coef * in1[4]; + tmp2 += coef * in2[-4]; + + coef = coef_ptr[5]; + tmp1 += coef * in1[5]; + tmp2 += coef * in2[-5]; + + coef = coef_ptr[6]; + tmp1 += coef * in1[6]; + tmp2 += coef * in2[-6]; + + coef = coef_ptr[7]; + tmp1 += coef * in1[7]; + tmp2 += coef * in2[-7]; + + coef = coef_ptr[8]; + tmp1 += coef * in1[8]; + tmp2 += coef * in2[-8]; + + // scale down, round and saturate + tmp1 >>= 15; + if (tmp1 > (WebRtc_Word32)0x00007FFF) + tmp1 = 0x00007FFF; + if (tmp1 < (WebRtc_Word32)0xFFFF8000) + tmp1 = 0xFFFF8000; + tmp2 >>= 15; + if (tmp2 > (WebRtc_Word32)0x00007FFF) + tmp2 = 0x00007FFF; + if (tmp2 < (WebRtc_Word32)0xFFFF8000) + tmp2 = 0xFFFF8000; + *out1 = (WebRtc_Word16)tmp1; + *out2 = (WebRtc_Word16)tmp2; +} + +// Resampling ratio: 11/16 +// input: WebRtc_Word32 (normalized, not saturated) :: size 16 * K +// output: WebRtc_Word32 (shifted 15 positions to the left, + offset 16384) :: size 11 * K +// K: Number of blocks + +void WebRtcSpl_32khzTo22khzIntToInt(const WebRtc_Word32* In, + WebRtc_Word32* Out, + const WebRtc_Word32 K) +{ + ///////////////////////////////////////////////////////////// + // Filter operation: + // + // Perform resampling (16 input samples -> 11 output samples); + // process in sub blocks of size 16 samples. + WebRtc_Word32 m; + + for (m = 0; m < K; m++) + { + // first output sample + Out[0] = ((WebRtc_Word32)In[3] << 15) + (1 << 14); + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_DotProdIntToInt(&In[0], &In[22], kCoefficients32To22[0], &Out[1], &Out[10]); + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_DotProdIntToInt(&In[2], &In[20], kCoefficients32To22[1], &Out[2], &Out[9]); + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_DotProdIntToInt(&In[3], &In[19], kCoefficients32To22[2], &Out[3], &Out[8]); + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_DotProdIntToInt(&In[5], &In[17], kCoefficients32To22[3], &Out[4], &Out[7]); + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_DotProdIntToInt(&In[6], &In[16], kCoefficients32To22[4], &Out[5], &Out[6]); + + // update pointers + In += 16; + Out += 11; + } +} + +// Resampling ratio: 11/16 +// input: WebRtc_Word32 (normalized, not saturated) :: size 16 * K +// output: WebRtc_Word16 (saturated) :: size 11 * K +// K: Number of blocks + +void WebRtcSpl_32khzTo22khzIntToShort(const WebRtc_Word32 *In, + WebRtc_Word16 *Out, + const WebRtc_Word32 K) +{ + ///////////////////////////////////////////////////////////// + // Filter operation: + // + // Perform resampling (16 input samples -> 11 output samples); + // process in sub blocks of size 16 samples. + WebRtc_Word32 tmp; + WebRtc_Word32 m; + + for (m = 0; m < K; m++) + { + // first output sample + tmp = In[3]; + if (tmp > (WebRtc_Word32)0x00007FFF) + tmp = 0x00007FFF; + if (tmp < (WebRtc_Word32)0xFFFF8000) + tmp = 0xFFFF8000; + Out[0] = (WebRtc_Word16)tmp; + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_DotProdIntToShort(&In[0], &In[22], kCoefficients32To22[0], &Out[1], &Out[10]); + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_DotProdIntToShort(&In[2], &In[20], kCoefficients32To22[1], &Out[2], &Out[9]); + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_DotProdIntToShort(&In[3], &In[19], kCoefficients32To22[2], &Out[3], &Out[8]); + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_DotProdIntToShort(&In[5], &In[17], kCoefficients32To22[3], &Out[4], &Out[7]); + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_DotProdIntToShort(&In[6], &In[16], kCoefficients32To22[4], &Out[5], &Out[6]); + + // update pointers + In += 16; + Out += 11; + } +} diff --git a/libs/miniwebrtc/audio/common/processing/resample_48khz.c b/libs/miniwebrtc/audio/common/processing/resample_48khz.c new file mode 100644 index 00000000..31cbe6b6 --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/resample_48khz.c @@ -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. + */ + + +/* + * This file contains resampling functions between 48 kHz and nb/wb. + * The description header can be found in signal_processing_library.h + * + */ + +#include +#include "signal_processing_library.h" +#include "resample_by_2_internal.h" + +//////////////////////////// +///// 48 kHz -> 16 kHz ///// +//////////////////////////// + +// 48 -> 16 resampler +void WebRtcSpl_Resample48khzTo16khz(const WebRtc_Word16* in, WebRtc_Word16* out, + WebRtcSpl_State48khzTo16khz* state, WebRtc_Word32* tmpmem) +{ + ///// 48 --> 48(LP) ///// + // WebRtc_Word16 in[480] + // WebRtc_Word32 out[480] + ///// + WebRtcSpl_LPBy2ShortToInt(in, 480, tmpmem + 16, state->S_48_48); + + ///// 48 --> 32 ///// + // WebRtc_Word32 in[480] + // WebRtc_Word32 out[320] + ///// + // copy state to and from input array + memcpy(tmpmem + 8, state->S_48_32, 8 * sizeof(WebRtc_Word32)); + memcpy(state->S_48_32, tmpmem + 488, 8 * sizeof(WebRtc_Word32)); + WebRtcSpl_Resample48khzTo32khz(tmpmem + 8, tmpmem, 160); + + ///// 32 --> 16 ///// + // WebRtc_Word32 in[320] + // WebRtc_Word16 out[160] + ///// + WebRtcSpl_DownBy2IntToShort(tmpmem, 320, out, state->S_32_16); +} + +// initialize state of 48 -> 16 resampler +void WebRtcSpl_ResetResample48khzTo16khz(WebRtcSpl_State48khzTo16khz* state) +{ + memset(state->S_48_48, 0, 16 * sizeof(WebRtc_Word32)); + memset(state->S_48_32, 0, 8 * sizeof(WebRtc_Word32)); + memset(state->S_32_16, 0, 8 * sizeof(WebRtc_Word32)); +} + +//////////////////////////// +///// 16 kHz -> 48 kHz ///// +//////////////////////////// + +// 16 -> 48 resampler +void WebRtcSpl_Resample16khzTo48khz(const WebRtc_Word16* in, WebRtc_Word16* out, + WebRtcSpl_State16khzTo48khz* state, WebRtc_Word32* tmpmem) +{ + ///// 16 --> 32 ///// + // WebRtc_Word16 in[160] + // WebRtc_Word32 out[320] + ///// + WebRtcSpl_UpBy2ShortToInt(in, 160, tmpmem + 16, state->S_16_32); + + ///// 32 --> 24 ///// + // WebRtc_Word32 in[320] + // WebRtc_Word32 out[240] + // copy state to and from input array + ///// + memcpy(tmpmem + 8, state->S_32_24, 8 * sizeof(WebRtc_Word32)); + memcpy(state->S_32_24, tmpmem + 328, 8 * sizeof(WebRtc_Word32)); + WebRtcSpl_Resample32khzTo24khz(tmpmem + 8, tmpmem, 80); + + ///// 24 --> 48 ///// + // WebRtc_Word32 in[240] + // WebRtc_Word16 out[480] + ///// + WebRtcSpl_UpBy2IntToShort(tmpmem, 240, out, state->S_24_48); +} + +// initialize state of 16 -> 48 resampler +void WebRtcSpl_ResetResample16khzTo48khz(WebRtcSpl_State16khzTo48khz* state) +{ + memset(state->S_16_32, 0, 8 * sizeof(WebRtc_Word32)); + memset(state->S_32_24, 0, 8 * sizeof(WebRtc_Word32)); + memset(state->S_24_48, 0, 8 * sizeof(WebRtc_Word32)); +} + +//////////////////////////// +///// 48 kHz -> 8 kHz ///// +//////////////////////////// + +// 48 -> 8 resampler +void WebRtcSpl_Resample48khzTo8khz(const WebRtc_Word16* in, WebRtc_Word16* out, + WebRtcSpl_State48khzTo8khz* state, WebRtc_Word32* tmpmem) +{ + ///// 48 --> 24 ///// + // WebRtc_Word16 in[480] + // WebRtc_Word32 out[240] + ///// + WebRtcSpl_DownBy2ShortToInt(in, 480, tmpmem + 256, state->S_48_24); + + ///// 24 --> 24(LP) ///// + // WebRtc_Word32 in[240] + // WebRtc_Word32 out[240] + ///// + WebRtcSpl_LPBy2IntToInt(tmpmem + 256, 240, tmpmem + 16, state->S_24_24); + + ///// 24 --> 16 ///// + // WebRtc_Word32 in[240] + // WebRtc_Word32 out[160] + ///// + // copy state to and from input array + memcpy(tmpmem + 8, state->S_24_16, 8 * sizeof(WebRtc_Word32)); + memcpy(state->S_24_16, tmpmem + 248, 8 * sizeof(WebRtc_Word32)); + WebRtcSpl_Resample48khzTo32khz(tmpmem + 8, tmpmem, 80); + + ///// 16 --> 8 ///// + // WebRtc_Word32 in[160] + // WebRtc_Word16 out[80] + ///// + WebRtcSpl_DownBy2IntToShort(tmpmem, 160, out, state->S_16_8); +} + +// initialize state of 48 -> 8 resampler +void WebRtcSpl_ResetResample48khzTo8khz(WebRtcSpl_State48khzTo8khz* state) +{ + memset(state->S_48_24, 0, 8 * sizeof(WebRtc_Word32)); + memset(state->S_24_24, 0, 16 * sizeof(WebRtc_Word32)); + memset(state->S_24_16, 0, 8 * sizeof(WebRtc_Word32)); + memset(state->S_16_8, 0, 8 * sizeof(WebRtc_Word32)); +} + +//////////////////////////// +///// 8 kHz -> 48 kHz ///// +//////////////////////////// + +// 8 -> 48 resampler +void WebRtcSpl_Resample8khzTo48khz(const WebRtc_Word16* in, WebRtc_Word16* out, + WebRtcSpl_State8khzTo48khz* state, WebRtc_Word32* tmpmem) +{ + ///// 8 --> 16 ///// + // WebRtc_Word16 in[80] + // WebRtc_Word32 out[160] + ///// + WebRtcSpl_UpBy2ShortToInt(in, 80, tmpmem + 264, state->S_8_16); + + ///// 16 --> 12 ///// + // WebRtc_Word32 in[160] + // WebRtc_Word32 out[120] + ///// + // copy state to and from input array + memcpy(tmpmem + 256, state->S_16_12, 8 * sizeof(WebRtc_Word32)); + memcpy(state->S_16_12, tmpmem + 416, 8 * sizeof(WebRtc_Word32)); + WebRtcSpl_Resample32khzTo24khz(tmpmem + 256, tmpmem + 240, 40); + + ///// 12 --> 24 ///// + // WebRtc_Word32 in[120] + // WebRtc_Word16 out[240] + ///// + WebRtcSpl_UpBy2IntToInt(tmpmem + 240, 120, tmpmem, state->S_12_24); + + ///// 24 --> 48 ///// + // WebRtc_Word32 in[240] + // WebRtc_Word16 out[480] + ///// + WebRtcSpl_UpBy2IntToShort(tmpmem, 240, out, state->S_24_48); +} + +// initialize state of 8 -> 48 resampler +void WebRtcSpl_ResetResample8khzTo48khz(WebRtcSpl_State8khzTo48khz* state) +{ + memset(state->S_8_16, 0, 8 * sizeof(WebRtc_Word32)); + memset(state->S_16_12, 0, 8 * sizeof(WebRtc_Word32)); + memset(state->S_12_24, 0, 8 * sizeof(WebRtc_Word32)); + memset(state->S_24_48, 0, 8 * sizeof(WebRtc_Word32)); +} diff --git a/libs/miniwebrtc/audio/common/processing/resample_by_2.c b/libs/miniwebrtc/audio/common/processing/resample_by_2.c new file mode 100644 index 00000000..e239db75 --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/resample_by_2.c @@ -0,0 +1,181 @@ +/* + * 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 contains the resampling by two functions. + * The description header can be found in signal_processing_library.h + * + */ + +#include "signal_processing_library.h" + +#ifdef WEBRTC_ARCH_ARM_V7A + +// allpass filter coefficients. +static const WebRtc_UWord32 kResampleAllpass1[3] = {3284, 24441, 49528 << 15}; +static const WebRtc_UWord32 kResampleAllpass2[3] = + {12199, 37471 << 15, 60255 << 15}; + +// Multiply two 32-bit values and accumulate to another input value. +// Return: state + ((diff * tbl_value) >> 16) + +static __inline WebRtc_Word32 MUL_ACCUM_1(WebRtc_Word32 tbl_value, + WebRtc_Word32 diff, + WebRtc_Word32 state) { + WebRtc_Word32 result; + __asm__("smlawb %r0, %r1, %r2, %r3": "=r"(result): "r"(diff), + "r"(tbl_value), "r"(state)); + return result; +} + +// Multiply two 32-bit values and accumulate to another input value. +// Return: Return: state + (((diff << 1) * tbl_value) >> 32) +// +// The reason to introduce this function is that, in case we can't use smlawb +// instruction (in MUL_ACCUM_1) due to input value range, we can still use +// smmla to save some cycles. + +static __inline WebRtc_Word32 MUL_ACCUM_2(WebRtc_Word32 tbl_value, + WebRtc_Word32 diff, + WebRtc_Word32 state) { + WebRtc_Word32 result; + __asm__("smmla %r0, %r1, %r2, %r3": "=r"(result): "r"(diff << 1), + "r"(tbl_value), "r"(state)); + return result; +} + +#else + +// allpass filter coefficients. +static const WebRtc_UWord16 kResampleAllpass1[3] = {3284, 24441, 49528}; +static const WebRtc_UWord16 kResampleAllpass2[3] = {12199, 37471, 60255}; + +// Multiply a 32-bit value with a 16-bit value and accumulate to another input: +#define MUL_ACCUM_1(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c) +#define MUL_ACCUM_2(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c) + +#endif // WEBRTC_ARCH_ARM_V7A + + +// decimator +void WebRtcSpl_DownsampleBy2(const WebRtc_Word16* in, const WebRtc_Word16 len, + WebRtc_Word16* out, WebRtc_Word32* filtState) { + WebRtc_Word32 tmp1, tmp2, diff, in32, out32; + WebRtc_Word16 i; + + register WebRtc_Word32 state0 = filtState[0]; + register WebRtc_Word32 state1 = filtState[1]; + register WebRtc_Word32 state2 = filtState[2]; + register WebRtc_Word32 state3 = filtState[3]; + register WebRtc_Word32 state4 = filtState[4]; + register WebRtc_Word32 state5 = filtState[5]; + register WebRtc_Word32 state6 = filtState[6]; + register WebRtc_Word32 state7 = filtState[7]; + + for (i = (len >> 1); i > 0; i--) { + // lower allpass filter + in32 = (WebRtc_Word32)(*in++) << 10; + diff = in32 - state1; + tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0); + state0 = in32; + diff = tmp1 - state2; + tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1); + state1 = tmp1; + diff = tmp2 - state3; + state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2); + state2 = tmp2; + + // upper allpass filter + in32 = (WebRtc_Word32)(*in++) << 10; + diff = in32 - state5; + tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4); + state4 = in32; + diff = tmp1 - state6; + tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5); + state5 = tmp1; + diff = tmp2 - state7; + state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6); + state6 = tmp2; + + // add two allpass outputs, divide by two and round + out32 = (state3 + state7 + 1024) >> 11; + + // limit amplitude to prevent wrap-around, and write to output array + *out++ = WebRtcSpl_SatW32ToW16(out32); + } + + filtState[0] = state0; + filtState[1] = state1; + filtState[2] = state2; + filtState[3] = state3; + filtState[4] = state4; + filtState[5] = state5; + filtState[6] = state6; + filtState[7] = state7; +} + + +void WebRtcSpl_UpsampleBy2(const WebRtc_Word16* in, WebRtc_Word16 len, + WebRtc_Word16* out, WebRtc_Word32* filtState) { + WebRtc_Word32 tmp1, tmp2, diff, in32, out32; + WebRtc_Word16 i; + + register WebRtc_Word32 state0 = filtState[0]; + register WebRtc_Word32 state1 = filtState[1]; + register WebRtc_Word32 state2 = filtState[2]; + register WebRtc_Word32 state3 = filtState[3]; + register WebRtc_Word32 state4 = filtState[4]; + register WebRtc_Word32 state5 = filtState[5]; + register WebRtc_Word32 state6 = filtState[6]; + register WebRtc_Word32 state7 = filtState[7]; + + for (i = len; i > 0; i--) { + // lower allpass filter + in32 = (WebRtc_Word32)(*in++) << 10; + diff = in32 - state1; + tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state0); + state0 = in32; + diff = tmp1 - state2; + tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state1); + state1 = tmp1; + diff = tmp2 - state3; + state3 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state2); + state2 = tmp2; + + // round; limit amplitude to prevent wrap-around; write to output array + out32 = (state3 + 512) >> 10; + *out++ = WebRtcSpl_SatW32ToW16(out32); + + // upper allpass filter + diff = in32 - state5; + tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state4); + state4 = in32; + diff = tmp1 - state6; + tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state5); + state5 = tmp1; + diff = tmp2 - state7; + state7 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state6); + state6 = tmp2; + + // round; limit amplitude to prevent wrap-around; write to output array + out32 = (state7 + 512) >> 10; + *out++ = WebRtcSpl_SatW32ToW16(out32); + } + + filtState[0] = state0; + filtState[1] = state1; + filtState[2] = state2; + filtState[3] = state3; + filtState[4] = state4; + filtState[5] = state5; + filtState[6] = state6; + filtState[7] = state7; +} diff --git a/libs/miniwebrtc/audio/common/processing/resample_by_2_internal.c b/libs/miniwebrtc/audio/common/processing/resample_by_2_internal.c new file mode 100644 index 00000000..cbd23958 --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/resample_by_2_internal.c @@ -0,0 +1,679 @@ +/* + * 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 header file contains some internal resampling functions. + * + */ + +#include "resample_by_2_internal.h" + +// allpass filter coefficients. +static const WebRtc_Word16 kResampleAllpass[2][3] = { + {821, 6110, 12382}, + {3050, 9368, 15063} +}; + +// +// decimator +// input: WebRtc_Word32 (shifted 15 positions to the left, + offset 16384) OVERWRITTEN! +// output: WebRtc_Word16 (saturated) (of length len/2) +// state: filter state array; length = 8 + +void WebRtcSpl_DownBy2IntToShort(WebRtc_Word32 *in, WebRtc_Word32 len, WebRtc_Word16 *out, + WebRtc_Word32 *state) +{ + WebRtc_Word32 tmp0, tmp1, diff; + WebRtc_Word32 i; + + len >>= 1; + + // lower allpass filter (operates on even input samples) + for (i = 0; i < len; i++) + { + tmp0 = in[i << 1]; + diff = tmp0 - state[1]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[0] + diff * kResampleAllpass[1][0]; + state[0] = tmp0; + diff = tmp1 - state[2]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[1] + diff * kResampleAllpass[1][1]; + state[1] = tmp1; + diff = tmp0 - state[3]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[3] = state[2] + diff * kResampleAllpass[1][2]; + state[2] = tmp0; + + // divide by two and store temporarily + in[i << 1] = (state[3] >> 1); + } + + in++; + + // upper allpass filter (operates on odd input samples) + for (i = 0; i < len; i++) + { + tmp0 = in[i << 1]; + diff = tmp0 - state[5]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[4] + diff * kResampleAllpass[0][0]; + state[4] = tmp0; + diff = tmp1 - state[6]; + // scale down and round + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[5] + diff * kResampleAllpass[0][1]; + state[5] = tmp1; + diff = tmp0 - state[7]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[7] = state[6] + diff * kResampleAllpass[0][2]; + state[6] = tmp0; + + // divide by two and store temporarily + in[i << 1] = (state[7] >> 1); + } + + in--; + + // combine allpass outputs + for (i = 0; i < len; i += 2) + { + // divide by two, add both allpass outputs and round + tmp0 = (in[i << 1] + in[(i << 1) + 1]) >> 15; + tmp1 = (in[(i << 1) + 2] + in[(i << 1) + 3]) >> 15; + if (tmp0 > (WebRtc_Word32)0x00007FFF) + tmp0 = 0x00007FFF; + if (tmp0 < (WebRtc_Word32)0xFFFF8000) + tmp0 = 0xFFFF8000; + out[i] = (WebRtc_Word16)tmp0; + if (tmp1 > (WebRtc_Word32)0x00007FFF) + tmp1 = 0x00007FFF; + if (tmp1 < (WebRtc_Word32)0xFFFF8000) + tmp1 = 0xFFFF8000; + out[i + 1] = (WebRtc_Word16)tmp1; + } +} + +// +// decimator +// input: WebRtc_Word16 +// output: WebRtc_Word32 (shifted 15 positions to the left, + offset 16384) (of length len/2) +// state: filter state array; length = 8 + +void WebRtcSpl_DownBy2ShortToInt(const WebRtc_Word16 *in, + WebRtc_Word32 len, + WebRtc_Word32 *out, + WebRtc_Word32 *state) +{ + WebRtc_Word32 tmp0, tmp1, diff; + WebRtc_Word32 i; + + len >>= 1; + + // lower allpass filter (operates on even input samples) + for (i = 0; i < len; i++) + { + tmp0 = ((WebRtc_Word32)in[i << 1] << 15) + (1 << 14); + diff = tmp0 - state[1]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[0] + diff * kResampleAllpass[1][0]; + state[0] = tmp0; + diff = tmp1 - state[2]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[1] + diff * kResampleAllpass[1][1]; + state[1] = tmp1; + diff = tmp0 - state[3]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[3] = state[2] + diff * kResampleAllpass[1][2]; + state[2] = tmp0; + + // divide by two and store temporarily + out[i] = (state[3] >> 1); + } + + in++; + + // upper allpass filter (operates on odd input samples) + for (i = 0; i < len; i++) + { + tmp0 = ((WebRtc_Word32)in[i << 1] << 15) + (1 << 14); + diff = tmp0 - state[5]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[4] + diff * kResampleAllpass[0][0]; + state[4] = tmp0; + diff = tmp1 - state[6]; + // scale down and round + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[5] + diff * kResampleAllpass[0][1]; + state[5] = tmp1; + diff = tmp0 - state[7]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[7] = state[6] + diff * kResampleAllpass[0][2]; + state[6] = tmp0; + + // divide by two and store temporarily + out[i] += (state[7] >> 1); + } + + in--; +} + +// +// interpolator +// input: WebRtc_Word16 +// output: WebRtc_Word32 (normalized, not saturated) (of length len*2) +// state: filter state array; length = 8 +void WebRtcSpl_UpBy2ShortToInt(const WebRtc_Word16 *in, WebRtc_Word32 len, WebRtc_Word32 *out, + WebRtc_Word32 *state) +{ + WebRtc_Word32 tmp0, tmp1, diff; + WebRtc_Word32 i; + + // upper allpass filter (generates odd output samples) + for (i = 0; i < len; i++) + { + tmp0 = ((WebRtc_Word32)in[i] << 15) + (1 << 14); + diff = tmp0 - state[5]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[4] + diff * kResampleAllpass[0][0]; + state[4] = tmp0; + diff = tmp1 - state[6]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[5] + diff * kResampleAllpass[0][1]; + state[5] = tmp1; + diff = tmp0 - state[7]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[7] = state[6] + diff * kResampleAllpass[0][2]; + state[6] = tmp0; + + // scale down, round and store + out[i << 1] = state[7] >> 15; + } + + out++; + + // lower allpass filter (generates even output samples) + for (i = 0; i < len; i++) + { + tmp0 = ((WebRtc_Word32)in[i] << 15) + (1 << 14); + diff = tmp0 - state[1]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[0] + diff * kResampleAllpass[1][0]; + state[0] = tmp0; + diff = tmp1 - state[2]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[1] + diff * kResampleAllpass[1][1]; + state[1] = tmp1; + diff = tmp0 - state[3]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[3] = state[2] + diff * kResampleAllpass[1][2]; + state[2] = tmp0; + + // scale down, round and store + out[i << 1] = state[3] >> 15; + } +} + +// +// interpolator +// input: WebRtc_Word32 (shifted 15 positions to the left, + offset 16384) +// output: WebRtc_Word32 (shifted 15 positions to the left, + offset 16384) (of length len*2) +// state: filter state array; length = 8 +void WebRtcSpl_UpBy2IntToInt(const WebRtc_Word32 *in, WebRtc_Word32 len, WebRtc_Word32 *out, + WebRtc_Word32 *state) +{ + WebRtc_Word32 tmp0, tmp1, diff; + WebRtc_Word32 i; + + // upper allpass filter (generates odd output samples) + for (i = 0; i < len; i++) + { + tmp0 = in[i]; + diff = tmp0 - state[5]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[4] + diff * kResampleAllpass[0][0]; + state[4] = tmp0; + diff = tmp1 - state[6]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[5] + diff * kResampleAllpass[0][1]; + state[5] = tmp1; + diff = tmp0 - state[7]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[7] = state[6] + diff * kResampleAllpass[0][2]; + state[6] = tmp0; + + // scale down, round and store + out[i << 1] = state[7]; + } + + out++; + + // lower allpass filter (generates even output samples) + for (i = 0; i < len; i++) + { + tmp0 = in[i]; + diff = tmp0 - state[1]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[0] + diff * kResampleAllpass[1][0]; + state[0] = tmp0; + diff = tmp1 - state[2]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[1] + diff * kResampleAllpass[1][1]; + state[1] = tmp1; + diff = tmp0 - state[3]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[3] = state[2] + diff * kResampleAllpass[1][2]; + state[2] = tmp0; + + // scale down, round and store + out[i << 1] = state[3]; + } +} + +// +// interpolator +// input: WebRtc_Word32 (shifted 15 positions to the left, + offset 16384) +// output: WebRtc_Word16 (saturated) (of length len*2) +// state: filter state array; length = 8 +void WebRtcSpl_UpBy2IntToShort(const WebRtc_Word32 *in, WebRtc_Word32 len, WebRtc_Word16 *out, + WebRtc_Word32 *state) +{ + WebRtc_Word32 tmp0, tmp1, diff; + WebRtc_Word32 i; + + // upper allpass filter (generates odd output samples) + for (i = 0; i < len; i++) + { + tmp0 = in[i]; + diff = tmp0 - state[5]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[4] + diff * kResampleAllpass[0][0]; + state[4] = tmp0; + diff = tmp1 - state[6]; + // scale down and round + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[5] + diff * kResampleAllpass[0][1]; + state[5] = tmp1; + diff = tmp0 - state[7]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[7] = state[6] + diff * kResampleAllpass[0][2]; + state[6] = tmp0; + + // scale down, saturate and store + tmp1 = state[7] >> 15; + if (tmp1 > (WebRtc_Word32)0x00007FFF) + tmp1 = 0x00007FFF; + if (tmp1 < (WebRtc_Word32)0xFFFF8000) + tmp1 = 0xFFFF8000; + out[i << 1] = (WebRtc_Word16)tmp1; + } + + out++; + + // lower allpass filter (generates even output samples) + for (i = 0; i < len; i++) + { + tmp0 = in[i]; + diff = tmp0 - state[1]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[0] + diff * kResampleAllpass[1][0]; + state[0] = tmp0; + diff = tmp1 - state[2]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[1] + diff * kResampleAllpass[1][1]; + state[1] = tmp1; + diff = tmp0 - state[3]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[3] = state[2] + diff * kResampleAllpass[1][2]; + state[2] = tmp0; + + // scale down, saturate and store + tmp1 = state[3] >> 15; + if (tmp1 > (WebRtc_Word32)0x00007FFF) + tmp1 = 0x00007FFF; + if (tmp1 < (WebRtc_Word32)0xFFFF8000) + tmp1 = 0xFFFF8000; + out[i << 1] = (WebRtc_Word16)tmp1; + } +} + +// lowpass filter +// input: WebRtc_Word16 +// output: WebRtc_Word32 (normalized, not saturated) +// state: filter state array; length = 8 +void WebRtcSpl_LPBy2ShortToInt(const WebRtc_Word16* in, WebRtc_Word32 len, WebRtc_Word32* out, + WebRtc_Word32* state) +{ + WebRtc_Word32 tmp0, tmp1, diff; + WebRtc_Word32 i; + + len >>= 1; + + // lower allpass filter: odd input -> even output samples + in++; + // initial state of polyphase delay element + tmp0 = state[12]; + for (i = 0; i < len; i++) + { + diff = tmp0 - state[1]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[0] + diff * kResampleAllpass[1][0]; + state[0] = tmp0; + diff = tmp1 - state[2]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[1] + diff * kResampleAllpass[1][1]; + state[1] = tmp1; + diff = tmp0 - state[3]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[3] = state[2] + diff * kResampleAllpass[1][2]; + state[2] = tmp0; + + // scale down, round and store + out[i << 1] = state[3] >> 1; + tmp0 = ((WebRtc_Word32)in[i << 1] << 15) + (1 << 14); + } + in--; + + // upper allpass filter: even input -> even output samples + for (i = 0; i < len; i++) + { + tmp0 = ((WebRtc_Word32)in[i << 1] << 15) + (1 << 14); + diff = tmp0 - state[5]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[4] + diff * kResampleAllpass[0][0]; + state[4] = tmp0; + diff = tmp1 - state[6]; + // scale down and round + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[5] + diff * kResampleAllpass[0][1]; + state[5] = tmp1; + diff = tmp0 - state[7]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[7] = state[6] + diff * kResampleAllpass[0][2]; + state[6] = tmp0; + + // average the two allpass outputs, scale down and store + out[i << 1] = (out[i << 1] + (state[7] >> 1)) >> 15; + } + + // switch to odd output samples + out++; + + // lower allpass filter: even input -> odd output samples + for (i = 0; i < len; i++) + { + tmp0 = ((WebRtc_Word32)in[i << 1] << 15) + (1 << 14); + diff = tmp0 - state[9]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[8] + diff * kResampleAllpass[1][0]; + state[8] = tmp0; + diff = tmp1 - state[10]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[9] + diff * kResampleAllpass[1][1]; + state[9] = tmp1; + diff = tmp0 - state[11]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[11] = state[10] + diff * kResampleAllpass[1][2]; + state[10] = tmp0; + + // scale down, round and store + out[i << 1] = state[11] >> 1; + } + + // upper allpass filter: odd input -> odd output samples + in++; + for (i = 0; i < len; i++) + { + tmp0 = ((WebRtc_Word32)in[i << 1] << 15) + (1 << 14); + diff = tmp0 - state[13]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[12] + diff * kResampleAllpass[0][0]; + state[12] = tmp0; + diff = tmp1 - state[14]; + // scale down and round + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[13] + diff * kResampleAllpass[0][1]; + state[13] = tmp1; + diff = tmp0 - state[15]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[15] = state[14] + diff * kResampleAllpass[0][2]; + state[14] = tmp0; + + // average the two allpass outputs, scale down and store + out[i << 1] = (out[i << 1] + (state[15] >> 1)) >> 15; + } +} + +// lowpass filter +// input: WebRtc_Word32 (shifted 15 positions to the left, + offset 16384) +// output: WebRtc_Word32 (normalized, not saturated) +// state: filter state array; length = 8 +void WebRtcSpl_LPBy2IntToInt(const WebRtc_Word32* in, WebRtc_Word32 len, WebRtc_Word32* out, + WebRtc_Word32* state) +{ + WebRtc_Word32 tmp0, tmp1, diff; + WebRtc_Word32 i; + + len >>= 1; + + // lower allpass filter: odd input -> even output samples + in++; + // initial state of polyphase delay element + tmp0 = state[12]; + for (i = 0; i < len; i++) + { + diff = tmp0 - state[1]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[0] + diff * kResampleAllpass[1][0]; + state[0] = tmp0; + diff = tmp1 - state[2]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[1] + diff * kResampleAllpass[1][1]; + state[1] = tmp1; + diff = tmp0 - state[3]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[3] = state[2] + diff * kResampleAllpass[1][2]; + state[2] = tmp0; + + // scale down, round and store + out[i << 1] = state[3] >> 1; + tmp0 = in[i << 1]; + } + in--; + + // upper allpass filter: even input -> even output samples + for (i = 0; i < len; i++) + { + tmp0 = in[i << 1]; + diff = tmp0 - state[5]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[4] + diff * kResampleAllpass[0][0]; + state[4] = tmp0; + diff = tmp1 - state[6]; + // scale down and round + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[5] + diff * kResampleAllpass[0][1]; + state[5] = tmp1; + diff = tmp0 - state[7]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[7] = state[6] + diff * kResampleAllpass[0][2]; + state[6] = tmp0; + + // average the two allpass outputs, scale down and store + out[i << 1] = (out[i << 1] + (state[7] >> 1)) >> 15; + } + + // switch to odd output samples + out++; + + // lower allpass filter: even input -> odd output samples + for (i = 0; i < len; i++) + { + tmp0 = in[i << 1]; + diff = tmp0 - state[9]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[8] + diff * kResampleAllpass[1][0]; + state[8] = tmp0; + diff = tmp1 - state[10]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[9] + diff * kResampleAllpass[1][1]; + state[9] = tmp1; + diff = tmp0 - state[11]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[11] = state[10] + diff * kResampleAllpass[1][2]; + state[10] = tmp0; + + // scale down, round and store + out[i << 1] = state[11] >> 1; + } + + // upper allpass filter: odd input -> odd output samples + in++; + for (i = 0; i < len; i++) + { + tmp0 = in[i << 1]; + diff = tmp0 - state[13]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[12] + diff * kResampleAllpass[0][0]; + state[12] = tmp0; + diff = tmp1 - state[14]; + // scale down and round + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[13] + diff * kResampleAllpass[0][1]; + state[13] = tmp1; + diff = tmp0 - state[15]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[15] = state[14] + diff * kResampleAllpass[0][2]; + state[14] = tmp0; + + // average the two allpass outputs, scale down and store + out[i << 1] = (out[i << 1] + (state[15] >> 1)) >> 15; + } +} diff --git a/libs/miniwebrtc/audio/common/processing/resample_by_2_internal.h b/libs/miniwebrtc/audio/common/processing/resample_by_2_internal.h new file mode 100644 index 00000000..b6ac9f0c --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/resample_by_2_internal.h @@ -0,0 +1,47 @@ +/* + * 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 header file contains some internal resampling functions. + * + */ + +#ifndef WEBRTC_SPL_RESAMPLE_BY_2_INTERNAL_H_ +#define WEBRTC_SPL_RESAMPLE_BY_2_INTERNAL_H_ + +#include "typedefs.h" + +/******************************************************************* + * resample_by_2_fast.c + * Functions for internal use in the other resample functions + ******************************************************************/ +void WebRtcSpl_DownBy2IntToShort(WebRtc_Word32 *in, WebRtc_Word32 len, WebRtc_Word16 *out, + WebRtc_Word32 *state); + +void WebRtcSpl_DownBy2ShortToInt(const WebRtc_Word16 *in, WebRtc_Word32 len, + WebRtc_Word32 *out, WebRtc_Word32 *state); + +void WebRtcSpl_UpBy2ShortToInt(const WebRtc_Word16 *in, WebRtc_Word32 len, + WebRtc_Word32 *out, WebRtc_Word32 *state); + +void WebRtcSpl_UpBy2IntToInt(const WebRtc_Word32 *in, WebRtc_Word32 len, WebRtc_Word32 *out, + WebRtc_Word32 *state); + +void WebRtcSpl_UpBy2IntToShort(const WebRtc_Word32 *in, WebRtc_Word32 len, + WebRtc_Word16 *out, WebRtc_Word32 *state); + +void WebRtcSpl_LPBy2ShortToInt(const WebRtc_Word16* in, WebRtc_Word32 len, + WebRtc_Word32* out, WebRtc_Word32* state); + +void WebRtcSpl_LPBy2IntToInt(const WebRtc_Word32* in, WebRtc_Word32 len, WebRtc_Word32* out, + WebRtc_Word32* state); + +#endif // WEBRTC_SPL_RESAMPLE_BY_2_INTERNAL_H_ diff --git a/libs/miniwebrtc/audio/common/processing/resample_fractional.c b/libs/miniwebrtc/audio/common/processing/resample_fractional.c new file mode 100644 index 00000000..51003d45 --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/resample_fractional.c @@ -0,0 +1,242 @@ +/* + * 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 contains the resampling functions between 48, 44, 32 and 24 kHz. + * The description headers can be found in signal_processing_library.h + * + */ + +#include "signal_processing_library.h" + +// interpolation coefficients +static const WebRtc_Word16 kCoefficients48To32[2][8] = { + {778, -2050, 1087, 23285, 12903, -3783, 441, 222}, + {222, 441, -3783, 12903, 23285, 1087, -2050, 778} +}; + +static const WebRtc_Word16 kCoefficients32To24[3][8] = { + {767, -2362, 2434, 24406, 10620, -3838, 721, 90}, + {386, -381, -2646, 19062, 19062, -2646, -381, 386}, + {90, 721, -3838, 10620, 24406, 2434, -2362, 767} +}; + +static const WebRtc_Word16 kCoefficients44To32[4][9] = { + {117, -669, 2245, -6183, 26267, 13529, -3245, 845, -138}, + {-101, 612, -2283, 8532, 29790, -5138, 1789, -524, 91}, + {50, -292, 1016, -3064, 32010, 3933, -1147, 315, -53}, + {-156, 974, -3863, 18603, 21691, -6246, 2353, -712, 126} +}; + +// Resampling ratio: 2/3 +// input: WebRtc_Word32 (normalized, not saturated) :: size 3 * K +// output: WebRtc_Word32 (shifted 15 positions to the left, + offset 16384) :: size 2 * K +// K: number of blocks + +void WebRtcSpl_Resample48khzTo32khz(const WebRtc_Word32 *In, WebRtc_Word32 *Out, + const WebRtc_Word32 K) +{ + ///////////////////////////////////////////////////////////// + // Filter operation: + // + // Perform resampling (3 input samples -> 2 output samples); + // process in sub blocks of size 3 samples. + WebRtc_Word32 tmp; + WebRtc_Word32 m; + + for (m = 0; m < K; m++) + { + tmp = 1 << 14; + tmp += kCoefficients48To32[0][0] * In[0]; + tmp += kCoefficients48To32[0][1] * In[1]; + tmp += kCoefficients48To32[0][2] * In[2]; + tmp += kCoefficients48To32[0][3] * In[3]; + tmp += kCoefficients48To32[0][4] * In[4]; + tmp += kCoefficients48To32[0][5] * In[5]; + tmp += kCoefficients48To32[0][6] * In[6]; + tmp += kCoefficients48To32[0][7] * In[7]; + Out[0] = tmp; + + tmp = 1 << 14; + tmp += kCoefficients48To32[1][0] * In[1]; + tmp += kCoefficients48To32[1][1] * In[2]; + tmp += kCoefficients48To32[1][2] * In[3]; + tmp += kCoefficients48To32[1][3] * In[4]; + tmp += kCoefficients48To32[1][4] * In[5]; + tmp += kCoefficients48To32[1][5] * In[6]; + tmp += kCoefficients48To32[1][6] * In[7]; + tmp += kCoefficients48To32[1][7] * In[8]; + Out[1] = tmp; + + // update pointers + In += 3; + Out += 2; + } +} + +// Resampling ratio: 3/4 +// input: WebRtc_Word32 (normalized, not saturated) :: size 4 * K +// output: WebRtc_Word32 (shifted 15 positions to the left, + offset 16384) :: size 3 * K +// K: number of blocks + +void WebRtcSpl_Resample32khzTo24khz(const WebRtc_Word32 *In, WebRtc_Word32 *Out, + const WebRtc_Word32 K) +{ + ///////////////////////////////////////////////////////////// + // Filter operation: + // + // Perform resampling (4 input samples -> 3 output samples); + // process in sub blocks of size 4 samples. + WebRtc_Word32 m; + WebRtc_Word32 tmp; + + for (m = 0; m < K; m++) + { + tmp = 1 << 14; + tmp += kCoefficients32To24[0][0] * In[0]; + tmp += kCoefficients32To24[0][1] * In[1]; + tmp += kCoefficients32To24[0][2] * In[2]; + tmp += kCoefficients32To24[0][3] * In[3]; + tmp += kCoefficients32To24[0][4] * In[4]; + tmp += kCoefficients32To24[0][5] * In[5]; + tmp += kCoefficients32To24[0][6] * In[6]; + tmp += kCoefficients32To24[0][7] * In[7]; + Out[0] = tmp; + + tmp = 1 << 14; + tmp += kCoefficients32To24[1][0] * In[1]; + tmp += kCoefficients32To24[1][1] * In[2]; + tmp += kCoefficients32To24[1][2] * In[3]; + tmp += kCoefficients32To24[1][3] * In[4]; + tmp += kCoefficients32To24[1][4] * In[5]; + tmp += kCoefficients32To24[1][5] * In[6]; + tmp += kCoefficients32To24[1][6] * In[7]; + tmp += kCoefficients32To24[1][7] * In[8]; + Out[1] = tmp; + + tmp = 1 << 14; + tmp += kCoefficients32To24[2][0] * In[2]; + tmp += kCoefficients32To24[2][1] * In[3]; + tmp += kCoefficients32To24[2][2] * In[4]; + tmp += kCoefficients32To24[2][3] * In[5]; + tmp += kCoefficients32To24[2][4] * In[6]; + tmp += kCoefficients32To24[2][5] * In[7]; + tmp += kCoefficients32To24[2][6] * In[8]; + tmp += kCoefficients32To24[2][7] * In[9]; + Out[2] = tmp; + + // update pointers + In += 4; + Out += 3; + } +} + +// +// fractional resampling filters +// Fout = 11/16 * Fin +// Fout = 8/11 * Fin +// + +// compute two inner-products and store them to output array +static void WebRtcSpl_ResampDotProduct(const WebRtc_Word32 *in1, const WebRtc_Word32 *in2, + const WebRtc_Word16 *coef_ptr, WebRtc_Word32 *out1, + WebRtc_Word32 *out2) +{ + WebRtc_Word32 tmp1 = 16384; + WebRtc_Word32 tmp2 = 16384; + WebRtc_Word16 coef; + + coef = coef_ptr[0]; + tmp1 += coef * in1[0]; + tmp2 += coef * in2[-0]; + + coef = coef_ptr[1]; + tmp1 += coef * in1[1]; + tmp2 += coef * in2[-1]; + + coef = coef_ptr[2]; + tmp1 += coef * in1[2]; + tmp2 += coef * in2[-2]; + + coef = coef_ptr[3]; + tmp1 += coef * in1[3]; + tmp2 += coef * in2[-3]; + + coef = coef_ptr[4]; + tmp1 += coef * in1[4]; + tmp2 += coef * in2[-4]; + + coef = coef_ptr[5]; + tmp1 += coef * in1[5]; + tmp2 += coef * in2[-5]; + + coef = coef_ptr[6]; + tmp1 += coef * in1[6]; + tmp2 += coef * in2[-6]; + + coef = coef_ptr[7]; + tmp1 += coef * in1[7]; + tmp2 += coef * in2[-7]; + + coef = coef_ptr[8]; + *out1 = tmp1 + coef * in1[8]; + *out2 = tmp2 + coef * in2[-8]; +} + +// Resampling ratio: 8/11 +// input: WebRtc_Word32 (normalized, not saturated) :: size 11 * K +// output: WebRtc_Word32 (shifted 15 positions to the left, + offset 16384) :: size 8 * K +// K: number of blocks + +void WebRtcSpl_Resample44khzTo32khz(const WebRtc_Word32 *In, WebRtc_Word32 *Out, + const WebRtc_Word32 K) +{ + ///////////////////////////////////////////////////////////// + // Filter operation: + // + // Perform resampling (11 input samples -> 8 output samples); + // process in sub blocks of size 11 samples. + WebRtc_Word32 tmp; + WebRtc_Word32 m; + + for (m = 0; m < K; m++) + { + tmp = 1 << 14; + + // first output sample + Out[0] = ((WebRtc_Word32)In[3] << 15) + tmp; + + // sum and accumulate filter coefficients and input samples + tmp += kCoefficients44To32[3][0] * In[5]; + tmp += kCoefficients44To32[3][1] * In[6]; + tmp += kCoefficients44To32[3][2] * In[7]; + tmp += kCoefficients44To32[3][3] * In[8]; + tmp += kCoefficients44To32[3][4] * In[9]; + tmp += kCoefficients44To32[3][5] * In[10]; + tmp += kCoefficients44To32[3][6] * In[11]; + tmp += kCoefficients44To32[3][7] * In[12]; + tmp += kCoefficients44To32[3][8] * In[13]; + Out[4] = tmp; + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_ResampDotProduct(&In[0], &In[17], kCoefficients44To32[0], &Out[1], &Out[7]); + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_ResampDotProduct(&In[2], &In[15], kCoefficients44To32[1], &Out[2], &Out[6]); + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_ResampDotProduct(&In[3], &In[14], kCoefficients44To32[2], &Out[3], &Out[5]); + + // update pointers + In += 11; + Out += 8; + } +} diff --git a/libs/miniwebrtc/audio/common/processing/signal_processing_library.h b/libs/miniwebrtc/audio/common/processing/signal_processing_library.h new file mode 100644 index 00000000..87b8f293 --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/signal_processing_library.h @@ -0,0 +1,1667 @@ +/* + * 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. + */ + + +/* + * This header file includes all of the fix point signal processing library (SPL) function + * descriptions and declarations. + * For specific function calls, see bottom of file. + */ + +#ifndef WEBRTC_SPL_SIGNAL_PROCESSING_LIBRARY_H_ +#define WEBRTC_SPL_SIGNAL_PROCESSING_LIBRARY_H_ + +#include +#include "typedefs.h" + +#ifdef ARM_WINM +#include // intrinsic file for windows mobile +#endif + +// Macros specific for the fixed point implementation +#define WEBRTC_SPL_WORD16_MAX 32767 +#define WEBRTC_SPL_WORD16_MIN -32768 +#define WEBRTC_SPL_WORD32_MAX (WebRtc_Word32)0x7fffffff +#define WEBRTC_SPL_WORD32_MIN (WebRtc_Word32)0x80000000 +#define WEBRTC_SPL_MAX_LPC_ORDER 14 +#define WEBRTC_SPL_MAX_SEED_USED 0x80000000L +#define WEBRTC_SPL_MIN(A, B) (A < B ? A : B) // Get min value +#define WEBRTC_SPL_MAX(A, B) (A > B ? A : B) // Get max value +#define WEBRTC_SPL_ABS_W16(a) \ + (((WebRtc_Word16)a >= 0) ? ((WebRtc_Word16)a) : -((WebRtc_Word16)a)) +#define WEBRTC_SPL_ABS_W32(a) \ + (((WebRtc_Word32)a >= 0) ? ((WebRtc_Word32)a) : -((WebRtc_Word32)a)) + +#if (defined WEBRTC_TARGET_PC)||(defined __TARGET_XSCALE) +#define WEBRTC_SPL_GET_BYTE(a, nr) (((WebRtc_Word8 *)a)[nr]) +#define WEBRTC_SPL_SET_BYTE(d_ptr, val, index) \ + (((WebRtc_Word8 *)d_ptr)[index] = (val)) +#elif defined WEBRTC_BIG_ENDIAN +#define WEBRTC_SPL_GET_BYTE(a, nr) \ + ((((WebRtc_Word16 *)a)[nr >> 1]) >> (((nr + 1) & 0x1) * 8) & 0x00ff) +#define WEBRTC_SPL_SET_BYTE(d_ptr, val, index) \ + ((WebRtc_Word16 *)d_ptr)[index >> 1] = \ + ((((WebRtc_Word16 *)d_ptr)[index >> 1]) \ + & (0x00ff << (8 * ((index) & 0x1)))) | (val << (8 * ((index + 1) & 0x1))) +#else +#define WEBRTC_SPL_GET_BYTE(a,nr) \ + ((((WebRtc_Word16 *)(a))[(nr) >> 1]) >> (((nr) & 0x1) * 8) & 0x00ff) +#define WEBRTC_SPL_SET_BYTE(d_ptr, val, index) \ + ((WebRtc_Word16 *)(d_ptr))[(index) >> 1] = \ + ((((WebRtc_Word16 *)(d_ptr))[(index) >> 1]) \ + & (0x00ff << (8 * (((index) + 1) & 0x1)))) | \ + ((val) << (8 * ((index) & 0x1))) +#endif + +#define WEBRTC_SPL_MUL(a, b) \ + ((WebRtc_Word32) ((WebRtc_Word32)(a) * (WebRtc_Word32)(b))) +#define WEBRTC_SPL_UMUL(a, b) \ + ((WebRtc_UWord32) ((WebRtc_UWord32)(a) * (WebRtc_UWord32)(b))) +#define WEBRTC_SPL_UMUL_RSFT16(a, b) \ + ((WebRtc_UWord32) ((WebRtc_UWord32)(a) * (WebRtc_UWord32)(b)) >> 16) +#define WEBRTC_SPL_UMUL_16_16(a, b) \ + ((WebRtc_UWord32) (WebRtc_UWord16)(a) * (WebRtc_UWord16)(b)) +#define WEBRTC_SPL_UMUL_16_16_RSFT16(a, b) \ + (((WebRtc_UWord32) (WebRtc_UWord16)(a) * (WebRtc_UWord16)(b)) >> 16) +#define WEBRTC_SPL_UMUL_32_16(a, b) \ + ((WebRtc_UWord32) ((WebRtc_UWord32)(a) * (WebRtc_UWord16)(b))) +#define WEBRTC_SPL_UMUL_32_16_RSFT16(a, b) \ + ((WebRtc_UWord32) ((WebRtc_UWord32)(a) * (WebRtc_UWord16)(b)) >> 16) +#define WEBRTC_SPL_MUL_16_U16(a, b) \ + ((WebRtc_Word32)(WebRtc_Word16)(a) * (WebRtc_UWord16)(b)) +#define WEBRTC_SPL_DIV(a, b) \ + ((WebRtc_Word32) ((WebRtc_Word32)(a) / (WebRtc_Word32)(b))) +#define WEBRTC_SPL_UDIV(a, b) \ + ((WebRtc_UWord32) ((WebRtc_UWord32)(a) / (WebRtc_UWord32)(b))) + +#ifndef WEBRTC_ARCH_ARM_V7A +// For ARMv7 platforms, these are inline functions in spl_inl_armv7.h +#define WEBRTC_SPL_MUL_16_16(a, b) \ + ((WebRtc_Word32) (((WebRtc_Word16)(a)) * ((WebRtc_Word16)(b)))) +#define WEBRTC_SPL_MUL_16_32_RSFT16(a, b) \ + (WEBRTC_SPL_MUL_16_16(a, b >> 16) \ + + ((WEBRTC_SPL_MUL_16_16(a, (b & 0xffff) >> 1) + 0x4000) >> 15)) +#define WEBRTC_SPL_MUL_32_32_RSFT32(a32a, a32b, b32) \ + ((WebRtc_Word32)(WEBRTC_SPL_MUL_16_32_RSFT16(a32a, b32) \ + + (WEBRTC_SPL_MUL_16_32_RSFT16(a32b, b32) >> 16))) +#define WEBRTC_SPL_MUL_32_32_RSFT32BI(a32, b32) \ + ((WebRtc_Word32)(WEBRTC_SPL_MUL_16_32_RSFT16(( \ + (WebRtc_Word16)(a32 >> 16)), b32) + \ + (WEBRTC_SPL_MUL_16_32_RSFT16(( \ + (WebRtc_Word16)((a32 & 0x0000FFFF) >> 1)), b32) >> 15))) +#endif + +#define WEBRTC_SPL_MUL_16_32_RSFT11(a, b) \ + ((WEBRTC_SPL_MUL_16_16(a, (b) >> 16) << 5) \ + + (((WEBRTC_SPL_MUL_16_U16(a, (WebRtc_UWord16)(b)) >> 1) + 0x0200) >> 10)) +#define WEBRTC_SPL_MUL_16_32_RSFT14(a, b) \ + ((WEBRTC_SPL_MUL_16_16(a, (b) >> 16) << 2) \ + + (((WEBRTC_SPL_MUL_16_U16(a, (WebRtc_UWord16)(b)) >> 1) + 0x1000) >> 13)) +#define WEBRTC_SPL_MUL_16_32_RSFT15(a, b) \ + ((WEBRTC_SPL_MUL_16_16(a, (b) >> 16) << 1) \ + + (((WEBRTC_SPL_MUL_16_U16(a, (WebRtc_UWord16)(b)) >> 1) + 0x2000) >> 14)) + +#ifdef ARM_WINM +#define WEBRTC_SPL_MUL_16_16(a, b) \ + _SmulLo_SW_SL((WebRtc_Word16)(a), (WebRtc_Word16)(b)) +#endif + +#define WEBRTC_SPL_MUL_16_16_RSFT(a, b, c) \ + (WEBRTC_SPL_MUL_16_16(a, b) >> (c)) + +#define WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(a, b, c) \ + ((WEBRTC_SPL_MUL_16_16(a, b) + ((WebRtc_Word32) \ + (((WebRtc_Word32)1) << ((c) - 1)))) >> (c)) +#define WEBRTC_SPL_MUL_16_16_RSFT_WITH_FIXROUND(a, b) \ + ((WEBRTC_SPL_MUL_16_16(a, b) + ((WebRtc_Word32) (1 << 14))) >> 15) + +// C + the 32 most significant bits of A * B +#define WEBRTC_SPL_SCALEDIFF32(A, B, C) \ + (C + (B >> 16) * A + (((WebRtc_UWord32)(0x0000FFFF & B) * A) >> 16)) + +#define WEBRTC_SPL_ADD_SAT_W32(a, b) WebRtcSpl_AddSatW32(a, b) +#define WEBRTC_SPL_SAT(a, b, c) (b > a ? a : b < c ? c : b) +#define WEBRTC_SPL_MUL_32_16(a, b) ((a) * (b)) + +#define WEBRTC_SPL_SUB_SAT_W32(a, b) WebRtcSpl_SubSatW32(a, b) +#define WEBRTC_SPL_ADD_SAT_W16(a, b) WebRtcSpl_AddSatW16(a, b) +#define WEBRTC_SPL_SUB_SAT_W16(a, b) WebRtcSpl_SubSatW16(a, b) + +// We cannot do casting here due to signed/unsigned problem +#define WEBRTC_SPL_IS_NEG(a) ((a) & 0x80000000) +// Shifting with negative numbers allowed +// Positive means left shift +#define WEBRTC_SPL_SHIFT_W16(x, c) \ + (((c) >= 0) ? ((x) << (c)) : ((x) >> (-(c)))) +#define WEBRTC_SPL_SHIFT_W32(x, c) \ + (((c) >= 0) ? ((x) << (c)) : ((x) >> (-(c)))) + +// Shifting with negative numbers not allowed +// We cannot do casting here due to signed/unsigned problem +#define WEBRTC_SPL_RSHIFT_W16(x, c) ((x) >> (c)) +#define WEBRTC_SPL_LSHIFT_W16(x, c) ((x) << (c)) +#define WEBRTC_SPL_RSHIFT_W32(x, c) ((x) >> (c)) +#define WEBRTC_SPL_LSHIFT_W32(x, c) ((x) << (c)) + +#define WEBRTC_SPL_RSHIFT_U16(x, c) ((WebRtc_UWord16)(x) >> (c)) +#define WEBRTC_SPL_LSHIFT_U16(x, c) ((WebRtc_UWord16)(x) << (c)) +#define WEBRTC_SPL_RSHIFT_U32(x, c) ((WebRtc_UWord32)(x) >> (c)) +#define WEBRTC_SPL_LSHIFT_U32(x, c) ((WebRtc_UWord32)(x) << (c)) + +#define WEBRTC_SPL_VNEW(t, n) (t *) malloc (sizeof (t) * (n)) +#define WEBRTC_SPL_FREE free + +#define WEBRTC_SPL_RAND(a) \ + ((WebRtc_Word16)(WEBRTC_SPL_MUL_16_16_RSFT((a), 18816, 7) & 0x00007fff)) + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define WEBRTC_SPL_MEMCPY_W8(v1, v2, length) \ + memcpy(v1, v2, (length) * sizeof(char)) +#define WEBRTC_SPL_MEMCPY_W16(v1, v2, length) \ + memcpy(v1, v2, (length) * sizeof(WebRtc_Word16)) + +#define WEBRTC_SPL_MEMMOVE_W16(v1, v2, length) \ + memmove(v1, v2, (length) * sizeof(WebRtc_Word16)) + +// inline functions: +#include "spl_inl.h" + +// Get SPL Version +WebRtc_Word16 WebRtcSpl_get_version(char* version, + WebRtc_Word16 length_in_bytes); + +int WebRtcSpl_GetScalingSquare(WebRtc_Word16* in_vector, + int in_vector_length, + int times); + +// Copy and set operations. Implementation in copy_set_operations.c. +// Descriptions at bottom of file. +void WebRtcSpl_MemSetW16(WebRtc_Word16* vector, + WebRtc_Word16 set_value, + int vector_length); +void WebRtcSpl_MemSetW32(WebRtc_Word32* vector, + WebRtc_Word32 set_value, + int vector_length); +void WebRtcSpl_MemCpyReversedOrder(WebRtc_Word16* out_vector, + WebRtc_Word16* in_vector, + int vector_length); +WebRtc_Word16 WebRtcSpl_CopyFromEndW16(G_CONST WebRtc_Word16* in_vector, + WebRtc_Word16 in_vector_length, + WebRtc_Word16 samples, + WebRtc_Word16* out_vector); +WebRtc_Word16 WebRtcSpl_ZerosArrayW16(WebRtc_Word16* vector, + WebRtc_Word16 vector_length); +WebRtc_Word16 WebRtcSpl_ZerosArrayW32(WebRtc_Word32* vector, + WebRtc_Word16 vector_length); +WebRtc_Word16 WebRtcSpl_OnesArrayW16(WebRtc_Word16* vector, + WebRtc_Word16 vector_length); +WebRtc_Word16 WebRtcSpl_OnesArrayW32(WebRtc_Word32* vector, + WebRtc_Word16 vector_length); +// End: Copy and set operations. + +// Minimum and maximum operations. Implementation in min_max_operations.c. +// Descriptions at bottom of file. +WebRtc_Word16 WebRtcSpl_MaxAbsValueW16(const WebRtc_Word16* vector, + WebRtc_Word16 length); +WebRtc_Word32 WebRtcSpl_MaxAbsValueW32(G_CONST WebRtc_Word32* vector, + WebRtc_Word16 length); +WebRtc_Word16 WebRtcSpl_MinValueW16(G_CONST WebRtc_Word16* vector, + WebRtc_Word16 length); +WebRtc_Word32 WebRtcSpl_MinValueW32(G_CONST WebRtc_Word32* vector, + WebRtc_Word16 length); +WebRtc_Word16 WebRtcSpl_MaxValueW16(G_CONST WebRtc_Word16* vector, + WebRtc_Word16 length); + +WebRtc_Word16 WebRtcSpl_MaxAbsIndexW16(G_CONST WebRtc_Word16* vector, + WebRtc_Word16 length); +WebRtc_Word32 WebRtcSpl_MaxValueW32(G_CONST WebRtc_Word32* vector, + WebRtc_Word16 length); +WebRtc_Word16 WebRtcSpl_MinIndexW16(G_CONST WebRtc_Word16* vector, + WebRtc_Word16 length); +WebRtc_Word16 WebRtcSpl_MinIndexW32(G_CONST WebRtc_Word32* vector, + WebRtc_Word16 length); +WebRtc_Word16 WebRtcSpl_MaxIndexW16(G_CONST WebRtc_Word16* vector, + WebRtc_Word16 length); +WebRtc_Word16 WebRtcSpl_MaxIndexW32(G_CONST WebRtc_Word32* vector, + WebRtc_Word16 length); +// End: Minimum and maximum operations. + +// Vector scaling operations. Implementation in vector_scaling_operations.c. +// Description at bottom of file. +void WebRtcSpl_VectorBitShiftW16(WebRtc_Word16* out_vector, + WebRtc_Word16 vector_length, + G_CONST WebRtc_Word16* in_vector, + WebRtc_Word16 right_shifts); +void WebRtcSpl_VectorBitShiftW32(WebRtc_Word32* out_vector, + WebRtc_Word16 vector_length, + G_CONST WebRtc_Word32* in_vector, + WebRtc_Word16 right_shifts); +void WebRtcSpl_VectorBitShiftW32ToW16(WebRtc_Word16* out_vector, + WebRtc_Word16 vector_length, + G_CONST WebRtc_Word32* in_vector, + WebRtc_Word16 right_shifts); + +void WebRtcSpl_ScaleVector(G_CONST WebRtc_Word16* in_vector, + WebRtc_Word16* out_vector, + WebRtc_Word16 gain, + WebRtc_Word16 vector_length, + WebRtc_Word16 right_shifts); +void WebRtcSpl_ScaleVectorWithSat(G_CONST WebRtc_Word16* in_vector, + WebRtc_Word16* out_vector, + WebRtc_Word16 gain, + WebRtc_Word16 vector_length, + WebRtc_Word16 right_shifts); +void WebRtcSpl_ScaleAndAddVectors(G_CONST WebRtc_Word16* in_vector1, + WebRtc_Word16 gain1, int right_shifts1, + G_CONST WebRtc_Word16* in_vector2, + WebRtc_Word16 gain2, int right_shifts2, + WebRtc_Word16* out_vector, + int vector_length); +// End: Vector scaling operations. + +// iLBC specific functions. Implementations in ilbc_specific_functions.c. +// Description at bottom of file. +void WebRtcSpl_ScaleAndAddVectorsWithRound(WebRtc_Word16* in_vector1, + WebRtc_Word16 scale1, + WebRtc_Word16* in_vector2, + WebRtc_Word16 scale2, + WebRtc_Word16 right_shifts, + WebRtc_Word16* out_vector, + WebRtc_Word16 vector_length); +void WebRtcSpl_ReverseOrderMultArrayElements(WebRtc_Word16* out_vector, + G_CONST WebRtc_Word16* in_vector, + G_CONST WebRtc_Word16* window, + WebRtc_Word16 vector_length, + WebRtc_Word16 right_shifts); +void WebRtcSpl_ElementwiseVectorMult(WebRtc_Word16* out_vector, + G_CONST WebRtc_Word16* in_vector, + G_CONST WebRtc_Word16* window, + WebRtc_Word16 vector_length, + WebRtc_Word16 right_shifts); +void WebRtcSpl_AddVectorsAndShift(WebRtc_Word16* out_vector, + G_CONST WebRtc_Word16* in_vector1, + G_CONST WebRtc_Word16* in_vector2, + WebRtc_Word16 vector_length, + WebRtc_Word16 right_shifts); +void WebRtcSpl_AddAffineVectorToVector(WebRtc_Word16* out_vector, + WebRtc_Word16* in_vector, + WebRtc_Word16 gain, + WebRtc_Word32 add_constant, + WebRtc_Word16 right_shifts, + int vector_length); +void WebRtcSpl_AffineTransformVector(WebRtc_Word16* out_vector, + WebRtc_Word16* in_vector, + WebRtc_Word16 gain, + WebRtc_Word32 add_constant, + WebRtc_Word16 right_shifts, + int vector_length); +// End: iLBC specific functions. + +// Signal processing operations. Descriptions at bottom of this file. +int WebRtcSpl_AutoCorrelation(G_CONST WebRtc_Word16* vector, + int vector_length, int order, + WebRtc_Word32* result_vector, + int* scale); +WebRtc_Word16 WebRtcSpl_LevinsonDurbin(WebRtc_Word32* auto_corr, + WebRtc_Word16* lpc_coef, + WebRtc_Word16* refl_coef, + WebRtc_Word16 order); +void WebRtcSpl_ReflCoefToLpc(G_CONST WebRtc_Word16* refl_coef, + int use_order, + WebRtc_Word16* lpc_coef); +void WebRtcSpl_LpcToReflCoef(WebRtc_Word16* lpc_coef, + int use_order, + WebRtc_Word16* refl_coef); +void WebRtcSpl_AutoCorrToReflCoef(G_CONST WebRtc_Word32* auto_corr, + int use_order, + WebRtc_Word16* refl_coef); +void WebRtcSpl_CrossCorrelation(WebRtc_Word32* cross_corr, + WebRtc_Word16* vector1, + WebRtc_Word16* vector2, + WebRtc_Word16 dim_vector, + WebRtc_Word16 dim_cross_corr, + WebRtc_Word16 right_shifts, + WebRtc_Word16 step_vector2); +void WebRtcSpl_GetHanningWindow(WebRtc_Word16* window, WebRtc_Word16 size); +void WebRtcSpl_SqrtOfOneMinusXSquared(WebRtc_Word16* in_vector, + int vector_length, + WebRtc_Word16* out_vector); +// End: Signal processing operations. + +// Randomization functions. Implementations collected in randomization_functions.c and +// descriptions at bottom of this file. +WebRtc_UWord32 WebRtcSpl_IncreaseSeed(WebRtc_UWord32* seed); +WebRtc_Word16 WebRtcSpl_RandU(WebRtc_UWord32* seed); +WebRtc_Word16 WebRtcSpl_RandN(WebRtc_UWord32* seed); +WebRtc_Word16 WebRtcSpl_RandUArray(WebRtc_Word16* vector, + WebRtc_Word16 vector_length, + WebRtc_UWord32* seed); +// End: Randomization functions. + +// Math functions +WebRtc_Word32 WebRtcSpl_Sqrt(WebRtc_Word32 value); +WebRtc_Word32 WebRtcSpl_SqrtFloor(WebRtc_Word32 value); + +// Divisions. Implementations collected in division_operations.c and +// descriptions at bottom of this file. +WebRtc_UWord32 WebRtcSpl_DivU32U16(WebRtc_UWord32 num, WebRtc_UWord16 den); +WebRtc_Word32 WebRtcSpl_DivW32W16(WebRtc_Word32 num, WebRtc_Word16 den); +WebRtc_Word16 WebRtcSpl_DivW32W16ResW16(WebRtc_Word32 num, WebRtc_Word16 den); +WebRtc_Word32 WebRtcSpl_DivResultInQ31(WebRtc_Word32 num, WebRtc_Word32 den); +WebRtc_Word32 WebRtcSpl_DivW32HiLow(WebRtc_Word32 num, WebRtc_Word16 den_hi, + WebRtc_Word16 den_low); +// End: Divisions. + +WebRtc_Word32 WebRtcSpl_Energy(WebRtc_Word16* vector, + int vector_length, + int* scale_factor); + +WebRtc_Word32 WebRtcSpl_DotProductWithScale(WebRtc_Word16* vector1, + WebRtc_Word16* vector2, + int vector_length, + int scaling); + +// Filter operations. +int WebRtcSpl_FilterAR(G_CONST WebRtc_Word16* ar_coef, int ar_coef_length, + G_CONST WebRtc_Word16* in_vector, int in_vector_length, + WebRtc_Word16* filter_state, int filter_state_length, + WebRtc_Word16* filter_state_low, + int filter_state_low_length, WebRtc_Word16* out_vector, + WebRtc_Word16* out_vector_low, int out_vector_low_length); + +void WebRtcSpl_FilterMAFastQ12(WebRtc_Word16* in_vector, + WebRtc_Word16* out_vector, + WebRtc_Word16* ma_coef, + WebRtc_Word16 ma_coef_length, + WebRtc_Word16 vector_length); + +// Performs a AR filtering on a vector in Q12 +// Input: +// - data_in : Input samples +// - data_out : State information in positions +// data_out[-order] .. data_out[-1] +// - coefficients : Filter coefficients (in Q12) +// - coefficients_length: Number of coefficients (order+1) +// - data_length : Number of samples to be filtered +// Output: +// - data_out : Filtered samples +void WebRtcSpl_FilterARFastQ12(const int16_t* data_in, + int16_t* data_out, + const int16_t* __restrict coefficients, + int coefficients_length, + int data_length); + +// Performs a MA down sampling filter on a vector +// Input: +// - data_in : Input samples (state in positions +// data_in[-order] .. data_in[-1]) +// - data_in_length : Number of samples in |data_in| to be filtered. +// This must be at least +// |delay| + |factor|*(|out_vector_length|-1) + 1) +// - data_out_length : Number of down sampled samples desired +// - coefficients : Filter coefficients (in Q12) +// - coefficients_length: Number of coefficients (order+1) +// - factor : Decimation factor +// - delay : Delay of filter (compensated for in out_vector) +// Output: +// - data_out : Filtered samples +// Return value : 0 if OK, -1 if |in_vector| is too short +int WebRtcSpl_DownsampleFast(const int16_t* data_in, + int data_in_length, + int16_t* data_out, + int data_out_length, + const int16_t* __restrict coefficients, + int coefficients_length, + int factor, + int delay); + +// End: Filter operations. + +// FFT operations + +int WebRtcSpl_ComplexFFT(WebRtc_Word16 vector[], int stages, int mode); +int WebRtcSpl_ComplexIFFT(WebRtc_Word16 vector[], int stages, int mode); + +// Treat a 16-bit complex data buffer |complex_data| as an array of 32-bit +// values, and swap elements whose indexes are bit-reverses of each other. +// +// Input: +// - complex_data : Complex data buffer containing 2^|stages| real +// elements interleaved with 2^|stages| imaginary +// elements: [Re Im Re Im Re Im....] +// - stages : Number of FFT stages. Must be at least 3 and at most +// 10, since the table WebRtcSpl_kSinTable1024[] is 1024 +// elements long. +// +// Output: +// - complex_data : The complex data buffer. + +void WebRtcSpl_ComplexBitReverse(int16_t* __restrict complex_data, int stages); + +// End: FFT operations + +/************************************************************ + * + * RESAMPLING FUNCTIONS AND THEIR STRUCTS ARE DEFINED BELOW + * + ************************************************************/ + +/******************************************************************* + * resample.c + * + * Includes the following resampling combinations + * 22 kHz -> 16 kHz + * 16 kHz -> 22 kHz + * 22 kHz -> 8 kHz + * 8 kHz -> 22 kHz + * + ******************************************************************/ + +// state structure for 22 -> 16 resampler +typedef struct +{ + WebRtc_Word32 S_22_44[8]; + WebRtc_Word32 S_44_32[8]; + WebRtc_Word32 S_32_16[8]; +} WebRtcSpl_State22khzTo16khz; + +void WebRtcSpl_Resample22khzTo16khz(const WebRtc_Word16* in, + WebRtc_Word16* out, + WebRtcSpl_State22khzTo16khz* state, + WebRtc_Word32* tmpmem); + +void WebRtcSpl_ResetResample22khzTo16khz(WebRtcSpl_State22khzTo16khz* state); + +// state structure for 16 -> 22 resampler +typedef struct +{ + WebRtc_Word32 S_16_32[8]; + WebRtc_Word32 S_32_22[8]; +} WebRtcSpl_State16khzTo22khz; + +void WebRtcSpl_Resample16khzTo22khz(const WebRtc_Word16* in, + WebRtc_Word16* out, + WebRtcSpl_State16khzTo22khz* state, + WebRtc_Word32* tmpmem); + +void WebRtcSpl_ResetResample16khzTo22khz(WebRtcSpl_State16khzTo22khz* state); + +// state structure for 22 -> 8 resampler +typedef struct +{ + WebRtc_Word32 S_22_22[16]; + WebRtc_Word32 S_22_16[8]; + WebRtc_Word32 S_16_8[8]; +} WebRtcSpl_State22khzTo8khz; + +void WebRtcSpl_Resample22khzTo8khz(const WebRtc_Word16* in, WebRtc_Word16* out, + WebRtcSpl_State22khzTo8khz* state, + WebRtc_Word32* tmpmem); + +void WebRtcSpl_ResetResample22khzTo8khz(WebRtcSpl_State22khzTo8khz* state); + +// state structure for 8 -> 22 resampler +typedef struct +{ + WebRtc_Word32 S_8_16[8]; + WebRtc_Word32 S_16_11[8]; + WebRtc_Word32 S_11_22[8]; +} WebRtcSpl_State8khzTo22khz; + +void WebRtcSpl_Resample8khzTo22khz(const WebRtc_Word16* in, WebRtc_Word16* out, + WebRtcSpl_State8khzTo22khz* state, + WebRtc_Word32* tmpmem); + +void WebRtcSpl_ResetResample8khzTo22khz(WebRtcSpl_State8khzTo22khz* state); + +/******************************************************************* + * resample_fractional.c + * Functions for internal use in the other resample functions + * + * Includes the following resampling combinations + * 48 kHz -> 32 kHz + * 32 kHz -> 24 kHz + * 44 kHz -> 32 kHz + * + ******************************************************************/ + +void WebRtcSpl_Resample48khzTo32khz(const WebRtc_Word32* In, WebRtc_Word32* Out, + const WebRtc_Word32 K); + +void WebRtcSpl_Resample32khzTo24khz(const WebRtc_Word32* In, WebRtc_Word32* Out, + const WebRtc_Word32 K); + +void WebRtcSpl_Resample44khzTo32khz(const WebRtc_Word32* In, WebRtc_Word32* Out, + const WebRtc_Word32 K); + +/******************************************************************* + * resample_48khz.c + * + * Includes the following resampling combinations + * 48 kHz -> 16 kHz + * 16 kHz -> 48 kHz + * 48 kHz -> 8 kHz + * 8 kHz -> 48 kHz + * + ******************************************************************/ + +typedef struct +{ + WebRtc_Word32 S_48_48[16]; + WebRtc_Word32 S_48_32[8]; + WebRtc_Word32 S_32_16[8]; +} WebRtcSpl_State48khzTo16khz; + +void WebRtcSpl_Resample48khzTo16khz(const WebRtc_Word16* in, WebRtc_Word16* out, + WebRtcSpl_State48khzTo16khz* state, + WebRtc_Word32* tmpmem); + +void WebRtcSpl_ResetResample48khzTo16khz(WebRtcSpl_State48khzTo16khz* state); + +typedef struct +{ + WebRtc_Word32 S_16_32[8]; + WebRtc_Word32 S_32_24[8]; + WebRtc_Word32 S_24_48[8]; +} WebRtcSpl_State16khzTo48khz; + +void WebRtcSpl_Resample16khzTo48khz(const WebRtc_Word16* in, WebRtc_Word16* out, + WebRtcSpl_State16khzTo48khz* state, + WebRtc_Word32* tmpmem); + +void WebRtcSpl_ResetResample16khzTo48khz(WebRtcSpl_State16khzTo48khz* state); + +typedef struct +{ + WebRtc_Word32 S_48_24[8]; + WebRtc_Word32 S_24_24[16]; + WebRtc_Word32 S_24_16[8]; + WebRtc_Word32 S_16_8[8]; +} WebRtcSpl_State48khzTo8khz; + +void WebRtcSpl_Resample48khzTo8khz(const WebRtc_Word16* in, WebRtc_Word16* out, + WebRtcSpl_State48khzTo8khz* state, + WebRtc_Word32* tmpmem); + +void WebRtcSpl_ResetResample48khzTo8khz(WebRtcSpl_State48khzTo8khz* state); + +typedef struct +{ + WebRtc_Word32 S_8_16[8]; + WebRtc_Word32 S_16_12[8]; + WebRtc_Word32 S_12_24[8]; + WebRtc_Word32 S_24_48[8]; +} WebRtcSpl_State8khzTo48khz; + +void WebRtcSpl_Resample8khzTo48khz(const WebRtc_Word16* in, WebRtc_Word16* out, + WebRtcSpl_State8khzTo48khz* state, + WebRtc_Word32* tmpmem); + +void WebRtcSpl_ResetResample8khzTo48khz(WebRtcSpl_State8khzTo48khz* state); + +/******************************************************************* + * resample_by_2.c + * + * Includes down and up sampling by a factor of two. + * + ******************************************************************/ + +void WebRtcSpl_DownsampleBy2(const WebRtc_Word16* in, const WebRtc_Word16 len, + WebRtc_Word16* out, WebRtc_Word32* filtState); + +void WebRtcSpl_UpsampleBy2(const WebRtc_Word16* in, WebRtc_Word16 len, WebRtc_Word16* out, + WebRtc_Word32* filtState); + +/************************************************************ + * END OF RESAMPLING FUNCTIONS + ************************************************************/ +void WebRtcSpl_AnalysisQMF(const WebRtc_Word16* in_data, + WebRtc_Word16* low_band, + WebRtc_Word16* high_band, + WebRtc_Word32* filter_state1, + WebRtc_Word32* filter_state2); +void WebRtcSpl_SynthesisQMF(const WebRtc_Word16* low_band, + const WebRtc_Word16* high_band, + WebRtc_Word16* out_data, + WebRtc_Word32* filter_state1, + WebRtc_Word32* filter_state2); + +#ifdef __cplusplus +} +#endif // __cplusplus +#endif // WEBRTC_SPL_SIGNAL_PROCESSING_LIBRARY_H_ + +// +// WebRtcSpl_AddSatW16(...) +// WebRtcSpl_AddSatW32(...) +// +// Returns the result of a saturated 16-bit, respectively 32-bit, addition of +// the numbers specified by the |var1| and |var2| parameters. +// +// Input: +// - var1 : Input variable 1 +// - var2 : Input variable 2 +// +// Return value : Added and saturated value +// + +// +// WebRtcSpl_SubSatW16(...) +// WebRtcSpl_SubSatW32(...) +// +// Returns the result of a saturated 16-bit, respectively 32-bit, subtraction +// of the numbers specified by the |var1| and |var2| parameters. +// +// Input: +// - var1 : Input variable 1 +// - var2 : Input variable 2 +// +// Returned value : Subtracted and saturated value +// + +// +// WebRtcSpl_GetSizeInBits(...) +// +// Returns the # of bits that are needed at the most to represent the number +// specified by the |value| parameter. +// +// Input: +// - value : Input value +// +// Return value : Number of bits needed to represent |value| +// + +// +// WebRtcSpl_NormW32(...) +// +// Norm returns the # of left shifts required to 32-bit normalize the 32-bit +// signed number specified by the |value| parameter. +// +// Input: +// - value : Input value +// +// Return value : Number of bit shifts needed to 32-bit normalize |value| +// + +// +// WebRtcSpl_NormW16(...) +// +// Norm returns the # of left shifts required to 16-bit normalize the 16-bit +// signed number specified by the |value| parameter. +// +// Input: +// - value : Input value +// +// Return value : Number of bit shifts needed to 32-bit normalize |value| +// + +// +// WebRtcSpl_NormU32(...) +// +// Norm returns the # of left shifts required to 32-bit normalize the unsigned +// 32-bit number specified by the |value| parameter. +// +// Input: +// - value : Input value +// +// Return value : Number of bit shifts needed to 32-bit normalize |value| +// + +// +// WebRtcSpl_GetScalingSquare(...) +// +// Returns the # of bits required to scale the samples specified in the +// |in_vector| parameter so that, if the squares of the samples are added the +// # of times specified by the |times| parameter, the 32-bit addition will not +// overflow (result in WebRtc_Word32). +// +// Input: +// - in_vector : Input vector to check scaling on +// - in_vector_length : Samples in |in_vector| +// - times : Number of additions to be performed +// +// Return value : Number of right bit shifts needed to avoid +// overflow in the addition calculation +// + +// +// WebRtcSpl_MemSetW16(...) +// +// Sets all the values in the WebRtc_Word16 vector |vector| of length +// |vector_length| to the specified value |set_value| +// +// Input: +// - vector : Pointer to the WebRtc_Word16 vector +// - set_value : Value specified +// - vector_length : Length of vector +// + +// +// WebRtcSpl_MemSetW32(...) +// +// Sets all the values in the WebRtc_Word32 vector |vector| of length +// |vector_length| to the specified value |set_value| +// +// Input: +// - vector : Pointer to the WebRtc_Word16 vector +// - set_value : Value specified +// - vector_length : Length of vector +// + +// +// WebRtcSpl_MemCpyReversedOrder(...) +// +// Copies all the values from the source WebRtc_Word16 vector |in_vector| to a +// destination WebRtc_Word16 vector |out_vector|. It is done in reversed order, +// meaning that the first sample of |in_vector| is copied to the last sample of +// the |out_vector|. The procedure continues until the last sample of +// |in_vector| has been copied to the first sample of |out_vector|. This +// creates a reversed vector. Used in e.g. prediction in iLBC. +// +// Input: +// - in_vector : Pointer to the first sample in a WebRtc_Word16 vector +// of length |length| +// - vector_length : Number of elements to copy +// +// Output: +// - out_vector : Pointer to the last sample in a WebRtc_Word16 vector +// of length |length| +// + +// +// WebRtcSpl_CopyFromEndW16(...) +// +// Copies the rightmost |samples| of |in_vector| (of length |in_vector_length|) +// to the vector |out_vector|. +// +// Input: +// - in_vector : Input vector +// - in_vector_length : Number of samples in |in_vector| +// - samples : Number of samples to extract (from right side) +// from |in_vector| +// +// Output: +// - out_vector : Vector with the requested samples +// +// Return value : Number of copied samples in |out_vector| +// + +// +// WebRtcSpl_ZerosArrayW16(...) +// WebRtcSpl_ZerosArrayW32(...) +// +// Inserts the value "zero" in all positions of a w16 and a w32 vector +// respectively. +// +// Input: +// - vector_length : Number of samples in vector +// +// Output: +// - vector : Vector containing all zeros +// +// Return value : Number of samples in vector +// + +// +// WebRtcSpl_OnesArrayW16(...) +// WebRtcSpl_OnesArrayW32(...) +// +// Inserts the value "one" in all positions of a w16 and a w32 vector +// respectively. +// +// Input: +// - vector_length : Number of samples in vector +// +// Output: +// - vector : Vector containing all ones +// +// Return value : Number of samples in vector +// + +// +// WebRtcSpl_MinValueW16(...) +// WebRtcSpl_MinValueW32(...) +// +// Returns the minimum value of a vector +// +// Input: +// - vector : Input vector +// - vector_length : Number of samples in vector +// +// Return value : Minimum sample value in vector +// + +// +// WebRtcSpl_MaxValueW16(...) +// WebRtcSpl_MaxValueW32(...) +// +// Returns the maximum value of a vector +// +// Input: +// - vector : Input vector +// - vector_length : Number of samples in vector +// +// Return value : Maximum sample value in vector +// + +// +// WebRtcSpl_MaxAbsValueW16(...) +// WebRtcSpl_MaxAbsValueW32(...) +// +// Returns the largest absolute value of a vector +// +// Input: +// - vector : Input vector +// - vector_length : Number of samples in vector +// +// Return value : Maximum absolute value in vector +// + +// +// WebRtcSpl_MaxAbsIndexW16(...) +// +// Returns the vector index to the largest absolute value of a vector +// +// Input: +// - vector : Input vector +// - vector_length : Number of samples in vector +// +// Return value : Index to maximum absolute value in vector +// + +// +// WebRtcSpl_MinIndexW16(...) +// WebRtcSpl_MinIndexW32(...) +// +// Returns the vector index to the minimum sample value of a vector +// +// Input: +// - vector : Input vector +// - vector_length : Number of samples in vector +// +// Return value : Index to minimum sample value in vector +// + +// +// WebRtcSpl_MaxIndexW16(...) +// WebRtcSpl_MaxIndexW32(...) +// +// Returns the vector index to the maximum sample value of a vector +// +// Input: +// - vector : Input vector +// - vector_length : Number of samples in vector +// +// Return value : Index to maximum sample value in vector +// + +// +// WebRtcSpl_VectorBitShiftW16(...) +// WebRtcSpl_VectorBitShiftW32(...) +// +// Bit shifts all the values in a vector up or downwards. Different calls for +// WebRtc_Word16 and WebRtc_Word32 vectors respectively. +// +// Input: +// - vector_length : Length of vector +// - in_vector : Pointer to the vector that should be bit shifted +// - right_shifts : Number of right bit shifts (negative value gives left +// shifts) +// +// Output: +// - out_vector : Pointer to the result vector (can be the same as +// |in_vector|) +// + +// +// WebRtcSpl_VectorBitShiftW32ToW16(...) +// +// Bit shifts all the values in a WebRtc_Word32 vector up or downwards and +// stores the result as a WebRtc_Word16 vector +// +// Input: +// - vector_length : Length of vector +// - in_vector : Pointer to the vector that should be bit shifted +// - right_shifts : Number of right bit shifts (negative value gives left +// shifts) +// +// Output: +// - out_vector : Pointer to the result vector (can be the same as +// |in_vector|) +// + +// +// WebRtcSpl_ScaleVector(...) +// +// Performs the vector operation: +// out_vector[k] = (gain*in_vector[k])>>right_shifts +// +// Input: +// - in_vector : Input vector +// - gain : Scaling gain +// - vector_length : Elements in the |in_vector| +// - right_shifts : Number of right bit shifts applied +// +// Output: +// - out_vector : Output vector (can be the same as |in_vector|) +// + +// +// WebRtcSpl_ScaleVectorWithSat(...) +// +// Performs the vector operation: +// out_vector[k] = SATURATE( (gain*in_vector[k])>>right_shifts ) +// +// Input: +// - in_vector : Input vector +// - gain : Scaling gain +// - vector_length : Elements in the |in_vector| +// - right_shifts : Number of right bit shifts applied +// +// Output: +// - out_vector : Output vector (can be the same as |in_vector|) +// + +// +// WebRtcSpl_ScaleAndAddVectors(...) +// +// Performs the vector operation: +// out_vector[k] = (gain1*in_vector1[k])>>right_shifts1 +// + (gain2*in_vector2[k])>>right_shifts2 +// +// Input: +// - in_vector1 : Input vector 1 +// - gain1 : Gain to be used for vector 1 +// - right_shifts1 : Right bit shift to be used for vector 1 +// - in_vector2 : Input vector 2 +// - gain2 : Gain to be used for vector 2 +// - right_shifts2 : Right bit shift to be used for vector 2 +// - vector_length : Elements in the input vectors +// +// Output: +// - out_vector : Output vector +// + +// +// WebRtcSpl_ScaleAndAddVectorsWithRound(...) +// +// Performs the vector operation: +// +// out_vector[k] = ((scale1*in_vector1[k]) + (scale2*in_vector2[k]) +// + round_value) >> right_shifts +// +// where: +// +// round_value = (1<>1 +// +// Input: +// - in_vector1 : Input vector 1 +// - scale1 : Gain to be used for vector 1 +// - in_vector2 : Input vector 2 +// - scale2 : Gain to be used for vector 2 +// - right_shifts : Number of right bit shifts to be applied +// - vector_length : Number of elements in the input vectors +// +// Output: +// - out_vector : Output vector +// + +// +// WebRtcSpl_ReverseOrderMultArrayElements(...) +// +// Performs the vector operation: +// out_vector[n] = (in_vector[n]*window[-n])>>right_shifts +// +// Input: +// - in_vector : Input vector +// - window : Window vector (should be reversed). The pointer +// should be set to the last value in the vector +// - right_shifts : Number of right bit shift to be applied after the +// multiplication +// - vector_length : Number of elements in |in_vector| +// +// Output: +// - out_vector : Output vector (can be same as |in_vector|) +// + +// +// WebRtcSpl_ElementwiseVectorMult(...) +// +// Performs the vector operation: +// out_vector[n] = (in_vector[n]*window[n])>>right_shifts +// +// Input: +// - in_vector : Input vector +// - window : Window vector. +// - right_shifts : Number of right bit shift to be applied after the +// multiplication +// - vector_length : Number of elements in |in_vector| +// +// Output: +// - out_vector : Output vector (can be same as |in_vector|) +// + +// +// WebRtcSpl_AddVectorsAndShift(...) +// +// Performs the vector operation: +// out_vector[k] = (in_vector1[k] + in_vector2[k])>>right_shifts +// +// Input: +// - in_vector1 : Input vector 1 +// - in_vector2 : Input vector 2 +// - right_shifts : Number of right bit shift to be applied after the +// multiplication +// - vector_length : Number of elements in |in_vector1| and |in_vector2| +// +// Output: +// - out_vector : Output vector (can be same as |in_vector1|) +// + +// +// WebRtcSpl_AddAffineVectorToVector(...) +// +// Adds an affine transformed vector to another vector |out_vector|, i.e, +// performs +// out_vector[k] += (in_vector[k]*gain+add_constant)>>right_shifts +// +// Input: +// - in_vector : Input vector +// - gain : Gain value, used to multiply the in vector with +// - add_constant : Constant value to add (usually 1<<(right_shifts-1), +// but others can be used as well +// - right_shifts : Number of right bit shifts (0-16) +// - vector_length : Number of samples in |in_vector| and |out_vector| +// +// Output: +// - out_vector : Vector with the output +// + +// +// WebRtcSpl_AffineTransformVector(...) +// +// Affine transforms a vector, i.e, performs +// out_vector[k] = (in_vector[k]*gain+add_constant)>>right_shifts +// +// Input: +// - in_vector : Input vector +// - gain : Gain value, used to multiply the in vector with +// - add_constant : Constant value to add (usually 1<<(right_shifts-1), +// but others can be used as well +// - right_shifts : Number of right bit shifts (0-16) +// - vector_length : Number of samples in |in_vector| and |out_vector| +// +// Output: +// - out_vector : Vector with the output +// + +// +// WebRtcSpl_AutoCorrelation(...) +// +// A 32-bit fix-point implementation of auto-correlation computation +// +// Input: +// - vector : Vector to calculate autocorrelation upon +// - vector_length : Length (in samples) of |vector| +// - order : The order up to which the autocorrelation should be +// calculated +// +// Output: +// - result_vector : auto-correlation values (values should be seen +// relative to each other since the absolute values +// might have been down shifted to avoid overflow) +// +// - scale : The number of left shifts required to obtain the +// auto-correlation in Q0 +// +// Return value : Number of samples in |result_vector|, i.e., (order+1) +// + +// +// WebRtcSpl_LevinsonDurbin(...) +// +// A 32-bit fix-point implementation of the Levinson-Durbin algorithm that +// does NOT use the 64 bit class +// +// Input: +// - auto_corr : Vector with autocorrelation values of length >= +// |use_order|+1 +// - use_order : The LPC filter order (support up to order 20) +// +// Output: +// - lpc_coef : lpc_coef[0..use_order] LPC coefficients in Q12 +// - refl_coef : refl_coef[0...use_order-1]| Reflection coefficients in +// Q15 +// +// Return value : 1 for stable 0 for unstable +// + +// +// WebRtcSpl_ReflCoefToLpc(...) +// +// Converts reflection coefficients |refl_coef| to LPC coefficients |lpc_coef|. +// This version is a 16 bit operation. +// +// NOTE: The 16 bit refl_coef -> lpc_coef conversion might result in a +// "slightly unstable" filter (i.e., a pole just outside the unit circle) in +// "rare" cases even if the reflection coefficients are stable. +// +// Input: +// - refl_coef : Reflection coefficients in Q15 that should be converted +// to LPC coefficients +// - use_order : Number of coefficients in |refl_coef| +// +// Output: +// - lpc_coef : LPC coefficients in Q12 +// + +// +// WebRtcSpl_LpcToReflCoef(...) +// +// Converts LPC coefficients |lpc_coef| to reflection coefficients |refl_coef|. +// This version is a 16 bit operation. +// The conversion is implemented by the step-down algorithm. +// +// Input: +// - lpc_coef : LPC coefficients in Q12, that should be converted to +// reflection coefficients +// - use_order : Number of coefficients in |lpc_coef| +// +// Output: +// - refl_coef : Reflection coefficients in Q15. +// + +// +// WebRtcSpl_AutoCorrToReflCoef(...) +// +// Calculates reflection coefficients (16 bit) from auto-correlation values +// +// Input: +// - auto_corr : Auto-correlation values +// - use_order : Number of coefficients wanted be calculated +// +// Output: +// - refl_coef : Reflection coefficients in Q15. +// + +// +// WebRtcSpl_CrossCorrelation(...) +// +// Calculates the cross-correlation between two sequences |vector1| and +// |vector2|. |vector1| is fixed and |vector2| slides as the pointer is +// increased with the amount |step_vector2| +// +// Input: +// - vector1 : First sequence (fixed throughout the correlation) +// - vector2 : Second sequence (slides |step_vector2| for each +// new correlation) +// - dim_vector : Number of samples to use in the cross-correlation +// - dim_cross_corr : Number of cross-correlations to calculate (the +// start position for |vector2| is updated for each +// new one) +// - right_shifts : Number of right bit shifts to use. This will +// become the output Q-domain. +// - step_vector2 : How many (positive or negative) steps the +// |vector2| pointer should be updated for each new +// cross-correlation value. +// +// Output: +// - cross_corr : The cross-correlation in Q(-right_shifts) +// + +// +// WebRtcSpl_GetHanningWindow(...) +// +// Creates (the first half of) a Hanning window. Size must be at least 1 and +// at most 512. +// +// Input: +// - size : Length of the requested Hanning window (1 to 512) +// +// Output: +// - window : Hanning vector in Q14. +// + +// +// WebRtcSpl_SqrtOfOneMinusXSquared(...) +// +// Calculates y[k] = sqrt(1 - x[k]^2) for each element of the input vector +// |in_vector|. Input and output values are in Q15. +// +// Inputs: +// - in_vector : Values to calculate sqrt(1 - x^2) of +// - vector_length : Length of vector |in_vector| +// +// Output: +// - out_vector : Output values in Q15 +// + +// +// WebRtcSpl_IncreaseSeed(...) +// +// Increases the seed (and returns the new value) +// +// Input: +// - seed : Seed for random calculation +// +// Output: +// - seed : Updated seed value +// +// Return value : The new seed value +// + +// +// WebRtcSpl_RandU(...) +// +// Produces a uniformly distributed value in the WebRtc_Word16 range +// +// Input: +// - seed : Seed for random calculation +// +// Output: +// - seed : Updated seed value +// +// Return value : Uniformly distributed value in the range +// [Word16_MIN...Word16_MAX] +// + +// +// WebRtcSpl_RandN(...) +// +// Produces a normal distributed value in the WebRtc_Word16 range +// +// Input: +// - seed : Seed for random calculation +// +// Output: +// - seed : Updated seed value +// +// Return value : N(0,1) value in the Q13 domain +// + +// +// WebRtcSpl_RandUArray(...) +// +// Produces a uniformly distributed vector with elements in the WebRtc_Word16 +// range +// +// Input: +// - vector_length : Samples wanted in the vector +// - seed : Seed for random calculation +// +// Output: +// - vector : Vector with the uniform values +// - seed : Updated seed value +// +// Return value : Number of samples in vector, i.e., |vector_length| +// + +// +// WebRtcSpl_Sqrt(...) +// +// Returns the square root of the input value |value|. The precision of this +// function is integer precision, i.e., sqrt(8) gives 2 as answer. +// If |value| is a negative number then 0 is returned. +// +// Algorithm: +// +// A sixth order Taylor Series expansion is used here to compute the square +// root of a number y^0.5 = (1+x)^0.5 +// where +// x = y-1 +// = 1+(x/2)-0.5*((x/2)^2+0.5*((x/2)^3-0.625*((x/2)^4+0.875*((x/2)^5) +// 0.5 <= x < 1 +// +// Input: +// - value : Value to calculate sqrt of +// +// Return value : Result of the sqrt calculation +// + +// +// WebRtcSpl_SqrtFloor(...) +// +// Returns the square root of the input value |value|. The precision of this +// function is rounding down integer precision, i.e., sqrt(8) gives 2 as answer. +// If |value| is a negative number then 0 is returned. +// +// Algorithm: +// +// An iterative 4 cylce/bit routine +// +// Input: +// - value : Value to calculate sqrt of +// +// Return value : Result of the sqrt calculation +// + +// +// WebRtcSpl_DivU32U16(...) +// +// Divides a WebRtc_UWord32 |num| by a WebRtc_UWord16 |den|. +// +// If |den|==0, (WebRtc_UWord32)0xFFFFFFFF is returned. +// +// Input: +// - num : Numerator +// - den : Denominator +// +// Return value : Result of the division (as a WebRtc_UWord32), i.e., the +// integer part of num/den. +// + +// +// WebRtcSpl_DivW32W16(...) +// +// Divides a WebRtc_Word32 |num| by a WebRtc_Word16 |den|. +// +// If |den|==0, (WebRtc_Word32)0x7FFFFFFF is returned. +// +// Input: +// - num : Numerator +// - den : Denominator +// +// Return value : Result of the division (as a WebRtc_Word32), i.e., the +// integer part of num/den. +// + +// +// WebRtcSpl_DivW32W16ResW16(...) +// +// Divides a WebRtc_Word32 |num| by a WebRtc_Word16 |den|, assuming that the +// result is less than 32768, otherwise an unpredictable result will occur. +// +// If |den|==0, (WebRtc_Word16)0x7FFF is returned. +// +// Input: +// - num : Numerator +// - den : Denominator +// +// Return value : Result of the division (as a WebRtc_Word16), i.e., the +// integer part of num/den. +// + +// +// WebRtcSpl_DivResultInQ31(...) +// +// Divides a WebRtc_Word32 |num| by a WebRtc_Word16 |den|, assuming that the +// absolute value of the denominator is larger than the numerator, otherwise +// an unpredictable result will occur. +// +// Input: +// - num : Numerator +// - den : Denominator +// +// Return value : Result of the division in Q31. +// + +// +// WebRtcSpl_DivW32HiLow(...) +// +// Divides a WebRtc_Word32 |num| by a denominator in hi, low format. The +// absolute value of the denominator has to be larger (or equal to) the +// numerator. +// +// Input: +// - num : Numerator +// - den_hi : High part of denominator +// - den_low : Low part of denominator +// +// Return value : Divided value in Q31 +// + +// +// WebRtcSpl_Energy(...) +// +// Calculates the energy of a vector +// +// Input: +// - vector : Vector which the energy should be calculated on +// - vector_length : Number of samples in vector +// +// Output: +// - scale_factor : Number of left bit shifts needed to get the physical +// energy value, i.e, to get the Q0 value +// +// Return value : Energy value in Q(-|scale_factor|) +// + +// +// WebRtcSpl_FilterAR(...) +// +// Performs a 32-bit AR filtering on a vector in Q12 +// +// Input: +// - ar_coef : AR-coefficient vector (values in Q12), +// ar_coef[0] must be 4096. +// - ar_coef_length : Number of coefficients in |ar_coef|. +// - in_vector : Vector to be filtered. +// - in_vector_length : Number of samples in |in_vector|. +// - filter_state : Current state (higher part) of the filter. +// - filter_state_length : Length (in samples) of |filter_state|. +// - filter_state_low : Current state (lower part) of the filter. +// - filter_state_low_length : Length (in samples) of |filter_state_low|. +// - out_vector_low_length : Maximum length (in samples) of +// |out_vector_low|. +// +// Output: +// - filter_state : Updated state (upper part) vector. +// - filter_state_low : Updated state (lower part) vector. +// - out_vector : Vector containing the upper part of the +// filtered values. +// - out_vector_low : Vector containing the lower part of the +// filtered values. +// +// Return value : Number of samples in the |out_vector|. +// + +// +// WebRtcSpl_FilterMAFastQ12(...) +// +// Performs a MA filtering on a vector in Q12 +// +// Input: +// - in_vector : Input samples (state in positions +// in_vector[-order] .. in_vector[-1]) +// - ma_coef : Filter coefficients (in Q12) +// - ma_coef_length : Number of B coefficients (order+1) +// - vector_length : Number of samples to be filtered +// +// Output: +// - out_vector : Filtered samples +// + + +// +// WebRtcSpl_DotProductWithScale(...) +// +// Calculates the dot product between two (WebRtc_Word16) vectors +// +// Input: +// - vector1 : Vector 1 +// - vector2 : Vector 2 +// - vector_length : Number of samples used in the dot product +// - scaling : The number of right bit shifts to apply on each term +// during calculation to avoid overflow, i.e., the +// output will be in Q(-|scaling|) +// +// Return value : The dot product in Q(-scaling) +// + +// +// WebRtcSpl_ComplexIFFT(...) +// +// Complex Inverse FFT +// +// Computes an inverse complex 2^|stages|-point FFT on the input vector, which +// is in bit-reversed order. The original content of the vector is destroyed in +// the process, since the input is overwritten by the output, normal-ordered, +// FFT vector. With X as the input complex vector, y as the output complex +// vector and with M = 2^|stages|, the following is computed: +// +// M-1 +// y(k) = sum[X(i)*[cos(2*pi*i*k/M) + j*sin(2*pi*i*k/M)]] +// i=0 +// +// The implementations are optimized for speed, not for code size. It uses the +// decimation-in-time algorithm with radix-2 butterfly technique. +// +// Input: +// - vector : In pointer to complex vector containing 2^|stages| +// real elements interleaved with 2^|stages| imaginary +// elements. +// [ReImReImReIm....] +// The elements are in Q(-scale) domain, see more on Return +// Value below. +// +// - stages : Number of FFT stages. Must be at least 3 and at most 10, +// since the table WebRtcSpl_kSinTable1024[] is 1024 +// elements long. +// +// - mode : This parameter gives the user to choose how the FFT +// should work. +// mode==0: Low-complexity and Low-accuracy mode +// mode==1: High-complexity and High-accuracy mode +// +// Output: +// - vector : Out pointer to the FFT vector (the same as input). +// +// Return Value : The scale value that tells the number of left bit shifts +// that the elements in the |vector| should be shifted with +// in order to get Q0 values, i.e. the physically correct +// values. The scale parameter is always 0 or positive, +// except if N>1024 (|stages|>10), which returns a scale +// value of -1, indicating error. +// + +// +// WebRtcSpl_ComplexFFT(...) +// +// Complex FFT +// +// Computes a complex 2^|stages|-point FFT on the input vector, which is in +// bit-reversed order. The original content of the vector is destroyed in +// the process, since the input is overwritten by the output, normal-ordered, +// FFT vector. With x as the input complex vector, Y as the output complex +// vector and with M = 2^|stages|, the following is computed: +// +// M-1 +// Y(k) = 1/M * sum[x(i)*[cos(2*pi*i*k/M) + j*sin(2*pi*i*k/M)]] +// i=0 +// +// The implementations are optimized for speed, not for code size. It uses the +// decimation-in-time algorithm with radix-2 butterfly technique. +// +// This routine prevents overflow by scaling by 2 before each FFT stage. This is +// a fixed scaling, for proper normalization - there will be log2(n) passes, so +// this results in an overall factor of 1/n, distributed to maximize arithmetic +// accuracy. +// +// Input: +// - vector : In pointer to complex vector containing 2^|stages| real +// elements interleaved with 2^|stages| imaginary elements. +// [ReImReImReIm....] +// The output is in the Q0 domain. +// +// - stages : Number of FFT stages. Must be at least 3 and at most 10, +// since the table WebRtcSpl_kSinTable1024[] is 1024 +// elements long. +// +// - mode : This parameter gives the user to choose how the FFT +// should work. +// mode==0: Low-complexity and Low-accuracy mode +// mode==1: High-complexity and High-accuracy mode +// +// Output: +// - vector : The output FFT vector is in the Q0 domain. +// +// Return value : The scale parameter is always 0, except if N>1024, +// which returns a scale value of -1, indicating error. +// + +// +// WebRtcSpl_AnalysisQMF(...) +// +// Splits a 0-2*F Hz signal into two sub bands: 0-F Hz and F-2*F Hz. The +// current version has F = 8000, therefore, a super-wideband audio signal is +// split to lower-band 0-8 kHz and upper-band 8-16 kHz. +// +// Input: +// - in_data : Wide band speech signal, 320 samples (10 ms) +// +// Input & Output: +// - filter_state1 : Filter state for first All-pass filter +// - filter_state2 : Filter state for second All-pass filter +// +// Output: +// - low_band : Lower-band signal 0-8 kHz band, 160 samples (10 ms) +// - high_band : Upper-band signal 8-16 kHz band (flipped in frequency +// domain), 160 samples (10 ms) +// + +// +// WebRtcSpl_SynthesisQMF(...) +// +// Combines the two sub bands (0-F and F-2*F Hz) into a signal of 0-2*F +// Hz, (current version has F = 8000 Hz). So the filter combines lower-band +// (0-8 kHz) and upper-band (8-16 kHz) channels to obtain super-wideband 0-16 +// kHz audio. +// +// Input: +// - low_band : The signal with the 0-8 kHz band, 160 samples (10 ms) +// - high_band : The signal with the 8-16 kHz band, 160 samples (10 ms) +// +// Input & Output: +// - filter_state1 : Filter state for first All-pass filter +// - filter_state2 : Filter state for second All-pass filter +// +// Output: +// - out_data : Super-wideband speech signal, 0-16 kHz +// + +// WebRtc_Word16 WebRtcSpl_SatW32ToW16(...) +// +// This function saturates a 32-bit word into a 16-bit word. +// +// Input: +// - value32 : The value of a 32-bit word. +// +// Output: +// - out16 : the saturated 16-bit word. +// + +// int32_t WebRtc_MulAccumW16(...) +// +// This function multiply a 16-bit word by a 16-bit word, and accumulate this +// value to a 32-bit integer. +// +// Input: +// - a : The value of the first 16-bit word. +// - b : The value of the second 16-bit word. +// - c : The value of an 32-bit integer. +// +// Return Value: The value of a * b + c. +// + +// WebRtc_Word16 WebRtcSpl_get_version(...) +// +// This function gives the version string of the Signal Processing Library. +// +// Input: +// - length_in_bytes : The size of Allocated space (in Bytes) where +// the version number is written to (in string format). +// +// Output: +// - version : Pointer to a buffer where the version number is written to. +// diff --git a/libs/miniwebrtc/audio/common/processing/spl_inl.h b/libs/miniwebrtc/audio/common/processing/spl_inl.h new file mode 100644 index 00000000..23b32099 --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/spl_inl.h @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +// This header file includes the inline functions in +// the fix point signal processing library. + +#ifndef WEBRTC_SPL_SPL_INL_H_ +#define WEBRTC_SPL_SPL_INL_H_ + +#ifdef WEBRTC_ARCH_ARM_V7A +#include "spl_inl_armv7.h" +#else + +static __inline WebRtc_Word16 WebRtcSpl_SatW32ToW16(WebRtc_Word32 value32) { + WebRtc_Word16 out16 = (WebRtc_Word16) value32; + + if (value32 > 32767) + out16 = 32767; + else if (value32 < -32768) + out16 = -32768; + + return out16; +} + +static __inline WebRtc_Word16 WebRtcSpl_AddSatW16(WebRtc_Word16 a, + WebRtc_Word16 b) { + return WebRtcSpl_SatW32ToW16((WebRtc_Word32) a + (WebRtc_Word32) b); +} + +static __inline WebRtc_Word32 WebRtcSpl_AddSatW32(WebRtc_Word32 l_var1, + WebRtc_Word32 l_var2) { + WebRtc_Word32 l_sum; + + // perform long addition + l_sum = l_var1 + l_var2; + + // check for under or overflow + if (WEBRTC_SPL_IS_NEG(l_var1)) { + if (WEBRTC_SPL_IS_NEG(l_var2) && !WEBRTC_SPL_IS_NEG(l_sum)) { + l_sum = (WebRtc_Word32)0x80000000; + } + } else { + if (!WEBRTC_SPL_IS_NEG(l_var2) && WEBRTC_SPL_IS_NEG(l_sum)) { + l_sum = (WebRtc_Word32)0x7FFFFFFF; + } + } + + return l_sum; +} + +static __inline WebRtc_Word16 WebRtcSpl_SubSatW16(WebRtc_Word16 var1, + WebRtc_Word16 var2) { + return WebRtcSpl_SatW32ToW16((WebRtc_Word32) var1 - (WebRtc_Word32) var2); +} + +static __inline WebRtc_Word32 WebRtcSpl_SubSatW32(WebRtc_Word32 l_var1, + WebRtc_Word32 l_var2) { + WebRtc_Word32 l_diff; + + // perform subtraction + l_diff = l_var1 - l_var2; + + // check for underflow + if ((l_var1 < 0) && (l_var2 > 0) && (l_diff > 0)) + l_diff = (WebRtc_Word32)0x80000000; + // check for overflow + if ((l_var1 > 0) && (l_var2 < 0) && (l_diff < 0)) + l_diff = (WebRtc_Word32)0x7FFFFFFF; + + return l_diff; +} + +static __inline WebRtc_Word16 WebRtcSpl_GetSizeInBits(WebRtc_UWord32 n) { + int bits; + + if (0xFFFF0000 & n) { + bits = 16; + } else { + bits = 0; + } + if (0x0000FF00 & (n >> bits)) bits += 8; + if (0x000000F0 & (n >> bits)) bits += 4; + if (0x0000000C & (n >> bits)) bits += 2; + if (0x00000002 & (n >> bits)) bits += 1; + if (0x00000001 & (n >> bits)) bits += 1; + + return bits; +} + +static __inline int WebRtcSpl_NormW32(WebRtc_Word32 a) { + int zeros; + + if (a <= 0) a ^= 0xFFFFFFFF; + + if (!(0xFFFF8000 & a)) { + zeros = 16; + } else { + zeros = 0; + } + if (!(0xFF800000 & (a << zeros))) zeros += 8; + if (!(0xF8000000 & (a << zeros))) zeros += 4; + if (!(0xE0000000 & (a << zeros))) zeros += 2; + if (!(0xC0000000 & (a << zeros))) zeros += 1; + + return zeros; +} + +static __inline int WebRtcSpl_NormU32(WebRtc_UWord32 a) { + int zeros; + + if (a == 0) return 0; + + if (!(0xFFFF0000 & a)) { + zeros = 16; + } else { + zeros = 0; + } + if (!(0xFF000000 & (a << zeros))) zeros += 8; + if (!(0xF0000000 & (a << zeros))) zeros += 4; + if (!(0xC0000000 & (a << zeros))) zeros += 2; + if (!(0x80000000 & (a << zeros))) zeros += 1; + + return zeros; +} + +static __inline int WebRtcSpl_NormW16(WebRtc_Word16 a) { + int zeros; + + if (a <= 0) a ^= 0xFFFF; + + if (!(0xFF80 & a)) { + zeros = 8; + } else { + zeros = 0; + } + if (!(0xF800 & (a << zeros))) zeros += 4; + if (!(0xE000 & (a << zeros))) zeros += 2; + if (!(0xC000 & (a << zeros))) zeros += 1; + + return zeros; +} + +static __inline int32_t WebRtc_MulAccumW16(int16_t a, + int16_t b, + int32_t c) { + return (a * b + c); +} + +#endif // WEBRTC_ARCH_ARM_V7A + +#endif // WEBRTC_SPL_SPL_INL_H_ diff --git a/libs/miniwebrtc/audio/common/processing/spl_inl_armv7.h b/libs/miniwebrtc/audio/common/processing/spl_inl_armv7.h new file mode 100644 index 00000000..5b19c2c1 --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/spl_inl_armv7.h @@ -0,0 +1,140 @@ +/* + * 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 header file includes the inline functions for ARM processors in +// the fix point signal processing library. + +#ifndef WEBRTC_SPL_SPL_INL_ARMV7_H_ +#define WEBRTC_SPL_SPL_INL_ARMV7_H_ + +// TODO(kma): Replace some assembly code with GCC intrinsics +// (e.g. __builtin_clz). + +static __inline WebRtc_Word32 WEBRTC_SPL_MUL_16_32_RSFT16(WebRtc_Word16 a, + WebRtc_Word32 b) { + WebRtc_Word32 tmp; + __asm__("smulwb %0, %1, %2":"=r"(tmp):"r"(b), "r"(a)); + return tmp; +} + +static __inline WebRtc_Word32 WEBRTC_SPL_MUL_32_32_RSFT32(WebRtc_Word16 a, + WebRtc_Word16 b, + WebRtc_Word32 c) { + WebRtc_Word32 tmp; + __asm__("pkhbt %0, %1, %2, lsl #16" : "=r"(tmp) : "r"(b), "r"(a)); + __asm__("smmul %0, %1, %2":"=r"(tmp):"r"(tmp), "r"(c)); + return tmp; +} + +static __inline WebRtc_Word32 WEBRTC_SPL_MUL_32_32_RSFT32BI(WebRtc_Word32 a, + WebRtc_Word32 b) { + WebRtc_Word32 tmp; + __asm__("smmul %0, %1, %2":"=r"(tmp):"r"(a), "r"(b)); + return tmp; +} + +static __inline WebRtc_Word32 WEBRTC_SPL_MUL_16_16(WebRtc_Word16 a, + WebRtc_Word16 b) { + WebRtc_Word32 tmp; + __asm__("smulbb %0, %1, %2":"=r"(tmp):"r"(a), "r"(b)); + return tmp; +} + +static __inline int32_t WebRtc_MulAccumW16(int16_t a, + int16_t b, + int32_t c) { + int32_t tmp = 0; + __asm__("smlabb %0, %1, %2, %3":"=r"(tmp):"r"(a), "r"(b), "r"(c)); + return tmp; +} + +static __inline WebRtc_Word16 WebRtcSpl_AddSatW16(WebRtc_Word16 a, + WebRtc_Word16 b) { + WebRtc_Word32 s_sum; + + __asm__("qadd16 %0, %1, %2":"=r"(s_sum):"r"(a), "r"(b)); + + return (WebRtc_Word16) s_sum; +} + +static __inline WebRtc_Word32 WebRtcSpl_AddSatW32(WebRtc_Word32 l_var1, + WebRtc_Word32 l_var2) { + WebRtc_Word32 l_sum; + + __asm__("qadd %0, %1, %2":"=r"(l_sum):"r"(l_var1), "r"(l_var2)); + + return l_sum; +} + +static __inline WebRtc_Word16 WebRtcSpl_SubSatW16(WebRtc_Word16 var1, + WebRtc_Word16 var2) { + WebRtc_Word32 s_sub; + + __asm__("qsub16 %0, %1, %2":"=r"(s_sub):"r"(var1), "r"(var2)); + + return (WebRtc_Word16)s_sub; +} + +static __inline WebRtc_Word32 WebRtcSpl_SubSatW32(WebRtc_Word32 l_var1, + WebRtc_Word32 l_var2) { + WebRtc_Word32 l_sub; + + __asm__("qsub %0, %1, %2":"=r"(l_sub):"r"(l_var1), "r"(l_var2)); + + return l_sub; +} + +static __inline WebRtc_Word16 WebRtcSpl_GetSizeInBits(WebRtc_UWord32 n) { + WebRtc_Word32 tmp; + + __asm__("clz %0, %1":"=r"(tmp):"r"(n)); + + return (WebRtc_Word16)(32 - tmp); +} + +static __inline int WebRtcSpl_NormW32(WebRtc_Word32 a) { + WebRtc_Word32 tmp; + + if (a <= 0) a ^= 0xFFFFFFFF; + + __asm__("clz %0, %1":"=r"(tmp):"r"(a)); + + return tmp - 1; +} + +static __inline int WebRtcSpl_NormU32(WebRtc_UWord32 a) { + int tmp; + + if (a == 0) return 0; + + __asm__("clz %0, %1":"=r"(tmp):"r"(a)); + + return tmp; +} + +static __inline int WebRtcSpl_NormW16(WebRtc_Word16 a) { + WebRtc_Word32 tmp; + + if (a <= 0) a ^= 0xFFFFFFFF; + + __asm__("clz %0, %1":"=r"(tmp):"r"(a)); + + return tmp - 17; +} + +static __inline WebRtc_Word16 WebRtcSpl_SatW32ToW16(WebRtc_Word32 value32) { + WebRtc_Word16 out16; + + __asm__("ssat %r0, #16, %r1" : "=r"(out16) : "r"(value32)); + + return out16; +} +#endif // WEBRTC_SPL_SPL_INL_ARMV7_H_ diff --git a/libs/miniwebrtc/audio/common/processing/spl_sqrt.c b/libs/miniwebrtc/audio/common/processing/spl_sqrt.c new file mode 100644 index 00000000..cfe2cd3f --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/spl_sqrt.c @@ -0,0 +1,184 @@ +/* + * 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 contains the function WebRtcSpl_Sqrt(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "signal_processing_library.h" + +WebRtc_Word32 WebRtcSpl_SqrtLocal(WebRtc_Word32 in); + +WebRtc_Word32 WebRtcSpl_SqrtLocal(WebRtc_Word32 in) +{ + + WebRtc_Word16 x_half, t16; + WebRtc_Word32 A, B, x2; + + /* The following block performs: + y=in/2 + x=y-2^30 + x_half=x/2^31 + t = 1 + (x_half) - 0.5*((x_half)^2) + 0.5*((x_half)^3) - 0.625*((x_half)^4) + + 0.875*((x_half)^5) + */ + + B = in; + + B = WEBRTC_SPL_RSHIFT_W32(B, 1); // B = in/2 + B = B - ((WebRtc_Word32)0x40000000); // B = in/2 - 1/2 + x_half = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(B, 16);// x_half = x/2 = (in-1)/2 + B = B + ((WebRtc_Word32)0x40000000); // B = 1 + x/2 + B = B + ((WebRtc_Word32)0x40000000); // Add 0.5 twice (since 1.0 does not exist in Q31) + + x2 = ((WebRtc_Word32)x_half) * ((WebRtc_Word32)x_half) * 2; // A = (x/2)^2 + A = -x2; // A = -(x/2)^2 + B = B + (A >> 1); // B = 1 + x/2 - 0.5*(x/2)^2 + + A = WEBRTC_SPL_RSHIFT_W32(A, 16); + A = A * A * 2; // A = (x/2)^4 + t16 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(A, 16); + B = B + WEBRTC_SPL_MUL_16_16(-20480, t16) * 2; // B = B - 0.625*A + // After this, B = 1 + x/2 - 0.5*(x/2)^2 - 0.625*(x/2)^4 + + t16 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(A, 16); + A = WEBRTC_SPL_MUL_16_16(x_half, t16) * 2; // A = (x/2)^5 + t16 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(A, 16); + B = B + WEBRTC_SPL_MUL_16_16(28672, t16) * 2; // B = B + 0.875*A + // After this, B = 1 + x/2 - 0.5*(x/2)^2 - 0.625*(x/2)^4 + 0.875*(x/2)^5 + + t16 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(x2, 16); + A = WEBRTC_SPL_MUL_16_16(x_half, t16) * 2; // A = x/2^3 + + B = B + (A >> 1); // B = B + 0.5*A + // After this, B = 1 + x/2 - 0.5*(x/2)^2 + 0.5*(x/2)^3 - 0.625*(x/2)^4 + 0.875*(x/2)^5 + + B = B + ((WebRtc_Word32)32768); // Round off bit + + return B; +} + +WebRtc_Word32 WebRtcSpl_Sqrt(WebRtc_Word32 value) +{ + /* + Algorithm: + + Six term Taylor Series is used here to compute the square root of a number + y^0.5 = (1+x)^0.5 where x = y-1 + = 1+(x/2)-0.5*((x/2)^2+0.5*((x/2)^3-0.625*((x/2)^4+0.875*((x/2)^5) + 0.5 <= x < 1 + + Example of how the algorithm works, with ut=sqrt(in), and + with in=73632 and ut=271 (even shift value case): + + in=73632 + y= in/131072 + x=y-1 + t = 1 + (x/2) - 0.5*((x/2)^2) + 0.5*((x/2)^3) - 0.625*((x/2)^4) + 0.875*((x/2)^5) + ut=t*(1/sqrt(2))*512 + + or: + + in=73632 + in2=73632*2^14 + y= in2/2^31 + x=y-1 + t = 1 + (x/2) - 0.5*((x/2)^2) + 0.5*((x/2)^3) - 0.625*((x/2)^4) + 0.875*((x/2)^5) + ut=t*(1/sqrt(2)) + ut2=ut*2^9 + + which gives: + + in = 73632 + in2 = 1206386688 + y = 0.56176757812500 + x = -0.43823242187500 + t = 0.74973506527313 + ut = 0.53014274874797 + ut2 = 2.714330873589594e+002 + + or: + + in=73632 + in2=73632*2^14 + y=in2/2 + x=y-2^30 + x_half=x/2^31 + t = 1 + (x_half) - 0.5*((x_half)^2) + 0.5*((x_half)^3) - 0.625*((x_half)^4) + + 0.875*((x_half)^5) + ut=t*(1/sqrt(2)) + ut2=ut*2^9 + + which gives: + + in = 73632 + in2 = 1206386688 + y = 603193344 + x = -470548480 + x_half = -0.21911621093750 + t = 0.74973506527313 + ut = 0.53014274874797 + ut2 = 2.714330873589594e+002 + + */ + + WebRtc_Word16 x_norm, nshift, t16, sh; + WebRtc_Word32 A; + + WebRtc_Word16 k_sqrt_2 = 23170; // 1/sqrt2 (==5a82) + + A = value; + + if (A == 0) + return (WebRtc_Word32)0; // sqrt(0) = 0 + + sh = WebRtcSpl_NormW32(A); // # shifts to normalize A + A = WEBRTC_SPL_LSHIFT_W32(A, sh); // Normalize A + if (A < (WEBRTC_SPL_WORD32_MAX - 32767)) + { + A = A + ((WebRtc_Word32)32768); // Round off bit + } else + { + A = WEBRTC_SPL_WORD32_MAX; + } + + x_norm = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(A, 16); // x_norm = AH + + nshift = WEBRTC_SPL_RSHIFT_W16(sh, 1); // nshift = sh>>1 + nshift = -nshift; // Negate the power for later de-normalization + + A = (WebRtc_Word32)WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)x_norm, 16); + A = WEBRTC_SPL_ABS_W32(A); // A = abs(x_norm<<16) + A = WebRtcSpl_SqrtLocal(A); // A = sqrt(A) + + if ((-2 * nshift) == sh) + { // Even shift value case + + t16 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(A, 16); // t16 = AH + + A = WEBRTC_SPL_MUL_16_16(k_sqrt_2, t16) * 2; // A = 1/sqrt(2)*t16 + A = A + ((WebRtc_Word32)32768); // Round off + A = A & ((WebRtc_Word32)0x7fff0000); // Round off + + A = WEBRTC_SPL_RSHIFT_W32(A, 15); // A = A>>16 + + } else + { + A = WEBRTC_SPL_RSHIFT_W32(A, 16); // A = A>>16 + } + + A = A & ((WebRtc_Word32)0x0000ffff); + A = (WebRtc_Word32)WEBRTC_SPL_SHIFT_W32(A, nshift); // De-normalize the result + + return A; +} diff --git a/libs/miniwebrtc/audio/common/processing/spl_sqrt_floor.c b/libs/miniwebrtc/audio/common/processing/spl_sqrt_floor.c new file mode 100644 index 00000000..f0e8ae28 --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/spl_sqrt_floor.c @@ -0,0 +1,54 @@ +/* + * Written by Wilco Dijkstra, 1996. Refer to file LICENSE under + * trunk/third_party_mods/sqrt_floor. + * + * Minor modifications in code style for WebRTC, 2012. + */ + +#include "signal_processing_library.h" + +/* + * Algorithm: + * Successive approximation of the equation (root + delta) ^ 2 = N + * until delta < 1. If delta < 1 we have the integer part of SQRT (N). + * Use delta = 2^i for i = 15 .. 0. + * + * Output precision is 16 bits. Note for large input values (close to + * 0x7FFFFFFF), bit 15 (the highest bit of the low 16-bit half word) + * contains the MSB information (a non-sign value). Do with caution + * if you need to cast the output to int16_t type. + * + * If the input value is negative, it returns 0. + */ + +#define WEBRTC_SPL_SQRT_ITER(N) \ + try1 = root + (1 << (N)); \ + if (value >= try1 << (N)) \ + { \ + value -= try1 << (N); \ + root |= 2 << (N); \ + } + +int32_t WebRtcSpl_SqrtFloor(int32_t value) +{ + int32_t root = 0, try1; + + WEBRTC_SPL_SQRT_ITER (15); + WEBRTC_SPL_SQRT_ITER (14); + WEBRTC_SPL_SQRT_ITER (13); + WEBRTC_SPL_SQRT_ITER (12); + WEBRTC_SPL_SQRT_ITER (11); + WEBRTC_SPL_SQRT_ITER (10); + WEBRTC_SPL_SQRT_ITER ( 9); + WEBRTC_SPL_SQRT_ITER ( 8); + WEBRTC_SPL_SQRT_ITER ( 7); + WEBRTC_SPL_SQRT_ITER ( 6); + WEBRTC_SPL_SQRT_ITER ( 5); + WEBRTC_SPL_SQRT_ITER ( 4); + WEBRTC_SPL_SQRT_ITER ( 3); + WEBRTC_SPL_SQRT_ITER ( 2); + WEBRTC_SPL_SQRT_ITER ( 1); + WEBRTC_SPL_SQRT_ITER ( 0); + + return root >> 1; +} diff --git a/libs/miniwebrtc/audio/common/processing/spl_version.c b/libs/miniwebrtc/audio/common/processing/spl_version.c new file mode 100644 index 00000000..936925ea --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/spl_version.c @@ -0,0 +1,25 @@ +/* + * 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 contains the function WebRtcSpl_get_version(). + * The description header can be found in signal_processing_library.h + * + */ + +#include +#include "signal_processing_library.h" + +WebRtc_Word16 WebRtcSpl_get_version(char* version, WebRtc_Word16 length_in_bytes) +{ + strncpy(version, "1.2.0", length_in_bytes); + return 0; +} diff --git a/libs/miniwebrtc/audio/common/processing/splitting_filter.c b/libs/miniwebrtc/audio/common/processing/splitting_filter.c new file mode 100644 index 00000000..f1acf675 --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/splitting_filter.c @@ -0,0 +1,198 @@ +/* + * 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 contains the splitting filter functions. + * + */ + +#include "signal_processing_library.h" + +// Number of samples in a low/high-band frame. +enum +{ + kBandFrameLength = 160 +}; + +// QMF filter coefficients in Q16. +static const WebRtc_UWord16 WebRtcSpl_kAllPassFilter1[3] = {6418, 36982, 57261}; +static const WebRtc_UWord16 WebRtcSpl_kAllPassFilter2[3] = {21333, 49062, 63010}; + +/////////////////////////////////////////////////////////////////////////////////////////////// +// WebRtcSpl_AllPassQMF(...) +// +// Allpass filter used by the analysis and synthesis parts of the QMF filter. +// +// Input: +// - in_data : Input data sequence (Q10) +// - data_length : Length of data sequence (>2) +// - filter_coefficients : Filter coefficients (length 3, Q16) +// +// Input & Output: +// - filter_state : Filter state (length 6, Q10). +// +// Output: +// - out_data : Output data sequence (Q10), length equal to +// |data_length| +// + +void WebRtcSpl_AllPassQMF(WebRtc_Word32* in_data, const WebRtc_Word16 data_length, + WebRtc_Word32* out_data, const WebRtc_UWord16* filter_coefficients, + WebRtc_Word32* filter_state) +{ + // The procedure is to filter the input with three first order all pass filters + // (cascade operations). + // + // a_3 + q^-1 a_2 + q^-1 a_1 + q^-1 + // y[n] = ----------- ----------- ----------- x[n] + // 1 + a_3q^-1 1 + a_2q^-1 1 + a_1q^-1 + // + // The input vector |filter_coefficients| includes these three filter coefficients. + // The filter state contains the in_data state, in_data[-1], followed by + // the out_data state, out_data[-1]. This is repeated for each cascade. + // The first cascade filter will filter the |in_data| and store the output in + // |out_data|. The second will the take the |out_data| as input and make an + // intermediate storage in |in_data|, to save memory. The third, and final, cascade + // filter operation takes the |in_data| (which is the output from the previous cascade + // filter) and store the output in |out_data|. + // Note that the input vector values are changed during the process. + WebRtc_Word16 k; + WebRtc_Word32 diff; + // First all-pass cascade; filter from in_data to out_data. + + // Let y_i[n] indicate the output of cascade filter i (with filter coefficient a_i) at + // vector position n. Then the final output will be y[n] = y_3[n] + + // First loop, use the states stored in memory. + // "diff" should be safe from wrap around since max values are 2^25 + diff = WEBRTC_SPL_SUB_SAT_W32(in_data[0], filter_state[1]); // = (x[0] - y_1[-1]) + // y_1[0] = x[-1] + a_1 * (x[0] - y_1[-1]) + out_data[0] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[0], diff, filter_state[0]); + + // For the remaining loops, use previous values. + for (k = 1; k < data_length; k++) + { + diff = WEBRTC_SPL_SUB_SAT_W32(in_data[k], out_data[k - 1]); // = (x[n] - y_1[n-1]) + // y_1[n] = x[n-1] + a_1 * (x[n] - y_1[n-1]) + out_data[k] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[0], diff, in_data[k - 1]); + } + + // Update states. + filter_state[0] = in_data[data_length - 1]; // x[N-1], becomes x[-1] next time + filter_state[1] = out_data[data_length - 1]; // y_1[N-1], becomes y_1[-1] next time + + // Second all-pass cascade; filter from out_data to in_data. + diff = WEBRTC_SPL_SUB_SAT_W32(out_data[0], filter_state[3]); // = (y_1[0] - y_2[-1]) + // y_2[0] = y_1[-1] + a_2 * (y_1[0] - y_2[-1]) + in_data[0] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[1], diff, filter_state[2]); + for (k = 1; k < data_length; k++) + { + diff = WEBRTC_SPL_SUB_SAT_W32(out_data[k], in_data[k - 1]); // =(y_1[n] - y_2[n-1]) + // y_2[0] = y_1[-1] + a_2 * (y_1[0] - y_2[-1]) + in_data[k] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[1], diff, out_data[k-1]); + } + + filter_state[2] = out_data[data_length - 1]; // y_1[N-1], becomes y_1[-1] next time + filter_state[3] = in_data[data_length - 1]; // y_2[N-1], becomes y_2[-1] next time + + // Third all-pass cascade; filter from in_data to out_data. + diff = WEBRTC_SPL_SUB_SAT_W32(in_data[0], filter_state[5]); // = (y_2[0] - y[-1]) + // y[0] = y_2[-1] + a_3 * (y_2[0] - y[-1]) + out_data[0] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[2], diff, filter_state[4]); + for (k = 1; k < data_length; k++) + { + diff = WEBRTC_SPL_SUB_SAT_W32(in_data[k], out_data[k - 1]); // = (y_2[n] - y[n-1]) + // y[n] = y_2[n-1] + a_3 * (y_2[n] - y[n-1]) + out_data[k] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[2], diff, in_data[k-1]); + } + filter_state[4] = in_data[data_length - 1]; // y_2[N-1], becomes y_2[-1] next time + filter_state[5] = out_data[data_length - 1]; // y[N-1], becomes y[-1] next time +} + +void WebRtcSpl_AnalysisQMF(const WebRtc_Word16* in_data, WebRtc_Word16* low_band, + WebRtc_Word16* high_band, WebRtc_Word32* filter_state1, + WebRtc_Word32* filter_state2) +{ + WebRtc_Word16 i; + WebRtc_Word16 k; + WebRtc_Word32 tmp; + WebRtc_Word32 half_in1[kBandFrameLength]; + WebRtc_Word32 half_in2[kBandFrameLength]; + WebRtc_Word32 filter1[kBandFrameLength]; + WebRtc_Word32 filter2[kBandFrameLength]; + + // Split even and odd samples. Also shift them to Q10. + for (i = 0, k = 0; i < kBandFrameLength; i++, k += 2) + { + half_in2[i] = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)in_data[k], 10); + half_in1[i] = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)in_data[k + 1], 10); + } + + // All pass filter even and odd samples, independently. + WebRtcSpl_AllPassQMF(half_in1, kBandFrameLength, filter1, WebRtcSpl_kAllPassFilter1, + filter_state1); + WebRtcSpl_AllPassQMF(half_in2, kBandFrameLength, filter2, WebRtcSpl_kAllPassFilter2, + filter_state2); + + // Take the sum and difference of filtered version of odd and even + // branches to get upper & lower band. + for (i = 0; i < kBandFrameLength; i++) + { + tmp = filter1[i] + filter2[i] + 1024; + tmp = WEBRTC_SPL_RSHIFT_W32(tmp, 11); + low_band[i] = WebRtcSpl_SatW32ToW16(tmp); + + tmp = filter1[i] - filter2[i] + 1024; + tmp = WEBRTC_SPL_RSHIFT_W32(tmp, 11); + high_band[i] = WebRtcSpl_SatW32ToW16(tmp); + } +} + +void WebRtcSpl_SynthesisQMF(const WebRtc_Word16* low_band, const WebRtc_Word16* high_band, + WebRtc_Word16* out_data, WebRtc_Word32* filter_state1, + WebRtc_Word32* filter_state2) +{ + WebRtc_Word32 tmp; + WebRtc_Word32 half_in1[kBandFrameLength]; + WebRtc_Word32 half_in2[kBandFrameLength]; + WebRtc_Word32 filter1[kBandFrameLength]; + WebRtc_Word32 filter2[kBandFrameLength]; + WebRtc_Word16 i; + WebRtc_Word16 k; + + // Obtain the sum and difference channels out of upper and lower-band channels. + // Also shift to Q10 domain. + for (i = 0; i < kBandFrameLength; i++) + { + tmp = (WebRtc_Word32)low_band[i] + (WebRtc_Word32)high_band[i]; + half_in1[i] = WEBRTC_SPL_LSHIFT_W32(tmp, 10); + tmp = (WebRtc_Word32)low_band[i] - (WebRtc_Word32)high_band[i]; + half_in2[i] = WEBRTC_SPL_LSHIFT_W32(tmp, 10); + } + + // all-pass filter the sum and difference channels + WebRtcSpl_AllPassQMF(half_in1, kBandFrameLength, filter1, WebRtcSpl_kAllPassFilter2, + filter_state1); + WebRtcSpl_AllPassQMF(half_in2, kBandFrameLength, filter2, WebRtcSpl_kAllPassFilter1, + filter_state2); + + // The filtered signals are even and odd samples of the output. Combine + // them. The signals are Q10 should shift them back to Q0 and take care of + // saturation. + for (i = 0, k = 0; i < kBandFrameLength; i++) + { + tmp = WEBRTC_SPL_RSHIFT_W32(filter2[i] + 512, 10); + out_data[k++] = WebRtcSpl_SatW32ToW16(tmp); + + tmp = WEBRTC_SPL_RSHIFT_W32(filter1[i] + 512, 10); + out_data[k++] = WebRtcSpl_SatW32ToW16(tmp); + } + +} diff --git a/libs/miniwebrtc/audio/common/processing/sqrt_of_one_minus_x_squared.c b/libs/miniwebrtc/audio/common/processing/sqrt_of_one_minus_x_squared.c new file mode 100644 index 00000000..9fb2c73b --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/sqrt_of_one_minus_x_squared.c @@ -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. + */ + + +/* + * This file contains the function WebRtcSpl_SqrtOfOneMinusXSquared(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "signal_processing_library.h" + +void WebRtcSpl_SqrtOfOneMinusXSquared(WebRtc_Word16 *xQ15, int vector_length, + WebRtc_Word16 *yQ15) +{ + WebRtc_Word32 sq; + int m; + WebRtc_Word16 tmp; + + for (m = 0; m < vector_length; m++) + { + tmp = xQ15[m]; + sq = WEBRTC_SPL_MUL_16_16(tmp, tmp); // x^2 in Q30 + sq = 1073741823 - sq; // 1-x^2, where 1 ~= 0.99999999906 is 1073741823 in Q30 + sq = WebRtcSpl_Sqrt(sq); // sqrt(1-x^2) in Q15 + yQ15[m] = (WebRtc_Word16)sq; + } +} diff --git a/libs/miniwebrtc/audio/common/processing/vector_scaling_operations.c b/libs/miniwebrtc/audio/common/processing/vector_scaling_operations.c new file mode 100644 index 00000000..20d239ca --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/vector_scaling_operations.c @@ -0,0 +1,151 @@ +/* + * 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 contains implementations of the functions + * WebRtcSpl_VectorBitShiftW16() + * WebRtcSpl_VectorBitShiftW32() + * WebRtcSpl_VectorBitShiftW32ToW16() + * WebRtcSpl_ScaleVector() + * WebRtcSpl_ScaleVectorWithSat() + * WebRtcSpl_ScaleAndAddVectors() + * + * The description header can be found in signal_processing_library.h + * + */ + +#include "signal_processing_library.h" + +void WebRtcSpl_VectorBitShiftW16(WebRtc_Word16 *res, + WebRtc_Word16 length, + G_CONST WebRtc_Word16 *in, + WebRtc_Word16 right_shifts) +{ + int i; + + if (right_shifts > 0) + { + for (i = length; i > 0; i--) + { + (*res++) = ((*in++) >> right_shifts); + } + } else + { + for (i = length; i > 0; i--) + { + (*res++) = ((*in++) << (-right_shifts)); + } + } +} + +void WebRtcSpl_VectorBitShiftW32(WebRtc_Word32 *out_vector, + WebRtc_Word16 vector_length, + G_CONST WebRtc_Word32 *in_vector, + WebRtc_Word16 right_shifts) +{ + int i; + + if (right_shifts > 0) + { + for (i = vector_length; i > 0; i--) + { + (*out_vector++) = ((*in_vector++) >> right_shifts); + } + } else + { + for (i = vector_length; i > 0; i--) + { + (*out_vector++) = ((*in_vector++) << (-right_shifts)); + } + } +} + +void WebRtcSpl_VectorBitShiftW32ToW16(WebRtc_Word16 *res, + WebRtc_Word16 length, + G_CONST WebRtc_Word32 *in, + WebRtc_Word16 right_shifts) +{ + int i; + + if (right_shifts >= 0) + { + for (i = length; i > 0; i--) + { + (*res++) = (WebRtc_Word16)((*in++) >> right_shifts); + } + } else + { + WebRtc_Word16 left_shifts = -right_shifts; + for (i = length; i > 0; i--) + { + (*res++) = (WebRtc_Word16)((*in++) << left_shifts); + } + } +} + +void WebRtcSpl_ScaleVector(G_CONST WebRtc_Word16 *in_vector, WebRtc_Word16 *out_vector, + WebRtc_Word16 gain, WebRtc_Word16 in_vector_length, + WebRtc_Word16 right_shifts) +{ + // Performs vector operation: out_vector = (gain*in_vector)>>right_shifts + int i; + G_CONST WebRtc_Word16 *inptr; + WebRtc_Word16 *outptr; + + inptr = in_vector; + outptr = out_vector; + + for (i = 0; i < in_vector_length; i++) + { + (*outptr++) = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(*inptr++, gain, right_shifts); + } +} + +void WebRtcSpl_ScaleVectorWithSat(G_CONST WebRtc_Word16 *in_vector, WebRtc_Word16 *out_vector, + WebRtc_Word16 gain, WebRtc_Word16 in_vector_length, + WebRtc_Word16 right_shifts) +{ + // Performs vector operation: out_vector = (gain*in_vector)>>right_shifts + int i; + WebRtc_Word32 tmpW32; + G_CONST WebRtc_Word16 *inptr; + WebRtc_Word16 *outptr; + + inptr = in_vector; + outptr = out_vector; + + for (i = 0; i < in_vector_length; i++) + { + tmpW32 = WEBRTC_SPL_MUL_16_16_RSFT(*inptr++, gain, right_shifts); + (*outptr++) = WebRtcSpl_SatW32ToW16(tmpW32); + } +} + +void WebRtcSpl_ScaleAndAddVectors(G_CONST WebRtc_Word16 *in1, WebRtc_Word16 gain1, int shift1, + G_CONST WebRtc_Word16 *in2, WebRtc_Word16 gain2, int shift2, + WebRtc_Word16 *out, int vector_length) +{ + // Performs vector operation: out = (gain1*in1)>>shift1 + (gain2*in2)>>shift2 + int i; + G_CONST WebRtc_Word16 *in1ptr; + G_CONST WebRtc_Word16 *in2ptr; + WebRtc_Word16 *outptr; + + in1ptr = in1; + in2ptr = in2; + outptr = out; + + for (i = 0; i < vector_length; i++) + { + (*outptr++) = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(gain1, *in1ptr++, shift1) + + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(gain2, *in2ptr++, shift2); + } +} diff --git a/libs/miniwebrtc/audio/common/processing/webrtc_fft_t_1024_8.c b/libs/miniwebrtc/audio/common/processing/webrtc_fft_t_1024_8.c new file mode 100644 index 00000000..b5873805 --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/webrtc_fft_t_1024_8.c @@ -0,0 +1,704 @@ +/* + * 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 contains the Q14 radix-8 tables used in ARM9e optimizations. + * + */ + +extern const int s_Q14S_8; +const int s_Q14S_8 = 1024; +extern const unsigned short t_Q14S_8[2032]; +const unsigned short t_Q14S_8[2032] = { + 0x4000,0x0000 ,0x4000,0x0000 ,0x4000,0x0000 , + 0x22a3,0x187e ,0x3249,0x0c7c ,0x11a8,0x238e , + 0x0000,0x2d41 ,0x22a3,0x187e ,0xdd5d,0x3b21 , + 0xdd5d,0x3b21 ,0x11a8,0x238e ,0xb4be,0x3ec5 , + 0xc000,0x4000 ,0x0000,0x2d41 ,0xa57e,0x2d41 , + 0xac61,0x3b21 ,0xee58,0x3537 ,0xb4be,0x0c7c , + 0xa57e,0x2d41 ,0xdd5d,0x3b21 ,0xdd5d,0xe782 , + 0xac61,0x187e ,0xcdb7,0x3ec5 ,0x11a8,0xcac9 , + 0x4000,0x0000 ,0x4000,0x0000 ,0x4000,0x0000 , + 0x396b,0x0646 ,0x3cc8,0x0324 ,0x35eb,0x0964 , + 0x3249,0x0c7c ,0x396b,0x0646 ,0x2aaa,0x1294 , + 0x2aaa,0x1294 ,0x35eb,0x0964 ,0x1e7e,0x1b5d , + 0x22a3,0x187e ,0x3249,0x0c7c ,0x11a8,0x238e , + 0x1a46,0x1e2b ,0x2e88,0x0f8d ,0x0471,0x2afb , + 0x11a8,0x238e ,0x2aaa,0x1294 ,0xf721,0x3179 , + 0x08df,0x289a ,0x26b3,0x1590 ,0xea02,0x36e5 , + 0x0000,0x2d41 ,0x22a3,0x187e ,0xdd5d,0x3b21 , + 0xf721,0x3179 ,0x1e7e,0x1b5d ,0xd178,0x3e15 , + 0xee58,0x3537 ,0x1a46,0x1e2b ,0xc695,0x3fb1 , + 0xe5ba,0x3871 ,0x15fe,0x20e7 ,0xbcf0,0x3fec , + 0xdd5d,0x3b21 ,0x11a8,0x238e ,0xb4be,0x3ec5 , + 0xd556,0x3d3f ,0x0d48,0x2620 ,0xae2e,0x3c42 , + 0xcdb7,0x3ec5 ,0x08df,0x289a ,0xa963,0x3871 , + 0xc695,0x3fb1 ,0x0471,0x2afb ,0xa678,0x3368 , + 0xc000,0x4000 ,0x0000,0x2d41 ,0xa57e,0x2d41 , + 0xba09,0x3fb1 ,0xfb8f,0x2f6c ,0xa678,0x2620 , + 0xb4be,0x3ec5 ,0xf721,0x3179 ,0xa963,0x1e2b , + 0xb02d,0x3d3f ,0xf2b8,0x3368 ,0xae2e,0x1590 , + 0xac61,0x3b21 ,0xee58,0x3537 ,0xb4be,0x0c7c , + 0xa963,0x3871 ,0xea02,0x36e5 ,0xbcf0,0x0324 , + 0xa73b,0x3537 ,0xe5ba,0x3871 ,0xc695,0xf9ba , + 0xa5ed,0x3179 ,0xe182,0x39db ,0xd178,0xf073 , + 0xa57e,0x2d41 ,0xdd5d,0x3b21 ,0xdd5d,0xe782 , + 0xa5ed,0x289a ,0xd94d,0x3c42 ,0xea02,0xdf19 , + 0xa73b,0x238e ,0xd556,0x3d3f ,0xf721,0xd766 , + 0xa963,0x1e2b ,0xd178,0x3e15 ,0x0471,0xd094 , + 0xac61,0x187e ,0xcdb7,0x3ec5 ,0x11a8,0xcac9 , + 0xb02d,0x1294 ,0xca15,0x3f4f ,0x1e7e,0xc625 , + 0xb4be,0x0c7c ,0xc695,0x3fb1 ,0x2aaa,0xc2c1 , + 0xba09,0x0646 ,0xc338,0x3fec ,0x35eb,0xc0b1 , + 0x4000,0x0000 ,0x4000,0x0000 ,0x4000,0x0000 , + 0x3e69,0x0192 ,0x3f36,0x00c9 ,0x3d9a,0x025b , + 0x3cc8,0x0324 ,0x3e69,0x0192 ,0x3b1e,0x04b5 , + 0x3b1e,0x04b5 ,0x3d9a,0x025b ,0x388e,0x070e , + 0x396b,0x0646 ,0x3cc8,0x0324 ,0x35eb,0x0964 , + 0x37af,0x07d6 ,0x3bf4,0x03ed ,0x3334,0x0bb7 , + 0x35eb,0x0964 ,0x3b1e,0x04b5 ,0x306c,0x0e06 , + 0x341e,0x0af1 ,0x3a46,0x057e ,0x2d93,0x1050 , + 0x3249,0x0c7c ,0x396b,0x0646 ,0x2aaa,0x1294 , + 0x306c,0x0e06 ,0x388e,0x070e ,0x27b3,0x14d2 , + 0x2e88,0x0f8d ,0x37af,0x07d6 ,0x24ae,0x1709 , + 0x2c9d,0x1112 ,0x36ce,0x089d ,0x219c,0x1937 , + 0x2aaa,0x1294 ,0x35eb,0x0964 ,0x1e7e,0x1b5d , + 0x28b2,0x1413 ,0x3505,0x0a2b ,0x1b56,0x1d79 , + 0x26b3,0x1590 ,0x341e,0x0af1 ,0x1824,0x1f8c , + 0x24ae,0x1709 ,0x3334,0x0bb7 ,0x14ea,0x2193 , + 0x22a3,0x187e ,0x3249,0x0c7c ,0x11a8,0x238e , + 0x2093,0x19ef ,0x315b,0x0d41 ,0x0e61,0x257e , + 0x1e7e,0x1b5d ,0x306c,0x0e06 ,0x0b14,0x2760 , + 0x1c64,0x1cc6 ,0x2f7b,0x0eca ,0x07c4,0x2935 , + 0x1a46,0x1e2b ,0x2e88,0x0f8d ,0x0471,0x2afb , + 0x1824,0x1f8c ,0x2d93,0x1050 ,0x011c,0x2cb2 , + 0x15fe,0x20e7 ,0x2c9d,0x1112 ,0xfdc7,0x2e5a , + 0x13d5,0x223d ,0x2ba4,0x11d3 ,0xfa73,0x2ff2 , + 0x11a8,0x238e ,0x2aaa,0x1294 ,0xf721,0x3179 , + 0x0f79,0x24da ,0x29af,0x1354 ,0xf3d2,0x32ef , + 0x0d48,0x2620 ,0x28b2,0x1413 ,0xf087,0x3453 , + 0x0b14,0x2760 ,0x27b3,0x14d2 ,0xed41,0x35a5 , + 0x08df,0x289a ,0x26b3,0x1590 ,0xea02,0x36e5 , + 0x06a9,0x29ce ,0x25b1,0x164c ,0xe6cb,0x3812 , + 0x0471,0x2afb ,0x24ae,0x1709 ,0xe39c,0x392b , + 0x0239,0x2c21 ,0x23a9,0x17c4 ,0xe077,0x3a30 , + 0x0000,0x2d41 ,0x22a3,0x187e ,0xdd5d,0x3b21 , + 0xfdc7,0x2e5a ,0x219c,0x1937 ,0xda4f,0x3bfd , + 0xfb8f,0x2f6c ,0x2093,0x19ef ,0xd74e,0x3cc5 , + 0xf957,0x3076 ,0x1f89,0x1aa7 ,0xd45c,0x3d78 , + 0xf721,0x3179 ,0x1e7e,0x1b5d ,0xd178,0x3e15 , + 0xf4ec,0x3274 ,0x1d72,0x1c12 ,0xcea5,0x3e9d , + 0xf2b8,0x3368 ,0x1c64,0x1cc6 ,0xcbe2,0x3f0f , + 0xf087,0x3453 ,0x1b56,0x1d79 ,0xc932,0x3f6b , + 0xee58,0x3537 ,0x1a46,0x1e2b ,0xc695,0x3fb1 , + 0xec2b,0x3612 ,0x1935,0x1edc ,0xc40c,0x3fe1 , + 0xea02,0x36e5 ,0x1824,0x1f8c ,0xc197,0x3ffb , + 0xe7dc,0x37b0 ,0x1711,0x203a ,0xbf38,0x3fff , + 0xe5ba,0x3871 ,0x15fe,0x20e7 ,0xbcf0,0x3fec , + 0xe39c,0x392b ,0x14ea,0x2193 ,0xbabf,0x3fc4 , + 0xe182,0x39db ,0x13d5,0x223d ,0xb8a6,0x3f85 , + 0xdf6d,0x3a82 ,0x12bf,0x22e7 ,0xb6a5,0x3f30 , + 0xdd5d,0x3b21 ,0x11a8,0x238e ,0xb4be,0x3ec5 , + 0xdb52,0x3bb6 ,0x1091,0x2435 ,0xb2f2,0x3e45 , + 0xd94d,0x3c42 ,0x0f79,0x24da ,0xb140,0x3daf , + 0xd74e,0x3cc5 ,0x0e61,0x257e ,0xafa9,0x3d03 , + 0xd556,0x3d3f ,0x0d48,0x2620 ,0xae2e,0x3c42 , + 0xd363,0x3daf ,0x0c2e,0x26c1 ,0xacd0,0x3b6d , + 0xd178,0x3e15 ,0x0b14,0x2760 ,0xab8e,0x3a82 , + 0xcf94,0x3e72 ,0x09fa,0x27fe ,0xaa6a,0x3984 , + 0xcdb7,0x3ec5 ,0x08df,0x289a ,0xa963,0x3871 , + 0xcbe2,0x3f0f ,0x07c4,0x2935 ,0xa87b,0x374b , + 0xca15,0x3f4f ,0x06a9,0x29ce ,0xa7b1,0x3612 , + 0xc851,0x3f85 ,0x058d,0x2a65 ,0xa705,0x34c6 , + 0xc695,0x3fb1 ,0x0471,0x2afb ,0xa678,0x3368 , + 0xc4e2,0x3fd4 ,0x0355,0x2b8f ,0xa60b,0x31f8 , + 0xc338,0x3fec ,0x0239,0x2c21 ,0xa5bc,0x3076 , + 0xc197,0x3ffb ,0x011c,0x2cb2 ,0xa58d,0x2ee4 , + 0xc000,0x4000 ,0x0000,0x2d41 ,0xa57e,0x2d41 , + 0xbe73,0x3ffb ,0xfee4,0x2dcf ,0xa58d,0x2b8f , + 0xbcf0,0x3fec ,0xfdc7,0x2e5a ,0xa5bc,0x29ce , + 0xbb77,0x3fd4 ,0xfcab,0x2ee4 ,0xa60b,0x27fe , + 0xba09,0x3fb1 ,0xfb8f,0x2f6c ,0xa678,0x2620 , + 0xb8a6,0x3f85 ,0xfa73,0x2ff2 ,0xa705,0x2435 , + 0xb74d,0x3f4f ,0xf957,0x3076 ,0xa7b1,0x223d , + 0xb600,0x3f0f ,0xf83c,0x30f9 ,0xa87b,0x203a , + 0xb4be,0x3ec5 ,0xf721,0x3179 ,0xa963,0x1e2b , + 0xb388,0x3e72 ,0xf606,0x31f8 ,0xaa6a,0x1c12 , + 0xb25e,0x3e15 ,0xf4ec,0x3274 ,0xab8e,0x19ef , + 0xb140,0x3daf ,0xf3d2,0x32ef ,0xacd0,0x17c4 , + 0xb02d,0x3d3f ,0xf2b8,0x3368 ,0xae2e,0x1590 , + 0xaf28,0x3cc5 ,0xf19f,0x33df ,0xafa9,0x1354 , + 0xae2e,0x3c42 ,0xf087,0x3453 ,0xb140,0x1112 , + 0xad41,0x3bb6 ,0xef6f,0x34c6 ,0xb2f2,0x0eca , + 0xac61,0x3b21 ,0xee58,0x3537 ,0xb4be,0x0c7c , + 0xab8e,0x3a82 ,0xed41,0x35a5 ,0xb6a5,0x0a2b , + 0xaac8,0x39db ,0xec2b,0x3612 ,0xb8a6,0x07d6 , + 0xaa0f,0x392b ,0xeb16,0x367d ,0xbabf,0x057e , + 0xa963,0x3871 ,0xea02,0x36e5 ,0xbcf0,0x0324 , + 0xa8c5,0x37b0 ,0xe8ef,0x374b ,0xbf38,0x00c9 , + 0xa834,0x36e5 ,0xe7dc,0x37b0 ,0xc197,0xfe6e , + 0xa7b1,0x3612 ,0xe6cb,0x3812 ,0xc40c,0xfc13 , + 0xa73b,0x3537 ,0xe5ba,0x3871 ,0xc695,0xf9ba , + 0xa6d3,0x3453 ,0xe4aa,0x38cf ,0xc932,0xf763 , + 0xa678,0x3368 ,0xe39c,0x392b ,0xcbe2,0xf50f , + 0xa62c,0x3274 ,0xe28e,0x3984 ,0xcea5,0xf2bf , + 0xa5ed,0x3179 ,0xe182,0x39db ,0xd178,0xf073 , + 0xa5bc,0x3076 ,0xe077,0x3a30 ,0xd45c,0xee2d , + 0xa599,0x2f6c ,0xdf6d,0x3a82 ,0xd74e,0xebed , + 0xa585,0x2e5a ,0xde64,0x3ad3 ,0xda4f,0xe9b4 , + 0xa57e,0x2d41 ,0xdd5d,0x3b21 ,0xdd5d,0xe782 , + 0xa585,0x2c21 ,0xdc57,0x3b6d ,0xe077,0xe559 , + 0xa599,0x2afb ,0xdb52,0x3bb6 ,0xe39c,0xe33a , + 0xa5bc,0x29ce ,0xda4f,0x3bfd ,0xe6cb,0xe124 , + 0xa5ed,0x289a ,0xd94d,0x3c42 ,0xea02,0xdf19 , + 0xa62c,0x2760 ,0xd84d,0x3c85 ,0xed41,0xdd19 , + 0xa678,0x2620 ,0xd74e,0x3cc5 ,0xf087,0xdb26 , + 0xa6d3,0x24da ,0xd651,0x3d03 ,0xf3d2,0xd93f , + 0xa73b,0x238e ,0xd556,0x3d3f ,0xf721,0xd766 , + 0xa7b1,0x223d ,0xd45c,0x3d78 ,0xfa73,0xd59b , + 0xa834,0x20e7 ,0xd363,0x3daf ,0xfdc7,0xd3df , + 0xa8c5,0x1f8c ,0xd26d,0x3de3 ,0x011c,0xd231 , + 0xa963,0x1e2b ,0xd178,0x3e15 ,0x0471,0xd094 , + 0xaa0f,0x1cc6 ,0xd085,0x3e45 ,0x07c4,0xcf07 , + 0xaac8,0x1b5d ,0xcf94,0x3e72 ,0x0b14,0xcd8c , + 0xab8e,0x19ef ,0xcea5,0x3e9d ,0x0e61,0xcc21 , + 0xac61,0x187e ,0xcdb7,0x3ec5 ,0x11a8,0xcac9 , + 0xad41,0x1709 ,0xcccc,0x3eeb ,0x14ea,0xc983 , + 0xae2e,0x1590 ,0xcbe2,0x3f0f ,0x1824,0xc850 , + 0xaf28,0x1413 ,0xcafb,0x3f30 ,0x1b56,0xc731 , + 0xb02d,0x1294 ,0xca15,0x3f4f ,0x1e7e,0xc625 , + 0xb140,0x1112 ,0xc932,0x3f6b ,0x219c,0xc52d , + 0xb25e,0x0f8d ,0xc851,0x3f85 ,0x24ae,0xc44a , + 0xb388,0x0e06 ,0xc772,0x3f9c ,0x27b3,0xc37b , + 0xb4be,0x0c7c ,0xc695,0x3fb1 ,0x2aaa,0xc2c1 , + 0xb600,0x0af1 ,0xc5ba,0x3fc4 ,0x2d93,0xc21d , + 0xb74d,0x0964 ,0xc4e2,0x3fd4 ,0x306c,0xc18e , + 0xb8a6,0x07d6 ,0xc40c,0x3fe1 ,0x3334,0xc115 , + 0xba09,0x0646 ,0xc338,0x3fec ,0x35eb,0xc0b1 , + 0xbb77,0x04b5 ,0xc266,0x3ff5 ,0x388e,0xc064 , + 0xbcf0,0x0324 ,0xc197,0x3ffb ,0x3b1e,0xc02c , + 0xbe73,0x0192 ,0xc0ca,0x3fff ,0x3d9a,0xc00b , + 0x4000,0x0000 ,0x3f9b,0x0065 ,0x3f36,0x00c9 , + 0x3ed0,0x012e ,0x3e69,0x0192 ,0x3e02,0x01f7 , + 0x3d9a,0x025b ,0x3d31,0x02c0 ,0x3cc8,0x0324 , + 0x3c5f,0x0388 ,0x3bf4,0x03ed ,0x3b8a,0x0451 , + 0x3b1e,0x04b5 ,0x3ab2,0x051a ,0x3a46,0x057e , + 0x39d9,0x05e2 ,0x396b,0x0646 ,0x38fd,0x06aa , + 0x388e,0x070e ,0x381f,0x0772 ,0x37af,0x07d6 , + 0x373f,0x0839 ,0x36ce,0x089d ,0x365d,0x0901 , + 0x35eb,0x0964 ,0x3578,0x09c7 ,0x3505,0x0a2b , + 0x3492,0x0a8e ,0x341e,0x0af1 ,0x33a9,0x0b54 , + 0x3334,0x0bb7 ,0x32bf,0x0c1a ,0x3249,0x0c7c , + 0x31d2,0x0cdf ,0x315b,0x0d41 ,0x30e4,0x0da4 , + 0x306c,0x0e06 ,0x2ff4,0x0e68 ,0x2f7b,0x0eca , + 0x2f02,0x0f2b ,0x2e88,0x0f8d ,0x2e0e,0x0fee , + 0x2d93,0x1050 ,0x2d18,0x10b1 ,0x2c9d,0x1112 , + 0x2c21,0x1173 ,0x2ba4,0x11d3 ,0x2b28,0x1234 , + 0x2aaa,0x1294 ,0x2a2d,0x12f4 ,0x29af,0x1354 , + 0x2931,0x13b4 ,0x28b2,0x1413 ,0x2833,0x1473 , + 0x27b3,0x14d2 ,0x2733,0x1531 ,0x26b3,0x1590 , + 0x2632,0x15ee ,0x25b1,0x164c ,0x252f,0x16ab , + 0x24ae,0x1709 ,0x242b,0x1766 ,0x23a9,0x17c4 , + 0x2326,0x1821 ,0x22a3,0x187e ,0x221f,0x18db , + 0x219c,0x1937 ,0x2117,0x1993 ,0x2093,0x19ef , + 0x200e,0x1a4b ,0x1f89,0x1aa7 ,0x1f04,0x1b02 , + 0x1e7e,0x1b5d ,0x1df8,0x1bb8 ,0x1d72,0x1c12 , + 0x1ceb,0x1c6c ,0x1c64,0x1cc6 ,0x1bdd,0x1d20 , + 0x1b56,0x1d79 ,0x1ace,0x1dd3 ,0x1a46,0x1e2b , + 0x19be,0x1e84 ,0x1935,0x1edc ,0x18ad,0x1f34 , + 0x1824,0x1f8c ,0x179b,0x1fe3 ,0x1711,0x203a , + 0x1688,0x2091 ,0x15fe,0x20e7 ,0x1574,0x213d , + 0x14ea,0x2193 ,0x145f,0x21e8 ,0x13d5,0x223d , + 0x134a,0x2292 ,0x12bf,0x22e7 ,0x1234,0x233b , + 0x11a8,0x238e ,0x111d,0x23e2 ,0x1091,0x2435 , + 0x1005,0x2488 ,0x0f79,0x24da ,0x0eed,0x252c , + 0x0e61,0x257e ,0x0dd4,0x25cf ,0x0d48,0x2620 , + 0x0cbb,0x2671 ,0x0c2e,0x26c1 ,0x0ba1,0x2711 , + 0x0b14,0x2760 ,0x0a87,0x27af ,0x09fa,0x27fe , + 0x096d,0x284c ,0x08df,0x289a ,0x0852,0x28e7 , + 0x07c4,0x2935 ,0x0736,0x2981 ,0x06a9,0x29ce , + 0x061b,0x2a1a ,0x058d,0x2a65 ,0x04ff,0x2ab0 , + 0x0471,0x2afb ,0x03e3,0x2b45 ,0x0355,0x2b8f , + 0x02c7,0x2bd8 ,0x0239,0x2c21 ,0x01aa,0x2c6a , + 0x011c,0x2cb2 ,0x008e,0x2cfa ,0x0000,0x2d41 , + 0xff72,0x2d88 ,0xfee4,0x2dcf ,0xfe56,0x2e15 , + 0xfdc7,0x2e5a ,0xfd39,0x2e9f ,0xfcab,0x2ee4 , + 0xfc1d,0x2f28 ,0xfb8f,0x2f6c ,0xfb01,0x2faf , + 0xfa73,0x2ff2 ,0xf9e5,0x3034 ,0xf957,0x3076 , + 0xf8ca,0x30b8 ,0xf83c,0x30f9 ,0xf7ae,0x3139 , + 0xf721,0x3179 ,0xf693,0x31b9 ,0xf606,0x31f8 , + 0xf579,0x3236 ,0xf4ec,0x3274 ,0xf45f,0x32b2 , + 0xf3d2,0x32ef ,0xf345,0x332c ,0xf2b8,0x3368 , + 0xf22c,0x33a3 ,0xf19f,0x33df ,0xf113,0x3419 , + 0xf087,0x3453 ,0xeffb,0x348d ,0xef6f,0x34c6 , + 0xeee3,0x34ff ,0xee58,0x3537 ,0xedcc,0x356e , + 0xed41,0x35a5 ,0xecb6,0x35dc ,0xec2b,0x3612 , + 0xeba1,0x3648 ,0xeb16,0x367d ,0xea8c,0x36b1 , + 0xea02,0x36e5 ,0xe978,0x3718 ,0xe8ef,0x374b , + 0xe865,0x377e ,0xe7dc,0x37b0 ,0xe753,0x37e1 , + 0xe6cb,0x3812 ,0xe642,0x3842 ,0xe5ba,0x3871 , + 0xe532,0x38a1 ,0xe4aa,0x38cf ,0xe423,0x38fd , + 0xe39c,0x392b ,0xe315,0x3958 ,0xe28e,0x3984 , + 0xe208,0x39b0 ,0xe182,0x39db ,0xe0fc,0x3a06 , + 0xe077,0x3a30 ,0xdff2,0x3a59 ,0xdf6d,0x3a82 , + 0xdee9,0x3aab ,0xde64,0x3ad3 ,0xdde1,0x3afa , + 0xdd5d,0x3b21 ,0xdcda,0x3b47 ,0xdc57,0x3b6d , + 0xdbd5,0x3b92 ,0xdb52,0x3bb6 ,0xdad1,0x3bda , + 0xda4f,0x3bfd ,0xd9ce,0x3c20 ,0xd94d,0x3c42 , + 0xd8cd,0x3c64 ,0xd84d,0x3c85 ,0xd7cd,0x3ca5 , + 0xd74e,0x3cc5 ,0xd6cf,0x3ce4 ,0xd651,0x3d03 , + 0xd5d3,0x3d21 ,0xd556,0x3d3f ,0xd4d8,0x3d5b , + 0xd45c,0x3d78 ,0xd3df,0x3d93 ,0xd363,0x3daf , + 0xd2e8,0x3dc9 ,0xd26d,0x3de3 ,0xd1f2,0x3dfc , + 0xd178,0x3e15 ,0xd0fe,0x3e2d ,0xd085,0x3e45 , + 0xd00c,0x3e5c ,0xcf94,0x3e72 ,0xcf1c,0x3e88 , + 0xcea5,0x3e9d ,0xce2e,0x3eb1 ,0xcdb7,0x3ec5 , + 0xcd41,0x3ed8 ,0xcccc,0x3eeb ,0xcc57,0x3efd , + 0xcbe2,0x3f0f ,0xcb6e,0x3f20 ,0xcafb,0x3f30 , + 0xca88,0x3f40 ,0xca15,0x3f4f ,0xc9a3,0x3f5d , + 0xc932,0x3f6b ,0xc8c1,0x3f78 ,0xc851,0x3f85 , + 0xc7e1,0x3f91 ,0xc772,0x3f9c ,0xc703,0x3fa7 , + 0xc695,0x3fb1 ,0xc627,0x3fbb ,0xc5ba,0x3fc4 , + 0xc54e,0x3fcc ,0xc4e2,0x3fd4 ,0xc476,0x3fdb , + 0xc40c,0x3fe1 ,0xc3a1,0x3fe7 ,0xc338,0x3fec , + 0xc2cf,0x3ff1 ,0xc266,0x3ff5 ,0xc1fe,0x3ff8 , + 0xc197,0x3ffb ,0xc130,0x3ffd ,0xc0ca,0x3fff , + 0xc065,0x4000 ,0xc000,0x4000 ,0xbf9c,0x4000 , + 0xbf38,0x3fff ,0xbed5,0x3ffd ,0xbe73,0x3ffb , + 0xbe11,0x3ff8 ,0xbdb0,0x3ff5 ,0xbd50,0x3ff1 , + 0xbcf0,0x3fec ,0xbc91,0x3fe7 ,0xbc32,0x3fe1 , + 0xbbd4,0x3fdb ,0xbb77,0x3fd4 ,0xbb1b,0x3fcc , + 0xbabf,0x3fc4 ,0xba64,0x3fbb ,0xba09,0x3fb1 , + 0xb9af,0x3fa7 ,0xb956,0x3f9c ,0xb8fd,0x3f91 , + 0xb8a6,0x3f85 ,0xb84f,0x3f78 ,0xb7f8,0x3f6b , + 0xb7a2,0x3f5d ,0xb74d,0x3f4f ,0xb6f9,0x3f40 , + 0xb6a5,0x3f30 ,0xb652,0x3f20 ,0xb600,0x3f0f , + 0xb5af,0x3efd ,0xb55e,0x3eeb ,0xb50e,0x3ed8 , + 0xb4be,0x3ec5 ,0xb470,0x3eb1 ,0xb422,0x3e9d , + 0xb3d5,0x3e88 ,0xb388,0x3e72 ,0xb33d,0x3e5c , + 0xb2f2,0x3e45 ,0xb2a7,0x3e2d ,0xb25e,0x3e15 , + 0xb215,0x3dfc ,0xb1cd,0x3de3 ,0xb186,0x3dc9 , + 0xb140,0x3daf ,0xb0fa,0x3d93 ,0xb0b5,0x3d78 , + 0xb071,0x3d5b ,0xb02d,0x3d3f ,0xafeb,0x3d21 , + 0xafa9,0x3d03 ,0xaf68,0x3ce4 ,0xaf28,0x3cc5 , + 0xaee8,0x3ca5 ,0xaea9,0x3c85 ,0xae6b,0x3c64 , + 0xae2e,0x3c42 ,0xadf2,0x3c20 ,0xadb6,0x3bfd , + 0xad7b,0x3bda ,0xad41,0x3bb6 ,0xad08,0x3b92 , + 0xacd0,0x3b6d ,0xac98,0x3b47 ,0xac61,0x3b21 , + 0xac2b,0x3afa ,0xabf6,0x3ad3 ,0xabc2,0x3aab , + 0xab8e,0x3a82 ,0xab5b,0x3a59 ,0xab29,0x3a30 , + 0xaaf8,0x3a06 ,0xaac8,0x39db ,0xaa98,0x39b0 , + 0xaa6a,0x3984 ,0xaa3c,0x3958 ,0xaa0f,0x392b , + 0xa9e3,0x38fd ,0xa9b7,0x38cf ,0xa98d,0x38a1 , + 0xa963,0x3871 ,0xa93a,0x3842 ,0xa912,0x3812 , + 0xa8eb,0x37e1 ,0xa8c5,0x37b0 ,0xa89f,0x377e , + 0xa87b,0x374b ,0xa857,0x3718 ,0xa834,0x36e5 , + 0xa812,0x36b1 ,0xa7f1,0x367d ,0xa7d0,0x3648 , + 0xa7b1,0x3612 ,0xa792,0x35dc ,0xa774,0x35a5 , + 0xa757,0x356e ,0xa73b,0x3537 ,0xa71f,0x34ff , + 0xa705,0x34c6 ,0xa6eb,0x348d ,0xa6d3,0x3453 , + 0xa6bb,0x3419 ,0xa6a4,0x33df ,0xa68e,0x33a3 , + 0xa678,0x3368 ,0xa664,0x332c ,0xa650,0x32ef , + 0xa63e,0x32b2 ,0xa62c,0x3274 ,0xa61b,0x3236 , + 0xa60b,0x31f8 ,0xa5fb,0x31b9 ,0xa5ed,0x3179 , + 0xa5e0,0x3139 ,0xa5d3,0x30f9 ,0xa5c7,0x30b8 , + 0xa5bc,0x3076 ,0xa5b2,0x3034 ,0xa5a9,0x2ff2 , + 0xa5a1,0x2faf ,0xa599,0x2f6c ,0xa593,0x2f28 , + 0xa58d,0x2ee4 ,0xa588,0x2e9f ,0xa585,0x2e5a , + 0xa581,0x2e15 ,0xa57f,0x2dcf ,0xa57e,0x2d88 , + 0xa57e,0x2d41 ,0xa57e,0x2cfa ,0xa57f,0x2cb2 , + 0xa581,0x2c6a ,0xa585,0x2c21 ,0xa588,0x2bd8 , + 0xa58d,0x2b8f ,0xa593,0x2b45 ,0xa599,0x2afb , + 0xa5a1,0x2ab0 ,0xa5a9,0x2a65 ,0xa5b2,0x2a1a , + 0xa5bc,0x29ce ,0xa5c7,0x2981 ,0xa5d3,0x2935 , + 0xa5e0,0x28e7 ,0xa5ed,0x289a ,0xa5fb,0x284c , + 0xa60b,0x27fe ,0xa61b,0x27af ,0xa62c,0x2760 , + 0xa63e,0x2711 ,0xa650,0x26c1 ,0xa664,0x2671 , + 0xa678,0x2620 ,0xa68e,0x25cf ,0xa6a4,0x257e , + 0xa6bb,0x252c ,0xa6d3,0x24da ,0xa6eb,0x2488 , + 0xa705,0x2435 ,0xa71f,0x23e2 ,0xa73b,0x238e , + 0xa757,0x233b ,0xa774,0x22e7 ,0xa792,0x2292 , + 0xa7b1,0x223d ,0xa7d0,0x21e8 ,0xa7f1,0x2193 , + 0xa812,0x213d ,0xa834,0x20e7 ,0xa857,0x2091 , + 0xa87b,0x203a ,0xa89f,0x1fe3 ,0xa8c5,0x1f8c , + 0xa8eb,0x1f34 ,0xa912,0x1edc ,0xa93a,0x1e84 , + 0xa963,0x1e2b ,0xa98d,0x1dd3 ,0xa9b7,0x1d79 , + 0xa9e3,0x1d20 ,0xaa0f,0x1cc6 ,0xaa3c,0x1c6c , + 0xaa6a,0x1c12 ,0xaa98,0x1bb8 ,0xaac8,0x1b5d , + 0xaaf8,0x1b02 ,0xab29,0x1aa7 ,0xab5b,0x1a4b , + 0xab8e,0x19ef ,0xabc2,0x1993 ,0xabf6,0x1937 , + 0xac2b,0x18db ,0xac61,0x187e ,0xac98,0x1821 , + 0xacd0,0x17c4 ,0xad08,0x1766 ,0xad41,0x1709 , + 0xad7b,0x16ab ,0xadb6,0x164c ,0xadf2,0x15ee , + 0xae2e,0x1590 ,0xae6b,0x1531 ,0xaea9,0x14d2 , + 0xaee8,0x1473 ,0xaf28,0x1413 ,0xaf68,0x13b4 , + 0xafa9,0x1354 ,0xafeb,0x12f4 ,0xb02d,0x1294 , + 0xb071,0x1234 ,0xb0b5,0x11d3 ,0xb0fa,0x1173 , + 0xb140,0x1112 ,0xb186,0x10b1 ,0xb1cd,0x1050 , + 0xb215,0x0fee ,0xb25e,0x0f8d ,0xb2a7,0x0f2b , + 0xb2f2,0x0eca ,0xb33d,0x0e68 ,0xb388,0x0e06 , + 0xb3d5,0x0da4 ,0xb422,0x0d41 ,0xb470,0x0cdf , + 0xb4be,0x0c7c ,0xb50e,0x0c1a ,0xb55e,0x0bb7 , + 0xb5af,0x0b54 ,0xb600,0x0af1 ,0xb652,0x0a8e , + 0xb6a5,0x0a2b ,0xb6f9,0x09c7 ,0xb74d,0x0964 , + 0xb7a2,0x0901 ,0xb7f8,0x089d ,0xb84f,0x0839 , + 0xb8a6,0x07d6 ,0xb8fd,0x0772 ,0xb956,0x070e , + 0xb9af,0x06aa ,0xba09,0x0646 ,0xba64,0x05e2 , + 0xbabf,0x057e ,0xbb1b,0x051a ,0xbb77,0x04b5 , + 0xbbd4,0x0451 ,0xbc32,0x03ed ,0xbc91,0x0388 , + 0xbcf0,0x0324 ,0xbd50,0x02c0 ,0xbdb0,0x025b , + 0xbe11,0x01f7 ,0xbe73,0x0192 ,0xbed5,0x012e , + 0xbf38,0x00c9 ,0xbf9c,0x0065 }; + + +extern const int s_Q14R_8; +const int s_Q14R_8 = 1024; +extern const unsigned short t_Q14R_8[2032]; +const unsigned short t_Q14R_8[2032] = { + 0x4000,0x0000 ,0x4000,0x0000 ,0x4000,0x0000 , + 0x3b21,0x187e ,0x3ec5,0x0c7c ,0x3537,0x238e , + 0x2d41,0x2d41 ,0x3b21,0x187e ,0x187e,0x3b21 , + 0x187e,0x3b21 ,0x3537,0x238e ,0xf384,0x3ec5 , + 0x0000,0x4000 ,0x2d41,0x2d41 ,0xd2bf,0x2d41 , + 0xe782,0x3b21 ,0x238e,0x3537 ,0xc13b,0x0c7c , + 0xd2bf,0x2d41 ,0x187e,0x3b21 ,0xc4df,0xe782 , + 0xc4df,0x187e ,0x0c7c,0x3ec5 ,0xdc72,0xcac9 , + 0x4000,0x0000 ,0x4000,0x0000 ,0x4000,0x0000 , + 0x3fb1,0x0646 ,0x3fec,0x0324 ,0x3f4f,0x0964 , + 0x3ec5,0x0c7c ,0x3fb1,0x0646 ,0x3d3f,0x1294 , + 0x3d3f,0x1294 ,0x3f4f,0x0964 ,0x39db,0x1b5d , + 0x3b21,0x187e ,0x3ec5,0x0c7c ,0x3537,0x238e , + 0x3871,0x1e2b ,0x3e15,0x0f8d ,0x2f6c,0x2afb , + 0x3537,0x238e ,0x3d3f,0x1294 ,0x289a,0x3179 , + 0x3179,0x289a ,0x3c42,0x1590 ,0x20e7,0x36e5 , + 0x2d41,0x2d41 ,0x3b21,0x187e ,0x187e,0x3b21 , + 0x289a,0x3179 ,0x39db,0x1b5d ,0x0f8d,0x3e15 , + 0x238e,0x3537 ,0x3871,0x1e2b ,0x0646,0x3fb1 , + 0x1e2b,0x3871 ,0x36e5,0x20e7 ,0xfcdc,0x3fec , + 0x187e,0x3b21 ,0x3537,0x238e ,0xf384,0x3ec5 , + 0x1294,0x3d3f ,0x3368,0x2620 ,0xea70,0x3c42 , + 0x0c7c,0x3ec5 ,0x3179,0x289a ,0xe1d5,0x3871 , + 0x0646,0x3fb1 ,0x2f6c,0x2afb ,0xd9e0,0x3368 , + 0x0000,0x4000 ,0x2d41,0x2d41 ,0xd2bf,0x2d41 , + 0xf9ba,0x3fb1 ,0x2afb,0x2f6c ,0xcc98,0x2620 , + 0xf384,0x3ec5 ,0x289a,0x3179 ,0xc78f,0x1e2b , + 0xed6c,0x3d3f ,0x2620,0x3368 ,0xc3be,0x1590 , + 0xe782,0x3b21 ,0x238e,0x3537 ,0xc13b,0x0c7c , + 0xe1d5,0x3871 ,0x20e7,0x36e5 ,0xc014,0x0324 , + 0xdc72,0x3537 ,0x1e2b,0x3871 ,0xc04f,0xf9ba , + 0xd766,0x3179 ,0x1b5d,0x39db ,0xc1eb,0xf073 , + 0xd2bf,0x2d41 ,0x187e,0x3b21 ,0xc4df,0xe782 , + 0xce87,0x289a ,0x1590,0x3c42 ,0xc91b,0xdf19 , + 0xcac9,0x238e ,0x1294,0x3d3f ,0xce87,0xd766 , + 0xc78f,0x1e2b ,0x0f8d,0x3e15 ,0xd505,0xd094 , + 0xc4df,0x187e ,0x0c7c,0x3ec5 ,0xdc72,0xcac9 , + 0xc2c1,0x1294 ,0x0964,0x3f4f ,0xe4a3,0xc625 , + 0xc13b,0x0c7c ,0x0646,0x3fb1 ,0xed6c,0xc2c1 , + 0xc04f,0x0646 ,0x0324,0x3fec ,0xf69c,0xc0b1 , + 0x4000,0x0000 ,0x4000,0x0000 ,0x4000,0x0000 , + 0x3ffb,0x0192 ,0x3fff,0x00c9 ,0x3ff5,0x025b , + 0x3fec,0x0324 ,0x3ffb,0x0192 ,0x3fd4,0x04b5 , + 0x3fd4,0x04b5 ,0x3ff5,0x025b ,0x3f9c,0x070e , + 0x3fb1,0x0646 ,0x3fec,0x0324 ,0x3f4f,0x0964 , + 0x3f85,0x07d6 ,0x3fe1,0x03ed ,0x3eeb,0x0bb7 , + 0x3f4f,0x0964 ,0x3fd4,0x04b5 ,0x3e72,0x0e06 , + 0x3f0f,0x0af1 ,0x3fc4,0x057e ,0x3de3,0x1050 , + 0x3ec5,0x0c7c ,0x3fb1,0x0646 ,0x3d3f,0x1294 , + 0x3e72,0x0e06 ,0x3f9c,0x070e ,0x3c85,0x14d2 , + 0x3e15,0x0f8d ,0x3f85,0x07d6 ,0x3bb6,0x1709 , + 0x3daf,0x1112 ,0x3f6b,0x089d ,0x3ad3,0x1937 , + 0x3d3f,0x1294 ,0x3f4f,0x0964 ,0x39db,0x1b5d , + 0x3cc5,0x1413 ,0x3f30,0x0a2b ,0x38cf,0x1d79 , + 0x3c42,0x1590 ,0x3f0f,0x0af1 ,0x37b0,0x1f8c , + 0x3bb6,0x1709 ,0x3eeb,0x0bb7 ,0x367d,0x2193 , + 0x3b21,0x187e ,0x3ec5,0x0c7c ,0x3537,0x238e , + 0x3a82,0x19ef ,0x3e9d,0x0d41 ,0x33df,0x257e , + 0x39db,0x1b5d ,0x3e72,0x0e06 ,0x3274,0x2760 , + 0x392b,0x1cc6 ,0x3e45,0x0eca ,0x30f9,0x2935 , + 0x3871,0x1e2b ,0x3e15,0x0f8d ,0x2f6c,0x2afb , + 0x37b0,0x1f8c ,0x3de3,0x1050 ,0x2dcf,0x2cb2 , + 0x36e5,0x20e7 ,0x3daf,0x1112 ,0x2c21,0x2e5a , + 0x3612,0x223d ,0x3d78,0x11d3 ,0x2a65,0x2ff2 , + 0x3537,0x238e ,0x3d3f,0x1294 ,0x289a,0x3179 , + 0x3453,0x24da ,0x3d03,0x1354 ,0x26c1,0x32ef , + 0x3368,0x2620 ,0x3cc5,0x1413 ,0x24da,0x3453 , + 0x3274,0x2760 ,0x3c85,0x14d2 ,0x22e7,0x35a5 , + 0x3179,0x289a ,0x3c42,0x1590 ,0x20e7,0x36e5 , + 0x3076,0x29ce ,0x3bfd,0x164c ,0x1edc,0x3812 , + 0x2f6c,0x2afb ,0x3bb6,0x1709 ,0x1cc6,0x392b , + 0x2e5a,0x2c21 ,0x3b6d,0x17c4 ,0x1aa7,0x3a30 , + 0x2d41,0x2d41 ,0x3b21,0x187e ,0x187e,0x3b21 , + 0x2c21,0x2e5a ,0x3ad3,0x1937 ,0x164c,0x3bfd , + 0x2afb,0x2f6c ,0x3a82,0x19ef ,0x1413,0x3cc5 , + 0x29ce,0x3076 ,0x3a30,0x1aa7 ,0x11d3,0x3d78 , + 0x289a,0x3179 ,0x39db,0x1b5d ,0x0f8d,0x3e15 , + 0x2760,0x3274 ,0x3984,0x1c12 ,0x0d41,0x3e9d , + 0x2620,0x3368 ,0x392b,0x1cc6 ,0x0af1,0x3f0f , + 0x24da,0x3453 ,0x38cf,0x1d79 ,0x089d,0x3f6b , + 0x238e,0x3537 ,0x3871,0x1e2b ,0x0646,0x3fb1 , + 0x223d,0x3612 ,0x3812,0x1edc ,0x03ed,0x3fe1 , + 0x20e7,0x36e5 ,0x37b0,0x1f8c ,0x0192,0x3ffb , + 0x1f8c,0x37b0 ,0x374b,0x203a ,0xff37,0x3fff , + 0x1e2b,0x3871 ,0x36e5,0x20e7 ,0xfcdc,0x3fec , + 0x1cc6,0x392b ,0x367d,0x2193 ,0xfa82,0x3fc4 , + 0x1b5d,0x39db ,0x3612,0x223d ,0xf82a,0x3f85 , + 0x19ef,0x3a82 ,0x35a5,0x22e7 ,0xf5d5,0x3f30 , + 0x187e,0x3b21 ,0x3537,0x238e ,0xf384,0x3ec5 , + 0x1709,0x3bb6 ,0x34c6,0x2435 ,0xf136,0x3e45 , + 0x1590,0x3c42 ,0x3453,0x24da ,0xeeee,0x3daf , + 0x1413,0x3cc5 ,0x33df,0x257e ,0xecac,0x3d03 , + 0x1294,0x3d3f ,0x3368,0x2620 ,0xea70,0x3c42 , + 0x1112,0x3daf ,0x32ef,0x26c1 ,0xe83c,0x3b6d , + 0x0f8d,0x3e15 ,0x3274,0x2760 ,0xe611,0x3a82 , + 0x0e06,0x3e72 ,0x31f8,0x27fe ,0xe3ee,0x3984 , + 0x0c7c,0x3ec5 ,0x3179,0x289a ,0xe1d5,0x3871 , + 0x0af1,0x3f0f ,0x30f9,0x2935 ,0xdfc6,0x374b , + 0x0964,0x3f4f ,0x3076,0x29ce ,0xddc3,0x3612 , + 0x07d6,0x3f85 ,0x2ff2,0x2a65 ,0xdbcb,0x34c6 , + 0x0646,0x3fb1 ,0x2f6c,0x2afb ,0xd9e0,0x3368 , + 0x04b5,0x3fd4 ,0x2ee4,0x2b8f ,0xd802,0x31f8 , + 0x0324,0x3fec ,0x2e5a,0x2c21 ,0xd632,0x3076 , + 0x0192,0x3ffb ,0x2dcf,0x2cb2 ,0xd471,0x2ee4 , + 0x0000,0x4000 ,0x2d41,0x2d41 ,0xd2bf,0x2d41 , + 0xfe6e,0x3ffb ,0x2cb2,0x2dcf ,0xd11c,0x2b8f , + 0xfcdc,0x3fec ,0x2c21,0x2e5a ,0xcf8a,0x29ce , + 0xfb4b,0x3fd4 ,0x2b8f,0x2ee4 ,0xce08,0x27fe , + 0xf9ba,0x3fb1 ,0x2afb,0x2f6c ,0xcc98,0x2620 , + 0xf82a,0x3f85 ,0x2a65,0x2ff2 ,0xcb3a,0x2435 , + 0xf69c,0x3f4f ,0x29ce,0x3076 ,0xc9ee,0x223d , + 0xf50f,0x3f0f ,0x2935,0x30f9 ,0xc8b5,0x203a , + 0xf384,0x3ec5 ,0x289a,0x3179 ,0xc78f,0x1e2b , + 0xf1fa,0x3e72 ,0x27fe,0x31f8 ,0xc67c,0x1c12 , + 0xf073,0x3e15 ,0x2760,0x3274 ,0xc57e,0x19ef , + 0xeeee,0x3daf ,0x26c1,0x32ef ,0xc493,0x17c4 , + 0xed6c,0x3d3f ,0x2620,0x3368 ,0xc3be,0x1590 , + 0xebed,0x3cc5 ,0x257e,0x33df ,0xc2fd,0x1354 , + 0xea70,0x3c42 ,0x24da,0x3453 ,0xc251,0x1112 , + 0xe8f7,0x3bb6 ,0x2435,0x34c6 ,0xc1bb,0x0eca , + 0xe782,0x3b21 ,0x238e,0x3537 ,0xc13b,0x0c7c , + 0xe611,0x3a82 ,0x22e7,0x35a5 ,0xc0d0,0x0a2b , + 0xe4a3,0x39db ,0x223d,0x3612 ,0xc07b,0x07d6 , + 0xe33a,0x392b ,0x2193,0x367d ,0xc03c,0x057e , + 0xe1d5,0x3871 ,0x20e7,0x36e5 ,0xc014,0x0324 , + 0xe074,0x37b0 ,0x203a,0x374b ,0xc001,0x00c9 , + 0xdf19,0x36e5 ,0x1f8c,0x37b0 ,0xc005,0xfe6e , + 0xddc3,0x3612 ,0x1edc,0x3812 ,0xc01f,0xfc13 , + 0xdc72,0x3537 ,0x1e2b,0x3871 ,0xc04f,0xf9ba , + 0xdb26,0x3453 ,0x1d79,0x38cf ,0xc095,0xf763 , + 0xd9e0,0x3368 ,0x1cc6,0x392b ,0xc0f1,0xf50f , + 0xd8a0,0x3274 ,0x1c12,0x3984 ,0xc163,0xf2bf , + 0xd766,0x3179 ,0x1b5d,0x39db ,0xc1eb,0xf073 , + 0xd632,0x3076 ,0x1aa7,0x3a30 ,0xc288,0xee2d , + 0xd505,0x2f6c ,0x19ef,0x3a82 ,0xc33b,0xebed , + 0xd3df,0x2e5a ,0x1937,0x3ad3 ,0xc403,0xe9b4 , + 0xd2bf,0x2d41 ,0x187e,0x3b21 ,0xc4df,0xe782 , + 0xd1a6,0x2c21 ,0x17c4,0x3b6d ,0xc5d0,0xe559 , + 0xd094,0x2afb ,0x1709,0x3bb6 ,0xc6d5,0xe33a , + 0xcf8a,0x29ce ,0x164c,0x3bfd ,0xc7ee,0xe124 , + 0xce87,0x289a ,0x1590,0x3c42 ,0xc91b,0xdf19 , + 0xcd8c,0x2760 ,0x14d2,0x3c85 ,0xca5b,0xdd19 , + 0xcc98,0x2620 ,0x1413,0x3cc5 ,0xcbad,0xdb26 , + 0xcbad,0x24da ,0x1354,0x3d03 ,0xcd11,0xd93f , + 0xcac9,0x238e ,0x1294,0x3d3f ,0xce87,0xd766 , + 0xc9ee,0x223d ,0x11d3,0x3d78 ,0xd00e,0xd59b , + 0xc91b,0x20e7 ,0x1112,0x3daf ,0xd1a6,0xd3df , + 0xc850,0x1f8c ,0x1050,0x3de3 ,0xd34e,0xd231 , + 0xc78f,0x1e2b ,0x0f8d,0x3e15 ,0xd505,0xd094 , + 0xc6d5,0x1cc6 ,0x0eca,0x3e45 ,0xd6cb,0xcf07 , + 0xc625,0x1b5d ,0x0e06,0x3e72 ,0xd8a0,0xcd8c , + 0xc57e,0x19ef ,0x0d41,0x3e9d ,0xda82,0xcc21 , + 0xc4df,0x187e ,0x0c7c,0x3ec5 ,0xdc72,0xcac9 , + 0xc44a,0x1709 ,0x0bb7,0x3eeb ,0xde6d,0xc983 , + 0xc3be,0x1590 ,0x0af1,0x3f0f ,0xe074,0xc850 , + 0xc33b,0x1413 ,0x0a2b,0x3f30 ,0xe287,0xc731 , + 0xc2c1,0x1294 ,0x0964,0x3f4f ,0xe4a3,0xc625 , + 0xc251,0x1112 ,0x089d,0x3f6b ,0xe6c9,0xc52d , + 0xc1eb,0x0f8d ,0x07d6,0x3f85 ,0xe8f7,0xc44a , + 0xc18e,0x0e06 ,0x070e,0x3f9c ,0xeb2e,0xc37b , + 0xc13b,0x0c7c ,0x0646,0x3fb1 ,0xed6c,0xc2c1 , + 0xc0f1,0x0af1 ,0x057e,0x3fc4 ,0xefb0,0xc21d , + 0xc0b1,0x0964 ,0x04b5,0x3fd4 ,0xf1fa,0xc18e , + 0xc07b,0x07d6 ,0x03ed,0x3fe1 ,0xf449,0xc115 , + 0xc04f,0x0646 ,0x0324,0x3fec ,0xf69c,0xc0b1 , + 0xc02c,0x04b5 ,0x025b,0x3ff5 ,0xf8f2,0xc064 , + 0xc014,0x0324 ,0x0192,0x3ffb ,0xfb4b,0xc02c , + 0xc005,0x0192 ,0x00c9,0x3fff ,0xfda5,0xc00b , + 0x4000,0x0000 ,0x4000,0x0065 ,0x3fff,0x00c9 , + 0x3ffd,0x012e ,0x3ffb,0x0192 ,0x3ff8,0x01f7 , + 0x3ff5,0x025b ,0x3ff1,0x02c0 ,0x3fec,0x0324 , + 0x3fe7,0x0388 ,0x3fe1,0x03ed ,0x3fdb,0x0451 , + 0x3fd4,0x04b5 ,0x3fcc,0x051a ,0x3fc4,0x057e , + 0x3fbb,0x05e2 ,0x3fb1,0x0646 ,0x3fa7,0x06aa , + 0x3f9c,0x070e ,0x3f91,0x0772 ,0x3f85,0x07d6 , + 0x3f78,0x0839 ,0x3f6b,0x089d ,0x3f5d,0x0901 , + 0x3f4f,0x0964 ,0x3f40,0x09c7 ,0x3f30,0x0a2b , + 0x3f20,0x0a8e ,0x3f0f,0x0af1 ,0x3efd,0x0b54 , + 0x3eeb,0x0bb7 ,0x3ed8,0x0c1a ,0x3ec5,0x0c7c , + 0x3eb1,0x0cdf ,0x3e9d,0x0d41 ,0x3e88,0x0da4 , + 0x3e72,0x0e06 ,0x3e5c,0x0e68 ,0x3e45,0x0eca , + 0x3e2d,0x0f2b ,0x3e15,0x0f8d ,0x3dfc,0x0fee , + 0x3de3,0x1050 ,0x3dc9,0x10b1 ,0x3daf,0x1112 , + 0x3d93,0x1173 ,0x3d78,0x11d3 ,0x3d5b,0x1234 , + 0x3d3f,0x1294 ,0x3d21,0x12f4 ,0x3d03,0x1354 , + 0x3ce4,0x13b4 ,0x3cc5,0x1413 ,0x3ca5,0x1473 , + 0x3c85,0x14d2 ,0x3c64,0x1531 ,0x3c42,0x1590 , + 0x3c20,0x15ee ,0x3bfd,0x164c ,0x3bda,0x16ab , + 0x3bb6,0x1709 ,0x3b92,0x1766 ,0x3b6d,0x17c4 , + 0x3b47,0x1821 ,0x3b21,0x187e ,0x3afa,0x18db , + 0x3ad3,0x1937 ,0x3aab,0x1993 ,0x3a82,0x19ef , + 0x3a59,0x1a4b ,0x3a30,0x1aa7 ,0x3a06,0x1b02 , + 0x39db,0x1b5d ,0x39b0,0x1bb8 ,0x3984,0x1c12 , + 0x3958,0x1c6c ,0x392b,0x1cc6 ,0x38fd,0x1d20 , + 0x38cf,0x1d79 ,0x38a1,0x1dd3 ,0x3871,0x1e2b , + 0x3842,0x1e84 ,0x3812,0x1edc ,0x37e1,0x1f34 , + 0x37b0,0x1f8c ,0x377e,0x1fe3 ,0x374b,0x203a , + 0x3718,0x2091 ,0x36e5,0x20e7 ,0x36b1,0x213d , + 0x367d,0x2193 ,0x3648,0x21e8 ,0x3612,0x223d , + 0x35dc,0x2292 ,0x35a5,0x22e7 ,0x356e,0x233b , + 0x3537,0x238e ,0x34ff,0x23e2 ,0x34c6,0x2435 , + 0x348d,0x2488 ,0x3453,0x24da ,0x3419,0x252c , + 0x33df,0x257e ,0x33a3,0x25cf ,0x3368,0x2620 , + 0x332c,0x2671 ,0x32ef,0x26c1 ,0x32b2,0x2711 , + 0x3274,0x2760 ,0x3236,0x27af ,0x31f8,0x27fe , + 0x31b9,0x284c ,0x3179,0x289a ,0x3139,0x28e7 , + 0x30f9,0x2935 ,0x30b8,0x2981 ,0x3076,0x29ce , + 0x3034,0x2a1a ,0x2ff2,0x2a65 ,0x2faf,0x2ab0 , + 0x2f6c,0x2afb ,0x2f28,0x2b45 ,0x2ee4,0x2b8f , + 0x2e9f,0x2bd8 ,0x2e5a,0x2c21 ,0x2e15,0x2c6a , + 0x2dcf,0x2cb2 ,0x2d88,0x2cfa ,0x2d41,0x2d41 , + 0x2cfa,0x2d88 ,0x2cb2,0x2dcf ,0x2c6a,0x2e15 , + 0x2c21,0x2e5a ,0x2bd8,0x2e9f ,0x2b8f,0x2ee4 , + 0x2b45,0x2f28 ,0x2afb,0x2f6c ,0x2ab0,0x2faf , + 0x2a65,0x2ff2 ,0x2a1a,0x3034 ,0x29ce,0x3076 , + 0x2981,0x30b8 ,0x2935,0x30f9 ,0x28e7,0x3139 , + 0x289a,0x3179 ,0x284c,0x31b9 ,0x27fe,0x31f8 , + 0x27af,0x3236 ,0x2760,0x3274 ,0x2711,0x32b2 , + 0x26c1,0x32ef ,0x2671,0x332c ,0x2620,0x3368 , + 0x25cf,0x33a3 ,0x257e,0x33df ,0x252c,0x3419 , + 0x24da,0x3453 ,0x2488,0x348d ,0x2435,0x34c6 , + 0x23e2,0x34ff ,0x238e,0x3537 ,0x233b,0x356e , + 0x22e7,0x35a5 ,0x2292,0x35dc ,0x223d,0x3612 , + 0x21e8,0x3648 ,0x2193,0x367d ,0x213d,0x36b1 , + 0x20e7,0x36e5 ,0x2091,0x3718 ,0x203a,0x374b , + 0x1fe3,0x377e ,0x1f8c,0x37b0 ,0x1f34,0x37e1 , + 0x1edc,0x3812 ,0x1e84,0x3842 ,0x1e2b,0x3871 , + 0x1dd3,0x38a1 ,0x1d79,0x38cf ,0x1d20,0x38fd , + 0x1cc6,0x392b ,0x1c6c,0x3958 ,0x1c12,0x3984 , + 0x1bb8,0x39b0 ,0x1b5d,0x39db ,0x1b02,0x3a06 , + 0x1aa7,0x3a30 ,0x1a4b,0x3a59 ,0x19ef,0x3a82 , + 0x1993,0x3aab ,0x1937,0x3ad3 ,0x18db,0x3afa , + 0x187e,0x3b21 ,0x1821,0x3b47 ,0x17c4,0x3b6d , + 0x1766,0x3b92 ,0x1709,0x3bb6 ,0x16ab,0x3bda , + 0x164c,0x3bfd ,0x15ee,0x3c20 ,0x1590,0x3c42 , + 0x1531,0x3c64 ,0x14d2,0x3c85 ,0x1473,0x3ca5 , + 0x1413,0x3cc5 ,0x13b4,0x3ce4 ,0x1354,0x3d03 , + 0x12f4,0x3d21 ,0x1294,0x3d3f ,0x1234,0x3d5b , + 0x11d3,0x3d78 ,0x1173,0x3d93 ,0x1112,0x3daf , + 0x10b1,0x3dc9 ,0x1050,0x3de3 ,0x0fee,0x3dfc , + 0x0f8d,0x3e15 ,0x0f2b,0x3e2d ,0x0eca,0x3e45 , + 0x0e68,0x3e5c ,0x0e06,0x3e72 ,0x0da4,0x3e88 , + 0x0d41,0x3e9d ,0x0cdf,0x3eb1 ,0x0c7c,0x3ec5 , + 0x0c1a,0x3ed8 ,0x0bb7,0x3eeb ,0x0b54,0x3efd , + 0x0af1,0x3f0f ,0x0a8e,0x3f20 ,0x0a2b,0x3f30 , + 0x09c7,0x3f40 ,0x0964,0x3f4f ,0x0901,0x3f5d , + 0x089d,0x3f6b ,0x0839,0x3f78 ,0x07d6,0x3f85 , + 0x0772,0x3f91 ,0x070e,0x3f9c ,0x06aa,0x3fa7 , + 0x0646,0x3fb1 ,0x05e2,0x3fbb ,0x057e,0x3fc4 , + 0x051a,0x3fcc ,0x04b5,0x3fd4 ,0x0451,0x3fdb , + 0x03ed,0x3fe1 ,0x0388,0x3fe7 ,0x0324,0x3fec , + 0x02c0,0x3ff1 ,0x025b,0x3ff5 ,0x01f7,0x3ff8 , + 0x0192,0x3ffb ,0x012e,0x3ffd ,0x00c9,0x3fff , + 0x0065,0x4000 ,0x0000,0x4000 ,0xff9b,0x4000 , + 0xff37,0x3fff ,0xfed2,0x3ffd ,0xfe6e,0x3ffb , + 0xfe09,0x3ff8 ,0xfda5,0x3ff5 ,0xfd40,0x3ff1 , + 0xfcdc,0x3fec ,0xfc78,0x3fe7 ,0xfc13,0x3fe1 , + 0xfbaf,0x3fdb ,0xfb4b,0x3fd4 ,0xfae6,0x3fcc , + 0xfa82,0x3fc4 ,0xfa1e,0x3fbb ,0xf9ba,0x3fb1 , + 0xf956,0x3fa7 ,0xf8f2,0x3f9c ,0xf88e,0x3f91 , + 0xf82a,0x3f85 ,0xf7c7,0x3f78 ,0xf763,0x3f6b , + 0xf6ff,0x3f5d ,0xf69c,0x3f4f ,0xf639,0x3f40 , + 0xf5d5,0x3f30 ,0xf572,0x3f20 ,0xf50f,0x3f0f , + 0xf4ac,0x3efd ,0xf449,0x3eeb ,0xf3e6,0x3ed8 , + 0xf384,0x3ec5 ,0xf321,0x3eb1 ,0xf2bf,0x3e9d , + 0xf25c,0x3e88 ,0xf1fa,0x3e72 ,0xf198,0x3e5c , + 0xf136,0x3e45 ,0xf0d5,0x3e2d ,0xf073,0x3e15 , + 0xf012,0x3dfc ,0xefb0,0x3de3 ,0xef4f,0x3dc9 , + 0xeeee,0x3daf ,0xee8d,0x3d93 ,0xee2d,0x3d78 , + 0xedcc,0x3d5b ,0xed6c,0x3d3f ,0xed0c,0x3d21 , + 0xecac,0x3d03 ,0xec4c,0x3ce4 ,0xebed,0x3cc5 , + 0xeb8d,0x3ca5 ,0xeb2e,0x3c85 ,0xeacf,0x3c64 , + 0xea70,0x3c42 ,0xea12,0x3c20 ,0xe9b4,0x3bfd , + 0xe955,0x3bda ,0xe8f7,0x3bb6 ,0xe89a,0x3b92 , + 0xe83c,0x3b6d ,0xe7df,0x3b47 ,0xe782,0x3b21 , + 0xe725,0x3afa ,0xe6c9,0x3ad3 ,0xe66d,0x3aab , + 0xe611,0x3a82 ,0xe5b5,0x3a59 ,0xe559,0x3a30 , + 0xe4fe,0x3a06 ,0xe4a3,0x39db ,0xe448,0x39b0 , + 0xe3ee,0x3984 ,0xe394,0x3958 ,0xe33a,0x392b , + 0xe2e0,0x38fd ,0xe287,0x38cf ,0xe22d,0x38a1 , + 0xe1d5,0x3871 ,0xe17c,0x3842 ,0xe124,0x3812 , + 0xe0cc,0x37e1 ,0xe074,0x37b0 ,0xe01d,0x377e , + 0xdfc6,0x374b ,0xdf6f,0x3718 ,0xdf19,0x36e5 , + 0xdec3,0x36b1 ,0xde6d,0x367d ,0xde18,0x3648 , + 0xddc3,0x3612 ,0xdd6e,0x35dc ,0xdd19,0x35a5 , + 0xdcc5,0x356e ,0xdc72,0x3537 ,0xdc1e,0x34ff , + 0xdbcb,0x34c6 ,0xdb78,0x348d ,0xdb26,0x3453 , + 0xdad4,0x3419 ,0xda82,0x33df ,0xda31,0x33a3 , + 0xd9e0,0x3368 ,0xd98f,0x332c ,0xd93f,0x32ef , + 0xd8ef,0x32b2 ,0xd8a0,0x3274 ,0xd851,0x3236 , + 0xd802,0x31f8 ,0xd7b4,0x31b9 ,0xd766,0x3179 , + 0xd719,0x3139 ,0xd6cb,0x30f9 ,0xd67f,0x30b8 , + 0xd632,0x3076 ,0xd5e6,0x3034 ,0xd59b,0x2ff2 , + 0xd550,0x2faf ,0xd505,0x2f6c ,0xd4bb,0x2f28 , + 0xd471,0x2ee4 ,0xd428,0x2e9f ,0xd3df,0x2e5a , + 0xd396,0x2e15 ,0xd34e,0x2dcf ,0xd306,0x2d88 , + 0xd2bf,0x2d41 ,0xd278,0x2cfa ,0xd231,0x2cb2 , + 0xd1eb,0x2c6a ,0xd1a6,0x2c21 ,0xd161,0x2bd8 , + 0xd11c,0x2b8f ,0xd0d8,0x2b45 ,0xd094,0x2afb , + 0xd051,0x2ab0 ,0xd00e,0x2a65 ,0xcfcc,0x2a1a , + 0xcf8a,0x29ce ,0xcf48,0x2981 ,0xcf07,0x2935 , + 0xcec7,0x28e7 ,0xce87,0x289a ,0xce47,0x284c , + 0xce08,0x27fe ,0xcdca,0x27af ,0xcd8c,0x2760 , + 0xcd4e,0x2711 ,0xcd11,0x26c1 ,0xccd4,0x2671 , + 0xcc98,0x2620 ,0xcc5d,0x25cf ,0xcc21,0x257e , + 0xcbe7,0x252c ,0xcbad,0x24da ,0xcb73,0x2488 , + 0xcb3a,0x2435 ,0xcb01,0x23e2 ,0xcac9,0x238e , + 0xca92,0x233b ,0xca5b,0x22e7 ,0xca24,0x2292 , + 0xc9ee,0x223d ,0xc9b8,0x21e8 ,0xc983,0x2193 , + 0xc94f,0x213d ,0xc91b,0x20e7 ,0xc8e8,0x2091 , + 0xc8b5,0x203a ,0xc882,0x1fe3 ,0xc850,0x1f8c , + 0xc81f,0x1f34 ,0xc7ee,0x1edc ,0xc7be,0x1e84 , + 0xc78f,0x1e2b ,0xc75f,0x1dd3 ,0xc731,0x1d79 , + 0xc703,0x1d20 ,0xc6d5,0x1cc6 ,0xc6a8,0x1c6c , + 0xc67c,0x1c12 ,0xc650,0x1bb8 ,0xc625,0x1b5d , + 0xc5fa,0x1b02 ,0xc5d0,0x1aa7 ,0xc5a7,0x1a4b , + 0xc57e,0x19ef ,0xc555,0x1993 ,0xc52d,0x1937 , + 0xc506,0x18db ,0xc4df,0x187e ,0xc4b9,0x1821 , + 0xc493,0x17c4 ,0xc46e,0x1766 ,0xc44a,0x1709 , + 0xc426,0x16ab ,0xc403,0x164c ,0xc3e0,0x15ee , + 0xc3be,0x1590 ,0xc39c,0x1531 ,0xc37b,0x14d2 , + 0xc35b,0x1473 ,0xc33b,0x1413 ,0xc31c,0x13b4 , + 0xc2fd,0x1354 ,0xc2df,0x12f4 ,0xc2c1,0x1294 , + 0xc2a5,0x1234 ,0xc288,0x11d3 ,0xc26d,0x1173 , + 0xc251,0x1112 ,0xc237,0x10b1 ,0xc21d,0x1050 , + 0xc204,0x0fee ,0xc1eb,0x0f8d ,0xc1d3,0x0f2b , + 0xc1bb,0x0eca ,0xc1a4,0x0e68 ,0xc18e,0x0e06 , + 0xc178,0x0da4 ,0xc163,0x0d41 ,0xc14f,0x0cdf , + 0xc13b,0x0c7c ,0xc128,0x0c1a ,0xc115,0x0bb7 , + 0xc103,0x0b54 ,0xc0f1,0x0af1 ,0xc0e0,0x0a8e , + 0xc0d0,0x0a2b ,0xc0c0,0x09c7 ,0xc0b1,0x0964 , + 0xc0a3,0x0901 ,0xc095,0x089d ,0xc088,0x0839 , + 0xc07b,0x07d6 ,0xc06f,0x0772 ,0xc064,0x070e , + 0xc059,0x06aa ,0xc04f,0x0646 ,0xc045,0x05e2 , + 0xc03c,0x057e ,0xc034,0x051a ,0xc02c,0x04b5 , + 0xc025,0x0451 ,0xc01f,0x03ed ,0xc019,0x0388 , + 0xc014,0x0324 ,0xc00f,0x02c0 ,0xc00b,0x025b , + 0xc008,0x01f7 ,0xc005,0x0192 ,0xc003,0x012e , + 0xc001,0x00c9 ,0xc000,0x0065 }; diff --git a/libs/miniwebrtc/audio/common/processing/webrtc_fft_t_rad.c b/libs/miniwebrtc/audio/common/processing/webrtc_fft_t_rad.c new file mode 100644 index 00000000..13fbd9f5 --- /dev/null +++ b/libs/miniwebrtc/audio/common/processing/webrtc_fft_t_rad.c @@ -0,0 +1,27 @@ +/* + * 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 contains the Q14 radix-2 tables used in ARM9E optimization routines. + * + */ + +extern const unsigned short t_Q14S_rad8[2]; +const unsigned short t_Q14S_rad8[2] = { 0x0000,0x2d41 }; + +//extern const int t_Q30S_rad8[2]; +//const int t_Q30S_rad8[2] = { 0x00000000,0x2d413ccd }; + +extern const unsigned short t_Q14R_rad8[2]; +const unsigned short t_Q14R_rad8[2] = { 0x2d41,0x2d41 }; + +//extern const int t_Q30R_rad8[2]; +//const int t_Q30R_rad8[2] = { 0x2d413ccd,0x2d413ccd }; diff --git a/libs/miniwebrtc/audio/common/resampler/resampler.cc b/libs/miniwebrtc/audio/common/resampler/resampler.cc new file mode 100644 index 00000000..2db27b1d --- /dev/null +++ b/libs/miniwebrtc/audio/common/resampler/resampler.cc @@ -0,0 +1,1084 @@ +/* + * 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. + */ + + +/* + * A wrapper for resampling a numerous amount of sampling combinations. + */ + +#include +#include + +#include "signal_processing_library.h" +#include "resampler.h" + + +namespace webrtc +{ + +Resampler::Resampler() +{ + state1_ = NULL; + state2_ = NULL; + state3_ = NULL; + in_buffer_ = NULL; + out_buffer_ = NULL; + in_buffer_size_ = 0; + out_buffer_size_ = 0; + in_buffer_size_max_ = 0; + out_buffer_size_max_ = 0; + // we need a reset before we will work + my_in_frequency_khz_ = 0; + my_out_frequency_khz_ = 0; + my_mode_ = kResamplerMode1To1; + my_type_ = kResamplerInvalid; + slave_left_ = NULL; + slave_right_ = NULL; +} + +Resampler::Resampler(int inFreq, int outFreq, ResamplerType type) +{ + state1_ = NULL; + state2_ = NULL; + state3_ = NULL; + in_buffer_ = NULL; + out_buffer_ = NULL; + in_buffer_size_ = 0; + out_buffer_size_ = 0; + in_buffer_size_max_ = 0; + out_buffer_size_max_ = 0; + // we need a reset before we will work + my_in_frequency_khz_ = 0; + my_out_frequency_khz_ = 0; + my_mode_ = kResamplerMode1To1; + my_type_ = kResamplerInvalid; + slave_left_ = NULL; + slave_right_ = NULL; + + Reset(inFreq, outFreq, type); +} + +Resampler::~Resampler() +{ + if (state1_) + { + free(state1_); + } + if (state2_) + { + free(state2_); + } + if (state3_) + { + free(state3_); + } + if (in_buffer_) + { + free(in_buffer_); + } + if (out_buffer_) + { + free(out_buffer_); + } + if (slave_left_) + { + delete slave_left_; + } + if (slave_right_) + { + delete slave_right_; + } +} + +int Resampler::ResetIfNeeded(int inFreq, int outFreq, ResamplerType type) +{ + int tmpInFreq_kHz = inFreq / 1000; + int tmpOutFreq_kHz = outFreq / 1000; + + if ((tmpInFreq_kHz != my_in_frequency_khz_) || (tmpOutFreq_kHz != my_out_frequency_khz_) + || (type != my_type_)) + { + return Reset(inFreq, outFreq, type); + } else + { + return 0; + } +} + +int Resampler::Reset(int inFreq, int outFreq, ResamplerType type) +{ + + if (state1_) + { + free(state1_); + state1_ = NULL; + } + if (state2_) + { + free(state2_); + state2_ = NULL; + } + if (state3_) + { + free(state3_); + state3_ = NULL; + } + if (in_buffer_) + { + free(in_buffer_); + in_buffer_ = NULL; + } + if (out_buffer_) + { + free(out_buffer_); + out_buffer_ = NULL; + } + if (slave_left_) + { + delete slave_left_; + slave_left_ = NULL; + } + if (slave_right_) + { + delete slave_right_; + slave_right_ = NULL; + } + + in_buffer_size_ = 0; + out_buffer_size_ = 0; + in_buffer_size_max_ = 0; + out_buffer_size_max_ = 0; + + // This might be overridden if parameters are not accepted. + my_type_ = type; + + // Start with a math exercise, Euclid's algorithm to find the gcd: + + int a = inFreq; + int b = outFreq; + int c = a % b; + while (c != 0) + { + a = b; + b = c; + c = a % b; + } + // b is now the gcd; + + // We need to track what domain we're in. + my_in_frequency_khz_ = inFreq / 1000; + my_out_frequency_khz_ = outFreq / 1000; + + // Scale with GCD + inFreq = inFreq / b; + outFreq = outFreq / b; + + // Do we need stereo? + if ((my_type_ & 0xf0) == 0x20) + { + // Change type to mono + type = static_cast( + ((static_cast(type) & 0x0f) + 0x10)); + slave_left_ = new Resampler(inFreq, outFreq, type); + slave_right_ = new Resampler(inFreq, outFreq, type); + } + + if (inFreq == outFreq) + { + my_mode_ = kResamplerMode1To1; + } else if (inFreq == 1) + { + switch (outFreq) + { + case 2: + my_mode_ = kResamplerMode1To2; + break; + case 3: + my_mode_ = kResamplerMode1To3; + break; + case 4: + my_mode_ = kResamplerMode1To4; + break; + case 6: + my_mode_ = kResamplerMode1To6; + break; + case 12: + my_mode_ = kResamplerMode1To12; + break; + default: + my_type_ = kResamplerInvalid; + return -1; + } + } else if (outFreq == 1) + { + switch (inFreq) + { + case 2: + my_mode_ = kResamplerMode2To1; + break; + case 3: + my_mode_ = kResamplerMode3To1; + break; + case 4: + my_mode_ = kResamplerMode4To1; + break; + case 6: + my_mode_ = kResamplerMode6To1; + break; + case 12: + my_mode_ = kResamplerMode12To1; + break; + default: + my_type_ = kResamplerInvalid; + return -1; + } + } else if ((inFreq == 2) && (outFreq == 3)) + { + my_mode_ = kResamplerMode2To3; + } else if ((inFreq == 2) && (outFreq == 11)) + { + my_mode_ = kResamplerMode2To11; + } else if ((inFreq == 4) && (outFreq == 11)) + { + my_mode_ = kResamplerMode4To11; + } else if ((inFreq == 8) && (outFreq == 11)) + { + my_mode_ = kResamplerMode8To11; + } else if ((inFreq == 3) && (outFreq == 2)) + { + my_mode_ = kResamplerMode3To2; + } else if ((inFreq == 11) && (outFreq == 2)) + { + my_mode_ = kResamplerMode11To2; + } else if ((inFreq == 11) && (outFreq == 4)) + { + my_mode_ = kResamplerMode11To4; + } else if ((inFreq == 11) && (outFreq == 16)) + { + my_mode_ = kResamplerMode11To16; + } else if ((inFreq == 11) && (outFreq == 32)) + { + my_mode_ = kResamplerMode11To32; + } else if ((inFreq == 11) && (outFreq == 8)) + { + my_mode_ = kResamplerMode11To8; + } else + { + my_type_ = kResamplerInvalid; + return -1; + } + + // Now create the states we need + switch (my_mode_) + { + case kResamplerMode1To1: + // No state needed; + break; + case kResamplerMode1To2: + state1_ = malloc(8 * sizeof(WebRtc_Word32)); + memset(state1_, 0, 8 * sizeof(WebRtc_Word32)); + break; + case kResamplerMode1To3: + state1_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz)); + WebRtcSpl_ResetResample16khzTo48khz((WebRtcSpl_State16khzTo48khz *)state1_); + break; + case kResamplerMode1To4: + // 1:2 + state1_ = malloc(8 * sizeof(WebRtc_Word32)); + memset(state1_, 0, 8 * sizeof(WebRtc_Word32)); + // 2:4 + state2_ = malloc(8 * sizeof(WebRtc_Word32)); + memset(state2_, 0, 8 * sizeof(WebRtc_Word32)); + break; + case kResamplerMode1To6: + // 1:2 + state1_ = malloc(8 * sizeof(WebRtc_Word32)); + memset(state1_, 0, 8 * sizeof(WebRtc_Word32)); + // 2:6 + state2_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz)); + WebRtcSpl_ResetResample16khzTo48khz((WebRtcSpl_State16khzTo48khz *)state2_); + break; + case kResamplerMode1To12: + // 1:2 + state1_ = malloc(8 * sizeof(WebRtc_Word32)); + memset(state1_, 0, 8 * sizeof(WebRtc_Word32)); + // 2:4 + state2_ = malloc(8 * sizeof(WebRtc_Word32)); + memset(state2_, 0, 8 * sizeof(WebRtc_Word32)); + // 4:12 + state3_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz)); + WebRtcSpl_ResetResample16khzTo48khz( + (WebRtcSpl_State16khzTo48khz*) state3_); + break; + case kResamplerMode2To3: + // 2:6 + state1_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz)); + WebRtcSpl_ResetResample16khzTo48khz((WebRtcSpl_State16khzTo48khz *)state1_); + // 6:3 + state2_ = malloc(8 * sizeof(WebRtc_Word32)); + memset(state2_, 0, 8 * sizeof(WebRtc_Word32)); + break; + case kResamplerMode2To11: + state1_ = malloc(8 * sizeof(WebRtc_Word32)); + memset(state1_, 0, 8 * sizeof(WebRtc_Word32)); + + state2_ = malloc(sizeof(WebRtcSpl_State8khzTo22khz)); + WebRtcSpl_ResetResample8khzTo22khz((WebRtcSpl_State8khzTo22khz *)state2_); + break; + case kResamplerMode4To11: + state1_ = malloc(sizeof(WebRtcSpl_State8khzTo22khz)); + WebRtcSpl_ResetResample8khzTo22khz((WebRtcSpl_State8khzTo22khz *)state1_); + break; + case kResamplerMode8To11: + state1_ = malloc(sizeof(WebRtcSpl_State16khzTo22khz)); + WebRtcSpl_ResetResample16khzTo22khz((WebRtcSpl_State16khzTo22khz *)state1_); + break; + case kResamplerMode11To16: + state1_ = malloc(8 * sizeof(WebRtc_Word32)); + memset(state1_, 0, 8 * sizeof(WebRtc_Word32)); + + state2_ = malloc(sizeof(WebRtcSpl_State22khzTo16khz)); + WebRtcSpl_ResetResample22khzTo16khz((WebRtcSpl_State22khzTo16khz *)state2_); + break; + case kResamplerMode11To32: + // 11 -> 22 + state1_ = malloc(8 * sizeof(WebRtc_Word32)); + memset(state1_, 0, 8 * sizeof(WebRtc_Word32)); + + // 22 -> 16 + state2_ = malloc(sizeof(WebRtcSpl_State22khzTo16khz)); + WebRtcSpl_ResetResample22khzTo16khz((WebRtcSpl_State22khzTo16khz *)state2_); + + // 16 -> 32 + state3_ = malloc(8 * sizeof(WebRtc_Word32)); + memset(state3_, 0, 8 * sizeof(WebRtc_Word32)); + + break; + case kResamplerMode2To1: + state1_ = malloc(8 * sizeof(WebRtc_Word32)); + memset(state1_, 0, 8 * sizeof(WebRtc_Word32)); + break; + case kResamplerMode3To1: + state1_ = malloc(sizeof(WebRtcSpl_State48khzTo16khz)); + WebRtcSpl_ResetResample48khzTo16khz((WebRtcSpl_State48khzTo16khz *)state1_); + break; + case kResamplerMode4To1: + // 4:2 + state1_ = malloc(8 * sizeof(WebRtc_Word32)); + memset(state1_, 0, 8 * sizeof(WebRtc_Word32)); + // 2:1 + state2_ = malloc(8 * sizeof(WebRtc_Word32)); + memset(state2_, 0, 8 * sizeof(WebRtc_Word32)); + break; + case kResamplerMode6To1: + // 6:2 + state1_ = malloc(sizeof(WebRtcSpl_State48khzTo16khz)); + WebRtcSpl_ResetResample48khzTo16khz((WebRtcSpl_State48khzTo16khz *)state1_); + // 2:1 + state2_ = malloc(8 * sizeof(WebRtc_Word32)); + memset(state2_, 0, 8 * sizeof(WebRtc_Word32)); + break; + case kResamplerMode12To1: + // 12:4 + state1_ = malloc(sizeof(WebRtcSpl_State48khzTo16khz)); + WebRtcSpl_ResetResample48khzTo16khz( + (WebRtcSpl_State48khzTo16khz*) state1_); + // 4:2 + state2_ = malloc(8 * sizeof(WebRtc_Word32)); + memset(state2_, 0, 8 * sizeof(WebRtc_Word32)); + // 2:1 + state3_ = malloc(8 * sizeof(WebRtc_Word32)); + memset(state3_, 0, 8 * sizeof(WebRtc_Word32)); + break; + case kResamplerMode3To2: + // 3:6 + state1_ = malloc(8 * sizeof(WebRtc_Word32)); + memset(state1_, 0, 8 * sizeof(WebRtc_Word32)); + // 6:2 + state2_ = malloc(sizeof(WebRtcSpl_State48khzTo16khz)); + WebRtcSpl_ResetResample48khzTo16khz((WebRtcSpl_State48khzTo16khz *)state2_); + break; + case kResamplerMode11To2: + state1_ = malloc(sizeof(WebRtcSpl_State22khzTo8khz)); + WebRtcSpl_ResetResample22khzTo8khz((WebRtcSpl_State22khzTo8khz *)state1_); + + state2_ = malloc(8 * sizeof(WebRtc_Word32)); + memset(state2_, 0, 8 * sizeof(WebRtc_Word32)); + + break; + case kResamplerMode11To4: + state1_ = malloc(sizeof(WebRtcSpl_State22khzTo8khz)); + WebRtcSpl_ResetResample22khzTo8khz((WebRtcSpl_State22khzTo8khz *)state1_); + break; + case kResamplerMode11To8: + state1_ = malloc(sizeof(WebRtcSpl_State22khzTo16khz)); + WebRtcSpl_ResetResample22khzTo16khz((WebRtcSpl_State22khzTo16khz *)state1_); + break; + + } + + return 0; +} + +// Synchronous resampling, all output samples are written to samplesOut +int Resampler::Push(const WebRtc_Word16 * samplesIn, int lengthIn, WebRtc_Word16* samplesOut, + int maxLen, int &outLen) +{ + // Check that the resampler is not in asynchronous mode + if (my_type_ & 0x0f) + { + return -1; + } + + // Do we have a stereo signal? + if ((my_type_ & 0xf0) == 0x20) + { + + // Split up the signal and call the slave object for each channel + + WebRtc_Word16* left = (WebRtc_Word16*)malloc(lengthIn * sizeof(WebRtc_Word16) / 2); + WebRtc_Word16* right = (WebRtc_Word16*)malloc(lengthIn * sizeof(WebRtc_Word16) / 2); + WebRtc_Word16* out_left = (WebRtc_Word16*)malloc(maxLen / 2 * sizeof(WebRtc_Word16)); + WebRtc_Word16* out_right = + (WebRtc_Word16*)malloc(maxLen / 2 * sizeof(WebRtc_Word16)); + int res = 0; + for (int i = 0; i < lengthIn; i += 2) + { + left[i >> 1] = samplesIn[i]; + right[i >> 1] = samplesIn[i + 1]; + } + + // It's OK to overwrite the local parameter, since it's just a copy + lengthIn = lengthIn / 2; + + int actualOutLen_left = 0; + int actualOutLen_right = 0; + // Do resampling for right channel + res |= slave_left_->Push(left, lengthIn, out_left, maxLen / 2, actualOutLen_left); + res |= slave_right_->Push(right, lengthIn, out_right, maxLen / 2, actualOutLen_right); + if (res || (actualOutLen_left != actualOutLen_right)) + { + free(left); + free(right); + free(out_left); + free(out_right); + return -1; + } + + // Reassemble the signal + for (int i = 0; i < actualOutLen_left; i++) + { + samplesOut[i * 2] = out_left[i]; + samplesOut[i * 2 + 1] = out_right[i]; + } + outLen = 2 * actualOutLen_left; + + free(left); + free(right); + free(out_left); + free(out_right); + + return 0; + } + + // Containers for temp samples + WebRtc_Word16* tmp; + WebRtc_Word16* tmp_2; + // tmp data for resampling routines + WebRtc_Word32* tmp_mem; + + switch (my_mode_) + { + case kResamplerMode1To1: + memcpy(samplesOut, samplesIn, lengthIn * sizeof(WebRtc_Word16)); + outLen = lengthIn; + break; + case kResamplerMode1To2: + if (maxLen < (lengthIn * 2)) + { + return -1; + } + WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, samplesOut, (WebRtc_Word32*)state1_); + outLen = lengthIn * 2; + return 0; + case kResamplerMode1To3: + + // We can only handle blocks of 160 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 160) != 0) + { + return -1; + } + if (maxLen < (lengthIn * 3)) + { + return -1; + } + tmp_mem = (WebRtc_Word32*)malloc(336 * sizeof(WebRtc_Word32)); + + for (int i = 0; i < lengthIn; i += 160) + { + WebRtcSpl_Resample16khzTo48khz(samplesIn + i, samplesOut + i * 3, + (WebRtcSpl_State16khzTo48khz *)state1_, + tmp_mem); + } + outLen = lengthIn * 3; + free(tmp_mem); + return 0; + case kResamplerMode1To4: + if (maxLen < (lengthIn * 4)) + { + return -1; + } + + tmp = (WebRtc_Word16*)malloc(sizeof(WebRtc_Word16) * 2 * lengthIn); + // 1:2 + WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, (WebRtc_Word32*)state1_); + // 2:4 + WebRtcSpl_UpsampleBy2(tmp, lengthIn * 2, samplesOut, (WebRtc_Word32*)state2_); + outLen = lengthIn * 4; + free(tmp); + return 0; + case kResamplerMode1To6: + // We can only handle blocks of 80 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 80) != 0) + { + return -1; + } + if (maxLen < (lengthIn * 6)) + { + return -1; + } + + //1:2 + + tmp_mem = (WebRtc_Word32*)malloc(336 * sizeof(WebRtc_Word32)); + tmp = (WebRtc_Word16*)malloc(sizeof(WebRtc_Word16) * 2 * lengthIn); + + WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, (WebRtc_Word32*)state1_); + outLen = lengthIn * 2; + + for (int i = 0; i < outLen; i += 160) + { + WebRtcSpl_Resample16khzTo48khz(tmp + i, samplesOut + i * 3, + (WebRtcSpl_State16khzTo48khz *)state2_, + tmp_mem); + } + outLen = outLen * 3; + free(tmp_mem); + free(tmp); + + return 0; + case kResamplerMode1To12: + // We can only handle blocks of 40 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 40) != 0) { + return -1; + } + if (maxLen < (lengthIn * 12)) { + return -1; + } + + tmp_mem = (WebRtc_Word32*) malloc(336 * sizeof(WebRtc_Word32)); + tmp = (WebRtc_Word16*) malloc(sizeof(WebRtc_Word16) * 4 * lengthIn); + //1:2 + WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, samplesOut, + (WebRtc_Word32*) state1_); + outLen = lengthIn * 2; + //2:4 + WebRtcSpl_UpsampleBy2(samplesOut, outLen, tmp, (WebRtc_Word32*) state2_); + outLen = outLen * 2; + // 4:12 + for (int i = 0; i < outLen; i += 160) { + // WebRtcSpl_Resample16khzTo48khz() takes a block of 160 samples + // as input and outputs a resampled block of 480 samples. The + // data is now actually in 32 kHz sampling rate, despite the + // function name, and with a resampling factor of three becomes + // 96 kHz. + WebRtcSpl_Resample16khzTo48khz(tmp + i, samplesOut + i * 3, + (WebRtcSpl_State16khzTo48khz*) state3_, + tmp_mem); + } + outLen = outLen * 3; + free(tmp_mem); + free(tmp); + + return 0; + case kResamplerMode2To3: + if (maxLen < (lengthIn * 3 / 2)) + { + return -1; + } + // 2:6 + // We can only handle blocks of 160 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 160) != 0) + { + return -1; + } + tmp = static_cast (malloc(sizeof(WebRtc_Word16) * lengthIn * 3)); + tmp_mem = (WebRtc_Word32*)malloc(336 * sizeof(WebRtc_Word32)); + for (int i = 0; i < lengthIn; i += 160) + { + WebRtcSpl_Resample16khzTo48khz(samplesIn + i, tmp + i * 3, + (WebRtcSpl_State16khzTo48khz *)state1_, + tmp_mem); + } + lengthIn = lengthIn * 3; + // 6:3 + WebRtcSpl_DownsampleBy2(tmp, lengthIn, samplesOut, (WebRtc_Word32*)state2_); + outLen = lengthIn / 2; + free(tmp); + free(tmp_mem); + return 0; + case kResamplerMode2To11: + + // We can only handle blocks of 80 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 80) != 0) + { + return -1; + } + if (maxLen < ((lengthIn * 11) / 2)) + { + return -1; + } + tmp = (WebRtc_Word16*)malloc(sizeof(WebRtc_Word16) * 2 * lengthIn); + // 1:2 + WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, (WebRtc_Word32*)state1_); + lengthIn *= 2; + + tmp_mem = (WebRtc_Word32*)malloc(98 * sizeof(WebRtc_Word32)); + + for (int i = 0; i < lengthIn; i += 80) + { + WebRtcSpl_Resample8khzTo22khz(tmp + i, samplesOut + (i * 11) / 4, + (WebRtcSpl_State8khzTo22khz *)state2_, + tmp_mem); + } + outLen = (lengthIn * 11) / 4; + free(tmp_mem); + free(tmp); + return 0; + case kResamplerMode4To11: + + // We can only handle blocks of 80 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 80) != 0) + { + return -1; + } + if (maxLen < ((lengthIn * 11) / 4)) + { + return -1; + } + tmp_mem = (WebRtc_Word32*)malloc(98 * sizeof(WebRtc_Word32)); + + for (int i = 0; i < lengthIn; i += 80) + { + WebRtcSpl_Resample8khzTo22khz(samplesIn + i, samplesOut + (i * 11) / 4, + (WebRtcSpl_State8khzTo22khz *)state1_, + tmp_mem); + } + outLen = (lengthIn * 11) / 4; + free(tmp_mem); + return 0; + case kResamplerMode8To11: + // We can only handle blocks of 160 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 160) != 0) + { + return -1; + } + if (maxLen < ((lengthIn * 11) / 8)) + { + return -1; + } + tmp_mem = (WebRtc_Word32*)malloc(88 * sizeof(WebRtc_Word32)); + + for (int i = 0; i < lengthIn; i += 160) + { + WebRtcSpl_Resample16khzTo22khz(samplesIn + i, samplesOut + (i * 11) / 8, + (WebRtcSpl_State16khzTo22khz *)state1_, + tmp_mem); + } + outLen = (lengthIn * 11) / 8; + free(tmp_mem); + return 0; + + case kResamplerMode11To16: + // We can only handle blocks of 110 samples + if ((lengthIn % 110) != 0) + { + return -1; + } + if (maxLen < ((lengthIn * 16) / 11)) + { + return -1; + } + + tmp_mem = (WebRtc_Word32*)malloc(104 * sizeof(WebRtc_Word32)); + tmp = (WebRtc_Word16*)malloc((sizeof(WebRtc_Word16) * lengthIn * 2)); + + WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, (WebRtc_Word32*)state1_); + + for (int i = 0; i < (lengthIn * 2); i += 220) + { + WebRtcSpl_Resample22khzTo16khz(tmp + i, samplesOut + (i / 220) * 160, + (WebRtcSpl_State22khzTo16khz *)state2_, + tmp_mem); + } + + outLen = (lengthIn * 16) / 11; + + free(tmp_mem); + free(tmp); + return 0; + + case kResamplerMode11To32: + + // We can only handle blocks of 110 samples + if ((lengthIn % 110) != 0) + { + return -1; + } + if (maxLen < ((lengthIn * 32) / 11)) + { + return -1; + } + + tmp_mem = (WebRtc_Word32*)malloc(104 * sizeof(WebRtc_Word32)); + tmp = (WebRtc_Word16*)malloc((sizeof(WebRtc_Word16) * lengthIn * 2)); + + // 11 -> 22 kHz in samplesOut + WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, samplesOut, (WebRtc_Word32*)state1_); + + // 22 -> 16 in tmp + for (int i = 0; i < (lengthIn * 2); i += 220) + { + WebRtcSpl_Resample22khzTo16khz(samplesOut + i, tmp + (i / 220) * 160, + (WebRtcSpl_State22khzTo16khz *)state2_, + tmp_mem); + } + + // 16 -> 32 in samplesOut + WebRtcSpl_UpsampleBy2(tmp, (lengthIn * 16) / 11, samplesOut, + (WebRtc_Word32*)state3_); + + outLen = (lengthIn * 32) / 11; + + free(tmp_mem); + free(tmp); + return 0; + + case kResamplerMode2To1: + if (maxLen < (lengthIn / 2)) + { + return -1; + } + WebRtcSpl_DownsampleBy2(samplesIn, lengthIn, samplesOut, (WebRtc_Word32*)state1_); + outLen = lengthIn / 2; + return 0; + case kResamplerMode3To1: + // We can only handle blocks of 480 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 480) != 0) + { + return -1; + } + if (maxLen < (lengthIn / 3)) + { + return -1; + } + tmp_mem = (WebRtc_Word32*)malloc(496 * sizeof(WebRtc_Word32)); + + for (int i = 0; i < lengthIn; i += 480) + { + WebRtcSpl_Resample48khzTo16khz(samplesIn + i, samplesOut + i / 3, + (WebRtcSpl_State48khzTo16khz *)state1_, + tmp_mem); + } + outLen = lengthIn / 3; + free(tmp_mem); + return 0; + case kResamplerMode4To1: + if (maxLen < (lengthIn / 4)) + { + return -1; + } + tmp = (WebRtc_Word16*)malloc(sizeof(WebRtc_Word16) * lengthIn / 2); + // 4:2 + WebRtcSpl_DownsampleBy2(samplesIn, lengthIn, tmp, (WebRtc_Word32*)state1_); + // 2:1 + WebRtcSpl_DownsampleBy2(tmp, lengthIn / 2, samplesOut, (WebRtc_Word32*)state2_); + outLen = lengthIn / 4; + free(tmp); + return 0; + + case kResamplerMode6To1: + // We can only handle blocks of 480 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 480) != 0) + { + return -1; + } + if (maxLen < (lengthIn / 6)) + { + return -1; + } + + tmp_mem = (WebRtc_Word32*)malloc(496 * sizeof(WebRtc_Word32)); + tmp = (WebRtc_Word16*)malloc((sizeof(WebRtc_Word16) * lengthIn) / 3); + + for (int i = 0; i < lengthIn; i += 480) + { + WebRtcSpl_Resample48khzTo16khz(samplesIn + i, tmp + i / 3, + (WebRtcSpl_State48khzTo16khz *)state1_, + tmp_mem); + } + outLen = lengthIn / 3; + free(tmp_mem); + WebRtcSpl_DownsampleBy2(tmp, outLen, samplesOut, (WebRtc_Word32*)state2_); + free(tmp); + outLen = outLen / 2; + return 0; + case kResamplerMode12To1: + // We can only handle blocks of 480 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 480) != 0) { + return -1; + } + if (maxLen < (lengthIn / 12)) { + return -1; + } + + tmp_mem = (WebRtc_Word32*) malloc(496 * sizeof(WebRtc_Word32)); + tmp = (WebRtc_Word16*) malloc((sizeof(WebRtc_Word16) * lengthIn) / 3); + tmp_2 = (WebRtc_Word16*) malloc((sizeof(WebRtc_Word16) * lengthIn) / 6); + // 12:4 + for (int i = 0; i < lengthIn; i += 480) { + // WebRtcSpl_Resample48khzTo16khz() takes a block of 480 samples + // as input and outputs a resampled block of 160 samples. The + // data is now actually in 96 kHz sampling rate, despite the + // function name, and with a resampling factor of 1/3 becomes + // 32 kHz. + WebRtcSpl_Resample48khzTo16khz(samplesIn + i, tmp + i / 3, + (WebRtcSpl_State48khzTo16khz*) state1_, + tmp_mem); + } + outLen = lengthIn / 3; + free(tmp_mem); + // 4:2 + WebRtcSpl_DownsampleBy2(tmp, outLen, tmp_2, + (WebRtc_Word32*) state2_); + outLen = outLen / 2; + free(tmp); + // 2:1 + WebRtcSpl_DownsampleBy2(tmp_2, outLen, samplesOut, + (WebRtc_Word32*) state3_); + free(tmp_2); + outLen = outLen / 2; + return 0; + case kResamplerMode3To2: + if (maxLen < (lengthIn * 2 / 3)) + { + return -1; + } + // 3:6 + tmp = static_cast (malloc(sizeof(WebRtc_Word16) * lengthIn * 2)); + WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, (WebRtc_Word32*)state1_); + lengthIn *= 2; + // 6:2 + // We can only handle blocks of 480 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 480) != 0) + { + free(tmp); + return -1; + } + tmp_mem = (WebRtc_Word32*)malloc(496 * sizeof(WebRtc_Word32)); + for (int i = 0; i < lengthIn; i += 480) + { + WebRtcSpl_Resample48khzTo16khz(tmp + i, samplesOut + i / 3, + (WebRtcSpl_State48khzTo16khz *)state2_, + tmp_mem); + } + outLen = lengthIn / 3; + free(tmp); + free(tmp_mem); + return 0; + case kResamplerMode11To2: + // We can only handle blocks of 220 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 220) != 0) + { + return -1; + } + if (maxLen < ((lengthIn * 2) / 11)) + { + return -1; + } + tmp_mem = (WebRtc_Word32*)malloc(126 * sizeof(WebRtc_Word32)); + tmp = (WebRtc_Word16*)malloc((lengthIn * 4) / 11 * sizeof(WebRtc_Word16)); + + for (int i = 0; i < lengthIn; i += 220) + { + WebRtcSpl_Resample22khzTo8khz(samplesIn + i, tmp + (i * 4) / 11, + (WebRtcSpl_State22khzTo8khz *)state1_, + tmp_mem); + } + lengthIn = (lengthIn * 4) / 11; + + WebRtcSpl_DownsampleBy2(tmp, lengthIn, samplesOut, (WebRtc_Word32*)state2_); + outLen = lengthIn / 2; + + free(tmp_mem); + free(tmp); + return 0; + case kResamplerMode11To4: + // We can only handle blocks of 220 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 220) != 0) + { + return -1; + } + if (maxLen < ((lengthIn * 4) / 11)) + { + return -1; + } + tmp_mem = (WebRtc_Word32*)malloc(126 * sizeof(WebRtc_Word32)); + + for (int i = 0; i < lengthIn; i += 220) + { + WebRtcSpl_Resample22khzTo8khz(samplesIn + i, samplesOut + (i * 4) / 11, + (WebRtcSpl_State22khzTo8khz *)state1_, + tmp_mem); + } + outLen = (lengthIn * 4) / 11; + free(tmp_mem); + return 0; + case kResamplerMode11To8: + // We can only handle blocks of 160 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 220) != 0) + { + return -1; + } + if (maxLen < ((lengthIn * 8) / 11)) + { + return -1; + } + tmp_mem = (WebRtc_Word32*)malloc(104 * sizeof(WebRtc_Word32)); + + for (int i = 0; i < lengthIn; i += 220) + { + WebRtcSpl_Resample22khzTo16khz(samplesIn + i, samplesOut + (i * 8) / 11, + (WebRtcSpl_State22khzTo16khz *)state1_, + tmp_mem); + } + outLen = (lengthIn * 8) / 11; + free(tmp_mem); + return 0; + break; + + } + return 0; +} + +// Asynchronous resampling, input +int Resampler::Insert(WebRtc_Word16 * samplesIn, int lengthIn) +{ + if (my_type_ != kResamplerAsynchronous) + { + return -1; + } + int sizeNeeded, tenMsblock; + + // Determine need for size of outBuffer + sizeNeeded = out_buffer_size_ + ((lengthIn + in_buffer_size_) * my_out_frequency_khz_) + / my_in_frequency_khz_; + if (sizeNeeded > out_buffer_size_max_) + { + // Round the value upwards to complete 10 ms blocks + tenMsblock = my_out_frequency_khz_ * 10; + sizeNeeded = (sizeNeeded / tenMsblock + 1) * tenMsblock; + out_buffer_ = (WebRtc_Word16*)realloc(out_buffer_, sizeNeeded * sizeof(WebRtc_Word16)); + out_buffer_size_max_ = sizeNeeded; + } + + // If we need to use inBuffer, make sure all input data fits there. + + tenMsblock = my_in_frequency_khz_ * 10; + if (in_buffer_size_ || (lengthIn % tenMsblock)) + { + // Check if input buffer size is enough + if ((in_buffer_size_ + lengthIn) > in_buffer_size_max_) + { + // Round the value upwards to complete 10 ms blocks + sizeNeeded = ((in_buffer_size_ + lengthIn) / tenMsblock + 1) * tenMsblock; + in_buffer_ = (WebRtc_Word16*)realloc(in_buffer_, + sizeNeeded * sizeof(WebRtc_Word16)); + in_buffer_size_max_ = sizeNeeded; + } + // Copy in data to input buffer + memcpy(in_buffer_ + in_buffer_size_, samplesIn, lengthIn * sizeof(WebRtc_Word16)); + + // Resample all available 10 ms blocks + int lenOut; + int dataLenToResample = (in_buffer_size_ / tenMsblock) * tenMsblock; + Push(in_buffer_, dataLenToResample, out_buffer_ + out_buffer_size_, + out_buffer_size_max_ - out_buffer_size_, lenOut); + out_buffer_size_ += lenOut; + + // Save the rest + memmove(in_buffer_, in_buffer_ + dataLenToResample, + (in_buffer_size_ - dataLenToResample) * sizeof(WebRtc_Word16)); + in_buffer_size_ -= dataLenToResample; + } else + { + // Just resample + int lenOut; + Push(in_buffer_, lengthIn, out_buffer_ + out_buffer_size_, + out_buffer_size_max_ - out_buffer_size_, lenOut); + out_buffer_size_ += lenOut; + } + + return 0; +} + +// Asynchronous resampling output, remaining samples are buffered +int Resampler::Pull(WebRtc_Word16* samplesOut, int desiredLen, int &outLen) +{ + if (my_type_ != kResamplerAsynchronous) + { + return -1; + } + + // Check that we have enough data + if (desiredLen <= out_buffer_size_) + { + // Give out the date + memcpy(samplesOut, out_buffer_, desiredLen * sizeof(WebRtc_Word32)); + + // Shuffle down remaining + memmove(out_buffer_, out_buffer_ + desiredLen, + (out_buffer_size_ - desiredLen) * sizeof(WebRtc_Word16)); + + // Update remaining size + out_buffer_size_ -= desiredLen; + + return 0; + } else + { + return -1; + } +} + +} // namespace webrtc diff --git a/libs/miniwebrtc/audio/common/resampler/resampler.h b/libs/miniwebrtc/audio/common/resampler/resampler.h new file mode 100644 index 00000000..38e6bd35 --- /dev/null +++ b/libs/miniwebrtc/audio/common/resampler/resampler.h @@ -0,0 +1,116 @@ +/* + * 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. + */ + + +/* + * A wrapper for resampling a numerous amount of sampling combinations. + */ + +#ifndef WEBRTC_RESAMPLER_RESAMPLER_H_ +#define WEBRTC_RESAMPLER_RESAMPLER_H_ + +#include "typedefs.h" + +namespace webrtc +{ + +// TODO(andrew): the implementation depends on the exact values of this enum. +// It should be rewritten in a less fragile way. +enum ResamplerType +{ + // 4 MSB = Number of channels + // 4 LSB = Synchronous or asynchronous + + kResamplerSynchronous = 0x10, + kResamplerAsynchronous = 0x11, + kResamplerSynchronousStereo = 0x20, + kResamplerAsynchronousStereo = 0x21, + kResamplerInvalid = 0xff +}; + +// TODO(andrew): doesn't need to be part of the interface. +enum ResamplerMode +{ + kResamplerMode1To1, + kResamplerMode1To2, + kResamplerMode1To3, + kResamplerMode1To4, + kResamplerMode1To6, + kResamplerMode1To12, + kResamplerMode2To3, + kResamplerMode2To11, + kResamplerMode4To11, + kResamplerMode8To11, + kResamplerMode11To16, + kResamplerMode11To32, + kResamplerMode2To1, + kResamplerMode3To1, + kResamplerMode4To1, + kResamplerMode6To1, + kResamplerMode12To1, + kResamplerMode3To2, + kResamplerMode11To2, + kResamplerMode11To4, + kResamplerMode11To8 +}; + +class Resampler +{ + +public: + Resampler(); + // TODO(andrew): use an init function instead. + Resampler(int inFreq, int outFreq, ResamplerType type); + ~Resampler(); + + // Reset all states + int Reset(int inFreq, int outFreq, ResamplerType type); + + // Reset all states if any parameter has changed + int ResetIfNeeded(int inFreq, int outFreq, ResamplerType type); + + // Synchronous resampling, all output samples are written to samplesOut + int Push(const WebRtc_Word16* samplesIn, int lengthIn, WebRtc_Word16* samplesOut, + int maxLen, int &outLen); + + // Asynchronous resampling, input + int Insert(WebRtc_Word16* samplesIn, int lengthIn); + + // Asynchronous resampling output, remaining samples are buffered + int Pull(WebRtc_Word16* samplesOut, int desiredLen, int &outLen); + +private: + // Generic pointers since we don't know what states we'll need + void* state1_; + void* state2_; + void* state3_; + + // Storage if needed + WebRtc_Word16* in_buffer_; + WebRtc_Word16* out_buffer_; + int in_buffer_size_; + int out_buffer_size_; + int in_buffer_size_max_; + int out_buffer_size_max_; + + // State + int my_in_frequency_khz_; + int my_out_frequency_khz_; + ResamplerMode my_mode_; + ResamplerType my_type_; + + // Extra instance for stereo + Resampler* slave_left_; + Resampler* slave_right_; +}; + +} // namespace webrtc + +#endif // WEBRTC_RESAMPLER_RESAMPLER_H_ diff --git a/libs/miniwebrtc/audio/common/vad/vad_core.c b/libs/miniwebrtc/audio/common/vad/vad_core.c new file mode 100644 index 00000000..2c6e6a95 --- /dev/null +++ b/libs/miniwebrtc/audio/common/vad/vad_core.c @@ -0,0 +1,663 @@ +/* + * 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 "vad_core.h" + +#include "signal_processing_library.h" +#include "typedefs.h" +#include "vad_defines.h" +#include "vad_filterbank.h" +#include "vad_gmm.h" +#include "vad_sp.h" + +// Spectrum Weighting +static const WebRtc_Word16 kSpectrumWeight[6] = { 6, 8, 10, 12, 14, 16 }; +static const WebRtc_Word16 kNoiseUpdateConst = 655; // Q15 +static const WebRtc_Word16 kSpeechUpdateConst = 6554; // Q15 +static const WebRtc_Word16 kBackEta = 154; // Q8 +// Minimum difference between the two models, Q5 +static const WebRtc_Word16 kMinimumDifference[6] = { + 544, 544, 576, 576, 576, 576 }; +// Upper limit of mean value for speech model, Q7 +static const WebRtc_Word16 kMaximumSpeech[6] = { + 11392, 11392, 11520, 11520, 11520, 11520 }; +// Minimum value for mean value +static const WebRtc_Word16 kMinimumMean[2] = { 640, 768 }; +// Upper limit of mean value for noise model, Q7 +static const WebRtc_Word16 kMaximumNoise[6] = { + 9216, 9088, 8960, 8832, 8704, 8576 }; +// Start values for the Gaussian models, Q7 +// Weights for the two Gaussians for the six channels (noise) +static const WebRtc_Word16 kNoiseDataWeights[12] = { + 34, 62, 72, 66, 53, 25, 94, 66, 56, 62, 75, 103 }; +// Weights for the two Gaussians for the six channels (speech) +static const WebRtc_Word16 kSpeechDataWeights[12] = { + 48, 82, 45, 87, 50, 47, 80, 46, 83, 41, 78, 81 }; +// Means for the two Gaussians for the six channels (noise) +static const WebRtc_Word16 kNoiseDataMeans[12] = { + 6738, 4892, 7065, 6715, 6771, 3369, 7646, 3863, 7820, 7266, 5020, 4362 }; +// Means for the two Gaussians for the six channels (speech) +static const WebRtc_Word16 kSpeechDataMeans[12] = { + 8306, 10085, 10078, 11823, 11843, 6309, 9473, 9571, 10879, 7581, 8180, 7483 +}; +// Stds for the two Gaussians for the six channels (noise) +static const WebRtc_Word16 kNoiseDataStds[12] = { + 378, 1064, 493, 582, 688, 593, 474, 697, 475, 688, 421, 455 }; +// Stds for the two Gaussians for the six channels (speech) +static const WebRtc_Word16 kSpeechDataStds[12] = { + 555, 505, 567, 524, 585, 1231, 509, 828, 492, 1540, 1079, 850 }; + +// Constants used in GmmProbability(). +// +// Maximum number of counted speech (VAD = 1) frames in a row. +static const int16_t kMaxSpeechFrames = 6; +// Minimum standard deviation for both speech and noise. +static const int16_t kMinStd = 384; + +// Constants in WebRtcVad_InitCore(). +// Default aggressiveness mode. +static const short kDefaultMode = 0; +static const int kInitCheck = 42; + +// Calculates the probabilities for both speech and background noise using +// Gaussian Mixture Models. A hypothesis-test is performed to decide which type +// of signal is most probable. +// +// - inst [i/o] : Pointer to VAD instance +// - feature_vector [i] : Feature vector = log10(energy in frequency band) +// - total_power [i] : Total power in audio frame. +// - frame_length [i] : Number of input samples +// +// - returns : the VAD decision (0 - noise, 1 - speech). +static int16_t GmmProbability(VadInstT *inst, WebRtc_Word16 *feature_vector, + WebRtc_Word16 total_power, int frame_length) +{ + int n, k; + WebRtc_Word16 backval; + WebRtc_Word16 h0, h1; + WebRtc_Word16 ratvec, xval; + WebRtc_Word16 vadflag; + WebRtc_Word16 shifts0, shifts1; + WebRtc_Word16 tmp16, tmp16_1, tmp16_2; + WebRtc_Word16 diff, nr, pos; + WebRtc_Word16 nmk, nmk2, nmk3, smk, smk2, nsk, ssk; + WebRtc_Word16 delt, ndelt; + WebRtc_Word16 maxspe, maxmu; + WebRtc_Word16 deltaN[NUM_TABLE_VALUES], deltaS[NUM_TABLE_VALUES]; + WebRtc_Word16 ngprvec[NUM_TABLE_VALUES], sgprvec[NUM_TABLE_VALUES]; + WebRtc_Word32 h0test, h1test; + WebRtc_Word32 tmp32_1, tmp32_2; + WebRtc_Word32 dotVal; + WebRtc_Word32 nmid, smid; + WebRtc_Word32 probn[NUM_MODELS], probs[NUM_MODELS]; + WebRtc_Word16 *nmean1ptr, *nmean2ptr, *smean1ptr, *smean2ptr, *nstd1ptr, *nstd2ptr, + *sstd1ptr, *sstd2ptr; + WebRtc_Word16 overhead1, overhead2, individualTest, totalTest; + + // Set the thresholds to different values based on frame length + if (frame_length == 80) + { + // 80 input samples + overhead1 = inst->over_hang_max_1[0]; + overhead2 = inst->over_hang_max_2[0]; + individualTest = inst->individual[0]; + totalTest = inst->total[0]; + } else if (frame_length == 160) + { + // 160 input samples + overhead1 = inst->over_hang_max_1[1]; + overhead2 = inst->over_hang_max_2[1]; + individualTest = inst->individual[1]; + totalTest = inst->total[1]; + } else + { + // 240 input samples + overhead1 = inst->over_hang_max_1[2]; + overhead2 = inst->over_hang_max_2[2]; + individualTest = inst->individual[2]; + totalTest = inst->total[2]; + } + + if (total_power > MIN_ENERGY) + { // If signal present at all + + // Set pointers to the gaussian parameters + nmean1ptr = &inst->noise_means[0]; + nmean2ptr = &inst->noise_means[NUM_CHANNELS]; + smean1ptr = &inst->speech_means[0]; + smean2ptr = &inst->speech_means[NUM_CHANNELS]; + nstd1ptr = &inst->noise_stds[0]; + nstd2ptr = &inst->noise_stds[NUM_CHANNELS]; + sstd1ptr = &inst->speech_stds[0]; + sstd2ptr = &inst->speech_stds[NUM_CHANNELS]; + + vadflag = 0; + dotVal = 0; + for (n = 0; n < NUM_CHANNELS; n++) + { // For all channels + + pos = WEBRTC_SPL_LSHIFT_W16(n, 1); + xval = feature_vector[n]; + + // Probability for Noise, Q7 * Q20 = Q27 + tmp32_1 = WebRtcVad_GaussianProbability(xval, *nmean1ptr++, *nstd1ptr++, + &deltaN[pos]); + probn[0] = (WebRtc_Word32)(kNoiseDataWeights[n] * tmp32_1); + tmp32_1 = WebRtcVad_GaussianProbability(xval, *nmean2ptr++, *nstd2ptr++, + &deltaN[pos + 1]); + probn[1] = (WebRtc_Word32)(kNoiseDataWeights[n + NUM_CHANNELS] * tmp32_1); + h0test = probn[0] + probn[1]; // Q27 + h0 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(h0test, 12); // Q15 + + // Probability for Speech + tmp32_1 = WebRtcVad_GaussianProbability(xval, *smean1ptr++, *sstd1ptr++, + &deltaS[pos]); + probs[0] = (WebRtc_Word32)(kSpeechDataWeights[n] * tmp32_1); + tmp32_1 = WebRtcVad_GaussianProbability(xval, *smean2ptr++, *sstd2ptr++, + &deltaS[pos + 1]); + probs[1] = (WebRtc_Word32)(kSpeechDataWeights[n + NUM_CHANNELS] * tmp32_1); + h1test = probs[0] + probs[1]; // Q27 + h1 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(h1test, 12); // Q15 + + // Get likelihood ratio. Approximate log2(H1/H0) with shifts0 - shifts1 + shifts0 = WebRtcSpl_NormW32(h0test); + shifts1 = WebRtcSpl_NormW32(h1test); + + if ((h0test > 0) && (h1test > 0)) + { + ratvec = shifts0 - shifts1; + } else if (h1test > 0) + { + ratvec = 31 - shifts1; + } else if (h0test > 0) + { + ratvec = shifts0 - 31; + } else + { + ratvec = 0; + } + + // VAD decision with spectrum weighting + dotVal += WEBRTC_SPL_MUL_16_16(ratvec, kSpectrumWeight[n]); + + // Individual channel test + if ((ratvec << 2) > individualTest) + { + vadflag = 1; + } + + // Probabilities used when updating model + if (h0 > 0) + { + tmp32_1 = probn[0] & 0xFFFFF000; // Q27 + tmp32_2 = WEBRTC_SPL_LSHIFT_W32(tmp32_1, 2); // Q29 + ngprvec[pos] = (WebRtc_Word16)WebRtcSpl_DivW32W16(tmp32_2, h0); + ngprvec[pos + 1] = 16384 - ngprvec[pos]; + } else + { + ngprvec[pos] = 16384; + ngprvec[pos + 1] = 0; + } + + // Probabilities used when updating model + if (h1 > 0) + { + tmp32_1 = probs[0] & 0xFFFFF000; + tmp32_2 = WEBRTC_SPL_LSHIFT_W32(tmp32_1, 2); + sgprvec[pos] = (WebRtc_Word16)WebRtcSpl_DivW32W16(tmp32_2, h1); + sgprvec[pos + 1] = 16384 - sgprvec[pos]; + } else + { + sgprvec[pos] = 0; + sgprvec[pos + 1] = 0; + } + } + + // Overall test + if (dotVal >= totalTest) + { + vadflag |= 1; + } + + // Set pointers to the means and standard deviations. + nmean1ptr = &inst->noise_means[0]; + smean1ptr = &inst->speech_means[0]; + nstd1ptr = &inst->noise_stds[0]; + sstd1ptr = &inst->speech_stds[0]; + + maxspe = 12800; + + // Update the model's parameters + for (n = 0; n < NUM_CHANNELS; n++) + { + + pos = WEBRTC_SPL_LSHIFT_W16(n, 1); + + // Get min value in past which is used for long term correction + backval = WebRtcVad_FindMinimum(inst, feature_vector[n], n); // Q4 + + // Compute the "global" mean, that is the sum of the two means weighted + nmid = WEBRTC_SPL_MUL_16_16(kNoiseDataWeights[n], *nmean1ptr); // Q7 * Q7 + nmid += WEBRTC_SPL_MUL_16_16(kNoiseDataWeights[n+NUM_CHANNELS], + *(nmean1ptr+NUM_CHANNELS)); + tmp16_1 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(nmid, 6); // Q8 + + for (k = 0; k < NUM_MODELS; k++) + { + + nr = pos + k; + + nmean2ptr = nmean1ptr + k * NUM_CHANNELS; + smean2ptr = smean1ptr + k * NUM_CHANNELS; + nstd2ptr = nstd1ptr + k * NUM_CHANNELS; + sstd2ptr = sstd1ptr + k * NUM_CHANNELS; + nmk = *nmean2ptr; + smk = *smean2ptr; + nsk = *nstd2ptr; + ssk = *sstd2ptr; + + // Update noise mean vector if the frame consists of noise only + nmk2 = nmk; + if (!vadflag) + { + // deltaN = (x-mu)/sigma^2 + // ngprvec[k] = probn[k]/(probn[0] + probn[1]) + + delt = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(ngprvec[nr], + deltaN[nr], 11); // Q14*Q11 + nmk2 = nmk + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(delt, + kNoiseUpdateConst, + 22); // Q7+(Q14*Q15>>22) + } + + // Long term correction of the noise mean + ndelt = WEBRTC_SPL_LSHIFT_W16(backval, 4); + ndelt -= tmp16_1; // Q8 - Q8 + nmk3 = nmk2 + (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(ndelt, + kBackEta, + 9); // Q7+(Q8*Q8)>>9 + + // Control that the noise mean does not drift to much + tmp16 = WEBRTC_SPL_LSHIFT_W16(k+5, 7); + if (nmk3 < tmp16) + nmk3 = tmp16; + tmp16 = WEBRTC_SPL_LSHIFT_W16(72+k-n, 7); + if (nmk3 > tmp16) + nmk3 = tmp16; + *nmean2ptr = nmk3; + + if (vadflag) + { + // Update speech mean vector: + // deltaS = (x-mu)/sigma^2 + // sgprvec[k] = probn[k]/(probn[0] + probn[1]) + + delt = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(sgprvec[nr], + deltaS[nr], + 11); // (Q14*Q11)>>11=Q14 + tmp16 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(delt, + kSpeechUpdateConst, + 21) + 1; + smk2 = smk + (tmp16 >> 1); // Q7 + (Q14 * Q15 >> 22) + + // Control that the speech mean does not drift to much + maxmu = maxspe + 640; + if (smk2 < kMinimumMean[k]) + smk2 = kMinimumMean[k]; + if (smk2 > maxmu) + smk2 = maxmu; + + *smean2ptr = smk2; + + // (Q7>>3) = Q4 + tmp16 = WEBRTC_SPL_RSHIFT_W16((smk + 4), 3); + + tmp16 = feature_vector[n] - tmp16; // Q4 + tmp32_1 = WEBRTC_SPL_MUL_16_16_RSFT(deltaS[nr], tmp16, 3); + tmp32_2 = tmp32_1 - (WebRtc_Word32)4096; // Q12 + tmp16 = WEBRTC_SPL_RSHIFT_W16((sgprvec[nr]), 2); + tmp32_1 = (WebRtc_Word32)(tmp16 * tmp32_2);// (Q15>>3)*(Q14>>2)=Q12*Q12=Q24 + + tmp32_2 = WEBRTC_SPL_RSHIFT_W32(tmp32_1, 4); // Q20 + + // 0.1 * Q20 / Q7 = Q13 + if (tmp32_2 > 0) + tmp16 = (WebRtc_Word16)WebRtcSpl_DivW32W16(tmp32_2, ssk * 10); + else + { + tmp16 = (WebRtc_Word16)WebRtcSpl_DivW32W16(-tmp32_2, ssk * 10); + tmp16 = -tmp16; + } + // divide by 4 giving an update factor of 0.025 + tmp16 += 128; // Rounding + ssk += WEBRTC_SPL_RSHIFT_W16(tmp16, 8); + // Division with 8 plus Q7 + if (ssk < kMinStd) + ssk = kMinStd; + *sstd2ptr = ssk; + } else + { + // Update GMM variance vectors + // deltaN * (feature_vector[n] - nmk) - 1, Q11 * Q4 + tmp16 = feature_vector[n] - WEBRTC_SPL_RSHIFT_W16(nmk, 3); + + // (Q15>>3) * (Q14>>2) = Q12 * Q12 = Q24 + tmp32_1 = WEBRTC_SPL_MUL_16_16_RSFT(deltaN[nr], tmp16, 3) - 4096; + tmp16 = WEBRTC_SPL_RSHIFT_W16((ngprvec[nr]+2), 2); + tmp32_2 = (WebRtc_Word32)(tmp16 * tmp32_1); + tmp32_1 = WEBRTC_SPL_RSHIFT_W32(tmp32_2, 14); + // Q20 * approx 0.001 (2^-10=0.0009766) + + // Q20 / Q7 = Q13 + tmp16 = (WebRtc_Word16)WebRtcSpl_DivW32W16(tmp32_1, nsk); + if (tmp32_1 > 0) + tmp16 = (WebRtc_Word16)WebRtcSpl_DivW32W16(tmp32_1, nsk); + else + { + tmp16 = (WebRtc_Word16)WebRtcSpl_DivW32W16(-tmp32_1, nsk); + tmp16 = -tmp16; + } + tmp16 += 32; // Rounding + nsk += WEBRTC_SPL_RSHIFT_W16(tmp16, 6); + + if (nsk < kMinStd) + nsk = kMinStd; + + *nstd2ptr = nsk; + } + } + + // Separate models if they are too close - nmid in Q14 + nmid = WEBRTC_SPL_MUL_16_16(kNoiseDataWeights[n], *nmean1ptr); + nmid += WEBRTC_SPL_MUL_16_16(kNoiseDataWeights[n+NUM_CHANNELS], *nmean2ptr); + + // smid in Q14 + smid = WEBRTC_SPL_MUL_16_16(kSpeechDataWeights[n], *smean1ptr); + smid += WEBRTC_SPL_MUL_16_16(kSpeechDataWeights[n+NUM_CHANNELS], *smean2ptr); + + // diff = "global" speech mean - "global" noise mean + diff = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(smid, 9); + tmp16 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(nmid, 9); + diff -= tmp16; + + if (diff < kMinimumDifference[n]) + { + + tmp16 = kMinimumDifference[n] - diff; // Q5 + + // tmp16_1 = ~0.8 * (kMinimumDifference - diff) in Q7 + // tmp16_2 = ~0.2 * (kMinimumDifference - diff) in Q7 + tmp16_1 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(13, tmp16, 2); + tmp16_2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(3, tmp16, 2); + + // First Gauss, speech model + tmp16 = tmp16_1 + *smean1ptr; + *smean1ptr = tmp16; + smid = WEBRTC_SPL_MUL_16_16(tmp16, kSpeechDataWeights[n]); + + // Second Gauss, speech model + tmp16 = tmp16_1 + *smean2ptr; + *smean2ptr = tmp16; + smid += WEBRTC_SPL_MUL_16_16(tmp16, kSpeechDataWeights[n+NUM_CHANNELS]); + + // First Gauss, noise model + tmp16 = *nmean1ptr - tmp16_2; + *nmean1ptr = tmp16; + + nmid = WEBRTC_SPL_MUL_16_16(tmp16, kNoiseDataWeights[n]); + + // Second Gauss, noise model + tmp16 = *nmean2ptr - tmp16_2; + *nmean2ptr = tmp16; + nmid += WEBRTC_SPL_MUL_16_16(tmp16, kNoiseDataWeights[n+NUM_CHANNELS]); + } + + // Control that the speech & noise means do not drift to much + maxspe = kMaximumSpeech[n]; + tmp16_2 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(smid, 7); + if (tmp16_2 > maxspe) + { // Upper limit of speech model + tmp16_2 -= maxspe; + + *smean1ptr -= tmp16_2; + *smean2ptr -= tmp16_2; + } + + tmp16_2 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(nmid, 7); + if (tmp16_2 > kMaximumNoise[n]) + { + tmp16_2 -= kMaximumNoise[n]; + + *nmean1ptr -= tmp16_2; + *nmean2ptr -= tmp16_2; + } + + nmean1ptr++; + smean1ptr++; + nstd1ptr++; + sstd1ptr++; + } + inst->frame_counter++; + } else + { + vadflag = 0; + } + + // Hangover smoothing + if (!vadflag) + { + if (inst->over_hang > 0) + { + vadflag = 2 + inst->over_hang; + inst->over_hang = inst->over_hang - 1; + } + inst->num_of_speech = 0; + } else + { + inst->num_of_speech = inst->num_of_speech + 1; + if (inst->num_of_speech > kMaxSpeechFrames) + { + inst->num_of_speech = kMaxSpeechFrames; + inst->over_hang = overhead2; + } else + inst->over_hang = overhead1; + } + return vadflag; +} + +// Initialize the VAD. Set aggressiveness mode to default value. +int WebRtcVad_InitCore(VadInstT* self) { + int i; + + if (self == NULL) { + return -1; + } + + // Initialization of general struct variables. + self->vad = 1; // Speech active (=1). + self->frame_counter = 0; + self->over_hang = 0; + self->num_of_speech = 0; + + // Initialization of downsampling filter state. + memset(self->downsampling_filter_states, 0, + sizeof(self->downsampling_filter_states)); + + // Read initial PDF parameters. + for (i = 0; i < NUM_TABLE_VALUES; i++) { + self->noise_means[i] = kNoiseDataMeans[i]; + self->speech_means[i] = kSpeechDataMeans[i]; + self->noise_stds[i] = kNoiseDataStds[i]; + self->speech_stds[i] = kSpeechDataStds[i]; + } + + // Initialize Index and Minimum value vectors. + for (i = 0; i < 16 * NUM_CHANNELS; i++) { + self->low_value_vector[i] = 10000; + self->index_vector[i] = 0; + } + + // Initialize splitting filter states. + memset(self->upper_state, 0, sizeof(self->upper_state)); + memset(self->lower_state, 0, sizeof(self->lower_state)); + + // Initialize high pass filter states. + memset(self->hp_filter_state, 0, sizeof(self->hp_filter_state)); + + // Initialize mean value memory, for WebRtcVad_FindMinimum(). + for (i = 0; i < NUM_CHANNELS; i++) { + self->mean_value[i] = 1600; + } + + // Set aggressiveness mode to default (=|kDefaultMode|). + if (WebRtcVad_set_mode_core(self, kDefaultMode) != 0) { + return -1; + } + + self->init_flag = kInitCheck; + + return 0; +} + +// Set aggressiveness mode +int WebRtcVad_set_mode_core(VadInstT *inst, int mode) +{ + + if (mode == 0) + { + // Quality mode + inst->over_hang_max_1[0] = OHMAX1_10MS_Q; // Overhang short speech burst + inst->over_hang_max_1[1] = OHMAX1_20MS_Q; // Overhang short speech burst + inst->over_hang_max_1[2] = OHMAX1_30MS_Q; // Overhang short speech burst + inst->over_hang_max_2[0] = OHMAX2_10MS_Q; // Overhang long speech burst + inst->over_hang_max_2[1] = OHMAX2_20MS_Q; // Overhang long speech burst + inst->over_hang_max_2[2] = OHMAX2_30MS_Q; // Overhang long speech burst + + inst->individual[0] = INDIVIDUAL_10MS_Q; + inst->individual[1] = INDIVIDUAL_20MS_Q; + inst->individual[2] = INDIVIDUAL_30MS_Q; + + inst->total[0] = TOTAL_10MS_Q; + inst->total[1] = TOTAL_20MS_Q; + inst->total[2] = TOTAL_30MS_Q; + } else if (mode == 1) + { + // Low bitrate mode + inst->over_hang_max_1[0] = OHMAX1_10MS_LBR; // Overhang short speech burst + inst->over_hang_max_1[1] = OHMAX1_20MS_LBR; // Overhang short speech burst + inst->over_hang_max_1[2] = OHMAX1_30MS_LBR; // Overhang short speech burst + inst->over_hang_max_2[0] = OHMAX2_10MS_LBR; // Overhang long speech burst + inst->over_hang_max_2[1] = OHMAX2_20MS_LBR; // Overhang long speech burst + inst->over_hang_max_2[2] = OHMAX2_30MS_LBR; // Overhang long speech burst + + inst->individual[0] = INDIVIDUAL_10MS_LBR; + inst->individual[1] = INDIVIDUAL_20MS_LBR; + inst->individual[2] = INDIVIDUAL_30MS_LBR; + + inst->total[0] = TOTAL_10MS_LBR; + inst->total[1] = TOTAL_20MS_LBR; + inst->total[2] = TOTAL_30MS_LBR; + } else if (mode == 2) + { + // Aggressive mode + inst->over_hang_max_1[0] = OHMAX1_10MS_AGG; // Overhang short speech burst + inst->over_hang_max_1[1] = OHMAX1_20MS_AGG; // Overhang short speech burst + inst->over_hang_max_1[2] = OHMAX1_30MS_AGG; // Overhang short speech burst + inst->over_hang_max_2[0] = OHMAX2_10MS_AGG; // Overhang long speech burst + inst->over_hang_max_2[1] = OHMAX2_20MS_AGG; // Overhang long speech burst + inst->over_hang_max_2[2] = OHMAX2_30MS_AGG; // Overhang long speech burst + + inst->individual[0] = INDIVIDUAL_10MS_AGG; + inst->individual[1] = INDIVIDUAL_20MS_AGG; + inst->individual[2] = INDIVIDUAL_30MS_AGG; + + inst->total[0] = TOTAL_10MS_AGG; + inst->total[1] = TOTAL_20MS_AGG; + inst->total[2] = TOTAL_30MS_AGG; + } else if (mode == 3) + { + // Very aggressive mode + inst->over_hang_max_1[0] = OHMAX1_10MS_VAG; // Overhang short speech burst + inst->over_hang_max_1[1] = OHMAX1_20MS_VAG; // Overhang short speech burst + inst->over_hang_max_1[2] = OHMAX1_30MS_VAG; // Overhang short speech burst + inst->over_hang_max_2[0] = OHMAX2_10MS_VAG; // Overhang long speech burst + inst->over_hang_max_2[1] = OHMAX2_20MS_VAG; // Overhang long speech burst + inst->over_hang_max_2[2] = OHMAX2_30MS_VAG; // Overhang long speech burst + + inst->individual[0] = INDIVIDUAL_10MS_VAG; + inst->individual[1] = INDIVIDUAL_20MS_VAG; + inst->individual[2] = INDIVIDUAL_30MS_VAG; + + inst->total[0] = TOTAL_10MS_VAG; + inst->total[1] = TOTAL_20MS_VAG; + inst->total[2] = TOTAL_30MS_VAG; + } else + { + return -1; + } + + return 0; +} + +// Calculate VAD decision by first extracting feature values and then calculate +// probability for both speech and background noise. + +WebRtc_Word16 WebRtcVad_CalcVad32khz(VadInstT *inst, WebRtc_Word16 *speech_frame, + int frame_length) +{ + WebRtc_Word16 len, vad; + WebRtc_Word16 speechWB[480]; // Downsampled speech frame: 960 samples (30ms in SWB) + WebRtc_Word16 speechNB[240]; // Downsampled speech frame: 480 samples (30ms in WB) + + + // Downsample signal 32->16->8 before doing VAD + WebRtcVad_Downsampling(speech_frame, speechWB, &(inst->downsampling_filter_states[2]), + frame_length); + len = WEBRTC_SPL_RSHIFT_W16(frame_length, 1); + + WebRtcVad_Downsampling(speechWB, speechNB, inst->downsampling_filter_states, len); + len = WEBRTC_SPL_RSHIFT_W16(len, 1); + + // Do VAD on an 8 kHz signal + vad = WebRtcVad_CalcVad8khz(inst, speechNB, len); + + return vad; +} + +WebRtc_Word16 WebRtcVad_CalcVad16khz(VadInstT *inst, WebRtc_Word16 *speech_frame, + int frame_length) +{ + WebRtc_Word16 len, vad; + WebRtc_Word16 speechNB[240]; // Downsampled speech frame: 480 samples (30ms in WB) + + // Wideband: Downsample signal before doing VAD + WebRtcVad_Downsampling(speech_frame, speechNB, inst->downsampling_filter_states, + frame_length); + + len = WEBRTC_SPL_RSHIFT_W16(frame_length, 1); + vad = WebRtcVad_CalcVad8khz(inst, speechNB, len); + + return vad; +} + +WebRtc_Word16 WebRtcVad_CalcVad8khz(VadInstT *inst, WebRtc_Word16 *speech_frame, + int frame_length) +{ + WebRtc_Word16 feature_vector[NUM_CHANNELS], total_power; + + // Get power in the bands + total_power = WebRtcVad_CalculateFeatures(inst, speech_frame, frame_length, + feature_vector); + + // Make a VAD + inst->vad = GmmProbability(inst, feature_vector, total_power, frame_length); + + return inst->vad; +} diff --git a/libs/miniwebrtc/audio/common/vad/vad_core.h b/libs/miniwebrtc/audio/common/vad/vad_core.h new file mode 100644 index 00000000..c82fbce0 --- /dev/null +++ b/libs/miniwebrtc/audio/common/vad/vad_core.h @@ -0,0 +1,106 @@ +/* + * 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. + */ + + +/* + * This header file includes the descriptions of the core VAD calls. + */ + +#ifndef WEBRTC_COMMON_AUDIO_VAD_VAD_CORE_H_ +#define WEBRTC_COMMON_AUDIO_VAD_VAD_CORE_H_ + +#include "typedefs.h" +#include "vad_defines.h" + +typedef struct VadInstT_ +{ + + WebRtc_Word16 vad; + WebRtc_Word32 downsampling_filter_states[4]; + WebRtc_Word16 noise_means[NUM_TABLE_VALUES]; + WebRtc_Word16 speech_means[NUM_TABLE_VALUES]; + WebRtc_Word16 noise_stds[NUM_TABLE_VALUES]; + WebRtc_Word16 speech_stds[NUM_TABLE_VALUES]; + // TODO(bjornv): Change to |frame_count|. + WebRtc_Word32 frame_counter; + WebRtc_Word16 over_hang; // Over Hang + WebRtc_Word16 num_of_speech; + // TODO(bjornv): Change to |age_vector|. + WebRtc_Word16 index_vector[16 * NUM_CHANNELS]; + WebRtc_Word16 low_value_vector[16 * NUM_CHANNELS]; + // TODO(bjornv): Change to |median|. + WebRtc_Word16 mean_value[NUM_CHANNELS]; + WebRtc_Word16 upper_state[5]; + WebRtc_Word16 lower_state[5]; + WebRtc_Word16 hp_filter_state[4]; + WebRtc_Word16 over_hang_max_1[3]; + WebRtc_Word16 over_hang_max_2[3]; + WebRtc_Word16 individual[3]; + WebRtc_Word16 total[3]; + + int init_flag; + +} VadInstT; + +// Initializes the core VAD component. The default aggressiveness mode is +// controlled by |kDefaultMode| in vad_core.c. +// +// - self [i/o] : Instance that should be initialized +// +// returns : 0 (OK), -1 (NULL pointer in or if the default mode can't be +// set) +int WebRtcVad_InitCore(VadInstT* self); + +/**************************************************************************** + * WebRtcVad_set_mode_core(...) + * + * This function changes the VAD settings + * + * Input: + * - inst : VAD instance + * - mode : Aggressiveness degree + * 0 (High quality) - 3 (Highly aggressive) + * + * Output: + * - inst : Changed instance + * + * Return value : 0 - Ok + * -1 - Error + */ + +int WebRtcVad_set_mode_core(VadInstT* inst, int mode); + +/**************************************************************************** + * WebRtcVad_CalcVad32khz(...) + * WebRtcVad_CalcVad16khz(...) + * WebRtcVad_CalcVad8khz(...) + * + * Calculate probability for active speech and make VAD decision. + * + * Input: + * - inst : Instance that should be initialized + * - speech_frame : Input speech frame + * - frame_length : Number of input samples + * + * Output: + * - inst : Updated filter states etc. + * + * Return value : VAD decision + * 0 - No active speech + * 1-6 - Active speech + */ +WebRtc_Word16 WebRtcVad_CalcVad32khz(VadInstT* inst, WebRtc_Word16* speech_frame, + int frame_length); +WebRtc_Word16 WebRtcVad_CalcVad16khz(VadInstT* inst, WebRtc_Word16* speech_frame, + int frame_length); +WebRtc_Word16 WebRtcVad_CalcVad8khz(VadInstT* inst, WebRtc_Word16* speech_frame, + int frame_length); + +#endif // WEBRTC_COMMON_AUDIO_VAD_VAD_CORE_H_ diff --git a/libs/miniwebrtc/audio/common/vad/vad_defines.h b/libs/miniwebrtc/audio/common/vad/vad_defines.h new file mode 100644 index 00000000..5d1539dd --- /dev/null +++ b/libs/miniwebrtc/audio/common/vad/vad_defines.h @@ -0,0 +1,93 @@ +/* + * 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 header file includes the macros used in VAD. + */ + +#ifndef WEBRTC_VAD_DEFINES_H_ +#define WEBRTC_VAD_DEFINES_H_ + +#define NUM_CHANNELS 6 // Eight frequency bands +#define NUM_MODELS 2 // Number of Gaussian models +#define NUM_TABLE_VALUES NUM_CHANNELS * NUM_MODELS + +#define MIN_ENERGY 10 +#define ALPHA1 6553 // 0.2 in Q15 +#define ALPHA2 32439 // 0.99 in Q15 +// Mode 0, Quality thresholds - Different thresholds for the different frame lengths +#define INDIVIDUAL_10MS_Q 24 +#define INDIVIDUAL_20MS_Q 21 // (log10(2)*66)<<2 ~=16 +#define INDIVIDUAL_30MS_Q 24 + +#define TOTAL_10MS_Q 57 +#define TOTAL_20MS_Q 48 +#define TOTAL_30MS_Q 57 + +#define OHMAX1_10MS_Q 8 // Max Overhang 1 +#define OHMAX2_10MS_Q 14 // Max Overhang 2 +#define OHMAX1_20MS_Q 4 // Max Overhang 1 +#define OHMAX2_20MS_Q 7 // Max Overhang 2 +#define OHMAX1_30MS_Q 3 +#define OHMAX2_30MS_Q 5 + +// Mode 1, Low bitrate thresholds - Different thresholds for the different frame lengths +#define INDIVIDUAL_10MS_LBR 37 +#define INDIVIDUAL_20MS_LBR 32 +#define INDIVIDUAL_30MS_LBR 37 + +#define TOTAL_10MS_LBR 100 +#define TOTAL_20MS_LBR 80 +#define TOTAL_30MS_LBR 100 + +#define OHMAX1_10MS_LBR 8 // Max Overhang 1 +#define OHMAX2_10MS_LBR 14 // Max Overhang 2 +#define OHMAX1_20MS_LBR 4 +#define OHMAX2_20MS_LBR 7 + +#define OHMAX1_30MS_LBR 3 +#define OHMAX2_30MS_LBR 5 + +// Mode 2, Very aggressive thresholds - Different thresholds for the different frame lengths +#define INDIVIDUAL_10MS_AGG 82 +#define INDIVIDUAL_20MS_AGG 78 +#define INDIVIDUAL_30MS_AGG 82 + +#define TOTAL_10MS_AGG 285 //580 +#define TOTAL_20MS_AGG 260 +#define TOTAL_30MS_AGG 285 + +#define OHMAX1_10MS_AGG 6 // Max Overhang 1 +#define OHMAX2_10MS_AGG 9 // Max Overhang 2 +#define OHMAX1_20MS_AGG 3 +#define OHMAX2_20MS_AGG 5 + +#define OHMAX1_30MS_AGG 2 +#define OHMAX2_30MS_AGG 3 + +// Mode 3, Super aggressive thresholds - Different thresholds for the different frame lengths +#define INDIVIDUAL_10MS_VAG 94 +#define INDIVIDUAL_20MS_VAG 94 +#define INDIVIDUAL_30MS_VAG 94 + +#define TOTAL_10MS_VAG 1100 //1700 +#define TOTAL_20MS_VAG 1050 +#define TOTAL_30MS_VAG 1100 + +#define OHMAX1_10MS_VAG 6 // Max Overhang 1 +#define OHMAX2_10MS_VAG 9 // Max Overhang 2 +#define OHMAX1_20MS_VAG 3 +#define OHMAX2_20MS_VAG 5 + +#define OHMAX1_30MS_VAG 2 +#define OHMAX2_30MS_VAG 3 + +#endif // WEBRTC_VAD_DEFINES_H_ diff --git a/libs/miniwebrtc/audio/common/vad/vad_filterbank.c b/libs/miniwebrtc/audio/common/vad/vad_filterbank.c new file mode 100644 index 00000000..2f5db448 --- /dev/null +++ b/libs/miniwebrtc/audio/common/vad/vad_filterbank.c @@ -0,0 +1,335 @@ +/* + * 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 "vad_filterbank.h" + +#include + +#include "signal_processing_library.h" +#include "typedefs.h" +#include "vad_defines.h" + +// Constants used in LogOfEnergy(). +static const int16_t kLogConst = 24660; // 160*log10(2) in Q9. +static const int16_t kLogEnergyIntPart = 14336; // 14 in Q10 + +// Coefficients used by HighPassFilter, Q14. +static const int16_t kHpZeroCoefs[3] = { 6631, -13262, 6631 }; +static const int16_t kHpPoleCoefs[3] = { 16384, -7756, 5620 }; + +// Allpass filter coefficients, upper and lower, in Q15. +// Upper: 0.64, Lower: 0.17 +static const int16_t kAllPassCoefsQ15[2] = { 20972, 5571 }; + +// Adjustment for division with two in SplitFilter. +static const int16_t kOffsetVector[6] = { 368, 368, 272, 176, 176, 176 }; + +// High pass filtering, with a cut-off frequency at 80 Hz, if the |data_in| is +// sampled at 500 Hz. +// +// - data_in [i] : Input audio data sampled at 500 Hz. +// - data_length [i] : Length of input and output data. +// - filter_state [i/o] : State of the filter. +// - data_out [o] : Output audio data in the frequency interval +// 80 - 250 Hz. +static void HighPassFilter(const int16_t* data_in, int data_length, + int16_t* filter_state, int16_t* data_out) { + int i; + const int16_t* in_ptr = data_in; + int16_t* out_ptr = data_out; + int32_t tmp32 = 0; + + + // The sum of the absolute values of the impulse response: + // The zero/pole-filter has a max amplification of a single sample of: 1.4546 + // Impulse response: 0.4047 -0.6179 -0.0266 0.1993 0.1035 -0.0194 + // The all-zero section has a max amplification of a single sample of: 1.6189 + // Impulse response: 0.4047 -0.8094 0.4047 0 0 0 + // The all-pole section has a max amplification of a single sample of: 1.9931 + // Impulse response: 1.0000 0.4734 -0.1189 -0.2187 -0.0627 0.04532 + + for (i = 0; i < data_length; i++) { + // All-zero section (filter coefficients in Q14). + tmp32 = WEBRTC_SPL_MUL_16_16(kHpZeroCoefs[0], *in_ptr); + tmp32 += WEBRTC_SPL_MUL_16_16(kHpZeroCoefs[1], filter_state[0]); + tmp32 += WEBRTC_SPL_MUL_16_16(kHpZeroCoefs[2], filter_state[1]); + filter_state[1] = filter_state[0]; + filter_state[0] = *in_ptr++; + + // All-pole section (filter coefficients in Q14). + tmp32 -= WEBRTC_SPL_MUL_16_16(kHpPoleCoefs[1], filter_state[2]); + tmp32 -= WEBRTC_SPL_MUL_16_16(kHpPoleCoefs[2], filter_state[3]); + filter_state[3] = filter_state[2]; + filter_state[2] = (int16_t) (tmp32 >> 14); + *out_ptr++ = filter_state[2]; + } +} + +// All pass filtering of |data_in|, used before splitting the signal into two +// frequency bands (low pass vs high pass). +// Note that |data_in| and |data_out| can NOT correspond to the same address. +// +// - data_in [i] : Input audio signal given in Q0. +// - data_length [i] : Length of input and output data. +// - filter_coefficient [i] : Given in Q15. +// - filter_state [i/o] : State of the filter given in Q(-1). +// - data_out [o] : Output audio signal given in Q(-1). +static void AllPassFilter(const int16_t* data_in, int data_length, + int16_t filter_coefficient, int16_t* filter_state, + int16_t* data_out) { + // The filter can only cause overflow (in the w16 output variable) + // if more than 4 consecutive input numbers are of maximum value and + // has the the same sign as the impulse responses first taps. + // First 6 taps of the impulse response: + // 0.6399 0.5905 -0.3779 0.2418 -0.1547 0.0990 + + int i; + int16_t tmp16 = 0; + int32_t tmp32 = 0; + int32_t state32 = ((int32_t) (*filter_state) << 16); // Q15 + + for (i = 0; i < data_length; i++) { + tmp32 = state32 + WEBRTC_SPL_MUL_16_16(filter_coefficient, *data_in); + tmp16 = (int16_t) (tmp32 >> 16); // Q(-1) + *data_out++ = tmp16; + state32 = (((int32_t) (*data_in)) << 14); // Q14 + state32 -= WEBRTC_SPL_MUL_16_16(filter_coefficient, tmp16); // Q14 + state32 <<= 1; // Q15. + data_in += 2; + } + + *filter_state = (int16_t) (state32 >> 16); // Q(-1) +} + +// Splits |data_in| into |hp_data_out| and |lp_data_out| corresponding to +// an upper (high pass) part and a lower (low pass) part respectively. +// +// - data_in [i] : Input audio data to be split into two frequency bands. +// - data_length [i] : Length of |data_in|. +// - upper_state [i/o] : State of the upper filter, given in Q(-1). +// - lower_state [i/o] : State of the lower filter, given in Q(-1). +// - hp_data_out [o] : Output audio data of the upper half of the spectrum. +// The length is |data_length| / 2. +// - lp_data_out [o] : Output audio data of the lower half of the spectrum. +// The length is |data_length| / 2. +static void SplitFilter(const int16_t* data_in, int data_length, + int16_t* upper_state, int16_t* lower_state, + int16_t* hp_data_out, int16_t* lp_data_out) { + int i; + int half_length = data_length >> 1; // Downsampling by 2. + int16_t tmp_out; + + // All-pass filtering upper branch. + AllPassFilter(&data_in[0], half_length, kAllPassCoefsQ15[0], upper_state, + hp_data_out); + + // All-pass filtering lower branch. + AllPassFilter(&data_in[1], half_length, kAllPassCoefsQ15[1], lower_state, + lp_data_out); + + // Make LP and HP signals. + for (i = 0; i < half_length; i++) { + tmp_out = *hp_data_out; + *hp_data_out++ -= *lp_data_out; + *lp_data_out++ += tmp_out; + } +} + +// Calculates the energy of |data_in| in dB, and also updates an overall +// |total_energy| if necessary. +// +// - data_in [i] : Input audio data for energy calculation. +// - data_length [i] : Length of input data. +// - offset [i] : Offset value added to |log_energy|. +// - total_energy [i/o] : An external energy updated with the energy of +// |data_in|. +// NOTE: |total_energy| is only updated if +// |total_energy| <= MIN_ENERGY. +// - log_energy [o] : 10 * log10("energy of |data_in|") given in Q4. +static void LogOfEnergy(const int16_t* data_in, int data_length, + int16_t offset, int16_t* total_energy, + int16_t* log_energy) { + // |tot_rshifts| accumulates the number of right shifts performed on |energy|. + int tot_rshifts = 0; + // The |energy| will be normalized to 15 bits. We use unsigned integer because + // we eventually will mask out the fractional part. + uint32_t energy = 0; + + assert(data_in != NULL); + assert(data_length > 0); + + energy = (uint32_t) WebRtcSpl_Energy((int16_t*) data_in, data_length, + &tot_rshifts); + + if (energy != 0) { + // By construction, normalizing to 15 bits is equivalent with 17 leading + // zeros of an unsigned 32 bit value. + int normalizing_rshifts = 17 - WebRtcSpl_NormU32(energy); + // In a 15 bit representation the leading bit is 2^14. log2(2^14) in Q10 is + // (14 << 10), which is what we initialize |log2_energy| with. For a more + // detailed derivations, see below. + int16_t log2_energy = kLogEnergyIntPart; + + tot_rshifts += normalizing_rshifts; + // Normalize |energy| to 15 bits. + // |tot_rshifts| is now the total number of right shifts performed on + // |energy| after normalization. This means that |energy| is in + // Q(-tot_rshifts). + if (normalizing_rshifts < 0) { + energy <<= -normalizing_rshifts; + } else { + energy >>= normalizing_rshifts; + } + + // Calculate the energy of |data_in| in dB, in Q4. + // + // 10 * log10("true energy") in Q4 = 2^4 * 10 * log10("true energy") = + // 160 * log10(|energy| * 2^|tot_rshifts|) = + // 160 * log10(2) * log2(|energy| * 2^|tot_rshifts|) = + // 160 * log10(2) * (log2(|energy|) + log2(2^|tot_rshifts|)) = + // (160 * log10(2)) * (log2(|energy|) + |tot_rshifts|) = + // |kLogConst| * (|log2_energy| + |tot_rshifts|) + // + // We know by construction that |energy| is normalized to 15 bits. Hence, + // |energy| = 2^14 + frac_Q15, where frac_Q15 is a fractional part in Q15. + // Further, we'd like |log2_energy| in Q10 + // log2(|energy|) in Q10 = 2^10 * log2(2^14 + frac_Q15) = + // 2^10 * log2(2^14 * (1 + frac_Q15 * 2^-14)) = + // 2^10 * (14 + log2(1 + frac_Q15 * 2^-14)) ~= + // (14 << 10) + 2^10 * (frac_Q15 * 2^-14) = + // (14 << 10) + (frac_Q15 * 2^-4) = (14 << 10) + (frac_Q15 >> 4) + // + // Note that frac_Q15 = (|energy| & 0x00003FFF) + + // Calculate and add the fractional part to |log2_energy|. + log2_energy += (int16_t) ((energy & 0x00003FFF) >> 4); + + // |kLogConst| is in Q9, |log2_energy| in Q10 and |tot_rshifts| in Q0. + // Note that we in our derivation above have accounted for an output in Q4. + *log_energy = (int16_t) (WEBRTC_SPL_MUL_16_16_RSFT( + kLogConst, log2_energy, 19) + + WEBRTC_SPL_MUL_16_16_RSFT(tot_rshifts, kLogConst, 9)); + + if (*log_energy < 0) { + *log_energy = 0; + } + } else { + *log_energy = offset; + return; + } + + *log_energy += offset; + + // Update the approximate |total_energy| with the energy of |data_in|, if + // |total_energy| has not exceeded MIN_ENERGY. |total_energy| is used as an + // energy indicator in WebRtcVad_GmmProbability() in vad_core.c. + if (*total_energy <= MIN_ENERGY) { + if (tot_rshifts >= 0) { + // We know by construction that the |energy| > MIN_ENERGY in Q0, so add an + // arbitrary value such that |total_energy| exceeds MIN_ENERGY. + *total_energy += MIN_ENERGY + 1; + } else { + // By construction |energy| is represented by 15 bits, hence any number of + // right shifted |energy| will fit in an int16_t. In addition, adding the + // value to |total_energy| is wrap around safe as long as + // MIN_ENERGY < 8192. + *total_energy += (int16_t) (energy >> -tot_rshifts); // Q0. + } + } +} + +int16_t WebRtcVad_CalculateFeatures(VadInstT* self, const int16_t* data_in, + int data_length, int16_t* features) { + int16_t total_energy = 0; + // We expect |data_length| to be 80, 160 or 240 samples, which corresponds to + // 10, 20 or 30 ms in 8 kHz. Therefore, the intermediate downsampled data will + // have at most 120 samples after the first split and at most 60 samples after + // the second split. + int16_t hp_120[120], lp_120[120]; + int16_t hp_60[60], lp_60[60]; + const int half_data_length = data_length >> 1; + int length = half_data_length; // |data_length| / 2, corresponds to + // bandwidth = 2000 Hz after downsampling. + + // Initialize variables for the first SplitFilter(). + int frequency_band = 0; + const int16_t* in_ptr = data_in; // [0 - 4000] Hz. + int16_t* hp_out_ptr = hp_120; // [2000 - 4000] Hz. + int16_t* lp_out_ptr = lp_120; // [0 - 2000] Hz. + + assert(data_length >= 0); + assert(data_length <= 240); + assert(4 < NUM_CHANNELS - 1); // Checking maximum |frequency_band|. + + // Split at 2000 Hz and downsample. + SplitFilter(in_ptr, data_length, &self->upper_state[frequency_band], + &self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr); + + // For the upper band (2000 Hz - 4000 Hz) split at 3000 Hz and downsample. + frequency_band = 1; + in_ptr = hp_120; // [2000 - 4000] Hz. + hp_out_ptr = hp_60; // [3000 - 4000] Hz. + lp_out_ptr = lp_60; // [2000 - 3000] Hz. + SplitFilter(in_ptr, length, &self->upper_state[frequency_band], + &self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr); + + // Energy in 3000 Hz - 4000 Hz. + length >>= 1; // |data_length| / 4 <=> bandwidth = 1000 Hz. + + LogOfEnergy(hp_60, length, kOffsetVector[5], &total_energy, &features[5]); + + // Energy in 2000 Hz - 3000 Hz. + LogOfEnergy(lp_60, length, kOffsetVector[4], &total_energy, &features[4]); + + // For the lower band (0 Hz - 2000 Hz) split at 1000 Hz and downsample. + frequency_band = 2; + in_ptr = lp_120; // [0 - 2000] Hz. + hp_out_ptr = hp_60; // [1000 - 2000] Hz. + lp_out_ptr = lp_60; // [0 - 1000] Hz. + length = half_data_length; // |data_length| / 2 <=> bandwidth = 2000 Hz. + SplitFilter(in_ptr, length, &self->upper_state[frequency_band], + &self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr); + + // Energy in 1000 Hz - 2000 Hz. + length >>= 1; // |data_length| / 4 <=> bandwidth = 1000 Hz. + LogOfEnergy(hp_60, length, kOffsetVector[3], &total_energy, &features[3]); + + // For the lower band (0 Hz - 1000 Hz) split at 500 Hz and downsample. + frequency_band = 3; + in_ptr = lp_60; // [0 - 1000] Hz. + hp_out_ptr = hp_120; // [500 - 1000] Hz. + lp_out_ptr = lp_120; // [0 - 500] Hz. + SplitFilter(in_ptr, length, &self->upper_state[frequency_band], + &self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr); + + // Energy in 500 Hz - 1000 Hz. + length >>= 1; // |data_length| / 8 <=> bandwidth = 500 Hz. + LogOfEnergy(hp_120, length, kOffsetVector[2], &total_energy, &features[2]); + + // For the lower band (0 Hz - 500 Hz) split at 250 Hz and downsample. + frequency_band = 4; + in_ptr = lp_120; // [0 - 500] Hz. + hp_out_ptr = hp_60; // [250 - 500] Hz. + lp_out_ptr = lp_60; // [0 - 250] Hz. + SplitFilter(in_ptr, length, &self->upper_state[frequency_band], + &self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr); + + // Energy in 250 Hz - 500 Hz. + length >>= 1; // |data_length| / 16 <=> bandwidth = 250 Hz. + LogOfEnergy(hp_60, length, kOffsetVector[1], &total_energy, &features[1]); + + // Remove 0 Hz - 80 Hz, by high pass filtering the lower band. + HighPassFilter(lp_60, length, self->hp_filter_state, hp_120); + + // Energy in 80 Hz - 250 Hz. + LogOfEnergy(hp_120, length, kOffsetVector[0], &total_energy, &features[0]); + + return total_energy; +} diff --git a/libs/miniwebrtc/audio/common/vad/vad_filterbank.h b/libs/miniwebrtc/audio/common/vad/vad_filterbank.h new file mode 100644 index 00000000..0c5c00c6 --- /dev/null +++ b/libs/miniwebrtc/audio/common/vad/vad_filterbank.h @@ -0,0 +1,44 @@ +/* + * 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 includes feature calculating functionality used in vad_core.c. + */ + +#ifndef WEBRTC_COMMON_AUDIO_VAD_VAD_FILTERBANK_H_ +#define WEBRTC_COMMON_AUDIO_VAD_VAD_FILTERBANK_H_ + +#include "typedefs.h" +#include "vad_core.h" + +// Takes |data_length| samples of |data_in| and calculates the logarithm of the +// energy of each of the |NUM_CHANNELS| = 6 frequency bands used by the VAD: +// 80 Hz - 250 Hz +// 250 Hz - 500 Hz +// 500 Hz - 1000 Hz +// 1000 Hz - 2000 Hz +// 2000 Hz - 3000 Hz +// 3000 Hz - 4000 Hz +// +// The values are given in Q4 and written to |features|. Further, an approximate +// overall energy is returned. The return value is used in +// WebRtcVad_GmmProbability() as a signal indicator, hence it is arbitrary above +// the threshold MIN_ENERGY. +// +// - self [i/o] : State information of the VAD. +// - data_in [i] : Input audio data, for feature extraction. +// - data_length [i] : Audio data size, in number of samples. +// - features [o] : 10 * log10(energy in each frequency band), Q4. +// - returns : Total energy of the signal (NOTE! This value is not +// exact. It is only used in a comparison.) +int16_t WebRtcVad_CalculateFeatures(VadInstT* self, const int16_t* data_in, + int data_length, int16_t* features); + +#endif // WEBRTC_COMMON_AUDIO_VAD_VAD_FILTERBANK_H_ diff --git a/libs/miniwebrtc/audio/common/vad/vad_gmm.c b/libs/miniwebrtc/audio/common/vad/vad_gmm.c new file mode 100644 index 00000000..20a703af --- /dev/null +++ b/libs/miniwebrtc/audio/common/vad/vad_gmm.c @@ -0,0 +1,83 @@ +/* + * 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 "vad_gmm.h" + +#include "signal_processing_library.h" +#include "typedefs.h" + +static const int32_t kCompVar = 22005; +static const int16_t kLog2Exp = 5909; // log2(exp(1)) in Q12. + +// For a normal distribution, the probability of |input| is calculated and +// returned (in Q20). The formula for normal distributed probability is +// +// 1 / s * exp(-(x - m)^2 / (2 * s^2)) +// +// where the parameters are given in the following Q domains: +// m = |mean| (Q7) +// s = |std| (Q7) +// x = |input| (Q4) +// in addition to the probability we output |delta| (in Q11) used when updating +// the noise/speech model. +int32_t WebRtcVad_GaussianProbability(int16_t input, + int16_t mean, + int16_t std, + int16_t* delta) { + int16_t tmp16, inv_std, inv_std2, exp_value = 0; + int32_t tmp32; + + // Calculate |inv_std| = 1 / s, in Q10. + // 131072 = 1 in Q17, and (|std| >> 1) is for rounding instead of truncation. + // Q-domain: Q17 / Q7 = Q10. + tmp32 = (int32_t) 131072 + (int32_t) (std >> 1); + inv_std = (int16_t) WebRtcSpl_DivW32W16(tmp32, std); + + // Calculate |inv_std2| = 1 / s^2, in Q14. + tmp16 = (inv_std >> 2); // Q10 -> Q8. + // Q-domain: (Q8 * Q8) >> 2 = Q14. + inv_std2 = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(tmp16, tmp16, 2); + // TODO(bjornv): Investigate if changing to + // |inv_std2| = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(|inv_std|, |inv_std|, 6); + // gives better accuracy. + + tmp16 = (input << 3); // Q4 -> Q7 + tmp16 = tmp16 - mean; // Q7 - Q7 = Q7 + + // To be used later, when updating noise/speech model. + // |delta| = (x - m) / s^2, in Q11. + // Q-domain: (Q14 * Q7) >> 10 = Q11. + *delta = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(inv_std2, tmp16, 10); + + // Calculate the exponent |tmp32| = (x - m)^2 / (2 * s^2), in Q10. Replacing + // division by two with one shift. + // Q-domain: (Q11 * Q7) >> 8 = Q10. + tmp32 = WEBRTC_SPL_MUL_16_16_RSFT(*delta, tmp16, 9); + + // If the exponent is small enough to give a non-zero probability we calculate + // |exp_value| ~= exp(-(x - m)^2 / (2 * s^2)) + // ~= exp2(-log2(exp(1)) * |tmp32|). + if (tmp32 < kCompVar) { + // Calculate |tmp16| = log2(exp(1)) * |tmp32|, in Q10. + // Q-domain: (Q12 * Q10) >> 12 = Q10. + tmp16 = (int16_t) WEBRTC_SPL_MUL_16_16_RSFT(kLog2Exp, (int16_t) tmp32, 12); + tmp16 = -tmp16; + exp_value = (0x0400 | (tmp16 & 0x03FF)); + tmp16 ^= 0xFFFF; + tmp16 >>= 10; + tmp16 += 1; + // Get |exp_value| = exp(-|tmp32|) in Q10. + exp_value >>= tmp16; + } + + // Calculate and return (1 / s) * exp(-(x - m)^2 / (2 * s^2)), in Q20. + // Q-domain: Q10 * Q10 = Q20. + return WEBRTC_SPL_MUL_16_16(inv_std, exp_value); +} diff --git a/libs/miniwebrtc/audio/common/vad/vad_gmm.h b/libs/miniwebrtc/audio/common/vad/vad_gmm.h new file mode 100644 index 00000000..2333af7e --- /dev/null +++ b/libs/miniwebrtc/audio/common/vad/vad_gmm.h @@ -0,0 +1,39 @@ +/* + * 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. + */ + +// Gaussian probability calculations internally used in vad_core.c. + +#ifndef WEBRTC_COMMON_AUDIO_VAD_VAD_GMM_H_ +#define WEBRTC_COMMON_AUDIO_VAD_VAD_GMM_H_ + +#include "typedefs.h" + +// Calculates the probability for |input|, given that |input| comes from a +// normal distribution with mean and standard deviation (|mean|, |std|). +// +// Inputs: +// - input : input sample in Q4. +// - mean : mean input in the statistical model, Q7. +// - std : standard deviation, Q7. +// +// Output: +// +// - delta : input used when updating the model, Q11. +// |delta| = (|input| - |mean|) / |std|^2. +// +// Return: +// (probability for |input|) = +// 1 / |std| * exp(-(|input| - |mean|)^2 / (2 * |std|^2)); +int32_t WebRtcVad_GaussianProbability(int16_t input, + int16_t mean, + int16_t std, + int16_t* delta); + +#endif // WEBRTC_COMMON_AUDIO_VAD_VAD_GMM_H_ diff --git a/libs/miniwebrtc/audio/common/vad/vad_sp.c b/libs/miniwebrtc/audio/common/vad/vad_sp.c new file mode 100644 index 00000000..4fface3a --- /dev/null +++ b/libs/miniwebrtc/audio/common/vad/vad_sp.c @@ -0,0 +1,181 @@ +/* + * 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 "vad_sp.h" + +#include + +#include "signal_processing_library.h" +#include "typedefs.h" +#include "vad_defines.h" + +// Allpass filter coefficients, upper and lower, in Q13. +// Upper: 0.64, Lower: 0.17. +static const int16_t kAllPassCoefsQ13[2] = { 5243, 1392 }; // Q13 + +// TODO(bjornv): Move this function to vad_filterbank.c. +// Downsampling filter based on splitting filter and allpass functions. +void WebRtcVad_Downsampling(int16_t* signal_in, + int16_t* signal_out, + int32_t* filter_state, + int in_length) { + int16_t tmp16_1 = 0, tmp16_2 = 0; + int32_t tmp32_1 = filter_state[0]; + int32_t tmp32_2 = filter_state[1]; + int n = 0; + int half_length = (in_length >> 1); // Downsampling by 2 gives half length. + + // Filter coefficients in Q13, filter state in Q0. + for (n = 0; n < half_length; n++) { + // All-pass filtering upper branch. + tmp16_1 = (int16_t) ((tmp32_1 >> 1) + + WEBRTC_SPL_MUL_16_16_RSFT(kAllPassCoefsQ13[0], *signal_in, 14)); + *signal_out = tmp16_1; + tmp32_1 = (int32_t) (*signal_in++) - + WEBRTC_SPL_MUL_16_16_RSFT(kAllPassCoefsQ13[0], tmp16_1, 12); + + // All-pass filtering lower branch. + tmp16_2 = (int16_t) ((tmp32_2 >> 1) + + WEBRTC_SPL_MUL_16_16_RSFT(kAllPassCoefsQ13[1], *signal_in, 14)); + *signal_out++ += tmp16_2; + tmp32_2 = (int32_t) (*signal_in++) - + WEBRTC_SPL_MUL_16_16_RSFT(kAllPassCoefsQ13[1], tmp16_2, 12); + } + // Store the filter states. + filter_state[0] = tmp32_1; + filter_state[1] = tmp32_2; +} + +// Inserts |feature_value| into |low_value_vector|, if it is one of the 16 +// smallest values the last 100 frames. Then calculates and returns the median +// of the five smallest values. +int16_t WebRtcVad_FindMinimum(VadInstT* self, + int16_t feature_value, + int channel) { + int i = 0, j = 0; + int position = -1; + // Offset to beginning of the 16 minimum values in memory. + int offset = (channel << 4); + int16_t current_median = 1600; + int16_t alpha = 0; + int32_t tmp32 = 0; + // Pointer to memory for the 16 minimum values and the age of each value of + // the |channel|. + int16_t* age_ptr = &self->index_vector[offset]; + int16_t* value_ptr = &self->low_value_vector[offset]; + int16_t *p1, *p2, *p3; + + assert(channel < NUM_CHANNELS); + + // Each value in |low_value_vector| is getting 1 loop older. + // Update age of each value in |age_ptr|, and remove old values. + for (i = 0; i < 16; i++) { + p3 = age_ptr + i; + if (*p3 != 100) { + *p3 += 1; + } else { + p1 = value_ptr + i + 1; + p2 = p3 + 1; + for (j = i; j < 16; j++) { + *(value_ptr + j) = *p1++; + *(age_ptr + j) = *p2++; + } + *(age_ptr + 15) = 101; + *(value_ptr + 15) = 10000; + } + } + + // Check if |feature_value| is smaller than any of the values in + // |low_value_vector|. If so, find the |position| where to insert the new + // value. + if (feature_value < *(value_ptr + 7)) { + if (feature_value < *(value_ptr + 3)) { + if (feature_value < *(value_ptr + 1)) { + if (feature_value < *value_ptr) { + position = 0; + } else { + position = 1; + } + } else if (feature_value < *(value_ptr + 2)) { + position = 2; + } else { + position = 3; + } + } else if (feature_value < *(value_ptr + 5)) { + if (feature_value < *(value_ptr + 4)) { + position = 4; + } else { + position = 5; + } + } else if (feature_value < *(value_ptr + 6)) { + position = 6; + } else { + position = 7; + } + } else if (feature_value < *(value_ptr + 15)) { + if (feature_value < *(value_ptr + 11)) { + if (feature_value < *(value_ptr + 9)) { + if (feature_value < *(value_ptr + 8)) { + position = 8; + } else { + position = 9; + } + } else if (feature_value < *(value_ptr + 10)) { + position = 10; + } else { + position = 11; + } + } else if (feature_value < *(value_ptr + 13)) { + if (feature_value < *(value_ptr + 12)) { + position = 12; + } else { + position = 13; + } + } else if (feature_value < *(value_ptr + 14)) { + position = 14; + } else { + position = 15; + } + } + + // If we have a new small value, put it in the correct position and shift + // larger values up. + if (position > -1) { + for (i = 15; i > position; i--) { + j = i - 1; + *(value_ptr + i) = *(value_ptr + j); + *(age_ptr + i) = *(age_ptr + j); + } + *(value_ptr + position) = feature_value; + *(age_ptr + position) = 1; + } + + // Get |current_median|. + if (self->frame_counter > 2) { + current_median = *(value_ptr + 2); + } else if (self->frame_counter > 0) { + current_median = *value_ptr; + } + + // Smooth the median value. + if (self->frame_counter > 0) { + if (current_median < self->mean_value[channel]) { + alpha = (int16_t) ALPHA1; // 0.2 in Q15. + } else { + alpha = (int16_t) ALPHA2; // 0.99 in Q15. + } + } + tmp32 = WEBRTC_SPL_MUL_16_16(alpha + 1, self->mean_value[channel]); + tmp32 += WEBRTC_SPL_MUL_16_16(WEBRTC_SPL_WORD16_MAX - alpha, current_median); + tmp32 += 16384; + self->mean_value[channel] = (int16_t) (tmp32 >> 15); + + return self->mean_value[channel]; +} diff --git a/libs/miniwebrtc/audio/common/vad/vad_sp.h b/libs/miniwebrtc/audio/common/vad/vad_sp.h new file mode 100644 index 00000000..9e8b204e --- /dev/null +++ b/libs/miniwebrtc/audio/common/vad/vad_sp.h @@ -0,0 +1,56 @@ +/* + * 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 includes specific signal processing tools used in vad_core.c. + +#ifndef WEBRTC_COMMON_AUDIO_VAD_VAD_SP_H_ +#define WEBRTC_COMMON_AUDIO_VAD_VAD_SP_H_ + +#include "typedefs.h" +#include "vad_core.h" + +// Downsamples the signal by a factor 2, eg. 32->16 or 16->8. +// +// Inputs: +// - signal_in : Input signal. +// - in_length : Length of input signal in samples. +// +// Input & Output: +// - filter_state : Current filter states of the two all-pass filters. The +// |filter_state| is updated after all samples have been +// processed. +// +// Output: +// - signal_out : Downsampled signal (of length |in_length| / 2). +void WebRtcVad_Downsampling(int16_t* signal_in, + int16_t* signal_out, + int32_t* filter_state, + int in_length); + +// Updates and returns the smoothed feature minimum. As minimum we use the +// median of the five smallest feature values in a 100 frames long window. +// As long as |handle->frame_counter| is zero, that is, we haven't received any +// "valid" data, FindMinimum() outputs the default value of 1600. +// +// Inputs: +// - feature_value : New feature value to update with. +// - channel : Channel number. +// +// Input & Output: +// - handle : State information of the VAD. +// +// Returns: +// : Smoothed minimum value for a moving window. +int16_t WebRtcVad_FindMinimum(VadInstT* handle, + int16_t feature_value, + int channel); + +#endif // WEBRTC_COMMON_AUDIO_VAD_VAD_SP_H_ diff --git a/libs/miniwebrtc/audio/common/vad/webrtc_vad.c b/libs/miniwebrtc/audio/common/vad/webrtc_vad.c new file mode 100644 index 00000000..26941e6d --- /dev/null +++ b/libs/miniwebrtc/audio/common/vad/webrtc_vad.c @@ -0,0 +1,165 @@ +/* + * 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. + */ + + +/* + * This file includes the VAD API calls. For a specific function call description, + * see webrtc_vad.h + */ + +#include +#include + +#include "webrtc_vad.h" +#include "vad_core.h" + +static const int kInitCheck = 42; + +WebRtc_Word16 WebRtcVad_AssignSize(int *size_in_bytes) +{ + *size_in_bytes = sizeof(VadInstT) * 2 / sizeof(WebRtc_Word16); + return 0; +} + +WebRtc_Word16 WebRtcVad_Assign(VadInst **vad_inst, void *vad_inst_addr) +{ + + if (vad_inst == NULL) + { + return -1; + } + + if (vad_inst_addr != NULL) + { + *vad_inst = (VadInst*)vad_inst_addr; + return 0; + } else + { + return -1; + } +} + +int WebRtcVad_Create(VadInst** handle) { + VadInstT* self = NULL; + + if (handle == NULL) { + return -1; + } + + *handle = NULL; + self = (VadInstT*) malloc(sizeof(VadInstT)); + *handle = (VadInst*) self; + + if (self == NULL) { + return -1; + } + + self->init_flag = 0; + + return 0; +} + +int WebRtcVad_Free(VadInst* handle) { + if (handle == NULL) { + return -1; + } + + free(handle); + + return 0; +} + +int WebRtcVad_Init(VadInst* handle) { + // Initialize the core VAD component. + return WebRtcVad_InitCore((VadInstT*) handle); +} + +int WebRtcVad_set_mode(VadInst *vad_inst, int mode) +{ + VadInstT* vad_ptr; + + if (vad_inst == NULL) + { + return -1; + } + + vad_ptr = (VadInstT*)vad_inst; + if (vad_ptr->init_flag != kInitCheck) + { + return -1; + } + + return WebRtcVad_set_mode_core((VadInstT*)vad_inst, mode); +} + +WebRtc_Word16 WebRtcVad_Process(VadInst *vad_inst, + WebRtc_Word16 fs, + WebRtc_Word16 *speech_frame, + WebRtc_Word16 frame_length) +{ + WebRtc_Word16 vad; + VadInstT* vad_ptr; + + if (vad_inst == NULL) + { + return -1; + } + + vad_ptr = (VadInstT*)vad_inst; + if (vad_ptr->init_flag != kInitCheck) + { + return -1; + } + + if (speech_frame == NULL) + { + return -1; + } + + if (fs == 32000) + { + if ((frame_length != 320) && (frame_length != 640) && (frame_length != 960)) + { + return -1; + } + vad = WebRtcVad_CalcVad32khz((VadInstT*)vad_inst, speech_frame, frame_length); + + } else if (fs == 16000) + { + if ((frame_length != 160) && (frame_length != 320) && (frame_length != 480)) + { + return -1; + } + vad = WebRtcVad_CalcVad16khz((VadInstT*)vad_inst, speech_frame, frame_length); + + } else if (fs == 8000) + { + if ((frame_length != 80) && (frame_length != 160) && (frame_length != 240)) + { + return -1; + } + vad = WebRtcVad_CalcVad8khz((VadInstT*)vad_inst, speech_frame, frame_length); + + } else + { + return -1; // Not a supported sampling frequency + } + + if (vad > 0) + { + return 1; + } else if (vad == 0) + { + return 0; + } else + { + return -1; + } +} diff --git a/libs/miniwebrtc/audio/common/vad/webrtc_vad.h b/libs/miniwebrtc/audio/common/vad/webrtc_vad.h new file mode 100644 index 00000000..3f9e4023 --- /dev/null +++ b/libs/miniwebrtc/audio/common/vad/webrtc_vad.h @@ -0,0 +1,130 @@ +/* + * 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. + */ + + +/* + * This header file includes the VAD API calls. Specific function calls are given below. + */ + +#ifndef WEBRTC_COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_ +#define WEBRTC_COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_ + +#include "typedefs.h" + +typedef struct WebRtcVadInst VadInst; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/**************************************************************************** + * WebRtcVad_AssignSize(...) + * + * This functions get the size needed for storing the instance for encoder + * and decoder, respectively + * + * Input/Output: + * - size_in_bytes : Pointer to integer where the size is returned + * + * Return value : 0 + */ +WebRtc_Word16 WebRtcVad_AssignSize(int *size_in_bytes); + +/**************************************************************************** + * WebRtcVad_Assign(...) + * + * This functions Assigns memory for the instances. + * + * Input: + * - vad_inst_addr : Address to where to assign memory + * Output: + * - vad_inst : Pointer to the instance that should be created + * + * Return value : 0 - Ok + * -1 - Error + */ +WebRtc_Word16 WebRtcVad_Assign(VadInst **vad_inst, void *vad_inst_addr); + +// Creates an instance to the VAD structure. +// +// - handle [o] : Pointer to the VAD instance that should be created. +// +// returns : 0 - (OK), -1 - (Error) +int WebRtcVad_Create(VadInst** handle); + +// Frees the dynamic memory of a specified VAD instance. +// +// - handle [i] : Pointer to VAD instance that should be freed. +// +// returns : 0 - (OK), -1 - (NULL pointer in) +int WebRtcVad_Free(VadInst* handle); + +/**************************************************************************** + * WebRtcVad_Init(...) + * + * This function initializes a VAD instance + * + * Input: + * - vad_inst : Instance that should be initialized + * + * Output: + * - vad_inst : Initialized instance + * + * Return value : 0 - Ok + * -1 - Error + */ +int WebRtcVad_Init(VadInst *vad_inst); + +/**************************************************************************** + * WebRtcVad_set_mode(...) + * + * This function initializes a VAD instance + * + * Input: + * - vad_inst : VAD instance + * - mode : Aggressiveness setting (0, 1, 2, or 3) + * + * Output: + * - vad_inst : Initialized instance + * + * Return value : 0 - Ok + * -1 - Error + */ +int WebRtcVad_set_mode(VadInst *vad_inst, int mode); + +/**************************************************************************** + * WebRtcVad_Process(...) + * + * This functions does a VAD for the inserted speech frame + * + * Input + * - vad_inst : VAD Instance. Needs to be initiated before call. + * - fs : sampling frequency (Hz): 8000, 16000, or 32000 + * - speech_frame : Pointer to speech frame buffer + * - frame_length : Length of speech frame buffer in number of samples + * + * Output: + * - vad_inst : Updated VAD instance + * + * Return value : 1 - Active Voice + * 0 - Non-active Voice + * -1 - Error + */ +WebRtc_Word16 WebRtcVad_Process(VadInst *vad_inst, + WebRtc_Word16 fs, + WebRtc_Word16 *speech_frame, + WebRtc_Word16 frame_length); + +#ifdef __cplusplus +} +#endif + +#endif // WEBRTC_COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_ diff --git a/libs/miniwebrtc/audio/processing/aec/aec_core.c b/libs/miniwebrtc/audio/processing/aec/aec_core.c new file mode 100644 index 00000000..4d838d4f --- /dev/null +++ b/libs/miniwebrtc/audio/processing/aec/aec_core.c @@ -0,0 +1,1528 @@ +/* + * 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. + */ + +/* + * The core AEC algorithm, which is presented with time-aligned signals. + */ + +#include "aec_core.h" + +#include +#include +#include // size_t +#include +#include + +#include "aec_rdft.h" +#include "signal_processing_library.h" +#include "delay_estimator_wrapper.h" +#include "ring_buffer.h" +#include "cpu_features_wrapper.h" +#include "typedefs.h" + +// Buffer size (samples) +static const size_t kBufSizePartitions = 250; // 1 second of audio in 16 kHz. + +// Noise suppression +static const int converged = 250; + +// Metrics +static const int subCountLen = 4; +static const int countLen = 50; + +// Quantities to control H band scaling for SWB input +static const int flagHbandCn = 1; // flag for adding comfort noise in H band +static const float cnScaleHband = (float)0.4; // scale for comfort noise in H band +// Initial bin for averaging nlp gain in low band +static const int freqAvgIc = PART_LEN / 2; + +// Matlab code to produce table: +// win = sqrt(hanning(63)); win = [0 ; win(1:32)]; +// fprintf(1, '\t%.14f, %.14f, %.14f,\n', win); +static const float sqrtHanning[65] = { + 0.00000000000000f, 0.02454122852291f, 0.04906767432742f, + 0.07356456359967f, 0.09801714032956f, 0.12241067519922f, + 0.14673047445536f, 0.17096188876030f, 0.19509032201613f, + 0.21910124015687f, 0.24298017990326f, 0.26671275747490f, + 0.29028467725446f, 0.31368174039889f, 0.33688985339222f, + 0.35989503653499f, 0.38268343236509f, 0.40524131400499f, + 0.42755509343028f, 0.44961132965461f, 0.47139673682600f, + 0.49289819222978f, 0.51410274419322f, 0.53499761988710f, + 0.55557023301960f, 0.57580819141785f, 0.59569930449243f, + 0.61523159058063f, 0.63439328416365f, 0.65317284295378f, + 0.67155895484702f, 0.68954054473707f, 0.70710678118655f, + 0.72424708295147f, 0.74095112535496f, 0.75720884650648f, + 0.77301045336274f, 0.78834642762661f, 0.80320753148064f, + 0.81758481315158f, 0.83146961230255f, 0.84485356524971f, + 0.85772861000027f, 0.87008699110871f, 0.88192126434835f, + 0.89322430119552f, 0.90398929312344f, 0.91420975570353f, + 0.92387953251129f, 0.93299279883474f, 0.94154406518302f, + 0.94952818059304f, 0.95694033573221f, 0.96377606579544f, + 0.97003125319454f, 0.97570213003853f, 0.98078528040323f, + 0.98527764238894f, 0.98917650996478f, 0.99247953459871f, + 0.99518472667220f, 0.99729045667869f, 0.99879545620517f, + 0.99969881869620f, 1.00000000000000f +}; + +// Matlab code to produce table: +// weightCurve = [0 ; 0.3 * sqrt(linspace(0,1,64))' + 0.1]; +// fprintf(1, '\t%.4f, %.4f, %.4f, %.4f, %.4f, %.4f,\n', weightCurve); +const float WebRtcAec_weightCurve[65] = { + 0.0000f, 0.1000f, 0.1378f, 0.1535f, 0.1655f, 0.1756f, + 0.1845f, 0.1926f, 0.2000f, 0.2069f, 0.2134f, 0.2195f, + 0.2254f, 0.2309f, 0.2363f, 0.2414f, 0.2464f, 0.2512f, + 0.2558f, 0.2604f, 0.2648f, 0.2690f, 0.2732f, 0.2773f, + 0.2813f, 0.2852f, 0.2890f, 0.2927f, 0.2964f, 0.3000f, + 0.3035f, 0.3070f, 0.3104f, 0.3138f, 0.3171f, 0.3204f, + 0.3236f, 0.3268f, 0.3299f, 0.3330f, 0.3360f, 0.3390f, + 0.3420f, 0.3449f, 0.3478f, 0.3507f, 0.3535f, 0.3563f, + 0.3591f, 0.3619f, 0.3646f, 0.3673f, 0.3699f, 0.3726f, + 0.3752f, 0.3777f, 0.3803f, 0.3828f, 0.3854f, 0.3878f, + 0.3903f, 0.3928f, 0.3952f, 0.3976f, 0.4000f +}; + +// Matlab code to produce table: +// overDriveCurve = [sqrt(linspace(0,1,65))' + 1]; +// fprintf(1, '\t%.4f, %.4f, %.4f, %.4f, %.4f, %.4f,\n', overDriveCurve); +const float WebRtcAec_overDriveCurve[65] = { + 1.0000f, 1.1250f, 1.1768f, 1.2165f, 1.2500f, 1.2795f, + 1.3062f, 1.3307f, 1.3536f, 1.3750f, 1.3953f, 1.4146f, + 1.4330f, 1.4507f, 1.4677f, 1.4841f, 1.5000f, 1.5154f, + 1.5303f, 1.5449f, 1.5590f, 1.5728f, 1.5863f, 1.5995f, + 1.6124f, 1.6250f, 1.6374f, 1.6495f, 1.6614f, 1.6731f, + 1.6847f, 1.6960f, 1.7071f, 1.7181f, 1.7289f, 1.7395f, + 1.7500f, 1.7603f, 1.7706f, 1.7806f, 1.7906f, 1.8004f, + 1.8101f, 1.8197f, 1.8292f, 1.8385f, 1.8478f, 1.8570f, + 1.8660f, 1.8750f, 1.8839f, 1.8927f, 1.9014f, 1.9100f, + 1.9186f, 1.9270f, 1.9354f, 1.9437f, 1.9520f, 1.9601f, + 1.9682f, 1.9763f, 1.9843f, 1.9922f, 2.0000f +}; + +// "Private" function prototypes. +static void ProcessBlock(aec_t* aec); + +static void NonLinearProcessing(aec_t *aec, short *output, short *outputH); + +static void GetHighbandGain(const float *lambda, float *nlpGainHband); + +// Comfort_noise also computes noise for H band returned in comfortNoiseHband +static void ComfortNoise(aec_t *aec, float efw[2][PART_LEN1], + complex_t *comfortNoiseHband, + const float *noisePow, const float *lambda); + +static void WebRtcAec_InitLevel(power_level_t *level); +static void WebRtcAec_InitStats(stats_t *stats); +static void UpdateLevel(power_level_t* level, float in[2][PART_LEN1]); +static void UpdateMetrics(aec_t *aec); +// Convert from time domain to frequency domain. Note that |time_data| are +// overwritten. +static void TimeToFrequency(float time_data[PART_LEN2], + float freq_data[2][PART_LEN1], + int window); + +__inline static float MulRe(float aRe, float aIm, float bRe, float bIm) +{ + return aRe * bRe - aIm * bIm; +} + +__inline static float MulIm(float aRe, float aIm, float bRe, float bIm) +{ + return aRe * bIm + aIm * bRe; +} + +static int CmpFloat(const void *a, const void *b) +{ + const float *da = (const float *)a; + const float *db = (const float *)b; + + return (*da > *db) - (*da < *db); +} + +int WebRtcAec_CreateAec(aec_t **aecInst) +{ + aec_t *aec = malloc(sizeof(aec_t)); + *aecInst = aec; + if (aec == NULL) { + return -1; + } + + if (WebRtc_CreateBuffer(&aec->nearFrBuf, + FRAME_LEN + PART_LEN, + sizeof(int16_t)) == -1) { + WebRtcAec_FreeAec(aec); + aec = NULL; + return -1; + } + + if (WebRtc_CreateBuffer(&aec->outFrBuf, + FRAME_LEN + PART_LEN, + sizeof(int16_t)) == -1) { + WebRtcAec_FreeAec(aec); + aec = NULL; + return -1; + } + + if (WebRtc_CreateBuffer(&aec->nearFrBufH, + FRAME_LEN + PART_LEN, + sizeof(int16_t)) == -1) { + WebRtcAec_FreeAec(aec); + aec = NULL; + return -1; + } + + if (WebRtc_CreateBuffer(&aec->outFrBufH, + FRAME_LEN + PART_LEN, + sizeof(int16_t)) == -1) { + WebRtcAec_FreeAec(aec); + aec = NULL; + return -1; + } + + // Create far-end buffers. + if (WebRtc_CreateBuffer(&aec->far_buf, kBufSizePartitions, + sizeof(float) * 2 * PART_LEN1) == -1) { + WebRtcAec_FreeAec(aec); + aec = NULL; + return -1; + } + if (WebRtc_CreateBuffer(&aec->far_buf_windowed, kBufSizePartitions, + sizeof(float) * 2 * PART_LEN1) == -1) { + WebRtcAec_FreeAec(aec); + aec = NULL; + return -1; + } +#ifdef WEBRTC_AEC_DEBUG_DUMP + if (WebRtc_CreateBuffer(&aec->far_time_buf, kBufSizePartitions, + sizeof(int16_t) * PART_LEN) == -1) { + WebRtcAec_FreeAec(aec); + aec = NULL; + return -1; + } +#endif + if (WebRtc_CreateDelayEstimator(&aec->delay_estimator, + PART_LEN1, + kMaxDelayBlocks, + kLookaheadBlocks) == -1) { + WebRtcAec_FreeAec(aec); + aec = NULL; + return -1; + } + + return 0; +} + +int WebRtcAec_FreeAec(aec_t *aec) +{ + if (aec == NULL) { + return -1; + } + + WebRtc_FreeBuffer(aec->nearFrBuf); + WebRtc_FreeBuffer(aec->outFrBuf); + + WebRtc_FreeBuffer(aec->nearFrBufH); + WebRtc_FreeBuffer(aec->outFrBufH); + + WebRtc_FreeBuffer(aec->far_buf); + WebRtc_FreeBuffer(aec->far_buf_windowed); +#ifdef WEBRTC_AEC_DEBUG_DUMP + WebRtc_FreeBuffer(aec->far_time_buf); +#endif + WebRtc_FreeDelayEstimator(aec->delay_estimator); + + free(aec); + return 0; +} + +static void FilterFar(aec_t *aec, float yf[2][PART_LEN1]) +{ + int i; + for (i = 0; i < NR_PART; i++) { + int j; + int xPos = (i + aec->xfBufBlockPos) * PART_LEN1; + int pos = i * PART_LEN1; + // Check for wrap + if (i + aec->xfBufBlockPos >= NR_PART) { + xPos -= NR_PART*(PART_LEN1); + } + + for (j = 0; j < PART_LEN1; j++) { + yf[0][j] += MulRe(aec->xfBuf[0][xPos + j], aec->xfBuf[1][xPos + j], + aec->wfBuf[0][ pos + j], aec->wfBuf[1][ pos + j]); + yf[1][j] += MulIm(aec->xfBuf[0][xPos + j], aec->xfBuf[1][xPos + j], + aec->wfBuf[0][ pos + j], aec->wfBuf[1][ pos + j]); + } + } +} + +static void ScaleErrorSignal(aec_t *aec, float ef[2][PART_LEN1]) +{ + int i; + float absEf; + for (i = 0; i < (PART_LEN1); i++) { + ef[0][i] /= (aec->xPow[i] + 1e-10f); + ef[1][i] /= (aec->xPow[i] + 1e-10f); + absEf = sqrtf(ef[0][i] * ef[0][i] + ef[1][i] * ef[1][i]); + + if (absEf > aec->errThresh) { + absEf = aec->errThresh / (absEf + 1e-10f); + ef[0][i] *= absEf; + ef[1][i] *= absEf; + } + + // Stepsize factor + ef[0][i] *= aec->mu; + ef[1][i] *= aec->mu; + } +} + +// Time-unconstrined filter adaptation. +// TODO(andrew): consider for a low-complexity mode. +//static void FilterAdaptationUnconstrained(aec_t *aec, float *fft, +// float ef[2][PART_LEN1]) { +// int i, j; +// for (i = 0; i < NR_PART; i++) { +// int xPos = (i + aec->xfBufBlockPos)*(PART_LEN1); +// int pos; +// // Check for wrap +// if (i + aec->xfBufBlockPos >= NR_PART) { +// xPos -= NR_PART * PART_LEN1; +// } +// +// pos = i * PART_LEN1; +// +// for (j = 0; j < PART_LEN1; j++) { +// aec->wfBuf[pos + j][0] += MulRe(aec->xfBuf[xPos + j][0], +// -aec->xfBuf[xPos + j][1], +// ef[j][0], ef[j][1]); +// aec->wfBuf[pos + j][1] += MulIm(aec->xfBuf[xPos + j][0], +// -aec->xfBuf[xPos + j][1], +// ef[j][0], ef[j][1]); +// } +// } +//} + +static void FilterAdaptation(aec_t *aec, float *fft, float ef[2][PART_LEN1]) { + int i, j; + for (i = 0; i < NR_PART; i++) { + int xPos = (i + aec->xfBufBlockPos)*(PART_LEN1); + int pos; + // Check for wrap + if (i + aec->xfBufBlockPos >= NR_PART) { + xPos -= NR_PART * PART_LEN1; + } + + pos = i * PART_LEN1; + + for (j = 0; j < PART_LEN; j++) { + + fft[2 * j] = MulRe(aec->xfBuf[0][xPos + j], + -aec->xfBuf[1][xPos + j], + ef[0][j], ef[1][j]); + fft[2 * j + 1] = MulIm(aec->xfBuf[0][xPos + j], + -aec->xfBuf[1][xPos + j], + ef[0][j], ef[1][j]); + } + fft[1] = MulRe(aec->xfBuf[0][xPos + PART_LEN], + -aec->xfBuf[1][xPos + PART_LEN], + ef[0][PART_LEN], ef[1][PART_LEN]); + + aec_rdft_inverse_128(fft); + memset(fft + PART_LEN, 0, sizeof(float) * PART_LEN); + + // fft scaling + { + float scale = 2.0f / PART_LEN2; + for (j = 0; j < PART_LEN; j++) { + fft[j] *= scale; + } + } + aec_rdft_forward_128(fft); + + aec->wfBuf[0][pos] += fft[0]; + aec->wfBuf[0][pos + PART_LEN] += fft[1]; + + for (j = 1; j < PART_LEN; j++) { + aec->wfBuf[0][pos + j] += fft[2 * j]; + aec->wfBuf[1][pos + j] += fft[2 * j + 1]; + } + } +} + +static void OverdriveAndSuppress(aec_t *aec, float hNl[PART_LEN1], + const float hNlFb, + float efw[2][PART_LEN1]) { + int i; + for (i = 0; i < PART_LEN1; i++) { + // Weight subbands + if (hNl[i] > hNlFb) { + hNl[i] = WebRtcAec_weightCurve[i] * hNlFb + + (1 - WebRtcAec_weightCurve[i]) * hNl[i]; + } + hNl[i] = powf(hNl[i], aec->overDriveSm * WebRtcAec_overDriveCurve[i]); + + // Suppress error signal + efw[0][i] *= hNl[i]; + efw[1][i] *= hNl[i]; + + // Ooura fft returns incorrect sign on imaginary component. It matters here + // because we are making an additive change with comfort noise. + efw[1][i] *= -1; + } +} + +WebRtcAec_FilterFar_t WebRtcAec_FilterFar; +WebRtcAec_ScaleErrorSignal_t WebRtcAec_ScaleErrorSignal; +WebRtcAec_FilterAdaptation_t WebRtcAec_FilterAdaptation; +WebRtcAec_OverdriveAndSuppress_t WebRtcAec_OverdriveAndSuppress; + +int WebRtcAec_InitAec(aec_t *aec, int sampFreq) +{ + int i; + + aec->sampFreq = sampFreq; + + if (sampFreq == 8000) { + aec->mu = 0.6f; + aec->errThresh = 2e-6f; + } + else { + aec->mu = 0.5f; + aec->errThresh = 1.5e-6f; + } + + if (WebRtc_InitBuffer(aec->nearFrBuf) == -1) { + return -1; + } + + if (WebRtc_InitBuffer(aec->outFrBuf) == -1) { + return -1; + } + + if (WebRtc_InitBuffer(aec->nearFrBufH) == -1) { + return -1; + } + + if (WebRtc_InitBuffer(aec->outFrBufH) == -1) { + return -1; + } + + // Initialize far-end buffers. + if (WebRtc_InitBuffer(aec->far_buf) == -1) { + return -1; + } + if (WebRtc_InitBuffer(aec->far_buf_windowed) == -1) { + return -1; + } +#ifdef WEBRTC_AEC_DEBUG_DUMP + if (WebRtc_InitBuffer(aec->far_time_buf) == -1) { + return -1; + } +#endif + aec->system_delay = 0; + + if (WebRtc_InitDelayEstimator(aec->delay_estimator) != 0) { + return -1; + } + aec->delay_logging_enabled = 0; + memset(aec->delay_histogram, 0, sizeof(aec->delay_histogram)); + + // Default target suppression level + aec->targetSupp = -11.5; + aec->minOverDrive = 2.0; + + // Sampling frequency multiplier + // SWB is processed as 160 frame size + if (aec->sampFreq == 32000) { + aec->mult = (short)aec->sampFreq / 16000; + } + else { + aec->mult = (short)aec->sampFreq / 8000; + } + + aec->farBufWritePos = 0; + aec->farBufReadPos = 0; + + aec->inSamples = 0; + aec->outSamples = 0; + aec->knownDelay = 0; + + // Initialize buffers + memset(aec->dBuf, 0, sizeof(aec->dBuf)); + memset(aec->eBuf, 0, sizeof(aec->eBuf)); + // For H band + memset(aec->dBufH, 0, sizeof(aec->dBufH)); + + memset(aec->xPow, 0, sizeof(aec->xPow)); + memset(aec->dPow, 0, sizeof(aec->dPow)); + memset(aec->dInitMinPow, 0, sizeof(aec->dInitMinPow)); + aec->noisePow = aec->dInitMinPow; + aec->noiseEstCtr = 0; + + // Initial comfort noise power + for (i = 0; i < PART_LEN1; i++) { + aec->dMinPow[i] = 1.0e6f; + } + + // Holds the last block written to + aec->xfBufBlockPos = 0; + // TODO: Investigate need for these initializations. Deleting them doesn't + // change the output at all and yields 0.4% overall speedup. + memset(aec->xfBuf, 0, sizeof(complex_t) * NR_PART * PART_LEN1); + memset(aec->wfBuf, 0, sizeof(complex_t) * NR_PART * PART_LEN1); + memset(aec->sde, 0, sizeof(complex_t) * PART_LEN1); + memset(aec->sxd, 0, sizeof(complex_t) * PART_LEN1); + memset(aec->xfwBuf, 0, sizeof(complex_t) * NR_PART * PART_LEN1); + memset(aec->se, 0, sizeof(float) * PART_LEN1); + + // To prevent numerical instability in the first block. + for (i = 0; i < PART_LEN1; i++) { + aec->sd[i] = 1; + } + for (i = 0; i < PART_LEN1; i++) { + aec->sx[i] = 1; + } + + memset(aec->hNs, 0, sizeof(aec->hNs)); + memset(aec->outBuf, 0, sizeof(float) * PART_LEN); + + aec->hNlFbMin = 1; + aec->hNlFbLocalMin = 1; + aec->hNlXdAvgMin = 1; + aec->hNlNewMin = 0; + aec->hNlMinCtr = 0; + aec->overDrive = 2; + aec->overDriveSm = 2; + aec->delayIdx = 0; + aec->stNearState = 0; + aec->echoState = 0; + aec->divergeState = 0; + + aec->seed = 777; + aec->delayEstCtr = 0; + + // Metrics disabled by default + aec->metricsMode = 0; + WebRtcAec_InitMetrics(aec); + + // Assembly optimization + WebRtcAec_FilterFar = FilterFar; + WebRtcAec_ScaleErrorSignal = ScaleErrorSignal; + WebRtcAec_FilterAdaptation = FilterAdaptation; + WebRtcAec_OverdriveAndSuppress = OverdriveAndSuppress; +#ifdef SSE2_OPS +#if defined(WEBRTC_ARCH_X86_FAMILY) + if (WebRtc_GetCPUInfo(kSSE2)) { + WebRtcAec_InitAec_SSE2(); + } +#endif +#endif + + aec_rdft_init(); + + return 0; +} + +void WebRtcAec_InitMetrics(aec_t *aec) +{ + aec->stateCounter = 0; + WebRtcAec_InitLevel(&aec->farlevel); + WebRtcAec_InitLevel(&aec->nearlevel); + WebRtcAec_InitLevel(&aec->linoutlevel); + WebRtcAec_InitLevel(&aec->nlpoutlevel); + + WebRtcAec_InitStats(&aec->erl); + WebRtcAec_InitStats(&aec->erle); + WebRtcAec_InitStats(&aec->aNlp); + WebRtcAec_InitStats(&aec->rerl); +} + + +void WebRtcAec_BufferFarendPartition(aec_t *aec, const float* farend) { + float fft[PART_LEN2]; + float xf[2][PART_LEN1]; + + // Check if the buffer is full, and in that case flush the oldest data. + if (WebRtc_available_write(aec->far_buf) < 1) { + WebRtc_MoveReadPtr(aec->far_buf, 1); + WebRtc_MoveReadPtr(aec->far_buf_windowed, 1); + aec->system_delay -= PART_LEN; +#ifdef WEBRTC_AEC_DEBUG_DUMP + WebRtc_MoveReadPtr(aec->far_time_buf, 1); +#endif + } + // Convert far-end partition to the frequency domain without windowing. + memcpy(fft, farend, sizeof(float) * PART_LEN2); + TimeToFrequency(fft, xf, 0); + WebRtc_WriteBuffer(aec->far_buf, &xf[0][0], 1); + + // Convert far-end partition to the frequency domain with windowing. + memcpy(fft, farend, sizeof(float) * PART_LEN2); + TimeToFrequency(fft, xf, 1); + WebRtc_WriteBuffer(aec->far_buf_windowed, &xf[0][0], 1); +} + +void WebRtcAec_ProcessFrame(aec_t *aec, + const short *nearend, + const short *nearendH, + int knownDelay) +{ + // For each frame the process is as follows: + // 1) If the system_delay indicates on being too small for processing a + // frame we stuff the buffer with enough data for 10 ms. + // 2) Adjust the buffer to the system delay, by moving the read pointer. + // 3) If we can't move read pointer due to buffer size limitations we + // flush/stuff the buffer. + // 4) Process as many partitions as possible. + // 5) Update the |system_delay| with respect to a full frame of FRAME_LEN + // samples. Even though we will have data left to process (we work with + // partitions) we consider updating a whole frame, since that's the + // amount of data we input and output in audio_processing. + + // TODO(bjornv): Investigate how we should round the delay difference; right + // now we know that incoming |knownDelay| is underestimated when it's less + // than |aec->knownDelay|. We therefore, round (-32) in that direction. In + // the other direction, we don't have this situation, but might flush one + // partition too little. This can cause non-causality, which should be + // investigated. Maybe, allow for a non-symmetric rounding, like -16. + int move_elements = (aec->knownDelay - knownDelay - 32) / PART_LEN; + int moved_elements = 0; + + // TODO(bjornv): Change the near-end buffer handling to be the same as for + // far-end, that is, with a near_pre_buf. + // Buffer the near-end frame. + WebRtc_WriteBuffer(aec->nearFrBuf, nearend, FRAME_LEN); + // For H band + if (aec->sampFreq == 32000) { + WebRtc_WriteBuffer(aec->nearFrBufH, nearendH, FRAME_LEN); + } + + // 1) At most we process |aec->mult|+1 partitions in 10 ms. Make sure we + // have enough far-end data for that by stuffing the buffer if the + // |system_delay| indicates others. + if (aec->system_delay < FRAME_LEN) { + // We don't have enough data so we rewind 10 ms. + WebRtc_MoveReadPtr(aec->far_buf_windowed, -(aec->mult + 1)); + aec->system_delay -= WebRtc_MoveReadPtr(aec->far_buf, -(aec->mult + 1)) * + PART_LEN; +#ifdef WEBRTC_AEC_DEBUG_DUMP + WebRtc_MoveReadPtr(aec->far_time_buf, -(aec->mult + 1)); +#endif + } + + // 2) Compensate for a possible change in the system delay. + + WebRtc_MoveReadPtr(aec->far_buf_windowed, move_elements); + moved_elements = WebRtc_MoveReadPtr(aec->far_buf, move_elements); + aec->knownDelay -= moved_elements * PART_LEN; +#ifdef WEBRTC_AEC_DEBUG_DUMP + WebRtc_MoveReadPtr(aec->far_time_buf, move_elements); +#endif + + // 4) Process as many blocks as possible. + while (WebRtc_available_read(aec->nearFrBuf) >= PART_LEN) { + ProcessBlock(aec); + } + + // 5) Update system delay with respect to the entire frame. + aec->system_delay -= FRAME_LEN; +} + +static void ProcessBlock(aec_t* aec) { + int i; + float d[PART_LEN], y[PART_LEN], e[PART_LEN], dH[PART_LEN]; + float scale; + + float fft[PART_LEN2]; + float xf[2][PART_LEN1], yf[2][PART_LEN1], ef[2][PART_LEN1]; + float df[2][PART_LEN1]; + float far_spectrum = 0.0f; + float near_spectrum = 0.0f; + float abs_far_spectrum[PART_LEN1]; + float abs_near_spectrum[PART_LEN1]; + + const float gPow[2] = {0.9f, 0.1f}; + + // Noise estimate constants. + const int noiseInitBlocks = 500 * aec->mult; + const float step = 0.1f; + const float ramp = 1.0002f; + const float gInitNoise[2] = {0.999f, 0.001f}; + + int16_t nearend[PART_LEN]; + int16_t* nearend_ptr = NULL; + int16_t output[PART_LEN]; + int16_t outputH[PART_LEN]; + + float* xf_ptr = NULL; + + memset(dH, 0, sizeof(dH)); + if (aec->sampFreq == 32000) { + // Get the upper band first so we can reuse |nearend|. + WebRtc_ReadBuffer(aec->nearFrBufH, + (void**) &nearend_ptr, + nearend, + PART_LEN); + for (i = 0; i < PART_LEN; i++) { + dH[i] = (float) (nearend_ptr[i]); + } + memcpy(aec->dBufH + PART_LEN, dH, sizeof(float) * PART_LEN); + } + WebRtc_ReadBuffer(aec->nearFrBuf, (void**) &nearend_ptr, nearend, PART_LEN); + + // ---------- Ooura fft ---------- + // Concatenate old and new nearend blocks. + for (i = 0; i < PART_LEN; i++) { + d[i] = (float) (nearend_ptr[i]); + } + memcpy(aec->dBuf + PART_LEN, d, sizeof(float) * PART_LEN); + +#ifdef WEBRTC_AEC_DEBUG_DUMP + { + int16_t farend[PART_LEN]; + int16_t* farend_ptr = NULL; + WebRtc_ReadBuffer(aec->far_time_buf, (void**) &farend_ptr, farend, 1); + fwrite(farend_ptr, sizeof(int16_t), PART_LEN, aec->farFile); + fwrite(nearend_ptr, sizeof(int16_t), PART_LEN, aec->nearFile); + } +#endif + + // We should always have at least one element stored in |far_buf|. + assert(WebRtc_available_read(aec->far_buf) > 0); + WebRtc_ReadBuffer(aec->far_buf, (void**) &xf_ptr, &xf[0][0], 1); + + // Near fft + memcpy(fft, aec->dBuf, sizeof(float) * PART_LEN2); + TimeToFrequency(fft, df, 0); + + // Power smoothing + for (i = 0; i < PART_LEN1; i++) { + far_spectrum = (xf_ptr[i] * xf_ptr[i]) + + (xf_ptr[PART_LEN1 + i] * xf_ptr[PART_LEN1 + i]); + aec->xPow[i] = gPow[0] * aec->xPow[i] + gPow[1] * NR_PART * far_spectrum; + // Calculate absolute spectra + abs_far_spectrum[i] = sqrtf(far_spectrum); + + near_spectrum = df[0][i] * df[0][i] + df[1][i] * df[1][i]; + aec->dPow[i] = gPow[0] * aec->dPow[i] + gPow[1] * near_spectrum; + // Calculate absolute spectra + abs_near_spectrum[i] = sqrtf(near_spectrum); + } + + // Estimate noise power. Wait until dPow is more stable. + if (aec->noiseEstCtr > 50) { + for (i = 0; i < PART_LEN1; i++) { + if (aec->dPow[i] < aec->dMinPow[i]) { + aec->dMinPow[i] = (aec->dPow[i] + step * (aec->dMinPow[i] - + aec->dPow[i])) * ramp; + } + else { + aec->dMinPow[i] *= ramp; + } + } + } + + // Smooth increasing noise power from zero at the start, + // to avoid a sudden burst of comfort noise. + if (aec->noiseEstCtr < noiseInitBlocks) { + aec->noiseEstCtr++; + for (i = 0; i < PART_LEN1; i++) { + if (aec->dMinPow[i] > aec->dInitMinPow[i]) { + aec->dInitMinPow[i] = gInitNoise[0] * aec->dInitMinPow[i] + + gInitNoise[1] * aec->dMinPow[i]; + } + else { + aec->dInitMinPow[i] = aec->dMinPow[i]; + } + } + aec->noisePow = aec->dInitMinPow; + } + else { + aec->noisePow = aec->dMinPow; + } + + // Block wise delay estimation used for logging + if (aec->delay_logging_enabled) { + int delay_estimate = 0; + // Estimate the delay + delay_estimate = WebRtc_DelayEstimatorProcessFloat(aec->delay_estimator, + abs_far_spectrum, + abs_near_spectrum, + PART_LEN1); + if (delay_estimate >= 0) { + // Update delay estimate buffer. + aec->delay_histogram[delay_estimate]++; + } + } + + // Update the xfBuf block position. + aec->xfBufBlockPos--; + if (aec->xfBufBlockPos == -1) { + aec->xfBufBlockPos = NR_PART - 1; + } + + // Buffer xf + memcpy(aec->xfBuf[0] + aec->xfBufBlockPos * PART_LEN1, xf_ptr, + sizeof(float) * PART_LEN1); + memcpy(aec->xfBuf[1] + aec->xfBufBlockPos * PART_LEN1, &xf_ptr[PART_LEN1], + sizeof(float) * PART_LEN1); + + memset(yf[0], 0, sizeof(float) * (PART_LEN1 * 2)); + + // Filter far + WebRtcAec_FilterFar(aec, yf); + + // Inverse fft to obtain echo estimate and error. + fft[0] = yf[0][0]; + fft[1] = yf[0][PART_LEN]; + for (i = 1; i < PART_LEN; i++) { + fft[2 * i] = yf[0][i]; + fft[2 * i + 1] = yf[1][i]; + } + aec_rdft_inverse_128(fft); + + scale = 2.0f / PART_LEN2; + for (i = 0; i < PART_LEN; i++) { + y[i] = fft[PART_LEN + i] * scale; // fft scaling + } + + for (i = 0; i < PART_LEN; i++) { + e[i] = d[i] - y[i]; + } + + // Error fft + memcpy(aec->eBuf + PART_LEN, e, sizeof(float) * PART_LEN); + memset(fft, 0, sizeof(float) * PART_LEN); + memcpy(fft + PART_LEN, e, sizeof(float) * PART_LEN); + // TODO(bjornv): Change to use TimeToFrequency(). + aec_rdft_forward_128(fft); + + ef[1][0] = 0; + ef[1][PART_LEN] = 0; + ef[0][0] = fft[0]; + ef[0][PART_LEN] = fft[1]; + for (i = 1; i < PART_LEN; i++) { + ef[0][i] = fft[2 * i]; + ef[1][i] = fft[2 * i + 1]; + } + + if (aec->metricsMode == 1) { + // Note that the first PART_LEN samples in fft (before transformation) are + // zero. Hence, the scaling by two in UpdateLevel() should not be + // performed. That scaling is taken care of in UpdateMetrics() instead. + UpdateLevel(&aec->linoutlevel, ef); + } + + // Scale error signal inversely with far power. + WebRtcAec_ScaleErrorSignal(aec, ef); + WebRtcAec_FilterAdaptation(aec, fft, ef); + NonLinearProcessing(aec, output, outputH); + + if (aec->metricsMode == 1) { + // Update power levels and echo metrics + UpdateLevel(&aec->farlevel, (float (*)[PART_LEN1]) xf_ptr); + UpdateLevel(&aec->nearlevel, df); + UpdateMetrics(aec); + } + + // Store the output block. + WebRtc_WriteBuffer(aec->outFrBuf, output, PART_LEN); + // For H band + if (aec->sampFreq == 32000) { + WebRtc_WriteBuffer(aec->outFrBufH, outputH, PART_LEN); + } + +#ifdef WEBRTC_AEC_DEBUG_DUMP + { + int16_t eInt16[PART_LEN]; + for (i = 0; i < PART_LEN; i++) { + eInt16[i] = (int16_t)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, e[i], + WEBRTC_SPL_WORD16_MIN); + } + + fwrite(eInt16, sizeof(int16_t), PART_LEN, aec->outLinearFile); + fwrite(output, sizeof(int16_t), PART_LEN, aec->outFile); + } +#endif +} + +static void NonLinearProcessing(aec_t *aec, short *output, short *outputH) +{ + float efw[2][PART_LEN1], dfw[2][PART_LEN1], xfw[2][PART_LEN1]; + complex_t comfortNoiseHband[PART_LEN1]; + float fft[PART_LEN2]; + float scale, dtmp; + float nlpGainHband; + int i, j, pos; + + // Coherence and non-linear filter + float cohde[PART_LEN1], cohxd[PART_LEN1]; + float hNlDeAvg, hNlXdAvg; + float hNl[PART_LEN1]; + float hNlPref[PREF_BAND_SIZE]; + float hNlFb = 0, hNlFbLow = 0; + const float prefBandQuant = 0.75f, prefBandQuantLow = 0.5f; + const int prefBandSize = PREF_BAND_SIZE / aec->mult; + const int minPrefBand = 4 / aec->mult; + + // Near and error power sums + float sdSum = 0, seSum = 0; + + // Power estimate smoothing coefficients + const float gCoh[2][2] = {{0.9f, 0.1f}, {0.93f, 0.07f}}; + const float *ptrGCoh = gCoh[aec->mult - 1]; + + // Filter energy + float wfEnMax = 0, wfEn = 0; + const int delayEstInterval = 10 * aec->mult; + + float* xfw_ptr = NULL; + + aec->delayEstCtr++; + if (aec->delayEstCtr == delayEstInterval) { + aec->delayEstCtr = 0; + } + + // initialize comfort noise for H band + memset(comfortNoiseHband, 0, sizeof(comfortNoiseHband)); + nlpGainHband = (float)0.0; + dtmp = (float)0.0; + + // Measure energy in each filter partition to determine delay. + // TODO: Spread by computing one partition per block? + if (aec->delayEstCtr == 0) { + wfEnMax = 0; + aec->delayIdx = 0; + for (i = 0; i < NR_PART; i++) { + pos = i * PART_LEN1; + wfEn = 0; + for (j = 0; j < PART_LEN1; j++) { + wfEn += aec->wfBuf[0][pos + j] * aec->wfBuf[0][pos + j] + + aec->wfBuf[1][pos + j] * aec->wfBuf[1][pos + j]; + } + + if (wfEn > wfEnMax) { + wfEnMax = wfEn; + aec->delayIdx = i; + } + } + } + + // We should always have at least one element stored in |far_buf|. + assert(WebRtc_available_read(aec->far_buf_windowed) > 0); + // NLP + WebRtc_ReadBuffer(aec->far_buf_windowed, (void**) &xfw_ptr, &xfw[0][0], 1); + + // TODO(bjornv): Investigate if we can reuse |far_buf_windowed| instead of + // |xfwBuf|. + // Buffer far. + memcpy(aec->xfwBuf, xfw_ptr, sizeof(float) * 2 * PART_LEN1); + + // Use delayed far. + memcpy(xfw, aec->xfwBuf + aec->delayIdx * PART_LEN1, sizeof(xfw)); + + // Windowed near fft + for (i = 0; i < PART_LEN; i++) { + fft[i] = aec->dBuf[i] * sqrtHanning[i]; + fft[PART_LEN + i] = aec->dBuf[PART_LEN + i] * sqrtHanning[PART_LEN - i]; + } + aec_rdft_forward_128(fft); + + dfw[1][0] = 0; + dfw[1][PART_LEN] = 0; + dfw[0][0] = fft[0]; + dfw[0][PART_LEN] = fft[1]; + for (i = 1; i < PART_LEN; i++) { + dfw[0][i] = fft[2 * i]; + dfw[1][i] = fft[2 * i + 1]; + } + + // Windowed error fft + for (i = 0; i < PART_LEN; i++) { + fft[i] = aec->eBuf[i] * sqrtHanning[i]; + fft[PART_LEN + i] = aec->eBuf[PART_LEN + i] * sqrtHanning[PART_LEN - i]; + } + aec_rdft_forward_128(fft); + efw[1][0] = 0; + efw[1][PART_LEN] = 0; + efw[0][0] = fft[0]; + efw[0][PART_LEN] = fft[1]; + for (i = 1; i < PART_LEN; i++) { + efw[0][i] = fft[2 * i]; + efw[1][i] = fft[2 * i + 1]; + } + + // Smoothed PSD + for (i = 0; i < PART_LEN1; i++) { + aec->sd[i] = ptrGCoh[0] * aec->sd[i] + ptrGCoh[1] * + (dfw[0][i] * dfw[0][i] + dfw[1][i] * dfw[1][i]); + aec->se[i] = ptrGCoh[0] * aec->se[i] + ptrGCoh[1] * + (efw[0][i] * efw[0][i] + efw[1][i] * efw[1][i]); + // We threshold here to protect against the ill-effects of a zero farend. + // The threshold is not arbitrarily chosen, but balances protection and + // adverse interaction with the algorithm's tuning. + // TODO: investigate further why this is so sensitive. + aec->sx[i] = ptrGCoh[0] * aec->sx[i] + ptrGCoh[1] * + WEBRTC_SPL_MAX(xfw[0][i] * xfw[0][i] + xfw[1][i] * xfw[1][i], 15); + + aec->sde[i][0] = ptrGCoh[0] * aec->sde[i][0] + ptrGCoh[1] * + (dfw[0][i] * efw[0][i] + dfw[1][i] * efw[1][i]); + aec->sde[i][1] = ptrGCoh[0] * aec->sde[i][1] + ptrGCoh[1] * + (dfw[0][i] * efw[1][i] - dfw[1][i] * efw[0][i]); + + aec->sxd[i][0] = ptrGCoh[0] * aec->sxd[i][0] + ptrGCoh[1] * + (dfw[0][i] * xfw[0][i] + dfw[1][i] * xfw[1][i]); + aec->sxd[i][1] = ptrGCoh[0] * aec->sxd[i][1] + ptrGCoh[1] * + (dfw[0][i] * xfw[1][i] - dfw[1][i] * xfw[0][i]); + + sdSum += aec->sd[i]; + seSum += aec->se[i]; + } + + // Divergent filter safeguard. + if (aec->divergeState == 0) { + if (seSum > sdSum) { + aec->divergeState = 1; + } + } + else { + if (seSum * 1.05f < sdSum) { + aec->divergeState = 0; + } + } + + if (aec->divergeState == 1) { + memcpy(efw, dfw, sizeof(efw)); + } + + // Reset if error is significantly larger than nearend (13 dB). + if (seSum > (19.95f * sdSum)) { + memset(aec->wfBuf, 0, sizeof(aec->wfBuf)); + } + + // Subband coherence + for (i = 0; i < PART_LEN1; i++) { + cohde[i] = (aec->sde[i][0] * aec->sde[i][0] + aec->sde[i][1] * aec->sde[i][1]) / + (aec->sd[i] * aec->se[i] + 1e-10f); + cohxd[i] = (aec->sxd[i][0] * aec->sxd[i][0] + aec->sxd[i][1] * aec->sxd[i][1]) / + (aec->sx[i] * aec->sd[i] + 1e-10f); + } + + hNlXdAvg = 0; + for (i = minPrefBand; i < prefBandSize + minPrefBand; i++) { + hNlXdAvg += cohxd[i]; + } + hNlXdAvg /= prefBandSize; + hNlXdAvg = 1 - hNlXdAvg; + + hNlDeAvg = 0; + for (i = minPrefBand; i < prefBandSize + minPrefBand; i++) { + hNlDeAvg += cohde[i]; + } + hNlDeAvg /= prefBandSize; + + if (hNlXdAvg < 0.75f && hNlXdAvg < aec->hNlXdAvgMin) { + aec->hNlXdAvgMin = hNlXdAvg; + } + + if (hNlDeAvg > 0.98f && hNlXdAvg > 0.9f) { + aec->stNearState = 1; + } + else if (hNlDeAvg < 0.95f || hNlXdAvg < 0.8f) { + aec->stNearState = 0; + } + + if (aec->hNlXdAvgMin == 1) { + aec->echoState = 0; + aec->overDrive = aec->minOverDrive; + + if (aec->stNearState == 1) { + memcpy(hNl, cohde, sizeof(hNl)); + hNlFb = hNlDeAvg; + hNlFbLow = hNlDeAvg; + } + else { + for (i = 0; i < PART_LEN1; i++) { + hNl[i] = 1 - cohxd[i]; + } + hNlFb = hNlXdAvg; + hNlFbLow = hNlXdAvg; + } + } + else { + + if (aec->stNearState == 1) { + aec->echoState = 0; + memcpy(hNl, cohde, sizeof(hNl)); + hNlFb = hNlDeAvg; + hNlFbLow = hNlDeAvg; + } + else { + aec->echoState = 1; + for (i = 0; i < PART_LEN1; i++) { + hNl[i] = WEBRTC_SPL_MIN(cohde[i], 1 - cohxd[i]); + } + + // Select an order statistic from the preferred bands. + // TODO: Using quicksort now, but a selection algorithm may be preferred. + memcpy(hNlPref, &hNl[minPrefBand], sizeof(float) * prefBandSize); + qsort(hNlPref, prefBandSize, sizeof(float), CmpFloat); + hNlFb = hNlPref[(int)floor(prefBandQuant * (prefBandSize - 1))]; + hNlFbLow = hNlPref[(int)floor(prefBandQuantLow * (prefBandSize - 1))]; + } + } + + // Track the local filter minimum to determine suppression overdrive. + if (hNlFbLow < 0.6f && hNlFbLow < aec->hNlFbLocalMin) { + aec->hNlFbLocalMin = hNlFbLow; + aec->hNlFbMin = hNlFbLow; + aec->hNlNewMin = 1; + aec->hNlMinCtr = 0; + } + aec->hNlFbLocalMin = WEBRTC_SPL_MIN(aec->hNlFbLocalMin + 0.0008f / aec->mult, 1); + aec->hNlXdAvgMin = WEBRTC_SPL_MIN(aec->hNlXdAvgMin + 0.0006f / aec->mult, 1); + + if (aec->hNlNewMin == 1) { + aec->hNlMinCtr++; + } + if (aec->hNlMinCtr == 2) { + aec->hNlNewMin = 0; + aec->hNlMinCtr = 0; + aec->overDrive = WEBRTC_SPL_MAX(aec->targetSupp / + ((float)log(aec->hNlFbMin + 1e-10f) + 1e-10f), aec->minOverDrive); + } + + // Smooth the overdrive. + if (aec->overDrive < aec->overDriveSm) { + aec->overDriveSm = 0.99f * aec->overDriveSm + 0.01f * aec->overDrive; + } + else { + aec->overDriveSm = 0.9f * aec->overDriveSm + 0.1f * aec->overDrive; + } + + WebRtcAec_OverdriveAndSuppress(aec, hNl, hNlFb, efw); + + // Add comfort noise. + ComfortNoise(aec, efw, comfortNoiseHband, aec->noisePow, hNl); + + // TODO(bjornv): Investigate how to take the windowing below into account if + // needed. + if (aec->metricsMode == 1) { + // Note that we have a scaling by two in the time domain |eBuf|. + // In addition the time domain signal is windowed before transformation, + // losing half the energy on the average. We take care of the first + // scaling only in UpdateMetrics(). + UpdateLevel(&aec->nlpoutlevel, efw); + } + // Inverse error fft. + fft[0] = efw[0][0]; + fft[1] = efw[0][PART_LEN]; + for (i = 1; i < PART_LEN; i++) { + fft[2*i] = efw[0][i]; + // Sign change required by Ooura fft. + fft[2*i + 1] = -efw[1][i]; + } + aec_rdft_inverse_128(fft); + + // Overlap and add to obtain output. + scale = 2.0f / PART_LEN2; + for (i = 0; i < PART_LEN; i++) { + fft[i] *= scale; // fft scaling + fft[i] = fft[i]*sqrtHanning[i] + aec->outBuf[i]; + + // Saturation protection + output[i] = (short)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, fft[i], + WEBRTC_SPL_WORD16_MIN); + + fft[PART_LEN + i] *= scale; // fft scaling + aec->outBuf[i] = fft[PART_LEN + i] * sqrtHanning[PART_LEN - i]; + } + + // For H band + if (aec->sampFreq == 32000) { + + // H band gain + // average nlp over low band: average over second half of freq spectrum + // (4->8khz) + GetHighbandGain(hNl, &nlpGainHband); + + // Inverse comfort_noise + if (flagHbandCn == 1) { + fft[0] = comfortNoiseHband[0][0]; + fft[1] = comfortNoiseHband[PART_LEN][0]; + for (i = 1; i < PART_LEN; i++) { + fft[2*i] = comfortNoiseHband[i][0]; + fft[2*i + 1] = comfortNoiseHband[i][1]; + } + aec_rdft_inverse_128(fft); + scale = 2.0f / PART_LEN2; + } + + // compute gain factor + for (i = 0; i < PART_LEN; i++) { + dtmp = (float)aec->dBufH[i]; + dtmp = (float)dtmp * nlpGainHband; // for variable gain + + // add some comfort noise where Hband is attenuated + if (flagHbandCn == 1) { + fft[i] *= scale; // fft scaling + dtmp += cnScaleHband * fft[i]; + } + + // Saturation protection + outputH[i] = (short)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, dtmp, + WEBRTC_SPL_WORD16_MIN); + } + } + + // Copy the current block to the old position. + memcpy(aec->dBuf, aec->dBuf + PART_LEN, sizeof(float) * PART_LEN); + memcpy(aec->eBuf, aec->eBuf + PART_LEN, sizeof(float) * PART_LEN); + + // Copy the current block to the old position for H band + if (aec->sampFreq == 32000) { + memcpy(aec->dBufH, aec->dBufH + PART_LEN, sizeof(float) * PART_LEN); + } + + memmove(aec->xfwBuf + PART_LEN1, aec->xfwBuf, sizeof(aec->xfwBuf) - + sizeof(complex_t) * PART_LEN1); +} + +static void GetHighbandGain(const float *lambda, float *nlpGainHband) +{ + int i; + + nlpGainHband[0] = (float)0.0; + for (i = freqAvgIc; i < PART_LEN1 - 1; i++) { + nlpGainHband[0] += lambda[i]; + } + nlpGainHband[0] /= (float)(PART_LEN1 - 1 - freqAvgIc); +} + +static void ComfortNoise(aec_t *aec, float efw[2][PART_LEN1], + complex_t *comfortNoiseHband, const float *noisePow, const float *lambda) +{ + int i, num; + float rand[PART_LEN]; + float noise, noiseAvg, tmp, tmpAvg; + WebRtc_Word16 randW16[PART_LEN]; + complex_t u[PART_LEN1]; + + const float pi2 = 6.28318530717959f; + + // Generate a uniform random array on [0 1] + WebRtcSpl_RandUArray(randW16, PART_LEN, &aec->seed); + for (i = 0; i < PART_LEN; i++) { + rand[i] = ((float)randW16[i]) / 32768; + } + + // Reject LF noise + u[0][0] = 0; + u[0][1] = 0; + for (i = 1; i < PART_LEN1; i++) { + tmp = pi2 * rand[i - 1]; + + noise = sqrtf(noisePow[i]); + u[i][0] = noise * (float)cos(tmp); + u[i][1] = -noise * (float)sin(tmp); + } + u[PART_LEN][1] = 0; + + for (i = 0; i < PART_LEN1; i++) { + // This is the proper weighting to match the background noise power + tmp = sqrtf(WEBRTC_SPL_MAX(1 - lambda[i] * lambda[i], 0)); + //tmp = 1 - lambda[i]; + efw[0][i] += tmp * u[i][0]; + efw[1][i] += tmp * u[i][1]; + } + + // For H band comfort noise + // TODO: don't compute noise and "tmp" twice. Use the previous results. + noiseAvg = 0.0; + tmpAvg = 0.0; + num = 0; + if (aec->sampFreq == 32000 && flagHbandCn == 1) { + + // average noise scale + // average over second half of freq spectrum (i.e., 4->8khz) + // TODO: we shouldn't need num. We know how many elements we're summing. + for (i = PART_LEN1 >> 1; i < PART_LEN1; i++) { + num++; + noiseAvg += sqrtf(noisePow[i]); + } + noiseAvg /= (float)num; + + // average nlp scale + // average over second half of freq spectrum (i.e., 4->8khz) + // TODO: we shouldn't need num. We know how many elements we're summing. + num = 0; + for (i = PART_LEN1 >> 1; i < PART_LEN1; i++) { + num++; + tmpAvg += sqrtf(WEBRTC_SPL_MAX(1 - lambda[i] * lambda[i], 0)); + } + tmpAvg /= (float)num; + + // Use average noise for H band + // TODO: we should probably have a new random vector here. + // Reject LF noise + u[0][0] = 0; + u[0][1] = 0; + for (i = 1; i < PART_LEN1; i++) { + tmp = pi2 * rand[i - 1]; + + // Use average noise for H band + u[i][0] = noiseAvg * (float)cos(tmp); + u[i][1] = -noiseAvg * (float)sin(tmp); + } + u[PART_LEN][1] = 0; + + for (i = 0; i < PART_LEN1; i++) { + // Use average NLP weight for H band + comfortNoiseHband[i][0] = tmpAvg * u[i][0]; + comfortNoiseHband[i][1] = tmpAvg * u[i][1]; + } + } +} + +static void WebRtcAec_InitLevel(power_level_t *level) +{ + const float bigFloat = 1E17f; + + level->averagelevel = 0; + level->framelevel = 0; + level->minlevel = bigFloat; + level->frsum = 0; + level->sfrsum = 0; + level->frcounter = 0; + level->sfrcounter = 0; +} + +static void WebRtcAec_InitStats(stats_t *stats) +{ + stats->instant = offsetLevel; + stats->average = offsetLevel; + stats->max = offsetLevel; + stats->min = offsetLevel * (-1); + stats->sum = 0; + stats->hisum = 0; + stats->himean = offsetLevel; + stats->counter = 0; + stats->hicounter = 0; +} + +static void UpdateLevel(power_level_t* level, float in[2][PART_LEN1]) { + // Do the energy calculation in the frequency domain. The FFT is performed on + // a segment of PART_LEN2 samples due to overlap, but we only want the energy + // of half that data (the last PART_LEN samples). Parseval's relation states + // that the energy is preserved according to + // + // \sum_{n=0}^{N-1} |x(n)|^2 = 1/N * \sum_{n=0}^{N-1} |X(n)|^2 + // = ENERGY, + // + // where N = PART_LEN2. Since we are only interested in calculating the energy + // for the last PART_LEN samples we approximate by calculating ENERGY and + // divide by 2, + // + // \sum_{n=N/2}^{N-1} |x(n)|^2 ~= ENERGY / 2 + // + // Since we deal with real valued time domain signals we only store frequency + // bins [0, PART_LEN], which is what |in| consists of. To calculate ENERGY we + // need to add the contribution from the missing part in + // [PART_LEN+1, PART_LEN2-1]. These values are, up to a phase shift, identical + // with the values in [1, PART_LEN-1], hence multiply those values by 2. This + // is the values in the for loop below, but multiplication by 2 and division + // by 2 cancel. + + // TODO(bjornv): Investigate reusing energy calculations performed at other + // places in the code. + int k = 1; + // Imaginary parts are zero at end points and left out of the calculation. + float energy = (in[0][0] * in[0][0]) / 2; + energy += (in[0][PART_LEN] * in[0][PART_LEN]) / 2; + + for (k = 1; k < PART_LEN; k++) { + energy += (in[0][k] * in[0][k] + in[1][k] * in[1][k]); + } + energy /= PART_LEN2; + + level->sfrsum += energy; + level->sfrcounter++; + + if (level->sfrcounter > subCountLen) { + level->framelevel = level->sfrsum / (subCountLen * PART_LEN); + level->sfrsum = 0; + level->sfrcounter = 0; + if (level->framelevel > 0) { + if (level->framelevel < level->minlevel) { + level->minlevel = level->framelevel; // New minimum. + } else { + level->minlevel *= (1 + 0.001f); // Small increase. + } + } + level->frcounter++; + level->frsum += level->framelevel; + if (level->frcounter > countLen) { + level->averagelevel = level->frsum / countLen; + level->frsum = 0; + level->frcounter = 0; + } + } +} + +static void UpdateMetrics(aec_t *aec) +{ + float dtmp, dtmp2; + + const float actThresholdNoisy = 8.0f; + const float actThresholdClean = 40.0f; + const float safety = 0.99995f; + const float noisyPower = 300000.0f; + + float actThreshold; + float echo, suppressedEcho; + + if (aec->echoState) { // Check if echo is likely present + aec->stateCounter++; + } + + if (aec->farlevel.frcounter == 0) { + + if (aec->farlevel.minlevel < noisyPower) { + actThreshold = actThresholdClean; + } + else { + actThreshold = actThresholdNoisy; + } + + if ((aec->stateCounter > (0.5f * countLen * subCountLen)) + && (aec->farlevel.sfrcounter == 0) + + // Estimate in active far-end segments only + && (aec->farlevel.averagelevel > (actThreshold * aec->farlevel.minlevel)) + ) { + + // Subtract noise power + echo = aec->nearlevel.averagelevel - safety * aec->nearlevel.minlevel; + + // ERL + dtmp = 10 * (float)log10(aec->farlevel.averagelevel / + aec->nearlevel.averagelevel + 1e-10f); + dtmp2 = 10 * (float)log10(aec->farlevel.averagelevel / echo + 1e-10f); + + aec->erl.instant = dtmp; + if (dtmp > aec->erl.max) { + aec->erl.max = dtmp; + } + + if (dtmp < aec->erl.min) { + aec->erl.min = dtmp; + } + + aec->erl.counter++; + aec->erl.sum += dtmp; + aec->erl.average = aec->erl.sum / aec->erl.counter; + + // Upper mean + if (dtmp > aec->erl.average) { + aec->erl.hicounter++; + aec->erl.hisum += dtmp; + aec->erl.himean = aec->erl.hisum / aec->erl.hicounter; + } + + // A_NLP + dtmp = 10 * (float)log10(aec->nearlevel.averagelevel / + (2 * aec->linoutlevel.averagelevel) + 1e-10f); + + // subtract noise power + suppressedEcho = 2 * (aec->linoutlevel.averagelevel - + safety * aec->linoutlevel.minlevel); + + dtmp2 = 10 * (float)log10(echo / suppressedEcho + 1e-10f); + + aec->aNlp.instant = dtmp2; + if (dtmp > aec->aNlp.max) { + aec->aNlp.max = dtmp; + } + + if (dtmp < aec->aNlp.min) { + aec->aNlp.min = dtmp; + } + + aec->aNlp.counter++; + aec->aNlp.sum += dtmp; + aec->aNlp.average = aec->aNlp.sum / aec->aNlp.counter; + + // Upper mean + if (dtmp > aec->aNlp.average) { + aec->aNlp.hicounter++; + aec->aNlp.hisum += dtmp; + aec->aNlp.himean = aec->aNlp.hisum / aec->aNlp.hicounter; + } + + // ERLE + + // subtract noise power + suppressedEcho = 2 * (aec->nlpoutlevel.averagelevel - + safety * aec->nlpoutlevel.minlevel); + + dtmp = 10 * (float)log10(aec->nearlevel.averagelevel / + (2 * aec->nlpoutlevel.averagelevel) + 1e-10f); + dtmp2 = 10 * (float)log10(echo / suppressedEcho + 1e-10f); + + dtmp = dtmp2; + aec->erle.instant = dtmp; + if (dtmp > aec->erle.max) { + aec->erle.max = dtmp; + } + + if (dtmp < aec->erle.min) { + aec->erle.min = dtmp; + } + + aec->erle.counter++; + aec->erle.sum += dtmp; + aec->erle.average = aec->erle.sum / aec->erle.counter; + + // Upper mean + if (dtmp > aec->erle.average) { + aec->erle.hicounter++; + aec->erle.hisum += dtmp; + aec->erle.himean = aec->erle.hisum / aec->erle.hicounter; + } + } + + aec->stateCounter = 0; + } +} + +static void TimeToFrequency(float time_data[PART_LEN2], + float freq_data[2][PART_LEN1], + int window) { + int i = 0; + + // TODO(bjornv): Should we have a different function/wrapper for windowed FFT? + if (window) { + for (i = 0; i < PART_LEN; i++) { + time_data[i] *= sqrtHanning[i]; + time_data[PART_LEN + i] *= sqrtHanning[PART_LEN - i]; + } + } + + aec_rdft_forward_128(time_data); + // Reorder. + freq_data[1][0] = 0; + freq_data[1][PART_LEN] = 0; + freq_data[0][0] = time_data[0]; + freq_data[0][PART_LEN] = time_data[1]; + for (i = 1; i < PART_LEN; i++) { + freq_data[0][i] = time_data[2 * i]; + freq_data[1][i] = time_data[2 * i + 1]; + } +} diff --git a/libs/miniwebrtc/audio/processing/aec/aec_core.h b/libs/miniwebrtc/audio/processing/aec/aec_core.h new file mode 100644 index 00000000..d326a684 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/aec/aec_core.h @@ -0,0 +1,180 @@ +/* + * 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. + */ + +/* + * Specifies the interface for the AEC core. + */ + +#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_CORE_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_CORE_H_ + +#ifdef WEBRTC_AEC_DEBUG_DUMP +#include +#endif + +#include "typedefs.h" + +#define FRAME_LEN 80 +#define PART_LEN 64 // Length of partition +#define PART_LEN1 (PART_LEN + 1) // Unique fft coefficients +#define PART_LEN2 (PART_LEN * 2) // Length of partition * 2 +#define NR_PART 12 // Number of partitions in filter. +#define PREF_BAND_SIZE 24 + +// Delay estimator constants, used for logging. +enum { kMaxDelayBlocks = 60 }; +enum { kLookaheadBlocks = 15 }; +enum { kHistorySizeBlocks = kMaxDelayBlocks + kLookaheadBlocks }; + +typedef float complex_t[2]; +// For performance reasons, some arrays of complex numbers are replaced by twice +// as long arrays of float, all the real parts followed by all the imaginary +// ones (complex_t[SIZE] -> float[2][SIZE]). This allows SIMD optimizations and +// is better than two arrays (one for the real parts and one for the imaginary +// parts) as this other way would require two pointers instead of one and cause +// extra register spilling. This also allows the offsets to be calculated at +// compile time. + +// Metrics +enum {offsetLevel = -100}; + +typedef struct { + float sfrsum; + int sfrcounter; + float framelevel; + float frsum; + int frcounter; + float minlevel; + float averagelevel; +} power_level_t; + +typedef struct { + float instant; + float average; + float min; + float max; + float sum; + float hisum; + float himean; + int counter; + int hicounter; +} stats_t; + +typedef struct { + int farBufWritePos, farBufReadPos; + + int knownDelay; + int inSamples, outSamples; + int delayEstCtr; + + void *nearFrBuf, *outFrBuf; + + void *nearFrBufH; + void *outFrBufH; + + float dBuf[PART_LEN2]; // nearend + float eBuf[PART_LEN2]; // error + + float dBufH[PART_LEN2]; // nearend + + float xPow[PART_LEN1]; + float dPow[PART_LEN1]; + float dMinPow[PART_LEN1]; + float dInitMinPow[PART_LEN1]; + float *noisePow; + + float xfBuf[2][NR_PART * PART_LEN1]; // farend fft buffer + float wfBuf[2][NR_PART * PART_LEN1]; // filter fft + complex_t sde[PART_LEN1]; // cross-psd of nearend and error + complex_t sxd[PART_LEN1]; // cross-psd of farend and nearend + complex_t xfwBuf[NR_PART * PART_LEN1]; // farend windowed fft buffer + + float sx[PART_LEN1], sd[PART_LEN1], se[PART_LEN1]; // far, near and error psd + float hNs[PART_LEN1]; + float hNlFbMin, hNlFbLocalMin; + float hNlXdAvgMin; + int hNlNewMin, hNlMinCtr; + float overDrive, overDriveSm; + float targetSupp, minOverDrive; + float outBuf[PART_LEN]; + int delayIdx; + + short stNearState, echoState; + short divergeState; + + int xfBufBlockPos; + + void* far_buf; + void* far_buf_windowed; + int system_delay; // Current system delay buffered in AEC. + + int mult; // sampling frequency multiple + int sampFreq; + WebRtc_UWord32 seed; + + float mu; // stepsize + float errThresh; // error threshold + + int noiseEstCtr; + + power_level_t farlevel; + power_level_t nearlevel; + power_level_t linoutlevel; + power_level_t nlpoutlevel; + + int metricsMode; + int stateCounter; + stats_t erl; + stats_t erle; + stats_t aNlp; + stats_t rerl; + + // Quantities to control H band scaling for SWB input + int freq_avg_ic; //initial bin for averaging nlp gain + int flag_Hband_cn; //for comfort noise + float cn_scale_Hband; //scale for comfort noise in H band + + int delay_histogram[kHistorySizeBlocks]; + int delay_logging_enabled; + void* delay_estimator; + +#ifdef WEBRTC_AEC_DEBUG_DUMP + void* far_time_buf; + FILE *farFile; + FILE *nearFile; + FILE *outFile; + FILE *outLinearFile; +#endif +} aec_t; + +typedef void (*WebRtcAec_FilterFar_t)(aec_t *aec, float yf[2][PART_LEN1]); +extern WebRtcAec_FilterFar_t WebRtcAec_FilterFar; +typedef void (*WebRtcAec_ScaleErrorSignal_t)(aec_t *aec, float ef[2][PART_LEN1]); +extern WebRtcAec_ScaleErrorSignal_t WebRtcAec_ScaleErrorSignal; +typedef void (*WebRtcAec_FilterAdaptation_t) + (aec_t *aec, float *fft, float ef[2][PART_LEN1]); +extern WebRtcAec_FilterAdaptation_t WebRtcAec_FilterAdaptation; +typedef void (*WebRtcAec_OverdriveAndSuppress_t) + (aec_t *aec, float hNl[PART_LEN1], const float hNlFb, float efw[2][PART_LEN1]); +extern WebRtcAec_OverdriveAndSuppress_t WebRtcAec_OverdriveAndSuppress; + +int WebRtcAec_CreateAec(aec_t **aec); +int WebRtcAec_FreeAec(aec_t *aec); +int WebRtcAec_InitAec(aec_t *aec, int sampFreq); +void WebRtcAec_InitAec_SSE2(void); + +void WebRtcAec_InitMetrics(aec_t *aec); +void WebRtcAec_BufferFarendPartition(aec_t *aec, const float* farend); +void WebRtcAec_ProcessFrame(aec_t* aec, + const short *nearend, + const short *nearendH, + int knownDelay); + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_CORE_H_ diff --git a/libs/miniwebrtc/audio/processing/aec/aec_core_sse2.c b/libs/miniwebrtc/audio/processing/aec/aec_core_sse2.c new file mode 100644 index 00000000..74a1c48b --- /dev/null +++ b/libs/miniwebrtc/audio/processing/aec/aec_core_sse2.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. + */ + +/* + * The core AEC algorithm, SSE2 version of speed-critical functions. + */ + +#include "aec_core.h" + +#include +#include +#include // memset + +#include "aec_rdft.h" + +__inline static float MulRe(float aRe, float aIm, float bRe, float bIm) +{ + return aRe * bRe - aIm * bIm; +} + +__inline static float MulIm(float aRe, float aIm, float bRe, float bIm) +{ + return aRe * bIm + aIm * bRe; +} + +static void FilterFarSSE2(aec_t *aec, float yf[2][PART_LEN1]) +{ + int i; + for (i = 0; i < NR_PART; i++) { + int j; + int xPos = (i + aec->xfBufBlockPos) * PART_LEN1; + int pos = i * PART_LEN1; + // Check for wrap + if (i + aec->xfBufBlockPos >= NR_PART) { + xPos -= NR_PART*(PART_LEN1); + } + + // vectorized code (four at once) + for (j = 0; j + 3 < PART_LEN1; j += 4) { + const __m128 xfBuf_re = _mm_loadu_ps(&aec->xfBuf[0][xPos + j]); + const __m128 xfBuf_im = _mm_loadu_ps(&aec->xfBuf[1][xPos + j]); + const __m128 wfBuf_re = _mm_loadu_ps(&aec->wfBuf[0][pos + j]); + const __m128 wfBuf_im = _mm_loadu_ps(&aec->wfBuf[1][pos + j]); + const __m128 yf_re = _mm_loadu_ps(&yf[0][j]); + const __m128 yf_im = _mm_loadu_ps(&yf[1][j]); + const __m128 a = _mm_mul_ps(xfBuf_re, wfBuf_re); + const __m128 b = _mm_mul_ps(xfBuf_im, wfBuf_im); + const __m128 c = _mm_mul_ps(xfBuf_re, wfBuf_im); + const __m128 d = _mm_mul_ps(xfBuf_im, wfBuf_re); + const __m128 e = _mm_sub_ps(a, b); + const __m128 f = _mm_add_ps(c, d); + const __m128 g = _mm_add_ps(yf_re, e); + const __m128 h = _mm_add_ps(yf_im, f); + _mm_storeu_ps(&yf[0][j], g); + _mm_storeu_ps(&yf[1][j], h); + } + // scalar code for the remaining items. + for (; j < PART_LEN1; j++) { + yf[0][j] += MulRe(aec->xfBuf[0][xPos + j], aec->xfBuf[1][xPos + j], + aec->wfBuf[0][ pos + j], aec->wfBuf[1][ pos + j]); + yf[1][j] += MulIm(aec->xfBuf[0][xPos + j], aec->xfBuf[1][xPos + j], + aec->wfBuf[0][ pos + j], aec->wfBuf[1][ pos + j]); + } + } +} + +static void ScaleErrorSignalSSE2(aec_t *aec, float ef[2][PART_LEN1]) +{ + const __m128 k1e_10f = _mm_set1_ps(1e-10f); + const __m128 kThresh = _mm_set1_ps(aec->errThresh); + const __m128 kMu = _mm_set1_ps(aec->mu); + + int i; + // vectorized code (four at once) + for (i = 0; i + 3 < PART_LEN1; i += 4) { + const __m128 xPow = _mm_loadu_ps(&aec->xPow[i]); + const __m128 ef_re_base = _mm_loadu_ps(&ef[0][i]); + const __m128 ef_im_base = _mm_loadu_ps(&ef[1][i]); + + const __m128 xPowPlus = _mm_add_ps(xPow, k1e_10f); + __m128 ef_re = _mm_div_ps(ef_re_base, xPowPlus); + __m128 ef_im = _mm_div_ps(ef_im_base, xPowPlus); + const __m128 ef_re2 = _mm_mul_ps(ef_re, ef_re); + const __m128 ef_im2 = _mm_mul_ps(ef_im, ef_im); + const __m128 ef_sum2 = _mm_add_ps(ef_re2, ef_im2); + const __m128 absEf = _mm_sqrt_ps(ef_sum2); + const __m128 bigger = _mm_cmpgt_ps(absEf, kThresh); + __m128 absEfPlus = _mm_add_ps(absEf, k1e_10f); + const __m128 absEfInv = _mm_div_ps(kThresh, absEfPlus); + __m128 ef_re_if = _mm_mul_ps(ef_re, absEfInv); + __m128 ef_im_if = _mm_mul_ps(ef_im, absEfInv); + ef_re_if = _mm_and_ps(bigger, ef_re_if); + ef_im_if = _mm_and_ps(bigger, ef_im_if); + ef_re = _mm_andnot_ps(bigger, ef_re); + ef_im = _mm_andnot_ps(bigger, ef_im); + ef_re = _mm_or_ps(ef_re, ef_re_if); + ef_im = _mm_or_ps(ef_im, ef_im_if); + ef_re = _mm_mul_ps(ef_re, kMu); + ef_im = _mm_mul_ps(ef_im, kMu); + + _mm_storeu_ps(&ef[0][i], ef_re); + _mm_storeu_ps(&ef[1][i], ef_im); + } + // scalar code for the remaining items. + for (; i < (PART_LEN1); i++) { + float absEf; + ef[0][i] /= (aec->xPow[i] + 1e-10f); + ef[1][i] /= (aec->xPow[i] + 1e-10f); + absEf = sqrtf(ef[0][i] * ef[0][i] + ef[1][i] * ef[1][i]); + + if (absEf > aec->errThresh) { + absEf = aec->errThresh / (absEf + 1e-10f); + ef[0][i] *= absEf; + ef[1][i] *= absEf; + } + + // Stepsize factor + ef[0][i] *= aec->mu; + ef[1][i] *= aec->mu; + } +} + +static void FilterAdaptationSSE2(aec_t *aec, float *fft, float ef[2][PART_LEN1]) { + int i, j; + for (i = 0; i < NR_PART; i++) { + int xPos = (i + aec->xfBufBlockPos)*(PART_LEN1); + int pos = i * PART_LEN1; + // Check for wrap + if (i + aec->xfBufBlockPos >= NR_PART) { + xPos -= NR_PART * PART_LEN1; + } + + // Process the whole array... + for (j = 0; j < PART_LEN; j+= 4) { + // Load xfBuf and ef. + const __m128 xfBuf_re = _mm_loadu_ps(&aec->xfBuf[0][xPos + j]); + const __m128 xfBuf_im = _mm_loadu_ps(&aec->xfBuf[1][xPos + j]); + const __m128 ef_re = _mm_loadu_ps(&ef[0][j]); + const __m128 ef_im = _mm_loadu_ps(&ef[1][j]); + // Calculate the product of conjugate(xfBuf) by ef. + // re(conjugate(a) * b) = aRe * bRe + aIm * bIm + // im(conjugate(a) * b)= aRe * bIm - aIm * bRe + const __m128 a = _mm_mul_ps(xfBuf_re, ef_re); + const __m128 b = _mm_mul_ps(xfBuf_im, ef_im); + const __m128 c = _mm_mul_ps(xfBuf_re, ef_im); + const __m128 d = _mm_mul_ps(xfBuf_im, ef_re); + const __m128 e = _mm_add_ps(a, b); + const __m128 f = _mm_sub_ps(c, d); + // Interleave real and imaginary parts. + const __m128 g = _mm_unpacklo_ps(e, f); + const __m128 h = _mm_unpackhi_ps(e, f); + // Store + _mm_storeu_ps(&fft[2*j + 0], g); + _mm_storeu_ps(&fft[2*j + 4], h); + } + // ... and fixup the first imaginary entry. + fft[1] = MulRe(aec->xfBuf[0][xPos + PART_LEN], + -aec->xfBuf[1][xPos + PART_LEN], + ef[0][PART_LEN], ef[1][PART_LEN]); + + aec_rdft_inverse_128(fft); + memset(fft + PART_LEN, 0, sizeof(float)*PART_LEN); + + // fft scaling + { + float scale = 2.0f / PART_LEN2; + const __m128 scale_ps = _mm_load_ps1(&scale); + for (j = 0; j < PART_LEN; j+=4) { + const __m128 fft_ps = _mm_loadu_ps(&fft[j]); + const __m128 fft_scale = _mm_mul_ps(fft_ps, scale_ps); + _mm_storeu_ps(&fft[j], fft_scale); + } + } + aec_rdft_forward_128(fft); + + { + float wt1 = aec->wfBuf[1][pos]; + aec->wfBuf[0][pos + PART_LEN] += fft[1]; + for (j = 0; j < PART_LEN; j+= 4) { + __m128 wtBuf_re = _mm_loadu_ps(&aec->wfBuf[0][pos + j]); + __m128 wtBuf_im = _mm_loadu_ps(&aec->wfBuf[1][pos + j]); + const __m128 fft0 = _mm_loadu_ps(&fft[2 * j + 0]); + const __m128 fft4 = _mm_loadu_ps(&fft[2 * j + 4]); + const __m128 fft_re = _mm_shuffle_ps(fft0, fft4, _MM_SHUFFLE(2, 0, 2 ,0)); + const __m128 fft_im = _mm_shuffle_ps(fft0, fft4, _MM_SHUFFLE(3, 1, 3 ,1)); + wtBuf_re = _mm_add_ps(wtBuf_re, fft_re); + wtBuf_im = _mm_add_ps(wtBuf_im, fft_im); + _mm_storeu_ps(&aec->wfBuf[0][pos + j], wtBuf_re); + _mm_storeu_ps(&aec->wfBuf[1][pos + j], wtBuf_im); + } + aec->wfBuf[1][pos] = wt1; + } + } +} + +static __m128 mm_pow_ps(__m128 a, __m128 b) +{ + // a^b = exp2(b * log2(a)) + // exp2(x) and log2(x) are calculated using polynomial approximations. + __m128 log2_a, b_log2_a, a_exp_b; + + // Calculate log2(x), x = a. + { + // To calculate log2(x), we decompose x like this: + // x = y * 2^n + // n is an integer + // y is in the [1.0, 2.0) range + // + // log2(x) = log2(y) + n + // n can be evaluated by playing with float representation. + // log2(y) in a small range can be approximated, this code uses an order + // five polynomial approximation. The coefficients have been + // estimated with the Remez algorithm and the resulting + // polynomial has a maximum relative error of 0.00086%. + + // Compute n. + // This is done by masking the exponent, shifting it into the top bit of + // the mantissa, putting eight into the biased exponent (to shift/ + // compensate the fact that the exponent has been shifted in the top/ + // fractional part and finally getting rid of the implicit leading one + // from the mantissa by substracting it out. + static const ALIGN16_BEG int float_exponent_mask[4] ALIGN16_END = + {0x7F800000, 0x7F800000, 0x7F800000, 0x7F800000}; + static const ALIGN16_BEG int eight_biased_exponent[4] ALIGN16_END = + {0x43800000, 0x43800000, 0x43800000, 0x43800000}; + static const ALIGN16_BEG int implicit_leading_one[4] ALIGN16_END = + {0x43BF8000, 0x43BF8000, 0x43BF8000, 0x43BF8000}; + static const int shift_exponent_into_top_mantissa = 8; + const __m128 two_n = _mm_and_ps(a, *((__m128 *)float_exponent_mask)); + const __m128 n_1 = _mm_castsi128_ps(_mm_srli_epi32(_mm_castps_si128(two_n), + shift_exponent_into_top_mantissa)); + const __m128 n_0 = _mm_or_ps(n_1, *((__m128 *)eight_biased_exponent)); + const __m128 n = _mm_sub_ps(n_0, *((__m128 *)implicit_leading_one)); + + // Compute y. + static const ALIGN16_BEG int mantissa_mask[4] ALIGN16_END = + {0x007FFFFF, 0x007FFFFF, 0x007FFFFF, 0x007FFFFF}; + static const ALIGN16_BEG int zero_biased_exponent_is_one[4] ALIGN16_END = + {0x3F800000, 0x3F800000, 0x3F800000, 0x3F800000}; + const __m128 mantissa = _mm_and_ps(a, *((__m128 *)mantissa_mask)); + const __m128 y = _mm_or_ps( + mantissa, *((__m128 *)zero_biased_exponent_is_one)); + + // Approximate log2(y) ~= (y - 1) * pol5(y). + // pol5(y) = C5 * y^5 + C4 * y^4 + C3 * y^3 + C2 * y^2 + C1 * y + C0 + static const ALIGN16_BEG float ALIGN16_END C5[4] = + {-3.4436006e-2f, -3.4436006e-2f, -3.4436006e-2f, -3.4436006e-2f}; + static const ALIGN16_BEG float ALIGN16_END C4[4] = + {3.1821337e-1f, 3.1821337e-1f, 3.1821337e-1f, 3.1821337e-1f}; + static const ALIGN16_BEG float ALIGN16_END C3[4] = + {-1.2315303f, -1.2315303f, -1.2315303f, -1.2315303f}; + static const ALIGN16_BEG float ALIGN16_END C2[4] = + {2.5988452f, 2.5988452f, 2.5988452f, 2.5988452f}; + static const ALIGN16_BEG float ALIGN16_END C1[4] = + {-3.3241990f, -3.3241990f, -3.3241990f, -3.3241990f}; + static const ALIGN16_BEG float ALIGN16_END C0[4] = + {3.1157899f, 3.1157899f, 3.1157899f, 3.1157899f}; + const __m128 pol5_y_0 = _mm_mul_ps(y, *((__m128 *)C5)); + const __m128 pol5_y_1 = _mm_add_ps(pol5_y_0, *((__m128 *)C4)); + const __m128 pol5_y_2 = _mm_mul_ps(pol5_y_1, y); + const __m128 pol5_y_3 = _mm_add_ps(pol5_y_2, *((__m128 *)C3)); + const __m128 pol5_y_4 = _mm_mul_ps(pol5_y_3, y); + const __m128 pol5_y_5 = _mm_add_ps(pol5_y_4, *((__m128 *)C2)); + const __m128 pol5_y_6 = _mm_mul_ps(pol5_y_5, y); + const __m128 pol5_y_7 = _mm_add_ps(pol5_y_6, *((__m128 *)C1)); + const __m128 pol5_y_8 = _mm_mul_ps(pol5_y_7, y); + const __m128 pol5_y = _mm_add_ps(pol5_y_8, *((__m128 *)C0)); + const __m128 y_minus_one = _mm_sub_ps( + y, *((__m128 *)zero_biased_exponent_is_one)); + const __m128 log2_y = _mm_mul_ps(y_minus_one , pol5_y); + + // Combine parts. + log2_a = _mm_add_ps(n, log2_y); + } + + // b * log2(a) + b_log2_a = _mm_mul_ps(b, log2_a); + + // Calculate exp2(x), x = b * log2(a). + { + // To calculate 2^x, we decompose x like this: + // x = n + y + // n is an integer, the value of x - 0.5 rounded down, therefore + // y is in the [0.5, 1.5) range + // + // 2^x = 2^n * 2^y + // 2^n can be evaluated by playing with float representation. + // 2^y in a small range can be approximated, this code uses an order two + // polynomial approximation. The coefficients have been estimated + // with the Remez algorithm and the resulting polynomial has a + // maximum relative error of 0.17%. + + // To avoid over/underflow, we reduce the range of input to ]-127, 129]. + static const ALIGN16_BEG float max_input[4] ALIGN16_END = + {129.f, 129.f, 129.f, 129.f}; + static const ALIGN16_BEG float min_input[4] ALIGN16_END = + {-126.99999f, -126.99999f, -126.99999f, -126.99999f}; + const __m128 x_min = _mm_min_ps(b_log2_a, *((__m128 *)max_input)); + const __m128 x_max = _mm_max_ps(x_min, *((__m128 *)min_input)); + // Compute n. + static const ALIGN16_BEG float half[4] ALIGN16_END = + {0.5f, 0.5f, 0.5f, 0.5f}; + const __m128 x_minus_half = _mm_sub_ps(x_max, *((__m128 *)half)); + const __m128i x_minus_half_floor = _mm_cvtps_epi32(x_minus_half); + // Compute 2^n. + static const ALIGN16_BEG int float_exponent_bias[4] ALIGN16_END = + {127, 127, 127, 127}; + static const int float_exponent_shift = 23; + const __m128i two_n_exponent = _mm_add_epi32( + x_minus_half_floor, *((__m128i *)float_exponent_bias)); + const __m128 two_n = _mm_castsi128_ps(_mm_slli_epi32( + two_n_exponent, float_exponent_shift)); + // Compute y. + const __m128 y = _mm_sub_ps(x_max, _mm_cvtepi32_ps(x_minus_half_floor)); + // Approximate 2^y ~= C2 * y^2 + C1 * y + C0. + static const ALIGN16_BEG float C2[4] ALIGN16_END = + {3.3718944e-1f, 3.3718944e-1f, 3.3718944e-1f, 3.3718944e-1f}; + static const ALIGN16_BEG float C1[4] ALIGN16_END = + {6.5763628e-1f, 6.5763628e-1f, 6.5763628e-1f, 6.5763628e-1f}; + static const ALIGN16_BEG float C0[4] ALIGN16_END = + {1.0017247f, 1.0017247f, 1.0017247f, 1.0017247f}; + const __m128 exp2_y_0 = _mm_mul_ps(y, *((__m128 *)C2)); + const __m128 exp2_y_1 = _mm_add_ps(exp2_y_0, *((__m128 *)C1)); + const __m128 exp2_y_2 = _mm_mul_ps(exp2_y_1, y); + const __m128 exp2_y = _mm_add_ps(exp2_y_2, *((__m128 *)C0)); + + // Combine parts. + a_exp_b = _mm_mul_ps(exp2_y, two_n); + } + return a_exp_b; +} + +extern const float WebRtcAec_weightCurve[65]; +extern const float WebRtcAec_overDriveCurve[65]; + +static void OverdriveAndSuppressSSE2(aec_t *aec, float hNl[PART_LEN1], + const float hNlFb, + float efw[2][PART_LEN1]) { + int i; + const __m128 vec_hNlFb = _mm_set1_ps(hNlFb); + const __m128 vec_one = _mm_set1_ps(1.0f); + const __m128 vec_minus_one = _mm_set1_ps(-1.0f); + const __m128 vec_overDriveSm = _mm_set1_ps(aec->overDriveSm); + // vectorized code (four at once) + for (i = 0; i + 3 < PART_LEN1; i+=4) { + // Weight subbands + __m128 vec_hNl = _mm_loadu_ps(&hNl[i]); + const __m128 vec_weightCurve = _mm_loadu_ps(&WebRtcAec_weightCurve[i]); + const __m128 bigger = _mm_cmpgt_ps(vec_hNl, vec_hNlFb); + const __m128 vec_weightCurve_hNlFb = _mm_mul_ps( + vec_weightCurve, vec_hNlFb); + const __m128 vec_one_weightCurve = _mm_sub_ps(vec_one, vec_weightCurve); + const __m128 vec_one_weightCurve_hNl = _mm_mul_ps( + vec_one_weightCurve, vec_hNl); + const __m128 vec_if0 = _mm_andnot_ps(bigger, vec_hNl); + const __m128 vec_if1 = _mm_and_ps( + bigger, _mm_add_ps(vec_weightCurve_hNlFb, vec_one_weightCurve_hNl)); + vec_hNl = _mm_or_ps(vec_if0, vec_if1); + + { + const __m128 vec_overDriveCurve = _mm_loadu_ps( + &WebRtcAec_overDriveCurve[i]); + const __m128 vec_overDriveSm_overDriveCurve = _mm_mul_ps( + vec_overDriveSm, vec_overDriveCurve); + vec_hNl = mm_pow_ps(vec_hNl, vec_overDriveSm_overDriveCurve); + _mm_storeu_ps(&hNl[i], vec_hNl); + } + + // Suppress error signal + { + __m128 vec_efw_re = _mm_loadu_ps(&efw[0][i]); + __m128 vec_efw_im = _mm_loadu_ps(&efw[1][i]); + vec_efw_re = _mm_mul_ps(vec_efw_re, vec_hNl); + vec_efw_im = _mm_mul_ps(vec_efw_im, vec_hNl); + + // Ooura fft returns incorrect sign on imaginary component. It matters + // here because we are making an additive change with comfort noise. + vec_efw_im = _mm_mul_ps(vec_efw_im, vec_minus_one); + _mm_storeu_ps(&efw[0][i], vec_efw_re); + _mm_storeu_ps(&efw[1][i], vec_efw_im); + } + } + // scalar code for the remaining items. + for (; i < PART_LEN1; i++) { + // Weight subbands + if (hNl[i] > hNlFb) { + hNl[i] = WebRtcAec_weightCurve[i] * hNlFb + + (1 - WebRtcAec_weightCurve[i]) * hNl[i]; + } + hNl[i] = powf(hNl[i], aec->overDriveSm * WebRtcAec_overDriveCurve[i]); + + // Suppress error signal + efw[0][i] *= hNl[i]; + efw[1][i] *= hNl[i]; + + // Ooura fft returns incorrect sign on imaginary component. It matters + // here because we are making an additive change with comfort noise. + efw[1][i] *= -1; + } +} + +void WebRtcAec_InitAec_SSE2(void) { + WebRtcAec_FilterFar = FilterFarSSE2; + WebRtcAec_ScaleErrorSignal = ScaleErrorSignalSSE2; + WebRtcAec_FilterAdaptation = FilterAdaptationSSE2; + WebRtcAec_OverdriveAndSuppress = OverdriveAndSuppressSSE2; +} + diff --git a/libs/miniwebrtc/audio/processing/aec/aec_rdft.c b/libs/miniwebrtc/audio/processing/aec/aec_rdft.c new file mode 100644 index 00000000..137f70d9 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/aec/aec_rdft.c @@ -0,0 +1,589 @@ +/* + * http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html + * Copyright Takuya OOURA, 1996-2001 + * + * You may use, copy, modify and distribute this code for any purpose (include + * commercial use) and without fee. Please refer to this package when you modify + * this code. + * + * Changes by the WebRTC authors: + * - Trivial type modifications. + * - Minimal code subset to do rdft of length 128. + * - Optimizations because of known length. + * + * All changes are covered by the WebRTC license and IP grant: + * 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 "aec_rdft.h" + +#include + +#include "cpu_features_wrapper.h" +#include "typedefs.h" + +// constants shared by all paths (C, SSE2). +float rdft_w[64]; +// constants used by the C path. +float rdft_wk3ri_first[32]; +float rdft_wk3ri_second[32]; +// constants used by SSE2 but initialized in C path. +ALIGN16_BEG float ALIGN16_END rdft_wk1r[32]; +ALIGN16_BEG float ALIGN16_END rdft_wk2r[32]; +ALIGN16_BEG float ALIGN16_END rdft_wk3r[32]; +ALIGN16_BEG float ALIGN16_END rdft_wk1i[32]; +ALIGN16_BEG float ALIGN16_END rdft_wk2i[32]; +ALIGN16_BEG float ALIGN16_END rdft_wk3i[32]; +ALIGN16_BEG float ALIGN16_END cftmdl_wk1r[4]; + +static int ip[16]; + +static void bitrv2_32or128(int n, int *ip, float *a) { + // n is 32 or 128 + int j, j1, k, k1, m, m2; + float xr, xi, yr, yi; + + ip[0] = 0; + { + int l = n; + m = 1; + while ((m << 3) < l) { + l >>= 1; + for (j = 0; j < m; j++) { + ip[m + j] = ip[j] + l; + } + m <<= 1; + } + } + m2 = 2 * m; + for (k = 0; k < m; k++) { + for (j = 0; j < k; j++) { + j1 = 2 * j + ip[k]; + k1 = 2 * k + ip[j]; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 += 2 * m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 -= m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 += 2 * m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + j1 = 2 * k + m2 + ip[k]; + k1 = j1 + m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } +} + +static void makewt_32(void) { + const int nw = 32; + int j, nwh; + float delta, x, y; + + ip[0] = nw; + ip[1] = 1; + nwh = nw >> 1; + delta = atanf(1.0f) / nwh; + rdft_w[0] = 1; + rdft_w[1] = 0; + rdft_w[nwh] = cosf(delta * nwh); + rdft_w[nwh + 1] = rdft_w[nwh]; + for (j = 2; j < nwh; j += 2) { + x = cosf(delta * j); + y = sinf(delta * j); + rdft_w[j] = x; + rdft_w[j + 1] = y; + rdft_w[nw - j] = y; + rdft_w[nw - j + 1] = x; + } + bitrv2_32or128(nw, ip + 2, rdft_w); + + // pre-calculate constants used by cft1st_128 and cftmdl_128... + cftmdl_wk1r[0] = rdft_w[2]; + cftmdl_wk1r[1] = rdft_w[2]; + cftmdl_wk1r[2] = rdft_w[2]; + cftmdl_wk1r[3] = -rdft_w[2]; + { + int k1; + + for (k1 = 0, j = 0; j < 128; j += 16, k1 += 2) { + const int k2 = 2 * k1; + const float wk2r = rdft_w[k1 + 0]; + const float wk2i = rdft_w[k1 + 1]; + float wk1r, wk1i; + // ... scalar version. + wk1r = rdft_w[k2 + 0]; + wk1i = rdft_w[k2 + 1]; + rdft_wk3ri_first[k1 + 0] = wk1r - 2 * wk2i * wk1i; + rdft_wk3ri_first[k1 + 1] = 2 * wk2i * wk1r - wk1i; + wk1r = rdft_w[k2 + 2]; + wk1i = rdft_w[k2 + 3]; + rdft_wk3ri_second[k1 + 0] = wk1r - 2 * wk2r * wk1i; + rdft_wk3ri_second[k1 + 1] = 2 * wk2r * wk1r - wk1i; + // ... vector version. + rdft_wk1r[k2 + 0] = rdft_w[k2 + 0]; + rdft_wk1r[k2 + 1] = rdft_w[k2 + 0]; + rdft_wk1r[k2 + 2] = rdft_w[k2 + 2]; + rdft_wk1r[k2 + 3] = rdft_w[k2 + 2]; + rdft_wk2r[k2 + 0] = rdft_w[k1 + 0]; + rdft_wk2r[k2 + 1] = rdft_w[k1 + 0]; + rdft_wk2r[k2 + 2] = -rdft_w[k1 + 1]; + rdft_wk2r[k2 + 3] = -rdft_w[k1 + 1]; + rdft_wk3r[k2 + 0] = rdft_wk3ri_first[k1 + 0]; + rdft_wk3r[k2 + 1] = rdft_wk3ri_first[k1 + 0]; + rdft_wk3r[k2 + 2] = rdft_wk3ri_second[k1 + 0]; + rdft_wk3r[k2 + 3] = rdft_wk3ri_second[k1 + 0]; + rdft_wk1i[k2 + 0] = -rdft_w[k2 + 1]; + rdft_wk1i[k2 + 1] = rdft_w[k2 + 1]; + rdft_wk1i[k2 + 2] = -rdft_w[k2 + 3]; + rdft_wk1i[k2 + 3] = rdft_w[k2 + 3]; + rdft_wk2i[k2 + 0] = -rdft_w[k1 + 1]; + rdft_wk2i[k2 + 1] = rdft_w[k1 + 1]; + rdft_wk2i[k2 + 2] = -rdft_w[k1 + 0]; + rdft_wk2i[k2 + 3] = rdft_w[k1 + 0]; + rdft_wk3i[k2 + 0] = -rdft_wk3ri_first[k1 + 1]; + rdft_wk3i[k2 + 1] = rdft_wk3ri_first[k1 + 1]; + rdft_wk3i[k2 + 2] = -rdft_wk3ri_second[k1 + 1]; + rdft_wk3i[k2 + 3] = rdft_wk3ri_second[k1 + 1]; + } + } +} + +static void makect_32(void) { + float *c = rdft_w + 32; + const int nc = 32; + int j, nch; + float delta; + + ip[1] = nc; + nch = nc >> 1; + delta = atanf(1.0f) / nch; + c[0] = cosf(delta * nch); + c[nch] = 0.5f * c[0]; + for (j = 1; j < nch; j++) { + c[j] = 0.5f * cosf(delta * j); + c[nc - j] = 0.5f * sinf(delta * j); + } +} + +static void cft1st_128_C(float *a) { + const int n = 128; + int j, k1, k2; + float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; + float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + x0r = a[0] + a[2]; + x0i = a[1] + a[3]; + x1r = a[0] - a[2]; + x1i = a[1] - a[3]; + x2r = a[4] + a[6]; + x2i = a[5] + a[7]; + x3r = a[4] - a[6]; + x3i = a[5] - a[7]; + a[0] = x0r + x2r; + a[1] = x0i + x2i; + a[4] = x0r - x2r; + a[5] = x0i - x2i; + a[2] = x1r - x3i; + a[3] = x1i + x3r; + a[6] = x1r + x3i; + a[7] = x1i - x3r; + wk1r = rdft_w[2]; + x0r = a[8] + a[10]; + x0i = a[9] + a[11]; + x1r = a[8] - a[10]; + x1i = a[9] - a[11]; + x2r = a[12] + a[14]; + x2i = a[13] + a[15]; + x3r = a[12] - a[14]; + x3i = a[13] - a[15]; + a[8] = x0r + x2r; + a[9] = x0i + x2i; + a[12] = x2i - x0i; + a[13] = x0r - x2r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[10] = wk1r * (x0r - x0i); + a[11] = wk1r * (x0r + x0i); + x0r = x3i + x1r; + x0i = x3r - x1i; + a[14] = wk1r * (x0i - x0r); + a[15] = wk1r * (x0i + x0r); + k1 = 0; + for (j = 16; j < n; j += 16) { + k1 += 2; + k2 = 2 * k1; + wk2r = rdft_w[k1 + 0]; + wk2i = rdft_w[k1 + 1]; + wk1r = rdft_w[k2 + 0]; + wk1i = rdft_w[k2 + 1]; + wk3r = rdft_wk3ri_first[k1 + 0]; + wk3i = rdft_wk3ri_first[k1 + 1]; + x0r = a[j + 0] + a[j + 2]; + x0i = a[j + 1] + a[j + 3]; + x1r = a[j + 0] - a[j + 2]; + x1i = a[j + 1] - a[j + 3]; + x2r = a[j + 4] + a[j + 6]; + x2i = a[j + 5] + a[j + 7]; + x3r = a[j + 4] - a[j + 6]; + x3i = a[j + 5] - a[j + 7]; + a[j + 0] = x0r + x2r; + a[j + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j + 4] = wk2r * x0r - wk2i * x0i; + a[j + 5] = wk2r * x0i + wk2i * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j + 2] = wk1r * x0r - wk1i * x0i; + a[j + 3] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j + 6] = wk3r * x0r - wk3i * x0i; + a[j + 7] = wk3r * x0i + wk3i * x0r; + wk1r = rdft_w[k2 + 2]; + wk1i = rdft_w[k2 + 3]; + wk3r = rdft_wk3ri_second[k1 + 0]; + wk3i = rdft_wk3ri_second[k1 + 1]; + x0r = a[j + 8] + a[j + 10]; + x0i = a[j + 9] + a[j + 11]; + x1r = a[j + 8] - a[j + 10]; + x1i = a[j + 9] - a[j + 11]; + x2r = a[j + 12] + a[j + 14]; + x2i = a[j + 13] + a[j + 15]; + x3r = a[j + 12] - a[j + 14]; + x3i = a[j + 13] - a[j + 15]; + a[j + 8] = x0r + x2r; + a[j + 9] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j + 12] = -wk2i * x0r - wk2r * x0i; + a[j + 13] = -wk2i * x0i + wk2r * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j + 10] = wk1r * x0r - wk1i * x0i; + a[j + 11] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j + 14] = wk3r * x0r - wk3i * x0i; + a[j + 15] = wk3r * x0i + wk3i * x0r; + } +} + +static void cftmdl_128_C(float *a) { + const int l = 8; + const int n = 128; + const int m = 32; + int j0, j1, j2, j3, k, k1, k2, m2; + float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; + float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + for (j0 = 0; j0 < l; j0 += 2) { + j1 = j0 + 8; + j2 = j0 + 16; + j3 = j0 + 24; + x0r = a[j0 + 0] + a[j1 + 0]; + x0i = a[j0 + 1] + a[j1 + 1]; + x1r = a[j0 + 0] - a[j1 + 0]; + x1i = a[j0 + 1] - a[j1 + 1]; + x2r = a[j2 + 0] + a[j3 + 0]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2 + 0] - a[j3 + 0]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j0 + 0] = x0r + x2r; + a[j0 + 1] = x0i + x2i; + a[j2 + 0] = x0r - x2r; + a[j2 + 1] = x0i - x2i; + a[j1 + 0] = x1r - x3i; + a[j1 + 1] = x1i + x3r; + a[j3 + 0] = x1r + x3i; + a[j3 + 1] = x1i - x3r; + } + wk1r = rdft_w[2]; + for (j0 = m; j0 < l + m; j0 += 2) { + j1 = j0 + 8; + j2 = j0 + 16; + j3 = j0 + 24; + x0r = a[j0 + 0] + a[j1 + 0]; + x0i = a[j0 + 1] + a[j1 + 1]; + x1r = a[j0 + 0] - a[j1 + 0]; + x1i = a[j0 + 1] - a[j1 + 1]; + x2r = a[j2 + 0] + a[j3 + 0]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2 + 0] - a[j3 + 0]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j0 + 0] = x0r + x2r; + a[j0 + 1] = x0i + x2i; + a[j2 + 0] = x2i - x0i; + a[j2 + 1] = x0r - x2r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1 + 0] = wk1r * (x0r - x0i); + a[j1 + 1] = wk1r * (x0r + x0i); + x0r = x3i + x1r; + x0i = x3r - x1i; + a[j3 + 0] = wk1r * (x0i - x0r); + a[j3 + 1] = wk1r * (x0i + x0r); + } + k1 = 0; + m2 = 2 * m; + for (k = m2; k < n; k += m2) { + k1 += 2; + k2 = 2 * k1; + wk2r = rdft_w[k1 + 0]; + wk2i = rdft_w[k1 + 1]; + wk1r = rdft_w[k2 + 0]; + wk1i = rdft_w[k2 + 1]; + wk3r = rdft_wk3ri_first[k1 + 0]; + wk3i = rdft_wk3ri_first[k1 + 1]; + for (j0 = k; j0 < l + k; j0 += 2) { + j1 = j0 + 8; + j2 = j0 + 16; + j3 = j0 + 24; + x0r = a[j0 + 0] + a[j1 + 0]; + x0i = a[j0 + 1] + a[j1 + 1]; + x1r = a[j0 + 0] - a[j1 + 0]; + x1i = a[j0 + 1] - a[j1 + 1]; + x2r = a[j2 + 0] + a[j3 + 0]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2 + 0] - a[j3 + 0]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j0 + 0] = x0r + x2r; + a[j0 + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j2 + 0] = wk2r * x0r - wk2i * x0i; + a[j2 + 1] = wk2r * x0i + wk2i * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1 + 0] = wk1r * x0r - wk1i * x0i; + a[j1 + 1] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3 + 0] = wk3r * x0r - wk3i * x0i; + a[j3 + 1] = wk3r * x0i + wk3i * x0r; + } + wk1r = rdft_w[k2 + 2]; + wk1i = rdft_w[k2 + 3]; + wk3r = rdft_wk3ri_second[k1 + 0]; + wk3i = rdft_wk3ri_second[k1 + 1]; + for (j0 = k + m; j0 < l + (k + m); j0 += 2) { + j1 = j0 + 8; + j2 = j0 + 16; + j3 = j0 + 24; + x0r = a[j0 + 0] + a[j1 + 0]; + x0i = a[j0 + 1] + a[j1 + 1]; + x1r = a[j0 + 0] - a[j1 + 0]; + x1i = a[j0 + 1] - a[j1 + 1]; + x2r = a[j2 + 0] + a[j3 + 0]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2 + 0] - a[j3 + 0]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j0 + 0] = x0r + x2r; + a[j0 + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j2 + 0] = -wk2i * x0r - wk2r * x0i; + a[j2 + 1] = -wk2i * x0i + wk2r * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1 + 0] = wk1r * x0r - wk1i * x0i; + a[j1 + 1] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3 + 0] = wk3r * x0r - wk3i * x0i; + a[j3 + 1] = wk3r * x0i + wk3i * x0r; + } + } +} + +static void cftfsub_128(float *a) { + int j, j1, j2, j3, l; + float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + cft1st_128(a); + cftmdl_128(a); + l = 32; + for (j = 0; j < l; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + a[j2] = x0r - x2r; + a[j2 + 1] = x0i - x2i; + a[j1] = x1r - x3i; + a[j1 + 1] = x1i + x3r; + a[j3] = x1r + x3i; + a[j3 + 1] = x1i - x3r; + } +} + +static void cftbsub_128(float *a) { + int j, j1, j2, j3, l; + float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + cft1st_128(a); + cftmdl_128(a); + l = 32; + + for (j = 0; j < l; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = -a[j + 1] - a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = -a[j + 1] + a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i - x2i; + a[j2] = x0r - x2r; + a[j2 + 1] = x0i + x2i; + a[j1] = x1r - x3i; + a[j1 + 1] = x1i - x3r; + a[j3] = x1r + x3i; + a[j3 + 1] = x1i + x3r; + } +} + +static void rftfsub_128_C(float *a) { + const float *c = rdft_w + 32; + int j1, j2, k1, k2; + float wkr, wki, xr, xi, yr, yi; + + for (j1 = 1, j2 = 2; j2 < 64; j1 += 1, j2 += 2) { + k2 = 128 - j2; + k1 = 32 - j1; + wkr = 0.5f - c[k1]; + wki = c[j1]; + xr = a[j2 + 0] - a[k2 + 0]; + xi = a[j2 + 1] + a[k2 + 1]; + yr = wkr * xr - wki * xi; + yi = wkr * xi + wki * xr; + a[j2 + 0] -= yr; + a[j2 + 1] -= yi; + a[k2 + 0] += yr; + a[k2 + 1] -= yi; + } +} + +static void rftbsub_128_C(float *a) { + const float *c = rdft_w + 32; + int j1, j2, k1, k2; + float wkr, wki, xr, xi, yr, yi; + + a[1] = -a[1]; + for (j1 = 1, j2 = 2; j2 < 64; j1 += 1, j2 += 2) { + k2 = 128 - j2; + k1 = 32 - j1; + wkr = 0.5f - c[k1]; + wki = c[j1]; + xr = a[j2 + 0] - a[k2 + 0]; + xi = a[j2 + 1] + a[k2 + 1]; + yr = wkr * xr + wki * xi; + yi = wkr * xi - wki * xr; + a[j2 + 0] = a[j2 + 0] - yr; + a[j2 + 1] = yi - a[j2 + 1]; + a[k2 + 0] = yr + a[k2 + 0]; + a[k2 + 1] = yi - a[k2 + 1]; + } + a[65] = -a[65]; +} + +void aec_rdft_forward_128(float *a) { + const int n = 128; + float xi; + + bitrv2_32or128(n, ip + 2, a); + cftfsub_128(a); + rftfsub_128(a); + xi = a[0] - a[1]; + a[0] += a[1]; + a[1] = xi; +} + +void aec_rdft_inverse_128(float *a) { + const int n = 128; + + a[1] = 0.5f * (a[0] - a[1]); + a[0] -= a[1]; + rftbsub_128(a); + bitrv2_32or128(n, ip + 2, a); + cftbsub_128(a); +} + +// code path selection +rft_sub_128_t cft1st_128; +rft_sub_128_t cftmdl_128; +rft_sub_128_t rftfsub_128; +rft_sub_128_t rftbsub_128; + +void aec_rdft_init(void) { + cft1st_128 = cft1st_128_C; + cftmdl_128 = cftmdl_128_C; + rftfsub_128 = rftfsub_128_C; + rftbsub_128 = rftbsub_128_C; +#ifdef SSE2_OPS +#if defined(WEBRTC_ARCH_X86_FAMILY) + if (WebRtc_GetCPUInfo(kSSE2)) { + aec_rdft_init_sse2(); + } +#endif +#endif + // init library constants. + makewt_32(); + makect_32(); +} diff --git a/libs/miniwebrtc/audio/processing/aec/aec_rdft.h b/libs/miniwebrtc/audio/processing/aec/aec_rdft.h new file mode 100644 index 00000000..91bedc9f --- /dev/null +++ b/libs/miniwebrtc/audio/processing/aec/aec_rdft.h @@ -0,0 +1,57 @@ +/* + * 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_PROCESSING_AEC_MAIN_SOURCE_AEC_RDFT_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_RDFT_H_ + +// These intrinsics were unavailable before VS 2008. +// TODO(andrew): move to a common file. +#if defined(_MSC_VER) && _MSC_VER < 1500 +#include +static __inline __m128 _mm_castsi128_ps(__m128i a) { return *(__m128*)&a; } +static __inline __m128i _mm_castps_si128(__m128 a) { return *(__m128i*)&a; } +#endif + +#ifdef _MSC_VER /* visual c++ */ +# define ALIGN16_BEG __declspec(align(16)) +# define ALIGN16_END +#else /* gcc or icc */ +# define ALIGN16_BEG +# define ALIGN16_END __attribute__((aligned(16))) +#endif + +// constants shared by all paths (C, SSE2). +extern float rdft_w[64]; +// constants used by the C path. +extern float rdft_wk3ri_first[32]; +extern float rdft_wk3ri_second[32]; +// constants used by SSE2 but initialized in C path. +extern float rdft_wk1r[32]; +extern float rdft_wk2r[32]; +extern float rdft_wk3r[32]; +extern float rdft_wk1i[32]; +extern float rdft_wk2i[32]; +extern float rdft_wk3i[32]; +extern float cftmdl_wk1r[4]; + +// code path selection function pointers +typedef void (*rft_sub_128_t)(float *a); +extern rft_sub_128_t rftfsub_128; +extern rft_sub_128_t rftbsub_128; +extern rft_sub_128_t cft1st_128; +extern rft_sub_128_t cftmdl_128; + +// entry points +void aec_rdft_init(void); +void aec_rdft_init_sse2(void); +void aec_rdft_forward_128(float *a); +void aec_rdft_inverse_128(float *a); + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_MAIN_SOURCE_AEC_RDFT_H_ diff --git a/libs/miniwebrtc/audio/processing/aec/aec_rdft_sse2.c b/libs/miniwebrtc/audio/processing/aec/aec_rdft_sse2.c new file mode 100644 index 00000000..eeb31524 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/aec/aec_rdft_sse2.c @@ -0,0 +1,427 @@ +/* + * 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 "aec_rdft.h" + +#include + +static const ALIGN16_BEG float ALIGN16_END k_swap_sign[4] = + {-1.f, 1.f, -1.f, 1.f}; + +static void cft1st_128_SSE2(float *a) { + const __m128 mm_swap_sign = _mm_load_ps(k_swap_sign); + int j, k2; + + for (k2 = 0, j = 0; j < 128; j += 16, k2 += 4) { + __m128 a00v = _mm_loadu_ps(&a[j + 0]); + __m128 a04v = _mm_loadu_ps(&a[j + 4]); + __m128 a08v = _mm_loadu_ps(&a[j + 8]); + __m128 a12v = _mm_loadu_ps(&a[j + 12]); + __m128 a01v = _mm_shuffle_ps(a00v, a08v, _MM_SHUFFLE(1, 0, 1 ,0)); + __m128 a23v = _mm_shuffle_ps(a00v, a08v, _MM_SHUFFLE(3, 2, 3 ,2)); + __m128 a45v = _mm_shuffle_ps(a04v, a12v, _MM_SHUFFLE(1, 0, 1 ,0)); + __m128 a67v = _mm_shuffle_ps(a04v, a12v, _MM_SHUFFLE(3, 2, 3 ,2)); + + const __m128 wk1rv = _mm_load_ps(&rdft_wk1r[k2]); + const __m128 wk1iv = _mm_load_ps(&rdft_wk1i[k2]); + const __m128 wk2rv = _mm_load_ps(&rdft_wk2r[k2]); + const __m128 wk2iv = _mm_load_ps(&rdft_wk2i[k2]); + const __m128 wk3rv = _mm_load_ps(&rdft_wk3r[k2]); + const __m128 wk3iv = _mm_load_ps(&rdft_wk3i[k2]); + __m128 x0v = _mm_add_ps(a01v, a23v); + const __m128 x1v = _mm_sub_ps(a01v, a23v); + const __m128 x2v = _mm_add_ps(a45v, a67v); + const __m128 x3v = _mm_sub_ps(a45v, a67v); + __m128 x0w; + a01v = _mm_add_ps(x0v, x2v); + x0v = _mm_sub_ps(x0v, x2v); + x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0 ,1)); + { + const __m128 a45_0v = _mm_mul_ps(wk2rv, x0v); + const __m128 a45_1v = _mm_mul_ps(wk2iv, x0w); + a45v = _mm_add_ps(a45_0v, a45_1v); + } + { + __m128 a23_0v, a23_1v; + const __m128 x3w = _mm_shuffle_ps(x3v, x3v, _MM_SHUFFLE(2, 3, 0 ,1)); + const __m128 x3s = _mm_mul_ps(mm_swap_sign, x3w); + x0v = _mm_add_ps(x1v, x3s); + x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0 ,1)); + a23_0v = _mm_mul_ps(wk1rv, x0v); + a23_1v = _mm_mul_ps(wk1iv, x0w); + a23v = _mm_add_ps(a23_0v, a23_1v); + + x0v = _mm_sub_ps(x1v, x3s); + x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0 ,1)); + } + { + const __m128 a67_0v = _mm_mul_ps(wk3rv, x0v); + const __m128 a67_1v = _mm_mul_ps(wk3iv, x0w); + a67v = _mm_add_ps(a67_0v, a67_1v); + } + + a00v = _mm_shuffle_ps(a01v, a23v, _MM_SHUFFLE(1, 0, 1 ,0)); + a04v = _mm_shuffle_ps(a45v, a67v, _MM_SHUFFLE(1, 0, 1 ,0)); + a08v = _mm_shuffle_ps(a01v, a23v, _MM_SHUFFLE(3, 2, 3 ,2)); + a12v = _mm_shuffle_ps(a45v, a67v, _MM_SHUFFLE(3, 2, 3 ,2)); + _mm_storeu_ps(&a[j + 0], a00v); + _mm_storeu_ps(&a[j + 4], a04v); + _mm_storeu_ps(&a[j + 8], a08v); + _mm_storeu_ps(&a[j + 12], a12v); + } +} + +static void cftmdl_128_SSE2(float *a) { + const int l = 8; + const __m128 mm_swap_sign = _mm_load_ps(k_swap_sign); + int j0; + + __m128 wk1rv = _mm_load_ps(cftmdl_wk1r); + for (j0 = 0; j0 < l; j0 += 2) { + const __m128i a_00 = _mm_loadl_epi64((__m128i*)&a[j0 + 0]); + const __m128i a_08 = _mm_loadl_epi64((__m128i*)&a[j0 + 8]); + const __m128i a_32 = _mm_loadl_epi64((__m128i*)&a[j0 + 32]); + const __m128i a_40 = _mm_loadl_epi64((__m128i*)&a[j0 + 40]); + const __m128 a_00_32 = _mm_shuffle_ps(_mm_castsi128_ps(a_00), + _mm_castsi128_ps(a_32), + _MM_SHUFFLE(1, 0, 1 ,0)); + const __m128 a_08_40 = _mm_shuffle_ps(_mm_castsi128_ps(a_08), + _mm_castsi128_ps(a_40), + _MM_SHUFFLE(1, 0, 1 ,0)); + __m128 x0r0_0i0_0r1_x0i1 = _mm_add_ps(a_00_32, a_08_40); + const __m128 x1r0_1i0_1r1_x1i1 = _mm_sub_ps(a_00_32, a_08_40); + + const __m128i a_16 = _mm_loadl_epi64((__m128i*)&a[j0 + 16]); + const __m128i a_24 = _mm_loadl_epi64((__m128i*)&a[j0 + 24]); + const __m128i a_48 = _mm_loadl_epi64((__m128i*)&a[j0 + 48]); + const __m128i a_56 = _mm_loadl_epi64((__m128i*)&a[j0 + 56]); + const __m128 a_16_48 = _mm_shuffle_ps(_mm_castsi128_ps(a_16), + _mm_castsi128_ps(a_48), + _MM_SHUFFLE(1, 0, 1 ,0)); + const __m128 a_24_56 = _mm_shuffle_ps(_mm_castsi128_ps(a_24), + _mm_castsi128_ps(a_56), + _MM_SHUFFLE(1, 0, 1 ,0)); + const __m128 x2r0_2i0_2r1_x2i1 = _mm_add_ps(a_16_48, a_24_56); + const __m128 x3r0_3i0_3r1_x3i1 = _mm_sub_ps(a_16_48, a_24_56); + + const __m128 xx0 = _mm_add_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); + const __m128 xx1 = _mm_sub_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); + + const __m128 x3i0_3r0_3i1_x3r1 = _mm_castsi128_ps( + _mm_shuffle_epi32(_mm_castps_si128(x3r0_3i0_3r1_x3i1), + _MM_SHUFFLE(2, 3, 0, 1))); + const __m128 x3_swapped = _mm_mul_ps(mm_swap_sign, x3i0_3r0_3i1_x3r1); + const __m128 x1_x3_add = _mm_add_ps(x1r0_1i0_1r1_x1i1, x3_swapped); + const __m128 x1_x3_sub = _mm_sub_ps(x1r0_1i0_1r1_x1i1, x3_swapped); + + const __m128 yy0 = _mm_shuffle_ps(x1_x3_add, x1_x3_sub, + _MM_SHUFFLE(2, 2, 2 ,2)); + const __m128 yy1 = _mm_shuffle_ps(x1_x3_add, x1_x3_sub, + _MM_SHUFFLE(3, 3, 3 ,3)); + const __m128 yy2 = _mm_mul_ps(mm_swap_sign, yy1); + const __m128 yy3 = _mm_add_ps(yy0, yy2); + const __m128 yy4 = _mm_mul_ps(wk1rv, yy3); + + _mm_storel_epi64((__m128i*)&a[j0 + 0], _mm_castps_si128(xx0)); + _mm_storel_epi64((__m128i*)&a[j0 + 32], + _mm_shuffle_epi32(_mm_castps_si128(xx0), + _MM_SHUFFLE(3, 2, 3, 2))); + + _mm_storel_epi64((__m128i*)&a[j0 + 16], _mm_castps_si128(xx1)); + _mm_storel_epi64((__m128i*)&a[j0 + 48], + _mm_shuffle_epi32(_mm_castps_si128(xx1), + _MM_SHUFFLE(2, 3, 2, 3))); + a[j0 + 48] = -a[j0 + 48]; + + _mm_storel_epi64((__m128i*)&a[j0 + 8], _mm_castps_si128(x1_x3_add)); + _mm_storel_epi64((__m128i*)&a[j0 + 24], _mm_castps_si128(x1_x3_sub)); + + _mm_storel_epi64((__m128i*)&a[j0 + 40], _mm_castps_si128(yy4)); + _mm_storel_epi64((__m128i*)&a[j0 + 56], + _mm_shuffle_epi32(_mm_castps_si128(yy4), + _MM_SHUFFLE(2, 3, 2, 3))); + } + + { + int k = 64; + int k1 = 2; + int k2 = 2 * k1; + const __m128 wk2rv = _mm_load_ps(&rdft_wk2r[k2+0]); + const __m128 wk2iv = _mm_load_ps(&rdft_wk2i[k2+0]); + const __m128 wk1iv = _mm_load_ps(&rdft_wk1i[k2+0]); + const __m128 wk3rv = _mm_load_ps(&rdft_wk3r[k2+0]); + const __m128 wk3iv = _mm_load_ps(&rdft_wk3i[k2+0]); + wk1rv = _mm_load_ps(&rdft_wk1r[k2+0]); + for (j0 = k; j0 < l + k; j0 += 2) { + const __m128i a_00 = _mm_loadl_epi64((__m128i*)&a[j0 + 0]); + const __m128i a_08 = _mm_loadl_epi64((__m128i*)&a[j0 + 8]); + const __m128i a_32 = _mm_loadl_epi64((__m128i*)&a[j0 + 32]); + const __m128i a_40 = _mm_loadl_epi64((__m128i*)&a[j0 + 40]); + const __m128 a_00_32 = _mm_shuffle_ps(_mm_castsi128_ps(a_00), + _mm_castsi128_ps(a_32), + _MM_SHUFFLE(1, 0, 1 ,0)); + const __m128 a_08_40 = _mm_shuffle_ps(_mm_castsi128_ps(a_08), + _mm_castsi128_ps(a_40), + _MM_SHUFFLE(1, 0, 1 ,0)); + __m128 x0r0_0i0_0r1_x0i1 = _mm_add_ps(a_00_32, a_08_40); + const __m128 x1r0_1i0_1r1_x1i1 = _mm_sub_ps(a_00_32, a_08_40); + + const __m128i a_16 = _mm_loadl_epi64((__m128i*)&a[j0 + 16]); + const __m128i a_24 = _mm_loadl_epi64((__m128i*)&a[j0 + 24]); + const __m128i a_48 = _mm_loadl_epi64((__m128i*)&a[j0 + 48]); + const __m128i a_56 = _mm_loadl_epi64((__m128i*)&a[j0 + 56]); + const __m128 a_16_48 = _mm_shuffle_ps(_mm_castsi128_ps(a_16), + _mm_castsi128_ps(a_48), + _MM_SHUFFLE(1, 0, 1 ,0)); + const __m128 a_24_56 = _mm_shuffle_ps(_mm_castsi128_ps(a_24), + _mm_castsi128_ps(a_56), + _MM_SHUFFLE(1, 0, 1 ,0)); + const __m128 x2r0_2i0_2r1_x2i1 = _mm_add_ps(a_16_48, a_24_56); + const __m128 x3r0_3i0_3r1_x3i1 = _mm_sub_ps(a_16_48, a_24_56); + + const __m128 xx = _mm_add_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); + const __m128 xx1 = _mm_sub_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); + const __m128 xx2 = _mm_mul_ps(xx1 , wk2rv); + const __m128 xx3 = _mm_mul_ps(wk2iv, + _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(xx1), + _MM_SHUFFLE(2, 3, 0, 1)))); + const __m128 xx4 = _mm_add_ps(xx2, xx3); + + const __m128 x3i0_3r0_3i1_x3r1 = _mm_castsi128_ps( + _mm_shuffle_epi32(_mm_castps_si128(x3r0_3i0_3r1_x3i1), + _MM_SHUFFLE(2, 3, 0, 1))); + const __m128 x3_swapped = _mm_mul_ps(mm_swap_sign, x3i0_3r0_3i1_x3r1); + const __m128 x1_x3_add = _mm_add_ps(x1r0_1i0_1r1_x1i1, x3_swapped); + const __m128 x1_x3_sub = _mm_sub_ps(x1r0_1i0_1r1_x1i1, x3_swapped); + + const __m128 xx10 = _mm_mul_ps(x1_x3_add, wk1rv); + const __m128 xx11 = _mm_mul_ps(wk1iv, + _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(x1_x3_add), + _MM_SHUFFLE(2, 3, 0, 1)))); + const __m128 xx12 = _mm_add_ps(xx10, xx11); + + const __m128 xx20 = _mm_mul_ps(x1_x3_sub, wk3rv); + const __m128 xx21 = _mm_mul_ps(wk3iv, + _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(x1_x3_sub), + _MM_SHUFFLE(2, 3, 0, 1)))); + const __m128 xx22 = _mm_add_ps(xx20, xx21); + + _mm_storel_epi64((__m128i*)&a[j0 + 0], _mm_castps_si128(xx)); + _mm_storel_epi64((__m128i*)&a[j0 + 32], + _mm_shuffle_epi32(_mm_castps_si128(xx), + _MM_SHUFFLE(3, 2, 3, 2))); + + _mm_storel_epi64((__m128i*)&a[j0 + 16], _mm_castps_si128(xx4)); + _mm_storel_epi64((__m128i*)&a[j0 + 48], + _mm_shuffle_epi32(_mm_castps_si128(xx4), + _MM_SHUFFLE(3, 2, 3, 2))); + + _mm_storel_epi64((__m128i*)&a[j0 + 8], _mm_castps_si128(xx12)); + _mm_storel_epi64((__m128i*)&a[j0 + 40], + _mm_shuffle_epi32(_mm_castps_si128(xx12), + _MM_SHUFFLE(3, 2, 3, 2))); + + _mm_storel_epi64((__m128i*)&a[j0 + 24], _mm_castps_si128(xx22)); + _mm_storel_epi64((__m128i*)&a[j0 + 56], + _mm_shuffle_epi32(_mm_castps_si128(xx22), + _MM_SHUFFLE(3, 2, 3, 2))); + } + } +} + +static void rftfsub_128_SSE2(float *a) { + const float *c = rdft_w + 32; + int j1, j2, k1, k2; + float wkr, wki, xr, xi, yr, yi; + + static const ALIGN16_BEG float ALIGN16_END k_half[4] = + {0.5f, 0.5f, 0.5f, 0.5f}; + const __m128 mm_half = _mm_load_ps(k_half); + + // Vectorized code (four at once). + // Note: commented number are indexes for the first iteration of the loop. + for (j1 = 1, j2 = 2; j2 + 7 < 64; j1 += 4, j2 += 8) { + // Load 'wk'. + const __m128 c_j1 = _mm_loadu_ps(&c[ j1]); // 1, 2, 3, 4, + const __m128 c_k1 = _mm_loadu_ps(&c[29 - j1]); // 28, 29, 30, 31, + const __m128 wkrt = _mm_sub_ps(mm_half, c_k1); // 28, 29, 30, 31, + const __m128 wkr_ = + _mm_shuffle_ps(wkrt, wkrt, _MM_SHUFFLE(0, 1, 2, 3)); // 31, 30, 29, 28, + const __m128 wki_ = c_j1; // 1, 2, 3, 4, + // Load and shuffle 'a'. + const __m128 a_j2_0 = _mm_loadu_ps(&a[0 + j2]); // 2, 3, 4, 5, + const __m128 a_j2_4 = _mm_loadu_ps(&a[4 + j2]); // 6, 7, 8, 9, + const __m128 a_k2_0 = _mm_loadu_ps(&a[122 - j2]); // 120, 121, 122, 123, + const __m128 a_k2_4 = _mm_loadu_ps(&a[126 - j2]); // 124, 125, 126, 127, + const __m128 a_j2_p0 = _mm_shuffle_ps(a_j2_0, a_j2_4, + _MM_SHUFFLE(2, 0, 2 ,0)); // 2, 4, 6, 8, + const __m128 a_j2_p1 = _mm_shuffle_ps(a_j2_0, a_j2_4, + _MM_SHUFFLE(3, 1, 3 ,1)); // 3, 5, 7, 9, + const __m128 a_k2_p0 = _mm_shuffle_ps(a_k2_4, a_k2_0, + _MM_SHUFFLE(0, 2, 0 ,2)); // 126, 124, 122, 120, + const __m128 a_k2_p1 = _mm_shuffle_ps(a_k2_4, a_k2_0, + _MM_SHUFFLE(1, 3, 1 ,3)); // 127, 125, 123, 121, + // Calculate 'x'. + const __m128 xr_ = _mm_sub_ps(a_j2_p0, a_k2_p0); + // 2-126, 4-124, 6-122, 8-120, + const __m128 xi_ = _mm_add_ps(a_j2_p1, a_k2_p1); + // 3-127, 5-125, 7-123, 9-121, + // Calculate product into 'y'. + // yr = wkr * xr - wki * xi; + // yi = wkr * xi + wki * xr; + const __m128 a_ = _mm_mul_ps(wkr_, xr_); + const __m128 b_ = _mm_mul_ps(wki_, xi_); + const __m128 c_ = _mm_mul_ps(wkr_, xi_); + const __m128 d_ = _mm_mul_ps(wki_, xr_); + const __m128 yr_ = _mm_sub_ps(a_, b_); // 2-126, 4-124, 6-122, 8-120, + const __m128 yi_ = _mm_add_ps(c_, d_); // 3-127, 5-125, 7-123, 9-121, + // Update 'a'. + // a[j2 + 0] -= yr; + // a[j2 + 1] -= yi; + // a[k2 + 0] += yr; + // a[k2 + 1] -= yi; + const __m128 a_j2_p0n = _mm_sub_ps(a_j2_p0, yr_); // 2, 4, 6, 8, + const __m128 a_j2_p1n = _mm_sub_ps(a_j2_p1, yi_); // 3, 5, 7, 9, + const __m128 a_k2_p0n = _mm_add_ps(a_k2_p0, yr_); // 126, 124, 122, 120, + const __m128 a_k2_p1n = _mm_sub_ps(a_k2_p1, yi_); // 127, 125, 123, 121, + // Shuffle in right order and store. + const __m128 a_j2_0n = _mm_unpacklo_ps(a_j2_p0n, a_j2_p1n); + // 2, 3, 4, 5, + const __m128 a_j2_4n = _mm_unpackhi_ps(a_j2_p0n, a_j2_p1n); + // 6, 7, 8, 9, + const __m128 a_k2_0nt = _mm_unpackhi_ps(a_k2_p0n, a_k2_p1n); + // 122, 123, 120, 121, + const __m128 a_k2_4nt = _mm_unpacklo_ps(a_k2_p0n, a_k2_p1n); + // 126, 127, 124, 125, + const __m128 a_k2_0n = _mm_shuffle_ps(a_k2_0nt, a_k2_0nt, + _MM_SHUFFLE(1, 0, 3 ,2)); // 120, 121, 122, 123, + const __m128 a_k2_4n = _mm_shuffle_ps(a_k2_4nt, a_k2_4nt, + _MM_SHUFFLE(1, 0, 3 ,2)); // 124, 125, 126, 127, + _mm_storeu_ps(&a[0 + j2], a_j2_0n); + _mm_storeu_ps(&a[4 + j2], a_j2_4n); + _mm_storeu_ps(&a[122 - j2], a_k2_0n); + _mm_storeu_ps(&a[126 - j2], a_k2_4n); + } + // Scalar code for the remaining items. + for (; j2 < 64; j1 += 1, j2 += 2) { + k2 = 128 - j2; + k1 = 32 - j1; + wkr = 0.5f - c[k1]; + wki = c[j1]; + xr = a[j2 + 0] - a[k2 + 0]; + xi = a[j2 + 1] + a[k2 + 1]; + yr = wkr * xr - wki * xi; + yi = wkr * xi + wki * xr; + a[j2 + 0] -= yr; + a[j2 + 1] -= yi; + a[k2 + 0] += yr; + a[k2 + 1] -= yi; + } +} + +static void rftbsub_128_SSE2(float *a) { + const float *c = rdft_w + 32; + int j1, j2, k1, k2; + float wkr, wki, xr, xi, yr, yi; + + static const ALIGN16_BEG float ALIGN16_END k_half[4] = + {0.5f, 0.5f, 0.5f, 0.5f}; + const __m128 mm_half = _mm_load_ps(k_half); + + a[1] = -a[1]; + // Vectorized code (four at once). + // Note: commented number are indexes for the first iteration of the loop. + for (j1 = 1, j2 = 2; j2 + 7 < 64; j1 += 4, j2 += 8) { + // Load 'wk'. + const __m128 c_j1 = _mm_loadu_ps(&c[ j1]); // 1, 2, 3, 4, + const __m128 c_k1 = _mm_loadu_ps(&c[29 - j1]); // 28, 29, 30, 31, + const __m128 wkrt = _mm_sub_ps(mm_half, c_k1); // 28, 29, 30, 31, + const __m128 wkr_ = + _mm_shuffle_ps(wkrt, wkrt, _MM_SHUFFLE(0, 1, 2, 3)); // 31, 30, 29, 28, + const __m128 wki_ = c_j1; // 1, 2, 3, 4, + // Load and shuffle 'a'. + const __m128 a_j2_0 = _mm_loadu_ps(&a[0 + j2]); // 2, 3, 4, 5, + const __m128 a_j2_4 = _mm_loadu_ps(&a[4 + j2]); // 6, 7, 8, 9, + const __m128 a_k2_0 = _mm_loadu_ps(&a[122 - j2]); // 120, 121, 122, 123, + const __m128 a_k2_4 = _mm_loadu_ps(&a[126 - j2]); // 124, 125, 126, 127, + const __m128 a_j2_p0 = _mm_shuffle_ps(a_j2_0, a_j2_4, + _MM_SHUFFLE(2, 0, 2 ,0)); // 2, 4, 6, 8, + const __m128 a_j2_p1 = _mm_shuffle_ps(a_j2_0, a_j2_4, + _MM_SHUFFLE(3, 1, 3 ,1)); // 3, 5, 7, 9, + const __m128 a_k2_p0 = _mm_shuffle_ps(a_k2_4, a_k2_0, + _MM_SHUFFLE(0, 2, 0 ,2)); // 126, 124, 122, 120, + const __m128 a_k2_p1 = _mm_shuffle_ps(a_k2_4, a_k2_0, + _MM_SHUFFLE(1, 3, 1 ,3)); // 127, 125, 123, 121, + // Calculate 'x'. + const __m128 xr_ = _mm_sub_ps(a_j2_p0, a_k2_p0); + // 2-126, 4-124, 6-122, 8-120, + const __m128 xi_ = _mm_add_ps(a_j2_p1, a_k2_p1); + // 3-127, 5-125, 7-123, 9-121, + // Calculate product into 'y'. + // yr = wkr * xr + wki * xi; + // yi = wkr * xi - wki * xr; + const __m128 a_ = _mm_mul_ps(wkr_, xr_); + const __m128 b_ = _mm_mul_ps(wki_, xi_); + const __m128 c_ = _mm_mul_ps(wkr_, xi_); + const __m128 d_ = _mm_mul_ps(wki_, xr_); + const __m128 yr_ = _mm_add_ps(a_, b_); // 2-126, 4-124, 6-122, 8-120, + const __m128 yi_ = _mm_sub_ps(c_, d_); // 3-127, 5-125, 7-123, 9-121, + // Update 'a'. + // a[j2 + 0] = a[j2 + 0] - yr; + // a[j2 + 1] = yi - a[j2 + 1]; + // a[k2 + 0] = yr + a[k2 + 0]; + // a[k2 + 1] = yi - a[k2 + 1]; + const __m128 a_j2_p0n = _mm_sub_ps(a_j2_p0, yr_); // 2, 4, 6, 8, + const __m128 a_j2_p1n = _mm_sub_ps(yi_, a_j2_p1); // 3, 5, 7, 9, + const __m128 a_k2_p0n = _mm_add_ps(a_k2_p0, yr_); // 126, 124, 122, 120, + const __m128 a_k2_p1n = _mm_sub_ps(yi_, a_k2_p1); // 127, 125, 123, 121, + // Shuffle in right order and store. + const __m128 a_j2_0n = _mm_unpacklo_ps(a_j2_p0n, a_j2_p1n); + // 2, 3, 4, 5, + const __m128 a_j2_4n = _mm_unpackhi_ps(a_j2_p0n, a_j2_p1n); + // 6, 7, 8, 9, + const __m128 a_k2_0nt = _mm_unpackhi_ps(a_k2_p0n, a_k2_p1n); + // 122, 123, 120, 121, + const __m128 a_k2_4nt = _mm_unpacklo_ps(a_k2_p0n, a_k2_p1n); + // 126, 127, 124, 125, + const __m128 a_k2_0n = _mm_shuffle_ps(a_k2_0nt, a_k2_0nt, + _MM_SHUFFLE(1, 0, 3 ,2)); // 120, 121, 122, 123, + const __m128 a_k2_4n = _mm_shuffle_ps(a_k2_4nt, a_k2_4nt, + _MM_SHUFFLE(1, 0, 3 ,2)); // 124, 125, 126, 127, + _mm_storeu_ps(&a[0 + j2], a_j2_0n); + _mm_storeu_ps(&a[4 + j2], a_j2_4n); + _mm_storeu_ps(&a[122 - j2], a_k2_0n); + _mm_storeu_ps(&a[126 - j2], a_k2_4n); + } + // Scalar code for the remaining items. + for (; j2 < 64; j1 += 1, j2 += 2) { + k2 = 128 - j2; + k1 = 32 - j1; + wkr = 0.5f - c[k1]; + wki = c[j1]; + xr = a[j2 + 0] - a[k2 + 0]; + xi = a[j2 + 1] + a[k2 + 1]; + yr = wkr * xr + wki * xi; + yi = wkr * xi - wki * xr; + a[j2 + 0] = a[j2 + 0] - yr; + a[j2 + 1] = yi - a[j2 + 1]; + a[k2 + 0] = yr + a[k2 + 0]; + a[k2 + 1] = yi - a[k2 + 1]; + } + a[65] = -a[65]; +} + +void aec_rdft_init_sse2(void) { + cft1st_128 = cft1st_128_SSE2; + cftmdl_128 = cftmdl_128_SSE2; + rftfsub_128 = rftfsub_128_SSE2; + rftbsub_128 = rftbsub_128_SSE2; +} + diff --git a/libs/miniwebrtc/audio/processing/aec/aec_resampler.c b/libs/miniwebrtc/audio/processing/aec/aec_resampler.c new file mode 100644 index 00000000..ea980cd9 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/aec/aec_resampler.c @@ -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. + */ + +/* Resamples a signal to an arbitrary rate. Used by the AEC to compensate for clock + * skew by resampling the farend signal. + */ + +#include "aec_resampler.h" + +#include +#include +#include +#include + +#include "aec_core.h" + +enum { kEstimateLengthFrames = 400 }; + +typedef struct { + short buffer[kResamplerBufferSize]; + float position; + + int deviceSampleRateHz; + int skewData[kEstimateLengthFrames]; + int skewDataIndex; + float skewEstimate; +} resampler_t; + +static int EstimateSkew(const int* rawSkew, + int size, + int absLimit, + float *skewEst); + +int WebRtcAec_CreateResampler(void **resampInst) +{ + resampler_t *obj = malloc(sizeof(resampler_t)); + *resampInst = obj; + if (obj == NULL) { + return -1; + } + + return 0; +} + +int WebRtcAec_InitResampler(void *resampInst, int deviceSampleRateHz) +{ + resampler_t *obj = (resampler_t*) resampInst; + memset(obj->buffer, 0, sizeof(obj->buffer)); + obj->position = 0.0; + + obj->deviceSampleRateHz = deviceSampleRateHz; + memset(obj->skewData, 0, sizeof(obj->skewData)); + obj->skewDataIndex = 0; + obj->skewEstimate = 0.0; + + return 0; +} + +int WebRtcAec_FreeResampler(void *resampInst) +{ + resampler_t *obj = (resampler_t*) resampInst; + free(obj); + + return 0; +} + +int WebRtcAec_ResampleLinear(void *resampInst, + const short *inspeech, + int size, + float skew, + short *outspeech) +{ + resampler_t *obj = (resampler_t*) resampInst; + + short *y; + float be, tnew, interp; + int tn, outsize, mm; + + if (size < 0 || size > 2 * FRAME_LEN) { + return -1; + } + + // Add new frame data in lookahead + memcpy(&obj->buffer[FRAME_LEN + kResamplingDelay], + inspeech, + size * sizeof(short)); + + // Sample rate ratio + be = 1 + skew; + + // Loop over input frame + mm = 0; + y = &obj->buffer[FRAME_LEN]; // Point at current frame + + tnew = be * mm + obj->position; + tn = (int) tnew; + + while (tn < size) { + + // Interpolation + interp = y[tn] + (tnew - tn) * (y[tn+1] - y[tn]); + + if (interp > 32767) { + interp = 32767; + } + else if (interp < -32768) { + interp = -32768; + } + + outspeech[mm] = (short) interp; + mm++; + + tnew = be * mm + obj->position; + tn = (int) tnew; + } + + outsize = mm; + obj->position += outsize * be - size; + + // Shift buffer + memmove(obj->buffer, + &obj->buffer[size], + (kResamplerBufferSize - size) * sizeof(short)); + + return outsize; +} + +int WebRtcAec_GetSkew(void *resampInst, int rawSkew, float *skewEst) +{ + resampler_t *obj = (resampler_t*)resampInst; + int err = 0; + + if (obj->skewDataIndex < kEstimateLengthFrames) { + obj->skewData[obj->skewDataIndex] = rawSkew; + obj->skewDataIndex++; + } + else if (obj->skewDataIndex == kEstimateLengthFrames) { + err = EstimateSkew(obj->skewData, + kEstimateLengthFrames, + obj->deviceSampleRateHz, + skewEst); + obj->skewEstimate = *skewEst; + obj->skewDataIndex++; + } + else { + *skewEst = obj->skewEstimate; + } + + return err; +} + +int EstimateSkew(const int* rawSkew, + int size, + int deviceSampleRateHz, + float *skewEst) +{ + const int absLimitOuter = (int)(0.04f * deviceSampleRateHz); + const int absLimitInner = (int)(0.0025f * deviceSampleRateHz); + int i = 0; + int n = 0; + float rawAvg = 0; + float err = 0; + float rawAbsDev = 0; + int upperLimit = 0; + int lowerLimit = 0; + float cumSum = 0; + float x = 0; + float x2 = 0; + float y = 0; + float xy = 0; + float xAvg = 0; + float denom = 0; + float skew = 0; + + *skewEst = 0; // Set in case of error below. + for (i = 0; i < size; i++) { + if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) { + n++; + rawAvg += rawSkew[i]; + } + } + + if (n == 0) { + return -1; + } + assert(n > 0); + rawAvg /= n; + + for (i = 0; i < size; i++) { + if ((rawSkew[i] < absLimitOuter && rawSkew[i] > -absLimitOuter)) { + err = rawSkew[i] - rawAvg; + rawAbsDev += err >= 0 ? err : -err; + } + } + assert(n > 0); + rawAbsDev /= n; + upperLimit = (int)(rawAvg + 5 * rawAbsDev + 1); // +1 for ceiling. + lowerLimit = (int)(rawAvg - 5 * rawAbsDev - 1); // -1 for floor. + + n = 0; + for (i = 0; i < size; i++) { + if ((rawSkew[i] < absLimitInner && rawSkew[i] > -absLimitInner) || + (rawSkew[i] < upperLimit && rawSkew[i] > lowerLimit)) { + n++; + cumSum += rawSkew[i]; + x += n; + x2 += n*n; + y += cumSum; + xy += n * cumSum; + } + } + + if (n == 0) { + return -1; + } + assert(n > 0); + xAvg = x / n; + denom = x2 - xAvg*x; + + if (denom != 0) { + skew = (xy - xAvg*y) / denom; + } + + *skewEst = skew; + return 0; +} diff --git a/libs/miniwebrtc/audio/processing/aec/aec_resampler.h b/libs/miniwebrtc/audio/processing/aec/aec_resampler.h new file mode 100644 index 00000000..ab4cc6ec --- /dev/null +++ b/libs/miniwebrtc/audio/processing/aec/aec_resampler.h @@ -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. + */ + +#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_RESAMPLER_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_RESAMPLER_H_ + +#include "aec_core.h" + +enum { kResamplingDelay = 1 }; +enum { kResamplerBufferSize = FRAME_LEN * 4 }; + +// Unless otherwise specified, functions return 0 on success and -1 on error +int WebRtcAec_CreateResampler(void **resampInst); +int WebRtcAec_InitResampler(void *resampInst, int deviceSampleRateHz); +int WebRtcAec_FreeResampler(void *resampInst); + +// Estimates skew from raw measurement. +int WebRtcAec_GetSkew(void *resampInst, int rawSkew, float *skewEst); + +// Resamples input using linear interpolation. +// Returns size of resampled array. +int WebRtcAec_ResampleLinear(void *resampInst, + const short *inspeech, + int size, + float skew, + short *outspeech); + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_AEC_RESAMPLER_H_ diff --git a/libs/miniwebrtc/audio/processing/aec/echo_cancellation.c b/libs/miniwebrtc/audio/processing/aec/echo_cancellation.c new file mode 100644 index 00000000..f3176f3b --- /dev/null +++ b/libs/miniwebrtc/audio/processing/aec/echo_cancellation.c @@ -0,0 +1,924 @@ +/* + * 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 API functions for the AEC. + */ +#include "echo_cancellation.h" + +#include +#ifdef WEBRTC_AEC_DEBUG_DUMP +#include +#endif +#include +#include + +#include "aec_core.h" +#include "aec_resampler.h" +#include "signal_processing_library.h" +#include "ring_buffer.h" +#include "typedefs.h" + +// Maximum length of resampled signal. Must be an integer multiple of frames +// (ceil(1/(1 + MIN_SKEW)*2) + 1)*FRAME_LEN +// The factor of 2 handles wb, and the + 1 is as a safety margin +// TODO(bjornv): Replace with kResamplerBufferSize +#define MAX_RESAMP_LEN (5 * FRAME_LEN) + +static const int kMaxBufSizeStart = 62; // In partitions +static const int sampMsNb = 8; // samples per ms in nb +// Target suppression levels for nlp modes +// log{0.001, 0.00001, 0.00000001} +static const float targetSupp[3] = {-6.9f, -11.5f, -18.4f}; +static const float minOverDrive[3] = {1.0f, 2.0f, 5.0f}; +static const int initCheck = 42; + +#ifdef WEBRTC_AEC_DEBUG_DUMP +static int instance_count = 0; +#endif + +typedef struct { + int delayCtr; + int sampFreq; + int splitSampFreq; + int scSampFreq; + float sampFactor; // scSampRate / sampFreq + short nlpMode; + short autoOnOff; + short activity; + short skewMode; + int bufSizeStart; + //short bufResetCtr; // counts number of noncausal frames + int knownDelay; + + short initFlag; // indicates if AEC has been initialized + + // Variables used for averaging far end buffer size + short counter; + int sum; + short firstVal; + short checkBufSizeCtr; + + // Variables used for delay shifts + short msInSndCardBuf; + short filtDelay; // Filtered delay estimate. + int timeForDelayChange; + int ECstartup; + int checkBuffSize; + short lastDelayDiff; + +#ifdef WEBRTC_AEC_DEBUG_DUMP + void* far_pre_buf_s16; // Time domain far-end pre-buffer in int16_t. + FILE *bufFile; + FILE *delayFile; + FILE *skewFile; +#endif + + // Structures + void *resampler; + + int skewFrCtr; + int resample; // if the skew is small enough we don't resample + int highSkewCtr; + float skew; + + void* far_pre_buf; // Time domain far-end pre-buffer. + + int lastError; + + aec_t *aec; +} aecpc_t; + +// Estimates delay to set the position of the far-end buffer read pointer +// (controlled by knownDelay) +static int EstBufDelay(aecpc_t *aecInst); + +WebRtc_Word32 WebRtcAec_Create(void **aecInst) +{ + aecpc_t *aecpc; + if (aecInst == NULL) { + return -1; + } + + aecpc = malloc(sizeof(aecpc_t)); + *aecInst = aecpc; + if (aecpc == NULL) { + return -1; + } + + if (WebRtcAec_CreateAec(&aecpc->aec) == -1) { + WebRtcAec_Free(aecpc); + aecpc = NULL; + return -1; + } + + if (WebRtcAec_CreateResampler(&aecpc->resampler) == -1) { + WebRtcAec_Free(aecpc); + aecpc = NULL; + return -1; + } + // Create far-end pre-buffer. The buffer size has to be large enough for + // largest possible drift compensation (kResamplerBufferSize) + "almost" an + // FFT buffer (PART_LEN2 - 1). + if (WebRtc_CreateBuffer(&aecpc->far_pre_buf, + PART_LEN2 + kResamplerBufferSize, + sizeof(float)) == -1) { + WebRtcAec_Free(aecpc); + aecpc = NULL; + return -1; + } + + aecpc->initFlag = 0; + aecpc->lastError = 0; + +#ifdef WEBRTC_AEC_DEBUG_DUMP + if (WebRtc_CreateBuffer(&aecpc->far_pre_buf_s16, + PART_LEN2 + kResamplerBufferSize, + sizeof(int16_t)) == -1) { + WebRtcAec_Free(aecpc); + aecpc = NULL; + return -1; + } + { + char filename[64]; + sprintf(filename, "aec_far%d.pcm", instance_count); + aecpc->aec->farFile = fopen(filename, "wb"); + sprintf(filename, "aec_near%d.pcm", instance_count); + aecpc->aec->nearFile = fopen(filename, "wb"); + sprintf(filename, "aec_out%d.pcm", instance_count); + aecpc->aec->outFile = fopen(filename, "wb"); + sprintf(filename, "aec_out_linear%d.pcm", instance_count); + aecpc->aec->outLinearFile = fopen(filename, "wb"); + sprintf(filename, "aec_buf%d.dat", instance_count); + aecpc->bufFile = fopen(filename, "wb"); + sprintf(filename, "aec_skew%d.dat", instance_count); + aecpc->skewFile = fopen(filename, "wb"); + sprintf(filename, "aec_delay%d.dat", instance_count); + aecpc->delayFile = fopen(filename, "wb"); + instance_count++; + } +#endif + + return 0; +} + +WebRtc_Word32 WebRtcAec_Free(void *aecInst) +{ + aecpc_t *aecpc = aecInst; + + if (aecpc == NULL) { + return -1; + } + + WebRtc_FreeBuffer(aecpc->far_pre_buf); + +#ifdef WEBRTC_AEC_DEBUG_DUMP + WebRtc_FreeBuffer(aecpc->far_pre_buf_s16); + fclose(aecpc->aec->farFile); + fclose(aecpc->aec->nearFile); + fclose(aecpc->aec->outFile); + fclose(aecpc->aec->outLinearFile); + fclose(aecpc->bufFile); + fclose(aecpc->skewFile); + fclose(aecpc->delayFile); +#endif + + WebRtcAec_FreeAec(aecpc->aec); + WebRtcAec_FreeResampler(aecpc->resampler); + free(aecpc); + + return 0; +} + +WebRtc_Word32 WebRtcAec_Init(void *aecInst, WebRtc_Word32 sampFreq, WebRtc_Word32 scSampFreq) +{ + aecpc_t *aecpc = aecInst; + AecConfig aecConfig; + + if (aecpc == NULL) { + return -1; + } + + if (sampFreq != 8000 && sampFreq != 16000 && sampFreq != 32000) { + aecpc->lastError = AEC_BAD_PARAMETER_ERROR; + return -1; + } + aecpc->sampFreq = sampFreq; + + if (scSampFreq < 1 || scSampFreq > 96000) { + aecpc->lastError = AEC_BAD_PARAMETER_ERROR; + return -1; + } + aecpc->scSampFreq = scSampFreq; + + // Initialize echo canceller core + if (WebRtcAec_InitAec(aecpc->aec, aecpc->sampFreq) == -1) { + aecpc->lastError = AEC_UNSPECIFIED_ERROR; + return -1; + } + + if (WebRtcAec_InitResampler(aecpc->resampler, aecpc->scSampFreq) == -1) { + aecpc->lastError = AEC_UNSPECIFIED_ERROR; + return -1; + } + + if (WebRtc_InitBuffer(aecpc->far_pre_buf) == -1) { + aecpc->lastError = AEC_UNSPECIFIED_ERROR; + return -1; + } + WebRtc_MoveReadPtr(aecpc->far_pre_buf, -PART_LEN); // Start overlap. + + aecpc->initFlag = initCheck; // indicates that initialization has been done + + if (aecpc->sampFreq == 32000) { + aecpc->splitSampFreq = 16000; + } + else { + aecpc->splitSampFreq = sampFreq; + } + + aecpc->skewFrCtr = 0; + aecpc->activity = 0; + + aecpc->delayCtr = 0; + + aecpc->sum = 0; + aecpc->counter = 0; + aecpc->checkBuffSize = 1; + aecpc->firstVal = 0; + + aecpc->ECstartup = 1; + aecpc->bufSizeStart = 0; + aecpc->checkBufSizeCtr = 0; + aecpc->filtDelay = 0; + aecpc->timeForDelayChange = 0; + aecpc->knownDelay = 0; + aecpc->lastDelayDiff = 0; + + aecpc->skew = 0; + aecpc->resample = kAecFalse; + aecpc->highSkewCtr = 0; + aecpc->sampFactor = (aecpc->scSampFreq * 1.0f) / aecpc->splitSampFreq; + + // Default settings. + aecConfig.nlpMode = kAecNlpModerate; + aecConfig.skewMode = kAecFalse; + aecConfig.metricsMode = kAecFalse; + aecConfig.delay_logging = kAecFalse; + + if (WebRtcAec_set_config(aecpc, aecConfig) == -1) { + aecpc->lastError = AEC_UNSPECIFIED_ERROR; + return -1; + } + +#ifdef WEBRTC_AEC_DEBUG_DUMP + if (WebRtc_InitBuffer(aecpc->far_pre_buf_s16) == -1) { + aecpc->lastError = AEC_UNSPECIFIED_ERROR; + return -1; + } + WebRtc_MoveReadPtr(aecpc->far_pre_buf_s16, -PART_LEN); // Start overlap. +#endif + + return 0; +} + +// only buffer L band for farend +WebRtc_Word32 WebRtcAec_BufferFarend(void *aecInst, const WebRtc_Word16 *farend, + WebRtc_Word16 nrOfSamples) +{ + aecpc_t *aecpc = aecInst; + WebRtc_Word32 retVal = 0; + int newNrOfSamples = (int) nrOfSamples; + short newFarend[MAX_RESAMP_LEN]; + const int16_t* farend_ptr = farend; + float tmp_farend[MAX_RESAMP_LEN]; + const float* farend_float = tmp_farend; + float skew; + int i = 0; + + if (aecpc == NULL) { + return -1; + } + + if (farend == NULL) { + aecpc->lastError = AEC_NULL_POINTER_ERROR; + return -1; + } + + if (aecpc->initFlag != initCheck) { + aecpc->lastError = AEC_UNINITIALIZED_ERROR; + return -1; + } + + // number of samples == 160 for SWB input + if (nrOfSamples != 80 && nrOfSamples != 160) { + aecpc->lastError = AEC_BAD_PARAMETER_ERROR; + return -1; + } + + skew = aecpc->skew; + + if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) { + // Resample and get a new number of samples + newNrOfSamples = WebRtcAec_ResampleLinear(aecpc->resampler, + farend, + nrOfSamples, + skew, + newFarend); + farend_ptr = (const int16_t*) newFarend; + } + + aecpc->aec->system_delay += newNrOfSamples; + +#ifdef WEBRTC_AEC_DEBUG_DUMP + WebRtc_WriteBuffer(aecpc->far_pre_buf_s16, farend_ptr, + (size_t) newNrOfSamples); +#endif + // Cast to float and write the time-domain data to |far_pre_buf|. + for (i = 0; i < newNrOfSamples; i++) { + tmp_farend[i] = (float) farend_ptr[i]; + } + WebRtc_WriteBuffer(aecpc->far_pre_buf, farend_float, + (size_t) newNrOfSamples); + + // Transform to frequency domain if we have enough data. + while (WebRtc_available_read(aecpc->far_pre_buf) >= PART_LEN2) { + // We have enough data to pass to the FFT, hence read PART_LEN2 samples. + WebRtc_ReadBuffer(aecpc->far_pre_buf, (void**) &farend_float, tmp_farend, + PART_LEN2); + + WebRtcAec_BufferFarendPartition(aecpc->aec, farend_float); + + // Rewind |far_pre_buf| PART_LEN samples for overlap before continuing. + WebRtc_MoveReadPtr(aecpc->far_pre_buf, -PART_LEN); +#ifdef WEBRTC_AEC_DEBUG_DUMP + WebRtc_ReadBuffer(aecpc->far_pre_buf_s16, (void**) &farend_ptr, newFarend, + PART_LEN2); + WebRtc_WriteBuffer(aecpc->aec->far_time_buf, &farend_ptr[PART_LEN], 1); + WebRtc_MoveReadPtr(aecpc->far_pre_buf_s16, -PART_LEN); +#endif + } + + return retVal; +} + +WebRtc_Word32 WebRtcAec_Process(void *aecInst, const WebRtc_Word16 *nearend, + const WebRtc_Word16 *nearendH, WebRtc_Word16 *out, WebRtc_Word16 *outH, + WebRtc_Word16 nrOfSamples, WebRtc_Word16 msInSndCardBuf, WebRtc_Word32 skew) +{ + aecpc_t *aecpc = aecInst; + WebRtc_Word32 retVal = 0; + short i; + short nBlocks10ms; + short nFrames; + // Limit resampling to doubling/halving of signal + const float minSkewEst = -0.5f; + const float maxSkewEst = 1.0f; + + if (aecpc == NULL) { + return -1; + } + + if (nearend == NULL) { + aecpc->lastError = AEC_NULL_POINTER_ERROR; + return -1; + } + + if (out == NULL) { + aecpc->lastError = AEC_NULL_POINTER_ERROR; + return -1; + } + + if (aecpc->initFlag != initCheck) { + aecpc->lastError = AEC_UNINITIALIZED_ERROR; + return -1; + } + + // number of samples == 160 for SWB input + if (nrOfSamples != 80 && nrOfSamples != 160) { + aecpc->lastError = AEC_BAD_PARAMETER_ERROR; + return -1; + } + + // Check for valid pointers based on sampling rate + if (aecpc->sampFreq == 32000 && nearendH == NULL) { + aecpc->lastError = AEC_NULL_POINTER_ERROR; + return -1; + } + + if (msInSndCardBuf < 0) { + msInSndCardBuf = 0; + aecpc->lastError = AEC_BAD_PARAMETER_WARNING; + retVal = -1; + } + else if (msInSndCardBuf > 500) { + msInSndCardBuf = 500; + aecpc->lastError = AEC_BAD_PARAMETER_WARNING; + retVal = -1; + } + // TODO(andrew): we need to investigate if this +10 is really wanted. + msInSndCardBuf += 10; + aecpc->msInSndCardBuf = msInSndCardBuf; + + if (aecpc->skewMode == kAecTrue) { + if (aecpc->skewFrCtr < 25) { + aecpc->skewFrCtr++; + } + else { + retVal = WebRtcAec_GetSkew(aecpc->resampler, skew, &aecpc->skew); + if (retVal == -1) { + aecpc->skew = 0; + aecpc->lastError = AEC_BAD_PARAMETER_WARNING; + } + + aecpc->skew /= aecpc->sampFactor*nrOfSamples; + + if (aecpc->skew < 1.0e-3 && aecpc->skew > -1.0e-3) { + aecpc->resample = kAecFalse; + } + else { + aecpc->resample = kAecTrue; + } + + if (aecpc->skew < minSkewEst) { + aecpc->skew = minSkewEst; + } + else if (aecpc->skew > maxSkewEst) { + aecpc->skew = maxSkewEst; + } + +#ifdef WEBRTC_AEC_DEBUG_DUMP + fwrite(&aecpc->skew, sizeof(aecpc->skew), 1, aecpc->skewFile); +#endif + } + } + + nFrames = nrOfSamples / FRAME_LEN; + nBlocks10ms = nFrames / aecpc->aec->mult; + + if (aecpc->ECstartup) { + if (nearend != out) { + // Only needed if they don't already point to the same place. + memcpy(out, nearend, sizeof(short) * nrOfSamples); + } + + // The AEC is in the start up mode + // AEC is disabled until the system delay is OK + + // Mechanism to ensure that the system delay is reasonably stable. + if (aecpc->checkBuffSize) { + aecpc->checkBufSizeCtr++; + // Before we fill up the far-end buffer we require the system delay + // to be stable (+/-8 ms) compared to the first value. This + // comparison is made during the following 6 consecutive 10 ms + // blocks. If it seems to be stable then we start to fill up the + // far-end buffer. + if (aecpc->counter == 0) { + aecpc->firstVal = aecpc->msInSndCardBuf; + aecpc->sum = 0; + } + + if (abs(aecpc->firstVal - aecpc->msInSndCardBuf) < + WEBRTC_SPL_MAX(0.2 * aecpc->msInSndCardBuf, sampMsNb)) { + aecpc->sum += aecpc->msInSndCardBuf; + aecpc->counter++; + } + else { + aecpc->counter = 0; + } + + if (aecpc->counter * nBlocks10ms >= 6) { + // The far-end buffer size is determined in partitions of + // PART_LEN samples. Use 75% of the average value of the system + // delay as buffer size to start with. + aecpc->bufSizeStart = WEBRTC_SPL_MIN((3 * aecpc->sum * + aecpc->aec->mult * 8) / (4 * aecpc->counter * PART_LEN), + kMaxBufSizeStart); + // Buffer size has now been determined. + aecpc->checkBuffSize = 0; + } + + if (aecpc->checkBufSizeCtr * nBlocks10ms > 50) { + // For really bad systems, don't disable the echo canceller for + // more than 0.5 sec. + aecpc->bufSizeStart = WEBRTC_SPL_MIN((aecpc->msInSndCardBuf * + aecpc->aec->mult * 3) / 40, kMaxBufSizeStart); + aecpc->checkBuffSize = 0; + } + } + + // If |checkBuffSize| changed in the if-statement above. + if (!aecpc->checkBuffSize) { + // The system delay is now reasonably stable (or has been unstable + // for too long). When the far-end buffer is filled with + // approximately the same amount of data as reported by the system + // we end the startup phase. + int overhead_elements = aecpc->aec->system_delay / PART_LEN - + aecpc->bufSizeStart; + if (overhead_elements == 0) { + // Enable the AEC + aecpc->ECstartup = 0; + } else if (overhead_elements > 0) { + WebRtc_MoveReadPtr(aecpc->aec->far_buf_windowed, + overhead_elements); + WebRtc_MoveReadPtr(aecpc->aec->far_buf, overhead_elements); +#ifdef WEBRTC_AEC_DEBUG_DUMP + WebRtc_MoveReadPtr(aecpc->aec->far_time_buf, overhead_elements); +#endif + // TODO(bjornv): Do we need a check on how much we actually + // moved the read pointer? It should always be possible to move + // the pointer |overhead_elements| since we have only added data + // to the buffer and no delay compensation nor AEC processing + // has been done. + aecpc->aec->system_delay -= overhead_elements * PART_LEN; + + // Enable the AEC + aecpc->ECstartup = 0; + } + } + } else { + // AEC is enabled. + + int out_elements = 0; + + EstBufDelay(aecpc); + + // Note that 1 frame is supported for NB and 2 frames for WB. + for (i = 0; i < nFrames; i++) { + int16_t* out_ptr = NULL; + int16_t out_tmp[FRAME_LEN]; + + // Call the AEC. + WebRtcAec_ProcessFrame(aecpc->aec, + &nearend[FRAME_LEN * i], + &nearendH[FRAME_LEN * i], + aecpc->knownDelay); + // TODO(bjornv): Re-structure such that we don't have to pass + // |aecpc->knownDelay| as input. Change name to something like + // |system_buffer_diff|. + + // Stuff the out buffer if we have less than a frame to output. + // This should only happen for the first frame. + out_elements = (int) WebRtc_available_read(aecpc->aec->outFrBuf); + if (out_elements < FRAME_LEN) { + WebRtc_MoveReadPtr(aecpc->aec->outFrBuf, + out_elements - FRAME_LEN); + if (aecpc->sampFreq == 32000) { + WebRtc_MoveReadPtr(aecpc->aec->outFrBufH, + out_elements - FRAME_LEN); + } + } + + // Obtain an output frame. + WebRtc_ReadBuffer(aecpc->aec->outFrBuf, (void**) &out_ptr, + out_tmp, FRAME_LEN); + memcpy(&out[FRAME_LEN * i], out_ptr, sizeof(int16_t) * FRAME_LEN); + // For H band + if (aecpc->sampFreq == 32000) { + WebRtc_ReadBuffer(aecpc->aec->outFrBufH, (void**) &out_ptr, + out_tmp, FRAME_LEN); + memcpy(&outH[FRAME_LEN * i], out_ptr, + sizeof(int16_t) * FRAME_LEN); + } + } + } + +#ifdef WEBRTC_AEC_DEBUG_DUMP + { + int16_t far_buf_size_ms = (int16_t) (aecpc->aec->system_delay / + (sampMsNb * aecpc->aec->mult)); + fwrite(&far_buf_size_ms, 2, 1, aecpc->bufFile); + fwrite(&(aecpc->knownDelay), sizeof(aecpc->knownDelay), 1, aecpc->delayFile); + } +#endif + + return retVal; +} + +WebRtc_Word32 WebRtcAec_set_config(void *aecInst, AecConfig config) +{ + aecpc_t *aecpc = aecInst; + + if (aecpc == NULL) { + return -1; + } + + if (aecpc->initFlag != initCheck) { + aecpc->lastError = AEC_UNINITIALIZED_ERROR; + return -1; + } + + if (config.skewMode != kAecFalse && config.skewMode != kAecTrue) { + aecpc->lastError = AEC_BAD_PARAMETER_ERROR; + return -1; + } + aecpc->skewMode = config.skewMode; + + if (config.nlpMode != kAecNlpConservative && config.nlpMode != + kAecNlpModerate && config.nlpMode != kAecNlpAggressive) { + aecpc->lastError = AEC_BAD_PARAMETER_ERROR; + return -1; + } + aecpc->nlpMode = config.nlpMode; + aecpc->aec->targetSupp = targetSupp[aecpc->nlpMode]; + aecpc->aec->minOverDrive = minOverDrive[aecpc->nlpMode]; + + if (config.metricsMode != kAecFalse && config.metricsMode != kAecTrue) { + aecpc->lastError = AEC_BAD_PARAMETER_ERROR; + return -1; + } + aecpc->aec->metricsMode = config.metricsMode; + if (aecpc->aec->metricsMode == kAecTrue) { + WebRtcAec_InitMetrics(aecpc->aec); + } + + if (config.delay_logging != kAecFalse && config.delay_logging != kAecTrue) { + aecpc->lastError = AEC_BAD_PARAMETER_ERROR; + return -1; + } + aecpc->aec->delay_logging_enabled = config.delay_logging; + if (aecpc->aec->delay_logging_enabled == kAecTrue) { + memset(aecpc->aec->delay_histogram, 0, sizeof(aecpc->aec->delay_histogram)); + } + + return 0; +} + +WebRtc_Word32 WebRtcAec_get_config(void *aecInst, AecConfig *config) +{ + aecpc_t *aecpc = aecInst; + + if (aecpc == NULL) { + return -1; + } + + if (config == NULL) { + aecpc->lastError = AEC_NULL_POINTER_ERROR; + return -1; + } + + if (aecpc->initFlag != initCheck) { + aecpc->lastError = AEC_UNINITIALIZED_ERROR; + return -1; + } + + config->nlpMode = aecpc->nlpMode; + config->skewMode = aecpc->skewMode; + config->metricsMode = aecpc->aec->metricsMode; + config->delay_logging = aecpc->aec->delay_logging_enabled; + + return 0; +} + +WebRtc_Word32 WebRtcAec_get_echo_status(void *aecInst, WebRtc_Word16 *status) +{ + aecpc_t *aecpc = aecInst; + + if (aecpc == NULL) { + return -1; + } + + if (status == NULL) { + aecpc->lastError = AEC_NULL_POINTER_ERROR; + return -1; + } + + if (aecpc->initFlag != initCheck) { + aecpc->lastError = AEC_UNINITIALIZED_ERROR; + return -1; + } + + *status = aecpc->aec->echoState; + + return 0; +} + +WebRtc_Word32 WebRtcAec_GetMetrics(void *aecInst, AecMetrics *metrics) +{ + const float upweight = 0.7f; + float dtmp; + short stmp; + aecpc_t *aecpc = aecInst; + + if (aecpc == NULL) { + return -1; + } + + if (metrics == NULL) { + aecpc->lastError = AEC_NULL_POINTER_ERROR; + return -1; + } + + if (aecpc->initFlag != initCheck) { + aecpc->lastError = AEC_UNINITIALIZED_ERROR; + return -1; + } + + // ERL + metrics->erl.instant = (short) aecpc->aec->erl.instant; + + if ((aecpc->aec->erl.himean > offsetLevel) && (aecpc->aec->erl.average > offsetLevel)) { + // Use a mix between regular average and upper part average + dtmp = upweight * aecpc->aec->erl.himean + (1 - upweight) * aecpc->aec->erl.average; + metrics->erl.average = (short) dtmp; + } + else { + metrics->erl.average = offsetLevel; + } + + metrics->erl.max = (short) aecpc->aec->erl.max; + + if (aecpc->aec->erl.min < (offsetLevel * (-1))) { + metrics->erl.min = (short) aecpc->aec->erl.min; + } + else { + metrics->erl.min = offsetLevel; + } + + // ERLE + metrics->erle.instant = (short) aecpc->aec->erle.instant; + + if ((aecpc->aec->erle.himean > offsetLevel) && (aecpc->aec->erle.average > offsetLevel)) { + // Use a mix between regular average and upper part average + dtmp = upweight * aecpc->aec->erle.himean + (1 - upweight) * aecpc->aec->erle.average; + metrics->erle.average = (short) dtmp; + } + else { + metrics->erle.average = offsetLevel; + } + + metrics->erle.max = (short) aecpc->aec->erle.max; + + if (aecpc->aec->erle.min < (offsetLevel * (-1))) { + metrics->erle.min = (short) aecpc->aec->erle.min; + } else { + metrics->erle.min = offsetLevel; + } + + // RERL + if ((metrics->erl.average > offsetLevel) && (metrics->erle.average > offsetLevel)) { + stmp = metrics->erl.average + metrics->erle.average; + } + else { + stmp = offsetLevel; + } + metrics->rerl.average = stmp; + + // No other statistics needed, but returned for completeness + metrics->rerl.instant = stmp; + metrics->rerl.max = stmp; + metrics->rerl.min = stmp; + + // A_NLP + metrics->aNlp.instant = (short) aecpc->aec->aNlp.instant; + + if ((aecpc->aec->aNlp.himean > offsetLevel) && (aecpc->aec->aNlp.average > offsetLevel)) { + // Use a mix between regular average and upper part average + dtmp = upweight * aecpc->aec->aNlp.himean + (1 - upweight) * aecpc->aec->aNlp.average; + metrics->aNlp.average = (short) dtmp; + } + else { + metrics->aNlp.average = offsetLevel; + } + + metrics->aNlp.max = (short) aecpc->aec->aNlp.max; + + if (aecpc->aec->aNlp.min < (offsetLevel * (-1))) { + metrics->aNlp.min = (short) aecpc->aec->aNlp.min; + } + else { + metrics->aNlp.min = offsetLevel; + } + + return 0; +} + +int WebRtcAec_GetDelayMetrics(void* handle, int* median, int* std) { + aecpc_t* self = handle; + int i = 0; + int delay_values = 0; + int num_delay_values = 0; + int my_median = 0; + const int kMsPerBlock = (PART_LEN * 1000) / self->splitSampFreq; + float l1_norm = 0; + + if (self == NULL) { + return -1; + } + if (median == NULL) { + self->lastError = AEC_NULL_POINTER_ERROR; + return -1; + } + if (std == NULL) { + self->lastError = AEC_NULL_POINTER_ERROR; + return -1; + } + if (self->initFlag != initCheck) { + self->lastError = AEC_UNINITIALIZED_ERROR; + return -1; + } + if (self->aec->delay_logging_enabled == 0) { + // Logging disabled + self->lastError = AEC_UNSUPPORTED_FUNCTION_ERROR; + return -1; + } + + // Get number of delay values since last update + for (i = 0; i < kHistorySizeBlocks; i++) { + num_delay_values += self->aec->delay_histogram[i]; + } + if (num_delay_values == 0) { + // We have no new delay value data. Even though -1 is a valid estimate, it + // will practically never be used since multiples of |kMsPerBlock| will + // always be returned. + *median = -1; + *std = -1; + return 0; + } + + delay_values = num_delay_values >> 1; // Start value for median count down + // Get median of delay values since last update + for (i = 0; i < kHistorySizeBlocks; i++) { + delay_values -= self->aec->delay_histogram[i]; + if (delay_values < 0) { + my_median = i; + break; + } + } + // Account for lookahead. + *median = (my_median - kLookaheadBlocks) * kMsPerBlock; + + // Calculate the L1 norm, with median value as central moment + for (i = 0; i < kHistorySizeBlocks; i++) { + l1_norm += (float) (fabs(i - my_median) * self->aec->delay_histogram[i]); + } + *std = (int) (l1_norm / (float) num_delay_values + 0.5f) * kMsPerBlock; + + // Reset histogram + memset(self->aec->delay_histogram, 0, sizeof(self->aec->delay_histogram)); + + return 0; +} + +WebRtc_Word32 WebRtcAec_get_error_code(void *aecInst) +{ + aecpc_t *aecpc = aecInst; + + if (aecpc == NULL) { + return -1; + } + + return aecpc->lastError; +} + +static int EstBufDelay(aecpc_t* aecpc) { + int nSampSndCard = aecpc->msInSndCardBuf * sampMsNb * aecpc->aec->mult; + int current_delay = nSampSndCard - aecpc->aec->system_delay; + int delay_difference = 0; + + // Before we proceed with the delay estimate filtering we: + // 1) Compensate for the frame that will be read. + // 2) Compensate for drift resampling. + + // 1) Compensating for the frame(s) that will be read/processed. + current_delay += FRAME_LEN * aecpc->aec->mult; + + // 2) Account for resampling frame delay. + if (aecpc->skewMode == kAecTrue && aecpc->resample == kAecTrue) { + current_delay -= kResamplingDelay; + } + + aecpc->filtDelay = WEBRTC_SPL_MAX(0, (short) (0.8 * aecpc->filtDelay + + 0.2 * current_delay)); + + delay_difference = aecpc->filtDelay - aecpc->knownDelay; + if (delay_difference > 224) { + if (aecpc->lastDelayDiff < 96) { + aecpc->timeForDelayChange = 0; + } else { + aecpc->timeForDelayChange++; + } + } else if (delay_difference < 96 && aecpc->knownDelay > 0) { + if (aecpc->lastDelayDiff > 224) { + aecpc->timeForDelayChange = 0; + } else { + aecpc->timeForDelayChange++; + } + } else { + aecpc->timeForDelayChange = 0; + } + aecpc->lastDelayDiff = delay_difference; + + if (aecpc->timeForDelayChange > 25) { + aecpc->knownDelay = WEBRTC_SPL_MAX((int) aecpc->filtDelay - 160, 0); + } + + return 0; +} diff --git a/libs/miniwebrtc/audio/processing/aec/echo_cancellation.h b/libs/miniwebrtc/audio/processing/aec/echo_cancellation.h new file mode 100644 index 00000000..a266e84f --- /dev/null +++ b/libs/miniwebrtc/audio/processing/aec/echo_cancellation.h @@ -0,0 +1,262 @@ +/* + * 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_PROCESSING_AEC_INCLUDE_ECHO_CANCELLATION_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_AEC_INCLUDE_ECHO_CANCELLATION_H_ + +#include "typedefs.h" + +// Errors +#define AEC_UNSPECIFIED_ERROR 12000 +#define AEC_UNSUPPORTED_FUNCTION_ERROR 12001 +#define AEC_UNINITIALIZED_ERROR 12002 +#define AEC_NULL_POINTER_ERROR 12003 +#define AEC_BAD_PARAMETER_ERROR 12004 + +// Warnings +#define AEC_BAD_PARAMETER_WARNING 12050 + +enum { + kAecNlpConservative = 0, + kAecNlpModerate, + kAecNlpAggressive +}; + +enum { + kAecFalse = 0, + kAecTrue +}; + +typedef struct { + WebRtc_Word16 nlpMode; // default kAecNlpModerate + WebRtc_Word16 skewMode; // default kAecFalse + WebRtc_Word16 metricsMode; // default kAecFalse + int delay_logging; // default kAecFalse + //float realSkew; +} AecConfig; + +typedef struct { + WebRtc_Word16 instant; + WebRtc_Word16 average; + WebRtc_Word16 max; + WebRtc_Word16 min; +} AecLevel; + +typedef struct { + AecLevel rerl; + AecLevel erl; + AecLevel erle; + AecLevel aNlp; +} AecMetrics; + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Allocates the memory needed by the AEC. The memory needs to be initialized + * separately using the WebRtcAec_Init() function. + * + * Inputs Description + * ------------------------------------------------------------------- + * void **aecInst Pointer to the AEC instance to be created + * and initialized + * + * Outputs Description + * ------------------------------------------------------------------- + * WebRtc_Word32 return 0: OK + * -1: error + */ +WebRtc_Word32 WebRtcAec_Create(void **aecInst); + +/* + * This function releases the memory allocated by WebRtcAec_Create(). + * + * Inputs Description + * ------------------------------------------------------------------- + * void *aecInst Pointer to the AEC instance + * + * Outputs Description + * ------------------------------------------------------------------- + * WebRtc_Word32 return 0: OK + * -1: error + */ +WebRtc_Word32 WebRtcAec_Free(void *aecInst); + +/* + * Initializes an AEC instance. + * + * Inputs Description + * ------------------------------------------------------------------- + * void *aecInst Pointer to the AEC instance + * WebRtc_Word32 sampFreq Sampling frequency of data + * WebRtc_Word32 scSampFreq Soundcard sampling frequency + * + * Outputs Description + * ------------------------------------------------------------------- + * WebRtc_Word32 return 0: OK + * -1: error + */ +WebRtc_Word32 WebRtcAec_Init(void *aecInst, + WebRtc_Word32 sampFreq, + WebRtc_Word32 scSampFreq); + +/* + * Inserts an 80 or 160 sample block of data into the farend buffer. + * + * Inputs Description + * ------------------------------------------------------------------- + * void *aecInst Pointer to the AEC instance + * WebRtc_Word16 *farend In buffer containing one frame of + * farend signal for L band + * WebRtc_Word16 nrOfSamples Number of samples in farend buffer + * + * Outputs Description + * ------------------------------------------------------------------- + * WebRtc_Word32 return 0: OK + * -1: error + */ +WebRtc_Word32 WebRtcAec_BufferFarend(void *aecInst, + const WebRtc_Word16 *farend, + WebRtc_Word16 nrOfSamples); + +/* + * Runs the echo canceller on an 80 or 160 sample blocks of data. + * + * Inputs Description + * ------------------------------------------------------------------- + * void *aecInst Pointer to the AEC instance + * WebRtc_Word16 *nearend In buffer containing one frame of + * nearend+echo signal for L band + * WebRtc_Word16 *nearendH In buffer containing one frame of + * nearend+echo signal for H band + * WebRtc_Word16 nrOfSamples Number of samples in nearend buffer + * WebRtc_Word16 msInSndCardBuf Delay estimate for sound card and + * system buffers + * WebRtc_Word16 skew Difference between number of samples played + * and recorded at the soundcard (for clock skew + * compensation) + * + * Outputs Description + * ------------------------------------------------------------------- + * WebRtc_Word16 *out Out buffer, one frame of processed nearend + * for L band + * WebRtc_Word16 *outH Out buffer, one frame of processed nearend + * for H band + * WebRtc_Word32 return 0: OK + * -1: error + */ +WebRtc_Word32 WebRtcAec_Process(void *aecInst, + const WebRtc_Word16 *nearend, + const WebRtc_Word16 *nearendH, + WebRtc_Word16 *out, + WebRtc_Word16 *outH, + WebRtc_Word16 nrOfSamples, + WebRtc_Word16 msInSndCardBuf, + WebRtc_Word32 skew); + +/* + * This function enables the user to set certain parameters on-the-fly. + * + * Inputs Description + * ------------------------------------------------------------------- + * void *aecInst Pointer to the AEC instance + * AecConfig config Config instance that contains all + * properties to be set + * + * Outputs Description + * ------------------------------------------------------------------- + * WebRtc_Word32 return 0: OK + * -1: error + */ +WebRtc_Word32 WebRtcAec_set_config(void *aecInst, AecConfig config); + +/* + * Gets the on-the-fly paramters. + * + * Inputs Description + * ------------------------------------------------------------------- + * void *aecInst Pointer to the AEC instance + * + * Outputs Description + * ------------------------------------------------------------------- + * AecConfig *config Pointer to the config instance that + * all properties will be written to + * WebRtc_Word32 return 0: OK + * -1: error + */ +WebRtc_Word32 WebRtcAec_get_config(void *aecInst, AecConfig *config); + +/* + * Gets the current echo status of the nearend signal. + * + * Inputs Description + * ------------------------------------------------------------------- + * void *aecInst Pointer to the AEC instance + * + * Outputs Description + * ------------------------------------------------------------------- + * WebRtc_Word16 *status 0: Almost certainly nearend single-talk + * 1: Might not be neared single-talk + * WebRtc_Word32 return 0: OK + * -1: error + */ +WebRtc_Word32 WebRtcAec_get_echo_status(void *aecInst, WebRtc_Word16 *status); + +/* + * Gets the current echo metrics for the session. + * + * Inputs Description + * ------------------------------------------------------------------- + * void *aecInst Pointer to the AEC instance + * + * Outputs Description + * ------------------------------------------------------------------- + * AecMetrics *metrics Struct which will be filled out with the + * current echo metrics. + * WebRtc_Word32 return 0: OK + * -1: error + */ +WebRtc_Word32 WebRtcAec_GetMetrics(void *aecInst, AecMetrics *metrics); + +/* + * Gets the current delay metrics for the session. + * + * Inputs Description + * ------------------------------------------------------------------- + * void* handle Pointer to the AEC instance + * + * Outputs Description + * ------------------------------------------------------------------- + * int* median Delay median value. + * int* std Delay standard deviation. + * + * int return 0: OK + * -1: error + */ +int WebRtcAec_GetDelayMetrics(void* handle, int* median, int* std); + +/* + * Gets the last error code. + * + * Inputs Description + * ------------------------------------------------------------------- + * void *aecInst Pointer to the AEC instance + * + * Outputs Description + * ------------------------------------------------------------------- + * WebRtc_Word32 return 11000-11100: error code + */ +WebRtc_Word32 WebRtcAec_get_error_code(void *aecInst); + +#ifdef __cplusplus +} +#endif +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AEC_INCLUDE_ECHO_CANCELLATION_H_ diff --git a/libs/miniwebrtc/audio/processing/aecm/aecm_core.c b/libs/miniwebrtc/audio/processing/aecm/aecm_core.c new file mode 100644 index 00000000..4a51d56a --- /dev/null +++ b/libs/miniwebrtc/audio/processing/aecm/aecm_core.c @@ -0,0 +1,2131 @@ +/* + * 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 "aecm_core.h" + +#include +#include + +#include "cpu_features_wrapper.h" +#include "delay_estimator_wrapper.h" +#include "echo_control_mobile.h" +#include "ring_buffer.h" +#include "typedefs.h" + +#ifdef ARM_WINM_LOG +#include +#include +#endif + +#ifdef AEC_DEBUG +FILE *dfile; +FILE *testfile; +#endif + +#ifdef _MSC_VER // visual c++ +#define ALIGN8_BEG __declspec(align(8)) +#define ALIGN8_END +#else // gcc or icc +#define ALIGN8_BEG +#define ALIGN8_END __attribute__((aligned(8))) +#endif + +#ifdef AECM_SHORT + +// Square root of Hanning window in Q14 +const WebRtc_Word16 WebRtcAecm_kSqrtHanning[] = +{ + 0, 804, 1606, 2404, 3196, 3981, 4756, 5520, + 6270, 7005, 7723, 8423, 9102, 9760, 10394, 11003, + 11585, 12140, 12665, 13160, 13623, 14053, 14449, 14811, + 15137, 15426, 15679, 15893, 16069, 16207, 16305, 16364, + 16384 +}; + +#else + +// Square root of Hanning window in Q14 +const ALIGN8_BEG WebRtc_Word16 WebRtcAecm_kSqrtHanning[] ALIGN8_END = +{ + 0, 399, 798, 1196, 1594, 1990, 2386, 2780, 3172, + 3562, 3951, 4337, 4720, 5101, 5478, 5853, 6224, 6591, 6954, 7313, 7668, 8019, 8364, + 8705, 9040, 9370, 9695, 10013, 10326, 10633, 10933, 11227, 11514, 11795, 12068, 12335, + 12594, 12845, 13089, 13325, 13553, 13773, 13985, 14189, 14384, 14571, 14749, 14918, + 15079, 15231, 15373, 15506, 15631, 15746, 15851, 15947, 16034, 16111, 16179, 16237, + 16286, 16325, 16354, 16373, 16384 +}; + +#endif + +//Q15 alpha = 0.99439986968132 const Factor for magnitude approximation +static const WebRtc_UWord16 kAlpha1 = 32584; +//Q15 beta = 0.12967166976970 const Factor for magnitude approximation +static const WebRtc_UWord16 kBeta1 = 4249; +//Q15 alpha = 0.94234827210087 const Factor for magnitude approximation +static const WebRtc_UWord16 kAlpha2 = 30879; +//Q15 beta = 0.33787806009150 const Factor for magnitude approximation +static const WebRtc_UWord16 kBeta2 = 11072; +//Q15 alpha = 0.82247698684306 const Factor for magnitude approximation +static const WebRtc_UWord16 kAlpha3 = 26951; +//Q15 beta = 0.57762063060713 const Factor for magnitude approximation +static const WebRtc_UWord16 kBeta3 = 18927; + +// Initialization table for echo channel in 8 kHz +static const WebRtc_Word16 kChannelStored8kHz[PART_LEN1] = { + 2040, 1815, 1590, 1498, 1405, 1395, 1385, 1418, + 1451, 1506, 1562, 1644, 1726, 1804, 1882, 1918, + 1953, 1982, 2010, 2025, 2040, 2034, 2027, 2021, + 2014, 1997, 1980, 1925, 1869, 1800, 1732, 1683, + 1635, 1604, 1572, 1545, 1517, 1481, 1444, 1405, + 1367, 1331, 1294, 1270, 1245, 1239, 1233, 1247, + 1260, 1282, 1303, 1338, 1373, 1407, 1441, 1470, + 1499, 1524, 1549, 1565, 1582, 1601, 1621, 1649, + 1676 +}; + +// Initialization table for echo channel in 16 kHz +static const WebRtc_Word16 kChannelStored16kHz[PART_LEN1] = { + 2040, 1590, 1405, 1385, 1451, 1562, 1726, 1882, + 1953, 2010, 2040, 2027, 2014, 1980, 1869, 1732, + 1635, 1572, 1517, 1444, 1367, 1294, 1245, 1233, + 1260, 1303, 1373, 1441, 1499, 1549, 1582, 1621, + 1676, 1741, 1802, 1861, 1921, 1983, 2040, 2102, + 2170, 2265, 2375, 2515, 2651, 2781, 2922, 3075, + 3253, 3471, 3738, 3976, 4151, 4258, 4308, 4288, + 4270, 4253, 4237, 4179, 4086, 3947, 3757, 3484, + 3153 +}; + +static const WebRtc_Word16 kCosTable[] = { + 8192, 8190, 8187, 8180, 8172, 8160, 8147, 8130, 8112, + 8091, 8067, 8041, 8012, 7982, 7948, 7912, 7874, 7834, + 7791, 7745, 7697, 7647, 7595, 7540, 7483, 7424, 7362, + 7299, 7233, 7164, 7094, 7021, 6947, 6870, 6791, 6710, + 6627, 6542, 6455, 6366, 6275, 6182, 6087, 5991, 5892, + 5792, 5690, 5586, 5481, 5374, 5265, 5155, 5043, 4930, + 4815, 4698, 4580, 4461, 4341, 4219, 4096, 3971, 3845, + 3719, 3591, 3462, 3331, 3200, 3068, 2935, 2801, 2667, + 2531, 2395, 2258, 2120, 1981, 1842, 1703, 1563, 1422, + 1281, 1140, 998, 856, 713, 571, 428, 285, 142, + 0, -142, -285, -428, -571, -713, -856, -998, -1140, + -1281, -1422, -1563, -1703, -1842, -1981, -2120, -2258, -2395, + -2531, -2667, -2801, -2935, -3068, -3200, -3331, -3462, -3591, + -3719, -3845, -3971, -4095, -4219, -4341, -4461, -4580, -4698, + -4815, -4930, -5043, -5155, -5265, -5374, -5481, -5586, -5690, + -5792, -5892, -5991, -6087, -6182, -6275, -6366, -6455, -6542, + -6627, -6710, -6791, -6870, -6947, -7021, -7094, -7164, -7233, + -7299, -7362, -7424, -7483, -7540, -7595, -7647, -7697, -7745, + -7791, -7834, -7874, -7912, -7948, -7982, -8012, -8041, -8067, + -8091, -8112, -8130, -8147, -8160, -8172, -8180, -8187, -8190, + -8191, -8190, -8187, -8180, -8172, -8160, -8147, -8130, -8112, + -8091, -8067, -8041, -8012, -7982, -7948, -7912, -7874, -7834, + -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424, -7362, + -7299, -7233, -7164, -7094, -7021, -6947, -6870, -6791, -6710, + -6627, -6542, -6455, -6366, -6275, -6182, -6087, -5991, -5892, + -5792, -5690, -5586, -5481, -5374, -5265, -5155, -5043, -4930, + -4815, -4698, -4580, -4461, -4341, -4219, -4096, -3971, -3845, + -3719, -3591, -3462, -3331, -3200, -3068, -2935, -2801, -2667, + -2531, -2395, -2258, -2120, -1981, -1842, -1703, -1563, -1422, + -1281, -1140, -998, -856, -713, -571, -428, -285, -142, + 0, 142, 285, 428, 571, 713, 856, 998, 1140, + 1281, 1422, 1563, 1703, 1842, 1981, 2120, 2258, 2395, + 2531, 2667, 2801, 2935, 3068, 3200, 3331, 3462, 3591, + 3719, 3845, 3971, 4095, 4219, 4341, 4461, 4580, 4698, + 4815, 4930, 5043, 5155, 5265, 5374, 5481, 5586, 5690, + 5792, 5892, 5991, 6087, 6182, 6275, 6366, 6455, 6542, + 6627, 6710, 6791, 6870, 6947, 7021, 7094, 7164, 7233, + 7299, 7362, 7424, 7483, 7540, 7595, 7647, 7697, 7745, + 7791, 7834, 7874, 7912, 7948, 7982, 8012, 8041, 8067, + 8091, 8112, 8130, 8147, 8160, 8172, 8180, 8187, 8190 +}; + +static const WebRtc_Word16 kSinTable[] = { + 0, 142, 285, 428, 571, 713, 856, 998, + 1140, 1281, 1422, 1563, 1703, 1842, 1981, 2120, + 2258, 2395, 2531, 2667, 2801, 2935, 3068, 3200, + 3331, 3462, 3591, 3719, 3845, 3971, 4095, 4219, + 4341, 4461, 4580, 4698, 4815, 4930, 5043, 5155, + 5265, 5374, 5481, 5586, 5690, 5792, 5892, 5991, + 6087, 6182, 6275, 6366, 6455, 6542, 6627, 6710, + 6791, 6870, 6947, 7021, 7094, 7164, 7233, 7299, + 7362, 7424, 7483, 7540, 7595, 7647, 7697, 7745, + 7791, 7834, 7874, 7912, 7948, 7982, 8012, 8041, + 8067, 8091, 8112, 8130, 8147, 8160, 8172, 8180, + 8187, 8190, 8191, 8190, 8187, 8180, 8172, 8160, + 8147, 8130, 8112, 8091, 8067, 8041, 8012, 7982, + 7948, 7912, 7874, 7834, 7791, 7745, 7697, 7647, + 7595, 7540, 7483, 7424, 7362, 7299, 7233, 7164, + 7094, 7021, 6947, 6870, 6791, 6710, 6627, 6542, + 6455, 6366, 6275, 6182, 6087, 5991, 5892, 5792, + 5690, 5586, 5481, 5374, 5265, 5155, 5043, 4930, + 4815, 4698, 4580, 4461, 4341, 4219, 4096, 3971, + 3845, 3719, 3591, 3462, 3331, 3200, 3068, 2935, + 2801, 2667, 2531, 2395, 2258, 2120, 1981, 1842, + 1703, 1563, 1422, 1281, 1140, 998, 856, 713, + 571, 428, 285, 142, 0, -142, -285, -428, + -571, -713, -856, -998, -1140, -1281, -1422, -1563, + -1703, -1842, -1981, -2120, -2258, -2395, -2531, -2667, + -2801, -2935, -3068, -3200, -3331, -3462, -3591, -3719, + -3845, -3971, -4095, -4219, -4341, -4461, -4580, -4698, + -4815, -4930, -5043, -5155, -5265, -5374, -5481, -5586, + -5690, -5792, -5892, -5991, -6087, -6182, -6275, -6366, + -6455, -6542, -6627, -6710, -6791, -6870, -6947, -7021, + -7094, -7164, -7233, -7299, -7362, -7424, -7483, -7540, + -7595, -7647, -7697, -7745, -7791, -7834, -7874, -7912, + -7948, -7982, -8012, -8041, -8067, -8091, -8112, -8130, + -8147, -8160, -8172, -8180, -8187, -8190, -8191, -8190, + -8187, -8180, -8172, -8160, -8147, -8130, -8112, -8091, + -8067, -8041, -8012, -7982, -7948, -7912, -7874, -7834, + -7791, -7745, -7697, -7647, -7595, -7540, -7483, -7424, + -7362, -7299, -7233, -7164, -7094, -7021, -6947, -6870, + -6791, -6710, -6627, -6542, -6455, -6366, -6275, -6182, + -6087, -5991, -5892, -5792, -5690, -5586, -5481, -5374, + -5265, -5155, -5043, -4930, -4815, -4698, -4580, -4461, + -4341, -4219, -4096, -3971, -3845, -3719, -3591, -3462, + -3331, -3200, -3068, -2935, -2801, -2667, -2531, -2395, + -2258, -2120, -1981, -1842, -1703, -1563, -1422, -1281, + -1140, -998, -856, -713, -571, -428, -285, -142 +}; + +static const WebRtc_Word16 kNoiseEstQDomain = 15; +static const WebRtc_Word16 kNoiseEstIncCount = 5; + +static void ComfortNoise(AecmCore_t* aecm, + const WebRtc_UWord16* dfa, + complex16_t* out, + const WebRtc_Word16* lambda); + +static WebRtc_Word16 CalcSuppressionGain(AecmCore_t * const aecm); + +// Moves the pointer to the next entry and inserts |far_spectrum| and +// corresponding Q-domain in its buffer. +// +// Inputs: +// - self : Pointer to the delay estimation instance +// - far_spectrum : Pointer to the far end spectrum +// - far_q : Q-domain of far end spectrum +// +static void UpdateFarHistory(AecmCore_t* self, + uint16_t* far_spectrum, + int far_q) { + // Get new buffer position + self->far_history_pos++; + if (self->far_history_pos >= MAX_DELAY) { + self->far_history_pos = 0; + } + // Update Q-domain buffer + self->far_q_domains[self->far_history_pos] = far_q; + // Update far end spectrum buffer + memcpy(&(self->far_history[self->far_history_pos * PART_LEN1]), + far_spectrum, + sizeof(uint16_t) * PART_LEN1); +} + +// Returns a pointer to the far end spectrum aligned to current near end +// spectrum. The function WebRtc_DelayEstimatorProcessFix(...) should have been +// called before AlignedFarend(...). Otherwise, you get the pointer to the +// previous frame. The memory is only valid until the next call of +// WebRtc_DelayEstimatorProcessFix(...). +// +// Inputs: +// - self : Pointer to the AECM instance. +// - delay : Current delay estimate. +// +// Output: +// - far_q : The Q-domain of the aligned far end spectrum +// +// Return value: +// - far_spectrum : Pointer to the aligned far end spectrum +// NULL - Error +// +static const uint16_t* AlignedFarend(AecmCore_t* self, int* far_q, int delay) { + int buffer_position = 0; + assert(self != NULL); + buffer_position = self->far_history_pos - delay; + + // Check buffer position + if (buffer_position < 0) { + buffer_position += MAX_DELAY; + } + // Get Q-domain + *far_q = self->far_q_domains[buffer_position]; + // Return far end spectrum + return &(self->far_history[buffer_position * PART_LEN1]); +} + +#ifdef ARM_WINM_LOG +HANDLE logFile = NULL; +#endif + +// Declare function pointers. +CalcLinearEnergies WebRtcAecm_CalcLinearEnergies; +StoreAdaptiveChannel WebRtcAecm_StoreAdaptiveChannel; +ResetAdaptiveChannel WebRtcAecm_ResetAdaptiveChannel; +WindowAndFFT WebRtcAecm_WindowAndFFT; +InverseFFTAndWindow WebRtcAecm_InverseFFTAndWindow; + +int WebRtcAecm_CreateCore(AecmCore_t **aecmInst) +{ + AecmCore_t *aecm = malloc(sizeof(AecmCore_t)); + *aecmInst = aecm; + if (aecm == NULL) + { + return -1; + } + + if (WebRtc_CreateBuffer(&aecm->farFrameBuf, FRAME_LEN + PART_LEN, + sizeof(int16_t)) == -1) + { + WebRtcAecm_FreeCore(aecm); + aecm = NULL; + return -1; + } + + if (WebRtc_CreateBuffer(&aecm->nearNoisyFrameBuf, FRAME_LEN + PART_LEN, + sizeof(int16_t)) == -1) + { + WebRtcAecm_FreeCore(aecm); + aecm = NULL; + return -1; + } + + if (WebRtc_CreateBuffer(&aecm->nearCleanFrameBuf, FRAME_LEN + PART_LEN, + sizeof(int16_t)) == -1) + { + WebRtcAecm_FreeCore(aecm); + aecm = NULL; + return -1; + } + + if (WebRtc_CreateBuffer(&aecm->outFrameBuf, FRAME_LEN + PART_LEN, + sizeof(int16_t)) == -1) + { + WebRtcAecm_FreeCore(aecm); + aecm = NULL; + return -1; + } + + if (WebRtc_CreateDelayEstimator(&aecm->delay_estimator, + PART_LEN1, + MAX_DELAY, + 0) == -1) { + WebRtcAecm_FreeCore(aecm); + aecm = NULL; + return -1; + } + + // Init some aecm pointers. 16 and 32 byte alignment is only necessary + // for Neon code currently. + aecm->xBuf = (WebRtc_Word16*) (((uintptr_t)aecm->xBuf_buf + 31) & ~ 31); + aecm->dBufClean = (WebRtc_Word16*) (((uintptr_t)aecm->dBufClean_buf + 31) & ~ 31); + aecm->dBufNoisy = (WebRtc_Word16*) (((uintptr_t)aecm->dBufNoisy_buf + 31) & ~ 31); + aecm->outBuf = (WebRtc_Word16*) (((uintptr_t)aecm->outBuf_buf + 15) & ~ 15); + aecm->channelStored = (WebRtc_Word16*) (((uintptr_t) + aecm->channelStored_buf + 15) & ~ 15); + aecm->channelAdapt16 = (WebRtc_Word16*) (((uintptr_t) + aecm->channelAdapt16_buf + 15) & ~ 15); + aecm->channelAdapt32 = (WebRtc_Word32*) (((uintptr_t) + aecm->channelAdapt32_buf + 31) & ~ 31); + + return 0; +} + +void WebRtcAecm_InitEchoPathCore(AecmCore_t* aecm, const WebRtc_Word16* echo_path) +{ + int i = 0; + + // Reset the stored channel + memcpy(aecm->channelStored, echo_path, sizeof(WebRtc_Word16) * PART_LEN1); + // Reset the adapted channels + memcpy(aecm->channelAdapt16, echo_path, sizeof(WebRtc_Word16) * PART_LEN1); + for (i = 0; i < PART_LEN1; i++) + { + aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32( + (WebRtc_Word32)(aecm->channelAdapt16[i]), 16); + } + + // Reset channel storing variables + aecm->mseAdaptOld = 1000; + aecm->mseStoredOld = 1000; + aecm->mseThreshold = WEBRTC_SPL_WORD32_MAX; + aecm->mseChannelCount = 0; +} + +static void WindowAndFFTC(WebRtc_Word16* fft, + const WebRtc_Word16* time_signal, + complex16_t* freq_signal, + int time_signal_scaling) +{ + int i, j; + + memset(fft, 0, sizeof(WebRtc_Word16) * PART_LEN4); + // FFT of signal + for (i = 0, j = 0; i < PART_LEN; i++, j += 2) + { + // Window time domain signal and insert into real part of + // transformation array |fft| + fft[j] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT( + (time_signal[i] << time_signal_scaling), + WebRtcAecm_kSqrtHanning[i], + 14); + fft[PART_LEN2 + j] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT( + (time_signal[i + PART_LEN] << time_signal_scaling), + WebRtcAecm_kSqrtHanning[PART_LEN - i], + 14); + // Inserting zeros in imaginary parts not necessary since we + // initialized the array with all zeros + } + + WebRtcSpl_ComplexBitReverse(fft, PART_LEN_SHIFT); + WebRtcSpl_ComplexFFT(fft, PART_LEN_SHIFT, 1); + + // Take only the first PART_LEN2 samples + for (i = 0, j = 0; j < PART_LEN2; i += 1, j += 2) + { + freq_signal[i].real = fft[j]; + + // The imaginary part has to switch sign + freq_signal[i].imag = - fft[j+1]; + } +} + +static void InverseFFTAndWindowC(AecmCore_t* aecm, + WebRtc_Word16* fft, + complex16_t* efw, + WebRtc_Word16* output, + const WebRtc_Word16* nearendClean) +{ + int i, j, outCFFT; + WebRtc_Word32 tmp32no1; + + // Synthesis + for (i = 1; i < PART_LEN; i++) + { + j = WEBRTC_SPL_LSHIFT_W32(i, 1); + fft[j] = efw[i].real; + + // mirrored data, even + fft[PART_LEN4 - j] = efw[i].real; + fft[j + 1] = -efw[i].imag; + + //mirrored data, odd + fft[PART_LEN4 - (j - 1)] = efw[i].imag; + } + fft[0] = efw[0].real; + fft[1] = -efw[0].imag; + + fft[PART_LEN2] = efw[PART_LEN].real; + fft[PART_LEN2 + 1] = -efw[PART_LEN].imag; + + // inverse FFT, result should be scaled with outCFFT + WebRtcSpl_ComplexBitReverse(fft, PART_LEN_SHIFT); + outCFFT = WebRtcSpl_ComplexIFFT(fft, PART_LEN_SHIFT, 1); + + //take only the real values and scale with outCFFT + for (i = 0; i < PART_LEN2; i++) + { + j = WEBRTC_SPL_LSHIFT_W32(i, 1); + fft[i] = fft[j]; + } + + for (i = 0; i < PART_LEN; i++) + { + fft[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( + fft[i], + WebRtcAecm_kSqrtHanning[i], + 14); + tmp32no1 = WEBRTC_SPL_SHIFT_W32((WebRtc_Word32)fft[i], + outCFFT - aecm->dfaCleanQDomain); + fft[i] = (WebRtc_Word16)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, + tmp32no1 + aecm->outBuf[i], + WEBRTC_SPL_WORD16_MIN); + output[i] = fft[i]; + + tmp32no1 = WEBRTC_SPL_MUL_16_16_RSFT( + fft[PART_LEN + i], + WebRtcAecm_kSqrtHanning[PART_LEN - i], + 14); + tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1, + outCFFT - aecm->dfaCleanQDomain); + aecm->outBuf[i] = (WebRtc_Word16)WEBRTC_SPL_SAT( + WEBRTC_SPL_WORD16_MAX, + tmp32no1, + WEBRTC_SPL_WORD16_MIN); + } + +#ifdef ARM_WINM_LOG_ + // measure tick end + QueryPerformanceCounter((LARGE_INTEGER*)&end); + diff__ = ((end - start) * 1000) / (freq/1000); + milliseconds = (unsigned int)(diff__ & 0xffffffff); + WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL); +#endif + + // Copy the current block to the old position (aecm->outBuf is shifted elsewhere) + memcpy(aecm->xBuf, aecm->xBuf + PART_LEN, sizeof(WebRtc_Word16) * PART_LEN); + memcpy(aecm->dBufNoisy, aecm->dBufNoisy + PART_LEN, sizeof(WebRtc_Word16) * PART_LEN); + if (nearendClean != NULL) + { + memcpy(aecm->dBufClean, aecm->dBufClean + PART_LEN, sizeof(WebRtc_Word16) * PART_LEN); + } +} + +static void CalcLinearEnergiesC(AecmCore_t* aecm, + const WebRtc_UWord16* far_spectrum, + WebRtc_Word32* echo_est, + WebRtc_UWord32* far_energy, + WebRtc_UWord32* echo_energy_adapt, + WebRtc_UWord32* echo_energy_stored) +{ + int i; + + // Get energy for the delayed far end signal and estimated + // echo using both stored and adapted channels. + for (i = 0; i < PART_LEN1; i++) + { + echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], + far_spectrum[i]); + (*far_energy) += (WebRtc_UWord32)(far_spectrum[i]); + (*echo_energy_adapt) += WEBRTC_SPL_UMUL_16_16(aecm->channelAdapt16[i], + far_spectrum[i]); + (*echo_energy_stored) += (WebRtc_UWord32)echo_est[i]; + } +} + +static void StoreAdaptiveChannelC(AecmCore_t* aecm, + const WebRtc_UWord16* far_spectrum, + WebRtc_Word32* echo_est) +{ + int i; + + // During startup we store the channel every block. + memcpy(aecm->channelStored, aecm->channelAdapt16, sizeof(WebRtc_Word16) * PART_LEN1); + // Recalculate echo estimate + for (i = 0; i < PART_LEN; i += 4) + { + echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], + far_spectrum[i]); + echo_est[i + 1] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 1], + far_spectrum[i + 1]); + echo_est[i + 2] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 2], + far_spectrum[i + 2]); + echo_est[i + 3] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i + 3], + far_spectrum[i + 3]); + } + echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], + far_spectrum[i]); +} + +static void ResetAdaptiveChannelC(AecmCore_t* aecm) +{ + int i; + + // The stored channel has a significantly lower MSE than the adaptive one for + // two consecutive calculations. Reset the adaptive channel. + memcpy(aecm->channelAdapt16, aecm->channelStored, + sizeof(WebRtc_Word16) * PART_LEN1); + // Restore the W32 channel + for (i = 0; i < PART_LEN; i += 4) + { + aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32( + (WebRtc_Word32)aecm->channelStored[i], 16); + aecm->channelAdapt32[i + 1] = WEBRTC_SPL_LSHIFT_W32( + (WebRtc_Word32)aecm->channelStored[i + 1], 16); + aecm->channelAdapt32[i + 2] = WEBRTC_SPL_LSHIFT_W32( + (WebRtc_Word32)aecm->channelStored[i + 2], 16); + aecm->channelAdapt32[i + 3] = WEBRTC_SPL_LSHIFT_W32( + (WebRtc_Word32)aecm->channelStored[i + 3], 16); + } + aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)aecm->channelStored[i], 16); +} + +// WebRtcAecm_InitCore(...) +// +// This function initializes the AECM instant created with WebRtcAecm_CreateCore(...) +// Input: +// - aecm : Pointer to the Echo Suppression instance +// - samplingFreq : Sampling Frequency +// +// Output: +// - aecm : Initialized instance +// +// Return value : 0 - Ok +// -1 - Error +// +int WebRtcAecm_InitCore(AecmCore_t * const aecm, int samplingFreq) +{ + int i = 0; + WebRtc_Word32 tmp32 = PART_LEN1 * PART_LEN1; + WebRtc_Word16 tmp16 = PART_LEN1; + + if (samplingFreq != 8000 && samplingFreq != 16000) + { + samplingFreq = 8000; + return -1; + } + // sanity check of sampling frequency + aecm->mult = (WebRtc_Word16)samplingFreq / 8000; + + aecm->farBufWritePos = 0; + aecm->farBufReadPos = 0; + aecm->knownDelay = 0; + aecm->lastKnownDelay = 0; + + WebRtc_InitBuffer(aecm->farFrameBuf); + WebRtc_InitBuffer(aecm->nearNoisyFrameBuf); + WebRtc_InitBuffer(aecm->nearCleanFrameBuf); + WebRtc_InitBuffer(aecm->outFrameBuf); + + memset(aecm->xBuf_buf, 0, sizeof(aecm->xBuf_buf)); + memset(aecm->dBufClean_buf, 0, sizeof(aecm->dBufClean_buf)); + memset(aecm->dBufNoisy_buf, 0, sizeof(aecm->dBufNoisy_buf)); + memset(aecm->outBuf_buf, 0, sizeof(aecm->outBuf_buf)); + + aecm->seed = 666; + aecm->totCount = 0; + + if (WebRtc_InitDelayEstimator(aecm->delay_estimator) != 0) { + return -1; + } + // Set far end histories to zero + memset(aecm->far_history, 0, sizeof(uint16_t) * PART_LEN1 * MAX_DELAY); + memset(aecm->far_q_domains, 0, sizeof(int) * MAX_DELAY); + aecm->far_history_pos = MAX_DELAY; + + aecm->nlpFlag = 1; + aecm->fixedDelay = -1; + + aecm->dfaCleanQDomain = 0; + aecm->dfaCleanQDomainOld = 0; + aecm->dfaNoisyQDomain = 0; + aecm->dfaNoisyQDomainOld = 0; + + memset(aecm->nearLogEnergy, 0, sizeof(aecm->nearLogEnergy)); + aecm->farLogEnergy = 0; + memset(aecm->echoAdaptLogEnergy, 0, sizeof(aecm->echoAdaptLogEnergy)); + memset(aecm->echoStoredLogEnergy, 0, sizeof(aecm->echoStoredLogEnergy)); + + // Initialize the echo channels with a stored shape. + if (samplingFreq == 8000) + { + WebRtcAecm_InitEchoPathCore(aecm, kChannelStored8kHz); + } + else + { + WebRtcAecm_InitEchoPathCore(aecm, kChannelStored16kHz); + } + + memset(aecm->echoFilt, 0, sizeof(aecm->echoFilt)); + memset(aecm->nearFilt, 0, sizeof(aecm->nearFilt)); + aecm->noiseEstCtr = 0; + + aecm->cngMode = AecmTrue; + + memset(aecm->noiseEstTooLowCtr, 0, sizeof(aecm->noiseEstTooLowCtr)); + memset(aecm->noiseEstTooHighCtr, 0, sizeof(aecm->noiseEstTooHighCtr)); + // Shape the initial noise level to an approximate pink noise. + for (i = 0; i < (PART_LEN1 >> 1) - 1; i++) + { + aecm->noiseEst[i] = (tmp32 << 8); + tmp16--; + tmp32 -= (WebRtc_Word32)((tmp16 << 1) + 1); + } + for (; i < PART_LEN1; i++) + { + aecm->noiseEst[i] = (tmp32 << 8); + } + + aecm->farEnergyMin = WEBRTC_SPL_WORD16_MAX; + aecm->farEnergyMax = WEBRTC_SPL_WORD16_MIN; + aecm->farEnergyMaxMin = 0; + aecm->farEnergyVAD = FAR_ENERGY_MIN; // This prevents false speech detection at the + // beginning. + aecm->farEnergyMSE = 0; + aecm->currentVADValue = 0; + aecm->vadUpdateCount = 0; + aecm->firstVAD = 1; + + aecm->startupState = 0; + aecm->supGain = SUPGAIN_DEFAULT; + aecm->supGainOld = SUPGAIN_DEFAULT; + + aecm->supGainErrParamA = SUPGAIN_ERROR_PARAM_A; + aecm->supGainErrParamD = SUPGAIN_ERROR_PARAM_D; + aecm->supGainErrParamDiffAB = SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B; + aecm->supGainErrParamDiffBD = SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D; + + assert(PART_LEN % 16 == 0); + + // Initialize function pointers. + WebRtcAecm_WindowAndFFT = WindowAndFFTC; + WebRtcAecm_InverseFFTAndWindow = InverseFFTAndWindowC; + WebRtcAecm_CalcLinearEnergies = CalcLinearEnergiesC; + WebRtcAecm_StoreAdaptiveChannel = StoreAdaptiveChannelC; + WebRtcAecm_ResetAdaptiveChannel = ResetAdaptiveChannelC; + +#ifdef WEBRTC_DETECT_ARM_NEON + uint64_t features = WebRtc_GetCPUFeaturesARM(); + if ((features & kCPUFeatureNEON) != 0) + { + WebRtcAecm_InitNeon(); + } +#elif defined(WEBRTC_ARCH_ARM_NEON) + WebRtcAecm_InitNeon(); +#endif + + return 0; +} + +// TODO(bjornv): This function is currently not used. Add support for these +// parameters from a higher level +int WebRtcAecm_Control(AecmCore_t *aecm, int delay, int nlpFlag) +{ + aecm->nlpFlag = nlpFlag; + aecm->fixedDelay = delay; + + return 0; +} + +int WebRtcAecm_FreeCore(AecmCore_t *aecm) +{ + if (aecm == NULL) + { + return -1; + } + + WebRtc_FreeBuffer(aecm->farFrameBuf); + WebRtc_FreeBuffer(aecm->nearNoisyFrameBuf); + WebRtc_FreeBuffer(aecm->nearCleanFrameBuf); + WebRtc_FreeBuffer(aecm->outFrameBuf); + + WebRtc_FreeDelayEstimator(aecm->delay_estimator); + free(aecm); + + return 0; +} + +int WebRtcAecm_ProcessFrame(AecmCore_t * aecm, + const WebRtc_Word16 * farend, + const WebRtc_Word16 * nearendNoisy, + const WebRtc_Word16 * nearendClean, + WebRtc_Word16 * out) +{ + WebRtc_Word16 outBlock_buf[PART_LEN + 8]; // Align buffer to 8-byte boundary. + WebRtc_Word16* outBlock = (WebRtc_Word16*) (((uintptr_t) outBlock_buf + 15) & ~ 15); + + WebRtc_Word16 farFrame[FRAME_LEN]; + const int16_t* out_ptr = NULL; + int size = 0; + + // Buffer the current frame. + // Fetch an older one corresponding to the delay. + WebRtcAecm_BufferFarFrame(aecm, farend, FRAME_LEN); + WebRtcAecm_FetchFarFrame(aecm, farFrame, FRAME_LEN, aecm->knownDelay); + + // Buffer the synchronized far and near frames, + // to pass the smaller blocks individually. + WebRtc_WriteBuffer(aecm->farFrameBuf, farFrame, FRAME_LEN); + WebRtc_WriteBuffer(aecm->nearNoisyFrameBuf, nearendNoisy, FRAME_LEN); + if (nearendClean != NULL) + { + WebRtc_WriteBuffer(aecm->nearCleanFrameBuf, nearendClean, FRAME_LEN); + } + + // Process as many blocks as possible. + while (WebRtc_available_read(aecm->farFrameBuf) >= PART_LEN) + { + int16_t far_block[PART_LEN]; + const int16_t* far_block_ptr = NULL; + int16_t near_noisy_block[PART_LEN]; + const int16_t* near_noisy_block_ptr = NULL; + + WebRtc_ReadBuffer(aecm->farFrameBuf, (void**) &far_block_ptr, far_block, + PART_LEN); + WebRtc_ReadBuffer(aecm->nearNoisyFrameBuf, + (void**) &near_noisy_block_ptr, + near_noisy_block, + PART_LEN); + if (nearendClean != NULL) + { + int16_t near_clean_block[PART_LEN]; + const int16_t* near_clean_block_ptr = NULL; + + WebRtc_ReadBuffer(aecm->nearCleanFrameBuf, + (void**) &near_clean_block_ptr, + near_clean_block, + PART_LEN); + if (WebRtcAecm_ProcessBlock(aecm, + far_block_ptr, + near_noisy_block_ptr, + near_clean_block_ptr, + outBlock) == -1) + { + return -1; + } + } else + { + if (WebRtcAecm_ProcessBlock(aecm, + far_block_ptr, + near_noisy_block_ptr, + NULL, + outBlock) == -1) + { + return -1; + } + } + + WebRtc_WriteBuffer(aecm->outFrameBuf, outBlock, PART_LEN); + } + + // Stuff the out buffer if we have less than a frame to output. + // This should only happen for the first frame. + size = (int) WebRtc_available_read(aecm->outFrameBuf); + if (size < FRAME_LEN) + { + WebRtc_MoveReadPtr(aecm->outFrameBuf, size - FRAME_LEN); + } + + // Obtain an output frame. + WebRtc_ReadBuffer(aecm->outFrameBuf, (void**) &out_ptr, out, FRAME_LEN); + if (out_ptr != out) { + // ReadBuffer() hasn't copied to |out| in this case. + memcpy(out, out_ptr, FRAME_LEN * sizeof(int16_t)); + } + + return 0; +} + +// WebRtcAecm_AsymFilt(...) +// +// Performs asymmetric filtering. +// +// Inputs: +// - filtOld : Previous filtered value. +// - inVal : New input value. +// - stepSizePos : Step size when we have a positive contribution. +// - stepSizeNeg : Step size when we have a negative contribution. +// +// Output: +// +// Return: - Filtered value. +// +WebRtc_Word16 WebRtcAecm_AsymFilt(const WebRtc_Word16 filtOld, const WebRtc_Word16 inVal, + const WebRtc_Word16 stepSizePos, + const WebRtc_Word16 stepSizeNeg) +{ + WebRtc_Word16 retVal; + + if ((filtOld == WEBRTC_SPL_WORD16_MAX) | (filtOld == WEBRTC_SPL_WORD16_MIN)) + { + return inVal; + } + retVal = filtOld; + if (filtOld > inVal) + { + retVal -= WEBRTC_SPL_RSHIFT_W16(filtOld - inVal, stepSizeNeg); + } else + { + retVal += WEBRTC_SPL_RSHIFT_W16(inVal - filtOld, stepSizePos); + } + + return retVal; +} + +// WebRtcAecm_CalcEnergies(...) +// +// This function calculates the log of energies for nearend, farend and estimated +// echoes. There is also an update of energy decision levels, i.e. internal VAD. +// +// +// @param aecm [i/o] Handle of the AECM instance. +// @param far_spectrum [in] Pointer to farend spectrum. +// @param far_q [in] Q-domain of farend spectrum. +// @param nearEner [in] Near end energy for current block in +// Q(aecm->dfaQDomain). +// @param echoEst [out] Estimated echo in Q(xfa_q+RESOLUTION_CHANNEL16). +// +void WebRtcAecm_CalcEnergies(AecmCore_t * aecm, + const WebRtc_UWord16* far_spectrum, + const WebRtc_Word16 far_q, + const WebRtc_UWord32 nearEner, + WebRtc_Word32 * echoEst) +{ + // Local variables + WebRtc_UWord32 tmpAdapt = 0; + WebRtc_UWord32 tmpStored = 0; + WebRtc_UWord32 tmpFar = 0; + + int i; + + WebRtc_Word16 zeros, frac; + WebRtc_Word16 tmp16; + WebRtc_Word16 increase_max_shifts = 4; + WebRtc_Word16 decrease_max_shifts = 11; + WebRtc_Word16 increase_min_shifts = 11; + WebRtc_Word16 decrease_min_shifts = 3; + WebRtc_Word16 kLogLowValue = WEBRTC_SPL_LSHIFT_W16(PART_LEN_SHIFT, 7); + + // Get log of near end energy and store in buffer + + // Shift buffer + memmove(aecm->nearLogEnergy + 1, aecm->nearLogEnergy, + sizeof(WebRtc_Word16) * (MAX_BUF_LEN - 1)); + + // Logarithm of integrated magnitude spectrum (nearEner) + tmp16 = kLogLowValue; + if (nearEner) + { + zeros = WebRtcSpl_NormU32(nearEner); + frac = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32( + (WEBRTC_SPL_LSHIFT_U32(nearEner, zeros) & 0x7FFFFFFF), + 23); + // log2 in Q8 + tmp16 += WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac; + tmp16 -= WEBRTC_SPL_LSHIFT_W16(aecm->dfaNoisyQDomain, 8); + } + aecm->nearLogEnergy[0] = tmp16; + // END: Get log of near end energy + + WebRtcAecm_CalcLinearEnergies(aecm, far_spectrum, echoEst, &tmpFar, &tmpAdapt, &tmpStored); + + // Shift buffers + memmove(aecm->echoAdaptLogEnergy + 1, aecm->echoAdaptLogEnergy, + sizeof(WebRtc_Word16) * (MAX_BUF_LEN - 1)); + memmove(aecm->echoStoredLogEnergy + 1, aecm->echoStoredLogEnergy, + sizeof(WebRtc_Word16) * (MAX_BUF_LEN - 1)); + + // Logarithm of delayed far end energy + tmp16 = kLogLowValue; + if (tmpFar) + { + zeros = WebRtcSpl_NormU32(tmpFar); + frac = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32((WEBRTC_SPL_LSHIFT_U32(tmpFar, zeros) + & 0x7FFFFFFF), 23); + // log2 in Q8 + tmp16 += WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac; + tmp16 -= WEBRTC_SPL_LSHIFT_W16(far_q, 8); + } + aecm->farLogEnergy = tmp16; + + // Logarithm of estimated echo energy through adapted channel + tmp16 = kLogLowValue; + if (tmpAdapt) + { + zeros = WebRtcSpl_NormU32(tmpAdapt); + frac = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32((WEBRTC_SPL_LSHIFT_U32(tmpAdapt, zeros) + & 0x7FFFFFFF), 23); + //log2 in Q8 + tmp16 += WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac; + tmp16 -= WEBRTC_SPL_LSHIFT_W16(RESOLUTION_CHANNEL16 + far_q, 8); + } + aecm->echoAdaptLogEnergy[0] = tmp16; + + // Logarithm of estimated echo energy through stored channel + tmp16 = kLogLowValue; + if (tmpStored) + { + zeros = WebRtcSpl_NormU32(tmpStored); + frac = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32((WEBRTC_SPL_LSHIFT_U32(tmpStored, zeros) + & 0x7FFFFFFF), 23); + //log2 in Q8 + tmp16 += WEBRTC_SPL_LSHIFT_W16((31 - zeros), 8) + frac; + tmp16 -= WEBRTC_SPL_LSHIFT_W16(RESOLUTION_CHANNEL16 + far_q, 8); + } + aecm->echoStoredLogEnergy[0] = tmp16; + + // Update farend energy levels (min, max, vad, mse) + if (aecm->farLogEnergy > FAR_ENERGY_MIN) + { + if (aecm->startupState == 0) + { + increase_max_shifts = 2; + decrease_min_shifts = 2; + increase_min_shifts = 8; + } + + aecm->farEnergyMin = WebRtcAecm_AsymFilt(aecm->farEnergyMin, aecm->farLogEnergy, + increase_min_shifts, decrease_min_shifts); + aecm->farEnergyMax = WebRtcAecm_AsymFilt(aecm->farEnergyMax, aecm->farLogEnergy, + increase_max_shifts, decrease_max_shifts); + aecm->farEnergyMaxMin = (aecm->farEnergyMax - aecm->farEnergyMin); + + // Dynamic VAD region size + tmp16 = 2560 - aecm->farEnergyMin; + if (tmp16 > 0) + { + tmp16 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16, FAR_ENERGY_VAD_REGION, 9); + } else + { + tmp16 = 0; + } + tmp16 += FAR_ENERGY_VAD_REGION; + + if ((aecm->startupState == 0) | (aecm->vadUpdateCount > 1024)) + { + // In startup phase or VAD update halted + aecm->farEnergyVAD = aecm->farEnergyMin + tmp16; + } else + { + if (aecm->farEnergyVAD > aecm->farLogEnergy) + { + aecm->farEnergyVAD += WEBRTC_SPL_RSHIFT_W16(aecm->farLogEnergy + + tmp16 - + aecm->farEnergyVAD, + 6); + aecm->vadUpdateCount = 0; + } else + { + aecm->vadUpdateCount++; + } + } + // Put MSE threshold higher than VAD + aecm->farEnergyMSE = aecm->farEnergyVAD + (1 << 8); + } + + // Update VAD variables + if (aecm->farLogEnergy > aecm->farEnergyVAD) + { + if ((aecm->startupState == 0) | (aecm->farEnergyMaxMin > FAR_ENERGY_DIFF)) + { + // We are in startup or have significant dynamics in input speech level + aecm->currentVADValue = 1; + } + } else + { + aecm->currentVADValue = 0; + } + if ((aecm->currentVADValue) && (aecm->firstVAD)) + { + aecm->firstVAD = 0; + if (aecm->echoAdaptLogEnergy[0] > aecm->nearLogEnergy[0]) + { + // The estimated echo has higher energy than the near end signal. + // This means that the initialization was too aggressive. Scale + // down by a factor 8 + for (i = 0; i < PART_LEN1; i++) + { + aecm->channelAdapt16[i] >>= 3; + } + // Compensate the adapted echo energy level accordingly. + aecm->echoAdaptLogEnergy[0] -= (3 << 8); + aecm->firstVAD = 1; + } + } +} + +// WebRtcAecm_CalcStepSize(...) +// +// This function calculates the step size used in channel estimation +// +// +// @param aecm [in] Handle of the AECM instance. +// @param mu [out] (Return value) Stepsize in log2(), i.e. number of shifts. +// +// +WebRtc_Word16 WebRtcAecm_CalcStepSize(AecmCore_t * const aecm) +{ + + WebRtc_Word32 tmp32; + WebRtc_Word16 tmp16; + WebRtc_Word16 mu = MU_MAX; + + // Here we calculate the step size mu used in the + // following NLMS based Channel estimation algorithm + if (!aecm->currentVADValue) + { + // Far end energy level too low, no channel update + mu = 0; + } else if (aecm->startupState > 0) + { + if (aecm->farEnergyMin >= aecm->farEnergyMax) + { + mu = MU_MIN; + } else + { + tmp16 = (aecm->farLogEnergy - aecm->farEnergyMin); + tmp32 = WEBRTC_SPL_MUL_16_16(tmp16, MU_DIFF); + tmp32 = WebRtcSpl_DivW32W16(tmp32, aecm->farEnergyMaxMin); + mu = MU_MIN - 1 - (WebRtc_Word16)(tmp32); + // The -1 is an alternative to rounding. This way we get a larger + // stepsize, so we in some sense compensate for truncation in NLMS + } + if (mu < MU_MAX) + { + mu = MU_MAX; // Equivalent with maximum step size of 2^-MU_MAX + } + } + + return mu; +} + +// WebRtcAecm_UpdateChannel(...) +// +// This function performs channel estimation. NLMS and decision on channel storage. +// +// +// @param aecm [i/o] Handle of the AECM instance. +// @param far_spectrum [in] Absolute value of the farend signal in Q(far_q) +// @param far_q [in] Q-domain of the farend signal +// @param dfa [in] Absolute value of the nearend signal (Q[aecm->dfaQDomain]) +// @param mu [in] NLMS step size. +// @param echoEst [i/o] Estimated echo in Q(far_q+RESOLUTION_CHANNEL16). +// +void WebRtcAecm_UpdateChannel(AecmCore_t * aecm, + const WebRtc_UWord16* far_spectrum, + const WebRtc_Word16 far_q, + const WebRtc_UWord16 * const dfa, + const WebRtc_Word16 mu, + WebRtc_Word32 * echoEst) +{ + + WebRtc_UWord32 tmpU32no1, tmpU32no2; + WebRtc_Word32 tmp32no1, tmp32no2; + WebRtc_Word32 mseStored; + WebRtc_Word32 mseAdapt; + + int i; + + WebRtc_Word16 zerosFar, zerosNum, zerosCh, zerosDfa; + WebRtc_Word16 shiftChFar, shiftNum, shift2ResChan; + WebRtc_Word16 tmp16no1; + WebRtc_Word16 xfaQ, dfaQ; + + // This is the channel estimation algorithm. It is base on NLMS but has a variable step + // length, which was calculated above. + if (mu) + { + for (i = 0; i < PART_LEN1; i++) + { + // Determine norm of channel and farend to make sure we don't get overflow in + // multiplication + zerosCh = WebRtcSpl_NormU32(aecm->channelAdapt32[i]); + zerosFar = WebRtcSpl_NormU32((WebRtc_UWord32)far_spectrum[i]); + if (zerosCh + zerosFar > 31) + { + // Multiplication is safe + tmpU32no1 = WEBRTC_SPL_UMUL_32_16(aecm->channelAdapt32[i], + far_spectrum[i]); + shiftChFar = 0; + } else + { + // We need to shift down before multiplication + shiftChFar = 32 - zerosCh - zerosFar; + tmpU32no1 = WEBRTC_SPL_UMUL_32_16( + WEBRTC_SPL_RSHIFT_W32(aecm->channelAdapt32[i], shiftChFar), + far_spectrum[i]); + } + // Determine Q-domain of numerator + zerosNum = WebRtcSpl_NormU32(tmpU32no1); + if (dfa[i]) + { + zerosDfa = WebRtcSpl_NormU32((WebRtc_UWord32)dfa[i]); + } else + { + zerosDfa = 32; + } + tmp16no1 = zerosDfa - 2 + aecm->dfaNoisyQDomain - + RESOLUTION_CHANNEL32 - far_q + shiftChFar; + if (zerosNum > tmp16no1 + 1) + { + xfaQ = tmp16no1; + dfaQ = zerosDfa - 2; + } else + { + xfaQ = zerosNum - 2; + dfaQ = RESOLUTION_CHANNEL32 + far_q - aecm->dfaNoisyQDomain - + shiftChFar + xfaQ; + } + // Add in the same Q-domain + tmpU32no1 = WEBRTC_SPL_SHIFT_W32(tmpU32no1, xfaQ); + tmpU32no2 = WEBRTC_SPL_SHIFT_W32((WebRtc_UWord32)dfa[i], dfaQ); + tmp32no1 = (WebRtc_Word32)tmpU32no2 - (WebRtc_Word32)tmpU32no1; + zerosNum = WebRtcSpl_NormW32(tmp32no1); + if ((tmp32no1) && (far_spectrum[i] > (CHANNEL_VAD << far_q))) + { + // + // Update is needed + // + // This is what we would like to compute + // + // tmp32no1 = dfa[i] - (aecm->channelAdapt[i] * far_spectrum[i]) + // tmp32norm = (i + 1) + // aecm->channelAdapt[i] += (2^mu) * tmp32no1 + // / (tmp32norm * far_spectrum[i]) + // + + // Make sure we don't get overflow in multiplication. + if (zerosNum + zerosFar > 31) + { + if (tmp32no1 > 0) + { + tmp32no2 = (WebRtc_Word32)WEBRTC_SPL_UMUL_32_16(tmp32no1, + far_spectrum[i]); + } else + { + tmp32no2 = -(WebRtc_Word32)WEBRTC_SPL_UMUL_32_16(-tmp32no1, + far_spectrum[i]); + } + shiftNum = 0; + } else + { + shiftNum = 32 - (zerosNum + zerosFar); + if (tmp32no1 > 0) + { + tmp32no2 = (WebRtc_Word32)WEBRTC_SPL_UMUL_32_16( + WEBRTC_SPL_RSHIFT_W32(tmp32no1, shiftNum), + far_spectrum[i]); + } else + { + tmp32no2 = -(WebRtc_Word32)WEBRTC_SPL_UMUL_32_16( + WEBRTC_SPL_RSHIFT_W32(-tmp32no1, shiftNum), + far_spectrum[i]); + } + } + // Normalize with respect to frequency bin + tmp32no2 = WebRtcSpl_DivW32W16(tmp32no2, i + 1); + // Make sure we are in the right Q-domain + shift2ResChan = shiftNum + shiftChFar - xfaQ - mu - ((30 - zerosFar) << 1); + if (WebRtcSpl_NormW32(tmp32no2) < shift2ResChan) + { + tmp32no2 = WEBRTC_SPL_WORD32_MAX; + } else + { + tmp32no2 = WEBRTC_SPL_SHIFT_W32(tmp32no2, shift2ResChan); + } + aecm->channelAdapt32[i] = WEBRTC_SPL_ADD_SAT_W32(aecm->channelAdapt32[i], + tmp32no2); + if (aecm->channelAdapt32[i] < 0) + { + // We can never have negative channel gain + aecm->channelAdapt32[i] = 0; + } + aecm->channelAdapt16[i] + = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(aecm->channelAdapt32[i], 16); + } + } + } + // END: Adaptive channel update + + // Determine if we should store or restore the channel + if ((aecm->startupState == 0) & (aecm->currentVADValue)) + { + // During startup we store the channel every block, + // and we recalculate echo estimate + WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst); + } else + { + if (aecm->farLogEnergy < aecm->farEnergyMSE) + { + aecm->mseChannelCount = 0; + } else + { + aecm->mseChannelCount++; + } + // Enough data for validation. Store channel if we can. + if (aecm->mseChannelCount >= (MIN_MSE_COUNT + 10)) + { + // We have enough data. + // Calculate MSE of "Adapt" and "Stored" versions. + // It is actually not MSE, but average absolute error. + mseStored = 0; + mseAdapt = 0; + for (i = 0; i < MIN_MSE_COUNT; i++) + { + tmp32no1 = ((WebRtc_Word32)aecm->echoStoredLogEnergy[i] + - (WebRtc_Word32)aecm->nearLogEnergy[i]); + tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1); + mseStored += tmp32no2; + + tmp32no1 = ((WebRtc_Word32)aecm->echoAdaptLogEnergy[i] + - (WebRtc_Word32)aecm->nearLogEnergy[i]); + tmp32no2 = WEBRTC_SPL_ABS_W32(tmp32no1); + mseAdapt += tmp32no2; + } + if (((mseStored << MSE_RESOLUTION) < (MIN_MSE_DIFF * mseAdapt)) + & ((aecm->mseStoredOld << MSE_RESOLUTION) < (MIN_MSE_DIFF + * aecm->mseAdaptOld))) + { + // The stored channel has a significantly lower MSE than the adaptive one for + // two consecutive calculations. Reset the adaptive channel. + WebRtcAecm_ResetAdaptiveChannel(aecm); + } else if (((MIN_MSE_DIFF * mseStored) > (mseAdapt << MSE_RESOLUTION)) & (mseAdapt + < aecm->mseThreshold) & (aecm->mseAdaptOld < aecm->mseThreshold)) + { + // The adaptive channel has a significantly lower MSE than the stored one. + // The MSE for the adaptive channel has also been low for two consecutive + // calculations. Store the adaptive channel. + WebRtcAecm_StoreAdaptiveChannel(aecm, far_spectrum, echoEst); + + // Update threshold + if (aecm->mseThreshold == WEBRTC_SPL_WORD32_MAX) + { + aecm->mseThreshold = (mseAdapt + aecm->mseAdaptOld); + } else + { + aecm->mseThreshold += WEBRTC_SPL_MUL_16_16_RSFT(mseAdapt + - WEBRTC_SPL_MUL_16_16_RSFT(aecm->mseThreshold, 5, 3), 205, 8); + } + + } + + // Reset counter + aecm->mseChannelCount = 0; + + // Store the MSE values. + aecm->mseStoredOld = mseStored; + aecm->mseAdaptOld = mseAdapt; + } + } + // END: Determine if we should store or reset channel estimate. +} + +// CalcSuppressionGain(...) +// +// This function calculates the suppression gain that is used in the Wiener filter. +// +// +// @param aecm [i/n] Handle of the AECM instance. +// @param supGain [out] (Return value) Suppression gain with which to scale the noise +// level (Q14). +// +// +static WebRtc_Word16 CalcSuppressionGain(AecmCore_t * const aecm) +{ + WebRtc_Word32 tmp32no1; + + WebRtc_Word16 supGain = SUPGAIN_DEFAULT; + WebRtc_Word16 tmp16no1; + WebRtc_Word16 dE = 0; + + // Determine suppression gain used in the Wiener filter. The gain is based on a mix of far + // end energy and echo estimation error. + // Adjust for the far end signal level. A low signal level indicates no far end signal, + // hence we set the suppression gain to 0 + if (!aecm->currentVADValue) + { + supGain = 0; + } else + { + // Adjust for possible double talk. If we have large variations in estimation error we + // likely have double talk (or poor channel). + tmp16no1 = (aecm->nearLogEnergy[0] - aecm->echoStoredLogEnergy[0] - ENERGY_DEV_OFFSET); + dE = WEBRTC_SPL_ABS_W16(tmp16no1); + + if (dE < ENERGY_DEV_TOL) + { + // Likely no double talk. The better estimation, the more we can suppress signal. + // Update counters + if (dE < SUPGAIN_EPC_DT) + { + tmp32no1 = WEBRTC_SPL_MUL_16_16(aecm->supGainErrParamDiffAB, dE); + tmp32no1 += (SUPGAIN_EPC_DT >> 1); + tmp16no1 = (WebRtc_Word16)WebRtcSpl_DivW32W16(tmp32no1, SUPGAIN_EPC_DT); + supGain = aecm->supGainErrParamA - tmp16no1; + } else + { + tmp32no1 = WEBRTC_SPL_MUL_16_16(aecm->supGainErrParamDiffBD, + (ENERGY_DEV_TOL - dE)); + tmp32no1 += ((ENERGY_DEV_TOL - SUPGAIN_EPC_DT) >> 1); + tmp16no1 = (WebRtc_Word16)WebRtcSpl_DivW32W16(tmp32no1, (ENERGY_DEV_TOL + - SUPGAIN_EPC_DT)); + supGain = aecm->supGainErrParamD + tmp16no1; + } + } else + { + // Likely in double talk. Use default value + supGain = aecm->supGainErrParamD; + } + } + + if (supGain > aecm->supGainOld) + { + tmp16no1 = supGain; + } else + { + tmp16no1 = aecm->supGainOld; + } + aecm->supGainOld = supGain; + if (tmp16no1 < aecm->supGain) + { + aecm->supGain += (WebRtc_Word16)((tmp16no1 - aecm->supGain) >> 4); + } else + { + aecm->supGain += (WebRtc_Word16)((tmp16no1 - aecm->supGain) >> 4); + } + + // END: Update suppression gain + + return aecm->supGain; +} + +// Transforms a time domain signal into the frequency domain, outputting the +// complex valued signal, absolute value and sum of absolute values. +// +// time_signal [in] Pointer to time domain signal +// freq_signal_real [out] Pointer to real part of frequency domain array +// freq_signal_imag [out] Pointer to imaginary part of frequency domain +// array +// freq_signal_abs [out] Pointer to absolute value of frequency domain +// array +// freq_signal_sum_abs [out] Pointer to the sum of all absolute values in +// the frequency domain array +// return value The Q-domain of current frequency values +// +static int TimeToFrequencyDomain(const WebRtc_Word16* time_signal, + complex16_t* freq_signal, + WebRtc_UWord16* freq_signal_abs, + WebRtc_UWord32* freq_signal_sum_abs) +{ + int i = 0; + int time_signal_scaling = 0; + + WebRtc_Word32 tmp32no1; + WebRtc_Word32 tmp32no2; + + // In fft_buf, +16 for 32-byte alignment. + WebRtc_Word16 fft_buf[PART_LEN4 + 16]; + WebRtc_Word16 *fft = (WebRtc_Word16 *) (((uintptr_t) fft_buf + 31) & ~31); + + WebRtc_Word16 tmp16no1; + WebRtc_Word16 tmp16no2; +#ifdef AECM_WITH_ABS_APPROX + WebRtc_Word16 max_value = 0; + WebRtc_Word16 min_value = 0; + WebRtc_UWord16 alpha = 0; + WebRtc_UWord16 beta = 0; +#endif + +#ifdef AECM_DYNAMIC_Q + tmp16no1 = WebRtcSpl_MaxAbsValueW16(time_signal, PART_LEN2); + time_signal_scaling = WebRtcSpl_NormW16(tmp16no1); +#endif + + WebRtcAecm_WindowAndFFT(fft, time_signal, freq_signal, time_signal_scaling); + + // Extract imaginary and real part, calculate the magnitude for all frequency bins + freq_signal[0].imag = 0; + freq_signal[PART_LEN].imag = 0; + freq_signal[PART_LEN].real = fft[PART_LEN2]; + freq_signal_abs[0] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16( + freq_signal[0].real); + freq_signal_abs[PART_LEN] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16( + freq_signal[PART_LEN].real); + (*freq_signal_sum_abs) = (WebRtc_UWord32)(freq_signal_abs[0]) + + (WebRtc_UWord32)(freq_signal_abs[PART_LEN]); + + for (i = 1; i < PART_LEN; i++) + { + if (freq_signal[i].real == 0) + { + freq_signal_abs[i] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16( + freq_signal[i].imag); + } + else if (freq_signal[i].imag == 0) + { + freq_signal_abs[i] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16( + freq_signal[i].real); + } + else + { + // Approximation for magnitude of complex fft output + // magn = sqrt(real^2 + imag^2) + // magn ~= alpha * max(|imag|,|real|) + beta * min(|imag|,|real|) + // + // The parameters alpha and beta are stored in Q15 + +#ifdef AECM_WITH_ABS_APPROX + tmp16no1 = WEBRTC_SPL_ABS_W16(freq_signal[i].real); + tmp16no2 = WEBRTC_SPL_ABS_W16(freq_signal[i].imag); + + if(tmp16no1 > tmp16no2) + { + max_value = tmp16no1; + min_value = tmp16no2; + } else + { + max_value = tmp16no2; + min_value = tmp16no1; + } + + // Magnitude in Q(-6) + if ((max_value >> 2) > min_value) + { + alpha = kAlpha1; + beta = kBeta1; + } else if ((max_value >> 1) > min_value) + { + alpha = kAlpha2; + beta = kBeta2; + } else + { + alpha = kAlpha3; + beta = kBeta3; + } + tmp16no1 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(max_value, + alpha, + 15); + tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(min_value, + beta, + 15); + freq_signal_abs[i] = (WebRtc_UWord16)tmp16no1 + + (WebRtc_UWord16)tmp16no2; +#else +#ifdef WEBRTC_ARCH_ARM_V7A + __asm __volatile( + "smulbb %[tmp32no1], %[real], %[real]\n\t" + "smlabb %[tmp32no2], %[imag], %[imag], %[tmp32no1]\n\t" + :[tmp32no1]"=r"(tmp32no1), + [tmp32no2]"=r"(tmp32no2) + :[real]"r"(freq_signal[i].real), + [imag]"r"(freq_signal[i].imag) + ); +#else + tmp16no1 = WEBRTC_SPL_ABS_W16(freq_signal[i].real); + tmp16no2 = WEBRTC_SPL_ABS_W16(freq_signal[i].imag); + tmp32no1 = WEBRTC_SPL_MUL_16_16(tmp16no1, tmp16no1); + tmp32no2 = WEBRTC_SPL_MUL_16_16(tmp16no2, tmp16no2); + tmp32no2 = WEBRTC_SPL_ADD_SAT_W32(tmp32no1, tmp32no2); +#endif // WEBRTC_ARCH_ARM_V7A + tmp32no1 = WebRtcSpl_SqrtFloor(tmp32no2); + + freq_signal_abs[i] = (WebRtc_UWord16)tmp32no1; +#endif // AECM_WITH_ABS_APPROX + } + (*freq_signal_sum_abs) += (WebRtc_UWord32)freq_signal_abs[i]; + } + + return time_signal_scaling; +} + +int WebRtcAecm_ProcessBlock(AecmCore_t * aecm, + const WebRtc_Word16 * farend, + const WebRtc_Word16 * nearendNoisy, + const WebRtc_Word16 * nearendClean, + WebRtc_Word16 * output) +{ + int i; + + WebRtc_UWord32 xfaSum; + WebRtc_UWord32 dfaNoisySum; + WebRtc_UWord32 dfaCleanSum; + WebRtc_UWord32 echoEst32Gained; + WebRtc_UWord32 tmpU32; + + WebRtc_Word32 tmp32no1; + + WebRtc_UWord16 xfa[PART_LEN1]; + WebRtc_UWord16 dfaNoisy[PART_LEN1]; + WebRtc_UWord16 dfaClean[PART_LEN1]; + WebRtc_UWord16* ptrDfaClean = dfaClean; + const WebRtc_UWord16* far_spectrum_ptr = NULL; + + // 32 byte aligned buffers (with +8 or +16). + // TODO (kma): define fft with complex16_t. + WebRtc_Word16 fft_buf[PART_LEN4 + 2 + 16]; // +2 to make a loop safe. + WebRtc_Word32 echoEst32_buf[PART_LEN1 + 8]; + WebRtc_Word32 dfw_buf[PART_LEN1 + 8]; + WebRtc_Word32 efw_buf[PART_LEN1 + 8]; + + WebRtc_Word16* fft = (WebRtc_Word16*) (((uintptr_t) fft_buf + 31) & ~ 31); + WebRtc_Word32* echoEst32 = (WebRtc_Word32*) (((uintptr_t) echoEst32_buf + 31) & ~ 31); + complex16_t* dfw = (complex16_t*) (((uintptr_t) dfw_buf + 31) & ~ 31); + complex16_t* efw = (complex16_t*) (((uintptr_t) efw_buf + 31) & ~ 31); + + WebRtc_Word16 hnl[PART_LEN1]; + WebRtc_Word16 numPosCoef = 0; + WebRtc_Word16 nlpGain = ONE_Q14; + int delay; + WebRtc_Word16 tmp16no1; + WebRtc_Word16 tmp16no2; + WebRtc_Word16 mu; + WebRtc_Word16 supGain; + WebRtc_Word16 zeros32, zeros16; + WebRtc_Word16 zerosDBufNoisy, zerosDBufClean, zerosXBuf; + int far_q; + WebRtc_Word16 resolutionDiff, qDomainDiff; + + const int kMinPrefBand = 4; + const int kMaxPrefBand = 24; + WebRtc_Word32 avgHnl32 = 0; + +#ifdef ARM_WINM_LOG_ + DWORD temp; + static int flag0 = 0; + __int64 freq, start, end, diff__; + unsigned int milliseconds; +#endif + + // Determine startup state. There are three states: + // (0) the first CONV_LEN blocks + // (1) another CONV_LEN blocks + // (2) the rest + + if (aecm->startupState < 2) + { + aecm->startupState = (aecm->totCount >= CONV_LEN) + (aecm->totCount >= CONV_LEN2); + } + // END: Determine startup state + + // Buffer near and far end signals + memcpy(aecm->xBuf + PART_LEN, farend, sizeof(WebRtc_Word16) * PART_LEN); + memcpy(aecm->dBufNoisy + PART_LEN, nearendNoisy, sizeof(WebRtc_Word16) * PART_LEN); + if (nearendClean != NULL) + { + memcpy(aecm->dBufClean + PART_LEN, nearendClean, sizeof(WebRtc_Word16) * PART_LEN); + } + +#ifdef ARM_WINM_LOG_ + // measure tick start + QueryPerformanceFrequency((LARGE_INTEGER*)&freq); + QueryPerformanceCounter((LARGE_INTEGER*)&start); +#endif + + // Transform far end signal from time domain to frequency domain. + far_q = TimeToFrequencyDomain(aecm->xBuf, + dfw, + xfa, + &xfaSum); + + // Transform noisy near end signal from time domain to frequency domain. + zerosDBufNoisy = TimeToFrequencyDomain(aecm->dBufNoisy, + dfw, + dfaNoisy, + &dfaNoisySum); + aecm->dfaNoisyQDomainOld = aecm->dfaNoisyQDomain; + aecm->dfaNoisyQDomain = (WebRtc_Word16)zerosDBufNoisy; + + + if (nearendClean == NULL) + { + ptrDfaClean = dfaNoisy; + aecm->dfaCleanQDomainOld = aecm->dfaNoisyQDomainOld; + aecm->dfaCleanQDomain = aecm->dfaNoisyQDomain; + dfaCleanSum = dfaNoisySum; + } else + { + // Transform clean near end signal from time domain to frequency domain. + zerosDBufClean = TimeToFrequencyDomain(aecm->dBufClean, + dfw, + dfaClean, + &dfaCleanSum); + aecm->dfaCleanQDomainOld = aecm->dfaCleanQDomain; + aecm->dfaCleanQDomain = (WebRtc_Word16)zerosDBufClean; + } + +#ifdef ARM_WINM_LOG_ + // measure tick end + QueryPerformanceCounter((LARGE_INTEGER*)&end); + diff__ = ((end - start) * 1000) / (freq/1000); + milliseconds = (unsigned int)(diff__ & 0xffffffff); + WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL); + // measure tick start + QueryPerformanceCounter((LARGE_INTEGER*)&start); +#endif + + // Get the delay + // Save far-end history and estimate delay + UpdateFarHistory(aecm, xfa, far_q); + delay = WebRtc_DelayEstimatorProcessFix(aecm->delay_estimator, + xfa, + dfaNoisy, + PART_LEN1, + far_q, + zerosDBufNoisy); + if (delay == -1) + { + return -1; + } + else if (delay == -2) + { + // If the delay is unknown, we assume zero. + // NOTE: this will have to be adjusted if we ever add lookahead. + delay = 0; + } + + if (aecm->fixedDelay >= 0) + { + // Use fixed delay + delay = aecm->fixedDelay; + } + +#ifdef ARM_WINM_LOG_ + // measure tick end + QueryPerformanceCounter((LARGE_INTEGER*)&end); + diff__ = ((end - start) * 1000) / (freq/1000); + milliseconds = (unsigned int)(diff__ & 0xffffffff); + WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL); + // measure tick start + QueryPerformanceCounter((LARGE_INTEGER*)&start); +#endif + // Get aligned far end spectrum + far_spectrum_ptr = AlignedFarend(aecm, &far_q, delay); + zerosXBuf = (WebRtc_Word16) far_q; + if (far_spectrum_ptr == NULL) + { + return -1; + } + + // Calculate log(energy) and update energy threshold levels + WebRtcAecm_CalcEnergies(aecm, + far_spectrum_ptr, + zerosXBuf, + dfaNoisySum, + echoEst32); + + // Calculate stepsize + mu = WebRtcAecm_CalcStepSize(aecm); + + // Update counters + aecm->totCount++; + + // This is the channel estimation algorithm. + // It is base on NLMS but has a variable step length, which was calculated above. + WebRtcAecm_UpdateChannel(aecm, far_spectrum_ptr, zerosXBuf, dfaNoisy, mu, echoEst32); + supGain = CalcSuppressionGain(aecm); + +#ifdef ARM_WINM_LOG_ + // measure tick end + QueryPerformanceCounter((LARGE_INTEGER*)&end); + diff__ = ((end - start) * 1000) / (freq/1000); + milliseconds = (unsigned int)(diff__ & 0xffffffff); + WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL); + // measure tick start + QueryPerformanceCounter((LARGE_INTEGER*)&start); +#endif + + // Calculate Wiener filter hnl[] + for (i = 0; i < PART_LEN1; i++) + { + // Far end signal through channel estimate in Q8 + // How much can we shift right to preserve resolution + tmp32no1 = echoEst32[i] - aecm->echoFilt[i]; + aecm->echoFilt[i] += WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_32_16(tmp32no1, 50), 8); + + zeros32 = WebRtcSpl_NormW32(aecm->echoFilt[i]) + 1; + zeros16 = WebRtcSpl_NormW16(supGain) + 1; + if (zeros32 + zeros16 > 16) + { + // Multiplication is safe + // Result in Q(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN+aecm->xfaQDomainBuf[diff]) + echoEst32Gained = WEBRTC_SPL_UMUL_32_16((WebRtc_UWord32)aecm->echoFilt[i], + (WebRtc_UWord16)supGain); + resolutionDiff = 14 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN; + resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf); + } else + { + tmp16no1 = 17 - zeros32 - zeros16; + resolutionDiff = 14 + tmp16no1 - RESOLUTION_CHANNEL16 - RESOLUTION_SUPGAIN; + resolutionDiff += (aecm->dfaCleanQDomain - zerosXBuf); + if (zeros32 > tmp16no1) + { + echoEst32Gained = WEBRTC_SPL_UMUL_32_16((WebRtc_UWord32)aecm->echoFilt[i], + (WebRtc_UWord16)WEBRTC_SPL_RSHIFT_W16(supGain, + tmp16no1)); // Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN-16) + } else + { + // Result in Q-(RESOLUTION_CHANNEL+RESOLUTION_SUPGAIN-16) + echoEst32Gained = WEBRTC_SPL_UMUL_32_16( + (WebRtc_UWord32)WEBRTC_SPL_RSHIFT_W32(aecm->echoFilt[i], tmp16no1), + (WebRtc_UWord16)supGain); + } + } + + zeros16 = WebRtcSpl_NormW16(aecm->nearFilt[i]); + if ((zeros16 < (aecm->dfaCleanQDomain - aecm->dfaCleanQDomainOld)) + & (aecm->nearFilt[i])) + { + tmp16no1 = WEBRTC_SPL_SHIFT_W16(aecm->nearFilt[i], zeros16); + qDomainDiff = zeros16 - aecm->dfaCleanQDomain + aecm->dfaCleanQDomainOld; + } else + { + tmp16no1 = WEBRTC_SPL_SHIFT_W16(aecm->nearFilt[i], + aecm->dfaCleanQDomain - aecm->dfaCleanQDomainOld); + qDomainDiff = 0; + } + tmp16no2 = WEBRTC_SPL_SHIFT_W16(ptrDfaClean[i], qDomainDiff); + tmp32no1 = (WebRtc_Word32)(tmp16no2 - tmp16no1); + tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32no1, 4); + tmp16no2 += tmp16no1; + zeros16 = WebRtcSpl_NormW16(tmp16no2); + if ((tmp16no2) & (-qDomainDiff > zeros16)) + { + aecm->nearFilt[i] = WEBRTC_SPL_WORD16_MAX; + } else + { + aecm->nearFilt[i] = WEBRTC_SPL_SHIFT_W16(tmp16no2, -qDomainDiff); + } + + // Wiener filter coefficients, resulting hnl in Q14 + if (echoEst32Gained == 0) + { + hnl[i] = ONE_Q14; + } else if (aecm->nearFilt[i] == 0) + { + hnl[i] = 0; + } else + { + // Multiply the suppression gain + // Rounding + echoEst32Gained += (WebRtc_UWord32)(aecm->nearFilt[i] >> 1); + tmpU32 = WebRtcSpl_DivU32U16(echoEst32Gained, (WebRtc_UWord16)aecm->nearFilt[i]); + + // Current resolution is + // Q-(RESOLUTION_CHANNEL + RESOLUTION_SUPGAIN - max(0, 17 - zeros16 - zeros32)) + // Make sure we are in Q14 + tmp32no1 = (WebRtc_Word32)WEBRTC_SPL_SHIFT_W32(tmpU32, resolutionDiff); + if (tmp32no1 > ONE_Q14) + { + hnl[i] = 0; + } else if (tmp32no1 < 0) + { + hnl[i] = ONE_Q14; + } else + { + // 1-echoEst/dfa + hnl[i] = ONE_Q14 - (WebRtc_Word16)tmp32no1; + if (hnl[i] < 0) + { + hnl[i] = 0; + } + } + } + if (hnl[i]) + { + numPosCoef++; + } + } + // Only in wideband. Prevent the gain in upper band from being larger than + // in lower band. + if (aecm->mult == 2) + { + // TODO(bjornv): Investigate if the scaling of hnl[i] below can cause + // speech distortion in double-talk. + for (i = 0; i < PART_LEN1; i++) + { + hnl[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(hnl[i], hnl[i], 14); + } + + for (i = kMinPrefBand; i <= kMaxPrefBand; i++) + { + avgHnl32 += (WebRtc_Word32)hnl[i]; + } + assert(kMaxPrefBand - kMinPrefBand + 1 > 0); + avgHnl32 /= (kMaxPrefBand - kMinPrefBand + 1); + + for (i = kMaxPrefBand; i < PART_LEN1; i++) + { + if (hnl[i] > (WebRtc_Word16)avgHnl32) + { + hnl[i] = (WebRtc_Word16)avgHnl32; + } + } + } + +#ifdef ARM_WINM_LOG_ + // measure tick end + QueryPerformanceCounter((LARGE_INTEGER*)&end); + diff__ = ((end - start) * 1000) / (freq/1000); + milliseconds = (unsigned int)(diff__ & 0xffffffff); + WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL); + // measure tick start + QueryPerformanceCounter((LARGE_INTEGER*)&start); +#endif + + // Calculate NLP gain, result is in Q14 + if (aecm->nlpFlag) + { + for (i = 0; i < PART_LEN1; i++) + { + // Truncate values close to zero and one. + if (hnl[i] > NLP_COMP_HIGH) + { + hnl[i] = ONE_Q14; + } else if (hnl[i] < NLP_COMP_LOW) + { + hnl[i] = 0; + } + + // Remove outliers + if (numPosCoef < 3) + { + nlpGain = 0; + } else + { + nlpGain = ONE_Q14; + } + + // NLP + if ((hnl[i] == ONE_Q14) && (nlpGain == ONE_Q14)) + { + hnl[i] = ONE_Q14; + } else + { + hnl[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(hnl[i], nlpGain, 14); + } + + // multiply with Wiener coefficients + efw[i].real = (WebRtc_Word16)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real, + hnl[i], 14)); + efw[i].imag = (WebRtc_Word16)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag, + hnl[i], 14)); + } + } + else + { + // multiply with Wiener coefficients + for (i = 0; i < PART_LEN1; i++) + { + efw[i].real = (WebRtc_Word16)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].real, + hnl[i], 14)); + efw[i].imag = (WebRtc_Word16)(WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(dfw[i].imag, + hnl[i], 14)); + } + } + + if (aecm->cngMode == AecmTrue) + { + ComfortNoise(aecm, ptrDfaClean, efw, hnl); + } + +#ifdef ARM_WINM_LOG_ + // measure tick end + QueryPerformanceCounter((LARGE_INTEGER*)&end); + diff__ = ((end - start) * 1000) / (freq/1000); + milliseconds = (unsigned int)(diff__ & 0xffffffff); + WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL); + // measure tick start + QueryPerformanceCounter((LARGE_INTEGER*)&start); +#endif + + WebRtcAecm_InverseFFTAndWindow(aecm, fft, efw, output, nearendClean); + + return 0; +} + + +// Generate comfort noise and add to output signal. +// +// \param[in] aecm Handle of the AECM instance. +// \param[in] dfa Absolute value of the nearend signal (Q[aecm->dfaQDomain]). +// \param[in,out] outReal Real part of the output signal (Q[aecm->dfaQDomain]). +// \param[in,out] outImag Imaginary part of the output signal (Q[aecm->dfaQDomain]). +// \param[in] lambda Suppression gain with which to scale the noise level (Q14). +// +static void ComfortNoise(AecmCore_t* aecm, + const WebRtc_UWord16* dfa, + complex16_t* out, + const WebRtc_Word16* lambda) +{ + WebRtc_Word16 i; + WebRtc_Word16 tmp16; + WebRtc_Word32 tmp32; + + WebRtc_Word16 randW16[PART_LEN]; + WebRtc_Word16 uReal[PART_LEN1]; + WebRtc_Word16 uImag[PART_LEN1]; + WebRtc_Word32 outLShift32; + WebRtc_Word16 noiseRShift16[PART_LEN1]; + + WebRtc_Word16 shiftFromNearToNoise = kNoiseEstQDomain - aecm->dfaCleanQDomain; + WebRtc_Word16 minTrackShift; + + assert(shiftFromNearToNoise >= 0); + assert(shiftFromNearToNoise < 16); + + if (aecm->noiseEstCtr < 100) + { + // Track the minimum more quickly initially. + aecm->noiseEstCtr++; + minTrackShift = 6; + } else + { + minTrackShift = 9; + } + + // Estimate noise power. + for (i = 0; i < PART_LEN1; i++) + { + + // Shift to the noise domain. + tmp32 = (WebRtc_Word32)dfa[i]; + outLShift32 = WEBRTC_SPL_LSHIFT_W32(tmp32, shiftFromNearToNoise); + + if (outLShift32 < aecm->noiseEst[i]) + { + // Reset "too low" counter + aecm->noiseEstTooLowCtr[i] = 0; + // Track the minimum. + if (aecm->noiseEst[i] < (1 << minTrackShift)) + { + // For small values, decrease noiseEst[i] every + // |kNoiseEstIncCount| block. The regular approach below can not + // go further down due to truncation. + aecm->noiseEstTooHighCtr[i]++; + if (aecm->noiseEstTooHighCtr[i] >= kNoiseEstIncCount) + { + aecm->noiseEst[i]--; + aecm->noiseEstTooHighCtr[i] = 0; // Reset the counter + } + } + else + { + aecm->noiseEst[i] -= ((aecm->noiseEst[i] - outLShift32) >> minTrackShift); + } + } else + { + // Reset "too high" counter + aecm->noiseEstTooHighCtr[i] = 0; + // Ramp slowly upwards until we hit the minimum again. + if ((aecm->noiseEst[i] >> 19) > 0) + { + // Avoid overflow. + // Multiplication with 2049 will cause wrap around. Scale + // down first and then multiply + aecm->noiseEst[i] >>= 11; + aecm->noiseEst[i] *= 2049; + } + else if ((aecm->noiseEst[i] >> 11) > 0) + { + // Large enough for relative increase + aecm->noiseEst[i] *= 2049; + aecm->noiseEst[i] >>= 11; + } + else + { + // Make incremental increases based on size every + // |kNoiseEstIncCount| block + aecm->noiseEstTooLowCtr[i]++; + if (aecm->noiseEstTooLowCtr[i] >= kNoiseEstIncCount) + { + aecm->noiseEst[i] += (aecm->noiseEst[i] >> 9) + 1; + aecm->noiseEstTooLowCtr[i] = 0; // Reset counter + } + } + } + } + + for (i = 0; i < PART_LEN1; i++) + { + tmp32 = WEBRTC_SPL_RSHIFT_W32(aecm->noiseEst[i], shiftFromNearToNoise); + if (tmp32 > 32767) + { + tmp32 = 32767; + aecm->noiseEst[i] = WEBRTC_SPL_LSHIFT_W32(tmp32, shiftFromNearToNoise); + } + noiseRShift16[i] = (WebRtc_Word16)tmp32; + + tmp16 = ONE_Q14 - lambda[i]; + noiseRShift16[i] + = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16, noiseRShift16[i], 14); + } + + // Generate a uniform random array on [0 2^15-1]. + WebRtcSpl_RandUArray(randW16, PART_LEN, &aecm->seed); + + // Generate noise according to estimated energy. + uReal[0] = 0; // Reject LF noise. + uImag[0] = 0; + for (i = 1; i < PART_LEN1; i++) + { + // Get a random index for the cos and sin tables over [0 359]. + tmp16 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(359, randW16[i - 1], 15); + + // Tables are in Q13. + uReal[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(noiseRShift16[i], + kCosTable[tmp16], 13); + uImag[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(-noiseRShift16[i], + kSinTable[tmp16], 13); + } + uImag[PART_LEN] = 0; + +#if (!defined ARM_WINM) && (!defined ARM9E_GCC) && (!defined ANDROID_AECOPT) + for (i = 0; i < PART_LEN1; i++) + { + out[i].real = WEBRTC_SPL_ADD_SAT_W16(out[i].real, uReal[i]); + out[i].imag = WEBRTC_SPL_ADD_SAT_W16(out[i].imag, uImag[i]); + } +#else + for (i = 0; i < PART_LEN1 -1; ) + { + out[i].real = WEBRTC_SPL_ADD_SAT_W16(out[i].real, uReal[i]); + out[i].imag = WEBRTC_SPL_ADD_SAT_W16(out[i].imag, uImag[i]); + i++; + + out[i].real = WEBRTC_SPL_ADD_SAT_W16(out[i].real, uReal[i]); + out[i].imag = WEBRTC_SPL_ADD_SAT_W16(out[i].imag, uImag[i]); + i++; + } + out[i].real = WEBRTC_SPL_ADD_SAT_W16(out[i].real, uReal[i]); + out[i].imag = WEBRTC_SPL_ADD_SAT_W16(out[i].imag, uImag[i]); +#endif +} + +void WebRtcAecm_BufferFarFrame(AecmCore_t* const aecm, + const WebRtc_Word16* const farend, + const int farLen) +{ + int writeLen = farLen, writePos = 0; + + // Check if the write position must be wrapped + while (aecm->farBufWritePos + writeLen > FAR_BUF_LEN) + { + // Write to remaining buffer space before wrapping + writeLen = FAR_BUF_LEN - aecm->farBufWritePos; + memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos, + sizeof(WebRtc_Word16) * writeLen); + aecm->farBufWritePos = 0; + writePos = writeLen; + writeLen = farLen - writeLen; + } + + memcpy(aecm->farBuf + aecm->farBufWritePos, farend + writePos, + sizeof(WebRtc_Word16) * writeLen); + aecm->farBufWritePos += writeLen; +} + +void WebRtcAecm_FetchFarFrame(AecmCore_t * const aecm, WebRtc_Word16 * const farend, + const int farLen, const int knownDelay) +{ + int readLen = farLen; + int readPos = 0; + int delayChange = knownDelay - aecm->lastKnownDelay; + + aecm->farBufReadPos -= delayChange; + + // Check if delay forces a read position wrap + while (aecm->farBufReadPos < 0) + { + aecm->farBufReadPos += FAR_BUF_LEN; + } + while (aecm->farBufReadPos > FAR_BUF_LEN - 1) + { + aecm->farBufReadPos -= FAR_BUF_LEN; + } + + aecm->lastKnownDelay = knownDelay; + + // Check if read position must be wrapped + while (aecm->farBufReadPos + readLen > FAR_BUF_LEN) + { + + // Read from remaining buffer space before wrapping + readLen = FAR_BUF_LEN - aecm->farBufReadPos; + memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos, + sizeof(WebRtc_Word16) * readLen); + aecm->farBufReadPos = 0; + readPos = readLen; + readLen = farLen - readLen; + } + memcpy(farend + readPos, aecm->farBuf + aecm->farBufReadPos, + sizeof(WebRtc_Word16) * readLen); + aecm->farBufReadPos += readLen; +} + + diff --git a/libs/miniwebrtc/audio/processing/aecm/aecm_core.h b/libs/miniwebrtc/audio/processing/aecm/aecm_core.h new file mode 100644 index 00000000..0ec62ec2 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/aecm/aecm_core.h @@ -0,0 +1,375 @@ +/* + * 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. + */ + +// Performs echo control (suppression) with fft routines in fixed-point + +#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AECM_MAIN_SOURCE_AECM_CORE_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_AECM_MAIN_SOURCE_AECM_CORE_H_ + +#define AECM_DYNAMIC_Q // turn on/off dynamic Q-domain +//#define AECM_WITH_ABS_APPROX +//#define AECM_SHORT // for 32 sample partition length (otherwise 64) + +#include "typedefs.h" +#include "signal_processing_library.h" + +// Algorithm parameters + +#define FRAME_LEN 80 // Total frame length, 10 ms +#ifdef AECM_SHORT + +#define PART_LEN 32 // Length of partition +#define PART_LEN_SHIFT 6 // Length of (PART_LEN * 2) in base 2 + +#else + +#define PART_LEN 64 // Length of partition +#define PART_LEN_SHIFT 7 // Length of (PART_LEN * 2) in base 2 + +#endif + +#define PART_LEN1 (PART_LEN + 1) // Unique fft coefficients +#define PART_LEN2 (PART_LEN << 1) // Length of partition * 2 +#define PART_LEN4 (PART_LEN << 2) // Length of partition * 4 +#define FAR_BUF_LEN PART_LEN4 // Length of buffers +#define MAX_DELAY 100 + +// Counter parameters +#ifdef AECM_SHORT + +#define CONV_LEN 1024 // Convergence length used at startup +#else + +#define CONV_LEN 512 // Convergence length used at startup +#endif + +#define CONV_LEN2 (CONV_LEN << 1) // Convergence length * 2 used at startup +// Energy parameters +#define MAX_BUF_LEN 64 // History length of energy signals + +#define FAR_ENERGY_MIN 1025 // Lowest Far energy level: At least 2 in energy +#define FAR_ENERGY_DIFF 929 // Allowed difference between max and min + +#define ENERGY_DEV_OFFSET 0 // The energy error offset in Q8 +#define ENERGY_DEV_TOL 400 // The energy estimation tolerance in Q8 +#define FAR_ENERGY_VAD_REGION 230 // Far VAD tolerance region +// Stepsize parameters +#define MU_MIN 10 // Min stepsize 2^-MU_MIN (far end energy dependent) +#define MU_MAX 1 // Max stepsize 2^-MU_MAX (far end energy dependent) +#define MU_DIFF 9 // MU_MIN - MU_MAX +// Channel parameters +#define MIN_MSE_COUNT 20 // Min number of consecutive blocks with enough far end + // energy to compare channel estimates +#define MIN_MSE_DIFF 29 // The ratio between adapted and stored channel to + // accept a new storage (0.8 in Q-MSE_RESOLUTION) +#define MSE_RESOLUTION 5 // MSE parameter resolution +#define RESOLUTION_CHANNEL16 12 // W16 Channel in Q-RESOLUTION_CHANNEL16 +#define RESOLUTION_CHANNEL32 28 // W32 Channel in Q-RESOLUTION_CHANNEL +#define CHANNEL_VAD 16 // Minimum energy in frequency band to update channel +// Suppression gain parameters: SUPGAIN_ parameters in Q-(RESOLUTION_SUPGAIN) +#define RESOLUTION_SUPGAIN 8 // Channel in Q-(RESOLUTION_SUPGAIN) +#define SUPGAIN_DEFAULT (1 << RESOLUTION_SUPGAIN) // Default suppression gain +#define SUPGAIN_ERROR_PARAM_A 3072 // Estimation error parameter (Maximum gain) (8 in Q8) +#define SUPGAIN_ERROR_PARAM_B 1536 // Estimation error parameter (Gain before going down) +#define SUPGAIN_ERROR_PARAM_D SUPGAIN_DEFAULT // Estimation error parameter + // (Should be the same as Default) (1 in Q8) +#define SUPGAIN_EPC_DT 200 // = SUPGAIN_ERROR_PARAM_C * ENERGY_DEV_TOL +// Defines for "check delay estimation" +#define CORR_WIDTH 31 // Number of samples to correlate over. +#define CORR_MAX 16 // Maximum correlation offset +#define CORR_MAX_BUF 63 +#define CORR_DEV 4 +#define CORR_MAX_LEVEL 20 +#define CORR_MAX_LOW 4 +#define CORR_BUF_LEN (CORR_MAX << 1) + 1 +// Note that CORR_WIDTH + 2*CORR_MAX <= MAX_BUF_LEN + +#define ONE_Q14 (1 << 14) + +// NLP defines +#define NLP_COMP_LOW 3277 // 0.2 in Q14 +#define NLP_COMP_HIGH ONE_Q14 // 1 in Q14 + +extern const WebRtc_Word16 WebRtcAecm_kSqrtHanning[]; + +typedef struct { + WebRtc_Word16 real; + WebRtc_Word16 imag; +} complex16_t; + +typedef struct +{ + int farBufWritePos; + int farBufReadPos; + int knownDelay; + int lastKnownDelay; + int firstVAD; // Parameter to control poorly initialized channels + + void *farFrameBuf; + void *nearNoisyFrameBuf; + void *nearCleanFrameBuf; + void *outFrameBuf; + + WebRtc_Word16 farBuf[FAR_BUF_LEN]; + + WebRtc_Word16 mult; + WebRtc_UWord32 seed; + + // Delay estimation variables + void* delay_estimator; + WebRtc_UWord16 currentDelay; + // Far end history variables + // TODO(bjornv): Replace |far_history| with ring_buffer. + uint16_t far_history[PART_LEN1 * MAX_DELAY]; + int far_history_pos; + int far_q_domains[MAX_DELAY]; + + WebRtc_Word16 nlpFlag; + WebRtc_Word16 fixedDelay; + + WebRtc_UWord32 totCount; + + WebRtc_Word16 dfaCleanQDomain; + WebRtc_Word16 dfaCleanQDomainOld; + WebRtc_Word16 dfaNoisyQDomain; + WebRtc_Word16 dfaNoisyQDomainOld; + + WebRtc_Word16 nearLogEnergy[MAX_BUF_LEN]; + WebRtc_Word16 farLogEnergy; + WebRtc_Word16 echoAdaptLogEnergy[MAX_BUF_LEN]; + WebRtc_Word16 echoStoredLogEnergy[MAX_BUF_LEN]; + + // The extra 16 or 32 bytes in the following buffers are for alignment based Neon code. + // It's designed this way since the current GCC compiler can't align a buffer in 16 or 32 + // byte boundaries properly. + WebRtc_Word16 channelStored_buf[PART_LEN1 + 8]; + WebRtc_Word16 channelAdapt16_buf[PART_LEN1 + 8]; + WebRtc_Word32 channelAdapt32_buf[PART_LEN1 + 8]; + WebRtc_Word16 xBuf_buf[PART_LEN2 + 16]; // farend + WebRtc_Word16 dBufClean_buf[PART_LEN2 + 16]; // nearend + WebRtc_Word16 dBufNoisy_buf[PART_LEN2 + 16]; // nearend + WebRtc_Word16 outBuf_buf[PART_LEN + 8]; + + // Pointers to the above buffers + WebRtc_Word16 *channelStored; + WebRtc_Word16 *channelAdapt16; + WebRtc_Word32 *channelAdapt32; + WebRtc_Word16 *xBuf; + WebRtc_Word16 *dBufClean; + WebRtc_Word16 *dBufNoisy; + WebRtc_Word16 *outBuf; + + WebRtc_Word32 echoFilt[PART_LEN1]; + WebRtc_Word16 nearFilt[PART_LEN1]; + WebRtc_Word32 noiseEst[PART_LEN1]; + int noiseEstTooLowCtr[PART_LEN1]; + int noiseEstTooHighCtr[PART_LEN1]; + WebRtc_Word16 noiseEstCtr; + WebRtc_Word16 cngMode; + + WebRtc_Word32 mseAdaptOld; + WebRtc_Word32 mseStoredOld; + WebRtc_Word32 mseThreshold; + + WebRtc_Word16 farEnergyMin; + WebRtc_Word16 farEnergyMax; + WebRtc_Word16 farEnergyMaxMin; + WebRtc_Word16 farEnergyVAD; + WebRtc_Word16 farEnergyMSE; + int currentVADValue; + WebRtc_Word16 vadUpdateCount; + + WebRtc_Word16 startupState; + WebRtc_Word16 mseChannelCount; + WebRtc_Word16 supGain; + WebRtc_Word16 supGainOld; + + WebRtc_Word16 supGainErrParamA; + WebRtc_Word16 supGainErrParamD; + WebRtc_Word16 supGainErrParamDiffAB; + WebRtc_Word16 supGainErrParamDiffBD; + +#ifdef AEC_DEBUG + FILE *farFile; + FILE *nearFile; + FILE *outFile; +#endif +} AecmCore_t; + +/////////////////////////////////////////////////////////////////////////////////////////////// +// WebRtcAecm_CreateCore(...) +// +// Allocates the memory needed by the AECM. The memory needs to be +// initialized separately using the WebRtcAecm_InitCore() function. +// +// Input: +// - aecm : Instance that should be created +// +// Output: +// - aecm : Created instance +// +// Return value : 0 - Ok +// -1 - Error +// +int WebRtcAecm_CreateCore(AecmCore_t **aecm); + +/////////////////////////////////////////////////////////////////////////////////////////////// +// WebRtcAecm_InitCore(...) +// +// This function initializes the AECM instant created with WebRtcAecm_CreateCore(...) +// Input: +// - aecm : Pointer to the AECM instance +// - samplingFreq : Sampling Frequency +// +// Output: +// - aecm : Initialized instance +// +// Return value : 0 - Ok +// -1 - Error +// +int WebRtcAecm_InitCore(AecmCore_t * const aecm, int samplingFreq); + +/////////////////////////////////////////////////////////////////////////////////////////////// +// WebRtcAecm_FreeCore(...) +// +// This function releases the memory allocated by WebRtcAecm_CreateCore() +// Input: +// - aecm : Pointer to the AECM instance +// +// Return value : 0 - Ok +// -1 - Error +// 11001-11016: Error +// +int WebRtcAecm_FreeCore(AecmCore_t *aecm); + +int WebRtcAecm_Control(AecmCore_t *aecm, int delay, int nlpFlag); + +/////////////////////////////////////////////////////////////////////////////////////////////// +// WebRtcAecm_InitEchoPathCore(...) +// +// This function resets the echo channel adaptation with the specified channel. +// Input: +// - aecm : Pointer to the AECM instance +// - echo_path : Pointer to the data that should initialize the echo path +// +// Output: +// - aecm : Initialized instance +// +void WebRtcAecm_InitEchoPathCore(AecmCore_t* aecm, const WebRtc_Word16* echo_path); + +/////////////////////////////////////////////////////////////////////////////////////////////// +// WebRtcAecm_ProcessFrame(...) +// +// This function processes frames and sends blocks to WebRtcAecm_ProcessBlock(...) +// +// Inputs: +// - aecm : Pointer to the AECM instance +// - farend : In buffer containing one frame of echo signal +// - nearendNoisy : In buffer containing one frame of nearend+echo signal without NS +// - nearendClean : In buffer containing one frame of nearend+echo signal with NS +// +// Output: +// - out : Out buffer, one frame of nearend signal : +// +// +int WebRtcAecm_ProcessFrame(AecmCore_t * aecm, const WebRtc_Word16 * farend, + const WebRtc_Word16 * nearendNoisy, + const WebRtc_Word16 * nearendClean, + WebRtc_Word16 * out); + +/////////////////////////////////////////////////////////////////////////////////////////////// +// WebRtcAecm_ProcessBlock(...) +// +// This function is called for every block within one frame +// This function is called by WebRtcAecm_ProcessFrame(...) +// +// Inputs: +// - aecm : Pointer to the AECM instance +// - farend : In buffer containing one block of echo signal +// - nearendNoisy : In buffer containing one frame of nearend+echo signal without NS +// - nearendClean : In buffer containing one frame of nearend+echo signal with NS +// +// Output: +// - out : Out buffer, one block of nearend signal : +// +// +int WebRtcAecm_ProcessBlock(AecmCore_t * aecm, const WebRtc_Word16 * farend, + const WebRtc_Word16 * nearendNoisy, + const WebRtc_Word16 * noisyClean, + WebRtc_Word16 * out); + +/////////////////////////////////////////////////////////////////////////////////////////////// +// WebRtcAecm_BufferFarFrame() +// +// Inserts a frame of data into farend buffer. +// +// Inputs: +// - aecm : Pointer to the AECM instance +// - farend : In buffer containing one frame of farend signal +// - farLen : Length of frame +// +void WebRtcAecm_BufferFarFrame(AecmCore_t * const aecm, const WebRtc_Word16 * const farend, + const int farLen); + +/////////////////////////////////////////////////////////////////////////////////////////////// +// WebRtcAecm_FetchFarFrame() +// +// Read the farend buffer to account for known delay +// +// Inputs: +// - aecm : Pointer to the AECM instance +// - farend : In buffer containing one frame of farend signal +// - farLen : Length of frame +// - knownDelay : known delay +// +void WebRtcAecm_FetchFarFrame(AecmCore_t * const aecm, WebRtc_Word16 * const farend, + const int farLen, const int knownDelay); + +/////////////////////////////////////////////////////////////////////////////// +// Some function pointers, for internal functions shared by ARM NEON and +// generic C code. +// +typedef void (*CalcLinearEnergies)( + AecmCore_t* aecm, + const WebRtc_UWord16* far_spectrum, + WebRtc_Word32* echoEst, + WebRtc_UWord32* far_energy, + WebRtc_UWord32* echo_energy_adapt, + WebRtc_UWord32* echo_energy_stored); +extern CalcLinearEnergies WebRtcAecm_CalcLinearEnergies; + +typedef void (*StoreAdaptiveChannel)( + AecmCore_t* aecm, + const WebRtc_UWord16* far_spectrum, + WebRtc_Word32* echo_est); +extern StoreAdaptiveChannel WebRtcAecm_StoreAdaptiveChannel; + +typedef void (*ResetAdaptiveChannel)(AecmCore_t* aecm); +extern ResetAdaptiveChannel WebRtcAecm_ResetAdaptiveChannel; + +typedef void (*WindowAndFFT)( + WebRtc_Word16* fft, + const WebRtc_Word16* time_signal, + complex16_t* freq_signal, + int time_signal_scaling); +extern WindowAndFFT WebRtcAecm_WindowAndFFT; + +typedef void (*InverseFFTAndWindow)( + AecmCore_t* aecm, + WebRtc_Word16* fft, complex16_t* efw, + WebRtc_Word16* output, + const WebRtc_Word16* nearendClean); +extern InverseFFTAndWindow WebRtcAecm_InverseFFTAndWindow; + +// Initialization of the above function pointers for ARM Neon. +void WebRtcAecm_InitNeon(void); + + +#endif diff --git a/libs/miniwebrtc/audio/processing/aecm/aecm_core_neon.c b/libs/miniwebrtc/audio/processing/aecm/aecm_core_neon.c new file mode 100644 index 00000000..ab448b48 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/aecm/aecm_core_neon.c @@ -0,0 +1,303 @@ +/* + * 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 "aecm_core.h" + +#include +#include + + +// Square root of Hanning window in Q14. +static const WebRtc_Word16 kSqrtHanningReversed[] __attribute__((aligned(8))) = { + 16384, 16373, 16354, 16325, + 16286, 16237, 16179, 16111, + 16034, 15947, 15851, 15746, + 15631, 15506, 15373, 15231, + 15079, 14918, 14749, 14571, + 14384, 14189, 13985, 13773, + 13553, 13325, 13089, 12845, + 12594, 12335, 12068, 11795, + 11514, 11227, 10933, 10633, + 10326, 10013, 9695, 9370, + 9040, 8705, 8364, 8019, + 7668, 7313, 6954, 6591, + 6224, 5853, 5478, 5101, + 4720, 4337, 3951, 3562, + 3172, 2780, 2386, 1990, + 1594, 1196, 798, 399 +}; + +static void WindowAndFFTNeon(WebRtc_Word16* fft, + const WebRtc_Word16* time_signal, + complex16_t* freq_signal, + int time_signal_scaling) { + int i, j; + + int16x4_t tmp16x4_scaling = vdup_n_s16(time_signal_scaling); + __asm__("vmov.i16 d21, #0" ::: "d21"); + + for (i = 0, j = 0; i < PART_LEN; i += 4, j += 8) { + int16x4_t tmp16x4_0; + int16x4_t tmp16x4_1; + int32x4_t tmp32x4_0; + + /* Window near end */ + // fft[j] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT((time_signal[i] + // << time_signal_scaling), WebRtcAecm_kSqrtHanning[i], 14); + __asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_0) : "r"(&time_signal[i])); + tmp16x4_0 = vshl_s16(tmp16x4_0, tmp16x4_scaling); + + __asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_1) : "r"(&WebRtcAecm_kSqrtHanning[i])); + tmp32x4_0 = vmull_s16(tmp16x4_0, tmp16x4_1); + + __asm__("vshrn.i32 d20, %q0, #14" : : "w"(tmp32x4_0) : "d20"); + __asm__("vst2.16 {d20, d21}, [%0, :128]" : : "r"(&fft[j]) : "q10"); + + // fft[PART_LEN2 + j] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT( + // (time_signal[PART_LEN + i] << time_signal_scaling), + // WebRtcAecm_kSqrtHanning[PART_LEN - i], 14); + __asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_0) : "r"(&time_signal[i + PART_LEN])); + tmp16x4_0 = vshl_s16(tmp16x4_0, tmp16x4_scaling); + + __asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_1) : "r"(&kSqrtHanningReversed[i])); + tmp32x4_0 = vmull_s16(tmp16x4_0, tmp16x4_1); + + __asm__("vshrn.i32 d20, %q0, #14" : : "w"(tmp32x4_0) : "d20"); + __asm__("vst2.16 {d20, d21}, [%0, :128]" : : "r"(&fft[PART_LEN2 + j]) : "q10"); + } + + WebRtcSpl_ComplexBitReverse(fft, PART_LEN_SHIFT); + WebRtcSpl_ComplexFFT(fft, PART_LEN_SHIFT, 1); + + // Take only the first PART_LEN2 samples, and switch the sign of the imaginary part. + for (i = 0, j = 0; j < PART_LEN2; i += 8, j += 16) { + __asm__("vld2.16 {d20, d21, d22, d23}, [%0, :256]" : : "r"(&fft[j]) : "q10", "q11"); + __asm__("vneg.s16 d22, d22" : : : "q10"); + __asm__("vneg.s16 d23, d23" : : : "q11"); + __asm__("vst2.16 {d20, d21, d22, d23}, [%0, :256]" : : + "r"(&freq_signal[i].real): "q10", "q11"); + } +} + +static void InverseFFTAndWindowNeon(AecmCore_t* aecm, + WebRtc_Word16* fft, + complex16_t* efw, + WebRtc_Word16* output, + const WebRtc_Word16* nearendClean) { + int i, j, outCFFT; + WebRtc_Word32 tmp32no1; + + // Synthesis + for (i = 0, j = 0; i < PART_LEN; i += 4, j += 8) { + // We overwrite two more elements in fft[], but it's ok. + __asm__("vld2.16 {d20, d21}, [%0, :128]" : : "r"(&(efw[i].real)) : "q10"); + __asm__("vmov q11, q10" : : : "q10", "q11"); + + __asm__("vneg.s16 d23, d23" : : : "q11"); + __asm__("vst2.16 {d22, d23}, [%0, :128]" : : "r"(&fft[j]): "q11"); + + __asm__("vrev64.16 q10, q10" : : : "q10"); + __asm__("vst2.16 {d20, d21}, [%0]" : : "r"(&fft[PART_LEN4 - j - 6]): "q10"); + } + + fft[PART_LEN2] = efw[PART_LEN].real; + fft[PART_LEN2 + 1] = -efw[PART_LEN].imag; + + // Inverse FFT, result should be scaled with outCFFT. + WebRtcSpl_ComplexBitReverse(fft, PART_LEN_SHIFT); + outCFFT = WebRtcSpl_ComplexIFFT(fft, PART_LEN_SHIFT, 1); + + // Take only the real values and scale with outCFFT. + for (i = 0, j = 0; i < PART_LEN2; i += 8, j += 16) { + __asm__("vld2.16 {d20, d21, d22, d23}, [%0, :256]" : : "r"(&fft[j]) : "q10", "q11"); + __asm__("vst1.16 {d20, d21}, [%0, :128]" : : "r"(&fft[i]): "q10"); + } + + int32x4_t tmp32x4_2; + __asm__("vdup.32 %q0, %1" : "=w"(tmp32x4_2) : "r"((WebRtc_Word32) + (outCFFT - aecm->dfaCleanQDomain))); + for (i = 0; i < PART_LEN; i += 4) { + int16x4_t tmp16x4_0; + int16x4_t tmp16x4_1; + int32x4_t tmp32x4_0; + int32x4_t tmp32x4_1; + + // fft[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( + // fft[i], WebRtcAecm_kSqrtHanning[i], 14); + __asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_0) : "r"(&fft[i])); + __asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_1) : "r"(&WebRtcAecm_kSqrtHanning[i])); + __asm__("vmull.s16 %q0, %P1, %P2" : "=w"(tmp32x4_0) : "w"(tmp16x4_0), "w"(tmp16x4_1)); + __asm__("vrshr.s32 %q0, %q1, #14" : "=w"(tmp32x4_0) : "0"(tmp32x4_0)); + + // tmp32no1 = WEBRTC_SPL_SHIFT_W32((WebRtc_Word32)fft[i], + // outCFFT - aecm->dfaCleanQDomain); + __asm__("vshl.s32 %q0, %q1, %q2" : "=w"(tmp32x4_0) : "0"(tmp32x4_0), "w"(tmp32x4_2)); + + // fft[i] = (WebRtc_Word16)WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, + // tmp32no1 + outBuf[i], WEBRTC_SPL_WORD16_MIN); + // output[i] = fft[i]; + __asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_0) : "r"(&aecm->outBuf[i])); + __asm__("vmovl.s16 %q0, %P1" : "=w"(tmp32x4_1) : "w"(tmp16x4_0)); + __asm__("vadd.i32 %q0, %q1" : : "w"(tmp32x4_0), "w"(tmp32x4_1)); + __asm__("vqshrn.s32 %P0, %q1, #0" : "=w"(tmp16x4_0) : "w"(tmp32x4_0)); + __asm__("vst1.16 %P0, [%1, :64]" : : "w"(tmp16x4_0), "r"(&fft[i])); + __asm__("vst1.16 %P0, [%1, :64]" : : "w"(tmp16x4_0), "r"(&output[i])); + + // tmp32no1 = WEBRTC_SPL_MUL_16_16_RSFT( + // fft[PART_LEN + i], WebRtcAecm_kSqrtHanning[PART_LEN - i], 14); + __asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_0) : "r"(&fft[PART_LEN + i])); + __asm__("vld1.16 %P0, [%1, :64]" : "=w"(tmp16x4_1) : "r"(&kSqrtHanningReversed[i])); + __asm__("vmull.s16 %q0, %P1, %P2" : "=w"(tmp32x4_0) : "w"(tmp16x4_0), "w"(tmp16x4_1)); + __asm__("vshr.s32 %q0, %q1, #14" : "=w"(tmp32x4_0) : "0"(tmp32x4_0)); + + // tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1, outCFFT - aecm->dfaCleanQDomain); + __asm__("vshl.s32 %q0, %q1, %q2" : "=w"(tmp32x4_0) : "0"(tmp32x4_0), "w"(tmp32x4_2)); + // outBuf[i] = (WebRtc_Word16)WEBRTC_SPL_SAT( + // WEBRTC_SPL_WORD16_MAX, tmp32no1, WEBRTC_SPL_WORD16_MIN); + __asm__("vqshrn.s32 %P0, %q1, #0" : "=w"(tmp16x4_0) : "w"(tmp32x4_0)); + __asm__("vst1.16 %P0, [%1, :64]" : : "w"(tmp16x4_0), "r"(&aecm->outBuf[i])); + } + + // Copy the current block to the old position (outBuf is shifted elsewhere). + for (i = 0; i < PART_LEN; i += 16) { + __asm__("vld1.16 {d20, d21, d22, d23}, [%0, :256]" : : + "r"(&aecm->xBuf[i + PART_LEN]) : "q10"); + __asm__("vst1.16 {d20, d21, d22, d23}, [%0, :256]" : : "r"(&aecm->xBuf[i]): "q10"); + } + for (i = 0; i < PART_LEN; i += 16) { + __asm__("vld1.16 {d20, d21, d22, d23}, [%0, :256]" : : + "r"(&aecm->dBufNoisy[i + PART_LEN]) : "q10"); + __asm__("vst1.16 {d20, d21, d22, d23}, [%0, :256]" : : + "r"(&aecm->dBufNoisy[i]): "q10"); + } + if (nearendClean != NULL) { + for (i = 0; i < PART_LEN; i += 16) { + __asm__("vld1.16 {d20, d21, d22, d23}, [%0, :256]" : : + "r"(&aecm->dBufClean[i + PART_LEN]) : "q10"); + __asm__("vst1.16 {d20, d21, d22, d23}, [%0, :256]" : : + "r"(&aecm->dBufClean[i]): "q10"); + } + } +} + +static void CalcLinearEnergiesNeon(AecmCore_t* aecm, + const WebRtc_UWord16* far_spectrum, + WebRtc_Word32* echo_est, + WebRtc_UWord32* far_energy, + WebRtc_UWord32* echo_energy_adapt, + WebRtc_UWord32* echo_energy_stored) { + int i; + + register WebRtc_UWord32 far_energy_r; + register WebRtc_UWord32 echo_energy_stored_r; + register WebRtc_UWord32 echo_energy_adapt_r; + uint32x4_t tmp32x4_0; + + __asm__("vmov.i32 q14, #0" : : : "q14"); // far_energy + __asm__("vmov.i32 q8, #0" : : : "q8"); // echo_energy_stored + __asm__("vmov.i32 q9, #0" : : : "q9"); // echo_energy_adapt + + for (i = 0; i < PART_LEN - 7; i += 8) { + // far_energy += (WebRtc_UWord32)(far_spectrum[i]); + __asm__("vld1.16 {d26, d27}, [%0]" : : "r"(&far_spectrum[i]) : "q13"); + __asm__("vaddw.u16 q14, q14, d26" : : : "q14", "q13"); + __asm__("vaddw.u16 q14, q14, d27" : : : "q14", "q13"); + + // Get estimated echo energies for adaptive channel and stored channel. + // echoEst[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]); + __asm__("vld1.16 {d24, d25}, [%0, :128]" : : "r"(&aecm->channelStored[i]) : "q12"); + __asm__("vmull.u16 q10, d26, d24" : : : "q12", "q13", "q10"); + __asm__("vmull.u16 q11, d27, d25" : : : "q12", "q13", "q11"); + __asm__("vst1.32 {d20, d21, d22, d23}, [%0, :256]" : : "r"(&echo_est[i]): + "q10", "q11"); + + // echo_energy_stored += (WebRtc_UWord32)echoEst[i]; + __asm__("vadd.u32 q8, q10" : : : "q10", "q8"); + __asm__("vadd.u32 q8, q11" : : : "q11", "q8"); + + // echo_energy_adapt += WEBRTC_SPL_UMUL_16_16( + // aecm->channelAdapt16[i], far_spectrum[i]); + __asm__("vld1.16 {d24, d25}, [%0, :128]" : : "r"(&aecm->channelAdapt16[i]) : "q12"); + __asm__("vmull.u16 q10, d26, d24" : : : "q12", "q13", "q10"); + __asm__("vmull.u16 q11, d27, d25" : : : "q12", "q13", "q11"); + __asm__("vadd.u32 q9, q10" : : : "q9", "q15"); + __asm__("vadd.u32 q9, q11" : : : "q9", "q11"); + } + + __asm__("vadd.u32 d28, d29" : : : "q14"); + __asm__("vpadd.u32 d28, d28" : : : "q14"); + __asm__("vmov.32 %0, d28[0]" : "=r"(far_energy_r): : "q14"); + + __asm__("vadd.u32 d18, d19" : : : "q9"); + __asm__("vpadd.u32 d18, d18" : : : "q9"); + __asm__("vmov.32 %0, d18[0]" : "=r"(echo_energy_adapt_r): : "q9"); + + __asm__("vadd.u32 d16, d17" : : : "q8"); + __asm__("vpadd.u32 d16, d16" : : : "q8"); + __asm__("vmov.32 %0, d16[0]" : "=r"(echo_energy_stored_r): : "q8"); + + // Get estimated echo energies for adaptive channel and stored channel. + echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]); + *echo_energy_stored = echo_energy_stored_r + (WebRtc_UWord32)echo_est[i]; + *far_energy = far_energy_r + (WebRtc_UWord32)(far_spectrum[i]); + *echo_energy_adapt = echo_energy_adapt_r + WEBRTC_SPL_UMUL_16_16( + aecm->channelAdapt16[i], far_spectrum[i]); +} + +static void StoreAdaptiveChannelNeon(AecmCore_t* aecm, + const WebRtc_UWord16* far_spectrum, + WebRtc_Word32* echo_est) { + int i; + + // During startup we store the channel every block. + // Recalculate echo estimate. + for (i = 0; i < PART_LEN - 7; i += 8) { + // aecm->channelStored[i] = acem->channelAdapt16[i]; + // echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]); + __asm__("vld1.16 {d26, d27}, [%0]" : : "r"(&far_spectrum[i]) : "q13"); + __asm__("vld1.16 {d24, d25}, [%0, :128]" : : "r"(&aecm->channelAdapt16[i]) : "q12"); + __asm__("vst1.16 {d24, d25}, [%0, :128]" : : "r"(&aecm->channelStored[i]) : "q12"); + __asm__("vmull.u16 q10, d26, d24" : : : "q12", "q13", "q10"); + __asm__("vmull.u16 q11, d27, d25" : : : "q12", "q13", "q11"); + __asm__("vst1.16 {d20, d21, d22, d23}, [%0, :256]" : : + "r"(&echo_est[i]) : "q10", "q11"); + } + aecm->channelStored[i] = aecm->channelAdapt16[i]; + echo_est[i] = WEBRTC_SPL_MUL_16_U16(aecm->channelStored[i], far_spectrum[i]); +} + +static void ResetAdaptiveChannelNeon(AecmCore_t* aecm) { + int i; + + for (i = 0; i < PART_LEN - 7; i += 8) { + // aecm->channelAdapt16[i] = aecm->channelStored[i]; + // aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32) + // aecm->channelStored[i], 16); + __asm__("vld1.16 {d24, d25}, [%0, :128]" : : + "r"(&aecm->channelStored[i]) : "q12"); + __asm__("vst1.16 {d24, d25}, [%0, :128]" : : + "r"(&aecm->channelAdapt16[i]) : "q12"); + __asm__("vshll.s16 q10, d24, #16" : : : "q12", "q13", "q10"); + __asm__("vshll.s16 q11, d25, #16" : : : "q12", "q13", "q11"); + __asm__("vst1.16 {d20, d21, d22, d23}, [%0, :256]" : : + "r"(&aecm->channelAdapt32[i]): "q10", "q11"); + } + aecm->channelAdapt16[i] = aecm->channelStored[i]; + aecm->channelAdapt32[i] = WEBRTC_SPL_LSHIFT_W32( + (WebRtc_Word32)aecm->channelStored[i], 16); +} + +void WebRtcAecm_InitNeon(void) { + WebRtcAecm_WindowAndFFT = WindowAndFFTNeon; + WebRtcAecm_InverseFFTAndWindow = InverseFFTAndWindowNeon; + WebRtcAecm_CalcLinearEnergies = CalcLinearEnergiesNeon; + WebRtcAecm_StoreAdaptiveChannel = StoreAdaptiveChannelNeon; + WebRtcAecm_ResetAdaptiveChannel = ResetAdaptiveChannelNeon; +} diff --git a/libs/miniwebrtc/audio/processing/aecm/echo_control_mobile.c b/libs/miniwebrtc/audio/processing/aecm/echo_control_mobile.c new file mode 100644 index 00000000..566ae00d --- /dev/null +++ b/libs/miniwebrtc/audio/processing/aecm/echo_control_mobile.c @@ -0,0 +1,792 @@ +/* + * 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 +//#include + +#include "echo_control_mobile.h" +#include "aecm_core.h" +#include "ring_buffer.h" +#ifdef AEC_DEBUG +#include +#endif +#ifdef MAC_IPHONE_PRINT +#include +#include +#elif defined ARM_WINM_LOG +#include "windows.h" +extern HANDLE logFile; +#endif + +#define BUF_SIZE_FRAMES 50 // buffer size (frames) +// Maximum length of resampled signal. Must be an integer multiple of frames +// (ceil(1/(1 + MIN_SKEW)*2) + 1)*FRAME_LEN +// The factor of 2 handles wb, and the + 1 is as a safety margin +#define MAX_RESAMP_LEN (5 * FRAME_LEN) + +static const size_t kBufSizeSamp = BUF_SIZE_FRAMES * FRAME_LEN; // buffer size (samples) +static const int kSampMsNb = 8; // samples per ms in nb +// Target suppression levels for nlp modes +// log{0.001, 0.00001, 0.00000001} +static const int kInitCheck = 42; + +typedef struct +{ + int sampFreq; + int scSampFreq; + short bufSizeStart; + int knownDelay; + + // Stores the last frame added to the farend buffer + short farendOld[2][FRAME_LEN]; + short initFlag; // indicates if AEC has been initialized + + // Variables used for averaging far end buffer size + short counter; + short sum; + short firstVal; + short checkBufSizeCtr; + + // Variables used for delay shifts + short msInSndCardBuf; + short filtDelay; + int timeForDelayChange; + int ECstartup; + int checkBuffSize; + int delayChange; + short lastDelayDiff; + + WebRtc_Word16 echoMode; + +#ifdef AEC_DEBUG + FILE *bufFile; + FILE *delayFile; + FILE *preCompFile; + FILE *postCompFile; +#endif // AEC_DEBUG + // Structures + void *farendBuf; + + int lastError; + + AecmCore_t *aecmCore; +} aecmob_t; + +// Estimates delay to set the position of the farend buffer read pointer +// (controlled by knownDelay) +static int WebRtcAecm_EstBufDelay(aecmob_t *aecmInst, short msInSndCardBuf); + +// Stuffs the farend buffer if the estimated delay is too large +static int WebRtcAecm_DelayComp(aecmob_t *aecmInst); + +WebRtc_Word32 WebRtcAecm_Create(void **aecmInst) +{ + aecmob_t *aecm; + if (aecmInst == NULL) + { + return -1; + } + + aecm = malloc(sizeof(aecmob_t)); + *aecmInst = aecm; + if (aecm == NULL) + { + return -1; + } + + if (WebRtcAecm_CreateCore(&aecm->aecmCore) == -1) + { + WebRtcAecm_Free(aecm); + aecm = NULL; + return -1; + } + + if (WebRtc_CreateBuffer(&aecm->farendBuf, kBufSizeSamp, + sizeof(int16_t)) == -1) + { + WebRtcAecm_Free(aecm); + aecm = NULL; + return -1; + } + + aecm->initFlag = 0; + aecm->lastError = 0; + +#ifdef AEC_DEBUG + aecm->aecmCore->farFile = fopen("aecFar.pcm","wb"); + aecm->aecmCore->nearFile = fopen("aecNear.pcm","wb"); + aecm->aecmCore->outFile = fopen("aecOut.pcm","wb"); + //aecm->aecmCore->outLpFile = fopen("aecOutLp.pcm","wb"); + + aecm->bufFile = fopen("aecBuf.dat", "wb"); + aecm->delayFile = fopen("aecDelay.dat", "wb"); + aecm->preCompFile = fopen("preComp.pcm", "wb"); + aecm->postCompFile = fopen("postComp.pcm", "wb"); +#endif // AEC_DEBUG + return 0; +} + +WebRtc_Word32 WebRtcAecm_Free(void *aecmInst) +{ + aecmob_t *aecm = aecmInst; + + if (aecm == NULL) + { + return -1; + } + +#ifdef AEC_DEBUG + fclose(aecm->aecmCore->farFile); + fclose(aecm->aecmCore->nearFile); + fclose(aecm->aecmCore->outFile); + //fclose(aecm->aecmCore->outLpFile); + + fclose(aecm->bufFile); + fclose(aecm->delayFile); + fclose(aecm->preCompFile); + fclose(aecm->postCompFile); +#endif // AEC_DEBUG + WebRtcAecm_FreeCore(aecm->aecmCore); + WebRtc_FreeBuffer(aecm->farendBuf); + free(aecm); + + return 0; +} + +WebRtc_Word32 WebRtcAecm_Init(void *aecmInst, WebRtc_Word32 sampFreq) +{ + aecmob_t *aecm = aecmInst; + AecmConfig aecConfig; + + if (aecm == NULL) + { + return -1; + } + + if (sampFreq != 8000 && sampFreq != 16000) + { + aecm->lastError = AECM_BAD_PARAMETER_ERROR; + return -1; + } + aecm->sampFreq = sampFreq; + + // Initialize AECM core + if (WebRtcAecm_InitCore(aecm->aecmCore, aecm->sampFreq) == -1) + { + aecm->lastError = AECM_UNSPECIFIED_ERROR; + return -1; + } + + // Initialize farend buffer + if (WebRtc_InitBuffer(aecm->farendBuf) == -1) + { + aecm->lastError = AECM_UNSPECIFIED_ERROR; + return -1; + } + + aecm->initFlag = kInitCheck; // indicates that initialization has been done + + aecm->delayChange = 1; + + aecm->sum = 0; + aecm->counter = 0; + aecm->checkBuffSize = 1; + aecm->firstVal = 0; + + aecm->ECstartup = 1; + aecm->bufSizeStart = 0; + aecm->checkBufSizeCtr = 0; + aecm->filtDelay = 0; + aecm->timeForDelayChange = 0; + aecm->knownDelay = 0; + aecm->lastDelayDiff = 0; + + memset(&aecm->farendOld[0][0], 0, 160); + + // Default settings. + aecConfig.cngMode = AecmTrue; + aecConfig.echoMode = 3; + + if (WebRtcAecm_set_config(aecm, aecConfig) == -1) + { + aecm->lastError = AECM_UNSPECIFIED_ERROR; + return -1; + } + + return 0; +} + +WebRtc_Word32 WebRtcAecm_BufferFarend(void *aecmInst, const WebRtc_Word16 *farend, + WebRtc_Word16 nrOfSamples) +{ + aecmob_t *aecm = aecmInst; + WebRtc_Word32 retVal = 0; + + if (aecm == NULL) + { + return -1; + } + + if (farend == NULL) + { + aecm->lastError = AECM_NULL_POINTER_ERROR; + return -1; + } + + if (aecm->initFlag != kInitCheck) + { + aecm->lastError = AECM_UNINITIALIZED_ERROR; + return -1; + } + + if (nrOfSamples != 80 && nrOfSamples != 160) + { + aecm->lastError = AECM_BAD_PARAMETER_ERROR; + return -1; + } + + // TODO: Is this really a good idea? + if (!aecm->ECstartup) + { + WebRtcAecm_DelayComp(aecm); + } + + WebRtc_WriteBuffer(aecm->farendBuf, farend, (size_t) nrOfSamples); + + return retVal; +} + +WebRtc_Word32 WebRtcAecm_Process(void *aecmInst, const WebRtc_Word16 *nearendNoisy, + const WebRtc_Word16 *nearendClean, WebRtc_Word16 *out, + WebRtc_Word16 nrOfSamples, WebRtc_Word16 msInSndCardBuf) +{ + aecmob_t *aecm = aecmInst; + WebRtc_Word32 retVal = 0; + short i; + short nmbrOfFilledBuffers; + short nBlocks10ms; + short nFrames; +#ifdef AEC_DEBUG + short msInAECBuf; +#endif + +#ifdef ARM_WINM_LOG + __int64 freq, start, end, diff; + unsigned int milliseconds; + DWORD temp; +#elif defined MAC_IPHONE_PRINT + // double endtime = 0, starttime = 0; + struct timeval starttime; + struct timeval endtime; + static long int timeused = 0; + static int timecount = 0; +#endif + + if (aecm == NULL) + { + return -1; + } + + if (nearendNoisy == NULL) + { + aecm->lastError = AECM_NULL_POINTER_ERROR; + return -1; + } + + if (out == NULL) + { + aecm->lastError = AECM_NULL_POINTER_ERROR; + return -1; + } + + if (aecm->initFlag != kInitCheck) + { + aecm->lastError = AECM_UNINITIALIZED_ERROR; + return -1; + } + + if (nrOfSamples != 80 && nrOfSamples != 160) + { + aecm->lastError = AECM_BAD_PARAMETER_ERROR; + return -1; + } + + if (msInSndCardBuf < 0) + { + msInSndCardBuf = 0; + aecm->lastError = AECM_BAD_PARAMETER_WARNING; + retVal = -1; + } else if (msInSndCardBuf > 500) + { + msInSndCardBuf = 500; + aecm->lastError = AECM_BAD_PARAMETER_WARNING; + retVal = -1; + } + msInSndCardBuf += 10; + aecm->msInSndCardBuf = msInSndCardBuf; + + nFrames = nrOfSamples / FRAME_LEN; + nBlocks10ms = nFrames / aecm->aecmCore->mult; + + if (aecm->ECstartup) + { + if (nearendClean == NULL) + { + if (out != nearendNoisy) + { + memcpy(out, nearendNoisy, sizeof(short) * nrOfSamples); + } + } else if (out != nearendClean) + { + memcpy(out, nearendClean, sizeof(short) * nrOfSamples); + } + + nmbrOfFilledBuffers = + (short) WebRtc_available_read(aecm->farendBuf) / FRAME_LEN; + // The AECM is in the start up mode + // AECM is disabled until the soundcard buffer and farend buffers are OK + + // Mechanism to ensure that the soundcard buffer is reasonably stable. + if (aecm->checkBuffSize) + { + aecm->checkBufSizeCtr++; + // Before we fill up the far end buffer we require the amount of data on the + // sound card to be stable (+/-8 ms) compared to the first value. This + // comparison is made during the following 4 consecutive frames. If it seems + // to be stable then we start to fill up the far end buffer. + + if (aecm->counter == 0) + { + aecm->firstVal = aecm->msInSndCardBuf; + aecm->sum = 0; + } + + if (abs(aecm->firstVal - aecm->msInSndCardBuf) + < WEBRTC_SPL_MAX(0.2 * aecm->msInSndCardBuf, kSampMsNb)) + { + aecm->sum += aecm->msInSndCardBuf; + aecm->counter++; + } else + { + aecm->counter = 0; + } + + if (aecm->counter * nBlocks10ms >= 6) + { + // The farend buffer size is determined in blocks of 80 samples + // Use 75% of the average value of the soundcard buffer + aecm->bufSizeStart + = WEBRTC_SPL_MIN((3 * aecm->sum + * aecm->aecmCore->mult) / (aecm->counter * 40), BUF_SIZE_FRAMES); + // buffersize has now been determined + aecm->checkBuffSize = 0; + } + + if (aecm->checkBufSizeCtr * nBlocks10ms > 50) + { + // for really bad sound cards, don't disable echocanceller for more than 0.5 sec + aecm->bufSizeStart = WEBRTC_SPL_MIN((3 * aecm->msInSndCardBuf + * aecm->aecmCore->mult) / 40, BUF_SIZE_FRAMES); + aecm->checkBuffSize = 0; + } + } + + // if checkBuffSize changed in the if-statement above + if (!aecm->checkBuffSize) + { + // soundcard buffer is now reasonably stable + // When the far end buffer is filled with approximately the same amount of + // data as the amount on the sound card we end the start up phase and start + // to cancel echoes. + + if (nmbrOfFilledBuffers == aecm->bufSizeStart) + { + aecm->ECstartup = 0; // Enable the AECM + } else if (nmbrOfFilledBuffers > aecm->bufSizeStart) + { + WebRtc_MoveReadPtr(aecm->farendBuf, + (int) WebRtc_available_read(aecm->farendBuf) + - (int) aecm->bufSizeStart * FRAME_LEN); + aecm->ECstartup = 0; + } + } + + } else + { + // AECM is enabled + + // Note only 1 block supported for nb and 2 blocks for wb + for (i = 0; i < nFrames; i++) + { + int16_t farend[FRAME_LEN]; + const int16_t* farend_ptr = NULL; + + nmbrOfFilledBuffers = + (short) WebRtc_available_read(aecm->farendBuf) / FRAME_LEN; + + // Check that there is data in the far end buffer + if (nmbrOfFilledBuffers > 0) + { + // Get the next 80 samples from the farend buffer + WebRtc_ReadBuffer(aecm->farendBuf, (void**) &farend_ptr, farend, + FRAME_LEN); + + // Always store the last frame for use when we run out of data + memcpy(&(aecm->farendOld[i][0]), farend_ptr, + FRAME_LEN * sizeof(short)); + } else + { + // We have no data so we use the last played frame + memcpy(farend, &(aecm->farendOld[i][0]), FRAME_LEN * sizeof(short)); + farend_ptr = farend; + } + + // Call buffer delay estimator when all data is extracted, + // i,e. i = 0 for NB and i = 1 for WB + if ((i == 0 && aecm->sampFreq == 8000) || (i == 1 && aecm->sampFreq == 16000)) + { + WebRtcAecm_EstBufDelay(aecm, aecm->msInSndCardBuf); + } + +#ifdef ARM_WINM_LOG + // measure tick start + QueryPerformanceFrequency((LARGE_INTEGER*)&freq); + QueryPerformanceCounter((LARGE_INTEGER*)&start); +#elif defined MAC_IPHONE_PRINT + // starttime = clock()/(double)CLOCKS_PER_SEC; + gettimeofday(&starttime, NULL); +#endif + // Call the AECM + /*WebRtcAecm_ProcessFrame(aecm->aecmCore, farend, &nearend[FRAME_LEN * i], + &out[FRAME_LEN * i], aecm->knownDelay);*/ + if (nearendClean == NULL) + { + if (WebRtcAecm_ProcessFrame(aecm->aecmCore, + farend_ptr, + &nearendNoisy[FRAME_LEN * i], + NULL, + &out[FRAME_LEN * i]) == -1) + { + return -1; + } + } else + { + if (WebRtcAecm_ProcessFrame(aecm->aecmCore, + farend_ptr, + &nearendNoisy[FRAME_LEN * i], + &nearendClean[FRAME_LEN * i], + &out[FRAME_LEN * i]) == -1) + { + return -1; + } + } + +#ifdef ARM_WINM_LOG + + // measure tick end + QueryPerformanceCounter((LARGE_INTEGER*)&end); + + if(end > start) + { + diff = ((end - start) * 1000) / (freq/1000); + milliseconds = (unsigned int)(diff & 0xffffffff); + WriteFile (logFile, &milliseconds, sizeof(unsigned int), &temp, NULL); + } +#elif defined MAC_IPHONE_PRINT + // endtime = clock()/(double)CLOCKS_PER_SEC; + // printf("%f\n", endtime - starttime); + + gettimeofday(&endtime, NULL); + + if( endtime.tv_usec > starttime.tv_usec) + { + timeused += endtime.tv_usec - starttime.tv_usec; + } else + { + timeused += endtime.tv_usec + 1000000 - starttime.tv_usec; + } + + if(++timecount == 1000) + { + timecount = 0; + printf("AEC: %ld\n", timeused); + timeused = 0; + } +#endif + + } + } + +#ifdef AEC_DEBUG + msInAECBuf = (short) WebRtc_available_read(aecm->farendBuf) / + (kSampMsNb * aecm->aecmCore->mult); + fwrite(&msInAECBuf, 2, 1, aecm->bufFile); + fwrite(&(aecm->knownDelay), sizeof(aecm->knownDelay), 1, aecm->delayFile); +#endif + + return retVal; +} + +WebRtc_Word32 WebRtcAecm_set_config(void *aecmInst, AecmConfig config) +{ + aecmob_t *aecm = aecmInst; + + if (aecm == NULL) + { + return -1; + } + + if (aecm->initFlag != kInitCheck) + { + aecm->lastError = AECM_UNINITIALIZED_ERROR; + return -1; + } + + if (config.cngMode != AecmFalse && config.cngMode != AecmTrue) + { + aecm->lastError = AECM_BAD_PARAMETER_ERROR; + return -1; + } + aecm->aecmCore->cngMode = config.cngMode; + + if (config.echoMode < 0 || config.echoMode > 4) + { + aecm->lastError = AECM_BAD_PARAMETER_ERROR; + return -1; + } + aecm->echoMode = config.echoMode; + + if (aecm->echoMode == 0) + { + aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 3; + aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 3; + aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 3; + aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 3; + aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 3) + - (SUPGAIN_ERROR_PARAM_B >> 3); + aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 3) + - (SUPGAIN_ERROR_PARAM_D >> 3); + } else if (aecm->echoMode == 1) + { + aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 2; + aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 2; + aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 2; + aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 2; + aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 2) + - (SUPGAIN_ERROR_PARAM_B >> 2); + aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 2) + - (SUPGAIN_ERROR_PARAM_D >> 2); + } else if (aecm->echoMode == 2) + { + aecm->aecmCore->supGain = SUPGAIN_DEFAULT >> 1; + aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT >> 1; + aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A >> 1; + aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D >> 1; + aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A >> 1) + - (SUPGAIN_ERROR_PARAM_B >> 1); + aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B >> 1) + - (SUPGAIN_ERROR_PARAM_D >> 1); + } else if (aecm->echoMode == 3) + { + aecm->aecmCore->supGain = SUPGAIN_DEFAULT; + aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT; + aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A; + aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D; + aecm->aecmCore->supGainErrParamDiffAB = SUPGAIN_ERROR_PARAM_A - SUPGAIN_ERROR_PARAM_B; + aecm->aecmCore->supGainErrParamDiffBD = SUPGAIN_ERROR_PARAM_B - SUPGAIN_ERROR_PARAM_D; + } else if (aecm->echoMode == 4) + { + aecm->aecmCore->supGain = SUPGAIN_DEFAULT << 1; + aecm->aecmCore->supGainOld = SUPGAIN_DEFAULT << 1; + aecm->aecmCore->supGainErrParamA = SUPGAIN_ERROR_PARAM_A << 1; + aecm->aecmCore->supGainErrParamD = SUPGAIN_ERROR_PARAM_D << 1; + aecm->aecmCore->supGainErrParamDiffAB = (SUPGAIN_ERROR_PARAM_A << 1) + - (SUPGAIN_ERROR_PARAM_B << 1); + aecm->aecmCore->supGainErrParamDiffBD = (SUPGAIN_ERROR_PARAM_B << 1) + - (SUPGAIN_ERROR_PARAM_D << 1); + } + + return 0; +} + +WebRtc_Word32 WebRtcAecm_get_config(void *aecmInst, AecmConfig *config) +{ + aecmob_t *aecm = aecmInst; + + if (aecm == NULL) + { + return -1; + } + + if (config == NULL) + { + aecm->lastError = AECM_NULL_POINTER_ERROR; + return -1; + } + + if (aecm->initFlag != kInitCheck) + { + aecm->lastError = AECM_UNINITIALIZED_ERROR; + return -1; + } + + config->cngMode = aecm->aecmCore->cngMode; + config->echoMode = aecm->echoMode; + + return 0; +} + +WebRtc_Word32 WebRtcAecm_InitEchoPath(void* aecmInst, + const void* echo_path, + size_t size_bytes) +{ + aecmob_t *aecm = aecmInst; + const WebRtc_Word16* echo_path_ptr = echo_path; + + if ((aecm == NULL) || (echo_path == NULL)) + { + aecm->lastError = AECM_NULL_POINTER_ERROR; + return -1; + } + if (size_bytes != WebRtcAecm_echo_path_size_bytes()) + { + // Input channel size does not match the size of AECM + aecm->lastError = AECM_BAD_PARAMETER_ERROR; + return -1; + } + if (aecm->initFlag != kInitCheck) + { + aecm->lastError = AECM_UNINITIALIZED_ERROR; + return -1; + } + + WebRtcAecm_InitEchoPathCore(aecm->aecmCore, echo_path_ptr); + + return 0; +} + +WebRtc_Word32 WebRtcAecm_GetEchoPath(void* aecmInst, + void* echo_path, + size_t size_bytes) +{ + aecmob_t *aecm = aecmInst; + WebRtc_Word16* echo_path_ptr = echo_path; + + if ((aecm == NULL) || (echo_path == NULL)) + { + aecm->lastError = AECM_NULL_POINTER_ERROR; + return -1; + } + if (size_bytes != WebRtcAecm_echo_path_size_bytes()) + { + // Input channel size does not match the size of AECM + aecm->lastError = AECM_BAD_PARAMETER_ERROR; + return -1; + } + if (aecm->initFlag != kInitCheck) + { + aecm->lastError = AECM_UNINITIALIZED_ERROR; + return -1; + } + + memcpy(echo_path_ptr, aecm->aecmCore->channelStored, size_bytes); + return 0; +} + +size_t WebRtcAecm_echo_path_size_bytes() +{ + return (PART_LEN1 * sizeof(WebRtc_Word16)); +} + +WebRtc_Word32 WebRtcAecm_get_error_code(void *aecmInst) +{ + aecmob_t *aecm = aecmInst; + + if (aecm == NULL) + { + return -1; + } + + return aecm->lastError; +} + +static int WebRtcAecm_EstBufDelay(aecmob_t *aecm, short msInSndCardBuf) +{ + short delayNew, nSampSndCard; + short nSampFar = (short) WebRtc_available_read(aecm->farendBuf); + short diff; + + nSampSndCard = msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult; + + delayNew = nSampSndCard - nSampFar; + + if (delayNew < FRAME_LEN) + { + WebRtc_MoveReadPtr(aecm->farendBuf, FRAME_LEN); + delayNew += FRAME_LEN; + } + + aecm->filtDelay = WEBRTC_SPL_MAX(0, (8 * aecm->filtDelay + 2 * delayNew) / 10); + + diff = aecm->filtDelay - aecm->knownDelay; + if (diff > 224) + { + if (aecm->lastDelayDiff < 96) + { + aecm->timeForDelayChange = 0; + } else + { + aecm->timeForDelayChange++; + } + } else if (diff < 96 && aecm->knownDelay > 0) + { + if (aecm->lastDelayDiff > 224) + { + aecm->timeForDelayChange = 0; + } else + { + aecm->timeForDelayChange++; + } + } else + { + aecm->timeForDelayChange = 0; + } + aecm->lastDelayDiff = diff; + + if (aecm->timeForDelayChange > 25) + { + aecm->knownDelay = WEBRTC_SPL_MAX((int)aecm->filtDelay - 160, 0); + } + return 0; +} + +static int WebRtcAecm_DelayComp(aecmob_t *aecm) +{ + int nSampFar = (int) WebRtc_available_read(aecm->farendBuf); + int nSampSndCard, delayNew, nSampAdd; + const int maxStuffSamp = 10 * FRAME_LEN; + + nSampSndCard = aecm->msInSndCardBuf * kSampMsNb * aecm->aecmCore->mult; + delayNew = nSampSndCard - nSampFar; + + if (delayNew > FAR_BUF_LEN - FRAME_LEN * aecm->aecmCore->mult) + { + // The difference of the buffer sizes is larger than the maximum + // allowed known delay. Compensate by stuffing the buffer. + nSampAdd = (int)(WEBRTC_SPL_MAX(((nSampSndCard >> 1) - nSampFar), + FRAME_LEN)); + nSampAdd = WEBRTC_SPL_MIN(nSampAdd, maxStuffSamp); + + WebRtc_MoveReadPtr(aecm->farendBuf, -nSampAdd); + aecm->delayChange = 1; // the delay needs to be updated + } + + return 0; +} diff --git a/libs/miniwebrtc/audio/processing/aecm/echo_control_mobile.h b/libs/miniwebrtc/audio/processing/aecm/echo_control_mobile.h new file mode 100644 index 00000000..da0ad868 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/aecm/echo_control_mobile.h @@ -0,0 +1,233 @@ +/* + * 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_PROCESSING_AECM_INCLUDE_ECHO_CONTROL_MOBILE_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_AECM_INCLUDE_ECHO_CONTROL_MOBILE_H_ + +#include "typedefs.h" + +enum { + AecmFalse = 0, + AecmTrue +}; + +// Errors +#define AECM_UNSPECIFIED_ERROR 12000 +#define AECM_UNSUPPORTED_FUNCTION_ERROR 12001 +#define AECM_UNINITIALIZED_ERROR 12002 +#define AECM_NULL_POINTER_ERROR 12003 +#define AECM_BAD_PARAMETER_ERROR 12004 + +// Warnings +#define AECM_BAD_PARAMETER_WARNING 12100 + +typedef struct { + WebRtc_Word16 cngMode; // AECM_FALSE, AECM_TRUE (default) + WebRtc_Word16 echoMode; // 0, 1, 2, 3 (default), 4 +} AecmConfig; + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Allocates the memory needed by the AECM. The memory needs to be + * initialized separately using the WebRtcAecm_Init() function. + * + * Inputs Description + * ------------------------------------------------------------------- + * void **aecmInst Pointer to the AECM instance to be + * created and initialized + * + * Outputs Description + * ------------------------------------------------------------------- + * WebRtc_Word32 return 0: OK + * -1: error + */ +WebRtc_Word32 WebRtcAecm_Create(void **aecmInst); + +/* + * This function releases the memory allocated by WebRtcAecm_Create() + * + * Inputs Description + * ------------------------------------------------------------------- + * void *aecmInst Pointer to the AECM instance + * + * Outputs Description + * ------------------------------------------------------------------- + * WebRtc_Word32 return 0: OK + * -1: error + */ +WebRtc_Word32 WebRtcAecm_Free(void *aecmInst); + +/* + * Initializes an AECM instance. + * + * Inputs Description + * ------------------------------------------------------------------- + * void *aecmInst Pointer to the AECM instance + * WebRtc_Word32 sampFreq Sampling frequency of data + * + * Outputs Description + * ------------------------------------------------------------------- + * WebRtc_Word32 return 0: OK + * -1: error + */ +WebRtc_Word32 WebRtcAecm_Init(void* aecmInst, + WebRtc_Word32 sampFreq); + +/* + * Inserts an 80 or 160 sample block of data into the farend buffer. + * + * Inputs Description + * ------------------------------------------------------------------- + * void *aecmInst Pointer to the AECM instance + * WebRtc_Word16 *farend In buffer containing one frame of + * farend signal + * WebRtc_Word16 nrOfSamples Number of samples in farend buffer + * + * Outputs Description + * ------------------------------------------------------------------- + * WebRtc_Word32 return 0: OK + * -1: error + */ +WebRtc_Word32 WebRtcAecm_BufferFarend(void* aecmInst, + const WebRtc_Word16* farend, + WebRtc_Word16 nrOfSamples); + +/* + * Runs the AECM on an 80 or 160 sample blocks of data. + * + * Inputs Description + * ------------------------------------------------------------------- + * void *aecmInst Pointer to the AECM instance + * WebRtc_Word16 *nearendNoisy In buffer containing one frame of + * reference nearend+echo signal. If + * noise reduction is active, provide + * the noisy signal here. + * WebRtc_Word16 *nearendClean In buffer containing one frame of + * nearend+echo signal. If noise + * reduction is active, provide the + * clean signal here. Otherwise pass a + * NULL pointer. + * WebRtc_Word16 nrOfSamples Number of samples in nearend buffer + * WebRtc_Word16 msInSndCardBuf Delay estimate for sound card and + * system buffers + * + * Outputs Description + * ------------------------------------------------------------------- + * WebRtc_Word16 *out Out buffer, one frame of processed nearend + * WebRtc_Word32 return 0: OK + * -1: error + */ +WebRtc_Word32 WebRtcAecm_Process(void* aecmInst, + const WebRtc_Word16* nearendNoisy, + const WebRtc_Word16* nearendClean, + WebRtc_Word16* out, + WebRtc_Word16 nrOfSamples, + WebRtc_Word16 msInSndCardBuf); + +/* + * This function enables the user to set certain parameters on-the-fly + * + * Inputs Description + * ------------------------------------------------------------------- + * void *aecmInst Pointer to the AECM instance + * AecmConfig config Config instance that contains all + * properties to be set + * + * Outputs Description + * ------------------------------------------------------------------- + * WebRtc_Word32 return 0: OK + * -1: error + */ +WebRtc_Word32 WebRtcAecm_set_config(void* aecmInst, + AecmConfig config); + +/* + * This function enables the user to set certain parameters on-the-fly + * + * Inputs Description + * ------------------------------------------------------------------- + * void *aecmInst Pointer to the AECM instance + * + * Outputs Description + * ------------------------------------------------------------------- + * AecmConfig *config Pointer to the config instance that + * all properties will be written to + * WebRtc_Word32 return 0: OK + * -1: error + */ +WebRtc_Word32 WebRtcAecm_get_config(void *aecmInst, + AecmConfig *config); + +/* + * This function enables the user to set the echo path on-the-fly. + * + * Inputs Description + * ------------------------------------------------------------------- + * void* aecmInst Pointer to the AECM instance + * void* echo_path Pointer to the echo path to be set + * size_t size_bytes Size in bytes of the echo path + * + * Outputs Description + * ------------------------------------------------------------------- + * WebRtc_Word32 return 0: OK + * -1: error + */ +WebRtc_Word32 WebRtcAecm_InitEchoPath(void* aecmInst, + const void* echo_path, + size_t size_bytes); + +/* + * This function enables the user to get the currently used echo path + * on-the-fly + * + * Inputs Description + * ------------------------------------------------------------------- + * void* aecmInst Pointer to the AECM instance + * void* echo_path Pointer to echo path + * size_t size_bytes Size in bytes of the echo path + * + * Outputs Description + * ------------------------------------------------------------------- + * WebRtc_Word32 return 0: OK + * -1: error + */ +WebRtc_Word32 WebRtcAecm_GetEchoPath(void* aecmInst, + void* echo_path, + size_t size_bytes); + +/* + * This function enables the user to get the echo path size in bytes + * + * Outputs Description + * ------------------------------------------------------------------- + * size_t return : size in bytes + */ +size_t WebRtcAecm_echo_path_size_bytes(); + +/* + * Gets the last error code. + * + * Inputs Description + * ------------------------------------------------------------------- + * void *aecmInst Pointer to the AECM instance + * + * Outputs Description + * ------------------------------------------------------------------- + * WebRtc_Word32 return 11000-11100: error code + */ +WebRtc_Word32 WebRtcAecm_get_error_code(void *aecmInst); + +#ifdef __cplusplus +} +#endif +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AECM_INCLUDE_ECHO_CONTROL_MOBILE_H_ diff --git a/libs/miniwebrtc/audio/processing/agc/analog_agc.c b/libs/miniwebrtc/audio/processing/agc/analog_agc.c new file mode 100644 index 00000000..558a6cba --- /dev/null +++ b/libs/miniwebrtc/audio/processing/agc/analog_agc.c @@ -0,0 +1,1694 @@ +/* + * 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. + */ + +/* analog_agc.c + * + * Using a feedback system, determines an appropriate analog volume level + * given an input signal and current volume level. Targets a conservative + * signal level and is intended for use with a digital AGC to apply + * additional gain. + * + */ + +#include +#include +#ifdef AGC_DEBUG //test log +#include +#endif +#include "analog_agc.h" + +/* The slope of in Q13*/ +static const WebRtc_Word16 kSlope1[8] = {21793, 12517, 7189, 4129, 2372, 1362, 472, 78}; + +/* The offset in Q14 */ +static const WebRtc_Word16 kOffset1[8] = {25395, 23911, 22206, 20737, 19612, 18805, 17951, + 17367}; + +/* The slope of in Q13*/ +static const WebRtc_Word16 kSlope2[8] = {2063, 1731, 1452, 1218, 1021, 857, 597, 337}; + +/* The offset in Q14 */ +static const WebRtc_Word16 kOffset2[8] = {18432, 18379, 18290, 18177, 18052, 17920, 17670, + 17286}; + +static const WebRtc_Word16 kMuteGuardTimeMs = 8000; +static const WebRtc_Word16 kInitCheck = 42; + +/* Default settings if config is not used */ +#define AGC_DEFAULT_TARGET_LEVEL 3 +#define AGC_DEFAULT_COMP_GAIN 9 +/* This is the target level for the analog part in ENV scale. To convert to RMS scale you + * have to add OFFSET_ENV_TO_RMS. + */ +#define ANALOG_TARGET_LEVEL 11 +#define ANALOG_TARGET_LEVEL_2 5 // ANALOG_TARGET_LEVEL / 2 +/* Offset between RMS scale (analog part) and ENV scale (digital part). This value actually + * varies with the FIXED_ANALOG_TARGET_LEVEL, hence we should in the future replace it with + * a table. + */ +#define OFFSET_ENV_TO_RMS 9 +/* The reference input level at which the digital part gives an output of targetLevelDbfs + * (desired level) if we have no compression gain. This level should be set high enough not + * to compress the peaks due to the dynamics. + */ +#define DIGITAL_REF_AT_0_COMP_GAIN 4 +/* Speed of reference level decrease. + */ +#define DIFF_REF_TO_ANALOG 5 + +#ifdef MIC_LEVEL_FEEDBACK +#define NUM_BLOCKS_IN_SAT_BEFORE_CHANGE_TARGET 7 +#endif +/* Size of analog gain table */ +#define GAIN_TBL_LEN 32 +/* Matlab code: + * fprintf(1, '\t%i, %i, %i, %i,\n', round(10.^(linspace(0,10,32)/20) * 2^12)); + */ +/* Q12 */ +static const WebRtc_UWord16 kGainTableAnalog[GAIN_TBL_LEN] = {4096, 4251, 4412, 4579, 4752, + 4932, 5118, 5312, 5513, 5722, 5938, 6163, 6396, 6638, 6889, 7150, 7420, 7701, 7992, + 8295, 8609, 8934, 9273, 9623, 9987, 10365, 10758, 11165, 11587, 12025, 12480, 12953}; + +/* Gain/Suppression tables for virtual Mic (in Q10) */ +static const WebRtc_UWord16 kGainTableVirtualMic[128] = {1052, 1081, 1110, 1141, 1172, 1204, + 1237, 1271, 1305, 1341, 1378, 1416, 1454, 1494, 1535, 1577, 1620, 1664, 1710, 1757, + 1805, 1854, 1905, 1957, 2010, 2065, 2122, 2180, 2239, 2301, 2364, 2428, 2495, 2563, + 2633, 2705, 2779, 2855, 2933, 3013, 3096, 3180, 3267, 3357, 3449, 3543, 3640, 3739, + 3842, 3947, 4055, 4166, 4280, 4397, 4517, 4640, 4767, 4898, 5032, 5169, 5311, 5456, + 5605, 5758, 5916, 6078, 6244, 6415, 6590, 6770, 6956, 7146, 7341, 7542, 7748, 7960, + 8178, 8402, 8631, 8867, 9110, 9359, 9615, 9878, 10148, 10426, 10711, 11004, 11305, + 11614, 11932, 12258, 12593, 12938, 13292, 13655, 14029, 14412, 14807, 15212, 15628, + 16055, 16494, 16945, 17409, 17885, 18374, 18877, 19393, 19923, 20468, 21028, 21603, + 22194, 22801, 23425, 24065, 24724, 25400, 26095, 26808, 27541, 28295, 29069, 29864, + 30681, 31520, 32382}; +static const WebRtc_UWord16 kSuppressionTableVirtualMic[128] = {1024, 1006, 988, 970, 952, + 935, 918, 902, 886, 870, 854, 839, 824, 809, 794, 780, 766, 752, 739, 726, 713, 700, + 687, 675, 663, 651, 639, 628, 616, 605, 594, 584, 573, 563, 553, 543, 533, 524, 514, + 505, 496, 487, 478, 470, 461, 453, 445, 437, 429, 421, 414, 406, 399, 392, 385, 378, + 371, 364, 358, 351, 345, 339, 333, 327, 321, 315, 309, 304, 298, 293, 288, 283, 278, + 273, 268, 263, 258, 254, 249, 244, 240, 236, 232, 227, 223, 219, 215, 211, 208, 204, + 200, 197, 193, 190, 186, 183, 180, 176, 173, 170, 167, 164, 161, 158, 155, 153, 150, + 147, 145, 142, 139, 137, 134, 132, 130, 127, 125, 123, 121, 118, 116, 114, 112, 110, + 108, 106, 104, 102}; + +/* Table for target energy levels. Values in Q(-7) + * Matlab code + * targetLevelTable = fprintf('%d,\t%d,\t%d,\t%d,\n', round((32767*10.^(-(0:63)'/20)).^2*16/2^7) */ + +static const WebRtc_Word32 kTargetLevelTable[64] = {134209536, 106606424, 84680493, 67264106, + 53429779, 42440782, 33711911, 26778323, 21270778, 16895980, 13420954, 10660642, + 8468049, 6726411, 5342978, 4244078, 3371191, 2677832, 2127078, 1689598, 1342095, + 1066064, 846805, 672641, 534298, 424408, 337119, 267783, 212708, 168960, 134210, + 106606, 84680, 67264, 53430, 42441, 33712, 26778, 21271, 16896, 13421, 10661, 8468, + 6726, 5343, 4244, 3371, 2678, 2127, 1690, 1342, 1066, 847, 673, 534, 424, 337, 268, + 213, 169, 134, 107, 85, 67}; + +int WebRtcAgc_AddMic(void *state, WebRtc_Word16 *in_mic, WebRtc_Word16 *in_mic_H, + WebRtc_Word16 samples) +{ + WebRtc_Word32 nrg, max_nrg, sample, tmp32; + WebRtc_Word32 *ptr; + WebRtc_UWord16 targetGainIdx, gain; + WebRtc_Word16 i, n, L, M, subFrames, tmp16, tmp_speech[16]; + Agc_t *stt; + stt = (Agc_t *)state; + + //default/initial values corresponding to 10ms for wb and swb + M = 10; + L = 16; + subFrames = 160; + + if (stt->fs == 8000) + { + if (samples == 80) + { + subFrames = 80; + M = 10; + L = 8; + } else if (samples == 160) + { + subFrames = 80; + M = 20; + L = 8; + } else + { +#ifdef AGC_DEBUG //test log + fprintf(stt->fpt, + "AGC->add_mic, frame %d: Invalid number of samples\n\n", + (stt->fcount + 1)); +#endif + return -1; + } + } else if (stt->fs == 16000) + { + if (samples == 160) + { + subFrames = 160; + M = 10; + L = 16; + } else if (samples == 320) + { + subFrames = 160; + M = 20; + L = 16; + } else + { +#ifdef AGC_DEBUG //test log + fprintf(stt->fpt, + "AGC->add_mic, frame %d: Invalid number of samples\n\n", + (stt->fcount + 1)); +#endif + return -1; + } + } else if (stt->fs == 32000) + { + /* SWB is processed as 160 sample for L and H bands */ + if (samples == 160) + { + subFrames = 160; + M = 10; + L = 16; + } else + { +#ifdef AGC_DEBUG + fprintf(stt->fpt, + "AGC->add_mic, frame %d: Invalid sample rate\n\n", + (stt->fcount + 1)); +#endif + return -1; + } + } + + /* Check for valid pointers based on sampling rate */ + if ((stt->fs == 32000) && (in_mic_H == NULL)) + { + return -1; + } + /* Check for valid pointer for low band */ + if (in_mic == NULL) + { + return -1; + } + + /* apply slowly varying digital gain */ + if (stt->micVol > stt->maxAnalog) + { + /* |maxLevel| is strictly >= |micVol|, so this condition should be + * satisfied here, ensuring there is no divide-by-zero. */ + assert(stt->maxLevel > stt->maxAnalog); + + /* Q1 */ + tmp16 = (WebRtc_Word16)(stt->micVol - stt->maxAnalog); + tmp32 = WEBRTC_SPL_MUL_16_16(GAIN_TBL_LEN - 1, tmp16); + tmp16 = (WebRtc_Word16)(stt->maxLevel - stt->maxAnalog); + targetGainIdx = (WebRtc_UWord16)WEBRTC_SPL_DIV(tmp32, tmp16); + assert(targetGainIdx < GAIN_TBL_LEN); + + /* Increment through the table towards the target gain. + * If micVol drops below maxAnalog, we allow the gain + * to be dropped immediately. */ + if (stt->gainTableIdx < targetGainIdx) + { + stt->gainTableIdx++; + } else if (stt->gainTableIdx > targetGainIdx) + { + stt->gainTableIdx--; + } + + /* Q12 */ + gain = kGainTableAnalog[stt->gainTableIdx]; + + for (i = 0; i < samples; i++) + { + // For lower band + tmp32 = WEBRTC_SPL_MUL_16_U16(in_mic[i], gain); + sample = WEBRTC_SPL_RSHIFT_W32(tmp32, 12); + if (sample > 32767) + { + in_mic[i] = 32767; + } else if (sample < -32768) + { + in_mic[i] = -32768; + } else + { + in_mic[i] = (WebRtc_Word16)sample; + } + + // For higher band + if (stt->fs == 32000) + { + tmp32 = WEBRTC_SPL_MUL_16_U16(in_mic_H[i], gain); + sample = WEBRTC_SPL_RSHIFT_W32(tmp32, 12); + if (sample > 32767) + { + in_mic_H[i] = 32767; + } else if (sample < -32768) + { + in_mic_H[i] = -32768; + } else + { + in_mic_H[i] = (WebRtc_Word16)sample; + } + } + } + } else + { + stt->gainTableIdx = 0; + } + + /* compute envelope */ + if ((M == 10) && (stt->inQueue > 0)) + { + ptr = stt->env[1]; + } else + { + ptr = stt->env[0]; + } + + for (i = 0; i < M; i++) + { + /* iterate over samples */ + max_nrg = 0; + for (n = 0; n < L; n++) + { + nrg = WEBRTC_SPL_MUL_16_16(in_mic[i * L + n], in_mic[i * L + n]); + if (nrg > max_nrg) + { + max_nrg = nrg; + } + } + ptr[i] = max_nrg; + } + + /* compute energy */ + if ((M == 10) && (stt->inQueue > 0)) + { + ptr = stt->Rxx16w32_array[1]; + } else + { + ptr = stt->Rxx16w32_array[0]; + } + + for (i = 0; i < WEBRTC_SPL_RSHIFT_W16(M, 1); i++) + { + if (stt->fs == 16000) + { + WebRtcSpl_DownsampleBy2(&in_mic[i * 32], 32, tmp_speech, stt->filterState); + } else + { + memcpy(tmp_speech, &in_mic[i * 16], 16 * sizeof(short)); + } + /* Compute energy in blocks of 16 samples */ + ptr[i] = WebRtcSpl_DotProductWithScale(tmp_speech, tmp_speech, 16, 4); + } + + /* update queue information */ + if ((stt->inQueue == 0) && (M == 10)) + { + stt->inQueue = 1; + } else + { + stt->inQueue = 2; + } + + /* call VAD (use low band only) */ + for (i = 0; i < samples; i += subFrames) + { + WebRtcAgc_ProcessVad(&stt->vadMic, &in_mic[i], subFrames); + } + + return 0; +} + +int WebRtcAgc_AddFarend(void *state, const WebRtc_Word16 *in_far, WebRtc_Word16 samples) +{ + WebRtc_Word32 errHandle = 0; + WebRtc_Word16 i, subFrames; + Agc_t *stt; + stt = (Agc_t *)state; + + if (stt == NULL) + { + return -1; + } + + if (stt->fs == 8000) + { + if ((samples != 80) && (samples != 160)) + { +#ifdef AGC_DEBUG //test log + fprintf(stt->fpt, + "AGC->add_far_end, frame %d: Invalid number of samples\n\n", + stt->fcount); +#endif + return -1; + } + subFrames = 80; + } else if (stt->fs == 16000) + { + if ((samples != 160) && (samples != 320)) + { +#ifdef AGC_DEBUG //test log + fprintf(stt->fpt, + "AGC->add_far_end, frame %d: Invalid number of samples\n\n", + stt->fcount); +#endif + return -1; + } + subFrames = 160; + } else if (stt->fs == 32000) + { + if ((samples != 160) && (samples != 320)) + { +#ifdef AGC_DEBUG //test log + fprintf(stt->fpt, + "AGC->add_far_end, frame %d: Invalid number of samples\n\n", + stt->fcount); +#endif + return -1; + } + subFrames = 160; + } else + { +#ifdef AGC_DEBUG //test log + fprintf(stt->fpt, + "AGC->add_far_end, frame %d: Invalid sample rate\n\n", + stt->fcount + 1); +#endif + return -1; + } + + for (i = 0; i < samples; i += subFrames) + { + errHandle += WebRtcAgc_AddFarendToDigital(&stt->digitalAgc, &in_far[i], subFrames); + } + + return errHandle; +} + +int WebRtcAgc_VirtualMic(void *agcInst, WebRtc_Word16 *in_near, WebRtc_Word16 *in_near_H, + WebRtc_Word16 samples, WebRtc_Word32 micLevelIn, + WebRtc_Word32 *micLevelOut) +{ + WebRtc_Word32 tmpFlt, micLevelTmp, gainIdx; + WebRtc_UWord16 gain; + WebRtc_Word16 ii; + Agc_t *stt; + + WebRtc_UWord32 nrg; + WebRtc_Word16 sampleCntr; + WebRtc_UWord32 frameNrg = 0; + WebRtc_UWord32 frameNrgLimit = 5500; + WebRtc_Word16 numZeroCrossing = 0; + const WebRtc_Word16 kZeroCrossingLowLim = 15; + const WebRtc_Word16 kZeroCrossingHighLim = 20; + + stt = (Agc_t *)agcInst; + + /* + * Before applying gain decide if this is a low-level signal. + * The idea is that digital AGC will not adapt to low-level + * signals. + */ + if (stt->fs != 8000) + { + frameNrgLimit = frameNrgLimit << 1; + } + + frameNrg = WEBRTC_SPL_MUL_16_16(in_near[0], in_near[0]); + for (sampleCntr = 1; sampleCntr < samples; sampleCntr++) + { + + // increment frame energy if it is less than the limit + // the correct value of the energy is not important + if (frameNrg < frameNrgLimit) + { + nrg = WEBRTC_SPL_MUL_16_16(in_near[sampleCntr], in_near[sampleCntr]); + frameNrg += nrg; + } + + // Count the zero crossings + numZeroCrossing += ((in_near[sampleCntr] ^ in_near[sampleCntr - 1]) < 0); + } + + if ((frameNrg < 500) || (numZeroCrossing <= 5)) + { + stt->lowLevelSignal = 1; + } else if (numZeroCrossing <= kZeroCrossingLowLim) + { + stt->lowLevelSignal = 0; + } else if (frameNrg <= frameNrgLimit) + { + stt->lowLevelSignal = 1; + } else if (numZeroCrossing >= kZeroCrossingHighLim) + { + stt->lowLevelSignal = 1; + } else + { + stt->lowLevelSignal = 0; + } + + micLevelTmp = WEBRTC_SPL_LSHIFT_W32(micLevelIn, stt->scale); + /* Set desired level */ + gainIdx = stt->micVol; + if (stt->micVol > stt->maxAnalog) + { + gainIdx = stt->maxAnalog; + } + if (micLevelTmp != stt->micRef) + { + /* Something has happened with the physical level, restart. */ + stt->micRef = micLevelTmp; + stt->micVol = 127; + *micLevelOut = 127; + stt->micGainIdx = 127; + gainIdx = 127; + } + /* Pre-process the signal to emulate the microphone level. */ + /* Take one step at a time in the gain table. */ + if (gainIdx > 127) + { + gain = kGainTableVirtualMic[gainIdx - 128]; + } else + { + gain = kSuppressionTableVirtualMic[127 - gainIdx]; + } + for (ii = 0; ii < samples; ii++) + { + tmpFlt = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_U16(in_near[ii], gain), 10); + if (tmpFlt > 32767) + { + tmpFlt = 32767; + gainIdx--; + if (gainIdx >= 127) + { + gain = kGainTableVirtualMic[gainIdx - 127]; + } else + { + gain = kSuppressionTableVirtualMic[127 - gainIdx]; + } + } + if (tmpFlt < -32768) + { + tmpFlt = -32768; + gainIdx--; + if (gainIdx >= 127) + { + gain = kGainTableVirtualMic[gainIdx - 127]; + } else + { + gain = kSuppressionTableVirtualMic[127 - gainIdx]; + } + } + in_near[ii] = (WebRtc_Word16)tmpFlt; + if (stt->fs == 32000) + { + tmpFlt = WEBRTC_SPL_MUL_16_U16(in_near_H[ii], gain); + tmpFlt = WEBRTC_SPL_RSHIFT_W32(tmpFlt, 10); + if (tmpFlt > 32767) + { + tmpFlt = 32767; + } + if (tmpFlt < -32768) + { + tmpFlt = -32768; + } + in_near_H[ii] = (WebRtc_Word16)tmpFlt; + } + } + /* Set the level we (finally) used */ + stt->micGainIdx = gainIdx; +// *micLevelOut = stt->micGainIdx; + *micLevelOut = WEBRTC_SPL_RSHIFT_W32(stt->micGainIdx, stt->scale); + /* Add to Mic as if it was the output from a true microphone */ + if (WebRtcAgc_AddMic(agcInst, in_near, in_near_H, samples) != 0) + { + return -1; + } + return 0; +} + +void WebRtcAgc_UpdateAgcThresholds(Agc_t *stt) +{ + + WebRtc_Word16 tmp16; +#ifdef MIC_LEVEL_FEEDBACK + int zeros; + + if (stt->micLvlSat) + { + /* Lower the analog target level since we have reached its maximum */ + zeros = WebRtcSpl_NormW32(stt->Rxx160_LPw32); + stt->targetIdxOffset = WEBRTC_SPL_RSHIFT_W16((3 * zeros) - stt->targetIdx - 2, 2); + } +#endif + + /* Set analog target level in envelope dBOv scale */ + tmp16 = (DIFF_REF_TO_ANALOG * stt->compressionGaindB) + ANALOG_TARGET_LEVEL_2; + tmp16 = WebRtcSpl_DivW32W16ResW16((WebRtc_Word32)tmp16, ANALOG_TARGET_LEVEL); + stt->analogTarget = DIGITAL_REF_AT_0_COMP_GAIN + tmp16; + if (stt->analogTarget < DIGITAL_REF_AT_0_COMP_GAIN) + { + stt->analogTarget = DIGITAL_REF_AT_0_COMP_GAIN; + } + if (stt->agcMode == kAgcModeFixedDigital) + { + /* Adjust for different parameter interpretation in FixedDigital mode */ + stt->analogTarget = stt->compressionGaindB; + } +#ifdef MIC_LEVEL_FEEDBACK + stt->analogTarget += stt->targetIdxOffset; +#endif + /* Since the offset between RMS and ENV is not constant, we should make this into a + * table, but for now, we'll stick with a constant, tuned for the chosen analog + * target level. + */ + stt->targetIdx = ANALOG_TARGET_LEVEL + OFFSET_ENV_TO_RMS; +#ifdef MIC_LEVEL_FEEDBACK + stt->targetIdx += stt->targetIdxOffset; +#endif + /* Analog adaptation limits */ + /* analogTargetLevel = round((32767*10^(-targetIdx/20))^2*16/2^7) */ + stt->analogTargetLevel = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx]; /* ex. -20 dBov */ + stt->startUpperLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 1];/* -19 dBov */ + stt->startLowerLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 1];/* -21 dBov */ + stt->upperPrimaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 2];/* -18 dBov */ + stt->lowerPrimaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 2];/* -22 dBov */ + stt->upperSecondaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx - 5];/* -15 dBov */ + stt->lowerSecondaryLimit = RXX_BUFFER_LEN * kTargetLevelTable[stt->targetIdx + 5];/* -25 dBov */ + stt->upperLimit = stt->startUpperLimit; + stt->lowerLimit = stt->startLowerLimit; +} + +void WebRtcAgc_SaturationCtrl(Agc_t *stt, WebRtc_UWord8 *saturated, WebRtc_Word32 *env) +{ + WebRtc_Word16 i, tmpW16; + + /* Check if the signal is saturated */ + for (i = 0; i < 10; i++) + { + tmpW16 = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(env[i], 20); + if (tmpW16 > 875) + { + stt->envSum += tmpW16; + } + } + + if (stt->envSum > 25000) + { + *saturated = 1; + stt->envSum = 0; + } + + /* stt->envSum *= 0.99; */ + stt->envSum = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(stt->envSum, + (WebRtc_Word16)32440, 15); +} + +void WebRtcAgc_ZeroCtrl(Agc_t *stt, WebRtc_Word32 *inMicLevel, WebRtc_Word32 *env) +{ + WebRtc_Word16 i; + WebRtc_Word32 tmp32 = 0; + WebRtc_Word32 midVal; + + /* Is the input signal zero? */ + for (i = 0; i < 10; i++) + { + tmp32 += env[i]; + } + + /* Each block is allowed to have a few non-zero + * samples. + */ + if (tmp32 < 500) + { + stt->msZero += 10; + } else + { + stt->msZero = 0; + } + + if (stt->muteGuardMs > 0) + { + stt->muteGuardMs -= 10; + } + + if (stt->msZero > 500) + { + stt->msZero = 0; + + /* Increase microphone level only if it's less than 50% */ + midVal = WEBRTC_SPL_RSHIFT_W32(stt->maxAnalog + stt->minLevel + 1, 1); + if (*inMicLevel < midVal) + { + /* *inMicLevel *= 1.1; */ + tmp32 = WEBRTC_SPL_MUL(1126, *inMicLevel); + *inMicLevel = WEBRTC_SPL_RSHIFT_W32(tmp32, 10); + /* Reduces risk of a muted mic repeatedly triggering excessive levels due + * to zero signal detection. */ + *inMicLevel = WEBRTC_SPL_MIN(*inMicLevel, stt->zeroCtrlMax); + stt->micVol = *inMicLevel; + } + +#ifdef AGC_DEBUG //test log + fprintf(stt->fpt, + "\t\tAGC->zeroCntrl, frame %d: 500 ms under threshold, micVol:\n", + stt->fcount, stt->micVol); +#endif + + stt->activeSpeech = 0; + stt->Rxx16_LPw32Max = 0; + + /* The AGC has a tendency (due to problems with the VAD parameters), to + * vastly increase the volume after a muting event. This timer prevents + * upwards adaptation for a short period. */ + stt->muteGuardMs = kMuteGuardTimeMs; + } +} + +void WebRtcAgc_SpeakerInactiveCtrl(Agc_t *stt) +{ + /* Check if the near end speaker is inactive. + * If that is the case the VAD threshold is + * increased since the VAD speech model gets + * more sensitive to any sound after a long + * silence. + */ + + WebRtc_Word32 tmp32; + WebRtc_Word16 vadThresh; + + if (stt->vadMic.stdLongTerm < 2500) + { + stt->vadThreshold = 1500; + } else + { + vadThresh = kNormalVadThreshold; + if (stt->vadMic.stdLongTerm < 4500) + { + /* Scale between min and max threshold */ + vadThresh += WEBRTC_SPL_RSHIFT_W16(4500 - stt->vadMic.stdLongTerm, 1); + } + + /* stt->vadThreshold = (31 * stt->vadThreshold + vadThresh) / 32; */ + tmp32 = (WebRtc_Word32)vadThresh; + tmp32 += WEBRTC_SPL_MUL_16_16((WebRtc_Word16)31, stt->vadThreshold); + stt->vadThreshold = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32, 5); + } +} + +void WebRtcAgc_ExpCurve(WebRtc_Word16 volume, WebRtc_Word16 *index) +{ + // volume in Q14 + // index in [0-7] + /* 8 different curves */ + if (volume > 5243) + { + if (volume > 7864) + { + if (volume > 12124) + { + *index = 7; + } else + { + *index = 6; + } + } else + { + if (volume > 6554) + { + *index = 5; + } else + { + *index = 4; + } + } + } else + { + if (volume > 2621) + { + if (volume > 3932) + { + *index = 3; + } else + { + *index = 2; + } + } else + { + if (volume > 1311) + { + *index = 1; + } else + { + *index = 0; + } + } + } +} + +WebRtc_Word32 WebRtcAgc_ProcessAnalog(void *state, WebRtc_Word32 inMicLevel, + WebRtc_Word32 *outMicLevel, + WebRtc_Word16 vadLogRatio, + WebRtc_Word16 echo, WebRtc_UWord8 *saturationWarning) +{ + WebRtc_UWord32 tmpU32; + WebRtc_Word32 Rxx16w32, tmp32; + WebRtc_Word32 inMicLevelTmp, lastMicVol; + WebRtc_Word16 i; + WebRtc_UWord8 saturated = 0; + Agc_t *stt; + + stt = (Agc_t *)state; + inMicLevelTmp = WEBRTC_SPL_LSHIFT_W32(inMicLevel, stt->scale); + + if (inMicLevelTmp > stt->maxAnalog) + { +#ifdef AGC_DEBUG //test log + fprintf(stt->fpt, "\tAGC->ProcessAnalog, frame %d: micLvl > maxAnalog\n", stt->fcount); +#endif + return -1; + } else if (inMicLevelTmp < stt->minLevel) + { +#ifdef AGC_DEBUG //test log + fprintf(stt->fpt, "\tAGC->ProcessAnalog, frame %d: micLvl < minLevel\n", stt->fcount); +#endif + return -1; + } + + if (stt->firstCall == 0) + { + WebRtc_Word32 tmpVol; + stt->firstCall = 1; + tmp32 = WEBRTC_SPL_RSHIFT_W32((stt->maxLevel - stt->minLevel) * (WebRtc_Word32)51, 9); + tmpVol = (stt->minLevel + tmp32); + + /* If the mic level is very low at start, increase it! */ + if ((inMicLevelTmp < tmpVol) && (stt->agcMode == kAgcModeAdaptiveAnalog)) + { + inMicLevelTmp = tmpVol; + } + stt->micVol = inMicLevelTmp; + } + + /* Set the mic level to the previous output value if there is digital input gain */ + if ((inMicLevelTmp == stt->maxAnalog) && (stt->micVol > stt->maxAnalog)) + { + inMicLevelTmp = stt->micVol; + } + + /* If the mic level was manually changed to a very low value raise it! */ + if ((inMicLevelTmp != stt->micVol) && (inMicLevelTmp < stt->minOutput)) + { + tmp32 = WEBRTC_SPL_RSHIFT_W32((stt->maxLevel - stt->minLevel) * (WebRtc_Word32)51, 9); + inMicLevelTmp = (stt->minLevel + tmp32); + stt->micVol = inMicLevelTmp; +#ifdef MIC_LEVEL_FEEDBACK + //stt->numBlocksMicLvlSat = 0; +#endif +#ifdef AGC_DEBUG //test log + fprintf(stt->fpt, + "\tAGC->ProcessAnalog, frame %d: micLvl < minLevel by manual decrease, raise vol\n", + stt->fcount); +#endif + } + + if (inMicLevelTmp != stt->micVol) + { + // Incoming level mismatch; update our level. + // This could be the case if the volume is changed manually, or if the + // sound device has a low volume resolution. + stt->micVol = inMicLevelTmp; + } + + if (inMicLevelTmp > stt->maxLevel) + { + // Always allow the user to raise the volume above the maxLevel. + stt->maxLevel = inMicLevelTmp; + } + + // Store last value here, after we've taken care of manual updates etc. + lastMicVol = stt->micVol; + + /* Checks if the signal is saturated. Also a check if individual samples + * are larger than 12000 is done. If they are the counter for increasing + * the volume level is set to -100ms + */ + WebRtcAgc_SaturationCtrl(stt, &saturated, stt->env[0]); + + /* The AGC is always allowed to lower the level if the signal is saturated */ + if (saturated == 1) + { + /* Lower the recording level + * Rxx160_LP is adjusted down because it is so slow it could + * cause the AGC to make wrong decisions. */ + /* stt->Rxx160_LPw32 *= 0.875; */ + stt->Rxx160_LPw32 = WEBRTC_SPL_MUL(WEBRTC_SPL_RSHIFT_W32(stt->Rxx160_LPw32, 3), 7); + + stt->zeroCtrlMax = stt->micVol; + + /* stt->micVol *= 0.903; */ + tmp32 = inMicLevelTmp - stt->minLevel; + tmpU32 = WEBRTC_SPL_UMUL(29591, (WebRtc_UWord32)(tmp32)); + stt->micVol = (WebRtc_Word32)WEBRTC_SPL_RSHIFT_U32(tmpU32, 15) + stt->minLevel; + if (stt->micVol > lastMicVol - 2) + { + stt->micVol = lastMicVol - 2; + } + inMicLevelTmp = stt->micVol; + +#ifdef AGC_DEBUG //test log + fprintf(stt->fpt, + "\tAGC->ProcessAnalog, frame %d: saturated, micVol = %d\n", + stt->fcount, stt->micVol); +#endif + + if (stt->micVol < stt->minOutput) + { + *saturationWarning = 1; + } + + /* Reset counter for decrease of volume level to avoid + * decreasing too much. The saturation control can still + * lower the level if needed. */ + stt->msTooHigh = -100; + + /* Enable the control mechanism to ensure that our measure, + * Rxx160_LP, is in the correct range. This must be done since + * the measure is very slow. */ + stt->activeSpeech = 0; + stt->Rxx16_LPw32Max = 0; + + /* Reset to initial values */ + stt->msecSpeechInnerChange = kMsecSpeechInner; + stt->msecSpeechOuterChange = kMsecSpeechOuter; + stt->changeToSlowMode = 0; + + stt->muteGuardMs = 0; + + stt->upperLimit = stt->startUpperLimit; + stt->lowerLimit = stt->startLowerLimit; +#ifdef MIC_LEVEL_FEEDBACK + //stt->numBlocksMicLvlSat = 0; +#endif + } + + /* Check if the input speech is zero. If so the mic volume + * is increased. On some computers the input is zero up as high + * level as 17% */ + WebRtcAgc_ZeroCtrl(stt, &inMicLevelTmp, stt->env[0]); + + /* Check if the near end speaker is inactive. + * If that is the case the VAD threshold is + * increased since the VAD speech model gets + * more sensitive to any sound after a long + * silence. + */ + WebRtcAgc_SpeakerInactiveCtrl(stt); + + for (i = 0; i < 5; i++) + { + /* Computed on blocks of 16 samples */ + + Rxx16w32 = stt->Rxx16w32_array[0][i]; + + /* Rxx160w32 in Q(-7) */ + tmp32 = WEBRTC_SPL_RSHIFT_W32(Rxx16w32 - stt->Rxx16_vectorw32[stt->Rxx16pos], 3); + stt->Rxx160w32 = stt->Rxx160w32 + tmp32; + stt->Rxx16_vectorw32[stt->Rxx16pos] = Rxx16w32; + + /* Circular buffer */ + stt->Rxx16pos++; + if (stt->Rxx16pos == RXX_BUFFER_LEN) + { + stt->Rxx16pos = 0; + } + + /* Rxx16_LPw32 in Q(-4) */ + tmp32 = WEBRTC_SPL_RSHIFT_W32(Rxx16w32 - stt->Rxx16_LPw32, kAlphaShortTerm); + stt->Rxx16_LPw32 = (stt->Rxx16_LPw32) + tmp32; + + if (vadLogRatio > stt->vadThreshold) + { + /* Speech detected! */ + + /* Check if Rxx160_LP is in the correct range. If + * it is too high/low then we set it to the maximum of + * Rxx16_LPw32 during the first 200ms of speech. + */ + if (stt->activeSpeech < 250) + { + stt->activeSpeech += 2; + + if (stt->Rxx16_LPw32 > stt->Rxx16_LPw32Max) + { + stt->Rxx16_LPw32Max = stt->Rxx16_LPw32; + } + } else if (stt->activeSpeech == 250) + { + stt->activeSpeech += 2; + tmp32 = WEBRTC_SPL_RSHIFT_W32(stt->Rxx16_LPw32Max, 3); + stt->Rxx160_LPw32 = WEBRTC_SPL_MUL(tmp32, RXX_BUFFER_LEN); + } + + tmp32 = WEBRTC_SPL_RSHIFT_W32(stt->Rxx160w32 - stt->Rxx160_LPw32, kAlphaLongTerm); + stt->Rxx160_LPw32 = stt->Rxx160_LPw32 + tmp32; + + if (stt->Rxx160_LPw32 > stt->upperSecondaryLimit) + { + stt->msTooHigh += 2; + stt->msTooLow = 0; + stt->changeToSlowMode = 0; + + if (stt->msTooHigh > stt->msecSpeechOuterChange) + { + stt->msTooHigh = 0; + + /* Lower the recording level */ + /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */ + tmp32 = WEBRTC_SPL_RSHIFT_W32(stt->Rxx160_LPw32, 6); + stt->Rxx160_LPw32 = WEBRTC_SPL_MUL(tmp32, 53); + + /* Reduce the max gain to avoid excessive oscillation + * (but never drop below the maximum analog level). + * stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16; + */ + tmp32 = (15 * stt->maxLevel) + stt->micVol; + stt->maxLevel = WEBRTC_SPL_RSHIFT_W32(tmp32, 4); + stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog); + + stt->zeroCtrlMax = stt->micVol; + + /* 0.95 in Q15 */ + tmp32 = inMicLevelTmp - stt->minLevel; + tmpU32 = WEBRTC_SPL_UMUL(31130, (WebRtc_UWord32)(tmp32)); + stt->micVol = (WebRtc_Word32)WEBRTC_SPL_RSHIFT_U32(tmpU32, 15) + stt->minLevel; + if (stt->micVol > lastMicVol - 1) + { + stt->micVol = lastMicVol - 1; + } + inMicLevelTmp = stt->micVol; + + /* Enable the control mechanism to ensure that our measure, + * Rxx160_LP, is in the correct range. + */ + stt->activeSpeech = 0; + stt->Rxx16_LPw32Max = 0; +#ifdef MIC_LEVEL_FEEDBACK + //stt->numBlocksMicLvlSat = 0; +#endif +#ifdef AGC_DEBUG //test log + fprintf(stt->fpt, + "\tAGC->ProcessAnalog, frame %d: measure > 2ndUpperLim, micVol = %d, maxLevel = %d\n", + stt->fcount, stt->micVol, stt->maxLevel); +#endif + } + } else if (stt->Rxx160_LPw32 > stt->upperLimit) + { + stt->msTooHigh += 2; + stt->msTooLow = 0; + stt->changeToSlowMode = 0; + + if (stt->msTooHigh > stt->msecSpeechInnerChange) + { + /* Lower the recording level */ + stt->msTooHigh = 0; + /* Multiply by 0.828125 which corresponds to decreasing ~0.8dB */ + tmp32 = WEBRTC_SPL_RSHIFT_W32(stt->Rxx160_LPw32, 6); + stt->Rxx160_LPw32 = WEBRTC_SPL_MUL(tmp32, 53); + + /* Reduce the max gain to avoid excessive oscillation + * (but never drop below the maximum analog level). + * stt->maxLevel = (15 * stt->maxLevel + stt->micVol) / 16; + */ + tmp32 = (15 * stt->maxLevel) + stt->micVol; + stt->maxLevel = WEBRTC_SPL_RSHIFT_W32(tmp32, 4); + stt->maxLevel = WEBRTC_SPL_MAX(stt->maxLevel, stt->maxAnalog); + + stt->zeroCtrlMax = stt->micVol; + + /* 0.965 in Q15 */ + tmp32 = inMicLevelTmp - stt->minLevel; + tmpU32 = WEBRTC_SPL_UMUL(31621, (WebRtc_UWord32)(inMicLevelTmp - stt->minLevel)); + stt->micVol = (WebRtc_Word32)WEBRTC_SPL_RSHIFT_U32(tmpU32, 15) + stt->minLevel; + if (stt->micVol > lastMicVol - 1) + { + stt->micVol = lastMicVol - 1; + } + inMicLevelTmp = stt->micVol; + +#ifdef MIC_LEVEL_FEEDBACK + //stt->numBlocksMicLvlSat = 0; +#endif +#ifdef AGC_DEBUG //test log + fprintf(stt->fpt, + "\tAGC->ProcessAnalog, frame %d: measure > UpperLim, micVol = %d, maxLevel = %d\n", + stt->fcount, stt->micVol, stt->maxLevel); +#endif + } + } else if (stt->Rxx160_LPw32 < stt->lowerSecondaryLimit) + { + stt->msTooHigh = 0; + stt->changeToSlowMode = 0; + stt->msTooLow += 2; + + if (stt->msTooLow > stt->msecSpeechOuterChange) + { + /* Raise the recording level */ + WebRtc_Word16 index, weightFIX; + WebRtc_Word16 volNormFIX = 16384; // =1 in Q14. + + stt->msTooLow = 0; + + /* Normalize the volume level */ + tmp32 = WEBRTC_SPL_LSHIFT_W32(inMicLevelTmp - stt->minLevel, 14); + if (stt->maxInit != stt->minLevel) + { + volNormFIX = (WebRtc_Word16)WEBRTC_SPL_DIV(tmp32, + (stt->maxInit - stt->minLevel)); + } + + /* Find correct curve */ + WebRtcAgc_ExpCurve(volNormFIX, &index); + + /* Compute weighting factor for the volume increase, 32^(-2*X)/2+1.05 */ + weightFIX = kOffset1[index] + - (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(kSlope1[index], + volNormFIX, 13); + + /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */ + tmp32 = WEBRTC_SPL_RSHIFT_W32(stt->Rxx160_LPw32, 6); + stt->Rxx160_LPw32 = WEBRTC_SPL_MUL(tmp32, 67); + + tmp32 = inMicLevelTmp - stt->minLevel; + tmpU32 = ((WebRtc_UWord32)weightFIX * (WebRtc_UWord32)(inMicLevelTmp - stt->minLevel)); + stt->micVol = (WebRtc_Word32)WEBRTC_SPL_RSHIFT_U32(tmpU32, 14) + stt->minLevel; + if (stt->micVol < lastMicVol + 2) + { + stt->micVol = lastMicVol + 2; + } + + inMicLevelTmp = stt->micVol; + +#ifdef MIC_LEVEL_FEEDBACK + /* Count ms in level saturation */ + //if (stt->micVol > stt->maxAnalog) { + if (stt->micVol > 150) + { + /* mic level is saturated */ + stt->numBlocksMicLvlSat++; + fprintf(stderr, "Sat mic Level: %d\n", stt->numBlocksMicLvlSat); + } +#endif +#ifdef AGC_DEBUG //test log + fprintf(stt->fpt, + "\tAGC->ProcessAnalog, frame %d: measure < 2ndLowerLim, micVol = %d\n", + stt->fcount, stt->micVol); +#endif + } + } else if (stt->Rxx160_LPw32 < stt->lowerLimit) + { + stt->msTooHigh = 0; + stt->changeToSlowMode = 0; + stt->msTooLow += 2; + + if (stt->msTooLow > stt->msecSpeechInnerChange) + { + /* Raise the recording level */ + WebRtc_Word16 index, weightFIX; + WebRtc_Word16 volNormFIX = 16384; // =1 in Q14. + + stt->msTooLow = 0; + + /* Normalize the volume level */ + tmp32 = WEBRTC_SPL_LSHIFT_W32(inMicLevelTmp - stt->minLevel, 14); + if (stt->maxInit != stt->minLevel) + { + volNormFIX = (WebRtc_Word16)WEBRTC_SPL_DIV(tmp32, + (stt->maxInit - stt->minLevel)); + } + + /* Find correct curve */ + WebRtcAgc_ExpCurve(volNormFIX, &index); + + /* Compute weighting factor for the volume increase, (3.^(-2.*X))/8+1 */ + weightFIX = kOffset2[index] + - (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(kSlope2[index], + volNormFIX, 13); + + /* stt->Rxx160_LPw32 *= 1.047 [~0.2 dB]; */ + tmp32 = WEBRTC_SPL_RSHIFT_W32(stt->Rxx160_LPw32, 6); + stt->Rxx160_LPw32 = WEBRTC_SPL_MUL(tmp32, 67); + + tmp32 = inMicLevelTmp - stt->minLevel; + tmpU32 = ((WebRtc_UWord32)weightFIX * (WebRtc_UWord32)(inMicLevelTmp - stt->minLevel)); + stt->micVol = (WebRtc_Word32)WEBRTC_SPL_RSHIFT_U32(tmpU32, 14) + stt->minLevel; + if (stt->micVol < lastMicVol + 1) + { + stt->micVol = lastMicVol + 1; + } + + inMicLevelTmp = stt->micVol; + +#ifdef MIC_LEVEL_FEEDBACK + /* Count ms in level saturation */ + //if (stt->micVol > stt->maxAnalog) { + if (stt->micVol > 150) + { + /* mic level is saturated */ + stt->numBlocksMicLvlSat++; + fprintf(stderr, "Sat mic Level: %d\n", stt->numBlocksMicLvlSat); + } +#endif +#ifdef AGC_DEBUG //test log + fprintf(stt->fpt, + "\tAGC->ProcessAnalog, frame %d: measure < LowerLim, micVol = %d\n", + stt->fcount, stt->micVol); +#endif + + } + } else + { + /* The signal is inside the desired range which is: + * lowerLimit < Rxx160_LP/640 < upperLimit + */ + if (stt->changeToSlowMode > 4000) + { + stt->msecSpeechInnerChange = 1000; + stt->msecSpeechOuterChange = 500; + stt->upperLimit = stt->upperPrimaryLimit; + stt->lowerLimit = stt->lowerPrimaryLimit; + } else + { + stt->changeToSlowMode += 2; // in milliseconds + } + stt->msTooLow = 0; + stt->msTooHigh = 0; + + stt->micVol = inMicLevelTmp; + + } +#ifdef MIC_LEVEL_FEEDBACK + if (stt->numBlocksMicLvlSat > NUM_BLOCKS_IN_SAT_BEFORE_CHANGE_TARGET) + { + stt->micLvlSat = 1; + fprintf(stderr, "target before = %d (%d)\n", stt->analogTargetLevel, stt->targetIdx); + WebRtcAgc_UpdateAgcThresholds(stt); + WebRtcAgc_CalculateGainTable(&(stt->digitalAgc.gainTable[0]), + stt->compressionGaindB, stt->targetLevelDbfs, stt->limiterEnable, + stt->analogTarget); + stt->numBlocksMicLvlSat = 0; + stt->micLvlSat = 0; + fprintf(stderr, "target offset = %d\n", stt->targetIdxOffset); + fprintf(stderr, "target after = %d (%d)\n", stt->analogTargetLevel, stt->targetIdx); + } +#endif + } + } + + /* Ensure gain is not increased in presence of echo or after a mute event + * (but allow the zeroCtrl() increase on the frame of a mute detection). + */ + if (echo == 1 || (stt->muteGuardMs > 0 && stt->muteGuardMs < kMuteGuardTimeMs)) + { + if (stt->micVol > lastMicVol) + { + stt->micVol = lastMicVol; + } + } + + /* limit the gain */ + if (stt->micVol > stt->maxLevel) + { + stt->micVol = stt->maxLevel; + } else if (stt->micVol < stt->minOutput) + { + stt->micVol = stt->minOutput; + } + + *outMicLevel = WEBRTC_SPL_RSHIFT_W32(stt->micVol, stt->scale); + if (*outMicLevel > WEBRTC_SPL_RSHIFT_W32(stt->maxAnalog, stt->scale)) + { + *outMicLevel = WEBRTC_SPL_RSHIFT_W32(stt->maxAnalog, stt->scale); + } + + return 0; +} + +int WebRtcAgc_Process(void *agcInst, const WebRtc_Word16 *in_near, + const WebRtc_Word16 *in_near_H, WebRtc_Word16 samples, + WebRtc_Word16 *out, WebRtc_Word16 *out_H, WebRtc_Word32 inMicLevel, + WebRtc_Word32 *outMicLevel, WebRtc_Word16 echo, + WebRtc_UWord8 *saturationWarning) +{ + Agc_t *stt; + WebRtc_Word32 inMicLevelTmp; + WebRtc_Word16 subFrames, i; + WebRtc_UWord8 satWarningTmp = 0; + + stt = (Agc_t *)agcInst; + + // + if (stt == NULL) + { + return -1; + } + // + + + if (stt->fs == 8000) + { + if ((samples != 80) && (samples != 160)) + { +#ifdef AGC_DEBUG //test log + fprintf(stt->fpt, + "AGC->Process, frame %d: Invalid number of samples\n\n", stt->fcount); +#endif + return -1; + } + subFrames = 80; + } else if (stt->fs == 16000) + { + if ((samples != 160) && (samples != 320)) + { +#ifdef AGC_DEBUG //test log + fprintf(stt->fpt, + "AGC->Process, frame %d: Invalid number of samples\n\n", stt->fcount); +#endif + return -1; + } + subFrames = 160; + } else if (stt->fs == 32000) + { + if ((samples != 160) && (samples != 320)) + { +#ifdef AGC_DEBUG //test log + fprintf(stt->fpt, + "AGC->Process, frame %d: Invalid number of samples\n\n", stt->fcount); +#endif + return -1; + } + subFrames = 160; + } else + { +#ifdef AGC_DEBUG// test log + fprintf(stt->fpt, + "AGC->Process, frame %d: Invalid sample rate\n\n", stt->fcount); +#endif + return -1; + } + + /* Check for valid pointers based on sampling rate */ + if (stt->fs == 32000 && in_near_H == NULL) + { + return -1; + } + /* Check for valid pointers for low band */ + if (in_near == NULL) + { + return -1; + } + + *saturationWarning = 0; + //TODO: PUT IN RANGE CHECKING FOR INPUT LEVELS + *outMicLevel = inMicLevel; + inMicLevelTmp = inMicLevel; + + // TODO(andrew): clearly we don't need input and output pointers... + // Change the interface to take a shared input/output. + if (in_near != out) + { + // Only needed if they don't already point to the same place. + memcpy(out, in_near, samples * sizeof(WebRtc_Word16)); + } + if (stt->fs == 32000) + { + if (in_near_H != out_H) + { + memcpy(out_H, in_near_H, samples * sizeof(WebRtc_Word16)); + } + } + +#ifdef AGC_DEBUG//test log + stt->fcount++; +#endif + + for (i = 0; i < samples; i += subFrames) + { + if (WebRtcAgc_ProcessDigital(&stt->digitalAgc, &in_near[i], &in_near_H[i], &out[i], &out_H[i], + stt->fs, stt->lowLevelSignal) == -1) + { +#ifdef AGC_DEBUG//test log + fprintf(stt->fpt, "AGC->Process, frame %d: Error from DigAGC\n\n", stt->fcount); +#endif + return -1; + } + if ((stt->agcMode < kAgcModeFixedDigital) && ((stt->lowLevelSignal == 0) + || (stt->agcMode != kAgcModeAdaptiveDigital))) + { + if (WebRtcAgc_ProcessAnalog(agcInst, inMicLevelTmp, outMicLevel, + stt->vadMic.logRatio, echo, saturationWarning) == -1) + { + return -1; + } + } +#ifdef AGC_DEBUG//test log + fprintf(stt->agcLog, "%5d\t%d\t%d\t%d\n", stt->fcount, inMicLevelTmp, *outMicLevel, stt->maxLevel, stt->micVol); +#endif + + /* update queue */ + if (stt->inQueue > 1) + { + memcpy(stt->env[0], stt->env[1], 10 * sizeof(WebRtc_Word32)); + memcpy(stt->Rxx16w32_array[0], stt->Rxx16w32_array[1], 5 * sizeof(WebRtc_Word32)); + } + + if (stt->inQueue > 0) + { + stt->inQueue--; + } + + /* If 20ms frames are used the input mic level must be updated so that + * the analog AGC does not think that there has been a manual volume + * change. */ + inMicLevelTmp = *outMicLevel; + + /* Store a positive saturation warning. */ + if (*saturationWarning == 1) + { + satWarningTmp = 1; + } + } + + /* Trigger the saturation warning if displayed by any of the frames. */ + *saturationWarning = satWarningTmp; + + return 0; +} + +int WebRtcAgc_set_config(void *agcInst, WebRtcAgc_config_t agcConfig) +{ + Agc_t *stt; + stt = (Agc_t *)agcInst; + + if (stt == NULL) + { + return -1; + } + + if (stt->initFlag != kInitCheck) + { + stt->lastError = AGC_UNINITIALIZED_ERROR; + return -1; + } + + if (agcConfig.limiterEnable != kAgcFalse && agcConfig.limiterEnable != kAgcTrue) + { + stt->lastError = AGC_BAD_PARAMETER_ERROR; + return -1; + } + stt->limiterEnable = agcConfig.limiterEnable; + stt->compressionGaindB = agcConfig.compressionGaindB; + if ((agcConfig.targetLevelDbfs < 0) || (agcConfig.targetLevelDbfs > 31)) + { + stt->lastError = AGC_BAD_PARAMETER_ERROR; + return -1; + } + stt->targetLevelDbfs = agcConfig.targetLevelDbfs; + + if (stt->agcMode == kAgcModeFixedDigital) + { + /* Adjust for different parameter interpretation in FixedDigital mode */ + stt->compressionGaindB += agcConfig.targetLevelDbfs; + } + + /* Update threshold levels for analog adaptation */ + WebRtcAgc_UpdateAgcThresholds(stt); + + /* Recalculate gain table */ + if (WebRtcAgc_CalculateGainTable(&(stt->digitalAgc.gainTable[0]), stt->compressionGaindB, + stt->targetLevelDbfs, stt->limiterEnable, stt->analogTarget) == -1) + { +#ifdef AGC_DEBUG//test log + fprintf(stt->fpt, "AGC->set_config, frame %d: Error from calcGainTable\n\n", stt->fcount); +#endif + return -1; + } + /* Store the config in a WebRtcAgc_config_t */ + stt->usedConfig.compressionGaindB = agcConfig.compressionGaindB; + stt->usedConfig.limiterEnable = agcConfig.limiterEnable; + stt->usedConfig.targetLevelDbfs = agcConfig.targetLevelDbfs; + + return 0; +} + +int WebRtcAgc_get_config(void *agcInst, WebRtcAgc_config_t *config) +{ + Agc_t *stt; + stt = (Agc_t *)agcInst; + + if (stt == NULL) + { + return -1; + } + + if (config == NULL) + { + stt->lastError = AGC_NULL_POINTER_ERROR; + return -1; + } + + if (stt->initFlag != kInitCheck) + { + stt->lastError = AGC_UNINITIALIZED_ERROR; + return -1; + } + + config->limiterEnable = stt->usedConfig.limiterEnable; + config->targetLevelDbfs = stt->usedConfig.targetLevelDbfs; + config->compressionGaindB = stt->usedConfig.compressionGaindB; + + return 0; +} + +int WebRtcAgc_Create(void **agcInst) +{ + Agc_t *stt; + if (agcInst == NULL) + { + return -1; + } + stt = (Agc_t *)malloc(sizeof(Agc_t)); + + *agcInst = stt; + if (stt == NULL) + { + return -1; + } + +#ifdef AGC_DEBUG + stt->fpt = fopen("./agc_test_log.txt", "wt"); + stt->agcLog = fopen("./agc_debug_log.txt", "wt"); + stt->digitalAgc.logFile = fopen("./agc_log.txt", "wt"); +#endif + + stt->initFlag = 0; + stt->lastError = 0; + + return 0; +} + +int WebRtcAgc_Free(void *state) +{ + Agc_t *stt; + + stt = (Agc_t *)state; +#ifdef AGC_DEBUG + fclose(stt->fpt); + fclose(stt->agcLog); + fclose(stt->digitalAgc.logFile); +#endif + free(stt); + + return 0; +} + +/* minLevel - Minimum volume level + * maxLevel - Maximum volume level + */ +int WebRtcAgc_Init(void *agcInst, WebRtc_Word32 minLevel, WebRtc_Word32 maxLevel, + WebRtc_Word16 agcMode, WebRtc_UWord32 fs) +{ + WebRtc_Word32 max_add, tmp32; + WebRtc_Word16 i; + int tmpNorm; + Agc_t *stt; + + /* typecast state pointer */ + stt = (Agc_t *)agcInst; + + if (WebRtcAgc_InitDigital(&stt->digitalAgc, agcMode) != 0) + { + stt->lastError = AGC_UNINITIALIZED_ERROR; + return -1; + } + + /* Analog AGC variables */ + stt->envSum = 0; + + /* mode = 0 - Only saturation protection + * 1 - Analog Automatic Gain Control [-targetLevelDbfs (default -3 dBOv)] + * 2 - Digital Automatic Gain Control [-targetLevelDbfs (default -3 dBOv)] + * 3 - Fixed Digital Gain [compressionGaindB (default 8 dB)] + */ +#ifdef AGC_DEBUG//test log + stt->fcount = 0; + fprintf(stt->fpt, "AGC->Init\n"); +#endif + if (agcMode < kAgcModeUnchanged || agcMode > kAgcModeFixedDigital) + { +#ifdef AGC_DEBUG//test log + fprintf(stt->fpt, "AGC->Init: error, incorrect mode\n\n"); +#endif + return -1; + } + stt->agcMode = agcMode; + stt->fs = fs; + + /* initialize input VAD */ + WebRtcAgc_InitVad(&stt->vadMic); + + /* If the volume range is smaller than 0-256 then + * the levels are shifted up to Q8-domain */ + tmpNorm = WebRtcSpl_NormU32((WebRtc_UWord32)maxLevel); + stt->scale = tmpNorm - 23; + if (stt->scale < 0) + { + stt->scale = 0; + } + // TODO(bjornv): Investigate if we really need to scale up a small range now when we have + // a guard against zero-increments. For now, we do not support scale up (scale = 0). + stt->scale = 0; + maxLevel = WEBRTC_SPL_LSHIFT_W32(maxLevel, stt->scale); + minLevel = WEBRTC_SPL_LSHIFT_W32(minLevel, stt->scale); + + /* Make minLevel and maxLevel static in AdaptiveDigital */ + if (stt->agcMode == kAgcModeAdaptiveDigital) + { + minLevel = 0; + maxLevel = 255; + stt->scale = 0; + } + /* The maximum supplemental volume range is based on a vague idea + * of how much lower the gain will be than the real analog gain. */ + max_add = WEBRTC_SPL_RSHIFT_W32(maxLevel - minLevel, 2); + + /* Minimum/maximum volume level that can be set */ + stt->minLevel = minLevel; + stt->maxAnalog = maxLevel; + stt->maxLevel = maxLevel + max_add; + stt->maxInit = stt->maxLevel; + + stt->zeroCtrlMax = stt->maxAnalog; + + /* Initialize micVol parameter */ + stt->micVol = stt->maxAnalog; + if (stt->agcMode == kAgcModeAdaptiveDigital) + { + stt->micVol = 127; /* Mid-point of mic level */ + } + stt->micRef = stt->micVol; + stt->micGainIdx = 127; +#ifdef MIC_LEVEL_FEEDBACK + stt->numBlocksMicLvlSat = 0; + stt->micLvlSat = 0; +#endif +#ifdef AGC_DEBUG//test log + fprintf(stt->fpt, + "AGC->Init: minLevel = %d, maxAnalog = %d, maxLevel = %d\n", + stt->minLevel, stt->maxAnalog, stt->maxLevel); +#endif + + /* Minimum output volume is 4% higher than the available lowest volume level */ + tmp32 = WEBRTC_SPL_RSHIFT_W32((stt->maxLevel - stt->minLevel) * (WebRtc_Word32)10, 8); + stt->minOutput = (stt->minLevel + tmp32); + + stt->msTooLow = 0; + stt->msTooHigh = 0; + stt->changeToSlowMode = 0; + stt->firstCall = 0; + stt->msZero = 0; + stt->muteGuardMs = 0; + stt->gainTableIdx = 0; + + stt->msecSpeechInnerChange = kMsecSpeechInner; + stt->msecSpeechOuterChange = kMsecSpeechOuter; + + stt->activeSpeech = 0; + stt->Rxx16_LPw32Max = 0; + + stt->vadThreshold = kNormalVadThreshold; + stt->inActive = 0; + + for (i = 0; i < RXX_BUFFER_LEN; i++) + { + stt->Rxx16_vectorw32[i] = (WebRtc_Word32)1000; /* -54dBm0 */ + } + stt->Rxx160w32 = 125 * RXX_BUFFER_LEN; /* (stt->Rxx16_vectorw32[0]>>3) = 125 */ + + stt->Rxx16pos = 0; + stt->Rxx16_LPw32 = (WebRtc_Word32)16284; /* Q(-4) */ + + for (i = 0; i < 5; i++) + { + stt->Rxx16w32_array[0][i] = 0; + } + for (i = 0; i < 20; i++) + { + stt->env[0][i] = 0; + } + stt->inQueue = 0; + +#ifdef MIC_LEVEL_FEEDBACK + stt->targetIdxOffset = 0; +#endif + + WebRtcSpl_MemSetW32(stt->filterState, 0, 8); + + stt->initFlag = kInitCheck; + // Default config settings. + stt->defaultConfig.limiterEnable = kAgcTrue; + stt->defaultConfig.targetLevelDbfs = AGC_DEFAULT_TARGET_LEVEL; + stt->defaultConfig.compressionGaindB = AGC_DEFAULT_COMP_GAIN; + + if (WebRtcAgc_set_config(stt, stt->defaultConfig) == -1) + { + stt->lastError = AGC_UNSPECIFIED_ERROR; + return -1; + } + stt->Rxx160_LPw32 = stt->analogTargetLevel; // Initialize rms value + + stt->lowLevelSignal = 0; + + /* Only positive values are allowed that are not too large */ + if ((minLevel >= maxLevel) || (maxLevel & 0xFC000000)) + { +#ifdef AGC_DEBUG//test log + fprintf(stt->fpt, "minLevel, maxLevel value(s) are invalid\n\n"); +#endif + return -1; + } else + { +#ifdef AGC_DEBUG//test log + fprintf(stt->fpt, "\n"); +#endif + return 0; + } +} diff --git a/libs/miniwebrtc/audio/processing/agc/analog_agc.h b/libs/miniwebrtc/audio/processing/agc/analog_agc.h new file mode 100644 index 00000000..b32ac658 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/agc/analog_agc.h @@ -0,0 +1,133 @@ +/* + * 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_PROCESSING_AGC_MAIN_SOURCE_ANALOG_AGC_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_AGC_MAIN_SOURCE_ANALOG_AGC_H_ + +#include "typedefs.h" +#include "gain_control.h" +#include "digital_agc.h" + +//#define AGC_DEBUG +//#define MIC_LEVEL_FEEDBACK +#ifdef AGC_DEBUG +#include +#endif + +/* Analog Automatic Gain Control variables: + * Constant declarations (inner limits inside which no changes are done) + * In the beginning the range is narrower to widen as soon as the measure + * 'Rxx160_LP' is inside it. Currently the starting limits are -22.2+/-1dBm0 + * and the final limits -22.2+/-2.5dBm0. These levels makes the speech signal + * go towards -25.4dBm0 (-31.4dBov). Tuned with wbfile-31.4dBov.pcm + * The limits are created by running the AGC with a file having the desired + * signal level and thereafter plotting Rxx160_LP in the dBm0-domain defined + * by out=10*log10(in/260537279.7); Set the target level to the average level + * of our measure Rxx160_LP. Remember that the levels are in blocks of 16 in + * Q(-7). (Example matlab code: round(db2pow(-21.2)*16/2^7) ) + */ +#define RXX_BUFFER_LEN 10 + +static const WebRtc_Word16 kMsecSpeechInner = 520; +static const WebRtc_Word16 kMsecSpeechOuter = 340; + +static const WebRtc_Word16 kNormalVadThreshold = 400; + +static const WebRtc_Word16 kAlphaShortTerm = 6; // 1 >> 6 = 0.0156 +static const WebRtc_Word16 kAlphaLongTerm = 10; // 1 >> 10 = 0.000977 + +typedef struct +{ + // Configurable parameters/variables + WebRtc_UWord32 fs; // Sampling frequency + WebRtc_Word16 compressionGaindB; // Fixed gain level in dB + WebRtc_Word16 targetLevelDbfs; // Target level in -dBfs of envelope (default -3) + WebRtc_Word16 agcMode; // Hard coded mode (adaptAna/adaptDig/fixedDig) + WebRtc_UWord8 limiterEnable; // Enabling limiter (on/off (default off)) + WebRtcAgc_config_t defaultConfig; + WebRtcAgc_config_t usedConfig; + + // General variables + WebRtc_Word16 initFlag; + WebRtc_Word16 lastError; + + // Target level parameters + // Based on the above: analogTargetLevel = round((32767*10^(-22/20))^2*16/2^7) + WebRtc_Word32 analogTargetLevel; // = RXX_BUFFER_LEN * 846805; -22 dBfs + WebRtc_Word32 startUpperLimit; // = RXX_BUFFER_LEN * 1066064; -21 dBfs + WebRtc_Word32 startLowerLimit; // = RXX_BUFFER_LEN * 672641; -23 dBfs + WebRtc_Word32 upperPrimaryLimit; // = RXX_BUFFER_LEN * 1342095; -20 dBfs + WebRtc_Word32 lowerPrimaryLimit; // = RXX_BUFFER_LEN * 534298; -24 dBfs + WebRtc_Word32 upperSecondaryLimit;// = RXX_BUFFER_LEN * 2677832; -17 dBfs + WebRtc_Word32 lowerSecondaryLimit;// = RXX_BUFFER_LEN * 267783; -27 dBfs + WebRtc_UWord16 targetIdx; // Table index for corresponding target level +#ifdef MIC_LEVEL_FEEDBACK + WebRtc_UWord16 targetIdxOffset; // Table index offset for level compensation +#endif + WebRtc_Word16 analogTarget; // Digital reference level in ENV scale + + // Analog AGC specific variables + WebRtc_Word32 filterState[8]; // For downsampling wb to nb + WebRtc_Word32 upperLimit; // Upper limit for mic energy + WebRtc_Word32 lowerLimit; // Lower limit for mic energy + WebRtc_Word32 Rxx160w32; // Average energy for one frame + WebRtc_Word32 Rxx16_LPw32; // Low pass filtered subframe energies + WebRtc_Word32 Rxx160_LPw32; // Low pass filtered frame energies + WebRtc_Word32 Rxx16_LPw32Max; // Keeps track of largest energy subframe + WebRtc_Word32 Rxx16_vectorw32[RXX_BUFFER_LEN];// Array with subframe energies + WebRtc_Word32 Rxx16w32_array[2][5];// Energy values of microphone signal + WebRtc_Word32 env[2][10]; // Envelope values of subframes + + WebRtc_Word16 Rxx16pos; // Current position in the Rxx16_vectorw32 + WebRtc_Word16 envSum; // Filtered scaled envelope in subframes + WebRtc_Word16 vadThreshold; // Threshold for VAD decision + WebRtc_Word16 inActive; // Inactive time in milliseconds + WebRtc_Word16 msTooLow; // Milliseconds of speech at a too low level + WebRtc_Word16 msTooHigh; // Milliseconds of speech at a too high level + WebRtc_Word16 changeToSlowMode; // Change to slow mode after some time at target + WebRtc_Word16 firstCall; // First call to the process-function + WebRtc_Word16 msZero; // Milliseconds of zero input + WebRtc_Word16 msecSpeechOuterChange;// Min ms of speech between volume changes + WebRtc_Word16 msecSpeechInnerChange;// Min ms of speech between volume changes + WebRtc_Word16 activeSpeech; // Milliseconds of active speech + WebRtc_Word16 muteGuardMs; // Counter to prevent mute action + WebRtc_Word16 inQueue; // 10 ms batch indicator + + // Microphone level variables + WebRtc_Word32 micRef; // Remember ref. mic level for virtual mic + WebRtc_UWord16 gainTableIdx; // Current position in virtual gain table + WebRtc_Word32 micGainIdx; // Gain index of mic level to increase slowly + WebRtc_Word32 micVol; // Remember volume between frames + WebRtc_Word32 maxLevel; // Max possible vol level, incl dig gain + WebRtc_Word32 maxAnalog; // Maximum possible analog volume level + WebRtc_Word32 maxInit; // Initial value of "max" + WebRtc_Word32 minLevel; // Minimum possible volume level + WebRtc_Word32 minOutput; // Minimum output volume level + WebRtc_Word32 zeroCtrlMax; // Remember max gain => don't amp low input + + WebRtc_Word16 scale; // Scale factor for internal volume levels +#ifdef MIC_LEVEL_FEEDBACK + WebRtc_Word16 numBlocksMicLvlSat; + WebRtc_UWord8 micLvlSat; +#endif + // Structs for VAD and digital_agc + AgcVad_t vadMic; + DigitalAgc_t digitalAgc; + +#ifdef AGC_DEBUG + FILE* fpt; + FILE* agcLog; + WebRtc_Word32 fcount; +#endif + + WebRtc_Word16 lowLevelSignal; +} Agc_t; + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AGC_MAIN_SOURCE_ANALOG_AGC_H_ diff --git a/libs/miniwebrtc/audio/processing/agc/digital_agc.c b/libs/miniwebrtc/audio/processing/agc/digital_agc.c new file mode 100644 index 00000000..3b4b39b9 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/agc/digital_agc.c @@ -0,0 +1,798 @@ +/* + * 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. + */ + +/* digital_agc.c + * + */ + +#include "digital_agc.h" + +#include +#include +#ifdef AGC_DEBUG +#include +#endif + +#include "gain_control.h" + +// To generate the gaintable, copy&paste the following lines to a Matlab window: +// MaxGain = 6; MinGain = 0; CompRatio = 3; Knee = 1; +// zeros = 0:31; lvl = 2.^(1-zeros); +// A = -10*log10(lvl) * (CompRatio - 1) / CompRatio; +// B = MaxGain - MinGain; +// gains = round(2^16*10.^(0.05 * (MinGain + B * ( log(exp(-Knee*A)+exp(-Knee*B)) - log(1+exp(-Knee*B)) ) / log(1/(1+exp(Knee*B)))))); +// fprintf(1, '\t%i, %i, %i, %i,\n', gains); +// % Matlab code for plotting the gain and input/output level characteristic (copy/paste the following 3 lines): +// in = 10*log10(lvl); out = 20*log10(gains/65536); +// subplot(121); plot(in, out); axis([-30, 0, -5, 20]); grid on; xlabel('Input (dB)'); ylabel('Gain (dB)'); +// subplot(122); plot(in, in+out); axis([-30, 0, -30, 5]); grid on; xlabel('Input (dB)'); ylabel('Output (dB)'); +// zoom on; + +// Generator table for y=log2(1+e^x) in Q8. +enum { kGenFuncTableSize = 128 }; +static const WebRtc_UWord16 kGenFuncTable[kGenFuncTableSize] = { + 256, 485, 786, 1126, 1484, 1849, 2217, 2586, + 2955, 3324, 3693, 4063, 4432, 4801, 5171, 5540, + 5909, 6279, 6648, 7017, 7387, 7756, 8125, 8495, + 8864, 9233, 9603, 9972, 10341, 10711, 11080, 11449, + 11819, 12188, 12557, 12927, 13296, 13665, 14035, 14404, + 14773, 15143, 15512, 15881, 16251, 16620, 16989, 17359, + 17728, 18097, 18466, 18836, 19205, 19574, 19944, 20313, + 20682, 21052, 21421, 21790, 22160, 22529, 22898, 23268, + 23637, 24006, 24376, 24745, 25114, 25484, 25853, 26222, + 26592, 26961, 27330, 27700, 28069, 28438, 28808, 29177, + 29546, 29916, 30285, 30654, 31024, 31393, 31762, 32132, + 32501, 32870, 33240, 33609, 33978, 34348, 34717, 35086, + 35456, 35825, 36194, 36564, 36933, 37302, 37672, 38041, + 38410, 38780, 39149, 39518, 39888, 40257, 40626, 40996, + 41365, 41734, 42104, 42473, 42842, 43212, 43581, 43950, + 44320, 44689, 45058, 45428, 45797, 46166, 46536, 46905 +}; + +static const WebRtc_Word16 kAvgDecayTime = 250; // frames; < 3000 + +WebRtc_Word32 WebRtcAgc_CalculateGainTable(WebRtc_Word32 *gainTable, // Q16 + WebRtc_Word16 digCompGaindB, // Q0 + WebRtc_Word16 targetLevelDbfs,// Q0 + WebRtc_UWord8 limiterEnable, + WebRtc_Word16 analogTarget) // Q0 +{ + // This function generates the compressor gain table used in the fixed digital part. + WebRtc_UWord32 tmpU32no1, tmpU32no2, absInLevel, logApprox; + WebRtc_Word32 inLevel, limiterLvl; + WebRtc_Word32 tmp32, tmp32no1, tmp32no2, numFIX, den, y32; + const WebRtc_UWord16 kLog10 = 54426; // log2(10) in Q14 + const WebRtc_UWord16 kLog10_2 = 49321; // 10*log10(2) in Q14 + const WebRtc_UWord16 kLogE_1 = 23637; // log2(e) in Q14 + WebRtc_UWord16 constMaxGain; + WebRtc_UWord16 tmpU16, intPart, fracPart; + const WebRtc_Word16 kCompRatio = 3; + const WebRtc_Word16 kSoftLimiterLeft = 1; + WebRtc_Word16 limiterOffset = 0; // Limiter offset + WebRtc_Word16 limiterIdx, limiterLvlX; + WebRtc_Word16 constLinApprox, zeroGainLvl, maxGain, diffGain; + WebRtc_Word16 i, tmp16, tmp16no1; + int zeros, zerosScale; + + // Constants +// kLogE_1 = 23637; // log2(e) in Q14 +// kLog10 = 54426; // log2(10) in Q14 +// kLog10_2 = 49321; // 10*log10(2) in Q14 + + // Calculate maximum digital gain and zero gain level + tmp32no1 = WEBRTC_SPL_MUL_16_16(digCompGaindB - analogTarget, kCompRatio - 1); + tmp16no1 = analogTarget - targetLevelDbfs; + tmp16no1 += WebRtcSpl_DivW32W16ResW16(tmp32no1 + (kCompRatio >> 1), kCompRatio); + maxGain = WEBRTC_SPL_MAX(tmp16no1, (analogTarget - targetLevelDbfs)); + tmp32no1 = WEBRTC_SPL_MUL_16_16(maxGain, kCompRatio); + zeroGainLvl = digCompGaindB; + zeroGainLvl -= WebRtcSpl_DivW32W16ResW16(tmp32no1 + ((kCompRatio - 1) >> 1), + kCompRatio - 1); + if ((digCompGaindB <= analogTarget) && (limiterEnable)) + { + zeroGainLvl += (analogTarget - digCompGaindB + kSoftLimiterLeft); + limiterOffset = 0; + } + + // Calculate the difference between maximum gain and gain at 0dB0v: + // diffGain = maxGain + (compRatio-1)*zeroGainLvl/compRatio + // = (compRatio-1)*digCompGaindB/compRatio + tmp32no1 = WEBRTC_SPL_MUL_16_16(digCompGaindB, kCompRatio - 1); + diffGain = WebRtcSpl_DivW32W16ResW16(tmp32no1 + (kCompRatio >> 1), kCompRatio); + if (diffGain < 0 || diffGain >= kGenFuncTableSize) + { + assert(0); + return -1; + } + + // Calculate the limiter level and index: + // limiterLvlX = analogTarget - limiterOffset + // limiterLvl = targetLevelDbfs + limiterOffset/compRatio + limiterLvlX = analogTarget - limiterOffset; + limiterIdx = 2 + + WebRtcSpl_DivW32W16ResW16(WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)limiterLvlX, 13), + WEBRTC_SPL_RSHIFT_U16(kLog10_2, 1)); + tmp16no1 = WebRtcSpl_DivW32W16ResW16(limiterOffset + (kCompRatio >> 1), kCompRatio); + limiterLvl = targetLevelDbfs + tmp16no1; + + // Calculate (through table lookup): + // constMaxGain = log2(1+2^(log2(e)*diffGain)); (in Q8) + constMaxGain = kGenFuncTable[diffGain]; // in Q8 + + // Calculate a parameter used to approximate the fractional part of 2^x with a + // piecewise linear function in Q14: + // constLinApprox = round(3/2*(4*(3-2*sqrt(2))/(log(2)^2)-0.5)*2^14); + constLinApprox = 22817; // in Q14 + + // Calculate a denominator used in the exponential part to convert from dB to linear scale: + // den = 20*constMaxGain (in Q8) + den = WEBRTC_SPL_MUL_16_U16(20, constMaxGain); // in Q8 + + for (i = 0; i < 32; i++) + { + // Calculate scaled input level (compressor): + // inLevel = fix((-constLog10_2*(compRatio-1)*(1-i)+fix(compRatio/2))/compRatio) + tmp16 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16(kCompRatio - 1, i - 1); // Q0 + tmp32 = WEBRTC_SPL_MUL_16_U16(tmp16, kLog10_2) + 1; // Q14 + inLevel = WebRtcSpl_DivW32W16(tmp32, kCompRatio); // Q14 + + // Calculate diffGain-inLevel, to map using the genFuncTable + inLevel = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)diffGain, 14) - inLevel; // Q14 + + // Make calculations on abs(inLevel) and compensate for the sign afterwards. + absInLevel = (WebRtc_UWord32)WEBRTC_SPL_ABS_W32(inLevel); // Q14 + + // LUT with interpolation + intPart = (WebRtc_UWord16)WEBRTC_SPL_RSHIFT_U32(absInLevel, 14); + fracPart = (WebRtc_UWord16)(absInLevel & 0x00003FFF); // extract the fractional part + tmpU16 = kGenFuncTable[intPart + 1] - kGenFuncTable[intPart]; // Q8 + tmpU32no1 = WEBRTC_SPL_UMUL_16_16(tmpU16, fracPart); // Q22 + tmpU32no1 += WEBRTC_SPL_LSHIFT_U32((WebRtc_UWord32)kGenFuncTable[intPart], 14); // Q22 + logApprox = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, 8); // Q14 + // Compensate for negative exponent using the relation: + // log2(1 + 2^-x) = log2(1 + 2^x) - x + if (inLevel < 0) + { + zeros = WebRtcSpl_NormU32(absInLevel); + zerosScale = 0; + if (zeros < 15) + { + // Not enough space for multiplication + tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(absInLevel, 15 - zeros); // Q(zeros-1) + tmpU32no2 = WEBRTC_SPL_UMUL_32_16(tmpU32no2, kLogE_1); // Q(zeros+13) + if (zeros < 9) + { + tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, 9 - zeros); // Q(zeros+13) + zerosScale = 9 - zeros; + } else + { + tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(tmpU32no2, zeros - 9); // Q22 + } + } else + { + tmpU32no2 = WEBRTC_SPL_UMUL_32_16(absInLevel, kLogE_1); // Q28 + tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(tmpU32no2, 6); // Q22 + } + logApprox = 0; + if (tmpU32no2 < tmpU32no1) + { + logApprox = WEBRTC_SPL_RSHIFT_U32(tmpU32no1 - tmpU32no2, 8 - zerosScale); //Q14 + } + } + numFIX = WEBRTC_SPL_LSHIFT_W32(WEBRTC_SPL_MUL_16_U16(maxGain, constMaxGain), 6); // Q14 + numFIX -= WEBRTC_SPL_MUL_32_16((WebRtc_Word32)logApprox, diffGain); // Q14 + + // Calculate ratio + // Shift |numFIX| as much as possible. + // Ensure we avoid wrap-around in |den| as well. + if (numFIX > (den >> 8)) // |den| is Q8. + { + zeros = WebRtcSpl_NormW32(numFIX); + } else + { + zeros = WebRtcSpl_NormW32(den) + 8; + } + numFIX = WEBRTC_SPL_LSHIFT_W32(numFIX, zeros); // Q(14+zeros) + + // Shift den so we end up in Qy1 + tmp32no1 = WEBRTC_SPL_SHIFT_W32(den, zeros - 8); // Q(zeros) + if (numFIX < 0) + { + numFIX -= WEBRTC_SPL_RSHIFT_W32(tmp32no1, 1); + } else + { + numFIX += WEBRTC_SPL_RSHIFT_W32(tmp32no1, 1); + } + y32 = WEBRTC_SPL_DIV(numFIX, tmp32no1); // in Q14 + if (limiterEnable && (i < limiterIdx)) + { + tmp32 = WEBRTC_SPL_MUL_16_U16(i - 1, kLog10_2); // Q14 + tmp32 -= WEBRTC_SPL_LSHIFT_W32(limiterLvl, 14); // Q14 + y32 = WebRtcSpl_DivW32W16(tmp32 + 10, 20); + } + if (y32 > 39000) + { + tmp32 = WEBRTC_SPL_MUL(y32 >> 1, kLog10) + 4096; // in Q27 + tmp32 = WEBRTC_SPL_RSHIFT_W32(tmp32, 13); // in Q14 + } else + { + tmp32 = WEBRTC_SPL_MUL(y32, kLog10) + 8192; // in Q28 + tmp32 = WEBRTC_SPL_RSHIFT_W32(tmp32, 14); // in Q14 + } + tmp32 += WEBRTC_SPL_LSHIFT_W32(16, 14); // in Q14 (Make sure final output is in Q16) + + // Calculate power + if (tmp32 > 0) + { + intPart = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32, 14); + fracPart = (WebRtc_UWord16)(tmp32 & 0x00003FFF); // in Q14 + if (WEBRTC_SPL_RSHIFT_W32(fracPart, 13)) + { + tmp16 = WEBRTC_SPL_LSHIFT_W16(2, 14) - constLinApprox; + tmp32no2 = WEBRTC_SPL_LSHIFT_W32(1, 14) - fracPart; + tmp32no2 = WEBRTC_SPL_MUL_32_16(tmp32no2, tmp16); + tmp32no2 = WEBRTC_SPL_RSHIFT_W32(tmp32no2, 13); + tmp32no2 = WEBRTC_SPL_LSHIFT_W32(1, 14) - tmp32no2; + } else + { + tmp16 = constLinApprox - WEBRTC_SPL_LSHIFT_W16(1, 14); + tmp32no2 = WEBRTC_SPL_MUL_32_16(fracPart, tmp16); + tmp32no2 = WEBRTC_SPL_RSHIFT_W32(tmp32no2, 13); + } + fracPart = (WebRtc_UWord16)tmp32no2; + gainTable[i] = WEBRTC_SPL_LSHIFT_W32(1, intPart) + + WEBRTC_SPL_SHIFT_W32(fracPart, intPart - 14); + } else + { + gainTable[i] = 0; + } + } + + return 0; +} + +WebRtc_Word32 WebRtcAgc_InitDigital(DigitalAgc_t *stt, WebRtc_Word16 agcMode) +{ + + if (agcMode == kAgcModeFixedDigital) + { + // start at minimum to find correct gain faster + stt->capacitorSlow = 0; + } else + { + // start out with 0 dB gain + stt->capacitorSlow = 134217728; // (WebRtc_Word32)(0.125f * 32768.0f * 32768.0f); + } + stt->capacitorFast = 0; + stt->gain = 65536; + stt->gatePrevious = 0; + stt->agcMode = agcMode; +#ifdef AGC_DEBUG + stt->frameCounter = 0; +#endif + + // initialize VADs + WebRtcAgc_InitVad(&stt->vadNearend); + WebRtcAgc_InitVad(&stt->vadFarend); + + return 0; +} + +WebRtc_Word32 WebRtcAgc_AddFarendToDigital(DigitalAgc_t *stt, const WebRtc_Word16 *in_far, + WebRtc_Word16 nrSamples) +{ + // Check for valid pointer + if (&stt->vadFarend == NULL) + { + return -1; + } + + // VAD for far end + WebRtcAgc_ProcessVad(&stt->vadFarend, in_far, nrSamples); + + return 0; +} + +WebRtc_Word32 WebRtcAgc_ProcessDigital(DigitalAgc_t *stt, const WebRtc_Word16 *in_near, + const WebRtc_Word16 *in_near_H, WebRtc_Word16 *out, + WebRtc_Word16 *out_H, WebRtc_UWord32 FS, + WebRtc_Word16 lowlevelSignal) +{ + // array for gains (one value per ms, incl start & end) + WebRtc_Word32 gains[11]; + + WebRtc_Word32 out_tmp, tmp32; + WebRtc_Word32 env[10]; + WebRtc_Word32 nrg, max_nrg; + WebRtc_Word32 cur_level; + WebRtc_Word32 gain32, delta; + WebRtc_Word16 logratio; + WebRtc_Word16 lower_thr, upper_thr; + WebRtc_Word16 zeros, zeros_fast, frac; + WebRtc_Word16 decay; + WebRtc_Word16 gate, gain_adj; + WebRtc_Word16 k, n; + WebRtc_Word16 L, L2; // samples/subframe + + // determine number of samples per ms + if (FS == 8000) + { + L = 8; + L2 = 3; + } else if (FS == 16000) + { + L = 16; + L2 = 4; + } else if (FS == 32000) + { + L = 16; + L2 = 4; + } else + { + return -1; + } + + // TODO(andrew): again, we don't need input and output pointers... + if (in_near != out) + { + // Only needed if they don't already point to the same place. + memcpy(out, in_near, 10 * L * sizeof(WebRtc_Word16)); + } + if (FS == 32000) + { + if (in_near_H != out_H) + { + memcpy(out_H, in_near_H, 10 * L * sizeof(WebRtc_Word16)); + } + } + // VAD for near end + logratio = WebRtcAgc_ProcessVad(&stt->vadNearend, out, L * 10); + + // Account for far end VAD + if (stt->vadFarend.counter > 10) + { + tmp32 = WEBRTC_SPL_MUL_16_16(3, logratio); + logratio = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32 - stt->vadFarend.logRatio, 2); + } + + // Determine decay factor depending on VAD + // upper_thr = 1.0f; + // lower_thr = 0.25f; + upper_thr = 1024; // Q10 + lower_thr = 0; // Q10 + if (logratio > upper_thr) + { + // decay = -2^17 / DecayTime; -> -65 + decay = -65; + } else if (logratio < lower_thr) + { + decay = 0; + } else + { + // decay = (WebRtc_Word16)(((lower_thr - logratio) + // * (2^27/(DecayTime*(upper_thr-lower_thr)))) >> 10); + // SUBSTITUTED: 2^27/(DecayTime*(upper_thr-lower_thr)) -> 65 + tmp32 = WEBRTC_SPL_MUL_16_16((lower_thr - logratio), 65); + decay = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32, 10); + } + + // adjust decay factor for long silence (detected as low standard deviation) + // This is only done in the adaptive modes + if (stt->agcMode != kAgcModeFixedDigital) + { + if (stt->vadNearend.stdLongTerm < 4000) + { + decay = 0; + } else if (stt->vadNearend.stdLongTerm < 8096) + { + // decay = (WebRtc_Word16)(((stt->vadNearend.stdLongTerm - 4000) * decay) >> 12); + tmp32 = WEBRTC_SPL_MUL_16_16((stt->vadNearend.stdLongTerm - 4000), decay); + decay = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32, 12); + } + + if (lowlevelSignal != 0) + { + decay = 0; + } + } +#ifdef AGC_DEBUG + stt->frameCounter++; + fprintf(stt->logFile, "%5.2f\t%d\t%d\t%d\t", (float)(stt->frameCounter) / 100, logratio, decay, stt->vadNearend.stdLongTerm); +#endif + // Find max amplitude per sub frame + // iterate over sub frames + for (k = 0; k < 10; k++) + { + // iterate over samples + max_nrg = 0; + for (n = 0; n < L; n++) + { + nrg = WEBRTC_SPL_MUL_16_16(out[k * L + n], out[k * L + n]); + if (nrg > max_nrg) + { + max_nrg = nrg; + } + } + env[k] = max_nrg; + } + + // Calculate gain per sub frame + gains[0] = stt->gain; + for (k = 0; k < 10; k++) + { + // Fast envelope follower + // decay time = -131000 / -1000 = 131 (ms) + stt->capacitorFast = AGC_SCALEDIFF32(-1000, stt->capacitorFast, stt->capacitorFast); + if (env[k] > stt->capacitorFast) + { + stt->capacitorFast = env[k]; + } + // Slow envelope follower + if (env[k] > stt->capacitorSlow) + { + // increase capacitorSlow + stt->capacitorSlow + = AGC_SCALEDIFF32(500, (env[k] - stt->capacitorSlow), stt->capacitorSlow); + } else + { + // decrease capacitorSlow + stt->capacitorSlow + = AGC_SCALEDIFF32(decay, stt->capacitorSlow, stt->capacitorSlow); + } + + // use maximum of both capacitors as current level + if (stt->capacitorFast > stt->capacitorSlow) + { + cur_level = stt->capacitorFast; + } else + { + cur_level = stt->capacitorSlow; + } + // Translate signal level into gain, using a piecewise linear approximation + // find number of leading zeros + zeros = WebRtcSpl_NormU32((WebRtc_UWord32)cur_level); + if (cur_level == 0) + { + zeros = 31; + } + tmp32 = (WEBRTC_SPL_LSHIFT_W32(cur_level, zeros) & 0x7FFFFFFF); + frac = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32, 19); // Q12 + tmp32 = WEBRTC_SPL_MUL((stt->gainTable[zeros-1] - stt->gainTable[zeros]), frac); + gains[k + 1] = stt->gainTable[zeros] + WEBRTC_SPL_RSHIFT_W32(tmp32, 12); +#ifdef AGC_DEBUG + if (k == 0) + { + fprintf(stt->logFile, "%d\t%d\t%d\t%d\t%d\n", env[0], cur_level, stt->capacitorFast, stt->capacitorSlow, zeros); + } +#endif + } + + // Gate processing (lower gain during absence of speech) + zeros = WEBRTC_SPL_LSHIFT_W16(zeros, 9) - WEBRTC_SPL_RSHIFT_W16(frac, 3); + // find number of leading zeros + zeros_fast = WebRtcSpl_NormU32((WebRtc_UWord32)stt->capacitorFast); + if (stt->capacitorFast == 0) + { + zeros_fast = 31; + } + tmp32 = (WEBRTC_SPL_LSHIFT_W32(stt->capacitorFast, zeros_fast) & 0x7FFFFFFF); + zeros_fast = WEBRTC_SPL_LSHIFT_W16(zeros_fast, 9); + zeros_fast -= (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32, 22); + + gate = 1000 + zeros_fast - zeros - stt->vadNearend.stdShortTerm; + + if (gate < 0) + { + stt->gatePrevious = 0; + } else + { + tmp32 = WEBRTC_SPL_MUL_16_16(stt->gatePrevious, 7); + gate = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((WebRtc_Word32)gate + tmp32, 3); + stt->gatePrevious = gate; + } + // gate < 0 -> no gate + // gate > 2500 -> max gate + if (gate > 0) + { + if (gate < 2500) + { + gain_adj = WEBRTC_SPL_RSHIFT_W16(2500 - gate, 5); + } else + { + gain_adj = 0; + } + for (k = 0; k < 10; k++) + { + if ((gains[k + 1] - stt->gainTable[0]) > 8388608) + { + // To prevent wraparound + tmp32 = WEBRTC_SPL_RSHIFT_W32((gains[k+1] - stt->gainTable[0]), 8); + tmp32 = WEBRTC_SPL_MUL(tmp32, (178 + gain_adj)); + } else + { + tmp32 = WEBRTC_SPL_MUL((gains[k+1] - stt->gainTable[0]), (178 + gain_adj)); + tmp32 = WEBRTC_SPL_RSHIFT_W32(tmp32, 8); + } + gains[k + 1] = stt->gainTable[0] + tmp32; + } + } + + // Limit gain to avoid overload distortion + for (k = 0; k < 10; k++) + { + // To prevent wrap around + zeros = 10; + if (gains[k + 1] > 47453132) + { + zeros = 16 - WebRtcSpl_NormW32(gains[k + 1]); + } + gain32 = WEBRTC_SPL_RSHIFT_W32(gains[k+1], zeros) + 1; + gain32 = WEBRTC_SPL_MUL(gain32, gain32); + // check for overflow + while (AGC_MUL32(WEBRTC_SPL_RSHIFT_W32(env[k], 12) + 1, gain32) + > WEBRTC_SPL_SHIFT_W32((WebRtc_Word32)32767, 2 * (1 - zeros + 10))) + { + // multiply by 253/256 ==> -0.1 dB + if (gains[k + 1] > 8388607) + { + // Prevent wrap around + gains[k + 1] = WEBRTC_SPL_MUL(WEBRTC_SPL_RSHIFT_W32(gains[k+1], 8), 253); + } else + { + gains[k + 1] = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(gains[k+1], 253), 8); + } + gain32 = WEBRTC_SPL_RSHIFT_W32(gains[k+1], zeros) + 1; + gain32 = WEBRTC_SPL_MUL(gain32, gain32); + } + } + // gain reductions should be done 1 ms earlier than gain increases + for (k = 1; k < 10; k++) + { + if (gains[k] > gains[k + 1]) + { + gains[k] = gains[k + 1]; + } + } + // save start gain for next frame + stt->gain = gains[10]; + + // Apply gain + // handle first sub frame separately + delta = WEBRTC_SPL_LSHIFT_W32(gains[1] - gains[0], (4 - L2)); + gain32 = WEBRTC_SPL_LSHIFT_W32(gains[0], 4); + // iterate over samples + for (n = 0; n < L; n++) + { + // For lower band + tmp32 = WEBRTC_SPL_MUL((WebRtc_Word32)out[n], WEBRTC_SPL_RSHIFT_W32(gain32 + 127, 7)); + out_tmp = WEBRTC_SPL_RSHIFT_W32(tmp32 , 16); + if (out_tmp > 4095) + { + out[n] = (WebRtc_Word16)32767; + } else if (out_tmp < -4096) + { + out[n] = (WebRtc_Word16)-32768; + } else + { + tmp32 = WEBRTC_SPL_MUL((WebRtc_Word32)out[n], WEBRTC_SPL_RSHIFT_W32(gain32, 4)); + out[n] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32 , 16); + } + // For higher band + if (FS == 32000) + { + tmp32 = WEBRTC_SPL_MUL((WebRtc_Word32)out_H[n], + WEBRTC_SPL_RSHIFT_W32(gain32 + 127, 7)); + out_tmp = WEBRTC_SPL_RSHIFT_W32(tmp32 , 16); + if (out_tmp > 4095) + { + out_H[n] = (WebRtc_Word16)32767; + } else if (out_tmp < -4096) + { + out_H[n] = (WebRtc_Word16)-32768; + } else + { + tmp32 = WEBRTC_SPL_MUL((WebRtc_Word32)out_H[n], + WEBRTC_SPL_RSHIFT_W32(gain32, 4)); + out_H[n] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32 , 16); + } + } + // + + gain32 += delta; + } + // iterate over subframes + for (k = 1; k < 10; k++) + { + delta = WEBRTC_SPL_LSHIFT_W32(gains[k+1] - gains[k], (4 - L2)); + gain32 = WEBRTC_SPL_LSHIFT_W32(gains[k], 4); + // iterate over samples + for (n = 0; n < L; n++) + { + // For lower band + tmp32 = WEBRTC_SPL_MUL((WebRtc_Word32)out[k * L + n], + WEBRTC_SPL_RSHIFT_W32(gain32, 4)); + out[k * L + n] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32 , 16); + // For higher band + if (FS == 32000) + { + tmp32 = WEBRTC_SPL_MUL((WebRtc_Word32)out_H[k * L + n], + WEBRTC_SPL_RSHIFT_W32(gain32, 4)); + out_H[k * L + n] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32 , 16); + } + gain32 += delta; + } + } + + return 0; +} + +void WebRtcAgc_InitVad(AgcVad_t *state) +{ + WebRtc_Word16 k; + + state->HPstate = 0; // state of high pass filter + state->logRatio = 0; // log( P(active) / P(inactive) ) + // average input level (Q10) + state->meanLongTerm = WEBRTC_SPL_LSHIFT_W16(15, 10); + + // variance of input level (Q8) + state->varianceLongTerm = WEBRTC_SPL_LSHIFT_W32(500, 8); + + state->stdLongTerm = 0; // standard deviation of input level in dB + // short-term average input level (Q10) + state->meanShortTerm = WEBRTC_SPL_LSHIFT_W16(15, 10); + + // short-term variance of input level (Q8) + state->varianceShortTerm = WEBRTC_SPL_LSHIFT_W32(500, 8); + + state->stdShortTerm = 0; // short-term standard deviation of input level in dB + state->counter = 3; // counts updates + for (k = 0; k < 8; k++) + { + // downsampling filter + state->downState[k] = 0; + } +} + +WebRtc_Word16 WebRtcAgc_ProcessVad(AgcVad_t *state, // (i) VAD state + const WebRtc_Word16 *in, // (i) Speech signal + WebRtc_Word16 nrSamples) // (i) number of samples +{ + WebRtc_Word32 out, nrg, tmp32, tmp32b; + WebRtc_UWord16 tmpU16; + WebRtc_Word16 k, subfr, tmp16; + WebRtc_Word16 buf1[8]; + WebRtc_Word16 buf2[4]; + WebRtc_Word16 HPstate; + WebRtc_Word16 zeros, dB; + + // process in 10 sub frames of 1 ms (to save on memory) + nrg = 0; + HPstate = state->HPstate; + for (subfr = 0; subfr < 10; subfr++) + { + // downsample to 4 kHz + if (nrSamples == 160) + { + for (k = 0; k < 8; k++) + { + tmp32 = (WebRtc_Word32)in[2 * k] + (WebRtc_Word32)in[2 * k + 1]; + tmp32 = WEBRTC_SPL_RSHIFT_W32(tmp32, 1); + buf1[k] = (WebRtc_Word16)tmp32; + } + in += 16; + + WebRtcSpl_DownsampleBy2(buf1, 8, buf2, state->downState); + } else + { + WebRtcSpl_DownsampleBy2(in, 8, buf2, state->downState); + in += 8; + } + + // high pass filter and compute energy + for (k = 0; k < 4; k++) + { + out = buf2[k] + HPstate; + tmp32 = WEBRTC_SPL_MUL(600, out); + HPstate = (WebRtc_Word16)(WEBRTC_SPL_RSHIFT_W32(tmp32, 10) - buf2[k]); + tmp32 = WEBRTC_SPL_MUL(out, out); + nrg += WEBRTC_SPL_RSHIFT_W32(tmp32, 6); + } + } + state->HPstate = HPstate; + + // find number of leading zeros + if (!(0xFFFF0000 & nrg)) + { + zeros = 16; + } else + { + zeros = 0; + } + if (!(0xFF000000 & (nrg << zeros))) + { + zeros += 8; + } + if (!(0xF0000000 & (nrg << zeros))) + { + zeros += 4; + } + if (!(0xC0000000 & (nrg << zeros))) + { + zeros += 2; + } + if (!(0x80000000 & (nrg << zeros))) + { + zeros += 1; + } + + // energy level (range {-32..30}) (Q10) + dB = WEBRTC_SPL_LSHIFT_W16(15 - zeros, 11); + + // Update statistics + + if (state->counter < kAvgDecayTime) + { + // decay time = AvgDecTime * 10 ms + state->counter++; + } + + // update short-term estimate of mean energy level (Q10) + tmp32 = (WEBRTC_SPL_MUL_16_16(state->meanShortTerm, 15) + (WebRtc_Word32)dB); + state->meanShortTerm = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32, 4); + + // update short-term estimate of variance in energy level (Q8) + tmp32 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(dB, dB), 12); + tmp32 += WEBRTC_SPL_MUL(state->varianceShortTerm, 15); + state->varianceShortTerm = WEBRTC_SPL_RSHIFT_W32(tmp32, 4); + + // update short-term estimate of standard deviation in energy level (Q10) + tmp32 = WEBRTC_SPL_MUL_16_16(state->meanShortTerm, state->meanShortTerm); + tmp32 = WEBRTC_SPL_LSHIFT_W32(state->varianceShortTerm, 12) - tmp32; + state->stdShortTerm = (WebRtc_Word16)WebRtcSpl_Sqrt(tmp32); + + // update long-term estimate of mean energy level (Q10) + tmp32 = WEBRTC_SPL_MUL_16_16(state->meanLongTerm, state->counter) + (WebRtc_Word32)dB; + state->meanLongTerm = WebRtcSpl_DivW32W16ResW16(tmp32, + WEBRTC_SPL_ADD_SAT_W16(state->counter, 1)); + + // update long-term estimate of variance in energy level (Q8) + tmp32 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(dB, dB), 12); + tmp32 += WEBRTC_SPL_MUL(state->varianceLongTerm, state->counter); + state->varianceLongTerm = WebRtcSpl_DivW32W16(tmp32, + WEBRTC_SPL_ADD_SAT_W16(state->counter, 1)); + + // update long-term estimate of standard deviation in energy level (Q10) + tmp32 = WEBRTC_SPL_MUL_16_16(state->meanLongTerm, state->meanLongTerm); + tmp32 = WEBRTC_SPL_LSHIFT_W32(state->varianceLongTerm, 12) - tmp32; + state->stdLongTerm = (WebRtc_Word16)WebRtcSpl_Sqrt(tmp32); + + // update voice activity measure (Q10) + tmp16 = WEBRTC_SPL_LSHIFT_W16(3, 12); + tmp32 = WEBRTC_SPL_MUL_16_16(tmp16, (dB - state->meanLongTerm)); + tmp32 = WebRtcSpl_DivW32W16(tmp32, state->stdLongTerm); + tmpU16 = WEBRTC_SPL_LSHIFT_U16((WebRtc_UWord16)13, 12); + tmp32b = WEBRTC_SPL_MUL_16_U16(state->logRatio, tmpU16); + tmp32 += WEBRTC_SPL_RSHIFT_W32(tmp32b, 10); + + state->logRatio = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32, 6); + + // limit + if (state->logRatio > 2048) + { + state->logRatio = 2048; + } + if (state->logRatio < -2048) + { + state->logRatio = -2048; + } + + return state->logRatio; // Q10 +} diff --git a/libs/miniwebrtc/audio/processing/agc/digital_agc.h b/libs/miniwebrtc/audio/processing/agc/digital_agc.h new file mode 100644 index 00000000..240b2206 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/agc/digital_agc.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_AGC_MAIN_SOURCE_DIGITAL_AGC_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_AGC_MAIN_SOURCE_DIGITAL_AGC_H_ + +#ifdef AGC_DEBUG +#include +#endif +#include "typedefs.h" +#include "signal_processing_library.h" + +// the 32 most significant bits of A(19) * B(26) >> 13 +#define AGC_MUL32(A, B) (((B)>>13)*(A) + ( ((0x00001FFF & (B))*(A)) >> 13 )) +// C + the 32 most significant bits of A * B +#define AGC_SCALEDIFF32(A, B, C) ((C) + ((B)>>16)*(A) + ( ((0x0000FFFF & (B))*(A)) >> 16 )) + +typedef struct +{ + WebRtc_Word32 downState[8]; + WebRtc_Word16 HPstate; + WebRtc_Word16 counter; + WebRtc_Word16 logRatio; // log( P(active) / P(inactive) ) (Q10) + WebRtc_Word16 meanLongTerm; // Q10 + WebRtc_Word32 varianceLongTerm; // Q8 + WebRtc_Word16 stdLongTerm; // Q10 + WebRtc_Word16 meanShortTerm; // Q10 + WebRtc_Word32 varianceShortTerm; // Q8 + WebRtc_Word16 stdShortTerm; // Q10 +} AgcVad_t; // total = 54 bytes + +typedef struct +{ + WebRtc_Word32 capacitorSlow; + WebRtc_Word32 capacitorFast; + WebRtc_Word32 gain; + WebRtc_Word32 gainTable[32]; + WebRtc_Word16 gatePrevious; + WebRtc_Word16 agcMode; + AgcVad_t vadNearend; + AgcVad_t vadFarend; +#ifdef AGC_DEBUG + FILE* logFile; + int frameCounter; +#endif +} DigitalAgc_t; + +WebRtc_Word32 WebRtcAgc_InitDigital(DigitalAgc_t *digitalAgcInst, WebRtc_Word16 agcMode); + +WebRtc_Word32 WebRtcAgc_ProcessDigital(DigitalAgc_t *digitalAgcInst, const WebRtc_Word16 *inNear, + const WebRtc_Word16 *inNear_H, WebRtc_Word16 *out, + WebRtc_Word16 *out_H, WebRtc_UWord32 FS, + WebRtc_Word16 lowLevelSignal); + +WebRtc_Word32 WebRtcAgc_AddFarendToDigital(DigitalAgc_t *digitalAgcInst, const WebRtc_Word16 *inFar, + WebRtc_Word16 nrSamples); + +void WebRtcAgc_InitVad(AgcVad_t *vadInst); + +WebRtc_Word16 WebRtcAgc_ProcessVad(AgcVad_t *vadInst, // (i) VAD state + const WebRtc_Word16 *in, // (i) Speech signal + WebRtc_Word16 nrSamples); // (i) number of samples + +WebRtc_Word32 WebRtcAgc_CalculateGainTable(WebRtc_Word32 *gainTable, // Q16 + WebRtc_Word16 compressionGaindB, // Q0 (in dB) + WebRtc_Word16 targetLevelDbfs,// Q0 (in dB) + WebRtc_UWord8 limiterEnable, WebRtc_Word16 analogTarget); + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AGC_MAIN_SOURCE_ANALOG_AGC_H_ diff --git a/libs/miniwebrtc/audio/processing/agc/gain_control.h b/libs/miniwebrtc/audio/processing/agc/gain_control.h new file mode 100644 index 00000000..8af5c718 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/agc/gain_control.h @@ -0,0 +1,259 @@ +/* + * 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_PROCESSING_AGC_INCLUDE_GAIN_CONTROL_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_AGC_INCLUDE_GAIN_CONTROL_H_ + +#include "typedefs.h" + +// Errors +#define AGC_UNSPECIFIED_ERROR 18000 +#define AGC_UNSUPPORTED_FUNCTION_ERROR 18001 +#define AGC_UNINITIALIZED_ERROR 18002 +#define AGC_NULL_POINTER_ERROR 18003 +#define AGC_BAD_PARAMETER_ERROR 18004 + +// Warnings +#define AGC_BAD_PARAMETER_WARNING 18050 + +enum +{ + kAgcModeUnchanged, + kAgcModeAdaptiveAnalog, + kAgcModeAdaptiveDigital, + kAgcModeFixedDigital +}; + +enum +{ + kAgcFalse = 0, + kAgcTrue +}; + +typedef struct +{ + WebRtc_Word16 targetLevelDbfs; // default 3 (-3 dBOv) + WebRtc_Word16 compressionGaindB; // default 9 dB + WebRtc_UWord8 limiterEnable; // default kAgcTrue (on) +} WebRtcAgc_config_t; + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/* + * This function processes a 10/20ms frame of far-end speech to determine + * if there is active speech. Far-end speech length can be either 10ms or + * 20ms. The length of the input speech vector must be given in samples + * (80/160 when FS=8000, and 160/320 when FS=16000 or FS=32000). + * + * Input: + * - agcInst : AGC instance. + * - inFar : Far-end input speech vector (10 or 20ms) + * - samples : Number of samples in input vector + * + * Return value: + * : 0 - Normal operation. + * : -1 - Error + */ +int WebRtcAgc_AddFarend(void* agcInst, + const WebRtc_Word16* inFar, + WebRtc_Word16 samples); + +/* + * This function processes a 10/20ms frame of microphone speech to determine + * if there is active speech. Microphone speech length can be either 10ms or + * 20ms. The length of the input speech vector must be given in samples + * (80/160 when FS=8000, and 160/320 when FS=16000 or FS=32000). For very low + * input levels, the input signal is increased in level by multiplying and + * overwriting the samples in inMic[]. + * + * This function should be called before any further processing of the + * near-end microphone signal. + * + * Input: + * - agcInst : AGC instance. + * - inMic : Microphone input speech vector (10 or 20 ms) for + * L band + * - inMic_H : Microphone input speech vector (10 or 20 ms) for + * H band + * - samples : Number of samples in input vector + * + * Return value: + * : 0 - Normal operation. + * : -1 - Error + */ +int WebRtcAgc_AddMic(void* agcInst, + WebRtc_Word16* inMic, + WebRtc_Word16* inMic_H, + WebRtc_Word16 samples); + +/* + * This function replaces the analog microphone with a virtual one. + * It is a digital gain applied to the input signal and is used in the + * agcAdaptiveDigital mode where no microphone level is adjustable. + * Microphone speech length can be either 10ms or 20ms. The length of the + * input speech vector must be given in samples (80/160 when FS=8000, and + * 160/320 when FS=16000 or FS=32000). + * + * Input: + * - agcInst : AGC instance. + * - inMic : Microphone input speech vector for (10 or 20 ms) + * L band + * - inMic_H : Microphone input speech vector for (10 or 20 ms) + * H band + * - samples : Number of samples in input vector + * - micLevelIn : Input level of microphone (static) + * + * Output: + * - inMic : Microphone output after processing (L band) + * - inMic_H : Microphone output after processing (H band) + * - micLevelOut : Adjusted microphone level after processing + * + * Return value: + * : 0 - Normal operation. + * : -1 - Error + */ +int WebRtcAgc_VirtualMic(void* agcInst, + WebRtc_Word16* inMic, + WebRtc_Word16* inMic_H, + WebRtc_Word16 samples, + WebRtc_Word32 micLevelIn, + WebRtc_Word32* micLevelOut); + +/* + * This function processes a 10/20ms frame and adjusts (normalizes) the gain + * both analog and digitally. The gain adjustments are done only during + * active periods of speech. The input speech length can be either 10ms or + * 20ms and the output is of the same length. The length of the speech + * vectors must be given in samples (80/160 when FS=8000, and 160/320 when + * FS=16000 or FS=32000). The echo parameter can be used to ensure the AGC will + * not adjust upward in the presence of echo. + * + * This function should be called after processing the near-end microphone + * signal, in any case after any echo cancellation. + * + * Input: + * - agcInst : AGC instance + * - inNear : Near-end input speech vector (10 or 20 ms) for + * L band + * - inNear_H : Near-end input speech vector (10 or 20 ms) for + * H band + * - samples : Number of samples in input/output vector + * - inMicLevel : Current microphone volume level + * - echo : Set to 0 if the signal passed to add_mic is + * almost certainly free of echo; otherwise set + * to 1. If you have no information regarding echo + * set to 0. + * + * Output: + * - outMicLevel : Adjusted microphone volume level + * - out : Gain-adjusted near-end speech vector (L band) + * : May be the same vector as the input. + * - out_H : Gain-adjusted near-end speech vector (H band) + * - saturationWarning : A returned value of 1 indicates a saturation event + * has occurred and the volume cannot be further + * reduced. Otherwise will be set to 0. + * + * Return value: + * : 0 - Normal operation. + * : -1 - Error + */ +int WebRtcAgc_Process(void* agcInst, + const WebRtc_Word16* inNear, + const WebRtc_Word16* inNear_H, + WebRtc_Word16 samples, + WebRtc_Word16* out, + WebRtc_Word16* out_H, + WebRtc_Word32 inMicLevel, + WebRtc_Word32* outMicLevel, + WebRtc_Word16 echo, + WebRtc_UWord8* saturationWarning); + +/* + * This function sets the config parameters (targetLevelDbfs, + * compressionGaindB and limiterEnable). + * + * Input: + * - agcInst : AGC instance + * - config : config struct + * + * Output: + * + * Return value: + * : 0 - Normal operation. + * : -1 - Error + */ +int WebRtcAgc_set_config(void* agcInst, WebRtcAgc_config_t config); + +/* + * This function returns the config parameters (targetLevelDbfs, + * compressionGaindB and limiterEnable). + * + * Input: + * - agcInst : AGC instance + * + * Output: + * - config : config struct + * + * Return value: + * : 0 - Normal operation. + * : -1 - Error + */ +int WebRtcAgc_get_config(void* agcInst, WebRtcAgc_config_t* config); + +/* + * This function creates an AGC instance, which will contain the state + * information for one (duplex) channel. + * + * Return value : AGC instance if successful + * : 0 (i.e., a NULL pointer) if unsuccessful + */ +int WebRtcAgc_Create(void **agcInst); + +/* + * This function frees the AGC instance created at the beginning. + * + * Input: + * - agcInst : AGC instance. + * + * Return value : 0 - Ok + * -1 - Error + */ +int WebRtcAgc_Free(void *agcInst); + +/* + * This function initializes an AGC instance. + * + * Input: + * - agcInst : AGC instance. + * - minLevel : Minimum possible mic level + * - maxLevel : Maximum possible mic level + * - agcMode : 0 - Unchanged + * : 1 - Adaptive Analog Automatic Gain Control -3dBOv + * : 2 - Adaptive Digital Automatic Gain Control -3dBOv + * : 3 - Fixed Digital Gain 0dB + * - fs : Sampling frequency + * + * Return value : 0 - Ok + * -1 - Error + */ +int WebRtcAgc_Init(void *agcInst, + WebRtc_Word32 minLevel, + WebRtc_Word32 maxLevel, + WebRtc_Word16 agcMode, + WebRtc_UWord32 fs); + +#if defined(__cplusplus) +} +#endif + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_AGC_INCLUDE_GAIN_CONTROL_H_ diff --git a/libs/miniwebrtc/audio/processing/audio_buffer.cc b/libs/miniwebrtc/audio/processing/audio_buffer.cc new file mode 100644 index 00000000..a7fb04d9 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/audio_buffer.cc @@ -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. + */ + +#include "audio_buffer.h" + +#include "signal_processing_library.h" + +namespace webrtc { +namespace { + +enum { + kSamplesPer8kHzChannel = 80, + kSamplesPer16kHzChannel = 160, + kSamplesPer32kHzChannel = 320 +}; + +void StereoToMono(const int16_t* left, const int16_t* right, + int16_t* out, int samples_per_channel) { + assert(left != NULL && right != NULL && out != NULL); + for (int i = 0; i < samples_per_channel; i++) { + int32_t data32 = (static_cast(left[i]) + + static_cast(right[i])) >> 1; + + out[i] = WebRtcSpl_SatW32ToW16(data32); + } +} +} // namespace + +struct AudioChannel { + AudioChannel() { + memset(data, 0, sizeof(data)); + } + + int16_t data[kSamplesPer32kHzChannel]; +}; + +struct SplitAudioChannel { + SplitAudioChannel() { + memset(low_pass_data, 0, sizeof(low_pass_data)); + memset(high_pass_data, 0, sizeof(high_pass_data)); + memset(analysis_filter_state1, 0, sizeof(analysis_filter_state1)); + memset(analysis_filter_state2, 0, sizeof(analysis_filter_state2)); + memset(synthesis_filter_state1, 0, sizeof(synthesis_filter_state1)); + memset(synthesis_filter_state2, 0, sizeof(synthesis_filter_state2)); + } + + int16_t low_pass_data[kSamplesPer16kHzChannel]; + int16_t high_pass_data[kSamplesPer16kHzChannel]; + + WebRtc_Word32 analysis_filter_state1[6]; + WebRtc_Word32 analysis_filter_state2[6]; + WebRtc_Word32 synthesis_filter_state1[6]; + WebRtc_Word32 synthesis_filter_state2[6]; +}; + +// TODO(andrew): check range of input parameters? +AudioBuffer::AudioBuffer(int max_num_channels, + int samples_per_channel) + : max_num_channels_(max_num_channels), + num_channels_(0), + num_mixed_channels_(0), + num_mixed_low_pass_channels_(0), + data_was_mixed_(false), + samples_per_channel_(samples_per_channel), + samples_per_split_channel_(samples_per_channel), + reference_copied_(false), + activity_(AudioFrame::kVadUnknown), + is_muted_(false), + data_(NULL), + channels_(NULL), + split_channels_(NULL), + mixed_channels_(NULL), + mixed_low_pass_channels_(NULL), + low_pass_reference_channels_(NULL) { + if (max_num_channels_ > 1) { + channels_.reset(new AudioChannel[max_num_channels_]); + mixed_channels_.reset(new AudioChannel[max_num_channels_]); + mixed_low_pass_channels_.reset(new AudioChannel[max_num_channels_]); + } + low_pass_reference_channels_.reset(new AudioChannel[max_num_channels_]); + + if (samples_per_channel_ == kSamplesPer32kHzChannel) { + split_channels_.reset(new SplitAudioChannel[max_num_channels_]); + samples_per_split_channel_ = kSamplesPer16kHzChannel; + } +} + +AudioBuffer::~AudioBuffer() {} + +int16_t* AudioBuffer::data(int channel) const { + assert(channel >= 0 && channel < num_channels_); + if (data_ != NULL) { + return data_; + } + + return channels_[channel].data; +} + +int16_t* AudioBuffer::low_pass_split_data(int channel) const { + assert(channel >= 0 && channel < num_channels_); + if (split_channels_.get() == NULL) { + return data(channel); + } + + return split_channels_[channel].low_pass_data; +} + +int16_t* AudioBuffer::high_pass_split_data(int channel) const { + assert(channel >= 0 && channel < num_channels_); + if (split_channels_.get() == NULL) { + return NULL; + } + + return split_channels_[channel].high_pass_data; +} + +int16_t* AudioBuffer::mixed_data(int channel) const { + assert(channel >= 0 && channel < num_mixed_channels_); + + return mixed_channels_[channel].data; +} + +int16_t* AudioBuffer::mixed_low_pass_data(int channel) const { + assert(channel >= 0 && channel < num_mixed_low_pass_channels_); + + return mixed_low_pass_channels_[channel].data; +} + +int16_t* AudioBuffer::low_pass_reference(int channel) const { + assert(channel >= 0 && channel < num_channels_); + if (!reference_copied_) { + return NULL; + } + + return low_pass_reference_channels_[channel].data; +} + +WebRtc_Word32* AudioBuffer::analysis_filter_state1(int channel) const { + assert(channel >= 0 && channel < num_channels_); + return split_channels_[channel].analysis_filter_state1; +} + +WebRtc_Word32* AudioBuffer::analysis_filter_state2(int channel) const { + assert(channel >= 0 && channel < num_channels_); + return split_channels_[channel].analysis_filter_state2; +} + +WebRtc_Word32* AudioBuffer::synthesis_filter_state1(int channel) const { + assert(channel >= 0 && channel < num_channels_); + return split_channels_[channel].synthesis_filter_state1; +} + +WebRtc_Word32* AudioBuffer::synthesis_filter_state2(int channel) const { + assert(channel >= 0 && channel < num_channels_); + return split_channels_[channel].synthesis_filter_state2; +} + +void AudioBuffer::set_activity(AudioFrame::VADActivity activity) { + activity_ = activity; +} + +AudioFrame::VADActivity AudioBuffer::activity() const { + return activity_; +} + +bool AudioBuffer::is_muted() const { + return is_muted_; +} + +int AudioBuffer::num_channels() const { + return num_channels_; +} + +int AudioBuffer::samples_per_channel() const { + return samples_per_channel_; +} + +int AudioBuffer::samples_per_split_channel() const { + return samples_per_split_channel_; +} + +// TODO(andrew): Do deinterleaving and mixing in one step? +void AudioBuffer::DeinterleaveFrom(AudioFrame* frame) { + assert(frame->_audioChannel <= max_num_channels_); + assert(frame->_payloadDataLengthInSamples == samples_per_channel_); + + num_channels_ = frame->_audioChannel; + data_was_mixed_ = false; + num_mixed_channels_ = 0; + num_mixed_low_pass_channels_ = 0; + reference_copied_ = false; + activity_ = frame->_vadActivity; + is_muted_ = false; + if (frame->_energy == 0) { + is_muted_ = true; + } + + if (num_channels_ == 1) { + // We can get away with a pointer assignment in this case. + data_ = frame->_payloadData; + return; + } + + int16_t* interleaved = frame->_payloadData; + for (int i = 0; i < num_channels_; i++) { + int16_t* deinterleaved = channels_[i].data; + int interleaved_idx = i; + for (int j = 0; j < samples_per_channel_; j++) { + deinterleaved[j] = interleaved[interleaved_idx]; + interleaved_idx += num_channels_; + } + } +} + +void AudioBuffer::InterleaveTo(AudioFrame* frame, bool data_changed) const { + assert(frame->_audioChannel == num_channels_); + assert(frame->_payloadDataLengthInSamples == samples_per_channel_); + frame->_vadActivity = activity_; + + if (!data_changed) { + return; + } + + if (num_channels_ == 1) { + if (data_was_mixed_) { + memcpy(frame->_payloadData, + channels_[0].data, + sizeof(int16_t) * samples_per_channel_); + } else { + // These should point to the same buffer in this case. + assert(data_ == frame->_payloadData); + } + + return; + } + + int16_t* interleaved = frame->_payloadData; + for (int i = 0; i < num_channels_; i++) { + int16_t* deinterleaved = channels_[i].data; + int interleaved_idx = i; + for (int j = 0; j < samples_per_channel_; j++) { + interleaved[interleaved_idx] = deinterleaved[j]; + interleaved_idx += num_channels_; + } + } +} + +// TODO(andrew): would be good to support the no-mix case with pointer +// assignment. +// TODO(andrew): handle mixing to multiple channels? +void AudioBuffer::Mix(int num_mixed_channels) { + // We currently only support the stereo to mono case. + assert(num_channels_ == 2); + assert(num_mixed_channels == 1); + + StereoToMono(channels_[0].data, + channels_[1].data, + channels_[0].data, + samples_per_channel_); + + num_channels_ = num_mixed_channels; + data_was_mixed_ = true; +} + +void AudioBuffer::CopyAndMix(int num_mixed_channels) { + // We currently only support the stereo to mono case. + assert(num_channels_ == 2); + assert(num_mixed_channels == 1); + + StereoToMono(channels_[0].data, + channels_[1].data, + mixed_channels_[0].data, + samples_per_channel_); + + num_mixed_channels_ = num_mixed_channels; +} + +void AudioBuffer::CopyAndMixLowPass(int num_mixed_channels) { + // We currently only support the stereo to mono case. + assert(num_channels_ == 2); + assert(num_mixed_channels == 1); + + StereoToMono(low_pass_split_data(0), + low_pass_split_data(1), + mixed_low_pass_channels_[0].data, + samples_per_split_channel_); + + num_mixed_low_pass_channels_ = num_mixed_channels; +} + +void AudioBuffer::CopyLowPassToReference() { + reference_copied_ = true; + for (int i = 0; i < num_channels_; i++) { + memcpy(low_pass_reference_channels_[i].data, + low_pass_split_data(i), + sizeof(int16_t) * samples_per_split_channel_); + } +} +} // namespace webrtc diff --git a/libs/miniwebrtc/audio/processing/audio_buffer.h b/libs/miniwebrtc/audio/processing/audio_buffer.h new file mode 100644 index 00000000..87d69727 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/audio_buffer.h @@ -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. + */ + +#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_AUDIO_BUFFER_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_AUDIO_BUFFER_H_ + +#include "module_common_types.h" +#include "scoped_ptr.h" +#include "typedefs.h" + +namespace webrtc { + +struct AudioChannel; +struct SplitAudioChannel; + +class AudioBuffer { + public: + AudioBuffer(int max_num_channels, int samples_per_channel); + virtual ~AudioBuffer(); + + int num_channels() const; + int samples_per_channel() const; + int samples_per_split_channel() const; + + int16_t* data(int channel) const; + int16_t* low_pass_split_data(int channel) const; + int16_t* high_pass_split_data(int channel) const; + int16_t* mixed_data(int channel) const; + int16_t* mixed_low_pass_data(int channel) const; + int16_t* low_pass_reference(int channel) const; + + int32_t* analysis_filter_state1(int channel) const; + int32_t* analysis_filter_state2(int channel) const; + int32_t* synthesis_filter_state1(int channel) const; + int32_t* synthesis_filter_state2(int channel) const; + + void set_activity(AudioFrame::VADActivity activity); + AudioFrame::VADActivity activity() const; + + bool is_muted() const; + + void DeinterleaveFrom(AudioFrame* audioFrame); + void InterleaveTo(AudioFrame* audioFrame) const; + // If |data_changed| is false, only the non-audio data members will be copied + // to |frame|. + void InterleaveTo(AudioFrame* frame, bool data_changed) const; + void Mix(int num_mixed_channels); + void CopyAndMix(int num_mixed_channels); + void CopyAndMixLowPass(int num_mixed_channels); + void CopyLowPassToReference(); + + private: + const int max_num_channels_; + int num_channels_; + int num_mixed_channels_; + int num_mixed_low_pass_channels_; + // Whether the original data was replaced with mixed data. + bool data_was_mixed_; + const int samples_per_channel_; + int samples_per_split_channel_; + bool reference_copied_; + AudioFrame::VADActivity activity_; + bool is_muted_; + + int16_t* data_; + scoped_array channels_; + scoped_array split_channels_; + scoped_array mixed_channels_; + // TODO(andrew): improve this, we don't need the full 32 kHz space here. + scoped_array mixed_low_pass_channels_; + scoped_array low_pass_reference_channels_; +}; +} // namespace webrtc + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_AUDIO_BUFFER_H_ diff --git a/libs/miniwebrtc/audio/processing/audio_processing.h b/libs/miniwebrtc/audio/processing/audio_processing.h new file mode 100644 index 00000000..aefb824d --- /dev/null +++ b/libs/miniwebrtc/audio/processing/audio_processing.h @@ -0,0 +1,595 @@ +/* + * 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_PROCESSING_MAIN_INTERFACE_AUDIO_PROCESSING_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_INTERFACE_AUDIO_PROCESSING_H_ + +#include // size_t + +#include "typedefs.h" +#include "module.h" + +namespace webrtc { + +class AudioFrame; +class EchoCancellation; +class EchoControlMobile; +class GainControl; +class HighPassFilter; +class LevelEstimator; +class NoiseSuppression; +class VoiceDetection; + +// The Audio Processing Module (APM) provides a collection of voice processing +// components designed for real-time communications software. +// +// APM operates on two audio streams on a frame-by-frame basis. Frames of the +// primary stream, on which all processing is applied, are passed to +// |ProcessStream()|. Frames of the reverse direction stream, which are used for +// analysis by some components, are passed to |AnalyzeReverseStream()|. On the +// client-side, this will typically be the near-end (capture) and far-end +// (render) streams, respectively. APM should be placed in the signal chain as +// close to the audio hardware abstraction layer (HAL) as possible. +// +// On the server-side, the reverse stream will normally not be used, with +// processing occurring on each incoming stream. +// +// Component interfaces follow a similar pattern and are accessed through +// corresponding getters in APM. All components are disabled at create-time, +// with default settings that are recommended for most situations. New settings +// can be applied without enabling a component. Enabling a component triggers +// memory allocation and initialization to allow it to start processing the +// streams. +// +// Thread safety is provided with the following assumptions to reduce locking +// overhead: +// 1. The stream getters and setters are called from the same thread as +// ProcessStream(). More precisely, stream functions are never called +// concurrently with ProcessStream(). +// 2. Parameter getters are never called concurrently with the corresponding +// setter. +// +// APM accepts only 16-bit linear PCM audio data in frames of 10 ms. Multiple +// channels should be interleaved. +// +// Usage example, omitting error checking: +// AudioProcessing* apm = AudioProcessing::Create(0); +// apm->set_sample_rate_hz(32000); // Super-wideband processing. +// +// // Mono capture and stereo render. +// apm->set_num_channels(1, 1); +// apm->set_num_reverse_channels(2); +// +// apm->high_pass_filter()->Enable(true); +// +// apm->echo_cancellation()->enable_drift_compensation(false); +// apm->echo_cancellation()->Enable(true); +// +// apm->noise_reduction()->set_level(kHighSuppression); +// apm->noise_reduction()->Enable(true); +// +// apm->gain_control()->set_analog_level_limits(0, 255); +// apm->gain_control()->set_mode(kAdaptiveAnalog); +// apm->gain_control()->Enable(true); +// +// apm->voice_detection()->Enable(true); +// +// // Start a voice call... +// +// // ... Render frame arrives bound for the audio HAL ... +// apm->AnalyzeReverseStream(render_frame); +// +// // ... Capture frame arrives from the audio HAL ... +// // Call required set_stream_ functions. +// apm->set_stream_delay_ms(delay_ms); +// apm->gain_control()->set_stream_analog_level(analog_level); +// +// apm->ProcessStream(capture_frame); +// +// // Call required stream_ functions. +// analog_level = apm->gain_control()->stream_analog_level(); +// has_voice = apm->stream_has_voice(); +// +// // Repeate render and capture processing for the duration of the call... +// // Start a new call... +// apm->Initialize(); +// +// // Close the application... +// AudioProcessing::Destroy(apm); +// apm = NULL; +// +class AudioProcessing : public Module { + public: + // Creates a APM instance, with identifier |id|. Use one instance for every + // primary audio stream requiring processing. On the client-side, this would + // typically be one instance for the near-end stream, and additional instances + // for each far-end stream which requires processing. On the server-side, + // this would typically be one instance for every incoming stream. + static AudioProcessing* Create(int id); + virtual ~AudioProcessing() {}; + + // TODO(andrew): remove this method. We now allow users to delete instances + // directly, useful for scoped_ptr. + // Destroys a |apm| instance. + static void Destroy(AudioProcessing* apm); + + // Initializes internal states, while retaining all user settings. This + // should be called before beginning to process a new audio stream. However, + // it is not necessary to call before processing the first stream after + // creation. + virtual int Initialize() = 0; + + // Sets the sample |rate| in Hz for both the primary and reverse audio + // streams. 8000, 16000 or 32000 Hz are permitted. + virtual int set_sample_rate_hz(int rate) = 0; + virtual int sample_rate_hz() const = 0; + + // Sets the number of channels for the primary audio stream. Input frames must + // contain a number of channels given by |input_channels|, while output frames + // will be returned with number of channels given by |output_channels|. + virtual int set_num_channels(int input_channels, int output_channels) = 0; + virtual int num_input_channels() const = 0; + virtual int num_output_channels() const = 0; + + // Sets the number of channels for the reverse audio stream. Input frames must + // contain a number of channels given by |channels|. + virtual int set_num_reverse_channels(int channels) = 0; + virtual int num_reverse_channels() const = 0; + + // Processes a 10 ms |frame| of the primary audio stream. On the client-side, + // this is the near-end (or captured) audio. + // + // If needed for enabled functionality, any function with the set_stream_ tag + // must be called prior to processing the current frame. Any getter function + // with the stream_ tag which is needed should be called after processing. + // + // The |_frequencyInHz|, |_audioChannel|, and |_payloadDataLengthInSamples| + // members of |frame| must be valid, and correspond to settings supplied + // to APM. + virtual int ProcessStream(AudioFrame* frame) = 0; + + // Analyzes a 10 ms |frame| of the reverse direction audio stream. The frame + // will not be modified. On the client-side, this is the far-end (or to be + // rendered) audio. + // + // It is only necessary to provide this if echo processing is enabled, as the + // reverse stream forms the echo reference signal. It is recommended, but not + // necessary, to provide if gain control is enabled. On the server-side this + // typically will not be used. If you're not sure what to pass in here, + // chances are you don't need to use it. + // + // The |_frequencyInHz|, |_audioChannel|, and |_payloadDataLengthInSamples| + // members of |frame| must be valid. + // + // TODO(ajm): add const to input; requires an implementation fix. + virtual int AnalyzeReverseStream(AudioFrame* frame) = 0; + + // This must be called if and only if echo processing is enabled. + // + // Sets the |delay| in ms between AnalyzeReverseStream() receiving a far-end + // frame and ProcessStream() receiving a near-end frame containing the + // corresponding echo. On the client-side this can be expressed as + // delay = (t_render - t_analyze) + (t_process - t_capture) + // where, + // - t_analyze is the time a frame is passed to AnalyzeReverseStream() and + // t_render is the time the first sample of the same frame is rendered by + // the audio hardware. + // - t_capture is the time the first sample of a frame is captured by the + // audio hardware and t_pull is the time the same frame is passed to + // ProcessStream(). + virtual int set_stream_delay_ms(int delay) = 0; + virtual int stream_delay_ms() const = 0; + + // Starts recording debugging information to a file specified by |filename|, + // a NULL-terminated string. If there is an ongoing recording, the old file + // will be closed, and recording will continue in the newly specified file. + // An already existing file will be overwritten without warning. + static const size_t kMaxFilenameSize = 1024; + virtual int StartDebugRecording(const char filename[kMaxFilenameSize]) = 0; + + // Stops recording debugging information, and closes the file. Recording + // cannot be resumed in the same file (without overwriting it). + virtual int StopDebugRecording() = 0; + + // These provide access to the component interfaces and should never return + // NULL. The pointers will be valid for the lifetime of the APM instance. + // The memory for these objects is entirely managed internally. + virtual EchoCancellation* echo_cancellation() const = 0; + virtual EchoControlMobile* echo_control_mobile() const = 0; + virtual GainControl* gain_control() const = 0; + virtual HighPassFilter* high_pass_filter() const = 0; + virtual LevelEstimator* level_estimator() const = 0; + virtual NoiseSuppression* noise_suppression() const = 0; + virtual VoiceDetection* voice_detection() const = 0; + + struct Statistic { + int instant; // Instantaneous value. + int average; // Long-term average. + int maximum; // Long-term maximum. + int minimum; // Long-term minimum. + }; + + enum Error { + // Fatal errors. + kNoError = 0, + kUnspecifiedError = -1, + kCreationFailedError = -2, + kUnsupportedComponentError = -3, + kUnsupportedFunctionError = -4, + kNullPointerError = -5, + kBadParameterError = -6, + kBadSampleRateError = -7, + kBadDataLengthError = -8, + kBadNumberChannelsError = -9, + kFileError = -10, + kStreamParameterNotSetError = -11, + kNotEnabledError = -12, + + // Warnings are non-fatal. + // This results when a set_stream_ parameter is out of range. Processing + // will continue, but the parameter may have been truncated. + kBadStreamParameterWarning = -13 + }; + + // Inherited from Module. + virtual WebRtc_Word32 TimeUntilNextProcess() { return -1; }; + virtual WebRtc_Word32 Process() { return -1; }; +}; + +// The acoustic echo cancellation (AEC) component provides better performance +// than AECM but also requires more processing power and is dependent on delay +// stability and reporting accuracy. As such it is well-suited and recommended +// for PC and IP phone applications. +// +// Not recommended to be enabled on the server-side. +class EchoCancellation { + public: + // EchoCancellation and EchoControlMobile may not be enabled simultaneously. + // Enabling one will disable the other. + virtual int Enable(bool enable) = 0; + virtual bool is_enabled() const = 0; + + // Differences in clock speed on the primary and reverse streams can impact + // the AEC performance. On the client-side, this could be seen when different + // render and capture devices are used, particularly with webcams. + // + // This enables a compensation mechanism, and requires that + // |set_device_sample_rate_hz()| and |set_stream_drift_samples()| be called. + virtual int enable_drift_compensation(bool enable) = 0; + virtual bool is_drift_compensation_enabled() const = 0; + + // Provides the sampling rate of the audio devices. It is assumed the render + // and capture devices use the same nominal sample rate. Required if and only + // if drift compensation is enabled. + virtual int set_device_sample_rate_hz(int rate) = 0; + virtual int device_sample_rate_hz() const = 0; + + // Sets the difference between the number of samples rendered and captured by + // the audio devices since the last call to |ProcessStream()|. Must be called + // if and only if drift compensation is enabled, prior to |ProcessStream()|. + virtual int set_stream_drift_samples(int drift) = 0; + virtual int stream_drift_samples() const = 0; + + enum SuppressionLevel { + kLowSuppression, + kModerateSuppression, + kHighSuppression + }; + + // Sets the aggressiveness of the suppressor. A higher level trades off + // double-talk performance for increased echo suppression. + virtual int set_suppression_level(SuppressionLevel level) = 0; + virtual SuppressionLevel suppression_level() const = 0; + + // Returns false if the current frame almost certainly contains no echo + // and true if it _might_ contain echo. + virtual bool stream_has_echo() const = 0; + + // Enables the computation of various echo metrics. These are obtained + // through |GetMetrics()|. + virtual int enable_metrics(bool enable) = 0; + virtual bool are_metrics_enabled() const = 0; + + // Each statistic is reported in dB. + // P_far: Far-end (render) signal power. + // P_echo: Near-end (capture) echo signal power. + // P_out: Signal power at the output of the AEC. + // P_a: Internal signal power at the point before the AEC's non-linear + // processor. + struct Metrics { + // RERL = ERL + ERLE + AudioProcessing::Statistic residual_echo_return_loss; + + // ERL = 10log_10(P_far / P_echo) + AudioProcessing::Statistic echo_return_loss; + + // ERLE = 10log_10(P_echo / P_out) + AudioProcessing::Statistic echo_return_loss_enhancement; + + // (Pre non-linear processing suppression) A_NLP = 10log_10(P_echo / P_a) + AudioProcessing::Statistic a_nlp; + }; + + // TODO(ajm): discuss the metrics update period. + virtual int GetMetrics(Metrics* metrics) = 0; + + // Enables computation and logging of delay values. Statistics are obtained + // through |GetDelayMetrics()|. + virtual int enable_delay_logging(bool enable) = 0; + virtual bool is_delay_logging_enabled() const = 0; + + // The delay metrics consists of the delay |median| and the delay standard + // deviation |std|. The values are averaged over the time period since the + // last call to |GetDelayMetrics()|. + virtual int GetDelayMetrics(int* median, int* std) = 0; + + protected: + virtual ~EchoCancellation() {}; +}; + +// The acoustic echo control for mobile (AECM) component is a low complexity +// robust option intended for use on mobile devices. +// +// Not recommended to be enabled on the server-side. +class EchoControlMobile { + public: + // EchoCancellation and EchoControlMobile may not be enabled simultaneously. + // Enabling one will disable the other. + virtual int Enable(bool enable) = 0; + virtual bool is_enabled() const = 0; + + // Recommended settings for particular audio routes. In general, the louder + // the echo is expected to be, the higher this value should be set. The + // preferred setting may vary from device to device. + enum RoutingMode { + kQuietEarpieceOrHeadset, + kEarpiece, + kLoudEarpiece, + kSpeakerphone, + kLoudSpeakerphone + }; + + // Sets echo control appropriate for the audio routing |mode| on the device. + // It can and should be updated during a call if the audio routing changes. + virtual int set_routing_mode(RoutingMode mode) = 0; + virtual RoutingMode routing_mode() const = 0; + + // Comfort noise replaces suppressed background noise to maintain a + // consistent signal level. + virtual int enable_comfort_noise(bool enable) = 0; + virtual bool is_comfort_noise_enabled() const = 0; + + // A typical use case is to initialize the component with an echo path from a + // previous call. The echo path is retrieved using |GetEchoPath()|, typically + // at the end of a call. The data can then be stored for later use as an + // initializer before the next call, using |SetEchoPath()|. + // + // Controlling the echo path this way requires the data |size_bytes| to match + // the internal echo path size. This size can be acquired using + // |echo_path_size_bytes()|. |SetEchoPath()| causes an entire reset, worth + // noting if it is to be called during an ongoing call. + // + // It is possible that version incompatibilities may result in a stored echo + // path of the incorrect size. In this case, the stored path should be + // discarded. + virtual int SetEchoPath(const void* echo_path, size_t size_bytes) = 0; + virtual int GetEchoPath(void* echo_path, size_t size_bytes) const = 0; + + // The returned path size is guaranteed not to change for the lifetime of + // the application. + static size_t echo_path_size_bytes(); + + protected: + virtual ~EchoControlMobile() {}; +}; + +// The automatic gain control (AGC) component brings the signal to an +// appropriate range. This is done by applying a digital gain directly and, in +// the analog mode, prescribing an analog gain to be applied at the audio HAL. +// +// Recommended to be enabled on the client-side. +class GainControl { + public: + virtual int Enable(bool enable) = 0; + virtual bool is_enabled() const = 0; + + // When an analog mode is set, this must be called prior to |ProcessStream()| + // to pass the current analog level from the audio HAL. Must be within the + // range provided to |set_analog_level_limits()|. + virtual int set_stream_analog_level(int level) = 0; + + // When an analog mode is set, this should be called after |ProcessStream()| + // to obtain the recommended new analog level for the audio HAL. It is the + // users responsibility to apply this level. + virtual int stream_analog_level() = 0; + + enum Mode { + // Adaptive mode intended for use if an analog volume control is available + // on the capture device. It will require the user to provide coupling + // between the OS mixer controls and AGC through the |stream_analog_level()| + // functions. + // + // It consists of an analog gain prescription for the audio device and a + // digital compression stage. + kAdaptiveAnalog, + + // Adaptive mode intended for situations in which an analog volume control + // is unavailable. It operates in a similar fashion to the adaptive analog + // mode, but with scaling instead applied in the digital domain. As with + // the analog mode, it additionally uses a digital compression stage. + kAdaptiveDigital, + + // Fixed mode which enables only the digital compression stage also used by + // the two adaptive modes. + // + // It is distinguished from the adaptive modes by considering only a + // short time-window of the input signal. It applies a fixed gain through + // most of the input level range, and compresses (gradually reduces gain + // with increasing level) the input signal at higher levels. This mode is + // preferred on embedded devices where the capture signal level is + // predictable, so that a known gain can be applied. + kFixedDigital + }; + + virtual int set_mode(Mode mode) = 0; + virtual Mode mode() const = 0; + + // Sets the target peak |level| (or envelope) of the AGC in dBFs (decibels + // from digital full-scale). The convention is to use positive values. For + // instance, passing in a value of 3 corresponds to -3 dBFs, or a target + // level 3 dB below full-scale. Limited to [0, 31]. + // + // TODO(ajm): use a negative value here instead, if/when VoE will similarly + // update its interface. + virtual int set_target_level_dbfs(int level) = 0; + virtual int target_level_dbfs() const = 0; + + // Sets the maximum |gain| the digital compression stage may apply, in dB. A + // higher number corresponds to greater compression, while a value of 0 will + // leave the signal uncompressed. Limited to [0, 90]. + virtual int set_compression_gain_db(int gain) = 0; + virtual int compression_gain_db() const = 0; + + // When enabled, the compression stage will hard limit the signal to the + // target level. Otherwise, the signal will be compressed but not limited + // above the target level. + virtual int enable_limiter(bool enable) = 0; + virtual bool is_limiter_enabled() const = 0; + + // Sets the |minimum| and |maximum| analog levels of the audio capture device. + // Must be set if and only if an analog mode is used. Limited to [0, 65535]. + virtual int set_analog_level_limits(int minimum, + int maximum) = 0; + virtual int analog_level_minimum() const = 0; + virtual int analog_level_maximum() const = 0; + + // Returns true if the AGC has detected a saturation event (period where the + // signal reaches digital full-scale) in the current frame and the analog + // level cannot be reduced. + // + // This could be used as an indicator to reduce or disable analog mic gain at + // the audio HAL. + virtual bool stream_is_saturated() const = 0; + + protected: + virtual ~GainControl() {}; +}; + +// A filtering component which removes DC offset and low-frequency noise. +// Recommended to be enabled on the client-side. +class HighPassFilter { + public: + virtual int Enable(bool enable) = 0; + virtual bool is_enabled() const = 0; + + protected: + virtual ~HighPassFilter() {}; +}; + +// An estimation component used to retrieve level metrics. +class LevelEstimator { + public: + virtual int Enable(bool enable) = 0; + virtual bool is_enabled() const = 0; + + // Returns the root mean square (RMS) level in dBFs (decibels from digital + // full-scale), or alternately dBov. It is computed over all primary stream + // frames since the last call to RMS(). The returned value is positive but + // should be interpreted as negative. It is constrained to [0, 127]. + // + // The computation follows: + // http://tools.ietf.org/html/draft-ietf-avtext-client-to-mixer-audio-level-05 + // with the intent that it can provide the RTP audio level indication. + // + // Frames passed to ProcessStream() with an |_energy| of zero are considered + // to have been muted. The RMS of the frame will be interpreted as -127. + virtual int RMS() = 0; + + protected: + virtual ~LevelEstimator() {}; +}; + +// The noise suppression (NS) component attempts to remove noise while +// retaining speech. Recommended to be enabled on the client-side. +// +// Recommended to be enabled on the client-side. +class NoiseSuppression { + public: + virtual int Enable(bool enable) = 0; + virtual bool is_enabled() const = 0; + + // Determines the aggressiveness of the suppression. Increasing the level + // will reduce the noise level at the expense of a higher speech distortion. + enum Level { + kLow, + kModerate, + kHigh, + kVeryHigh + }; + + virtual int set_level(Level level) = 0; + virtual Level level() const = 0; + + protected: + virtual ~NoiseSuppression() {}; +}; + +// The voice activity detection (VAD) component analyzes the stream to +// determine if voice is present. A facility is also provided to pass in an +// external VAD decision. +// +// In addition to |stream_has_voice()| the VAD decision is provided through the +// |AudioFrame| passed to |ProcessStream()|. The |_vadActivity| member will be +// modified to reflect the current decision. +class VoiceDetection { + public: + virtual int Enable(bool enable) = 0; + virtual bool is_enabled() const = 0; + + // Returns true if voice is detected in the current frame. Should be called + // after |ProcessStream()|. + virtual bool stream_has_voice() const = 0; + + // Some of the APM functionality requires a VAD decision. In the case that + // a decision is externally available for the current frame, it can be passed + // in here, before |ProcessStream()| is called. + // + // VoiceDetection does _not_ need to be enabled to use this. If it happens to + // be enabled, detection will be skipped for any frame in which an external + // VAD decision is provided. + virtual int set_stream_has_voice(bool has_voice) = 0; + + // Specifies the likelihood that a frame will be declared to contain voice. + // A higher value makes it more likely that speech will not be clipped, at + // the expense of more noise being detected as voice. + enum Likelihood { + kVeryLowLikelihood, + kLowLikelihood, + kModerateLikelihood, + kHighLikelihood + }; + + virtual int set_likelihood(Likelihood likelihood) = 0; + virtual Likelihood likelihood() const = 0; + + // Sets the |size| of the frames in ms on which the VAD will operate. Larger + // frames will improve detection accuracy, but reduce the frequency of + // updates. + // + // This does not impact the size of frames passed to |ProcessStream()|. + virtual int set_frame_size_ms(int size) = 0; + virtual int frame_size_ms() const = 0; + + protected: + virtual ~VoiceDetection() {}; +}; +} // namespace webrtc + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_INTERFACE_AUDIO_PROCESSING_H_ diff --git a/libs/miniwebrtc/audio/processing/audio_processing_impl.cc b/libs/miniwebrtc/audio/processing/audio_processing_impl.cc new file mode 100644 index 00000000..35d266d2 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/audio_processing_impl.cc @@ -0,0 +1,643 @@ +/* + * 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 "audio_processing_impl.h" + +#include + +#include "audio_buffer.h" +#include "critical_section_wrapper.h" +#include "echo_cancellation_impl.h" +#include "echo_control_mobile_impl.h" +#include "file_wrapper.h" +#include "high_pass_filter_impl.h" +#include "gain_control_impl.h" +#include "level_estimator_impl.h" +#include "module_common_types.h" +#include "noise_suppression_impl.h" +#include "processing_component.h" +#include "splitting_filter.h" +#include "voice_detection_impl.h" + +#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP +// Files generated at build-time by the protobuf compiler. +#ifdef WEBRTC_ANDROID +#include "external/webrtc/src/modules/audio_processing/debug.pb.h" +#else +#include "webrtc/audio_processing/debug.pb.h" +#endif +#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP + +namespace webrtc { +AudioProcessing* AudioProcessing::Create(int id) { + + AudioProcessingImpl* apm = new AudioProcessingImpl(id); + if (apm->Initialize() != kNoError) { + delete apm; + apm = NULL; + } + + return apm; +} + +void AudioProcessing::Destroy(AudioProcessing* apm) { + delete static_cast(apm); +} + +AudioProcessingImpl::AudioProcessingImpl(int id) + : id_(id), + echo_cancellation_(NULL), + echo_control_mobile_(NULL), + gain_control_(NULL), + high_pass_filter_(NULL), + level_estimator_(NULL), + noise_suppression_(NULL), + voice_detection_(NULL), + crit_(CriticalSectionWrapper::CreateCriticalSection()), + render_audio_(NULL), + capture_audio_(NULL), +#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP + debug_file_(FileWrapper::Create()), + event_msg_(new audioproc::Event()), +#endif + sample_rate_hz_(kSampleRate16kHz), + split_sample_rate_hz_(kSampleRate16kHz), + samples_per_channel_(sample_rate_hz_ / 100), + stream_delay_ms_(0), + was_stream_delay_set_(false), + num_reverse_channels_(1), + num_input_channels_(1), + num_output_channels_(1) { + + echo_cancellation_ = new EchoCancellationImpl(this); + component_list_.push_back(echo_cancellation_); + + echo_control_mobile_ = new EchoControlMobileImpl(this); + component_list_.push_back(echo_control_mobile_); + + gain_control_ = new GainControlImpl(this); + component_list_.push_back(gain_control_); + + high_pass_filter_ = new HighPassFilterImpl(this); + component_list_.push_back(high_pass_filter_); + + level_estimator_ = new LevelEstimatorImpl(this); + component_list_.push_back(level_estimator_); + + noise_suppression_ = new NoiseSuppressionImpl(this); + component_list_.push_back(noise_suppression_); + + voice_detection_ = new VoiceDetectionImpl(this); + component_list_.push_back(voice_detection_); +} + +AudioProcessingImpl::~AudioProcessingImpl() { + while (!component_list_.empty()) { + ProcessingComponent* component = component_list_.front(); + component->Destroy(); + delete component; + component_list_.pop_front(); + } + +#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP + if (debug_file_->Open()) { + debug_file_->CloseFile(); + } +#endif + + delete crit_; + crit_ = NULL; + + if (render_audio_) { + delete render_audio_; + render_audio_ = NULL; + } + + if (capture_audio_) { + delete capture_audio_; + capture_audio_ = NULL; + } +} + +CriticalSectionWrapper* AudioProcessingImpl::crit() const { + return crit_; +} + +int AudioProcessingImpl::split_sample_rate_hz() const { + return split_sample_rate_hz_; +} + +int AudioProcessingImpl::Initialize() { + CriticalSectionScoped crit_scoped(crit_); + return InitializeLocked(); +} + +int AudioProcessingImpl::InitializeLocked() { + if (render_audio_ != NULL) { + delete render_audio_; + render_audio_ = NULL; + } + + if (capture_audio_ != NULL) { + delete capture_audio_; + capture_audio_ = NULL; + } + + render_audio_ = new AudioBuffer(num_reverse_channels_, + samples_per_channel_); + capture_audio_ = new AudioBuffer(num_input_channels_, + samples_per_channel_); + + was_stream_delay_set_ = false; + + // Initialize all components. + std::list::iterator it; + for (it = component_list_.begin(); it != component_list_.end(); it++) { + int err = (*it)->Initialize(); + if (err != kNoError) { + return err; + } + } + +#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP + if (debug_file_->Open()) { + int err = WriteInitMessage(); + if (err != kNoError) { + return err; + } + } +#endif + + return kNoError; +} + +int AudioProcessingImpl::set_sample_rate_hz(int rate) { + CriticalSectionScoped crit_scoped(crit_); + if (rate != kSampleRate8kHz && + rate != kSampleRate16kHz && + rate != kSampleRate32kHz) { + return kBadParameterError; + } + + sample_rate_hz_ = rate; + samples_per_channel_ = rate / 100; + + if (sample_rate_hz_ == kSampleRate32kHz) { + split_sample_rate_hz_ = kSampleRate16kHz; + } else { + split_sample_rate_hz_ = sample_rate_hz_; + } + + return InitializeLocked(); +} + +int AudioProcessingImpl::sample_rate_hz() const { + return sample_rate_hz_; +} + +int AudioProcessingImpl::set_num_reverse_channels(int channels) { + CriticalSectionScoped crit_scoped(crit_); + // Only stereo supported currently. + if (channels > 2 || channels < 1) { + return kBadParameterError; + } + + num_reverse_channels_ = channels; + + return InitializeLocked(); +} + +int AudioProcessingImpl::num_reverse_channels() const { + return num_reverse_channels_; +} + +int AudioProcessingImpl::set_num_channels( + int input_channels, + int output_channels) { + CriticalSectionScoped crit_scoped(crit_); + if (output_channels > input_channels) { + return kBadParameterError; + } + + // Only stereo supported currently. + if (input_channels > 2 || input_channels < 1) { + return kBadParameterError; + } + + if (output_channels > 2 || output_channels < 1) { + return kBadParameterError; + } + + num_input_channels_ = input_channels; + num_output_channels_ = output_channels; + + return InitializeLocked(); +} + +int AudioProcessingImpl::num_input_channels() const { + return num_input_channels_; +} + +int AudioProcessingImpl::num_output_channels() const { + return num_output_channels_; +} + +int AudioProcessingImpl::ProcessStream(AudioFrame* frame) { + CriticalSectionScoped crit_scoped(crit_); + int err = kNoError; + + if (frame == NULL) { + return kNullPointerError; + } + + if (frame->_frequencyInHz != sample_rate_hz_) { + return kBadSampleRateError; + } + + if (frame->_audioChannel != num_input_channels_) { + return kBadNumberChannelsError; + } + + if (frame->_payloadDataLengthInSamples != samples_per_channel_) { + return kBadDataLengthError; + } + +#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP + if (debug_file_->Open()) { + event_msg_->set_type(audioproc::Event::STREAM); + audioproc::Stream* msg = event_msg_->mutable_stream(); + const size_t data_size = sizeof(int16_t) * + frame->_payloadDataLengthInSamples * + frame->_audioChannel; + msg->set_input_data(frame->_payloadData, data_size); + msg->set_delay(stream_delay_ms_); + msg->set_drift(echo_cancellation_->stream_drift_samples()); + msg->set_level(gain_control_->stream_analog_level()); + } +#endif + + capture_audio_->DeinterleaveFrom(frame); + + // TODO(ajm): experiment with mixing and AEC placement. + if (num_output_channels_ < num_input_channels_) { + capture_audio_->Mix(num_output_channels_); + frame->_audioChannel = num_output_channels_; + } + + bool data_changed = stream_data_changed(); + if (analysis_needed(data_changed)) { + for (int i = 0; i < num_output_channels_; i++) { + // Split into a low and high band. + SplittingFilterAnalysis(capture_audio_->data(i), + capture_audio_->low_pass_split_data(i), + capture_audio_->high_pass_split_data(i), + capture_audio_->analysis_filter_state1(i), + capture_audio_->analysis_filter_state2(i)); + } + } + + err = high_pass_filter_->ProcessCaptureAudio(capture_audio_); + if (err != kNoError) { + return err; + } + + err = gain_control_->AnalyzeCaptureAudio(capture_audio_); + if (err != kNoError) { + return err; + } + + err = echo_cancellation_->ProcessCaptureAudio(capture_audio_); + if (err != kNoError) { + return err; + } + + if (echo_control_mobile_->is_enabled() && + noise_suppression_->is_enabled()) { + capture_audio_->CopyLowPassToReference(); + } + + err = noise_suppression_->ProcessCaptureAudio(capture_audio_); + if (err != kNoError) { + return err; + } + + err = echo_control_mobile_->ProcessCaptureAudio(capture_audio_); + if (err != kNoError) { + return err; + } + + err = voice_detection_->ProcessCaptureAudio(capture_audio_); + if (err != kNoError) { + return err; + } + + err = gain_control_->ProcessCaptureAudio(capture_audio_); + if (err != kNoError) { + return err; + } + + if (synthesis_needed(data_changed)) { + for (int i = 0; i < num_output_channels_; i++) { + // Recombine low and high bands. + SplittingFilterSynthesis(capture_audio_->low_pass_split_data(i), + capture_audio_->high_pass_split_data(i), + capture_audio_->data(i), + capture_audio_->synthesis_filter_state1(i), + capture_audio_->synthesis_filter_state2(i)); + } + } + + // The level estimator operates on the recombined data. + err = level_estimator_->ProcessStream(capture_audio_); + if (err != kNoError) { + return err; + } + + capture_audio_->InterleaveTo(frame, data_changed); + +#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP + if (debug_file_->Open()) { + audioproc::Stream* msg = event_msg_->mutable_stream(); + const size_t data_size = sizeof(int16_t) * + frame->_payloadDataLengthInSamples * + frame->_audioChannel; + msg->set_output_data(frame->_payloadData, data_size); + err = WriteMessageToDebugFile(); + if (err != kNoError) { + return err; + } + } +#endif + + was_stream_delay_set_ = false; + return kNoError; +} + +int AudioProcessingImpl::AnalyzeReverseStream(AudioFrame* frame) { + CriticalSectionScoped crit_scoped(crit_); + int err = kNoError; + + if (frame == NULL) { + return kNullPointerError; + } + + if (frame->_frequencyInHz != sample_rate_hz_) { + return kBadSampleRateError; + } + + if (frame->_audioChannel != num_reverse_channels_) { + return kBadNumberChannelsError; + } + + if (frame->_payloadDataLengthInSamples != samples_per_channel_) { + return kBadDataLengthError; + } + +#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP + if (debug_file_->Open()) { + event_msg_->set_type(audioproc::Event::REVERSE_STREAM); + audioproc::ReverseStream* msg = event_msg_->mutable_reverse_stream(); + const size_t data_size = sizeof(int16_t) * + frame->_payloadDataLengthInSamples * + frame->_audioChannel; + msg->set_data(frame->_payloadData, data_size); + err = WriteMessageToDebugFile(); + if (err != kNoError) { + return err; + } + } +#endif + + render_audio_->DeinterleaveFrom(frame); + + // TODO(ajm): turn the splitting filter into a component? + if (sample_rate_hz_ == kSampleRate32kHz) { + for (int i = 0; i < num_reverse_channels_; i++) { + // Split into low and high band. + SplittingFilterAnalysis(render_audio_->data(i), + render_audio_->low_pass_split_data(i), + render_audio_->high_pass_split_data(i), + render_audio_->analysis_filter_state1(i), + render_audio_->analysis_filter_state2(i)); + } + } + + // TODO(ajm): warnings possible from components? + err = echo_cancellation_->ProcessRenderAudio(render_audio_); + if (err != kNoError) { + return err; + } + + err = echo_control_mobile_->ProcessRenderAudio(render_audio_); + if (err != kNoError) { + return err; + } + + err = gain_control_->ProcessRenderAudio(render_audio_); + if (err != kNoError) { + return err; + } + + return err; // TODO(ajm): this is for returning warnings; necessary? +} + +int AudioProcessingImpl::set_stream_delay_ms(int delay) { + was_stream_delay_set_ = true; + if (delay < 0) { + return kBadParameterError; + } + + // TODO(ajm): the max is rather arbitrarily chosen; investigate. + if (delay > 500) { + stream_delay_ms_ = 500; + return kBadStreamParameterWarning; + } + + stream_delay_ms_ = delay; + return kNoError; +} + +int AudioProcessingImpl::stream_delay_ms() const { + return stream_delay_ms_; +} + +bool AudioProcessingImpl::was_stream_delay_set() const { + return was_stream_delay_set_; +} + +int AudioProcessingImpl::StartDebugRecording( + const char filename[AudioProcessing::kMaxFilenameSize]) { + CriticalSectionScoped crit_scoped(crit_); + assert(kMaxFilenameSize == FileWrapper::kMaxFileNameSize); + + if (filename == NULL) { + return kNullPointerError; + } + +#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP + // Stop any ongoing recording. + if (debug_file_->Open()) { + if (debug_file_->CloseFile() == -1) { + return kFileError; + } + } + + if (debug_file_->OpenFile(filename, false) == -1) { + debug_file_->CloseFile(); + return kFileError; + } + + int err = WriteInitMessage(); + if (err != kNoError) { + return err; + } + return kNoError; +#else + return kUnsupportedFunctionError; +#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP +} + +int AudioProcessingImpl::StopDebugRecording() { + CriticalSectionScoped crit_scoped(crit_); + +#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP + // We just return if recording hasn't started. + if (debug_file_->Open()) { + if (debug_file_->CloseFile() == -1) { + return kFileError; + } + } + return kNoError; +#else + return kUnsupportedFunctionError; +#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP +} + +EchoCancellation* AudioProcessingImpl::echo_cancellation() const { + return echo_cancellation_; +} + +EchoControlMobile* AudioProcessingImpl::echo_control_mobile() const { + return echo_control_mobile_; +} + +GainControl* AudioProcessingImpl::gain_control() const { + return gain_control_; +} + +HighPassFilter* AudioProcessingImpl::high_pass_filter() const { + return high_pass_filter_; +} + +LevelEstimator* AudioProcessingImpl::level_estimator() const { + return level_estimator_; +} + +NoiseSuppression* AudioProcessingImpl::noise_suppression() const { + return noise_suppression_; +} + +VoiceDetection* AudioProcessingImpl::voice_detection() const { + return voice_detection_; +} + +WebRtc_Word32 AudioProcessingImpl::ChangeUniqueId(const WebRtc_Word32 id) { + CriticalSectionScoped crit_scoped(crit_); + id_ = id; + + return kNoError; +} + +bool AudioProcessingImpl::stream_data_changed() const { + int enabled_count = 0; + std::list::const_iterator it; + for (it = component_list_.begin(); it != component_list_.end(); it++) { + if ((*it)->is_component_enabled()) { + enabled_count++; + } + } + + // Data is unchanged if no components are enabled, or if only level_estimator_ + // or voice_detection_ is enabled. + if (enabled_count == 0) { + return false; + } else if (enabled_count == 1) { + if (level_estimator_->is_enabled() || voice_detection_->is_enabled()) { + return false; + } + } else if (enabled_count == 2) { + if (level_estimator_->is_enabled() && voice_detection_->is_enabled()) { + return false; + } + } + return true; +} + +bool AudioProcessingImpl::synthesis_needed(bool stream_data_changed) const { + return (stream_data_changed && sample_rate_hz_ == kSampleRate32kHz); +} + +bool AudioProcessingImpl::analysis_needed(bool stream_data_changed) const { + if (!stream_data_changed && !voice_detection_->is_enabled()) { + // Only level_estimator_ is enabled. + return false; + } else if (sample_rate_hz_ == kSampleRate32kHz) { + // Something besides level_estimator_ is enabled, and we have super-wb. + return true; + } + return false; +} + +#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP +int AudioProcessingImpl::WriteMessageToDebugFile() { + int32_t size = event_msg_->ByteSize(); + if (size <= 0) { + return kUnspecifiedError; + } +#if defined(WEBRTC_BIG_ENDIAN) + // TODO(ajm): Use little-endian "on the wire". For the moment, we can be + // pretty safe in assuming little-endian. +#endif + + if (!event_msg_->SerializeToString(&event_str_)) { + return kUnspecifiedError; + } + + // Write message preceded by its size. + if (!debug_file_->Write(&size, sizeof(int32_t))) { + return kFileError; + } + if (!debug_file_->Write(event_str_.data(), event_str_.length())) { + return kFileError; + } + + event_msg_->Clear(); + + return 0; +} + +int AudioProcessingImpl::WriteInitMessage() { + event_msg_->set_type(audioproc::Event::INIT); + audioproc::Init* msg = event_msg_->mutable_init(); + msg->set_sample_rate(sample_rate_hz_); + msg->set_device_sample_rate(echo_cancellation_->device_sample_rate_hz()); + msg->set_num_input_channels(num_input_channels_); + msg->set_num_output_channels(num_output_channels_); + msg->set_num_reverse_channels(num_reverse_channels_); + + int err = WriteMessageToDebugFile(); + if (err != kNoError) { + return err; + } + + return kNoError; +} +#endif // WEBRTC_AUDIOPROC_DEBUG_DUMP +} // namespace webrtc diff --git a/libs/miniwebrtc/audio/processing/audio_processing_impl.h b/libs/miniwebrtc/audio/processing/audio_processing_impl.h new file mode 100644 index 00000000..c1ab4763 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/audio_processing_impl.h @@ -0,0 +1,126 @@ +/* + * 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_PROCESSING_MAIN_SOURCE_AUDIO_PROCESSING_IMPL_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_AUDIO_PROCESSING_IMPL_H_ + +#include "audio_processing.h" + +#include +#include + +#include "scoped_ptr.h" + +namespace webrtc { +class AudioBuffer; +class CriticalSectionWrapper; +class EchoCancellationImpl; +class EchoControlMobileImpl; +class FileWrapper; +class GainControlImpl; +class HighPassFilterImpl; +class LevelEstimatorImpl; +class NoiseSuppressionImpl; +class ProcessingComponent; +class VoiceDetectionImpl; + +#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP +namespace audioproc { + +class Event; + +} // namespace audioproc +#endif + +class AudioProcessingImpl : public AudioProcessing { + public: + enum { + kSampleRate8kHz = 8000, + kSampleRate16kHz = 16000, + kSampleRate32kHz = 32000 + }; + + explicit AudioProcessingImpl(int id); + virtual ~AudioProcessingImpl(); + + CriticalSectionWrapper* crit() const; + + int split_sample_rate_hz() const; + bool was_stream_delay_set() const; + + // AudioProcessing methods. + virtual int Initialize(); + virtual int InitializeLocked(); + virtual int set_sample_rate_hz(int rate); + virtual int sample_rate_hz() const; + virtual int set_num_channels(int input_channels, int output_channels); + virtual int num_input_channels() const; + virtual int num_output_channels() const; + virtual int set_num_reverse_channels(int channels); + virtual int num_reverse_channels() const; + virtual int ProcessStream(AudioFrame* frame); + virtual int AnalyzeReverseStream(AudioFrame* frame); + virtual int set_stream_delay_ms(int delay); + virtual int stream_delay_ms() const; + virtual int StartDebugRecording(const char filename[kMaxFilenameSize]); + virtual int StopDebugRecording(); + virtual EchoCancellation* echo_cancellation() const; + virtual EchoControlMobile* echo_control_mobile() const; + virtual GainControl* gain_control() const; + virtual HighPassFilter* high_pass_filter() const; + virtual LevelEstimator* level_estimator() const; + virtual NoiseSuppression* noise_suppression() const; + virtual VoiceDetection* voice_detection() const; + + // Module methods. + virtual WebRtc_Word32 ChangeUniqueId(const WebRtc_Word32 id); + + private: + bool stream_data_changed() const; + bool synthesis_needed(bool stream_data_changed) const; + bool analysis_needed(bool stream_data_changed) const; + + int id_; + + EchoCancellationImpl* echo_cancellation_; + EchoControlMobileImpl* echo_control_mobile_; + GainControlImpl* gain_control_; + HighPassFilterImpl* high_pass_filter_; + LevelEstimatorImpl* level_estimator_; + NoiseSuppressionImpl* noise_suppression_; + VoiceDetectionImpl* voice_detection_; + + std::list component_list_; + CriticalSectionWrapper* crit_; + AudioBuffer* render_audio_; + AudioBuffer* capture_audio_; +#ifdef WEBRTC_AUDIOPROC_DEBUG_DUMP + // TODO(andrew): make this more graceful. Ideally we would split this stuff + // out into a separate class with an "enabled" and "disabled" implementation. + int WriteMessageToDebugFile(); + int WriteInitMessage(); + scoped_ptr debug_file_; + scoped_ptr event_msg_; // Protobuf message. + std::string event_str_; // Memory for protobuf serialization. +#endif + + int sample_rate_hz_; + int split_sample_rate_hz_; + int samples_per_channel_; + int stream_delay_ms_; + bool was_stream_delay_set_; + + int num_reverse_channels_; + int num_input_channels_; + int num_output_channels_; +}; +} // namespace webrtc + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_AUDIO_PROCESSING_IMPL_H_ diff --git a/libs/miniwebrtc/audio/processing/echo_cancellation_impl.cc b/libs/miniwebrtc/audio/processing/echo_cancellation_impl.cc new file mode 100644 index 00000000..d4c5523d --- /dev/null +++ b/libs/miniwebrtc/audio/processing/echo_cancellation_impl.cc @@ -0,0 +1,371 @@ +/* + * 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 "echo_cancellation_impl.h" + +#include +#include + +#include "critical_section_wrapper.h" +#include "echo_cancellation.h" + +#include "audio_processing_impl.h" +#include "audio_buffer.h" + +namespace webrtc { + +typedef void Handle; + +namespace { +WebRtc_Word16 MapSetting(EchoCancellation::SuppressionLevel level) { + switch (level) { + case EchoCancellation::kLowSuppression: + return kAecNlpConservative; + case EchoCancellation::kModerateSuppression: + return kAecNlpModerate; + case EchoCancellation::kHighSuppression: + return kAecNlpAggressive; + } + assert(false); + return -1; +} + +AudioProcessing::Error MapError(int err) { + switch (err) { + case AEC_UNSUPPORTED_FUNCTION_ERROR: + return AudioProcessing::kUnsupportedFunctionError; + case AEC_BAD_PARAMETER_ERROR: + return AudioProcessing::kBadParameterError; + case AEC_BAD_PARAMETER_WARNING: + return AudioProcessing::kBadStreamParameterWarning; + default: + // AEC_UNSPECIFIED_ERROR + // AEC_UNINITIALIZED_ERROR + // AEC_NULL_POINTER_ERROR + return AudioProcessing::kUnspecifiedError; + } +} +} // namespace + +EchoCancellationImpl::EchoCancellationImpl(const AudioProcessingImpl* apm) + : ProcessingComponent(apm), + apm_(apm), + drift_compensation_enabled_(false), + metrics_enabled_(false), + suppression_level_(kModerateSuppression), + device_sample_rate_hz_(48000), + stream_drift_samples_(0), + was_stream_drift_set_(false), + stream_has_echo_(false), + delay_logging_enabled_(false) {} + +EchoCancellationImpl::~EchoCancellationImpl() {} + +int EchoCancellationImpl::ProcessRenderAudio(const AudioBuffer* audio) { + if (!is_component_enabled()) { + return apm_->kNoError; + } + + assert(audio->samples_per_split_channel() <= 160); + assert(audio->num_channels() == apm_->num_reverse_channels()); + + int err = apm_->kNoError; + + // The ordering convention must be followed to pass to the correct AEC. + size_t handle_index = 0; + for (int i = 0; i < apm_->num_output_channels(); i++) { + for (int j = 0; j < audio->num_channels(); j++) { + Handle* my_handle = static_cast(handle(handle_index)); + err = WebRtcAec_BufferFarend( + my_handle, + audio->low_pass_split_data(j), + static_cast(audio->samples_per_split_channel())); + + if (err != apm_->kNoError) { + return GetHandleError(my_handle); // TODO(ajm): warning possible? + } + + handle_index++; + } + } + + return apm_->kNoError; +} + +int EchoCancellationImpl::ProcessCaptureAudio(AudioBuffer* audio) { + if (!is_component_enabled()) { + return apm_->kNoError; + } + + if (!apm_->was_stream_delay_set()) { + return apm_->kStreamParameterNotSetError; + } + + if (drift_compensation_enabled_ && !was_stream_drift_set_) { + return apm_->kStreamParameterNotSetError; + } + + assert(audio->samples_per_split_channel() <= 160); + assert(audio->num_channels() == apm_->num_output_channels()); + + int err = apm_->kNoError; + + // The ordering convention must be followed to pass to the correct AEC. + size_t handle_index = 0; + stream_has_echo_ = false; + for (int i = 0; i < audio->num_channels(); i++) { + for (int j = 0; j < apm_->num_reverse_channels(); j++) { + Handle* my_handle = handle(handle_index); + err = WebRtcAec_Process( + my_handle, + audio->low_pass_split_data(i), + audio->high_pass_split_data(i), + audio->low_pass_split_data(i), + audio->high_pass_split_data(i), + static_cast(audio->samples_per_split_channel()), + apm_->stream_delay_ms(), + stream_drift_samples_); + + if (err != apm_->kNoError) { + err = GetHandleError(my_handle); + // TODO(ajm): Figure out how to return warnings properly. + if (err != apm_->kBadStreamParameterWarning) { + return err; + } + } + + WebRtc_Word16 status = 0; + err = WebRtcAec_get_echo_status(my_handle, &status); + if (err != apm_->kNoError) { + return GetHandleError(my_handle); + } + + if (status == 1) { + stream_has_echo_ = true; + } + + handle_index++; + } + } + + was_stream_drift_set_ = false; + return apm_->kNoError; +} + +int EchoCancellationImpl::Enable(bool enable) { + CriticalSectionScoped crit_scoped(apm_->crit()); + // Ensure AEC and AECM are not both enabled. + if (enable && apm_->echo_control_mobile()->is_enabled()) { + return apm_->kBadParameterError; + } + + return EnableComponent(enable); +} + +bool EchoCancellationImpl::is_enabled() const { + return is_component_enabled(); +} + +int EchoCancellationImpl::set_suppression_level(SuppressionLevel level) { + CriticalSectionScoped crit_scoped(apm_->crit()); + if (MapSetting(level) == -1) { + return apm_->kBadParameterError; + } + + suppression_level_ = level; + return Configure(); +} + +EchoCancellation::SuppressionLevel EchoCancellationImpl::suppression_level() + const { + return suppression_level_; +} + +int EchoCancellationImpl::enable_drift_compensation(bool enable) { + CriticalSectionScoped crit_scoped(apm_->crit()); + drift_compensation_enabled_ = enable; + return Configure(); +} + +bool EchoCancellationImpl::is_drift_compensation_enabled() const { + return drift_compensation_enabled_; +} + +int EchoCancellationImpl::set_device_sample_rate_hz(int rate) { + CriticalSectionScoped crit_scoped(apm_->crit()); + if (rate < 8000 || rate > 96000) { + return apm_->kBadParameterError; + } + + device_sample_rate_hz_ = rate; + return Initialize(); +} + +int EchoCancellationImpl::device_sample_rate_hz() const { + return device_sample_rate_hz_; +} + +int EchoCancellationImpl::set_stream_drift_samples(int drift) { + was_stream_drift_set_ = true; + stream_drift_samples_ = drift; + return apm_->kNoError; +} + +int EchoCancellationImpl::stream_drift_samples() const { + return stream_drift_samples_; +} + +int EchoCancellationImpl::enable_metrics(bool enable) { + CriticalSectionScoped crit_scoped(apm_->crit()); + metrics_enabled_ = enable; + return Configure(); +} + +bool EchoCancellationImpl::are_metrics_enabled() const { + return metrics_enabled_; +} + +// TODO(ajm): we currently just use the metrics from the first AEC. Think more +// aboue the best way to extend this to multi-channel. +int EchoCancellationImpl::GetMetrics(Metrics* metrics) { + CriticalSectionScoped crit_scoped(apm_->crit()); + if (metrics == NULL) { + return apm_->kNullPointerError; + } + + if (!is_component_enabled() || !metrics_enabled_) { + return apm_->kNotEnabledError; + } + + AecMetrics my_metrics; + memset(&my_metrics, 0, sizeof(my_metrics)); + memset(metrics, 0, sizeof(Metrics)); + + Handle* my_handle = static_cast(handle(0)); + int err = WebRtcAec_GetMetrics(my_handle, &my_metrics); + if (err != apm_->kNoError) { + return GetHandleError(my_handle); + } + + metrics->residual_echo_return_loss.instant = my_metrics.rerl.instant; + metrics->residual_echo_return_loss.average = my_metrics.rerl.average; + metrics->residual_echo_return_loss.maximum = my_metrics.rerl.max; + metrics->residual_echo_return_loss.minimum = my_metrics.rerl.min; + + metrics->echo_return_loss.instant = my_metrics.erl.instant; + metrics->echo_return_loss.average = my_metrics.erl.average; + metrics->echo_return_loss.maximum = my_metrics.erl.max; + metrics->echo_return_loss.minimum = my_metrics.erl.min; + + metrics->echo_return_loss_enhancement.instant = my_metrics.erle.instant; + metrics->echo_return_loss_enhancement.average = my_metrics.erle.average; + metrics->echo_return_loss_enhancement.maximum = my_metrics.erle.max; + metrics->echo_return_loss_enhancement.minimum = my_metrics.erle.min; + + metrics->a_nlp.instant = my_metrics.aNlp.instant; + metrics->a_nlp.average = my_metrics.aNlp.average; + metrics->a_nlp.maximum = my_metrics.aNlp.max; + metrics->a_nlp.minimum = my_metrics.aNlp.min; + + return apm_->kNoError; +} + +bool EchoCancellationImpl::stream_has_echo() const { + return stream_has_echo_; +} + +int EchoCancellationImpl::enable_delay_logging(bool enable) { + CriticalSectionScoped crit_scoped(apm_->crit()); + delay_logging_enabled_ = enable; + return Configure(); +} + +bool EchoCancellationImpl::is_delay_logging_enabled() const { + return delay_logging_enabled_; +} + +// TODO(bjornv): How should we handle the multi-channel case? +int EchoCancellationImpl::GetDelayMetrics(int* median, int* std) { + CriticalSectionScoped crit_scoped(apm_->crit()); + if (median == NULL) { + return apm_->kNullPointerError; + } + if (std == NULL) { + return apm_->kNullPointerError; + } + + if (!is_component_enabled() || !delay_logging_enabled_) { + return apm_->kNotEnabledError; + } + + Handle* my_handle = static_cast(handle(0)); + if (WebRtcAec_GetDelayMetrics(my_handle, median, std) != + apm_->kNoError) { + return GetHandleError(my_handle); + } + + return apm_->kNoError; +} + +int EchoCancellationImpl::Initialize() { + int err = ProcessingComponent::Initialize(); + if (err != apm_->kNoError || !is_component_enabled()) { + return err; + } + + was_stream_drift_set_ = false; + + return apm_->kNoError; +} + +void* EchoCancellationImpl::CreateHandle() const { + Handle* handle = NULL; + if (WebRtcAec_Create(&handle) != apm_->kNoError) { + handle = NULL; + } else { + assert(handle != NULL); + } + + return handle; +} + +int EchoCancellationImpl::DestroyHandle(void* handle) const { + assert(handle != NULL); + return WebRtcAec_Free(static_cast(handle)); +} + +int EchoCancellationImpl::InitializeHandle(void* handle) const { + assert(handle != NULL); + return WebRtcAec_Init(static_cast(handle), + apm_->sample_rate_hz(), + device_sample_rate_hz_); +} + +int EchoCancellationImpl::ConfigureHandle(void* handle) const { + assert(handle != NULL); + AecConfig config; + config.metricsMode = metrics_enabled_; + config.nlpMode = MapSetting(suppression_level_); + config.skewMode = drift_compensation_enabled_; + config.delay_logging = delay_logging_enabled_; + + return WebRtcAec_set_config(static_cast(handle), config); +} + +int EchoCancellationImpl::num_handles_required() const { + return apm_->num_output_channels() * + apm_->num_reverse_channels(); +} + +int EchoCancellationImpl::GetHandleError(void* handle) const { + assert(handle != NULL); + return MapError(WebRtcAec_get_error_code(static_cast(handle))); +} +} // namespace webrtc diff --git a/libs/miniwebrtc/audio/processing/echo_cancellation_impl.h b/libs/miniwebrtc/audio/processing/echo_cancellation_impl.h new file mode 100644 index 00000000..3c2198ca --- /dev/null +++ b/libs/miniwebrtc/audio/processing/echo_cancellation_impl.h @@ -0,0 +1,75 @@ +/* + * 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_PROCESSING_ECHO_CANCELLATION_IMPL_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_ECHO_CANCELLATION_IMPL_H_ + +#include "audio_processing.h" +#include "processing_component.h" + +namespace webrtc { +class AudioProcessingImpl; +class AudioBuffer; + +class EchoCancellationImpl : public EchoCancellation, + public ProcessingComponent { + public: + explicit EchoCancellationImpl(const AudioProcessingImpl* apm); + virtual ~EchoCancellationImpl(); + + int ProcessRenderAudio(const AudioBuffer* audio); + int ProcessCaptureAudio(AudioBuffer* audio); + + // EchoCancellation implementation. + virtual bool is_enabled() const; + virtual int device_sample_rate_hz() const; + virtual int stream_drift_samples() const; + + // ProcessingComponent implementation. + virtual int Initialize(); + + private: + // EchoCancellation implementation. + virtual int Enable(bool enable); + virtual int enable_drift_compensation(bool enable); + virtual bool is_drift_compensation_enabled() const; + virtual int set_device_sample_rate_hz(int rate); + virtual int set_stream_drift_samples(int drift); + virtual int set_suppression_level(SuppressionLevel level); + virtual SuppressionLevel suppression_level() const; + virtual int enable_metrics(bool enable); + virtual bool are_metrics_enabled() const; + virtual bool stream_has_echo() const; + virtual int GetMetrics(Metrics* metrics); + virtual int enable_delay_logging(bool enable); + virtual bool is_delay_logging_enabled() const; + virtual int GetDelayMetrics(int* median, int* std); + + // ProcessingComponent implementation. + virtual void* CreateHandle() const; + virtual int InitializeHandle(void* handle) const; + virtual int ConfigureHandle(void* handle) const; + virtual int DestroyHandle(void* handle) const; + virtual int num_handles_required() const; + virtual int GetHandleError(void* handle) const; + + const AudioProcessingImpl* apm_; + bool drift_compensation_enabled_; + bool metrics_enabled_; + SuppressionLevel suppression_level_; + int device_sample_rate_hz_; + int stream_drift_samples_; + bool was_stream_drift_set_; + bool stream_has_echo_; + bool delay_logging_enabled_; +}; +} // namespace webrtc + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_ECHO_CANCELLATION_IMPL_H_ diff --git a/libs/miniwebrtc/audio/processing/echo_control_mobile_impl.cc b/libs/miniwebrtc/audio/processing/echo_control_mobile_impl.cc new file mode 100644 index 00000000..94277890 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/echo_control_mobile_impl.cc @@ -0,0 +1,300 @@ +/* + * 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 "echo_control_mobile_impl.h" + +#include +#include + +#include "critical_section_wrapper.h" +#include "echo_control_mobile.h" + +#include "audio_processing_impl.h" +#include "audio_buffer.h" + +namespace webrtc { + +typedef void Handle; + +namespace { +WebRtc_Word16 MapSetting(EchoControlMobile::RoutingMode mode) { + switch (mode) { + case EchoControlMobile::kQuietEarpieceOrHeadset: + return 0; + case EchoControlMobile::kEarpiece: + return 1; + case EchoControlMobile::kLoudEarpiece: + return 2; + case EchoControlMobile::kSpeakerphone: + return 3; + case EchoControlMobile::kLoudSpeakerphone: + return 4; + } + assert(false); + return -1; +} + +AudioProcessing::Error MapError(int err) { + switch (err) { + case AECM_UNSUPPORTED_FUNCTION_ERROR: + return AudioProcessing::kUnsupportedFunctionError; + case AECM_NULL_POINTER_ERROR: + return AudioProcessing::kNullPointerError; + case AECM_BAD_PARAMETER_ERROR: + return AudioProcessing::kBadParameterError; + case AECM_BAD_PARAMETER_WARNING: + return AudioProcessing::kBadStreamParameterWarning; + default: + // AECM_UNSPECIFIED_ERROR + // AECM_UNINITIALIZED_ERROR + return AudioProcessing::kUnspecifiedError; + } +} +} // namespace + +size_t EchoControlMobile::echo_path_size_bytes() { + return WebRtcAecm_echo_path_size_bytes(); +} + +EchoControlMobileImpl::EchoControlMobileImpl(const AudioProcessingImpl* apm) + : ProcessingComponent(apm), + apm_(apm), + routing_mode_(kSpeakerphone), + comfort_noise_enabled_(true), + external_echo_path_(NULL) {} + +EchoControlMobileImpl::~EchoControlMobileImpl() { + if (external_echo_path_ != NULL) { + delete [] external_echo_path_; + external_echo_path_ = NULL; + } +} + +int EchoControlMobileImpl::ProcessRenderAudio(const AudioBuffer* audio) { + if (!is_component_enabled()) { + return apm_->kNoError; + } + + assert(audio->samples_per_split_channel() <= 160); + assert(audio->num_channels() == apm_->num_reverse_channels()); + + int err = apm_->kNoError; + + // The ordering convention must be followed to pass to the correct AECM. + size_t handle_index = 0; + for (int i = 0; i < apm_->num_output_channels(); i++) { + for (int j = 0; j < audio->num_channels(); j++) { + Handle* my_handle = static_cast(handle(handle_index)); + err = WebRtcAecm_BufferFarend( + my_handle, + audio->low_pass_split_data(j), + static_cast(audio->samples_per_split_channel())); + + if (err != apm_->kNoError) { + return GetHandleError(my_handle); // TODO(ajm): warning possible? + } + + handle_index++; + } + } + + return apm_->kNoError; +} + +int EchoControlMobileImpl::ProcessCaptureAudio(AudioBuffer* audio) { + if (!is_component_enabled()) { + return apm_->kNoError; + } + + if (!apm_->was_stream_delay_set()) { + return apm_->kStreamParameterNotSetError; + } + + assert(audio->samples_per_split_channel() <= 160); + assert(audio->num_channels() == apm_->num_output_channels()); + + int err = apm_->kNoError; + + // The ordering convention must be followed to pass to the correct AECM. + size_t handle_index = 0; + for (int i = 0; i < audio->num_channels(); i++) { + // TODO(ajm): improve how this works, possibly inside AECM. + // This is kind of hacked up. + WebRtc_Word16* noisy = audio->low_pass_reference(i); + WebRtc_Word16* clean = audio->low_pass_split_data(i); + if (noisy == NULL) { + noisy = clean; + clean = NULL; + } + for (int j = 0; j < apm_->num_reverse_channels(); j++) { + Handle* my_handle = static_cast(handle(handle_index)); + err = WebRtcAecm_Process( + my_handle, + noisy, + clean, + audio->low_pass_split_data(i), + static_cast(audio->samples_per_split_channel()), + apm_->stream_delay_ms()); + + if (err != apm_->kNoError) { + return GetHandleError(my_handle); // TODO(ajm): warning possible? + } + + handle_index++; + } + } + + return apm_->kNoError; +} + +int EchoControlMobileImpl::Enable(bool enable) { + CriticalSectionScoped crit_scoped(apm_->crit()); + // Ensure AEC and AECM are not both enabled. + if (enable && apm_->echo_cancellation()->is_enabled()) { + return apm_->kBadParameterError; + } + + return EnableComponent(enable); +} + +bool EchoControlMobileImpl::is_enabled() const { + return is_component_enabled(); +} + +int EchoControlMobileImpl::set_routing_mode(RoutingMode mode) { + CriticalSectionScoped crit_scoped(apm_->crit()); + if (MapSetting(mode) == -1) { + return apm_->kBadParameterError; + } + + routing_mode_ = mode; + return Configure(); +} + +EchoControlMobile::RoutingMode EchoControlMobileImpl::routing_mode() + const { + return routing_mode_; +} + +int EchoControlMobileImpl::enable_comfort_noise(bool enable) { + CriticalSectionScoped crit_scoped(apm_->crit()); + comfort_noise_enabled_ = enable; + return Configure(); +} + +bool EchoControlMobileImpl::is_comfort_noise_enabled() const { + return comfort_noise_enabled_; +} + +int EchoControlMobileImpl::SetEchoPath(const void* echo_path, + size_t size_bytes) { + CriticalSectionScoped crit_scoped(apm_->crit()); + if (echo_path == NULL) { + return apm_->kNullPointerError; + } + if (size_bytes != echo_path_size_bytes()) { + // Size mismatch + return apm_->kBadParameterError; + } + + if (external_echo_path_ == NULL) { + external_echo_path_ = new unsigned char[size_bytes]; + } + memcpy(external_echo_path_, echo_path, size_bytes); + + return Initialize(); +} + +int EchoControlMobileImpl::GetEchoPath(void* echo_path, + size_t size_bytes) const { + CriticalSectionScoped crit_scoped(apm_->crit()); + if (echo_path == NULL) { + return apm_->kNullPointerError; + } + if (size_bytes != echo_path_size_bytes()) { + // Size mismatch + return apm_->kBadParameterError; + } + if (!is_component_enabled()) { + return apm_->kNotEnabledError; + } + + // Get the echo path from the first channel + Handle* my_handle = static_cast(handle(0)); + if (WebRtcAecm_GetEchoPath(my_handle, echo_path, size_bytes) != 0) { + return GetHandleError(my_handle); + } + + return apm_->kNoError; +} + +int EchoControlMobileImpl::Initialize() { + if (!is_component_enabled()) { + return apm_->kNoError; + } + + if (apm_->sample_rate_hz() == apm_->kSampleRate32kHz) { + // AECM doesn't support super-wideband. + return apm_->kBadSampleRateError; + } + + return ProcessingComponent::Initialize(); +} + +void* EchoControlMobileImpl::CreateHandle() const { + Handle* handle = NULL; + if (WebRtcAecm_Create(&handle) != apm_->kNoError) { + handle = NULL; + } else { + assert(handle != NULL); + } + + return handle; +} + +int EchoControlMobileImpl::DestroyHandle(void* handle) const { + return WebRtcAecm_Free(static_cast(handle)); +} + +int EchoControlMobileImpl::InitializeHandle(void* handle) const { + assert(handle != NULL); + Handle* my_handle = static_cast(handle); + if (WebRtcAecm_Init(my_handle, apm_->sample_rate_hz()) != 0) { + return GetHandleError(my_handle); + } + if (external_echo_path_ != NULL) { + if (WebRtcAecm_InitEchoPath(my_handle, + external_echo_path_, + echo_path_size_bytes()) != 0) { + return GetHandleError(my_handle); + } + } + + return apm_->kNoError; +} + +int EchoControlMobileImpl::ConfigureHandle(void* handle) const { + AecmConfig config; + config.cngMode = comfort_noise_enabled_; + config.echoMode = MapSetting(routing_mode_); + + return WebRtcAecm_set_config(static_cast(handle), config); +} + +int EchoControlMobileImpl::num_handles_required() const { + return apm_->num_output_channels() * + apm_->num_reverse_channels(); +} + +int EchoControlMobileImpl::GetHandleError(void* handle) const { + assert(handle != NULL); + return MapError(WebRtcAecm_get_error_code(static_cast(handle))); +} +} // namespace webrtc diff --git a/libs/miniwebrtc/audio/processing/echo_control_mobile_impl.h b/libs/miniwebrtc/audio/processing/echo_control_mobile_impl.h new file mode 100644 index 00000000..6d9e3694 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/echo_control_mobile_impl.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. + */ + +#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_ECHO_CONTROL_MOBILE_IMPL_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_ECHO_CONTROL_MOBILE_IMPL_H_ + +#include "audio_processing.h" +#include "processing_component.h" + +namespace webrtc { +class AudioProcessingImpl; +class AudioBuffer; + +class EchoControlMobileImpl : public EchoControlMobile, + public ProcessingComponent { + public: + explicit EchoControlMobileImpl(const AudioProcessingImpl* apm); + virtual ~EchoControlMobileImpl(); + + int ProcessRenderAudio(const AudioBuffer* audio); + int ProcessCaptureAudio(AudioBuffer* audio); + + // EchoControlMobile implementation. + virtual bool is_enabled() const; + + // ProcessingComponent implementation. + virtual int Initialize(); + + private: + // EchoControlMobile implementation. + virtual int Enable(bool enable); + virtual int set_routing_mode(RoutingMode mode); + virtual RoutingMode routing_mode() const; + virtual int enable_comfort_noise(bool enable); + virtual bool is_comfort_noise_enabled() const; + virtual int SetEchoPath(const void* echo_path, size_t size_bytes); + virtual int GetEchoPath(void* echo_path, size_t size_bytes) const; + + // ProcessingComponent implementation. + virtual void* CreateHandle() const; + virtual int InitializeHandle(void* handle) const; + virtual int ConfigureHandle(void* handle) const; + virtual int DestroyHandle(void* handle) const; + virtual int num_handles_required() const; + virtual int GetHandleError(void* handle) const; + + const AudioProcessingImpl* apm_; + RoutingMode routing_mode_; + bool comfort_noise_enabled_; + unsigned char* external_echo_path_; +}; +} // namespace webrtc + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_ECHO_CONTROL_MOBILE_IMPL_H_ diff --git a/libs/miniwebrtc/audio/processing/gain_control_impl.cc b/libs/miniwebrtc/audio/processing/gain_control_impl.cc new file mode 100644 index 00000000..a518ab5e --- /dev/null +++ b/libs/miniwebrtc/audio/processing/gain_control_impl.cc @@ -0,0 +1,367 @@ +/* + * 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 "gain_control_impl.h" + +#include + +#include "critical_section_wrapper.h" +#include "gain_control.h" + +#include "audio_processing_impl.h" +#include "audio_buffer.h" + +namespace webrtc { + +typedef void Handle; + +namespace { +WebRtc_Word16 MapSetting(GainControl::Mode mode) { + switch (mode) { + case GainControl::kAdaptiveAnalog: + return kAgcModeAdaptiveAnalog; + case GainControl::kAdaptiveDigital: + return kAgcModeAdaptiveDigital; + case GainControl::kFixedDigital: + return kAgcModeFixedDigital; + } + assert(false); + return -1; +} +} // namespace + +GainControlImpl::GainControlImpl(const AudioProcessingImpl* apm) + : ProcessingComponent(apm), + apm_(apm), + mode_(kAdaptiveAnalog), + minimum_capture_level_(0), + maximum_capture_level_(255), + limiter_enabled_(true), + target_level_dbfs_(3), + compression_gain_db_(9), + analog_capture_level_(0), + was_analog_level_set_(false), + stream_is_saturated_(false) {} + +GainControlImpl::~GainControlImpl() {} + +int GainControlImpl::ProcessRenderAudio(AudioBuffer* audio) { + if (!is_component_enabled()) { + return apm_->kNoError; + } + + assert(audio->samples_per_split_channel() <= 160); + + WebRtc_Word16* mixed_data = audio->low_pass_split_data(0); + if (audio->num_channels() > 1) { + audio->CopyAndMixLowPass(1); + mixed_data = audio->mixed_low_pass_data(0); + } + + for (int i = 0; i < num_handles(); i++) { + Handle* my_handle = static_cast(handle(i)); + int err = WebRtcAgc_AddFarend( + my_handle, + mixed_data, + static_cast(audio->samples_per_split_channel())); + + if (err != apm_->kNoError) { + return GetHandleError(my_handle); + } + } + + return apm_->kNoError; +} + +int GainControlImpl::AnalyzeCaptureAudio(AudioBuffer* audio) { + if (!is_component_enabled()) { + return apm_->kNoError; + } + + assert(audio->samples_per_split_channel() <= 160); + assert(audio->num_channels() == num_handles()); + + int err = apm_->kNoError; + + if (mode_ == kAdaptiveAnalog) { + for (int i = 0; i < num_handles(); i++) { + Handle* my_handle = static_cast(handle(i)); + err = WebRtcAgc_AddMic( + my_handle, + audio->low_pass_split_data(i), + audio->high_pass_split_data(i), + static_cast(audio->samples_per_split_channel())); + + if (err != apm_->kNoError) { + return GetHandleError(my_handle); + } + } + } else if (mode_ == kAdaptiveDigital) { + + for (int i = 0; i < num_handles(); i++) { + Handle* my_handle = static_cast(handle(i)); + WebRtc_Word32 capture_level_out = 0; + + err = WebRtcAgc_VirtualMic( + my_handle, + audio->low_pass_split_data(i), + audio->high_pass_split_data(i), + static_cast(audio->samples_per_split_channel()), + //capture_levels_[i], + analog_capture_level_, + &capture_level_out); + + capture_levels_[i] = capture_level_out; + + if (err != apm_->kNoError) { + return GetHandleError(my_handle); + } + + } + } + + return apm_->kNoError; +} + +int GainControlImpl::ProcessCaptureAudio(AudioBuffer* audio) { + if (!is_component_enabled()) { + return apm_->kNoError; + } + + if (mode_ == kAdaptiveAnalog && !was_analog_level_set_) { + return apm_->kStreamParameterNotSetError; + } + + assert(audio->samples_per_split_channel() <= 160); + assert(audio->num_channels() == num_handles()); + + stream_is_saturated_ = false; + for (int i = 0; i < num_handles(); i++) { + Handle* my_handle = static_cast(handle(i)); + WebRtc_Word32 capture_level_out = 0; + WebRtc_UWord8 saturation_warning = 0; + + int err = WebRtcAgc_Process( + my_handle, + audio->low_pass_split_data(i), + audio->high_pass_split_data(i), + static_cast(audio->samples_per_split_channel()), + audio->low_pass_split_data(i), + audio->high_pass_split_data(i), + capture_levels_[i], + &capture_level_out, + apm_->echo_cancellation()->stream_has_echo(), + &saturation_warning); + + if (err != apm_->kNoError) { + return GetHandleError(my_handle); + } + + capture_levels_[i] = capture_level_out; + if (saturation_warning == 1) { + stream_is_saturated_ = true; + } + } + + if (mode_ == kAdaptiveAnalog) { + // Take the analog level to be the average across the handles. + analog_capture_level_ = 0; + for (int i = 0; i < num_handles(); i++) { + analog_capture_level_ += capture_levels_[i]; + } + + analog_capture_level_ /= num_handles(); + } + + was_analog_level_set_ = false; + return apm_->kNoError; +} + +// TODO(ajm): ensure this is called under kAdaptiveAnalog. +int GainControlImpl::set_stream_analog_level(int level) { + was_analog_level_set_ = true; + if (level < minimum_capture_level_ || level > maximum_capture_level_) { + return apm_->kBadParameterError; + } + + if (mode_ == kAdaptiveAnalog) { + if (level != analog_capture_level_) { + // The analog level has been changed; update our internal levels. + capture_levels_.assign(num_handles(), level); + } + } + analog_capture_level_ = level; + + return apm_->kNoError; +} + +int GainControlImpl::stream_analog_level() { + // TODO(ajm): enable this assertion? + //assert(mode_ == kAdaptiveAnalog); + + return analog_capture_level_; +} + +int GainControlImpl::Enable(bool enable) { + CriticalSectionScoped crit_scoped(apm_->crit()); + return EnableComponent(enable); +} + +bool GainControlImpl::is_enabled() const { + return is_component_enabled(); +} + +int GainControlImpl::set_mode(Mode mode) { + CriticalSectionScoped crit_scoped(apm_->crit()); + if (MapSetting(mode) == -1) { + return apm_->kBadParameterError; + } + + mode_ = mode; + return Initialize(); +} + +GainControl::Mode GainControlImpl::mode() const { + return mode_; +} + +int GainControlImpl::set_analog_level_limits(int minimum, + int maximum) { + CriticalSectionScoped crit_scoped(apm_->crit()); + if (minimum < 0) { + return apm_->kBadParameterError; + } + + if (maximum > 65535) { + return apm_->kBadParameterError; + } + + if (maximum < minimum) { + return apm_->kBadParameterError; + } + + minimum_capture_level_ = minimum; + maximum_capture_level_ = maximum; + + return Initialize(); +} + +int GainControlImpl::analog_level_minimum() const { + return minimum_capture_level_; +} + +int GainControlImpl::analog_level_maximum() const { + return maximum_capture_level_; +} + +bool GainControlImpl::stream_is_saturated() const { + return stream_is_saturated_; +} + +int GainControlImpl::set_target_level_dbfs(int level) { + CriticalSectionScoped crit_scoped(apm_->crit()); + if (level > 31 || level < 0) { + return apm_->kBadParameterError; + } + + target_level_dbfs_ = level; + return Configure(); +} + +int GainControlImpl::target_level_dbfs() const { + return target_level_dbfs_; +} + +int GainControlImpl::set_compression_gain_db(int gain) { + CriticalSectionScoped crit_scoped(apm_->crit()); + if (gain < 0 || gain > 90) { + return apm_->kBadParameterError; + } + + compression_gain_db_ = gain; + return Configure(); +} + +int GainControlImpl::compression_gain_db() const { + return compression_gain_db_; +} + +int GainControlImpl::enable_limiter(bool enable) { + CriticalSectionScoped crit_scoped(apm_->crit()); + limiter_enabled_ = enable; + return Configure(); +} + +bool GainControlImpl::is_limiter_enabled() const { + return limiter_enabled_; +} + +int GainControlImpl::Initialize() { + int err = ProcessingComponent::Initialize(); + if (err != apm_->kNoError || !is_component_enabled()) { + return err; + } + + analog_capture_level_ = + (maximum_capture_level_ - minimum_capture_level_) >> 1; + capture_levels_.assign(num_handles(), analog_capture_level_); + was_analog_level_set_ = false; + + return apm_->kNoError; +} + +void* GainControlImpl::CreateHandle() const { + Handle* handle = NULL; + if (WebRtcAgc_Create(&handle) != apm_->kNoError) { + handle = NULL; + } else { + assert(handle != NULL); + } + + return handle; +} + +int GainControlImpl::DestroyHandle(void* handle) const { + return WebRtcAgc_Free(static_cast(handle)); +} + +int GainControlImpl::InitializeHandle(void* handle) const { + return WebRtcAgc_Init(static_cast(handle), + minimum_capture_level_, + maximum_capture_level_, + MapSetting(mode_), + apm_->sample_rate_hz()); +} + +int GainControlImpl::ConfigureHandle(void* handle) const { + WebRtcAgc_config_t config; + // TODO(ajm): Flip the sign here (since AGC expects a positive value) if we + // change the interface. + //assert(target_level_dbfs_ <= 0); + //config.targetLevelDbfs = static_cast(-target_level_dbfs_); + config.targetLevelDbfs = static_cast(target_level_dbfs_); + config.compressionGaindB = + static_cast(compression_gain_db_); + config.limiterEnable = limiter_enabled_; + + return WebRtcAgc_set_config(static_cast(handle), config); +} + +int GainControlImpl::num_handles_required() const { + return apm_->num_output_channels(); +} + +int GainControlImpl::GetHandleError(void* handle) const { + // The AGC has no get_error() function. + // (Despite listing errors in its interface...) + assert(handle != NULL); + return apm_->kUnspecifiedError; +} +} // namespace webrtc diff --git a/libs/miniwebrtc/audio/processing/gain_control_impl.h b/libs/miniwebrtc/audio/processing/gain_control_impl.h new file mode 100644 index 00000000..5915eeb0 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/gain_control_impl.h @@ -0,0 +1,79 @@ +/* + * 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_PROCESSING_GAIN_CONTROL_IMPL_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_GAIN_CONTROL_IMPL_H_ + +#include + +#include "audio_processing.h" +#include "processing_component.h" + +namespace webrtc { +class AudioProcessingImpl; +class AudioBuffer; + +class GainControlImpl : public GainControl, + public ProcessingComponent { + public: + explicit GainControlImpl(const AudioProcessingImpl* apm); + virtual ~GainControlImpl(); + + int ProcessRenderAudio(AudioBuffer* audio); + int AnalyzeCaptureAudio(AudioBuffer* audio); + int ProcessCaptureAudio(AudioBuffer* audio); + + // ProcessingComponent implementation. + virtual int Initialize(); + + // GainControl implementation. + virtual bool is_enabled() const; + virtual int stream_analog_level(); + + private: + // GainControl implementation. + virtual int Enable(bool enable); + virtual int set_stream_analog_level(int level); + virtual int set_mode(Mode mode); + virtual Mode mode() const; + virtual int set_target_level_dbfs(int level); + virtual int target_level_dbfs() const; + virtual int set_compression_gain_db(int gain); + virtual int compression_gain_db() const; + virtual int enable_limiter(bool enable); + virtual bool is_limiter_enabled() const; + virtual int set_analog_level_limits(int minimum, int maximum); + virtual int analog_level_minimum() const; + virtual int analog_level_maximum() const; + virtual bool stream_is_saturated() const; + + // ProcessingComponent implementation. + virtual void* CreateHandle() const; + virtual int InitializeHandle(void* handle) const; + virtual int ConfigureHandle(void* handle) const; + virtual int DestroyHandle(void* handle) const; + virtual int num_handles_required() const; + virtual int GetHandleError(void* handle) const; + + const AudioProcessingImpl* apm_; + Mode mode_; + int minimum_capture_level_; + int maximum_capture_level_; + bool limiter_enabled_; + int target_level_dbfs_; + int compression_gain_db_; + std::vector capture_levels_; + int analog_capture_level_; + bool was_analog_level_set_; + bool stream_is_saturated_; +}; +} // namespace webrtc + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_GAIN_CONTROL_IMPL_H_ diff --git a/libs/miniwebrtc/audio/processing/high_pass_filter_impl.cc b/libs/miniwebrtc/audio/processing/high_pass_filter_impl.cc new file mode 100644 index 00000000..b20fed87 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/high_pass_filter_impl.cc @@ -0,0 +1,173 @@ +/* + * 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 "high_pass_filter_impl.h" + +#include + +#include "critical_section_wrapper.h" +#include "typedefs.h" +#include "signal_processing_library.h" + +#include "audio_processing_impl.h" +#include "audio_buffer.h" + +namespace webrtc { +namespace { +const WebRtc_Word16 kFilterCoefficients8kHz[5] = + {3798, -7596, 3798, 7807, -3733}; + +const WebRtc_Word16 kFilterCoefficients[5] = + {4012, -8024, 4012, 8002, -3913}; + +struct FilterState { + WebRtc_Word16 y[4]; + WebRtc_Word16 x[2]; + const WebRtc_Word16* ba; +}; + +int InitializeFilter(FilterState* hpf, int sample_rate_hz) { + assert(hpf != NULL); + + if (sample_rate_hz == AudioProcessingImpl::kSampleRate8kHz) { + hpf->ba = kFilterCoefficients8kHz; + } else { + hpf->ba = kFilterCoefficients; + } + + WebRtcSpl_MemSetW16(hpf->x, 0, 2); + WebRtcSpl_MemSetW16(hpf->y, 0, 4); + + return AudioProcessing::kNoError; +} + +int Filter(FilterState* hpf, WebRtc_Word16* data, int length) { + assert(hpf != NULL); + + WebRtc_Word32 tmp_int32 = 0; + WebRtc_Word16* y = hpf->y; + WebRtc_Word16* x = hpf->x; + const WebRtc_Word16* ba = hpf->ba; + + for (int i = 0; i < length; i++) { + // y[i] = b[0] * x[i] + b[1] * x[i-1] + b[2] * x[i-2] + // + -a[1] * y[i-1] + -a[2] * y[i-2]; + + tmp_int32 = + WEBRTC_SPL_MUL_16_16(y[1], ba[3]); // -a[1] * y[i-1] (low part) + tmp_int32 += + WEBRTC_SPL_MUL_16_16(y[3], ba[4]); // -a[2] * y[i-2] (low part) + tmp_int32 = (tmp_int32 >> 15); + tmp_int32 += + WEBRTC_SPL_MUL_16_16(y[0], ba[3]); // -a[1] * y[i-1] (high part) + tmp_int32 += + WEBRTC_SPL_MUL_16_16(y[2], ba[4]); // -a[2] * y[i-2] (high part) + tmp_int32 = (tmp_int32 << 1); + + tmp_int32 += WEBRTC_SPL_MUL_16_16(data[i], ba[0]); // b[0]*x[0] + tmp_int32 += WEBRTC_SPL_MUL_16_16(x[0], ba[1]); // b[1]*x[i-1] + tmp_int32 += WEBRTC_SPL_MUL_16_16(x[1], ba[2]); // b[2]*x[i-2] + + // Update state (input part) + x[1] = x[0]; + x[0] = data[i]; + + // Update state (filtered part) + y[2] = y[0]; + y[3] = y[1]; + y[0] = static_cast(tmp_int32 >> 13); + y[1] = static_cast((tmp_int32 - + WEBRTC_SPL_LSHIFT_W32(static_cast(y[0]), 13)) << 2); + + // Rounding in Q12, i.e. add 2^11 + tmp_int32 += 2048; + + // Saturate (to 2^27) so that the HP filtered signal does not overflow + tmp_int32 = WEBRTC_SPL_SAT(static_cast(134217727), + tmp_int32, + static_cast(-134217728)); + + // Convert back to Q0 and use rounding + data[i] = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp_int32, 12); + + } + + return AudioProcessing::kNoError; +} +} // namespace + +typedef FilterState Handle; + +HighPassFilterImpl::HighPassFilterImpl(const AudioProcessingImpl* apm) + : ProcessingComponent(apm), + apm_(apm) {} + +HighPassFilterImpl::~HighPassFilterImpl() {} + +int HighPassFilterImpl::ProcessCaptureAudio(AudioBuffer* audio) { + int err = apm_->kNoError; + + if (!is_component_enabled()) { + return apm_->kNoError; + } + + assert(audio->samples_per_split_channel() <= 160); + + for (int i = 0; i < num_handles(); i++) { + Handle* my_handle = static_cast(handle(i)); + err = Filter(my_handle, + audio->low_pass_split_data(i), + audio->samples_per_split_channel()); + + if (err != apm_->kNoError) { + return GetHandleError(my_handle); + } + } + + return apm_->kNoError; +} + +int HighPassFilterImpl::Enable(bool enable) { + CriticalSectionScoped crit_scoped(apm_->crit()); + return EnableComponent(enable); +} + +bool HighPassFilterImpl::is_enabled() const { + return is_component_enabled(); +} + +void* HighPassFilterImpl::CreateHandle() const { + return new FilterState; +} + +int HighPassFilterImpl::DestroyHandle(void* handle) const { + delete static_cast(handle); + return apm_->kNoError; +} + +int HighPassFilterImpl::InitializeHandle(void* handle) const { + return InitializeFilter(static_cast(handle), + apm_->sample_rate_hz()); +} + +int HighPassFilterImpl::ConfigureHandle(void* /*handle*/) const { + return apm_->kNoError; // Not configurable. +} + +int HighPassFilterImpl::num_handles_required() const { + return apm_->num_output_channels(); +} + +int HighPassFilterImpl::GetHandleError(void* handle) const { + // The component has no detailed errors. + assert(handle != NULL); + return apm_->kUnspecifiedError; +} +} // namespace webrtc diff --git a/libs/miniwebrtc/audio/processing/high_pass_filter_impl.h b/libs/miniwebrtc/audio/processing/high_pass_filter_impl.h new file mode 100644 index 00000000..94a9c897 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/high_pass_filter_impl.h @@ -0,0 +1,48 @@ +/* + * 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_PROCESSING_HIGH_PASS_FILTER_IMPL_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_HIGH_PASS_FILTER_IMPL_H_ + +#include "audio_processing.h" +#include "processing_component.h" + +namespace webrtc { +class AudioProcessingImpl; +class AudioBuffer; + +class HighPassFilterImpl : public HighPassFilter, + public ProcessingComponent { + public: + explicit HighPassFilterImpl(const AudioProcessingImpl* apm); + virtual ~HighPassFilterImpl(); + + int ProcessCaptureAudio(AudioBuffer* audio); + + // HighPassFilter implementation. + virtual bool is_enabled() const; + + private: + // HighPassFilter implementation. + virtual int Enable(bool enable); + + // ProcessingComponent implementation. + virtual void* CreateHandle() const; + virtual int InitializeHandle(void* handle) const; + virtual int ConfigureHandle(void* handle) const; + virtual int DestroyHandle(void* handle) const; + virtual int num_handles_required() const; + virtual int GetHandleError(void* handle) const; + + const AudioProcessingImpl* apm_; +}; +} // namespace webrtc + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_HIGH_PASS_FILTER_IMPL_H_ diff --git a/libs/miniwebrtc/audio/processing/level_estimator_impl.cc b/libs/miniwebrtc/audio/processing/level_estimator_impl.cc new file mode 100644 index 00000000..42cac99a --- /dev/null +++ b/libs/miniwebrtc/audio/processing/level_estimator_impl.cc @@ -0,0 +1,165 @@ +/* + * 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 "level_estimator_impl.h" + +#include +#include +#include + +#include "audio_processing_impl.h" +#include "audio_buffer.h" +#include "critical_section_wrapper.h" + +namespace webrtc { +namespace { + +const double kMaxSquaredLevel = 32768.0 * 32768.0; + +class Level { + public: + static const int kMinLevel = 127; + + Level() + : sum_square_(0.0), + sample_count_(0) {} + ~Level() {} + + void Init() { + sum_square_ = 0.0; + sample_count_ = 0; + } + + void Process(int16_t* data, int length) { + assert(data != NULL); + assert(length > 0); + sum_square_ += SumSquare(data, length); + sample_count_ += length; + } + + void ProcessMuted(int length) { + assert(length > 0); + sample_count_ += length; + } + + int RMS() { + if (sample_count_ == 0 || sum_square_ == 0.0) { + Init(); + return kMinLevel; + } + + // Normalize by the max level. + double rms = sum_square_ / (sample_count_ * kMaxSquaredLevel); + // 20log_10(x^0.5) = 10log_10(x) + rms = 10 * log10(rms); + if (rms > 0) + rms = 0; + else if (rms < -kMinLevel) + rms = -kMinLevel; + + rms = -rms; + Init(); + return static_cast(rms + 0.5); + } + + private: + static double SumSquare(int16_t* data, int length) { + double sum_square = 0.0; + for (int i = 0; i < length; ++i) { + double data_d = static_cast(data[i]); + sum_square += data_d * data_d; + } + return sum_square; + } + + double sum_square_; + int sample_count_; +}; +} // namespace + +LevelEstimatorImpl::LevelEstimatorImpl(const AudioProcessingImpl* apm) + : ProcessingComponent(apm), + apm_(apm) {} + +LevelEstimatorImpl::~LevelEstimatorImpl() {} + +int LevelEstimatorImpl::ProcessStream(AudioBuffer* audio) { + if (!is_component_enabled()) { + return apm_->kNoError; + } + + Level* level = static_cast(handle(0)); + if (audio->is_muted()) { + level->ProcessMuted(audio->samples_per_channel()); + return apm_->kNoError; + } + + int16_t* mixed_data = audio->data(0); + if (audio->num_channels() > 1) { + audio->CopyAndMix(1); + mixed_data = audio->mixed_data(0); + } + + level->Process(mixed_data, audio->samples_per_channel()); + + return apm_->kNoError; +} + +int LevelEstimatorImpl::Enable(bool enable) { + CriticalSectionScoped crit_scoped(apm_->crit()); + return EnableComponent(enable); +} + +bool LevelEstimatorImpl::is_enabled() const { + return is_component_enabled(); +} + +int LevelEstimatorImpl::RMS() { + if (!is_component_enabled()) { + return apm_->kNotEnabledError; + } + + Level* level = static_cast(handle(0)); + return level->RMS(); +} + +void* LevelEstimatorImpl::CreateHandle() const { + return new Level; +} + +int LevelEstimatorImpl::DestroyHandle(void* handle) const { + assert(handle != NULL); + Level* level = static_cast(handle); + delete level; + return apm_->kNoError; +} + +int LevelEstimatorImpl::InitializeHandle(void* handle) const { + assert(handle != NULL); + Level* level = static_cast(handle); + level->Init(); + + return apm_->kNoError; +} + +int LevelEstimatorImpl::ConfigureHandle(void* /*handle*/) const { + return apm_->kNoError; +} + +int LevelEstimatorImpl::num_handles_required() const { + return 1; +} + +int LevelEstimatorImpl::GetHandleError(void* handle) const { + // The component has no detailed errors. + assert(handle != NULL); + return apm_->kUnspecifiedError; +} +} // namespace webrtc diff --git a/libs/miniwebrtc/audio/processing/level_estimator_impl.h b/libs/miniwebrtc/audio/processing/level_estimator_impl.h new file mode 100644 index 00000000..1a063437 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/level_estimator_impl.h @@ -0,0 +1,49 @@ +/* + * 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_PROCESSING_LEVEL_ESTIMATOR_IMPL_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_LEVEL_ESTIMATOR_IMPL_H_ + +#include "audio_processing.h" +#include "processing_component.h" + +namespace webrtc { +class AudioProcessingImpl; +class AudioBuffer; + +class LevelEstimatorImpl : public LevelEstimator, + public ProcessingComponent { + public: + explicit LevelEstimatorImpl(const AudioProcessingImpl* apm); + virtual ~LevelEstimatorImpl(); + + int ProcessStream(AudioBuffer* audio); + + // LevelEstimator implementation. + virtual bool is_enabled() const; + + private: + // LevelEstimator implementation. + virtual int Enable(bool enable); + virtual int RMS(); + + // ProcessingComponent implementation. + virtual void* CreateHandle() const; + virtual int InitializeHandle(void* handle) const; + virtual int ConfigureHandle(void* handle) const; + virtual int DestroyHandle(void* handle) const; + virtual int num_handles_required() const; + virtual int GetHandleError(void* handle) const; + + const AudioProcessingImpl* apm_; +}; +} // namespace webrtc + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_LEVEL_ESTIMATOR_IMPL_H_ diff --git a/libs/miniwebrtc/audio/processing/noise_suppression_impl.cc b/libs/miniwebrtc/audio/processing/noise_suppression_impl.cc new file mode 100644 index 00000000..c44d3fed --- /dev/null +++ b/libs/miniwebrtc/audio/processing/noise_suppression_impl.cc @@ -0,0 +1,165 @@ +/* + * 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 "noise_suppression_impl.h" + +#include + +#include "critical_section_wrapper.h" +#if defined(WEBRTC_NS_FLOAT) +#include "noise_suppression.h" +#elif defined(WEBRTC_NS_FIXED) +#include "noise_suppression_x.h" +#endif + +#include "audio_processing_impl.h" +#include "audio_buffer.h" + +namespace webrtc { + +#if defined(WEBRTC_NS_FLOAT) +typedef NsHandle Handle; +#elif defined(WEBRTC_NS_FIXED) +typedef NsxHandle Handle; +#endif + +namespace { +int MapSetting(NoiseSuppression::Level level) { + switch (level) { + case NoiseSuppression::kLow: + return 0; + case NoiseSuppression::kModerate: + return 1; + case NoiseSuppression::kHigh: + return 2; + case NoiseSuppression::kVeryHigh: + return 3; + } + assert(false); + return -1; +} +} // namespace + +NoiseSuppressionImpl::NoiseSuppressionImpl(const AudioProcessingImpl* apm) + : ProcessingComponent(apm), + apm_(apm), + level_(kModerate) {} + +NoiseSuppressionImpl::~NoiseSuppressionImpl() {} + +int NoiseSuppressionImpl::ProcessCaptureAudio(AudioBuffer* audio) { + int err = apm_->kNoError; + + if (!is_component_enabled()) { + return apm_->kNoError; + } + assert(audio->samples_per_split_channel() <= 160); + assert(audio->num_channels() == num_handles()); + + for (int i = 0; i < num_handles(); i++) { + Handle* my_handle = static_cast(handle(i)); +#if defined(WEBRTC_NS_FLOAT) + err = WebRtcNs_Process(static_cast(handle(i)), + audio->low_pass_split_data(i), + audio->high_pass_split_data(i), + audio->low_pass_split_data(i), + audio->high_pass_split_data(i)); +#elif defined(WEBRTC_NS_FIXED) + err = WebRtcNsx_Process(static_cast(handle(i)), + audio->low_pass_split_data(i), + audio->high_pass_split_data(i), + audio->low_pass_split_data(i), + audio->high_pass_split_data(i)); +#endif + + if (err != apm_->kNoError) { + return GetHandleError(my_handle); + } + } + + return apm_->kNoError; +} + +int NoiseSuppressionImpl::Enable(bool enable) { + CriticalSectionScoped crit_scoped(apm_->crit()); + return EnableComponent(enable); +} + +bool NoiseSuppressionImpl::is_enabled() const { + return is_component_enabled(); +} + +int NoiseSuppressionImpl::set_level(Level level) { + CriticalSectionScoped crit_scoped(apm_->crit()); + if (MapSetting(level) == -1) { + return apm_->kBadParameterError; + } + + level_ = level; + return Configure(); +} + +NoiseSuppression::Level NoiseSuppressionImpl::level() const { + return level_; +} + +void* NoiseSuppressionImpl::CreateHandle() const { + Handle* handle = NULL; +#if defined(WEBRTC_NS_FLOAT) + if (WebRtcNs_Create(&handle) != apm_->kNoError) +#elif defined(WEBRTC_NS_FIXED) + if (WebRtcNsx_Create(&handle) != apm_->kNoError) +#endif + { + handle = NULL; + } else { + assert(handle != NULL); + } + + return handle; +} + +int NoiseSuppressionImpl::DestroyHandle(void* handle) const { +#if defined(WEBRTC_NS_FLOAT) + return WebRtcNs_Free(static_cast(handle)); +#elif defined(WEBRTC_NS_FIXED) + return WebRtcNsx_Free(static_cast(handle)); +#endif +} + +int NoiseSuppressionImpl::InitializeHandle(void* handle) const { +#if defined(WEBRTC_NS_FLOAT) + return WebRtcNs_Init(static_cast(handle), apm_->sample_rate_hz()); +#elif defined(WEBRTC_NS_FIXED) + return WebRtcNsx_Init(static_cast(handle), apm_->sample_rate_hz()); +#endif +} + +int NoiseSuppressionImpl::ConfigureHandle(void* handle) const { +#if defined(WEBRTC_NS_FLOAT) + return WebRtcNs_set_policy(static_cast(handle), + MapSetting(level_)); +#elif defined(WEBRTC_NS_FIXED) + return WebRtcNsx_set_policy(static_cast(handle), + MapSetting(level_)); +#endif +} + +int NoiseSuppressionImpl::num_handles_required() const { + return apm_->num_output_channels(); +} + +int NoiseSuppressionImpl::GetHandleError(void* handle) const { + // The NS has no get_error() function. + assert(handle != NULL); + return apm_->kUnspecifiedError; +} +} // namespace webrtc + diff --git a/libs/miniwebrtc/audio/processing/noise_suppression_impl.h b/libs/miniwebrtc/audio/processing/noise_suppression_impl.h new file mode 100644 index 00000000..7b65b708 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/noise_suppression_impl.h @@ -0,0 +1,51 @@ +/* + * 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_PROCESSING_NOISE_SUPPRESSION_IMPL_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_NOISE_SUPPRESSION_IMPL_H_ + +#include "audio_processing.h" +#include "processing_component.h" + +namespace webrtc { +class AudioProcessingImpl; +class AudioBuffer; + +class NoiseSuppressionImpl : public NoiseSuppression, + public ProcessingComponent { + public: + explicit NoiseSuppressionImpl(const AudioProcessingImpl* apm); + virtual ~NoiseSuppressionImpl(); + + int ProcessCaptureAudio(AudioBuffer* audio); + + // NoiseSuppression implementation. + virtual bool is_enabled() const; + + private: + // NoiseSuppression implementation. + virtual int Enable(bool enable); + virtual int set_level(Level level); + virtual Level level() const; + + // ProcessingComponent implementation. + virtual void* CreateHandle() const; + virtual int InitializeHandle(void* handle) const; + virtual int ConfigureHandle(void* handle) const; + virtual int DestroyHandle(void* handle) const; + virtual int num_handles_required() const; + virtual int GetHandleError(void* handle) const; + + const AudioProcessingImpl* apm_; + Level level_; +}; +} // namespace webrtc + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_NOISE_SUPPRESSION_IMPL_H_ diff --git a/libs/miniwebrtc/audio/processing/ns/defines.h b/libs/miniwebrtc/audio/processing/ns/defines.h new file mode 100644 index 00000000..d2539679 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/ns/defines.h @@ -0,0 +1,53 @@ +/* + * 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_PROCESSING_NS_MAIN_SOURCE_DEFINES_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_DEFINES_H_ + +//#define PROCESS_FLOW_0 // Use the traditional method. +//#define PROCESS_FLOW_1 // Use traditional with DD estimate of prior SNR. +#define PROCESS_FLOW_2 // Use the new method of speech/noise classification. + +#define BLOCKL_MAX 160 // max processing block length: 160 +#define ANAL_BLOCKL_MAX 256 // max analysis block length: 256 +#define HALF_ANAL_BLOCKL 129 // half max analysis block length + 1 + +#define QUANTILE (float)0.25 + +#define SIMULT 3 +#define END_STARTUP_LONG 200 +#define END_STARTUP_SHORT 50 +#define FACTOR (float)40.0 +#define WIDTH (float)0.01 + +#define SMOOTH (float)0.75 // filter smoothing +// Length of fft work arrays. +#define IP_LENGTH (ANAL_BLOCKL_MAX >> 1) // must be at least ceil(2 + sqrt(ANAL_BLOCKL_MAX/2)) +#define W_LENGTH (ANAL_BLOCKL_MAX >> 1) + +//PARAMETERS FOR NEW METHOD +#define DD_PR_SNR (float)0.98 // DD update of prior SNR +#define LRT_TAVG (float)0.50 // tavg parameter for LRT (previously 0.90) +#define SPECT_FL_TAVG (float)0.30 // tavg parameter for spectral flatness measure +#define SPECT_DIFF_TAVG (float)0.30 // tavg parameter for spectral difference measure +#define PRIOR_UPDATE (float)0.10 // update parameter of prior model +#define NOISE_UPDATE (float)0.90 // update parameter for noise +#define SPEECH_UPDATE (float)0.99 // update parameter when likely speech +#define WIDTH_PR_MAP (float)4.0 // width parameter in sigmoid map for prior model +#define LRT_FEATURE_THR (float)0.5 // default threshold for LRT feature +#define SF_FEATURE_THR (float)0.5 // default threshold for Spectral Flatness feature +#define SD_FEATURE_THR (float)0.5 // default threshold for Spectral Difference feature +#define PROB_RANGE (float)0.20 // probability threshold for noise state in + // speech/noise likelihood +#define HIST_PAR_EST 1000 // histogram size for estimation of parameters +#define GAMMA_PAUSE (float)0.05 // update for conservative noise estimate +// +#define B_LIM (float)0.5 // threshold in final energy gain factor calculation +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_DEFINES_H_ diff --git a/libs/miniwebrtc/audio/processing/ns/noise_suppression.c b/libs/miniwebrtc/audio/processing/ns/noise_suppression.c new file mode 100644 index 00000000..a1e5ae8b --- /dev/null +++ b/libs/miniwebrtc/audio/processing/ns/noise_suppression.c @@ -0,0 +1,48 @@ +/* + * 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 +#include + +#include "noise_suppression.h" +#include "ns_core.h" +#include "defines.h" + +int WebRtcNs_Create(NsHandle** NS_inst) { + *NS_inst = (NsHandle*) malloc(sizeof(NSinst_t)); + if (*NS_inst != NULL) { + (*(NSinst_t**)NS_inst)->initFlag = 0; + return 0; + } else { + return -1; + } + +} + +int WebRtcNs_Free(NsHandle* NS_inst) { + free(NS_inst); + return 0; +} + + +int WebRtcNs_Init(NsHandle* NS_inst, WebRtc_UWord32 fs) { + return WebRtcNs_InitCore((NSinst_t*) NS_inst, fs); +} + +int WebRtcNs_set_policy(NsHandle* NS_inst, int mode) { + return WebRtcNs_set_policy_core((NSinst_t*) NS_inst, mode); +} + + +int WebRtcNs_Process(NsHandle* NS_inst, short* spframe, short* spframe_H, + short* outframe, short* outframe_H) { + return WebRtcNs_ProcessCore( + (NSinst_t*) NS_inst, spframe, spframe_H, outframe, outframe_H); +} diff --git a/libs/miniwebrtc/audio/processing/ns/noise_suppression.h b/libs/miniwebrtc/audio/processing/ns/noise_suppression.h new file mode 100644 index 00000000..1f498c1c --- /dev/null +++ b/libs/miniwebrtc/audio/processing/ns/noise_suppression.h @@ -0,0 +1,110 @@ +/* + * 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_PROCESSING_NS_INCLUDE_NOISE_SUPPRESSION_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_NS_INCLUDE_NOISE_SUPPRESSION_H_ + +#include "typedefs.h" + +typedef struct NsHandleT NsHandle; + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This function creates an instance to the noise reduction structure + * + * Input: + * - NS_inst : Pointer to noise reduction instance that should be + * created + * + * Output: + * - NS_inst : Pointer to created noise reduction instance + * + * Return value : 0 - Ok + * -1 - Error + */ +int WebRtcNs_Create(NsHandle** NS_inst); + + +/* + * This function frees the dynamic memory of a specified Noise Reduction + * instance. + * + * Input: + * - NS_inst : Pointer to NS instance that should be freed + * + * Return value : 0 - Ok + * -1 - Error + */ +int WebRtcNs_Free(NsHandle* NS_inst); + + +/* + * This function initializes a NS instance + * + * Input: + * - NS_inst : Instance that should be initialized + * - fs : sampling frequency + * + * Output: + * - NS_inst : Initialized instance + * + * Return value : 0 - Ok + * -1 - Error + */ +int WebRtcNs_Init(NsHandle* NS_inst, WebRtc_UWord32 fs); + +/* + * This changes the aggressiveness of the noise suppression method. + * + * Input: + * - NS_inst : Instance that should be initialized + * - mode : 0: Mild, 1: Medium , 2: Aggressive + * + * Output: + * - NS_inst : Initialized instance + * + * Return value : 0 - Ok + * -1 - Error + */ +int WebRtcNs_set_policy(NsHandle* NS_inst, int mode); + + +/* + * This functions does Noise Suppression for the inserted speech frame. The + * input and output signals should always be 10ms (80 or 160 samples). + * + * Input + * - NS_inst : NS Instance. Needs to be initiated before call. + * - spframe : Pointer to speech frame buffer for L band + * - spframe_H : Pointer to speech frame buffer for H band + * - fs : sampling frequency + * + * Output: + * - NS_inst : Updated NS instance + * - outframe : Pointer to output frame for L band + * - outframe_H : Pointer to output frame for H band + * + * Return value : 0 - OK + * -1 - Error + */ +int WebRtcNs_Process(NsHandle* NS_inst, + short* spframe, + short* spframe_H, + short* outframe, + short* outframe_H); + +#ifdef __cplusplus +} +#endif + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_NS_INCLUDE_NOISE_SUPPRESSION_H_ diff --git a/libs/miniwebrtc/audio/processing/ns/noise_suppression_x.c b/libs/miniwebrtc/audio/processing/ns/noise_suppression_x.c new file mode 100644 index 00000000..6d27d0e1 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/ns/noise_suppression_x.c @@ -0,0 +1,48 @@ +/* + * 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 +#include + +#include "noise_suppression_x.h" +#include "nsx_core.h" +#include "nsx_defines.h" + +int WebRtcNsx_Create(NsxHandle** nsxInst) { + *nsxInst = (NsxHandle*)malloc(sizeof(NsxInst_t)); + if (*nsxInst != NULL) { + (*(NsxInst_t**)nsxInst)->initFlag = 0; + return 0; + } else { + return -1; + } + +} + +int WebRtcNsx_Free(NsxHandle* nsxInst) { + free(nsxInst); + return 0; +} + +int WebRtcNsx_Init(NsxHandle* nsxInst, WebRtc_UWord32 fs) { + return WebRtcNsx_InitCore((NsxInst_t*)nsxInst, fs); +} + +int WebRtcNsx_set_policy(NsxHandle* nsxInst, int mode) { + return WebRtcNsx_set_policy_core((NsxInst_t*)nsxInst, mode); +} + +int WebRtcNsx_Process(NsxHandle* nsxInst, short* speechFrame, + short* speechFrameHB, short* outFrame, + short* outFrameHB) { + return WebRtcNsx_ProcessCore( + (NsxInst_t*)nsxInst, speechFrame, speechFrameHB, outFrame, outFrameHB); +} + diff --git a/libs/miniwebrtc/audio/processing/ns/noise_suppression_x.h b/libs/miniwebrtc/audio/processing/ns/noise_suppression_x.h new file mode 100644 index 00000000..b6eef904 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/ns/noise_suppression_x.h @@ -0,0 +1,109 @@ +/* + * 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_PROCESSING_NS_INCLUDE_NOISE_SUPPRESSION_X_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_NS_INCLUDE_NOISE_SUPPRESSION_X_H_ + +#include "typedefs.h" + +typedef struct NsxHandleT NsxHandle; + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This function creates an instance to the noise reduction structure + * + * Input: + * - nsxInst : Pointer to noise reduction instance that should be + * created + * + * Output: + * - nsxInst : Pointer to created noise reduction instance + * + * Return value : 0 - Ok + * -1 - Error + */ +int WebRtcNsx_Create(NsxHandle** nsxInst); + + +/* + * This function frees the dynamic memory of a specified Noise Suppression + * instance. + * + * Input: + * - nsxInst : Pointer to NS instance that should be freed + * + * Return value : 0 - Ok + * -1 - Error + */ +int WebRtcNsx_Free(NsxHandle* nsxInst); + + +/* + * This function initializes a NS instance + * + * Input: + * - nsxInst : Instance that should be initialized + * - fs : sampling frequency + * + * Output: + * - nsxInst : Initialized instance + * + * Return value : 0 - Ok + * -1 - Error + */ +int WebRtcNsx_Init(NsxHandle* nsxInst, WebRtc_UWord32 fs); + +/* + * This changes the aggressiveness of the noise suppression method. + * + * Input: + * - nsxInst : Instance that should be initialized + * - mode : 0: Mild, 1: Medium , 2: Aggressive + * + * Output: + * - nsxInst : Initialized instance + * + * Return value : 0 - Ok + * -1 - Error + */ +int WebRtcNsx_set_policy(NsxHandle* nsxInst, int mode); + +/* + * This functions does noise suppression for the inserted speech frame. The + * input and output signals should always be 10ms (80 or 160 samples). + * + * Input + * - nsxInst : NSx instance. Needs to be initiated before call. + * - speechFrame : Pointer to speech frame buffer for L band + * - speechFrameHB : Pointer to speech frame buffer for H band + * - fs : sampling frequency + * + * Output: + * - nsxInst : Updated NSx instance + * - outFrame : Pointer to output frame for L band + * - outFrameHB : Pointer to output frame for H band + * + * Return value : 0 - OK + * -1 - Error + */ +int WebRtcNsx_Process(NsxHandle* nsxInst, + short* speechFrame, + short* speechFrameHB, + short* outFrame, + short* outFrameHB); + +#ifdef __cplusplus +} +#endif + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_NS_INCLUDE_NOISE_SUPPRESSION_X_H_ diff --git a/libs/miniwebrtc/audio/processing/ns/ns_core.c b/libs/miniwebrtc/audio/processing/ns/ns_core.c new file mode 100644 index 00000000..e5aa4ff3 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/ns/ns_core.c @@ -0,0 +1,1303 @@ +/* + * 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 +#include +//#include +#include +#include "noise_suppression.h" +#include "ns_core.h" +#include "windows_private.h" +#include "fft4g.h" +#include "signal_processing_library.h" + +// Set Feature Extraction Parameters +void WebRtcNs_set_feature_extraction_parameters(NSinst_t* inst) { + //bin size of histogram + inst->featureExtractionParams.binSizeLrt = (float)0.1; + inst->featureExtractionParams.binSizeSpecFlat = (float)0.05; + inst->featureExtractionParams.binSizeSpecDiff = (float)0.1; + + //range of histogram over which lrt threshold is computed + inst->featureExtractionParams.rangeAvgHistLrt = (float)1.0; + + //scale parameters: multiply dominant peaks of the histograms by scale factor to obtain + // thresholds for prior model + inst->featureExtractionParams.factor1ModelPars = (float)1.20; //for lrt and spectral diff + inst->featureExtractionParams.factor2ModelPars = (float)0.9; //for spectral_flatness: + // used when noise is flatter than speech + + //peak limit for spectral flatness (varies between 0 and 1) + inst->featureExtractionParams.thresPosSpecFlat = (float)0.6; + + //limit on spacing of two highest peaks in histogram: spacing determined by bin size + inst->featureExtractionParams.limitPeakSpacingSpecFlat = + 2 * inst->featureExtractionParams.binSizeSpecFlat; + inst->featureExtractionParams.limitPeakSpacingSpecDiff = + 2 * inst->featureExtractionParams.binSizeSpecDiff; + + //limit on relevance of second peak: + inst->featureExtractionParams.limitPeakWeightsSpecFlat = (float)0.5; + inst->featureExtractionParams.limitPeakWeightsSpecDiff = (float)0.5; + + // fluctuation limit of lrt feature + inst->featureExtractionParams.thresFluctLrt = (float)0.05; + + //limit on the max and min values for the feature thresholds + inst->featureExtractionParams.maxLrt = (float)1.0; + inst->featureExtractionParams.minLrt = (float)0.20; + + inst->featureExtractionParams.maxSpecFlat = (float)0.95; + inst->featureExtractionParams.minSpecFlat = (float)0.10; + + inst->featureExtractionParams.maxSpecDiff = (float)1.0; + inst->featureExtractionParams.minSpecDiff = (float)0.16; + + //criteria of weight of histogram peak to accept/reject feature + inst->featureExtractionParams.thresWeightSpecFlat = (int)(0.3 + * (inst->modelUpdatePars[1])); //for spectral flatness + inst->featureExtractionParams.thresWeightSpecDiff = (int)(0.3 + * (inst->modelUpdatePars[1])); //for spectral difference +} + +// Initialize state +int WebRtcNs_InitCore(NSinst_t* inst, WebRtc_UWord32 fs) { + int i; + //We only support 10ms frames + + //check for valid pointer + if (inst == NULL) { + return -1; + } + + // Initialization of struct + if (fs == 8000 || fs == 16000 || fs == 32000) { + inst->fs = fs; + } else { + return -1; + } + inst->windShift = 0; + if (fs == 8000) { + // We only support 10ms frames + inst->blockLen = 80; + inst->blockLen10ms = 80; + inst->anaLen = 128; + inst->window = kBlocks80w128; + inst->outLen = 0; + } else if (fs == 16000) { + // We only support 10ms frames + inst->blockLen = 160; + inst->blockLen10ms = 160; + inst->anaLen = 256; + inst->window = kBlocks160w256; + inst->outLen = 0; + } else if (fs == 32000) { + // We only support 10ms frames + inst->blockLen = 160; + inst->blockLen10ms = 160; + inst->anaLen = 256; + inst->window = kBlocks160w256; + inst->outLen = 0; + } + inst->magnLen = inst->anaLen / 2 + 1; // Number of frequency bins + + // Initialize fft work arrays. + inst->ip[0] = 0; // Setting this triggers initialization. + memset(inst->dataBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX); + WebRtc_rdft(inst->anaLen, 1, inst->dataBuf, inst->ip, inst->wfft); + + memset(inst->dataBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX); + memset(inst->syntBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX); + + //for HB processing + memset(inst->dataBufHB, 0, sizeof(float) * ANAL_BLOCKL_MAX); + + //for quantile noise estimation + memset(inst->quantile, 0, sizeof(float) * HALF_ANAL_BLOCKL); + for (i = 0; i < SIMULT * HALF_ANAL_BLOCKL; i++) { + inst->lquantile[i] = (float)8.0; + inst->density[i] = (float)0.3; + } + + for (i = 0; i < SIMULT; i++) { + inst->counter[i] = (int)floor((float)(END_STARTUP_LONG * (i + 1)) / (float)SIMULT); + } + + inst->updates = 0; + + // Wiener filter initialization + for (i = 0; i < HALF_ANAL_BLOCKL; i++) { + inst->smooth[i] = (float)1.0; + } + + // Set the aggressiveness: default + inst->aggrMode = 0; + + //initialize variables for new method + inst->priorSpeechProb = (float)0.5; //prior prob for speech/noise + for (i = 0; i < HALF_ANAL_BLOCKL; i++) { + inst->magnPrev[i] = (float)0.0; //previous mag spectrum + inst->noisePrev[i] = (float)0.0; //previous noise-spectrum + inst->logLrtTimeAvg[i] = LRT_FEATURE_THR; //smooth LR ratio (same as threshold) + inst->magnAvgPause[i] = (float)0.0; //conservative noise spectrum estimate + inst->speechProbHB[i] = (float)0.0; //for estimation of HB in second pass + inst->initMagnEst[i] = (float)0.0; //initial average mag spectrum + } + + //feature quantities + inst->featureData[0] = SF_FEATURE_THR; //spectral flatness (start on threshold) + inst->featureData[1] = (float)0.0; //spectral entropy: not used in this version + inst->featureData[2] = (float)0.0; //spectral variance: not used in this version + inst->featureData[3] = LRT_FEATURE_THR; //average lrt factor (start on threshold) + inst->featureData[4] = SF_FEATURE_THR; //spectral template diff (start on threshold) + inst->featureData[5] = (float)0.0; //normalization for spectral-diff + inst->featureData[6] = (float)0.0; //window time-average of input magnitude spectrum + + //histogram quantities: used to estimate/update thresholds for features + for (i = 0; i < HIST_PAR_EST; i++) { + inst->histLrt[i] = 0; + inst->histSpecFlat[i] = 0; + inst->histSpecDiff[i] = 0; + } + + inst->blockInd = -1; //frame counter + inst->priorModelPars[0] = LRT_FEATURE_THR; //default threshold for lrt feature + inst->priorModelPars[1] = (float)0.5; //threshold for spectral flatness: + // determined on-line + inst->priorModelPars[2] = (float)1.0; //sgn_map par for spectral measure: + // 1 for flatness measure + inst->priorModelPars[3] = (float)0.5; //threshold for template-difference feature: + // determined on-line + inst->priorModelPars[4] = (float)1.0; //default weighting parameter for lrt feature + inst->priorModelPars[5] = (float)0.0; //default weighting parameter for + // spectral flatness feature + inst->priorModelPars[6] = (float)0.0; //default weighting parameter for + // spectral difference feature + + inst->modelUpdatePars[0] = 2; //update flag for parameters: + // 0 no update, 1=update once, 2=update every window + inst->modelUpdatePars[1] = 500; //window for update + inst->modelUpdatePars[2] = 0; //counter for update of conservative noise spectrum + //counter if the feature thresholds are updated during the sequence + inst->modelUpdatePars[3] = inst->modelUpdatePars[1]; + + inst->signalEnergy = 0.0; + inst->sumMagn = 0.0; + inst->whiteNoiseLevel = 0.0; + inst->pinkNoiseNumerator = 0.0; + inst->pinkNoiseExp = 0.0; + + WebRtcNs_set_feature_extraction_parameters(inst); // Set feature configuration + + //default mode + WebRtcNs_set_policy_core(inst, 0); + + + memset(inst->outBuf, 0, sizeof(float) * 3 * BLOCKL_MAX); + + inst->initFlag = 1; + return 0; +} + +int WebRtcNs_set_policy_core(NSinst_t* inst, int mode) { + // allow for modes:0,1,2,3 + if (mode < 0 || mode > 3) { + return (-1); + } + + inst->aggrMode = mode; + if (mode == 0) { + inst->overdrive = (float)1.0; + inst->denoiseBound = (float)0.5; + inst->gainmap = 0; + } else if (mode == 1) { + //inst->overdrive = (float)1.25; + inst->overdrive = (float)1.0; + inst->denoiseBound = (float)0.25; + inst->gainmap = 1; + } else if (mode == 2) { + //inst->overdrive = (float)1.25; + inst->overdrive = (float)1.1; + inst->denoiseBound = (float)0.125; + inst->gainmap = 1; + } else if (mode == 3) { + //inst->overdrive = (float)1.30; + inst->overdrive = (float)1.25; + inst->denoiseBound = (float)0.09; + inst->gainmap = 1; + } + return 0; +} + +// Estimate noise +void WebRtcNs_NoiseEstimation(NSinst_t* inst, float* magn, float* noise) { + int i, s, offset; + float lmagn[HALF_ANAL_BLOCKL], delta; + + if (inst->updates < END_STARTUP_LONG) { + inst->updates++; + } + + for (i = 0; i < inst->magnLen; i++) { + lmagn[i] = (float)log(magn[i]); + } + + // loop over simultaneous estimates + for (s = 0; s < SIMULT; s++) { + offset = s * inst->magnLen; + + // newquantest(...) + for (i = 0; i < inst->magnLen; i++) { + // compute delta + if (inst->density[offset + i] > 1.0) { + delta = FACTOR * (float)1.0 / inst->density[offset + i]; + } else { + delta = FACTOR; + } + + // update log quantile estimate + if (lmagn[i] > inst->lquantile[offset + i]) { + inst->lquantile[offset + i] += QUANTILE * delta + / (float)(inst->counter[s] + 1); + } else { + inst->lquantile[offset + i] -= ((float)1.0 - QUANTILE) * delta + / (float)(inst->counter[s] + 1); + } + + // update density estimate + if (fabs(lmagn[i] - inst->lquantile[offset + i]) < WIDTH) { + inst->density[offset + i] = ((float)inst->counter[s] * inst->density[offset + + i] + (float)1.0 / ((float)2.0 * WIDTH)) / (float)(inst->counter[s] + 1); + } + } // end loop over magnitude spectrum + + if (inst->counter[s] >= END_STARTUP_LONG) { + inst->counter[s] = 0; + if (inst->updates >= END_STARTUP_LONG) { + for (i = 0; i < inst->magnLen; i++) { + inst->quantile[i] = (float)exp(inst->lquantile[offset + i]); + } + } + } + + inst->counter[s]++; + } // end loop over simultaneous estimates + + // Sequentially update the noise during startup + if (inst->updates < END_STARTUP_LONG) { + // Use the last "s" to get noise during startup that differ from zero. + for (i = 0; i < inst->magnLen; i++) { + inst->quantile[i] = (float)exp(inst->lquantile[offset + i]); + } + } + + for (i = 0; i < inst->magnLen; i++) { + noise[i] = inst->quantile[i]; + } +} + +// Extract thresholds for feature parameters +// histograms are computed over some window_size (given by inst->modelUpdatePars[1]) +// thresholds and weights are extracted every window +// flag 0 means update histogram only, flag 1 means compute the thresholds/weights +// threshold and weights are returned in: inst->priorModelPars +void WebRtcNs_FeatureParameterExtraction(NSinst_t* inst, int flag) { + int i, useFeatureSpecFlat, useFeatureSpecDiff, numHistLrt; + int maxPeak1, maxPeak2; + int weightPeak1SpecFlat, weightPeak2SpecFlat, weightPeak1SpecDiff, weightPeak2SpecDiff; + + float binMid, featureSum; + float posPeak1SpecFlat, posPeak2SpecFlat, posPeak1SpecDiff, posPeak2SpecDiff; + float fluctLrt, avgHistLrt, avgSquareHistLrt, avgHistLrtCompl; + + //3 features: lrt, flatness, difference + //lrt_feature = inst->featureData[3]; + //flat_feature = inst->featureData[0]; + //diff_feature = inst->featureData[4]; + + //update histograms + if (flag == 0) { + // LRT + if ((inst->featureData[3] < HIST_PAR_EST * inst->featureExtractionParams.binSizeLrt) + && (inst->featureData[3] >= 0.0)) { + i = (int)(inst->featureData[3] / inst->featureExtractionParams.binSizeLrt); + inst->histLrt[i]++; + } + // Spectral flatness + if ((inst->featureData[0] < HIST_PAR_EST + * inst->featureExtractionParams.binSizeSpecFlat) + && (inst->featureData[0] >= 0.0)) { + i = (int)(inst->featureData[0] / inst->featureExtractionParams.binSizeSpecFlat); + inst->histSpecFlat[i]++; + } + // Spectral difference + if ((inst->featureData[4] < HIST_PAR_EST + * inst->featureExtractionParams.binSizeSpecDiff) + && (inst->featureData[4] >= 0.0)) { + i = (int)(inst->featureData[4] / inst->featureExtractionParams.binSizeSpecDiff); + inst->histSpecDiff[i]++; + } + } + + // extract parameters for speech/noise probability + if (flag == 1) { + //lrt feature: compute the average over inst->featureExtractionParams.rangeAvgHistLrt + avgHistLrt = 0.0; + avgHistLrtCompl = 0.0; + avgSquareHistLrt = 0.0; + numHistLrt = 0; + for (i = 0; i < HIST_PAR_EST; i++) { + binMid = ((float)i + (float)0.5) * inst->featureExtractionParams.binSizeLrt; + if (binMid <= inst->featureExtractionParams.rangeAvgHistLrt) { + avgHistLrt += inst->histLrt[i] * binMid; + numHistLrt += inst->histLrt[i]; + } + avgSquareHistLrt += inst->histLrt[i] * binMid * binMid; + avgHistLrtCompl += inst->histLrt[i] * binMid; + } + if (numHistLrt > 0) { + avgHistLrt = avgHistLrt / ((float)numHistLrt); + } + avgHistLrtCompl = avgHistLrtCompl / ((float)inst->modelUpdatePars[1]); + avgSquareHistLrt = avgSquareHistLrt / ((float)inst->modelUpdatePars[1]); + fluctLrt = avgSquareHistLrt - avgHistLrt * avgHistLrtCompl; + // get threshold for lrt feature: + if (fluctLrt < inst->featureExtractionParams.thresFluctLrt) { + //very low fluct, so likely noise + inst->priorModelPars[0] = inst->featureExtractionParams.maxLrt; + } else { + inst->priorModelPars[0] = inst->featureExtractionParams.factor1ModelPars + * avgHistLrt; + // check if value is within min/max range + if (inst->priorModelPars[0] < inst->featureExtractionParams.minLrt) { + inst->priorModelPars[0] = inst->featureExtractionParams.minLrt; + } + if (inst->priorModelPars[0] > inst->featureExtractionParams.maxLrt) { + inst->priorModelPars[0] = inst->featureExtractionParams.maxLrt; + } + } + // done with lrt feature + + // + // for spectral flatness and spectral difference: compute the main peaks of histogram + maxPeak1 = 0; + maxPeak2 = 0; + posPeak1SpecFlat = 0.0; + posPeak2SpecFlat = 0.0; + weightPeak1SpecFlat = 0; + weightPeak2SpecFlat = 0; + + // peaks for flatness + for (i = 0; i < HIST_PAR_EST; i++) { + binMid = ((float)i + (float)0.5) * inst->featureExtractionParams.binSizeSpecFlat; + if (inst->histSpecFlat[i] > maxPeak1) { + // Found new "first" peak + maxPeak2 = maxPeak1; + weightPeak2SpecFlat = weightPeak1SpecFlat; + posPeak2SpecFlat = posPeak1SpecFlat; + + maxPeak1 = inst->histSpecFlat[i]; + weightPeak1SpecFlat = inst->histSpecFlat[i]; + posPeak1SpecFlat = binMid; + } else if (inst->histSpecFlat[i] > maxPeak2) { + // Found new "second" peak + maxPeak2 = inst->histSpecFlat[i]; + weightPeak2SpecFlat = inst->histSpecFlat[i]; + posPeak2SpecFlat = binMid; + } + } + + //compute two peaks for spectral difference + maxPeak1 = 0; + maxPeak2 = 0; + posPeak1SpecDiff = 0.0; + posPeak2SpecDiff = 0.0; + weightPeak1SpecDiff = 0; + weightPeak2SpecDiff = 0; + // peaks for spectral difference + for (i = 0; i < HIST_PAR_EST; i++) { + binMid = ((float)i + (float)0.5) * inst->featureExtractionParams.binSizeSpecDiff; + if (inst->histSpecDiff[i] > maxPeak1) { + // Found new "first" peak + maxPeak2 = maxPeak1; + weightPeak2SpecDiff = weightPeak1SpecDiff; + posPeak2SpecDiff = posPeak1SpecDiff; + + maxPeak1 = inst->histSpecDiff[i]; + weightPeak1SpecDiff = inst->histSpecDiff[i]; + posPeak1SpecDiff = binMid; + } else if (inst->histSpecDiff[i] > maxPeak2) { + // Found new "second" peak + maxPeak2 = inst->histSpecDiff[i]; + weightPeak2SpecDiff = inst->histSpecDiff[i]; + posPeak2SpecDiff = binMid; + } + } + + // for spectrum flatness feature + useFeatureSpecFlat = 1; + // merge the two peaks if they are close + if ((fabs(posPeak2SpecFlat - posPeak1SpecFlat) + < inst->featureExtractionParams.limitPeakSpacingSpecFlat) + && (weightPeak2SpecFlat + > inst->featureExtractionParams.limitPeakWeightsSpecFlat + * weightPeak1SpecFlat)) { + weightPeak1SpecFlat += weightPeak2SpecFlat; + posPeak1SpecFlat = (float)0.5 * (posPeak1SpecFlat + posPeak2SpecFlat); + } + //reject if weight of peaks is not large enough, or peak value too small + if (weightPeak1SpecFlat < inst->featureExtractionParams.thresWeightSpecFlat + || posPeak1SpecFlat < inst->featureExtractionParams.thresPosSpecFlat) { + useFeatureSpecFlat = 0; + } + // if selected, get the threshold + if (useFeatureSpecFlat == 1) { + // compute the threshold + inst->priorModelPars[1] = inst->featureExtractionParams.factor2ModelPars + * posPeak1SpecFlat; + //check if value is within min/max range + if (inst->priorModelPars[1] < inst->featureExtractionParams.minSpecFlat) { + inst->priorModelPars[1] = inst->featureExtractionParams.minSpecFlat; + } + if (inst->priorModelPars[1] > inst->featureExtractionParams.maxSpecFlat) { + inst->priorModelPars[1] = inst->featureExtractionParams.maxSpecFlat; + } + } + // done with flatness feature + + // for template feature + useFeatureSpecDiff = 1; + // merge the two peaks if they are close + if ((fabs(posPeak2SpecDiff - posPeak1SpecDiff) + < inst->featureExtractionParams.limitPeakSpacingSpecDiff) + && (weightPeak2SpecDiff + > inst->featureExtractionParams.limitPeakWeightsSpecDiff + * weightPeak1SpecDiff)) { + weightPeak1SpecDiff += weightPeak2SpecDiff; + posPeak1SpecDiff = (float)0.5 * (posPeak1SpecDiff + posPeak2SpecDiff); + } + // get the threshold value + inst->priorModelPars[3] = inst->featureExtractionParams.factor1ModelPars + * posPeak1SpecDiff; + //reject if weight of peaks is not large enough + if (weightPeak1SpecDiff < inst->featureExtractionParams.thresWeightSpecDiff) { + useFeatureSpecDiff = 0; + } + //check if value is within min/max range + if (inst->priorModelPars[3] < inst->featureExtractionParams.minSpecDiff) { + inst->priorModelPars[3] = inst->featureExtractionParams.minSpecDiff; + } + if (inst->priorModelPars[3] > inst->featureExtractionParams.maxSpecDiff) { + inst->priorModelPars[3] = inst->featureExtractionParams.maxSpecDiff; + } + // done with spectral difference feature + + // don't use template feature if fluctuation of lrt feature is very low: + // most likely just noise state + if (fluctLrt < inst->featureExtractionParams.thresFluctLrt) { + useFeatureSpecDiff = 0; + } + + // select the weights between the features + // inst->priorModelPars[4] is weight for lrt: always selected + // inst->priorModelPars[5] is weight for spectral flatness + // inst->priorModelPars[6] is weight for spectral difference + featureSum = (float)(1 + useFeatureSpecFlat + useFeatureSpecDiff); + inst->priorModelPars[4] = (float)1.0 / featureSum; + inst->priorModelPars[5] = ((float)useFeatureSpecFlat) / featureSum; + inst->priorModelPars[6] = ((float)useFeatureSpecDiff) / featureSum; + + // set hists to zero for next update + if (inst->modelUpdatePars[0] >= 1) { + for (i = 0; i < HIST_PAR_EST; i++) { + inst->histLrt[i] = 0; + inst->histSpecFlat[i] = 0; + inst->histSpecDiff[i] = 0; + } + } + } // end of flag == 1 +} + +// Compute spectral flatness on input spectrum +// magnIn is the magnitude spectrum +// spectral flatness is returned in inst->featureData[0] +void WebRtcNs_ComputeSpectralFlatness(NSinst_t* inst, float* magnIn) { + int i; + int shiftLP = 1; //option to remove first bin(s) from spectral measures + float avgSpectralFlatnessNum, avgSpectralFlatnessDen, spectralTmp; + + // comute spectral measures + // for flatness + avgSpectralFlatnessNum = 0.0; + avgSpectralFlatnessDen = inst->sumMagn; + for (i = 0; i < shiftLP; i++) { + avgSpectralFlatnessDen -= magnIn[i]; + } + // compute log of ratio of the geometric to arithmetic mean: check for log(0) case + for (i = shiftLP; i < inst->magnLen; i++) { + if (magnIn[i] > 0.0) { + avgSpectralFlatnessNum += (float)log(magnIn[i]); + } else { + inst->featureData[0] -= SPECT_FL_TAVG * inst->featureData[0]; + return; + } + } + //normalize + avgSpectralFlatnessDen = avgSpectralFlatnessDen / inst->magnLen; + avgSpectralFlatnessNum = avgSpectralFlatnessNum / inst->magnLen; + + //ratio and inverse log: check for case of log(0) + spectralTmp = (float)exp(avgSpectralFlatnessNum) / avgSpectralFlatnessDen; + + //time-avg update of spectral flatness feature + inst->featureData[0] += SPECT_FL_TAVG * (spectralTmp - inst->featureData[0]); + // done with flatness feature +} + +// Compute the difference measure between input spectrum and a template/learned noise spectrum +// magnIn is the input spectrum +// the reference/template spectrum is inst->magnAvgPause[i] +// returns (normalized) spectral difference in inst->featureData[4] +void WebRtcNs_ComputeSpectralDifference(NSinst_t* inst, float* magnIn) { + // avgDiffNormMagn = var(magnIn) - cov(magnIn, magnAvgPause)^2 / var(magnAvgPause) + int i; + float avgPause, avgMagn, covMagnPause, varPause, varMagn, avgDiffNormMagn; + + avgPause = 0.0; + avgMagn = inst->sumMagn; + // compute average quantities + for (i = 0; i < inst->magnLen; i++) { + //conservative smooth noise spectrum from pause frames + avgPause += inst->magnAvgPause[i]; + } + avgPause = avgPause / ((float)inst->magnLen); + avgMagn = avgMagn / ((float)inst->magnLen); + + covMagnPause = 0.0; + varPause = 0.0; + varMagn = 0.0; + // compute variance and covariance quantities + for (i = 0; i < inst->magnLen; i++) { + covMagnPause += (magnIn[i] - avgMagn) * (inst->magnAvgPause[i] - avgPause); + varPause += (inst->magnAvgPause[i] - avgPause) * (inst->magnAvgPause[i] - avgPause); + varMagn += (magnIn[i] - avgMagn) * (magnIn[i] - avgMagn); + } + covMagnPause = covMagnPause / ((float)inst->magnLen); + varPause = varPause / ((float)inst->magnLen); + varMagn = varMagn / ((float)inst->magnLen); + // update of average magnitude spectrum + inst->featureData[6] += inst->signalEnergy; + + avgDiffNormMagn = varMagn - (covMagnPause * covMagnPause) / (varPause + (float)0.0001); + // normalize and compute time-avg update of difference feature + avgDiffNormMagn = (float)(avgDiffNormMagn / (inst->featureData[5] + (float)0.0001)); + inst->featureData[4] += SPECT_DIFF_TAVG * (avgDiffNormMagn - inst->featureData[4]); +} + +// Compute speech/noise probability +// speech/noise probability is returned in: probSpeechFinal +//magn is the input magnitude spectrum +//noise is the noise spectrum +//snrLocPrior is the prior snr for each freq. +//snr loc_post is the post snr for each freq. +void WebRtcNs_SpeechNoiseProb(NSinst_t* inst, float* probSpeechFinal, float* snrLocPrior, + float* snrLocPost) { + int i, sgnMap; + float invLrt, gainPrior, indPrior; + float logLrtTimeAvgKsum, besselTmp; + float indicator0, indicator1, indicator2; + float tmpFloat1, tmpFloat2; + float weightIndPrior0, weightIndPrior1, weightIndPrior2; + float threshPrior0, threshPrior1, threshPrior2; + float widthPrior, widthPrior0, widthPrior1, widthPrior2; + + widthPrior0 = WIDTH_PR_MAP; + widthPrior1 = (float)2.0 * WIDTH_PR_MAP; //width for pause region: + // lower range, so increase width in tanh map + widthPrior2 = (float)2.0 * WIDTH_PR_MAP; //for spectral-difference measure + + //threshold parameters for features + threshPrior0 = inst->priorModelPars[0]; + threshPrior1 = inst->priorModelPars[1]; + threshPrior2 = inst->priorModelPars[3]; + + //sign for flatness feature + sgnMap = (int)(inst->priorModelPars[2]); + + //weight parameters for features + weightIndPrior0 = inst->priorModelPars[4]; + weightIndPrior1 = inst->priorModelPars[5]; + weightIndPrior2 = inst->priorModelPars[6]; + + // compute feature based on average LR factor + // this is the average over all frequencies of the smooth log lrt + logLrtTimeAvgKsum = 0.0; + for (i = 0; i < inst->magnLen; i++) { + tmpFloat1 = (float)1.0 + (float)2.0 * snrLocPrior[i]; + tmpFloat2 = (float)2.0 * snrLocPrior[i] / (tmpFloat1 + (float)0.0001); + besselTmp = (snrLocPost[i] + (float)1.0) * tmpFloat2; + inst->logLrtTimeAvg[i] += LRT_TAVG * (besselTmp - (float)log(tmpFloat1) + - inst->logLrtTimeAvg[i]); + logLrtTimeAvgKsum += inst->logLrtTimeAvg[i]; + } + logLrtTimeAvgKsum = (float)logLrtTimeAvgKsum / (inst->magnLen); + inst->featureData[3] = logLrtTimeAvgKsum; + // done with computation of LR factor + + // + //compute the indicator functions + // + + // average lrt feature + widthPrior = widthPrior0; + //use larger width in tanh map for pause regions + if (logLrtTimeAvgKsum < threshPrior0) { + widthPrior = widthPrior1; + } + // compute indicator function: sigmoid map + indicator0 = (float)0.5 * ((float)tanh(widthPrior * + (logLrtTimeAvgKsum - threshPrior0)) + (float)1.0); + + //spectral flatness feature + tmpFloat1 = inst->featureData[0]; + widthPrior = widthPrior0; + //use larger width in tanh map for pause regions + if (sgnMap == 1 && (tmpFloat1 > threshPrior1)) { + widthPrior = widthPrior1; + } + if (sgnMap == -1 && (tmpFloat1 < threshPrior1)) { + widthPrior = widthPrior1; + } + // compute indicator function: sigmoid map + indicator1 = (float)0.5 * ((float)tanh((float)sgnMap * + widthPrior * (threshPrior1 - tmpFloat1)) + (float)1.0); + + //for template spectrum-difference + tmpFloat1 = inst->featureData[4]; + widthPrior = widthPrior0; + //use larger width in tanh map for pause regions + if (tmpFloat1 < threshPrior2) { + widthPrior = widthPrior2; + } + // compute indicator function: sigmoid map + indicator2 = (float)0.5 * ((float)tanh(widthPrior * (tmpFloat1 - threshPrior2)) + + (float)1.0); + + //combine the indicator function with the feature weights + indPrior = weightIndPrior0 * indicator0 + weightIndPrior1 * indicator1 + weightIndPrior2 + * indicator2; + // done with computing indicator function + + //compute the prior probability + inst->priorSpeechProb += PRIOR_UPDATE * (indPrior - inst->priorSpeechProb); + // make sure probabilities are within range: keep floor to 0.01 + if (inst->priorSpeechProb > 1.0) { + inst->priorSpeechProb = (float)1.0; + } + if (inst->priorSpeechProb < 0.01) { + inst->priorSpeechProb = (float)0.01; + } + + //final speech probability: combine prior model with LR factor: + gainPrior = ((float)1.0 - inst->priorSpeechProb) / (inst->priorSpeechProb + (float)0.0001); + for (i = 0; i < inst->magnLen; i++) { + invLrt = (float)exp(-inst->logLrtTimeAvg[i]); + invLrt = (float)gainPrior * invLrt; + probSpeechFinal[i] = (float)1.0 / ((float)1.0 + invLrt); + } +} + +int WebRtcNs_ProcessCore(NSinst_t* inst, + short* speechFrame, + short* speechFrameHB, + short* outFrame, + short* outFrameHB) { + // main routine for noise reduction + + int flagHB = 0; + int i; + const int kStartBand = 5; // Skip first frequency bins during estimation. + int updateParsFlag; + + float energy1, energy2, gain, factor, factor1, factor2; + float signalEnergy, sumMagn; + float snrPrior, currentEstimateStsa; + float tmpFloat1, tmpFloat2, tmpFloat3, probSpeech, probNonSpeech; + float gammaNoiseTmp, gammaNoiseOld; + float noiseUpdateTmp, fTmp, dTmp; + float fin[BLOCKL_MAX], fout[BLOCKL_MAX]; + float winData[ANAL_BLOCKL_MAX]; + float magn[HALF_ANAL_BLOCKL], noise[HALF_ANAL_BLOCKL]; + float theFilter[HALF_ANAL_BLOCKL], theFilterTmp[HALF_ANAL_BLOCKL]; + float snrLocPost[HALF_ANAL_BLOCKL], snrLocPrior[HALF_ANAL_BLOCKL]; + float probSpeechFinal[HALF_ANAL_BLOCKL], previousEstimateStsa[HALF_ANAL_BLOCKL]; + float real[ANAL_BLOCKL_MAX], imag[HALF_ANAL_BLOCKL]; + // Variables during startup + float sum_log_i = 0.0; + float sum_log_i_square = 0.0; + float sum_log_magn = 0.0; + float sum_log_i_log_magn = 0.0; + float parametric_noise = 0.0; + float parametric_exp = 0.0; + float parametric_num = 0.0; + + // SWB variables + int deltaBweHB = 1; + int deltaGainHB = 1; + float decayBweHB = 1.0; + float gainMapParHB = 1.0; + float gainTimeDomainHB = 1.0; + float avgProbSpeechHB, avgProbSpeechHBTmp, avgFilterGainHB, gainModHB; + + // Check that initiation has been done + if (inst->initFlag != 1) { + return (-1); + } + // Check for valid pointers based on sampling rate + if (inst->fs == 32000) { + if (speechFrameHB == NULL) { + return -1; + } + flagHB = 1; + // range for averaging low band quantities for H band gain + deltaBweHB = (int)inst->magnLen / 4; + deltaGainHB = deltaBweHB; + } + // + updateParsFlag = inst->modelUpdatePars[0]; + // + + //for LB do all processing + // convert to float + for (i = 0; i < inst->blockLen10ms; i++) { + fin[i] = (float)speechFrame[i]; + } + // update analysis buffer for L band + memcpy(inst->dataBuf, inst->dataBuf + inst->blockLen10ms, + sizeof(float) * (inst->anaLen - inst->blockLen10ms)); + memcpy(inst->dataBuf + inst->anaLen - inst->blockLen10ms, fin, + sizeof(float) * inst->blockLen10ms); + + if (flagHB == 1) { + // convert to float + for (i = 0; i < inst->blockLen10ms; i++) { + fin[i] = (float)speechFrameHB[i]; + } + // update analysis buffer for H band + memcpy(inst->dataBufHB, inst->dataBufHB + inst->blockLen10ms, + sizeof(float) * (inst->anaLen - inst->blockLen10ms)); + memcpy(inst->dataBufHB + inst->anaLen - inst->blockLen10ms, fin, + sizeof(float) * inst->blockLen10ms); + } + + // check if processing needed + if (inst->outLen == 0) { + // windowing + energy1 = 0.0; + for (i = 0; i < inst->anaLen; i++) { + winData[i] = inst->window[i] * inst->dataBuf[i]; + energy1 += winData[i] * winData[i]; + } + if (energy1 == 0.0) { + // synthesize the special case of zero input + // we want to avoid updating statistics in this case: + // Updating feature statistics when we have zeros only will cause thresholds to + // move towards zero signal situations. This in turn has the effect that once the + // signal is "turned on" (non-zero values) everything will be treated as speech + // and there is no noise suppression effect. Depending on the duration of the + // inactive signal it takes a considerable amount of time for the system to learn + // what is noise and what is speech. + + // read out fully processed segment + for (i = inst->windShift; i < inst->blockLen + inst->windShift; i++) { + fout[i - inst->windShift] = inst->syntBuf[i]; + } + // update synthesis buffer + memcpy(inst->syntBuf, inst->syntBuf + inst->blockLen, + sizeof(float) * (inst->anaLen - inst->blockLen)); + memset(inst->syntBuf + inst->anaLen - inst->blockLen, 0, + sizeof(float) * inst->blockLen); + + // out buffer + inst->outLen = inst->blockLen - inst->blockLen10ms; + if (inst->blockLen > inst->blockLen10ms) { + for (i = 0; i < inst->outLen; i++) { + inst->outBuf[i] = fout[i + inst->blockLen10ms]; + } + } + // convert to short + for (i = 0; i < inst->blockLen10ms; i++) { + dTmp = fout[i]; + if (dTmp < WEBRTC_SPL_WORD16_MIN) { + dTmp = WEBRTC_SPL_WORD16_MIN; + } else if (dTmp > WEBRTC_SPL_WORD16_MAX) { + dTmp = WEBRTC_SPL_WORD16_MAX; + } + outFrame[i] = (short)dTmp; + } + + // for time-domain gain of HB + if (flagHB == 1) { + for (i = 0; i < inst->blockLen10ms; i++) { + dTmp = inst->dataBufHB[i]; + if (dTmp < WEBRTC_SPL_WORD16_MIN) { + dTmp = WEBRTC_SPL_WORD16_MIN; + } else if (dTmp > WEBRTC_SPL_WORD16_MAX) { + dTmp = WEBRTC_SPL_WORD16_MAX; + } + outFrameHB[i] = (short)dTmp; + } + } // end of H band gain computation + // + return 0; + } + + // + inst->blockInd++; // Update the block index only when we process a block. + // FFT + WebRtc_rdft(inst->anaLen, 1, winData, inst->ip, inst->wfft); + + imag[0] = 0; + real[0] = winData[0]; + magn[0] = (float)(fabs(real[0]) + 1.0f); + imag[inst->magnLen - 1] = 0; + real[inst->magnLen - 1] = winData[1]; + magn[inst->magnLen - 1] = (float)(fabs(real[inst->magnLen - 1]) + 1.0f); + signalEnergy = (float)(real[0] * real[0]) + + (float)(real[inst->magnLen - 1] * real[inst->magnLen - 1]); + sumMagn = magn[0] + magn[inst->magnLen - 1]; + if (inst->blockInd < END_STARTUP_SHORT) { + inst->initMagnEst[0] += magn[0]; + inst->initMagnEst[inst->magnLen - 1] += magn[inst->magnLen - 1]; + tmpFloat2 = log((float)(inst->magnLen - 1)); + sum_log_i = tmpFloat2; + sum_log_i_square = tmpFloat2 * tmpFloat2; + tmpFloat1 = log(magn[inst->magnLen - 1]); + sum_log_magn = tmpFloat1; + sum_log_i_log_magn = tmpFloat2 * tmpFloat1; + } + for (i = 1; i < inst->magnLen - 1; i++) { + real[i] = winData[2 * i]; + imag[i] = winData[2 * i + 1]; + // magnitude spectrum + fTmp = real[i] * real[i]; + fTmp += imag[i] * imag[i]; + signalEnergy += fTmp; + magn[i] = ((float)sqrt(fTmp)) + 1.0f; + sumMagn += magn[i]; + if (inst->blockInd < END_STARTUP_SHORT) { + inst->initMagnEst[i] += magn[i]; + if (i >= kStartBand) { + tmpFloat2 = log((float)i); + sum_log_i += tmpFloat2; + sum_log_i_square += tmpFloat2 * tmpFloat2; + tmpFloat1 = log(magn[i]); + sum_log_magn += tmpFloat1; + sum_log_i_log_magn += tmpFloat2 * tmpFloat1; + } + } + } + signalEnergy = signalEnergy / ((float)inst->magnLen); + inst->signalEnergy = signalEnergy; + inst->sumMagn = sumMagn; + + //compute spectral flatness on input spectrum + WebRtcNs_ComputeSpectralFlatness(inst, magn); + // quantile noise estimate + WebRtcNs_NoiseEstimation(inst, magn, noise); + //compute simplified noise model during startup + if (inst->blockInd < END_STARTUP_SHORT) { + // Estimate White noise + inst->whiteNoiseLevel += sumMagn / ((float)inst->magnLen) * inst->overdrive; + // Estimate Pink noise parameters + tmpFloat1 = sum_log_i_square * ((float)(inst->magnLen - kStartBand)); + tmpFloat1 -= (sum_log_i * sum_log_i); + tmpFloat2 = (sum_log_i_square * sum_log_magn - sum_log_i * sum_log_i_log_magn); + tmpFloat3 = tmpFloat2 / tmpFloat1; + // Constrain the estimated spectrum to be positive + if (tmpFloat3 < 0.0f) { + tmpFloat3 = 0.0f; + } + inst->pinkNoiseNumerator += tmpFloat3; + tmpFloat2 = (sum_log_i * sum_log_magn); + tmpFloat2 -= ((float)(inst->magnLen - kStartBand)) * sum_log_i_log_magn; + tmpFloat3 = tmpFloat2 / tmpFloat1; + // Constrain the pink noise power to be in the interval [0, 1]; + if (tmpFloat3 < 0.0f) { + tmpFloat3 = 0.0f; + } + if (tmpFloat3 > 1.0f) { + tmpFloat3 = 1.0f; + } + inst->pinkNoiseExp += tmpFloat3; + + // Calculate frequency independent parts of parametric noise estimate. + if (inst->pinkNoiseExp == 0.0f) { + // Use white noise estimate + parametric_noise = inst->whiteNoiseLevel; + } else { + // Use pink noise estimate + parametric_num = exp(inst->pinkNoiseNumerator / (float)(inst->blockInd + 1)); + parametric_num *= (float)(inst->blockInd + 1); + parametric_exp = inst->pinkNoiseExp / (float)(inst->blockInd + 1); + parametric_noise = parametric_num / pow((float)kStartBand, parametric_exp); + } + for (i = 0; i < inst->magnLen; i++) { + // Estimate the background noise using the white and pink noise parameters + if ((inst->pinkNoiseExp > 0.0f) && (i >= kStartBand)) { + // Use pink noise estimate + parametric_noise = parametric_num / pow((float)i, parametric_exp); + } + theFilterTmp[i] = (inst->initMagnEst[i] - inst->overdrive * parametric_noise); + theFilterTmp[i] /= (inst->initMagnEst[i] + (float)0.0001); + // Weight quantile noise with modeled noise + noise[i] *= (inst->blockInd); + tmpFloat2 = parametric_noise * (END_STARTUP_SHORT - inst->blockInd); + noise[i] += (tmpFloat2 / (float)(inst->blockInd + 1)); + noise[i] /= END_STARTUP_SHORT; + } + } + //compute average signal during END_STARTUP_LONG time: + // used to normalize spectral difference measure + if (inst->blockInd < END_STARTUP_LONG) { + inst->featureData[5] *= inst->blockInd; + inst->featureData[5] += signalEnergy; + inst->featureData[5] /= (inst->blockInd + 1); + } + +#ifdef PROCESS_FLOW_0 + if (inst->blockInd > END_STARTUP_LONG) { + //option: average the quantile noise: for check with AEC2 + for (i = 0; i < inst->magnLen; i++) { + noise[i] = (float)0.6 * inst->noisePrev[i] + (float)0.4 * noise[i]; + } + for (i = 0; i < inst->magnLen; i++) { + // Wiener with over sub-substraction: + theFilter[i] = (magn[i] - inst->overdrive * noise[i]) / (magn[i] + (float)0.0001); + } + } +#else + //start processing at frames == converged+1 + // + // STEP 1: compute prior and post snr based on quantile noise est + // + + // compute DD estimate of prior SNR: needed for new method + for (i = 0; i < inst->magnLen; i++) { + // post snr + snrLocPost[i] = (float)0.0; + if (magn[i] > noise[i]) { + snrLocPost[i] = magn[i] / (noise[i] + (float)0.0001) - (float)1.0; + } + // previous post snr + // previous estimate: based on previous frame with gain filter + previousEstimateStsa[i] = inst->magnPrev[i] / (inst->noisePrev[i] + (float)0.0001) + * (inst->smooth[i]); + // DD estimate is sum of two terms: current estimate and previous estimate + // directed decision update of snrPrior + snrLocPrior[i] = DD_PR_SNR * previousEstimateStsa[i] + ((float)1.0 - DD_PR_SNR) + * snrLocPost[i]; + // post and prior snr needed for step 2 + } // end of loop over freqs +#ifdef PROCESS_FLOW_1 + for (i = 0; i < inst->magnLen; i++) { + // gain filter + tmpFloat1 = inst->overdrive + snrLocPrior[i]; + tmpFloat2 = (float)snrLocPrior[i] / tmpFloat1; + theFilter[i] = (float)tmpFloat2; + } // end of loop over freqs +#endif + // done with step 1: dd computation of prior and post snr + + // + //STEP 2: compute speech/noise likelihood + // +#ifdef PROCESS_FLOW_2 + // compute difference of input spectrum with learned/estimated noise spectrum + WebRtcNs_ComputeSpectralDifference(inst, magn); + // compute histograms for parameter decisions (thresholds and weights for features) + // parameters are extracted once every window time (=inst->modelUpdatePars[1]) + if (updateParsFlag >= 1) { + // counter update + inst->modelUpdatePars[3]--; + // update histogram + if (inst->modelUpdatePars[3] > 0) { + WebRtcNs_FeatureParameterExtraction(inst, 0); + } + // compute model parameters + if (inst->modelUpdatePars[3] == 0) { + WebRtcNs_FeatureParameterExtraction(inst, 1); + inst->modelUpdatePars[3] = inst->modelUpdatePars[1]; + // if wish to update only once, set flag to zero + if (updateParsFlag == 1) { + inst->modelUpdatePars[0] = 0; + } else { + // update every window: + // get normalization for spectral difference for next window estimate + inst->featureData[6] = inst->featureData[6] + / ((float)inst->modelUpdatePars[1]); + inst->featureData[5] = (float)0.5 * (inst->featureData[6] + + inst->featureData[5]); + inst->featureData[6] = (float)0.0; + } + } + } + // compute speech/noise probability + WebRtcNs_SpeechNoiseProb(inst, probSpeechFinal, snrLocPrior, snrLocPost); + // time-avg parameter for noise update + gammaNoiseTmp = NOISE_UPDATE; + for (i = 0; i < inst->magnLen; i++) { + probSpeech = probSpeechFinal[i]; + probNonSpeech = (float)1.0 - probSpeech; + // temporary noise update: + // use it for speech frames if update value is less than previous + noiseUpdateTmp = gammaNoiseTmp * inst->noisePrev[i] + ((float)1.0 - gammaNoiseTmp) + * (probNonSpeech * magn[i] + probSpeech * inst->noisePrev[i]); + // + // time-constant based on speech/noise state + gammaNoiseOld = gammaNoiseTmp; + gammaNoiseTmp = NOISE_UPDATE; + // increase gamma (i.e., less noise update) for frame likely to be speech + if (probSpeech > PROB_RANGE) { + gammaNoiseTmp = SPEECH_UPDATE; + } + // conservative noise update + if (probSpeech < PROB_RANGE) { + inst->magnAvgPause[i] += GAMMA_PAUSE * (magn[i] - inst->magnAvgPause[i]); + } + // noise update + if (gammaNoiseTmp == gammaNoiseOld) { + noise[i] = noiseUpdateTmp; + } else { + noise[i] = gammaNoiseTmp * inst->noisePrev[i] + ((float)1.0 - gammaNoiseTmp) + * (probNonSpeech * magn[i] + probSpeech * inst->noisePrev[i]); + // allow for noise update downwards: + // if noise update decreases the noise, it is safe, so allow it to happen + if (noiseUpdateTmp < noise[i]) { + noise[i] = noiseUpdateTmp; + } + } + } // end of freq loop + // done with step 2: noise update + + // + // STEP 3: compute dd update of prior snr and post snr based on new noise estimate + // + for (i = 0; i < inst->magnLen; i++) { + // post and prior snr + currentEstimateStsa = (float)0.0; + if (magn[i] > noise[i]) { + currentEstimateStsa = magn[i] / (noise[i] + (float)0.0001) - (float)1.0; + } + // DD estimate is sume of two terms: current estimate and previous estimate + // directed decision update of snrPrior + snrPrior = DD_PR_SNR * previousEstimateStsa[i] + ((float)1.0 - DD_PR_SNR) + * currentEstimateStsa; + // gain filter + tmpFloat1 = inst->overdrive + snrPrior; + tmpFloat2 = (float)snrPrior / tmpFloat1; + theFilter[i] = (float)tmpFloat2; + } // end of loop over freqs + // done with step3 +#endif +#endif + + for (i = 0; i < inst->magnLen; i++) { + // flooring bottom + if (theFilter[i] < inst->denoiseBound) { + theFilter[i] = inst->denoiseBound; + } + // flooring top + if (theFilter[i] > (float)1.0) { + theFilter[i] = 1.0; + } + if (inst->blockInd < END_STARTUP_SHORT) { + // flooring bottom + if (theFilterTmp[i] < inst->denoiseBound) { + theFilterTmp[i] = inst->denoiseBound; + } + // flooring top + if (theFilterTmp[i] > (float)1.0) { + theFilterTmp[i] = 1.0; + } + // Weight the two suppression filters + theFilter[i] *= (inst->blockInd); + theFilterTmp[i] *= (END_STARTUP_SHORT - inst->blockInd); + theFilter[i] += theFilterTmp[i]; + theFilter[i] /= (END_STARTUP_SHORT); + } + // smoothing +#ifdef PROCESS_FLOW_0 + inst->smooth[i] *= SMOOTH; // value set to 0.7 in define.h file + inst->smooth[i] += ((float)1.0 - SMOOTH) * theFilter[i]; +#else + inst->smooth[i] = theFilter[i]; +#endif + real[i] *= inst->smooth[i]; + imag[i] *= inst->smooth[i]; + } + // keep track of noise and magn spectrum for next frame + for (i = 0; i < inst->magnLen; i++) { + inst->noisePrev[i] = noise[i]; + inst->magnPrev[i] = magn[i]; + } + // back to time domain + winData[0] = real[0]; + winData[1] = real[inst->magnLen - 1]; + for (i = 1; i < inst->magnLen - 1; i++) { + winData[2 * i] = real[i]; + winData[2 * i + 1] = imag[i]; + } + WebRtc_rdft(inst->anaLen, -1, winData, inst->ip, inst->wfft); + + for (i = 0; i < inst->anaLen; i++) { + real[i] = 2.0f * winData[i] / inst->anaLen; // fft scaling + } + + //scale factor: only do it after END_STARTUP_LONG time + factor = (float)1.0; + if (inst->gainmap == 1 && inst->blockInd > END_STARTUP_LONG) { + factor1 = (float)1.0; + factor2 = (float)1.0; + + energy2 = 0.0; + for (i = 0; i < inst->anaLen; i++) { + energy2 += (float)real[i] * (float)real[i]; + } + gain = (float)sqrt(energy2 / (energy1 + (float)1.0)); + +#ifdef PROCESS_FLOW_2 + // scaling for new version + if (gain > B_LIM) { + factor1 = (float)1.0 + (float)1.3 * (gain - B_LIM); + if (gain * factor1 > (float)1.0) { + factor1 = (float)1.0 / gain; + } + } + if (gain < B_LIM) { + //don't reduce scale too much for pause regions: + // attenuation here should be controlled by flooring + if (gain <= inst->denoiseBound) { + gain = inst->denoiseBound; + } + factor2 = (float)1.0 - (float)0.3 * (B_LIM - gain); + } + //combine both scales with speech/noise prob: + // note prior (priorSpeechProb) is not frequency dependent + factor = inst->priorSpeechProb * factor1 + ((float)1.0 - inst->priorSpeechProb) + * factor2; +#else + if (gain > B_LIM) { + factor = (float)1.0 + (float)1.3 * (gain - B_LIM); + } else { + factor = (float)1.0 + (float)2.0 * (gain - B_LIM); + } + if (gain * factor > (float)1.0) { + factor = (float)1.0 / gain; + } +#endif + } // out of inst->gainmap==1 + + // synthesis + for (i = 0; i < inst->anaLen; i++) { + inst->syntBuf[i] += factor * inst->window[i] * (float)real[i]; + } + // read out fully processed segment + for (i = inst->windShift; i < inst->blockLen + inst->windShift; i++) { + fout[i - inst->windShift] = inst->syntBuf[i]; + } + // update synthesis buffer + memcpy(inst->syntBuf, inst->syntBuf + inst->blockLen, + sizeof(float) * (inst->anaLen - inst->blockLen)); + memset(inst->syntBuf + inst->anaLen - inst->blockLen, 0, + sizeof(float) * inst->blockLen); + + // out buffer + inst->outLen = inst->blockLen - inst->blockLen10ms; + if (inst->blockLen > inst->blockLen10ms) { + for (i = 0; i < inst->outLen; i++) { + inst->outBuf[i] = fout[i + inst->blockLen10ms]; + } + } + } // end of if out.len==0 + else { + for (i = 0; i < inst->blockLen10ms; i++) { + fout[i] = inst->outBuf[i]; + } + memcpy(inst->outBuf, inst->outBuf + inst->blockLen10ms, + sizeof(float) * (inst->outLen - inst->blockLen10ms)); + memset(inst->outBuf + inst->outLen - inst->blockLen10ms, 0, + sizeof(float) * inst->blockLen10ms); + inst->outLen -= inst->blockLen10ms; + } + + // convert to short + for (i = 0; i < inst->blockLen10ms; i++) { + dTmp = fout[i]; + if (dTmp < WEBRTC_SPL_WORD16_MIN) { + dTmp = WEBRTC_SPL_WORD16_MIN; + } else if (dTmp > WEBRTC_SPL_WORD16_MAX) { + dTmp = WEBRTC_SPL_WORD16_MAX; + } + outFrame[i] = (short)dTmp; + } + + // for time-domain gain of HB + if (flagHB == 1) { + for (i = 0; i < inst->magnLen; i++) { + inst->speechProbHB[i] = probSpeechFinal[i]; + } + // average speech prob from low band + // avg over second half (i.e., 4->8kHz) of freq. spectrum + avgProbSpeechHB = 0.0; + for (i = inst->magnLen - deltaBweHB - 1; i < inst->magnLen - 1; i++) { + avgProbSpeechHB += inst->speechProbHB[i]; + } + avgProbSpeechHB = avgProbSpeechHB / ((float)deltaBweHB); + // average filter gain from low band + // average over second half (i.e., 4->8kHz) of freq. spectrum + avgFilterGainHB = 0.0; + for (i = inst->magnLen - deltaGainHB - 1; i < inst->magnLen - 1; i++) { + avgFilterGainHB += inst->smooth[i]; + } + avgFilterGainHB = avgFilterGainHB / ((float)(deltaGainHB)); + avgProbSpeechHBTmp = (float)2.0 * avgProbSpeechHB - (float)1.0; + // gain based on speech prob: + gainModHB = (float)0.5 * ((float)1.0 + (float)tanh(gainMapParHB * avgProbSpeechHBTmp)); + //combine gain with low band gain + gainTimeDomainHB = (float)0.5 * gainModHB + (float)0.5 * avgFilterGainHB; + if (avgProbSpeechHB >= (float)0.5) { + gainTimeDomainHB = (float)0.25 * gainModHB + (float)0.75 * avgFilterGainHB; + } + gainTimeDomainHB = gainTimeDomainHB * decayBweHB; + //make sure gain is within flooring range + // flooring bottom + if (gainTimeDomainHB < inst->denoiseBound) { + gainTimeDomainHB = inst->denoiseBound; + } + // flooring top + if (gainTimeDomainHB > (float)1.0) { + gainTimeDomainHB = 1.0; + } + //apply gain + for (i = 0; i < inst->blockLen10ms; i++) { + dTmp = gainTimeDomainHB * inst->dataBufHB[i]; + if (dTmp < WEBRTC_SPL_WORD16_MIN) { + dTmp = WEBRTC_SPL_WORD16_MIN; + } else if (dTmp > WEBRTC_SPL_WORD16_MAX) { + dTmp = WEBRTC_SPL_WORD16_MAX; + } + outFrameHB[i] = (short)dTmp; + } + } // end of H band gain computation + // + + return 0; +} diff --git a/libs/miniwebrtc/audio/processing/ns/ns_core.h b/libs/miniwebrtc/audio/processing/ns/ns_core.h new file mode 100644 index 00000000..2f4c34ff --- /dev/null +++ b/libs/miniwebrtc/audio/processing/ns/ns_core.h @@ -0,0 +1,179 @@ +/* + * 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_PROCESSING_NS_MAIN_SOURCE_NS_CORE_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_NS_CORE_H_ + +#include "defines.h" + +typedef struct NSParaExtract_t_ { + + //bin size of histogram + float binSizeLrt; + float binSizeSpecFlat; + float binSizeSpecDiff; + //range of histogram over which lrt threshold is computed + float rangeAvgHistLrt; + //scale parameters: multiply dominant peaks of the histograms by scale factor to obtain + //thresholds for prior model + float factor1ModelPars; //for lrt and spectral difference + float factor2ModelPars; //for spectral_flatness: used when noise is flatter than speech + //peak limit for spectral flatness (varies between 0 and 1) + float thresPosSpecFlat; + //limit on spacing of two highest peaks in histogram: spacing determined by bin size + float limitPeakSpacingSpecFlat; + float limitPeakSpacingSpecDiff; + //limit on relevance of second peak: + float limitPeakWeightsSpecFlat; + float limitPeakWeightsSpecDiff; + //limit on fluctuation of lrt feature + float thresFluctLrt; + //limit on the max and min values for the feature thresholds + float maxLrt; + float minLrt; + float maxSpecFlat; + float minSpecFlat; + float maxSpecDiff; + float minSpecDiff; + //criteria of weight of histogram peak to accept/reject feature + int thresWeightSpecFlat; + int thresWeightSpecDiff; + +} NSParaExtract_t; + +typedef struct NSinst_t_ { + + WebRtc_UWord32 fs; + int blockLen; + int blockLen10ms; + int windShift; + int outLen; + int anaLen; + int magnLen; + int aggrMode; + const float* window; + float dataBuf[ANAL_BLOCKL_MAX]; + float syntBuf[ANAL_BLOCKL_MAX]; + float outBuf[3 * BLOCKL_MAX]; + + int initFlag; + // parameters for quantile noise estimation + float density[SIMULT* HALF_ANAL_BLOCKL]; + float lquantile[SIMULT* HALF_ANAL_BLOCKL]; + float quantile[HALF_ANAL_BLOCKL]; + int counter[SIMULT]; + int updates; + // parameters for Wiener filter + float smooth[HALF_ANAL_BLOCKL]; + float overdrive; + float denoiseBound; + int gainmap; + // fft work arrays. + int ip[IP_LENGTH]; + float wfft[W_LENGTH]; + + // parameters for new method: some not needed, will reduce/cleanup later + WebRtc_Word32 blockInd; //frame index counter + int modelUpdatePars[4]; //parameters for updating or estimating + // thresholds/weights for prior model + float priorModelPars[7]; //parameters for prior model + float noisePrev[HALF_ANAL_BLOCKL]; //noise spectrum from previous frame + float magnPrev[HALF_ANAL_BLOCKL]; //magnitude spectrum of previous frame + float logLrtTimeAvg[HALF_ANAL_BLOCKL]; //log lrt factor with time-smoothing + float priorSpeechProb; //prior speech/noise probability + float featureData[7]; //data for features + float magnAvgPause[HALF_ANAL_BLOCKL]; //conservative noise spectrum estimate + float signalEnergy; //energy of magn + float sumMagn; //sum of magn + float whiteNoiseLevel; //initial noise estimate + float initMagnEst[HALF_ANAL_BLOCKL]; //initial magnitude spectrum estimate + float pinkNoiseNumerator; //pink noise parameter: numerator + float pinkNoiseExp; //pink noise parameter: power of freq + NSParaExtract_t featureExtractionParams; //parameters for feature extraction + //histograms for parameter estimation + int histLrt[HIST_PAR_EST]; + int histSpecFlat[HIST_PAR_EST]; + int histSpecDiff[HIST_PAR_EST]; + //quantities for high band estimate + float speechProbHB[HALF_ANAL_BLOCKL]; //final speech/noise prob: prior + LRT + float dataBufHB[ANAL_BLOCKL_MAX]; //buffering data for HB + +} NSinst_t; + + +#ifdef __cplusplus +extern "C" { +#endif + +/**************************************************************************** + * WebRtcNs_InitCore(...) + * + * This function initializes a noise suppression instance + * + * Input: + * - inst : Instance that should be initialized + * - fs : Sampling frequency + * + * Output: + * - inst : Initialized instance + * + * Return value : 0 - Ok + * -1 - Error + */ +int WebRtcNs_InitCore(NSinst_t* inst, WebRtc_UWord32 fs); + +/**************************************************************************** + * WebRtcNs_set_policy_core(...) + * + * This changes the aggressiveness of the noise suppression method. + * + * Input: + * - inst : Instance that should be initialized + * - mode : 0: Mild (6 dB), 1: Medium (10 dB), 2: Aggressive (15 dB) + * + * Output: + * - NS_inst : Initialized instance + * + * Return value : 0 - Ok + * -1 - Error + */ +int WebRtcNs_set_policy_core(NSinst_t* inst, int mode); + +/**************************************************************************** + * WebRtcNs_ProcessCore + * + * Do noise suppression. + * + * Input: + * - inst : Instance that should be initialized + * - inFrameLow : Input speech frame for lower band + * - inFrameHigh : Input speech frame for higher band + * + * Output: + * - inst : Updated instance + * - outFrameLow : Output speech frame for lower band + * - outFrameHigh : Output speech frame for higher band + * + * Return value : 0 - OK + * -1 - Error + */ + + +int WebRtcNs_ProcessCore(NSinst_t* inst, + short* inFrameLow, + short* inFrameHigh, + short* outFrameLow, + short* outFrameHigh); + + +#ifdef __cplusplus +} +#endif +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_NS_CORE_H_ diff --git a/libs/miniwebrtc/audio/processing/ns/nsx_core.c b/libs/miniwebrtc/audio/processing/ns/nsx_core.c new file mode 100644 index 00000000..51bde0c7 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/ns/nsx_core.c @@ -0,0 +1,2444 @@ +/* + * 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 "noise_suppression_x.h" + +#include +#include +#include +#include +#include + +#include "cpu_features_wrapper.h" +#include "nsx_core.h" + +// Skip first frequency bins during estimation. (0 <= value < 64) +static const int kStartBand = 5; + +// Constants to compensate for shifting signal log(2^shifts). +const WebRtc_Word16 WebRtcNsx_kLogTable[9] = { + 0, 177, 355, 532, 710, 887, 1065, 1242, 1420 +}; + +const WebRtc_Word16 WebRtcNsx_kCounterDiv[201] = { + 32767, 16384, 10923, 8192, 6554, 5461, 4681, + 4096, 3641, 3277, 2979, 2731, 2521, 2341, 2185, 2048, 1928, 1820, 1725, 1638, 1560, + 1489, 1425, 1365, 1311, 1260, 1214, 1170, 1130, 1092, 1057, 1024, 993, 964, 936, 910, + 886, 862, 840, 819, 799, 780, 762, 745, 728, 712, 697, 683, 669, 655, 643, 630, 618, + 607, 596, 585, 575, 565, 555, 546, 537, 529, 520, 512, 504, 496, 489, 482, 475, 468, + 462, 455, 449, 443, 437, 431, 426, 420, 415, 410, 405, 400, 395, 390, 386, 381, 377, + 372, 368, 364, 360, 356, 352, 349, 345, 341, 338, 334, 331, 328, 324, 321, 318, 315, + 312, 309, 306, 303, 301, 298, 295, 293, 290, 287, 285, 282, 280, 278, 275, 273, 271, + 269, 266, 264, 262, 260, 258, 256, 254, 252, 250, 248, 246, 245, 243, 241, 239, 237, + 236, 234, 232, 231, 229, 228, 226, 224, 223, 221, 220, 218, 217, 216, 214, 213, 211, + 210, 209, 207, 206, 205, 204, 202, 201, 200, 199, 197, 196, 195, 194, 193, 192, 191, + 189, 188, 187, 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, 176, 175, 174, 173, + 172, 172, 171, 170, 169, 168, 167, 166, 165, 165, 164, 163 +}; + +const WebRtc_Word16 WebRtcNsx_kLogTableFrac[256] = { + 0, 1, 3, 4, 6, 7, 9, 10, 11, 13, 14, 16, 17, 18, 20, 21, + 22, 24, 25, 26, 28, 29, 30, 32, 33, 34, 36, 37, 38, 40, 41, 42, + 44, 45, 46, 47, 49, 50, 51, 52, 54, 55, 56, 57, 59, 60, 61, 62, + 63, 65, 66, 67, 68, 69, 71, 72, 73, 74, 75, 77, 78, 79, 80, 81, + 82, 84, 85, 86, 87, 88, 89, 90, 92, 93, 94, 95, 96, 97, 98, 99, + 100, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 116, 117, + 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 166, 167, 168, 169, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 178, + 179, 180, 181, 182, 183, 184, 185, 185, 186, 187, 188, 189, 190, 191, 192, 192, + 193, 194, 195, 196, 197, 198, 198, 199, 200, 201, 202, 203, 203, 204, 205, 206, + 207, 208, 208, 209, 210, 211, 212, 212, 213, 214, 215, 216, 216, 217, 218, 219, + 220, 220, 221, 222, 223, 224, 224, 225, 226, 227, 228, 228, 229, 230, 231, 231, + 232, 233, 234, 234, 235, 236, 237, 238, 238, 239, 240, 241, 241, 242, 243, 244, + 244, 245, 246, 247, 247, 248, 249, 249, 250, 251, 252, 252, 253, 254, 255, 255 +}; + +static const WebRtc_Word16 kPowTableFrac[1024] = { + 0, 1, 1, 2, 3, 3, 4, 5, + 6, 6, 7, 8, 8, 9, 10, 10, + 11, 12, 13, 13, 14, 15, 15, 16, + 17, 17, 18, 19, 20, 20, 21, 22, + 22, 23, 24, 25, 25, 26, 27, 27, + 28, 29, 30, 30, 31, 32, 32, 33, + 34, 35, 35, 36, 37, 37, 38, 39, + 40, 40, 41, 42, 42, 43, 44, 45, + 45, 46, 47, 48, 48, 49, 50, 50, + 51, 52, 53, 53, 54, 55, 56, 56, + 57, 58, 58, 59, 60, 61, 61, 62, + 63, 64, 64, 65, 66, 67, 67, 68, + 69, 69, 70, 71, 72, 72, 73, 74, + 75, 75, 76, 77, 78, 78, 79, 80, + 81, 81, 82, 83, 84, 84, 85, 86, + 87, 87, 88, 89, 90, 90, 91, 92, + 93, 93, 94, 95, 96, 96, 97, 98, + 99, 100, 100, 101, 102, 103, 103, 104, + 105, 106, 106, 107, 108, 109, 109, 110, + 111, 112, 113, 113, 114, 115, 116, 116, + 117, 118, 119, 119, 120, 121, 122, 123, + 123, 124, 125, 126, 126, 127, 128, 129, + 130, 130, 131, 132, 133, 133, 134, 135, + 136, 137, 137, 138, 139, 140, 141, 141, + 142, 143, 144, 144, 145, 146, 147, 148, + 148, 149, 150, 151, 152, 152, 153, 154, + 155, 156, 156, 157, 158, 159, 160, 160, + 161, 162, 163, 164, 164, 165, 166, 167, + 168, 168, 169, 170, 171, 172, 173, 173, + 174, 175, 176, 177, 177, 178, 179, 180, + 181, 181, 182, 183, 184, 185, 186, 186, + 187, 188, 189, 190, 190, 191, 192, 193, + 194, 195, 195, 196, 197, 198, 199, 200, + 200, 201, 202, 203, 204, 205, 205, 206, + 207, 208, 209, 210, 210, 211, 212, 213, + 214, 215, 215, 216, 217, 218, 219, 220, + 220, 221, 222, 223, 224, 225, 225, 226, + 227, 228, 229, 230, 231, 231, 232, 233, + 234, 235, 236, 237, 237, 238, 239, 240, + 241, 242, 243, 243, 244, 245, 246, 247, + 248, 249, 249, 250, 251, 252, 253, 254, + 255, 255, 256, 257, 258, 259, 260, 261, + 262, 262, 263, 264, 265, 266, 267, 268, + 268, 269, 270, 271, 272, 273, 274, 275, + 276, 276, 277, 278, 279, 280, 281, 282, + 283, 283, 284, 285, 286, 287, 288, 289, + 290, 291, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 299, 300, 301, 302, 303, + 304, 305, 306, 307, 308, 308, 309, 310, + 311, 312, 313, 314, 315, 316, 317, 318, + 318, 319, 320, 321, 322, 323, 324, 325, + 326, 327, 328, 328, 329, 330, 331, 332, + 333, 334, 335, 336, 337, 338, 339, 339, + 340, 341, 342, 343, 344, 345, 346, 347, + 348, 349, 350, 351, 352, 352, 353, 354, + 355, 356, 357, 358, 359, 360, 361, 362, + 363, 364, 365, 366, 367, 367, 368, 369, + 370, 371, 372, 373, 374, 375, 376, 377, + 378, 379, 380, 381, 382, 383, 384, 385, + 385, 386, 387, 388, 389, 390, 391, 392, + 393, 394, 395, 396, 397, 398, 399, 400, + 401, 402, 403, 404, 405, 406, 407, 408, + 409, 410, 410, 411, 412, 413, 414, 415, + 416, 417, 418, 419, 420, 421, 422, 423, + 424, 425, 426, 427, 428, 429, 430, 431, + 432, 433, 434, 435, 436, 437, 438, 439, + 440, 441, 442, 443, 444, 445, 446, 447, + 448, 449, 450, 451, 452, 453, 454, 455, + 456, 457, 458, 459, 460, 461, 462, 463, + 464, 465, 466, 467, 468, 469, 470, 471, + 472, 473, 474, 475, 476, 477, 478, 479, + 480, 481, 482, 483, 484, 485, 486, 487, + 488, 489, 490, 491, 492, 493, 494, 495, + 496, 498, 499, 500, 501, 502, 503, 504, + 505, 506, 507, 508, 509, 510, 511, 512, + 513, 514, 515, 516, 517, 518, 519, 520, + 521, 522, 523, 525, 526, 527, 528, 529, + 530, 531, 532, 533, 534, 535, 536, 537, + 538, 539, 540, 541, 542, 544, 545, 546, + 547, 548, 549, 550, 551, 552, 553, 554, + 555, 556, 557, 558, 560, 561, 562, 563, + 564, 565, 566, 567, 568, 569, 570, 571, + 572, 574, 575, 576, 577, 578, 579, 580, + 581, 582, 583, 584, 585, 587, 588, 589, + 590, 591, 592, 593, 594, 595, 596, 597, + 599, 600, 601, 602, 603, 604, 605, 606, + 607, 608, 610, 611, 612, 613, 614, 615, + 616, 617, 618, 620, 621, 622, 623, 624, + 625, 626, 627, 628, 630, 631, 632, 633, + 634, 635, 636, 637, 639, 640, 641, 642, + 643, 644, 645, 646, 648, 649, 650, 651, + 652, 653, 654, 656, 657, 658, 659, 660, + 661, 662, 664, 665, 666, 667, 668, 669, + 670, 672, 673, 674, 675, 676, 677, 678, + 680, 681, 682, 683, 684, 685, 687, 688, + 689, 690, 691, 692, 693, 695, 696, 697, + 698, 699, 700, 702, 703, 704, 705, 706, + 708, 709, 710, 711, 712, 713, 715, 716, + 717, 718, 719, 720, 722, 723, 724, 725, + 726, 728, 729, 730, 731, 732, 733, 735, + 736, 737, 738, 739, 741, 742, 743, 744, + 745, 747, 748, 749, 750, 751, 753, 754, + 755, 756, 757, 759, 760, 761, 762, 763, + 765, 766, 767, 768, 770, 771, 772, 773, + 774, 776, 777, 778, 779, 780, 782, 783, + 784, 785, 787, 788, 789, 790, 792, 793, + 794, 795, 796, 798, 799, 800, 801, 803, + 804, 805, 806, 808, 809, 810, 811, 813, + 814, 815, 816, 818, 819, 820, 821, 823, + 824, 825, 826, 828, 829, 830, 831, 833, + 834, 835, 836, 838, 839, 840, 841, 843, + 844, 845, 846, 848, 849, 850, 851, 853, + 854, 855, 857, 858, 859, 860, 862, 863, + 864, 866, 867, 868, 869, 871, 872, 873, + 874, 876, 877, 878, 880, 881, 882, 883, + 885, 886, 887, 889, 890, 891, 893, 894, + 895, 896, 898, 899, 900, 902, 903, 904, + 906, 907, 908, 909, 911, 912, 913, 915, + 916, 917, 919, 920, 921, 923, 924, 925, + 927, 928, 929, 931, 932, 933, 935, 936, + 937, 938, 940, 941, 942, 944, 945, 946, + 948, 949, 950, 952, 953, 955, 956, 957, + 959, 960, 961, 963, 964, 965, 967, 968, + 969, 971, 972, 973, 975, 976, 977, 979, + 980, 981, 983, 984, 986, 987, 988, 990, + 991, 992, 994, 995, 996, 998, 999, 1001, + 1002, 1003, 1005, 1006, 1007, 1009, 1010, 1012, + 1013, 1014, 1016, 1017, 1018, 1020, 1021, 1023 +}; + +static const WebRtc_Word16 kIndicatorTable[17] = { + 0, 2017, 3809, 5227, 6258, 6963, 7424, 7718, + 7901, 8014, 8084, 8126, 8152, 8168, 8177, 8183, 8187 +}; + +// hybrib Hanning & flat window +static const WebRtc_Word16 kBlocks80w128x[128] = { + 0, 536, 1072, 1606, 2139, 2669, 3196, 3720, 4240, 4756, 5266, + 5771, 6270, 6762, 7246, 7723, 8192, 8652, 9102, 9543, 9974, 10394, + 10803, 11200, 11585, 11958, 12318, 12665, 12998, 13318, 13623, 13913, 14189, + 14449, 14694, 14924, 15137, 15334, 15515, 15679, 15826, 15956, 16069, 16165, + 16244, 16305, 16349, 16375, 16384, 16384, 16384, 16384, 16384, 16384, 16384, + 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, + 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, + 16384, 16384, 16384, 16384, 16375, 16349, 16305, 16244, 16165, 16069, 15956, + 15826, 15679, 15515, 15334, 15137, 14924, 14694, 14449, 14189, 13913, 13623, + 13318, 12998, 12665, 12318, 11958, 11585, 11200, 10803, 10394, 9974, 9543, + 9102, 8652, 8192, 7723, 7246, 6762, 6270, 5771, 5266, 4756, 4240, + 3720, 3196, 2669, 2139, 1606, 1072, 536 +}; + +// hybrib Hanning & flat window +static const WebRtc_Word16 kBlocks160w256x[256] = { + 0, 268, 536, 804, 1072, 1339, 1606, 1872, + 2139, 2404, 2669, 2933, 3196, 3459, 3720, 3981, + 4240, 4499, 4756, 5012, 5266, 5520, 5771, 6021, + 6270, 6517, 6762, 7005, 7246, 7486, 7723, 7959, + 8192, 8423, 8652, 8878, 9102, 9324, 9543, 9760, + 9974, 10185, 10394, 10600, 10803, 11003, 11200, 11394, + 11585, 11773, 11958, 12140, 12318, 12493, 12665, 12833, + 12998, 13160, 13318, 13472, 13623, 13770, 13913, 14053, + 14189, 14321, 14449, 14574, 14694, 14811, 14924, 15032, + 15137, 15237, 15334, 15426, 15515, 15599, 15679, 15754, + 15826, 15893, 15956, 16015, 16069, 16119, 16165, 16207, + 16244, 16277, 16305, 16329, 16349, 16364, 16375, 16382, + 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, + 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, + 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, + 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, + 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, + 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, + 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, + 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, + 16384, 16382, 16375, 16364, 16349, 16329, 16305, 16277, + 16244, 16207, 16165, 16119, 16069, 16015, 15956, 15893, + 15826, 15754, 15679, 15599, 15515, 15426, 15334, 15237, + 15137, 15032, 14924, 14811, 14694, 14574, 14449, 14321, + 14189, 14053, 13913, 13770, 13623, 13472, 13318, 13160, + 12998, 12833, 12665, 12493, 12318, 12140, 11958, 11773, + 11585, 11394, 11200, 11003, 10803, 10600, 10394, 10185, + 9974, 9760, 9543, 9324, 9102, 8878, 8652, 8423, + 8192, 7959, 7723, 7486, 7246, 7005, 6762, 6517, + 6270, 6021, 5771, 5520, 5266, 5012, 4756, 4499, + 4240, 3981, 3720, 3459, 3196, 2933, 2669, 2404, + 2139, 1872, 1606, 1339, 1072, 804, 536, 268 +}; + +// Gain factor1 table: Input value in Q8 and output value in Q13 +// original floating point code +// if (gain > blim) { +// factor1 = 1.0 + 1.3 * (gain - blim); +// if (gain * factor1 > 1.0) { +// factor1 = 1.0 / gain; +// } +// } else { +// factor1 = 1.0; +// } +static const WebRtc_Word16 kFactor1Table[257] = { + 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8233, 8274, 8315, 8355, 8396, 8436, 8475, 8515, 8554, 8592, 8631, 8669, + 8707, 8745, 8783, 8820, 8857, 8894, 8931, 8967, 9003, 9039, 9075, 9111, 9146, 9181, + 9216, 9251, 9286, 9320, 9354, 9388, 9422, 9456, 9489, 9523, 9556, 9589, 9622, 9655, + 9687, 9719, 9752, 9784, 9816, 9848, 9879, 9911, 9942, 9973, 10004, 10035, 10066, + 10097, 10128, 10158, 10188, 10218, 10249, 10279, 10308, 10338, 10368, 10397, 10426, + 10456, 10485, 10514, 10543, 10572, 10600, 10629, 10657, 10686, 10714, 10742, 10770, + 10798, 10826, 10854, 10882, 10847, 10810, 10774, 10737, 10701, 10666, 10631, 10596, + 10562, 10527, 10494, 10460, 10427, 10394, 10362, 10329, 10297, 10266, 10235, 10203, + 10173, 10142, 10112, 10082, 10052, 10023, 9994, 9965, 9936, 9908, 9879, 9851, 9824, + 9796, 9769, 9742, 9715, 9689, 9662, 9636, 9610, 9584, 9559, 9534, 9508, 9484, 9459, + 9434, 9410, 9386, 9362, 9338, 9314, 9291, 9268, 9245, 9222, 9199, 9176, 9154, 9132, + 9110, 9088, 9066, 9044, 9023, 9002, 8980, 8959, 8939, 8918, 8897, 8877, 8857, 8836, + 8816, 8796, 8777, 8757, 8738, 8718, 8699, 8680, 8661, 8642, 8623, 8605, 8586, 8568, + 8550, 8532, 8514, 8496, 8478, 8460, 8443, 8425, 8408, 8391, 8373, 8356, 8339, 8323, + 8306, 8289, 8273, 8256, 8240, 8224, 8208, 8192 +}; + +// For Factor2 tables +// original floating point code +// if (gain > blim) { +// factor2 = 1.0; +// } else { +// factor2 = 1.0 - 0.3 * (blim - gain); +// if (gain <= inst->denoiseBound) { +// factor2 = 1.0 - 0.3 * (blim - inst->denoiseBound); +// } +// } +// +// Gain factor table: Input value in Q8 and output value in Q13 +static const WebRtc_Word16 kFactor2Aggressiveness1[257] = { + 7577, 7577, 7577, 7577, 7577, 7577, + 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7596, 7614, 7632, + 7650, 7667, 7683, 7699, 7715, 7731, 7746, 7761, 7775, 7790, 7804, 7818, 7832, 7845, + 7858, 7871, 7884, 7897, 7910, 7922, 7934, 7946, 7958, 7970, 7982, 7993, 8004, 8016, + 8027, 8038, 8049, 8060, 8070, 8081, 8091, 8102, 8112, 8122, 8132, 8143, 8152, 8162, + 8172, 8182, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192 +}; + +// Gain factor table: Input value in Q8 and output value in Q13 +static const WebRtc_Word16 kFactor2Aggressiveness2[257] = { + 7270, 7270, 7270, 7270, 7270, 7306, + 7339, 7369, 7397, 7424, 7448, 7472, 7495, 7517, 7537, 7558, 7577, 7596, 7614, 7632, + 7650, 7667, 7683, 7699, 7715, 7731, 7746, 7761, 7775, 7790, 7804, 7818, 7832, 7845, + 7858, 7871, 7884, 7897, 7910, 7922, 7934, 7946, 7958, 7970, 7982, 7993, 8004, 8016, + 8027, 8038, 8049, 8060, 8070, 8081, 8091, 8102, 8112, 8122, 8132, 8143, 8152, 8162, + 8172, 8182, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192 +}; + +// Gain factor table: Input value in Q8 and output value in Q13 +static const WebRtc_Word16 kFactor2Aggressiveness3[257] = { + 7184, 7184, 7184, 7229, 7270, 7306, + 7339, 7369, 7397, 7424, 7448, 7472, 7495, 7517, 7537, 7558, 7577, 7596, 7614, 7632, + 7650, 7667, 7683, 7699, 7715, 7731, 7746, 7761, 7775, 7790, 7804, 7818, 7832, 7845, + 7858, 7871, 7884, 7897, 7910, 7922, 7934, 7946, 7958, 7970, 7982, 7993, 8004, 8016, + 8027, 8038, 8049, 8060, 8070, 8081, 8091, 8102, 8112, 8122, 8132, 8143, 8152, 8162, + 8172, 8182, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192 +}; + +// sum of log2(i) from table index to inst->anaLen2 in Q5 +// Note that the first table value is invalid, since log2(0) = -infinity +static const WebRtc_Word16 kSumLogIndex[66] = { + 0, 22917, 22917, 22885, 22834, 22770, 22696, 22613, + 22524, 22428, 22326, 22220, 22109, 21994, 21876, 21754, + 21629, 21501, 21370, 21237, 21101, 20963, 20822, 20679, + 20535, 20388, 20239, 20089, 19937, 19783, 19628, 19470, + 19312, 19152, 18991, 18828, 18664, 18498, 18331, 18164, + 17994, 17824, 17653, 17480, 17306, 17132, 16956, 16779, + 16602, 16423, 16243, 16063, 15881, 15699, 15515, 15331, + 15146, 14960, 14774, 14586, 14398, 14209, 14019, 13829, + 13637, 13445 +}; + +// sum of log2(i)^2 from table index to inst->anaLen2 in Q2 +// Note that the first table value is invalid, since log2(0) = -infinity +static const WebRtc_Word16 kSumSquareLogIndex[66] = { + 0, 16959, 16959, 16955, 16945, 16929, 16908, 16881, + 16850, 16814, 16773, 16729, 16681, 16630, 16575, 16517, + 16456, 16392, 16325, 16256, 16184, 16109, 16032, 15952, + 15870, 15786, 15700, 15612, 15521, 15429, 15334, 15238, + 15140, 15040, 14938, 14834, 14729, 14622, 14514, 14404, + 14292, 14179, 14064, 13947, 13830, 13710, 13590, 13468, + 13344, 13220, 13094, 12966, 12837, 12707, 12576, 12444, + 12310, 12175, 12039, 11902, 11763, 11624, 11483, 11341, + 11198, 11054 +}; + +// log2(table index) in Q12 +// Note that the first table value is invalid, since log2(0) = -infinity +static const WebRtc_Word16 kLogIndex[129] = { + 0, 0, 4096, 6492, 8192, 9511, 10588, 11499, + 12288, 12984, 13607, 14170, 14684, 15157, 15595, 16003, + 16384, 16742, 17080, 17400, 17703, 17991, 18266, 18529, + 18780, 19021, 19253, 19476, 19691, 19898, 20099, 20292, + 20480, 20662, 20838, 21010, 21176, 21338, 21496, 21649, + 21799, 21945, 22087, 22226, 22362, 22495, 22625, 22752, + 22876, 22998, 23117, 23234, 23349, 23462, 23572, 23680, + 23787, 23892, 23994, 24095, 24195, 24292, 24388, 24483, + 24576, 24668, 24758, 24847, 24934, 25021, 25106, 25189, + 25272, 25354, 25434, 25513, 25592, 25669, 25745, 25820, + 25895, 25968, 26041, 26112, 26183, 26253, 26322, 26390, + 26458, 26525, 26591, 26656, 26721, 26784, 26848, 26910, + 26972, 27033, 27094, 27154, 27213, 27272, 27330, 27388, + 27445, 27502, 27558, 27613, 27668, 27722, 27776, 27830, + 27883, 27935, 27988, 28039, 28090, 28141, 28191, 28241, + 28291, 28340, 28388, 28437, 28484, 28532, 28579, 28626, + 28672 +}; + +// determinant of estimation matrix in Q0 corresponding to the log2 tables above +// Note that the first table value is invalid, since log2(0) = -infinity +static const WebRtc_Word16 kDeterminantEstMatrix[66] = { + 0, 29814, 25574, 22640, 20351, 18469, 16873, 15491, + 14277, 13199, 12233, 11362, 10571, 9851, 9192, 8587, + 8030, 7515, 7038, 6596, 6186, 5804, 5448, 5115, + 4805, 4514, 4242, 3988, 3749, 3524, 3314, 3116, + 2930, 2755, 2590, 2435, 2289, 2152, 2022, 1900, + 1785, 1677, 1575, 1478, 1388, 1302, 1221, 1145, + 1073, 1005, 942, 881, 825, 771, 721, 674, + 629, 587, 547, 510, 475, 442, 411, 382, + 355, 330 +}; + +// Declare function pointers. +NoiseEstimation WebRtcNsx_NoiseEstimation; +PrepareSpectrum WebRtcNsx_PrepareSpectrum; +SynthesisUpdate WebRtcNsx_SynthesisUpdate; +AnalysisUpdate WebRtcNsx_AnalysisUpdate; +Denormalize WebRtcNsx_Denormalize; +CreateComplexBuffer WebRtcNsx_CreateComplexBuffer; + +// Update the noise estimation information. +static void UpdateNoiseEstimate(NsxInst_t* inst, int offset) { + WebRtc_Word32 tmp32no1 = 0; + WebRtc_Word32 tmp32no2 = 0; + WebRtc_Word16 tmp16 = 0; + const WebRtc_Word16 kExp2Const = 11819; // Q13 + + int i = 0; + + tmp16 = WebRtcSpl_MaxValueW16(inst->noiseEstLogQuantile + offset, + inst->magnLen); + // Guarantee a Q-domain as high as possible and still fit in int16 + inst->qNoise = 14 - (int) WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( + kExp2Const, tmp16, 21); + for (i = 0; i < inst->magnLen; i++) { + // inst->quantile[i]=exp(inst->lquantile[offset+i]); + // in Q21 + tmp32no2 = WEBRTC_SPL_MUL_16_16(kExp2Const, + inst->noiseEstLogQuantile[offset + i]); + tmp32no1 = (0x00200000 | (tmp32no2 & 0x001FFFFF)); // 2^21 + frac + tmp16 = (WebRtc_Word16) WEBRTC_SPL_RSHIFT_W32(tmp32no2, 21); + tmp16 -= 21;// shift 21 to get result in Q0 + tmp16 += (WebRtc_Word16) inst->qNoise; //shift to get result in Q(qNoise) + if (tmp16 < 0) { + tmp32no1 = WEBRTC_SPL_RSHIFT_W32(tmp32no1, -tmp16); + } else { + tmp32no1 = WEBRTC_SPL_LSHIFT_W32(tmp32no1, tmp16); + } + inst->noiseEstQuantile[i] = WebRtcSpl_SatW32ToW16(tmp32no1); + } +} + +// Noise Estimation +static void NoiseEstimationC(NsxInst_t* inst, + uint16_t* magn, + uint32_t* noise, + int16_t* q_noise) { + WebRtc_Word16 lmagn[HALF_ANAL_BLOCKL], counter, countDiv; + WebRtc_Word16 countProd, delta, zeros, frac; + WebRtc_Word16 log2, tabind, logval, tmp16, tmp16no1, tmp16no2; + const int16_t log2_const = 22713; // Q15 + const int16_t width_factor = 21845; + + int i, s, offset; + + tabind = inst->stages - inst->normData; + assert(tabind < 9); + assert(tabind > -9); + if (tabind < 0) { + logval = -WebRtcNsx_kLogTable[-tabind]; + } else { + logval = WebRtcNsx_kLogTable[tabind]; + } + + // lmagn(i)=log(magn(i))=log(2)*log2(magn(i)) + // magn is in Q(-stages), and the real lmagn values are: + // real_lmagn(i)=log(magn(i)*2^stages)=log(magn(i))+log(2^stages) + // lmagn in Q8 + for (i = 0; i < inst->magnLen; i++) { + if (magn[i]) { + zeros = WebRtcSpl_NormU32((WebRtc_UWord32)magn[i]); + frac = (WebRtc_Word16)((((WebRtc_UWord32)magn[i] << zeros) + & 0x7FFFFFFF) >> 23); + // log2(magn(i)) + assert(frac < 256); + log2 = (WebRtc_Word16)(((31 - zeros) << 8) + + WebRtcNsx_kLogTableFrac[frac]); + // log2(magn(i))*log(2) + lmagn[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(log2, log2_const, 15); + // + log(2^stages) + lmagn[i] += logval; + } else { + lmagn[i] = logval;//0; + } + } + + // loop over simultaneous estimates + for (s = 0; s < SIMULT; s++) { + offset = s * inst->magnLen; + + // Get counter values from state + counter = inst->noiseEstCounter[s]; + assert(counter < 201); + countDiv = WebRtcNsx_kCounterDiv[counter]; + countProd = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16(counter, countDiv); + + // quant_est(...) + for (i = 0; i < inst->magnLen; i++) { + // compute delta + if (inst->noiseEstDensity[offset + i] > 512) { + // Get the value for delta by shifting intead of dividing. + int factor = WebRtcSpl_NormW16(inst->noiseEstDensity[offset + i]); + delta = (int16_t)(FACTOR_Q16 >> (14 - factor)); + } else { + delta = FACTOR_Q7; + if (inst->blockIndex < END_STARTUP_LONG) { + // Smaller step size during startup. This prevents from using + // unrealistic values causing overflow. + delta = FACTOR_Q7_STARTUP; + } + } + + // update log quantile estimate + tmp16 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(delta, countDiv, 14); + if (lmagn[i] > inst->noiseEstLogQuantile[offset + i]) { + // +=QUANTILE*delta/(inst->counter[s]+1) QUANTILE=0.25, =1 in Q2 + // CounterDiv=1/(inst->counter[s]+1) in Q15 + tmp16 += 2; + tmp16no1 = WEBRTC_SPL_RSHIFT_W16(tmp16, 2); + inst->noiseEstLogQuantile[offset + i] += tmp16no1; + } else { + tmp16 += 1; + tmp16no1 = WEBRTC_SPL_RSHIFT_W16(tmp16, 1); + // *(1-QUANTILE), in Q2 QUANTILE=0.25, 1-0.25=0.75=3 in Q2 + tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16no1, 3, 1); + inst->noiseEstLogQuantile[offset + i] -= tmp16no2; + if (inst->noiseEstLogQuantile[offset + i] < logval) { + // This is the smallest fixed point representation we can + // have, hence we limit the output. + inst->noiseEstLogQuantile[offset + i] = logval; + } + } + + // update density estimate + if (WEBRTC_SPL_ABS_W16(lmagn[i] - inst->noiseEstLogQuantile[offset + i]) + < WIDTH_Q8) { + tmp16no1 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( + inst->noiseEstDensity[offset + i], countProd, 15); + tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( + width_factor, countDiv, 15); + inst->noiseEstDensity[offset + i] = tmp16no1 + tmp16no2; + } + } // end loop over magnitude spectrum + + if (counter >= END_STARTUP_LONG) { + inst->noiseEstCounter[s] = 0; + if (inst->blockIndex >= END_STARTUP_LONG) { + UpdateNoiseEstimate(inst, offset); + } + } + inst->noiseEstCounter[s]++; + + } // end loop over simultaneous estimates + + // Sequentially update the noise during startup + if (inst->blockIndex < END_STARTUP_LONG) { + UpdateNoiseEstimate(inst, offset); + } + + for (i = 0; i < inst->magnLen; i++) { + noise[i] = (WebRtc_UWord32)(inst->noiseEstQuantile[i]); // Q(qNoise) + } + (*q_noise) = (WebRtc_Word16)inst->qNoise; +} + +// Filter the data in the frequency domain, and create spectrum. +static void PrepareSpectrumC(NsxInst_t* inst, int16_t* freq_buf) { + int i = 0, j = 0; + int16_t tmp16 = 0; + + for (i = 0; i < inst->magnLen; i++) { + inst->real[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(inst->real[i], + (WebRtc_Word16)(inst->noiseSupFilter[i]), 14); // Q(normData-stages) + inst->imag[i] = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(inst->imag[i], + (WebRtc_Word16)(inst->noiseSupFilter[i]), 14); // Q(normData-stages) + } + + freq_buf[0] = inst->real[0]; + freq_buf[1] = -inst->imag[0]; + for (i = 1, j = 2; i < inst->anaLen2; i += 1, j += 2) { + tmp16 = (inst->anaLen << 1) - j; + freq_buf[j] = inst->real[i]; + freq_buf[j + 1] = -inst->imag[i]; + freq_buf[tmp16] = inst->real[i]; + freq_buf[tmp16 + 1] = inst->imag[i]; + } + freq_buf[inst->anaLen] = inst->real[inst->anaLen2]; + freq_buf[inst->anaLen + 1] = -inst->imag[inst->anaLen2]; +} + +// Denormalize the input buffer. +static __inline void DenormalizeC(NsxInst_t* inst, int16_t* in, int factor) { + int i = 0, j = 0; + int32_t tmp32 = 0; + for (i = 0, j = 0; i < inst->anaLen; i += 1, j += 2) { + tmp32 = WEBRTC_SPL_SHIFT_W32((WebRtc_Word32)in[j], + factor - inst->normData); + inst->real[i] = WebRtcSpl_SatW32ToW16(tmp32); // Q0 + } +} + +// For the noise supression process, synthesis, read out fully processed +// segment, and update synthesis buffer. +static void SynthesisUpdateC(NsxInst_t* inst, + int16_t* out_frame, + int16_t gain_factor) { + int i = 0; + int16_t tmp16a = 0; + int16_t tmp16b = 0; + int32_t tmp32 = 0; + + // synthesis + for (i = 0; i < inst->anaLen; i++) { + tmp16a = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( + inst->window[i], inst->real[i], 14); // Q0, window in Q14 + tmp32 = WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(tmp16a, gain_factor, 13); // Q0 + // Down shift with rounding + tmp16b = WebRtcSpl_SatW32ToW16(tmp32); // Q0 + inst->synthesisBuffer[i] = WEBRTC_SPL_ADD_SAT_W16(inst->synthesisBuffer[i], + tmp16b); // Q0 + } + + // read out fully processed segment + for (i = 0; i < inst->blockLen10ms; i++) { + out_frame[i] = inst->synthesisBuffer[i]; // Q0 + } + + // update synthesis buffer + WEBRTC_SPL_MEMCPY_W16(inst->synthesisBuffer, + inst->synthesisBuffer + inst->blockLen10ms, + inst->anaLen - inst->blockLen10ms); + WebRtcSpl_ZerosArrayW16(inst->synthesisBuffer + + inst->anaLen - inst->blockLen10ms, inst->blockLen10ms); +} + +// Update analysis buffer for lower band, and window data before FFT. +static void AnalysisUpdateC(NsxInst_t* inst, + int16_t* out, + int16_t* new_speech) { + int i = 0; + + // For lower band update analysis buffer. + WEBRTC_SPL_MEMCPY_W16(inst->analysisBuffer, + inst->analysisBuffer + inst->blockLen10ms, + inst->anaLen - inst->blockLen10ms); + WEBRTC_SPL_MEMCPY_W16(inst->analysisBuffer + + inst->anaLen - inst->blockLen10ms, new_speech, inst->blockLen10ms); + + // Window data before FFT. + for (i = 0; i < inst->anaLen; i++) { + out[i] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( + inst->window[i], inst->analysisBuffer[i], 14); // Q0 + } +} + +// Create a complex number buffer (out[]) as the intput (in[]) interleaved with +// zeros, and normalize it. +static __inline void CreateComplexBufferC(NsxInst_t* inst, + int16_t* in, + int16_t* out) { + int i = 0, j = 0; + for (i = 0, j = 0; i < inst->anaLen; i += 1, j += 2) { + out[j] = WEBRTC_SPL_LSHIFT_W16(in[i], inst->normData); // Q(normData) + out[j + 1] = 0; // Insert zeros in imaginary part + } +} + +void WebRtcNsx_CalcParametricNoiseEstimate(NsxInst_t* inst, + WebRtc_Word16 pink_noise_exp_avg, + WebRtc_Word32 pink_noise_num_avg, + int freq_index, + WebRtc_UWord32* noise_estimate, + WebRtc_UWord32* noise_estimate_avg) { + WebRtc_Word32 tmp32no1 = 0; + WebRtc_Word32 tmp32no2 = 0; + + WebRtc_Word16 int_part = 0; + WebRtc_Word16 frac_part = 0; + + // Use pink noise estimate + // noise_estimate = 2^(pinkNoiseNumerator + pinkNoiseExp * log2(j)) + assert(freq_index >= 0); + assert(freq_index < 129); + tmp32no2 = WEBRTC_SPL_MUL_16_16(pink_noise_exp_avg, kLogIndex[freq_index]); // Q26 + tmp32no2 = WEBRTC_SPL_RSHIFT_W32(tmp32no2, 15); // Q11 + tmp32no1 = pink_noise_num_avg - tmp32no2; // Q11 + + // Calculate output: 2^tmp32no1 + // Output in Q(minNorm-stages) + tmp32no1 += WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)(inst->minNorm - inst->stages), 11); + if (tmp32no1 > 0) { + int_part = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32no1, 11); + frac_part = (WebRtc_Word16)(tmp32no1 & 0x000007ff); // Q11 + // Piecewise linear approximation of 'b' in + // 2^(int_part+frac_part) = 2^int_part * (1 + b) + // 'b' is given in Q11 and below stored in frac_part. + if (WEBRTC_SPL_RSHIFT_W16(frac_part, 10)) { + // Upper fractional part + tmp32no2 = WEBRTC_SPL_MUL_16_16(2048 - frac_part, 1244); // Q21 + tmp32no2 = 2048 - WEBRTC_SPL_RSHIFT_W32(tmp32no2, 10); + } else { + // Lower fractional part + tmp32no2 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_16_16(frac_part, 804), 10); + } + // Shift fractional part to Q(minNorm-stages) + tmp32no2 = WEBRTC_SPL_SHIFT_W32(tmp32no2, int_part - 11); + *noise_estimate_avg = WEBRTC_SPL_LSHIFT_U32(1, int_part) + (WebRtc_UWord32)tmp32no2; + // Scale up to initMagnEst, which is not block averaged + *noise_estimate = (*noise_estimate_avg) * (WebRtc_UWord32)(inst->blockIndex + 1); + } +} + +// Initialize state +WebRtc_Word32 WebRtcNsx_InitCore(NsxInst_t* inst, WebRtc_UWord32 fs) { + int i; + + //check for valid pointer + if (inst == NULL) { + return -1; + } + // + + // Initialization of struct + if (fs == 8000 || fs == 16000 || fs == 32000) { + inst->fs = fs; + } else { + return -1; + } + + if (fs == 8000) { + inst->blockLen10ms = 80; + inst->anaLen = 128; + inst->stages = 7; + inst->window = kBlocks80w128x; + inst->thresholdLogLrt = 131072; //default threshold for LRT feature + inst->maxLrt = 0x0040000; + inst->minLrt = 52429; + } else if (fs == 16000) { + inst->blockLen10ms = 160; + inst->anaLen = 256; + inst->stages = 8; + inst->window = kBlocks160w256x; + inst->thresholdLogLrt = 212644; //default threshold for LRT feature + inst->maxLrt = 0x0080000; + inst->minLrt = 104858; + } else if (fs == 32000) { + inst->blockLen10ms = 160; + inst->anaLen = 256; + inst->stages = 8; + inst->window = kBlocks160w256x; + inst->thresholdLogLrt = 212644; //default threshold for LRT feature + inst->maxLrt = 0x0080000; + inst->minLrt = 104858; + } + inst->anaLen2 = WEBRTC_SPL_RSHIFT_W16(inst->anaLen, 1); + inst->magnLen = inst->anaLen2 + 1; + + WebRtcSpl_ZerosArrayW16(inst->analysisBuffer, ANAL_BLOCKL_MAX); + WebRtcSpl_ZerosArrayW16(inst->synthesisBuffer, ANAL_BLOCKL_MAX); + + // for HB processing + WebRtcSpl_ZerosArrayW16(inst->dataBufHBFX, ANAL_BLOCKL_MAX); + // for quantile noise estimation + WebRtcSpl_ZerosArrayW16(inst->noiseEstQuantile, HALF_ANAL_BLOCKL); + for (i = 0; i < SIMULT * HALF_ANAL_BLOCKL; i++) { + inst->noiseEstLogQuantile[i] = 2048; // Q8 + inst->noiseEstDensity[i] = 153; // Q9 + } + for (i = 0; i < SIMULT; i++) { + inst->noiseEstCounter[i] = (WebRtc_Word16)(END_STARTUP_LONG * (i + 1)) / SIMULT; + } + + // Initialize suppression filter with ones + WebRtcSpl_MemSetW16((WebRtc_Word16*)inst->noiseSupFilter, 16384, HALF_ANAL_BLOCKL); + + // Set the aggressiveness: default + inst->aggrMode = 0; + + //initialize variables for new method + inst->priorNonSpeechProb = 8192; // Q14(0.5) prior probability for speech/noise + for (i = 0; i < HALF_ANAL_BLOCKL; i++) { + inst->prevMagnU16[i] = 0; + inst->prevNoiseU32[i] = 0; //previous noise-spectrum + inst->logLrtTimeAvgW32[i] = 0; //smooth LR ratio + inst->avgMagnPause[i] = 0; //conservative noise spectrum estimate + inst->initMagnEst[i] = 0; //initial average magnitude spectrum + } + + //feature quantities + inst->thresholdSpecDiff = 50; //threshold for difference feature: determined on-line + inst->thresholdSpecFlat = 20480; //threshold for flatness: determined on-line + inst->featureLogLrt = inst->thresholdLogLrt; //average LRT factor (= threshold) + inst->featureSpecFlat = inst->thresholdSpecFlat; //spectral flatness (= threshold) + inst->featureSpecDiff = inst->thresholdSpecDiff; //spectral difference (= threshold) + inst->weightLogLrt = 6; //default weighting par for LRT feature + inst->weightSpecFlat = 0; //default weighting par for spectral flatness feature + inst->weightSpecDiff = 0; //default weighting par for spectral difference feature + + inst->curAvgMagnEnergy = 0; //window time-average of input magnitude spectrum + inst->timeAvgMagnEnergy = 0; //normalization for spectral difference + inst->timeAvgMagnEnergyTmp = 0; //normalization for spectral difference + + //histogram quantities: used to estimate/update thresholds for features + WebRtcSpl_ZerosArrayW16(inst->histLrt, HIST_PAR_EST); + WebRtcSpl_ZerosArrayW16(inst->histSpecDiff, HIST_PAR_EST); + WebRtcSpl_ZerosArrayW16(inst->histSpecFlat, HIST_PAR_EST); + + inst->blockIndex = -1; //frame counter + + //inst->modelUpdate = 500; //window for update + inst->modelUpdate = (1 << STAT_UPDATES); //window for update + inst->cntThresUpdate = 0; //counter feature thresholds updates + + inst->sumMagn = 0; + inst->magnEnergy = 0; + inst->prevQMagn = 0; + inst->qNoise = 0; + inst->prevQNoise = 0; + + inst->energyIn = 0; + inst->scaleEnergyIn = 0; + + inst->whiteNoiseLevel = 0; + inst->pinkNoiseNumerator = 0; + inst->pinkNoiseExp = 0; + inst->minNorm = 15; // Start with full scale + inst->zeroInputSignal = 0; + + //default mode + WebRtcNsx_set_policy_core(inst, 0); + +#ifdef NS_FILEDEBUG + inst->infile = fopen("indebug.pcm", "wb"); + inst->outfile = fopen("outdebug.pcm", "wb"); + inst->file1 = fopen("file1.pcm", "wb"); + inst->file2 = fopen("file2.pcm", "wb"); + inst->file3 = fopen("file3.pcm", "wb"); + inst->file4 = fopen("file4.pcm", "wb"); + inst->file5 = fopen("file5.pcm", "wb"); +#endif + + // Initialize function pointers. + WebRtcNsx_NoiseEstimation = NoiseEstimationC; + WebRtcNsx_PrepareSpectrum = PrepareSpectrumC; + WebRtcNsx_SynthesisUpdate = SynthesisUpdateC; + WebRtcNsx_AnalysisUpdate = AnalysisUpdateC; + WebRtcNsx_Denormalize = DenormalizeC; + WebRtcNsx_CreateComplexBuffer = CreateComplexBufferC; + +#ifdef WEBRTC_DETECT_ARM_NEON + uint64_t features = WebRtc_GetCPUFeaturesARM(); + if ((features & kCPUFeatureNEON) != 0) + { + WebRtcNsx_InitNeon(); + } +#elif defined(WEBRTC_ARCH_ARM_NEON) + WebRtcNsx_InitNeon(); +#endif + + inst->initFlag = 1; + + return 0; +} + +int WebRtcNsx_set_policy_core(NsxInst_t* inst, int mode) { + // allow for modes:0,1,2,3 + if (mode < 0 || mode > 3) { + return -1; + } + + inst->aggrMode = mode; + if (mode == 0) { + inst->overdrive = 256; // Q8(1.0) + inst->denoiseBound = 8192; // Q14(0.5) + inst->gainMap = 0; // No gain compensation + } else if (mode == 1) { + inst->overdrive = 256; // Q8(1.0) + inst->denoiseBound = 4096; // Q14(0.25) + inst->factor2Table = kFactor2Aggressiveness1; + inst->gainMap = 1; + } else if (mode == 2) { + inst->overdrive = 282; // ~= Q8(1.1) + inst->denoiseBound = 2048; // Q14(0.125) + inst->factor2Table = kFactor2Aggressiveness2; + inst->gainMap = 1; + } else if (mode == 3) { + inst->overdrive = 320; // Q8(1.25) + inst->denoiseBound = 1475; // ~= Q14(0.09) + inst->factor2Table = kFactor2Aggressiveness3; + inst->gainMap = 1; + } + return 0; +} + +// Extract thresholds for feature parameters +// histograms are computed over some window_size (given by window_pars) +// thresholds and weights are extracted every window +// flag 0 means update histogram only, flag 1 means compute the thresholds/weights +// threshold and weights are returned in: inst->priorModelPars +void WebRtcNsx_FeatureParameterExtraction(NsxInst_t* inst, int flag) { + WebRtc_UWord32 tmpU32; + WebRtc_UWord32 histIndex; + WebRtc_UWord32 posPeak1SpecFlatFX, posPeak2SpecFlatFX; + WebRtc_UWord32 posPeak1SpecDiffFX, posPeak2SpecDiffFX; + + WebRtc_Word32 tmp32; + WebRtc_Word32 fluctLrtFX, thresFluctLrtFX; + WebRtc_Word32 avgHistLrtFX, avgSquareHistLrtFX, avgHistLrtComplFX; + + WebRtc_Word16 j; + WebRtc_Word16 numHistLrt; + + int i; + int useFeatureSpecFlat, useFeatureSpecDiff, featureSum; + int maxPeak1, maxPeak2; + int weightPeak1SpecFlat, weightPeak2SpecFlat; + int weightPeak1SpecDiff, weightPeak2SpecDiff; + + //update histograms + if (!flag) { + // LRT + // Type casting to UWord32 is safe since negative values will not be wrapped to larger + // values than HIST_PAR_EST + histIndex = (WebRtc_UWord32)(inst->featureLogLrt); + if (histIndex < HIST_PAR_EST) { + inst->histLrt[histIndex]++; + } + // Spectral flatness + // (inst->featureSpecFlat*20)>>10 = (inst->featureSpecFlat*5)>>8 + histIndex = WEBRTC_SPL_RSHIFT_U32(inst->featureSpecFlat * 5, 8); + if (histIndex < HIST_PAR_EST) { + inst->histSpecFlat[histIndex]++; + } + // Spectral difference + histIndex = HIST_PAR_EST; + if (inst->timeAvgMagnEnergy > 0) { + // Guard against division by zero + // If timeAvgMagnEnergy == 0 we have no normalizing statistics and + // therefore can't update the histogram + histIndex = WEBRTC_SPL_UDIV((inst->featureSpecDiff * 5) >> inst->stages, + inst->timeAvgMagnEnergy); + } + if (histIndex < HIST_PAR_EST) { + inst->histSpecDiff[histIndex]++; + } + } + + // extract parameters for speech/noise probability + if (flag) { + useFeatureSpecDiff = 1; + //for LRT feature: + // compute the average over inst->featureExtractionParams.rangeAvgHistLrt + avgHistLrtFX = 0; + avgSquareHistLrtFX = 0; + numHistLrt = 0; + for (i = 0; i < BIN_SIZE_LRT; i++) { + j = (2 * i + 1); + tmp32 = WEBRTC_SPL_MUL_16_16(inst->histLrt[i], j); + avgHistLrtFX += tmp32; + numHistLrt += inst->histLrt[i]; + avgSquareHistLrtFX += WEBRTC_SPL_MUL_32_16(tmp32, j); + } + avgHistLrtComplFX = avgHistLrtFX; + for (; i < HIST_PAR_EST; i++) { + j = (2 * i + 1); + tmp32 = WEBRTC_SPL_MUL_16_16(inst->histLrt[i], j); + avgHistLrtComplFX += tmp32; + avgSquareHistLrtFX += WEBRTC_SPL_MUL_32_16(tmp32, j); + } + fluctLrtFX = WEBRTC_SPL_MUL(avgSquareHistLrtFX, numHistLrt); + fluctLrtFX -= WEBRTC_SPL_MUL(avgHistLrtFX, avgHistLrtComplFX); + thresFluctLrtFX = THRES_FLUCT_LRT * numHistLrt; + // get threshold for LRT feature: + tmpU32 = (FACTOR_1_LRT_DIFF * (WebRtc_UWord32)avgHistLrtFX); + if ((fluctLrtFX < thresFluctLrtFX) || (numHistLrt == 0) || + (tmpU32 > (WebRtc_UWord32)(100 * numHistLrt))) { + //very low fluctuation, so likely noise + inst->thresholdLogLrt = inst->maxLrt; + } else { + tmp32 = (WebRtc_Word32)((tmpU32 << (9 + inst->stages)) / numHistLrt / + 25); + // check if value is within min/max range + inst->thresholdLogLrt = WEBRTC_SPL_SAT(inst->maxLrt, + tmp32, + inst->minLrt); + } + if (fluctLrtFX < thresFluctLrtFX) { + // Do not use difference feature if fluctuation of LRT feature is very low: + // most likely just noise state + useFeatureSpecDiff = 0; + } + + // for spectral flatness and spectral difference: compute the main peaks of histogram + maxPeak1 = 0; + maxPeak2 = 0; + posPeak1SpecFlatFX = 0; + posPeak2SpecFlatFX = 0; + weightPeak1SpecFlat = 0; + weightPeak2SpecFlat = 0; + + // peaks for flatness + for (i = 0; i < HIST_PAR_EST; i++) { + if (inst->histSpecFlat[i] > maxPeak1) { + // Found new "first" peak + maxPeak2 = maxPeak1; + weightPeak2SpecFlat = weightPeak1SpecFlat; + posPeak2SpecFlatFX = posPeak1SpecFlatFX; + + maxPeak1 = inst->histSpecFlat[i]; + weightPeak1SpecFlat = inst->histSpecFlat[i]; + posPeak1SpecFlatFX = (WebRtc_UWord32)(2 * i + 1); + } else if (inst->histSpecFlat[i] > maxPeak2) { + // Found new "second" peak + maxPeak2 = inst->histSpecFlat[i]; + weightPeak2SpecFlat = inst->histSpecFlat[i]; + posPeak2SpecFlatFX = (WebRtc_UWord32)(2 * i + 1); + } + } + + // for spectral flatness feature + useFeatureSpecFlat = 1; + // merge the two peaks if they are close + if ((posPeak1SpecFlatFX - posPeak2SpecFlatFX < LIM_PEAK_SPACE_FLAT_DIFF) + && (weightPeak2SpecFlat * LIM_PEAK_WEIGHT_FLAT_DIFF > weightPeak1SpecFlat)) { + weightPeak1SpecFlat += weightPeak2SpecFlat; + posPeak1SpecFlatFX = (posPeak1SpecFlatFX + posPeak2SpecFlatFX) >> 1; + } + //reject if weight of peaks is not large enough, or peak value too small + if (weightPeak1SpecFlat < THRES_WEIGHT_FLAT_DIFF || posPeak1SpecFlatFX + < THRES_PEAK_FLAT) { + useFeatureSpecFlat = 0; + } else { // if selected, get the threshold + // compute the threshold and check if value is within min/max range + inst->thresholdSpecFlat = WEBRTC_SPL_SAT(MAX_FLAT_Q10, FACTOR_2_FLAT_Q10 + * posPeak1SpecFlatFX, MIN_FLAT_Q10); //Q10 + } + // done with flatness feature + + if (useFeatureSpecDiff) { + //compute two peaks for spectral difference + maxPeak1 = 0; + maxPeak2 = 0; + posPeak1SpecDiffFX = 0; + posPeak2SpecDiffFX = 0; + weightPeak1SpecDiff = 0; + weightPeak2SpecDiff = 0; + // peaks for spectral difference + for (i = 0; i < HIST_PAR_EST; i++) { + if (inst->histSpecDiff[i] > maxPeak1) { + // Found new "first" peak + maxPeak2 = maxPeak1; + weightPeak2SpecDiff = weightPeak1SpecDiff; + posPeak2SpecDiffFX = posPeak1SpecDiffFX; + + maxPeak1 = inst->histSpecDiff[i]; + weightPeak1SpecDiff = inst->histSpecDiff[i]; + posPeak1SpecDiffFX = (WebRtc_UWord32)(2 * i + 1); + } else if (inst->histSpecDiff[i] > maxPeak2) { + // Found new "second" peak + maxPeak2 = inst->histSpecDiff[i]; + weightPeak2SpecDiff = inst->histSpecDiff[i]; + posPeak2SpecDiffFX = (WebRtc_UWord32)(2 * i + 1); + } + } + + // merge the two peaks if they are close + if ((posPeak1SpecDiffFX - posPeak2SpecDiffFX < LIM_PEAK_SPACE_FLAT_DIFF) + && (weightPeak2SpecDiff * LIM_PEAK_WEIGHT_FLAT_DIFF > weightPeak1SpecDiff)) { + weightPeak1SpecDiff += weightPeak2SpecDiff; + posPeak1SpecDiffFX = (posPeak1SpecDiffFX + posPeak2SpecDiffFX) >> 1; + } + // get the threshold value and check if value is within min/max range + inst->thresholdSpecDiff = WEBRTC_SPL_SAT(MAX_DIFF, FACTOR_1_LRT_DIFF + * posPeak1SpecDiffFX, MIN_DIFF); //5x bigger + //reject if weight of peaks is not large enough + if (weightPeak1SpecDiff < THRES_WEIGHT_FLAT_DIFF) { + useFeatureSpecDiff = 0; + } + // done with spectral difference feature + } + + // select the weights between the features + // inst->priorModelPars[4] is weight for LRT: always selected + featureSum = 6 / (1 + useFeatureSpecFlat + useFeatureSpecDiff); + inst->weightLogLrt = featureSum; + inst->weightSpecFlat = useFeatureSpecFlat * featureSum; + inst->weightSpecDiff = useFeatureSpecDiff * featureSum; + + // set histograms to zero for next update + WebRtcSpl_ZerosArrayW16(inst->histLrt, HIST_PAR_EST); + WebRtcSpl_ZerosArrayW16(inst->histSpecDiff, HIST_PAR_EST); + WebRtcSpl_ZerosArrayW16(inst->histSpecFlat, HIST_PAR_EST); + } // end of flag == 1 +} + + +// Compute spectral flatness on input spectrum +// magn is the magnitude spectrum +// spectral flatness is returned in inst->featureSpecFlat +void WebRtcNsx_ComputeSpectralFlatness(NsxInst_t* inst, WebRtc_UWord16* magn) { + WebRtc_UWord32 tmpU32; + WebRtc_UWord32 avgSpectralFlatnessNum, avgSpectralFlatnessDen; + + WebRtc_Word32 tmp32; + WebRtc_Word32 currentSpectralFlatness, logCurSpectralFlatness; + + WebRtc_Word16 zeros, frac, intPart; + + int i; + + // for flatness + avgSpectralFlatnessNum = 0; + avgSpectralFlatnessDen = inst->sumMagn - (WebRtc_UWord32)magn[0]; // Q(normData-stages) + + // compute log of ratio of the geometric to arithmetic mean: check for log(0) case + // flatness = exp( sum(log(magn[i]))/N - log(sum(magn[i])/N) ) + // = exp( sum(log(magn[i]))/N ) * N / sum(magn[i]) + // = 2^( sum(log2(magn[i]))/N - (log2(sum(magn[i])) - log2(N)) ) [This is used] + for (i = 1; i < inst->magnLen; i++) { + // First bin is excluded from spectrum measures. Number of bins is now a power of 2 + if (magn[i]) { + zeros = WebRtcSpl_NormU32((WebRtc_UWord32)magn[i]); + frac = (WebRtc_Word16)(((WebRtc_UWord32)((WebRtc_UWord32)(magn[i]) << zeros) + & 0x7FFFFFFF) >> 23); + // log2(magn(i)) + assert(frac < 256); + tmpU32 = (WebRtc_UWord32)(((31 - zeros) << 8) + + WebRtcNsx_kLogTableFrac[frac]); // Q8 + avgSpectralFlatnessNum += tmpU32; // Q8 + } else { + //if at least one frequency component is zero, treat separately + tmpU32 = WEBRTC_SPL_UMUL_32_16(inst->featureSpecFlat, SPECT_FLAT_TAVG_Q14); // Q24 + inst->featureSpecFlat -= WEBRTC_SPL_RSHIFT_U32(tmpU32, 14); // Q10 + return; + } + } + //ratio and inverse log: check for case of log(0) + zeros = WebRtcSpl_NormU32(avgSpectralFlatnessDen); + frac = (WebRtc_Word16)(((avgSpectralFlatnessDen << zeros) & 0x7FFFFFFF) >> 23); + // log2(avgSpectralFlatnessDen) + assert(frac < 256); + tmp32 = (WebRtc_Word32)(((31 - zeros) << 8) + WebRtcNsx_kLogTableFrac[frac]); // Q8 + logCurSpectralFlatness = (WebRtc_Word32)avgSpectralFlatnessNum; + logCurSpectralFlatness += ((WebRtc_Word32)(inst->stages - 1) << (inst->stages + 7)); // Q(8+stages-1) + logCurSpectralFlatness -= (tmp32 << (inst->stages - 1)); + logCurSpectralFlatness = WEBRTC_SPL_LSHIFT_W32(logCurSpectralFlatness, 10 - inst->stages); // Q17 + tmp32 = (WebRtc_Word32)(0x00020000 | (WEBRTC_SPL_ABS_W32(logCurSpectralFlatness) + & 0x0001FFFF)); //Q17 + intPart = -(WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(logCurSpectralFlatness, 17); + intPart += 7; // Shift 7 to get the output in Q10 (from Q17 = -17+10) + if (intPart > 0) { + currentSpectralFlatness = WEBRTC_SPL_RSHIFT_W32(tmp32, intPart); + } else { + currentSpectralFlatness = WEBRTC_SPL_LSHIFT_W32(tmp32, -intPart); + } + + //time average update of spectral flatness feature + tmp32 = currentSpectralFlatness - (WebRtc_Word32)inst->featureSpecFlat; // Q10 + tmp32 = WEBRTC_SPL_MUL_32_16(SPECT_FLAT_TAVG_Q14, tmp32); // Q24 + inst->featureSpecFlat = (WebRtc_UWord32)((WebRtc_Word32)inst->featureSpecFlat + + WEBRTC_SPL_RSHIFT_W32(tmp32, 14)); // Q10 + // done with flatness feature +} + + +// Compute the difference measure between input spectrum and a template/learned noise spectrum +// magn_tmp is the input spectrum +// the reference/template spectrum is inst->magn_avg_pause[i] +// returns (normalized) spectral difference in inst->featureSpecDiff +void WebRtcNsx_ComputeSpectralDifference(NsxInst_t* inst, WebRtc_UWord16* magnIn) { + // This is to be calculated: + // avgDiffNormMagn = var(magnIn) - cov(magnIn, magnAvgPause)^2 / var(magnAvgPause) + + WebRtc_UWord32 tmpU32no1, tmpU32no2; + WebRtc_UWord32 varMagnUFX, varPauseUFX, avgDiffNormMagnUFX; + + WebRtc_Word32 tmp32no1, tmp32no2; + WebRtc_Word32 avgPauseFX, avgMagnFX, covMagnPauseFX; + WebRtc_Word32 maxPause, minPause; + + WebRtc_Word16 tmp16no1; + + int i, norm32, nShifts; + + avgPauseFX = 0; + maxPause = 0; + minPause = inst->avgMagnPause[0]; // Q(prevQMagn) + // compute average quantities + for (i = 0; i < inst->magnLen; i++) { + // Compute mean of magn_pause + avgPauseFX += inst->avgMagnPause[i]; // in Q(prevQMagn) + maxPause = WEBRTC_SPL_MAX(maxPause, inst->avgMagnPause[i]); + minPause = WEBRTC_SPL_MIN(minPause, inst->avgMagnPause[i]); + } + // normalize by replacing div of "inst->magnLen" with "inst->stages-1" shifts + avgPauseFX = WEBRTC_SPL_RSHIFT_W32(avgPauseFX, inst->stages - 1); + avgMagnFX = (WebRtc_Word32)WEBRTC_SPL_RSHIFT_U32(inst->sumMagn, inst->stages - 1); + // Largest possible deviation in magnPause for (co)var calculations + tmp32no1 = WEBRTC_SPL_MAX(maxPause - avgPauseFX, avgPauseFX - minPause); + // Get number of shifts to make sure we don't get wrap around in varPause + nShifts = WEBRTC_SPL_MAX(0, 10 + inst->stages - WebRtcSpl_NormW32(tmp32no1)); + + varMagnUFX = 0; + varPauseUFX = 0; + covMagnPauseFX = 0; + for (i = 0; i < inst->magnLen; i++) { + // Compute var and cov of magn and magn_pause + tmp16no1 = (WebRtc_Word16)((WebRtc_Word32)magnIn[i] - avgMagnFX); + tmp32no2 = inst->avgMagnPause[i] - avgPauseFX; + varMagnUFX += (WebRtc_UWord32)WEBRTC_SPL_MUL_16_16(tmp16no1, tmp16no1); // Q(2*qMagn) + tmp32no1 = WEBRTC_SPL_MUL_32_16(tmp32no2, tmp16no1); // Q(prevQMagn+qMagn) + covMagnPauseFX += tmp32no1; // Q(prevQMagn+qMagn) + tmp32no1 = WEBRTC_SPL_RSHIFT_W32(tmp32no2, nShifts); // Q(prevQMagn-minPause) + varPauseUFX += (WebRtc_UWord32)WEBRTC_SPL_MUL(tmp32no1, tmp32no1); // Q(2*(prevQMagn-minPause)) + } + //update of average magnitude spectrum: Q(-2*stages) and averaging replaced by shifts + inst->curAvgMagnEnergy += WEBRTC_SPL_RSHIFT_U32(inst->magnEnergy, 2 * inst->normData + + inst->stages - 1); + + avgDiffNormMagnUFX = varMagnUFX; // Q(2*qMagn) + if ((varPauseUFX) && (covMagnPauseFX)) { + tmpU32no1 = (WebRtc_UWord32)WEBRTC_SPL_ABS_W32(covMagnPauseFX); // Q(prevQMagn+qMagn) + norm32 = WebRtcSpl_NormU32(tmpU32no1) - 16; + if (norm32 > 0) { + tmpU32no1 = WEBRTC_SPL_LSHIFT_U32(tmpU32no1, norm32); // Q(prevQMagn+qMagn+norm32) + } else { + tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, -norm32); // Q(prevQMagn+qMagn+norm32) + } + tmpU32no2 = WEBRTC_SPL_UMUL(tmpU32no1, tmpU32no1); // Q(2*(prevQMagn+qMagn-norm32)) + + nShifts += norm32; + nShifts <<= 1; + if (nShifts < 0) { + varPauseUFX >>= (-nShifts); // Q(2*(qMagn+norm32+minPause)) + nShifts = 0; + } + if (varPauseUFX > 0) { + // Q(2*(qMagn+norm32-16+minPause)) + tmpU32no1 = WEBRTC_SPL_UDIV(tmpU32no2, varPauseUFX); + tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, nShifts); + + // Q(2*qMagn) + avgDiffNormMagnUFX -= WEBRTC_SPL_MIN(avgDiffNormMagnUFX, tmpU32no1); + } else { + avgDiffNormMagnUFX = 0; + } + } + //normalize and compute time average update of difference feature + tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(avgDiffNormMagnUFX, 2 * inst->normData); + if (inst->featureSpecDiff > tmpU32no1) { + tmpU32no2 = WEBRTC_SPL_UMUL_32_16(inst->featureSpecDiff - tmpU32no1, + SPECT_DIFF_TAVG_Q8); // Q(8-2*stages) + inst->featureSpecDiff -= WEBRTC_SPL_RSHIFT_U32(tmpU32no2, 8); // Q(-2*stages) + } else { + tmpU32no2 = WEBRTC_SPL_UMUL_32_16(tmpU32no1 - inst->featureSpecDiff, + SPECT_DIFF_TAVG_Q8); // Q(8-2*stages) + inst->featureSpecDiff += WEBRTC_SPL_RSHIFT_U32(tmpU32no2, 8); // Q(-2*stages) + } +} + +// Compute speech/noise probability +// speech/noise probability is returned in: probSpeechFinal +//snrLocPrior is the prior SNR for each frequency (in Q11) +//snrLocPost is the post SNR for each frequency (in Q11) +void WebRtcNsx_SpeechNoiseProb(NsxInst_t* inst, WebRtc_UWord16* nonSpeechProbFinal, + WebRtc_UWord32* priorLocSnr, WebRtc_UWord32* postLocSnr) { + WebRtc_UWord32 zeros, num, den, tmpU32no1, tmpU32no2, tmpU32no3; + + WebRtc_Word32 invLrtFX, indPriorFX, tmp32, tmp32no1, tmp32no2, besselTmpFX32; + WebRtc_Word32 frac32, logTmp; + WebRtc_Word32 logLrtTimeAvgKsumFX; + + WebRtc_Word16 indPriorFX16; + WebRtc_Word16 tmp16, tmp16no1, tmp16no2, tmpIndFX, tableIndex, frac, intPart; + + int i, normTmp, normTmp2, nShifts; + + // compute feature based on average LR factor + // this is the average over all frequencies of the smooth log LRT + logLrtTimeAvgKsumFX = 0; + for (i = 0; i < inst->magnLen; i++) { + besselTmpFX32 = (WebRtc_Word32)postLocSnr[i]; // Q11 + normTmp = WebRtcSpl_NormU32(postLocSnr[i]); + num = WEBRTC_SPL_LSHIFT_U32(postLocSnr[i], normTmp); // Q(11+normTmp) + if (normTmp > 10) { + den = WEBRTC_SPL_LSHIFT_U32(priorLocSnr[i], normTmp - 11); // Q(normTmp) + } else { + den = WEBRTC_SPL_RSHIFT_U32(priorLocSnr[i], 11 - normTmp); // Q(normTmp) + } + if (den > 0) { + besselTmpFX32 -= WEBRTC_SPL_UDIV(num, den); // Q11 + } else { + besselTmpFX32 -= num; // Q11 + } + + // inst->logLrtTimeAvg[i] += LRT_TAVG * (besselTmp - log(snrLocPrior) - inst->logLrtTimeAvg[i]); + // Here, LRT_TAVG = 0.5 + zeros = WebRtcSpl_NormU32(priorLocSnr[i]); + frac32 = (WebRtc_Word32)(((priorLocSnr[i] << zeros) & 0x7FFFFFFF) >> 19); + tmp32 = WEBRTC_SPL_MUL(frac32, frac32); + tmp32 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(tmp32, -43), 19); + tmp32 += WEBRTC_SPL_MUL_16_16_RSFT((WebRtc_Word16)frac32, 5412, 12); + frac32 = tmp32 + 37; + // tmp32 = log2(priorLocSnr[i]) + tmp32 = (WebRtc_Word32)(((31 - zeros) << 12) + frac32) - (11 << 12); // Q12 + logTmp = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL_32_16(tmp32, 178), 8); // log2(priorLocSnr[i])*log(2) + tmp32no1 = WEBRTC_SPL_RSHIFT_W32(logTmp + inst->logLrtTimeAvgW32[i], 1); // Q12 + inst->logLrtTimeAvgW32[i] += (besselTmpFX32 - tmp32no1); // Q12 + + logLrtTimeAvgKsumFX += inst->logLrtTimeAvgW32[i]; // Q12 + } + inst->featureLogLrt = WEBRTC_SPL_RSHIFT_W32(logLrtTimeAvgKsumFX * 5, inst->stages + 10); // 5 = BIN_SIZE_LRT / 2 + // done with computation of LR factor + + // + //compute the indicator functions + // + + // average LRT feature + // FLOAT code + // indicator0 = 0.5 * (tanh(widthPrior * (logLrtTimeAvgKsum - threshPrior0)) + 1.0); + tmpIndFX = 16384; // Q14(1.0) + tmp32no1 = logLrtTimeAvgKsumFX - inst->thresholdLogLrt; // Q12 + nShifts = 7 - inst->stages; // WIDTH_PR_MAP_SHIFT - inst->stages + 5; + //use larger width in tanh map for pause regions + if (tmp32no1 < 0) { + tmpIndFX = 0; + tmp32no1 = -tmp32no1; + //widthPrior = widthPrior * 2.0; + nShifts++; + } + tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1, nShifts); // Q14 + // compute indicator function: sigmoid map + tableIndex = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32no1, 14); + if ((tableIndex < 16) && (tableIndex >= 0)) { + tmp16no2 = kIndicatorTable[tableIndex]; + tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex]; + frac = (WebRtc_Word16)(tmp32no1 & 0x00003fff); // Q14 + tmp16no2 += (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16no1, frac, 14); + if (tmpIndFX == 0) { + tmpIndFX = 8192 - tmp16no2; // Q14 + } else { + tmpIndFX = 8192 + tmp16no2; // Q14 + } + } + indPriorFX = WEBRTC_SPL_MUL_16_16(inst->weightLogLrt, tmpIndFX); // 6*Q14 + + //spectral flatness feature + if (inst->weightSpecFlat) { + tmpU32no1 = WEBRTC_SPL_UMUL(inst->featureSpecFlat, 400); // Q10 + tmpIndFX = 16384; // Q14(1.0) + //use larger width in tanh map for pause regions + tmpU32no2 = inst->thresholdSpecFlat - tmpU32no1; //Q10 + nShifts = 4; + if (inst->thresholdSpecFlat < tmpU32no1) { + tmpIndFX = 0; + tmpU32no2 = tmpU32no1 - inst->thresholdSpecFlat; + //widthPrior = widthPrior * 2.0; + nShifts++; + } + tmp32no1 = (WebRtc_Word32)WebRtcSpl_DivU32U16(WEBRTC_SPL_LSHIFT_U32(tmpU32no2, + nShifts), 25); //Q14 + tmpU32no1 = WebRtcSpl_DivU32U16(WEBRTC_SPL_LSHIFT_U32(tmpU32no2, nShifts), 25); //Q14 + // compute indicator function: sigmoid map + // FLOAT code + // indicator1 = 0.5 * (tanh(sgnMap * widthPrior * (threshPrior1 - tmpFloat1)) + 1.0); + tableIndex = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32(tmpU32no1, 14); + if (tableIndex < 16) { + tmp16no2 = kIndicatorTable[tableIndex]; + tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex]; + frac = (WebRtc_Word16)(tmpU32no1 & 0x00003fff); // Q14 + tmp16no2 += (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16no1, frac, 14); + if (tmpIndFX) { + tmpIndFX = 8192 + tmp16no2; // Q14 + } else { + tmpIndFX = 8192 - tmp16no2; // Q14 + } + } + indPriorFX += WEBRTC_SPL_MUL_16_16(inst->weightSpecFlat, tmpIndFX); // 6*Q14 + } + + //for template spectral-difference + if (inst->weightSpecDiff) { + tmpU32no1 = 0; + if (inst->featureSpecDiff) { + normTmp = WEBRTC_SPL_MIN(20 - inst->stages, + WebRtcSpl_NormU32(inst->featureSpecDiff)); + tmpU32no1 = WEBRTC_SPL_LSHIFT_U32(inst->featureSpecDiff, normTmp); // Q(normTmp-2*stages) + tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(inst->timeAvgMagnEnergy, 20 - inst->stages + - normTmp); + if (tmpU32no2 > 0) { + // Q(20 - inst->stages) + tmpU32no1 = WEBRTC_SPL_UDIV(tmpU32no1, tmpU32no2); + } else { + tmpU32no1 = (WebRtc_UWord32)(0x7fffffff); + } + } + tmpU32no3 = WEBRTC_SPL_UDIV(WEBRTC_SPL_LSHIFT_U32(inst->thresholdSpecDiff, 17), 25); + tmpU32no2 = tmpU32no1 - tmpU32no3; + nShifts = 1; + tmpIndFX = 16384; // Q14(1.0) + //use larger width in tanh map for pause regions + if (tmpU32no2 & 0x80000000) { + tmpIndFX = 0; + tmpU32no2 = tmpU32no3 - tmpU32no1; + //widthPrior = widthPrior * 2.0; + nShifts--; + } + tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no2, nShifts); + // compute indicator function: sigmoid map + /* FLOAT code + indicator2 = 0.5 * (tanh(widthPrior * (tmpFloat1 - threshPrior2)) + 1.0); + */ + tableIndex = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32(tmpU32no1, 14); + if (tableIndex < 16) { + tmp16no2 = kIndicatorTable[tableIndex]; + tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex]; + frac = (WebRtc_Word16)(tmpU32no1 & 0x00003fff); // Q14 + tmp16no2 += (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( + tmp16no1, frac, 14); + if (tmpIndFX) { + tmpIndFX = 8192 + tmp16no2; + } else { + tmpIndFX = 8192 - tmp16no2; + } + } + indPriorFX += WEBRTC_SPL_MUL_16_16(inst->weightSpecDiff, tmpIndFX); // 6*Q14 + } + + //combine the indicator function with the feature weights + // FLOAT code + // indPrior = 1 - (weightIndPrior0 * indicator0 + weightIndPrior1 * indicator1 + weightIndPrior2 * indicator2); + indPriorFX16 = WebRtcSpl_DivW32W16ResW16(98307 - indPriorFX, 6); // Q14 + // done with computing indicator function + + //compute the prior probability + // FLOAT code + // inst->priorNonSpeechProb += PRIOR_UPDATE * (indPriorNonSpeech - inst->priorNonSpeechProb); + tmp16 = indPriorFX16 - inst->priorNonSpeechProb; // Q14 + inst->priorNonSpeechProb += (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT( + PRIOR_UPDATE_Q14, tmp16, 14); // Q14 + + //final speech probability: combine prior model with LR factor: + + memset(nonSpeechProbFinal, 0, sizeof(WebRtc_UWord16) * inst->magnLen); + + if (inst->priorNonSpeechProb > 0) { + for (i = 0; i < inst->magnLen; i++) { + // FLOAT code + // invLrt = exp(inst->logLrtTimeAvg[i]); + // invLrt = inst->priorSpeechProb * invLrt; + // nonSpeechProbFinal[i] = (1.0 - inst->priorSpeechProb) / (1.0 - inst->priorSpeechProb + invLrt); + // invLrt = (1.0 - inst->priorNonSpeechProb) * invLrt; + // nonSpeechProbFinal[i] = inst->priorNonSpeechProb / (inst->priorNonSpeechProb + invLrt); + if (inst->logLrtTimeAvgW32[i] < 65300) { + tmp32no1 = WEBRTC_SPL_RSHIFT_W32(WEBRTC_SPL_MUL(inst->logLrtTimeAvgW32[i], 23637), + 14); // Q12 + intPart = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmp32no1, 12); + if (intPart < -8) { + intPart = -8; + } + frac = (WebRtc_Word16)(tmp32no1 & 0x00000fff); // Q12 + + // Quadratic approximation of 2^frac + tmp32no2 = WEBRTC_SPL_RSHIFT_W32(frac * frac * 44, 19); // Q12 + tmp32no2 += WEBRTC_SPL_MUL_16_16_RSFT(frac, 84, 7); // Q12 + invLrtFX = WEBRTC_SPL_LSHIFT_W32(1, 8 + intPart) + + WEBRTC_SPL_SHIFT_W32(tmp32no2, intPart - 4); // Q8 + + normTmp = WebRtcSpl_NormW32(invLrtFX); + normTmp2 = WebRtcSpl_NormW16((16384 - inst->priorNonSpeechProb)); + if (normTmp + normTmp2 >= 7) { + if (normTmp + normTmp2 < 15) { + invLrtFX = WEBRTC_SPL_RSHIFT_W32(invLrtFX, 15 - normTmp2 - normTmp); + // Q(normTmp+normTmp2-7) + tmp32no1 = WEBRTC_SPL_MUL_32_16(invLrtFX, (16384 - inst->priorNonSpeechProb)); + // Q(normTmp+normTmp2+7) + invLrtFX = WEBRTC_SPL_SHIFT_W32(tmp32no1, 7 - normTmp - normTmp2); // Q14 + } else { + tmp32no1 = WEBRTC_SPL_MUL_32_16(invLrtFX, (16384 - inst->priorNonSpeechProb)); // Q22 + invLrtFX = WEBRTC_SPL_RSHIFT_W32(tmp32no1, 8); // Q14 + } + + tmp32no1 = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)inst->priorNonSpeechProb, 8); // Q22 + + nonSpeechProbFinal[i] = (WebRtc_UWord16)WEBRTC_SPL_DIV(tmp32no1, + (WebRtc_Word32)inst->priorNonSpeechProb + invLrtFX); // Q8 + } + } + } + } +} + +// Transform input (speechFrame) to frequency domain magnitude (magnU16) +void WebRtcNsx_DataAnalysis(NsxInst_t* inst, short* speechFrame, WebRtc_UWord16* magnU16) { + + WebRtc_UWord32 tmpU32no1, tmpU32no2; + + WebRtc_Word32 tmp_1_w32 = 0; + WebRtc_Word32 tmp_2_w32 = 0; + WebRtc_Word32 sum_log_magn = 0; + WebRtc_Word32 sum_log_i_log_magn = 0; + + WebRtc_UWord16 sum_log_magn_u16 = 0; + WebRtc_UWord16 tmp_u16 = 0; + + WebRtc_Word16 sum_log_i = 0; + WebRtc_Word16 sum_log_i_square = 0; + WebRtc_Word16 frac = 0; + WebRtc_Word16 log2 = 0; + WebRtc_Word16 matrix_determinant = 0; + WebRtc_Word16 winData[ANAL_BLOCKL_MAX], maxWinData; + WebRtc_Word16 realImag[ANAL_BLOCKL_MAX << 1]; + + int i, j; + int zeros; + int net_norm = 0; + int right_shifts_in_magnU16 = 0; + int right_shifts_in_initMagnEst = 0; + + // Update analysis buffer for lower band, and window data before FFT. + WebRtcNsx_AnalysisUpdate(inst, winData, speechFrame); + + // Get input energy + inst->energyIn = WebRtcSpl_Energy(winData, (int)inst->anaLen, &(inst->scaleEnergyIn)); + + // Reset zero input flag + inst->zeroInputSignal = 0; + // Acquire norm for winData + maxWinData = WebRtcSpl_MaxAbsValueW16(winData, inst->anaLen); + inst->normData = WebRtcSpl_NormW16(maxWinData); + if (maxWinData == 0) { + // Treat zero input separately. + inst->zeroInputSignal = 1; + return; + } + + // Determine the net normalization in the frequency domain + net_norm = inst->stages - inst->normData; + // Track lowest normalization factor and use it to prevent wrap around in shifting + right_shifts_in_magnU16 = inst->normData - inst->minNorm; + right_shifts_in_initMagnEst = WEBRTC_SPL_MAX(-right_shifts_in_magnU16, 0); + inst->minNorm -= right_shifts_in_initMagnEst; + right_shifts_in_magnU16 = WEBRTC_SPL_MAX(right_shifts_in_magnU16, 0); + + // create realImag as winData interleaved with zeros (= imag. part), normalize it + WebRtcNsx_CreateComplexBuffer(inst, winData, realImag); + + // bit-reverse position of elements in array and FFT the array + WebRtcSpl_ComplexBitReverse(realImag, inst->stages); // Q(normData-stages) + WebRtcSpl_ComplexFFT(realImag, inst->stages, 1); + + inst->imag[0] = 0; // Q(normData-stages) + inst->imag[inst->anaLen2] = 0; + inst->real[0] = realImag[0]; // Q(normData-stages) + inst->real[inst->anaLen2] = realImag[inst->anaLen]; + // Q(2*(normData-stages)) + inst->magnEnergy = (WebRtc_UWord32)WEBRTC_SPL_MUL_16_16(inst->real[0], inst->real[0]); + inst->magnEnergy += (WebRtc_UWord32)WEBRTC_SPL_MUL_16_16(inst->real[inst->anaLen2], + inst->real[inst->anaLen2]); + magnU16[0] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16(inst->real[0]); // Q(normData-stages) + magnU16[inst->anaLen2] = (WebRtc_UWord16)WEBRTC_SPL_ABS_W16(inst->real[inst->anaLen2]); + inst->sumMagn = (WebRtc_UWord32)magnU16[0]; // Q(normData-stages) + inst->sumMagn += (WebRtc_UWord32)magnU16[inst->anaLen2]; + + if (inst->blockIndex >= END_STARTUP_SHORT) { + for (i = 1, j = 2; i < inst->anaLen2; i += 1, j += 2) { + inst->real[i] = realImag[j]; + inst->imag[i] = -realImag[j + 1]; + // magnitude spectrum + // energy in Q(2*(normData-stages)) + tmpU32no1 = (WebRtc_UWord32)WEBRTC_SPL_MUL_16_16(realImag[j], realImag[j]); + tmpU32no1 += (WebRtc_UWord32)WEBRTC_SPL_MUL_16_16(realImag[j + 1], realImag[j + 1]); + inst->magnEnergy += tmpU32no1; // Q(2*(normData-stages)) + + magnU16[i] = (WebRtc_UWord16)WebRtcSpl_SqrtFloor(tmpU32no1); // Q(normData-stages) + inst->sumMagn += (WebRtc_UWord32)magnU16[i]; // Q(normData-stages) + } + } else { + // + // Gather information during startup for noise parameter estimation + // + + // Switch initMagnEst to Q(minNorm-stages) + inst->initMagnEst[0] = WEBRTC_SPL_RSHIFT_U32(inst->initMagnEst[0], + right_shifts_in_initMagnEst); + inst->initMagnEst[inst->anaLen2] = + WEBRTC_SPL_RSHIFT_U32(inst->initMagnEst[inst->anaLen2], + right_shifts_in_initMagnEst); // Q(minNorm-stages) + + // Shift magnU16 to same domain as initMagnEst + tmpU32no1 = WEBRTC_SPL_RSHIFT_W32((WebRtc_UWord32)magnU16[0], + right_shifts_in_magnU16); // Q(minNorm-stages) + tmpU32no2 = WEBRTC_SPL_RSHIFT_W32((WebRtc_UWord32)magnU16[inst->anaLen2], + right_shifts_in_magnU16); // Q(minNorm-stages) + + // Update initMagnEst + inst->initMagnEst[0] += tmpU32no1; // Q(minNorm-stages) + inst->initMagnEst[inst->anaLen2] += tmpU32no2; // Q(minNorm-stages) + + log2 = 0; + if (magnU16[inst->anaLen2]) { + // Calculate log2(magnU16[inst->anaLen2]) + zeros = WebRtcSpl_NormU32((WebRtc_UWord32)magnU16[inst->anaLen2]); + frac = (WebRtc_Word16)((((WebRtc_UWord32)magnU16[inst->anaLen2] << zeros) & + 0x7FFFFFFF) >> 23); // Q8 + // log2(magnU16(i)) in Q8 + assert(frac < 256); + log2 = (WebRtc_Word16)(((31 - zeros) << 8) + WebRtcNsx_kLogTableFrac[frac]); + } + + sum_log_magn = (WebRtc_Word32)log2; // Q8 + // sum_log_i_log_magn in Q17 + sum_log_i_log_magn = (WEBRTC_SPL_MUL_16_16(kLogIndex[inst->anaLen2], log2) >> 3); + + for (i = 1, j = 2; i < inst->anaLen2; i += 1, j += 2) { + inst->real[i] = realImag[j]; + inst->imag[i] = -realImag[j + 1]; + // magnitude spectrum + // energy in Q(2*(normData-stages)) + tmpU32no1 = (WebRtc_UWord32)WEBRTC_SPL_MUL_16_16(realImag[j], realImag[j]); + tmpU32no1 += (WebRtc_UWord32)WEBRTC_SPL_MUL_16_16(realImag[j + 1], realImag[j + 1]); + inst->magnEnergy += tmpU32no1; // Q(2*(normData-stages)) + + magnU16[i] = (WebRtc_UWord16)WebRtcSpl_SqrtFloor(tmpU32no1); // Q(normData-stages) + inst->sumMagn += (WebRtc_UWord32)magnU16[i]; // Q(normData-stages) + + // Switch initMagnEst to Q(minNorm-stages) + inst->initMagnEst[i] = WEBRTC_SPL_RSHIFT_U32(inst->initMagnEst[i], + right_shifts_in_initMagnEst); + + // Shift magnU16 to same domain as initMagnEst, i.e., Q(minNorm-stages) + tmpU32no1 = WEBRTC_SPL_RSHIFT_W32((WebRtc_UWord32)magnU16[i], + right_shifts_in_magnU16); + // Update initMagnEst + inst->initMagnEst[i] += tmpU32no1; // Q(minNorm-stages) + + if (i >= kStartBand) { + // For pink noise estimation. Collect data neglecting lower frequency band + log2 = 0; + if (magnU16[i]) { + zeros = WebRtcSpl_NormU32((WebRtc_UWord32)magnU16[i]); + frac = (WebRtc_Word16)((((WebRtc_UWord32)magnU16[i] << zeros) & + 0x7FFFFFFF) >> 23); + // log2(magnU16(i)) in Q8 + assert(frac < 256); + log2 = (WebRtc_Word16)(((31 - zeros) << 8) + + WebRtcNsx_kLogTableFrac[frac]); + } + sum_log_magn += (WebRtc_Word32)log2; // Q8 + // sum_log_i_log_magn in Q17 + sum_log_i_log_magn += (WEBRTC_SPL_MUL_16_16(kLogIndex[i], log2) >> 3); + } + } + + // + //compute simplified noise model during startup + // + + // Estimate White noise + + // Switch whiteNoiseLevel to Q(minNorm-stages) + inst->whiteNoiseLevel = WEBRTC_SPL_RSHIFT_U32(inst->whiteNoiseLevel, + right_shifts_in_initMagnEst); + + // Update the average magnitude spectrum, used as noise estimate. + tmpU32no1 = WEBRTC_SPL_UMUL_32_16(inst->sumMagn, inst->overdrive); + tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, inst->stages + 8); + + // Replacing division above with 'stages' shifts + // Shift to same Q-domain as whiteNoiseLevel + tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, right_shifts_in_magnU16); + // This operation is safe from wrap around as long as END_STARTUP_SHORT < 128 + assert(END_STARTUP_SHORT < 128); + inst->whiteNoiseLevel += tmpU32no1; // Q(minNorm-stages) + + // Estimate Pink noise parameters + // Denominator used in both parameter estimates. + // The value is only dependent on the size of the frequency band (kStartBand) + // and to reduce computational complexity stored in a table (kDeterminantEstMatrix[]) + assert(kStartBand < 66); + matrix_determinant = kDeterminantEstMatrix[kStartBand]; // Q0 + sum_log_i = kSumLogIndex[kStartBand]; // Q5 + sum_log_i_square = kSumSquareLogIndex[kStartBand]; // Q2 + if (inst->fs == 8000) { + // Adjust values to shorter blocks in narrow band. + tmp_1_w32 = (WebRtc_Word32)matrix_determinant; + tmp_1_w32 += WEBRTC_SPL_MUL_16_16_RSFT(kSumLogIndex[65], sum_log_i, 9); + tmp_1_w32 -= WEBRTC_SPL_MUL_16_16_RSFT(kSumLogIndex[65], kSumLogIndex[65], 10); + tmp_1_w32 -= WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)sum_log_i_square, 4); + tmp_1_w32 -= WEBRTC_SPL_MUL_16_16_RSFT((WebRtc_Word16) + (inst->magnLen - kStartBand), kSumSquareLogIndex[65], 2); + matrix_determinant = (WebRtc_Word16)tmp_1_w32; + sum_log_i -= kSumLogIndex[65]; // Q5 + sum_log_i_square -= kSumSquareLogIndex[65]; // Q2 + } + + // Necessary number of shifts to fit sum_log_magn in a word16 + zeros = 16 - WebRtcSpl_NormW32(sum_log_magn); + if (zeros < 0) { + zeros = 0; + } + tmp_1_w32 = WEBRTC_SPL_LSHIFT_W32(sum_log_magn, 1); // Q9 + sum_log_magn_u16 = (WebRtc_UWord16)WEBRTC_SPL_RSHIFT_W32(tmp_1_w32, zeros);//Q(9-zeros) + + // Calculate and update pinkNoiseNumerator. Result in Q11. + tmp_2_w32 = WEBRTC_SPL_MUL_16_U16(sum_log_i_square, sum_log_magn_u16); // Q(11-zeros) + tmpU32no1 = WEBRTC_SPL_RSHIFT_U32((WebRtc_UWord32)sum_log_i_log_magn, 12); // Q5 + + // Shift the largest value of sum_log_i and tmp32no3 before multiplication + tmp_u16 = WEBRTC_SPL_LSHIFT_U16((WebRtc_UWord16)sum_log_i, 1); // Q6 + if ((WebRtc_UWord32)sum_log_i > tmpU32no1) { + tmp_u16 = WEBRTC_SPL_RSHIFT_U16(tmp_u16, zeros); + } else { + tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, zeros); + } + tmp_2_w32 -= (WebRtc_Word32)WEBRTC_SPL_UMUL_32_16(tmpU32no1, tmp_u16); // Q(11-zeros) + matrix_determinant = WEBRTC_SPL_RSHIFT_W16(matrix_determinant, zeros); // Q(-zeros) + tmp_2_w32 = WebRtcSpl_DivW32W16(tmp_2_w32, matrix_determinant); // Q11 + tmp_2_w32 += WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)net_norm, 11); // Q11 + if (tmp_2_w32 < 0) { + tmp_2_w32 = 0; + } + inst->pinkNoiseNumerator += tmp_2_w32; // Q11 + + // Calculate and update pinkNoiseExp. Result in Q14. + tmp_2_w32 = WEBRTC_SPL_MUL_16_U16(sum_log_i, sum_log_magn_u16); // Q(14-zeros) + tmp_1_w32 = WEBRTC_SPL_RSHIFT_W32(sum_log_i_log_magn, 3 + zeros); + tmp_1_w32 = WEBRTC_SPL_MUL((WebRtc_Word32)(inst->magnLen - kStartBand), + tmp_1_w32); + tmp_2_w32 -= tmp_1_w32; // Q(14-zeros) + if (tmp_2_w32 > 0) { + // If the exponential parameter is negative force it to zero, which means a + // flat spectrum. + tmp_1_w32 = WebRtcSpl_DivW32W16(tmp_2_w32, matrix_determinant); // Q14 + inst->pinkNoiseExp += WEBRTC_SPL_SAT(16384, tmp_1_w32, 0); // Q14 + } + } +} + +void WebRtcNsx_DataSynthesis(NsxInst_t* inst, short* outFrame) { + WebRtc_Word32 energyOut; + + WebRtc_Word16 realImag[ANAL_BLOCKL_MAX << 1]; + WebRtc_Word16 tmp16no1, tmp16no2; + WebRtc_Word16 energyRatio; + WebRtc_Word16 gainFactor, gainFactor1, gainFactor2; + + int i; + int outCIFFT; + int scaleEnergyOut = 0; + + if (inst->zeroInputSignal) { + // synthesize the special case of zero input + // read out fully processed segment + for (i = 0; i < inst->blockLen10ms; i++) { + outFrame[i] = inst->synthesisBuffer[i]; // Q0 + } + // update synthesis buffer + WEBRTC_SPL_MEMCPY_W16(inst->synthesisBuffer, + inst->synthesisBuffer + inst->blockLen10ms, + inst->anaLen - inst->blockLen10ms); + WebRtcSpl_ZerosArrayW16(inst->synthesisBuffer + inst->anaLen - inst->blockLen10ms, + inst->blockLen10ms); + return; + } + + // Filter the data in the frequency domain, and create spectrum. + WebRtcNsx_PrepareSpectrum(inst, realImag); + + // bit-reverse position of elements in array and IFFT it + WebRtcSpl_ComplexBitReverse(realImag, inst->stages); + outCIFFT = WebRtcSpl_ComplexIFFT(realImag, inst->stages, 1); + + // Denormalize. + WebRtcNsx_Denormalize(inst, realImag, outCIFFT); + + //scale factor: only do it after END_STARTUP_LONG time + gainFactor = 8192; // 8192 = Q13(1.0) + if (inst->gainMap == 1 && + inst->blockIndex > END_STARTUP_LONG && + inst->energyIn > 0) { + energyOut = WebRtcSpl_Energy(inst->real, (int)inst->anaLen, &scaleEnergyOut); // Q(-scaleEnergyOut) + if (scaleEnergyOut == 0 && !(energyOut & 0x7f800000)) { + energyOut = WEBRTC_SPL_SHIFT_W32(energyOut, 8 + scaleEnergyOut + - inst->scaleEnergyIn); + } else { + inst->energyIn = WEBRTC_SPL_RSHIFT_W32(inst->energyIn, 8 + scaleEnergyOut + - inst->scaleEnergyIn); // Q(-8-scaleEnergyOut) + } + + assert(inst->energyIn > 0); + energyRatio = (WebRtc_Word16)WEBRTC_SPL_DIV(energyOut + + WEBRTC_SPL_RSHIFT_W32(inst->energyIn, 1), inst->energyIn); // Q8 + // Limit the ratio to [0, 1] in Q8, i.e., [0, 256] + energyRatio = WEBRTC_SPL_SAT(256, energyRatio, 0); + + // all done in lookup tables now + assert(energyRatio < 257); + gainFactor1 = kFactor1Table[energyRatio]; // Q8 + gainFactor2 = inst->factor2Table[energyRatio]; // Q8 + + //combine both scales with speech/noise prob: note prior (priorSpeechProb) is not frequency dependent + + // factor = inst->priorSpeechProb*factor1 + (1.0-inst->priorSpeechProb)*factor2; // original code + tmp16no1 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(16384 - inst->priorNonSpeechProb, + gainFactor1, 14); // Q13 16384 = Q14(1.0) + tmp16no2 = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(inst->priorNonSpeechProb, + gainFactor2, 14); // Q13; + gainFactor = tmp16no1 + tmp16no2; // Q13 + } // out of flag_gain_map==1 + + // Synthesis, read out fully processed segment, and update synthesis buffer. + WebRtcNsx_SynthesisUpdate(inst, outFrame, gainFactor); +} + +int WebRtcNsx_ProcessCore(NsxInst_t* inst, short* speechFrame, short* speechFrameHB, + short* outFrame, short* outFrameHB) { + // main routine for noise suppression + + WebRtc_UWord32 tmpU32no1, tmpU32no2, tmpU32no3; + WebRtc_UWord32 satMax, maxNoiseU32; + WebRtc_UWord32 tmpMagnU32, tmpNoiseU32; + WebRtc_UWord32 nearMagnEst; + WebRtc_UWord32 noiseUpdateU32; + WebRtc_UWord32 noiseU32[HALF_ANAL_BLOCKL]; + WebRtc_UWord32 postLocSnr[HALF_ANAL_BLOCKL]; + WebRtc_UWord32 priorLocSnr[HALF_ANAL_BLOCKL]; + WebRtc_UWord32 prevNearSnr[HALF_ANAL_BLOCKL]; + WebRtc_UWord32 curNearSnr; + WebRtc_UWord32 priorSnr; + WebRtc_UWord32 noise_estimate = 0; + WebRtc_UWord32 noise_estimate_avg = 0; + WebRtc_UWord32 numerator = 0; + + WebRtc_Word32 tmp32no1, tmp32no2; + WebRtc_Word32 pink_noise_num_avg = 0; + + WebRtc_UWord16 tmpU16no1; + WebRtc_UWord16 magnU16[HALF_ANAL_BLOCKL]; + WebRtc_UWord16 prevNoiseU16[HALF_ANAL_BLOCKL]; + WebRtc_UWord16 nonSpeechProbFinal[HALF_ANAL_BLOCKL]; + WebRtc_UWord16 gammaNoise, prevGammaNoise; + WebRtc_UWord16 noiseSupFilterTmp[HALF_ANAL_BLOCKL]; + + WebRtc_Word16 qMagn, qNoise; + WebRtc_Word16 avgProbSpeechHB, gainModHB, avgFilterGainHB, gainTimeDomainHB; + WebRtc_Word16 pink_noise_exp_avg = 0; + + int i; + int nShifts, postShifts; + int norm32no1, norm32no2; + int flag, sign; + int q_domain_to_use = 0; + + // Code for ARMv7-Neon platform assumes the following: + assert(inst->anaLen % 16 == 0); + assert(inst->anaLen2 % 8 == 0); + assert(inst->blockLen10ms % 16 == 0); + assert(inst->magnLen == inst->anaLen2 + 1); + +#ifdef NS_FILEDEBUG + fwrite(spframe, sizeof(short), inst->blockLen10ms, inst->infile); +#endif + + // Check that initialization has been done + if (inst->initFlag != 1) { + return -1; + } + // Check for valid pointers based on sampling rate + if ((inst->fs == 32000) && (speechFrameHB == NULL)) { + return -1; + } + + // Store speechFrame and transform to frequency domain + WebRtcNsx_DataAnalysis(inst, speechFrame, magnU16); + + if (inst->zeroInputSignal) { + WebRtcNsx_DataSynthesis(inst, outFrame); + + if (inst->fs == 32000) { + // update analysis buffer for H band + // append new data to buffer FX + WEBRTC_SPL_MEMCPY_W16(inst->dataBufHBFX, inst->dataBufHBFX + inst->blockLen10ms, + inst->anaLen - inst->blockLen10ms); + WEBRTC_SPL_MEMCPY_W16(inst->dataBufHBFX + inst->anaLen - inst->blockLen10ms, + speechFrameHB, inst->blockLen10ms); + for (i = 0; i < inst->blockLen10ms; i++) { + outFrameHB[i] = inst->dataBufHBFX[i]; // Q0 + } + } // end of H band gain computation + return 0; + } + + // Update block index when we have something to process + inst->blockIndex++; + // + + // Norm of magn + qMagn = inst->normData - inst->stages; + + // Compute spectral flatness on input spectrum + WebRtcNsx_ComputeSpectralFlatness(inst, magnU16); + + // quantile noise estimate + WebRtcNsx_NoiseEstimation(inst, magnU16, noiseU32, &qNoise); + + //noise estimate from previous frame + for (i = 0; i < inst->magnLen; i++) { + prevNoiseU16[i] = (WebRtc_UWord16)WEBRTC_SPL_RSHIFT_U32(inst->prevNoiseU32[i], 11); // Q(prevQNoise) + } + + if (inst->blockIndex < END_STARTUP_SHORT) { + // Noise Q-domain to be used later; see description at end of section. + q_domain_to_use = WEBRTC_SPL_MIN((int)qNoise, inst->minNorm - inst->stages); + + // Calculate frequency independent parts in parametric noise estimate and calculate + // the estimate for the lower frequency band (same values for all frequency bins) + if (inst->pinkNoiseExp) { + pink_noise_exp_avg = (WebRtc_Word16)WebRtcSpl_DivW32W16(inst->pinkNoiseExp, + (WebRtc_Word16)(inst->blockIndex + 1)); // Q14 + pink_noise_num_avg = WebRtcSpl_DivW32W16(inst->pinkNoiseNumerator, + (WebRtc_Word16)(inst->blockIndex + 1)); // Q11 + WebRtcNsx_CalcParametricNoiseEstimate(inst, + pink_noise_exp_avg, + pink_noise_num_avg, + kStartBand, + &noise_estimate, + &noise_estimate_avg); + } else { + // Use white noise estimate if we have poor pink noise parameter estimates + noise_estimate = inst->whiteNoiseLevel; // Q(minNorm-stages) + noise_estimate_avg = noise_estimate / (inst->blockIndex + 1); // Q(minNorm-stages) + } + for (i = 0; i < inst->magnLen; i++) { + // Estimate the background noise using the pink noise parameters if permitted + if ((inst->pinkNoiseExp) && (i >= kStartBand)) { + // Reset noise_estimate + noise_estimate = 0; + noise_estimate_avg = 0; + // Calculate the parametric noise estimate for current frequency bin + WebRtcNsx_CalcParametricNoiseEstimate(inst, + pink_noise_exp_avg, + pink_noise_num_avg, + i, + &noise_estimate, + &noise_estimate_avg); + } + // Calculate parametric Wiener filter + noiseSupFilterTmp[i] = inst->denoiseBound; + if (inst->initMagnEst[i]) { + // numerator = (initMagnEst - noise_estimate * overdrive) + // Result in Q(8+minNorm-stages) + tmpU32no1 = WEBRTC_SPL_UMUL_32_16(noise_estimate, inst->overdrive); + numerator = WEBRTC_SPL_LSHIFT_U32(inst->initMagnEst[i], 8); + if (numerator > tmpU32no1) { + // Suppression filter coefficient larger than zero, so calculate. + numerator -= tmpU32no1; + + // Determine number of left shifts in numerator for best accuracy after + // division + nShifts = WebRtcSpl_NormU32(numerator); + nShifts = WEBRTC_SPL_SAT(6, nShifts, 0); + + // Shift numerator to Q(nShifts+8+minNorm-stages) + numerator = WEBRTC_SPL_LSHIFT_U32(numerator, nShifts); + + // Shift denominator to Q(nShifts-6+minNorm-stages) + tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(inst->initMagnEst[i], 6 - nShifts); + if (tmpU32no1 == 0) { + // This is only possible if numerator = 0, in which case + // we don't need any division. + tmpU32no1 = 1; + } + tmpU32no2 = WEBRTC_SPL_UDIV(numerator, tmpU32no1); // Q14 + noiseSupFilterTmp[i] = (WebRtc_UWord16)WEBRTC_SPL_SAT(16384, tmpU32no2, + (WebRtc_UWord32)(inst->denoiseBound)); // Q14 + } + } + // Weight quantile noise 'noiseU32' with modeled noise 'noise_estimate_avg' + // 'noiseU32 is in Q(qNoise) and 'noise_estimate' in Q(minNorm-stages) + // To guarantee that we do not get wrap around when shifting to the same domain + // we use the lowest one. Furthermore, we need to save 6 bits for the weighting. + // 'noise_estimate_avg' can handle this operation by construction, but 'noiseU32' + // may not. + + // Shift 'noiseU32' to 'q_domain_to_use' + tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(noiseU32[i], (int)qNoise - q_domain_to_use); + // Shift 'noise_estimate_avg' to 'q_domain_to_use' + tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(noise_estimate_avg, inst->minNorm - inst->stages + - q_domain_to_use); + // Make a simple check to see if we have enough room for weighting 'tmpU32no1' + // without wrap around + nShifts = 0; + if (tmpU32no1 & 0xfc000000) { + tmpU32no1 = WEBRTC_SPL_RSHIFT_U32(tmpU32no1, 6); + tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(tmpU32no2, 6); + nShifts = 6; + } + tmpU32no1 *= inst->blockIndex; + tmpU32no2 *= (END_STARTUP_SHORT - inst->blockIndex); + // Add them together and divide by startup length + noiseU32[i] = WebRtcSpl_DivU32U16(tmpU32no1 + tmpU32no2, END_STARTUP_SHORT); + // Shift back if necessary + noiseU32[i] = WEBRTC_SPL_LSHIFT_U32(noiseU32[i], nShifts); + } + // Update new Q-domain for 'noiseU32' + qNoise = q_domain_to_use; + } + // compute average signal during END_STARTUP_LONG time: + // used to normalize spectral difference measure + if (inst->blockIndex < END_STARTUP_LONG) { + // substituting division with shift ending up in Q(-2*stages) + inst->timeAvgMagnEnergyTmp + += WEBRTC_SPL_RSHIFT_U32(inst->magnEnergy, + 2 * inst->normData + inst->stages - 1); + inst->timeAvgMagnEnergy = WebRtcSpl_DivU32U16(inst->timeAvgMagnEnergyTmp, + inst->blockIndex + 1); + } + + //start processing at frames == converged+1 + // STEP 1: compute prior and post SNR based on quantile noise estimates + + // compute direct decision (DD) estimate of prior SNR: needed for new method + satMax = (WebRtc_UWord32)1048575;// Largest possible value without getting overflow despite shifting 12 steps + postShifts = 6 + qMagn - qNoise; + nShifts = 5 - inst->prevQMagn + inst->prevQNoise; + for (i = 0; i < inst->magnLen; i++) { + // FLOAT: + // post SNR + // postLocSnr[i] = 0.0; + // if (magn[i] > noise[i]) + // { + // postLocSnr[i] = magn[i] / (noise[i] + 0.0001); + // } + // // previous post SNR + // // previous estimate: based on previous frame with gain filter (smooth is previous filter) + // + // prevNearSnr[i] = inst->prevMagnU16[i] / (inst->noisePrev[i] + 0.0001) * (inst->smooth[i]); + // + // // DD estimate is sum of two terms: current estimate and previous estimate + // // directed decision update of priorSnr (or we actually store [2*priorSnr+1]) + // + // priorLocSnr[i] = DD_PR_SNR * prevNearSnr[i] + (1.0 - DD_PR_SNR) * (postLocSnr[i] - 1.0); + + // calculate post SNR: output in Q11 + postLocSnr[i] = 2048; // 1.0 in Q11 + tmpU32no1 = WEBRTC_SPL_LSHIFT_U32((WebRtc_UWord32)magnU16[i], 6); // Q(6+qMagn) + if (postShifts < 0) { + tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(noiseU32[i], -postShifts); // Q(6+qMagn) + } else { + tmpU32no2 = WEBRTC_SPL_LSHIFT_U32(noiseU32[i], postShifts); // Q(6+qMagn) + } + if (tmpU32no1 > tmpU32no2) { + // Current magnitude larger than noise + tmpU32no1 = WEBRTC_SPL_LSHIFT_U32(tmpU32no1, 11); // Q(17+qMagn) + if (tmpU32no2 > 0) { + tmpU32no1 = WEBRTC_SPL_UDIV(tmpU32no1, tmpU32no2); // Q11 + postLocSnr[i] = WEBRTC_SPL_MIN(satMax, tmpU32no1); // Q11 + } else { + postLocSnr[i] = satMax; + } + } + + // calculate prevNearSnr[i] and save for later instead of recalculating it later + nearMagnEst = WEBRTC_SPL_UMUL_16_16(inst->prevMagnU16[i], inst->noiseSupFilter[i]); // Q(prevQMagn+14) + tmpU32no1 = WEBRTC_SPL_LSHIFT_U32(nearMagnEst, 3); // Q(prevQMagn+17) + tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(inst->prevNoiseU32[i], nShifts); // Q(prevQMagn+6) + + if (tmpU32no2 > 0) { + tmpU32no1 = WEBRTC_SPL_UDIV(tmpU32no1, tmpU32no2); // Q11 + tmpU32no1 = WEBRTC_SPL_MIN(satMax, tmpU32no1); // Q11 + } else { + tmpU32no1 = satMax; // Q11 + } + prevNearSnr[i] = tmpU32no1; // Q11 + + //directed decision update of priorSnr + tmpU32no1 = WEBRTC_SPL_UMUL_32_16(prevNearSnr[i], DD_PR_SNR_Q11); // Q22 + tmpU32no2 = WEBRTC_SPL_UMUL_32_16(postLocSnr[i] - 2048, ONE_MINUS_DD_PR_SNR_Q11); // Q22 + priorSnr = tmpU32no1 + tmpU32no2 + 512; // Q22 (added 512 for rounding) + // priorLocSnr = 1 + 2*priorSnr + priorLocSnr[i] = 2048 + WEBRTC_SPL_RSHIFT_U32(priorSnr, 10); // Q11 + } // end of loop over frequencies + // done with step 1: DD computation of prior and post SNR + + // STEP 2: compute speech/noise likelihood + + //compute difference of input spectrum with learned/estimated noise spectrum + WebRtcNsx_ComputeSpectralDifference(inst, magnU16); + //compute histograms for determination of parameters (thresholds and weights for features) + //parameters are extracted once every window time (=inst->modelUpdate) + //counter update + inst->cntThresUpdate++; + flag = (int)(inst->cntThresUpdate == inst->modelUpdate); + //update histogram + WebRtcNsx_FeatureParameterExtraction(inst, flag); + //compute model parameters + if (flag) { + inst->cntThresUpdate = 0; // Reset counter + //update every window: + // get normalization for spectral difference for next window estimate + + // Shift to Q(-2*stages) + inst->curAvgMagnEnergy = WEBRTC_SPL_RSHIFT_U32(inst->curAvgMagnEnergy, STAT_UPDATES); + + tmpU32no1 = (inst->curAvgMagnEnergy + inst->timeAvgMagnEnergy + 1) >> 1; //Q(-2*stages) + // Update featureSpecDiff + if ((tmpU32no1 != inst->timeAvgMagnEnergy) && (inst->featureSpecDiff) && + (inst->timeAvgMagnEnergy > 0)) { + norm32no1 = 0; + tmpU32no3 = tmpU32no1; + while (0xFFFF0000 & tmpU32no3) { + tmpU32no3 >>= 1; + norm32no1++; + } + tmpU32no2 = inst->featureSpecDiff; + while (0xFFFF0000 & tmpU32no2) { + tmpU32no2 >>= 1; + norm32no1++; + } + tmpU32no3 = WEBRTC_SPL_UMUL(tmpU32no3, tmpU32no2); + tmpU32no3 = WEBRTC_SPL_UDIV(tmpU32no3, inst->timeAvgMagnEnergy); + if (WebRtcSpl_NormU32(tmpU32no3) < norm32no1) { + inst->featureSpecDiff = 0x007FFFFF; + } else { + inst->featureSpecDiff = WEBRTC_SPL_MIN(0x007FFFFF, + WEBRTC_SPL_LSHIFT_U32(tmpU32no3, norm32no1)); + } + } + + inst->timeAvgMagnEnergy = tmpU32no1; // Q(-2*stages) + inst->curAvgMagnEnergy = 0; + } + + //compute speech/noise probability + WebRtcNsx_SpeechNoiseProb(inst, nonSpeechProbFinal, priorLocSnr, postLocSnr); + + //time-avg parameter for noise update + gammaNoise = NOISE_UPDATE_Q8; // Q8 + + maxNoiseU32 = 0; + postShifts = inst->prevQNoise - qMagn; + nShifts = inst->prevQMagn - qMagn; + for (i = 0; i < inst->magnLen; i++) { + // temporary noise update: use it for speech frames if update value is less than previous + // the formula has been rewritten into: + // noiseUpdate = noisePrev[i] + (1 - gammaNoise) * nonSpeechProb * (magn[i] - noisePrev[i]) + + if (postShifts < 0) { + tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(magnU16[i], -postShifts); // Q(prevQNoise) + } else { + tmpU32no2 = WEBRTC_SPL_LSHIFT_U32(magnU16[i], postShifts); // Q(prevQNoise) + } + if (prevNoiseU16[i] > tmpU32no2) { + sign = -1; + tmpU32no1 = prevNoiseU16[i] - tmpU32no2; + } else { + sign = 1; + tmpU32no1 = tmpU32no2 - prevNoiseU16[i]; + } + noiseUpdateU32 = inst->prevNoiseU32[i]; // Q(prevQNoise+11) + tmpU32no3 = 0; + if ((tmpU32no1) && (nonSpeechProbFinal[i])) { + // This value will be used later, if gammaNoise changes + tmpU32no3 = WEBRTC_SPL_UMUL_32_16(tmpU32no1, nonSpeechProbFinal[i]); // Q(prevQNoise+8) + if (0x7c000000 & tmpU32no3) { + // Shifting required before multiplication + tmpU32no2 + = WEBRTC_SPL_UMUL_32_16(WEBRTC_SPL_RSHIFT_U32(tmpU32no3, 5), gammaNoise); // Q(prevQNoise+11) + } else { + // We can do shifting after multiplication + tmpU32no2 + = WEBRTC_SPL_RSHIFT_U32(WEBRTC_SPL_UMUL_32_16(tmpU32no3, gammaNoise), 5); // Q(prevQNoise+11) + } + if (sign > 0) { + noiseUpdateU32 += tmpU32no2; // Q(prevQNoise+11) + } else { + // This operation is safe. We can never get wrap around, since worst + // case scenario means magnU16 = 0 + noiseUpdateU32 -= tmpU32no2; // Q(prevQNoise+11) + } + } + + //increase gamma (i.e., less noise update) for frame likely to be speech + prevGammaNoise = gammaNoise; + gammaNoise = NOISE_UPDATE_Q8; + //time-constant based on speech/noise state + //increase gamma (i.e., less noise update) for frames likely to be speech + if (nonSpeechProbFinal[i] < ONE_MINUS_PROB_RANGE_Q8) { + gammaNoise = GAMMA_NOISE_TRANS_AND_SPEECH_Q8; + } + + if (prevGammaNoise != gammaNoise) { + // new noise update + // this line is the same as above, only that the result is stored in a different variable and the gammaNoise + // has changed + // + // noiseUpdate = noisePrev[i] + (1 - gammaNoise) * nonSpeechProb * (magn[i] - noisePrev[i]) + + if (0x7c000000 & tmpU32no3) { + // Shifting required before multiplication + tmpU32no2 + = WEBRTC_SPL_UMUL_32_16(WEBRTC_SPL_RSHIFT_U32(tmpU32no3, 5), gammaNoise); // Q(prevQNoise+11) + } else { + // We can do shifting after multiplication + tmpU32no2 + = WEBRTC_SPL_RSHIFT_U32(WEBRTC_SPL_UMUL_32_16(tmpU32no3, gammaNoise), 5); // Q(prevQNoise+11) + } + if (sign > 0) { + tmpU32no1 = inst->prevNoiseU32[i] + tmpU32no2; // Q(prevQNoise+11) + } else { + tmpU32no1 = inst->prevNoiseU32[i] - tmpU32no2; // Q(prevQNoise+11) + } + if (noiseUpdateU32 > tmpU32no1) { + noiseUpdateU32 = tmpU32no1; // Q(prevQNoise+11) + } + } + noiseU32[i] = noiseUpdateU32; // Q(prevQNoise+11) + if (noiseUpdateU32 > maxNoiseU32) { + maxNoiseU32 = noiseUpdateU32; + } + + // conservative noise update + // // original FLOAT code + // if (prob_speech < PROB_RANGE) { + // inst->avgMagnPause[i] = inst->avgMagnPause[i] + (1.0 - gamma_pause)*(magn[i] - inst->avgMagnPause[i]); + // } + + tmp32no2 = WEBRTC_SPL_SHIFT_W32(inst->avgMagnPause[i], -nShifts); + if (nonSpeechProbFinal[i] > ONE_MINUS_PROB_RANGE_Q8) { + if (nShifts < 0) { + tmp32no1 = (WebRtc_Word32)magnU16[i] - tmp32no2; // Q(qMagn) + tmp32no1 = WEBRTC_SPL_MUL_32_16(tmp32no1, ONE_MINUS_GAMMA_PAUSE_Q8); // Q(8+prevQMagn+nShifts) + tmp32no1 = WEBRTC_SPL_RSHIFT_W32(tmp32no1 + 128, 8); // Q(qMagn) + } else { + tmp32no1 = WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)magnU16[i], nShifts) + - inst->avgMagnPause[i]; // Q(qMagn+nShifts) + tmp32no1 = WEBRTC_SPL_MUL_32_16(tmp32no1, ONE_MINUS_GAMMA_PAUSE_Q8); // Q(8+prevQMagn+nShifts) + tmp32no1 = WEBRTC_SPL_RSHIFT_W32(tmp32no1 + (128 << nShifts), 8 + nShifts); // Q(qMagn) + } + tmp32no2 += tmp32no1; // Q(qMagn) + } + inst->avgMagnPause[i] = tmp32no2; + } // end of frequency loop + + norm32no1 = WebRtcSpl_NormU32(maxNoiseU32); + qNoise = inst->prevQNoise + norm32no1 - 5; + // done with step 2: noise update + + // STEP 3: compute dd update of prior snr and post snr based on new noise estimate + nShifts = inst->prevQNoise + 11 - qMagn; + for (i = 0; i < inst->magnLen; i++) { + // FLOAT code + // // post and prior SNR + // curNearSnr = 0.0; + // if (magn[i] > noise[i]) + // { + // curNearSnr = magn[i] / (noise[i] + 0.0001) - 1.0; + // } + // // DD estimate is sum of two terms: current estimate and previous estimate + // // directed decision update of snrPrior + // snrPrior = DD_PR_SNR * prevNearSnr[i] + (1.0 - DD_PR_SNR) * curNearSnr; + // // gain filter + // tmpFloat1 = inst->overdrive + snrPrior; + // tmpFloat2 = snrPrior / tmpFloat1; + // theFilter[i] = tmpFloat2; + + // calculate curNearSnr again, this is necessary because a new noise estimate has been made since then. for the original + curNearSnr = 0; // Q11 + if (nShifts < 0) { + // This case is equivalent with magn < noise which implies curNearSnr = 0; + tmpMagnU32 = (WebRtc_UWord32)magnU16[i]; // Q(qMagn) + tmpNoiseU32 = WEBRTC_SPL_LSHIFT_U32(noiseU32[i], -nShifts); // Q(qMagn) + } else if (nShifts > 17) { + tmpMagnU32 = WEBRTC_SPL_LSHIFT_U32(magnU16[i], 17); // Q(qMagn+17) + tmpNoiseU32 = WEBRTC_SPL_RSHIFT_U32(noiseU32[i], nShifts - 17); // Q(qMagn+17) + } else { + tmpMagnU32 = WEBRTC_SPL_LSHIFT_U32((WebRtc_UWord32)magnU16[i], nShifts); // Q(qNoise_prev+11) + tmpNoiseU32 = noiseU32[i]; // Q(qNoise_prev+11) + } + if (tmpMagnU32 > tmpNoiseU32) { + tmpU32no1 = tmpMagnU32 - tmpNoiseU32; // Q(qCur) + norm32no2 = WEBRTC_SPL_MIN(11, WebRtcSpl_NormU32(tmpU32no1)); + tmpU32no1 = WEBRTC_SPL_LSHIFT_U32(tmpU32no1, norm32no2); // Q(qCur+norm32no2) + tmpU32no2 = WEBRTC_SPL_RSHIFT_U32(tmpNoiseU32, 11 - norm32no2); // Q(qCur+norm32no2-11) + if (tmpU32no2 > 0) { + tmpU32no1 = WEBRTC_SPL_UDIV(tmpU32no1, tmpU32no2); // Q11 + } + curNearSnr = WEBRTC_SPL_MIN(satMax, tmpU32no1); // Q11 + } + + //directed decision update of priorSnr + // FLOAT + // priorSnr = DD_PR_SNR * prevNearSnr + (1.0-DD_PR_SNR) * curNearSnr; + + tmpU32no1 = WEBRTC_SPL_UMUL_32_16(prevNearSnr[i], DD_PR_SNR_Q11); // Q22 + tmpU32no2 = WEBRTC_SPL_UMUL_32_16(curNearSnr, ONE_MINUS_DD_PR_SNR_Q11); // Q22 + priorSnr = tmpU32no1 + tmpU32no2; // Q22 + + //gain filter + tmpU32no1 = (WebRtc_UWord32)(inst->overdrive) + + WEBRTC_SPL_RSHIFT_U32(priorSnr + 8192, 14); // Q8 + assert(inst->overdrive > 0); + tmpU16no1 = (WebRtc_UWord16)WEBRTC_SPL_UDIV(priorSnr + (tmpU32no1 >> 1), tmpU32no1); // Q14 + inst->noiseSupFilter[i] = WEBRTC_SPL_SAT(16384, tmpU16no1, inst->denoiseBound); // 16384 = Q14(1.0) // Q14 + + // Weight in the parametric Wiener filter during startup + if (inst->blockIndex < END_STARTUP_SHORT) { + // Weight the two suppression filters + tmpU32no1 = WEBRTC_SPL_UMUL_16_16(inst->noiseSupFilter[i], + (WebRtc_UWord16)inst->blockIndex); + tmpU32no2 = WEBRTC_SPL_UMUL_16_16(noiseSupFilterTmp[i], + (WebRtc_UWord16)(END_STARTUP_SHORT + - inst->blockIndex)); + tmpU32no1 += tmpU32no2; + inst->noiseSupFilter[i] = (WebRtc_UWord16)WebRtcSpl_DivU32U16(tmpU32no1, + END_STARTUP_SHORT); + } + } // end of loop over frequencies + //done with step3 + + // save noise and magnitude spectrum for next frame + inst->prevQNoise = qNoise; + inst->prevQMagn = qMagn; + if (norm32no1 > 5) { + for (i = 0; i < inst->magnLen; i++) { + inst->prevNoiseU32[i] = WEBRTC_SPL_LSHIFT_U32(noiseU32[i], norm32no1 - 5); // Q(qNoise+11) + inst->prevMagnU16[i] = magnU16[i]; // Q(qMagn) + } + } else { + for (i = 0; i < inst->magnLen; i++) { + inst->prevNoiseU32[i] = WEBRTC_SPL_RSHIFT_U32(noiseU32[i], 5 - norm32no1); // Q(qNoise+11) + inst->prevMagnU16[i] = magnU16[i]; // Q(qMagn) + } + } + + WebRtcNsx_DataSynthesis(inst, outFrame); +#ifdef NS_FILEDEBUG + fwrite(outframe, sizeof(short), inst->blockLen10ms, inst->outfile); +#endif + + //for H band: + // only update data buffer, then apply time-domain gain is applied derived from L band + if (inst->fs == 32000) { + // update analysis buffer for H band + // append new data to buffer FX + WEBRTC_SPL_MEMCPY_W16(inst->dataBufHBFX, inst->dataBufHBFX + inst->blockLen10ms, inst->anaLen - inst->blockLen10ms); + WEBRTC_SPL_MEMCPY_W16(inst->dataBufHBFX + inst->anaLen - inst->blockLen10ms, speechFrameHB, inst->blockLen10ms); + // range for averaging low band quantities for H band gain + + gainTimeDomainHB = 16384; // 16384 = Q14(1.0) + //average speech prob from low band + //average filter gain from low band + //avg over second half (i.e., 4->8kHz) of freq. spectrum + tmpU32no1 = 0; // Q12 + tmpU16no1 = 0; // Q8 + for (i = inst->anaLen2 - (inst->anaLen2 >> 2); i < inst->anaLen2; i++) { + tmpU16no1 += nonSpeechProbFinal[i]; // Q8 + tmpU32no1 += (WebRtc_UWord32)(inst->noiseSupFilter[i]); // Q14 + } + avgProbSpeechHB = (WebRtc_Word16)(4096 + - WEBRTC_SPL_RSHIFT_U16(tmpU16no1, inst->stages - 7)); // Q12 + avgFilterGainHB = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_U32( + tmpU32no1, inst->stages - 3); // Q14 + + // // original FLOAT code + // // gain based on speech probability: + // avg_prob_speech_tt=(float)2.0*avg_prob_speech-(float)1.0; + // gain_mod=(float)0.5*((float)1.0+(float)tanh(avg_prob_speech_tt)); // between 0 and 1 + + // gain based on speech probability: + // original expression: "0.5 * (1 + tanh(2x-1))" + // avgProbSpeechHB has been anyway saturated to a value between 0 and 1 so the other cases don't have to be dealt with + // avgProbSpeechHB and gainModHB are in Q12, 3607 = Q12(0.880615234375) which is a zero point of + // |0.5 * (1 + tanh(2x-1)) - x| - |0.5 * (1 + tanh(2x-1)) - 0.880615234375| meaning that from that point the error of approximating + // the expression with f(x) = x would be greater than the error of approximating the expression with f(x) = 0.880615234375 + // error: "|0.5 * (1 + tanh(2x-1)) - x| from x=0 to 0.880615234375" -> http://www.wolframalpha.com/input/?i=|0.5+*+(1+%2B+tanh(2x-1))+-+x|+from+x%3D0+to+0.880615234375 + // and: "|0.5 * (1 + tanh(2x-1)) - 0.880615234375| from x=0.880615234375 to 1" -> http://www.wolframalpha.com/input/?i=+|0.5+*+(1+%2B+tanh(2x-1))+-+0.880615234375|+from+x%3D0.880615234375+to+1 + gainModHB = WEBRTC_SPL_MIN(avgProbSpeechHB, 3607); + + // // original FLOAT code + // //combine gain with low band gain + // if (avg_prob_speech < (float)0.5) { + // gain_time_domain_HB=(float)0.5*gain_mod+(float)0.5*avg_filter_gain; + // } + // else { + // gain_time_domain_HB=(float)0.25*gain_mod+(float)0.75*avg_filter_gain; + // } + + + //combine gain with low band gain + if (avgProbSpeechHB < 2048) { + // 2048 = Q12(0.5) + // the next two lines in float are "gain_time_domain = 0.5 * gain_mod + 0.5 * avg_filter_gain"; Q2(0.5) = 2 equals one left shift + gainTimeDomainHB = (gainModHB << 1) + (avgFilterGainHB >> 1); // Q14 + } else { + // "gain_time_domain = 0.25 * gain_mod + 0.75 * agv_filter_gain;" + gainTimeDomainHB = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(3, avgFilterGainHB, 2); // 3 = Q2(0.75); Q14 + gainTimeDomainHB += gainModHB; // Q14 + } + //make sure gain is within flooring range + gainTimeDomainHB + = WEBRTC_SPL_SAT(16384, gainTimeDomainHB, (WebRtc_Word16)(inst->denoiseBound)); // 16384 = Q14(1.0) + + + //apply gain + for (i = 0; i < inst->blockLen10ms; i++) { + outFrameHB[i] + = (WebRtc_Word16)WEBRTC_SPL_MUL_16_16_RSFT(gainTimeDomainHB, inst->dataBufHBFX[i], 14); // Q0 + } + } // end of H band gain computation + + return 0; +} + + diff --git a/libs/miniwebrtc/audio/processing/ns/nsx_core.h b/libs/miniwebrtc/audio/processing/ns/nsx_core.h new file mode 100644 index 00000000..0a0faf98 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/ns/nsx_core.h @@ -0,0 +1,222 @@ +/* + * 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_PROCESSING_NS_MAIN_SOURCE_NSX_CORE_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_NSX_CORE_H_ + +#include "typedefs.h" +#include "signal_processing_library.h" + +#include "nsx_defines.h" + +#ifdef NS_FILEDEBUG +#include +#endif + +typedef struct NsxInst_t_ { + WebRtc_UWord32 fs; + + const WebRtc_Word16* window; + WebRtc_Word16 analysisBuffer[ANAL_BLOCKL_MAX]; + WebRtc_Word16 synthesisBuffer[ANAL_BLOCKL_MAX]; + WebRtc_UWord16 noiseSupFilter[HALF_ANAL_BLOCKL]; + WebRtc_UWord16 overdrive; /* Q8 */ + WebRtc_UWord16 denoiseBound; /* Q14 */ + const WebRtc_Word16* factor2Table; + WebRtc_Word16 noiseEstLogQuantile[SIMULT* HALF_ANAL_BLOCKL]; + WebRtc_Word16 noiseEstDensity[SIMULT* HALF_ANAL_BLOCKL]; + WebRtc_Word16 noiseEstCounter[SIMULT]; + WebRtc_Word16 noiseEstQuantile[HALF_ANAL_BLOCKL]; + + WebRtc_Word16 anaLen; + int anaLen2; + int magnLen; + int aggrMode; + int stages; + int initFlag; + int gainMap; + + WebRtc_Word32 maxLrt; + WebRtc_Word32 minLrt; + WebRtc_Word32 logLrtTimeAvgW32[HALF_ANAL_BLOCKL]; //log lrt factor with time-smoothing in Q8 + WebRtc_Word32 featureLogLrt; + WebRtc_Word32 thresholdLogLrt; + WebRtc_Word16 weightLogLrt; + + WebRtc_UWord32 featureSpecDiff; + WebRtc_UWord32 thresholdSpecDiff; + WebRtc_Word16 weightSpecDiff; + + WebRtc_UWord32 featureSpecFlat; + WebRtc_UWord32 thresholdSpecFlat; + WebRtc_Word16 weightSpecFlat; + + WebRtc_Word32 avgMagnPause[HALF_ANAL_BLOCKL]; //conservative estimate of noise spectrum + WebRtc_UWord32 magnEnergy; + WebRtc_UWord32 sumMagn; + WebRtc_UWord32 curAvgMagnEnergy; + WebRtc_UWord32 timeAvgMagnEnergy; + WebRtc_UWord32 timeAvgMagnEnergyTmp; + + WebRtc_UWord32 whiteNoiseLevel; //initial noise estimate + WebRtc_UWord32 initMagnEst[HALF_ANAL_BLOCKL];//initial magnitude spectrum estimate + WebRtc_Word32 pinkNoiseNumerator; //pink noise parameter: numerator + WebRtc_Word32 pinkNoiseExp; //pink noise parameter: power of freq + int minNorm; //smallest normalization factor + int zeroInputSignal; //zero input signal flag + + WebRtc_UWord32 prevNoiseU32[HALF_ANAL_BLOCKL]; //noise spectrum from previous frame + WebRtc_UWord16 prevMagnU16[HALF_ANAL_BLOCKL]; //magnitude spectrum from previous frame + WebRtc_Word16 priorNonSpeechProb; //prior speech/noise probability // Q14 + + int blockIndex; //frame index counter + int modelUpdate; //parameter for updating or estimating thresholds/weights for prior model + int cntThresUpdate; + + //histograms for parameter estimation + WebRtc_Word16 histLrt[HIST_PAR_EST]; + WebRtc_Word16 histSpecFlat[HIST_PAR_EST]; + WebRtc_Word16 histSpecDiff[HIST_PAR_EST]; + + //quantities for high band estimate + WebRtc_Word16 dataBufHBFX[ANAL_BLOCKL_MAX]; /* Q0 */ + + int qNoise; + int prevQNoise; + int prevQMagn; + int blockLen10ms; + + WebRtc_Word16 real[ANAL_BLOCKL_MAX]; + WebRtc_Word16 imag[ANAL_BLOCKL_MAX]; + WebRtc_Word32 energyIn; + int scaleEnergyIn; + int normData; + +} NsxInst_t; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/**************************************************************************** + * WebRtcNsx_InitCore(...) + * + * This function initializes a noise suppression instance + * + * Input: + * - inst : Instance that should be initialized + * - fs : Sampling frequency + * + * Output: + * - inst : Initialized instance + * + * Return value : 0 - Ok + * -1 - Error + */ +WebRtc_Word32 WebRtcNsx_InitCore(NsxInst_t* inst, WebRtc_UWord32 fs); + +/**************************************************************************** + * WebRtcNsx_set_policy_core(...) + * + * This changes the aggressiveness of the noise suppression method. + * + * Input: + * - inst : Instance that should be initialized + * - mode : 0: Mild (6 dB), 1: Medium (10 dB), 2: Aggressive (15 dB) + * + * Output: + * - inst : Initialized instance + * + * Return value : 0 - Ok + * -1 - Error + */ +int WebRtcNsx_set_policy_core(NsxInst_t* inst, int mode); + +/**************************************************************************** + * WebRtcNsx_ProcessCore + * + * Do noise suppression. + * + * Input: + * - inst : Instance that should be initialized + * - inFrameLow : Input speech frame for lower band + * - inFrameHigh : Input speech frame for higher band + * + * Output: + * - inst : Updated instance + * - outFrameLow : Output speech frame for lower band + * - outFrameHigh : Output speech frame for higher band + * + * Return value : 0 - OK + * -1 - Error + */ +int WebRtcNsx_ProcessCore(NsxInst_t* inst, + short* inFrameLow, + short* inFrameHigh, + short* outFrameLow, + short* outFrameHigh); + +/**************************************************************************** + * Some function pointers, for internal functions shared by ARM NEON and + * generic C code. + */ +// Noise Estimation. +typedef void (*NoiseEstimation)(NsxInst_t* inst, + uint16_t* magn, + uint32_t* noise, + int16_t* q_noise); +extern NoiseEstimation WebRtcNsx_NoiseEstimation; + +// Filter the data in the frequency domain, and create spectrum. +typedef void (*PrepareSpectrum)(NsxInst_t* inst, + int16_t* freq_buff); +extern PrepareSpectrum WebRtcNsx_PrepareSpectrum; + +// For the noise supression process, synthesis, read out fully processed +// segment, and update synthesis buffer. +typedef void (*SynthesisUpdate)(NsxInst_t* inst, + int16_t* out_frame, + int16_t gain_factor); +extern SynthesisUpdate WebRtcNsx_SynthesisUpdate; + +// Update analysis buffer for lower band, and window data before FFT. +typedef void (*AnalysisUpdate)(NsxInst_t* inst, + int16_t* out, + int16_t* new_speech); +extern AnalysisUpdate WebRtcNsx_AnalysisUpdate; + +// Denormalize the input buffer. +typedef void (*Denormalize)(NsxInst_t* inst, + int16_t* in, + int factor); +extern Denormalize WebRtcNsx_Denormalize; + +// Create a complex number buffer, as the intput interleaved with zeros, +// and normalize it. +typedef void (*CreateComplexBuffer)(NsxInst_t* inst, + int16_t* in, + int16_t* out); +extern CreateComplexBuffer WebRtcNsx_CreateComplexBuffer; + +/**************************************************************************** + * Initialization of the above function pointers for ARM Neon. + */ +void WebRtcNsx_InitNeon(void); + +extern const WebRtc_Word16 WebRtcNsx_kLogTable[9]; +extern const WebRtc_Word16 WebRtcNsx_kLogTableFrac[256]; +extern const WebRtc_Word16 WebRtcNsx_kCounterDiv[201]; + +#ifdef __cplusplus +} +#endif + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_NSX_CORE_H_ diff --git a/libs/miniwebrtc/audio/processing/ns/nsx_core_neon.c b/libs/miniwebrtc/audio/processing/ns/nsx_core_neon.c new file mode 100644 index 00000000..2f85abd0 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/ns/nsx_core_neon.c @@ -0,0 +1,734 @@ +/* + * 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 "nsx_core.h" + +#include +#include + +// Update the noise estimation information. +static void UpdateNoiseEstimateNeon(NsxInst_t* inst, int offset) { + int i = 0; + const int16_t kExp2Const = 11819; // Q13 + int16_t* ptr_noiseEstLogQuantile = NULL; + int16_t* ptr_noiseEstQuantile = NULL; + int16x4_t kExp2Const16x4 = vdup_n_s16(kExp2Const); + int32x4_t twentyOne32x4 = vdupq_n_s32(21); + int32x4_t constA32x4 = vdupq_n_s32(0x1fffff); + int32x4_t constB32x4 = vdupq_n_s32(0x200000); + + int16_t tmp16 = WebRtcSpl_MaxValueW16(inst->noiseEstLogQuantile + offset, + inst->magnLen); + + // Guarantee a Q-domain as high as possible and still fit in int16 + inst->qNoise = 14 - (int) WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(kExp2Const, + tmp16, + 21); + + int32x4_t qNoise32x4 = vdupq_n_s32(inst->qNoise); + + for (ptr_noiseEstLogQuantile = &inst->noiseEstLogQuantile[offset], + ptr_noiseEstQuantile = &inst->noiseEstQuantile[0]; + ptr_noiseEstQuantile < &inst->noiseEstQuantile[inst->magnLen - 3]; + ptr_noiseEstQuantile += 4, ptr_noiseEstLogQuantile += 4) { + + // tmp32no2 = WEBRTC_SPL_MUL_16_16(kExp2Const, + // inst->noiseEstLogQuantile[offset + i]); + int16x4_t v16x4 = vld1_s16(ptr_noiseEstLogQuantile); + int32x4_t v32x4B = vmull_s16(v16x4, kExp2Const16x4); + + // tmp32no1 = (0x00200000 | (tmp32no2 & 0x001FFFFF)); // 2^21 + frac + int32x4_t v32x4A = vandq_s32(v32x4B, constA32x4); + v32x4A = vorrq_s32(v32x4A, constB32x4); + + // tmp16 = (int16_t) WEBRTC_SPL_RSHIFT_W32(tmp32no2, 21); + v32x4B = vshrq_n_s32(v32x4B, 21); + + // tmp16 -= 21;// shift 21 to get result in Q0 + v32x4B = vsubq_s32(v32x4B, twentyOne32x4); + + // tmp16 += (int16_t) inst->qNoise; + // shift to get result in Q(qNoise) + v32x4B = vaddq_s32(v32x4B, qNoise32x4); + + // if (tmp16 < 0) { + // tmp32no1 = WEBRTC_SPL_RSHIFT_W32(tmp32no1, -tmp16); + // } else { + // tmp32no1 = WEBRTC_SPL_LSHIFT_W32(tmp32no1, tmp16); + // } + v32x4B = vshlq_s32(v32x4A, v32x4B); + + // tmp16 = WebRtcSpl_SatW32ToW16(tmp32no1); + v16x4 = vqmovn_s32(v32x4B); + + //inst->noiseEstQuantile[i] = tmp16; + vst1_s16(ptr_noiseEstQuantile, v16x4); + } + + // Last iteration: + + // inst->quantile[i]=exp(inst->lquantile[offset+i]); + // in Q21 + int32_t tmp32no2 = WEBRTC_SPL_MUL_16_16(kExp2Const, + *ptr_noiseEstLogQuantile); + int32_t tmp32no1 = (0x00200000 | (tmp32no2 & 0x001FFFFF)); // 2^21 + frac + + tmp16 = (int16_t) WEBRTC_SPL_RSHIFT_W32(tmp32no2, 21); + tmp16 -= 21;// shift 21 to get result in Q0 + tmp16 += (int16_t) inst->qNoise; //shift to get result in Q(qNoise) + if (tmp16 < 0) { + tmp32no1 = WEBRTC_SPL_RSHIFT_W32(tmp32no1, -tmp16); + } else { + tmp32no1 = WEBRTC_SPL_LSHIFT_W32(tmp32no1, tmp16); + } + *ptr_noiseEstQuantile = WebRtcSpl_SatW32ToW16(tmp32no1); +} + +// Noise Estimation +static void NoiseEstimationNeon(NsxInst_t* inst, + uint16_t* magn, + uint32_t* noise, + int16_t* q_noise) { + int16_t lmagn[HALF_ANAL_BLOCKL], counter, countDiv; + int16_t countProd, delta, zeros, frac; + int16_t log2, tabind, logval, tmp16, tmp16no1, tmp16no2; + const int16_t log2_const = 22713; + const int16_t width_factor = 21845; + + int i, s, offset; + + tabind = inst->stages - inst->normData; + assert(tabind < 9); + assert(tabind > -9); + if (tabind < 0) { + logval = -WebRtcNsx_kLogTable[-tabind]; + } else { + logval = WebRtcNsx_kLogTable[tabind]; + } + + int16x8_t logval_16x8 = vdupq_n_s16(logval); + + // lmagn(i)=log(magn(i))=log(2)*log2(magn(i)) + // magn is in Q(-stages), and the real lmagn values are: + // real_lmagn(i)=log(magn(i)*2^stages)=log(magn(i))+log(2^stages) + // lmagn in Q8 + for (i = 0; i < inst->magnLen; i++) { + if (magn[i]) { + zeros = WebRtcSpl_NormU32((uint32_t)magn[i]); + frac = (int16_t)((((uint32_t)magn[i] << zeros) + & 0x7FFFFFFF) >> 23); + assert(frac < 256); + // log2(magn(i)) + log2 = (int16_t)(((31 - zeros) << 8) + + WebRtcNsx_kLogTableFrac[frac]); + // log2(magn(i))*log(2) + lmagn[i] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(log2, log2_const, 15); + // + log(2^stages) + lmagn[i] += logval; + } else { + lmagn[i] = logval; + } + } + + int16x4_t Q3_16x4 = vdup_n_s16(3); + int16x8_t WIDTHQ8_16x8 = vdupq_n_s16(WIDTH_Q8); + int16x8_t WIDTHFACTOR_16x8 = vdupq_n_s16(width_factor); + + int16_t factor = FACTOR_Q7; + if (inst->blockIndex < END_STARTUP_LONG) + factor = FACTOR_Q7_STARTUP; + + // Loop over simultaneous estimates + for (s = 0; s < SIMULT; s++) { + offset = s * inst->magnLen; + + // Get counter values from state + counter = inst->noiseEstCounter[s]; + assert(counter < 201); + countDiv = WebRtcNsx_kCounterDiv[counter]; + countProd = (int16_t)WEBRTC_SPL_MUL_16_16(counter, countDiv); + + // quant_est(...) + int16_t deltaBuff[8]; + int16x4_t tmp16x4_0; + int16x4_t tmp16x4_1; + int16x4_t countDiv_16x4 = vdup_n_s16(countDiv); + int16x8_t countProd_16x8 = vdupq_n_s16(countProd); + int16x8_t tmp16x8_0 = vdupq_n_s16(countDiv); + int16x8_t prod16x8 = vqrdmulhq_s16(WIDTHFACTOR_16x8, tmp16x8_0); + int16x8_t tmp16x8_1; + int16x8_t tmp16x8_2; + int16x8_t tmp16x8_3; + int16x8_t tmp16x8_4; + int16x8_t tmp16x8_5; + int32x4_t tmp32x4; + + for (i = 0; i < inst->magnLen - 7; i += 8) { + // Compute delta. + // Smaller step size during startup. This prevents from using + // unrealistic values causing overflow. + tmp16x8_0 = vdupq_n_s16(factor); + vst1q_s16(deltaBuff, tmp16x8_0); + + int j; + for (j = 0; j < 8; j++) { + if (inst->noiseEstDensity[offset + i + j] > 512) { + // Get values for deltaBuff by shifting intead of dividing. + int factor = WebRtcSpl_NormW16(inst->noiseEstDensity[offset + i + j]); + deltaBuff[j] = (int16_t)(FACTOR_Q16 >> (14 - factor)); + } + } + + // Update log quantile estimate + + // tmp16 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(delta, countDiv, 14); + tmp32x4 = vmull_s16(vld1_s16(&deltaBuff[0]), countDiv_16x4); + tmp16x4_1 = vshrn_n_s32(tmp32x4, 14); + tmp32x4 = vmull_s16(vld1_s16(&deltaBuff[4]), countDiv_16x4); + tmp16x4_0 = vshrn_n_s32(tmp32x4, 14); + tmp16x8_0 = vcombine_s16(tmp16x4_1, tmp16x4_0); // Keep for several lines. + + // prepare for the "if" branch + // tmp16 += 2; + // tmp16_1 = (Word16)(tmp16>>2); + tmp16x8_1 = vrshrq_n_s16(tmp16x8_0, 2); + + // inst->noiseEstLogQuantile[offset+i] + tmp16_1; + tmp16x8_2 = vld1q_s16(&inst->noiseEstLogQuantile[offset + i]); // Keep + tmp16x8_1 = vaddq_s16(tmp16x8_2, tmp16x8_1); // Keep for several lines + + // Prepare for the "else" branch + // tmp16 += 1; + // tmp16_1 = (Word16)(tmp16>>1); + tmp16x8_0 = vrshrq_n_s16(tmp16x8_0, 1); + + // tmp16_2 = (Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16_1,3,1); + tmp32x4 = vmull_s16(vget_low_s16(tmp16x8_0), Q3_16x4); + tmp16x4_1 = vshrn_n_s32(tmp32x4, 1); + + // tmp16_2 = (Word16)WEBRTC_SPL_MUL_16_16_RSFT(tmp16_1,3,1); + tmp32x4 = vmull_s16(vget_high_s16(tmp16x8_0), Q3_16x4); + tmp16x4_0 = vshrn_n_s32(tmp32x4, 1); + + // inst->noiseEstLogQuantile[offset + i] - tmp16_2; + tmp16x8_0 = vcombine_s16(tmp16x4_1, tmp16x4_0); // keep + tmp16x8_0 = vsubq_s16(tmp16x8_2, tmp16x8_0); + + // logval is the smallest fixed point representation we can have. Values + // below that will correspond to values in the interval [0, 1], which + // can't possibly occur. + tmp16x8_0 = vmaxq_s16(tmp16x8_0, logval_16x8); + + // Do the if-else branches: + tmp16x8_3 = vld1q_s16(&lmagn[i]); // keep for several lines + tmp16x8_5 = vsubq_s16(tmp16x8_3, tmp16x8_2); + __asm__("vcgt.s16 %q0, %q1, #0"::"w"(tmp16x8_4), "w"(tmp16x8_5)); + __asm__("vbit %q0, %q1, %q2":: + "w"(tmp16x8_2), "w"(tmp16x8_1), "w"(tmp16x8_4)); + __asm__("vbif %q0, %q1, %q2":: + "w"(tmp16x8_2), "w"(tmp16x8_0), "w"(tmp16x8_4)); + vst1q_s16(&inst->noiseEstLogQuantile[offset + i], tmp16x8_2); + + // Update density estimate + // tmp16_1 + tmp16_2 + tmp16x8_1 = vld1q_s16(&inst->noiseEstDensity[offset + i]); + tmp16x8_0 = vqrdmulhq_s16(tmp16x8_1, countProd_16x8); + tmp16x8_0 = vaddq_s16(tmp16x8_0, prod16x8); + + // lmagn[i] - inst->noiseEstLogQuantile[offset + i] + tmp16x8_3 = vsubq_s16(tmp16x8_3, tmp16x8_2); + tmp16x8_3 = vabsq_s16(tmp16x8_3); + tmp16x8_4 = vcgtq_s16(WIDTHQ8_16x8, tmp16x8_3); + __asm__("vbit %q0, %q1, %q2":: + "w"(tmp16x8_1), "w"(tmp16x8_0), "w"(tmp16x8_4)); + vst1q_s16(&inst->noiseEstDensity[offset + i], tmp16x8_1); + } // End loop over magnitude spectrum + + // Last iteration over magnitude spectrum: + // compute delta + if (inst->noiseEstDensity[offset + i] > 512) { + // Get values for deltaBuff by shifting intead of dividing. + int factor = WebRtcSpl_NormW16(inst->noiseEstDensity[offset + i]); + delta = (int16_t)(FACTOR_Q16 >> (14 - factor)); + } else { + delta = FACTOR_Q7; + if (inst->blockIndex < END_STARTUP_LONG) { + // Smaller step size during startup. This prevents from using + // unrealistic values causing overflow. + delta = FACTOR_Q7_STARTUP; + } + } + // update log quantile estimate + tmp16 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(delta, countDiv, 14); + if (lmagn[i] > inst->noiseEstLogQuantile[offset + i]) { + // +=QUANTILE*delta/(inst->counter[s]+1) QUANTILE=0.25, =1 in Q2 + // CounterDiv=1/(inst->counter[s]+1) in Q15 + tmp16 += 2; + tmp16no1 = WEBRTC_SPL_RSHIFT_W16(tmp16, 2); + inst->noiseEstLogQuantile[offset + i] += tmp16no1; + } else { + tmp16 += 1; + tmp16no1 = WEBRTC_SPL_RSHIFT_W16(tmp16, 1); + // *(1-QUANTILE), in Q2 QUANTILE=0.25, 1-0.25=0.75=3 in Q2 + tmp16no2 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(tmp16no1, 3, 1); + inst->noiseEstLogQuantile[offset + i] -= tmp16no2; + if (inst->noiseEstLogQuantile[offset + i] < logval) { + // logval is the smallest fixed point representation we can have. + // Values below that will correspond to values in the interval + // [0, 1], which can't possibly occur. + inst->noiseEstLogQuantile[offset + i] = logval; + } + } + + // update density estimate + if (WEBRTC_SPL_ABS_W16(lmagn[i] - inst->noiseEstLogQuantile[offset + i]) + < WIDTH_Q8) { + tmp16no1 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( + inst->noiseEstDensity[offset + i], countProd, 15); + tmp16no2 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( + width_factor, countDiv, 15); + inst->noiseEstDensity[offset + i] = tmp16no1 + tmp16no2; + } + + + if (counter >= END_STARTUP_LONG) { + inst->noiseEstCounter[s] = 0; + if (inst->blockIndex >= END_STARTUP_LONG) { + UpdateNoiseEstimateNeon(inst, offset); + } + } + inst->noiseEstCounter[s]++; + + } // end loop over simultaneous estimates + + // Sequentially update the noise during startup + if (inst->blockIndex < END_STARTUP_LONG) { + UpdateNoiseEstimateNeon(inst, offset); + } + + for (i = 0; i < inst->magnLen; i++) { + noise[i] = (uint32_t)(inst->noiseEstQuantile[i]); // Q(qNoise) + } + (*q_noise) = (int16_t)inst->qNoise; +} + +// Filter the data in the frequency domain, and create spectrum. +static void PrepareSpectrumNeon(NsxInst_t* inst, int16_t* freq_buf) { + + // (1) Filtering. + + // Fixed point C code for the next block is as follows: + // for (i = 0; i < inst->magnLen; i++) { + // inst->real[i] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(inst->real[i], + // (int16_t)(inst->noiseSupFilter[i]), 14); // Q(normData-stages) + // inst->imag[i] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(inst->imag[i], + // (int16_t)(inst->noiseSupFilter[i]), 14); // Q(normData-stages) + // } + + int16_t* ptr_real = &inst->real[0]; + int16_t* ptr_imag = &inst->imag[0]; + uint16_t* ptr_noiseSupFilter = &inst->noiseSupFilter[0]; + + // Filter the rest in the frequency domain. + for (; ptr_real < &inst->real[inst->magnLen - 1];) { + // Loop unrolled once. Both pointers are incremented by 4 twice. + __asm__ __volatile__( + "vld1.16 d20, [%[ptr_real]]\n\t" + "vld1.16 d22, [%[ptr_imag]]\n\t" + "vld1.16 d23, [%[ptr_noiseSupFilter]]!\n\t" + "vmull.s16 q10, d20, d23\n\t" + "vmull.s16 q11, d22, d23\n\t" + "vshrn.s32 d20, q10, #14\n\t" + "vshrn.s32 d22, q11, #14\n\t" + "vst1.16 d20, [%[ptr_real]]!\n\t" + "vst1.16 d22, [%[ptr_imag]]!\n\t" + + "vld1.16 d18, [%[ptr_real]]\n\t" + "vld1.16 d24, [%[ptr_imag]]\n\t" + "vld1.16 d25, [%[ptr_noiseSupFilter]]!\n\t" + "vmull.s16 q9, d18, d25\n\t" + "vmull.s16 q12, d24, d25\n\t" + "vshrn.s32 d18, q9, #14\n\t" + "vshrn.s32 d24, q12, #14\n\t" + "vst1.16 d18, [%[ptr_real]]!\n\t" + "vst1.16 d24, [%[ptr_imag]]!\n\t" + + // Specify constraints. + :[ptr_imag]"+r"(ptr_imag), + [ptr_real]"+r"(ptr_real), + [ptr_noiseSupFilter]"+r"(ptr_noiseSupFilter) + : + :"d18", "d19", "d20", "d21", "d22", "d23", "d24", "d25", + "q9", "q10", "q11", "q12" + ); + } + + // Filter the last pair of elements in the frequency domain. + *ptr_real = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(*ptr_real, + (int16_t)(*ptr_noiseSupFilter), 14); // Q(normData-stages) + *ptr_imag = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT(*ptr_imag, + (int16_t)(*ptr_noiseSupFilter), 14); // Q(normData-stages) + + // (2) Create spectrum. + + // Fixed point C code for the rest of the function is as follows: + // freq_buf[0] = inst->real[0]; + // freq_buf[1] = -inst->imag[0]; + // for (i = 1, j = 2; i < inst->anaLen2; i += 1, j += 2) { + // tmp16 = (inst->anaLen << 1) - j; + // freq_buf[j] = inst->real[i]; + // freq_buf[j + 1] = -inst->imag[i]; + // freq_buf[tmp16] = inst->real[i]; + // freq_buf[tmp16 + 1] = inst->imag[i]; + // } + // freq_buf[inst->anaLen] = inst->real[inst->anaLen2]; + // freq_buf[inst->anaLen + 1] = -inst->imag[inst->anaLen2]; + + freq_buf[0] = inst->real[0]; + freq_buf[1] = -inst->imag[0]; + + int offset = -16; + int16_t* ptr_realImag1 = &freq_buf[2]; + int16_t* ptr_realImag2 = ptr_realImag2 = &freq_buf[(inst->anaLen << 1) - 8]; + ptr_real = &inst->real[1]; + ptr_imag = &inst->imag[1]; + for (; ptr_real < &inst->real[inst->anaLen2 - 11];) { + // Loop unrolled once. All pointers are incremented twice. + __asm__ __volatile__( + "vld1.16 d22, [%[ptr_real]]!\n\t" + "vld1.16 d23, [%[ptr_imag]]!\n\t" + // Negate and interleave: + "vmov.s16 d20, d22\n\t" + "vneg.s16 d21, d23\n\t" + "vzip.16 d20, d21\n\t" + // Write 8 elements to &freq_buf[j] + "vst1.16 {d20, d21}, [%[ptr_realImag1]]!\n\t" + // Interleave and reverse elements: + "vzip.16 d22, d23\n\t" + "vrev64.32 d18, d23\n\t" + "vrev64.32 d19, d22\n\t" + // Write 8 elements to &freq_buf[tmp16] + "vst1.16 {d18, d19}, [%[ptr_realImag2]], %[offset]\n\t" + + "vld1.16 d22, [%[ptr_real]]!\n\t" + "vld1.16 d23, [%[ptr_imag]]!\n\t" + // Negate and interleave: + "vmov.s16 d20, d22\n\t" + "vneg.s16 d21, d23\n\t" + "vzip.16 d20, d21\n\t" + // Write 8 elements to &freq_buf[j] + "vst1.16 {d20, d21}, [%[ptr_realImag1]]!\n\t" + // Interleave and reverse elements: + "vzip.16 d22, d23\n\t" + "vrev64.32 d18, d23\n\t" + "vrev64.32 d19, d22\n\t" + // Write 8 elements to &freq_buf[tmp16] + "vst1.16 {d18, d19}, [%[ptr_realImag2]], %[offset]\n\t" + + // Specify constraints. + :[ptr_imag]"+r"(ptr_imag), + [ptr_real]"+r"(ptr_real), + [ptr_realImag1]"+r"(ptr_realImag1), + [ptr_realImag2]"+r"(ptr_realImag2) + :[offset]"r"(offset) + :"d18", "d19", "d20", "d21", "d22", "d23" + ); + } + for (ptr_realImag2 += 6; + ptr_real <= &inst->real[inst->anaLen2]; + ptr_real += 1, ptr_imag += 1, ptr_realImag1 += 2, ptr_realImag2 -= 2) { + *ptr_realImag1 = *ptr_real; + *(ptr_realImag1 + 1) = -(*ptr_imag); + *ptr_realImag2 = *ptr_real; + *(ptr_realImag2 + 1) = *ptr_imag; + } + + freq_buf[inst->anaLen] = inst->real[inst->anaLen2]; + freq_buf[inst->anaLen + 1] = -inst->imag[inst->anaLen2]; +} + +// Denormalize the input buffer. +static __inline void DenormalizeNeon(NsxInst_t* inst, int16_t* in, int factor) { + int16_t* ptr_real = &inst->real[0]; + int16_t* ptr_in = &in[0]; + + __asm__ __volatile__("vdup.32 q10, %0" :: + "r"((int32_t)(factor - inst->normData)) : "q10"); + for (; ptr_real < &inst->real[inst->anaLen];) { + + // Loop unrolled once. Both pointers are incremented. + __asm__ __volatile__( + // tmp32 = WEBRTC_SPL_SHIFT_W32((int32_t)in[j], + // factor - inst->normData); + "vld2.16 {d24, d25}, [%[ptr_in]]!\n\t" + "vmovl.s16 q12, d24\n\t" + "vshl.s32 q12, q10\n\t" + // inst->real[i] = WebRtcSpl_SatW32ToW16(tmp32); // Q0 + "vqmovn.s32 d24, q12\n\t" + "vst1.16 d24, [%[ptr_real]]!\n\t" + + // tmp32 = WEBRTC_SPL_SHIFT_W32((int32_t)in[j], + // factor - inst->normData); + "vld2.16 {d22, d23}, [%[ptr_in]]!\n\t" + "vmovl.s16 q11, d22\n\t" + "vshl.s32 q11, q10\n\t" + // inst->real[i] = WebRtcSpl_SatW32ToW16(tmp32); // Q0 + "vqmovn.s32 d22, q11\n\t" + "vst1.16 d22, [%[ptr_real]]!\n\t" + + // Specify constraints. + :[ptr_in]"+r"(ptr_in), + [ptr_real]"+r"(ptr_real) + : + :"d22", "d23", "d24", "d25" + ); + } +} + +// For the noise supress process, synthesis, read out fully processed segment, +// and update synthesis buffer. +static void SynthesisUpdateNeon(NsxInst_t* inst, + int16_t* out_frame, + int16_t gain_factor) { + int16_t* ptr_real = &inst->real[0]; + int16_t* ptr_syn = &inst->synthesisBuffer[0]; + int16_t* ptr_window = &inst->window[0]; + + // synthesis + __asm__ __volatile__("vdup.16 d24, %0" : : "r"(gain_factor) : "d24"); + // Loop unrolled once. All pointers are incremented in the assembly code. + for (; ptr_syn < &inst->synthesisBuffer[inst->anaLen];) { + __asm__ __volatile__( + // Load variables. + "vld1.16 d22, [%[ptr_real]]!\n\t" + "vld1.16 d23, [%[ptr_window]]!\n\t" + "vld1.16 d25, [%[ptr_syn]]\n\t" + // tmp16a = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( + // inst->window[i], inst->real[i], 14); // Q0, window in Q14 + "vmull.s16 q11, d22, d23\n\t" + "vrshrn.i32 d22, q11, #14\n\t" + // tmp32 = WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(tmp16a, gain_factor, 13); + "vmull.s16 q11, d24, d22\n\t" + // tmp16b = WebRtcSpl_SatW32ToW16(tmp32); // Q0 + "vqrshrn.s32 d22, q11, #13\n\t" + // inst->synthesisBuffer[i] = WEBRTC_SPL_ADD_SAT_W16( + // inst->synthesisBuffer[i], tmp16b); // Q0 + "vqadd.s16 d25, d22\n\t" + "vst1.16 d25, [%[ptr_syn]]!\n\t" + + // Load variables. + "vld1.16 d26, [%[ptr_real]]!\n\t" + "vld1.16 d27, [%[ptr_window]]!\n\t" + "vld1.16 d28, [%[ptr_syn]]\n\t" + // tmp16a = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( + // inst->window[i], inst->real[i], 14); // Q0, window in Q14 + "vmull.s16 q13, d26, d27\n\t" + "vrshrn.i32 d26, q13, #14\n\t" + // tmp32 = WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(tmp16a, gain_factor, 13); + "vmull.s16 q13, d24, d26\n\t" + // tmp16b = WebRtcSpl_SatW32ToW16(tmp32); // Q0 + "vqrshrn.s32 d26, q13, #13\n\t" + // inst->synthesisBuffer[i] = WEBRTC_SPL_ADD_SAT_W16( + // inst->synthesisBuffer[i], tmp16b); // Q0 + "vqadd.s16 d28, d26\n\t" + "vst1.16 d28, [%[ptr_syn]]!\n\t" + + // Specify constraints. + :[ptr_real]"+r"(ptr_real), + [ptr_window]"+r"(ptr_window), + [ptr_syn]"+r"(ptr_syn) + : + :"d22", "d23", "d24", "d25", "d26", "d27", "d28", "q11", "q12", "q13" + ); + } + + int16_t* ptr_out = &out_frame[0]; + ptr_syn = &inst->synthesisBuffer[0]; + // read out fully processed segment + for (; ptr_syn < &inst->synthesisBuffer[inst->blockLen10ms];) { + // Loop unrolled once. Both pointers are incremented in the assembly code. + __asm__ __volatile__( + // out_frame[i] = inst->synthesisBuffer[i]; // Q0 + "vld1.16 {d22, d23}, [%[ptr_syn]]!\n\t" + "vld1.16 {d24, d25}, [%[ptr_syn]]!\n\t" + "vst1.16 {d22, d23}, [%[ptr_out]]!\n\t" + "vst1.16 {d24, d25}, [%[ptr_out]]!\n\t" + :[ptr_syn]"+r"(ptr_syn), + [ptr_out]"+r"(ptr_out) + : + :"d22", "d23", "d24", "d25" + ); + } + + // Update synthesis buffer. + // C code: + // WEBRTC_SPL_MEMCPY_W16(inst->synthesisBuffer, + // inst->synthesisBuffer + inst->blockLen10ms, + // inst->anaLen - inst->blockLen10ms); + ptr_out = &inst->synthesisBuffer[0], + ptr_syn = &inst->synthesisBuffer[inst->blockLen10ms]; + for (; ptr_syn < &inst->synthesisBuffer[inst->anaLen];) { + // Loop unrolled once. Both pointers are incremented in the assembly code. + __asm__ __volatile__( + "vld1.16 {d22, d23}, [%[ptr_syn]]!\n\t" + "vld1.16 {d24, d25}, [%[ptr_syn]]!\n\t" + "vst1.16 {d22, d23}, [%[ptr_out]]!\n\t" + "vst1.16 {d24, d25}, [%[ptr_out]]!\n\t" + :[ptr_syn]"+r"(ptr_syn), + [ptr_out]"+r"(ptr_out) + : + :"d22", "d23", "d24", "d25" + ); + } + + // C code: + // WebRtcSpl_ZerosArrayW16(inst->synthesisBuffer + // + inst->anaLen - inst->blockLen10ms, inst->blockLen10ms); + __asm__ __volatile__("vdup.16 q10, %0" : : "r"(0) : "q10"); + for (; ptr_out < &inst->synthesisBuffer[inst->anaLen];) { + // Loop unrolled once. Pointer is incremented in the assembly code. + __asm__ __volatile__( + "vst1.16 {d20, d21}, [%[ptr_out]]!\n\t" + "vst1.16 {d20, d21}, [%[ptr_out]]!\n\t" + :[ptr_out]"+r"(ptr_out) + : + :"d20", "d21" + ); + } +} + +// Update analysis buffer for lower band, and window data before FFT. +static void AnalysisUpdateNeon(NsxInst_t* inst, + int16_t* out, + int16_t* new_speech) { + + int16_t* ptr_ana = &inst->analysisBuffer[inst->blockLen10ms]; + int16_t* ptr_out = &inst->analysisBuffer[0]; + + // For lower band update analysis buffer. + // WEBRTC_SPL_MEMCPY_W16(inst->analysisBuffer, + // inst->analysisBuffer + inst->blockLen10ms, + // inst->anaLen - inst->blockLen10ms); + for (; ptr_out < &inst->analysisBuffer[inst->anaLen - inst->blockLen10ms];) { + // Loop unrolled once, so both pointers are incremented by 8 twice. + __asm__ __volatile__( + "vld1.16 {d20, d21}, [%[ptr_ana]]!\n\t" + "vst1.16 {d20, d21}, [%[ptr_out]]!\n\t" + "vld1.16 {d22, d23}, [%[ptr_ana]]!\n\t" + "vst1.16 {d22, d23}, [%[ptr_out]]!\n\t" + :[ptr_ana]"+r"(ptr_ana), + [ptr_out]"+r"(ptr_out) + : + :"d20", "d21", "d22", "d23" + ); + } + + // WEBRTC_SPL_MEMCPY_W16(inst->analysisBuffer + // + inst->anaLen - inst->blockLen10ms, new_speech, inst->blockLen10ms); + for (ptr_ana = new_speech; ptr_out < &inst->analysisBuffer[inst->anaLen];) { + // Loop unrolled once, so both pointers are incremented by 8 twice. + __asm__ __volatile__( + "vld1.16 {d20, d21}, [%[ptr_ana]]!\n\t" + "vst1.16 {d20, d21}, [%[ptr_out]]!\n\t" + "vld1.16 {d22, d23}, [%[ptr_ana]]!\n\t" + "vst1.16 {d22, d23}, [%[ptr_out]]!\n\t" + :[ptr_ana]"+r"(ptr_ana), + [ptr_out]"+r"(ptr_out) + : + :"d20", "d21", "d22", "d23" + ); + } + + // Window data before FFT + int16_t* ptr_window = &inst->window[0]; + ptr_out = &out[0]; + ptr_ana = &inst->analysisBuffer[0]; + for (; ptr_out < &out[inst->anaLen];) { + + // Loop unrolled once, so all pointers are incremented by 4 twice. + __asm__ __volatile__( + "vld1.16 d20, [%[ptr_ana]]!\n\t" + "vld1.16 d21, [%[ptr_window]]!\n\t" + // out[i] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( + // inst->window[i], inst->analysisBuffer[i], 14); // Q0 + "vmull.s16 q10, d20, d21\n\t" + "vrshrn.i32 d20, q10, #14\n\t" + "vst1.16 d20, [%[ptr_out]]!\n\t" + + "vld1.16 d22, [%[ptr_ana]]!\n\t" + "vld1.16 d23, [%[ptr_window]]!\n\t" + // out[i] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND( + // inst->window[i], inst->analysisBuffer[i], 14); // Q0 + "vmull.s16 q11, d22, d23\n\t" + "vrshrn.i32 d22, q11, #14\n\t" + "vst1.16 d22, [%[ptr_out]]!\n\t" + + // Specify constraints. + :[ptr_ana]"+r"(ptr_ana), + [ptr_window]"+r"(ptr_window), + [ptr_out]"+r"(ptr_out) + : + :"d20", "d21", "d22", "d23", "q10", "q11" + ); + } +} + +// Create a complex number buffer (out[]) as the intput (in[]) interleaved with +// zeros, and normalize it. +static __inline void CreateComplexBufferNeon(NsxInst_t* inst, + int16_t* in, + int16_t* out) { + int16_t* ptr_out = &out[0]; + int16_t* ptr_in = &in[0]; + + __asm__ __volatile__("vdup.16 d25, %0" : : "r"(0) : "d25"); + __asm__ __volatile__("vdup.16 q10, %0" : : "r"(inst->normData) : "q10"); + for (; ptr_in < &in[inst->anaLen];) { + + // Loop unrolled once, so ptr_in is incremented by 8 twice, + // and ptr_out is incremented by 8 four times. + __asm__ __volatile__( + // out[j] = WEBRTC_SPL_LSHIFT_W16(in[i], inst->normData); // Q(normData) + "vld1.16 {d22, d23}, [%[ptr_in]]!\n\t" + "vshl.s16 q11, q10\n\t" + "vmov d24, d23\n\t" + + // out[j + 1] = 0; // Insert zeros in imaginary part + "vmov d23, d25\n\t" + "vst2.16 {d22, d23}, [%[ptr_out]]!\n\t" + "vst2.16 {d24, d25}, [%[ptr_out]]!\n\t" + + // out[j] = WEBRTC_SPL_LSHIFT_W16(in[i], inst->normData); // Q(normData) + "vld1.16 {d22, d23}, [%[ptr_in]]!\n\t" + "vshl.s16 q11, q10\n\t" + "vmov d24, d23\n\t" + + // out[j + 1] = 0; // Insert zeros in imaginary part + "vmov d23, d25\n\t" + "vst2.16 {d22, d23}, [%[ptr_out]]!\n\t" + "vst2.16 {d24, d25}, [%[ptr_out]]!\n\t" + + // Specify constraints. + :[ptr_in]"+r"(ptr_in), + [ptr_out]"+r"(ptr_out) + : + :"d22", "d23", "d24", "d25", "q10", "q11" + ); + } +} + +void WebRtcNsx_InitNeon(void) { + WebRtcNsx_NoiseEstimation = NoiseEstimationNeon; + WebRtcNsx_PrepareSpectrum = PrepareSpectrumNeon; + WebRtcNsx_SynthesisUpdate = SynthesisUpdateNeon; + WebRtcNsx_AnalysisUpdate = AnalysisUpdateNeon; + WebRtcNsx_Denormalize = DenormalizeNeon; + WebRtcNsx_CreateComplexBuffer = CreateComplexBufferNeon; +} diff --git a/libs/miniwebrtc/audio/processing/ns/nsx_defines.h b/libs/miniwebrtc/audio/processing/ns/nsx_defines.h new file mode 100644 index 00000000..cd1e3bf5 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/ns/nsx_defines.h @@ -0,0 +1,59 @@ +/* + * 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_PROCESSING_NS_MAIN_SOURCE_NSX_DEFINES_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_NSX_DEFINES_H_ + +#define ANAL_BLOCKL_MAX 256 // max analysis block length +#define HALF_ANAL_BLOCKL 129 // half max analysis block length + 1 +#define SIMULT 3 +#define END_STARTUP_LONG 200 +#define END_STARTUP_SHORT 50 +#define FACTOR_Q16 (WebRtc_Word32)2621440 // 40 in Q16 +#define FACTOR_Q7 (WebRtc_Word16)5120 // 40 in Q7 +#define FACTOR_Q7_STARTUP (WebRtc_Word16)1024 // 8 in Q7 +#define WIDTH_Q8 3 // 0.01 in Q8 (or 25 ) +//PARAMETERS FOR NEW METHOD +#define DD_PR_SNR_Q11 2007 // ~= Q11(0.98) DD update of prior SNR +#define ONE_MINUS_DD_PR_SNR_Q11 41 // DD update of prior SNR +#define SPECT_FLAT_TAVG_Q14 4915 // (0.30) tavg parameter for spectral flatness measure +#define SPECT_DIFF_TAVG_Q8 77 // (0.30) tavg parameter for spectral flatness measure +#define PRIOR_UPDATE_Q14 1638 // Q14(0.1) update parameter of prior model +#define NOISE_UPDATE_Q8 26 // 26 ~= Q8(0.1) update parameter for noise +// probability threshold for noise state in speech/noise likelihood +#define ONE_MINUS_PROB_RANGE_Q8 205 // 205 ~= Q8(0.8) +#define HIST_PAR_EST 1000 // histogram size for estimation of parameters +//FEATURE EXTRACTION CONFIG +//bin size of histogram +#define BIN_SIZE_LRT 10 +//scale parameters: multiply dominant peaks of the histograms by scale factor to obtain +// thresholds for prior model +#define FACTOR_1_LRT_DIFF 6 //for LRT and spectral difference (5 times bigger) +//for spectral_flatness: used when noise is flatter than speech (10 times bigger) +#define FACTOR_2_FLAT_Q10 922 +//peak limit for spectral flatness (varies between 0 and 1) +#define THRES_PEAK_FLAT 24 // * 2 * BIN_SIZE_FLAT_FX +//limit on spacing of two highest peaks in histogram: spacing determined by bin size +#define LIM_PEAK_SPACE_FLAT_DIFF 4 // * 2 * BIN_SIZE_DIFF_FX +//limit on relevance of second peak: +#define LIM_PEAK_WEIGHT_FLAT_DIFF 2 +#define THRES_FLUCT_LRT 10240 //=20 * inst->modelUpdate; fluctuation limit of LRT feat. +//limit on the max and min values for the feature thresholds +#define MAX_FLAT_Q10 38912 // * 2 * BIN_SIZE_FLAT_FX +#define MIN_FLAT_Q10 4096 // * 2 * BIN_SIZE_FLAT_FX +#define MAX_DIFF 100 // * 2 * BIN_SIZE_DIFF_FX +#define MIN_DIFF 16 // * 2 * BIN_SIZE_DIFF_FX +//criteria of weight of histogram peak to accept/reject feature +#define THRES_WEIGHT_FLAT_DIFF 154//(int)(0.3*(inst->modelUpdate)) for flatness and difference +// +#define STAT_UPDATES 9 // Update every 512 = 1 << 9 block +#define ONE_MINUS_GAMMA_PAUSE_Q8 13 // ~= Q8(0.05) update for conservative noise estimate +#define GAMMA_NOISE_TRANS_AND_SPEECH_Q8 3 // ~= Q8(0.01) update for transition and noise region +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_NSX_DEFINES_H_ diff --git a/libs/miniwebrtc/audio/processing/ns/windows_private.h b/libs/miniwebrtc/audio/processing/ns/windows_private.h new file mode 100644 index 00000000..44c2e846 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/ns/windows_private.h @@ -0,0 +1,574 @@ +/* + * 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_PROCESSING_NS_MAIN_SOURCE_WINDOWS_PRIVATE_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_WINDOWS_PRIVATE_H_ + +// Hanning window for 4ms 16kHz +static const float kHanning64w128[128] = { + 0.00000000000000f, 0.02454122852291f, 0.04906767432742f, + 0.07356456359967f, 0.09801714032956f, 0.12241067519922f, + 0.14673047445536f, 0.17096188876030f, 0.19509032201613f, + 0.21910124015687f, 0.24298017990326f, 0.26671275747490f, + 0.29028467725446f, 0.31368174039889f, 0.33688985339222f, + 0.35989503653499f, 0.38268343236509f, 0.40524131400499f, + 0.42755509343028f, 0.44961132965461f, 0.47139673682600f, + 0.49289819222978f, 0.51410274419322f, 0.53499761988710f, + 0.55557023301960f, 0.57580819141785f, 0.59569930449243f, + 0.61523159058063f, 0.63439328416365f, 0.65317284295378f, + 0.67155895484702f, 0.68954054473707f, 0.70710678118655f, + 0.72424708295147f, 0.74095112535496f, 0.75720884650648f, + 0.77301045336274f, 0.78834642762661f, 0.80320753148064f, + 0.81758481315158f, 0.83146961230255f, 0.84485356524971f, + 0.85772861000027f, 0.87008699110871f, 0.88192126434835f, + 0.89322430119552f, 0.90398929312344f, 0.91420975570353f, + 0.92387953251129f, 0.93299279883474f, 0.94154406518302f, + 0.94952818059304f, 0.95694033573221f, 0.96377606579544f, + 0.97003125319454f, 0.97570213003853f, 0.98078528040323f, + 0.98527764238894f, 0.98917650996478f, 0.99247953459871f, + 0.99518472667220f, 0.99729045667869f, 0.99879545620517f, + 0.99969881869620f, 1.00000000000000f, + 0.99969881869620f, 0.99879545620517f, 0.99729045667869f, + 0.99518472667220f, 0.99247953459871f, 0.98917650996478f, + 0.98527764238894f, 0.98078528040323f, 0.97570213003853f, + 0.97003125319454f, 0.96377606579544f, 0.95694033573221f, + 0.94952818059304f, 0.94154406518302f, 0.93299279883474f, + 0.92387953251129f, 0.91420975570353f, 0.90398929312344f, + 0.89322430119552f, 0.88192126434835f, 0.87008699110871f, + 0.85772861000027f, 0.84485356524971f, 0.83146961230255f, + 0.81758481315158f, 0.80320753148064f, 0.78834642762661f, + 0.77301045336274f, 0.75720884650648f, 0.74095112535496f, + 0.72424708295147f, 0.70710678118655f, 0.68954054473707f, + 0.67155895484702f, 0.65317284295378f, 0.63439328416365f, + 0.61523159058063f, 0.59569930449243f, 0.57580819141785f, + 0.55557023301960f, 0.53499761988710f, 0.51410274419322f, + 0.49289819222978f, 0.47139673682600f, 0.44961132965461f, + 0.42755509343028f, 0.40524131400499f, 0.38268343236509f, + 0.35989503653499f, 0.33688985339222f, 0.31368174039889f, + 0.29028467725446f, 0.26671275747490f, 0.24298017990326f, + 0.21910124015687f, 0.19509032201613f, 0.17096188876030f, + 0.14673047445536f, 0.12241067519922f, 0.09801714032956f, + 0.07356456359967f, 0.04906767432742f, 0.02454122852291f +}; + + + +// hybrib Hanning & flat window +static const float kBlocks80w128[128] = { + (float)0.00000000, (float)0.03271908, (float)0.06540313, (float)0.09801714, (float)0.13052619, + (float)0.16289547, (float)0.19509032, (float)0.22707626, (float)0.25881905, (float)0.29028468, + (float)0.32143947, (float)0.35225005, (float)0.38268343, (float)0.41270703, (float)0.44228869, + (float)0.47139674, (float)0.50000000, (float)0.52806785, (float)0.55557023, (float)0.58247770, + (float)0.60876143, (float)0.63439328, (float)0.65934582, (float)0.68359230, (float)0.70710678, + (float)0.72986407, (float)0.75183981, (float)0.77301045, (float)0.79335334, (float)0.81284668, + (float)0.83146961, (float)0.84920218, (float)0.86602540, (float)0.88192126, (float)0.89687274, + (float)0.91086382, (float)0.92387953, (float)0.93590593, (float)0.94693013, (float)0.95694034, + (float)0.96592583, (float)0.97387698, (float)0.98078528, (float)0.98664333, (float)0.99144486, + (float)0.99518473, (float)0.99785892, (float)0.99946459, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)0.99946459, (float)0.99785892, (float)0.99518473, (float)0.99144486, + (float)0.98664333, (float)0.98078528, (float)0.97387698, (float)0.96592583, (float)0.95694034, + (float)0.94693013, (float)0.93590593, (float)0.92387953, (float)0.91086382, (float)0.89687274, + (float)0.88192126, (float)0.86602540, (float)0.84920218, (float)0.83146961, (float)0.81284668, + (float)0.79335334, (float)0.77301045, (float)0.75183981, (float)0.72986407, (float)0.70710678, + (float)0.68359230, (float)0.65934582, (float)0.63439328, (float)0.60876143, (float)0.58247770, + (float)0.55557023, (float)0.52806785, (float)0.50000000, (float)0.47139674, (float)0.44228869, + (float)0.41270703, (float)0.38268343, (float)0.35225005, (float)0.32143947, (float)0.29028468, + (float)0.25881905, (float)0.22707626, (float)0.19509032, (float)0.16289547, (float)0.13052619, + (float)0.09801714, (float)0.06540313, (float)0.03271908 +}; + +// hybrib Hanning & flat window +static const float kBlocks160w256[256] = { + (float)0.00000000, (float)0.01636173, (float)0.03271908, (float)0.04906767, (float)0.06540313, + (float)0.08172107, (float)0.09801714, (float)0.11428696, (float)0.13052619, (float)0.14673047, + (float)0.16289547, (float)0.17901686, (float)0.19509032, (float)0.21111155, (float)0.22707626, + (float)0.24298018, (float)0.25881905, (float)0.27458862, (float)0.29028468, (float)0.30590302, + (float)0.32143947, (float)0.33688985, (float)0.35225005, (float)0.36751594, (float)0.38268343, + (float)0.39774847, (float)0.41270703, (float)0.42755509, (float)0.44228869, (float)0.45690388, + (float)0.47139674, (float)0.48576339, (float)0.50000000, (float)0.51410274, (float)0.52806785, + (float)0.54189158, (float)0.55557023, (float)0.56910015, (float)0.58247770, (float)0.59569930, + (float)0.60876143, (float)0.62166057, (float)0.63439328, (float)0.64695615, (float)0.65934582, + (float)0.67155895, (float)0.68359230, (float)0.69544264, (float)0.70710678, (float)0.71858162, + (float)0.72986407, (float)0.74095113, (float)0.75183981, (float)0.76252720, (float)0.77301045, + (float)0.78328675, (float)0.79335334, (float)0.80320753, (float)0.81284668, (float)0.82226822, + (float)0.83146961, (float)0.84044840, (float)0.84920218, (float)0.85772861, (float)0.86602540, + (float)0.87409034, (float)0.88192126, (float)0.88951608, (float)0.89687274, (float)0.90398929, + (float)0.91086382, (float)0.91749450, (float)0.92387953, (float)0.93001722, (float)0.93590593, + (float)0.94154407, (float)0.94693013, (float)0.95206268, (float)0.95694034, (float)0.96156180, + (float)0.96592583, (float)0.97003125, (float)0.97387698, (float)0.97746197, (float)0.98078528, + (float)0.98384601, (float)0.98664333, (float)0.98917651, (float)0.99144486, (float)0.99344778, + (float)0.99518473, (float)0.99665524, (float)0.99785892, (float)0.99879546, (float)0.99946459, + (float)0.99986614, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)0.99986614, (float)0.99946459, (float)0.99879546, (float)0.99785892, + (float)0.99665524, (float)0.99518473, (float)0.99344778, (float)0.99144486, (float)0.98917651, + (float)0.98664333, (float)0.98384601, (float)0.98078528, (float)0.97746197, (float)0.97387698, + (float)0.97003125, (float)0.96592583, (float)0.96156180, (float)0.95694034, (float)0.95206268, + (float)0.94693013, (float)0.94154407, (float)0.93590593, (float)0.93001722, (float)0.92387953, + (float)0.91749450, (float)0.91086382, (float)0.90398929, (float)0.89687274, (float)0.88951608, + (float)0.88192126, (float)0.87409034, (float)0.86602540, (float)0.85772861, (float)0.84920218, + (float)0.84044840, (float)0.83146961, (float)0.82226822, (float)0.81284668, (float)0.80320753, + (float)0.79335334, (float)0.78328675, (float)0.77301045, (float)0.76252720, (float)0.75183981, + (float)0.74095113, (float)0.72986407, (float)0.71858162, (float)0.70710678, (float)0.69544264, + (float)0.68359230, (float)0.67155895, (float)0.65934582, (float)0.64695615, (float)0.63439328, + (float)0.62166057, (float)0.60876143, (float)0.59569930, (float)0.58247770, (float)0.56910015, + (float)0.55557023, (float)0.54189158, (float)0.52806785, (float)0.51410274, (float)0.50000000, + (float)0.48576339, (float)0.47139674, (float)0.45690388, (float)0.44228869, (float)0.42755509, + (float)0.41270703, (float)0.39774847, (float)0.38268343, (float)0.36751594, (float)0.35225005, + (float)0.33688985, (float)0.32143947, (float)0.30590302, (float)0.29028468, (float)0.27458862, + (float)0.25881905, (float)0.24298018, (float)0.22707626, (float)0.21111155, (float)0.19509032, + (float)0.17901686, (float)0.16289547, (float)0.14673047, (float)0.13052619, (float)0.11428696, + (float)0.09801714, (float)0.08172107, (float)0.06540313, (float)0.04906767, (float)0.03271908, + (float)0.01636173 +}; + +// hybrib Hanning & flat window: for 20ms +static const float kBlocks320w512[512] = { + (float)0.00000000, (float)0.00818114, (float)0.01636173, (float)0.02454123, (float)0.03271908, + (float)0.04089475, (float)0.04906767, (float)0.05723732, (float)0.06540313, (float)0.07356456, + (float)0.08172107, (float)0.08987211, (float)0.09801714, (float)0.10615561, (float)0.11428696, + (float)0.12241068, (float)0.13052619, (float)0.13863297, (float)0.14673047, (float)0.15481816, + (float)0.16289547, (float)0.17096189, (float)0.17901686, (float)0.18705985, (float)0.19509032, + (float)0.20310773, (float)0.21111155, (float)0.21910124, (float)0.22707626, (float)0.23503609, + (float)0.24298018, (float)0.25090801, (float)0.25881905, (float)0.26671276, (float)0.27458862, + (float)0.28244610, (float)0.29028468, (float)0.29810383, (float)0.30590302, (float)0.31368174, + (float)0.32143947, (float)0.32917568, (float)0.33688985, (float)0.34458148, (float)0.35225005, + (float)0.35989504, (float)0.36751594, (float)0.37511224, (float)0.38268343, (float)0.39022901, + (float)0.39774847, (float)0.40524131, (float)0.41270703, (float)0.42014512, (float)0.42755509, + (float)0.43493645, (float)0.44228869, (float)0.44961133, (float)0.45690388, (float)0.46416584, + (float)0.47139674, (float)0.47859608, (float)0.48576339, (float)0.49289819, (float)0.50000000, + (float)0.50706834, (float)0.51410274, (float)0.52110274, (float)0.52806785, (float)0.53499762, + (float)0.54189158, (float)0.54874927, (float)0.55557023, (float)0.56235401, (float)0.56910015, + (float)0.57580819, (float)0.58247770, (float)0.58910822, (float)0.59569930, (float)0.60225052, + (float)0.60876143, (float)0.61523159, (float)0.62166057, (float)0.62804795, (float)0.63439328, + (float)0.64069616, (float)0.64695615, (float)0.65317284, (float)0.65934582, (float)0.66547466, + (float)0.67155895, (float)0.67759830, (float)0.68359230, (float)0.68954054, (float)0.69544264, + (float)0.70129818, (float)0.70710678, (float)0.71286806, (float)0.71858162, (float)0.72424708, + (float)0.72986407, (float)0.73543221, (float)0.74095113, (float)0.74642045, (float)0.75183981, + (float)0.75720885, (float)0.76252720, (float)0.76779452, (float)0.77301045, (float)0.77817464, + (float)0.78328675, (float)0.78834643, (float)0.79335334, (float)0.79830715, (float)0.80320753, + (float)0.80805415, (float)0.81284668, (float)0.81758481, (float)0.82226822, (float)0.82689659, + (float)0.83146961, (float)0.83598698, (float)0.84044840, (float)0.84485357, (float)0.84920218, + (float)0.85349396, (float)0.85772861, (float)0.86190585, (float)0.86602540, (float)0.87008699, + (float)0.87409034, (float)0.87803519, (float)0.88192126, (float)0.88574831, (float)0.88951608, + (float)0.89322430, (float)0.89687274, (float)0.90046115, (float)0.90398929, (float)0.90745693, + (float)0.91086382, (float)0.91420976, (float)0.91749450, (float)0.92071783, (float)0.92387953, + (float)0.92697940, (float)0.93001722, (float)0.93299280, (float)0.93590593, (float)0.93875641, + (float)0.94154407, (float)0.94426870, (float)0.94693013, (float)0.94952818, (float)0.95206268, + (float)0.95453345, (float)0.95694034, (float)0.95928317, (float)0.96156180, (float)0.96377607, + (float)0.96592583, (float)0.96801094, (float)0.97003125, (float)0.97198664, (float)0.97387698, + (float)0.97570213, (float)0.97746197, (float)0.97915640, (float)0.98078528, (float)0.98234852, + (float)0.98384601, (float)0.98527764, (float)0.98664333, (float)0.98794298, (float)0.98917651, + (float)0.99034383, (float)0.99144486, (float)0.99247953, (float)0.99344778, (float)0.99434953, + (float)0.99518473, (float)0.99595331, (float)0.99665524, (float)0.99729046, (float)0.99785892, + (float)0.99836060, (float)0.99879546, (float)0.99916346, (float)0.99946459, (float)0.99969882, + (float)0.99986614, (float)0.99996653, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000, + (float)1.00000000, (float)0.99996653, (float)0.99986614, (float)0.99969882, (float)0.99946459, + (float)0.99916346, (float)0.99879546, (float)0.99836060, (float)0.99785892, (float)0.99729046, + (float)0.99665524, (float)0.99595331, (float)0.99518473, (float)0.99434953, (float)0.99344778, + (float)0.99247953, (float)0.99144486, (float)0.99034383, (float)0.98917651, (float)0.98794298, + (float)0.98664333, (float)0.98527764, (float)0.98384601, (float)0.98234852, (float)0.98078528, + (float)0.97915640, (float)0.97746197, (float)0.97570213, (float)0.97387698, (float)0.97198664, + (float)0.97003125, (float)0.96801094, (float)0.96592583, (float)0.96377607, (float)0.96156180, + (float)0.95928317, (float)0.95694034, (float)0.95453345, (float)0.95206268, (float)0.94952818, + (float)0.94693013, (float)0.94426870, (float)0.94154407, (float)0.93875641, (float)0.93590593, + (float)0.93299280, (float)0.93001722, (float)0.92697940, (float)0.92387953, (float)0.92071783, + (float)0.91749450, (float)0.91420976, (float)0.91086382, (float)0.90745693, (float)0.90398929, + (float)0.90046115, (float)0.89687274, (float)0.89322430, (float)0.88951608, (float)0.88574831, + (float)0.88192126, (float)0.87803519, (float)0.87409034, (float)0.87008699, (float)0.86602540, + (float)0.86190585, (float)0.85772861, (float)0.85349396, (float)0.84920218, (float)0.84485357, + (float)0.84044840, (float)0.83598698, (float)0.83146961, (float)0.82689659, (float)0.82226822, + (float)0.81758481, (float)0.81284668, (float)0.80805415, (float)0.80320753, (float)0.79830715, + (float)0.79335334, (float)0.78834643, (float)0.78328675, (float)0.77817464, (float)0.77301045, + (float)0.76779452, (float)0.76252720, (float)0.75720885, (float)0.75183981, (float)0.74642045, + (float)0.74095113, (float)0.73543221, (float)0.72986407, (float)0.72424708, (float)0.71858162, + (float)0.71286806, (float)0.70710678, (float)0.70129818, (float)0.69544264, (float)0.68954054, + (float)0.68359230, (float)0.67759830, (float)0.67155895, (float)0.66547466, (float)0.65934582, + (float)0.65317284, (float)0.64695615, (float)0.64069616, (float)0.63439328, (float)0.62804795, + (float)0.62166057, (float)0.61523159, (float)0.60876143, (float)0.60225052, (float)0.59569930, + (float)0.58910822, (float)0.58247770, (float)0.57580819, (float)0.56910015, (float)0.56235401, + (float)0.55557023, (float)0.54874927, (float)0.54189158, (float)0.53499762, (float)0.52806785, + (float)0.52110274, (float)0.51410274, (float)0.50706834, (float)0.50000000, (float)0.49289819, + (float)0.48576339, (float)0.47859608, (float)0.47139674, (float)0.46416584, (float)0.45690388, + (float)0.44961133, (float)0.44228869, (float)0.43493645, (float)0.42755509, (float)0.42014512, + (float)0.41270703, (float)0.40524131, (float)0.39774847, (float)0.39022901, (float)0.38268343, + (float)0.37511224, (float)0.36751594, (float)0.35989504, (float)0.35225005, (float)0.34458148, + (float)0.33688985, (float)0.32917568, (float)0.32143947, (float)0.31368174, (float)0.30590302, + (float)0.29810383, (float)0.29028468, (float)0.28244610, (float)0.27458862, (float)0.26671276, + (float)0.25881905, (float)0.25090801, (float)0.24298018, (float)0.23503609, (float)0.22707626, + (float)0.21910124, (float)0.21111155, (float)0.20310773, (float)0.19509032, (float)0.18705985, + (float)0.17901686, (float)0.17096189, (float)0.16289547, (float)0.15481816, (float)0.14673047, + (float)0.13863297, (float)0.13052619, (float)0.12241068, (float)0.11428696, (float)0.10615561, + (float)0.09801714, (float)0.08987211, (float)0.08172107, (float)0.07356456, (float)0.06540313, + (float)0.05723732, (float)0.04906767, (float)0.04089475, (float)0.03271908, (float)0.02454123, + (float)0.01636173, (float)0.00818114 +}; + + +// Hanning window: for 15ms at 16kHz with symmetric zeros +static const float kBlocks240w512[512] = { + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00654494, (float)0.01308960, (float)0.01963369, + (float)0.02617695, (float)0.03271908, (float)0.03925982, (float)0.04579887, (float)0.05233596, + (float)0.05887080, (float)0.06540313, (float)0.07193266, (float)0.07845910, (float)0.08498218, + (float)0.09150162, (float)0.09801714, (float)0.10452846, (float)0.11103531, (float)0.11753740, + (float)0.12403446, (float)0.13052620, (float)0.13701233, (float)0.14349262, (float)0.14996676, + (float)0.15643448, (float)0.16289547, (float)0.16934951, (float)0.17579629, (float)0.18223552, + (float)0.18866697, (float)0.19509032, (float)0.20150533, (float)0.20791170, (float)0.21430916, + (float)0.22069745, (float)0.22707628, (float)0.23344538, (float)0.23980446, (float)0.24615330, + (float)0.25249159, (float)0.25881904, (float)0.26513544, (float)0.27144045, (float)0.27773386, + (float)0.28401536, (float)0.29028466, (float)0.29654160, (float)0.30278578, (float)0.30901700, + (float)0.31523499, (float)0.32143945, (float)0.32763019, (float)0.33380687, (float)0.33996925, + (float)0.34611708, (float)0.35225007, (float)0.35836795, (float)0.36447051, (float)0.37055743, + (float)0.37662852, (float)0.38268346, (float)0.38872197, (float)0.39474389, (float)0.40074885, + (float)0.40673664, (float)0.41270703, (float)0.41865975, (float)0.42459452, (float)0.43051112, + (float)0.43640924, (float)0.44228873, (float)0.44814920, (float)0.45399052, (float)0.45981237, + (float)0.46561453, (float)0.47139674, (float)0.47715878, (float)0.48290035, (float)0.48862126, + (float)0.49432120, (float)0.50000000, (float)0.50565743, (float)0.51129311, (float)0.51690692, + (float)0.52249855, (float)0.52806789, (float)0.53361452, (float)0.53913832, (float)0.54463905, + (float)0.55011642, (float)0.55557024, (float)0.56100029, (float)0.56640625, (float)0.57178795, + (float)0.57714522, (float)0.58247769, (float)0.58778524, (float)0.59306765, (float)0.59832460, + (float)0.60355598, (float)0.60876143, (float)0.61394083, (float)0.61909395, (float)0.62422055, + (float)0.62932038, (float)0.63439333, (float)0.63943899, (float)0.64445734, (float)0.64944810, + (float)0.65441096, (float)0.65934587, (float)0.66425246, (float)0.66913062, (float)0.67398012, + (float)0.67880076, (float)0.68359232, (float)0.68835455, (float)0.69308740, (float)0.69779050, + (float)0.70246369, (float)0.70710677, (float)0.71171963, (float)0.71630198, (float)0.72085363, + (float)0.72537440, (float)0.72986406, (float)0.73432255, (float)0.73874950, (float)0.74314487, + (float)0.74750835, (float)0.75183982, (float)0.75613910, (float)0.76040596, (float)0.76464027, + (float)0.76884186, (float)0.77301043, (float)0.77714598, (float)0.78124821, (float)0.78531694, + (float)0.78935206, (float)0.79335338, (float)0.79732066, (float)0.80125386, (float)0.80515265, + (float)0.80901700, (float)0.81284672, (float)0.81664157, (float)0.82040149, (float)0.82412618, + (float)0.82781565, (float)0.83146966, (float)0.83508795, (float)0.83867061, (float)0.84221727, + (float)0.84572780, (float)0.84920216, (float)0.85264021, (float)0.85604161, (float)0.85940641, + (float)0.86273444, (float)0.86602545, (float)0.86927933, (float)0.87249607, (float)0.87567532, + (float)0.87881714, (float)0.88192129, (float)0.88498765, (float)0.88801610, (float)0.89100653, + (float)0.89395881, (float)0.89687276, (float)0.89974827, (float)0.90258533, (float)0.90538365, + (float)0.90814316, (float)0.91086388, (float)0.91354549, (float)0.91618794, (float)0.91879123, + (float)0.92135513, (float)0.92387950, (float)0.92636442, (float)0.92880958, (float)0.93121493, + (float)0.93358046, (float)0.93590593, (float)0.93819135, (float)0.94043654, (float)0.94264150, + (float)0.94480604, (float)0.94693011, (float)0.94901365, (float)0.95105654, (float)0.95305866, + (float)0.95501995, (float)0.95694035, (float)0.95881975, (float)0.96065807, (float)0.96245527, + (float)0.96421117, (float)0.96592581, (float)0.96759909, (float)0.96923089, (float)0.97082120, + (float)0.97236991, (float)0.97387701, (float)0.97534233, (float)0.97676587, (float)0.97814763, + (float)0.97948742, (float)0.98078531, (float)0.98204112, (float)0.98325491, (float)0.98442656, + (float)0.98555607, (float)0.98664331, (float)0.98768836, (float)0.98869103, (float)0.98965138, + (float)0.99056935, (float)0.99144489, (float)0.99227792, (float)0.99306846, (float)0.99381649, + (float)0.99452192, (float)0.99518472, (float)0.99580491, (float)0.99638247, (float)0.99691731, + (float)0.99740952, (float)0.99785894, (float)0.99826562, (float)0.99862951, (float)0.99895066, + (float)0.99922901, (float)0.99946457, (float)0.99965733, (float)0.99980724, (float)0.99991435, + (float)0.99997860, (float)1.00000000, (float)0.99997860, (float)0.99991435, (float)0.99980724, + (float)0.99965733, (float)0.99946457, (float)0.99922901, (float)0.99895066, (float)0.99862951, + (float)0.99826562, (float)0.99785894, (float)0.99740946, (float)0.99691731, (float)0.99638247, + (float)0.99580491, (float)0.99518472, (float)0.99452192, (float)0.99381644, (float)0.99306846, + (float)0.99227792, (float)0.99144489, (float)0.99056935, (float)0.98965138, (float)0.98869103, + (float)0.98768836, (float)0.98664331, (float)0.98555607, (float)0.98442656, (float)0.98325491, + (float)0.98204112, (float)0.98078525, (float)0.97948742, (float)0.97814757, (float)0.97676587, + (float)0.97534227, (float)0.97387695, (float)0.97236991, (float)0.97082120, (float)0.96923089, + (float)0.96759909, (float)0.96592581, (float)0.96421117, (float)0.96245521, (float)0.96065807, + (float)0.95881969, (float)0.95694029, (float)0.95501995, (float)0.95305860, (float)0.95105648, + (float)0.94901365, (float)0.94693011, (float)0.94480604, (float)0.94264150, (float)0.94043654, + (float)0.93819129, (float)0.93590593, (float)0.93358046, (float)0.93121493, (float)0.92880952, + (float)0.92636436, (float)0.92387950, (float)0.92135507, (float)0.91879123, (float)0.91618794, + (float)0.91354543, (float)0.91086382, (float)0.90814310, (float)0.90538365, (float)0.90258527, + (float)0.89974827, (float)0.89687276, (float)0.89395875, (float)0.89100647, (float)0.88801610, + (float)0.88498759, (float)0.88192123, (float)0.87881714, (float)0.87567532, (float)0.87249595, + (float)0.86927933, (float)0.86602539, (float)0.86273432, (float)0.85940641, (float)0.85604161, + (float)0.85264009, (float)0.84920216, (float)0.84572780, (float)0.84221715, (float)0.83867055, + (float)0.83508795, (float)0.83146954, (float)0.82781565, (float)0.82412612, (float)0.82040137, + (float)0.81664157, (float)0.81284660, (float)0.80901700, (float)0.80515265, (float)0.80125374, + (float)0.79732066, (float)0.79335332, (float)0.78935200, (float)0.78531694, (float)0.78124815, + (float)0.77714586, (float)0.77301049, (float)0.76884180, (float)0.76464021, (float)0.76040596, + (float)0.75613904, (float)0.75183970, (float)0.74750835, (float)0.74314481, (float)0.73874938, + (float)0.73432249, (float)0.72986400, (float)0.72537428, (float)0.72085363, (float)0.71630186, + (float)0.71171951, (float)0.70710677, (float)0.70246363, (float)0.69779032, (float)0.69308734, + (float)0.68835449, (float)0.68359220, (float)0.67880070, (float)0.67398006, (float)0.66913044, + (float)0.66425240, (float)0.65934575, (float)0.65441096, (float)0.64944804, (float)0.64445722, + (float)0.63943905, (float)0.63439327, (float)0.62932026, (float)0.62422055, (float)0.61909389, + (float)0.61394072, (float)0.60876143, (float)0.60355592, (float)0.59832448, (float)0.59306765, + (float)0.58778518, (float)0.58247757, (float)0.57714522, (float)0.57178789, (float)0.56640613, + (float)0.56100023, (float)0.55557019, (float)0.55011630, (float)0.54463905, (float)0.53913826, + (float)0.53361434, (float)0.52806783, (float)0.52249849, (float)0.51690674, (float)0.51129305, + (float)0.50565726, (float)0.50000006, (float)0.49432117, (float)0.48862115, (float)0.48290038, + (float)0.47715873, (float)0.47139663, (float)0.46561456, (float)0.45981231, (float)0.45399037, + (float)0.44814920, (float)0.44228864, (float)0.43640912, (float)0.43051112, (float)0.42459446, + (float)0.41865960, (float)0.41270703, (float)0.40673658, (float)0.40074870, (float)0.39474386, + (float)0.38872188, (float)0.38268328, (float)0.37662849, (float)0.37055734, (float)0.36447033, + (float)0.35836792, (float)0.35224995, (float)0.34611690, (float)0.33996922, (float)0.33380675, + (float)0.32763001, (float)0.32143945, (float)0.31523487, (float)0.30901679, (float)0.30278572, + (float)0.29654145, (float)0.29028472, (float)0.28401530, (float)0.27773371, (float)0.27144048, + (float)0.26513538, (float)0.25881892, (float)0.25249159, (float)0.24615324, (float)0.23980433, + (float)0.23344538, (float)0.22707619, (float)0.22069728, (float)0.21430916, (float)0.20791161, + (float)0.20150517, (float)0.19509031, (float)0.18866688, (float)0.18223536, (float)0.17579627, + (float)0.16934940, (float)0.16289529, (float)0.15643445, (float)0.14996666, (float)0.14349243, + (float)0.13701232, (float)0.13052608, (float)0.12403426, (float)0.11753736, (float)0.11103519, + (float)0.10452849, (float)0.09801710, (float)0.09150149, (float)0.08498220, (float)0.07845904, + (float)0.07193252, (float)0.06540315, (float)0.05887074, (float)0.05233581, (float)0.04579888, + (float)0.03925974, (float)0.03271893, (float)0.02617695, (float)0.01963361, (float)0.01308943, + (float)0.00654493, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000 +}; + + +// Hanning window: for 30ms with 1024 fft with symmetric zeros at 16kHz +static const float kBlocks480w1024[1024] = { + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00327249, (float)0.00654494, + (float)0.00981732, (float)0.01308960, (float)0.01636173, (float)0.01963369, (float)0.02290544, + (float)0.02617695, (float)0.02944817, (float)0.03271908, (float)0.03598964, (float)0.03925982, + (float)0.04252957, (float)0.04579887, (float)0.04906768, (float)0.05233596, (float)0.05560368, + (float)0.05887080, (float)0.06213730, (float)0.06540313, (float)0.06866825, (float)0.07193266, + (float)0.07519628, (float)0.07845910, (float)0.08172107, (float)0.08498218, (float)0.08824237, + (float)0.09150162, (float)0.09475989, (float)0.09801714, (float)0.10127335, (float)0.10452846, + (float)0.10778246, (float)0.11103531, (float)0.11428697, (float)0.11753740, (float)0.12078657, + (float)0.12403446, (float)0.12728101, (float)0.13052620, (float)0.13376999, (float)0.13701233, + (float)0.14025325, (float)0.14349262, (float)0.14673047, (float)0.14996676, (float)0.15320145, + (float)0.15643448, (float)0.15966582, (float)0.16289547, (float)0.16612339, (float)0.16934951, + (float)0.17257382, (float)0.17579629, (float)0.17901687, (float)0.18223552, (float)0.18545224, + (float)0.18866697, (float)0.19187967, (float)0.19509032, (float)0.19829889, (float)0.20150533, + (float)0.20470962, (float)0.20791170, (float)0.21111156, (float)0.21430916, (float)0.21750447, + (float)0.22069745, (float)0.22388805, (float)0.22707628, (float)0.23026206, (float)0.23344538, + (float)0.23662618, (float)0.23980446, (float)0.24298020, (float)0.24615330, (float)0.24932377, + (float)0.25249159, (float)0.25565669, (float)0.25881904, (float)0.26197866, (float)0.26513544, + (float)0.26828939, (float)0.27144045, (float)0.27458861, (float)0.27773386, (float)0.28087610, + (float)0.28401536, (float)0.28715158, (float)0.29028466, (float)0.29341471, (float)0.29654160, + (float)0.29966527, (float)0.30278578, (float)0.30590302, (float)0.30901700, (float)0.31212768, + (float)0.31523499, (float)0.31833893, (float)0.32143945, (float)0.32453656, (float)0.32763019, + (float)0.33072028, (float)0.33380687, (float)0.33688986, (float)0.33996925, (float)0.34304500, + (float)0.34611708, (float)0.34918544, (float)0.35225007, (float)0.35531089, (float)0.35836795, + (float)0.36142117, (float)0.36447051, (float)0.36751595, (float)0.37055743, (float)0.37359497, + (float)0.37662852, (float)0.37965801, (float)0.38268346, (float)0.38570479, (float)0.38872197, + (float)0.39173502, (float)0.39474389, (float)0.39774847, (float)0.40074885, (float)0.40374491, + (float)0.40673664, (float)0.40972406, (float)0.41270703, (float)0.41568562, (float)0.41865975, + (float)0.42162940, (float)0.42459452, (float)0.42755508, (float)0.43051112, (float)0.43346250, + (float)0.43640924, (float)0.43935132, (float)0.44228873, (float)0.44522133, (float)0.44814920, + (float)0.45107228, (float)0.45399052, (float)0.45690390, (float)0.45981237, (float)0.46271592, + (float)0.46561453, (float)0.46850815, (float)0.47139674, (float)0.47428030, (float)0.47715878, + (float)0.48003215, (float)0.48290035, (float)0.48576337, (float)0.48862126, (float)0.49147385, + (float)0.49432120, (float)0.49716330, (float)0.50000000, (float)0.50283140, (float)0.50565743, + (float)0.50847799, (float)0.51129311, (float)0.51410276, (float)0.51690692, (float)0.51970553, + (float)0.52249855, (float)0.52528602, (float)0.52806789, (float)0.53084403, (float)0.53361452, + (float)0.53637928, (float)0.53913832, (float)0.54189163, (float)0.54463905, (float)0.54738063, + (float)0.55011642, (float)0.55284631, (float)0.55557024, (float)0.55828828, (float)0.56100029, + (float)0.56370628, (float)0.56640625, (float)0.56910014, (float)0.57178795, (float)0.57446963, + (float)0.57714522, (float)0.57981455, (float)0.58247769, (float)0.58513463, (float)0.58778524, + (float)0.59042960, (float)0.59306765, (float)0.59569931, (float)0.59832460, (float)0.60094351, + (float)0.60355598, (float)0.60616195, (float)0.60876143, (float)0.61135441, (float)0.61394083, + (float)0.61652070, (float)0.61909395, (float)0.62166059, (float)0.62422055, (float)0.62677383, + (float)0.62932038, (float)0.63186020, (float)0.63439333, (float)0.63691956, (float)0.63943899, + (float)0.64195162, (float)0.64445734, (float)0.64695615, (float)0.64944810, (float)0.65193301, + (float)0.65441096, (float)0.65688187, (float)0.65934587, (float)0.66180271, (float)0.66425246, + (float)0.66669512, (float)0.66913062, (float)0.67155898, (float)0.67398012, (float)0.67639405, + (float)0.67880076, (float)0.68120021, (float)0.68359232, (float)0.68597710, (float)0.68835455, + (float)0.69072467, (float)0.69308740, (float)0.69544262, (float)0.69779050, (float)0.70013082, + (float)0.70246369, (float)0.70478904, (float)0.70710677, (float)0.70941699, (float)0.71171963, + (float)0.71401459, (float)0.71630198, (float)0.71858168, (float)0.72085363, (float)0.72311789, + (float)0.72537440, (float)0.72762316, (float)0.72986406, (float)0.73209721, (float)0.73432255, + (float)0.73653996, (float)0.73874950, (float)0.74095118, (float)0.74314487, (float)0.74533057, + (float)0.74750835, (float)0.74967808, (float)0.75183982, (float)0.75399351, (float)0.75613910, + (float)0.75827658, (float)0.76040596, (float)0.76252723, (float)0.76464027, (float)0.76674515, + (float)0.76884186, (float)0.77093029, (float)0.77301043, (float)0.77508241, (float)0.77714598, + (float)0.77920127, (float)0.78124821, (float)0.78328675, (float)0.78531694, (float)0.78733873, + (float)0.78935206, (float)0.79135692, (float)0.79335338, (float)0.79534125, (float)0.79732066, + (float)0.79929149, (float)0.80125386, (float)0.80320752, (float)0.80515265, (float)0.80708915, + (float)0.80901700, (float)0.81093621, (float)0.81284672, (float)0.81474853, (float)0.81664157, + (float)0.81852591, (float)0.82040149, (float)0.82226825, (float)0.82412618, (float)0.82597536, + (float)0.82781565, (float)0.82964706, (float)0.83146966, (float)0.83328325, (float)0.83508795, + (float)0.83688378, (float)0.83867061, (float)0.84044838, (float)0.84221727, (float)0.84397703, + (float)0.84572780, (float)0.84746957, (float)0.84920216, (float)0.85092574, (float)0.85264021, + (float)0.85434544, (float)0.85604161, (float)0.85772866, (float)0.85940641, (float)0.86107504, + (float)0.86273444, (float)0.86438453, (float)0.86602545, (float)0.86765707, (float)0.86927933, + (float)0.87089235, (float)0.87249607, (float)0.87409031, (float)0.87567532, (float)0.87725097, + (float)0.87881714, (float)0.88037390, (float)0.88192129, (float)0.88345921, (float)0.88498765, + (float)0.88650668, (float)0.88801610, (float)0.88951612, (float)0.89100653, (float)0.89248741, + (float)0.89395881, (float)0.89542055, (float)0.89687276, (float)0.89831537, (float)0.89974827, + (float)0.90117162, (float)0.90258533, (float)0.90398932, (float)0.90538365, (float)0.90676826, + (float)0.90814316, (float)0.90950841, (float)0.91086388, (float)0.91220951, (float)0.91354549, + (float)0.91487163, (float)0.91618794, (float)0.91749454, (float)0.91879123, (float)0.92007810, + (float)0.92135513, (float)0.92262226, (float)0.92387950, (float)0.92512691, (float)0.92636442, + (float)0.92759192, (float)0.92880958, (float)0.93001723, (float)0.93121493, (float)0.93240267, + (float)0.93358046, (float)0.93474817, (float)0.93590593, (float)0.93705362, (float)0.93819135, + (float)0.93931901, (float)0.94043654, (float)0.94154406, (float)0.94264150, (float)0.94372880, + (float)0.94480604, (float)0.94587320, (float)0.94693011, (float)0.94797695, (float)0.94901365, + (float)0.95004016, (float)0.95105654, (float)0.95206273, (float)0.95305866, (float)0.95404440, + (float)0.95501995, (float)0.95598525, (float)0.95694035, (float)0.95788521, (float)0.95881975, + (float)0.95974404, (float)0.96065807, (float)0.96156180, (float)0.96245527, (float)0.96333838, + (float)0.96421117, (float)0.96507370, (float)0.96592581, (float)0.96676767, (float)0.96759909, + (float)0.96842021, (float)0.96923089, (float)0.97003126, (float)0.97082120, (float)0.97160077, + (float)0.97236991, (float)0.97312868, (float)0.97387701, (float)0.97461486, (float)0.97534233, + (float)0.97605932, (float)0.97676587, (float)0.97746199, (float)0.97814763, (float)0.97882277, + (float)0.97948742, (float)0.98014158, (float)0.98078531, (float)0.98141843, (float)0.98204112, + (float)0.98265332, (float)0.98325491, (float)0.98384601, (float)0.98442656, (float)0.98499662, + (float)0.98555607, (float)0.98610497, (float)0.98664331, (float)0.98717111, (float)0.98768836, + (float)0.98819500, (float)0.98869103, (float)0.98917651, (float)0.98965138, (float)0.99011570, + (float)0.99056935, (float)0.99101239, (float)0.99144489, (float)0.99186671, (float)0.99227792, + (float)0.99267852, (float)0.99306846, (float)0.99344778, (float)0.99381649, (float)0.99417448, + (float)0.99452192, (float)0.99485862, (float)0.99518472, (float)0.99550015, (float)0.99580491, + (float)0.99609905, (float)0.99638247, (float)0.99665523, (float)0.99691731, (float)0.99716878, + (float)0.99740952, (float)0.99763954, (float)0.99785894, (float)0.99806762, (float)0.99826562, + (float)0.99845290, (float)0.99862951, (float)0.99879545, (float)0.99895066, (float)0.99909520, + (float)0.99922901, (float)0.99935216, (float)0.99946457, (float)0.99956632, (float)0.99965733, + (float)0.99973762, (float)0.99980724, (float)0.99986613, (float)0.99991435, (float)0.99995178, + (float)0.99997860, (float)0.99999464, (float)1.00000000, (float)0.99999464, (float)0.99997860, + (float)0.99995178, (float)0.99991435, (float)0.99986613, (float)0.99980724, (float)0.99973762, + (float)0.99965733, (float)0.99956632, (float)0.99946457, (float)0.99935216, (float)0.99922901, + (float)0.99909520, (float)0.99895066, (float)0.99879545, (float)0.99862951, (float)0.99845290, + (float)0.99826562, (float)0.99806762, (float)0.99785894, (float)0.99763954, (float)0.99740946, + (float)0.99716872, (float)0.99691731, (float)0.99665523, (float)0.99638247, (float)0.99609905, + (float)0.99580491, (float)0.99550015, (float)0.99518472, (float)0.99485862, (float)0.99452192, + (float)0.99417448, (float)0.99381644, (float)0.99344778, (float)0.99306846, (float)0.99267852, + (float)0.99227792, (float)0.99186671, (float)0.99144489, (float)0.99101239, (float)0.99056935, + (float)0.99011564, (float)0.98965138, (float)0.98917651, (float)0.98869103, (float)0.98819494, + (float)0.98768836, (float)0.98717111, (float)0.98664331, (float)0.98610497, (float)0.98555607, + (float)0.98499656, (float)0.98442656, (float)0.98384601, (float)0.98325491, (float)0.98265326, + (float)0.98204112, (float)0.98141843, (float)0.98078525, (float)0.98014158, (float)0.97948742, + (float)0.97882277, (float)0.97814757, (float)0.97746193, (float)0.97676587, (float)0.97605932, + (float)0.97534227, (float)0.97461486, (float)0.97387695, (float)0.97312862, (float)0.97236991, + (float)0.97160077, (float)0.97082120, (float)0.97003126, (float)0.96923089, (float)0.96842015, + (float)0.96759909, (float)0.96676761, (float)0.96592581, (float)0.96507365, (float)0.96421117, + (float)0.96333838, (float)0.96245521, (float)0.96156180, (float)0.96065807, (float)0.95974404, + (float)0.95881969, (float)0.95788515, (float)0.95694029, (float)0.95598525, (float)0.95501995, + (float)0.95404440, (float)0.95305860, (float)0.95206267, (float)0.95105648, (float)0.95004016, + (float)0.94901365, (float)0.94797695, (float)0.94693011, (float)0.94587314, (float)0.94480604, + (float)0.94372880, (float)0.94264150, (float)0.94154406, (float)0.94043654, (float)0.93931895, + (float)0.93819129, (float)0.93705362, (float)0.93590593, (float)0.93474817, (float)0.93358046, + (float)0.93240267, (float)0.93121493, (float)0.93001723, (float)0.92880952, (float)0.92759192, + (float)0.92636436, (float)0.92512691, (float)0.92387950, (float)0.92262226, (float)0.92135507, + (float)0.92007804, (float)0.91879123, (float)0.91749448, (float)0.91618794, (float)0.91487157, + (float)0.91354543, (float)0.91220951, (float)0.91086382, (float)0.90950835, (float)0.90814310, + (float)0.90676820, (float)0.90538365, (float)0.90398932, (float)0.90258527, (float)0.90117157, + (float)0.89974827, (float)0.89831525, (float)0.89687276, (float)0.89542055, (float)0.89395875, + (float)0.89248741, (float)0.89100647, (float)0.88951600, (float)0.88801610, (float)0.88650662, + (float)0.88498759, (float)0.88345915, (float)0.88192123, (float)0.88037384, (float)0.87881714, + (float)0.87725091, (float)0.87567532, (float)0.87409031, (float)0.87249595, (float)0.87089223, + (float)0.86927933, (float)0.86765701, (float)0.86602539, (float)0.86438447, (float)0.86273432, + (float)0.86107504, (float)0.85940641, (float)0.85772860, (float)0.85604161, (float)0.85434544, + (float)0.85264009, (float)0.85092574, (float)0.84920216, (float)0.84746951, (float)0.84572780, + (float)0.84397697, (float)0.84221715, (float)0.84044844, (float)0.83867055, (float)0.83688372, + (float)0.83508795, (float)0.83328319, (float)0.83146954, (float)0.82964706, (float)0.82781565, + (float)0.82597530, (float)0.82412612, (float)0.82226813, (float)0.82040137, (float)0.81852591, + (float)0.81664157, (float)0.81474847, (float)0.81284660, (float)0.81093609, (float)0.80901700, + (float)0.80708915, (float)0.80515265, (float)0.80320752, (float)0.80125374, (float)0.79929143, + (float)0.79732066, (float)0.79534125, (float)0.79335332, (float)0.79135686, (float)0.78935200, + (float)0.78733861, (float)0.78531694, (float)0.78328675, (float)0.78124815, (float)0.77920121, + (float)0.77714586, (float)0.77508223, (float)0.77301049, (float)0.77093029, (float)0.76884180, + (float)0.76674509, (float)0.76464021, (float)0.76252711, (float)0.76040596, (float)0.75827658, + (float)0.75613904, (float)0.75399339, (float)0.75183970, (float)0.74967796, (float)0.74750835, + (float)0.74533057, (float)0.74314481, (float)0.74095106, (float)0.73874938, (float)0.73653996, + (float)0.73432249, (float)0.73209721, (float)0.72986400, (float)0.72762305, (float)0.72537428, + (float)0.72311789, (float)0.72085363, (float)0.71858162, (float)0.71630186, (float)0.71401453, + (float)0.71171951, (float)0.70941705, (float)0.70710677, (float)0.70478898, (float)0.70246363, + (float)0.70013070, (float)0.69779032, (float)0.69544268, (float)0.69308734, (float)0.69072461, + (float)0.68835449, (float)0.68597704, (float)0.68359220, (float)0.68120021, (float)0.67880070, + (float)0.67639399, (float)0.67398006, (float)0.67155886, (float)0.66913044, (float)0.66669512, + (float)0.66425240, (float)0.66180259, (float)0.65934575, (float)0.65688181, (float)0.65441096, + (float)0.65193301, (float)0.64944804, (float)0.64695609, (float)0.64445722, (float)0.64195150, + (float)0.63943905, (float)0.63691956, (float)0.63439327, (float)0.63186014, (float)0.62932026, + (float)0.62677372, (float)0.62422055, (float)0.62166059, (float)0.61909389, (float)0.61652064, + (float)0.61394072, (float)0.61135429, (float)0.60876143, (float)0.60616189, (float)0.60355592, + (float)0.60094339, (float)0.59832448, (float)0.59569913, (float)0.59306765, (float)0.59042960, + (float)0.58778518, (float)0.58513451, (float)0.58247757, (float)0.57981461, (float)0.57714522, + (float)0.57446963, (float)0.57178789, (float)0.56910002, (float)0.56640613, (float)0.56370628, + (float)0.56100023, (float)0.55828822, (float)0.55557019, (float)0.55284619, (float)0.55011630, + (float)0.54738069, (float)0.54463905, (float)0.54189152, (float)0.53913826, (float)0.53637916, + (float)0.53361434, (float)0.53084403, (float)0.52806783, (float)0.52528596, (float)0.52249849, + (float)0.51970541, (float)0.51690674, (float)0.51410276, (float)0.51129305, (float)0.50847787, + (float)0.50565726, (float)0.50283122, (float)0.50000006, (float)0.49716327, (float)0.49432117, + (float)0.49147379, (float)0.48862115, (float)0.48576325, (float)0.48290038, (float)0.48003212, + (float)0.47715873, (float)0.47428021, (float)0.47139663, (float)0.46850798, (float)0.46561456, + (float)0.46271589, (float)0.45981231, (float)0.45690379, (float)0.45399037, (float)0.45107210, + (float)0.44814920, (float)0.44522130, (float)0.44228864, (float)0.43935123, (float)0.43640912, + (float)0.43346232, (float)0.43051112, (float)0.42755505, (float)0.42459446, (float)0.42162928, + (float)0.41865960, (float)0.41568545, (float)0.41270703, (float)0.40972400, (float)0.40673658, + (float)0.40374479, (float)0.40074870, (float)0.39774850, (float)0.39474386, (float)0.39173496, + (float)0.38872188, (float)0.38570464, (float)0.38268328, (float)0.37965804, (float)0.37662849, + (float)0.37359491, (float)0.37055734, (float)0.36751580, (float)0.36447033, (float)0.36142117, + (float)0.35836792, (float)0.35531086, (float)0.35224995, (float)0.34918529, (float)0.34611690, + (float)0.34304500, (float)0.33996922, (float)0.33688980, (float)0.33380675, (float)0.33072016, + (float)0.32763001, (float)0.32453656, (float)0.32143945, (float)0.31833887, (float)0.31523487, + (float)0.31212750, (float)0.30901679, (float)0.30590302, (float)0.30278572, (float)0.29966521, + (float)0.29654145, (float)0.29341453, (float)0.29028472, (float)0.28715155, (float)0.28401530, + (float)0.28087601, (float)0.27773371, (float)0.27458847, (float)0.27144048, (float)0.26828936, + (float)0.26513538, (float)0.26197854, (float)0.25881892, (float)0.25565651, (float)0.25249159, + (float)0.24932374, (float)0.24615324, (float)0.24298008, (float)0.23980433, (float)0.23662600, + (float)0.23344538, (float)0.23026201, (float)0.22707619, (float)0.22388794, (float)0.22069728, + (float)0.21750426, (float)0.21430916, (float)0.21111152, (float)0.20791161, (float)0.20470949, + (float)0.20150517, (float)0.19829892, (float)0.19509031, (float)0.19187963, (float)0.18866688, + (float)0.18545210, (float)0.18223536, (float)0.17901689, (float)0.17579627, (float)0.17257376, + (float)0.16934940, (float)0.16612324, (float)0.16289529, (float)0.15966584, (float)0.15643445, + (float)0.15320137, (float)0.14996666, (float)0.14673033, (float)0.14349243, (float)0.14025325, + (float)0.13701232, (float)0.13376991, (float)0.13052608, (float)0.12728085, (float)0.12403426, + (float)0.12078657, (float)0.11753736, (float)0.11428688, (float)0.11103519, (float)0.10778230, + (float)0.10452849, (float)0.10127334, (float)0.09801710, (float)0.09475980, (float)0.09150149, + (float)0.08824220, (float)0.08498220, (float)0.08172106, (float)0.07845904, (float)0.07519618, + (float)0.07193252, (float)0.06866808, (float)0.06540315, (float)0.06213728, (float)0.05887074, + (float)0.05560357, (float)0.05233581, (float)0.04906749, (float)0.04579888, (float)0.04252954, + (float)0.03925974, (float)0.03598953, (float)0.03271893, (float)0.02944798, (float)0.02617695, + (float)0.02290541, (float)0.01963361, (float)0.01636161, (float)0.01308943, (float)0.00981712, + (float)0.00654493, (float)0.00327244, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000, + (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000 +}; + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_WINDOWS_PRIVATE_H_ diff --git a/libs/miniwebrtc/audio/processing/processing_component.cc b/libs/miniwebrtc/audio/processing/processing_component.cc new file mode 100644 index 00000000..9ac12579 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/processing_component.cc @@ -0,0 +1,112 @@ +/* + * 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 "processing_component.h" + +#include + +#include "audio_processing_impl.h" + +namespace webrtc { + +ProcessingComponent::ProcessingComponent(const AudioProcessingImpl* apm) + : apm_(apm), + initialized_(false), + enabled_(false), + num_handles_(0) {} + +ProcessingComponent::~ProcessingComponent() { + assert(initialized_ == false); +} + +int ProcessingComponent::Destroy() { + while (!handles_.empty()) { + DestroyHandle(handles_.back()); + handles_.pop_back(); + } + initialized_ = false; + + return apm_->kNoError; +} + +int ProcessingComponent::EnableComponent(bool enable) { + if (enable && !enabled_) { + enabled_ = enable; // Must be set before Initialize() is called. + + int err = Initialize(); + if (err != apm_->kNoError) { + enabled_ = false; + return err; + } + } else { + enabled_ = enable; + } + + return apm_->kNoError; +} + +bool ProcessingComponent::is_component_enabled() const { + return enabled_; +} + +void* ProcessingComponent::handle(int index) const { + assert(index < num_handles_); + return handles_[index]; +} + +int ProcessingComponent::num_handles() const { + return num_handles_; +} + +int ProcessingComponent::Initialize() { + if (!enabled_) { + return apm_->kNoError; + } + + num_handles_ = num_handles_required(); + if (num_handles_ > static_cast(handles_.size())) { + handles_.resize(num_handles_, NULL); + } + + assert(static_cast(handles_.size()) >= num_handles_); + for (int i = 0; i < num_handles_; i++) { + if (handles_[i] == NULL) { + handles_[i] = CreateHandle(); + if (handles_[i] == NULL) { + return apm_->kCreationFailedError; + } + } + + int err = InitializeHandle(handles_[i]); + if (err != apm_->kNoError) { + return GetHandleError(handles_[i]); + } + } + + initialized_ = true; + return Configure(); +} + +int ProcessingComponent::Configure() { + if (!initialized_) { + return apm_->kNoError; + } + + assert(static_cast(handles_.size()) >= num_handles_); + for (int i = 0; i < num_handles_; i++) { + int err = ConfigureHandle(handles_[i]); + if (err != apm_->kNoError) { + return GetHandleError(handles_[i]); + } + } + + return apm_->kNoError; +} +} // namespace webrtc diff --git a/libs/miniwebrtc/audio/processing/processing_component.h b/libs/miniwebrtc/audio/processing/processing_component.h new file mode 100644 index 00000000..b3457b50 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/processing_component.h @@ -0,0 +1,53 @@ +/* + * 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_PROCESSING_PROCESSING_COMPONENT_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_PROCESSING_COMPONENT_H_ + +#include + +#include "audio_processing.h" + +namespace webrtc { +class AudioProcessingImpl; + +class ProcessingComponent { + public: + explicit ProcessingComponent(const AudioProcessingImpl* apm); + virtual ~ProcessingComponent(); + + virtual int Initialize(); + virtual int Destroy(); + + bool is_component_enabled() const; + + protected: + virtual int Configure(); + int EnableComponent(bool enable); + void* handle(int index) const; + int num_handles() const; + + private: + virtual void* CreateHandle() const = 0; + virtual int InitializeHandle(void* handle) const = 0; + virtual int ConfigureHandle(void* handle) const = 0; + virtual int DestroyHandle(void* handle) const = 0; + virtual int num_handles_required() const = 0; + virtual int GetHandleError(void* handle) const = 0; + + const AudioProcessingImpl* apm_; + std::vector handles_; + bool initialized_; + bool enabled_; + int num_handles_; +}; +} // namespace webrtc + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_PROCESSING_COMPONENT_H__ diff --git a/libs/miniwebrtc/audio/processing/splitting_filter.cc b/libs/miniwebrtc/audio/processing/splitting_filter.cc new file mode 100644 index 00000000..1526141c --- /dev/null +++ b/libs/miniwebrtc/audio/processing/splitting_filter.cc @@ -0,0 +1,33 @@ +/* + * 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 "splitting_filter.h" +#include "signal_processing_library.h" + +namespace webrtc { + +void SplittingFilterAnalysis(const WebRtc_Word16* in_data, + WebRtc_Word16* low_band, + WebRtc_Word16* high_band, + WebRtc_Word32* filter_state1, + WebRtc_Word32* filter_state2) +{ + WebRtcSpl_AnalysisQMF(in_data, low_band, high_band, filter_state1, filter_state2); +} + +void SplittingFilterSynthesis(const WebRtc_Word16* low_band, + const WebRtc_Word16* high_band, + WebRtc_Word16* out_data, + WebRtc_Word32* filt_state1, + WebRtc_Word32* filt_state2) +{ + WebRtcSpl_SynthesisQMF(low_band, high_band, out_data, filt_state1, filt_state2); +} +} // namespace webrtc diff --git a/libs/miniwebrtc/audio/processing/splitting_filter.h b/libs/miniwebrtc/audio/processing/splitting_filter.h new file mode 100644 index 00000000..661bfb2f --- /dev/null +++ b/libs/miniwebrtc/audio/processing/splitting_filter.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_SPLITTING_FILTER_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_SPLITTING_FILTER_H_ + +#include "typedefs.h" +#include "signal_processing_library.h" + +namespace webrtc { +/* + * SplittingFilterbank_analysisQMF(...) + * + * Splits a super-wb signal into two subbands: 0-8 kHz and 8-16 kHz. + * + * Input: + * - in_data : super-wb audio signal + * + * Input & Output: + * - filt_state1: Filter state for first all-pass filter + * - filt_state2: Filter state for second all-pass filter + * + * Output: + * - low_band : The signal from the 0-4 kHz band + * - high_band : The signal from the 4-8 kHz band + */ +void SplittingFilterAnalysis(const WebRtc_Word16* in_data, + WebRtc_Word16* low_band, + WebRtc_Word16* high_band, + WebRtc_Word32* filt_state1, + WebRtc_Word32* filt_state2); + +/* + * SplittingFilterbank_synthesisQMF(...) + * + * Combines the two subbands (0-8 and 8-16 kHz) into a super-wb signal. + * + * Input: + * - low_band : The signal with the 0-8 kHz band + * - high_band : The signal with the 8-16 kHz band + * + * Input & Output: + * - filt_state1: Filter state for first all-pass filter + * - filt_state2: Filter state for second all-pass filter + * + * Output: + * - out_data : super-wb speech signal + */ +void SplittingFilterSynthesis(const WebRtc_Word16* low_band, + const WebRtc_Word16* high_band, + WebRtc_Word16* out_data, + WebRtc_Word32* filt_state1, + WebRtc_Word32* filt_state2); +} // namespace webrtc + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_MAIN_SOURCE_SPLITTING_FILTER_H_ diff --git a/libs/miniwebrtc/audio/processing/utility/delay_estimator.c b/libs/miniwebrtc/audio/processing/utility/delay_estimator.c new file mode 100644 index 00000000..24ee74d7 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/utility/delay_estimator.c @@ -0,0 +1,319 @@ +/* + * 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 "delay_estimator.h" + +#include +#include +#include + +// Number of right shifts for scaling is linearly depending on number of bits in +// the far-end binary spectrum. +static const int kShiftsAtZero = 13; // Right shifts at zero binary spectrum. +static const int kShiftsLinearSlope = 3; + +static const int32_t kProbabilityOffset = 1024; // 2 in Q9. +static const int32_t kProbabilityLowerLimit = 8704; // 17 in Q9. +static const int32_t kProbabilityMinSpread = 2816; // 5.5 in Q9. + +// Counts and returns number of bits of a 32-bit word. +static int BitCount(uint32_t u32) { + uint32_t tmp = u32 - ((u32 >> 1) & 033333333333) - + ((u32 >> 2) & 011111111111); + tmp = ((tmp + (tmp >> 3)) & 030707070707); + tmp = (tmp + (tmp >> 6)); + tmp = (tmp + (tmp >> 12) + (tmp >> 24)) & 077; + + return ((int) tmp); +} + +// Compares the |binary_vector| with all rows of the |binary_matrix| and counts +// per row the number of times they have the same value. +// +// Inputs: +// - binary_vector : binary "vector" stored in a long +// - binary_matrix : binary "matrix" stored as a vector of long +// - matrix_size : size of binary "matrix" +// +// Output: +// - bit_counts : "Vector" stored as a long, containing for each +// row the number of times the matrix row and the +// input vector have the same value +// +static void BitCountComparison(uint32_t binary_vector, + const uint32_t* binary_matrix, + int matrix_size, + int32_t* bit_counts) { + int n = 0; + + // Compare |binary_vector| with all rows of the |binary_matrix| + for (; n < matrix_size; n++) { + bit_counts[n] = (int32_t) BitCount(binary_vector ^ binary_matrix[n]); + } +} + +int WebRtc_FreeBinaryDelayEstimator(BinaryDelayEstimator* handle) { + assert(handle != NULL); + + if (handle->mean_bit_counts != NULL) { + free(handle->mean_bit_counts); + handle->mean_bit_counts = NULL; + } + if (handle->bit_counts != NULL) { + free(handle->bit_counts); + handle->bit_counts = NULL; + } + if (handle->binary_far_history != NULL) { + free(handle->binary_far_history); + handle->binary_far_history = NULL; + } + if (handle->binary_near_history != NULL) { + free(handle->binary_near_history); + handle->binary_near_history = NULL; + } + if (handle->far_bit_counts != NULL) { + free(handle->far_bit_counts); + handle->far_bit_counts = NULL; + } + + free(handle); + + return 0; +} + +int WebRtc_CreateBinaryDelayEstimator(BinaryDelayEstimator** handle, + int max_delay, + int lookahead) { + BinaryDelayEstimator* self = NULL; + int history_size = max_delay + lookahead; + + if (handle == NULL) { + return -1; + } + if (max_delay < 0) { + return -1; + } + if (lookahead < 0) { + return -1; + } + if (history_size < 2) { + // Must be this large for buffer shifting. + return -1; + } + + self = malloc(sizeof(BinaryDelayEstimator)); + *handle = self; + if (self == NULL) { + return -1; + } + + self->mean_bit_counts = NULL; + self->bit_counts = NULL; + self->binary_far_history = NULL; + self->far_bit_counts = NULL; + + self->history_size = history_size; + self->near_history_size = lookahead + 1; + + // Allocate memory for spectrum buffers. + self->mean_bit_counts = malloc(history_size * sizeof(int32_t)); + if (self->mean_bit_counts == NULL) { + WebRtc_FreeBinaryDelayEstimator(self); + self = NULL; + return -1; + } + self->bit_counts = malloc(history_size * sizeof(int32_t)); + if (self->bit_counts == NULL) { + WebRtc_FreeBinaryDelayEstimator(self); + self = NULL; + return -1; + } + // Allocate memory for history buffers. + self->binary_far_history = malloc(history_size * sizeof(uint32_t)); + if (self->binary_far_history == NULL) { + WebRtc_FreeBinaryDelayEstimator(self); + self = NULL; + return -1; + } + self->binary_near_history = malloc(self->near_history_size * + sizeof(uint32_t)); + if (self->binary_near_history == NULL) { + WebRtc_FreeBinaryDelayEstimator(self); + self = NULL; + return -1; + } + self->far_bit_counts = malloc(history_size * sizeof(int)); + if (self->far_bit_counts == NULL) { + WebRtc_FreeBinaryDelayEstimator(self); + self = NULL; + return -1; + } + + return 0; +} + +int WebRtc_InitBinaryDelayEstimator(BinaryDelayEstimator* handle) { + int i = 0; + assert(handle != NULL); + + memset(handle->bit_counts, 0, sizeof(int32_t) * handle->history_size); + memset(handle->binary_far_history, 0, + sizeof(uint32_t) * handle->history_size); + memset(handle->binary_near_history, 0, + sizeof(uint32_t) * handle->near_history_size); + memset(handle->far_bit_counts, 0, sizeof(int) * handle->history_size); + for (i = 0; i < handle->history_size; ++i) { + handle->mean_bit_counts[i] = (20 << 9); // 20 in Q9. + } + handle->minimum_probability = (32 << 9); // 32 in Q9. + handle->last_delay_probability = (32 << 9); // 32 in Q9. + + // Default return value if we're unable to estimate. -1 is used for errors. + handle->last_delay = -2; + + return 0; +} + +int WebRtc_ProcessBinarySpectrum(BinaryDelayEstimator* handle, + uint32_t binary_far_spectrum, + uint32_t binary_near_spectrum) { + int i = 0; + int candidate_delay = -1; + + int32_t value_best_candidate = 16384; // 32 in Q9, (max |mean_bit_counts|). + int32_t value_worst_candidate = 0; + + assert(handle != NULL); + // Shift binary spectrum history and insert current |binary_far_spectrum|. + memmove(&(handle->binary_far_history[1]), &(handle->binary_far_history[0]), + (handle->history_size - 1) * sizeof(uint32_t)); + handle->binary_far_history[0] = binary_far_spectrum; + + // Shift history of far-end binary spectrum bit counts and insert bit count + // of current |binary_far_spectrum|. + memmove(&(handle->far_bit_counts[1]), &(handle->far_bit_counts[0]), + (handle->history_size - 1) * sizeof(int)); + handle->far_bit_counts[0] = BitCount(binary_far_spectrum); + + if (handle->near_history_size > 1) { + // If we apply lookahead, shift near-end binary spectrum history. Insert + // current |binary_near_spectrum| and pull out the delayed one. + memmove(&(handle->binary_near_history[1]), + &(handle->binary_near_history[0]), + (handle->near_history_size - 1) * sizeof(uint32_t)); + handle->binary_near_history[0] = binary_near_spectrum; + binary_near_spectrum = + handle->binary_near_history[handle->near_history_size - 1]; + } + + // Compare with delayed spectra and store the |bit_counts| for each delay. + BitCountComparison(binary_near_spectrum, + handle->binary_far_history, + handle->history_size, + handle->bit_counts); + + // Update |mean_bit_counts|, which is the smoothed version of |bit_counts|. + for (i = 0; i < handle->history_size; i++) { + // |bit_counts| is constrained to [0, 32], meaning we can smooth with a + // factor up to 2^26. We use Q9. + int32_t bit_count = (handle->bit_counts[i] << 9); // Q9. + + // Update |mean_bit_counts| only when far-end signal has something to + // contribute. If |far_bit_counts| is zero the far-end signal is weak and + // we likely have a poor echo condition, hence don't update. + if (handle->far_bit_counts[i] > 0) { + // Make number of right shifts piecewise linear w.r.t. |far_bit_counts|. + int shifts = kShiftsAtZero; + shifts -= (kShiftsLinearSlope * handle->far_bit_counts[i]) >> 4; + WebRtc_MeanEstimatorFix(bit_count, shifts, &(handle->mean_bit_counts[i])); + } + } + + // Find |candidate_delay|, |value_best_candidate| and |value_worst_candidate| + // of |mean_bit_counts|. + for (i = 0; i < handle->history_size; i++) { + if (handle->mean_bit_counts[i] < value_best_candidate) { + value_best_candidate = handle->mean_bit_counts[i]; + candidate_delay = i; + } + if (handle->mean_bit_counts[i] > value_worst_candidate) { + value_worst_candidate = handle->mean_bit_counts[i]; + } + } + + // The |value_best_candidate| is a good indicator on the probability of + // |candidate_delay| being an accurate delay (a small |value_best_candidate| + // means a good binary match). In the following sections we make a decision + // whether to update |last_delay| or not. + // 1) If the difference bit counts between the best and the worst delay + // candidates is too small we consider the situation to be unreliable and + // don't update |last_delay|. + // 2) If the situation is reliable we update |last_delay| if the value of the + // best candidate delay has a value less than + // i) an adaptive threshold |minimum_probability|, or + // ii) this corresponding value |last_delay_probability|, but updated at + // this time instant. + + // Update |minimum_probability|. + if ((handle->minimum_probability > kProbabilityLowerLimit) && + (value_worst_candidate - value_best_candidate > kProbabilityMinSpread)) { + // The "hard" threshold can't be lower than 17 (in Q9). + // The valley in the curve also has to be distinct, i.e., the + // difference between |value_worst_candidate| and |value_best_candidate| has + // to be large enough. + int32_t threshold = value_best_candidate + kProbabilityOffset; + if (threshold < kProbabilityLowerLimit) { + threshold = kProbabilityLowerLimit; + } + if (handle->minimum_probability > threshold) { + handle->minimum_probability = threshold; + } + } + // Update |last_delay_probability|. + // We use a Markov type model, i.e., a slowly increasing level over time. + handle->last_delay_probability++; + if (value_worst_candidate > value_best_candidate + kProbabilityOffset) { + // Reliable delay value for usage. + if (value_best_candidate < handle->minimum_probability) { + handle->last_delay = candidate_delay; + } + if (value_best_candidate < handle->last_delay_probability) { + handle->last_delay = candidate_delay; + // Reset |last_delay_probability|. + handle->last_delay_probability = value_best_candidate; + } + } + + return handle->last_delay; +} + +int WebRtc_binary_last_delay(BinaryDelayEstimator* handle) { + assert(handle != NULL); + return handle->last_delay; +} + +int WebRtc_history_size(BinaryDelayEstimator* handle) { + assert(handle != NULL); + return handle->history_size; +} + +void WebRtc_MeanEstimatorFix(int32_t new_value, + int factor, + int32_t* mean_value) { + int32_t diff = new_value - *mean_value; + + // mean_new = mean_value + ((new_value - mean_value) >> factor); + if (diff < 0) { + diff = -((-diff) >> factor); + } else { + diff = (diff >> factor); + } + *mean_value += diff; +} diff --git a/libs/miniwebrtc/audio/processing/utility/delay_estimator.h b/libs/miniwebrtc/audio/processing/utility/delay_estimator.h new file mode 100644 index 00000000..a376dfeb --- /dev/null +++ b/libs/miniwebrtc/audio/processing/utility/delay_estimator.h @@ -0,0 +1,128 @@ +/* + * 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. + */ + +// Performs delay estimation on binary converted spectra. +// The return value is 0 - OK and -1 - Error, unless otherwise stated. + +#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_H_ + +#include "typedefs.h" + +typedef struct { + // Pointer to bit counts. + int32_t* mean_bit_counts; + int* far_bit_counts; + + // Array only used locally in ProcessBinarySpectrum() but whose size is + // determined at run-time. + int32_t* bit_counts; + + // Binary history variables. + uint32_t* binary_far_history; + uint32_t* binary_near_history; + + // Delay estimation variables. + int32_t minimum_probability; + int last_delay_probability; + + // Delay memory. + int last_delay; + + // Buffer size. + int history_size; + + // Near-end buffer size. + int near_history_size; +} BinaryDelayEstimator; + +// Releases the memory allocated by WebRtc_CreateBinaryDelayEstimator(...). +// Input: +// - handle : Pointer to the delay estimation instance. +// +int WebRtc_FreeBinaryDelayEstimator(BinaryDelayEstimator* handle); + +// Refer to WebRtc_CreateDelayEstimator() in delay_estimator_wrapper.h. +int WebRtc_CreateBinaryDelayEstimator(BinaryDelayEstimator** handle, + int max_delay, + int lookahead); + +// Initializes the delay estimation instance created with +// WebRtc_CreateBinaryDelayEstimator(...). +// Input: +// - handle : Pointer to the delay estimation instance. +// +// Output: +// - handle : Initialized instance. +// +int WebRtc_InitBinaryDelayEstimator(BinaryDelayEstimator* handle); + +// Estimates and returns the delay between the binary far-end and binary near- +// end spectra. The value will be offset by the lookahead (i.e. the lookahead +// should be subtracted from the returned value). +// Inputs: +// - handle : Pointer to the delay estimation instance. +// - binary_far_spectrum : Far-end binary spectrum. +// - binary_near_spectrum : Near-end binary spectrum of the current block. +// +// Output: +// - handle : Updated instance. +// +// Return value: +// - delay : >= 0 - Calculated delay value. +// -1 - Error. +// -2 - Insufficient data for estimation. +// +int WebRtc_ProcessBinarySpectrum(BinaryDelayEstimator* handle, + uint32_t binary_far_spectrum, + uint32_t binary_near_spectrum); + +// Returns the last calculated delay updated by the function +// WebRtc_ProcessBinarySpectrum(...). +// +// Input: +// - handle : Pointer to the delay estimation instance. +// +// Return value: +// - delay : >= 0 - Last calculated delay value +// -1 - Error +// -2 - Insufficient data for estimation. +// +int WebRtc_binary_last_delay(BinaryDelayEstimator* handle); + +// Returns the history size used in the far-end buffers to calculate the delay +// over. +// +// Input: +// - handle : Pointer to the delay estimation instance. +// +// Return value: +// - history_size : > 0 - Far-end history size. +// -1 - Error. +// +int WebRtc_history_size(BinaryDelayEstimator* handle); + +// Updates the |mean_value| recursively with a step size of 2^-|factor|. This +// function is used internally in the Binary Delay Estimator as well as the +// Fixed point wrapper. +// +// Inputs: +// - new_value : The new value the mean should be updated with. +// - factor : The step size, in number of right shifts. +// +// Input/Output: +// - mean_value : Pointer to the mean value. +// +void WebRtc_MeanEstimatorFix(int32_t new_value, + int factor, + int32_t* mean_value); + + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_H_ diff --git a/libs/miniwebrtc/audio/processing/utility/delay_estimator_wrapper.c b/libs/miniwebrtc/audio/processing/utility/delay_estimator_wrapper.c new file mode 100644 index 00000000..438c95f5 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/utility/delay_estimator_wrapper.c @@ -0,0 +1,336 @@ +/* + * 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 "delay_estimator_wrapper.h" + +#include +#include +#include + +#include "delay_estimator.h" + +typedef union { + float float_; + int32_t int32_; +} SpectrumType; + +typedef struct { + // Pointers to mean values of spectrum. + SpectrumType* mean_far_spectrum; + SpectrumType* mean_near_spectrum; + // |mean_*_spectrum| initialization indicator. + int far_spectrum_initialized; + int near_spectrum_initialized; + + int spectrum_size; + + // Binary spectrum based delay estimator + BinaryDelayEstimator* binary_handle; +} DelayEstimator; + +// Only bit |kBandFirst| through bit |kBandLast| are processed and +// |kBandFirst| - |kBandLast| must be < 32. +static const int kBandFirst = 12; +static const int kBandLast = 43; + +static __inline uint32_t SetBit(uint32_t in, int pos) { + uint32_t mask = (1 << pos); + uint32_t out = (in | mask); + + return out; +} + +// Calculates the mean recursively. Same version as WebRtc_MeanEstimatorFix(), +// but for float. +// +// Inputs: +// - new_value : New additional value. +// - scale : Scale for smoothing (should be less than 1.0). +// +// Input/Output: +// - mean_value : Pointer to the mean value for updating. +// +static void MeanEstimatorFloat(float new_value, + float scale, + float* mean_value) { + assert(scale < 1.0f); + *mean_value += (new_value - *mean_value) * scale; +} + +// Computes the binary spectrum by comparing the input |spectrum| with a +// |threshold_spectrum|. Float and fixed point versions. +// +// Inputs: +// - spectrum : Spectrum of which the binary spectrum should be +// calculated. +// - threshold_spectrum : Threshold spectrum with which the input +// spectrum is compared. +// Return: +// - out : Binary spectrum. +// +static uint32_t BinarySpectrumFix(uint16_t* spectrum, + SpectrumType* threshold_spectrum, + int q_domain, + int* threshold_initialized) { + int i = kBandFirst; + uint32_t out = 0; + + assert(q_domain < 16); + + if (!(*threshold_initialized)) { + // Set the |threshold_spectrum| to half the input |spectrum| as starting + // value. This speeds up the convergence. + for (i = kBandFirst; i <= kBandLast; i++) { + if (spectrum[i] > 0) { + // Convert input spectrum from Q(|q_domain|) to Q15. + int32_t spectrum_q15 = ((int32_t) spectrum[i]) << (15 - q_domain); + threshold_spectrum[i].int32_ = (spectrum_q15 >> 1); + *threshold_initialized = 1; + } + } + } + for (i = kBandFirst; i <= kBandLast; i++) { + // Convert input spectrum from Q(|q_domain|) to Q15. + int32_t spectrum_q15 = ((int32_t) spectrum[i]) << (15 - q_domain); + // Update the |threshold_spectrum|. + WebRtc_MeanEstimatorFix(spectrum_q15, 6, &(threshold_spectrum[i].int32_)); + // Convert |spectrum| at current frequency bin to a binary value. + if (spectrum_q15 > threshold_spectrum[i].int32_) { + out = SetBit(out, i - kBandFirst); + } + } + + return out; +} + +static uint32_t BinarySpectrumFloat(float* spectrum, + SpectrumType* threshold_spectrum, + int* threshold_initialized) { + int i = kBandFirst; + uint32_t out = 0; + const float kScale = 1 / 64.0; + + if (!(*threshold_initialized)) { + // Set the |threshold_spectrum| to half the input |spectrum| as starting + // value. This speeds up the convergence. + for (i = kBandFirst; i <= kBandLast; i++) { + if (spectrum[i] > 0.0f) { + threshold_spectrum[i].float_ = (spectrum[i] / 2); + *threshold_initialized = 1; + } + } + } + + for (i = kBandFirst; i <= kBandLast; i++) { + // Update the |threshold_spectrum|. + MeanEstimatorFloat(spectrum[i], kScale, &(threshold_spectrum[i].float_)); + // Convert |spectrum| at current frequency bin to a binary value. + if (spectrum[i] > threshold_spectrum[i].float_) { + out = SetBit(out, i - kBandFirst); + } + } + + return out; +} + +int WebRtc_FreeDelayEstimator(void* handle) { + DelayEstimator* self = (DelayEstimator*) handle; + + if (self == NULL) { + return -1; + } + + if (self->mean_far_spectrum != NULL) { + free(self->mean_far_spectrum); + self->mean_far_spectrum = NULL; + } + if (self->mean_near_spectrum != NULL) { + free(self->mean_near_spectrum); + self->mean_near_spectrum = NULL; + } + + WebRtc_FreeBinaryDelayEstimator(self->binary_handle); + + free(self); + + return 0; +} + +int WebRtc_CreateDelayEstimator(void** handle, + int spectrum_size, + int max_delay, + int lookahead) { + DelayEstimator* self = NULL; + + // Check if the sub band used in the delay estimation is small enough to fit + // the binary spectra in a uint32_t. + assert(kBandLast - kBandFirst < 32); + + if (handle == NULL) { + return -1; + } + if (spectrum_size < kBandLast) { + return -1; + } + + self = malloc(sizeof(DelayEstimator)); + *handle = self; + if (self == NULL) { + return -1; + } + + self->mean_far_spectrum = NULL; + self->mean_near_spectrum = NULL; + + // Create binary delay estimator. + if (WebRtc_CreateBinaryDelayEstimator(&self->binary_handle, + max_delay, + lookahead) != 0) { + WebRtc_FreeDelayEstimator(self); + self = NULL; + return -1; + } + // Allocate memory for spectrum buffers. + self->mean_far_spectrum = malloc(spectrum_size * sizeof(SpectrumType)); + if (self->mean_far_spectrum == NULL) { + WebRtc_FreeDelayEstimator(self); + self = NULL; + return -1; + } + self->mean_near_spectrum = malloc(spectrum_size * sizeof(SpectrumType)); + if (self->mean_near_spectrum == NULL) { + WebRtc_FreeDelayEstimator(self); + self = NULL; + return -1; + } + + self->spectrum_size = spectrum_size; + + return 0; +} + +int WebRtc_InitDelayEstimator(void* handle) { + DelayEstimator* self = (DelayEstimator*) handle; + + if (self == NULL) { + return -1; + } + + // Initialize binary delay estimator. + if (WebRtc_InitBinaryDelayEstimator(self->binary_handle) != 0) { + return -1; + } + // Set averaged far and near end spectra to zero. + memset(self->mean_far_spectrum, 0, + sizeof(SpectrumType) * self->spectrum_size); + memset(self->mean_near_spectrum, 0, + sizeof(SpectrumType) * self->spectrum_size); + // Reset initialization indicators. + self->far_spectrum_initialized = 0; + self->near_spectrum_initialized = 0; + + return 0; +} + +int WebRtc_DelayEstimatorProcessFix(void* handle, + uint16_t* far_spectrum, + uint16_t* near_spectrum, + int spectrum_size, + int far_q, + int near_q) { + DelayEstimator* self = (DelayEstimator*) handle; + uint32_t binary_far_spectrum = 0; + uint32_t binary_near_spectrum = 0; + + if (self == NULL) { + return -1; + } + if (far_spectrum == NULL) { + // Empty far end spectrum. + return -1; + } + if (near_spectrum == NULL) { + // Empty near end spectrum. + return -1; + } + if (spectrum_size != self->spectrum_size) { + // Data sizes don't match. + return -1; + } + if (far_q > 15) { + // If |far_q| is larger than 15 we cannot guarantee no wrap around. + return -1; + } + if (near_q > 15) { + // If |near_q| is larger than 15 we cannot guarantee no wrap around. + return -1; + } + + // Get binary spectra. + binary_far_spectrum = BinarySpectrumFix(far_spectrum, + self->mean_far_spectrum, + far_q, + &(self->far_spectrum_initialized)); + binary_near_spectrum = BinarySpectrumFix(near_spectrum, + self->mean_near_spectrum, + near_q, + &(self->near_spectrum_initialized)); + + return WebRtc_ProcessBinarySpectrum(self->binary_handle, + binary_far_spectrum, + binary_near_spectrum); +} + +int WebRtc_DelayEstimatorProcessFloat(void* handle, + float* far_spectrum, + float* near_spectrum, + int spectrum_size) { + DelayEstimator* self = (DelayEstimator*) handle; + uint32_t binary_far_spectrum = 0; + uint32_t binary_near_spectrum = 0; + + if (self == NULL) { + return -1; + } + if (far_spectrum == NULL) { + // Empty far end spectrum. + return -1; + } + if (near_spectrum == NULL) { + // Empty near end spectrum. + return -1; + } + if (spectrum_size != self->spectrum_size) { + // Data sizes don't match. + return -1; + } + + // Get binary spectra. + binary_far_spectrum = BinarySpectrumFloat(far_spectrum, + self->mean_far_spectrum, + &(self->far_spectrum_initialized)); + binary_near_spectrum = BinarySpectrumFloat(near_spectrum, + self->mean_near_spectrum, + &(self->near_spectrum_initialized)); + + return WebRtc_ProcessBinarySpectrum(self->binary_handle, + binary_far_spectrum, + binary_near_spectrum); +} + +int WebRtc_last_delay(void* handle) { + DelayEstimator* self = (DelayEstimator*) handle; + + if (self == NULL) { + return -1; + } + + return WebRtc_binary_last_delay(self->binary_handle); +} diff --git a/libs/miniwebrtc/audio/processing/utility/delay_estimator_wrapper.h b/libs/miniwebrtc/audio/processing/utility/delay_estimator_wrapper.h new file mode 100644 index 00000000..2a47b5d8 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/utility/delay_estimator_wrapper.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// Performs delay estimation on block by block basis. +// The return value is 0 - OK and -1 - Error, unless otherwise stated. + +#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_WRAPPER_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_WRAPPER_H_ + +#include "typedefs.h" + +// Releases the memory allocated by WebRtc_CreateDelayEstimator(...) +// Input: +// - handle : Pointer to the delay estimation instance. +// +int WebRtc_FreeDelayEstimator(void* handle); + +// Allocates the memory needed by the delay estimation. The memory needs to be +// initialized separately through WebRtc_InitDelayEstimator(...). +// +// Inputs: +// - handle : Instance that should be created. +// - spectrum_size : Size of the spectrum used both in far-end and +// near-end. Used to allocate memory for spectrum +// specific buffers. +// - max_delay : The maximum delay which can be estimated. Needed to +// allocate memory for history buffers. +// - lookahead : Amount of non-causal lookahead to use. This can +// detect cases in which a near-end signal occurs before +// the corresponding far-end signal. It will delay the +// estimate for the current block by an equal amount, +// and the returned values will be offset by it. +// +// A value of zero is the typical no-lookahead case. +// This also represents the minimum delay which can be +// estimated. +// +// Output: +// - handle : Created instance. +// +int WebRtc_CreateDelayEstimator(void** handle, + int spectrum_size, + int max_delay, + int lookahead); + +// Initializes the delay estimation instance created with +// WebRtc_CreateDelayEstimator(...) +// Input: +// - handle : Pointer to the delay estimation instance. +// +// Output: +// - handle : Initialized instance. +// +int WebRtc_InitDelayEstimator(void* handle); + +// Estimates and returns the delay between the far-end and near-end blocks. The +// value will be offset by the lookahead (i.e. the lookahead should be +// subtracted from the returned value). +// Inputs: +// - handle : Pointer to the delay estimation instance. +// - far_spectrum : Pointer to the far-end spectrum data. +// - near_spectrum : Pointer to the near-end spectrum data of the current +// block. +// - spectrum_size : The size of the data arrays (same for both far- and +// near-end). +// - far_q : The Q-domain of the far-end data. +// - near_q : The Q-domain of the near-end data. +// +// Output: +// - handle : Updated instance. +// +// Return value: +// - delay : >= 0 - Calculated delay value. +// -1 - Error. +// -2 - Insufficient data for estimation. +// +int WebRtc_DelayEstimatorProcessFix(void* handle, + uint16_t* far_spectrum, + uint16_t* near_spectrum, + int spectrum_size, + int far_q, + int near_q); + +// See WebRtc_DelayEstimatorProcessFix() for description. +int WebRtc_DelayEstimatorProcessFloat(void* handle, + float* far_spectrum, + float* near_spectrum, + int spectrum_size); + +// Returns the last calculated delay updated by the function +// WebRtc_DelayEstimatorProcess(...). +// +// Input: +// - handle : Pointer to the delay estimation instance. +// +// Return value: +// - delay : >= 0 - Last calculated delay value. +// -1 - Error. +// -2 - Insufficient data for estimation. +// +int WebRtc_last_delay(void* handle); + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_DELAY_ESTIMATOR_WRAPPER_H_ diff --git a/libs/miniwebrtc/audio/processing/utility/fft4g.c b/libs/miniwebrtc/audio/processing/utility/fft4g.c new file mode 100644 index 00000000..cbc4dc31 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/utility/fft4g.c @@ -0,0 +1,1326 @@ +/* + * http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html + * Copyright Takuya OOURA, 1996-2001 + * + * You may use, copy, modify and distribute this code for any purpose (include + * commercial use) and without fee. Please refer to this package when you modify + * this code. + * + * Changes: + * Trivial type modifications by the WebRTC authors. + */ + +/* +Fast Fourier/Cosine/Sine Transform + dimension :one + data length :power of 2 + decimation :frequency + radix :4, 2 + data :inplace + table :use +functions + cdft: Complex Discrete Fourier Transform + rdft: Real Discrete Fourier Transform + ddct: Discrete Cosine Transform + ddst: Discrete Sine Transform + dfct: Cosine Transform of RDFT (Real Symmetric DFT) + dfst: Sine Transform of RDFT (Real Anti-symmetric DFT) +function prototypes + void cdft(int, int, float *, int *, float *); + void rdft(int, int, float *, int *, float *); + void ddct(int, int, float *, int *, float *); + void ddst(int, int, float *, int *, float *); + void dfct(int, float *, float *, int *, float *); + void dfst(int, float *, float *, int *, float *); + + +-------- Complex DFT (Discrete Fourier Transform) -------- + [definition] + + X[k] = sum_j=0^n-1 x[j]*exp(2*pi*i*j*k/n), 0<=k + X[k] = sum_j=0^n-1 x[j]*exp(-2*pi*i*j*k/n), 0<=k + ip[0] = 0; // first time only + cdft(2*n, 1, a, ip, w); + + ip[0] = 0; // first time only + cdft(2*n, -1, a, ip, w); + [parameters] + 2*n :data length (int) + n >= 1, n = power of 2 + a[0...2*n-1] :input/output data (float *) + input data + a[2*j] = Re(x[j]), + a[2*j+1] = Im(x[j]), 0<=j= 2+sqrt(n) + strictly, + length of ip >= + 2+(1<<(int)(log(n+0.5)/log(2))/2). + ip[0],ip[1] are pointers of the cos/sin table. + w[0...n/2-1] :cos/sin table (float *) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + cdft(2*n, -1, a, ip, w); + is + cdft(2*n, 1, a, ip, w); + for (j = 0; j <= 2 * n - 1; j++) { + a[j] *= 1.0 / n; + } + . + + +-------- Real DFT / Inverse of Real DFT -------- + [definition] + RDFT + R[k] = sum_j=0^n-1 a[j]*cos(2*pi*j*k/n), 0<=k<=n/2 + I[k] = sum_j=0^n-1 a[j]*sin(2*pi*j*k/n), 0 IRDFT (excluding scale) + a[k] = (R[0] + R[n/2]*cos(pi*k))/2 + + sum_j=1^n/2-1 R[j]*cos(2*pi*j*k/n) + + sum_j=1^n/2-1 I[j]*sin(2*pi*j*k/n), 0<=k + ip[0] = 0; // first time only + rdft(n, 1, a, ip, w); + + ip[0] = 0; // first time only + rdft(n, -1, a, ip, w); + [parameters] + n :data length (int) + n >= 2, n = power of 2 + a[0...n-1] :input/output data (float *) + + output data + a[2*k] = R[k], 0<=k + input data + a[2*j] = R[j], 0<=j= 2+sqrt(n/2) + strictly, + length of ip >= + 2+(1<<(int)(log(n/2+0.5)/log(2))/2). + ip[0],ip[1] are pointers of the cos/sin table. + w[0...n/2-1] :cos/sin table (float *) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + rdft(n, 1, a, ip, w); + is + rdft(n, -1, a, ip, w); + for (j = 0; j <= n - 1; j++) { + a[j] *= 2.0 / n; + } + . + + +-------- DCT (Discrete Cosine Transform) / Inverse of DCT -------- + [definition] + IDCT (excluding scale) + C[k] = sum_j=0^n-1 a[j]*cos(pi*j*(k+1/2)/n), 0<=k DCT + C[k] = sum_j=0^n-1 a[j]*cos(pi*(j+1/2)*k/n), 0<=k + ip[0] = 0; // first time only + ddct(n, 1, a, ip, w); + + ip[0] = 0; // first time only + ddct(n, -1, a, ip, w); + [parameters] + n :data length (int) + n >= 2, n = power of 2 + a[0...n-1] :input/output data (float *) + output data + a[k] = C[k], 0<=k= 2+sqrt(n/2) + strictly, + length of ip >= + 2+(1<<(int)(log(n/2+0.5)/log(2))/2). + ip[0],ip[1] are pointers of the cos/sin table. + w[0...n*5/4-1] :cos/sin table (float *) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + ddct(n, -1, a, ip, w); + is + a[0] *= 0.5; + ddct(n, 1, a, ip, w); + for (j = 0; j <= n - 1; j++) { + a[j] *= 2.0 / n; + } + . + + +-------- DST (Discrete Sine Transform) / Inverse of DST -------- + [definition] + IDST (excluding scale) + S[k] = sum_j=1^n A[j]*sin(pi*j*(k+1/2)/n), 0<=k DST + S[k] = sum_j=0^n-1 a[j]*sin(pi*(j+1/2)*k/n), 0 + ip[0] = 0; // first time only + ddst(n, 1, a, ip, w); + + ip[0] = 0; // first time only + ddst(n, -1, a, ip, w); + [parameters] + n :data length (int) + n >= 2, n = power of 2 + a[0...n-1] :input/output data (float *) + + input data + a[j] = A[j], 0 + output data + a[k] = S[k], 0= 2+sqrt(n/2) + strictly, + length of ip >= + 2+(1<<(int)(log(n/2+0.5)/log(2))/2). + ip[0],ip[1] are pointers of the cos/sin table. + w[0...n*5/4-1] :cos/sin table (float *) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + ddst(n, -1, a, ip, w); + is + a[0] *= 0.5; + ddst(n, 1, a, ip, w); + for (j = 0; j <= n - 1; j++) { + a[j] *= 2.0 / n; + } + . + + +-------- Cosine Transform of RDFT (Real Symmetric DFT) -------- + [definition] + C[k] = sum_j=0^n a[j]*cos(pi*j*k/n), 0<=k<=n + [usage] + ip[0] = 0; // first time only + dfct(n, a, t, ip, w); + [parameters] + n :data length - 1 (int) + n >= 2, n = power of 2 + a[0...n] :input/output data (float *) + output data + a[k] = C[k], 0<=k<=n + t[0...n/2] :work area (float *) + ip[0...*] :work area for bit reversal (int *) + length of ip >= 2+sqrt(n/4) + strictly, + length of ip >= + 2+(1<<(int)(log(n/4+0.5)/log(2))/2). + ip[0],ip[1] are pointers of the cos/sin table. + w[0...n*5/8-1] :cos/sin table (float *) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + a[0] *= 0.5; + a[n] *= 0.5; + dfct(n, a, t, ip, w); + is + a[0] *= 0.5; + a[n] *= 0.5; + dfct(n, a, t, ip, w); + for (j = 0; j <= n; j++) { + a[j] *= 2.0 / n; + } + . + + +-------- Sine Transform of RDFT (Real Anti-symmetric DFT) -------- + [definition] + S[k] = sum_j=1^n-1 a[j]*sin(pi*j*k/n), 0= 2, n = power of 2 + a[0...n-1] :input/output data (float *) + output data + a[k] = S[k], 0= 2+sqrt(n/4) + strictly, + length of ip >= + 2+(1<<(int)(log(n/4+0.5)/log(2))/2). + ip[0],ip[1] are pointers of the cos/sin table. + w[0...n*5/8-1] :cos/sin table (float *) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + dfst(n, a, t, ip, w); + is + dfst(n, a, t, ip, w); + for (j = 1; j <= n - 1; j++) { + a[j] *= 2.0 / n; + } + . + + +Appendix : + The cos/sin table is recalculated when the larger table required. + w[] and ip[] are compatible with all routines. +*/ + +static void makewt(int nw, int *ip, float *w); +static void makect(int nc, int *ip, float *c); +static void bitrv2(int n, int *ip, float *a); +static void bitrv2conj(int n, int *ip, float *a); +static void cftfsub(int n, float *a, float *w); +static void cftbsub(int n, float *a, float *w); +static void cft1st(int n, float *a, float *w); +static void cftmdl(int n, int l, float *a, float *w); +static void rftfsub(int n, float *a, int nc, float *c); +static void rftbsub(int n, float *a, int nc, float *c); +#if 0 // Not used. +static void dctsub(int n, float *a, int nc, float *c) +static void dstsub(int n, float *a, int nc, float *c) +#endif + + +void WebRtc_cdft(int n, int isgn, float *a, int *ip, float *w) +{ + if (n > (ip[0] << 2)) { + makewt(n >> 2, ip, w); + } + if (n > 4) { + if (isgn >= 0) { + bitrv2(n, ip + 2, a); + cftfsub(n, a, w); + } else { + bitrv2conj(n, ip + 2, a); + cftbsub(n, a, w); + } + } else if (n == 4) { + cftfsub(n, a, w); + } +} + + +void WebRtc_rdft(int n, int isgn, float *a, int *ip, float *w) +{ + int nw, nc; + float xi; + + nw = ip[0]; + if (n > (nw << 2)) { + nw = n >> 2; + makewt(nw, ip, w); + } + nc = ip[1]; + if (n > (nc << 2)) { + nc = n >> 2; + makect(nc, ip, w + nw); + } + if (isgn >= 0) { + if (n > 4) { + bitrv2(n, ip + 2, a); + cftfsub(n, a, w); + rftfsub(n, a, nc, w + nw); + } else if (n == 4) { + cftfsub(n, a, w); + } + xi = a[0] - a[1]; + a[0] += a[1]; + a[1] = xi; + } else { + a[1] = 0.5f * (a[0] - a[1]); + a[0] -= a[1]; + if (n > 4) { + rftbsub(n, a, nc, w + nw); + bitrv2(n, ip + 2, a); + cftbsub(n, a, w); + } else if (n == 4) { + cftfsub(n, a, w); + } + } +} + +#if 0 // Not used. +static void ddct(int n, int isgn, float *a, int *ip, float *w) +{ + int j, nw, nc; + float xr; + + nw = ip[0]; + if (n > (nw << 2)) { + nw = n >> 2; + makewt(nw, ip, w); + } + nc = ip[1]; + if (n > nc) { + nc = n; + makect(nc, ip, w + nw); + } + if (isgn < 0) { + xr = a[n - 1]; + for (j = n - 2; j >= 2; j -= 2) { + a[j + 1] = a[j] - a[j - 1]; + a[j] += a[j - 1]; + } + a[1] = a[0] - xr; + a[0] += xr; + if (n > 4) { + rftbsub(n, a, nc, w + nw); + bitrv2(n, ip + 2, a); + cftbsub(n, a, w); + } else if (n == 4) { + cftfsub(n, a, w); + } + } + dctsub(n, a, nc, w + nw); + if (isgn >= 0) { + if (n > 4) { + bitrv2(n, ip + 2, a); + cftfsub(n, a, w); + rftfsub(n, a, nc, w + nw); + } else if (n == 4) { + cftfsub(n, a, w); + } + xr = a[0] - a[1]; + a[0] += a[1]; + for (j = 2; j < n; j += 2) { + a[j - 1] = a[j] - a[j + 1]; + a[j] += a[j + 1]; + } + a[n - 1] = xr; + } +} + + +static void ddst(int n, int isgn, float *a, int *ip, float *w) +{ + int j, nw, nc; + float xr; + + nw = ip[0]; + if (n > (nw << 2)) { + nw = n >> 2; + makewt(nw, ip, w); + } + nc = ip[1]; + if (n > nc) { + nc = n; + makect(nc, ip, w + nw); + } + if (isgn < 0) { + xr = a[n - 1]; + for (j = n - 2; j >= 2; j -= 2) { + a[j + 1] = -a[j] - a[j - 1]; + a[j] -= a[j - 1]; + } + a[1] = a[0] + xr; + a[0] -= xr; + if (n > 4) { + rftbsub(n, a, nc, w + nw); + bitrv2(n, ip + 2, a); + cftbsub(n, a, w); + } else if (n == 4) { + cftfsub(n, a, w); + } + } + dstsub(n, a, nc, w + nw); + if (isgn >= 0) { + if (n > 4) { + bitrv2(n, ip + 2, a); + cftfsub(n, a, w); + rftfsub(n, a, nc, w + nw); + } else if (n == 4) { + cftfsub(n, a, w); + } + xr = a[0] - a[1]; + a[0] += a[1]; + for (j = 2; j < n; j += 2) { + a[j - 1] = -a[j] - a[j + 1]; + a[j] -= a[j + 1]; + } + a[n - 1] = -xr; + } +} + + +static void dfct(int n, float *a, float *t, int *ip, float *w) +{ + int j, k, l, m, mh, nw, nc; + float xr, xi, yr, yi; + + nw = ip[0]; + if (n > (nw << 3)) { + nw = n >> 3; + makewt(nw, ip, w); + } + nc = ip[1]; + if (n > (nc << 1)) { + nc = n >> 1; + makect(nc, ip, w + nw); + } + m = n >> 1; + yi = a[m]; + xi = a[0] + a[n]; + a[0] -= a[n]; + t[0] = xi - yi; + t[m] = xi + yi; + if (n > 2) { + mh = m >> 1; + for (j = 1; j < mh; j++) { + k = m - j; + xr = a[j] - a[n - j]; + xi = a[j] + a[n - j]; + yr = a[k] - a[n - k]; + yi = a[k] + a[n - k]; + a[j] = xr; + a[k] = yr; + t[j] = xi - yi; + t[k] = xi + yi; + } + t[mh] = a[mh] + a[n - mh]; + a[mh] -= a[n - mh]; + dctsub(m, a, nc, w + nw); + if (m > 4) { + bitrv2(m, ip + 2, a); + cftfsub(m, a, w); + rftfsub(m, a, nc, w + nw); + } else if (m == 4) { + cftfsub(m, a, w); + } + a[n - 1] = a[0] - a[1]; + a[1] = a[0] + a[1]; + for (j = m - 2; j >= 2; j -= 2) { + a[2 * j + 1] = a[j] + a[j + 1]; + a[2 * j - 1] = a[j] - a[j + 1]; + } + l = 2; + m = mh; + while (m >= 2) { + dctsub(m, t, nc, w + nw); + if (m > 4) { + bitrv2(m, ip + 2, t); + cftfsub(m, t, w); + rftfsub(m, t, nc, w + nw); + } else if (m == 4) { + cftfsub(m, t, w); + } + a[n - l] = t[0] - t[1]; + a[l] = t[0] + t[1]; + k = 0; + for (j = 2; j < m; j += 2) { + k += l << 2; + a[k - l] = t[j] - t[j + 1]; + a[k + l] = t[j] + t[j + 1]; + } + l <<= 1; + mh = m >> 1; + for (j = 0; j < mh; j++) { + k = m - j; + t[j] = t[m + k] - t[m + j]; + t[k] = t[m + k] + t[m + j]; + } + t[mh] = t[m + mh]; + m = mh; + } + a[l] = t[0]; + a[n] = t[2] - t[1]; + a[0] = t[2] + t[1]; + } else { + a[1] = a[0]; + a[2] = t[0]; + a[0] = t[1]; + } +} + +static void dfst(int n, float *a, float *t, int *ip, float *w) +{ + int j, k, l, m, mh, nw, nc; + float xr, xi, yr, yi; + + nw = ip[0]; + if (n > (nw << 3)) { + nw = n >> 3; + makewt(nw, ip, w); + } + nc = ip[1]; + if (n > (nc << 1)) { + nc = n >> 1; + makect(nc, ip, w + nw); + } + if (n > 2) { + m = n >> 1; + mh = m >> 1; + for (j = 1; j < mh; j++) { + k = m - j; + xr = a[j] + a[n - j]; + xi = a[j] - a[n - j]; + yr = a[k] + a[n - k]; + yi = a[k] - a[n - k]; + a[j] = xr; + a[k] = yr; + t[j] = xi + yi; + t[k] = xi - yi; + } + t[0] = a[mh] - a[n - mh]; + a[mh] += a[n - mh]; + a[0] = a[m]; + dstsub(m, a, nc, w + nw); + if (m > 4) { + bitrv2(m, ip + 2, a); + cftfsub(m, a, w); + rftfsub(m, a, nc, w + nw); + } else if (m == 4) { + cftfsub(m, a, w); + } + a[n - 1] = a[1] - a[0]; + a[1] = a[0] + a[1]; + for (j = m - 2; j >= 2; j -= 2) { + a[2 * j + 1] = a[j] - a[j + 1]; + a[2 * j - 1] = -a[j] - a[j + 1]; + } + l = 2; + m = mh; + while (m >= 2) { + dstsub(m, t, nc, w + nw); + if (m > 4) { + bitrv2(m, ip + 2, t); + cftfsub(m, t, w); + rftfsub(m, t, nc, w + nw); + } else if (m == 4) { + cftfsub(m, t, w); + } + a[n - l] = t[1] - t[0]; + a[l] = t[0] + t[1]; + k = 0; + for (j = 2; j < m; j += 2) { + k += l << 2; + a[k - l] = -t[j] - t[j + 1]; + a[k + l] = t[j] - t[j + 1]; + } + l <<= 1; + mh = m >> 1; + for (j = 1; j < mh; j++) { + k = m - j; + t[j] = t[m + k] + t[m + j]; + t[k] = t[m + k] - t[m + j]; + } + t[0] = t[m + mh]; + m = mh; + } + a[l] = t[0]; + } + a[0] = 0; +} +#endif // Not used. + + +/* -------- initializing routines -------- */ + + +#include + +static void makewt(int nw, int *ip, float *w) +{ + int j, nwh; + float delta, x, y; + + ip[0] = nw; + ip[1] = 1; + if (nw > 2) { + nwh = nw >> 1; + delta = (float)atan(1.0f) / nwh; + w[0] = 1; + w[1] = 0; + w[nwh] = (float)cos(delta * nwh); + w[nwh + 1] = w[nwh]; + if (nwh > 2) { + for (j = 2; j < nwh; j += 2) { + x = (float)cos(delta * j); + y = (float)sin(delta * j); + w[j] = x; + w[j + 1] = y; + w[nw - j] = y; + w[nw - j + 1] = x; + } + bitrv2(nw, ip + 2, w); + } + } +} + + +static void makect(int nc, int *ip, float *c) +{ + int j, nch; + float delta; + + ip[1] = nc; + if (nc > 1) { + nch = nc >> 1; + delta = (float)atan(1.0f) / nch; + c[0] = (float)cos(delta * nch); + c[nch] = 0.5f * c[0]; + for (j = 1; j < nch; j++) { + c[j] = 0.5f * (float)cos(delta * j); + c[nc - j] = 0.5f * (float)sin(delta * j); + } + } +} + + +/* -------- child routines -------- */ + + +static void bitrv2(int n, int *ip, float *a) +{ + int j, j1, k, k1, l, m, m2; + float xr, xi, yr, yi; + + ip[0] = 0; + l = n; + m = 1; + while ((m << 3) < l) { + l >>= 1; + for (j = 0; j < m; j++) { + ip[m + j] = ip[j] + l; + } + m <<= 1; + } + m2 = 2 * m; + if ((m << 3) == l) { + for (k = 0; k < m; k++) { + for (j = 0; j < k; j++) { + j1 = 2 * j + ip[k]; + k1 = 2 * k + ip[j]; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 += 2 * m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 -= m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 += 2 * m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + j1 = 2 * k + m2 + ip[k]; + k1 = j1 + m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + } else { + for (k = 1; k < m; k++) { + for (j = 0; j < k; j++) { + j1 = 2 * j + ip[k]; + k1 = 2 * k + ip[j]; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 += m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + } + } +} + + +static void bitrv2conj(int n, int *ip, float *a) +{ + int j, j1, k, k1, l, m, m2; + float xr, xi, yr, yi; + + ip[0] = 0; + l = n; + m = 1; + while ((m << 3) < l) { + l >>= 1; + for (j = 0; j < m; j++) { + ip[m + j] = ip[j] + l; + } + m <<= 1; + } + m2 = 2 * m; + if ((m << 3) == l) { + for (k = 0; k < m; k++) { + for (j = 0; j < k; j++) { + j1 = 2 * j + ip[k]; + k1 = 2 * k + ip[j]; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 += 2 * m2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 -= m2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 += 2 * m2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + k1 = 2 * k + ip[k]; + a[k1 + 1] = -a[k1 + 1]; + j1 = k1 + m2; + k1 = j1 + m2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + k1 += m2; + a[k1 + 1] = -a[k1 + 1]; + } + } else { + a[1] = -a[1]; + a[m2 + 1] = -a[m2 + 1]; + for (k = 1; k < m; k++) { + for (j = 0; j < k; j++) { + j1 = 2 * j + ip[k]; + k1 = 2 * k + ip[j]; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 += m2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + k1 = 2 * k + ip[k]; + a[k1 + 1] = -a[k1 + 1]; + a[k1 + m2 + 1] = -a[k1 + m2 + 1]; + } + } +} + + +static void cftfsub(int n, float *a, float *w) +{ + int j, j1, j2, j3, l; + float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + l = 2; + if (n > 8) { + cft1st(n, a, w); + l = 8; + while ((l << 2) < n) { + cftmdl(n, l, a, w); + l <<= 2; + } + } + if ((l << 2) == n) { + for (j = 0; j < l; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + a[j2] = x0r - x2r; + a[j2 + 1] = x0i - x2i; + a[j1] = x1r - x3i; + a[j1 + 1] = x1i + x3r; + a[j3] = x1r + x3i; + a[j3 + 1] = x1i - x3r; + } + } else { + for (j = 0; j < l; j += 2) { + j1 = j + l; + x0r = a[j] - a[j1]; + x0i = a[j + 1] - a[j1 + 1]; + a[j] += a[j1]; + a[j + 1] += a[j1 + 1]; + a[j1] = x0r; + a[j1 + 1] = x0i; + } + } +} + + +static void cftbsub(int n, float *a, float *w) +{ + int j, j1, j2, j3, l; + float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + l = 2; + if (n > 8) { + cft1st(n, a, w); + l = 8; + while ((l << 2) < n) { + cftmdl(n, l, a, w); + l <<= 2; + } + } + if ((l << 2) == n) { + for (j = 0; j < l; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = -a[j + 1] - a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = -a[j + 1] + a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i - x2i; + a[j2] = x0r - x2r; + a[j2 + 1] = x0i + x2i; + a[j1] = x1r - x3i; + a[j1 + 1] = x1i - x3r; + a[j3] = x1r + x3i; + a[j3 + 1] = x1i + x3r; + } + } else { + for (j = 0; j < l; j += 2) { + j1 = j + l; + x0r = a[j] - a[j1]; + x0i = -a[j + 1] + a[j1 + 1]; + a[j] += a[j1]; + a[j + 1] = -a[j + 1] - a[j1 + 1]; + a[j1] = x0r; + a[j1 + 1] = x0i; + } + } +} + + +static void cft1st(int n, float *a, float *w) +{ + int j, k1, k2; + float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; + float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + x0r = a[0] + a[2]; + x0i = a[1] + a[3]; + x1r = a[0] - a[2]; + x1i = a[1] - a[3]; + x2r = a[4] + a[6]; + x2i = a[5] + a[7]; + x3r = a[4] - a[6]; + x3i = a[5] - a[7]; + a[0] = x0r + x2r; + a[1] = x0i + x2i; + a[4] = x0r - x2r; + a[5] = x0i - x2i; + a[2] = x1r - x3i; + a[3] = x1i + x3r; + a[6] = x1r + x3i; + a[7] = x1i - x3r; + wk1r = w[2]; + x0r = a[8] + a[10]; + x0i = a[9] + a[11]; + x1r = a[8] - a[10]; + x1i = a[9] - a[11]; + x2r = a[12] + a[14]; + x2i = a[13] + a[15]; + x3r = a[12] - a[14]; + x3i = a[13] - a[15]; + a[8] = x0r + x2r; + a[9] = x0i + x2i; + a[12] = x2i - x0i; + a[13] = x0r - x2r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[10] = wk1r * (x0r - x0i); + a[11] = wk1r * (x0r + x0i); + x0r = x3i + x1r; + x0i = x3r - x1i; + a[14] = wk1r * (x0i - x0r); + a[15] = wk1r * (x0i + x0r); + k1 = 0; + for (j = 16; j < n; j += 16) { + k1 += 2; + k2 = 2 * k1; + wk2r = w[k1]; + wk2i = w[k1 + 1]; + wk1r = w[k2]; + wk1i = w[k2 + 1]; + wk3r = wk1r - 2 * wk2i * wk1i; + wk3i = 2 * wk2i * wk1r - wk1i; + x0r = a[j] + a[j + 2]; + x0i = a[j + 1] + a[j + 3]; + x1r = a[j] - a[j + 2]; + x1i = a[j + 1] - a[j + 3]; + x2r = a[j + 4] + a[j + 6]; + x2i = a[j + 5] + a[j + 7]; + x3r = a[j + 4] - a[j + 6]; + x3i = a[j + 5] - a[j + 7]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j + 4] = wk2r * x0r - wk2i * x0i; + a[j + 5] = wk2r * x0i + wk2i * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j + 2] = wk1r * x0r - wk1i * x0i; + a[j + 3] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j + 6] = wk3r * x0r - wk3i * x0i; + a[j + 7] = wk3r * x0i + wk3i * x0r; + wk1r = w[k2 + 2]; + wk1i = w[k2 + 3]; + wk3r = wk1r - 2 * wk2r * wk1i; + wk3i = 2 * wk2r * wk1r - wk1i; + x0r = a[j + 8] + a[j + 10]; + x0i = a[j + 9] + a[j + 11]; + x1r = a[j + 8] - a[j + 10]; + x1i = a[j + 9] - a[j + 11]; + x2r = a[j + 12] + a[j + 14]; + x2i = a[j + 13] + a[j + 15]; + x3r = a[j + 12] - a[j + 14]; + x3i = a[j + 13] - a[j + 15]; + a[j + 8] = x0r + x2r; + a[j + 9] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j + 12] = -wk2i * x0r - wk2r * x0i; + a[j + 13] = -wk2i * x0i + wk2r * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j + 10] = wk1r * x0r - wk1i * x0i; + a[j + 11] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j + 14] = wk3r * x0r - wk3i * x0i; + a[j + 15] = wk3r * x0i + wk3i * x0r; + } +} + + +static void cftmdl(int n, int l, float *a, float *w) +{ + int j, j1, j2, j3, k, k1, k2, m, m2; + float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; + float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + m = l << 2; + for (j = 0; j < l; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + a[j2] = x0r - x2r; + a[j2 + 1] = x0i - x2i; + a[j1] = x1r - x3i; + a[j1 + 1] = x1i + x3r; + a[j3] = x1r + x3i; + a[j3 + 1] = x1i - x3r; + } + wk1r = w[2]; + for (j = m; j < l + m; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + a[j2] = x2i - x0i; + a[j2 + 1] = x0r - x2r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1] = wk1r * (x0r - x0i); + a[j1 + 1] = wk1r * (x0r + x0i); + x0r = x3i + x1r; + x0i = x3r - x1i; + a[j3] = wk1r * (x0i - x0r); + a[j3 + 1] = wk1r * (x0i + x0r); + } + k1 = 0; + m2 = 2 * m; + for (k = m2; k < n; k += m2) { + k1 += 2; + k2 = 2 * k1; + wk2r = w[k1]; + wk2i = w[k1 + 1]; + wk1r = w[k2]; + wk1i = w[k2 + 1]; + wk3r = wk1r - 2 * wk2i * wk1i; + wk3i = 2 * wk2i * wk1r - wk1i; + for (j = k; j < l + k; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j2] = wk2r * x0r - wk2i * x0i; + a[j2 + 1] = wk2r * x0i + wk2i * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1] = wk1r * x0r - wk1i * x0i; + a[j1 + 1] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3] = wk3r * x0r - wk3i * x0i; + a[j3 + 1] = wk3r * x0i + wk3i * x0r; + } + wk1r = w[k2 + 2]; + wk1i = w[k2 + 3]; + wk3r = wk1r - 2 * wk2r * wk1i; + wk3i = 2 * wk2r * wk1r - wk1i; + for (j = k + m; j < l + (k + m); j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j2] = -wk2i * x0r - wk2r * x0i; + a[j2 + 1] = -wk2i * x0i + wk2r * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1] = wk1r * x0r - wk1i * x0i; + a[j1 + 1] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3] = wk3r * x0r - wk3i * x0i; + a[j3 + 1] = wk3r * x0i + wk3i * x0r; + } + } +} + + +static void rftfsub(int n, float *a, int nc, float *c) +{ + int j, k, kk, ks, m; + float wkr, wki, xr, xi, yr, yi; + + m = n >> 1; + ks = 2 * nc / m; + kk = 0; + for (j = 2; j < m; j += 2) { + k = n - j; + kk += ks; + wkr = 0.5f - c[nc - kk]; + wki = c[kk]; + xr = a[j] - a[k]; + xi = a[j + 1] + a[k + 1]; + yr = wkr * xr - wki * xi; + yi = wkr * xi + wki * xr; + a[j] -= yr; + a[j + 1] -= yi; + a[k] += yr; + a[k + 1] -= yi; + } +} + + +static void rftbsub(int n, float *a, int nc, float *c) +{ + int j, k, kk, ks, m; + float wkr, wki, xr, xi, yr, yi; + + a[1] = -a[1]; + m = n >> 1; + ks = 2 * nc / m; + kk = 0; + for (j = 2; j < m; j += 2) { + k = n - j; + kk += ks; + wkr = 0.5f - c[nc - kk]; + wki = c[kk]; + xr = a[j] - a[k]; + xi = a[j + 1] + a[k + 1]; + yr = wkr * xr + wki * xi; + yi = wkr * xi - wki * xr; + a[j] -= yr; + a[j + 1] = yi - a[j + 1]; + a[k] += yr; + a[k + 1] = yi - a[k + 1]; + } + a[m + 1] = -a[m + 1]; +} + +#if 0 // Not used. +static void dctsub(int n, float *a, int nc, float *c) +{ + int j, k, kk, ks, m; + float wkr, wki, xr; + + m = n >> 1; + ks = nc / n; + kk = 0; + for (j = 1; j < m; j++) { + k = n - j; + kk += ks; + wkr = c[kk] - c[nc - kk]; + wki = c[kk] + c[nc - kk]; + xr = wki * a[j] - wkr * a[k]; + a[j] = wkr * a[j] + wki * a[k]; + a[k] = xr; + } + a[m] *= c[0]; +} + + +static void dstsub(int n, float *a, int nc, float *c) +{ + int j, k, kk, ks, m; + float wkr, wki, xr; + + m = n >> 1; + ks = nc / n; + kk = 0; + for (j = 1; j < m; j++) { + k = n - j; + kk += ks; + wkr = c[kk] - c[nc - kk]; + wki = c[kk] + c[nc - kk]; + xr = wki * a[k] - wkr * a[j]; + a[k] = wkr * a[k] + wki * a[j]; + a[j] = xr; + } + a[m] *= c[0]; +} +#endif // Not used. diff --git a/libs/miniwebrtc/audio/processing/utility/fft4g.h b/libs/miniwebrtc/audio/processing/utility/fft4g.h new file mode 100644 index 00000000..14a52a10 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/utility/fft4g.h @@ -0,0 +1,17 @@ +/* + * 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_PROCESSING_UTILITY_FFT4G_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_FFT4G_H_ + +void WebRtc_rdft(int, int, float *, int *, float *); +void WebRtc_cdft(int, int, float *, int *, float *); + +#endif diff --git a/libs/miniwebrtc/audio/processing/utility/ring_buffer.c b/libs/miniwebrtc/audio/processing/utility/ring_buffer.c new file mode 100644 index 00000000..8b2b4364 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/utility/ring_buffer.c @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// A ring buffer to hold arbitrary data. Provides no thread safety. Unless +// otherwise specified, functions return 0 on success and -1 on error. + +#include "ring_buffer.h" + +#include // size_t +#include +#include + +enum Wrap { + SAME_WRAP, + DIFF_WRAP +}; + +typedef struct { + size_t read_pos; + size_t write_pos; + size_t element_count; + size_t element_size; + enum Wrap rw_wrap; + char* data; +} buf_t; + +// Get address of region(s) from which we can read data. +// If the region is contiguous, |data_ptr_bytes_2| will be zero. +// If non-contiguous, |data_ptr_bytes_2| will be the size in bytes of the second +// region. Returns room available to be read or |element_count|, whichever is +// smaller. +static size_t GetBufferReadRegions(buf_t* buf, + size_t element_count, + void** data_ptr_1, + size_t* data_ptr_bytes_1, + void** data_ptr_2, + size_t* data_ptr_bytes_2) { + + const size_t readable_elements = WebRtc_available_read(buf); + const size_t read_elements = (readable_elements < element_count ? + readable_elements : element_count); + const size_t margin = buf->element_count - buf->read_pos; + + // Check to see if read is not contiguous. + if (read_elements > margin) { + // Write data in two blocks that wrap the buffer. + *data_ptr_1 = buf->data + buf->read_pos * buf->element_size; + *data_ptr_bytes_1 = margin * buf->element_size; + *data_ptr_2 = buf->data; + *data_ptr_bytes_2 = (read_elements - margin) * buf->element_size; + } else { + *data_ptr_1 = buf->data + buf->read_pos * buf->element_size; + *data_ptr_bytes_1 = read_elements * buf->element_size; + *data_ptr_2 = NULL; + *data_ptr_bytes_2 = 0; + } + + return read_elements; +} + +int WebRtc_CreateBuffer(void** handle, + size_t element_count, + size_t element_size) { + buf_t* self = NULL; + + if (handle == NULL) { + return -1; + } + + self = malloc(sizeof(buf_t)); + if (self == NULL) { + return -1; + } + *handle = self; + + self->data = malloc(element_count * element_size); + if (self->data == NULL) { + free(self); + self = NULL; + return -1; + } + + self->element_count = element_count; + self->element_size = element_size; + + return 0; +} + +int WebRtc_InitBuffer(void* handle) { + buf_t* self = (buf_t*) handle; + + if (self == NULL) { + return -1; + } + + self->read_pos = 0; + self->write_pos = 0; + self->rw_wrap = SAME_WRAP; + + // Initialize buffer to zeros + memset(self->data, 0, self->element_count * self->element_size); + + return 0; +} + +int WebRtc_FreeBuffer(void* handle) { + buf_t* self = (buf_t*) handle; + + if (self == NULL) { + return -1; + } + + free(self->data); + free(self); + + return 0; +} + +size_t WebRtc_ReadBuffer(void* handle, + void** data_ptr, + void* data, + size_t element_count) { + + buf_t* self = (buf_t*) handle; + + if (self == NULL) { + return 0; + } + if (data == NULL) { + return 0; + } + if (data_ptr == NULL) { + return 0; + } + + { + void* buf_ptr_1 = NULL; + void* buf_ptr_2 = NULL; + size_t buf_ptr_bytes_1 = 0; + size_t buf_ptr_bytes_2 = 0; + const size_t read_count = GetBufferReadRegions(self, + element_count, + &buf_ptr_1, + &buf_ptr_bytes_1, + &buf_ptr_2, + &buf_ptr_bytes_2); + + if (buf_ptr_bytes_2 > 0) { + // We have a wrap around when reading the buffer. Copy the buffer data to + // |data| and point to it. + memcpy(data, buf_ptr_1, buf_ptr_bytes_1); + memcpy(((char*) data) + buf_ptr_bytes_1, buf_ptr_2, buf_ptr_bytes_2); + *data_ptr = data; + } else { + *data_ptr = buf_ptr_1; + } + + // Update read position + WebRtc_MoveReadPtr(handle, (int) read_count); + + return read_count; + } +} + +size_t WebRtc_WriteBuffer(void* handle, + const void* data, + size_t element_count) { + + buf_t* self = (buf_t*) handle; + + if (self == NULL) { + return 0; + } + if (data == NULL) { + return 0; + } + + { + const size_t free_elements = WebRtc_available_write(handle); + const size_t write_elements = (free_elements < element_count ? free_elements + : element_count); + size_t n = write_elements; + const size_t margin = self->element_count - self->write_pos; + + if (write_elements > margin) { + // Buffer wrap around when writing. + memcpy(self->data + self->write_pos * self->element_size, + data, margin * self->element_size); + self->write_pos = 0; + n -= margin; + self->rw_wrap = DIFF_WRAP; + } + memcpy(self->data + self->write_pos * self->element_size, + ((const char*) data) + ((write_elements - n) * self->element_size), + n * self->element_size); + self->write_pos += n; + + return write_elements; + } +} + +int WebRtc_MoveReadPtr(void* handle, int element_count) { + + buf_t* self = (buf_t*) handle; + + if (self == NULL) { + return 0; + } + + { + // We need to be able to take care of negative changes, hence use "int" + // instead of "size_t". + const int free_elements = (int) WebRtc_available_write(handle); + const int readable_elements = (int) WebRtc_available_read(handle); + int read_pos = (int) self->read_pos; + + if (element_count > readable_elements) { + element_count = readable_elements; + } + if (element_count < -free_elements) { + element_count = -free_elements; + } + + read_pos += element_count; + if (read_pos > (int) self->element_count) { + // Buffer wrap around. Restart read position and wrap indicator. + read_pos -= (int) self->element_count; + self->rw_wrap = SAME_WRAP; + } + if (read_pos < 0) { + // Buffer wrap around. Restart read position and wrap indicator. + read_pos += (int) self->element_count; + self->rw_wrap = DIFF_WRAP; + } + + self->read_pos = (size_t) read_pos; + + return element_count; + } +} + +size_t WebRtc_available_read(const void* handle) { + const buf_t* self = (buf_t*) handle; + + if (self == NULL) { + return 0; + } + + if (self->rw_wrap == SAME_WRAP) { + return self->write_pos - self->read_pos; + } else { + return self->element_count - self->read_pos + self->write_pos; + } +} + +size_t WebRtc_available_write(const void* handle) { + const buf_t* self = (buf_t*) handle; + + if (self == NULL) { + return 0; + } + + return self->element_count - WebRtc_available_read(handle); +} diff --git a/libs/miniwebrtc/audio/processing/utility/ring_buffer.h b/libs/miniwebrtc/audio/processing/utility/ring_buffer.h new file mode 100644 index 00000000..3c440296 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/utility/ring_buffer.h @@ -0,0 +1,53 @@ +/* + * 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. + */ + +// A ring buffer to hold arbitrary data. Provides no thread safety. Unless +// otherwise specified, functions return 0 on success and -1 on error. + +#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_RING_BUFFER_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_RING_BUFFER_H_ + +#include // size_t + +int WebRtc_CreateBuffer(void** handle, + size_t element_count, + size_t element_size); +int WebRtc_InitBuffer(void* handle); +int WebRtc_FreeBuffer(void* handle); + +// Reads data from the buffer. The |data_ptr| will point to the address where +// it is located. If all |element_count| data are feasible to read without +// buffer wrap around |data_ptr| will point to the location in the buffer. +// Otherwise, the data will be copied to |data| (memory allocation done by the +// user) and |data_ptr| points to the address of |data|. |data_ptr| is only +// guaranteed to be valid until the next call to WebRtc_WriteBuffer(). +// Returns number of elements read. +size_t WebRtc_ReadBuffer(void* handle, + void** data_ptr, + void* data, + size_t element_count); + +// Writes |data| to buffer and returns the number of elements written. +size_t WebRtc_WriteBuffer(void* handle, const void* data, size_t element_count); + +// Moves the buffer read position and returns the number of elements moved. +// Positive |element_count| moves the read position towards the write position, +// that is, flushing the buffer. Negative |element_count| moves the read +// position away from the the write position, that is, stuffing the buffer. +// Returns number of elements moved. +int WebRtc_MoveReadPtr(void* handle, int element_count); + +// Returns number of available elements to read. +size_t WebRtc_available_read(const void* handle); + +// Returns number of available elements for write. +size_t WebRtc_available_write(const void* handle); + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_UTILITY_RING_BUFFER_H_ diff --git a/libs/miniwebrtc/audio/processing/voice_detection_impl.cc b/libs/miniwebrtc/audio/processing/voice_detection_impl.cc new file mode 100644 index 00000000..50b99a0d --- /dev/null +++ b/libs/miniwebrtc/audio/processing/voice_detection_impl.cc @@ -0,0 +1,188 @@ +/* + * 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 "voice_detection_impl.h" + +#include + +#include "critical_section_wrapper.h" +#include "webrtc_vad.h" + +#include "audio_processing_impl.h" +#include "audio_buffer.h" + +namespace webrtc { + +typedef VadInst Handle; + +namespace { +int MapSetting(VoiceDetection::Likelihood likelihood) { + switch (likelihood) { + case VoiceDetection::kVeryLowLikelihood: + return 3; + case VoiceDetection::kLowLikelihood: + return 2; + case VoiceDetection::kModerateLikelihood: + return 1; + case VoiceDetection::kHighLikelihood: + return 0; + } + assert(false); + return -1; +} +} // namespace + +VoiceDetectionImpl::VoiceDetectionImpl(const AudioProcessingImpl* apm) + : ProcessingComponent(apm), + apm_(apm), + stream_has_voice_(false), + using_external_vad_(false), + likelihood_(kLowLikelihood), + frame_size_ms_(10), + frame_size_samples_(0) {} + +VoiceDetectionImpl::~VoiceDetectionImpl() {} + +int VoiceDetectionImpl::ProcessCaptureAudio(AudioBuffer* audio) { + if (!is_component_enabled()) { + return apm_->kNoError; + } + + if (using_external_vad_) { + using_external_vad_ = false; + return apm_->kNoError; + } + assert(audio->samples_per_split_channel() <= 160); + + WebRtc_Word16* mixed_data = audio->low_pass_split_data(0); + if (audio->num_channels() > 1) { + audio->CopyAndMixLowPass(1); + mixed_data = audio->mixed_low_pass_data(0); + } + + // TODO(ajm): concatenate data in frame buffer here. + + int vad_ret = WebRtcVad_Process(static_cast(handle(0)), + apm_->split_sample_rate_hz(), + mixed_data, + frame_size_samples_); + if (vad_ret == 0) { + stream_has_voice_ = false; + audio->set_activity(AudioFrame::kVadPassive); + } else if (vad_ret == 1) { + stream_has_voice_ = true; + audio->set_activity(AudioFrame::kVadActive); + } else { + return apm_->kUnspecifiedError; + } + + return apm_->kNoError; +} + +int VoiceDetectionImpl::Enable(bool enable) { + CriticalSectionScoped crit_scoped(apm_->crit()); + return EnableComponent(enable); +} + +bool VoiceDetectionImpl::is_enabled() const { + return is_component_enabled(); +} + +int VoiceDetectionImpl::set_stream_has_voice(bool has_voice) { + using_external_vad_ = true; + stream_has_voice_ = has_voice; + return apm_->kNoError; +} + +bool VoiceDetectionImpl::stream_has_voice() const { + // TODO(ajm): enable this assertion? + //assert(using_external_vad_ || is_component_enabled()); + return stream_has_voice_; +} + +int VoiceDetectionImpl::set_likelihood(VoiceDetection::Likelihood likelihood) { + CriticalSectionScoped crit_scoped(apm_->crit()); + if (MapSetting(likelihood) == -1) { + return apm_->kBadParameterError; + } + + likelihood_ = likelihood; + return Configure(); +} + +VoiceDetection::Likelihood VoiceDetectionImpl::likelihood() const { + return likelihood_; +} + +int VoiceDetectionImpl::set_frame_size_ms(int size) { + CriticalSectionScoped crit_scoped(apm_->crit()); + assert(size == 10); // TODO(ajm): remove when supported. + if (size != 10 && + size != 20 && + size != 30) { + return apm_->kBadParameterError; + } + + frame_size_ms_ = size; + + return Initialize(); +} + +int VoiceDetectionImpl::frame_size_ms() const { + return frame_size_ms_; +} + +int VoiceDetectionImpl::Initialize() { + int err = ProcessingComponent::Initialize(); + if (err != apm_->kNoError || !is_component_enabled()) { + return err; + } + + using_external_vad_ = false; + frame_size_samples_ = frame_size_ms_ * (apm_->split_sample_rate_hz() / 1000); + // TODO(ajm): intialize frame buffer here. + + return apm_->kNoError; +} + +void* VoiceDetectionImpl::CreateHandle() const { + Handle* handle = NULL; + if (WebRtcVad_Create(&handle) != apm_->kNoError) { + handle = NULL; + } else { + assert(handle != NULL); + } + + return handle; +} + +int VoiceDetectionImpl::DestroyHandle(void* handle) const { + return WebRtcVad_Free(static_cast(handle)); +} + +int VoiceDetectionImpl::InitializeHandle(void* handle) const { + return WebRtcVad_Init(static_cast(handle)); +} + +int VoiceDetectionImpl::ConfigureHandle(void* handle) const { + return WebRtcVad_set_mode(static_cast(handle), + MapSetting(likelihood_)); +} + +int VoiceDetectionImpl::num_handles_required() const { + return 1; +} + +int VoiceDetectionImpl::GetHandleError(void* handle) const { + // The VAD has no get_error() function. + assert(handle != NULL); + return apm_->kUnspecifiedError; +} +} // namespace webrtc diff --git a/libs/miniwebrtc/audio/processing/voice_detection_impl.h b/libs/miniwebrtc/audio/processing/voice_detection_impl.h new file mode 100644 index 00000000..52d92e01 --- /dev/null +++ b/libs/miniwebrtc/audio/processing/voice_detection_impl.h @@ -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. + */ + +#ifndef WEBRTC_MODULES_AUDIO_PROCESSING_VOICE_DETECTION_IMPL_H_ +#define WEBRTC_MODULES_AUDIO_PROCESSING_VOICE_DETECTION_IMPL_H_ + +#include "audio_processing.h" +#include "processing_component.h" + +namespace webrtc { +class AudioProcessingImpl; +class AudioBuffer; + +class VoiceDetectionImpl : public VoiceDetection, + public ProcessingComponent { + public: + explicit VoiceDetectionImpl(const AudioProcessingImpl* apm); + virtual ~VoiceDetectionImpl(); + + int ProcessCaptureAudio(AudioBuffer* audio); + + // VoiceDetection implementation. + virtual bool is_enabled() const; + + // ProcessingComponent implementation. + virtual int Initialize(); + + private: + // VoiceDetection implementation. + virtual int Enable(bool enable); + virtual int set_stream_has_voice(bool has_voice); + virtual bool stream_has_voice() const; + virtual int set_likelihood(Likelihood likelihood); + virtual Likelihood likelihood() const; + virtual int set_frame_size_ms(int size); + virtual int frame_size_ms() const; + + // ProcessingComponent implementation. + virtual void* CreateHandle() const; + virtual int InitializeHandle(void* handle) const; + virtual int ConfigureHandle(void* handle) const; + virtual int DestroyHandle(void* handle) const; + virtual int num_handles_required() const; + virtual int GetHandleError(void* handle) const; + + const AudioProcessingImpl* apm_; + bool stream_has_voice_; + bool using_external_vad_; + Likelihood likelihood_; + int frame_size_ms_; + int frame_size_samples_; +}; +} // namespace webrtc + +#endif // WEBRTC_MODULES_AUDIO_PROCESSING_VOICE_DETECTION_IMPL_H_ diff --git a/libs/miniwebrtc/common_types.h b/libs/miniwebrtc/common_types.h new file mode 100644 index 00000000..9b3a0cee --- /dev/null +++ b/libs/miniwebrtc/common_types.h @@ -0,0 +1,573 @@ +/* + * 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_COMMON_TYPES_H +#define WEBRTC_COMMON_TYPES_H + +#include "typedefs.h" + +#ifdef WEBRTC_EXPORT + #define WEBRTC_DLLEXPORT _declspec(dllexport) +#elif WEBRTC_DLL + #define WEBRTC_DLLEXPORT _declspec(dllimport) +#else + #define WEBRTC_DLLEXPORT +#endif + +#ifndef NULL + #define NULL 0 +#endif + +#define RTP_PAYLOAD_NAME_SIZE 32 + +namespace webrtc { + +class InStream +{ +public: + virtual int Read(void *buf,int len) = 0; + virtual int Rewind() {return -1;} + virtual ~InStream() {} +protected: + InStream() {} +}; + +class OutStream +{ +public: + virtual bool Write(const void *buf,int len) = 0; + virtual int Rewind() {return -1;} + virtual ~OutStream() {} +protected: + OutStream() {} +}; + +enum TraceModule +{ + // not a module, triggered from the engine code + kTraceVoice = 0x0001, + // not a module, triggered from the engine code + kTraceVideo = 0x0002, + // not a module, triggered from the utility code + kTraceUtility = 0x0003, + kTraceRtpRtcp = 0x0004, + kTraceTransport = 0x0005, + kTraceSrtp = 0x0006, + kTraceAudioCoding = 0x0007, + kTraceAudioMixerServer = 0x0008, + kTraceAudioMixerClient = 0x0009, + kTraceFile = 0x000a, + kTraceAudioProcessing = 0x000b, + kTraceVideoCoding = 0x0010, + kTraceVideoMixer = 0x0011, + kTraceAudioDevice = 0x0012, + kTraceVideoRenderer = 0x0014, + kTraceVideoCapture = 0x0015, + kTraceVideoPreocessing = 0x0016 +}; + +enum TraceLevel +{ + kTraceNone = 0x0000, // no trace + kTraceStateInfo = 0x0001, + kTraceWarning = 0x0002, + kTraceError = 0x0004, + kTraceCritical = 0x0008, + kTraceApiCall = 0x0010, + kTraceDefault = 0x00ff, + + kTraceModuleCall = 0x0020, + kTraceMemory = 0x0100, // memory info + kTraceTimer = 0x0200, // timing info + kTraceStream = 0x0400, // "continuous" stream of data + + // used for debug purposes + kTraceDebug = 0x0800, // debug + kTraceInfo = 0x1000, // debug info + + kTraceAll = 0xffff +}; + +// External Trace API +class TraceCallback +{ +public: + virtual void Print(const TraceLevel level, + const char *traceString, + const int length) = 0; +protected: + virtual ~TraceCallback() {} + TraceCallback() {} +}; + + +enum FileFormats +{ + kFileFormatWavFile = 1, + kFileFormatCompressedFile = 2, + kFileFormatAviFile = 3, + kFileFormatPreencodedFile = 4, + kFileFormatPcm16kHzFile = 7, + kFileFormatPcm8kHzFile = 8, + kFileFormatPcm32kHzFile = 9 +}; + + +enum ProcessingTypes +{ + kPlaybackPerChannel = 0, + kPlaybackAllChannelsMixed, + kRecordingPerChannel, + kRecordingAllChannelsMixed +}; + +// Encryption enums +enum CipherTypes +{ + kCipherNull = 0, + kCipherAes128CounterMode = 1 +}; + +enum AuthenticationTypes +{ + kAuthNull = 0, + kAuthHmacSha1 = 3 +}; + +enum SecurityLevels +{ + kNoProtection = 0, + kEncryption = 1, + kAuthentication = 2, + kEncryptionAndAuthentication = 3 +}; + +// Interface for encrypting and decrypting regular data and rtp/rtcp packets. +// Implement this interface if you wish to provide an encryption scheme to +// the voice or video engines. +class Encryption +{ +public: + // Encrypt the given data. + // + // Args: + // channel: The channel to encrypt data for. + // in_data: The data to encrypt. This data is bytes_in bytes long. + // out_data: The buffer to write the encrypted data to. You may write more + // bytes of encrypted data than what you got as input, up to a maximum + // of webrtc::kViEMaxMtu if you are encrypting in the video engine, or + // webrtc::kVoiceEngineMaxIpPacketSizeBytes for the voice engine. + // bytes_in: The number of bytes in the input buffer. + // bytes_out: The number of bytes written in out_data. + virtual void encrypt( + int channel, + unsigned char* in_data, + unsigned char* out_data, + int bytes_in, + int* bytes_out) = 0; + + // Decrypts the given data. This should reverse the effects of encrypt(). + // + // Args: + // channel_no: The channel to decrypt data for. + // in_data: The data to decrypt. This data is bytes_in bytes long. + // out_data: The buffer to write the decrypted data to. You may write more + // bytes of decrypted data than what you got as input, up to a maximum + // of webrtc::kViEMaxMtu if you are encrypting in the video engine, or + // webrtc::kVoiceEngineMaxIpPacketSizeBytes for the voice engine. + // bytes_in: The number of bytes in the input buffer. + // bytes_out: The number of bytes written in out_data. + virtual void decrypt( + int channel, + unsigned char* in_data, + unsigned char* out_data, + int bytes_in, + int* bytes_out) = 0; + + // Encrypts a RTCP packet. Otherwise, this method has the same contract as + // encrypt(). + virtual void encrypt_rtcp( + int channel, + unsigned char* in_data, + unsigned char* out_data, + int bytes_in, + int* bytes_out) = 0; + + // Decrypts a RTCP packet. Otherwise, this method has the same contract as + // decrypt(). + virtual void decrypt_rtcp( + int channel, + unsigned char* in_data, + unsigned char* out_data, + int bytes_in, + int* bytes_out) = 0; + +protected: + virtual ~Encryption() {} + Encryption() {} +}; + +// External transport callback interface +class Transport +{ +public: + virtual int SendPacket(int channel, const void *data, int len) = 0; + virtual int SendRTCPPacket(int channel, const void *data, int len) = 0; + +protected: + virtual ~Transport() {} + Transport() {} +}; + +// ================================================================== +// Voice specific types +// ================================================================== + +// Each codec supported can be described by this structure. +struct CodecInst +{ + int pltype; + char plname[RTP_PAYLOAD_NAME_SIZE]; + int plfreq; + int pacsize; + int channels; + int rate; +}; + +enum FrameType +{ + kFrameEmpty = 0, + kAudioFrameSpeech = 1, + kAudioFrameCN = 2, + kVideoFrameKey = 3, // independent frame + kVideoFrameDelta = 4, // depends on the previus frame + kVideoFrameGolden = 5, // depends on a old known previus frame + kVideoFrameAltRef = 6 +}; + +// RTP +enum {kRtpCsrcSize = 15}; // RFC 3550 page 13 + +enum RTPDirections +{ + kRtpIncoming = 0, + kRtpOutgoing +}; + +enum PayloadFrequencies +{ + kFreq8000Hz = 8000, + kFreq16000Hz = 16000, + kFreq32000Hz = 32000 +}; + +enum VadModes // degree of bandwidth reduction +{ + kVadConventional = 0, // lowest reduction + kVadAggressiveLow, + kVadAggressiveMid, + kVadAggressiveHigh // highest reduction +}; + +struct NetworkStatistics // NETEQ statistics +{ + // current jitter buffer size in ms + WebRtc_UWord16 currentBufferSize; + // preferred (optimal) buffer size in ms + WebRtc_UWord16 preferredBufferSize; + // adding extra delay due to "peaky jitter" + bool jitterPeaksFound; + // loss rate (network + late) in percent (in Q14) + WebRtc_UWord16 currentPacketLossRate; + // late loss rate in percent (in Q14) + WebRtc_UWord16 currentDiscardRate; + // fraction (of original stream) of synthesized speech inserted through + // expansion (in Q14) + WebRtc_UWord16 currentExpandRate; + // fraction of synthesized speech inserted through pre-emptive expansion + // (in Q14) + WebRtc_UWord16 currentPreemptiveRate; + // fraction of data removed through acceleration (in Q14) + WebRtc_UWord16 currentAccelerateRate; + // clock-drift in parts-per-million (negative or positive) + int32_t clockDriftPPM; + // average packet waiting time in the jitter buffer (ms) + int meanWaitingTimeMs; + // median packet waiting time in the jitter buffer (ms) + int medianWaitingTimeMs; + // min packet waiting time in the jitter buffer (ms) + int minWaitingTimeMs; + // max packet waiting time in the jitter buffer (ms) + int maxWaitingTimeMs; +}; + +typedef struct +{ + int min; // minumum + int max; // maximum + int average; // average +} StatVal; + +typedef struct // All levels are reported in dBm0 +{ + StatVal speech_rx; // long-term speech levels on receiving side + StatVal speech_tx; // long-term speech levels on transmitting side + StatVal noise_rx; // long-term noise/silence levels on receiving side + StatVal noise_tx; // long-term noise/silence levels on transmitting side +} LevelStatistics; + +typedef struct // All levels are reported in dB +{ + StatVal erl; // Echo Return Loss + StatVal erle; // Echo Return Loss Enhancement + StatVal rerl; // RERL = ERL + ERLE + // Echo suppression inside EC at the point just before its NLP + StatVal a_nlp; +} EchoStatistics; + +enum TelephoneEventDetectionMethods +{ + kInBand = 0, + kOutOfBand = 1, + kInAndOutOfBand = 2 +}; + +enum NsModes // type of Noise Suppression +{ + kNsUnchanged = 0, // previously set mode + kNsDefault, // platform default + kNsConference, // conferencing default + kNsLowSuppression, // lowest suppression + kNsModerateSuppression, + kNsHighSuppression, + kNsVeryHighSuppression, // highest suppression +}; + +enum AgcModes // type of Automatic Gain Control +{ + kAgcUnchanged = 0, // previously set mode + kAgcDefault, // platform default + // adaptive mode for use when analog volume control exists (e.g. for + // PC softphone) + kAgcAdaptiveAnalog, + // scaling takes place in the digital domain (e.g. for conference servers + // and embedded devices) + kAgcAdaptiveDigital, + // can be used on embedded devices where the the capture signal is level + // is predictable + kAgcFixedDigital +}; + +// EC modes +enum EcModes // type of Echo Control +{ + kEcUnchanged = 0, // previously set mode + kEcDefault, // platform default + kEcConference, // conferencing default (aggressive AEC) + kEcAec, // Acoustic Echo Cancellation + kEcAecm, // AEC mobile +}; + +// AECM modes +enum AecmModes // mode of AECM +{ + kAecmQuietEarpieceOrHeadset = 0, + // Quiet earpiece or headset use + kAecmEarpiece, // most earpiece use + kAecmLoudEarpiece, // Loud earpiece or quiet speakerphone use + kAecmSpeakerphone, // most speakerphone use (default) + kAecmLoudSpeakerphone // Loud speakerphone +}; + +// AGC configuration +typedef struct +{ + unsigned short targetLeveldBOv; + unsigned short digitalCompressionGaindB; + bool limiterEnable; +} AgcConfig; // AGC configuration parameters + +enum StereoChannel +{ + kStereoLeft = 0, + kStereoRight, + kStereoBoth +}; + +// Audio device layers +enum AudioLayers +{ + kAudioPlatformDefault = 0, + kAudioWindowsWave = 1, + kAudioWindowsCore = 2, + kAudioLinuxAlsa = 3, + kAudioLinuxPulse = 4 +}; + +enum NetEqModes // NetEQ playout configurations +{ + // Optimized trade-off between low delay and jitter robustness for two-way + // communication. + kNetEqDefault = 0, + // Improved jitter robustness at the cost of increased delay. Can be + // used in one-way communication. + kNetEqStreaming = 1, + // Optimzed for decodability of fax signals rather than for perceived audio + // quality. + kNetEqFax = 2, +}; + +enum NetEqBgnModes // NetEQ Background Noise (BGN) configurations +{ + // BGN is always on and will be generated when the incoming RTP stream + // stops (default). + kBgnOn = 0, + // The BGN is faded to zero (complete silence) after a few seconds. + kBgnFade = 1, + // BGN is not used at all. Silence is produced after speech extrapolation + // has faded. + kBgnOff = 2, +}; + +enum OnHoldModes // On Hold direction +{ + kHoldSendAndPlay = 0, // Put both sending and playing in on-hold state. + kHoldSendOnly, // Put only sending in on-hold state. + kHoldPlayOnly // Put only playing in on-hold state. +}; + +enum AmrMode +{ + kRfc3267BwEfficient = 0, + kRfc3267OctetAligned = 1, + kRfc3267FileStorage = 2, +}; + +// ================================================================== +// Video specific types +// ================================================================== + +// Raw video types +enum RawVideoType +{ + kVideoI420 = 0, + kVideoYV12 = 1, + kVideoYUY2 = 2, + kVideoUYVY = 3, + kVideoIYUV = 4, + kVideoARGB = 5, + kVideoRGB24 = 6, + kVideoRGB565 = 7, + kVideoARGB4444 = 8, + kVideoARGB1555 = 9, + kVideoMJPEG = 10, + kVideoNV12 = 11, + kVideoNV21 = 12, + kVideoBGRA = 13, + kVideoUnknown = 99 +}; + +// Video codec +enum { kConfigParameterSize = 128}; +enum { kPayloadNameSize = 32}; +enum { kMaxSimulcastStreams = 4}; +enum { kMaxTemporalStreams = 4}; + +enum VideoCodecComplexity +{ + kComplexityNormal = 0, + kComplexityHigh = 1, + kComplexityHigher = 2, + kComplexityMax = 3 +}; + +enum VideoCodecProfile +{ + kProfileBase = 0x00, + kProfileMain = 0x01 +}; + +enum VP8ResilienceMode { + kResilienceOff, // The stream produced by the encoder requires a + // recovery frame (typically a key frame) to be + // decodable after a packet loss. + kResilientStream, // A stream produced by the encoder is resilient to + // packet losses, but packets within a frame subsequent + // to a loss can't be decoded. + kResilientFrames // Same as kResilientStream but with added resilience + // within a frame. +}; + +// VP8 specific +struct VideoCodecVP8 +{ + bool pictureLossIndicationOn; + bool feedbackModeOn; + VideoCodecComplexity complexity; + VP8ResilienceMode resilience; + unsigned char numberOfTemporalLayers; +}; + +// Unknown specific +struct VideoCodecGeneric +{ +}; + +// Video codec types +enum VideoCodecType +{ + kVideoCodecVP8, + kVideoCodecI420, + kVideoCodecRED, + kVideoCodecULPFEC, + kVideoCodecUnknown +}; + +union VideoCodecUnion +{ + VideoCodecVP8 VP8; + VideoCodecGeneric Generic; +}; + + +// Simulcast is when the same stream is encoded multiple times with different +// settings such as resolution. +struct SimulcastStream +{ + unsigned short width; + unsigned short height; + unsigned char numberOfTemporalLayers; + unsigned int maxBitrate; + unsigned int qpMax; // minimum quality +}; + +// Common video codec properties +struct VideoCodec +{ + VideoCodecType codecType; + char plName[kPayloadNameSize]; + unsigned char plType; + + unsigned short width; + unsigned short height; + + unsigned int startBitrate; + unsigned int maxBitrate; + unsigned int minBitrate; + unsigned char maxFramerate; + + VideoCodecUnion codecSpecific; + + unsigned int qpMax; + unsigned char numberOfSimulcastStreams; + SimulcastStream simulcastStream[kMaxSimulcastStreams]; +}; +} // namespace webrtc +#endif // WEBRTC_COMMON_TYPES_H diff --git a/libs/miniwebrtc/import.sh b/libs/miniwebrtc/import.sh new file mode 100755 index 00000000..c369d6bd --- /dev/null +++ b/libs/miniwebrtc/import.sh @@ -0,0 +1,290 @@ +#! /bin/sh + +src="/home/andrei/Documents/WebRTC/src/" + +test "X$1" != "X" && src="$1" + +( +baseorig="" +basedest="" +while IFS=' ' read orig dest; do + echo $orig '->' $dest + case "X$orig" in + */) + baseorig="$orig" + basedest="$dest" + continue + ;; + X) + ;; + esac + test -z "$dest" && dest="$orig" + orig="$baseorig$orig" + dest="$basedest$dest" + if [ -f "$src/$orig" ]; then + base=`dirname "$dest"` + mkdir -p "$base" + cp -a "$src/$orig" "$dest" || echo "Failed to copy: $orig" >&2 + else + echo "Missing: $orig" >&2 + fi +done +)< + +#include "typedefs.h" + +namespace webrtc { + +class Module { + public: + // Change the unique identifier of this object. + virtual int32_t ChangeUniqueId(const int32_t id) = 0; + + // Returns the number of milliseconds until the module want a worker + // thread to call Process. + virtual int32_t TimeUntilNextProcess() = 0; + + // Process any pending tasks such as timeouts. + virtual int32_t Process() = 0; + + protected: + virtual ~Module() {} +}; + +// Reference counted version of the module interface. +class RefCountedModule : public Module { + public: + // Increase the reference count by one. + // Returns the incremented reference count. + // TODO(perkj): Make this pure virtual when Chromium have implemented + // reference counting ADM and Video capture module. + virtual int32_t AddRef() { + assert(false && "Not implemented."); + return 1; + } + + // Decrease the reference count by one. + // Returns the decreased reference count. + // Returns 0 if the last reference was just released. + // When the reference count reach 0 the object will self-destruct. + // TODO(perkj): Make this pure virtual when Chromium have implemented + // reference counting ADM and Video capture module. + virtual int32_t Release() { + assert(false && "Not implemented."); + return 1; + } + + protected: + virtual ~RefCountedModule() {} +}; + +} // namespace webrtc + +#endif // MODULES_INTERFACE_MODULE_H_ diff --git a/libs/miniwebrtc/module_common_types.h b/libs/miniwebrtc/module_common_types.h new file mode 100644 index 00000000..6d571a4f --- /dev/null +++ b/libs/miniwebrtc/module_common_types.h @@ -0,0 +1,1053 @@ +/* + * 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 MODULE_COMMON_TYPES_H +#define MODULE_COMMON_TYPES_H + +#include // memcpy +#include + +#include "typedefs.h" +#include "common_types.h" + +#ifdef _WIN32 + #pragma warning(disable:4351) // remove warning "new behavior: elements of array + // 'array' will be default initialized" +#endif + +namespace webrtc +{ +struct RTPHeader +{ + bool markerBit; + WebRtc_UWord8 payloadType; + WebRtc_UWord16 sequenceNumber; + WebRtc_UWord32 timestamp; + WebRtc_UWord32 ssrc; + WebRtc_UWord8 numCSRCs; + WebRtc_UWord32 arrOfCSRCs[kRtpCsrcSize]; + WebRtc_UWord8 paddingLength; + WebRtc_UWord16 headerLength; +}; + +struct RTPHeaderExtension +{ + WebRtc_Word32 transmissionTimeOffset; +}; + +struct RTPAudioHeader +{ + WebRtc_UWord8 numEnergy; // number of valid entries in arrOfEnergy + WebRtc_UWord8 arrOfEnergy[kRtpCsrcSize]; // one energy byte (0-9) per channel + bool isCNG; // is this CNG + WebRtc_UWord8 channel; // number of channels 2 = stereo +}; + +enum {kNoPictureId = -1}; +enum {kNoTl0PicIdx = -1}; +enum {kNoTemporalIdx = -1}; +enum {kNoKeyIdx = -1}; +enum {kNoSimulcastIdx = 0}; + +struct RTPVideoHeaderVP8 +{ + void InitRTPVideoHeaderVP8() + { + nonReference = false; + pictureId = kNoPictureId; + tl0PicIdx = kNoTl0PicIdx; + temporalIdx = kNoTemporalIdx; + layerSync = false; + keyIdx = kNoKeyIdx; + partitionId = 0; + beginningOfPartition = false; + frameWidth = 0; + frameHeight = 0; + } + + bool nonReference; // Frame is discardable. + WebRtc_Word16 pictureId; // Picture ID index, 15 bits; + // kNoPictureId if PictureID does not exist. + WebRtc_Word16 tl0PicIdx; // TL0PIC_IDX, 8 bits; + // kNoTl0PicIdx means no value provided. + WebRtc_Word8 temporalIdx; // Temporal layer index, or kNoTemporalIdx. + bool layerSync; // This frame is a layer sync frame. + // Disabled if temporalIdx == kNoTemporalIdx. + int keyIdx; // 5 bits; kNoKeyIdx means not used. + int partitionId; // VP8 partition ID + bool beginningOfPartition; // True if this packet is the first + // in a VP8 partition. Otherwise false + int frameWidth; // Exists for key frames. + int frameHeight; // Exists for key frames. +}; +union RTPVideoTypeHeader +{ + RTPVideoHeaderVP8 VP8; +}; + +enum RTPVideoCodecTypes +{ + kRTPVideoGeneric = 0, + kRTPVideoVP8 = 8, + kRTPVideoNoVideo = 10, + kRTPVideoFEC = 11, + kRTPVideoI420 = 12 +}; +struct RTPVideoHeader +{ + WebRtc_UWord16 width; // size + WebRtc_UWord16 height; + + bool isFirstPacket; // first packet in frame + WebRtc_UWord8 simulcastIdx; // Index if the simulcast encoder creating + // this frame, 0 if not using simulcast. + RTPVideoCodecTypes codec; + RTPVideoTypeHeader codecHeader; +}; +union RTPTypeHeader +{ + RTPAudioHeader Audio; + RTPVideoHeader Video; +}; + +struct WebRtcRTPHeader +{ + RTPHeader header; + FrameType frameType; + RTPTypeHeader type; + RTPHeaderExtension extension; +}; + +class RTPFragmentationHeader +{ +public: + RTPFragmentationHeader() : + fragmentationVectorSize(0), + fragmentationOffset(NULL), + fragmentationLength(NULL), + fragmentationTimeDiff(NULL), + fragmentationPlType(NULL) + {}; + + ~RTPFragmentationHeader() + { + delete [] fragmentationOffset; + delete [] fragmentationLength; + delete [] fragmentationTimeDiff; + delete [] fragmentationPlType; + } + + RTPFragmentationHeader& operator=(const RTPFragmentationHeader& header) + { + if(this == &header) + { + return *this; + } + + if(header.fragmentationVectorSize != fragmentationVectorSize) + { + // new size of vectors + + // delete old + delete [] fragmentationOffset; + fragmentationOffset = NULL; + delete [] fragmentationLength; + fragmentationLength = NULL; + delete [] fragmentationTimeDiff; + fragmentationTimeDiff = NULL; + delete [] fragmentationPlType; + fragmentationPlType = NULL; + + if(header.fragmentationVectorSize > 0) + { + // allocate new + if(header.fragmentationOffset) + { + fragmentationOffset = new WebRtc_UWord32[header.fragmentationVectorSize]; + } + if(header.fragmentationLength) + { + fragmentationLength = new WebRtc_UWord32[header.fragmentationVectorSize]; + } + if(header.fragmentationTimeDiff) + { + fragmentationTimeDiff = new WebRtc_UWord16[header.fragmentationVectorSize]; + } + if(header.fragmentationPlType) + { + fragmentationPlType = new WebRtc_UWord8[header.fragmentationVectorSize]; + } + } + // set new size + fragmentationVectorSize = header.fragmentationVectorSize; + } + + if(header.fragmentationVectorSize > 0) + { + // copy values + if(header.fragmentationOffset) + { + memcpy(fragmentationOffset, header.fragmentationOffset, + header.fragmentationVectorSize * sizeof(WebRtc_UWord32)); + } + if(header.fragmentationLength) + { + memcpy(fragmentationLength, header.fragmentationLength, + header.fragmentationVectorSize * sizeof(WebRtc_UWord32)); + } + if(header.fragmentationTimeDiff) + { + memcpy(fragmentationTimeDiff, header.fragmentationTimeDiff, + header.fragmentationVectorSize * sizeof(WebRtc_UWord16)); + } + if(header.fragmentationPlType) + { + memcpy(fragmentationPlType, header.fragmentationPlType, + header.fragmentationVectorSize * sizeof(WebRtc_UWord8)); + } + } + return *this; + } + void VerifyAndAllocateFragmentationHeader( const WebRtc_UWord16 size) + { + if( fragmentationVectorSize < size) + { + WebRtc_UWord16 oldVectorSize = fragmentationVectorSize; + { + // offset + WebRtc_UWord32* oldOffsets = fragmentationOffset; + fragmentationOffset = new WebRtc_UWord32[size]; + memset(fragmentationOffset+oldVectorSize, 0, + sizeof(WebRtc_UWord32)*(size-oldVectorSize)); + // copy old values + memcpy(fragmentationOffset,oldOffsets, sizeof(WebRtc_UWord32) * oldVectorSize); + delete[] oldOffsets; + } + // length + { + WebRtc_UWord32* oldLengths = fragmentationLength; + fragmentationLength = new WebRtc_UWord32[size]; + memset(fragmentationLength+oldVectorSize, 0, + sizeof(WebRtc_UWord32) * (size- oldVectorSize)); + memcpy(fragmentationLength, oldLengths, + sizeof(WebRtc_UWord32) * oldVectorSize); + delete[] oldLengths; + } + // time diff + { + WebRtc_UWord16* oldTimeDiffs = fragmentationTimeDiff; + fragmentationTimeDiff = new WebRtc_UWord16[size]; + memset(fragmentationTimeDiff+oldVectorSize, 0, + sizeof(WebRtc_UWord16) * (size- oldVectorSize)); + memcpy(fragmentationTimeDiff, oldTimeDiffs, + sizeof(WebRtc_UWord16) * oldVectorSize); + delete[] oldTimeDiffs; + } + // payload type + { + WebRtc_UWord8* oldTimePlTypes = fragmentationPlType; + fragmentationPlType = new WebRtc_UWord8[size]; + memset(fragmentationPlType+oldVectorSize, 0, + sizeof(WebRtc_UWord8) * (size- oldVectorSize)); + memcpy(fragmentationPlType, oldTimePlTypes, + sizeof(WebRtc_UWord8) * oldVectorSize); + delete[] oldTimePlTypes; + } + fragmentationVectorSize = size; + } + } + + WebRtc_UWord16 fragmentationVectorSize; // Number of fragmentations + WebRtc_UWord32* fragmentationOffset; // Offset of pointer to data for each fragm. + WebRtc_UWord32* fragmentationLength; // Data size for each fragmentation + WebRtc_UWord16* fragmentationTimeDiff; // Timestamp difference relative "now" for + // each fragmentation + WebRtc_UWord8* fragmentationPlType; // Payload type of each fragmentation +}; + +struct RTCPVoIPMetric +{ + // RFC 3611 4.7 + WebRtc_UWord8 lossRate; + WebRtc_UWord8 discardRate; + WebRtc_UWord8 burstDensity; + WebRtc_UWord8 gapDensity; + WebRtc_UWord16 burstDuration; + WebRtc_UWord16 gapDuration; + WebRtc_UWord16 roundTripDelay; + WebRtc_UWord16 endSystemDelay; + WebRtc_UWord8 signalLevel; + WebRtc_UWord8 noiseLevel; + WebRtc_UWord8 RERL; + WebRtc_UWord8 Gmin; + WebRtc_UWord8 Rfactor; + WebRtc_UWord8 extRfactor; + WebRtc_UWord8 MOSLQ; + WebRtc_UWord8 MOSCQ; + WebRtc_UWord8 RXconfig; + WebRtc_UWord16 JBnominal; + WebRtc_UWord16 JBmax; + WebRtc_UWord16 JBabsMax; +}; + +// class describing a complete, or parts of an encoded frame. +class EncodedVideoData +{ +public: + EncodedVideoData() : + completeFrame(false), + missingFrame(false), + payloadData(NULL), + payloadSize(0), + bufferSize(0) + {}; + + EncodedVideoData(const EncodedVideoData& data) + { + payloadType = data.payloadType; + timeStamp = data.timeStamp; + renderTimeMs = data.renderTimeMs; + encodedWidth = data.encodedWidth; + encodedHeight = data.encodedHeight; + completeFrame = data.completeFrame; + missingFrame = data.missingFrame; + payloadSize = data.payloadSize; + fragmentationHeader = data.fragmentationHeader; + frameType = data.frameType; + codec = data.codec; + if (data.payloadSize > 0) + { + payloadData = new WebRtc_UWord8[data.payloadSize]; + memcpy(payloadData, data.payloadData, data.payloadSize); + } + else + { + payloadData = NULL; + } + } + + + ~EncodedVideoData() + { + delete [] payloadData; + }; + + EncodedVideoData& operator=(const EncodedVideoData& data) + { + if (this == &data) + { + return *this; + } + payloadType = data.payloadType; + timeStamp = data.timeStamp; + renderTimeMs = data.renderTimeMs; + encodedWidth = data.encodedWidth; + encodedHeight = data.encodedHeight; + completeFrame = data.completeFrame; + missingFrame = data.missingFrame; + payloadSize = data.payloadSize; + fragmentationHeader = data.fragmentationHeader; + frameType = data.frameType; + codec = data.codec; + if (data.payloadSize > 0) + { + delete [] payloadData; + payloadData = new WebRtc_UWord8[data.payloadSize]; + memcpy(payloadData, data.payloadData, data.payloadSize); + bufferSize = data.payloadSize; + } + return *this; + }; + void VerifyAndAllocate( const WebRtc_UWord32 size) + { + if (bufferSize < size) + { + WebRtc_UWord8* oldPayload = payloadData; + payloadData = new WebRtc_UWord8[size]; + memcpy(payloadData, oldPayload, sizeof(WebRtc_UWord8) * payloadSize); + + bufferSize = size; + delete[] oldPayload; + } + } + + WebRtc_UWord8 payloadType; + WebRtc_UWord32 timeStamp; + WebRtc_Word64 renderTimeMs; + WebRtc_UWord32 encodedWidth; + WebRtc_UWord32 encodedHeight; + bool completeFrame; + bool missingFrame; + WebRtc_UWord8* payloadData; + WebRtc_UWord32 payloadSize; + WebRtc_UWord32 bufferSize; + RTPFragmentationHeader fragmentationHeader; + FrameType frameType; + VideoCodecType codec; +}; + +// Video Content Metrics +struct VideoContentMetrics +{ + VideoContentMetrics(): motionMagnitudeNZ(0), sizeZeroMotion(0), spatialPredErr(0), + spatialPredErrH(0), spatialPredErrV(0), motionPredErr(0), + motionHorizontalness(0), motionClusterDistortion(0), + nativeWidth(0), nativeHeight(0), contentChange(false) { } + void Reset(){ motionMagnitudeNZ = 0; sizeZeroMotion = 0; spatialPredErr = 0; + spatialPredErrH = 0; spatialPredErrV = 0; motionPredErr = 0; + motionHorizontalness = 0; motionClusterDistortion = 0; + nativeWidth = 0; nativeHeight = 0; contentChange = false; } + + float motionMagnitudeNZ; + float sizeZeroMotion; + float spatialPredErr; + float spatialPredErrH; + float spatialPredErrV; + float motionPredErr; + float motionHorizontalness; + float motionClusterDistortion; + WebRtc_UWord32 nativeWidth; + WebRtc_UWord32 nativeHeight; + WebRtc_UWord32 nativeFrameRate; + bool contentChange; +}; + +/************************************************* + * + * VideoFrame class + * + * The VideoFrame class allows storing and + * handling of video frames. + * + * + *************************************************/ +class VideoFrame +{ +public: + VideoFrame(); + ~VideoFrame(); + /** + * Verifies that current allocated buffer size is larger than or equal to the input size. + * If the current buffer size is smaller, a new allocation is made and the old buffer data + * is copied to the new buffer. + * Buffer size is updated to minimumSize. + */ + WebRtc_Word32 VerifyAndAllocate(const WebRtc_UWord32 minimumSize); + /** + * Update length of data buffer in frame. Function verifies that new length is less or + * equal to allocated size. + */ + WebRtc_Word32 SetLength(const WebRtc_UWord32 newLength); + /* + * Swap buffer and size data + */ + WebRtc_Word32 Swap(WebRtc_UWord8*& newMemory, + WebRtc_UWord32& newLength, + WebRtc_UWord32& newSize); + /* + * Swap buffer and size data + */ + WebRtc_Word32 SwapFrame(VideoFrame& videoFrame); + /** + * Copy buffer: If newLength is bigger than allocated size, a new buffer of size length + * is allocated. + */ + WebRtc_Word32 CopyFrame(const VideoFrame& videoFrame); + /** + * Copy buffer: If newLength is bigger than allocated size, a new buffer of size length + * is allocated. + */ + WebRtc_Word32 CopyFrame(WebRtc_UWord32 length, const WebRtc_UWord8* sourceBuffer); + /** + * Delete VideoFrame and resets members to zero + */ + void Free(); + /** + * Set frame timestamp (90kHz) + */ + void SetTimeStamp(const WebRtc_UWord32 timeStamp) {_timeStamp = timeStamp;} + /** + * Get pointer to frame buffer + */ + WebRtc_UWord8* Buffer() const {return _buffer;} + + WebRtc_UWord8*& Buffer() {return _buffer;} + + /** + * Get allocated buffer size + */ + WebRtc_UWord32 Size() const {return _bufferSize;} + /** + * Get frame length + */ + WebRtc_UWord32 Length() const {return _bufferLength;} + /** + * Get frame timestamp (90kHz) + */ + WebRtc_UWord32 TimeStamp() const {return _timeStamp;} + /** + * Get frame width + */ + WebRtc_UWord32 Width() const {return _width;} + /** + * Get frame height + */ + WebRtc_UWord32 Height() const {return _height;} + /** + * Set frame width + */ + void SetWidth(const WebRtc_UWord32 width) {_width = width;} + /** + * Set frame height + */ + void SetHeight(const WebRtc_UWord32 height) {_height = height;} + /** + * Set render time in miliseconds + */ + void SetRenderTime(const WebRtc_Word64 renderTimeMs) {_renderTimeMs = renderTimeMs;} + /** + * Get render time in miliseconds + */ + WebRtc_Word64 RenderTimeMs() const {return _renderTimeMs;} + +private: + void Set(WebRtc_UWord8* buffer, + WebRtc_UWord32 size, + WebRtc_UWord32 length, + WebRtc_UWord32 timeStamp); + + WebRtc_UWord8* _buffer; // Pointer to frame buffer + WebRtc_UWord32 _bufferSize; // Allocated buffer size + WebRtc_UWord32 _bufferLength; // Length (in bytes) of buffer + WebRtc_UWord32 _timeStamp; // Timestamp of frame (90kHz) + WebRtc_UWord32 _width; + WebRtc_UWord32 _height; + WebRtc_Word64 _renderTimeMs; +}; // end of VideoFrame class declaration + +// inline implementation of VideoFrame class: +inline +VideoFrame::VideoFrame(): + _buffer(0), + _bufferSize(0), + _bufferLength(0), + _timeStamp(0), + _width(0), + _height(0), + _renderTimeMs(0) +{ + // +} +inline +VideoFrame::~VideoFrame() +{ + if(_buffer) + { + delete [] _buffer; + _buffer = NULL; + } +} + + +inline +WebRtc_Word32 +VideoFrame::VerifyAndAllocate(const WebRtc_UWord32 minimumSize) +{ + if (minimumSize < 1) + { + return -1; + } + if(minimumSize > _bufferSize) + { + // create buffer of sufficient size + WebRtc_UWord8* newBufferBuffer = new WebRtc_UWord8[minimumSize]; + if(_buffer) + { + // copy old data + memcpy(newBufferBuffer, _buffer, _bufferSize); + delete [] _buffer; + } + else + { + memset(newBufferBuffer, 0, minimumSize * sizeof(WebRtc_UWord8)); + } + _buffer = newBufferBuffer; + _bufferSize = minimumSize; + } + return 0; +} + +inline +WebRtc_Word32 +VideoFrame::SetLength(const WebRtc_UWord32 newLength) +{ + if (newLength >_bufferSize ) + { // can't accomodate new value + return -1; + } + _bufferLength = newLength; + return 0; +} + +inline +WebRtc_Word32 +VideoFrame::SwapFrame(VideoFrame& videoFrame) +{ + WebRtc_UWord32 tmpTimeStamp = _timeStamp; + WebRtc_UWord32 tmpWidth = _width; + WebRtc_UWord32 tmpHeight = _height; + WebRtc_Word64 tmpRenderTime = _renderTimeMs; + + _timeStamp = videoFrame._timeStamp; + _width = videoFrame._width; + _height = videoFrame._height; + _renderTimeMs = videoFrame._renderTimeMs; + + videoFrame._timeStamp = tmpTimeStamp; + videoFrame._width = tmpWidth; + videoFrame._height = tmpHeight; + videoFrame._renderTimeMs = tmpRenderTime; + + return Swap(videoFrame._buffer, videoFrame._bufferLength, videoFrame._bufferSize); +} + +inline +WebRtc_Word32 +VideoFrame::Swap(WebRtc_UWord8*& newMemory, WebRtc_UWord32& newLength, WebRtc_UWord32& newSize) +{ + WebRtc_UWord8* tmpBuffer = _buffer; + WebRtc_UWord32 tmpLength = _bufferLength; + WebRtc_UWord32 tmpSize = _bufferSize; + _buffer = newMemory; + _bufferLength = newLength; + _bufferSize = newSize; + newMemory = tmpBuffer; + newLength = tmpLength; + newSize = tmpSize; + return 0; +} + +inline +WebRtc_Word32 +VideoFrame::CopyFrame(WebRtc_UWord32 length, const WebRtc_UWord8* sourceBuffer) +{ + if (length > _bufferSize) + { + WebRtc_Word32 ret = VerifyAndAllocate(length); + if (ret < 0) + { + return ret; + } + } + memcpy(_buffer, sourceBuffer, length); + _bufferLength = length; + return 0; +} + +inline +WebRtc_Word32 +VideoFrame::CopyFrame(const VideoFrame& videoFrame) +{ + if(CopyFrame(videoFrame.Length(), videoFrame.Buffer()) != 0) + { + return -1; + } + _timeStamp = videoFrame._timeStamp; + _width = videoFrame._width; + _height = videoFrame._height; + _renderTimeMs = videoFrame._renderTimeMs; + return 0; +} + +inline +void +VideoFrame::Free() +{ + _timeStamp = 0; + _bufferLength = 0; + _bufferSize = 0; + _height = 0; + _width = 0; + _renderTimeMs = 0; + + if(_buffer) + { + delete [] _buffer; + _buffer = NULL; + } +} + + +/************************************************* + * + * AudioFrame class + * + * The AudioFrame class holds up to 60 ms wideband + * audio. It allows for adding and subtracting frames + * while keeping track of the resulting states. + * + * Note + * - The +operator assume that you would never add + * exact opposite frames when deciding the resulting + * state. To do this use the -operator. + * + * - _audioChannel of 1 indicated mono, and 2 + * indicates stereo. + * + * - _payloadDataLengthInSamples is the number of + * samples per channel. Therefore, the total + * number of samples in _payloadData is + * (_payloadDataLengthInSamples * _audioChannel). + * + * - Stereo data is stored in interleaved fashion + * starting with the left channel. + * + *************************************************/ +class AudioFrame +{ +public: + enum{kMaxAudioFrameSizeSamples = 3840}; // stereo 32KHz 60ms 2*32*60 + + enum VADActivity + { + kVadActive = 0, + kVadPassive = 1, + kVadUnknown = 2 + }; + enum SpeechType + { + kNormalSpeech = 0, + kPLC = 1, + kCNG = 2, + kPLCCNG = 3, + kUndefined = 4 + }; + + AudioFrame(); + virtual ~AudioFrame(); + + WebRtc_Word32 UpdateFrame( + const WebRtc_Word32 id, + const WebRtc_UWord32 timeStamp, + const WebRtc_Word16* payloadData, + const WebRtc_UWord16 payloadDataLengthInSamples, + const int frequencyInHz, + const SpeechType speechType, + const VADActivity vadActivity, + const WebRtc_UWord8 audioChannel = 1, + const WebRtc_Word32 volume = -1, + const WebRtc_Word32 energy = -1); + + AudioFrame& Append(const AudioFrame& rhs); + + void Mute(); + + AudioFrame& operator=(const AudioFrame& rhs); + AudioFrame& operator>>=(const WebRtc_Word32 rhs); + AudioFrame& operator+=(const AudioFrame& rhs); + AudioFrame& operator-=(const AudioFrame& rhs); + + WebRtc_Word32 _id; + WebRtc_UWord32 _timeStamp; + + // Supporting Stereo, stereo samples are interleaved + WebRtc_Word16 _payloadData[kMaxAudioFrameSizeSamples]; + WebRtc_UWord16 _payloadDataLengthInSamples; + int _frequencyInHz; + WebRtc_UWord8 _audioChannel; + SpeechType _speechType; + VADActivity _vadActivity; + + WebRtc_UWord32 _energy; + WebRtc_Word32 _volume; +}; + +inline +AudioFrame::AudioFrame() + : + _id(-1), + _timeStamp(0), + _payloadData(), + _payloadDataLengthInSamples(0), + _frequencyInHz(0), + _audioChannel(1), + _speechType(kUndefined), + _vadActivity(kVadUnknown), + _energy(0xffffffff), + _volume(0xffffffff) +{ +} + +inline +AudioFrame::~AudioFrame() +{ +} + +inline +WebRtc_Word32 +AudioFrame::UpdateFrame( + const WebRtc_Word32 id, + const WebRtc_UWord32 timeStamp, + const WebRtc_Word16* payloadData, + const WebRtc_UWord16 payloadDataLengthInSamples, + const int frequencyInHz, + const SpeechType speechType, + const VADActivity vadActivity, + const WebRtc_UWord8 audioChannel, + const WebRtc_Word32 volume, + const WebRtc_Word32 energy) +{ + _id = id; + _timeStamp = timeStamp; + _frequencyInHz = frequencyInHz; + _speechType = speechType; + _vadActivity = vadActivity; + _volume = volume; + _audioChannel = audioChannel; + _energy = energy; + + if((payloadDataLengthInSamples > kMaxAudioFrameSizeSamples) || + (audioChannel > 2) || (audioChannel < 1)) + { + _payloadDataLengthInSamples = 0; + return -1; + } + _payloadDataLengthInSamples = payloadDataLengthInSamples; + if(payloadData != NULL) + { + memcpy(_payloadData, payloadData, sizeof(WebRtc_Word16) * + payloadDataLengthInSamples * _audioChannel); + } + else + { + memset(_payloadData,0,sizeof(WebRtc_Word16) * + payloadDataLengthInSamples * _audioChannel); + } + return 0; +} + +inline +void +AudioFrame::Mute() +{ + memset(_payloadData, 0, _payloadDataLengthInSamples * sizeof(WebRtc_Word16)); +} + +inline +AudioFrame& +AudioFrame::operator=(const AudioFrame& rhs) +{ + // Sanity Check + if((rhs._payloadDataLengthInSamples > kMaxAudioFrameSizeSamples) || + (rhs._audioChannel > 2) || + (rhs._audioChannel < 1)) + { + return *this; + } + if(this == &rhs) + { + return *this; + } + _id = rhs._id; + _timeStamp = rhs._timeStamp; + _frequencyInHz = rhs._frequencyInHz; + _speechType = rhs._speechType; + _vadActivity = rhs._vadActivity; + _volume = rhs._volume; + _audioChannel = rhs._audioChannel; + _energy = rhs._energy; + + _payloadDataLengthInSamples = rhs._payloadDataLengthInSamples; + memcpy(_payloadData, rhs._payloadData, + sizeof(WebRtc_Word16) * rhs._payloadDataLengthInSamples * _audioChannel); + + return *this; +} + +inline +AudioFrame& +AudioFrame::operator>>=(const WebRtc_Word32 rhs) +{ + assert((_audioChannel > 0) && (_audioChannel < 3)); + if((_audioChannel > 2) || + (_audioChannel < 1)) + { + return *this; + } + for(WebRtc_UWord16 i = 0; i < _payloadDataLengthInSamples * _audioChannel; i++) + { + _payloadData[i] = WebRtc_Word16(_payloadData[i] >> rhs); + } + return *this; +} + +inline +AudioFrame& +AudioFrame::Append(const AudioFrame& rhs) +{ + // Sanity check + assert((_audioChannel > 0) && (_audioChannel < 3)); + if((_audioChannel > 2) || + (_audioChannel < 1)) + { + return *this; + } + if(_audioChannel != rhs._audioChannel) + { + return *this; + } + if((_vadActivity == kVadActive) || + rhs._vadActivity == kVadActive) + { + _vadActivity = kVadActive; + } + else if((_vadActivity == kVadUnknown) || + rhs._vadActivity == kVadUnknown) + { + _vadActivity = kVadUnknown; + } + if(_speechType != rhs._speechType) + { + _speechType = kUndefined; + } + + WebRtc_UWord16 offset = _payloadDataLengthInSamples * _audioChannel; + for(WebRtc_UWord16 i = 0; + i < rhs._payloadDataLengthInSamples * rhs._audioChannel; + i++) + { + _payloadData[offset+i] = rhs._payloadData[i]; + } + _payloadDataLengthInSamples += rhs._payloadDataLengthInSamples; + return *this; +} + +// merge vectors +inline +AudioFrame& +AudioFrame::operator+=(const AudioFrame& rhs) +{ + // Sanity check + assert((_audioChannel > 0) && (_audioChannel < 3)); + if((_audioChannel > 2) || + (_audioChannel < 1)) + { + return *this; + } + if(_audioChannel != rhs._audioChannel) + { + return *this; + } + bool noPrevData = false; + if(_payloadDataLengthInSamples != rhs._payloadDataLengthInSamples) + { + if(_payloadDataLengthInSamples == 0) + { + // special case we have no data to start with + _payloadDataLengthInSamples = rhs._payloadDataLengthInSamples; + noPrevData = true; + } else + { + return *this; + } + } + + if((_vadActivity == kVadActive) || + rhs._vadActivity == kVadActive) + { + _vadActivity = kVadActive; + } + else if((_vadActivity == kVadUnknown) || + rhs._vadActivity == kVadUnknown) + { + _vadActivity = kVadUnknown; + } + + if(_speechType != rhs._speechType) + { + _speechType = kUndefined; + } + + if(noPrevData) + { + memcpy(_payloadData, rhs._payloadData, + sizeof(WebRtc_Word16) * rhs._payloadDataLengthInSamples * _audioChannel); + } else + { + // IMPROVEMENT this can be done very fast in assembly + for(WebRtc_UWord16 i = 0; i < _payloadDataLengthInSamples * _audioChannel; i++) + { + WebRtc_Word32 wrapGuard = (WebRtc_Word32)_payloadData[i] + + (WebRtc_Word32)rhs._payloadData[i]; + if(wrapGuard < -32768) + { + _payloadData[i] = -32768; + }else if(wrapGuard > 32767) + { + _payloadData[i] = 32767; + }else + { + _payloadData[i] = (WebRtc_Word16)wrapGuard; + } + } + } + _energy = 0xffffffff; + _volume = 0xffffffff; + return *this; +} + +inline +AudioFrame& +AudioFrame::operator-=(const AudioFrame& rhs) +{ + // Sanity check + assert((_audioChannel > 0) && (_audioChannel < 3)); + if((_audioChannel > 2)|| + (_audioChannel < 1)) + { + return *this; + } + if((_payloadDataLengthInSamples != rhs._payloadDataLengthInSamples) || + (_audioChannel != rhs._audioChannel)) + { + return *this; + } + if((_vadActivity != kVadPassive) || + rhs._vadActivity != kVadPassive) + { + _vadActivity = kVadUnknown; + } + _speechType = kUndefined; + + for(WebRtc_UWord16 i = 0; i < _payloadDataLengthInSamples * _audioChannel; i++) + { + WebRtc_Word32 wrapGuard = (WebRtc_Word32)_payloadData[i] - + (WebRtc_Word32)rhs._payloadData[i]; + if(wrapGuard < -32768) + { + _payloadData[i] = -32768; + } + else if(wrapGuard > 32767) + { + _payloadData[i] = 32767; + } + else + { + _payloadData[i] = (WebRtc_Word16)wrapGuard; + } + } + _energy = 0xffffffff; + _volume = 0xffffffff; + return *this; +} + +} // namespace webrtc + +#endif // MODULE_COMMON_TYPES_H diff --git a/libs/miniwebrtc/system_wrappers/cpu.cc b/libs/miniwebrtc/system_wrappers/cpu.cc new file mode 100644 index 00000000..3df5d183 --- /dev/null +++ b/libs/miniwebrtc/system_wrappers/cpu.cc @@ -0,0 +1,38 @@ +/* + * 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 "cpu_wrapper.h" + +#if defined(_WIN32) + #include "cpu_win.h" +#elif defined(WEBRTC_MAC) + #include "cpu_mac.h" +#elif defined(WEBRTC_MAC_INTEL) + #include "cpu_mac.h" +#elif defined(WEBRTC_ANDROID) + // Not implemented yet, might be possible to use Linux implementation +#else // defined(WEBRTC_LINUX) + #include "cpu_linux.h" +#endif + +namespace webrtc { +CpuWrapper* CpuWrapper::CreateCpu() +{ +#if defined(_WIN32) + return new CpuWindows(); +#elif (defined(WEBRTC_MAC) || defined(WEBRTC_MAC_INTEL)) + return new CpuWrapperMac(); +#elif defined(WEBRTC_ANDROID) + return 0; +#else + return new CpuLinux(); +#endif +} +} // namespace webrtc diff --git a/libs/miniwebrtc/system_wrappers/cpu_features.cc b/libs/miniwebrtc/system_wrappers/cpu_features.cc new file mode 100644 index 00000000..41a86e36 --- /dev/null +++ b/libs/miniwebrtc/system_wrappers/cpu_features.cc @@ -0,0 +1,74 @@ +/* + * 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. + */ + +// Parts of this file derived from Chromium's base/cpu.cc. + +#include "cpu_features_wrapper.h" + +#include "typedefs.h" + +#if defined(WEBRTC_ARCH_X86_FAMILY) +#if defined(_MSC_VER) +#include +#endif +#endif + +// No CPU feature is available => straight C path. +int GetCPUInfoNoASM(CPUFeature feature) { + (void)feature; + return 0; +} + +#if defined(WEBRTC_ARCH_X86_FAMILY) +#ifndef _MSC_VER +// Intrinsic for "cpuid". +#if defined(__pic__) && defined(__i386__) +static inline void __cpuid(int cpu_info[4], int info_type) { + __asm__ volatile ( + "mov %%ebx, %%edi\n" + "cpuid\n" + "xchg %%edi, %%ebx\n" + : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) + : "a"(info_type)); +} +#else +static inline void __cpuid(int cpu_info[4], int info_type) { + __asm__ volatile ( + "cpuid\n" + : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3]) + : "a"(info_type)); +} +#endif +#endif // _MSC_VER +#endif // WEBRTC_ARCH_X86_FAMILY + +#if defined(WEBRTC_ARCH_X86_FAMILY) +// Actual feature detection for x86. +static int GetCPUInfo(CPUFeature feature) { + int cpu_info[4]; + __cpuid(cpu_info, 1); + if (feature == kSSE2) { + return 0 != (cpu_info[3] & 0x04000000); + } + if (feature == kSSE3) { + return 0 != (cpu_info[2] & 0x00000001); + } + return 0; +} +#else +// Default to straight C for other platforms. +static int GetCPUInfo(CPUFeature feature) { + (void)feature; + return 0; +} +#endif + +WebRtc_CPUInfo WebRtc_GetCPUInfo = GetCPUInfo; +WebRtc_CPUInfo WebRtc_GetCPUInfoNoASM = GetCPUInfoNoASM; diff --git a/libs/miniwebrtc/system_wrappers/cpu_features_arm.c b/libs/miniwebrtc/system_wrappers/cpu_features_arm.c new file mode 100644 index 00000000..10651185 --- /dev/null +++ b/libs/miniwebrtc/system_wrappers/cpu_features_arm.c @@ -0,0 +1,333 @@ +/* + * 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 +// /sources/android/cpufeatures/ (downloadable from +// http://developer.android.com/sdk/ndk/index.html). + +#include "cpu_features_wrapper.h" + +#include +#include +#include +#include +#include + +// 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/libs/miniwebrtc/system_wrappers/cpu_features_wrapper.h b/libs/miniwebrtc/system_wrappers/cpu_features_wrapper.h new file mode 100644 index 00000000..d9495921 --- /dev/null +++ b/libs/miniwebrtc/system_wrappers/cpu_features_wrapper.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_FEATURES_WRAPPER_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_FEATURES_WRAPPER_H_ + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#include + +// List of features in x86. +typedef enum { + kSSE2, + kSSE3 +} CPUFeature; + +// List of features in ARM. +enum { + kCPUFeatureARMv7 = (1 << 0), + kCPUFeatureVFPv3 = (1 << 1), + kCPUFeatureNEON = (1 << 2), + kCPUFeatureLDREXSTREX = (1 << 3) +}; + +typedef int (*WebRtc_CPUInfo)(CPUFeature feature); +// returns true if the CPU supports the feature. +extern WebRtc_CPUInfo WebRtc_GetCPUInfo; +// No CPU feature is available => straight C path. +extern WebRtc_CPUInfo WebRtc_GetCPUInfoNoASM; + +// Return the features in an ARM device. +// It detects the features in the hardware platform, and returns supported +// values in the above enum definition as a bitmask. +extern uint64_t WebRtc_GetCPUFeaturesARM(void); + +#if defined(__cplusplus) || defined(c_plusplus) +} // extern "C" +#endif + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CPU_FEATURES_WRAPPER_H_ diff --git a/libs/miniwebrtc/system_wrappers/cpu_info.cc b/libs/miniwebrtc/system_wrappers/cpu_info.cc new file mode 100644 index 00000000..e367abfb --- /dev/null +++ b/libs/miniwebrtc/system_wrappers/cpu_info.cc @@ -0,0 +1,72 @@ +/* + * 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 "cpu_info.h" + +#if defined(_WIN32) +#include +#elif defined(WEBRTC_MAC) +#include +#include +#elif defined(WEBRTC_MAC_INTEL) +// Intentionally empty +#elif defined(WEBRTC_ANDROID) +// Not implemented yet, might be possible to use Linux implementation +#else // defined(WEBRTC_LINUX) +#include +#endif + +#include "trace.h" + +namespace webrtc { + +WebRtc_UWord32 CpuInfo::_numberOfCores = 0; + +WebRtc_UWord32 CpuInfo::DetectNumberOfCores() +{ + if (!_numberOfCores) + { +#if defined(_WIN32) + SYSTEM_INFO si; + GetSystemInfo(&si); + _numberOfCores = static_cast(si.dwNumberOfProcessors); + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, + "Available number of cores:%d", _numberOfCores); + +#elif defined(WEBRTC_LINUX) && !defined(WEBRTC_ANDROID) + _numberOfCores = get_nprocs(); + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, + "Available number of cores:%d", _numberOfCores); + +#elif (defined(WEBRTC_MAC) || defined(WEBRTC_MAC_INTEL)) + int name[] = {CTL_HW, HW_AVAILCPU}; + int ncpu; + size_t size = sizeof(ncpu); + if(0 == sysctl(name, 2, &ncpu, &size, NULL, 0)) + { + _numberOfCores = static_cast(ncpu); + WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, + "Available number of cores:%d", _numberOfCores); + } else + { + WEBRTC_TRACE(kTraceError, kTraceUtility, -1, + "Failed to get number of cores"); + _numberOfCores = 1; + } +#else + WEBRTC_TRACE(kTraceWarning, kTraceUtility, -1, + "No function to get number of cores"); + _numberOfCores = 1; +#endif + } + return _numberOfCores; +} + +} // namespace webrtc diff --git a/libs/miniwebrtc/system_wrappers/cpu_linux.cc b/libs/miniwebrtc/system_wrappers/cpu_linux.cc new file mode 100644 index 00000000..8e8ecda6 --- /dev/null +++ b/libs/miniwebrtc/system_wrappers/cpu_linux.cc @@ -0,0 +1,202 @@ +/* + * 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 "cpu_linux.h" + +#include +#include +#include +#include + +namespace webrtc { +CpuLinux::CpuLinux() + : m_oldBusyTime(0), + m_oldIdleTime(0), + m_oldBusyTimeMulti(NULL), + m_oldIdleTimeMulti(NULL), + m_idleArray(NULL), + m_busyArray(NULL), + m_resultArray(NULL), + m_numCores(0) { + const int result = GetNumCores(); + if (result != -1) { + m_numCores = result; + m_oldBusyTimeMulti = new long long[m_numCores]; + memset(m_oldBusyTimeMulti, 0, sizeof(long long) * m_numCores); + m_oldIdleTimeMulti = new long long[m_numCores]; + memset(m_oldIdleTimeMulti, 0, sizeof(long long) * m_numCores); + m_idleArray = new long long[m_numCores]; + memset(m_idleArray, 0, sizeof(long long) * m_numCores); + m_busyArray = new long long[m_numCores]; + memset(m_busyArray, 0, sizeof(long long) * m_numCores); + m_resultArray = new WebRtc_UWord32[m_numCores]; + + GetData(m_oldBusyTime, m_oldIdleTime, m_busyArray, m_idleArray); + } +} + +CpuLinux::~CpuLinux() +{ + delete [] m_oldBusyTimeMulti; + delete [] m_oldIdleTimeMulti; + delete [] m_idleArray; + delete [] m_busyArray; + delete [] m_resultArray; +} + +WebRtc_Word32 CpuLinux::CpuUsage() +{ + WebRtc_UWord32 dummy = 0; + WebRtc_UWord32* dummyArray = NULL; + return CpuUsageMultiCore(dummy, dummyArray); +} + +WebRtc_Word32 CpuLinux::CpuUsageMultiCore(WebRtc_UWord32& numCores, + WebRtc_UWord32*& coreArray) +{ + coreArray = m_resultArray; + numCores = m_numCores; + long long busy = 0; + long long idle = 0; + if (GetData(busy, idle, m_busyArray, m_idleArray) != 0) + return -1; + + long long deltaBusy = busy - m_oldBusyTime; + long long deltaIdle = idle - m_oldIdleTime; + m_oldBusyTime = busy; + m_oldIdleTime = idle; + + int retVal = -1; + if (deltaBusy + deltaIdle == 0) + { + retVal = 0; + } + else + { + retVal = (int)(100 * (deltaBusy) / (deltaBusy + deltaIdle)); + } + + if (coreArray == NULL) + { + return retVal; + } + + for (WebRtc_UWord32 i = 0; i < m_numCores; i++) + { + deltaBusy = m_busyArray[i] - m_oldBusyTimeMulti[i]; + deltaIdle = m_idleArray[i] - m_oldIdleTimeMulti[i]; + m_oldBusyTimeMulti[i] = m_busyArray[i]; + m_oldIdleTimeMulti[i] = m_idleArray[i]; + if(deltaBusy + deltaIdle == 0) + { + coreArray[i] = 0; + } + else + { + coreArray[i] = (int)(100 * (deltaBusy) / (deltaBusy+deltaIdle)); + } + } + return retVal; +} + + +int CpuLinux::GetData(long long& busy, long long& idle, long long*& busyArray, + long long*& idleArray) +{ + FILE* fp = fopen("/proc/stat", "r"); + if (!fp) + { + return -1; + } + + char line[100]; + if (fgets(line, 100, fp) == NULL) { + fclose(fp); + return -1; + } + char firstWord[100]; + if (sscanf(line, "%s ", firstWord) != 1) { + fclose(fp); + return -1; + } + if (strncmp(firstWord, "cpu", 3) != 0) { + fclose(fp); + return -1; + } + char sUser[100]; + char sNice[100]; + char sSystem[100]; + char sIdle[100]; + if (sscanf(line, "%s %s %s %s %s ", + firstWord, sUser, sNice, sSystem, sIdle) != 5) { + fclose(fp); + return -1; + } + long long luser = atoll(sUser); + long long lnice = atoll(sNice); + long long lsystem = atoll(sSystem); + long long lidle = atoll (sIdle); + + busy = luser + lnice + lsystem; + idle = lidle; + for (WebRtc_UWord32 i = 0; i < m_numCores; i++) + { + if (fgets(line, 100, fp) == NULL) { + fclose(fp); + return -1; + } + if (sscanf(line, "%s %s %s %s %s ", firstWord, sUser, sNice, sSystem, + sIdle) != 5) { + fclose(fp); + return -1; + } + luser = atoll(sUser); + lnice = atoll(sNice); + lsystem = atoll(sSystem); + lidle = atoll (sIdle); + busyArray[i] = luser + lnice + lsystem; + idleArray[i] = lidle; + } + fclose(fp); + return 0; +} + +int CpuLinux::GetNumCores() +{ + FILE* fp = fopen("/proc/stat", "r"); + if (!fp) + { + return -1; + } + // Skip first line + char line[100]; + if (!fgets(line, 100, fp)) + { + fclose(fp); + return -1; + } + int numCores = -1; + char firstWord[100]; + do + { + numCores++; + if (fgets(line, 100, fp)) + { + if (sscanf(line, "%s ", firstWord) != 1) { + firstWord[0] = '\0'; + } + } else { + break; + } + } while (strncmp(firstWord, "cpu", 3) == 0); + fclose(fp); + return numCores; +} +} // namespace webrtc diff --git a/libs/miniwebrtc/system_wrappers/cpu_linux.h b/libs/miniwebrtc/system_wrappers/cpu_linux.h new file mode 100644 index 00000000..9b22e836 --- /dev/null +++ b/libs/miniwebrtc/system_wrappers/cpu_linux.h @@ -0,0 +1,51 @@ +/* + * 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_LINUX_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_LINUX_H_ + +#include "cpu_wrapper.h" + +namespace webrtc { +class CpuLinux : public CpuWrapper +{ +public: + CpuLinux(); + virtual ~CpuLinux(); + + virtual WebRtc_Word32 CpuUsage(); + virtual WebRtc_Word32 CpuUsage(WebRtc_Word8* /*pProcessName*/, + WebRtc_UWord32 /*length*/) {return 0;} + virtual WebRtc_Word32 CpuUsage(WebRtc_UWord32 /*dwProcessID*/) {return 0;} + + virtual WebRtc_Word32 CpuUsageMultiCore(WebRtc_UWord32& numCores, + WebRtc_UWord32*& array); + + virtual void Reset() {return;} + virtual void Stop() {return;} +private: + int GetData(long long& busy, long long& idle, long long*& busyArray, + long long*& idleArray); + int GetNumCores(); + + long long m_oldBusyTime; + long long m_oldIdleTime; + + long long* m_oldBusyTimeMulti; + long long* m_oldIdleTimeMulti; + + long long* m_idleArray; + long long* m_busyArray; + WebRtc_UWord32* m_resultArray; + WebRtc_UWord32 m_numCores; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_LINUX_H_ diff --git a/libs/miniwebrtc/system_wrappers/cpu_mac.cc b/libs/miniwebrtc/system_wrappers/cpu_mac.cc new file mode 100644 index 00000000..d82bf07d --- /dev/null +++ b/libs/miniwebrtc/system_wrappers/cpu_mac.cc @@ -0,0 +1,143 @@ +/* + * 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 "cpu_mac.h" + +#include +#include +#include + +#include "tick_util.h" + +namespace webrtc { +CpuWrapperMac::CpuWrapperMac() + : _cpuCount(0), + _cpuUsage(NULL), + _totalCpuUsage(0), + _lastTickCount(NULL), + _lastTime(0) +{ + natural_t cpuCount; + processor_info_array_t infoArray; + mach_msg_type_number_t infoCount; + + kern_return_t error = host_processor_info(mach_host_self(), + PROCESSOR_CPU_LOAD_INFO, + &cpuCount, + &infoArray, + &infoCount); + if (error) + { + return; + } + + _cpuCount = cpuCount; + _cpuUsage = new WebRtc_UWord32[cpuCount]; + _lastTickCount = new WebRtc_Word64[cpuCount]; + _lastTime = TickTime::MillisecondTimestamp(); + + processor_cpu_load_info_data_t* cpuLoadInfo = + (processor_cpu_load_info_data_t*) infoArray; + for (unsigned int cpu= 0; cpu < cpuCount; cpu++) + { + WebRtc_Word64 ticks = 0; + for (int state = 0; state < 2; state++) + { + ticks += cpuLoadInfo[cpu].cpu_ticks[state]; + } + _lastTickCount[cpu] = ticks; + _cpuUsage[cpu] = 0; + } + vm_deallocate(mach_task_self(), (vm_address_t)infoArray, infoCount); +} + +CpuWrapperMac::~CpuWrapperMac() +{ + delete[] _cpuUsage; + delete[] _lastTickCount; +} + +WebRtc_Word32 CpuWrapperMac::CpuUsage() +{ + WebRtc_UWord32 numCores; + WebRtc_UWord32* array = NULL; + return CpuUsageMultiCore(numCores, array); +} + +WebRtc_Word32 +CpuWrapperMac::CpuUsageMultiCore(WebRtc_UWord32& numCores, + WebRtc_UWord32*& array) +{ + // sanity check + if(_cpuUsage == NULL) + { + return -1; + } + + WebRtc_Word64 now = TickTime::MillisecondTimestamp(); + WebRtc_Word64 timeDiffMS = now - _lastTime; + if(timeDiffMS >= 500) + { + if(Update(timeDiffMS) != 0) + { + return -1; + } + _lastTime = now; + } + + numCores = _cpuCount; + array = _cpuUsage; + return _totalCpuUsage / _cpuCount; +} + +WebRtc_Word32 CpuWrapperMac::Update(WebRtc_Word64 timeDiffMS) +{ + natural_t cpuCount; + processor_info_array_t infoArray; + mach_msg_type_number_t infoCount; + + kern_return_t error = host_processor_info(mach_host_self(), + PROCESSOR_CPU_LOAD_INFO, + &cpuCount, + &infoArray, + &infoCount); + if (error) + { + return -1; + } + + processor_cpu_load_info_data_t* cpuLoadInfo = + (processor_cpu_load_info_data_t*) infoArray; + + _totalCpuUsage = 0; + for (unsigned int cpu = 0; cpu < cpuCount; cpu++) + { + WebRtc_Word64 ticks = 0; + for (int state = 0; state < 2; state++) + { + ticks += cpuLoadInfo[cpu].cpu_ticks[state]; + } + if(timeDiffMS <= 0) + { + _cpuUsage[cpu] = 0; + }else { + _cpuUsage[cpu] = (WebRtc_UWord32)((1000 * + (ticks - _lastTickCount[cpu])) / + timeDiffMS); + } + _lastTickCount[cpu] = ticks; + _totalCpuUsage += _cpuUsage[cpu]; + } + + vm_deallocate(mach_task_self(), (vm_address_t)infoArray, infoCount); + + return 0; +} +} // namespace webrtc diff --git a/libs/miniwebrtc/system_wrappers/cpu_mac.h b/libs/miniwebrtc/system_wrappers/cpu_mac.h new file mode 100644 index 00000000..f9f82072 --- /dev/null +++ b/libs/miniwebrtc/system_wrappers/cpu_mac.h @@ -0,0 +1,48 @@ +/* + * 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_MAC_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_MAC_H_ + +#include "cpu_wrapper.h" + +namespace webrtc { +class CpuWrapperMac : public CpuWrapper +{ +public: + CpuWrapperMac(); + virtual ~CpuWrapperMac(); + + 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;} + + // Note: this class will block the call and sleep if called too fast + // This function blocks the calling thread if the thread is calling it more + // often than every 500 ms. + virtual WebRtc_Word32 CpuUsageMultiCore(WebRtc_UWord32& numCores, + WebRtc_UWord32*& array); + + virtual void Reset() {} + virtual void Stop() {} + +private: + WebRtc_Word32 Update(WebRtc_Word64 timeDiffMS); + + WebRtc_UWord32 _cpuCount; + WebRtc_UWord32* _cpuUsage; + WebRtc_Word32 _totalCpuUsage; + WebRtc_Word64* _lastTickCount; + WebRtc_Word64 _lastTime; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CPU_MAC_H_ diff --git a/libs/miniwebrtc/system_wrappers/cpu_measurement_harness.cc b/libs/miniwebrtc/system_wrappers/cpu_measurement_harness.cc new file mode 100644 index 00000000..237e7765 --- /dev/null +++ b/libs/miniwebrtc/system_wrappers/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/libs/miniwebrtc/system_wrappers/cpu_measurement_harness.h b/libs/miniwebrtc/system_wrappers/cpu_measurement_harness.h new file mode 100644 index 00000000..3b87f277 --- /dev/null +++ b/libs/miniwebrtc/system_wrappers/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 cpu_; + scoped_ptr event_; +}; + +} // namespace webrtc + +#endif // SRC_SYSTEM_WRAPPERS_SOURCE_CPU_MEASUREMENT_HARNESS_H_ diff --git a/libs/miniwebrtc/system_wrappers/cpu_no_op.cc b/libs/miniwebrtc/system_wrappers/cpu_no_op.cc new file mode 100644 index 00000000..e42ef918 --- /dev/null +++ b/libs/miniwebrtc/system_wrappers/cpu_no_op.cc @@ -0,0 +1,22 @@ +/* + * 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 + +#include "cpu_wrapper.h" + +namespace webrtc { + +CpuWrapper* CpuWrapper::CreateCpu() +{ + return NULL; +} + +} // namespace webrtc diff --git a/libs/miniwebrtc/system_wrappers/cpu_win.cc b/libs/miniwebrtc/system_wrappers/cpu_win.cc new file mode 100644 index 00000000..57920230 --- /dev/null +++ b/libs/miniwebrtc/system_wrappers/cpu_win.cc @@ -0,0 +1,534 @@ +/* + * 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 +#include +#include + +#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(). + const bool success = StopPollingCpu(); + assert(success); + DeAllocateComplexDataTypes(); +} + +bool CpuWindows::AllocateComplexDataTypes() +{ + cpu_polling_thread = ThreadWrapper::CreateThread( + CpuWindows::Process, + reinterpret_cast(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(thread_object)->ProcessImpl(); +} + +bool CpuWindows::ProcessImpl() +{ + { + CriticalSectionScoped cs(terminate_crit_); + if (terminate_) + { + const bool success = Terminate(); + assert(success); + 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 but make sure it doesnt trigger in + // debug. + const bool success = UpdateCpuUsage(); + assert(success); + return true; +} + +bool CpuWindows::CreateWmiConnection() +{ + IWbemLocator* service_locator = NULL; + HRESULT hr = CoCreateInstance(CLSID_WbemLocator, NULL, + CLSCTX_INPROC_SERVER, IID_IWbemLocator, + reinterpret_cast (&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 (&wbem_refresher_)); + if (FAILED(hr)) + { + return false; + } + // Create PerfOS_Processor enum. + IWbemConfigureRefresher* wbem_refresher_config = NULL; + hr = wbem_refresher_->QueryInterface( + IID_IWbemConfigureRefresher, + reinterpret_cast (&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 (wbem_service_), + reinterpret_cast (&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 (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(processor_timestamp_delta) / + static_cast(timestamp_100ns_delta); + cpu_usage_[i] = 100 - static_cast(delta_quotient * + 100); + } + previous_processor_timestamp_[i] = cpu_usage; + previous_100ns_timestamp_[i] = timestamp_100ns; + } + return returnValue; +} +} // namespace webrtc diff --git a/libs/miniwebrtc/system_wrappers/cpu_win.h b/libs/miniwebrtc/system_wrappers/cpu_win.h new file mode 100644 index 00000000..d15073c0 --- /dev/null +++ b/libs/miniwebrtc/system_wrappers/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 + +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/libs/miniwebrtc/system_wrappers/critical_section.cc b/libs/miniwebrtc/system_wrappers/critical_section.cc new file mode 100644 index 00000000..d3f3f016 --- /dev/null +++ b/libs/miniwebrtc/system_wrappers/critical_section.cc @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#if defined(_WIN32) + #include + #include "critical_section_win.h" +#else + #include "critical_section_posix.h" +#endif + +namespace webrtc { +CriticalSectionWrapper* CriticalSectionWrapper::CreateCriticalSection() +{ +#ifdef _WIN32 + return new CriticalSectionWindows(); +#else + return new CriticalSectionPosix(); +#endif +} +} // namespace webrtc diff --git a/libs/miniwebrtc/system_wrappers/critical_section_posix.cc b/libs/miniwebrtc/system_wrappers/critical_section_posix.cc new file mode 100644 index 00000000..70f85f9a --- /dev/null +++ b/libs/miniwebrtc/system_wrappers/critical_section_posix.cc @@ -0,0 +1,46 @@ +/* + * 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. + */ + +// 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; + (void) pthread_mutexattr_init(&attr); + (void) pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + (void) pthread_mutex_init(&_mutex, &attr); +} + +CriticalSectionPosix::~CriticalSectionPosix() +{ + (void) pthread_mutex_destroy(&_mutex); +} + +void +CriticalSectionPosix::Enter() +{ + (void) pthread_mutex_lock(&_mutex); +} + +void +CriticalSectionPosix::Leave() +{ + (void) pthread_mutex_unlock(&_mutex); +} + +} // namespace webrtc diff --git a/libs/miniwebrtc/system_wrappers/critical_section_posix.h b/libs/miniwebrtc/system_wrappers/critical_section_posix.h new file mode 100644 index 00000000..40b7dc92 --- /dev/null +++ b/libs/miniwebrtc/system_wrappers/critical_section_posix.h @@ -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. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_POSIX_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_POSIX_H_ + +#include "critical_section_wrapper.h" + +#include + +namespace webrtc { +class CriticalSectionPosix : public CriticalSectionWrapper +{ +public: + CriticalSectionPosix(); + + virtual ~CriticalSectionPosix(); + + virtual void Enter(); + virtual void Leave(); + +private: + pthread_mutex_t _mutex; + friend class ConditionVariablePosix; +}; +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_CRITICAL_SECTION_POSIX_H_ diff --git a/libs/miniwebrtc/system_wrappers/critical_section_win.cc b/libs/miniwebrtc/system_wrappers/critical_section_win.cc new file mode 100644 index 00000000..bbc66e5c --- /dev/null +++ b/libs/miniwebrtc/system_wrappers/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/libs/miniwebrtc/system_wrappers/critical_section_win.h b/libs/miniwebrtc/system_wrappers/critical_section_win.h new file mode 100644 index 00000000..9556fa95 --- /dev/null +++ b/libs/miniwebrtc/system_wrappers/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 + +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/libs/miniwebrtc/system_wrappers/critical_section_wrapper.h b/libs/miniwebrtc/system_wrappers/critical_section_wrapper.h new file mode 100644 index 00000000..cfec9ae7 --- /dev/null +++ b/libs/miniwebrtc/system_wrappers/critical_section_wrapper.h @@ -0,0 +1,74 @@ +/* + * 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_INTERFACE_CRITICAL_SECTION_WRAPPER_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CRITICAL_SECTION_WRAPPER_H_ + +// If the critical section is heavily contended it may be beneficial to use +// read/write locks instead. + +#include "common_types.h" + +namespace webrtc { +class CriticalSectionWrapper +{ +public: + // Factory method, constructor disabled + static CriticalSectionWrapper* CreateCriticalSection(); + + virtual ~CriticalSectionWrapper() {} + + // Tries to grab lock, beginning of a critical section. Will wait for the + // lock to become available if the grab failed. + virtual void Enter() = 0; + + // Returns a grabbed lock, end of critical section. + virtual void Leave() = 0; +}; + +// RAII extension of the critical section. Prevents Enter/Leave mismatches and +// provides more compact critical section syntax. +class CriticalSectionScoped +{ +public: + // Deprecated, don't add more users of this constructor. + // TODO(mflodman) Remove this version of the constructor when no one is + // using it any longer. + explicit CriticalSectionScoped(CriticalSectionWrapper& critsec) + : _ptrCritSec(&critsec) + { + _ptrCritSec->Enter(); + } + + explicit CriticalSectionScoped(CriticalSectionWrapper* critsec) + : _ptrCritSec(critsec) + { + _ptrCritSec->Enter(); + } + + ~CriticalSectionScoped() + { + if (_ptrCritSec) + { + Leave(); + } + } + +private: + void Leave() + { + _ptrCritSec->Leave(); + _ptrCritSec = 0; + } + + CriticalSectionWrapper* _ptrCritSec; +}; +} // namespace webrtc +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_CRITICAL_SECTION_WRAPPER_H_ diff --git a/libs/miniwebrtc/system_wrappers/file_impl.cc b/libs/miniwebrtc/system_wrappers/file_impl.cc new file mode 100644 index 00000000..4d06c547 --- /dev/null +++ b/libs/miniwebrtc/system_wrappers/file_impl.cc @@ -0,0 +1,265 @@ +/* + * 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 "file_impl.h" + +#include + +#ifdef _WIN32 +#include +#else +#include +#include +#endif + +namespace webrtc { + +FileWrapper* FileWrapper::Create() +{ + return new FileWrapperImpl(); +} + +FileWrapperImpl::FileWrapperImpl() + : _id(NULL), + _open(false), + _looping(false), + _readOnly(false), + _maxSizeInBytes(0), + _sizeInBytes(0) +{ + memset(_fileNameUTF8, 0, kMaxFileNameSize); +} + +FileWrapperImpl::~FileWrapperImpl() +{ + if (_id != NULL) + { + fclose(_id); + } +} + +int FileWrapperImpl::CloseFile() +{ + if (_id != NULL) + { + fclose(_id); + _id = NULL; + } + memset(_fileNameUTF8, 0, kMaxFileNameSize); + _open = false; + return 0; +} + +int FileWrapperImpl::Rewind() +{ + if(_looping || !_readOnly) + { + if (_id != NULL) + { + _sizeInBytes = 0; + return fseek(_id, 0, SEEK_SET); + } + } + return -1; +} + +int FileWrapperImpl::SetMaxFileSize(size_t bytes) +{ + _maxSizeInBytes = bytes; + return 0; +} + +int FileWrapperImpl::Flush() +{ + if (_id != NULL) + { + return fflush(_id); + } + return -1; +} + +int FileWrapperImpl::FileName(char* fileNameUTF8, + size_t size) const +{ + size_t length = strlen(_fileNameUTF8); + if(length > kMaxFileNameSize) + { + assert(false); + return -1; + } + if(length < 1) + { + return -1; + } + + // Make sure to NULL terminate + if(size < length) + { + length = size - 1; + } + memcpy(fileNameUTF8, _fileNameUTF8, length); + fileNameUTF8[length] = 0; + return 0; +} + +bool FileWrapperImpl::Open() const +{ + return _open; +} + +int FileWrapperImpl::OpenFile(const char *fileNameUTF8, bool readOnly, + bool loop, bool text) +{ + size_t length = strlen(fileNameUTF8); + if (length > kMaxFileNameSize - 1) + { + return -1; + } + + _readOnly = readOnly; + + FILE *tmpId = NULL; +#if defined _WIN32 + wchar_t wideFileName[kMaxFileNameSize]; + wideFileName[0] = 0; + + MultiByteToWideChar(CP_UTF8, + 0 /*UTF8 flag*/, + fileNameUTF8, + -1 /*Null terminated string*/, + wideFileName, + kMaxFileNameSize); + if(text) + { + if(readOnly) + { + tmpId = _wfopen(wideFileName, L"rt"); + } else { + tmpId = _wfopen(wideFileName, L"wt"); + } + } else { + if(readOnly) + { + tmpId = _wfopen(wideFileName, L"rb"); + } else { + tmpId = _wfopen(wideFileName, L"wb"); + } + } +#else + if(text) + { + if(readOnly) + { + tmpId = fopen(fileNameUTF8, "rt"); + } else { + tmpId = fopen(fileNameUTF8, "wt"); + } + } else { + if(readOnly) + { + tmpId = fopen(fileNameUTF8, "rb"); + } else { + tmpId = fopen(fileNameUTF8, "wb"); + } + } +#endif + + if (tmpId != NULL) + { + // +1 comes from copying the NULL termination character. + memcpy(_fileNameUTF8, fileNameUTF8, length + 1); + if (_id != NULL) + { + fclose(_id); + } + _id = tmpId; + _looping = loop; + _open = true; + return 0; + } + return -1; +} + +int FileWrapperImpl::Read(void* buf, int length) +{ + if (length < 0) + return -1; + + if (_id == NULL) + return -1; + + int bytes_read = static_cast(fread(buf, 1, length, _id)); + if (bytes_read != length && !_looping) + { + CloseFile(); + } + return bytes_read; +} + +int FileWrapperImpl::WriteText(const char* format, ...) +{ + if (format == NULL) + return -1; + + if (_readOnly) + return -1; + + if (_id == NULL) + return -1; + + va_list args; + va_start(args, format); + int num_chars = vfprintf(_id, format, args); + va_end(args); + + if (num_chars >= 0) + { + return num_chars; + } + else + { + CloseFile(); + return -1; + } +} + +bool FileWrapperImpl::Write(const void* buf, int length) +{ + if (buf == NULL) + return false; + + if (length < 0) + return false; + + if (_readOnly) + return false; + + if (_id == NULL) + return false; + + // Check if it's time to stop writing. + if (_maxSizeInBytes > 0 && (_sizeInBytes + length) > _maxSizeInBytes) + { + Flush(); + return false; + } + + size_t num_bytes = fwrite(buf, 1, length, _id); + if (num_bytes > 0) + { + _sizeInBytes += num_bytes; + return true; + } + + CloseFile(); + return false; +} + +} // namespace webrtc diff --git a/libs/miniwebrtc/system_wrappers/file_impl.h b/libs/miniwebrtc/system_wrappers/file_impl.h new file mode 100644 index 00000000..31ab31e5 --- /dev/null +++ b/libs/miniwebrtc/system_wrappers/file_impl.h @@ -0,0 +1,57 @@ +/* + * 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_FILE_IMPL_H_ +#define WEBRTC_SYSTEM_WRAPPERS_SOURCE_FILE_IMPL_H_ + +#include "file_wrapper.h" + +#include + +namespace webrtc { + +class FileWrapperImpl : public FileWrapper +{ +public: + FileWrapperImpl(); + virtual ~FileWrapperImpl(); + + virtual int FileName(char* fileNameUTF8, + size_t size) const; + + virtual bool Open() const; + + virtual int OpenFile(const char* fileNameUTF8, + bool readOnly, + bool loop = false, + bool text = false); + + virtual int CloseFile(); + virtual int SetMaxFileSize(size_t bytes); + virtual int Flush(); + + virtual int Read(void* buf, int length); + virtual bool Write(const void *buf, int length); + virtual int WriteText(const char* format, ...); + virtual int Rewind(); + +private: + FILE* _id; + bool _open; + bool _looping; + bool _readOnly; + size_t _maxSizeInBytes; // -1 indicates file size limitation is off + size_t _sizeInBytes; + char _fileNameUTF8[kMaxFileNameSize]; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_SOURCE_FILE_IMPL_H_ diff --git a/libs/miniwebrtc/system_wrappers/file_wrapper.h b/libs/miniwebrtc/system_wrappers/file_wrapper.h new file mode 100644 index 00000000..4d174383 --- /dev/null +++ b/libs/miniwebrtc/system_wrappers/file_wrapper.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_FILE_WRAPPER_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_FILE_WRAPPER_H_ + +#include + +#include "common_types.h" +#include "typedefs.h" + +// Implementation of an InStream and OutStream that can read (exclusive) or +// write from/to a file. + +namespace webrtc { + +class FileWrapper : public InStream, public OutStream +{ +public: + static const size_t kMaxFileNameSize = 1024; + + // Factory method. Constructor disabled. + static FileWrapper* Create(); + + // Returns true if a file has been opened. + virtual bool Open() const = 0; + + // Opens a file in read or write mode, decided by the readOnly parameter. + virtual int OpenFile(const char* fileNameUTF8, + bool readOnly, + bool loop = false, + bool text = false) = 0; + + virtual int CloseFile() = 0; + + // Limits the file size to |bytes|. Writing will fail after the cap + // is hit. Pass zero to use an unlimited size. + virtual int SetMaxFileSize(size_t bytes) = 0; + + // Flush any pending writes. + virtual int Flush() = 0; + + // Returns the opened file's name in |fileNameUTF8|. Provide the size of + // the buffer in bytes in |size|. The name will be truncated if |size| is + // too small. + virtual int FileName(char* fileNameUTF8, + size_t size) const = 0; + + // Write |format| to the opened file. Arguments are taken in the same manner + // as printf. That is, supply a format string containing text and + // specifiers. Returns the number of characters written or -1 on error. + virtual int WriteText(const char* format, ...) = 0; + + // Inherited from Instream. + // Reads |length| bytes from file to |buf|. Returns the number of bytes read + // or -1 on error. + virtual int Read(void* buf, int length) = 0; + + // Inherited from OutStream. + // Writes |length| bytes from |buf| to file. The actual writing may happen + // some time later. Call Flush() to force a write. + virtual bool Write(const void *buf, int length) = 0; + + // Inherited from both Instream and OutStream. + // Rewinds the file to the start. Only available when OpenFile() has been + // called with |loop| == true or |readOnly| == true. + virtual int Rewind() = 0; +}; + +} // namespace webrtc + +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_FILE_WRAPPER_H_ diff --git a/libs/miniwebrtc/system_wrappers/scoped_ptr.h b/libs/miniwebrtc/system_wrappers/scoped_ptr.h new file mode 100644 index 00000000..74b6ad36 --- /dev/null +++ b/libs/miniwebrtc/system_wrappers/scoped_ptr.h @@ -0,0 +1,258 @@ +// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999. +// Copyright (c) 2001, 2002 Peter Dimov +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +// See http://www.boost.org/libs/smart_ptr/scoped_ptr.htm for documentation. +// + +// scoped_ptr mimics a built-in pointer except that it guarantees deletion +// of the object pointed to, either on destruction of the scoped_ptr or via +// an explicit reset(). scoped_ptr is a simple solution for simple needs; +// use shared_ptr or std::auto_ptr if your needs are more complex. + +// scoped_ptr_malloc added in by Google. When one of +// these goes out of scope, instead of doing a delete or delete[], it +// calls free(). scoped_ptr_malloc is likely to see much more +// use than any other specializations. + +// release() added in by Google. Use this to conditionally +// transfer ownership of a heap-allocated object to the caller, usually on +// method success. +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SCOPED_PTR_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SCOPED_PTR_H_ + +#include // for assert +#include // for free() decl + +#include // for std::ptrdiff_t + +#ifdef _WIN32 +namespace std { using ::ptrdiff_t; }; +#endif // _WIN32 + +namespace webrtc { + +template +class scoped_ptr { + private: + + T* ptr; + + scoped_ptr(scoped_ptr const &); + scoped_ptr & operator=(scoped_ptr const &); + + public: + + typedef T element_type; + + explicit scoped_ptr(T* p = NULL): ptr(p) {} + + ~scoped_ptr() { + typedef char type_must_be_complete[sizeof(T)]; + delete ptr; + } + + void reset(T* p = NULL) { + typedef char type_must_be_complete[sizeof(T)]; + + if (ptr != p) { + T* obj = ptr; + ptr = p; + // Delete last, in case obj destructor indirectly results in ~scoped_ptr + delete obj; + } + } + + T& operator*() const { + assert(ptr != NULL); + return *ptr; + } + + T* operator->() const { + assert(ptr != NULL); + return ptr; + } + + T* get() const { + return ptr; + } + + void swap(scoped_ptr & b) { + T* tmp = b.ptr; + b.ptr = ptr; + ptr = tmp; + } + + T* release() { + T* tmp = ptr; + ptr = NULL; + return tmp; + } + + T** accept() { + if (ptr) { + delete ptr; + ptr = NULL; + } + return &ptr; + } + + T** use() { + return &ptr; + } +}; + +template inline +void swap(scoped_ptr& a, scoped_ptr& b) { + a.swap(b); +} + + + + +// scoped_array extends scoped_ptr to arrays. Deletion of the array pointed to +// is guaranteed, either on destruction of the scoped_array or via an explicit +// reset(). Use shared_array or std::vector if your needs are more complex. + +template +class scoped_array { + private: + + T* ptr; + + scoped_array(scoped_array const &); + scoped_array & operator=(scoped_array const &); + + public: + + typedef T element_type; + + explicit scoped_array(T* p = NULL) : ptr(p) {} + + ~scoped_array() { + typedef char type_must_be_complete[sizeof(T)]; + delete[] ptr; + } + + void reset(T* p = NULL) { + typedef char type_must_be_complete[sizeof(T)]; + + if (ptr != p) { + T* arr = ptr; + ptr = p; + // Delete last, in case arr destructor indirectly results in ~scoped_array + delete [] arr; + } + } + + T& operator[](std::ptrdiff_t i) const { + assert(ptr != NULL); + assert(i >= 0); + return ptr[i]; + } + + T* get() const { + return ptr; + } + + void swap(scoped_array & b) { + T* tmp = b.ptr; + b.ptr = ptr; + ptr = tmp; + } + + T* release() { + T* tmp = ptr; + ptr = NULL; + return tmp; + } + + T** accept() { + if (ptr) { + delete [] ptr; + ptr = NULL; + } + return &ptr; + } +}; + +template inline +void swap(scoped_array& a, scoped_array& b) { + a.swap(b); +} + +// scoped_ptr_malloc<> is similar to scoped_ptr<>, but it accepts a +// second template argument, the function used to free the object. + +template class scoped_ptr_malloc { + private: + + T* ptr; + + scoped_ptr_malloc(scoped_ptr_malloc const &); + scoped_ptr_malloc & operator=(scoped_ptr_malloc const &); + + public: + + typedef T element_type; + + explicit scoped_ptr_malloc(T* p = 0): ptr(p) {} + + ~scoped_ptr_malloc() { + FF(static_cast(ptr)); + } + + void reset(T* p = 0) { + if (ptr != p) { + FF(static_cast(ptr)); + ptr = p; + } + } + + T& operator*() const { + assert(ptr != 0); + return *ptr; + } + + T* operator->() const { + assert(ptr != 0); + return ptr; + } + + T* get() const { + return ptr; + } + + void swap(scoped_ptr_malloc & b) { + T* tmp = b.ptr; + b.ptr = ptr; + ptr = tmp; + } + + T* release() { + T* tmp = ptr; + ptr = 0; + return tmp; + } + + T** accept() { + if (ptr) { + FF(static_cast(ptr)); + ptr = 0; + } + return &ptr; + } +}; + +template inline +void swap(scoped_ptr_malloc& a, scoped_ptr_malloc& b) { + a.swap(b); +} + +} // namespace webrtc + +#endif // #ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_SCOPED_PTR_H_ diff --git a/libs/miniwebrtc/typedefs.h b/libs/miniwebrtc/typedefs.h new file mode 100644 index 00000000..ba873096 --- /dev/null +++ b/libs/miniwebrtc/typedefs.h @@ -0,0 +1,142 @@ +/* + * 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 contains platform-specific typedefs and defines. + +#ifndef WEBRTC_TYPEDEFS_H_ +#define WEBRTC_TYPEDEFS_H_ + +// Reserved words definitions +// TODO(andrew): Look at removing these. +#define WEBRTC_EXTERN extern +#define G_CONST const +#define WEBRTC_INLINE extern __inline + +// Define WebRTC preprocessor identifiers based on the current build platform. +// TODO(andrew): Clean these up. We can probably remove everything in this +// block. +// - TARGET_MAC_INTEL and TARGET_MAC aren't used anywhere. +// - In the few places where TARGET_PC is used, it should be replaced by +// something more specific. +// - Do we really support PowerPC? Probably not. Remove WEBRTC_MAC_INTEL +// from build/common.gypi as well. +#if defined(WIN32) + // Windows & Windows Mobile. + #if !defined(WEBRTC_TARGET_PC) + #define WEBRTC_TARGET_PC + #endif +#elif defined(__APPLE__) + // Mac OS X. + #if defined(__LITTLE_ENDIAN__ ) + #if !defined(WEBRTC_TARGET_MAC_INTEL) + #define WEBRTC_TARGET_MAC_INTEL + #endif + #else + #if !defined(WEBRTC_TARGET_MAC) + #define WEBRTC_TARGET_MAC + #endif + #endif +#else + // Linux etc. + #if !defined(WEBRTC_TARGET_PC) + #define WEBRTC_TARGET_PC + #endif +#endif + +// Derived from Chromium's build/build_config.h +// Processor architecture detection. For more info on what's defined, see: +// http://msdn.microsoft.com/en-us/library/b0084kay.aspx +// http://www.agner.org/optimize/calling_conventions.pdf +// or with gcc, run: "echo | gcc -E -dM -" +// TODO(andrew): replace WEBRTC_LITTLE_ENDIAN with WEBRTC_ARCH_LITTLE_ENDIAN? +#if defined(_M_X64) || defined(__x86_64__) +#define WEBRTC_ARCH_X86_FAMILY +#define WEBRTC_ARCH_X86_64 +#define WEBRTC_ARCH_64_BITS +#define WEBRTC_ARCH_LITTLE_ENDIAN +#elif defined(_M_IX86) || defined(__i386__) +#define WEBRTC_ARCH_X86_FAMILY +#define WEBRTC_ARCH_X86 +#define WEBRTC_ARCH_32_BITS +#define WEBRTC_ARCH_LITTLE_ENDIAN +#elif defined(__ARMEL__) +// TODO(andrew): We'd prefer to control platform defines here, but this is +// currently provided by the Android makefiles. Commented to avoid duplicate +// definition warnings. +//#define WEBRTC_ARCH_ARM +// TODO(andrew): Chromium uses the following two defines. Should we switch? +//#define WEBRTC_ARCH_ARM_FAMILY +//#define WEBRTC_ARCH_ARMEL +#define WEBRTC_ARCH_32_BITS +#define WEBRTC_ARCH_LITTLE_ENDIAN +#else +#error Please add support for your architecture in typedefs.h +#endif + +#if defined(__SSE2__) || defined(_MSC_VER) +#define WEBRTC_USE_SSE2 +#endif + +#if defined(WEBRTC_TARGET_PC) + +#if !defined(_MSC_VER) + #include +#else + // Define C99 equivalent types. + // Since MSVC doesn't include these headers, we have to write our own + // version to provide a compatibility layer between MSVC and the WebRTC + // headers. + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef signed long long int64_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; + typedef unsigned long long uint64_t; +#endif + +#if defined(WIN32) + typedef __int64 WebRtc_Word64; + typedef unsigned __int64 WebRtc_UWord64; +#else + typedef int64_t WebRtc_Word64; + typedef uint64_t WebRtc_UWord64; +#endif + typedef int32_t WebRtc_Word32; + typedef uint32_t WebRtc_UWord32; + typedef int16_t WebRtc_Word16; + typedef uint16_t WebRtc_UWord16; + typedef char WebRtc_Word8; + typedef uint8_t WebRtc_UWord8; + + // Define endian for the platform + #define WEBRTC_LITTLE_ENDIAN + +#elif defined(WEBRTC_TARGET_MAC_INTEL) + #include + + typedef int64_t WebRtc_Word64; + typedef uint64_t WebRtc_UWord64; + typedef int32_t WebRtc_Word32; + typedef uint32_t WebRtc_UWord32; + typedef int16_t WebRtc_Word16; + typedef char WebRtc_Word8; + typedef uint16_t WebRtc_UWord16; + typedef uint8_t WebRtc_UWord8; + + // Define endian for the platform + #define WEBRTC_LITTLE_ENDIAN + +#else + #error "No platform defined for WebRTC type definitions (typedefs.h)" +#endif + +#endif // WEBRTC_TYPEDEFS_H_ diff --git a/modules/Makefile.in b/modules/Makefile.in index f926ef9a..d3b43411 100644 --- a/modules/Makefile.in +++ b/modules/Makefile.in @@ -149,6 +149,10 @@ ifneq (@HAVE_ILBC@,no) PROGS := $(PROGS) ilbccodec.yate endif +ifneq (@HAVE_ISAC@,no) +PROGS := $(PROGS) isaccodec.yate +endif + ifneq (@HAVE_SPEEX@,no) PROGS := $(PROGS) speexcodec.yate endif @@ -336,6 +340,10 @@ ilbccodec.yate: ../libs/ilbc/libilbc.a ilbccodec.yate: LOCALFLAGS = @ILBC_INC@ ilbccodec.yate: LOCALLIBS = -L../libs/ilbc -lilbc +isaccodec.yate: ../libs/miniwebrtc/libminiwebrtc.a +isaccodec.yate: LOCALFLAGS = @ISAC_INC@ -I@top_srcdir@/libs/miniwebrtc/audio/common/processing -I@top_srcdir@/libs/miniwebrtc +isaccodec.yate: LOCALLIBS = -L../libs/miniwebrtc -lminiwebrtc + gsmcodec.yate: LOCALFLAGS = @GSM_INC@ gsmcodec.yate: LOCALLIBS = @GSM_LIB@ @@ -386,6 +394,9 @@ server/ysnmpagent.yate: LOCALLIBS = -L../libs/yasn -lyasn -L../libs/ysnmp -lysnm ../libs/ilbc/libilbc.a: $(MAKE) -C ../libs/ilbc +../libs/miniwebrtc/libminiwebrtc.a: + $(MAKE) -C ../libs/miniwebrtc + ../libs/ysip/libyatesip.a: @top_srcdir@/libs/ysip/yatesip.h $(MAKE) -C ../libs/ysip diff --git a/modules/isaccodec.cpp b/modules/isaccodec.cpp new file mode 100644 index 00000000..c7f80f25 --- /dev/null +++ b/modules/isaccodec.cpp @@ -0,0 +1,580 @@ +/** + * isaccodec.cpp + * This file is part of the YATE Project http://YATE.null.ro + * + * iSAC codec using iSAC library based on WebRTC project. + * + * Yet Another Telephony Engine - a fully featured software PBX and IVR + * Copyright (C) 2011 Null Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + * + * + * Copyright (c) 2011, The WebRTC project authors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Google nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +extern "C" { +#include "signal_processing_library.h" +#ifdef ISAC_FIXED +#include "isacfix.h" +#else +#include "isac.h" +#endif +} + +// ISAC frame size (in milliseconds) to set in encoder and format info +// 0: use default (don't set), 30/60ms otherwise +#define ISAC_FRAME_SIZE_MS 30 + +// Coding mode: +// 0: Channel-adaptive: the bit rate is adjusted by the encoder +// 1: Channel-independent: fixed bit rate +#define ISAC_CODING_ADAPTIVE 0 +#define ISAC_CODING_INDEPENDENT 1 + +#ifndef ISAC_CODING_MODE +#define ISAC_CODING_MODE ISAC_CODING_INDEPENDENT +//#define ISAC_CODING_MODE ISAC_CODING_ADAPTIVE +#endif + +// Channel independent: REQUIRED: set it to 32000 (default library value) +// Channel adaptive: set it to 0 to use default +#define ISAC_RATE 32000 + +using namespace TelEngine; +namespace { // anonymous + +class iSACCodec : public DataTranslator +{ +public: + iSACCodec(const char* sFormat, const char* dFormat, bool encoding); + ~iSACCodec(); + inline bool valid() const + { return m_isac != 0; } + virtual unsigned long Consume(const DataBlock& data, unsigned long tStamp, + unsigned long flags); + void timerTick(); +private: + // Retrieve the ISAC error + inline WebRtc_Word16 isacGetError() const + { +#ifdef ISAC_FIXED + return WebRtcIsacfix_GetErrorCode(m_isac); +#else + return WebRtcIsac_GetErrorCode(m_isac); +#endif + } + // Check error after encode/decode + // Forward data if result is greater then 0 and return the number of bytes forwarded + // Update last error. Output a debug message if error changed + unsigned long processCodecResult(WebRtc_Word16 result, unsigned int inBytes, + unsigned long tStamp, unsigned long flags); + // Initialize the codec structure. Return false on failure + bool isacInit(); + // Release the ISAC structure + void isacFree(); + + bool m_encoding; // Encoder/decoder flag +#ifdef ISAC_FIXED + ISACFIX_MainStruct* m_isac; // ISAC library structure +#else + ISACStruct* m_isac; +#endif + WebRtc_Word16 m_error; // Last error + DataBlock m_outData; // Codec output + WebRtc_Word16 m_mode; // Encoder mode (chan adaptive/instantaneous) + unsigned int m_encodeChunk; // Encoder input data length in bytes + unsigned long m_tStamp; // Encoder timestamp + DataBlock m_buffer; // Encoder buffer for incomplete data + // Statistics + unsigned long m_inPackets; + unsigned long m_outPackets; + unsigned long m_inBytes; + unsigned long m_outBytes; + unsigned long m_failedBytes; +}; + +class iSACFactory : public TranslatorFactory +{ +public: + iSACFactory(); + virtual const TranslatorCaps* getCapabilities() const + { return m_caps; } + virtual DataTranslator* create(const DataFormat& sFormat, const DataFormat& dFormat); +private: + const TranslatorCaps* m_caps; +}; + +class iSACModule : public Module +{ +public: + iSACModule(); + ~iSACModule(); + inline void incCount() { + Lock mylock(this); + m_count++; + } + inline void decCount() { + Lock mylock(this); + m_count--; + } + virtual void initialize(); + virtual bool isBusy() const + { return (m_count != 0); } +protected: + virtual void statusParams(String& str); +private: + int m_count; // Current number of codecs + iSACFactory* m_factory; // Factory used to create codecs +}; + + +INIT_PLUGIN(iSACModule); + +static TranslatorCaps s_caps[] = { + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 } +}; + +UNLOAD_PLUGIN(unloadNow) +{ + if (unloadNow) + return !__plugin.isBusy(); + return true; +} + + +/* + * iSACFactory + */ +iSACCodec::iSACCodec(const char* sFormat, const char* dFormat, bool encoding) + : DataTranslator(sFormat,dFormat), m_encoding(encoding), + m_isac(0), m_error(0), m_mode(ISAC_CODING_MODE), m_encodeChunk(0), m_tStamp(0), + m_inPackets(0), m_outPackets(0), m_inBytes(0), m_outBytes(0), m_failedBytes(0) +{ + Debug(&__plugin,DebugAll,"iSACCodec(\"%s\",\"%s\",%scoding) [%p]", + sFormat,dFormat,m_encoding ? "en" : "de",this); + __plugin.incCount(); + isacInit(); +} + +iSACCodec::~iSACCodec() +{ + isacFree(); + Debug(&__plugin,DebugAll, + "iSACCodec(%scoding) destroyed packets in/out=%lu/%lu bytes in/out/failed=%lu/%lu/%lu [%p]", + m_encoding ? "en" : "de",m_inPackets,m_outPackets,m_inBytes,m_outBytes,m_failedBytes,this); + __plugin.decCount(); +} + +unsigned long iSACCodec::Consume(const DataBlock& data, unsigned long tStamp, + unsigned long flags) +{ + XDebug(&__plugin,DebugAll,"%scoder::Consume(%u,%lu,%lu) buffer=%u [%p]", + m_encoding ? "En" : "De",data.length(),tStamp,flags,m_buffer.length(),this); + m_inBytes += data.length(); + m_inPackets++; + if (!(valid() && getTransSource())) { + m_failedBytes += data.length(); + return 0; + } + if (data.null() && (flags & DataSilent)) + return getTransSource()->Forward(data,tStamp,flags); + ref(); + WebRtc_Word16 res = 0; + WebRtc_Word16* out = (WebRtc_Word16*)m_outData.data(); + unsigned long len = 0; + if (m_encoding) { + // NOTE: draft-ietf-avt-rtp-isac-00.txt section 3.4: + // More than one iSAC payload block MUST NOT be included in an RTP packet by a sender + // Forward data when encoded, don't accumulate the encoder output + + // Avoid copying data if our buffer is empty + const DataBlock* inDataBlock = &data; + if (m_buffer.length()) { + m_buffer += data; + inDataBlock = &m_buffer; + } + const unsigned char* ptr = (const unsigned char*)inDataBlock->data(); + unsigned int remaining = inDataBlock->length(); + while (remaining >= m_encodeChunk) { + // Encode returns the number of bytes set in output buffer +#ifdef ISAC_FIXED + res = WebRtcIsacfix_Encode(m_isac,(const WebRtc_Word16*)ptr,out); +#else + res = WebRtcIsac_Encode(m_isac,(const WebRtc_Word16*)ptr,out); +#endif + if (res > 0) { + if (m_tStamp) { + WebRtc_Word16 frameLengthSamples = 0; + WebRtc_Word16 r = 0; +#ifdef ISAC_FIXED + r = WebRtcIsacfix_ReadFrameLen(out,&frameLengthSamples); +#else + r = WebRtcIsac_ReadFrameLen(m_isac,out,&frameLengthSamples); +#endif + if (r == 0) + m_tStamp += frameLengthSamples; + } + else + m_tStamp = tStamp; + } + remaining -= m_encodeChunk; + ptr += m_encodeChunk; + unsigned long l = processCodecResult(res,m_encodeChunk,m_tStamp,flags); + if (!len) + len = l; + else if (len != invalidStamp() && l != invalidStamp()) + len += l; + } + if (!remaining) + m_buffer.clear(); + else + m_buffer.assign((void*)ptr,remaining); + } + else { +#ifndef NO_ISAC_PLC + if (flags & DataMissed) { + // guess how many frames were lost + int lost = (tStamp - timeStamp()) / 480; + if (lost <= 0) + lost = 1; + else if (lost > 2) + lost = 2; +#ifdef ISAC_FIXED + res = WebRtcIsacfix_DecodePlc(m_isac,out,lost); +#else + res = WebRtcIsac_DecodePlc(m_isac,out,lost); +#endif + DDebug(&__plugin,DebugNote,"Loss Concealment %d samples [%p]",res,this); + if (res > 0) { + flags &= ~DataMissed; + unsigned long ts = tStamp; + if (data.length()) + ts -= res; + processCodecResult(res*2,0,ts,flags); + } + } +#endif + if (data.length()) { + // NOTE: We must workaround the following issues in WebRtcIsacfix_Decode: + // - It doesn't honor the 'const' qualifier of the input buffer on + // little endian machines, it changes it! + // Copy data to out buffer to avoid altering source data for another data consumer + // - It makes read/write access past buffer end for odd buffer length + const DataBlock* inDataBlock = &data; + if (0 != (data.length() & 0x01)) { + m_buffer.assign(0,data.length() + 1); + ::memcpy(m_buffer.data(),data.data(),data.length()); + inDataBlock = &m_buffer; + } +#ifndef BIGENDIAN + else { + m_buffer = data; + inDataBlock = &m_buffer; + } +#endif + WebRtc_Word16 speechType = 0; +#ifdef ISAC_FIXED + res = WebRtcIsacfix_Decode(m_isac,(const WebRtc_UWord16*) + inDataBlock->data(),data.length(),out,&speechType); +#else + res = WebRtcIsac_Decode(m_isac,(const WebRtc_UWord16*) + inDataBlock->data(),data.length(),out,&speechType); +#endif + // Decode returns the number of decoded samples + if (res > 0) + res *= 2; + len = processCodecResult(res,data.length(),tStamp,flags); + } + } + deref(); + return len; +} + +// Check error after encode/decode +// Forward data if result is greater then 0 and return the number of bytes forwarded +// Update last error. Output a debug message if error changed +unsigned long iSACCodec::processCodecResult(WebRtc_Word16 result, unsigned int inBytes, + unsigned long tStamp, unsigned long flags) +{ + XDebug(&__plugin,DebugAll,"%scoded %u --> %d tStamp=%lu [%p]", + m_encoding ? "En" : "De",inBytes,result,tStamp,this); + if (result >= 0) { + m_error = 0; + if (!result) + return 0; + m_outPackets++; + m_outBytes += (unsigned long)result; + DataBlock tmp(m_outData.data(),result,false); + DDebug(&__plugin,DebugAll,"%scoder forwarding %u tStamp=%lu [%p]", + m_encoding ? "En" : "De",tmp.length(),tStamp,this); + unsigned long len = getTransSource()->Forward(tmp,tStamp,flags); + tmp.clear(false); + return len; + } + m_failedBytes += inBytes; + WebRtc_Word16 err = isacGetError(); + if (m_error != err) { + m_error = err; + Debug(&__plugin,DebugNote,"%scoder failed %u bytes error=%d [%p]", + m_encoding ? "En" : "De",inBytes,m_error,this); + } + return 0; +} + +// Initialize the ISAC structure. Return false on failure +bool iSACCodec::isacInit() +{ + if (m_isac) + return true; + // Create the isac structure + WebRtc_Word16 res = -1; + int sampleRate = getFormat().sampleRate(); +#ifdef ISAC_FIXED + res = WebRtcIsacfix_Create(&m_isac); +#else + res = WebRtcIsac_Create(&m_isac); +#endif + if (res) { + Debug(&__plugin,DebugWarn,"iSACCodec failed to allocate ISAC data [%p]",this); + m_isac = 0; + return false; + } + // Init the codec + if (m_encoding) { +#ifdef ISAC_FIXED + res = WebRtcIsacfix_EncoderInit(m_isac,m_mode); +#else + res = WebRtcIsac_EncoderInit(m_isac,m_mode); + WebRtcIsac_SetEncSampRate(m_isac,sampleRate == 16000 ? kIsacWideband : kIsacSuperWideband); +#endif + + if (sampleRate == 16000) { + m_outData.assign(0,400); + m_encodeChunk = 320; + } +#ifndef ISAC_FIXED + else if (sampleRate == 32000) { + m_outData.assign(0,800); + m_encodeChunk = 640; + } +#endif + else { + Debug(&__plugin,DebugWarn,"Bad iSAC sample Rate %d",sampleRate); + return false; + } + } + else { +#ifdef ISAC_FIXED + res = WebRtcIsacfix_DecoderInit(m_isac); +#else + res = WebRtcIsac_DecoderInit(m_isac); + WebRtcIsac_SetDecSampRate(m_isac,sampleRate == 16000 ? kIsacWideband : kIsacSuperWideband); +#endif + // Decode may return 480 or 960 samples + m_outData.assign(0,1920); + } + if (res == 0) { + if (m_encoding) { + // Set frame size if instructed + WebRtc_Word16 fs = ISAC_FRAME_SIZE_MS; + if (fs) { + WebRtc_Word16 err = 0; + // Isac fixed point implementation rate: + // Channel adaptive: 0 to use default + // Channel independent use default value (32000) + WebRtc_Word16 rateBps = sampleRate; + if (m_mode == ISAC_CODING_INDEPENDENT) { +#ifdef ISAC_FIXED + err = WebRtcIsacfix_Control(m_isac,rateBps,fs); +#else + err = WebRtcIsac_Control(m_isac,rateBps,fs); +#endif + } + else { + // Enforce frame size: 1: fix, 0: let the codec change it + WebRtc_Word16 efs = 1; +#ifdef ISAC_FIXED + err = WebRtcIsacfix_ControlBwe(m_isac,rateBps,fs,efs); +#else + err = WebRtcIsac_ControlBwe(m_isac,rateBps,fs,efs); +#endif + } + if (err == 0) + XDebug(&__plugin,DebugAll,"Encoder set framesize=%dms [%p]",fs,this); + else + Debug(&__plugin,DebugNote, + "Encoder failed to set framesize=%dms error=%d [%p]", + fs,isacGetError(),this); + } + } + DDebug(&__plugin,DebugAll,"iSACCodec initialized [%p]",this); + return true; + } + m_error = isacGetError(); + Debug(&__plugin,DebugWarn,"iSACCodec failed to initialize error=%d [%p]", + m_error,this); + isacFree(); + return false; +} + +// Release the ISAC structure +void iSACCodec::isacFree() +{ + if (!m_isac) + return; + XDebug(&__plugin,DebugAll,"iSACCodec releasing ISAC [%p]",this); +#ifdef ISAC_FIXED + WebRtcIsacfix_Free(m_isac); +#else + WebRtcIsac_Free(m_isac); +#endif + m_isac = 0; +} + + +/* + * iSACFactory + */ +iSACFactory::iSACFactory() + : TranslatorFactory("isac"), + m_caps(s_caps) +{ +} + +DataTranslator* iSACFactory::create(const DataFormat& sFormat, const DataFormat& dFormat) +{ + iSACCodec* codec = 0; + if (sFormat == YSTRING("slin/16000")) { + if (dFormat == YSTRING("isac/16000")) + codec = new iSACCodec(sFormat,dFormat,true); + } + else if (dFormat == YSTRING("slin/16000")) { + if (sFormat == YSTRING("isac/16000")) + codec = new iSACCodec(sFormat,dFormat,false); + } +#ifndef ISAC_FIXED + if (sFormat == YSTRING("slin/32000")) { + if (dFormat == YSTRING("isac/32000")) + codec = new iSACCodec(sFormat,dFormat,true); + } + else if (dFormat == YSTRING("slin/32000")) { + if (sFormat == YSTRING("isac/32000")) + codec = new iSACCodec(sFormat,dFormat,false); + } +#endif + if (codec && !codec->valid()) + TelEngine::destruct(codec); + return codec; +} + + +/* + * iSACModule + */ +iSACModule::iSACModule() + : Module("isaccodec","misc"), + m_count(0), m_factory(0) +{ + char ver[65] = {0}; + char splVer[65] = {0}; + const char* type = 0; + WebRtcSpl_get_version(splVer,64); +#ifdef ISAC_FIXED + WebRtcIsacfix_version(ver); + type = "fixed point"; +#else + WebRtcIsac_version(ver); + type = "floating point"; +#endif + Output("Loaded module iSAC %s - based on WebRTC iSAC library version %s (SPL version %s)", + type,ver,splVer); + const FormatInfo* f = FormatRepository::addFormat("isac/16000",0, + ISAC_FRAME_SIZE_MS * 1000,"audio",16000); + s_caps[0].src = s_caps[1].dest = f; + s_caps[0].dest = s_caps[1].src = FormatRepository::getFormat("slin/16000"); + // FIXME: put proper conversion costs + s_caps[0].cost = s_caps[1].cost = 10; +#ifndef ISAC_FIXED + const FormatInfo* f32 = FormatRepository::addFormat("isac/32000",0, + ISAC_FRAME_SIZE_MS * 1000,"audio",32000); + s_caps[2].src = s_caps[3].dest = f32; + s_caps[2].dest = s_caps[3].src = FormatRepository::getFormat("slin/32000"); + // FIXME: put proper conversion costs + s_caps[2].cost = s_caps[3].cost = 10; +#endif + m_factory = new iSACFactory; +} + +iSACModule::~iSACModule() +{ + Output("Unloading module iSAC with %d codecs still in use",m_count); + TelEngine::destruct(m_factory); +} + +void iSACModule::initialize() +{ + static bool s_first = true; + Output("Initializing module iSAC"); + if (s_first) { + installRelay(Level); + installRelay(Status); + installRelay(Command); + s_first = false; + } +} + +void iSACModule::statusParams(String& str) +{ + str << "codecs=" << m_count; +} + +}; // anonymous namespace + +/* vi: set ts=8 sw=4 sts=4 noet: */