From 547b6a570dbad844e79b4ba5eb934f043bab6318 Mon Sep 17 00:00:00 2001 From: Solomon Peachy Date: Wed, 8 May 2024 10:36:38 -0400 Subject: codecs: Update libspeex from 1.2beta3 to 1.2rc1 This is a relatively minor bump, but it's the first step towards bringing this current. Change-Id: Iab6c9b0c77f0ba705280434ea74b513364719499 --- lib/rbcodec/codecs/libspeex/COPYING | 15 +- lib/rbcodec/codecs/libspeex/README.rockbox | 6 +- lib/rbcodec/codecs/libspeex/arch.h | 2 +- lib/rbcodec/codecs/libspeex/bits.c | 51 +- lib/rbcodec/codecs/libspeex/config-speex.h | 20 +- lib/rbcodec/codecs/libspeex/fftwrap.c | 131 ++++- lib/rbcodec/codecs/libspeex/filters_arm4.h | 2 +- lib/rbcodec/codecs/libspeex/fixed_debug.h | 58 +- lib/rbcodec/codecs/libspeex/fixed_generic.h | 4 +- lib/rbcodec/codecs/libspeex/jitter.c | 192 +++---- lib/rbcodec/codecs/libspeex/mdf.c | 576 ++++++++++++-------- lib/rbcodec/codecs/libspeex/modes.c | 8 +- lib/rbcodec/codecs/libspeex/modes_wb.c | 10 +- lib/rbcodec/codecs/libspeex/preprocess.c | 202 ++++--- lib/rbcodec/codecs/libspeex/quant_lsp_bfin.h | 72 +-- lib/rbcodec/codecs/libspeex/resample.c | 735 +++++++++++++------------- lib/rbcodec/codecs/libspeex/resample_sse.h | 128 +++++ lib/rbcodec/codecs/libspeex/speex.c | 42 +- lib/rbcodec/codecs/libspeex/speex_callbacks.c | 28 +- lib/rbcodec/codecs/libspeex/speex_header.c | 55 +- lib/rbcodec/codecs/libspeex/stereo.c | 56 +- 21 files changed, 1399 insertions(+), 994 deletions(-) create mode 100644 lib/rbcodec/codecs/libspeex/resample_sse.h diff --git a/lib/rbcodec/codecs/libspeex/COPYING b/lib/rbcodec/codecs/libspeex/COPYING index 3b6b579cf3..de6fbe2c91 100644 --- a/lib/rbcodec/codecs/libspeex/COPYING +++ b/lib/rbcodec/codecs/libspeex/COPYING @@ -1,10 +1,11 @@ -Copyright 2002-2006 - Xiph.org Foundation - Jean-Marc Valin - David Rowe - EpicGames - Analog Devices - Commonwealth Scientific and Industrial Research Organisation (CSIRO) +Copyright 2002-2008 Xiph.org Foundation +Copyright 2002-2008 Jean-Marc Valin +Copyright 2005-2007 Analog Devices Inc. +Copyright 2005-2008 Commonwealth Scientific and Industrial Research + Organisation (CSIRO) +Copyright 1993, 2002, 2006 David Rowe +Copyright 2003 EpicGames +Copyright 1992-1994 Jutta Degener, Carsten Bormann Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions diff --git a/lib/rbcodec/codecs/libspeex/README.rockbox b/lib/rbcodec/codecs/libspeex/README.rockbox index 84fff59b60..be809dc40d 100644 --- a/lib/rbcodec/codecs/libspeex/README.rockbox +++ b/lib/rbcodec/codecs/libspeex/README.rockbox @@ -1,6 +1,6 @@ -Library: libspeex-1.2beta3 (SVN version 14054) -Imported: 2007-03-12 by Dan Everton - +Library: libspeex-1.2rc1 +Imported 1.2beta3: 2007-03-12 by Dan Everton +Updated 1.2rc1: 2024-05-08 by Solomon Peachy This directory contains a local version of libspeex for decoding Ogg/Speex audio streams. diff --git a/lib/rbcodec/codecs/libspeex/arch.h b/lib/rbcodec/codecs/libspeex/arch.h index 35b5363837..b0a9097f99 100644 --- a/lib/rbcodec/codecs/libspeex/arch.h +++ b/lib/rbcodec/codecs/libspeex/arch.h @@ -235,7 +235,7 @@ typedef float spx_word32_t; #ifdef FIXED_DEBUG -long long spx_mips=0; +extern long long spx_mips=0; #endif diff --git a/lib/rbcodec/codecs/libspeex/bits.c b/lib/rbcodec/codecs/libspeex/bits.c index c7a5c14ede..2580e700fe 100644 --- a/lib/rbcodec/codecs/libspeex/bits.c +++ b/lib/rbcodec/codecs/libspeex/bits.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2002 Jean-Marc Valin +/* Copyright (C) 2002 Jean-Marc Valin File: speex_bits.c Handles bit packing/unpacking @@ -6,18 +6,18 @@ 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 the Xiph.org Foundation 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 @@ -46,7 +46,7 @@ #endif #ifdef ROCKBOX_VOICE_ENCODER -void speex_bits_init(SpeexBits *bits) +EXPORT void speex_bits_init(SpeexBits *bits) { bits->chars = (char*)speex_alloc(MAX_CHARS_PER_FRAME); if (!bits->chars) @@ -62,7 +62,7 @@ void speex_bits_init(SpeexBits *bits) #if 0 /* Rockbox: unused */ -void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size) +EXPORT void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size) { bits->chars = (char*)buff; bits->buf_size = buf_size; @@ -73,7 +73,7 @@ void speex_bits_init_buffer(SpeexBits *bits, void *buff, int buf_size) } #endif -void speex_bits_set_bit_buffer(SpeexBits *bits, void *buff, int buf_size) +EXPORT void speex_bits_set_bit_buffer(SpeexBits *bits, void *buff, int buf_size) { bits->chars = (char*)buff; bits->buf_size = buf_size; @@ -84,11 +84,11 @@ void speex_bits_set_bit_buffer(SpeexBits *bits, void *buff, int buf_size) bits->charPtr=0; bits->bitPtr=0; bits->overflow=0; - + } #ifndef ROCKBOX_VOICE_CODEC -void speex_bits_destroy(SpeexBits *bits) +EXPORT void speex_bits_destroy(SpeexBits *bits) { if (bits->owner) speex_free(bits->chars); @@ -97,7 +97,7 @@ void speex_bits_destroy(SpeexBits *bits) #endif #ifdef ROCKBOX_VOICE_ENCODER -void speex_bits_reset(SpeexBits *bits) +EXPORT void speex_bits_reset(SpeexBits *bits) { /* We only need to clear the first byte now */ bits->chars[0]=0; @@ -110,7 +110,7 @@ void speex_bits_reset(SpeexBits *bits) #if 0 /* Rockbox: unused */ -void speex_bits_rewind(SpeexBits *bits) +EXPORT void speex_bits_rewind(SpeexBits *bits) { bits->charPtr=0; bits->bitPtr=0; @@ -119,7 +119,7 @@ void speex_bits_rewind(SpeexBits *bits) #endif #if !defined(SPEEX_VOICE_ENCODER) && !defined(ROCKBOX_VOICE_CODEC) -void speex_bits_read_from(SpeexBits *bits, char *chars, int len) +EXPORT void speex_bits_read_from(SpeexBits *bits, char *chars, int len) { int i; int nchars = len / BYTES_PER_CHAR; @@ -166,9 +166,10 @@ static void speex_bits_flush(SpeexBits *bits) bits->charPtr=0; } -void speex_bits_read_whole_bytes(SpeexBits *bits, char *chars, int nbytes) +EXPORT void speex_bits_read_whole_bytes(SpeexBits *bits, char *chars, int nbytes) { int i,pos; + int nchars = nbytes/BYTES_PER_CHAR; if (((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR)+nchars > bits->buf_size) @@ -200,7 +201,7 @@ void speex_bits_read_whole_bytes(SpeexBits *bits, char *chars, int nbytes) #endif #ifndef SPEEX_DISABLE_ENCODER -int speex_bits_write(SpeexBits *bits, char *chars, int max_nbytes) +EXPORT int speex_bits_write(SpeexBits *bits, char *chars, int max_nbytes) { int i; int max_nchars = max_nbytes/BYTES_PER_CHAR; @@ -223,7 +224,7 @@ int speex_bits_write(SpeexBits *bits, char *chars, int max_nbytes) return max_nchars*BYTES_PER_CHAR; } -int speex_bits_write_whole_bytes(SpeexBits *bits, char *chars, int max_nbytes) +EXPORT int speex_bits_write_whole_bytes(SpeexBits *bits, char *chars, int max_nbytes) { int max_nchars = max_nbytes/BYTES_PER_CHAR; int i; @@ -241,7 +242,7 @@ int speex_bits_write_whole_bytes(SpeexBits *bits, char *chars, int max_nbytes) return max_nchars*BYTES_PER_CHAR; } -void speex_bits_pack(SpeexBits *bits, int data, int nbBits) +EXPORT void speex_bits_pack(SpeexBits *bits, int data, int nbBits) { unsigned int d=data; @@ -287,7 +288,7 @@ void speex_bits_pack(SpeexBits *bits, int data, int nbBits) #if 0 /* Rockbox: unused */ -int speex_bits_unpack_signed(SpeexBits *bits, int nbBits) +EXPORT int speex_bits_unpack_signed(SpeexBits *bits, int nbBits) { unsigned int d=speex_bits_unpack_unsigned(bits,nbBits); /* If number is negative */ @@ -299,7 +300,7 @@ int speex_bits_unpack_signed(SpeexBits *bits, int nbBits) } #endif -unsigned int speex_bits_unpack_unsigned(SpeexBits *bits, int nbBits) +EXPORT unsigned int speex_bits_unpack_unsigned(SpeexBits *bits, int nbBits) { unsigned int d=0; if ((bits->charPtr<bitPtr+nbBits>bits->nbBits) @@ -323,7 +324,7 @@ unsigned int speex_bits_unpack_unsigned(SpeexBits *bits, int nbBits) #if 0 /* Rockbox: unused */ -unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits) +EXPORT unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits) { unsigned int d=0; int bitPtr, charPtr; @@ -353,7 +354,7 @@ unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits) } #endif -int speex_bits_peek(SpeexBits *bits) +EXPORT int speex_bits_peek(SpeexBits *bits) { if ((bits->charPtr<bitPtr+1>bits->nbBits) bits->overflow=1; @@ -362,7 +363,7 @@ int speex_bits_peek(SpeexBits *bits) return (bits->chars[bits->charPtr]>>(BITS_PER_CHAR-1 - bits->bitPtr))&1; } -void speex_bits_advance(SpeexBits *bits, int n) +EXPORT void speex_bits_advance(SpeexBits *bits, int n) { if (((bits->charPtr<bitPtr+n>bits->nbBits) || bits->overflow){ bits->overflow=1; @@ -372,7 +373,7 @@ void speex_bits_advance(SpeexBits *bits, int n) bits->bitPtr = (bits->bitPtr+n) & (BITS_PER_CHAR-1); /* modulo by BITS_PER_CHAR */ } -int speex_bits_remaining(SpeexBits *bits) +EXPORT int speex_bits_remaining(SpeexBits *bits) { if (bits->overflow) return -1; @@ -382,14 +383,14 @@ int speex_bits_remaining(SpeexBits *bits) #if 0 /* Rockbox: unused */ -int speex_bits_nbytes(SpeexBits *bits) +EXPORT int speex_bits_nbytes(SpeexBits *bits) { return ((bits->nbBits+BITS_PER_CHAR-1)>>LOG2_BITS_PER_CHAR); } #endif #ifndef SPEEX_DISABLE_ENCODER -void speex_bits_insert_terminator(SpeexBits *bits) +EXPORT void speex_bits_insert_terminator(SpeexBits *bits) { if (bits->bitPtr) speex_bits_pack(bits, 0, 1); diff --git a/lib/rbcodec/codecs/libspeex/config-speex.h b/lib/rbcodec/codecs/libspeex/config-speex.h index 7e0672c150..d6d3b23a0a 100644 --- a/lib/rbcodec/codecs/libspeex/config-speex.h +++ b/lib/rbcodec/codecs/libspeex/config-speex.h @@ -1,5 +1,5 @@ #ifndef ROCKBOX_VOICE_ENCODER -#include "codeclib.h" +#include "codeclib.h" #include "autoconf.h" #else #define ICODE_ATTR @@ -17,7 +17,11 @@ /* Make use of ARM4E assembly optimizations */ #if defined(CPU_ARM) +#if (ARM_ARCH < 5) #define ARM4_ASM +#else +#define ARM5E_ASM +#endif #endif /* Make use of Coldfire assembly optimizations */ @@ -40,10 +44,10 @@ #ifndef ROCKBOX_VOICE_ENCODER /* Compile target codec as fixed point */ -#define FIXED_POINT +#define FIXED_POINT #else /* Compile voice clip encoder as floating point */ -#define FLOATING_POINT +#define FLOATING_POINT #endif #ifndef ROCKBOX_VOICE_CODEC @@ -137,13 +141,13 @@ #define SPEEX_MAJOR_VERSION 1 /* Version micro */ -#define SPEEX_MICRO_VERSION 15 +#define SPEEX_MICRO_VERSION 16 /* Version minor */ #define SPEEX_MINOR_VERSION 1 /* Complete version string */ -#define SPEEX_VERSION "1.2beta3" +#define SPEEX_VERSION "1.2rc1" /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 @@ -155,7 +159,7 @@ /* #undef USE_ALLOCA */ /* Use C99 variable-size arrays */ -#define VAR_ARRAYS +#define VAR_ARRAYS /* Enable Vorbis-style psychoacoustics (EXPERIMENTAL) */ /* #undef VORBIS_PSYCHO */ @@ -184,3 +188,7 @@ #define RELEASE 1 +/* We don't care */ +#define EXPORT + +#define USE_KISS_FFT diff --git a/lib/rbcodec/codecs/libspeex/fftwrap.c b/lib/rbcodec/codecs/libspeex/fftwrap.c index 2312f755d6..b849e74f7c 100644 --- a/lib/rbcodec/codecs/libspeex/fftwrap.c +++ b/lib/rbcodec/codecs/libspeex/fftwrap.c @@ -1,23 +1,23 @@ -/* Copyright (C) 2005-2006 Jean-Marc Valin +/* Copyright (C) 2005-2006 Jean-Marc Valin File: fftwrap.c - Wrapper for various FFTs + Wrapper for various FFTs 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 the Xiph.org Foundation 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 @@ -36,10 +36,6 @@ #include "config-speex.h" #endif -/*#define USE_SMALLFT*/ -#define USE_KISS_FFT - - #include "arch.h" #include "os_support.h" @@ -66,7 +62,7 @@ static int maximize_range(spx_word16_t *in, spx_word16_t *out, spx_word16_t boun for (i=0;i + +struct mkl_config { + DFTI_DESCRIPTOR_HANDLE desc; + int N; +}; + +void *spx_fft_init(int size) +{ + struct mkl_config *table = (struct mkl_config *) speex_alloc(sizeof(struct mkl_config)); + table->N = size; + DftiCreateDescriptor(&table->desc, DFTI_SINGLE, DFTI_REAL, 1, size); + DftiSetValue(table->desc, DFTI_PACKED_FORMAT, DFTI_PACK_FORMAT); + DftiSetValue(table->desc, DFTI_PLACEMENT, DFTI_NOT_INPLACE); + DftiSetValue(table->desc, DFTI_FORWARD_SCALE, 1.0f / size); + DftiCommitDescriptor(table->desc); + return table; +} + +void spx_fft_destroy(void *table) +{ + struct mkl_config *t = (struct mkl_config *) table; + DftiFreeDescriptor(t->desc); + speex_free(table); +} + +void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + struct mkl_config *t = (struct mkl_config *) table; + DftiComputeForward(t->desc, in, out); +} + +void spx_ifft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + struct mkl_config *t = (struct mkl_config *) table; + DftiComputeBackward(t->desc, in, out); +} + +#elif defined(USE_GPL_FFTW3) + +#include + +struct fftw_config { + float *in; + float *out; + fftwf_plan fft; + fftwf_plan ifft; + int N; +}; + +void *spx_fft_init(int size) +{ + struct fftw_config *table = (struct fftw_config *) speex_alloc(sizeof(struct fftw_config)); + table->in = fftwf_malloc(sizeof(float) * (size+2)); + table->out = fftwf_malloc(sizeof(float) * (size+2)); + + table->fft = fftwf_plan_dft_r2c_1d(size, table->in, (fftwf_complex *) table->out, FFTW_PATIENT); + table->ifft = fftwf_plan_dft_c2r_1d(size, (fftwf_complex *) table->in, table->out, FFTW_PATIENT); + + table->N = size; + return table; +} + +void spx_fft_destroy(void *table) +{ + struct fftw_config *t = (struct fftw_config *) table; + fftwf_destroy_plan(t->fft); + fftwf_destroy_plan(t->ifft); + fftwf_free(t->in); + fftwf_free(t->out); + speex_free(table); +} + + +void spx_fft(void *table, spx_word16_t *in, spx_word16_t *out) +{ + int i; + struct fftw_config *t = (struct fftw_config *) table; + const int N = t->N; + float *iptr = t->in; + float *optr = t->out; + const float m = 1.0 / N; + for(i=0;ifft); + + out[0] = optr[0]; + for(i=1;iN; + float *iptr = t->in; + float *optr = t->out; + + iptr[0] = in[0]; + iptr[1] = 0.0f; + for(i=1;iifft); + + for(i=0;i>2), "3" (sig_shift) diff --git a/lib/rbcodec/codecs/libspeex/fixed_debug.h b/lib/rbcodec/codecs/libspeex/fixed_debug.h index d5c449f4d9..4d5fe11113 100644 --- a/lib/rbcodec/codecs/libspeex/fixed_debug.h +++ b/lib/rbcodec/codecs/libspeex/fixed_debug.h @@ -7,18 +7,18 @@ 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 the Xiph.org Foundation 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 @@ -101,7 +101,7 @@ static inline int _EXTEND32(int x, char *file, int line) } #define SHR16(a, shift) _SHR16(a, shift, __FILE__, __LINE__) -static inline short _SHR16(int a, int shift, char *file, int line) +static inline short _SHR16(int a, int shift, char *file, int line) { int res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) @@ -115,7 +115,7 @@ static inline short _SHR16(int a, int shift, char *file, int line) return res; } #define SHL16(a, shift) _SHL16(a, shift, __FILE__, __LINE__) -static inline short _SHL16(int a, int shift, char *file, int line) +static inline short _SHL16(int a, int shift, char *file, int line) { int res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) @@ -129,7 +129,7 @@ static inline short _SHL16(int a, int shift, char *file, int line) return res; } -static inline int SHR32(long long a, int shift) +static inline int SHR32(long long a, int shift) { long long res; if (!VERIFY_INT(a) || !VERIFY_SHORT(shift)) @@ -144,7 +144,7 @@ static inline int SHR32(long long a, int shift) spx_mips++; return res; } -static inline int SHL32(long long a, int shift) +static inline int SHL32(long long a, int shift) { long long res; if (!VERIFY_INT(a) || !VERIFY_SHORT(shift)) @@ -161,7 +161,7 @@ static inline int SHL32(long long a, int shift) } #define PSHR16(a,shift) (SHR16(ADD16((a),((1<<((shift))>>1))),shift)) -#define PSHR32(a,shift) (SHR32(ADD32((a),((1<<((shift))>>1))),shift)) +#define PSHR32(a,shift) (SHR32(ADD32((a),((EXTEND32(1)<<((shift))>>1))),shift)) #define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) #define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) @@ -171,7 +171,7 @@ static inline int SHL32(long long a, int shift) //#define SHL(a,shift) ((a) << (shift)) #define ADD16(a, b) _ADD16(a, b, __FILE__, __LINE__) -static inline short _ADD16(int a, int b, char *file, int line) +static inline short _ADD16(int a, int b, char *file, int line) { int res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -188,7 +188,7 @@ static inline short _ADD16(int a, int b, char *file, int line) } #define SUB16(a, b) _SUB16(a, b, __FILE__, __LINE__) -static inline short _SUB16(int a, int b, char *file, int line) +static inline short _SUB16(int a, int b, char *file, int line) { int res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -203,7 +203,7 @@ static inline short _SUB16(int a, int b, char *file, int line) } #define ADD32(a, b) _ADD32(a, b, __FILE__, __LINE__) -static inline int _ADD32(long long a, long long b, char *file, int line) +static inline int _ADD32(long long a, long long b, char *file, int line) { long long res; if (!VERIFY_INT(a) || !VERIFY_INT(b)) @@ -219,7 +219,7 @@ static inline int _ADD32(long long a, long long b, char *file, int line) return res; } -static inline int SUB32(long long a, long long b) +static inline int SUB32(long long a, long long b) { long long res; if (!VERIFY_INT(a) || !VERIFY_INT(b)) @@ -236,7 +236,7 @@ static inline int SUB32(long long a, long long b) #define ADD64(a,b) (MIPS_INC(a)+(b)) /* result fits in 16 bits */ -static inline short MULT16_16_16(int a, int b) +static inline short MULT16_16_16(int a, int b) { int res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -251,7 +251,7 @@ static inline short MULT16_16_16(int a, int b) } #define MULT16_16(a, b) _MULT16_16(a, b, __FILE__, __LINE__) -static inline int _MULT16_16(int a, int b, char *file, int line) +static inline int _MULT16_16(int a, int b, char *file, int line) { long long res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -279,8 +279,8 @@ static inline int _MULT16_32_QX(int a, long long b, int Q, char *file, int line) { fprintf (stderr, "MULT16_32_Q%d: inputs are not short+int: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); } - if (ABS32(b)>=(1<<(15+Q))) - fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); + if (ABS32(b)>=(EXTEND32(1)<<(15+Q))) + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); res = (((long long)a)*(long long)b) >> Q; if (!VERIFY_INT(res)) fprintf (stderr, "MULT16_32_Q%d: output is not int: %d*%d=%d in %s: line %d\n", Q, (int)a, (int)b,(int)res, file, line); @@ -295,9 +295,9 @@ static inline int MULT16_32_PX(int a, long long b, int Q) { fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d\n", Q, (int)a, (int)b); } - if (ABS32(b)>=(1<<(15+Q))) - fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d\n", Q, (int)a, (int)b); - res = ((((long long)a)*(long long)b) + ((1<>1))>> Q; + if (ABS32(b)>=(EXTEND32(1)<<(15+Q))) + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d\n", Q, (int)a, (int)b); + res = ((((long long)a)*(long long)b) + ((EXTEND32(1)<>1))>> Q; if (!VERIFY_INT(res)) fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d\n", Q, (int)a, (int)b,(int)res); spx_mips+=5; @@ -323,7 +323,7 @@ static inline int SATURATE(int a, int b) return a; } -static inline int MULT16_16_Q11_32(int a, int b) +static inline int MULT16_16_Q11_32(int a, int b) { long long res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -337,7 +337,7 @@ static inline int MULT16_16_Q11_32(int a, int b) spx_mips+=3; return res; } -static inline short MULT16_16_Q13(int a, int b) +static inline short MULT16_16_Q13(int a, int b) { long long res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -351,7 +351,7 @@ static inline short MULT16_16_Q13(int a, int b) spx_mips+=3; return res; } -static inline short MULT16_16_Q14(int a, int b) +static inline short MULT16_16_Q14(int a, int b) { long long res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -365,7 +365,7 @@ static inline short MULT16_16_Q14(int a, int b) spx_mips+=3; return res; } -static inline short MULT16_16_Q15(int a, int b) +static inline short MULT16_16_Q15(int a, int b) { long long res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -382,7 +382,7 @@ static inline short MULT16_16_Q15(int a, int b) return res; } -static inline short MULT16_16_P13(int a, int b) +static inline short MULT16_16_P13(int a, int b) { long long res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -399,7 +399,7 @@ static inline short MULT16_16_P13(int a, int b) spx_mips+=4; return res; } -static inline short MULT16_16_P14(int a, int b) +static inline short MULT16_16_P14(int a, int b) { long long res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -416,7 +416,7 @@ static inline short MULT16_16_P14(int a, int b) spx_mips+=4; return res; } -static inline short MULT16_16_P15(int a, int b) +static inline short MULT16_16_P15(int a, int b) { long long res; if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) @@ -436,7 +436,7 @@ static inline short MULT16_16_P15(int a, int b) #define DIV32_16(a, b) _DIV32_16(a, b, __FILE__, __LINE__) -static inline int _DIV32_16(long long a, long long b, char *file, int line) +static inline int _DIV32_16(long long a, long long b, char *file, int line) { long long res; if (b==0) @@ -462,7 +462,7 @@ static inline int _DIV32_16(long long a, long long b, char *file, int line) } #define DIV32(a, b) _DIV32(a, b, __FILE__, __LINE__) -static inline int _DIV32(long long a, long long b, char *file, int line) +static inline int _DIV32(long long a, long long b, char *file, int line) { long long res; if (b==0) diff --git a/lib/rbcodec/codecs/libspeex/fixed_generic.h b/lib/rbcodec/codecs/libspeex/fixed_generic.h index 2948177c0b..3fb096ed90 100644 --- a/lib/rbcodec/codecs/libspeex/fixed_generic.h +++ b/lib/rbcodec/codecs/libspeex/fixed_generic.h @@ -47,14 +47,14 @@ #define SHR32(a,shift) ((a) >> (shift)) #define SHL32(a,shift) ((a) << (shift)) #define PSHR16(a,shift) (SHR16((a)+((1<<((shift))>>1)),shift)) -#define PSHR32(a,shift) (SHR32((a)+((1<<((shift))>>1)),shift)) +#define PSHR32(a,shift) (SHR32((a)+((EXTEND32(1)<<((shift))>>1)),shift)) #define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) #define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) #define SATURATE32(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) #define SHR(a,shift) ((a) >> (shift)) #define SHL(a,shift) ((spx_word32_t)(a) << (shift)) -#define PSHR(a,shift) (SHR((a)+((1<<((shift))>>1)),shift)) +#define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift)) #define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) diff --git a/lib/rbcodec/codecs/libspeex/jitter.c b/lib/rbcodec/codecs/libspeex/jitter.c index d9f6c67b86..f4e3bc2be1 100644 --- a/lib/rbcodec/codecs/libspeex/jitter.c +++ b/lib/rbcodec/codecs/libspeex/jitter.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2002 Jean-Marc Valin +/* Copyright (C) 2002 Jean-Marc Valin File: speex_jitter.h Adaptive jitter buffer for Speex @@ -6,18 +6,18 @@ 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 the Xiph.org Foundation 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 @@ -73,17 +73,17 @@ TODO: #define LT32(a,b) (((spx_int32_t)((a)-(b)))<0) #define LE32(a,b) (((spx_int32_t)((a)-(b)))<=0) -#define ROUND_DOWN(x, step) ((x)<0 ? ((x)-(step)+1)/(step)*(step) : (x)/(step)*(step)) +#define ROUND_DOWN(x, step) ((x)<0 ? ((x)-(step)+1)/(step)*(step) : (x)/(step)*(step)) -#define MAX_TIMINGS 20 +#define MAX_TIMINGS 40 #define MAX_BUFFERS 3 -#define TOP_DELAY 20 +#define TOP_DELAY 40 /** Buffer that keeps the time of arrival of the latest packets */ struct TimingBuffer { int filled; /**< Number of entries occupied in "timing" and "counts"*/ int curr_count; /**< Number of packet timings we got (including those we discarded) */ - spx_int16_t timing[MAX_TIMINGS]; /**< Sorted list of all timings ("latest" packets first) */ + spx_int32_t timing[MAX_TIMINGS]; /**< Sorted list of all timings ("latest" packets first) */ spx_int16_t counts[MAX_TIMINGS]; /**< Order the packets were put in (will be used for short-term estimate) */ }; @@ -103,7 +103,7 @@ static void tb_add(struct TimingBuffer *tb, spx_int16_t timing) tb->curr_count++; return; } - + /* Find where the timing info goes in the sorted list */ pos = 0; /* FIXME: Do bisection instead of linear search */ @@ -111,9 +111,9 @@ static void tb_add(struct TimingBuffer *tb, spx_int16_t timing) { pos++; } - + speex_assert(pos <= tb->filled && pos < MAX_TIMINGS); - + /* Shift everything so we can perform the insertion */ if (pos < tb->filled) { @@ -126,7 +126,7 @@ static void tb_add(struct TimingBuffer *tb, spx_int16_t timing) /* Insert */ tb->timing[pos] = timing; tb->counts[pos] = tb->curr_count; - + tb->curr_count++; if (tb->filledfilled++; @@ -139,12 +139,12 @@ struct JitterBuffer_ { spx_uint32_t pointer_timestamp; /**< Timestamp of what we will *get* next */ spx_uint32_t last_returned_timestamp; /**< Useful for getting the next packet with the same timestamp (for fragmented media) */ spx_uint32_t next_stop; /**< Estimated time the next get() will be called */ - + spx_int32_t buffered; /**< Amount of data we think is still buffered by the application (timestamp units)*/ - + JitterBufferPacket packets[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Packets stored in the buffer */ spx_uint32_t arrival[SPEEX_JITTER_MAX_BUFFER_SIZE]; /**< Packet arrival time (0 means it was late, even though it's a valid timestamp) */ - + void (*destroy) (void *); /**< Callback for destroying a packet */ spx_int32_t delay_step; /**< Size of the steps when adjusting buffering (timestamp units) */ @@ -154,7 +154,7 @@ struct JitterBuffer_ { int late_cutoff; /**< How late must a packet be for it not to be considered at all */ int interp_requested; /**< An interpolation is requested by speex_jitter_update_delay() */ int auto_adjust; /**< Whether to automatically adjust the delay at any time */ - + struct TimingBuffer _tb[MAX_BUFFERS]; /**< Don't use those directly */ struct TimingBuffer *timeBuffers[MAX_BUFFERS]; /**< Storing arrival time of latest frames so we can compute some stats */ int window_size; /**< Total window over which the late frames are counted */ @@ -162,15 +162,15 @@ struct JitterBuffer_ { int max_late_rate; /**< Absolute maximum amount of late packets tolerable (in percent) */ int latency_tradeoff; /**< Latency equivalent of losing one percent of packets */ int auto_tradeoff; /**< Latency equivalent of losing one percent of packets (automatic default) */ - + int lost_count; /**< Number of consecutive lost packets */ }; -/** Based on available data, this computes the optimal delay for the jitter buffer. +/** Based on available data, this computes the optimal delay for the jitter buffer. The optimised function is in timestamp units and is: cost = delay + late_factor*[number of frames that would be late if we used that delay] @param tb Array of buffers - @param late_factor Equivalent cost of a late frame (in timestamp units) + @param late_factor Equivalent cost of a late frame (in timestamp units) */ static spx_int16_t compute_opt_delay(JitterBuffer *jitter) { @@ -186,27 +186,27 @@ static spx_int16_t compute_opt_delay(JitterBuffer *jitter) int worst = 0; spx_int32_t deltaT; struct TimingBuffer *tb; - + tb = jitter->_tb; - + /* Number of packet timings we have received (including those we didn't keep) */ tot_count = 0; for (i=0;ilatency_tradeoff != 0) late_factor = jitter->latency_tradeoff * 100.0f / tot_count; else late_factor = jitter->auto_tradeoff * jitter->window_size/tot_count; - + /*fprintf(stderr, "late_factor = %f\n", late_factor);*/ for (i=0;idelay_step); pos[next]++; - + /* Actual cost function that tells us how bad using this delay would be */ cost = -latest + late_factor*late; /*fprintf(stderr, "cost %d = %d + %f * %d\n", cost, -latest, late_factor, late);*/ @@ -243,24 +243,24 @@ static spx_int16_t compute_opt_delay(JitterBuffer *jitter) } else { break; } - + /* For the next timing we will consider, there will be one more late packet to count */ late++; /* Two-frame penalty if we're going to increase the amount of late frames (hysteresis) */ if (latest >= 0 && !penalty_taken) { penalty_taken = 1; - late+=2; + late+=4; } } - + deltaT = best-worst; /* This is a default "automatic latency tradeoff" when none is provided */ jitter->auto_tradeoff = 1 + deltaT/TOP_DELAY; /*fprintf(stderr, "auto_tradeoff = %d (%d %d %d)\n", jitter->auto_tradeoff, best, worst, i);*/ - + /* FIXME: Compute a short-term estimate too and combine with the long-term one */ - + /* Prevents reducing the buffer size when we haven't really had much data */ if (tot_count < TOP_DELAY && opt > 0) return 0; @@ -269,7 +269,7 @@ static spx_int16_t compute_opt_delay(JitterBuffer *jitter) /** Initialise jitter buffer */ -JitterBuffer *jitter_buffer_init(int step_size) +EXPORT JitterBuffer *jitter_buffer_init(int step_size) { JitterBuffer *jitter = (JitterBuffer*)speex_alloc(sizeof(JitterBuffer)); if (jitter) @@ -294,7 +294,7 @@ JitterBuffer *jitter_buffer_init(int step_size) } /** Reset jitter buffer */ -void jitter_buffer_reset(JitterBuffer *jitter) +EXPORT void jitter_buffer_reset(JitterBuffer *jitter) { int i; for (i=0;ilost_count = 0; jitter->buffered = 0; jitter->auto_tradeoff = 32000; - + for (i=0;i_tb[i]); @@ -325,7 +325,7 @@ void jitter_buffer_reset(JitterBuffer *jitter) } /** Destroy jitter buffer */ -void jitter_buffer_destroy(JitterBuffer *jitter) +EXPORT void jitter_buffer_destroy(JitterBuffer *jitter) { jitter_buffer_reset(jitter); speex_free(jitter); @@ -365,12 +365,12 @@ static void shift_timings(JitterBuffer *jitter, spx_int16_t amount) /** Put one packet into the jitter buffer */ -void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet) +EXPORT void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet) { int i,j; int late; /*fprintf (stderr, "put packet %d %d\n", timestamp, span);*/ - + /* Cleanup buffer (remove old packets that weren't played) */ if (!jitter->reset_state) { @@ -388,7 +388,7 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet) } } } - + /*fprintf(stderr, "arrival: %d %d %d\n", packet->timestamp, jitter->next_stop, jitter->pointer_timestamp);*/ /* Check if packet is late (could still be useful though) */ if (!jitter->reset_state && LT32(packet->timestamp, jitter->next_stop)) @@ -398,7 +398,14 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet) } else { late = 0; } - + + /* For some reason, the consumer has failed the last 20 fetches. Make sure this packet is + * used to resync. */ + if (jitter->lost_count>20) + { + jitter_buffer_reset(jitter); + } + /* Only insert the packet if it's not hopelessly late (i.e. totally useless) */ if (jitter->reset_state || GE32(packet->timestamp+packet->span+jitter->delay_step, jitter->pointer_timestamp)) { @@ -409,7 +416,7 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet) if (jitter->packets[i].data==NULL) break; } - + /*No place left in the buffer, need to make room for it by discarding the oldest packet */ if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) { @@ -428,13 +435,9 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet) else speex_free(jitter->packets[i].data); jitter->packets[i].data=NULL; - if (jitter->lost_count>20) - { - jitter_buffer_reset(jitter); - } - /*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, jitter->pointer_timestamp);*/ + /*fprintf (stderr, "Buffer is full, discarding earliest frame %d (currently at %d)\n", timestamp, jitter->pointer_timestamp);*/ } - + /* Copy packet in buffer */ if (jitter->destroy) { @@ -454,18 +457,18 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet) else jitter->arrival[i] = jitter->next_stop; } - - + + } /** Get one packet from the jitter buffer */ -int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t desired_span, spx_int32_t *start_offset) +EXPORT int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t desired_span, spx_int32_t *start_offset) { int i; unsigned int j; int incomplete = 0; spx_int16_t opt; - + if (start_offset != NULL) *start_offset = 0; @@ -485,7 +488,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3 } if (found) { - jitter->reset_state=0; + jitter->reset_state=0; jitter->pointer_timestamp = oldest; jitter->next_stop = oldest; } else { @@ -494,36 +497,36 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3 return JITTER_BUFFER_MISSING; } } - + jitter->last_returned_timestamp = jitter->pointer_timestamp; - + if (jitter->interp_requested != 0) { packet->timestamp = jitter->pointer_timestamp; packet->span = jitter->interp_requested; - + /* Increment the pointer because it got decremented in the delay update */ jitter->pointer_timestamp += jitter->interp_requested; packet->len = 0; /*fprintf (stderr, "Deferred interpolate\n");*/ - + jitter->interp_requested = 0; - + jitter->buffered = packet->span - desired_span; return JITTER_BUFFER_INSERTION; } - + /* Searching for the packet that fits best */ - + /* Search the buffer for a packet with the right timestamp and spanning the whole current chunk */ for (i=0;ipackets[i].data && jitter->packets[i].timestamp==jitter->pointer_timestamp && GE32(jitter->packets[i].timestamp+jitter->packets[i].span,jitter->pointer_timestamp+desired_span)) break; } - + /* If no match, try for an "older" packet that still spans (fully) the current chunk */ if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) { @@ -533,7 +536,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3 break; } } - + /* If still no match, try for an "older" packet that spans part of the current chunk */ if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) { @@ -543,7 +546,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3 break; } } - + /* If still no match, try for earliest packet possible */ if (i==SPEEX_JITTER_MAX_BUFFER_SIZE) { @@ -577,17 +580,17 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3 if (i!=SPEEX_JITTER_MAX_BUFFER_SIZE) { spx_int32_t offset; - + /* We (obviously) haven't lost this packet */ jitter->lost_count = 0; - + /* In this case, 0 isn't as a valid timestamp */ if (jitter->arrival[i] != 0) { update_timings(jitter, ((spx_int32_t)jitter->packets[i].timestamp) - ((spx_int32_t)jitter->arrival[i]) - jitter->buffer_margin); } - - + + if (jitter->packets[i].len > packet->len) { speex_warning_int("jitter_buffer_get(): packet too large to fit. Size is", jitter->packets[i].len); @@ -611,10 +614,10 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3 *start_offset = offset; else if (offset != 0) speex_warning_int("jitter_buffer_get() discarding non-zero start_offset", offset); - + packet->timestamp = jitter->packets[i].timestamp; jitter->last_returned_timestamp = packet->timestamp; - + packet->span = jitter->packets[i].span; packet->sequence = jitter->packets[i].sequence; packet->user_data = jitter->packets[i].user_data; @@ -622,36 +625,36 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3 jitter->pointer_timestamp = jitter->packets[i].timestamp+jitter->packets[i].span; jitter->buffered = packet->span - desired_span; - + if (start_offset != NULL) jitter->buffered += *start_offset; - + return JITTER_BUFFER_OK; } - - + + /* If we haven't found anything worth returning */ - + /*fprintf (stderr, "not found\n");*/ jitter->lost_count++; /*fprintf (stderr, "m");*/ /*fprintf (stderr, "lost_count = %d\n", jitter->lost_count);*/ - + opt = compute_opt_delay(jitter); - - /* Should we force an increase in the buffer or just do normal interpolation? */ + + /* Should we force an increase in the buffer or just do normal interpolation? */ if (opt < 0) { /* Need to increase buffering */ - + /* Shift histogram to compensate */ shift_timings(jitter, -opt); - + packet->timestamp = jitter->pointer_timestamp; packet->span = -opt; /* Don't move the pointer_timestamp forward */ packet->len = 0; - + jitter->buffered = packet->span - desired_span; return JITTER_BUFFER_INSERTION; /*jitter->pointer_timestamp -= jitter->delay_step;*/ @@ -659,12 +662,12 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3 } else { /* Normal packet loss */ packet->timestamp = jitter->pointer_timestamp; - + desired_span = ROUND_DOWN(desired_span, jitter->concealment_size); packet->span = desired_span; jitter->pointer_timestamp += desired_span; packet->len = 0; - + jitter->buffered = packet->span - desired_span; return JITTER_BUFFER_MISSING; /*fprintf (stderr, "Normal loss\n");*/ @@ -673,7 +676,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int3 } -int jitter_buffer_get_another(JitterBuffer *jitter, JitterBufferPacket *packet) +EXPORT int jitter_buffer_get_another(JitterBuffer *jitter, JitterBufferPacket *packet) { int i, j; for (i=0;ipointer_timestamp += opt; jitter->interp_requested = -opt; /*fprintf (stderr, "Decision to interpolate %d samples\n", -opt);*/ @@ -727,14 +730,14 @@ static int _jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket jitter->pointer_timestamp += opt; /*fprintf (stderr, "Decision to drop %d samples\n", opt);*/ } - + return opt; } /* Let the jitter buffer know it's the right time to adjust the buffering delay to the network conditions */ -int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset) +EXPORT int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, spx_int32_t *start_offset) { - /* If the programmer calls jitter_buffer_update_delay() directly, + /* If the programmer calls jitter_buffer_update_delay() directly, automatically disable auto-adjustment */ jitter->auto_adjust = 0; @@ -742,17 +745,17 @@ int jitter_buffer_update_delay(JitterBuffer *jitter, JitterBufferPacket *packet, } /** Get pointer timestamp of jitter buffer */ -int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter) +EXPORT int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter) { return jitter->pointer_timestamp; } -void jitter_buffer_tick(JitterBuffer *jitter) +EXPORT void jitter_buffer_tick(JitterBuffer *jitter) { /* Automatically-adjust the buffering delay if requested */ if (jitter->auto_adjust) _jitter_buffer_update_delay(jitter, NULL, NULL); - + if (jitter->buffered >= 0) { jitter->next_stop = jitter->pointer_timestamp - jitter->buffered; @@ -763,12 +766,12 @@ void jitter_buffer_tick(JitterBuffer *jitter) jitter->buffered = 0; } -void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem) +EXPORT void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem) { /* Automatically-adjust the buffering delay if requested */ if (jitter->auto_adjust) _jitter_buffer_update_delay(jitter, NULL, NULL); - + if (jitter->buffered < 0) speex_warning_int("jitter buffer sees negative buffering, your code might be broken. Value is ", jitter->buffered); jitter->next_stop = jitter->pointer_timestamp - rem; @@ -776,7 +779,7 @@ void jitter_buffer_remaining_span(JitterBuffer *jitter, spx_uint32_t rem) /* Used like the ioctl function to control the jitter buffer parameters */ -int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr) +EXPORT int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr) { int count, i; switch(request) @@ -836,4 +839,3 @@ int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr) } return 0; } - diff --git a/lib/rbcodec/codecs/libspeex/mdf.c b/lib/rbcodec/codecs/libspeex/mdf.c index 1994f2a886..cfbe4d1284 100644 --- a/lib/rbcodec/codecs/libspeex/mdf.c +++ b/lib/rbcodec/codecs/libspeex/mdf.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2003-2006 Jean-Marc Valin +/* Copyright (C) 2003-2008 Jean-Marc Valin File: mdf.c Echo canceller based on the MDF algorithm (see below) @@ -33,36 +33,36 @@ /* The echo canceller is based on the MDF algorithm described in: - J. S. Soo, K. K. Pang Multidelay block frequency adaptive filter, - IEEE Trans. Acoust. Speech Signal Process., Vol. ASSP-38, No. 2, + J. S. Soo, K. K. Pang Multidelay block frequency adaptive filter, + IEEE Trans. Acoust. Speech Signal Process., Vol. ASSP-38, No. 2, February 1990. - - We use the Alternatively Updated MDF (AUMDF) variant. Robustness to + + We use the Alternatively Updated MDF (AUMDF) variant. Robustness to double-talk is achieved using a variable learning rate as described in: - - Valin, J.-M., On Adjusting the Learning Rate in Frequency Domain Echo + + Valin, J.-M., On Adjusting the Learning Rate in Frequency Domain Echo Cancellation With Double-Talk. IEEE Transactions on Audio, Speech and Language Processing, Vol. 15, No. 3, pp. 1030-1034, 2007. http://people.xiph.org/~jm/papers/valin_taslp2006.pdf - + There is no explicit double-talk detection, but a continuous variation in the learning rate based on residual echo, double-talk and background noise. - + About the fixed-point version: - All the signals are represented with 16-bit words. The filter weights + All the signals are represented with 16-bit words. The filter weights are represented with 32-bit words, but only the top 16 bits are used in most cases. The lower 16 bits are completely unreliable (due to the fact that the update is done only on the top bits), but help in the adaptation -- probably by removing a "threshold effect" due to quantization (rounding going to zero) when the gradient is small. - + Another kludge that seems to work good: when performing the weight update, we only move half the way toward the "goal" this seems to reduce the effect of quantization noise in the update phase. This can be seen as applying a gradient descent on a "soft constraint" instead of having a hard constraint. - + */ #ifdef HAVE_CONFIG_H @@ -88,6 +88,12 @@ #define WEIGHT_SHIFT 0 #endif +#ifdef FIXED_POINT +#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x))) +#else +#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x)))) +#endif + /* If enabled, the AEC will use a foreground filter and a background filter to be more robust to double-talk and difficult signals in general. The cost is an extra FFT and a matrix-vector multiply */ #define TWO_PATH @@ -131,13 +137,15 @@ struct SpeexEchoState_ { int adapted; int saturated; int screwed_up; + int C; /** Number of input channels (microphones) */ + int K; /** Number of output channels (loudspeakers) */ spx_int32_t sampling_rate; spx_word16_t spec_average; spx_word16_t beta0; spx_word16_t beta_max; spx_word32_t sum_adapt; spx_word16_t leak_estimate; - + spx_word16_t *e; /* scratch */ spx_word16_t *x; /* Far-end input buffer (2N) */ spx_word16_t *X; /* Far-end buffer (M+1 frames) in frequency domain */ @@ -171,10 +179,10 @@ struct SpeexEchoState_ { spx_word16_t *window; spx_word16_t *prop; void *fft_table; - spx_word16_t memX, memD, memE; + spx_word16_t *memX, *memD, *memE; spx_word16_t preemph; spx_word16_t notch_radius; - spx_mem_t notch_mem[2]; + spx_mem_t *notch_mem; /* NOTE: If you only use speex_echo_cancel() and want to save some memory, remove this */ spx_int16_t *play_buf; @@ -182,7 +190,7 @@ struct SpeexEchoState_ { int play_buf_started; }; -static inline void filter_dc_notch16(const spx_int16_t *in, spx_word16_t radius, spx_word16_t *out, int len, spx_mem_t *mem) +static inline void filter_dc_notch16(const spx_int16_t *in, spx_word16_t radius, spx_word16_t *out, int len, spx_mem_t *mem, int stride) { int i; spx_word16_t den2; @@ -190,11 +198,11 @@ static inline void filter_dc_notch16(const spx_int16_t *in, spx_word16_t radius, den2 = MULT16_16_Q15(radius,radius) + MULT16_16_Q15(QCONST16(.7,15),MULT16_16_Q15(32767-radius,32767-radius)); #else den2 = radius*radius + .7*(1-radius)*(1-radius); -#endif +#endif /*printf ("%d %d %d %d %d %d\n", num[0], num[1], num[2], den[0], den[1], den[2]);*/ for (i=0;iK = nb_speakers; + st->C = nb_mic; + C=st->C; + K=st->K; #ifdef DUMP_ECHO_CANCEL_DATA if (rFile || pFile || oFile) speex_fatal("Opening dump files twice"); @@ -390,7 +420,7 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length) pFile = fopen("aec_play.sw", "wb"); oFile = fopen("aec_out.sw", "wb"); #endif - + st->frame_size = frame_size; st->window_size = 2*frame_size; N = st->window_size; @@ -412,24 +442,24 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length) st->leak_estimate = 0; st->fft_table = spx_fft_init(N); - - st->e = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t)); - st->x = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t)); - st->input = (spx_word16_t*)speex_alloc(st->frame_size*sizeof(spx_word16_t)); - st->y = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t)); - st->last_y = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t)); + + st->e = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); + st->x = (spx_word16_t*)speex_alloc(K*N*sizeof(spx_word16_t)); + st->input = (spx_word16_t*)speex_alloc(C*st->frame_size*sizeof(spx_word16_t)); + st->y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); + st->last_y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); st->Yf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); st->Rf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); st->Xf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); st->Yh = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); st->Eh = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t)); - st->X = (spx_word16_t*)speex_alloc((M+1)*N*sizeof(spx_word16_t)); - st->Y = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t)); - st->E = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t)); - st->W = (spx_word32_t*)speex_alloc(M*N*sizeof(spx_word32_t)); + st->X = (spx_word16_t*)speex_alloc(K*(M+1)*N*sizeof(spx_word16_t)); + st->Y = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); + st->E = (spx_word16_t*)speex_alloc(C*N*sizeof(spx_word16_t)); + st->W = (spx_word32_t*)speex_alloc(C*K*M*N*sizeof(spx_word32_t)); #ifdef TWO_PATH - st->foreground = (spx_word16_t*)speex_alloc(M*N*sizeof(spx_word16_t)); + st->foreground = (spx_word16_t*)speex_alloc(M*N*C*K*sizeof(spx_word16_t)); #endif st->PHI = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); st->power = (spx_word32_t*)speex_alloc((frame_size+1)*sizeof(spx_word32_t)); @@ -450,7 +480,7 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length) #endif for (i=0;i<=st->frame_size;i++) st->power_1[i] = FLOAT_ONE; - for (i=0;iW[i] = 0; { spx_word32_t sum = 0; @@ -465,11 +495,13 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length) } for (i=M-1;i>=0;i--) { - st->prop[i] = DIV32(MULT16_16(QCONST16(.8,15), st->prop[i]),sum); + st->prop[i] = DIV32(MULT16_16(QCONST16(.8f,15), st->prop[i]),sum); } } - - st->memX=st->memD=st->memE=0; + + st->memX = (spx_word16_t*)speex_alloc(K*sizeof(spx_word16_t)); + st->memD = (spx_word16_t*)speex_alloc(C*sizeof(spx_word16_t)); + st->memE = (spx_word16_t*)speex_alloc(C*sizeof(spx_word16_t)); st->preemph = QCONST16(.9,15); if (st->sampling_rate<12000) st->notch_radius = QCONST16(.9, 15); @@ -478,30 +510,32 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length) else st->notch_radius = QCONST16(.992, 15); - st->notch_mem[0] = st->notch_mem[1] = 0; + st->notch_mem = (spx_mem_t*)speex_alloc(2*C*sizeof(spx_mem_t)); st->adapted = 0; st->Pey = st->Pyy = FLOAT_ONE; - + #ifdef TWO_PATH st->Davg1 = st->Davg2 = 0; st->Dvar1 = st->Dvar2 = FLOAT_ZERO; #endif - - st->play_buf = (spx_int16_t*)speex_alloc((PLAYBACK_DELAY+1)*st->frame_size*sizeof(spx_int16_t)); + + st->play_buf = (spx_int16_t*)speex_alloc(K*(PLAYBACK_DELAY+1)*st->frame_size*sizeof(spx_int16_t)); st->play_buf_pos = PLAYBACK_DELAY*st->frame_size; st->play_buf_started = 0; - + return st; } /** Resets echo canceller state */ -void speex_echo_state_reset(SpeexEchoState *st) +EXPORT void speex_echo_state_reset(SpeexEchoState *st) { - int i, M, N; + int i, M, N, C, K; st->cancel_count=0; st->screwed_up = 0; N = st->window_size; M = st->M; + C=st->C; + K=st->K; for (i=0;iW[i] = 0; #ifdef TWO_PATH @@ -521,13 +555,20 @@ void speex_echo_state_reset(SpeexEchoState *st) { st->last_y[i] = 0; } - for (i=0;iE[i] = 0; + } + for (i=0;ix[i] = 0; } - st->notch_mem[0] = st->notch_mem[1] = 0; - st->memX=st->memD=st->memE=0; + for (i=0;i<2*C;i++) + st->notch_mem[i] = 0; + for (i=0;imemD[i]=st->memE[i]=0; + for (i=0;imemX[i]=0; st->saturated = 0; st->adapted = 0; @@ -545,7 +586,7 @@ void speex_echo_state_reset(SpeexEchoState *st) } /** Destroys an echo canceller state */ -void speex_echo_state_destroy(SpeexEchoState *st) +EXPORT void speex_echo_state_destroy(SpeexEchoState *st) { spx_fft_destroy(st->fft_table); @@ -576,9 +617,14 @@ void speex_echo_state_destroy(SpeexEchoState *st) #ifdef FIXED_POINT speex_free(st->wtmp2); #endif + speex_free(st->memX); + speex_free(st->memD); + speex_free(st->memE); + speex_free(st->notch_mem); + speex_free(st->play_buf); speex_free(st); - + #ifdef DUMP_ECHO_CANCEL_DATA fclose(rFile); fclose(pFile); @@ -587,7 +633,7 @@ void speex_echo_state_destroy(SpeexEchoState *st) #endif } -void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out) +EXPORT void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out) { int i; /*speex_warning_int("capture with fill level ", st->play_buf_pos/st->frame_size);*/ @@ -610,7 +656,7 @@ void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t } } -void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play) +EXPORT void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play) { /*speex_warning_int("playback with fill level ", st->play_buf_pos/st->frame_size);*/ if (!st->play_buf_started) @@ -637,16 +683,16 @@ void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play) } /** Performs echo cancellation on a frame (deprecated, last arg now ignored) */ -void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out, spx_int32_t *Yout) +EXPORT void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out, spx_int32_t *Yout) { speex_echo_cancellation(st, in, far_end, out); } /** Performs echo cancellation on a frame */ -void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out) +EXPORT void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const spx_int16_t *far_end, spx_int16_t *out) { - int i,j; - int N,M; + int i,j, chan, speak; + int N,M, C, K; spx_word32_t Syy,See,Sxx,Sdd, Sff; #ifdef TWO_PATH spx_word32_t Dbf; @@ -658,9 +704,12 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp spx_float_t alpha, alpha_1; spx_word16_t RER; spx_word32_t tmp32; - + N = st->window_size; M = st->M; + C = st->C; + K = st->K; + st->cancel_count++; #ifdef FIXED_POINT ss=DIV32_16(11469,M); @@ -670,157 +719,198 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp ss_1 = 1-ss; #endif - /* Apply a notch filter to make sure DC doesn't end up causing problems */ - filter_dc_notch16(in, st->notch_radius, st->input, st->frame_size, st->notch_mem); - /* Copy input data to buffer and apply pre-emphasis */ - for (i=0;iframe_size;i++) + for (chan = 0; chan < C; chan++) { - spx_word32_t tmp32; - tmp32 = SUB32(EXTEND32(far_end[i]), EXTEND32(MULT16_16_P15(st->preemph, st->memX))); -#ifdef FIXED_POINT - /* If saturation occurs here, we need to freeze adaptation for M+1 frames (not just one) */ - if (tmp32 > 32767) + /* Apply a notch filter to make sure DC doesn't end up causing problems */ + filter_dc_notch16(in+chan, st->notch_radius, st->input+chan*st->frame_size, st->frame_size, st->notch_mem+2*chan, C); + /* Copy input data to buffer and apply pre-emphasis */ + /* Copy input data to buffer */ + for (i=0;iframe_size;i++) { - tmp32 = 32767; - st->saturated = M+1; + spx_word32_t tmp32; + /* FIXME: This core has changed a bit, need to merge properly */ + tmp32 = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(MULT16_16_P15(st->preemph, st->memD[chan]))); +#ifdef FIXED_POINT + if (tmp32 > 32767) + { + tmp32 = 32767; + if (st->saturated == 0) + st->saturated = 1; + } + if (tmp32 < -32767) + { + tmp32 = -32767; + if (st->saturated == 0) + st->saturated = 1; + } +#endif + st->memD[chan] = st->input[chan*st->frame_size+i]; + st->input[chan*st->frame_size+i] = EXTRACT16(tmp32); } - if (tmp32 < -32767) + } + + for (speak = 0; speak < K; speak++) + { + for (i=0;iframe_size;i++) { - tmp32 = -32767; - st->saturated = M+1; - } -#endif - st->x[i+st->frame_size] = EXTRACT16(tmp32); - st->memX = far_end[i]; - - tmp32 = SUB32(EXTEND32(st->input[i]), EXTEND32(MULT16_16_P15(st->preemph, st->memD))); + spx_word32_t tmp32; + st->x[speak*N+i] = st->x[speak*N+i+st->frame_size]; + tmp32 = SUB32(EXTEND32(far_end[i*K+speak]), EXTEND32(MULT16_16_P15(st->preemph, st->memX[speak]))); #ifdef FIXED_POINT - if (tmp32 > 32767) - { - tmp32 = 32767; - if (st->saturated == 0) - st->saturated = 1; - } - if (tmp32 < -32767) + /*FIXME: If saturation occurs here, we need to freeze adaptation for M frames (not just one) */ + if (tmp32 > 32767) + { + tmp32 = 32767; + st->saturated = M+1; + } + if (tmp32 < -32767) + { + tmp32 = -32767; + st->saturated = M+1; + } +#endif + st->x[speak*N+i+st->frame_size] = EXTRACT16(tmp32); + st->memX[speak] = far_end[i*K+speak]; + } + } + + for (speak = 0; speak < K; speak++) + { + /* Shift memory: this could be optimized eventually*/ + for (j=M-1;j>=0;j--) { - tmp32 = -32767; - if (st->saturated == 0) - st->saturated = 1; + for (i=0;iX[(j+1)*N*K+speak*N+i] = st->X[j*N*K+speak*N+i]; } -#endif - st->memD = st->input[i]; - st->input[i] = tmp32; + /* Convert x (echo input) to frequency domain */ + spx_fft(st->fft_table, st->x+speak*N, &st->X[speak*N]); } - /* Shift memory: this could be optimized eventually*/ - for (j=M-1;j>=0;j--) + Sxx = 0; + for (speak = 0; speak < K; speak++) { - for (i=0;iX[(j+1)*N+i] = st->X[j*N+i]; + Sxx += mdf_inner_prod(st->x+speak*N+st->frame_size, st->x+speak*N+st->frame_size, st->frame_size); + power_spectrum_accum(st->X+speak*N, st->Xf, N); } - /* Convert x (far end) to frequency domain */ - spx_fft(st->fft_table, st->x, &st->X[0]); - for (i=0;ilast_y[i] = st->x[i]; - Sxx = mdf_inner_prod(st->x+st->frame_size, st->x+st->frame_size, st->frame_size); - for (i=0;iframe_size;i++) - st->x[i] = st->x[i+st->frame_size]; - /* From here on, the top part of x is used as scratch space */ - + Sff = 0; + for (chan = 0; chan < C; chan++) + { #ifdef TWO_PATH - /* Compute foreground filter */ - spectral_mul_accum16(st->X, st->foreground, st->Y, N, M); - spx_ifft(st->fft_table, st->Y, st->e); - for (i=0;iframe_size;i++) - st->e[i] = SUB16(st->input[i], st->e[i+st->frame_size]); - Sff = mdf_inner_prod(st->e, st->e, st->frame_size); + /* Compute foreground filter */ + spectral_mul_accum16(st->X, st->foreground+chan*N*K*M, st->Y+chan*N, N, M*K); + spx_ifft(st->fft_table, st->Y+chan*N, st->e+chan*N); + for (i=0;iframe_size;i++) + st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->e[chan*N+i+st->frame_size]); + Sff += mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size); #endif - + } + /* Adjust proportional adaption rate */ - mdf_adjust_prop (st->W, N, M, st->prop); + /* FIXME: Adjust that for C, K*/ + if (st->adapted) + mdf_adjust_prop (st->W, N, M, C*K, st->prop); /* Compute weight gradient */ if (st->saturated == 0) { - for (j=M-1;j>=0;j--) + for (chan = 0; chan < C; chan++) { - weighted_spectral_mul_conj(st->power_1, FLOAT_SHL(PSEUDOFLOAT(st->prop[j]),-15), &st->X[(j+1)*N], st->E, st->PHI, N); - for (i=0;iW[j*N+i] = ADD32(st->W[j*N+i], st->PHI[i]); - + for (speak = 0; speak < K; speak++) + { + for (j=M-1;j>=0;j--) + { + weighted_spectral_mul_conj(st->power_1, FLOAT_SHL(PSEUDOFLOAT(st->prop[j]),-15), &st->X[(j+1)*N*K+speak*N], st->E+chan*N, st->PHI, N); + for (i=0;iW[chan*N*K*M + j*N*K + speak*N + i] += st->PHI[i]; + } + } } } else { st->saturated--; } - + + /* FIXME: MC conversion required */ /* Update weight to prevent circular convolution (MDF / AUMDF) */ - for (j=0;jcancel_count%(M-1) == j-1) + for (speak = 0; speak < K; speak++) { -#ifdef FIXED_POINT - for (i=0;iwtmp2[i] = EXTRACT16(PSHR32(st->W[j*N+i],NORMALIZE_SCALEDOWN+16)); - spx_ifft(st->fft_table, st->wtmp2, st->wtmp); - for (i=0;iframe_size;i++) + for (j=0;jwtmp[i]=0; - } - for (i=st->frame_size;iwtmp[i]=SHL16(st->wtmp[i],NORMALIZE_SCALEUP); - } - spx_fft(st->fft_table, st->wtmp, st->wtmp2); - /* The "-1" in the shift is a sort of kludge that trades less efficient update speed for decrease noise */ - for (i=0;iW[j*N+i] -= SHL32(EXTEND32(st->wtmp2[i]),16+NORMALIZE_SCALEDOWN-NORMALIZE_SCALEUP-1); + /* This is a variant of the Alternatively Updated MDF (AUMDF) */ + /* Remove the "if" to make this an MDF filter */ + if (j==0 || st->cancel_count%(M-1) == j-1) + { +#ifdef FIXED_POINT + for (i=0;iwtmp2[i] = EXTRACT16(PSHR32(st->W[chan*N*K*M + j*N*K + speak*N + i],NORMALIZE_SCALEDOWN+16)); + spx_ifft(st->fft_table, st->wtmp2, st->wtmp); + for (i=0;iframe_size;i++) + { + st->wtmp[i]=0; + } + for (i=st->frame_size;iwtmp[i]=SHL16(st->wtmp[i],NORMALIZE_SCALEUP); + } + spx_fft(st->fft_table, st->wtmp, st->wtmp2); + /* The "-1" in the shift is a sort of kludge that trades less efficient update speed for decrease noise */ + for (i=0;iW[chan*N*K*M + j*N*K + speak*N + i] -= SHL32(EXTEND32(st->wtmp2[i]),16+NORMALIZE_SCALEDOWN-NORMALIZE_SCALEUP-1); #else - spx_ifft(st->fft_table, &st->W[j*N], st->wtmp); - for (i=st->frame_size;iwtmp[i]=0; - } - spx_fft(st->fft_table, st->wtmp, &st->W[j*N]); + spx_ifft(st->fft_table, &st->W[chan*N*K*M + j*N*K + speak*N], st->wtmp); + for (i=st->frame_size;iwtmp[i]=0; + } + spx_fft(st->fft_table, st->wtmp, &st->W[chan*N*K*M + j*N*K + speak*N]); #endif + } + } } } - /* Compute filter response Y */ - spectral_mul_accum(st->X, st->W, st->Y, N, M); - spx_ifft(st->fft_table, st->Y, st->y); + /* So we can use power_spectrum_accum */ + for (i=0;i<=st->frame_size;i++) + st->Rf[i] = st->Yf[i] = st->Xf[i] = 0; + Dbf = 0; + See = 0; #ifdef TWO_PATH /* Difference in response, this is used to estimate the variance of our residual power estimate */ - for (i=0;iframe_size;i++) - st->e[i] = SUB16(st->e[i+st->frame_size], st->y[i+st->frame_size]); - Dbf = 10+mdf_inner_prod(st->e, st->e, st->frame_size); + for (chan = 0; chan < C; chan++) + { + spectral_mul_accum(st->X, st->W+chan*N*K*M, st->Y+chan*N, N, M*K); + spx_ifft(st->fft_table, st->Y+chan*N, st->y+chan*N); + for (i=0;iframe_size;i++) + st->e[chan*N+i] = SUB16(st->e[chan*N+i+st->frame_size], st->y[chan*N+i+st->frame_size]); + Dbf += 10+mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size); + for (i=0;iframe_size;i++) + st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->y[chan*N+i+st->frame_size]); + See += mdf_inner_prod(st->e+chan*N, st->e+chan*N, st->frame_size); + } #endif - for (i=0;iframe_size;i++) - st->e[i] = SUB16(st->input[i], st->y[i+st->frame_size]); - See = mdf_inner_prod(st->e, st->e, st->frame_size); #ifndef TWO_PATH Sff = See; #endif #ifdef TWO_PATH /* Logic for updating the foreground filter */ - + /* For two time windows, compute the mean of the energy difference, as well as the variance */ st->Davg1 = ADD32(MULT16_32_Q15(QCONST16(.6f,15),st->Davg1), MULT16_32_Q15(QCONST16(.4f,15),SUB32(Sff,See))); st->Davg2 = ADD32(MULT16_32_Q15(QCONST16(.85f,15),st->Davg2), MULT16_32_Q15(QCONST16(.15f,15),SUB32(Sff,See))); st->Dvar1 = FLOAT_ADD(FLOAT_MULT(VAR1_SMOOTH, st->Dvar1), FLOAT_MUL32U(MULT16_32_Q15(QCONST16(.4f,15),Sff), MULT16_32_Q15(QCONST16(.4f,15),Dbf))); st->Dvar2 = FLOAT_ADD(FLOAT_MULT(VAR2_SMOOTH, st->Dvar2), FLOAT_MUL32U(MULT16_32_Q15(QCONST16(.15f,15),Sff), MULT16_32_Q15(QCONST16(.15f,15),Dbf))); - + /* Equivalent float code: st->Davg1 = .6*st->Davg1 + .4*(Sff-See); st->Davg2 = .85*st->Davg2 + .15*(Sff-See); st->Dvar1 = .36*st->Dvar1 + .16*Sff*Dbf; st->Dvar2 = .7225*st->Dvar2 + .0225*Sff*Dbf; */ - + update_foreground = 0; /* Check if we have a statistically significant reduction in the residual echo */ /* Note that this is *not* Gaussian, so we need to be careful about the longer tail */ @@ -830,18 +920,19 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp update_foreground = 1; else if (FLOAT_GT(FLOAT_MUL32U(st->Davg2, ABS32(st->Davg2)), FLOAT_MULT(VAR2_UPDATE,(st->Dvar2)))) update_foreground = 1; - + /* Do we update? */ if (update_foreground) { st->Davg1 = st->Davg2 = 0; st->Dvar1 = st->Dvar2 = FLOAT_ZERO; /* Copy background filter to foreground filter */ - for (i=0;iforeground[i] = EXTRACT16(PSHR32(st->W[i],16)); /* Apply a smooth transition so as to not introduce blocking artifacts */ - for (i=0;iframe_size;i++) - st->e[i+st->frame_size] = MULT16_16_Q15(st->window[i+st->frame_size],st->e[i+st->frame_size]) + MULT16_16_Q15(st->window[i],st->y[i+st->frame_size]); + for (chan = 0; chan < C; chan++) + for (i=0;iframe_size;i++) + st->e[chan*N+i+st->frame_size] = MULT16_16_Q15(st->window[i+st->frame_size],st->e[chan*N+i+st->frame_size]) + MULT16_16_Q15(st->window[i],st->y[chan*N+i+st->frame_size]); } else { int reset_background=0; /* Otherwise, check if the background filter is significantly worse */ @@ -854,13 +945,16 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp if (reset_background) { /* Copy foreground filter to background filter */ - for (i=0;iW[i] = SHL32(EXTEND32(st->foreground[i]),16); /* We also need to copy the output so as to get correct adaptation */ - for (i=0;iframe_size;i++) - st->y[i+st->frame_size] = st->e[i+st->frame_size]; - for (i=0;iframe_size;i++) - st->e[i] = SUB16(st->input[i], st->y[i+st->frame_size]); + for (chan = 0; chan < C; chan++) + { + for (i=0;iframe_size;i++) + st->y[chan*N+i+st->frame_size] = st->e[chan*N+i+st->frame_size]; + for (i=0;iframe_size;i++) + st->e[chan*N+i] = SUB16(st->input[chan*st->frame_size+i], st->y[chan*N+i+st->frame_size]); + } See = Sff; st->Davg1 = st->Davg2 = 0; st->Dvar1 = st->Dvar2 = FLOAT_ZERO; @@ -868,50 +962,60 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp } #endif - /* Compute error signal (for the output with de-emphasis) */ - for (i=0;iframe_size;i++) + Sey = Syy = Sdd = 0; + for (chan = 0; chan < C; chan++) { - spx_word32_t tmp_out; + /* Compute error signal (for the output with de-emphasis) */ + for (i=0;iframe_size;i++) + { + spx_word32_t tmp_out; #ifdef TWO_PATH - tmp_out = SUB32(EXTEND32(st->input[i]), EXTEND32(st->e[i+st->frame_size])); + tmp_out = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(st->e[chan*N+i+st->frame_size])); #else - tmp_out = SUB32(EXTEND32(st->input[i]), EXTEND32(st->y[i+st->frame_size])); + tmp_out = SUB32(EXTEND32(st->input[chan*st->frame_size+i]), EXTEND32(st->y[chan*N+i+st->frame_size])); #endif - /* Saturation */ - if (tmp_out>32767) - tmp_out = 32767; - else if (tmp_out<-32768) - tmp_out = -32768; - tmp_out = ADD32(tmp_out, EXTEND32(MULT16_16_P15(st->preemph, st->memE))); + tmp_out = ADD32(tmp_out, EXTEND32(MULT16_16_P15(st->preemph, st->memE[chan]))); /* This is an arbitrary test for saturation in the microphone signal */ - if (in[i] <= -32000 || in[i] >= 32000) - { - tmp_out = 0; + if (in[i*C+chan] <= -32000 || in[i*C+chan] >= 32000) + { if (st->saturated == 0) st->saturated = 1; + } + out[i*C+chan] = WORD2INT(tmp_out); + st->memE[chan] = tmp_out; } - out[i] = (spx_int16_t)tmp_out; - st->memE = tmp_out; - } - + #ifdef DUMP_ECHO_CANCEL_DATA - dump_audio(in, far_end, out, st->frame_size); + dump_audio(in, far_end, out, st->frame_size); #endif - - /* Compute error signal (filter update version) */ - for (i=0;iframe_size;i++) - { - st->e[i+st->frame_size] = st->e[i]; - st->e[i] = 0; + + /* Compute error signal (filter update version) */ + for (i=0;iframe_size;i++) + { + st->e[chan*N+i+st->frame_size] = st->e[chan*N+i]; + st->e[chan*N+i] = 0; + } + + /* Compute a bunch of correlations */ + /* FIXME: bad merge */ + Sey += mdf_inner_prod(st->e+chan*N+st->frame_size, st->y+chan*N+st->frame_size, st->frame_size); + Syy += mdf_inner_prod(st->y+chan*N+st->frame_size, st->y+chan*N+st->frame_size, st->frame_size); + Sdd += mdf_inner_prod(st->input+chan*st->frame_size, st->input+chan*st->frame_size, st->frame_size); + + /* Convert error to frequency domain */ + spx_fft(st->fft_table, st->e+chan*N, st->E+chan*N); + for (i=0;iframe_size;i++) + st->y[i+chan*N] = 0; + spx_fft(st->fft_table, st->y+chan*N, st->Y+chan*N); + + /* Compute power spectrum of echo (X), error (E) and filter response (Y) */ + power_spectrum_accum(st->E+chan*N, st->Rf, N); + power_spectrum_accum(st->Y+chan*N, st->Yf, N); + } - /* Compute a bunch of correlations */ - Sey = mdf_inner_prod(st->e+st->frame_size, st->y+st->frame_size, st->frame_size); - Syy = mdf_inner_prod(st->y+st->frame_size, st->y+st->frame_size, st->frame_size); - Sdd = mdf_inner_prod(st->input, st->input, st->frame_size); - /*printf ("%f %f %f %f\n", Sff, See, Syy, Sdd, st->update_cond);*/ - + /* Do some sanity check */ if (!(Syy>=0 && Sxx>=0 && See >= 0) #ifndef FIXED_POINT @@ -921,7 +1025,7 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp { /* Things have gone really bad */ st->screwed_up += 50; - for (i=0;iframe_size;i++) + for (i=0;iframe_size*C;i++) out[i] = 0; } else if (SHR32(Sff, 2) > ADD32(Sdd, SHR32(MULT16_16(N, 10000),6))) { @@ -941,35 +1045,16 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp /* Add a small noise floor to make sure not to have problems when dividing */ See = MAX32(See, SHR32(MULT16_16(N, 100),6)); - /* Convert error to frequency domain */ - spx_fft(st->fft_table, st->e, st->E); - for (i=0;iframe_size;i++) - st->y[i] = 0; - spx_fft(st->fft_table, st->y, st->Y); + for (speak = 0; speak < K; speak++) + { + Sxx += mdf_inner_prod(st->x+speak*N+st->frame_size, st->x+speak*N+st->frame_size, st->frame_size); + power_spectrum_accum(st->X+speak*N, st->Xf, N); + } + - /* Compute power spectrum of far end (X), error (E) and filter response (Y) */ - power_spectrum(st->E, st->Rf, N); - power_spectrum(st->Y, st->Yf, N); - power_spectrum(st->X, st->Xf, N); - /* Smooth far end energy estimate over time */ for (j=0;j<=st->frame_size;j++) st->power[j] = MULT16_32_Q15(ss_1,st->power[j]) + 1 + MULT16_32_Q15(ss,st->Xf[j]); - - /* Enable this to compute the power based only on the tail (would need to compute more - efficiently to make this really useful */ - if (0) - { - float scale2 = .5f/M; - for (j=0;j<=st->frame_size;j++) - st->power[j] = 100; - for (i=0;iX[i*N], st->Xf, N); - for (j=0;j<=st->frame_size;j++) - st->power[j] += scale2*st->Xf[j]; - } - } /* Compute filtered spectra and (cross-)correlations */ for (j=st->frame_size;j>=0;j--) @@ -987,7 +1072,7 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp st->Yh[j] = (1-st->spec_average)*st->Yh[j] + st->spec_average*st->Yf[j]; #endif } - + Pyy = FLOAT_SQRT(Pyy); Pey = FLOAT_DIVU(Pey,Pyy); @@ -1015,7 +1100,7 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp else st->leak_estimate = SHL16(st->leak_estimate,1); /*printf ("%f\n", st->leak_estimate);*/ - + /* Compute Residual to Error Ratio */ #ifdef FIXED_POINT tmp32 = MULT16_32_Q15(st->leak_estimate,Syy); @@ -1071,7 +1156,7 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp /* Temporary adaption rate if filter is not yet adapted enough */ spx_word16_t adapt_rate=0; - if (Sxx > SHR32(MULT16_16(N, 1000),6)) + if (Sxx > SHR32(MULT16_16(N, 1000),6)) { tmp32 = MULT16_32_Q15(QCONST16(.25f, 15), Sxx); #ifdef FIXED_POINT @@ -1091,12 +1176,12 @@ void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *in, const sp st->sum_adapt = ADD32(st->sum_adapt,adapt_rate); } - /* Save residual echo so it can be used by the nonlinear processor */ + /* FIXME: MC conversion required */ + for (i=0;iframe_size;i++) + st->last_y[i] = st->last_y[st->frame_size+i]; if (st->adapted) { /* If the filter is adapted, take the filtered echo */ - for (i=0;iframe_size;i++) - st->last_y[i] = st->last_y[st->frame_size+i]; for (i=0;iframe_size;i++) st->last_y[st->frame_size+i] = in[i]-out[i]; } else { @@ -1113,17 +1198,17 @@ void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *residual_echo, in int i; spx_word16_t leak2; int N; - + N = st->window_size; /* Apply hanning window (should pre-compute it)*/ for (i=0;iy[i] = MULT16_16_Q15(st->window[i],st->last_y[i]); - + /* Compute power spectrum of the echo */ spx_fft(st->fft_table, st->y, st->Y); power_spectrum(st->Y, residual_echo, N); - + #ifdef FIXED_POINT if (st->leak_estimate > 16383) leak2 = 32767; @@ -1138,14 +1223,14 @@ void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *residual_echo, in /* Estimate residual echo */ for (i=0;i<=st->frame_size;i++) residual_echo[i] = (spx_int32_t)MULT16_32_Q15(leak2,residual_echo[i]); - + } -int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr) +EXPORT int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr) { switch(request) { - + case SPEEX_ECHO_GET_FRAME_SIZE: (*(int*)ptr) = st->frame_size; break; @@ -1169,6 +1254,29 @@ int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr) case SPEEX_ECHO_GET_SAMPLING_RATE: (*(int*)ptr) = st->sampling_rate; break; + case SPEEX_ECHO_GET_IMPULSE_RESPONSE_SIZE: + /*FIXME: Implement this for multiple channels */ + *((spx_int32_t *)ptr) = st->M * st->frame_size; + break; + case SPEEX_ECHO_GET_IMPULSE_RESPONSE: + { + int M = st->M, N = st->window_size, n = st->frame_size, i, j; + spx_int32_t *filt = (spx_int32_t *) ptr; + for(j=0;jwtmp2[i] = EXTRACT16(PSHR32(st->W[j*N+i],16+NORMALIZE_SCALEDOWN)); + spx_ifft(st->fft_table, st->wtmp2, st->wtmp); +#else + spx_ifft(st->fft_table, &st->W[j*N], st->wtmp); +#endif + for(i=0;iwtmp[i]), WEIGHT_SHIFT-NORMALIZE_SCALEDOWN); + } + } + break; default: speex_warning_int("Unknown speex_echo_ctl request: ", request); return -1; diff --git a/lib/rbcodec/codecs/libspeex/modes.c b/lib/rbcodec/codecs/libspeex/modes.c index a58c0786dd..881ff91368 100644 --- a/lib/rbcodec/codecs/libspeex/modes.c +++ b/lib/rbcodec/codecs/libspeex/modes.c @@ -450,7 +450,7 @@ static const SpeexNBMode nb_mode = { /* Default mode for narrowband */ -const SpeexMode speex_nb_mode = { +EXPORT const SpeexMode speex_nb_mode = { &nb_mode, nb_mode_query, "narrowband", @@ -479,8 +479,12 @@ const SpeexMode speex_nb_mode = { -int speex_mode_query(const SpeexMode *mode, int request, void *ptr) +EXPORT int speex_mode_query(const SpeexMode *mode, int request, void *ptr) { return mode->query(mode->mode, request, ptr); } +#ifdef FIXED_DEBUG +long long spx_mips=0; +#endif + diff --git a/lib/rbcodec/codecs/libspeex/modes_wb.c b/lib/rbcodec/codecs/libspeex/modes_wb.c index 5438551c1b..4fe1ef08fc 100644 --- a/lib/rbcodec/codecs/libspeex/modes_wb.c +++ b/lib/rbcodec/codecs/libspeex/modes_wb.c @@ -55,9 +55,9 @@ #endif #ifndef ROCKBOX_VOICE_CODEC -const SpeexMode * const speex_mode_list[SPEEX_NB_MODES] = {&speex_nb_mode, &speex_wb_mode, &speex_uwb_mode}; +EXPORT const SpeexMode * const speex_mode_list[SPEEX_NB_MODES] = {&speex_nb_mode, &speex_wb_mode, &speex_uwb_mode}; #else -const SpeexMode * const speex_mode_list[SPEEX_NB_MODES] = {&speex_nb_mode, &speex_wb_mode, NULL}; +EXPORT const SpeexMode * const speex_mode_list[SPEEX_NB_MODES] = {&speex_nb_mode, &speex_wb_mode, NULL}; #endif extern const signed char hexc_table[]; @@ -250,7 +250,7 @@ static const SpeexSBMode sb_wb_mode = { }; -const SpeexMode speex_wb_mode = { +EXPORT const SpeexMode speex_wb_mode = { &sb_wb_mode, wb_mode_query, "wideband (sub-band CELP)", @@ -285,7 +285,7 @@ const SpeexMode speex_wb_mode = { #ifndef ROCKBOX_VOICE_CODEC /* Split-band "ultra-wideband" (32 kbps) CELP mode*/ -static const SpeexSBMode sb_uwb_mode = { +EXPORT static const SpeexSBMode sb_uwb_mode = { &speex_wb_mode, 320, /*frameSize*/ 80, /*subframeSize*/ @@ -365,7 +365,7 @@ const SpeexMode speex_uwb_mode = { /* We have defined speex_lib_get_mode() as a macro in speex.h */ #undef speex_lib_get_mode -const SpeexMode * speex_lib_get_mode (int mode) +EXPORT const SpeexMode * speex_lib_get_mode (int mode) { if (mode < 0 || mode >= SPEEX_NB_MODES) return NULL; diff --git a/lib/rbcodec/codecs/libspeex/preprocess.c b/lib/rbcodec/codecs/libspeex/preprocess.c index 07a2ad3479..58d213a0a9 100644 --- a/lib/rbcodec/codecs/libspeex/preprocess.c +++ b/lib/rbcodec/codecs/libspeex/preprocess.c @@ -1,6 +1,6 @@ /* Copyright (C) 2003 Epic Games (written by Jean-Marc Valin) - Copyright (C) 2004-2006 Epic Games - + Copyright (C) 2004-2006 Epic Games + File: preprocess.c Preprocessor with denoising based on the algorithm by Ephraim and Malah @@ -34,24 +34,24 @@ /* Recommended papers: - + Y. Ephraim and D. Malah, "Speech enhancement using minimum mean-square error - short-time spectral amplitude estimator". IEEE Transactions on Acoustics, + short-time spectral amplitude estimator". IEEE Transactions on Acoustics, Speech and Signal Processing, vol. ASSP-32, no. 6, pp. 1109-1121, 1984. - + Y. Ephraim and D. Malah, "Speech enhancement using minimum mean-square error - log-spectral amplitude estimator". IEEE Transactions on Acoustics, Speech and + log-spectral amplitude estimator". IEEE Transactions on Acoustics, Speech and Signal Processing, vol. ASSP-33, no. 2, pp. 443-445, 1985. - + I. Cohen and B. Berdugo, "Speech enhancement for non-stationary noise environments". Signal Processing, vol. 81, no. 2, pp. 2403-2418, 2001. - Stefan Gustafsson, Rainer Martin, Peter Jax, and Peter Vary. "A psychoacoustic - approach to combined acoustic echo cancellation and noise reduction". IEEE + Stefan Gustafsson, Rainer Martin, Peter Jax, and Peter Vary. "A psychoacoustic + approach to combined acoustic echo cancellation and noise reduction". IEEE Transactions on Speech and Audio Processing, 2002. - + J.-M. Valin, J. Rouat, and F. Michaud, "Microphone array post-filter for separation - of simultaneous non-stationary sources". In Proceedings IEEE International + of simultaneous non-stationary sources". In Proceedings IEEE International Conference on Acoustics, Speech, and Signal Processing, 2004. */ @@ -75,7 +75,7 @@ #define LOUDNESS_EXP 5.f #define AMP_SCALE .001f #define AMP_SCALE_1 1000.f - + #define NB_BANDS 24 #define SPEECH_PROB_START_DEFAULT QCONST16(0.35f,15) @@ -117,7 +117,7 @@ static inline spx_word16_t DIV32_16_Q8(spx_word32_t a, spx_word32_t b) a = SHL32(a,8); return PDIV32_16(a,b); } - + } static inline spx_word16_t DIV32_16_Q15(spx_word32_t a, spx_word32_t b) { @@ -185,7 +185,7 @@ struct SpeexPreprocessState_ { int sampling_rate; /**< Sampling rate of the input/output */ int nbands; FilterBank *bank; - + /* Parameters */ int denoise_enabled; int vad_enabled; @@ -198,7 +198,9 @@ struct SpeexPreprocessState_ { int echo_suppress; int echo_suppress_active; SpeexEchoState *echo_state; - + + spx_word16_t speech_prob; /**< Probability last frame was speech */ + /* DSP-related arrays */ spx_word16_t *frame; /**< Processing frame (2*ps_size) */ spx_word16_t *ft; /**< Processing frame in freq domain (2*ps_size) */ @@ -234,7 +236,6 @@ struct SpeexPreprocessState_ { float *loudness_weight; /**< Perceptual loudness curve */ float loudness; /**< Loudness estimate */ float agc_gain; /**< Current AGC gain */ - int nb_loudness_adapt; /**< Number of frames used for loudness adaptation so far */ float max_gain; /**< Maximum gain allowed */ float max_increase_step; /**< Maximum increase in gain from one frame to another */ float max_decrease_step; /**< Maximum decrease in gain from one frame to another */ @@ -259,7 +260,7 @@ static void conj_window(spx_word16_t *w, int len) spx_word16_t tmp; #ifdef FIXED_POINT spx_word16_t x = DIV32_16(MULT16_16(32767,i),len); -#else +#else spx_word16_t x = DIV32_16(MULT16_16(QCONST16(4.f,13),i),len); #endif int inv=0; @@ -284,10 +285,10 @@ static void conj_window(spx_word16_t *w, int len) } } - + #ifdef FIXED_POINT -/* This function approximates the gain function - y = gamma(1.25)^2 * M(-.25;1;-x) / sqrt(x) +/* This function approximates the gain function + y = gamma(1.25)^2 * M(-.25;1;-x) / sqrt(x) which multiplied by xi/(1+xi) is the optimal gain in the loudness domain ( sqrt[amplitude] ) Input in Q11 format, output in Q15 @@ -320,7 +321,7 @@ static inline spx_word16_t qcurve(spx_word16_t x) static void compute_gain_floor(int noise_suppress, int effective_echo_suppress, spx_word32_t *noise, spx_word32_t *echo, spx_word16_t *gain_floor, int len) { int i; - + if (noise_suppress > effective_echo_suppress) { spx_word16_t noise_gain, gain_ratio; @@ -346,8 +347,8 @@ static void compute_gain_floor(int noise_suppress, int effective_echo_suppress, } #else -/* This function approximates the gain function - y = gamma(1.25)^2 * M(-.25;1;-x) / sqrt(x) +/* This function approximates the gain function + y = gamma(1.25)^2 * M(-.25;1;-x) / sqrt(x) which multiplied by xi/(1+xi) is the optimal gain in the loudness domain ( sqrt[amplitude] ) */ @@ -391,7 +392,7 @@ static void compute_gain_floor(int noise_suppress, int effective_echo_suppress, } #endif -SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_rate) +EXPORT SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_rate) { int i; int N, N3, N4, M; @@ -413,8 +414,8 @@ SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_r break; } } - - + + if (st->ps_size < 3*st->frame_size/4) st->ps_size = st->ps_size * 3 / 2; #else @@ -424,7 +425,7 @@ SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_r N = st->ps_size; N3 = 2*N - st->frame_size; N4 = st->frame_size - N3; - + st->sampling_rate = sampling_rate; st->denoise_enabled = 1; st->vad_enabled = 0; @@ -439,15 +440,15 @@ SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_r st->speech_prob_continue = SPEECH_PROB_CONTINUE_DEFAULT; st->echo_state = NULL; - + st->nbands = NB_BANDS; M = st->nbands; st->bank = filterbank_new(M, sampling_rate, N, 1); - + st->frame = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t)); st->window = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t)); st->ft = (spx_word16_t*)speex_alloc(2*N*sizeof(spx_word16_t)); - + st->ps = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); st->noise = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); st->echo_noise = (spx_word32_t*)speex_alloc((N+M)*sizeof(spx_word32_t)); @@ -460,19 +461,19 @@ SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_r st->gain2 = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); st->gain_floor = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); st->zeta = (spx_word16_t*)speex_alloc((N+M)*sizeof(spx_word16_t)); - + st->S = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); st->Smin = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); st->Stmp = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t)); st->update_prob = (int*)speex_alloc(N*sizeof(int)); - + st->inbuf = (spx_word16_t*)speex_alloc(N3*sizeof(spx_word16_t)); st->outbuf = (spx_word16_t*)speex_alloc(N3*sizeof(spx_word16_t)); conj_window(st->window, 2*N3); for (i=2*N3;i<2*st->ps_size;i++) st->window[i]=Q15_ONE; - + if (N4>0) { for (i=N3-1;i>=0;i--) @@ -514,7 +515,6 @@ SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_r /*st->loudness = pow(AMP_SCALE*st->agc_level,LOUDNESS_EXP);*/ st->loudness = 1e-15; st->agc_gain = 1; - st->nb_loudness_adapt = 0; st->max_gain = 30; st->max_increase_step = exp(0.11513f * 12.*st->frame_size / st->sampling_rate); st->max_decrease_step = exp(-0.11513f * 40.*st->frame_size / st->sampling_rate); @@ -530,7 +530,7 @@ SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_r return st; } -void speex_preprocess_state_destroy(SpeexPreprocessState *st) +EXPORT void speex_preprocess_state_destroy(SpeexPreprocessState *st) { speex_free(st->frame); speex_free(st->ft); @@ -573,7 +573,7 @@ static void speex_compute_agc(SpeexPreprocessState *st, spx_word16_t Pframe, spx float target_gain; float loudness=1.f; float rate; - + for (i=2;ips[i]* st->loudness_weight[i]; @@ -583,7 +583,6 @@ static void speex_compute_agc(SpeexPreprocessState *st, spx_word16_t Pframe, spx loudness*2 > pow(st->loudness, 1.0/LOUDNESS_EXP))*/ if (Pframe>.3f) { - st->nb_loudness_adapt++; /*rate=2.0f*Pframe*Pframe/(1+st->nb_loudness_adapt);*/ rate = .03*Pframe*Pframe; st->loudness = (1-rate)*st->loudness + (rate)*pow(AMP_SCALE*loudness, LOUDNESS_EXP); @@ -592,7 +591,7 @@ static void speex_compute_agc(SpeexPreprocessState *st, spx_word16_t Pframe, spx st->init_max *= 1.f + .1f*Pframe*Pframe; } /*printf ("%f %f %f %f\n", Pframe, loudness, pow(st->loudness, 1.0f/LOUDNESS_EXP), st->loudness2);*/ - + target_gain = AMP_SCALE*st->agc_level*pow(st->loudness/(1e-4+st->loudness_accum), -1.0f/LOUDNESS_EXP); if ((Pframe>.5 && st->nb_adapt > 20) || target_gain < st->agc_gain) @@ -605,11 +604,11 @@ static void speex_compute_agc(SpeexPreprocessState *st, spx_word16_t Pframe, spx target_gain = st->max_gain; if (target_gain > st->init_max) target_gain = st->init_max; - + st->agc_gain = target_gain; } /*fprintf (stderr, "%f %f %f\n", loudness, (float)AMP_SCALE_1*pow(st->loudness, 1.0f/LOUDNESS_EXP), st->agc_gain);*/ - + for (i=0;i<2*N;i++) ft[i] *= st->agc_gain; st->prev_loudness = loudness; @@ -629,7 +628,7 @@ static void preprocess_analysis(SpeexPreprocessState *st, spx_int16_t *x) st->frame[i]=st->inbuf[i]; for (i=0;iframe_size;i++) st->frame[N3+i]=x[i]; - + /* Update inbuf */ for (i=0;iinbuf[i]=x[N4+i]; @@ -648,10 +647,10 @@ static void preprocess_analysis(SpeexPreprocessState *st, spx_int16_t *x) st->frame[i] = SHL16(st->frame[i], st->frame_shift); } #endif - + /* Perform FFT */ spx_fft(st->fft_lookup, st->frame, st->ft); - + /* Power spectrum */ ps[0]=MULT16_16(st->ft[0],st->ft[0]); for (i=1;ips_size; for (i=1;iS[i] = MULT16_32_Q15(QCONST16(.8f,15),st->S[i]) + MULT16_32_Q15(QCONST16(.05f,15),st->ps[i-1]) + st->S[i] = MULT16_32_Q15(QCONST16(.8f,15),st->S[i]) + MULT16_32_Q15(QCONST16(.05f,15),st->ps[i-1]) + MULT16_32_Q15(QCONST16(.1f,15),st->ps[i]) + MULT16_32_Q15(QCONST16(.05f,15),st->ps[i+1]); st->S[0] = MULT16_32_Q15(QCONST16(.8f,15),st->S[0]) + MULT16_32_Q15(QCONST16(.2f,15),st->ps[0]); st->S[N-1] = MULT16_32_Q15(QCONST16(.8f,15),st->S[N-1]) + MULT16_32_Q15(QCONST16(.2f,15),st->ps[N-1]); - + if (st->nb_adapt==1) { for (i=0;iSmin[i] = MIN32(st->Smin[i], st->S[i]); - st->Stmp[i] = MIN32(st->Stmp[i], st->S[i]); + st->Stmp[i] = MIN32(st->Stmp[i], st->S[i]); } } for (i=0;iS[i]) > ADD32(st->Smin[i],EXTEND32(20))) + if (MULT16_32_Q15(QCONST16(.4f,15),st->S[i]) > st->Smin[i]) st->update_prob[i] = 1; else st->update_prob[i] = 0; @@ -719,12 +718,12 @@ static void update_noise_prob(SpeexPreprocessState *st) void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *Yout, int len); -int speex_preprocess(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo) +EXPORT int speex_preprocess(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo) { return speex_preprocess_run(st, x); } -int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) +EXPORT int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) { int i; int M; @@ -736,12 +735,12 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) spx_word16_t Pframe; spx_word16_t beta, beta_1; spx_word16_t effective_echo_suppress; - + st->nb_adapt++; if (st->nb_adapt>20000) st->nb_adapt = 20000; st->min_count++; - + beta = MAX16(QCONST16(.03,15),DIV32_16(Q15_ONE,st->nb_adapt)); beta_1 = Q15_ONE-beta; M = st->nbands; @@ -775,7 +774,7 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) st->update_prob[i] = 0; } */ - + /* Update the noise estimate for the frequencies where it can be */ for (i=0;inoise[i],NOISE_SHIFT)) , st->echo_noise[i]) , st->reverb_estimate[i]); - + /* A posteriori SNR = ps/noise - 1*/ st->post[i] = SUB16(DIV32_16_Q8(ps[i],tot_noise), QCONST16(1.f,SNR_SHIFT)); st->post[i]=MIN16(st->post[i], QCONST16(100.f,SNR_SHIFT)); - + /* Computing update gamma = .1 + .9*(old/(old+noise))^2 */ gamma = QCONST16(.1f,15)+MULT16_16_Q15(QCONST16(.89f,15),SQR16_Q15(DIV32_16_Q15(st->old_ps[i],ADD32(st->old_ps[i],tot_noise)))); - + /* A priori SNR update = gamma*max(0,post) + (1-gamma)*old/noise */ st->prior[i] = EXTRACT16(PSHR32(ADD32(MULT16_16(gamma,MAX16(0,st->post[i])), MULT16_16(Q15_ONE-gamma,DIV32_16_Q8(st->old_ps[i],tot_noise))), 15)); st->prior[i]=MIN16(st->prior[i], QCONST16(100.f,SNR_SHIFT)); @@ -824,13 +823,13 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) for (i=N;izeta[i])); Pframe = QCONST16(.1f,15)+MULT16_16_Q15(QCONST16(.899f,15),qcurve(DIV32_16(Zframe,st->nbands))); - + effective_echo_suppress = EXTRACT16(PSHR32(ADD32(MULT16_16(SUB16(Q15_ONE,Pframe), st->echo_suppress), MULT16_16(Pframe, st->echo_suppress_active)),15)); - + compute_gain_floor(st->noise_suppress, effective_echo_suppress, st->noise+N, st->echo_noise+N, st->gain_floor+N, M); - - /* Compute Ephraim & Malah gain speech probability of presence for each critical band (Bark scale) - Technically this is actually wrong because the EM gaim assumes a slightly different probability + + /* Compute Ephraim & Malah gain speech probability of presence for each critical band (Bark scale) + Technically this is actually wrong because the EM gaim assumes a slightly different probability distribution */ for (i=N;iprior[i]), 15), ADD16(st->prior[i], SHL32(1,SNR_SHIFT))); theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(st->post[i]),EXPIN_SHIFT-SNR_SHIFT)); @@ -872,12 +871,12 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) /* Convert the EM gains and speech prob to linear frequency */ filterbank_compute_psd16(st->bank,st->gain2+N, st->gain2); filterbank_compute_psd16(st->bank,st->gain+N, st->gain); - + /* Use 1 for linear gain resolution (best) or 0 for Bark gain resolution (faster) */ if (1) { filterbank_compute_psd16(st->bank,st->gain_floor+N, st->gain_floor); - + /* Compute gain according to the Ephraim-Malah algorithm -- linear frequency */ for (i=0;iprior[i]), 15), ADD16(st->prior[i], SHL32(1,SNR_SHIFT))); theta = MULT16_32_P15(prior_ratio, QCONST32(1.f,EXPIN_SHIFT)+SHL32(EXTEND32(st->post[i]),EXPIN_SHIFT-SNR_SHIFT)); @@ -898,22 +897,22 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) g = EXTRACT16(MIN32(Q15_ONE, MULT16_32_Q15(prior_ratio, MM))); /* Interpolated speech probability of presence */ p = st->gain2[i]; - + /* Constrain the gain to be close to the Bark scale gain */ if (MULT16_16_Q15(QCONST16(.333f,15),g) > st->gain[i]) g = MULT16_16(3,st->gain[i]); st->gain[i] = g; - + /* Save old power spectrum */ st->old_ps[i] = MULT16_32_P15(QCONST16(.2f,15),st->old_ps[i]) + MULT16_32_P15(MULT16_16_P15(QCONST16(.8f,15),SQR16_Q15(st->gain[i])),ps[i]); - + /* Apply gain floor */ if (st->gain[i] < st->gain_floor[i]) st->gain[i] = st->gain_floor[i]; /* Exponential decay model for reverberation (unused) */ /*st->reverb_estimate[i] = st->reverb_decay*st->reverb_estimate[i] + st->reverb_decay*st->reverb_level*st->gain[i]*st->gain[i]*st->ps[i];*/ - + /* Take into account speech probability of presence (loudness domain MMSE estimator) */ /* gain2 = [p*sqrt(gain)+(1-p)*sqrt(gain _floor) ]^2 */ tmp = MULT16_16_P15(p,spx_sqrt(SHL32(EXTEND32(st->gain[i]),15))) + MULT16_16_P15(SUB16(Q15_ONE,p),spx_sqrt(SHL32(EXTEND32(st->gain_floor[i]),15))); @@ -927,20 +926,20 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) { spx_word16_t tmp; spx_word16_t p = st->gain2[i]; - st->gain[i] = MAX16(st->gain[i], st->gain_floor[i]); + st->gain[i] = MAX16(st->gain[i], st->gain_floor[i]); tmp = MULT16_16_P15(p,spx_sqrt(SHL32(EXTEND32(st->gain[i]),15))) + MULT16_16_P15(SUB16(Q15_ONE,p),spx_sqrt(SHL32(EXTEND32(st->gain_floor[i]),15))); st->gain2[i]=SQR16_Q15(tmp); } filterbank_compute_psd16(st->bank,st->gain2+N, st->gain2); } - + /* If noise suppression is off, don't apply the gain (but then why call this in the first place!) */ if (!st->denoise_enabled) { for (i=0;igain2[i]=Q15_ONE; } - + /* Apply computed gain */ for (i=1;ift[0] = MULT16_16_P15(st->gain2[0],st->ft[0]); st->ft[2*N-1] = MULT16_16_P15(st->gain2[N-1],st->ft[2*N-1]); - + /*FIXME: This *will* not work for fixed-point */ #ifndef FIXED_POINT if (st->agc_enabled) @@ -978,7 +977,7 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) } } #endif - + /* Synthesis window (for WOLA) */ for (i=0;i<2*N;i++) st->frame[i] = MULT16_16_Q15(st->frame[i], st->window[i]); @@ -988,15 +987,16 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) x[i] = st->outbuf[i] + st->frame[i]; for (i=0;iframe[N3+i]; - + /* Update outbuf */ for (i=0;ioutbuf[i] = st->frame[st->frame_size+i]; /* FIXME: This VAD is a kludge */ + st->speech_prob = Pframe; if (st->vad_enabled) { - if (Pframe > st->speech_prob_start || (st->was_speech && Pframe > st->speech_prob_continue)) + if (st->speech_prob > st->speech_prob_start || (st->was_speech && st->speech_prob > st->speech_prob_continue)) { st->was_speech=1; return 1; @@ -1010,7 +1010,7 @@ int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x) } } -void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x) +EXPORT void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x) { int i; int N = st->ps_size; @@ -1020,11 +1020,11 @@ void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x) M = st->nbands; st->min_count++; - + preprocess_analysis(st, x); update_noise_prob(st); - + for (i=1;iupdate_prob[i] || st->ps[i] < PSHR32(st->noise[i],NOISE_SHIFT)) @@ -1045,7 +1045,7 @@ void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x) } -int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr) +EXPORT int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr) { int i; SpeexPreprocessState *st; @@ -1103,7 +1103,7 @@ int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr) case SPEEX_PREPROCESS_GET_VAD: (*(spx_int32_t*)ptr) = st->vad_enabled; break; - + case SPEEX_PREPROCESS_SET_DEREVERB: st->dereverb_enabled = (*(spx_int32_t*)ptr); for (i=0;ips_size;i++) @@ -1121,7 +1121,7 @@ int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr) /* FIXME: Re-enable when de-reverberation is actually enabled again */ /*(*(float*)ptr) = st->reverb_level;*/ break; - + case SPEEX_PREPROCESS_SET_DEREVERB_DECAY: /* FIXME: Re-enable when de-reverberation is actually enabled again */ /*st->reverb_decay = (*(float*)ptr);*/ @@ -1169,17 +1169,51 @@ int speex_preprocess_ctl(SpeexPreprocessState *state, int request, void *ptr) st->echo_state = (SpeexEchoState*)ptr; break; case SPEEX_PREPROCESS_GET_ECHO_STATE: - ptr = (void*)st->echo_state; + (*(SpeexEchoState**)ptr) = (SpeexEchoState*)st->echo_state; break; #ifndef FIXED_POINT case SPEEX_PREPROCESS_GET_AGC_LOUDNESS: (*(spx_int32_t*)ptr) = pow(st->loudness, 1.0/LOUDNESS_EXP); break; + case SPEEX_PREPROCESS_GET_AGC_GAIN: + (*(spx_int32_t*)ptr) = floor(.5+8.6858*log(st->agc_gain)); + break; +#endif + case SPEEX_PREPROCESS_GET_PSD_SIZE: + case SPEEX_PREPROCESS_GET_NOISE_PSD_SIZE: + (*(spx_int32_t*)ptr) = st->ps_size; + break; + case SPEEX_PREPROCESS_GET_PSD: + for(i=0;ips_size;i++) + ((spx_int32_t *)ptr)[i] = (spx_int32_t) st->ps[i]; + break; + case SPEEX_PREPROCESS_GET_NOISE_PSD: + for(i=0;ips_size;i++) + ((spx_int32_t *)ptr)[i] = (spx_int32_t) PSHR32(st->noise[i], NOISE_SHIFT); + break; + case SPEEX_PREPROCESS_GET_PROB: + (*(spx_int32_t*)ptr) = MULT16_16_Q15(st->speech_prob, 100); + break; +#ifndef FIXED_POINT + case SPEEX_PREPROCESS_SET_AGC_TARGET: + st->agc_level = (*(spx_int32_t*)ptr); + if (st->agc_level<1) + st->agc_level=1; + if (st->agc_level>32768) + st->agc_level=32768; + break; + case SPEEX_PREPROCESS_GET_AGC_TARGET: + (*(spx_int32_t*)ptr) = st->agc_level; + break; #endif - default: speex_warning_int("Unknown speex_preprocess_ctl request: ", request); return -1; } return 0; } + +#ifdef FIXED_DEBUG +long long spx_mips=0; +#endif + diff --git a/lib/rbcodec/codecs/libspeex/quant_lsp_bfin.h b/lib/rbcodec/codecs/libspeex/quant_lsp_bfin.h index 917047bb56..087b466b75 100644 --- a/lib/rbcodec/codecs/libspeex/quant_lsp_bfin.h +++ b/lib/rbcodec/codecs/libspeex/quant_lsp_bfin.h @@ -55,9 +55,9 @@ static int lsp_quant( __asm__ __volatile__ ( -" %0 = 1 (X);\n\t" /* %0: best_dist */ -" %0 <<= 30;\n\t" -" %1 = 0 (X);\n\t" /* %1: best_i */ +" %0 = 1 (X);\n\t" /* %0: best_dist */ +" %0 <<= 30;\n\t" +" %1 = 0 (X);\n\t" /* %1: best_i */ " P2 = %3\n\t" /* P2: ptr to cdbk */ " R5 = 0;\n\t" /* R5: best cb entry */ @@ -68,19 +68,19 @@ static int lsp_quant( " B0 = %2;\n\t" " R2.L = W [I0++];\n\t" -" LSETUP (lq1, lq2) LC0 = %4;\n\t" -"lq1: R3 = 0;\n\t" /* R3: dist */ -" LSETUP (lq3, lq4) LC1 = %5;\n\t" -"lq3: R1 = B [P2++] (X);\n\t" -" R1 <<= 5;\n\t" -" R0.L = R2.L - R1.L || R2.L = W [I0++];\n\t" -" R0 = R0.L*R0.L;\n\t" -"lq4: R3 = R3 + R0;\n\t" - -" cc =R3<%0;\n\t" -" if cc %0=R3;\n\t" -" if cc %1=R5;\n\t" -"lq2: R5 += 1;\n\t" +" LSETUP (1f, 2f) LC0 = %4;\n\t" +"1: R3 = 0;\n\t" /* R3: dist */ +" LSETUP (3f, 4f) LC1 = %5;\n\t" +"3: R1 = B [P2++] (X);\n\t" +" R1 <<= 5;\n\t" +" R0.L = R2.L - R1.L || R2.L = W [I0++];\n\t" +" R0 = R0.L*R0.L;\n\t" +"4: R3 = R3 + R0;\n\t" + +" cc =R3<%0;\n\t" +" if cc %0=R3;\n\t" +" if cc %1=R5;\n\t" +"2: R5 += 1;\n\t" " L0 = 0;\n\t" : "=&d" (best_dist), "=&d" (best_id) : "a" (x), "b" (cdbk), "a" (nbVec), "a" (nbDim) @@ -117,9 +117,9 @@ static int lsp_weight_quant( __asm__ __volatile__ ( -" %0 = 1 (X);\n\t" /* %0: best_dist */ -" %0 <<= 30;\n\t" -" %1 = 0 (X);\n\t" /* %1: best_i */ +" %0 = 1 (X);\n\t" /* %0: best_dist */ +" %0 <<= 30;\n\t" +" %1 = 0 (X);\n\t" /* %1: best_i */ " P2 = %4\n\t" /* P2: ptr to cdbk */ " R5 = 0;\n\t" /* R5: best cb entry */ @@ -128,27 +128,27 @@ static int lsp_weight_quant( " L0 = R0;\n\t" " L1 = R0;\n\t" " I0 = %2;\n\t" /* %2: &x[0] */ -" I1 = %3;\n\t" /* %3: &weight[0] */ +" I1 = %3;\n\t" /* %3: &weight[0] */ " B0 = %2;\n\t" -" B1 = %3;\n\t" +" B1 = %3;\n\t" -" LSETUP (lwq1, lwq2) LC0 = %5;\n\t" -"lwq1: R3 = 0 (X);\n\t" /* R3: dist */ -" LSETUP (lwq3, lwq4) LC1 = %6;\n\t" -"lwq3: R0.L = W [I0++] || R2.L = W [I1++];\n\t" +" LSETUP (1f, 2f) LC0 = %5;\n\t" +"1: R3 = 0 (X);\n\t" /* R3: dist */ +" LSETUP (3f, 4f) LC1 = %6;\n\t" +"3: R0.L = W [I0++] || R2.L = W [I1++];\n\t" " R1 = B [P2++] (X);\n\t" -" R1 <<= 5;\n\t" -" R0.L = R0.L - R1.L;\n\t" +" R1 <<= 5;\n\t" +" R0.L = R0.L - R1.L;\n\t" " R0 = R0.L*R0.L;\n\t" -" A1 = R2.L*R0.L (M,IS);\n\t" -" A1 = A1 >>> 16;\n\t" -" R1 = (A1 += R2.L*R0.H) (IS);\n\t" -"lwq4: R3 = R3 + R1;\n\t" - -" cc =R3<%0;\n\t" -" if cc %0=R3;\n\t" -" if cc %1=R5;\n\t" -"lwq2: R5 += 1;\n\t" +" A1 = R2.L*R0.L (M,IS);\n\t" +" A1 = A1 >>> 16;\n\t" +" R1 = (A1 += R2.L*R0.H) (IS);\n\t" +"4: R3 = R3 + R1;\n\t" + +" cc =R3<%0;\n\t" +" if cc %0=R3;\n\t" +" if cc %1=R5;\n\t" +"2: R5 += 1;\n\t" " L0 = 0;\n\t" " L1 = 0;\n\t" : "=&d" (best_dist), "=&d" (best_id) diff --git a/lib/rbcodec/codecs/libspeex/resample.c b/lib/rbcodec/codecs/libspeex/resample.c index 65dfef28a3..5f5b9c6b4d 100644 --- a/lib/rbcodec/codecs/libspeex/resample.c +++ b/lib/rbcodec/codecs/libspeex/resample.c @@ -1,5 +1,6 @@ -/* Copyright (C) 2007 Jean-Marc Valin - +/* Copyright (C) 2007-2008 Jean-Marc Valin + Copyright (C) 2008 Thorvald Natvig + File: resample.c Arbitrary resampling code @@ -37,27 +38,27 @@ - Low memory requirement - Good *perceptual* quality (and not best SNR) - Warning: This resampler is relatively new. Although I think I got rid of + Warning: This resampler is relatively new. Although I think I got rid of all the major bugs and I don't expect the API to change anymore, there may be something I've missed. So use with caution. This algorithm is based on this original resampling algorithm: Smith, Julius O. Digital Audio Resampling Home Page - Center for Computer Research in Music and Acoustics (CCRMA), + Center for Computer Research in Music and Acoustics (CCRMA), Stanford University, 2007. Web published at http://www-ccrma.stanford.edu/~jos/resample/. - There is one main difference, though. This resampler uses cubic + There is one main difference, though. This resampler uses cubic interpolation instead of linear interpolation in the above paper. This makes the table much smaller and makes it possible to compute that table - on a per-stream basis. In turn, being able to tweak the table for each - stream makes it possible to both reduce complexity on simple ratios - (e.g. 2/3), and get rid of the rounding operations in the inner loop. + on a per-stream basis. In turn, being able to tweak the table for each + stream makes it possible to both reduce complexity on simple ratios + (e.g. 2/3), and get rid of the rounding operations in the inner loop. The latter both reduces CPU time and makes the algorithm more SIMD-friendly. */ #ifdef HAVE_CONFIG_H -#include "config-speex.h" +#include "config.h" #endif #ifdef OUTSIDE_SPEEX @@ -68,12 +69,13 @@ static void speex_free (void *ptr) {free(ptr);} #include "speex_resampler.h" #include "arch.h" #else /* OUTSIDE_SPEEX */ - + #include "speex/speex_resampler.h" #include "arch.h" #include "os_support.h" #endif /* OUTSIDE_SPEEX */ +#include "stack_alloc.h" #include #ifndef M_PI @@ -81,14 +83,10 @@ static void speex_free (void *ptr) {free(ptr);} #endif #ifdef FIXED_POINT -#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x))) +#define WORD2INT(x) ((x) < -32767 ? -32768 : ((x) > 32766 ? 32767 : (x))) #else -#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x)))) +#define WORD2INT(x) ((x) < -32767.5f ? -32768 : ((x) > 32766.5f ? 32767 : floor(.5+(x)))) #endif - -/*#define float double*/ -#define FILTER_SIZE 64 -#define OVERSAMPLE 8 #define IMAX(a,b) ((a) > (b) ? (a) : (b)) #define IMIN(a,b) ((a) < (b) ? (a) : (b)) @@ -97,6 +95,17 @@ static void speex_free (void *ptr) {free(ptr);} #define NULL 0 #endif +#ifdef _USE_SSE +#include "resample_sse.h" +#endif + +/* Numer of elements to allocate on the stack */ +#ifdef VAR_ARRAYS +#define FIXED_STACK_ALLOC 8192 +#else +#define FIXED_STACK_ALLOC 1024 +#endif + typedef int (*resampler_basic_func)(SpeexResamplerState *, spx_uint32_t , const spx_word16_t *, spx_uint32_t *, spx_word16_t *, spx_uint32_t *); struct SpeexResamplerState_ { @@ -104,28 +113,29 @@ struct SpeexResamplerState_ { spx_uint32_t out_rate; spx_uint32_t num_rate; spx_uint32_t den_rate; - + int quality; spx_uint32_t nb_channels; spx_uint32_t filt_len; spx_uint32_t mem_alloc_size; + spx_uint32_t buffer_size; int int_advance; int frac_advance; float cutoff; spx_uint32_t oversample; int initialised; int started; - + /* These are per-channel */ spx_int32_t *last_sample; spx_uint32_t *samp_frac_num; spx_uint32_t *magic_samples; - + spx_word16_t *mem; spx_word16_t *sinc_table; spx_uint32_t sinc_table_length; resampler_basic_func resampler_ptr; - + int in_stride; int out_stride; } ; @@ -167,7 +177,7 @@ static double kaiser8_table[36] = { 0.32108304, 0.27619388, 0.23465776, 0.19672670, 0.16255380, 0.13219758, 0.10562887, 0.08273982, 0.06335451, 0.04724088, 0.03412321, 0.02369490, 0.01563093, 0.00959968, 0.00527363, 0.00233883, 0.00050000, 0.00000000}; - + static double kaiser6_table[36] = { 0.99733006, 1.00000000, 0.99733006, 0.98935595, 0.97618418, 0.95799003, 0.93501423, 0.90755855, 0.87598009, 0.84068475, 0.80211977, 0.76076565, @@ -180,7 +190,7 @@ struct FuncDef { double *table; int oversample; }; - + static struct FuncDef _KAISER12 = {kaiser12_table, 64}; #define KAISER12 (&_KAISER12) /*static struct FuncDef _KAISER12 = {kaiser12_table, 32}; @@ -202,7 +212,7 @@ struct QualityMapping { /* This table maps conversion quality to internal parameters. There are two - reasons that explain why the up-sampling bandwidth is larger than the + reasons that explain why the up-sampling bandwidth is larger than the down-sampling bandwidth: 1) When up-sampling, we can assume that the spectrum is already attenuated close to the Nyquist rate (from an A/D or a previous resampling filter) @@ -228,7 +238,7 @@ static double compute_func(float x, struct FuncDef *func) { float y, frac; double interp[4]; - int ind; + int ind; y = x*func->oversample; ind = (int)floor(y); frac = (y-ind); @@ -239,7 +249,7 @@ static double compute_func(float x, struct FuncDef *func) interp[0] = -0.3333333333*frac + 0.5*(frac*frac) - 0.1666666667*(frac*frac*frac); /* Just to make sure we don't have rounding problems */ interp[1] = 1.f-interp[3]-interp[2]-interp[0]; - + /*sum = frac*accum[1] + (1-frac)*accum[2];*/ return interp[0]*func->table[ind] + interp[1]*func->table[ind+1] + interp[2]*func->table[ind+2] + interp[3]*func->table[ind+3]; } @@ -317,47 +327,47 @@ static void cubic_coef(spx_word16_t frac, spx_word16_t interp[4]) static int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) { - int N = st->filt_len; + const int N = st->filt_len; int out_sample = 0; - spx_word16_t *mem; int last_sample = st->last_sample[channel_index]; spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; - mem = st->mem + channel_index * st->mem_alloc_size; + const spx_word16_t *sinc_table = st->sinc_table; + const int out_stride = st->out_stride; + const int int_advance = st->int_advance; + const int frac_advance = st->frac_advance; + const spx_uint32_t den_rate = st->den_rate; + spx_word32_t sum; + int j; + while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) { - int j; - spx_word32_t sum=0; - - /* We already have all the filter coefficients pre-computed in the table */ - const spx_word16_t *ptr; - /* Do the memory part */ - for (j=0;last_sample-N+1+j < 0;j++) - { - sum += MULT16_16(mem[last_sample+j],st->sinc_table[samp_frac_num*st->filt_len+j]); - } - - /* Do the new part */ - if (in != NULL) - { - ptr = in+st->in_stride*(last_sample-N+1+j); - for (;jsinc_table[samp_frac_num*st->filt_len+j]); - ptr += st->in_stride; - } + const spx_word16_t *sinc = & sinc_table[samp_frac_num*N]; + const spx_word16_t *iptr = & in[last_sample]; + +#ifndef OVERRIDE_INNER_PRODUCT_SINGLE + float accum[4] = {0,0,0,0}; + + for(j=0;jout_stride; - out_sample++; - last_sample += st->int_advance; - samp_frac_num += st->frac_advance; - if (samp_frac_num >= st->den_rate) + sum = accum[0] + accum[1] + accum[2] + accum[3]; +#else + sum = inner_product_single(sinc, iptr, N); +#endif + + out[out_stride * out_sample++] = PSHR32(sum, 15); + last_sample += int_advance; + samp_frac_num += frac_advance; + if (samp_frac_num >= den_rate) { - samp_frac_num -= st->den_rate; + samp_frac_num -= den_rate; last_sample++; } } + st->last_sample[channel_index] = last_sample; st->samp_frac_num[channel_index] = samp_frac_num; return out_sample; @@ -368,47 +378,47 @@ static int resampler_basic_direct_single(SpeexResamplerState *st, spx_uint32_t c /* This is the same as the previous function, except with a double-precision accumulator */ static int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) { - int N = st->filt_len; + const int N = st->filt_len; int out_sample = 0; - spx_word16_t *mem; int last_sample = st->last_sample[channel_index]; spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; - mem = st->mem + channel_index * st->mem_alloc_size; + const spx_word16_t *sinc_table = st->sinc_table; + const int out_stride = st->out_stride; + const int int_advance = st->int_advance; + const int frac_advance = st->frac_advance; + const spx_uint32_t den_rate = st->den_rate; + double sum; + int j; + while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) { - int j; - double sum=0; - - /* We already have all the filter coefficients pre-computed in the table */ - const spx_word16_t *ptr; - /* Do the memory part */ - for (j=0;last_sample-N+1+j < 0;j++) - { - sum += MULT16_16(mem[last_sample+j],(double)st->sinc_table[samp_frac_num*st->filt_len+j]); - } - - /* Do the new part */ - if (in != NULL) - { - ptr = in+st->in_stride*(last_sample-N+1+j); - for (;jsinc_table[samp_frac_num*st->filt_len+j]); - ptr += st->in_stride; - } + const spx_word16_t *sinc = & sinc_table[samp_frac_num*N]; + const spx_word16_t *iptr = & in[last_sample]; + +#ifndef OVERRIDE_INNER_PRODUCT_DOUBLE + double accum[4] = {0,0,0,0}; + + for(j=0;jout_stride; - out_sample++; - last_sample += st->int_advance; - samp_frac_num += st->frac_advance; - if (samp_frac_num >= st->den_rate) + sum = accum[0] + accum[1] + accum[2] + accum[3]; +#else + sum = inner_product_double(sinc, iptr, N); +#endif + + out[out_stride * out_sample++] = PSHR32(sum, 15); + last_sample += int_advance; + samp_frac_num += frac_advance; + if (samp_frac_num >= den_rate) { - samp_frac_num -= st->den_rate; + samp_frac_num -= den_rate; last_sample++; } } + st->last_sample[channel_index] = last_sample; st->samp_frac_num[channel_index] = samp_frac_num; return out_sample; @@ -417,69 +427,58 @@ static int resampler_basic_direct_double(SpeexResamplerState *st, spx_uint32_t c static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) { - int N = st->filt_len; + const int N = st->filt_len; int out_sample = 0; - spx_word16_t *mem; int last_sample = st->last_sample[channel_index]; spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; - mem = st->mem + channel_index * st->mem_alloc_size; + const int out_stride = st->out_stride; + const int int_advance = st->int_advance; + const int frac_advance = st->frac_advance; + const spx_uint32_t den_rate = st->den_rate; + int j; + spx_word32_t sum; + while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) { - int j; - spx_word32_t sum=0; - - /* We need to interpolate the sinc filter */ - spx_word32_t accum[4] = {0.f,0.f, 0.f, 0.f}; - spx_word16_t interp[4]; - const spx_word16_t *ptr; - int offset; - spx_word16_t frac; - offset = samp_frac_num*st->oversample/st->den_rate; + const spx_word16_t *iptr = & in[last_sample]; + + const int offset = samp_frac_num*st->oversample/st->den_rate; #ifdef FIXED_POINT - frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate); + const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate); #else - frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate; + const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate; #endif - /* This code is written like this to make it easy to optimise with SIMD. - For most DSPs, it would be best to split the loops in two because most DSPs - have only two accumulators */ - for (j=0;last_sample-N+1+j < 0;j++) - { - spx_word16_t curr_mem = mem[last_sample+j]; - accum[0] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-2]); - accum[1] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-1]); - accum[2] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset]); - accum[3] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset+1]); - } - - if (in != NULL) - { - ptr = in+st->in_stride*(last_sample-N+1+j); - /* Do the new part */ - for (;jin_stride; - accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]); - accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); - accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); - accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); - } + spx_word16_t interp[4]; + + +#ifndef OVERRIDE_INTERPOLATE_PRODUCT_SINGLE + spx_word32_t accum[4] = {0,0,0,0}; + + for(j=0;jsinc_table[4+(j+1)*st->oversample-offset-2]); + accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); + accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); + accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); } + cubic_coef(frac, interp); sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]); - - *out = PSHR32(sum,15); - out += st->out_stride; - out_sample++; - last_sample += st->int_advance; - samp_frac_num += st->frac_advance; - if (samp_frac_num >= st->den_rate) +#else + cubic_coef(frac, interp); + sum = interpolate_product_single(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp); +#endif + + out[out_stride * out_sample++] = PSHR32(sum,15); + last_sample += int_advance; + samp_frac_num += frac_advance; + if (samp_frac_num >= den_rate) { - samp_frac_num -= st->den_rate; + samp_frac_num -= den_rate; last_sample++; } } + st->last_sample[channel_index] = last_sample; st->samp_frac_num[channel_index] = samp_frac_num; return out_sample; @@ -490,63 +489,58 @@ static int resampler_basic_interpolate_single(SpeexResamplerState *st, spx_uint3 /* This is the same as the previous function, except with a double-precision accumulator */ static int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) { - int N = st->filt_len; + const int N = st->filt_len; int out_sample = 0; - spx_word16_t *mem; int last_sample = st->last_sample[channel_index]; spx_uint32_t samp_frac_num = st->samp_frac_num[channel_index]; - mem = st->mem + channel_index * st->mem_alloc_size; + const int out_stride = st->out_stride; + const int int_advance = st->int_advance; + const int frac_advance = st->frac_advance; + const spx_uint32_t den_rate = st->den_rate; + int j; + spx_word32_t sum; + while (!(last_sample >= (spx_int32_t)*in_len || out_sample >= (spx_int32_t)*out_len)) { - int j; - spx_word32_t sum=0; - - /* We need to interpolate the sinc filter */ - double accum[4] = {0.f,0.f, 0.f, 0.f}; - float interp[4]; - const spx_word16_t *ptr; - float alpha = ((float)samp_frac_num)/st->den_rate; - int offset = samp_frac_num*st->oversample/st->den_rate; - float frac = alpha*st->oversample - offset; - /* This code is written like this to make it easy to optimise with SIMD. - For most DSPs, it would be best to split the loops in two because most DSPs - have only two accumulators */ - for (j=0;last_sample-N+1+j < 0;j++) - { - double curr_mem = mem[last_sample+j]; - accum[0] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-2]); - accum[1] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset-1]); - accum[2] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset]); - accum[3] += MULT16_16(curr_mem,st->sinc_table[4+(j+1)*st->oversample-offset+1]); - } - if (in != NULL) - { - ptr = in+st->in_stride*(last_sample-N+1+j); - /* Do the new part */ - for (;jin_stride; - accum[0] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-2]); - accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); - accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); - accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); - } + const spx_word16_t *iptr = & in[last_sample]; + + const int offset = samp_frac_num*st->oversample/st->den_rate; +#ifdef FIXED_POINT + const spx_word16_t frac = PDIV32(SHL32((samp_frac_num*st->oversample) % st->den_rate,15),st->den_rate); +#else + const spx_word16_t frac = ((float)((samp_frac_num*st->oversample) % st->den_rate))/st->den_rate; +#endif + spx_word16_t interp[4]; + + +#ifndef OVERRIDE_INTERPOLATE_PRODUCT_DOUBLE + double accum[4] = {0,0,0,0}; + + for(j=0;jsinc_table[4+(j+1)*st->oversample-offset-2]); + accum[1] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset-1]); + accum[2] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset]); + accum[3] += MULT16_16(curr_in,st->sinc_table[4+(j+1)*st->oversample-offset+1]); } + cubic_coef(frac, interp); - sum = interp[0]*accum[0] + interp[1]*accum[1] + interp[2]*accum[2] + interp[3]*accum[3]; - - *out = PSHR32(sum,15); - out += st->out_stride; - out_sample++; - last_sample += st->int_advance; - samp_frac_num += st->frac_advance; - if (samp_frac_num >= st->den_rate) + sum = MULT16_32_Q15(interp[0],accum[0]) + MULT16_32_Q15(interp[1],accum[1]) + MULT16_32_Q15(interp[2],accum[2]) + MULT16_32_Q15(interp[3],accum[3]); +#else + cubic_coef(frac, interp); + sum = interpolate_product_double(iptr, st->sinc_table + st->oversample + 4 - offset - 2, N, st->oversample, interp); +#endif + + out[out_stride * out_sample++] = PSHR32(sum,15); + last_sample += int_advance; + samp_frac_num += frac_advance; + if (samp_frac_num >= den_rate) { - samp_frac_num -= st->den_rate; + samp_frac_num -= den_rate; last_sample++; } } + st->last_sample[channel_index] = last_sample; st->samp_frac_num[channel_index] = samp_frac_num; return out_sample; @@ -556,11 +550,11 @@ static int resampler_basic_interpolate_double(SpeexResamplerState *st, spx_uint3 static void update_filter(SpeexResamplerState *st) { spx_uint32_t old_length; - + old_length = st->filt_len; st->oversample = quality_map[st->quality].oversample; st->filt_len = quality_map[st->quality].base_length; - + if (st->num_rate > st->den_rate) { /* down-sampling */ @@ -636,25 +630,25 @@ static void update_filter(SpeexResamplerState *st) st->int_advance = st->num_rate/st->den_rate; st->frac_advance = st->num_rate%st->den_rate; - + /* Here's the place where we update the filter memory to take into account the change in filter length. It's probably the messiest part of the code due to handling of lots of corner cases. */ if (!st->mem) { spx_uint32_t i; - st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t)); - for (i=0;inb_channels*(st->filt_len-1);i++) + st->mem_alloc_size = st->filt_len-1 + st->buffer_size; + st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t)); + for (i=0;inb_channels*st->mem_alloc_size;i++) st->mem[i] = 0; - st->mem_alloc_size = st->filt_len-1; /*speex_warning("init filter");*/ } else if (!st->started) { spx_uint32_t i; - st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t)); - for (i=0;inb_channels*(st->filt_len-1);i++) + st->mem_alloc_size = st->filt_len-1 + st->buffer_size; + st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t)); + for (i=0;inb_channels*st->mem_alloc_size;i++) st->mem[i] = 0; - st->mem_alloc_size = st->filt_len-1; /*speex_warning("reinit filter");*/ } else if (st->filt_len > old_length) { @@ -662,10 +656,10 @@ static void update_filter(SpeexResamplerState *st) /* Increase the filter length */ /*speex_warning("increase filter size");*/ int old_alloc_size = st->mem_alloc_size; - if (st->filt_len-1 > st->mem_alloc_size) + if ((st->filt_len-1 + st->buffer_size) > st->mem_alloc_size) { - st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t)); - st->mem_alloc_size = st->filt_len-1; + st->mem_alloc_size = st->filt_len-1 + st->buffer_size; + st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*st->mem_alloc_size * sizeof(spx_word16_t)); } for (i=st->nb_channels-1;i>=0;i--) { @@ -674,7 +668,7 @@ static void update_filter(SpeexResamplerState *st) /*if (st->magic_samples[i])*/ { /* Try and remove the magic samples as if nothing had happened */ - + /* FIXME: This is wrong but for now we need it to avoid going over the array bounds */ olen = old_length + 2*st->magic_samples[i]; for (j=old_length-2+st->magic_samples[i];j>=0;j--) @@ -721,12 +715,12 @@ static void update_filter(SpeexResamplerState *st) } -SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) +EXPORT SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) { return speex_resampler_init_frac(nb_channels, in_rate, out_rate, in_rate, out_rate, quality, err); } -SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) +EXPORT SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate, int quality, int *err) { spx_uint32_t i; SpeexResamplerState *st; @@ -749,12 +743,18 @@ SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uin st->filt_len = 0; st->mem = 0; st->resampler_ptr = 0; - + st->cutoff = 1.f; st->nb_channels = nb_channels; st->in_stride = 1; st->out_stride = 1; - + +#ifdef FIXED_POINT + st->buffer_size = 160; +#else + st->buffer_size = 160; +#endif + /* Per channel data */ st->last_sample = (spx_int32_t*)speex_alloc(nb_channels*sizeof(int)); st->magic_samples = (spx_uint32_t*)speex_alloc(nb_channels*sizeof(int)); @@ -769,9 +769,9 @@ SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uin speex_resampler_set_quality(st, quality); speex_resampler_set_rate_frac(st, ratio_num, ratio_den, in_rate, out_rate); - + update_filter(st); - + st->initialised = 1; if (err) *err = RESAMPLER_ERR_SUCCESS; @@ -779,7 +779,7 @@ SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels, spx_uin return st; } -void speex_resampler_destroy(SpeexResamplerState *st) +EXPORT void speex_resampler_destroy(SpeexResamplerState *st) { speex_free(st->mem); speex_free(st->sinc_table); @@ -789,186 +789,168 @@ void speex_resampler_destroy(SpeexResamplerState *st) speex_free(st); } - - -static int speex_resampler_process_native(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_word16_t *in, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) +static int speex_resampler_process_native(SpeexResamplerState *st, spx_uint32_t channel_index, spx_uint32_t *in_len, spx_word16_t *out, spx_uint32_t *out_len) { int j=0; - int N = st->filt_len; + const int N = st->filt_len; int out_sample = 0; - spx_word16_t *mem; - spx_uint32_t tmp_out_len = 0; - mem = st->mem + channel_index * st->mem_alloc_size; + spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size; + spx_uint32_t ilen; + st->started = 1; - - /* Handle the case where we have samples left from a reduction in filter length */ - if (st->magic_samples[channel_index]) - { - int istride_save; - spx_uint32_t tmp_in_len; - spx_uint32_t tmp_magic; - - istride_save = st->in_stride; - tmp_in_len = st->magic_samples[channel_index]; - tmp_out_len = *out_len; - /* magic_samples needs to be set to zero to avoid infinite recursion */ - tmp_magic = st->magic_samples[channel_index]; - st->magic_samples[channel_index] = 0; - st->in_stride = 1; - speex_resampler_process_native(st, channel_index, mem+N-1, &tmp_in_len, out, &tmp_out_len); - st->in_stride = istride_save; - /*speex_warning_int("extra samples:", tmp_out_len);*/ - /* If we couldn't process all "magic" input samples, save the rest for next time */ - if (tmp_in_len < tmp_magic) - { - spx_uint32_t i; - st->magic_samples[channel_index] = tmp_magic-tmp_in_len; - for (i=0;imagic_samples[channel_index];i++) - mem[N-1+i]=mem[N-1+i+tmp_in_len]; - } - out += tmp_out_len*st->out_stride; - *out_len -= tmp_out_len; - } - + /* Call the right resampler through the function ptr */ - out_sample = st->resampler_ptr(st, channel_index, in, in_len, out, out_len); - + out_sample = st->resampler_ptr(st, channel_index, mem, in_len, out, out_len); + if (st->last_sample[channel_index] < (spx_int32_t)*in_len) *in_len = st->last_sample[channel_index]; - *out_len = out_sample+tmp_out_len; + *out_len = out_sample; st->last_sample[channel_index] -= *in_len; - - for (j=0;jin_stride*(j+*in_len-N+1)]; - + + ilen = *in_len; + + for(j=0;jmagic_samples[channel_index]; + spx_word16_t *mem = st->mem + channel_index * st->mem_alloc_size; + const int N = st->filt_len; + + speex_resampler_process_native(st, channel_index, &tmp_in_len, *out, &out_len); + + st->magic_samples[channel_index] -= tmp_in_len; + + /* If we couldn't process all "magic" input samples, save the rest for next time */ + if (st->magic_samples[channel_index]) + { + spx_uint32_t i; + for (i=0;imagic_samples[channel_index];i++) + mem[N-1+i]=mem[N-1+i+tmp_in_len]; + } + *out += out_len*st->out_stride; + return out_len; +} #ifdef FIXED_POINT -int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) -{ - spx_uint32_t i; - int istride_save, ostride_save; -#ifdef VAR_ARRAYS - spx_word16_t x[*in_len]; - spx_word16_t y[*out_len]; - /*VARDECL(spx_word16_t *x); - VARDECL(spx_word16_t *y); - ALLOC(x, *in_len, spx_word16_t); - ALLOC(y, *out_len, spx_word16_t);*/ - istride_save = st->in_stride; - ostride_save = st->out_stride; - for (i=0;i<*in_len;i++) - x[i] = WORD2INT(in[i*st->in_stride]); - st->in_stride = st->out_stride = 1; - speex_resampler_process_native(st, channel_index, x, in_len, y, out_len); - st->in_stride = istride_save; - st->out_stride = ostride_save; - for (i=0;i<*out_len;i++) - out[i*st->out_stride] = y[i]; +EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) #else - spx_word16_t x[FIXED_STACK_ALLOC]; - spx_word16_t y[FIXED_STACK_ALLOC]; - spx_uint32_t ilen=*in_len, olen=*out_len; - istride_save = st->in_stride; - ostride_save = st->out_stride; - while (ilen && olen) - { - spx_uint32_t ichunk, ochunk; - ichunk = ilen; - ochunk = olen; - if (ichunk>FIXED_STACK_ALLOC) - ichunk=FIXED_STACK_ALLOC; - if (ochunk>FIXED_STACK_ALLOC) - ochunk=FIXED_STACK_ALLOC; - for (i=0;iin_stride]); - st->in_stride = st->out_stride = 1; - speex_resampler_process_native(st, channel_index, x, &ichunk, y, &ochunk); - st->in_stride = istride_save; - st->out_stride = ostride_save; - for (i=0;iout_stride] = y[i]; - out += ochunk; - in += ichunk; - ilen -= ichunk; - olen -= ochunk; +EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) +#endif +{ + int j; + spx_uint32_t ilen = *in_len; + spx_uint32_t olen = *out_len; + spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size; + const int filt_offs = st->filt_len - 1; + const spx_uint32_t xlen = st->mem_alloc_size - filt_offs; + const int istride = st->in_stride; + + if (st->magic_samples[channel_index]) + olen -= speex_resampler_magic(st, channel_index, &out, olen); + if (! st->magic_samples[channel_index]) { + while (ilen && olen) { + spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen; + spx_uint32_t ochunk = olen; + + if (in) { + for(j=0;jout_stride; + if (in) + in += ichunk * istride; + } } *in_len -= ilen; - *out_len -= olen; -#endif + *out_len -= olen; return RESAMPLER_ERR_SUCCESS; } -int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) -{ - return speex_resampler_process_native(st, channel_index, in, in_len, out, out_len); -} + +#ifdef FIXED_POINT +EXPORT int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) #else -int speex_resampler_process_float(SpeexResamplerState *st, spx_uint32_t channel_index, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) -{ - return speex_resampler_process_native(st, channel_index, in, in_len, out, out_len); -} -int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) +EXPORT int speex_resampler_process_int(SpeexResamplerState *st, spx_uint32_t channel_index, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) +#endif { - spx_uint32_t i; - int istride_save, ostride_save; + int j; + const int istride_save = st->in_stride; + const int ostride_save = st->out_stride; + spx_uint32_t ilen = *in_len; + spx_uint32_t olen = *out_len; + spx_word16_t *x = st->mem + channel_index * st->mem_alloc_size; + const spx_uint32_t xlen = st->mem_alloc_size - (st->filt_len - 1); #ifdef VAR_ARRAYS - spx_word16_t x[*in_len]; - spx_word16_t y[*out_len]; - /*VARDECL(spx_word16_t *x); - VARDECL(spx_word16_t *y); - ALLOC(x, *in_len, spx_word16_t); - ALLOC(y, *out_len, spx_word16_t);*/ - istride_save = st->in_stride; - ostride_save = st->out_stride; - for (i=0;i<*in_len;i++) - x[i] = in[i*st->in_stride]; - st->in_stride = st->out_stride = 1; - speex_resampler_process_native(st, channel_index, x, in_len, y, out_len); - st->in_stride = istride_save; - st->out_stride = ostride_save; - for (i=0;i<*out_len;i++) - out[i*st->out_stride] = WORD2INT(y[i]); + const unsigned int ylen = (olen < FIXED_STACK_ALLOC) ? olen : FIXED_STACK_ALLOC; + VARDECL(spx_word16_t *ystack); + ALLOC(ystack, ylen, spx_word16_t); #else - spx_word16_t x[FIXED_STACK_ALLOC]; - spx_word16_t y[FIXED_STACK_ALLOC]; - spx_uint32_t ilen=*in_len, olen=*out_len; - istride_save = st->in_stride; - ostride_save = st->out_stride; - while (ilen && olen) - { - spx_uint32_t ichunk, ochunk; - ichunk = ilen; - ochunk = olen; - if (ichunk>FIXED_STACK_ALLOC) - ichunk=FIXED_STACK_ALLOC; - if (ochunk>FIXED_STACK_ALLOC) - ochunk=FIXED_STACK_ALLOC; - for (i=0;iin_stride]; - st->in_stride = st->out_stride = 1; - speex_resampler_process_native(st, channel_index, x, &ichunk, y, &ochunk); - st->in_stride = istride_save; - st->out_stride = ostride_save; - for (i=0;iout_stride] = WORD2INT(y[i]); - out += ochunk; - in += ichunk; - ilen -= ichunk; - olen -= ochunk; + const unsigned int ylen = FIXED_STACK_ALLOC; + spx_word16_t ystack[FIXED_STACK_ALLOC]; +#endif + + st->out_stride = 1; + + while (ilen && olen) { + spx_word16_t *y = ystack; + spx_uint32_t ichunk = (ilen > xlen) ? xlen : ilen; + spx_uint32_t ochunk = (olen > ylen) ? ylen : olen; + spx_uint32_t omagic = 0; + + if (st->magic_samples[channel_index]) { + omagic = speex_resampler_magic(st, channel_index, &y, ochunk); + ochunk -= omagic; + olen -= omagic; + } + if (! st->magic_samples[channel_index]) { + if (in) { + for(j=0;jfilt_len-1]=WORD2INT(in[j*istride_save]); +#else + x[j+st->filt_len-1]=in[j*istride_save]; +#endif + } else { + for(j=0;jfilt_len-1]=0; + } + + speex_resampler_process_native(st, channel_index, &ichunk, y, &ochunk); + } else { + ichunk = 0; + ochunk = 0; + } + + for (j=0;jout_stride = ostride_save; *in_len -= ilen; - *out_len -= olen; -#endif + *out_len -= olen; + return RESAMPLER_ERR_SUCCESS; } -#endif -int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) +EXPORT int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, spx_uint32_t *in_len, float *out, spx_uint32_t *out_len) { spx_uint32_t i; int istride_save, ostride_save; @@ -989,8 +971,7 @@ int speex_resampler_process_interleaved_float(SpeexResamplerState *st, const flo return RESAMPLER_ERR_SUCCESS; } - -int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) +EXPORT int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_int16_t *in, spx_uint32_t *in_len, spx_int16_t *out, spx_uint32_t *out_len) { spx_uint32_t i; int istride_save, ostride_save; @@ -1011,25 +992,25 @@ int speex_resampler_process_interleaved_int(SpeexResamplerState *st, const spx_i return RESAMPLER_ERR_SUCCESS; } -int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate) +EXPORT int speex_resampler_set_rate(SpeexResamplerState *st, spx_uint32_t in_rate, spx_uint32_t out_rate) { return speex_resampler_set_rate_frac(st, in_rate, out_rate, in_rate, out_rate); } -void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate) +EXPORT void speex_resampler_get_rate(SpeexResamplerState *st, spx_uint32_t *in_rate, spx_uint32_t *out_rate) { *in_rate = st->in_rate; *out_rate = st->out_rate; } -int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate) +EXPORT int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_num, spx_uint32_t ratio_den, spx_uint32_t in_rate, spx_uint32_t out_rate) { spx_uint32_t fact; spx_uint32_t old_den; spx_uint32_t i; if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den) return RESAMPLER_ERR_SUCCESS; - + old_den = st->den_rate; st->in_rate = in_rate; st->out_rate = out_rate; @@ -1044,7 +1025,7 @@ int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_nu st->den_rate /= fact; } } - + if (old_den > 0) { for (i=0;inb_channels;i++) @@ -1055,19 +1036,19 @@ int speex_resampler_set_rate_frac(SpeexResamplerState *st, spx_uint32_t ratio_nu st->samp_frac_num[i] = st->den_rate-1; } } - + if (st->initialised) update_filter(st); return RESAMPLER_ERR_SUCCESS; } -void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den) +EXPORT void speex_resampler_get_ratio(SpeexResamplerState *st, spx_uint32_t *ratio_num, spx_uint32_t *ratio_den) { *ratio_num = st->num_rate; *ratio_den = st->den_rate; } -int speex_resampler_set_quality(SpeexResamplerState *st, int quality) +EXPORT int speex_resampler_set_quality(SpeexResamplerState *st, int quality) { if (quality > 10 || quality < 0) return RESAMPLER_ERR_INVALID_ARG; @@ -1079,32 +1060,42 @@ int speex_resampler_set_quality(SpeexResamplerState *st, int quality) return RESAMPLER_ERR_SUCCESS; } -void speex_resampler_get_quality(SpeexResamplerState *st, int *quality) +EXPORT void speex_resampler_get_quality(SpeexResamplerState *st, int *quality) { *quality = st->quality; } -void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride) +EXPORT void speex_resampler_set_input_stride(SpeexResamplerState *st, spx_uint32_t stride) { st->in_stride = stride; } -void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride) +EXPORT void speex_resampler_get_input_stride(SpeexResamplerState *st, spx_uint32_t *stride) { *stride = st->in_stride; } -void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride) +EXPORT void speex_resampler_set_output_stride(SpeexResamplerState *st, spx_uint32_t stride) { st->out_stride = stride; } -void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride) +EXPORT void speex_resampler_get_output_stride(SpeexResamplerState *st, spx_uint32_t *stride) { *stride = st->out_stride; } -int speex_resampler_skip_zeros(SpeexResamplerState *st) +EXPORT int speex_resampler_get_input_latency(SpeexResamplerState *st) +{ + return st->filt_len / 2; +} + +EXPORT int speex_resampler_get_output_latency(SpeexResamplerState *st) +{ + return ((st->filt_len / 2) * st->den_rate + (st->num_rate >> 1)) / st->num_rate; +} + +EXPORT int speex_resampler_skip_zeros(SpeexResamplerState *st) { spx_uint32_t i; for (i=0;inb_channels;i++) @@ -1112,7 +1103,7 @@ int speex_resampler_skip_zeros(SpeexResamplerState *st) return RESAMPLER_ERR_SUCCESS; } -int speex_resampler_reset_mem(SpeexResamplerState *st) +EXPORT int speex_resampler_reset_mem(SpeexResamplerState *st) { spx_uint32_t i; for (i=0;inb_channels*(st->filt_len-1);i++) @@ -1120,7 +1111,7 @@ int speex_resampler_reset_mem(SpeexResamplerState *st) return RESAMPLER_ERR_SUCCESS; } -const char *speex_resampler_strerror(int err) +EXPORT const char *speex_resampler_strerror(int err) { switch (err) { diff --git a/lib/rbcodec/codecs/libspeex/resample_sse.h b/lib/rbcodec/codecs/libspeex/resample_sse.h new file mode 100644 index 0000000000..d85898067e --- /dev/null +++ b/lib/rbcodec/codecs/libspeex/resample_sse.h @@ -0,0 +1,128 @@ +/* Copyright (C) 2007-2008 Jean-Marc Valin + * Copyright (C) 2008 Thorvald Natvig + */ +/** + @file resample_sse.h + @brief Resampler functions (SSE version) +*/ +/* + 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 the Xiph.org Foundation 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 FOUNDATION 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 + +#define OVERRIDE_INNER_PRODUCT_SINGLE +static inline float inner_product_single(const float *a, const float *b, unsigned int len) +{ + int i; + float ret; + __m128 sum = _mm_setzero_ps(); + for (i=0;i +#define OVERRIDE_INNER_PRODUCT_DOUBLE + +static inline double inner_product_double(const float *a, const float *b, unsigned int len) +{ + int i; + double ret; + __m128d sum = _mm_setzero_pd(); + __m128 t; + for (i=0;ienc_init(mode); } #endif -void *speex_decoder_init(const SpeexMode *mode) +EXPORT void *speex_decoder_init(const SpeexMode *mode) { return mode->dec_init(mode); } #ifndef SPEEX_DISABLE_ENCODER -void speex_encoder_destroy(void *state) +EXPORT void speex_encoder_destroy(void *state) { (*((SpeexMode**)state))->enc_destroy(state); } #endif -void speex_decoder_destroy(void *state) +EXPORT void speex_decoder_destroy(void *state) { (*((SpeexMode**)state))->dec_destroy(state); } @@ -90,7 +90,7 @@ int speex_decode_native(void *state, SpeexBits *bits, spx_word16_t *out) #ifndef SPEEX_DISABLE_ENCODER #ifndef DISABLE_FLOAT_API -int speex_encode(void *state, float *in, SpeexBits *bits) +EXPORT int speex_encode(void *state, float *in, SpeexBits *bits) { int i; spx_int32_t N; @@ -109,7 +109,7 @@ int speex_encode(void *state, float *in, SpeexBits *bits) } #endif /* #ifndef DISABLE_FLOAT_API */ -int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits) +EXPORT int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits) { SpeexMode *mode; mode = *(SpeexMode**)state; @@ -118,7 +118,7 @@ int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits) #endif /* SPEEX_DISABLE_ENCODER */ #ifndef DISABLE_FLOAT_API -int speex_decode(void *state, SpeexBits *bits, float *out) +EXPORT int speex_decode(void *state, SpeexBits *bits, float *out) { int i, ret; spx_int32_t N; @@ -131,7 +131,7 @@ int speex_decode(void *state, SpeexBits *bits, float *out) } #endif /* #ifndef DISABLE_FLOAT_API */ -int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out) +EXPORT int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out) { SpeexMode *mode = *(SpeexMode**)state; return (mode)->dec(state, bits, out); @@ -139,12 +139,12 @@ int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out) #else -int speex_encode(void *state, float *in, SpeexBits *bits) +EXPORT int speex_encode(void *state, float *in, SpeexBits *bits) { return (*((SpeexMode**)state))->enc(state, in, bits); } -int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits) +EXPORT int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits) { int i; spx_int32_t N; @@ -155,12 +155,12 @@ int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits) return (*((SpeexMode**)state))->enc(state, float_in, bits); } -int speex_decode(void *state, SpeexBits *bits, float *out) +EXPORT int speex_decode(void *state, SpeexBits *bits, float *out) { return (*((SpeexMode**)state))->dec(state, bits, out); } -int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out) +EXPORT int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out) { int i; spx_int32_t N; @@ -182,13 +182,13 @@ int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out) #endif #ifndef SPEEX_DISABLE_ENCODER -int speex_encoder_ctl(void *state, int request, void *ptr) +EXPORT int speex_encoder_ctl(void *state, int request, void *ptr) { return (*((SpeexMode**)state))->enc_ctl(state, request, ptr); } #endif -int speex_decoder_ctl(void *state, int request, void *ptr) +EXPORT int speex_decoder_ctl(void *state, int request, void *ptr) { return (*((SpeexMode**)state))->dec_ctl(state, request, ptr); } @@ -196,7 +196,7 @@ int speex_decoder_ctl(void *state, int request, void *ptr) int nb_mode_query(const void *mode, int request, void *ptr) { const SpeexNBMode *m = (const SpeexNBMode*)mode; - + switch (request) { case SPEEX_MODE_FRAME_SIZE: @@ -219,7 +219,7 @@ int nb_mode_query(const void *mode, int request, void *ptr) -int speex_lib_ctl(int request, void *ptr) +EXPORT int speex_lib_ctl(int request, void *ptr) { switch (request) { diff --git a/lib/rbcodec/codecs/libspeex/speex_callbacks.c b/lib/rbcodec/codecs/libspeex/speex_callbacks.c index f1de038488..ca236ed399 100644 --- a/lib/rbcodec/codecs/libspeex/speex_callbacks.c +++ b/lib/rbcodec/codecs/libspeex/speex_callbacks.c @@ -6,18 +6,18 @@ 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 the Xiph.org Foundation 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 @@ -40,7 +40,7 @@ #include "arch.h" #include "os_support.h" -int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *state) +EXPORT int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *state) { int id; SpeexCallback *callback; @@ -65,7 +65,7 @@ int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *st adv = 16; else if (id<14) adv = 32; - else + else adv = 64; speex_bits_advance(bits, adv); } @@ -74,7 +74,7 @@ int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *st #if 0 /* Rockbox: unused */ -int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data) +EXPORT int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data) { (void)state; spx_int32_t m; @@ -83,7 +83,7 @@ int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data) return 0; } -int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data) +EXPORT int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data) { (void)state; spx_int32_t m; @@ -92,7 +92,7 @@ int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data) return 0; } -int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data) +EXPORT int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data) { (void)state; spx_int32_t m; @@ -103,7 +103,7 @@ int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data #endif #ifndef DISABLE_VBR -int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data) +EXPORT int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data) { (void)state; spx_int32_t vbr; @@ -115,7 +115,7 @@ int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data) #if 0 /* Rockbox: unused */ -int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data) +EXPORT int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data) { (void)state; spx_int32_t enh; @@ -126,7 +126,7 @@ int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data) #endif #ifndef DISABLE_VBR -int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *data) +EXPORT int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *data) { (void)state; float qual; @@ -138,7 +138,7 @@ int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *da #if 0 /* Rockbox: unused */ -int speex_std_char_handler(SpeexBits *bits, void *state, void *data) +EXPORT int speex_std_char_handler(SpeexBits *bits, void *state, void *data) { (void)state; unsigned char ch; @@ -150,7 +150,7 @@ int speex_std_char_handler(SpeexBits *bits, void *state, void *data) #endif /* Default handler for user callbacks: skip it */ -int speex_default_user_handler(SpeexBits *bits, void *state, void *data) +EXPORT int speex_default_user_handler(SpeexBits *bits, void *state, void *data) { (void)state; (void)data; diff --git a/lib/rbcodec/codecs/libspeex/speex_header.c b/lib/rbcodec/codecs/libspeex/speex_header.c index b0e98b7c9c..f83e0f2152 100644 --- a/lib/rbcodec/codecs/libspeex/speex_header.c +++ b/lib/rbcodec/codecs/libspeex/speex_header.c @@ -1,22 +1,22 @@ -/* Copyright (C) 2002 Jean-Marc Valin +/* Copyright (C) 2002 Jean-Marc Valin File: speex_header.c Describes the Speex header 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 the Xiph.org Foundation 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 @@ -47,7 +47,7 @@ /** Convert little endian */ static inline spx_int32_t le_int(spx_int32_t i) { -#ifdef ROCKBOX +#ifdef ROCKBOX return letoh32(i); #elif !defined(__LITTLE_ENDIAN__) && ( defined(WORDS_BIGENDIAN) || defined(__BIG_ENDIAN__) ) spx_uint32_t ui, ret; @@ -86,7 +86,7 @@ typedef struct SpeexHeader { */ #ifndef SPEEX_DISABLE_ENCODER -void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const SpeexMode *m) +EXPORT void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const SpeexMode *m) { int i; const char *h="Speex "; @@ -101,10 +101,10 @@ void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const Spe header->speex_version[i]=SPEEX_VERSION[i]; for (;ispeex_version[i]=0; - + header->speex_version_id = 1; header->header_size = sizeof(SpeexHeader); - + header->rate = rate; header->mode = m->modeID; header->mode_bitstream_version = m->bitstream_version; @@ -114,20 +114,20 @@ void speex_init_header(SpeexHeader *header, int rate, int nb_channels, const Spe header->bitrate = -1; speex_mode_query(m, SPEEX_MODE_FRAME_SIZE, &header->frame_size); header->vbr = 0; - + header->frames_per_packet = 0; header->extra_headers = 0; header->reserved1 = 0; header->reserved2 = 0; } -char *speex_header_to_packet(SpeexHeader *header, int *size) +EXPORT char *speex_header_to_packet(SpeexHeader *header, int *size) { SpeexHeader *le_header; le_header = (SpeexHeader*)speex_alloc(sizeof(SpeexHeader)); - + SPEEX_COPY(le_header, header, 1); - + /*Make sure everything is now little-endian*/ ENDIAN_SWITCH(le_header->speex_version_id); ENDIAN_SWITCH(le_header->header_size); @@ -147,7 +147,7 @@ char *speex_header_to_packet(SpeexHeader *header, int *size) #endif /* SPEEX_DISABLE_ENCODER */ static SpeexHeader global_le_header; /* Avoid malloc */ -SpeexHeader *speex_packet_to_header(char *packet, int size) +EXPORT SpeexHeader *speex_packet_to_header(char *packet, int size) { int i; SpeexHeader *le_header = &global_le_header; @@ -158,18 +158,18 @@ SpeexHeader *speex_packet_to_header(char *packet, int size) speex_notify("This doesn't look like a Speex file"); return NULL; } - + /*FIXME: Do we allow larger headers?*/ if (size < (int)sizeof(SpeexHeader)) { speex_notify("Speex header too small"); return NULL; } - + /* le_header = (SpeexHeader*)speex_alloc(sizeof(SpeexHeader)); */ - + SPEEX_COPY(le_header, (SpeexHeader*)packet, 1); - + /*Make sure everything is converted correctly from little-endian*/ ENDIAN_SWITCH(le_header->speex_version_id); ENDIAN_SWITCH(le_header->header_size); @@ -183,6 +183,25 @@ SpeexHeader *speex_packet_to_header(char *packet, int size) ENDIAN_SWITCH(le_header->frames_per_packet); ENDIAN_SWITCH(le_header->extra_headers); + if (le_header->mode >= SPEEX_NB_MODES || le_header->mode < 0) + { + speex_notify("Invalid mode specified in Speex header"); + speex_free (le_header); + return NULL; + } + + if (le_header->nb_channels>2) + le_header->nb_channels = 2; + if (le_header->nb_channels<1) + le_header->nb_channels = 1; + return le_header; } + +#if 0 /* Unused by rockbox */ +EXPORT void speex_header_free(void *ptr) +{ + speex_free(ptr); +} +#endif diff --git a/lib/rbcodec/codecs/libspeex/stereo.c b/lib/rbcodec/codecs/libspeex/stereo.c index 0aca1050fa..e995cde093 100644 --- a/lib/rbcodec/codecs/libspeex/stereo.c +++ b/lib/rbcodec/codecs/libspeex/stereo.c @@ -1,21 +1,21 @@ -/* Copyright (C) 2002 Jean-Marc Valin +/* Copyright (C) 2002 Jean-Marc Valin File: stereo.c 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 the Xiph.org Foundation 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 @@ -71,11 +71,11 @@ static const spx_word16_t balance_bounds[31] = {18, 23, 30, 38, 49, 63, 81, 104 #ifdef FIXED_POINT #define COMPATIBILITY_HACK(s) do {if ((s)->reserved1 != 0xdeadbeef) speex_stereo_state_reset((SpeexStereoState*)s); } while (0); #else -#define COMPATIBILITY_HACK(s) +#define COMPATIBILITY_HACK(s) #endif static SpeexStereoState global_stereo_state; -SpeexStereoState *speex_stereo_state_init() +EXPORT SpeexStereoState *speex_stereo_state_init() { /* SpeexStereoState *stereo = speex_alloc(sizeof(SpeexStereoState)); */ SpeexStereoState *stereo = &global_stereo_state; @@ -83,7 +83,7 @@ SpeexStereoState *speex_stereo_state_init() return stereo; } -void speex_stereo_state_reset(SpeexStereoState *_stereo) +EXPORT void speex_stereo_state_reset(SpeexStereoState *_stereo) { RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo; #ifdef FIXED_POINT @@ -100,10 +100,10 @@ void speex_stereo_state_reset(SpeexStereoState *_stereo) stereo->smooth_right = 1.f; stereo->reserved1 = 0; stereo->reserved2 = 0; -#endif +#endif } -void speex_stereo_state_destroy(SpeexStereoState *stereo) +EXPORT void speex_stereo_state_destroy(SpeexStereoState *stereo) { (void)stereo; /* speex_free(stereo); */ @@ -111,7 +111,7 @@ void speex_stereo_state_destroy(SpeexStereoState *stereo) #ifndef SPEEX_DISABLE_ENCODER #ifndef DISABLE_FLOAT_API -void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits) +EXPORT void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits) { int i, tmp; float e_left=0, e_right=0, e_tot=0; @@ -129,7 +129,7 @@ void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits) /*Quantization*/ speex_bits_pack(bits, 14, 5); speex_bits_pack(bits, SPEEX_INBAND_STEREO, 4); - + balance=4*log(balance); /*Pack sign*/ @@ -140,16 +140,16 @@ void speex_encode_stereo(float *data, int frame_size, SpeexBits *bits) balance=floor(.5+fabs(balance)); if (balance>30) balance=31; - + speex_bits_pack(bits, (int)balance, 5); - + /* FIXME: this is a hack */ tmp=scal_quant(e_ratio*Q15_ONE, e_ratio_quant_bounds, 4); speex_bits_pack(bits, tmp, 2); } #endif /* #ifndef DISABLE_FLOAT_API */ -void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits) +EXPORT void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits) { int i, tmp; spx_word32_t e_left=0, e_right=0, e_tot=0; @@ -159,7 +159,7 @@ void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits) #ifdef FIXED_POINT int shift; #endif - + /* In band marker */ speex_bits_pack(bits, 14, 5); /* Stereo marker */ @@ -204,9 +204,9 @@ void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits) if (balance_id>30) balance_id=31; #endif - + speex_bits_pack(bits, balance_id, 5); - + /* "coherence" quantisation */ #ifdef FIXED_POINT shift = spx_ilog2(e_tot); @@ -217,7 +217,7 @@ void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits) #else e_ratio = e_tot/(1.+e_left+e_right); #endif - + tmp=scal_quant(EXTRACT16(e_ratio), e_ratio_quant_bounds, 4); /*fprintf (stderr, "%d %d %d %d\n", largest, smallest, balance_id, e_ratio);*/ speex_bits_pack(bits, tmp, 2); @@ -225,18 +225,18 @@ void speex_encode_stereo_int(spx_int16_t *data, int frame_size, SpeexBits *bits) #endif /* SPEEX_DISABLE_ENCODER */ #ifndef DISABLE_FLOAT_API -void speex_decode_stereo(float *data, int frame_size, SpeexStereoState *_stereo) +EXPORT void speex_decode_stereo(float *data, int frame_size, SpeexStereoState *_stereo) { int i; spx_word32_t balance; spx_word16_t e_left, e_right, e_ratio; RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo; - + COMPATIBILITY_HACK(stereo); - + balance=stereo->balance; e_ratio=stereo->e_ratio; - + /* These two are Q14, with max value just below 2. */ e_right = DIV32(QCONST32(1., 22), spx_sqrt(MULT16_32_Q15(e_ratio, ADD32(QCONST32(1., 16), balance)))); e_left = SHR32(MULT16_16(spx_sqrt(balance), e_right), 8); @@ -252,7 +252,7 @@ void speex_decode_stereo(float *data, int frame_size, SpeexStereoState *_stereo) } #endif /* #ifndef DISABLE_FLOAT_API */ -void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState *_stereo) +EXPORT void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState *_stereo) { int i; spx_word32_t balance; @@ -260,10 +260,10 @@ void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState RealSpeexStereoState *stereo = (RealSpeexStereoState*)_stereo; /* COMPATIBILITY_HACK(stereo); */ - + balance=stereo->balance; e_ratio=stereo->e_ratio; - + /* These two are Q14, with max value just below 2. */ e_right = DIV32(QCONST32(1., 22), spx_sqrt(MULT16_32_Q15(e_ratio, ADD32(QCONST32(1., 16), balance)))); e_left = SHR32(MULT16_16(spx_sqrt(balance), e_right), 8); @@ -278,7 +278,7 @@ void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState } } -int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data) +EXPORT int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data) { (void)state; RealSpeexStereoState *stereo; @@ -286,7 +286,7 @@ int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data) int tmp; stereo = (RealSpeexStereoState*)data; - + /* COMPATIBILITY_HACK(stereo); */ if (speex_bits_unpack_unsigned(bits, 1)) -- cgit v1.2.3