forked from len0rd/rockbox
* Sync Speex codec with Speex SVN revision 12449 (roughly Speex 1.2beta1).
* Redo the changes required to make Speex compile in Rockbox. Should be a bit easier to keep in sync with Speex SVN now. * Fix name of Speex library in codecs Makefile. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12254 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
5158751263
commit
7bf62e8da6
70 changed files with 4847 additions and 3314 deletions
|
@ -17,7 +17,7 @@ ifdef APPEXTRA
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifdef SOFTWARECODECS
|
ifdef SOFTWARECODECS
|
||||||
CODECLIBS = -lmad -la52 -lffmpegFLAC -lTremor -lwavpack -lmusepack -lalac -lfaad -lm4a -lspeex
|
CODECLIBS = -lmad -la52 -lffmpegFLAC -lTremor -lwavpack -lmusepack -lalac -lfaad -lm4a -lspeex
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# we "borrow" the plugin LDS file
|
# we "borrow" the plugin LDS file
|
||||||
|
@ -39,7 +39,7 @@ DIRS = .
|
||||||
|
|
||||||
CODECDEPS = $(LINKCODEC) $(BUILDDIR)/libcodec.a
|
CODECDEPS = $(LINKCODEC) $(BUILDDIR)/libcodec.a
|
||||||
|
|
||||||
.PHONY: libmad liba52 libffmpegFLAC libTremor libspeex libwavpack libmusepack libalac libfaad libm4a
|
.PHONY: libmad liba52 libffmpegFLAC libTremor libspeex libwavpack libmusepack libalac libfaad libm4a
|
||||||
|
|
||||||
OUTPUT = $(SOFTWARECODECS)
|
OUTPUT = $(SOFTWARECODECS)
|
||||||
|
|
||||||
|
@ -164,9 +164,7 @@ $(BUILDDIR)/libspeex.a: libspeex
|
||||||
|
|
||||||
libspeex:
|
libspeex:
|
||||||
$(SILENT)mkdir -p $(OBJDIR)/libspeex
|
$(SILENT)mkdir -p $(OBJDIR)/libspeex
|
||||||
$(call PRINTS,MAKE in Tremor)$(MAKE) -C libspeex OBJDIR=$(OBJDIR)/libspeex OUTPUT=$(BUILDDIR)/libspeex.a
|
$(call PRINTS,MAKE in libspeex)$(MAKE) -C libspeex OBJDIR=$(OBJDIR)/libspeex OUTPUT=$(BUILDDIR)/libspeex.a
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$(BUILDDIR)/libwavpack.a: libwavpack
|
$(BUILDDIR)/libwavpack.a: libwavpack
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ ifdef APPEXTRA
|
||||||
INCLUDES += $(patsubst %,-I$(APPSDIR)/%,$(subst :, ,$(APPEXTRA)))
|
INCLUDES += $(patsubst %,-I$(APPSDIR)/%,$(subst :, ,$(APPEXTRA)))
|
||||||
endif
|
endif
|
||||||
|
|
||||||
SPEEXOPTS = -O
|
SPEEXOPTS = -O -DHAVE_CONFIG_H
|
||||||
CFLAGS = $(INCLUDES) $(GCCOPTS) $(TARGET_INC) $(SPEEXOPTS) $(TARGET) \
|
CFLAGS = $(INCLUDES) $(GCCOPTS) $(TARGET_INC) $(SPEEXOPTS) $(TARGET) \
|
||||||
$(EXTRA_DEFINES) -DMEM=${MEMORYSIZE} ${PROFILE_OPTS} -Wno-unused-parameter
|
$(EXTRA_DEFINES) -DMEM=${MEMORYSIZE} ${PROFILE_OPTS} -Wno-unused-parameter
|
||||||
|
|
||||||
|
|
|
@ -1,38 +1,45 @@
|
||||||
nb_celp.c
|
|
||||||
sb_celp.c
|
|
||||||
lpc.c
|
|
||||||
ltp.c
|
|
||||||
lsp.c
|
|
||||||
quant_lsp.c
|
|
||||||
lsp_tables_nb.c
|
|
||||||
gain_table.c
|
|
||||||
gain_table_lbr.c
|
|
||||||
cb_search.c
|
|
||||||
filters.c
|
|
||||||
bits.c
|
bits.c
|
||||||
modes.c
|
cb_search.c
|
||||||
speex.c
|
exc_10_16_table.c
|
||||||
vq.c
|
exc_10_32_table.c
|
||||||
high_lsp_tables.c
|
exc_20_32_table.c
|
||||||
vbr.c
|
|
||||||
hexc_table.c
|
|
||||||
exc_5_256_table.c
|
exc_5_256_table.c
|
||||||
exc_5_64_table.c
|
exc_5_64_table.c
|
||||||
exc_8_128_table.c
|
exc_8_128_table.c
|
||||||
exc_10_32_table.c
|
|
||||||
exc_10_16_table.c
|
|
||||||
exc_20_32_table.c
|
|
||||||
hexc_10_32_table.c
|
|
||||||
misc.c
|
|
||||||
speex_header.c
|
|
||||||
speex_callbacks.c
|
|
||||||
math_approx.c
|
|
||||||
stereo.c
|
|
||||||
preprocess.c
|
|
||||||
jitter.c
|
|
||||||
mdf.c
|
|
||||||
fftwrap.c
|
fftwrap.c
|
||||||
|
filterbank.c
|
||||||
|
filters.c
|
||||||
|
gain_table.c
|
||||||
|
gain_table_lbr.c
|
||||||
|
hexc_10_32_table.c
|
||||||
|
hexc_table.c
|
||||||
|
high_lsp_tables.c
|
||||||
|
jitter.c
|
||||||
kiss_fft.c
|
kiss_fft.c
|
||||||
kiss_fftr.c
|
kiss_fftr.c
|
||||||
window.c
|
lbr_48k_tables.c
|
||||||
|
lpc.c
|
||||||
|
lsp.c
|
||||||
|
lsp_tables_nb.c
|
||||||
|
ltp.c
|
||||||
|
math_approx.c
|
||||||
|
mdf.c
|
||||||
|
medfilter.c
|
||||||
|
misc.c
|
||||||
|
modes.c
|
||||||
|
nb_celp.c
|
||||||
oggframing.c
|
oggframing.c
|
||||||
|
preprocess.c
|
||||||
|
quant_lsp.c
|
||||||
|
resample.c
|
||||||
|
rockbox.c
|
||||||
|
sb_celp.c
|
||||||
|
smallft.c
|
||||||
|
speex.c
|
||||||
|
speex_callbacks.c
|
||||||
|
speex_header.c
|
||||||
|
stereo.c
|
||||||
|
vbr.c
|
||||||
|
vorbis_psy.c
|
||||||
|
vq.c
|
||||||
|
window.c
|
||||||
|
|
|
@ -11,18 +11,16 @@ Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
|
||||||
*/
|
*/
|
||||||
#ifndef MIN
|
|
||||||
#define MIN(a,b) ((a)<(b) ? (a):(b))
|
#define MIN(a,b) ((a)<(b) ? (a):(b))
|
||||||
#endif
|
|
||||||
#ifndef MAX
|
|
||||||
#define MAX(a,b) ((a)>(b) ? (a):(b))
|
#define MAX(a,b) ((a)>(b) ? (a):(b))
|
||||||
#endif
|
|
||||||
|
|
||||||
/* kiss_fft.h
|
/* kiss_fft.h
|
||||||
defines kiss_fft_scalar as either short or a float type
|
defines kiss_fft_scalar as either short or a float type
|
||||||
and defines
|
and defines
|
||||||
typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */
|
typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */
|
||||||
#include "kiss_fft.h"
|
#include "kiss_fft.h"
|
||||||
|
#include "math_approx.h"
|
||||||
|
|
||||||
#define MAXFACTORS 32
|
#define MAXFACTORS 32
|
||||||
/* e.g. an fft of length 128 has 4 factors
|
/* e.g. an fft of length 128 has 4 factors
|
||||||
|
@ -143,6 +141,11 @@ struct kiss_fft_state{
|
||||||
(x)->r = KISS_FFT_COS(phase);\
|
(x)->r = KISS_FFT_COS(phase);\
|
||||||
(x)->i = KISS_FFT_SIN(phase);\
|
(x)->i = KISS_FFT_SIN(phase);\
|
||||||
}while(0)
|
}while(0)
|
||||||
|
#define kf_cexp2(x,phase) \
|
||||||
|
do{ \
|
||||||
|
(x)->r = spx_cos_norm((phase));\
|
||||||
|
(x)->i = spx_cos_norm((phase)-32768);\
|
||||||
|
}while(0)
|
||||||
|
|
||||||
|
|
||||||
/* a debugging function */
|
/* a debugging function */
|
||||||
|
|
|
@ -35,16 +35,15 @@
|
||||||
#ifndef ARCH_H
|
#ifndef ARCH_H
|
||||||
#define ARCH_H
|
#define ARCH_H
|
||||||
|
|
||||||
//#warning "----------------Arch.h-------------"
|
|
||||||
#include "speex/speex_types.h"
|
#include "speex/speex_types.h"
|
||||||
|
|
||||||
|
|
||||||
#define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer value. */
|
#define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer value. */
|
||||||
#define ABS16(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 16-bit value. */
|
#define ABS16(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 16-bit value. */
|
||||||
|
#define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 16-bit value. */
|
||||||
#define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */
|
#define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */
|
||||||
#define ABS32(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 32-bit value. */
|
#define ABS32(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 32-bit value. */
|
||||||
|
#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 32-bit value. */
|
||||||
#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */
|
#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */
|
||||||
#define FIXED_POINT
|
|
||||||
|
|
||||||
#ifdef FIXED_POINT
|
#ifdef FIXED_POINT
|
||||||
|
|
||||||
|
@ -71,6 +70,7 @@ typedef spx_word32_t spx_sig_t;
|
||||||
#define VERY_SMALL 0
|
#define VERY_SMALL 0
|
||||||
#define VERY_LARGE32 ((spx_word32_t)2147483647)
|
#define VERY_LARGE32 ((spx_word32_t)2147483647)
|
||||||
#define VERY_LARGE16 ((spx_word16_t)32767)
|
#define VERY_LARGE16 ((spx_word16_t)32767)
|
||||||
|
#define Q15_ONE ((spx_word16_t)32767)
|
||||||
|
|
||||||
|
|
||||||
#ifdef FIXED_DEBUG
|
#ifdef FIXED_DEBUG
|
||||||
|
@ -79,7 +79,7 @@ typedef spx_word32_t spx_sig_t;
|
||||||
|
|
||||||
#include "fixed_generic.h"
|
#include "fixed_generic.h"
|
||||||
|
|
||||||
#if defined (ARM5E_ASM)
|
#ifdef ARM5E_ASM
|
||||||
#include "fixed_arm5e.h"
|
#include "fixed_arm5e.h"
|
||||||
#elif defined (ARM4_ASM)
|
#elif defined (ARM4_ASM)
|
||||||
#include "fixed_arm4.h"
|
#include "fixed_arm4.h"
|
||||||
|
@ -116,6 +116,7 @@ typedef float spx_word32_t;
|
||||||
#define VERY_SMALL 1e-15f
|
#define VERY_SMALL 1e-15f
|
||||||
#define VERY_LARGE32 1e15f
|
#define VERY_LARGE32 1e15f
|
||||||
#define VERY_LARGE16 1e15f
|
#define VERY_LARGE16 1e15f
|
||||||
|
#define Q15_ONE ((spx_word16_t)1.f)
|
||||||
|
|
||||||
#define QCONST16(x,bits) (x)
|
#define QCONST16(x,bits) (x)
|
||||||
#define QCONST32(x,bits) (x)
|
#define QCONST32(x,bits) (x)
|
||||||
|
@ -130,6 +131,7 @@ typedef float spx_word32_t;
|
||||||
#define SHL32(a,shift) (a)
|
#define SHL32(a,shift) (a)
|
||||||
#define PSHR16(a,shift) (a)
|
#define PSHR16(a,shift) (a)
|
||||||
#define PSHR32(a,shift) (a)
|
#define PSHR32(a,shift) (a)
|
||||||
|
#define VSHR32(a,shift) (a)
|
||||||
#define SATURATE16(x,a) (x)
|
#define SATURATE16(x,a) (x)
|
||||||
#define SATURATE32(x,a) (x)
|
#define SATURATE32(x,a) (x)
|
||||||
|
|
||||||
|
@ -150,6 +152,7 @@ typedef float spx_word32_t;
|
||||||
#define MULT16_32_Q13(a,b) ((a)*(b))
|
#define MULT16_32_Q13(a,b) ((a)*(b))
|
||||||
#define MULT16_32_Q14(a,b) ((a)*(b))
|
#define MULT16_32_Q14(a,b) ((a)*(b))
|
||||||
#define MULT16_32_Q15(a,b) ((a)*(b))
|
#define MULT16_32_Q15(a,b) ((a)*(b))
|
||||||
|
#define MULT16_32_P15(a,b) ((a)*(b))
|
||||||
|
|
||||||
#define MAC16_32_Q11(c,a,b) ((c)+(a)*(b))
|
#define MAC16_32_Q11(c,a,b) ((c)+(a)*(b))
|
||||||
#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b))
|
#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b))
|
||||||
|
|
|
@ -76,6 +76,7 @@ void speex_bits_destroy(SpeexBits *bits)
|
||||||
|
|
||||||
void speex_bits_reset(SpeexBits *bits)
|
void speex_bits_reset(SpeexBits *bits)
|
||||||
{
|
{
|
||||||
|
/* We only need to clear the first byte now */
|
||||||
bits->chars[0]=0;
|
bits->chars[0]=0;
|
||||||
bits->nbBits=0;
|
bits->nbBits=0;
|
||||||
bits->charPtr=0;
|
bits->charPtr=0;
|
||||||
|
@ -225,11 +226,10 @@ void speex_bits_pack(SpeexBits *bits, int data, int nbBits)
|
||||||
speex_warning("Buffer too small to pack bits");
|
speex_warning("Buffer too small to pack bits");
|
||||||
if (bits->owner)
|
if (bits->owner)
|
||||||
{
|
{
|
||||||
int new_nchars = ((bits->buf_size+5)*3)>>1;
|
int new_nchars = ((bits->buf_size+5)*3)>>1;
|
||||||
char *tmp = (char*)speex_realloc(bits->chars, new_nchars);
|
char *tmp = (char*)speex_realloc(bits->chars, new_nchars);
|
||||||
if (tmp)
|
if (tmp)
|
||||||
{
|
{
|
||||||
speex_memset_bytes(tmp, 0, new_nchars);
|
|
||||||
bits->buf_size=new_nchars;
|
bits->buf_size=new_nchars;
|
||||||
bits->chars=tmp;
|
bits->chars=tmp;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -226,11 +226,13 @@ int update_target
|
||||||
/* Update target: only update target if necessary */
|
/* Update target: only update target if necessary */
|
||||||
if (update_target)
|
if (update_target)
|
||||||
{
|
{
|
||||||
VARDECL(spx_sig_t *r2);
|
VARDECL(spx_word16_t *r2);
|
||||||
ALLOC(r2, nsf, spx_sig_t);
|
ALLOC(r2, nsf, spx_word16_t);
|
||||||
syn_percep_zero(e, ak, awk1, awk2, r2, nsf,p, stack);
|
|
||||||
for (j=0;j<nsf;j++)
|
for (j=0;j<nsf;j++)
|
||||||
target[j]=SUB16(target[j],EXTRACT16(PSHR32(r2[j],8)));
|
r2[j] = EXTRACT16(PSHR32(e[j] ,6));
|
||||||
|
syn_percep_zero16(r2, ak, awk1, awk2, r2, nsf,p, stack);
|
||||||
|
for (j=0;j<nsf;j++)
|
||||||
|
target[j]=SUB16(target[j],PSHR16(r2[j],2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,7 +265,6 @@ int update_target
|
||||||
#endif
|
#endif
|
||||||
VARDECL(spx_word16_t *t);
|
VARDECL(spx_word16_t *t);
|
||||||
VARDECL(spx_sig_t *e);
|
VARDECL(spx_sig_t *e);
|
||||||
VARDECL(spx_sig_t *r2);
|
|
||||||
VARDECL(spx_word16_t *tmp);
|
VARDECL(spx_word16_t *tmp);
|
||||||
VARDECL(spx_word32_t *ndist);
|
VARDECL(spx_word32_t *ndist);
|
||||||
VARDECL(spx_word32_t *odist);
|
VARDECL(spx_word32_t *odist);
|
||||||
|
@ -316,7 +317,6 @@ int update_target
|
||||||
#endif
|
#endif
|
||||||
ALLOC(t, nsf, spx_word16_t);
|
ALLOC(t, nsf, spx_word16_t);
|
||||||
ALLOC(e, nsf, spx_sig_t);
|
ALLOC(e, nsf, spx_sig_t);
|
||||||
ALLOC(r2, nsf, spx_sig_t);
|
|
||||||
ALLOC(ind, nb_subvect, int);
|
ALLOC(ind, nb_subvect, int);
|
||||||
|
|
||||||
ALLOC(tmp, 2*N*nsf, spx_word16_t);
|
ALLOC(tmp, 2*N*nsf, spx_word16_t);
|
||||||
|
@ -495,9 +495,13 @@ int update_target
|
||||||
/* Update target: only update target if necessary */
|
/* Update target: only update target if necessary */
|
||||||
if (update_target)
|
if (update_target)
|
||||||
{
|
{
|
||||||
syn_percep_zero(e, ak, awk1, awk2, r2, nsf,p, stack);
|
VARDECL(spx_word16_t *r2);
|
||||||
|
ALLOC(r2, nsf, spx_word16_t);
|
||||||
for (j=0;j<nsf;j++)
|
for (j=0;j<nsf;j++)
|
||||||
target[j]=SUB16(target[j],EXTRACT16(PSHR32(r2[j],8)));
|
r2[j] = EXTRACT16(PSHR32(e[j] ,6));
|
||||||
|
syn_percep_zero16(r2, ak, awk1, awk2, r2, nsf,p, stack);
|
||||||
|
for (j=0;j<nsf;j++)
|
||||||
|
target[j]=SUB16(target[j],PSHR16(r2[j],2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -577,14 +581,12 @@ int update_target
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
VARDECL(spx_sig_t *tmp);
|
VARDECL(spx_word16_t *tmp);
|
||||||
ALLOC(tmp, nsf, spx_sig_t);
|
ALLOC(tmp, nsf, spx_word16_t);
|
||||||
for (i=0;i<nsf;i++)
|
residue_percep_zero16(target, ak, awk1, awk2, tmp, nsf, p, stack);
|
||||||
tmp[i]=PSHR32(EXTEND32(target[i]),SIG_SHIFT);
|
|
||||||
residue_percep_zero(tmp, ak, awk1, awk2, tmp, nsf, p, stack);
|
|
||||||
|
|
||||||
for (i=0;i<nsf;i++)
|
for (i=0;i<nsf;i++)
|
||||||
exc[i]+=tmp[i];
|
exc[i]+=SHL32(EXTEND32(tmp[i]),8);
|
||||||
for (i=0;i<nsf;i++)
|
for (i=0;i<nsf;i++)
|
||||||
target[i]=0;
|
target[i]=0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,7 +73,10 @@ void compute_weighted_codebook(const signed char *shape_cb, const spx_word16_t *
|
||||||
:
|
:
|
||||||
: "m" (subvect_size), "m" (shape_cb), "m" (r), "m" (resp), "m" (E)
|
: "m" (subvect_size), "m" (shape_cb), "m" (r), "m" (resp), "m" (E)
|
||||||
: "A0", "P0", "P1", "P2", "P3", "P4", "R0", "R1", "R2", "I0", "I1", "L0",
|
: "A0", "P0", "P1", "P2", "P3", "P4", "R0", "R1", "R2", "I0", "I1", "L0",
|
||||||
"L1", "A0", "A1", "memory", "LC0", "LC1"
|
"L1", "A0", "A1", "memory"
|
||||||
|
#if !(__GNUC__ == 3)
|
||||||
|
, "LC0", "LC1" /* gcc 3.4 doesn't know about LC registers */
|
||||||
|
#endif
|
||||||
);
|
);
|
||||||
shape_cb += subvect_size;
|
shape_cb += subvect_size;
|
||||||
resp += subvect_size;
|
resp += subvect_size;
|
||||||
|
|
166
apps/codecs/libspeex/config.h
Normal file
166
apps/codecs/libspeex/config.h
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
#include "autoconf.h"
|
||||||
|
/* config.h. Generated from config.h.in by configure. */
|
||||||
|
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||||
|
|
||||||
|
/* Make use of ARM4 assembly optimizations */
|
||||||
|
/* #undef ARM4_ASM */
|
||||||
|
|
||||||
|
/* Make use of ARM5E assembly optimizations */
|
||||||
|
#if defined(CPU_ARM) && !defined(SIMULATOR)
|
||||||
|
#define ARM5E_ASM 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Make use of Blackfin assembly optimizations */
|
||||||
|
/* #undef BFIN_ASM */
|
||||||
|
|
||||||
|
/* Disable wideband codec */
|
||||||
|
/* #undef DISABLE_WIDEBAND */
|
||||||
|
|
||||||
|
/* Enable valgrind extra checks */
|
||||||
|
/* #undef ENABLE_VALGRIND */
|
||||||
|
|
||||||
|
/* Enable support for Epic 4.8 kbps mode */
|
||||||
|
/* #undef EPIC_48K */
|
||||||
|
|
||||||
|
/* Debug fixed-point implementation */
|
||||||
|
/* #undef FIXED_DEBUG */
|
||||||
|
|
||||||
|
/* Compile as fixed-point */
|
||||||
|
#define FIXED_POINT
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||||
|
/* #undef HAVE_DLFCN_H */
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `getopt_long' function. */
|
||||||
|
#define HAVE_GETOPT_LONG 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <inttypes.h> header file. */
|
||||||
|
#define HAVE_INTTYPES_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `m' library (-lm). */
|
||||||
|
/* #undef HAVE_LIBM */
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `winmm' library (-lwinmm). */
|
||||||
|
/* #undef HAVE_LIBWINMM */
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <memory.h> header file. */
|
||||||
|
#define HAVE_MEMORY_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <stdint.h> header file. */
|
||||||
|
#define HAVE_STDINT_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <stdlib.h> header file. */
|
||||||
|
#define HAVE_STDLIB_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <strings.h> header file. */
|
||||||
|
#define HAVE_STRINGS_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <string.h> header file. */
|
||||||
|
#define HAVE_STRING_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/audioio.h> header file. */
|
||||||
|
/* #undef HAVE_SYS_AUDIOIO_H */
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/soundcard.h> header file. */
|
||||||
|
#define HAVE_SYS_SOUNDCARD_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||||
|
#define HAVE_SYS_STAT_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||||
|
#define HAVE_SYS_TYPES_H 1
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <unistd.h> header file. */
|
||||||
|
#define HAVE_UNISTD_H 1
|
||||||
|
|
||||||
|
/* Define to the address where bug reports for this package should be sent. */
|
||||||
|
#define PACKAGE_BUGREPORT ""
|
||||||
|
|
||||||
|
/* Define to the full name of this package. */
|
||||||
|
#define PACKAGE_NAME ""
|
||||||
|
|
||||||
|
/* Define to the full name and version of this package. */
|
||||||
|
#define PACKAGE_STRING ""
|
||||||
|
|
||||||
|
/* Define to the one symbol short name of this package. */
|
||||||
|
#define PACKAGE_TARNAME ""
|
||||||
|
|
||||||
|
/* Define to the version of this package. */
|
||||||
|
#define PACKAGE_VERSION ""
|
||||||
|
|
||||||
|
/* Reduce precision to 16 bits (EXPERIMENTAL) */
|
||||||
|
/* #undef PRECISION16 */
|
||||||
|
|
||||||
|
/* The size of `int', as computed by sizeof. */
|
||||||
|
#define SIZEOF_INT 4
|
||||||
|
|
||||||
|
/* The size of `long', as computed by sizeof. */
|
||||||
|
#define SIZEOF_LONG 4
|
||||||
|
|
||||||
|
/* The size of `short', as computed by sizeof. */
|
||||||
|
#define SIZEOF_SHORT 2
|
||||||
|
|
||||||
|
/* Version extra */
|
||||||
|
#define SPEEX_EXTRA_VERSION "-svn"
|
||||||
|
|
||||||
|
/* Version major */
|
||||||
|
#define SPEEX_MAJOR_VERSION 1
|
||||||
|
|
||||||
|
/* Version micro */
|
||||||
|
#define SPEEX_MICRO_VERSION 14
|
||||||
|
|
||||||
|
/* Version minor */
|
||||||
|
#define SPEEX_MINOR_VERSION 1
|
||||||
|
|
||||||
|
/* Complete version string */
|
||||||
|
#define SPEEX_VERSION "1.1.14-svn"
|
||||||
|
|
||||||
|
/* Define to 1 if you have the ANSI C header files. */
|
||||||
|
#define STDC_HEADERS 1
|
||||||
|
|
||||||
|
/* Enable support for TI C55X DSP */
|
||||||
|
/* #undef TI_C55X */
|
||||||
|
|
||||||
|
/* Make use of alloca */
|
||||||
|
/* #undef USE_ALLOCA */
|
||||||
|
|
||||||
|
/* Use C99 variable-size arrays */
|
||||||
|
#define VAR_ARRAYS
|
||||||
|
|
||||||
|
/* Enable Vorbis-style psychoacoustics (EXPERIMENTAL) */
|
||||||
|
/* #undef VORBIS_PSYCHO */
|
||||||
|
|
||||||
|
/* Define to 1 if your processor stores words with the most significant byte
|
||||||
|
first (like Motorola and SPARC, unlike Intel and VAX). */
|
||||||
|
#ifdef ROCKBOX_BIG_ENDIAN
|
||||||
|
#define WORDS_BIGENDIAN 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Enable SSE support */
|
||||||
|
/* #undef _USE_SSE */
|
||||||
|
|
||||||
|
/* Define to empty if `const' does not conform to ANSI C. */
|
||||||
|
/* #undef const */
|
||||||
|
|
||||||
|
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||||
|
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||||
|
#ifndef __cplusplus
|
||||||
|
/* #undef inline */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Define to equivalent of C99 restrict keyword, or to nothing if this is not
|
||||||
|
supported. Do not define if restrict is supported directly. */
|
||||||
|
#define restrict __restrict
|
||||||
|
|
||||||
|
#define RELEASE 1
|
||||||
|
#define OVERRIDE_SPEEX_ALLOC 1
|
||||||
|
#define OVERRIDE_SPEEX_ALLOC_SCRATCH 1
|
||||||
|
#define OVERRIDE_SPEEX_REALLOC 1
|
||||||
|
#define OVERRIDE_SPEEX_FREE 1
|
||||||
|
#define OVERRIDE_SPEEX_FREE_SCRATCH 1
|
||||||
|
#define OVERRIDE_SPEEX_MOVE 1
|
||||||
|
#define OVERRIDE_SPEEX_ERROR 1
|
||||||
|
#define OVERRIDE_SPEEX_WARNING 1
|
||||||
|
#define OVERRIDE_SPEEX_WARNING_INT 1
|
||||||
|
#define OVERRIDE_SPEEX_PUTC 1
|
||||||
|
|
|
@ -41,7 +41,6 @@
|
||||||
|
|
||||||
|
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "math_approx.h"
|
|
||||||
|
|
||||||
#define MAX_FFT_SIZE 2048
|
#define MAX_FFT_SIZE 2048
|
||||||
|
|
||||||
|
@ -65,7 +64,7 @@ static int maximize_range(spx_word16_t *in, spx_word16_t *out, spx_word16_t boun
|
||||||
}
|
}
|
||||||
for (i=0;i<len;i++)
|
for (i=0;i<len;i++)
|
||||||
{
|
{
|
||||||
out[i] = in[i] << shift;
|
out[i] = SHL16(in[i], shift);
|
||||||
}
|
}
|
||||||
return shift;
|
return shift;
|
||||||
}
|
}
|
||||||
|
@ -75,7 +74,7 @@ static void renorm_range(spx_word16_t *in, spx_word16_t *out, int shift, int len
|
||||||
int i;
|
int i;
|
||||||
for (i=0;i<len;i++)
|
for (i=0;i<len;i++)
|
||||||
{
|
{
|
||||||
out[i] = (in[i] + (1<<(shift-1))) >> shift;
|
out[i] = PSHR16(in[i], shift);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -104,8 +103,8 @@ void spx_fft(void *table, float *in, float *out)
|
||||||
if (in==out)
|
if (in==out)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
speex_warning("FFT should not be done in-place");
|
|
||||||
float scale = 1./((struct drft_lookup *)table)->n;
|
float scale = 1./((struct drft_lookup *)table)->n;
|
||||||
|
speex_warning("FFT should not be done in-place");
|
||||||
for (i=0;i<((struct drft_lookup *)table)->n;i++)
|
for (i=0;i<((struct drft_lookup *)table)->n;i++)
|
||||||
out[i] = scale*in[i];
|
out[i] = scale*in[i];
|
||||||
} else {
|
} else {
|
||||||
|
@ -121,7 +120,6 @@ void spx_ifft(void *table, float *in, float *out)
|
||||||
{
|
{
|
||||||
if (in==out)
|
if (in==out)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
speex_warning("FFT should not be done in-place");
|
speex_warning("FFT should not be done in-place");
|
||||||
} else {
|
} else {
|
||||||
int i;
|
int i;
|
||||||
|
|
226
apps/codecs/libspeex/filterbank.c
Normal file
226
apps/codecs/libspeex/filterbank.c
Normal file
|
@ -0,0 +1,226 @@
|
||||||
|
/* Copyright (C) 2006 Jean-Marc Valin */
|
||||||
|
/**
|
||||||
|
@file filterbank.c
|
||||||
|
@brief Converting between psd and filterbank
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. 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.
|
||||||
|
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "filterbank.h"
|
||||||
|
#include "misc.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include "math_approx.h"
|
||||||
|
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
|
||||||
|
#define toBARK(n) (MULT16_16(26829,spx_atan(SHR32(MULT16_16(97,n),2))) + MULT16_16(4588,spx_atan(MULT16_32_Q15(20,MULT16_16(n,n)))) + MULT16_16(3355,n))
|
||||||
|
|
||||||
|
#else
|
||||||
|
#define toBARK(n) (13.1f*atan(.00074f*(n))+2.24f*atan((n)*(n)*1.85e-8f)+1e-4f*(n))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define toMEL(n) (2595.f*log10(1.f+(n)/700.f))
|
||||||
|
|
||||||
|
FilterBank *filterbank_new(int banks, spx_word32_t sampling, int len, int type)
|
||||||
|
{
|
||||||
|
FilterBank *bank;
|
||||||
|
spx_word32_t df;
|
||||||
|
spx_word32_t max_mel, mel_interval;
|
||||||
|
int i;
|
||||||
|
int id1;
|
||||||
|
int id2;
|
||||||
|
df = DIV32(SHL32(sampling,15),MULT16_16(2,len));
|
||||||
|
max_mel = toBARK(EXTRACT16(MULT16_16_Q15(QCONST16(.5f,15),sampling)));
|
||||||
|
mel_interval = PDIV32(max_mel,banks-1);
|
||||||
|
|
||||||
|
bank = (FilterBank*)speex_alloc(sizeof(FilterBank));
|
||||||
|
bank->nb_banks = banks;
|
||||||
|
bank->len = len;
|
||||||
|
bank->bank_left = (int*)speex_alloc(len*sizeof(int));
|
||||||
|
bank->bank_right = (int*)speex_alloc(len*sizeof(int));
|
||||||
|
bank->filter_left = (spx_word16_t*)speex_alloc(len*sizeof(spx_word16_t));
|
||||||
|
bank->filter_right = (spx_word16_t*)speex_alloc(len*sizeof(spx_word16_t));
|
||||||
|
/* Think I can safely disable normalisation that for fixed-point (and probably float as well) */
|
||||||
|
#ifndef FIXED_POINT
|
||||||
|
bank->scaling = (float*)speex_alloc(banks*sizeof(float));
|
||||||
|
#endif
|
||||||
|
for (i=0;i<len;i++)
|
||||||
|
{
|
||||||
|
spx_word16_t curr_freq;
|
||||||
|
spx_word32_t mel;
|
||||||
|
spx_word16_t val;
|
||||||
|
curr_freq = EXTRACT16(MULT16_32_P15(i,df));
|
||||||
|
mel = toBARK(curr_freq);
|
||||||
|
if (mel > max_mel)
|
||||||
|
break;
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
id1 = DIV32(mel,mel_interval);
|
||||||
|
#else
|
||||||
|
id1 = (int)(floor(mel/mel_interval));
|
||||||
|
#endif
|
||||||
|
if (id1>banks-2)
|
||||||
|
{
|
||||||
|
id1 = banks-2;
|
||||||
|
val = Q15_ONE;
|
||||||
|
} else {
|
||||||
|
val = DIV32_16(mel - id1*mel_interval,EXTRACT16(PSHR32(mel_interval,15)));
|
||||||
|
}
|
||||||
|
id2 = id1+1;
|
||||||
|
bank->bank_left[i] = id1;
|
||||||
|
bank->filter_left[i] = SUB16(Q15_ONE,val);
|
||||||
|
bank->bank_right[i] = id2;
|
||||||
|
bank->filter_right[i] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Think I can safely disable normalisation for fixed-point (and probably float as well) */
|
||||||
|
#ifndef FIXED_POINT
|
||||||
|
for (i=0;i<bank->nb_banks;i++)
|
||||||
|
bank->scaling[i] = 0;
|
||||||
|
for (i=0;i<bank->len;i++)
|
||||||
|
{
|
||||||
|
int id = bank->bank_left[i];
|
||||||
|
bank->scaling[id] += bank->filter_left[i];
|
||||||
|
id = bank->bank_right[i];
|
||||||
|
bank->scaling[id] += bank->filter_right[i];
|
||||||
|
}
|
||||||
|
for (i=0;i<bank->nb_banks;i++)
|
||||||
|
bank->scaling[i] = Q15_ONE/(bank->scaling[i]);
|
||||||
|
#endif
|
||||||
|
return bank;
|
||||||
|
}
|
||||||
|
|
||||||
|
void filterbank_destroy(FilterBank *bank)
|
||||||
|
{
|
||||||
|
speex_free(bank->bank_left);
|
||||||
|
speex_free(bank->bank_right);
|
||||||
|
speex_free(bank->filter_left);
|
||||||
|
speex_free(bank->filter_right);
|
||||||
|
#ifndef FIXED_POINT
|
||||||
|
speex_free(bank->scaling);
|
||||||
|
#endif
|
||||||
|
speex_free(bank);
|
||||||
|
}
|
||||||
|
|
||||||
|
void filterbank_compute_bank32(FilterBank *bank, spx_word32_t *ps, spx_word32_t *mel)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i=0;i<bank->nb_banks;i++)
|
||||||
|
mel[i] = 0;
|
||||||
|
|
||||||
|
for (i=0;i<bank->len;i++)
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
id = bank->bank_left[i];
|
||||||
|
mel[id] += MULT16_32_P15(bank->filter_left[i],ps[i]);
|
||||||
|
id = bank->bank_right[i];
|
||||||
|
mel[id] += MULT16_32_P15(bank->filter_right[i],ps[i]);
|
||||||
|
}
|
||||||
|
/* Think I can safely disable normalisation that for fixed-point (and probably float as well) */
|
||||||
|
#ifndef FIXED_POINT
|
||||||
|
/*for (i=0;i<bank->nb_banks;i++)
|
||||||
|
mel[i] = MULT16_32_P15(Q15(bank->scaling[i]),mel[i]);
|
||||||
|
*/
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void filterbank_compute_psd16(FilterBank *bank, spx_word16_t *mel, spx_word16_t *ps)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i=0;i<bank->len;i++)
|
||||||
|
{
|
||||||
|
spx_word32_t tmp;
|
||||||
|
int id1, id2;
|
||||||
|
id1 = bank->bank_left[i];
|
||||||
|
id2 = bank->bank_right[i];
|
||||||
|
tmp = MULT16_16(mel[id1],bank->filter_left[i]);
|
||||||
|
tmp += MULT16_16(mel[id2],bank->filter_right[i]);
|
||||||
|
ps[i] = EXTRACT16(PSHR32(tmp,15));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef FIXED_POINT
|
||||||
|
void filterbank_compute_bank(FilterBank *bank, float *ps, float *mel)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i=0;i<bank->nb_banks;i++)
|
||||||
|
mel[i] = 0;
|
||||||
|
|
||||||
|
for (i=0;i<bank->len;i++)
|
||||||
|
{
|
||||||
|
int id = bank->bank_left[i];
|
||||||
|
mel[id] += bank->filter_left[i]*ps[i];
|
||||||
|
id = bank->bank_right[i];
|
||||||
|
mel[id] += bank->filter_right[i]*ps[i];
|
||||||
|
}
|
||||||
|
for (i=0;i<bank->nb_banks;i++)
|
||||||
|
mel[i] *= bank->scaling[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void filterbank_compute_psd(FilterBank *bank, float *mel, float *ps)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i=0;i<bank->len;i++)
|
||||||
|
{
|
||||||
|
int id = bank->bank_left[i];
|
||||||
|
ps[i] = mel[id]*bank->filter_left[i];
|
||||||
|
id = bank->bank_right[i];
|
||||||
|
ps[i] += mel[id]*bank->filter_right[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void filterbank_psy_smooth(FilterBank *bank, float *ps, float *mask)
|
||||||
|
{
|
||||||
|
/* Low freq slope: 14 dB/Bark*/
|
||||||
|
/* High freq slope: 9 dB/Bark*/
|
||||||
|
/* Noise vs tone: 5 dB difference */
|
||||||
|
/* FIXME: Temporary kludge */
|
||||||
|
float bark[100];
|
||||||
|
int i;
|
||||||
|
/* Assumes 1/3 Bark resolution */
|
||||||
|
float decay_low = 0.34145f;
|
||||||
|
float decay_high = 0.50119f;
|
||||||
|
filterbank_compute_bank(bank, ps, bark);
|
||||||
|
for (i=1;i<bank->nb_banks;i++)
|
||||||
|
{
|
||||||
|
/*float decay_high = 13-1.6*log10(bark[i-1]);
|
||||||
|
decay_high = pow(10,(-decay_high/30.f));*/
|
||||||
|
bark[i] = bark[i] + decay_high*bark[i-1];
|
||||||
|
}
|
||||||
|
for (i=bank->nb_banks-2;i>=0;i--)
|
||||||
|
{
|
||||||
|
bark[i] = bark[i] + decay_low*bark[i+1];
|
||||||
|
}
|
||||||
|
filterbank_compute_psd(bank, bark, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
66
apps/codecs/libspeex/filterbank.h
Normal file
66
apps/codecs/libspeex/filterbank.h
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
/* Copyright (C) 2006 Jean-Marc Valin */
|
||||||
|
/**
|
||||||
|
@file filterbank.h
|
||||||
|
@brief Converting between psd and filterbank
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. 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.
|
||||||
|
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FILTERBANK_H
|
||||||
|
#define FILTERBANK_H
|
||||||
|
|
||||||
|
#include "misc.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int *bank_left;
|
||||||
|
int *bank_right;
|
||||||
|
spx_word16_t *filter_left;
|
||||||
|
spx_word16_t *filter_right;
|
||||||
|
#ifndef FIXED_POINT
|
||||||
|
float *scaling;
|
||||||
|
#endif
|
||||||
|
int nb_banks;
|
||||||
|
int len;
|
||||||
|
} FilterBank;
|
||||||
|
|
||||||
|
|
||||||
|
FilterBank *filterbank_new(int banks, spx_word32_t sampling, int len, int type);
|
||||||
|
|
||||||
|
void filterbank_destroy(FilterBank *bank);
|
||||||
|
|
||||||
|
void filterbank_compute_bank32(FilterBank *bank, spx_word32_t *ps, spx_word32_t *mel);
|
||||||
|
|
||||||
|
void filterbank_compute_psd16(FilterBank *bank, spx_word16_t *mel, spx_word16_t *psd);
|
||||||
|
|
||||||
|
#ifndef FIXED_POINT
|
||||||
|
void filterbank_compute_bank(FilterBank *bank, float *psd, float *mel);
|
||||||
|
void filterbank_compute_psd(FilterBank *bank, float *mel, float *psd);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -83,8 +83,8 @@ void highpass(const spx_word16_t *x, spx_word16_t *y, int len, int filtID, spx_m
|
||||||
spx_word16_t yi;
|
spx_word16_t yi;
|
||||||
spx_word32_t vout = ADD32(MULT16_16(num[0], x[i]),mem[0]);
|
spx_word32_t vout = ADD32(MULT16_16(num[0], x[i]),mem[0]);
|
||||||
yi = EXTRACT16(SATURATE(PSHR32(vout,14),32767));
|
yi = EXTRACT16(SATURATE(PSHR32(vout,14),32767));
|
||||||
mem[0] = ADD32(MAC16_16(mem[1], num[1],x[i]), MULT16_32_Q14(-den[1],vout));
|
mem[0] = ADD32(MAC16_16(mem[1], num[1],x[i]), SHL32(MULT16_32_Q15(-den[1],vout),1));
|
||||||
mem[1] = ADD32(MULT16_16(num[2],x[i]), MULT16_32_Q14(-den[2],vout));
|
mem[1] = ADD32(MULT16_16(num[2],x[i]), SHL32(MULT16_32_Q15(-den[2],vout),1));
|
||||||
y[i] = yi;
|
y[i] = yi;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,10 +218,10 @@ spx_word16_t compute_rms16(const spx_word16_t *x, int len)
|
||||||
for (i=0;i<len;i+=4)
|
for (i=0;i<len;i+=4)
|
||||||
{
|
{
|
||||||
spx_word32_t sum2=0;
|
spx_word32_t sum2=0;
|
||||||
sum2 = MAC16_16(sum2,PSHR16(x[i],1),PSHR16(x[i],1));
|
sum2 = MAC16_16(sum2,SHR16(x[i],1),SHR16(x[i],1));
|
||||||
sum2 = MAC16_16(sum2,PSHR16(x[i+1],1),PSHR16(x[i+1],1));
|
sum2 = MAC16_16(sum2,SHR16(x[i+1],1),SHR16(x[i+1],1));
|
||||||
sum2 = MAC16_16(sum2,PSHR16(x[i+2],1),PSHR16(x[i+2],1));
|
sum2 = MAC16_16(sum2,SHR16(x[i+2],1),SHR16(x[i+2],1));
|
||||||
sum2 = MAC16_16(sum2,PSHR16(x[i+3],1),PSHR16(x[i+3],1));
|
sum2 = MAC16_16(sum2,SHR16(x[i+3],1),SHR16(x[i+3],1));
|
||||||
sum = ADD32(sum,SHR32(sum2,6));
|
sum = ADD32(sum,SHR32(sum2,6));
|
||||||
}
|
}
|
||||||
return SHL16(spx_sqrt(DIV32(sum,len)),4);
|
return SHL16(spx_sqrt(DIV32(sum,len)),4);
|
||||||
|
@ -297,53 +297,6 @@ spx_word16_t compute_rms16(const spx_word16_t *x, int len)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef OVERRIDE_FILTER_MEM2
|
|
||||||
#ifdef PRECISION16
|
|
||||||
void filter_mem2(const spx_sig_t *x, const spx_coef_t *num, const spx_coef_t *den, spx_sig_t *y, int N, int ord, spx_mem_t *mem)
|
|
||||||
{
|
|
||||||
int i,j;
|
|
||||||
spx_word16_t xi,yi,nyi;
|
|
||||||
|
|
||||||
for (i=0;i<N;i++)
|
|
||||||
{
|
|
||||||
xi= EXTRACT16(PSHR32(SATURATE(x[i],536870911),SIG_SHIFT));
|
|
||||||
yi = EXTRACT16(PSHR32(SATURATE(ADD32(x[i], SHL32(mem[0],1)),536870911),SIG_SHIFT));
|
|
||||||
nyi = NEG16(yi);
|
|
||||||
for (j=0;j<ord-1;j++)
|
|
||||||
{
|
|
||||||
mem[j] = MAC16_16(MAC16_16(mem[j+1], num[j],xi), den[j],nyi);
|
|
||||||
}
|
|
||||||
mem[ord-1] = ADD32(MULT16_16(num[ord-1],xi), MULT16_16(den[ord-1],nyi));
|
|
||||||
y[i] = SHL32(EXTEND32(yi),SIG_SHIFT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
void filter_mem2(const spx_sig_t *x, const spx_coef_t *num, const spx_coef_t *den, spx_sig_t *y, int N, int ord, spx_mem_t *mem)
|
|
||||||
{
|
|
||||||
int i,j;
|
|
||||||
spx_sig_t xi,yi,nyi;
|
|
||||||
|
|
||||||
for (i=0;i<ord;i++)
|
|
||||||
mem[i] = SHR32(mem[i],1);
|
|
||||||
for (i=0;i<N;i++)
|
|
||||||
{
|
|
||||||
xi=SATURATE(x[i],805306368);
|
|
||||||
yi = SATURATE(ADD32(xi, SHL32(mem[0],2)),805306368);
|
|
||||||
nyi = NEG32(yi);
|
|
||||||
for (j=0;j<ord-1;j++)
|
|
||||||
{
|
|
||||||
mem[j] = MAC16_32_Q15(MAC16_32_Q15(mem[j+1], num[j],xi), den[j],nyi);
|
|
||||||
}
|
|
||||||
mem[ord-1] = SUB32(MULT16_32_Q15(num[ord-1],xi), MULT16_32_Q15(den[ord-1],yi));
|
|
||||||
y[i] = yi;
|
|
||||||
}
|
|
||||||
for (i=0;i<ord;i++)
|
|
||||||
mem[i] = SHL32(mem[i],1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef FIXED_POINT
|
|
||||||
#ifndef OVERRIDE_FILTER_MEM16
|
#ifndef OVERRIDE_FILTER_MEM16
|
||||||
void filter_mem16(const spx_word16_t *x, const spx_coef_t *num, const spx_coef_t *den, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack)
|
void filter_mem16(const spx_word16_t *x, const spx_coef_t *num, const spx_coef_t *den, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack)
|
||||||
{
|
{
|
||||||
|
@ -363,60 +316,7 @@ void filter_mem16(const spx_word16_t *x, const spx_coef_t *num, const spx_coef_t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#else
|
|
||||||
void filter_mem16(const spx_word16_t *x, const spx_coef_t *num, const spx_coef_t *den, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack)
|
|
||||||
{
|
|
||||||
filter_mem2(x, num, den, y, N, ord, mem);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef OVERRIDE_IIR_MEM2
|
|
||||||
#ifdef PRECISION16
|
|
||||||
void iir_mem2(const spx_sig_t *x, const spx_coef_t *den, spx_sig_t *y, int N, int ord, spx_mem_t *mem)
|
|
||||||
{
|
|
||||||
int i,j;
|
|
||||||
spx_word16_t yi,nyi;
|
|
||||||
|
|
||||||
for (i=0;i<N;i++)
|
|
||||||
{
|
|
||||||
yi = EXTRACT16(PSHR32(SATURATE(x[i] + SHL32(mem[0],1),536870911),SIG_SHIFT));
|
|
||||||
nyi = NEG16(yi);
|
|
||||||
for (j=0;j<ord-1;j++)
|
|
||||||
{
|
|
||||||
mem[j] = MAC16_16(mem[j+1],den[j],nyi);
|
|
||||||
}
|
|
||||||
mem[ord-1] = MULT16_16(den[ord-1],nyi);
|
|
||||||
y[i] = SHL32(EXTEND32(yi),SIG_SHIFT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
void iir_mem2(const spx_sig_t *x, const spx_coef_t *den, spx_sig_t *y, int N, int ord, spx_mem_t *mem)
|
|
||||||
{
|
|
||||||
int i,j;
|
|
||||||
spx_word32_t xi,yi,nyi;
|
|
||||||
|
|
||||||
for (i=0;i<ord;i++)
|
|
||||||
mem[i] = SHR32(mem[i],1);
|
|
||||||
for (i=0;i<N;i++)
|
|
||||||
{
|
|
||||||
xi=SATURATE(x[i],805306368);
|
|
||||||
yi = SATURATE(xi + SHL32(mem[0],2),805306368);
|
|
||||||
nyi = NEG32(yi);
|
|
||||||
for (j=0;j<ord-1;j++)
|
|
||||||
{
|
|
||||||
mem[j] = MAC16_32_Q15(mem[j+1],den[j],nyi);
|
|
||||||
}
|
|
||||||
mem[ord-1] = MULT16_32_Q15(den[ord-1],nyi);
|
|
||||||
y[i] = yi;
|
|
||||||
}
|
|
||||||
for (i=0;i<ord;i++)
|
|
||||||
mem[i] = SHL32(mem[i],1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef FIXED_POINT
|
|
||||||
#ifndef OVERRIDE_IIR_MEM16
|
#ifndef OVERRIDE_IIR_MEM16
|
||||||
void iir_mem16(const spx_word16_t *x, const spx_coef_t *den, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack)
|
void iir_mem16(const spx_word16_t *x, const spx_coef_t *den, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack)
|
||||||
{
|
{
|
||||||
|
@ -436,59 +336,7 @@ void iir_mem16(const spx_word16_t *x, const spx_coef_t *den, spx_word16_t *y, in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#else
|
|
||||||
void iir_mem16(const spx_word16_t *x, const spx_coef_t *den, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack)
|
|
||||||
{
|
|
||||||
iir_mem2(x, den, y, N, ord, mem);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef OVERRIDE_FIR_MEM2
|
|
||||||
#ifdef PRECISION16
|
|
||||||
void fir_mem2(const spx_sig_t *x, const spx_coef_t *num, spx_sig_t *y, int N, int ord, spx_mem_t *mem)
|
|
||||||
{
|
|
||||||
int i,j;
|
|
||||||
spx_word16_t xi,yi;
|
|
||||||
|
|
||||||
for (i=0;i<N;i++)
|
|
||||||
{
|
|
||||||
xi= EXTRACT16(PSHR32(SATURATE(x[i],536870911),SIG_SHIFT));
|
|
||||||
yi = EXTRACT16(PSHR32(SATURATE(x[i] + SHL32(mem[0],1),536870911),SIG_SHIFT));
|
|
||||||
for (j=0;j<ord-1;j++)
|
|
||||||
{
|
|
||||||
mem[j] = MAC16_16(mem[j+1], num[j],xi);
|
|
||||||
}
|
|
||||||
mem[ord-1] = MULT16_16(num[ord-1],xi);
|
|
||||||
y[i] = SHL32(EXTEND32(yi),SIG_SHIFT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
void fir_mem2(const spx_sig_t *x, const spx_coef_t *num, spx_sig_t *y, int N, int ord, spx_mem_t *mem)
|
|
||||||
{
|
|
||||||
int i,j;
|
|
||||||
spx_word32_t xi,yi;
|
|
||||||
|
|
||||||
for (i=0;i<ord;i++)
|
|
||||||
mem[i] = SHR32(mem[i],1);
|
|
||||||
for (i=0;i<N;i++)
|
|
||||||
{
|
|
||||||
xi=SATURATE(x[i],805306368);
|
|
||||||
yi = xi + SHL32(mem[0],2);
|
|
||||||
for (j=0;j<ord-1;j++)
|
|
||||||
{
|
|
||||||
mem[j] = MAC16_32_Q15(mem[j+1], num[j],xi);
|
|
||||||
}
|
|
||||||
mem[ord-1] = MULT16_32_Q15(num[ord-1],xi);
|
|
||||||
y[i] = SATURATE(yi,805306368);
|
|
||||||
}
|
|
||||||
for (i=0;i<ord;i++)
|
|
||||||
mem[i] = SHL32(mem[i],1);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef FIXED_POINT
|
|
||||||
#ifndef OVERRIDE_FIR_MEM16
|
#ifndef OVERRIDE_FIR_MEM16
|
||||||
void fir_mem16(const spx_word16_t *x, const spx_coef_t *num, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack)
|
void fir_mem16(const spx_word16_t *x, const spx_coef_t *num, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack)
|
||||||
{
|
{
|
||||||
|
@ -508,43 +356,33 @@ void fir_mem16(const spx_word16_t *x, const spx_coef_t *num, spx_word16_t *y, in
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#else
|
|
||||||
void fir_mem16(const spx_word16_t *x, const spx_coef_t *num, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack)
|
|
||||||
{
|
|
||||||
fir_mem2(x, num, y, N, ord, mem);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
void syn_percep_zero16(const spx_word16_t *xx, const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_word16_t *y, int N, int ord, char *stack)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void syn_percep_zero(const spx_sig_t *xx, const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_sig_t *y, int N, int ord, char *stack)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
VARDECL(spx_mem_t *mem);
|
|
||||||
ALLOC(mem, ord, spx_mem_t);
|
|
||||||
for (i=0;i<ord;i++)
|
|
||||||
mem[i]=0;
|
|
||||||
iir_mem2(xx, ak, y, N, ord, mem);
|
|
||||||
for (i=0;i<ord;i++)
|
|
||||||
mem[i]=0;
|
|
||||||
filter_mem2(y, awk1, awk2, y, N, ord, mem);
|
|
||||||
}
|
|
||||||
|
|
||||||
void residue_percep_zero(const spx_sig_t *xx, const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_sig_t *y, int N, int ord, char *stack)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
VARDECL(spx_mem_t *mem);
|
VARDECL(spx_mem_t *mem);
|
||||||
ALLOC(mem, ord, spx_mem_t);
|
ALLOC(mem, ord, spx_mem_t);
|
||||||
for (i=0;i<ord;i++)
|
for (i=0;i<ord;i++)
|
||||||
mem[i]=0;
|
mem[i]=0;
|
||||||
filter_mem2(xx, ak, awk1, y, N, ord, mem);
|
iir_mem16(xx, ak, y, N, ord, mem, stack);
|
||||||
for (i=0;i<ord;i++)
|
for (i=0;i<ord;i++)
|
||||||
mem[i]=0;
|
mem[i]=0;
|
||||||
fir_mem2(y, awk2, y, N, ord, mem);
|
filter_mem16(y, awk1, awk2, y, N, ord, mem, stack);
|
||||||
}
|
}
|
||||||
|
void residue_percep_zero16(const spx_word16_t *xx, const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_word16_t *y, int N, int ord, char *stack)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
VARDECL(spx_mem_t *mem);
|
||||||
|
ALLOC(mem, ord, spx_mem_t);
|
||||||
|
for (i=0;i<ord;i++)
|
||||||
|
mem[i]=0;
|
||||||
|
filter_mem16(xx, ak, awk1, y, N, ord, mem, stack);
|
||||||
|
for (i=0;i<ord;i++)
|
||||||
|
mem[i]=0;
|
||||||
|
fir_mem16(y, awk2, y, N, ord, mem, stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifndef OVERRIDE_COMPUTE_IMPULSE_RESPONSE
|
#ifndef OVERRIDE_COMPUTE_IMPULSE_RESPONSE
|
||||||
void compute_impulse_response(const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_word16_t *y, int N, int ord, char *stack)
|
void compute_impulse_response(const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_word16_t *y, int N, int ord, char *stack)
|
||||||
|
@ -581,7 +419,8 @@ void compute_impulse_response(const spx_coef_t *ak, const spx_coef_t *awk1, cons
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void qmf_decomp(const spx_word16_t *xx, const spx_word16_t *aa, spx_sig_t *y1, spx_sig_t *y2, int N, int M, spx_word16_t *mem, char *stack)
|
/* Decomposes a signal into low-band and high-band using a QMF */
|
||||||
|
void qmf_decomp(const spx_word16_t *xx, const spx_word16_t *aa, spx_word16_t *y1, spx_word16_t *y2, int N, int M, spx_word16_t *mem, char *stack)
|
||||||
{
|
{
|
||||||
int i,j,k,M2;
|
int i,j,k,M2;
|
||||||
VARDECL(spx_word16_t *a);
|
VARDECL(spx_word16_t *a);
|
||||||
|
@ -594,103 +433,137 @@ void qmf_decomp(const spx_word16_t *xx, const spx_word16_t *aa, spx_sig_t *y1, s
|
||||||
M2=M>>1;
|
M2=M>>1;
|
||||||
for (i=0;i<M;i++)
|
for (i=0;i<M;i++)
|
||||||
a[M-i-1]= aa[i];
|
a[M-i-1]= aa[i];
|
||||||
|
|
||||||
for (i=0;i<M-1;i++)
|
for (i=0;i<M-1;i++)
|
||||||
x[i]=mem[M-i-2];
|
x[i]=mem[M-i-2];
|
||||||
for (i=0;i<N;i++)
|
for (i=0;i<N;i++)
|
||||||
x[i+M-1]=SATURATE(PSHR(xx[i],1),16383);
|
x[i+M-1]=SHR16(xx[i],1);
|
||||||
|
for (i=0;i<M-1;i++)
|
||||||
|
mem[i]=SHR16(xx[N-i-1],1);
|
||||||
for (i=0,k=0;i<N;i+=2,k++)
|
for (i=0,k=0;i<N;i+=2,k++)
|
||||||
{
|
{
|
||||||
y1[k]=0;
|
spx_word32_t y1k=0, y2k=0;
|
||||||
y2[k]=0;
|
|
||||||
for (j=0;j<M2;j++)
|
for (j=0;j<M2;j++)
|
||||||
{
|
{
|
||||||
y1[k]=ADD32(y1[k],MULT16_16(a[j],ADD16(x[i+j],x2[i-j])));
|
y1k=ADD32(y1k,MULT16_16(a[j],ADD16(x[i+j],x2[i-j])));
|
||||||
y2[k]=SUB32(y2[k],MULT16_16(a[j],SUB16(x[i+j],x2[i-j])));
|
y2k=SUB32(y2k,MULT16_16(a[j],SUB16(x[i+j],x2[i-j])));
|
||||||
j++;
|
j++;
|
||||||
y1[k]=ADD32(y1[k],MULT16_16(a[j],ADD16(x[i+j],x2[i-j])));
|
y1k=ADD32(y1k,MULT16_16(a[j],ADD16(x[i+j],x2[i-j])));
|
||||||
y2[k]=ADD32(y2[k],MULT16_16(a[j],SUB16(x[i+j],x2[i-j])));
|
y2k=ADD32(y2k,MULT16_16(a[j],SUB16(x[i+j],x2[i-j])));
|
||||||
}
|
}
|
||||||
y1[k] = SHR32(y1[k],1);
|
y1[k] = EXTRACT16(SATURATE(PSHR32(y1k,15),32767));
|
||||||
y2[k] = SHR32(y2[k],1);
|
y2[k] = EXTRACT16(SATURATE(PSHR32(y2k,15),32767));
|
||||||
}
|
}
|
||||||
for (i=0;i<M-1;i++)
|
|
||||||
mem[i]=SATURATE(PSHR(xx[N-i-1],1),16383);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Re-synthesised a signal from the QMF low-band and high-band signals */
|
||||||
/* By segher */
|
void qmf_synth(const spx_word16_t *x1, const spx_word16_t *x2, const spx_word16_t *a, spx_word16_t *y, int N, int M, spx_word32_t *mem1, spx_word32_t *mem2, char *stack)
|
||||||
void fir_mem_up(const spx_sig_t *x, const spx_word16_t *a, spx_sig_t *y, int N, int M, spx_word32_t *mem, char *stack)
|
|
||||||
/* assumptions:
|
/* assumptions:
|
||||||
all odd x[i] are zero -- well, actually they are left out of the array now
|
all odd x[i] are zero -- well, actually they are left out of the array now
|
||||||
N and M are multiples of 4 */
|
N and M are multiples of 4 */
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
VARDECL(spx_word16_t *xx);
|
int M2, N2;
|
||||||
|
VARDECL(spx_word16_t *xx1);
|
||||||
|
VARDECL(spx_word16_t *xx2);
|
||||||
|
|
||||||
ALLOC(xx, M+N-1, spx_word16_t);
|
M2 = M>>1;
|
||||||
|
N2 = N>>1;
|
||||||
|
ALLOC(xx1, M2+N2, spx_word16_t);
|
||||||
|
ALLOC(xx2, M2+N2, spx_word16_t);
|
||||||
|
|
||||||
for (i = 0; i < N/2; i++)
|
for (i = 0; i < N2; i++)
|
||||||
xx[2*i] = PSHR32(x[N/2-1-i],SIG_SHIFT);
|
xx1[i] = x1[N2-1-i];
|
||||||
for (i = 0; i < M - 1; i += 2)
|
for (i = 0; i < M2; i++)
|
||||||
xx[N+i] = mem[i+1];
|
xx1[N2+i] = mem1[2*i+1];
|
||||||
|
for (i = 0; i < N2; i++)
|
||||||
|
xx2[i] = x2[N2-1-i];
|
||||||
|
for (i = 0; i < M2; i++)
|
||||||
|
xx2[N2+i] = mem2[2*i+1];
|
||||||
|
|
||||||
for (i = 0; i < N; i += 4) {
|
for (i = 0; i < N2; i += 2) {
|
||||||
spx_sig_t y0, y1, y2, y3;
|
spx_sig_t y0, y1, y2, y3;
|
||||||
spx_word16_t x0;
|
spx_word16_t x10, x20;
|
||||||
|
|
||||||
y0 = y1 = y2 = y3 = 0;
|
y0 = y1 = y2 = y3 = 0;
|
||||||
x0 = xx[N-4-i];
|
x10 = xx1[N2-2-i];
|
||||||
|
x20 = xx2[N2-2-i];
|
||||||
|
|
||||||
for (j = 0; j < M; j += 4) {
|
for (j = 0; j < M2; j += 2) {
|
||||||
spx_word16_t x1;
|
spx_word16_t x11, x21;
|
||||||
spx_word16_t a0, a1;
|
spx_word16_t a0, a1;
|
||||||
|
|
||||||
a0 = a[j];
|
a0 = a[2*j];
|
||||||
a1 = a[j+1];
|
a1 = a[2*j+1];
|
||||||
x1 = xx[N-2+j-i];
|
x11 = xx1[N2-1+j-i];
|
||||||
|
x21 = xx2[N2-1+j-i];
|
||||||
|
|
||||||
y0 = ADD32(y0,SHR(MULT16_16(a0, x1),2));
|
#ifdef FIXED_POINT
|
||||||
y1 = ADD32(y1,SHR(MULT16_16(a1, x1),2));
|
/* We multiply twice by the same coef to avoid overflows */
|
||||||
y2 = ADD32(y2,SHR(MULT16_16(a0, x0),2));
|
y0 = MAC16_16(MAC16_16(y0, a0, x11), NEG16(a0), x21);
|
||||||
y3 = ADD32(y3,SHR(MULT16_16(a1, x0),2));
|
y1 = MAC16_16(MAC16_16(y1, a1, x11), a1, x21);
|
||||||
|
y2 = MAC16_16(MAC16_16(y2, a0, x10), NEG16(a0), x20);
|
||||||
|
y3 = MAC16_16(MAC16_16(y3, a1, x10), a1, x20);
|
||||||
|
#else
|
||||||
|
y0 = ADD32(y0,MULT16_16(a0, x11-x21));
|
||||||
|
y1 = ADD32(y1,MULT16_16(a1, x11+x21));
|
||||||
|
y2 = ADD32(y2,MULT16_16(a0, x10-x20));
|
||||||
|
y3 = ADD32(y3,MULT16_16(a1, x10+x20));
|
||||||
|
#endif
|
||||||
|
a0 = a[2*j+2];
|
||||||
|
a1 = a[2*j+3];
|
||||||
|
x10 = xx1[N2+j-i];
|
||||||
|
x20 = xx2[N2+j-i];
|
||||||
|
|
||||||
a0 = a[j+2];
|
#ifdef FIXED_POINT
|
||||||
a1 = a[j+3];
|
/* We multiply twice by the same coef to avoid overflows */
|
||||||
x0 = xx[N+j-i];
|
y0 = MAC16_16(MAC16_16(y0, a0, x10), NEG16(a0), x20);
|
||||||
|
y1 = MAC16_16(MAC16_16(y1, a1, x10), a1, x20);
|
||||||
y0 = ADD32(y0,SHR(MULT16_16(a0, x0),2));
|
y2 = MAC16_16(MAC16_16(y2, a0, x11), NEG16(a0), x21);
|
||||||
y1 = ADD32(y1,SHR(MULT16_16(a1, x0),2));
|
y3 = MAC16_16(MAC16_16(y3, a1, x11), a1, x21);
|
||||||
y2 = ADD32(y2,SHR(MULT16_16(a0, x1),2));
|
#else
|
||||||
y3 = ADD32(y3,SHR(MULT16_16(a1, x1),2));
|
y0 = ADD32(y0,MULT16_16(a0, x10-x20));
|
||||||
|
y1 = ADD32(y1,MULT16_16(a1, x10+x20));
|
||||||
|
y2 = ADD32(y2,MULT16_16(a0, x11-x21));
|
||||||
|
y3 = ADD32(y3,MULT16_16(a1, x11+x21));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
y[i] = y0;
|
#ifdef FIXED_POINT
|
||||||
y[i+1] = y1;
|
y[2*i] = EXTRACT16(SATURATE32(PSHR32(y0,15),32767));
|
||||||
y[i+2] = y2;
|
y[2*i+1] = EXTRACT16(SATURATE32(PSHR32(y1,15),32767));
|
||||||
y[i+3] = y3;
|
y[2*i+2] = EXTRACT16(SATURATE32(PSHR32(y2,15),32767));
|
||||||
|
y[2*i+3] = EXTRACT16(SATURATE32(PSHR32(y3,15),32767));
|
||||||
|
#else
|
||||||
|
/* Normalize up explicitly if we're in float */
|
||||||
|
y[2*i] = 2.f*y0;
|
||||||
|
y[2*i+1] = 2.f*y1;
|
||||||
|
y[2*i+2] = 2.f*y2;
|
||||||
|
y[2*i+3] = 2.f*y3;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < M - 1; i += 2)
|
for (i = 0; i < M2; i++)
|
||||||
mem[i+1] = xx[i];
|
mem1[2*i+1] = xx1[i];
|
||||||
|
for (i = 0; i < M2; i++)
|
||||||
|
mem2[2*i+1] = xx2[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FIXED_POINT
|
#ifdef FIXED_POINT
|
||||||
#if 0
|
#if 0
|
||||||
spx_word16_t shift_filt[3][7] = {{-33, 1043, -4551, 19959, 19959, -4551, 1043},
|
const spx_word16_t shift_filt[3][7] = {{-33, 1043, -4551, 19959, 19959, -4551, 1043},
|
||||||
{-98, 1133, -4425, 29179, 8895, -2328, 444},
|
{-98, 1133, -4425, 29179, 8895, -2328, 444},
|
||||||
{444, -2328, 8895, 29179, -4425, 1133, -98}};
|
{444, -2328, 8895, 29179, -4425, 1133, -98}};
|
||||||
#else
|
#else
|
||||||
spx_word16_t shift_filt[3][7] = {{-390, 1540, -4993, 20123, 20123, -4993, 1540},
|
const spx_word16_t shift_filt[3][7] = {{-390, 1540, -4993, 20123, 20123, -4993, 1540},
|
||||||
{-1064, 2817, -6694, 31589, 6837, -990, -209},
|
{-1064, 2817, -6694, 31589, 6837, -990, -209},
|
||||||
{-209, -990, 6837, 31589, -6694, 2817, -1064}};
|
{-209, -990, 6837, 31589, -6694, 2817, -1064}};
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
#if 0
|
#if 0
|
||||||
float shift_filt[3][7] = {{-9.9369e-04, 3.1831e-02, -1.3889e-01, 6.0910e-01, 6.0910e-01, -1.3889e-01, 3.1831e-02},
|
const float shift_filt[3][7] = {{-9.9369e-04, 3.1831e-02, -1.3889e-01, 6.0910e-01, 6.0910e-01, -1.3889e-01, 3.1831e-02},
|
||||||
{-0.0029937, 0.0345613, -0.1350474, 0.8904793, 0.2714479, -0.0710304, 0.0135403},
|
{-0.0029937, 0.0345613, -0.1350474, 0.8904793, 0.2714479, -0.0710304, 0.0135403},
|
||||||
{0.0135403, -0.0710304, 0.2714479, 0.8904793, -0.1350474, 0.0345613, -0.0029937}};
|
{0.0135403, -0.0710304, 0.2714479, 0.8904793, -0.1350474, 0.0345613, -0.0029937}};
|
||||||
#else
|
#else
|
||||||
float shift_filt[3][7] = {{-0.011915f, 0.046995f, -0.152373f, 0.614108f, 0.614108f, -0.152373f, 0.046995f},
|
const float shift_filt[3][7] = {{-0.011915f, 0.046995f, -0.152373f, 0.614108f, 0.614108f, -0.152373f, 0.046995f},
|
||||||
{-0.0324855f, 0.0859768f, -0.2042986f, 0.9640297f, 0.2086420f, -0.0302054f, -0.0063646f},
|
{-0.0324855f, 0.0859768f, -0.2042986f, 0.9640297f, 0.2086420f, -0.0302054f, -0.0063646f},
|
||||||
{-0.0063646f, -0.0302054f, 0.2086420f, 0.9640297f, -0.2042986f, 0.0859768f, -0.0324855f}};
|
{-0.0063646f, -0.0302054f, 0.2086420f, 0.9640297f, -0.2042986f, 0.0859768f, -0.0324855f}};
|
||||||
#endif
|
#endif
|
||||||
|
@ -784,7 +657,9 @@ char *stack
|
||||||
spx_word16_t g1, g2;
|
spx_word16_t g1, g2;
|
||||||
spx_word16_t ngain;
|
spx_word16_t ngain;
|
||||||
spx_word16_t gg1, gg2;
|
spx_word16_t gg1, gg2;
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
int scaledown=0;
|
||||||
|
#endif
|
||||||
#if 0 /* Set to 1 to enable full pitch search */
|
#if 0 /* Set to 1 to enable full pitch search */
|
||||||
int nol_pitch[6];
|
int nol_pitch[6];
|
||||||
spx_word16_t nol_pitch_coef[6];
|
spx_word16_t nol_pitch_coef[6];
|
||||||
|
@ -819,6 +694,23 @@ char *stack
|
||||||
else
|
else
|
||||||
interp_pitch(exc, iexc+nsf, -corr_pitch, 80);
|
interp_pitch(exc, iexc+nsf, -corr_pitch, 80);
|
||||||
|
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
for (i=0;i<nsf;i++)
|
||||||
|
{
|
||||||
|
if (ABS16(exc[i])>16383)
|
||||||
|
{
|
||||||
|
scaledown = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (scaledown)
|
||||||
|
{
|
||||||
|
for (i=0;i<nsf;i++)
|
||||||
|
exc[i] = SHR16(exc[i],1);
|
||||||
|
for (i=0;i<2*nsf;i++)
|
||||||
|
iexc[i] = SHR16(iexc[i],1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
/*interp_pitch(exc, iexc+2*nsf, 2*corr_pitch, 80);*/
|
/*interp_pitch(exc, iexc+2*nsf, 2*corr_pitch, 80);*/
|
||||||
|
|
||||||
/*printf ("%d %d %f\n", pitch, corr_pitch, max_corr*ener_1);*/
|
/*printf ("%d %d %f\n", pitch, corr_pitch, max_corr*ener_1);*/
|
||||||
|
@ -898,5 +790,14 @@ char *stack
|
||||||
|
|
||||||
for (i=0;i<nsf;i++)
|
for (i=0;i<nsf;i++)
|
||||||
new_exc[i] = MULT16_16_Q14(ngain, new_exc[i]);
|
new_exc[i] = MULT16_16_Q14(ngain, new_exc[i]);
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
if (scaledown)
|
||||||
|
{
|
||||||
|
for (i=0;i<nsf;i++)
|
||||||
|
exc[i] = SHL16(exc[i],1);
|
||||||
|
for (i=0;i<nsf;i++)
|
||||||
|
new_exc[i] = SHL16(SATURATE16(new_exc[i],16383),1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,13 +58,8 @@ int normalize16(const spx_sig_t *x, spx_word16_t *y, spx_sig_t max_scale, int le
|
||||||
void highpass(const spx_word16_t *x, spx_word16_t *y, int len, int filtID, spx_mem_t *mem);
|
void highpass(const spx_word16_t *x, spx_word16_t *y, int len, int filtID, spx_mem_t *mem);
|
||||||
|
|
||||||
|
|
||||||
void qmf_decomp(const spx_word16_t *xx, const spx_word16_t *aa, spx_sig_t *, spx_sig_t *y2, int N, int M, spx_word16_t *mem, char *stack);
|
void qmf_decomp(const spx_word16_t *xx, const spx_word16_t *aa, spx_word16_t *, spx_word16_t *y2, int N, int M, spx_word16_t *mem, char *stack);
|
||||||
void fir_mem_up(const spx_sig_t *x, const spx_word16_t *a, spx_sig_t *y, int N, int M, spx_word32_t *mem, char *stack);
|
void qmf_synth(const spx_word16_t *x1, const spx_word16_t *x2, const spx_word16_t *a, spx_word16_t *y, int N, int M, spx_word32_t *mem1, spx_word32_t *mem2, char *stack);
|
||||||
|
|
||||||
|
|
||||||
void filter_mem2(const spx_sig_t *x, const spx_coef_t *num, const spx_coef_t *den, spx_sig_t *y, int N, int ord, spx_mem_t *mem);
|
|
||||||
void fir_mem2(const spx_sig_t *x, const spx_coef_t *num, spx_sig_t *y, int N, int ord, spx_mem_t *mem);
|
|
||||||
void iir_mem2(const spx_sig_t *x, const spx_coef_t *den, spx_sig_t *y, int N, int ord, spx_mem_t *mem);
|
|
||||||
|
|
||||||
void filter_mem16(const spx_word16_t *x, const spx_coef_t *num, const spx_coef_t *den, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack);
|
void filter_mem16(const spx_word16_t *x, const spx_coef_t *num, const spx_coef_t *den, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack);
|
||||||
void iir_mem16(const spx_word16_t *x, const spx_coef_t *den, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack);
|
void iir_mem16(const spx_word16_t *x, const spx_coef_t *den, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack);
|
||||||
|
@ -74,10 +69,8 @@ void fir_mem16(const spx_word16_t *x, const spx_coef_t *num, spx_word16_t *y, in
|
||||||
void bw_lpc(spx_word16_t , const spx_coef_t *lpc_in, spx_coef_t *lpc_out, int order);
|
void bw_lpc(spx_word16_t , const spx_coef_t *lpc_in, spx_coef_t *lpc_out, int order);
|
||||||
|
|
||||||
|
|
||||||
|
void syn_percep_zero16(const spx_word16_t *xx, const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_word16_t *y, int N, int ord, char *stack);
|
||||||
void syn_percep_zero(const spx_sig_t *x, const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_sig_t *y, int N, int ord, char *stack);
|
void residue_percep_zero16(const spx_word16_t *xx, const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_word16_t *y, int N, int ord, char *stack);
|
||||||
|
|
||||||
void residue_percep_zero(const spx_sig_t *xx, const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_sig_t *y, int N, int ord, char *stack);
|
|
||||||
|
|
||||||
void compute_impulse_response(const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_word16_t *y, int N, int ord, char *stack);
|
void compute_impulse_response(const spx_coef_t *ak, const spx_coef_t *awk1, const spx_coef_t *awk2, spx_word16_t *y, int N, int ord, char *stack);
|
||||||
|
|
||||||
|
|
|
@ -33,9 +33,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define OVERRIDE_NORMALIZE16
|
#define OVERRIDE_NORMALIZE16
|
||||||
int normalize16(const spx_sig_t *x, spx_word16_t *y, spx_sig_t max_scale, int len)
|
int normalize16(const spx_sig_t *x, spx_word16_t *y, int max_scale, int len)
|
||||||
{
|
{
|
||||||
//int i;
|
int i;
|
||||||
spx_sig_t max_val=1;
|
spx_sig_t max_val=1;
|
||||||
int sig_shift;
|
int sig_shift;
|
||||||
int dead1, dead2, dead3, dead4, dead5, dead6;
|
int dead1, dead2, dead3, dead4, dead5, dead6;
|
||||||
|
@ -95,295 +95,3 @@ int normalize16(const spx_sig_t *x, spx_word16_t *y, spx_sig_t max_scale, int le
|
||||||
return sig_shift;
|
return sig_shift;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define OVERRIDE_FILTER_MEM2
|
|
||||||
void filter_mem2(const spx_sig_t *x, const spx_coef_t *num, const spx_coef_t *den, spx_sig_t *y, int N, int ord, spx_mem_t *mem)
|
|
||||||
{
|
|
||||||
int i/*,j*/;
|
|
||||||
spx_sig_t xi,yi,nyi;
|
|
||||||
|
|
||||||
for (i=0;i<ord;i++)
|
|
||||||
mem[i] = SHR32(mem[i],1);
|
|
||||||
for (i=0;i<N;i++)
|
|
||||||
{
|
|
||||||
int deadm, deadn, deadd, deadidx, /*x1, y1,*/ dead1, dead2, dead3, dead4, dead5, dead6;
|
|
||||||
xi=SATURATE(x[i],805306368);
|
|
||||||
yi = SATURATE(ADD32(xi, SHL(mem[0],2)),805306368);
|
|
||||||
nyi = -yi;
|
|
||||||
y[i] = yi;
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
"\tldrsh %6, [%1], #2\n"
|
|
||||||
"\tsmull %8, %9, %4, %6\n"
|
|
||||||
#ifdef SHORTCUTS
|
|
||||||
"\tldrsh %6, [%2], #2\n"
|
|
||||||
"\tldr %10, [%0, #4]\n"
|
|
||||||
"\tmov %8, %8, lsr #15\n"
|
|
||||||
"\tsmull %7, %11, %5, %6\n"
|
|
||||||
"\tldrsh %6, [%1], #2\n"
|
|
||||||
"\tadd %8, %8, %9, lsl #17\n"
|
|
||||||
"\tadd %10, %10, %8\n"
|
|
||||||
"\tsmull %8, %9, %4, %6\n"
|
|
||||||
"\tadd %10, %10, %7, lsr #15\n"
|
|
||||||
"\tadd %10, %10, %11, lsl #17\n"
|
|
||||||
"\tstr %10, [%0], #4 \n"
|
|
||||||
|
|
||||||
"\tldrsh %6, [%2], #2\n"
|
|
||||||
"\tldr %10, [%0, #4]\n"
|
|
||||||
"\tmov %8, %8, lsr #15\n"
|
|
||||||
"\tsmull %7, %11, %5, %6\n"
|
|
||||||
"\tldrsh %6, [%1], #2\n"
|
|
||||||
"\tadd %8, %8, %9, lsl #17\n"
|
|
||||||
"\tadd %10, %10, %8\n"
|
|
||||||
"\tsmull %8, %9, %4, %6\n"
|
|
||||||
"\tadd %10, %10, %7, lsr #15\n"
|
|
||||||
"\tadd %10, %10, %11, lsl #17\n"
|
|
||||||
"\tstr %10, [%0], #4 \n"
|
|
||||||
|
|
||||||
"\tldrsh %6, [%2], #2\n"
|
|
||||||
"\tldr %10, [%0, #4]\n"
|
|
||||||
"\tmov %8, %8, lsr #15\n"
|
|
||||||
"\tsmull %7, %11, %5, %6\n"
|
|
||||||
"\tldrsh %6, [%1], #2\n"
|
|
||||||
"\tadd %8, %8, %9, lsl #17\n"
|
|
||||||
"\tadd %10, %10, %8\n"
|
|
||||||
"\tsmull %8, %9, %4, %6\n"
|
|
||||||
"\tadd %10, %10, %7, lsr #15\n"
|
|
||||||
"\tadd %10, %10, %11, lsl #17\n"
|
|
||||||
"\tstr %10, [%0], #4 \n"
|
|
||||||
|
|
||||||
"\tldrsh %6, [%2], #2\n"
|
|
||||||
"\tldr %10, [%0, #4]\n"
|
|
||||||
"\tmov %8, %8, lsr #15\n"
|
|
||||||
"\tsmull %7, %11, %5, %6\n"
|
|
||||||
"\tldrsh %6, [%1], #2\n"
|
|
||||||
"\tadd %8, %8, %9, lsl #17\n"
|
|
||||||
"\tadd %10, %10, %8\n"
|
|
||||||
"\tsmull %8, %9, %4, %6\n"
|
|
||||||
"\tadd %10, %10, %7, lsr #15\n"
|
|
||||||
"\tadd %10, %10, %11, lsl #17\n"
|
|
||||||
"\tstr %10, [%0], #4 \n"
|
|
||||||
|
|
||||||
"\tldrsh %6, [%2], #2\n"
|
|
||||||
"\tldr %10, [%0, #4]\n"
|
|
||||||
"\tmov %8, %8, lsr #15\n"
|
|
||||||
"\tsmull %7, %11, %5, %6\n"
|
|
||||||
"\tldrsh %6, [%1], #2\n"
|
|
||||||
"\tadd %8, %8, %9, lsl #17\n"
|
|
||||||
"\tadd %10, %10, %8\n"
|
|
||||||
"\tsmull %8, %9, %4, %6\n"
|
|
||||||
"\tadd %10, %10, %7, lsr #15\n"
|
|
||||||
"\tadd %10, %10, %11, lsl #17\n"
|
|
||||||
"\tstr %10, [%0], #4 \n"
|
|
||||||
|
|
||||||
"\tldrsh %6, [%2], #2\n"
|
|
||||||
"\tldr %10, [%0, #4]\n"
|
|
||||||
"\tmov %8, %8, lsr #15\n"
|
|
||||||
"\tsmull %7, %11, %5, %6\n"
|
|
||||||
"\tldrsh %6, [%1], #2\n"
|
|
||||||
"\tadd %8, %8, %9, lsl #17\n"
|
|
||||||
"\tadd %10, %10, %8\n"
|
|
||||||
"\tsmull %8, %9, %4, %6\n"
|
|
||||||
"\tadd %10, %10, %7, lsr #15\n"
|
|
||||||
"\tadd %10, %10, %11, lsl #17\n"
|
|
||||||
"\tstr %10, [%0], #4 \n"
|
|
||||||
|
|
||||||
"\tldrsh %6, [%2], #2\n"
|
|
||||||
"\tldr %10, [%0, #4]\n"
|
|
||||||
"\tmov %8, %8, lsr #15\n"
|
|
||||||
"\tsmull %7, %11, %5, %6\n"
|
|
||||||
"\tldrsh %6, [%1], #2\n"
|
|
||||||
"\tadd %8, %8, %9, lsl #17\n"
|
|
||||||
"\tadd %10, %10, %8\n"
|
|
||||||
"\tsmull %8, %9, %4, %6\n"
|
|
||||||
"\tadd %10, %10, %7, lsr #15\n"
|
|
||||||
"\tadd %10, %10, %11, lsl #17\n"
|
|
||||||
"\tstr %10, [%0], #4 \n"
|
|
||||||
|
|
||||||
"\tldrsh %6, [%2], #2\n"
|
|
||||||
"\tldr %10, [%0, #4]\n"
|
|
||||||
"\tmov %8, %8, lsr #15\n"
|
|
||||||
"\tsmull %7, %11, %5, %6\n"
|
|
||||||
"\tldrsh %6, [%1], #2\n"
|
|
||||||
"\tadd %8, %8, %9, lsl #17\n"
|
|
||||||
"\tadd %10, %10, %8\n"
|
|
||||||
"\tsmull %8, %9, %4, %6\n"
|
|
||||||
"\tadd %10, %10, %7, lsr #15\n"
|
|
||||||
"\tadd %10, %10, %11, lsl #17\n"
|
|
||||||
"\tstr %10, [%0], #4 \n"
|
|
||||||
|
|
||||||
"\tldrsh %6, [%2], #2\n"
|
|
||||||
"\tldr %10, [%0, #4]\n"
|
|
||||||
"\tmov %8, %8, lsr #15\n"
|
|
||||||
"\tsmull %7, %11, %5, %6\n"
|
|
||||||
"\tldrsh %6, [%1], #2\n"
|
|
||||||
"\tadd %8, %8, %9, lsl #17\n"
|
|
||||||
"\tadd %10, %10, %8\n"
|
|
||||||
"\tsmull %8, %9, %4, %6\n"
|
|
||||||
"\tadd %10, %10, %7, lsr #15\n"
|
|
||||||
"\tadd %10, %10, %11, lsl #17\n"
|
|
||||||
"\tstr %10, [%0], #4 \n"
|
|
||||||
|
|
||||||
|
|
||||||
#else
|
|
||||||
".filterloop%=: \n"
|
|
||||||
"\tldrsh %6, [%2], #2\n"
|
|
||||||
"\tldr %10, [%0, #4]\n"
|
|
||||||
"\tmov %8, %8, lsr #15\n"
|
|
||||||
"\tsmull %7, %11, %5, %6\n"
|
|
||||||
"\tadd %8, %8, %9, lsl #17\n"
|
|
||||||
"\tldrsh %6, [%1], #2\n"
|
|
||||||
"\tadd %10, %10, %8\n"
|
|
||||||
"\tsmull %8, %9, %4, %6\n"
|
|
||||||
"\tadd %10, %10, %7, lsr #15\n"
|
|
||||||
"\tsubs %3, %3, #1\n"
|
|
||||||
"\tadd %10, %10, %11, lsl #17\n"
|
|
||||||
"\tstr %10, [%0], #4 \n"
|
|
||||||
"\t bne .filterloop%=\n"
|
|
||||||
#endif
|
|
||||||
"\tmov %8, %8, lsr #15\n"
|
|
||||||
"\tadd %10, %8, %9, lsl #17\n"
|
|
||||||
"\tldrsh %6, [%2], #2\n"
|
|
||||||
"\tsmull %8, %9, %5, %6\n"
|
|
||||||
"\tadd %10, %10, %8, lsr #15\n"
|
|
||||||
"\tadd %10, %10, %9, lsl #17\n"
|
|
||||||
"\tstr %10, [%0], #4 \n"
|
|
||||||
|
|
||||||
: "=r" (deadm), "=r" (deadn), "=r" (deadd), "=r" (deadidx),
|
|
||||||
"=r" (xi), "=r" (nyi), "=r" (dead1), "=r" (dead2),
|
|
||||||
"=r" (dead3), "=r" (dead4), "=r" (dead5), "=r" (dead6)
|
|
||||||
: "0" (mem), "1" (num), "2" (den), "3" (ord-1), "4" (xi), "5" (nyi)
|
|
||||||
: "cc", "memory");
|
|
||||||
|
|
||||||
}
|
|
||||||
for (i=0;i<ord;i++)
|
|
||||||
mem[i] = SHL32(mem[i],1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define OVERRIDE_IIR_MEM2
|
|
||||||
void iir_mem2(const spx_sig_t *x, const spx_coef_t *den, spx_sig_t *y, int N, int ord, spx_mem_t *mem)
|
|
||||||
{
|
|
||||||
int i/*,j*/;
|
|
||||||
spx_sig_t xi,yi,nyi;
|
|
||||||
|
|
||||||
for (i=0;i<ord;i++)
|
|
||||||
mem[i] = SHR32(mem[i],1);
|
|
||||||
|
|
||||||
for (i=0;i<N;i++)
|
|
||||||
{
|
|
||||||
int deadm, deadd, deadidx, dead1, dead2, dead3, dead4, dead5, dead6;
|
|
||||||
xi=SATURATE(x[i],805306368);
|
|
||||||
yi = SATURATE(ADD32(xi, SHL(mem[0],2)),805306368);
|
|
||||||
nyi = -yi;
|
|
||||||
y[i] = yi;
|
|
||||||
__asm__ __volatile__ (
|
|
||||||
"\tldrsh %4, [%1], #2\n"
|
|
||||||
"\tsmull %5, %6, %3, %4\n"
|
|
||||||
|
|
||||||
#ifdef SHORTCUTS
|
|
||||||
|
|
||||||
"\tldrsh %4, [%1], #2\n"
|
|
||||||
"\tmov %5, %5, lsr #15\n"
|
|
||||||
"\tldr %7, [%0, #4]\n"
|
|
||||||
"\tadd %8, %5, %6, lsl #17\n"
|
|
||||||
"\tsmull %5, %6, %3, %4\n"
|
|
||||||
"\tadd %7, %7, %8\n"
|
|
||||||
"\tstr %7, [%0], #4 \n"
|
|
||||||
|
|
||||||
|
|
||||||
"\tldrsh %4, [%1], #2\n"
|
|
||||||
"\tmov %5, %5, lsr #15\n"
|
|
||||||
"\tldr %9, [%0, #4]\n"
|
|
||||||
"\tadd %8, %5, %6, lsl #17\n"
|
|
||||||
"\tsmull %5, %6, %3, %4\n"
|
|
||||||
"\tadd %9, %9, %8\n"
|
|
||||||
"\tstr %9, [%0], #4 \n"
|
|
||||||
|
|
||||||
"\tldrsh %4, [%1], #2\n"
|
|
||||||
"\tmov %5, %5, lsr #15\n"
|
|
||||||
"\tldr %7, [%0, #4]\n"
|
|
||||||
"\tadd %8, %5, %6, lsl #17\n"
|
|
||||||
"\tsmull %5, %6, %3, %4\n"
|
|
||||||
"\tadd %7, %7, %8\n"
|
|
||||||
"\tstr %7, [%0], #4 \n"
|
|
||||||
|
|
||||||
|
|
||||||
"\tldrsh %4, [%1], #2\n"
|
|
||||||
"\tmov %5, %5, lsr #15\n"
|
|
||||||
"\tldr %9, [%0, #4]\n"
|
|
||||||
"\tadd %8, %5, %6, lsl #17\n"
|
|
||||||
"\tsmull %5, %6, %3, %4\n"
|
|
||||||
"\tadd %9, %9, %8\n"
|
|
||||||
"\tstr %9, [%0], #4 \n"
|
|
||||||
|
|
||||||
"\tldrsh %4, [%1], #2\n"
|
|
||||||
"\tmov %5, %5, lsr #15\n"
|
|
||||||
"\tldr %7, [%0, #4]\n"
|
|
||||||
"\tadd %8, %5, %6, lsl #17\n"
|
|
||||||
"\tsmull %5, %6, %3, %4\n"
|
|
||||||
"\tadd %7, %7, %8\n"
|
|
||||||
"\tstr %7, [%0], #4 \n"
|
|
||||||
|
|
||||||
|
|
||||||
"\tldrsh %4, [%1], #2\n"
|
|
||||||
"\tmov %5, %5, lsr #15\n"
|
|
||||||
"\tldr %9, [%0, #4]\n"
|
|
||||||
"\tadd %8, %5, %6, lsl #17\n"
|
|
||||||
"\tsmull %5, %6, %3, %4\n"
|
|
||||||
"\tadd %9, %9, %8\n"
|
|
||||||
"\tstr %9, [%0], #4 \n"
|
|
||||||
|
|
||||||
"\tldrsh %4, [%1], #2\n"
|
|
||||||
"\tmov %5, %5, lsr #15\n"
|
|
||||||
"\tldr %7, [%0, #4]\n"
|
|
||||||
"\tadd %8, %5, %6, lsl #17\n"
|
|
||||||
"\tsmull %5, %6, %3, %4\n"
|
|
||||||
"\tadd %7, %7, %8\n"
|
|
||||||
"\tstr %7, [%0], #4 \n"
|
|
||||||
|
|
||||||
|
|
||||||
"\tldrsh %4, [%1], #2\n"
|
|
||||||
"\tmov %5, %5, lsr #15\n"
|
|
||||||
"\tldr %9, [%0, #4]\n"
|
|
||||||
"\tadd %8, %5, %6, lsl #17\n"
|
|
||||||
"\tsmull %5, %6, %3, %4\n"
|
|
||||||
"\tadd %9, %9, %8\n"
|
|
||||||
"\tstr %9, [%0], #4 \n"
|
|
||||||
|
|
||||||
"\tldrsh %4, [%1], #2\n"
|
|
||||||
"\tmov %5, %5, lsr #15\n"
|
|
||||||
"\tldr %7, [%0, #4]\n"
|
|
||||||
"\tadd %8, %5, %6, lsl #17\n"
|
|
||||||
"\tsmull %5, %6, %3, %4\n"
|
|
||||||
"\tadd %7, %7, %8\n"
|
|
||||||
"\tstr %7, [%0], #4 \n"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#else
|
|
||||||
".iirloop%=: \n"
|
|
||||||
"\tldr %7, [%0, #4]\n"
|
|
||||||
|
|
||||||
"\tldrsh %4, [%1], #2\n"
|
|
||||||
"\tmov %5, %5, lsr #15\n"
|
|
||||||
"\tadd %8, %5, %6, lsl #17\n"
|
|
||||||
"\tsmull %5, %6, %3, %4\n"
|
|
||||||
"\tadd %7, %7, %8\n"
|
|
||||||
"\tstr %7, [%0], #4 \n"
|
|
||||||
"\tsubs %2, %2, #1\n"
|
|
||||||
"\t bne .iirloop%=\n"
|
|
||||||
|
|
||||||
#endif
|
|
||||||
"\tmov %5, %5, lsr #15\n"
|
|
||||||
"\tadd %7, %5, %6, lsl #17\n"
|
|
||||||
"\tstr %7, [%0], #4 \n"
|
|
||||||
|
|
||||||
: "=r" (deadm), "=r" (deadd), "=r" (deadidx), "=r" (nyi),
|
|
||||||
"=r" (dead1), "=r" (dead2), "=r" (dead3), "=r" (dead4),
|
|
||||||
"=r" (dead5), "=r" (dead6)
|
|
||||||
: "0" (mem), "1" (den), "2" (ord-1), "3" (nyi)
|
|
||||||
: "cc", "memory");
|
|
||||||
|
|
||||||
}
|
|
||||||
for (i=0;i<ord;i++)
|
|
||||||
mem[i] = SHL32(mem[i],1);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -79,143 +79,6 @@ int normalize16(const spx_sig_t *x, spx_word16_t *y, spx_sig_t max_scale, int le
|
||||||
return sig_shift;
|
return sig_shift;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define OVERRIDE_FILTER_MEM2
|
|
||||||
void filter_mem2(const spx_sig_t *_x, const spx_coef_t *num, const spx_coef_t *den, spx_sig_t *_y, int N, int ord, spx_mem_t *mem)
|
|
||||||
{
|
|
||||||
spx_word32_t xy2[N+1];
|
|
||||||
spx_word32_t *xy = xy2+1;
|
|
||||||
spx_word32_t numden_a[2*ord+2];
|
|
||||||
spx_word16_t *numden = (spx_word16_t*) numden_a;
|
|
||||||
int i;
|
|
||||||
for (i=0;i<ord;i++)
|
|
||||||
{
|
|
||||||
numden[2*i] = num[i];
|
|
||||||
numden[2*i+1] = den[i];
|
|
||||||
}
|
|
||||||
__asm__ __volatile__
|
|
||||||
(
|
|
||||||
/* Register setup */
|
|
||||||
"R0 = %5;\n\t" /*ord */
|
|
||||||
|
|
||||||
"P0 = %3;\n\t"
|
|
||||||
"I0 = P0;\n\t"
|
|
||||||
"B0 = P0;\n\t" /* numden */
|
|
||||||
"L0 = 0;\n\t"
|
|
||||||
|
|
||||||
"P2 = %0;\n\t" /* Fused xy */
|
|
||||||
"I2 = P2;\n\t"
|
|
||||||
"L2 = 0;\n\t"
|
|
||||||
|
|
||||||
"P4 = %6;\n\t" /* mem */
|
|
||||||
"P0 = %1;\n\t" /* _x */
|
|
||||||
"P1 = %2;\n\t" /* _y */
|
|
||||||
|
|
||||||
/* First sample */
|
|
||||||
"R1 = [P4++];\n\t"
|
|
||||||
"R1 <<= 1;\n\t" /* shift mem */
|
|
||||||
"R2 = [P0++];\n\t" /* load x[0] */
|
|
||||||
"R1 = R1 + R2;\n\t"
|
|
||||||
"[P1++] = R1;\n\t" /* store y[0] */
|
|
||||||
"R1 <<= 2;\n\t"
|
|
||||||
"R2 <<= 2;\n\t"
|
|
||||||
"R2 = PACK(R1.H, R2.H);\n\t" /* pack x16 and y16 */
|
|
||||||
"[P2] = R2;\n\t"
|
|
||||||
|
|
||||||
/* Samples 1 to ord-1 (using memory) */
|
|
||||||
"R0 += -1;\n\t"
|
|
||||||
"R3 = 0;\n\t"
|
|
||||||
"LC0 = R0;\n\t"
|
|
||||||
"LOOP filter_start%= LC0;\n\t"
|
|
||||||
"LOOP_BEGIN filter_start%=;\n\t"
|
|
||||||
"R3 += 1;\n\t"
|
|
||||||
"LC1 = R3;\n\t"
|
|
||||||
|
|
||||||
"R1 = [P4++];\n\t"
|
|
||||||
"A1 = R1;\n\t"
|
|
||||||
"A0 = 0;\n\t"
|
|
||||||
"I0 = B0;\n\t"
|
|
||||||
"I2 = P2;\n\t"
|
|
||||||
"P2 += 4;\n\t"
|
|
||||||
"R4 = [I0++] || R5 = [I2--];\n\t"
|
|
||||||
"LOOP filter_start_inner%= LC1;\n\t"
|
|
||||||
"LOOP_BEGIN filter_start_inner%=;\n\t"
|
|
||||||
"A1 -= R4.H*R5.H, A0 += R4.L*R5.L (IS) || R4 = [I0++] || R5 = [I2--];\n\t"
|
|
||||||
"LOOP_END filter_start_inner%=;\n\t"
|
|
||||||
"A0 += A1;\n\t"
|
|
||||||
"R4 = A0;\n\t"
|
|
||||||
"R4 <<= 1;\n\t" /* shift mem */
|
|
||||||
"R2 = [P0++];\n\t" /* load x */
|
|
||||||
"R4 = R4 + R2;\n\t"
|
|
||||||
"[P1++] = R4;\n\t" /* store y */
|
|
||||||
"R4 <<= 2;\n\t"
|
|
||||||
"R2 <<= 2;\n\t"
|
|
||||||
"R2 = PACK(R4.H, R2.H);\n\t" /* pack x16 and y16 */
|
|
||||||
"[P2] = R2;\n\t"
|
|
||||||
|
|
||||||
"LOOP_END filter_start%=;\n\t"
|
|
||||||
|
|
||||||
/* Samples ord to N*/
|
|
||||||
"R0 = %5;\n\t"
|
|
||||||
"R0 <<= 1;\n\t"
|
|
||||||
"I0 = B0;\n\t" /* numden */
|
|
||||||
"R0 <<= 1;\n\t"
|
|
||||||
"L0 = R0;\n\t"
|
|
||||||
|
|
||||||
"R0 = %5;\n\t" /* org */
|
|
||||||
"R2 = %4;\n\t" /* N */
|
|
||||||
"R2 = R2 - R0;\n\t"
|
|
||||||
"R4 = [I0++];\n\t" /* numden */
|
|
||||||
"LC0 = R2;\n\t"
|
|
||||||
"P3 = R0;\n\t"
|
|
||||||
"R0 <<= 2;\n\t"
|
|
||||||
"R0 += 8;\n\t"
|
|
||||||
"I2 = P2;\n\t"
|
|
||||||
"M0 = R0;\n\t"
|
|
||||||
"A1 = A0 = 0;\n\t"
|
|
||||||
"R5 = [I2--];\n\t" /* load xy */
|
|
||||||
"LOOP filter_mid%= LC0;\n\t"
|
|
||||||
"LOOP_BEGIN filter_mid%=;\n\t"
|
|
||||||
"LOOP filter_mid_inner%= LC1=P3;\n\t"
|
|
||||||
"LOOP_BEGIN filter_mid_inner%=;\n\t"
|
|
||||||
"A1 -= R4.H*R5.H, A0 += R4.L*R5.L (IS) || R4 = [I0++] || R5 = [I2--];\n\t"
|
|
||||||
"LOOP_END filter_mid_inner%=;\n\t"
|
|
||||||
"R0 = (A0 += A1) || I2 += M0;\n\t"
|
|
||||||
"R0 = R0 << 1 || R5 = [P0++];\n\t" /* load x */
|
|
||||||
"R0 = R0 + R5;\n\t"
|
|
||||||
"R0 = R0 << 2 || [P1++] = R0;\n\t" /* shift y | store y */
|
|
||||||
"R5 = R5 << 2;\n\t"
|
|
||||||
"R5 = PACK(R0.H, R5.H);\n\t"
|
|
||||||
"A1 = A0 = 0 || [I2--] = R5\n\t"
|
|
||||||
"LOOP_END filter_mid%=;\n\t"
|
|
||||||
"I2 += 4;\n\t"
|
|
||||||
"P2 = I2;\n\t"
|
|
||||||
/* Update memory */
|
|
||||||
"P4 = %6;\n\t"
|
|
||||||
"R0 = %5;\n\t"
|
|
||||||
"LC0 = R0;\n\t"
|
|
||||||
"P0 = B0;\n\t"
|
|
||||||
"A1 = A0 = 0;\n\t"
|
|
||||||
"LOOP mem_update%= LC0;\n\t"
|
|
||||||
"LOOP_BEGIN mem_update%=;\n\t"
|
|
||||||
"I2 = P2;\n\t"
|
|
||||||
"I0 = P0;\n\t"
|
|
||||||
"P0 += 4;\n\t"
|
|
||||||
"R0 = LC0;\n\t"
|
|
||||||
"LC1 = R0;\n\t"
|
|
||||||
"R5 = [I2--] || R4 = [I0++];\n\t"
|
|
||||||
"LOOP mem_accum%= LC1;\n\t"
|
|
||||||
"LOOP_BEGIN mem_accum%=;\n\t"
|
|
||||||
"A1 -= R4.H*R5.H, A0 += R4.L*R5.L (IS) || R4 = [I0++] || R5 = [I2--];\n\t"
|
|
||||||
"LOOP_END mem_accum%=;\n\t"
|
|
||||||
"R0 = (A0 += A1);\n\t"
|
|
||||||
"A1 = A0 = 0 || [P4++] = R0;\n\t"
|
|
||||||
"LOOP_END mem_update%=;\n\t"
|
|
||||||
"L0 = 0;\n\t"
|
|
||||||
: : "m" (xy), "m" (_x), "m" (_y), "m" (numden), "m" (N), "m" (ord), "m" (mem)
|
|
||||||
: "A0", "A1", "R0", "R1", "R2", "R3", "R4", "R5", "P0", "P1", "P2", "P3", "P4", "B0", "I0", "I2", "L0", "L2", "M0", "memory"
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define OVERRIDE_FILTER_MEM16
|
#define OVERRIDE_FILTER_MEM16
|
||||||
|
@ -363,130 +226,6 @@ void filter_mem16(const spx_word16_t *_x, const spx_coef_t *num, const spx_coef_
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define OVERRIDE_IIR_MEM2
|
|
||||||
void iir_mem2(const spx_sig_t *_x, const spx_coef_t *den, spx_sig_t *_y, int N, int ord, spx_mem_t *mem)
|
|
||||||
{
|
|
||||||
spx_word16_t y[N+2];
|
|
||||||
spx_word16_t *yy;
|
|
||||||
yy = y+2;
|
|
||||||
__asm__ __volatile__
|
|
||||||
(
|
|
||||||
/* Register setup */
|
|
||||||
"R0 = %5;\n\t" /*ord */
|
|
||||||
|
|
||||||
"P1 = %3;\n\t"
|
|
||||||
"I1 = P1;\n\t"
|
|
||||||
"B1 = P1;\n\t"
|
|
||||||
"L1 = 0;\n\t"
|
|
||||||
|
|
||||||
"P3 = %0;\n\t"
|
|
||||||
"I3 = P3;\n\t"
|
|
||||||
"L3 = 0;\n\t"
|
|
||||||
|
|
||||||
"P4 = %6;\n\t"
|
|
||||||
"P0 = %1;\n\t"
|
|
||||||
"P1 = %2;\n\t"
|
|
||||||
|
|
||||||
/* First sample */
|
|
||||||
"R1 = [P4++];\n\t"
|
|
||||||
"R1 <<= 1;\n\t"
|
|
||||||
"R2 = [P0++];\n\t"
|
|
||||||
"R1 = R1 + R2;\n\t"
|
|
||||||
"[P1++] = R1;\n\t"
|
|
||||||
"R1 <<= 2;\n\t"
|
|
||||||
"W[P3] = R1.H;\n\t"
|
|
||||||
"R2 <<= 2;\n\t"
|
|
||||||
|
|
||||||
/* Samples 1 to ord-1 (using memory) */
|
|
||||||
"R0 += -1;\n\t"
|
|
||||||
"R3 = 0;\n\t"
|
|
||||||
"LC0 = R0;\n\t"
|
|
||||||
"LOOP filter_start%= LC0;\n\t"
|
|
||||||
"LOOP_BEGIN filter_start%=;\n\t"
|
|
||||||
"R3 += 1;\n\t"
|
|
||||||
"LC1 = R3;\n\t"
|
|
||||||
|
|
||||||
"R1 = [P4++];\n\t"
|
|
||||||
"A1 = R1;\n\t"
|
|
||||||
"I1 = B1;\n\t"
|
|
||||||
"I3 = P3;\n\t"
|
|
||||||
"P3 += 2;\n\t"
|
|
||||||
"LOOP filter_start_inner%= LC1;\n\t"
|
|
||||||
"LOOP_BEGIN filter_start_inner%=;\n\t"
|
|
||||||
"R4.L = W[I1++];\n\t"
|
|
||||||
"R5.L = W[I3--];\n\t"
|
|
||||||
"A1 -= R4.L*R5.L (IS);\n\t"
|
|
||||||
"LOOP_END filter_start_inner%=;\n\t"
|
|
||||||
|
|
||||||
"R1 = A1;\n\t"
|
|
||||||
"R1 <<= 1;\n\t"
|
|
||||||
"R2 = [P0++];\n\t"
|
|
||||||
"R1 = R1 + R2;\n\t"
|
|
||||||
"[P1++] = R1;\n\t"
|
|
||||||
"R1 <<= 2;\n\t"
|
|
||||||
"W[P3] = R1.H;\n\t"
|
|
||||||
"R2 <<= 2;\n\t"
|
|
||||||
"LOOP_END filter_start%=;\n\t"
|
|
||||||
|
|
||||||
/* Samples ord to N*/
|
|
||||||
"R0 = %5;\n\t"
|
|
||||||
"R0 <<= 1;\n\t"
|
|
||||||
"I1 = B1;\n\t"
|
|
||||||
"L1 = R0;\n\t"
|
|
||||||
|
|
||||||
"R0 = %5;\n\t"
|
|
||||||
"R2 = %4;\n\t"
|
|
||||||
"R2 = R2 - R0;\n\t"
|
|
||||||
"R4.L = W[I1++];\n\t"
|
|
||||||
"LC0 = R2;\n\t"
|
|
||||||
"LOOP filter_mid%= LC0;\n\t"
|
|
||||||
"LOOP_BEGIN filter_mid%=;\n\t"
|
|
||||||
"LC1 = R0;\n\t"
|
|
||||||
"A1 = 0;\n\t"
|
|
||||||
"I3 = P3;\n\t"
|
|
||||||
"P3 += 2;\n\t"
|
|
||||||
"R5.L = W[I3--];\n\t"
|
|
||||||
"LOOP filter_mid_inner%= LC1;\n\t"
|
|
||||||
"LOOP_BEGIN filter_mid_inner%=;\n\t"
|
|
||||||
"A1 -= R4.L*R5.L (IS) || R4.L = W[I1++] || R5.L = W[I3--];\n\t"
|
|
||||||
"LOOP_END filter_mid_inner%=;\n\t"
|
|
||||||
"R1 = A1;\n\t"
|
|
||||||
"R1 = R1 << 1 || R2 = [P0++];\n\t"
|
|
||||||
"R1 = R1 + R2;\n\t"
|
|
||||||
"R1 = R1 << 2 || [P1++] = R1;\n\t"
|
|
||||||
"W[P3] = R1.H;\n\t"
|
|
||||||
"LOOP_END filter_mid%=;\n\t"
|
|
||||||
|
|
||||||
/* Update memory */
|
|
||||||
"P4 = %6;\n\t"
|
|
||||||
"R0 = %5;\n\t"
|
|
||||||
"LC0 = R0;\n\t"
|
|
||||||
"P1 = B1;\n\t"
|
|
||||||
"LOOP mem_update%= LC0;\n\t"
|
|
||||||
"LOOP_BEGIN mem_update%=;\n\t"
|
|
||||||
"A0 = 0;\n\t"
|
|
||||||
"I3 = P3;\n\t"
|
|
||||||
"I1 = P1;\n\t"
|
|
||||||
"P1 += 2;\n\t"
|
|
||||||
"R0 = LC0;\n\t"
|
|
||||||
"LC1=R0;\n\t"
|
|
||||||
"R5.L = W[I3--] || R4.L = W[I1++];\n\t"
|
|
||||||
"LOOP mem_accum%= LC1;\n\t"
|
|
||||||
"LOOP_BEGIN mem_accum%=;\n\t"
|
|
||||||
"A0 -= R4.L*R5.L (IS) || R4.L = W[I1++] || R5.L = W[I3--];\n\t"
|
|
||||||
"LOOP_END mem_accum%=;\n\t"
|
|
||||||
"R0 = A0;\n\t"
|
|
||||||
"[P4++] = R0;\n\t"
|
|
||||||
"LOOP_END mem_update%=;\n\t"
|
|
||||||
"L1 = 0;\n\t"
|
|
||||||
: : "m" (yy), "m" (_x), "m" (_y), "m" (den), "m" (N), "m" (ord), "m" (mem)
|
|
||||||
: "A0", "A1", "R0", "R1", "R2", "R3", "R4", "R5", "P0", "P1", "P2", "P3", "P4", "B1", "I1", "I3", "L1", "L3", "memory"
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define OVERRIDE_IIR_MEM16
|
#define OVERRIDE_IIR_MEM16
|
||||||
void iir_mem16(const spx_word16_t *_x, const spx_coef_t *den, spx_word16_t *_y, int N, int ord, spx_mem_t *mem, char *stack)
|
void iir_mem16(const spx_word16_t *_x, const spx_coef_t *den, spx_word16_t *_y, int N, int ord, spx_mem_t *mem, char *stack)
|
||||||
{
|
{
|
||||||
|
@ -612,18 +351,6 @@ void iir_mem16(const spx_word16_t *_x, const spx_coef_t *den, spx_word16_t *_y,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define OVERRIDE_FIR_MEM2
|
|
||||||
void fir_mem2(const spx_sig_t *x, const spx_coef_t *num, spx_sig_t *y, int N, int ord, spx_mem_t *mem)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
spx_coef_t den2[12];
|
|
||||||
spx_coef_t *den;
|
|
||||||
den = (spx_coef_t*)((((int)den2)+4)&0xfffffffc);
|
|
||||||
for (i=0;i<10;i++)
|
|
||||||
den[i] = 0;
|
|
||||||
filter_mem2(x, num, den, y, N, ord, mem);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define OVERRIDE_FIR_MEM16
|
#define OVERRIDE_FIR_MEM16
|
||||||
void fir_mem16(const spx_word16_t *x, const spx_coef_t *num, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack)
|
void fir_mem16(const spx_word16_t *x, const spx_coef_t *num, spx_word16_t *y, int N, int ord, spx_mem_t *mem, char *stack)
|
||||||
{
|
{
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
|
|
||||||
#include <xmmintrin.h>
|
#include <xmmintrin.h>
|
||||||
|
|
||||||
void filter_mem2_10(const float *x, const float *_num, const float *_den, float *y, int N, int ord, float *_mem)
|
void filter_mem16_10(const float *x, const float *_num, const float *_den, float *y, int N, int ord, float *_mem)
|
||||||
{
|
{
|
||||||
__m128 num[3], den[3], mem[3];
|
__m128 num[3], den[3], mem[3];
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ void filter_mem2_10(const float *x, const float *_num, const float *_den, float
|
||||||
_mm_store_ss(_mem+9, mem[2]);
|
_mm_store_ss(_mem+9, mem[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void filter_mem2_8(const float *x, const float *_num, const float *_den, float *y, int N, int ord, float *_mem)
|
void filter_mem16_8(const float *x, const float *_num, const float *_den, float *y, int N, int ord, float *_mem)
|
||||||
{
|
{
|
||||||
__m128 num[2], den[2], mem[2];
|
__m128 num[2], den[2], mem[2];
|
||||||
|
|
||||||
|
@ -130,18 +130,18 @@ void filter_mem2_8(const float *x, const float *_num, const float *_den, float *
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define OVERRIDE_FILTER_MEM2
|
#define OVERRIDE_FILTER_MEM16
|
||||||
void filter_mem2(const float *x, const float *_num, const float *_den, float *y, int N, int ord, float *_mem)
|
void filter_mem16(const float *x, const float *_num, const float *_den, float *y, int N, int ord, float *_mem, char *stack)
|
||||||
{
|
{
|
||||||
if(ord==10)
|
if(ord==10)
|
||||||
filter_mem2_10(x, _num, _den, y, N, ord, _mem);
|
filter_mem16_10(x, _num, _den, y, N, ord, _mem);
|
||||||
else if (ord==8)
|
else if (ord==8)
|
||||||
filter_mem2_8(x, _num, _den, y, N, ord, _mem);
|
filter_mem16_8(x, _num, _den, y, N, ord, _mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void iir_mem2_10(const float *x, const float *_den, float *y, int N, int ord, float *_mem)
|
void iir_mem16_10(const float *x, const float *_den, float *y, int N, int ord, float *_mem)
|
||||||
{
|
{
|
||||||
__m128 den[3], mem[3];
|
__m128 den[3], mem[3];
|
||||||
|
|
||||||
|
@ -190,7 +190,7 @@ void iir_mem2_10(const float *x, const float *_den, float *y, int N, int ord, fl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void iir_mem2_8(const float *x, const float *_den, float *y, int N, int ord, float *_mem)
|
void iir_mem16_8(const float *x, const float *_den, float *y, int N, int ord, float *_mem)
|
||||||
{
|
{
|
||||||
__m128 den[2], mem[2];
|
__m128 den[2], mem[2];
|
||||||
|
|
||||||
|
@ -229,17 +229,17 @@ void iir_mem2_8(const float *x, const float *_den, float *y, int N, int ord, flo
|
||||||
_mm_storeu_ps(_mem+4, mem[1]);
|
_mm_storeu_ps(_mem+4, mem[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define OVERRIDE_IIR_MEM2
|
#define OVERRIDE_IIR_MEM16
|
||||||
void iir_mem2(const float *x, const float *_den, float *y, int N, int ord, float *_mem)
|
void iir_mem16(const float *x, const float *_den, float *y, int N, int ord, float *_mem, char *stack)
|
||||||
{
|
{
|
||||||
if(ord==10)
|
if(ord==10)
|
||||||
iir_mem2_10(x, _den, y, N, ord, _mem);
|
iir_mem16_10(x, _den, y, N, ord, _mem);
|
||||||
else if (ord==8)
|
else if (ord==8)
|
||||||
iir_mem2_8(x, _den, y, N, ord, _mem);
|
iir_mem16_8(x, _den, y, N, ord, _mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void fir_mem2_10(const float *x, const float *_num, float *y, int N, int ord, float *_mem)
|
void fir_mem16_10(const float *x, const float *_num, float *y, int N, int ord, float *_mem)
|
||||||
{
|
{
|
||||||
__m128 num[3], mem[3];
|
__m128 num[3], mem[3];
|
||||||
|
|
||||||
|
@ -287,7 +287,7 @@ void fir_mem2_10(const float *x, const float *_num, float *y, int N, int ord, fl
|
||||||
_mm_store_ss(_mem+9, mem[2]);
|
_mm_store_ss(_mem+9, mem[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fir_mem2_8(const float *x, const float *_num, float *y, int N, int ord, float *_mem)
|
void fir_mem16_8(const float *x, const float *_num, float *y, int N, int ord, float *_mem)
|
||||||
{
|
{
|
||||||
__m128 num[2], mem[2];
|
__m128 num[2], mem[2];
|
||||||
|
|
||||||
|
@ -326,11 +326,11 @@ void fir_mem2_8(const float *x, const float *_num, float *y, int N, int ord, flo
|
||||||
_mm_storeu_ps(_mem+4, mem[1]);
|
_mm_storeu_ps(_mem+4, mem[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define OVERRIDE_FIR_MEM2
|
#define OVERRIDE_FIR_MEM16
|
||||||
void fir_mem2(const float *x, const float *_num, float *y, int N, int ord, float *_mem)
|
void fir_mem16(const float *x, const float *_num, float *y, int N, int ord, float *_mem, char *stack)
|
||||||
{
|
{
|
||||||
if(ord==10)
|
if(ord==10)
|
||||||
fir_mem2_10(x, _num, y, N, ord, _mem);
|
fir_mem16_10(x, _num, y, N, ord, _mem);
|
||||||
else if (ord==8)
|
else if (ord==8)
|
||||||
fir_mem2_8(x, _num, y, N, ord, _mem);
|
fir_mem16_8(x, _num, y, N, ord, _mem);
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,53 +74,57 @@ static inline int NEG32(long long x)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline short EXTRACT16(int x)
|
#define EXTRACT16(x) _EXTRACT16(x, __FILE__, __LINE__)
|
||||||
|
static inline short _EXTRACT16(int x, char *file, int line)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
if (!VERIFY_SHORT(x))
|
if (!VERIFY_SHORT(x))
|
||||||
{
|
{
|
||||||
fprintf (stderr, "EXTRACT16: input is not short: %d\n", x);
|
fprintf (stderr, "EXTRACT16: input is not short: %d in %s: line %d\n", x, file, line);
|
||||||
}
|
}
|
||||||
res = x;
|
res = x;
|
||||||
spx_mips++;
|
spx_mips++;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int EXTEND32(int x)
|
#define EXTEND32(x) _EXTEND32(x, __FILE__, __LINE__)
|
||||||
|
static inline int _EXTEND32(int x, char *file, int line)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
if (!VERIFY_SHORT(x))
|
if (!VERIFY_SHORT(x))
|
||||||
{
|
{
|
||||||
fprintf (stderr, "EXTRACT16: input is not short: %d\n", x);
|
fprintf (stderr, "EXTEND32: input is not short: %d in %s: line %d\n", x, file, line);
|
||||||
}
|
}
|
||||||
res = x;
|
res = x;
|
||||||
spx_mips++;
|
spx_mips++;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline short SHR16(int a, int shift)
|
#define SHR16(a, shift) _SHR16(a, shift, __FILE__, __LINE__)
|
||||||
|
static inline short _SHR16(int a, int shift, char *file, int line)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift))
|
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift))
|
||||||
{
|
{
|
||||||
fprintf (stderr, "SHR16: inputs are not short: %d %d\n", a, shift);
|
fprintf (stderr, "SHR16: inputs are not short: %d >> %d in %s: line %d\n", a, shift, file, line);
|
||||||
}
|
}
|
||||||
res = a>>shift;
|
res = a>>shift;
|
||||||
if (!VERIFY_SHORT(res))
|
if (!VERIFY_SHORT(res))
|
||||||
fprintf (stderr, "SHR16: output is not short: %d\n", res);
|
fprintf (stderr, "SHR16: output is not short: %d in %s: line %d\n", res, file, line);
|
||||||
spx_mips++;
|
spx_mips++;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
static inline short SHL16(int a, int shift)
|
#define SHL16(a, shift) _SHL16(a, shift, __FILE__, __LINE__)
|
||||||
|
static inline short _SHL16(int a, int shift, char *file, int line)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift))
|
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift))
|
||||||
{
|
{
|
||||||
fprintf (stderr, "SHR16: inputs are not short: %d %d\n", a, shift);
|
fprintf (stderr, "SHL16: inputs are not short: %d %d in %s: line %d\n", a, shift, file, line);
|
||||||
}
|
}
|
||||||
res = a<<shift;
|
res = a<<shift;
|
||||||
if (!VERIFY_SHORT(res))
|
if (!VERIFY_SHORT(res))
|
||||||
fprintf (stderr, "SHR16: output is not short: %d\n", res);
|
fprintf (stderr, "SHL16: output is not short: %d in %s: line %d\n", res, file, line);
|
||||||
spx_mips++;
|
spx_mips++;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -134,7 +138,9 @@ static inline int SHR32(long long a, int shift)
|
||||||
}
|
}
|
||||||
res = a>>shift;
|
res = a>>shift;
|
||||||
if (!VERIFY_INT(res))
|
if (!VERIFY_INT(res))
|
||||||
|
{
|
||||||
fprintf (stderr, "SHR32: output is not int: %d\n", (int)res);
|
fprintf (stderr, "SHR32: output is not int: %d\n", (int)res);
|
||||||
|
}
|
||||||
spx_mips++;
|
spx_mips++;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -143,62 +149,71 @@ static inline int SHL32(long long a, int shift)
|
||||||
long long res;
|
long long res;
|
||||||
if (!VERIFY_INT(a) || !VERIFY_SHORT(shift))
|
if (!VERIFY_INT(a) || !VERIFY_SHORT(shift))
|
||||||
{
|
{
|
||||||
fprintf (stderr, "SHR32: inputs are not int: %d %d\n", (int)a, shift);
|
fprintf (stderr, "SHL32: inputs are not int: %d %d\n", (int)a, shift);
|
||||||
}
|
}
|
||||||
res = a<<shift;
|
res = a<<shift;
|
||||||
if (!VERIFY_INT(res))
|
if (!VERIFY_INT(res))
|
||||||
fprintf (stderr, "SHR32: output is not int: %d\n", (int)res);
|
{
|
||||||
|
fprintf (stderr, "SHL32: output is not int: %d\n", (int)res);
|
||||||
|
}
|
||||||
spx_mips++;
|
spx_mips++;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define PSHR16(a,shift) (SHR16(ADD16((a),((1<<((shift))>>1))),shift))
|
||||||
|
#define PSHR32(a,shift) (SHR32(ADD32((a),((1<<((shift))>>1))),shift))
|
||||||
|
#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift)))
|
||||||
|
|
||||||
#define PSHR16(a,shift) (SHR16(ADD16(a,(1<<((shift)-1))),shift))
|
|
||||||
#define PSHR32(a,shift) (SHR32(ADD32(a,(1<<((shift)-1))),shift))
|
|
||||||
#define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
|
#define SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
|
||||||
#define SATURATE32(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 SHR(a,shift) ((a) >> (shift))
|
||||||
#define SHL(a,shift) ((a) << (shift))
|
//#define SHL(a,shift) ((a) << (shift))
|
||||||
|
|
||||||
static inline short ADD16(int a, int b)
|
#define ADD16(a, b) _ADD16(a, b, __FILE__, __LINE__)
|
||||||
|
static inline short _ADD16(int a, int b, char *file, int line)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
|
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
|
||||||
{
|
{
|
||||||
fprintf (stderr, "ADD16: inputs are not short: %d %d\n", a, b);
|
fprintf (stderr, "ADD16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
|
||||||
}
|
}
|
||||||
res = a+b;
|
res = a+b;
|
||||||
if (!VERIFY_SHORT(res))
|
if (!VERIFY_SHORT(res))
|
||||||
fprintf (stderr, "ADD16: output is not short: %d+%d=%d\n", a,b,res);
|
|
||||||
spx_mips++;
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
static inline short SUB16(int a, int b)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
|
|
||||||
{
|
{
|
||||||
fprintf (stderr, "SUB16: inputs are not short: %d %d\n", a, b);
|
fprintf (stderr, "ADD16: output is not short: %d+%d=%d in %s: line %d\n", a,b,res, file, line);
|
||||||
}
|
}
|
||||||
res = a-b;
|
|
||||||
if (!VERIFY_SHORT(res))
|
|
||||||
fprintf (stderr, "SUB16: output is not short: %d\n", res);
|
|
||||||
spx_mips++;
|
spx_mips++;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int ADD32(long long a, long long b)
|
#define SUB16(a, b) _SUB16(a, b, __FILE__, __LINE__)
|
||||||
|
static inline short _SUB16(int a, int b, char *file, int line)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
|
||||||
|
{
|
||||||
|
fprintf (stderr, "SUB16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
|
||||||
|
}
|
||||||
|
res = a-b;
|
||||||
|
if (!VERIFY_SHORT(res))
|
||||||
|
fprintf (stderr, "SUB16: output is not short: %d in %s: line %d\n", res, file, line);
|
||||||
|
spx_mips++;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ADD32(a, b) _ADD32(a, b, __FILE__, __LINE__)
|
||||||
|
static inline int _ADD32(long long a, long long b, char *file, int line)
|
||||||
{
|
{
|
||||||
long long res;
|
long long res;
|
||||||
if (!VERIFY_INT(a) || !VERIFY_INT(b))
|
if (!VERIFY_INT(a) || !VERIFY_INT(b))
|
||||||
{
|
{
|
||||||
fprintf (stderr, "ADD32: inputs are not int: %d %d\n", (int)a, (int)b);
|
fprintf (stderr, "ADD32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
|
||||||
}
|
}
|
||||||
res = a+b;
|
res = a+b;
|
||||||
if (!VERIFY_INT(res))
|
if (!VERIFY_INT(res))
|
||||||
{
|
{
|
||||||
fprintf (stderr, "ADD32: output is not int: %d\n", (int)res);
|
fprintf (stderr, "ADD32: output is not int: %d in %s: line %d\n", (int)res, file, line);
|
||||||
}
|
}
|
||||||
spx_mips++;
|
spx_mips++;
|
||||||
return res;
|
return res;
|
||||||
|
@ -220,8 +235,6 @@ static inline int SUB32(long long a, long long b)
|
||||||
|
|
||||||
#define ADD64(a,b) (MIPS_INC(a)+(b))
|
#define ADD64(a,b) (MIPS_INC(a)+(b))
|
||||||
|
|
||||||
#define PSHR(a,shift) (SHR((a)+(1<<((shift)-1)),shift))
|
|
||||||
|
|
||||||
/* result fits in 16 bits */
|
/* 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)
|
||||||
{
|
{
|
||||||
|
@ -237,36 +250,56 @@ static inline short MULT16_16_16(int a, int b)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int MULT16_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)
|
||||||
{
|
{
|
||||||
long long res;
|
long long res;
|
||||||
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
|
if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
|
||||||
{
|
{
|
||||||
fprintf (stderr, "MULT16_16: inputs are not short: %d %d\n", a, b);
|
fprintf (stderr, "MULT16_16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
|
||||||
}
|
}
|
||||||
res = ((long long)a)*b;
|
res = ((long long)a)*b;
|
||||||
if (!VERIFY_INT(res))
|
if (!VERIFY_INT(res))
|
||||||
fprintf (stderr, "MULT16_16: output is not int: %d\n", (int)res);
|
fprintf (stderr, "MULT16_16: output is not int: %d in %s: line %d\n", (int)res, file, line);
|
||||||
spx_mips++;
|
spx_mips++;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAC16_16(c,a,b) (spx_mips--,ADD32((c),MULT16_16((a),(b))))
|
#define MAC16_16(c,a,b) (spx_mips--,ADD32((c),MULT16_16((a),(b))))
|
||||||
#define MAC16_16_Q11(c,a,b) (ADD16((c),EXTRACT16(SHR32(MULT16_16((a),(b)),11))))
|
#define MAC16_16_Q11(c,a,b) (EXTRACT16(ADD16((c),EXTRACT16(SHR32(MULT16_16((a),(b)),11)))))
|
||||||
#define MAC16_16_Q13(c,a,b) (ADD16((c),EXTRACT16(SHR32(MULT16_16((a),(b)),13))))
|
#define MAC16_16_Q13(c,a,b) (EXTRACT16(ADD16((c),EXTRACT16(SHR32(MULT16_16((a),(b)),13)))))
|
||||||
#define MAC16_16_P13(c,a,b) (ADD32((c),SHR(ADD32(4096,MULT16_16((a),(b))),13)))
|
#define MAC16_16_P13(c,a,b) (EXTRACT16(ADD32((c),SHR32(ADD32(4096,MULT16_16((a),(b))),13))))
|
||||||
|
|
||||||
|
|
||||||
static inline int MULT16_32_QX(int a, long long b, int Q)
|
#define MULT16_32_QX(a, b, Q) _MULT16_32_QX(a, b, Q, __FILE__, __LINE__)
|
||||||
|
static inline int _MULT16_32_QX(int a, long long b, int Q, char *file, int line)
|
||||||
{
|
{
|
||||||
long long res;
|
long long res;
|
||||||
if (!VERIFY_SHORT(a) || !VERIFY_INT(b))
|
if (!VERIFY_SHORT(a) || !VERIFY_INT(b))
|
||||||
{
|
{
|
||||||
fprintf (stderr, "MULT16_32_Q%d: inputs are not short+int: %d %d\n", Q, (int)a, (int)b);
|
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);
|
||||||
res = (((long long)a)*(long long)b) >> Q;
|
res = (((long long)a)*(long long)b) >> Q;
|
||||||
if (!VERIFY_INT(res))
|
if (!VERIFY_INT(res))
|
||||||
fprintf (stderr, "MULT16_32_Q%d: output is not int: %d*%d=%d\n", Q, (int)a, (int)b,(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);
|
||||||
|
spx_mips+=5;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int MULT16_32_PX(int a, long long b, int Q)
|
||||||
|
{
|
||||||
|
long long res;
|
||||||
|
if (!VERIFY_SHORT(a) || !VERIFY_INT(b))
|
||||||
|
{
|
||||||
|
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<<Q)>>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;
|
spx_mips+=5;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -278,6 +311,7 @@ static inline int MULT16_32_QX(int a, long long b, int Q)
|
||||||
#define MULT16_32_Q13(a,b) MULT16_32_QX(a,b,13)
|
#define MULT16_32_Q13(a,b) MULT16_32_QX(a,b,13)
|
||||||
#define MULT16_32_Q14(a,b) MULT16_32_QX(a,b,14)
|
#define MULT16_32_Q14(a,b) MULT16_32_QX(a,b,14)
|
||||||
#define MULT16_32_Q15(a,b) MULT16_32_QX(a,b,15)
|
#define MULT16_32_Q15(a,b) MULT16_32_QX(a,b,15)
|
||||||
|
#define MULT16_32_P15(a,b) MULT16_32_PX(a,b,15)
|
||||||
#define MAC16_32_Q15(c,a,b) ADD32((c),MULT16_32_Q15((a),(b)))
|
#define MAC16_32_Q15(c,a,b) ADD32((c),MULT16_32_Q15((a),(b)))
|
||||||
|
|
||||||
static inline int SATURATE(int a, int b)
|
static inline int SATURATE(int a, int b)
|
||||||
|
@ -341,7 +375,9 @@ static inline short MULT16_16_Q15(int a, int b)
|
||||||
res = ((long long)a)*b;
|
res = ((long long)a)*b;
|
||||||
res >>= 15;
|
res >>= 15;
|
||||||
if (!VERIFY_SHORT(res))
|
if (!VERIFY_SHORT(res))
|
||||||
|
{
|
||||||
fprintf (stderr, "MULT16_16_Q15: output is not short: %d\n", (int)res);
|
fprintf (stderr, "MULT16_16_Q15: output is not short: %d\n", (int)res);
|
||||||
|
}
|
||||||
spx_mips+=3;
|
spx_mips+=3;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -398,23 +434,24 @@ static inline short MULT16_16_P15(int a, int b)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define DIV32_16(a, b) _DIV32_16(a, b, __FILE__, __LINE__)
|
||||||
|
|
||||||
static inline int DIV32_16(long long a, long long b)
|
static inline int _DIV32_16(long long a, long long b, char *file, int line)
|
||||||
{
|
{
|
||||||
long long res;
|
long long res;
|
||||||
if (b==0)
|
if (b==0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "DIV32_16: divide by zero: %d/%d\n", (int)a, (int)b);
|
fprintf(stderr, "DIV32_16: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (!VERIFY_INT(a) || !VERIFY_SHORT(b))
|
if (!VERIFY_INT(a) || !VERIFY_SHORT(b))
|
||||||
{
|
{
|
||||||
fprintf (stderr, "DIV32_16: inputs are not int/short: %d %d\n", (int)a, (int)b);
|
fprintf (stderr, "DIV32_16: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
|
||||||
}
|
}
|
||||||
res = a/b;
|
res = a/b;
|
||||||
if (!VERIFY_SHORT(res))
|
if (!VERIFY_SHORT(res))
|
||||||
{
|
{
|
||||||
fprintf (stderr, "DIV32_16: output is not short: %d / %d = %d\n", (int)a,(int)b,(int)res);
|
fprintf (stderr, "DIV32_16: output is not short: %d / %d = %d in %s: line %d\n", (int)a,(int)b,(int)res, file, line);
|
||||||
if (res>32767)
|
if (res>32767)
|
||||||
res = 32767;
|
res = 32767;
|
||||||
if (res<-32768)
|
if (res<-32768)
|
||||||
|
@ -423,22 +460,24 @@ static inline int DIV32_16(long long a, long long b)
|
||||||
spx_mips+=20;
|
spx_mips+=20;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
static inline int DIV32(long long a, long long b)
|
|
||||||
|
#define DIV32(a, b) _DIV32(a, b, __FILE__, __LINE__)
|
||||||
|
static inline int _DIV32(long long a, long long b, char *file, int line)
|
||||||
{
|
{
|
||||||
long long res;
|
long long res;
|
||||||
if (b==0)
|
if (b==0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "DIV32: divide by zero: %d/%d\n", (int)a, (int)b);
|
fprintf(stderr, "DIV32: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!VERIFY_INT(a) || !VERIFY_INT(b))
|
if (!VERIFY_INT(a) || !VERIFY_INT(b))
|
||||||
{
|
{
|
||||||
fprintf (stderr, "DIV32: inputs are not int/short: %d %d\n", (int)a, (int)b);
|
fprintf (stderr, "DIV32: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
|
||||||
}
|
}
|
||||||
res = a/b;
|
res = a/b;
|
||||||
if (!VERIFY_INT(res))
|
if (!VERIFY_INT(res))
|
||||||
fprintf (stderr, "DIV32: output is not int: %d\n", (int)res);
|
fprintf (stderr, "DIV32: output is not int: %d in %s: line %d\n", (int)res, file, line);
|
||||||
spx_mips+=36;
|
spx_mips+=36;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,14 +46,15 @@
|
||||||
#define SHL16(a,shift) ((a) << (shift))
|
#define SHL16(a,shift) ((a) << (shift))
|
||||||
#define SHR32(a,shift) ((a) >> (shift))
|
#define SHR32(a,shift) ((a) >> (shift))
|
||||||
#define SHL32(a,shift) ((a) << (shift))
|
#define SHL32(a,shift) ((a) << (shift))
|
||||||
#define PSHR16(a,shift) (SHR16((a)+(1<<((shift)-1)),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)+((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 SATURATE16(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
|
||||||
#define SATURATE32(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 SHR(a,shift) ((a) >> (shift))
|
||||||
#define SHL(a,shift) ((spx_word32_t)(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)+((1<<((shift))>>1)),shift))
|
||||||
#define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
|
#define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
|
||||||
|
|
||||||
|
|
||||||
|
@ -77,6 +78,7 @@
|
||||||
#define MULT16_32_Q11(a,b) ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11))
|
#define MULT16_32_Q11(a,b) ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11))
|
||||||
#define MAC16_32_Q11(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11)))
|
#define MAC16_32_Q11(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),11)), SHR(MULT16_16((a),((b)&0x000007ff)),11)))
|
||||||
|
|
||||||
|
#define MULT16_32_P15(a,b) ADD32(MULT16_16((a),SHR((b),15)), PSHR(MULT16_16((a),((b)&0x00007fff)),15))
|
||||||
#define MULT16_32_Q15(a,b) ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15))
|
#define MULT16_32_Q15(a,b) ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15))
|
||||||
#define MAC16_32_Q15(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)))
|
#define MAC16_32_Q15(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)))
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,10 @@
|
||||||
#include <speex/speex.h>
|
#include <speex/speex.h>
|
||||||
#include <speex/speex_bits.h>
|
#include <speex/speex_bits.h>
|
||||||
#include <speex/speex_jitter.h>
|
#include <speex/speex_jitter.h>
|
||||||
#include <stdio.h>
|
|
||||||
|
#ifndef NULL
|
||||||
|
#define NULL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#define LATE_BINS 10
|
#define LATE_BINS 10
|
||||||
#define MAX_MARGIN 30 /**< Number of bins in margin histogram */
|
#define MAX_MARGIN 30 /**< Number of bins in margin histogram */
|
||||||
|
@ -181,7 +184,7 @@ void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet)
|
||||||
|
|
||||||
/* Copy packet in buffer */
|
/* Copy packet in buffer */
|
||||||
jitter->buf[i]=(char*)speex_alloc(packet->len);
|
jitter->buf[i]=(char*)speex_alloc(packet->len);
|
||||||
for (j=0;j<(signed int)packet->len;j++)
|
for (j=0;((unsigned)j)<packet->len;j++)
|
||||||
jitter->buf[i][j]=packet->data[j];
|
jitter->buf[i][j]=packet->data[j];
|
||||||
jitter->timestamp[i]=packet->timestamp;
|
jitter->timestamp[i]=packet->timestamp;
|
||||||
jitter->span[i]=packet->span;
|
jitter->span[i]=packet->span;
|
||||||
|
@ -378,7 +381,7 @@ int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint
|
||||||
/* Check for potential overflow */
|
/* Check for potential overflow */
|
||||||
packet->len = jitter->len[i];
|
packet->len = jitter->len[i];
|
||||||
/* Copy packet */
|
/* Copy packet */
|
||||||
for (j=0;j<(signed int)packet->len;j++)
|
for (j=0;((unsigned)j)<packet->len;j++)
|
||||||
packet->data[j] = jitter->buf[i][j];
|
packet->data[j] = jitter->buf[i][j];
|
||||||
/* Remove packet */
|
/* Remove packet */
|
||||||
speex_free(jitter->buf[i]);
|
speex_free(jitter->buf[i]);
|
||||||
|
@ -424,7 +427,23 @@ void jitter_buffer_tick(JitterBuffer *jitter)
|
||||||
jitter->current_timestamp += jitter->tick_size;
|
jitter->current_timestamp += jitter->tick_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Used like the ioctl function to control the jitter buffer parameters */
|
||||||
|
int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr)
|
||||||
|
{
|
||||||
|
switch(request)
|
||||||
|
{
|
||||||
|
case JITTER_BUFFER_SET_MARGIN:
|
||||||
|
jitter->buffer_margin = *(spx_int32_t*)ptr;
|
||||||
|
break;
|
||||||
|
case JITTER_BUFFER_GET_MARGIN:
|
||||||
|
*(spx_int32_t*)ptr = jitter->buffer_margin;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
speex_warning_int("Unknown jitter_buffer_ctl request: ", request);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
|
||||||
#include "_kiss_fft_guts.h"
|
#include "_kiss_fft_guts.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "math_approx.h"
|
|
||||||
|
|
||||||
/* The guts header contains all the multiplication and addition macros that are defined for
|
/* The guts header contains all the multiplication and addition macros that are defined for
|
||||||
fixed or floating point complex numbers. It also delares the kf_ internal functions.
|
fixed or floating point complex numbers. It also delares the kf_ internal functions.
|
||||||
|
@ -55,8 +54,8 @@ static void kf_bfly2(
|
||||||
kiss_fft_cpx *x=Fout;
|
kiss_fft_cpx *x=Fout;
|
||||||
for (i=0;i<2*m;i++)
|
for (i=0;i<2*m;i++)
|
||||||
{
|
{
|
||||||
x[i].r = SHR(x[i].r,1);
|
x[i].r = SHR16(x[i].r,1);
|
||||||
x[i].i = SHR(x[i].i,1);
|
x[i].i = SHR16(x[i].i,1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,9 +85,9 @@ static void kf_bfly4(
|
||||||
tw3 = tw2 = tw1 = st->twiddles;
|
tw3 = tw2 = tw1 = st->twiddles;
|
||||||
|
|
||||||
if (!st->inverse) {
|
if (!st->inverse) {
|
||||||
int i;
|
unsigned int i;
|
||||||
kiss_fft_cpx *x=Fout;
|
kiss_fft_cpx *x=Fout;
|
||||||
for (i=0;i<4*(signed int)m;i++)
|
for (i=0;i<4*m;i++)
|
||||||
{
|
{
|
||||||
x[i].r = PSHR16(x[i].r,2);
|
x[i].r = PSHR16(x[i].r,2);
|
||||||
x[i].i = PSHR16(x[i].i,2);
|
x[i].i = PSHR16(x[i].i,2);
|
||||||
|
@ -339,8 +338,6 @@ static
|
||||||
void kf_factor(int n,int * facbuf)
|
void kf_factor(int n,int * facbuf)
|
||||||
{
|
{
|
||||||
int p=4;
|
int p=4;
|
||||||
double floor_sqrt;
|
|
||||||
floor_sqrt = floor( sqrt((double)n) );
|
|
||||||
|
|
||||||
/*factor out powers of 4, powers of 2, then any remaining primes */
|
/*factor out powers of 4, powers of 2, then any remaining primes */
|
||||||
do {
|
do {
|
||||||
|
@ -350,7 +347,7 @@ void kf_factor(int n,int * facbuf)
|
||||||
case 2: p = 3; break;
|
case 2: p = 3; break;
|
||||||
default: p += 2; break;
|
default: p += 2; break;
|
||||||
}
|
}
|
||||||
if (p > floor_sqrt)
|
if (p>32000 || (spx_int32_t)p*(spx_int32_t)p > n)
|
||||||
p = n; /* no more factors, skip to end */
|
p = n; /* no more factors, skip to end */
|
||||||
}
|
}
|
||||||
n /= p;
|
n /= p;
|
||||||
|
@ -358,7 +355,6 @@ void kf_factor(int n,int * facbuf)
|
||||||
*facbuf++ = n;
|
*facbuf++ = n;
|
||||||
} while (n > 1);
|
} while (n > 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* User-callable function to allocate all necessary storage space for the fft.
|
* User-callable function to allocate all necessary storage space for the fft.
|
||||||
|
@ -383,15 +379,22 @@ kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem
|
||||||
int i;
|
int i;
|
||||||
st->nfft=nfft;
|
st->nfft=nfft;
|
||||||
st->inverse = inverse_fft;
|
st->inverse = inverse_fft;
|
||||||
|
#ifdef FIXED_POINT
|
||||||
for (i=0;i<nfft;++i) {
|
for (i=0;i<nfft;++i) {
|
||||||
const double pi=3.14159265358979323846264338327;
|
spx_word32_t phase = i;
|
||||||
double phase = ( -2*pi /nfft ) * i;
|
if (!st->inverse)
|
||||||
if (st->inverse)
|
phase = -phase;
|
||||||
phase *= -1;
|
kf_cexp2(st->twiddles+i, DIV32(SHL32(phase,17),nfft));
|
||||||
kf_cexp(st->twiddles+i, phase );
|
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
for (i=0;i<nfft;++i) {
|
||||||
|
const double pi=3.14159265358979323846264338327;
|
||||||
|
double phase = ( -2*pi /nfft ) * i;
|
||||||
|
if (st->inverse)
|
||||||
|
phase *= -1;
|
||||||
|
kf_cexp(st->twiddles+i, phase );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
kf_factor(nfft,st->factors);
|
kf_factor(nfft,st->factors);
|
||||||
}
|
}
|
||||||
return st;
|
return st;
|
||||||
|
|
|
@ -17,7 +17,6 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "kiss_fftr.h"
|
#include "kiss_fftr.h"
|
||||||
#include "math_approx.h"
|
|
||||||
#include "_kiss_fft_guts.h"
|
#include "_kiss_fft_guts.h"
|
||||||
|
|
||||||
struct kiss_fftr_state{
|
struct kiss_fftr_state{
|
||||||
|
@ -59,13 +58,22 @@ kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenme
|
||||||
st->super_twiddles = st->tmpbuf + nfft;
|
st->super_twiddles = st->tmpbuf + nfft;
|
||||||
kiss_fft_alloc(nfft, inverse_fft, st->substate, &subsize);
|
kiss_fft_alloc(nfft, inverse_fft, st->substate, &subsize);
|
||||||
|
|
||||||
for (i = 0; i < nfft; ++i) {
|
#ifdef FIXED_POINT
|
||||||
double phase =
|
for (i=0;i<nfft;++i) {
|
||||||
-3.14159265358979323846264338327 * ((double) i / nfft + .5);
|
spx_word32_t phase = i+(nfft>>1);
|
||||||
if (inverse_fft)
|
if (!inverse_fft)
|
||||||
phase *= -1;
|
phase = -phase;
|
||||||
kf_cexp (st->super_twiddles+i,phase);
|
kf_cexp2(st->super_twiddles+i, DIV32(SHL32(phase,16),nfft));
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
for (i=0;i<nfft;++i) {
|
||||||
|
const double pi=3.14159265358979323846264338327;
|
||||||
|
double phase = pi*(((double)i) /nfft + .5);
|
||||||
|
if (!inverse_fft)
|
||||||
|
phase = -phase;
|
||||||
|
kf_cexp(st->super_twiddles+i, phase );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return st;
|
return st;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,8 +84,7 @@ void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *fr
|
||||||
kiss_fft_cpx fpnk,fpk,f1k,f2k,tw,tdc;
|
kiss_fft_cpx fpnk,fpk,f1k,f2k,tw,tdc;
|
||||||
|
|
||||||
if ( st->substate->inverse) {
|
if ( st->substate->inverse) {
|
||||||
speex_warning("kiss fft usage error: improper alloc\n");
|
speex_error("kiss fft usage error: improper alloc\n");
|
||||||
//exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ncfft = st->substate->nfft;
|
ncfft = st->substate->nfft;
|
||||||
|
@ -131,8 +138,7 @@ void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata,kiss_fft_scalar *t
|
||||||
int k, ncfft;
|
int k, ncfft;
|
||||||
|
|
||||||
if (st->substate->inverse == 0) {
|
if (st->substate->inverse == 0) {
|
||||||
speex_warning ("kiss fft usage error: improper alloc\n");
|
speex_error ("kiss fft usage error: improper alloc\n");
|
||||||
//exit (1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ncfft = st->substate->nfft;
|
ncfft = st->substate->nfft;
|
||||||
|
|
|
@ -34,74 +34,74 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
int dummy_epic_48k_variable=0;
|
const int dummy_epic_48k_variable=0;
|
||||||
#ifdef EPIC_48K
|
#ifdef EPIC_48K
|
||||||
|
|
||||||
const signed char gain_cdbk_ulbr[192] = {
|
const signed char gain_cdbk_ulbr[256] = {
|
||||||
-31, -48, -30,
|
-31, -48, -30, 10,
|
||||||
-19, -10, -18,
|
-19, -10, -18, 25,
|
||||||
-33, -22, -45,
|
-33, -22, -45, 12,
|
||||||
-5, -56, -43,
|
-5, -56, -43, 31,
|
||||||
-30, -56, -3,
|
-30, -56, -3, 28,
|
||||||
-59, -17, -52,
|
-59, -17, -52, 31,
|
||||||
-41, -60, -58,
|
-41, -60, -58, 32,
|
||||||
-64, -47, -22,
|
-64, -47, -22, 29,
|
||||||
-30, -31, -31,
|
-30, -31, -31, 2,
|
||||||
-29, -14, -31,
|
-29, -14, -31, 11,
|
||||||
-22, -37, -58,
|
-22, -37, -58, 21,
|
||||||
-31, -44, 13,
|
-31, -44, 13, 29,
|
||||||
-37, 0, 1,
|
-37, 0, 1, 35,
|
||||||
-46, -55, -35,
|
-46, -55, -35, 20,
|
||||||
-56, -14, -53,
|
-56, -14, -53, 32,
|
||||||
-8, 1, -36,
|
-8, 1, -36, 31,
|
||||||
-29, -15, -27,
|
-29, -15, -27, 13,
|
||||||
-29, -39, -28,
|
-29, -39, -28, 7,
|
||||||
-43, -5, 3,
|
-43, -5, 3, 37,
|
||||||
-51, -27, -54,
|
-51, -27, -54, 23,
|
||||||
10, -46, -36,
|
10, -46, -36, 30,
|
||||||
3, -3, -42,
|
3, -3, -42, 37,
|
||||||
-27, 16, -22,
|
-27, 16, -22, 32,
|
||||||
-34, -52, 13,
|
-34, -52, 13, 34,
|
||||||
-31, -21, -28,
|
-31, -21, -28, 8,
|
||||||
-34, -45, -40,
|
-34, -45, -40, 12,
|
||||||
-20, -48, 4,
|
-20, -48, 4, 32,
|
||||||
-40, -27, 16,
|
-40, -27, 16, 31,
|
||||||
-6, 11, -44,
|
-6, 11, -44, 41,
|
||||||
-35, 12, -5,
|
-35, 12, -5, 37,
|
||||||
19, -33, -37,
|
19, -33, -37, 29,
|
||||||
-29, 18, -32,
|
-29, 18, -32, 27,
|
||||||
-29, -23, -19,
|
-29, -23, -19, 13,
|
||||||
16, -47, -28,
|
16, -47, -28, 34,
|
||||||
-34, -30, 17,
|
-34, -30, 17, 27,
|
||||||
-20, 2, -26,
|
-20, 2, -26, 26,
|
||||||
-38, -40, -36,
|
-38, -40, -36, 9,
|
||||||
15, -14, -40,
|
15, -14, -40, 37,
|
||||||
-39, 14, -9,
|
-39, 14, -9, 38,
|
||||||
-15, 25, -39,
|
-15, 25, -39, 41,
|
||||||
-26, 19, -32,
|
-26, 19, -32, 29,
|
||||||
-39, 17, -14,
|
-39, 17, -14, 37,
|
||||||
10, -36, -26,
|
10, -36, -26, 26,
|
||||||
14, -13, -40,
|
14, -13, -40, 37,
|
||||||
-29, -21, -12,
|
-29, -21, -12, 17,
|
||||||
-8, 19, -39,
|
-8, 19, -39, 41,
|
||||||
-36, -18, 15,
|
-36, -18, 15, 33,
|
||||||
-32, -38, -38,
|
-32, -38, -38, 6,
|
||||||
-19, 4, -23,
|
-19, 4, -23, 29,
|
||||||
-38, -7, 11,
|
-38, -7, 11, 37,
|
||||||
9, -10, -39,
|
9, -10, -39, 35,
|
||||||
-37, 24, -19,
|
-37, 24, -19, 37,
|
||||||
-34, -5, -8,
|
-34, -5, -8, 27,
|
||||||
-20, 23, -41,
|
-20, 23, -41, 38,
|
||||||
-4, 17, -31,
|
-4, 17, -31, 39,
|
||||||
-17, -26, -26,
|
-17, -26, -26, 14,
|
||||||
-24, 28, -36,
|
-24, 28, -36, 36,
|
||||||
-7, 15, -39,
|
-7, 15, -39, 40,
|
||||||
-42, 16, -11,
|
-42, 16, -11, 40,
|
||||||
-29, 14, -6,
|
-29, 14, -6, 38,
|
||||||
-36, 28, -27,
|
-36, 28, -27, 35,
|
||||||
-21, 5, -26,
|
-21, 5, -26, 27,
|
||||||
11, -9, -39,
|
11, -9, -39, 37,
|
||||||
-38, -7, 13,
|
-38, -7, 13, 38
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -509,7 +509,7 @@ void lsp_to_lpc(spx_lsp_t *freq,spx_coef_t *ak,int lpcrdr, char *stack)
|
||||||
|
|
||||||
/* hard limit ak's to +/- 32767 */
|
/* hard limit ak's to +/- 32767 */
|
||||||
|
|
||||||
if (a < -32767) a = 32767;
|
if (a < -32767) a = -32767;
|
||||||
if (a > 32767) a = 32767;
|
if (a > 32767) a = 32767;
|
||||||
ak[j-1] = (short)a;
|
ak[j-1] = (short)a;
|
||||||
|
|
||||||
|
|
|
@ -1,89 +0,0 @@
|
||||||
/* Copyright (C) 2006 David Rowe */
|
|
||||||
/**
|
|
||||||
@file lsp_bfin.h
|
|
||||||
@author David Rowe
|
|
||||||
@brief LSP routines optimised for the Blackfin
|
|
||||||
*/
|
|
||||||
/*
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define OVERRIDE_CHEB_POLY_EVA
|
|
||||||
#ifdef OVERRIDE_CHEB_POLY_EVA
|
|
||||||
static inline spx_word32_t cheb_poly_eva(
|
|
||||||
spx_word16_t *coef, /* P or Q coefs in Q13 format */
|
|
||||||
spx_word16_t x, /* cos of freq (-1.0 to 1.0) in Q14 format */
|
|
||||||
int m, /* LPC order/2 */
|
|
||||||
char *stack
|
|
||||||
)
|
|
||||||
{
|
|
||||||
spx_word32_t sum;
|
|
||||||
|
|
||||||
__asm__ __volatile__
|
|
||||||
(
|
|
||||||
"P0 = %2;\n\t" /* P0: coef[m], coef[m-1],..., coef[0] */
|
|
||||||
"R4 = 8192;\n\t" /* R4: rounding constant */
|
|
||||||
"R2 = %1;\n\t" /* R2: x */
|
|
||||||
|
|
||||||
"R5 = -16383;\n\t"
|
|
||||||
"R2 = MAX(R2,R5);\n\t"
|
|
||||||
"R5 = 16383;\n\t"
|
|
||||||
"R2 = MIN(R2,R5);\n\t"
|
|
||||||
|
|
||||||
"R3 = W[P0--] (X);\n\t" /* R3: sum */
|
|
||||||
"R5 = W[P0--] (X);\n\t"
|
|
||||||
"R5 = R5.L * R2.L (IS);\n\t"
|
|
||||||
"R5 = R5 + R4;\n\t"
|
|
||||||
"R5 >>>= 14;\n\t"
|
|
||||||
"R3 = R3 + R5;\n\t"
|
|
||||||
|
|
||||||
"R0 = R2;\n\t" /* R0: b0 */
|
|
||||||
"R1 = 16384;\n\t" /* R1: b1 */
|
|
||||||
"LOOP cpe%= LC0 = %3;\n\t"
|
|
||||||
"LOOP_BEGIN cpe%=;\n\t"
|
|
||||||
"P1 = R0;\n\t"
|
|
||||||
"R0 = R2.L * R0.L (IS) || R5 = W[P0--] (X);\n\t"
|
|
||||||
"R0 >>>= 13;\n\t"
|
|
||||||
"R0 = R0 - R1;\n\t"
|
|
||||||
"R1 = P1;\n\t"
|
|
||||||
"R5 = R5.L * R0.L (IS);\n\t"
|
|
||||||
"R5 = R5 + R4;\n\t"
|
|
||||||
"R5 >>>= 14;\n\t"
|
|
||||||
"R3 = R3 + R5;\n\t"
|
|
||||||
"LOOP_END cpe%=;\n\t"
|
|
||||||
"%0 = R3;\n\t"
|
|
||||||
: "=&d" (sum)
|
|
||||||
: "a" (x), "a" (&coef[m]), "a" (m-1)
|
|
||||||
: "R0", "R1", "R3", "R2", "R4", "R5", "P0", "P1"
|
|
||||||
);
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -176,13 +176,31 @@ void open_loop_nbest_pitch(spx_word16_t *sw, int start, int end, int len, int *p
|
||||||
VARDECL(spx_word32_t *best_ener);
|
VARDECL(spx_word32_t *best_ener);
|
||||||
spx_word32_t e0;
|
spx_word32_t e0;
|
||||||
VARDECL(spx_word32_t *corr);
|
VARDECL(spx_word32_t *corr);
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
/* In fixed-point, we need only one (temporary) array of 32-bit values and two (corr16, ener16)
|
||||||
|
arrays for (normalized) 16-bit values */
|
||||||
|
VARDECL(spx_word16_t *corr16);
|
||||||
|
VARDECL(spx_word16_t *ener16);
|
||||||
|
spx_word32_t *energy;
|
||||||
|
int cshift=0, eshift=0;
|
||||||
|
int scaledown = 0;
|
||||||
|
ALLOC(corr16, end-start+1, spx_word16_t);
|
||||||
|
ALLOC(ener16, end-start+1, spx_word16_t);
|
||||||
|
ALLOC(corr, end-start+1, spx_word32_t);
|
||||||
|
energy = corr;
|
||||||
|
#else
|
||||||
|
/* In floating-point, we need to float arrays and no normalized copies */
|
||||||
VARDECL(spx_word32_t *energy);
|
VARDECL(spx_word32_t *energy);
|
||||||
|
spx_word16_t *corr16;
|
||||||
|
spx_word16_t *ener16;
|
||||||
|
ALLOC(energy, end-start+2, spx_word32_t);
|
||||||
|
ALLOC(corr, end-start+1, spx_word32_t);
|
||||||
|
corr16 = corr;
|
||||||
|
ener16 = energy;
|
||||||
|
#endif
|
||||||
|
|
||||||
ALLOC(best_score, N, spx_word32_t);
|
ALLOC(best_score, N, spx_word32_t);
|
||||||
ALLOC(best_ener, N, spx_word32_t);
|
ALLOC(best_ener, N, spx_word32_t);
|
||||||
ALLOC(corr, end-start+1, spx_word32_t);
|
|
||||||
ALLOC(energy, end-start+2, spx_word32_t);
|
|
||||||
|
|
||||||
for (i=0;i<N;i++)
|
for (i=0;i<N;i++)
|
||||||
{
|
{
|
||||||
best_score[i]=-1;
|
best_score[i]=-1;
|
||||||
|
@ -190,6 +208,24 @@ void open_loop_nbest_pitch(spx_word16_t *sw, int start, int end, int len, int *p
|
||||||
pitch[i]=start;
|
pitch[i]=start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
for (i=-end;i<len;i++)
|
||||||
|
{
|
||||||
|
if (ABS16(sw[i])>16383)
|
||||||
|
{
|
||||||
|
scaledown=1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* If the weighted input is close to saturation, then we scale it down */
|
||||||
|
if (scaledown)
|
||||||
|
{
|
||||||
|
for (i=-end;i<len;i++)
|
||||||
|
{
|
||||||
|
sw[i]=SHR16(sw[i],1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
energy[0]=inner_prod(sw-start, sw-start, len);
|
energy[0]=inner_prod(sw-start, sw-start, len);
|
||||||
e0=inner_prod(sw, sw, len);
|
e0=inner_prod(sw, sw, len);
|
||||||
for (i=start;i<end;i++)
|
for (i=start;i<end;i++)
|
||||||
|
@ -200,58 +236,41 @@ void open_loop_nbest_pitch(spx_word16_t *sw, int start, int end, int len, int *p
|
||||||
energy[i-start+1] = 0;
|
energy[i-start+1] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
eshift = normalize16(energy, ener16, 32766, end-start+1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* In fixed-point, this actually overrites the energy array (aliased to corr) */
|
||||||
pitch_xcorr(sw, sw-end, corr, len, end-start+1, stack);
|
pitch_xcorr(sw, sw-end, corr, len, end-start+1, stack);
|
||||||
|
|
||||||
/* FIXME: Fixed-point and floating-point code should be merged */
|
|
||||||
#ifdef FIXED_POINT
|
#ifdef FIXED_POINT
|
||||||
|
/* Normalize to 180 so we can square it and it still fits in 16 bits */
|
||||||
|
cshift = normalize16(corr, corr16, 180, end-start+1);
|
||||||
|
/* If we scaled weighted input down, we need to scale it up again (OK, so we've just lost the LSB, who cares?) */
|
||||||
|
if (scaledown)
|
||||||
{
|
{
|
||||||
VARDECL(spx_word16_t *corr16);
|
for (i=-end;i<len;i++)
|
||||||
VARDECL(spx_word16_t *ener16);
|
|
||||||
ALLOC(corr16, end-start+1, spx_word16_t);
|
|
||||||
ALLOC(ener16, end-start+1, spx_word16_t);
|
|
||||||
/* Normalize to 180 so we can square it and it still fits in 16 bits */
|
|
||||||
normalize16(corr, corr16, 180, end-start+1);
|
|
||||||
normalize16(energy, ener16, 180, end-start+1);
|
|
||||||
|
|
||||||
for (i=start;i<=end;i++)
|
|
||||||
{
|
{
|
||||||
spx_word16_t tmp = MULT16_16_16(corr16[i-start],corr16[i-start]);
|
sw[i]=SHL16(sw[i],1);
|
||||||
/* Instead of dividing the tmp by the energy, we multiply on the other side */
|
|
||||||
if (MULT16_16(tmp,best_ener[N-1])>MULT16_16(best_score[N-1],ADD16(1,ener16[i-start])))
|
|
||||||
{
|
|
||||||
/* We can safely put it last and then check */
|
|
||||||
best_score[N-1]=tmp;
|
|
||||||
best_ener[N-1]=ener16[i-start]+1;
|
|
||||||
pitch[N-1]=i;
|
|
||||||
/* Check if it comes in front of others */
|
|
||||||
for (j=0;j<N-1;j++)
|
|
||||||
{
|
|
||||||
if (MULT16_16(tmp,best_ener[j])>MULT16_16(best_score[j],ADD16(1,ener16[i-start])))
|
|
||||||
{
|
|
||||||
for (k=N-1;k>j;k--)
|
|
||||||
{
|
|
||||||
best_score[k]=best_score[k-1];
|
|
||||||
best_ener[k]=best_ener[k-1];
|
|
||||||
pitch[k]=pitch[k-1];
|
|
||||||
}
|
|
||||||
best_score[j]=tmp;
|
|
||||||
best_ener[j]=ener16[i-start]+1;
|
|
||||||
pitch[j]=i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#endif
|
||||||
|
|
||||||
|
/* Search for the best pitch prediction gain */
|
||||||
for (i=start;i<=end;i++)
|
for (i=start;i<=end;i++)
|
||||||
{
|
{
|
||||||
float tmp = corr[i-start]*corr[i-start];
|
spx_word16_t tmp = MULT16_16_16(corr16[i-start],corr16[i-start]);
|
||||||
if (tmp*best_ener[N-1]>best_score[N-1]*(1+energy[i-start]))
|
/* Instead of dividing the tmp by the energy, we multiply on the other side */
|
||||||
|
if (MULT16_16(tmp,best_ener[N-1])>MULT16_16(best_score[N-1],ADD16(1,ener16[i-start])))
|
||||||
{
|
{
|
||||||
for (j=0;j<N;j++)
|
/* We can safely put it last and then check */
|
||||||
|
best_score[N-1]=tmp;
|
||||||
|
best_ener[N-1]=ener16[i-start]+1;
|
||||||
|
pitch[N-1]=i;
|
||||||
|
/* Check if it comes in front of others */
|
||||||
|
for (j=0;j<N-1;j++)
|
||||||
{
|
{
|
||||||
if (tmp*best_ener[j]>best_score[j]*(1+energy[i-start]))
|
if (MULT16_16(tmp,best_ener[j])>MULT16_16(best_score[j],ADD16(1,ener16[i-start])))
|
||||||
{
|
{
|
||||||
for (k=N-1;k>j;k--)
|
for (k=N-1;k>j;k--)
|
||||||
{
|
{
|
||||||
|
@ -260,29 +279,30 @@ void open_loop_nbest_pitch(spx_word16_t *sw, int start, int end, int len, int *p
|
||||||
pitch[k]=pitch[k-1];
|
pitch[k]=pitch[k-1];
|
||||||
}
|
}
|
||||||
best_score[j]=tmp;
|
best_score[j]=tmp;
|
||||||
best_ener[j]=energy[i-start]+1;
|
best_ener[j]=ener16[i-start]+1;
|
||||||
pitch[j]=i;
|
pitch[j]=i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Compute open-loop gain */
|
/* Compute open-loop gain if necessary */
|
||||||
if (gain)
|
if (gain)
|
||||||
{
|
{
|
||||||
for (j=0;j<N;j++)
|
for (j=0;j<N;j++)
|
||||||
{
|
{
|
||||||
spx_word16_t g;
|
spx_word16_t g;
|
||||||
i=pitch[j];
|
i=pitch[j];
|
||||||
g = DIV32(corr[i-start], 10+SHR32(MULT16_16(spx_sqrt(e0),spx_sqrt(energy[i-start])),6));
|
g = DIV32(SHL32(EXTEND32(corr16[i-start]),cshift), 10+SHR32(MULT16_16(spx_sqrt(e0),spx_sqrt(SHL32(EXTEND32(ener16[i-start]),eshift))),6));
|
||||||
/* FIXME: g = max(g,corr/energy) */
|
/* FIXME: g = max(g,corr/energy) */
|
||||||
if (g<0)
|
if (g<0)
|
||||||
g = 0;
|
g = 0;
|
||||||
gain[j]=g;
|
gain[j]=g;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -342,7 +362,8 @@ const spx_word16_t *r,
|
||||||
spx_word16_t *new_target,
|
spx_word16_t *new_target,
|
||||||
int *cdbk_index,
|
int *cdbk_index,
|
||||||
int plc_tuning,
|
int plc_tuning,
|
||||||
spx_word32_t cumul_gain
|
spx_word32_t cumul_gain,
|
||||||
|
int scaledown
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
int i,j;
|
int i,j;
|
||||||
|
@ -366,6 +387,9 @@ spx_word32_t cumul_gain
|
||||||
x[1]=tmp1+nsf;
|
x[1]=tmp1+nsf;
|
||||||
x[2]=tmp1+2*nsf;
|
x[2]=tmp1+2*nsf;
|
||||||
|
|
||||||
|
for (j=0;j<nsf;j++)
|
||||||
|
new_target[j] = target[j];
|
||||||
|
|
||||||
{
|
{
|
||||||
VARDECL(spx_mem_t *mm);
|
VARDECL(spx_mem_t *mm);
|
||||||
int pp=pitch-1;
|
int pp=pitch-1;
|
||||||
|
@ -379,6 +403,16 @@ spx_word32_t cumul_gain
|
||||||
else
|
else
|
||||||
e[j]=0;
|
e[j]=0;
|
||||||
}
|
}
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
/* Scale target and excitation down if needed (avoiding overflow) */
|
||||||
|
if (scaledown)
|
||||||
|
{
|
||||||
|
for (j=0;j<nsf;j++)
|
||||||
|
e[j] = SHR16(e[j],1);
|
||||||
|
for (j=0;j<nsf;j++)
|
||||||
|
new_target[j] = SHR16(new_target[j],1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
for (j=0;j<p;j++)
|
for (j=0;j<p;j++)
|
||||||
mm[j] = 0;
|
mm[j] = 0;
|
||||||
iir_mem16(e, ak, e, nsf, p, mm, stack);
|
iir_mem16(e, ak, e, nsf, p, mm, stack);
|
||||||
|
@ -391,13 +425,18 @@ spx_word32_t cumul_gain
|
||||||
for (i=1;i>=0;i--)
|
for (i=1;i>=0;i--)
|
||||||
{
|
{
|
||||||
spx_word16_t e0=exc2[-pitch-1+i];
|
spx_word16_t e0=exc2[-pitch-1+i];
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
/* Scale excitation down if needed (avoiding overflow) */
|
||||||
|
if (scaledown)
|
||||||
|
e0 = SHR16(e0,1);
|
||||||
|
#endif
|
||||||
x[i][0]=MULT16_16_Q14(r[0], e0);
|
x[i][0]=MULT16_16_Q14(r[0], e0);
|
||||||
for (j=0;j<nsf-1;j++)
|
for (j=0;j<nsf-1;j++)
|
||||||
x[i][j+1]=ADD32(x[i+1][j],MULT16_16_P14(r[j+1], e0));
|
x[i][j+1]=ADD32(x[i+1][j],MULT16_16_P14(r[j+1], e0));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=0;i<3;i++)
|
for (i=0;i<3;i++)
|
||||||
corr[i]=inner_prod(x[i],target,nsf);
|
corr[i]=inner_prod(x[i],new_target,nsf);
|
||||||
for (i=0;i<3;i++)
|
for (i=0;i<3;i++)
|
||||||
for (j=0;j<=i;j++)
|
for (j=0;j<=i;j++)
|
||||||
A[i][j]=A[j][i]=inner_prod(x[i],x[j],nsf);
|
A[i][j]=A[j][i]=inner_prod(x[i],x[j],nsf);
|
||||||
|
@ -478,7 +517,7 @@ spx_word32_t cumul_gain
|
||||||
{
|
{
|
||||||
spx_word32_t tmp = ADD32(ADD32(MULT16_16(gain[0],x[2][i]),MULT16_16(gain[1],x[1][i])),
|
spx_word32_t tmp = ADD32(ADD32(MULT16_16(gain[0],x[2][i]),MULT16_16(gain[1],x[1][i])),
|
||||||
MULT16_16(gain[2],x[0][i]));
|
MULT16_16(gain[2],x[0][i]));
|
||||||
new_target[i] = SUB16(target[i], EXTRACT16(PSHR32(tmp,6)));
|
new_target[i] = SUB16(new_target[i], EXTRACT16(PSHR32(tmp,6)));
|
||||||
}
|
}
|
||||||
err = inner_prod(new_target, new_target, nsf);
|
err = inner_prod(new_target, new_target, nsf);
|
||||||
|
|
||||||
|
@ -520,6 +559,7 @@ spx_word32_t *cumul_gain
|
||||||
const ltp_params *params;
|
const ltp_params *params;
|
||||||
const signed char *gain_cdbk;
|
const signed char *gain_cdbk;
|
||||||
int gain_cdbk_size;
|
int gain_cdbk_size;
|
||||||
|
int scaledown=0;
|
||||||
|
|
||||||
VARDECL(int *nbest);
|
VARDECL(int *nbest);
|
||||||
|
|
||||||
|
@ -545,6 +585,25 @@ spx_word32_t *cumul_gain
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
/* Check if we need to scale everything down in the pitch search to avoid overflows */
|
||||||
|
for (i=0;i<nsf;i++)
|
||||||
|
{
|
||||||
|
if (ABS16(target[i])>16383)
|
||||||
|
{
|
||||||
|
scaledown=1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i=-end;i<nsf;i++)
|
||||||
|
{
|
||||||
|
if (ABS16(exc2[i])>16383)
|
||||||
|
{
|
||||||
|
scaledown=1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (N>end-start+1)
|
if (N>end-start+1)
|
||||||
N=end-start+1;
|
N=end-start+1;
|
||||||
if (end != start)
|
if (end != start)
|
||||||
|
@ -562,7 +621,7 @@ spx_word32_t *cumul_gain
|
||||||
for (j=0;j<nsf;j++)
|
for (j=0;j<nsf;j++)
|
||||||
exc[j]=0;
|
exc[j]=0;
|
||||||
err=pitch_gain_search_3tap(target, ak, awk1, awk2, exc, gain_cdbk, gain_cdbk_size, pitch, p, nsf,
|
err=pitch_gain_search_3tap(target, ak, awk1, awk2, exc, gain_cdbk, gain_cdbk_size, pitch, p, nsf,
|
||||||
bits, stack, exc2, r, new_target, &cdbk_index, plc_tuning, *cumul_gain);
|
bits, stack, exc2, r, new_target, &cdbk_index, plc_tuning, *cumul_gain, scaledown);
|
||||||
if (err<best_err || best_err<0)
|
if (err<best_err || best_err<0)
|
||||||
{
|
{
|
||||||
for (j=0;j<nsf;j++)
|
for (j=0;j<nsf;j++)
|
||||||
|
@ -588,7 +647,14 @@ spx_word32_t *cumul_gain
|
||||||
exc[i]=best_exc[i];
|
exc[i]=best_exc[i];
|
||||||
for (i=0;i<nsf;i++)
|
for (i=0;i<nsf;i++)
|
||||||
target[i]=best_target[i];
|
target[i]=best_target[i];
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
/* Scale target back up if needed */
|
||||||
|
if (scaledown)
|
||||||
|
{
|
||||||
|
for (i=0;i<nsf;i++)
|
||||||
|
target[i]=SHL16(target[i],1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return pitch;
|
return pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -717,8 +783,8 @@ spx_word32_t *cumul_gain
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
VARDECL(spx_sig_t *res);
|
VARDECL(spx_word16_t *res);
|
||||||
ALLOC(res, nsf, spx_sig_t);
|
ALLOC(res, nsf, spx_word16_t);
|
||||||
#ifdef FIXED_POINT
|
#ifdef FIXED_POINT
|
||||||
if (pitch_coef>63)
|
if (pitch_coef>63)
|
||||||
pitch_coef=63;
|
pitch_coef=63;
|
||||||
|
@ -734,9 +800,11 @@ spx_word32_t *cumul_gain
|
||||||
{
|
{
|
||||||
exc[i]=MULT16_32_Q15(SHL16(pitch_coef, 9),exc[i-start]);
|
exc[i]=MULT16_32_Q15(SHL16(pitch_coef, 9),exc[i-start]);
|
||||||
}
|
}
|
||||||
syn_percep_zero(exc, ak, awk1, awk2, res, nsf, p, stack);
|
|
||||||
for (i=0;i<nsf;i++)
|
for (i=0;i<nsf;i++)
|
||||||
target[i]=EXTRACT16(SATURATE(SUB32(EXTEND32(target[i]),PSHR32(res[i],SIG_SHIFT-1)),32700));
|
res[i] = EXTRACT16(PSHR32(exc[i], SIG_SHIFT-1));
|
||||||
|
syn_percep_zero16(res, ak, awk1, awk2, res, nsf, p, stack);
|
||||||
|
for (i=0;i<nsf;i++)
|
||||||
|
target[i]=EXTRACT16(SATURATE(SUB32(EXTEND32(target[i]),EXTEND32(res[i])),32700));
|
||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -770,7 +838,7 @@ int cdbk_offset
|
||||||
for (i=0;i<nsf;i++)
|
for (i=0;i<nsf;i++)
|
||||||
{
|
{
|
||||||
exc_out[i]=MULT16_16(exc[i-start],SHL16(pitch_coef,7));
|
exc_out[i]=MULT16_16(exc[i-start],SHL16(pitch_coef,7));
|
||||||
exc[i] = PSHR(exc_out[i],13);
|
exc[i] = EXTRACT16(PSHR32(exc_out[i],13));
|
||||||
}
|
}
|
||||||
*pitch_val = start;
|
*pitch_val = start;
|
||||||
gain_val[0]=gain_val[2]=0;
|
gain_val[0]=gain_val[2]=0;
|
||||||
|
|
|
@ -173,9 +173,9 @@ void pitch_xcorr(const spx_word16_t *_x, const spx_word16_t *_y, spx_word32_t *c
|
||||||
"=r" (part1), "=r" (part2), "=r" (part3), "=r" (part4),
|
"=r" (part1), "=r" (part2), "=r" (part3), "=r" (part4),
|
||||||
"=r" (x), "=r" (y), "=r" (x0),
|
"=r" (x), "=r" (y), "=r" (x0),
|
||||||
"=m" (sum1), "=m" (sum2), "=m" (sum3), "=m" (sum4), "=r" (dead1)
|
"=m" (sum1), "=m" (sum2), "=m" (sum3), "=m" (sum4), "=r" (dead1)
|
||||||
: "m" (y0), "m" (y1), "m" (y2), "m" (y3),
|
: "0" (y0), "1" (y1), "2" (y2), "3" (y3),
|
||||||
"m" (x), "m" (y),
|
"8" (x), "9" (y),
|
||||||
"m" (sum1), "m" (sum2), "m" (sum3), "m" (sum4)
|
"11" (sum1), "12" (sum2), "13" (sum3), "14" (sum4)
|
||||||
: "cc", "memory"
|
: "cc", "memory"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
32
apps/codecs/libspeex/math.h
Normal file
32
apps/codecs/libspeex/math.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/**************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Dan Everton
|
||||||
|
*
|
||||||
|
* All files in this archive are subject to the GNU General Public License.
|
||||||
|
* See the file COPYING in the source tree root for full license agreement.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef MATH_H
|
||||||
|
#define MATH_H
|
||||||
|
|
||||||
|
float floor(float);
|
||||||
|
float exp(float);
|
||||||
|
float sqrt(float);
|
||||||
|
float fabs(float);
|
||||||
|
float log(float);
|
||||||
|
float pow(float, float);
|
||||||
|
float sin(float);
|
||||||
|
float cos(float);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -34,181 +34,89 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "math_approx.h"
|
#include "math_approx.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
||||||
|
spx_int16_t spx_ilog2(spx_uint32_t x)
|
||||||
|
{
|
||||||
|
int r=0;
|
||||||
|
if (x>=(spx_int32_t)65536)
|
||||||
|
{
|
||||||
|
x >>= 16;
|
||||||
|
r += 16;
|
||||||
|
}
|
||||||
|
if (x>=256)
|
||||||
|
{
|
||||||
|
x >>= 8;
|
||||||
|
r += 8;
|
||||||
|
}
|
||||||
|
if (x>=16)
|
||||||
|
{
|
||||||
|
x >>= 4;
|
||||||
|
r += 4;
|
||||||
|
}
|
||||||
|
if (x>=4)
|
||||||
|
{
|
||||||
|
x >>= 2;
|
||||||
|
r += 2;
|
||||||
|
}
|
||||||
|
if (x>=2)
|
||||||
|
{
|
||||||
|
r += 1;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
spx_int16_t spx_ilog4(spx_uint32_t x)
|
||||||
|
{
|
||||||
|
int r=0;
|
||||||
|
if (x>=(spx_int32_t)65536)
|
||||||
|
{
|
||||||
|
x >>= 16;
|
||||||
|
r += 8;
|
||||||
|
}
|
||||||
|
if (x>=256)
|
||||||
|
{
|
||||||
|
x >>= 8;
|
||||||
|
r += 4;
|
||||||
|
}
|
||||||
|
if (x>=16)
|
||||||
|
{
|
||||||
|
x >>= 4;
|
||||||
|
r += 2;
|
||||||
|
}
|
||||||
|
if (x>=4)
|
||||||
|
{
|
||||||
|
r += 1;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef FIXED_POINT
|
#ifdef FIXED_POINT
|
||||||
|
|
||||||
/* sqrt(x) ~= 0.22178 + 1.29227*x - 0.77070*x^2 + 0.25723*x^3 (for .25 < x < 1) */
|
/* sqrt(x) ~= 0.22178 + 1.29227*x - 0.77070*x^2 + 0.25723*x^3 (for .25 < x < 1) */
|
||||||
|
/*#define C0 3634
|
||||||
|
#define C1 21173
|
||||||
|
#define C2 -12627
|
||||||
|
#define C3 4215*/
|
||||||
|
|
||||||
|
/* sqrt(x) ~= 0.22178 + 1.29227*x - 0.77070*x^2 + 0.25659*x^3 (for .25 < x < 1) */
|
||||||
#define C0 3634
|
#define C0 3634
|
||||||
#define C1 21173
|
#define C1 21173
|
||||||
#define C2 -12627
|
#define C2 -12627
|
||||||
#define C3 4215
|
#define C3 4204
|
||||||
|
|
||||||
spx_word16_t spx_sqrt(spx_word32_t x)
|
spx_word16_t spx_sqrt(spx_word32_t x)
|
||||||
{
|
{
|
||||||
int k=0;
|
int k;
|
||||||
spx_word32_t rt;
|
spx_word32_t rt;
|
||||||
|
k = spx_ilog4(x)-6;
|
||||||
if (x<=0)
|
x = VSHR32(x, (k<<1));
|
||||||
return 0;
|
|
||||||
#if 1
|
|
||||||
if (x>=16777216)
|
|
||||||
{
|
|
||||||
x>>=10;
|
|
||||||
k+=5;
|
|
||||||
}
|
|
||||||
if (x>=1048576)
|
|
||||||
{
|
|
||||||
x>>=6;
|
|
||||||
k+=3;
|
|
||||||
}
|
|
||||||
if (x>=262144)
|
|
||||||
{
|
|
||||||
x>>=4;
|
|
||||||
k+=2;
|
|
||||||
}
|
|
||||||
if (x>=32768)
|
|
||||||
{
|
|
||||||
x>>=2;
|
|
||||||
k+=1;
|
|
||||||
}
|
|
||||||
if (x>=16384)
|
|
||||||
{
|
|
||||||
x>>=2;
|
|
||||||
k+=1;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
while (x>=16384)
|
|
||||||
{
|
|
||||||
x>>=2;
|
|
||||||
k++;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
while (x<4096)
|
|
||||||
{
|
|
||||||
x<<=2;
|
|
||||||
k--;
|
|
||||||
}
|
|
||||||
rt = ADD16(C0, MULT16_16_Q14(x, ADD16(C1, MULT16_16_Q14(x, ADD16(C2, MULT16_16_Q14(x, (C3)))))));
|
rt = ADD16(C0, MULT16_16_Q14(x, ADD16(C1, MULT16_16_Q14(x, ADD16(C2, MULT16_16_Q14(x, (C3)))))));
|
||||||
if (rt > 16383)
|
rt = VSHR32(rt,7-k);
|
||||||
rt = 16383;
|
|
||||||
if (k>0)
|
|
||||||
rt <<= k;
|
|
||||||
else
|
|
||||||
rt >>= -k;
|
|
||||||
rt >>=7;
|
|
||||||
return rt;
|
return rt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int intSqrt(int x) {
|
|
||||||
int xn;
|
|
||||||
static int sqrt_table[256] = {
|
|
||||||
0, 16, 22, 27, 32, 35, 39, 42, 45, 48, 50, 53, 55, 57,
|
|
||||||
59, 61, 64, 65, 67, 69, 71, 73, 75, 76, 78, 80, 81, 83,
|
|
||||||
84, 86, 87, 89, 90, 91, 93, 94, 96, 97, 98, 99, 101, 102,
|
|
||||||
103, 104, 106, 107, 108, 109, 110, 112, 113, 114, 115, 116, 117, 118,
|
|
||||||
119, 120, 121, 122, 123, 124, 125, 126, 128, 128, 129, 130, 131, 132,
|
|
||||||
133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 144, 145,
|
|
||||||
146, 147, 148, 149, 150, 150, 151, 152, 153, 154, 155, 155, 156, 157,
|
|
||||||
158, 159, 160, 160, 161, 162, 163, 163, 164, 165, 166, 167, 167, 168,
|
|
||||||
169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 178,
|
|
||||||
179, 180, 181, 181, 182, 183, 183, 184, 185, 185, 186, 187, 187, 188,
|
|
||||||
189, 189, 190, 191, 192, 192, 193, 193, 194, 195, 195, 196, 197, 197,
|
|
||||||
198, 199, 199, 200, 201, 201, 202, 203, 203, 204, 204, 205, 206, 206,
|
|
||||||
207, 208, 208, 209, 209, 210, 211, 211, 212, 212, 213, 214, 214, 215,
|
|
||||||
215, 216, 217, 217, 218, 218, 219, 219, 220, 221, 221, 222, 222, 223,
|
|
||||||
224, 224, 225, 225, 226, 226, 227, 227, 228, 229, 229, 230, 230, 231,
|
|
||||||
231, 232, 232, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238,
|
|
||||||
239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246,
|
|
||||||
246, 247, 247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253,
|
|
||||||
253, 254, 254, 255
|
|
||||||
};
|
|
||||||
if (x >= 0x10000) {
|
|
||||||
if (x >= 0x1000000) {
|
|
||||||
if (x >= 0x10000000) {
|
|
||||||
if (x >= 0x40000000) {
|
|
||||||
xn = sqrt_table[x >> 24] << 8;
|
|
||||||
} else {
|
|
||||||
xn = sqrt_table[x >> 22] << 7;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (x >= 0x4000000) {
|
|
||||||
xn = sqrt_table[x >> 20] << 6;
|
|
||||||
} else {
|
|
||||||
xn = sqrt_table[x >> 18] << 5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
xn = (xn + 1 + (x / xn)) >> 1;
|
|
||||||
xn = (xn + 1 + (x / xn)) >> 1;
|
|
||||||
return ((xn * xn) > x) ? --xn : xn;
|
|
||||||
} else {
|
|
||||||
if (x >= 0x100000) {
|
|
||||||
if (x >= 0x400000) {
|
|
||||||
xn = sqrt_table[x >> 16] << 4;
|
|
||||||
} else {
|
|
||||||
xn = sqrt_table[x >> 14] << 3;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (x >= 0x40000) {
|
|
||||||
xn = sqrt_table[x >> 12] << 2;
|
|
||||||
} else {
|
|
||||||
xn = sqrt_table[x >> 10] << 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
xn = (xn + 1 + (x / xn)) >> 1;
|
|
||||||
|
|
||||||
return ((xn * xn) > x) ? --xn : xn;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (x >= 0x100) {
|
|
||||||
if (x >= 0x1000) {
|
|
||||||
if (x >= 0x4000) {
|
|
||||||
xn = (sqrt_table[x >> 8]) + 1;
|
|
||||||
} else {
|
|
||||||
xn = (sqrt_table[x >> 6] >> 1) + 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (x >= 0x400) {
|
|
||||||
xn = (sqrt_table[x >> 4] >> 2) + 1;
|
|
||||||
} else {
|
|
||||||
xn = (sqrt_table[x >> 2] >> 3) + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ((xn * xn) > x) ? --xn : xn;
|
|
||||||
} else {
|
|
||||||
if (x >= 0) {
|
|
||||||
return sqrt_table[x] >> 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
float spx_sqrtf(float arg)
|
|
||||||
{
|
|
||||||
if(arg==0.0)
|
|
||||||
return 0.0;
|
|
||||||
else if(arg==1.0)
|
|
||||||
return 1.0;
|
|
||||||
else if(arg==2.0)
|
|
||||||
return 1.414;
|
|
||||||
else if(arg==3.27)
|
|
||||||
return 1.8083;
|
|
||||||
//printf("Sqrt:%f:%f:%f\n",arg,(((float)intSqrt((int)(arg*10000)))/100)+0.0055,(float)spx_sqrt((spx_word32_t)arg));
|
|
||||||
//return ((float)fastSqrt((int)(arg*2500)))/50;
|
|
||||||
//LOGF("Sqrt:%d:%d\n",arg,(intSqrt((int)(arg*2500)))/50);
|
|
||||||
return (((float)intSqrt((int)(arg*10000)))/100)+0.0055;//(float)spx_sqrt((spx_word32_t)arg);
|
|
||||||
//return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* log(x) ~= -2.18151 + 4.20592*x - 2.88938*x^2 + 0.86535*x^3 (for .5 < x < 1) */
|
/* log(x) ~= -2.18151 + 4.20592*x - 2.88938*x^2 + 0.86535*x^3 (for .5 < x < 1) */
|
||||||
|
|
||||||
|
|
||||||
|
@ -259,6 +167,101 @@ spx_word16_t spx_cos(spx_word16_t x)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define L1 32767
|
||||||
|
#define L2 -7651
|
||||||
|
#define L3 8277
|
||||||
|
#define L4 -626
|
||||||
|
|
||||||
|
static inline spx_word16_t _spx_cos_pi_2(spx_word16_t x)
|
||||||
|
{
|
||||||
|
spx_word16_t x2;
|
||||||
|
|
||||||
|
x2 = MULT16_16_P15(x,x);
|
||||||
|
return ADD16(1,MIN16(32766,ADD32(SUB16(L1,x2), MULT16_16_P15(x2, ADD32(L2, MULT16_16_P15(x2, ADD32(L3, MULT16_16_P15(L4, x2))))))));
|
||||||
|
}
|
||||||
|
|
||||||
|
spx_word16_t spx_cos_norm(spx_word32_t x)
|
||||||
|
{
|
||||||
|
x = x&0x0001ffff;
|
||||||
|
if (x>SHL32(EXTEND32(1), 16))
|
||||||
|
x = SUB32(SHL32(EXTEND32(1), 17),x);
|
||||||
|
if (x&0x00007fff)
|
||||||
|
{
|
||||||
|
if (x<SHL32(EXTEND32(1), 15))
|
||||||
|
{
|
||||||
|
return _spx_cos_pi_2(EXTRACT16(x));
|
||||||
|
} else {
|
||||||
|
return NEG32(_spx_cos_pi_2(EXTRACT16(65536-x)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (x&0x0000ffff)
|
||||||
|
return 0;
|
||||||
|
else if (x&0x0001ffff)
|
||||||
|
return -32767;
|
||||||
|
else
|
||||||
|
return 32767;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
K0 = 1
|
||||||
|
K1 = log(2)
|
||||||
|
K2 = 3-4*log(2)
|
||||||
|
K3 = 3*log(2) - 2
|
||||||
|
*/
|
||||||
|
#define D0 16384
|
||||||
|
#define D1 11356
|
||||||
|
#define D2 3726
|
||||||
|
#define D3 1301
|
||||||
|
/* Input in Q11 format, output in Q16 */
|
||||||
|
static spx_word32_t spx_exp2(spx_word16_t x)
|
||||||
|
{
|
||||||
|
int integer;
|
||||||
|
spx_word16_t frac;
|
||||||
|
integer = SHR16(x,11);
|
||||||
|
if (integer>14)
|
||||||
|
return 0x7fffffff;
|
||||||
|
else if (integer < -15)
|
||||||
|
return 0;
|
||||||
|
frac = SHL16(x-SHL16(integer,11),3);
|
||||||
|
frac = ADD16(D0, MULT16_16_Q14(frac, ADD16(D1, MULT16_16_Q14(frac, ADD16(D2 , MULT16_16_Q14(D3,frac))))));
|
||||||
|
return VSHR32(EXTEND32(frac), -integer-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Input in Q11 format, output in Q16 */
|
||||||
|
spx_word32_t spx_exp(spx_word16_t x)
|
||||||
|
{
|
||||||
|
if (x>21290)
|
||||||
|
return 0x7fffffff;
|
||||||
|
else if (x<-21290)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return spx_exp2(MULT16_16_P14(23637,x));
|
||||||
|
}
|
||||||
|
#define M1 32767
|
||||||
|
#define M2 -21
|
||||||
|
#define M3 -11943
|
||||||
|
#define M4 4936
|
||||||
|
|
||||||
|
static inline spx_word16_t spx_atan01(spx_word16_t x)
|
||||||
|
{
|
||||||
|
return MULT16_16_P15(x, ADD32(M1, MULT16_16_P15(x, ADD32(M2, MULT16_16_P15(x, ADD32(M3, MULT16_16_P15(M4, x)))))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Input in Q15, output in Q14 */
|
||||||
|
spx_word16_t spx_atan(spx_word32_t x)
|
||||||
|
{
|
||||||
|
if (x <= 32767)
|
||||||
|
{
|
||||||
|
return SHR16(spx_atan01(x),1);
|
||||||
|
} else {
|
||||||
|
int e = spx_ilog2(x);
|
||||||
|
if (e>=29)
|
||||||
|
return 25736;
|
||||||
|
x = DIV32_16(SHL32(EXTEND32(32767),29-e), EXTRACT16(SHR32(x, e-14)));
|
||||||
|
return SUB16(25736, SHR16(spx_atan01(x),1));
|
||||||
|
}
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#ifndef M_PI
|
#ifndef M_PI
|
||||||
|
@ -284,161 +287,5 @@ spx_word16_t spx_cos(spx_word16_t x)
|
||||||
return NEG16(C1 + x*(C2+x*(C3+C4*x)));
|
return NEG16(C1 + x*(C2+x*(C3+C4*x)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline float spx_floor(float x){
|
|
||||||
return ((float)(((int)x)));
|
|
||||||
}
|
|
||||||
|
|
||||||
#define FP_BITS (14)
|
|
||||||
#define FP_MASK ((1 << FP_BITS) - 1)
|
|
||||||
#define FP_ONE (1 << FP_BITS)
|
|
||||||
#define FP_TWO (2 << FP_BITS)
|
|
||||||
#define FP_HALF (1 << (FP_BITS - 1))
|
|
||||||
#define FP_LN2 ( 45426 >> (16 - FP_BITS))
|
|
||||||
#define FP_LN2_INV ( 94548 >> (16 - FP_BITS))
|
|
||||||
#define FP_EXP_ZERO ( 10922 >> (16 - FP_BITS))
|
|
||||||
#define FP_EXP_ONE ( -182 >> (16 - FP_BITS))
|
|
||||||
#define FP_EXP_TWO ( 4 >> (16 - FP_BITS))
|
|
||||||
// #define FP_INF (0x7fffffff)
|
|
||||||
// #define FP_LN10 (150902 >> (16 - FP_BITS))
|
|
||||||
|
|
||||||
#define FP_MAX_DIGITS (4)
|
|
||||||
#define FP_MAX_DIGITS_INT (10000)
|
|
||||||
|
|
||||||
|
|
||||||
// #define FP_FAST_MUL_DIV
|
|
||||||
|
|
||||||
// #ifdef FP_FAST_MUL_DIV
|
|
||||||
|
|
||||||
/* These macros can easily overflow, but they are good enough for our uses,
|
|
||||||
* and saves some code.
|
|
||||||
*/
|
|
||||||
#define fp_mul(x, y) (((x) * (y)) >> FP_BITS)
|
|
||||||
#define fp_div(x, y) (((x) << FP_BITS) / (y))
|
|
||||||
|
|
||||||
#ifndef abs
|
|
||||||
#define abs(x) (((x)<0)?((x)*-1):(x))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
float spx_sqrt2(float xf) {
|
|
||||||
long x=(xf*(2.0*FP_BITS));
|
|
||||||
int i=0, s = (x + FP_ONE) >> 1;
|
|
||||||
for (; i < 8; i++) {
|
|
||||||
s = (s + fp_div(x, s)) >> 1;
|
|
||||||
}
|
|
||||||
return s/((float)(2*FP_BITS));
|
|
||||||
}
|
|
||||||
|
|
||||||
static int exp_s16p16(int x)
|
|
||||||
{
|
|
||||||
int t;
|
|
||||||
int y = 0x00010000;
|
|
||||||
|
|
||||||
if (x < 0) x += 0xb1721, y >>= 16;
|
|
||||||
t = x - 0x58b91; if (t >= 0) x = t, y <<= 8;
|
|
||||||
t = x - 0x2c5c8; if (t >= 0) x = t, y <<= 4;
|
|
||||||
t = x - 0x162e4; if (t >= 0) x = t, y <<= 2;
|
|
||||||
t = x - 0x0b172; if (t >= 0) x = t, y <<= 1;
|
|
||||||
t = x - 0x067cd; if (t >= 0) x = t, y += y >> 1;
|
|
||||||
t = x - 0x03920; if (t >= 0) x = t, y += y >> 2;
|
|
||||||
t = x - 0x01e27; if (t >= 0) x = t, y += y >> 3;
|
|
||||||
t = x - 0x00f85; if (t >= 0) x = t, y += y >> 4;
|
|
||||||
t = x - 0x007e1; if (t >= 0) x = t, y += y >> 5;
|
|
||||||
t = x - 0x003f8; if (t >= 0) x = t, y += y >> 6;
|
|
||||||
t = x - 0x001fe; if (t >= 0) x = t, y += y >> 7;
|
|
||||||
y += ((y >> 8) * x) >> 8;
|
|
||||||
|
|
||||||
return y;
|
|
||||||
}
|
|
||||||
float spx_expB(float xf) {
|
|
||||||
return exp_s16p16(xf*32)/32;
|
|
||||||
}
|
|
||||||
float spx_expC(float xf){
|
|
||||||
long x=xf*(2*FP_BITS);
|
|
||||||
/*
|
|
||||||
static long fp_exp(long x)
|
|
||||||
{*/
|
|
||||||
long k;
|
|
||||||
long z;
|
|
||||||
long R;
|
|
||||||
long xp;
|
|
||||||
|
|
||||||
if (x == 0)
|
|
||||||
{
|
|
||||||
return FP_ONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
k = (fp_mul(abs(x), FP_LN2_INV) + FP_HALF) & ~FP_MASK;
|
|
||||||
|
|
||||||
if (x < 0)
|
|
||||||
{
|
|
||||||
k = -k;
|
|
||||||
}
|
|
||||||
|
|
||||||
x -= fp_mul(k, FP_LN2);
|
|
||||||
z = fp_mul(x, x);
|
|
||||||
R = FP_TWO + fp_mul(z, FP_EXP_ZERO + fp_mul(z, FP_EXP_ONE
|
|
||||||
+ fp_mul(z, FP_EXP_TWO)));
|
|
||||||
xp = FP_ONE + fp_div(fp_mul(FP_TWO, x), R - x);
|
|
||||||
|
|
||||||
if (k < 0)
|
|
||||||
{
|
|
||||||
k = FP_ONE >> (-k >> FP_BITS);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
k = FP_ONE << (k >> FP_BITS);
|
|
||||||
}
|
|
||||||
|
|
||||||
return fp_mul(k, xp)/(2*FP_BITS);
|
|
||||||
}
|
|
||||||
/*To generate (ruby code): (0...33).each { |idx| puts Math.exp((idx-10) / 8.0).to_s + "," } */
|
|
||||||
const float exp_lookup_int[33]={0.28650479686019,0.32465246735835,0.367879441171442,0.416862019678508,0.472366552741015,0.53526142851899,0.606530659712633,0.687289278790972,0.778800783071405,0.882496902584595,1.0,1.13314845306683,1.28402541668774,1.4549914146182,1.64872127070013,1.86824595743222,2.11700001661267,2.3988752939671,2.71828182845905,3.08021684891803,3.49034295746184,3.95507672292058,4.48168907033806,5.07841903718008,5.75460267600573,6.52081912033011,7.38905609893065,8.37289748812726,9.48773583635853,10.7510131860764,12.1824939607035,13.8045741860671,15.6426318841882};
|
|
||||||
/*To generate (ruby code): (0...32).each { |idx| puts Math.exp((idx-16.0) / 4.0).to_s+","} */
|
|
||||||
static const float exp_table[32]={0.0183156388887342,0.0235177458560091,0.0301973834223185,0.038774207831722,0.0497870683678639,0.0639278612067076,0.0820849986238988,0.105399224561864,0.135335283236613,0.173773943450445,0.22313016014843,0.28650479686019,0.367879441171442,0.472366552741015,0.606530659712633,0.778800783071405,1.0,1.28402541668774,1.64872127070013,2.11700001661267,2.71828182845905,3.49034295746184,4.48168907033806,5.75460267600573,7.38905609893065,9.48773583635853,12.1824939607035,15.6426318841882,20.0855369231877,25.7903399171931,33.1154519586923,42.5210820000628};
|
|
||||||
/**Returns exp(x) Range x=-4-+4 {x.0,x.25,x.5,x.75} */
|
|
||||||
float spx_exp(float xf){
|
|
||||||
float flt=spx_floor(xf);
|
|
||||||
if(-4<xf&&4>xf&&(abs(xf-flt)==0.0||abs(xf-flt)==0.25||abs(xf-flt)==0.5||abs(xf-flt)==0.75||abs(xf-flt)==1.0)){
|
|
||||||
#ifdef SIMULATOR
|
|
||||||
/* printf("NtbSexp:%f,%d,%f:%f,%f,%f:%d,%d:%d\n",
|
|
||||||
exp_sqrt_table[(int)((xf+4.0)*4.0)],
|
|
||||||
(int)((xf-4.0)*4.0),
|
|
||||||
(xf-4.0)*4.0,
|
|
||||||
xf,
|
|
||||||
flt,
|
|
||||||
xf-flt,
|
|
||||||
-4<xf,
|
|
||||||
4>xf,
|
|
||||||
abs(xf-flt)
|
|
||||||
);*/
|
|
||||||
#endif
|
|
||||||
return exp_table[(int)((xf+4.0)*4.0)];
|
|
||||||
} else if (-4<xf&&4>xf){
|
|
||||||
#ifdef SIMULATOR
|
|
||||||
/* printf("NtbLexp:%f,%f,%f:%d,%d:%d\n",xf,flt,xf-flt,-4<xf,4>xf,abs(xf-flt)); */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return exp_table[(int)((xf+4.0)*4.0)];
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef SIMULATOR
|
|
||||||
/* printf("NTBLexp:%f,%f,%f:%d,%d:%d\n",xf,flt,xf-flt,-4<xf,4>xf,abs(xf-flt)); */
|
|
||||||
#endif
|
|
||||||
return spx_expB(xf);
|
|
||||||
//return exp(xf);
|
|
||||||
}
|
|
||||||
//Placeholders (not fixed point, only used when encoding):
|
|
||||||
float pow(float a,float b){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
float log(float l){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
float fabs(float a){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
float sin(float a){
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
|
@ -35,37 +35,28 @@
|
||||||
#ifndef MATH_APPROX_H
|
#ifndef MATH_APPROX_H
|
||||||
#define MATH_APPROX_H
|
#define MATH_APPROX_H
|
||||||
|
|
||||||
|
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
||||||
#ifdef FIXED_POINT
|
|
||||||
spx_word16_t spx_cos(spx_word16_t x);
|
spx_word16_t spx_cos(spx_word16_t x);
|
||||||
|
spx_int16_t spx_ilog2(spx_uint32_t x);
|
||||||
|
spx_int16_t spx_ilog4(spx_uint32_t x);
|
||||||
|
#ifdef FIXED_POINT
|
||||||
spx_word16_t spx_sqrt(spx_word32_t x);
|
spx_word16_t spx_sqrt(spx_word32_t x);
|
||||||
float spx_sqrtf(float arg);
|
|
||||||
spx_word16_t spx_acos(spx_word16_t x);
|
spx_word16_t spx_acos(spx_word16_t x);
|
||||||
float spx_floor(float x);
|
spx_word32_t spx_exp(spx_word16_t x);
|
||||||
float spx_exp(float x);
|
spx_word16_t spx_cos_norm(spx_word32_t x);
|
||||||
extern const float exp_lookup_int[];
|
|
||||||
/** Returns: Math.exp((idx-10) / 8.0) Range:0-32*/
|
|
||||||
static inline float spx_exp_lookup(int xf){
|
|
||||||
return exp_lookup_int[xf];
|
|
||||||
}
|
|
||||||
//Placeholders:
|
|
||||||
float pow(float a,float b);
|
|
||||||
float log(float l);
|
|
||||||
float fabs(float l);
|
|
||||||
float sin(float l);
|
|
||||||
//float floor(float l);
|
|
||||||
|
|
||||||
#define floor spx_floor
|
/* Input in Q15, output in Q14 */
|
||||||
#define exp spx_exp
|
spx_word16_t spx_atan(spx_word32_t x);
|
||||||
#define sqrt spx_sqrt
|
|
||||||
#define acos spx_acos
|
|
||||||
#define cos spx_cos
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define spx_sqrt sqrt
|
#define spx_sqrt sqrt
|
||||||
#define spx_acos acos
|
#define spx_acos acos
|
||||||
|
#define spx_exp exp
|
||||||
|
#define spx_cos_norm(x) (cos((.5f*M_PI)*(x)))
|
||||||
|
#define spx_atan atan
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -79,9 +79,6 @@
|
||||||
#define M_PI 3.14159265358979323846
|
#define M_PI 3.14159265358979323846
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define min(a,b) ((a)<(b) ? (a) : (b))
|
|
||||||
#define max(a,b) ((a)>(b) ? (a) : (b))
|
|
||||||
|
|
||||||
#ifdef FIXED_POINT
|
#ifdef FIXED_POINT
|
||||||
#define WEIGHT_SHIFT 11
|
#define WEIGHT_SHIFT 11
|
||||||
#define NORMALIZE_SCALEDOWN 5
|
#define NORMALIZE_SCALEDOWN 5
|
||||||
|
@ -90,19 +87,40 @@
|
||||||
#define WEIGHT_SHIFT 0
|
#define WEIGHT_SHIFT 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* If enabled, the transition between blocks is smooth, so there isn't any blocking
|
/* If enabled, the AEC will use a foreground filter and a background filter to be more robust to double-talk
|
||||||
aftifact when adapting. The cost is an extra FFT and a matrix-vector multiply */
|
and difficult signals in general. The cost is an extra FFT and a matrix-vector multiply */
|
||||||
#define SMOOTH_BLOCKS
|
#define TWO_PATH
|
||||||
|
|
||||||
#ifdef FIXED_POINT
|
#ifdef FIXED_POINT
|
||||||
static const spx_float_t MIN_LEAK = {16777, -19};
|
static const spx_float_t MIN_LEAK = {20972, -22};
|
||||||
|
|
||||||
|
/* Constants for the two-path filter */
|
||||||
|
static const spx_float_t VAR1_SMOOTH = {23593, -16};
|
||||||
|
static const spx_float_t VAR2_SMOOTH = {23675, -15};
|
||||||
|
static const spx_float_t VAR1_UPDATE = {16384, -15};
|
||||||
|
static const spx_float_t VAR2_UPDATE = {16384, -16};
|
||||||
|
static const spx_float_t VAR_BACKTRACK = {16384, -12};
|
||||||
#define TOP16(x) ((x)>>16)
|
#define TOP16(x) ((x)>>16)
|
||||||
|
|
||||||
#else
|
#else
|
||||||
static const spx_float_t MIN_LEAK = .032f;
|
|
||||||
|
static const spx_float_t MIN_LEAK = .005f;
|
||||||
|
|
||||||
|
/* Constants for the two-path filter */
|
||||||
|
static const spx_float_t VAR1_SMOOTH = .36f;
|
||||||
|
static const spx_float_t VAR2_SMOOTH = .7225f;
|
||||||
|
static const spx_float_t VAR1_UPDATE = .5f;
|
||||||
|
static const spx_float_t VAR2_UPDATE = .25f;
|
||||||
|
static const spx_float_t VAR_BACKTRACK = 4.f;
|
||||||
#define TOP16(x) (x)
|
#define TOP16(x) (x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define PLAYBACK_DELAY 2
|
||||||
|
|
||||||
|
void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *Yout, int len);
|
||||||
|
|
||||||
|
|
||||||
/** Speex echo cancellation state. */
|
/** Speex echo cancellation state. */
|
||||||
struct SpeexEchoState_ {
|
struct SpeexEchoState_ {
|
||||||
int frame_size; /**< Number of samples processed each time */
|
int frame_size; /**< Number of samples processed each time */
|
||||||
|
@ -111,35 +129,44 @@ struct SpeexEchoState_ {
|
||||||
int cancel_count;
|
int cancel_count;
|
||||||
int adapted;
|
int adapted;
|
||||||
int saturated;
|
int saturated;
|
||||||
|
int screwed_up;
|
||||||
spx_int32_t sampling_rate;
|
spx_int32_t sampling_rate;
|
||||||
spx_word16_t spec_average;
|
spx_word16_t spec_average;
|
||||||
spx_word16_t beta0;
|
spx_word16_t beta0;
|
||||||
spx_word16_t beta_max;
|
spx_word16_t beta_max;
|
||||||
spx_word32_t sum_adapt;
|
spx_word32_t sum_adapt;
|
||||||
spx_word16_t *e;
|
spx_word16_t leak_estimate;
|
||||||
spx_word16_t *x;
|
|
||||||
spx_word16_t *X;
|
spx_word16_t *e; /* scratch */
|
||||||
spx_word16_t *d;
|
spx_word16_t *x; /* Far-end input buffer (2N) */
|
||||||
spx_word16_t *y;
|
spx_word16_t *X; /* Far-end buffer (M+1 frames) in frequency domain */
|
||||||
|
spx_word16_t *input; /* scratch */
|
||||||
|
spx_word16_t *y; /* scratch */
|
||||||
spx_word16_t *last_y;
|
spx_word16_t *last_y;
|
||||||
spx_word32_t *Yps;
|
spx_word16_t *Y; /* scratch */
|
||||||
spx_word16_t *Y;
|
|
||||||
spx_word16_t *E;
|
spx_word16_t *E;
|
||||||
spx_word32_t *PHI;
|
spx_word32_t *PHI; /* scratch */
|
||||||
spx_word32_t *W;
|
spx_word32_t *W; /* (Background) filter weights */
|
||||||
spx_word32_t *power;
|
#ifdef TWO_PATH
|
||||||
spx_float_t *power_1;
|
spx_word32_t *foreground; /* Foreground filter weights */
|
||||||
spx_word16_t *wtmp;
|
spx_word32_t Davg1; /* 1st recursive average of the residual power difference */
|
||||||
#ifdef FIXED_POINT
|
spx_word32_t Davg2; /* 2nd recursive average of the residual power difference */
|
||||||
spx_word16_t *wtmp2;
|
spx_float_t Dvar1; /* Estimated variance of 1st estimator */
|
||||||
|
spx_float_t Dvar2; /* Estimated variance of 2nd estimator */
|
||||||
#endif
|
#endif
|
||||||
spx_word32_t *Rf;
|
spx_word32_t *power; /* Power of the far-end signal */
|
||||||
spx_word32_t *Yf;
|
spx_float_t *power_1;/* Inverse power of far-end */
|
||||||
spx_word32_t *Xf;
|
spx_word16_t *wtmp; /* scratch */
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
spx_word16_t *wtmp2; /* scratch */
|
||||||
|
#endif
|
||||||
|
spx_word32_t *Rf; /* scratch */
|
||||||
|
spx_word32_t *Yf; /* scratch */
|
||||||
|
spx_word32_t *Xf; /* scratch */
|
||||||
spx_word32_t *Eh;
|
spx_word32_t *Eh;
|
||||||
spx_word32_t *Yh;
|
spx_word32_t *Yh;
|
||||||
spx_float_t Pey;
|
spx_float_t Pey;
|
||||||
spx_float_t Pyy;
|
spx_float_t Pyy;
|
||||||
spx_word16_t *window;
|
spx_word16_t *window;
|
||||||
spx_word16_t *prop;
|
spx_word16_t *prop;
|
||||||
void *fft_table;
|
void *fft_table;
|
||||||
|
@ -151,6 +178,7 @@ struct SpeexEchoState_ {
|
||||||
/* NOTE: If you only use speex_echo_cancel() and want to save some memory, remove this */
|
/* NOTE: If you only use speex_echo_cancel() and want to save some memory, remove this */
|
||||||
spx_int16_t *play_buf;
|
spx_int16_t *play_buf;
|
||||||
int play_buf_pos;
|
int play_buf_pos;
|
||||||
|
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)
|
||||||
|
@ -177,6 +205,7 @@ static inline void filter_dc_notch16(const spx_int16_t *in, spx_word16_t radius,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This inner product is slightly different from the codec version because of fixed-point */
|
||||||
static inline spx_word32_t mdf_inner_prod(const spx_word16_t *x, const spx_word16_t *y, int len)
|
static inline spx_word32_t mdf_inner_prod(const spx_word16_t *x, const spx_word16_t *y, int len)
|
||||||
{
|
{
|
||||||
spx_word32_t sum=0;
|
spx_word32_t sum=0;
|
||||||
|
@ -255,18 +284,52 @@ static inline void spectral_mul_accum(const spx_word16_t *X, const spx_word32_t
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** Compute weighted cross-power spectrum of a half-complex (packed) vector with conjugate */
|
/** Compute weighted cross-power spectrum of a half-complex (packed) vector with conjugate */
|
||||||
static inline void weighted_spectral_mul_conj(const spx_float_t *w, const spx_word16_t *X, const spx_word16_t *Y, spx_word32_t *prod, int N)
|
static inline void weighted_spectral_mul_conj(const spx_float_t *w, const spx_float_t p, const spx_word16_t *X, const spx_word16_t *Y, spx_word32_t *prod, int N)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
prod[0] = FLOAT_MUL32(w[0],MULT16_16(X[0],Y[0]));
|
spx_float_t W;
|
||||||
|
W = FLOAT_AMULT(p, w[0]);
|
||||||
|
prod[0] = FLOAT_MUL32(W,MULT16_16(X[0],Y[0]));
|
||||||
for (i=1,j=1;i<N-1;i+=2,j++)
|
for (i=1,j=1;i<N-1;i+=2,j++)
|
||||||
{
|
{
|
||||||
prod[i] = FLOAT_MUL32(w[j],MAC16_16(MULT16_16(X[i],Y[i]), X[i+1],Y[i+1]));
|
W = FLOAT_AMULT(p, w[j]);
|
||||||
prod[i+1] = FLOAT_MUL32(w[j],MAC16_16(MULT16_16(-X[i+1],Y[i]), X[i],Y[i+1]));
|
prod[i] = FLOAT_MUL32(W,MAC16_16(MULT16_16(X[i],Y[i]), X[i+1],Y[i+1]));
|
||||||
|
prod[i+1] = FLOAT_MUL32(W,MAC16_16(MULT16_16(-X[i+1],Y[i]), X[i],Y[i+1]));
|
||||||
}
|
}
|
||||||
prod[i] = FLOAT_MUL32(w[j],MULT16_16(X[i],Y[i]));
|
W = FLOAT_AMULT(p, w[j]);
|
||||||
|
prod[i] = FLOAT_MUL32(W,MULT16_16(X[i],Y[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void mdf_adjust_prop(const spx_word32_t *W, int N, int M, spx_word16_t *prop)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
spx_word16_t max_sum = 1;
|
||||||
|
spx_word32_t prop_sum = 1;
|
||||||
|
for (i=0;i<M;i++)
|
||||||
|
{
|
||||||
|
spx_word32_t tmp = 1;
|
||||||
|
for (j=0;j<N;j++)
|
||||||
|
tmp += MULT16_16(EXTRACT16(SHR32(W[i*N+j],18)), EXTRACT16(SHR32(W[i*N+j],18)));
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
/* Just a security in case an overflow were to occur */
|
||||||
|
tmp = MIN32(ABS32(tmp), 536870912);
|
||||||
|
#endif
|
||||||
|
prop[i] = spx_sqrt(tmp);
|
||||||
|
if (prop[i] > max_sum)
|
||||||
|
max_sum = prop[i];
|
||||||
|
}
|
||||||
|
for (i=0;i<M;i++)
|
||||||
|
{
|
||||||
|
prop[i] += MULT16_16_Q15(QCONST16(.1f,15),max_sum);
|
||||||
|
prop_sum += EXTEND32(prop[i]);
|
||||||
|
}
|
||||||
|
for (i=0;i<M;i++)
|
||||||
|
{
|
||||||
|
prop[i] = DIV32(MULT16_16(QCONST16(.99f,15), prop[i]),prop_sum);
|
||||||
|
/*printf ("%f ", prop[i]);*/
|
||||||
|
}
|
||||||
|
/*printf ("\n");*/
|
||||||
|
}
|
||||||
|
|
||||||
/** Creates a new echo canceller state */
|
/** Creates a new echo canceller state */
|
||||||
SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
|
SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
|
||||||
|
@ -281,7 +344,8 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
|
||||||
st->cancel_count=0;
|
st->cancel_count=0;
|
||||||
st->sum_adapt = 0;
|
st->sum_adapt = 0;
|
||||||
st->saturated = 0;
|
st->saturated = 0;
|
||||||
/* FIXME: Make that an init option (new API call?) */
|
st->screwed_up = 0;
|
||||||
|
/* This is the default sampling rate */
|
||||||
st->sampling_rate = 8000;
|
st->sampling_rate = 8000;
|
||||||
st->spec_average = DIV32_16(SHL32(EXTEND32(st->frame_size), 15), st->sampling_rate);
|
st->spec_average = DIV32_16(SHL32(EXTEND32(st->frame_size), 15), st->sampling_rate);
|
||||||
#ifdef FIXED_POINT
|
#ifdef FIXED_POINT
|
||||||
|
@ -291,14 +355,14 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
|
||||||
st->beta0 = (2.0f*st->frame_size)/st->sampling_rate;
|
st->beta0 = (2.0f*st->frame_size)/st->sampling_rate;
|
||||||
st->beta_max = (.5f*st->frame_size)/st->sampling_rate;
|
st->beta_max = (.5f*st->frame_size)/st->sampling_rate;
|
||||||
#endif
|
#endif
|
||||||
|
st->leak_estimate = 0;
|
||||||
|
|
||||||
st->fft_table = spx_fft_init(N);
|
st->fft_table = spx_fft_init(N);
|
||||||
|
|
||||||
st->e = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
|
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->x = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
|
||||||
st->d = (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->y = (spx_word16_t*)speex_alloc(N*sizeof(spx_word16_t));
|
||||||
st->Yps = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t));
|
|
||||||
st->last_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->Yf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_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->Rf = (spx_word32_t*)speex_alloc((st->frame_size+1)*sizeof(spx_word32_t));
|
||||||
|
@ -310,6 +374,9 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
|
||||||
st->Y = (spx_word16_t*)speex_alloc(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->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->W = (spx_word32_t*)speex_alloc(M*N*sizeof(spx_word32_t));
|
||||||
|
#ifdef TWO_PATH
|
||||||
|
st->foreground = (spx_word32_t*)speex_alloc(M*N*sizeof(spx_word32_t));
|
||||||
|
#endif
|
||||||
st->PHI = (spx_word32_t*)speex_alloc(N*sizeof(spx_word32_t));
|
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));
|
st->power = (spx_word32_t*)speex_alloc((frame_size+1)*sizeof(spx_word32_t));
|
||||||
st->power_1 = (spx_float_t*)speex_alloc((frame_size+1)*sizeof(spx_float_t));
|
st->power_1 = (spx_float_t*)speex_alloc((frame_size+1)*sizeof(spx_float_t));
|
||||||
|
@ -331,12 +398,10 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
|
||||||
st->power_1[i] = FLOAT_ONE;
|
st->power_1[i] = FLOAT_ONE;
|
||||||
for (i=0;i<N*M;i++)
|
for (i=0;i<N*M;i++)
|
||||||
st->W[i] = 0;
|
st->W[i] = 0;
|
||||||
for (i=0;i<N;i++)
|
|
||||||
st->PHI[i] = 0;
|
|
||||||
{
|
{
|
||||||
spx_word32_t sum = 0;
|
spx_word32_t sum = 0;
|
||||||
/* Ratio of ~10 between adaptation rate of first and last block */
|
/* Ratio of ~10 between adaptation rate of first and last block */
|
||||||
spx_word16_t decay = QCONST16(exp(-2.4/M),15);
|
spx_word16_t decay = SHR32(spx_exp(NEG16(DIV32_16(QCONST16(2.4,11),M))),1);
|
||||||
st->prop[0] = QCONST16(.7, 15);
|
st->prop[0] = QCONST16(.7, 15);
|
||||||
sum = EXTEND32(st->prop[0]);
|
sum = EXTEND32(st->prop[0]);
|
||||||
for (i=1;i<M;i++)
|
for (i=1;i<M;i++)
|
||||||
|
@ -346,7 +411,7 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
|
||||||
}
|
}
|
||||||
for (i=M-1;i>=0;i--)
|
for (i=M-1;i>=0;i--)
|
||||||
{
|
{
|
||||||
st->prop[i] = DIV32(SHL32(EXTEND32(st->prop[i]),15),sum);
|
st->prop[i] = DIV32(MULT16_16(QCONST16(.8,15), st->prop[i]),sum);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,8 +428,14 @@ SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length)
|
||||||
st->adapted = 0;
|
st->adapted = 0;
|
||||||
st->Pey = st->Pyy = FLOAT_ONE;
|
st->Pey = st->Pyy = FLOAT_ONE;
|
||||||
|
|
||||||
st->play_buf = (spx_int16_t*)speex_alloc(2*st->frame_size*sizeof(spx_int16_t));
|
#ifdef TWO_PATH
|
||||||
st->play_buf_pos = 0;
|
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_pos = PLAYBACK_DELAY*st->frame_size;
|
||||||
|
st->play_buf_started = 0;
|
||||||
|
|
||||||
return st;
|
return st;
|
||||||
}
|
}
|
||||||
|
@ -374,23 +445,48 @@ void speex_echo_state_reset(SpeexEchoState *st)
|
||||||
{
|
{
|
||||||
int i, M, N;
|
int i, M, N;
|
||||||
st->cancel_count=0;
|
st->cancel_count=0;
|
||||||
|
st->screwed_up = 0;
|
||||||
N = st->window_size;
|
N = st->window_size;
|
||||||
M = st->M;
|
M = st->M;
|
||||||
for (i=0;i<N*M;i++)
|
for (i=0;i<N*M;i++)
|
||||||
st->W[i] = 0;
|
st->W[i] = 0;
|
||||||
|
#ifdef TWO_PATH
|
||||||
|
for (i=0;i<N*M;i++)
|
||||||
|
st->foreground[i] = 0;
|
||||||
|
#endif
|
||||||
for (i=0;i<N*(M+1);i++)
|
for (i=0;i<N*(M+1);i++)
|
||||||
st->X[i] = 0;
|
st->X[i] = 0;
|
||||||
for (i=0;i<=st->frame_size;i++)
|
for (i=0;i<=st->frame_size;i++)
|
||||||
|
{
|
||||||
st->power[i] = 0;
|
st->power[i] = 0;
|
||||||
|
st->power_1[i] = FLOAT_ONE;
|
||||||
|
st->Eh[i] = 0;
|
||||||
|
st->Yh[i] = 0;
|
||||||
|
}
|
||||||
|
for (i=0;i<st->frame_size;i++)
|
||||||
|
{
|
||||||
|
st->last_y[i] = 0;
|
||||||
|
}
|
||||||
for (i=0;i<N;i++)
|
for (i=0;i<N;i++)
|
||||||
|
{
|
||||||
st->E[i] = 0;
|
st->E[i] = 0;
|
||||||
|
st->x[i] = 0;
|
||||||
|
}
|
||||||
st->notch_mem[0] = st->notch_mem[1] = 0;
|
st->notch_mem[0] = st->notch_mem[1] = 0;
|
||||||
|
st->memX=st->memD=st->memE=0;
|
||||||
|
|
||||||
st->saturated = 0;
|
st->saturated = 0;
|
||||||
st->adapted = 0;
|
st->adapted = 0;
|
||||||
st->sum_adapt = 0;
|
st->sum_adapt = 0;
|
||||||
st->Pey = st->Pyy = FLOAT_ONE;
|
st->Pey = st->Pyy = FLOAT_ONE;
|
||||||
st->play_buf_pos = 0;
|
#ifdef TWO_PATH
|
||||||
|
st->Davg1 = st->Davg2 = 0;
|
||||||
|
st->Dvar1 = st->Dvar2 = FLOAT_ZERO;
|
||||||
|
#endif
|
||||||
|
for (i=0;i<3*st->frame_size;i++)
|
||||||
|
st->play_buf[i] = 0;
|
||||||
|
st->play_buf_pos = PLAYBACK_DELAY*st->frame_size;
|
||||||
|
st->play_buf_started = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,10 +497,9 @@ void speex_echo_state_destroy(SpeexEchoState *st)
|
||||||
|
|
||||||
speex_free(st->e);
|
speex_free(st->e);
|
||||||
speex_free(st->x);
|
speex_free(st->x);
|
||||||
speex_free(st->d);
|
speex_free(st->input);
|
||||||
speex_free(st->y);
|
speex_free(st->y);
|
||||||
speex_free(st->last_y);
|
speex_free(st->last_y);
|
||||||
speex_free(st->Yps);
|
|
||||||
speex_free(st->Yf);
|
speex_free(st->Yf);
|
||||||
speex_free(st->Rf);
|
speex_free(st->Rf);
|
||||||
speex_free(st->Xf);
|
speex_free(st->Xf);
|
||||||
|
@ -415,6 +510,9 @@ void speex_echo_state_destroy(SpeexEchoState *st)
|
||||||
speex_free(st->Y);
|
speex_free(st->Y);
|
||||||
speex_free(st->E);
|
speex_free(st->E);
|
||||||
speex_free(st->W);
|
speex_free(st->W);
|
||||||
|
#ifdef TWO_PATH
|
||||||
|
speex_free(st->foreground);
|
||||||
|
#endif
|
||||||
speex_free(st->PHI);
|
speex_free(st->PHI);
|
||||||
speex_free(st->power);
|
speex_free(st->power);
|
||||||
speex_free(st->power_1);
|
speex_free(st->power_1);
|
||||||
|
@ -428,17 +526,19 @@ void speex_echo_state_destroy(SpeexEchoState *st)
|
||||||
speex_free(st);
|
speex_free(st);
|
||||||
}
|
}
|
||||||
|
|
||||||
void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out, spx_int32_t *Yout)
|
void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
/*speex_warning_int("capture with fill level ", st->play_buf_pos/st->frame_size);*/
|
||||||
|
st->play_buf_started = 1;
|
||||||
if (st->play_buf_pos>=st->frame_size)
|
if (st->play_buf_pos>=st->frame_size)
|
||||||
{
|
{
|
||||||
speex_echo_cancel(st, rec, st->play_buf, out, Yout);
|
speex_echo_cancellation(st, rec, st->play_buf, out);
|
||||||
st->play_buf_pos -= st->frame_size;
|
st->play_buf_pos -= st->frame_size;
|
||||||
for (i=0;i<st->frame_size;i++)
|
for (i=0;i<st->play_buf_pos;i++)
|
||||||
st->play_buf[i] = st->play_buf[i+st->frame_size];
|
st->play_buf[i] = st->play_buf[i+st->frame_size];
|
||||||
} else {
|
} else {
|
||||||
speex_warning("no playback frame available");
|
speex_warning("No playback frame available (your application is buggy and/or got xruns)");
|
||||||
if (st->play_buf_pos!=0)
|
if (st->play_buf_pos!=0)
|
||||||
{
|
{
|
||||||
speex_warning("internal playback buffer corruption?");
|
speex_warning("internal playback buffer corruption?");
|
||||||
|
@ -451,24 +551,46 @@ 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)
|
void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play)
|
||||||
{
|
{
|
||||||
if (st->play_buf_pos<=st->frame_size)
|
/*speex_warning_int("playback with fill level ", st->play_buf_pos/st->frame_size);*/
|
||||||
|
if (!st->play_buf_started)
|
||||||
|
{
|
||||||
|
speex_warning("discarded first playback frame");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (st->play_buf_pos<=PLAYBACK_DELAY*st->frame_size)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i=0;i<st->frame_size;i++)
|
for (i=0;i<st->frame_size;i++)
|
||||||
st->play_buf[st->play_buf_pos+i] = play[i];
|
st->play_buf[st->play_buf_pos+i] = play[i];
|
||||||
st->play_buf_pos += st->frame_size;
|
st->play_buf_pos += st->frame_size;
|
||||||
|
if (st->play_buf_pos <= (PLAYBACK_DELAY-1)*st->frame_size)
|
||||||
|
{
|
||||||
|
speex_warning("Auto-filling the buffer (your application is buggy and/or got xruns)");
|
||||||
|
for (i=0;i<st->frame_size;i++)
|
||||||
|
st->play_buf[st->play_buf_pos+i] = play[i];
|
||||||
|
st->play_buf_pos += st->frame_size;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
speex_warning("had to discard a playback frame");
|
speex_warning("Had to discard a playback frame (your application is buggy and/or got xruns)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Performs echo cancellation on a frame */
|
/** Performs echo cancellation on a frame */
|
||||||
void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int16_t *echo, spx_int16_t *out, spx_int32_t *Yout)
|
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 (deprecated, last arg now ignored) */
|
||||||
|
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 i,j;
|
||||||
int N,M;
|
int N,M;
|
||||||
spx_word32_t Syy,See,Sxx;
|
spx_word32_t Syy,See,Sxx,Sdd, Sff;
|
||||||
spx_word16_t leak_estimate;
|
#ifdef TWO_PATH
|
||||||
|
spx_word32_t Dbf;
|
||||||
|
int update_foreground;
|
||||||
|
#endif
|
||||||
spx_word32_t Sey;
|
spx_word32_t Sey;
|
||||||
spx_word16_t ss, ss_1;
|
spx_word16_t ss, ss_1;
|
||||||
spx_float_t Pey = FLOAT_ONE, Pyy=FLOAT_ONE;
|
spx_float_t Pey = FLOAT_ONE, Pyy=FLOAT_ONE;
|
||||||
|
@ -487,47 +609,46 @@ void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int
|
||||||
ss_1 = 1-ss;
|
ss_1 = 1-ss;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
filter_dc_notch16(ref, st->notch_radius, st->d, st->frame_size, st->notch_mem);
|
/* Apply a notch filter to make sure DC doesn't end up causing problems */
|
||||||
/* Copy input data to buffer */
|
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;i<st->frame_size;i++)
|
for (i=0;i<st->frame_size;i++)
|
||||||
{
|
{
|
||||||
spx_word16_t tmp;
|
|
||||||
spx_word32_t tmp32;
|
spx_word32_t tmp32;
|
||||||
st->x[i] = st->x[i+st->frame_size];
|
tmp32 = SUB32(EXTEND32(far_end[i]), EXTEND32(MULT16_16_P15(st->preemph, st->memX)));
|
||||||
tmp32 = SUB32(EXTEND32(echo[i]), EXTEND32(MULT16_16_P15(st->preemph, st->memX)));
|
|
||||||
#ifdef FIXED_POINT
|
#ifdef FIXED_POINT
|
||||||
/*FIXME: If saturation occurs here, we need to freeze adaptation for M frames (not just one) */
|
/* If saturation occurs here, we need to freeze adaptation for M+1 frames (not just one) */
|
||||||
if (tmp32 > 32767)
|
if (tmp32 > 32767)
|
||||||
{
|
{
|
||||||
tmp32 = 32767;
|
tmp32 = 32767;
|
||||||
st->saturated = 1;
|
st->saturated = M+1;
|
||||||
}
|
}
|
||||||
if (tmp32 < -32767)
|
if (tmp32 < -32767)
|
||||||
{
|
{
|
||||||
tmp32 = -32767;
|
tmp32 = -32767;
|
||||||
st->saturated = 1;
|
st->saturated = M+1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
st->x[i+st->frame_size] = EXTRACT16(tmp32);
|
st->x[i+st->frame_size] = EXTRACT16(tmp32);
|
||||||
st->memX = echo[i];
|
st->memX = far_end[i];
|
||||||
|
|
||||||
tmp = st->d[i];
|
tmp32 = SUB32(EXTEND32(st->input[i]), EXTEND32(MULT16_16_P15(st->preemph, st->memD)));
|
||||||
st->d[i] = st->d[i+st->frame_size];
|
|
||||||
tmp32 = SUB32(EXTEND32(tmp), EXTEND32(MULT16_16_P15(st->preemph, st->memD)));
|
|
||||||
#ifdef FIXED_POINT
|
#ifdef FIXED_POINT
|
||||||
if (tmp32 > 32767)
|
if (tmp32 > 32767)
|
||||||
{
|
{
|
||||||
tmp32 = 32767;
|
tmp32 = 32767;
|
||||||
st->saturated = 1;
|
if (st->saturated == 0)
|
||||||
|
st->saturated = 1;
|
||||||
}
|
}
|
||||||
if (tmp32 < -32767)
|
if (tmp32 < -32767)
|
||||||
{
|
{
|
||||||
tmp32 = -32767;
|
tmp32 = -32767;
|
||||||
st->saturated = 1;
|
if (st->saturated == 0)
|
||||||
|
st->saturated = 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
st->d[i+st->frame_size] = tmp32;
|
st->memD = st->input[i];
|
||||||
st->memD = tmp;
|
st->input[i] = tmp32;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Shift memory: this could be optimized eventually*/
|
/* Shift memory: this could be optimized eventually*/
|
||||||
|
@ -537,28 +658,40 @@ void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int
|
||||||
st->X[(j+1)*N+i] = st->X[j*N+i];
|
st->X[(j+1)*N+i] = st->X[j*N+i];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert x (echo input) to frequency domain */
|
/* Convert x (far end) to frequency domain */
|
||||||
spx_fft(st->fft_table, st->x, &st->X[0]);
|
spx_fft(st->fft_table, st->x, &st->X[0]);
|
||||||
|
for (i=0;i<N;i++)
|
||||||
|
st->last_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;i<st->frame_size;i++)
|
||||||
|
st->x[i] = st->x[i+st->frame_size];
|
||||||
|
/* From here on, the top part of x is used as scratch space */
|
||||||
|
|
||||||
#ifdef SMOOTH_BLOCKS
|
#ifdef TWO_PATH
|
||||||
spectral_mul_accum(st->X, st->W, st->Y, N, M);
|
/* Compute foreground filter */
|
||||||
|
spectral_mul_accum(st->X, st->foreground, st->Y, N, M);
|
||||||
spx_ifft(st->fft_table, st->Y, st->e);
|
spx_ifft(st->fft_table, st->Y, st->e);
|
||||||
|
for (i=0;i<st->frame_size;i++)
|
||||||
|
st->x[i+st->frame_size] = SUB16(st->input[i], st->e[i+st->frame_size]);
|
||||||
|
Sff = mdf_inner_prod(st->x+st->frame_size, st->x+st->frame_size, st->frame_size);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Adjust proportional adaption rate */
|
||||||
|
mdf_adjust_prop (st->W, N, M, st->prop);
|
||||||
/* Compute weight gradient */
|
/* Compute weight gradient */
|
||||||
if (!st->saturated)
|
if (st->saturated == 0)
|
||||||
{
|
{
|
||||||
for (j=M-1;j>=0;j--)
|
for (j=M-1;j>=0;j--)
|
||||||
{
|
{
|
||||||
weighted_spectral_mul_conj(st->power_1, &st->X[(j+1)*N], st->E, st->PHI, N);
|
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;i<N;i++)
|
for (i=0;i<N;i++)
|
||||||
st->W[j*N+i] += MULT16_32_Q15(st->prop[j], st->PHI[i]);
|
st->W[j*N+i] = ADD32(st->W[j*N+i], st->PHI[i]);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
st->saturated--;
|
||||||
}
|
}
|
||||||
|
|
||||||
st->saturated = 0;
|
|
||||||
|
|
||||||
/* Update weight to prevent circular convolution (MDF / AUMDF) */
|
/* Update weight to prevent circular convolution (MDF / AUMDF) */
|
||||||
for (j=0;j<M;j++)
|
for (j=0;j<M;j++)
|
||||||
{
|
{
|
||||||
|
@ -597,29 +730,104 @@ void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int
|
||||||
spectral_mul_accum(st->X, st->W, st->Y, N, M);
|
spectral_mul_accum(st->X, st->W, st->Y, N, M);
|
||||||
spx_ifft(st->fft_table, st->Y, st->y);
|
spx_ifft(st->fft_table, st->Y, st->y);
|
||||||
|
|
||||||
|
#ifdef TWO_PATH
|
||||||
|
/* Difference in response, this is used to estimate the variance of our residual power estimate */
|
||||||
|
for (i=0;i<st->frame_size;i++)
|
||||||
|
st->x[i+st->frame_size] = SUB16(st->e[i+st->frame_size], st->y[i+st->frame_size]);
|
||||||
|
Dbf = 10+mdf_inner_prod(st->x+st->frame_size, st->x+st->frame_size, st->frame_size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (i=0;i<st->frame_size;i++)
|
||||||
|
st->x[i+st->frame_size] = SUB16(st->input[i], st->y[i+st->frame_size]);
|
||||||
|
See = mdf_inner_prod(st->x+st->frame_size, st->x+st->frame_size, 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 */
|
||||||
|
if (FLOAT_GT(FLOAT_MUL32U(SUB32(Sff,See),ABS32(SUB32(Sff,See))), FLOAT_MUL32U(Sff,Dbf)))
|
||||||
|
update_foreground = 1;
|
||||||
|
else if (FLOAT_GT(FLOAT_MUL32U(st->Davg1, ABS32(st->Davg1)), FLOAT_MULT(VAR1_UPDATE,(st->Dvar1))))
|
||||||
|
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;i<N*M;i++)
|
||||||
|
st->foreground[i] = st->W[i];
|
||||||
|
/* Apply a smooth transition so as to not introduce blocking artifacts */
|
||||||
|
for (i=0;i<st->frame_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]);
|
||||||
|
} else {
|
||||||
|
int reset_background=0;
|
||||||
|
/* Otherwise, check if the background filter is significantly worse */
|
||||||
|
if (FLOAT_GT(FLOAT_MUL32U(NEG32(SUB32(Sff,See)),ABS32(SUB32(Sff,See))), FLOAT_MULT(VAR_BACKTRACK,FLOAT_MUL32U(Sff,Dbf))))
|
||||||
|
reset_background = 1;
|
||||||
|
if (FLOAT_GT(FLOAT_MUL32U(NEG32(st->Davg1), ABS32(st->Davg1)), FLOAT_MULT(VAR_BACKTRACK,st->Dvar1)))
|
||||||
|
reset_background = 1;
|
||||||
|
if (FLOAT_GT(FLOAT_MUL32U(NEG32(st->Davg2), ABS32(st->Davg2)), FLOAT_MULT(VAR_BACKTRACK,st->Dvar2)))
|
||||||
|
reset_background = 1;
|
||||||
|
if (reset_background)
|
||||||
|
{
|
||||||
|
/* Copy foreground filter to background filter */
|
||||||
|
for (i=0;i<N*M;i++)
|
||||||
|
st->W[i] = st->foreground[i];
|
||||||
|
/* We also need to copy the output so as to get correct adaptation */
|
||||||
|
for (i=0;i<st->frame_size;i++)
|
||||||
|
st->y[i+st->frame_size] = st->e[i+st->frame_size];
|
||||||
|
for (i=0;i<st->frame_size;i++)
|
||||||
|
st->x[i+st->frame_size] = SUB16(st->input[i], st->y[i+st->frame_size]);
|
||||||
|
See = Sff;
|
||||||
|
st->Davg1 = st->Davg2 = 0;
|
||||||
|
st->Dvar1 = st->Dvar2 = FLOAT_ZERO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Compute error signal (for the output with de-emphasis) */
|
/* Compute error signal (for the output with de-emphasis) */
|
||||||
for (i=0;i<st->frame_size;i++)
|
for (i=0;i<st->frame_size;i++)
|
||||||
{
|
{
|
||||||
spx_word32_t tmp_out;
|
spx_word32_t tmp_out;
|
||||||
#ifdef SMOOTH_BLOCKS
|
#ifdef TWO_PATH
|
||||||
spx_word16_t y = 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]);
|
tmp_out = SUB32(EXTEND32(st->input[i]), EXTEND32(st->e[i+st->frame_size]));
|
||||||
tmp_out = SUB32(EXTEND32(st->d[i+st->frame_size]), EXTEND32(y));
|
|
||||||
#else
|
#else
|
||||||
tmp_out = SUB32(EXTEND32(st->d[i+st->frame_size]), EXTEND32(st->y[i+st->frame_size]));
|
tmp_out = SUB32(EXTEND32(st->input[i]), EXTEND32(st->y[i+st->frame_size]));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Saturation */
|
/* Saturation */
|
||||||
if (tmp_out>32767)
|
if (tmp_out>32767)
|
||||||
tmp_out = 32767;
|
tmp_out = 32767;
|
||||||
else if (tmp_out<-32768)
|
else if (tmp_out<-32768)
|
||||||
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)));
|
||||||
/* This is an arbitrary test for saturation */
|
/* This is an arbitrary test for saturation in the microphone signal */
|
||||||
if (ref[i] <= -32000 || ref[i] >= 32000)
|
if (in[i] <= -32000 || in[i] >= 32000)
|
||||||
{
|
{
|
||||||
tmp_out = 0;
|
tmp_out = 0;
|
||||||
st->saturated = 1;
|
if (st->saturated == 0)
|
||||||
|
st->saturated = 1;
|
||||||
}
|
}
|
||||||
out[i] = (spx_int16_t)tmp_out;
|
out[i] = (spx_int16_t)tmp_out;
|
||||||
st->memE = tmp_out;
|
st->memE = tmp_out;
|
||||||
|
@ -629,15 +837,44 @@ void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int
|
||||||
for (i=0;i<st->frame_size;i++)
|
for (i=0;i<st->frame_size;i++)
|
||||||
{
|
{
|
||||||
st->e[i] = 0;
|
st->e[i] = 0;
|
||||||
st->e[i+st->frame_size] = st->d[i+st->frame_size] - st->y[i+st->frame_size];
|
st->e[i+st->frame_size] = st->x[i+st->frame_size];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute a bunch of correlations */
|
/* Compute a bunch of correlations */
|
||||||
Sey = mdf_inner_prod(st->e+st->frame_size, st->y+st->frame_size, st->frame_size);
|
Sey = mdf_inner_prod(st->e+st->frame_size, st->y+st->frame_size, st->frame_size);
|
||||||
See = mdf_inner_prod(st->e+st->frame_size, st->e+st->frame_size, st->frame_size);
|
|
||||||
See = ADD32(See, SHR32(MULT16_16(N, 100),6));
|
|
||||||
Syy = mdf_inner_prod(st->y+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);
|
||||||
Sxx = mdf_inner_prod(st->x+st->frame_size, st->x+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
|
||||||
|
|| !(Sff < N*1e9 && Syy < N*1e9 && Sxx < N*1e9)
|
||||||
|
#endif
|
||||||
|
)
|
||||||
|
{
|
||||||
|
/* Things have gone really bad */
|
||||||
|
st->screwed_up += 50;
|
||||||
|
for (i=0;i<st->frame_size;i++)
|
||||||
|
out[i] = 0;
|
||||||
|
} else if (SHR32(Sff, 2) > ADD32(Sdd, SHR32(MULT16_16(N, 10000),6)))
|
||||||
|
{
|
||||||
|
/* AEC seems to add lots of echo instead of removing it, let's see if it will improve */
|
||||||
|
st->screwed_up++;
|
||||||
|
} else {
|
||||||
|
/* Everything's fine */
|
||||||
|
st->screwed_up=0;
|
||||||
|
}
|
||||||
|
if (st->screwed_up>=50)
|
||||||
|
{
|
||||||
|
speex_warning("The echo canceller started acting funny and got slapped (reset). It swears it will behave now.");
|
||||||
|
speex_echo_state_reset(st);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 */
|
/* Convert error to frequency domain */
|
||||||
spx_fft(st->fft_table, st->e, st->E);
|
spx_fft(st->fft_table, st->e, st->E);
|
||||||
|
@ -645,12 +882,12 @@ void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int
|
||||||
st->y[i] = 0;
|
st->y[i] = 0;
|
||||||
spx_fft(st->fft_table, st->y, st->Y);
|
spx_fft(st->fft_table, st->y, st->Y);
|
||||||
|
|
||||||
/* Compute power spectrum of echo (X), error (E) and filter response (Y) */
|
/* Compute power spectrum of far end (X), error (E) and filter response (Y) */
|
||||||
power_spectrum(st->E, st->Rf, N);
|
power_spectrum(st->E, st->Rf, N);
|
||||||
power_spectrum(st->Y, st->Yf, N);
|
power_spectrum(st->Y, st->Yf, N);
|
||||||
power_spectrum(st->X, st->Xf, N);
|
power_spectrum(st->X, st->Xf, N);
|
||||||
|
|
||||||
/* Smooth echo energy estimate over time */
|
/* Smooth far end energy estimate over time */
|
||||||
for (j=0;j<=st->frame_size;j++)
|
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]);
|
st->power[j] = MULT16_32_Q15(ss_1,st->power[j]) + 1 + MULT16_32_Q15(ss,st->Xf[j]);
|
||||||
|
|
||||||
|
@ -660,7 +897,7 @@ void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int
|
||||||
{
|
{
|
||||||
float scale2 = .5f/M;
|
float scale2 = .5f/M;
|
||||||
for (j=0;j<=st->frame_size;j++)
|
for (j=0;j<=st->frame_size;j++)
|
||||||
st->power[j] = 0;
|
st->power[j] = 100;
|
||||||
for (i=0;i<M;i++)
|
for (i=0;i<M;i++)
|
||||||
{
|
{
|
||||||
power_spectrum(&st->X[i*N], st->Xf, N);
|
power_spectrum(&st->X[i*N], st->Xf, N);
|
||||||
|
@ -706,17 +943,17 @@ void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int
|
||||||
if (FLOAT_GT(st->Pey, st->Pyy))
|
if (FLOAT_GT(st->Pey, st->Pyy))
|
||||||
st->Pey = st->Pyy;
|
st->Pey = st->Pyy;
|
||||||
/* leak_estimate is the linear regression result */
|
/* leak_estimate is the linear regression result */
|
||||||
leak_estimate = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIVU(st->Pey, st->Pyy),14));
|
st->leak_estimate = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIVU(st->Pey, st->Pyy),14));
|
||||||
/* This looks like a stupid bug, but it's right (because we convert from Q14 to Q15) */
|
/* This looks like a stupid bug, but it's right (because we convert from Q14 to Q15) */
|
||||||
if (leak_estimate > 16383)
|
if (st->leak_estimate > 16383)
|
||||||
leak_estimate = 32767;
|
st->leak_estimate = 32767;
|
||||||
else
|
else
|
||||||
leak_estimate = SHL16(leak_estimate,1);
|
st->leak_estimate = SHL16(st->leak_estimate,1);
|
||||||
/*printf ("%f\n", leak_estimate);*/
|
/*printf ("%f\n", st->leak_estimate);*/
|
||||||
|
|
||||||
/* Compute Residual to Error Ratio */
|
/* Compute Residual to Error Ratio */
|
||||||
#ifdef FIXED_POINT
|
#ifdef FIXED_POINT
|
||||||
tmp32 = MULT16_32_Q15(leak_estimate,Syy);
|
tmp32 = MULT16_32_Q15(st->leak_estimate,Syy);
|
||||||
tmp32 = ADD32(SHR32(Sxx,13), ADD32(tmp32, SHL32(tmp32,1)));
|
tmp32 = ADD32(SHR32(Sxx,13), ADD32(tmp32, SHL32(tmp32,1)));
|
||||||
/* Check for y in e (lower bound on RER) */
|
/* Check for y in e (lower bound on RER) */
|
||||||
{
|
{
|
||||||
|
@ -731,7 +968,7 @@ void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int
|
||||||
tmp32 = SHR32(See,1);
|
tmp32 = SHR32(See,1);
|
||||||
RER = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIV32(tmp32,See),15));
|
RER = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIV32(tmp32,See),15));
|
||||||
#else
|
#else
|
||||||
RER = (.0001*Sxx + 3.*MULT16_32_Q15(leak_estimate,Syy)) / See;
|
RER = (.0001*Sxx + 3.*MULT16_32_Q15(st->leak_estimate,Syy)) / See;
|
||||||
/* Check for y in e (lower bound on RER) */
|
/* Check for y in e (lower bound on RER) */
|
||||||
if (RER < Sey*Sey/(1+See*Syy))
|
if (RER < Sey*Sey/(1+See*Syy))
|
||||||
RER = Sey*Sey/(1+See*Syy);
|
RER = Sey*Sey/(1+See*Syy);
|
||||||
|
@ -740,18 +977,19 @@ void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* We consider that the filter has had minimal adaptation if the following is true*/
|
/* We consider that the filter has had minimal adaptation if the following is true*/
|
||||||
if (!st->adapted && st->sum_adapt > QCONST32(1,15))
|
if (!st->adapted && st->sum_adapt > QCONST32(M,15) && MULT16_32_Q15(st->leak_estimate,Syy) > MULT16_32_Q15(QCONST16(.03f,15),Syy))
|
||||||
{
|
{
|
||||||
st->adapted = 1;
|
st->adapted = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (st->adapted)
|
if (st->adapted)
|
||||||
{
|
{
|
||||||
|
/* Normal learning rate calculation once we're past the minimal adaptation phase */
|
||||||
for (i=0;i<=st->frame_size;i++)
|
for (i=0;i<=st->frame_size;i++)
|
||||||
{
|
{
|
||||||
spx_word32_t r, e;
|
spx_word32_t r, e;
|
||||||
/* Compute frequency-domain adaptation mask */
|
/* Compute frequency-domain adaptation mask */
|
||||||
r = MULT16_32_Q15(leak_estimate,SHL32(st->Yf[i],3));
|
r = MULT16_32_Q15(st->leak_estimate,SHL32(st->Yf[i],3));
|
||||||
e = SHL32(st->Rf[i],3)+1;
|
e = SHL32(st->Rf[i],3)+1;
|
||||||
#ifdef FIXED_POINT
|
#ifdef FIXED_POINT
|
||||||
if (r>SHR32(e,1))
|
if (r>SHR32(e,1))
|
||||||
|
@ -764,20 +1002,22 @@ void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int
|
||||||
/*st->power_1[i] = adapt_rate*r/(e*(1+st->power[i]));*/
|
/*st->power_1[i] = adapt_rate*r/(e*(1+st->power[i]));*/
|
||||||
st->power_1[i] = FLOAT_SHL(FLOAT_DIV32_FLOAT(r,FLOAT_MUL32U(e,st->power[i]+10)),WEIGHT_SHIFT+16);
|
st->power_1[i] = FLOAT_SHL(FLOAT_DIV32_FLOAT(r,FLOAT_MUL32U(e,st->power[i]+10)),WEIGHT_SHIFT+16);
|
||||||
}
|
}
|
||||||
} else if (Sxx > SHR32(MULT16_16(N, 1000),6)) {
|
} else {
|
||||||
/* Temporary adaption rate if filter is not yet adapted enough */
|
/* Temporary adaption rate if filter is not yet adapted enough */
|
||||||
spx_word16_t adapt_rate=0;
|
spx_word16_t adapt_rate=0;
|
||||||
|
|
||||||
tmp32 = MULT16_32_Q15(QCONST16(.25f, 15), Sxx);
|
if (Sxx > SHR32(MULT16_16(N, 1000),6))
|
||||||
|
{
|
||||||
|
tmp32 = MULT16_32_Q15(QCONST16(.25f, 15), Sxx);
|
||||||
#ifdef FIXED_POINT
|
#ifdef FIXED_POINT
|
||||||
if (tmp32 > SHR32(See,2))
|
if (tmp32 > SHR32(See,2))
|
||||||
tmp32 = SHR32(See,2);
|
tmp32 = SHR32(See,2);
|
||||||
#else
|
#else
|
||||||
if (tmp32 > .25*See)
|
if (tmp32 > .25*See)
|
||||||
tmp32 = .25*See;
|
tmp32 = .25*See;
|
||||||
#endif
|
#endif
|
||||||
adapt_rate = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIV32(tmp32, See),15));
|
adapt_rate = FLOAT_EXTRACT16(FLOAT_SHL(FLOAT_DIV32(tmp32, See),15));
|
||||||
|
}
|
||||||
for (i=0;i<=st->frame_size;i++)
|
for (i=0;i<=st->frame_size;i++)
|
||||||
st->power_1[i] = FLOAT_SHL(FLOAT_DIV32(EXTEND32(adapt_rate),ADD32(st->power[i],10)),WEIGHT_SHIFT+1);
|
st->power_1[i] = FLOAT_SHL(FLOAT_DIV32(EXTEND32(adapt_rate),ADD32(st->power[i],10)),WEIGHT_SHIFT+1);
|
||||||
|
|
||||||
|
@ -786,48 +1026,55 @@ void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *ref, const spx_int
|
||||||
st->sum_adapt = ADD32(st->sum_adapt,adapt_rate);
|
st->sum_adapt = ADD32(st->sum_adapt,adapt_rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute spectrum of estimated echo for use in an echo post-filter (if necessary)*/
|
/* Save residual echo so it can be used by the nonlinear processor */
|
||||||
if (Yout)
|
if (st->adapted)
|
||||||
{
|
{
|
||||||
spx_word16_t leak2;
|
/* If the filter is adapted, take the filtered echo */
|
||||||
if (st->adapted)
|
for (i=0;i<st->frame_size;i++)
|
||||||
{
|
st->last_y[i] = st->last_y[st->frame_size+i];
|
||||||
/* If the filter is adapted, take the filtered echo */
|
for (i=0;i<st->frame_size;i++)
|
||||||
for (i=0;i<st->frame_size;i++)
|
st->last_y[st->frame_size+i] = in[i]-out[i];
|
||||||
st->last_y[i] = st->last_y[st->frame_size+i];
|
} else {
|
||||||
for (i=0;i<st->frame_size;i++)
|
/* If filter isn't adapted yet, all we can do is take the far end signal directly */
|
||||||
st->last_y[st->frame_size+i] = ref[i]-out[i];
|
/* moved earlier: for (i=0;i<N;i++)
|
||||||
} else {
|
st->last_y[i] = st->x[i];*/
|
||||||
/* If filter isn't adapted yet, all we can do is take the echo signal directly */
|
|
||||||
for (i=0;i<N;i++)
|
|
||||||
st->last_y[i] = st->x[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Apply hanning window (should pre-compute it)*/
|
|
||||||
for (i=0;i<N;i++)
|
|
||||||
st->y[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, st->Yps, N);
|
|
||||||
|
|
||||||
#ifdef FIXED_POINT
|
|
||||||
if (leak_estimate > 16383)
|
|
||||||
leak2 = 32767;
|
|
||||||
else
|
|
||||||
leak2 = SHL16(leak_estimate, 1);
|
|
||||||
#else
|
|
||||||
if (leak_estimate>.5)
|
|
||||||
leak2 = 1;
|
|
||||||
else
|
|
||||||
leak2 = 2*leak_estimate;
|
|
||||||
#endif
|
|
||||||
/* Estimate residual echo */
|
|
||||||
for (i=0;i<=st->frame_size;i++)
|
|
||||||
Yout[i] = (spx_int32_t)MULT16_32_Q15(leak2,st->Yps[i]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Compute spectrum of estimated echo for use in an echo post-filter */
|
||||||
|
void speex_echo_get_residual(SpeexEchoState *st, spx_word32_t *residual_echo, int len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
spx_word16_t leak2;
|
||||||
|
int N;
|
||||||
|
|
||||||
|
N = st->window_size;
|
||||||
|
|
||||||
|
/* Apply hanning window (should pre-compute it)*/
|
||||||
|
for (i=0;i<N;i++)
|
||||||
|
st->y[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;
|
||||||
|
else
|
||||||
|
leak2 = SHL16(st->leak_estimate, 1);
|
||||||
|
#else
|
||||||
|
if (st->leak_estimate>.5)
|
||||||
|
leak2 = 1;
|
||||||
|
else
|
||||||
|
leak2 = 2*st->leak_estimate;
|
||||||
|
#endif
|
||||||
|
/* 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)
|
int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr)
|
||||||
{
|
{
|
||||||
|
|
|
@ -34,15 +34,11 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "../codecs.h"
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef USER_MISC
|
#ifdef USER_MISC
|
||||||
#include "user_misc.h"
|
#include "user_misc.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -51,16 +47,14 @@
|
||||||
#include "misc_bfin.h"
|
#include "misc_bfin.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//static struct codec_api *rb;//defined in decoder api speex.c
|
|
||||||
|
|
||||||
#ifndef RELEASE
|
#ifndef RELEASE
|
||||||
void print_vec(float *vec, int len, char *name)
|
void print_vec(float *vec, int len, char *name)
|
||||||
{
|
{
|
||||||
/* int i;
|
int i;
|
||||||
printf ("%s ", name);
|
printf ("%s ", name);
|
||||||
for (i=0;i<len;i++)
|
for (i=0;i<len;i++)
|
||||||
printf (" %f", vec[i]);
|
printf (" %f", vec[i]);
|
||||||
printf ("\n");*/
|
printf ("\n");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -72,7 +66,7 @@ long long spx_mips=0;
|
||||||
spx_uint32_t be_int(spx_uint32_t i)
|
spx_uint32_t be_int(spx_uint32_t i)
|
||||||
{
|
{
|
||||||
spx_uint32_t ret=i;
|
spx_uint32_t ret=i;
|
||||||
#ifndef ROCKBOX_BIG_ENDIAN
|
#ifndef WORDS_BIGENDIAN
|
||||||
ret = i>>24;
|
ret = i>>24;
|
||||||
ret += (i>>8)&0x0000ff00;
|
ret += (i>>8)&0x0000ff00;
|
||||||
ret += (i<<8)&0x00ff0000;
|
ret += (i<<8)&0x00ff0000;
|
||||||
|
@ -84,7 +78,7 @@ spx_uint32_t be_int(spx_uint32_t i)
|
||||||
spx_uint32_t le_int(spx_uint32_t i)
|
spx_uint32_t le_int(spx_uint32_t i)
|
||||||
{
|
{
|
||||||
spx_uint32_t ret=i;
|
spx_uint32_t ret=i;
|
||||||
#ifdef ROCKBOX_BIG_ENDIAN
|
#ifdef WORDS_BIGENDIAN
|
||||||
ret = i>>24;
|
ret = i>>24;
|
||||||
ret += (i>>8)&0x0000ff00;
|
ret += (i>>8)&0x0000ff00;
|
||||||
ret += (i<<8)&0x00ff0000;
|
ret += (i<<8)&0x00ff0000;
|
||||||
|
@ -93,86 +87,38 @@ spx_uint32_t le_int(spx_uint32_t i)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if BYTES_PER_CHAR == 2
|
|
||||||
void speex_memcpy_bytes(char *dst, char *src, int nbytes)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
int nchars = nbytes/BYTES_PER_CHAR;
|
|
||||||
for (i=0;i<nchars;i++)
|
|
||||||
dst[i]=src[i];
|
|
||||||
if (nbytes & 1) {
|
|
||||||
/* copy in the last byte */
|
|
||||||
int last_i = nchars;
|
|
||||||
char last_dst_char = dst[last_i];
|
|
||||||
char last_src_char = src[last_i];
|
|
||||||
last_dst_char &= 0xff00;
|
|
||||||
last_dst_char |= (last_src_char & 0x00ff);
|
|
||||||
dst[last_i] = last_dst_char;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void speex_memset_bytes(char *dst, char c, int nbytes)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
spx_int16_t cc = ((c << 8) | c);
|
|
||||||
int nchars = nbytes/BYTES_PER_CHAR;
|
|
||||||
for (i=0;i<nchars;i++)
|
|
||||||
dst[i]=cc;
|
|
||||||
if (nbytes & 1) {
|
|
||||||
/* copy in the last byte */
|
|
||||||
int last_i = nchars;
|
|
||||||
char last_dst_char = dst[last_i];
|
|
||||||
last_dst_char &= 0xff00;
|
|
||||||
last_dst_char |= (c & 0x00ff);
|
|
||||||
dst[last_i] = last_dst_char;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
void speex_memcpy_bytes(char *dst, char *src, int nbytes)
|
|
||||||
{
|
|
||||||
memcpy(dst, src, nbytes);
|
|
||||||
}
|
|
||||||
void speex_memset_bytes(char *dst, char src, int nbytes)
|
|
||||||
{
|
|
||||||
memset(dst, src, nbytes);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef OVERRIDE_SPEEX_ALLOC
|
#ifndef OVERRIDE_SPEEX_ALLOC
|
||||||
void *speex_alloc (int size)
|
void *speex_alloc (int size)
|
||||||
{
|
{
|
||||||
//printf("CLC:%d\n",size);
|
return calloc(size,1);
|
||||||
return codec_calloc(size,1);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef OVERRIDE_SPEEX_ALLOC_SCRATCH
|
#ifndef OVERRIDE_SPEEX_ALLOC_SCRATCH
|
||||||
void *speex_alloc_scratch (int size)
|
void *speex_alloc_scratch (int size)
|
||||||
{
|
{
|
||||||
//printf("CLCS:%d\n",size);
|
return calloc(size,1);
|
||||||
return codec_calloc(size,1);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef OVERRIDE_SPEEX_REALLOC
|
#ifndef OVERRIDE_SPEEX_REALLOC
|
||||||
void *speex_realloc (void *ptr, int size)
|
void *speex_realloc (void *ptr, int size)
|
||||||
{
|
{
|
||||||
//printf("CLCR:%d\n",size);
|
return realloc(ptr, size);
|
||||||
return codec_realloc(ptr, size);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef OVERRIDE_SPEEX_FREE
|
#ifndef OVERRIDE_SPEEX_FREE
|
||||||
void speex_free (void *ptr)
|
void speex_free (void *ptr)
|
||||||
{
|
{
|
||||||
//printf("CLF:%d\n",ptr);
|
free(ptr);
|
||||||
codec_free(ptr);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef OVERRIDE_SPEEX_FREE_SCRATCH
|
#ifndef OVERRIDE_SPEEX_FREE_SCRATCH
|
||||||
void speex_free_scratch (void *ptr)
|
void speex_free_scratch (void *ptr)
|
||||||
{
|
{
|
||||||
codec_free(ptr);
|
free(ptr);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -186,60 +132,50 @@ void *speex_move (void *dest, void *src, int n)
|
||||||
#ifndef OVERRIDE_SPEEX_ERROR
|
#ifndef OVERRIDE_SPEEX_ERROR
|
||||||
void speex_error(const char *str)
|
void speex_error(const char *str)
|
||||||
{
|
{
|
||||||
//fprintf ("Fatal error: %s\n", str);
|
fprintf (stderr, "Fatal error: %s\n", str);
|
||||||
//exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef OVERRIDE_SPEEX_WARNING
|
#ifndef OVERRIDE_SPEEX_WARNING
|
||||||
void speex_warning(const char *str)
|
void speex_warning(const char *str)
|
||||||
{
|
{
|
||||||
//fprintf ("warning: %s\n", str);
|
fprintf (stderr, "warning: %s\n", str);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef OVERRIDE_SPEEX_WARNING_INT
|
#ifndef OVERRIDE_SPEEX_WARNING_INT
|
||||||
void speex_warning_int(const char *str, int val)
|
void speex_warning_int(const char *str, int val)
|
||||||
{
|
{
|
||||||
//printf ("warning: %s %d\n", str, val);
|
fprintf (stderr, "warning: %s %d\n", str, val);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FIXED_POINT
|
|
||||||
#ifdef FIXED_POINT
|
#ifdef FIXED_POINT
|
||||||
spx_word16_t speex_rand(spx_word16_t std, spx_int32_t *seed)
|
spx_word16_t speex_rand(spx_word16_t std, spx_int32_t *seed)
|
||||||
{
|
{
|
||||||
// spx_word32_t res;
|
spx_word32_t res;
|
||||||
// *seed = 1664525 * *seed + 1013904223;
|
*seed = 1664525 * *seed + 1013904223;
|
||||||
// res = MULT16_16(EXTRACT16(SHR32(*seed,16)),std);
|
res = MULT16_16(EXTRACT16(SHR32(*seed,16)),std);
|
||||||
// return PSHR32(SUB32(res, SHR(res, 3)),14);
|
return EXTRACT16(PSHR32(SUB32(res, SHR32(res, 3)),14));
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
spx_word16_t speex_rand(spx_word16_t std, spx_int32_t *seed)
|
spx_word16_t speex_rand(spx_word16_t std, spx_int32_t *seed)
|
||||||
{
|
{
|
||||||
// const unsigned int jflone = 0x3f800000;
|
const unsigned int jflone = 0x3f800000;
|
||||||
// const unsigned int jflmsk = 0x007fffff;
|
const unsigned int jflmsk = 0x007fffff;
|
||||||
// union {int i; float f;} ran;
|
union {int i; float f;} ran;
|
||||||
// *seed = 1664525 * *seed + 1013904223;
|
*seed = 1664525 * *seed + 1013904223;
|
||||||
// ran.i = jflone | (jflmsk & *seed);
|
ran.i = jflone | (jflmsk & *seed);
|
||||||
// ran.f -= 1.5;
|
ran.f -= 1.5;
|
||||||
// return 3.4642*std*ran.f;
|
return 3.4642*std*ran.f;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/*#define RAND_MAX_VEC 32767*/
|
|
||||||
void speex_rand_vec(float std, spx_sig_t *data, int len)
|
|
||||||
{
|
|
||||||
/* int i;
|
|
||||||
for (i=0;i<len;i++)
|
|
||||||
data[i]+=SIG_SCALING*3*std*((((float)(speex_rand(RAND_MAX_VEC,10)))/RAND_MAX_VEC)-.5);*/
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef OVERRIDE_SPEEX_PUTC
|
#ifndef OVERRIDE_SPEEX_PUTC
|
||||||
void _speex_putc(int ch, void *file)
|
void _speex_putc(int ch, void *file)
|
||||||
{
|
{
|
||||||
//FILE *f = (FILE *)file;
|
FILE *f = (FILE *)file;
|
||||||
//printf("%c", ch);
|
fprintf(f, "%c", ch);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -40,10 +40,7 @@
|
||||||
#define SPEEX_MINOR_VERSION 1 /**< Minor Speex version. */
|
#define SPEEX_MINOR_VERSION 1 /**< Minor Speex version. */
|
||||||
#define SPEEX_MICRO_VERSION 13 /**< Micro Speex version. */
|
#define SPEEX_MICRO_VERSION 13 /**< Micro Speex version. */
|
||||||
#define SPEEX_EXTRA_VERSION "" /**< Extra Speex version. */
|
#define SPEEX_EXTRA_VERSION "" /**< Extra Speex version. */
|
||||||
#define SPEEX_VERSION "speex-1.2-beta1" /**< Speex version string. */
|
#define SPEEX_VERSION "speex-1.2beta1" /**< Speex version string. */
|
||||||
#define FIXED_POINT
|
|
||||||
//#define EPIC_48K
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* A couple test to catch stupid option combinations */
|
/* A couple test to catch stupid option combinations */
|
||||||
|
@ -65,36 +62,12 @@
|
||||||
#error I suppose you can have a [ARM4/ARM5E/Blackfin] that has float instructions?
|
#error I suppose you can have a [ARM4/ARM5E/Blackfin] that has float instructions?
|
||||||
#endif
|
#endif
|
||||||
#ifdef FIXED_POINT_DEBUG
|
#ifdef FIXED_POINT_DEBUG
|
||||||
#error Don't you think enabling fixed-point is a good thing to do if you want to debug that?
|
#error "Don't you think enabling fixed-point is a good thing to do if you want to debug that?"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "../codec.h"
|
|
||||||
#include "../lib/codeclib.h"
|
|
||||||
|
|
||||||
extern struct codec_api* rb;
|
|
||||||
|
|
||||||
#if defined(DEBUG) || defined(SIMULATOR)
|
|
||||||
#undef DEBUGF
|
|
||||||
#define DEBUGF rb->debugf
|
|
||||||
#else
|
|
||||||
#define DEBUGF(...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ROCKBOX_HAS_LOGF
|
|
||||||
#undef LOGF
|
|
||||||
#define LOGF rb->logf
|
|
||||||
#else
|
|
||||||
#define LOGF(...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CPU_ARM
|
|
||||||
#define ARM4_ASM
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#include "arch.h"
|
#include "arch.h"
|
||||||
|
|
||||||
#ifndef RELEASE
|
#ifndef RELEASE
|
||||||
|
@ -125,12 +98,6 @@ void speex_free_scratch (void *ptr);
|
||||||
/** Speex wrapper for mem_move */
|
/** Speex wrapper for mem_move */
|
||||||
void *speex_move (void *dest, void *src, int n);
|
void *speex_move (void *dest, void *src, int n);
|
||||||
|
|
||||||
/** Speex wrapper for memcpy */
|
|
||||||
void speex_memcpy_bytes(char *dst, char *src, int nbytes);
|
|
||||||
|
|
||||||
/** Speex wrapper for memset */
|
|
||||||
void speex_memset_bytes(char *dst, char src, int nbytes);
|
|
||||||
|
|
||||||
/** Print error message to stderr */
|
/** Print error message to stderr */
|
||||||
void speex_error(const char *str);
|
void speex_error(const char *str);
|
||||||
|
|
||||||
|
|
|
@ -495,7 +495,7 @@ static const SpeexSBMode sb_wb_mode = {
|
||||||
#endif
|
#endif
|
||||||
.012, /*lag_factor*/
|
.012, /*lag_factor*/
|
||||||
QCONST16(.0002,15), /*lpc_floor*/
|
QCONST16(.0002,15), /*lpc_floor*/
|
||||||
0.9,
|
QCONST16(0.9f,15),
|
||||||
{NULL, &wb_submode1, &wb_submode2, &wb_submode3, &wb_submode4, NULL, NULL, NULL},
|
{NULL, &wb_submode1, &wb_submode2, &wb_submode3, &wb_submode4, NULL, NULL, NULL},
|
||||||
3,
|
3,
|
||||||
{1, 8, 2, 3, 4, 5, 5, 6, 6, 7, 7},
|
{1, 8, 2, 3, 4, 5, 5, 6, 6, 7, 7},
|
||||||
|
@ -541,7 +541,7 @@ static const SpeexSBMode sb_uwb_mode = {
|
||||||
#endif
|
#endif
|
||||||
.012, /*lag_factor*/
|
.012, /*lag_factor*/
|
||||||
QCONST16(.0002,15), /*lpc_floor*/
|
QCONST16(.0002,15), /*lpc_floor*/
|
||||||
0.7,
|
QCONST16(0.7f,15),
|
||||||
{NULL, &wb_submode1, NULL, NULL, NULL, NULL, NULL, NULL},
|
{NULL, &wb_submode1, NULL, NULL, NULL, NULL, NULL, NULL},
|
||||||
1,
|
1,
|
||||||
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
|
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
|
||||||
|
@ -608,11 +608,7 @@ static const SpeexSubmode nb_48k_submode = {
|
||||||
split_cb_search_shape_sign,
|
split_cb_search_shape_sign,
|
||||||
split_cb_shape_sign_unquant,
|
split_cb_shape_sign_unquant,
|
||||||
&split_cb_nb_48k,
|
&split_cb_nb_48k,
|
||||||
#ifdef FIXED_POINT
|
QCONST16(.7,15),
|
||||||
22938, 16384, 11796, 18022,
|
|
||||||
#else
|
|
||||||
0.7, 0.5, .36, .55,
|
|
||||||
#endif
|
|
||||||
144
|
144
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -622,7 +618,6 @@ static const SpeexNBMode nb_48k_mode = {
|
||||||
240, /*frameSize*/
|
240, /*frameSize*/
|
||||||
48, /*subframeSize*/
|
48, /*subframeSize*/
|
||||||
10, /*lpcSize*/
|
10, /*lpcSize*/
|
||||||
640, /*bufSize*/
|
|
||||||
17, /*pitchStart*/
|
17, /*pitchStart*/
|
||||||
144, /*pitchEnd*/
|
144, /*pitchEnd*/
|
||||||
0.9, /*gamma1*/
|
0.9, /*gamma1*/
|
||||||
|
|
|
@ -130,7 +130,7 @@ typedef struct SpeexSBMode {
|
||||||
spx_word16_t gamma2; /**< Perceptual filter parameter #1 */
|
spx_word16_t gamma2; /**< Perceptual filter parameter #1 */
|
||||||
float lag_factor; /**< Lag-windowing parameter */
|
float lag_factor; /**< Lag-windowing parameter */
|
||||||
spx_word16_t lpc_floor; /**< Noise floor for LPC analysis */
|
spx_word16_t lpc_floor; /**< Noise floor for LPC analysis */
|
||||||
float folding_gain;
|
spx_word16_t folding_gain;
|
||||||
|
|
||||||
const SpeexSubmode *submodes[SB_SUBMODES]; /**< Sub-mode data for the mode */
|
const SpeexSubmode *submodes[SB_SUBMODES]; /**< Sub-mode data for the mode */
|
||||||
int defaultSubmode; /**< Default sub-mode to use when encoding */
|
int defaultSubmode; /**< Default sub-mode to use when encoding */
|
||||||
|
|
|
@ -187,7 +187,7 @@ void *nb_encoder_init(const SpeexMode *m)
|
||||||
st->mem_exc2 = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t));
|
st->mem_exc2 = (spx_mem_t*)speex_alloc((st->lpcSize)*sizeof(spx_mem_t));
|
||||||
|
|
||||||
st->pi_gain = (spx_word32_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word32_t));
|
st->pi_gain = (spx_word32_t*)speex_alloc((st->nbSubframes)*sizeof(spx_word32_t));
|
||||||
st->innov_save = NULL;
|
st->innov_rms_save = NULL;
|
||||||
|
|
||||||
st->pitch = (int*)speex_alloc((st->nbSubframes)*sizeof(int));
|
st->pitch = (int*)speex_alloc((st->nbSubframes)*sizeof(int));
|
||||||
|
|
||||||
|
@ -280,6 +280,8 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
|
||||||
int pitch_half[2];
|
int pitch_half[2];
|
||||||
int ol_pitch_id=0;
|
int ol_pitch_id=0;
|
||||||
#endif
|
#endif
|
||||||
|
spx_word32_t ener=0;
|
||||||
|
spx_word16_t fine_gain;
|
||||||
spx_word16_t *in = (spx_word16_t*)vin;
|
spx_word16_t *in = (spx_word16_t*)vin;
|
||||||
|
|
||||||
st=(EncState *)state;
|
st=(EncState *)state;
|
||||||
|
@ -432,7 +434,7 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
|
||||||
ol_gain2=ol2;
|
ol_gain2=ol2;
|
||||||
ol_gain2 = sqrt(2*ol_gain2*(ol1+ol2))*1.3*(1-.5*GAIN_SCALING_1*GAIN_SCALING_1*ol_pitch_coef*ol_pitch_coef);
|
ol_gain2 = sqrt(2*ol_gain2*(ol1+ol2))*1.3*(1-.5*GAIN_SCALING_1*GAIN_SCALING_1*ol_pitch_coef*ol_pitch_coef);
|
||||||
|
|
||||||
ol_gain=SHR(sqrt(1+ol_gain2/st->frameSize),SIG_SHIFT);
|
ol_gain=SHR32(sqrt(1+ol_gain2/st->frameSize),SIG_SHIFT);
|
||||||
|
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
|
@ -490,7 +492,7 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
|
||||||
/* delta_qual*=.1*(3+st->vbr_quality);*/
|
/* delta_qual*=.1*(3+st->vbr_quality);*/
|
||||||
if (st->vbr_enabled)
|
if (st->vbr_enabled)
|
||||||
{
|
{
|
||||||
int mode;
|
spx_int32_t mode;
|
||||||
int choice=0;
|
int choice=0;
|
||||||
float min_diff=100;
|
float min_diff=100;
|
||||||
mode = 8;
|
mode = 8;
|
||||||
|
@ -540,7 +542,7 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
|
||||||
|
|
||||||
if (st->abr_enabled)
|
if (st->abr_enabled)
|
||||||
{
|
{
|
||||||
int bitrate;
|
spx_int32_t bitrate;
|
||||||
speex_encoder_ctl(state, SPEEX_GET_BITRATE, &bitrate);
|
speex_encoder_ctl(state, SPEEX_GET_BITRATE, &bitrate);
|
||||||
st->abr_drift+=(bitrate-st->abr_enabled);
|
st->abr_drift+=(bitrate-st->abr_enabled);
|
||||||
st->abr_drift2 = .95*st->abr_drift2 + .05*(bitrate-st->abr_enabled);
|
st->abr_drift2 = .95*st->abr_drift2 + .05*(bitrate-st->abr_enabled);
|
||||||
|
@ -720,7 +722,6 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
|
||||||
int offset;
|
int offset;
|
||||||
spx_word16_t *sw;
|
spx_word16_t *sw;
|
||||||
spx_word16_t *exc;
|
spx_word16_t *exc;
|
||||||
spx_sig_t *innov_save = NULL;
|
|
||||||
int pitch;
|
int pitch;
|
||||||
int response_bound = st->subframeSize;
|
int response_bound = st->subframeSize;
|
||||||
#ifdef EPIC_48K
|
#ifdef EPIC_48K
|
||||||
|
@ -739,9 +740,6 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
|
||||||
exc=st->exc+offset;
|
exc=st->exc+offset;
|
||||||
/* Weighted signal */
|
/* Weighted signal */
|
||||||
sw=st->sw+offset;
|
sw=st->sw+offset;
|
||||||
/* Pointer for saving innovation */
|
|
||||||
if (st->innov_save)
|
|
||||||
innov_save = st->innov_save+offset;
|
|
||||||
|
|
||||||
/* LSP interpolation (quantized and unquantized) */
|
/* LSP interpolation (quantized and unquantized) */
|
||||||
lsp_interpolate(st->old_lsp, lsp, interp_lsp, st->lpcSize, sub, st->nbSubframes);
|
lsp_interpolate(st->old_lsp, lsp, interp_lsp, st->lpcSize, sub, st->nbSubframes);
|
||||||
|
@ -838,9 +836,9 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
|
||||||
for (i=0;i<st->lpcSize;i++)
|
for (i=0;i<st->lpcSize;i++)
|
||||||
st->mem_sw[i]=mem[i];
|
st->mem_sw[i]=mem[i];
|
||||||
|
|
||||||
/* Compute target signal */
|
/* Compute target signal (saturation prevents overflows on clipped input speech) */
|
||||||
for (i=0;i<st->subframeSize;i++)
|
for (i=0;i<st->subframeSize;i++)
|
||||||
target[i]=SUB16(sw[i],PSHR32(ringing[i],1));
|
target[i]=EXTRACT16(SATURATE(SUB32(sw[i],PSHR32(ringing[i],1)),32767));
|
||||||
|
|
||||||
/* Reset excitation */
|
/* Reset excitation */
|
||||||
for (i=0;i<st->subframeSize;i++)
|
for (i=0;i<st->subframeSize;i++)
|
||||||
|
@ -901,75 +899,64 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Quantization of innovation */
|
/* Quantization of innovation */
|
||||||
{
|
for (i=0;i<st->subframeSize;i++)
|
||||||
spx_word32_t ener=0;
|
innov[i]=0;
|
||||||
spx_word16_t fine_gain;
|
|
||||||
|
|
||||||
for (i=0;i<st->subframeSize;i++)
|
/* FIXME: Make sure this is save from overflows (so far so good) */
|
||||||
innov[i]=0;
|
for (i=0;i<st->subframeSize;i++)
|
||||||
|
real_exc[i] = EXTRACT16(SUB32(EXTEND32(real_exc[i]), PSHR32(exc32[i],SIG_SHIFT-1)));
|
||||||
|
|
||||||
for (i=0;i<st->subframeSize;i++)
|
ener = SHL32(EXTEND32(compute_rms16(real_exc, st->subframeSize)),SIG_SHIFT);
|
||||||
real_exc[i] = SUB16(real_exc[i], PSHR32(exc32[i],SIG_SHIFT-1));
|
|
||||||
|
|
||||||
ener = SHL32(EXTEND32(compute_rms16(real_exc, st->subframeSize)),SIG_SHIFT);
|
/*FIXME: Should use DIV32_16 and make sure result fits in 16 bits */
|
||||||
|
|
||||||
/*FIXME: Should use DIV32_16 and make sure result fits in 16 bits */
|
|
||||||
#ifdef FIXED_POINT
|
#ifdef FIXED_POINT
|
||||||
{
|
{
|
||||||
spx_word32_t f = PDIV32(ener,PSHR32(ol_gain,SIG_SHIFT));
|
spx_word32_t f = PDIV32(ener,PSHR32(ol_gain,SIG_SHIFT));
|
||||||
if (f<=32767)
|
if (f<=32767)
|
||||||
fine_gain = f;
|
fine_gain = f;
|
||||||
else
|
else
|
||||||
fine_gain = 32767;
|
fine_gain = 32767;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
fine_gain = PDIV32_16(ener,PSHR32(ol_gain,SIG_SHIFT));
|
fine_gain = PDIV32_16(ener,PSHR32(ol_gain,SIG_SHIFT));
|
||||||
#endif
|
#endif
|
||||||
/* Calculate gain correction for the sub-frame (if any) */
|
/* Calculate gain correction for the sub-frame (if any) */
|
||||||
if (SUBMODE(have_subframe_gain))
|
if (SUBMODE(have_subframe_gain))
|
||||||
|
{
|
||||||
|
int qe;
|
||||||
|
if (SUBMODE(have_subframe_gain)==3)
|
||||||
{
|
{
|
||||||
int qe;
|
qe = scal_quant(fine_gain, exc_gain_quant_scal3_bound, 8);
|
||||||
if (SUBMODE(have_subframe_gain)==3)
|
speex_bits_pack(bits, qe, 3);
|
||||||
{
|
ener=MULT16_32_Q14(exc_gain_quant_scal3[qe],ol_gain);
|
||||||
qe = scal_quant(fine_gain, exc_gain_quant_scal3_bound, 8);
|
|
||||||
speex_bits_pack(bits, qe, 3);
|
|
||||||
ener=MULT16_32_Q14(exc_gain_quant_scal3[qe],ol_gain);
|
|
||||||
} else {
|
|
||||||
qe = scal_quant(fine_gain, exc_gain_quant_scal1_bound, 2);
|
|
||||||
speex_bits_pack(bits, qe, 1);
|
|
||||||
ener=MULT16_32_Q14(exc_gain_quant_scal1[qe],ol_gain);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
ener=ol_gain;
|
qe = scal_quant(fine_gain, exc_gain_quant_scal1_bound, 2);
|
||||||
|
speex_bits_pack(bits, qe, 1);
|
||||||
|
ener=MULT16_32_Q14(exc_gain_quant_scal1[qe],ol_gain);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
ener=ol_gain;
|
||||||
|
}
|
||||||
|
|
||||||
/*printf ("%f %f\n", ener, ol_gain);*/
|
/*printf ("%f %f\n", ener, ol_gain);*/
|
||||||
|
|
||||||
/* Normalize innovation */
|
/* Normalize innovation */
|
||||||
signal_div(target, target, ener, st->subframeSize);
|
signal_div(target, target, ener, st->subframeSize);
|
||||||
|
|
||||||
/* Quantize innovation */
|
/* Quantize innovation */
|
||||||
if (SUBMODE(innovation_quant))
|
if (SUBMODE(innovation_quant))
|
||||||
{
|
{
|
||||||
/* Codebook search */
|
/* Codebook search */
|
||||||
SUBMODE(innovation_quant)(target, interp_qlpc, bw_lpc1, bw_lpc2,
|
SUBMODE(innovation_quant)(target, interp_qlpc, bw_lpc1, bw_lpc2,
|
||||||
SUBMODE(innovation_params), st->lpcSize, st->subframeSize,
|
SUBMODE(innovation_params), st->lpcSize, st->subframeSize,
|
||||||
innov, syn_resp, bits, stack, st->complexity, SUBMODE(double_codebook));
|
innov, syn_resp, bits, stack, st->complexity, SUBMODE(double_codebook));
|
||||||
|
|
||||||
/* De-normalize innovation and update excitation */
|
/* De-normalize innovation and update excitation */
|
||||||
signal_mul(innov, innov, ener, st->subframeSize);
|
signal_mul(innov, innov, ener, st->subframeSize);
|
||||||
|
|
||||||
for (i=0;i<st->subframeSize;i++)
|
for (i=0;i<st->subframeSize;i++)
|
||||||
exc[i] = EXTRACT16(PSHR32(ADD32(SHL32(exc32[i],1),innov[i]),SIG_SHIFT));
|
exc[i] = EXTRACT16(SATURATE32(PSHR32(ADD32(SHL32(exc32[i],1),innov[i]),SIG_SHIFT),32767));
|
||||||
} else {
|
|
||||||
speex_error("No fixed codebook");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (innov_save)
|
|
||||||
{
|
|
||||||
for (i=0;i<st->subframeSize;i++)
|
|
||||||
innov_save[i] = innov[i];
|
|
||||||
}
|
|
||||||
/* In some (rare) modes, we do a second search (more bits) to reduce noise even more */
|
/* In some (rare) modes, we do a second search (more bits) to reduce noise even more */
|
||||||
if (SUBMODE(double_codebook)) {
|
if (SUBMODE(double_codebook)) {
|
||||||
char *tmp_stack=stack;
|
char *tmp_stack=stack;
|
||||||
|
@ -978,23 +965,26 @@ int nb_encode(void *state, void *vin, SpeexBits *bits)
|
||||||
for (i=0;i<st->subframeSize;i++)
|
for (i=0;i<st->subframeSize;i++)
|
||||||
innov2[i]=0;
|
innov2[i]=0;
|
||||||
for (i=0;i<st->subframeSize;i++)
|
for (i=0;i<st->subframeSize;i++)
|
||||||
target[i]=MULT16_16_P13(QCONST16(2.2,13), target[i]);
|
target[i]=MULT16_16_P13(QCONST16(2.2f,13), target[i]);
|
||||||
SUBMODE(innovation_quant)(target, interp_qlpc, bw_lpc1, bw_lpc2,
|
SUBMODE(innovation_quant)(target, interp_qlpc, bw_lpc1, bw_lpc2,
|
||||||
SUBMODE(innovation_params), st->lpcSize, st->subframeSize,
|
SUBMODE(innovation_params), st->lpcSize, st->subframeSize,
|
||||||
innov2, syn_resp, bits, stack, st->complexity, 0);
|
innov2, syn_resp, bits, stack, st->complexity, 0);
|
||||||
signal_mul(innov2, innov2, MULT16_32_Q15(QCONST16(0.454545,15),ener), st->subframeSize);
|
signal_mul(innov2, innov2, MULT16_32_Q15(QCONST16(0.454545f,15),ener), st->subframeSize);
|
||||||
for (i=0;i<st->subframeSize;i++)
|
for (i=0;i<st->subframeSize;i++)
|
||||||
exc[i] = ADD32(exc[i],PSHR32(innov2[i],SIG_SHIFT));
|
innov[i] = ADD32(innov[i],innov2[i]);
|
||||||
if (innov_save)
|
|
||||||
{
|
|
||||||
for (i=0;i<st->subframeSize;i++)
|
|
||||||
innov_save[i] = ADD32(innov_save[i],innov2[i]);
|
|
||||||
}
|
|
||||||
stack = tmp_stack;
|
stack = tmp_stack;
|
||||||
}
|
}
|
||||||
|
for (i=0;i<st->subframeSize;i++)
|
||||||
|
exc[i] = EXTRACT16(SATURATE32(PSHR32(ADD32(SHL32(exc32[i],1),innov[i]),SIG_SHIFT),32767));
|
||||||
|
if (st->innov_rms_save)
|
||||||
|
{
|
||||||
|
st->innov_rms_save[sub] = compute_rms(innov, st->subframeSize);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
speex_error("No fixed codebook");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (i=0;i<st->subframeSize;i++)
|
for (i=0;i<st->subframeSize;i++)
|
||||||
sw[i] = exc[i];
|
sw[i] = exc[i];
|
||||||
/* Final signal synthesis from excitation */
|
/* Final signal synthesis from excitation */
|
||||||
|
@ -1166,7 +1156,7 @@ static void nb_decode_lost(DecState *st, spx_word16_t *out, char *stack)
|
||||||
pitch_gain = st->last_pitch_gain;
|
pitch_gain = st->last_pitch_gain;
|
||||||
if (pitch_gain>54)
|
if (pitch_gain>54)
|
||||||
pitch_gain = 54;
|
pitch_gain = 54;
|
||||||
pitch_gain = SHL(pitch_gain, 9);
|
pitch_gain = SHL16(pitch_gain, 9);
|
||||||
#else
|
#else
|
||||||
pitch_gain = GAIN_SCALING_1*st->last_pitch_gain;
|
pitch_gain = GAIN_SCALING_1*st->last_pitch_gain;
|
||||||
if (pitch_gain>.85)
|
if (pitch_gain>.85)
|
||||||
|
@ -1200,7 +1190,7 @@ static void nb_decode_lost(DecState *st, spx_word16_t *out, char *stack)
|
||||||
|
|
||||||
st->first = 0;
|
st->first = 0;
|
||||||
st->count_lost++;
|
st->count_lost++;
|
||||||
st->pitch_gain_buf[st->pitch_gain_buf_idx++] = PSHR(pitch_gain,9);
|
st->pitch_gain_buf[st->pitch_gain_buf_idx++] = PSHR16(pitch_gain,9);
|
||||||
if (st->pitch_gain_buf_idx > 2) /* rollover */
|
if (st->pitch_gain_buf_idx > 2) /* rollover */
|
||||||
st->pitch_gain_buf_idx = 0;
|
st->pitch_gain_buf_idx = 0;
|
||||||
}
|
}
|
||||||
|
@ -1226,7 +1216,7 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
|
||||||
VARDECL(spx_lsp_t *qlsp);
|
VARDECL(spx_lsp_t *qlsp);
|
||||||
spx_word16_t pitch_average=0;
|
spx_word16_t pitch_average=0;
|
||||||
#ifdef EPIC_48K
|
#ifdef EPIC_48K
|
||||||
int pitch_half[2];
|
int pitch_half[2] = {0, 0};
|
||||||
int ol_pitch_id=0;
|
int ol_pitch_id=0;
|
||||||
#endif
|
#endif
|
||||||
spx_word16_t *out = (spx_word16_t*)vout;
|
spx_word16_t *out = (spx_word16_t*)vout;
|
||||||
|
@ -1338,7 +1328,7 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
|
||||||
{
|
{
|
||||||
VARDECL(spx_coef_t *lpc);
|
VARDECL(spx_coef_t *lpc);
|
||||||
ALLOC(lpc, st->lpcSize, spx_coef_t);
|
ALLOC(lpc, st->lpcSize, spx_coef_t);
|
||||||
bw_lpc(GAMMA_SCALING*.93, st->interp_qlpc, lpc, st->lpcSize);
|
bw_lpc(QCONST16(0.93f,15), st->interp_qlpc, lpc, st->lpcSize);
|
||||||
{
|
{
|
||||||
float innov_gain=0;
|
float innov_gain=0;
|
||||||
float pgain=GAIN_SCALING_1*st->last_pitch_gain;
|
float pgain=GAIN_SCALING_1*st->last_pitch_gain;
|
||||||
|
@ -1426,6 +1416,7 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
|
||||||
int qe;
|
int qe;
|
||||||
qe = speex_bits_unpack_unsigned(bits, 5);
|
qe = speex_bits_unpack_unsigned(bits, 5);
|
||||||
#ifdef FIXED_POINT
|
#ifdef FIXED_POINT
|
||||||
|
/* FIXME: Perhaps we could slightly lower the gain here when the output is going to saturate? */
|
||||||
ol_gain = MULT16_32_Q15(28406,ol_gain_table[qe]);
|
ol_gain = MULT16_32_Q15(28406,ol_gain_table[qe]);
|
||||||
#else
|
#else
|
||||||
ol_gain = SIG_SCALING*exp(qe/3.5);
|
ol_gain = SIG_SCALING*exp(qe/3.5);
|
||||||
|
@ -1458,7 +1449,7 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
|
||||||
int offset;
|
int offset;
|
||||||
spx_word16_t *exc;
|
spx_word16_t *exc;
|
||||||
spx_word16_t *sp;
|
spx_word16_t *sp;
|
||||||
spx_sig_t *innov_save = NULL;
|
spx_word16_t *innov_save = NULL;
|
||||||
spx_word16_t tmp;
|
spx_word16_t tmp;
|
||||||
|
|
||||||
#ifdef EPIC_48K
|
#ifdef EPIC_48K
|
||||||
|
@ -1576,16 +1567,38 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
|
||||||
{
|
{
|
||||||
/*Fixed codebook contribution*/
|
/*Fixed codebook contribution*/
|
||||||
SUBMODE(innovation_unquant)(innov, SUBMODE(innovation_params), st->subframeSize, bits, stack, &st->seed);
|
SUBMODE(innovation_unquant)(innov, SUBMODE(innovation_params), st->subframeSize, bits, stack, &st->seed);
|
||||||
|
/* De-normalize innovation and update excitation */
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
signal_mul(innov, innov, ener, st->subframeSize);
|
||||||
|
#else
|
||||||
|
signal_mul(innov, innov, ener, st->subframeSize);
|
||||||
|
#endif
|
||||||
|
/* Decode second codebook (only for some modes) */
|
||||||
|
if (SUBMODE(double_codebook))
|
||||||
|
{
|
||||||
|
char *tmp_stack=stack;
|
||||||
|
VARDECL(spx_sig_t *innov2);
|
||||||
|
ALLOC(innov2, st->subframeSize, spx_sig_t);
|
||||||
|
for (i=0;i<st->subframeSize;i++)
|
||||||
|
innov2[i]=0;
|
||||||
|
SUBMODE(innovation_unquant)(innov2, SUBMODE(innovation_params), st->subframeSize, bits, stack, &st->seed);
|
||||||
|
signal_mul(innov2, innov2, MULT16_32_Q15(QCONST16(0.454545f,15),ener), st->subframeSize);
|
||||||
|
for (i=0;i<st->subframeSize;i++)
|
||||||
|
innov[i] = ADD32(innov[i], innov2[i]);
|
||||||
|
stack = tmp_stack;
|
||||||
|
}
|
||||||
|
for (i=0;i<st->subframeSize;i++)
|
||||||
|
exc[i]=EXTRACT16(SATURATE32(PSHR32(ADD32(SHL32(exc32[i],1),innov[i]),SIG_SHIFT),32767));
|
||||||
|
/*print_vec(exc, 40, "innov");*/
|
||||||
|
if (innov_save)
|
||||||
|
{
|
||||||
|
for (i=0;i<st->subframeSize;i++)
|
||||||
|
innov_save[i] = EXTRACT16(PSHR32(innov[i], SIG_SHIFT));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
speex_error("No fixed codebook");
|
speex_error("No fixed codebook");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* De-normalize innovation and update excitation */
|
|
||||||
#ifdef FIXED_POINT
|
|
||||||
signal_mul(innov, innov, ener, st->subframeSize);
|
|
||||||
#else
|
|
||||||
signal_mul(innov, innov, ener, st->subframeSize);
|
|
||||||
#endif
|
|
||||||
/*Vocoder mode*/
|
/*Vocoder mode*/
|
||||||
if (st->submodeID==1)
|
if (st->submodeID==1)
|
||||||
{
|
{
|
||||||
|
@ -1617,35 +1630,8 @@ int nb_decode(void *state, SpeexBits *bits, void *vout)
|
||||||
st->voc_mean = .95*st->voc_mean + .05*exc[i];
|
st->voc_mean = .95*st->voc_mean + .05*exc[i];
|
||||||
exc[i]-=st->voc_mean;
|
exc[i]-=st->voc_mean;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
for (i=0;i<st->subframeSize;i++)
|
|
||||||
exc[i]=PSHR32(ADD32(SHL32(exc32[i],1),innov[i]),SIG_SHIFT);
|
|
||||||
/*print_vec(exc, 40, "innov");*/
|
|
||||||
}
|
|
||||||
if (innov_save)
|
|
||||||
{
|
|
||||||
for (i=0;i<st->subframeSize;i++)
|
|
||||||
innov_save[i] = innov[i];
|
|
||||||
}
|
|
||||||
/* Decode second codebook (only for some modes) */
|
|
||||||
if (SUBMODE(double_codebook))
|
|
||||||
{
|
|
||||||
char *tmp_stack=stack;
|
|
||||||
VARDECL(spx_sig_t *innov2);
|
|
||||||
ALLOC(innov2, st->subframeSize, spx_sig_t);
|
|
||||||
for (i=0;i<st->subframeSize;i++)
|
|
||||||
innov2[i]=0;
|
|
||||||
SUBMODE(innovation_unquant)(innov2, SUBMODE(innovation_params), st->subframeSize, bits, stack, &st->seed);
|
|
||||||
signal_mul(innov2, innov2, MULT16_32_Q15(QCONST16(0.454545,15),ener), st->subframeSize);
|
|
||||||
for (i=0;i<st->subframeSize;i++)
|
|
||||||
exc[i] = ADD16(exc[i],PSHR32(innov2[i],SIG_SHIFT));
|
|
||||||
if (innov_save)
|
|
||||||
{
|
|
||||||
for (i=0;i<st->subframeSize;i++)
|
|
||||||
innov_save[i] = ADD32(innov_save[i],innov2[i]);
|
|
||||||
}
|
|
||||||
stack = tmp_stack;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1759,40 +1745,40 @@ int nb_encoder_ctl(void *state, int request, void *ptr)
|
||||||
switch(request)
|
switch(request)
|
||||||
{
|
{
|
||||||
case SPEEX_GET_FRAME_SIZE:
|
case SPEEX_GET_FRAME_SIZE:
|
||||||
(*(int*)ptr) = st->frameSize;
|
(*(spx_int32_t*)ptr) = st->frameSize;
|
||||||
break;
|
break;
|
||||||
case SPEEX_SET_LOW_MODE:
|
case SPEEX_SET_LOW_MODE:
|
||||||
case SPEEX_SET_MODE:
|
case SPEEX_SET_MODE:
|
||||||
st->submodeSelect = st->submodeID = (*(int*)ptr);
|
st->submodeSelect = st->submodeID = (*(spx_int32_t*)ptr);
|
||||||
break;
|
break;
|
||||||
case SPEEX_GET_LOW_MODE:
|
case SPEEX_GET_LOW_MODE:
|
||||||
case SPEEX_GET_MODE:
|
case SPEEX_GET_MODE:
|
||||||
(*(int*)ptr) = st->submodeID;
|
(*(spx_int32_t*)ptr) = st->submodeID;
|
||||||
break;
|
break;
|
||||||
case SPEEX_SET_VBR:
|
case SPEEX_SET_VBR:
|
||||||
st->vbr_enabled = (*(int*)ptr);
|
st->vbr_enabled = (*(spx_int32_t*)ptr);
|
||||||
break;
|
break;
|
||||||
case SPEEX_GET_VBR:
|
case SPEEX_GET_VBR:
|
||||||
(*(int*)ptr) = st->vbr_enabled;
|
(*(spx_int32_t*)ptr) = st->vbr_enabled;
|
||||||
break;
|
break;
|
||||||
case SPEEX_SET_VAD:
|
case SPEEX_SET_VAD:
|
||||||
st->vad_enabled = (*(int*)ptr);
|
st->vad_enabled = (*(spx_int32_t*)ptr);
|
||||||
break;
|
break;
|
||||||
case SPEEX_GET_VAD:
|
case SPEEX_GET_VAD:
|
||||||
(*(int*)ptr) = st->vad_enabled;
|
(*(spx_int32_t*)ptr) = st->vad_enabled;
|
||||||
break;
|
break;
|
||||||
case SPEEX_SET_DTX:
|
case SPEEX_SET_DTX:
|
||||||
st->dtx_enabled = (*(int*)ptr);
|
st->dtx_enabled = (*(spx_int32_t*)ptr);
|
||||||
break;
|
break;
|
||||||
case SPEEX_GET_DTX:
|
case SPEEX_GET_DTX:
|
||||||
(*(int*)ptr) = st->dtx_enabled;
|
(*(spx_int32_t*)ptr) = st->dtx_enabled;
|
||||||
break;
|
break;
|
||||||
case SPEEX_SET_ABR:
|
case SPEEX_SET_ABR:
|
||||||
st->abr_enabled = (*(spx_int32_t*)ptr);
|
st->abr_enabled = (*(spx_int32_t*)ptr);
|
||||||
st->vbr_enabled = st->abr_enabled!=0;
|
st->vbr_enabled = st->abr_enabled!=0;
|
||||||
if (st->vbr_enabled)
|
if (st->vbr_enabled)
|
||||||
{
|
{
|
||||||
int i=10;
|
spx_int32_t i=10;
|
||||||
spx_int32_t rate, target;
|
spx_int32_t rate, target;
|
||||||
float vbr_qual;
|
float vbr_qual;
|
||||||
target = (*(spx_int32_t*)ptr);
|
target = (*(spx_int32_t*)ptr);
|
||||||
|
@ -1825,7 +1811,7 @@ int nb_encoder_ctl(void *state, int request, void *ptr)
|
||||||
break;
|
break;
|
||||||
case SPEEX_SET_QUALITY:
|
case SPEEX_SET_QUALITY:
|
||||||
{
|
{
|
||||||
int quality = (*(int*)ptr);
|
int quality = (*(spx_int32_t*)ptr);
|
||||||
if (quality < 0)
|
if (quality < 0)
|
||||||
quality = 0;
|
quality = 0;
|
||||||
if (quality > 10)
|
if (quality > 10)
|
||||||
|
@ -1834,7 +1820,7 @@ int nb_encoder_ctl(void *state, int request, void *ptr)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SPEEX_SET_COMPLEXITY:
|
case SPEEX_SET_COMPLEXITY:
|
||||||
st->complexity = (*(int*)ptr);
|
st->complexity = (*(spx_int32_t*)ptr);
|
||||||
if (st->complexity<0)
|
if (st->complexity<0)
|
||||||
st->complexity=0;
|
st->complexity=0;
|
||||||
break;
|
break;
|
||||||
|
@ -1843,7 +1829,7 @@ int nb_encoder_ctl(void *state, int request, void *ptr)
|
||||||
break;
|
break;
|
||||||
case SPEEX_SET_BITRATE:
|
case SPEEX_SET_BITRATE:
|
||||||
{
|
{
|
||||||
int i=10;
|
spx_int32_t i=10;
|
||||||
spx_int32_t rate, target;
|
spx_int32_t rate, target;
|
||||||
target = (*(spx_int32_t*)ptr);
|
target = (*(spx_int32_t*)ptr);
|
||||||
while (i>=0)
|
while (i>=0)
|
||||||
|
@ -1884,21 +1870,21 @@ int nb_encoder_ctl(void *state, int request, void *ptr)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SPEEX_SET_SUBMODE_ENCODING:
|
case SPEEX_SET_SUBMODE_ENCODING:
|
||||||
st->encode_submode = (*(int*)ptr);
|
st->encode_submode = (*(spx_int32_t*)ptr);
|
||||||
break;
|
break;
|
||||||
case SPEEX_GET_SUBMODE_ENCODING:
|
case SPEEX_GET_SUBMODE_ENCODING:
|
||||||
(*(int*)ptr) = st->encode_submode;
|
(*(spx_int32_t*)ptr) = st->encode_submode;
|
||||||
break;
|
break;
|
||||||
case SPEEX_GET_LOOKAHEAD:
|
case SPEEX_GET_LOOKAHEAD:
|
||||||
(*(int*)ptr)=(st->windowSize-st->frameSize);
|
(*(spx_int32_t*)ptr)=(st->windowSize-st->frameSize);
|
||||||
break;
|
break;
|
||||||
case SPEEX_SET_PLC_TUNING:
|
case SPEEX_SET_PLC_TUNING:
|
||||||
st->plc_tuning = (*(int*)ptr);
|
st->plc_tuning = (*(spx_int32_t*)ptr);
|
||||||
if (st->plc_tuning>100)
|
if (st->plc_tuning>100)
|
||||||
st->plc_tuning=100;
|
st->plc_tuning=100;
|
||||||
break;
|
break;
|
||||||
case SPEEX_GET_PLC_TUNING:
|
case SPEEX_GET_PLC_TUNING:
|
||||||
(*(int*)ptr)=(st->plc_tuning);
|
(*(spx_int32_t*)ptr)=(st->plc_tuning);
|
||||||
break;
|
break;
|
||||||
case SPEEX_SET_VBR_MAX_BITRATE:
|
case SPEEX_SET_VBR_MAX_BITRATE:
|
||||||
st->vbr_max = (*(spx_int32_t*)ptr);
|
st->vbr_max = (*(spx_int32_t*)ptr);
|
||||||
|
@ -1925,19 +1911,18 @@ int nb_encoder_ctl(void *state, int request, void *ptr)
|
||||||
case SPEEX_GET_EXC:
|
case SPEEX_GET_EXC:
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
spx_word16_t *e = (spx_word16_t*)ptr;
|
for (i=0;i<st->nbSubframes;i++)
|
||||||
for (i=0;i<st->frameSize;i++)
|
((spx_word16_t*)ptr)[i] = compute_rms16(st->exc+i*st->subframeSize, st->subframeSize);
|
||||||
e[i]=st->exc[i];
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SPEEX_GET_RELATIVE_QUALITY:
|
case SPEEX_GET_RELATIVE_QUALITY:
|
||||||
(*(float*)ptr)=st->relative_quality;
|
(*(float*)ptr)=st->relative_quality;
|
||||||
break;
|
break;
|
||||||
case SPEEX_SET_INNOVATION_SAVE:
|
case SPEEX_SET_INNOVATION_SAVE:
|
||||||
st->innov_save = (spx_sig_t*)ptr;
|
st->innov_rms_save = (spx_word16_t*)ptr;
|
||||||
break;
|
break;
|
||||||
case SPEEX_SET_WIDEBAND:
|
case SPEEX_SET_WIDEBAND:
|
||||||
st->isWideband = *((int*)ptr);
|
st->isWideband = *((spx_int32_t*)ptr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
speex_warning_int("Unknown nb_ctl request: ", request);
|
speex_warning_int("Unknown nb_ctl request: ", request);
|
||||||
|
@ -1954,20 +1939,20 @@ int nb_decoder_ctl(void *state, int request, void *ptr)
|
||||||
{
|
{
|
||||||
case SPEEX_SET_LOW_MODE:
|
case SPEEX_SET_LOW_MODE:
|
||||||
case SPEEX_SET_MODE:
|
case SPEEX_SET_MODE:
|
||||||
st->submodeID = (*(int*)ptr);
|
st->submodeID = (*(spx_int32_t*)ptr);
|
||||||
break;
|
break;
|
||||||
case SPEEX_GET_LOW_MODE:
|
case SPEEX_GET_LOW_MODE:
|
||||||
case SPEEX_GET_MODE:
|
case SPEEX_GET_MODE:
|
||||||
(*(int*)ptr) = st->submodeID;
|
(*(spx_int32_t*)ptr) = st->submodeID;
|
||||||
break;
|
break;
|
||||||
case SPEEX_SET_ENH:
|
case SPEEX_SET_ENH:
|
||||||
st->lpc_enh_enabled = *((int*)ptr);
|
st->lpc_enh_enabled = *((spx_int32_t*)ptr);
|
||||||
break;
|
break;
|
||||||
case SPEEX_GET_ENH:
|
case SPEEX_GET_ENH:
|
||||||
*((int*)ptr) = st->lpc_enh_enabled;
|
*((spx_int32_t*)ptr) = st->lpc_enh_enabled;
|
||||||
break;
|
break;
|
||||||
case SPEEX_GET_FRAME_SIZE:
|
case SPEEX_GET_FRAME_SIZE:
|
||||||
(*(int*)ptr) = st->frameSize;
|
(*(spx_int32_t*)ptr) = st->frameSize;
|
||||||
break;
|
break;
|
||||||
case SPEEX_GET_BITRATE:
|
case SPEEX_GET_BITRATE:
|
||||||
if (st->submodes[st->submodeID])
|
if (st->submodes[st->submodeID])
|
||||||
|
@ -2007,13 +1992,13 @@ int nb_decoder_ctl(void *state, int request, void *ptr)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SPEEX_SET_SUBMODE_ENCODING:
|
case SPEEX_SET_SUBMODE_ENCODING:
|
||||||
st->encode_submode = (*(int*)ptr);
|
st->encode_submode = (*(spx_int32_t*)ptr);
|
||||||
break;
|
break;
|
||||||
case SPEEX_GET_SUBMODE_ENCODING:
|
case SPEEX_GET_SUBMODE_ENCODING:
|
||||||
(*(int*)ptr) = st->encode_submode;
|
(*(spx_int32_t*)ptr) = st->encode_submode;
|
||||||
break;
|
break;
|
||||||
case SPEEX_GET_LOOKAHEAD:
|
case SPEEX_GET_LOOKAHEAD:
|
||||||
(*(int*)ptr)=st->subframeSize;
|
(*(spx_int32_t*)ptr)=st->subframeSize;
|
||||||
break;
|
break;
|
||||||
case SPEEX_SET_HIGHPASS:
|
case SPEEX_SET_HIGHPASS:
|
||||||
st->highpass_enabled = (*(spx_int32_t*)ptr);
|
st->highpass_enabled = (*(spx_int32_t*)ptr);
|
||||||
|
@ -2033,19 +2018,18 @@ int nb_decoder_ctl(void *state, int request, void *ptr)
|
||||||
case SPEEX_GET_EXC:
|
case SPEEX_GET_EXC:
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
spx_word16_t *e = (spx_word16_t*)ptr;
|
for (i=0;i<st->nbSubframes;i++)
|
||||||
for (i=0;i<st->frameSize;i++)
|
((spx_word16_t*)ptr)[i] = compute_rms16(st->exc+i*st->subframeSize, st->subframeSize);
|
||||||
e[i]=st->exc[i];
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SPEEX_GET_DTX_STATUS:
|
case SPEEX_GET_DTX_STATUS:
|
||||||
*((int*)ptr) = st->dtx_enabled;
|
*((spx_int32_t*)ptr) = st->dtx_enabled;
|
||||||
break;
|
break;
|
||||||
case SPEEX_SET_INNOVATION_SAVE:
|
case SPEEX_SET_INNOVATION_SAVE:
|
||||||
st->innov_save = (spx_sig_t*)ptr;
|
st->innov_save = (spx_word16_t*)ptr;
|
||||||
break;
|
break;
|
||||||
case SPEEX_SET_WIDEBAND:
|
case SPEEX_SET_WIDEBAND:
|
||||||
st->isWideband = *((int*)ptr);
|
st->isWideband = *((spx_int32_t*)ptr);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
speex_warning_int("Unknown nb_ctl request: ", request);
|
speex_warning_int("Unknown nb_ctl request: ", request);
|
||||||
|
|
|
@ -96,12 +96,12 @@ typedef struct EncState {
|
||||||
spx_mem_t *mem_exc2; /**< Filter memory for excitation (whole frame) */
|
spx_mem_t *mem_exc2; /**< Filter memory for excitation (whole frame) */
|
||||||
spx_mem_t mem_hp[2]; /**< High-pass filter memory */
|
spx_mem_t mem_hp[2]; /**< High-pass filter memory */
|
||||||
spx_word32_t *pi_gain; /**< Gain of LPC filter at theta=pi (fe/2) */
|
spx_word32_t *pi_gain; /**< Gain of LPC filter at theta=pi (fe/2) */
|
||||||
spx_sig_t *innov_save; /**< If non-NULL, innovation is copied here */
|
spx_word16_t *innov_rms_save; /**< If non-NULL, innovation RMS is copied here */
|
||||||
|
|
||||||
VBRState *vbr; /**< State of the VBR data */
|
VBRState *vbr; /**< State of the VBR data */
|
||||||
float vbr_quality; /**< Quality setting for VBR encoding */
|
float vbr_quality; /**< Quality setting for VBR encoding */
|
||||||
float relative_quality; /**< Relative quality that will be needed by VBR */
|
float relative_quality; /**< Relative quality that will be needed by VBR */
|
||||||
int vbr_enabled; /**< 1 for enabling VBR, 0 otherwise */
|
spx_int32_t vbr_enabled; /**< 1 for enabling VBR, 0 otherwise */
|
||||||
spx_int32_t vbr_max; /**< Max bit-rate allowed in VBR mode */
|
spx_int32_t vbr_max; /**< Max bit-rate allowed in VBR mode */
|
||||||
int vad_enabled; /**< 1 for enabling VAD, 0 otherwise */
|
int vad_enabled; /**< 1 for enabling VAD, 0 otherwise */
|
||||||
int dtx_enabled; /**< 1 for enabling DTX, 0 otherwise */
|
int dtx_enabled; /**< 1 for enabling DTX, 0 otherwise */
|
||||||
|
@ -148,7 +148,7 @@ typedef struct DecState {
|
||||||
spx_mem_t *mem_sp; /**< Filter memory for synthesis signal */
|
spx_mem_t *mem_sp; /**< Filter memory for synthesis signal */
|
||||||
spx_mem_t mem_hp[2]; /**< High-pass filter memory */
|
spx_mem_t mem_hp[2]; /**< High-pass filter memory */
|
||||||
spx_word32_t *pi_gain; /**< Gain of LPC filter at theta=pi (fe/2) */
|
spx_word32_t *pi_gain; /**< Gain of LPC filter at theta=pi (fe/2) */
|
||||||
spx_sig_t *innov_save; /** If non-NULL, innovation is copied here */
|
spx_word16_t *innov_save; /** If non-NULL, innovation is copied here */
|
||||||
|
|
||||||
/* This is used in packet loss concealment */
|
/* This is used in packet loss concealment */
|
||||||
int last_pitch; /**< Pitch of last correctly decoded frame */
|
int last_pitch; /**< Pitch of last correctly decoded frame */
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -37,7 +37,7 @@
|
||||||
|
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "math_approx.h"
|
#include "math_approx.h"
|
||||||
//#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#ifdef FIXED_POINT
|
#ifdef FIXED_POINT
|
||||||
|
|
||||||
|
@ -50,9 +50,7 @@ static const spx_float_t FLOAT_ZERO = {0,0};
|
||||||
static const spx_float_t FLOAT_ONE = {16384,-14};
|
static const spx_float_t FLOAT_ONE = {16384,-14};
|
||||||
static const spx_float_t FLOAT_HALF = {16384,-15};
|
static const spx_float_t FLOAT_HALF = {16384,-15};
|
||||||
|
|
||||||
#ifndef MIN
|
|
||||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||||
#endif
|
|
||||||
static inline spx_float_t PSEUDOFLOAT(spx_int32_t x)
|
static inline spx_float_t PSEUDOFLOAT(spx_int32_t x)
|
||||||
{
|
{
|
||||||
int e=0;
|
int e=0;
|
||||||
|
@ -67,18 +65,8 @@ static inline spx_float_t PSEUDOFLOAT(spx_int32_t x)
|
||||||
spx_float_t r = {0,0};
|
spx_float_t r = {0,0};
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
while (x>32767)
|
e = spx_ilog2(ABS32(x))-14;
|
||||||
{
|
x = VSHR32(x, e);
|
||||||
x >>= 1;
|
|
||||||
/*x *= .5;*/
|
|
||||||
e++;
|
|
||||||
}
|
|
||||||
while (x<16383)
|
|
||||||
{
|
|
||||||
x <<= 1;
|
|
||||||
/*x *= 2;*/
|
|
||||||
e--;
|
|
||||||
}
|
|
||||||
if (sign)
|
if (sign)
|
||||||
{
|
{
|
||||||
spx_float_t r;
|
spx_float_t r;
|
||||||
|
@ -207,6 +195,14 @@ static inline spx_float_t FLOAT_MULT(spx_float_t a, spx_float_t b)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline spx_float_t FLOAT_AMULT(spx_float_t a, spx_float_t b)
|
||||||
|
{
|
||||||
|
spx_float_t r;
|
||||||
|
r.m = (spx_int16_t)((spx_int32_t)(a).m*(b).m>>15);
|
||||||
|
r.e = (a).e+(b).e+15;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline spx_float_t FLOAT_SHL(spx_float_t a, int b)
|
static inline spx_float_t FLOAT_SHL(spx_float_t a, int b)
|
||||||
{
|
{
|
||||||
|
@ -232,64 +228,40 @@ static inline spx_int32_t FLOAT_EXTRACT32(spx_float_t a)
|
||||||
return EXTEND32(a.m)<<a.e;
|
return EXTEND32(a.m)<<a.e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline spx_int32_t FLOAT_MUL32(spx_float_t a, spx_word32_t b)
|
static inline spx_int32_t FLOAT_MUL32(spx_float_t a, spx_word32_t b)
|
||||||
{
|
{
|
||||||
if (a.e<-15)
|
return VSHR32(MULT16_32_Q15(a.m, b),-a.e-15);
|
||||||
return SHR32(MULT16_32_Q15(a.m, b),-a.e-15);
|
|
||||||
else
|
|
||||||
return SHL32(MULT16_32_Q15(a.m, b),15+a.e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline spx_float_t FLOAT_MUL32U(spx_word32_t a, spx_word32_t b)
|
static inline spx_float_t FLOAT_MUL32U(spx_word32_t a, spx_word32_t b)
|
||||||
{
|
{
|
||||||
int e=0;
|
int e1, e2;
|
||||||
spx_float_t r;
|
spx_float_t r;
|
||||||
/* FIXME: Handle the sign */
|
if (a==0 || b==0)
|
||||||
if (a==0)
|
|
||||||
{
|
{
|
||||||
return FLOAT_ZERO;
|
return FLOAT_ZERO;
|
||||||
}
|
}
|
||||||
while (a>32767)
|
e1 = spx_ilog2(ABS32(a));
|
||||||
{
|
a = VSHR32(a, e1-14);
|
||||||
a >>= 1;
|
e2 = spx_ilog2(ABS32(b));
|
||||||
e++;
|
b = VSHR32(b, e2-14);
|
||||||
}
|
|
||||||
while (a<16384)
|
|
||||||
{
|
|
||||||
a <<= 1;
|
|
||||||
e--;
|
|
||||||
}
|
|
||||||
while (b>32767)
|
|
||||||
{
|
|
||||||
b >>= 1;
|
|
||||||
e++;
|
|
||||||
}
|
|
||||||
while (b<16384)
|
|
||||||
{
|
|
||||||
b <<= 1;
|
|
||||||
e--;
|
|
||||||
}
|
|
||||||
r.m = MULT16_16_Q15(a,b);
|
r.m = MULT16_16_Q15(a,b);
|
||||||
r.e = e+15;
|
r.e = e1+e2-13;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Do NOT attempt to divide by a negative number */
|
||||||
static inline spx_float_t FLOAT_DIV32_FLOAT(spx_word32_t a, spx_float_t b)
|
static inline spx_float_t FLOAT_DIV32_FLOAT(spx_word32_t a, spx_float_t b)
|
||||||
{
|
{
|
||||||
int e=0;
|
int e=0;
|
||||||
spx_float_t r;
|
spx_float_t r;
|
||||||
/* FIXME: Handle the sign */
|
|
||||||
if (a==0)
|
if (a==0)
|
||||||
{
|
{
|
||||||
return FLOAT_ZERO;
|
return FLOAT_ZERO;
|
||||||
}
|
}
|
||||||
while (a<SHL32(EXTEND32(b.m),14))
|
e = spx_ilog2(ABS32(a))-spx_ilog2(b.m-1)-15;
|
||||||
{
|
a = VSHR32(a, e);
|
||||||
a <<= 1;
|
if (ABS32(a)>=SHL32(EXTEND32(b.m-1),15))
|
||||||
e--;
|
|
||||||
}
|
|
||||||
while (a>=SHL32(EXTEND32(b.m-1),15))
|
|
||||||
{
|
{
|
||||||
a >>= 1;
|
a >>= 1;
|
||||||
e++;
|
e++;
|
||||||
|
@ -300,41 +272,47 @@ static inline spx_float_t FLOAT_DIV32_FLOAT(spx_word32_t a, spx_float_t b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Do NOT attempt to divide by a negative number */
|
||||||
static inline spx_float_t FLOAT_DIV32(spx_word32_t a, spx_word32_t b)
|
static inline spx_float_t FLOAT_DIV32(spx_word32_t a, spx_word32_t b)
|
||||||
{
|
{
|
||||||
int e=0;
|
int e0=0,e=0;
|
||||||
spx_float_t r;
|
spx_float_t r;
|
||||||
/* FIXME: Handle the sign */
|
|
||||||
if (a==0)
|
if (a==0)
|
||||||
{
|
{
|
||||||
return FLOAT_ZERO;
|
return FLOAT_ZERO;
|
||||||
}
|
}
|
||||||
while (b>32767)
|
if (b>32767)
|
||||||
{
|
{
|
||||||
b >>= 1;
|
e0 = spx_ilog2(b)-14;
|
||||||
e--;
|
b = VSHR32(b, e0);
|
||||||
|
e0 = -e0;
|
||||||
}
|
}
|
||||||
while (a<SHL32(b,14))
|
e = spx_ilog2(ABS32(a))-spx_ilog2(b-1)-15;
|
||||||
{
|
a = VSHR32(a, e);
|
||||||
a <<= 1;
|
if (ABS32(a)>=SHL32(EXTEND32(b-1),15))
|
||||||
e--;
|
|
||||||
}
|
|
||||||
while (a>=SHL32(b-1,15))
|
|
||||||
{
|
{
|
||||||
a >>= 1;
|
a >>= 1;
|
||||||
e++;
|
e++;
|
||||||
}
|
}
|
||||||
|
e += e0;
|
||||||
r.m = DIV32_16(a,b);
|
r.m = DIV32_16(a,b);
|
||||||
r.e = e;
|
r.e = e;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Do NOT attempt to divide by a negative number */
|
||||||
static inline spx_float_t FLOAT_DIVU(spx_float_t a, spx_float_t b)
|
static inline spx_float_t FLOAT_DIVU(spx_float_t a, spx_float_t b)
|
||||||
{
|
{
|
||||||
int e=0;
|
int e=0;
|
||||||
spx_int32_t num;
|
spx_int32_t num;
|
||||||
spx_float_t r;
|
spx_float_t r;
|
||||||
|
if (b.m<=0)
|
||||||
|
{
|
||||||
|
speex_warning_int("Attempted to divide by", b.m);
|
||||||
|
return FLOAT_ONE;
|
||||||
|
}
|
||||||
num = a.m;
|
num = a.m;
|
||||||
|
a.m = ABS16(a.m);
|
||||||
while (a.m >= b.m)
|
while (a.m >= b.m)
|
||||||
{
|
{
|
||||||
e++;
|
e++;
|
||||||
|
@ -350,7 +328,7 @@ static inline spx_float_t FLOAT_SQRT(spx_float_t a)
|
||||||
{
|
{
|
||||||
spx_float_t r;
|
spx_float_t r;
|
||||||
spx_int32_t m;
|
spx_int32_t m;
|
||||||
m = a.m << 14;
|
m = SHL32(EXTEND32(a.m), 14);
|
||||||
r.e = a.e - 14;
|
r.e = a.e - 14;
|
||||||
if (r.e & 1)
|
if (r.e & 1)
|
||||||
{
|
{
|
||||||
|
@ -370,6 +348,7 @@ static inline spx_float_t FLOAT_SQRT(spx_float_t a)
|
||||||
#define FLOAT_HALF 0.5f
|
#define FLOAT_HALF 0.5f
|
||||||
#define PSEUDOFLOAT(x) (x)
|
#define PSEUDOFLOAT(x) (x)
|
||||||
#define FLOAT_MULT(a,b) ((a)*(b))
|
#define FLOAT_MULT(a,b) ((a)*(b))
|
||||||
|
#define FLOAT_AMULT(a,b) ((a)*(b))
|
||||||
#define FLOAT_MUL32(a,b) ((a)*(b))
|
#define FLOAT_MUL32(a,b) ((a)*(b))
|
||||||
#define FLOAT_DIV32(a,b) ((a)/(b))
|
#define FLOAT_DIV32(a,b) ((a)/(b))
|
||||||
#define FLOAT_EXTRACT16(a) (a)
|
#define FLOAT_EXTRACT16(a) (a)
|
||||||
|
|
|
@ -417,7 +417,7 @@ void lsp_quant_48k(spx_lsp_t *lsp, spx_lsp_t *qlsp, int order, SpeexBits *bits)
|
||||||
|
|
||||||
#ifdef FIXED_POINT
|
#ifdef FIXED_POINT
|
||||||
for (i=0;i<order;i++)
|
for (i=0;i<order;i++)
|
||||||
qlsp[i]=PSHR(qlsp[i],2);
|
qlsp[i]=PSHR16(qlsp[i],2);
|
||||||
#else
|
#else
|
||||||
for (i=0;i<order;i++)
|
for (i=0;i<order;i++)
|
||||||
qlsp[i]=qlsp[i]*0.00097655;
|
qlsp[i]=qlsp[i]*0.00097655;
|
||||||
|
|
625
apps/codecs/libspeex/resample.c
Normal file
625
apps/codecs/libspeex/resample.c
Normal file
|
@ -0,0 +1,625 @@
|
||||||
|
/* Copyright (C) 2007 Jean-Marc Valin
|
||||||
|
|
||||||
|
File: resample.c
|
||||||
|
Arbitrary resampling code
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. 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.
|
||||||
|
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
The design goals of this code are:
|
||||||
|
- Very fast algorithm
|
||||||
|
- SIMD-friendly algorithm
|
||||||
|
- Low memory requirement
|
||||||
|
- Good *perceptual* quality (and not best SNR)
|
||||||
|
|
||||||
|
The code is working, but it's in a very early stage, so it may have
|
||||||
|
artifacts, noise or subliminal messages from satan. Also, the API
|
||||||
|
isn't stable and I can actually promise that I *will* change the API
|
||||||
|
some time in the future.
|
||||||
|
|
||||||
|
TODO list:
|
||||||
|
- Variable calculation resolution depending on quality setting
|
||||||
|
- Single vs double in float mode
|
||||||
|
- 16-bit vs 32-bit (sinc only) in fixed-point mode
|
||||||
|
- Make sure the filter update works even when changing params
|
||||||
|
after only a few samples procesed
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef OUTSIDE_SPEEX
|
||||||
|
#include <stdlib.h>
|
||||||
|
void *speex_alloc (int size) {return calloc(size,1);}
|
||||||
|
void *speex_realloc (void *ptr, int size) {return realloc(ptr, size);}
|
||||||
|
void speex_free (void *ptr) {free(ptr);}
|
||||||
|
#else
|
||||||
|
#include "misc.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include "speex/speex_resampler.h"
|
||||||
|
|
||||||
|
#ifndef M_PI
|
||||||
|
#define M_PI 3.14159263
|
||||||
|
#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
|
||||||
|
|
||||||
|
/*#define float double*/
|
||||||
|
#define FILTER_SIZE 64
|
||||||
|
#define OVERSAMPLE 8
|
||||||
|
|
||||||
|
#define IMAX(a,b) ((a) > (b) ? (a) : (b))
|
||||||
|
|
||||||
|
struct QualityMapping {
|
||||||
|
int base_length;
|
||||||
|
int oversample;
|
||||||
|
float downsample_bandwidth;
|
||||||
|
float upsample_bandwidth;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* This table maps conversion quality to internal parameters. There are two
|
||||||
|
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)
|
||||||
|
2) Any aliasing that occurs very close to the Nyquist rate will be masked
|
||||||
|
by the sinusoids/noise just below the Nyquist rate (guaranteed only for
|
||||||
|
up-sampling).
|
||||||
|
*/
|
||||||
|
const struct QualityMapping quality_map[11] = {
|
||||||
|
{ 8, 4, 0.70f, 0.80f}, /* 0 */
|
||||||
|
{ 16, 4, 0.74f, 0.83f}, /* 1 */
|
||||||
|
{ 32, 4, 0.77f, 0.87f}, /* 2 */
|
||||||
|
{ 48, 8, 0.84f, 0.90f}, /* 3 */
|
||||||
|
{ 64, 8, 0.88f, 0.92f}, /* 4 */
|
||||||
|
{ 80, 8, 0.90f, 0.94f}, /* 5 */
|
||||||
|
{ 96, 8, 0.91f, 0.94f}, /* 6 */
|
||||||
|
{128, 16, 0.93f, 0.95f}, /* 7 */
|
||||||
|
{160, 16, 0.94f, 0.96f}, /* 8 */
|
||||||
|
{192, 16, 0.95f, 0.96f}, /* 9 */
|
||||||
|
{256, 16, 0.96f, 0.97f}, /* 10 */
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum {SPEEX_RESAMPLER_DIRECT_SINGLE=0, SPEEX_RESAMPLER_INTERPOLATE_SINGLE=1} SpeexSincType;
|
||||||
|
|
||||||
|
typedef int (*resampler_basic_func)(SpeexResamplerState *, int , const spx_word16_t *, int *, spx_word16_t *, int *);
|
||||||
|
|
||||||
|
struct SpeexResamplerState_ {
|
||||||
|
int in_rate;
|
||||||
|
int out_rate;
|
||||||
|
int num_rate;
|
||||||
|
int den_rate;
|
||||||
|
|
||||||
|
int quality;
|
||||||
|
int nb_channels;
|
||||||
|
int filt_len;
|
||||||
|
int mem_alloc_size;
|
||||||
|
int int_advance;
|
||||||
|
int frac_advance;
|
||||||
|
float cutoff;
|
||||||
|
int oversample;
|
||||||
|
int initialised;
|
||||||
|
int started;
|
||||||
|
|
||||||
|
/* These are per-channel */
|
||||||
|
int *last_sample;
|
||||||
|
int *samp_frac_num;
|
||||||
|
int *magic_samples;
|
||||||
|
|
||||||
|
spx_word16_t *mem;
|
||||||
|
spx_word16_t *sinc_table;
|
||||||
|
int sinc_table_length;
|
||||||
|
resampler_basic_func resampler_ptr;
|
||||||
|
|
||||||
|
int in_stride;
|
||||||
|
int out_stride;
|
||||||
|
SpeexSincType type;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
/* The slow way of computing a sinc for the table. Should improve that some day */
|
||||||
|
static spx_word16_t sinc(float cutoff, float x, int N)
|
||||||
|
{
|
||||||
|
/*fprintf (stderr, "%f ", x);*/
|
||||||
|
x *= cutoff;
|
||||||
|
if (fabs(x)<1e-6f)
|
||||||
|
return WORD2INT(32768.*cutoff);
|
||||||
|
else if (fabs(x) > .5f*N)
|
||||||
|
return 0;
|
||||||
|
/*FIXME: Can it really be any slower than this? */
|
||||||
|
return WORD2INT(32768.*cutoff*sin(M_PI*x)/(M_PI*x) * (.42+.5*cos(2*x*M_PI/N)+.08*cos(4*x*M_PI/N)));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/* The slow way of computing a sinc for the table. Should improve that some day */
|
||||||
|
static spx_word16_t sinc(float cutoff, float x, int N)
|
||||||
|
{
|
||||||
|
/*fprintf (stderr, "%f ", x);*/
|
||||||
|
x *= cutoff;
|
||||||
|
if (fabs(x)<1e-6)
|
||||||
|
return cutoff;
|
||||||
|
else if (fabs(x) > .5*N)
|
||||||
|
return 0;
|
||||||
|
/*FIXME: Can it really be any slower than this? */
|
||||||
|
return cutoff*sin(M_PI*x)/(M_PI*x) * (.42+.5*cos(2*x*M_PI/N)+.08*cos(4*x*M_PI/N));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int resampler_basic_direct_single(SpeexResamplerState *st, int channel_index, const spx_word16_t *in, int *in_len, spx_word16_t *out, int *out_len)
|
||||||
|
{
|
||||||
|
int N = st->filt_len;
|
||||||
|
int out_sample = 0;
|
||||||
|
spx_word16_t *mem;
|
||||||
|
int last_sample = st->last_sample[channel_index];
|
||||||
|
int samp_frac_num = st->samp_frac_num[channel_index];
|
||||||
|
mem = st->mem + channel_index * st->mem_alloc_size;
|
||||||
|
while (!(last_sample >= *in_len || out_sample >= *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 */
|
||||||
|
ptr = in+st->in_stride*(last_sample-N+1+j);
|
||||||
|
for (;j<N;j++)
|
||||||
|
{
|
||||||
|
sum += MULT16_16(*ptr,st->sinc_table[samp_frac_num*st->filt_len+j]);
|
||||||
|
ptr += st->in_stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
*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)
|
||||||
|
{
|
||||||
|
samp_frac_num -= st->den_rate;
|
||||||
|
last_sample++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
st->last_sample[channel_index] = last_sample;
|
||||||
|
st->samp_frac_num[channel_index] = samp_frac_num;
|
||||||
|
return out_sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int resampler_basic_interpolate_single(SpeexResamplerState *st, int channel_index, const spx_word16_t *in, int *in_len, spx_word16_t *out, int *out_len)
|
||||||
|
{
|
||||||
|
int N = st->filt_len;
|
||||||
|
int out_sample = 0;
|
||||||
|
spx_word16_t *mem;
|
||||||
|
int last_sample = st->last_sample[channel_index];
|
||||||
|
int samp_frac_num = st->samp_frac_num[channel_index];
|
||||||
|
mem = st->mem + channel_index * st->mem_alloc_size;
|
||||||
|
while (!(last_sample >= *in_len || out_sample >= *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};
|
||||||
|
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++)
|
||||||
|
{
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
ptr = in+st->in_stride*(last_sample-N+1+j);
|
||||||
|
/* Do the new part */
|
||||||
|
for (;j<N;j++)
|
||||||
|
{
|
||||||
|
spx_word16_t curr_in = *ptr;
|
||||||
|
ptr += st->in_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]);
|
||||||
|
}
|
||||||
|
/* Compute interpolation coefficients. I'm not sure whether this corresponds to cubic interpolation
|
||||||
|
but I know it's MMSE-optimal on a sinc */
|
||||||
|
interp[0] = -0.16667f*frac + 0.16667f*frac*frac*frac;
|
||||||
|
interp[1] = frac + 0.5f*frac*frac - 0.5f*frac*frac*frac;
|
||||||
|
/*interp[2] = 1.f - 0.5f*frac - frac*frac + 0.5f*frac*frac*frac;*/
|
||||||
|
interp[3] = -0.33333f*frac + 0.5f*frac*frac - 0.16667f*frac*frac*frac;
|
||||||
|
/* Just to make sure we don't have rounding problems */
|
||||||
|
interp[2] = 1.f-interp[0]-interp[1]-interp[3];
|
||||||
|
/*sum = frac*accum[1] + (1-frac)*accum[2];*/
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
samp_frac_num -= st->den_rate;
|
||||||
|
last_sample++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
st->last_sample[channel_index] = last_sample;
|
||||||
|
st->samp_frac_num[channel_index] = samp_frac_num;
|
||||||
|
return out_sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void update_filter(SpeexResamplerState *st)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int 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 */
|
||||||
|
st->cutoff = quality_map[st->quality].downsample_bandwidth * st->den_rate / st->num_rate;
|
||||||
|
/* FIXME: divide the numerator and denominator by a certain amount if they're too large */
|
||||||
|
st->filt_len = st->filt_len*st->num_rate / st->den_rate;
|
||||||
|
/* Round down to make sure we have a multiple of 4 */
|
||||||
|
st->filt_len &= (~0x3);
|
||||||
|
} else {
|
||||||
|
/* up-sampling */
|
||||||
|
st->cutoff = quality_map[st->quality].upsample_bandwidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Choose the resampling type that requires the least amount of memory */
|
||||||
|
if (st->den_rate <= st->oversample)
|
||||||
|
{
|
||||||
|
if (!st->sinc_table)
|
||||||
|
st->sinc_table = (spx_word16_t *)speex_alloc(st->filt_len*st->den_rate*sizeof(spx_word16_t));
|
||||||
|
else if (st->sinc_table_length < st->filt_len*st->den_rate)
|
||||||
|
{
|
||||||
|
st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,st->filt_len*st->den_rate*sizeof(spx_word16_t));
|
||||||
|
st->sinc_table_length = st->filt_len*st->den_rate;
|
||||||
|
}
|
||||||
|
for (i=0;i<st->den_rate;i++)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
for (j=0;j<st->filt_len;j++)
|
||||||
|
{
|
||||||
|
st->sinc_table[i*st->filt_len+j] = sinc(st->cutoff,((j-st->filt_len/2+1)-((float)i)/st->den_rate), st->filt_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
st->type = SPEEX_RESAMPLER_DIRECT_SINGLE;
|
||||||
|
st->resampler_ptr = resampler_basic_direct_single;
|
||||||
|
/*fprintf (stderr, "resampler uses direct sinc table and normalised cutoff %f\n", cutoff);*/
|
||||||
|
} else {
|
||||||
|
if (!st->sinc_table)
|
||||||
|
st->sinc_table = (spx_word16_t *)speex_alloc((st->filt_len*st->oversample+8)*sizeof(spx_word16_t));
|
||||||
|
else if (st->sinc_table_length < st->filt_len*st->oversample+8)
|
||||||
|
{
|
||||||
|
st->sinc_table = (spx_word16_t *)speex_realloc(st->sinc_table,(st->filt_len*st->oversample+8)*sizeof(spx_word16_t));
|
||||||
|
st->sinc_table_length = st->filt_len*st->oversample+8;
|
||||||
|
}
|
||||||
|
for (i=-4;i<st->oversample*st->filt_len+4;i++)
|
||||||
|
st->sinc_table[i+4] = sinc(st->cutoff,(i/(float)st->oversample - st->filt_len/2), st->filt_len);
|
||||||
|
st->type = SPEEX_RESAMPLER_INTERPOLATE_SINGLE;
|
||||||
|
st->resampler_ptr = resampler_basic_interpolate_single;
|
||||||
|
/*fprintf (stderr, "resampler uses interpolated sinc table and normalised cutoff %f\n", cutoff);*/
|
||||||
|
}
|
||||||
|
st->int_advance = st->num_rate/st->den_rate;
|
||||||
|
st->frac_advance = st->num_rate%st->den_rate;
|
||||||
|
|
||||||
|
if (!st->mem)
|
||||||
|
{
|
||||||
|
st->mem = (spx_word16_t*)speex_alloc(st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t));
|
||||||
|
for (i=0;i<st->nb_channels*(st->filt_len-1);i++)
|
||||||
|
st->mem[i] = 0;
|
||||||
|
st->mem_alloc_size = st->filt_len-1;
|
||||||
|
/*speex_warning("init filter");*/
|
||||||
|
} else if (!st->started)
|
||||||
|
{
|
||||||
|
st->mem = (spx_word16_t*)speex_realloc(st->mem, st->nb_channels*(st->filt_len-1) * sizeof(spx_word16_t));
|
||||||
|
for (i=0;i<st->nb_channels*(st->filt_len-1);i++)
|
||||||
|
st->mem[i] = 0;
|
||||||
|
st->mem_alloc_size = st->filt_len-1;
|
||||||
|
/*speex_warning("reinit filter");*/
|
||||||
|
} else if (st->filt_len > old_length)
|
||||||
|
{
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
for (i=0;i<st->nb_channels;i++)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
/* Copy data going backward */
|
||||||
|
for (j=0;j<old_length-1;j++)
|
||||||
|
st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = st->mem[i*old_alloc_size+(old_length-2-j)];
|
||||||
|
/* Then put zeros for lack of anything better */
|
||||||
|
for (;j<st->filt_len-1;j++)
|
||||||
|
st->mem[i*st->mem_alloc_size+(st->filt_len-2-j)] = 0;
|
||||||
|
/* Adjust last_sample */
|
||||||
|
st->last_sample[i] += (st->filt_len - old_length)/2;
|
||||||
|
}
|
||||||
|
} else if (st->filt_len < old_length)
|
||||||
|
{
|
||||||
|
/* Reduce filter length, this a bit tricky */
|
||||||
|
/*speex_warning("decrease filter size (unimplemented)");*/
|
||||||
|
/* Adjust last_sample (which will likely end up negative) */
|
||||||
|
/*st->last_sample += (st->filt_len - old_length)/2;*/
|
||||||
|
for (i=0;i<st->nb_channels;i++)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
st->magic_samples[i] = (old_length - st->filt_len)/2;
|
||||||
|
/* Copy data going backward */
|
||||||
|
for (j=0;j<st->filt_len-1+st->magic_samples[i];j++)
|
||||||
|
st->mem[i*st->mem_alloc_size+j] = st->mem[i*st->mem_alloc_size+j+st->magic_samples[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SpeexResamplerState *speex_resampler_init(int nb_channels, int ratio_num, int ratio_den, int in_rate, int out_rate, int quality)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
SpeexResamplerState *st = (SpeexResamplerState *)speex_alloc(sizeof(SpeexResamplerState));
|
||||||
|
st->initialised = 0;
|
||||||
|
st->started = 0;
|
||||||
|
st->in_rate = 0;
|
||||||
|
st->out_rate = 0;
|
||||||
|
st->num_rate = 0;
|
||||||
|
st->den_rate = 0;
|
||||||
|
st->quality = -1;
|
||||||
|
st->sinc_table_length = 0;
|
||||||
|
st->mem_alloc_size = 0;
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* Per channel data */
|
||||||
|
st->last_sample = (int*)speex_alloc(nb_channels*sizeof(int));
|
||||||
|
st->magic_samples = (int*)speex_alloc(nb_channels*sizeof(int));
|
||||||
|
st->samp_frac_num = (int*)speex_alloc(nb_channels*sizeof(int));
|
||||||
|
for (i=0;i<nb_channels;i++)
|
||||||
|
{
|
||||||
|
st->last_sample[i] = 0;
|
||||||
|
st->magic_samples[i] = 0;
|
||||||
|
st->samp_frac_num[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
speex_resampler_set_quality(st, quality);
|
||||||
|
speex_resampler_set_rate(st, ratio_num, ratio_den, in_rate, out_rate);
|
||||||
|
|
||||||
|
|
||||||
|
update_filter(st);
|
||||||
|
|
||||||
|
st->initialised = 1;
|
||||||
|
return st;
|
||||||
|
}
|
||||||
|
|
||||||
|
void speex_resampler_destroy(SpeexResamplerState *st)
|
||||||
|
{
|
||||||
|
speex_free(st->mem);
|
||||||
|
speex_free(st->sinc_table);
|
||||||
|
speex_free(st->last_sample);
|
||||||
|
speex_free(st->magic_samples);
|
||||||
|
speex_free(st->samp_frac_num);
|
||||||
|
speex_free(st);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void speex_resampler_process_native(SpeexResamplerState *st, int channel_index, const spx_word16_t *in, int *in_len, spx_word16_t *out, int *out_len)
|
||||||
|
{
|
||||||
|
int j=0;
|
||||||
|
int N = st->filt_len;
|
||||||
|
int out_sample = 0;
|
||||||
|
spx_word16_t *mem;
|
||||||
|
int tmp_out_len = 0;
|
||||||
|
mem = st->mem + channel_index * st->mem_alloc_size;
|
||||||
|
st->started = 1;
|
||||||
|
|
||||||
|
/* Handle the case where we have samples left from a reduction in filter length */
|
||||||
|
if (st->magic_samples)
|
||||||
|
{
|
||||||
|
int tmp_in_len;
|
||||||
|
tmp_in_len = st->magic_samples[channel_index];
|
||||||
|
tmp_out_len = *out_len;
|
||||||
|
/* FIXME: Need to handle the case where the out array is too small */
|
||||||
|
/* magic_samples needs to be set to zero to avoid infinite recursion */
|
||||||
|
st->magic_samples = 0;
|
||||||
|
speex_resampler_process_native(st, channel_index, mem+N-1, &tmp_in_len, out, &tmp_out_len);
|
||||||
|
/*speex_warning_int("extra samples:", tmp_out_len);*/
|
||||||
|
out += 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);
|
||||||
|
|
||||||
|
if (st->last_sample[channel_index] < *in_len)
|
||||||
|
*in_len = st->last_sample[channel_index];
|
||||||
|
*out_len = out_sample+tmp_out_len;
|
||||||
|
st->last_sample[channel_index] -= *in_len;
|
||||||
|
|
||||||
|
for (j=0;j<N-1-*in_len;j++)
|
||||||
|
mem[j] = mem[j+*in_len];
|
||||||
|
for (;j<N-1;j++)
|
||||||
|
mem[j] = in[st->in_stride*(j+*in_len-N+1)];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
void speex_resampler_process_float(SpeexResamplerState *st, int channel_index, const float *in, int *in_len, float *out, int *out_len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int istride_save, ostride_save;
|
||||||
|
spx_word16_t x[*in_len];
|
||||||
|
spx_word16_t y[*out_len];
|
||||||
|
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];
|
||||||
|
}
|
||||||
|
void speex_resampler_process_int(SpeexResamplerState *st, int channel_index, const spx_int16_t *in, int *in_len, spx_int16_t *out, int *out_len)
|
||||||
|
{
|
||||||
|
speex_resampler_process_native(st, channel_index, in, in_len, out, out_len);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void speex_resampler_process_float(SpeexResamplerState *st, int channel_index, const float *in, int *in_len, float *out, int *out_len)
|
||||||
|
{
|
||||||
|
speex_resampler_process_native(st, channel_index, in, in_len, out, out_len);
|
||||||
|
}
|
||||||
|
void speex_resampler_process_int(SpeexResamplerState *st, int channel_index, const spx_int16_t *in, int *in_len, spx_int16_t *out, int *out_len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int istride_save, ostride_save;
|
||||||
|
spx_word16_t x[*in_len];
|
||||||
|
spx_word16_t y[*out_len];
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, int *in_len, float *out, int *out_len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int istride_save, ostride_save;
|
||||||
|
istride_save = st->in_stride;
|
||||||
|
ostride_save = st->out_stride;
|
||||||
|
st->in_stride = st->out_stride = st->nb_channels;
|
||||||
|
for (i=0;i<st->nb_channels;i++)
|
||||||
|
{
|
||||||
|
speex_resampler_process_float(st, i, in+i, in_len, out+i, out_len);
|
||||||
|
}
|
||||||
|
st->in_stride = istride_save;
|
||||||
|
st->out_stride = ostride_save;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void speex_resampler_set_rate(SpeexResamplerState *st, int ratio_num, int ratio_den, int in_rate, int out_rate)
|
||||||
|
{
|
||||||
|
int fact;
|
||||||
|
if (st->in_rate == in_rate && st->out_rate == out_rate && st->num_rate == ratio_num && st->den_rate == ratio_den)
|
||||||
|
return;
|
||||||
|
|
||||||
|
st->in_rate = in_rate;
|
||||||
|
st->out_rate = out_rate;
|
||||||
|
st->num_rate = ratio_num;
|
||||||
|
st->den_rate = ratio_den;
|
||||||
|
/* FIXME: This is terribly inefficient, but who cares (at least for now)? */
|
||||||
|
for (fact=2;fact<=sqrt(IMAX(in_rate, out_rate));fact++)
|
||||||
|
{
|
||||||
|
while ((st->num_rate % fact == 0) && (st->den_rate % fact == 0))
|
||||||
|
{
|
||||||
|
st->num_rate /= fact;
|
||||||
|
st->den_rate /= fact;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st->initialised)
|
||||||
|
update_filter(st);
|
||||||
|
}
|
||||||
|
|
||||||
|
void speex_resampler_set_quality(SpeexResamplerState *st, int quality)
|
||||||
|
{
|
||||||
|
if (quality < 0)
|
||||||
|
quality = 0;
|
||||||
|
if (quality > 10)
|
||||||
|
quality = 10;
|
||||||
|
if (st->quality == quality)
|
||||||
|
return;
|
||||||
|
st->quality = quality;
|
||||||
|
if (st->initialised)
|
||||||
|
update_filter(st);
|
||||||
|
}
|
||||||
|
|
||||||
|
void speex_resampler_set_input_stride(SpeexResamplerState *st, int stride)
|
||||||
|
{
|
||||||
|
st->in_stride = stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
void speex_resampler_set_output_stride(SpeexResamplerState *st, int stride)
|
||||||
|
{
|
||||||
|
st->out_stride = stride;
|
||||||
|
}
|
||||||
|
|
||||||
|
void speex_resampler_skip_zeros(SpeexResamplerState *st)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i=0;i<st->nb_channels;i++)
|
||||||
|
st->last_sample[i] = st->filt_len/2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void speex_resampler_reset_mem(SpeexResamplerState *st)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i=0;i<st->nb_channels*(st->filt_len-1);i++)
|
||||||
|
st->mem[i] = 0;
|
||||||
|
}
|
||||||
|
|
121
apps/codecs/libspeex/rockbox.c
Normal file
121
apps/codecs/libspeex/rockbox.c
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
/**************************************************************************
|
||||||
|
* __________ __ ___.
|
||||||
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
||||||
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
||||||
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
||||||
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
||||||
|
* \/ \/ \/ \/ \/
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007 Dan Everton
|
||||||
|
*
|
||||||
|
* All files in this archive are subject to the GNU General Public License.
|
||||||
|
* See the file COPYING in the source tree root for full license agreement.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "../codec.h"
|
||||||
|
#include "../lib/codeclib.h"
|
||||||
|
|
||||||
|
extern struct codec_api* ci;
|
||||||
|
|
||||||
|
#if defined(DEBUG) || defined(SIMULATOR)
|
||||||
|
#undef DEBUGF
|
||||||
|
#define DEBUGF ci->debugf
|
||||||
|
#else
|
||||||
|
#define DEBUGF(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef ROCKBOX_HAS_LOGF
|
||||||
|
#undef LOGF
|
||||||
|
#define LOGF ci->logf
|
||||||
|
#else
|
||||||
|
#define LOGF(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void *speex_alloc (int size)
|
||||||
|
{
|
||||||
|
return codec_calloc(size, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *speex_alloc_scratch (int size)
|
||||||
|
{
|
||||||
|
return codec_calloc(size,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *speex_realloc (void *ptr, int size)
|
||||||
|
{
|
||||||
|
return codec_realloc(ptr, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void speex_free (void *ptr)
|
||||||
|
{
|
||||||
|
codec_free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void speex_free_scratch (void *ptr)
|
||||||
|
{
|
||||||
|
codec_free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *speex_move (void *dest, void *src, int n)
|
||||||
|
{
|
||||||
|
return memmove(dest,src,n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void speex_error(const char *str)
|
||||||
|
{
|
||||||
|
DEBUGF("Fatal error: %s\n", str);
|
||||||
|
//exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void speex_warning(const char *str)
|
||||||
|
{
|
||||||
|
DEBUGF("warning: %s\n", str);
|
||||||
|
}
|
||||||
|
|
||||||
|
void speex_warning_int(const char *str, int val)
|
||||||
|
{
|
||||||
|
DEBUGF("warning: %s %d\n", str, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _speex_putc(int ch, void *file)
|
||||||
|
{
|
||||||
|
//FILE *f = (FILE *)file;
|
||||||
|
//printf("%c", ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
float floor(float x) {
|
||||||
|
return ((float)(((int)x)));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Placeholders (not fixed point, only used when encoding):
|
||||||
|
float pow(float a, float b) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float log(float l) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float fabs(float a) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float sin(float a) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float cos(float a) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float sqrt(float a) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float exp(float a) {
|
||||||
|
return 0;
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -58,16 +58,9 @@ typedef struct SBEncState {
|
||||||
spx_word16_t gamma2; /**< Perceptual weighting coef 2 */
|
spx_word16_t gamma2; /**< Perceptual weighting coef 2 */
|
||||||
|
|
||||||
char *stack; /**< Temporary allocation stack */
|
char *stack; /**< Temporary allocation stack */
|
||||||
spx_sig_t *x0d, *x1d; /**< QMF filter signals*/
|
spx_word16_t *high; /**< High-band signal (buffer) */
|
||||||
spx_sig_t *high; /**< High-band signal (buffer) */
|
|
||||||
spx_sig_t *y0, *y1; /**< QMF synthesis signals */
|
|
||||||
spx_word16_t *h0_mem, *h1_mem;
|
spx_word16_t *h0_mem, *h1_mem;
|
||||||
spx_word32_t *g0_mem, *g1_mem; /**< QMF memories */
|
|
||||||
|
|
||||||
spx_sig_t *excBuf; /**< High-band excitation */
|
|
||||||
spx_sig_t *exc; /**< High-band excitation (for QMF only)*/
|
|
||||||
spx_sig_t *res; /**< Zero-input response (ringing) */
|
|
||||||
spx_sig_t *sw; /**< Perceptually weighted signal */
|
|
||||||
const spx_word16_t *window; /**< LPC analysis window */
|
const spx_word16_t *window; /**< LPC analysis window */
|
||||||
spx_word16_t *lagWindow; /**< Auto-correlation window */
|
spx_word16_t *lagWindow; /**< Auto-correlation window */
|
||||||
spx_word16_t *autocorr; /**< Auto-correlation (for LPC analysis) */
|
spx_word16_t *autocorr; /**< Auto-correlation (for LPC analysis) */
|
||||||
|
@ -87,8 +80,8 @@ typedef struct SBEncState {
|
||||||
spx_mem_t *mem_sp2;
|
spx_mem_t *mem_sp2;
|
||||||
spx_mem_t *mem_sw; /**< Perceptual signal memory */
|
spx_mem_t *mem_sw; /**< Perceptual signal memory */
|
||||||
spx_word32_t *pi_gain;
|
spx_word32_t *pi_gain;
|
||||||
spx_sig_t *innov_save; /**< If non-NULL, innovation is copied here */
|
spx_word16_t *exc_rms;
|
||||||
spx_sig_t *low_innov; /**< Lower-band innovation is copied here magically */
|
spx_word16_t *innov_rms_save; /**< If non-NULL, innovation is copied here */
|
||||||
|
|
||||||
float vbr_quality; /**< Quality setting for VBR encoding */
|
float vbr_quality; /**< Quality setting for VBR encoding */
|
||||||
int vbr_enabled; /**< 1 for enabling VBR, 0 otherwise */
|
int vbr_enabled; /**< 1 for enabling VBR, 0 otherwise */
|
||||||
|
@ -125,13 +118,9 @@ typedef struct SBDecState {
|
||||||
int lpc_enh_enabled;
|
int lpc_enh_enabled;
|
||||||
|
|
||||||
char *stack;
|
char *stack;
|
||||||
spx_sig_t *x0d, *x1d;
|
|
||||||
spx_sig_t *high;
|
|
||||||
spx_sig_t *y0, *y1;
|
|
||||||
spx_word32_t *g0_mem, *g1_mem;
|
spx_word32_t *g0_mem, *g1_mem;
|
||||||
|
|
||||||
spx_sig_t *exc;
|
spx_word16_t *excBuf;
|
||||||
spx_sig_t *excBuf;
|
|
||||||
spx_lsp_t *qlsp;
|
spx_lsp_t *qlsp;
|
||||||
spx_lsp_t *old_qlsp;
|
spx_lsp_t *old_qlsp;
|
||||||
spx_lsp_t *interp_qlsp;
|
spx_lsp_t *interp_qlsp;
|
||||||
|
@ -139,9 +128,10 @@ typedef struct SBDecState {
|
||||||
|
|
||||||
spx_mem_t *mem_sp;
|
spx_mem_t *mem_sp;
|
||||||
spx_word32_t *pi_gain;
|
spx_word32_t *pi_gain;
|
||||||
spx_sig_t *innov_save; /** If non-NULL, innovation is copied here */
|
spx_word16_t *exc_rms;
|
||||||
spx_sig_t *low_innov; /** Lower-band innovation is copied here magically */
|
spx_word16_t *innov_save; /** If non-NULL, innovation is copied here */
|
||||||
|
|
||||||
|
spx_word16_t last_ener;
|
||||||
spx_int32_t seed;
|
spx_int32_t seed;
|
||||||
|
|
||||||
int encode_submode;
|
int encode_submode;
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "modes.h"
|
#include "modes.h"
|
||||||
#include "math_approx.h"
|
#include <math.h>
|
||||||
|
|
||||||
#ifndef NULL
|
#ifndef NULL
|
||||||
#define NULL 0
|
#define NULL 0
|
||||||
|
@ -86,7 +86,7 @@ int speex_decode_native(void *state, SpeexBits *bits, spx_word16_t *out)
|
||||||
int speex_encode(void *state, float *in, SpeexBits *bits)
|
int speex_encode(void *state, float *in, SpeexBits *bits)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int N;
|
spx_int32_t N;
|
||||||
spx_int16_t short_in[MAX_IN_SAMPLES];
|
spx_int16_t short_in[MAX_IN_SAMPLES];
|
||||||
speex_encoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N);
|
speex_encoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N);
|
||||||
for (i=0;i<N;i++)
|
for (i=0;i<N;i++)
|
||||||
|
@ -111,7 +111,7 @@ int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits)
|
||||||
int speex_decode(void *state, SpeexBits *bits, float *out)
|
int speex_decode(void *state, SpeexBits *bits, float *out)
|
||||||
{
|
{
|
||||||
int i, ret;
|
int i, ret;
|
||||||
int N;
|
spx_int32_t N;
|
||||||
spx_int16_t short_out[MAX_IN_SAMPLES];
|
spx_int16_t short_out[MAX_IN_SAMPLES];
|
||||||
speex_decoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N);
|
speex_decoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N);
|
||||||
ret = (*((SpeexMode**)state))->dec(state, bits, short_out);
|
ret = (*((SpeexMode**)state))->dec(state, bits, short_out);
|
||||||
|
@ -136,7 +136,7 @@ int speex_encode(void *state, float *in, SpeexBits *bits)
|
||||||
int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits)
|
int speex_encode_int(void *state, spx_int16_t *in, SpeexBits *bits)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int N;
|
spx_int32_t N;
|
||||||
float float_in[MAX_IN_SAMPLES];
|
float float_in[MAX_IN_SAMPLES];
|
||||||
speex_encoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N);
|
speex_encoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N);
|
||||||
for (i=0;i<N;i++)
|
for (i=0;i<N;i++)
|
||||||
|
@ -152,7 +152,7 @@ int speex_decode(void *state, SpeexBits *bits, float *out)
|
||||||
int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out)
|
int speex_decode_int(void *state, SpeexBits *bits, spx_int16_t *out)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int N;
|
spx_int32_t N;
|
||||||
float float_out[MAX_IN_SAMPLES];
|
float float_out[MAX_IN_SAMPLES];
|
||||||
int ret;
|
int ret;
|
||||||
speex_decoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N);
|
speex_decoder_ctl(state, SPEEX_GET_FRAME_SIZE, &N);
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "../../codec.h"
|
||||||
|
|
||||||
typedef short spx_ogg_int16_t;
|
typedef short spx_ogg_int16_t;
|
||||||
typedef unsigned short spx_ogg_uint16_t;
|
typedef unsigned short spx_ogg_uint16_t;
|
||||||
typedef int spx_ogg_int32_t;
|
typedef int spx_ogg_int32_t;
|
||||||
|
|
|
@ -35,6 +35,10 @@
|
||||||
|
|
||||||
#ifndef SPEEX_H
|
#ifndef SPEEX_H
|
||||||
#define SPEEX_H
|
#define SPEEX_H
|
||||||
|
/** @defgroup Codec Speex encoder and decoder
|
||||||
|
* This is the Speex codec itself.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
#include "speex_bits.h"
|
#include "speex_bits.h"
|
||||||
#include "speex_types.h"
|
#include "speex_types.h"
|
||||||
|
@ -427,5 +431,5 @@ const SpeexMode * speex_lib_get_mode (int mode);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** @}*/
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -35,6 +35,11 @@
|
||||||
|
|
||||||
#ifndef BITS_H
|
#ifndef BITS_H
|
||||||
#define BITS_H
|
#define BITS_H
|
||||||
|
/** @defgroup SpeexBits SpeexBits: Bit-stream manipulations
|
||||||
|
* This is the structure that holds the bit-stream when encoding or decoding
|
||||||
|
* with Speex. It allows some manipulations as well.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -72,13 +77,20 @@ void speex_bits_rewind(SpeexBits *bits);
|
||||||
void speex_bits_read_from(SpeexBits *bits, char *bytes, int len);
|
void speex_bits_read_from(SpeexBits *bits, char *bytes, int len);
|
||||||
|
|
||||||
/** Append bytes to the bit-stream
|
/** Append bytes to the bit-stream
|
||||||
|
*
|
||||||
* @param bits Bit-stream to operate on
|
* @param bits Bit-stream to operate on
|
||||||
* @param bytes pointer to the bytes what will be appended
|
* @param bytes pointer to the bytes what will be appended
|
||||||
* @param len Number of bytes of append
|
* @param len Number of bytes of append
|
||||||
*/
|
*/
|
||||||
void speex_bits_read_whole_bytes(SpeexBits *bits, char *bytes, int len);
|
void speex_bits_read_whole_bytes(SpeexBits *bits, char *bytes, int len);
|
||||||
|
|
||||||
/** Write the content of a bit-stream to an area of memory */
|
/** Write the content of a bit-stream to an area of memory
|
||||||
|
*
|
||||||
|
* @param bits Bit-stream to operate on
|
||||||
|
* @param bytes Memory location where to write the bits
|
||||||
|
* @param max_len Maximum number of bytes to write (i.e. size of the "bytes" buffer)
|
||||||
|
* @return Number of bytes written to the "bytes" buffer
|
||||||
|
*/
|
||||||
int speex_bits_write(SpeexBits *bits, char *bytes, int max_len);
|
int speex_bits_write(SpeexBits *bits, char *bytes, int max_len);
|
||||||
|
|
||||||
/** Like speex_bits_write, but writes only the complete bytes in the stream. Also removes the written bytes from the stream */
|
/** Like speex_bits_write, but writes only the complete bytes in the stream. Also removes the written bytes from the stream */
|
||||||
|
@ -114,13 +126,19 @@ unsigned int speex_bits_unpack_unsigned(SpeexBits *bits, int nbBits);
|
||||||
*/
|
*/
|
||||||
int speex_bits_nbytes(SpeexBits *bits);
|
int speex_bits_nbytes(SpeexBits *bits);
|
||||||
|
|
||||||
/** Same as speex_bits_unpack_unsigned, but without modifying the cursor position */
|
/** Same as speex_bits_unpack_unsigned, but without modifying the cursor position
|
||||||
|
*
|
||||||
|
* @param bits Bit-stream to operate on
|
||||||
|
* @param nbBits Number of bits to look for
|
||||||
|
* @return Value of the bits peeked, interpreted as unsigned
|
||||||
|
*/
|
||||||
unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits);
|
unsigned int speex_bits_peek_unsigned(SpeexBits *bits, int nbBits);
|
||||||
|
|
||||||
/** Get the value of the next bit in the stream, without modifying the
|
/** Get the value of the next bit in the stream, without modifying the
|
||||||
* "cursor" position
|
* "cursor" position
|
||||||
*
|
*
|
||||||
* @param bits Bit-stream to operate on
|
* @param bits Bit-stream to operate on
|
||||||
|
* @return Value of the bit peeked (one bit only)
|
||||||
*/
|
*/
|
||||||
int speex_bits_peek(SpeexBits *bits);
|
int speex_bits_peek(SpeexBits *bits);
|
||||||
|
|
||||||
|
@ -134,6 +152,7 @@ void speex_bits_advance(SpeexBits *bits, int n);
|
||||||
/** Returns the number of bits remaining to be read in a stream
|
/** Returns the number of bits remaining to be read in a stream
|
||||||
*
|
*
|
||||||
* @param bits Bit-stream to operate on
|
* @param bits Bit-stream to operate on
|
||||||
|
* @return Number of bits that can still be read from the stream
|
||||||
*/
|
*/
|
||||||
int speex_bits_remaining(SpeexBits *bits);
|
int speex_bits_remaining(SpeexBits *bits);
|
||||||
|
|
||||||
|
@ -148,4 +167,5 @@ void speex_bits_insert_terminator(SpeexBits *bits);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* @} */
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -35,6 +35,9 @@
|
||||||
|
|
||||||
#ifndef SPEEX_CALLBACKS_H
|
#ifndef SPEEX_CALLBACKS_H
|
||||||
#define SPEEX_CALLBACKS_H
|
#define SPEEX_CALLBACKS_H
|
||||||
|
/** @defgroup SpeexCallbacks Various definitions for Speex callbacks supported by the decoder.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
#include "speex.h"
|
#include "speex.h"
|
||||||
|
|
||||||
|
@ -110,13 +113,16 @@ int speex_default_user_handler(SpeexBits *bits, void *state, void *data);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Standard handler for low mode request (change low mode, no questions asked) */
|
||||||
int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data);
|
int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data);
|
||||||
|
|
||||||
|
/** Standard handler for VBR request (Set VBR, no questions asked) */
|
||||||
int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data);
|
int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data);
|
||||||
|
|
||||||
|
/** Standard handler for enhancer request (Turn ehnancer on/off, no questions asked) */
|
||||||
int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data);
|
int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data);
|
||||||
|
|
||||||
|
/** Standard handler for VBR quality request (Set VBR quality, no questions asked) */
|
||||||
int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *data);
|
int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *data);
|
||||||
|
|
||||||
|
|
||||||
|
@ -124,5 +130,5 @@ int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *da
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** @} */
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
#ifndef __SPEEX_TYPES_H__
|
#ifndef __SPEEX_TYPES_H__
|
||||||
#define __SPEEX_TYPES_H__
|
#define __SPEEX_TYPES_H__
|
||||||
|
|
||||||
/* these are filled in by configure */
|
#include "inttypes.h"
|
||||||
typedef short spx_int16_t;
|
#define spx_int16_t int16_t
|
||||||
typedef unsigned short spx_uint16_t;
|
#define spx_uint16_t uint16_t
|
||||||
typedef int spx_int32_t;
|
#define spx_int32_t int32_t
|
||||||
typedef unsigned int spx_uint32_t;
|
#define spx_uint32_t uint32_t
|
||||||
|
#define spx_int64_t int64_t
|
||||||
|
#define spx_uint64_t uint64_t
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -33,8 +33,11 @@
|
||||||
|
|
||||||
#ifndef SPEEX_ECHO_H
|
#ifndef SPEEX_ECHO_H
|
||||||
#define SPEEX_ECHO_H
|
#define SPEEX_ECHO_H
|
||||||
|
/** @defgroup SpeexEchoState SpeexEchoState: Acoustic echo canceller
|
||||||
#include "speex/speex_types.h"
|
* This is the acoustic echo canceller module.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
#include "speex_types.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -48,33 +51,63 @@ extern "C" {
|
||||||
/** Get sampling rate */
|
/** Get sampling rate */
|
||||||
#define SPEEX_ECHO_GET_SAMPLING_RATE 25
|
#define SPEEX_ECHO_GET_SAMPLING_RATE 25
|
||||||
|
|
||||||
|
/** Internal echo canceller state. Should never be accessed directly. */
|
||||||
/*struct drft_lookup;*/
|
|
||||||
struct SpeexEchoState_;
|
struct SpeexEchoState_;
|
||||||
|
|
||||||
|
/** @class SpeexEchoState
|
||||||
|
* This holds the state of the echo canceller. You need one per channel.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Internal echo canceller state. Should never be accessed directly. */
|
||||||
typedef struct SpeexEchoState_ SpeexEchoState;
|
typedef struct SpeexEchoState_ SpeexEchoState;
|
||||||
|
|
||||||
/** Creates a new echo canceller state */
|
/** Creates a new echo canceller state
|
||||||
|
* @param frame_size Number of samples to process at one time (should correspond to 10-20 ms)
|
||||||
|
* @param filter_length Number of samples of echo to cancel (should generally correspond to 100-500 ms)
|
||||||
|
* @return Newly-created echo canceller state
|
||||||
|
*/
|
||||||
SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length);
|
SpeexEchoState *speex_echo_state_init(int frame_size, int filter_length);
|
||||||
|
|
||||||
/** Destroys an echo canceller state */
|
/** Destroys an echo canceller state
|
||||||
|
* @param st Echo canceller state
|
||||||
|
*/
|
||||||
void speex_echo_state_destroy(SpeexEchoState *st);
|
void speex_echo_state_destroy(SpeexEchoState *st);
|
||||||
|
|
||||||
/** Performs echo cancellation a frame */
|
/** Performs echo cancellation a frame, based on the audio sent to the speaker (no delay is added
|
||||||
|
* to playback ni this form)
|
||||||
|
*
|
||||||
|
* @param st Echo canceller state
|
||||||
|
* @param rec signal from the microphone (near end + far end echo)
|
||||||
|
* @param play Signal played to the speaker (received from far end)
|
||||||
|
* @param out Returns near-end signal with echo removed
|
||||||
|
*/
|
||||||
|
void speex_echo_cancellation(SpeexEchoState *st, const spx_int16_t *rec, const spx_int16_t *play, spx_int16_t *out);
|
||||||
|
|
||||||
|
/** Performs echo cancellation a frame (deprecated) */
|
||||||
void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *rec, const spx_int16_t *play, spx_int16_t *out, spx_int32_t *Yout);
|
void speex_echo_cancel(SpeexEchoState *st, const spx_int16_t *rec, const spx_int16_t *play, spx_int16_t *out, spx_int32_t *Yout);
|
||||||
|
|
||||||
/** Perform echo cancellation using internal playback buffer */
|
/** Perform echo cancellation using internal playback buffer, which is delayed by two frames
|
||||||
void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out, spx_int32_t *Yout);
|
* to account for the delay introduced by most soundcards (but it could be off!)
|
||||||
|
* @param st Echo canceller state
|
||||||
|
* @param rec signal from the microphone (near end + far end echo)
|
||||||
|
* @param out Returns near-end signal with echo removed
|
||||||
|
*/
|
||||||
|
void speex_echo_capture(SpeexEchoState *st, const spx_int16_t *rec, spx_int16_t *out);
|
||||||
|
|
||||||
/** Let the echo canceller know that a frame was just played */
|
/** Let the echo canceller know that a frame was just queued to the soundcard
|
||||||
|
* @param st Echo canceller state
|
||||||
|
* @param play Signal played to the speaker (received from far end)
|
||||||
|
*/
|
||||||
void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play);
|
void speex_echo_playback(SpeexEchoState *st, const spx_int16_t *play);
|
||||||
|
|
||||||
/** Reset the echo canceller state */
|
/** Reset the echo canceller to its original state
|
||||||
|
* @param st Echo canceller state
|
||||||
|
*/
|
||||||
void speex_echo_state_reset(SpeexEchoState *st);
|
void speex_echo_state_reset(SpeexEchoState *st);
|
||||||
|
|
||||||
/** Used like the ioctl function to control the echo canceller parameters
|
/** Used like the ioctl function to control the echo canceller parameters
|
||||||
*
|
*
|
||||||
* @param state Encoder state
|
* @param st Echo canceller state
|
||||||
* @param request ioctl-type request (one of the SPEEX_ECHO_* macros)
|
* @param request ioctl-type request (one of the SPEEX_ECHO_* macros)
|
||||||
* @param ptr Data exchanged to-from function
|
* @param ptr Data exchanged to-from function
|
||||||
* @return 0 if no error, -1 if request in unknown
|
* @return 0 if no error, -1 if request in unknown
|
||||||
|
@ -85,4 +118,6 @@ int speex_echo_ctl(SpeexEchoState *st, int request, void *ptr);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/** @}*/
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -36,6 +36,10 @@
|
||||||
|
|
||||||
#ifndef SPEEX_HEADER_H
|
#ifndef SPEEX_HEADER_H
|
||||||
#define SPEEX_HEADER_H
|
#define SPEEX_HEADER_H
|
||||||
|
/** @defgroup SpeexHeader SpeexHeader: Makes it easy to write/parse an Ogg/Speex header
|
||||||
|
* This is the Speex header for the Ogg encapsulation. You don't need that if you just use RTP.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
#include "speex_types.h"
|
#include "speex_types.h"
|
||||||
|
|
||||||
|
@ -45,6 +49,7 @@ extern "C" {
|
||||||
|
|
||||||
struct SpeexMode;
|
struct SpeexMode;
|
||||||
|
|
||||||
|
/** Length of the Speex header identifier */
|
||||||
#define SPEEX_HEADER_STRING_LENGTH 8
|
#define SPEEX_HEADER_STRING_LENGTH 8
|
||||||
|
|
||||||
/** Maximum number of characters for encoding the Speex version number in the header */
|
/** Maximum number of characters for encoding the Speex version number in the header */
|
||||||
|
@ -82,5 +87,5 @@ SpeexHeader *speex_packet_to_header(char *packet, int size);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** @} */
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -35,6 +35,11 @@
|
||||||
|
|
||||||
#ifndef SPEEX_JITTER_H
|
#ifndef SPEEX_JITTER_H
|
||||||
#define SPEEX_JITTER_H
|
#define SPEEX_JITTER_H
|
||||||
|
/** @defgroup JitterBuffer JitterBuffer: Adaptive jitter buffer
|
||||||
|
* This is the jitter buffer that reorders UDP/RTP packets and adjusts the buffer size
|
||||||
|
* to maintain good quality and low latency.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
#include "speex.h"
|
#include "speex.h"
|
||||||
#include "speex_bits.h"
|
#include "speex_bits.h"
|
||||||
|
@ -43,58 +48,120 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** Generic adaptive jitter buffer state */
|
||||||
struct JitterBuffer_;
|
struct JitterBuffer_;
|
||||||
|
|
||||||
|
/** Generic adaptive jitter buffer state */
|
||||||
typedef struct JitterBuffer_ JitterBuffer;
|
typedef struct JitterBuffer_ JitterBuffer;
|
||||||
|
|
||||||
|
/** Definition of an incoming packet */
|
||||||
typedef struct _JitterBufferPacket JitterBufferPacket;
|
typedef struct _JitterBufferPacket JitterBufferPacket;
|
||||||
|
|
||||||
|
/** Definition of an incoming packet */
|
||||||
struct _JitterBufferPacket {
|
struct _JitterBufferPacket {
|
||||||
char *data;
|
char *data; /**< Data bytes contained in the packet */
|
||||||
spx_uint32_t len;
|
spx_uint32_t len; /**< Length of the packet in bytes */
|
||||||
spx_uint32_t timestamp;
|
spx_uint32_t timestamp; /**< Timestamp for the packet */
|
||||||
spx_uint32_t span;
|
spx_uint32_t span; /**< Time covered by the packet (same units as timestamp) */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Packet has been retrieved */
|
||||||
#define JITTER_BUFFER_OK 0
|
#define JITTER_BUFFER_OK 0
|
||||||
|
/** Packet is missing */
|
||||||
#define JITTER_BUFFER_MISSING 1
|
#define JITTER_BUFFER_MISSING 1
|
||||||
|
/** Packet is incomplete (does not cover the entive tick */
|
||||||
#define JITTER_BUFFER_INCOMPLETE 2
|
#define JITTER_BUFFER_INCOMPLETE 2
|
||||||
|
/** There was an error in the jitter buffer */
|
||||||
#define JITTER_BUFFER_INTERNAL_ERROR -1
|
#define JITTER_BUFFER_INTERNAL_ERROR -1
|
||||||
|
/** Invalid argument */
|
||||||
#define JITTER_BUFFER_BAD_ARGUMENT -2
|
#define JITTER_BUFFER_BAD_ARGUMENT -2
|
||||||
|
|
||||||
/** Initialise jitter buffer */
|
|
||||||
|
/** Set minimum amount of extra buffering required (margin) */
|
||||||
|
#define JITTER_BUFFER_SET_MARGIN 0
|
||||||
|
/** Get minimum amount of extra buffering required (margin) */
|
||||||
|
#define JITTER_BUFFER_GET_MARGIN 1
|
||||||
|
|
||||||
|
|
||||||
|
/** Initialises jitter buffer
|
||||||
|
*
|
||||||
|
* @param tick Number of samples per "tick", i.e. the time period of the elements that will be retrieved
|
||||||
|
* @return Newly created jitter buffer state
|
||||||
|
*/
|
||||||
JitterBuffer *jitter_buffer_init(int tick);
|
JitterBuffer *jitter_buffer_init(int tick);
|
||||||
|
|
||||||
/** Reset jitter buffer */
|
/** Restores jitter buffer to its original state
|
||||||
|
*
|
||||||
|
* @param jitter Jitter buffer state
|
||||||
|
*/
|
||||||
void jitter_buffer_reset(JitterBuffer *jitter);
|
void jitter_buffer_reset(JitterBuffer *jitter);
|
||||||
|
|
||||||
/** Destroy jitter buffer */
|
/** Destroys jitter buffer
|
||||||
|
*
|
||||||
|
* @param jitter Jitter buffer state
|
||||||
|
*/
|
||||||
void jitter_buffer_destroy(JitterBuffer *jitter);
|
void jitter_buffer_destroy(JitterBuffer *jitter);
|
||||||
|
|
||||||
/** Put one packet into the jitter buffer */
|
/** Put one packet into the jitter buffer
|
||||||
|
*
|
||||||
|
* @param jitter Jitter buffer state
|
||||||
|
* @param packet Incoming packet
|
||||||
|
*/
|
||||||
void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet);
|
void jitter_buffer_put(JitterBuffer *jitter, const JitterBufferPacket *packet);
|
||||||
|
|
||||||
/** Get one packet from the jitter buffer */
|
/** Get one packet from the jitter buffer
|
||||||
|
*
|
||||||
|
* @param jitter Jitter buffer state
|
||||||
|
* @param packet Returned packet
|
||||||
|
* @param current_timestamp Timestamp for the returned packet
|
||||||
|
*/
|
||||||
int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint32_t *current_timestamp);
|
int jitter_buffer_get(JitterBuffer *jitter, JitterBufferPacket *packet, spx_uint32_t *current_timestamp);
|
||||||
|
|
||||||
/** Get pointer timestamp of jitter buffer */
|
/** Get pointer timestamp of jitter buffer
|
||||||
|
*
|
||||||
|
* @param jitter Jitter buffer state
|
||||||
|
*/
|
||||||
int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter);
|
int jitter_buffer_get_pointer_timestamp(JitterBuffer *jitter);
|
||||||
|
|
||||||
/** Advance by one tick */
|
/** Advance by one tick
|
||||||
|
*
|
||||||
|
* @param jitter Jitter buffer state
|
||||||
|
*/
|
||||||
void jitter_buffer_tick(JitterBuffer *jitter);
|
void jitter_buffer_tick(JitterBuffer *jitter);
|
||||||
|
|
||||||
|
/** Used like the ioctl function to control the jitter buffer parameters
|
||||||
|
*
|
||||||
|
* @param jitter Jitter buffer state
|
||||||
|
* @param request ioctl-type request (one of the JITTER_BUFFER_* macros)
|
||||||
|
* @param ptr Data exchanged to-from function
|
||||||
|
* @return 0 if no error, -1 if request in unknown
|
||||||
|
*/
|
||||||
|
int jitter_buffer_ctl(JitterBuffer *jitter, int request, void *ptr);
|
||||||
|
|
||||||
/** Speex jitter-buffer state. */
|
/* @} */
|
||||||
|
|
||||||
|
/** @defgroup SpeexJitter SpeexJitter: Adaptive jitter buffer specifically for Speex
|
||||||
|
* This is the jitter buffer that reorders UDP/RTP packets and adjusts the buffer size
|
||||||
|
* to maintain good quality and low latency. This is a simplified version that works only
|
||||||
|
* with Speex, but is much easier to use.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** Speex jitter-buffer state. Never use it directly! */
|
||||||
typedef struct SpeexJitter {
|
typedef struct SpeexJitter {
|
||||||
SpeexBits current_packet; /**< Current Speex packet */
|
SpeexBits current_packet; /**< Current Speex packet */
|
||||||
int valid_bits; /**< True if Speex bits are valid */
|
int valid_bits; /**< True if Speex bits are valid */
|
||||||
JitterBuffer *packets;
|
JitterBuffer *packets; /**< Generic jitter buffer state */
|
||||||
void *dec; /**< Pointer to Speex decoder */
|
void *dec; /**< Pointer to Speex decoder */
|
||||||
int frame_size; /**< Frame size of Speex decoder */
|
spx_int32_t frame_size; /**< Frame size of Speex decoder */
|
||||||
} SpeexJitter;
|
} SpeexJitter;
|
||||||
|
|
||||||
/** Initialise jitter buffer */
|
/** Initialise jitter buffer
|
||||||
|
*
|
||||||
|
* @param jitter State of the Speex jitter buffer
|
||||||
|
* @param decoder Speex decoder to call
|
||||||
|
* @param sampling_rate Sampling rate used by the decoder
|
||||||
|
*/
|
||||||
void speex_jitter_init(SpeexJitter *jitter, void *decoder, int sampling_rate);
|
void speex_jitter_init(SpeexJitter *jitter, void *decoder, int sampling_rate);
|
||||||
|
|
||||||
/** Destroy jitter buffer */
|
/** Destroy jitter buffer */
|
||||||
|
@ -113,5 +180,5 @@ int speex_jitter_get_pointer_timestamp(SpeexJitter *jitter);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* @} */
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
/* Copyright (C) 2003 Epic Games
|
/* Copyright (C) 2003 Epic Games
|
||||||
Written by Jean-Marc Valin */
|
Written by Jean-Marc Valin */
|
||||||
/**
|
/**
|
||||||
@file speex_preprocess.h
|
* @file speex_preprocess.h
|
||||||
@brief Speex preprocessor
|
* @brief Speex preprocessor. The preprocess can do noise suppression,
|
||||||
|
* residual echo suppression (after using the echo canceller), automatic
|
||||||
|
* gain control (AGC) and voice activity detection (VAD).
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -34,91 +36,61 @@
|
||||||
|
|
||||||
#ifndef SPEEX_PREPROCESS_H
|
#ifndef SPEEX_PREPROCESS_H
|
||||||
#define SPEEX_PREPROCESS_H
|
#define SPEEX_PREPROCESS_H
|
||||||
|
/** @defgroup SpeexPreprocessState SpeexPreprocessState: The Speex preprocessor
|
||||||
|
* This is the Speex preprocessor. The preprocess can do noise suppression,
|
||||||
|
* residual echo suppression (after using the echo canceller), automatic
|
||||||
|
* gain control (AGC) and voice activity detection (VAD).
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
#include "speex/speex_types.h"
|
#include "speex_types.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct drft_lookup;
|
/** State of the preprocessor (one per channel). Should never be accessed directly. */
|
||||||
|
struct SpeexPreprocessState_;
|
||||||
|
|
||||||
/** Speex pre-processor state. */
|
/** State of the preprocessor (one per channel). Should never be accessed directly. */
|
||||||
typedef struct SpeexPreprocessState {
|
typedef struct SpeexPreprocessState_ SpeexPreprocessState;
|
||||||
int frame_size; /**< Number of samples processed each time */
|
|
||||||
int ps_size; /**< Number of points in the power spectrum */
|
|
||||||
int sampling_rate; /**< Sampling rate of the input/output */
|
|
||||||
|
|
||||||
/* parameters */
|
|
||||||
int denoise_enabled;
|
|
||||||
int agc_enabled;
|
|
||||||
float agc_level;
|
|
||||||
int vad_enabled;
|
|
||||||
int dereverb_enabled;
|
|
||||||
float reverb_decay;
|
|
||||||
float reverb_level;
|
|
||||||
float speech_prob_start;
|
|
||||||
float speech_prob_continue;
|
|
||||||
|
|
||||||
float *frame; /**< Processing frame (2*ps_size) */
|
/** Creates a new preprocessing state. You MUST create one state per channel processed.
|
||||||
float *ps; /**< Current power spectrum */
|
* @param frame_size Number of samples to process at one time (should correspond to 10-20 ms). Must be
|
||||||
float *gain2; /**< Adjusted gains */
|
* the same value as that used for the echo canceller for residual echo cancellation to work.
|
||||||
float *window; /**< Analysis/Synthesis window */
|
* @param sampling_rate Sampling rate used for the input.
|
||||||
float *noise; /**< Noise estimate */
|
* @return Newly created preprocessor state
|
||||||
float *reverb_estimate; /**< Estimate of reverb energy */
|
*/
|
||||||
float *old_ps; /**< Power spectrum for last frame */
|
|
||||||
float *gain; /**< Ephraim Malah gain */
|
|
||||||
float *prior; /**< A-priori SNR */
|
|
||||||
float *post; /**< A-posteriori SNR */
|
|
||||||
|
|
||||||
float *S; /**< Smoothed power spectrum */
|
|
||||||
float *Smin; /**< See Cohen paper */
|
|
||||||
float *Stmp; /**< See Cohen paper */
|
|
||||||
float *update_prob; /**< Propability of speech presence for noise update */
|
|
||||||
|
|
||||||
float *zeta; /**< Smoothed a priori SNR */
|
|
||||||
float Zpeak;
|
|
||||||
float Zlast;
|
|
||||||
|
|
||||||
float *loudness_weight; /**< Perceptual loudness curve */
|
|
||||||
|
|
||||||
float *echo_noise;
|
|
||||||
|
|
||||||
float *noise_bands;
|
|
||||||
float *noise_bands2;
|
|
||||||
int noise_bandsN;
|
|
||||||
float *speech_bands;
|
|
||||||
float *speech_bands2;
|
|
||||||
int speech_bandsN;
|
|
||||||
|
|
||||||
float *inbuf; /**< Input buffer (overlapped analysis) */
|
|
||||||
float *outbuf; /**< Output buffer (for overlap and add) */
|
|
||||||
|
|
||||||
float speech_prob;
|
|
||||||
int last_speech;
|
|
||||||
float loudness; /**< loudness estimate */
|
|
||||||
float loudness2; /**< loudness estimate */
|
|
||||||
int nb_adapt; /**< Number of frames used for adaptation so far */
|
|
||||||
int nb_loudness_adapt; /**< Number of frames used for loudness adaptation so far */
|
|
||||||
int consec_noise; /**< Number of consecutive noise frames */
|
|
||||||
int nb_preprocess; /**< Number of frames processed so far */
|
|
||||||
struct drft_lookup *fft_lookup; /**< Lookup table for the FFT */
|
|
||||||
|
|
||||||
} SpeexPreprocessState;
|
|
||||||
|
|
||||||
/** Creates a new preprocessing state */
|
|
||||||
SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_rate);
|
SpeexPreprocessState *speex_preprocess_state_init(int frame_size, int sampling_rate);
|
||||||
|
|
||||||
/** Destroys a denoising state */
|
/** Destroys a preprocessor state
|
||||||
|
* @param st Preprocessor state to destroy
|
||||||
|
*/
|
||||||
void speex_preprocess_state_destroy(SpeexPreprocessState *st);
|
void speex_preprocess_state_destroy(SpeexPreprocessState *st);
|
||||||
|
|
||||||
/** Preprocess a frame */
|
/** Preprocess a frame
|
||||||
|
* @param st Preprocessor state
|
||||||
|
* @param x Audio sample vector (in and out). Must be same size as specified in speex_preprocess_state_init().
|
||||||
|
* @return Bool value for voice activity (1 for speech, 0 for noise/silence), ONLY if VAD turned on.
|
||||||
|
*/
|
||||||
|
int speex_preprocess_run(SpeexPreprocessState *st, spx_int16_t *x);
|
||||||
|
|
||||||
|
/** Preprocess a frame (deprecated, use speex_preprocess_run() instead)*/
|
||||||
int speex_preprocess(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo);
|
int speex_preprocess(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo);
|
||||||
|
|
||||||
/** Preprocess a frame */
|
/** Update preprocessor state, but do not compute the output
|
||||||
void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x, spx_int32_t *echo);
|
* @param st Preprocessor state
|
||||||
|
* @param x Audio sample vector (in only). Must be same size as specified in speex_preprocess_state_init().
|
||||||
|
*/
|
||||||
|
void speex_preprocess_estimate_update(SpeexPreprocessState *st, spx_int16_t *x);
|
||||||
|
|
||||||
/** Used like the ioctl function to control the preprocessor parameters */
|
/** Used like the ioctl function to control the preprocessor parameters
|
||||||
|
* @param st Preprocessor state
|
||||||
|
* @param request ioctl-type request (one of the SPEEX_PREPROCESS_* macros)
|
||||||
|
* @param ptr Data exchanged to-from function
|
||||||
|
* @return 0 if no error, -1 if request in unknown
|
||||||
|
*/
|
||||||
int speex_preprocess_ctl(SpeexPreprocessState *st, int request, void *ptr);
|
int speex_preprocess_ctl(SpeexPreprocessState *st, int request, void *ptr);
|
||||||
|
|
||||||
|
|
||||||
|
@ -158,14 +130,57 @@ int speex_preprocess_ctl(SpeexPreprocessState *st, int request, void *ptr);
|
||||||
/** Get preprocessor dereverb decay */
|
/** Get preprocessor dereverb decay */
|
||||||
#define SPEEX_PREPROCESS_GET_DEREVERB_DECAY 13
|
#define SPEEX_PREPROCESS_GET_DEREVERB_DECAY 13
|
||||||
|
|
||||||
|
/** Set probability required for the VAD to go from silence to voice */
|
||||||
#define SPEEX_PREPROCESS_SET_PROB_START 14
|
#define SPEEX_PREPROCESS_SET_PROB_START 14
|
||||||
|
/** Get probability required for the VAD to go from silence to voice */
|
||||||
#define SPEEX_PREPROCESS_GET_PROB_START 15
|
#define SPEEX_PREPROCESS_GET_PROB_START 15
|
||||||
|
|
||||||
|
/** Set probability required for the VAD to stay in the voice state (integer percent) */
|
||||||
#define SPEEX_PREPROCESS_SET_PROB_CONTINUE 16
|
#define SPEEX_PREPROCESS_SET_PROB_CONTINUE 16
|
||||||
|
/** Get probability required for the VAD to stay in the voice state (integer percent) */
|
||||||
#define SPEEX_PREPROCESS_GET_PROB_CONTINUE 17
|
#define SPEEX_PREPROCESS_GET_PROB_CONTINUE 17
|
||||||
|
|
||||||
|
/** Set maximum attenuation of the noise in dB (negative number) */
|
||||||
|
#define SPEEX_PREPROCESS_SET_NOISE_SUPPRESS 18
|
||||||
|
/** Get maximum attenuation of the noise in dB (negative number) */
|
||||||
|
#define SPEEX_PREPROCESS_GET_NOISE_SUPPRESS 19
|
||||||
|
|
||||||
|
/** Set maximum attenuation of the residual echo in dB (negative number) */
|
||||||
|
#define SPEEX_PREPROCESS_SET_ECHO_SUPPRESS 20
|
||||||
|
/** Get maximum attenuation of the residual echo in dB (negative number) */
|
||||||
|
#define SPEEX_PREPROCESS_GET_ECHO_SUPPRESS 21
|
||||||
|
|
||||||
|
/** Set maximum attenuation of the residual echo in dB when near end is active (negative number) */
|
||||||
|
#define SPEEX_PREPROCESS_SET_ECHO_SUPPRESS_ACTIVE 22
|
||||||
|
/** Get maximum attenuation of the residual echo in dB when near end is active (negative number) */
|
||||||
|
#define SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE 23
|
||||||
|
|
||||||
|
/** Set the corresponding echo canceller state so that residual echo suppression can be performed (NULL for no residual echo suppression) */
|
||||||
|
#define SPEEX_PREPROCESS_SET_ECHO_STATE 24
|
||||||
|
/** Get the corresponding echo canceller state */
|
||||||
|
#define SPEEX_PREPROCESS_GET_ECHO_STATE 25
|
||||||
|
|
||||||
|
/** Set maximal gain increase in dB/second (int32) */
|
||||||
|
#define SPEEX_PREPROCESS_SET_AGC_INCREMENT 26
|
||||||
|
|
||||||
|
/** Get maximal gain increase in dB/second (int32) */
|
||||||
|
#define SPEEX_PREPROCESS_GET_AGC_INCREMENT 27
|
||||||
|
|
||||||
|
/** Set maximal gain decrease in dB/second (int32) */
|
||||||
|
#define SPEEX_PREPROCESS_SET_AGC_DECREMENT 28
|
||||||
|
|
||||||
|
/** Get maximal gain decrease in dB/second (int32) */
|
||||||
|
#define SPEEX_PREPROCESS_GET_AGC_DECREMENT 29
|
||||||
|
|
||||||
|
/** Set maximal gain in dB (int32) */
|
||||||
|
#define SPEEX_PREPROCESS_SET_AGC_MAX_GAIN 30
|
||||||
|
|
||||||
|
/** Get maximal gain in dB (int32) */
|
||||||
|
#define SPEEX_PREPROCESS_GET_AGC_MAX_GAIN 31
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** @}*/
|
||||||
#endif
|
#endif
|
||||||
|
|
162
apps/codecs/libspeex/speex/speex_resampler.h
Normal file
162
apps/codecs/libspeex/speex/speex_resampler.h
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
/* Copyright (C) 2007 Jean-Marc Valin
|
||||||
|
|
||||||
|
File: speex_resampler.h
|
||||||
|
Resampling code
|
||||||
|
|
||||||
|
The design goals of this code are:
|
||||||
|
- Very fast algorithm
|
||||||
|
- Low memory requirement
|
||||||
|
- Good *perceptual* quality (and not best SNR)
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. 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.
|
||||||
|
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef SPEEX_RESAMPLER_H
|
||||||
|
#define SPEEX_RESAMPLER_H
|
||||||
|
|
||||||
|
#ifdef OUTSIDE_SPEEX
|
||||||
|
|
||||||
|
#define spx_int16_t short
|
||||||
|
#ifdef FIXED_POINT
|
||||||
|
#define spx_word16_t short
|
||||||
|
#define spx_word32_t int
|
||||||
|
#else
|
||||||
|
#define spx_word16_t float
|
||||||
|
#define spx_word32_t float
|
||||||
|
#define MULT16_16(a,b) ((a)*(b))
|
||||||
|
#define PSHR32(a,b) (a)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include "speex_types.h"
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SPEEX_RESAMPLER_QUALITY_MAX 10
|
||||||
|
#define SPEEX_RESAMPLER_QUALITY_MIN 0
|
||||||
|
#define SPEEX_RESAMPLER_QUALITY_DEFAULT 4
|
||||||
|
#define SPEEX_RESAMPLER_QUALITY_VOIP 3
|
||||||
|
#define SPEEX_RESAMPLER_QUALITY_DESKTOP 5
|
||||||
|
|
||||||
|
struct SpeexResamplerState_;
|
||||||
|
typedef struct SpeexResamplerState_ SpeexResamplerState;
|
||||||
|
|
||||||
|
/** Create a new resampler. The sampling rate ratio is an arbitrary rational number
|
||||||
|
* with both the numerator and denominator being 32-bit integers.
|
||||||
|
* @param nb_channels Number of channels to be processed
|
||||||
|
* @param ratio_num Numerator of the sampling rate ratio
|
||||||
|
* @param ratio_den Denominator of the sampling rate ratio
|
||||||
|
* @param in_rate Nominal input sampling rate rounded to the nearest integer (in Hz). This does not need to be accurate.
|
||||||
|
* @param out_rate Nominal output sampling rate rounded to the nearest integer (in Hz). This does not need to be accurate.
|
||||||
|
* @param quality Resampling quality between 0 and 10, where 0 has poor quality and 10 has very high quality.
|
||||||
|
* @return Newly created resampler state
|
||||||
|
*/
|
||||||
|
SpeexResamplerState *speex_resampler_init(int nb_channels, int ratio_num, int ratio_den, int in_rate, int out_rate, int quality);
|
||||||
|
|
||||||
|
/** Destroy a resampler state.
|
||||||
|
* @param st Resampler state
|
||||||
|
*/
|
||||||
|
void speex_resampler_destroy(SpeexResamplerState *st);
|
||||||
|
|
||||||
|
/** Resample a float array. The input and output may *not* alias.
|
||||||
|
* @param st Resampler state
|
||||||
|
* @param channel_index Index of the channel to process for the multi-channel base (0 otherwise)
|
||||||
|
* @param in Input buffer
|
||||||
|
* @param in_len Number of input samples in the input buffer. Returns the number of samples processed
|
||||||
|
* @param out Output buffer
|
||||||
|
* @param out_len Size of the output buffer. Returns the number of samples written
|
||||||
|
*/
|
||||||
|
void speex_resampler_process_float(SpeexResamplerState *st, int channel_index, const float *in, int *in_len, float *out, int *out_len);
|
||||||
|
|
||||||
|
/** Resample an int array. The input and output may *not* alias.
|
||||||
|
* @param st Resampler state
|
||||||
|
* @param channel_index Index of the channel to process for the multi-channel base (0 otherwise)
|
||||||
|
* @param in Input buffer
|
||||||
|
* @param in_len Number of input samples in the input buffer. Returns the number of samples processed
|
||||||
|
* @param out Output buffer
|
||||||
|
* @param out_len Size of the output buffer. Returns the number of samples written
|
||||||
|
*/
|
||||||
|
void speex_resampler_process_int(SpeexResamplerState *st, int channel_index, const spx_int16_t *in, int *in_len, spx_int16_t *out, int *out_len);
|
||||||
|
|
||||||
|
/** Resample an interleaved float array. The input and output may *not* alias.
|
||||||
|
* @param st Resampler state
|
||||||
|
* @param in Input buffer
|
||||||
|
* @param in_len Number of input samples in the input buffer. Returns the number of samples processed. This is all per-channel.
|
||||||
|
* @param out Output buffer
|
||||||
|
* @param out_len Size of the output buffer. Returns the number of samples written. This is all per-channel.
|
||||||
|
*/
|
||||||
|
void speex_resampler_process_interleaved_float(SpeexResamplerState *st, const float *in, int *in_len, float *out, int *out_len);
|
||||||
|
|
||||||
|
/** Set (change) the input/output sampling rates and resampling ratio.
|
||||||
|
* @param st Resampler state
|
||||||
|
* @param ratio_num Numerator of the sampling rate ratio
|
||||||
|
* @param ratio_den Denominator of the sampling rate ratio
|
||||||
|
* @param in_rate Nominal input sampling rate rounded to the nearest integer (in Hz). This does not need to be accurate.
|
||||||
|
* @param out_rate Nominal output sampling rate rounded to the nearest integer (in Hz). This does not need to be accurate.
|
||||||
|
*/
|
||||||
|
void speex_resampler_set_rate(SpeexResamplerState *st, int ratio_num, int ratio_den, int in_rate, int out_rate);
|
||||||
|
|
||||||
|
/** Set (change) the conversion quality.
|
||||||
|
* @param st Resampler state
|
||||||
|
* @param quality Resampling quality between 0 and 10, where 0 has poor quality and 10 has very high quality.
|
||||||
|
*/
|
||||||
|
void speex_resampler_set_quality(SpeexResamplerState *st, int quality);
|
||||||
|
|
||||||
|
/** Set (change) the input stride.
|
||||||
|
* @param st Resampler state
|
||||||
|
* @param stride Input stride
|
||||||
|
*/
|
||||||
|
void speex_resampler_set_input_stride(SpeexResamplerState *st, int stride);
|
||||||
|
|
||||||
|
/** Set (change) the output stride.
|
||||||
|
* @param st Resampler state
|
||||||
|
* @param stride Output stride
|
||||||
|
*/
|
||||||
|
void speex_resample_set_output_stride(SpeexResamplerState *st, int stride);
|
||||||
|
|
||||||
|
/** Make sure that the first samples to go out of the resamplers don't have leading zeros.
|
||||||
|
* This is only useful before starting to use a newly created resampler.
|
||||||
|
* @param st Resampler state
|
||||||
|
*/
|
||||||
|
void speex_resampler_skip_zeros(SpeexResamplerState *st);
|
||||||
|
|
||||||
|
/** Reset a resampler so a new (unrelated) stream can be processed.
|
||||||
|
* @param st Resampler state
|
||||||
|
*/
|
||||||
|
void speex_resampler_reset_mem(SpeexResamplerState *st);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -34,6 +34,10 @@
|
||||||
|
|
||||||
#ifndef STEREO_H
|
#ifndef STEREO_H
|
||||||
#define STEREO_H
|
#define STEREO_H
|
||||||
|
/** @defgroup SpeexStereoState SpeexStereoState: Handling Speex stereo files
|
||||||
|
* This describes the Speex intensity stereo encoding/decoding
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
#include "speex_types.h"
|
#include "speex_types.h"
|
||||||
#include "speex_bits.h"
|
#include "speex_bits.h"
|
||||||
|
@ -74,5 +78,5 @@ int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/** @} */
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -21,11 +21,106 @@
|
||||||
*/
|
*/
|
||||||
#ifndef _SPEEX_TYPES_H
|
#ifndef _SPEEX_TYPES_H
|
||||||
#define _SPEEX_TYPES_H
|
#define _SPEEX_TYPES_H
|
||||||
#include "inttypes.h"
|
|
||||||
#define spx_int16_t int16_t
|
#if defined(_WIN32)
|
||||||
#define spx_uint16_t uint16_t
|
|
||||||
#define spx_int32_t int32_t
|
# if defined(__CYGWIN__)
|
||||||
#define spx_uint32_t uint32_t
|
# include <_G_config.h>
|
||||||
#define spx_int64_t int64_t
|
typedef _G_int32_t spx_int32_t;
|
||||||
#define spx_uint64_t uint64_t
|
typedef _G_uint32_t spx_uint32_t;
|
||||||
|
typedef _G_int16_t spx_int16_t;
|
||||||
|
typedef _G_uint16_t spx_uint16_t;
|
||||||
|
# elif defined(__MINGW32__)
|
||||||
|
typedef short spx_int16_t;
|
||||||
|
typedef unsigned short spx_uint16_t;
|
||||||
|
typedef int spx_int32_t;
|
||||||
|
typedef unsigned int spx_uint32_t;
|
||||||
|
# elif defined(__MWERKS__)
|
||||||
|
typedef int spx_int32_t;
|
||||||
|
typedef unsigned int spx_uint32_t;
|
||||||
|
typedef short spx_int16_t;
|
||||||
|
typedef unsigned short spx_uint16_t;
|
||||||
|
# else
|
||||||
|
/* MSVC/Borland */
|
||||||
|
typedef __int32 spx_int32_t;
|
||||||
|
typedef unsigned __int32 spx_uint32_t;
|
||||||
|
typedef __int16 spx_int16_t;
|
||||||
|
typedef unsigned __int16 spx_uint16_t;
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#elif defined(__MACOS__)
|
||||||
|
|
||||||
|
# include <sys/types.h>
|
||||||
|
typedef SInt16 spx_int16_t;
|
||||||
|
typedef UInt16 spx_uint16_t;
|
||||||
|
typedef SInt32 spx_int32_t;
|
||||||
|
typedef UInt32 spx_uint32_t;
|
||||||
|
|
||||||
|
#elif defined(__MACOSX__) /* MacOS X Framework build */
|
||||||
|
|
||||||
|
# include <sys/types.h>
|
||||||
|
typedef int16_t spx_int16_t;
|
||||||
|
typedef u_int16_t spx_uint16_t;
|
||||||
|
typedef int32_t spx_int32_t;
|
||||||
|
typedef u_int32_t spx_uint32_t;
|
||||||
|
|
||||||
|
#elif defined(__BEOS__)
|
||||||
|
|
||||||
|
/* Be */
|
||||||
|
# include <inttypes.h>
|
||||||
|
typedef int16_t spx_int16_t;
|
||||||
|
typedef u_int16_t spx_uint16_t;
|
||||||
|
typedef int32_t spx_int32_t;
|
||||||
|
typedef u_int32_t spx_uint32_t;
|
||||||
|
|
||||||
|
#elif defined (__EMX__)
|
||||||
|
|
||||||
|
/* OS/2 GCC */
|
||||||
|
typedef short spx_int16_t;
|
||||||
|
typedef unsigned short spx_uint16_t;
|
||||||
|
typedef int spx_int32_t;
|
||||||
|
typedef unsigned int spx_uint32_t;
|
||||||
|
|
||||||
|
#elif defined (DJGPP)
|
||||||
|
|
||||||
|
/* DJGPP */
|
||||||
|
typedef short spx_int16_t;
|
||||||
|
typedef int spx_int32_t;
|
||||||
|
typedef unsigned int spx_uint32_t;
|
||||||
|
|
||||||
|
#elif defined(R5900)
|
||||||
|
|
||||||
|
/* PS2 EE */
|
||||||
|
typedef int spx_int32_t;
|
||||||
|
typedef unsigned spx_uint32_t;
|
||||||
|
typedef short spx_int16_t;
|
||||||
|
|
||||||
|
#elif defined(__SYMBIAN32__)
|
||||||
|
|
||||||
|
/* Symbian GCC */
|
||||||
|
typedef signed short spx_int16_t;
|
||||||
|
typedef unsigned short spx_uint16_t;
|
||||||
|
typedef signed int spx_int32_t;
|
||||||
|
typedef unsigned int spx_uint32_t;
|
||||||
|
|
||||||
|
#elif defined(CONFIG_TI_C54X) || defined (CONFIG_TI_C55X)
|
||||||
|
|
||||||
|
typedef short spx_int16_t;
|
||||||
|
typedef unsigned short spx_uint16_t;
|
||||||
|
typedef long spx_int32_t;
|
||||||
|
typedef unsigned long spx_uint32_t;
|
||||||
|
|
||||||
|
#elif defined(CONFIG_TI_C6X)
|
||||||
|
|
||||||
|
typedef short spx_int16_t;
|
||||||
|
typedef unsigned short spx_uint16_t;
|
||||||
|
typedef int spx_int32_t;
|
||||||
|
typedef unsigned int spx_uint32_t;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
# include "speex_config_types.h"
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* _SPEEX_TYPES_H */
|
#endif /* _SPEEX_TYPES_H */
|
||||||
|
|
|
@ -73,7 +73,7 @@ int speex_inband_handler(SpeexBits *bits, SpeexCallback *callback_list, void *st
|
||||||
|
|
||||||
int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data)
|
int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data)
|
||||||
{
|
{
|
||||||
int m;
|
spx_int32_t m;
|
||||||
m = speex_bits_unpack_unsigned(bits, 4);
|
m = speex_bits_unpack_unsigned(bits, 4);
|
||||||
speex_encoder_ctl(data, SPEEX_SET_MODE, &m);
|
speex_encoder_ctl(data, SPEEX_SET_MODE, &m);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -81,7 +81,7 @@ int speex_std_mode_request_handler(SpeexBits *bits, void *state, void *data)
|
||||||
|
|
||||||
int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data)
|
int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data)
|
||||||
{
|
{
|
||||||
int m;
|
spx_int32_t m;
|
||||||
m = speex_bits_unpack_unsigned(bits, 4);
|
m = speex_bits_unpack_unsigned(bits, 4);
|
||||||
speex_encoder_ctl(data, SPEEX_SET_LOW_MODE, &m);
|
speex_encoder_ctl(data, SPEEX_SET_LOW_MODE, &m);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -89,7 +89,7 @@ int speex_std_low_mode_request_handler(SpeexBits *bits, void *state, void *data)
|
||||||
|
|
||||||
int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data)
|
int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data)
|
||||||
{
|
{
|
||||||
int m;
|
spx_int32_t m;
|
||||||
m = speex_bits_unpack_unsigned(bits, 4);
|
m = speex_bits_unpack_unsigned(bits, 4);
|
||||||
speex_encoder_ctl(data, SPEEX_SET_HIGH_MODE, &m);
|
speex_encoder_ctl(data, SPEEX_SET_HIGH_MODE, &m);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -97,7 +97,7 @@ int speex_std_high_mode_request_handler(SpeexBits *bits, void *state, void *data
|
||||||
|
|
||||||
int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data)
|
int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data)
|
||||||
{
|
{
|
||||||
int vbr;
|
spx_int32_t vbr;
|
||||||
vbr = speex_bits_unpack_unsigned(bits, 1);
|
vbr = speex_bits_unpack_unsigned(bits, 1);
|
||||||
speex_encoder_ctl(data, SPEEX_SET_VBR, &vbr);
|
speex_encoder_ctl(data, SPEEX_SET_VBR, &vbr);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -105,7 +105,7 @@ int speex_std_vbr_request_handler(SpeexBits *bits, void *state, void *data)
|
||||||
|
|
||||||
int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data)
|
int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data)
|
||||||
{
|
{
|
||||||
int enh;
|
spx_int32_t enh;
|
||||||
enh = speex_bits_unpack_unsigned(bits, 1);
|
enh = speex_bits_unpack_unsigned(bits, 1);
|
||||||
speex_decoder_ctl(data, SPEEX_SET_ENH, &enh);
|
speex_decoder_ctl(data, SPEEX_SET_ENH, &enh);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -113,7 +113,7 @@ int speex_std_enh_request_handler(SpeexBits *bits, void *state, void *data)
|
||||||
|
|
||||||
int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *data)
|
int speex_std_vbr_quality_request_handler(SpeexBits *bits, void *state, void *data)
|
||||||
{
|
{
|
||||||
int qual;
|
float qual;
|
||||||
qual = speex_bits_unpack_unsigned(bits, 4);
|
qual = speex_bits_unpack_unsigned(bits, 4);
|
||||||
speex_encoder_ctl(data, SPEEX_SET_VBR_QUALITY, &qual);
|
speex_encoder_ctl(data, SPEEX_SET_VBR_QUALITY, &qual);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
#include <speex/speex_stereo.h>
|
#include <speex/speex_stereo.h>
|
||||||
#include <speex/speex_callbacks.h>
|
#include <speex/speex_callbacks.h>
|
||||||
#include "vq.h"
|
#include "vq.h"
|
||||||
#include <math_approx.h>
|
#include <math.h>
|
||||||
|
|
||||||
/*float e_ratio_quant[4] = {1, 1.26, 1.587, 2};*/
|
/*float e_ratio_quant[4] = {1, 1.26, 1.587, 2};*/
|
||||||
static const float e_ratio_quant[4] = {.25f, .315f, .397f, .5f};
|
static const float e_ratio_quant[4] = {.25f, .315f, .397f, .5f};
|
||||||
|
@ -148,7 +148,7 @@ void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState
|
||||||
{
|
{
|
||||||
float balance, e_ratio;
|
float balance, e_ratio;
|
||||||
int i;
|
int i;
|
||||||
float e_tot=0.0, e_left, e_right, e_sum;
|
float e_tot=0, e_left, e_right, e_sum;
|
||||||
|
|
||||||
balance=stereo->balance;
|
balance=stereo->balance;
|
||||||
e_ratio=stereo->e_ratio;
|
e_ratio=stereo->e_ratio;
|
||||||
|
@ -157,11 +157,11 @@ void speex_decode_stereo_int(spx_int16_t *data, int frame_size, SpeexStereoState
|
||||||
e_tot += ((float)data[i])*data[i];
|
e_tot += ((float)data[i])*data[i];
|
||||||
}
|
}
|
||||||
e_sum=e_tot/e_ratio;
|
e_sum=e_tot/e_ratio;
|
||||||
e_left = e_sum*balance / (1.0+balance);
|
e_left = e_sum*balance / (1+balance);
|
||||||
e_right = e_sum-e_left;
|
e_right = e_sum-e_left;
|
||||||
|
|
||||||
e_left = spx_sqrtf(e_left/(e_tot+.01));
|
e_left = sqrt(e_left/(e_tot+.01));
|
||||||
e_right = spx_sqrtf(e_right/(e_tot+.01));
|
e_right = sqrt(e_right/(e_tot+.01));
|
||||||
|
|
||||||
for (i=frame_size-1;i>=0;i--)
|
for (i=frame_size-1;i>=0;i--)
|
||||||
{
|
{
|
||||||
|
@ -183,7 +183,7 @@ int speex_std_stereo_request_handler(SpeexBits *bits, void *state, void *data)
|
||||||
if (speex_bits_unpack_unsigned(bits, 1))
|
if (speex_bits_unpack_unsigned(bits, 1))
|
||||||
sign=-1;
|
sign=-1;
|
||||||
tmp = speex_bits_unpack_unsigned(bits, 5);
|
tmp = speex_bits_unpack_unsigned(bits, 5);
|
||||||
stereo->balance = spx_exp(sign*.25*tmp);
|
stereo->balance = exp(sign*.25*tmp);
|
||||||
|
|
||||||
tmp = speex_bits_unpack_unsigned(bits, 2);
|
tmp = speex_bits_unpack_unsigned(bits, 2);
|
||||||
stereo->e_ratio = e_ratio_quant[tmp];
|
stereo->e_ratio = e_ratio_quant[tmp];
|
||||||
|
|
44
apps/codecs/libspeex/testdenoise.c
Normal file
44
apps/codecs/libspeex/testdenoise.c
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <speex/speex_preprocess.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define NN 160
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
short in[NN];
|
||||||
|
int i;
|
||||||
|
SpeexPreprocessState *st;
|
||||||
|
int count=0;
|
||||||
|
float f;
|
||||||
|
|
||||||
|
st = speex_preprocess_state_init(NN, 8000);
|
||||||
|
i=1;
|
||||||
|
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DENOISE, &i);
|
||||||
|
i=0;
|
||||||
|
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC, &i);
|
||||||
|
f=8000;
|
||||||
|
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC_LEVEL, &f);
|
||||||
|
i=0;
|
||||||
|
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB, &i);
|
||||||
|
f=.0;
|
||||||
|
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &f);
|
||||||
|
f=.0;
|
||||||
|
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &f);
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
int vad;
|
||||||
|
fread(in, sizeof(short), NN, stdin);
|
||||||
|
if (feof(stdin))
|
||||||
|
break;
|
||||||
|
vad = speex_preprocess_run(st, in);
|
||||||
|
/*fprintf (stderr, "%d\n", vad);*/
|
||||||
|
fwrite(in, sizeof(short), NN, stdout);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
speex_preprocess_state_destroy(st);
|
||||||
|
return 0;
|
||||||
|
}
|
53
apps/codecs/libspeex/testecho.c
Normal file
53
apps/codecs/libspeex/testecho.c
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "speex/speex_echo.h"
|
||||||
|
#include "speex/speex_preprocess.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define NN 128
|
||||||
|
#define TAIL 1024
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int echo_fd, ref_fd, e_fd;
|
||||||
|
short echo_buf[NN], ref_buf[NN], e_buf[NN];
|
||||||
|
SpeexEchoState *st;
|
||||||
|
SpeexPreprocessState *den;
|
||||||
|
|
||||||
|
if (argc != 4)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "testecho mic_signal.sw speaker_signal.sw output.sw\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
echo_fd = open (argv[2], O_RDONLY);
|
||||||
|
ref_fd = open (argv[1], O_RDONLY);
|
||||||
|
e_fd = open (argv[3], O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||||
|
|
||||||
|
st = speex_echo_state_init(NN, TAIL);
|
||||||
|
den = speex_preprocess_state_init(NN, 8000);
|
||||||
|
int tmp = 8000;
|
||||||
|
speex_echo_ctl(st, SPEEX_ECHO_SET_SAMPLING_RATE, &tmp);
|
||||||
|
speex_preprocess_ctl(den, SPEEX_PREPROCESS_SET_ECHO_STATE, st);
|
||||||
|
|
||||||
|
while (read(ref_fd, ref_buf, NN*2))
|
||||||
|
{
|
||||||
|
read(echo_fd, echo_buf, NN*2);
|
||||||
|
speex_echo_cancellation(st, ref_buf, echo_buf, e_buf);
|
||||||
|
speex_preprocess_run(den, e_buf);
|
||||||
|
write(e_fd, e_buf, NN*2);
|
||||||
|
}
|
||||||
|
speex_echo_state_destroy(st);
|
||||||
|
speex_preprocess_state_destroy(den);
|
||||||
|
close(e_fd);
|
||||||
|
close(echo_fd);
|
||||||
|
close(ref_fd);
|
||||||
|
return 0;
|
||||||
|
}
|
142
apps/codecs/libspeex/testenc.c
Normal file
142
apps/codecs/libspeex/testenc.c
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <speex/speex.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <speex/speex_callbacks.h>
|
||||||
|
|
||||||
|
#ifdef FIXED_DEBUG
|
||||||
|
extern long long spx_mips;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FRAME_SIZE 160
|
||||||
|
#include <math.h>
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char *inFile, *outFile, *bitsFile;
|
||||||
|
FILE *fin, *fout, *fbits=NULL;
|
||||||
|
short in_short[FRAME_SIZE];
|
||||||
|
short out_short[FRAME_SIZE];
|
||||||
|
float sigpow,errpow,snr, seg_snr=0;
|
||||||
|
int snr_frames = 0;
|
||||||
|
char cbits[200];
|
||||||
|
int nbBits;
|
||||||
|
int i;
|
||||||
|
void *st;
|
||||||
|
void *dec;
|
||||||
|
SpeexBits bits;
|
||||||
|
spx_int32_t tmp;
|
||||||
|
int bitCount=0;
|
||||||
|
spx_int32_t skip_group_delay;
|
||||||
|
SpeexCallback callback;
|
||||||
|
|
||||||
|
sigpow = 0;
|
||||||
|
errpow = 0;
|
||||||
|
|
||||||
|
st = speex_encoder_init(&speex_nb_mode);
|
||||||
|
dec = speex_decoder_init(&speex_nb_mode);
|
||||||
|
|
||||||
|
/* BEGIN: You probably don't need the following in a real application */
|
||||||
|
callback.callback_id = SPEEX_INBAND_CHAR;
|
||||||
|
callback.func = speex_std_char_handler;
|
||||||
|
callback.data = stderr;
|
||||||
|
speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback);
|
||||||
|
|
||||||
|
callback.callback_id = SPEEX_INBAND_MODE_REQUEST;
|
||||||
|
callback.func = speex_std_mode_request_handler;
|
||||||
|
callback.data = st;
|
||||||
|
speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback);
|
||||||
|
/* END of unnecessary stuff */
|
||||||
|
|
||||||
|
tmp=1;
|
||||||
|
speex_decoder_ctl(dec, SPEEX_SET_ENH, &tmp);
|
||||||
|
tmp=0;
|
||||||
|
speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp);
|
||||||
|
tmp=8;
|
||||||
|
speex_encoder_ctl(st, SPEEX_SET_QUALITY, &tmp);
|
||||||
|
tmp=1;
|
||||||
|
speex_encoder_ctl(st, SPEEX_SET_COMPLEXITY, &tmp);
|
||||||
|
|
||||||
|
/* Turn this off if you want to measure SNR (on by default) */
|
||||||
|
tmp=1;
|
||||||
|
speex_encoder_ctl(st, SPEEX_SET_HIGHPASS, &tmp);
|
||||||
|
speex_decoder_ctl(dec, SPEEX_SET_HIGHPASS, &tmp);
|
||||||
|
|
||||||
|
speex_encoder_ctl(st, SPEEX_GET_LOOKAHEAD, &skip_group_delay);
|
||||||
|
speex_decoder_ctl(dec, SPEEX_GET_LOOKAHEAD, &tmp);
|
||||||
|
skip_group_delay += tmp;
|
||||||
|
|
||||||
|
if (argc != 4 && argc != 3)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Usage: encode [in file] [out file] [bits file]\nargc = %d", argc);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
inFile = argv[1];
|
||||||
|
fin = fopen(inFile, "r");
|
||||||
|
outFile = argv[2];
|
||||||
|
fout = fopen(outFile, "w+");
|
||||||
|
if (argc==4)
|
||||||
|
{
|
||||||
|
bitsFile = argv[3];
|
||||||
|
fbits = fopen(bitsFile, "w");
|
||||||
|
}
|
||||||
|
speex_bits_init(&bits);
|
||||||
|
while (!feof(fin))
|
||||||
|
{
|
||||||
|
fread(in_short, sizeof(short), FRAME_SIZE, fin);
|
||||||
|
if (feof(fin))
|
||||||
|
break;
|
||||||
|
speex_bits_reset(&bits);
|
||||||
|
|
||||||
|
speex_encode_int(st, in_short, &bits);
|
||||||
|
nbBits = speex_bits_write(&bits, cbits, 200);
|
||||||
|
bitCount+=bits.nbBits;
|
||||||
|
|
||||||
|
if (argc==4)
|
||||||
|
fwrite(cbits, 1, nbBits, fbits);
|
||||||
|
speex_bits_rewind(&bits);
|
||||||
|
|
||||||
|
speex_decode_int(dec, &bits, out_short);
|
||||||
|
speex_bits_reset(&bits);
|
||||||
|
|
||||||
|
fwrite(&out_short[skip_group_delay], sizeof(short), FRAME_SIZE-skip_group_delay, fout);
|
||||||
|
skip_group_delay = 0;
|
||||||
|
}
|
||||||
|
fprintf (stderr, "Total encoded size: %d bits\n", bitCount);
|
||||||
|
speex_encoder_destroy(st);
|
||||||
|
speex_decoder_destroy(dec);
|
||||||
|
speex_bits_destroy(&bits);
|
||||||
|
|
||||||
|
/* This code just computes SNR, so you don't need it either */
|
||||||
|
rewind(fin);
|
||||||
|
rewind(fout);
|
||||||
|
|
||||||
|
while ( FRAME_SIZE == fread(in_short, sizeof(short), FRAME_SIZE, fin)
|
||||||
|
&&
|
||||||
|
FRAME_SIZE == fread(out_short, sizeof(short), FRAME_SIZE,fout) )
|
||||||
|
{
|
||||||
|
float s=0, e=0;
|
||||||
|
for (i=0;i<FRAME_SIZE;++i) {
|
||||||
|
s += (float)in_short[i] * in_short[i];
|
||||||
|
e += ((float)in_short[i]-out_short[i]) * ((float)in_short[i]-out_short[i]);
|
||||||
|
}
|
||||||
|
seg_snr += 10*log10((s+160)/(e+160));
|
||||||
|
sigpow += s;
|
||||||
|
errpow += e;
|
||||||
|
snr_frames++;
|
||||||
|
}
|
||||||
|
fclose(fin);
|
||||||
|
fclose(fout);
|
||||||
|
|
||||||
|
snr = 10 * log10( sigpow / errpow );
|
||||||
|
seg_snr /= snr_frames;
|
||||||
|
fprintf(stderr,"SNR = %f\nsegmental SNR = %f\n",snr, seg_snr);
|
||||||
|
|
||||||
|
#ifdef FIXED_DEBUG
|
||||||
|
printf ("Total: %f MIPS\n", (float)(1e-6*50*spx_mips/snr_frames));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
137
apps/codecs/libspeex/testenc_uwb.c
Normal file
137
apps/codecs/libspeex/testenc_uwb.c
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <speex/speex.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <speex/speex_callbacks.h>
|
||||||
|
|
||||||
|
#ifdef FIXED_DEBUG
|
||||||
|
extern long long spx_mips;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FRAME_SIZE 640
|
||||||
|
#include <math.h>
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char *inFile, *outFile, *bitsFile;
|
||||||
|
FILE *fin, *fout, *fbits=NULL;
|
||||||
|
short in_short[FRAME_SIZE];
|
||||||
|
short out_short[FRAME_SIZE];
|
||||||
|
float in_float[FRAME_SIZE];
|
||||||
|
float sigpow,errpow,snr, seg_snr=0;
|
||||||
|
int snr_frames = 0;
|
||||||
|
char cbits[200];
|
||||||
|
int nbBits;
|
||||||
|
int i;
|
||||||
|
void *st;
|
||||||
|
void *dec;
|
||||||
|
SpeexBits bits;
|
||||||
|
spx_int32_t tmp;
|
||||||
|
int bitCount=0;
|
||||||
|
spx_int32_t skip_group_delay;
|
||||||
|
SpeexCallback callback;
|
||||||
|
|
||||||
|
sigpow = 0;
|
||||||
|
errpow = 0;
|
||||||
|
|
||||||
|
st = speex_encoder_init(&speex_uwb_mode);
|
||||||
|
dec = speex_decoder_init(&speex_uwb_mode);
|
||||||
|
|
||||||
|
callback.callback_id = SPEEX_INBAND_CHAR;
|
||||||
|
callback.func = speex_std_char_handler;
|
||||||
|
callback.data = stderr;
|
||||||
|
speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback);
|
||||||
|
|
||||||
|
callback.callback_id = SPEEX_INBAND_MODE_REQUEST;
|
||||||
|
callback.func = speex_std_mode_request_handler;
|
||||||
|
callback.data = st;
|
||||||
|
speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback);
|
||||||
|
|
||||||
|
tmp=0;
|
||||||
|
speex_decoder_ctl(dec, SPEEX_SET_ENH, &tmp);
|
||||||
|
tmp=0;
|
||||||
|
speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp);
|
||||||
|
tmp=7;
|
||||||
|
speex_encoder_ctl(st, SPEEX_SET_QUALITY, &tmp);
|
||||||
|
tmp=1;
|
||||||
|
speex_encoder_ctl(st, SPEEX_SET_COMPLEXITY, &tmp);
|
||||||
|
|
||||||
|
speex_encoder_ctl(st, SPEEX_GET_LOOKAHEAD, &skip_group_delay);
|
||||||
|
speex_decoder_ctl(dec, SPEEX_GET_LOOKAHEAD, &tmp);
|
||||||
|
skip_group_delay += tmp;
|
||||||
|
|
||||||
|
|
||||||
|
if (argc != 4 && argc != 3)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Usage: encode [in file] [out file] [bits file]\nargc = %d", argc);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
inFile = argv[1];
|
||||||
|
fin = fopen(inFile, "r");
|
||||||
|
outFile = argv[2];
|
||||||
|
fout = fopen(outFile, "w+");
|
||||||
|
if (argc==4)
|
||||||
|
{
|
||||||
|
bitsFile = argv[3];
|
||||||
|
fbits = fopen(bitsFile, "w");
|
||||||
|
}
|
||||||
|
speex_bits_init(&bits);
|
||||||
|
while (!feof(fin))
|
||||||
|
{
|
||||||
|
fread(in_short, sizeof(short), FRAME_SIZE, fin);
|
||||||
|
if (feof(fin))
|
||||||
|
break;
|
||||||
|
for (i=0;i<FRAME_SIZE;i++)
|
||||||
|
in_float[i]=in_short[i];
|
||||||
|
speex_bits_reset(&bits);
|
||||||
|
|
||||||
|
speex_encode_int(st, in_short, &bits);
|
||||||
|
nbBits = speex_bits_write(&bits, cbits, 200);
|
||||||
|
bitCount+=bits.nbBits;
|
||||||
|
|
||||||
|
if (argc==4)
|
||||||
|
fwrite(cbits, 1, nbBits, fbits);
|
||||||
|
speex_bits_rewind(&bits);
|
||||||
|
|
||||||
|
speex_decode_int(dec, &bits, out_short);
|
||||||
|
speex_bits_reset(&bits);
|
||||||
|
|
||||||
|
fwrite(&out_short[skip_group_delay], sizeof(short), FRAME_SIZE-skip_group_delay, fout);
|
||||||
|
skip_group_delay = 0;
|
||||||
|
}
|
||||||
|
fprintf (stderr, "Total encoded size: %d bits\n", bitCount);
|
||||||
|
speex_encoder_destroy(st);
|
||||||
|
speex_decoder_destroy(dec);
|
||||||
|
|
||||||
|
rewind(fin);
|
||||||
|
rewind(fout);
|
||||||
|
|
||||||
|
while ( FRAME_SIZE == fread(in_short, sizeof(short), FRAME_SIZE, fin)
|
||||||
|
&&
|
||||||
|
FRAME_SIZE == fread(out_short, sizeof(short), FRAME_SIZE,fout) )
|
||||||
|
{
|
||||||
|
float s=0, e=0;
|
||||||
|
for (i=0;i<FRAME_SIZE;++i) {
|
||||||
|
s += (float)in_short[i] * in_short[i];
|
||||||
|
e += ((float)in_short[i]-out_short[i]) * ((float)in_short[i]-out_short[i]);
|
||||||
|
}
|
||||||
|
seg_snr += 10*log10((s+1)/(e+1));
|
||||||
|
sigpow += s;
|
||||||
|
errpow += e;
|
||||||
|
snr_frames++;
|
||||||
|
}
|
||||||
|
fclose(fin);
|
||||||
|
fclose(fout);
|
||||||
|
|
||||||
|
snr = 10 * log10( sigpow / errpow );
|
||||||
|
seg_snr /= snr_frames;
|
||||||
|
fprintf(stderr,"SNR = %f\nsegmental SNR = %f\n",snr, seg_snr);
|
||||||
|
|
||||||
|
#ifdef FIXED_DEBUG
|
||||||
|
printf ("Total: %f MIPS\n", (float)(1e-6*50*spx_mips/snr_frames));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
143
apps/codecs/libspeex/testenc_wb.c
Normal file
143
apps/codecs/libspeex/testenc_wb.c
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <speex/speex.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <speex/speex_callbacks.h>
|
||||||
|
|
||||||
|
#ifdef FIXED_DEBUG
|
||||||
|
extern long long spx_mips;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FRAME_SIZE 320
|
||||||
|
#include <math.h>
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char *inFile, *outFile, *bitsFile;
|
||||||
|
FILE *fin, *fout, *fbits=NULL;
|
||||||
|
short in_short[FRAME_SIZE];
|
||||||
|
short out_short[FRAME_SIZE];
|
||||||
|
float in_float[FRAME_SIZE];
|
||||||
|
float sigpow,errpow,snr, seg_snr=0;
|
||||||
|
int snr_frames = 0;
|
||||||
|
char cbits[200];
|
||||||
|
int nbBits;
|
||||||
|
int i;
|
||||||
|
void *st;
|
||||||
|
void *dec;
|
||||||
|
SpeexBits bits;
|
||||||
|
spx_int32_t tmp;
|
||||||
|
int bitCount=0;
|
||||||
|
spx_int32_t skip_group_delay;
|
||||||
|
SpeexCallback callback;
|
||||||
|
|
||||||
|
sigpow = 0;
|
||||||
|
errpow = 0;
|
||||||
|
|
||||||
|
st = speex_encoder_init(&speex_wb_mode);
|
||||||
|
dec = speex_decoder_init(&speex_wb_mode);
|
||||||
|
|
||||||
|
callback.callback_id = SPEEX_INBAND_CHAR;
|
||||||
|
callback.func = speex_std_char_handler;
|
||||||
|
callback.data = stderr;
|
||||||
|
speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback);
|
||||||
|
|
||||||
|
callback.callback_id = SPEEX_INBAND_MODE_REQUEST;
|
||||||
|
callback.func = speex_std_mode_request_handler;
|
||||||
|
callback.data = st;
|
||||||
|
speex_decoder_ctl(dec, SPEEX_SET_HANDLER, &callback);
|
||||||
|
|
||||||
|
tmp=1;
|
||||||
|
speex_decoder_ctl(dec, SPEEX_SET_ENH, &tmp);
|
||||||
|
tmp=0;
|
||||||
|
speex_encoder_ctl(st, SPEEX_SET_VBR, &tmp);
|
||||||
|
tmp=8;
|
||||||
|
speex_encoder_ctl(st, SPEEX_SET_QUALITY, &tmp);
|
||||||
|
tmp=3;
|
||||||
|
speex_encoder_ctl(st, SPEEX_SET_COMPLEXITY, &tmp);
|
||||||
|
/*tmp=3;
|
||||||
|
speex_encoder_ctl(st, SPEEX_SET_HIGH_MODE, &tmp);
|
||||||
|
tmp=6;
|
||||||
|
speex_encoder_ctl(st, SPEEX_SET_LOW_MODE, &tmp);
|
||||||
|
*/
|
||||||
|
|
||||||
|
speex_encoder_ctl(st, SPEEX_GET_LOOKAHEAD, &skip_group_delay);
|
||||||
|
speex_decoder_ctl(dec, SPEEX_GET_LOOKAHEAD, &tmp);
|
||||||
|
skip_group_delay += tmp;
|
||||||
|
|
||||||
|
|
||||||
|
if (argc != 4 && argc != 3)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "Usage: encode [in file] [out file] [bits file]\nargc = %d", argc);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
inFile = argv[1];
|
||||||
|
fin = fopen(inFile, "r");
|
||||||
|
outFile = argv[2];
|
||||||
|
fout = fopen(outFile, "w+");
|
||||||
|
if (argc==4)
|
||||||
|
{
|
||||||
|
bitsFile = argv[3];
|
||||||
|
fbits = fopen(bitsFile, "w");
|
||||||
|
}
|
||||||
|
speex_bits_init(&bits);
|
||||||
|
while (!feof(fin))
|
||||||
|
{
|
||||||
|
fread(in_short, sizeof(short), FRAME_SIZE, fin);
|
||||||
|
if (feof(fin))
|
||||||
|
break;
|
||||||
|
for (i=0;i<FRAME_SIZE;i++)
|
||||||
|
in_float[i]=in_short[i];
|
||||||
|
speex_bits_reset(&bits);
|
||||||
|
|
||||||
|
speex_encode_int(st, in_short, &bits);
|
||||||
|
nbBits = speex_bits_write(&bits, cbits, 200);
|
||||||
|
bitCount+=bits.nbBits;
|
||||||
|
|
||||||
|
if (argc==4)
|
||||||
|
fwrite(cbits, 1, nbBits, fbits);
|
||||||
|
speex_bits_rewind(&bits);
|
||||||
|
|
||||||
|
speex_decode_int(dec, &bits, out_short);
|
||||||
|
speex_bits_reset(&bits);
|
||||||
|
|
||||||
|
fwrite(&out_short[skip_group_delay], sizeof(short), FRAME_SIZE-skip_group_delay, fout);
|
||||||
|
skip_group_delay = 0;
|
||||||
|
}
|
||||||
|
fprintf (stderr, "Total encoded size: %d bits\n", bitCount);
|
||||||
|
speex_encoder_destroy(st);
|
||||||
|
speex_decoder_destroy(dec);
|
||||||
|
speex_bits_destroy(&bits);
|
||||||
|
|
||||||
|
rewind(fin);
|
||||||
|
rewind(fout);
|
||||||
|
|
||||||
|
while ( FRAME_SIZE == fread(in_short, sizeof(short), FRAME_SIZE, fin)
|
||||||
|
&&
|
||||||
|
FRAME_SIZE == fread(out_short, sizeof(short), FRAME_SIZE,fout) )
|
||||||
|
{
|
||||||
|
float s=0, e=0;
|
||||||
|
for (i=0;i<FRAME_SIZE;++i) {
|
||||||
|
s += (float)in_short[i] * in_short[i];
|
||||||
|
e += ((float)in_short[i]-out_short[i]) * ((float)in_short[i]-out_short[i]);
|
||||||
|
}
|
||||||
|
seg_snr += 10*log10((s+160)/(e+160));
|
||||||
|
sigpow += s;
|
||||||
|
errpow += e;
|
||||||
|
snr_frames++;
|
||||||
|
}
|
||||||
|
fclose(fin);
|
||||||
|
fclose(fout);
|
||||||
|
|
||||||
|
snr = 10 * log10( sigpow / errpow );
|
||||||
|
seg_snr /= snr_frames;
|
||||||
|
fprintf(stderr,"SNR = %f\nsegmental SNR = %f\n",snr, seg_snr);
|
||||||
|
|
||||||
|
#ifdef FIXED_DEBUG
|
||||||
|
printf ("Total: %f MIPS\n", (float)(1e-6*50*spx_mips/snr_frames));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
83
apps/codecs/libspeex/testresample.c
Normal file
83
apps/codecs/libspeex/testresample.c
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
/* Copyright (C) 2007 Jean-Marc Valin
|
||||||
|
|
||||||
|
File: testresample.c
|
||||||
|
Testing the resampling code
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are
|
||||||
|
met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. 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.
|
||||||
|
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "speex/speex_resampler.h"
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define NN 256
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
short *in;
|
||||||
|
short *out;
|
||||||
|
float *fin, *fout;
|
||||||
|
int count = 0;
|
||||||
|
SpeexResamplerState *st = speex_resampler_init(1, 8000, 12000, 8000, 12000, 5);
|
||||||
|
speex_resampler_set_rate(st, 16000, 8001, 8000, 15999);
|
||||||
|
speex_resampler_skip_zeros(st);
|
||||||
|
|
||||||
|
in = malloc(NN*sizeof(short));
|
||||||
|
out = malloc(2*NN*sizeof(short));
|
||||||
|
fin = malloc(NN*sizeof(float));
|
||||||
|
fout = malloc(2*NN*sizeof(float));
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
int in_len;
|
||||||
|
int out_len;
|
||||||
|
fread(in, sizeof(short), NN, stdin);
|
||||||
|
if (feof(stdin))
|
||||||
|
break;
|
||||||
|
for (i=0;i<NN;i++)
|
||||||
|
fin[i]=in[i];
|
||||||
|
in_len = NN;
|
||||||
|
out_len = 2*NN;
|
||||||
|
speex_resampler_process_float(st, 0, fin, &in_len, fout, &out_len);
|
||||||
|
for (i=0;i<out_len;i++)
|
||||||
|
out[i]=floor(.5+fout[i]);
|
||||||
|
fwrite(out, sizeof(short), out_len, stdout);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
speex_resampler_destroy(st);
|
||||||
|
free(in);
|
||||||
|
free(out);
|
||||||
|
free(fin);
|
||||||
|
free(fout);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "vbr.h"
|
#include "vbr.h"
|
||||||
#include "math_approx.h"
|
#include <math.h>
|
||||||
|
|
||||||
|
|
||||||
#define sqr(x) ((x)*(x))
|
#define sqr(x) ((x)*(x))
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
#ifdef _USE_SSE
|
#ifdef _USE_SSE
|
||||||
#include <xmmintrin.h>
|
#include <xmmintrin.h>
|
||||||
#include "vq_sse.h"
|
#include "vq_sse.h"
|
||||||
#elif (defined(ARM4_ASM) || defined(ARM5E_ASM))
|
#elif defined(SHORTCUTS) && (defined(ARM4_ASM) || defined(ARM5E_ASM))
|
||||||
#include "vq_arm4.h"
|
#include "vq_arm4.h"
|
||||||
#elif defined(BFIN_ASM)
|
#elif defined(BFIN_ASM)
|
||||||
#include "vq_bfin.h"
|
#include "vq_bfin.h"
|
||||||
|
|
|
@ -35,12 +35,12 @@
|
||||||
#define OVERRIDE_VQ_NBEST
|
#define OVERRIDE_VQ_NBEST
|
||||||
void vq_nbest(spx_word16_t *in, const spx_word16_t *codebook, int len, int entries, spx_word32_t *E, int N, int *nbest, spx_word32_t *best_dist, char *stack)
|
void vq_nbest(spx_word16_t *in, const spx_word16_t *codebook, int len, int entries, spx_word32_t *E, int N, int *nbest, spx_word32_t *best_dist, char *stack)
|
||||||
{
|
{
|
||||||
int i/*,j*/;
|
int i,j;
|
||||||
for (i=0;i<entries;i+=4)
|
for (i=0;i<entries;i+=4)
|
||||||
{
|
{
|
||||||
#if 1
|
#if 1
|
||||||
spx_word32_t dist1, dist2, dist3, dist4;
|
spx_word32_t dist1, dist2, dist3, dist4;
|
||||||
int dead1, dead2, /*dead3,*/ dead4, dead5, dead6, dead7/*, dead8*/;
|
int dead1, dead2, dead3, dead4, dead5, dead6, dead7, dead8;
|
||||||
__asm__ __volatile__ (
|
__asm__ __volatile__ (
|
||||||
"mov %0, #0 \n\t"
|
"mov %0, #0 \n\t"
|
||||||
"mov %1, #0 \n\t"
|
"mov %1, #0 \n\t"
|
||||||
|
|
|
@ -20,9 +20,10 @@
|
||||||
|
|
||||||
#include "libspeex/speex/ogg.h"
|
#include "libspeex/speex/ogg.h"
|
||||||
#include "libspeex/speex/speex.h"
|
#include "libspeex/speex/speex.h"
|
||||||
|
#include "libspeex/speex/speex_callbacks.h"
|
||||||
#include "libspeex/speex/speex_header.h"
|
#include "libspeex/speex/speex_header.h"
|
||||||
#include "libspeex/speex/speex_stereo.h"
|
#include "libspeex/speex/speex_stereo.h"
|
||||||
#include "libspeex/speex/speex_callbacks.h"
|
#include "libspeex/speex/speex_types.h"
|
||||||
#include "codeclib.h"
|
#include "codeclib.h"
|
||||||
|
|
||||||
#define MAX_FRAME_SIZE 2000
|
#define MAX_FRAME_SIZE 2000
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue